@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.
Files changed (185) hide show
  1. package/README.md +155 -23
  2. package/dist/components/APITable.svelte.d.ts +21 -0
  3. package/dist/components/Breadcrumbs.svelte.d.ts +14 -0
  4. package/dist/components/Callout.svelte.d.ts +15 -0
  5. package/dist/components/CodeBlock.svelte.d.ts +12 -0
  6. package/{src/lib → dist}/components/DocLayout.svelte +18 -6
  7. package/dist/components/DocLayout.svelte.d.ts +18 -0
  8. package/dist/components/DocsPage.svelte +39 -0
  9. package/dist/components/DocsPage.svelte.d.ts +8 -0
  10. package/dist/components/Documentation.svelte +639 -0
  11. package/dist/components/Footer.svelte.d.ts +10 -0
  12. package/dist/components/Image.svelte.d.ts +15 -0
  13. package/{src/lib → dist}/components/Navbar.svelte +4 -4
  14. package/dist/components/Navbar.svelte.d.ts +10 -0
  15. package/{src/lib → dist}/components/Search.svelte +2 -2
  16. package/dist/components/Search.svelte.d.ts +6 -0
  17. package/{template-starter/src/lib → dist}/components/Sidebar.svelte +2 -2
  18. package/dist/components/Sidebar.svelte.d.ts +9 -0
  19. package/dist/components/Tabs.svelte.d.ts +16 -0
  20. package/dist/config.d.ts +93 -0
  21. package/dist/config.js +89 -0
  22. package/dist/configLoader.d.ts +48 -0
  23. package/dist/configLoader.js +187 -0
  24. package/dist/configParser.d.ts +27 -0
  25. package/dist/configParser.js +208 -0
  26. package/{template-starter/src/lib/index.ts → dist/index.d.ts} +6 -7
  27. package/dist/index.js +18 -0
  28. package/dist/navigationBuilder.d.ts +64 -0
  29. package/dist/navigationBuilder.js +225 -0
  30. package/dist/plugin.d.ts +30 -0
  31. package/dist/plugin.js +172 -0
  32. package/dist/routing.d.ts +48 -0
  33. package/dist/routing.js +92 -0
  34. package/dist/stores/i18n.d.ts +20 -0
  35. package/dist/stores/i18n.js +119 -0
  36. package/dist/stores/nav.d.ts +20 -0
  37. package/dist/stores/nav.js +15 -0
  38. package/dist/stores/search.d.ts +49 -0
  39. package/dist/stores/search.js +127 -0
  40. package/dist/stores/theme.d.ts +7 -0
  41. package/dist/stores/theme.js +152 -0
  42. package/dist/stores/version.d.ts +18 -0
  43. package/dist/stores/version.js +93 -0
  44. package/dist/themeCustomization.d.ts +46 -0
  45. package/dist/themeCustomization.js +188 -0
  46. package/dist/utils/highlight.d.ts +13 -0
  47. package/dist/utils/highlight.js +83 -0
  48. package/dist/utils/index.d.ts +1 -0
  49. package/dist/utils/index.js +1 -0
  50. package/dist/utils/markdown.d.ts +40 -0
  51. package/dist/utils/markdown.js +165 -0
  52. package/package.json +44 -23
  53. package/COMPONENTS.md +0 -365
  54. package/COVERAGE_REPORT.md +0 -663
  55. package/SEARCH_VERIFICATION.md +0 -229
  56. package/TEST_SUMMARY.md +0 -344
  57. package/bin/init.js +0 -821
  58. package/docs/COMPONENT_LIBRARY_INTEGRATION_REPORT.md +0 -153
  59. package/docs/DARK_MODE_AUDIT_REPORT.md +0 -403
  60. package/docs/E2E_TESTS.md +0 -354
  61. package/docs/TESTING.md +0 -754
  62. package/docs/THEME_INHERITANCE.md +0 -192
  63. package/docs/de/index.md +0 -41
  64. package/docs/en/COMPONENTS.md +0 -443
  65. package/docs/en/api/examples.md +0 -100
  66. package/docs/en/api/overview.md +0 -69
  67. package/docs/en/components/index.md +0 -622
  68. package/docs/en/config/navigation.md +0 -505
  69. package/docs/en/config/theme-and-colors.md +0 -395
  70. package/docs/en/getting-started/integration.md +0 -406
  71. package/docs/en/guides/common-setups.md +0 -651
  72. package/docs/en/index.md +0 -243
  73. package/docs/en/markdown.md +0 -102
  74. package/docs/en/routing.md +0 -64
  75. package/docs/en/setup.md +0 -52
  76. package/docs/en/troubleshooting.md +0 -704
  77. package/docs/es/index.md +0 -41
  78. package/docs/fr/index.md +0 -41
  79. package/docs/ja/index.md +0 -41
  80. package/pagefind.toml +0 -8
  81. package/postcss.config.js +0 -5
  82. package/src/app.css +0 -119
  83. package/src/app.d.ts +0 -13
  84. package/src/app.html +0 -11
  85. package/src/lib/components/APITable.test.ts +0 -153
  86. package/src/lib/components/Breadcrumbs.test.ts +0 -148
  87. package/src/lib/components/Callout.test.ts +0 -100
  88. package/src/lib/components/CodeBlock.test.ts +0 -133
  89. package/src/lib/components/Image.test.ts +0 -163
  90. package/src/lib/components/Sidebar.svelte +0 -110
  91. package/src/lib/components/Tabs.test.ts +0 -102
  92. package/src/lib/config.test.ts +0 -140
  93. package/src/lib/config.ts +0 -179
  94. package/src/lib/configIntegration.test.ts +0 -272
  95. package/src/lib/configLoader.ts +0 -231
  96. package/src/lib/configParser.test.ts +0 -217
  97. package/src/lib/configParser.ts +0 -234
  98. package/src/lib/index.ts +0 -37
  99. package/src/lib/integration.test.ts +0 -426
  100. package/src/lib/navigationBuilder.test.ts +0 -338
  101. package/src/lib/navigationBuilder.ts +0 -268
  102. package/src/lib/performance.test.ts +0 -369
  103. package/src/lib/routing.test.ts +0 -202
  104. package/src/lib/routing.ts +0 -127
  105. package/src/lib/search-functionality.test.ts +0 -493
  106. package/src/lib/stores/i18n.test.ts +0 -180
  107. package/src/lib/stores/i18n.ts +0 -143
  108. package/src/lib/stores/nav.ts +0 -36
  109. package/src/lib/stores/search.test.ts +0 -140
  110. package/src/lib/stores/search.ts +0 -162
  111. package/src/lib/stores/theme.test.ts +0 -117
  112. package/src/lib/stores/theme.ts +0 -167
  113. package/src/lib/stores/version.test.ts +0 -139
  114. package/src/lib/stores/version.ts +0 -111
  115. package/src/lib/themeCustomization.test.ts +0 -223
  116. package/src/lib/themeCustomization.ts +0 -212
  117. package/src/lib/utils/highlight.test.ts +0 -136
  118. package/src/lib/utils/highlight.ts +0 -100
  119. package/src/lib/utils/index.ts +0 -7
  120. package/src/lib/utils/markdown.test.ts +0 -357
  121. package/src/lib/utils/markdown.ts +0 -77
  122. package/src/routes/+layout.server.ts +0 -1
  123. package/src/routes/+layout.svelte +0 -29
  124. package/src/routes/+page.svelte +0 -165
  125. package/src/routes/quote-demo/+page.svelte +0 -141
  126. package/static/robots.txt +0 -3
  127. package/svelte.config.js +0 -15
  128. package/tailwind.config.ts +0 -55
  129. package/template-starter/.github/workflows/build.yml +0 -40
  130. package/template-starter/.github/workflows/deploy-github-pages.yml +0 -47
  131. package/template-starter/.github/workflows/deploy-netlify.yml +0 -41
  132. package/template-starter/.github/workflows/deploy-vercel.yml +0 -64
  133. package/template-starter/NPM-PACKAGE-SETUP.md +0 -233
  134. package/template-starter/README.md +0 -320
  135. package/template-starter/docs/_config.json +0 -39
  136. package/template-starter/docs/api/components.md +0 -257
  137. package/template-starter/docs/api/overview.md +0 -169
  138. package/template-starter/docs/guides/configuration.md +0 -145
  139. package/template-starter/docs/guides/github-pages-deployment.md +0 -254
  140. package/template-starter/docs/guides/netlify-deployment.md +0 -159
  141. package/template-starter/docs/guides/vercel-deployment.md +0 -131
  142. package/template-starter/docs/index.md +0 -49
  143. package/template-starter/docs/setup.md +0 -149
  144. package/template-starter/package.json +0 -31
  145. package/template-starter/pagefind.toml +0 -3
  146. package/template-starter/postcss.config.js +0 -5
  147. package/template-starter/src/app.css +0 -34
  148. package/template-starter/src/app.d.ts +0 -13
  149. package/template-starter/src/app.html +0 -11
  150. package/template-starter/src/lib/components/APITable.svelte +0 -120
  151. package/template-starter/src/lib/components/APITable.test.ts +0 -96
  152. package/template-starter/src/lib/components/Breadcrumbs.svelte +0 -85
  153. package/template-starter/src/lib/components/Breadcrumbs.test.ts +0 -82
  154. package/template-starter/src/lib/components/Callout.svelte +0 -60
  155. package/template-starter/src/lib/components/Callout.test.ts +0 -91
  156. package/template-starter/src/lib/components/CodeBlock.svelte +0 -68
  157. package/template-starter/src/lib/components/CodeBlock.test.ts +0 -62
  158. package/template-starter/src/lib/components/DocLayout.svelte +0 -84
  159. package/template-starter/src/lib/components/Footer.svelte +0 -78
  160. package/template-starter/src/lib/components/Image.svelte +0 -100
  161. package/template-starter/src/lib/components/Image.test.ts +0 -81
  162. package/template-starter/src/lib/components/Navbar.svelte +0 -141
  163. package/template-starter/src/lib/components/Search.svelte +0 -248
  164. package/template-starter/src/lib/components/Tabs.svelte +0 -48
  165. package/template-starter/src/lib/components/Tabs.test.ts +0 -89
  166. package/template-starter/src/routes/+layout.svelte +0 -28
  167. package/template-starter/src/routes/+page.svelte +0 -92
  168. package/template-starter/svelte.config.js +0 -17
  169. package/template-starter/tailwind.config.ts +0 -17
  170. package/template-starter/tsconfig.json +0 -13
  171. package/template-starter/vite.config.ts +0 -6
  172. package/tests/e2e/example.spec.ts +0 -345
  173. package/tsconfig.json +0 -20
  174. package/vite.config.ts +0 -6
  175. package/vitest.config.ts +0 -33
  176. package/vitest.setup.ts +0 -21
  177. /package/{src/lib → dist}/assets/favicon.svg +0 -0
  178. /package/{src/lib → dist}/components/APITable.svelte +0 -0
  179. /package/{src/lib → dist}/components/Breadcrumbs.svelte +0 -0
  180. /package/{src/lib → dist}/components/Callout.svelte +0 -0
  181. /package/{src/lib → dist}/components/CodeBlock.svelte +0 -0
  182. /package/{src/lib → dist}/components/Footer.svelte +0 -0
  183. /package/{src/lib → dist}/components/Image.svelte +0 -0
  184. /package/{src/lib → dist}/components/Tabs.svelte +0 -0
  185. /package/{src/lib → dist}/svelte-component-library.d.ts +0 -0
@@ -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();
@@ -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
- });
@@ -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
- });