Compare commits
3 Commits
3fe9ecbbb8
...
config-set
| Author | SHA1 | Date | |
|---|---|---|---|
|
4f5b301e7d
|
|||
|
8fedbc34fa
|
|||
| 47d4c7926e |
@@ -247,6 +247,35 @@ def osc_tracker_updater(address, fixed_args, *args) -> None:
|
|||||||
|
|
||||||
asyncio.ensure_future(update_all_clients(app))
|
asyncio.ensure_future(update_all_clients(app))
|
||||||
|
|
||||||
|
async def handle_add_tracker(request):
|
||||||
|
# Add tracker with id from request
|
||||||
|
try:
|
||||||
|
trackers = request.app["trackers"]
|
||||||
|
request_data = await request.json()
|
||||||
|
tracker_id = request_data["id"]
|
||||||
|
if tracker_id in trackers:
|
||||||
|
return web.Response(text="Tracker already exists", status=400)
|
||||||
|
|
||||||
|
trackers[tracker_id] = TrackerData(tracker_id, *START_POSITION_INTERNAL)
|
||||||
|
return web.Response(text="OK", status=200)
|
||||||
|
except Exception as e:
|
||||||
|
return web.Response(text=f"Error: {e}", status=400)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async def handler_delete_tracker(request):
|
||||||
|
# Delete tracker with id from request
|
||||||
|
try:
|
||||||
|
trackers = request.app["trackers"]
|
||||||
|
request_data = await request.json()
|
||||||
|
tracker_id = request_data["id"]
|
||||||
|
if tracker_id not in trackers:
|
||||||
|
return web.Response(text="Tracker does not exist", status=400)
|
||||||
|
|
||||||
|
del trackers[tracker_id]
|
||||||
|
return web.Response(text="OK", status=200)
|
||||||
|
except Exception as e:
|
||||||
|
return web.Response(text=f"Error: {e}", status=400)
|
||||||
|
|
||||||
async def receive_osc_data(app):
|
async def receive_osc_data(app):
|
||||||
dispatcher = Dispatcher()
|
dispatcher = Dispatcher()
|
||||||
@@ -265,8 +294,13 @@ def create_app():
|
|||||||
app.router.add_get("/", handle_root)
|
app.router.add_get("/", handle_root)
|
||||||
app.router.add_get("/ws", handle_websocket)
|
app.router.add_get("/ws", handle_websocket)
|
||||||
app.router.add_get("/background_image", handle_background_image)
|
app.router.add_get("/background_image", handle_background_image)
|
||||||
|
|
||||||
app.router.add_post("/mode", handle_set_mode)
|
app.router.add_post("/mode", handle_set_mode)
|
||||||
app.router.add_get("/mode", handlet_get_mode)
|
app.router.add_get("/mode", handlet_get_mode)
|
||||||
|
|
||||||
|
app.router.add_post("/tracker", handle_add_tracker)
|
||||||
|
app.router.add_delete("/tracker", handler_delete_tracker)
|
||||||
|
|
||||||
app.router.add_static("/", "./static")
|
app.router.add_static("/", "./static")
|
||||||
|
|
||||||
# Setup app state
|
# Setup app state
|
||||||
|
|||||||
@@ -8,5 +8,10 @@ import tailwind from "@astrojs/tailwind";
|
|||||||
|
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
integrations: [svelte(), tailwind()],
|
integrations: [
|
||||||
|
svelte(),
|
||||||
|
tailwind({
|
||||||
|
applyBaseStyles: false,
|
||||||
|
}),
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|||||||
14
frontend/components.json
Normal file
14
frontend/components.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://shadcn-svelte.com/schema.json",
|
||||||
|
"style": "default",
|
||||||
|
"tailwind": {
|
||||||
|
"config": "tailwind.config.mjs",
|
||||||
|
"css": "src/styles/app.css",
|
||||||
|
"baseColor": "slate"
|
||||||
|
},
|
||||||
|
"aliases": {
|
||||||
|
"components": "$lib/components",
|
||||||
|
"utils": "$lib/utils"
|
||||||
|
},
|
||||||
|
"typescript": true
|
||||||
|
}
|
||||||
@@ -19,10 +19,15 @@
|
|||||||
"typescript": "^5.8.2"
|
"typescript": "^5.8.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"bits-ui": "0.22.0",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"prettier-plugin-astro": "^0.14.1",
|
"prettier-plugin-astro": "^0.14.1",
|
||||||
"prettier-plugin-svelte": "^3.3.3",
|
"prettier-plugin-svelte": "^3.3.3",
|
||||||
"prettier-plugin-tailwindcss": "^0.6.11"
|
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||||
|
"tailwind-merge": "^3.0.2",
|
||||||
|
"tailwind-variants": "^1.0.0",
|
||||||
|
"vaul-svelte": "^0.3.2"
|
||||||
},
|
},
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"onlyBuiltDependencies": [
|
"onlyBuiltDependencies": [
|
||||||
|
|||||||
133
frontend/pnpm-lock.yaml
generated
133
frontend/pnpm-lock.yaml
generated
@@ -30,6 +30,12 @@ importers:
|
|||||||
specifier: ^5.8.2
|
specifier: ^5.8.2
|
||||||
version: 5.8.2
|
version: 5.8.2
|
||||||
devDependencies:
|
devDependencies:
|
||||||
|
bits-ui:
|
||||||
|
specifier: 0.22.0
|
||||||
|
version: 0.22.0(svelte@5.22.6)
|
||||||
|
clsx:
|
||||||
|
specifier: ^2.1.1
|
||||||
|
version: 2.1.1
|
||||||
prettier:
|
prettier:
|
||||||
specifier: ^3.5.3
|
specifier: ^3.5.3
|
||||||
version: 3.5.3
|
version: 3.5.3
|
||||||
@@ -42,6 +48,15 @@ importers:
|
|||||||
prettier-plugin-tailwindcss:
|
prettier-plugin-tailwindcss:
|
||||||
specifier: ^0.6.11
|
specifier: ^0.6.11
|
||||||
version: 0.6.11(prettier-plugin-astro@0.14.1)(prettier-plugin-svelte@3.3.3(prettier@3.5.3)(svelte@5.22.6))(prettier@3.5.3)
|
version: 0.6.11(prettier-plugin-astro@0.14.1)(prettier-plugin-svelte@3.3.3(prettier@3.5.3)(svelte@5.22.6))(prettier@3.5.3)
|
||||||
|
tailwind-merge:
|
||||||
|
specifier: ^3.0.2
|
||||||
|
version: 3.0.2
|
||||||
|
tailwind-variants:
|
||||||
|
specifier: ^1.0.0
|
||||||
|
version: 1.0.0(tailwindcss@3.4.17)
|
||||||
|
vaul-svelte:
|
||||||
|
specifier: ^0.3.2
|
||||||
|
version: 0.3.2(svelte@5.22.6)
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@@ -296,6 +311,15 @@ packages:
|
|||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
|
'@floating-ui/core@1.6.9':
|
||||||
|
resolution: {integrity: sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==}
|
||||||
|
|
||||||
|
'@floating-ui/dom@1.6.13':
|
||||||
|
resolution: {integrity: sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==}
|
||||||
|
|
||||||
|
'@floating-ui/utils@0.2.9':
|
||||||
|
resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==}
|
||||||
|
|
||||||
'@img/sharp-darwin-arm64@0.33.5':
|
'@img/sharp-darwin-arm64@0.33.5':
|
||||||
resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==}
|
resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
@@ -401,6 +425,9 @@ packages:
|
|||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
|
'@internationalized/date@3.7.0':
|
||||||
|
resolution: {integrity: sha512-VJ5WS3fcVx0bejE/YHfbDKR/yawZgKqn/if+oEeLqNwBtPzVB06olkfcnojTmEMX+gTpH+FlQ69SHNitJ8/erQ==}
|
||||||
|
|
||||||
'@isaacs/cliui@8.0.2':
|
'@isaacs/cliui@8.0.2':
|
||||||
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
|
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@@ -423,6 +450,11 @@ packages:
|
|||||||
'@jridgewell/trace-mapping@0.3.25':
|
'@jridgewell/trace-mapping@0.3.25':
|
||||||
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
|
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
|
||||||
|
|
||||||
|
'@melt-ui/svelte@0.76.2':
|
||||||
|
resolution: {integrity: sha512-7SbOa11tXUS95T3fReL+dwDs5FyJtCEqrqG3inRziDws346SYLsxOQ6HmX+4BkIsQh1R8U3XNa+EMmdMt38lMA==}
|
||||||
|
peerDependencies:
|
||||||
|
svelte: '>=3 <5'
|
||||||
|
|
||||||
'@nodelib/fs.scandir@2.1.5':
|
'@nodelib/fs.scandir@2.1.5':
|
||||||
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
@@ -587,6 +619,9 @@ packages:
|
|||||||
svelte: ^5.0.0
|
svelte: ^5.0.0
|
||||||
vite: ^6.0.0
|
vite: ^6.0.0
|
||||||
|
|
||||||
|
'@swc/helpers@0.5.15':
|
||||||
|
resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==}
|
||||||
|
|
||||||
'@types/cookie@0.6.0':
|
'@types/cookie@0.6.0':
|
||||||
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
|
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
|
||||||
|
|
||||||
@@ -719,6 +754,16 @@ packages:
|
|||||||
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
|
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
bits-ui@0.21.16:
|
||||||
|
resolution: {integrity: sha512-XFZ7/bK7j/K+5iktxX/ZpmoFHjYjpPzP5EOO/4bWiaFg5TG1iMcfjDhlBTQnJxD6BoVoHuqeZPHZvaTgF4Iv3Q==}
|
||||||
|
peerDependencies:
|
||||||
|
svelte: ^4.0.0 || ^5.0.0-next.118
|
||||||
|
|
||||||
|
bits-ui@0.22.0:
|
||||||
|
resolution: {integrity: sha512-r7Fw1HNgA4YxZBRcozl7oP0bheQ8EHh+kfMBZJgyFISix8t4p/nqDcHLmBgIiJ3T5XjYnJRorYDjIWaCfhb5fw==}
|
||||||
|
peerDependencies:
|
||||||
|
svelte: ^4.0.0 || ^5.0.0
|
||||||
|
|
||||||
boxen@8.0.1:
|
boxen@8.0.1:
|
||||||
resolution: {integrity: sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==}
|
resolution: {integrity: sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -990,6 +1035,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==}
|
resolution: {integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
focus-trap@7.6.4:
|
||||||
|
resolution: {integrity: sha512-xx560wGBk7seZ6y933idtjJQc1l+ck+pI3sKvhKozdBV1dRZoKhkW5xoCaFv9tQiX5RH1xfSxjuNu6g+lmN/gw==}
|
||||||
|
|
||||||
foreground-child@3.3.1:
|
foreground-child@3.3.1:
|
||||||
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
|
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
@@ -1362,6 +1410,11 @@ packages:
|
|||||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
nanoid@5.1.3:
|
||||||
|
resolution: {integrity: sha512-zAbEOEr7u2CbxwoMRlz/pNSpRP0FdAU4pRaYunCdEezWohXFs+a0Xw7RfkKaezMsmSM1vttcLthJtwRnVtOfHQ==}
|
||||||
|
engines: {node: ^18 || >=20}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
neotraverse@0.6.18:
|
neotraverse@0.6.18:
|
||||||
resolution: {integrity: sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==}
|
resolution: {integrity: sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
@@ -1814,6 +1867,18 @@ packages:
|
|||||||
resolution: {integrity: sha512-dxHyh3USJyayafSt5I5QD7KuoCM5ZGdIOtLQiKHEro7tymdh0jMcNkiSBVHW+LOA2jEqZEHhyfwN6/pCjx0Fug==}
|
resolution: {integrity: sha512-dxHyh3USJyayafSt5I5QD7KuoCM5ZGdIOtLQiKHEro7tymdh0jMcNkiSBVHW+LOA2jEqZEHhyfwN6/pCjx0Fug==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
tabbable@6.2.0:
|
||||||
|
resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==}
|
||||||
|
|
||||||
|
tailwind-merge@3.0.2:
|
||||||
|
resolution: {integrity: sha512-l7z+OYZ7mu3DTqrL88RiKrKIqO3NcpEO8V/Od04bNpvk0kiIFndGEoqfuzvj4yuhRkHKjRkII2z+KS2HfPcSxw==}
|
||||||
|
|
||||||
|
tailwind-variants@1.0.0:
|
||||||
|
resolution: {integrity: sha512-2WSbv4ulEEyuBKomOunut65D8UZwxrHoRfYnxGcQNnHqlSCp2+B7Yz2W+yrNDrxRodOXtGD/1oCcKGNBnUqMqA==}
|
||||||
|
engines: {node: '>=16.x', pnpm: '>=7.x'}
|
||||||
|
peerDependencies:
|
||||||
|
tailwindcss: '*'
|
||||||
|
|
||||||
tailwindcss@3.4.17:
|
tailwindcss@3.4.17:
|
||||||
resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==}
|
resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
@@ -1981,6 +2046,11 @@ packages:
|
|||||||
util-deprecate@1.0.2:
|
util-deprecate@1.0.2:
|
||||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||||
|
|
||||||
|
vaul-svelte@0.3.2:
|
||||||
|
resolution: {integrity: sha512-X4OGWttSTVUl417qGDsSFgOvIx24DoiMRY/jaP9z0v9FL8LQQJ0RQ1ZM0QpdyQPRlNd24ewjNQHh5EgYDtfNpw==}
|
||||||
|
peerDependencies:
|
||||||
|
svelte: ^4.0.0 || ^5.0.0-next.1
|
||||||
|
|
||||||
vfile-location@5.0.3:
|
vfile-location@5.0.3:
|
||||||
resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==}
|
resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==}
|
||||||
|
|
||||||
@@ -2480,6 +2550,17 @@ snapshots:
|
|||||||
'@esbuild/win32-x64@0.25.0':
|
'@esbuild/win32-x64@0.25.0':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@floating-ui/core@1.6.9':
|
||||||
|
dependencies:
|
||||||
|
'@floating-ui/utils': 0.2.9
|
||||||
|
|
||||||
|
'@floating-ui/dom@1.6.13':
|
||||||
|
dependencies:
|
||||||
|
'@floating-ui/core': 1.6.9
|
||||||
|
'@floating-ui/utils': 0.2.9
|
||||||
|
|
||||||
|
'@floating-ui/utils@0.2.9': {}
|
||||||
|
|
||||||
'@img/sharp-darwin-arm64@0.33.5':
|
'@img/sharp-darwin-arm64@0.33.5':
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@img/sharp-libvips-darwin-arm64': 1.0.4
|
'@img/sharp-libvips-darwin-arm64': 1.0.4
|
||||||
@@ -2555,6 +2636,10 @@ snapshots:
|
|||||||
'@img/sharp-win32-x64@0.33.5':
|
'@img/sharp-win32-x64@0.33.5':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@internationalized/date@3.7.0':
|
||||||
|
dependencies:
|
||||||
|
'@swc/helpers': 0.5.15
|
||||||
|
|
||||||
'@isaacs/cliui@8.0.2':
|
'@isaacs/cliui@8.0.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
string-width: 5.1.2
|
string-width: 5.1.2
|
||||||
@@ -2581,6 +2666,16 @@ snapshots:
|
|||||||
'@jridgewell/resolve-uri': 3.1.2
|
'@jridgewell/resolve-uri': 3.1.2
|
||||||
'@jridgewell/sourcemap-codec': 1.5.0
|
'@jridgewell/sourcemap-codec': 1.5.0
|
||||||
|
|
||||||
|
'@melt-ui/svelte@0.76.2(svelte@5.22.6)':
|
||||||
|
dependencies:
|
||||||
|
'@floating-ui/core': 1.6.9
|
||||||
|
'@floating-ui/dom': 1.6.13
|
||||||
|
'@internationalized/date': 3.7.0
|
||||||
|
dequal: 2.0.3
|
||||||
|
focus-trap: 7.6.4
|
||||||
|
nanoid: 5.1.3
|
||||||
|
svelte: 5.22.6
|
||||||
|
|
||||||
'@nodelib/fs.scandir@2.1.5':
|
'@nodelib/fs.scandir@2.1.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nodelib/fs.stat': 2.0.5
|
'@nodelib/fs.stat': 2.0.5
|
||||||
@@ -2724,6 +2819,10 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
'@swc/helpers@0.5.15':
|
||||||
|
dependencies:
|
||||||
|
tslib: 2.8.1
|
||||||
|
|
||||||
'@types/cookie@0.6.0': {}
|
'@types/cookie@0.6.0': {}
|
||||||
|
|
||||||
'@types/debug@4.1.12':
|
'@types/debug@4.1.12':
|
||||||
@@ -2959,6 +3058,20 @@ snapshots:
|
|||||||
|
|
||||||
binary-extensions@2.3.0: {}
|
binary-extensions@2.3.0: {}
|
||||||
|
|
||||||
|
bits-ui@0.21.16(svelte@5.22.6):
|
||||||
|
dependencies:
|
||||||
|
'@internationalized/date': 3.7.0
|
||||||
|
'@melt-ui/svelte': 0.76.2(svelte@5.22.6)
|
||||||
|
nanoid: 5.1.3
|
||||||
|
svelte: 5.22.6
|
||||||
|
|
||||||
|
bits-ui@0.22.0(svelte@5.22.6):
|
||||||
|
dependencies:
|
||||||
|
'@internationalized/date': 3.7.0
|
||||||
|
'@melt-ui/svelte': 0.76.2(svelte@5.22.6)
|
||||||
|
nanoid: 5.1.3
|
||||||
|
svelte: 5.22.6
|
||||||
|
|
||||||
boxen@8.0.1:
|
boxen@8.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
ansi-align: 3.0.1
|
ansi-align: 3.0.1
|
||||||
@@ -3217,6 +3330,10 @@ snapshots:
|
|||||||
|
|
||||||
flattie@1.1.1: {}
|
flattie@1.1.1: {}
|
||||||
|
|
||||||
|
focus-trap@7.6.4:
|
||||||
|
dependencies:
|
||||||
|
tabbable: 6.2.0
|
||||||
|
|
||||||
foreground-child@3.3.1:
|
foreground-child@3.3.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
cross-spawn: 7.0.6
|
cross-spawn: 7.0.6
|
||||||
@@ -3810,6 +3927,8 @@ snapshots:
|
|||||||
|
|
||||||
nanoid@3.3.9: {}
|
nanoid@3.3.9: {}
|
||||||
|
|
||||||
|
nanoid@5.1.3: {}
|
||||||
|
|
||||||
neotraverse@0.6.18: {}
|
neotraverse@0.6.18: {}
|
||||||
|
|
||||||
nlcst-to-string@4.0.0:
|
nlcst-to-string@4.0.0:
|
||||||
@@ -4297,6 +4416,15 @@ snapshots:
|
|||||||
magic-string: 0.30.17
|
magic-string: 0.30.17
|
||||||
zimmerframe: 1.1.2
|
zimmerframe: 1.1.2
|
||||||
|
|
||||||
|
tabbable@6.2.0: {}
|
||||||
|
|
||||||
|
tailwind-merge@3.0.2: {}
|
||||||
|
|
||||||
|
tailwind-variants@1.0.0(tailwindcss@3.4.17):
|
||||||
|
dependencies:
|
||||||
|
tailwind-merge: 3.0.2
|
||||||
|
tailwindcss: 3.4.17
|
||||||
|
|
||||||
tailwindcss@3.4.17:
|
tailwindcss@3.4.17:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@alloc/quick-lru': 5.2.0
|
'@alloc/quick-lru': 5.2.0
|
||||||
@@ -4442,6 +4570,11 @@ snapshots:
|
|||||||
|
|
||||||
util-deprecate@1.0.2: {}
|
util-deprecate@1.0.2: {}
|
||||||
|
|
||||||
|
vaul-svelte@0.3.2(svelte@5.22.6):
|
||||||
|
dependencies:
|
||||||
|
bits-ui: 0.21.16(svelte@5.22.6)
|
||||||
|
svelte: 5.22.6
|
||||||
|
|
||||||
vfile-location@5.0.3:
|
vfile-location@5.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/unist': 3.0.3
|
'@types/unist': 3.0.3
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import type { TrackerData } from "../utils/types";
|
import type { TrackerData } from "../utils/types";
|
||||||
import Drag from "./Drag.svelte";
|
import Drag from "./Drag.svelte";
|
||||||
import Slider from "./Slider.svelte";
|
import Slider from "./Slider.svelte";
|
||||||
|
import Settings from "./Settings.svelte";
|
||||||
|
|
||||||
let ws: WebSocket | null = $state(null);
|
let ws: WebSocket | null = $state(null);
|
||||||
let image: HTMLImageElement | null = $state(null);
|
let image: HTMLImageElement | null = $state(null);
|
||||||
@@ -65,7 +66,9 @@
|
|||||||
|
|
||||||
<svelte:window onresize={resize} />
|
<svelte:window onresize={resize} />
|
||||||
<div class="flex h-screen w-screen items-center justify-center">
|
<div class="flex h-screen w-screen items-center justify-center">
|
||||||
<div class="mr-auto w-20"></div>
|
<div class="mr-auto w-20">
|
||||||
|
<Settings />
|
||||||
|
</div>
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<img
|
<img
|
||||||
src="/background_image?342038402"
|
src="/background_image?342038402"
|
||||||
|
|||||||
48
frontend/src/components/Settings.svelte
Normal file
48
frontend/src/components/Settings.svelte
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import * as Drawer from "$lib/components/ui/drawer/index.js";
|
||||||
|
import { Button } from "$lib/components/ui/button/index.js";
|
||||||
|
import TrackerSetting from "./TrackerSetting.svelte";
|
||||||
|
|
||||||
|
const addTracker = async () => {
|
||||||
|
const response = await fetch("/tracker", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
id: 4,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(response);
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteTracker = async () => {
|
||||||
|
const response = await fetch("/tracker", {
|
||||||
|
method: "DELETE",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
id: 4,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
console.log(response);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Drawer.Root>
|
||||||
|
<Drawer.Trigger asChild let:builder>
|
||||||
|
<Button builders={[builder]} variant="outline">Settings</Button>
|
||||||
|
</Drawer.Trigger>
|
||||||
|
<Drawer.Content>
|
||||||
|
<Drawer.Header>
|
||||||
|
<Drawer.Title>Are you sure absolutely sure?</Drawer.Title>
|
||||||
|
<Drawer.Description>This action cannot be undone.</Drawer.Description>
|
||||||
|
</Drawer.Header>
|
||||||
|
<div class="flex items-center justify-evenly">
|
||||||
|
<TrackerSetting action={addTracker} text="Add Tracker" />
|
||||||
|
<TrackerSetting action={deleteTracker} text="Delete Tracker" />
|
||||||
|
</div>
|
||||||
|
</Drawer.Content>
|
||||||
|
</Drawer.Root>
|
||||||
@@ -20,15 +20,19 @@
|
|||||||
|
|
||||||
let arena_state: "full_arena" | "scene_only" = $state("scene_only");
|
let arena_state: "full_arena" | "scene_only" = $state("scene_only");
|
||||||
|
|
||||||
|
let tracker = trackers.find((ball) => {
|
||||||
|
ball.id === selected;
|
||||||
|
});
|
||||||
|
|
||||||
const onchange = () => {
|
const onchange = () => {
|
||||||
const x_send = trackers[selected].x / width;
|
const x_send = tracker!.x / width;
|
||||||
const y_send = trackers[selected].y / height;
|
const y_send = tracker!.y / height;
|
||||||
ws?.send(
|
ws?.send(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
id: trackers[selected].id,
|
id: tracker!.id,
|
||||||
x: x_send,
|
x: x_send,
|
||||||
y: y_send,
|
y: y_send,
|
||||||
z: trackers[selected].z,
|
z: tracker!.z,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -52,7 +56,7 @@
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
let z_viz = $derived(trackers[selected].z.toFixed(2));
|
let z_viz = $derived(tracker?.z.toFixed(2));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="slider-container ml-auto">
|
<div class="slider-container ml-auto">
|
||||||
@@ -64,7 +68,6 @@
|
|||||||
max="4"
|
max="4"
|
||||||
step="0.01"
|
step="0.01"
|
||||||
oninput={onchange}
|
oninput={onchange}
|
||||||
bind:value={trackers[selected].z}
|
|
||||||
/>
|
/>
|
||||||
<output for="z">{z_viz} m</output>
|
<output for="z">{z_viz} m</output>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
17
frontend/src/components/TrackerSetting.svelte
Normal file
17
frontend/src/components/TrackerSetting.svelte
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import Button from "./ui/button/button.svelte";
|
||||||
|
import Input from "./ui/input/input.svelte";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
text: string;
|
||||||
|
action: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
let { action, text }: Props = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2>{text}</h2>
|
||||||
|
<Input placeholder={"1"} type="tel" />
|
||||||
|
<Button onclick={action}>Submit</Button>
|
||||||
|
</div>
|
||||||
25
frontend/src/components/ui/button/button.svelte
Normal file
25
frontend/src/components/ui/button/button.svelte
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Button as ButtonPrimitive } from "bits-ui";
|
||||||
|
import { type Events, type Props, buttonVariants } from "./index.js";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
type $$Props = Props;
|
||||||
|
type $$Events = Events;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let variant: $$Props["variant"] = "default";
|
||||||
|
export let size: $$Props["size"] = "default";
|
||||||
|
export let builders: $$Props["builders"] = [];
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ButtonPrimitive.Root
|
||||||
|
{builders}
|
||||||
|
class={cn(buttonVariants({ variant, size, className }))}
|
||||||
|
type="button"
|
||||||
|
{...$$restProps}
|
||||||
|
on:click
|
||||||
|
on:keydown
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</ButtonPrimitive.Root>
|
||||||
49
frontend/src/components/ui/button/index.ts
Normal file
49
frontend/src/components/ui/button/index.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import { type VariantProps, tv } from "tailwind-variants";
|
||||||
|
import type { Button as ButtonPrimitive } from "bits-ui";
|
||||||
|
import Root from "./button.svelte";
|
||||||
|
|
||||||
|
const buttonVariants = tv({
|
||||||
|
base: "ring-offset-background focus-visible:ring-ring inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
||||||
|
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
||||||
|
outline:
|
||||||
|
"border-input bg-background hover:bg-accent hover:text-accent-foreground border",
|
||||||
|
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||||
|
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||||
|
link: "text-primary underline-offset-4 hover:underline",
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
default: "h-10 px-4 py-2",
|
||||||
|
sm: "h-9 rounded-md px-3",
|
||||||
|
lg: "h-11 rounded-md px-8",
|
||||||
|
icon: "h-10 w-10",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: "default",
|
||||||
|
size: "default",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
type Variant = VariantProps<typeof buttonVariants>["variant"];
|
||||||
|
type Size = VariantProps<typeof buttonVariants>["size"];
|
||||||
|
|
||||||
|
type Props = ButtonPrimitive.Props & {
|
||||||
|
variant?: Variant;
|
||||||
|
size?: Size;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Events = ButtonPrimitive.Events;
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
type Props,
|
||||||
|
type Events,
|
||||||
|
//
|
||||||
|
Root as Button,
|
||||||
|
type Props as ButtonProps,
|
||||||
|
type Events as ButtonEvents,
|
||||||
|
buttonVariants,
|
||||||
|
};
|
||||||
24
frontend/src/components/ui/drawer/drawer-content.svelte
Normal file
24
frontend/src/components/ui/drawer/drawer-content.svelte
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Drawer as DrawerPrimitive } from "vaul-svelte";
|
||||||
|
import DrawerOverlay from "./drawer-overlay.svelte";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
type $$Props = DrawerPrimitive.ContentProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DrawerPrimitive.Portal>
|
||||||
|
<DrawerOverlay />
|
||||||
|
<DrawerPrimitive.Content
|
||||||
|
class={cn(
|
||||||
|
"bg-background fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<div class="bg-muted mx-auto mt-4 h-2 w-[100px] rounded-full"></div>
|
||||||
|
<slot />
|
||||||
|
</DrawerPrimitive.Content>
|
||||||
|
</DrawerPrimitive.Portal>
|
||||||
18
frontend/src/components/ui/drawer/drawer-description.svelte
Normal file
18
frontend/src/components/ui/drawer/drawer-description.svelte
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Drawer as DrawerPrimitive } from "vaul-svelte";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
type $$Props = DrawerPrimitive.DescriptionProps;
|
||||||
|
|
||||||
|
export let el: $$Props["el"] = undefined;
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DrawerPrimitive.Description
|
||||||
|
bind:el
|
||||||
|
class={cn("text-muted-foreground text-sm", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</DrawerPrimitive.Description>
|
||||||
16
frontend/src/components/ui/drawer/drawer-footer.svelte
Normal file
16
frontend/src/components/ui/drawer/drawer-footer.svelte
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
type $$Props = HTMLAttributes<HTMLDivElement> & {
|
||||||
|
el?: HTMLDivElement;
|
||||||
|
};
|
||||||
|
|
||||||
|
export let el: $$Props["el"] = undefined;
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div bind:this={el} class={cn("mt-auto flex flex-col gap-2 p-4", className)} {...$$restProps}>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
19
frontend/src/components/ui/drawer/drawer-header.svelte
Normal file
19
frontend/src/components/ui/drawer/drawer-header.svelte
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
type $$Props = HTMLAttributes<HTMLDivElement> & {
|
||||||
|
el?: HTMLDivElement;
|
||||||
|
};
|
||||||
|
export let el: $$Props["el"] = undefined;
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
bind:this={el}
|
||||||
|
class={cn("grid gap-1.5 p-4 text-center sm:text-left", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
12
frontend/src/components/ui/drawer/drawer-nested.svelte
Normal file
12
frontend/src/components/ui/drawer/drawer-nested.svelte
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Drawer as DrawerPrimitive } from "vaul-svelte";
|
||||||
|
|
||||||
|
type $$Props = DrawerPrimitive.Props;
|
||||||
|
export let shouldScaleBackground: $$Props["shouldScaleBackground"] = true;
|
||||||
|
export let open: $$Props["open"] = false;
|
||||||
|
export let activeSnapPoint: $$Props["activeSnapPoint"] = undefined;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DrawerPrimitive.NestedRoot {shouldScaleBackground} bind:open bind:activeSnapPoint {...$$restProps}>
|
||||||
|
<slot />
|
||||||
|
</DrawerPrimitive.NestedRoot>
|
||||||
18
frontend/src/components/ui/drawer/drawer-overlay.svelte
Normal file
18
frontend/src/components/ui/drawer/drawer-overlay.svelte
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Drawer as DrawerPrimitive } from "vaul-svelte";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
type $$Props = DrawerPrimitive.OverlayProps;
|
||||||
|
|
||||||
|
export let el: $$Props["el"] = undefined;
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DrawerPrimitive.Overlay
|
||||||
|
bind:el
|
||||||
|
class={cn("fixed inset-0 z-50 bg-black/80", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</DrawerPrimitive.Overlay>
|
||||||
18
frontend/src/components/ui/drawer/drawer-title.svelte
Normal file
18
frontend/src/components/ui/drawer/drawer-title.svelte
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Drawer as DrawerPrimitive } from "vaul-svelte";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
type $$Props = DrawerPrimitive.TitleProps;
|
||||||
|
|
||||||
|
export let el: $$Props["el"] = undefined;
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DrawerPrimitive.Title
|
||||||
|
bind:el
|
||||||
|
class={cn("text-lg font-semibold leading-none tracking-tight", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</DrawerPrimitive.Title>
|
||||||
12
frontend/src/components/ui/drawer/drawer.svelte
Normal file
12
frontend/src/components/ui/drawer/drawer.svelte
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Drawer as DrawerPrimitive } from "vaul-svelte";
|
||||||
|
|
||||||
|
type $$Props = DrawerPrimitive.Props;
|
||||||
|
export let shouldScaleBackground: $$Props["shouldScaleBackground"] = true;
|
||||||
|
export let open: $$Props["open"] = false;
|
||||||
|
export let activeSnapPoint: $$Props["activeSnapPoint"] = undefined;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DrawerPrimitive.Root {shouldScaleBackground} bind:open bind:activeSnapPoint {...$$restProps}>
|
||||||
|
<slot />
|
||||||
|
</DrawerPrimitive.Root>
|
||||||
41
frontend/src/components/ui/drawer/index.ts
Normal file
41
frontend/src/components/ui/drawer/index.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { Drawer as DrawerPrimitive } from "vaul-svelte";
|
||||||
|
|
||||||
|
import Root from "./drawer.svelte";
|
||||||
|
import Content from "./drawer-content.svelte";
|
||||||
|
import Description from "./drawer-description.svelte";
|
||||||
|
import Overlay from "./drawer-overlay.svelte";
|
||||||
|
import Footer from "./drawer-footer.svelte";
|
||||||
|
import Header from "./drawer-header.svelte";
|
||||||
|
import Title from "./drawer-title.svelte";
|
||||||
|
import NestedRoot from "./drawer-nested.svelte";
|
||||||
|
|
||||||
|
const Trigger = DrawerPrimitive.Trigger;
|
||||||
|
const Portal = DrawerPrimitive.Portal;
|
||||||
|
const Close = DrawerPrimitive.Close;
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
NestedRoot,
|
||||||
|
Content,
|
||||||
|
Description,
|
||||||
|
Overlay,
|
||||||
|
Footer,
|
||||||
|
Header,
|
||||||
|
Title,
|
||||||
|
Trigger,
|
||||||
|
Portal,
|
||||||
|
Close,
|
||||||
|
|
||||||
|
//
|
||||||
|
Root as Drawer,
|
||||||
|
NestedRoot as DrawerNestedRoot,
|
||||||
|
Content as DrawerContent,
|
||||||
|
Description as DrawerDescription,
|
||||||
|
Overlay as DrawerOverlay,
|
||||||
|
Footer as DrawerFooter,
|
||||||
|
Header as DrawerHeader,
|
||||||
|
Title as DrawerTitle,
|
||||||
|
Trigger as DrawerTrigger,
|
||||||
|
Portal as DrawerPortal,
|
||||||
|
Close as DrawerClose,
|
||||||
|
};
|
||||||
29
frontend/src/components/ui/input/index.ts
Normal file
29
frontend/src/components/ui/input/index.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import Root from "./input.svelte";
|
||||||
|
|
||||||
|
export type FormInputEvent<T extends Event = Event> = T & {
|
||||||
|
currentTarget: EventTarget & HTMLInputElement;
|
||||||
|
};
|
||||||
|
export type InputEvents = {
|
||||||
|
blur: FormInputEvent<FocusEvent>;
|
||||||
|
change: FormInputEvent<Event>;
|
||||||
|
click: FormInputEvent<MouseEvent>;
|
||||||
|
focus: FormInputEvent<FocusEvent>;
|
||||||
|
focusin: FormInputEvent<FocusEvent>;
|
||||||
|
focusout: FormInputEvent<FocusEvent>;
|
||||||
|
keydown: FormInputEvent<KeyboardEvent>;
|
||||||
|
keypress: FormInputEvent<KeyboardEvent>;
|
||||||
|
keyup: FormInputEvent<KeyboardEvent>;
|
||||||
|
mouseover: FormInputEvent<MouseEvent>;
|
||||||
|
mouseenter: FormInputEvent<MouseEvent>;
|
||||||
|
mouseleave: FormInputEvent<MouseEvent>;
|
||||||
|
mousemove: FormInputEvent<MouseEvent>;
|
||||||
|
paste: FormInputEvent<ClipboardEvent>;
|
||||||
|
input: FormInputEvent<InputEvent>;
|
||||||
|
wheel: FormInputEvent<WheelEvent>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
//
|
||||||
|
Root as Input,
|
||||||
|
};
|
||||||
42
frontend/src/components/ui/input/input.svelte
Normal file
42
frontend/src/components/ui/input/input.svelte
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { HTMLInputAttributes } from "svelte/elements";
|
||||||
|
import type { InputEvents } from "./index.js";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
type $$Props = HTMLInputAttributes;
|
||||||
|
type $$Events = InputEvents;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let value: $$Props["value"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
|
||||||
|
// Workaround for https://github.com/sveltejs/svelte/issues/9305
|
||||||
|
// Fixed in Svelte 5, but not backported to 4.x.
|
||||||
|
export let readonly: $$Props["readonly"] = undefined;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<input
|
||||||
|
class={cn(
|
||||||
|
"border-input bg-background ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring flex h-10 w-full rounded-md border px-3 py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
bind:value
|
||||||
|
{readonly}
|
||||||
|
on:blur
|
||||||
|
on:change
|
||||||
|
on:click
|
||||||
|
on:focus
|
||||||
|
on:focusin
|
||||||
|
on:focusout
|
||||||
|
on:keydown
|
||||||
|
on:keypress
|
||||||
|
on:keyup
|
||||||
|
on:mouseover
|
||||||
|
on:mouseenter
|
||||||
|
on:mouseleave
|
||||||
|
on:mousemove
|
||||||
|
on:paste
|
||||||
|
on:input
|
||||||
|
on:wheel|passive
|
||||||
|
{...$$restProps}
|
||||||
|
/>
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
import Container from "../components/Container.svelte";
|
import Container from "../components/Container.svelte";
|
||||||
|
import "$lib/styles/app.css";
|
||||||
---
|
---
|
||||||
|
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|||||||
78
frontend/src/styles/app.css
Normal file
78
frontend/src/styles/app.css
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
:root {
|
||||||
|
--background: 0 0% 100%;
|
||||||
|
--foreground: 222.2 84% 4.9%;
|
||||||
|
|
||||||
|
--muted: 210 40% 96.1%;
|
||||||
|
--muted-foreground: 215.4 16.3% 46.9%;
|
||||||
|
|
||||||
|
--popover: 0 0% 100%;
|
||||||
|
--popover-foreground: 222.2 84% 4.9%;
|
||||||
|
|
||||||
|
--card: 0 0% 100%;
|
||||||
|
--card-foreground: 222.2 84% 4.9%;
|
||||||
|
|
||||||
|
--border: 214.3 31.8% 91.4%;
|
||||||
|
--input: 214.3 31.8% 91.4%;
|
||||||
|
|
||||||
|
--primary: 222.2 47.4% 11.2%;
|
||||||
|
--primary-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--secondary: 210 40% 96.1%;
|
||||||
|
--secondary-foreground: 222.2 47.4% 11.2%;
|
||||||
|
|
||||||
|
--accent: 210 40% 96.1%;
|
||||||
|
--accent-foreground: 222.2 47.4% 11.2%;
|
||||||
|
|
||||||
|
--destructive: 0 72.2% 50.6%;
|
||||||
|
--destructive-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--ring: 222.2 84% 4.9%;
|
||||||
|
|
||||||
|
--radius: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark {
|
||||||
|
--background: 222.2 84% 4.9%;
|
||||||
|
--foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--muted: 217.2 32.6% 17.5%;
|
||||||
|
--muted-foreground: 215 20.2% 65.1%;
|
||||||
|
|
||||||
|
--popover: 222.2 84% 4.9%;
|
||||||
|
--popover-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--card: 222.2 84% 4.9%;
|
||||||
|
--card-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--border: 217.2 32.6% 17.5%;
|
||||||
|
--input: 217.2 32.6% 17.5%;
|
||||||
|
|
||||||
|
--primary: 210 40% 98%;
|
||||||
|
--primary-foreground: 222.2 47.4% 11.2%;
|
||||||
|
|
||||||
|
--secondary: 217.2 32.6% 17.5%;
|
||||||
|
--secondary-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--accent: 217.2 32.6% 17.5%;
|
||||||
|
--accent-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--destructive: 0 62.8% 30.6%;
|
||||||
|
--destructive-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--ring: 212.7 26.8% 83.9%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
* {
|
||||||
|
@apply border-border;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
@apply bg-background text-foreground;
|
||||||
|
}
|
||||||
|
}
|
||||||
62
frontend/src/utils.ts
Normal file
62
frontend/src/utils.ts
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
import { type ClassValue, clsx } from "clsx";
|
||||||
|
import { twMerge } from "tailwind-merge";
|
||||||
|
import { cubicOut } from "svelte/easing";
|
||||||
|
import type { TransitionConfig } from "svelte/transition";
|
||||||
|
|
||||||
|
export function cn(...inputs: ClassValue[]) {
|
||||||
|
return twMerge(clsx(inputs));
|
||||||
|
}
|
||||||
|
|
||||||
|
type FlyAndScaleParams = {
|
||||||
|
y?: number;
|
||||||
|
x?: number;
|
||||||
|
start?: number;
|
||||||
|
duration?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const flyAndScale = (
|
||||||
|
node: Element,
|
||||||
|
params: FlyAndScaleParams = { y: -8, x: 0, start: 0.95, duration: 150 }
|
||||||
|
): TransitionConfig => {
|
||||||
|
const style = getComputedStyle(node);
|
||||||
|
const transform = style.transform === "none" ? "" : style.transform;
|
||||||
|
|
||||||
|
const scaleConversion = (
|
||||||
|
valueA: number,
|
||||||
|
scaleA: [number, number],
|
||||||
|
scaleB: [number, number]
|
||||||
|
) => {
|
||||||
|
const [minA, maxA] = scaleA;
|
||||||
|
const [minB, maxB] = scaleB;
|
||||||
|
|
||||||
|
const percentage = (valueA - minA) / (maxA - minA);
|
||||||
|
const valueB = percentage * (maxB - minB) + minB;
|
||||||
|
|
||||||
|
return valueB;
|
||||||
|
};
|
||||||
|
|
||||||
|
const styleToString = (
|
||||||
|
style: Record<string, number | string | undefined>
|
||||||
|
): string => {
|
||||||
|
return Object.keys(style).reduce((str, key) => {
|
||||||
|
if (style[key] === undefined) return str;
|
||||||
|
return str + `${key}:${style[key]};`;
|
||||||
|
}, "");
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
duration: params.duration ?? 200,
|
||||||
|
delay: 0,
|
||||||
|
css: (t) => {
|
||||||
|
const y = scaleConversion(t, [0, 1], [params.y ?? 5, 0]);
|
||||||
|
const x = scaleConversion(t, [0, 1], [params.x ?? 0, 0]);
|
||||||
|
const scale = scaleConversion(t, [0, 1], [params.start ?? 0.95, 1]);
|
||||||
|
|
||||||
|
return styleToString({
|
||||||
|
transform: `${transform} translate3d(${x}px, ${y}px, 0) scale(${scale})`,
|
||||||
|
opacity: t
|
||||||
|
});
|
||||||
|
},
|
||||||
|
easing: cubicOut
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -1,8 +1,64 @@
|
|||||||
|
import { fontFamily } from "tailwindcss/defaultTheme";
|
||||||
|
|
||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
export default {
|
const config = {
|
||||||
content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"],
|
darkMode: ["class"],
|
||||||
|
content: ["./src/**/*.{html,js,svelte,ts}"],
|
||||||
|
safelist: ["dark"],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {},
|
container: {
|
||||||
|
center: true,
|
||||||
|
padding: "2rem",
|
||||||
|
screens: {
|
||||||
|
"2xl": "1400px"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
border: "hsl(var(--border) / <alpha-value>)",
|
||||||
|
input: "hsl(var(--input) / <alpha-value>)",
|
||||||
|
ring: "hsl(var(--ring) / <alpha-value>)",
|
||||||
|
background: "hsl(var(--background) / <alpha-value>)",
|
||||||
|
foreground: "hsl(var(--foreground) / <alpha-value>)",
|
||||||
|
primary: {
|
||||||
|
DEFAULT: "hsl(var(--primary) / <alpha-value>)",
|
||||||
|
foreground: "hsl(var(--primary-foreground) / <alpha-value>)"
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
DEFAULT: "hsl(var(--secondary) / <alpha-value>)",
|
||||||
|
foreground: "hsl(var(--secondary-foreground) / <alpha-value>)"
|
||||||
|
},
|
||||||
|
destructive: {
|
||||||
|
DEFAULT: "hsl(var(--destructive) / <alpha-value>)",
|
||||||
|
foreground: "hsl(var(--destructive-foreground) / <alpha-value>)"
|
||||||
|
},
|
||||||
|
muted: {
|
||||||
|
DEFAULT: "hsl(var(--muted) / <alpha-value>)",
|
||||||
|
foreground: "hsl(var(--muted-foreground) / <alpha-value>)"
|
||||||
|
},
|
||||||
|
accent: {
|
||||||
|
DEFAULT: "hsl(var(--accent) / <alpha-value>)",
|
||||||
|
foreground: "hsl(var(--accent-foreground) / <alpha-value>)"
|
||||||
|
},
|
||||||
|
popover: {
|
||||||
|
DEFAULT: "hsl(var(--popover) / <alpha-value>)",
|
||||||
|
foreground: "hsl(var(--popover-foreground) / <alpha-value>)"
|
||||||
|
},
|
||||||
|
card: {
|
||||||
|
DEFAULT: "hsl(var(--card) / <alpha-value>)",
|
||||||
|
foreground: "hsl(var(--card-foreground) / <alpha-value>)"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
borderRadius: {
|
||||||
|
lg: "var(--radius)",
|
||||||
|
md: "calc(var(--radius) - 2px)",
|
||||||
|
sm: "calc(var(--radius) - 4px)"
|
||||||
|
},
|
||||||
|
fontFamily: {
|
||||||
|
sans: [...fontFamily.sans]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
plugins: [],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
|
|||||||
Reference in New Issue
Block a user