diff --git a/.gitignore b/.gitignore index 7e94f3d..06e6b23 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ Thumbs.db # Yarn .yarn +.yarn/** .pnp.* # Zed @@ -32,3 +33,4 @@ vite.config.js.timestamp-* vite.config.ts.timestamp-* /docs +AGENTS.md diff --git a/.yarn/install-state.gz b/.yarn/install-state.gz index ef90f75..adf660e 100644 Binary files a/.yarn/install-state.gz and b/.yarn/install-state.gz differ diff --git a/components.json b/components.json index b723574..ffab50d 100644 --- a/components.json +++ b/components.json @@ -5,11 +5,11 @@ "baseColor": "zinc" }, "aliases": { - "components": "$lib/components", - "utils": "$lib/utils", - "ui": "$lib/components/ui", - "hooks": "$lib/hooks", - "lib": "$lib" + "components": "$shared/shadcn/ui", + "utils": "$shared/shadcn/utils/shadcn-utils", + "ui": "$shared/shadcn/ui", + "hooks": "$shared/shadcn/hooks", + "lib": "$shared" }, "typescript": true, "registry": "https://shadcn-svelte.com/registry" diff --git a/dprint.json b/dprint.json index 8c057ab..bc8bd21 100644 --- a/dprint.json +++ b/dprint.json @@ -1,4 +1,5 @@ { + "$schema": "https://dprint.dev/schemas/v0.json", "incremental": true, "includes": ["**/*.{ts,tsx,js,jsx,svelte,json,md}"], "excludes": [ @@ -22,7 +23,15 @@ "quoteStyle": "preferSingle", "trailingCommas": "onlyMultiLine", "arrowFunction.useParentheses": "preferNone", - "importDeclaration.sortNamedImports": "caseInsensitive" + + "module.sortImportDeclarations": "caseSensitive", + "module.sortExportDeclarations": "caseSensitive", + "importDeclaration.sortNamedImports": "caseSensitive", + + "importDeclaration.forceMultiLine": "whenMultiple", + "importDeclaration.forceSingleLine": false, + "exportDeclaration.forceMultiLine": "whenMultiple", + "exportDeclaration.forceSingleLine": false }, "json": { "indentWidth": 2, @@ -36,7 +45,11 @@ "indentWidth": 4, "useTabs": false, "quotes": "double", - "scriptIndent": true, - "styleIndent": true + "scriptIndent": false, + "styleIndent": false, + + "vBindStyle": "short", + "vOnStyle": "short", + "formatComments": true } } diff --git a/e2e/demo.test.ts b/e2e/demo.test.ts index cad77f2..11af6a2 100644 --- a/e2e/demo.test.ts +++ b/e2e/demo.test.ts @@ -1,4 +1,7 @@ -import { expect, test } from '@playwright/test'; +import { + expect, + test, +} from '@playwright/test'; test('home page has expected h1', async ({ page }) => { await page.goto('/'); diff --git a/package.json b/package.json index 43560de..81c5592 100644 --- a/package.json +++ b/package.json @@ -17,16 +17,20 @@ "test": "npm run test:e2e" }, "devDependencies": { - "@lucide/svelte": "^0.562.0", + "@internationalized/date": "^3.10.0", + "@lucide/svelte": "^0.561.0", "@playwright/test": "^1.57.0", "@sveltejs/vite-plugin-svelte": "^6.2.1", "@tailwindcss/vite": "^4.1.18", + "@tsconfig/svelte": "^5.0.6", + "bits-ui": "^2.14.4", "clsx": "^2.1.1", "dprint": "^0.50.2", "lefthook": "^2.0.13", "oxlint": "^1.35.0", "svelte": "^5.45.6", "svelte-check": "^4.3.4", + "svelte-language-server": "^0.17.23", "tailwind-merge": "^3.4.0", "tailwind-variants": "^3.2.2", "tailwindcss": "^4.1.18", diff --git a/src/App.svelte b/src/App.svelte deleted file mode 100644 index c447756..0000000 --- a/src/App.svelte +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - -
- -
- - diff --git a/src/ambient.d.ts b/src/ambient.d.ts deleted file mode 100644 index 68c306f..0000000 --- a/src/ambient.d.ts +++ /dev/null @@ -1,20 +0,0 @@ -declare module '*.svelte' { - import type { ComponentType } from 'svelte'; - const component: ComponentType; - export default component; -} - -declare module '*.svg' { - const content: string; - export default content; -} - -declare module '*.png' { - const content: string; - export default content; -} - -declare module '*.jpg' { - const content: string; - export default content; -} diff --git a/src/app/App.svelte b/src/app/App.svelte new file mode 100644 index 0000000..4934271 --- /dev/null +++ b/src/app/App.svelte @@ -0,0 +1,18 @@ + + + + + diff --git a/src/app.css b/src/app/styles/app.css similarity index 89% rename from src/app.css rename to src/app/styles/app.css index ee2d8d5..f574f19 100644 --- a/src/app.css +++ b/src/app/styles/app.css @@ -118,4 +118,23 @@ body { @apply bg-background text-foreground; } -} \ No newline at end of file +} + +/* Global utility - useful across your app */ +@media (prefers-reduced-motion: reduce) { + * { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } +} + +/* Performance optimization for collapsible elements */ +[data-state="open"] { + will-change: height; +} + +/* Smooth focus transitions - good globally */ +.peer:focus-visible ~ * { + transition: all 150ms cubic-bezier(0.4, 0, 0.2, 1); +} diff --git a/src/app/types/ambient.d.ts b/src/app/types/ambient.d.ts new file mode 100644 index 0000000..d2f5b6e --- /dev/null +++ b/src/app/types/ambient.d.ts @@ -0,0 +1,37 @@ +declare module '*.svelte' { + import type { + ComponentProps as SvelteComponentProps, + ComponentType, + Snippet, + } from 'svelte'; + import type { HTMLAttributes } from 'svelte/elements'; + + interface Component { + new(options: { + target: HTMLElement; + props?: Record; + intro?: boolean; + }): { + $on: (event: string, handler: (...args: unknown[]) => unknown) => void; + $destroy: () => void; + $set: (props: Record) => void; + }; + } + + export default Component; +} + +declare module '*.svg' { + const content: string; + export default content; +} + +declare module '*.png' { + const content: string; + export default content; +} + +declare module '*.jpg' { + const content: string; + export default content; +} diff --git a/src/app/ui/Layout.svelte b/src/app/ui/Layout.svelte new file mode 100644 index 0000000..b188574 --- /dev/null +++ b/src/app/ui/Layout.svelte @@ -0,0 +1,46 @@ + + + + + + +
+
+ + + +
+ + {@render children?.()} +
+
+
+
+ + diff --git a/src/entities/Font/index.ts b/src/entities/Font/index.ts new file mode 100644 index 0000000..539f081 --- /dev/null +++ b/src/entities/Font/index.ts @@ -0,0 +1,22 @@ +export type { + FontCategory, + FontProvider, + FontSubset, +} from './model/font'; +export type { + FontshareApiModel, + FontshareDesigner, + FontshareFeature, + FontshareFont, + FontsharePublisher, + FontshareStyle, + FontshareStyleProperties, + FontshareTag, + FontshareWeight, +} from './model/fontshare_fonts'; +export type { + FontFiles, + FontItem, + FontVariant, + GoogleFontsApiModel, +} from './model/google_fonts'; diff --git a/src/entities/Font/model/font.ts b/src/entities/Font/model/font.ts new file mode 100644 index 0000000..3222835 --- /dev/null +++ b/src/entities/Font/model/font.ts @@ -0,0 +1,14 @@ +/** + * Font category + */ +export type FontCategory = 'sans-serif' | 'serif' | 'display' | 'handwriting' | 'monospace'; + +/** + * Font provider + */ +export type FontProvider = 'google' | 'fontshare'; + +/** + * Font subset + */ +export type FontSubset = 'latin' | 'latin-ext' | 'cyrillic' | 'greek' | 'arabic' | 'devanagari'; diff --git a/src/lib/types/fontshare_fonts.ts b/src/entities/Font/model/fontshare_fonts.ts similarity index 98% rename from src/lib/types/fontshare_fonts.ts rename to src/entities/Font/model/fontshare_fonts.ts index 9a407bf..fddce6d 100644 --- a/src/lib/types/fontshare_fonts.ts +++ b/src/entities/Font/model/fontshare_fonts.ts @@ -1,4 +1,6 @@ -import type { CollectionApiModel } from './collection'; +import type { CollectionApiModel } from '../../../shared/types/collection'; + +export const FONTSHARE_API_URL = 'https://api.fontshare.com/v2' as const; /** * Model of Fontshare API response diff --git a/src/lib/types/google_fonts.ts b/src/entities/Font/model/google_fonts.ts similarity index 100% rename from src/lib/types/google_fonts.ts rename to src/entities/Font/model/google_fonts.ts diff --git a/src/features/FilterFonts/index.ts b/src/features/FilterFonts/index.ts new file mode 100644 index 0000000..3fc1009 --- /dev/null +++ b/src/features/FilterFonts/index.ts @@ -0,0 +1,5 @@ +export { categoryFilterStore } from './model/stores/categoryFilterStore'; +export { providersFilterStore } from './model/stores/providersFilterStore'; +export { subsetsFilterStore } from './model/stores/subsetsFilterStore'; + +export { clearAllFilters } from './model/services/clearAllFilters/clearAllFilters'; diff --git a/src/features/FilterFonts/model/const/const.ts b/src/features/FilterFonts/model/const/const.ts new file mode 100644 index 0000000..fbf9088 --- /dev/null +++ b/src/features/FilterFonts/model/const/const.ts @@ -0,0 +1,70 @@ +import type { Property } from '$shared/store/createFilterStore'; + +export const FONT_CATEGORIES: Property[] = [ + { + id: 'serif', + name: 'Serif', + }, + { + id: 'sans-serif', + name: 'Sans-serif', + }, + { + id: 'display', + name: 'Display', + }, + { + id: 'handwriting', + name: 'Handwriting', + }, + { + id: 'monospace', + name: 'Monospace', + }, + { + id: 'script', + name: 'Script', + }, + { + id: 'slab', + name: 'Slab', + }, +] as const; + +export const FONT_PROVIDERS: Property[] = [ + { + id: 'google', + name: 'Google Fonts', + }, + { + id: 'fontshare', + name: 'Fontshare', + }, +] as const; + +export const FONT_SUBSETS: Property[] = [ + { + id: 'latin', + name: 'Latin', + }, + { + id: 'latin-ext', + name: 'Latin Extended', + }, + { + id: 'cyrillic', + name: 'Cyrillic', + }, + { + id: 'greek', + name: 'Greek', + }, + { + id: 'arabic', + name: 'Arabic', + }, + { + id: 'devanagari', + name: 'Devanagari', + }, +] as const; diff --git a/src/features/FilterFonts/model/services/clearAllFilters/clearAllFilters.ts b/src/features/FilterFonts/model/services/clearAllFilters/clearAllFilters.ts new file mode 100644 index 0000000..260077c --- /dev/null +++ b/src/features/FilterFonts/model/services/clearAllFilters/clearAllFilters.ts @@ -0,0 +1,9 @@ +import { categoryFilterStore } from '../../stores/categoryFilterStore'; +import { providersFilterStore } from '../../stores/providersFilterStore'; +import { subsetsFilterStore } from '../../stores/subsetsFilterStore'; + +export function clearAllFilters() { + categoryFilterStore.deselectAllProperties(); + providersFilterStore.deselectAllProperties(); + subsetsFilterStore.deselectAllProperties(); +} diff --git a/src/features/FilterFonts/model/stores/categoryFilterStore.ts b/src/features/FilterFonts/model/stores/categoryFilterStore.ts new file mode 100644 index 0000000..60448c4 --- /dev/null +++ b/src/features/FilterFonts/model/stores/categoryFilterStore.ts @@ -0,0 +1,18 @@ +import { + type FilterModel, + createFilterStore, +} from '$shared/store/createFilterStore'; +import { FONT_CATEGORIES } from '../const/const'; + +/** + * Initial state for CategoryFilter + */ +export const initialState: FilterModel = { + searchQuery: '', + properties: FONT_CATEGORIES, +}; + +/** + * CategoryFilter store + */ +export const categoryFilterStore = createFilterStore(initialState); diff --git a/src/features/FilterFonts/model/stores/providersFilterStore.ts b/src/features/FilterFonts/model/stores/providersFilterStore.ts new file mode 100644 index 0000000..489a202 --- /dev/null +++ b/src/features/FilterFonts/model/stores/providersFilterStore.ts @@ -0,0 +1,18 @@ +import { + type FilterModel, + createFilterStore, +} from '$shared/store/createFilterStore'; +import { FONT_PROVIDERS } from '../const/const'; + +/** + * Initial state for ProvidersFilter + */ +export const initialState: FilterModel = { + searchQuery: '', + properties: FONT_PROVIDERS, +}; + +/** + * ProvidersFilter store + */ +export const providersFilterStore = createFilterStore(initialState); diff --git a/src/features/FilterFonts/model/stores/subsetsFilterStore.ts b/src/features/FilterFonts/model/stores/subsetsFilterStore.ts new file mode 100644 index 0000000..1df9378 --- /dev/null +++ b/src/features/FilterFonts/model/stores/subsetsFilterStore.ts @@ -0,0 +1,18 @@ +import { + type FilterModel, + createFilterStore, +} from '$shared/store/createFilterStore'; +import { FONT_SUBSETS } from '../const/const'; + +/** + * Initial state for SubsetsFilter + */ +const initialState: FilterModel = { + searchQuery: '', + properties: FONT_SUBSETS, +}; + +/** + * SubsetsFilter store + */ +export const subsetsFilterStore = createFilterStore(initialState); diff --git a/src/lib/index.ts b/src/lib/index.ts deleted file mode 100644 index 856f2b6..0000000 --- a/src/lib/index.ts +++ /dev/null @@ -1 +0,0 @@ -// place files you want to import through the `$lib` alias in this folder. diff --git a/src/lib/types/common.ts b/src/lib/types/common.ts deleted file mode 100644 index 2c1f8c8..0000000 --- a/src/lib/types/common.ts +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Model of response with error - */ -export interface ApiErrorResponse { - /** - * Error text - */ - error: string; - /** - * Status - */ - status: number; - /** - * Status text - */ - statusText: string; -} - -/** - * Model of response with success - */ -export interface ApiSuccessResponse { - /** - * Data - */ - data: T; - /** - * Status - */ - status: number; - /** - * Status text - */ - statusText: string; -} - -export type ApiResponse = ApiErrorResponse | ApiSuccessResponse; diff --git a/src/lib/utils.ts b/src/lib/utils.ts deleted file mode 100644 index f5acaf9..0000000 --- a/src/lib/utils.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { type ClassValue, clsx } from 'clsx'; -import { twMerge } from 'tailwind-merge'; - -export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)); -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export type WithoutChild = T extends { child?: any } ? Omit : T; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export type WithoutChildren = T extends { children?: any } ? Omit : T; -export type WithoutChildrenOrChild = WithoutChildren>; -export type WithElementRef = T & { ref?: U | null }; diff --git a/src/main.ts b/src/main.ts index 631bd81..c353493 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,5 +1,6 @@ +import App from '$app/App.svelte'; import { mount } from 'svelte'; -import App from './App.svelte'; +import '$app/styles/app.css'; mount(App, { target: document.getElementById('app')!, diff --git a/src/routes/Page.svelte b/src/routes/Page.svelte index b355f9e..1c3ee63 100644 --- a/src/routes/Page.svelte +++ b/src/routes/Page.svelte @@ -1,9 +1,16 @@

