feat: replace native date inputs with shadcn date picker
Add calendar + popover components and a custom DateTimePicker wrapper. Video forms use date-only; article forms include a time picker. Also add video player preview to the video edit form. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -15,7 +15,7 @@
|
|||||||
"@iconify-json/ri": "^1.2.10",
|
"@iconify-json/ri": "^1.2.10",
|
||||||
"@iconify/tailwind4": "^1.2.1",
|
"@iconify/tailwind4": "^1.2.1",
|
||||||
"@internationalized/date": "^3.11.0",
|
"@internationalized/date": "^3.11.0",
|
||||||
"@lucide/svelte": "^0.577.0",
|
"@lucide/svelte": "^0.561.0",
|
||||||
"@sveltejs/adapter-node": "^5.5.4",
|
"@sveltejs/adapter-node": "^5.5.4",
|
||||||
"@sveltejs/adapter-static": "^3.0.10",
|
"@sveltejs/adapter-static": "^3.0.10",
|
||||||
"@sveltejs/kit": "^2.53.4",
|
"@sveltejs/kit": "^2.53.4",
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { ComponentProps } from "svelte";
|
||||||
|
import type Calendar from "./calendar.svelte";
|
||||||
|
import CalendarMonthSelect from "./calendar-month-select.svelte";
|
||||||
|
import CalendarYearSelect from "./calendar-year-select.svelte";
|
||||||
|
import { DateFormatter, getLocalTimeZone, type DateValue } from "@internationalized/date";
|
||||||
|
|
||||||
|
let {
|
||||||
|
captionLayout,
|
||||||
|
months,
|
||||||
|
monthFormat,
|
||||||
|
years,
|
||||||
|
yearFormat,
|
||||||
|
month,
|
||||||
|
locale,
|
||||||
|
placeholder = $bindable(),
|
||||||
|
monthIndex = 0,
|
||||||
|
}: {
|
||||||
|
captionLayout: ComponentProps<typeof Calendar>["captionLayout"];
|
||||||
|
months: ComponentProps<typeof CalendarMonthSelect>["months"];
|
||||||
|
monthFormat: ComponentProps<typeof CalendarMonthSelect>["monthFormat"];
|
||||||
|
years: ComponentProps<typeof CalendarYearSelect>["years"];
|
||||||
|
yearFormat: ComponentProps<typeof CalendarYearSelect>["yearFormat"];
|
||||||
|
month: DateValue;
|
||||||
|
placeholder: DateValue | undefined;
|
||||||
|
locale: string;
|
||||||
|
monthIndex: number;
|
||||||
|
} = $props();
|
||||||
|
|
||||||
|
function formatYear(date: DateValue) {
|
||||||
|
const dateObj = date.toDate(getLocalTimeZone());
|
||||||
|
if (typeof yearFormat === "function") return yearFormat(dateObj.getFullYear());
|
||||||
|
return new DateFormatter(locale, { year: yearFormat }).format(dateObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatMonth(date: DateValue) {
|
||||||
|
const dateObj = date.toDate(getLocalTimeZone());
|
||||||
|
if (typeof monthFormat === "function") return monthFormat(dateObj.getMonth() + 1);
|
||||||
|
return new DateFormatter(locale, { month: monthFormat }).format(dateObj);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#snippet MonthSelect()}
|
||||||
|
<CalendarMonthSelect
|
||||||
|
{months}
|
||||||
|
{monthFormat}
|
||||||
|
value={month.month}
|
||||||
|
onchange={(e) => {
|
||||||
|
if (!placeholder) return;
|
||||||
|
const v = Number.parseInt(e.currentTarget.value);
|
||||||
|
const newPlaceholder = placeholder.set({ month: v });
|
||||||
|
placeholder = newPlaceholder.subtract({ months: monthIndex });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/snippet}
|
||||||
|
|
||||||
|
{#snippet YearSelect()}
|
||||||
|
<CalendarYearSelect {years} {yearFormat} value={month.year} />
|
||||||
|
{/snippet}
|
||||||
|
|
||||||
|
{#if captionLayout === "dropdown"}
|
||||||
|
{@render MonthSelect()}
|
||||||
|
{@render YearSelect()}
|
||||||
|
{:else if captionLayout === "dropdown-months"}
|
||||||
|
{@render MonthSelect()}
|
||||||
|
{#if placeholder}
|
||||||
|
{formatYear(placeholder)}
|
||||||
|
{/if}
|
||||||
|
{:else if captionLayout === "dropdown-years"}
|
||||||
|
{#if placeholder}
|
||||||
|
{formatMonth(placeholder)}
|
||||||
|
{/if}
|
||||||
|
{@render YearSelect()}
|
||||||
|
{:else}
|
||||||
|
{formatMonth(month)} {formatYear(month)}
|
||||||
|
{/if}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Calendar as CalendarPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
...restProps
|
||||||
|
}: CalendarPrimitive.CellProps = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<CalendarPrimitive.Cell
|
||||||
|
bind:ref
|
||||||
|
class={cn(
|
||||||
|
"relative size-(--cell-size) p-0 text-center text-sm focus-within:z-20 [&:first-child[data-selected]_[data-bits-day]]:rounded-s-md [&:last-child[data-selected]_[data-bits-day]]:rounded-e-md",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { buttonVariants } from "$lib/components/ui/button/index.js";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
import { Calendar as CalendarPrimitive } from "bits-ui";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
...restProps
|
||||||
|
}: CalendarPrimitive.DayProps = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<CalendarPrimitive.Day
|
||||||
|
bind:ref
|
||||||
|
class={cn(
|
||||||
|
buttonVariants({ variant: "ghost" }),
|
||||||
|
"flex size-(--cell-size) flex-col items-center justify-center gap-1 p-0 leading-none font-normal whitespace-nowrap select-none",
|
||||||
|
"[&[data-today]:not([data-selected])]:bg-accent [&[data-today]:not([data-selected])]:text-accent-foreground [&[data-today][data-disabled]]:text-muted-foreground",
|
||||||
|
"data-[selected]:bg-primary dark:data-[selected]:hover:bg-accent/50 data-[selected]:text-primary-foreground",
|
||||||
|
// Outside months
|
||||||
|
"[&[data-outside-month]:not([data-selected])]:text-muted-foreground [&[data-outside-month]:not([data-selected])]:hover:text-accent-foreground",
|
||||||
|
// Disabled
|
||||||
|
"data-[disabled]:text-muted-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
|
// Unavailable
|
||||||
|
"data-[unavailable]:text-muted-foreground data-[unavailable]:line-through",
|
||||||
|
// hover
|
||||||
|
"dark:hover:text-accent-foreground",
|
||||||
|
// focus
|
||||||
|
"focus:border-ring focus:ring-ring/50 focus:relative",
|
||||||
|
// inner spans
|
||||||
|
"[&>span]:text-xs [&>span]:opacity-70",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Calendar as CalendarPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
...restProps
|
||||||
|
}: CalendarPrimitive.GridBodyProps = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<CalendarPrimitive.GridBody bind:ref class={cn(className)} {...restProps} />
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Calendar as CalendarPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
...restProps
|
||||||
|
}: CalendarPrimitive.GridHeadProps = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<CalendarPrimitive.GridHead bind:ref class={cn(className)} {...restProps} />
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Calendar as CalendarPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
...restProps
|
||||||
|
}: CalendarPrimitive.GridRowProps = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<CalendarPrimitive.GridRow bind:ref class={cn("flex", className)} {...restProps} />
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Calendar as CalendarPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
...restProps
|
||||||
|
}: CalendarPrimitive.GridProps = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<CalendarPrimitive.Grid
|
||||||
|
bind:ref
|
||||||
|
class={cn("mt-4 flex w-full border-collapse flex-col gap-1", className)}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Calendar as CalendarPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
...restProps
|
||||||
|
}: CalendarPrimitive.HeadCellProps = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<CalendarPrimitive.HeadCell
|
||||||
|
bind:ref
|
||||||
|
class={cn(
|
||||||
|
"text-muted-foreground w-(--cell-size) rounded-md text-[0.8rem] font-normal",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Calendar as CalendarPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
...restProps
|
||||||
|
}: CalendarPrimitive.HeaderProps = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<CalendarPrimitive.Header
|
||||||
|
bind:ref
|
||||||
|
class={cn(
|
||||||
|
"flex h-(--cell-size) w-full items-center justify-center gap-1.5 text-sm font-medium",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Calendar as CalendarPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
...restProps
|
||||||
|
}: CalendarPrimitive.HeadingProps = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<CalendarPrimitive.Heading
|
||||||
|
bind:ref
|
||||||
|
class={cn("px-(--cell-size) text-sm font-medium", className)}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Calendar as CalendarPrimitive } from "bits-ui";
|
||||||
|
import { cn, type WithoutChildrenOrChild } from "$lib/utils.js";
|
||||||
|
import ChevronDownIcon from "@lucide/svelte/icons/chevron-down";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
value,
|
||||||
|
onchange,
|
||||||
|
...restProps
|
||||||
|
}: WithoutChildrenOrChild<CalendarPrimitive.MonthSelectProps> = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<span
|
||||||
|
class={cn(
|
||||||
|
"has-focus:border-ring border-input has-focus:ring-ring/50 relative flex rounded-md border shadow-xs has-focus:ring-[3px]",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<CalendarPrimitive.MonthSelect
|
||||||
|
bind:ref
|
||||||
|
class="dark:bg-popover dark:text-popover-foreground absolute inset-0 opacity-0"
|
||||||
|
{...restProps}
|
||||||
|
>
|
||||||
|
{#snippet child({ props, monthItems, selectedMonthItem })}
|
||||||
|
<select {...props} {value} {onchange}>
|
||||||
|
{#each monthItems as monthItem (monthItem.value)}
|
||||||
|
<option
|
||||||
|
value={monthItem.value}
|
||||||
|
selected={value !== undefined
|
||||||
|
? monthItem.value === value
|
||||||
|
: monthItem.value === selectedMonthItem.value}
|
||||||
|
>
|
||||||
|
{monthItem.label}
|
||||||
|
</option>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
<span
|
||||||
|
class="[&>svg]:text-muted-foreground flex h-8 items-center gap-1 rounded-md ps-2 pe-1 text-sm font-medium select-none [&>svg]:size-3.5"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
{monthItems.find((item) => item.value === value)?.label || selectedMonthItem.label}
|
||||||
|
<ChevronDownIcon class="size-4" />
|
||||||
|
</span>
|
||||||
|
{/snippet}
|
||||||
|
</CalendarPrimitive.MonthSelect>
|
||||||
|
</span>
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { type WithElementRef, cn } from "$lib/utils.js";
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
children,
|
||||||
|
...restProps
|
||||||
|
}: WithElementRef<HTMLAttributes<HTMLElement>> = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div {...restProps} bind:this={ref} class={cn("flex flex-col", className)}>
|
||||||
|
{@render children?.()}
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
import { cn, type WithElementRef } from "$lib/utils.js";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
children,
|
||||||
|
...restProps
|
||||||
|
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
bind:this={ref}
|
||||||
|
class={cn("relative flex flex-col gap-4 md:flex-row", className)}
|
||||||
|
{...restProps}
|
||||||
|
>
|
||||||
|
{@render children?.()}
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { cn, type WithElementRef } from "$lib/utils.js";
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
children,
|
||||||
|
...restProps
|
||||||
|
}: WithElementRef<HTMLAttributes<HTMLElement>> = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<nav
|
||||||
|
{...restProps}
|
||||||
|
bind:this={ref}
|
||||||
|
class={cn("absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1", className)}
|
||||||
|
>
|
||||||
|
{@render children?.()}
|
||||||
|
</nav>
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Calendar as CalendarPrimitive } from "bits-ui";
|
||||||
|
import ChevronRightIcon from "@lucide/svelte/icons/chevron-right";
|
||||||
|
import { buttonVariants, type ButtonVariant } from "$lib/components/ui/button/index.js";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
children,
|
||||||
|
variant = "ghost",
|
||||||
|
...restProps
|
||||||
|
}: CalendarPrimitive.NextButtonProps & {
|
||||||
|
variant?: ButtonVariant;
|
||||||
|
} = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#snippet Fallback()}
|
||||||
|
<ChevronRightIcon class="size-4" />
|
||||||
|
{/snippet}
|
||||||
|
|
||||||
|
<CalendarPrimitive.NextButton
|
||||||
|
bind:ref
|
||||||
|
class={cn(
|
||||||
|
buttonVariants({ variant }),
|
||||||
|
"size-(--cell-size) bg-transparent p-0 select-none disabled:opacity-50 rtl:rotate-180",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
children={children || Fallback}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Calendar as CalendarPrimitive } from "bits-ui";
|
||||||
|
import ChevronLeftIcon from "@lucide/svelte/icons/chevron-left";
|
||||||
|
import { buttonVariants, type ButtonVariant } from "$lib/components/ui/button/index.js";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
children,
|
||||||
|
variant = "ghost",
|
||||||
|
...restProps
|
||||||
|
}: CalendarPrimitive.PrevButtonProps & {
|
||||||
|
variant?: ButtonVariant;
|
||||||
|
} = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#snippet Fallback()}
|
||||||
|
<ChevronLeftIcon class="size-4" />
|
||||||
|
{/snippet}
|
||||||
|
|
||||||
|
<CalendarPrimitive.PrevButton
|
||||||
|
bind:ref
|
||||||
|
class={cn(
|
||||||
|
buttonVariants({ variant }),
|
||||||
|
"size-(--cell-size) bg-transparent p-0 select-none disabled:opacity-50 rtl:rotate-180",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
children={children || Fallback}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Calendar as CalendarPrimitive } from "bits-ui";
|
||||||
|
import { cn, type WithoutChildrenOrChild } from "$lib/utils.js";
|
||||||
|
import ChevronDownIcon from "@lucide/svelte/icons/chevron-down";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
value,
|
||||||
|
...restProps
|
||||||
|
}: WithoutChildrenOrChild<CalendarPrimitive.YearSelectProps> = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<span
|
||||||
|
class={cn(
|
||||||
|
"has-focus:border-ring border-input has-focus:ring-ring/50 relative flex rounded-md border shadow-xs has-focus:ring-[3px]",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<CalendarPrimitive.YearSelect
|
||||||
|
bind:ref
|
||||||
|
class="dark:bg-popover dark:text-popover-foreground absolute inset-0 opacity-0"
|
||||||
|
{...restProps}
|
||||||
|
>
|
||||||
|
{#snippet child({ props, yearItems, selectedYearItem })}
|
||||||
|
<select {...props} {value}>
|
||||||
|
{#each yearItems as yearItem (yearItem.value)}
|
||||||
|
<option
|
||||||
|
value={yearItem.value}
|
||||||
|
selected={value !== undefined
|
||||||
|
? yearItem.value === value
|
||||||
|
: yearItem.value === selectedYearItem.value}
|
||||||
|
>
|
||||||
|
{yearItem.label}
|
||||||
|
</option>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
<span
|
||||||
|
class="[&>svg]:text-muted-foreground flex h-8 items-center gap-1 rounded-md ps-2 pe-1 text-sm font-medium select-none [&>svg]:size-3.5"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
{yearItems.find((item) => item.value === value)?.label || selectedYearItem.label}
|
||||||
|
<ChevronDownIcon class="size-4" />
|
||||||
|
</span>
|
||||||
|
{/snippet}
|
||||||
|
</CalendarPrimitive.YearSelect>
|
||||||
|
</span>
|
||||||
115
packages/frontend/src/lib/components/ui/calendar/calendar.svelte
Normal file
115
packages/frontend/src/lib/components/ui/calendar/calendar.svelte
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Calendar as CalendarPrimitive } from "bits-ui";
|
||||||
|
import * as Calendar from "./index.js";
|
||||||
|
import { cn, type WithoutChildrenOrChild } from "$lib/utils.js";
|
||||||
|
import type { ButtonVariant } from "../button/button.svelte";
|
||||||
|
import { isEqualMonth, type DateValue } from "@internationalized/date";
|
||||||
|
import type { Snippet } from "svelte";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
value = $bindable(),
|
||||||
|
placeholder = $bindable(),
|
||||||
|
class: className,
|
||||||
|
weekdayFormat = "short",
|
||||||
|
buttonVariant = "ghost",
|
||||||
|
captionLayout = "label",
|
||||||
|
locale = "en-US",
|
||||||
|
months: monthsProp,
|
||||||
|
years,
|
||||||
|
monthFormat: monthFormatProp,
|
||||||
|
yearFormat = "numeric",
|
||||||
|
day,
|
||||||
|
disableDaysOutsideMonth = false,
|
||||||
|
...restProps
|
||||||
|
}: WithoutChildrenOrChild<CalendarPrimitive.RootProps> & {
|
||||||
|
buttonVariant?: ButtonVariant;
|
||||||
|
captionLayout?: "dropdown" | "dropdown-months" | "dropdown-years" | "label";
|
||||||
|
months?: CalendarPrimitive.MonthSelectProps["months"];
|
||||||
|
years?: CalendarPrimitive.YearSelectProps["years"];
|
||||||
|
monthFormat?: CalendarPrimitive.MonthSelectProps["monthFormat"];
|
||||||
|
yearFormat?: CalendarPrimitive.YearSelectProps["yearFormat"];
|
||||||
|
day?: Snippet<[{ day: DateValue; outsideMonth: boolean }]>;
|
||||||
|
} = $props();
|
||||||
|
|
||||||
|
const monthFormat = $derived.by(() => {
|
||||||
|
if (monthFormatProp) return monthFormatProp;
|
||||||
|
if (captionLayout.startsWith("dropdown")) return "short";
|
||||||
|
return "long";
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Discriminated Unions + Destructing (required for bindable) do not
|
||||||
|
get along, so we shut typescript up by casting `value` to `never`.
|
||||||
|
-->
|
||||||
|
<CalendarPrimitive.Root
|
||||||
|
bind:value={value as never}
|
||||||
|
bind:ref
|
||||||
|
bind:placeholder
|
||||||
|
{weekdayFormat}
|
||||||
|
{disableDaysOutsideMonth}
|
||||||
|
class={cn(
|
||||||
|
"bg-background group/calendar p-3 [--cell-size:--spacing(8)] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{locale}
|
||||||
|
{monthFormat}
|
||||||
|
{yearFormat}
|
||||||
|
{...restProps}
|
||||||
|
>
|
||||||
|
{#snippet children({ months, weekdays })}
|
||||||
|
<Calendar.Months>
|
||||||
|
<Calendar.Nav>
|
||||||
|
<Calendar.PrevButton variant={buttonVariant} />
|
||||||
|
<Calendar.NextButton variant={buttonVariant} />
|
||||||
|
</Calendar.Nav>
|
||||||
|
{#each months as month, monthIndex (month)}
|
||||||
|
<Calendar.Month>
|
||||||
|
<Calendar.Header>
|
||||||
|
<Calendar.Caption
|
||||||
|
{captionLayout}
|
||||||
|
months={monthsProp}
|
||||||
|
{monthFormat}
|
||||||
|
{years}
|
||||||
|
{yearFormat}
|
||||||
|
month={month.value}
|
||||||
|
bind:placeholder
|
||||||
|
{locale}
|
||||||
|
{monthIndex}
|
||||||
|
/>
|
||||||
|
</Calendar.Header>
|
||||||
|
<Calendar.Grid>
|
||||||
|
<Calendar.GridHead>
|
||||||
|
<Calendar.GridRow class="select-none">
|
||||||
|
{#each weekdays as weekday (weekday)}
|
||||||
|
<Calendar.HeadCell>
|
||||||
|
{weekday.slice(0, 2)}
|
||||||
|
</Calendar.HeadCell>
|
||||||
|
{/each}
|
||||||
|
</Calendar.GridRow>
|
||||||
|
</Calendar.GridHead>
|
||||||
|
<Calendar.GridBody>
|
||||||
|
{#each month.weeks as weekDates (weekDates)}
|
||||||
|
<Calendar.GridRow class="mt-2 w-full">
|
||||||
|
{#each weekDates as date (date)}
|
||||||
|
<Calendar.Cell {date} month={month.value}>
|
||||||
|
{#if day}
|
||||||
|
{@render day({
|
||||||
|
day: date,
|
||||||
|
outsideMonth: !isEqualMonth(date, month.value),
|
||||||
|
})}
|
||||||
|
{:else}
|
||||||
|
<Calendar.Day />
|
||||||
|
{/if}
|
||||||
|
</Calendar.Cell>
|
||||||
|
{/each}
|
||||||
|
</Calendar.GridRow>
|
||||||
|
{/each}
|
||||||
|
</Calendar.GridBody>
|
||||||
|
</Calendar.Grid>
|
||||||
|
</Calendar.Month>
|
||||||
|
{/each}
|
||||||
|
</Calendar.Months>
|
||||||
|
{/snippet}
|
||||||
|
</CalendarPrimitive.Root>
|
||||||
40
packages/frontend/src/lib/components/ui/calendar/index.ts
Normal file
40
packages/frontend/src/lib/components/ui/calendar/index.ts
Normal file
@@ -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,
|
||||||
|
};
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { parseDate, type DateValue } from "@internationalized/date";
|
||||||
|
import { Calendar } from "$lib/components/ui/calendar";
|
||||||
|
import * as Popover from "$lib/components/ui/popover";
|
||||||
|
import { Button } from "$lib/components/ui/button";
|
||||||
|
|
||||||
|
let {
|
||||||
|
value = $bindable(""),
|
||||||
|
placeholder = "Pick a date",
|
||||||
|
showTime = true,
|
||||||
|
}: {
|
||||||
|
value?: string;
|
||||||
|
placeholder?: string;
|
||||||
|
showTime?: boolean;
|
||||||
|
} = $props();
|
||||||
|
|
||||||
|
function toCalendarDate(v: string): DateValue | undefined {
|
||||||
|
if (!v) return undefined;
|
||||||
|
try {
|
||||||
|
return parseDate(v.slice(0, 10));
|
||||||
|
} catch {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function pad(n: number) {
|
||||||
|
return String(n).padStart(2, "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
let calendarDate = $state<DateValue | undefined>(toCalendarDate(value));
|
||||||
|
let timeStr = $state(value.length >= 16 ? value.slice(11, 16) : "00:00");
|
||||||
|
let open = $state(false);
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
if (calendarDate) {
|
||||||
|
const d = calendarDate;
|
||||||
|
const dateStr = `${d.year}-${pad(d.month)}-${pad(d.day)}`;
|
||||||
|
value = showTime ? `${dateStr}T${timeStr}` : dateStr;
|
||||||
|
} else {
|
||||||
|
value = "";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let displayLabel = $derived.by(() => {
|
||||||
|
if (!calendarDate) return placeholder;
|
||||||
|
const d = calendarDate;
|
||||||
|
const date = new Date(d.year, d.month - 1, d.day);
|
||||||
|
const dateLabel = date.toLocaleDateString("en-US", {
|
||||||
|
year: "numeric",
|
||||||
|
month: "long",
|
||||||
|
day: "numeric",
|
||||||
|
});
|
||||||
|
return showTime ? `${dateLabel} ${timeStr}` : dateLabel;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Popover.Root bind:open>
|
||||||
|
<Popover.Trigger>
|
||||||
|
{#snippet child({ props })}
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
{...props}
|
||||||
|
class="w-full justify-start font-normal {!calendarDate ? 'text-muted-foreground' : ''}"
|
||||||
|
>
|
||||||
|
<span class="icon-[ri--calendar-line] h-4 w-4 mr-2 shrink-0"></span>
|
||||||
|
{displayLabel}
|
||||||
|
</Button>
|
||||||
|
{/snippet}
|
||||||
|
</Popover.Trigger>
|
||||||
|
<Popover.Content class="w-auto p-0" align="start">
|
||||||
|
<Calendar bind:value={calendarDate} />
|
||||||
|
{#if showTime}
|
||||||
|
<div class="border-t border-border/40 p-3">
|
||||||
|
<input
|
||||||
|
type="time"
|
||||||
|
value={timeStr}
|
||||||
|
oninput={(e) => {
|
||||||
|
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"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</Popover.Content>
|
||||||
|
</Popover.Root>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default as DatePicker } from "./date-picker.svelte";
|
||||||
19
packages/frontend/src/lib/components/ui/popover/index.ts
Normal file
19
packages/frontend/src/lib/components/ui/popover/index.ts
Normal file
@@ -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,
|
||||||
|
};
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Popover as PopoverPrimitive } from "bits-ui";
|
||||||
|
|
||||||
|
let { ref = $bindable(null), ...restProps }: PopoverPrimitive.CloseProps = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<PopoverPrimitive.Close bind:ref data-slot="popover-close" {...restProps} />
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Popover as PopoverPrimitive } from "bits-ui";
|
||||||
|
import PopoverPortal from "./popover-portal.svelte";
|
||||||
|
import { cn, type WithoutChildrenOrChild } from "$lib/utils.js";
|
||||||
|
import type { ComponentProps } from "svelte";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
sideOffset = 4,
|
||||||
|
align = "center",
|
||||||
|
portalProps,
|
||||||
|
...restProps
|
||||||
|
}: PopoverPrimitive.ContentProps & {
|
||||||
|
portalProps?: WithoutChildrenOrChild<ComponentProps<typeof PopoverPortal>>;
|
||||||
|
} = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<PopoverPortal {...portalProps}>
|
||||||
|
<PopoverPrimitive.Content
|
||||||
|
bind:ref
|
||||||
|
data-slot="popover-content"
|
||||||
|
{sideOffset}
|
||||||
|
{align}
|
||||||
|
class={cn(
|
||||||
|
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-end-2 data-[side=right]:slide-in-from-start-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--bits-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
|
</PopoverPortal>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Popover as PopoverPrimitive } from "bits-ui";
|
||||||
|
|
||||||
|
let { ...restProps }: PopoverPrimitive.PortalProps = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<PopoverPrimitive.Portal {...restProps} />
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
import { Popover as PopoverPrimitive } from "bits-ui";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
...restProps
|
||||||
|
}: PopoverPrimitive.TriggerProps = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<PopoverPrimitive.Trigger
|
||||||
|
bind:ref
|
||||||
|
data-slot="popover-trigger"
|
||||||
|
class={cn("", className)}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Popover as PopoverPrimitive } from "bits-ui";
|
||||||
|
|
||||||
|
let { open = $bindable(false), ...restProps }: PopoverPrimitive.RootProps = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<PopoverPrimitive.Root bind:open {...restProps} />
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
import { FileDropZone, MEGABYTE } from "$lib/components/ui/file-drop-zone";
|
import { FileDropZone, MEGABYTE } from "$lib/components/ui/file-drop-zone";
|
||||||
import { getAssetUrl } from "$lib/api";
|
import { getAssetUrl } from "$lib/api";
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger } from "$lib/components/ui/select";
|
import { Select, SelectContent, SelectItem, SelectTrigger } from "$lib/components/ui/select";
|
||||||
|
import { DatePicker } from "$lib/components/ui/date-picker";
|
||||||
|
|
||||||
const { data } = $props();
|
const { data } = $props();
|
||||||
|
|
||||||
@@ -178,8 +179,8 @@
|
|||||||
<Input id="category" bind:value={category} />
|
<Input id="category" bind:value={category} />
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-1.5">
|
<div class="space-y-1.5">
|
||||||
<Label for="publishDate">{$_("admin.common.publish_date")}</Label>
|
<Label>{$_("admin.common.publish_date")}</Label>
|
||||||
<Input id="publishDate" type="datetime-local" bind:value={publishDate} />
|
<DatePicker bind:value={publishDate} placeholder={$_("admin.common.publish_date")} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
import { Label } from "$lib/components/ui/label";
|
import { Label } from "$lib/components/ui/label";
|
||||||
import { Textarea } from "$lib/components/ui/textarea";
|
import { Textarea } from "$lib/components/ui/textarea";
|
||||||
import { TagsInput } from "$lib/components/ui/tags-input";
|
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";
|
import { FileDropZone, MEGABYTE } from "$lib/components/ui/file-drop-zone";
|
||||||
|
|
||||||
let title = $state("");
|
let title = $state("");
|
||||||
@@ -154,8 +155,8 @@
|
|||||||
<Input id="category" bind:value={category} placeholder={$_("admin.article_form.category_placeholder")} />
|
<Input id="category" bind:value={category} placeholder={$_("admin.article_form.category_placeholder")} />
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-1.5">
|
<div class="space-y-1.5">
|
||||||
<Label for="publishDate">{$_("admin.common.publish_date")}</Label>
|
<Label>{$_("admin.common.publish_date")}</Label>
|
||||||
<Input id="publishDate" type="datetime-local" bind:value={publishDate} />
|
<DatePicker bind:value={publishDate} placeholder={$_("admin.common.publish_date")} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
import { FileDropZone, MEGABYTE } from "$lib/components/ui/file-drop-zone";
|
import { FileDropZone, MEGABYTE } from "$lib/components/ui/file-drop-zone";
|
||||||
import { getAssetUrl } from "$lib/api";
|
import { getAssetUrl } from "$lib/api";
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger } from "$lib/components/ui/select";
|
import { Select, SelectContent, SelectItem, SelectTrigger } from "$lib/components/ui/select";
|
||||||
|
import { DatePicker } from "$lib/components/ui/date-picker";
|
||||||
|
|
||||||
const { data } = $props();
|
const { data } = $props();
|
||||||
|
|
||||||
@@ -124,7 +125,12 @@
|
|||||||
<div class="space-y-1.5">
|
<div class="space-y-1.5">
|
||||||
<Label>{$_("admin.video_form.video_file")}</Label>
|
<Label>{$_("admin.video_form.video_file")}</Label>
|
||||||
{#if movieId}
|
{#if movieId}
|
||||||
<p class="text-xs text-muted-foreground mb-1">{$_("admin.video_form.current_file", { values: { id: movieId } })}</p>
|
<video
|
||||||
|
src={getAssetUrl(movieId)}
|
||||||
|
poster={imageId ? getAssetUrl(imageId, "preview") ?? undefined : undefined}
|
||||||
|
controls
|
||||||
|
class="w-full rounded-lg bg-black max-h-72 mb-2"
|
||||||
|
></video>
|
||||||
{/if}
|
{/if}
|
||||||
<FileDropZone accept="video/*" maxFileSize={2000 * MEGABYTE} onUpload={handleVideoUpload} />
|
<FileDropZone accept="video/*" maxFileSize={2000 * MEGABYTE} onUpload={handleVideoUpload} />
|
||||||
</div>
|
</div>
|
||||||
@@ -135,8 +141,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="space-y-1.5">
|
<div class="space-y-1.5">
|
||||||
<Label for="uploadDate">{$_("admin.common.publish_date")}</Label>
|
<Label>{$_("admin.common.publish_date")}</Label>
|
||||||
<Input id="uploadDate" type="datetime-local" bind:value={uploadDate} />
|
<DatePicker bind:value={uploadDate} placeholder={$_("admin.common.publish_date")} showTime={false} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex gap-6">
|
<div class="flex gap-6">
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
import { Label } from "$lib/components/ui/label";
|
import { Label } from "$lib/components/ui/label";
|
||||||
import { Textarea } from "$lib/components/ui/textarea";
|
import { Textarea } from "$lib/components/ui/textarea";
|
||||||
import { TagsInput } from "$lib/components/ui/tags-input";
|
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";
|
import { FileDropZone, MEGABYTE } from "$lib/components/ui/file-drop-zone";
|
||||||
|
|
||||||
const { data } = $props();
|
const { data } = $props();
|
||||||
@@ -151,8 +152,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="space-y-1.5">
|
<div class="space-y-1.5">
|
||||||
<Label for="uploadDate">{$_("admin.common.publish_date")}</Label>
|
<Label>{$_("admin.common.publish_date")}</Label>
|
||||||
<Input id="uploadDate" type="datetime-local" bind:value={uploadDate} />
|
<DatePicker bind:value={uploadDate} placeholder={$_("admin.common.publish_date")} showTime={false} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex gap-6">
|
<div class="flex gap-6">
|
||||||
|
|||||||
10
pnpm-lock.yaml
generated
10
pnpm-lock.yaml
generated
@@ -186,8 +186,8 @@ importers:
|
|||||||
specifier: ^3.11.0
|
specifier: ^3.11.0
|
||||||
version: 3.11.0
|
version: 3.11.0
|
||||||
'@lucide/svelte':
|
'@lucide/svelte':
|
||||||
specifier: ^0.577.0
|
specifier: ^0.561.0
|
||||||
version: 0.577.0(svelte@5.53.7)
|
version: 0.561.0(svelte@5.53.7)
|
||||||
'@sveltejs/adapter-node':
|
'@sveltejs/adapter-node':
|
||||||
specifier: ^5.5.4
|
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)))
|
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':
|
'@jridgewell/trace-mapping@0.3.31':
|
||||||
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
|
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
|
||||||
|
|
||||||
'@lucide/svelte@0.577.0':
|
'@lucide/svelte@0.561.0':
|
||||||
resolution: {integrity: sha512-0P6mkySd2MapIEgq08tADPmcN4DHndC/02PWwaLkOerXlx5Sv9aT4BxyXLIY+eccr0g/nEyCYiJesqS61YdBZQ==}
|
resolution: {integrity: sha512-vofKV2UFVrKE6I4ewKJ3dfCXSV6iP6nWVmiM83MLjsU91EeJcEg7LoWUABLp/aOTxj1HQNbJD1f3g3L0JQgH9A==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
svelte: ^5
|
svelte: ^5
|
||||||
|
|
||||||
@@ -4138,7 +4138,7 @@ snapshots:
|
|||||||
'@jridgewell/resolve-uri': 3.1.2
|
'@jridgewell/resolve-uri': 3.1.2
|
||||||
'@jridgewell/sourcemap-codec': 1.5.5
|
'@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:
|
dependencies:
|
||||||
svelte: 5.53.7
|
svelte: 5.53.7
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user