feature/build #1

Open
Tobi wants to merge 43 commits from feature/build into develop
21 changed files with 369 additions and 353 deletions
Showing only changes of commit cce1dfff33 - Show all commits

View File

@@ -21,8 +21,9 @@ jobs:
id: cache-key id: cache-key
run: echo "key=bun-${{ hashFiles('**/bun.lock') }}" >> $GITHUB_OUTPUT run: echo "key=bun-${{ hashFiles('**/bun.lock') }}" >> $GITHUB_OUTPUT
- name: Cache node_modules - name: Restore node_modules cache
uses: actions/cache@v4 id: cache-restore
uses: actions/cache/restore@v4
with: with:
path: node_modules path: node_modules
key: ${{ steps.cache-key.outputs.key }} key: ${{ steps.cache-key.outputs.key }}
@@ -30,8 +31,16 @@ jobs:
bun- bun-
- name: Install dependencies - name: Install dependencies
if: steps.cache-restore.outputs.cache-hit != 'true'
run: bun install --frozen-lockfile run: bun install --frozen-lockfile
- name: Save node_modules cache
if: steps.cache-restore.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: node_modules
key: ${{ steps.cache-key.outputs.key }}
type-check: type-check:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
@@ -42,7 +51,7 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Restore node_modules - name: Restore node_modules
uses: actions/cache@v4 uses: actions/cache/restore@v4
with: with:
path: node_modules path: node_modules
key: ${{ needs.install.outputs.cache-key }} key: ${{ needs.install.outputs.cache-key }}
@@ -62,7 +71,7 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Restore node_modules - name: Restore node_modules
uses: actions/cache@v4 uses: actions/cache/restore@v4
with: with:
path: node_modules path: node_modules
key: ${{ needs.install.outputs.cache-key }} key: ${{ needs.install.outputs.cache-key }}
@@ -70,7 +79,7 @@ jobs:
bun- bun-
- name: Run linting - name: Run linting
run: bun run lint run: bun run lint:check
format-check: format-check:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -82,7 +91,7 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Restore node_modules - name: Restore node_modules
uses: actions/cache@v4 uses: actions/cache/restore@v4
with: with:
path: node_modules path: node_modules
key: ${{ needs.install.outputs.cache-key }} key: ${{ needs.install.outputs.cache-key }}
@@ -90,7 +99,7 @@ jobs:
bun- bun-
- name: Check formatting - name: Check formatting
run: bun exec prettier --check . run: bun run format:check
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -102,7 +111,7 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Restore node_modules - name: Restore node_modules
uses: actions/cache@v4 uses: actions/cache/restore@v4
with: with:
path: node_modules path: node_modules
key: ${{ needs.install.outputs.cache-key }} key: ${{ needs.install.outputs.cache-key }}

View File

