@alliance-droid/svelte-docs-system 0.0.1

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 (134) hide show
  1. package/COMPONENTS.md +365 -0
  2. package/COVERAGE_REPORT.md +663 -0
  3. package/README.md +42 -0
  4. package/SEARCH_VERIFICATION.md +229 -0
  5. package/TEST_SUMMARY.md +344 -0
  6. package/bin/init.js +821 -0
  7. package/docs/E2E_TESTS.md +354 -0
  8. package/docs/TESTING.md +754 -0
  9. package/docs/de/index.md +41 -0
  10. package/docs/en/COMPONENTS.md +443 -0
  11. package/docs/en/api/examples.md +100 -0
  12. package/docs/en/api/overview.md +69 -0
  13. package/docs/en/components/index.md +622 -0
  14. package/docs/en/config/navigation.md +505 -0
  15. package/docs/en/config/theme-and-colors.md +395 -0
  16. package/docs/en/getting-started/integration.md +406 -0
  17. package/docs/en/guides/common-setups.md +651 -0
  18. package/docs/en/index.md +243 -0
  19. package/docs/en/markdown.md +102 -0
  20. package/docs/en/routing.md +64 -0
  21. package/docs/en/setup.md +52 -0
  22. package/docs/en/troubleshooting.md +704 -0
  23. package/docs/es/index.md +41 -0
  24. package/docs/fr/index.md +41 -0
  25. package/docs/ja/index.md +41 -0
  26. package/package.json +40 -0
  27. package/pagefind.toml +8 -0
  28. package/postcss.config.js +5 -0
  29. package/src/app.css +119 -0
  30. package/src/app.d.ts +13 -0
  31. package/src/app.html +11 -0
  32. package/src/lib/assets/favicon.svg +1 -0
  33. package/src/lib/components/APITable.svelte +120 -0
  34. package/src/lib/components/APITable.test.ts +153 -0
  35. package/src/lib/components/Breadcrumbs.svelte +85 -0
  36. package/src/lib/components/Breadcrumbs.test.ts +148 -0
  37. package/src/lib/components/Callout.svelte +60 -0
  38. package/src/lib/components/Callout.test.ts +100 -0
  39. package/src/lib/components/CodeBlock.svelte +68 -0
  40. package/src/lib/components/CodeBlock.test.ts +133 -0
  41. package/src/lib/components/DocLayout.svelte +84 -0
  42. package/src/lib/components/Footer.svelte +78 -0
  43. package/src/lib/components/Image.svelte +100 -0
  44. package/src/lib/components/Image.test.ts +163 -0
  45. package/src/lib/components/Navbar.svelte +141 -0
  46. package/src/lib/components/Search.svelte +248 -0
  47. package/src/lib/components/Sidebar.svelte +110 -0
  48. package/src/lib/components/Tabs.svelte +48 -0
  49. package/src/lib/components/Tabs.test.ts +102 -0
  50. package/src/lib/config.test.ts +140 -0
  51. package/src/lib/config.ts +179 -0
  52. package/src/lib/configIntegration.test.ts +272 -0
  53. package/src/lib/configLoader.ts +231 -0
  54. package/src/lib/configParser.test.ts +217 -0
  55. package/src/lib/configParser.ts +234 -0
  56. package/src/lib/index.ts +34 -0
  57. package/src/lib/integration.test.ts +426 -0
  58. package/src/lib/navigationBuilder.test.ts +338 -0
  59. package/src/lib/navigationBuilder.ts +268 -0
  60. package/src/lib/performance.test.ts +369 -0
  61. package/src/lib/routing.test.ts +202 -0
  62. package/src/lib/routing.ts +127 -0
  63. package/src/lib/search-functionality.test.ts +493 -0
  64. package/src/lib/stores/i18n.test.ts +180 -0
  65. package/src/lib/stores/i18n.ts +143 -0
  66. package/src/lib/stores/nav.ts +36 -0
  67. package/src/lib/stores/search.test.ts +140 -0
  68. package/src/lib/stores/search.ts +162 -0
  69. package/src/lib/stores/theme.ts +59 -0
  70. package/src/lib/stores/version.test.ts +139 -0
  71. package/src/lib/stores/version.ts +111 -0
  72. package/src/lib/themeCustomization.test.ts +223 -0
  73. package/src/lib/themeCustomization.ts +212 -0
  74. package/src/lib/utils/highlight.test.ts +136 -0
  75. package/src/lib/utils/highlight.ts +100 -0
  76. package/src/lib/utils/index.ts +7 -0
  77. package/src/lib/utils/markdown.test.ts +357 -0
  78. package/src/lib/utils/markdown.ts +77 -0
  79. package/src/routes/+layout.server.ts +1 -0
  80. package/src/routes/+layout.svelte +28 -0
  81. package/src/routes/+page.svelte +165 -0
  82. package/static/robots.txt +3 -0
  83. package/svelte.config.js +18 -0
  84. package/tailwind.config.ts +55 -0
  85. package/template-starter/.github/workflows/build.yml +40 -0
  86. package/template-starter/.github/workflows/deploy-github-pages.yml +47 -0
  87. package/template-starter/.github/workflows/deploy-netlify.yml +41 -0
  88. package/template-starter/.github/workflows/deploy-vercel.yml +64 -0
  89. package/template-starter/NPM-PACKAGE-SETUP.md +233 -0
  90. package/template-starter/README.md +320 -0
  91. package/template-starter/docs/_config.json +39 -0
  92. package/template-starter/docs/api/components.md +257 -0
  93. package/template-starter/docs/api/overview.md +169 -0
  94. package/template-starter/docs/guides/configuration.md +145 -0
  95. package/template-starter/docs/guides/github-pages-deployment.md +254 -0
  96. package/template-starter/docs/guides/netlify-deployment.md +159 -0
  97. package/template-starter/docs/guides/vercel-deployment.md +131 -0
  98. package/template-starter/docs/index.md +49 -0
  99. package/template-starter/docs/setup.md +149 -0
  100. package/template-starter/package.json +31 -0
  101. package/template-starter/pagefind.toml +3 -0
  102. package/template-starter/postcss.config.js +5 -0
  103. package/template-starter/src/app.css +34 -0
  104. package/template-starter/src/app.d.ts +13 -0
  105. package/template-starter/src/app.html +11 -0
  106. package/template-starter/src/lib/components/APITable.svelte +120 -0
  107. package/template-starter/src/lib/components/APITable.test.ts +19 -0
  108. package/template-starter/src/lib/components/Breadcrumbs.svelte +85 -0
  109. package/template-starter/src/lib/components/Breadcrumbs.test.ts +19 -0
  110. package/template-starter/src/lib/components/Callout.svelte +60 -0
  111. package/template-starter/src/lib/components/Callout.test.ts +16 -0
  112. package/template-starter/src/lib/components/CodeBlock.svelte +68 -0
  113. package/template-starter/src/lib/components/CodeBlock.test.ts +12 -0
  114. package/template-starter/src/lib/components/DocLayout.svelte +84 -0
  115. package/template-starter/src/lib/components/Footer.svelte +78 -0
  116. package/template-starter/src/lib/components/Image.svelte +100 -0
  117. package/template-starter/src/lib/components/Image.test.ts +15 -0
  118. package/template-starter/src/lib/components/Navbar.svelte +141 -0
  119. package/template-starter/src/lib/components/Search.svelte +248 -0
  120. package/template-starter/src/lib/components/Sidebar.svelte +110 -0
  121. package/template-starter/src/lib/components/Tabs.svelte +48 -0
  122. package/template-starter/src/lib/components/Tabs.test.ts +17 -0
  123. package/template-starter/src/lib/index.ts +15 -0
  124. package/template-starter/src/routes/+layout.svelte +28 -0
  125. package/template-starter/src/routes/+page.svelte +92 -0
  126. package/template-starter/svelte.config.js +17 -0
  127. package/template-starter/tailwind.config.ts +17 -0
  128. package/template-starter/tsconfig.json +13 -0
  129. package/template-starter/vite.config.ts +6 -0
  130. package/tests/e2e/example.spec.ts +345 -0
  131. package/tsconfig.json +20 -0
  132. package/vite.config.ts +6 -0
  133. package/vitest.config.ts +34 -0
  134. package/vitest.setup.ts +21 -0