Welcome to Svelte + Vite

Visit svelte.dev/docs to read the documentation

- diff --git a/src/shared/api/api.ts b/src/shared/api/api.ts new file mode 100644 index 0000000..1b440d6 --- /dev/null +++ b/src/shared/api/api.ts @@ -0,0 +1,61 @@ +import type { ApiResponse } from '$shared/types/common'; + +export class ApiError extends Error { + constructor( + public status: number, + message: string, + public response?: Response, + ) { + super(message); + this.name = 'ApiError'; + } +} + +async function request( + url: string, + options?: RequestInit, +): Promise> { + const response = await fetch(url, { + headers: { + 'Content-Type': 'application/json', + ...options?.headers, + }, + ...options, + }); + + if (!response.ok) { + throw new ApiError( + response.status, + `Request failed: ${response.statusText}`, + response, + ); + } + + const data = await response.json() as T; + + return { + data, + status: response.status, + }; +} + +export const api = { + get: (url: string, options?: RequestInit) => request(url, { ...options, method: 'GET' }), + + post: (url: string, body?: unknown, options?: RequestInit) => + request(url, { + ...options, + method: 'POST', + body: JSON.stringify(body), + }), + + put: (url: string, body?: unknown, options?: RequestInit) => + request(url, { + ...options, + method: 'PUT', + body: JSON.stringify(body), + }), + + delete: (url: string, options?: RequestInit) => + request(url, { ...options, method: 'DELETE' }), +}; diff --git a/src/lib/assets/favicon.svg b/src/shared/assets/favicon.svg similarity index 100% rename from src/lib/assets/favicon.svg rename to src/shared/assets/favicon.svg diff --git a/src/shared/shadcn/hooks/is-mobile.svelte.ts b/src/shared/shadcn/hooks/is-mobile.svelte.ts new file mode 100644 index 0000000..2dfb0eb --- /dev/null +++ b/src/shared/shadcn/hooks/is-mobile.svelte.ts @@ -0,0 +1,9 @@ +import { MediaQuery } from 'svelte/reactivity'; + +const DEFAULT_MOBILE_BREAKPOINT = 768; + +export class IsMobile extends MediaQuery { + constructor(breakpoint: number = DEFAULT_MOBILE_BREAKPOINT) { + super(`max-width: ${breakpoint - 1}px`); + } +} diff --git a/src/shared/shadcn/ui/badge/badge.svelte b/src/shared/shadcn/ui/badge/badge.svelte new file mode 100644 index 0000000..523a922 --- /dev/null +++ b/src/shared/shadcn/ui/badge/badge.svelte @@ -0,0 +1,57 @@ + + + + + + {@render children?.()} + diff --git a/src/shared/shadcn/ui/badge/index.ts b/src/shared/shadcn/ui/badge/index.ts new file mode 100644 index 0000000..34b149c --- /dev/null +++ b/src/shared/shadcn/ui/badge/index.ts @@ -0,0 +1,5 @@ +export { default as Badge } from './badge.svelte'; +export { + type BadgeVariant, + badgeVariants, +} from './badge.svelte'; diff --git a/src/lib/components/ui/button/button.svelte b/src/shared/shadcn/ui/button/button.svelte similarity index 92% rename from src/lib/components/ui/button/button.svelte rename to src/shared/shadcn/ui/button/button.svelte index 371540b..25de114 100644 --- a/src/lib/components/ui/button/button.svelte +++ b/src/shared/shadcn/ui/button/button.svelte @@ -1,7 +1,16 @@ + + + {#snippet children({ checked, indeterminate })} +
+ {#if checked} + + {:else if indeterminate} + + {/if} +
+ {/snippet} +
diff --git a/src/shared/shadcn/ui/checkbox/index.ts b/src/shared/shadcn/ui/checkbox/index.ts new file mode 100644 index 0000000..d3e5023 --- /dev/null +++ b/src/shared/shadcn/ui/checkbox/index.ts @@ -0,0 +1,6 @@ +import Root from './checkbox.svelte'; +export { + Root, + // + Root as Checkbox, +}; diff --git a/src/shared/shadcn/ui/collapsible/collapsible-content.svelte b/src/shared/shadcn/ui/collapsible/collapsible-content.svelte new file mode 100644 index 0000000..25a505d --- /dev/null +++ b/src/shared/shadcn/ui/collapsible/collapsible-content.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/shared/shadcn/ui/collapsible/collapsible-trigger.svelte b/src/shared/shadcn/ui/collapsible/collapsible-trigger.svelte new file mode 100644 index 0000000..5204f38 --- /dev/null +++ b/src/shared/shadcn/ui/collapsible/collapsible-trigger.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/shared/shadcn/ui/collapsible/collapsible.svelte b/src/shared/shadcn/ui/collapsible/collapsible.svelte new file mode 100644 index 0000000..4c0539c --- /dev/null +++ b/src/shared/shadcn/ui/collapsible/collapsible.svelte @@ -0,0 +1,11 @@ + + + diff --git a/src/shared/shadcn/ui/collapsible/index.ts b/src/shared/shadcn/ui/collapsible/index.ts new file mode 100644 index 0000000..dedc5e7 --- /dev/null +++ b/src/shared/shadcn/ui/collapsible/index.ts @@ -0,0 +1,13 @@ +import Content from './collapsible-content.svelte'; +import Trigger from './collapsible-trigger.svelte'; +import Root from './collapsible.svelte'; + +export { + Content, + Content as CollapsibleContent, + Root, + // + Root as Collapsible, + Trigger, + Trigger as CollapsibleTrigger, +}; diff --git a/src/shared/shadcn/ui/dialog/dialog-close.svelte b/src/shared/shadcn/ui/dialog/dialog-close.svelte new file mode 100644 index 0000000..190949b --- /dev/null +++ b/src/shared/shadcn/ui/dialog/dialog-close.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/shared/shadcn/ui/dialog/dialog-content.svelte b/src/shared/shadcn/ui/dialog/dialog-content.svelte new file mode 100644 index 0000000..84e5b4a --- /dev/null +++ b/src/shared/shadcn/ui/dialog/dialog-content.svelte @@ -0,0 +1,48 @@ + + + + + + {@render children?.()} + {#if showCloseButton} + + + Close + + {/if} + + diff --git a/src/shared/shadcn/ui/dialog/dialog-description.svelte b/src/shared/shadcn/ui/dialog/dialog-description.svelte new file mode 100644 index 0000000..95ee2cb --- /dev/null +++ b/src/shared/shadcn/ui/dialog/dialog-description.svelte @@ -0,0 +1,17 @@ + + + diff --git a/src/shared/shadcn/ui/dialog/dialog-footer.svelte b/src/shared/shadcn/ui/dialog/dialog-footer.svelte new file mode 100644 index 0000000..9f1b33a --- /dev/null +++ b/src/shared/shadcn/ui/dialog/dialog-footer.svelte @@ -0,0 +1,23 @@ + + +
+ {@render children?.()} +
diff --git a/src/shared/shadcn/ui/dialog/dialog-header.svelte b/src/shared/shadcn/ui/dialog/dialog-header.svelte new file mode 100644 index 0000000..5c61174 --- /dev/null +++ b/src/shared/shadcn/ui/dialog/dialog-header.svelte @@ -0,0 +1,23 @@ + + +
+ {@render children?.()} +
diff --git a/src/shared/shadcn/ui/dialog/dialog-overlay.svelte b/src/shared/shadcn/ui/dialog/dialog-overlay.svelte new file mode 100644 index 0000000..1b28ebd --- /dev/null +++ b/src/shared/shadcn/ui/dialog/dialog-overlay.svelte @@ -0,0 +1,20 @@ + + + diff --git a/src/shared/shadcn/ui/dialog/dialog-portal.svelte b/src/shared/shadcn/ui/dialog/dialog-portal.svelte new file mode 100644 index 0000000..20907d7 --- /dev/null +++ b/src/shared/shadcn/ui/dialog/dialog-portal.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/shared/shadcn/ui/dialog/dialog-title.svelte b/src/shared/shadcn/ui/dialog/dialog-title.svelte new file mode 100644 index 0000000..0c82aff --- /dev/null +++ b/src/shared/shadcn/ui/dialog/dialog-title.svelte @@ -0,0 +1,17 @@ + + + diff --git a/src/shared/shadcn/ui/dialog/dialog-trigger.svelte b/src/shared/shadcn/ui/dialog/dialog-trigger.svelte new file mode 100644 index 0000000..b606eba --- /dev/null +++ b/src/shared/shadcn/ui/dialog/dialog-trigger.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/shared/shadcn/ui/dialog/dialog.svelte b/src/shared/shadcn/ui/dialog/dialog.svelte new file mode 100644 index 0000000..1be37a7 --- /dev/null +++ b/src/shared/shadcn/ui/dialog/dialog.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/shared/shadcn/ui/dialog/index.ts b/src/shared/shadcn/ui/dialog/index.ts new file mode 100644 index 0000000..f10e275 --- /dev/null +++ b/src/shared/shadcn/ui/dialog/index.ts @@ -0,0 +1,34 @@ +import Close from './dialog-close.svelte'; +import Content from './dialog-content.svelte'; +import Description from './dialog-description.svelte'; +import Footer from './dialog-footer.svelte'; +import Header from './dialog-header.svelte'; +import Overlay from './dialog-overlay.svelte'; +import Portal from './dialog-portal.svelte'; +import Title from './dialog-title.svelte'; +import Trigger from './dialog-trigger.svelte'; +import Root from './dialog.svelte'; + +export { + Close, + Close as DialogClose, + Content, + Content as DialogContent, + Description, + Description as DialogDescription, + Footer, + Footer as DialogFooter, + Header, + Header as DialogHeader, + Overlay, + Overlay as DialogOverlay, + Portal, + Portal as DialogPortal, + Root, + // + Root as Dialog, + Title, + Title as DialogTitle, + Trigger, + Trigger as DialogTrigger, +}; diff --git a/src/shared/shadcn/ui/input/index.ts b/src/shared/shadcn/ui/input/index.ts new file mode 100644 index 0000000..8c0f4f7 --- /dev/null +++ b/src/shared/shadcn/ui/input/index.ts @@ -0,0 +1,7 @@ +import Root from './input.svelte'; + +export { + Root, + // + Root as Input, +}; diff --git a/src/shared/shadcn/ui/input/input.svelte b/src/shared/shadcn/ui/input/input.svelte new file mode 100644 index 0000000..f9b4855 --- /dev/null +++ b/src/shared/shadcn/ui/input/input.svelte @@ -0,0 +1,58 @@ + + +{#if type === 'file'} + +{:else} + +{/if} diff --git a/src/shared/shadcn/ui/label/index.ts b/src/shared/shadcn/ui/label/index.ts new file mode 100644 index 0000000..9800cbe --- /dev/null +++ b/src/shared/shadcn/ui/label/index.ts @@ -0,0 +1,7 @@ +import Root from './label.svelte'; + +export { + Root, + // + Root as Label, +}; diff --git a/src/shared/shadcn/ui/label/label.svelte b/src/shared/shadcn/ui/label/label.svelte new file mode 100644 index 0000000..0b2fcb4 --- /dev/null +++ b/src/shared/shadcn/ui/label/label.svelte @@ -0,0 +1,20 @@ + + + diff --git a/src/shared/shadcn/ui/separator/index.ts b/src/shared/shadcn/ui/separator/index.ts new file mode 100644 index 0000000..25e42eb --- /dev/null +++ b/src/shared/shadcn/ui/separator/index.ts @@ -0,0 +1,7 @@ +import Root from './separator.svelte'; + +export { + Root, + // + Root as Separator, +}; diff --git a/src/shared/shadcn/ui/separator/separator.svelte b/src/shared/shadcn/ui/separator/separator.svelte new file mode 100644 index 0000000..65a873c --- /dev/null +++ b/src/shared/shadcn/ui/separator/separator.svelte @@ -0,0 +1,21 @@ + + + diff --git a/src/shared/shadcn/ui/sheet/index.ts b/src/shared/shadcn/ui/sheet/index.ts new file mode 100644 index 0000000..c2da041 --- /dev/null +++ b/src/shared/shadcn/ui/sheet/index.ts @@ -0,0 +1,34 @@ +import Close from './sheet-close.svelte'; +import Content from './sheet-content.svelte'; +import Description from './sheet-description.svelte'; +import Footer from './sheet-footer.svelte'; +import Header from './sheet-header.svelte'; +import Overlay from './sheet-overlay.svelte'; +import Portal from './sheet-portal.svelte'; +import Title from './sheet-title.svelte'; +import Trigger from './sheet-trigger.svelte'; +import Root from './sheet.svelte'; + +export { + Close, + Close as SheetClose, + Content, + Content as SheetContent, + Description, + Description as SheetDescription, + Footer, + Footer as SheetFooter, + Header, + Header as SheetHeader, + Overlay, + Overlay as SheetOverlay, + Portal, + Portal as SheetPortal, + Root, + // + Root as Sheet, + Title, + Title as SheetTitle, + Trigger, + Trigger as SheetTrigger, +}; diff --git a/src/shared/shadcn/ui/sheet/sheet-close.svelte b/src/shared/shadcn/ui/sheet/sheet-close.svelte new file mode 100644 index 0000000..9d7a483 --- /dev/null +++ b/src/shared/shadcn/ui/sheet/sheet-close.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/shared/shadcn/ui/sheet/sheet-content.svelte b/src/shared/shadcn/ui/sheet/sheet-content.svelte new file mode 100644 index 0000000..5ff5d6d --- /dev/null +++ b/src/shared/shadcn/ui/sheet/sheet-content.svelte @@ -0,0 +1,70 @@ + + + + + + + + {@render children?.()} + + + Close + + + diff --git a/src/shared/shadcn/ui/sheet/sheet-description.svelte b/src/shared/shadcn/ui/sheet/sheet-description.svelte new file mode 100644 index 0000000..f8236ef --- /dev/null +++ b/src/shared/shadcn/ui/sheet/sheet-description.svelte @@ -0,0 +1,17 @@ + + + diff --git a/src/shared/shadcn/ui/sheet/sheet-footer.svelte b/src/shared/shadcn/ui/sheet/sheet-footer.svelte new file mode 100644 index 0000000..4d90588 --- /dev/null +++ b/src/shared/shadcn/ui/sheet/sheet-footer.svelte @@ -0,0 +1,23 @@ + + +
+ {@render children?.()} +
diff --git a/src/shared/shadcn/ui/sheet/sheet-header.svelte b/src/shared/shadcn/ui/sheet/sheet-header.svelte new file mode 100644 index 0000000..ac28e2f --- /dev/null +++ b/src/shared/shadcn/ui/sheet/sheet-header.svelte @@ -0,0 +1,23 @@ + + +
+ {@render children?.()} +
diff --git a/src/shared/shadcn/ui/sheet/sheet-overlay.svelte b/src/shared/shadcn/ui/sheet/sheet-overlay.svelte new file mode 100644 index 0000000..362a6cd --- /dev/null +++ b/src/shared/shadcn/ui/sheet/sheet-overlay.svelte @@ -0,0 +1,20 @@ + + + diff --git a/src/shared/shadcn/ui/sheet/sheet-portal.svelte b/src/shared/shadcn/ui/sheet/sheet-portal.svelte new file mode 100644 index 0000000..1586c14 --- /dev/null +++ b/src/shared/shadcn/ui/sheet/sheet-portal.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/shared/shadcn/ui/sheet/sheet-title.svelte b/src/shared/shadcn/ui/sheet/sheet-title.svelte new file mode 100644 index 0000000..fbc4e7b --- /dev/null +++ b/src/shared/shadcn/ui/sheet/sheet-title.svelte @@ -0,0 +1,17 @@ + + + diff --git a/src/shared/shadcn/ui/sheet/sheet-trigger.svelte b/src/shared/shadcn/ui/sheet/sheet-trigger.svelte new file mode 100644 index 0000000..2115e27 --- /dev/null +++ b/src/shared/shadcn/ui/sheet/sheet-trigger.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/shared/shadcn/ui/sheet/sheet.svelte b/src/shared/shadcn/ui/sheet/sheet.svelte new file mode 100644 index 0000000..582e04e --- /dev/null +++ b/src/shared/shadcn/ui/sheet/sheet.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/shared/shadcn/ui/sidebar/constants.ts b/src/shared/shadcn/ui/sidebar/constants.ts new file mode 100644 index 0000000..2d3bbfb --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/constants.ts @@ -0,0 +1,6 @@ +export const SIDEBAR_COOKIE_NAME = 'sidebar:state'; +export const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7; +export const SIDEBAR_WIDTH = '16rem'; +export const SIDEBAR_WIDTH_MOBILE = '18rem'; +export const SIDEBAR_WIDTH_ICON = '3rem'; +export const SIDEBAR_KEYBOARD_SHORTCUT = 'b'; diff --git a/src/shared/shadcn/ui/sidebar/context.svelte.ts b/src/shared/shadcn/ui/sidebar/context.svelte.ts new file mode 100644 index 0000000..87bee3c --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/context.svelte.ts @@ -0,0 +1,84 @@ +import { IsMobile } from '$shared/shadcn/hooks/is-mobile.svelte.js'; +import { + getContext, + setContext, +} from 'svelte'; +import { SIDEBAR_KEYBOARD_SHORTCUT } from './constants.js'; + +type Getter = () => T; + +export type SidebarStateProps = { + /** + * A getter function that returns the current open state of the sidebar. + * We use a getter function here to support `bind:open` on the `Sidebar.Provider` + * component. + */ + open: Getter; + + /** + * 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 + * the sub-components and any `bind:` references. + */ + setOpen: (open: boolean) => void; +}; + +class SidebarState { + readonly props: SidebarStateProps; + open = $derived.by(() => this.props.open()); + openMobile = $state(false); + setOpen: SidebarStateProps['setOpen']; + #isMobile: IsMobile; + state = $derived.by(() => (this.open ? 'expanded' : 'collapsed')); + + constructor(props: SidebarStateProps) { + this.setOpen = props.setOpen; + this.#isMobile = new IsMobile(); + this.props = props; + } + + // Convenience getter for checking if the sidebar is mobile + // without this, we would need to use `sidebar.isMobile.current` everywhere + get isMobile() { + return this.#isMobile.current; + } + + // Event handler to apply to the `` + handleShortcutKeydown = (e: KeyboardEvent) => { + if (e.key === SIDEBAR_KEYBOARD_SHORTCUT && (e.metaKey || e.ctrlKey)) { + e.preventDefault(); + this.toggle(); + } + }; + + setOpenMobile = (value: boolean) => { + this.openMobile = value; + }; + + toggle = () => { + return this.#isMobile.current + ? (this.openMobile = !this.openMobile) + : this.setOpen(!this.open); + }; +} + +const SYMBOL_KEY = 'scn-sidebar'; + +/** + * Instantiates a new `SidebarState` instance and sets it in the context. + * + * @param props The constructor props for the `SidebarState` class. + * @returns The `SidebarState` instance. + */ +export function setSidebar(props: SidebarStateProps): SidebarState { + return setContext(Symbol.for(SYMBOL_KEY), new SidebarState(props)); +} + +/** + * Retrieves the `SidebarState` instance from the context. This is a class instance, + * so you cannot destructure it. + * @returns The `SidebarState` instance. + */ +export function useSidebar(): SidebarState { + return getContext(Symbol.for(SYMBOL_KEY)); +} diff --git a/src/shared/shadcn/ui/sidebar/index.ts b/src/shared/shadcn/ui/sidebar/index.ts new file mode 100644 index 0000000..cbafa36 --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/index.ts @@ -0,0 +1,75 @@ +import { useSidebar } from './context.svelte.js'; +import Content from './sidebar-content.svelte'; +import Footer from './sidebar-footer.svelte'; +import GroupAction from './sidebar-group-action.svelte'; +import GroupContent from './sidebar-group-content.svelte'; +import GroupLabel from './sidebar-group-label.svelte'; +import Group from './sidebar-group.svelte'; +import Header from './sidebar-header.svelte'; +import Input from './sidebar-input.svelte'; +import Inset from './sidebar-inset.svelte'; +import MenuAction from './sidebar-menu-action.svelte'; +import MenuBadge from './sidebar-menu-badge.svelte'; +import MenuButton from './sidebar-menu-button.svelte'; +import MenuItem from './sidebar-menu-item.svelte'; +import MenuSkeleton from './sidebar-menu-skeleton.svelte'; +import MenuSubButton from './sidebar-menu-sub-button.svelte'; +import MenuSubItem from './sidebar-menu-sub-item.svelte'; +import MenuSub from './sidebar-menu-sub.svelte'; +import Menu from './sidebar-menu.svelte'; +import Provider from './sidebar-provider.svelte'; +import Rail from './sidebar-rail.svelte'; +import Separator from './sidebar-separator.svelte'; +import Trigger from './sidebar-trigger.svelte'; +import Root from './sidebar.svelte'; + +export { + Content, + Content as SidebarContent, + Footer, + Footer as SidebarFooter, + Group, + Group as SidebarGroup, + GroupAction, + GroupAction as SidebarGroupAction, + GroupContent, + GroupContent as SidebarGroupContent, + GroupLabel, + GroupLabel as SidebarGroupLabel, + Header, + Header as SidebarHeader, + Input, + Input as SidebarInput, + Inset, + Inset as SidebarInset, + Menu, + Menu as SidebarMenu, + MenuAction, + MenuAction as SidebarMenuAction, + MenuBadge, + MenuBadge as SidebarMenuBadge, + MenuButton, + MenuButton as SidebarMenuButton, + MenuItem, + MenuItem as SidebarMenuItem, + MenuSkeleton, + MenuSkeleton as SidebarMenuSkeleton, + MenuSub, + MenuSub as SidebarMenuSub, + MenuSubButton, + MenuSubButton as SidebarMenuSubButton, + MenuSubItem, + MenuSubItem as SidebarMenuSubItem, + Provider, + Provider as SidebarProvider, + Rail, + Rail as SidebarRail, + Root, + // + Root as Sidebar, + Separator, + Separator as SidebarSeparator, + Trigger, + Trigger as SidebarTrigger, + useSidebar, +}; diff --git a/src/shared/shadcn/ui/sidebar/sidebar-content.svelte b/src/shared/shadcn/ui/sidebar/sidebar-content.svelte new file mode 100644 index 0000000..71b8988 --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/sidebar-content.svelte @@ -0,0 +1,27 @@ + + +
+ {@render children?.()} +
diff --git a/src/shared/shadcn/ui/sidebar/sidebar-footer.svelte b/src/shared/shadcn/ui/sidebar/sidebar-footer.svelte new file mode 100644 index 0000000..bcf8357 --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/sidebar-footer.svelte @@ -0,0 +1,24 @@ + + +
+ {@render children?.()} +
diff --git a/src/shared/shadcn/ui/sidebar/sidebar-group-action.svelte b/src/shared/shadcn/ui/sidebar/sidebar-group-action.svelte new file mode 100644 index 0000000..6cc0c51 --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/sidebar-group-action.svelte @@ -0,0 +1,39 @@ + + +{#if child} + {@render child({ props: mergedProps })} +{:else} + +{/if} diff --git a/src/shared/shadcn/ui/sidebar/sidebar-group-content.svelte b/src/shared/shadcn/ui/sidebar/sidebar-group-content.svelte new file mode 100644 index 0000000..ca289d0 --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/sidebar-group-content.svelte @@ -0,0 +1,24 @@ + + +
+ {@render children?.()} +
diff --git a/src/shared/shadcn/ui/sidebar/sidebar-group-label.svelte b/src/shared/shadcn/ui/sidebar/sidebar-group-label.svelte new file mode 100644 index 0000000..7be0e64 --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/sidebar-group-label.svelte @@ -0,0 +1,37 @@ + + +{#if child} + {@render child({ props: mergedProps })} +{:else} +
+ {@render children?.()} +
+{/if} diff --git a/src/shared/shadcn/ui/sidebar/sidebar-group.svelte b/src/shared/shadcn/ui/sidebar/sidebar-group.svelte new file mode 100644 index 0000000..4720700 --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/sidebar-group.svelte @@ -0,0 +1,24 @@ + + +
+ {@render children?.()} +
diff --git a/src/shared/shadcn/ui/sidebar/sidebar-header.svelte b/src/shared/shadcn/ui/sidebar/sidebar-header.svelte new file mode 100644 index 0000000..87635d1 --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/sidebar-header.svelte @@ -0,0 +1,24 @@ + + +
+ {@render children?.()} +
diff --git a/src/shared/shadcn/ui/sidebar/sidebar-input.svelte b/src/shared/shadcn/ui/sidebar/sidebar-input.svelte new file mode 100644 index 0000000..18a0296 --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/sidebar-input.svelte @@ -0,0 +1,21 @@ + + + diff --git a/src/shared/shadcn/ui/sidebar/sidebar-inset.svelte b/src/shared/shadcn/ui/sidebar/sidebar-inset.svelte new file mode 100644 index 0000000..f163977 --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/sidebar-inset.svelte @@ -0,0 +1,27 @@ + + +
+ {@render children?.()} +
diff --git a/src/shared/shadcn/ui/sidebar/sidebar-menu-action.svelte b/src/shared/shadcn/ui/sidebar/sidebar-menu-action.svelte new file mode 100644 index 0000000..fd5a8c5 --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/sidebar-menu-action.svelte @@ -0,0 +1,46 @@ + + +{#if child} + {@render child({ props: mergedProps })} +{:else} + +{/if} diff --git a/src/shared/shadcn/ui/sidebar/sidebar-menu-badge.svelte b/src/shared/shadcn/ui/sidebar/sidebar-menu-badge.svelte new file mode 100644 index 0000000..7b0867a --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/sidebar-menu-badge.svelte @@ -0,0 +1,32 @@ + + +
+ {@render children?.()} +
diff --git a/src/shared/shadcn/ui/sidebar/sidebar-menu-button.svelte b/src/shared/shadcn/ui/sidebar/sidebar-menu-button.svelte new file mode 100644 index 0000000..bb51ae9 --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/sidebar-menu-button.svelte @@ -0,0 +1,114 @@ + + + + +{#snippet Button({ props }: { props?: Record })} + {@const mergedProps = mergeProps(buttonProps, props)} + {#if child} + {@render child({ props: mergedProps })} + {:else} + + {/if} +{/snippet} + +{#if !tooltipContent} + {@render Button({})} +{:else} + + + {#snippet child({ props })} + {@render Button({ props })} + {/snippet} + + + +{/if} diff --git a/src/shared/shadcn/ui/sidebar/sidebar-menu-item.svelte b/src/shared/shadcn/ui/sidebar/sidebar-menu-item.svelte new file mode 100644 index 0000000..d536fd4 --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/sidebar-menu-item.svelte @@ -0,0 +1,24 @@ + + +
  • + {@render children?.()} +
  • diff --git a/src/shared/shadcn/ui/sidebar/sidebar-menu-skeleton.svelte b/src/shared/shadcn/ui/sidebar/sidebar-menu-skeleton.svelte new file mode 100644 index 0000000..4b31a63 --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/sidebar-menu-skeleton.svelte @@ -0,0 +1,39 @@ + + +
    + {#if showIcon} + + {/if} + + {@render children?.()} +
    diff --git a/src/shared/shadcn/ui/sidebar/sidebar-menu-sub-button.svelte b/src/shared/shadcn/ui/sidebar/sidebar-menu-sub-button.svelte new file mode 100644 index 0000000..1b030ce --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/sidebar-menu-sub-button.svelte @@ -0,0 +1,46 @@ + + +{#if child} + {@render child({ props: mergedProps })} +{:else} + + {@render children?.()} + +{/if} diff --git a/src/shared/shadcn/ui/sidebar/sidebar-menu-sub-item.svelte b/src/shared/shadcn/ui/sidebar/sidebar-menu-sub-item.svelte new file mode 100644 index 0000000..1dfd167 --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/sidebar-menu-sub-item.svelte @@ -0,0 +1,24 @@ + + +
  • + {@render children?.()} +
  • diff --git a/src/shared/shadcn/ui/sidebar/sidebar-menu-sub.svelte b/src/shared/shadcn/ui/sidebar/sidebar-menu-sub.svelte new file mode 100644 index 0000000..aefea30 --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/sidebar-menu-sub.svelte @@ -0,0 +1,28 @@ + + +
      + {@render children?.()} +
    diff --git a/src/shared/shadcn/ui/sidebar/sidebar-menu.svelte b/src/shared/shadcn/ui/sidebar/sidebar-menu.svelte new file mode 100644 index 0000000..7e3d656 --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/sidebar-menu.svelte @@ -0,0 +1,24 @@ + + +
      + {@render children?.()} +
    diff --git a/src/shared/shadcn/ui/sidebar/sidebar-provider.svelte b/src/shared/shadcn/ui/sidebar/sidebar-provider.svelte new file mode 100644 index 0000000..5d9e4e5 --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/sidebar-provider.svelte @@ -0,0 +1,57 @@ + + + + + +
    + {@render children?.()} +
    +
    diff --git a/src/shared/shadcn/ui/sidebar/sidebar-rail.svelte b/src/shared/shadcn/ui/sidebar/sidebar-rail.svelte new file mode 100644 index 0000000..d2606b0 --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/sidebar-rail.svelte @@ -0,0 +1,39 @@ + + + diff --git a/src/shared/shadcn/ui/sidebar/sidebar-separator.svelte b/src/shared/shadcn/ui/sidebar/sidebar-separator.svelte new file mode 100644 index 0000000..cedaf9f --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/sidebar-separator.svelte @@ -0,0 +1,19 @@ + + + diff --git a/src/shared/shadcn/ui/sidebar/sidebar-trigger.svelte b/src/shared/shadcn/ui/sidebar/sidebar-trigger.svelte new file mode 100644 index 0000000..c8d5fb0 --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/sidebar-trigger.svelte @@ -0,0 +1,35 @@ + + + diff --git a/src/shared/shadcn/ui/sidebar/sidebar.svelte b/src/shared/shadcn/ui/sidebar/sidebar.svelte new file mode 100644 index 0000000..1f83479 --- /dev/null +++ b/src/shared/shadcn/ui/sidebar/sidebar.svelte @@ -0,0 +1,108 @@ + + +{#if collapsible === 'none'} +
    + {@render children?.()} +
    +{:else if sidebar.isMobile} + sidebar.openMobile, v => sidebar.setOpenMobile(v)} + {...restProps} + > + + + Sidebar + Displays the mobile sidebar. + +
    + {@render children?.()} +
    +
    +
    +{:else} + +{/if} diff --git a/src/shared/shadcn/ui/skeleton/index.ts b/src/shared/shadcn/ui/skeleton/index.ts new file mode 100644 index 0000000..8b4fb82 --- /dev/null +++ b/src/shared/shadcn/ui/skeleton/index.ts @@ -0,0 +1,7 @@ +import Root from './skeleton.svelte'; + +export { + Root, + // + Root as Skeleton, +}; diff --git a/src/shared/shadcn/ui/skeleton/skeleton.svelte b/src/shared/shadcn/ui/skeleton/skeleton.svelte new file mode 100644 index 0000000..7149724 --- /dev/null +++ b/src/shared/shadcn/ui/skeleton/skeleton.svelte @@ -0,0 +1,22 @@ + + +
    +
    diff --git a/src/shared/shadcn/ui/tooltip/index.ts b/src/shared/shadcn/ui/tooltip/index.ts new file mode 100644 index 0000000..247b714 --- /dev/null +++ b/src/shared/shadcn/ui/tooltip/index.ts @@ -0,0 +1,19 @@ +import Content from './tooltip-content.svelte'; +import Portal from './tooltip-portal.svelte'; +import Provider from './tooltip-provider.svelte'; +import Trigger from './tooltip-trigger.svelte'; +import Root from './tooltip.svelte'; + +export { + Content, + Content as TooltipContent, + Portal, + Portal as TooltipPortal, + Provider, + Provider as TooltipProvider, + Root, + // + Root as Tooltip, + Trigger, + Trigger as TooltipTrigger, +}; diff --git a/src/shared/shadcn/ui/tooltip/tooltip-content.svelte b/src/shared/shadcn/ui/tooltip/tooltip-content.svelte new file mode 100644 index 0000000..8e4e4c3 --- /dev/null +++ b/src/shared/shadcn/ui/tooltip/tooltip-content.svelte @@ -0,0 +1,53 @@ + + + + + {@render children?.()} + + {#snippet child({ props })} +
    +
    + {/snippet} +
    +
    +
    diff --git a/src/shared/shadcn/ui/tooltip/tooltip-portal.svelte b/src/shared/shadcn/ui/tooltip/tooltip-portal.svelte new file mode 100644 index 0000000..d52ed4e --- /dev/null +++ b/src/shared/shadcn/ui/tooltip/tooltip-portal.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/shared/shadcn/ui/tooltip/tooltip-provider.svelte b/src/shared/shadcn/ui/tooltip/tooltip-provider.svelte new file mode 100644 index 0000000..7795b7f --- /dev/null +++ b/src/shared/shadcn/ui/tooltip/tooltip-provider.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/shared/shadcn/ui/tooltip/tooltip-trigger.svelte b/src/shared/shadcn/ui/tooltip/tooltip-trigger.svelte new file mode 100644 index 0000000..16086d4 --- /dev/null +++ b/src/shared/shadcn/ui/tooltip/tooltip-trigger.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/shared/shadcn/ui/tooltip/tooltip.svelte b/src/shared/shadcn/ui/tooltip/tooltip.svelte new file mode 100644 index 0000000..6a316fc --- /dev/null +++ b/src/shared/shadcn/ui/tooltip/tooltip.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/shared/shadcn/utils/shadcn-utils.ts b/src/shared/shadcn/utils/shadcn-utils.ts new file mode 100644 index 0000000..155cee4 --- /dev/null +++ b/src/shared/shadcn/utils/shadcn-utils.ts @@ -0,0 +1,40 @@ +import { + type ClassValue, + clsx, +} from 'clsx'; +import { twMerge } from 'tailwind-merge'; + +/** + * Utility function to merge Tailwind CSS classes + * Combines clsx for conditional classes and tailwind-merge to handle conflicts + */ +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} + +/** + * Type utility to add a ref property to HTML element attributes + * Used in shadcn-svelte components to support element references + * @template T - The attributes type (e.g., HTMLAttributes) + * @template E - The element type (e.g., HTMLDivElement) + */ +export type WithElementRef = T & { + /** + * Reference to the DOM element + */ + ref?: E | null; +}; + +/** + * Type utility to remove 'children' and 'child' properties from a type + * Used in shadcn-svelte components that use Snippets instead of children + * @template T - The type to remove children from + */ +export type WithoutChildren = Omit; + +/** + * Type utility to remove 'children' and 'child' properties from a type + * Used in shadcn-svelte components that use Snippets instead of children + * @template T - The type to remove children and child from + */ +export type WithoutChildrenOrChild = Omit; diff --git a/src/shared/store/createFilterStore.ts b/src/shared/store/createFilterStore.ts new file mode 100644 index 0000000..a15ab0f --- /dev/null +++ b/src/shared/store/createFilterStore.ts @@ -0,0 +1,226 @@ +import { + type Readable, + type Writable, + derived, + writable, +} from 'svelte/store'; + +export interface Property { + /** + * Property identifier + */ + id: string; + /** + * Property name + */ + name: string; + /** + * Property selected state + */ + selected?: boolean; +} + +export interface FilterModel { + /** + * Search query + */ + searchQuery?: string; + /** + * Properties + */ + properties: Property[]; +} + +/** + * Model for reusable filter store with search support and property selection + */ +export interface FilterStore extends Writable { + /** + * Get the store. + * @returns Readable store with filter data + */ + getStore: () => Readable; + /** + * Get all properties. + * @returns Readable store with properties + */ + getAllProperties: () => Readable; + /** + * Get the selected properties. + * @returns Readable store with selected properties + */ + getSelectedProperties: () => Readable; + /** + * Get the filtered properties. + * @returns Readable store with filtered properties + */ + getFilteredProperties: () => Readable; + /** + * Update the search query filter. + * + * @param searchQuery - Search text (undefined to clear) + */ + setSearchQuery: (searchQuery: string | undefined) => void; + /** + * Clear the search query filter. + */ + clearSearchQuery: () => void; + /** + * Select a property. + * + * @param property - Property to select + */ + selectProperty: (propertyId: string) => void; + /** + * Deselect a property. + * + * @param property - Property to deselect + */ + deselectProperty: (propertyId: string) => void; + /** + * Toggle a property. + * + * @param propertyId - Property ID + */ + toggleProperty: (propertyId: string) => void; + /** + * Select all properties. + */ + selectAllProperties: () => void; + /** + * Deselect all properties. + */ + deselectAllProperties: () => void; +} + +/** + * Create a filter store. + * @param initialState - Initial state of the filter store + * @returns FilterStore + */ +export function createFilterStore( + initialState?: T, +): FilterStore { + const { subscribe, set, update } = writable(initialState); + + return { + /* + * Expose subscribe, set, and update from Writable. + * This makes FilterStore compatible with Writable interface. + */ + subscribe, + set, + update, + /** + * Get the current state of the filter store. + */ + getStore: () => { + return { + subscribe, + }; + }, + /** + * Get the filtered properties. + */ + getAllProperties: () => { + return derived({ subscribe }, $store => { + return $store.properties; + }); + }, + /** + * Get the selected properties. + */ + getSelectedProperties: () => { + return derived({ subscribe }, $store => { + return $store.properties.filter(property => property.selected); + }); + }, + /** + * Get the filtered properties. + */ + getFilteredProperties: () => { + return derived({ subscribe }, $store => { + return $store.properties.filter(property => + property.name.includes($store.searchQuery || '') + ); + }); + }, + /** + * Update the search query filter. + * + * @param searchQuery - Search text (undefined to clear) + */ + setSearchQuery: (searchQuery: string | undefined) => { + update(state => ({ + ...state, + searchQuery: searchQuery || undefined, + })); + }, + /** + * Clear the search query filter. + */ + clearSearchQuery: () => { + update(state => ({ + ...state, + searchQuery: undefined, + })); + }, + /** + * Select a property. + * + * @param propertyId - Property ID + */ + selectProperty: (propertyId: string) => { + update(state => ({ + ...state, + properties: state.properties.map(c => + c.id === propertyId ? { ...c, selected: true } : c + ), + })); + }, + /** + * Deselect a property. + * + * @param propertyId - Property ID + */ + deselectProperty: (propertyId: string) => { + update(state => ({ + ...state, + properties: state.properties.map(c => + c.id === propertyId ? { ...c, selected: false } : c + ), + })); + }, + /** + * Toggle a property. + * + * @param propertyId - Property ID + */ + toggleProperty: (propertyId: string) => { + update(state => ({ + ...state, + properties: state.properties.map(c => + c.id === propertyId ? { ...c, selected: !c.selected } : c + ), + })); + }, + /** + * Select all properties + */ + selectAllProperties: () => { + update(state => ({ + ...state, + properties: state.properties.map(c => ({ ...c, selected: true })), + })); + }, + /** + * Deselect all properties + */ + deselectAllProperties: () => { + update(state => ({ + ...state, + properties: state.properties.map(c => ({ ...c, selected: false })), + })); + }, + }; +} diff --git a/src/lib/types/collection.ts b/src/shared/types/collection.ts similarity index 100% rename from src/lib/types/collection.ts rename to src/shared/types/collection.ts diff --git a/src/shared/types/common.ts b/src/shared/types/common.ts new file mode 100644 index 0000000..8bcc1b7 --- /dev/null +++ b/src/shared/types/common.ts @@ -0,0 +1,4 @@ +export interface ApiResponse { + data: T; + status: number; +} diff --git a/src/shared/ui/CheckboxFilter/CheckboxFilter.svelte b/src/shared/ui/CheckboxFilter/CheckboxFilter.svelte new file mode 100644 index 0000000..87a8025 --- /dev/null +++ b/src/shared/ui/CheckboxFilter/CheckboxFilter.svelte @@ -0,0 +1,158 @@ + + + + + +
    + +

    {displayedLabel}

    + + + {#if hasSelection} + + {selectedCount} + + {/if} + + +
    + +
    +
    +
    + + + {#if isOpen} +
    +
    +
    + + + {#each properties as property (property.id)} + + {/each} +
    +
    +
    + {/if} +
    diff --git a/src/widgets/FiltersSidebar/index.ts b/src/widgets/FiltersSidebar/index.ts new file mode 100644 index 0000000..895591f --- /dev/null +++ b/src/widgets/FiltersSidebar/index.ts @@ -0,0 +1,3 @@ +import FiltersSidebar from './ui/FiltersSidebar.svelte'; + +export { FiltersSidebar }; diff --git a/src/widgets/FiltersSidebar/ui/Controls.svelte b/src/widgets/FiltersSidebar/ui/Controls.svelte new file mode 100644 index 0000000..39d350e --- /dev/null +++ b/src/widgets/FiltersSidebar/ui/Controls.svelte @@ -0,0 +1,24 @@ + + +
    + + +
    diff --git a/src/widgets/FiltersSidebar/ui/Filters.svelte b/src/widgets/FiltersSidebar/ui/Filters.svelte new file mode 100644 index 0000000..a42ee3a --- /dev/null +++ b/src/widgets/FiltersSidebar/ui/Filters.svelte @@ -0,0 +1,42 @@ + + + + + diff --git a/src/widgets/FiltersSidebar/ui/FiltersSidebar.svelte b/src/widgets/FiltersSidebar/ui/FiltersSidebar.svelte new file mode 100644 index 0000000..b9f2f38 --- /dev/null +++ b/src/widgets/FiltersSidebar/ui/FiltersSidebar.svelte @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/svelte.config.js b/svelte.config.js index 6d1da96..e04d6f9 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -1,8 +1,6 @@ import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; const config = { - // Consult https://svelte.dev/docs/kit/integrations - // for more information about preprocessors preprocess: vitePreprocess(), compilerOptions: { diff --git a/tsconfig.json b/tsconfig.json index c27aaed..6e6cdb3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,9 +1,11 @@ { + "extends": "@tsconfig/svelte/tsconfig.json", "compilerOptions": { "module": "ESNext", "moduleResolution": "bundler", "target": "ESNext", "lib": ["ESNext", "DOM", "DOM.Iterable"], + "types": ["svelte"], /* Strictness & Safety */ "strict": true, @@ -15,12 +17,19 @@ "skipLibCheck": true, "sourceMap": true, "isolatedModules": true, + "allowImportingTsExtensions": true, "verbatimModuleSyntax": true, /* Path Aliases */ "baseUrl": ".", "paths": { - "$lib/*": ["./src/lib/*"] + "$lib/*": ["./src/lib/*"], + "$app/*": ["./src/app/*"], + "$widgets/*": ["./src/widgets/*"], + "$shared/*": ["./src/shared/*"], + "$entities/*": ["./src/entities/*"], + "$features/*": ["./src/features/*"], + "$routes/*": ["./src/routes/*"] } }, "include": [ @@ -32,6 +41,7 @@ "exclude": [ "node_modules", "dist", - "./src/lib/components/ui" + "src/shared/shadcn/**/*", + "node_modules/**/*" ] } diff --git a/vite.config.ts b/vite.config.ts index 2730f4a..64a58d9 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -7,6 +7,12 @@ export default defineConfig({ resolve: { alias: { $lib: '/src/lib', + $app: '/src/app', + $shared: '/src/shared', + $entities: '/src/entities', + $features: '/src/features', + $routes: '/src/routes', + $widgets: '/src/widgets', }, }, build: { diff --git a/yarn.lock b/yarn.lock index 9871ec3..5685666 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,6 +5,16 @@ __metadata: version: 8 cacheKey: 10c0 +"@ampproject/remapping@npm:^2.2.1": + version: 2.3.0 + resolution: "@ampproject/remapping@npm:2.3.0" + dependencies: + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10c0/81d63cca5443e0f0c72ae18b544cc28c7c0ec2cea46e7cb888bb0e0f411a1191d0d6b7af798d54e30777d8d1488b2ec0732aac2be342d3d7d3ffd271c6f489ed + languageName: node + linkType: hard + "@dprint/darwin-arm64@npm:0.50.2": version: 0.50.2 resolution: "@dprint/darwin-arm64@npm:0.50.2" @@ -68,6 +78,31 @@ __metadata: languageName: node linkType: hard +"@emmetio/abbreviation@npm:^2.3.3": + version: 2.3.3 + resolution: "@emmetio/abbreviation@npm:2.3.3" + dependencies: + "@emmetio/scanner": "npm:^1.0.4" + checksum: 10c0/835b460706d5920a6f9a569a44b7d98e88d5530e3983af3678b44fa38b4cbdf68b5df933476d72e340779b16e7e7962ffa63142db8d2f59b1175a11c30c14635 + languageName: node + linkType: hard + +"@emmetio/css-abbreviation@npm:^2.1.8": + version: 2.1.8 + resolution: "@emmetio/css-abbreviation@npm:2.1.8" + dependencies: + "@emmetio/scanner": "npm:^1.0.4" + checksum: 10c0/b5b3b39e773185d848b634e48e1b520e6ebffd28bfd0ba34fbcf877ca77e0edb8c7bbf58230cb0621f80f579bd7fd0265f00ab5e09ac482a835897cbdb6182a6 + languageName: node + linkType: hard + +"@emmetio/scanner@npm:^1.0.4": + version: 1.0.4 + resolution: "@emmetio/scanner@npm:1.0.4" + checksum: 10c0/ae6244e563caaff0f88d7afefc33fd6cfb7cc767ce914b54d35b46002637948cfc65951dba6d6941328afa54c721c225836fafce2de40fb7643660ba09fe7372 + languageName: node + linkType: hard + "@emnapi/core@npm:^1.7.1": version: 1.7.1 resolution: "@emnapi/core@npm:1.7.1" @@ -278,6 +313,41 @@ __metadata: languageName: node linkType: hard +"@floating-ui/core@npm:^1.7.1, @floating-ui/core@npm:^1.7.3": + version: 1.7.3 + resolution: "@floating-ui/core@npm:1.7.3" + dependencies: + "@floating-ui/utils": "npm:^0.2.10" + checksum: 10c0/edfc23800122d81df0df0fb780b7328ae6c5f00efbb55bd48ea340f4af8c5b3b121ceb4bb81220966ab0f87b443204d37105abdd93d94846468be3243984144c + languageName: node + linkType: hard + +"@floating-ui/dom@npm:^1.7.1": + version: 1.7.4 + resolution: "@floating-ui/dom@npm:1.7.4" + dependencies: + "@floating-ui/core": "npm:^1.7.3" + "@floating-ui/utils": "npm:^0.2.10" + checksum: 10c0/da6166c25f9b0729caa9f498685a73a0e28251613b35d27db8de8014bc9d045158a23c092b405321a3d67c2064909b6e2a7e6c1c9cc0f62967dca5779f5aef30 + languageName: node + linkType: hard + +"@floating-ui/utils@npm:^0.2.10": + version: 0.2.10 + resolution: "@floating-ui/utils@npm:0.2.10" + checksum: 10c0/e9bc2a1730ede1ee25843937e911ab6e846a733a4488623cd353f94721b05ec2c9ec6437613a2ac9379a94c2fd40c797a2ba6fa1df2716f5ce4aa6ddb1cf9ea4 + languageName: node + linkType: hard + +"@internationalized/date@npm:^3.10.0": + version: 3.10.1 + resolution: "@internationalized/date@npm:3.10.1" + dependencies: + "@swc/helpers": "npm:^0.5.0" + checksum: 10c0/2b7a8144a97baf0c8bd9f3ef28fe86238e2cfde3b837c943aa03bd07354a04753bab3fd7162e5865c284f5b2616e832c9eee395dec92c0fed4eff57615d9d940 + languageName: node + linkType: hard + "@isaacs/balanced-match@npm:^4.0.1": version: 4.0.1 resolution: "@isaacs/balanced-match@npm:4.0.1" @@ -337,7 +407,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25": +"@jridgewell/trace-mapping@npm:^0.3.18, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25": version: 0.3.31 resolution: "@jridgewell/trace-mapping@npm:0.3.31" dependencies: @@ -347,12 +417,12 @@ __metadata: languageName: node linkType: hard -"@lucide/svelte@npm:^0.562.0": - version: 0.562.0 - resolution: "@lucide/svelte@npm:0.562.0" +"@lucide/svelte@npm:^0.561.0": + version: 0.561.0 + resolution: "@lucide/svelte@npm:0.561.0" peerDependencies: svelte: ^5 - checksum: 10c0/4886cbae7bf575daf5ee66b26be55a49f6e361672db6eb85f39779c202cd7d4e0d1431f6af710a7045ce9e36e720aef589d78da5807a2f2612c24e54198290bd + checksum: 10c0/9f6c0ef143a5b61248b5671ad6e2f94471200e95a5af554b0b5dc60458d175a7b0b07a1e07ee10192f04a24e433122189be54ea5ab87d36527f01ca05e1507e1 languageName: node linkType: hard @@ -648,6 +718,15 @@ __metadata: languageName: node linkType: hard +"@swc/helpers@npm:^0.5.0": + version: 0.5.18 + resolution: "@swc/helpers@npm:0.5.18" + dependencies: + tslib: "npm:^2.8.0" + checksum: 10c0/cb32d72e32f775c30287bffbcf61c89ea3a963608cb3a4a675a3f9af545b8b3ab0bc9930432a5520a7307daaa87538158e253584ae1cf39f3e7e6e83408a2d51 + languageName: node + linkType: hard + "@tailwindcss/node@npm:4.1.18": version: 4.1.18 resolution: "@tailwindcss/node@npm:4.1.18" @@ -812,6 +891,13 @@ __metadata: languageName: node linkType: hard +"@tsconfig/svelte@npm:^5.0.6": + version: 5.0.6 + resolution: "@tsconfig/svelte@npm:5.0.6" + checksum: 10c0/0b382dd946e516271a97ee72c513bc509a5fd8f2d7ba9b315cf4b8d85a1796f4e043fd8e2a01c90b652e528a7cfd243f65ef373c18299a90872f602c5f93683e + languageName: node + linkType: hard + "@tybys/wasm-util@npm:^0.10.1": version: 0.10.1 resolution: "@tybys/wasm-util@npm:0.10.1" @@ -821,13 +907,34 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:1.0.8, @types/estree@npm:^1.0.5, @types/estree@npm:^1.0.6": +"@types/estree@npm:1.0.8, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.1, @types/estree@npm:^1.0.5, @types/estree@npm:^1.0.6": version: 1.0.8 resolution: "@types/estree@npm:1.0.8" checksum: 10c0/39d34d1afaa338ab9763f37ad6066e3f349444f9052b9676a7cc0252ef9485a41c6d81c9c4e0d26e9077993354edf25efc853f3224dd4b447175ef62bdcc86a5 languageName: node linkType: hard +"@vscode/emmet-helper@npm:2.8.4": + version: 2.8.4 + resolution: "@vscode/emmet-helper@npm:2.8.4" + dependencies: + emmet: "npm:^2.3.0" + jsonc-parser: "npm:^2.3.0" + vscode-languageserver-textdocument: "npm:^1.0.1" + vscode-languageserver-types: "npm:^3.15.1" + vscode-nls: "npm:^5.0.0" + vscode-uri: "npm:^2.1.2" + checksum: 10c0/775d49361c587eec5727ceff49299307cd3ecfc704ce75084c6ed077b4056a980049e5da72900f851d4a21f99fc81b876a7bc5a8f31ec6609d32dd2fe587ca50 + languageName: node + linkType: hard + +"@vscode/l10n@npm:^0.0.18": + version: 0.0.18 + resolution: "@vscode/l10n@npm:0.0.18" + checksum: 10c0/d1fc797001f7d508ab3fa91175f7a50ea98516c4e47830ff2be79163cde9279279514a167a3bad15b7ab7fc243e7808d8f32d3eb41f4a7d6721d9dfdbb38d89e + languageName: node + linkType: hard + "abbrev@npm:^4.0.0": version: 4.0.0 resolution: "abbrev@npm:4.0.0" @@ -835,7 +942,7 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.12.1": +"acorn@npm:^8.10.0, acorn@npm:^8.12.1, acorn@npm:^8.9.0": version: 8.15.0 resolution: "acorn@npm:8.15.0" bin: @@ -851,20 +958,37 @@ __metadata: languageName: node linkType: hard -"aria-query@npm:^5.3.1": +"aria-query@npm:^5.3.0, aria-query@npm:^5.3.1": version: 5.3.2 resolution: "aria-query@npm:5.3.2" checksum: 10c0/003c7e3e2cff5540bf7a7893775fc614de82b0c5dde8ae823d47b7a28a9d4da1f7ed85f340bdb93d5649caa927755f0e31ecc7ab63edfdfc00c8ef07e505e03e languageName: node linkType: hard -"axobject-query@npm:^4.1.0": +"axobject-query@npm:^4.0.0, axobject-query@npm:^4.1.0": version: 4.1.0 resolution: "axobject-query@npm:4.1.0" checksum: 10c0/c470e4f95008f232eadd755b018cb55f16c03ccf39c027b941cd8820ac6b68707ce5d7368a46756db4256fbc91bb4ead368f84f7fb034b2b7932f082f6dc0775 languageName: node linkType: hard +"bits-ui@npm:^2.14.4": + version: 2.14.4 + resolution: "bits-ui@npm:2.14.4" + dependencies: + "@floating-ui/core": "npm:^1.7.1" + "@floating-ui/dom": "npm:^1.7.1" + esm-env: "npm:^1.1.2" + runed: "npm:^0.35.1" + svelte-toolbelt: "npm:^0.10.6" + tabbable: "npm:^6.2.0" + peerDependencies: + "@internationalized/date": ^3.8.1 + svelte: ^5.33.0 + checksum: 10c0/cb3f240e42e5ef948bd0581a5ff818f84740963b6b59e8806aa2019434b6fccdf9b0b9f502d33c2dd51ea32e55d5168949ee0e58a99049ef01ad3437f19d0dc8 + languageName: node + linkType: hard + "cacache@npm:^20.0.1": version: 20.0.3 resolution: "cacache@npm:20.0.3" @@ -907,6 +1031,29 @@ __metadata: languageName: node linkType: hard +"code-red@npm:^1.0.3": + version: 1.0.4 + resolution: "code-red@npm:1.0.4" + dependencies: + "@jridgewell/sourcemap-codec": "npm:^1.4.15" + "@types/estree": "npm:^1.0.1" + acorn: "npm:^8.10.0" + estree-walker: "npm:^3.0.3" + periscopic: "npm:^3.1.0" + checksum: 10c0/1309f062369ae520c422d7f45b93190faea2cbc7e3fe3375918f36bb394030d0936d940601426564c30abc71b8aa8e6d1505cccd67a8620183fb01c84bcb7304 + languageName: node + linkType: hard + +"css-tree@npm:^2.3.1": + version: 2.3.1 + resolution: "css-tree@npm:2.3.1" + dependencies: + mdn-data: "npm:2.0.30" + source-map-js: "npm:^1.0.1" + checksum: 10c0/6f8c1a11d5e9b14bf02d10717fc0351b66ba12594166f65abfbd8eb8b5b490dd367f5c7721db241a3c792d935fc6751fbc09f7e1598d421477ad9fadc30f4f24 + languageName: node + linkType: hard + "debug@npm:4, debug@npm:^4.3.4, debug@npm:^4.4.1": version: 4.4.3 resolution: "debug@npm:4.4.3" @@ -919,6 +1066,13 @@ __metadata: languageName: node linkType: hard +"dedent-js@npm:^1.0.1": + version: 1.0.1 + resolution: "dedent-js@npm:1.0.1" + checksum: 10c0/a8cff2e02d5a1ce64615c5c53c9789e7ef1abb9ae7bf2322dc991fcbaf08d901ace1a679c1e021de15a85db7787b8ccfb02011e1f394afef0f698fc857a47009 + languageName: node + linkType: hard + "deepmerge@npm:^4.3.1": version: 4.3.1 resolution: "deepmerge@npm:4.3.1" @@ -926,6 +1080,13 @@ __metadata: languageName: node linkType: hard +"dequal@npm:^2.0.3": + version: 2.0.3 + resolution: "dequal@npm:2.0.3" + checksum: 10c0/f98860cdf58b64991ae10205137c0e97d384c3a4edc7f807603887b7c4b850af1224a33d88012009f150861cbee4fa2d322c4cc04b9313bee312e47f6ecaa888 + languageName: node + linkType: hard + "detect-libc@npm:^2.0.3": version: 2.1.2 resolution: "detect-libc@npm:2.1.2" @@ -978,6 +1139,16 @@ __metadata: languageName: node linkType: hard +"emmet@npm:^2.3.0": + version: 2.4.11 + resolution: "emmet@npm:2.4.11" + dependencies: + "@emmetio/abbreviation": "npm:^2.3.3" + "@emmetio/css-abbreviation": "npm:^2.1.8" + checksum: 10c0/4099d9d0d5dee766603c4ea03e1b87296bd397a0e8c6d8d5d6dcfdaad3e4581df5d48939a00eb4437dc08c83e857e231222ee037cb34ad63b1f2cce4041c6fc2 + languageName: node + linkType: hard + "encoding@npm:^0.1.13": version: 0.1.13 resolution: "encoding@npm:0.1.13" @@ -1100,7 +1271,7 @@ __metadata: languageName: node linkType: hard -"esm-env@npm:^1.2.1": +"esm-env@npm:^1.0.0, esm-env@npm:^1.1.2, esm-env@npm:^1.2.1": version: 1.2.2 resolution: "esm-env@npm:1.2.2" checksum: 10c0/3d25c973f2fd69c25ffff29c964399cea573fe10795ecc1d26f6f957ce0483d3254e1cceddb34bf3296a0d7b0f1d53a28992f064ba509dfe6366751e752c4166 @@ -1116,6 +1287,22 @@ __metadata: languageName: node linkType: hard +"estree-walker@npm:^2.0.1": + version: 2.0.2 + resolution: "estree-walker@npm:2.0.2" + checksum: 10c0/53a6c54e2019b8c914dc395890153ffdc2322781acf4bd7d1a32d7aedc1710807bdcd866ac133903d5629ec601fbb50abe8c2e5553c7f5a0afdd9b6af6c945af + languageName: node + linkType: hard + +"estree-walker@npm:^3.0.0, estree-walker@npm:^3.0.3": + version: 3.0.3 + resolution: "estree-walker@npm:3.0.3" + dependencies: + "@types/estree": "npm:^1.0.0" + checksum: 10c0/c12e3c2b2642d2bcae7d5aa495c60fa2f299160946535763969a1c83fc74518ffa9c2cd3a8b69ac56aea547df6a8aac25f729a342992ef0bbac5f1c73e78995d + languageName: node + linkType: hard + "exponential-backoff@npm:^3.1.1": version: 3.1.3 resolution: "exponential-backoff@npm:3.1.3" @@ -1193,20 +1380,31 @@ __metadata: languageName: node linkType: hard +"globrex@npm:^0.1.2": + version: 0.1.2 + resolution: "globrex@npm:0.1.2" + checksum: 10c0/a54c029520cf58bda1d8884f72bd49b4cd74e977883268d931fd83bcbd1a9eb96d57c7dbd4ad80148fb9247467ebfb9b215630b2ed7563b2a8de02e1ff7f89d1 + languageName: node + linkType: hard + "glyphdiff@workspace:.": version: 0.0.0-use.local resolution: "glyphdiff@workspace:." dependencies: - "@lucide/svelte": "npm:^0.562.0" + "@internationalized/date": "npm:^3.10.0" + "@lucide/svelte": "npm:^0.561.0" "@playwright/test": "npm:^1.57.0" "@sveltejs/vite-plugin-svelte": "npm:^6.2.1" "@tailwindcss/vite": "npm:^4.1.18" + "@tsconfig/svelte": "npm:^5.0.6" + bits-ui: "npm:^2.14.4" clsx: "npm:^2.1.1" dprint: "npm:^0.50.2" lefthook: "npm:^2.0.13" oxlint: "npm:^1.35.0" svelte: "npm:^5.45.6" svelte-check: "npm:^4.3.4" + svelte-language-server: "npm:^0.17.23" tailwind-merge: "npm:^3.4.0" tailwind-variants: "npm:^3.2.2" tailwindcss: "npm:^4.1.18" @@ -1266,6 +1464,13 @@ __metadata: languageName: node linkType: hard +"inline-style-parser@npm:0.2.7": + version: 0.2.7 + resolution: "inline-style-parser@npm:0.2.7" + checksum: 10c0/d884d76f84959517430ae6c22f0bda59bb3f58f539f99aac75a8d786199ec594ed648c6ab4640531f9fc244b0ed5cd8c458078e592d016ef06de793beb1debff + languageName: node + linkType: hard + "ip-address@npm:^10.0.1": version: 10.1.0 resolution: "ip-address@npm:10.1.0" @@ -1273,7 +1478,7 @@ __metadata: languageName: node linkType: hard -"is-reference@npm:^3.0.3": +"is-reference@npm:^3.0.0, is-reference@npm:^3.0.1, is-reference@npm:^3.0.3": version: 3.0.3 resolution: "is-reference@npm:3.0.3" dependencies: @@ -1298,6 +1503,13 @@ __metadata: languageName: node linkType: hard +"jsonc-parser@npm:^2.3.0": + version: 2.3.1 + resolution: "jsonc-parser@npm:2.3.1" + checksum: 10c0/b5e823612f6518a4d35e65d3c642e87b994c52a71b6d83d306d59f9b57003a1f6c64659808f0f1c3448991c28916d56faca45222f31ddb1a32effecdef0f0485 + languageName: node + linkType: hard + "lefthook-darwin-arm64@npm:2.0.13": version: 2.0.13 resolution: "lefthook-darwin-arm64@npm:2.0.13" @@ -1536,6 +1748,13 @@ __metadata: languageName: node linkType: hard +"lodash@npm:^4.17.21": + version: 4.17.21 + resolution: "lodash@npm:4.17.21" + checksum: 10c0/d8cbea072bb08655bb4c989da418994b073a608dffa608b09ac04b43a791b12aeae7cd7ad919aa4c925f33b48490b5cfe6c1f71d827956071dae2e7bb3a6b74c + languageName: node + linkType: hard + "lru-cache@npm:^11.0.0, lru-cache@npm:^11.1.0, lru-cache@npm:^11.2.1": version: 11.2.4 resolution: "lru-cache@npm:11.2.4" @@ -1543,7 +1762,16 @@ __metadata: languageName: node linkType: hard -"magic-string@npm:^0.30.11, magic-string@npm:^0.30.17, magic-string@npm:^0.30.21": +"lz-string@npm:^1.5.0": + version: 1.5.0 + resolution: "lz-string@npm:1.5.0" + bin: + lz-string: bin/bin.js + checksum: 10c0/36128e4de34791838abe979b19927c26e67201ca5acf00880377af7d765b38d1c60847e01c5ec61b1a260c48029084ab3893a3925fd6e48a04011364b089991b + languageName: node + linkType: hard + +"magic-string@npm:^0.30.11, magic-string@npm:^0.30.17, magic-string@npm:^0.30.21, magic-string@npm:^0.30.4": version: 0.30.21 resolution: "magic-string@npm:0.30.21" dependencies: @@ -1571,6 +1799,13 @@ __metadata: languageName: node linkType: hard +"mdn-data@npm:2.0.30": + version: 2.0.30 + resolution: "mdn-data@npm:2.0.30" + checksum: 10c0/a2c472ea16cee3911ae742593715aa4c634eb3d4b9f1e6ada0902aa90df13dcbb7285d19435f3ff213ebaa3b2e0c0265c1eb0e3fb278fda7f8919f046a410cd9 + languageName: node + linkType: hard + "minimatch@npm:^10.1.1": version: 10.1.1 resolution: "minimatch@npm:10.1.1" @@ -1775,6 +2010,17 @@ __metadata: languageName: node linkType: hard +"periscopic@npm:^3.1.0": + version: 3.1.0 + resolution: "periscopic@npm:3.1.0" + dependencies: + "@types/estree": "npm:^1.0.0" + estree-walker: "npm:^3.0.0" + is-reference: "npm:^3.0.0" + checksum: 10c0/fb5ce7cd810c49254cdf1cd3892811e6dd1a1dfbdf5f10a0a33fb7141baac36443c4cad4f0e2b30abd4eac613f6ab845c2bc1b7ce66ae9694c7321e6ada5bd96 + languageName: node + linkType: hard + "picocolors@npm:^1.0.0, picocolors@npm:^1.1.1": version: 1.1.1 resolution: "picocolors@npm:1.1.1" @@ -1824,6 +2070,25 @@ __metadata: languageName: node linkType: hard +"prettier-plugin-svelte@npm:^3.4.0": + version: 3.4.1 + resolution: "prettier-plugin-svelte@npm:3.4.1" + peerDependencies: + prettier: ^3.0.0 + svelte: ^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0 + checksum: 10c0/ae19ea425458ae26b79eba303a9dd9ffacfb17bf233fa9879a108d4be63929459b226d693e972514afd2fd3c9fa8ee31f9a1bb4749d6dce9012f70f282704c5d + languageName: node + linkType: hard + +"prettier@npm:~3.3.3": + version: 3.3.3 + resolution: "prettier@npm:3.3.3" + bin: + prettier: bin/prettier.cjs + checksum: 10c0/b85828b08e7505716324e4245549b9205c0cacb25342a030ba8885aba2039a115dbcf75a0b7ca3b37bc9d101ee61fab8113fc69ca3359f2a226f1ecc07ad2e26 + languageName: node + linkType: hard + "proc-log@npm:^6.0.0": version: 6.1.0 resolution: "proc-log@npm:6.1.0" @@ -1936,6 +2201,23 @@ __metadata: languageName: node linkType: hard +"runed@npm:^0.35.1": + version: 0.35.1 + resolution: "runed@npm:0.35.1" + dependencies: + dequal: "npm:^2.0.3" + esm-env: "npm:^1.0.0" + lz-string: "npm:^1.5.0" + peerDependencies: + "@sveltejs/kit": ^2.21.0 + svelte: ^5.7.0 + peerDependenciesMeta: + "@sveltejs/kit": + optional: true + checksum: 10c0/ea6c6ba684b52075a5991a0b79d4c381d987f802eabe5689afd495589fdf6fa5aae7eae6843091364b8602643b342deda85f99267c2ff837c83c28d5d9e771ce + languageName: node + linkType: hard + "sade@npm:^1.7.4": version: 1.8.1 resolution: "sade@npm:1.8.1" @@ -1952,7 +2234,14 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.3.5": +"scule@npm:^1.3.0": + version: 1.3.0 + resolution: "scule@npm:1.3.0" + checksum: 10c0/5d1736daa10622c420f2aa74e60d3c722e756bfb139fa784ae5c66669fdfe92932d30ed5072e4ce3107f9c3053e35ad73b2461cb18de45b867e1d4dea63f8823 + languageName: node + linkType: hard + +"semver@npm:^7.3.5, semver@npm:^7.3.8": version: 7.7.3 resolution: "semver@npm:7.7.3" bin: @@ -1989,7 +2278,7 @@ __metadata: languageName: node linkType: hard -"source-map-js@npm:^1.2.1": +"source-map-js@npm:^1.0.1, source-map-js@npm:^1.2.1": version: 1.2.1 resolution: "source-map-js@npm:1.2.1" checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf @@ -2005,6 +2294,15 @@ __metadata: languageName: node linkType: hard +"style-to-object@npm:^1.0.8": + version: 1.0.14 + resolution: "style-to-object@npm:1.0.14" + dependencies: + inline-style-parser: "npm:0.2.7" + checksum: 10c0/854d9e9b77afc336e6d7b09348e7939f2617b34eb0895824b066d8cd1790284cb6d8b2ba36be88025b2595d715dba14b299ae76e4628a366541106f639e13679 + languageName: node + linkType: hard + "svelte-check@npm:^4.3.4": version: 4.3.5 resolution: "svelte-check@npm:4.3.5" @@ -2023,6 +2321,83 @@ __metadata: languageName: node linkType: hard +"svelte-language-server@npm:^0.17.23": + version: 0.17.23 + resolution: "svelte-language-server@npm:0.17.23" + dependencies: + "@jridgewell/trace-mapping": "npm:^0.3.25" + "@vscode/emmet-helper": "npm:2.8.4" + chokidar: "npm:^4.0.1" + estree-walker: "npm:^2.0.1" + fdir: "npm:^6.2.0" + globrex: "npm:^0.1.2" + lodash: "npm:^4.17.21" + prettier: "npm:~3.3.3" + prettier-plugin-svelte: "npm:^3.4.0" + svelte: "npm:^4.2.19" + svelte2tsx: "npm:~0.7.46" + typescript: "npm:^5.9.2" + typescript-auto-import-cache: "npm:^0.3.6" + vscode-css-languageservice: "npm:~6.3.5" + vscode-html-languageservice: "npm:~5.4.0" + vscode-languageserver: "npm:9.0.1" + vscode-languageserver-protocol: "npm:3.17.5" + vscode-languageserver-types: "npm:3.17.5" + vscode-uri: "npm:~3.1.0" + bin: + svelteserver: bin/server.js + checksum: 10c0/229e17c7c1845da0ef5f05380c9bb6cec83633c168546c70ee186f5b24994d733b4f9001fb0a005afea2a49c7e67acd6a70fda3a6f0594c57b83d5ec128b75e8 + languageName: node + linkType: hard + +"svelte-toolbelt@npm:^0.10.6": + version: 0.10.6 + resolution: "svelte-toolbelt@npm:0.10.6" + dependencies: + clsx: "npm:^2.1.1" + runed: "npm:^0.35.1" + style-to-object: "npm:^1.0.8" + peerDependencies: + svelte: ^5.30.2 + checksum: 10c0/1d8edc5ba5daba4b97e427f1a324f86157b0e9efd98acdd88e852a3c901a7e0ad06170422376d24bf9dad8016ef06075f298778b37b91335ba51599b5ae9c8af + languageName: node + linkType: hard + +"svelte2tsx@npm:~0.7.46": + version: 0.7.46 + resolution: "svelte2tsx@npm:0.7.46" + dependencies: + dedent-js: "npm:^1.0.1" + scule: "npm:^1.3.0" + peerDependencies: + svelte: ^3.55 || ^4.0.0-next.0 || ^4.0 || ^5.0.0-next.0 + typescript: ^4.9.4 || ^5.0.0 + checksum: 10c0/b3c860bd9bd5b2de2f692c7561b8c17203dfb68a31f4ff19290ec5e68a5001db7666ec05a2ea1491730c332ea64d55ec3eef81a9f7748fb5a79947a4282ca026 + languageName: node + linkType: hard + +"svelte@npm:^4.2.19": + version: 4.2.20 + resolution: "svelte@npm:4.2.20" + dependencies: + "@ampproject/remapping": "npm:^2.2.1" + "@jridgewell/sourcemap-codec": "npm:^1.4.15" + "@jridgewell/trace-mapping": "npm:^0.3.18" + "@types/estree": "npm:^1.0.1" + acorn: "npm:^8.9.0" + aria-query: "npm:^5.3.0" + axobject-query: "npm:^4.0.0" + code-red: "npm:^1.0.3" + css-tree: "npm:^2.3.1" + estree-walker: "npm:^3.0.3" + is-reference: "npm:^3.0.1" + locate-character: "npm:^3.0.0" + magic-string: "npm:^0.30.4" + periscopic: "npm:^3.1.0" + checksum: 10c0/b51d5d01aa363f47c1631b6f4160754221bc8d234146d3ddeea6172928ad6554acc925c2fb39c31e5cab77ba6711f1c49f4c79e2e592eb4df4eb418b8793a0f9 + languageName: node + linkType: hard + "svelte@npm:^5.45.6": version: 5.46.1 resolution: "svelte@npm:5.46.1" @@ -2046,6 +2421,13 @@ __metadata: languageName: node linkType: hard +"tabbable@npm:^6.2.0": + version: 6.3.0 + resolution: "tabbable@npm:6.3.0" + checksum: 10c0/57ba019d29b5cfa0c862248883bcec0e6d29d8f156ba52a1f425e7cfeca4a0fc701ab8d035c4c86ddf74ecdbd0e9f454a88d9b55d924a51f444038e9cd14d7a0 + languageName: node + linkType: hard + "tailwind-merge@npm:^3.4.0": version: 3.4.0 resolution: "tailwind-merge@npm:3.4.0" @@ -2103,7 +2485,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.4.0": +"tslib@npm:^2.4.0, tslib@npm:^2.8.0": version: 2.8.1 resolution: "tslib@npm:2.8.1" checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 @@ -2117,7 +2499,16 @@ __metadata: languageName: node linkType: hard -"typescript@npm:^5.9.3": +"typescript-auto-import-cache@npm:^0.3.6": + version: 0.3.6 + resolution: "typescript-auto-import-cache@npm:0.3.6" + dependencies: + semver: "npm:^7.3.8" + checksum: 10c0/aad48d6aa9985f9a056c5c89ab91b6781c5430c0b80652586c2a997f2cc394f3ed70ec18c0c818a8423991a1cfe7e64d010cc2fded9ea192067a3188476c2b51 + languageName: node + linkType: hard + +"typescript@npm:^5.9.2, typescript@npm:^5.9.3": version: 5.9.3 resolution: "typescript@npm:5.9.3" bin: @@ -2127,7 +2518,7 @@ __metadata: languageName: node linkType: hard -"typescript@patch:typescript@npm%3A^5.9.3#optional!builtin": +"typescript@patch:typescript@npm%3A^5.9.2#optional!builtin, typescript@patch:typescript@npm%3A^5.9.3#optional!builtin": version: 5.9.3 resolution: "typescript@patch:typescript@npm%3A5.9.3#optional!builtin::version=5.9.3&hash=5786d5" bin: @@ -2222,6 +2613,93 @@ __metadata: languageName: node linkType: hard +"vscode-css-languageservice@npm:~6.3.5": + version: 6.3.9 + resolution: "vscode-css-languageservice@npm:6.3.9" + dependencies: + "@vscode/l10n": "npm:^0.0.18" + vscode-languageserver-textdocument: "npm:^1.0.12" + vscode-languageserver-types: "npm:3.17.5" + vscode-uri: "npm:^3.1.0" + checksum: 10c0/bd796771a735e5ca8489a0830cb6d1880fadaaeb5ca6058ea58f3266f038dc9c9ccb8df1a80b30443b2c4f10f2544ab86a483bd46cdd9ba43f04e298f150155c + languageName: node + linkType: hard + +"vscode-html-languageservice@npm:~5.4.0": + version: 5.4.0 + resolution: "vscode-html-languageservice@npm:5.4.0" + dependencies: + "@vscode/l10n": "npm:^0.0.18" + vscode-languageserver-textdocument: "npm:^1.0.12" + vscode-languageserver-types: "npm:^3.17.5" + vscode-uri: "npm:^3.1.0" + checksum: 10c0/a67fafa723b55fd389d58b7105fd747ef79b9dd0b926e4b2169ca17655951a57904a7e02c4d4bdae2b01deaf37064583cec9a1b97d21a9e33b25fa19d4297e9a + languageName: node + linkType: hard + +"vscode-jsonrpc@npm:8.2.0": + version: 8.2.0 + resolution: "vscode-jsonrpc@npm:8.2.0" + checksum: 10c0/0789c227057a844f5ead55c84679206227a639b9fb76e881185053abc4e9848aa487245966cc2393fcb342c4541241b015a1a2559fddd20ac1e68945c95344e6 + languageName: node + linkType: hard + +"vscode-languageserver-protocol@npm:3.17.5": + version: 3.17.5 + resolution: "vscode-languageserver-protocol@npm:3.17.5" + dependencies: + vscode-jsonrpc: "npm:8.2.0" + vscode-languageserver-types: "npm:3.17.5" + checksum: 10c0/5f38fd80da9868d706eaa4a025f4aff9c3faad34646bcde1426f915cbd8d7e8b6c3755ce3fef6eebd256ba3145426af1085305f8a76e34276d2e95aaf339a90b + languageName: node + linkType: hard + +"vscode-languageserver-textdocument@npm:^1.0.1, vscode-languageserver-textdocument@npm:^1.0.12": + version: 1.0.12 + resolution: "vscode-languageserver-textdocument@npm:1.0.12" + checksum: 10c0/534349894b059602c4d97615a1147b6c4c031141c2093e59657f54e38570f5989c21b376836f13b9375419869242e9efb4066643208b21ab1e1dee111a0f00fb + languageName: node + linkType: hard + +"vscode-languageserver-types@npm:3.17.5, vscode-languageserver-types@npm:^3.15.1, vscode-languageserver-types@npm:^3.17.5": + version: 3.17.5 + resolution: "vscode-languageserver-types@npm:3.17.5" + checksum: 10c0/1e1260de79a2cc8de3e46f2e0182cdc94a7eddab487db5a3bd4ee716f67728e685852707d72c059721ce500447be9a46764a04f0611e94e4321ffa088eef36f8 + languageName: node + linkType: hard + +"vscode-languageserver@npm:9.0.1": + version: 9.0.1 + resolution: "vscode-languageserver@npm:9.0.1" + dependencies: + vscode-languageserver-protocol: "npm:3.17.5" + bin: + installServerIntoExtension: bin/installServerIntoExtension + checksum: 10c0/8a0838d77c98a211c76e54bd3a6249fc877e4e1a73322673fb0e921168d8e91de4f170f1d4ff7e8b6289d0698207afc6aba6662d4c1cd8e4bd7cae96afd6b0c2 + languageName: node + linkType: hard + +"vscode-nls@npm:^5.0.0": + version: 5.2.0 + resolution: "vscode-nls@npm:5.2.0" + checksum: 10c0/dc9e48f58ebbc807f435d351008813a2ea0c9432d51e778bcac9163c0642f929ddb518411ad654e775ce31e24d6acfa8fb7db8893c05b42c2019894e08b050f9 + languageName: node + linkType: hard + +"vscode-uri@npm:^2.1.2": + version: 2.1.2 + resolution: "vscode-uri@npm:2.1.2" + checksum: 10c0/4ed01e79f8caee5518d7dce567280001a00c87ff75c29421ac3693c735834f17950e79f818981c591e58c6efe681e13928470037b6ae75c948bec9b398e4c8db + languageName: node + linkType: hard + +"vscode-uri@npm:^3.1.0, vscode-uri@npm:~3.1.0": + version: 3.1.0 + resolution: "vscode-uri@npm:3.1.0" + checksum: 10c0/5f6c9c10fd9b1664d71fab4e9fbbae6be93c7f75bb3a1d9d74399a88ab8649e99691223fd7cef4644376cac6e94fa2c086d802521b9a8e31c5af3e60f0f35624 + languageName: node + linkType: hard + "which@npm:^6.0.0": version: 6.0.0 resolution: "which@npm:6.0.0"