@@ -11,7 +11,8 @@
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"format": "prettier --write .", "format": "prettier --write .",
"lint": "prettier --check . && eslint ." "format:check": "prettier --check",
"lint:check": "eslint ."
}, },
"devDependencies": { "devDependencies": {
"@eslint/compat": "^1.4.0", "@eslint/compat": "^1.4.0",

View File

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

View File

@@ -1,10 +1,10 @@
import Root from "./card.svelte"; import Root from './card.svelte'
import Content from "./card-content.svelte"; import Content from './card-content.svelte'
import Description from "./card-description.svelte"; import Description from './card-description.svelte'
import Footer from "./card-footer.svelte"; import Footer from './card-footer.svelte'
import Header from "./card-header.svelte"; import Header from './card-header.svelte'
import Title from "./card-title.svelte"; import Title from './card-title.svelte'
import Action from "./card-action.svelte"; import Action from './card-action.svelte'
export { export {
Root, Root,
@@ -22,4 +22,4 @@ export {
Header as CardHeader, Header as CardHeader,
Title as CardTitle, Title as CardTitle,
Action as CardAction, Action as CardAction,
}; }

View File

@@ -1,58 +1,60 @@
import type { WithElementRef } from "$lib/utils.js"; import type { WithElementRef } from '$lib/utils.js'
import type { import type {
EmblaCarouselSvelteType, EmblaCarouselSvelteType,
default as emblaCarouselSvelte, default as emblaCarouselSvelte,
} from "embla-carousel-svelte"; } from 'embla-carousel-svelte'
import { getContext, hasContext, setContext } from "svelte"; import { getContext, hasContext, setContext } from 'svelte'
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from 'svelte/elements'
export type CarouselAPI = export type CarouselAPI =
NonNullable<NonNullable<EmblaCarouselSvelteType["$$_attributes"]>["on:emblaInit"]> extends ( NonNullable<
evt: CustomEvent<infer CarouselAPI> NonNullable<EmblaCarouselSvelteType['$$_attributes']>['on:emblaInit']
) => void > extends (evt: CustomEvent<infer CarouselAPI>) => void
? CarouselAPI ? CarouselAPI
: never; : never
type EmblaCarouselConfig = NonNullable<Parameters<typeof emblaCarouselSvelte>[1]>; type EmblaCarouselConfig = NonNullable<
Parameters<typeof emblaCarouselSvelte>[1]
>
export type CarouselOptions = EmblaCarouselConfig["options"]; export type CarouselOptions = EmblaCarouselConfig['options']
export type CarouselPlugins = EmblaCarouselConfig["plugins"]; export type CarouselPlugins = EmblaCarouselConfig['plugins']
//// ////
export type CarouselProps = { export type CarouselProps = {
opts?: CarouselOptions; opts?: CarouselOptions
plugins?: CarouselPlugins; plugins?: CarouselPlugins
setApi?: (api: CarouselAPI | undefined) => void; setApi?: (api: CarouselAPI | undefined) => void
orientation?: "horizontal" | "vertical"; orientation?: 'horizontal' | 'vertical'
} & WithElementRef<HTMLAttributes<HTMLDivElement>>; } & WithElementRef<HTMLAttributes<HTMLDivElement>>
const EMBLA_CAROUSEL_CONTEXT = Symbol("EMBLA_CAROUSEL_CONTEXT"); const EMBLA_CAROUSEL_CONTEXT = Symbol('EMBLA_CAROUSEL_CONTEXT')
export type EmblaContext = { export type EmblaContext = {
api: CarouselAPI | undefined; api: CarouselAPI | undefined
orientation: "horizontal" | "vertical"; orientation: 'horizontal' | 'vertical'
scrollNext: () => void; scrollNext: () => void
scrollPrev: () => void; scrollPrev: () => void
canScrollNext: boolean; canScrollNext: boolean
canScrollPrev: boolean; canScrollPrev: boolean
handleKeyDown: (e: KeyboardEvent) => void; handleKeyDown: (e: KeyboardEvent) => void
options: CarouselOptions; options: CarouselOptions
plugins: CarouselPlugins; plugins: CarouselPlugins
onInit: (e: CustomEvent<CarouselAPI>) => void; onInit: (e: CustomEvent<CarouselAPI>) => void
scrollTo: (index: number, jump?: boolean) => void; scrollTo: (index: number, jump?: boolean) => void
scrollSnaps: number[]; scrollSnaps: number[]
selectedIndex: number; selectedIndex: number
}; }
export function setEmblaContext(config: EmblaContext): EmblaContext { export function setEmblaContext(config: EmblaContext): EmblaContext {
setContext(EMBLA_CAROUSEL_CONTEXT, config); setContext(EMBLA_CAROUSEL_CONTEXT, config)
return config; return config
} }
export function getEmblaContext(name = "This component") { export function getEmblaContext(name = 'This component') {
if (!hasContext(EMBLA_CAROUSEL_CONTEXT)) { if (!hasContext(EMBLA_CAROUSEL_CONTEXT)) {
throw new Error(`${name} must be used within a <Carousel.Root> component`); throw new Error(`${name} must be used within a <Carousel.Root> component`)
} }
return getContext<ReturnType<typeof setEmblaContext>>(EMBLA_CAROUSEL_CONTEXT); return getContext<ReturnType<typeof setEmblaContext>>(EMBLA_CAROUSEL_CONTEXT)
} }

View File

@@ -1,8 +1,8 @@
import Root from "./carousel.svelte"; import Root from './carousel.svelte'
import Content from "./carousel-content.svelte"; import Content from './carousel-content.svelte'
import Item from "./carousel-item.svelte"; import Item from './carousel-item.svelte'
import Previous from "./carousel-previous.svelte"; import Previous from './carousel-previous.svelte'
import Next from "./carousel-next.svelte"; import Next from './carousel-next.svelte'
export { export {
Root, Root,
@@ -16,4 +16,4 @@ export {
Item as CarouselItem, Item as CarouselItem,
Previous as CarouselPrevious, Previous as CarouselPrevious,
Next as CarouselNext, Next as CarouselNext,
}; }

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
import Root from "./radio-group.svelte"; import Root from './radio-group.svelte'
import Item from "./radio-group-item.svelte"; import Item from './radio-group-item.svelte'
export { export {
Root, Root,
@@ -7,4 +7,4 @@ export {
// //
Root as RadioGroup, Root as RadioGroup,
Item as RadioGroupItem, Item as RadioGroupItem,
}; }

View File

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

View File

@@ -1,15 +1,15 @@
import { Dialog as SheetPrimitive } from "bits-ui"; import { Dialog as SheetPrimitive } from 'bits-ui'
import Trigger from "./sheet-trigger.svelte"; import Trigger from './sheet-trigger.svelte'
import Close from "./sheet-close.svelte"; import Close from './sheet-close.svelte'
import Overlay from "./sheet-overlay.svelte"; import Overlay from './sheet-overlay.svelte'
import Content from "./sheet-content.svelte"; import Content from './sheet-content.svelte'
import Header from "./sheet-header.svelte"; import Header from './sheet-header.svelte'
import Footer from "./sheet-footer.svelte"; import Footer from './sheet-footer.svelte'
import Title from "./sheet-title.svelte"; import Title from './sheet-title.svelte'
import Description from "./sheet-description.svelte"; import Description from './sheet-description.svelte'
const Root = SheetPrimitive.Root; const Root = SheetPrimitive.Root
const Portal = SheetPrimitive.Portal; const Portal = SheetPrimitive.Portal
export { export {
Root, Root,
@@ -33,4 +33,4 @@ export {
Footer as SheetFooter, Footer as SheetFooter,
Title as SheetTitle, Title as SheetTitle,
Description as SheetDescription, Description as SheetDescription,
}; }

View File

@@ -1,6 +1,6 @@
export const SIDEBAR_COOKIE_NAME = "sidebar:state"; export const SIDEBAR_COOKIE_NAME = 'sidebar:state'
export const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7; export const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7
export const SIDEBAR_WIDTH = "16rem"; export const SIDEBAR_WIDTH = '16rem'
export const SIDEBAR_WIDTH_MOBILE = "18rem"; export const SIDEBAR_WIDTH_MOBILE = '18rem'
export const SIDEBAR_WIDTH_ICON = "3rem"; export const SIDEBAR_WIDTH_ICON = '3rem'
export const SIDEBAR_KEYBOARD_SHORTCUT = "b"; export const SIDEBAR_KEYBOARD_SHORTCUT = 'b'

View File

@@ -1,8 +1,8 @@
import { IsMobile } from "$lib/hooks/is-mobile.svelte.js"; import { IsMobile } from '$lib/hooks/is-mobile.svelte.js'
import { getContext, setContext } from "svelte"; import { getContext, setContext } from 'svelte'
import { SIDEBAR_KEYBOARD_SHORTCUT } from "./constants.js"; import { SIDEBAR_KEYBOARD_SHORTCUT } from './constants.js'
type Getter<T> = () => T; type Getter<T> = () => T
export type SidebarStateProps = { export type SidebarStateProps = {
/** /**
@@ -10,56 +10,56 @@ export type SidebarStateProps = {
* We use a getter function here to support `bind:open` on the `Sidebar.Provider` * We use a getter function here to support `bind:open` on the `Sidebar.Provider`
* component. * component.
*/ */
open: Getter<boolean>; open: Getter<boolean>
/** /**
* A function that sets the open state of the sidebar. To support `bind:open`, we need * A function that sets the open state of the sidebar. To support `bind:open`, we need
* a source of truth for changing the open state to ensure it will be synced throughout * a source of truth for changing the open state to ensure it will be synced throughout
* the sub-components and any `bind:` references. * the sub-components and any `bind:` references.
*/ */
setOpen: (open: boolean) => void; setOpen: (open: boolean) => void
}; }
class SidebarState { class SidebarState {
readonly props: SidebarStateProps; readonly props: SidebarStateProps
open = $derived.by(() => this.props.open()); open = $derived.by(() => this.props.open())
openMobile = $state(false); openMobile = $state(false)
setOpen: SidebarStateProps["setOpen"]; setOpen: SidebarStateProps['setOpen']
#isMobile: IsMobile; #isMobile: IsMobile
state = $derived.by(() => (this.open ? "expanded" : "collapsed")); state = $derived.by(() => (this.open ? 'expanded' : 'collapsed'))
constructor(props: SidebarStateProps) { constructor(props: SidebarStateProps) {
this.setOpen = props.setOpen; this.setOpen = props.setOpen
this.#isMobile = new IsMobile(); this.#isMobile = new IsMobile()
this.props = props; this.props = props
} }
// Convenience getter for checking if the sidebar is mobile // Convenience getter for checking if the sidebar is mobile
// without this, we would need to use `sidebar.isMobile.current` everywhere // without this, we would need to use `sidebar.isMobile.current` everywhere
get isMobile() { get isMobile() {
return this.#isMobile.current; return this.#isMobile.current
} }
// Event handler to apply to the `<svelte:window>` // Event handler to apply to the `<svelte:window>`
handleShortcutKeydown = (e: KeyboardEvent) => { handleShortcutKeydown = (e: KeyboardEvent) => {
if (e.key === SIDEBAR_KEYBOARD_SHORTCUT && (e.metaKey || e.ctrlKey)) { if (e.key === SIDEBAR_KEYBOARD_SHORTCUT && (e.metaKey || e.ctrlKey)) {
e.preventDefault(); e.preventDefault()
this.toggle(); this.toggle()
}
} }
};
setOpenMobile = (value: boolean) => { setOpenMobile = (value: boolean) => {
this.openMobile = value; this.openMobile = value
}; }
toggle = () => { toggle = () => {
return this.#isMobile.current return this.#isMobile.current
? (this.openMobile = !this.openMobile) ? (this.openMobile = !this.openMobile)
: this.setOpen(!this.open); : this.setOpen(!this.open)
}; }
} }
const SYMBOL_KEY = "scn-sidebar"; const SYMBOL_KEY = 'scn-sidebar'
/** /**
* Instantiates a new `SidebarState` instance and sets it in the context. * Instantiates a new `SidebarState` instance and sets it in the context.
@@ -68,7 +68,7 @@ const SYMBOL_KEY = "scn-sidebar";
* @returns The `SidebarState` instance. * @returns The `SidebarState` instance.
*/ */
export function setSidebar(props: SidebarStateProps): SidebarState { export function setSidebar(props: SidebarStateProps): SidebarState {
return setContext(Symbol.for(SYMBOL_KEY), new SidebarState(props)); return setContext(Symbol.for(SYMBOL_KEY), new SidebarState(props))
} }
/** /**
@@ -77,5 +77,5 @@ export function setSidebar(props: SidebarStateProps): SidebarState {
* @returns The `SidebarState` instance. * @returns The `SidebarState` instance.
*/ */
export function useSidebar(): SidebarState { export function useSidebar(): SidebarState {
return getContext(Symbol.for(SYMBOL_KEY)); return getContext(Symbol.for(SYMBOL_KEY))
} }

View File

@@ -1,27 +1,27 @@
import { useSidebar } from "./context.svelte.js"; import { useSidebar } from './context.svelte.js'
import Content from "./sidebar-content.svelte"; import Content from './sidebar-content.svelte'
import Footer from "./sidebar-footer.svelte"; import Footer from './sidebar-footer.svelte'
import GroupAction from "./sidebar-group-action.svelte"; import GroupAction from './sidebar-group-action.svelte'
import GroupContent from "./sidebar-group-content.svelte"; import GroupContent from './sidebar-group-content.svelte'
import GroupLabel from "./sidebar-group-label.svelte"; import GroupLabel from './sidebar-group-label.svelte'
import Group from "./sidebar-group.svelte"; import Group from './sidebar-group.svelte'
import Header from "./sidebar-header.svelte"; import Header from './sidebar-header.svelte'
import Input from "./sidebar-input.svelte"; import Input from './sidebar-input.svelte'
import Inset from "./sidebar-inset.svelte"; import Inset from './sidebar-inset.svelte'
import MenuAction from "./sidebar-menu-action.svelte"; import MenuAction from './sidebar-menu-action.svelte'
import MenuBadge from "./sidebar-menu-badge.svelte"; import MenuBadge from './sidebar-menu-badge.svelte'
import MenuButton from "./sidebar-menu-button.svelte"; import MenuButton from './sidebar-menu-button.svelte'
import MenuItem from "./sidebar-menu-item.svelte"; import MenuItem from './sidebar-menu-item.svelte'
import MenuSkeleton from "./sidebar-menu-skeleton.svelte"; import MenuSkeleton from './sidebar-menu-skeleton.svelte'
import MenuSubButton from "./sidebar-menu-sub-button.svelte"; import MenuSubButton from './sidebar-menu-sub-button.svelte'
import MenuSubItem from "./sidebar-menu-sub-item.svelte"; import MenuSubItem from './sidebar-menu-sub-item.svelte'
import MenuSub from "./sidebar-menu-sub.svelte"; import MenuSub from './sidebar-menu-sub.svelte'
import Menu from "./sidebar-menu.svelte"; import Menu from './sidebar-menu.svelte'
import Provider from "./sidebar-provider.svelte"; import Provider from './sidebar-provider.svelte'
import Rail from "./sidebar-rail.svelte"; import Rail from './sidebar-rail.svelte'
import Separator from "./sidebar-separator.svelte"; import Separator from './sidebar-separator.svelte'
import Trigger from "./sidebar-trigger.svelte"; import Trigger from './sidebar-trigger.svelte'
import Root from "./sidebar.svelte"; import Root from './sidebar.svelte'
export { export {
Content, Content,
@@ -72,4 +72,4 @@ export {
Trigger as SidebarTrigger, Trigger as SidebarTrigger,
Trigger, Trigger,
useSidebar, useSidebar,
}; }

View File

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

View File

@@ -1,7 +1,7 @@
import Root from "./tabs.svelte"; import Root from './tabs.svelte'
import Content from "./tabs-content.svelte"; import Content from './tabs-content.svelte'
import List from "./tabs-list.svelte"; import List from './tabs-list.svelte'
import Trigger from "./tabs-trigger.svelte"; import Trigger from './tabs-trigger.svelte'
export { export {
Root, Root,
@@ -13,4 +13,4 @@ export {
Content as TabsContent, Content as TabsContent,
List as TabsList, List as TabsList,
Trigger as TabsTrigger, Trigger as TabsTrigger,
}; }

View File

@@ -1,10 +1,10 @@
import { Tooltip as TooltipPrimitive } from "bits-ui"; import { Tooltip as TooltipPrimitive } from 'bits-ui'
import Trigger from "./tooltip-trigger.svelte"; import Trigger from './tooltip-trigger.svelte'
import Content from "./tooltip-content.svelte"; import Content from './tooltip-content.svelte'
const Root = TooltipPrimitive.Root; const Root = TooltipPrimitive.Root
const Provider = TooltipPrimitive.Provider; const Provider = TooltipPrimitive.Provider
const Portal = TooltipPrimitive.Portal; const Portal = TooltipPrimitive.Portal
export { export {
Root, Root,
@@ -18,4 +18,4 @@ export {
Trigger as TooltipTrigger, Trigger as TooltipTrigger,
Provider as TooltipProvider, Provider as TooltipProvider,
Portal as TooltipPortal, Portal as TooltipPortal,
}; }

View File

@@ -1,13 +1,17 @@
import { clsx, type ClassValue } from "clsx"; import { clsx, type ClassValue } from 'clsx'
import { twMerge } from "tailwind-merge"; import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]) { export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs)); return twMerge(clsx(inputs))
} }
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
export type WithoutChild<T> = T extends { child?: any } ? Omit<T, "child"> : T; export type WithoutChild<T> = T extends { child?: any } ? Omit<T, 'child'> : T
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
export type WithoutChildren<T> = T extends { children?: any } ? Omit<T, "children"> : T; export type WithoutChildren<T> = T extends { children?: any }
export type WithoutChildrenOrChild<T> = WithoutChildren<WithoutChild<T>>; ? Omit<T, 'children'>
export type WithElementRef<T, U extends HTMLElement = HTMLElement> = T & { ref?: U | null }; : T
export type WithoutChildrenOrChild<T> = WithoutChildren<WithoutChild<T>>
export type WithElementRef<T, U extends HTMLElement = HTMLElement> = T & {
ref?: U | null
}