feat: improve design trough the whole application

This commit is contained in:
Elias Schneider
2026-05-29 11:14:49 +02:00
parent 272d1479bd
commit b3d40a476b
115 changed files with 822 additions and 550 deletions

View File

@@ -165,11 +165,12 @@ func initServer(r *gin.Engine) (*serverConfig, error) {
}
var socketFn func() (*socket, error)
if common.EnvConfig.SystemdSocket {
switch {
case common.EnvConfig.SystemdSocket:
socketFn = systemdSocket
} else if common.EnvConfig.UnixSocket != "" {
case common.EnvConfig.UnixSocket != "":
socketFn = unixSocket
} else {
default:
socketFn = tcpSocket
}

View File

@@ -54,7 +54,7 @@ func CreateDefaultProfilePicture(initials string) (*bytes.Buffer, error) {
img := imaging.New(profilePictureSize, profilePictureSize, color.RGBA{R: 255, G: 255, B: 255, A: 255})
// Load the font
fontBytes, err := resources.FS.ReadFile("fonts/PlayfairDisplay-Bold.ttf")
fontBytes, err := resources.FS.ReadFile("fonts/Gloock.ttf")
if err != nil {
return nil, fmt.Errorf("failed to read font file: %w", err)
}
@@ -84,7 +84,7 @@ func CreateDefaultProfilePicture(initials string) (*bytes.Buffer, error) {
// Center the initials
x := (profilePictureSize - font.MeasureString(face, initials).Ceil()) / 2
y := (profilePictureSize-face.Metrics().Height.Ceil())/2 + face.Metrics().Ascent.Ceil() - 10
y := (profilePictureSize-face.Metrics().Height.Ceil())/2 + face.Metrics().Ascent.Ceil()
drawer.Dot = fixed.P(x, y)
// Draw the initials

Binary file not shown.

View File

@@ -14,6 +14,7 @@
"format": "prettier --write ."
},
"dependencies": {
"@fontsource/gloock": "^5.2.8",
"@simplewebauthn/browser": "^13.3.0",
"@tailwindcss/vite": "^4.3.0",
"axios": "^1.16.1",

View File

@@ -1,5 +1,6 @@
@import 'tailwindcss';
@import 'tw-animate-css';
@import '@fontsource/gloock';
@variant dark (&:where(.dark, .dark *));
@@ -12,245 +13,192 @@
color utility to any element that depends on these defaults.
*/
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentcolor);
}
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentcolor);
}
}
:root {
--radius: 0.625rem;
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
--warning: oklch(0.96 0.06 85);
--warning-foreground: oklch(0.32 0.07 70);
--border: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
--radius: 1rem;
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
--warning: oklch(0.96 0.06 85);
--warning-foreground: oklch(0.32 0.07 70);
--border: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.205 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--warning: oklch(0.42 0.09 70);
--warning-foreground: oklch(0.93 0.03 85);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.556 0 0);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.556 0 0);
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.205 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--warning: oklch(0.42 0.09 70);
--warning-foreground: oklch(0.93 0.03 85);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.556 0 0);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.556 0 0);
}
@theme inline {
/* Radius (for rounded-*) */
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
/* Radius (for rounded-*) */
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
/* Colors */
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-border: var(--border);
--color-input: var(--input);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-warning: var(--warning);
--color-warning-foreground: var(--warning-foreground);
--color-ring: var(--ring);
--color-radius: var(--radius);
--color-sidebar-background: var(--sidebar-background);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
/* Colors */
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-border: var(--border);
--color-input: var(--input);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-warning: var(--warning);
--color-warning-foreground: var(--warning-foreground);
--color-ring: var(--ring);
--color-radius: var(--radius);
--color-sidebar-background: var(--sidebar-background);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
/* Animations */
--animate-accordion-up: accordion-up 0.2s ease-out;
--animate-accordion-down: accordion-down 0.2s ease-out;
--animate-caret-blink: caret-blink 1.25s ease-out infinite;
/* Font */
--font-playfair: 'Playfair Display', serif;
/* Font */
--font-glooock: 'glooock ', serif;
}
@layer base {
* {
@apply border-border;
}
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
body {
@apply bg-background text-foreground;
}
button {
@apply cursor-pointer;
}
@font-face {
font-family: 'Playfair Display';
font-weight: 400;
src: url('/fonts/PlayfairDisplay-Regular.woff') format('woff');
}
@font-face {
font-family: 'Playfair Display';
font-weight: 500;
src: url('/fonts/PlayfairDisplay-Medium.woff') format('woff');
}
@font-face {
font-family: 'Playfair Display';
font-weight: 600;
src: url('/fonts/PlayfairDisplay-SemiBold.woff') format('woff');
}
@font-face {
font-family: 'Playfair Display';
font-weight: 700;
src: url('/fonts/PlayfairDisplay-Bold.woff') format('woff');
}
button {
@apply cursor-pointer;
}
}
@keyframes accordion-down {
from {
height: 0;
}
to {
height: var(--bits-accordion-content-height);
}
}
@keyframes accordion-up {
from {
height: var(--bits-accordion-content-height);
}
to {
height: 0;
}
}
@keyframes caret-blink {
0%,
70%,
100% {
opacity: 1;
}
20%,
50% {
opacity: 0;
}
}
.animate-fade-in {
animation: fadeIn 0.3s ease-out forwards;
opacity: 0;
animation: fadeIn 0.3s ease-out forwards;
opacity: 0;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes bg-zoom {
0% {
transform: scale(1.3);
}
100% {
transform: scale(1);
}
0% {
transform: scale(1.3);
}
100% {
transform: scale(1);
}
}
.animate-bg-zoom {
transform-origin: center;
will-change: transform;
animation: bg-zoom 0.7s cubic-bezier(0.25, 0.1, 0.25, 1) forwards;
transform-origin: center;
will-change: transform;
animation: bg-zoom 0.7s cubic-bezier(0.25, 0.1, 0.25, 1) forwards;
}
@keyframes delayed-fade {
0%,
40% {
opacity: 0;
}
100% {
opacity: 1;
}
0%,
40% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.animate-delayed-fade {
animation: delayed-fade 0.5s ease-out forwards;
}
animation: delayed-fade 0.5s ease-out forwards;
}

View File

@@ -81,18 +81,20 @@
variant="outline"
role="combobox"
aria-expanded={open}
class="h-auto min-h-10 w-full justify-between"
class="h-auto min-h-10 w-full bg-input/30!"
>
<div class="flex flex-wrap items-center gap-1">
{#if selectedItems.length > 0}
{#each selectedLabels as label}
<Badge variant="secondary">{label}</Badge>
{/each}
{:else}
<span class="text-muted-foreground font-normal">{m.select_items()}</span>
{/if}
<div class="flex items-center justify-between w-full">
<div class="flex flex-wrap items-center gap-1">
{#if selectedItems.length > 0}
{#each selectedLabels as label}
<Badge variant="secondary">{label}</Badge>
{/each}
{:else}
<span class="text-muted-foreground font-normal">{m.select_items()}</span>
{/if}
</div>
<LucideChevronDown class="ml-2 size-4 shrink-0 opacity-50" />
</div>
<LucideChevronDown class="ml-2 size-4 shrink-0 opacity-50" />
</Button>
{/snippet}
</Popover.Trigger>

View File

@@ -70,10 +70,12 @@
role="combobox"
aria-expanded={open}
{...props}
class={cn('justify-between', restProps.class)}
class={restProps.class}
>
{items.find((item) => item.value === value)?.label || selectText}
<LucideChevronDown class="ml-2 size-4 shrink-0 opacity-50" />
<span class="flex justify-between w-full">
{items.find((item) => item.value === value)?.label || selectText}
<LucideChevronDown class="size-4 shrink-0 opacity-50" />
</span>
</Button>
{/snippet}
</Popover.Trigger>

View File

@@ -1,8 +1,9 @@
<script lang="ts">
import { page } from '$app/state';
import appConfigStore from '$lib/stores/application-configuration-store';
import { m } from '$lib/paraglide/messages';
import userStore from '$lib/stores/user-store';
import Logo from '../logo.svelte';
import Separator from '../ui/separator/separator.svelte';
import HeaderAvatar from './header-avatar.svelte';
import ModeSwitcher from './mode-switcher.svelte';
@@ -19,7 +20,7 @@
);
</script>
<div class=" w-full {isAuthPage ? 'absolute top-0 z-10 mt-3 lg:mt-8 pr-2 lg:pr-3' : 'border-b'}">
<div class=" w-full {isAuthPage ? 'absolute top-0 z-10 mt-3 lg:mt-8 pr-2 lg:pr-3' : 'pt-3 bg-muted/40 dark:bg-background '}">
<div
class="{!isAuthPage
? 'max-w-410'
@@ -27,10 +28,11 @@
>
<div class="flex h-16 items-center">
{#if !isAuthPage}
<a href="/" class="flex items-center gap-3 transition-opacity hover:opacity-80">
<a href="/" class="flex items-center transition-opacity hover:opacity-80">
<Logo class="size-8" />
<h1 class="text-lg font-semibold tracking-tight" data-testid="application-name">
{$appConfigStore.appName}
<Separator orientation="vertical" class="h-5! bg-neutral-600 ml-2 mr-3" />
<h1 class="text-2xl font-glooock" data-testid="application-name">
{m.settings()}
</h1>
</a>
{/if}

View File

@@ -23,7 +23,7 @@
</script>
<Item.Root variant="transparent" class="hover:bg-muted transition-colors py-3 px-0 sm:px-4">
<Item.Media class="bg-primary/10 text-primary rounded-lg p-2">
<Item.Media class="bg-primary/10 text-primary rounded-full p-3">
{#if icon}{@const Icon = icon}
<Icon class="size-5" />
{/if}

View File

@@ -9,7 +9,7 @@
value,
size = 200,
color = '#000000',
backgroundColor = '#FFFFFF',
backgroundColor = 'transparent',
...restProps
}: HTMLAttributes<HTMLCanvasElement> & {
value: string | null;
@@ -39,4 +39,4 @@
});
</script>
<canvas {...restProps} bind:this={canvasEl} class={cn('rounded-lg', restProps.class)}></canvas>
<canvas {...restProps} bind:this={canvasEl} class={cn('rounded', restProps.class)}></canvas>

View File

@@ -187,7 +187,6 @@
value={signupLink}
size={180}
color={mode.current === 'dark' ? '#FFFFFF' : '#000000'}
backgroundColor={mode.current === 'dark' ? '#000000' : '#FFFFFF'}
/>
<CopyToClipboard value={signupLink!}>
<p data-testId="signup-token-link" class="px-2 text-center text-sm break-all">

View File

@@ -16,7 +16,7 @@
class={buttonVariants({
variant: 'outline',
size: 'sm',
class: 'ml-auto h-8'
class: 'ml-auto'
})}
>
<Settings2Icon />

View File

@@ -38,11 +38,13 @@
{...props}
variant="outline"
size="sm"
class="h-8 border-dashed"
class="order-dashed"
data-testid={`facet-${title.toLowerCase()}-trigger`}
>
<ListFilterIcon />
{title}
<span class="flex gap-2 items-center">
<ListFilterIcon />
{title}
</span>
{#if selectedValues.size > 0}
<Separator orientation="vertical" class="mx-2 h-4" />
<Badge variant="secondary" class="rounded-sm px-1 font-normal lg:hidden">

View File

@@ -239,7 +239,7 @@
class="h-12 w-full justify-start px-4 font-medium hover:bg-transparent"
onclick={() => onSort(column.column)}
>
<span class="flex items-center">
<span class="flex items-center w-full">
{column.label}
<ChevronDown
class={cn(
@@ -310,9 +310,7 @@
<DropdownMenu.Item
onclick={() => action.onClick(item)}
disabled={action.disabled}
class={action.variant === 'danger'
? 'text-red-500 focus:!text-red-700'
: ''}
class={action.variant === 'danger' ? 'text-red-500!' : ''}
>
{#if action.icon}
{@const Icon = action.icon}

View File

@@ -1,18 +1,27 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import { buttonVariants } from '$lib/components/ui/button/index.js';
import { cn } from '$lib/utils/style.js';
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
import {
buttonVariants,
type ButtonVariant,
type ButtonSize,
} from "$lib/components/ui/button/index.js";
import { cn } from "$lib/utils/style.js";
let {
ref = $bindable(null),
class: className,
variant = "default",
size = "default",
...restProps
}: AlertDialogPrimitive.ActionProps = $props();
}: AlertDialogPrimitive.ActionProps & {
variant?: ButtonVariant;
size?: ButtonSize;
} = $props();
</script>
<AlertDialogPrimitive.Action
bind:ref
data-slot="alert-dialog-action"
class={cn(buttonVariants(), className)}
class={cn(buttonVariants({ variant, size }), "cn-alert-dialog-action", className)}
{...restProps}
/>

View File

@@ -1,18 +1,27 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import { buttonVariants } from '$lib/components/ui/button/index.js';
import { cn } from '$lib/utils/style.js';
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
import {
buttonVariants,
type ButtonVariant,
type ButtonSize,
} from "$lib/components/ui/button/index.js";
import { cn } from "$lib/utils/style.js";
let {
ref = $bindable(null),
class: className,
variant = "outline",
size = "default",
...restProps
}: AlertDialogPrimitive.CancelProps = $props();
}: AlertDialogPrimitive.CancelProps & {
variant?: ButtonVariant;
size?: ButtonSize;
} = $props();
</script>
<AlertDialogPrimitive.Cancel
bind:ref
data-slot="alert-dialog-cancel"
class={cn(buttonVariants({ variant: 'outline' }), className)}
class={cn(buttonVariants({ variant, size }), "cn-alert-dialog-cancel", className)}
{...restProps}
/>

View File

@@ -1,27 +1,32 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import AlertDialogOverlay from './alert-dialog-overlay.svelte';
import { cn, type WithoutChild, type WithoutChildrenOrChild } from '$lib/utils/style.js';
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
import AlertDialogPortal from "./alert-dialog-portal.svelte";
import AlertDialogOverlay from "./alert-dialog-overlay.svelte";
import { cn, type WithoutChild, type WithoutChildrenOrChild } from "$lib/utils/style.js";
import type { ComponentProps } from "svelte";
let {
ref = $bindable(null),
class: className,
size = "default",
portalProps,
...restProps
}: WithoutChild<AlertDialogPrimitive.ContentProps> & {
portalProps?: WithoutChildrenOrChild<AlertDialogPrimitive.PortalProps>;
size?: "default" | "sm";
portalProps?: WithoutChildrenOrChild<ComponentProps<typeof AlertDialogPortal>>;
} = $props();
</script>
<AlertDialogPrimitive.Portal {...portalProps}>
<AlertDialogPortal {...portalProps}>
<AlertDialogOverlay />
<AlertDialogPrimitive.Content
bind:ref
data-slot="alert-dialog-content"
data-size={size}
class={cn(
'bg-background 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 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg',
"data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 bg-popover text-popover-foreground ring-foreground/10 gap-4 rounded-4xl p-5 sm:p-8 sm:pb-6 ring-1 duration-100 data-[size=default]:max-w-sm data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-md group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 outline-none",
className
)}
{...restProps}
/>
</AlertDialogPrimitive.Portal>
</AlertDialogPortal>

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
import { cn } from "$lib/utils/style.js";
let {
ref = $bindable(null),
@@ -12,6 +12,6 @@
<AlertDialogPrimitive.Description
bind:ref
data-slot="alert-dialog-description"
class={cn('text-muted-foreground text-sm', className)}
class={cn("text-muted-foreground *:[a]:hover:text-foreground text-sm text-balance md:text-pretty *:[a]:underline *:[a]:underline-offset-3", className)}
{...restProps}
/>

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { cn, type WithElementRef } from '$lib/utils/style.js';
import type { HTMLAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from "$lib/utils/style.js";
import type { HTMLAttributes } from "svelte/elements";
let {
ref = $bindable(null),
@@ -13,7 +13,10 @@
<div
bind:this={ref}
data-slot="alert-dialog-footer"
class={cn('flex flex-col-reverse gap-2 sm:flex-row sm:justify-end', className)}
class={cn(
"-mx-4 -mb-4 rounded-b-xl p-4 flex flex-col-reverse gap-2 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end",
className
)}
{...restProps}
>
{@render children?.()}

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils/style.js';
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils/style.js";
let {
ref = $bindable(null),
@@ -13,7 +13,7 @@
<div
bind:this={ref}
data-slot="alert-dialog-header"
class={cn('flex flex-col gap-2 text-center sm:text-left', className)}
class={cn("grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-4 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]", className)}
{...restProps}
>
{@render children?.()}

View File

@@ -0,0 +1,20 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils/style.js";
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script>
<div
bind:this={ref}
data-slot="alert-dialog-media"
class={cn("bg-muted mb-2 inline-flex size-10 items-center justify-center rounded-md sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-6", className)}
{...restProps}
>
{@render children?.()}
</div>

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
import { cn } from "$lib/utils/style.js";
let {
ref = $bindable(null),
@@ -12,9 +12,6 @@
<AlertDialogPrimitive.Overlay
bind:ref
data-slot="alert-dialog-overlay"
class={cn(
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50',
className
)}
class={cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 z-50", className)}
{...restProps}
/>

View File

@@ -0,0 +1,7 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
let { ...restProps }: AlertDialogPrimitive.PortalProps = $props();
</script>
<AlertDialogPrimitive.Portal {...restProps} />

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
import { cn } from "$lib/utils/style.js";
let {
ref = $bindable(null),
@@ -12,6 +12,6 @@
<AlertDialogPrimitive.Title
bind:ref
data-slot="alert-dialog-title"
class={cn('text-lg font-semibold', className)}
class={cn("text-base font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2", className)}
{...restProps}
/>

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
let { ref = $bindable(null), ...restProps }: AlertDialogPrimitive.TriggerProps = $props();
</script>

View File

@@ -0,0 +1,7 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
let { open = $bindable(false), ...restProps }: AlertDialogPrimitive.RootProps = $props();
</script>
<AlertDialogPrimitive.Root bind:open {...restProps} />

View File

@@ -1,36 +1,40 @@
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import Trigger from './alert-dialog-trigger.svelte';
import Title from './alert-dialog-title.svelte';
import Action from './alert-dialog-action.svelte';
import Cancel from './alert-dialog-cancel.svelte';
import Footer from './alert-dialog-footer.svelte';
import Header from './alert-dialog-header.svelte';
import Overlay from './alert-dialog-overlay.svelte';
import Content from './alert-dialog-content.svelte';
import Description from './alert-dialog-description.svelte';
const Root = AlertDialogPrimitive.Root;
import Root from "./alert-dialog.svelte";
import Portal from "./alert-dialog-portal.svelte";
import Trigger from "./alert-dialog-trigger.svelte";
import Title from "./alert-dialog-title.svelte";
import Action from "./alert-dialog-action.svelte";
import Cancel from "./alert-dialog-cancel.svelte";
import Footer from "./alert-dialog-footer.svelte";
import Header from "./alert-dialog-header.svelte";
import Overlay from "./alert-dialog-overlay.svelte";
import Content from "./alert-dialog-content.svelte";
import Description from "./alert-dialog-description.svelte";
import Media from "./alert-dialog-media.svelte";
export {
Root,
Title,
Action,
Cancel,
Portal,
Footer,
Header,
Trigger,
Overlay,
Content,
Description,
Media,
//
Root as AlertDialog,
Title as AlertDialogTitle,
Action as AlertDialogAction,
Cancel as AlertDialogCancel,
Portal as AlertDialogPortal,
Footer as AlertDialogFooter,
Header as AlertDialogHeader,
Trigger as AlertDialogTrigger,
Overlay as AlertDialogOverlay,
Content as AlertDialogContent,
Description as AlertDialogDescription
Description as AlertDialogDescription,
Media as AlertDialogMedia,
};

View File

@@ -2,7 +2,7 @@
import { tv, type VariantProps } from 'tailwind-variants';
export const alertVariants = tv({
base: 'relative grid w-full grid-cols-[0_1fr] items-start gap-y-0.5 rounded-lg border px-4 py-3 text-sm has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] has-[>svg]:gap-x-3 [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current',
base: 'relative grid w-full grid-cols-[0_1fr] items-start gap-y-0.5 rounded-3xl border px-4 py-3 text-sm has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] has-[>svg]:gap-x-3 [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current',
variants: {
variant: {
default: 'bg-card text-card-foreground',

View File

@@ -1,35 +1,35 @@
<script lang="ts" module>
import { type VariantProps, tv } from 'tailwind-variants';
import { type VariantProps, tv } from "tailwind-variants";
export const badgeVariants = tv({
base: 'focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden whitespace-nowrap rounded-md border px-2 py-0.5 text-xs font-medium transition-[color,box-shadow] focus-visible:ring-[3px] [&>svg]:pointer-events-none [&>svg]:size-3',
base: "h-5 gap-1 rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium transition-all has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&>svg]:size-3! focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive group/badge inline-flex w-fit shrink-0 items-center justify-center overflow-hidden whitespace-nowrap transition-colors focus-visible:ring-[3px] [&>svg]:pointer-events-none",
variants: {
variant: {
default: 'bg-primary text-primary-foreground [a&]:hover:bg-primary/90 border-transparent',
secondary:
'bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90 border-transparent',
destructive:
'bg-destructive [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/70 border-transparent text-white',
outline: 'text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground'
}
default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
secondary: "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
destructive: "bg-destructive/10 [a]:hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 text-destructive dark:bg-destructive/20",
outline: "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",
ghost: "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
link: "text-primary underline-offset-4 hover:underline",
},
},
defaultVariants: {
variant: 'default'
}
variant: "default",
},
});
export type BadgeVariant = VariantProps<typeof badgeVariants>['variant'];
export type BadgeVariant = VariantProps<typeof badgeVariants>["variant"];
</script>
<script lang="ts">
import type { HTMLAnchorAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils/style.js';
import type { HTMLAnchorAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils/style.js";
let {
ref = $bindable(null),
href,
class: className,
variant = 'default',
variant = "default",
children,
...restProps
}: WithElementRef<HTMLAnchorAttributes> & {
@@ -38,7 +38,7 @@
</script>
<svelte:element
this={href ? 'a' : 'span'}
this={href ? "a" : "span"}
bind:this={ref}
data-slot="badge"
{href}

View File

@@ -1,2 +1,2 @@
export { default as Badge } from './badge.svelte';
export { badgeVariants, type BadgeVariant } from './badge.svelte';
export { default as Badge } from "./badge.svelte";
export { badgeVariants, type BadgeVariant } from "./badge.svelte";

View File

@@ -4,22 +4,24 @@
import { tv, type VariantProps } from 'tailwind-variants';
export const buttonVariants = tv({
base: "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium outline-none transition-all focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
base: "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-full text-sm font-medium outline-none transition-all focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:shrink-0 transition active:scale-95",
variants: {
variant: {
default: 'bg-primary text-primary-foreground shadow-xs hover:bg-primary/90',
destructive:
'bg-destructive shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60 text-white',
default: 'bg-primary text-primary-foreground hover:bg-primary/80',
outline:
'bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 border',
secondary: 'bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80',
ghost: 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
'border border-border bg-background hover:bg-muted hover:text-foreground dark:hover:bg-input/30 aria-expanded:bg-muted aria-expanded:text-foreground dark:bg-transparent',
secondary:
'bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground',
ghost:
'hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground',
destructive:
'bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30',
link: 'text-primary underline-offset-4 hover:underline'
},
size: {
default: 'h-10 px-4 py-2',
sm: 'h-8 rounded-md px-3',
lg: 'h-11 rounded-md px-8',
sm: 'h-9 px-3 py-2',
lg: 'h-11 px-8',
icon: 'h-10 w-10'
}
},
@@ -96,9 +98,6 @@
tabindex={disabled ? -1 : undefined}
{...restProps}
>
{#if isLoading}
<Spinner />
{/if}
{@render children?.()}
</a>
{:else}
@@ -111,9 +110,15 @@
onclick={handleOnClick}
{...restProps}
>
{#if isLoading}
<Spinner />
{/if}
{@render children?.()}
<span class="flex items-center w-full justify-center">
<Spinner
class={cn(
'grid overflow-hidden transition-[width,opacity,margin-right] duration-400 ease-[linear(0,0.897_14.4%,1.311_31.2%,1.338_46%,1.054_80.4%,1)]',
isLoading ? 'w-4 opacity-100 mr-2' : 'w-0 opacity-0'
)}
aria-hidden={!isLoading}
/>
{@render children?.()}
</span>
</button>
{/if}

View File

@@ -2,8 +2,8 @@ import Root, {
type ButtonProps,
type ButtonSize,
type ButtonVariant,
buttonVariants
} from './button.svelte';
buttonVariants,
} from "./button.svelte";
export {
Root,
@@ -13,5 +13,5 @@ export {
buttonVariants,
type ButtonProps,
type ButtonSize,
type ButtonVariant
type ButtonVariant,
};

View File

@@ -14,7 +14,7 @@
bind:this={ref}
data-slot="card"
class={cn(
'bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm',
'bg-card text-card-foreground flex flex-col gap-6 rounded-4xl border py-6 shadow-sm',
className
)}
{...restProps}

View File

@@ -23,14 +23,14 @@
bind:ref
data-slot="dialog-content"
class={cn(
'bg-background 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 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg',
'bg-popover 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 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-4xl border p-6 shadow-lg duration-200 sm:max-w-lg',
className
)}
{...restProps}
>
{@render children?.()}
<DialogPrimitive.Close
class="ring-offset-background focus:ring-ring absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
class="ring-offset-popover focus:ring-ring absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
>
<XIcon />
<span class="sr-only">Close</span>

View File

@@ -0,0 +1,16 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
let {
ref = $bindable(null),
value = $bindable([]),
...restProps
}: DropdownMenuPrimitive.CheckboxGroupProps = $props();
</script>
<DropdownMenuPrimitive.CheckboxGroup
bind:ref
bind:value
data-slot="dropdown-menu-checkbox-group"
{...restProps}
/>

View File

@@ -1,9 +1,9 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import CheckIcon from '@lucide/svelte/icons/check';
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import MinusIcon from '@lucide/svelte/icons/minus';
import { cn, type WithoutChildrenOrChild } from '$lib/utils/style.js';
import type { Snippet } from 'svelte';
import CheckIcon from '@lucide/svelte/icons/check';
import { cn, type WithoutChildrenOrChild } from "$lib/utils/style.js";
import type { Snippet } from "svelte";
let {
ref = $bindable(null),
@@ -23,17 +23,20 @@
bind:indeterminate
data-slot="dropdown-menu-checkbox-item"
class={cn(
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
"focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground gap-1.5 rounded-md py-1.5 pr-9 pl-2 text-sm data-inset:pl-7 [&_svg:not([class*='size-'])]:size-4 relative flex cursor-default items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
className
)}
{...restProps}
>
{#snippet children({ checked, indeterminate })}
<span class="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
<span
class="absolute right-2 flex items-center justify-center pointer-events-none"
data-slot="dropdown-menu-checkbox-item-indicator"
>
{#if indeterminate}
<MinusIcon class="size-4" />
{:else}
<CheckIcon class={cn('size-4', !checked && 'text-transparent')} />
<MinusIcon />
{:else if checked}
<CheckIcon />
{/if}
</span>
{@render childrenProp?.()}

View File

@@ -1,27 +1,31 @@
<script lang="ts">
import { cn } from '$lib/utils/style.js';
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn, type WithoutChildrenOrChild } from "$lib/utils/style.js";
import DropdownMenuPortal from "./dropdown-menu-portal.svelte";
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import type { ComponentProps } from "svelte";
let {
ref = $bindable(null),
sideOffset = 4,
align = "start",
portalProps,
class: className,
...restProps
}: DropdownMenuPrimitive.ContentProps & {
portalProps?: DropdownMenuPrimitive.PortalProps;
portalProps?: WithoutChildrenOrChild<ComponentProps<typeof DropdownMenuPortal>>;
} = $props();
</script>
<DropdownMenuPrimitive.Portal {...portalProps}>
<DropdownMenuPortal {...portalProps}>
<DropdownMenuPrimitive.Content
bind:ref
data-slot="dropdown-menu-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-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md',
"data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 bg-popover text-popover-foreground min-w-32 rounded-lg p-1 shadow-md ring-1 duration-100 data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2 z-50 overflow-x-hidden overflow-y-auto outline-none data-closed:overflow-hidden",
className
)}
{...restProps}
/>
</DropdownMenuPrimitive.Portal>
</DropdownMenuPortal>

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
import type { ComponentProps } from 'svelte';
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { cn } from "$lib/utils/style.js";
import type { ComponentProps } from "svelte";
let {
ref = $bindable(null),
@@ -17,6 +17,6 @@
bind:ref
data-slot="dropdown-menu-group-heading"
data-inset={inset}
class={cn('px-2 py-1.5 text-sm font-semibold data-[inset]:pl-8', className)}
class={cn("px-2 py-1.5 text-sm font-semibold data-[inset]:ps-8", className)}
{...restProps}
/>

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
let { ref = $bindable(null), ...restProps }: DropdownMenuPrimitive.GroupProps = $props();
</script>

View File

@@ -1,16 +1,16 @@
<script lang="ts">
import { cn } from '$lib/utils/style.js';
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn } from "$lib/utils/style.js";
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
let {
ref = $bindable(null),
class: className,
inset,
variant = 'default',
variant = "default",
...restProps
}: DropdownMenuPrimitive.ItemProps & {
inset?: boolean;
variant?: 'default' | 'destructive';
variant?: "default" | "destructive";
} = $props();
</script>
@@ -20,7 +20,7 @@
data-inset={inset}
data-variant={variant}
class={cn(
"data-highlighted:bg-accent data-highlighted:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:data-highlighted:bg-destructive/10 dark:data-[variant=destructive]:data-highlighted:bg-destructive/20 data-[variant=destructive]:data-highlighted:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive relative flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:text-destructive not-data-[variant=destructive]:focus:**:text-accent-foreground gap-1.5 rounded-md px-2 py-1.5 text-sm data-inset:pl-7 [&_svg:not([class*='size-'])]:size-4 group/dropdown-menu-item relative flex cursor-pointer items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0",
className
)}
{...restProps}

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { cn, type WithElementRef } from '$lib/utils/style.js';
import type { HTMLAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from "$lib/utils/style.js";
import type { HTMLAttributes } from "svelte/elements";
let {
ref = $bindable(null),
@@ -17,7 +17,7 @@
bind:this={ref}
data-slot="dropdown-menu-label"
data-inset={inset}
class={cn('px-2 py-1.5 text-sm font-semibold data-[inset]:pl-8', className)}
class={cn("text-muted-foreground px-1.5 py-1 text-xs font-medium data-inset:pl-7 data-[inset]:pl-8", className)}
{...restProps}
>
{@render children?.()}

View File

@@ -0,0 +1,7 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
let { ...restProps }: DropdownMenuPrimitive.PortalProps = $props();
</script>
<DropdownMenuPrimitive.Portal {...restProps} />

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
let {
ref = $bindable(null),

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import CircleIcon from '@lucide/svelte/icons/circle';
import { cn, type WithoutChild } from '$lib/utils/style.js';
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import CheckIcon from '@lucide/svelte/icons/check';
import { cn, type WithoutChild } from "$lib/utils/style.js";
let {
ref = $bindable(null),
@@ -15,15 +15,18 @@
bind:ref
data-slot="dropdown-menu-radio-item"
class={cn(
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
"focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm data-inset:pl-7 [&_svg:not([class*='size-'])]:size-4 relative flex cursor-default items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
className
)}
{...restProps}
>
{#snippet children({ checked })}
<span class="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
<span
class="absolute right-2 flex items-center justify-center"
data-slot="dropdown-menu-radio-item-indicator"
>
{#if checked}
<CircleIcon class="size-2 fill-current" />
<CheckIcon />
{/if}
</span>
{@render childrenProp?.({ checked })}

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { cn } from "$lib/utils/style.js";
let {
ref = $bindable(null),
@@ -12,6 +12,6 @@
<DropdownMenuPrimitive.Separator
bind:ref
data-slot="dropdown-menu-separator"
class={cn('bg-border -mx-1 my-1 h-px', className)}
class={cn("bg-border -mx-1 my-1 h-px", className)}
{...restProps}
/>

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils/style.js';
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils/style.js";
let {
ref = $bindable(null),
@@ -13,7 +13,7 @@
<span
bind:this={ref}
data-slot="dropdown-menu-shortcut"
class={cn('text-muted-foreground ml-auto text-xs tracking-widest', className)}
class={cn("text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground ml-auto text-xs tracking-widest", className)}
{...restProps}
>
{@render children?.()}

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { cn } from "$lib/utils/style.js";
let {
ref = $bindable(null),
@@ -12,9 +12,6 @@
<DropdownMenuPrimitive.SubContent
bind:ref
data-slot="dropdown-menu-sub-content"
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-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg',
className
)}
class={cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 bg-popover text-popover-foreground min-w-[96px] rounded-lg p-1 shadow-lg ring-1 duration-100 w-auto", className)}
{...restProps}
/>

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { cn } from '$lib/utils/style.js';
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import ChevronRightIcon from '@lucide/svelte/icons/chevron-right';
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn } from "$lib/utils/style.js";
let {
ref = $bindable(null),
@@ -19,11 +19,11 @@
data-slot="dropdown-menu-sub-trigger"
data-inset={inset}
class={cn(
"data-highlighted:bg-accent data-highlighted:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
"focus:bg-accent focus:text-accent-foreground data-open:bg-accent data-open:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground gap-1.5 rounded-md px-1.5 py-1 text-sm data-inset:pl-7 [&_svg:not([class*='size-'])]:size-4 flex cursor-default items-center outline-hidden select-none data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0",
className
)}
{...restProps}
>
{@render children?.()}
<ChevronRightIcon class="ml-auto size-4" />
<ChevronRightIcon class="ml-auto" />
</DropdownMenuPrimitive.SubTrigger>

View File

@@ -0,0 +1,7 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
let { open = $bindable(false), ...restProps }: DropdownMenuPrimitive.SubProps = $props();
</script>
<DropdownMenuPrimitive.Sub bind:open {...restProps} />

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
let { ref = $bindable(null), ...restProps }: DropdownMenuPrimitive.TriggerProps = $props();
</script>

View File

@@ -0,0 +1,7 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
let { open = $bindable(false), ...restProps }: DropdownMenuPrimitive.RootProps = $props();
</script>
<DropdownMenuPrimitive.Root bind:open {...restProps} />

View File

@@ -1,26 +1,31 @@
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import CheckboxItem from './dropdown-menu-checkbox-item.svelte';
import Content from './dropdown-menu-content.svelte';
import Group from './dropdown-menu-group.svelte';
import Item from './dropdown-menu-item.svelte';
import Label from './dropdown-menu-label.svelte';
import RadioGroup from './dropdown-menu-radio-group.svelte';
import RadioItem from './dropdown-menu-radio-item.svelte';
import Separator from './dropdown-menu-separator.svelte';
import Shortcut from './dropdown-menu-shortcut.svelte';
import Trigger from './dropdown-menu-trigger.svelte';
import SubContent from './dropdown-menu-sub-content.svelte';
import SubTrigger from './dropdown-menu-sub-trigger.svelte';
import GroupHeading from './dropdown-menu-group-heading.svelte';
const Sub = DropdownMenuPrimitive.Sub;
const Root = DropdownMenuPrimitive.Root;
import Root from "./dropdown-menu.svelte";
import Sub from "./dropdown-menu-sub.svelte";
import CheckboxGroup from "./dropdown-menu-checkbox-group.svelte";
import CheckboxItem from "./dropdown-menu-checkbox-item.svelte";
import Content from "./dropdown-menu-content.svelte";
import Group from "./dropdown-menu-group.svelte";
import Item from "./dropdown-menu-item.svelte";
import Label from "./dropdown-menu-label.svelte";
import RadioGroup from "./dropdown-menu-radio-group.svelte";
import RadioItem from "./dropdown-menu-radio-item.svelte";
import Separator from "./dropdown-menu-separator.svelte";
import Shortcut from "./dropdown-menu-shortcut.svelte";
import Trigger from "./dropdown-menu-trigger.svelte";
import SubContent from "./dropdown-menu-sub-content.svelte";
import SubTrigger from "./dropdown-menu-sub-trigger.svelte";
import GroupHeading from "./dropdown-menu-group-heading.svelte";
import Portal from "./dropdown-menu-portal.svelte";
export {
CheckboxGroup,
CheckboxItem,
Content,
Portal,
Root as DropdownMenu,
CheckboxGroup as DropdownMenuCheckboxGroup,
CheckboxItem as DropdownMenuCheckboxItem,
Content as DropdownMenuContent,
Portal as DropdownMenuPortal,
Group as DropdownMenuGroup,
Item as DropdownMenuItem,
Label as DropdownMenuLabel,
@@ -45,5 +50,5 @@ export {
Sub,
SubContent,
SubTrigger,
Trigger
Trigger,
};

View File

@@ -24,7 +24,7 @@
bind:this={ref}
data-slot="input"
class={cn(
'selection:bg-primary dark:bg-input/30 selection:text-primary-foreground border-input ring-offset-background placeholder:text-muted-foreground flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-2 text-base font-medium shadow-xs transition-[color,box-shadow] outline-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
'selection:bg-primary dark:bg-input/30 selection:text-primary-foreground border-input ring-offset-background placeholder:text-muted-foreground flex h-9 w-full min-w-0 rounded-full border bg-transparent px-3 py-2 text-base font-medium shadow-xs transition-[color,box-shadow] outline-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
className
@@ -39,7 +39,7 @@
bind:this={ref}
data-slot="input"
class={cn(
'border-input bg-background selection:bg-primary dark:bg-input/30 selection:text-primary-foreground ring-offset-background placeholder:text-muted-foreground flex h-9 w-full min-w-0 rounded-md border px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
'border-input bg-background selection:bg-primary dark:bg-input/30 selection:text-primary-foreground ring-offset-background placeholder:text-muted-foreground flex h-9 w-full min-w-0 rounded-full border px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
className

View File

@@ -2,7 +2,7 @@
import { tv, type VariantProps } from 'tailwind-variants';
export const itemVariants = tv({
base: 'group/item focus-visible:border-ring focus-visible:ring-ring/50 flex flex-wrap items-center rounded-xl border border-transparent text-sm outline-none transition-colors duration-100 focus-visible:ring-[3px]',
base: 'group/item focus-visible:border-ring focus-visible:ring-ring/50 flex flex-wrap items-center rounded-4xl border border-transparent text-sm outline-none transition-colors duration-100 focus-visible:ring-[3px]',
variants: {
variant: {
default: 'bg-transparent [a&]:hover:bg-accent/50 [a&]:transition-colors',
@@ -12,8 +12,8 @@
transparent: 'bg-transparent'
},
size: {
default: 'gap-4 p-4',
sm: 'gap-2.5 px-4 py-3'
default: 'gap-4 p-6',
sm: 'gap-2.5 px-4 py-4'
}
},
defaultVariants: {

View File

@@ -1,17 +1,28 @@
import { Popover as PopoverPrimitive } from 'bits-ui';
import Content from './popover-content.svelte';
import Trigger from './popover-trigger.svelte';
const Root = PopoverPrimitive.Root;
const Close = PopoverPrimitive.Close;
import Root from "./popover.svelte";
import Close from "./popover-close.svelte";
import Content from "./popover-content.svelte";
import Description from "./popover-description.svelte";
import Header from "./popover-header.svelte";
import Title from "./popover-title.svelte";
import Trigger from "./popover-trigger.svelte";
import Portal from "./popover-portal.svelte";
export {
Root,
Content,
Description,
Header,
Title,
Trigger,
Close,
Portal,
//
Root as Popover,
Content as PopoverContent,
Description as PopoverDescription,
Header as PopoverHeader,
Title as PopoverTitle,
Trigger as PopoverTrigger,
Close as PopoverClose
Close as PopoverClose,
Portal as PopoverPortal,
};

View File

@@ -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} />

View File

@@ -1,6 +1,8 @@
<script lang="ts">
import { cn } from '$lib/utils/style.js';
import { cn, type WithoutChildrenOrChild } from '$lib/utils/style.js';
import { Popover as PopoverPrimitive } from 'bits-ui';
import type { ComponentProps } from 'svelte';
import PopoverPortal from './popover-portal.svelte';
let {
ref = $bindable(null),
@@ -11,22 +13,22 @@
portalProps,
...restProps
}: PopoverPrimitive.ContentProps & {
portalProps?: PopoverPrimitive.PortalProps;
portalProps?: WithoutChildrenOrChild<ComponentProps<typeof PopoverPortal>>;
sameWidth?: boolean;
} = $props();
</script>
<PopoverPrimitive.Portal {...portalProps}>
<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-right-2 data-[side=right]:slide-in-from-left-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',
'bg-popover text-popover-foreground data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 flex flex-col gap-2.5 rounded-sm p-2.5 text-sm shadow-md ring-1 duration-100 data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2 z-50 w-72 origin-(--transform-origin) outline-hidden',
sameWidth && 'w-[var(--bits-popover-anchor-width)]',
className
)}
{...restProps}
/>
</PopoverPrimitive.Portal>
</PopoverPortal>

View File

@@ -0,0 +1,20 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils/style.js";
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script>
<div
bind:this={ref}
data-slot="popover-description"
class={cn("text-muted-foreground", className)}
{...restProps}
>
{@render children?.()}
</div>

View File

@@ -0,0 +1,20 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils/style.js";
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script>
<div
bind:this={ref}
data-slot="popover-header"
class={cn("flex flex-col gap-0.5 text-sm", className)}
{...restProps}
>
{@render children?.()}
</div>

View File

@@ -0,0 +1,7 @@
<script lang="ts">
import { Popover as PopoverPrimitive } from "bits-ui";
let { ...restProps }: PopoverPrimitive.PortalProps = $props();
</script>
<PopoverPrimitive.Portal {...restProps} />

View File

@@ -0,0 +1,20 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils/style.js";
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script>
<div
bind:this={ref}
data-slot="popover-title"
class={cn("font-medium", className)}
{...restProps}
>
{@render children?.()}
</div>

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { cn } from '$lib/utils/style.js';
import { Popover as PopoverPrimitive } from 'bits-ui';
import { cn } from "$lib/utils/style.js";
import { Popover as PopoverPrimitive } from "bits-ui";
let {
ref = $bindable(null),
@@ -12,6 +12,6 @@
<PopoverPrimitive.Trigger
bind:ref
data-slot="popover-trigger"
class={cn('', className)}
class={cn("", className)}
{...restProps}
/>

View File

@@ -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} />

View File

@@ -1,15 +1,14 @@
import { Select as SelectPrimitive } from 'bits-ui';
import Group from './select-group.svelte';
import Label from './select-label.svelte';
import Item from './select-item.svelte';
import Content from './select-content.svelte';
import Trigger from './select-trigger.svelte';
import Separator from './select-separator.svelte';
import ScrollDownButton from './select-scroll-down-button.svelte';
import ScrollUpButton from './select-scroll-up-button.svelte';
const Root = SelectPrimitive.Root;
import Root from "./select.svelte";
import Group from "./select-group.svelte";
import Label from "./select-label.svelte";
import Item from "./select-item.svelte";
import Content from "./select-content.svelte";
import Trigger from "./select-trigger.svelte";
import Separator from "./select-separator.svelte";
import ScrollDownButton from "./select-scroll-down-button.svelte";
import ScrollUpButton from "./select-scroll-up-button.svelte";
import GroupHeading from "./select-group-heading.svelte";
import Portal from "./select-portal.svelte";
export {
Root,
@@ -21,6 +20,8 @@ export {
Separator,
ScrollDownButton,
ScrollUpButton,
GroupHeading,
Portal,
//
Root as Select,
Group as SelectGroup,
@@ -30,5 +31,7 @@ export {
Trigger as SelectTrigger,
Separator as SelectSeparator,
ScrollDownButton as SelectScrollDownButton,
ScrollUpButton as SelectScrollUpButton
ScrollUpButton as SelectScrollUpButton,
GroupHeading as SelectGroupHeading,
Portal as SelectPortal,
};

View File

@@ -1,8 +1,11 @@
<script lang="ts">
import { Select as SelectPrimitive } from 'bits-ui';
import SelectScrollUpButton from './select-scroll-up-button.svelte';
import SelectScrollDownButton from './select-scroll-down-button.svelte';
import type { WithoutChildrenOrChild } from '$lib/utils/style.js';
import { cn, type WithoutChild } from '$lib/utils/style.js';
import { Select as SelectPrimitive } from 'bits-ui';
import type { ComponentProps } from 'svelte';
import SelectPortal from './select-portal.svelte';
import SelectScrollDownButton from './select-scroll-down-button.svelte';
import SelectScrollUpButton from './select-scroll-up-button.svelte';
let {
ref = $bindable(null),
@@ -10,19 +13,21 @@
sideOffset = 4,
portalProps,
children,
preventScroll = true,
...restProps
}: WithoutChild<SelectPrimitive.ContentProps> & {
portalProps?: SelectPrimitive.PortalProps;
portalProps?: WithoutChildrenOrChild<ComponentProps<typeof SelectPortal>>;
} = $props();
</script>
<SelectPrimitive.Portal {...portalProps}>
<SelectPortal {...portalProps}>
<SelectPrimitive.Content
bind:ref
{sideOffset}
{preventScroll}
data-slot="select-content"
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-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--bits-select-content-available-height) min-w-[8rem] origin-(--bits-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
'bg-popover y-5 p-1 text-popover-foreground data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 min-w-36 rounded-lg shadow-md ring-1 duration-100 data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2 relative isolate z-50 overflow-x-hidden overflow-y-auto',
className
)}
{...restProps}
@@ -30,11 +35,11 @@
<SelectScrollUpButton />
<SelectPrimitive.Viewport
class={cn(
'h-(--bits-select-anchor-height) w-full min-w-(--bits-select-anchor-width) scroll-my-1 p-1'
'h-(--bits-select-anchor-height) w-full min-w-(--bits-select-anchor-width) scroll-my-1'
)}
>
{@render children?.()}
</SelectPrimitive.Viewport>
<SelectScrollDownButton />
</SelectPrimitive.Content>
</SelectPrimitive.Portal>
</SelectPortal>

View File

@@ -0,0 +1,21 @@
<script lang="ts">
import { Select as SelectPrimitive } from "bits-ui";
import { cn } from "$lib/utils/style.js";
import type { ComponentProps } from "svelte";
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: ComponentProps<typeof SelectPrimitive.GroupHeading> = $props();
</script>
<SelectPrimitive.GroupHeading
bind:ref
data-slot="select-group-heading"
class={cn("text-muted-foreground px-2 py-1.5 text-xs", className)}
{...restProps}
>
{@render children?.()}
</SelectPrimitive.GroupHeading>

View File

@@ -1,7 +1,17 @@
<script lang="ts">
import { Select as SelectPrimitive } from 'bits-ui';
import { Select as SelectPrimitive } from "bits-ui";
import { cn } from "$lib/utils/style.js";
let { ref = $bindable(null), ...restProps }: SelectPrimitive.GroupProps = $props();
let {
ref = $bindable(null),
class: className,
...restProps
}: SelectPrimitive.GroupProps = $props();
</script>
<SelectPrimitive.Group data-slot="select-group" {...restProps} />
<SelectPrimitive.Group
bind:ref
data-slot="select-group"
class={cn("scroll-my-1 p-1", className)}
{...restProps}
/>

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { Select as SelectPrimitive } from "bits-ui";
import { cn, type WithoutChild } from "$lib/utils/style.js";
import CheckIcon from '@lucide/svelte/icons/check';
import { Select as SelectPrimitive } from 'bits-ui';
import { cn, type WithoutChild } from '$lib/utils/style.js';
let {
ref = $bindable(null),
@@ -18,15 +18,15 @@
{value}
data-slot="select-item"
class={cn(
"data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
"focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground gap-1.5 rounded-md py-1.5 pr-9 pl-2 text-sm [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2 focus:bg-accent data-highlighted:bg-accent data-highlighted:text-accent-foreground focus:text-accent-foreground relative flex w-full cursor-pointer items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
className
)}
{...restProps}
>
{#snippet children({ selected, highlighted })}
<span class="absolute right-2 flex size-3.5 items-center justify-center">
<span class="absolute end-2 flex size-3.5 items-center justify-center">
{#if selected}
<CheckIcon class="size-4" />
<CheckIcon class="cn-select-item-indicator-icon" />
{/if}
</span>
{#if childrenProp}

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { cn, type WithElementRef } from '$lib/utils/style.js';
import type { HTMLAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from "$lib/utils/style.js";
import type { HTMLAttributes } from "svelte/elements";
let {
ref = $bindable(null),
@@ -13,7 +13,7 @@
<div
bind:this={ref}
data-slot="select-label"
class={cn('text-muted-foreground px-2 py-1.5 text-xs', className)}
class={cn("text-muted-foreground px-1.5 py-1 text-xs", className)}
{...restProps}
>
{@render children?.()}

View File

@@ -0,0 +1,7 @@
<script lang="ts">
import { Select as SelectPrimitive } from "bits-ui";
let { ...restProps }: SelectPrimitive.PortalProps = $props();
</script>
<SelectPrimitive.Portal {...restProps} />

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { Select as SelectPrimitive } from "bits-ui";
import { cn, type WithoutChildrenOrChild } from "$lib/utils/style.js";
import ChevronDownIcon from '@lucide/svelte/icons/chevron-down';
import { Select as SelectPrimitive } from 'bits-ui';
import { cn, type WithoutChildrenOrChild } from '$lib/utils/style.js';
let {
ref = $bindable(null),
@@ -12,9 +12,9 @@
<SelectPrimitive.ScrollDownButton
bind:ref
data-slot="select-scroll-up-button"
class={cn('flex cursor-default items-center justify-center py-1', className)}
data-slot="select-scroll-down-button"
class={cn("bg-popover z-10 flex cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-4 bottom-0 w-full", className)}
{...restProps}
>
<ChevronDownIcon class="size-4" />
<ChevronDownIcon />
</SelectPrimitive.ScrollDownButton>

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { Select as SelectPrimitive } from "bits-ui";
import { cn, type WithoutChildrenOrChild } from "$lib/utils/style.js";
import ChevronUpIcon from '@lucide/svelte/icons/chevron-up';
import { Select as SelectPrimitive } from 'bits-ui';
import { cn, type WithoutChildrenOrChild } from '$lib/utils/style.js';
let {
ref = $bindable(null),
@@ -12,9 +12,9 @@
<SelectPrimitive.ScrollUpButton
bind:ref
data-slot="select-scroll-down-button"
class={cn('flex cursor-default items-center justify-center py-1', className)}
data-slot="select-scroll-up-button"
class={cn("bg-popover z-10 flex cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-4 top-0 w-full", className)}
{...restProps}
>
<ChevronUpIcon class="size-4" />
<ChevronUpIcon />
</SelectPrimitive.ScrollUpButton>

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import type { Separator as SeparatorPrimitive } from 'bits-ui';
import { Separator } from '$lib/components/ui/separator/index.js';
import { cn } from '$lib/utils/style.js';
import type { Separator as SeparatorPrimitive } from "bits-ui";
import { Separator } from "$lib/components/ui/separator/index.js";
import { cn } from "$lib/utils/style.js";
let {
ref = $bindable(null),
@@ -13,6 +13,6 @@
<Separator
bind:ref
data-slot="select-separator"
class={cn('bg-border pointer-events-none -mx-1 my-1 h-px', className)}
class={cn("bg-border -mx-1 my-1 h-px pointer-events-none", className)}
{...restProps}
/>

View File

@@ -1,16 +1,16 @@
<script lang="ts">
import { Select as SelectPrimitive } from 'bits-ui';
import { Select as SelectPrimitive } from "bits-ui";
import { cn, type WithoutChild } from "$lib/utils/style.js";
import ChevronDownIcon from '@lucide/svelte/icons/chevron-down';
import { cn, type WithoutChild } from '$lib/utils/style.js';
let {
ref = $bindable(null),
class: className,
children,
size = 'default',
size = "default",
...restProps
}: WithoutChild<SelectPrimitive.TriggerProps> & {
size?: 'sm' | 'default';
size?: "sm" | "default";
} = $props();
</script>
@@ -19,11 +19,11 @@
data-slot="select-trigger"
data-size={size}
class={cn(
"border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
"border-input data-placeholder:text-muted-foreground dark:bg-input/30 dark:hover:bg-input/50 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 gap-1.5 rounded-full border bg-transparent py-2 px-4 text-sm transition-colors select-none focus-visible:ring-3 aria-invalid:ring-3 data-[size=default]:h-9 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md),10px)] *:data-[slot=select-value]:flex *:data-[slot=select-value]:gap-1.5 [&_svg:not([class*='size-'])]:size-4 flex w-fit items-center justify-between whitespace-nowrap outline-none disabled:cursor-not-allowed disabled:opacity-50 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center [&_svg]:pointer-events-none [&_svg]:shrink-0",
className
)}
{...restProps}
>
{@render children?.()}
<ChevronDownIcon class="size-4 opacity-50" />
<ChevronDownIcon class="text-muted-foreground size-4" />
</SelectPrimitive.Trigger>

View File

@@ -0,0 +1,11 @@
<script lang="ts">
import { Select as SelectPrimitive } from "bits-ui";
let {
open = $bindable(false),
value = $bindable(),
...restProps
}: SelectPrimitive.RootProps = $props();
</script>
<SelectPrimitive.Root bind:open bind:value={value as never} {...restProps} />

View File

@@ -1,7 +1,7 @@
import Root from './separator.svelte';
import Root from "./separator.svelte";
export {
Root,
//
Root as Separator
Root as Separator,
};

View File

@@ -1,19 +1,22 @@
<script lang="ts">
import { Separator as SeparatorPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
import { Separator as SeparatorPrimitive } from "bits-ui";
import { cn } from "$lib/utils/style.js";
let {
ref = $bindable(null),
class: className,
"data-slot": dataSlot = "separator",
...restProps
}: SeparatorPrimitive.RootProps = $props();
</script>
<SeparatorPrimitive.Root
bind:ref
data-slot="separator-root"
data-slot={dataSlot}
class={cn(
'bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px',
"bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-px",
// this is different in shadcn/ui but self-stretch breaks things for us
"data-[orientation=vertical]:h-full",
className
)}
{...restProps}

View File

@@ -23,7 +23,7 @@
<SwitchPrimitive.Thumb
data-slot="switch-thumb"
class={cn(
'bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0'
'bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0'
)}
/>
</SwitchPrimitive.Root>

View File

@@ -1,16 +1,18 @@
import Root from './tabs.svelte';
import Content from './tabs-content.svelte';
import List from './tabs-list.svelte';
import Trigger from './tabs-trigger.svelte';
import Root from "./tabs.svelte";
import Content from "./tabs-content.svelte";
import List, { tabsListVariants, type TabsListVariant } from "./tabs-list.svelte";
import Trigger from "./tabs-trigger.svelte";
export {
Root,
Content,
List,
Trigger,
tabsListVariants,
type TabsListVariant,
//
Root as Tabs,
Content as TabsContent,
List as TabsList,
Trigger as TabsTrigger
Trigger as TabsTrigger,
};

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { Tabs as TabsPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
import { Tabs as TabsPrimitive } from "bits-ui";
import { cn } from "$lib/utils/style.js";
let {
ref = $bindable(null),
@@ -12,6 +12,6 @@
<TabsPrimitive.Content
bind:ref
data-slot="tabs-content"
class={cn('flex-1 outline-none', className)}
class={cn("text-sm flex-1 outline-none", className)}
{...restProps}
/>

View File

@@ -1,16 +1,40 @@
<script lang="ts">
import { cn } from '$lib/utils/style';
import { Tabs as TabsPrimitive } from 'bits-ui';
<script lang="ts" module>
import { tv, type VariantProps } from "tailwind-variants";
let { ref = $bindable(null), class: className, ...restProps }: TabsPrimitive.ListProps = $props();
export const tabsListVariants = tv({
base: "rounded-lg p-[3px] group-data-horizontal/tabs:h-8 data-[variant=line]:rounded-none group/tabs-list text-muted-foreground inline-flex w-fit items-center justify-center group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col",
variants: {
variant: {
default: "cn-tabs-list-variant-default bg-muted",
line: "cn-tabs-list-variant-line gap-1 bg-transparent",
},
},
defaultVariants: {
variant: "default",
},
});
export type TabsListVariant = VariantProps<typeof tabsListVariants>["variant"];
</script>
<script lang="ts">
import { Tabs as TabsPrimitive } from "bits-ui";
import { cn } from "$lib/utils/style.js";
let {
ref = $bindable(null),
variant = "default",
class: className,
...restProps
}: TabsPrimitive.ListProps & {
variant?: TabsListVariant;
} = $props();
</script>
<TabsPrimitive.List
bind:ref
data-slot="tabs-list"
class={cn(
'bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]',
className
)}
data-variant={variant}
class={cn(tabsListVariants({ variant }), className)}
{...restProps}
/>

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { cn } from '$lib/utils/style.js';
import { Tabs as TabsPrimitive } from 'bits-ui';
import { Tabs as TabsPrimitive } from "bits-ui";
import { cn } from "$lib/utils/style.js";
let {
ref = $bindable(null),
@@ -17,4 +17,4 @@
className
)}
{...restProps}
></TabsPrimitive.Trigger>
/>

View File

@@ -1,10 +1,10 @@
<script lang="ts">
import { Tabs as TabsPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
import { Tabs as TabsPrimitive } from "bits-ui";
import { cn } from "$lib/utils/style.js";
let {
ref = $bindable(null),
value = $bindable(''),
value = $bindable(""),
class: className,
...restProps
}: TabsPrimitive.RootProps = $props();
@@ -14,6 +14,6 @@
bind:ref
bind:value
data-slot="tabs"
class={cn('flex flex-col gap-2', className)}
class={cn("gap-2 group/tabs flex data-[orientation=horizontal]:flex-col", className)}
{...restProps}
/>

View File

@@ -1,10 +1,8 @@
import { Tooltip as TooltipPrimitive } from 'bits-ui';
import Trigger from './tooltip-trigger.svelte';
import Content from './tooltip-content.svelte';
const Root = TooltipPrimitive.Root;
const Provider = TooltipPrimitive.Provider;
const Portal = TooltipPrimitive.Portal;
import Root from "./tooltip.svelte";
import Trigger from "./tooltip-trigger.svelte";
import Content from "./tooltip-content.svelte";
import Provider from "./tooltip-provider.svelte";
import Portal from "./tooltip-portal.svelte";
export {
Root,
@@ -17,5 +15,5 @@ export {
Content as TooltipContent,
Trigger as TooltipTrigger,
Provider as TooltipProvider,
Portal as TooltipPortal
Portal as TooltipPortal,
};

View File

@@ -1,28 +1,33 @@
<script lang="ts">
import { Tooltip as TooltipPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
import { Tooltip as TooltipPrimitive } from "bits-ui";
import { cn } from "$lib/utils/style.js";
import TooltipPortal from "./tooltip-portal.svelte";
import type { ComponentProps } from "svelte";
import type { WithoutChildrenOrChild } from "$lib/utils/style.js";
let {
ref = $bindable(null),
class: className,
sideOffset = 0,
side = 'top',
side = "top",
children,
arrowClasses,
portalProps,
...restProps
}: TooltipPrimitive.ContentProps & {
arrowClasses?: string;
portalProps?: WithoutChildrenOrChild<ComponentProps<typeof TooltipPortal>>;
} = $props();
</script>
<TooltipPrimitive.Portal>
<TooltipPortal {...portalProps}>
<TooltipPrimitive.Content
bind:ref
data-slot="tooltip-content"
{sideOffset}
{side}
class={cn(
'bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--bits-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance',
"data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs has-data-[slot=kbd]:pr-1.5 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm bg-foreground text-background z-50 w-fit max-w-xs origin-(--bits-tooltip-content-transform-origin)",
className
)}
{...restProps}
@@ -32,11 +37,11 @@
{#snippet child({ props })}
<div
class={cn(
'bg-primary z-50 size-2.5 rotate-45 rounded-[2px]',
side === 'top' && 'translate-x-1/2 translate-y-[calc(-50%_+_2px)]',
side === 'bottom' && '-translate-x-1/2 -translate-y-[calc(-50%_+_1px)]',
side === 'right' && 'translate-x-[calc(50%_+_2px)] translate-y-1/2',
side === 'left' && '-translate-y-[calc(50%_-_3px)]',
"size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground z-50",
"data-[side=top]:translate-x-1/2 data-[side=top]:translate-y-[calc(-50%+2px)]",
"data-[side=bottom]:-translate-x-1/2 data-[side=bottom]:-translate-y-[calc(-50%+1px)]",
"data-[side=right]:translate-x-[calc(50%+2px)] data-[side=right]:translate-y-1/2",
"data-[side=left]:-translate-y-[calc(50%-3px)]",
arrowClasses
)}
{...props}
@@ -44,4 +49,4 @@
{/snippet}
</TooltipPrimitive.Arrow>
</TooltipPrimitive.Content>
</TooltipPrimitive.Portal>
</TooltipPortal>

View File

@@ -0,0 +1,7 @@
<script lang="ts">
import { Tooltip as TooltipPrimitive } from "bits-ui";
let { ...restProps }: TooltipPrimitive.PortalProps = $props();
</script>
<TooltipPrimitive.Portal {...restProps} />

View File

@@ -0,0 +1,7 @@
<script lang="ts">
import { Tooltip as TooltipPrimitive } from "bits-ui";
let { delayDuration = 0, ...restProps }: TooltipPrimitive.ProviderProps = $props();
</script>
<TooltipPrimitive.Provider {delayDuration} {...restProps} />

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import { Tooltip as TooltipPrimitive } from 'bits-ui';
import { Tooltip as TooltipPrimitive } from "bits-ui";
let { ref = $bindable(null), ...restProps }: TooltipPrimitive.TriggerProps = $props();
</script>

View File

@@ -0,0 +1,7 @@
<script lang="ts">
import { Tooltip as TooltipPrimitive } from "bits-ui";
let { open = $bindable(false), ...restProps }: TooltipPrimitive.RootProps = $props();
</script>
<TooltipPrimitive.Root bind:open {...restProps} />

View File

@@ -7,7 +7,7 @@
<div class="bg-muted mx-auto rounded-2xl p-3">
<Logo class="size-10" />
</div>
<p class="font-playfair mt-5 text-3xl font-bold sm:text-4xl">{m.browser_unsupported()}</p>
<p class="font-glooock mt-5 text-3xl font-bold sm:text-4xl">{m.browser_unsupported()}</p>
<p class="text-muted-foreground mt-3">
{m.this_browser_does_not_support_passkeys()}
</p>

View File

@@ -265,7 +265,7 @@
{:else}
<SignInWrapper showAlternativeSignInMethodButton={$userStore == null}>
<ClientProviderImages {client} {success} error={!!errorMessage} />
<h1 class="font-playfair mt-5 text-3xl font-bold sm:text-4xl">
<h1 class="font-glooock mt-5 text-3xl font-bold sm:text-4xl">
{m.sign_in_to({ name: client.name })}
</h1>
{#if errorMessage}

View File

@@ -79,7 +79,7 @@
<LoginLogoErrorSuccessIndicator {success} error={!!errorMessage} />
{/if}
</div>
<h1 class="font-playfair mt-5 text-4xl font-bold">{m.authorize_device()}</h1>
<h1 class="font-glooock mt-5 text-4xl font-bold">{m.authorize_device()}</h1>
{#if errorMessage}
<p class="text-muted-foreground mt-2">
{errorMessage}. {m.please_try_again()}

View File

@@ -44,7 +44,7 @@
<div class="flex justify-center">
<LoginLogoErrorSuccessIndicator error={!!error} />
</div>
<h1 class="font-playfair mt-5 text-3xl font-bold sm:text-4xl">
<h1 class="font-glooock mt-5 text-3xl font-bold sm:text-4xl">
{m.sign_in_to_appname({ appName: $appConfigStore.appName })}
</h1>
{#if error}

View File

@@ -35,7 +35,7 @@
<div class="bg-muted mx-auto rounded-2xl p-3">
<Logo class="size-10" />
</div>
<h1 class="font-playfair mt-5 text-3xl font-bold sm:text-4xl">{m.alternative_sign_in()}</h1>
<h1 class="font-glooock mt-5 text-3xl font-bold sm:text-4xl">{m.alternative_sign_in()}</h1>
<p class="text-muted-foreground mt-3">
{m.if_you_do_not_have_access_to_your_passkey_you_can_sign_in_using_one_of_the_following_methods()}
</p>

View File

@@ -59,7 +59,7 @@
<div class="flex justify-center">
<LoginLogoErrorSuccessIndicator error={!!error} />
</div>
<h1 class="font-playfair mt-5 text-4xl font-bold">{m.login_code()}</h1>
<h1 class="font-glooock mt-5 text-4xl font-bold">{m.login_code()}</h1>
{#if error}
<p class="text-muted-foreground mt-2">
{error}. {m.please_try_again()}

View File

@@ -5,9 +5,9 @@
import Input from '$lib/components/ui/input/input.svelte';
import { m } from '$lib/paraglide/messages';
import UserService from '$lib/services/user-service';
import { preventDefault } from '$lib/utils/event-util';
import { fade } from 'svelte/transition';
import LoginLogoErrorSuccessIndicator from '../../components/login-logo-error-success-indicator.svelte';
import { preventDefault } from '$lib/utils/event-util';
const { data } = $props();
@@ -37,7 +37,7 @@
<div class="flex justify-center">
<LoginLogoErrorSuccessIndicator {success} error={!!error} />
</div>
<h1 class="font-playfair mt-5 text-3xl font-bold sm:text-4xl">{m.email_login()}</h1>
<h1 class="font-glooock mt-5 text-3xl font-bold sm:text-4xl">{m.email_login()}</h1>
{#if error}
<p class="text-muted-foreground mt-2" in:fade>
{error}. {m.please_try_again()}

View File

@@ -34,7 +34,7 @@
<Logo class="size-10" />
</div>
</div>
<h1 class="font-playfair mt-5 text-4xl font-bold">{m.sign_out()}</h1>
<h1 class="font-glooock mt-5 text-4xl">{m.sign_out()}</h1>
<p class="text-muted-foreground mt-2">
<FormattedMessage

View File

@@ -4,7 +4,6 @@
import Sidebar from '$lib/components/sidebar.svelte';
import { m } from '$lib/paraglide/messages';
import userStore from '$lib/stores/user-store';
import { LucideSettings } from '@lucide/svelte';
import type { Snippet } from 'svelte';
import { fade, fly } from 'svelte/transition';
import type { LayoutData } from './$types';
@@ -46,7 +45,7 @@
<section>
<div
class="bg-muted/40 dark:bg-background flex min-h-[calc(100vh-64px)] w-full flex-col justify-between"
class="bg-muted/40 dark:bg-background flex min-h-[calc(100vh-86px)] w-full flex-col justify-between"
>
<main
in:fade={{ duration: 200 }}
@@ -54,13 +53,6 @@
>
<div class="min-w-[200px] xl:min-w-[250px]">
<div in:fly={{ x: -15, duration: 200 }} class="sticky top-6">
<div class="mx-auto grid w-full gap-2">
<h1 class="mb-4 flex items-center gap-2 text-2xl font-semibold">
<LucideSettings class="size-5" />
{m.settings()}
</h1>
</div>
<Sidebar
{items}
storageKey="sidebar-open:settings"
@@ -70,7 +62,7 @@
</div>
</div>
<div class="flex w-full flex-col gap-4 overflow-hidden">
<div class="flex w-full flex-col gap-4 overflow-hidden pb-2">
<FadeWrapper>
<EmailVerificationStateBox />
{@render children()}

View File

@@ -141,7 +141,7 @@
</Card.Content>
</Card.Root>
<Item.Group class="bg-card rounded-xl border p-4 shadow-sm">
<Item.Group class="bg-card border shadow-sm rounded-4xl p-5">
<Item.Root class="border-none bg-transparent p-0">
<Item.Media class="text-primary/80">
<KeyRound class="size-5" />

Some files were not shown because too many files have changed in this diff Show More