From df73ebd8cf4d88df7469b3d0736b24d218df467d Mon Sep 17 00:00:00 2001 From: Jesse Winton Date: Mon, 25 Aug 2025 14:22:45 -0400 Subject: [PATCH 01/26] Update Search.svelte --- src/lib/components/Search.svelte | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/lib/components/Search.svelte b/src/lib/components/Search.svelte index 892ab0085b..61c5528921 100644 --- a/src/lib/components/Search.svelte +++ b/src/lib/components/Search.svelte @@ -14,9 +14,14 @@ let container: HTMLDivElement; const client = new MeiliSearch({ - host: 'https://search.appwrite.org', - apiKey: '10a5fea149bfaff21ef4d7cbe7f8a09d4fab404d6c3510279a365e065f8955a7' + host: 'https://ms-4f2b8bcd5490-29219.fra.meilisearch.io', + apiKey: 'b347cbb673ff7c143dfb2dca1dda55c2e849e585' }); + + // const client = new MeiliSearch({ + // host: 'https://search.appwrite.org', + // apiKey: '10a5fea149bfaff21ef4d7cbe7f8a09d4fab404d6c3510279a365e065f8955a7' + // }); const index = client.index('website'); type Props = { From ff2d4809422296c7fd510e61b77e516db44f5a9a Mon Sep 17 00:00:00 2001 From: Jesse Winton Date: Mon, 25 Aug 2025 15:08:22 -0400 Subject: [PATCH 02/26] update --- src/lib/components/search-v2.svelte | 116 ++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 src/lib/components/search-v2.svelte diff --git a/src/lib/components/search-v2.svelte b/src/lib/components/search-v2.svelte new file mode 100644 index 0000000000..c04b6ccbc7 --- /dev/null +++ b/src/lib/components/search-v2.svelte @@ -0,0 +1,116 @@ + + + + + + + From 99237802f719bf05cabe8be2d791dd556b461e2a Mon Sep 17 00:00:00 2001 From: Jesse Winton Date: Mon, 25 Aug 2025 15:44:49 -0400 Subject: [PATCH 03/26] update --- src/lib/components/search-v2.svelte | 199 +++++++++++++++++++++++++++- src/lib/layouts/Docs.svelte | 3 +- 2 files changed, 196 insertions(+), 6 deletions(-) diff --git a/src/lib/components/search-v2.svelte b/src/lib/components/search-v2.svelte index c04b6ccbc7..61c5528921 100644 --- a/src/lib/components/search-v2.svelte +++ b/src/lib/components/search-v2.svelte @@ -2,11 +2,16 @@ import { afterNavigate, goto } from '$app/navigation'; import { layoutState } from '$lib/layouts/Docs.svelte'; import { isMac } from '$lib/utils/platform'; - import { Command } from 'bits-ui'; import { createCombobox, melt } from '@melt-ui/svelte'; import { type Hit, type Hits, MeiliSearch } from 'meilisearch'; + import { tick } from 'svelte'; + + export let open = true; + + let value: string; + let container: HTMLDivElement; const client = new MeiliSearch({ host: 'https://ms-4f2b8bcd5490-29219.fra.meilisearch.io', @@ -17,7 +22,6 @@ // host: 'https://search.appwrite.org', // apiKey: '10a5fea149bfaff21ef4d7cbe7f8a09d4fab404d6c3510279a365e065f8955a7' // }); - const index = client.index('website'); type Props = { @@ -54,6 +58,13 @@ } } + function handleExit(event: MouseEvent & { currentTarget: EventTarget & HTMLDivElement }) { + if (event.target === container) { + open = false; + value = ''; + } + } + function createHref(hit: Hit): string { const anchor = hit.anchor === '#' ? '' : (hit.anchor ?? ''); const target = hit.url + anchor; @@ -88,7 +99,37 @@ } ]; + afterNavigate(() => { + open = false; + }); + + $: handleInput(value); + let inputEl: HTMLInputElement; + $: if (open && inputEl) { + inputEl.value = ''; + inputEl?.focus(); + } + + const { + elements: { input, menu, option }, + states: { inputValue } + } = createCombobox({ + forceVisible: true, + preventScroll: false, + portal: null, + positioning: null, + onSelectedChange({ next }) { + if (next) { + goto(next.value.url); + tick().then(() => { + inputValue.set(''); + }); + inputValue.set(''); + } + return undefined; + } + }); function handleKeypress(event: KeyboardEvent) { const cmdPressed = isMac() ? event.metaKey : event.ctrlKey; @@ -111,6 +152,154 @@ - - - + + +
+
+ + + + { + if (e.key === 'Tab') { + e.preventDefault(); + } + }} + /> +
+ {#if value} +
+ {#if results.length > 0} +
+ {results.length} results found +
+ + {:else} +

+ No results found for {value} +

+ {/if} +
+ {/if} +
+
Recommended
+ +
+
+
+
+ + diff --git a/src/lib/layouts/Docs.svelte b/src/lib/layouts/Docs.svelte index 26e8871f78..6e5cecd3c9 100644 --- a/src/lib/layouts/Docs.svelte +++ b/src/lib/layouts/Docs.svelte @@ -47,6 +47,7 @@ import { getAppwriteDashboardUrl } from '$lib/utils/dashboard'; import { Button, Icon, InlineTag } from '$lib/components/ui'; import { afterNavigate } from '$app/navigation'; + import SearchV2 from '$lib/components/search-v2.svelte'; interface Props { variant?: DocsLayoutVariant; @@ -205,4 +206,4 @@ - + From 6492623e0aab316e79bfea3f880d9a94ba68d6bf Mon Sep 17 00:00:00 2001 From: Jesse Winton Date: Mon, 25 Aug 2025 16:27:31 -0400 Subject: [PATCH 04/26] Update search-v2.svelte --- src/lib/components/search-v2.svelte | 169 ++++++++++++++-------------- 1 file changed, 86 insertions(+), 83 deletions(-) diff --git a/src/lib/components/search-v2.svelte b/src/lib/components/search-v2.svelte index 61c5528921..f96fb8c1fb 100644 --- a/src/lib/components/search-v2.svelte +++ b/src/lib/components/search-v2.svelte @@ -7,24 +7,30 @@ import { type Hit, type Hits, MeiliSearch } from 'meilisearch'; import { tick } from 'svelte'; + import Icon from './ui/icon'; - export let open = true; + interface SearchProps { + open: boolean; + } + + let { open = $bindable(false) }: SearchProps = $props(); - let value: string; + let value = $state(''); let container: HTMLDivElement; + // const client = new MeiliSearch({ + // host: 'https://ms-4f2b8bcd5490-29219.fra.meilisearch.io', + // apiKey: 'b347cbb673ff7c143dfb2dca1dda55c2e849e585' + // }); + const client = new MeiliSearch({ - host: 'https://ms-4f2b8bcd5490-29219.fra.meilisearch.io', - apiKey: 'b347cbb673ff7c143dfb2dca1dda55c2e849e585' + host: 'https://search.appwrite.org', + apiKey: '10a5fea149bfaff21ef4d7cbe7f8a09d4fab404d6c3510279a365e065f8955a7' }); - // const client = new MeiliSearch({ - // host: 'https://search.appwrite.org', - // apiKey: '10a5fea149bfaff21ef4d7cbe7f8a09d4fab404d6c3510279a365e065f8955a7' - // }); - const index = client.index('website'); + const index = client.index('website'); - type Props = { + interface IndexProps { url: string; title?: string; uid?: string; @@ -39,23 +45,21 @@ h6?: string; p?: string; anchor?: string; - }; + } - let results: Hits = []; + let results = $state>([]); + let isSearching = $state(false); - async function search(value: string) { - return index.search(value, { + async function handleSearch(value: string) { + return await index.search(value, { limit: 20 }); } async function handleInput(value: string) { - if (!value) { - results = []; - } else { - const response = await search(value); - results = response.hits; - } + if (value.length < 3) return; + const response = await handleSearch(value); + results = response.hits; } function handleExit(event: MouseEvent & { currentTarget: EventTarget & HTMLDivElement }) { @@ -65,37 +69,28 @@ } } - function createHref(hit: Hit): string { + function createHref(hit: Hit): string { const anchor = hit.anchor === '#' ? '' : (hit.anchor ?? ''); const target = hit.url + anchor; return target.toString(); } - const recommended: Hits = [ + const recommended: Hits = [ { - uid: 'recommended-references-account', - url: '/docs/references/cloud/client-web/account', - h1: 'API reference', - h2: 'Account' + uid: 'blog', + url: '/block', + h1: 'Blog' }, { - uid: 'recommended-references-teams', - url: '/docs/references/cloud/client-web/teams', - h1: 'API reference', - h2: 'Teams' + uid: 'docs', + url: '/docs', + h1: 'Docs' }, { - uid: 'recommended-references-databases', - url: '/docs/references/cloud/client-web/databases', - h1: 'API reference', - h2: 'Databases' - }, - { - uid: 'recommended-references-storage', - url: '/docs/references/cloud/client-web/storage', - h1: 'API reference', - h2: 'Storage' + uid: 'pricing', + url: '/pricing', + h1: 'Pricing' } ]; @@ -103,18 +98,23 @@ open = false; }); - $: handleInput(value); + $effect(() => { + handleInput(value); + }); let inputEl: HTMLInputElement; - $: if (open && inputEl) { - inputEl.value = ''; - inputEl?.focus(); - } + + $effect(() => { + if (open && inputEl) { + inputEl.value = ''; + inputEl?.focus(); + } + }); const { elements: { input, menu, option }, states: { inputValue } - } = createCombobox({ + } = createCombobox({ forceVisible: true, preventScroll: false, portal: null, @@ -152,8 +152,8 @@ - - + +
-
+
{ + onkeydown={(e) => { if (e.key === 'Tab') { e.preventDefault(); } @@ -190,7 +192,7 @@ use:melt={$menu} style="--card-padding-mobile:1rem; border-radius:0 0 0.5rem 0.5rem;" > - {#if value} + {#if value && value.length >= 3}
{#if results.length > 0}
@@ -240,39 +242,40 @@ {/each} {:else} -

- No results found for {value} +

+ No results found for "{value}"

{/if}
+ {:else} +
+
Suggestions
+
    + {#each recommended as hit, i (hit.uid)} + {@const index = i + (results.length ? results.length : 0)} +
  • + +
    + {hit.h1} +
    + +
    +
  • + {/each} +
+
{/if} -
-
Recommended
- -
From 7a8fa5b0b3ef6f69eed84d8acb149fd85427d9d7 Mon Sep 17 00:00:00 2001 From: Jesse Winton Date: Mon, 25 Aug 2025 16:53:06 -0400 Subject: [PATCH 05/26] working on it --- package.json | 2 +- src/icons/optimized/book.svg | 1 + src/icons/optimized/hash.svg | 1 + src/icons/optimized/text.svg | 1 + src/icons/svg/book.svg | 8 +++++++ src/icons/svg/hash.svg | 6 +++++ src/icons/svg/text.svg | 5 ++++ src/lib/components/search-v2.svelte | 18 ++++---------- .../components/ui/icon/sprite/sprite.svelte | 24 +++++++++++++++++++ src/lib/components/ui/icon/types.ts | 3 +++ src/lib/meilisearch/index.ts | 11 +++++++++ src/search-config.json | 19 +++++++++++++++ 12 files changed, 84 insertions(+), 15 deletions(-) create mode 100644 src/icons/optimized/book.svg create mode 100644 src/icons/optimized/hash.svg create mode 100644 src/icons/optimized/text.svg create mode 100644 src/icons/svg/book.svg create mode 100644 src/icons/svg/hash.svg create mode 100644 src/icons/svg/text.svg create mode 100644 src/lib/meilisearch/index.ts create mode 100644 src/search-config.json diff --git a/package.json b/package.json index 7e66720765..6954fdc775 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "download-contributors": "node ./scripts/download-contributor-data.js", "format": "prettier --write .", "format:check": "prettier --check .", - "generate:icons": "node ./src/icons/optimize.js", + "generate:icons": "node ./src/icons/optimize.js && pnpm format", "icons:build": "node ./src/icons/build.js", "icons:generate": "node ./src/icons/optimize.js && node ./src/icons/build.js", "icons:optimize": "node ./src/icons/optimize.js", diff --git a/src/icons/optimized/book.svg b/src/icons/optimized/book.svg new file mode 100644 index 0000000000..6529e6a822 --- /dev/null +++ b/src/icons/optimized/book.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/optimized/hash.svg b/src/icons/optimized/hash.svg new file mode 100644 index 0000000000..380967cd41 --- /dev/null +++ b/src/icons/optimized/hash.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/optimized/text.svg b/src/icons/optimized/text.svg new file mode 100644 index 0000000000..489b541022 --- /dev/null +++ b/src/icons/optimized/text.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/book.svg b/src/icons/svg/book.svg new file mode 100644 index 0000000000..1c5912ac70 --- /dev/null +++ b/src/icons/svg/book.svg @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/src/icons/svg/hash.svg b/src/icons/svg/hash.svg new file mode 100644 index 0000000000..ab96d0899e --- /dev/null +++ b/src/icons/svg/hash.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/icons/svg/text.svg b/src/icons/svg/text.svg new file mode 100644 index 0000000000..22ea7416c2 --- /dev/null +++ b/src/icons/svg/text.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/lib/components/search-v2.svelte b/src/lib/components/search-v2.svelte index f96fb8c1fb..8372bb1bac 100644 --- a/src/lib/components/search-v2.svelte +++ b/src/lib/components/search-v2.svelte @@ -5,9 +5,10 @@ import { createCombobox, melt } from '@melt-ui/svelte'; - import { type Hit, type Hits, MeiliSearch } from 'meilisearch'; + import { type Hit, type Hits } from 'meilisearch'; import { tick } from 'svelte'; import Icon from './ui/icon'; + import { meilisearchClient } from '$lib/meilisearch'; interface SearchProps { open: boolean; @@ -18,17 +19,7 @@ let value = $state(''); let container: HTMLDivElement; - // const client = new MeiliSearch({ - // host: 'https://ms-4f2b8bcd5490-29219.fra.meilisearch.io', - // apiKey: 'b347cbb673ff7c143dfb2dca1dda55c2e849e585' - // }); - - const client = new MeiliSearch({ - host: 'https://search.appwrite.org', - apiKey: '10a5fea149bfaff21ef4d7cbe7f8a09d4fab404d6c3510279a365e065f8955a7' - }); - - const index = client.index('website'); + const index = meilisearchClient.index('website'); interface IndexProps { url: string; @@ -57,7 +48,6 @@ } async function handleInput(value: string) { - if (value.length < 3) return; const response = await handleSearch(value); results = response.hits; } @@ -79,7 +69,7 @@ const recommended: Hits = [ { uid: 'blog', - url: '/block', + url: '/blog', h1: 'Blog' }, { diff --git a/src/lib/components/ui/icon/sprite/sprite.svelte b/src/lib/components/ui/icon/sprite/sprite.svelte index 59df8605f7..ea58a514ab 100644 --- a/src/lib/components/ui/icon/sprite/sprite.svelte +++ b/src/lib/components/ui/icon/sprite/sprite.svelte @@ -67,6 +67,14 @@ fill-rule="evenodd" > + + + + + + + + + Date: Mon, 25 Aug 2025 16:59:03 -0400 Subject: [PATCH 06/26] tweaks --- src/lib/components/search-v2.svelte | 20 +++++++++++--------- src/lib/meilisearch/index.ts | 14 +++++++------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/lib/components/search-v2.svelte b/src/lib/components/search-v2.svelte index 8372bb1bac..44e71921d3 100644 --- a/src/lib/components/search-v2.svelte +++ b/src/lib/components/search-v2.svelte @@ -202,29 +202,31 @@ label: hit.title ?? i.toString() })} > -
+
{#if subtitleContent.header} - {subtitleContent.header} + + {subtitleContent.subtitle} - {#if subtitleContent.subtitle} + {/if} - {#if subtitleContent.subtitle} +
{#if hit.p}
- {hit.p} + + {hit.p}
{/if} diff --git a/src/lib/meilisearch/index.ts b/src/lib/meilisearch/index.ts index 6da8e6b474..134615603f 100644 --- a/src/lib/meilisearch/index.ts +++ b/src/lib/meilisearch/index.ts @@ -1,11 +1,11 @@ import { MeiliSearch } from 'meilisearch'; +// export const meilisearchClient = new MeiliSearch({ +// host: 'https://ms-4f2b8bcd5490-29219.fra.meilisearch.io', +// apiKey: 'b347cbb673ff7c143dfb2dca1dda55c2e849e585' +// }); + export const meilisearchClient = new MeiliSearch({ - host: 'https://ms-4f2b8bcd5490-29219.fra.meilisearch.io', - apiKey: 'b347cbb673ff7c143dfb2dca1dda55c2e849e585' + host: 'https://search.appwrite.org', + apiKey: '10a5fea149bfaff21ef4d7cbe7f8a09d4fab404d6c3510279a365e065f8955a7' }); - -// const client = new MeiliSearch({ -// host: 'https://search.appwrite.org', -// apiKey: '10a5fea149bfaff21ef4d7cbe7f8a09d4fab404d6c3510279a365e065f8955a7' -// }); From f326842154240bf1d8b73625f2aadd55138b6888 Mon Sep 17 00:00:00 2001 From: Jesse Winton Date: Mon, 25 Aug 2025 17:27:03 -0400 Subject: [PATCH 07/26] updates --- src/icons/optimized/blog.svg | 1 + src/icons/optimized/docs.svg | 1 + src/icons/optimized/integrations.svg | 1 + src/icons/svg/blog.svg | 5 +++ src/icons/svg/book.svg | 8 ---- src/icons/svg/docs.svg | 5 +++ src/icons/svg/hash.svg | 6 --- src/icons/svg/integrations.svg | 5 +++ src/lib/components/search-v2.svelte | 43 +++++++++++++------ .../components/ui/icon/sprite/sprite.svelte | 24 +++++++++++ src/lib/components/ui/icon/types.ts | 3 ++ 11 files changed, 75 insertions(+), 27 deletions(-) create mode 100644 src/icons/optimized/blog.svg create mode 100644 src/icons/optimized/docs.svg create mode 100644 src/icons/optimized/integrations.svg create mode 100644 src/icons/svg/blog.svg delete mode 100644 src/icons/svg/book.svg create mode 100644 src/icons/svg/docs.svg delete mode 100644 src/icons/svg/hash.svg create mode 100644 src/icons/svg/integrations.svg diff --git a/src/icons/optimized/blog.svg b/src/icons/optimized/blog.svg new file mode 100644 index 0000000000..525aaa5433 --- /dev/null +++ b/src/icons/optimized/blog.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/optimized/docs.svg b/src/icons/optimized/docs.svg new file mode 100644 index 0000000000..153c58080b --- /dev/null +++ b/src/icons/optimized/docs.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/optimized/integrations.svg b/src/icons/optimized/integrations.svg new file mode 100644 index 0000000000..176b23d39c --- /dev/null +++ b/src/icons/optimized/integrations.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/blog.svg b/src/icons/svg/blog.svg new file mode 100644 index 0000000000..b19eb99257 --- /dev/null +++ b/src/icons/svg/blog.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/src/icons/svg/book.svg b/src/icons/svg/book.svg deleted file mode 100644 index 1c5912ac70..0000000000 --- a/src/icons/svg/book.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/src/icons/svg/docs.svg b/src/icons/svg/docs.svg new file mode 100644 index 0000000000..7c891111d7 --- /dev/null +++ b/src/icons/svg/docs.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/src/icons/svg/hash.svg b/src/icons/svg/hash.svg deleted file mode 100644 index ab96d0899e..0000000000 --- a/src/icons/svg/hash.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src/icons/svg/integrations.svg b/src/icons/svg/integrations.svg new file mode 100644 index 0000000000..02f5a8c76b --- /dev/null +++ b/src/icons/svg/integrations.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/src/lib/components/search-v2.svelte b/src/lib/components/search-v2.svelte index 44e71921d3..10f997cc36 100644 --- a/src/lib/components/search-v2.svelte +++ b/src/lib/components/search-v2.svelte @@ -19,9 +19,9 @@ let value = $state(''); let container: HTMLDivElement; - const index = meilisearchClient.index('website'); + const index = meilisearchClient.index('website'); - interface IndexProps { + interface SearchResult { url: string; title?: string; uid?: string; @@ -36,14 +36,21 @@ h6?: string; p?: string; anchor?: string; + _formatted?: SearchResult; } - let results = $state>([]); - let isSearching = $state(false); + let results = $state>([]); + + $inspect(results); async function handleSearch(value: string) { return await index.search(value, { - limit: 20 + limit: 20, + attributesToHighlight: ['title', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p'], + cropLength: 40, + highlightPreTag: + '', + highlightPostTag: '' }); } @@ -59,14 +66,14 @@ } } - function createHref(hit: Hit): string { + function createHref(hit: Hit): string { const anchor = hit.anchor === '#' ? '' : (hit.anchor ?? ''); const target = hit.url + anchor; return target.toString(); } - const recommended: Hits = [ + const recommended: Hits = [ { uid: 'blog', url: '/blog', @@ -104,7 +111,7 @@ const { elements: { input, menu, option }, states: { inputValue } - } = createCombobox({ + } = createCombobox({ forceVisible: true, preventScroll: false, portal: null, @@ -191,6 +198,8 @@
    {#each results as hit, i (hit.uid)} {@const subtitleContent = getSubtitleContent(hit)} + {@const isDocs = hit.urls_tags?.includes('docs')} + {@const isBlog = hit.urls_tags?.includes('blog')}
  • -
    +
    {#if subtitleContent.header} - + {subtitleContent.subtitle} @@ -221,12 +237,13 @@ > {/if} -->
    - {#if hit.p} + {#if hit._formatted}
    - - {hit.p} + {@html hit._formatted.p}
    {/if}
    diff --git a/src/lib/components/ui/icon/sprite/sprite.svelte b/src/lib/components/ui/icon/sprite/sprite.svelte index ea58a514ab..2d19f87b39 100644 --- a/src/lib/components/ui/icon/sprite/sprite.svelte +++ b/src/lib/components/ui/icon/sprite/sprite.svelte @@ -59,6 +59,14 @@ fill="currentColor" > + + + + + + + + + Date: Mon, 25 Aug 2025 17:29:58 -0400 Subject: [PATCH 08/26] update --- src/lib/meilisearch/index.ts | 5 ----- src/search-config.json | 19 ------------------- 2 files changed, 24 deletions(-) delete mode 100644 src/search-config.json diff --git a/src/lib/meilisearch/index.ts b/src/lib/meilisearch/index.ts index 134615603f..407b8f7a50 100644 --- a/src/lib/meilisearch/index.ts +++ b/src/lib/meilisearch/index.ts @@ -1,10 +1,5 @@ import { MeiliSearch } from 'meilisearch'; -// export const meilisearchClient = new MeiliSearch({ -// host: 'https://ms-4f2b8bcd5490-29219.fra.meilisearch.io', -// apiKey: 'b347cbb673ff7c143dfb2dca1dda55c2e849e585' -// }); - export const meilisearchClient = new MeiliSearch({ host: 'https://search.appwrite.org', apiKey: '10a5fea149bfaff21ef4d7cbe7f8a09d4fab404d6c3510279a365e065f8955a7' diff --git a/src/search-config.json b/src/search-config.json deleted file mode 100644 index 2156a7f1b3..0000000000 --- a/src/search-config.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "start_urls": [ - "https://appwrite.io/docs", - "https://appwrite.io/blog", - "https://appwrite.io/integrations" - ], - "meilisearch_url": "https://ms-4f2b8bcd5490-29219.fra.meilisearch.io", - "meilisearch_api_key": "b347cbb673ff7c143dfb2dca1dda55c2e849e585", - "meilisearch_index_uid": "website", - "strategy": "default", - "headless": true, - "batch_size": 1000, - "primary_key": null, - "meilisearch_settings": { - "searchableAttributes": ["h1", "h2", "h3", "h4", "h5", "h6", "p", "title"], - "filterableAttributes": ["urls_tags"], - "distinctAttribute": "url" - } -} From dc229d69907917f65195cc517f36f5b866ddf7db Mon Sep 17 00:00:00 2001 From: Jesse Winton Date: Mon, 25 Aug 2025 17:31:03 -0400 Subject: [PATCH 09/26] rm --- src/lib/components/search-v2.svelte | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/lib/components/search-v2.svelte b/src/lib/components/search-v2.svelte index 10f997cc36..0abee5ba27 100644 --- a/src/lib/components/search-v2.svelte +++ b/src/lib/components/search-v2.svelte @@ -5,10 +5,9 @@ import { createCombobox, melt } from '@melt-ui/svelte'; - import { type Hit, type Hits } from 'meilisearch'; + import { type Hit, type Hits, MeiliSearch } from 'meilisearch'; import { tick } from 'svelte'; import Icon from './ui/icon'; - import { meilisearchClient } from '$lib/meilisearch'; interface SearchProps { open: boolean; @@ -19,6 +18,11 @@ let value = $state(''); let container: HTMLDivElement; + const meilisearchClient = new MeiliSearch({ + host: 'https://search.appwrite.org', + apiKey: '10a5fea149bfaff21ef4d7cbe7f8a09d4fab404d6c3510279a365e065f8955a7' + }); + const index = meilisearchClient.index('website'); interface SearchResult { From e911e8dd4dd674033815279d46d7dfd2b2175892 Mon Sep 17 00:00:00 2001 From: Jesse Winton Date: Mon, 25 Aug 2025 17:31:54 -0400 Subject: [PATCH 10/26] rm --- src/lib/meilisearch/index.ts | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 src/lib/meilisearch/index.ts diff --git a/src/lib/meilisearch/index.ts b/src/lib/meilisearch/index.ts deleted file mode 100644 index 407b8f7a50..0000000000 --- a/src/lib/meilisearch/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { MeiliSearch } from 'meilisearch'; - -export const meilisearchClient = new MeiliSearch({ - host: 'https://search.appwrite.org', - apiKey: '10a5fea149bfaff21ef4d7cbe7f8a09d4fab404d6c3510279a365e065f8955a7' -}); From 546da3a3c9380672602cbe4dd8b598da9daa9f94 Mon Sep 17 00:00:00 2001 From: Jesse Winton Date: Mon, 25 Aug 2025 17:32:52 -0400 Subject: [PATCH 11/26] Delete Search.svelte --- src/lib/components/Search.svelte | 305 ------------------------------- 1 file changed, 305 deletions(-) delete mode 100644 src/lib/components/Search.svelte diff --git a/src/lib/components/Search.svelte b/src/lib/components/Search.svelte deleted file mode 100644 index 61c5528921..0000000000 --- a/src/lib/components/Search.svelte +++ /dev/null @@ -1,305 +0,0 @@ - - - - - - -
    -
    - - - - { - if (e.key === 'Tab') { - e.preventDefault(); - } - }} - /> -
    - {#if value} -
    - {#if results.length > 0} -
    - {results.length} results found -
    - - {:else} -

    - No results found for {value} -

    - {/if} -
    - {/if} -
    -
    Recommended
    - -
    -
    -
    -
    - - From 712e4728349900f2bff2b45b45a1a48771023cbe Mon Sep 17 00:00:00 2001 From: Jesse Winton Date: Tue, 26 Aug 2025 08:10:59 -0400 Subject: [PATCH 12/26] tweak --- src/lib/components/Newsletter.svelte | 13 ------------- src/lib/components/index.ts | 2 +- src/lib/components/search-v2.svelte | 5 +++++ src/lib/layouts/Docs.svelte | 6 +++--- 4 files changed, 9 insertions(+), 17 deletions(-) diff --git a/src/lib/components/Newsletter.svelte b/src/lib/components/Newsletter.svelte index 659fec0f63..8668ffc8ba 100644 --- a/src/lib/components/Newsletter.svelte +++ b/src/lib/components/Newsletter.svelte @@ -141,16 +141,3 @@
- - diff --git a/src/lib/components/index.ts b/src/lib/components/index.ts index 1028053c25..3e8a408189 100644 --- a/src/lib/components/index.ts +++ b/src/lib/components/index.ts @@ -14,4 +14,4 @@ export { default as Feedback } from './Feedback.svelte'; export { default as Select } from './Select.svelte'; export { default as MetricCard } from './MetricCard.svelte'; export { default as IsLoggedIn } from './IsLoggedIn.svelte'; -export { default as Search } from './Search.svelte'; +export { default as Search } from './search-v2.svelte'; diff --git a/src/lib/components/search-v2.svelte b/src/lib/components/search-v2.svelte index 0abee5ba27..c7ddc56a9f 100644 --- a/src/lib/components/search-v2.svelte +++ b/src/lib/components/search-v2.svelte @@ -24,6 +24,7 @@ }); const index = meilisearchClient.index('website'); + index.updateFilterableAttributes(['h1']); interface SearchResult { url: string; @@ -49,6 +50,7 @@ async function handleSearch(value: string) { return await index.search(value, { + distinct: 'h1', limit: 20, attributesToHighlight: ['title', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p'], cropLength: 40, @@ -204,6 +206,9 @@ {@const subtitleContent = getSubtitleContent(hit)} {@const isDocs = hit.urls_tags?.includes('docs')} {@const isBlog = hit.urls_tags?.includes('blog')} + {@const isTutorial = hit.urls_tags?.includes('tutorials')} + {@const isIntegration = hit.urls_tags?.includes('integrations')} + {@const isReference = hit.urls_tags?.includes('reference')}}
  • @@ -164,25 +181,35 @@ onclick={handleExit} >
    - - { - if (e.key === 'Tab') { - e.preventDefault(); - } - }} - /> +
    + + { + if (e.key === 'Tab') { + e.preventDefault(); + } + }} + /> + {#if value} + + {/if} +
    @@ -201,46 +228,41 @@
    - - diff --git a/src/lib/components/ui/icon/sprite/sprite.svelte b/src/lib/components/ui/icon/sprite/sprite.svelte index 2d19f87b39..3660506484 100644 --- a/src/lib/components/ui/icon/sprite/sprite.svelte +++ b/src/lib/components/ui/icon/sprite/sprite.svelte @@ -59,6 +59,13 @@ fill="currentColor" > + + + + + + + + + + + + + + + + + + Date: Tue, 26 Aug 2025 12:46:03 -0400 Subject: [PATCH 16/26] workin --- meilisearch.config.json | 14 +++++++++++ src/lib/components/search-v2.svelte | 36 +++++++++++++++++------------ src/routes/search/sync/+server.ts | 7 ++++++ 3 files changed, 42 insertions(+), 15 deletions(-) create mode 100644 meilisearch.config.json create mode 100644 src/routes/search/sync/+server.ts diff --git a/meilisearch.config.json b/meilisearch.config.json new file mode 100644 index 0000000000..b3d469e884 --- /dev/null +++ b/meilisearch.config.json @@ -0,0 +1,14 @@ +{ + "start_urls": ["https://appwrite.io/docs"], + "meilisearch_url": "https://search.appwrite.org", + "meilisearch_index_uid": "website", + "strategy": "default", + "headless": true, + "batch_size": 1000, + "primary_key": null, + "meilisearch_settings": { + "searchableAttributes": ["h1", "h2", "h3", "h4", "h5", "h6", "p", "title"], + "filterableAttributes": ["urls_tags"], + "distinctAttribute": "url" + } +} diff --git a/src/lib/components/search-v2.svelte b/src/lib/components/search-v2.svelte index 8438d5f6f9..a69b4cc6aa 100644 --- a/src/lib/components/search-v2.svelte +++ b/src/lib/components/search-v2.svelte @@ -51,13 +51,12 @@ const handleInput = async (value: string) => { const response = await index.search(value, { - attributesToCrop: ['h1', 'p'], + attributesToCrop: ['p'], cropLength: 40, limit: 20, - attributesToHighlight: ['title', 'p'], - highlightPreTag: - '', - highlightPostTag: '' + attributesToHighlight: ['title', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p'], + highlightPreTag: '', + highlightPostTag: '' }); results = response.hits; }; @@ -184,7 +183,7 @@
    {#if value && value.length >= 3}
    @@ -246,15 +244,22 @@ class="size-4" />
    -
    -
    +
    +
    {#if subtitleContent.header} - + {@html subtitleContent.header} {#if subtitleContent.subtitle} - / - / + {@html subtitleContent.subtitle} {/if} @@ -264,7 +269,8 @@
    - {@html hit._formatted.p}
    @@ -282,7 +288,7 @@ {:else}
    -
    Suggestions
    +
    Suggestions
      {#each recommended as hit, i (hit.uid)} {@const index = i + (results.length ? results.length : 0)} diff --git a/src/routes/search/sync/+server.ts b/src/routes/search/sync/+server.ts new file mode 100644 index 0000000000..db27730447 --- /dev/null +++ b/src/routes/search/sync/+server.ts @@ -0,0 +1,7 @@ +import { json } from '@sveltejs/kit'; + +export function GET() { + const number = Math.floor(Math.random() * 6) + 1; + + return json(number); +} From 7f957c66e9f3a2a1685dcee9459646ea281f6094 Mon Sep 17 00:00:00 2001 From: Jesse Winton Date: Tue, 26 Aug 2025 13:13:37 -0400 Subject: [PATCH 17/26] rm bad class --- src/icons/optimized/blog.svg | 2 +- src/icons/optimized/database.svg | 2 +- src/icons/svg/blog.svg | 8 ++++---- src/icons/svg/database.svg | 11 +++-------- src/lib/components/search-v2.svelte | 6 +++--- src/lib/components/ui/icon/sprite/sprite.svelte | 7 ++++--- 6 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/icons/optimized/blog.svg b/src/icons/optimized/blog.svg index 525aaa5433..c00f9a5de1 100644 --- a/src/icons/optimized/blog.svg +++ b/src/icons/optimized/blog.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/icons/optimized/database.svg b/src/icons/optimized/database.svg index 0595e933a2..da1d0cee61 100644 --- a/src/icons/optimized/database.svg +++ b/src/icons/optimized/database.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/icons/svg/blog.svg b/src/icons/svg/blog.svg index b19eb99257..b845af4443 100644 --- a/src/icons/svg/blog.svg +++ b/src/icons/svg/blog.svg @@ -1,5 +1,5 @@ - - + + \ No newline at end of file diff --git a/src/icons/svg/database.svg b/src/icons/svg/database.svg index a72489496f..1f0f8f820a 100644 --- a/src/icons/svg/database.svg +++ b/src/icons/svg/database.svg @@ -1,9 +1,4 @@ - - - - - + + \ No newline at end of file diff --git a/src/lib/components/search-v2.svelte b/src/lib/components/search-v2.svelte index a69b4cc6aa..1fc5eb028e 100644 --- a/src/lib/components/search-v2.svelte +++ b/src/lib/components/search-v2.svelte @@ -183,7 +183,7 @@
      {#if value && value.length >= 3} @@ -305,7 +305,7 @@
      - {hit.h1} + {hit.h1}
      diff --git a/src/lib/components/ui/icon/sprite/sprite.svelte b/src/lib/components/ui/icon/sprite/sprite.svelte index 3660506484..7502b57099 100644 --- a/src/lib/components/ui/icon/sprite/sprite.svelte +++ b/src/lib/components/ui/icon/sprite/sprite.svelte @@ -68,10 +68,10 @@ @@ -188,7 +188,8 @@ From 21474208885cb5c8573a28ee2fbc36f15bff9df9 Mon Sep 17 00:00:00 2001 From: Jesse Winton Date: Tue, 26 Aug 2025 13:15:23 -0400 Subject: [PATCH 18/26] updates --- src/lib/components/search-v2.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/search-v2.svelte b/src/lib/components/search-v2.svelte index 1fc5eb028e..edb634a102 100644 --- a/src/lib/components/search-v2.svelte +++ b/src/lib/components/search-v2.svelte @@ -183,7 +183,7 @@
      Date: Tue, 26 Aug 2025 15:20:39 -0400 Subject: [PATCH 19/26] update --- package.json | 2 + pnpm-lock.yaml | 80 +++++++++++ src/hooks.server.ts | 6 +- src/lib/components/search-v2.svelte | 214 +++++++++++++++------------- src/routes/search/(lib)/blog.ts | 34 +++++ src/routes/search/(lib)/client.ts | 10 ++ src/routes/search/(lib)/types.ts | 21 +++ src/routes/search/(lib)/utils.ts | 128 +++++++++++++++++ src/routes/search/show/+server.ts | 0 src/routes/search/sync/+server.ts | 16 ++- 10 files changed, 409 insertions(+), 102 deletions(-) create mode 100644 src/routes/search/(lib)/blog.ts create mode 100644 src/routes/search/(lib)/client.ts create mode 100644 src/routes/search/(lib)/types.ts create mode 100644 src/routes/search/(lib)/utils.ts create mode 100644 src/routes/search/show/+server.ts diff --git a/package.json b/package.json index 9570764560..69f863015e 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "@fingerprintjs/fingerprintjs": "^4.5.1", "@internationalized/date": "3.5.0", "@lucide/svelte": "^0.539.0", + "@markdoc/markdoc": "^0.5.4", "@melt-ui/pp": "^0.3.2", "@melt-ui/svelte": "^0.86.5", "@number-flow/svelte": "^0.3.7", @@ -73,6 +74,7 @@ "eslint-plugin-svelte": "^2.46.1", "fuse.js": "^7.0.0", "globals": "^15.14.0", + "gray-matter": "^4.0.3", "highlight.js": "^11.11.1", "linkedom": "^0.18.9", "markdown-it": "^14.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6d5dfc1285..54df44db93 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,6 +45,9 @@ importers: '@lucide/svelte': specifier: ^0.539.0 version: 0.539.0(svelte@5.38.3) + '@markdoc/markdoc': + specifier: ^0.5.4 + version: 0.5.4 '@melt-ui/pp': specifier: ^0.3.2 version: 0.3.2(@melt-ui/svelte@0.86.6(svelte@5.38.3))(svelte@5.38.3) @@ -144,6 +147,9 @@ importers: globals: specifier: ^15.14.0 version: 15.15.0 + gray-matter: + specifier: ^4.0.3 + version: 4.0.3 highlight.js: specifier: ^11.11.1 version: 11.11.1 @@ -1893,6 +1899,9 @@ packages: engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} deprecated: This package is no longer supported. + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -2397,6 +2406,11 @@ packages: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + esquery@1.6.0: resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} @@ -2440,6 +2454,10 @@ packages: exponential-backoff@3.1.2: resolution: {integrity: sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==} + extend-shallow@2.0.1: + resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} + engines: {node: '>=0.10.0'} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -2633,6 +2651,10 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + gray-matter@4.0.3: + resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} + engines: {node: '>=6.0'} + h3@1.15.4: resolution: {integrity: sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ==} @@ -2754,6 +2776,10 @@ packages: resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} + is-extendable@0.1.1: + resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} + engines: {node: '>=0.10.0'} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -2840,6 +2866,10 @@ packages: js-tokens@9.0.1: resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true @@ -2863,6 +2893,10 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + kleur@4.1.5: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} @@ -3670,6 +3704,10 @@ packages: sax@1.4.1: resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} + section-matter@1.0.0: + resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==} + engines: {node: '>=4'} + semver@7.7.2: resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} engines: {node: '>=10'} @@ -3737,6 +3775,9 @@ packages: split2@1.1.1: resolution: {integrity: sha512-cfurE2q8LamExY+lJ9Ex3ZfBwqAPduzOKVscPDXNCLLMvyaeD3DTz1yk7fVIs6Chco+12XeD0BB6HEoYzPYbXA==} + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + ssri@9.0.1: resolution: {integrity: sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} @@ -3769,6 +3810,10 @@ packages: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} engines: {node: '>=12'} + strip-bom-string@1.0.0: + resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==} + engines: {node: '>=0.10.0'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -5794,6 +5839,10 @@ snapshots: delegates: 1.0.0 readable-stream: 3.6.2 + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + argparse@2.0.1: {} aria-query@5.3.2: {} @@ -6359,6 +6408,8 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.15.0) eslint-visitor-keys: 3.4.3 + esprima@4.0.1: {} + esquery@1.6.0: dependencies: estraverse: 5.3.0 @@ -6391,6 +6442,10 @@ snapshots: exponential-backoff@3.1.2: {} + extend-shallow@2.0.1: + dependencies: + is-extendable: 0.1.1 + fast-deep-equal@3.1.3: {} fast-glob@3.3.3: @@ -6597,6 +6652,13 @@ snapshots: graphemer@1.4.0: {} + gray-matter@4.0.3: + dependencies: + js-yaml: 3.14.1 + kind-of: 6.0.3 + section-matter: 1.0.0 + strip-bom-string: 1.0.0 + h3@1.15.4: dependencies: cookie-es: 1.2.2 @@ -6709,6 +6771,8 @@ snapshots: dependencies: hasown: 2.0.2 + is-extendable@0.1.1: {} + is-extglob@2.1.1: {} is-fullwidth-code-point@3.0.0: {} @@ -6794,6 +6858,11 @@ snapshots: js-tokens@9.0.1: {} + js-yaml@3.14.1: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + js-yaml@4.1.0: dependencies: argparse: 2.0.1 @@ -6821,6 +6890,8 @@ snapshots: dependencies: json-buffer: 3.0.1 + kind-of@6.0.3: {} + kleur@4.1.5: {} known-css-properties@0.35.0: {} @@ -7545,6 +7616,11 @@ snapshots: sax@1.4.1: {} + section-matter@1.0.0: + dependencies: + extend-shallow: 2.0.1 + kind-of: 6.0.3 + semver@7.7.2: {} set-blocking@2.0.0: {} @@ -7651,6 +7727,8 @@ snapshots: dependencies: through2: 2.0.5 + sprintf-js@1.0.3: {} + ssri@9.0.1: dependencies: minipass: 3.3.6 @@ -7687,6 +7765,8 @@ snapshots: dependencies: ansi-regex: 6.2.0 + strip-bom-string@1.0.0: {} + strip-json-comments@3.1.1: {} strip-literal@3.0.0: diff --git a/src/hooks.server.ts b/src/hooks.server.ts index d4a2554807..4f6ddf7e7c 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -56,7 +56,8 @@ const securityheaders: Handle = async ({ event, resolve }) => { 'https://js.zi-scripts.com', 'https://ws.zoominfo.com', 'https://*.cookieyes.com', - 'https://cdn-cookieyes.com' + 'https://cdn-cookieyes.com', + 'https://ms-6b6b7d6df3ec-29090.fra.meilisearch.io' ]), 'style-src': "'self' 'unsafe-inline'", 'img-src': "'self' data: https:", @@ -81,7 +82,8 @@ const securityheaders: Handle = async ({ event, resolve }) => { 'https://hemsync.clickagy.com', 'https://ws.zoominfo.com ', 'https://*.cookieyes.com', - 'https://cdn-cookieyes.com' + 'https://cdn-cookieyes.com', + 'https://ms-6b6b7d6df3ec-29090.fra.meilisearch.io' ]), 'frame-src': join([ "'self'", diff --git a/src/lib/components/search-v2.svelte b/src/lib/components/search-v2.svelte index edb634a102..e4f35fde49 100644 --- a/src/lib/components/search-v2.svelte +++ b/src/lib/components/search-v2.svelte @@ -8,6 +8,7 @@ import { type Hit, type Hits, MeiliSearch } from 'meilisearch'; import { tick } from 'svelte'; import Icon, { type IconType } from './ui/icon'; + import type { SearchHit, SearchResult } from '$routes/search/(lib)/types'; interface SearchProps { open: boolean; @@ -25,25 +26,7 @@ const index = meilisearchClient.index('website'); - interface SearchResult { - url: string; - title?: string; - uid?: string; - meta?: Record; - page_block?: number; - urls_tags?: Array; - h1?: string; - h2?: string; - h3?: string; - h4?: string; - h5?: string; - h6?: string; - p?: string; - anchor?: string; - _formatted?: SearchResult; - } - - let results = $state>([]); + let results = $state>([]); const resetValue = () => { value = ''; @@ -68,7 +51,7 @@ } } - function createHref(hit: Hit): string { + function createHref(hit: SearchHit): string { const anchor = hit.anchor === '#' ? '' : (hit.anchor ?? ''); const target = hit.url + anchor; @@ -156,7 +139,9 @@ } } - function getSubtitleContent(hit: Hit): { header?: string; subtitle?: string } { + function getSubtitleContent( + hit: Hit<{ h1?: string; h2?: string; h3?: string; h4?: string; h5?: string; h6?: string }> + ): { header?: string; subtitle?: string } { return { header: hit._formatted?.h1, subtitle: @@ -167,6 +152,10 @@ hit._formatted?.h6 }; } + + type GroupKey = 'docs' | 'blog' | 'integrations'; + + type GroupedResults = Record; @@ -183,7 +172,7 @@
      {#if value && value.length >= 3} -
      - {#if results.length > 0} -
      - {results.length} results found -
      - - {:else} -

      - No results found for "{value}" -

      - {/if} -
      + {#if subtitleContent.header} + + {@html subtitleContent.header} + {#if subtitleContent.subtitle} + / + {@html subtitleContent.subtitle} + {/if} + {/if} +
      + {#if hit._formatted} +
      + {@html hit._formatted.p} +
      + {/if} +
      + + + {/each} +
    +
    + {/if} + {/each} +
    +
    +
    + {totalResults} result{totalResults === 1 ? '' : 's'} found +
    +
    + {:else} +

    + No results found for "{value}" +

    + {/if} {:else} -
    +
    Suggestions
      {#each recommended as hit, i (hit.uid)} @@ -311,7 +333,7 @@ {/each}
    -
    +
    {/if}
    diff --git a/src/routes/search/(lib)/blog.ts b/src/routes/search/(lib)/blog.ts new file mode 100644 index 0000000000..6e24a24d2a --- /dev/null +++ b/src/routes/search/(lib)/blog.ts @@ -0,0 +1,34 @@ +import { readdirSync, statSync } from 'fs'; +import path, { join } from 'path'; +import type { SearchResult } from './types'; +import { generateSearchableContent, getMarkdocContent } from './utils'; +import { randomUUID } from 'crypto'; + +export const getSearchablePosts = () => { + const searchablePosts = [] as Array; + const directoryPath = join(process.cwd(), `src/routes/blog/post`); + + readdirSync(directoryPath).forEach((entry) => { + const filePath = join(directoryPath, entry); + const stats = statSync(filePath); + + if (stats.isDirectory()) { + const { title, content } = getMarkdocContent<{ + title: string; + content: string; + }>(path.join(filePath, '+page.markdoc')); + + const posts = generateSearchableContent({ title, slug: filePath, content }); + const url = filePath.split('/').pop(); + + posts.forEach((post, i) => { + searchablePosts.push({ + ...post, + url: `/blog/post/${url}` + }); + }); + } + }); + + return searchablePosts; +}; diff --git a/src/routes/search/(lib)/client.ts b/src/routes/search/(lib)/client.ts new file mode 100644 index 0000000000..1393602a44 --- /dev/null +++ b/src/routes/search/(lib)/client.ts @@ -0,0 +1,10 @@ +import { env } from '$env/dynamic/private'; +import { MeiliSearch } from 'meilisearch'; +import type { SearchResult } from './types'; + +const client = new MeiliSearch({ + host: 'https://ms-6b6b7d6df3ec-29090.fra.meilisearch.io', + apiKey: env.MEILISEARCH_WRITE_KEY +}); + +export const index = client.index('website'); diff --git a/src/routes/search/(lib)/types.ts b/src/routes/search/(lib)/types.ts new file mode 100644 index 0000000000..b962ef5682 --- /dev/null +++ b/src/routes/search/(lib)/types.ts @@ -0,0 +1,21 @@ +import type { Hit } from 'meilisearch'; + +export interface SearchResult { + url: string; + title?: string; + uid?: string; + meta?: Record; + page_block?: number; + urls_tags?: Array; + h1?: string; + h2?: string; + h3?: string; + h4?: string; + h5?: string; + h6?: string; + p?: string; + anchor?: string; + _formatted?: SearchResult; +} + +export type SearchHit = Hit; diff --git a/src/routes/search/(lib)/utils.ts b/src/routes/search/(lib)/utils.ts new file mode 100644 index 0000000000..d551632cca --- /dev/null +++ b/src/routes/search/(lib)/utils.ts @@ -0,0 +1,128 @@ +import { readFileSync } from 'fs'; +import Markdoc, { type RenderableTreeNode } from '@markdoc/markdoc'; +import matter from 'gray-matter'; +import type { SearchResult } from './types'; + +export const flattenArrayAndConcatenate = (arr: string[]): string => { + return arr + .map((element) => (Array.isArray(element) ? flattenArrayAndConcatenate(element) : element)) + .join(''); +}; + +export const removeFileExtension = (string: string) => { + return string.replace(/\.[^/.]+$/, ''); +}; + +export const getMarkdocContent = (filePath: string) => { + let source; + + try { + source = readFileSync(filePath, 'utf-8'); + } catch (error) { + console.error(`File ${filePath} cannot be read or doesn't exist`); + } + + if (!source) + return {} as T & { + content: RenderableTreeNode; + slug: string; + }; + + const matterResult = matter(source); + const attributes = matterResult.data as T; + const ast = Markdoc.parse(source); + const content = Markdoc.transform(ast); + + return { + ...attributes, + content + }; +}; + +export const extractMarkdocContent = (children: RenderableTreeNode[]): string[] => { + return children.flatMap((child) => { + if (child instanceof Markdoc.Tag) { + return extractMarkdocContent(child.children); + } else { + return [child]; + } + }) as string[]; +}; + +export const isHeading = (name: string) => name === 'Heading'; + +export const generateSearchableContent = ({ + title, + slug, + content +}: { + title: string; + slug: string; + content?: RenderableTreeNode; +}) => { + const groups = [] as SearchResult[]; + + const paragraphRegex = /^p$/; + const isParagraph = (name: string) => name.match(paragraphRegex); + + let position = 0; + + if (Array.isArray(content)) { + content.forEach((child) => { + if (Markdoc.Tag.isTag(child)) { + if ( + isHeading(child.name) && + child.children[0] && + Markdoc.Tag.isTag(child.children[0]) + ) { + const section: string[] = extractMarkdocContent(child.children[0].children); + const content = flattenArrayAndConcatenate(section); + + position++; + + groups.push({ + title, + url: slug + //content, + //position + }); + } else if (isParagraph(child.name) && child.children) { + const paragraph = extractMarkdocContent(child.children); + const content = flattenArrayAndConcatenate(paragraph); + + position++; + + groups.push({ + title, + url: slug + //content, + //position + }); + } + } + }); + } else if (typeof content === 'string') { + position++; + + groups.push({ + title, + url: slug + //content, + //position + }); + } else if (Markdoc.Tag.isTag(content)) { + const extractedContent = extractMarkdocContent([content]); + const flattenedContent = flattenArrayAndConcatenate(extractedContent); + + position++; + + groups.push({ + title, + url: slug + //content: flattenedContent, + //position + }); + } + + return groups; +}; diff --git a/src/routes/search/show/+server.ts b/src/routes/search/show/+server.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/routes/search/sync/+server.ts b/src/routes/search/sync/+server.ts index db27730447..b017593928 100644 --- a/src/routes/search/sync/+server.ts +++ b/src/routes/search/sync/+server.ts @@ -1,7 +1,15 @@ import { json } from '@sveltejs/kit'; +import { getSearchablePosts } from '../(lib)/blog'; +import { index } from '../(lib)/client'; -export function GET() { - const number = Math.floor(Math.random() * 6) + 1; +export const GET = async () => { + try { + const posts = getSearchablePosts(); - return json(number); -} + const res = await index.addDocuments(posts); + + return json(res); + } catch (error) { + return json({ updated: false, error }); + } +}; From aebc8480ac457e5a02deee800a7b91ebce3f3c9e Mon Sep 17 00:00:00 2001 From: Jesse Winton Date: Tue, 26 Aug 2025 15:24:04 -0400 Subject: [PATCH 20/26] Update search-v2.svelte --- src/lib/components/search-v2.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/search-v2.svelte b/src/lib/components/search-v2.svelte index e4f35fde49..019ecdf96b 100644 --- a/src/lib/components/search-v2.svelte +++ b/src/lib/components/search-v2.svelte @@ -226,7 +226,7 @@ integrations: { label: 'Integrations', icon: 'integrations' } } as const} -
    +
    {#each groupOrder as groupKey} {@const groupResults = groupedResults[groupKey]} {#if groupResults && groupResults.length > 0} From 86b37a5c30392c918edf355d1eb6f00c3d22d1d5 Mon Sep 17 00:00:00 2001 From: Jesse Winton Date: Tue, 26 Aug 2025 15:30:50 -0400 Subject: [PATCH 21/26] update colors --- src/app.css | 3 ++- src/lib/components/search-v2.svelte | 32 +++++++++++++++-------------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/app.css b/src/app.css index 9e56d32f02..24390732c4 100644 --- a/src/app.css +++ b/src/app.css @@ -475,7 +475,7 @@ --color-card: color-mix(in srgb, var(--color-white) 90%, transparent); --color-tertiary: var(--color-greyscale-600); --color-offset: hsl(0 0% 0% / 0.08); - --color-subtle: var(--color-greyscale-850); + --color-subtle: var(--color-greyscale-50); } .dark { @@ -487,4 +487,5 @@ --color-tertiary: var(--color-greyscale-600); --color-offset: hsl(0 0% 100% / 0.1); --color-card: var(--color-greyscale-850); + --color-subtle: var(--color-greyscale-850); } diff --git a/src/lib/components/search-v2.svelte b/src/lib/components/search-v2.svelte index 019ecdf96b..fa46c97893 100644 --- a/src/lib/components/search-v2.svelte +++ b/src/lib/components/search-v2.svelte @@ -156,6 +156,23 @@ type GroupKey = 'docs' | 'blog' | 'integrations'; type GroupedResults = Record; + + const groupedResults = $derived( + results.reduce((groups, hit) => { + const tags = hit.urls_tags || []; + const primaryTag: GroupKey = tags.includes('docs') + ? 'docs' + : tags.includes('blog') + ? 'blog' + : 'integrations'; + + if (!groups[primaryTag]) { + groups[primaryTag] = []; + } + groups[primaryTag].push(hit); + return groups; + }, {} as GroupedResults) + ); @@ -203,21 +220,6 @@ {#if value && value.length >= 3} {#if results.length > 0} {@const totalResults = results.length} - {@const groupedResults = results.reduce((groups, hit) => { - const tags = hit.urls_tags || []; - const primaryTag: GroupKey = tags.includes('docs') - ? 'docs' - : tags.includes('blog') - ? 'blog' - : 'integrations'; - - if (!groups[primaryTag]) { - groups[primaryTag] = []; - } - groups[primaryTag].push(hit); - return groups; - }, {} as GroupedResults)} - {@const groupOrder: readonly GroupKey[] = ['docs', 'blog', 'integrations'] as const} {@const groupConfig = { From c53d685b7f94254952d884b36de12bb378869a23 Mon Sep 17 00:00:00 2001 From: Jesse Winton Date: Wed, 27 Aug 2025 08:11:35 -0400 Subject: [PATCH 22/26] update colors --- src/lib/components/search-v2.svelte | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/components/search-v2.svelte b/src/lib/components/search-v2.svelte index fa46c97893..55bb6116cc 100644 --- a/src/lib/components/search-v2.svelte +++ b/src/lib/components/search-v2.svelte @@ -36,7 +36,7 @@ const response = await index.search(value, { attributesToCrop: ['p'], cropLength: 40, - limit: 20, + attributesToHighlight: ['title', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p'], highlightPreTag: '', highlightPostTag: '' @@ -189,7 +189,7 @@
    {#if value && value.length >= 3} From 609cb6b77189274aa8b4fe0c1804c69b09dd3a86 Mon Sep 17 00:00:00 2001 From: Jesse Winton Date: Wed, 27 Aug 2025 08:43:08 -0400 Subject: [PATCH 23/26] update --- src/lib/components/search-v2.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/search-v2.svelte b/src/lib/components/search-v2.svelte index 55bb6116cc..7f71531420 100644 --- a/src/lib/components/search-v2.svelte +++ b/src/lib/components/search-v2.svelte @@ -307,7 +307,7 @@
    {:else}

    - No results found for "{value}" + No results found for "{value}"

    {/if} {:else} From 87e7fb7c625fd2770588de3020f89661d30cd257 Mon Sep 17 00:00:00 2001 From: Jesse Winton Date: Wed, 27 Aug 2025 10:20:12 -0400 Subject: [PATCH 24/26] rm --- meilisearch.config.json | 14 -------------- src/routes/search/show/+server.ts | 0 2 files changed, 14 deletions(-) delete mode 100644 meilisearch.config.json delete mode 100644 src/routes/search/show/+server.ts diff --git a/meilisearch.config.json b/meilisearch.config.json deleted file mode 100644 index b3d469e884..0000000000 --- a/meilisearch.config.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "start_urls": ["https://appwrite.io/docs"], - "meilisearch_url": "https://search.appwrite.org", - "meilisearch_index_uid": "website", - "strategy": "default", - "headless": true, - "batch_size": 1000, - "primary_key": null, - "meilisearch_settings": { - "searchableAttributes": ["h1", "h2", "h3", "h4", "h5", "h6", "p", "title"], - "filterableAttributes": ["urls_tags"], - "distinctAttribute": "url" - } -} diff --git a/src/routes/search/show/+server.ts b/src/routes/search/show/+server.ts deleted file mode 100644 index e69de29bb2..0000000000 From 08c21cdf7947834510c3b2fe681f65e125fc829b Mon Sep 17 00:00:00 2001 From: Jesse Winton Date: Wed, 27 Aug 2025 10:22:43 -0400 Subject: [PATCH 25/26] Update types.ts --- src/lib/components/ui/icon/types.ts | 77 ++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/src/lib/components/ui/icon/types.ts b/src/lib/components/ui/icon/types.ts index ee0053c0a7..b15caa2a9a 100644 --- a/src/lib/components/ui/icon/types.ts +++ b/src/lib/components/ui/icon/types.ts @@ -1 +1,76 @@ -export type IconType = "apple" | "appwrite" | "arrow-down" | "arrow-ext-link" | "arrow-left" | "arrow-right" | "arrow-up" | "arrows-up-down" | "blog" | "bluesky" | "book" | "calendar" | "check" | "chevron-down" | "chevron-left" | "chevron-right" | "chevron-up" | "close" | "command" | "copy" | "customize" | "daily-dev" | "dark" | "database" | "discord" | "divider-vertical" | "docs" | "download" | "edge" | "ext-link" | "firebase" | "github" | "google" | "hamburger-menu" | "hash" | "instagram" | "integrations" | "light" | "lightning" | "linkedin" | "location" | "logout-left" | "logout-right" | "mailgun" | "mcp" | "message" | "microsoft" | "minus" | "nuxt" | "platform" | "play" | "plus" | "pop-locations" | "product-hunt" | "quickstarts" | "refine" | "regions" | "remix" | "rest" | "search" | "sendgrid" | "sparkle" | "star" | "system" | "text" | "textmagic" | "ticket" | "tiktok" | "twitter" | "user" | "users" | "vue" | "x" | "ycombinator" | "youtube"; \ No newline at end of file +export type IconType = + | 'apple' + | 'appwrite' + | 'arrow-down' + | 'arrow-ext-link' + | 'arrow-left' + | 'arrow-right' + | 'arrow-up' + | 'arrows-up-down' + | 'blog' + | 'bluesky' + | 'book' + | 'calendar' + | 'check' + | 'chevron-down' + | 'chevron-left' + | 'chevron-right' + | 'chevron-up' + | 'close' + | 'command' + | 'copy' + | 'customize' + | 'daily-dev' + | 'dark' + | 'database' + | 'discord' + | 'divider-vertical' + | 'docs' + | 'download' + | 'edge' + | 'ext-link' + | 'firebase' + | 'github' + | 'google' + | 'hamburger-menu' + | 'hash' + | 'instagram' + | 'integrations' + | 'light' + | 'lightning' + | 'linkedin' + | 'location' + | 'logout-left' + | 'logout-right' + | 'mailgun' + | 'mcp' + | 'message' + | 'microsoft' + | 'minus' + | 'nuxt' + | 'platform' + | 'play' + | 'plus' + | 'pop-locations' + | 'product-hunt' + | 'quickstarts' + | 'refine' + | 'regions' + | 'remix' + | 'rest' + | 'search' + | 'sendgrid' + | 'sparkle' + | 'star' + | 'system' + | 'text' + | 'textmagic' + | 'ticket' + | 'tiktok' + | 'twitter' + | 'user' + | 'users' + | 'vue' + | 'x' + | 'ycombinator' + | 'youtube'; From 592c7a3d7baf2664c75300e2c11f5848ddd49c25 Mon Sep 17 00:00:00 2001 From: Jesse Winton Date: Wed, 27 Aug 2025 10:23:48 -0400 Subject: [PATCH 26/26] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 69f863015e..3ca0f40283 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "download-contributors": "node ./scripts/download-contributor-data.js", "format": "prettier --write .", "format:check": "prettier --check .", - "generate:icons": "node ./src/icons/optimize.js && pnpm prettier --write ./src/lib/components/ui/icon/sprite/sprite.svelte", + "generate:icons": "node ./src/icons/optimize.js && pnpm prettier --write ./src/lib/components/ui/icon/**", "icons:build": "node ./src/icons/build.js", "icons:generate": "node ./src/icons/optimize.js && node ./src/icons/build.js", "icons:optimize": "node ./src/icons/optimize.js",