sdga-ui 1.0.6 → 1.0.8
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 +4 -4
- package/css/dga-ui.css +571 -220
- package/css/dga-ui.css.map +1 -1
- package/demo-angular/angular.json +3 -0
- package/demo-angular/package-lock.json +41 -41
- package/demo-angular/package.json +8 -8
- package/demo-angular/public/404.html +35 -0
- package/demo-angular/public/i18n/ar.json +47 -0
- package/demo-angular/public/i18n/en.json +47 -0
- package/demo-angular/src/app/app.html +1 -1
- package/demo-angular/src/app/app.routes.ts +8 -4
- package/demo-angular/src/app/app.ts +11 -2
- package/demo-angular/src/app/shared/code-example/code-example.component.html +1 -1
- package/demo-angular/src/app/shared/code-example/code-example.component.ts +12 -1
- package/demo-angular/src/app/views/alerts/alerts.component.html +10 -10
- package/demo-angular/src/app/views/alerts/alerts.component.ts +10 -10
- package/demo-angular/src/app/views/buttons/buttons.component.html +118 -47
- package/demo-angular/src/app/views/buttons/buttons.component.scss +0 -3
- package/demo-angular/src/app/views/buttons/buttons.component.ts +91 -21
- package/demo-angular/src/app/views/cards/cards.component.html +6 -6
- package/demo-angular/src/app/views/cards/cards.component.ts +10 -10
- package/demo-angular/src/app/views/footer/footer.html +270 -0
- package/demo-angular/src/app/views/footer/footer.ts +276 -0
- package/demo-angular/src/app/views/header/header.html +1 -0
- package/demo-angular/src/app/views/header/header.scss +0 -0
- package/demo-angular/src/app/views/header/header.spec.ts +23 -0
- package/demo-angular/src/app/views/header/header.ts +11 -0
- package/demo-angular/src/app/views/home/home.component.html +0 -5
- package/demo-angular/src/app/views/links/links.component.html +2 -2
- package/demo-angular/src/app/views/links/links.component.ts +1 -1
- package/demo-angular/src/app/views/toasts/toasts.component.html +7 -7
- package/demo-angular/src/app/views/toasts/toasts.component.ts +7 -7
- package/demo-angular/src/index.html +15 -1
- package/demo-angular/tsconfig.app.json +2 -1
- package/package.json +2 -2
- package/sdga-ui/README.md +45 -0
- package/sdga-ui/content/docs/components/alerts.mdx +475 -0
- package/sdga-ui/content/docs/index.mdx +239 -0
- package/sdga-ui/next.config.mjs +10 -0
- package/sdga-ui/package-lock.json +5851 -0
- package/sdga-ui/package.json +32 -0
- package/sdga-ui/postcss.config.mjs +5 -0
- package/sdga-ui/source.config.ts +27 -0
- package/sdga-ui/src/app/(home)/layout.tsx +6 -0
- package/sdga-ui/src/app/(home)/page.tsx +202 -0
- package/sdga-ui/src/app/api/search/route.ts +7 -0
- package/sdga-ui/src/app/docs/[[...slug]]/page.tsx +54 -0
- package/sdga-ui/src/app/docs/layout.tsx +11 -0
- package/sdga-ui/src/app/global.css +3 -0
- package/sdga-ui/src/app/layout.tsx +25 -0
- package/sdga-ui/src/app/llms-full.txt/route.ts +10 -0
- package/sdga-ui/src/app/og/docs/[...slug]/route.tsx +34 -0
- package/sdga-ui/src/app/sdga-scoped.css +7 -0
- package/sdga-ui/src/components/sdga-preview.tsx +105 -0
- package/sdga-ui/src/lib/layout.shared.tsx +9 -0
- package/sdga-ui/src/lib/source.ts +27 -0
- package/sdga-ui/src/mdx-components.tsx +9 -0
- package/sdga-ui/tsconfig.json +46 -0
- package/theme/_variables.scss +6 -5
- package/theme/components/_buttons.scss +1 -197
- package/theme/config/_base.scss +11 -1
- package/theme/customizations/_alerts.scss +115 -126
- package/theme/customizations/_badges.scss +15 -0
- package/theme/customizations/_buttons.scss +349 -146
- package/theme/customizations/_cards.scss +52 -0
- package/theme/customizations/_footer.scss +160 -0
- package/theme/customizations/_global.scss +20 -2
- package/theme/customizations/_links.scss +62 -45
- package/theme/customizations/_toasts.scss +92 -114
- package/theme/dga-ui.scss +2 -1
- package/demo-angular/src/app/views/bootstrap/bootstrap.component.html +0 -14
- package/demo-angular/src/app/views/bootstrap/bootstrap.component.scss +0 -91
- package/demo-angular/src/app/views/bootstrap/bootstrap.component.ts +0 -23
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sdga-ui",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "next build",
|
|
7
|
+
"dev": "next dev",
|
|
8
|
+
"start": "next start",
|
|
9
|
+
"types:check": "fumadocs-mdx && tsc --noEmit",
|
|
10
|
+
"postinstall": "fumadocs-mdx"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"fumadocs-core": "16.2.2",
|
|
14
|
+
"fumadocs-mdx": "14.0.4",
|
|
15
|
+
"fumadocs-ui": "16.2.2",
|
|
16
|
+
"lucide-react": "^0.552.0",
|
|
17
|
+
"next": "16.0.1",
|
|
18
|
+
"react": "^19.2.0",
|
|
19
|
+
"react-dom": "^19.2.0",
|
|
20
|
+
"sdga-ui": "^1.0.6"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@tailwindcss/postcss": "^4.1.16",
|
|
24
|
+
"@types/mdx": "^2.0.13",
|
|
25
|
+
"@types/node": "^24.10.0",
|
|
26
|
+
"@types/react": "^19.2.2",
|
|
27
|
+
"@types/react-dom": "^19.2.2",
|
|
28
|
+
"postcss": "^8.5.6",
|
|
29
|
+
"tailwindcss": "^4.1.16",
|
|
30
|
+
"typescript": "^5.9.3"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineConfig,
|
|
3
|
+
defineDocs,
|
|
4
|
+
frontmatterSchema,
|
|
5
|
+
metaSchema,
|
|
6
|
+
} from 'fumadocs-mdx/config';
|
|
7
|
+
|
|
8
|
+
// You can customise Zod schemas for frontmatter and `meta.json` here
|
|
9
|
+
// see https://fumadocs.dev/docs/mdx/collections
|
|
10
|
+
export const docs = defineDocs({
|
|
11
|
+
dir: 'content/docs',
|
|
12
|
+
docs: {
|
|
13
|
+
schema: frontmatterSchema,
|
|
14
|
+
postprocess: {
|
|
15
|
+
includeProcessedMarkdown: true,
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
meta: {
|
|
19
|
+
schema: metaSchema,
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export default defineConfig({
|
|
24
|
+
mdxOptions: {
|
|
25
|
+
// MDX options
|
|
26
|
+
},
|
|
27
|
+
});
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import Link from 'next/link';
|
|
2
|
+
import { ArrowRight, Code2, Palette, Zap, Globe, Sparkles, BookOpen } from 'lucide-react';
|
|
3
|
+
|
|
4
|
+
export default function HomePage() {
|
|
5
|
+
return (
|
|
6
|
+
<div className="flex flex-col">
|
|
7
|
+
{/* Hero Section */}
|
|
8
|
+
<section className="relative overflow-hidden">
|
|
9
|
+
<div className="absolute inset-0 bg-linear-to-br from-blue-50 via-indigo-50 to-purple-50 dark:from-blue-950/20 dark:via-indigo-950/20 dark:to-purple-950/20" />
|
|
10
|
+
<div className="absolute inset-0 opacity-[0.02]" style={{ backgroundImage: 'radial-gradient(circle at 1px 1px, rgb(0 0 0 / 0.5) 1px, transparent 0)', backgroundSize: '40px 40px' }} />
|
|
11
|
+
|
|
12
|
+
<div className="relative container mx-auto px-4 py-24 md:py-32">
|
|
13
|
+
<div className="flex flex-col items-center text-center max-w-4xl mx-auto">
|
|
14
|
+
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-white/80 dark:bg-neutral-900/80 backdrop-blur-sm border border-neutral-200 dark:border-neutral-800 mb-6 shadow-sm">
|
|
15
|
+
<Sparkles className="w-4 h-4 text-indigo-600 dark:text-indigo-400" />
|
|
16
|
+
<span className="text-sm font-medium">Saudi Digital Government Authority</span>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<h1 className="text-5xl md:text-7xl font-bold mb-6 bg-clip-text text-transparent bg-linear-to-r from-indigo-600 via-purple-600 to-pink-600 dark:from-indigo-400 dark:via-purple-400 dark:to-pink-400">
|
|
20
|
+
SDGA UI
|
|
21
|
+
</h1>
|
|
22
|
+
|
|
23
|
+
<p className="text-xl md:text-2xl text-neutral-600 dark:text-neutral-400 mb-8 max-w-2xl">
|
|
24
|
+
A beautiful, accessible, and customizable component library built for modern web applications
|
|
25
|
+
</p>
|
|
26
|
+
|
|
27
|
+
<div className="flex flex-wrap items-center justify-center gap-4 mb-12">
|
|
28
|
+
<Link
|
|
29
|
+
href="/docs"
|
|
30
|
+
className="inline-flex items-center gap-2 px-8 py-4 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg font-semibold transition-all hover:scale-105 hover:shadow-xl shadow-lg"
|
|
31
|
+
>
|
|
32
|
+
Get Started
|
|
33
|
+
<ArrowRight className="w-5 h-5" />
|
|
34
|
+
</Link>
|
|
35
|
+
|
|
36
|
+
<Link
|
|
37
|
+
href="/docs"
|
|
38
|
+
className="inline-flex items-center gap-2 px-8 py-4 bg-white dark:bg-neutral-900 hover:bg-neutral-50 dark:hover:bg-neutral-800 text-neutral-900 dark:text-white rounded-lg font-semibold border border-neutral-200 dark:border-neutral-800 transition-all hover:shadow-lg"
|
|
39
|
+
>
|
|
40
|
+
<BookOpen className="w-5 h-5" />
|
|
41
|
+
View Documentation
|
|
42
|
+
</Link>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
{/* Stats */}
|
|
46
|
+
<div className="grid grid-cols-3 gap-8 md:gap-12 pt-8 border-t border-neutral-200 dark:border-neutral-800 w-full max-w-2xl">
|
|
47
|
+
<div>
|
|
48
|
+
<div className="text-3xl md:text-4xl font-bold text-indigo-600 dark:text-indigo-400 mb-1">50+</div>
|
|
49
|
+
<div className="text-sm text-neutral-600 dark:text-neutral-400">Components</div>
|
|
50
|
+
</div>
|
|
51
|
+
<div>
|
|
52
|
+
<div className="text-3xl md:text-4xl font-bold text-purple-600 dark:text-purple-400 mb-1">100%</div>
|
|
53
|
+
<div className="text-sm text-neutral-600 dark:text-neutral-400">Accessible</div>
|
|
54
|
+
</div>
|
|
55
|
+
<div>
|
|
56
|
+
<div className="text-3xl md:text-4xl font-bold text-pink-600 dark:text-pink-400 mb-1">RTL</div>
|
|
57
|
+
<div className="text-sm text-neutral-600 dark:text-neutral-400">Support</div>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</section>
|
|
63
|
+
|
|
64
|
+
{/* Features Section */}
|
|
65
|
+
<section className="py-24 px-4">
|
|
66
|
+
<div className="container mx-auto max-w-6xl">
|
|
67
|
+
<div className="text-center mb-16">
|
|
68
|
+
<h2 className="text-4xl md:text-5xl font-bold mb-4">Why Choose SDGA UI?</h2>
|
|
69
|
+
<p className="text-lg text-neutral-600 dark:text-neutral-400 max-w-2xl mx-auto">
|
|
70
|
+
Built with modern technologies and best practices to help you create stunning interfaces faster
|
|
71
|
+
</p>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
|
|
75
|
+
<FeatureCard
|
|
76
|
+
icon={<Zap className="w-8 h-8" />}
|
|
77
|
+
title="Lightning Fast"
|
|
78
|
+
description="Optimized for performance with minimal bundle size and zero runtime overhead"
|
|
79
|
+
gradient="from-yellow-500 to-orange-500"
|
|
80
|
+
/>
|
|
81
|
+
|
|
82
|
+
<FeatureCard
|
|
83
|
+
icon={<Palette className="w-8 h-8" />}
|
|
84
|
+
title="Fully Customizable"
|
|
85
|
+
description="Extensive theming system with CSS variables and SCSS support for complete control"
|
|
86
|
+
gradient="from-pink-500 to-rose-500"
|
|
87
|
+
/>
|
|
88
|
+
|
|
89
|
+
<FeatureCard
|
|
90
|
+
icon={<Code2 className="w-8 h-8" />}
|
|
91
|
+
title="Developer Friendly"
|
|
92
|
+
description="Clean API, TypeScript support, and comprehensive documentation for seamless integration"
|
|
93
|
+
gradient="from-blue-500 to-cyan-500"
|
|
94
|
+
/>
|
|
95
|
+
|
|
96
|
+
<FeatureCard
|
|
97
|
+
icon={<Globe className="w-8 h-8" />}
|
|
98
|
+
title="RTL Support"
|
|
99
|
+
description="Built-in right-to-left language support for Arabic and other RTL languages"
|
|
100
|
+
gradient="from-green-500 to-emerald-500"
|
|
101
|
+
/>
|
|
102
|
+
|
|
103
|
+
<FeatureCard
|
|
104
|
+
icon={<Sparkles className="w-8 h-8" />}
|
|
105
|
+
title="Modern Design"
|
|
106
|
+
description="Contemporary UI patterns and components that follow the latest design trends"
|
|
107
|
+
gradient="from-purple-500 to-indigo-500"
|
|
108
|
+
/>
|
|
109
|
+
|
|
110
|
+
<FeatureCard
|
|
111
|
+
icon={<BookOpen className="w-8 h-8" />}
|
|
112
|
+
title="Rich Documentation"
|
|
113
|
+
description="Detailed guides, examples, and interactive demos for every component"
|
|
114
|
+
gradient="from-orange-500 to-red-500"
|
|
115
|
+
/>
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
</section>
|
|
119
|
+
|
|
120
|
+
{/* Code Preview Section */}
|
|
121
|
+
<section className="py-24 px-4 bg-neutral-50 dark:bg-neutral-900/50">
|
|
122
|
+
<div className="container mx-auto max-w-5xl">
|
|
123
|
+
<div className="text-center mb-12">
|
|
124
|
+
<h2 className="text-4xl font-bold mb-4">Simple to Use</h2>
|
|
125
|
+
<p className="text-lg text-neutral-600 dark:text-neutral-400">
|
|
126
|
+
Get started in minutes with our intuitive component API
|
|
127
|
+
</p>
|
|
128
|
+
</div>
|
|
129
|
+
|
|
130
|
+
<div className="bg-white dark:bg-neutral-900 rounded-2xl shadow-2xl border border-neutral-200 dark:border-neutral-800 overflow-hidden">
|
|
131
|
+
<div className="bg-neutral-100 dark:bg-neutral-800 px-6 py-4 border-b border-neutral-200 dark:border-neutral-700 flex items-center gap-2">
|
|
132
|
+
<div className="w-3 h-3 rounded-full bg-red-500" />
|
|
133
|
+
<div className="w-3 h-3 rounded-full bg-yellow-500" />
|
|
134
|
+
<div className="w-3 h-3 rounded-full bg-green-500" />
|
|
135
|
+
<span className="ml-4 text-sm text-neutral-600 dark:text-neutral-400 font-mono">example.html</span>
|
|
136
|
+
</div>
|
|
137
|
+
<pre className="p-6 overflow-x-auto">
|
|
138
|
+
<code className="text-sm font-mono text-neutral-800 dark:text-neutral-200">
|
|
139
|
+
{`<!-- Import SDGA UI -->
|
|
140
|
+
<link rel="stylesheet" href="sdga-ui.css">
|
|
141
|
+
|
|
142
|
+
<!-- Use components -->
|
|
143
|
+
<button class="btn btn-primary">
|
|
144
|
+
Click me
|
|
145
|
+
</button>
|
|
146
|
+
|
|
147
|
+
<div class="alert alert-success">
|
|
148
|
+
Success! Your changes have been saved.
|
|
149
|
+
</div>`}
|
|
150
|
+
</code>
|
|
151
|
+
</pre>
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
</section>
|
|
155
|
+
|
|
156
|
+
{/* CTA Section */}
|
|
157
|
+
<section className="py-24 px-4">
|
|
158
|
+
<div className="container mx-auto max-w-4xl text-center">
|
|
159
|
+
<div className="bg-linear-to-r from-indigo-600 to-purple-600 rounded-3xl p-12 md:p-16 shadow-2xl">
|
|
160
|
+
<h2 className="text-4xl md:text-5xl font-bold text-white mb-6">
|
|
161
|
+
Ready to Build Something Amazing?
|
|
162
|
+
</h2>
|
|
163
|
+
<p className="text-xl text-indigo-100 mb-8 max-w-2xl mx-auto">
|
|
164
|
+
Start creating beautiful, accessible interfaces with SDGA UI today
|
|
165
|
+
</p>
|
|
166
|
+
<Link
|
|
167
|
+
href="/docs"
|
|
168
|
+
className="inline-flex items-center gap-2 px-8 py-4 bg-white text-indigo-600 rounded-lg font-semibold hover:bg-indigo-50 transition-all hover:scale-105 shadow-lg"
|
|
169
|
+
>
|
|
170
|
+
Explore Documentation
|
|
171
|
+
<ArrowRight className="w-5 h-5" />
|
|
172
|
+
</Link>
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
175
|
+
</section>
|
|
176
|
+
</div>
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function FeatureCard({
|
|
181
|
+
icon,
|
|
182
|
+
title,
|
|
183
|
+
description,
|
|
184
|
+
gradient
|
|
185
|
+
}: {
|
|
186
|
+
icon: React.ReactNode;
|
|
187
|
+
title: string;
|
|
188
|
+
description: string;
|
|
189
|
+
gradient: string;
|
|
190
|
+
}) {
|
|
191
|
+
return (
|
|
192
|
+
<div className="group relative p-8 rounded-2xl bg-white dark:bg-neutral-900 border border-neutral-200 dark:border-neutral-800 hover:border-neutral-300 dark:hover:border-neutral-700 transition-all hover:shadow-xl">
|
|
193
|
+
<div className={`inline-flex p-3 rounded-xl bg-linear-to-br ${gradient} text-white mb-4 group-hover:scale-110 transition-transform`}>
|
|
194
|
+
{icon}
|
|
195
|
+
</div>
|
|
196
|
+
<h3 className="text-xl font-bold mb-2">{title}</h3>
|
|
197
|
+
<p className="text-neutral-600 dark:text-neutral-400 leading-relaxed">
|
|
198
|
+
{description}
|
|
199
|
+
</p>
|
|
200
|
+
</div>
|
|
201
|
+
);
|
|
202
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { getPageImage, source } from '@/lib/source';
|
|
2
|
+
import {
|
|
3
|
+
DocsBody,
|
|
4
|
+
DocsDescription,
|
|
5
|
+
DocsPage,
|
|
6
|
+
DocsTitle,
|
|
7
|
+
} from 'fumadocs-ui/layouts/docs/page';
|
|
8
|
+
import { notFound } from 'next/navigation';
|
|
9
|
+
import { getMDXComponents } from '@/mdx-components';
|
|
10
|
+
import type { Metadata } from 'next';
|
|
11
|
+
import { createRelativeLink } from 'fumadocs-ui/mdx';
|
|
12
|
+
|
|
13
|
+
export default async function Page(props: PageProps<'/docs/[[...slug]]'>) {
|
|
14
|
+
const params = await props.params;
|
|
15
|
+
const page = source.getPage(params.slug);
|
|
16
|
+
if (!page) notFound();
|
|
17
|
+
|
|
18
|
+
const MDX = page.data.body;
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<DocsPage toc={page.data.toc} full={page.data.full}>
|
|
22
|
+
<DocsTitle>{page.data.title}</DocsTitle>
|
|
23
|
+
<DocsDescription>{page.data.description}</DocsDescription>
|
|
24
|
+
<DocsBody>
|
|
25
|
+
<MDX
|
|
26
|
+
components={getMDXComponents({
|
|
27
|
+
// this allows you to link to other pages with relative file paths
|
|
28
|
+
a: createRelativeLink(source, page),
|
|
29
|
+
})}
|
|
30
|
+
/>
|
|
31
|
+
</DocsBody>
|
|
32
|
+
</DocsPage>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export async function generateStaticParams() {
|
|
37
|
+
return source.generateParams();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function generateMetadata(
|
|
41
|
+
props: PageProps<'/docs/[[...slug]]'>,
|
|
42
|
+
): Promise<Metadata> {
|
|
43
|
+
const params = await props.params;
|
|
44
|
+
const page = source.getPage(params.slug);
|
|
45
|
+
if (!page) notFound();
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
title: page.data.title,
|
|
49
|
+
description: page.data.description,
|
|
50
|
+
openGraph: {
|
|
51
|
+
images: getPageImage(page).url,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { source } from '@/lib/source';
|
|
2
|
+
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
|
|
3
|
+
import { baseOptions } from '@/lib/layout.shared';
|
|
4
|
+
|
|
5
|
+
export default function Layout({ children }: LayoutProps<'/docs'>) {
|
|
6
|
+
return (
|
|
7
|
+
<DocsLayout tree={source.pageTree} {...baseOptions()}>
|
|
8
|
+
{children}
|
|
9
|
+
</DocsLayout>
|
|
10
|
+
);
|
|
11
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { RootProvider } from 'fumadocs-ui/provider/next';
|
|
2
|
+
import './global.css';
|
|
3
|
+
import { Inter } from 'next/font/google';
|
|
4
|
+
import Script from 'next/script';
|
|
5
|
+
|
|
6
|
+
const inter = Inter({
|
|
7
|
+
subsets: ['latin'],
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export default function Layout({ children }: LayoutProps<'/'>) {
|
|
11
|
+
return (
|
|
12
|
+
<html lang="en" className={inter.className} suppressHydrationWarning>
|
|
13
|
+
<body className="flex flex-col min-h-screen">
|
|
14
|
+
<RootProvider>{children}</RootProvider>
|
|
15
|
+
{/* Bootstrap JS for interactive components */}
|
|
16
|
+
<Script
|
|
17
|
+
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"
|
|
18
|
+
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
|
|
19
|
+
crossOrigin="anonymous"
|
|
20
|
+
strategy="afterInteractive"
|
|
21
|
+
/>
|
|
22
|
+
</body>
|
|
23
|
+
</html>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { getLLMText, source } from '@/lib/source';
|
|
2
|
+
|
|
3
|
+
export const revalidate = false;
|
|
4
|
+
|
|
5
|
+
export async function GET() {
|
|
6
|
+
const scan = source.getPages().map(getLLMText);
|
|
7
|
+
const scanned = await Promise.all(scan);
|
|
8
|
+
|
|
9
|
+
return new Response(scanned.join('\n\n'));
|
|
10
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { getPageImage, source } from '@/lib/source';
|
|
2
|
+
import { notFound } from 'next/navigation';
|
|
3
|
+
import { ImageResponse } from 'next/og';
|
|
4
|
+
import { generate as DefaultImage } from 'fumadocs-ui/og';
|
|
5
|
+
|
|
6
|
+
export const revalidate = false;
|
|
7
|
+
|
|
8
|
+
export async function GET(
|
|
9
|
+
_req: Request,
|
|
10
|
+
{ params }: RouteContext<'/og/docs/[...slug]'>,
|
|
11
|
+
) {
|
|
12
|
+
const { slug } = await params;
|
|
13
|
+
const page = source.getPage(slug.slice(0, -1));
|
|
14
|
+
if (!page) notFound();
|
|
15
|
+
|
|
16
|
+
return new ImageResponse(
|
|
17
|
+
<DefaultImage
|
|
18
|
+
title={page.data.title}
|
|
19
|
+
description={page.data.description}
|
|
20
|
+
site="My App"
|
|
21
|
+
/>,
|
|
22
|
+
{
|
|
23
|
+
width: 1200,
|
|
24
|
+
height: 630,
|
|
25
|
+
},
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function generateStaticParams() {
|
|
30
|
+
return source.getPages().map((page) => ({
|
|
31
|
+
lang: page.locale,
|
|
32
|
+
slug: getPageImage(page).segments,
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useEffect, useRef, useState } from 'react';
|
|
4
|
+
|
|
5
|
+
interface SdgaPreviewProps {
|
|
6
|
+
html: string;
|
|
7
|
+
minHeight?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Preload resources once for all previews
|
|
11
|
+
if (typeof window !== 'undefined') {
|
|
12
|
+
const preloadCSS = document.createElement('link');
|
|
13
|
+
preloadCSS.rel = 'preload';
|
|
14
|
+
preloadCSS.as = 'style';
|
|
15
|
+
preloadCSS.href = 'https://cdn.jsdelivr.net/npm/sdga-ui@latest/css/dga-ui.css';
|
|
16
|
+
|
|
17
|
+
const preloadJS = document.createElement('link');
|
|
18
|
+
preloadJS.rel = 'preload';
|
|
19
|
+
preloadJS.as = 'script';
|
|
20
|
+
preloadJS.href = 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js';
|
|
21
|
+
|
|
22
|
+
if (!document.querySelector(`link[href="${preloadCSS.href}"]`)) {
|
|
23
|
+
document.head.appendChild(preloadCSS);
|
|
24
|
+
document.head.appendChild(preloadJS);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function SdgaPreview({ html, minHeight = '150px' }: SdgaPreviewProps) {
|
|
29
|
+
const iframeRef = useRef<HTMLIFrameElement>(null);
|
|
30
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
31
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
32
|
+
|
|
33
|
+
// Lazy load iframe when it enters viewport
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
const container = containerRef.current;
|
|
36
|
+
if (!container) return;
|
|
37
|
+
|
|
38
|
+
const observer = new IntersectionObserver(
|
|
39
|
+
(entries) => {
|
|
40
|
+
entries.forEach((entry) => {
|
|
41
|
+
if (entry.isIntersecting) {
|
|
42
|
+
setIsVisible(true);
|
|
43
|
+
observer.disconnect();
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
},
|
|
47
|
+
{ rootMargin: '200px' } // Load 200px before entering viewport
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
observer.observe(container);
|
|
51
|
+
return () => observer.disconnect();
|
|
52
|
+
}, []);
|
|
53
|
+
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
if (!isVisible) return;
|
|
56
|
+
|
|
57
|
+
const iframe = iframeRef.current;
|
|
58
|
+
if (!iframe) return;
|
|
59
|
+
|
|
60
|
+
const content = `<!DOCTYPE html>
|
|
61
|
+
<html lang="en">
|
|
62
|
+
<head>
|
|
63
|
+
<meta charset="UTF-8">
|
|
64
|
+
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
65
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sdga-ui@latest/css/dga-ui.css">
|
|
66
|
+
<style>body{margin:0;padding:1.5rem;background:transparent;overflow-x:hidden}</style>
|
|
67
|
+
</head>
|
|
68
|
+
<body>${html}<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js" integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI" crossorigin="anonymous"><\/script><script>let t;function r(){clearTimeout(t);t=setTimeout(()=>window.parent.postMessage({type:'resize',height:document.body.scrollHeight},'*'),150)}window.addEventListener('load',()=>setTimeout(r,100));if(!window.__RO_DISABLED__){const o=new MutationObserver(()=>requestAnimationFrame(r));o.observe(document.body,{childList:true,subtree:true,attributes:true,attributeFilter:['class','style']})}<\/script></body></html>`;
|
|
69
|
+
|
|
70
|
+
iframe.srcdoc = content;
|
|
71
|
+
}, [html, isVisible]);
|
|
72
|
+
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
const handleMessage = (event: MessageEvent) => {
|
|
75
|
+
if (event.data.type === 'resize' && iframeRef.current) {
|
|
76
|
+
iframeRef.current.style.height = `${event.data.height + 10}px`;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
window.addEventListener('message', handleMessage);
|
|
81
|
+
return () => window.removeEventListener('message', handleMessage);
|
|
82
|
+
}, []);
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<div ref={containerRef} style={{ minHeight }}>
|
|
86
|
+
{isVisible ? (
|
|
87
|
+
<iframe
|
|
88
|
+
ref={iframeRef}
|
|
89
|
+
className="w-full border border-neutral-200 dark:border-neutral-800 rounded-lg"
|
|
90
|
+
style={{ minHeight, border: '1px solid rgb(229 229 229)', borderRadius: '0.5rem' }}
|
|
91
|
+
sandbox="allow-scripts allow-same-origin"
|
|
92
|
+
loading="lazy"
|
|
93
|
+
title="SDGA UI Preview"
|
|
94
|
+
/>
|
|
95
|
+
) : (
|
|
96
|
+
<div
|
|
97
|
+
className="w-full border border-neutral-200 dark:border-neutral-800 rounded-lg flex items-center justify-center"
|
|
98
|
+
style={{ minHeight, background: '#f9fafb' }}
|
|
99
|
+
>
|
|
100
|
+
<span className="text-neutral-400">Loading preview...</span>
|
|
101
|
+
</div>
|
|
102
|
+
)}
|
|
103
|
+
</div>
|
|
104
|
+
);
|
|
105
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { docs } from 'fumadocs-mdx:collections/server';
|
|
2
|
+
import { type InferPageType, loader } from 'fumadocs-core/source';
|
|
3
|
+
import { lucideIconsPlugin } from 'fumadocs-core/source/lucide-icons';
|
|
4
|
+
|
|
5
|
+
// See https://fumadocs.dev/docs/headless/source-api for more info
|
|
6
|
+
export const source = loader({
|
|
7
|
+
baseUrl: '/docs',
|
|
8
|
+
source: docs.toFumadocsSource(),
|
|
9
|
+
plugins: [lucideIconsPlugin()],
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export function getPageImage(page: InferPageType<typeof source>) {
|
|
13
|
+
const segments = [...page.slugs, 'image.png'];
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
segments,
|
|
17
|
+
url: `/og/docs/${segments.join('/')}`,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function getLLMText(page: InferPageType<typeof source>) {
|
|
22
|
+
const processed = await page.data.getText('processed');
|
|
23
|
+
|
|
24
|
+
return `# ${page.data.title}
|
|
25
|
+
|
|
26
|
+
${processed}`;
|
|
27
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"baseUrl": ".",
|
|
4
|
+
"target": "ESNext",
|
|
5
|
+
"lib": [
|
|
6
|
+
"dom",
|
|
7
|
+
"dom.iterable",
|
|
8
|
+
"esnext"
|
|
9
|
+
],
|
|
10
|
+
"allowJs": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"strict": true,
|
|
13
|
+
"forceConsistentCasingInFileNames": true,
|
|
14
|
+
"noEmit": true,
|
|
15
|
+
"esModuleInterop": true,
|
|
16
|
+
"module": "esnext",
|
|
17
|
+
"moduleResolution": "bundler",
|
|
18
|
+
"resolveJsonModule": true,
|
|
19
|
+
"isolatedModules": true,
|
|
20
|
+
"jsx": "react-jsx",
|
|
21
|
+
"incremental": true,
|
|
22
|
+
"paths": {
|
|
23
|
+
"@/*": [
|
|
24
|
+
"./src/*"
|
|
25
|
+
],
|
|
26
|
+
"fumadocs-mdx:collections/*": [
|
|
27
|
+
".source/*"
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"plugins": [
|
|
31
|
+
{
|
|
32
|
+
"name": "next"
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
"include": [
|
|
37
|
+
"next-env.d.ts",
|
|
38
|
+
"**/*.ts",
|
|
39
|
+
"**/*.tsx",
|
|
40
|
+
".next/types/**/*.ts",
|
|
41
|
+
".next/dev/types/**/*.ts"
|
|
42
|
+
],
|
|
43
|
+
"exclude": [
|
|
44
|
+
"node_modules"
|
|
45
|
+
]
|
|
46
|
+
}
|
package/theme/_variables.scss
CHANGED
|
@@ -31,17 +31,18 @@
|
|
|
31
31
|
@import 'components/buttons';
|
|
32
32
|
@import 'components/alerts';
|
|
33
33
|
@import 'components/toasts';
|
|
34
|
+
@import 'components/forms';
|
|
35
|
+
@import 'components/dropdowns';
|
|
36
|
+
@import 'components/cards';
|
|
37
|
+
@import 'components/tables';
|
|
38
|
+
|
|
39
|
+
@import 'components/navbar';
|
|
34
40
|
@import 'components/modals';
|
|
35
41
|
@import 'components/tooltips';
|
|
36
42
|
@import 'components/popovers';
|
|
37
43
|
@import 'components/offcanvas';
|
|
38
|
-
@import 'components/forms';
|
|
39
|
-
@import 'components/navbar';
|
|
40
|
-
@import 'components/dropdowns';
|
|
41
44
|
@import 'components/pagination';
|
|
42
45
|
@import 'components/breadcrumb';
|
|
43
|
-
@import 'components/cards';
|
|
44
|
-
@import 'components/tables';
|
|
45
46
|
@import 'components/list-group';
|
|
46
47
|
@import 'components/accordion';
|
|
47
48
|
@import 'components/badges';
|