Merge branch 'main' into example-bind-local-lib

This commit is contained in:
Anton Tranelis 2025-02-19 12:24:24 +00:00 committed by Ulf Gebhardt
commit d462a7847a
Signed by: ulfgebhardt
GPG Key ID: DA6B843E748679C9
34 changed files with 154 additions and 94 deletions

View File

@ -32,7 +32,6 @@ jobs:
run: | run: |
npm install npm install
npm run build npm run build
npm link
working-directory: ./ working-directory: ./
build-examples: build-examples:
@ -45,17 +44,14 @@ jobs:
app: [examples/1-basic-map, examples/2-static-layers] # Aktualisierte Pfade der Beispiel-Apps app: [examples/1-basic-map, examples/2-static-layers] # Aktualisierte Pfade der Beispiel-Apps
steps: steps:
- name: Checkout Repository - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
uses: actions/checkout@v3 - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.0.3
- name: Set Up Node.js
uses: actions/setup-node@v3
with: with:
node-version: 18 node-version-file: './.tool-versions'
- name: Link Utopia-UI in Example App - name: Link Utopia-UI in Example App
run: | run: |
npm install
npm run build
cd ${{ matrix.app }} cd ${{ matrix.app }}
npm install npm install
npm link utopia-ui
npm run build npm run build

View File

