span]:text-xs [&>span]:opacity-70",
+ className
+ )}
+ {...restProps}
+/>
diff --git a/packages/frontend/src/lib/components/ui/calendar/calendar-grid-body.svelte b/packages/frontend/src/lib/components/ui/calendar/calendar-grid-body.svelte
new file mode 100644
index 0000000..8cd86de
--- /dev/null
+++ b/packages/frontend/src/lib/components/ui/calendar/calendar-grid-body.svelte
@@ -0,0 +1,12 @@
+
+
+
diff --git a/packages/frontend/src/lib/components/ui/calendar/calendar-grid-head.svelte b/packages/frontend/src/lib/components/ui/calendar/calendar-grid-head.svelte
new file mode 100644
index 0000000..333edc4
--- /dev/null
+++ b/packages/frontend/src/lib/components/ui/calendar/calendar-grid-head.svelte
@@ -0,0 +1,12 @@
+
+
+
diff --git a/packages/frontend/src/lib/components/ui/calendar/calendar-grid-row.svelte b/packages/frontend/src/lib/components/ui/calendar/calendar-grid-row.svelte
new file mode 100644
index 0000000..9032236
--- /dev/null
+++ b/packages/frontend/src/lib/components/ui/calendar/calendar-grid-row.svelte
@@ -0,0 +1,12 @@
+
+
+
diff --git a/packages/frontend/src/lib/components/ui/calendar/calendar-grid.svelte b/packages/frontend/src/lib/components/ui/calendar/calendar-grid.svelte
new file mode 100644
index 0000000..e0c8627
--- /dev/null
+++ b/packages/frontend/src/lib/components/ui/calendar/calendar-grid.svelte
@@ -0,0 +1,16 @@
+
+
+
diff --git a/packages/frontend/src/lib/components/ui/calendar/calendar-head-cell.svelte b/packages/frontend/src/lib/components/ui/calendar/calendar-head-cell.svelte
new file mode 100644
index 0000000..131807e
--- /dev/null
+++ b/packages/frontend/src/lib/components/ui/calendar/calendar-head-cell.svelte
@@ -0,0 +1,19 @@
+
+
+
diff --git a/packages/frontend/src/lib/components/ui/calendar/calendar-header.svelte b/packages/frontend/src/lib/components/ui/calendar/calendar-header.svelte
new file mode 100644
index 0000000..c39e955
--- /dev/null
+++ b/packages/frontend/src/lib/components/ui/calendar/calendar-header.svelte
@@ -0,0 +1,19 @@
+
+
+
diff --git a/packages/frontend/src/lib/components/ui/calendar/calendar-heading.svelte b/packages/frontend/src/lib/components/ui/calendar/calendar-heading.svelte
new file mode 100644
index 0000000..a9b9810
--- /dev/null
+++ b/packages/frontend/src/lib/components/ui/calendar/calendar-heading.svelte
@@ -0,0 +1,16 @@
+
+
+
diff --git a/packages/frontend/src/lib/components/ui/calendar/calendar-month-select.svelte b/packages/frontend/src/lib/components/ui/calendar/calendar-month-select.svelte
new file mode 100644
index 0000000..664afab
--- /dev/null
+++ b/packages/frontend/src/lib/components/ui/calendar/calendar-month-select.svelte
@@ -0,0 +1,48 @@
+
+
+
+
+ {#snippet child({ props, monthItems, selectedMonthItem })}
+
+
+ {monthItems.find((item) => item.value === value)?.label || selectedMonthItem.label}
+
+
+ {/snippet}
+
+
diff --git a/packages/frontend/src/lib/components/ui/calendar/calendar-month.svelte b/packages/frontend/src/lib/components/ui/calendar/calendar-month.svelte
new file mode 100644
index 0000000..e747fae
--- /dev/null
+++ b/packages/frontend/src/lib/components/ui/calendar/calendar-month.svelte
@@ -0,0 +1,15 @@
+
+
+
+ {@render children?.()}
+
diff --git a/packages/frontend/src/lib/components/ui/calendar/calendar-months.svelte b/packages/frontend/src/lib/components/ui/calendar/calendar-months.svelte
new file mode 100644
index 0000000..f717a9d
--- /dev/null
+++ b/packages/frontend/src/lib/components/ui/calendar/calendar-months.svelte
@@ -0,0 +1,19 @@
+
+
+
+ {@render children?.()}
+
diff --git a/packages/frontend/src/lib/components/ui/calendar/calendar-nav.svelte b/packages/frontend/src/lib/components/ui/calendar/calendar-nav.svelte
new file mode 100644
index 0000000..27f33d7
--- /dev/null
+++ b/packages/frontend/src/lib/components/ui/calendar/calendar-nav.svelte
@@ -0,0 +1,19 @@
+
+
+
diff --git a/packages/frontend/src/lib/components/ui/calendar/calendar-next-button.svelte b/packages/frontend/src/lib/components/ui/calendar/calendar-next-button.svelte
new file mode 100644
index 0000000..5c5a78d
--- /dev/null
+++ b/packages/frontend/src/lib/components/ui/calendar/calendar-next-button.svelte
@@ -0,0 +1,31 @@
+
+
+{#snippet Fallback()}
+
+{/snippet}
+
+
diff --git a/packages/frontend/src/lib/components/ui/calendar/calendar-prev-button.svelte b/packages/frontend/src/lib/components/ui/calendar/calendar-prev-button.svelte
new file mode 100644
index 0000000..33cfd63
--- /dev/null
+++ b/packages/frontend/src/lib/components/ui/calendar/calendar-prev-button.svelte
@@ -0,0 +1,31 @@
+
+
+{#snippet Fallback()}
+
+{/snippet}
+
+
diff --git a/packages/frontend/src/lib/components/ui/calendar/calendar-year-select.svelte b/packages/frontend/src/lib/components/ui/calendar/calendar-year-select.svelte
new file mode 100644
index 0000000..33cc961
--- /dev/null
+++ b/packages/frontend/src/lib/components/ui/calendar/calendar-year-select.svelte
@@ -0,0 +1,47 @@
+
+
+
+
+ {#snippet child({ props, yearItems, selectedYearItem })}
+
+
+ {yearItems.find((item) => item.value === value)?.label || selectedYearItem.label}
+
+
+ {/snippet}
+
+
diff --git a/packages/frontend/src/lib/components/ui/calendar/calendar.svelte b/packages/frontend/src/lib/components/ui/calendar/calendar.svelte
new file mode 100644
index 0000000..29b6fff
--- /dev/null
+++ b/packages/frontend/src/lib/components/ui/calendar/calendar.svelte
@@ -0,0 +1,115 @@
+
+
+
+
+ {#snippet children({ months, weekdays })}
+
+
+
+
+
+ {#each months as month, monthIndex (month)}
+
+
+
+
+
+
+
+ {#each weekdays as weekday (weekday)}
+
+ {weekday.slice(0, 2)}
+
+ {/each}
+
+
+
+ {#each month.weeks as weekDates (weekDates)}
+
+ {#each weekDates as date (date)}
+
+ {#if day}
+ {@render day({
+ day: date,
+ outsideMonth: !isEqualMonth(date, month.value),
+ })}
+ {:else}
+
+ {/if}
+
+ {/each}
+
+ {/each}
+
+
+
+ {/each}
+
+ {/snippet}
+
diff --git a/packages/frontend/src/lib/components/ui/calendar/index.ts b/packages/frontend/src/lib/components/ui/calendar/index.ts
new file mode 100644
index 0000000..f3a16d2
--- /dev/null
+++ b/packages/frontend/src/lib/components/ui/calendar/index.ts
@@ -0,0 +1,40 @@
+import Root from "./calendar.svelte";
+import Cell from "./calendar-cell.svelte";
+import Day from "./calendar-day.svelte";
+import Grid from "./calendar-grid.svelte";
+import Header from "./calendar-header.svelte";
+import Months from "./calendar-months.svelte";
+import GridRow from "./calendar-grid-row.svelte";
+import Heading from "./calendar-heading.svelte";
+import GridBody from "./calendar-grid-body.svelte";
+import GridHead from "./calendar-grid-head.svelte";
+import HeadCell from "./calendar-head-cell.svelte";
+import NextButton from "./calendar-next-button.svelte";
+import PrevButton from "./calendar-prev-button.svelte";
+import MonthSelect from "./calendar-month-select.svelte";
+import YearSelect from "./calendar-year-select.svelte";
+import Month from "./calendar-month.svelte";
+import Nav from "./calendar-nav.svelte";
+import Caption from "./calendar-caption.svelte";
+
+export {
+ Day,
+ Cell,
+ Grid,
+ Header,
+ Months,
+ GridRow,
+ Heading,
+ GridBody,
+ GridHead,
+ HeadCell,
+ NextButton,
+ PrevButton,
+ Nav,
+ Month,
+ YearSelect,
+ MonthSelect,
+ Caption,
+ //
+ Root as Calendar,
+};
diff --git a/packages/frontend/src/lib/components/ui/date-picker/date-picker.svelte b/packages/frontend/src/lib/components/ui/date-picker/date-picker.svelte
new file mode 100644
index 0000000..91a2a96
--- /dev/null
+++ b/packages/frontend/src/lib/components/ui/date-picker/date-picker.svelte
@@ -0,0 +1,85 @@
+
+
+
+
+ {#snippet child({ props })}
+
+ {/snippet}
+
+
+
+ {#if showTime}
+
+ {
+ timeStr = (e.target as HTMLInputElement).value;
+ }}
+ class="w-full rounded-md border border-input bg-background px-3 py-1.5 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
+ />
+
+ {/if}
+
+
diff --git a/packages/frontend/src/lib/components/ui/date-picker/index.ts b/packages/frontend/src/lib/components/ui/date-picker/index.ts
new file mode 100644
index 0000000..8275128
--- /dev/null
+++ b/packages/frontend/src/lib/components/ui/date-picker/index.ts
@@ -0,0 +1 @@
+export { default as DatePicker } from "./date-picker.svelte";
diff --git a/packages/frontend/src/lib/components/ui/popover/index.ts b/packages/frontend/src/lib/components/ui/popover/index.ts
new file mode 100644
index 0000000..b79d12e
--- /dev/null
+++ b/packages/frontend/src/lib/components/ui/popover/index.ts
@@ -0,0 +1,19 @@
+import Root from "./popover.svelte";
+import Close from "./popover-close.svelte";
+import Content from "./popover-content.svelte";
+import Trigger from "./popover-trigger.svelte";
+import Portal from "./popover-portal.svelte";
+
+export {
+ Root,
+ Content,
+ Trigger,
+ Close,
+ Portal,
+ //
+ Root as Popover,
+ Content as PopoverContent,
+ Trigger as PopoverTrigger,
+ Close as PopoverClose,
+ Portal as PopoverPortal,
+};
diff --git a/packages/frontend/src/lib/components/ui/popover/popover-close.svelte b/packages/frontend/src/lib/components/ui/popover/popover-close.svelte
new file mode 100644
index 0000000..c360925
--- /dev/null
+++ b/packages/frontend/src/lib/components/ui/popover/popover-close.svelte
@@ -0,0 +1,7 @@
+
+
+
diff --git a/packages/frontend/src/lib/components/ui/popover/popover-content.svelte b/packages/frontend/src/lib/components/ui/popover/popover-content.svelte
new file mode 100644
index 0000000..3d79f3c
--- /dev/null
+++ b/packages/frontend/src/lib/components/ui/popover/popover-content.svelte
@@ -0,0 +1,31 @@
+
+
+
+
+
diff --git a/packages/frontend/src/lib/components/ui/popover/popover-portal.svelte b/packages/frontend/src/lib/components/ui/popover/popover-portal.svelte
new file mode 100644
index 0000000..dd8265f
--- /dev/null
+++ b/packages/frontend/src/lib/components/ui/popover/popover-portal.svelte
@@ -0,0 +1,7 @@
+
+
+
diff --git a/packages/frontend/src/lib/components/ui/popover/popover-trigger.svelte b/packages/frontend/src/lib/components/ui/popover/popover-trigger.svelte
new file mode 100644
index 0000000..586323c
--- /dev/null
+++ b/packages/frontend/src/lib/components/ui/popover/popover-trigger.svelte
@@ -0,0 +1,17 @@
+
+
+
diff --git a/packages/frontend/src/lib/components/ui/popover/popover.svelte b/packages/frontend/src/lib/components/ui/popover/popover.svelte
new file mode 100644
index 0000000..6b1aa5f
--- /dev/null
+++ b/packages/frontend/src/lib/components/ui/popover/popover.svelte
@@ -0,0 +1,7 @@
+
+
+
diff --git a/packages/frontend/src/routes/admin/articles/[id]/+page.svelte b/packages/frontend/src/routes/admin/articles/[id]/+page.svelte
index c78205e..5ab5d5d 100644
--- a/packages/frontend/src/routes/admin/articles/[id]/+page.svelte
+++ b/packages/frontend/src/routes/admin/articles/[id]/+page.svelte
@@ -12,6 +12,7 @@
import { FileDropZone, MEGABYTE } from "$lib/components/ui/file-drop-zone";
import { getAssetUrl } from "$lib/api";
import { Select, SelectContent, SelectItem, SelectTrigger } from "$lib/components/ui/select";
+ import { DatePicker } from "$lib/components/ui/date-picker";
const { data } = $props();
@@ -178,8 +179,8 @@
-
-
+
+
diff --git a/packages/frontend/src/routes/admin/articles/new/+page.svelte b/packages/frontend/src/routes/admin/articles/new/+page.svelte
index 41953a3..485309e 100644
--- a/packages/frontend/src/routes/admin/articles/new/+page.svelte
+++ b/packages/frontend/src/routes/admin/articles/new/+page.svelte
@@ -9,6 +9,7 @@
import { Label } from "$lib/components/ui/label";
import { Textarea } from "$lib/components/ui/textarea";
import { TagsInput } from "$lib/components/ui/tags-input";
+ import { DatePicker } from "$lib/components/ui/date-picker";
import { FileDropZone, MEGABYTE } from "$lib/components/ui/file-drop-zone";
let title = $state("");
@@ -154,8 +155,8 @@
-
-
+
+
diff --git a/packages/frontend/src/routes/admin/videos/[id]/+page.svelte b/packages/frontend/src/routes/admin/videos/[id]/+page.svelte
index 22d4ad5..eecf2f2 100644
--- a/packages/frontend/src/routes/admin/videos/[id]/+page.svelte
+++ b/packages/frontend/src/routes/admin/videos/[id]/+page.svelte
@@ -11,6 +11,7 @@
import { FileDropZone, MEGABYTE } from "$lib/components/ui/file-drop-zone";
import { getAssetUrl } from "$lib/api";
import { Select, SelectContent, SelectItem, SelectTrigger } from "$lib/components/ui/select";
+ import { DatePicker } from "$lib/components/ui/date-picker";
const { data } = $props();
@@ -124,7 +125,12 @@
{#if movieId}
-
{$_("admin.video_form.current_file", { values: { id: movieId } })}
+
{/if}
@@ -135,8 +141,8 @@
-
-
+
+
diff --git a/packages/frontend/src/routes/admin/videos/new/+page.svelte b/packages/frontend/src/routes/admin/videos/new/+page.svelte
index 2f34635..90a29da 100644
--- a/packages/frontend/src/routes/admin/videos/new/+page.svelte
+++ b/packages/frontend/src/routes/admin/videos/new/+page.svelte
@@ -8,6 +8,7 @@
import { Label } from "$lib/components/ui/label";
import { Textarea } from "$lib/components/ui/textarea";
import { TagsInput } from "$lib/components/ui/tags-input";
+ import { DatePicker } from "$lib/components/ui/date-picker";
import { FileDropZone, MEGABYTE } from "$lib/components/ui/file-drop-zone";
const { data } = $props();
@@ -151,8 +152,8 @@
-
-
+
+
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index d2b6800..87f624f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -186,8 +186,8 @@ importers:
specifier: ^3.11.0
version: 3.11.0
'@lucide/svelte':
- specifier: ^0.577.0
- version: 0.577.0(svelte@5.53.7)
+ specifier: ^0.561.0
+ version: 0.561.0(svelte@5.53.7)
'@sveltejs/adapter-node':
specifier: ^5.5.4
version: 5.5.4(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)))
@@ -1202,8 +1202,8 @@ packages:
'@jridgewell/trace-mapping@0.3.31':
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
- '@lucide/svelte@0.577.0':
- resolution: {integrity: sha512-0P6mkySd2MapIEgq08tADPmcN4DHndC/02PWwaLkOerXlx5Sv9aT4BxyXLIY+eccr0g/nEyCYiJesqS61YdBZQ==}
+ '@lucide/svelte@0.561.0':
+ resolution: {integrity: sha512-vofKV2UFVrKE6I4ewKJ3dfCXSV6iP6nWVmiM83MLjsU91EeJcEg7LoWUABLp/aOTxj1HQNbJD1f3g3L0JQgH9A==}
peerDependencies:
svelte: ^5
@@ -4138,7 +4138,7 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.5
- '@lucide/svelte@0.577.0(svelte@5.53.7)':
+ '@lucide/svelte@0.561.0(svelte@5.53.7)':
dependencies:
svelte: 5.53.7