feature: add necessary shadcn components for CategoryFilter and Sidebar
This commit is contained in:
108
src/shared/ui/sidebar/sidebar-menu-button.svelte
Normal file
108
src/shared/ui/sidebar/sidebar-menu-button.svelte
Normal file
@@ -0,0 +1,108 @@
|
||||
<script lang="ts" module>
|
||||
import { tv, type VariantProps } from 'tailwind-variants';
|
||||
|
||||
export const sidebarMenuButtonVariants = tv({
|
||||
base:
|
||||
'peer/menu-button ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-start text-sm outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pe-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:font-medium [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',
|
||||
variants: {
|
||||
variant: {
|
||||
default: 'hover:bg-sidebar-accent hover:text-sidebar-accent-foreground',
|
||||
outline:
|
||||
'bg-background hover:bg-sidebar-accent hover:text-sidebar-accent-foreground shadow-[0_0_0_1px_var(--sidebar-border)] hover:shadow-[0_0_0_1px_var(--sidebar-accent)]',
|
||||
},
|
||||
size: {
|
||||
default: 'h-8 text-sm',
|
||||
sm: 'h-7 text-xs',
|
||||
lg: 'h-12 text-sm group-data-[collapsible=icon]:p-0!',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default',
|
||||
size: 'default',
|
||||
},
|
||||
});
|
||||
|
||||
export type SidebarMenuButtonVariant = VariantProps<
|
||||
typeof sidebarMenuButtonVariants
|
||||
>['variant'];
|
||||
export type SidebarMenuButtonSize = VariantProps<typeof sidebarMenuButtonVariants>['size'];
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import * as Tooltip from '$shared/ui/tooltip/index.js';
|
||||
import {
|
||||
cn,
|
||||
type WithElementRef,
|
||||
type WithoutChildrenOrChild,
|
||||
} from '$shared/utils/shadcn-utils.js';
|
||||
import { mergeProps } from 'bits-ui';
|
||||
import type { ComponentProps, Snippet } from 'svelte';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
import { useSidebar } from './context.svelte.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
children,
|
||||
child,
|
||||
variant = 'default',
|
||||
size = 'default',
|
||||
isActive = false,
|
||||
tooltipContent,
|
||||
tooltipContentProps,
|
||||
...restProps
|
||||
}: WithElementRef<HTMLAttributes<HTMLButtonElement>, HTMLButtonElement> & {
|
||||
isActive?: boolean;
|
||||
variant?: SidebarMenuButtonVariant;
|
||||
size?: SidebarMenuButtonSize;
|
||||
tooltipContent?: Snippet | string;
|
||||
tooltipContentProps?: WithoutChildrenOrChild<ComponentProps<typeof Tooltip.Content>>;
|
||||
child?: Snippet<[{ props: Record<string, unknown> }]>;
|
||||
} = $props();
|
||||
|
||||
const sidebar = useSidebar();
|
||||
|
||||
const buttonProps = $derived({
|
||||
class: cn(sidebarMenuButtonVariants({ variant, size }), className),
|
||||
'data-slot': 'sidebar-menu-button',
|
||||
'data-sidebar': 'menu-button',
|
||||
'data-size': size,
|
||||
'data-active': isActive,
|
||||
...restProps,
|
||||
});
|
||||
</script>
|
||||
|
||||
{#snippet Button({ props }: { props?: Record<string, unknown> })}
|
||||
{@const mergedProps = mergeProps(buttonProps, props)}
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<button bind:this={ref} {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</button>
|
||||
{/if}
|
||||
{/snippet}
|
||||
|
||||
{#if !tooltipContent}
|
||||
{@render Button({})}
|
||||
{:else}
|
||||
<Tooltip.Root>
|
||||
<Tooltip.Trigger>
|
||||
{#snippet child({ props })}
|
||||
{@render Button({ props })}
|
||||
{/snippet}
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Content
|
||||
side="right"
|
||||
align="center"
|
||||
hidden={sidebar.state !== 'collapsed' || sidebar.isMobile}
|
||||
{...tooltipContentProps}
|
||||
>
|
||||
{#if typeof tooltipContent === 'string'}
|
||||
{tooltipContent}
|
||||
{:else if tooltipContent}
|
||||
{@render tooltipContent()}
|
||||
{/if}
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Root>
|
||||
{/if}
|
||||
Reference in New Issue
Block a user