@ -14,6 +14,7 @@
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.17.0", "@eslint/js": "^9.17.0",
"@types/geojson": "^7946.0.16",
"@types/react": "^18.3.18", "@types/react": "^18.3.18",
"@types/react-dom": "^18.3.5", "@types/react-dom": "^18.3.5",
"@vitejs/plugin-react": "^4.3.4", "@vitejs/plugin-react": "^4.3.4",
@ -1352,6 +1353,13 @@
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
"dev": true "dev": true
}, },
"node_modules/@types/geojson": {
"version": "7946.0.16",
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz",
"integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/json-schema": { "node_modules/@types/json-schema": {
"version": "7.0.15", "version": "7.0.15",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",

View File

@ -16,6 +16,7 @@
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.17.0", "@eslint/js": "^9.17.0",
"@types/geojson": "^7946.0.16",
"@types/react": "^18.3.18", "@types/react": "^18.3.18",
"@types/react-dom": "^18.3.5", "@types/react-dom": "^18.3.5",
"@vitejs/plugin-react": "^4.3.4", "@vitejs/plugin-react": "^4.3.4",

View File

@ -1,6 +1,40 @@
import { UtopiaMap, Layer } from "utopia-ui" import { UtopiaMap, Layer } from "utopia-ui"
import { events, places } from "./sample-data" import { events, places } from "./sample-data"
const itemTypeEvent = {
name: "event",
show_name_input: false,
show_profile_button: false,
show_start_end: false,
show_start_end_input: false,
show_text: false,
show_text_input: false,
custom_text: "",
profileTemplate: [],
offers_and_needs: false,
icon_as_labels: null,
relations: false,
template: "TODO",
questlog: false,
}
const itemTypePlace = {
name: "event",
show_name_input: false,
show_profile_button: false,
show_start_end: false,
show_start_end_input: false,
show_text: false,
show_text_input: false,
custom_text: "",
profileTemplate: [],
offers_and_needs: false,
icon_as_labels: null,
relations: false,
template: "TODO",
questlog: false,
}
function App() { function App() {
return ( return (
<UtopiaMap center={[50.6, 15.5]} zoom={5} height='100dvh' width="100dvw"> <UtopiaMap center={[50.6, 15.5]} zoom={5} height='100dvh' width="100dvw">
@ -9,13 +43,23 @@ function App() {
markerIcon='calendar' markerIcon='calendar'
markerShape='square' markerShape='square'
markerDefaultColor='#700' markerDefaultColor='#700'
data={events} /> data={events}
menuIcon="calendar"
menuColor="#700"
menuText="events"
itemType={itemTypeEvent}
/>
<Layer <Layer
name='places' name='places'
markerIcon='point' markerIcon='point'
markerShape='circle' markerShape='circle'
markerDefaultColor='#007' markerDefaultColor='#007'
data={places} /> data={places}
menuIcon="point"
menuColor="#007"
menuText="places"
itemType={itemTypePlace}
/>
</UtopiaMap> </UtopiaMap>
) )
} }

View File

@ -1,22 +1,24 @@
import { Point } from "utopia-ui";
export const places = [{ export const places = [{
"id": 51, "id": "062a1176-f7ee-458d-adba-4a0b3b1ce2a0",
"name": "Stadtgemüse", "name": "Stadtgemüse",
"text": "Stadtgemüse Fulda ist eine Gemüsegärtnerei in Maberzell, die es sich zur Aufgabe gemacht hat, die Stadt und seine Bewohner:innen mit regionalem, frischem und natürlich angebautem Gemüse mittels Gemüsekisten zu versorgen. Es gibt also jede Woche, von Frühjahr bis Herbst, angepasst an die Saison eine Kiste mit schmackhaftem und frischem Gemüse für euch, welche ihr direkt vor Ort abholen könnt. \r\n\r\nhttps://stadtgemuese-fulda.de", "text": "Stadtgemüse Fulda ist eine Gemüsegärtnerei in Maberzell, die es sich zur Aufgabe gemacht hat, die Stadt und seine Bewohner:innen mit regionalem, frischem und natürlich angebautem Gemüse mittels Gemüsekisten zu versorgen. Es gibt also jede Woche, von Frühjahr bis Herbst, angepasst an die Saison eine Kiste mit schmackhaftem und frischem Gemüse für euch, welche ihr direkt vor Ort abholen könnt. \r\n\r\nhttps://stadtgemuese-fulda.de #food #permaculture #nature",
"position": { "type": "Point", "coordinates": [9.632435, 50.560342] }, "position": { "type": "Point", "coordinates": [9.632435, 50.560342] } as Point,
}, },
{ {
"id": 166, "id": "144e379c-b719-4334-9f0e-de277d3b6d0f",
"name": "Weidendom", "name": "Weidendom",
"text": "free camping", "text": "free camping #nature",
"position": { "type": "Point", "coordinates": [9.438793, 50.560112] }, "position": { "type": "Point", "coordinates": [9.438793, 50.560112] } as Point,
}]; }];
export const events = [ export const events = [
{ {
"id": 423, "id": "efe00aaa-8b14-47b5-a032-3e0560980c1e",
"name": "Hackathon", "name": "Hackathon",
"text": "still in progress", "text": "still in progress #utopia #map",
"position": { "type": "Point", "coordinates": [10.5, 51.62] }, "position": { "type": "Point", "coordinates": [10.5, 51.62] } as Point,
"start": "2022-03-25T12:00:00", "start": "2022-03-25T12:00:00",
"end": "2022-05-12T12:00:00", "end": "2022-05-12T12:00:00",
} }

View File

@ -113,8 +113,8 @@
"imports": { "imports": {
"#components/*": "./src/Components/*", "#components/*": "./src/Components/*",
"#utils/*": "./src/Utils/*", "#utils/*": "./src/Utils/*",
"#types/*": "./src/types/*",
"#src/*": "./src/*", "#src/*": "./src/*",
"#types/*": "./types/*",
"#root/*": "./*" "#root/*": "./*"
} }
} }

View File

@ -76,17 +76,16 @@ export default [
], ],
}, },
{ {
input: 'src/index.tsx', input: 'dist/types/src/index.d.ts',
output: [{ file: 'dist/index.d.ts', format: 'es' }], output: [{ file: 'dist/index.d.ts', format: 'es' }],
plugins: [ plugins: [
aliasConfig, aliasConfig,
dts({ dts({
respectExternal: true,
compilerOptions: { compilerOptions: {
skipLibCheck: true, skipLibCheck: true,
}, },
}), }),
], ],
external: [/\.css$/, /\.d\.ts$/], // ✅ `.d.ts` als extern behandeln external: [/\.css$/], //, /\.d\.ts$/
}, },
] ]

View File

@ -4,6 +4,8 @@ import { SetAppState } from './SetAppState'
import type { AssetsApi } from '#types/AssetsApi' import type { AssetsApi } from '#types/AssetsApi'
export type { AssetsApi } from '#types/AssetsApi'
/** /**
* @category AppShell * @category AppShell
*/ */

View File

@ -3,7 +3,7 @@ import { useEffect, useRef, useState } from 'react'
import { Link, useLocation } from 'react-router-dom' import { Link, useLocation } from 'react-router-dom'
import { toast } from 'react-toastify' import { toast } from 'react-toastify'
import { useAuth } from '#components/Auth' import { useAuth } from '#components/Auth/useAuth'
import { useItems } from '#components/Map/hooks/useItems' import { useItems } from '#components/Map/hooks/useItems'
import type { Item } from '#types/Item' import type { Item } from '#types/Item'

View File

@ -1,4 +1,4 @@
export { AppShell } from './AppShell' export * from './AppShell'
export { SideBar } from './SideBar' export { SideBar } from './SideBar'
export { Content } from './Content' export { Content } from './Content'
export { Sitemap } from './Sitemap' export { Sitemap } from './Sitemap'

