mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2025-12-12 23:36:00 +00:00
Merge pull request #29 from utopia-os/eslint
refactor(frontend): eslint
This commit is contained in:
commit
02833c79af
3
.eslintignore
Normal file
3
.eslintignore
Normal file
@ -0,0 +1,3 @@
|
||||
node_modules/
|
||||
dist/
|
||||
data/
|
||||
223
.eslintrc.cjs
Normal file
223
.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'],
|
||||
},
|
||||
],
|
||||
}
|
||||
33
.github/workflows/test.lint.yml
vendored
Normal file
33
.github/workflows/test.lint.yml
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
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/**/*'
|
||||
- '**/*'
|
||||
|
||||
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: ./
|
||||
14
.prettierrc.json
Normal file
14
.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"
|
||||
}
|
||||
1
.tool-versions
Normal file
1
.tool-versions
Normal file
@ -0,0 +1 @@
|
||||
nodejs 20.12.1
|
||||
@ -17,4 +17,4 @@ services:
|
||||
- SECRET=SECRET
|
||||
- PUBLIC_URL=http://localhost
|
||||
- ADMIN_EMAIL=admin@it4c.dev
|
||||
- ADMIN_PASSWORD=admin123
|
||||
- ADMIN_PASSWORD=admin123
|
||||
|
||||
1373
package-lock.json
generated
1373
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
23
package.json
23
package.json
@ -6,7 +6,7 @@
|
||||
"scripts": {
|
||||
"dev": "vite --host",
|
||||
"build": "tsc && vite build",
|
||||
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||
"test:lint:eslint": "eslint --ext .ts,.tsx,.js,.jsx,.cjs,.mjs,.json,.yml,.yaml --max-warnings 0 .",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -22,16 +22,29 @@
|
||||
"utopia-ui": "^3.0.76"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint-community/eslint-plugin-eslint-comments": "^4.4.1",
|
||||
"@types/react": "^18.2.79",
|
||||
"@types/react-dom": "^18.2.25",
|
||||
"@typescript-eslint/eslint-plugin": "^5.57.1",
|
||||
"@typescript-eslint/parser": "^5.57.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
||||
"@typescript-eslint/parser": "^5.62.0",
|
||||
"@vitejs/plugin-react": "^4.0.0",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"daisyui": "^4.12.23",
|
||||
"eslint": "^8.38.0",
|
||||
"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.3.4",
|
||||
"eslint-plugin-react-refresh": "^0.4.18",
|
||||
"eslint-plugin-security": "^3.0.1",
|
||||
"eslint-plugin-yml": "^1.14.0",
|
||||
"postcss": "^8.4.30",
|
||||
"tailwindcss": "^3.3.3",
|
||||
"typescript": "^5.0.2",
|
||||
|
||||
267
src/App.tsx
267
src/App.tsx
@ -1,143 +1,198 @@
|
||||
import { AppShell, SideBar, Content, AuthProvider, Modal, LoginPage, SignupPage, Quests, RequestPasswordPage, SetNewPasswordPage, UserSettings, OverlayItemsIndexPage, ProfileView, ProfileForm, Permissions, Tags, SelectUser, AttestationForm, MarketView } from 'utopia-ui'
|
||||
import { getBottomRoutes, routes } from './routes/sidebar'
|
||||
/* 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,
|
||||
UserSettings,
|
||||
OverlayItemsIndexPage,
|
||||
ProfileView,
|
||||
ProfileForm,
|
||||
Permissions,
|
||||
Tags,
|
||||
SelectUser,
|
||||
AttestationForm,
|
||||
MarketView,
|
||||
} from 'utopia-ui'
|
||||
import { Route, Routes } from 'react-router-dom'
|
||||
import MapContainer from "./pages/MapContainer"
|
||||
|
||||
import './App.css'
|
||||
import { userApi } from './api/userApi'
|
||||
import { 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 { useEffect, useState } from 'react'
|
||||
import { itemsApi } from './api/itemsApi'
|
||||
import { permissionsApi } from './api/permissionsApi'
|
||||
import { Tag } from 'utopia-ui'
|
||||
import { mapApi } from './api/mapApi'
|
||||
import { layersApi } from './api/layersApi'
|
||||
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 [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 [map, setMap] = useState<any>()
|
||||
const [layers, setLayers] = useState<any>()
|
||||
const [layerPageRoutes, setLayerPageRoutes] = useState<any>()
|
||||
const [loading, setLoading] = useState<boolean>(true)
|
||||
|
||||
useEffect(() => {
|
||||
setPermissionsApiInstance(new permissionsApi());
|
||||
setMapApiInstance(new mapApi(window.location.origin));
|
||||
setAttestationApi(new itemsApi<any>("attestations"));
|
||||
setPermissionsApiInstance(new permissionsApi())
|
||||
setMapApiInstance(new mapApi(window.location.origin))
|
||||
setAttestationApi(new itemsApi<any>('attestations'))
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
mapApiInstance && getMap();
|
||||
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'));
|
||||
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 && 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: <img src={"https://api.utopia-lab.org/assets/" + l.indexIcon}></img>,
|
||||
name: l.name, // name that appear in Sidebar
|
||||
})));
|
||||
const layers = await layersApiInstance?.getItems()
|
||||
layers && setLayers(layers)
|
||||
setLayerPageRoutes(
|
||||
layers
|
||||
?.filter((l: any) => l.listed)
|
||||
.map((l: any) => ({
|
||||
path: '/' + l.name, // url
|
||||
icon: <img src={'https://api.utopia-lab.org/assets/' + l.indexIcon}></img>,
|
||||
name: l.name, // name that appear in Sidebar
|
||||
})),
|
||||
)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (map && map.name) {
|
||||
document.title = map?.name && map.name;
|
||||
let link = document.querySelector("link[rel~='icon']") as HTMLLinkElement
|
||||
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 = 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
|
||||
|
||||
link.href = map?.logo && 'https://api.utopia-lab.org/assets/' + map.logo // Specify the path to your favicon
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
|
||||
|
||||
|
||||
setLoading(false)
|
||||
}, [map])
|
||||
|
||||
const currentUrl = window.location.href;
|
||||
const bottomRoutes = getBottomRoutes(currentUrl);
|
||||
const currentUrl = window.location.href
|
||||
const bottomRoutes = getBottomRoutes(currentUrl)
|
||||
|
||||
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} >
|
||||
<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={<ProfileView attestationApi={attestationApi} />} />
|
||||
<Route path="edit-item/*" element={<ProfileForm />} />
|
||||
<Route path="user-settings" element={<UserSettings />} />
|
||||
<Route path="landingpage" element={<Landingpage />} />
|
||||
<Route path="market" element={<MarketView />} />
|
||||
<Route path="select-user" element={<SelectUser />} />
|
||||
<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>
|
||||
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}
|
||||
>
|
||||
<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={<ProfileView attestationApi={attestationApi} />} />
|
||||
<Route path='edit-item/*' element={<ProfileForm />} />
|
||||
<Route path='user-settings' element={<UserSettings />} />
|
||||
<Route path='landingpage' element={<Landingpage />} />
|
||||
<Route path='market' element={<MarketView />} />
|
||||
<Route path='select-user' element={<SelectUser />} />
|
||||
<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>
|
||||
</div>
|
||||
)
|
||||
|
||||
else return (
|
||||
<div className="outer">
|
||||
<img className="pulse-loader opacity h-[96px]" src="/3markers-globe.svg" />
|
||||
<br/>
|
||||
<span className="loader"></span>
|
||||
</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
|
||||
|
||||
@ -1,147 +1,177 @@
|
||||
/* 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 { useState } from 'react'
|
||||
import { TextView } from 'utopia-ui'
|
||||
|
||||
type ChapterProps = {
|
||||
clickAction1?: () => void
|
||||
clickAction2?: () => void
|
||||
map?: any
|
||||
|
||||
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 place-self-end mt-4" onClick={() => clickAction1!()}>Close</label>
|
||||
</div>
|
||||
</>}
|
||||
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 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>
|
||||
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>
|
||||
</>
|
||||
)
|
||||
<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>
|
||||
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>
|
||||
</>
|
||||
)
|
||||
<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>
|
||||
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-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'>
|
||||
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>
|
||||
</>
|
||||
)
|
||||
<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();
|
||||
const myModal = document.getElementById('my_modal_3') as HTMLDialogElement
|
||||
myModal.close()
|
||||
}
|
||||
|
||||
export const ModalContent = ({map}:{map: any}) => {
|
||||
export const ModalContent = ({ map }: { map: any }) => {
|
||||
const [chapter, setChapter] = useState<number>(1)
|
||||
// const setQuestsOpen = useSetQuestOpen()
|
||||
|
||||
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 <></>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
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 />
|
||||
)
|
||||
return <ActiveChapter />
|
||||
}
|
||||
|
||||
@ -1,27 +1,28 @@
|
||||
import { uploadFiles } from '@directus/sdk';
|
||||
import { directusClient } from './directus';
|
||||
import { AssetsApi } from 'utopia-ui';
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable no-console */
|
||||
import { uploadFiles } from '@directus/sdk'
|
||||
|
||||
import { directusClient } from './directus'
|
||||
|
||||
export class assetsApi implements AssetsApi{
|
||||
import type { AssetsApi } from 'utopia-ui'
|
||||
|
||||
url : string;
|
||||
export class assetsApi implements AssetsApi {
|
||||
url: string
|
||||
|
||||
constructor(url: string) {
|
||||
this.url = url;
|
||||
this.url = url
|
||||
}
|
||||
|
||||
async upload(file:Blob, title: string) {
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('title', title);
|
||||
formData.append('file', file);
|
||||
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));
|
||||
return await directusClient.request(uploadFiles(formData))
|
||||
} catch (error: any) {
|
||||
console.log(error);
|
||||
throw error;
|
||||
console.log(error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,87 +1,93 @@
|
||||
import { createDirectus, rest, authentication, AuthenticationData, AuthenticationStorage } from '@directus/sdk';
|
||||
import { Point } from 'geojson'
|
||||
/* 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'
|
||||
|
||||
export type Place = {
|
||||
id: string;
|
||||
name: string;
|
||||
text: string;
|
||||
position?: Point;
|
||||
};
|
||||
import type { AuthenticationData, AuthenticationStorage } from '@directus/sdk'
|
||||
import type { Point } from 'geojson'
|
||||
|
||||
export type Project = {
|
||||
id: string;
|
||||
name: string;
|
||||
text: string;
|
||||
position?: Point;
|
||||
picture: string;
|
||||
subname: string;
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
export type Tag = {
|
||||
id: string;
|
||||
color: string;
|
||||
};
|
||||
|
||||
export type Event = {
|
||||
id: string;
|
||||
name: string;
|
||||
text: string;
|
||||
position?: Point;
|
||||
start: Date;
|
||||
end: Date;
|
||||
};
|
||||
|
||||
export type Update = {
|
||||
id: string;
|
||||
text: string;
|
||||
position?: Point;
|
||||
user_created: string;
|
||||
date_created: string;
|
||||
}
|
||||
|
||||
type CustomUserFields = {
|
||||
position: Point;
|
||||
};
|
||||
|
||||
|
||||
export type MyCollections = {
|
||||
places: Place[];
|
||||
events: Event[];
|
||||
updates: Update[];
|
||||
tags: Tag[];
|
||||
projects: Project[];
|
||||
directus_users: CustomUserFields[];
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
export const authLocalStorage = (mainKey: string = "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(){
|
||||
let auth = await authLocalStorage().get()
|
||||
return auth!.refresh_token;
|
||||
export interface Place {
|
||||
id: string
|
||||
name: string
|
||||
text: string
|
||||
position?: Point
|
||||
}
|
||||
|
||||
export const directusClient = createDirectus<MyCollections>("https://api.utopia-lab.org/")
|
||||
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
|
||||
}));
|
||||
.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
|
||||
}),
|
||||
)
|
||||
|
||||
@ -1,103 +1,124 @@
|
||||
import { createItem, deleteItem, readItem, readItems, updateItem } from '@directus/sdk';
|
||||
import { MyCollections, directusClient } from './directus';
|
||||
import { ItemsApi } from 'utopia-ui';
|
||||
/* 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;
|
||||
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 }}}}
|
||||
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 }}}}
|
||||
this.mapId = mapId
|
||||
if (mapId) {
|
||||
this.filter = { ...filter, ...{ map: { id: { _eq: mapId } } } }
|
||||
}
|
||||
if(customParameter) this.customParameter = customParameter;
|
||||
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.*", { offers: ['*'], needs: ['*'], gallery: ['*.*'] } as any],
|
||||
filter: this.filter,
|
||||
limit: -1
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
return result as T[];
|
||||
readItems(this.collectionName as never, {
|
||||
fields: [
|
||||
'*',
|
||||
'to.*',
|
||||
'relations.*',
|
||||
'user_created.*',
|
||||
{ offers: ['*'], needs: ['*'], gallery: ['*.*'] } as any,
|
||||
],
|
||||
filter: this.filter,
|
||||
limit: -1,
|
||||
}),
|
||||
)
|
||||
|
||||
return result
|
||||
} catch (error: any) {
|
||||
console.error(error);
|
||||
console.error(error)
|
||||
if (error.errors?.[0]?.message) {
|
||||
throw new Error(error.errors[0].message);
|
||||
throw new Error(error.errors[0].message)
|
||||
} else {
|
||||
throw error;
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async getItem(id : string): Promise<T> {
|
||||
async getItem(id: string): Promise<T> {
|
||||
try {
|
||||
const result = await directusClient.request(readItem(this.collectionName as never, id));
|
||||
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;
|
||||
console.log(error)
|
||||
if (error.errors[0]?.message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
async createItem(item: T & { id?: string }) : Promise<T> {
|
||||
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})}))
|
||||
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;
|
||||
console.log(error)
|
||||
if (error.errors[0]?.message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
async updateItem(item: T & { id?: string }) : Promise<T> {
|
||||
async updateItem(item: T & { id?: string }): Promise<T> {
|
||||
try {
|
||||
const result = await directusClient.request(updateItem(this.collectionName as keyof MyCollections, item.id!, item))
|
||||
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;
|
||||
console.log(error)
|
||||
if (error.errors[0].message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
async deleteItem(id: string) : Promise<boolean> {
|
||||
async deleteItem(id: string): Promise<boolean> {
|
||||
try {
|
||||
const result = await directusClient.request(deleteItem(this.collectionName as keyof MyCollections, id))
|
||||
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;
|
||||
console.log(error)
|
||||
if (error.errors[0].message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,25 +1,31 @@
|
||||
import { readItems } from '@directus/sdk';
|
||||
import { directusClient } from './directus';
|
||||
|
||||
/* 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
|
||||
mapId: string
|
||||
|
||||
constructor(mapId: string) {
|
||||
this.mapId = mapId;
|
||||
this.mapId = mapId
|
||||
}
|
||||
|
||||
async getItems() {
|
||||
try {
|
||||
const layers = await directusClient.request(readItems("layers" as any, { fields: ['*', {itemType : ['*.*', {profileTemplate: ['*', 'item.*.*.*'] }]} as any], filter: { "maps": { "maps_id": { "id": { "_eq": this.mapId } } } }, limit: 500 }));
|
||||
return layers;
|
||||
const layers = await directusClient.request(
|
||||
readItems('layers' as any, {
|
||||
fields: ['*', { itemType: ['*.*', { profileTemplate: ['*', 'item.*.*.*'] }] } 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;
|
||||
console.log(error)
|
||||
if (error.errors[0]?.message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,26 +1,33 @@
|
||||
import { readItems } from '@directus/sdk';
|
||||
import { directusClient } from './directus';
|
||||
|
||||
/* 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
|
||||
url: string
|
||||
|
||||
constructor(url: string) {
|
||||
this.url = url;
|
||||
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";
|
||||
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;
|
||||
console.log(error)
|
||||
if (error.errors[0]?.message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,13 @@
|
||||
import { readPermissions } from "@directus/sdk";
|
||||
import { directusClient } from "./directus";
|
||||
import { ItemsApi, Permission } from "utopia-ui";
|
||||
/* 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() {}
|
||||
@ -8,13 +15,13 @@ export class permissionsApi implements ItemsApi<Permission> {
|
||||
async getItems(): Promise<Permission[]> {
|
||||
try {
|
||||
const result = await directusClient.request(
|
||||
readPermissions({ fields: ["*", { policy: ["name", "roles"] } as any] })
|
||||
);
|
||||
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;
|
||||
console.log(error)
|
||||
if (error.errors[0]?.message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,19 +1,18 @@
|
||||
import { readUser } from '@directus/sdk';
|
||||
import { directusClient } from './directus';
|
||||
/* 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) {
|
||||
export class readUserApi {
|
||||
async getItem(id: string) {
|
||||
try {
|
||||
return await directusClient.request(readUser(id));
|
||||
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;
|
||||
console.log(error)
|
||||
if (error.errors[0]?.message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,24 +1,29 @@
|
||||
import axios from 'axios';
|
||||
import { ItemsApi } from 'utopia-ui';
|
||||
/* 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;
|
||||
export class refiBcnApi implements ItemsApi<any> {
|
||||
collectionName: string
|
||||
|
||||
constructor(collectionName: string) {
|
||||
this.collectionName = collectionName;
|
||||
this.collectionName = collectionName
|
||||
}
|
||||
|
||||
async getItems() {
|
||||
try {
|
||||
return (await axios.get('https://antontranelis.github.io/ReFi-Barcelona-Prototype/projects/index.json')).data.data;
|
||||
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;
|
||||
console.log(error)
|
||||
if (error.errors[0]?.message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,110 +1,97 @@
|
||||
import { createUser, passwordRequest, passwordReset, readMe, updateMe} from '@directus/sdk';
|
||||
import { directusClient } from './directus';
|
||||
import { UserApi, UserItem } from 'utopia-ui';
|
||||
/* 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'
|
||||
|
||||
export class userApi implements UserApi {
|
||||
|
||||
async register(email: string, password: string, userName: string): Promise<any> {
|
||||
try {
|
||||
return await directusClient.request(createUser({email: email, password: password, first_name: userName}));
|
||||
return await directusClient.request(createUser({ email, password, first_name: userName }))
|
||||
} catch (error: any) {
|
||||
console.log(error);
|
||||
if (error.errors[0].message)
|
||||
throw error.errors[0].message;
|
||||
else throw error;
|
||||
console.log(error)
|
||||
if (error.errors[0].message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
async login(email: string, password: string): Promise<any> {
|
||||
try {
|
||||
return await directusClient.login(email,password,{mode: 'json'});
|
||||
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;
|
||||
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();
|
||||
return await directusClient.logout()
|
||||
} catch (error: any) {
|
||||
console.log(error);
|
||||
if (error.errors[0].message)
|
||||
throw error.errors[0].message;
|
||||
else throw error;
|
||||
console.log(error)
|
||||
if (error.errors[0].message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
async getUser(): Promise<any> {
|
||||
try {
|
||||
let user = await directusClient.request(readMe({ fields: ['*', {role: ['*']} as any] }));
|
||||
return user;
|
||||
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;
|
||||
console.log(error)
|
||||
if (error.errors[0].message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
async getToken(): Promise<any> {
|
||||
async getToken(): Promise<any> {
|
||||
try {
|
||||
const token = await directusClient.getToken();
|
||||
return token;
|
||||
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;
|
||||
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;
|
||||
const { id, ...userRest } = user
|
||||
try {
|
||||
const res = await directusClient.request(updateMe(userRest,{ fields: ['*'] }))
|
||||
return res as any;
|
||||
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;
|
||||
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> {
|
||||
async requestPasswordReset(email: string, reset_url?: string): Promise<any> {
|
||||
try {
|
||||
return await directusClient.request(passwordRequest(email,reset_url));
|
||||
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;
|
||||
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> {
|
||||
async passwordReset(reset_token: string, new_password: string): Promise<any> {
|
||||
try {
|
||||
return await directusClient.request(passwordReset(reset_token, new_password));
|
||||
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;
|
||||
console.log(error)
|
||||
if (error.errors[0].message) throw error.errors[0].message
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,14 @@
|
||||
/* 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') as HTMLElement).render(
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
|
||||
@ -1,102 +1,98 @@
|
||||
import React, { useState } from 'react'
|
||||
/* 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 { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/24/outline';
|
||||
import { MapOverlayPage } from 'utopia-ui';
|
||||
|
||||
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"));
|
||||
let 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}
|
||||
/>
|
||||
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>
|
||||
<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>
|
||||
);
|
||||
)
|
||||
})}
|
||||
</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
|
||||
}
|
||||
return string
|
||||
}
|
||||
|
||||
@ -1,120 +1,109 @@
|
||||
import { CardPage } from "utopia-ui"
|
||||
|
||||
/* 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.
|
||||
<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>
|
||||
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>
|
||||
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>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 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"> 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 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">
|
||||
<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">
|
||||
<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>
|
||||
<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>
|
||||
|
||||
<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">
|
||||
|
||||
<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>
|
||||
@ -123,106 +112,77 @@ export default function Concept() {
|
||||
</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 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>
|
||||
|
||||
|
||||
<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 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 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 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 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>
|
||||
|
||||
<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 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 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>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,130 +1,118 @@
|
||||
import { CardPage } from "utopia-ui"
|
||||
|
||||
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.
|
||||
|
||||
<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 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 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 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 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 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 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 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 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">
|
||||
<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">
|
||||
|
||||
<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">
|
||||
<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>
|
||||
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>
|
||||
<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">
|
||||
|
||||
<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>
|
||||
@ -133,117 +121,83 @@ export default function Concept() {
|
||||
</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 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>
|
||||
|
||||
|
||||
<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 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 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 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 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>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,195 +1,216 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
/* 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';
|
||||
|
||||
import { itemsApi } from '../api/itemsApi'
|
||||
|
||||
export const Landingpage = () => {
|
||||
const [isLandingpageVisible, setIsLandingpageVisible] = useState(true)
|
||||
const [isBoxVisible, setIsBoxVisible] = useState(true)
|
||||
const [isPhoneVisible, setIsPhoneVisible] = useState(true)
|
||||
|
||||
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 [featuresApi, setFeaturesApi] = useState<itemsApi<any>>();
|
||||
const [features, setFeatures] = useState<any[]>();
|
||||
|
||||
|
||||
const [teamApi, setTeamApi] = useState<itemsApi<any>>();
|
||||
const [team, setTeam] = 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 items = await featuresApi?.getItems()
|
||||
setFeatures(items as any)
|
||||
}
|
||||
|
||||
const loadTeam = async () => {
|
||||
const items = await teamApi?.getItems();
|
||||
setTeam(items as any);
|
||||
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();
|
||||
setFeaturesApi(
|
||||
new itemsApi<any>('features', undefined, undefined, { status: { _eq: 'published' } }),
|
||||
)
|
||||
setTeamApi(new itemsApi<any>('team'))
|
||||
loadTeam()
|
||||
loadFeatures()
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
loadFeatures();
|
||||
loadFeatures()
|
||||
}, [featuresApi])
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
loadTeam();
|
||||
loadTeam()
|
||||
}, [teamApi])
|
||||
|
||||
|
||||
|
||||
const navigate = useNavigate();
|
||||
const navigate = useNavigate()
|
||||
|
||||
const startGame = () => {
|
||||
setTimeout(() => {
|
||||
setIsBoxVisible(false)
|
||||
}, 200
|
||||
)
|
||||
}, 200)
|
||||
setTimeout(() => {
|
||||
setIsPhoneVisible(false)
|
||||
}, 200
|
||||
)
|
||||
}, 200)
|
||||
setTimeout(() => {
|
||||
setIsLandingpageVisible(false)
|
||||
}, 500
|
||||
)
|
||||
}, 500)
|
||||
setTimeout(() => {
|
||||
navigate("/")
|
||||
}, 1500
|
||||
)
|
||||
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)" }}>
|
||||
<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-sm 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
|
||||
className={`max-w-md text-center bg-black p-8 m-8 bg-opacity-50 text-white backdrop-blur-sm 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
|
||||
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>
|
||||
))
|
||||
}
|
||||
<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-screen-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.
|
||||
<section className='py-14 min-h-[40em] p-8 flex h-full items-center justify-center mb-28'>
|
||||
<div className='max-w-screen-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>
|
||||
))
|
||||
}
|
||||
<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>
|
||||
<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>
|
||||
<div className='mt-8 flex item s-center justify-center'>© 2024</div>
|
||||
</footer>
|
||||
|
||||
|
||||
</MapOverlayPage>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,104 +1,145 @@
|
||||
import { UtopiaMap, Layer, ItemView, PopupButton, StartEndView, TextView, ItemForm, PopupStartEndInput, PopupTextAreaInput, PopupTextInput, LayerProps } from 'utopia-ui'
|
||||
import { itemsApi } from '../api/itemsApi';
|
||||
import { Place } from '../api/directus';
|
||||
import { useEffect, useState } from 'react';
|
||||
/* 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,
|
||||
ItemView,
|
||||
PopupButton,
|
||||
StartEndView,
|
||||
TextView,
|
||||
ItemForm,
|
||||
PopupStartEndInput,
|
||||
PopupTextAreaInput,
|
||||
PopupTextInput,
|
||||
} from 'utopia-ui'
|
||||
|
||||
type layerApi = {
|
||||
id: string;
|
||||
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: Array<LayerProps>, map: any }) {
|
||||
const [apis, setApis] = useState<Array<layerApi>>([]);
|
||||
function MapContainer({ layers, map }: { layers: LayerProps[]; map: any }) {
|
||||
const [apis, setApis] = useState<layerApi[]>([])
|
||||
|
||||
useEffect(() => {
|
||||
// get timestamp for the end of the current day
|
||||
let now = new Date();
|
||||
let startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
||||
let etartOfDayISO = startOfDay.toISOString();
|
||||
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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
}])
|
||||
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])
|
||||
|
||||
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%"
|
||||
width='100%'
|
||||
showFilterControl={map.show_filter_control}
|
||||
showLayerControl={map.show_layer_control}
|
||||
showGratitudeControl={map.show_gratitude_control}
|
||||
donationWidget = {map.donation_widget}
|
||||
donationWidget={map.donation_widget}
|
||||
>
|
||||
{layers && apis &&
|
||||
layers.map(layer =>
|
||||
{layers &&
|
||||
apis &&
|
||||
layers.map((layer) => (
|
||||
<Layer
|
||||
id={layer.id}
|
||||
key={layer.id}
|
||||
name={layer.name}
|
||||
menuIcon={"https://api.utopia-lab.org/assets/" + layer.menuIcon}
|
||||
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)"}
|
||||
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}>
|
||||
api={apis.find((api) => api.id === layer.id)?.api}
|
||||
>
|
||||
<ItemView>
|
||||
{layer.itemType.show_start_end &&
|
||||
<StartEndView></StartEndView>
|
||||
}
|
||||
{layer.itemType.show_profile_button &&
|
||||
{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>
|
||||
}
|
||||
)}
|
||||
{layer.itemType.show_text && <TextView truncate></TextView>}
|
||||
</ItemView>
|
||||
<ItemForm>
|
||||
{layer.itemType.show_name_input && <PopupTextInput dataField='name' placeholder='Name'></PopupTextInput>}
|
||||
{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.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]} />)}
|
||||
{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]} />
|
||||
))}
|
||||
</ItemForm>
|
||||
</Layer>)
|
||||
}
|
||||
</Layer>
|
||||
))}
|
||||
</UtopiaMap>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,129 +1,115 @@
|
||||
import { Item, Tag } from "utopia-ui";
|
||||
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 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[] = [
|
||||
|
||||
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
|
||||
]
|
||||
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",
|
||||
}
|
||||
];
|
||||
|
||||
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"
|
||||
start: '2022-03-18T12:00:00',
|
||||
end: '2022-10-08T12:00:00',
|
||||
},
|
||||
{
|
||||
"id": "adsasdas2",
|
||||
"name": "Rainbow Crystal Land",
|
||||
"text": "https://rainbowcrystal.land",
|
||||
"position": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
-76.367426,
|
||||
1.87
|
||||
]
|
||||
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],
|
||||
},
|
||||
"date_created": "2021-04-04T18:01:24.596Z",
|
||||
"date_updated": "2021-04-04T18:01:24.596Z"
|
||||
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": "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
|
||||
]
|
||||
id: 'adsasdas2',
|
||||
name: 'Rainbow Crystal Land',
|
||||
text: 'https://rainbowcrystal.land',
|
||||
position: {
|
||||
type: 'Point',
|
||||
coordinates: [-76.367426, 1.87],
|
||||
},
|
||||
"date_created": "2022-03-13T23:09:56.305Z",
|
||||
"date_updated": "2022-03-13T23:09:56.305Z"
|
||||
}]
|
||||
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',
|
||||
},
|
||||
]
|
||||
|
||||
@ -1,22 +1,17 @@
|
||||
import { MapIcon } from '@heroicons/react/24/outline'
|
||||
|
||||
|
||||
export const routes = [
|
||||
|
||||
{
|
||||
path: '/',
|
||||
icon: <MapIcon style={{width: 24 }}/>,
|
||||
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
|
||||
@ -44,21 +39,29 @@ export const routes = [
|
||||
]
|
||||
|
||||
export const getBottomRoutes = (currentUrl: string) => {
|
||||
const url = new URL(currentUrl);
|
||||
const isEmbedded = url.searchParams.get('embedded') === 'true';
|
||||
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 viewBox="0 0 24 24" aria-hidden="true" className="tw-h-6 tw-w-6" stroke="currentColor"><path fillRule="evenodd" clipRule="evenodd" d="M12 2C6.477 2 2 6.463 2 11.97c0 4.404 2.865 8.14 6.839 9.458.5.092.682-.216.682-.48 0-.236-.008-.864-.013-1.695-2.782.602-3.369-1.337-3.369-1.337-.454-1.151-1.11-1.458-1.11-1.458-.908-.618.069-.606.069-.606 1.003.07 1.531 1.027 1.531 1.027.892 1.524 2.341 1.084 2.91.828.092-.643.35-1.083.636-1.332-2.22-.251-4.555-1.107-4.555-4.927 0-1.088.39-1.979 1.029-2.675-.103-.252-.446-1.266.098-2.638 0 0 .84-.268 2.75 1.022A9.607 9.607 0 0 1 12 6.82c.85.004 1.705.114 2.504.336 1.909-1.29 2.747-1.022 2.747-1.022.546 1.372.202 2.386.1 2.638.64.696 1.028 1.587 1.028 2.675 0 3.83-2.339 4.673-4.566 4.92.359.307.678.915.678 1.846 0 1.332-.012 2.407-.012 2.734 0 .267.18.577.688.48 3.97-1.32 6.833-5.054 6.833-9.458C22 6.463 17.522 2 12 2Z"></path></svg>,
|
||||
icon: (
|
||||
<svg viewBox='0 0 24 24' aria-hidden='true' className='tw-h-6 tw-w-6' stroke='currentColor'>
|
||||
<path
|
||||
fillRule='evenodd'
|
||||
clipRule='evenodd'
|
||||
d='M12 2C6.477 2 2 6.463 2 11.97c0 4.404 2.865 8.14 6.839 9.458.5.092.682-.216.682-.48 0-.236-.008-.864-.013-1.695-2.782.602-3.369-1.337-3.369-1.337-.454-1.151-1.11-1.458-1.11-1.458-.908-.618.069-.606.069-.606 1.003.07 1.531 1.027 1.531 1.027.892 1.524 2.341 1.084 2.91.828.092-.643.35-1.083.636-1.332-2.22-.251-4.555-1.107-4.555-4.927 0-1.088.39-1.979 1.029-2.675-.103-.252-.446-1.266.098-2.638 0 0 .84-.268 2.75 1.022A9.607 9.607 0 0 1 12 6.82c.85.004 1.705.114 2.504.336 1.909-1.29 2.747-1.022 2.747-1.022.546 1.372.202 2.386.1 2.638.64.696 1.028 1.587 1.028 2.675 0 3.83-2.339 4.673-4.566 4.92.359.307.678.915.678 1.846 0 1.332-.012 2.407-.012 2.734 0 .267.18.577.688.48 3.97-1.32 6.833-5.054 6.833-9.458C22 6.463 17.522 2 12 2Z'
|
||||
></path>
|
||||
</svg>
|
||||
),
|
||||
name: 'Github', // name that appear in Sidebar
|
||||
blank: true
|
||||
});
|
||||
blank: true,
|
||||
})
|
||||
}
|
||||
|
||||
return bottomRoutes;
|
||||
};
|
||||
return bottomRoutes
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: ["./src/**/*.{html,js,jsx,tsx,ts}"],
|
||||
content: ['./src/**/*.{html,js,jsx,tsx,ts}'],
|
||||
theme: {
|
||||
extend: {
|
||||
// that is animation class
|
||||
@ -9,9 +9,8 @@ export default {
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [import("daisyui")],
|
||||
plugins: [import('daisyui')],
|
||||
daisyui: {
|
||||
themes: ["light", "dark", "cupcake", "retro", "cyberpunk", "aqua"]
|
||||
}
|
||||
themes: ['light', 'dark', 'cupcake', 'retro', 'cyberpunk', 'aqua'],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user