@alliance-droid/svelte-docs-system 0.0.2 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +155 -23
- package/dist/components/APITable.svelte.d.ts +21 -0
- package/dist/components/Breadcrumbs.svelte.d.ts +14 -0
- package/dist/components/Callout.svelte.d.ts +15 -0
- package/dist/components/CodeBlock.svelte.d.ts +12 -0
- package/{src/lib → dist}/components/DocLayout.svelte +18 -6
- package/dist/components/DocLayout.svelte.d.ts +18 -0
- package/dist/components/DocsPage.svelte +39 -0
- package/dist/components/DocsPage.svelte.d.ts +8 -0
- package/dist/components/Documentation.svelte +639 -0
- package/dist/components/Footer.svelte.d.ts +10 -0
- package/dist/components/Image.svelte.d.ts +15 -0
- package/{src/lib → dist}/components/Navbar.svelte +4 -4
- package/dist/components/Navbar.svelte.d.ts +10 -0
- package/{src/lib → dist}/components/Search.svelte +2 -2
- package/dist/components/Search.svelte.d.ts +6 -0
- package/{template-starter/src/lib → dist}/components/Sidebar.svelte +2 -2
- package/dist/components/Sidebar.svelte.d.ts +9 -0
- package/dist/components/Tabs.svelte.d.ts +16 -0
- package/dist/config.d.ts +93 -0
- package/dist/config.js +89 -0
- package/dist/configLoader.d.ts +48 -0
- package/dist/configLoader.js +187 -0
- package/dist/configParser.d.ts +27 -0
- package/dist/configParser.js +208 -0
- package/{template-starter/src/lib/index.ts → dist/index.d.ts} +6 -7
- package/dist/index.js +18 -0
- package/dist/navigationBuilder.d.ts +64 -0
- package/dist/navigationBuilder.js +225 -0
- package/dist/plugin.d.ts +30 -0
- package/dist/plugin.js +172 -0
- package/dist/routing.d.ts +48 -0
- package/dist/routing.js +92 -0
- package/dist/stores/i18n.d.ts +20 -0
- package/dist/stores/i18n.js +119 -0
- package/dist/stores/nav.d.ts +20 -0
- package/dist/stores/nav.js +15 -0
- package/dist/stores/search.d.ts +49 -0
- package/dist/stores/search.js +127 -0
- package/dist/stores/theme.d.ts +7 -0
- package/dist/stores/theme.js +152 -0
- package/dist/stores/version.d.ts +18 -0
- package/dist/stores/version.js +93 -0
- package/dist/themeCustomization.d.ts +46 -0
- package/dist/themeCustomization.js +188 -0
- package/dist/utils/highlight.d.ts +13 -0
- package/dist/utils/highlight.js +83 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/markdown.d.ts +40 -0
- package/dist/utils/markdown.js +165 -0
- package/package.json +44 -23
- package/COMPONENTS.md +0 -365
- package/COVERAGE_REPORT.md +0 -663
- package/SEARCH_VERIFICATION.md +0 -229
- package/TEST_SUMMARY.md +0 -344
- package/bin/init.js +0 -821
- package/docs/COMPONENT_LIBRARY_INTEGRATION_REPORT.md +0 -153
- package/docs/DARK_MODE_AUDIT_REPORT.md +0 -403
- package/docs/E2E_TESTS.md +0 -354
- package/docs/TESTING.md +0 -754
- package/docs/THEME_INHERITANCE.md +0 -192
- package/docs/de/index.md +0 -41
- package/docs/en/COMPONENTS.md +0 -443
- package/docs/en/api/examples.md +0 -100
- package/docs/en/api/overview.md +0 -69
- package/docs/en/components/index.md +0 -622
- package/docs/en/config/navigation.md +0 -505
- package/docs/en/config/theme-and-colors.md +0 -395
- package/docs/en/getting-started/integration.md +0 -406
- package/docs/en/guides/common-setups.md +0 -651
- package/docs/en/index.md +0 -243
- package/docs/en/markdown.md +0 -102
- package/docs/en/routing.md +0 -64
- package/docs/en/setup.md +0 -52
- package/docs/en/troubleshooting.md +0 -704
- package/docs/es/index.md +0 -41
- package/docs/fr/index.md +0 -41
- package/docs/ja/index.md +0 -41
- package/pagefind.toml +0 -8
- package/postcss.config.js +0 -5
- package/src/app.css +0 -119
- package/src/app.d.ts +0 -13
- package/src/app.html +0 -11
- package/src/lib/components/APITable.test.ts +0 -153
- package/src/lib/components/Breadcrumbs.test.ts +0 -148
- package/src/lib/components/Callout.test.ts +0 -100
- package/src/lib/components/CodeBlock.test.ts +0 -133
- package/src/lib/components/Image.test.ts +0 -163
- package/src/lib/components/Sidebar.svelte +0 -110
- package/src/lib/components/Tabs.test.ts +0 -102
- package/src/lib/config.test.ts +0 -140
- package/src/lib/config.ts +0 -179
- package/src/lib/configIntegration.test.ts +0 -272
- package/src/lib/configLoader.ts +0 -231
- package/src/lib/configParser.test.ts +0 -217
- package/src/lib/configParser.ts +0 -234
- package/src/lib/index.ts +0 -37
- package/src/lib/integration.test.ts +0 -426
- package/src/lib/navigationBuilder.test.ts +0 -338
- package/src/lib/navigationBuilder.ts +0 -268
- package/src/lib/performance.test.ts +0 -369
- package/src/lib/routing.test.ts +0 -202
- package/src/lib/routing.ts +0 -127
- package/src/lib/search-functionality.test.ts +0 -493
- package/src/lib/stores/i18n.test.ts +0 -180
- package/src/lib/stores/i18n.ts +0 -143
- package/src/lib/stores/nav.ts +0 -36
- package/src/lib/stores/search.test.ts +0 -140
- package/src/lib/stores/search.ts +0 -162
- package/src/lib/stores/theme.test.ts +0 -117
- package/src/lib/stores/theme.ts +0 -167
- package/src/lib/stores/version.test.ts +0 -139
- package/src/lib/stores/version.ts +0 -111
- package/src/lib/themeCustomization.test.ts +0 -223
- package/src/lib/themeCustomization.ts +0 -212
- package/src/lib/utils/highlight.test.ts +0 -136
- package/src/lib/utils/highlight.ts +0 -100
- package/src/lib/utils/index.ts +0 -7
- package/src/lib/utils/markdown.test.ts +0 -357
- package/src/lib/utils/markdown.ts +0 -77
- package/src/routes/+layout.server.ts +0 -1
- package/src/routes/+layout.svelte +0 -29
- package/src/routes/+page.svelte +0 -165
- package/src/routes/quote-demo/+page.svelte +0 -141
- package/static/robots.txt +0 -3
- package/svelte.config.js +0 -15
- package/tailwind.config.ts +0 -55
- package/template-starter/.github/workflows/build.yml +0 -40
- package/template-starter/.github/workflows/deploy-github-pages.yml +0 -47
- package/template-starter/.github/workflows/deploy-netlify.yml +0 -41
- package/template-starter/.github/workflows/deploy-vercel.yml +0 -64
- package/template-starter/NPM-PACKAGE-SETUP.md +0 -233
- package/template-starter/README.md +0 -320
- package/template-starter/docs/_config.json +0 -39
- package/template-starter/docs/api/components.md +0 -257
- package/template-starter/docs/api/overview.md +0 -169
- package/template-starter/docs/guides/configuration.md +0 -145
- package/template-starter/docs/guides/github-pages-deployment.md +0 -254
- package/template-starter/docs/guides/netlify-deployment.md +0 -159
- package/template-starter/docs/guides/vercel-deployment.md +0 -131
- package/template-starter/docs/index.md +0 -49
- package/template-starter/docs/setup.md +0 -149
- package/template-starter/package.json +0 -31
- package/template-starter/pagefind.toml +0 -3
- package/template-starter/postcss.config.js +0 -5
- package/template-starter/src/app.css +0 -34
- package/template-starter/src/app.d.ts +0 -13
- package/template-starter/src/app.html +0 -11
- package/template-starter/src/lib/components/APITable.svelte +0 -120
- package/template-starter/src/lib/components/APITable.test.ts +0 -96
- package/template-starter/src/lib/components/Breadcrumbs.svelte +0 -85
- package/template-starter/src/lib/components/Breadcrumbs.test.ts +0 -82
- package/template-starter/src/lib/components/Callout.svelte +0 -60
- package/template-starter/src/lib/components/Callout.test.ts +0 -91
- package/template-starter/src/lib/components/CodeBlock.svelte +0 -68
- package/template-starter/src/lib/components/CodeBlock.test.ts +0 -62
- package/template-starter/src/lib/components/DocLayout.svelte +0 -84
- package/template-starter/src/lib/components/Footer.svelte +0 -78
- package/template-starter/src/lib/components/Image.svelte +0 -100
- package/template-starter/src/lib/components/Image.test.ts +0 -81
- package/template-starter/src/lib/components/Navbar.svelte +0 -141
- package/template-starter/src/lib/components/Search.svelte +0 -248
- package/template-starter/src/lib/components/Tabs.svelte +0 -48
- package/template-starter/src/lib/components/Tabs.test.ts +0 -89
- package/template-starter/src/routes/+layout.svelte +0 -28
- package/template-starter/src/routes/+page.svelte +0 -92
- package/template-starter/svelte.config.js +0 -17
- package/template-starter/tailwind.config.ts +0 -17
- package/template-starter/tsconfig.json +0 -13
- package/template-starter/vite.config.ts +0 -6
- package/tests/e2e/example.spec.ts +0 -345
- package/tsconfig.json +0 -20
- package/vite.config.ts +0 -6
- package/vitest.config.ts +0 -33
- package/vitest.setup.ts +0 -21
- /package/{src/lib → dist}/assets/favicon.svg +0 -0
- /package/{src/lib → dist}/components/APITable.svelte +0 -0
- /package/{src/lib → dist}/components/Breadcrumbs.svelte +0 -0
- /package/{src/lib → dist}/components/Callout.svelte +0 -0
- /package/{src/lib → dist}/components/CodeBlock.svelte +0 -0
- /package/{src/lib → dist}/components/Footer.svelte +0 -0
- /package/{src/lib → dist}/components/Image.svelte +0 -0
- /package/{src/lib → dist}/components/Tabs.svelte +0 -0
- /package/{src/lib → dist}/svelte-component-library.d.ts +0 -0
package/src/lib/stores/i18n.ts
DELETED
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import { writable } from 'svelte/store';
|
|
2
|
-
|
|
3
|
-
export type Language = 'en' | 'fr' | 'es' | 'de' | 'ja';
|
|
4
|
-
|
|
5
|
-
export interface LanguageMetadata {
|
|
6
|
-
code: Language;
|
|
7
|
-
label: string;
|
|
8
|
-
nativeLabel: string;
|
|
9
|
-
direction: 'ltr' | 'rtl';
|
|
10
|
-
isDefault?: boolean;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface I18nConfig {
|
|
14
|
-
currentLanguage: Language;
|
|
15
|
-
availableLanguages: LanguageMetadata[];
|
|
16
|
-
defaultLanguage: Language;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function createI18nStore() {
|
|
20
|
-
// Default language configuration
|
|
21
|
-
const defaultConfig: I18nConfig = {
|
|
22
|
-
currentLanguage: 'en',
|
|
23
|
-
defaultLanguage: 'en',
|
|
24
|
-
availableLanguages: [
|
|
25
|
-
{
|
|
26
|
-
code: 'en',
|
|
27
|
-
label: 'English',
|
|
28
|
-
nativeLabel: 'English',
|
|
29
|
-
direction: 'ltr',
|
|
30
|
-
isDefault: true,
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
code: 'fr',
|
|
34
|
-
label: 'Français',
|
|
35
|
-
nativeLabel: 'Français',
|
|
36
|
-
direction: 'ltr',
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
code: 'es',
|
|
40
|
-
label: 'Español',
|
|
41
|
-
nativeLabel: 'Español',
|
|
42
|
-
direction: 'ltr',
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
code: 'de',
|
|
46
|
-
label: 'Deutsch',
|
|
47
|
-
nativeLabel: 'Deutsch',
|
|
48
|
-
direction: 'ltr',
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
code: 'ja',
|
|
52
|
-
label: '日本語',
|
|
53
|
-
nativeLabel: '日本語',
|
|
54
|
-
direction: 'ltr',
|
|
55
|
-
},
|
|
56
|
-
],
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const getInitialLanguage = (): Language => {
|
|
60
|
-
if (typeof window === 'undefined') {
|
|
61
|
-
return defaultConfig.defaultLanguage;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
try {
|
|
65
|
-
// Check localStorage for stored language preference
|
|
66
|
-
const stored = localStorage?.getItem?.('docs-language') as Language | null;
|
|
67
|
-
if (stored && defaultConfig.availableLanguages.some((l) => l.code === stored)) {
|
|
68
|
-
return stored;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Check browser language preference
|
|
72
|
-
const browserLang = navigator?.language?.split('-')[0].toLowerCase();
|
|
73
|
-
const matchedLang = defaultConfig.availableLanguages.find(
|
|
74
|
-
(l) => l.code === (browserLang as Language)
|
|
75
|
-
);
|
|
76
|
-
if (matchedLang) {
|
|
77
|
-
return matchedLang.code;
|
|
78
|
-
}
|
|
79
|
-
} catch (e) {
|
|
80
|
-
// localStorage or navigator may not be available in some environments
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return defaultConfig.defaultLanguage;
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
const { subscribe, set, update } = writable<I18nConfig>({
|
|
87
|
-
...defaultConfig,
|
|
88
|
-
currentLanguage: getInitialLanguage(),
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
return {
|
|
92
|
-
subscribe,
|
|
93
|
-
setLanguage: (language: Language) => {
|
|
94
|
-
update((config) => {
|
|
95
|
-
if (config.availableLanguages.some((l) => l.code === language)) {
|
|
96
|
-
if (typeof window !== 'undefined') {
|
|
97
|
-
try {
|
|
98
|
-
localStorage?.setItem?.('docs-language', language);
|
|
99
|
-
} catch (e) {
|
|
100
|
-
// localStorage may not be available
|
|
101
|
-
}
|
|
102
|
-
// Update document lang attribute
|
|
103
|
-
if (document?.documentElement) {
|
|
104
|
-
document.documentElement.lang = language;
|
|
105
|
-
// Update document dir attribute
|
|
106
|
-
const metadata = config.availableLanguages.find((l) => l.code === language);
|
|
107
|
-
if (metadata) {
|
|
108
|
-
document.documentElement.dir = metadata.direction;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return { ...config, currentLanguage: language };
|
|
113
|
-
}
|
|
114
|
-
return config;
|
|
115
|
-
});
|
|
116
|
-
},
|
|
117
|
-
addLanguage: (metadata: LanguageMetadata) => {
|
|
118
|
-
update((config) => ({
|
|
119
|
-
...config,
|
|
120
|
-
availableLanguages: [
|
|
121
|
-
...config.availableLanguages.filter((l) => l.code !== metadata.code),
|
|
122
|
-
metadata,
|
|
123
|
-
],
|
|
124
|
-
}));
|
|
125
|
-
},
|
|
126
|
-
removeLanguage: (language: Language) => {
|
|
127
|
-
update((config) => ({
|
|
128
|
-
...config,
|
|
129
|
-
availableLanguages: config.availableLanguages.filter((l) => l.code !== language),
|
|
130
|
-
}));
|
|
131
|
-
},
|
|
132
|
-
getLanguageMetadata: (language: Language): LanguageMetadata | undefined => {
|
|
133
|
-
let metadata: LanguageMetadata | undefined;
|
|
134
|
-
const unsubscribe = subscribe((config) => {
|
|
135
|
-
metadata = config.availableLanguages.find((l) => l.code === language);
|
|
136
|
-
});
|
|
137
|
-
unsubscribe();
|
|
138
|
-
return metadata;
|
|
139
|
-
},
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
export const i18n = createI18nStore();
|
package/src/lib/stores/nav.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { writable } from 'svelte/store';
|
|
2
|
-
|
|
3
|
-
export interface NavItem {
|
|
4
|
-
label: string;
|
|
5
|
-
href?: string;
|
|
6
|
-
children?: NavItem[];
|
|
7
|
-
icon?: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface NavConfig {
|
|
11
|
-
title: string;
|
|
12
|
-
sections: NavSection[];
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface NavSection {
|
|
16
|
-
title: string;
|
|
17
|
-
items: NavItem[];
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function createNavStore() {
|
|
21
|
-
const { subscribe, set, update } = writable<NavConfig>({
|
|
22
|
-
title: 'Documentation',
|
|
23
|
-
sections: [],
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
return {
|
|
27
|
-
subscribe,
|
|
28
|
-
setNav: (config: NavConfig) => set(config),
|
|
29
|
-
updateNav: (fn: (nav: NavConfig) => NavConfig) => update(fn),
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export const nav = createNavStore();
|
|
34
|
-
|
|
35
|
-
// Store for mobile sidebar visibility
|
|
36
|
-
export const sidebarOpen = writable(false);
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
query,
|
|
4
|
-
results,
|
|
5
|
-
loading,
|
|
6
|
-
resultCount,
|
|
7
|
-
initPagefind,
|
|
8
|
-
updateSearch,
|
|
9
|
-
clearSearch,
|
|
10
|
-
performSearch,
|
|
11
|
-
subscribeToSearch
|
|
12
|
-
} from './search';
|
|
13
|
-
|
|
14
|
-
describe('Search Store', () => {
|
|
15
|
-
beforeEach(() => {
|
|
16
|
-
clearSearch();
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
describe('query store', () => {
|
|
20
|
-
it('should initialize with empty string', () => {
|
|
21
|
-
let currentQuery = '';
|
|
22
|
-
query.subscribe((q) => {
|
|
23
|
-
currentQuery = q;
|
|
24
|
-
});
|
|
25
|
-
expect(currentQuery).toBe('');
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
describe('results store', () => {
|
|
30
|
-
it('should initialize with empty array', () => {
|
|
31
|
-
let currentResults: any[] = [];
|
|
32
|
-
results.subscribe((r) => {
|
|
33
|
-
currentResults = r;
|
|
34
|
-
});
|
|
35
|
-
expect(currentResults).toEqual([]);
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
describe('loading store', () => {
|
|
40
|
-
it('should initialize as false', () => {
|
|
41
|
-
let isLoading = false;
|
|
42
|
-
loading.subscribe((l) => {
|
|
43
|
-
isLoading = l;
|
|
44
|
-
});
|
|
45
|
-
expect(isLoading).toBe(false);
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
describe('resultCount store', () => {
|
|
50
|
-
it('should initialize with 0', () => {
|
|
51
|
-
let count = 0;
|
|
52
|
-
resultCount.subscribe((c) => {
|
|
53
|
-
count = c;
|
|
54
|
-
});
|
|
55
|
-
expect(count).toBe(0);
|
|
56
|
-
});
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
describe('clearSearch', () => {
|
|
60
|
-
it('should clear query and results', async () => {
|
|
61
|
-
query.set('test query');
|
|
62
|
-
let queries: string[] = [];
|
|
63
|
-
let resultsList: any[] = [];
|
|
64
|
-
|
|
65
|
-
const unsubscribeQuery = query.subscribe((q) => {
|
|
66
|
-
queries.push(q);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
const unsubscribeResults = results.subscribe((r) => {
|
|
70
|
-
resultsList.push(r);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
clearSearch();
|
|
74
|
-
|
|
75
|
-
// Allow time for updates
|
|
76
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
77
|
-
|
|
78
|
-
expect(queries[queries.length - 1]).toBe('');
|
|
79
|
-
expect(resultsList[resultsList.length - 1]).toEqual([]);
|
|
80
|
-
unsubscribeQuery();
|
|
81
|
-
unsubscribeResults();
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
describe('updateSearch', () => {
|
|
86
|
-
it('should update query store', async () => {
|
|
87
|
-
let currentQuery = '';
|
|
88
|
-
const unsubscribe = query.subscribe((q) => {
|
|
89
|
-
currentQuery = q;
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
// Note: This will fail without Pagefind initialized,
|
|
93
|
-
// but we're testing the store behavior
|
|
94
|
-
try {
|
|
95
|
-
await updateSearch('test');
|
|
96
|
-
} catch {
|
|
97
|
-
// Expected to fail without Pagefind
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
expect(currentQuery).toBe('test');
|
|
101
|
-
unsubscribe();
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
describe('subscribeToSearch', () => {
|
|
106
|
-
it('should unsubscribe properly', () => {
|
|
107
|
-
const mockCallback = vi.fn();
|
|
108
|
-
const unsubscribe = subscribeToSearch(mockCallback, 100);
|
|
109
|
-
|
|
110
|
-
query.set('test');
|
|
111
|
-
|
|
112
|
-
// Unsubscribe immediately
|
|
113
|
-
unsubscribe();
|
|
114
|
-
|
|
115
|
-
// Query should still update but callback should not be called
|
|
116
|
-
// (because we unsubscribed)
|
|
117
|
-
expect(mockCallback).not.toHaveBeenCalled();
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
describe('Search results type', () => {
|
|
122
|
-
it('should have correct result properties', () => {
|
|
123
|
-
const mockResult = {
|
|
124
|
-
id: 'test-1',
|
|
125
|
-
url: '/test',
|
|
126
|
-
title: 'Test Title',
|
|
127
|
-
content: 'Test content',
|
|
128
|
-
excerpt: 'Test excerpt',
|
|
129
|
-
meta: { category: 'test' }
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
expect(mockResult.id).toBe('test-1');
|
|
133
|
-
expect(mockResult.url).toBe('/test');
|
|
134
|
-
expect(mockResult.title).toBe('Test Title');
|
|
135
|
-
expect(mockResult.content).toBe('Test content');
|
|
136
|
-
expect(mockResult.excerpt).toBe('Test excerpt');
|
|
137
|
-
expect(mockResult.meta).toEqual({ category: 'test' });
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
});
|
package/src/lib/stores/search.ts
DELETED
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import { writable, derived, type Writable, type Readable } from 'svelte/store';
|
|
2
|
-
|
|
3
|
-
export interface SearchResult {
|
|
4
|
-
id: string;
|
|
5
|
-
url: string;
|
|
6
|
-
title: string;
|
|
7
|
-
content: string;
|
|
8
|
-
excerpt?: string;
|
|
9
|
-
meta?: Record<string, unknown>;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
interface SearchFilters {
|
|
13
|
-
limit?: number;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// Main search query store
|
|
17
|
-
const searchQuery: Writable<string> = writable('');
|
|
18
|
-
|
|
19
|
-
// Search results store
|
|
20
|
-
const searchResults: Writable<SearchResult[]> = writable([]);
|
|
21
|
-
|
|
22
|
-
// Loading state store
|
|
23
|
-
const isSearching: Writable<boolean> = writable(false);
|
|
24
|
-
|
|
25
|
-
// Pagefind index reference
|
|
26
|
-
let pagefindIndex: any = null;
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Initialize Pagefind when the client loads
|
|
30
|
-
*/
|
|
31
|
-
export async function initPagefind(): Promise<void> {
|
|
32
|
-
if (typeof window === 'undefined') {
|
|
33
|
-
console.warn('Pagefind can only be initialized on the client side');
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
try {
|
|
38
|
-
// Check if pagefind is already available globally (from build output)
|
|
39
|
-
if ((window as any).pagefind) {
|
|
40
|
-
pagefindIndex = (window as any).pagefind;
|
|
41
|
-
console.log('Pagefind initialized successfully (from global)');
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Dynamically import Pagefind from the build output
|
|
46
|
-
// Use string concatenation to prevent Vite from resolving this at build time
|
|
47
|
-
const pagefindPath = '/' + 'pagefind' + '/' + 'pagefind.js';
|
|
48
|
-
const pagefind = await import(/* @vite-ignore */ pagefindPath);
|
|
49
|
-
pagefindIndex = pagefind;
|
|
50
|
-
console.log('Pagefind initialized successfully (from dynamic import)');
|
|
51
|
-
} catch (error) {
|
|
52
|
-
console.error('Failed to initialize Pagefind:', error);
|
|
53
|
-
console.warn(
|
|
54
|
-
'Search functionality will not work. Make sure to run `npm run build` to generate search index.'
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Perform a search query
|
|
61
|
-
*/
|
|
62
|
-
export async function performSearch(query: string, filters?: SearchFilters): Promise<SearchResult[]> {
|
|
63
|
-
if (!query.trim()) {
|
|
64
|
-
searchResults.set([]);
|
|
65
|
-
return [];
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (!pagefindIndex) {
|
|
69
|
-
console.warn('Pagefind not yet initialized');
|
|
70
|
-
return [];
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
isSearching.set(true);
|
|
74
|
-
|
|
75
|
-
try {
|
|
76
|
-
const results = await pagefindIndex.search(query);
|
|
77
|
-
const limit = filters?.limit || 20;
|
|
78
|
-
|
|
79
|
-
// Convert Pagefind results to our SearchResult format
|
|
80
|
-
const formattedResults: SearchResult[] = results.results
|
|
81
|
-
.slice(0, limit)
|
|
82
|
-
.map((result: any) => ({
|
|
83
|
-
id: result.id,
|
|
84
|
-
url: result.url,
|
|
85
|
-
title: result.meta?.title || 'Untitled',
|
|
86
|
-
content: result.meta?.content || '',
|
|
87
|
-
excerpt: result.excerpt || '',
|
|
88
|
-
meta: result.meta || {}
|
|
89
|
-
}));
|
|
90
|
-
|
|
91
|
-
searchResults.set(formattedResults);
|
|
92
|
-
return formattedResults;
|
|
93
|
-
} catch (error) {
|
|
94
|
-
console.error('Search error:', error);
|
|
95
|
-
searchResults.set([]);
|
|
96
|
-
return [];
|
|
97
|
-
} finally {
|
|
98
|
-
isSearching.set(false);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Get reactive search results
|
|
104
|
-
*/
|
|
105
|
-
export const results: Readable<SearchResult[]> = derived(
|
|
106
|
-
searchResults,
|
|
107
|
-
($results) => $results
|
|
108
|
-
);
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Get reactive search query
|
|
112
|
-
*/
|
|
113
|
-
export const query = searchQuery;
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Get reactive loading state
|
|
117
|
-
*/
|
|
118
|
-
export const loading = isSearching;
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Computed derived store for result count
|
|
122
|
-
*/
|
|
123
|
-
export const resultCount: Readable<number> = derived(
|
|
124
|
-
searchResults,
|
|
125
|
-
($results) => $results.length
|
|
126
|
-
);
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Clear search results and query
|
|
130
|
-
*/
|
|
131
|
-
export function clearSearch(): void {
|
|
132
|
-
searchQuery.set('');
|
|
133
|
-
searchResults.set([]);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Update search query and perform search
|
|
138
|
-
*/
|
|
139
|
-
export async function updateSearch(newQuery: string, filters?: SearchFilters): Promise<SearchResult[]> {
|
|
140
|
-
searchQuery.set(newQuery);
|
|
141
|
-
return performSearch(newQuery, filters);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Subscribe to search query changes with debouncing
|
|
146
|
-
*/
|
|
147
|
-
export function subscribeToSearch(
|
|
148
|
-
callback: (query: string) => Promise<void>,
|
|
149
|
-
delayMs: number = 300
|
|
150
|
-
): () => void {
|
|
151
|
-
let timeout: ReturnType<typeof setTimeout>;
|
|
152
|
-
|
|
153
|
-
const unsubscribe = searchQuery.subscribe((query) => {
|
|
154
|
-
clearTimeout(timeout);
|
|
155
|
-
timeout = setTimeout(() => callback(query), delayMs);
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
return () => {
|
|
159
|
-
clearTimeout(timeout);
|
|
160
|
-
unsubscribe();
|
|
161
|
-
};
|
|
162
|
-
}
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
-
import { theme } from './theme';
|
|
3
|
-
|
|
4
|
-
// Mock localStorage
|
|
5
|
-
const localStorageMock = (() => {
|
|
6
|
-
let store: Record<string, string> = {};
|
|
7
|
-
|
|
8
|
-
return {
|
|
9
|
-
getItem: (key: string) => store[key] || null,
|
|
10
|
-
setItem: (key: string, value: string) => {
|
|
11
|
-
store[key] = value.toString();
|
|
12
|
-
},
|
|
13
|
-
removeItem: (key: string) => {
|
|
14
|
-
delete store[key];
|
|
15
|
-
},
|
|
16
|
-
clear: () => {
|
|
17
|
-
store = {};
|
|
18
|
-
},
|
|
19
|
-
};
|
|
20
|
-
})();
|
|
21
|
-
|
|
22
|
-
Object.defineProperty(window, 'localStorage', {
|
|
23
|
-
value: localStorageMock,
|
|
24
|
-
writable: true,
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
describe('Theme Store', () => {
|
|
28
|
-
let unsubscribe: () => void;
|
|
29
|
-
let currentTheme: 'light' | 'dark' | null = null;
|
|
30
|
-
|
|
31
|
-
beforeEach(() => {
|
|
32
|
-
// Clear localStorage
|
|
33
|
-
localStorage.clear();
|
|
34
|
-
currentTheme = null;
|
|
35
|
-
|
|
36
|
-
// Subscribe to theme changes
|
|
37
|
-
unsubscribe = theme.subscribe((t) => {
|
|
38
|
-
currentTheme = t;
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
afterEach(() => {
|
|
43
|
-
if (unsubscribe) {
|
|
44
|
-
unsubscribe();
|
|
45
|
-
}
|
|
46
|
-
localStorage.clear();
|
|
47
|
-
// Remove dark class from document
|
|
48
|
-
document.documentElement.classList.remove('dark');
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
describe('Theme initialization', () => {
|
|
52
|
-
it('should default to light theme', () => {
|
|
53
|
-
expect(currentTheme).toBe('light');
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('should respect localStorage preference in standalone mode', () => {
|
|
57
|
-
// Verify that when we set a theme, it's saved to localStorage
|
|
58
|
-
theme.set('dark');
|
|
59
|
-
expect(localStorage.getItem('theme')).toBe('dark');
|
|
60
|
-
|
|
61
|
-
// Verify that the store reflects the saved value
|
|
62
|
-
expect(currentTheme).toBe('dark');
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
describe('Theme set', () => {
|
|
67
|
-
it('should set theme and apply dark class to document', () => {
|
|
68
|
-
theme.set('dark');
|
|
69
|
-
expect(currentTheme).toBe('dark');
|
|
70
|
-
expect(document.documentElement.classList.contains('dark')).toBe(true);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('should set theme and remove dark class from document', () => {
|
|
74
|
-
document.documentElement.classList.add('dark');
|
|
75
|
-
theme.set('light');
|
|
76
|
-
expect(currentTheme).toBe('light');
|
|
77
|
-
expect(document.documentElement.classList.contains('dark')).toBe(false);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it('should save theme to localStorage in standalone mode', () => {
|
|
81
|
-
theme.set('dark');
|
|
82
|
-
const stored = localStorage.getItem('theme');
|
|
83
|
-
expect(stored).toBe('dark');
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
describe('Theme toggle', () => {
|
|
88
|
-
it('should toggle from light to dark', () => {
|
|
89
|
-
theme.set('light');
|
|
90
|
-
theme.toggle();
|
|
91
|
-
expect(currentTheme).toBe('dark');
|
|
92
|
-
expect(document.documentElement.classList.contains('dark')).toBe(true);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('should toggle from dark to light', () => {
|
|
96
|
-
theme.set('dark');
|
|
97
|
-
theme.toggle();
|
|
98
|
-
expect(currentTheme).toBe('light');
|
|
99
|
-
expect(document.documentElement.classList.contains('dark')).toBe(false);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('should persist toggled theme to localStorage', () => {
|
|
103
|
-
theme.set('light');
|
|
104
|
-
theme.toggle();
|
|
105
|
-
expect(localStorage.getItem('theme')).toBe('dark');
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
describe('Parent theme detection', () => {
|
|
110
|
-
it('should detect parent theme when embedded', () => {
|
|
111
|
-
// This test would require mocking window.parent
|
|
112
|
-
// In a real scenario, window.parent would be set up in the parent app
|
|
113
|
-
// For now, we skip this test in unit tests and rely on integration tests
|
|
114
|
-
expect(true).toBe(true);
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
});
|