diff --git a/webapp/package.json b/webapp/package.json
index ae69af2..18a6b81 100644
--- a/webapp/package.json
+++ b/webapp/package.json
@@ -22,7 +22,7 @@
"@tanstack/table-core": "^8.20.5",
"@types/eslint": "^9.6.1",
"autoprefixer": "^10.4.20",
- "bits-ui": "1.0.0-next.41",
+ "bits-ui": "1.0.0-next.45",
"clsx": "^2.1.1",
"eslint": "^9.14.0",
"eslint-config-prettier": "^9.1.0",
@@ -30,12 +30,14 @@
"globals": "^15.12.0",
"konva": "^9.3.16",
"lucide-svelte": "^0.454.0",
+ "mode-watcher": "^0.4.1",
"peaks.js": "^3.4.2",
"prettier": "^3.3.3",
"prettier-plugin-svelte": "^3.2.7",
"prettier-plugin-tailwindcss": "^0.6.8",
"svelte": "^5.1.10",
"svelte-check": "^4.0.5",
+ "svelte-sonner": "^0.3.28",
"tailwind-merge": "^2.5.4",
"tailwind-variants": "^0.2.1",
"tailwindcss": "^3.4.14",
diff --git a/webapp/pnpm-lock.yaml b/webapp/pnpm-lock.yaml
index a73b43e..c51875d 100644
--- a/webapp/pnpm-lock.yaml
+++ b/webapp/pnpm-lock.yaml
@@ -30,8 +30,8 @@ importers:
specifier: ^10.4.20
version: 10.4.20(postcss@8.4.47)
bits-ui:
- specifier: 1.0.0-next.41
- version: 1.0.0-next.41(svelte@5.1.10)
+ specifier: 1.0.0-next.45
+ version: 1.0.0-next.45(svelte@5.1.10)
clsx:
specifier: ^2.1.1
version: 2.1.1
@@ -53,6 +53,9 @@ importers:
lucide-svelte:
specifier: ^0.454.0
version: 0.454.0(svelte@5.1.10)
+ mode-watcher:
+ specifier: ^0.4.1
+ version: 0.4.1(svelte@5.1.10)
peaks.js:
specifier: ^3.4.2
version: 3.4.2(konva@9.3.16)(waveform-data@4.5.0)
@@ -71,6 +74,9 @@ importers:
svelte-check:
specifier: ^4.0.5
version: 4.0.5(svelte@5.1.10)(typescript@5.6.3)
+ svelte-sonner:
+ specifier: ^0.3.28
+ version: 0.3.28(svelte@5.1.10)
tailwind-merge:
specifier: ^2.5.4
version: 2.5.4
@@ -656,8 +662,8 @@ packages:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'}
- bits-ui@1.0.0-next.41:
- resolution: {integrity: sha512-5Ig/z4pksiJeKoHVCwwEj4vowEKD3P35qfUxmEGnY9kgq4054dJoVaGrWcMQhfx37wKGpEl6ezGa5dd0/61nDg==}
+ bits-ui@1.0.0-next.45:
+ resolution: {integrity: sha512-kt7gYIirEo2Rg1hMudcGEzSHogQTA22d/j1x8v+wIshsIqqcCN6DXJZpTojSCQWxny8IEa9CRnLwAzY4B2qf1Q==}
engines: {node: '>=18', pnpm: '>=8.7.0'}
peerDependencies:
svelte: ^5.0.0-next.1
@@ -1124,6 +1130,11 @@ packages:
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
engines: {node: '>=16 || 14 >=14.17'}
+ mode-watcher@0.4.1:
+ resolution: {integrity: sha512-bNC+1NXmwEFZtziCdZSgP7HFQTpqJPcQn9GwwJQGSf6SBF3neEPYV1uRwkYuAQwbsvsXIYtzaqgedDzJ7D1mhg==}
+ peerDependencies:
+ svelte: ^4.0.0 || ^5.0.0-next.1
+
mri@1.2.0:
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
engines: {node: '>=4'}
@@ -1510,6 +1521,11 @@ packages:
svelte:
optional: true
+ svelte-sonner@0.3.28:
+ resolution: {integrity: sha512-K3AmlySeFifF/cKgsYNv5uXqMVNln0NBAacOYgmkQStLa/UoU0LhfAACU6Gr+YYC8bOCHdVmFNoKuDbMEsppJg==}
+ peerDependencies:
+ svelte: ^3.0.0 || ^4.0.0 || ^5.0.0-next.1
+
svelte-toolbelt@0.4.6:
resolution: {integrity: sha512-k8OUvXBUifHZcAlWeY/HLg/4J0v5m2iOfOhn8fDmjt4AP8ZluaDh9eBFus9lFiLX6O5l6vKqI1dKL5wy7090NQ==}
engines: {node: '>=18', pnpm: '>=8.7.0'}
@@ -2216,7 +2232,7 @@ snapshots:
binary-extensions@2.3.0: {}
- bits-ui@1.0.0-next.41(svelte@5.1.10):
+ bits-ui@1.0.0-next.45(svelte@5.1.10):
dependencies:
'@floating-ui/core': 1.6.8
'@floating-ui/dom': 1.6.12
@@ -2685,6 +2701,10 @@ snapshots:
minipass@7.1.2: {}
+ mode-watcher@0.4.1(svelte@5.1.10):
+ dependencies:
+ svelte: 5.1.10
+
mri@1.2.0: {}
mrmime@2.0.0: {}
@@ -2989,6 +3009,10 @@ snapshots:
optionalDependencies:
svelte: 5.1.10
+ svelte-sonner@0.3.28(svelte@5.1.10):
+ dependencies:
+ svelte: 5.1.10
+
svelte-toolbelt@0.4.6(svelte@5.1.10):
dependencies:
clsx: 2.1.1
diff --git a/webapp/src/lib/components/time/SetTimeDialog.svelte b/webapp/src/lib/components/time/SetTimeDialog.svelte
new file mode 100644
index 0000000..77ffe76
--- /dev/null
+++ b/webapp/src/lib/components/time/SetTimeDialog.svelte
@@ -0,0 +1,51 @@
+
+
+
+ Set
+
+
+ Set time
+ Set the time immediately
+
+
+
+
+
+
+
diff --git a/webapp/src/lib/components/time/TimePanel.svelte b/webapp/src/lib/components/time/TimePanel.svelte
index f9e62b9..414322e 100644
--- a/webapp/src/lib/components/time/TimePanel.svelte
+++ b/webapp/src/lib/components/time/TimePanel.svelte
@@ -4,6 +4,7 @@
import Disc3 from 'lucide-svelte/icons/disc-3'
import { Button } from '@/ui/button'
import * as Card from '@/ui/card'
+ import SetTimeDialog from './SetTimeDialog.svelte'
@@ -20,6 +21,6 @@
-
+
diff --git a/webapp/src/lib/components/ui/dialog/dialog-content.svelte b/webapp/src/lib/components/ui/dialog/dialog-content.svelte
new file mode 100644
index 0000000..d0cd7a5
--- /dev/null
+++ b/webapp/src/lib/components/ui/dialog/dialog-content.svelte
@@ -0,0 +1,36 @@
+
+
+
+
+
+ {@render children?.()}
+
+
+ Close
+
+
+
diff --git a/webapp/src/lib/components/ui/dialog/dialog-description.svelte b/webapp/src/lib/components/ui/dialog/dialog-description.svelte
new file mode 100644
index 0000000..bc048e4
--- /dev/null
+++ b/webapp/src/lib/components/ui/dialog/dialog-description.svelte
@@ -0,0 +1,16 @@
+
+
+
diff --git a/webapp/src/lib/components/ui/dialog/dialog-footer.svelte b/webapp/src/lib/components/ui/dialog/dialog-footer.svelte
new file mode 100644
index 0000000..91ecaba
--- /dev/null
+++ b/webapp/src/lib/components/ui/dialog/dialog-footer.svelte
@@ -0,0 +1,20 @@
+
+
+
+ {@render children?.()}
+
diff --git a/webapp/src/lib/components/ui/dialog/dialog-header.svelte b/webapp/src/lib/components/ui/dialog/dialog-header.svelte
new file mode 100644
index 0000000..8d1abfc
--- /dev/null
+++ b/webapp/src/lib/components/ui/dialog/dialog-header.svelte
@@ -0,0 +1,20 @@
+
+
+
+ {@render children?.()}
+
diff --git a/webapp/src/lib/components/ui/dialog/dialog-overlay.svelte b/webapp/src/lib/components/ui/dialog/dialog-overlay.svelte
new file mode 100644
index 0000000..05c30ac
--- /dev/null
+++ b/webapp/src/lib/components/ui/dialog/dialog-overlay.svelte
@@ -0,0 +1,19 @@
+
+
+
diff --git a/webapp/src/lib/components/ui/dialog/dialog-title.svelte b/webapp/src/lib/components/ui/dialog/dialog-title.svelte
new file mode 100644
index 0000000..9cf592c
--- /dev/null
+++ b/webapp/src/lib/components/ui/dialog/dialog-title.svelte
@@ -0,0 +1,16 @@
+
+
+
diff --git a/webapp/src/lib/components/ui/dialog/index.ts b/webapp/src/lib/components/ui/dialog/index.ts
new file mode 100644
index 0000000..3286ab7
--- /dev/null
+++ b/webapp/src/lib/components/ui/dialog/index.ts
@@ -0,0 +1,37 @@
+import { Dialog as DialogPrimitive } from "bits-ui";
+
+import Title from "./dialog-title.svelte";
+import Footer from "./dialog-footer.svelte";
+import Header from "./dialog-header.svelte";
+import Overlay from "./dialog-overlay.svelte";
+import Content from "./dialog-content.svelte";
+import Description from "./dialog-description.svelte";
+
+const Root = DialogPrimitive.Root;
+const Trigger = DialogPrimitive.Trigger;
+const Close = DialogPrimitive.Close;
+const Portal = DialogPrimitive.Portal;
+
+export {
+ Root,
+ Title,
+ Portal,
+ Footer,
+ Header,
+ Trigger,
+ Overlay,
+ Content,
+ Description,
+ Close,
+ //
+ Root as Dialog,
+ Title as DialogTitle,
+ Portal as DialogPortal,
+ Footer as DialogFooter,
+ Header as DialogHeader,
+ Trigger as DialogTrigger,
+ Overlay as DialogOverlay,
+ Content as DialogContent,
+ Description as DialogDescription,
+ Close as DialogClose,
+};
diff --git a/webapp/src/lib/components/ui/input/index.ts b/webapp/src/lib/components/ui/input/index.ts
new file mode 100644
index 0000000..f47b6d3
--- /dev/null
+++ b/webapp/src/lib/components/ui/input/index.ts
@@ -0,0 +1,7 @@
+import Root from "./input.svelte";
+
+export {
+ Root,
+ //
+ Root as Input,
+};
diff --git a/webapp/src/lib/components/ui/input/input.svelte b/webapp/src/lib/components/ui/input/input.svelte
new file mode 100644
index 0000000..598829f
--- /dev/null
+++ b/webapp/src/lib/components/ui/input/input.svelte
@@ -0,0 +1,22 @@
+
+
+
diff --git a/webapp/src/lib/components/ui/sonner/index.ts b/webapp/src/lib/components/ui/sonner/index.ts
new file mode 100644
index 0000000..1ad9f4a
--- /dev/null
+++ b/webapp/src/lib/components/ui/sonner/index.ts
@@ -0,0 +1 @@
+export { default as Toaster } from "./sonner.svelte";
diff --git a/webapp/src/lib/components/ui/sonner/sonner.svelte b/webapp/src/lib/components/ui/sonner/sonner.svelte
new file mode 100644
index 0000000..8050e04
--- /dev/null
+++ b/webapp/src/lib/components/ui/sonner/sonner.svelte
@@ -0,0 +1,20 @@
+
+
+
diff --git a/webapp/src/lib/data/control.ts b/webapp/src/lib/data/control.ts
index 03e8c28..ba928fa 100644
--- a/webapp/src/lib/data/control.ts
+++ b/webapp/src/lib/data/control.ts
@@ -1,5 +1,6 @@
import { writable } from 'svelte/store'
import { get, post } from '$lib/data/api'
+import type { Timecode } from '$lib/data/types'
export const playing = writable(false)
export const paused = writable(false)
@@ -33,3 +34,7 @@ export const pause = async () => {
export const stop = async () => {
await post('/control/stop')
}
+
+export const setTime = async (t: Timecode) => {
+ await post('/control/set', t)
+}
diff --git a/webapp/src/routes/+layout.svelte b/webapp/src/routes/+layout.svelte
index ace082f..b376813 100644
--- a/webapp/src/routes/+layout.svelte
+++ b/webapp/src/routes/+layout.svelte
@@ -1,6 +1,8 @@
+
{@render children()}