Merge main
2
.github/workflows/test.build.lib.yml
vendored
@ -37,7 +37,7 @@ jobs:
|
|||||||
build-examples:
|
build-examples:
|
||||||
if: needs.files-changed.outputs.build == 'true'
|
if: needs.files-changed.outputs.build == 'true'
|
||||||
name: Test Example Apps
|
name: Test Example Apps
|
||||||
needs: build
|
needs: [files-changed, build]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
|
|||||||
10
.github/workflows/test.lint.frontend.yml
vendored
@ -1,10 +1,10 @@
|
|||||||
name: test:lint:frontend
|
name: test:lint:app
|
||||||
|
|
||||||
on: push
|
on: push
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
files-changed:
|
files-changed:
|
||||||
name: Detect File Changes - lint - frontend
|
name: Detect File Changes - lint - app
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
outputs:
|
outputs:
|
||||||
lint: ${{ steps.filter.outputs.lint }}
|
lint: ${{ steps.filter.outputs.lint }}
|
||||||
@ -16,11 +16,11 @@ jobs:
|
|||||||
filters: |
|
filters: |
|
||||||
lint:
|
lint:
|
||||||
- '.github/workflows/**/*'
|
- '.github/workflows/**/*'
|
||||||
- 'frontend/**/*'
|
- 'app/**/*'
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
if: needs.files-changed.outputs.lint == 'true'
|
if: needs.files-changed.outputs.lint == 'true'
|
||||||
name: Lint - frontend
|
name: Lint - app
|
||||||
needs: files-changed
|
needs: files-changed
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
@ -30,4 +30,4 @@ jobs:
|
|||||||
node-version-file: '.tool-versions'
|
node-version-file: '.tool-versions'
|
||||||
- name: Lint
|
- name: Lint
|
||||||
run: npm install && npm run test:lint:eslint
|
run: npm install && npm run test:lint:eslint
|
||||||
working-directory: frontend/
|
working-directory: app/
|
||||||
|
|||||||
2
.github/workflows/test.lint.pr.yml
vendored
@ -30,7 +30,7 @@ jobs:
|
|||||||
# Append a scope for each service here
|
# Append a scope for each service here
|
||||||
scopes: |
|
scopes: |
|
||||||
backend
|
backend
|
||||||
frontend
|
app
|
||||||
lib
|
lib
|
||||||
docu
|
docu
|
||||||
docker
|
docker
|
||||||
|
|||||||
0
frontend/.gitignore → app/.gitignore
vendored
@ -38,7 +38,7 @@ services:
|
|||||||
backend:
|
backend:
|
||||||
container_name: backend
|
container_name: backend
|
||||||
build:
|
build:
|
||||||
context: ./backend
|
context: ../backend
|
||||||
depends_on:
|
depends_on:
|
||||||
database:
|
database:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
156
frontend/package-lock.json → app/package-lock.json
generated
@ -18,7 +18,7 @@
|
|||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-rnd": "^10.4.1",
|
"react-rnd": "^10.4.1",
|
||||||
"react-router-dom": "^6.23.0",
|
"react-router-dom": "^6.23.0",
|
||||||
"utopia-ui": "^3.0.105",
|
"utopia-ui": "^3.0.111",
|
||||||
"vite-tsconfig-paths": "^5.1.4"
|
"vite-tsconfig-paths": "^5.1.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -2798,9 +2798,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/node": {
|
"node_modules/@tailwindcss/node": {
|
||||||
"version": "4.1.7",
|
"version": "4.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.11.tgz",
|
||||||
"integrity": "sha512-9rsOpdY9idRI2NH6CL4wORFY0+Q6fnx9XP9Ju+iq/0wJwGD5IByIgFmwVbyy4ymuyprj8Qh4ErxMKTUL4uNh3g==",
|
"integrity": "sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ampproject/remapping": "^2.3.0",
|
"@ampproject/remapping": "^2.3.0",
|
||||||
@ -2809,13 +2809,13 @@
|
|||||||
"lightningcss": "1.30.1",
|
"lightningcss": "1.30.1",
|
||||||
"magic-string": "^0.30.17",
|
"magic-string": "^0.30.17",
|
||||||
"source-map-js": "^1.2.1",
|
"source-map-js": "^1.2.1",
|
||||||
"tailwindcss": "4.1.7"
|
"tailwindcss": "4.1.11"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide": {
|
"node_modules/@tailwindcss/oxide": {
|
||||||
"version": "4.1.7",
|
"version": "4.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.11.tgz",
|
||||||
"integrity": "sha512-5SF95Ctm9DFiUyjUPnDGkoKItPX/k+xifcQhcqX5RA85m50jw1pT/KzjdvlqxRja45Y52nR4MR9fD1JYd7f8NQ==",
|
"integrity": "sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -2826,24 +2826,24 @@
|
|||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@tailwindcss/oxide-android-arm64": "4.1.7",
|
"@tailwindcss/oxide-android-arm64": "4.1.11",
|
||||||
"@tailwindcss/oxide-darwin-arm64": "4.1.7",
|
"@tailwindcss/oxide-darwin-arm64": "4.1.11",
|
||||||
"@tailwindcss/oxide-darwin-x64": "4.1.7",
|
"@tailwindcss/oxide-darwin-x64": "4.1.11",
|
||||||
"@tailwindcss/oxide-freebsd-x64": "4.1.7",
|
"@tailwindcss/oxide-freebsd-x64": "4.1.11",
|
||||||
"@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.7",
|
"@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.11",
|
||||||
"@tailwindcss/oxide-linux-arm64-gnu": "4.1.7",
|
"@tailwindcss/oxide-linux-arm64-gnu": "4.1.11",
|
||||||
"@tailwindcss/oxide-linux-arm64-musl": "4.1.7",
|
"@tailwindcss/oxide-linux-arm64-musl": "4.1.11",
|
||||||
"@tailwindcss/oxide-linux-x64-gnu": "4.1.7",
|
"@tailwindcss/oxide-linux-x64-gnu": "4.1.11",
|
||||||
"@tailwindcss/oxide-linux-x64-musl": "4.1.7",
|
"@tailwindcss/oxide-linux-x64-musl": "4.1.11",
|
||||||
"@tailwindcss/oxide-wasm32-wasi": "4.1.7",
|
"@tailwindcss/oxide-wasm32-wasi": "4.1.11",
|
||||||
"@tailwindcss/oxide-win32-arm64-msvc": "4.1.7",
|
"@tailwindcss/oxide-win32-arm64-msvc": "4.1.11",
|
||||||
"@tailwindcss/oxide-win32-x64-msvc": "4.1.7"
|
"@tailwindcss/oxide-win32-x64-msvc": "4.1.11"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide-android-arm64": {
|
"node_modules/@tailwindcss/oxide-android-arm64": {
|
||||||
"version": "4.1.7",
|
"version": "4.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.11.tgz",
|
||||||
"integrity": "sha512-IWA410JZ8fF7kACus6BrUwY2Z1t1hm0+ZWNEzykKmMNM09wQooOcN/VXr0p/WJdtHZ90PvJf2AIBS/Ceqx1emg==",
|
"integrity": "sha512-3IfFuATVRUMZZprEIx9OGDjG3Ou3jG4xQzNTvjDoKmU9JdmoCohQJ83MYd0GPnQIu89YoJqvMM0G3uqLRFtetg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -2857,9 +2857,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide-darwin-arm64": {
|
"node_modules/@tailwindcss/oxide-darwin-arm64": {
|
||||||
"version": "4.1.7",
|
"version": "4.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.11.tgz",
|
||||||
"integrity": "sha512-81jUw9To7fimGGkuJ2W5h3/oGonTOZKZ8C2ghm/TTxbwvfSiFSDPd6/A/KE2N7Jp4mv3Ps9OFqg2fEKgZFfsvg==",
|
"integrity": "sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -2873,9 +2873,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide-darwin-x64": {
|
"node_modules/@tailwindcss/oxide-darwin-x64": {
|
||||||
"version": "4.1.7",
|
"version": "4.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.11.tgz",
|
||||||
"integrity": "sha512-q77rWjEyGHV4PdDBtrzO0tgBBPlQWKY7wZK0cUok/HaGgbNKecegNxCGikuPJn5wFAlIywC3v+WMBt0PEBtwGw==",
|
"integrity": "sha512-EgnK8kRchgmgzG6jE10UQNaH9Mwi2n+yw1jWmof9Vyg2lpKNX2ioe7CJdf9M5f8V9uaQxInenZkOxnTVL3fhAw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -2889,9 +2889,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide-freebsd-x64": {
|
"node_modules/@tailwindcss/oxide-freebsd-x64": {
|
||||||
"version": "4.1.7",
|
"version": "4.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.11.tgz",
|
||||||
"integrity": "sha512-RfmdbbK6G6ptgF4qqbzoxmH+PKfP4KSVs7SRlTwcbRgBwezJkAO3Qta/7gDy10Q2DcUVkKxFLXUQO6J3CRvBGw==",
|
"integrity": "sha512-xdqKtbpHs7pQhIKmqVpxStnY1skuNh4CtbcyOHeX1YBE0hArj2romsFGb6yUmzkq/6M24nkxDqU8GYrKrz+UcA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -2905,9 +2905,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
|
"node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
|
||||||
"version": "4.1.7",
|
"version": "4.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.11.tgz",
|
||||||
"integrity": "sha512-OZqsGvpwOa13lVd1z6JVwQXadEobmesxQ4AxhrwRiPuE04quvZHWn/LnihMg7/XkN+dTioXp/VMu/p6A5eZP3g==",
|
"integrity": "sha512-ryHQK2eyDYYMwB5wZL46uoxz2zzDZsFBwfjssgB7pzytAeCCa6glsiJGjhTEddq/4OsIjsLNMAiMlHNYnkEEeg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@ -2921,9 +2921,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
|
"node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
|
||||||
"version": "4.1.7",
|
"version": "4.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.11.tgz",
|
||||||
"integrity": "sha512-voMvBTnJSfKecJxGkoeAyW/2XRToLZ227LxswLAwKY7YslG/Xkw9/tJNH+3IVh5bdYzYE7DfiaPbRkSHFxY1xA==",
|
"integrity": "sha512-mYwqheq4BXF83j/w75ewkPJmPZIqqP1nhoghS9D57CLjsh3Nfq0m4ftTotRYtGnZd3eCztgbSPJ9QhfC91gDZQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -2937,9 +2937,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide-linux-arm64-musl": {
|
"node_modules/@tailwindcss/oxide-linux-arm64-musl": {
|
||||||
"version": "4.1.7",
|
"version": "4.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.11.tgz",
|
||||||
"integrity": "sha512-PjGuNNmJeKHnP58M7XyjJyla8LPo+RmwHQpBI+W/OxqrwojyuCQ+GUtygu7jUqTEexejZHr/z3nBc/gTiXBj4A==",
|
"integrity": "sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -2953,9 +2953,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide-linux-x64-gnu": {
|
"node_modules/@tailwindcss/oxide-linux-x64-gnu": {
|
||||||
"version": "4.1.7",
|
"version": "4.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.11.tgz",
|
||||||
"integrity": "sha512-HMs+Va+ZR3gC3mLZE00gXxtBo3JoSQxtu9lobbZd+DmfkIxR54NO7Z+UQNPsa0P/ITn1TevtFxXTpsRU7qEvWg==",
|
"integrity": "sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -2969,9 +2969,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide-linux-x64-musl": {
|
"node_modules/@tailwindcss/oxide-linux-x64-musl": {
|
||||||
"version": "4.1.7",
|
"version": "4.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.11.tgz",
|
||||||
"integrity": "sha512-MHZ6jyNlutdHH8rd+YTdr3QbXrHXqwIhHw9e7yXEBcQdluGwhpQY2Eku8UZK6ReLaWtQ4gijIv5QoM5eE+qlsA==",
|
"integrity": "sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -2985,9 +2985,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide-wasm32-wasi": {
|
"node_modules/@tailwindcss/oxide-wasm32-wasi": {
|
||||||
"version": "4.1.7",
|
"version": "4.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.11.tgz",
|
||||||
"integrity": "sha512-ANaSKt74ZRzE2TvJmUcbFQ8zS201cIPxUDm5qez5rLEwWkie2SkGtA4P+GPTj+u8N6JbPrC8MtY8RmJA35Oo+A==",
|
"integrity": "sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g==",
|
||||||
"bundleDependencies": [
|
"bundleDependencies": [
|
||||||
"@napi-rs/wasm-runtime",
|
"@napi-rs/wasm-runtime",
|
||||||
"@emnapi/core",
|
"@emnapi/core",
|
||||||
@ -3005,7 +3005,7 @@
|
|||||||
"@emnapi/core": "^1.4.3",
|
"@emnapi/core": "^1.4.3",
|
||||||
"@emnapi/runtime": "^1.4.3",
|
"@emnapi/runtime": "^1.4.3",
|
||||||
"@emnapi/wasi-threads": "^1.0.2",
|
"@emnapi/wasi-threads": "^1.0.2",
|
||||||
"@napi-rs/wasm-runtime": "^0.2.9",
|
"@napi-rs/wasm-runtime": "^0.2.11",
|
||||||
"@tybys/wasm-util": "^0.9.0",
|
"@tybys/wasm-util": "^0.9.0",
|
||||||
"tslib": "^2.8.0"
|
"tslib": "^2.8.0"
|
||||||
},
|
},
|
||||||
@ -3014,9 +3014,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
|
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
|
||||||
"version": "4.1.7",
|
"version": "4.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.11.tgz",
|
||||||
"integrity": "sha512-HUiSiXQ9gLJBAPCMVRk2RT1ZrBjto7WvqsPBwUrNK2BcdSxMnk19h4pjZjI7zgPhDxlAbJSumTC4ljeA9y0tEw==",
|
"integrity": "sha512-UgKYx5PwEKrac3GPNPf6HVMNhUIGuUh4wlDFR2jYYdkX6pL/rn73zTq/4pzUm8fOjAn5L8zDeHp9iXmUGOXZ+w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -3030,9 +3030,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide-win32-x64-msvc": {
|
"node_modules/@tailwindcss/oxide-win32-x64-msvc": {
|
||||||
"version": "4.1.7",
|
"version": "4.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.11.tgz",
|
||||||
"integrity": "sha512-rYHGmvoHiLJ8hWucSfSOEmdCBIGZIq7SpkPRSqLsH2Ab2YUNgKeAPT1Fi2cx3+hnYOrAb0jp9cRyode3bBW4mQ==",
|
"integrity": "sha512-YfHoggn1j0LK7wR82TOucWc5LDCguHnoS879idHekmmiR7g9HUtMw9MI0NHatS28u/Xlkfi9w5RJWgz2Dl+5Qg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -3046,17 +3046,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/vite": {
|
"node_modules/@tailwindcss/vite": {
|
||||||
"version": "4.1.7",
|
"version": "4.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.11.tgz",
|
||||||
"integrity": "sha512-tYa2fO3zDe41I7WqijyVbRd8oWT0aEID1Eokz5hMT6wShLIHj3yvwj9XbfuloHP9glZ6H+aG2AN/+ZrxJ1Y5RQ==",
|
"integrity": "sha512-RHYhrR3hku0MJFRV+fN2gNbDNEh3dwKvY8XJvTxCSXeMOsCRSr+uKvDWQcbizrHgjML6ZmTE5OwMrl5wKcujCw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tailwindcss/node": "4.1.7",
|
"@tailwindcss/node": "4.1.11",
|
||||||
"@tailwindcss/oxide": "4.1.7",
|
"@tailwindcss/oxide": "4.1.11",
|
||||||
"tailwindcss": "4.1.7"
|
"tailwindcss": "4.1.11"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"vite": "^5.2.0 || ^6"
|
"vite": "^5.2.0 || ^6 || ^7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tanstack/query-core": {
|
"node_modules/@tanstack/query-core": {
|
||||||
@ -5248,9 +5248,9 @@
|
|||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/enhanced-resolve": {
|
"node_modules/enhanced-resolve": {
|
||||||
"version": "5.18.1",
|
"version": "5.18.2",
|
||||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz",
|
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz",
|
||||||
"integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==",
|
"integrity": "sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"graceful-fs": "^4.2.4",
|
"graceful-fs": "^4.2.4",
|
||||||
@ -9230,9 +9230,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.5.3",
|
"version": "8.5.6",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
||||||
"integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
|
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@ -9249,7 +9249,7 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.8",
|
"nanoid": "^3.3.11",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
"source-map-js": "^1.2.1"
|
"source-map-js": "^1.2.1"
|
||||||
},
|
},
|
||||||
@ -10762,9 +10762,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tailwindcss": {
|
"node_modules/tailwindcss": {
|
||||||
"version": "4.1.7",
|
"version": "4.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.11.tgz",
|
||||||
"integrity": "sha512-kr1o/ErIdNhTz8uzAYL7TpaUuzKIE6QPQ4qmSdxnoX/lo+5wmUHQA6h3L5yIqEImSRnAAURDirLu/BgiXGPAhg==",
|
"integrity": "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/tapable": {
|
"node_modules/tapable": {
|
||||||
@ -11465,9 +11465,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/utopia-ui": {
|
"node_modules/utopia-ui": {
|
||||||
"version": "3.0.105",
|
"version": "3.0.111",
|
||||||
"resolved": "https://registry.npmjs.org/utopia-ui/-/utopia-ui-3.0.105.tgz",
|
"resolved": "https://registry.npmjs.org/utopia-ui/-/utopia-ui-3.0.111.tgz",
|
||||||
"integrity": "sha512-QihvnHeR0R9GXIZ/Mx1EBlsYBthhykM/jPdfN/5bHyyBAXGX0jm+6msEySo0jFWASxPr2G4rhImJJzeRxPyUhw==",
|
"integrity": "sha512-bUqgPCWyS3IcyegweXbRLt2SVYM9cWWLvLst9gcEaezfF4Egz4yXOq7mYmjBl+PpCt0d8EY6Tj8VhdfLxg63qg==",
|
||||||
"license": "GPL-3.0-only",
|
"license": "GPL-3.0-only",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@heroicons/react": "^2.0.17",
|
"@heroicons/react": "^2.0.17",
|
||||||
@ -11498,7 +11498,7 @@
|
|||||||
"react-leaflet-cluster": "^2.1.0",
|
"react-leaflet-cluster": "^2.1.0",
|
||||||
"react-markdown": "^9.0.1",
|
"react-markdown": "^9.0.1",
|
||||||
"react-photo-album": "^3.0.2",
|
"react-photo-album": "^3.0.2",
|
||||||
"react-router-dom": "^6.16.0",
|
"react-router-dom": "^6.23.0",
|
||||||
"react-toastify": "^9.1.3",
|
"react-toastify": "^9.1.3",
|
||||||
"remark-breaks": "^4.0.0",
|
"remark-breaks": "^4.0.0",
|
||||||
"tiptap-markdown": "^0.8.10",
|
"tiptap-markdown": "^0.8.10",
|
||||||
@ -20,8 +20,8 @@
|
|||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-rnd": "^10.4.1",
|
"react-rnd": "^10.4.1",
|
||||||
"react-router-dom": "^6.23.0",
|
"react-router-dom": "^6.23.0",
|
||||||
"utopia-ui": "^3.0.105",
|
"vite-tsconfig-paths": "^5.1.4",
|
||||||
"vite-tsconfig-paths": "^5.1.4"
|
"utopia-ui": "^3.0.111"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint-community/eslint-plugin-eslint-comments": "^4.4.1",
|
"@eslint-community/eslint-plugin-eslint-comments": "^4.4.1",
|
||||||
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 682 KiB After Width: | Height: | Size: 682 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 487 B After Width: | Height: | Size: 487 B |
@ -129,7 +129,7 @@ function App() {
|
|||||||
icon: (
|
icon: (
|
||||||
<SVG
|
<SVG
|
||||||
src={'https://api.utopia-lab.org/assets/' + l.indexIcon}
|
src={'https://api.utopia-lab.org/assets/' + l.indexIcon}
|
||||||
className='w-6 h-6'
|
className='tw:w-6 tw:h-6'
|
||||||
preProcessor={(code: string) =>
|
preProcessor={(code: string) =>
|
||||||
code.replace(/stroke=".*?"/g, 'stroke="currentColor"')
|
code.replace(/stroke=".*?"/g, 'stroke="currentColor"')
|
||||||
}
|
}
|
||||||
@ -160,7 +160,7 @@ function App() {
|
|||||||
|
|
||||||
if (map && layers)
|
if (map && layers)
|
||||||
return (
|
return (
|
||||||
<div className='App overflow-x-hidden'>
|
<div className='App tw:overflow-x-hidden'>
|
||||||
<AuthProvider userApi={userApi} inviteApi={inviteApi}>
|
<AuthProvider userApi={userApi} inviteApi={inviteApi}>
|
||||||
<AppShell
|
<AppShell
|
||||||
assetsApi={new assetsApi('https://api.utopia-lab.org/assets/')}
|
assetsApi={new assetsApi('https://api.utopia-lab.org/assets/')}
|
||||||
@ -253,18 +253,18 @@ function App() {
|
|||||||
)
|
)
|
||||||
else if (map == 'null' && !loading)
|
else if (map == 'null' && !loading)
|
||||||
return (
|
return (
|
||||||
<div className='flex items-center justify-center h-screen'>
|
<div className='tw:flex tw:items-center tw:justify-center tw:h-screen'>
|
||||||
<div>
|
<div>
|
||||||
<p className='text-xl font-semibold'>This map does not exist</p>
|
<p className='tw:text-xl tw:font-semibold'>This map does not exist</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
return (
|
return (
|
||||||
<div className='outer'>
|
<div className='outer'>
|
||||||
<img className='pulse-loader opacity h-[96px]' src='/3markers-globe.svg' />
|
<img className='pulse-loader tw-h-[96px]' src='/3markers-globe.svg' />
|
||||||
<br />
|
<br />
|
||||||
<span className='loader'></span>
|
<span className='tw:loader'></span>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -2,13 +2,12 @@
|
|||||||
/* eslint-disable @typescript-eslint/restrict-plus-operands */
|
/* eslint-disable @typescript-eslint/restrict-plus-operands */
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { TextView } from 'utopia-ui'
|
import { TextView } from 'utopia-ui'
|
||||||
|
|
||||||
interface ChapterProps {
|
interface ChapterProps {
|
||||||
clickAction1?: () => void
|
clickAction1: () => void
|
||||||
clickAction2?: () => void
|
|
||||||
map?: any
|
map?: any
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,20 +20,23 @@ export function Welcome1({ clickAction1, map }: ChapterProps) {
|
|||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<h3 className='font-bold text-lg'>Welcome to {map?.name || 'Utopia Map'}</h3>
|
<h3 className='tw:font-bold tw:text-lg'>Welcome to {map?.name || 'Utopia Map'}</h3>
|
||||||
<img
|
<img
|
||||||
className='float-right w-32 m-2'
|
className='tw:float-right tw:w-32 tw:m-2'
|
||||||
src={'https://api.utopia-lab.org/assets/' + map.logo}
|
src={'https://api.utopia-lab.org/assets/' + map.logo}
|
||||||
></img>
|
></img>
|
||||||
<p className='py-3'>
|
<p className='tw:py-3'>
|
||||||
It is a tool for collaborative mapping to connect local initiatives, people and events.
|
It is a tool for collaborative mapping to connect local initiatives, people and events.
|
||||||
</p>
|
</p>
|
||||||
<p className='py-1'>
|
<p className='tw:py-1'>
|
||||||
Join us and grow the network by adding projects and events to the map.
|
Join us and grow the network by adding projects and events to the map.
|
||||||
</p>
|
</p>
|
||||||
<p className='py-1'>Create your personal profile and place it on the map.</p>
|
<p className='tw:py-1'>Create your personal profile and place it on the map.</p>
|
||||||
<div className='grid'>
|
<div className='tw:grid'>
|
||||||
<label className='btn btn-primary place-self-end mt-4' onClick={() => clickAction1!()}>
|
<label
|
||||||
|
className='tw:btn tw:btn-primary tw:place-self-end tw:mt-4'
|
||||||
|
onClick={() => clickAction1()}
|
||||||
|
>
|
||||||
Close
|
Close
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@ -5,4 +5,7 @@
|
|||||||
|
|
||||||
@theme {
|
@theme {
|
||||||
--animate-fade: fadeOut 1s ease-in-out;
|
--animate-fade: fadeOut 1s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@import 'tailwindcss' prefix(tw);
|
||||||
|
@source '../../lib/src/';
|
||||||
@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable import/default */
|
|
||||||
/* eslint-disable import/extensions */
|
/* eslint-disable import/extensions */
|
||||||
/* eslint-disable import/no-named-as-default-member */
|
/* eslint-disable import/no-named-as-default-member */
|
||||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||||
@ -84,6 +84,8 @@ function MapContainer({ layers, map }: { layers: LayerProps[]; map: any }) {
|
|||||||
defaultTheme={map.default_theme}
|
defaultTheme={map.default_theme}
|
||||||
showZoomControl={map.show_zoom_control}
|
showZoomControl={map.show_zoom_control}
|
||||||
expandLayerControl={map.expand_layer_control}
|
expandLayerControl={map.expand_layer_control}
|
||||||
|
tileServerUrl={map.tile_server_url}
|
||||||
|
tileServerAttribution={map.tile_server_attribution}
|
||||||
>
|
>
|
||||||
{layers &&
|
{layers &&
|
||||||
apis &&
|
apis &&
|
||||||
@ -124,11 +126,11 @@ function MapContainer({ layers, map }: { layers: LayerProps[]; map: any }) {
|
|||||||
<PopupStartEndInput showLabels={false}></PopupStartEndInput>
|
<PopupStartEndInput showLabels={false}></PopupStartEndInput>
|
||||||
)}
|
)}
|
||||||
{layer.itemType.show_text_input && (
|
{layer.itemType.show_text_input && (
|
||||||
<div className='mt-4'>
|
<div className='tw:mt-4'>
|
||||||
<PopupTextAreaInput
|
<PopupTextAreaInput
|
||||||
dataField='text'
|
dataField='text'
|
||||||
placeholder={'Text ...'}
|
placeholder={'Text ...'}
|
||||||
style='tw-h-40'
|
style='tw:h-40'
|
||||||
></PopupTextAreaInput>
|
></PopupTextAreaInput>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@ -136,7 +138,7 @@ function MapContainer({ layers, map }: { layers: LayerProps[]; map: any }) {
|
|||||||
// layer.public_edit_items && <PopupCheckboxInput dataField={'public_edit'} label={'public edit'}/>
|
// layer.public_edit_items && <PopupCheckboxInput dataField={'public_edit'} label={'public edit'}/>
|
||||||
}
|
}
|
||||||
{layer.itemType.custom_text && (
|
{layer.itemType.custom_text && (
|
||||||
<div className='flex justify-center'>
|
<div className='tw:flex tw:justify-center'>
|
||||||
<p>{layer.itemType.custom_text}</p>
|
<p>{layer.itemType.custom_text}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@ -1,6 +1,8 @@
|
|||||||
import { MapIcon } from '@heroicons/react/24/outline'
|
import { MapIcon } from '@heroicons/react/24/outline'
|
||||||
import { SVG } from 'utopia-ui'
|
import { SVG } from 'utopia-ui'
|
||||||
|
|
||||||
|
import type { Route } from '#components/AppShell/SideBar'
|
||||||
|
|
||||||
export const routes = [
|
export const routes = [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
@ -43,7 +45,7 @@ export const getBottomRoutes = (currentUrl: string) => {
|
|||||||
const url = new URL(currentUrl)
|
const url = new URL(currentUrl)
|
||||||
const isEmbedded = url.searchParams.get('embedded') === 'true'
|
const isEmbedded = url.searchParams.get('embedded') === 'true'
|
||||||
|
|
||||||
const bottomRoutes = [
|
const bottomRoutes: Route[] = [
|
||||||
// Other routes can be added here
|
// Other routes can be added here
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -51,13 +53,13 @@ export const getBottomRoutes = (currentUrl: string) => {
|
|||||||
bottomRoutes.push(
|
bottomRoutes.push(
|
||||||
{
|
{
|
||||||
path: 'https://github.com/utopia-os/utopia-ui', // url
|
path: 'https://github.com/utopia-os/utopia-ui', // url
|
||||||
icon: <SVG src='/github.svg' className='w-6 h-6' />,
|
icon: <SVG src='/github.svg' className='tw:w-6 tw:h-6' />,
|
||||||
name: 'GitHub', // name that appear in Sidebar
|
name: 'GitHub', // name that appear in Sidebar
|
||||||
blank: true,
|
blank: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'https://opencollective.com/utopia-project', // url
|
path: 'https://opencollective.com/utopia-project', // url
|
||||||
icon: <SVG src='/opencollective.svg' className='w-6 h-6' />,
|
icon: <SVG src='/opencollective.svg' className='tw:w-6 tw:h-6' />,
|
||||||
name: 'Open Collective', // name that appear in Sidebar
|
name: 'Open Collective', // name that appear in Sidebar
|
||||||
blank: true,
|
blank: true,
|
||||||
},
|
},
|
||||||
49
app/tsconfig.json
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"@/*": [
|
||||||
|
"src/*"
|
||||||
|
],
|
||||||
|
"utopia-ui": [
|
||||||
|
"../lib/src"
|
||||||
|
],
|
||||||
|
"#components/*": [
|
||||||
|
"../lib/src/Components/*"
|
||||||
|
],
|
||||||
|
"#utils/*": [
|
||||||
|
"../lib/src/Utils/*"
|
||||||
|
],
|
||||||
|
"#types/*": [
|
||||||
|
"../lib/src/types/*"
|
||||||
|
],
|
||||||
|
"#assets/*": [
|
||||||
|
"../lib/src/assets/*"
|
||||||
|
],
|
||||||
|
"#src/*": [
|
||||||
|
"../lib/src/*"
|
||||||
|
],
|
||||||
|
"#root/*": [
|
||||||
|
"../lib/*"
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src"
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.node.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 535 KiB After Width: | Height: | Size: 535 KiB |
61
app/vite.config.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import react from '@vitejs/plugin-react'
|
||||||
|
import tailwindcss from '@tailwindcss/vite'
|
||||||
|
import fs from 'fs'
|
||||||
|
import path from 'path'
|
||||||
|
import tsConfigPaths from 'vite-tsconfig-paths'
|
||||||
|
|
||||||
|
// __dirname-Ersatz für ESModules
|
||||||
|
const __dirname = path.dirname(new URL(import.meta.url).pathname)
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
server: {
|
||||||
|
host: true,
|
||||||
|
port: 5174,
|
||||||
|
/**
|
||||||
|
* https: {
|
||||||
|
* key: fs.readFileSync(path.resolve(__dirname, 'localhost-key.pem')),
|
||||||
|
* cert: fs.readFileSync(path.resolve(__dirname, 'localhost-cert.pem')),
|
||||||
|
* },
|
||||||
|
*/
|
||||||
|
},
|
||||||
|
plugins: [react(), tailwindcss(), tsConfigPaths()],
|
||||||
|
resolve: {
|
||||||
|
dedupe: ['react', 'react-dom', 'react-router-dom'],
|
||||||
|
alias: {
|
||||||
|
'utopia-ui': path.resolve(__dirname, '../lib/src'),
|
||||||
|
'#components': path.resolve(__dirname, '../lib/src/Components'),
|
||||||
|
'#utils': path.resolve(__dirname, '../lib/src/Utils'),
|
||||||
|
'#types': path.resolve(__dirname, '../lib/src/types'),
|
||||||
|
'#assets': path.resolve(__dirname, '../lib/src/assets'),
|
||||||
|
'#src': path.resolve(__dirname, '../lib/src'),
|
||||||
|
'#root': path.resolve(__dirname, '../lib'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
build: {
|
||||||
|
sourcemap: true,
|
||||||
|
rollupOptions: {
|
||||||
|
output: {
|
||||||
|
manualChunks: (id) => {
|
||||||
|
if (id.includes('lib/src')) {
|
||||||
|
return 'utopia-ui'
|
||||||
|
}
|
||||||
|
if (id.includes('node_modules')) {
|
||||||
|
if (id.includes('react')) {
|
||||||
|
return 'react'
|
||||||
|
}
|
||||||
|
if (id.includes('tiptap')) {
|
||||||
|
return 'tiptap'
|
||||||
|
}
|
||||||
|
if (id.includes('leaflet')) {
|
||||||
|
return 'leaflet'
|
||||||
|
}
|
||||||
|
if (id.includes('lib/node_modules')) {
|
||||||
|
return 'utopia-ui-vendor'
|
||||||
|
} else return 'vendor'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
@ -1,4 +1,4 @@
|
|||||||
In order to pull data from your locally running backend (see [docker-compose](../docker-compose.yml)) to your local harddrive, you can run the following command
|
In order to pull data from your locally running backend (see [docker-compose](../app/docker-compose.yml)) to your local harddrive, you can run the following command
|
||||||
|
|
||||||
```
|
```
|
||||||
npx directus-sync pull \
|
npx directus-sync pull \
|
||||||
|
|||||||
@ -1,98 +0,0 @@
|
|||||||
/* eslint-disable import/default */
|
|
||||||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
|
||||||
import { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/24/outline'
|
|
||||||
import {
|
|
||||||
add,
|
|
||||||
eachDayOfInterval,
|
|
||||||
endOfMonth,
|
|
||||||
endOfWeek,
|
|
||||||
format,
|
|
||||||
getDay,
|
|
||||||
isSameMonth,
|
|
||||||
isToday,
|
|
||||||
parse,
|
|
||||||
startOfToday,
|
|
||||||
startOfWeek,
|
|
||||||
} from 'date-fns'
|
|
||||||
import React, { useState } from 'react'
|
|
||||||
import { MapOverlayPage } from 'utopia-ui'
|
|
||||||
|
|
||||||
export const Calendar = () => {
|
|
||||||
const today = startOfToday()
|
|
||||||
const days = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']
|
|
||||||
const colStartClasses = [
|
|
||||||
'',
|
|
||||||
'col-start-2',
|
|
||||||
'col-start-3',
|
|
||||||
'col-start-4',
|
|
||||||
'col-start-5',
|
|
||||||
'col-start-6',
|
|
||||||
'col-start-7',
|
|
||||||
]
|
|
||||||
|
|
||||||
const [currMonth, setCurrMonth] = useState(() => format(today, 'MMM-yyyy'))
|
|
||||||
const firstDayOfMonth = parse(currMonth, 'MMM-yyyy', new Date())
|
|
||||||
|
|
||||||
const daysInMonth = eachDayOfInterval({
|
|
||||||
start: startOfWeek(firstDayOfMonth),
|
|
||||||
end: endOfWeek(endOfMonth(firstDayOfMonth)),
|
|
||||||
})
|
|
||||||
|
|
||||||
const getPrevMonth = (event: React.MouseEvent<SVGSVGElement>) => {
|
|
||||||
event.preventDefault()
|
|
||||||
const firstDayOfPrevMonth = add(firstDayOfMonth, { months: -1 })
|
|
||||||
setCurrMonth(format(firstDayOfPrevMonth, 'MMM-yyyy'))
|
|
||||||
}
|
|
||||||
|
|
||||||
const getNextMonth = (event: React.MouseEvent<SVGSVGElement>) => {
|
|
||||||
event.preventDefault()
|
|
||||||
const firstDayOfNextMonth = add(firstDayOfMonth, { months: 1 })
|
|
||||||
setCurrMonth(format(firstDayOfNextMonth, 'MMM-yyyy'))
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MapOverlayPage
|
|
||||||
backdrop
|
|
||||||
className='tw-max-h-[calc(100dvh-96px)] tw-h-fit md:tw-w-[calc(50%-32px)] tw-w-[calc(100%-32px)] max-w-lg'
|
|
||||||
>
|
|
||||||
<div className='flex items-center justify-between'>
|
|
||||||
<p className='font-semibold text-xl'>{format(firstDayOfMonth, 'MMMM yyyy')}</p>
|
|
||||||
<div className='flex items-center justify-evenly gap-6 sm:gap-12'>
|
|
||||||
<ChevronLeftIcon className='w-6 h-6 cursor-pointer' onClick={getPrevMonth} />
|
|
||||||
<ChevronRightIcon className='w-6 h-6 cursor-pointer' onClick={getNextMonth} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr className='my-6' />
|
|
||||||
<div className='grid grid-cols-7 gap-6 sm:gap-12 place-items-center'>
|
|
||||||
{days.map((day, idx) => {
|
|
||||||
return (
|
|
||||||
<div key={idx} className='font-semibold'>
|
|
||||||
{capitalizeFirstLetter(day)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
<div className='grid grid-cols-7 gap-4 sm:gap-12 mt-8 place-items-center'>
|
|
||||||
{daysInMonth.map((day, idx) => {
|
|
||||||
return (
|
|
||||||
<div key={idx} className={colStartClasses[getDay(day)]}>
|
|
||||||
<p
|
|
||||||
className={`cursor-pointer flex items-center justify-center font-semibold h-8 w-8 rounded-full hover:text-white ${
|
|
||||||
isSameMonth(day, today) ? 'text-current' : 'text-gray-500'
|
|
||||||
} ${!isToday(day) && 'hover:bg-primary-content'} ${
|
|
||||||
isToday(day) && 'bg-primary text-white!'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{format(day, 'd')}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</MapOverlayPage>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const capitalizeFirstLetter = (string: string) => {
|
|
||||||
return string
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "ESNext",
|
|
||||||
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
|
||||||
"module": "ESNext",
|
|
||||||
"skipLibCheck": true,
|
|
||||||
|
|
||||||
/* Bundler mode */
|
|
||||||
"moduleResolution": "bundler",
|
|
||||||
"allowImportingTsExtensions": true,
|
|
||||||
"resolveJsonModule": true,
|
|
||||||
"isolatedModules": true,
|
|
||||||
"noEmit": true,
|
|
||||||
"jsx": "react-jsx",
|
|
||||||
|
|
||||||
/* Linting */
|
|
||||||
"strict": true,
|
|
||||||
"noUnusedLocals": true,
|
|
||||||
"noUnusedParameters": true,
|
|
||||||
"noFallthroughCasesInSwitch": true,
|
|
||||||
|
|
||||||
/* Paths */
|
|
||||||
"baseUrl": ".",
|
|
||||||
"paths": {
|
|
||||||
"@/*": ["src/*"],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"include": ["src"],
|
|
||||||
"references": [{ "path": "./tsconfig.node.json" }]
|
|
||||||
}
|
|
||||||
@ -1,42 +0,0 @@
|
|||||||
import { defineConfig } from 'vite'
|
|
||||||
import react from '@vitejs/plugin-react'
|
|
||||||
import tailwindcss from '@tailwindcss/vite'
|
|
||||||
import tsConfigPaths from 'vite-tsconfig-paths'
|
|
||||||
import fs from 'fs'
|
|
||||||
import path from 'path'
|
|
||||||
|
|
||||||
// __dirname-Ersatz für ESModules
|
|
||||||
const __dirname = path.dirname(new URL(import.meta.url).pathname)
|
|
||||||
|
|
||||||
export default defineConfig({
|
|
||||||
server: {
|
|
||||||
host: true,
|
|
||||||
port: 5174,
|
|
||||||
/**
|
|
||||||
* https: {
|
|
||||||
* key: fs.readFileSync(path.resolve(__dirname, 'localhost-key.pem')),
|
|
||||||
* cert: fs.readFileSync(path.resolve(__dirname, 'localhost-cert.pem')),
|
|
||||||
* },
|
|
||||||
*/
|
|
||||||
},
|
|
||||||
plugins: [react(), tailwindcss(), tsConfigPaths()],
|
|
||||||
build: {
|
|
||||||
rollupOptions: {
|
|
||||||
output: {
|
|
||||||
manualChunks(id) {
|
|
||||||
if (id.includes('node_modules/utopia-ui/dist/Profile') && /\.(esm|cjs)\.js$/.test(id)) {
|
|
||||||
return 'profile-form'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id.includes('node_modules/utopia-ui/')) {
|
|
||||||
return 'utopia-ui-vendor'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id.includes('node_modules/')) {
|
|
||||||
return 'vendor'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
6
lib/package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "utopia-ui",
|
"name": "utopia-ui",
|
||||||
"version": "3.0.106",
|
"version": "3.0.111",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "utopia-ui",
|
"name": "utopia-ui",
|
||||||
"version": "3.0.106",
|
"version": "3.0.111",
|
||||||
"license": "GPL-3.0-only",
|
"license": "GPL-3.0-only",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@heroicons/react": "^2.0.17",
|
"@heroicons/react": "^2.0.17",
|
||||||
@ -38,7 +38,7 @@
|
|||||||
"react-markdown": "^9.0.1",
|
"react-markdown": "^9.0.1",
|
||||||
"react-photo-album": "^3.0.2",
|
"react-photo-album": "^3.0.2",
|
||||||
"react-qr-code": "^2.0.16",
|
"react-qr-code": "^2.0.16",
|
||||||
"react-router-dom": "^6.16.0",
|
"react-router-dom": "^6.23.0",
|
||||||
"react-toastify": "^9.1.3",
|
"react-toastify": "^9.1.3",
|
||||||
"remark-breaks": "^4.0.0",
|
"remark-breaks": "^4.0.0",
|
||||||
"tiptap-markdown": "^0.8.10",
|
"tiptap-markdown": "^0.8.10",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "utopia-ui",
|
"name": "utopia-ui",
|
||||||
"version": "3.0.106",
|
"version": "3.0.111",
|
||||||
"description": "Reuseable React Components to build mapping apps for real life communities and networks",
|
"description": "Reuseable React Components to build mapping apps for real life communities and networks",
|
||||||
"repository": "https://github.com/utopia-os/utopia-ui",
|
"repository": "https://github.com/utopia-os/utopia-ui",
|
||||||
"homepage": "https://utopia-os.org/",
|
"homepage": "https://utopia-os.org/",
|
||||||
@ -126,7 +126,7 @@
|
|||||||
"react-markdown": "^9.0.1",
|
"react-markdown": "^9.0.1",
|
||||||
"react-photo-album": "^3.0.2",
|
"react-photo-album": "^3.0.2",
|
||||||
"react-qr-code": "^2.0.16",
|
"react-qr-code": "^2.0.16",
|
||||||
"react-router-dom": "^6.16.0",
|
"react-router-dom": "^6.23.0",
|
||||||
"react-toastify": "^9.1.3",
|
"react-toastify": "^9.1.3",
|
||||||
"remark-breaks": "^4.0.0",
|
"remark-breaks": "^4.0.0",
|
||||||
"tiptap-markdown": "^0.8.10",
|
"tiptap-markdown": "^0.8.10",
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
export { AuthProvider, UserApi, UserItem } from './useAuth'
|
export { AuthProvider } 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'
|
||||||
export { SetNewPasswordPage } from './SetNewPasswordPage'
|
export { SetNewPasswordPage } from './SetNewPasswordPage'
|
||||||
|
export type { UserItem } from '#types/UserItem'
|
||||||
|
export type { UserApi } from '#types/UserApi'
|
||||||
|
|||||||
@ -4,9 +4,6 @@ import type { InviteApi } from '#types/InviteApi'
|
|||||||
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
|
||||||
inviteApi: InviteApi
|
inviteApi: InviteApi
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||||
@ -35,8 +34,6 @@ export const Autocomplete = ({
|
|||||||
|
|
||||||
const inputRef = useRef<HTMLInputElement>()
|
const inputRef = useRef<HTMLInputElement>()
|
||||||
|
|
||||||
const getSuggestionValue = (suggestion) => suggestion.name
|
|
||||||
|
|
||||||
const getSuggestions = (value) => {
|
const getSuggestions = (value) => {
|
||||||
const inputValue = value.trim().toLowerCase()
|
const inputValue = value.trim().toLowerCase()
|
||||||
const inputLength = inputValue.length
|
const inputLength = inputValue.length
|
||||||
|
|||||||
9
lib/src/Components/Input/InputLabel.tsx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export const InputLabel = ({ label }: { label: string }) => {
|
||||||
|
return (
|
||||||
|
<label className='tw:label tw:pb-1'>
|
||||||
|
<span className='tw:block tw:text-sm tw:font-medium tw:text-base-content/50 tw:mb-1'>
|
||||||
|
{label}:
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -10,6 +10,7 @@ import { StarterKit } from '@tiptap/starter-kit'
|
|||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { Markdown } from 'tiptap-markdown'
|
import { Markdown } from 'tiptap-markdown'
|
||||||
|
|
||||||
|
import { InputLabel } from './InputLabel'
|
||||||
import { TextEditorMenu } from './TextEditorMenu'
|
import { TextEditorMenu } from './TextEditorMenu'
|
||||||
|
|
||||||
interface RichTextEditorProps {
|
interface RichTextEditorProps {
|
||||||
@ -27,7 +28,6 @@ interface RichTextEditorProps {
|
|||||||
*/
|
*/
|
||||||
export function RichTextEditor({
|
export function RichTextEditor({
|
||||||
labelTitle,
|
labelTitle,
|
||||||
labelStyle,
|
|
||||||
containerStyle,
|
containerStyle,
|
||||||
defaultValue,
|
defaultValue,
|
||||||
placeholder,
|
placeholder,
|
||||||
@ -88,13 +88,7 @@ export function RichTextEditor({
|
|||||||
<div
|
<div
|
||||||
className={`tw:form-control tw:w-full tw:flex tw:flex-col tw:min-h-0 ${containerStyle ?? ''}`}
|
className={`tw:form-control tw:w-full tw:flex tw:flex-col tw:min-h-0 ${containerStyle ?? ''}`}
|
||||||
>
|
>
|
||||||
{labelTitle ? (
|
{labelTitle ? <InputLabel label={labelTitle} /> : null}
|
||||||
<label className='tw:label tw:pb-1'>
|
|
||||||
<span className={`tw:label-text tw:text-base-content ${labelStyle ?? ''}`}>
|
|
||||||
{labelTitle}
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
) : null}
|
|
||||||
<div
|
<div
|
||||||
className={`editor-wrapper tw:border-base-content/20 tw:rounded-box tw:border tw:flex tw:flex-col tw:flex-1 tw:min-h-0`}
|
className={`editor-wrapper tw:border-base-content/20 tw:rounded-box tw:border tw:flex tw:flex-col tw:flex-1 tw:min-h-0`}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
|
|
||||||
|
import { InputLabel } from './InputLabel'
|
||||||
|
|
||||||
interface TextAreaProps {
|
interface TextAreaProps {
|
||||||
labelTitle?: string
|
labelTitle?: string
|
||||||
labelStyle?: string
|
|
||||||
containerStyle?: string
|
containerStyle?: string
|
||||||
dataField?: string
|
dataField?: string
|
||||||
inputStyle?: string
|
inputStyle?: string
|
||||||
@ -18,7 +19,6 @@ interface TextAreaProps {
|
|||||||
export function TextAreaInput({
|
export function TextAreaInput({
|
||||||
labelTitle,
|
labelTitle,
|
||||||
dataField,
|
dataField,
|
||||||
labelStyle,
|
|
||||||
containerStyle,
|
containerStyle,
|
||||||
inputStyle,
|
inputStyle,
|
||||||
defaultValue,
|
defaultValue,
|
||||||
@ -43,13 +43,7 @@ export function TextAreaInput({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`tw:form-control tw:w-full ${containerStyle ?? ''}`}>
|
<div className={`tw:form-control tw:w-full ${containerStyle ?? ''}`}>
|
||||||
{labelTitle ? (
|
{labelTitle ? <InputLabel label={labelTitle} /> : null}
|
||||||
<label className='tw:label'>
|
|
||||||
<span className={`tw:label-text tw:text-base-content ${labelStyle ?? ''}`}>
|
|
||||||
{labelTitle}
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
) : null}
|
|
||||||
<textarea
|
<textarea
|
||||||
required={required}
|
required={required}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
import { InputLabel } from './InputLabel'
|
||||||
|
|
||||||
interface InputTextProps {
|
interface InputTextProps {
|
||||||
labelTitle?: string
|
labelTitle?: string
|
||||||
labelStyle?: string
|
|
||||||
type?: string
|
type?: string
|
||||||
dataField?: string
|
dataField?: string
|
||||||
containerStyle?: string
|
containerStyle?: string
|
||||||
@ -20,7 +21,6 @@ interface InputTextProps {
|
|||||||
*/
|
*/
|
||||||
export function TextInput({
|
export function TextInput({
|
||||||
labelTitle,
|
labelTitle,
|
||||||
labelStyle,
|
|
||||||
type,
|
type,
|
||||||
dataField,
|
dataField,
|
||||||
containerStyle,
|
containerStyle,
|
||||||
@ -48,13 +48,7 @@ export function TextInput({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`tw:form-control ${containerStyle ?? ''}`}>
|
<div className={`tw:form-control ${containerStyle ?? ''}`}>
|
||||||
{labelTitle ? (
|
{labelTitle ? <InputLabel label={labelTitle} /> : null}
|
||||||
<label className='tw:label'>
|
|
||||||
<span className={`tw:label-text tw:text-base-content ${labelStyle ?? ''}`}>
|
|
||||||
{labelTitle}
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
) : null}
|
|
||||||
<input
|
<input
|
||||||
required={required}
|
required={required}
|
||||||
pattern={pattern}
|
pattern={pattern}
|
||||||
|
|||||||
@ -5,12 +5,13 @@ exports[`<TextAreaInput /> > labelTitle > sets label 1`] = `
|
|||||||
class="tw:form-control tw:w-full "
|
class="tw:form-control tw:w-full "
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
class="tw:label"
|
class="tw:label tw:pb-1"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="tw:label-text tw:text-base-content "
|
class="tw:block tw:text-sm tw:font-medium tw:text-base-content/50 tw:mb-1"
|
||||||
>
|
>
|
||||||
My Title
|
My Title
|
||||||
|
:
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<textarea
|
<textarea
|
||||||
|
|||||||
@ -5,12 +5,13 @@ exports[`<TextInput /> > labelTitle > sets label 1`] = `
|
|||||||
class="tw:form-control "
|
class="tw:form-control "
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
class="tw:label"
|
class="tw:label tw:pb-1"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="tw:label-text tw:text-base-content "
|
class="tw:block tw:text-sm tw:font-medium tw:text-base-content/50 tw:mb-1"
|
||||||
>
|
>
|
||||||
My Title
|
My Title
|
||||||
|
:
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
|
|||||||
@ -1,2 +1,4 @@
|
|||||||
export { TextAreaInput } from './TextAreaInput'
|
export { TextAreaInput } from './TextAreaInput'
|
||||||
export { TextInput } from './TextInput'
|
export { TextInput } from './TextInput'
|
||||||
|
export { InputLabel } from './InputLabel'
|
||||||
|
export { RichTextEditor } from './RichTextEditor'
|
||||||
|
|||||||
@ -74,7 +74,7 @@ export function HeaderView({
|
|||||||
<>
|
<>
|
||||||
<div className='tw:flex tw:flex-row'>
|
<div className='tw:flex tw:flex-row'>
|
||||||
<div className={'tw:grow tw:max-w-[calc(100%-60px)] }'}>
|
<div className={'tw:grow tw:max-w-[calc(100%-60px)] }'}>
|
||||||
<div className='flex items-center'>
|
<div className='tw:flex tw:items-center'>
|
||||||
{avatar && (
|
{avatar && (
|
||||||
<div className='tw:avatar'>
|
<div className='tw:avatar'>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import type { Item } from '#types/Item'
|
|||||||
export interface StartEndInputProps {
|
export interface StartEndInputProps {
|
||||||
item?: Item
|
item?: Item
|
||||||
showLabels?: boolean
|
showLabels?: boolean
|
||||||
labelStyle?: string
|
|
||||||
updateStartValue?: (value: string) => void
|
updateStartValue?: (value: string) => void
|
||||||
updateEndValue?: (value: string) => void
|
updateEndValue?: (value: string) => void
|
||||||
containerStyle?: string
|
containerStyle?: string
|
||||||
@ -18,7 +17,6 @@ export interface StartEndInputProps {
|
|||||||
export const PopupStartEndInput = ({
|
export const PopupStartEndInput = ({
|
||||||
item,
|
item,
|
||||||
showLabels = true,
|
showLabels = true,
|
||||||
labelStyle,
|
|
||||||
updateStartValue,
|
updateStartValue,
|
||||||
updateEndValue,
|
updateEndValue,
|
||||||
containerStyle,
|
containerStyle,
|
||||||
@ -31,7 +29,6 @@ export const PopupStartEndInput = ({
|
|||||||
dataField='start'
|
dataField='start'
|
||||||
inputStyle='tw:text-sm tw:px-2'
|
inputStyle='tw:text-sm tw:px-2'
|
||||||
labelTitle={showLabels ? 'Start' : ''}
|
labelTitle={showLabels ? 'Start' : ''}
|
||||||
labelStyle={labelStyle}
|
|
||||||
defaultValue={item && item.start ? item.start.substring(0, 10) : ''}
|
defaultValue={item && item.start ? item.start.substring(0, 10) : ''}
|
||||||
autocomplete='one-time-code'
|
autocomplete='one-time-code'
|
||||||
updateFormValue={updateStartValue}
|
updateFormValue={updateStartValue}
|
||||||
@ -42,7 +39,6 @@ export const PopupStartEndInput = ({
|
|||||||
dataField='end'
|
dataField='end'
|
||||||
inputStyle='tw:text-sm tw:px-2'
|
inputStyle='tw:text-sm tw:px-2'
|
||||||
labelTitle={showLabels ? 'End' : ''}
|
labelTitle={showLabels ? 'End' : ''}
|
||||||
labelStyle={labelStyle}
|
|
||||||
defaultValue={item && item.end ? item.end.substring(0, 10) : ''}
|
defaultValue={item && item.end ? item.end.substring(0, 10) : ''}
|
||||||
autocomplete='one-time-code'
|
autocomplete='one-time-code'
|
||||||
updateFormValue={updateEndValue}
|
updateFormValue={updateEndValue}
|
||||||
|
|||||||
@ -129,15 +129,17 @@ export const TextView = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Markdown
|
<div translate='no'>
|
||||||
className={'markdown tw:text-map tw:leading-map tw:text-sm'}
|
<Markdown
|
||||||
remarkPlugins={[remarkBreaks]}
|
className={'markdown tw:text-map tw:leading-map tw:text-sm'}
|
||||||
components={{
|
remarkPlugins={[remarkBreaks]}
|
||||||
a: Link,
|
components={{
|
||||||
}}
|
a: Link,
|
||||||
>
|
}}
|
||||||
{replacedText}
|
>
|
||||||
</Markdown>
|
{replacedText}
|
||||||
|
</Markdown>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -100,7 +100,7 @@ export const ItemViewPopup = forwardRef((props: ItemViewPopupProps, ref: any) =>
|
|||||||
}}
|
}}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
/>
|
/>
|
||||||
<div className='tw:overflow-y-auto tw:overflow-x-hidden tw:max-h-64 fade'>
|
<div className='tw:overflow-hidden tw:max-h-64 fade'>
|
||||||
{props.children ?? <TextView text={props.item.text} itemId={props.item.id} />}
|
{props.children ?? <TextView text={props.item.text} itemId={props.item.id} />}
|
||||||
</div>
|
</div>
|
||||||
<div className='tw:flex tw:-mb-1 tw:flex-row tw:mr-2 tw:mt-1'>
|
<div className='tw:flex tw:-mb-1 tw:flex-row tw:mr-2 tw:mt-1'>
|
||||||
|
|||||||
@ -20,7 +20,7 @@ export const SelectPosition = ({
|
|||||||
</label>
|
</label>
|
||||||
<div className='tw:alert tw:bg-base-100 tw:text-base-content'>
|
<div className='tw:alert tw:bg-base-100 tw:text-base-content'>
|
||||||
<div>
|
<div>
|
||||||
{selectNewItemPosition && 'text' in selectNewItemPosition && (
|
{selectNewItemPosition && 'layer' in selectNewItemPosition && (
|
||||||
<span className='tw:text-lg'>
|
<span className='tw:text-lg'>
|
||||||
Select new position of <b>{selectNewItemPosition.name}</b> on the map!
|
Select new position of <b>{selectNewItemPosition.name}</b> on the map!
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@ -56,6 +56,8 @@ function UtopiaMap({
|
|||||||
defaultTheme,
|
defaultTheme,
|
||||||
donationWidget,
|
donationWidget,
|
||||||
expandLayerControl,
|
expandLayerControl,
|
||||||
|
tileServerUrl,
|
||||||
|
tileServerAttribution,
|
||||||
}: {
|
}: {
|
||||||
/** height of the map (default '500px') */
|
/** height of the map (default '500px') */
|
||||||
height?: string
|
height?: string
|
||||||
@ -85,6 +87,10 @@ function UtopiaMap({
|
|||||||
donationWidget?: boolean
|
donationWidget?: boolean
|
||||||
/** open layer control on map initialisation */
|
/** open layer control on map initialisation */
|
||||||
expandLayerControl?: boolean
|
expandLayerControl?: boolean
|
||||||
|
/** configure a custom tile server */
|
||||||
|
tileServerUrl?: string
|
||||||
|
/** configure a custom tile server attribution */
|
||||||
|
tileServerAttribution?: string
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<ContextWrapper>
|
<ContextWrapper>
|
||||||
@ -104,6 +110,8 @@ function UtopiaMap({
|
|||||||
showThemeControl={showThemeControl}
|
showThemeControl={showThemeControl}
|
||||||
defaultTheme={defaultTheme}
|
defaultTheme={defaultTheme}
|
||||||
expandLayerControl={expandLayerControl}
|
expandLayerControl={expandLayerControl}
|
||||||
|
tileServerUrl={tileServerUrl}
|
||||||
|
tileServerAttribution={tileServerAttribution}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</UtopiaMapInner>
|
</UtopiaMapInner>
|
||||||
|
|||||||
@ -55,6 +55,8 @@ export function UtopiaMapInner({
|
|||||||
defaultTheme = '',
|
defaultTheme = '',
|
||||||
donationWidget,
|
donationWidget,
|
||||||
expandLayerControl,
|
expandLayerControl,
|
||||||
|
tileServerUrl,
|
||||||
|
tileServerAttribution,
|
||||||
}: {
|
}: {
|
||||||
children?: React.ReactNode
|
children?: React.ReactNode
|
||||||
geo?: GeoJsonObject
|
geo?: GeoJsonObject
|
||||||
@ -65,6 +67,8 @@ export function UtopiaMapInner({
|
|||||||
showThemeControl?: boolean
|
showThemeControl?: boolean
|
||||||
defaultTheme?: string
|
defaultTheme?: string
|
||||||
expandLayerControl?: boolean
|
expandLayerControl?: boolean
|
||||||
|
tileServerUrl?: string
|
||||||
|
tileServerAttribution?: string
|
||||||
}) {
|
}) {
|
||||||
const selectNewItemPosition = useSelectPosition()
|
const selectNewItemPosition = useSelectPosition()
|
||||||
const setSelectNewItemPosition = useSetSelectPosition()
|
const setSelectNewItemPosition = useSetSelectPosition()
|
||||||
@ -278,8 +282,11 @@ export function UtopiaMapInner({
|
|||||||
</Control>
|
</Control>
|
||||||
<TileLayer
|
<TileLayer
|
||||||
maxZoom={19}
|
maxZoom={19}
|
||||||
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
attribution={
|
||||||
url='https://tile.osmand.net/hd/{z}/{x}/{y}.png'
|
tileServerAttribution ??
|
||||||
|
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||||||
|
}
|
||||||
|
url={tileServerUrl ?? 'https://tile.osmand.net/hd/{z}/{x}/{y}.png'}
|
||||||
/>
|
/>
|
||||||
<MarkerClusterGroup
|
<MarkerClusterGroup
|
||||||
ref={(r) => setClusterRef(r as any)}
|
ref={(r) => setClusterRef(r as any)}
|
||||||
|
|||||||
@ -69,7 +69,7 @@ function useSelectPositionManager(): {
|
|||||||
})
|
})
|
||||||
setSelectPosition(null)
|
setSelectPosition(null)
|
||||||
}
|
}
|
||||||
if ('text' in selectPosition) {
|
if ('layer' in selectPosition) {
|
||||||
// if selectPosition is an Item
|
// if selectPosition is an Item
|
||||||
const position =
|
const position =
|
||||||
mapClicked?.position.lng &&
|
mapClicked?.position.lng &&
|
||||||
@ -101,9 +101,9 @@ function useSelectPositionManager(): {
|
|||||||
success = true
|
success = true
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
toast.update(toastId, { render: error.message, type: 'error' })
|
toast.update(toastId, { render: error.message, type: 'error', autoClose: 5000 })
|
||||||
} else if (typeof error === 'string') {
|
} else if (typeof error === 'string') {
|
||||||
toast.update(toastId, { render: error, type: 'error' })
|
toast.update(toastId, { render: error, type: 'error', autoClose: 5000 })
|
||||||
} else {
|
} else {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
@ -115,6 +115,7 @@ function useSelectPositionManager(): {
|
|||||||
render: 'Item position updated',
|
render: 'Item position updated',
|
||||||
type: 'success',
|
type: 'success',
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
|
autoClose: 5000,
|
||||||
})
|
})
|
||||||
setSelectPosition(null)
|
setSelectPosition(null)
|
||||||
setMarkerClicked(null)
|
setMarkerClicked(null)
|
||||||
@ -125,6 +126,8 @@ function useSelectPositionManager(): {
|
|||||||
render: "you don't have permission to add items to " + markerClicked?.name,
|
render: "you don't have permission to add items to " + markerClicked?.name,
|
||||||
type: 'error',
|
type: 'error',
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
|
autoClose: 5000,
|
||||||
|
closeButton: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -140,16 +143,34 @@ function useSelectPositionManager(): {
|
|||||||
success = true
|
success = true
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
toast.update(toastId, { render: error.message, type: 'error', isLoading: false })
|
toast.update(toastId, {
|
||||||
|
render: error.message,
|
||||||
|
type: 'error',
|
||||||
|
isLoading: false,
|
||||||
|
autoClose: 5000,
|
||||||
|
closeButton: true,
|
||||||
|
})
|
||||||
} else if (typeof error === 'string') {
|
} else if (typeof error === 'string') {
|
||||||
toast.update(toastId, { render: error, type: 'error', isLoading: false })
|
toast.update(toastId, {
|
||||||
|
render: error,
|
||||||
|
type: 'error',
|
||||||
|
isLoading: false,
|
||||||
|
autoClose: 5000,
|
||||||
|
closeButton: true,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (success) {
|
if (success) {
|
||||||
updateItem(updatedItem)
|
updateItem(updatedItem)
|
||||||
toast.update(toastId, { render: 'Item position updated', type: 'success', isLoading: false })
|
toast.update(toastId, {
|
||||||
|
render: 'Item position updated',
|
||||||
|
type: 'success',
|
||||||
|
isLoading: false,
|
||||||
|
autoClose: 5000,
|
||||||
|
closeButton: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,16 +189,34 @@ function useSelectPositionManager(): {
|
|||||||
success = true
|
success = true
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
toast.update(toastId, { render: error.message, type: 'error', isLoading: false })
|
toast.update(toastId, {
|
||||||
|
render: error.message,
|
||||||
|
type: 'error',
|
||||||
|
isLoading: false,
|
||||||
|
autoClose: 5000,
|
||||||
|
closeButton: true,
|
||||||
|
})
|
||||||
} else if (typeof error === 'string') {
|
} else if (typeof error === 'string') {
|
||||||
toast.update(toastId, { render: error, type: 'error', isLoading: false })
|
toast.update(toastId, {
|
||||||
|
render: error,
|
||||||
|
type: 'error',
|
||||||
|
isLoading: false,
|
||||||
|
autoClose: 5000,
|
||||||
|
closeButton: true,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (success) {
|
if (success) {
|
||||||
updateItem({ ...markerClicked, relations: newRelations })
|
updateItem({ ...markerClicked, relations: newRelations })
|
||||||
toast.update(toastId, { render: 'Item linked', type: 'success', isLoading: false })
|
toast.update(toastId, {
|
||||||
|
render: 'Item linked',
|
||||||
|
type: 'success',
|
||||||
|
isLoading: false,
|
||||||
|
autoClose: 5000,
|
||||||
|
closeButton: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { TextInput } from '#components/Input'
|
import { InputLabel, TextInput } from '#components/Input'
|
||||||
|
|
||||||
import type { FormState } from '#types/FormState'
|
import type { FormState } from '#types/FormState'
|
||||||
|
|
||||||
@ -12,12 +12,7 @@ export const ContactInfoForm = ({
|
|||||||
return (
|
return (
|
||||||
<div className='tw:mt-2 tw:space-y-2'>
|
<div className='tw:mt-2 tw:space-y-2'>
|
||||||
<div>
|
<div>
|
||||||
<label
|
<InputLabel label='Email-Adresse (Kontakt)' />
|
||||||
htmlFor='email'
|
|
||||||
className='tw:block tw:text-sm tw:font-medium tw:text-gray-500 tw:mb-1'
|
|
||||||
>
|
|
||||||
Email-Adresse (Kontakt):
|
|
||||||
</label>
|
|
||||||
<TextInput
|
<TextInput
|
||||||
placeholder='Email'
|
placeholder='Email'
|
||||||
type='email'
|
type='email'
|
||||||
@ -33,12 +28,7 @@ export const ContactInfoForm = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label
|
<InputLabel label='Telefonnummer (Kontakt)' />
|
||||||
htmlFor='telephone'
|
|
||||||
className='tw:block tw:text-sm tw:font-medium tw:text-gray-500 tw:mb-1'
|
|
||||||
>
|
|
||||||
Telefonnummer (Kontakt):
|
|
||||||
</label>
|
|
||||||
<TextInput
|
<TextInput
|
||||||
placeholder='Telefonnummer'
|
placeholder='Telefonnummer'
|
||||||
type='tel'
|
type='tel'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { TextInput } from '#components/Input'
|
import { TextInput, InputLabel } from '#components/Input'
|
||||||
|
|
||||||
import type { FormState } from '#types/FormState'
|
import type { FormState } from '#types/FormState'
|
||||||
|
|
||||||
@ -12,12 +12,7 @@ export const CrowdfundingForm = ({
|
|||||||
return (
|
return (
|
||||||
<div className='tw:mt-4 tw:space-y-4'>
|
<div className='tw:mt-4 tw:space-y-4'>
|
||||||
<div>
|
<div>
|
||||||
<label
|
<InputLabel label='Open Collective Slug' />
|
||||||
htmlFor='OpenCollectiveSlug'
|
|
||||||
className='tw:block tw:text-sm tw:font-medium tw:text-gray-500 tw:mb-1'
|
|
||||||
>
|
|
||||||
Open Collective Slug:
|
|
||||||
</label>
|
|
||||||
<TextInput
|
<TextInput
|
||||||
placeholder='Open Collective Slug'
|
placeholder='Open Collective Slug'
|
||||||
type='text'
|
type='text'
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import { useDropzone } from 'react-dropzone'
|
|||||||
import { BiSolidImage } from 'react-icons/bi'
|
import { BiSolidImage } from 'react-icons/bi'
|
||||||
|
|
||||||
import { useAppState } from '#components/AppShell/hooks/useAppState'
|
import { useAppState } from '#components/AppShell/hooks/useAppState'
|
||||||
|
import { InputLabel } from '#components/Input/InputLabel'
|
||||||
import DialogModal from '#components/Templates/DialogModal'
|
import DialogModal from '#components/Templates/DialogModal'
|
||||||
import { getImageDimensions } from '#utils/getImageDimensions'
|
import { getImageDimensions } from '#utils/getImageDimensions'
|
||||||
|
|
||||||
@ -13,6 +14,7 @@ import type { FormState } from '#types/FormState'
|
|||||||
interface Props {
|
interface Props {
|
||||||
state: FormState
|
state: FormState
|
||||||
setState: React.Dispatch<React.SetStateAction<FormState>>
|
setState: React.Dispatch<React.SetStateAction<FormState>>
|
||||||
|
hideInputLabel?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const compressionOptions = {
|
const compressionOptions = {
|
||||||
@ -21,7 +23,7 @@ const compressionOptions = {
|
|||||||
useWebWorker: true,
|
useWebWorker: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const GalleryForm = ({ state, setState }: Props) => {
|
export const GalleryForm = ({ state, setState, hideInputLabel = false }: Props) => {
|
||||||
const appState = useAppState()
|
const appState = useAppState()
|
||||||
|
|
||||||
const [imageSelectedToDelete, setImageSelectedToDelete] = useState<number | null>(null)
|
const [imageSelectedToDelete, setImageSelectedToDelete] = useState<number | null>(null)
|
||||||
@ -76,7 +78,9 @@ export const GalleryForm = ({ state, setState }: Props) => {
|
|||||||
|
|
||||||
const images = state.gallery
|
const images = state.gallery
|
||||||
.map((image) => ({
|
.map((image) => ({
|
||||||
src: appState.assetsApi.url + `${image.directus_files_id.id}.jpg`,
|
src:
|
||||||
|
typeof image.directus_files_id !== 'string' &&
|
||||||
|
appState.assetsApi.url + `${image.directus_files_id.id}.jpg`,
|
||||||
state: 'uploaded',
|
state: 'uploaded',
|
||||||
}))
|
}))
|
||||||
.concat(
|
.concat(
|
||||||
@ -94,12 +98,13 @@ export const GalleryForm = ({ state, setState }: Props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className='tw:mt-3'>
|
||||||
<div className='tw:grid tw:grid-cols-2 tw:@md:grid-cols-3 tw:@lg:grid-cols-4 tw:gap-4 tw:my-4'>
|
{!hideInputLabel && <InputLabel label='Media' />}
|
||||||
|
<div className='tw:grid tw:grid-cols-2 tw:@md:grid-cols-3 tw:@lg:grid-cols-4 tw:gap-4'>
|
||||||
{images.map((image, index) => (
|
{images.map((image, index) => (
|
||||||
<div key={index} className='tw:relative'>
|
<div key={index} className='tw:relative'>
|
||||||
<img
|
<img
|
||||||
src={image.src}
|
src={image.src || undefined}
|
||||||
alt={`Gallery image ${index + 1}`}
|
alt={`Gallery image ${index + 1}`}
|
||||||
className={`tw:w-full tw:h-full tw:object-cover tw:rounded-lg ${
|
className={`tw:w-full tw:h-full tw:object-cover tw:rounded-lg ${
|
||||||
image.state === 'uploading' ? 'tw:opacity-50' : ''
|
image.state === 'uploading' ? 'tw:opacity-50' : ''
|
||||||
@ -159,6 +164,6 @@ export const GalleryForm = ({ state, setState }: Props) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</DialogModal>
|
</DialogModal>
|
||||||
</>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,12 +23,19 @@ export const GalleryView = ({ item }: { item: Item }) => {
|
|||||||
const [index, setIndex] = useState(-1)
|
const [index, setIndex] = useState(-1)
|
||||||
const appState = useAppState()
|
const appState = useAppState()
|
||||||
const images =
|
const images =
|
||||||
item.gallery?.map(({ directus_files_id: { id, type, width, height } }, index) => ({
|
item.gallery?.flatMap((g, index) => {
|
||||||
src: `${appState.assetsApi.url}${id}${getExtension(type)}`,
|
const file = g.directus_files_id
|
||||||
width,
|
if (typeof file === 'string') return []
|
||||||
height,
|
const { id, type, width, height } = file
|
||||||
index,
|
return [
|
||||||
})) ?? []
|
{
|
||||||
|
src: `${appState.assetsApi.url}${id}${getExtension(type)}`,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
index,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}) ?? []
|
||||||
|
|
||||||
if (images.length > 0)
|
if (images.length > 0)
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
|
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
|
|
||||||
|
import { InputLabel } from '#components/Input'
|
||||||
import ComboBoxInput from '#components/Input/ComboBoxInput'
|
import ComboBoxInput from '#components/Input/ComboBoxInput'
|
||||||
|
|
||||||
import type { FormState } from '#types/FormState'
|
import type { FormState } from '#types/FormState'
|
||||||
@ -51,12 +52,7 @@ export const GroupSubheaderForm = ({
|
|||||||
return (
|
return (
|
||||||
<div className='tw:grid tw:grid-cols-1 tw:@sm:grid-cols-2 tw:gap-2'>
|
<div className='tw:grid tw:grid-cols-1 tw:@sm:grid-cols-2 tw:gap-2'>
|
||||||
<div>
|
<div>
|
||||||
<label
|
<InputLabel label='Gruppenstatus' />
|
||||||
htmlFor='status'
|
|
||||||
className='tw:block tw:text-sm tw:font-medium tw:text-gray-500 tw:mb-1'
|
|
||||||
>
|
|
||||||
Gruppenstatus:
|
|
||||||
</label>
|
|
||||||
<ComboBoxInput
|
<ComboBoxInput
|
||||||
id='status'
|
id='status'
|
||||||
options={groupStates || []}
|
options={groupStates || []}
|
||||||
@ -70,12 +66,7 @@ export const GroupSubheaderForm = ({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label
|
<InputLabel label='Gruppenart' />
|
||||||
htmlFor='groupType'
|
|
||||||
className='tw:block tw:text-sm tw:font-medium tw:text-gray-500 tw:mb-1'
|
|
||||||
>
|
|
||||||
Gruppenart:
|
|
||||||
</label>
|
|
||||||
<ComboBoxInput
|
<ComboBoxInput
|
||||||
id='groupType'
|
id='groupType'
|
||||||
options={groupTypes?.map((gt) => gt.groupTypes_id.name) || []}
|
options={groupTypes?.map((gt) => gt.groupTypes_id.name) || []}
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
import { RichTextEditor } from '#components/Input/RichTextEditor'
|
import { InputLabel, RichTextEditor } from '#components/Input'
|
||||||
|
|
||||||
import { MarkdownHint } from './MarkdownHint'
|
import { MarkdownHint } from './MarkdownHint'
|
||||||
|
|
||||||
@ -13,11 +13,9 @@ import type { FormState } from '#types/FormState'
|
|||||||
export const ProfileTextForm = ({
|
export const ProfileTextForm = ({
|
||||||
state,
|
state,
|
||||||
setState,
|
setState,
|
||||||
// Is this really used?
|
|
||||||
dataField,
|
dataField,
|
||||||
heading,
|
heading,
|
||||||
size,
|
size,
|
||||||
hideInputLabel,
|
|
||||||
}: {
|
}: {
|
||||||
state: FormState
|
state: FormState
|
||||||
setState: React.Dispatch<React.SetStateAction<FormState>>
|
setState: React.Dispatch<React.SetStateAction<FormState>>
|
||||||
@ -36,15 +34,10 @@ export const ProfileTextForm = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`tw:max-h-124 tw:md:max-h-full tw:flex tw:flex-col tw:mt-2 ${size === 'full' ? 'tw:flex-1 tw:min-h-42' : 'tw:h-28 tw:flex-none'}`}
|
className={`tw:max-h-124 tw:md:max-h-full tw:flex tw:flex-col tw:mt-3 ${size === 'full' ? 'tw:flex-1 tw:min-h-42' : 'tw:h-30 tw:flex-none'}`}
|
||||||
>
|
>
|
||||||
<div className='tw:flex tw:justify-between tw:items-center'>
|
<div className='tw:flex tw:justify-between tw:items-center'>
|
||||||
<label
|
<InputLabel label={heading || 'Text'} />
|
||||||
htmlFor='nextAppointment'
|
|
||||||
className='tw:block tw:text-sm tw:font-medium tw:text-base-content/50 tw:mb-1'
|
|
||||||
>
|
|
||||||
{heading || 'Text'}:
|
|
||||||
</label>
|
|
||||||
<MarkdownHint />
|
<MarkdownHint />
|
||||||
</div>
|
</div>
|
||||||
<RichTextEditor
|
<RichTextEditor
|
||||||
@ -58,7 +51,6 @@ export const ProfileTextForm = ({
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
showMenu={size === 'full'}
|
showMenu={size === 'full'}
|
||||||
labelStyle={hideInputLabel ? 'tw:hidden' : ''}
|
|
||||||
containerStyle={size === 'full' ? 'tw:flex-1' : 'tw:h-24 tw:flex-none'}
|
containerStyle={size === 'full' ? 'tw:flex-1' : 'tw:h-24 tw:flex-none'}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -3,99 +3,113 @@
|
|||||||
exports[`GalleryForm > with previous images > renders 1`] = `
|
exports[`GalleryForm > with previous images > renders 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="tw:grid tw:grid-cols-2 tw:@md:grid-cols-3 tw:@lg:grid-cols-4 tw:gap-4 tw:my-4"
|
class="tw:mt-3"
|
||||||
>
|
>
|
||||||
<div
|
<label
|
||||||
class="tw:relative"
|
class="tw:label tw:pb-1"
|
||||||
>
|
>
|
||||||
<img
|
<span
|
||||||
alt="Gallery image 1"
|
class="tw:block tw:text-sm tw:font-medium tw:text-base-content/50 tw:mb-1"
|
||||||
class="tw:w-full tw:h-full tw:object-cover tw:rounded-lg "
|
|
||||||
src="undefined1.jpg"
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
class="tw:m-2 tw:bg-red-500 tw:text-white tw:p-2 tw:rounded-full tw:absolute tw:top-0 tw:right-0 tw:hover:bg-red-600 tw:cursor-pointer"
|
|
||||||
type="button"
|
|
||||||
>
|
>
|
||||||
<svg
|
Media
|
||||||
aria-hidden="true"
|
:
|
||||||
class="tw:h-5 tw:w-5"
|
</span>
|
||||||
data-slot="icon"
|
</label>
|
||||||
data-testid="trash"
|
|
||||||
fill="currentColor"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
clip-rule="evenodd"
|
|
||||||
d="M16.5 4.478v.227a48.816 48.816 0 0 1 3.878.512.75.75 0 1 1-.256 1.478l-.209-.035-1.005 13.07a3 3 0 0 1-2.991 2.77H8.084a3 3 0 0 1-2.991-2.77L4.087 6.66l-.209.035a.75.75 0 0 1-.256-1.478A48.567 48.567 0 0 1 7.5 4.705v-.227c0-1.564 1.213-2.9 2.816-2.951a52.662 52.662 0 0 1 3.369 0c1.603.051 2.815 1.387 2.815 2.951Zm-6.136-1.452a51.196 51.196 0 0 1 3.273 0C14.39 3.05 15 3.684 15 4.478v.113a49.488 49.488 0 0 0-6 0v-.113c0-.794.609-1.428 1.364-1.452Zm-.355 5.945a.75.75 0 1 0-1.5.058l.347 9a.75.75 0 1 0 1.499-.058l-.346-9Zm5.48.058a.75.75 0 1 0-1.498-.058l-.347 9a.75.75 0 0 0 1.5.058l.345-9Z"
|
|
||||||
fill-rule="evenodd"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
class="tw:relative"
|
class="tw:grid tw:grid-cols-2 tw:@md:grid-cols-3 tw:@lg:grid-cols-4 tw:gap-4"
|
||||||
>
|
>
|
||||||
<img
|
<div
|
||||||
alt="Gallery image 2"
|
class="tw:relative"
|
||||||
class="tw:w-full tw:h-full tw:object-cover tw:rounded-lg "
|
|
||||||
src="undefined2.jpg"
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
class="tw:m-2 tw:bg-red-500 tw:text-white tw:p-2 tw:rounded-full tw:absolute tw:top-0 tw:right-0 tw:hover:bg-red-600 tw:cursor-pointer"
|
|
||||||
type="button"
|
|
||||||
>
|
>
|
||||||
<svg
|
<img
|
||||||
aria-hidden="true"
|
alt="Gallery image 1"
|
||||||
class="tw:h-5 tw:w-5"
|
class="tw:w-full tw:h-full tw:object-cover tw:rounded-lg "
|
||||||
data-slot="icon"
|
src="undefined1.jpg"
|
||||||
data-testid="trash"
|
/>
|
||||||
fill="currentColor"
|
<button
|
||||||
viewBox="0 0 24 24"
|
class="tw:m-2 tw:bg-red-500 tw:text-white tw:p-2 tw:rounded-full tw:absolute tw:top-0 tw:right-0 tw:hover:bg-red-600 tw:cursor-pointer"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
type="button"
|
||||||
>
|
>
|
||||||
<path
|
<svg
|
||||||
clip-rule="evenodd"
|
aria-hidden="true"
|
||||||
d="M16.5 4.478v.227a48.816 48.816 0 0 1 3.878.512.75.75 0 1 1-.256 1.478l-.209-.035-1.005 13.07a3 3 0 0 1-2.991 2.77H8.084a3 3 0 0 1-2.991-2.77L4.087 6.66l-.209.035a.75.75 0 0 1-.256-1.478A48.567 48.567 0 0 1 7.5 4.705v-.227c0-1.564 1.213-2.9 2.816-2.951a52.662 52.662 0 0 1 3.369 0c1.603.051 2.815 1.387 2.815 2.951Zm-6.136-1.452a51.196 51.196 0 0 1 3.273 0C14.39 3.05 15 3.684 15 4.478v.113a49.488 49.488 0 0 0-6 0v-.113c0-.794.609-1.428 1.364-1.452Zm-.355 5.945a.75.75 0 1 0-1.5.058l.347 9a.75.75 0 1 0 1.499-.058l-.346-9Zm5.48.058a.75.75 0 1 0-1.498-.058l-.347 9a.75.75 0 0 0 1.5.058l.345-9Z"
|
class="tw:h-5 tw:w-5"
|
||||||
fill-rule="evenodd"
|
data-slot="icon"
|
||||||
/>
|
data-testid="trash"
|
||||||
</svg>
|
fill="currentColor"
|
||||||
</button>
|
viewBox="0 0 24 24"
|
||||||
</div>
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
<div
|
>
|
||||||
class="tw:flex tw:flex-col tw:items-center tw:justify-center tw:text-base-content/50 tw:w-full tw:h-full tw:cursor-pointer tw:card tw:card-body tw:border tw:border-current/50 tw:border-dashed tw:bg-base-200"
|
<path
|
||||||
role="presentation"
|
clip-rule="evenodd"
|
||||||
tabindex="0"
|
d="M16.5 4.478v.227a48.816 48.816 0 0 1 3.878.512.75.75 0 1 1-.256 1.478l-.209-.035-1.005 13.07a3 3 0 0 1-2.991 2.77H8.084a3 3 0 0 1-2.991-2.77L4.087 6.66l-.209.035a.75.75 0 0 1-.256-1.478A48.567 48.567 0 0 1 7.5 4.705v-.227c0-1.564 1.213-2.9 2.816-2.951a52.662 52.662 0 0 1 3.369 0c1.603.051 2.815 1.387 2.815 2.951Zm-6.136-1.452a51.196 51.196 0 0 1 3.273 0C14.39 3.05 15 3.684 15 4.478v.113a49.488 49.488 0 0 0-6 0v-.113c0-.794.609-1.428 1.364-1.452Zm-.355 5.945a.75.75 0 1 0-1.5.058l.347 9a.75.75 0 1 0 1.499-.058l-.346-9Zm5.48.058a.75.75 0 1 0-1.498-.058l-.347 9a.75.75 0 0 0 1.5.058l.345-9Z"
|
||||||
>
|
fill-rule="evenodd"
|
||||||
<input
|
/>
|
||||||
accept="image/jpeg,image/png"
|
</svg>
|
||||||
data-testid="gallery-upload-input"
|
</button>
|
||||||
multiple=""
|
</div>
|
||||||
style="border: 0px; clip: rect(0, 0, 0, 0); clip-path: inset(50%); height: 1px; margin: 0px -1px -1px 0px; overflow: hidden; padding: 0px; position: absolute; width: 1px; white-space: nowrap;"
|
<div
|
||||||
tabindex="-1"
|
class="tw:relative"
|
||||||
type="file"
|
>
|
||||||
/>
|
<img
|
||||||
<div>
|
alt="Gallery image 2"
|
||||||
<svg
|
class="tw:w-full tw:h-full tw:object-cover tw:rounded-lg "
|
||||||
class="tw:h-16 tw:w-16 tw:m-auto tw:mb-2"
|
src="undefined2.jpg"
|
||||||
fill="currentColor"
|
/>
|
||||||
height="1em"
|
<button
|
||||||
stroke="currentColor"
|
class="tw:m-2 tw:bg-red-500 tw:text-white tw:p-2 tw:rounded-full tw:absolute tw:top-0 tw:right-0 tw:hover:bg-red-600 tw:cursor-pointer"
|
||||||
stroke-width="0"
|
type="button"
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="1em"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
>
|
||||||
<path
|
<svg
|
||||||
d="M19.999 4h-16c-1.103 0-2 .897-2 2v12c0 1.103.897 2 2 2h16c1.103 0 2-.897 2-2V6c0-1.103-.897-2-2-2zm-13.5 3a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3zm5.5 10h-7l4-5 1.5 2 3-4 5.5 7h-7z"
|
aria-hidden="true"
|
||||||
/>
|
class="tw:h-5 tw:w-5"
|
||||||
</svg>
|
data-slot="icon"
|
||||||
<span
|
data-testid="trash"
|
||||||
class="tw:text-center"
|
fill="currentColor"
|
||||||
>
|
viewBox="0 0 24 24"
|
||||||
Upload Image
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
</span>
|
>
|
||||||
|
<path
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M16.5 4.478v.227a48.816 48.816 0 0 1 3.878.512.75.75 0 1 1-.256 1.478l-.209-.035-1.005 13.07a3 3 0 0 1-2.991 2.77H8.084a3 3 0 0 1-2.991-2.77L4.087 6.66l-.209.035a.75.75 0 0 1-.256-1.478A48.567 48.567 0 0 1 7.5 4.705v-.227c0-1.564 1.213-2.9 2.816-2.951a52.662 52.662 0 0 1 3.369 0c1.603.051 2.815 1.387 2.815 2.951Zm-6.136-1.452a51.196 51.196 0 0 1 3.273 0C14.39 3.05 15 3.684 15 4.478v.113a49.488 49.488 0 0 0-6 0v-.113c0-.794.609-1.428 1.364-1.452Zm-.355 5.945a.75.75 0 1 0-1.5.058l.347 9a.75.75 0 1 0 1.499-.058l-.346-9Zm5.48.058a.75.75 0 1 0-1.498-.058l-.347 9a.75.75 0 0 0 1.5.058l.345-9Z"
|
||||||
|
fill-rule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="tw:flex tw:flex-col tw:items-center tw:justify-center tw:text-base-content/50 tw:w-full tw:h-full tw:cursor-pointer tw:card tw:card-body tw:border tw:border-current/50 tw:border-dashed tw:bg-base-200"
|
||||||
|
role="presentation"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
accept="image/jpeg,image/png"
|
||||||
|
data-testid="gallery-upload-input"
|
||||||
|
multiple=""
|
||||||
|
style="border: 0px; clip: rect(0, 0, 0, 0); clip-path: inset(50%); height: 1px; margin: 0px -1px -1px 0px; overflow: hidden; padding: 0px; position: absolute; width: 1px; white-space: nowrap;"
|
||||||
|
tabindex="-1"
|
||||||
|
type="file"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<svg
|
||||||
|
class="tw:h-16 tw:w-16 tw:m-auto tw:mb-2"
|
||||||
|
fill="currentColor"
|
||||||
|
height="1em"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="0"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="1em"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M19.999 4h-16c-1.103 0-2 .897-2 2v12c0 1.103.897 2 2 2h16c1.103 0 2-.897 2-2V6c0-1.103-.897-2-2-2zm-13.5 3a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3zm5.5 10h-7l4-5 1.5 2 3-4 5.5 7h-7z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span
|
||||||
|
class="tw:text-center"
|
||||||
|
>
|
||||||
|
Upload Image
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -105,77 +119,91 @@ exports[`GalleryForm > with previous images > renders 1`] = `
|
|||||||
exports[`GalleryForm > with uploading images > renders 1`] = `
|
exports[`GalleryForm > with uploading images > renders 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="tw:grid tw:grid-cols-2 tw:@md:grid-cols-3 tw:@lg:grid-cols-4 tw:gap-4 tw:my-4"
|
class="tw:mt-3"
|
||||||
>
|
>
|
||||||
<div
|
<label
|
||||||
class="tw:relative"
|
class="tw:label tw:pb-1"
|
||||||
>
|
>
|
||||||
<img
|
|
||||||
alt="Gallery image 1"
|
|
||||||
class="tw:w-full tw:h-full tw:object-cover tw:rounded-lg tw:opacity-50"
|
|
||||||
src="blob-url-placeholder"
|
|
||||||
/>
|
|
||||||
<span
|
<span
|
||||||
class="tw:loading tw:loading-spinner tw:absolute tw:inset-0 tw:m-auto"
|
class="tw:block tw:text-sm tw:font-medium tw:text-base-content/50 tw:mb-1"
|
||||||
/>
|
>
|
||||||
</div>
|
Media
|
||||||
|
:
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
<div
|
<div
|
||||||
class="tw:relative"
|
class="tw:grid tw:grid-cols-2 tw:@md:grid-cols-3 tw:@lg:grid-cols-4 tw:gap-4"
|
||||||
>
|
>
|
||||||
<img
|
<div
|
||||||
alt="Gallery image 2"
|
class="tw:relative"
|
||||||
class="tw:w-full tw:h-full tw:object-cover tw:rounded-lg tw:opacity-50"
|
>
|
||||||
src="blob-url-placeholder"
|
<img
|
||||||
/>
|
alt="Gallery image 1"
|
||||||
<span
|
class="tw:w-full tw:h-full tw:object-cover tw:rounded-lg tw:opacity-50"
|
||||||
class="tw:loading tw:loading-spinner tw:absolute tw:inset-0 tw:m-auto"
|
src="blob-url-placeholder"
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="tw:relative"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt="Gallery image 3"
|
|
||||||
class="tw:w-full tw:h-full tw:object-cover tw:rounded-lg tw:opacity-50"
|
|
||||||
src="blob-url-placeholder"
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
class="tw:loading tw:loading-spinner tw:absolute tw:inset-0 tw:m-auto"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="tw:flex tw:flex-col tw:items-center tw:justify-center tw:text-base-content/50 tw:w-full tw:h-full tw:cursor-pointer tw:card tw:card-body tw:border tw:border-current/50 tw:border-dashed tw:bg-base-200"
|
|
||||||
role="presentation"
|
|
||||||
tabindex="0"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
accept="image/jpeg,image/png"
|
|
||||||
data-testid="gallery-upload-input"
|
|
||||||
multiple=""
|
|
||||||
style="border: 0px; clip: rect(0, 0, 0, 0); clip-path: inset(50%); height: 1px; margin: 0px -1px -1px 0px; overflow: hidden; padding: 0px; position: absolute; width: 1px; white-space: nowrap;"
|
|
||||||
tabindex="-1"
|
|
||||||
type="file"
|
|
||||||
/>
|
|
||||||
<div>
|
|
||||||
<svg
|
|
||||||
class="tw:h-16 tw:w-16 tw:m-auto tw:mb-2"
|
|
||||||
fill="currentColor"
|
|
||||||
height="1em"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="0"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="1em"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M19.999 4h-16c-1.103 0-2 .897-2 2v12c0 1.103.897 2 2 2h16c1.103 0 2-.897 2-2V6c0-1.103-.897-2-2-2zm-13.5 3a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3zm5.5 10h-7l4-5 1.5 2 3-4 5.5 7h-7z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<span
|
<span
|
||||||
class="tw:text-center"
|
class="tw:loading tw:loading-spinner tw:absolute tw:inset-0 tw:m-auto"
|
||||||
>
|
/>
|
||||||
Upload Image
|
</div>
|
||||||
</span>
|
<div
|
||||||
|
class="tw:relative"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
alt="Gallery image 2"
|
||||||
|
class="tw:w-full tw:h-full tw:object-cover tw:rounded-lg tw:opacity-50"
|
||||||
|
src="blob-url-placeholder"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="tw:loading tw:loading-spinner tw:absolute tw:inset-0 tw:m-auto"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="tw:relative"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
alt="Gallery image 3"
|
||||||
|
class="tw:w-full tw:h-full tw:object-cover tw:rounded-lg tw:opacity-50"
|
||||||
|
src="blob-url-placeholder"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="tw:loading tw:loading-spinner tw:absolute tw:inset-0 tw:m-auto"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="tw:flex tw:flex-col tw:items-center tw:justify-center tw:text-base-content/50 tw:w-full tw:h-full tw:cursor-pointer tw:card tw:card-body tw:border tw:border-current/50 tw:border-dashed tw:bg-base-200"
|
||||||
|
role="presentation"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
accept="image/jpeg,image/png"
|
||||||
|
data-testid="gallery-upload-input"
|
||||||
|
multiple=""
|
||||||
|
style="border: 0px; clip: rect(0, 0, 0, 0); clip-path: inset(50%); height: 1px; margin: 0px -1px -1px 0px; overflow: hidden; padding: 0px; position: absolute; width: 1px; white-space: nowrap;"
|
||||||
|
tabindex="-1"
|
||||||
|
type="file"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<svg
|
||||||
|
class="tw:h-16 tw:w-16 tw:m-auto tw:mb-2"
|
||||||
|
fill="currentColor"
|
||||||
|
height="1em"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="0"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="1em"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M19.999 4h-16c-1.103 0-2 .897-2 2v12c0 1.103.897 2 2 2h16c1.103 0 2-.897 2-2V6c0-1.103-.897-2-2-2zm-13.5 3a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3zm5.5 10h-7l4-5 1.5 2 3-4 5.5 7h-7z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span
|
||||||
|
class="tw:text-center"
|
||||||
|
>
|
||||||
|
Upload Image
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -185,41 +213,55 @@ exports[`GalleryForm > with uploading images > renders 1`] = `
|
|||||||
exports[`GalleryForm > without previous images > renders 1`] = `
|
exports[`GalleryForm > without previous images > renders 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="tw:grid tw:grid-cols-2 tw:@md:grid-cols-3 tw:@lg:grid-cols-4 tw:gap-4 tw:my-4"
|
class="tw:mt-3"
|
||||||
>
|
>
|
||||||
<div
|
<label
|
||||||
class="tw:flex tw:flex-col tw:items-center tw:justify-center tw:text-base-content/50 tw:w-full tw:h-full tw:cursor-pointer tw:card tw:card-body tw:border tw:border-current/50 tw:border-dashed tw:bg-base-200"
|
class="tw:label tw:pb-1"
|
||||||
role="presentation"
|
|
||||||
tabindex="0"
|
|
||||||
>
|
>
|
||||||
<input
|
<span
|
||||||
accept="image/jpeg,image/png"
|
class="tw:block tw:text-sm tw:font-medium tw:text-base-content/50 tw:mb-1"
|
||||||
data-testid="gallery-upload-input"
|
>
|
||||||
multiple=""
|
Media
|
||||||
style="border: 0px; clip: rect(0, 0, 0, 0); clip-path: inset(50%); height: 1px; margin: 0px -1px -1px 0px; overflow: hidden; padding: 0px; position: absolute; width: 1px; white-space: nowrap;"
|
:
|
||||||
tabindex="-1"
|
</span>
|
||||||
type="file"
|
</label>
|
||||||
/>
|
<div
|
||||||
<div>
|
class="tw:grid tw:grid-cols-2 tw:@md:grid-cols-3 tw:@lg:grid-cols-4 tw:gap-4"
|
||||||
<svg
|
>
|
||||||
class="tw:h-16 tw:w-16 tw:m-auto tw:mb-2"
|
<div
|
||||||
fill="currentColor"
|
class="tw:flex tw:flex-col tw:items-center tw:justify-center tw:text-base-content/50 tw:w-full tw:h-full tw:cursor-pointer tw:card tw:card-body tw:border tw:border-current/50 tw:border-dashed tw:bg-base-200"
|
||||||
height="1em"
|
role="presentation"
|
||||||
stroke="currentColor"
|
tabindex="0"
|
||||||
stroke-width="0"
|
>
|
||||||
viewBox="0 0 24 24"
|
<input
|
||||||
width="1em"
|
accept="image/jpeg,image/png"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
data-testid="gallery-upload-input"
|
||||||
>
|
multiple=""
|
||||||
<path
|
style="border: 0px; clip: rect(0, 0, 0, 0); clip-path: inset(50%); height: 1px; margin: 0px -1px -1px 0px; overflow: hidden; padding: 0px; position: absolute; width: 1px; white-space: nowrap;"
|
||||||
d="M19.999 4h-16c-1.103 0-2 .897-2 2v12c0 1.103.897 2 2 2h16c1.103 0 2-.897 2-2V6c0-1.103-.897-2-2-2zm-13.5 3a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3zm5.5 10h-7l4-5 1.5 2 3-4 5.5 7h-7z"
|
tabindex="-1"
|
||||||
/>
|
type="file"
|
||||||
</svg>
|
/>
|
||||||
<span
|
<div>
|
||||||
class="tw:text-center"
|
<svg
|
||||||
>
|
class="tw:h-16 tw:w-16 tw:m-auto tw:mb-2"
|
||||||
Upload Image
|
fill="currentColor"
|
||||||
</span>
|
height="1em"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="0"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="1em"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M19.999 4h-16c-1.103 0-2 .897-2 2v12c0 1.103.897 2 2 2h16c1.103 0 2-.897 2-2V6c0-1.103-.897-2-2-2zm-13.5 3a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3zm5.5 10h-7l4-5 1.5 2 3-4 5.5 7h-7z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span
|
||||||
|
class="tw:text-center"
|
||||||
|
>
|
||||||
|
Upload Image
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -44,7 +44,6 @@ export const TabsForm = ({
|
|||||||
<PopupStartEndInput
|
<PopupStartEndInput
|
||||||
item={item}
|
item={item}
|
||||||
showLabels={true}
|
showLabels={true}
|
||||||
labelStyle={'tw:text-base-content/50'}
|
|
||||||
updateEndValue={(e) =>
|
updateEndValue={(e) =>
|
||||||
setState((prevState) => ({
|
setState((prevState) => ({
|
||||||
...prevState,
|
...prevState,
|
||||||
@ -62,7 +61,6 @@ export const TabsForm = ({
|
|||||||
|
|
||||||
<RichTextEditor
|
<RichTextEditor
|
||||||
labelTitle='About'
|
labelTitle='About'
|
||||||
labelStyle={'tw:text-base-content/50'}
|
|
||||||
placeholder='about ...'
|
placeholder='about ...'
|
||||||
defaultValue={item?.text ? item.text : ''}
|
defaultValue={item?.text ? item.text : ''}
|
||||||
updateFormValue={(v) =>
|
updateFormValue={(v) =>
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
export { UserSettings } from './UserSettings'
|
export { UserSettings } from './UserSettings'
|
||||||
// export { PlusButton } from './Subcomponents/PlusButton'
|
|
||||||
export { ProfileView } from './ProfileView'
|
export { ProfileView } from './ProfileView'
|
||||||
export { ProfileForm } from './ProfileForm'
|
export { ProfileForm } from './ProfileForm'
|
||||||
|
|||||||
@ -200,7 +200,7 @@ export const onUpdateItem = async (
|
|||||||
...(state.needs.length > 0 && { needs: needsUpdates }),
|
...(state.needs.length > 0 && { needs: needsUpdates }),
|
||||||
...(state.openCollectiveSlug && { openCollectiveSlug: state.openCollectiveSlug }),
|
...(state.openCollectiveSlug && { openCollectiveSlug: state.openCollectiveSlug }),
|
||||||
gallery: state.gallery.map((i) => ({
|
gallery: state.gallery.map((i) => ({
|
||||||
directus_files_id: i.directus_files_id.id,
|
directus_files_id: typeof i.directus_files_id !== 'string' && i.directus_files_id.id,
|
||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -32,7 +32,6 @@ import type { Item } from '#types/Item'
|
|||||||
export const OverlayItemsIndexPage = ({
|
export const OverlayItemsIndexPage = ({
|
||||||
url,
|
url,
|
||||||
layerName,
|
layerName,
|
||||||
parameterField,
|
|
||||||
}: {
|
}: {
|
||||||
layerName: string
|
layerName: string
|
||||||
url: string
|
url: string
|
||||||
@ -40,8 +39,6 @@ export const OverlayItemsIndexPage = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const [loading, setLoading] = useState<boolean>(false)
|
const [loading, setLoading] = useState<boolean>(false)
|
||||||
const [addItemPopupOpen, setAddItemPopupOpen] = useState<boolean>(false)
|
const [addItemPopupOpen, setAddItemPopupOpen] = useState<boolean>(false)
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
const parameterFieldDummy = parameterField
|
|
||||||
|
|
||||||
const tabRef = useRef<HTMLFormElement>(null)
|
const tabRef = useRef<HTMLFormElement>(null)
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,29 @@
|
|||||||
.leaflet-control-attribution {
|
.leaflet-control-attribution{
|
||||||
display: none;
|
color: #000 !important;
|
||||||
|
background-color: white/50 !important;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 0 4px;
|
||||||
|
z-index: 400 !important;
|
||||||
|
font-size: 10px;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-control-attribution a{
|
||||||
|
color: #000 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.leaflet-attribution-flag {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-control-attribution a:not([href*="openstreetmap"]) {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2) Entfernt den Trenner “|” (liegt im span[aria-hidden]) */
|
||||||
|
.leaflet-control-attribution span[aria-hidden="true"] {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
.leaflet-control-locate {
|
.leaflet-control-locate {
|
||||||
display: none;
|
display: none;
|
||||||
|
|||||||
@ -9,6 +9,7 @@ export * from './Components/Templates'
|
|||||||
export * from './Components/Input'
|
export * from './Components/Input'
|
||||||
export * from './Components/Item'
|
export * from './Components/Item'
|
||||||
export * from './Components/Onboarding'
|
export * from './Components/Onboarding'
|
||||||
|
export * from './Components/Profile'
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
|
|||||||
14
lib/src/types/Item.d.ts
vendored
@ -8,12 +8,14 @@ import type { Point } from 'geojson'
|
|||||||
type TagIds = { tags_id: string }[]
|
type TagIds = { tags_id: string }[]
|
||||||
|
|
||||||
interface GalleryItem {
|
interface GalleryItem {
|
||||||
directus_files_id: {
|
directus_files_id:
|
||||||
id: string
|
| {
|
||||||
width: number
|
id: string
|
||||||
height: number
|
width: number
|
||||||
type: string
|
height: number
|
||||||
}
|
type: string
|
||||||
|
}
|
||||||
|
| string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ItemSecret {
|
interface ItemSecret {
|
||||||
|
|||||||
2
lib/src/types/UtopiaMapProps.d.ts
vendored
@ -18,4 +18,6 @@ export interface UtopiaMapProps {
|
|||||||
donationWidget?: boolean
|
donationWidget?: boolean
|
||||||
defaultTheme?: string
|
defaultTheme?: string
|
||||||
expandLayerControl?: boolean
|
expandLayerControl?: boolean
|
||||||
|
tileServerUrl?: string
|
||||||
|
tileServerAttribution?: string
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,24 +1,19 @@
|
|||||||
{
|
{
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "dist",
|
"outDir": "dist",
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"declarationDir": "dist/types", // 🔹 Muss innerhalb von dist/ liegen
|
"declarationDir": "dist/types", // 🔹 Muss innerhalb von dist/ liegen
|
||||||
"emitDeclarationOnly": true, // Nur `.d.ts` generieren, kein JavaScript
|
"emitDeclarationOnly": true, // Nur `.d.ts` generieren, kein JavaScript
|
||||||
"module": "esnext",
|
|
||||||
"target": "ESNext",
|
|
||||||
"lib": ["es6", "dom","es2015", "es2016", "es2017", "es2020"],
|
|
||||||
"sourceMap": false,
|
"sourceMap": false,
|
||||||
"allowJs": false,
|
"allowJs": false,
|
||||||
"jsx": "react-jsx",
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"noImplicitReturns": true,
|
"noImplicitReturns": true,
|
||||||
"noImplicitThis": true,
|
"noImplicitThis": true,
|
||||||
"strictNullChecks": true,
|
"strictNullChecks": true,
|
||||||
"noUnusedLocals": false,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"skipLibCheck": true,
|
|
||||||
"paths": {
|
"paths": {
|
||||||
"#assets/*": ["./src/assets/*"],
|
"#assets/*": ["./src/assets/*"],
|
||||||
"#components/*": ["./src/Components/*"],
|
"#components/*": ["./src/Components/*"],
|
||||||
@ -29,7 +24,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"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"],
|
||||||
"typeRoots": [
|
"typeRoots": [
|
||||||
"./src/types",
|
"./src/types",
|
||||||
"./node_modules/@types/"
|
"./node_modules/@types/"
|
||||||
|
|||||||
10
package-lock.json
generated
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "utopia-map",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "utopia-map"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12
tsconfig.base.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ESNext",
|
||||||
|
"module": "ESNext",
|
||||||
|
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||||
|
"moduleResolution": "Node",
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
}
|
||||||
|
}
|
||||||