@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
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
/**
|
|
3
|
-
* Image component with caption support
|
|
4
|
-
* Provides responsive images with optional captions and alt text
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
interface Props {
|
|
8
|
-
src: string;
|
|
9
|
-
alt: string;
|
|
10
|
-
caption?: string;
|
|
11
|
-
width?: number;
|
|
12
|
-
height?: number;
|
|
13
|
-
zoomable?: boolean;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
let { src, alt, caption, width, height, zoomable = true }: Props = $props();
|
|
17
|
-
|
|
18
|
-
let isZoomed = $state(false);
|
|
19
|
-
|
|
20
|
-
function handleZoom() {
|
|
21
|
-
if (zoomable) {
|
|
22
|
-
isZoomed = !isZoomed;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function handleKeydown(e: KeyboardEvent) {
|
|
27
|
-
if (e.key === 'Escape' && isZoomed) {
|
|
28
|
-
isZoomed = false;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
</script>
|
|
32
|
-
|
|
33
|
-
<svelte:window on:keydown={handleKeydown} />
|
|
34
|
-
|
|
35
|
-
<figure class="my-6 flex flex-col items-center gap-2">
|
|
36
|
-
<div class="relative w-full max-w-4xl overflow-hidden rounded-lg border border-gray-200 dark:border-gray-700">
|
|
37
|
-
<!-- Zoomed overlay -->
|
|
38
|
-
{#if isZoomed}
|
|
39
|
-
<div
|
|
40
|
-
class="fixed inset-0 z-50 flex cursor-pointer items-center justify-center bg-black/80 backdrop-blur"
|
|
41
|
-
onclick={() => (isZoomed = false)}
|
|
42
|
-
onkeydown={(e) => {
|
|
43
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
44
|
-
isZoomed = false;
|
|
45
|
-
}
|
|
46
|
-
}}
|
|
47
|
-
role="button"
|
|
48
|
-
tabindex="0"
|
|
49
|
-
>
|
|
50
|
-
<img
|
|
51
|
-
{src}
|
|
52
|
-
{alt}
|
|
53
|
-
class="max-h-[90vh] max-w-[90vw] rounded-lg object-contain"
|
|
54
|
-
{width}
|
|
55
|
-
{height}
|
|
56
|
-
/>
|
|
57
|
-
</div>
|
|
58
|
-
{/if}
|
|
59
|
-
|
|
60
|
-
<!-- Regular image wrapper for clickability -->
|
|
61
|
-
<button
|
|
62
|
-
onclick={handleZoom}
|
|
63
|
-
class="w-full border-0 bg-transparent p-0"
|
|
64
|
-
aria-label={zoomable ? 'Click to zoom image' : ''}
|
|
65
|
-
type="button"
|
|
66
|
-
>
|
|
67
|
-
<img
|
|
68
|
-
{src}
|
|
69
|
-
{alt}
|
|
70
|
-
{width}
|
|
71
|
-
{height}
|
|
72
|
-
class="w-full object-cover {zoomable ? 'cursor-zoom-in hover:opacity-90' : ''} transition-opacity"
|
|
73
|
-
/>
|
|
74
|
-
</button>
|
|
75
|
-
</div>
|
|
76
|
-
|
|
77
|
-
{#if caption}
|
|
78
|
-
<figcaption class="text-center text-sm text-gray-600 dark:text-gray-400">
|
|
79
|
-
{caption}
|
|
80
|
-
</figcaption>
|
|
81
|
-
{/if}
|
|
82
|
-
</figure>
|
|
83
|
-
|
|
84
|
-
<style>
|
|
85
|
-
figure {
|
|
86
|
-
margin-top: 1.5rem;
|
|
87
|
-
margin-bottom: 1.5rem;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
figcaption {
|
|
91
|
-
margin-top: 0.5rem;
|
|
92
|
-
text-align: center;
|
|
93
|
-
font-size: 0.875rem;
|
|
94
|
-
color: #4b5563;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
:global(.dark) figcaption {
|
|
98
|
-
color: #9ca3af;
|
|
99
|
-
}
|
|
100
|
-
</style>
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Unit tests for Image component
|
|
5
|
-
* Tests component configuration and prop handling
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
describe('Image Component', () => {
|
|
9
|
-
describe('Props', () => {
|
|
10
|
-
it('renders image with src and alt', () => {
|
|
11
|
-
const props = {
|
|
12
|
-
src: 'test.jpg',
|
|
13
|
-
alt: 'Test image'
|
|
14
|
-
};
|
|
15
|
-
expect(props.src).toBeTruthy();
|
|
16
|
-
expect(props.alt).toBeTruthy();
|
|
17
|
-
expect(props.src).toMatch(/\.(jpg|png|gif|webp|svg)$/);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('should accept required src prop', () => {
|
|
21
|
-
const src = 'image.png';
|
|
22
|
-
expect(typeof src).toBe('string');
|
|
23
|
-
expect(src).toBeTruthy();
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('should accept required alt text prop', () => {
|
|
27
|
-
const alt = 'Descriptive alt text';
|
|
28
|
-
expect(typeof alt).toBe('string');
|
|
29
|
-
expect(alt.length).toBeGreaterThan(0);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('should accept optional caption prop', () => {
|
|
33
|
-
const caption = 'Image caption';
|
|
34
|
-
expect(typeof caption).toBe('string');
|
|
35
|
-
expect(caption).toBeTruthy();
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('should accept optional width and height props', () => {
|
|
39
|
-
const width = 800;
|
|
40
|
-
const height = 600;
|
|
41
|
-
expect(typeof width).toBe('number');
|
|
42
|
-
expect(typeof height).toBe('number');
|
|
43
|
-
expect(width).toBeGreaterThan(0);
|
|
44
|
-
expect(height).toBeGreaterThan(0);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('should have zoomable enabled by default', () => {
|
|
48
|
-
const zoomable = true;
|
|
49
|
-
expect(zoomable).toBe(true);
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
describe('Functionality', () => {
|
|
54
|
-
it('should support zoom functionality when enabled', () => {
|
|
55
|
-
const zoomable = true;
|
|
56
|
-
const isZoomed = false;
|
|
57
|
-
expect(zoomable).toBe(true);
|
|
58
|
-
expect(typeof isZoomed).toBe('boolean');
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('should handle Escape key to close zoom', () => {
|
|
62
|
-
const key = 'Escape';
|
|
63
|
-
expect(['Escape', 'Enter', ' ']).toContain(key);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('should display caption with image', () => {
|
|
67
|
-
const props = {
|
|
68
|
-
src: 'test.jpg',
|
|
69
|
-
alt: 'Test',
|
|
70
|
-
caption: 'This is a caption'
|
|
71
|
-
};
|
|
72
|
-
expect(props.caption).toBeDefined();
|
|
73
|
-
expect(props.caption).toBeTruthy();
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('should be accessible with proper alt text', () => {
|
|
77
|
-
const alt = 'Important diagram showing architecture';
|
|
78
|
-
expect(alt.length).toBeGreaterThan(10);
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
});
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { theme } from '$lib/stores/theme';
|
|
3
|
-
import { sidebarOpen } from '$lib/stores/nav';
|
|
4
|
-
import { version } from '$lib/stores/version';
|
|
5
|
-
import { i18n } from '$lib/stores/i18n';
|
|
6
|
-
import { onMount } from 'svelte';
|
|
7
|
-
|
|
8
|
-
let {
|
|
9
|
-
title = 'Docs',
|
|
10
|
-
logo = null,
|
|
11
|
-
onLogoClick = () => {},
|
|
12
|
-
onVersionChange = (ver: string) => {},
|
|
13
|
-
onLanguageChange = (lang: string) => {},
|
|
14
|
-
}: {
|
|
15
|
-
title?: string;
|
|
16
|
-
logo?: string | null;
|
|
17
|
-
onLogoClick?: () => void;
|
|
18
|
-
onVersionChange?: (version: string) => void;
|
|
19
|
-
onLanguageChange?: (language: string) => void;
|
|
20
|
-
} = $props();
|
|
21
|
-
|
|
22
|
-
let isDark = $derived($theme === 'dark');
|
|
23
|
-
let currentVersion = $derived.by(() => $version.current);
|
|
24
|
-
let currentLanguage = $derived.by(() => $i18n.currentLanguage);
|
|
25
|
-
let availableVersions = $derived.by(() => $version.availableVersions);
|
|
26
|
-
let availableLanguages = $derived.by(() => $i18n.availableLanguages);
|
|
27
|
-
let isMounted = $state(false);
|
|
28
|
-
|
|
29
|
-
onMount(() => {
|
|
30
|
-
isMounted = true;
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
function toggleTheme() {
|
|
34
|
-
theme.toggle();
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function toggleSidebar() {
|
|
38
|
-
sidebarOpen.update(v => !v);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function handleVersionChange(e: Event) {
|
|
42
|
-
const select = e.target as HTMLSelectElement;
|
|
43
|
-
const newVersion = select.value;
|
|
44
|
-
version.setVersion(newVersion);
|
|
45
|
-
onVersionChange(newVersion);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function handleLanguageChange(e: Event) {
|
|
49
|
-
const select = e.target as HTMLSelectElement;
|
|
50
|
-
const newLanguage = select.value;
|
|
51
|
-
i18n.setLanguage(newLanguage as any);
|
|
52
|
-
onLanguageChange(newLanguage);
|
|
53
|
-
}
|
|
54
|
-
</script>
|
|
55
|
-
|
|
56
|
-
<nav class="sticky top-0 z-40 border-b border-claude-border dark:border-claude-dark-border bg-white dark:bg-claude-dark-bg-secondary backdrop-blur-sm">
|
|
57
|
-
<div class="doc-container flex items-center justify-between h-16 px-4 sm:px-6">
|
|
58
|
-
<!-- Logo / Brand -->
|
|
59
|
-
<button
|
|
60
|
-
onclick={onLogoClick}
|
|
61
|
-
class="flex items-center gap-2 font-semibold text-lg text-claude-text dark:text-claude-dark-text hover:text-claude-accent dark:hover:text-claude-dark-accent transition-colors"
|
|
62
|
-
aria-label="Home"
|
|
63
|
-
>
|
|
64
|
-
{#if logo}
|
|
65
|
-
<img src={logo} alt="Logo" class="h-8 w-8" />
|
|
66
|
-
{/if}
|
|
67
|
-
<span>{title}</span>
|
|
68
|
-
</button>
|
|
69
|
-
|
|
70
|
-
<!-- Mobile Menu Button -->
|
|
71
|
-
<button
|
|
72
|
-
onclick={toggleSidebar}
|
|
73
|
-
class="md:hidden p-2 hover:bg-claude-bg-secondary dark:hover:bg-claude-dark-bg rounded-lg transition-colors"
|
|
74
|
-
aria-label="Toggle menu"
|
|
75
|
-
>
|
|
76
|
-
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
77
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
|
|
78
|
-
</svg>
|
|
79
|
-
</button>
|
|
80
|
-
|
|
81
|
-
<!-- Right Section: Language, Version, Theme Toggle -->
|
|
82
|
-
<div class="hidden md:flex items-center gap-4">
|
|
83
|
-
<!-- Language Switcher -->
|
|
84
|
-
{#if isMounted && availableLanguages.length > 0}
|
|
85
|
-
<select
|
|
86
|
-
value={currentLanguage}
|
|
87
|
-
onchange={handleLanguageChange}
|
|
88
|
-
class="px-3 py-2 rounded-lg bg-claude-bg-secondary dark:bg-claude-dark-bg border border-claude-border dark:border-claude-dark-border text-claude-text dark:text-claude-dark-text text-sm cursor-pointer hover:border-claude-accent dark:hover:border-claude-dark-accent transition-colors"
|
|
89
|
-
aria-label="Select language"
|
|
90
|
-
>
|
|
91
|
-
{#each availableLanguages as lang (lang.code)}
|
|
92
|
-
<option value={lang.code}>
|
|
93
|
-
{lang.label}
|
|
94
|
-
</option>
|
|
95
|
-
{/each}
|
|
96
|
-
</select>
|
|
97
|
-
{/if}
|
|
98
|
-
|
|
99
|
-
<!-- Version Switcher -->
|
|
100
|
-
{#if isMounted && availableVersions.length > 0}
|
|
101
|
-
<select
|
|
102
|
-
value={currentVersion}
|
|
103
|
-
onchange={handleVersionChange}
|
|
104
|
-
class="px-3 py-2 rounded-lg bg-claude-bg-secondary dark:bg-claude-dark-bg border border-claude-border dark:border-claude-dark-border text-claude-text dark:text-claude-dark-text text-sm cursor-pointer hover:border-claude-accent dark:hover:border-claude-dark-accent transition-colors"
|
|
105
|
-
aria-label="Select version"
|
|
106
|
-
>
|
|
107
|
-
{#each availableVersions as ver (ver.version)}
|
|
108
|
-
<option value={ver.version}>
|
|
109
|
-
{ver.label}
|
|
110
|
-
</option>
|
|
111
|
-
{/each}
|
|
112
|
-
</select>
|
|
113
|
-
{/if}
|
|
114
|
-
|
|
115
|
-
<!-- Dark Mode Toggle -->
|
|
116
|
-
<button
|
|
117
|
-
onclick={toggleTheme}
|
|
118
|
-
class="p-2 rounded-lg bg-claude-bg-secondary dark:bg-claude-dark-bg border border-claude-border dark:border-claude-dark-border hover:border-claude-accent dark:hover:border-claude-dark-accent transition-colors"
|
|
119
|
-
aria-label="Toggle dark mode"
|
|
120
|
-
>
|
|
121
|
-
{#if isDark}
|
|
122
|
-
<!-- Moon Icon -->
|
|
123
|
-
<svg class="w-5 h-5 text-claude-accent dark:text-claude-dark-accent" fill="currentColor" viewBox="0 0 20 20">
|
|
124
|
-
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" />
|
|
125
|
-
</svg>
|
|
126
|
-
{:else}
|
|
127
|
-
<!-- Sun Icon -->
|
|
128
|
-
<svg class="w-5 h-5 text-claude-accent" fill="currentColor" viewBox="0 0 20 20">
|
|
129
|
-
<path fill-rule="evenodd" d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4.323 2.323a1 1 0 011.414 0l.707.707a1 1 0 11-1.414 1.414l-.707-.707a1 1 0 010-1.414zm2.828 2.828a1 1 0 011.414 0l.707.707a1 1 0 11-1.414 1.414l-.707-.707a1 1 0 010-1.414zm2.828 2.828a1 1 0 011.414 0l.707.707a1 1 0 11-1.414 1.414l-.707-.707a1 1 0 010-1.414zM10 11a1 1 0 110 2 1 1 0 010-2zm4.464-1.465a1 1 0 111.414-1.414l.707.707a1 1 0 11-1.414 1.414l-.707-.707zm2.828 2.828a1 1 0 111.414-1.414l.707.707a1 1 0 11-1.414 1.414l-.707-.707zm2.828 2.828a1 1 0 111.414-1.414l.707.707a1 1 0 11-1.414 1.414l-.707-.707zM10 18a1 1 0 110-2 1 1 0 010 2zm-4.464-1.465a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 1.414l-.707.707zm-2.828-2.828a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 1.414l-.707.707zm-2.828-2.828a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 1.414l-.707.707z" clip-rule="evenodd" />
|
|
130
|
-
</svg>
|
|
131
|
-
{/if}
|
|
132
|
-
</button>
|
|
133
|
-
</div>
|
|
134
|
-
</div>
|
|
135
|
-
</nav>
|
|
136
|
-
|
|
137
|
-
<style>
|
|
138
|
-
:global(html.dark nav) {
|
|
139
|
-
background-color: #0f0f0f;
|
|
140
|
-
}
|
|
141
|
-
</style>
|
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { onMount } from 'svelte';
|
|
3
|
-
import {
|
|
4
|
-
query,
|
|
5
|
-
results,
|
|
6
|
-
loading,
|
|
7
|
-
resultCount,
|
|
8
|
-
initPagefind,
|
|
9
|
-
updateSearch,
|
|
10
|
-
clearSearch
|
|
11
|
-
} from '$lib/stores/search';
|
|
12
|
-
import { highlightSearchTerms, extractExcerpt } from '$lib/utils/highlight';
|
|
13
|
-
|
|
14
|
-
interface Props {
|
|
15
|
-
showResults?: boolean;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
let { showResults = true }: Props = $props();
|
|
19
|
-
|
|
20
|
-
let searchInput: HTMLInputElement | undefined;
|
|
21
|
-
let isInitialized = $state(false);
|
|
22
|
-
let searchError = $state<string | null>(null);
|
|
23
|
-
let isDropdownOpen = $state(false);
|
|
24
|
-
|
|
25
|
-
onMount(async () => {
|
|
26
|
-
try {
|
|
27
|
-
await initPagefind();
|
|
28
|
-
isInitialized = true;
|
|
29
|
-
} catch (error) {
|
|
30
|
-
console.error('Failed to initialize search:', error);
|
|
31
|
-
searchError = 'Failed to initialize search';
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
async function handleSearch(e: Event) {
|
|
36
|
-
const target = e.target as HTMLInputElement;
|
|
37
|
-
const searchQuery = target.value;
|
|
38
|
-
|
|
39
|
-
try {
|
|
40
|
-
searchError = null;
|
|
41
|
-
await updateSearch(searchQuery);
|
|
42
|
-
} catch (error) {
|
|
43
|
-
console.error('Search error:', error);
|
|
44
|
-
searchError = 'Search failed. Please try again.';
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function handleClear() {
|
|
49
|
-
clearSearch();
|
|
50
|
-
if (searchInput) {
|
|
51
|
-
searchInput.focus();
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function handleKeyDown(e: KeyboardEvent) {
|
|
56
|
-
if (e.key === 'Escape') {
|
|
57
|
-
handleClear();
|
|
58
|
-
isDropdownOpen = false;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function handleFocus() {
|
|
63
|
-
isDropdownOpen = true;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function handleBlur(e: FocusEvent) {
|
|
67
|
-
// Only close dropdown if focus moves outside the search container
|
|
68
|
-
const target = e.relatedTarget as HTMLElement;
|
|
69
|
-
if (!target || !target.closest('[data-search-container]')) {
|
|
70
|
-
setTimeout(() => {
|
|
71
|
-
isDropdownOpen = false;
|
|
72
|
-
}, 100);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
</script>
|
|
76
|
-
|
|
77
|
-
<div class="relative w-full" data-search-container>
|
|
78
|
-
<!-- Search Input -->
|
|
79
|
-
<div class="relative">
|
|
80
|
-
<input
|
|
81
|
-
bind:this={searchInput}
|
|
82
|
-
type="text"
|
|
83
|
-
placeholder="Search documentation..."
|
|
84
|
-
value={$query}
|
|
85
|
-
oninput={handleSearch}
|
|
86
|
-
onkeydown={handleKeyDown}
|
|
87
|
-
onfocus={handleFocus}
|
|
88
|
-
onblur={handleBlur}
|
|
89
|
-
disabled={!isInitialized}
|
|
90
|
-
class="w-full rounded-lg border border-gray-300 bg-white px-4 py-2 pl-10 text-sm text-gray-900 placeholder-gray-500 focus:border-blue-500 focus:ring-1 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100 dark:placeholder-gray-400 disabled:opacity-50 transition-all"
|
|
91
|
-
aria-label="Search documentation"
|
|
92
|
-
/>
|
|
93
|
-
|
|
94
|
-
<!-- Search Icon -->
|
|
95
|
-
<div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
|
|
96
|
-
{#if $loading}
|
|
97
|
-
<svg
|
|
98
|
-
class="h-4 w-4 animate-spin text-gray-400"
|
|
99
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
100
|
-
fill="none"
|
|
101
|
-
viewBox="0 0 24 24"
|
|
102
|
-
>
|
|
103
|
-
<circle
|
|
104
|
-
class="opacity-25"
|
|
105
|
-
cx="12"
|
|
106
|
-
cy="12"
|
|
107
|
-
r="10"
|
|
108
|
-
stroke="currentColor"
|
|
109
|
-
stroke-width="4"
|
|
110
|
-
></circle>
|
|
111
|
-
<path
|
|
112
|
-
class="opacity-75"
|
|
113
|
-
fill="currentColor"
|
|
114
|
-
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
115
|
-
></path>
|
|
116
|
-
</svg>
|
|
117
|
-
{:else}
|
|
118
|
-
<svg
|
|
119
|
-
class="h-4 w-4 text-gray-400"
|
|
120
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
121
|
-
fill="none"
|
|
122
|
-
viewBox="0 0 24 24"
|
|
123
|
-
stroke="currentColor"
|
|
124
|
-
>
|
|
125
|
-
<path
|
|
126
|
-
stroke-linecap="round"
|
|
127
|
-
stroke-linejoin="round"
|
|
128
|
-
stroke-width="2"
|
|
129
|
-
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
|
130
|
-
/>
|
|
131
|
-
</svg>
|
|
132
|
-
{/if}
|
|
133
|
-
</div>
|
|
134
|
-
|
|
135
|
-
<!-- Clear Button -->
|
|
136
|
-
{#if $query}
|
|
137
|
-
<button
|
|
138
|
-
onclick={handleClear}
|
|
139
|
-
class="absolute inset-y-0 right-0 pr-3 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
|
|
140
|
-
aria-label="Clear search"
|
|
141
|
-
>
|
|
142
|
-
<svg class="h-4 w-4" fill="currentColor" viewBox="0 0 20 20">
|
|
143
|
-
<path
|
|
144
|
-
fill-rule="evenodd"
|
|
145
|
-
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
|
|
146
|
-
clip-rule="evenodd"
|
|
147
|
-
/>
|
|
148
|
-
</svg>
|
|
149
|
-
</button>
|
|
150
|
-
{/if}
|
|
151
|
-
</div>
|
|
152
|
-
|
|
153
|
-
<!-- Error Message -->
|
|
154
|
-
{#if searchError}
|
|
155
|
-
<div class="mt-2 rounded-lg bg-red-50 p-3 text-sm text-red-700 dark:bg-red-900/20 dark:text-red-400">
|
|
156
|
-
{searchError}
|
|
157
|
-
</div>
|
|
158
|
-
{/if}
|
|
159
|
-
|
|
160
|
-
<!-- Search Results -->
|
|
161
|
-
{#if showResults && isDropdownOpen && ($query || $results.length > 0)}
|
|
162
|
-
<div class="absolute top-full left-0 right-0 mt-2 max-h-96 overflow-y-auto rounded-lg border border-gray-300 bg-white shadow-lg dark:border-gray-600 dark:bg-gray-800 z-50">
|
|
163
|
-
{#if $loading}
|
|
164
|
-
<div class="px-4 py-8 text-center text-gray-500 dark:text-gray-400">
|
|
165
|
-
<div class="inline-block">
|
|
166
|
-
<svg
|
|
167
|
-
class="h-5 w-5 animate-spin"
|
|
168
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
169
|
-
fill="none"
|
|
170
|
-
viewBox="0 0 24 24"
|
|
171
|
-
>
|
|
172
|
-
<circle
|
|
173
|
-
class="opacity-25"
|
|
174
|
-
cx="12"
|
|
175
|
-
cy="12"
|
|
176
|
-
r="10"
|
|
177
|
-
stroke="currentColor"
|
|
178
|
-
stroke-width="4"
|
|
179
|
-
></circle>
|
|
180
|
-
<path
|
|
181
|
-
class="opacity-75"
|
|
182
|
-
fill="currentColor"
|
|
183
|
-
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
184
|
-
></path>
|
|
185
|
-
</svg>
|
|
186
|
-
</div>
|
|
187
|
-
</div>
|
|
188
|
-
{:else if $results.length === 0 && $query}
|
|
189
|
-
<div class="px-4 py-8 text-center text-gray-500 dark:text-gray-400">
|
|
190
|
-
No results found for "<strong>{$query}</strong>"
|
|
191
|
-
</div>
|
|
192
|
-
{:else if $results.length > 0}
|
|
193
|
-
<div class="divide-y divide-gray-200 dark:divide-gray-700">
|
|
194
|
-
{#each $results as result (result.id)}
|
|
195
|
-
<a
|
|
196
|
-
href={result.url}
|
|
197
|
-
class="block px-4 py-3 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
|
|
198
|
-
>
|
|
199
|
-
<div class="font-semibold text-gray-900 dark:text-gray-100">
|
|
200
|
-
{@html highlightSearchTerms(result.title, $query)}
|
|
201
|
-
</div>
|
|
202
|
-
{#if result.excerpt || result.content}
|
|
203
|
-
<div class="mt-1 text-sm text-gray-600 dark:text-gray-400 line-clamp-2">
|
|
204
|
-
{@html highlightSearchTerms(
|
|
205
|
-
extractExcerpt(result.content || result.excerpt || '', $query, 200),
|
|
206
|
-
$query
|
|
207
|
-
)}
|
|
208
|
-
</div>
|
|
209
|
-
{/if}
|
|
210
|
-
<div class="mt-2 text-xs text-gray-500 dark:text-gray-500">
|
|
211
|
-
{result.url}
|
|
212
|
-
</div>
|
|
213
|
-
</a>
|
|
214
|
-
{/each}
|
|
215
|
-
</div>
|
|
216
|
-
|
|
217
|
-
{#if $resultCount > 0}
|
|
218
|
-
<div class="border-t border-gray-200 bg-gray-50 px-4 py-2 text-xs text-gray-600 dark:border-gray-700 dark:bg-gray-700/50 dark:text-gray-400">
|
|
219
|
-
{$resultCount} result{$resultCount !== 1 ? 's' : ''} found
|
|
220
|
-
</div>
|
|
221
|
-
{/if}
|
|
222
|
-
{/if}
|
|
223
|
-
</div>
|
|
224
|
-
{/if}
|
|
225
|
-
</div>
|
|
226
|
-
|
|
227
|
-
<style>
|
|
228
|
-
:global(.line-clamp-2) {
|
|
229
|
-
display: -webkit-box;
|
|
230
|
-
-webkit-line-clamp: 2;
|
|
231
|
-
-webkit-box-orient: vertical;
|
|
232
|
-
line-clamp: 2;
|
|
233
|
-
overflow: hidden;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
:global(mark) {
|
|
237
|
-
background-color: #fef3c7;
|
|
238
|
-
color: #92400e;
|
|
239
|
-
font-weight: 500;
|
|
240
|
-
padding: 0 0.125rem;
|
|
241
|
-
border-radius: 0.125rem;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
:global(.dark mark) {
|
|
245
|
-
background-color: #78350f;
|
|
246
|
-
color: #fef3c7;
|
|
247
|
-
}
|
|
248
|
-
</style>
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
/**
|
|
3
|
-
* Tabs component for switching between content panels
|
|
4
|
-
* Usage:
|
|
5
|
-
* <Tabs items={[{label: 'Tab 1', content: 'Content 1'}]} />
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
interface TabItem {
|
|
9
|
-
label: string;
|
|
10
|
-
content?: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
interface Props {
|
|
14
|
-
items: TabItem[];
|
|
15
|
-
defaultIndex?: number;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
let { items, defaultIndex = 0 }: Props = $props();
|
|
19
|
-
|
|
20
|
-
let activeIndex = $state(0);
|
|
21
|
-
|
|
22
|
-
$effect(() => {
|
|
23
|
-
activeIndex = defaultIndex;
|
|
24
|
-
});
|
|
25
|
-
</script>
|
|
26
|
-
|
|
27
|
-
<div class="my-4">
|
|
28
|
-
<div class="flex border-b border-gray-200 dark:border-gray-700">
|
|
29
|
-
{#each items as item, index (index)}
|
|
30
|
-
<button
|
|
31
|
-
onclick={() => (activeIndex = index)}
|
|
32
|
-
class="px-4 py-2 font-medium transition-colors {activeIndex === index
|
|
33
|
-
? 'border-b-2 border-blue-500 text-blue-600 dark:text-blue-400'
|
|
34
|
-
: 'text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100'}"
|
|
35
|
-
>
|
|
36
|
-
{item.label}
|
|
37
|
-
</button>
|
|
38
|
-
{/each}
|
|
39
|
-
</div>
|
|
40
|
-
|
|
41
|
-
<div class="mt-4 rounded-b-lg bg-gray-50 p-4 dark:bg-gray-900/20">
|
|
42
|
-
{#if items[activeIndex]?.content}
|
|
43
|
-
<div class="prose dark:prose-invert">
|
|
44
|
-
{@html items[activeIndex].content}
|
|
45
|
-
</div>
|
|
46
|
-
{/if}
|
|
47
|
-
</div>
|
|
48
|
-
</div>
|