yaxa-svelte 1.0.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/LICENSE +21 -0
- package/README.md +163 -0
- package/dist/assets/favicon.svg +15 -0
- package/dist/components/elements/Avatar.svelte +106 -0
- package/dist/components/elements/Avatar.svelte.d.ts +40 -0
- package/dist/components/elements/AvatarGroup.svelte +18 -0
- package/dist/components/elements/AvatarGroup.svelte.d.ts +8 -0
- package/dist/components/elements/Badge.svelte +202 -0
- package/dist/components/elements/Badge.svelte.d.ts +75 -0
- package/dist/components/elements/Button.svelte +300 -0
- package/dist/components/elements/Button.svelte.d.ts +109 -0
- package/dist/components/elements/ButtonGroup.svelte +22 -0
- package/dist/components/elements/ButtonGroup.svelte.d.ts +9 -0
- package/dist/components/elements/Chip.svelte +117 -0
- package/dist/components/elements/Chip.svelte.d.ts +15 -0
- package/dist/components/elements/DataTable.svelte +222 -0
- package/dist/components/elements/DataTable.svelte.d.ts +43 -0
- package/dist/components/elements/Icon.svelte +87 -0
- package/dist/components/elements/Icon.svelte.d.ts +10 -0
- package/dist/components/elements/Kbd.svelte +37 -0
- package/dist/components/elements/Kbd.svelte.d.ts +32 -0
- package/dist/components/elements/Link.svelte +63 -0
- package/dist/components/elements/Link.svelte.d.ts +15 -0
- package/dist/components/elements/Logo.svelte +77 -0
- package/dist/components/elements/Logo.svelte.d.ts +9 -0
- package/dist/components/elements/Meter.svelte +87 -0
- package/dist/components/elements/Meter.svelte.d.ts +14 -0
- package/dist/components/elements/Progress.svelte +63 -0
- package/dist/components/elements/Progress.svelte.d.ts +49 -0
- package/dist/components/elements/Skeleton.svelte +12 -0
- package/dist/components/elements/Skeleton.svelte.d.ts +6 -0
- package/dist/components/elements/Spinner.svelte +39 -0
- package/dist/components/elements/Spinner.svelte.d.ts +7 -0
- package/dist/components/forms/Checkbox.svelte +77 -0
- package/dist/components/forms/Checkbox.svelte.d.ts +17 -0
- package/dist/components/forms/ColorPicker.svelte +142 -0
- package/dist/components/forms/ColorPicker.svelte.d.ts +10 -0
- package/dist/components/forms/Form.svelte +84 -0
- package/dist/components/forms/Form.svelte.d.ts +14 -0
- package/dist/components/forms/FormField.svelte +56 -0
- package/dist/components/forms/FormField.svelte.d.ts +14 -0
- package/dist/components/forms/Input.svelte +138 -0
- package/dist/components/forms/Input.svelte.d.ts +58 -0
- package/dist/components/forms/RadioGroup.svelte +74 -0
- package/dist/components/forms/RadioGroup.svelte.d.ts +17 -0
- package/dist/components/forms/Select.svelte +91 -0
- package/dist/components/forms/Select.svelte.d.ts +50 -0
- package/dist/components/forms/Slider.svelte +37 -0
- package/dist/components/forms/Slider.svelte.d.ts +12 -0
- package/dist/components/forms/Switch.svelte +81 -0
- package/dist/components/forms/Switch.svelte.d.ts +53 -0
- package/dist/components/forms/Textarea.svelte +73 -0
- package/dist/components/forms/Textarea.svelte.d.ts +64 -0
- package/dist/components/layout/Card.svelte +89 -0
- package/dist/components/layout/Card.svelte.d.ts +64 -0
- package/dist/components/layout/Container.svelte +36 -0
- package/dist/components/layout/Container.svelte.d.ts +37 -0
- package/dist/components/layout/Divider.svelte +45 -0
- package/dist/components/layout/Divider.svelte.d.ts +11 -0
- package/dist/components/layout/Footer.svelte +96 -0
- package/dist/components/layout/Footer.svelte.d.ts +10 -0
- package/dist/components/layout/Header.svelte +175 -0
- package/dist/components/layout/Header.svelte.d.ts +12 -0
- package/dist/components/layout/Section.svelte +62 -0
- package/dist/components/layout/Section.svelte.d.ts +14 -0
- package/dist/components/layout/YaxaApp.svelte +48 -0
- package/dist/components/layout/YaxaApp.svelte.d.ts +12 -0
- package/dist/components/navigation/Breadcrumb.svelte +58 -0
- package/dist/components/navigation/Breadcrumb.svelte.d.ts +13 -0
- package/dist/components/navigation/CommandPalette.svelte +201 -0
- package/dist/components/navigation/CommandPalette.svelte.d.ts +19 -0
- package/dist/components/navigation/DropdownMenu.svelte +75 -0
- package/dist/components/navigation/DropdownMenu.svelte.d.ts +20 -0
- package/dist/components/navigation/Pagination.svelte +106 -0
- package/dist/components/navigation/Pagination.svelte.d.ts +10 -0
- package/dist/components/navigation/Tabs.svelte +91 -0
- package/dist/components/navigation/Tabs.svelte.d.ts +18 -0
- package/dist/components/overlays/Accordion.svelte +54 -0
- package/dist/components/overlays/Accordion.svelte.d.ts +16 -0
- package/dist/components/overlays/Alert.svelte +110 -0
- package/dist/components/overlays/Alert.svelte.d.ts +37 -0
- package/dist/components/overlays/ContextMenu.svelte +67 -0
- package/dist/components/overlays/ContextMenu.svelte.d.ts +21 -0
- package/dist/components/overlays/Modal.svelte +99 -0
- package/dist/components/overlays/Modal.svelte.d.ts +40 -0
- package/dist/components/overlays/Popover.svelte +33 -0
- package/dist/components/overlays/Popover.svelte.d.ts +11 -0
- package/dist/components/overlays/Slideover.svelte +102 -0
- package/dist/components/overlays/Slideover.svelte.d.ts +37 -0
- package/dist/components/overlays/Tooltip.svelte +39 -0
- package/dist/components/overlays/Tooltip.svelte.d.ts +12 -0
- package/dist/components/saas/AuthCard.svelte +273 -0
- package/dist/components/saas/AuthCard.svelte.d.ts +16 -0
- package/dist/components/saas/PricingCard.svelte +166 -0
- package/dist/components/saas/PricingCard.svelte.d.ts +19 -0
- package/dist/components/saas/PricingTable.svelte +139 -0
- package/dist/components/saas/PricingTable.svelte.d.ts +11 -0
- package/dist/components/saas/SubscriptionCard.svelte +162 -0
- package/dist/components/saas/SubscriptionCard.svelte.d.ts +16 -0
- package/dist/components/saas/UserMenu.svelte +137 -0
- package/dist/components/saas/UserMenu.svelte.d.ts +19 -0
- package/dist/components/seo/Favicons.svelte +22 -0
- package/dist/components/seo/Favicons.svelte.d.ts +8 -0
- package/dist/components/seo/OgImage.svelte +61 -0
- package/dist/components/seo/OgImage.svelte.d.ts +12 -0
- package/dist/components/seo/Seo.svelte +170 -0
- package/dist/components/seo/Seo.svelte.d.ts +21 -0
- package/dist/composables/useAuth.svelte.d.ts +23 -0
- package/dist/composables/useAuth.svelte.js +157 -0
- package/dist/composables/useClipboard.svelte.d.ts +9 -0
- package/dist/composables/useClipboard.svelte.js +36 -0
- package/dist/composables/useColorMode.svelte.d.ts +8 -0
- package/dist/composables/useColorMode.svelte.js +20 -0
- package/dist/composables/useDebounce.svelte.d.ts +3 -0
- package/dist/composables/useDebounce.svelte.js +17 -0
- package/dist/composables/useMediaQuery.svelte.d.ts +3 -0
- package/dist/composables/useMediaQuery.svelte.js +17 -0
- package/dist/composables/useShortcuts.svelte.d.ts +10 -0
- package/dist/composables/useShortcuts.svelte.js +50 -0
- package/dist/composables/useToast.d.ts +19 -0
- package/dist/composables/useToast.js +34 -0
- package/dist/index.d.ts +101 -0
- package/dist/index.js +92 -0
- package/dist/server/auth/hook.d.ts +14 -0
- package/dist/server/auth/hook.js +36 -0
- package/dist/server/auth/index.d.ts +39 -0
- package/dist/server/auth/index.js +69 -0
- package/dist/server/db/index.d.ts +18 -0
- package/dist/server/db/index.js +43 -0
- package/dist/server/db/schema-pg.d.ts +977 -0
- package/dist/server/db/schema-pg.js +83 -0
- package/dist/server/db/schema-sqlite.d.ts +1045 -0
- package/dist/server/db/schema-sqlite.js +83 -0
- package/dist/server/db/types.d.ts +44 -0
- package/dist/server/db/types.js +1 -0
- package/dist/server/email/index.d.ts +27 -0
- package/dist/server/email/index.js +79 -0
- package/dist/server/polar/index.d.ts +29 -0
- package/dist/server/polar/index.js +49 -0
- package/dist/server/polar/webhook.d.ts +16 -0
- package/dist/server/polar/webhook.js +118 -0
- package/dist/site/config.d.ts +63 -0
- package/dist/site/config.js +48 -0
- package/dist/site/context.d.ts +11 -0
- package/dist/site/context.js +23 -0
- package/dist/site/hook.d.ts +15 -0
- package/dist/site/hook.js +38 -0
- package/dist/site/manifest.d.ts +6 -0
- package/dist/site/manifest.js +32 -0
- package/dist/site/og.d.ts +14 -0
- package/dist/site/og.js +116 -0
- package/dist/site/robots.d.ts +10 -0
- package/dist/site/robots.js +54 -0
- package/dist/site/schema.d.ts +67 -0
- package/dist/site/schema.js +67 -0
- package/dist/site/seo-helpers.d.ts +36 -0
- package/dist/site/seo-helpers.js +21 -0
- package/dist/site/sitemap-xsl.d.ts +6 -0
- package/dist/site/sitemap-xsl.js +164 -0
- package/dist/site/sitemap.d.ts +20 -0
- package/dist/site/sitemap.js +61 -0
- package/dist/styles/yaxa.css +84 -0
- package/dist/theme/theme.svelte.d.ts +74 -0
- package/dist/theme/theme.svelte.js +421 -0
- package/dist/utils/cn.d.ts +3 -0
- package/dist/utils/cn.js +3 -0
- package/dist/vite/index.d.ts +20 -0
- package/dist/vite/index.js +29 -0
- package/package.json +108 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { DEFAULT_SITE_CONFIG } from './config';
|
|
2
|
+
export function createManifestHandler(optionsOrConfig) {
|
|
3
|
+
const config = !optionsOrConfig
|
|
4
|
+
? DEFAULT_SITE_CONFIG
|
|
5
|
+
: 'name' in optionsOrConfig
|
|
6
|
+
? optionsOrConfig
|
|
7
|
+
: optionsOrConfig.config || DEFAULT_SITE_CONFIG;
|
|
8
|
+
return async () => {
|
|
9
|
+
const manifest = {
|
|
10
|
+
name: config.title || config.name,
|
|
11
|
+
short_name: config.name,
|
|
12
|
+
description: config.description,
|
|
13
|
+
start_url: '/',
|
|
14
|
+
display: 'standalone',
|
|
15
|
+
background_color: config.theme?.neutralColor || '#121212',
|
|
16
|
+
theme_color: config.theme?.primaryColor || '#ff3e00',
|
|
17
|
+
icons: [
|
|
18
|
+
{
|
|
19
|
+
src: '/favicon.svg',
|
|
20
|
+
sizes: 'any',
|
|
21
|
+
type: 'image/svg+xml'
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
};
|
|
25
|
+
return new Response(JSON.stringify(manifest, null, 2), {
|
|
26
|
+
headers: {
|
|
27
|
+
'Content-Type': 'application/manifest+json; charset=utf-8',
|
|
28
|
+
'Cache-Control': 'public, max-age=86400'
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { RequestHandler } from '@sveltejs/kit';
|
|
2
|
+
import type { SiteConfig } from './config';
|
|
3
|
+
export interface OgImageOptions {
|
|
4
|
+
config?: SiteConfig;
|
|
5
|
+
}
|
|
6
|
+
export declare function generateOgSvg(params: {
|
|
7
|
+
title: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
siteName?: string;
|
|
10
|
+
badge?: string;
|
|
11
|
+
theme?: 'dark' | 'light';
|
|
12
|
+
url?: string;
|
|
13
|
+
}): string;
|
|
14
|
+
export declare function createOgImageHandler(options?: OgImageOptions): RequestHandler;
|
package/dist/site/og.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
export function generateOgSvg(params) {
|
|
2
|
+
const isDark = params.theme !== 'light';
|
|
3
|
+
const bgGradientStart = isDark ? '#121212' : '#fafafa';
|
|
4
|
+
const bgGradientEnd = isDark ? '#1c1917' : '#f5f5f4';
|
|
5
|
+
const cardBg = isDark ? 'rgba(24, 24, 27, 0.85)' : 'rgba(255, 255, 255, 0.9)';
|
|
6
|
+
const cardBorder = isDark ? 'rgba(63, 63, 70, 0.5)' : 'rgba(228, 228, 231, 0.9)';
|
|
7
|
+
const titleColor = isDark ? '#fafafa' : '#09090b';
|
|
8
|
+
const descColor = isDark ? '#a1a1aa' : '#52525b';
|
|
9
|
+
const svelteFlame1 = '#ff3e00';
|
|
10
|
+
const svelteFlame2 = '#ea580c';
|
|
11
|
+
const metaColor = isDark ? '#71717a' : '#71717a';
|
|
12
|
+
// Escape XML characters
|
|
13
|
+
const escapeXml = (unsafe) => unsafe
|
|
14
|
+
.replace(/&/g, '&')
|
|
15
|
+
.replace(/</g, '<')
|
|
16
|
+
.replace(/>/g, '>')
|
|
17
|
+
.replace(/"/g, '"')
|
|
18
|
+
.replace(/'/g, ''');
|
|
19
|
+
const safeTitle = escapeXml(params.title || 'Welcome');
|
|
20
|
+
const safeDesc = escapeXml(params.description || 'Fast, beautiful, accessible web applications.');
|
|
21
|
+
const safeSiteName = escapeXml(params.siteName || 'Yaxa');
|
|
22
|
+
const safeBadge = params.badge ? escapeXml(params.badge) : null;
|
|
23
|
+
const safeUrl = escapeXml(params.url ? params.url.replace(/^https?:\/\//, '') : 'yaxa.dev');
|
|
24
|
+
return `<svg width="1200" height="630" viewBox="0 0 1200 630" xmlns="http://www.w3.org/2000/svg">
|
|
25
|
+
<defs>
|
|
26
|
+
<linearGradient id="bgGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
27
|
+
<stop offset="0%" stop-color="${bgGradientStart}"/>
|
|
28
|
+
<stop offset="100%" stop-color="${bgGradientEnd}"/>
|
|
29
|
+
</linearGradient>
|
|
30
|
+
<linearGradient id="brandGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
31
|
+
<stop offset="0%" stop-color="${svelteFlame1}"/>
|
|
32
|
+
<stop offset="100%" stop-color="${svelteFlame2}"/>
|
|
33
|
+
</linearGradient>
|
|
34
|
+
<linearGradient id="glowGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
35
|
+
<stop offset="0%" stop-color="${svelteFlame1}" stop-opacity="0.25"/>
|
|
36
|
+
<stop offset="100%" stop-color="${svelteFlame2}" stop-opacity="0.08"/>
|
|
37
|
+
</linearGradient>
|
|
38
|
+
<filter id="blurFilter" x="-20%" y="-20%" width="140%" height="140%">
|
|
39
|
+
<feGaussianBlur stdDeviation="80"/>
|
|
40
|
+
</filter>
|
|
41
|
+
</defs>
|
|
42
|
+
|
|
43
|
+
<!-- Background -->
|
|
44
|
+
<rect width="1200" height="630" fill="url(#bgGrad)"/>
|
|
45
|
+
|
|
46
|
+
<!-- Glowing Orbs -->
|
|
47
|
+
<circle cx="150" cy="120" r="280" fill="url(#glowGrad)" filter="url(#blurFilter)"/>
|
|
48
|
+
<circle cx="1050" cy="500" r="300" fill="url(#glowGrad)" filter="url(#blurFilter)"/>
|
|
49
|
+
|
|
50
|
+
<!-- Card Border and Container -->
|
|
51
|
+
<rect x="60" y="60" width="1080" height="510" rx="24" fill="${cardBg}" stroke="${cardBorder}" stroke-width="2"/>
|
|
52
|
+
|
|
53
|
+
<!-- Top Bar: Logo & Badge -->
|
|
54
|
+
<g transform="translate(120, 130)">
|
|
55
|
+
<!-- Yaxa Svelte-Style Dual-Tone X Ribbon Icon -->
|
|
56
|
+
<g transform="translate(0, -2) scale(0.44)">
|
|
57
|
+
<!-- Outer Flame Track -->
|
|
58
|
+
<path d="M24 24 L76 76" stroke="url(#brandGrad)" stroke-width="22" stroke-linecap="round"/>
|
|
59
|
+
<path d="M76 24 L56 44 M44 56 L24 76" stroke="url(#brandGrad)" stroke-width="22" stroke-linecap="round"/>
|
|
60
|
+
<!-- Inner White Core Track -->
|
|
61
|
+
<path d="M24 24 L76 76" stroke="#ffffff" stroke-width="8" stroke-linecap="round"/>
|
|
62
|
+
<path d="M76 24 L58 42 M42 58 L24 76" stroke="#ffffff" stroke-width="8" stroke-linecap="round"/>
|
|
63
|
+
</g>
|
|
64
|
+
|
|
65
|
+
<!-- Site Name -->
|
|
66
|
+
<text x="54" y="27" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" font-size="24" font-weight="700" fill="${titleColor}">${safeSiteName}</text>
|
|
67
|
+
|
|
68
|
+
<!-- Badge -->
|
|
69
|
+
${safeBadge
|
|
70
|
+
? `
|
|
71
|
+
<rect x="760" y="2" width="${safeBadge.length * 10 + 36}" height="32" rx="16" fill="rgba(255, 62, 0, 0.15)" stroke="rgba(255, 62, 0, 0.4)" stroke-width="1"/>
|
|
72
|
+
<text x="${760 + (safeBadge.length * 10 + 36) / 2}" y="23" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" font-size="14" font-weight="600" fill="#ff6a00" text-anchor="middle">${safeBadge}</text>
|
|
73
|
+
`
|
|
74
|
+
: ''}
|
|
75
|
+
</g>
|
|
76
|
+
|
|
77
|
+
<!-- Middle: Title & Description -->
|
|
78
|
+
<g transform="translate(120, 250)">
|
|
79
|
+
<text x="0" y="40" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" font-size="52" font-weight="800" fill="${titleColor}" letter-spacing="-0.03em">${safeTitle}</text>
|
|
80
|
+
<text x="0" y="110" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" font-size="24" font-weight="400" fill="${descColor}" width="840">${safeDesc}</text>
|
|
81
|
+
</g>
|
|
82
|
+
|
|
83
|
+
<!-- Bottom: Domain and Decorative Accent Line -->
|
|
84
|
+
<g transform="translate(120, 480)">
|
|
85
|
+
<line x1="0" y1="0" x2="840" y2="0" stroke="${cardBorder}" stroke-width="1"/>
|
|
86
|
+
<circle cx="6" cy="30" r="4" fill="${svelteFlame1}"/>
|
|
87
|
+
<text x="20" y="35" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" font-size="18" font-weight="500" fill="${metaColor}">${safeUrl}</text>
|
|
88
|
+
</g>
|
|
89
|
+
</svg>`;
|
|
90
|
+
}
|
|
91
|
+
export function createOgImageHandler(options) {
|
|
92
|
+
return async ({ url }) => {
|
|
93
|
+
const title = url.searchParams.get('title') || options?.config?.title || 'Yaxa';
|
|
94
|
+
const description = url.searchParams.get('description') ||
|
|
95
|
+
options?.config?.description ||
|
|
96
|
+
'Fast, beautiful, accessible UI components and SEO tools for SvelteKit.';
|
|
97
|
+
const badge = url.searchParams.get('badge') || undefined;
|
|
98
|
+
const theme = url.searchParams.get('theme') || 'dark';
|
|
99
|
+
const siteName = url.searchParams.get('site') || options?.config?.name || 'Yaxa';
|
|
100
|
+
const siteUrl = options?.config?.url || url.origin;
|
|
101
|
+
const svg = generateOgSvg({
|
|
102
|
+
title,
|
|
103
|
+
description,
|
|
104
|
+
siteName,
|
|
105
|
+
badge,
|
|
106
|
+
theme,
|
|
107
|
+
url: siteUrl
|
|
108
|
+
});
|
|
109
|
+
return new Response(svg, {
|
|
110
|
+
headers: {
|
|
111
|
+
'Content-Type': 'image/svg+xml; charset=utf-8',
|
|
112
|
+
'Cache-Control': 'public, max-age=86400, s-maxage=86400'
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
};
|
|
116
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { RequestHandler } from '@sveltejs/kit';
|
|
2
|
+
import type { SiteConfig } from './config';
|
|
3
|
+
export interface RobotsOptions {
|
|
4
|
+
config: SiteConfig;
|
|
5
|
+
/**
|
|
6
|
+
* Override environment detection. If true, allows indexing. If false, disallows indexing.
|
|
7
|
+
*/
|
|
8
|
+
isProduction?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function createRobotsHandler(optionsOrConfig: SiteConfig | RobotsOptions): RequestHandler;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export function createRobotsHandler(optionsOrConfig) {
|
|
2
|
+
const options = 'config' in optionsOrConfig ? optionsOrConfig : { config: optionsOrConfig };
|
|
3
|
+
const { config } = options;
|
|
4
|
+
return async ({ url }) => {
|
|
5
|
+
try {
|
|
6
|
+
const isProdEnv = typeof process !== 'undefined' && process.env?.NODE_ENV === 'production';
|
|
7
|
+
const isProd = options.isProduction ??
|
|
8
|
+
(isProdEnv &&
|
|
9
|
+
!url.hostname.includes('localhost') &&
|
|
10
|
+
!url.hostname.includes('vercel.app') &&
|
|
11
|
+
!url.hostname.includes('preview') &&
|
|
12
|
+
!url.hostname.includes('staging'));
|
|
13
|
+
const baseUrl = config?.url || url?.origin || 'https://yaxa.vercel.app';
|
|
14
|
+
let body;
|
|
15
|
+
if (!isProd && !options.isProduction) {
|
|
16
|
+
// Non-production or preview deployment: protect against indexing
|
|
17
|
+
body = `# Non-production environment: indexing disabled\nUser-agent: *\nDisallow: /\n`;
|
|
18
|
+
}
|
|
19
|
+
else if (config?.robots?.rules && config.robots.rules.length > 0) {
|
|
20
|
+
// Custom defined rules
|
|
21
|
+
body = config.robots.rules
|
|
22
|
+
.map((rule) => {
|
|
23
|
+
let ruleText = `User-agent: ${rule.userAgent}\n`;
|
|
24
|
+
if (rule.allow) {
|
|
25
|
+
ruleText += rule.allow.map((path) => `Allow: ${path}\n`).join('');
|
|
26
|
+
}
|
|
27
|
+
if (rule.disallow) {
|
|
28
|
+
ruleText += rule.disallow.map((path) => `Disallow: ${path}\n`).join('');
|
|
29
|
+
}
|
|
30
|
+
return ruleText;
|
|
31
|
+
})
|
|
32
|
+
.join('\n');
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
// Default production allow
|
|
36
|
+
body = `User-agent: *\nAllow: /\n`;
|
|
37
|
+
}
|
|
38
|
+
// Always append sitemap reference
|
|
39
|
+
body += `\nSitemap: ${baseUrl}/sitemap.xml\n`;
|
|
40
|
+
return new Response(body, {
|
|
41
|
+
headers: {
|
|
42
|
+
'Content-Type': 'text/plain; charset=utf-8',
|
|
43
|
+
'Cache-Control': 'public, max-age=86400'
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
console.error('robots.txt handler error:', err);
|
|
49
|
+
return new Response(`User-agent: *\nDisallow: /\n`, {
|
|
50
|
+
headers: { 'Content-Type': 'text/plain; charset=utf-8' }
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { SiteConfig } from './config';
|
|
2
|
+
export type SchemaType = 'WebSite' | 'Organization' | 'WebPage' | 'Article' | 'Product' | 'BreadcrumbList' | 'FAQPage';
|
|
3
|
+
export interface BreadcrumbItem {
|
|
4
|
+
name: string;
|
|
5
|
+
url: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ArticleSchemaData {
|
|
8
|
+
title: string;
|
|
9
|
+
description: string;
|
|
10
|
+
url: string;
|
|
11
|
+
datePublished: string;
|
|
12
|
+
dateModified?: string;
|
|
13
|
+
image?: string;
|
|
14
|
+
authorName?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function generateWebSiteSchema(config: SiteConfig): {
|
|
17
|
+
author?: {
|
|
18
|
+
'@type': string;
|
|
19
|
+
name: string;
|
|
20
|
+
url: string | undefined;
|
|
21
|
+
} | undefined;
|
|
22
|
+
'@context': string;
|
|
23
|
+
'@type': string;
|
|
24
|
+
name: string;
|
|
25
|
+
url: string;
|
|
26
|
+
description: string;
|
|
27
|
+
};
|
|
28
|
+
export declare function generateOrganizationSchema(config: SiteConfig): {
|
|
29
|
+
'@context': string;
|
|
30
|
+
'@type': string;
|
|
31
|
+
name: string;
|
|
32
|
+
url: string;
|
|
33
|
+
logo: string | undefined;
|
|
34
|
+
sameAs: (string | undefined)[];
|
|
35
|
+
};
|
|
36
|
+
export declare function generateArticleSchema(config: SiteConfig, article: ArticleSchemaData): {
|
|
37
|
+
'@context': string;
|
|
38
|
+
'@type': string;
|
|
39
|
+
headline: string;
|
|
40
|
+
description: string;
|
|
41
|
+
url: string;
|
|
42
|
+
datePublished: string;
|
|
43
|
+
dateModified: string;
|
|
44
|
+
image: string | undefined;
|
|
45
|
+
author: {
|
|
46
|
+
'@type': string;
|
|
47
|
+
name: string;
|
|
48
|
+
};
|
|
49
|
+
publisher: {
|
|
50
|
+
'@type': string;
|
|
51
|
+
name: string;
|
|
52
|
+
logo: {
|
|
53
|
+
'@type': string;
|
|
54
|
+
url: string;
|
|
55
|
+
} | undefined;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
export declare function generateBreadcrumbSchema(config: SiteConfig, items: BreadcrumbItem[]): {
|
|
59
|
+
'@context': string;
|
|
60
|
+
'@type': string;
|
|
61
|
+
itemListElement: {
|
|
62
|
+
'@type': string;
|
|
63
|
+
position: number;
|
|
64
|
+
name: string;
|
|
65
|
+
item: string;
|
|
66
|
+
}[];
|
|
67
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export function generateWebSiteSchema(config) {
|
|
2
|
+
return {
|
|
3
|
+
'@context': 'https://schema.org',
|
|
4
|
+
'@type': 'WebSite',
|
|
5
|
+
name: config.name,
|
|
6
|
+
url: config.url,
|
|
7
|
+
description: config.description,
|
|
8
|
+
...(config.author
|
|
9
|
+
? {
|
|
10
|
+
author: {
|
|
11
|
+
'@type': 'Person',
|
|
12
|
+
name: config.author.name,
|
|
13
|
+
url: config.author.url
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
: {})
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export function generateOrganizationSchema(config) {
|
|
20
|
+
return {
|
|
21
|
+
'@context': 'https://schema.org',
|
|
22
|
+
'@type': 'Organization',
|
|
23
|
+
name: config.name,
|
|
24
|
+
url: config.url,
|
|
25
|
+
logo: config.logo ? `${config.url}${config.logo}` : undefined,
|
|
26
|
+
sameAs: [
|
|
27
|
+
config.socials?.github,
|
|
28
|
+
config.socials?.twitter,
|
|
29
|
+
config.socials?.discord,
|
|
30
|
+
config.socials?.bluesky,
|
|
31
|
+
config.socials?.youtube
|
|
32
|
+
].filter(Boolean)
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export function generateArticleSchema(config, article) {
|
|
36
|
+
return {
|
|
37
|
+
'@context': 'https://schema.org',
|
|
38
|
+
'@type': 'Article',
|
|
39
|
+
headline: article.title,
|
|
40
|
+
description: article.description,
|
|
41
|
+
url: article.url,
|
|
42
|
+
datePublished: article.datePublished,
|
|
43
|
+
dateModified: article.dateModified || article.datePublished,
|
|
44
|
+
image: article.image,
|
|
45
|
+
author: {
|
|
46
|
+
'@type': 'Person',
|
|
47
|
+
name: article.authorName || config.author?.name || config.name
|
|
48
|
+
},
|
|
49
|
+
publisher: {
|
|
50
|
+
'@type': 'Organization',
|
|
51
|
+
name: config.name,
|
|
52
|
+
logo: config.logo ? { '@type': 'ImageObject', url: `${config.url}${config.logo}` } : undefined
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export function generateBreadcrumbSchema(config, items) {
|
|
57
|
+
return {
|
|
58
|
+
'@context': 'https://schema.org',
|
|
59
|
+
'@type': 'BreadcrumbList',
|
|
60
|
+
itemListElement: items.map((item, index) => ({
|
|
61
|
+
'@type': 'ListItem',
|
|
62
|
+
position: index + 1,
|
|
63
|
+
name: item.name,
|
|
64
|
+
item: item.url.startsWith('http') ? item.url : `${config.url}${item.url}`
|
|
65
|
+
}))
|
|
66
|
+
};
|
|
67
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface PageSeoConfig {
|
|
2
|
+
title: string;
|
|
3
|
+
description?: string;
|
|
4
|
+
canonical?: string;
|
|
5
|
+
badge?: string;
|
|
6
|
+
ogImage?: string | {
|
|
7
|
+
title?: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
badge?: string;
|
|
10
|
+
theme?: 'dark' | 'light';
|
|
11
|
+
};
|
|
12
|
+
twitterCard?: 'summary' | 'summary_large_image' | 'app' | 'player';
|
|
13
|
+
keywords?: string[];
|
|
14
|
+
noindex?: boolean;
|
|
15
|
+
nofollow?: boolean;
|
|
16
|
+
schema?: Record<string, unknown> | Record<string, unknown>[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Type-safe helper for SvelteKit load() functions to define page-level SEO.
|
|
20
|
+
* When returned inside { seo: definePageSeo(...) }, YaxaApp automatically
|
|
21
|
+
* extracts and binds all meta tags, OpenGraph cards, Twitter cards, and Schema.org data.
|
|
22
|
+
*
|
|
23
|
+
* Example:
|
|
24
|
+
* ```ts
|
|
25
|
+
* export const load = () => {
|
|
26
|
+
* return {
|
|
27
|
+
* seo: definePageSeo({
|
|
28
|
+
* title: 'DataTable Component',
|
|
29
|
+
* description: 'Interactive sortable table for SvelteKit',
|
|
30
|
+
* badge: 'Components'
|
|
31
|
+
* })
|
|
32
|
+
* };
|
|
33
|
+
* };
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare function definePageSeo(seo: PageSeoConfig): PageSeoConfig;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type-safe helper for SvelteKit load() functions to define page-level SEO.
|
|
3
|
+
* When returned inside { seo: definePageSeo(...) }, YaxaApp automatically
|
|
4
|
+
* extracts and binds all meta tags, OpenGraph cards, Twitter cards, and Schema.org data.
|
|
5
|
+
*
|
|
6
|
+
* Example:
|
|
7
|
+
* ```ts
|
|
8
|
+
* export const load = () => {
|
|
9
|
+
* return {
|
|
10
|
+
* seo: definePageSeo({
|
|
11
|
+
* title: 'DataTable Component',
|
|
12
|
+
* description: 'Interactive sortable table for SvelteKit',
|
|
13
|
+
* badge: 'Components'
|
|
14
|
+
* })
|
|
15
|
+
* };
|
|
16
|
+
* };
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export function definePageSeo(seo) {
|
|
20
|
+
return seo;
|
|
21
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { RequestHandler } from '@sveltejs/kit';
|
|
2
|
+
import type { SiteConfig } from './config';
|
|
3
|
+
export declare function generateSitemapXsl(config?: SiteConfig): string;
|
|
4
|
+
export declare function createSitemapXslHandler(options?: {
|
|
5
|
+
config?: SiteConfig;
|
|
6
|
+
}): RequestHandler;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
export function generateSitemapXsl(config) {
|
|
2
|
+
const siteName = config?.name || 'Yaxa';
|
|
3
|
+
const primaryColor = config?.theme?.primaryColor || '#ff3e00';
|
|
4
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
5
|
+
<xsl:stylesheet version="2.0"
|
|
6
|
+
xmlns:html="http://www.w3.org/TR/REC-html40"
|
|
7
|
+
xmlns:sitemap="http://www.sitemaps.org/schemas/sitemap/0.9"
|
|
8
|
+
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
|
9
|
+
<xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
|
|
10
|
+
<xsl:template match="/">
|
|
11
|
+
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
|
|
12
|
+
<head>
|
|
13
|
+
<title>XML Sitemap · ${siteName}</title>
|
|
14
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
15
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
16
|
+
<style type="text/css">
|
|
17
|
+
:root {
|
|
18
|
+
--primary: ${primaryColor};
|
|
19
|
+
}
|
|
20
|
+
body {
|
|
21
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
22
|
+
background-color: #121212;
|
|
23
|
+
color: #e4e4e7;
|
|
24
|
+
margin: 0;
|
|
25
|
+
padding: 32px 16px;
|
|
26
|
+
}
|
|
27
|
+
.container {
|
|
28
|
+
max-width: 1024px;
|
|
29
|
+
margin: 0 auto;
|
|
30
|
+
background-color: #18181b;
|
|
31
|
+
border: 1px solid #27272a;
|
|
32
|
+
border-radius: 16px;
|
|
33
|
+
padding: 32px;
|
|
34
|
+
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.5);
|
|
35
|
+
}
|
|
36
|
+
.header {
|
|
37
|
+
display: flex;
|
|
38
|
+
align-items: center;
|
|
39
|
+
justify-content: space-between;
|
|
40
|
+
border-bottom: 1px solid #27272a;
|
|
41
|
+
padding-bottom: 24px;
|
|
42
|
+
margin-bottom: 24px;
|
|
43
|
+
}
|
|
44
|
+
.logo-area {
|
|
45
|
+
display: flex;
|
|
46
|
+
align-items: center;
|
|
47
|
+
gap: 12px;
|
|
48
|
+
}
|
|
49
|
+
.badge {
|
|
50
|
+
background-color: rgba(255, 62, 0, 0.15);
|
|
51
|
+
color: var(--primary);
|
|
52
|
+
border: 1px solid rgba(255, 62, 0, 0.3);
|
|
53
|
+
border-radius: 9999px;
|
|
54
|
+
padding: 4px 12px;
|
|
55
|
+
font-size: 12px;
|
|
56
|
+
font-weight: 600;
|
|
57
|
+
}
|
|
58
|
+
h1 {
|
|
59
|
+
font-size: 24px;
|
|
60
|
+
font-weight: 800;
|
|
61
|
+
margin: 0;
|
|
62
|
+
color: #ffffff;
|
|
63
|
+
}
|
|
64
|
+
p {
|
|
65
|
+
color: #a1a1aa;
|
|
66
|
+
font-size: 14px;
|
|
67
|
+
margin: 8px 0 0 0;
|
|
68
|
+
}
|
|
69
|
+
table {
|
|
70
|
+
width: 100%;
|
|
71
|
+
border-collapse: collapse;
|
|
72
|
+
font-size: 13px;
|
|
73
|
+
}
|
|
74
|
+
th {
|
|
75
|
+
background-color: #27272a;
|
|
76
|
+
color: #d4d4d8;
|
|
77
|
+
font-weight: 600;
|
|
78
|
+
text-align: left;
|
|
79
|
+
padding: 12px 16px;
|
|
80
|
+
border-bottom: 1px solid #3f3f46;
|
|
81
|
+
}
|
|
82
|
+
th:first-child { border-top-left-radius: 8px; }
|
|
83
|
+
th:last-child { border-top-right-radius: 8px; }
|
|
84
|
+
td {
|
|
85
|
+
padding: 12px 16px;
|
|
86
|
+
border-bottom: 1px solid #27272a;
|
|
87
|
+
}
|
|
88
|
+
tr:hover td {
|
|
89
|
+
background-color: #27272a;
|
|
90
|
+
}
|
|
91
|
+
a {
|
|
92
|
+
color: var(--primary);
|
|
93
|
+
text-decoration: none;
|
|
94
|
+
font-weight: 500;
|
|
95
|
+
}
|
|
96
|
+
a:hover {
|
|
97
|
+
text-decoration: underline;
|
|
98
|
+
}
|
|
99
|
+
.footer {
|
|
100
|
+
margin-top: 24px;
|
|
101
|
+
font-size: 12px;
|
|
102
|
+
color: #71717a;
|
|
103
|
+
text-align: center;
|
|
104
|
+
}
|
|
105
|
+
</style>
|
|
106
|
+
</head>
|
|
107
|
+
<body>
|
|
108
|
+
<div class="container">
|
|
109
|
+
<div class="header">
|
|
110
|
+
<div>
|
|
111
|
+
<div class="logo-area">
|
|
112
|
+
<h1>${siteName} Sitemap</h1>
|
|
113
|
+
<span class="badge"><xsl:value-of select="count(sitemap:urlset/sitemap:url)"/> URLs</span>
|
|
114
|
+
</div>
|
|
115
|
+
<p>Generated dynamically by Yaxa for SvelteKit 2.7+ and search crawlers.</p>
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
<table>
|
|
119
|
+
<thead>
|
|
120
|
+
<tr>
|
|
121
|
+
<th style="width: 55%;">URL Location</th>
|
|
122
|
+
<th style="width: 15%;">Changefreq</th>
|
|
123
|
+
<th style="width: 15%;">Priority</th>
|
|
124
|
+
<th style="width: 15%;">Last Modified</th>
|
|
125
|
+
</tr>
|
|
126
|
+
</thead>
|
|
127
|
+
<tbody>
|
|
128
|
+
<xsl:for-each select="sitemap:urlset/sitemap:url">
|
|
129
|
+
<tr>
|
|
130
|
+
<td>
|
|
131
|
+
<a target="_blank">
|
|
132
|
+
<xsl:attribute name="href">
|
|
133
|
+
<xsl:value-of select="sitemap:loc"/>
|
|
134
|
+
</xsl:attribute>
|
|
135
|
+
<xsl:value-of select="sitemap:loc"/>
|
|
136
|
+
</a>
|
|
137
|
+
</td>
|
|
138
|
+
<td><xsl:value-of select="sitemap:changefreq"/></td>
|
|
139
|
+
<td><xsl:value-of select="sitemap:priority"/></td>
|
|
140
|
+
<td><xsl:value-of select="sitemap:lastmod"/></td>
|
|
141
|
+
</tr>
|
|
142
|
+
</xsl:for-each>
|
|
143
|
+
</tbody>
|
|
144
|
+
</table>
|
|
145
|
+
<div class="footer">
|
|
146
|
+
Powered by Yaxa · SvelteKit 2.7+ · Svelte 5
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
</body>
|
|
150
|
+
</html>
|
|
151
|
+
</xsl:template>
|
|
152
|
+
</xsl:stylesheet>`;
|
|
153
|
+
}
|
|
154
|
+
export function createSitemapXslHandler(options) {
|
|
155
|
+
return async () => {
|
|
156
|
+
const xsl = generateSitemapXsl(options?.config);
|
|
157
|
+
return new Response(xsl, {
|
|
158
|
+
headers: {
|
|
159
|
+
'Content-Type': 'application/xml; charset=utf-8',
|
|
160
|
+
'Cache-Control': 'public, max-age=86400, s-maxage=86400'
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
};
|
|
164
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { RequestHandler } from '@sveltejs/kit';
|
|
2
|
+
import type { SiteConfig } from './config';
|
|
3
|
+
export interface SitemapRoute {
|
|
4
|
+
loc: string;
|
|
5
|
+
lastmod?: string;
|
|
6
|
+
changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
|
|
7
|
+
priority?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface SitemapOptions {
|
|
10
|
+
config: SiteConfig;
|
|
11
|
+
/**
|
|
12
|
+
* Additional static or dynamic routes to include (e.g. /blog/[slug], /products/[id])
|
|
13
|
+
*/
|
|
14
|
+
dynamicRoutes?: () => Promise<SitemapRoute[]> | SitemapRoute[];
|
|
15
|
+
/**
|
|
16
|
+
* Default routes to include if not providing dynamic list
|
|
17
|
+
*/
|
|
18
|
+
staticRoutes?: string[];
|
|
19
|
+
}
|
|
20
|
+
export declare function createSitemapHandler(optionsOrConfig: SiteConfig | SitemapOptions): RequestHandler;
|