@@ -0,0 +1,345 @@
1
+ import { test, expect } from '@playwright/test';
2
+
3
+ /**
4
+ * Example E2E Tests
5
+ * Demonstrates the structure of E2E tests for Svelte Docs System
6
+ *
7
+ * Note: These tests require Playwright to be installed
8
+ * Run with: npm run test:e2e
9
+ */
10
+
11
+ test.describe('Documentation System E2E', () => {
12
+ test.beforeEach(async ({ page }) => {
13
+ // Navigate to the documentation homepage before each test
14
+ await page.goto('/');
15
+ });
16
+
17
+ test.describe('Navigation', () => {
18
+ test('should navigate between pages', async ({ page }) => {
19
+ // Find and click a navigation link
20
+ await page.click('a[href="/docs/guides"]');
21
+
22
+ // Wait for navigation and verify page content
23
+ await page.waitForURL('/docs/guides');
24
+ expect(page.url()).toContain('/docs/guides');
25
+
26
+ // Verify content loaded
27
+ const heading = await page.locator('h1');
28
+ await expect(heading).toBeVisible();
29
+ });
30
+
31
+ test('should display breadcrumbs', async ({ page }) => {
32
+ await page.goto('/docs/guides/getting-started');
33
+
34
+ // Check breadcrumb structure
35
+ const breadcrumbs = page.locator('[role="navigation"] a');
36
+ const count = await breadcrumbs.count();
37
+
38
+ expect(count).toBeGreaterThan(0);
39
+
40
+ // Verify breadcrumb content
41
+ const lastBreadcrumb = breadcrumbs.nth(count - 1);
42
+ await expect(lastBreadcrumb).toContainText(/Getting Started|getting-started/i);
43
+ });
44
+
45
+ test('should update active navigation item', async ({ page }) => {
46
+ const navItem = page.locator('nav a').first();
47
+
48
+ await navItem.click();
49
+ await page.waitForLoadState('networkidle');
50
+
51
+ // Check if active class is applied
52
+ const activeItem = page.locator('nav a.active, nav a[aria-current]').first();
53
+ await expect(activeItem).toBeVisible();
54
+ });
55
+ });
56
+
57
+ test.describe('Search', () => {
58
+ test('should search and display results', async ({ page }) => {
59
+ // Click search input
60
+ const searchInput = page.locator('input[placeholder*="Search"]');
61
+ await searchInput.click();
62
+
63
+ // Type search query
64
+ await searchInput.fill('getting started');
65
+
66
+ // Wait for results to appear
67
+ const searchResults = page.locator('[role="listbox"], .search-results');
68
+ await expect(searchResults).toBeVisible();
69
+
70
+ // Verify results contain the query
71
+ const resultItems = page.locator('[role="option"], .search-result-item');
72
+ expect(await resultItems.count()).toBeGreaterThan(0);
73
+ });
74
+
75
+ test('should navigate to search result', async ({ page }) => {
76
+ const searchInput = page.locator('input[placeholder*="Search"]');
77
+ await searchInput.fill('API');
78
+
79
+ // Wait for results and click first one
80
+ const firstResult = page.locator('[role="option"], .search-result-item').first();
81
+ await firstResult.click();
82
+
83
+ // Verify navigation happened
84
+ await page.waitForLoadState('networkidle');
85
+ expect(page.url()).toContain('/');
86
+ });
87
+
88
+ test('should show no results message', async ({ page }) => {
89
+ const searchInput = page.locator('input[placeholder*="Search"]');
90
+ await searchInput.fill('xyzabc123notarealterm');
91
+
92
+ // Wait a bit for search to complete
93
+ await page.waitForTimeout(500);
94
+
95
+ // Check for no results message
96
+ const noResultsMsg = page.locator('text=/No results|nothing found/i');
97
+ await expect(noResultsMsg).toBeVisible();
98
+ });
99
+ });
100
+
101
+ test.describe('Dark Mode', () => {
102
+ test('should toggle dark mode', async ({ page }) => {
103
+ // Find and click dark mode toggle
104
+ const darkModeToggle = page.locator('[aria-label*="Dark"], [aria-label*="Theme"]');
105
+
106
+ // Get initial state
107
+ const htmlElement = page.locator('html');
108
+ const initialClass = await htmlElement.getAttribute('class');
109
+
110
+ // Click toggle
111
+ await darkModeToggle.click();
112
+
113
+ // Verify class changed
114
+ const newClass = await htmlElement.getAttribute('class');
115
+ expect(newClass).not.toBe(initialClass);
116
+ });
117
+
118
+ test('should persist dark mode preference', async ({ page, context }) => {
119
+ // Enable dark mode
120
+ const toggle = page.locator('[aria-label*="Dark"], [aria-label*="Theme"]');
121
+ await toggle.click();
122
+
123
+ // Verify it's enabled
124
+ const htmlElement = page.locator('html');
125
+ const isDarkMode = (await htmlElement.getAttribute('class'))?.includes('dark');
126
+ expect(isDarkMode).toBeTruthy();
127
+
128
+ // Reload page
129
+ await page.reload();
130
+
131
+ // Verify dark mode still active
132
+ const isDarkModeAfterReload = (
133
+ await htmlElement.getAttribute('class')
134
+ )?.includes('dark');
135
+ expect(isDarkModeAfterReload).toBeTruthy();
136
+ });
137
+
138
+ test('should have readable text in dark mode', async ({ page }) => {
139
+ // Enable dark mode
140
+ const toggle = page.locator('[aria-label*="Dark"], [aria-label*="Theme"]');
141
+ await toggle.click();
142
+
143
+ // Get text color and background color
144
+ const mainContent = page.locator('main').first();
145
+
146
+ const styles = await mainContent.evaluate((el) => {
147
+ const computed = window.getComputedStyle(el);
148
+ return {
149
+ color: computed.color,
150
+ backgroundColor: computed.backgroundColor
151
+ };
152
+ });
153
+
154
+ // Verify colors are defined
155
+ expect(styles.color).toBeTruthy();
156
+ expect(styles.backgroundColor).toBeTruthy();
157
+ });
158
+ });
159
+
160
+ test.describe('Responsive Design', () => {
161
+ test('should show mobile menu on small screens', async ({ page }) => {
162
+ // Set mobile viewport
163
+ await page.setViewportSize({ width: 375, height: 667 });
164
+
165
+ // Look for hamburger menu
166
+ const hamburgerMenu = page.locator('[aria-label*="Menu"], [aria-label*="Navigation"]');
167
+ await expect(hamburgerMenu).toBeVisible();
168
+
169
+ // Click hamburger
170
+ await hamburgerMenu.click();
171
+
172
+ // Verify menu opens
173
+ const mobileNav = page.locator('nav').first();
174
+ await expect(mobileNav).toBeVisible();
175
+ });
176
+
177
+ test('should show sidebar on desktop', async ({ page }) => {
178
+ // Set desktop viewport
179
+ await page.setViewportSize({ width: 1440, height: 900 });
180
+
181
+ // Sidebar should be visible
182
+ const sidebar = page.locator('aside, nav');
183
+ await expect(sidebar.first()).toBeVisible();
184
+ });
185
+ });
186
+
187
+ test.describe('Accessibility', () => {
188
+ test('should be keyboard navigable', async ({ page }) => {
189
+ // Tab through page elements
190
+ const firstButton = page.locator('button').first();
191
+
192
+ // Initially should not have focus
193
+ let hasFocus = await firstButton.evaluate((el) => el === document.activeElement);
194
+ expect(hasFocus).toBeFalsy();
195
+
196
+ // Press Tab and verify focus appears
197
+ await page.keyboard.press('Tab');
198
+
199
+ // Check if any element has focus
200
+ const focusedElement = await page.evaluate(() => {
201
+ return document.activeElement?.tagName;
202
+ });
203
+
204
+ expect(focusedElement).toBeTruthy();
205
+ });
206
+
207
+ test('should have alt text for images', async ({ page }) => {
208
+ const images = page.locator('img');
209
+
210
+ const count = await images.count();
211
+ if (count > 0) {
212
+ // Get alt text of first image
213
+ const altText = await images.first().getAttribute('alt');
214
+
215
+ // Should have alt text (if decorative, should be empty intentionally)
216
+ expect(altText).not.toBeNull();
217
+ }
218
+ });
219
+
220
+ test('should have proper heading hierarchy', async ({ page }) => {
221
+ const h1Count = await page.locator('h1').count();
222
+ const h2s = await page.locator('h2').count();
223
+
224
+ // Page should have exactly one h1
225
+ expect(h1Count).toBe(1);
226
+
227
+ // h2s should exist (if multiple sections)
228
+ // This is flexible as some pages might not have subsections
229
+ expect(h2s).toBeGreaterThanOrEqual(0);
230
+ });
231
+ });
232
+
233
+ test.describe('Content Display', () => {
234
+ test('should render markdown content', async ({ page }) => {
235
+ // Navigate to a content page
236
+ await page.goto('/docs');
237
+
238
+ // Wait for main content to load
239
+ const mainContent = page.locator('main, article').first();
240
+ await expect(mainContent).toBeVisible();
241
+
242
+ // Verify content exists
243
+ const text = await mainContent.textContent();
244
+ expect(text).toBeTruthy();
245
+ expect(text?.length).toBeGreaterThan(0);
246
+ });
247
+
248
+ test('should display code blocks with syntax highlighting', async ({ page }) => {
249
+ const codeBlocks = page.locator('pre, code');
250
+
251
+ if (await codeBlocks.count() > 0) {
252
+ const firstCode = codeBlocks.first();
253
+ await expect(firstCode).toBeVisible();
254
+
255
+ // Verify code content
256
+ const content = await firstCode.textContent();
257
+ expect(content).toBeTruthy();
258
+ }
259
+ });
260
+
261
+ test('should have functional copy button on code blocks', async ({ page }) => {
262
+ const codeBlock = page.locator('pre').first();
263
+
264
+ if (await codeBlock.isVisible()) {
265
+ const copyButton = page
266
+ .locator('button')
267
+ .filter({ hasText: /Copy|copy/ })
268
+ .first();
269
+
270
+ if (await copyButton.isVisible()) {
271
+ // Click copy button
272
+ await copyButton.click();
273
+
274
+ // Verify some feedback (success message, button state change, etc.)
275
+ const successMsg = page.locator('text=/copied|success/i').first();
276
+ await expect(successMsg).toBeVisible({ timeout: 2000 });
277
+ }
278
+ }
279
+ });
280
+ });
281
+
282
+ test.describe('Performance', () => {
283
+ test('should load page within acceptable time', async ({ page }) => {
284
+ const startTime = Date.now();
285
+
286
+ await page.goto('/');
287
+ await page.waitForLoadState('networkidle');
288
+
289
+ const loadTime = Date.now() - startTime;
290
+
291
+ // Page should load within 3 seconds
292
+ expect(loadTime).toBeLessThan(3000);
293
+ });
294
+
295
+ test('should have good Core Web Vitals', async ({ page }) => {
296
+ await page.goto('/');
297
+
298
+ const vitals = await page.evaluate(() => {
299
+ return new Promise<any>((resolve) => {
300
+ let lcp = 0;
301
+ let cls = 0;
302
+
303
+ const observer = new PerformanceObserver((list) => {
304
+ for (const entry of list.getEntries()) {
305
+ if ((entry as any).name === 'largest-contentful-paint') {
306
+ lcp = (entry as any).renderTime || (entry as any).loadTime;
307
+ } else if ((entry as any).hadRecentInput === false) {
308
+ cls += (entry as any).value;
309
+ }
310
+ }
311
+ });
312
+
313
+ observer.observe({ entryTypes: ['largest-contentful-paint', 'layout-shift'] });
314
+
315
+ setTimeout(() => {
316
+ observer.disconnect();
317
+ resolve({ lcp, cls });
318
+ }, 3000);
319
+ });
320
+ });
321
+
322
+ // LCP should be less than 2.5 seconds
323
+ expect(vitals.lcp).toBeLessThan(2500);
324
+
325
+ // CLS should be less than 0.1
326
+ expect(vitals.cls).toBeLessThan(0.1);
327
+ });
328
+ });
329
+ });
330
+
331
+ test.describe('Error Handling', () => {
332
+ test('should show 404 page for non-existent routes', async ({ page }) => {
333
+ await page.goto('/docs/this-page-does-not-exist-123');
334
+
335
+ // Should see 404 message or not found page
336
+ const notFoundMsg = page.locator('text=/404|not found|does not exist/i');
337
+
338
+ // Try to find error message
339
+ const hasError =
340
+ (await notFoundMsg.count()) > 0 ||
341
+ page.url().includes('404');
342
+
343
+ expect(hasError).toBeTruthy();
344
+ });
345
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "extends": "./.svelte-kit/tsconfig.json",
3
+ "compilerOptions": {
4
+ "rewriteRelativeImportExtensions": true,
5
+ "allowJs": true,
6
+ "checkJs": true,
7
+ "esModuleInterop": true,
8
+ "forceConsistentCasingInFileNames": true,
9
+ "resolveJsonModule": true,
10
+ "skipLibCheck": true,
11
+ "sourceMap": true,
12
+ "strict": true,
13
+ "moduleResolution": "bundler"
14
+ }
15
+ // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
16
+ // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
17
+ //
18
+ // To make changes to top-level options such as include and exclude, we recommend extending
19
+ // the generated config; see https://svelte.dev/docs/kit/configuration#typescript
20
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,6 @@
1
+ import { sveltekit } from '@sveltejs/kit/vite';
2
+ import { defineConfig } from 'vite';
3
+
4
+ export default defineConfig({
5
+ plugins: [sveltekit()]
6
+ });
@@ -0,0 +1,34 @@
1
+ import { defineConfig } from 'vitest/config';
2
+ import { sveltekit } from '@sveltejs/kit/vite';
3
+
4
+ export default defineConfig({
5
+ plugins: [sveltekit()],
6
+ test: {
7
+ globals: true,
8
+ environment: 'jsdom',
9
+ setupFiles: ['./vitest.setup.ts'],
10
+ // Ensure we use browser build of Svelte
11
+ alias: {
12
+ 'svelte/internal': 'svelte/internal'
13
+ },
14
+ coverage: {
15
+ provider: 'v8',
16
+ reporter: ['text', 'json', 'html', 'lcov'],
17
+ exclude: [
18
+ 'node_modules/',
19
+ 'dist/',
20
+ 'build/',
21
+ 'coverage/',
22
+ '**/*.test.ts',
23
+ '**/*.spec.ts',
24
+ 'tests/',
25
+ 'template-starter/'
26
+ ],
27
+ include: ['src/lib/**/*.ts', 'src/lib/**/*.svelte'],
28
+ lines: 85,
29
+ functions: 85,
30
+ branches: 80,
31
+ statements: 85
32
+ }
33
+ }
34
+ });
@@ -0,0 +1,21 @@
1
+ import { expect, afterEach, beforeEach, vi } from 'vitest';
2
+ import { cleanup } from '@testing-library/svelte';
3
+
4
+ // Cleanup after each test
5
+ afterEach(() => {
6
+ cleanup();
7
+ });
8
+
9
+ // Initialize and clear storage if available
10
+ beforeEach(() => {
11
+ try {
12
+ if (typeof localStorage !== 'undefined' && localStorage.clear) {
13
+ localStorage.clear();
14
+ }
15
+ if (typeof sessionStorage !== 'undefined' && sessionStorage.clear) {
16
+ sessionStorage.clear();
17
+ }
18
+ } catch (e) {
19
+ // Storage might not be available in some test environments
20
+ }
21
+ });