Merge pull request #245 from utopia-os/mono-repo
chore(other): mono repo
15
.github/workflows/deploy.docs.yml
vendored
@ -1,4 +1,4 @@
|
||||
name: deploy:docs
|
||||
name: deploy:docs:lib
|
||||
|
||||
on:
|
||||
push:
|
||||
@ -14,36 +14,37 @@ jobs:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.0.3
|
||||
with:
|
||||
node-version-file: './.tool-versions'
|
||||
node-version-file: '.tool-versions'
|
||||
- name: Install Dependencies & Build Library
|
||||
run: |
|
||||
npm install
|
||||
npm run build
|
||||
working-directory: ./
|
||||
working-directory: lib/
|
||||
|
||||
- name: Build static files
|
||||
id: build
|
||||
run: npm run docs:generate
|
||||
working-directory: ./
|
||||
working-directory: lib/
|
||||
|
||||
- name: Generate coverage
|
||||
id: coverage
|
||||
run: npm run test:unit
|
||||
working-directory: lib/
|
||||
|
||||
- name: Create coverage badges
|
||||
id: coverage-badge
|
||||
uses: jaywcjlove/coverage-badges-cli@main
|
||||
with:
|
||||
style: flat
|
||||
source: coverage/coverage-summary.json
|
||||
output: docs/test-coverage.svg
|
||||
source: lib/coverage/coverage-summary.json
|
||||
output: lib/docs/test-coverage.svg
|
||||
jsonPath: total.lines.pct
|
||||
|
||||
- name: Upload static files as artifact
|
||||
id: deployment
|
||||
uses: actions/upload-pages-artifact@v3.0.1
|
||||
with:
|
||||
path: docs/
|
||||
path: lib/docs/
|
||||
|
||||
# Deploy job
|
||||
deploy:
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
name: build
|
||||
name: build:lib
|
||||
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
files-changed:
|
||||
name: Detect File Changes - build
|
||||
name: Detect File Changes - build -lib
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
build: ${{ steps.filter.outputs.build }}
|
||||
@ -16,7 +16,7 @@ jobs:
|
||||
filters: |
|
||||
build:
|
||||
- '.github/workflows/**/*'
|
||||
- '**/*'
|
||||
- 'lib/**/*'
|
||||
|
||||
build:
|
||||
if: needs.files-changed.outputs.build == 'true'
|
||||
@ -27,12 +27,12 @@ jobs:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.0.3
|
||||
with:
|
||||
node-version-file: './.tool-versions'
|
||||
node-version-file: '.tool-versions'
|
||||
- name: Install Dependencies & Build Library
|
||||
run: |
|
||||
npm install
|
||||
npm run build
|
||||
working-directory: ./
|
||||
working-directory: lib/
|
||||
|
||||
build-examples:
|
||||
if: needs.files-changed.outputs.build == 'true'
|
||||
@ -47,7 +47,7 @@ jobs:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.0.3
|
||||
with:
|
||||
node-version-file: './.tool-versions'
|
||||
node-version-file: '.tool-versions'
|
||||
- name: Link Utopia-UI in Example App
|
||||
run: |
|
||||
npm install
|
||||
@ -55,3 +55,4 @@ jobs:
|
||||
cd ${{ matrix.app }}
|
||||
npm install
|
||||
npm run build
|
||||
working-directory: lib/
|
||||
@ -1,10 +1,10 @@
|
||||
name: test:docs
|
||||
name: test:docs:lib
|
||||
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
files-changed:
|
||||
name: Detect File Changes - docs
|
||||
name: Detect File Changes - docs - lib
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
docs: ${{ steps.filter.outputs.docs }}
|
||||
@ -16,7 +16,7 @@ jobs:
|
||||
filters: |
|
||||
docs:
|
||||
- '.github/workflows/**/*'
|
||||
- '**/*.md'
|
||||
- 'lib/**/*.md'
|
||||
- 'LICENSE'
|
||||
|
||||
# build:
|
||||
@ -35,7 +35,7 @@ jobs:
|
||||
|
||||
docs:
|
||||
if: needs.files-changed.outputs.docs == 'true'
|
||||
name: Docs
|
||||
name: Docs - lib
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
@ -44,10 +44,10 @@ jobs:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.0.3
|
||||
with:
|
||||
node-version-file: './.tool-versions'
|
||||
node-version-file: '.tool-versions'
|
||||
- name: Docs
|
||||
run: |
|
||||
npm install
|
||||
npm run docs:generate
|
||||
./scripts/docs-coverage.sh
|
||||
working-directory: ./
|
||||
working-directory: lib/
|
||||
33
.github/workflows/test.lint.frontend.yml
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
name: test:lint:frontend
|
||||
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
files-changed:
|
||||
name: Detect File Changes - lint - frontend
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
lint: ${{ steps.filter.outputs.lint }}
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
lint:
|
||||
- '.github/workflows/**/*'
|
||||
- 'frontend/**/*'
|
||||
|
||||
lint:
|
||||
if: needs.files-changed.outputs.lint == 'true'
|
||||
name: Lint - frontend
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.0.3
|
||||
with:
|
||||
node-version-file: '.tool-versions'
|
||||
- name: Lint
|
||||
run: npm install && npm run test:lint:eslint
|
||||
working-directory: frontend/
|
||||
@ -1,4 +1,4 @@
|
||||
name: test::examples
|
||||
name: test::examples:lib
|
||||
|
||||
on: push
|
||||
|
||||
@ -16,7 +16,7 @@ jobs:
|
||||
filters: |
|
||||
lint:
|
||||
- '.github/workflows/**/*'
|
||||
- '**/*'
|
||||
- 'lib/**/*'
|
||||
|
||||
# build:
|
||||
# if: needs.files-changed.outputs.frontend == 'true'
|
||||
@ -41,10 +41,10 @@ jobs:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.0.3
|
||||
with:
|
||||
node-version-file: './.tool-versions'
|
||||
node-version-file: '.tool-versions'
|
||||
- name: Lint
|
||||
run: npm install && npm run lint
|
||||
working-directory: ./examples/1-basic-map
|
||||
working-directory: lib/examples/1-basic-map
|
||||
|
||||
lint-example-2-static-layers:
|
||||
if: needs.files-changed.outputs.lint == 'true'
|
||||
@ -55,10 +55,10 @@ jobs:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.0.3
|
||||
with:
|
||||
node-version-file: './.tool-versions'
|
||||
node-version-file: '.tool-versions'
|
||||
- name: Lint
|
||||
run: npm install && npm run lint
|
||||
working-directory: ./examples/2-static-layers
|
||||
working-directory: lib/examples/2-static-layers
|
||||
|
||||
lint-example-3-tags:
|
||||
if: needs.files-changed.outputs.lint == 'true'
|
||||
@ -69,10 +69,10 @@ jobs:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.0.3
|
||||
with:
|
||||
node-version-file: './.tool-versions'
|
||||
node-version-file: '.tool-versions'
|
||||
- name: Lint
|
||||
run: npm install && npm run lint
|
||||
working-directory: ./examples/3-tags
|
||||
working-directory: lib/examples/3-tags
|
||||
|
||||
# unit:
|
||||
# if: needs.files-changed.outputs.frontend == 'true'
|
||||
33
.github/workflows/test.lint.lib.yml
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
name: test:lint:lib
|
||||
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
files-changed:
|
||||
name: Detect File Changes - lint - lib
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
lint: ${{ steps.filter.outputs.lint }}
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
lint:
|
||||
- '.github/workflows/**/*'
|
||||
- 'lib/**/*'
|
||||
|
||||
lint:
|
||||
if: needs.files-changed.outputs.lint == 'true'
|
||||
name: Lint - lib
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.0.3
|
||||
with:
|
||||
node-version-file: '.tool-versions'
|
||||
- name: Lint
|
||||
run: npm install && npm run test:lint:eslint
|
||||
working-directory: lib/
|
||||
6
.github/workflows/test.lint.pr.yml
vendored
@ -29,11 +29,13 @@ jobs:
|
||||
# Configure which scopes are allowed (newline delimited).
|
||||
# Append a scope for each service here
|
||||
scopes: |
|
||||
backend
|
||||
frontend
|
||||
lib
|
||||
docu
|
||||
docker
|
||||
release
|
||||
workflow
|
||||
source
|
||||
other
|
||||
# Configure that a scope must always be provided.
|
||||
requireScope: true
|
||||
@ -74,4 +76,4 @@ jobs:
|
||||
# special "[WIP]" prefix to indicate this state. This will avoid the
|
||||
# validation of the PR title and the pull request checks remain pending.
|
||||
# Note that a second check will be reported if this is enabled.
|
||||
wip: true
|
||||
wip: true
|
||||
61
.github/workflows/test.lint.yml
vendored
@ -1,61 +0,0 @@
|
||||
name: test:lint
|
||||
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
files-changed:
|
||||
name: Detect File Changes - lint
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
lint: ${{ steps.filter.outputs.lint }}
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
lint:
|
||||
- '.github/workflows/**/*'
|
||||
- '**/*'
|
||||
|
||||
# build:
|
||||
# if: needs.files-changed.outputs.frontend == 'true'
|
||||
# name: Build - Frontend
|
||||
# needs: files-changed
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
# - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
# - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.0.3
|
||||
# with:
|
||||
# node-version-file: './.tool-versions'
|
||||
# - name: Frontend | Build
|
||||
# run: npm install && npm run build
|
||||
# working-directory: ./frontend
|
||||
|
||||
lint:
|
||||
if: needs.files-changed.outputs.lint == 'true'
|
||||
name: Lint
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.0.3
|
||||
with:
|
||||
node-version-file: './.tool-versions'
|
||||
- name: Lint
|
||||
run: npm install && npm run test:lint:eslint
|
||||
working-directory: ./
|
||||
|
||||
# unit:
|
||||
# if: needs.files-changed.outputs.frontend == 'true'
|
||||
# name: Unit - Frontend
|
||||
# needs: files-changed
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
# - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
# - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.0.3
|
||||
# with:
|
||||
# node-version-file: './.tool-versions'
|
||||
# - name: Frontend | Unit
|
||||
# run: npm install && npm run test:unit
|
||||
# working-directory: ./frontend
|
||||
@ -1,10 +1,10 @@
|
||||
name: test:unit
|
||||
name: test:unit:lib
|
||||
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
files-changed:
|
||||
name: Detect File Changes - unit
|
||||
name: Detect File Changes - unit - lib
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
unit: ${{ steps.filter.outputs.unit }}
|
||||
@ -16,18 +16,18 @@ jobs:
|
||||
filters: |
|
||||
unit:
|
||||
- '.github/workflows/**/*'
|
||||
- '**/*'
|
||||
- 'lib/**/*'
|
||||
|
||||
unit:
|
||||
if: needs.files-changed.outputs.unit == 'true'
|
||||
name: Unit
|
||||
name: Unit - lib
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.0.3
|
||||
with:
|
||||
node-version-file: './.tool-versions'
|
||||
node-version-file: '.tool-versions'
|
||||
- name: Unit
|
||||
run: npm install && npm run test:unit
|
||||
working-directory: ./
|
||||
working-directory: lib/
|
||||
12
backend/Dockerfile
Normal file
@ -0,0 +1,12 @@
|
||||
FROM node:20-alpine as third-party-ext
|
||||
RUN apk add python3 g++ make
|
||||
WORKDIR /extensions
|
||||
ADD extensions .
|
||||
RUN npm install
|
||||
# Move all extensions the starts with directus-extension-, using find, to the /extensions/directus folder
|
||||
RUN mkdir -p ./directus
|
||||
RUN cd node_modules && find . -maxdepth 1 -type d -name "directus-extension-*" -exec mv {} ../directus \;
|
||||
|
||||
FROM directus/directus:11.4.1
|
||||
# Copy third party extensions
|
||||
COPY --from=third-party-ext /extensions/directus ./extensions
|
||||
16
backend/README.md
Normal file
@ -0,0 +1,16 @@
|
||||
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
|
||||
|
||||
```
|
||||
npx directus-sync pull \
|
||||
--directus-url http://localhost:8055 \
|
||||
--directus-email admin@it4c.dev \
|
||||
--directus-password admin123
|
||||
```
|
||||
|
||||
To push local changes or to seed directus use the following command
|
||||
```
|
||||
npx directus-sync push \
|
||||
--directus-url http://localhost:8055 \
|
||||
--directus-email admin@it4c.dev \
|
||||
--directus-password admin123
|
||||
```
|
||||
1
backend/directus-config/collections/dashboards.json
Normal file
@ -0,0 +1 @@
|
||||
[]
|
||||
1
backend/directus-config/collections/flows.json
Normal file
@ -0,0 +1 @@
|
||||
[]
|
||||
1
backend/directus-config/collections/folders.json
Normal file
@ -0,0 +1 @@
|
||||
[]
|
||||
1
backend/directus-config/collections/operations.json
Normal file
@ -0,0 +1 @@
|
||||
[]
|
||||
1
backend/directus-config/collections/panels.json
Normal file
@ -0,0 +1 @@
|
||||
[]
|
||||
1
backend/directus-config/collections/permissions.json
Normal file
@ -0,0 +1 @@
|
||||
[]
|
||||
34
backend/directus-config/collections/policies.json
Normal file
@ -0,0 +1,34 @@
|
||||
[
|
||||
{
|
||||
"name": "Administrator",
|
||||
"icon": "verified",
|
||||
"description": "$t:admin_description",
|
||||
"ip_access": null,
|
||||
"enforce_tfa": false,
|
||||
"admin_access": true,
|
||||
"app_access": true,
|
||||
"roles": [
|
||||
{
|
||||
"role": "_sync_default_admin_role",
|
||||
"sort": null
|
||||
}
|
||||
],
|
||||
"_syncId": "_sync_default_admin_policy"
|
||||
},
|
||||
{
|
||||
"name": "$t:public_label",
|
||||
"icon": "public",
|
||||
"description": "$t:public_description",
|
||||
"ip_access": null,
|
||||
"enforce_tfa": false,
|
||||
"admin_access": false,
|
||||
"app_access": false,
|
||||
"roles": [
|
||||
{
|
||||
"role": null,
|
||||
"sort": 1
|
||||
}
|
||||
],
|
||||
"_syncId": "_sync_default_public_policy"
|
||||
}
|
||||
]
|
||||
1
backend/directus-config/collections/presets.json
Normal file
@ -0,0 +1 @@
|
||||
[]
|
||||
9
backend/directus-config/collections/roles.json
Normal file
@ -0,0 +1,9 @@
|
||||
[
|
||||
{
|
||||
"name": "Administrator",
|
||||
"icon": "verified",
|
||||
"description": "$t:admin_description",
|
||||
"parent": null,
|
||||
"_syncId": "_sync_default_admin_role"
|
||||
}
|
||||
]
|
||||
1
backend/directus-config/collections/settings.json
Normal file
@ -0,0 +1 @@
|
||||
[]
|
||||
1
backend/directus-config/collections/translations.json
Normal file
@ -0,0 +1 @@
|
||||
[]
|
||||
@ -0,0 +1,7 @@
|
||||
{
|
||||
"collection": "directus_sync_id_map",
|
||||
"meta": null,
|
||||
"schema": {
|
||||
"name": "directus_sync_id_map"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
{
|
||||
"collection": "directus_sync_id_map",
|
||||
"field": "created_at",
|
||||
"type": "dateTime",
|
||||
"meta": null,
|
||||
"schema": {
|
||||
"name": "created_at",
|
||||
"table": "directus_sync_id_map",
|
||||
"data_type": "datetime",
|
||||
"default_value": "CURRENT_TIMESTAMP",
|
||||
"max_length": null,
|
||||
"numeric_precision": null,
|
||||
"numeric_scale": null,
|
||||
"is_nullable": true,
|
||||
"is_unique": false,
|
||||
"is_indexed": true,
|
||||
"is_primary_key": false,
|
||||
"is_generated": false,
|
||||
"generation_expression": null,
|
||||
"has_auto_increment": false,
|
||||
"foreign_key_table": null,
|
||||
"foreign_key_column": null
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
{
|
||||
"collection": "directus_sync_id_map",
|
||||
"field": "id",
|
||||
"type": "integer",
|
||||
"meta": null,
|
||||
"schema": {
|
||||
"name": "id",
|
||||
"table": "directus_sync_id_map",
|
||||
"data_type": "integer",
|
||||
"default_value": null,
|
||||
"max_length": null,
|
||||
"numeric_precision": null,
|
||||
"numeric_scale": null,
|
||||
"is_nullable": false,
|
||||
"is_unique": false,
|
||||
"is_indexed": false,
|
||||
"is_primary_key": true,
|
||||
"is_generated": false,
|
||||
"generation_expression": null,
|
||||
"has_auto_increment": true,
|
||||
"foreign_key_table": null,
|
||||
"foreign_key_column": null
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
{
|
||||
"collection": "directus_sync_id_map",
|
||||
"field": "local_id",
|
||||
"type": "string",
|
||||
"meta": null,
|
||||
"schema": {
|
||||
"name": "local_id",
|
||||
"table": "directus_sync_id_map",
|
||||
"data_type": "varchar",
|
||||
"default_value": null,
|
||||
"max_length": 255,
|
||||
"numeric_precision": null,
|
||||
"numeric_scale": null,
|
||||
"is_nullable": false,
|
||||
"is_unique": false,
|
||||
"is_indexed": false,
|
||||
"is_primary_key": false,
|
||||
"is_generated": false,
|
||||
"generation_expression": null,
|
||||
"has_auto_increment": false,
|
||||
"foreign_key_table": null,
|
||||
"foreign_key_column": null
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
{
|
||||
"collection": "directus_sync_id_map",
|
||||
"field": "sync_id",
|
||||
"type": "string",
|
||||
"meta": null,
|
||||
"schema": {
|
||||
"name": "sync_id",
|
||||
"table": "directus_sync_id_map",
|
||||
"data_type": "varchar",
|
||||
"default_value": null,
|
||||
"max_length": 255,
|
||||
"numeric_precision": null,
|
||||
"numeric_scale": null,
|
||||
"is_nullable": false,
|
||||
"is_unique": false,
|
||||
"is_indexed": false,
|
||||
"is_primary_key": false,
|
||||
"is_generated": false,
|
||||
"generation_expression": null,
|
||||
"has_auto_increment": false,
|
||||
"foreign_key_table": null,
|
||||
"foreign_key_column": null
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
{
|
||||
"collection": "directus_sync_id_map",
|
||||
"field": "table",
|
||||
"type": "string",
|
||||
"meta": null,
|
||||
"schema": {
|
||||
"name": "table",
|
||||
"table": "directus_sync_id_map",
|
||||
"data_type": "varchar",
|
||||
"default_value": null,
|
||||
"max_length": 255,
|
||||
"numeric_precision": null,
|
||||
"numeric_scale": null,
|
||||
"is_nullable": false,
|
||||
"is_unique": false,
|
||||
"is_indexed": false,
|
||||
"is_primary_key": false,
|
||||
"is_generated": false,
|
||||
"generation_expression": null,
|
||||
"has_auto_increment": false,
|
||||
"foreign_key_table": null,
|
||||
"foreign_key_column": null
|
||||
}
|
||||
}
|
||||
5
backend/directus-config/snapshot/info.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"version": 1,
|
||||
"directus": "11.4.1",
|
||||
"vendor": "sqlite"
|
||||
}
|
||||
973
backend/directus-config/specs/item.graphql
Normal file
@ -0,0 +1,973 @@
|
||||
type Query {
|
||||
"""There's no data to query."""
|
||||
_empty: Void
|
||||
}
|
||||
|
||||
type Mutation
|
||||
|
||||
type Subscription {
|
||||
directus_folders_mutated(event: EventEnum): directus_folders_mutated
|
||||
directus_files_mutated(event: EventEnum): directus_files_mutated
|
||||
directus_operations_mutated(event: EventEnum): directus_operations_mutated
|
||||
directus_notifications_mutated(event: EventEnum): directus_notifications_mutated
|
||||
directus_translations_mutated(event: EventEnum): directus_translations_mutated
|
||||
directus_shares_mutated(event: EventEnum): directus_shares_mutated
|
||||
directus_versions_mutated(event: EventEnum): directus_versions_mutated
|
||||
directus_revisions_mutated(event: EventEnum): directus_revisions_mutated
|
||||
directus_users_mutated(event: EventEnum): directus_users_mutated
|
||||
directus_webhooks_mutated(event: EventEnum): directus_webhooks_mutated
|
||||
directus_settings_mutated(event: EventEnum): directus_settings_mutated
|
||||
directus_policies_mutated(event: EventEnum): directus_policies_mutated
|
||||
directus_permissions_mutated(event: EventEnum): directus_permissions_mutated
|
||||
directus_access_mutated(event: EventEnum): directus_access_mutated
|
||||
directus_dashboards_mutated(event: EventEnum): directus_dashboards_mutated
|
||||
directus_flows_mutated(event: EventEnum): directus_flows_mutated
|
||||
directus_panels_mutated(event: EventEnum): directus_panels_mutated
|
||||
directus_presets_mutated(event: EventEnum): directus_presets_mutated
|
||||
directus_roles_mutated(event: EventEnum): directus_roles_mutated
|
||||
directus_comments_mutated(event: EventEnum): directus_comments_mutated
|
||||
directus_activity_mutated(event: EventEnum): directus_activity_mutated
|
||||
}
|
||||
|
||||
"""The `Boolean` scalar type represents `true` or `false`."""
|
||||
scalar Boolean
|
||||
|
||||
"""ISO8601 Date values"""
|
||||
scalar Date
|
||||
|
||||
"""BigInt value"""
|
||||
scalar GraphQLBigInt
|
||||
|
||||
"""A Float or a String"""
|
||||
scalar GraphQLStringOrFloat
|
||||
|
||||
"""Hashed string values"""
|
||||
scalar Hash
|
||||
|
||||
"""
|
||||
The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `"4"`) or integer (such as `4`) input value will be accepted as an ID.
|
||||
"""
|
||||
scalar ID
|
||||
|
||||
"""
|
||||
The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.
|
||||
"""
|
||||
scalar Int
|
||||
|
||||
"""
|
||||
The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf).
|
||||
"""
|
||||
scalar JSON
|
||||
|
||||
"""
|
||||
The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.
|
||||
"""
|
||||
scalar String
|
||||
|
||||
"""Represents NULL values"""
|
||||
scalar Void
|
||||
|
||||
enum EventEnum {
|
||||
create
|
||||
update
|
||||
delete
|
||||
}
|
||||
|
||||
type count_functions {
|
||||
count: Int
|
||||
}
|
||||
|
||||
type datetime_functions {
|
||||
year: Int
|
||||
month: Int
|
||||
week: Int
|
||||
day: Int
|
||||
weekday: Int
|
||||
hour: Int
|
||||
minute: Int
|
||||
second: Int
|
||||
}
|
||||
|
||||
type directus_access {
|
||||
id: ID!
|
||||
role(filter: directus_roles_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_roles
|
||||
user(filter: directus_users_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_users
|
||||
policy(filter: directus_policies_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_policies
|
||||
sort: Int
|
||||
}
|
||||
|
||||
type directus_access_mutated {
|
||||
key: ID!
|
||||
event: EventEnum
|
||||
data: directus_access
|
||||
}
|
||||
|
||||
type directus_activity {
|
||||
id: ID!
|
||||
action: String!
|
||||
user(filter: directus_users_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_users
|
||||
timestamp: Date
|
||||
timestamp_func: datetime_functions
|
||||
ip: String
|
||||
user_agent: String
|
||||
collection: String!
|
||||
item: String!
|
||||
origin: String
|
||||
revisions(filter: directus_revisions_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): [directus_revisions]
|
||||
revisions_func: count_functions
|
||||
}
|
||||
|
||||
type directus_activity_mutated {
|
||||
key: ID!
|
||||
event: EventEnum
|
||||
data: directus_activity
|
||||
}
|
||||
|
||||
type directus_comments {
|
||||
id: ID!
|
||||
collection: String!
|
||||
item: String!
|
||||
comment: String!
|
||||
date_created: Date
|
||||
date_created_func: datetime_functions
|
||||
date_updated: Date
|
||||
date_updated_func: datetime_functions
|
||||
user_created(filter: directus_users_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_users
|
||||
user_updated(filter: directus_users_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_users
|
||||
}
|
||||
|
||||
type directus_comments_mutated {
|
||||
key: ID!
|
||||
event: EventEnum
|
||||
data: directus_comments
|
||||
}
|
||||
|
||||
type directus_dashboards {
|
||||
id: ID!
|
||||
name: String!
|
||||
icon: String
|
||||
note: String
|
||||
date_created: Date
|
||||
date_created_func: datetime_functions
|
||||
user_created(filter: directus_users_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_users
|
||||
color: String
|
||||
panels(filter: directus_panels_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): [directus_panels]
|
||||
panels_func: count_functions
|
||||
}
|
||||
|
||||
type directus_dashboards_mutated {
|
||||
key: ID!
|
||||
event: EventEnum
|
||||
data: directus_dashboards
|
||||
}
|
||||
|
||||
type directus_files {
|
||||
id: ID!
|
||||
storage: String!
|
||||
filename_disk: String
|
||||
filename_download: String!
|
||||
title: String
|
||||
type: String
|
||||
folder(filter: directus_folders_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_folders
|
||||
uploaded_by(filter: directus_users_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_users
|
||||
created_on: Date
|
||||
created_on_func: datetime_functions
|
||||
modified_by(filter: directus_users_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_users
|
||||
modified_on: Date
|
||||
modified_on_func: datetime_functions
|
||||
charset: String
|
||||
filesize: GraphQLBigInt
|
||||
width: Int
|
||||
height: Int
|
||||
duration: Int
|
||||
embed: String
|
||||
description: String
|
||||
location: String
|
||||
tags: JSON
|
||||
tags_func: count_functions
|
||||
metadata: JSON
|
||||
metadata_func: count_functions
|
||||
focal_point_x: Int
|
||||
focal_point_y: Int
|
||||
tus_id: String
|
||||
tus_data: JSON
|
||||
tus_data_func: count_functions
|
||||
uploaded_on: Date
|
||||
uploaded_on_func: datetime_functions
|
||||
}
|
||||
|
||||
type directus_files_mutated {
|
||||
key: ID!
|
||||
event: EventEnum
|
||||
data: directus_files
|
||||
}
|
||||
|
||||
type directus_flows {
|
||||
id: ID!
|
||||
name: String!
|
||||
icon: String
|
||||
color: String
|
||||
description: String
|
||||
status: String
|
||||
trigger: String
|
||||
accountability: String
|
||||
options: JSON
|
||||
options_func: count_functions
|
||||
operation(filter: directus_operations_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_operations
|
||||
date_created: Date
|
||||
date_created_func: datetime_functions
|
||||
user_created(filter: directus_users_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_users
|
||||
operations(filter: directus_operations_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): [directus_operations]
|
||||
operations_func: count_functions
|
||||
}
|
||||
|
||||
type directus_flows_mutated {
|
||||
key: ID!
|
||||
event: EventEnum
|
||||
data: directus_flows
|
||||
}
|
||||
|
||||
type directus_folders {
|
||||
id: ID!
|
||||
name: String!
|
||||
parent(filter: directus_folders_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_folders
|
||||
}
|
||||
|
||||
type directus_folders_mutated {
|
||||
key: ID!
|
||||
event: EventEnum
|
||||
data: directus_folders
|
||||
}
|
||||
|
||||
type directus_notifications {
|
||||
id: ID!
|
||||
timestamp: Date
|
||||
timestamp_func: datetime_functions
|
||||
status: String
|
||||
recipient(filter: directus_users_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_users
|
||||
sender(filter: directus_users_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_users
|
||||
subject: String!
|
||||
message: String
|
||||
collection: String
|
||||
item: String
|
||||
}
|
||||
|
||||
type directus_notifications_mutated {
|
||||
key: ID!
|
||||
event: EventEnum
|
||||
data: directus_notifications
|
||||
}
|
||||
|
||||
type directus_operations {
|
||||
id: ID!
|
||||
name: String
|
||||
key: String!
|
||||
type: String!
|
||||
position_x: Int!
|
||||
position_y: Int!
|
||||
options: JSON
|
||||
options_func: count_functions
|
||||
resolve(filter: directus_operations_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_operations
|
||||
reject(filter: directus_operations_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_operations
|
||||
flow(filter: directus_flows_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_flows
|
||||
date_created: Date
|
||||
date_created_func: datetime_functions
|
||||
user_created(filter: directus_users_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_users
|
||||
}
|
||||
|
||||
type directus_operations_mutated {
|
||||
key: ID!
|
||||
event: EventEnum
|
||||
data: directus_operations
|
||||
}
|
||||
|
||||
type directus_panels {
|
||||
id: ID!
|
||||
dashboard(filter: directus_dashboards_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_dashboards
|
||||
name: String
|
||||
icon: String
|
||||
color: String
|
||||
show_header: Boolean!
|
||||
note: String
|
||||
type: String!
|
||||
position_x: Int!
|
||||
position_y: Int!
|
||||
width: Int!
|
||||
height: Int!
|
||||
options: JSON
|
||||
options_func: count_functions
|
||||
date_created: Date
|
||||
date_created_func: datetime_functions
|
||||
user_created(filter: directus_users_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_users
|
||||
}
|
||||
|
||||
type directus_panels_mutated {
|
||||
key: ID!
|
||||
event: EventEnum
|
||||
data: directus_panels
|
||||
}
|
||||
|
||||
type directus_permissions {
|
||||
id: ID
|
||||
collection: String!
|
||||
action: String!
|
||||
permissions: JSON
|
||||
permissions_func: count_functions
|
||||
validation: JSON
|
||||
validation_func: count_functions
|
||||
presets: JSON
|
||||
presets_func: count_functions
|
||||
fields: [String]
|
||||
policy(filter: directus_policies_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_policies
|
||||
}
|
||||
|
||||
type directus_permissions_mutated {
|
||||
key: ID!
|
||||
event: EventEnum
|
||||
data: directus_permissions
|
||||
}
|
||||
|
||||
type directus_policies {
|
||||
id: ID!
|
||||
name: String!
|
||||
icon: String
|
||||
description: String
|
||||
ip_access: [String]
|
||||
|
||||
"""$t:field_options.directus_policies.enforce_tfa"""
|
||||
enforce_tfa: Boolean!
|
||||
admin_access: Boolean!
|
||||
app_access: Boolean!
|
||||
permissions(filter: directus_permissions_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): [directus_permissions]
|
||||
permissions_func: count_functions
|
||||
users(filter: directus_access_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): [directus_access]
|
||||
users_func: count_functions
|
||||
roles(filter: directus_access_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): [directus_access]
|
||||
roles_func: count_functions
|
||||
}
|
||||
|
||||
type directus_policies_mutated {
|
||||
key: ID!
|
||||
event: EventEnum
|
||||
data: directus_policies
|
||||
}
|
||||
|
||||
type directus_presets {
|
||||
id: ID!
|
||||
bookmark: String
|
||||
user(filter: directus_users_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_users
|
||||
role(filter: directus_roles_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_roles
|
||||
collection: String
|
||||
search: String
|
||||
layout: String
|
||||
layout_query: JSON
|
||||
layout_query_func: count_functions
|
||||
layout_options: JSON
|
||||
layout_options_func: count_functions
|
||||
refresh_interval: Int
|
||||
filter: JSON
|
||||
filter_func: count_functions
|
||||
icon: String
|
||||
color: String
|
||||
}
|
||||
|
||||
type directus_presets_mutated {
|
||||
key: ID!
|
||||
event: EventEnum
|
||||
data: directus_presets
|
||||
}
|
||||
|
||||
type directus_revisions {
|
||||
id: ID!
|
||||
activity(filter: directus_activity_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_activity
|
||||
collection: String!
|
||||
item: String!
|
||||
data: JSON
|
||||
data_func: count_functions
|
||||
delta: JSON
|
||||
delta_func: count_functions
|
||||
parent(filter: directus_revisions_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_revisions
|
||||
version(filter: directus_versions_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_versions
|
||||
}
|
||||
|
||||
type directus_revisions_mutated {
|
||||
key: ID!
|
||||
event: EventEnum
|
||||
data: directus_revisions
|
||||
}
|
||||
|
||||
type directus_roles {
|
||||
id: ID!
|
||||
name: String!
|
||||
icon: String
|
||||
description: String
|
||||
parent(filter: directus_roles_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_roles
|
||||
children(filter: directus_roles_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): [directus_roles]
|
||||
children_func: count_functions
|
||||
policies(filter: directus_access_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): [directus_access]
|
||||
policies_func: count_functions
|
||||
users(filter: directus_users_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): [directus_users]
|
||||
users_func: count_functions
|
||||
}
|
||||
|
||||
type directus_roles_mutated {
|
||||
key: ID!
|
||||
event: EventEnum
|
||||
data: directus_roles
|
||||
}
|
||||
|
||||
type directus_settings {
|
||||
id: ID!
|
||||
project_name: String
|
||||
project_url: String
|
||||
|
||||
"""$t:field_options.directus_settings.project_color_note"""
|
||||
project_color: String
|
||||
project_logo(filter: directus_files_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_files
|
||||
public_foreground(filter: directus_files_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_files
|
||||
public_background(filter: directus_files_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_files
|
||||
public_note: String
|
||||
auth_login_attempts: Int
|
||||
auth_password_policy: String
|
||||
storage_asset_transform: String
|
||||
storage_asset_presets: JSON
|
||||
storage_asset_presets_func: count_functions
|
||||
custom_css: String
|
||||
storage_default_folder(filter: directus_folders_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_folders
|
||||
basemaps: JSON
|
||||
basemaps_func: count_functions
|
||||
mapbox_key: String
|
||||
module_bar: JSON
|
||||
module_bar_func: count_functions
|
||||
project_descriptor: String
|
||||
default_language: String
|
||||
custom_aspect_ratios: JSON
|
||||
custom_aspect_ratios_func: count_functions
|
||||
public_favicon(filter: directus_files_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_files
|
||||
default_appearance: String
|
||||
default_theme_light: String
|
||||
theme_light_overrides: JSON
|
||||
theme_light_overrides_func: count_functions
|
||||
default_theme_dark: String
|
||||
theme_dark_overrides: JSON
|
||||
theme_dark_overrides_func: count_functions
|
||||
report_error_url: String
|
||||
report_bug_url: String
|
||||
report_feature_url: String
|
||||
|
||||
"""$t:fields.directus_settings.public_registration_note"""
|
||||
public_registration: Boolean!
|
||||
|
||||
"""$t:fields.directus_settings.public_registration_verify_email_note"""
|
||||
public_registration_verify_email: Boolean
|
||||
public_registration_role(filter: directus_roles_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_roles
|
||||
|
||||
"""$t:fields.directus_settings.public_registration_email_filter_note"""
|
||||
public_registration_email_filter: JSON
|
||||
public_registration_email_filter_func: count_functions
|
||||
}
|
||||
|
||||
type directus_settings_mutated {
|
||||
key: ID!
|
||||
event: EventEnum
|
||||
data: directus_settings
|
||||
}
|
||||
|
||||
type directus_shares {
|
||||
id: ID!
|
||||
name: String
|
||||
collection: String!
|
||||
item: String!
|
||||
role(filter: directus_roles_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_roles
|
||||
|
||||
"""$t:shared_leave_blank_for_passwordless_access"""
|
||||
password: Hash
|
||||
user_created(filter: directus_users_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_users
|
||||
date_created: Date
|
||||
date_created_func: datetime_functions
|
||||
|
||||
"""$t:shared_leave_blank_for_unlimited"""
|
||||
date_start: Date
|
||||
date_start_func: datetime_functions
|
||||
|
||||
"""$t:shared_leave_blank_for_unlimited"""
|
||||
date_end: Date
|
||||
date_end_func: datetime_functions
|
||||
times_used: Int
|
||||
|
||||
"""$t:shared_leave_blank_for_unlimited"""
|
||||
max_uses: Int
|
||||
}
|
||||
|
||||
type directus_shares_mutated {
|
||||
key: ID!
|
||||
event: EventEnum
|
||||
data: directus_shares
|
||||
}
|
||||
|
||||
type directus_translations {
|
||||
id: ID!
|
||||
language: String!
|
||||
key: String!
|
||||
value: String!
|
||||
}
|
||||
|
||||
type directus_translations_mutated {
|
||||
key: ID!
|
||||
event: EventEnum
|
||||
data: directus_translations
|
||||
}
|
||||
|
||||
type directus_users {
|
||||
id: ID!
|
||||
first_name: String
|
||||
last_name: String
|
||||
email: String
|
||||
password: Hash
|
||||
location: String
|
||||
title: String
|
||||
description: String
|
||||
tags: JSON
|
||||
tags_func: count_functions
|
||||
avatar(filter: directus_files_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_files
|
||||
language: String
|
||||
tfa_secret: Hash
|
||||
status: String
|
||||
role(filter: directus_roles_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_roles
|
||||
token: Hash
|
||||
last_access: Date
|
||||
last_access_func: datetime_functions
|
||||
last_page: String
|
||||
provider: String
|
||||
external_identifier: String
|
||||
auth_data: JSON
|
||||
auth_data_func: count_functions
|
||||
email_notifications: Boolean
|
||||
appearance: String
|
||||
theme_dark: String
|
||||
theme_light: String
|
||||
theme_light_overrides: JSON
|
||||
theme_light_overrides_func: count_functions
|
||||
theme_dark_overrides: JSON
|
||||
theme_dark_overrides_func: count_functions
|
||||
policies(filter: directus_access_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): [directus_access]
|
||||
policies_func: count_functions
|
||||
}
|
||||
|
||||
type directus_users_mutated {
|
||||
key: ID!
|
||||
event: EventEnum
|
||||
data: directus_users
|
||||
}
|
||||
|
||||
type directus_versions {
|
||||
id: ID!
|
||||
key: String!
|
||||
name: String
|
||||
collection: String!
|
||||
item: String!
|
||||
hash: String
|
||||
date_created: Date
|
||||
date_created_func: datetime_functions
|
||||
date_updated: Date
|
||||
date_updated_func: datetime_functions
|
||||
user_created(filter: directus_users_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_users
|
||||
user_updated(filter: directus_users_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_users
|
||||
delta: JSON
|
||||
delta_func: count_functions
|
||||
}
|
||||
|
||||
type directus_versions_mutated {
|
||||
key: ID!
|
||||
event: EventEnum
|
||||
data: directus_versions
|
||||
}
|
||||
|
||||
type directus_webhooks {
|
||||
id: ID!
|
||||
name: String!
|
||||
method: String
|
||||
url: String!
|
||||
status: String
|
||||
data: Boolean
|
||||
actions: [String]!
|
||||
collections: [String]!
|
||||
headers: JSON
|
||||
headers_func: count_functions
|
||||
was_active_before_deprecation: Boolean!
|
||||
migrated_flow(filter: directus_flows_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_flows
|
||||
}
|
||||
|
||||
type directus_webhooks_mutated {
|
||||
key: ID!
|
||||
event: EventEnum
|
||||
data: directus_webhooks
|
||||
}
|
||||
|
||||
input big_int_filter_operators {
|
||||
_eq: GraphQLBigInt
|
||||
_neq: GraphQLBigInt
|
||||
_in: [GraphQLBigInt]
|
||||
_nin: [GraphQLBigInt]
|
||||
_gt: GraphQLBigInt
|
||||
_gte: GraphQLBigInt
|
||||
_lt: GraphQLBigInt
|
||||
_lte: GraphQLBigInt
|
||||
_null: Boolean
|
||||
_nnull: Boolean
|
||||
_between: [GraphQLBigInt]
|
||||
_nbetween: [GraphQLBigInt]
|
||||
}
|
||||
|
||||
input boolean_filter_operators {
|
||||
_eq: Boolean
|
||||
_neq: Boolean
|
||||
_null: Boolean
|
||||
_nnull: Boolean
|
||||
}
|
||||
|
||||
input count_function_filter_operators {
|
||||
count: number_filter_operators
|
||||
}
|
||||
|
||||
input date_filter_operators {
|
||||
_eq: String
|
||||
_neq: String
|
||||
_gt: String
|
||||
_gte: String
|
||||
_lt: String
|
||||
_lte: String
|
||||
_null: Boolean
|
||||
_nnull: Boolean
|
||||
_in: [String]
|
||||
_nin: [String]
|
||||
_between: [GraphQLStringOrFloat]
|
||||
_nbetween: [GraphQLStringOrFloat]
|
||||
}
|
||||
|
||||
input datetime_function_filter_operators {
|
||||
year: number_filter_operators
|
||||
month: number_filter_operators
|
||||
week: number_filter_operators
|
||||
day: number_filter_operators
|
||||
weekday: number_filter_operators
|
||||
hour: number_filter_operators
|
||||
minute: number_filter_operators
|
||||
second: number_filter_operators
|
||||
}
|
||||
|
||||
input directus_access_filter {
|
||||
id: string_filter_operators
|
||||
role: directus_roles_filter
|
||||
user: directus_users_filter
|
||||
policy: directus_policies_filter
|
||||
sort: number_filter_operators
|
||||
_and: [directus_access_filter]
|
||||
_or: [directus_access_filter]
|
||||
}
|
||||
|
||||
input directus_activity_filter {
|
||||
id: number_filter_operators
|
||||
action: string_filter_operators
|
||||
user: directus_users_filter
|
||||
timestamp: date_filter_operators
|
||||
timestamp_func: datetime_function_filter_operators
|
||||
ip: string_filter_operators
|
||||
user_agent: string_filter_operators
|
||||
collection: string_filter_operators
|
||||
item: string_filter_operators
|
||||
origin: string_filter_operators
|
||||
revisions: directus_revisions_filter
|
||||
revisions_func: count_function_filter_operators
|
||||
_and: [directus_activity_filter]
|
||||
_or: [directus_activity_filter]
|
||||
}
|
||||
|
||||
input directus_dashboards_filter {
|
||||
id: string_filter_operators
|
||||
name: string_filter_operators
|
||||
icon: string_filter_operators
|
||||
note: string_filter_operators
|
||||
date_created: date_filter_operators
|
||||
date_created_func: datetime_function_filter_operators
|
||||
user_created: directus_users_filter
|
||||
color: string_filter_operators
|
||||
panels: directus_panels_filter
|
||||
panels_func: count_function_filter_operators
|
||||
_and: [directus_dashboards_filter]
|
||||
_or: [directus_dashboards_filter]
|
||||
}
|
||||
|
||||
input directus_files_filter {
|
||||
id: string_filter_operators
|
||||
storage: string_filter_operators
|
||||
filename_disk: string_filter_operators
|
||||
filename_download: string_filter_operators
|
||||
title: string_filter_operators
|
||||
type: string_filter_operators
|
||||
folder: directus_folders_filter
|
||||
uploaded_by: directus_users_filter
|
||||
created_on: date_filter_operators
|
||||
created_on_func: datetime_function_filter_operators
|
||||
modified_by: directus_users_filter
|
||||
modified_on: date_filter_operators
|
||||
modified_on_func: datetime_function_filter_operators
|
||||
charset: string_filter_operators
|
||||
filesize: big_int_filter_operators
|
||||
width: number_filter_operators
|
||||
height: number_filter_operators
|
||||
duration: number_filter_operators
|
||||
embed: string_filter_operators
|
||||
description: string_filter_operators
|
||||
location: string_filter_operators
|
||||
tags: string_filter_operators
|
||||
tags_func: count_function_filter_operators
|
||||
metadata: string_filter_operators
|
||||
metadata_func: count_function_filter_operators
|
||||
focal_point_x: number_filter_operators
|
||||
focal_point_y: number_filter_operators
|
||||
tus_id: string_filter_operators
|
||||
tus_data: string_filter_operators
|
||||
tus_data_func: count_function_filter_operators
|
||||
uploaded_on: date_filter_operators
|
||||
uploaded_on_func: datetime_function_filter_operators
|
||||
_and: [directus_files_filter]
|
||||
_or: [directus_files_filter]
|
||||
}
|
||||
|
||||
input directus_flows_filter {
|
||||
id: string_filter_operators
|
||||
name: string_filter_operators
|
||||
icon: string_filter_operators
|
||||
color: string_filter_operators
|
||||
description: string_filter_operators
|
||||
status: string_filter_operators
|
||||
trigger: string_filter_operators
|
||||
accountability: string_filter_operators
|
||||
options: string_filter_operators
|
||||
options_func: count_function_filter_operators
|
||||
operation: directus_operations_filter
|
||||
date_created: date_filter_operators
|
||||
date_created_func: datetime_function_filter_operators
|
||||
user_created: directus_users_filter
|
||||
operations: directus_operations_filter
|
||||
operations_func: count_function_filter_operators
|
||||
_and: [directus_flows_filter]
|
||||
_or: [directus_flows_filter]
|
||||
}
|
||||
|
||||
input directus_folders_filter {
|
||||
id: string_filter_operators
|
||||
name: string_filter_operators
|
||||
parent: directus_folders_filter
|
||||
_and: [directus_folders_filter]
|
||||
_or: [directus_folders_filter]
|
||||
}
|
||||
|
||||
input directus_operations_filter {
|
||||
id: string_filter_operators
|
||||
name: string_filter_operators
|
||||
key: string_filter_operators
|
||||
type: string_filter_operators
|
||||
position_x: number_filter_operators
|
||||
position_y: number_filter_operators
|
||||
options: string_filter_operators
|
||||
options_func: count_function_filter_operators
|
||||
resolve: directus_operations_filter
|
||||
reject: directus_operations_filter
|
||||
flow: directus_flows_filter
|
||||
date_created: date_filter_operators
|
||||
date_created_func: datetime_function_filter_operators
|
||||
user_created: directus_users_filter
|
||||
_and: [directus_operations_filter]
|
||||
_or: [directus_operations_filter]
|
||||
}
|
||||
|
||||
input directus_panels_filter {
|
||||
id: string_filter_operators
|
||||
dashboard: directus_dashboards_filter
|
||||
name: string_filter_operators
|
||||
icon: string_filter_operators
|
||||
color: string_filter_operators
|
||||
show_header: boolean_filter_operators
|
||||
note: string_filter_operators
|
||||
type: string_filter_operators
|
||||
position_x: number_filter_operators
|
||||
position_y: number_filter_operators
|
||||
width: number_filter_operators
|
||||
height: number_filter_operators
|
||||
options: string_filter_operators
|
||||
options_func: count_function_filter_operators
|
||||
date_created: date_filter_operators
|
||||
date_created_func: datetime_function_filter_operators
|
||||
user_created: directus_users_filter
|
||||
_and: [directus_panels_filter]
|
||||
_or: [directus_panels_filter]
|
||||
}
|
||||
|
||||
input directus_permissions_filter {
|
||||
id: number_filter_operators
|
||||
collection: string_filter_operators
|
||||
action: string_filter_operators
|
||||
permissions: string_filter_operators
|
||||
permissions_func: count_function_filter_operators
|
||||
validation: string_filter_operators
|
||||
validation_func: count_function_filter_operators
|
||||
presets: string_filter_operators
|
||||
presets_func: count_function_filter_operators
|
||||
fields: string_filter_operators
|
||||
policy: directus_policies_filter
|
||||
_and: [directus_permissions_filter]
|
||||
_or: [directus_permissions_filter]
|
||||
}
|
||||
|
||||
input directus_policies_filter {
|
||||
id: string_filter_operators
|
||||
name: string_filter_operators
|
||||
icon: string_filter_operators
|
||||
description: string_filter_operators
|
||||
ip_access: string_filter_operators
|
||||
enforce_tfa: boolean_filter_operators
|
||||
admin_access: boolean_filter_operators
|
||||
app_access: boolean_filter_operators
|
||||
permissions: directus_permissions_filter
|
||||
permissions_func: count_function_filter_operators
|
||||
users: directus_access_filter
|
||||
users_func: count_function_filter_operators
|
||||
roles: directus_access_filter
|
||||
roles_func: count_function_filter_operators
|
||||
_and: [directus_policies_filter]
|
||||
_or: [directus_policies_filter]
|
||||
}
|
||||
|
||||
input directus_revisions_filter {
|
||||
id: number_filter_operators
|
||||
activity: directus_activity_filter
|
||||
collection: string_filter_operators
|
||||
item: string_filter_operators
|
||||
data: string_filter_operators
|
||||
data_func: count_function_filter_operators
|
||||
delta: string_filter_operators
|
||||
delta_func: count_function_filter_operators
|
||||
parent: directus_revisions_filter
|
||||
version: directus_versions_filter
|
||||
_and: [directus_revisions_filter]
|
||||
_or: [directus_revisions_filter]
|
||||
}
|
||||
|
||||
input directus_roles_filter {
|
||||
id: string_filter_operators
|
||||
name: string_filter_operators
|
||||
icon: string_filter_operators
|
||||
description: string_filter_operators
|
||||
parent: directus_roles_filter
|
||||
children: directus_roles_filter
|
||||
children_func: count_function_filter_operators
|
||||
policies: directus_access_filter
|
||||
policies_func: count_function_filter_operators
|
||||
users: directus_users_filter
|
||||
users_func: count_function_filter_operators
|
||||
_and: [directus_roles_filter]
|
||||
_or: [directus_roles_filter]
|
||||
}
|
||||
|
||||
input directus_users_filter {
|
||||
id: string_filter_operators
|
||||
first_name: string_filter_operators
|
||||
last_name: string_filter_operators
|
||||
email: string_filter_operators
|
||||
password: hash_filter_operators
|
||||
location: string_filter_operators
|
||||
title: string_filter_operators
|
||||
description: string_filter_operators
|
||||
tags: string_filter_operators
|
||||
tags_func: count_function_filter_operators
|
||||
avatar: directus_files_filter
|
||||
language: string_filter_operators
|
||||
tfa_secret: hash_filter_operators
|
||||
status: string_filter_operators
|
||||
role: directus_roles_filter
|
||||
token: hash_filter_operators
|
||||
last_access: date_filter_operators
|
||||
last_access_func: datetime_function_filter_operators
|
||||
last_page: string_filter_operators
|
||||
provider: string_filter_operators
|
||||
external_identifier: string_filter_operators
|
||||
auth_data: string_filter_operators
|
||||
auth_data_func: count_function_filter_operators
|
||||
email_notifications: boolean_filter_operators
|
||||
appearance: string_filter_operators
|
||||
theme_dark: string_filter_operators
|
||||
theme_light: string_filter_operators
|
||||
theme_light_overrides: string_filter_operators
|
||||
theme_light_overrides_func: count_function_filter_operators
|
||||
theme_dark_overrides: string_filter_operators
|
||||
theme_dark_overrides_func: count_function_filter_operators
|
||||
policies: directus_access_filter
|
||||
policies_func: count_function_filter_operators
|
||||
_and: [directus_users_filter]
|
||||
_or: [directus_users_filter]
|
||||
}
|
||||
|
||||
input directus_versions_filter {
|
||||
id: string_filter_operators
|
||||
key: string_filter_operators
|
||||
name: string_filter_operators
|
||||
collection: string_filter_operators
|
||||
item: string_filter_operators
|
||||
hash: string_filter_operators
|
||||
date_created: date_filter_operators
|
||||
date_created_func: datetime_function_filter_operators
|
||||
date_updated: date_filter_operators
|
||||
date_updated_func: datetime_function_filter_operators
|
||||
user_created: directus_users_filter
|
||||
user_updated: directus_users_filter
|
||||
delta: string_filter_operators
|
||||
delta_func: count_function_filter_operators
|
||||
_and: [directus_versions_filter]
|
||||
_or: [directus_versions_filter]
|
||||
}
|
||||
|
||||
input hash_filter_operators {
|
||||
_null: Boolean
|
||||
_nnull: Boolean
|
||||
_empty: Boolean
|
||||
_nempty: Boolean
|
||||
}
|
||||
|
||||
input number_filter_operators {
|
||||
_eq: GraphQLStringOrFloat
|
||||
_neq: GraphQLStringOrFloat
|
||||
_in: [GraphQLStringOrFloat]
|
||||
_nin: [GraphQLStringOrFloat]
|
||||
_gt: GraphQLStringOrFloat
|
||||
_gte: GraphQLStringOrFloat
|
||||
_lt: GraphQLStringOrFloat
|
||||
_lte: GraphQLStringOrFloat
|
||||
_null: Boolean
|
||||
_nnull: Boolean
|
||||
_between: [GraphQLStringOrFloat]
|
||||
_nbetween: [GraphQLStringOrFloat]
|
||||
}
|
||||
|
||||
input string_filter_operators {
|
||||
_eq: String
|
||||
_neq: String
|
||||
_contains: String
|
||||
_icontains: String
|
||||
_ncontains: String
|
||||
_starts_with: String
|
||||
_nstarts_with: String
|
||||
_istarts_with: String
|
||||
_nistarts_with: String
|
||||
_ends_with: String
|
||||
_nends_with: String
|
||||
_iends_with: String
|
||||
_niends_with: String
|
||||
_in: [String]
|
||||
_nin: [String]
|
||||
_null: Boolean
|
||||
_nnull: Boolean
|
||||
_empty: Boolean
|
||||
_nempty: Boolean
|
||||
}
|
||||
9731
backend/directus-config/specs/openapi.json
Normal file
2813
backend/directus-config/specs/system.graphql
Normal file
6
backend/extensions/package.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "directus-extensions",
|
||||
"dependencies": {
|
||||
"directus-extension-sync": "^3.0.2"
|
||||
}
|
||||
}
|
||||
1
frontend/.env
Normal file
@ -0,0 +1 @@
|
||||
VITE_OPEN_COLLECTIVE_API_KEY=your_key
|
||||
3
frontend/.eslintignore
Normal file
@ -0,0 +1,3 @@
|
||||
node_modules/
|
||||
dist/
|
||||
data/
|
||||
223
frontend/.eslintrc.cjs
Normal file
@ -0,0 +1,223 @@
|
||||
// eslint-disable-next-line import/no-commonjs
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true,
|
||||
},
|
||||
extends: [
|
||||
'standard',
|
||||
'eslint:recommended',
|
||||
'plugin:@eslint-community/eslint-comments/recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:import/recommended',
|
||||
'plugin:import/typescript',
|
||||
// 'plugin:promise/recommended',
|
||||
'plugin:security/recommended-legacy',
|
||||
'plugin:react/recommended',
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
parser: '@typescript-eslint/parser',
|
||||
sourceType: 'module',
|
||||
},
|
||||
plugins: [
|
||||
'@typescript-eslint',
|
||||
'import',
|
||||
'promise',
|
||||
'security',
|
||||
'no-catch-all',
|
||||
'react',
|
||||
'react-hooks',
|
||||
'react-refresh',
|
||||
],
|
||||
// TODO also parse this
|
||||
ignorePatterns: ['vite.config.ts'],
|
||||
settings: {
|
||||
'import/resolver': {
|
||||
typescript: true,
|
||||
node: {
|
||||
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
||||
},
|
||||
},
|
||||
react: {
|
||||
version: '18.2.0',
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'react-hooks/rules-of-hooks': 'error', // Checks rules of Hooks
|
||||
'react-hooks/exhaustive-deps': 'warn', // Checks effect dependencies
|
||||
'react/react-in-jsx-scope': 'off', // Disable requirement for React import
|
||||
'no-catch-all/no-catch-all': 'error',
|
||||
'no-console': 'error',
|
||||
'no-debugger': 'error',
|
||||
camelcase: 'error',
|
||||
indent: ['error', 2],
|
||||
'linebreak-style': ['error', 'unix'],
|
||||
semi: ['error', 'never'],
|
||||
// Optional eslint-comments rule
|
||||
'@eslint-community/eslint-comments/no-unused-disable': 'error',
|
||||
'@eslint-community/eslint-comments/disable-enable-pair': ['error', { allowWholeFile: true }],
|
||||
// import
|
||||
'import/export': 'error',
|
||||
'import/no-deprecated': 'error',
|
||||
'import/no-empty-named-blocks': 'error',
|
||||
'import/no-extraneous-dependencies': 'error',
|
||||
'import/no-mutable-exports': 'error',
|
||||
'import/no-unused-modules': 'error',
|
||||
'import/no-named-as-default': 'error',
|
||||
'import/no-named-as-default-member': 'error',
|
||||
'import/no-amd': 'error',
|
||||
'import/no-commonjs': 'error',
|
||||
'import/no-import-module-exports': 'error',
|
||||
'import/no-nodejs-modules': 'off',
|
||||
'import/unambiguous': 'off', // not compatible with scriptless vue files
|
||||
'import/default': 'error',
|
||||
'import/named': 'error',
|
||||
'import/namespace': 'error',
|
||||
'import/no-absolute-path': 'error',
|
||||
'import/no-cycle': 'error',
|
||||
'import/no-dynamic-require': 'error',
|
||||
'import/no-internal-modules': 'off',
|
||||
'import/no-relative-packages': 'error',
|
||||
'import/no-relative-parent-imports': [
|
||||
'error',
|
||||
{
|
||||
ignore: ['#[src,types,root,components,utils,assets]/*'],
|
||||
},
|
||||
],
|
||||
'import/no-self-import': 'error',
|
||||
'import/no-unresolved': [
|
||||
'error',
|
||||
{
|
||||
ignore: ['react'],
|
||||
},
|
||||
],
|
||||
'import/no-useless-path-segments': 'error',
|
||||
'import/no-webpack-loader-syntax': 'error',
|
||||
'import/consistent-type-specifier-style': 'error',
|
||||
'import/exports-last': 'off',
|
||||
'import/extensions': [
|
||||
'error',
|
||||
'never',
|
||||
{
|
||||
json: 'always',
|
||||
},
|
||||
],
|
||||
'import/first': 'error',
|
||||
'import/group-exports': 'off',
|
||||
'import/newline-after-import': 'error',
|
||||
'import/no-anonymous-default-export': 'off', // todo - consider to enable again
|
||||
'import/no-default-export': 'off', // incompatible with vite & vike
|
||||
'import/no-duplicates': 'error',
|
||||
'import/no-named-default': 'error',
|
||||
'import/no-namespace': 'error',
|
||||
'import/no-unassigned-import': [
|
||||
'error',
|
||||
{
|
||||
allow: ['**/*.css'],
|
||||
},
|
||||
],
|
||||
'import/order': [
|
||||
'error',
|
||||
{
|
||||
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'],
|
||||
'newlines-between': 'always',
|
||||
alphabetize: {
|
||||
order: 'asc', // sort in ascending order. Options: ["ignore", "asc", "desc"]
|
||||
caseInsensitive: true, // ignore case. Options: [true, false]
|
||||
},
|
||||
distinctGroup: true,
|
||||
},
|
||||
],
|
||||
'import/prefer-default-export': 'off',
|
||||
// promise
|
||||
'promise/catch-or-return': 'error',
|
||||
'promise/no-return-wrap': 'error',
|
||||
'promise/param-names': 'error',
|
||||
'promise/always-return': 'error',
|
||||
'promise/no-native': 'off',
|
||||
'promise/no-nesting': 'warn',
|
||||
'promise/no-promise-in-callback': 'warn',
|
||||
'promise/no-callback-in-promise': 'warn',
|
||||
'promise/avoid-new': 'warn',
|
||||
'promise/no-new-statics': 'error',
|
||||
'promise/no-return-in-finally': 'warn',
|
||||
'promise/valid-params': 'warn',
|
||||
'promise/prefer-await-to-callbacks': 'error',
|
||||
'promise/no-multiple-resolved': 'error',
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.ts', '*.tsx'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ['./tsconfig.json', '**/tsconfig.json'],
|
||||
ecmaVersion: 'latest',
|
||||
parser: '@typescript-eslint/parser',
|
||||
sourceType: 'module',
|
||||
},
|
||||
plugins: ['@typescript-eslint'],
|
||||
extends: [
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:@typescript-eslint/recommended-requiring-type-checking',
|
||||
'plugin:@typescript-eslint/strict',
|
||||
],
|
||||
rules: {
|
||||
'@typescript-eslint/consistent-type-imports': 'error',
|
||||
// allow explicitly defined dangling promises
|
||||
'@typescript-eslint/no-floating-promises': ['error', { ignoreVoid: true }],
|
||||
'no-void': ['error', { allowAsStatement: true }],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['!*.json'],
|
||||
plugins: ['prettier'],
|
||||
extends: ['plugin:prettier/recommended'],
|
||||
rules: {
|
||||
'prettier/prettier': 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.json'],
|
||||
plugins: ['json'],
|
||||
extends: ['plugin:json/recommended-with-comments'],
|
||||
},
|
||||
// {
|
||||
// files: ['*.{test,spec}.[tj]s'],
|
||||
// plugins: ['vitest'],
|
||||
// extends: ['plugin:vitest/all'],
|
||||
// rules: {
|
||||
// 'vitest/prefer-lowercase-title': 'off',
|
||||
// 'vitest/no-hooks': 'off',
|
||||
// 'vitest/consistent-test-filename': 'off',
|
||||
// 'vitest/prefer-expect-assertions': [
|
||||
// 'off',
|
||||
// {
|
||||
// onlyFunctionsWithExpectInLoop: true,
|
||||
// onlyFunctionsWithExpectInCallback: true,
|
||||
// },
|
||||
// ],
|
||||
// 'vitest/prefer-strict-equal': 'off',
|
||||
// 'vitest/prefer-to-be-falsy': 'off',
|
||||
// 'vitest/prefer-to-be-truthy': 'off',
|
||||
// 'vitest/require-hook': [
|
||||
// 'error',
|
||||
// {
|
||||
// allowedFunctionCalls: [
|
||||
// 'mockClient.setRequestHandler',
|
||||
// 'setActivePinia',
|
||||
// 'provideApolloClient',
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// },
|
||||
{
|
||||
files: ['*.yaml', '*.yml'],
|
||||
parser: 'yaml-eslint-parser',
|
||||
plugins: ['yml'],
|
||||
extends: ['plugin:yml/prettier'],
|
||||
},
|
||||
],
|
||||
}
|
||||
2
frontend/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
node_modules/
|
||||
dist/
|
||||
47
frontend/README.md
Normal file
@ -0,0 +1,47 @@
|
||||
# 🌍 Utopia Map [](https://opencollective.com/utopia-project#section-contributors) [](https://t.me/UtopiaMap)
|
||||
|
||||
The Utopia Map is a flexible collaborative app for decentralized coordination and real-life networking that can be adapted to the specific requirements of different networks. Its central element is the interactive geographical map, where users can add and manage **Items** in predefined **Layers**.
|
||||
|
||||
Utopia Map is made for networks and initiatives that aim to connect people in real life. By providing a custom instance of Utopia Map, each network can grow and coordinate its ecosystem effectively while encouraging real-world interactions and collaborations.
|
||||
|
||||
**Utopia Map** is based on **[Utopia UI](https://github.com/utopia-os/utopia-ui)**.
|
||||
|
||||
## Key Features
|
||||
|
||||
- **Interactive Map**: The core feature is an intuitive geographical map where users can add, edit, and manage items like members, activities, and resources. Each map instance has its own identity, users, and unique configuration.
|
||||
- **Customizable Layers**: Items are organized into predefined Layers, each with specific icons, colors, texts, and Map Markers. This ensures clarity and relevance for different networks.
|
||||
- **Dynamic Map Markers**: Geographic position of item are indicated on the map by adaptive and customizable Map Markers
|
||||
- **Popups**: Clicking a Map Marker reveals a Popup — a compact preview of the Item with its most relevant information. Define custom Popups for each of your Layers.
|
||||
- **Profiles**: Each Item has a dedicated Profile that showcases all its associated data, making it easier to explore and manage. Define custom profiles for each of your Layers.
|
||||
|
||||
## Deployment Options
|
||||
|
||||
- **SaaS**: A hosted solution with regular updates and support for easy onboarding and maintenance.
|
||||
- **Self-Hosted**: Deploy on your own infrastructure to retain full control and customization.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Clone the repository and get started with the following commands:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## Get your Map! 🌱 🌍
|
||||
|
||||
Start mapping and growing your community ecosystem together with your custom map.
|
||||
|
||||
[Join us on Telegram](https://t.me/UtopiaMap)
|
||||
|
||||
## Support Utopia Map 💚
|
||||
|
||||
We are building Utopia Map as an free and opensource tool. To keep this project sustainable and accessible, we need financial support as well as Developrs, UX Designer, Community Managers and Content Creators.
|
||||
|
||||
[Join us on Telegram](https://t.me/UtopiaMap) and support us on [OpenCollective](https://opencollective.com/utopia-project)
|
||||
|
||||
<a href="https://opencollective.com/utopia-project">
|
||||
<img width="250" src="https://opencollective.com/utopia-project/donate/button@2x.png?color=blue" style="margin-bottom:20px;" />
|
||||
</a>
|
||||
|
||||
|
||||
70
frontend/docker-compose.yml
Normal file
@ -0,0 +1,70 @@
|
||||
services:
|
||||
frontend:
|
||||
image: cupcakearmy/static
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- 8080:80
|
||||
volumes:
|
||||
- ./dist:/srv:ro
|
||||
|
||||
database:
|
||||
image: postgis/postgis:13-master
|
||||
# Required when running on platform other than amd64, like Apple M1/M2:
|
||||
# platform: linux/amd64
|
||||
volumes:
|
||||
- ./data/database:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_USER: 'directus'
|
||||
POSTGRES_PASSWORD: 'directus'
|
||||
POSTGRES_DB: 'directus'
|
||||
healthcheck:
|
||||
test: ['CMD', 'pg_isready', '--host=localhost', '--username=directus']
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_interval: 5s
|
||||
start_period: 30s
|
||||
|
||||
cache:
|
||||
image: redis:6
|
||||
healthcheck:
|
||||
test: ['CMD-SHELL', "[ $$(redis-cli ping) = 'PONG' ]"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_interval: 5s
|
||||
start_period: 30s
|
||||
|
||||
backend:
|
||||
container_name: backend
|
||||
build:
|
||||
context: ./backend
|
||||
depends_on:
|
||||
database:
|
||||
condition: service_healthy
|
||||
cache:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- 8055:8055
|
||||
environment:
|
||||
PUBLIC_URL: 'http://localhost'
|
||||
|
||||
SECRET: 'SECRET'
|
||||
|
||||
CORS_ENABLED: 'true'
|
||||
CORS_ORIGIN: 'http://localhost:8080'
|
||||
|
||||
DB_CLIENT: 'pg'
|
||||
DB_HOST: 'database'
|
||||
DB_PORT: '5432'
|
||||
DB_DATABASE: 'directus'
|
||||
DB_USER: 'directus'
|
||||
DB_PASSWORD: 'directus'
|
||||
|
||||
CACHE_ENABLED: 'true'
|
||||
CACHE_AUTO_PURGE: 'true'
|
||||
CACHE_STORE: 'redis'
|
||||
REDIS: 'redis://cache:6379'
|
||||
|
||||
ADMIN_EMAIL: 'admin@it4c.dev'
|
||||
ADMIN_PASSWORD: 'admin123'
|
||||
22
frontend/index.html
Normal file
@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, interactive-widget=resizes-visual" />
|
||||
<meta name="description" content="collaborative and interactive Maps for Utopians">
|
||||
<link rel="icon" type="image/png" href="/3markers-globe.svg" />
|
||||
<link rel="stylesheet" type="text/css" href="/style.css" />
|
||||
<title>Utopia Map</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root">
|
||||
<div class="outer fade-in">
|
||||
<img height="100" class="pulse-loader opacity" src="/3markers-globe.svg"/>
|
||||
<br>
|
||||
<span class="loader"></span>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
26
frontend/localhost-cert.pem
Normal file
@ -0,0 +1,26 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEXTCCAsWgAwIBAgIQcCbPt92wSwGqEayIluO/fTANBgkqhkiG9w0BAQsFADB7
|
||||
MR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExKDAmBgNVBAsMH2ZyaXR6
|
||||
QGZyaXR6LVRoaW5rUGFkLVQxNHMtR2VuLTMxLzAtBgNVBAMMJm1rY2VydCBmcml0
|
||||
ekBmcml0ei1UaGlua1BhZC1UMTRzLUdlbi0zMB4XDTI1MDUzMDE3NTUwMFoXDTI3
|
||||
MDgzMDE3NTUwMFowUzEnMCUGA1UEChMebWtjZXJ0IGRldmVsb3BtZW50IGNlcnRp
|
||||
ZmljYXRlMSgwJgYDVQQLDB9mcml0ekBmcml0ei1UaGlua1BhZC1UMTRzLUdlbi0z
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApl8YZzbT2AHZCtsVR7Er
|
||||
8TNDl6EbpKsppOstbtcF7m3eRNL6C/NrgGusDYEpqimUNFkzietD/WFHjzZFiOwL
|
||||
UUNlTlFud+xAhjFEpI7VMdckY0vWYNRpX5A3qZM5Mj0GnP8HJOeRvp855XpaIlR9
|
||||
Nlnx8PQy7Na40MAf6dXUEnEyXHDSEasNaGpsi/csEDvWc4APzVyi22IE5yPoGJqr
|
||||
gr04zgy6Vk5sorCFIxdJ1AjyNsO8TK3cP5c/AWbeG9rzD6Ue8kTNIx/C6IPVWTjz
|
||||
UltRwoFYNmqNAfyMC92jsDOyNzIceA83flfij073Bux1nry6ECsCgClS4G3N+6/f
|
||||
ewIDAQABo4GEMIGBMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcD
|
||||
ATAfBgNVHSMEGDAWgBRK5epC4SLzleTP68biJNt6oll9xzA5BgNVHREEMjAwggls
|
||||
b2NhbGhvc3SCCzE5Mi4xNjgueC54hwR/AAABhxAAAAAAAAAAAAAAAAAAAAABMA0G
|
||||
CSqGSIb3DQEBCwUAA4IBgQCLTcK+MOuA99iF4aOE3iUwsuJmmcr/CLjMi3S+MqmP
|
||||
LKRakqefruV2x4cpgW52Y31nH7UYUTus8FPj/FJAFF8+A1Cw/mLvamAGfcHRpeX0
|
||||
CiqmOlDmfqN8x40qeckOn+ymHtjG6szWJ1Erryb2v8KkRmE/dJYCtuUKIvid+yK1
|
||||
RObg8UBNf98CpzBWnNgGjIKcJOjtde9sl2d0970SJ3udPJ1Vg2iqx/7sSrFFnBi8
|
||||
s7S086GJDEE7vj+3BGs+Xdvscibf9J5TUf0LzziDj7v/1xbQSdsqyhjp2oFXv44A
|
||||
JZLehvqnyrQ2LxGeECitLugwWg/VabZC8OGMo15VUO4Vexx/l4SjrqVVcBP4rfs0
|
||||
rjLUvxNcpyQEX6sFSBIrlA1NhQc9fH9SK1ownjiSoYKyDn/aQ1M57oQJXIm8+kVN
|
||||
VUrPrqDOopsCj4uOuRhnN7Pr6R4r2JX/N9SlaYvCACIYVdlsO/ENdOamtoLXSZKF
|
||||
v+MkgeYzDeqx7kJDhrLwhKY=
|
||||
-----END CERTIFICATE-----
|
||||
28
frontend/localhost-key.pem
Normal file
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCmXxhnNtPYAdkK
|
||||
2xVHsSvxM0OXoRukqymk6y1u1wXubd5E0voL82uAa6wNgSmqKZQ0WTOJ60P9YUeP
|
||||
NkWI7AtRQ2VOUW537ECGMUSkjtUx1yRjS9Zg1GlfkDepkzkyPQac/wck55G+nznl
|
||||
eloiVH02WfHw9DLs1rjQwB/p1dQScTJccNIRqw1oamyL9ywQO9ZzgA/NXKLbYgTn
|
||||
I+gYmquCvTjODLpWTmyisIUjF0nUCPI2w7xMrdw/lz8BZt4b2vMPpR7yRM0jH8Lo
|
||||
g9VZOPNSW1HCgVg2ao0B/IwL3aOwM7I3Mhx4Dzd+V+KPTvcG7HWevLoQKwKAKVLg
|
||||
bc37r997AgMBAAECggEBAJk7+TQHkbLgcNHI256+lmR//P+JifZvF9ooKh5uua3T
|
||||
T+dAEsIzH46WnU+K6Z8q0LAugIPFR0f283v6Vq04C2x7kLFD22VlGkD+2+RdEgvn
|
||||
xkIWtYtV2QAFyt7LFOEqyA6N7jyVdO2HpkGwIZiBDRqkWWy+3rC5TFwouLwdEEky
|
||||
sPExVAYYkuDwYpb82ENz6fxR4rvfI5mMkoyI12q4UxByLd7lC6rHgCP8jpz3lpMB
|
||||
dx2+eWpRH4cA/SSxn2SnpSyLIWnPaS4FmL7t6Yfd9xnp9Qm6vtiTeR+i6mOP1D9u
|
||||
yjNhI/CoUBIFlxOnweGwlycR9kEiF0khzV7LKq5N55ECgYEA1eQeDs/hd7QAcmKN
|
||||
lyH0ZdXXFoUpE81yZHECoQ/EZaWh+qzvRQoMusUMRZHKXewgCjuj3CygatIFX+gS
|
||||
tkjz04K24p/ilGgGXUAnsc2K0N0lDhd5fTngP49AOvbpwbH1pmy1YIeWML0AvdZO
|
||||
qAir+mo8WYArOBJNVsfnjYChyZcCgYEAxyAKM4D6G2k7MzlRoZ5rNifk8lYP0TZc
|
||||
fISRt5g4ckGL/qLHJl0Y5EcFXdElEwO9VTNYkuRNSffttzVtR4MSpVsSOcGW+fcd
|
||||
nAarlK58EZzg54LCITANEJNVFrj6zhaxKLKLfvhvuhM6hR36Th8xz+JHeSf2zEGP
|
||||
lXWLxHt1rb0CgYEAshUE5aY0/foTaSke5Bc0Kdl6BFkIE2G5fWEOJFVBWrQmAdUc
|
||||
PeoZISPQjNfOmpZvMrXnPvi081s7eFd7xONGhvLNHDCscI2PxvIUWphcnHuTT4FB
|
||||
+H5IdALsImvTwh5N/auC9ATPinLCfExDHuphbdQnvQjWcw/h7n/wDUNs8K8CgYEA
|
||||
kM4o/PlfaI2nIoIdbgXRe4mZge26BO+eZGLXwQaujdBC6UMgxjJPhrprGaWda219
|
||||
wzbaw7/IwPDOazwsIyQbbCqFX4D7tP3TB4MGRdJ5oSlPmKxLVm0mIxaxexu8MCDq
|
||||
Zmko7oXmYg/Xr7R0MVmYFNA+H8pDPJi0vQDFSnZpxpUCgYB2/fXHBjlBrvq41Tve
|
||||
O46t0vZVcePsmLPNNE9wugT6QRuIlRGbi3PVE0PIjPG+gpfZPDGedLztMnsrm4cj
|
||||
RMuCOer300/MAw/cBLEhmaX38Y/UK4oQ3y+XlvniEHcFSBhDoBFrvMqxLvYdU06X
|
||||
ktmcj6c87RE7QEWnSmbpj3Oo3A==
|
||||
-----END PRIVATE KEY-----
|
||||
11533
frontend/package-lock.json
generated
Normal file
55
frontend/package.json
Normal file
@ -0,0 +1,55 @@
|
||||
{
|
||||
"name": "utopia-map",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --host",
|
||||
"build": "tsc && vite build",
|
||||
"test:lint:eslint": "eslint --ext .ts,.tsx,.js,.jsx,.cjs,.mjs,.json,.yml,.yaml --max-warnings 0 .",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@directus/sdk": "^17.0.2",
|
||||
"@heroicons/react": "^2.1.1",
|
||||
"@tailwindcss/vite": "^4.0.15",
|
||||
"@types/geojson": "^7946.0.10",
|
||||
"axios": "^1.6.5",
|
||||
"date-fns": "^3.3.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-rnd": "^10.4.1",
|
||||
"react-router-dom": "^6.23.0",
|
||||
"utopia-ui": "^3.0.96"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint-community/eslint-plugin-eslint-comments": "^4.4.1",
|
||||
"@types/node": "^22.15.28",
|
||||
"@types/react": "^18.2.79",
|
||||
"@types/react-dom": "^18.2.25",
|
||||
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
||||
"@typescript-eslint/parser": "^5.62.0",
|
||||
"@vitejs/plugin-react": "^4.0.0",
|
||||
"daisyui": "^5.0.6",
|
||||
"eslint": "^8.24.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-config-standard": "^17.1.0",
|
||||
"eslint-import-resolver-typescript": "^3.6.3",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-json": "^3.1.0",
|
||||
"eslint-plugin-n": "^16.6.2",
|
||||
"eslint-plugin-no-catch-all": "^1.1.0",
|
||||
"eslint-plugin-prettier": "^5.2.1",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"eslint-plugin-react": "^7.31.8",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.18",
|
||||
"eslint-plugin-security": "^3.0.1",
|
||||
"eslint-plugin-yml": "^1.14.0",
|
||||
"postcss": "^8.4.30",
|
||||
"tailwindcss": "^4.0.15",
|
||||
"typescript": "^5.0.2",
|
||||
"vite": "^6.2.0",
|
||||
"vite-plugin-pwa": "^0.21.1"
|
||||
}
|
||||
}
|
||||
264
frontend/public/3markers-globe.svg
Normal file
@ -0,0 +1,264 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="18mm"
|
||||
height="16mm"
|
||||
viewBox="0 0 17.999999 16.000001"
|
||||
version="1.1"
|
||||
id="svg119"
|
||||
sodipodi:docname="3markers-globe.svg"
|
||||
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs113" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="10.24"
|
||||
inkscape:cx="25.927734"
|
||||
inkscape:cy="34.61914"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer6"
|
||||
showgrid="false"
|
||||
fit-margin-right="-0.1"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1013"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:pagecheckerboard="0" />
|
||||
<metadata
|
||||
id="metadata116">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer4"
|
||||
inkscape:label="Ebene 4"
|
||||
style="display:inline"
|
||||
transform="translate(0,-4.809948)">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="display:inline;fill:#aad400;stroke-width:0.26458332;fill-opacity:1"
|
||||
d="m 8.5782875,9.4721385 c -2.9104166,0 -5.2916666,2.3812505 -5.2916666,5.2916675 0,2.910417 2.38125,5.291667 5.2916666,5.291667 2.9104165,0 5.2916665,-2.38125 5.2916665,-5.291667 0,-2.910417 -2.38125,-5.2916675 -5.2916665,-5.2916675 z"
|
||||
id="path2" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="display:inline;fill:#31b0fd;stroke-width:0.26458332;fill-opacity:1"
|
||||
d="m 14.134538,14.763806 c 0,3.095625 -2.513542,5.55625 -5.5562505,5.55625 -3.0427082,0 -5.5562499,-2.460625 -5.5562499,-5.55625 0,-3.095625 2.460625,-5.5562505 5.5562499,-5.5562505 3.0956255,0 5.5562505,2.4606255 5.5562505,5.5562505 z m -5.6091675,2.566458 c 0,-0.105833 -0.05292,-0.15875 -0.15875,-0.211666 -0.3439579,-0.105834 -0.6614579,-0.105834 -0.9524996,-0.396875 -0.052917,-0.105834 -0.052917,-0.211667 -0.1058333,-0.343959 -0.1058333,-0.105833 -0.396875,-0.15875 -0.555625,-0.211666 -0.2116667,0 -0.4497917,0 -0.714375,0 -0.1058333,0 -0.2910417,0 -0.396875,0 -0.15875,-0.05292 -0.2910417,-0.291042 -0.396875,-0.449792 0,-0.05292 0,-0.15875 -0.1058333,-0.15875 -0.1058334,-0.05292 -0.2116667,0.05292 -0.3439584,0 -0.052917,-0.05292 -0.052917,-0.105833 -0.052917,-0.15875 0,-0.15875 0.1058333,-0.343958 0.2116666,-0.449792 0.15875,-0.105833 0.3439584,0.05292 0.5027084,0.05292 0.052917,0 0.052917,0 0.1058333,0.05292 0.15875,0.05292 0.2116667,0.264583 0.2116667,0.449791 0,0.05292 0,0.105834 0,0.105834 0,0.05292 0.052917,0.05292 0.1058333,0.05292 0.052917,-0.291041 0.052917,-0.555625 0.1058333,-0.846666 0,-0.343959 0.3439584,-0.661459 0.6085417,-0.767292 0.1058333,-0.05292 0.15875,0.05292 0.2910417,0 0.3439583,-0.105833 1.1641666,-0.449792 1.0054166,-0.899583 -0.1058333,-0.396875 -0.4497916,-0.767292 -0.8995833,-0.714375 -0.1058333,0.05292 -0.15875,0.105833 -0.2645833,0.15875 -0.15875,0.105833 -0.5027084,0.449791 -0.6614584,0.449791 -0.2910416,-0.05292 -0.2910416,-0.449791 -0.2116666,-0.608541 0.052917,-0.211667 0.555625,-0.9525 0.8995833,-0.820209 0.052917,0.05292 0.15875,0.15875 0.2116667,0.211667 0.1058333,0.05292 0.2910416,0.05292 0.4497916,0.05292 0.052917,0 0.1058334,0 0.15875,-0.05292 0.052917,-0.05292 0.052917,-0.05292 0.052917,-0.105833 0,-0.15875 -0.15875,-0.343959 -0.2645833,-0.449792 -0.1058334,-0.105833 -0.2910417,-0.211667 -0.4497917,-0.291042 -0.555625,-0.15875 -1.4552083,0.05292 -1.8785417,0.449792 -0.4233333,0.396875 -0.7672916,1.058333 -1.0054166,1.613958 -0.1058334,0.343959 -0.2116667,0.767292 -0.2645834,1.164167 -0.052917,0.264583 -0.1058333,0.502708 0.052917,0.767292 0.15875,0.343958 0.5027083,0.661458 0.8466667,0.899583 0.2116666,0.15875 0.6614583,0.15875 0.8995833,0.449792 0.15875,0.211666 0.1058333,0.502708 0.1058333,0.767291 0,0.343959 0.2116667,0.608542 0.3439584,0.899584 0.052917,0.15875 0.1058333,0.396875 0.15875,0.555625 0,0.05292 0.052917,0.396875 0.052917,0.449791 0.3439584,0.15875 0.6085417,0.343959 1.0054167,0.449792 0.052917,0 0.2645833,-0.343958 0.2645833,-0.396875 0.15875,-0.15875 0.2910417,-0.396875 0.4497917,-0.502708 0.1058333,-0.05292 0.2116663,-0.105834 0.3439583,-0.211667 0.105833,-0.105833 0.15875,-0.343958 0.211667,-0.502708 0.02646,-0.132292 0.07937,-0.343959 0.02646,-0.502709 z m 0.105834,-5.132916 c 0.05292,0 0.105833,-0.05292 0.211666,-0.105834 0.15875,-0.105833 0.343959,-0.291041 0.502709,-0.396875 0.15875,-0.105833 0.343958,-0.291041 0.449791,-0.396875 0.15875,-0.105833 0.2910415,-0.343958 0.3439585,-0.502708 0.05292,-0.105833 0.211666,-0.343958 0.15875,-0.502708 -0.05292,-0.105834 -0.3439585,-0.15875 -0.4497915,-0.211667 -0.449792,-0.1058335 -0.820208,-0.1587505 -1.27,-0.1587505 -0.15875,0 -0.396875,0.05292 -0.449792,0.2116675 -0.05292,0.291041 0.15875,0.211666 0.396875,0.291041 0,0 0.05292,0.449792 0.05292,0.502709 0.05292,0.264583 -0.105833,0.449791 -0.105833,0.714375 0,0.15875 0,0.449791 0.105833,0.555625 z m 4.6566665,3.889375 c 0.05292,-0.105834 0.05292,-0.291042 0.105833,-0.396875 0.05292,-0.264584 0.05292,-0.555625 0.05292,-0.820209 0,-0.555625 -0.05292,-1.11125 -0.211666,-1.613958 -0.105834,-0.15875 -0.15875,-0.343958 -0.211667,-0.502708 -0.105833,-0.291042 -0.264583,-0.555625 -0.502708,-0.767292 -0.211667,-0.291042 -0.502709,-1.058333 -1.005417,-0.820208 -0.15875,0.05292 -0.264583,0.264583 -0.396875,0.396875 -0.105833,0.15875 -0.211667,0.343958 -0.343959,0.502708 -0.05292,0.05292 -0.105833,0.15875 -0.05292,0.211667 0,0.05292 0.05292,0.05292 0.105834,0.05292 0.105833,0.05292 0.15875,0.05292 0.264583,0.105834 0.05292,0 0.105834,0.05292 0.05292,0.105833 0,0 0,0.05292 -0.05292,0.05292 -0.264583,0.291041 -0.555625,0.502708 -0.820208,0.767291 -0.05292,0.05292 -0.105834,0.15875 -0.105834,0.211667 0,0.05292 0.05292,0.05292 0.05292,0.105833 0,0.05292 -0.05292,0.05292 -0.105833,0.105834 -0.105832,0.05292 -0.2116665,0.105833 -0.2910415,0.15875 -0.05292,0.105833 0,0.291041 -0.05292,0.396875 -0.05292,0.291041 -0.211666,0.502708 -0.343958,0.767291 -0.105833,0.15875 -0.15875,0.343959 -0.264583,0.502709 0,0.211666 -0.05292,0.396875 0.05292,0.555625 0.264583,0.396875 0.767291,0.15875 1.1641655,0.343958 0.105834,0.05292 0.211667,0.05292 0.291042,0.15875 0.15875,0.15875 0.15875,0.449792 0.211667,0.608542 0.05292,0.211666 0.105833,0.449791 0.211667,0.661458 0.05292,0.264583 0.15875,0.555625 0.211666,0.767292 0.502709,-0.396875 0.9525,-0.820209 1.27,-1.375834 0.396875,-0.343958 0.555625,-0.79375 0.714375,-1.243541 z"
|
||||
id="path4" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer3"
|
||||
inkscape:label="Ebene 2"
|
||||
style="display:inline"
|
||||
transform="translate(4.6675853,46.091266)">
|
||||
<g
|
||||
id="g89"
|
||||
transform="rotate(-34.618495,35.488753,-41.431433)">
|
||||
<g
|
||||
id="g356"
|
||||
font-style="normal"
|
||||
font-weight="400"
|
||||
font-size="10"
|
||||
transform="matrix(0.1012137,-0.03262355,0.01210909,0.10427296,3.1730944,-59.40221)"
|
||||
stroke-miterlimit="2"
|
||||
style="font-style:normal;font-weight:400;font-size:10px;font-family:Ubuntu;display:inline;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:2;stroke-opacity:1">
|
||||
<image
|
||||
id="image354"
|
||||
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACMAAAAQCAYAAACcN8ZaAAAACXBIWXMAAA9hAAAPYQGoP6dpAAABoUlEQVRIic2Vy3LCMAxFD2lS6Gtg0f//x0JoEwKmC98LqklCZ7qpZjSynYdOrmQH/pEtJtarYlxNrM89V1oaiSnMR2Gq4HVwry0m4OZgnPAInBUPikdfd5LyhTXwKF8CK+ChgIrPTSl8DjBJAINiBXQBMtUzIC/Aq+JKa02AmAIwRCzDSQl7uQFqRdCktErJ34A1sBFQU8DYUhi7BGeyAkfFgdteORfP3sBYmaUANsA7WSErU4L4pafgA7msveYprLtM7plLE48pY6gl8CyQNfCkBLaY3Ar0Gp/I/fAFfAJ7je2dYBLXMt30jEHsDblk7ptGShjAfeAvPyh5B2wDyF5rPSO7aE6ZSAvXrdzofpfGQBFgB7SaO1qNsjRwp2cM4i+OsrqffK3VtZ08wrg8VsIl+XHIlVaPXHT9nWgrVQYBHZS4lRugJ5ej1b1dUOHSF3rHKNCYMj6cdlxP3J7cwGhsGAO7DLM9MTKehfHNhnFJPsi7K4WvngOYTDhnU1v7yPWoTuT6+1fgph3COPGLnrhnUz/KCFuHseGiAnHn/cm+AU9X31BIhxprAAAAAElFTkSuQmCC"
|
||||
preserveAspectRatio="none"
|
||||
height="16"
|
||||
width="35"
|
||||
y="-6.5234251"
|
||||
x="3.2418795"
|
||||
transform="rotate(32.792589)" />
|
||||
</g>
|
||||
<g
|
||||
id="g522"
|
||||
font-style="normal"
|
||||
font-weight="400"
|
||||
font-size="10"
|
||||
transform="matrix(0.13120595,0,0,0.13120595,2.0117562,-64.499292)"
|
||||
style="font-style:normal;font-weight:400;font-size:10px;font-family:Ubuntu;display:inline;fill:#c4037d;fill-opacity:1;stroke:none">
|
||||
<path
|
||||
id="path520"
|
||||
d="M 28.205,3.217 H 6.777 c -2.367,0 -4.286,1.87 -4.286,4.179 v 19.847 c 0,2.308 1.919,4.179 4.286,4.179 h 5.357 l 5.337,13.58 5.377,-13.58 h 5.357 c 2.366,0 4.285,-1.87 4.285,-4.179 V 7.396 c 0,-2.308 -1.919,-4.179 -4.285,-4.179"
|
||||
inkscape:connector-curvature="0"
|
||||
style="vector-effect:none;fill-rule:nonzero" />
|
||||
</g>
|
||||
<g
|
||||
id="g550"
|
||||
font-style="normal"
|
||||
font-weight="400"
|
||||
font-size="10"
|
||||
transform="matrix(0.13915785,0,0,0.13915785,1.8725982,-64.608673)"
|
||||
style="font-style:normal;font-weight:400;font-size:10px;font-family:Ubuntu;display:inline;fill:#ffffff;fill-opacity:1;stroke:none">
|
||||
<path
|
||||
id="path548"
|
||||
d="m 11.875,22.4375 c 0,0.3646 0.1276,0.6745 0.3828,0.9297 0.2552,0.2552 0.5651,0.3828 0.9297,0.3828 h 9.625 c 0.3646,0 0.6745,-0.1276 0.9297,-0.3828 0.2552,-0.2552 0.3828,-0.5651 0.3828,-0.9297 V 15 h -12.25 v 7.4375 m 8.75,-5.3594 c 0,-0.0937 0.0313,-0.1718 0.0938,-0.2343 0.0625,-0.0625 0.1406,-0.0938 0.2343,-0.0938 h 1.0938 c 0.0937,0 0.1719,0.0313 0.2344,0.0938 0.0625,0.0625 0.0937,0.1406 0.0937,0.2343 v 1.0938 c 0,0.0937 -0.0312,0.1719 -0.0937,0.2344 C 22.2188,18.4688 22.1406,18.5 22.0469,18.5 h -1.0938 c -0.0937,0 -0.1718,-0.0312 -0.2343,-0.0937 -0.0625,-0.0625 -0.0938,-0.1407 -0.0938,-0.2344 v -1.0938 m 0,3.5 c 0,-0.0937 0.0313,-0.1718 0.0938,-0.2343 0.0625,-0.0625 0.1406,-0.0938 0.2343,-0.0938 h 1.0938 c 0.0937,0 0.1719,0.0313 0.2344,0.0938 0.0625,0.0625 0.0937,0.1406 0.0937,0.2343 v 1.0938 c 0,0.0937 -0.0312,0.1719 -0.0937,0.2344 C 22.2188,21.9688 22.1406,22 22.0469,22 H 20.9531 C 20.8594,22 20.7813,21.9688 20.7188,21.9063 20.6563,21.8438 20.625,21.7656 20.625,21.6719 v -1.0938 m -3.5,-3.5 c 0,-0.0937 0.0313,-0.1718 0.0938,-0.2343 0.0625,-0.0625 0.1406,-0.0938 0.2343,-0.0938 h 1.0938 c 0.0937,0 0.1719,0.0313 0.2344,0.0938 0.0625,0.0625 0.0937,0.1406 0.0937,0.2343 v 1.0938 c 0,0.0937 -0.0312,0.1719 -0.0937,0.2344 C 18.7188,18.4688 18.6406,18.5 18.5469,18.5 h -1.0938 c -0.0937,0 -0.1718,-0.0312 -0.2343,-0.0937 -0.0625,-0.0625 -0.0938,-0.1407 -0.0938,-0.2344 v -1.0938 m 0,3.5 c 0,-0.0937 0.0313,-0.1718 0.0938,-0.2343 0.0625,-0.0625 0.1406,-0.0938 0.2343,-0.0938 h 1.0938 c 0.0937,0 0.1719,0.0313 0.2344,0.0938 0.0625,0.0625 0.0937,0.1406 0.0937,0.2343 v 1.0938 c 0,0.0937 -0.0312,0.1719 -0.0937,0.2344 C 18.7188,21.9688 18.6406,22 18.5469,22 H 17.4531 C 17.3594,22 17.2813,21.9688 17.2188,21.9063 17.1563,21.8438 17.125,21.7656 17.125,21.6719 v -1.0938 m -3.5,-3.5 c 0,-0.0937 0.0313,-0.1718 0.0938,-0.2343 0.0625,-0.0625 0.1406,-0.0938 0.2343,-0.0938 h 1.0938 c 0.0937,0 0.1719,0.0313 0.2344,0.0938 0.0625,0.0625 0.0937,0.1406 0.0937,0.2343 v 1.0938 c 0,0.0937 -0.0312,0.1719 -0.0937,0.2344 C 15.2188,18.4688 15.1406,18.5 15.0469,18.5 h -1.0938 c -0.0937,0 -0.1718,-0.0312 -0.2343,-0.0937 -0.0625,-0.0625 -0.0938,-0.1407 -0.0938,-0.2344 v -1.0938 m 0,3.5 c 0,-0.0937 0.0313,-0.1718 0.0938,-0.2343 0.0625,-0.0625 0.1406,-0.0938 0.2343,-0.0938 h 1.0938 c 0.0937,0 0.1719,0.0313 0.2344,0.0938 0.0625,0.0625 0.0937,0.1406 0.0937,0.2343 v 1.0938 c 0,0.0937 -0.0312,0.1719 -0.0937,0.2344 C 15.2188,21.9688 15.1406,22 15.0469,22 H 13.9531 C 13.8594,22 13.7813,21.9688 13.7188,21.9063 13.6563,21.8438 13.625,21.7656 13.625,21.6719 V 20.5781 M 22.8125,11.5 H 21.5 V 10.1875 C 21.5,10.0625 21.4583,9.95833 21.375,9.875 21.2917,9.79167 21.1875,9.75 21.0625,9.75 h -0.875 c -0.125,0 -0.2292,0.04167 -0.3125,0.125 -0.0833,0.08333 -0.125,0.1875 -0.125,0.3125 V 11.5 h -3.5 V 10.1875 C 16.25,10.0625 16.2083,9.95833 16.125,9.875 16.0417,9.79167 15.9375,9.75 15.8125,9.75 h -0.875 c -0.125,0 -0.2292,0.04167 -0.3125,0.125 C 14.5417,9.95833 14.5,10.0625 14.5,10.1875 V 11.5 h -1.3125 c -0.3646,0 -0.6745,0.1276 -0.9297,0.3828 -0.2552,0.2552 -0.3828,0.5651 -0.3828,0.9297 v 1.3125 h 12.25 v -1.3125 c 0,-0.3646 -0.1276,-0.6745 -0.3828,-0.9297 C 23.487,11.6276 23.1771,11.5 22.8125,11.5"
|
||||
inkscape:connector-curvature="0"
|
||||
style="vector-effect:none;fill-rule:nonzero" />
|
||||
</g>
|
||||
<g
|
||||
id="g356-3"
|
||||
font-style="normal"
|
||||
font-weight="400"
|
||||
font-size="10"
|
||||
transform="matrix(0.1012137,-0.03262355,0.01210909,0.10427296,8.1741435,-58.851786)"
|
||||
stroke-miterlimit="2"
|
||||
style="font-style:normal;font-weight:400;font-size:10px;font-family:Ubuntu;display:inline;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:2;stroke-opacity:1">
|
||||
<image
|
||||
id="image354-6"
|
||||
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACMAAAAQCAYAAACcN8ZaAAAACXBIWXMAAA9hAAAPYQGoP6dpAAABoUlEQVRIic2Vy3LCMAxFD2lS6Gtg0f//x0JoEwKmC98LqklCZ7qpZjSynYdOrmQH/pEtJtarYlxNrM89V1oaiSnMR2Gq4HVwry0m4OZgnPAInBUPikdfd5LyhTXwKF8CK+ChgIrPTSl8DjBJAINiBXQBMtUzIC/Aq+JKa02AmAIwRCzDSQl7uQFqRdCktErJ34A1sBFQU8DYUhi7BGeyAkfFgdteORfP3sBYmaUANsA7WSErU4L4pafgA7msveYprLtM7plLE48pY6gl8CyQNfCkBLaY3Ar0Gp/I/fAFfAJ7je2dYBLXMt30jEHsDblk7ptGShjAfeAvPyh5B2wDyF5rPSO7aE6ZSAvXrdzofpfGQBFgB7SaO1qNsjRwp2cM4i+OsrqffK3VtZ08wrg8VsIl+XHIlVaPXHT9nWgrVQYBHZS4lRugJ5ej1b1dUOHSF3rHKNCYMj6cdlxP3J7cwGhsGAO7DLM9MTKehfHNhnFJPsi7K4WvngOYTDhnU1v7yPWoTuT6+1fgph3COPGLnrhnUz/KCFuHseGiAnHn/cm+AU9X31BIhxprAAAAAElFTkSuQmCC"
|
||||
preserveAspectRatio="none"
|
||||
height="13.833991"
|
||||
width="32.70261"
|
||||
y="-4.4695668"
|
||||
x="2.8086059"
|
||||
transform="matrix(0.82962222,0.55832515,-0.5232806,0.85216044,0,0)" />
|
||||
</g>
|
||||
<g
|
||||
id="g356-3-7"
|
||||
font-style="normal"
|
||||
font-weight="400"
|
||||
font-size="10"
|
||||
transform="matrix(0.1012137,-0.03262355,0.01210909,0.10427296,10.119996,-55.735617)"
|
||||
stroke-miterlimit="2"
|
||||
style="font-style:normal;font-weight:400;font-size:10px;font-family:Ubuntu;display:inline;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:2;stroke-opacity:1">
|
||||
<image
|
||||
id="image354-6-5"
|
||||
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACMAAAAQCAYAAACcN8ZaAAAACXBIWXMAAA9hAAAPYQGoP6dpAAABoUlEQVRIic2Vy3LCMAxFD2lS6Gtg0f//x0JoEwKmC98LqklCZ7qpZjSynYdOrmQH/pEtJtarYlxNrM89V1oaiSnMR2Gq4HVwry0m4OZgnPAInBUPikdfd5LyhTXwKF8CK+ChgIrPTSl8DjBJAINiBXQBMtUzIC/Aq+JKa02AmAIwRCzDSQl7uQFqRdCktErJ34A1sBFQU8DYUhi7BGeyAkfFgdteORfP3sBYmaUANsA7WSErU4L4pafgA7msveYprLtM7plLE48pY6gl8CyQNfCkBLaY3Ar0Gp/I/fAFfAJ7je2dYBLXMt30jEHsDblk7ptGShjAfeAvPyh5B2wDyF5rPSO7aE6ZSAvXrdzofpfGQBFgB7SaO1qNsjRwp2cM4i+OsrqffK3VtZ08wrg8VsIl+XHIlVaPXHT9nWgrVQYBHZS4lRugJ5ej1b1dUOHSF3rHKNCYMj6cdlxP3J7cwGhsGAO7DLM9MTKehfHNhnFJPsi7K4WvngOYTDhnU1v7yPWoTuT6+1fgph3COPGLnrhnUz/KCFuHseGiAnHn/cm+AU9X31BIhxprAAAAAElFTkSuQmCC"
|
||||
preserveAspectRatio="none"
|
||||
height="16"
|
||||
width="35"
|
||||
y="-2.0808461"
|
||||
x="2.1253965"
|
||||
transform="rotate(32.792589)" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
inkscape:label="Ebene 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-58.269337,-115.53478)"
|
||||
style="display:inline">
|
||||
<g
|
||||
id="g109"
|
||||
transform="rotate(-1.1556361,1155.3307,302.61847)">
|
||||
<g
|
||||
style="font-style:normal;font-weight:400;font-size:10px;font-family:Ubuntu;fill:#e87520;fill-opacity:1;stroke:none"
|
||||
transform="matrix(0.13120595,0,0,0.13120595,69.079628,93.634241)"
|
||||
font-size="10"
|
||||
font-weight="400"
|
||||
font-style="normal"
|
||||
id="g6701">
|
||||
<path
|
||||
style="vector-effect:none;fill-rule:nonzero"
|
||||
inkscape:connector-curvature="0"
|
||||
d="M 28.205,3.217 H 6.777 c -2.367,0 -4.286,1.87 -4.286,4.179 v 19.847 c 0,2.308 1.919,4.179 4.286,4.179 h 5.357 l 5.337,13.58 5.377,-13.58 h 5.357 c 2.366,0 4.285,-1.87 4.285,-4.179 V 7.396 c 0,-2.308 -1.919,-4.179 -4.285,-4.179"
|
||||
id="path6699" />
|
||||
</g>
|
||||
<g
|
||||
style="font-style:normal;font-weight:400;font-size:10px;font-family:Ubuntu;fill:#231f20;fill-opacity:0.2;stroke:none"
|
||||
transform="matrix(0.14057447,0,0,-0.14057447,38.479791,112.89298)"
|
||||
font-size="10"
|
||||
font-weight="400"
|
||||
font-style="normal"
|
||||
id="g6709">
|
||||
<path
|
||||
style="vector-effect:none;fill-rule:nonzero"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 244,134 h -20 c -2.209,0 -4,-1.746 -4,-3.9 v -18.525 c 0,-2.154 1.791,-3.9 4,-3.9 h 5 L 233.982,95 239,107.675 h 5 c 2.209,0 4,1.746 4,3.9 V 130.1 c 0,2.154 -1.791,3.9 -4,3.9 m 0,-1 c 1.654,0 3,-1.301 3,-2.9 v -18.525 c 0,-1.599 -1.346,-2.9 -3,-2.9 h -5.68 l -0.25,-0.632 -4.084,-10.318 -4.055,10.316 -0.249,0.634 H 224 c -1.654,0 -3,1.301 -3,2.9 V 130.1 c 0,1.599 1.346,2.9 3,2.9 h 20"
|
||||
id="path6707" />
|
||||
</g>
|
||||
<g
|
||||
style="font-style:normal;font-weight:400;font-size:10px;font-family:Ubuntu;fill:#ffffff;fill-opacity:1;stroke:none"
|
||||
transform="matrix(0.13915785,0,0,0.13915785,68.702265,93.556608)"
|
||||
font-size="10"
|
||||
font-weight="400"
|
||||
font-style="normal"
|
||||
id="g6729">
|
||||
<path
|
||||
style="vector-effect:none;fill-rule:nonzero"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 18.364194,16.757346 c 0.6354,0 1.224,-0.1562 1.7656,-0.4687 0.5417,-0.3125 0.9662,-0.737 1.2735,-1.2735 0.3073,-0.5364 0.4609,-1.1224 0.4609,-1.7578 0,-0.6354 -0.1536,-1.224 -0.4609,-1.7656 -0.3073,-0.5417 -0.7318,-0.9662 -1.2735,-1.2735 -0.5416,-0.3072494 -1.1302,-0.4608994 -1.7656,-0.4608994 -0.6354,0 -1.2214,0.15365 -1.7578,0.4608994 -0.5365,0.3073 -0.9609,0.7318 -1.2734,1.2735 -0.3125,0.5416 -0.4688,1.1302 -0.4688,1.7656 0,0.6354 0.1563,1.2214 0.4688,1.7578 0.3125,0.5365 0.7369,0.961 1.2734,1.2735 0.5364,0.3125 1.1224,0.4687 1.7578,0.4687 m 2.4688,0.875 h -0.4688 c -0.6354,0.2917 -1.2995,0.4375 -1.9922,0.4375 -0.6927,0 -1.362,-0.1458 -2.0078,-0.4375 h -0.4531 c -0.6563,0 -1.2683,0.1641 -1.836,0.4922 -0.5677,0.3281 -1.0156,0.7734 -1.3437,1.3359 -0.3281,0.5625 -0.4922,1.1719 -0.4922,1.8282 v 1.1562 c 0,0.3646 0.1276,0.6745 0.3828,0.9297 0.2552,0.2552 0.5651,0.3828 0.9297,0.3828 h 9.625 c 0.3646,0 0.6745,-0.1276 0.9297,-0.3828 0.2552,-0.2552 0.3828,-0.5651 0.3828,-0.9297 v -1.1562 c 0,-0.6563 -0.1641,-1.2657 -0.4922,-1.8282 -0.3281,-0.5625 -0.7734,-1.0078 -1.3359,-1.3359 -0.5625,-0.3281 -1.1719,-0.4922 -1.8281,-0.4922"
|
||||
id="path6727" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer6"
|
||||
inkscape:label="Ebene 3"
|
||||
style="display:inline"
|
||||
transform="translate(4.6675853,46.091266)">
|
||||
<g
|
||||
id="g99"
|
||||
transform="rotate(58.747582,-19.440046,-29.612246)">
|
||||
<g
|
||||
id="g678"
|
||||
font-style="normal"
|
||||
font-weight="400"
|
||||
font-size="10"
|
||||
transform="matrix(0.12723008,0,0,0.12723008,-15.000979,-62.923636)"
|
||||
style="font-style:normal;font-weight:400;font-size:10px;font-family:Ubuntu;display:inline;fill:#008e5b;fill-opacity:1;stroke:none">
|
||||
<path
|
||||
id="path676"
|
||||
d="m 17.5,2.746 c -8.284,0 -15,6.853 -15,15.307 0,0.963 0.098,1.902 0.265,2.816 0.36664,2.0268 1.13579,3.9595 2.262,5.684 l 0.134,0.193 12.295,17.785 12.439,-17.863 0.056,-0.08 c 1.2093,-1.8462 2.0083,-3.9305 2.343,-6.112 0.123,-0.791 0.206,-1.597 0.206,-2.423 0,-8.454 -6.716,-15.307 -15,-15.307"
|
||||
inkscape:connector-curvature="0"
|
||||
style="vector-effect:none;fill-rule:nonzero" />
|
||||
</g>
|
||||
<g
|
||||
id="g684"
|
||||
font-style="normal"
|
||||
font-weight="400"
|
||||
font-size="10"
|
||||
transform="matrix(0.12723008,0,0,0.12723008,-15.000979,-62.923636)"
|
||||
style="font-style:normal;font-weight:400;font-size:10px;font-family:Ubuntu;display:inline;fill:#2a71b0;fill-opacity:1;stroke:none">
|
||||
<path
|
||||
id="path682"
|
||||
d="m 17.488,2.748 c -8.284,0 -15,6.853 -15,15.307 0,0.963 0.098,1.902 0.265,2.816 0.36664,2.0268 1.13579,3.9595 2.262,5.684 l 0.134,0.193 12.295,17.785 12.44,-17.863 0.055,-0.08 c 1.2093,-1.8462 2.0083,-3.9305 2.343,-6.112 0.124,-0.791 0.206,-1.597 0.206,-2.423 0,-8.454 -6.716,-15.307 -15,-15.307 m 0,1.071 c 7.68,0 13.929,6.386 13.929,14.236 0,0.685 -0.064,1.423 -0.193,2.258 -0.325,2.075 -1.059,3.99 -2.164,5.667 L 29.005,26.058 17.448,42.653 6.032,26.14 5.912,25.966 C 4.86177,24.3621 4.14583,22.5629 3.807,20.676 3.64649,19.8118 3.56383,18.935 3.56,18.056 3.56,10.205 9.809,3.819 17.488,3.819"
|
||||
inkscape:connector-curvature="0"
|
||||
style="vector-effect:none;fill-rule:nonzero;fill:#008000" />
|
||||
</g>
|
||||
<g
|
||||
id="g702"
|
||||
font-style="normal"
|
||||
font-weight="400"
|
||||
font-size="10"
|
||||
transform="matrix(0.13915785,0,0,0.13915785,-15.279297,-63.122493)"
|
||||
style="font-style:normal;font-weight:400;font-size:10px;font-family:Ubuntu;display:inline;fill:#ffffff;fill-opacity:1;stroke:none">
|
||||
<path
|
||||
id="path700"
|
||||
d="m 18,9.96875 c -1.2187,0 -2.349,0.30465 -3.3906,0.91405 -1.0417,0.6094 -1.8672,1.4349 -2.4766,2.4766 -0.6094,1.0416 -0.914,2.1719 -0.914,3.3906 0,1.2188 0.3046,2.349 0.914,3.3906 0.6094,1.0417 1.4349,1.8672 2.4766,2.4766 1.0416,0.6094 2.1719,0.9141 3.3906,0.9141 1.2188,0 2.349,-0.3047 3.3906,-0.9141 1.0417,-0.6094 1.8672,-1.4349 2.4766,-2.4766 0.6094,-1.0416 0.9141,-2.1718 0.9141,-3.3906 0,-1.2187 -0.3047,-2.349 -0.9141,-3.3906 C 23.2578,12.3177 22.4323,11.4922 21.3906,10.8828 20.349,10.2734 19.2188,9.96875 18,9.96875"
|
||||
inkscape:connector-curvature="0"
|
||||
style="vector-effect:none;fill-rule:nonzero" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 22 KiB |
BIN
frontend/public/bg1.webp
Normal file
|
After Width: | Height: | Size: 682 KiB |
14
frontend/public/github.svg
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" fill="currentColor" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
</defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Dribbble-Light-Preview" transform="translate(-140.000000, -7559.000000)" fill="currentColor">
|
||||
<g id="icons" transform="translate(56.000000, 160.000000)">
|
||||
<path d="M94,7399 C99.523,7399 104,7403.59 104,7409.253 C104,7413.782 101.138,7417.624 97.167,7418.981 C96.66,7419.082 96.48,7418.762 96.48,7418.489 C96.48,7418.151 96.492,7417.047 96.492,7415.675 C96.492,7414.719 96.172,7414.095 95.813,7413.777 C98.04,7413.523 100.38,7412.656 100.38,7408.718 C100.38,7407.598 99.992,7406.684 99.35,7405.966 C99.454,7405.707 99.797,7404.664 99.252,7403.252 C99.252,7403.252 98.414,7402.977 96.505,7404.303 C95.706,7404.076 94.85,7403.962 94,7403.958 C93.15,7403.962 92.295,7404.076 91.497,7404.303 C89.586,7402.977 88.746,7403.252 88.746,7403.252 C88.203,7404.664 88.546,7405.707 88.649,7405.966 C88.01,7406.684 87.619,7407.598 87.619,7408.718 C87.619,7412.646 89.954,7413.526 92.175,7413.785 C91.889,7414.041 91.63,7414.493 91.54,7415.156 C90.97,7415.418 89.522,7415.871 88.63,7414.304 C88.63,7414.304 88.101,7413.319 87.097,7413.247 C87.097,7413.247 86.122,7413.234 87.029,7413.87 C87.029,7413.87 87.684,7414.185 88.139,7415.37 C88.139,7415.37 88.726,7417.2 91.508,7416.58 C91.513,7417.437 91.522,7418.245 91.522,7418.489 C91.522,7418.76 91.338,7419.077 90.839,7418.982 C86.865,7417.627 84,7413.783 84,7409.253 C84,7403.59 88.478,7399 94,7399" id="github-[#142]">
|
||||
|
||||
</path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
4
frontend/public/opencollective.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-opencollective" viewBox="0 0 16 16">
|
||||
<path fill-opacity=".4" d="M12.995 8.195c0 .937-.312 1.912-.78 2.693l1.99 1.99c.976-1.327 1.6-2.966 1.6-4.683 0-1.795-.624-3.434-1.561-4.76l-2.068 2.028c.468.781.78 1.679.78 2.732h.04Z"/>
|
||||
<path d="M8 13.151a4.995 4.995 0 1 1 0-9.99c1.015 0 1.951.273 2.732.82l1.95-2.03a7.805 7.805 0 1 0 .04 12.449l-1.951-2.03a5.072 5.072 0 0 1-2.732.781H8Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 487 B |
111
frontend/public/style.css
Normal file
@ -0,0 +1,111 @@
|
||||
body {
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#root {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.pulse-loader {
|
||||
animation: pulse 2.5s infinite ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
30% {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
70% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.loader {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
display: block;
|
||||
margin: 15px auto;
|
||||
position: relative;
|
||||
color: #FFF;
|
||||
left: -120px;
|
||||
box-sizing: border-box;
|
||||
animation: shadowRolling 2s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes shadowRolling {
|
||||
0% {
|
||||
box-shadow: 0px 0 rgba(255, 255, 255, 0), 0px 0 rgba(255, 255, 255, 0), 0px 0 rgba(255, 255, 255, 0), 0px 0 rgba(255, 255, 255, 0);
|
||||
}
|
||||
|
||||
12% {
|
||||
box-shadow: 100px 0 lightgray, 0px 0 rgba(255, 255, 255, 0), 0px 0 rgba(255, 255, 255, 0), 0px 0 rgba(255, 255, 255, 0);
|
||||
}
|
||||
|
||||
25% {
|
||||
box-shadow: 110px 0 lightgray, 100px 0 lightgray, 0px 0 rgba(255, 255, 255, 0), 0px 0 rgba(255, 255, 255, 0);
|
||||
}
|
||||
|
||||
36% {
|
||||
box-shadow: 120px 0 lightgray, 110px 0 lightgray, 100px 0 lightgray, 0px 0 rgba(255, 255, 255, 0);
|
||||
}
|
||||
|
||||
50% {
|
||||
box-shadow: 130px 0 lightgray, 120px 0 lightgray, 110px 0 lightgray, 100px 0 lightgray;
|
||||
}
|
||||
|
||||
62% {
|
||||
box-shadow: 200px 0 rgba(255, 255, 255, 0), 130px 0 lightgray, 120px 0 lightgray, 110px 0 lightgray;
|
||||
}
|
||||
|
||||
75% {
|
||||
box-shadow: 200px 0 rgba(255, 255, 255, 0), 200px 0 rgba(255, 255, 255, 0), 130px 0 lightgray, 120px 0 lightgray;
|
||||
}
|
||||
|
||||
87% {
|
||||
box-shadow: 200px 0 rgba(255, 255, 255, 0), 200px 0 rgba(255, 255, 255, 0), 200px 0 rgba(255, 255, 255, 0), 130px 0 lightgray;
|
||||
}
|
||||
|
||||
100% {
|
||||
box-shadow: 200px 0 rgba(255, 255, 255, 0), 200px 0 rgba(255, 255, 255, 0), 200px 0 rgba(255, 255, 255, 0), 200px 0 rgba(255, 255, 255, 0);
|
||||
}
|
||||
}
|
||||
|
||||
.opacity {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.outer {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center; /* Zentriert die Items horizontal */
|
||||
justify-content: center; /* Zentriert die Items vertikal */}
|
||||
|
||||
.inner {
|
||||
height: 96px;
|
||||
color: lightgray;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.fade-in {
|
||||
animation: fade-in 1.5s ease-in;
|
||||
}
|
||||
41
frontend/src/App.css
Normal file
@ -0,0 +1,41 @@
|
||||
html, body, #root {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.App {
|
||||
width: 100vw;
|
||||
height: 100dvh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#app-content {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.fadeable-div {
|
||||
transition: opacity 1000ms ease;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.div-hidden {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.movable-div {
|
||||
transition: transform 600ms ease;
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.move-out-right {
|
||||
transform: translateX(100vw);
|
||||
/* Verschiebt das Div um die Breite des Viewports */
|
||||
}
|
||||
|
||||
|
||||
.move-out-left {
|
||||
transform: translateX(-100vw);
|
||||
/* Verschiebt das Div um die Breite des Viewports */
|
||||
}
|
||||
266
frontend/src/App.tsx
Normal file
@ -0,0 +1,266 @@
|
||||
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
/* eslint-disable import/order */
|
||||
/* eslint-disable eqeqeq */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
/* eslint-disable @typescript-eslint/no-floating-promises */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable new-cap */
|
||||
/* eslint-disable @typescript-eslint/prefer-optional-chain */
|
||||
/* eslint-disable @typescript-eslint/restrict-plus-operands */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
import type { Tag } from 'utopia-ui'
|
||||
|
||||
import {
|
||||
AppShell,
|
||||
SideBar,
|
||||
Content,
|
||||
AuthProvider,
|
||||
Modal,
|
||||
LoginPage,
|
||||
SignupPage,
|
||||
Quests,
|
||||
RequestPasswordPage,
|
||||
SetNewPasswordPage,
|
||||
OverlayItemsIndexPage,
|
||||
Permissions,
|
||||
Tags,
|
||||
SelectUser,
|
||||
AttestationForm,
|
||||
MarketView,
|
||||
SVG,
|
||||
LoadingMapOverlay,
|
||||
} from 'utopia-ui'
|
||||
|
||||
import { Route, Routes } from 'react-router-dom'
|
||||
|
||||
import './App.css'
|
||||
import { lazy, Suspense, useEffect, useState } from 'react'
|
||||
|
||||
import { assetsApi } from './api/assetsApi'
|
||||
import { itemsApi } from './api/itemsApi'
|
||||
import { layersApi } from './api/layersApi'
|
||||
import { mapApi } from './api/mapApi'
|
||||
import { permissionsApi } from './api/permissionsApi'
|
||||
import { userApi } from './api/userApi'
|
||||
import { ModalContent } from './ModalContent'
|
||||
import { Landingpage } from './pages/Landingpage'
|
||||
import MapContainer from './pages/MapContainer'
|
||||
import { getBottomRoutes, routes } from './routes/sidebar'
|
||||
|
||||
function App() {
|
||||
const [permissionsApiInstance, setPermissionsApiInstance] = useState<permissionsApi>()
|
||||
const [tagsApi, setTagsApi] = useState<itemsApi<Tag>>()
|
||||
const [mapApiInstance, setMapApiInstance] = useState<mapApi>()
|
||||
const [layersApiInstance, setLayersApiInstance] = useState<layersApi>()
|
||||
const [attestationApi, setAttestationApi] = useState<itemsApi<any>>()
|
||||
|
||||
const [map, setMap] = useState<any>()
|
||||
const [layers, setLayers] = useState<any>()
|
||||
const [layerPageRoutes, setLayerPageRoutes] = useState<any>()
|
||||
const [loading, setLoading] = useState<boolean>(true)
|
||||
|
||||
const [embedded, setEmbedded] = useState<boolean>(true)
|
||||
|
||||
useEffect(() => {
|
||||
const params = new URLSearchParams(location.search)
|
||||
const embedded = params.get('embedded')
|
||||
embedded !== 'true' && setEmbedded(false)
|
||||
}, [location])
|
||||
|
||||
useEffect(() => {
|
||||
setPermissionsApiInstance(new permissionsApi())
|
||||
setMapApiInstance(new mapApi(window.location.origin))
|
||||
setAttestationApi(new itemsApi<any>('attestations'))
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
mapApiInstance && getMap()
|
||||
}, [mapApiInstance])
|
||||
|
||||
const getMap = async () => {
|
||||
const map = await mapApiInstance?.getItems()
|
||||
map && setMap(map)
|
||||
map && map != 'null' && setLayersApiInstance(new layersApi(map.id))
|
||||
map && map != 'null' && map.own_tag_space
|
||||
? setTagsApi(new itemsApi<Tag>('tags', undefined, map.id))
|
||||
: setTagsApi(new itemsApi<Tag>('tags'))
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
layersApiInstance && getLayers()
|
||||
}, [layersApiInstance])
|
||||
|
||||
const getLayers = async () => {
|
||||
const layers = await layersApiInstance?.getItems()
|
||||
layers && setLayers(layers)
|
||||
setLayerPageRoutes(
|
||||
layers
|
||||
?.filter((l: any) => l.listed)
|
||||
.map((l: any) => ({
|
||||
path: '/' + l.name, // url
|
||||
icon: (
|
||||
<SVG
|
||||
src={'https://api.utopia-lab.org/assets/' + l.indexIcon}
|
||||
className='w-6 h-6'
|
||||
preProcessor={(code: string) =>
|
||||
code.replace(/stroke=".*?"/g, 'stroke="currentColor"')
|
||||
}
|
||||
/>
|
||||
),
|
||||
name: l.name, // name that appear in Sidebar
|
||||
})),
|
||||
)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (map && map.name) {
|
||||
document.title = map?.name && map.name
|
||||
let link: HTMLLinkElement = document.querySelector("link[rel~='icon']")!
|
||||
if (!link) {
|
||||
link = document.createElement('link')
|
||||
link.rel = 'icon'
|
||||
document.getElementsByTagName('head')[0].appendChild(link)
|
||||
}
|
||||
link.href = map?.logo && 'https://api.utopia-lab.org/assets/' + map.logo // Specify the path to your favicon
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}, [map])
|
||||
|
||||
const currentUrl = window.location.href
|
||||
const bottomRoutes = getBottomRoutes(currentUrl)
|
||||
|
||||
const ProfileForm = lazy(() =>
|
||||
import('utopia-ui/Profile').then((mod) => ({
|
||||
default: mod.ProfileForm,
|
||||
})),
|
||||
)
|
||||
|
||||
const ProfileView = lazy(() =>
|
||||
import('utopia-ui/Profile').then((mod) => ({
|
||||
default: mod.ProfileView,
|
||||
})),
|
||||
)
|
||||
|
||||
const UserSettings = lazy(() =>
|
||||
import('utopia-ui/Profile').then((mod) => ({
|
||||
default: mod.UserSettings,
|
||||
})),
|
||||
)
|
||||
|
||||
if (map && layers)
|
||||
return (
|
||||
<div className='App overflow-x-hidden'>
|
||||
<AuthProvider userApi={new userApi()}>
|
||||
<AppShell
|
||||
assetsApi={new assetsApi('https://api.utopia-lab.org/assets/')}
|
||||
appName={map.name}
|
||||
embedded={embedded}
|
||||
openCollectiveApiKey={import.meta.env.VITE_OPEN_COLLECTIVE_API_KEY}
|
||||
>
|
||||
<Permissions
|
||||
api={permissionsApiInstance}
|
||||
adminRole='8ed0b24e-3320-48cd-8444-bc152304e580'
|
||||
></Permissions>
|
||||
{tagsApi && <Tags api={tagsApi}></Tags>}
|
||||
<Modal>
|
||||
<ModalContent map={map} />
|
||||
</Modal>
|
||||
<SideBar routes={[...routes, ...layerPageRoutes]} bottomRoutes={bottomRoutes} />
|
||||
<Content>
|
||||
<Quests />
|
||||
<Routes>
|
||||
<Route path='/*' element={<MapContainer map={map} layers={layers} />}>
|
||||
<Route path='login' element={<LoginPage />} />
|
||||
<Route path='signup' element={<SignupPage />} />
|
||||
<Route
|
||||
path='reset-password'
|
||||
element={<RequestPasswordPage resetUrl={map.url + '/set-new-password/'} />}
|
||||
/>
|
||||
<Route path='set-new-password' element={<SetNewPasswordPage />} />
|
||||
<Route
|
||||
path='item/*'
|
||||
element={
|
||||
<Suspense fallback={<LoadingMapOverlay />}>
|
||||
<ProfileView attestationApi={attestationApi} />
|
||||
</Suspense>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path='edit-item/*'
|
||||
element={
|
||||
<Suspense fallback={<LoadingMapOverlay />}>
|
||||
<ProfileForm />
|
||||
</Suspense>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path='user-settings'
|
||||
element={
|
||||
<Suspense fallback={<LoadingMapOverlay />}>
|
||||
<UserSettings />
|
||||
</Suspense>
|
||||
}
|
||||
/>
|
||||
<Route path='landingpage' element={<Landingpage />} />
|
||||
<Route path='market' element={<MarketView />} />
|
||||
<Route path='select-user' element={<SelectUser />} />
|
||||
{/* <Route
|
||||
path='onboarding'
|
||||
element={
|
||||
<MapOverlayPage
|
||||
backdrop
|
||||
className='max-w-[calc(100vw-32px)] md:max-w-md h-[calc(100vh-96px)] md:h-fit'
|
||||
>
|
||||
<Onboarding />
|
||||
</MapOverlayPage>
|
||||
}
|
||||
/> */}
|
||||
<Route
|
||||
path='attestation-form'
|
||||
element={<AttestationForm api={attestationApi} />}
|
||||
/>
|
||||
{layers.map((l: any) => (
|
||||
<Route
|
||||
key={l.id}
|
||||
path={l.name}
|
||||
element={
|
||||
<OverlayItemsIndexPage
|
||||
plusButton={l.index_plus_button}
|
||||
layerName={l.name}
|
||||
url={'/item/'}
|
||||
parameterField={'id'}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</Route>
|
||||
</Routes>
|
||||
</Content>
|
||||
</AppShell>
|
||||
</AuthProvider>
|
||||
</div>
|
||||
)
|
||||
else if (map == 'null' && !loading)
|
||||
return (
|
||||
<div className='flex items-center justify-center h-screen'>
|
||||
<div>
|
||||
<p className='text-xl font-semibold'>This map does not exist</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
else
|
||||
return (
|
||||
<div className='outer'>
|
||||
<img className='pulse-loader opacity h-[96px]' src='/3markers-globe.svg' />
|
||||
<br />
|
||||
<span className='loader'></span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default App
|
||||
184
frontend/src/ModalContent.tsx
Normal file
@ -0,0 +1,184 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/restrict-plus-operands */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable react/no-unescaped-entities */
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
import { useEffect, useState } from 'react'
|
||||
import { TextView } from 'utopia-ui'
|
||||
|
||||
interface ChapterProps {
|
||||
clickAction1?: () => void
|
||||
clickAction2?: () => void
|
||||
map?: any
|
||||
}
|
||||
|
||||
export function Welcome1({ clickAction1, map }: ChapterProps) {
|
||||
return (
|
||||
<>
|
||||
{map.custom_text ? (
|
||||
<>
|
||||
<TextView rawText={map.custom_text}></TextView>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<h3 className='font-bold text-lg'>Welcome to {map?.name || 'Utopia Map'}</h3>
|
||||
<img
|
||||
className='float-right w-32 m-2'
|
||||
src={'https://api.utopia-lab.org/assets/' + map.logo}
|
||||
></img>
|
||||
<p className='py-3'>
|
||||
It is a tool for collaborative mapping to connect local initiatives, people and events.
|
||||
</p>
|
||||
<p className='py-1'>
|
||||
Join us and grow the network by adding projects and events to the map.
|
||||
</p>
|
||||
<p className='py-1'>Create your personal profile and place it on the map.</p>
|
||||
<div className='grid'>
|
||||
<label className='btn btn-primary place-self-end mt-4' onClick={() => clickAction1!()}>
|
||||
Close
|
||||
</label>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export function Welcome2({ clickAction1 }: ChapterProps) {
|
||||
return (
|
||||
<>
|
||||
<h3 className='font-bold text-lg'> Dencentralized Networking</h3>
|
||||
<img className='float-right w-32 mx-4 my-2' src='/markers-circle.svg'></img>
|
||||
|
||||
<p className='py-3'>
|
||||
Find like-minded people, projects and events. In your neighbourhood and wherever you are!
|
||||
</p>
|
||||
<p className='py-3'>Onboard new people, places and events</p>
|
||||
<div className='grid'>
|
||||
<button className='btn place-self-end mt-4' onClick={() => clickAction1!()}>
|
||||
next
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export function Welcome3({ clickAction1 }: ChapterProps) {
|
||||
return (
|
||||
<>
|
||||
<h3 className='font-bold text-lg'>Mapping the Change</h3>
|
||||
<p className='py-3'>More and more people are waking up to what's really happening. </p>
|
||||
<p className='py-1'>
|
||||
They are in the process of understanding the potential that is within themselves and within
|
||||
the whole mankind.
|
||||
</p>
|
||||
<img className='float-left w-32 mx-4' src='/3markers-globe.svg'></img>
|
||||
|
||||
<p className='py-1'>
|
||||
Starting to reconnect with our Mother Earth and beginning to question things that long times
|
||||
have been taken for granted.
|
||||
</p>
|
||||
<div className='grid'>
|
||||
<label className='btn place-self-end mt-4' onClick={() => clickAction1!()}>
|
||||
next
|
||||
</label>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export function Welcome4({ clickAction1 }: ChapterProps) {
|
||||
return (
|
||||
<>
|
||||
<h3 className='font-bold text-lg'> Dezentralized Networks </h3>
|
||||
|
||||
<p className='py-3'>
|
||||
Find like-minded people, places and events. In your neighbourhood and wherever you are!
|
||||
</p>
|
||||
<img className='float-right w-32 mx-4 my-2' src='/network.svg'></img>
|
||||
|
||||
<p className='py-1'>
|
||||
Hypnotised, they sit in front of screens in concrete blocks, flooded and disillusioned by
|
||||
irrelevant information.
|
||||
</p>
|
||||
|
||||
<p className='py-1'>
|
||||
From an early age, they are trained to do alienated work and consume unhealthy and
|
||||
meaningless products.
|
||||
</p>
|
||||
<div className='grid'>
|
||||
<button className='btn place-self-end mt-4' onClick={() => clickAction1!()}>
|
||||
next
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
const myModal = document.getElementById('my_modal_3') as HTMLDialogElement
|
||||
myModal.close()
|
||||
}
|
||||
|
||||
export const ModalContent = ({ map }: { map: any }) => {
|
||||
useEffect(() => {
|
||||
const myModal = document.getElementById('my_modal_3') as HTMLDialogElement
|
||||
if (map.info_open) {
|
||||
myModal.showModal()
|
||||
}
|
||||
}, [map.info_open])
|
||||
|
||||
const [chapter, setChapter] = useState<number>(1)
|
||||
// const setQuestsOpen = useSetQuestOpen()
|
||||
|
||||
const ActiveChapter = () => {
|
||||
switch (chapter) {
|
||||
case 1:
|
||||
return (
|
||||
<Welcome1
|
||||
map={map}
|
||||
clickAction1={() => {
|
||||
close()
|
||||
setTimeout(() => {
|
||||
// setQuestsOpen(true);
|
||||
setChapter(1)
|
||||
}, 1000)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
case 2:
|
||||
return (
|
||||
<Welcome2
|
||||
clickAction1={() => {
|
||||
setChapter(3)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
case 3:
|
||||
return (
|
||||
<Welcome3
|
||||
clickAction1={() => {
|
||||
setChapter(4)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
case 4:
|
||||
return (
|
||||
<Welcome4
|
||||
clickAction1={() => {
|
||||
close()
|
||||
setTimeout(() => {
|
||||
// setQuestsOpen(true);
|
||||
setChapter(1)
|
||||
}, 1000)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
default:
|
||||
return <></>
|
||||
}
|
||||
}
|
||||
|
||||
return <ActiveChapter />
|
||||
}
|
||||
28
frontend/src/api/assetsApi.ts
Normal file
@ -0,0 +1,28 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable no-console */
|
||||
import { uploadFiles } from '@directus/sdk'
|
||||
|
||||
import { directusClient } from './directus'
|
||||
|
||||
import type { AssetsApi } from 'utopia-ui'
|
||||
|
||||
export class assetsApi implements AssetsApi {
|
||||
url: string
|
||||
|
||||
constructor(url: string) {
|
||||
this.url = url
|
||||
}
|
||||
|
||||
async upload(file: Blob, title: string) {
|
||||
const formData = new FormData()
|
||||
formData.append('title', title)
|
||||
formData.append('file', file)
|
||||
|
||||
try {
|
||||
return await directusClient.request(uploadFiles(formData))
|
||||
} catch (error: any) {
|
||||
console.log(error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
93
frontend/src/api/directus.ts
Normal file
@ -0,0 +1,93 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
/* eslint-disable @typescript-eslint/require-await */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
import { createDirectus, rest, authentication } from '@directus/sdk'
|
||||
|
||||
import type { AuthenticationData, AuthenticationStorage } from '@directus/sdk'
|
||||
import type { Point } from 'geojson'
|
||||
|
||||
export interface Place {
|
||||
id: string
|
||||
name: string
|
||||
text: string
|
||||
position?: Point
|
||||
}
|
||||
|
||||
export interface Project {
|
||||
id: string
|
||||
name: string
|
||||
text: string
|
||||
position?: Point
|
||||
picture: string
|
||||
subname: string
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export interface Tag {
|
||||
id: string
|
||||
color: string
|
||||
}
|
||||
|
||||
export interface Event {
|
||||
id: string
|
||||
name: string
|
||||
text: string
|
||||
position?: Point
|
||||
start: Date
|
||||
end: Date
|
||||
}
|
||||
|
||||
export interface Update {
|
||||
id: string
|
||||
text: string
|
||||
position?: Point
|
||||
user_created: string
|
||||
date_created: string
|
||||
}
|
||||
|
||||
interface CustomUserFields {
|
||||
position: Point
|
||||
}
|
||||
|
||||
export interface MyCollections {
|
||||
places: Place[]
|
||||
events: Event[]
|
||||
updates: Update[]
|
||||
tags: Tag[]
|
||||
projects: Project[]
|
||||
directus_users: CustomUserFields[]
|
||||
}
|
||||
|
||||
export const authLocalStorage = (mainKey = 'directus_storage') =>
|
||||
({
|
||||
// implementation of get, here return json parsed data from localStorage at mainKey (or null if not found)
|
||||
get: async () => {
|
||||
const data = window.localStorage.getItem(mainKey)
|
||||
if (data) {
|
||||
return JSON.parse(data)
|
||||
}
|
||||
return null
|
||||
},
|
||||
// implementation of set, here set the value at mainKey in localStorage, or remove it if value is null
|
||||
set: async (value: AuthenticationData | null) => {
|
||||
if (!value) {
|
||||
return window.localStorage.removeItem(mainKey)
|
||||
}
|
||||
return window.localStorage.setItem(mainKey, JSON.stringify(value))
|
||||
},
|
||||
}) as AuthenticationStorage
|
||||
|
||||
export async function getRefreshToken() {
|
||||
const auth = await authLocalStorage().get()
|
||||
return auth!.refresh_token
|
||||
}
|
||||
|
||||
export const directusClient = createDirectus<MyCollections>('https://api.utopia-lab.org/')
|
||||
.with(rest())
|
||||
.with(
|
||||
authentication('json', {
|
||||
// add this if you want to use authentication, json is important, it's type of your authentication usage, here JWT
|
||||
storage: authLocalStorage(), // here set the storage previously created
|
||||
}),
|
||||
)
|
||||
125
frontend/src/api/itemsApi.ts
Normal file
@ -0,0 +1,125 @@
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||
import { createItem, deleteItem, readItem, readItems, updateItem } from '@directus/sdk'
|
||||
|
||||
import { directusClient } from './directus'
|
||||
|
||||
import type { MyCollections } from './directus'
|
||||
import type { ItemsApi } from 'utopia-ui'
|
||||
|
||||
export class itemsApi<T> implements ItemsApi<T> {
|
||||
collectionName: string
|
||||
filter: any
|
||||
layerId: string | undefined
|
||||
mapId: string | undefined
|
||||
customParameter: any
|
||||
|
||||
constructor(
|
||||
collectionName: string,
|
||||
layerId?: string | undefined,
|
||||
mapId?: string | undefined,
|
||||
filter?: any,
|
||||
customParameter?: any,
|
||||
) {
|
||||
this.collectionName = collectionName
|
||||
if (filter) this.filter = filter
|
||||
else this.filter = {}
|
||||
this.layerId = layerId
|
||||
if (layerId) {
|
||||
this.filter = { ...filter, ...{ layer: { id: { _eq: layerId } } } }
|
||||
}
|
||||
this.mapId = mapId
|
||||
if (mapId) {
|
||||
this.filter = { ...filter, ...{ map: { id: { _eq: mapId } } } }
|
||||
}
|
||||
if (customParameter) this.customParameter = customParameter
|
||||
}
|
||||
|
||||
async getItems(): Promise<T[]> {
|
||||
try {
|
||||
const result = await directusClient.request<T[]>(
|
||||
readItems(this.collectionName as never, {
|
||||
fields: [
|
||||
'*',
|
||||
'to.*',
|
||||
'relations.*',
|
||||
'user_created.*',
|
||||
'markerIcon.*',
|
||||
{ offers: ['*'], needs: ['*'], gallery: ['*.*'] } as any,
|
||||
],
|
||||
filter: this.filter,
|
||||
limit: -1,
|
||||
}),
|
||||
)
|
||||
|
||||
return result
|
||||
} catch (error: any) {
|
||||
console.error(error)
|
||||
if (error.errors?.[0]?.message) {
|
||||
throw new Error(error.errors[0].message)
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async getItem(id: string): Promise<T> {
|
||||
try {
|
||||
const result = await directusClient.request(readItem(this.collectionName as never, id))
|
||||
return result as T
|
||||
} catch (error: any) {
|
||||
console.log(error)
|
||||
if (error.errors[0]?.message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
async createItem(item: T & { id?: string }): Promise<T> {
|
||||
try {
|
||||
const result = await directusClient.request(
|
||||
createItem(this.collectionName as keyof MyCollections, {
|
||||
...item,
|
||||
...(this.customParameter && this.customParameter),
|
||||
...(this.layerId && { layer: this.layerId }),
|
||||
...(this.layerId && { layer: this.layerId }),
|
||||
...(this.mapId && { map: this.mapId }),
|
||||
}),
|
||||
)
|
||||
return result as T
|
||||
} catch (error: any) {
|
||||
console.log(error)
|
||||
if (error.errors[0]?.message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
async updateItem(item: T & { id?: string }): Promise<T> {
|
||||
try {
|
||||
const result = await directusClient.request(
|
||||
updateItem(this.collectionName as keyof MyCollections, item.id!, item),
|
||||
)
|
||||
return result as T
|
||||
} catch (error: any) {
|
||||
console.log(error)
|
||||
if (error.errors[0].message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
async deleteItem(id: string): Promise<boolean> {
|
||||
try {
|
||||
const result = await directusClient.request(
|
||||
deleteItem(this.collectionName as keyof MyCollections, id),
|
||||
)
|
||||
return result as unknown as boolean
|
||||
} catch (error: any) {
|
||||
console.log(error)
|
||||
if (error.errors[0].message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
35
frontend/src/api/layersApi.ts
Normal file
@ -0,0 +1,35 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable no-console */
|
||||
import { readItems } from '@directus/sdk'
|
||||
|
||||
import { directusClient } from './directus'
|
||||
|
||||
export class layersApi {
|
||||
mapId: string
|
||||
|
||||
constructor(mapId: string) {
|
||||
this.mapId = mapId
|
||||
}
|
||||
|
||||
async getItems() {
|
||||
try {
|
||||
const layers = await directusClient.request(
|
||||
readItems('layers' as any, {
|
||||
fields: [
|
||||
'*',
|
||||
{ itemType: ['*.*', { profileTemplate: ['*', 'item.*.*.*.*'] }] },
|
||||
{ markerIcon: ['*'] } as any,
|
||||
],
|
||||
filter: { maps: { maps_id: { id: { _eq: this.mapId } } } },
|
||||
limit: 500,
|
||||
}),
|
||||
)
|
||||
return layers
|
||||
} catch (error: any) {
|
||||
console.log(error)
|
||||
if (error.errors[0]?.message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
33
frontend/src/api/mapApi.ts
Normal file
@ -0,0 +1,33 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { readItems } from '@directus/sdk'
|
||||
|
||||
import { directusClient } from './directus'
|
||||
|
||||
export class mapApi {
|
||||
url: string
|
||||
|
||||
constructor(url: string) {
|
||||
this.url = url
|
||||
}
|
||||
|
||||
async getItems() {
|
||||
try {
|
||||
const map = await directusClient.request(
|
||||
readItems('maps' as any, {
|
||||
fields: ['*', { user_type: ['name'] }],
|
||||
filter: { url: { _eq: this.url } } as any,
|
||||
limit: 500,
|
||||
}),
|
||||
)
|
||||
if (map[0]) return map[0]
|
||||
else return 'null'
|
||||
} catch (error: any) {
|
||||
console.log(error)
|
||||
if (error.errors[0]?.message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
27
frontend/src/api/permissionsApi.ts
Normal file
@ -0,0 +1,27 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-useless-constructor */
|
||||
/* eslint-disable @typescript-eslint/no-empty-function */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable no-console */
|
||||
import { readPermissions } from '@directus/sdk'
|
||||
|
||||
import { directusClient } from './directus'
|
||||
|
||||
import type { ItemsApi, Permission } from 'utopia-ui'
|
||||
|
||||
export class permissionsApi implements ItemsApi<Permission> {
|
||||
constructor() {}
|
||||
|
||||
async getItems(): Promise<Permission[]> {
|
||||
try {
|
||||
const result = await directusClient.request(
|
||||
readPermissions({ fields: ['*', { policy: ['name', 'roles'] } as any] }),
|
||||
)
|
||||
return result as unknown as Permission[]
|
||||
} catch (error: any) {
|
||||
console.log(error)
|
||||
if (error.errors[0]?.message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
18
frontend/src/api/readUserApi.ts
Normal file
@ -0,0 +1,18 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { readUser } from '@directus/sdk'
|
||||
|
||||
import { directusClient } from './directus'
|
||||
|
||||
export class readUserApi {
|
||||
async getItem(id: string) {
|
||||
try {
|
||||
return await directusClient.request(readUser(id))
|
||||
} catch (error: any) {
|
||||
console.log(error)
|
||||
if (error.errors[0]?.message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
29
frontend/src/api/refiBcnApi.ts
Normal file
@ -0,0 +1,29 @@
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import axios from 'axios'
|
||||
|
||||
import type { ItemsApi } from 'utopia-ui'
|
||||
|
||||
export class refiBcnApi implements ItemsApi<any> {
|
||||
collectionName: string
|
||||
|
||||
constructor(collectionName: string) {
|
||||
this.collectionName = collectionName
|
||||
}
|
||||
|
||||
async getItems() {
|
||||
try {
|
||||
return (
|
||||
await axios.get(
|
||||
'https://antontranelis.github.io/ReFi-Barcelona-Prototype/projects/index.json',
|
||||
)
|
||||
).data.data
|
||||
} catch (error: any) {
|
||||
console.log(error)
|
||||
if (error.errors[0]?.message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
118
frontend/src/api/userApi.ts
Normal file
@ -0,0 +1,118 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
/* eslint-disable camelcase */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
import { createUser, passwordRequest, passwordReset, readMe, updateMe } from '@directus/sdk'
|
||||
|
||||
import { directusClient } from './directus'
|
||||
|
||||
import type { UserApi, UserItem } from 'utopia-ui'
|
||||
|
||||
interface DirectusError {
|
||||
errors: {
|
||||
message: string
|
||||
[key: string]: any
|
||||
}[]
|
||||
}
|
||||
|
||||
export class userApi implements UserApi {
|
||||
async register(email: string, password: string, userName: string): Promise<any> {
|
||||
try {
|
||||
return await directusClient.request(createUser({ email, password, first_name: userName }))
|
||||
} catch (error: unknown) {
|
||||
console.error('Registration error:', error)
|
||||
if (
|
||||
typeof error === 'object' &&
|
||||
error !== null &&
|
||||
'errors' in error &&
|
||||
Array.isArray((error as any).errors)
|
||||
) {
|
||||
const directusError = error as DirectusError
|
||||
const errorMessage = directusError.errors[0]?.message
|
||||
|
||||
if (errorMessage.includes('has to be unique')) {
|
||||
throw new Error('This e-mail address is already registered.')
|
||||
}
|
||||
|
||||
throw new Error(errorMessage || 'Unknown error during registration.')
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
async login(email: string, password: string): Promise<any> {
|
||||
try {
|
||||
return await directusClient.login(email, password, { mode: 'json' })
|
||||
} catch (error: any) {
|
||||
console.log(error)
|
||||
if (error.errors[0].message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
async logout(): Promise<any> {
|
||||
try {
|
||||
return await directusClient.logout()
|
||||
} catch (error: any) {
|
||||
console.log(error)
|
||||
if (error.errors[0].message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
async getUser(): Promise<any> {
|
||||
try {
|
||||
const user = await directusClient.request(readMe({ fields: ['*', { role: ['*'] } as any] }))
|
||||
return user
|
||||
} catch (error: any) {
|
||||
console.log(error)
|
||||
if (error.errors[0].message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
async getToken(): Promise<any> {
|
||||
try {
|
||||
const token = await directusClient.getToken()
|
||||
return token
|
||||
} catch (error: any) {
|
||||
console.log(error)
|
||||
if (error.errors[0].message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
async updateUser(user: UserItem): Promise<any> {
|
||||
const { id, ...userRest } = user
|
||||
try {
|
||||
const res = await directusClient.request(updateMe(userRest, { fields: ['*'] }))
|
||||
return res as any
|
||||
} catch (error: any) {
|
||||
console.log(error)
|
||||
if (error.errors[0].message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
async requestPasswordReset(email: string, reset_url?: string): Promise<any> {
|
||||
try {
|
||||
return await directusClient.request(passwordRequest(email, reset_url))
|
||||
} catch (error: any) {
|
||||
console.log(error)
|
||||
if (error.errors[0].message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
async passwordReset(reset_token: string, new_password: string): Promise<any> {
|
||||
try {
|
||||
return await directusClient.request(passwordReset(reset_token, new_password))
|
||||
} catch (error: any) {
|
||||
console.log(error)
|
||||
if (error.errors[0].message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
8
frontend/src/index.css
Normal file
@ -0,0 +1,8 @@
|
||||
@import 'tailwindcss';
|
||||
@plugin "daisyui" {
|
||||
themes: light --default, dark --prefersdark, valentine, retro, aqua, cyberpunk, caramellatte, abyss, silk;
|
||||
}
|
||||
|
||||
@theme {
|
||||
--animate-fade: fadeOut 1s ease-in-out;
|
||||
}
|
||||
15
frontend/src/main.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
/* eslint-disable import/default */
|
||||
/* eslint-disable import/extensions */
|
||||
/* eslint-disable import/no-named-as-default-member */
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
|
||||
import App from './App.tsx'
|
||||
import './index.css'
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
)
|
||||
98
frontend/src/pages/Calendar.tsx
Normal file
@ -0,0 +1,98 @@
|
||||
/* 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
|
||||
}
|
||||
188
frontend/src/pages/Concept.tsx
Normal file
@ -0,0 +1,188 @@
|
||||
/* eslint-disable react/no-unescaped-entities */
|
||||
import { CardPage } from 'utopia-ui'
|
||||
|
||||
export default function Concept() {
|
||||
return (
|
||||
<CardPage title='Concept'>
|
||||
Utopia is a cooperative Real Life Manifestation Game. While playing, we connect with
|
||||
ourselves, each other and our dreams to manifest them together.<br></br>
|
||||
<br></br>
|
||||
<div className='collapse collapse-arrow bg-base-200 mb-2'>
|
||||
<input type='radio' name='my-accordion-2' />
|
||||
<div className='collapse-title text-xl font-medium'>Real Life Manifestation Games </div>
|
||||
<div className='collapse-content'>
|
||||
<ul className='list-disc list-inside pl-4'>
|
||||
<li>
|
||||
Like a role-playing game, you can create your own profile, but here you can map, share
|
||||
and train real skills.
|
||||
</li>
|
||||
<li>
|
||||
Further, real resources are made visible and available, managed and used, similar to a
|
||||
strategy game.
|
||||
</li>
|
||||
<li>
|
||||
Project management tasks can be mapped as quests, levels, missions and problems become
|
||||
challenges.
|
||||
</li>
|
||||
<li>The storytelling is based on the real conditions and challenges on our planet.</li>
|
||||
<li>
|
||||
The goal of the game is to create win-win-win situations. Win for you, win for us, win
|
||||
for the world.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div className='collapse collapse-arrow bg-base-200 mb-2'>
|
||||
<input type='radio' name='my-accordion-2' />
|
||||
<div className='collapse-title text-xl font-medium'>Elements</div>
|
||||
<div className='collapse-content'>
|
||||
<div className='flex flex-row flex-wrap'>
|
||||
<div className='basis-full md:basis-1/2 pr-4 pb-4'>
|
||||
<h3 className='text-base my-3 font-medium'> The App</h3>
|
||||
The app provides an interactive geographical map as a playing field. It also allows
|
||||
you to create and view player profiles. The marketplace shows offers and needs.{' '}
|
||||
</div>
|
||||
<div className='basis-full md:basis-1/2 pr-4 pb-4'>
|
||||
<h3 className='text-base my-3 font-medium'> Print Material</h3>
|
||||
To complement offline play, there are flyers, stickers, signs and workbooks that
|
||||
invite players to play. Players receive or print ID cards with QR codes that are used
|
||||
for networking (more on this later).
|
||||
</div>
|
||||
<div className='basis-full md:basis-1/2 pr-4 pb-4'>
|
||||
<h3 className='text-base my-3 font-medium'> Gatherings</h3>
|
||||
Coming together at workshops, festivals and local meetings to connect, build
|
||||
structures and to engage new players.{' '}
|
||||
</div>
|
||||
<div className='basis-full md:basis-1/2 pr-4 pb-4'>
|
||||
<h3 className='text-base my-3 font-medium'> Permanent Structures</h3>
|
||||
When we play, we create tangible structures like places and infrastructure. And also
|
||||
intangibles like networks of relationships, stories, information ...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='collapse collapse-arrow bg-base-200 mb-2'>
|
||||
<input type='radio' name='my-accordion-2' />
|
||||
<div className='collapse-title text-xl font-medium'>Goals </div>
|
||||
<div className='collapse-content'>
|
||||
<ol className='list-decimal list-inside pl-4'>
|
||||
<li>To build a decentralised network</li>
|
||||
<li>Free development of our collective and individual potential</li>
|
||||
<li>Start co-creation and build collective structures</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div className='collapse collapse-arrow bg-base-200 mb-2'>
|
||||
<input type='radio' name='my-accordion-2' />
|
||||
<div className='collapse-title text-xl font-medium'>Gameplay </div>
|
||||
<div className='collapse-content'>
|
||||
Through playful elements and gamification, the player is motivated and guided through
|
||||
quests and levels.
|
||||
<h3 className='text-base my-3 font-medium'> Player Profiles</h3>
|
||||
The player examines himself and his abilities as well as deeper desires and visions to
|
||||
define his character or player profile. The focus is on the following questions:
|
||||
<ul className='list-disc list-inside pl-4 pt-4'>
|
||||
<li>How and in what kind of world do I want to live?</li>
|
||||
<li>Who am I and what are my special abilities or my special task in this life?</li>
|
||||
<li>
|
||||
What do I have to give? What can and do I want to share with others and the world?
|
||||
</li>
|
||||
<li>
|
||||
What do I still need to come fully into my power? How can others support me in this?
|
||||
</li>
|
||||
</ul>
|
||||
<h3 className='text-base my-3 font-medium'> Resources</h3>
|
||||
The player explores and defines his/her offers and needs, shares his/her resources and
|
||||
uses those of the network. E.g. tools, machines, electrical appliances, vehicles, food and
|
||||
drink, places to sleep, rides, books, access to the internet, individual skills and help
|
||||
in everyday life
|
||||
<h3 className='text-base my-3 font-medium'> Realising Projects</h3>
|
||||
The player joins projects and starts his own. The game offers support in project
|
||||
management or crowdfunding. In this way, structures, events, permanent places,
|
||||
infrastructure and everything we need to meet our human needs in harmony with Mother Earth
|
||||
can be created.
|
||||
<h3 className='text-base my-3 font-medium'> Making Change visible</h3>
|
||||
The player is motivated to map and document the newly emerging world by ...
|
||||
<ul className='list-disc list-inside pl-4 pt-4'>
|
||||
<li>adding places, events etc. to the map</li>
|
||||
|
||||
<li>documenting projects with text, images, audio and video</li>
|
||||
|
||||
<li>telling stories of change</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div className='collapse collapse-arrow bg-base-200 mb-2'>
|
||||
<input type='radio' name='my-accordion-2' />
|
||||
<div className='collapse-title text-xl font-medium'>Web of Trust </div>
|
||||
<div className='collapse-content'>
|
||||
<div className='flex flex-row flex-wrap'>
|
||||
While we connect with other people in real life and build our personal network, we are
|
||||
simultaneously exchanging cryptographic keys and building a "Web of Trust".{' '}
|
||||
<div className='basis-full'>
|
||||
<div className='divider divider-vertical'></div>
|
||||
</div>
|
||||
<h3 className='text-base basis-full my-3 font-medium'> Decentralised IDs</h3>
|
||||
<div className='basis-full md:basis-1/2 pr-4 pb-4'>
|
||||
<img className='float-right h-28 px-4 pb-4' src='/public-private-key.svg'></img>
|
||||
|
||||
<p>
|
||||
When we create our profile, a key pair consisting of a private key and a public key
|
||||
is generated at the same time.
|
||||
</p>
|
||||
</div>
|
||||
<div className='basis-full md:basis-1/2 pr-4 pb-4'>
|
||||
<p className='basis-full pb-4'>
|
||||
We share the public key with our friends and they can use it to encrypt data for us.
|
||||
We keep the private key secret. It is needed to decrypt data that has been encrypted
|
||||
for us on our device.
|
||||
</p>
|
||||
</div>
|
||||
<div className='basis-full'>
|
||||
<div className='divider divider-vertical'></div>
|
||||
</div>
|
||||
<div className='basis-full md:basis-1/2 pr-4 pb-4'>
|
||||
<h3 className='text-base my-3 font-medium'> Key Exchange</h3>
|
||||
<img className='float-left h-32 px-4' src='/qr-scan.svg'></img>
|
||||
When we meet people in real life, we can exchange our public keys by scanning each
|
||||
other's QR codes or on paper.{' '}
|
||||
</div>
|
||||
<div className='basis-full md:basis-1/2 pr-4 pb-4'>
|
||||
<h3 className='text-base my-3 font-medium'> Private data sharing</h3>
|
||||
<img className='float-right h-32 px-4' src='/web-of-trust.svg'></img>
|
||||
Within our network, we can then share our profiles, offers, needs, projects, locations
|
||||
and events end-to-end encrypted.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='collapse collapse-arrow bg-base-200 mb-2'>
|
||||
<input type='radio' name='my-accordion-2' />
|
||||
<h2 className='collapse-title text-xl font-medium'>Principles </h2>
|
||||
<div className='collapse-content'>
|
||||
<div className='flex flex-row flex-wrap'>
|
||||
<div className='basis-full md:basis-1/2 pr-4 pb-4'>
|
||||
<h3 className='text-base my-3 font-medium'> Everything is just a game</h3>
|
||||
Everything happens voluntarily, out of ourselves in the flow. Everyone is invited to
|
||||
join in at any time.
|
||||
</div>
|
||||
<div className='basis-full md:basis-1/2 pr-4 pb-4'>
|
||||
<h3 className='text-base my-3 font-medium'> No Money</h3>
|
||||
Since the fun stops with money, we don't pay each other money when we play.
|
||||
</div>
|
||||
<div className='basis-full md:basis-1/2 pr-4 pb-4'>
|
||||
<h3 className='text-base my-3 font-medium'> Decentralised Structures</h3>
|
||||
All structures we create are decentralised and free of hierarchies. The same rules
|
||||
apply to everyone.
|
||||
</div>
|
||||
<div className='basis-full md:basis-1/2 pr-4 pb-4'>
|
||||
<h3 className='text-base my-3 font-medium'> Real Life</h3>
|
||||
Real change happens in real life. We only use the internet where it directly helps to
|
||||
organise real encounters.{' '}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardPage>
|
||||
)
|
||||
}
|
||||
203
frontend/src/pages/ConceptDE.tsx
Normal file
@ -0,0 +1,203 @@
|
||||
import { CardPage } from 'utopia-ui'
|
||||
|
||||
export default function Concept() {
|
||||
return (
|
||||
<CardPage title='Concept'>
|
||||
<b>Utopia Game</b> is a cooperative <b>Real Life Manifestation Game</b>. While playing, we
|
||||
connect with ourselves, each other and our dreams to manifest them together.<br></br>
|
||||
<br></br>
|
||||
<div className='collapse collapse-arrow bg-base-200 mb-2'>
|
||||
<input type='radio' name='my-accordion-2' />
|
||||
<div className='collapse-title text-xl font-medium'>Real-Life-Manifestations-Spiel ? </div>
|
||||
<div className='collapse-content'>
|
||||
<div className='flex flex-row flex-wrap'>
|
||||
<div className='basis-full pr-4 pb-4'>
|
||||
Ähnlich wie bei einem Rollenspiel kann man sich sein eigenes Profil erstellen, mit dem
|
||||
Unterschied, dass hier echte Fähigkeiten abgebildet, geteilt und trainiert werden
|
||||
können.
|
||||
</div>
|
||||
<div className='basis-full pr-4 pb-4'>
|
||||
Die Geschichte und das Storytelling orientiert sich an den realen Zuständen und
|
||||
Herausforderungen auf unserer Erde.
|
||||
</div>
|
||||
<div className='basis-full pr-4 pb-4'>
|
||||
Des weiteren werden reale Ressourcen sichtbar und verfügbar gemacht, verwaltet und
|
||||
eingesetzt, ähnlich wie bei einem Strategie-Spiel.
|
||||
</div>
|
||||
<div className='basis-full pr-4 pb-4'>
|
||||
Die Aufgaben des Projektmanagements können als Quests bzw. Spielaufträge abgebildet
|
||||
werden. Kleine und große Aufgaben werden in Abenteuer und Herausforderungen verwandelt
|
||||
und Probleme in Rätsel.
|
||||
</div>
|
||||
</div>
|
||||
<div className='basis-full pr-4 pb-4'>
|
||||
Ziel des Spiels ist es, WinWinWin Situationen zu erzeugen. Win für Dich, Win für Uns,
|
||||
Win für die Welt.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='collapse collapse-arrow bg-base-200 mb-2'>
|
||||
<input type='radio' name='my-accordion-2' />
|
||||
<div className='collapse-title text-xl font-medium'>Elemente des Spiels </div>
|
||||
<div className='collapse-content'>
|
||||
<div className='flex flex-row flex-wrap'>
|
||||
<div className='basis-full md:basis-1/2 pr-4 pb-4'>
|
||||
<h3 className='text-base my-3 font-medium'> App</h3>
|
||||
Die App bietet eine interaktive geografische Karte als Spielfeld. Außerdem ermöglicht
|
||||
sie das Erstellen und Ansehen von Spieler-Profilen. Der Marktplatz zeigt Angebote und
|
||||
Bedürfnisse
|
||||
</div>
|
||||
<div className='basis-full md:basis-1/2 pr-4 pb-4'>
|
||||
<h3 className='text-base my-3 font-medium'> Print Material</h3>
|
||||
Als Ergänzung und zum Offline-Spielen gibt es Flyer, Aufkleber, Schilder und
|
||||
Workbooks, welche zum Spielen einladen. Spieler erhalten Ausweise und Visitenkarten
|
||||
mit QR-Codes, die zu Vernetzung genutzt werden (später mehr)
|
||||
</div>
|
||||
<div className='basis-full md:basis-1/2 pr-4 pb-4'>
|
||||
<h3 className='text-base my-3 font-medium'> Temporäre Events</h3>
|
||||
Wir kommen zusammen bei Workshops, auf Festivals und bei lokalen Treffen um uns zu
|
||||
connecten, Strukturen zu bilden und neue Spieler zu gewinnen.
|
||||
</div>
|
||||
<div className='basis-full md:basis-1/2 pr-4 pb-4'>
|
||||
<h3 className='text-base my-3 font-medium'> Dauerhafte Strukturen</h3>
|
||||
Beim Spielen erschaffen wir dauerhafte materielle Strukturen wie Orte und
|
||||
Infrastruktur. Und Immaterielles wie Netzwerke aus Beziehungen, Geschichten,
|
||||
Informationen ...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='collapse collapse-arrow bg-base-200 mb-2'>
|
||||
<input type='radio' name='my-accordion-2' />
|
||||
<div className='collapse-title text-xl font-medium'>Ziel des Spiels </div>
|
||||
<div className='collapse-content'>
|
||||
<ol className='list-decimal list-inside pl-4'>
|
||||
<li>Ein dezentrales Netzwerk aufspannen</li>
|
||||
<li>Freie Entfaltung unserer kollektiven und individuellen Potentiale</li>
|
||||
<li>Aufbau kollektiver Strukturen und Co-Kreation</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div className='collapse collapse-arrow bg-base-200 mb-2'>
|
||||
<input type='radio' name='my-accordion-2' />
|
||||
<div className='collapse-title text-xl font-medium'>Ablauf </div>
|
||||
<div className='collapse-content'>
|
||||
Durch spielerische Elemente / Gamification wird der Spieler motiviert und angeleitet ...
|
||||
<h3 className='text-base my-3 font-medium'> Spieler Profile</h3>
|
||||
Der Spieler setzt sich mit sich selbst und seinen Fähigkeiten sowie tieferen Wünschen und
|
||||
Visionen auseinander und definiert seinen Charakter bzw. Spieler-Profil Dabei stehen
|
||||
folgende Fragen im Mittelpunkt:
|
||||
<ul className='list-disc list-inside pl-4 pt-4'>
|
||||
<li>Wie und in was für einer Welt möchte ich leben?</li>
|
||||
<li>
|
||||
Wer bin ich und was sind meine besonderen Fähigkeiten oder meine spezielle Aufgabe in
|
||||
diesem Leben?
|
||||
</li>
|
||||
<li>Was habe ich zu geben? Was kann und möchte ich mit anderen und der Welt teilen?</li>
|
||||
<li>
|
||||
Was brauche ich noch um ganz in meine Kraft zu kommen? Wie können mich andere dabei
|
||||
unterstützen?
|
||||
</li>
|
||||
</ul>
|
||||
<h3 className='text-base my-3 font-medium'> Ressourcen</h3>
|
||||
Der Spieler erforscht und definiert seine Angebote und Bedürfnisse, teilt seine Ressourcen
|
||||
und nutzt die des Netzwerks Z.B. Werkzeuge, Maschinen, Elektrogeräte, Fahrzeuge, Essen und
|
||||
Trinken, Schlafplätze, Mitfahrten, Bücher, Zugang zum Internet, individuelle Fähigkeiten
|
||||
sowie Hilfe im Alltag
|
||||
<h3 className='text-base my-3 font-medium'> Projekte umsetzen</h3>
|
||||
Der Spieler schließt sich Projekten an und startet selbst welche. Das Spiel unterstützt
|
||||
beim Projektmanagement oder beim Crowdfunding So entstehen Strukturen, Veranstaltungen,
|
||||
dauerhafte Orte, Infrastruktur und alles was wir brauchen um unsere menschlichen
|
||||
Bedürfnisse im Einklang mit Mutter Erde zu befriedigen.
|
||||
<h3 className='text-base my-3 font-medium'> Wandel sichtbar machen</h3>
|
||||
Der Spieler wird motiviert die neu entstehende Welt zu kartieren und zu dokumentieren
|
||||
indem er ...
|
||||
<ul className='list-disc list-inside pl-4 pt-4'>
|
||||
<li>Orte, Veranstaltungen usw. in der Karte einträgt</li>
|
||||
|
||||
<li>Projekte mit Text, Bild und Ton dokumentiert</li>
|
||||
|
||||
<li>Geschichten des Wandels erzählt</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div className='collapse collapse-arrow bg-base-200 mb-2'>
|
||||
<input type='radio' name='my-accordion-2' />
|
||||
<div className='collapse-title text-xl font-medium'>Web of Trust </div>
|
||||
<div className='collapse-content'>
|
||||
<div className='flex flex-row flex-wrap'>
|
||||
Während wir uns mit anderen Menschen im echten Leben connecten und unser persönliches
|
||||
Netzwerk aufbauen, tauschen wir gleichzeitig kryptografische Schlüssel aus und bauen ein
|
||||
sogenanntes Web of Trust.
|
||||
<div className='basis-full'>
|
||||
<div className='divider divider-vertical'></div>
|
||||
</div>
|
||||
<h3 className='text-base basis-full my-3 font-medium'> Dezentrale IDs</h3>
|
||||
<div className='basis-full md:basis-1/2 pr-4 pb-4'>
|
||||
<img className='float-right h-24 px-4' src='/public-private-key.svg'></img>
|
||||
|
||||
<p>
|
||||
Wenn wir unser Profil erstellen wird gleichzeitig ein Schlüsselpaar bestehend aus
|
||||
einem privaten und einem öffentlichen Schlüssel erzeugt.
|
||||
</p>
|
||||
</div>
|
||||
<div className='basis-full md:basis-1/2 pr-4 pb-4'>
|
||||
<p className='basis-full pb-4'>
|
||||
Den öffentlichen Schlüssel teilen wir mit unseren Freunden und diese können damit
|
||||
Daten für uns verschlüsseln.
|
||||
</p>
|
||||
|
||||
<p className='basis-full'>
|
||||
Den privaten Schlüssel halten wir geheim. Er wird benötigt um Daten die für uns
|
||||
verschlüsselt wurden auf unserem Gerät wieder zu entschlüsselt.
|
||||
</p>
|
||||
</div>
|
||||
<div className='basis-full'>
|
||||
<div className='divider divider-vertical'></div>
|
||||
</div>
|
||||
<div className='basis-full md:basis-1/2 pr-4 pb-4'>
|
||||
<h3 className='text-base my-3 font-medium'> Schlüsseltausch</h3>
|
||||
<img className='float-left h-32 px-4' src='/qr-scan.svg'></img>
|
||||
Wenn wir Menschen im echten Leben begegnen tauschen wir unsere öffentlichen Schlüssel
|
||||
via QR-Code-Scan oder auf Papier.
|
||||
</div>
|
||||
<div className='basis-full md:basis-1/2 pr-4 pb-4'>
|
||||
<h3 className='text-base my-3 font-medium'> Private Daten teilen</h3>
|
||||
<img className='float-right h-32 px-4' src='/web-of-trust.svg'></img>
|
||||
Innerhalb unseres Netzwerkes können wir dann unsere Profile, Angebote, Bedürfnisse,
|
||||
Projekte, Orte und Veranstaltungen ende-zu-ende-verschlüsselt teilen.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='collapse collapse-arrow bg-base-200 mb-2'>
|
||||
<input type='radio' name='my-accordion-2' />
|
||||
<h2 className='collapse-title text-xl font-semibold'>Prinzipien </h2>
|
||||
<div className='collapse-content'>
|
||||
<div className='flex flex-row flex-wrap'>
|
||||
<div className='basis-full md:basis-1/2 pr-4 pb-4'>
|
||||
<h3 className='text-base my-3 font-medium'> Alles ist nur ein Spiel</h3>
|
||||
Alles passiert freiwillig, aus uns selbst heraus im Flow. Jeder ist jederzeit
|
||||
eingeladen mitzumachen.
|
||||
</div>
|
||||
<div className='basis-full md:basis-1/2 pr-4 pb-4'>
|
||||
<h3 className='text-base my-3 font-medium'> Kein Geld</h3>
|
||||
Da beim Geld der Spaß bekanntlich aufhört, bezahlen wir uns beim Spielen gegenseitig
|
||||
kein Geld.
|
||||
</div>
|
||||
<div className='basis-full md:basis-1/2 pr-4 pb-4'>
|
||||
<h3 className='text-base my-3 font-medium'> Dezentrale Strukturen</h3>
|
||||
Alle Strukturen, die wir erschaffen, gestalten wir dezentral und frei von Hierarchien.
|
||||
Für alle gelten die gleichen Regeln.
|
||||
</div>
|
||||
<div className='basis-full md:basis-1/2 pr-4 pb-4'>
|
||||
<h3 className='text-base my-3 font-medium'> Real Life</h3>
|
||||
Veränderung passiert im echten Leben. Wir nutzen das Internet nur wo es direkt hilft
|
||||
echte Begegnungen zu organisieren.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardPage>
|
||||
)
|
||||
}
|
||||
216
frontend/src/pages/Landingpage.tsx
Normal file
@ -0,0 +1,216 @@
|
||||
/* eslint-disable react/no-unescaped-entities */
|
||||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable import/no-relative-parent-imports */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||
/* eslint-disable new-cap */
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
/* eslint-disable @typescript-eslint/no-floating-promises */
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { MapOverlayPage } from 'utopia-ui'
|
||||
|
||||
import { itemsApi } from '../api/itemsApi'
|
||||
|
||||
export const Landingpage = () => {
|
||||
const [isLandingpageVisible, setIsLandingpageVisible] = useState(true)
|
||||
const [isBoxVisible, setIsBoxVisible] = useState(true)
|
||||
const [isPhoneVisible, setIsPhoneVisible] = useState(true)
|
||||
|
||||
const [featuresApi, setFeaturesApi] = useState<itemsApi<any>>()
|
||||
const [features, setFeatures] = useState<any[]>()
|
||||
|
||||
const [teamApi, setTeamApi] = useState<itemsApi<any>>()
|
||||
const [team, setTeam] = useState<any[]>()
|
||||
|
||||
const loadFeatures = async () => {
|
||||
const items = await featuresApi?.getItems()
|
||||
setFeatures(items as any)
|
||||
}
|
||||
|
||||
const loadTeam = async () => {
|
||||
const items = await teamApi?.getItems()
|
||||
setTeam(items as any)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setFeaturesApi(
|
||||
new itemsApi<any>('features', undefined, undefined, { status: { _eq: 'published' } }),
|
||||
)
|
||||
setTeamApi(new itemsApi<any>('team'))
|
||||
loadTeam()
|
||||
loadFeatures()
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
loadFeatures()
|
||||
}, [featuresApi])
|
||||
|
||||
useEffect(() => {
|
||||
loadTeam()
|
||||
}, [teamApi])
|
||||
|
||||
const navigate = useNavigate()
|
||||
|
||||
const startGame = () => {
|
||||
setTimeout(() => {
|
||||
setIsBoxVisible(false)
|
||||
}, 200)
|
||||
setTimeout(() => {
|
||||
setIsPhoneVisible(false)
|
||||
}, 200)
|
||||
setTimeout(() => {
|
||||
setIsLandingpageVisible(false)
|
||||
}, 500)
|
||||
setTimeout(() => {
|
||||
navigate('/')
|
||||
}, 1500)
|
||||
}
|
||||
|
||||
return (
|
||||
<MapOverlayPage
|
||||
className={`rounded-none! overflow-y-auto p-0! fadeable-div flex-none ${isLandingpageVisible ? '' : 'div-hidden'}`}
|
||||
card={false}
|
||||
>
|
||||
<div className='hero min-h-full text-base'>
|
||||
<div className='hero-content text-center flex flex-col place-items-center p-0'>
|
||||
<div
|
||||
className='bg-no-repeat bg-center w-full'
|
||||
style={{ backgroundImage: 'url(bg1.webp)' }}
|
||||
>
|
||||
<div className='min-h-[calc(100vh-60px)] flex flex-row items-center justify-center '>
|
||||
<div
|
||||
className={`max-w-md text-center bg-black p-8 m-8 bg-opacity-50 text-white backdrop-blur-xs rounded-xl movable-div ${isBoxVisible ? '' : 'move-out-left'}`}
|
||||
>
|
||||
<h1 className='text-5xl font-bold'>Utopia Game</h1>
|
||||
<p className='py-6'>
|
||||
ist mehr als nur ein Spiel. Es ist eine Bewegung, die darauf abzielt, die Spieler
|
||||
aus ihren virtuellen Welten zu befreien und sie zu inspirieren, das echte Leben zu
|
||||
erkunden, Fähigkeiten zu entwickeln und die Welt um sie herum zu gestalten. Bist
|
||||
du bereit, Teil dieser Revolution zu werden?{' '}
|
||||
</p>
|
||||
<div className='btn text-white! btn-primary' onClick={startGame}>
|
||||
Play ▶
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={`mockup-phone m-8 hidden lg:block movable-div ${isPhoneVisible ? '' : 'move-out-right'}`}
|
||||
>
|
||||
<div className='camera'></div>
|
||||
<div className='display'>
|
||||
my-8
|
||||
<div className='artboard artboard-demo phone-1'>
|
||||
<iframe src='/' height={568} width={320}></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section className='min-h-[50em] p-8 flex h-full items-center justify-center'>
|
||||
<ul className='my-8 grid gap-y-8 gap-x-12 sm:grid-cols-2 lg:grid-cols-3'>
|
||||
{features?.map((item, idx) => (
|
||||
<li key={idx} className='space-y-3'>
|
||||
<div className='w-12tw-card tw-card-body h-12 mx-auto bg-transparent! text-indigo-600 rounded-full flex items-center justify-center text-5xl'>
|
||||
{item.symbol}
|
||||
</div>
|
||||
<h4 className='text-lg font-semibold'>{item.heading}</h4>
|
||||
<p>{item.text}</p>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section className='py-14 min-h-[40em] p-8 flex h-full items-center justify-center mb-28'>
|
||||
<div className='max-w-(--breakpoint-xl) mx-auto text-center'>
|
||||
<div className='max-w-xl mx-auto'>
|
||||
<h3 className='text-3xl font-semibold sm:text-4xl'>Meet our team</h3>
|
||||
<p className='mt-3'>
|
||||
Lorem Ipsum is simply dummy text of the printing and typesetting industry.Lorem
|
||||
Ipsum has been the industry's standard dummy.
|
||||
</p>
|
||||
</div>
|
||||
<div className='mt-12'>
|
||||
<ul className='grid gap-8 sm:grid-cols-2 md:grid-cols-3'>
|
||||
{team?.map((item, idx) => (
|
||||
<li key={idx}>
|
||||
<div className='w-24 h-24 mx-auto'>
|
||||
<img
|
||||
src={`https://api.utopia-lab.org/assets/${item.image}`}
|
||||
className='w-full h-full rounded-full'
|
||||
alt=''
|
||||
/>
|
||||
</div>
|
||||
<div className='mt-2'>
|
||||
<h4 className='font-semibold sm:text-lg'>{item.name}</h4>
|
||||
<p className='text-indigo-600'>{item.role}</p>
|
||||
<p className='mt-2'>{item.text}</p>
|
||||
<div className='mt-4 flex justify-center gap-4'></div>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<footer className='text-gray-500 bg-base-200 px-4 py-5 w-full mx-auto md:px-8 text-base'>
|
||||
<div className='mt-8 items-center justify-center flex'>
|
||||
<div className='mt-6 sm:mt-0'>
|
||||
<ul className='flex items-center space-x-4'>
|
||||
<li className='w-8 h-8 border-current bg-white rounded-full flex items-center justify-center'>
|
||||
<a href='https://t.me/UtopiaMap'>
|
||||
<svg
|
||||
stroke='currentColor'
|
||||
fill='#1d93d2'
|
||||
strokeWidth='0'
|
||||
viewBox='0 0 512 512'
|
||||
height='1.4rem'
|
||||
width='1.4rem'
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
>
|
||||
<path d='M446.7 98.6l-67.6 318.8c-5.1 22.5-18.4 28.1-37.3 17.5l-103-75.9-49.7 47.8c-5.5 5.5-10.1 10.1-20.7 10.1l7.4-104.9 190.9-172.5c8.3-7.4-1.8-11.5-12.9-4.1L117.8 284 16.2 252.2c-22.1-6.9-22.5-22.1 4.6-32.7L418.2 66.4c18.4-6.9 34.5 4.1 28.5 32.2z'></path>
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li className='w-8 h-8 border-current bg-white rounded-full flex items-center justify-center'>
|
||||
<a href='mailto:hello@utopia-lab.org'>
|
||||
<svg
|
||||
stroke='currentColor'
|
||||
fill='#333'
|
||||
strokeWidth='0'
|
||||
viewBox='0 0 24 24'
|
||||
height='1.25rem'
|
||||
width='1.25rem'
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
>
|
||||
<path fill='none' d='M0 0h24v24H0z'></path>
|
||||
<path d='M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4-8 5-8-5V6l8 5 8-5v2z'></path>
|
||||
</svg>{' '}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li className='w-8 h-8 border-current bg-white rounded-full flex items-center justify-center'>
|
||||
<a href='https://twitter.com/UtopiaMapGame/' className='text-white'>
|
||||
<svg
|
||||
className='svg-icon w-[1.4rem] h-[1.4rem] text-[#1d93d2]'
|
||||
viewBox='0 0 20 20'
|
||||
>
|
||||
<path
|
||||
fill='currentColor'
|
||||
d='M18.258,3.266c-0.693,0.405-1.46,0.698-2.277,0.857c-0.653-0.686-1.586-1.115-2.618-1.115c-1.98,0-3.586,1.581-3.586,3.53c0,0.276,0.031,0.545,0.092,0.805C6.888,7.195,4.245,5.79,2.476,3.654C2.167,4.176,1.99,4.781,1.99,5.429c0,1.224,0.633,2.305,1.596,2.938C2.999,8.349,2.445,8.19,1.961,7.925C1.96,7.94,1.96,7.954,1.96,7.97c0,1.71,1.237,3.138,2.877,3.462c-0.301,0.08-0.617,0.123-0.945,0.123c-0.23,0-0.456-0.021-0.674-0.062c0.456,1.402,1.781,2.422,3.35,2.451c-1.228,0.947-2.773,1.512-4.454,1.512c-0.291,0-0.575-0.016-0.855-0.049c1.588,1,3.473,1.586,5.498,1.586c6.598,0,10.205-5.379,10.205-10.045c0-0.153-0.003-0.305-0.01-0.456c0.7-0.499,1.308-1.12,1.789-1.827c-0.644,0.28-1.334,0.469-2.06,0.555C17.422,4.782,17.99,4.091,18.258,3.266'
|
||||
></path>
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div className='mt-8 flex item s-center justify-center'>© 2024</div>
|
||||
</footer>
|
||||
</MapOverlayPage>
|
||||
)
|
||||
}
|
||||
153
frontend/src/pages/MapContainer.tsx
Normal file
@ -0,0 +1,153 @@
|
||||
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
/* eslint-disable import/no-relative-parent-imports */
|
||||
/* eslint-disable array-callback-return */
|
||||
/* eslint-disable new-cap */
|
||||
/* eslint-disable @typescript-eslint/no-empty-function */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { useEffect, useState } from 'react'
|
||||
import {
|
||||
UtopiaMap,
|
||||
Layer,
|
||||
PopupView,
|
||||
PopupButton,
|
||||
StartEndView,
|
||||
TextView,
|
||||
PopupForm,
|
||||
PopupStartEndInput,
|
||||
PopupTextAreaInput,
|
||||
PopupTextInput,
|
||||
} from 'utopia-ui'
|
||||
|
||||
import { itemsApi } from '../api/itemsApi'
|
||||
|
||||
import type { Place } from '../api/directus'
|
||||
import type { LayerProps } from 'utopia-ui'
|
||||
|
||||
interface layerApi {
|
||||
id: string
|
||||
api: itemsApi<Place>
|
||||
}
|
||||
|
||||
function MapContainer({ layers, map }: { layers: LayerProps[]; map: any }) {
|
||||
const [apis, setApis] = useState<layerApi[]>([])
|
||||
|
||||
useEffect(() => {
|
||||
// get timestamp for the end of the current day
|
||||
const now = new Date()
|
||||
const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate())
|
||||
const etartOfDayISO = startOfDay.toISOString()
|
||||
|
||||
layers.map((layer: LayerProps) => {
|
||||
apis &&
|
||||
setApis((current) => [
|
||||
...current,
|
||||
{
|
||||
id: layer.id!,
|
||||
api: new itemsApi<Place>('items', layer.id, undefined, {
|
||||
_or: [
|
||||
{
|
||||
end: {
|
||||
_gt: etartOfDayISO,
|
||||
},
|
||||
},
|
||||
{
|
||||
end: {
|
||||
_null: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
])
|
||||
})
|
||||
}, [layers])
|
||||
|
||||
useEffect(() => {}, [apis])
|
||||
|
||||
return (
|
||||
<>
|
||||
<UtopiaMap
|
||||
geo={map.geo}
|
||||
zoom={map.zoom || 5}
|
||||
center={map.center ? [map.center?.coordinates[1], map.center?.coordinates[0]] : [50.6, 9.5]}
|
||||
height='100%'
|
||||
width='100%'
|
||||
showFilterControl={map.show_filter_control}
|
||||
showLayerControl={map.show_layer_control}
|
||||
showGratitudeControl={map.show_gratitude_control}
|
||||
donationWidget={map.donation_widget}
|
||||
showThemeControl={map.show_theme_control}
|
||||
defaultTheme={map.default_theme}
|
||||
showZoomControl={map.show_zoom_control}
|
||||
expandLayerControl={map.expand_layer_control}
|
||||
>
|
||||
{layers &&
|
||||
apis &&
|
||||
layers.map((layer) => (
|
||||
<Layer
|
||||
id={layer.id}
|
||||
key={layer.id}
|
||||
name={layer.name}
|
||||
menuIcon={'https://api.utopia-lab.org/assets/' + layer.menuIcon}
|
||||
menuText={layer.menuText}
|
||||
menuColor={layer.menuColor}
|
||||
markerIcon={layer.markerIcon}
|
||||
markerShape={layer.markerShape}
|
||||
userProfileLayer={layer.userProfileLayer}
|
||||
markerDefaultColor={layer.menuColor}
|
||||
markerDefaultColor2={
|
||||
layer.markerDefaultColor2 ? layer.markerDefaultColor2 : 'RGBA(35, 31, 32, 0.2)'
|
||||
}
|
||||
itemType={layer.itemType}
|
||||
customEditLink='/edit-item'
|
||||
customEditParameter='id'
|
||||
public_edit_items={layer.public_edit_items}
|
||||
listed={layer.listed}
|
||||
api={apis.find((api) => api.id === layer.id)?.api}
|
||||
>
|
||||
<PopupView>
|
||||
{layer.itemType.show_start_end && <StartEndView></StartEndView>}
|
||||
{layer.itemType.show_profile_button && (
|
||||
<PopupButton url={'/item'} parameterField={'id'} text={'Profile'} />
|
||||
)}
|
||||
{layer.itemType.show_text && <TextView truncate></TextView>}
|
||||
</PopupView>
|
||||
<PopupForm>
|
||||
{layer.itemType.show_name_input && (
|
||||
<PopupTextInput dataField='name' placeholder='Name'></PopupTextInput>
|
||||
)}
|
||||
{layer.itemType.show_start_end_input && <PopupStartEndInput></PopupStartEndInput>}
|
||||
{layer.itemType.show_text_input && (
|
||||
<div className='mt-4'>
|
||||
<PopupTextAreaInput
|
||||
dataField='text'
|
||||
placeholder={'Text ...'}
|
||||
style='tw-h-40'
|
||||
></PopupTextAreaInput>
|
||||
</div>
|
||||
)}
|
||||
{
|
||||
// layer.public_edit_items && <PopupCheckboxInput dataField={'public_edit'} label={'public edit'}/>
|
||||
}
|
||||
{layer.itemType.custom_text && (
|
||||
<div className='flex justify-center'>
|
||||
<p>{layer.itemType.custom_text}</p>
|
||||
</div>
|
||||
)}
|
||||
{layer.item_presets &&
|
||||
Object.entries(layer.item_presets).map((ip: any) => (
|
||||
<input key={ip[0]} type='hidden' id={ip[0]} name={ip[0]} value={ip[1]} />
|
||||
))}
|
||||
</PopupForm>
|
||||
</Layer>
|
||||
))}
|
||||
</UtopiaMap>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default MapContainer
|
||||
115
frontend/src/pages/data.ts
Normal file
@ -0,0 +1,115 @@
|
||||
import type { Item, Tag } from 'utopia-ui'
|
||||
|
||||
export const tags: Tag[] = [
|
||||
{
|
||||
id: '423423423423',
|
||||
name: 'Activism',
|
||||
color: '#6d398b',
|
||||
},
|
||||
{
|
||||
id: '4234423',
|
||||
name: 'Art',
|
||||
color: '#fdc60b',
|
||||
},
|
||||
{
|
||||
id: '4231223423',
|
||||
name: 'Community',
|
||||
color: '#FFA439',
|
||||
},
|
||||
{
|
||||
id: '429803423423',
|
||||
name: 'Culture',
|
||||
color: '#f18e1c',
|
||||
},
|
||||
{
|
||||
id: '42423423',
|
||||
name: 'Education',
|
||||
color: '#444e99',
|
||||
},
|
||||
{
|
||||
id: '4565654423',
|
||||
name: 'Gardening',
|
||||
color: '#008e5b',
|
||||
},
|
||||
{
|
||||
id: '4234gfh423',
|
||||
name: 'Healing',
|
||||
color: '#c4037d',
|
||||
},
|
||||
{
|
||||
id: '4223423',
|
||||
name: 'Market',
|
||||
color: '#2a71b0',
|
||||
},
|
||||
{
|
||||
id: '42342gd3423',
|
||||
name: 'Nature',
|
||||
color: '#8cbb26',
|
||||
},
|
||||
{
|
||||
id: '423123423',
|
||||
name: 'Technology',
|
||||
color: '#0696bb',
|
||||
},
|
||||
]
|
||||
|
||||
export const events: Item[] = [
|
||||
{
|
||||
id: '243253f3645643',
|
||||
name: 'Vollmondtrommeln',
|
||||
text: 'Zu den Vollmonden vom März bis Oktober treffen sich traditionell Menschen zum gemeinsamen Musizieren, Tanzen, Spielen, Grillen und Entspannen am Gerloser Häuschen im Niesiger Wald.\r\n\r\nUhrzeit: immer ab 17 Uhr\r\n\r\nhttps://trommeln-fulda.de/vollmondtrommeln/',
|
||||
position: {
|
||||
type: 'Point',
|
||||
coordinates: [9.667615, 50.588632],
|
||||
},
|
||||
start: '2022-03-18T12:00:00',
|
||||
end: '2022-10-08T12:00:00',
|
||||
},
|
||||
{
|
||||
id: 'fsdfsdfsdfsdfdse',
|
||||
name: 'anderes Event',
|
||||
text: 'Zu den Vollmonden vom März bis Oktober treffen sich traditionell Menschen zum gemeinsamen Musizieren, Tanzen, Spielen, Grillen und Entspannen am Gerloser Häuschen im Niesiger Wald.\r\n\r\nUhrzeit: immer ab 17 Uhr\r\n\r\nhttps://trommeln-fulda.de/vollmondtrommeln/',
|
||||
position: {
|
||||
type: 'Point',
|
||||
coordinates: [9.68, 50.59],
|
||||
},
|
||||
start: '2022-03-18T12:00:00',
|
||||
end: '2022-10-08T12:00:00',
|
||||
},
|
||||
]
|
||||
|
||||
export const places: Item[] = [
|
||||
{
|
||||
id: '1asdasdasd',
|
||||
name: 'Gärtnerei am Leisebach',
|
||||
text: 'Wir sind eine Bio-Gemüsegärtnerei und suchen noch fleißige Helfer für diese Saison.',
|
||||
position: {
|
||||
type: 'Point',
|
||||
coordinates: [8.476371, 51.0044],
|
||||
},
|
||||
date_created: '2021-04-15T07:46:26.906Z',
|
||||
date_updated: '2021-04-15T07:46:26.906Z',
|
||||
},
|
||||
{
|
||||
id: 'adsasdas2',
|
||||
name: 'Rainbow Crystal Land',
|
||||
text: 'https://rainbowcrystal.land',
|
||||
position: {
|
||||
type: 'Point',
|
||||
coordinates: [-76.367426, 1.87],
|
||||
},
|
||||
date_created: '2021-04-04T18:01:24.596Z',
|
||||
date_updated: '2021-04-04T18:01:24.596Z',
|
||||
},
|
||||
{
|
||||
id: 'f345v34',
|
||||
name: '🌈 RainbowCrystaleARThshipKinderGarten',
|
||||
text: "AMYTIME WELCOME HOME\r\n\r\n#lebenliebenlernen\r\n#symbioticsynergysolutions\r\n#lebenlanglachen\r\n#soriendosiempresaludpazyamor\r\n#laughinglearninglivingloving\r\n#souriresantétoujoursamoure\r\n\r\n\r\n<b>Garden IntroductionVideo</b>\r\n<br>\r\n\r\n\r\n<iframe width='250' src='https://www.youtube-nocookie.com/embed/7jUaixJGK08' title='YouTube video player' frameborder='0' allow='accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture' allowfullscreen></iframe>",
|
||||
position: {
|
||||
type: 'Point',
|
||||
coordinates: [9.502648, 51.334741],
|
||||
},
|
||||
date_created: '2022-03-13T23:09:56.305Z',
|
||||
date_updated: '2022-03-13T23:09:56.305Z',
|
||||
},
|
||||
]
|
||||
68
frontend/src/routes/sidebar.tsx
Normal file
@ -0,0 +1,68 @@
|
||||
import { MapIcon } from '@heroicons/react/24/outline'
|
||||
import { SVG } from 'utopia-ui'
|
||||
|
||||
export const routes = [
|
||||
{
|
||||
path: '/',
|
||||
icon: <MapIcon style={{ width: 24 }} />,
|
||||
name: 'Map',
|
||||
} /**
|
||||
{
|
||||
path: '/people', // url
|
||||
icon: <UsersIcon style={{width: 24 }}/>, // icon component
|
||||
name: 'People', // name that appear in Sidebar
|
||||
}, */,
|
||||
|
||||
/*
|
||||
{
|
||||
path: '', //no url needed as this has submenu
|
||||
icon: <DocumentDuplicateIcon className={`${iconClasses} inline` }/>, // icon component
|
||||
name: 'Pages', // name that appear in Sidebar
|
||||
submenu : [
|
||||
{
|
||||
path: '/login',
|
||||
icon: <ArrowRightOnRectangleIcon className={submenuIconClasses}/>,
|
||||
name: 'Kanban',
|
||||
},
|
||||
{
|
||||
path: '/register', //url
|
||||
icon: <UserIcon className={submenuIconClasses}/>, // icon component
|
||||
name: 'Gitlab', // name that appear in Sidebar
|
||||
},
|
||||
{
|
||||
path: '/forgot-password',
|
||||
icon: <KeyIcon className={submenuIconClasses}/>,
|
||||
name: 'Wiki',
|
||||
},
|
||||
]
|
||||
}
|
||||
*/
|
||||
]
|
||||
|
||||
export const getBottomRoutes = (currentUrl: string) => {
|
||||
const url = new URL(currentUrl)
|
||||
const isEmbedded = url.searchParams.get('embedded') === 'true'
|
||||
|
||||
const bottomRoutes = [
|
||||
// Other routes can be added here
|
||||
]
|
||||
|
||||
if (!isEmbedded) {
|
||||
bottomRoutes.push(
|
||||
{
|
||||
path: 'https://github.com/utopia-os/utopia-ui', // url
|
||||
icon: <SVG src='/github.svg' className='w-6 h-6' />,
|
||||
name: 'GitHub', // name that appear in Sidebar
|
||||
blank: true,
|
||||
},
|
||||
{
|
||||
path: 'https://opencollective.com/utopia-project', // url
|
||||
icon: <SVG src='/opencollective.svg' className='w-6 h-6' />,
|
||||
name: 'Open Collective', // name that appear in Sidebar
|
||||
blank: true,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
return bottomRoutes
|
||||
}
|
||||
12
frontend/tailwind.config.js
Normal file
@ -0,0 +1,12 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: ['./src/**/*.{html,js,jsx,tsx,ts}'],
|
||||
theme: {
|
||||
extend: {
|
||||
// that is animation class
|
||||
animation: {
|
||||
fade: 'fadeOut 1s ease-in-out',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
24
frontend/tsconfig.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"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
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
10
frontend/tsconfig.node.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
BIN
frontend/video_preview.png
Normal file
|
After Width: | Height: | Size: 535 KiB |
47
frontend/vite.config.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import tailwindcss from '@tailwindcss/vite';
|
||||
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(),
|
||||
],
|
||||
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'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
0
.gitignore → lib/.gitignore
vendored
14
lib/.prettierrc.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"printWidth": 100,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"quoteProps": "as-needed",
|
||||
"jsxSingleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"bracketSpacing": true,
|
||||
"bracketSameLine": false,
|
||||
"arrowParens": "always",
|
||||
"endOfLine": "auto"
|
||||
}
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
2
lib/FUNDING.yaml
Normal file
@ -0,0 +1,2 @@
|
||||
github: [utopia-os]
|
||||
open_collective: utopia-project
|
||||
|
Before Width: | Height: | Size: 133 KiB After Width: | Height: | Size: 133 KiB |