From 8c05be3a83a22d8c675c9930109da284fc959d94 Mon Sep 17 00:00:00 2001 From: hugos68 Date: Fri, 17 May 2024 17:24:20 +0200 Subject: [PATCH 01/21] Added search --- .eslintignore | 2 + .gitignore | 1 + .prettierignore | 1 + package.json | 4 +- pnpm-lock.yaml | 77 +++++++ .../components/PageHeader/PageHeader.svelte | 2 + src/docs/components/PageHeader/Search.svelte | 125 +++++++++++ src/docs/types.ts | 207 ++++++++++++++++++ src/routes/(inner)/+layout.svelte | 2 +- vite.config.ts | 9 +- 10 files changed, 427 insertions(+), 3 deletions(-) create mode 100644 src/docs/components/PageHeader/Search.svelte diff --git a/.eslintignore b/.eslintignore index 1a258241..785e27df 100644 --- a/.eslintignore +++ b/.eslintignore @@ -8,8 +8,10 @@ node_modules .env.* !.env.example /coverage +**/pagefind # Ignore files for PNPM, NPM and YARN pnpm-lock.yaml package-lock.json yarn.lock + diff --git a/.gitignore b/.gitignore index aa375a81..011c15c9 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ node_modules vite.config.js.timestamp-* vite.config.ts.timestamp-* /coverage +**/pagefind \ No newline at end of file diff --git a/.prettierignore b/.prettierignore index 68c83f36..cd362878 100644 --- a/.prettierignore +++ b/.prettierignore @@ -5,3 +5,4 @@ yarn.lock /coverage **/*.mdx **/*.md +**/pagefind diff --git a/package.json b/package.json index b95a3157..1a3b01c8 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "dev": "vite dev", "preview": "vite preview", "build": "pnpm build:docs && pnpm build:package", - "build:docs": "svelte-kit sync && vite build", + "build:docs": "svelte-kit sync && vite build && pagefind --site build", "build:package": "svelte-kit sync && svelte-package && publint", "ci:publish": "pnpm build:package && changeset publish", "test": "vitest run --coverage", @@ -53,6 +53,7 @@ "eslint-plugin-svelte": "^2.36.0-next.4", "jsdom": "^24.0.0", "lucide-svelte": "^0.373.0", + "pagefind": "^1.1.0", "postcss": "^8.4.32", "postcss-load-config": "^5.0.2", "prettier": "^3.1.1", @@ -65,6 +66,7 @@ "tslib": "^2.4.1", "typescript": "^5.0.0", "vite": "^5.0.11", + "vite-plugin-pagefind": "^0.0.30", "vitest": "^1.2.0" }, "svelte": "./dist/index.js", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5359f0f2..e2259c3f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -69,6 +69,9 @@ importers: lucide-svelte: specifier: ^0.373.0 version: 0.373.0(svelte@5.0.0-next.125) + pagefind: + specifier: ^1.1.0 + version: 1.1.0 postcss: specifier: ^8.4.32 version: 8.4.38 @@ -105,6 +108,9 @@ importers: vite: specifier: ^5.0.11 version: 5.2.11 + vite-plugin-pagefind: + specifier: ^0.0.30 + version: 0.0.30 vitest: specifier: ^1.2.0 version: 1.6.0(jsdom@24.0.0) @@ -122,6 +128,10 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} + '@antfu/ni@0.21.12': + resolution: {integrity: sha512-2aDL3WUv8hMJb2L3r/PIQWsTLyq7RQr3v9xD16fiz6O8ys1xEyLhhTOv8gxtZvJiTzjTF5pHoArvRdesGL1DMQ==} + hasBin: true + '@babel/code-frame@7.24.2': resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==} engines: {node: '>=6.9.0'} @@ -430,6 +440,31 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@pagefind/darwin-arm64@1.1.0': + resolution: {integrity: sha512-SLsXNLtSilGZjvqis8sX42fBWsWAVkcDh1oerxwqbac84HbiwxpxOC2jm8hRwcR0Z55HPZPWO77XeRix/8GwTg==} + cpu: [arm64] + os: [darwin] + + '@pagefind/darwin-x64@1.1.0': + resolution: {integrity: sha512-QjQSE/L5oS1C8N8GdljGaWtjCBMgMtfrPAoiCmINTu9Y9dp0ggAyXvF8K7Qg3VyIMYJ6v8vg2PN7Z3b+AaAqUA==} + cpu: [x64] + os: [darwin] + + '@pagefind/linux-arm64@1.1.0': + resolution: {integrity: sha512-8zjYCa2BtNEL7KnXtysPtBELCyv5DSQ4yHeK/nsEq6w4ToAMTBl0K06khqxdSGgjMSwwrxvLzq3so0LC5Q14dA==} + cpu: [arm64] + os: [linux] + + '@pagefind/linux-x64@1.1.0': + resolution: {integrity: sha512-4lsg6VB7A6PWTwaP8oSmXV4O9H0IHX7AlwTDcfyT+YJo/sPXOVjqycD5cdBgqNLfUk8B9bkWcTDCRmJbHrKeCw==} + cpu: [x64] + os: [linux] + + '@pagefind/windows-x64@1.1.0': + resolution: {integrity: sha512-OboCM76BcMKT9IoSfZuFhiqMRgTde8x4qDDvKulFmycgiJrlL5WnIqBHJLQxZq+o2KyZpoHF97iwsGAm8c32sQ==} + cpu: [x64] + os: [win32] + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -937,6 +972,9 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -1989,6 +2027,10 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + pagefind@1.1.0: + resolution: {integrity: sha512-1nmj0/vfYcMxNEQj0YDRp6bTVv9hI7HLdPhK/vBBYlrnwjATndQvHyicj5Y7pUHrpCFZpFnLVQXIF829tpFmaw==} + hasBin: true + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -2706,6 +2748,9 @@ packages: engines: {node: ^18.0.0 || >=20.0.0} hasBin: true + vite-plugin-pagefind@0.0.30: + resolution: {integrity: sha512-gqdHbEU+v3YduhD8Igp/oOGIbk0+mSVuVJXK38DSXfZoIMFEMX3A5ZzTjRsCoOmwF25K4f65lFfv6R5p520YPQ==} + vite@5.2.11: resolution: {integrity: sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==} engines: {node: ^18.0.0 || >=20.0.0} @@ -2920,6 +2965,8 @@ snapshots: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 + '@antfu/ni@0.21.12': {} + '@babel/code-frame@7.24.2': dependencies: '@babel/highlight': 7.24.5 @@ -3275,6 +3322,21 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 + '@pagefind/darwin-arm64@1.1.0': + optional: true + + '@pagefind/darwin-x64@1.1.0': + optional: true + + '@pagefind/linux-arm64@1.1.0': + optional: true + + '@pagefind/linux-x64@1.1.0': + optional: true + + '@pagefind/windows-x64@1.1.0': + optional: true + '@pkgjs/parseargs@0.11.0': optional: true @@ -3823,6 +3885,8 @@ snapshots: color-name@1.1.4: {} + colorette@2.0.20: {} + combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 @@ -4994,6 +5058,14 @@ snapshots: p-try@2.2.0: {} + pagefind@1.1.0: + optionalDependencies: + '@pagefind/darwin-arm64': 1.1.0 + '@pagefind/darwin-x64': 1.1.0 + '@pagefind/linux-arm64': 1.1.0 + '@pagefind/linux-x64': 1.1.0 + '@pagefind/windows-x64': 1.1.0 + parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -5751,6 +5823,11 @@ snapshots: - supports-color - terser + vite-plugin-pagefind@0.0.30: + dependencies: + '@antfu/ni': 0.21.12 + colorette: 2.0.20 + vite@5.2.11: dependencies: esbuild: 0.20.2 diff --git a/src/docs/components/PageHeader/PageHeader.svelte b/src/docs/components/PageHeader/PageHeader.svelte index c28507b3..6248b480 100644 --- a/src/docs/components/PageHeader/PageHeader.svelte +++ b/src/docs/components/PageHeader/PageHeader.svelte @@ -4,6 +4,7 @@ // Icons import IconMenu from 'lucide-svelte/icons/menu'; + import Search from './Search.svelte';
Floating UI Svelte +
+ import { + autoUpdate, + offset, + useClick, + useDismiss, + useFloating, + useInteractions, + } from '$lib/index.js'; + import SearchIcon from 'lucide-svelte/icons/search'; + import LoaderIcon from 'lucide-svelte/icons/loader'; + import type { Pagefind } from '$docs/types.js'; + + let pagefind: Pagefind | null = null; + + $effect(() => { + // @ts-expect-error - Pagefind will be present at runtime + import('/pagefind/pagefind.js').then((module: Pagefind) => { + pagefind = module; + pagefind.init(); + }); + }); + + let open = $state(false); + + const floating = useFloating({ + whileElementsMounted: autoUpdate, + get open() { + return open; + }, + onOpenChange(value) { + open = value; + }, + middleware: [offset(10)], + }); + + // TODO: Move to `useFocus` once https://github.com/skeletonlabs/floating-ui-svelte/pull/99 is merged + const click = useClick(floating.context); + const dismiss = useDismiss(floating.context); + const interactions = useInteractions([click, dismiss]); + + let query = $state(''); + + const searchPromise = $derived.by(async () => { + if (pagefind === null || query === '') { + return []; + } + const result = await pagefind.debouncedSearch(query); + + if (result === null) { + return []; + } + + return await Promise.all(result.results.map((result) => result.data())); + }); + + $effect(() => { + if (query !== '') { + open = true; + } + }); + + +
+ +
+ {#if query !== ''} + {#await searchPromise} + + {:then} + + {/await} + {:else} + + {/if} +
+
+ +{#if open && query !== ''} +
+{/if} + + diff --git a/src/docs/types.ts b/src/docs/types.ts index 90b1bd43..8c93688f 100644 --- a/src/docs/types.ts +++ b/src/docs/types.ts @@ -8,3 +8,210 @@ export interface TableData { default?: string; required?: boolean; } + +/* eslint-disable @typescript-eslint/ban-types */ +/** Global index options that can be passed to pagefind.options() */ +export type PagefindIndexOptions = { + /** Overrides the URL path that Pagefind uses to load its search bundle */ + basePath?: string; + /** Appends the given baseURL to all search results. May be a path, or a full domain */ + baseUrl?: string; + /** The maximum length of excerpts that Pagefind should generate for search results. Default to 30 */ + excerptLength?: number; + /** + * Multiply all rankings for this index by the given weight. + * + * Only applies in multisite setups, where one site should rank higher or lower than others. + */ + indexWeight?: number; + /** + * Merge this filter object into all search queries in this index. + * + * Only applies in multisite setups. + */ + mergeFilter?: Object; + language?: string; + /** + * Whether an instance of Pagefind is the primary index or not (for multisite). + * + * This is set for you automatically, so it is unlikely you should set this directly. + */ + primary?: boolean; +}; + +/** Options that can be passed to pagefind.search() */ +export type PagefindSearchOptions = { + /** If set, this call will load all assets but return before searching. Prefer using pagefind.preload() instead */ + preload?: boolean; + /** Add more verbose console logging for this search query */ + verbose?: boolean; + /** The set of filters to execute with this search. Input type is extremely flexible, see the filtering docs for details */ + filters?: Object; + /** The set of sorts to use for this search, instead of relevancy */ + sort?: Object; +}; + +/** Filter counts returned from pagefind.filters(), and alongside results from pagefind.search() */ +type PagefindFilterCounts = Record>; + +/** The main results object returned from a call to pagefind.search() */ +export type PagefindSearchResults = { + /** All pages that match the search query and filters provided */ + results: PagefindSearchResult[]; + /** How many results would there have been if you had omitted the filters */ + unfilteredResultCount: number; + /** Given the query and filters provided, how many remaining results are there under each filter? */ + filters: PagefindFilterCounts; + /** If the searched filters were removed, how many total results for each filter are there? */ + totalFilters: PagefindFilterCounts; + /** Information on how long it took Pagefind to execute this query */ + timings: { + preload: number; + search: number; + total: number; + }; +}; + +/** A single result from a search query, before actual data has been loaded */ +export type PagefindSearchResult = { + /** Pagefind's internal ID for this page, unique across the site */ + id: string; + /** Pagefind's internal score for your query matching this page, that is used when ranking these results */ + score: number; + /** The locations of all matching words in this page */ + words: number[]; + /** + * Calling data() loads the final data fragment needed to display this result. + * + * Only call this when you need to display the data, rather than all at once. + * (e.g. one page as a time, or in a scroll listener) + * */ + data: () => Promise; +}; + +/** The useful data Pagefind provides for a search result */ +export type PagefindSearchFragment = { + /** Pagefind's processed URL for this page. Will include the baseUrl if configured */ + url: string; + /** Pagefind's unprocessed URL for this page */ + raw_url?: string; + /** The full processed content text of this page */ + content: string; + /** Internal type — ignore for now */ + raw_content?: string; + /** The processed excerpt for this result, with matching terms wrapping in `` elements */ + excerpt: string; + /** + * What regions of the page matched this search query? + * + * Precalculates based on h1->6 tags with IDs, using the text between each. + */ + sub_results: PagefindSubResult[]; + /** How many total words are there on this page? */ + word_count: number; + /** The locations of all matching words in this page */ + locations: number[]; + /** + * The locations of all matching words in this page, + * paired with data about their weight and relevance to this query + */ + weighted_locations: PagefindWordLocation[]; + /** The filter keys and values this page was tagged with */ + filters: Record; + /** The metadata keys and values this page was tagged with */ + meta: Record; + /** + * The raw anchor data that Pagefind used to generate sub_results. + * + * Contains _all_ elements that had IDs on the page, so can be used to + * implement your own sub result calculations with different semantics. + */ + anchors: PagefindSearchAnchor[]; +}; + +/** Data for a matched section within a page */ +export type PagefindSubResult = { + /** + * Title of this sub result — derived from the heading content. + * + * If this is a result for the section of the page before any headings with IDs, + * this will be the same as the page's meta.title value. + */ + title: string; + /** + * Direct URL to this sub result, comprised of the page's URL plus the hash string of the heading. + * + * If this is a result for the section of the page before any headings with IDs, + * this will be the same as the page URL. + */ + url: string; + /** The locations of all matching words in this segment */ + locations: number[]; + /** + * The locations of all matching words in this segment, + * paired with data about their weight and relevance to this query + */ + weighted_locations: PagefindWordLocation[]; + /** The processed excerpt for this segment, with matching terms wrapping in `` elements */ + excerpt: string; + /** + * Raw data about the anchor element associated with this sub result. + * + * The omission of this field means this sub result is for text found on the page + * before the first heading that had an ID. + */ + anchor?: PagefindSearchAnchor; +}; + +/** Information about a matching word on a page */ +export type PagefindWordLocation = { + /** The weight that this word was originally tagged as */ + weight: number; + /** + * An internal score that Pagefind calculated for this word. + * + * The absolute value is somewhat meaningless, but the value can be used + * in comparison to other values in this set of search results to perform custom ranking. + */ + balanced_score: number; + /** + * The index of this word in the result content. + * + * Splitting the content key by whitespacing and indexing by this number + * will yield the correct word. + */ + location: number; +}; + +/** Raw data about elements with IDs that Pagefind encountered when indexing the page */ +export type PagefindSearchAnchor = { + /** What element type was this anchor? e.g. `h1`, `div` */ + element: string; + /** The raw id="..." attribute contents of the element */ + id: string; + /** + * The text content of this element. + * + * In order to prevent repeating most of the page data for every anchor, + * Pagefind will only take top level text nodes, or text nodes nested within + * inline elements such as and . + */ + text?: string; + /** + * The position of this anchor in the result content. + * Splitting the content key by whitespacing and indexing by this number + * will yield the first word indexed after this element's ID was found. + */ + location: number; +}; + +export type Pagefind = { + init: () => Promise; + search: (query: string, options?: PagefindSearchOptions) => Promise; + debouncedSearch: ( + query: string, + options?: PagefindSearchOptions, + duration?: number, + ) => Promise; + options: (options: PagefindIndexOptions) => Promise; +}; diff --git a/src/routes/(inner)/+layout.svelte b/src/routes/(inner)/+layout.svelte index 1fa9ae5d..55b3f06b 100644 --- a/src/routes/(inner)/+layout.svelte +++ b/src/routes/(inner)/+layout.svelte @@ -41,7 +41,7 @@ -
+
diff --git a/vite.config.ts b/vite.config.ts index b6e3c4c5..41ce33c3 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,9 +1,16 @@ import { defineConfig } from 'vitest/config'; import { sveltekit } from '@sveltejs/kit/vite'; import { svelteTesting } from '@testing-library/svelte/vite'; +import { pagefind, type PagefindConfig } from 'vite-plugin-pagefind'; + +const pagefindConfig: PagefindConfig = { + buildDir: 'build', + buildScript: 'build:docs', + publicDir: 'static', +}; export default defineConfig({ - plugins: [sveltekit(), svelteTesting()], + plugins: [sveltekit(), svelteTesting(), pagefind(pagefindConfig)], experimental: { // Remove when https://github.com/sveltejs/vite-plugin-svelte/issues/909 is fixed hmrPartialAccept: false, From b43ba5e4ef08b31708e18b49d1778a8d829d242d Mon Sep 17 00:00:00 2001 From: hugos68 Date: Fri, 17 May 2024 19:43:51 +0200 Subject: [PATCH 02/21] fix? --- vite.config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vite.config.ts b/vite.config.ts index 41ce33c3..69103e04 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -4,9 +4,9 @@ import { svelteTesting } from '@testing-library/svelte/vite'; import { pagefind, type PagefindConfig } from 'vite-plugin-pagefind'; const pagefindConfig: PagefindConfig = { - buildDir: 'build', + buildDir: './build', buildScript: 'build:docs', - publicDir: 'static', + publicDir: './static', }; export default defineConfig({ From 50cc525c19d30849dccb397473a8a3932a201cf2 Mon Sep 17 00:00:00 2001 From: hugos68 Date: Fri, 17 May 2024 19:54:23 +0200 Subject: [PATCH 03/21] output --- vite.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vite.config.ts b/vite.config.ts index 69103e04..bb3cacfb 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -4,7 +4,7 @@ import { svelteTesting } from '@testing-library/svelte/vite'; import { pagefind, type PagefindConfig } from 'vite-plugin-pagefind'; const pagefindConfig: PagefindConfig = { - buildDir: './build', + buildDir: process.env.VERCEL ? '.vercel/output/static' : 'build', buildScript: 'build:docs', publicDir: './static', }; From 62928a510f8f52e2439913e676d0a0efb8648185 Mon Sep 17 00:00:00 2001 From: hugos68 Date: Fri, 17 May 2024 19:55:26 +0200 Subject: [PATCH 04/21] Test with vercel config --- vercel.json | 3 +++ vite.config.ts | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 vercel.json diff --git a/vercel.json b/vercel.json new file mode 100644 index 00000000..b7c60edc --- /dev/null +++ b/vercel.json @@ -0,0 +1,3 @@ +{ + "outputDirectory": "build" +} \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index bb3cacfb..6acd288c 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -4,7 +4,7 @@ import { svelteTesting } from '@testing-library/svelte/vite'; import { pagefind, type PagefindConfig } from 'vite-plugin-pagefind'; const pagefindConfig: PagefindConfig = { - buildDir: process.env.VERCEL ? '.vercel/output/static' : 'build', + buildDir: 'build', buildScript: 'build:docs', publicDir: './static', }; From 28ae1c02d9f35be87598b55482a7b8b4bab13e29 Mon Sep 17 00:00:00 2001 From: hugos68 Date: Fri, 17 May 2024 20:00:29 +0200 Subject: [PATCH 05/21] done? --- svelte.config.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/svelte.config.js b/svelte.config.js index 6284f19a..00503dfb 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -6,7 +6,10 @@ import { readFileSync } from 'node:fs'; const config = { preprocess: [vitePreprocess()], kit: { - adapter: adapter(), + adapter: adapter({ + pages: 'build', + assets: 'build' + }), alias: { $docs: './src/docs', '@skeletonlabs/floating-ui-svelte': './src/lib/index.js', From b1f4d9023e4a6f71e73ec5a2a723d17e02f07aa7 Mon Sep 17 00:00:00 2001 From: hugos68 Date: Fri, 17 May 2024 20:01:35 +0200 Subject: [PATCH 06/21] test with vercel.json --- vercel.json | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 vercel.json diff --git a/vercel.json b/vercel.json deleted file mode 100644 index b7c60edc..00000000 --- a/vercel.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "outputDirectory": "build" -} \ No newline at end of file From 89a3088aa1f169f20671530b9e57fbfe9275143c Mon Sep 17 00:00:00 2001 From: hugos68 Date: Fri, 17 May 2024 20:03:28 +0200 Subject: [PATCH 07/21] stuff --- svelte.config.js | 2 +- vercel.json | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 vercel.json diff --git a/svelte.config.js b/svelte.config.js index 00503dfb..40122d03 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -8,7 +8,7 @@ const config = { kit: { adapter: adapter({ pages: 'build', - assets: 'build' + assets: 'build', }), alias: { $docs: './src/docs', diff --git a/vercel.json b/vercel.json new file mode 100644 index 00000000..03578cfe --- /dev/null +++ b/vercel.json @@ -0,0 +1,3 @@ +{ + "outputDirectory": "build" +} From 4ebeea28ac32d38bfb6d0f746d05cef98cd654b7 Mon Sep 17 00:00:00 2001 From: hugos68 Date: Sat, 18 May 2024 01:28:08 +0200 Subject: [PATCH 08/21] Overhaul, modal stuffs --- src/docs/components/Dialog/Dialog.svelte | 61 +++++++++ src/docs/components/Overlay/Overlay.svelte | 15 +++ .../components/PageHeader/PageHeader.svelte | 4 +- src/docs/components/PageHeader/Search.svelte | 125 ------------------ .../components/PageHeader/SearchDialog.svelte | 100 ++++++++++++++ src/docs/components/Portal/Portal.svelte | 31 +++++ src/routes/+layout.svelte | 5 +- 7 files changed, 213 insertions(+), 128 deletions(-) create mode 100644 src/docs/components/Dialog/Dialog.svelte create mode 100644 src/docs/components/Overlay/Overlay.svelte delete mode 100644 src/docs/components/PageHeader/Search.svelte create mode 100644 src/docs/components/PageHeader/SearchDialog.svelte create mode 100644 src/docs/components/Portal/Portal.svelte diff --git a/src/docs/components/Dialog/Dialog.svelte b/src/docs/components/Dialog/Dialog.svelte new file mode 100644 index 00000000..0d29a5ef --- /dev/null +++ b/src/docs/components/Dialog/Dialog.svelte @@ -0,0 +1,61 @@ + + + + {#if open} + + + {/if} + diff --git a/src/docs/components/Overlay/Overlay.svelte b/src/docs/components/Overlay/Overlay.svelte new file mode 100644 index 00000000..b5441ea0 --- /dev/null +++ b/src/docs/components/Overlay/Overlay.svelte @@ -0,0 +1,15 @@ + + +
+ +
+ {@render children()} +
diff --git a/src/docs/components/PageHeader/PageHeader.svelte b/src/docs/components/PageHeader/PageHeader.svelte index 6248b480..5bb2d18c 100644 --- a/src/docs/components/PageHeader/PageHeader.svelte +++ b/src/docs/components/PageHeader/PageHeader.svelte @@ -4,7 +4,7 @@ // Icons import IconMenu from 'lucide-svelte/icons/menu'; - import Search from './Search.svelte'; + import SearchDialog from './SearchDialog.svelte';
Floating UI Svelte
- +
- import { - autoUpdate, - offset, - useClick, - useDismiss, - useFloating, - useInteractions, - } from '$lib/index.js'; - import SearchIcon from 'lucide-svelte/icons/search'; - import LoaderIcon from 'lucide-svelte/icons/loader'; - import type { Pagefind } from '$docs/types.js'; - - let pagefind: Pagefind | null = null; - - $effect(() => { - // @ts-expect-error - Pagefind will be present at runtime - import('/pagefind/pagefind.js').then((module: Pagefind) => { - pagefind = module; - pagefind.init(); - }); - }); - - let open = $state(false); - - const floating = useFloating({ - whileElementsMounted: autoUpdate, - get open() { - return open; - }, - onOpenChange(value) { - open = value; - }, - middleware: [offset(10)], - }); - - // TODO: Move to `useFocus` once https://github.com/skeletonlabs/floating-ui-svelte/pull/99 is merged - const click = useClick(floating.context); - const dismiss = useDismiss(floating.context); - const interactions = useInteractions([click, dismiss]); - - let query = $state(''); - - const searchPromise = $derived.by(async () => { - if (pagefind === null || query === '') { - return []; - } - const result = await pagefind.debouncedSearch(query); - - if (result === null) { - return []; - } - - return await Promise.all(result.results.map((result) => result.data())); - }); - - $effect(() => { - if (query !== '') { - open = true; - } - }); - - -
- -
- {#if query !== ''} - {#await searchPromise} - - {:then} - - {/await} - {:else} - - {/if} -
-
- -{#if open && query !== ''} -
-{/if} - - diff --git a/src/docs/components/PageHeader/SearchDialog.svelte b/src/docs/components/PageHeader/SearchDialog.svelte new file mode 100644 index 00000000..75c396e7 --- /dev/null +++ b/src/docs/components/PageHeader/SearchDialog.svelte @@ -0,0 +1,100 @@ + + + + + +
+
+ + +
+
+ {#await searchPromise then results} + {#if results.length > 0} +

+ Found {results.length} + {results.length === 1 ? 'result' : 'results'} for "{query}": +

+ + {:else if query !== ''} +

No results found for "{query}"

+ {/if} + {/await} +
+
+
+ + diff --git a/src/docs/components/Portal/Portal.svelte b/src/docs/components/Portal/Portal.svelte new file mode 100644 index 00000000..5c5b70ed --- /dev/null +++ b/src/docs/components/Portal/Portal.svelte @@ -0,0 +1,31 @@ + + +
+ {@render children()} +
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index bceae6ed..b8554945 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -2,6 +2,7 @@ // Stylesheets import '../app.pcss'; import { page } from '$app/stores'; + import Overlay from '$docs/components/Overlay/Overlay.svelte'; // Props let { children } = $props(); @@ -19,4 +20,6 @@ {title} | Floating UI Svelte -{@render children()} + + {@render children()} + From 3e0942b9cf048359a9c692e44033bd457b727d05 Mon Sep 17 00:00:00 2001 From: hugos68 Date: Sat, 18 May 2024 10:54:20 +0200 Subject: [PATCH 09/21] search --- src/docs/components/Dialog/Dialog.svelte | 6 ++++-- src/docs/components/PageHeader/SearchDialog.svelte | 4 ++-- src/routes/(inner)/+layout.svelte | 8 ++++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/docs/components/Dialog/Dialog.svelte b/src/docs/components/Dialog/Dialog.svelte index 0d29a5ef..b38a6df0 100644 --- a/src/docs/components/Dialog/Dialog.svelte +++ b/src/docs/components/Dialog/Dialog.svelte @@ -51,11 +51,13 @@ > {/if} diff --git a/src/docs/components/PageHeader/SearchDialog.svelte b/src/docs/components/PageHeader/SearchDialog.svelte index 75c396e7..88897784 100644 --- a/src/docs/components/PageHeader/SearchDialog.svelte +++ b/src/docs/components/PageHeader/SearchDialog.svelte @@ -55,7 +55,7 @@ -
+
-
+
{#await searchPromise then results} {#if results.length > 0}

diff --git a/src/routes/(inner)/+layout.svelte b/src/routes/(inner)/+layout.svelte index 55b3f06b..d6484651 100644 --- a/src/routes/(inner)/+layout.svelte +++ b/src/routes/(inner)/+layout.svelte @@ -41,11 +41,15 @@ -

+
-
+
{@render children()}
From 4145a9b50909d09f565453b8fb9a555f9a4d7c51 Mon Sep 17 00:00:00 2001 From: hugos68 Date: Sat, 18 May 2024 16:42:27 +0200 Subject: [PATCH 10/21] Removed debounce for shits and giggles --- src/docs/components/PageHeader/SearchDialog.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/docs/components/PageHeader/SearchDialog.svelte b/src/docs/components/PageHeader/SearchDialog.svelte index 88897784..95f36e84 100644 --- a/src/docs/components/PageHeader/SearchDialog.svelte +++ b/src/docs/components/PageHeader/SearchDialog.svelte @@ -11,7 +11,7 @@ if (pagefind === null || query === '') { return []; } - const result = await pagefind.debouncedSearch(query); + const result = await pagefind.search(query); if (result === null) { return []; From 1cd8264e84012a672ce5aba1643a2a52590e4589 Mon Sep 17 00:00:00 2001 From: hugos68 Date: Sat, 18 May 2024 16:50:54 +0200 Subject: [PATCH 11/21] Better init --- src/app.d.ts | 1 + .../components/PageHeader/SearchDialog.svelte | 18 ++++++------------ src/routes/+layout.ts | 12 ++++++++++++ 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/app.d.ts b/src/app.d.ts index 9f8152d6..756c4d05 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -6,6 +6,7 @@ declare global { // interface Locals {} interface PageData { highlighter: import('shiki').Highlighter; + pagefind: import('$docs/types.ts').Pagefind; } // interface PageState {} // interface Platform {} diff --git a/src/docs/components/PageHeader/SearchDialog.svelte b/src/docs/components/PageHeader/SearchDialog.svelte index 95f36e84..a3772109 100644 --- a/src/docs/components/PageHeader/SearchDialog.svelte +++ b/src/docs/components/PageHeader/SearchDialog.svelte @@ -1,17 +1,19 @@ {#if open} - +
{/if}
diff --git a/src/docs/components/PageHeader/SearchDialog.svelte b/src/docs/components/PageHeader/SearchDialog.svelte index a3772109..0a6944e3 100644 --- a/src/docs/components/PageHeader/SearchDialog.svelte +++ b/src/docs/components/PageHeader/SearchDialog.svelte @@ -36,8 +36,6 @@ document.removeEventListener('keydown', onKeydown); }; }); - - const focus = (node: HTMLElement) => node.focus();
From b65b836277b25c9cc0d650de3ae051e243eaf54f Mon Sep 17 00:00:00 2001 From: hugos68 Date: Sat, 18 May 2024 17:57:51 +0200 Subject: [PATCH 13/21] Moved drawer to global dialog system with types --- src/docs/components/Dialog/Dialog.svelte | 27 ++++++++++++------ .../components/Navigation/Navigation.svelte | 14 ++++++++-- .../components/PageHeader/PageHeader.svelte | 10 +++++-- src/docs/stores.svelte.ts | 17 ++++------- src/routes/(inner)/+layout.svelte | 28 ------------------- src/routes/+layout.svelte | 22 +++++++++++++++ 6 files changed, 67 insertions(+), 51 deletions(-) diff --git a/src/docs/components/Dialog/Dialog.svelte b/src/docs/components/Dialog/Dialog.svelte index 137c78d6..becfbd0e 100644 --- a/src/docs/components/Dialog/Dialog.svelte +++ b/src/docs/components/Dialog/Dialog.svelte @@ -8,10 +8,11 @@ interface Props { children: Snippet; + type?: 'modal' | 'drawer'; open?: boolean; } - let { children, open = $bindable(false) }: Props = $props(); + let { children, type = 'drawer', open = $bindable(false) }: Props = $props(); $effect(() => { if (open) { @@ -49,18 +50,28 @@ beforeNavigate(() => { open = false; }); + + const commonClasses = 'fixed z-50'; + + const classes = $derived( + { + drawer: `${commonClasses} top-0 left-0 right-0 bottom-0 h-screen w-fit max-w-[500px]`, + modal: `${commonClasses} top-4 md:top-[15%] left-1/2 -translate-x-1/2 w-[calc(100%-2rem)] max-w-[500px] rounded-md bg-surface-700`, + }[type], + ); + + const flyParams = $derived( + { + drawer: { x: -200, duration: 200 }, + modal: { y: 50, easing: cubicOut, duration: 250 }, + }[type], + ); {#if open}
-