@seip/blue-bird 0.4.5 → 0.4.6
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/.env_example +26 -25
- package/AGENTS.md +199 -199
- package/README.md +79 -79
- package/backend/index.js +13 -13
- package/backend/routes/frontend.js +41 -41
- package/backend/routes/seo.js +39 -39
- package/core/app.js +328 -325
- package/core/auth.js +114 -114
- package/core/cache.js +44 -44
- package/core/cli/component.js +42 -42
- package/core/cli/init.js +119 -118
- package/core/cli/react.js +435 -435
- package/core/cli/route.js +42 -42
- package/core/config.js +48 -47
- package/core/debug.js +248 -248
- package/core/logger.js +100 -100
- package/core/middleware.js +27 -27
- package/core/router.js +333 -333
- package/core/seo.js +95 -100
- package/core/template.js +472 -462
- package/core/upload.js +76 -76
- package/core/validate.js +380 -380
- package/frontend/index.html +26 -26
- package/frontend/landing.html +69 -69
- package/frontend/resources/css/tailwind.css +17 -17
- package/frontend/resources/js/App.jsx +70 -70
- package/frontend/resources/js/Main.jsx +18 -18
- package/frontend/resources/js/blue-bird/components/Button.jsx +67 -67
- package/frontend/resources/js/blue-bird/components/Card.jsx +18 -18
- package/frontend/resources/js/blue-bird/components/DataTable.jsx +126 -126
- package/frontend/resources/js/blue-bird/components/Input.jsx +21 -21
- package/frontend/resources/js/blue-bird/components/Label.jsx +12 -12
- package/frontend/resources/js/blue-bird/components/LanguageButton.jsx +23 -23
- package/frontend/resources/js/blue-bird/components/Link.jsx +15 -15
- package/frontend/resources/js/blue-bird/components/Modal.jsx +27 -27
- package/frontend/resources/js/blue-bird/components/Skeleton.jsx +44 -44
- package/frontend/resources/js/blue-bird/components/Translate.jsx +12 -12
- package/frontend/resources/js/blue-bird/components/Typography.jsx +69 -69
- package/frontend/resources/js/blue-bird/contexts/LanguageContext.jsx +41 -41
- package/frontend/resources/js/blue-bird/contexts/SPAContext.jsx +239 -237
- package/frontend/resources/js/blue-bird/contexts/SnackbarContext.jsx +38 -38
- package/frontend/resources/js/blue-bird/contexts/ThemeContext.jsx +49 -49
- package/frontend/resources/js/blue-bird/locales/en.json +47 -47
- package/frontend/resources/js/blue-bird/locales/es.json +47 -47
- package/frontend/resources/js/components/Header.jsx +55 -55
- package/frontend/resources/js/pages/About.jsx +31 -31
- package/frontend/resources/js/pages/Home.jsx +82 -82
- package/package.json +57 -57
- package/vite.config.js +22 -22
- package/frontend/public/robots.txt +0 -0
- package/frontend/public/sitemap.xml +0 -0
package/frontend/index.html
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="__LANG__">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<title>__TITLE__</title>
|
|
7
|
-
<link rel="icon" href="/favicon.ico" />
|
|
8
|
-
<meta name="description" content="__DESCRIPTION__" />
|
|
9
|
-
<meta name="keywords" content="__KEYWORDS__" />
|
|
10
|
-
<meta name="author" content="__AUTHOR__" />
|
|
11
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
12
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
13
|
-
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@100..900&family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap" rel="stylesheet">
|
|
14
|
-
__HEAD_OPTIONS__
|
|
15
|
-
__LINK_STYLES__
|
|
16
|
-
__SCRIPTS_HEAD__
|
|
17
|
-
__VITE_ASSETS__
|
|
18
|
-
__STYLES_SKELETON__
|
|
19
|
-
</head>
|
|
20
|
-
<body class="__CLASS_BODY__">
|
|
21
|
-
<div id="root" data-react-component="__COMPONENT__" data-props='__PROPS__'>
|
|
22
|
-
__SKELETON__
|
|
23
|
-
</div>
|
|
24
|
-
__SCRIPTS_BODY__
|
|
25
|
-
</body>
|
|
26
|
-
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="__LANG__">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>__TITLE__</title>
|
|
7
|
+
<link rel="icon" href="/favicon.ico" />
|
|
8
|
+
<meta name="description" content="__DESCRIPTION__" />
|
|
9
|
+
<meta name="keywords" content="__KEYWORDS__" />
|
|
10
|
+
<meta name="author" content="__AUTHOR__" />
|
|
11
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
12
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
13
|
+
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@100..900&family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap" rel="stylesheet">
|
|
14
|
+
__HEAD_OPTIONS__
|
|
15
|
+
__LINK_STYLES__
|
|
16
|
+
__SCRIPTS_HEAD__
|
|
17
|
+
__VITE_ASSETS__
|
|
18
|
+
__STYLES_SKELETON__
|
|
19
|
+
</head>
|
|
20
|
+
<body class="__CLASS_BODY__">
|
|
21
|
+
<div id="root" data-react-component="__COMPONENT__" data-props='__PROPS__'>
|
|
22
|
+
__SKELETON__
|
|
23
|
+
</div>
|
|
24
|
+
__SCRIPTS_BODY__
|
|
25
|
+
</body>
|
|
26
|
+
|
|
27
27
|
</html>
|
package/frontend/landing.html
CHANGED
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="__LANG__">
|
|
3
|
-
|
|
4
|
-
<head>
|
|
5
|
-
<meta charset="UTF-8">
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
-
<title>__TITLE__</title>
|
|
8
|
-
<meta name="description" content="__DESCRIPTION__">
|
|
9
|
-
<meta name="keywords" content="__KEYWORDS__">
|
|
10
|
-
<meta name="author" content="__AUTHOR__">
|
|
11
|
-
<link rel="icon" href="/favicon.ico" />
|
|
12
|
-
__HEAD_OPTIONS__
|
|
13
|
-
<script src="https://cdn.tailwindcss.com"></script>
|
|
14
|
-
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;700&display=swap" rel="stylesheet">
|
|
15
|
-
<style>
|
|
16
|
-
body {
|
|
17
|
-
font-family: 'Outfit', sans-serif;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
.hero-gradient {
|
|
21
|
-
background: radial-gradient(circle at top right, #f0f9ff 0%, #ffffff 100%);
|
|
22
|
-
}
|
|
23
|
-
</style>
|
|
24
|
-
__LINK_STYLES__
|
|
25
|
-
__SCRIPTS_HEAD__
|
|
26
|
-
__VITE_ASSETS__
|
|
27
|
-
__STYLES_SKELETON__
|
|
28
|
-
</head>
|
|
29
|
-
|
|
30
|
-
<body class="__CLASS_BODY__ hero-gradient min-h-screen">
|
|
31
|
-
<div id="root">
|
|
32
|
-
<!-- Landing Content -->
|
|
33
|
-
<nav class="p-6 flex justify-between items-center max-w-7xl mx-auto">
|
|
34
|
-
<div class="text-2xl font-bold text-sky-600">Blue Bird</div>
|
|
35
|
-
<div class="space-x-6 text-slate-600 font-medium">
|
|
36
|
-
<a href="#features" class="hover:text-sky-600">Features</a>
|
|
37
|
-
</div>
|
|
38
|
-
</nav>
|
|
39
|
-
|
|
40
|
-
<main class="max-w-7xl mx-auto px-6 pt-20 pb-32 text-center">
|
|
41
|
-
<h1 class="text-6xl md:text-8xl font-black text-slate-900 mb-8 tracking-tight">
|
|
42
|
-
Built for <span class="text-sky-600">Speed.</span>
|
|
43
|
-
</h1>
|
|
44
|
-
<p class="text-xl text-slate-600 max-w-2xl mx-auto mb-12 leading-relaxed">
|
|
45
|
-
This page was served in under 1ms thanks to Blue Bird's in-memory caching. No heavy bundles, just pure
|
|
46
|
-
performance.
|
|
47
|
-
</p>
|
|
48
|
-
|
|
49
|
-
<div class="flex flex-col sm:flex-row justify-center gap-4 mb-20">
|
|
50
|
-
<div class="p-8 bg-white rounded-3xl shadow-xl shadow-sky-100 border border-slate-50 flex-1 max-w-sm">
|
|
51
|
-
<div class="text-3xl mb-4">🚀</div>
|
|
52
|
-
<h3 class="font-bold text-xl mb-2">Static First</h3>
|
|
53
|
-
<p class="text-slate-500 text-sm">Perfect for SEO and instant first contentful paint.</p>
|
|
54
|
-
</div>
|
|
55
|
-
<div class="p-8 bg-white rounded-3xl shadow-xl shadow-sky-100 border border-slate-50 flex-1 max-w-sm">
|
|
56
|
-
<div class="text-3xl mb-4">💎</div>
|
|
57
|
-
<h3 class="font-bold text-xl mb-2">Hybrid Ready</h3>
|
|
58
|
-
<p class="text-slate-500 text-sm">Hydrate React in the background whenever you need it.</p>
|
|
59
|
-
</div>
|
|
60
|
-
</div>
|
|
61
|
-
|
|
62
|
-
<footer class="text-slate-400 text-sm italic">
|
|
63
|
-
Served by Blue Bird Framework © 2026
|
|
64
|
-
</footer>
|
|
65
|
-
</main>
|
|
66
|
-
</div>
|
|
67
|
-
__SCRIPTS_BODY__
|
|
68
|
-
</body>
|
|
69
|
-
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="__LANG__">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>__TITLE__</title>
|
|
8
|
+
<meta name="description" content="__DESCRIPTION__">
|
|
9
|
+
<meta name="keywords" content="__KEYWORDS__">
|
|
10
|
+
<meta name="author" content="__AUTHOR__">
|
|
11
|
+
<link rel="icon" href="/favicon.ico" />
|
|
12
|
+
__HEAD_OPTIONS__
|
|
13
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
14
|
+
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;700&display=swap" rel="stylesheet">
|
|
15
|
+
<style>
|
|
16
|
+
body {
|
|
17
|
+
font-family: 'Outfit', sans-serif;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.hero-gradient {
|
|
21
|
+
background: radial-gradient(circle at top right, #f0f9ff 0%, #ffffff 100%);
|
|
22
|
+
}
|
|
23
|
+
</style>
|
|
24
|
+
__LINK_STYLES__
|
|
25
|
+
__SCRIPTS_HEAD__
|
|
26
|
+
__VITE_ASSETS__
|
|
27
|
+
__STYLES_SKELETON__
|
|
28
|
+
</head>
|
|
29
|
+
|
|
30
|
+
<body class="__CLASS_BODY__ hero-gradient min-h-screen">
|
|
31
|
+
<div id="root">
|
|
32
|
+
<!-- Landing Content -->
|
|
33
|
+
<nav class="p-6 flex justify-between items-center max-w-7xl mx-auto">
|
|
34
|
+
<div class="text-2xl font-bold text-sky-600">Blue Bird</div>
|
|
35
|
+
<div class="space-x-6 text-slate-600 font-medium">
|
|
36
|
+
<a href="#features" class="hover:text-sky-600">Features</a>
|
|
37
|
+
</div>
|
|
38
|
+
</nav>
|
|
39
|
+
|
|
40
|
+
<main class="max-w-7xl mx-auto px-6 pt-20 pb-32 text-center">
|
|
41
|
+
<h1 class="text-6xl md:text-8xl font-black text-slate-900 mb-8 tracking-tight">
|
|
42
|
+
Built for <span class="text-sky-600">Speed.</span>
|
|
43
|
+
</h1>
|
|
44
|
+
<p class="text-xl text-slate-600 max-w-2xl mx-auto mb-12 leading-relaxed">
|
|
45
|
+
This page was served in under 1ms thanks to Blue Bird's in-memory caching. No heavy bundles, just pure
|
|
46
|
+
performance.
|
|
47
|
+
</p>
|
|
48
|
+
|
|
49
|
+
<div class="flex flex-col sm:flex-row justify-center gap-4 mb-20">
|
|
50
|
+
<div class="p-8 bg-white rounded-3xl shadow-xl shadow-sky-100 border border-slate-50 flex-1 max-w-sm">
|
|
51
|
+
<div class="text-3xl mb-4">🚀</div>
|
|
52
|
+
<h3 class="font-bold text-xl mb-2">Static First</h3>
|
|
53
|
+
<p class="text-slate-500 text-sm">Perfect for SEO and instant first contentful paint.</p>
|
|
54
|
+
</div>
|
|
55
|
+
<div class="p-8 bg-white rounded-3xl shadow-xl shadow-sky-100 border border-slate-50 flex-1 max-w-sm">
|
|
56
|
+
<div class="text-3xl mb-4">💎</div>
|
|
57
|
+
<h3 class="font-bold text-xl mb-2">Hybrid Ready</h3>
|
|
58
|
+
<p class="text-slate-500 text-sm">Hydrate React in the background whenever you need it.</p>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<footer class="text-slate-400 text-sm italic">
|
|
63
|
+
Served by Blue Bird Framework © 2026
|
|
64
|
+
</footer>
|
|
65
|
+
</main>
|
|
66
|
+
</div>
|
|
67
|
+
__SCRIPTS_BODY__
|
|
68
|
+
</body>
|
|
69
|
+
|
|
70
70
|
</html>
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
@import "tailwindcss";
|
|
2
|
-
@custom-variant dark (&:where(.dark, .dark *));
|
|
3
|
-
|
|
4
|
-
@theme {
|
|
5
|
-
--font-sans: "Outfit", ui-sans-serif, system-ui, sans-serif;
|
|
6
|
-
--font-mono: "JetBrains Mono", ui-monospace, monospace;
|
|
7
|
-
|
|
8
|
-
--color-skye-50: #f0f9ff;
|
|
9
|
-
--color-skye-100: #e0f2fe;
|
|
10
|
-
--color-skye-200: #bae6fd;
|
|
11
|
-
--color-skye-300: #7dd3fc;
|
|
12
|
-
--color-skye-400: #38bdf8;
|
|
13
|
-
--color-skye-500: #0ea5e9;
|
|
14
|
-
--color-skye-600: #0284c7;
|
|
15
|
-
--color-skye-700: #0369a1;
|
|
16
|
-
--color-skye-800: #075985;
|
|
17
|
-
--color-skye-900: #0c4a6e;
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
@custom-variant dark (&:where(.dark, .dark *));
|
|
3
|
+
|
|
4
|
+
@theme {
|
|
5
|
+
--font-sans: "Outfit", ui-sans-serif, system-ui, sans-serif;
|
|
6
|
+
--font-mono: "JetBrains Mono", ui-monospace, monospace;
|
|
7
|
+
|
|
8
|
+
--color-skye-50: #f0f9ff;
|
|
9
|
+
--color-skye-100: #e0f2fe;
|
|
10
|
+
--color-skye-200: #bae6fd;
|
|
11
|
+
--color-skye-300: #7dd3fc;
|
|
12
|
+
--color-skye-400: #38bdf8;
|
|
13
|
+
--color-skye-500: #0ea5e9;
|
|
14
|
+
--color-skye-600: #0284c7;
|
|
15
|
+
--color-skye-700: #0369a1;
|
|
16
|
+
--color-skye-800: #075985;
|
|
17
|
+
--color-skye-900: #0c4a6e;
|
|
18
18
|
}
|
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
import React, { lazy, Suspense } from 'react';
|
|
2
|
-
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
|
|
3
|
-
import { ThemeProvider } from './blue-bird/contexts/ThemeContext.jsx';
|
|
4
|
-
import Skeleton from './blue-bird/components/Skeleton.jsx';
|
|
5
|
-
import { LanguageProvider } from './blue-bird/contexts/LanguageContext.jsx';
|
|
6
|
-
import { SPAProvider } from './blue-bird/contexts/SPAContext.jsx';
|
|
7
|
-
|
|
8
|
-
const Home = lazy(() => import('./pages/Home'));
|
|
9
|
-
const About = lazy(() => import('./pages/About'));
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Supported languages and default language.
|
|
13
|
-
* Leave LANGUAGES empty for monolingual applications.
|
|
14
|
-
*/
|
|
15
|
-
const LANGUAGES = ["en", "es"];
|
|
16
|
-
const DEFAULT_LANGUAGE = "en";
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Route definitions.
|
|
20
|
-
*/
|
|
21
|
-
const ROUTES = [
|
|
22
|
-
{ path: "/", element: <Home /> },
|
|
23
|
-
{ path: "/about", element: <About /> },
|
|
24
|
-
];
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Generates routes for all language prefixes if LANGUAGES is defined.
|
|
28
|
-
*/
|
|
29
|
-
function generateRoutes(routes, languages = []) {
|
|
30
|
-
const allRoutes = [];
|
|
31
|
-
|
|
32
|
-
routes.forEach(({ path: routePath, element }) => {
|
|
33
|
-
// Base path
|
|
34
|
-
allRoutes.push(
|
|
35
|
-
<Route key={routePath} path={routePath} element={element} />
|
|
36
|
-
);
|
|
37
|
-
|
|
38
|
-
// Language-prefixed paths (only if multiple languages are used)
|
|
39
|
-
if (languages && languages.length > 0) {
|
|
40
|
-
languages.forEach((lang) => {
|
|
41
|
-
const langPath = `/${lang}${routePath === "/" ? "" : routePath}`;
|
|
42
|
-
allRoutes.push(
|
|
43
|
-
<Route key={langPath} path={langPath} element={element} />
|
|
44
|
-
);
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
return allRoutes;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export default function App(_props) {
|
|
53
|
-
const { lang } = _props.props;
|
|
54
|
-
|
|
55
|
-
return (
|
|
56
|
-
<ThemeProvider>
|
|
57
|
-
<LanguageProvider initialLang={lang}>
|
|
58
|
-
<Router>
|
|
59
|
-
<SPAProvider languages={LANGUAGES} defaultLanguage={DEFAULT_LANGUAGE}>
|
|
60
|
-
<Suspense fallback={<Skeleton />}>
|
|
61
|
-
<Routes>
|
|
62
|
-
{generateRoutes(ROUTES, LANGUAGES)}
|
|
63
|
-
</Routes>
|
|
64
|
-
</Suspense>
|
|
65
|
-
</SPAProvider>
|
|
66
|
-
</Router>
|
|
67
|
-
</LanguageProvider>
|
|
68
|
-
</ThemeProvider>
|
|
69
|
-
);
|
|
70
|
-
}
|
|
1
|
+
import React, { lazy, Suspense } from 'react';
|
|
2
|
+
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
|
|
3
|
+
import { ThemeProvider } from './blue-bird/contexts/ThemeContext.jsx';
|
|
4
|
+
import Skeleton from './blue-bird/components/Skeleton.jsx';
|
|
5
|
+
import { LanguageProvider } from './blue-bird/contexts/LanguageContext.jsx';
|
|
6
|
+
import { SPAProvider } from './blue-bird/contexts/SPAContext.jsx';
|
|
7
|
+
|
|
8
|
+
const Home = lazy(() => import('./pages/Home'));
|
|
9
|
+
const About = lazy(() => import('./pages/About'));
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Supported languages and default language.
|
|
13
|
+
* Leave LANGUAGES empty for monolingual applications.
|
|
14
|
+
*/
|
|
15
|
+
const LANGUAGES = ["en", "es"];
|
|
16
|
+
const DEFAULT_LANGUAGE = "en";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Route definitions.
|
|
20
|
+
*/
|
|
21
|
+
const ROUTES = [
|
|
22
|
+
{ path: "/", element: <Home /> },
|
|
23
|
+
{ path: "/about", element: <About /> },
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Generates routes for all language prefixes if LANGUAGES is defined.
|
|
28
|
+
*/
|
|
29
|
+
function generateRoutes(routes, languages = []) {
|
|
30
|
+
const allRoutes = [];
|
|
31
|
+
|
|
32
|
+
routes.forEach(({ path: routePath, element }) => {
|
|
33
|
+
// Base path
|
|
34
|
+
allRoutes.push(
|
|
35
|
+
<Route key={routePath} path={routePath} element={element} />
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
// Language-prefixed paths (only if multiple languages are used)
|
|
39
|
+
if (languages && languages.length > 0) {
|
|
40
|
+
languages.forEach((lang) => {
|
|
41
|
+
const langPath = `/${lang}${routePath === "/" ? "" : routePath}`;
|
|
42
|
+
allRoutes.push(
|
|
43
|
+
<Route key={langPath} path={langPath} element={element} />
|
|
44
|
+
);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
return allRoutes;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export default function App(_props) {
|
|
53
|
+
const { lang } = _props.props;
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<ThemeProvider>
|
|
57
|
+
<LanguageProvider initialLang={lang}>
|
|
58
|
+
<Router>
|
|
59
|
+
<SPAProvider languages={LANGUAGES} defaultLanguage={DEFAULT_LANGUAGE}>
|
|
60
|
+
<Suspense fallback={<Skeleton />}>
|
|
61
|
+
<Routes>
|
|
62
|
+
{generateRoutes(ROUTES, LANGUAGES)}
|
|
63
|
+
</Routes>
|
|
64
|
+
</Suspense>
|
|
65
|
+
</SPAProvider>
|
|
66
|
+
</Router>
|
|
67
|
+
</LanguageProvider>
|
|
68
|
+
</ThemeProvider>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { createRoot } from 'react-dom/client';
|
|
3
|
-
import App from './App';
|
|
4
|
-
import "../css/tailwind.css"
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
8
|
-
document.querySelectorAll('[data-react-component]').forEach(el => {
|
|
9
|
-
const component = {
|
|
10
|
-
component: el.dataset.reactComponent
|
|
11
|
-
};
|
|
12
|
-
const props = JSON.parse(el.dataset.props || '{}');
|
|
13
|
-
const allProps = {
|
|
14
|
-
...props,
|
|
15
|
-
...component
|
|
16
|
-
}
|
|
17
|
-
createRoot(el).render(<App {...allProps} />);
|
|
18
|
-
});
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { createRoot } from 'react-dom/client';
|
|
3
|
+
import App from './App';
|
|
4
|
+
import "../css/tailwind.css"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
8
|
+
document.querySelectorAll('[data-react-component]').forEach(el => {
|
|
9
|
+
const component = {
|
|
10
|
+
component: el.dataset.reactComponent
|
|
11
|
+
};
|
|
12
|
+
const props = JSON.parse(el.dataset.props || '{}');
|
|
13
|
+
const allProps = {
|
|
14
|
+
...props,
|
|
15
|
+
...component
|
|
16
|
+
}
|
|
17
|
+
createRoot(el).render(<App {...allProps} />);
|
|
18
|
+
});
|
|
19
19
|
});
|
|
@@ -1,67 +1,67 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
|
|
3
|
-
export default function Button({ children, variant = 'default', size = 'default', className = '', ...props }) {
|
|
4
|
-
const baseStyle = "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50";
|
|
5
|
-
|
|
6
|
-
const variants = {
|
|
7
|
-
default: "bg-slate-900 dark:bg-slate-100 text-slate-50 dark:text-slate-900 hover:bg-slate-900/90 dark:hover:bg-slate-100/90",
|
|
8
|
-
destructive: "bg-red-500 text-slate-50 hover:bg-red-500/90 dark:bg-red-900 dark:hover:bg-red-900/90",
|
|
9
|
-
outline: "border border-slate-200 dark:border-slate-800 bg-white dark:bg-slate-900 text-slate-900 dark:text-slate-100 hover:bg-slate-100 dark:hover:bg-slate-800",
|
|
10
|
-
secondary: "bg-slate-100 dark:bg-slate-800 text-slate-900 dark:text-slate-100 hover:bg-slate-100/80 dark:hover:bg-slate-800/80",
|
|
11
|
-
ghost: "hover:bg-slate-100 dark:hover:bg-slate-800 text-slate-900 dark:text-slate-100",
|
|
12
|
-
link: "text-slate-900 dark:text-slate-100 underline-offset-4 hover:underline",
|
|
13
|
-
fill: "bg-gray-100 dark:bg-slate-800 text-gray-900 dark:text-slate-100 hover:bg-gray-100/80 dark:hover:bg-slate-800/80 w-full",
|
|
14
|
-
blue: "bg-blue-500 text-white hover:bg-blue-500/90 w-full",
|
|
15
|
-
blue_light: "bg-blue-100 text-blue-500 hover:bg-blue-100/80 w-full font-semibold",
|
|
16
|
-
green: "bg-green-500 text-white hover:bg-green-500/90 w-full",
|
|
17
|
-
green_light: "bg-green-100 text-green-500 hover:bg-green-100/80 w-full font-semibold",
|
|
18
|
-
red: "bg-red-500 text-white hover:bg-red-500/90 w-full",
|
|
19
|
-
red_light: "bg-red-100 text-red-500 hover:bg-red-100/80 w-full font-semibold",
|
|
20
|
-
yellow: "bg-yellow-500 text-white hover:bg-yellow-500/90 w-full",
|
|
21
|
-
yellow_light: "bg-yellow-100 text-yellow-500 hover:bg-yellow-100/80 w-full font-semibold",
|
|
22
|
-
purple: "bg-purple-500 text-white hover:bg-purple-500/90 w-full",
|
|
23
|
-
purple_light: "bg-purple-100 text-purple-500 hover:bg-purple-100/80 w-full font-semibold",
|
|
24
|
-
pink: "bg-pink-500 text-white hover:bg-pink-500/90 w-full",
|
|
25
|
-
pink_light: "bg-pink-100 text-pink-500 hover:bg-pink-100/80 w-full font-semibold",
|
|
26
|
-
orange: "bg-orange-500 text-white hover:bg-orange-500/90 w-full",
|
|
27
|
-
orange_light: "bg-orange-100 text-orange-500 hover:bg-orange-100/80 w-full font-semibold",
|
|
28
|
-
cyan: "bg-cyan-500 text-white hover:bg-cyan-500/90 w-full",
|
|
29
|
-
cyan_light: "bg-cyan-100 text-cyan-500 hover:bg-cyan-100/80 w-full font-semibold",
|
|
30
|
-
teal: "bg-teal-500 text-white hover:bg-teal-500/90 w-full",
|
|
31
|
-
teal_light: "bg-teal-100 text-teal-500 hover:bg-teal-100/80 w-full font-semibold",
|
|
32
|
-
lime: "bg-lime-500 text-white hover:bg-lime-500/90 w-full",
|
|
33
|
-
lime_light: "bg-lime-100 text-lime-500 hover:bg-lime-100/80 w-full font-semibold",
|
|
34
|
-
indigo: "bg-indigo-500 text-white hover:bg-indigo-500/90 w-full",
|
|
35
|
-
indigo_light: "bg-indigo-100 text-indigo-500 hover:bg-indigo-100/80 w-full font-semibold",
|
|
36
|
-
violet: "bg-violet-500 text-white hover:bg-violet-500/90 w-full",
|
|
37
|
-
violet_light: "bg-violet-100 text-violet-500 hover:bg-violet-100/80 w-full font-semibold",
|
|
38
|
-
fuchsia: "bg-fuchsia-500 text-white hover:bg-fuchsia-500/90 w-full",
|
|
39
|
-
fuchsia_light: "bg-fuchsia-100 text-fuchsia-500 hover:bg-fuchsia-100/80 w-full font-semibold",
|
|
40
|
-
rose: "bg-rose-500 text-white hover:bg-rose-500/90 w-full",
|
|
41
|
-
rose_light: "bg-rose-100 text-rose-500 hover:bg-rose-100/80 w-full font-semibold",
|
|
42
|
-
emerald: "bg-emerald-500 text-white hover:bg-emerald-500/90 w-full",
|
|
43
|
-
emerald_light: "bg-emerald-100 text-emerald-500 hover:bg-emerald-100/80 w-full font-semibold",
|
|
44
|
-
sky: "bg-sky-500 text-white hover:bg-sky-500/90 w-full",
|
|
45
|
-
sky_light: "bg-sky-100 text-sky-500 hover:bg-sky-100/80 w-full font-semibold",
|
|
46
|
-
slate: "bg-slate-500 text-white hover:bg-slate-500/90 w-full",
|
|
47
|
-
gray: "bg-gray-500 text-white hover:bg-gray-500/90 w-full",
|
|
48
|
-
zinc: "bg-zinc-500 text-white hover:bg-zinc-500/90 w-full",
|
|
49
|
-
neutral: "bg-neutral-500 text-white hover:bg-neutral-500/90 w-full",
|
|
50
|
-
stone: "bg-stone-500 text-white hover:bg-stone-500/90 w-full",
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
const sizes = {
|
|
54
|
-
default: "h-10 px-4 py-2",
|
|
55
|
-
sm: "h-9 rounded-md px-3",
|
|
56
|
-
lg: "h-11 rounded-md px-8",
|
|
57
|
-
icon: "h-10 w-10"
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const style = `${baseStyle} ${variants[variant] || variants.default} ${sizes[size] || sizes.default} ${className}`;
|
|
61
|
-
|
|
62
|
-
return (
|
|
63
|
-
<button className={style} {...props}>
|
|
64
|
-
{children}
|
|
65
|
-
</button>
|
|
66
|
-
);
|
|
67
|
-
}
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
export default function Button({ children, variant = 'default', size = 'default', className = '', ...props }) {
|
|
4
|
+
const baseStyle = "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50";
|
|
5
|
+
|
|
6
|
+
const variants = {
|
|
7
|
+
default: "bg-slate-900 dark:bg-slate-100 text-slate-50 dark:text-slate-900 hover:bg-slate-900/90 dark:hover:bg-slate-100/90",
|
|
8
|
+
destructive: "bg-red-500 text-slate-50 hover:bg-red-500/90 dark:bg-red-900 dark:hover:bg-red-900/90",
|
|
9
|
+
outline: "border border-slate-200 dark:border-slate-800 bg-white dark:bg-slate-900 text-slate-900 dark:text-slate-100 hover:bg-slate-100 dark:hover:bg-slate-800",
|
|
10
|
+
secondary: "bg-slate-100 dark:bg-slate-800 text-slate-900 dark:text-slate-100 hover:bg-slate-100/80 dark:hover:bg-slate-800/80",
|
|
11
|
+
ghost: "hover:bg-slate-100 dark:hover:bg-slate-800 text-slate-900 dark:text-slate-100",
|
|
12
|
+
link: "text-slate-900 dark:text-slate-100 underline-offset-4 hover:underline",
|
|
13
|
+
fill: "bg-gray-100 dark:bg-slate-800 text-gray-900 dark:text-slate-100 hover:bg-gray-100/80 dark:hover:bg-slate-800/80 w-full",
|
|
14
|
+
blue: "bg-blue-500 text-white hover:bg-blue-500/90 w-full",
|
|
15
|
+
blue_light: "bg-blue-100 text-blue-500 hover:bg-blue-100/80 w-full font-semibold",
|
|
16
|
+
green: "bg-green-500 text-white hover:bg-green-500/90 w-full",
|
|
17
|
+
green_light: "bg-green-100 text-green-500 hover:bg-green-100/80 w-full font-semibold",
|
|
18
|
+
red: "bg-red-500 text-white hover:bg-red-500/90 w-full",
|
|
19
|
+
red_light: "bg-red-100 text-red-500 hover:bg-red-100/80 w-full font-semibold",
|
|
20
|
+
yellow: "bg-yellow-500 text-white hover:bg-yellow-500/90 w-full",
|
|
21
|
+
yellow_light: "bg-yellow-100 text-yellow-500 hover:bg-yellow-100/80 w-full font-semibold",
|
|
22
|
+
purple: "bg-purple-500 text-white hover:bg-purple-500/90 w-full",
|
|
23
|
+
purple_light: "bg-purple-100 text-purple-500 hover:bg-purple-100/80 w-full font-semibold",
|
|
24
|
+
pink: "bg-pink-500 text-white hover:bg-pink-500/90 w-full",
|
|
25
|
+
pink_light: "bg-pink-100 text-pink-500 hover:bg-pink-100/80 w-full font-semibold",
|
|
26
|
+
orange: "bg-orange-500 text-white hover:bg-orange-500/90 w-full",
|
|
27
|
+
orange_light: "bg-orange-100 text-orange-500 hover:bg-orange-100/80 w-full font-semibold",
|
|
28
|
+
cyan: "bg-cyan-500 text-white hover:bg-cyan-500/90 w-full",
|
|
29
|
+
cyan_light: "bg-cyan-100 text-cyan-500 hover:bg-cyan-100/80 w-full font-semibold",
|
|
30
|
+
teal: "bg-teal-500 text-white hover:bg-teal-500/90 w-full",
|
|
31
|
+
teal_light: "bg-teal-100 text-teal-500 hover:bg-teal-100/80 w-full font-semibold",
|
|
32
|
+
lime: "bg-lime-500 text-white hover:bg-lime-500/90 w-full",
|
|
33
|
+
lime_light: "bg-lime-100 text-lime-500 hover:bg-lime-100/80 w-full font-semibold",
|
|
34
|
+
indigo: "bg-indigo-500 text-white hover:bg-indigo-500/90 w-full",
|
|
35
|
+
indigo_light: "bg-indigo-100 text-indigo-500 hover:bg-indigo-100/80 w-full font-semibold",
|
|
36
|
+
violet: "bg-violet-500 text-white hover:bg-violet-500/90 w-full",
|
|
37
|
+
violet_light: "bg-violet-100 text-violet-500 hover:bg-violet-100/80 w-full font-semibold",
|
|
38
|
+
fuchsia: "bg-fuchsia-500 text-white hover:bg-fuchsia-500/90 w-full",
|
|
39
|
+
fuchsia_light: "bg-fuchsia-100 text-fuchsia-500 hover:bg-fuchsia-100/80 w-full font-semibold",
|
|
40
|
+
rose: "bg-rose-500 text-white hover:bg-rose-500/90 w-full",
|
|
41
|
+
rose_light: "bg-rose-100 text-rose-500 hover:bg-rose-100/80 w-full font-semibold",
|
|
42
|
+
emerald: "bg-emerald-500 text-white hover:bg-emerald-500/90 w-full",
|
|
43
|
+
emerald_light: "bg-emerald-100 text-emerald-500 hover:bg-emerald-100/80 w-full font-semibold",
|
|
44
|
+
sky: "bg-sky-500 text-white hover:bg-sky-500/90 w-full",
|
|
45
|
+
sky_light: "bg-sky-100 text-sky-500 hover:bg-sky-100/80 w-full font-semibold",
|
|
46
|
+
slate: "bg-slate-500 text-white hover:bg-slate-500/90 w-full",
|
|
47
|
+
gray: "bg-gray-500 text-white hover:bg-gray-500/90 w-full",
|
|
48
|
+
zinc: "bg-zinc-500 text-white hover:bg-zinc-500/90 w-full",
|
|
49
|
+
neutral: "bg-neutral-500 text-white hover:bg-neutral-500/90 w-full",
|
|
50
|
+
stone: "bg-stone-500 text-white hover:bg-stone-500/90 w-full",
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const sizes = {
|
|
54
|
+
default: "h-10 px-4 py-2",
|
|
55
|
+
sm: "h-9 rounded-md px-3",
|
|
56
|
+
lg: "h-11 rounded-md px-8",
|
|
57
|
+
icon: "h-10 w-10"
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const style = `${baseStyle} ${variants[variant] || variants.default} ${sizes[size] || sizes.default} ${className}`;
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<button className={style} {...props}>
|
|
64
|
+
{children}
|
|
65
|
+
</button>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import Typography from './Typography';
|
|
3
|
-
|
|
4
|
-
export default function Card({ children, className = '', title, description, border = true, shadow = true }) {
|
|
5
|
-
return (
|
|
6
|
-
<div className={`rounded-lg ${border ? "border border-slate-200 dark:border-slate-800" : ""} ${shadow ? "shadow-sm" : ""} bg-white dark:bg-slate-900 text-slate-900 dark:text-slate-100 ${className}`}>
|
|
7
|
-
{(title || description) && (
|
|
8
|
-
<div className="flex flex-col space-y-1.5 p-6">
|
|
9
|
-
{title && <Typography variant='h5' className="font-semibold leading-none tracking-tight">{title}</Typography>}
|
|
10
|
-
{description && <Typography variant='p' className="text-sm text-slate-500 dark:text-slate-400">{description}</Typography>}
|
|
11
|
-
</div>
|
|
12
|
-
)}
|
|
13
|
-
<div className={`p-6 ${title || description ? 'pt-0' : ''}`}>
|
|
14
|
-
{children}
|
|
15
|
-
</div>
|
|
16
|
-
</div>
|
|
17
|
-
);
|
|
18
|
-
}
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Typography from './Typography';
|
|
3
|
+
|
|
4
|
+
export default function Card({ children, className = '', title, description, border = true, shadow = true }) {
|
|
5
|
+
return (
|
|
6
|
+
<div className={`rounded-lg ${border ? "border border-slate-200 dark:border-slate-800" : ""} ${shadow ? "shadow-sm" : ""} bg-white dark:bg-slate-900 text-slate-900 dark:text-slate-100 ${className}`}>
|
|
7
|
+
{(title || description) && (
|
|
8
|
+
<div className="flex flex-col space-y-1.5 p-6">
|
|
9
|
+
{title && <Typography variant='h5' className="font-semibold leading-none tracking-tight">{title}</Typography>}
|
|
10
|
+
{description && <Typography variant='p' className="text-sm text-slate-500 dark:text-slate-400">{description}</Typography>}
|
|
11
|
+
</div>
|
|
12
|
+
)}
|
|
13
|
+
<div className={`p-6 ${title || description ? 'pt-0' : ''}`}>
|
|
14
|
+
{children}
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
);
|
|
18
|
+
}
|