View File

@ -1,4 +1,4 @@
export { AuthProvider, useAuth } from './useAuth' export { AuthProvider, UserApi, UserItem } from './useAuth'
export { LoginPage } from './LoginPage' export { LoginPage } from './LoginPage'
export { SignupPage } from './SignupPage' export { SignupPage } from './SignupPage'
export { RequestPasswordPage } from './RequestPasswordPage' export { RequestPasswordPage } from './RequestPasswordPage'

View File

@ -8,6 +8,9 @@ import { createContext, useState, useContext, useEffect } from 'react'
import type { UserApi } from '#types/UserApi' import type { UserApi } from '#types/UserApi'
import type { UserItem } from '#types/UserItem' import type { UserItem } from '#types/UserItem'
export type { UserApi } from '#types/UserApi'
export type { UserItem } from '#types/UserItem'
interface AuthProviderProps { interface AuthProviderProps {
userApi: UserApi userApi: UserApi
children?: React.ReactNode children?: React.ReactNode

View File

@ -1,6 +1,6 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useAuth } from '#components/Auth' import { useAuth } from '#components/Auth/useAuth'
import { useItems } from '#components/Map/hooks/useItems' import { useItems } from '#components/Map/hooks/useItems'
import { useQuestsOpen, useSetQuestOpen } from './hooks/useQuests' import { useQuestsOpen, useSetQuestOpen } from './hooks/useQuests'

View File

@ -27,6 +27,12 @@ import type { Tag } from '#types/Tag'
import type { Popup } from 'leaflet' import type { Popup } from 'leaflet'
import type { ReactElement, ReactNode } from 'react' import type { ReactElement, ReactNode } from 'react'
export type { Point } from 'geojson'
export type { Item } from '#types/Item'
export type { LayerProps } from '#types/LayerProps'
export type { Tag } from '#types/Tag'
export type { Popup } from 'leaflet'
/** /**
* @category Map * @category Map
*/ */

View File

@ -1,6 +1,6 @@
import { useEffect } from 'react' import { useEffect } from 'react'
import { useAuth } from '#components/Auth' import { useAuth } from '#components/Auth/useAuth'
import { useSetPermissionData, useSetPermissionApi, useSetAdminRole } from './hooks/usePermissions' import { useSetPermissionData, useSetPermissionApi, useSetAdminRole } from './hooks/usePermissions'
@ -8,17 +8,20 @@ import type { ItemsApi } from '#types/ItemsApi'
import type { Permission } from '#types/Permission' import type { Permission } from '#types/Permission'
/** /**
* @category Map * @category Types
*/ */
export function Permissions({ export interface PermissionsProps {
data,
api,
adminRole,
}: {
data?: Permission[] data?: Permission[]
api?: ItemsApi<Permission> api?: ItemsApi<Permission>
adminRole?: string adminRole?: string
}) { }
export type { Permission } from '#types/Permission'
export type { ItemsApi } from '#types/ItemsApi'
/**
* @category Map
*/
export function Permissions({ data, api, adminRole }: PermissionsProps) {
const setPermissionData = useSetPermissionData() const setPermissionData = useSetPermissionData()
const setPermissionApi = useSetPermissionApi() const setPermissionApi = useSetPermissionApi()
const setAdminRole = useSetAdminRole() const setAdminRole = useSetAdminRole()

View File

@ -1,6 +1,6 @@
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { useAuth } from '#components/Auth' import { useAuth } from '#components/Auth/useAuth'
export const GratitudeControl = () => { export const GratitudeControl = () => {
const navigate = useNavigate() const navigate = useNavigate()

View File

@ -27,12 +27,14 @@ export const TextView = ({
text, text,
truncate = false, truncate = false,
rawText, rawText,
itemTextField,
}: { }: {
item?: Item item?: Item
itemId: string itemId?: string
text?: string text?: string
truncate?: boolean truncate?: boolean
rawText?: string rawText?: string
itemTextField?: string
}) => { }) => {
if (item) { if (item) {
text = item.text text = item.text
@ -40,6 +42,8 @@ export const TextView = ({
} }
const tags = useTags() const tags = useTags()
const addFilterTag = useAddFilterTag() const addFilterTag = useAddFilterTag()
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const itemTextFieldDummy = itemTextField
let innerText = '' let innerText = ''
let replacedText = '' let replacedText = ''
@ -125,7 +129,7 @@ export const TextView = ({
}: { }: {
children: string children: string
tag: Tag tag: Tag
itemId: string itemId?: string
}) => { }) => {
return ( return (
<a <a

View File

@ -1,7 +1,7 @@
export { UtopiaMap } from './UtopiaMap' export { UtopiaMap } from './UtopiaMap'
export { Layer } from './Layer' export * from './Layer'
export { Tags } from './Tags' export { Tags } from './Tags'
export { Permissions } from './Permissions' export * from './Permissions'
export { ItemForm } from './ItemForm' export { ItemForm } from './ItemForm'
export { ItemView } from './ItemView' export { ItemView } from './ItemView'
export { PopupTextAreaInput } from './Subcomponents/ItemPopupComponents/PopupTextAreaInput' export { PopupTextAreaInput } from './Subcomponents/ItemPopupComponents/PopupTextAreaInput'

View File

@ -5,7 +5,7 @@ import { useEffect, useState } from 'react'
import { useLocation, useNavigate } from 'react-router-dom' import { useLocation, useNavigate } from 'react-router-dom'
import { useAppState } from '#components/AppShell/hooks/useAppState' import { useAppState } from '#components/AppShell/hooks/useAppState'
import { useAuth } from '#components/Auth' import { useAuth } from '#components/Auth/useAuth'
import { useItems, useUpdateItem, useAddItem } from '#components/Map/hooks/useItems' import { useItems, useUpdateItem, useAddItem } from '#components/Map/hooks/useItems'
import { useLayers } from '#components/Map/hooks/useLayers' import { useLayers } from '#components/Map/hooks/useLayers'
import { useHasUserPermission } from '#components/Map/hooks/usePermissions' import { useHasUserPermission } from '#components/Map/hooks/usePermissions'

View File

@ -4,7 +4,7 @@ import { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { toast } from 'react-toastify' import { toast } from 'react-toastify'
import { useAuth } from '#components/Auth' import { useAuth } from '#components/Auth/useAuth'
import { TextInput } from '#components/Input' import { TextInput } from '#components/Input'
import { MapOverlayPage } from '#components/Templates' import { MapOverlayPage } from '#components/Templates'

View File

@ -1,4 +1,4 @@
export { UserSettings } from './UserSettings' export { UserSettings } from './UserSettings'
export { PlusButton } from './Subcomponents/PlusButton' // export { PlusButton } from './Subcomponents/PlusButton'
export { ProfileView } from './ProfileView' export { ProfileView } from './ProfileView'
export { ProfileForm } from './ProfileForm' export { ProfileForm } from './ProfileForm'

View File

@ -33,14 +33,18 @@ import type { Item } from '#types/Item'
export const OverlayItemsIndexPage = ({ export const OverlayItemsIndexPage = ({
url, url,
layerName, layerName,
parameterField,
plusButton = true, plusButton = true,
}: { }: {
layerName: string layerName: string
url: string url: string
parameterField?: string
plusButton?: boolean plusButton?: boolean
}) => { }) => {
const [loading, setLoading] = useState<boolean>(false) const [loading, setLoading] = useState<boolean>(false)
const [addItemPopupType, setAddItemPopupType] = useState<string>('') const [addItemPopupType, setAddItemPopupType] = useState<string>('')
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const parameterFieldDummy = parameterField
const tabRef = useRef<HTMLFormElement>(null) const tabRef = useRef<HTMLFormElement>(null)

View File

@ -1,43 +1,12 @@
import './index.css' import './index.css'
export { export * from './Components/Map'
UtopiaMap, export * from './Components/AppShell'
Layer, export * from './Components/Auth'
Tags, export * from './Components/Profile'
Permissions, export * from './Components/Gaming'
ItemForm, export * from './Components/Templates'
ItemView, export * from './Components/Input'
PopupTextAreaInput,
PopupStartEndInput,
PopupTextInput,
PopupButton,
TextView,
StartEndView,
PopupCheckboxInput,
} from './Components/Map'
export { AppShell, Content, SideBar, Sitemap } from './Components/AppShell'
export {
AuthProvider,
LoginPage,
SignupPage,
RequestPasswordPage,
SetNewPasswordPage,
} from './Components/Auth'
export { UserSettings, ProfileView, ProfileForm } from './Components/Profile'
export { Quests, Modal } from './Components/Gaming'
export {
TitleCard,
CardPage,
MapOverlayPage,
OverlayItemsIndexPage,
MoonCalendar,
SelectUser,
AttestationForm,
MarketView,
} from './Components/Templates'
export { TextInput, TextAreaInput, SelectBox } from './Components/Input'
export * from './types'
declare global { declare global {
interface Window { interface Window {

View File

@ -1,3 +1,6 @@
/**
* @category Types
*/
export interface AssetsApi { export interface AssetsApi {
upload(file: Blob, title: string): Promise<{ id: string }> upload(file: Blob, title: string): Promise<{ id: string }>
url: string url: string

3
src/types/Item.d.ts vendored
View File

@ -15,6 +15,9 @@ interface GalleryItem {
} }
} }
/**
* @category Types
*/
export interface Item { export interface Item {
id: string id: string
name: string name: string

View File

@ -2,14 +2,18 @@ import type { Key } from 'react'
export interface ItemType { export interface ItemType {
name: string name: string
show_name_input: boolean
show_profile_button: boolean
show_start_end: boolean show_start_end: boolean
show_start_end_input: boolean
show_text: boolean show_text: boolean
show_text_input: boolean
custom_text: string
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
profileTemplate: { collection: string | number; id: Key | null | undefined; item: any }[] profileTemplate: { collection: string | number; id: Key | null | undefined; item: any }[]
offers_and_needs: boolean offers_and_needs: boolean
icon_as_labels: unknown icon_as_labels: unknown
relations: boolean relations: boolean
template: string template: string
show_start_end_input: boolean
questlog: boolean questlog: boolean
} }

View File

@ -1,3 +1,6 @@
/**
* @category Types
*/
export interface ItemsApi<T> { export interface ItemsApi<T> {
getItems(): Promise<T[]> getItems(): Promise<T[]>
getItem?(id: string): Promise<T> getItem?(id: string): Promise<T>

View File

@ -3,6 +3,9 @@ import type { ItemFormPopupProps } from './ItemFormPopupProps'
import type { ItemsApi } from './ItemsApi' import type { ItemsApi } from './ItemsApi'
import type { ItemType } from './ItemType' import type { ItemType } from './ItemType'
/**
* @category Types
*/
export interface LayerProps { export interface LayerProps {
id?: string id?: string
data?: Item[] data?: Item[]

View File

@ -1,6 +1,9 @@
import type { PermissionAction } from './PermissionAction' import type { PermissionAction } from './PermissionAction'
import type { PermissionCondition } from './PermissionCondition' import type { PermissionCondition } from './PermissionCondition'
/**
* @category Types
*/
export interface Permission { export interface Permission {
id?: string id?: string
policy?: { name: string } policy?: { name: string }

3
src/types/Tag.d.ts vendored
View File

@ -1,3 +1,6 @@
/**
* @category Types
*/
export interface Tag { export interface Tag {
color: string color: string
id: string id: string

View File

@ -1,5 +1,8 @@
import type { UserItem } from './UserItem' import type { UserItem } from './UserItem'
/**
* @category Types
*/
export interface UserApi { export interface UserApi {
register(email: string, password: string, userName: string): Promise<void> register(email: string, password: string, userName: string): Promise<void>
login(email: string, password: string): Promise<UserItem | undefined> login(email: string, password: string): Promise<UserItem | undefined>

View File

@ -1,5 +1,8 @@
import type { Profile } from './Profile' import type { Profile } from './Profile'
/**
* @category Types
*/
export interface UserItem { export interface UserItem {
id?: string id?: string
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any

View File

@ -1,9 +0,0 @@
export type { ItemsApi } from './ItemsApi'
export type { Tag } from './Tag'
export type { Item } from './Item'
export type { Permission } from './Permission'
export type { LayerProps } from './LayerProps'
export type { UserApi } from './UserApi'
export type { UserItem } from './UserItem'
export type { UtopiaMapProps } from './UtopiaMapProps'
export type { AssetsApi } from './AssetsApi'

View File

@ -22,15 +22,15 @@
"paths": { "paths": {
"#components/*": ["./src/Components/*"], "#components/*": ["./src/Components/*"],
"#utils/*": ["./src/Utils/*"], "#utils/*": ["./src/Utils/*"],
"#src/*": ["./src/*"],
"#types/*": ["./src/types/*"], "#types/*": ["./src/types/*"],
"#src/*": ["./src/*"],
"#root/*": ["./*"] "#root/*": ["./*"]
} }
}, },
"include": ["src", "vite.config.ts", "setupTest.ts", "cypress.config.ts", "cypress/support/commands.ts", "cypress/support/component.ts"], "include": ["src", "vite.config.ts", "setupTest.ts", "cypress.config.ts", "cypress/support/commands.ts", "cypress/support/component.ts"],
"exclude": ["node_modules", "dist", "example", "rollup.config.mjss"], "exclude": ["node_modules", "dist", "example", "rollup.config.mjss"],
"typeRoots": [ "typeRoots": [
"./types", "./src/types",
"./node_modules/@types/" "./node_modules/@types/"
] ]
} }