generator-kodly-react-app 1.0.6 → 1.0.10
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/generators/app/index.js +63 -11
- package/generators/app/templates/.env.dev +4 -0
- package/generators/app/templates/.env.sandbox +4 -0
- package/generators/app/templates/STRUCTURE.md +661 -0
- package/generators/app/templates/components.json +22 -0
- package/generators/app/templates/index.html +14 -6
- package/generators/app/templates/openapi-ts.config.ts +29 -0
- package/generators/app/templates/package.json +46 -26
- package/generators/app/templates/public/favicon.svg +4 -0
- package/generators/app/templates/src/app.tsx +8 -8
- package/generators/app/templates/src/components/layout/language-switcher.tsx +40 -0
- package/generators/app/templates/src/components/layout/theme-switcher.tsx +37 -0
- package/generators/app/templates/src/components/theme/theme-provider.tsx +22 -28
- package/generators/app/templates/src/components/ui/button.tsx +34 -32
- package/generators/app/templates/src/components/ui/card.tsx +76 -0
- package/generators/app/templates/src/components/ui/field.tsx +242 -0
- package/generators/app/templates/src/components/ui/form.tsx +129 -0
- package/generators/app/templates/src/components/ui/input-group.tsx +170 -0
- package/generators/app/templates/src/components/ui/input.tsx +19 -21
- package/generators/app/templates/src/components/ui/label.tsx +24 -0
- package/generators/app/templates/src/components/ui/select.tsx +184 -0
- package/generators/app/templates/src/components/ui/separator.tsx +31 -0
- package/generators/app/templates/src/components/ui/textarea.tsx +22 -0
- package/generators/app/templates/src/index.css +83 -26
- package/generators/app/templates/src/lib/api/client.ts +4 -5
- package/generators/app/templates/src/lib/i18n.ts +31 -16
- package/generators/app/templates/src/lib/routes.ts +14 -0
- package/generators/app/templates/src/lib/utils/error-handler.ts +7 -2
- package/generators/app/templates/src/lib/utils/init-form-schema.ts +12 -0
- package/generators/app/templates/src/lib/utils.ts +3 -4
- package/generators/app/templates/src/locales/en/common.json +5 -0
- package/generators/app/templates/src/locales/en/theme.json +5 -0
- package/generators/app/templates/src/locales/index.ts +31 -0
- package/generators/app/templates/src/locales/ja/common.json +5 -0
- package/generators/app/templates/src/locales/ja/theme.json +6 -0
- package/generators/app/templates/src/main.tsx +19 -15
- package/generators/app/templates/src/modules/app/layouts/app-layout.tsx +37 -0
- package/generators/app/templates/src/modules/app/locales/app-en.json +9 -0
- package/generators/app/templates/src/modules/app/locales/app-ja.json +9 -0
- package/generators/app/templates/src/modules/auth/components/forgot-password-form.tsx +74 -0
- package/generators/app/templates/src/modules/auth/components/login-form.tsx +95 -0
- package/generators/app/templates/src/modules/auth/components/reset-password-form.tsx +112 -0
- package/generators/app/templates/src/modules/auth/components/signup-form.tsx +92 -0
- package/generators/app/templates/src/modules/auth/contexts/auth-context.tsx +11 -0
- package/generators/app/templates/src/modules/auth/hooks/use-auth-hook.ts +175 -0
- package/generators/app/templates/src/modules/auth/layouts/auth-layout.tsx +28 -0
- package/generators/app/templates/src/modules/auth/locales/auth-en.json +105 -0
- package/generators/app/templates/src/modules/auth/locales/auth-ja.json +105 -0
- package/generators/app/templates/src/modules/landing/components/auth-hero.tsx +34 -0
- package/generators/app/templates/src/modules/landing/components/welcome-hero.tsx +24 -0
- package/generators/app/templates/src/modules/landing/landing-page-layout.tsx +24 -0
- package/generators/app/templates/src/modules/landing/landing-page.tsx +17 -0
- package/generators/app/templates/src/modules/landing/layouts/landing-page-layout.tsx +24 -0
- package/generators/app/templates/src/modules/landing/locales/landing-en.json +12 -0
- package/generators/app/templates/src/modules/landing/locales/landing-ja.json +11 -0
- package/generators/app/templates/src/openapi-client-config.ts +6 -0
- package/generators/app/templates/src/routeTree.gen.ts +268 -3
- package/generators/app/templates/src/router.tsx +2 -2
- package/generators/app/templates/src/routes/__root.tsx +3 -3
- package/generators/app/templates/src/routes/_landing/index.tsx +10 -0
- package/generators/app/templates/src/routes/_landing/route.tsx +14 -0
- package/generators/app/templates/src/routes/app/index.tsx +4 -21
- package/generators/app/templates/src/routes/app/route.tsx +12 -8
- package/generators/app/templates/src/routes/auth/forgot-password.tsx +10 -0
- package/generators/app/templates/src/routes/auth/login.tsx +6 -7
- package/generators/app/templates/src/routes/auth/reset-password.tsx +15 -0
- package/generators/app/templates/src/routes/auth/route.tsx +23 -6
- package/generators/app/templates/src/routes/auth/signup.tsx +11 -0
- package/generators/app/templates/src/sdk/@tanstack/react-query.gen.ts +91 -0
- package/generators/app/templates/src/sdk/client/client.gen.ts +167 -0
- package/generators/app/templates/src/sdk/client/index.ts +23 -0
- package/generators/app/templates/src/sdk/client/types.gen.ts +197 -0
- package/generators/app/templates/src/sdk/client/utils.gen.ts +213 -0
- package/generators/app/templates/src/sdk/client.gen.ts +18 -0
- package/generators/app/templates/src/sdk/core/auth.gen.ts +42 -0
- package/generators/app/templates/src/sdk/core/bodySerializer.gen.ts +100 -0
- package/generators/app/templates/src/sdk/core/params.gen.ts +176 -0
- package/generators/app/templates/src/sdk/core/pathSerializer.gen.ts +181 -0
- package/generators/app/templates/src/sdk/core/queryKeySerializer.gen.ts +136 -0
- package/generators/app/templates/src/sdk/core/serverSentEvents.gen.ts +266 -0
- package/generators/app/templates/src/sdk/core/types.gen.ts +118 -0
- package/generators/app/templates/src/sdk/core/utils.gen.ts +143 -0
- package/generators/app/templates/src/sdk/index.ts +4 -0
- package/generators/app/templates/src/sdk/schemas.gen.ts +195 -0
- package/generators/app/templates/src/sdk/sdk.gen.ts +80 -0
- package/generators/app/templates/src/sdk/types.gen.ts +158 -0
- package/generators/app/templates/src/sdk/zod.gen.ts +148 -0
- package/generators/app/templates/src/vite-env.d.ts +2 -1
- package/generators/app/templates/tsconfig.json +1 -1
- package/generators/app/templates/vite.config.js +35 -21
- package/generators/constants.js +9 -9
- package/package.json +3 -2
- package/generators/app/templates/.env.example +0 -5
- package/generators/app/templates/README.md +0 -57
- package/generators/app/templates/src/locales/en.json +0 -18
- package/generators/app/templates/src/modules/auth/auth-context.tsx +0 -13
- package/generators/app/templates/src/modules/auth/login/login-form.tsx +0 -49
- package/generators/app/templates/src/modules/auth/login/login-page.tsx +0 -12
- package/generators/app/templates/src/modules/auth/use-auth-hook.ts +0 -87
- package/generators/app/templates/src/routes/index.tsx +0 -12
- package/generators/app/templates/types.d.ts +0 -3
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { defineConfig } from '@hey-api/openapi-ts';
|
|
2
|
+
import { loadEnv } from 'vite';
|
|
3
|
+
|
|
4
|
+
// Get the mode from environment variable (set by npm scripts)
|
|
5
|
+
const mode = process.env.MODE || 'development';
|
|
6
|
+
|
|
7
|
+
// Load environment variables from .env files
|
|
8
|
+
const env = loadEnv(mode, process.cwd(), '');
|
|
9
|
+
|
|
10
|
+
export default defineConfig({
|
|
11
|
+
input: `${env.VITE_API_BASE_URL}/v3/api-docs`,
|
|
12
|
+
output: 'src/sdk',
|
|
13
|
+
plugins: [
|
|
14
|
+
{
|
|
15
|
+
name: '@hey-api/client-axios',
|
|
16
|
+
runtimeConfigPath: '@/openapi-client-config.ts',
|
|
17
|
+
},
|
|
18
|
+
'@tanstack/react-query',
|
|
19
|
+
'zod',
|
|
20
|
+
{
|
|
21
|
+
name: '@hey-api/sdk',
|
|
22
|
+
validator: true,
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: '@hey-api/schemas',
|
|
26
|
+
type: 'json',
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
});
|
|
@@ -1,42 +1,62 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "
|
|
2
|
+
"name": "app",
|
|
3
3
|
"private": true,
|
|
4
4
|
"type": "module",
|
|
5
5
|
"version": "0.0.1",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
7
|
+
"generate-routes": "tsr generate",
|
|
8
|
+
"watch-routes": "tsr watch",
|
|
9
|
+
"vite": "vite",
|
|
10
|
+
"vite:dev": "vite --mode dev",
|
|
11
|
+
"vite:sandbox": "vite --mode sandbox",
|
|
12
|
+
"dev": "npm-run-all --parallel watch-routes vite:dev",
|
|
13
|
+
"dev:sandbox": "npm-run-all --parallel watch-routes vite:sandbox",
|
|
14
|
+
"build": "npm run generate-routes && vite build --mode dev && tsc",
|
|
15
|
+
"build:sandbox": "npm run generate-routes && vite build --mode sandbox && tsc",
|
|
16
|
+
"serve": "vite preview",
|
|
17
|
+
"openapi-ts:dev": "MODE=dev openapi-ts",
|
|
18
|
+
"openapi-ts:sandbox": "MODE=sandbox openapi-ts"
|
|
11
19
|
},
|
|
12
20
|
"dependencies": {
|
|
21
|
+
"@hey-api/openapi-ts": "^0.90.2",
|
|
22
|
+
"@hookform/resolvers": "^5.2.2",
|
|
23
|
+
"@radix-ui/react-label": "^2.1.8",
|
|
24
|
+
"@radix-ui/react-select": "^2.2.6",
|
|
25
|
+
"@radix-ui/react-separator": "^1.1.8",
|
|
13
26
|
"@radix-ui/react-slot": "^1.2.4",
|
|
14
|
-
"@tanstack/react-query": "
|
|
15
|
-
"@tanstack/react-router": "
|
|
16
|
-
"@tanstack/router-plugin": "
|
|
17
|
-
"axios": "
|
|
27
|
+
"@tanstack/react-query": "^5.90.16",
|
|
28
|
+
"@tanstack/react-router": "^1.145.7",
|
|
29
|
+
"@tanstack/router-plugin": "^1.145.7",
|
|
30
|
+
"axios": "^1.13.2",
|
|
18
31
|
"class-variance-authority": "^0.7.1",
|
|
19
32
|
"clsx": "^2.1.1",
|
|
20
|
-
"dotenv": "
|
|
21
|
-
"i18next": "
|
|
22
|
-
"jotai": "
|
|
23
|
-
"lucide-react": "^0.
|
|
24
|
-
"react": "
|
|
25
|
-
"react-dom": "
|
|
26
|
-
"react-
|
|
33
|
+
"dotenv": "^17.2.3",
|
|
34
|
+
"i18next": "^25.7.3",
|
|
35
|
+
"jotai": "^2.16.1",
|
|
36
|
+
"lucide-react": "^0.562.0",
|
|
37
|
+
"react": "^19.2.3",
|
|
38
|
+
"react-dom": "^19.2.3",
|
|
39
|
+
"react-hook-form": "^7.70.0",
|
|
40
|
+
"react-i18next": "^16.5.1",
|
|
27
41
|
"sonner": "^2.0.7",
|
|
28
|
-
"tailwind-merge": "^3.4.0"
|
|
42
|
+
"tailwind-merge": "^3.4.0",
|
|
43
|
+
"tailwindcss-animate": "^1.0.7",
|
|
44
|
+
"tw-animate-css": "^1.4.0",
|
|
45
|
+
"zod": "^4.3.5",
|
|
46
|
+
"zod-empty": "^2.0.2"
|
|
29
47
|
},
|
|
30
48
|
"devDependencies": {
|
|
31
|
-
"@tailwindcss/postcss": "
|
|
32
|
-
"@tailwindcss/vite": "
|
|
33
|
-
"@
|
|
34
|
-
"@types/
|
|
49
|
+
"@tailwindcss/postcss": "^4.1.18",
|
|
50
|
+
"@tailwindcss/vite": "^4.1.18",
|
|
51
|
+
"@tanstack/router-cli": "^1.145.7",
|
|
52
|
+
"@types/node": "^25.0.3",
|
|
53
|
+
"@types/react": "^19.2.7",
|
|
35
54
|
"@types/react-dom": "^19.2.3",
|
|
36
|
-
"@vitejs/plugin-react": "^5.1.
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
55
|
+
"@vitejs/plugin-react": "^5.1.2",
|
|
56
|
+
"babel-plugin-react-compiler": "^1.0.0",
|
|
57
|
+
"npm-run-all": "^4.1.5",
|
|
58
|
+
"tailwindcss": "^4.1.18",
|
|
59
|
+
"typescript": "^5.9.3",
|
|
60
|
+
"vite": "^7.3.1"
|
|
41
61
|
}
|
|
42
62
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
|
2
|
+
<rect width="32" height="32" rx="10" fill="#000000"/>
|
|
3
|
+
<path d="M 9 7 L 9 25 M 9 16 L 19 7 M 9 16 L 19 25" stroke="#ffffff" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
|
4
|
+
</svg>
|
|
@@ -3,11 +3,11 @@ import { useAtomValue } from 'jotai';
|
|
|
3
3
|
import { Loader2 } from 'lucide-react';
|
|
4
4
|
import { useEffect } from 'react';
|
|
5
5
|
import { Toaster } from 'sonner';
|
|
6
|
-
import '
|
|
7
|
-
import { AuthProvider } from '
|
|
8
|
-
import { authTokenAtom, currentUserDetailsAtom, useValidateToken,
|
|
9
|
-
import { router } from '
|
|
10
|
-
import { getLanguage } from '
|
|
6
|
+
import '@/index.css';
|
|
7
|
+
import { AuthProvider } from '@/modules/auth/contexts/auth-context';
|
|
8
|
+
import { authTokenAtom, currentUserDetailsAtom, useValidateToken, setLocaleInClient } from '@/modules/auth/hooks/use-auth-hook';
|
|
9
|
+
import { router } from '@/router';
|
|
10
|
+
import { getLanguage, SupportedLanguages } from '@/lib/i18n';
|
|
11
11
|
|
|
12
12
|
declare module '@tanstack/react-router' {
|
|
13
13
|
interface Register {
|
|
@@ -31,13 +31,13 @@ export default function App() {
|
|
|
31
31
|
const token = useAtomValue(authTokenAtom);
|
|
32
32
|
|
|
33
33
|
useEffect(() => {
|
|
34
|
-
const currentLanguage = getLanguage() as
|
|
35
|
-
|
|
34
|
+
const currentLanguage = getLanguage() as SupportedLanguages;
|
|
35
|
+
setLocaleInClient(currentLanguage);
|
|
36
36
|
}, []);
|
|
37
37
|
|
|
38
38
|
useEffect(() => {
|
|
39
39
|
if (token) {
|
|
40
|
-
mutate();
|
|
40
|
+
mutate({});
|
|
41
41
|
}
|
|
42
42
|
}, [token, mutate]);
|
|
43
43
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
|
2
|
+
import { getLanguage, changeLanguage } from '@/lib/i18n';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import { useEffect, useState } from 'react';
|
|
5
|
+
|
|
6
|
+
export function LanguageSwitcher() {
|
|
7
|
+
const { i18n } = useTranslation();
|
|
8
|
+
const [currentLang, setCurrentLang] = useState<'en' | 'ja'>(() => {
|
|
9
|
+
return (getLanguage() as 'en' | 'ja') || 'en';
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
const handleLanguageChange = (lng: string) => {
|
|
14
|
+
setCurrentLang(lng as 'en' | 'ja');
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
i18n.on('languageChanged', handleLanguageChange);
|
|
18
|
+
return () => {
|
|
19
|
+
i18n.off('languageChanged', handleLanguageChange);
|
|
20
|
+
};
|
|
21
|
+
}, [i18n]);
|
|
22
|
+
|
|
23
|
+
const handleLanguageChange = (value: string) => {
|
|
24
|
+
changeLanguage(value as 'en' | 'ja');
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<Select
|
|
29
|
+
value={currentLang}
|
|
30
|
+
onValueChange={handleLanguageChange}>
|
|
31
|
+
<SelectTrigger className='min-w-[120px]'>
|
|
32
|
+
<SelectValue />
|
|
33
|
+
</SelectTrigger>
|
|
34
|
+
<SelectContent>
|
|
35
|
+
<SelectItem value='en'>English</SelectItem>
|
|
36
|
+
<SelectItem value='ja'>日本語</SelectItem>
|
|
37
|
+
</SelectContent>
|
|
38
|
+
</Select>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Button } from '@/components/ui/button';
|
|
2
|
+
import { ThemeTypes, useTheme } from '@/components/theme/theme-provider';
|
|
3
|
+
import { Moon, Sun, Monitor } from 'lucide-react';
|
|
4
|
+
|
|
5
|
+
export function ThemeSwitcher() {
|
|
6
|
+
const { theme, setTheme } = useTheme();
|
|
7
|
+
|
|
8
|
+
const cycleTheme = () => {
|
|
9
|
+
const themes: ThemeTypes[] = ['light', 'dark', 'system'];
|
|
10
|
+
const currentIndex = themes.indexOf(theme);
|
|
11
|
+
const nextIndex = (currentIndex + 1) % themes.length;
|
|
12
|
+
setTheme(themes[nextIndex]);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const getIcon = () => {
|
|
16
|
+
switch (theme) {
|
|
17
|
+
case 'light':
|
|
18
|
+
return <Sun className='h-4 w-4' />;
|
|
19
|
+
case 'dark':
|
|
20
|
+
return <Moon className='h-4 w-4' />;
|
|
21
|
+
case 'system':
|
|
22
|
+
return <Monitor className='h-4 w-4' />;
|
|
23
|
+
default:
|
|
24
|
+
return <Monitor className='h-4 w-4' />;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<Button
|
|
30
|
+
variant='outline'
|
|
31
|
+
size='icon'
|
|
32
|
+
onClick={cycleTheme}
|
|
33
|
+
aria-label='Toggle theme'>
|
|
34
|
+
{getIcon()}
|
|
35
|
+
</Button>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
@@ -1,45 +1,41 @@
|
|
|
1
|
-
import { createContext, useContext, useEffect, useState } from
|
|
1
|
+
import { createContext, useContext, useEffect, useState } from 'react';
|
|
2
2
|
|
|
3
|
-
type
|
|
3
|
+
export type ThemeTypes = 'dark' | 'light' | 'system';
|
|
4
4
|
|
|
5
5
|
type ThemeProviderProps = {
|
|
6
6
|
children: React.ReactNode;
|
|
7
|
-
defaultTheme?:
|
|
7
|
+
defaultTheme?: ThemeTypes;
|
|
8
8
|
storageKey?: string;
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
type ThemeProviderState = {
|
|
12
|
-
theme:
|
|
13
|
-
setTheme: (theme:
|
|
12
|
+
theme: ThemeTypes;
|
|
13
|
+
setTheme: (theme: ThemeTypes) => void;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
const initialState: ThemeProviderState = {
|
|
17
|
-
theme:
|
|
17
|
+
theme: 'system' as ThemeTypes,
|
|
18
18
|
setTheme: () => null,
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
const ThemeProviderContext = createContext<ThemeProviderState>(initialState);
|
|
22
22
|
|
|
23
|
-
export function ThemeProvider({
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
);
|
|
23
|
+
export function ThemeProvider({ children, defaultTheme = 'system', storageKey = 'vite-ui-theme', ...props }: ThemeProviderProps) {
|
|
24
|
+
const [theme, setTheme] = useState<ThemeTypes>(() => {
|
|
25
|
+
const stored = localStorage.getItem(storageKey);
|
|
26
|
+
if (stored && ['dark', 'light', 'system'].includes(stored)) {
|
|
27
|
+
return stored as ThemeTypes;
|
|
28
|
+
}
|
|
29
|
+
return 'system';
|
|
30
|
+
});
|
|
32
31
|
|
|
33
32
|
useEffect(() => {
|
|
34
33
|
const root = window.document.documentElement;
|
|
35
34
|
|
|
36
|
-
root.classList.remove(
|
|
35
|
+
root.classList.remove('light', 'dark');
|
|
37
36
|
|
|
38
|
-
if (theme ===
|
|
39
|
-
const systemTheme = window.matchMedia(
|
|
40
|
-
.matches
|
|
41
|
-
? "dark"
|
|
42
|
-
: "light";
|
|
37
|
+
if (theme === 'system') {
|
|
38
|
+
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
43
39
|
root.classList.add(systemTheme);
|
|
44
40
|
return;
|
|
45
41
|
}
|
|
@@ -49,14 +45,16 @@ export function ThemeProvider({
|
|
|
49
45
|
|
|
50
46
|
const value = {
|
|
51
47
|
theme,
|
|
52
|
-
setTheme: (theme:
|
|
48
|
+
setTheme: (theme: ThemeTypes) => {
|
|
53
49
|
localStorage.setItem(storageKey, theme);
|
|
54
50
|
setTheme(theme);
|
|
55
51
|
},
|
|
56
52
|
};
|
|
57
53
|
|
|
58
54
|
return (
|
|
59
|
-
<ThemeProviderContext.Provider
|
|
55
|
+
<ThemeProviderContext.Provider
|
|
56
|
+
{...props}
|
|
57
|
+
value={value}>
|
|
60
58
|
{children}
|
|
61
59
|
</ThemeProviderContext.Provider>
|
|
62
60
|
);
|
|
@@ -64,10 +62,6 @@ export function ThemeProvider({
|
|
|
64
62
|
|
|
65
63
|
export const useTheme = () => {
|
|
66
64
|
const context = useContext(ThemeProviderContext);
|
|
67
|
-
|
|
68
|
-
if (context === undefined)
|
|
69
|
-
throw new Error("useTheme must be used within a ThemeProvider");
|
|
70
|
-
|
|
65
|
+
if (context === undefined) throw new Error('useTheme must be used within a ThemeProvider');
|
|
71
66
|
return context;
|
|
72
67
|
};
|
|
73
|
-
|
|
@@ -1,23 +1,28 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import { Slot } from "@radix-ui/react-slot"
|
|
3
|
-
import { cva, type VariantProps } from "class-variance-authority"
|
|
4
|
-
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { Slot } from "@radix-ui/react-slot"
|
|
3
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils"
|
|
5
6
|
|
|
6
7
|
const buttonVariants = cva(
|
|
7
|
-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-
|
|
8
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
8
9
|
{
|
|
9
10
|
variants: {
|
|
10
11
|
variant: {
|
|
11
|
-
default:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
default:
|
|
13
|
+
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
|
14
|
+
destructive:
|
|
15
|
+
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
|
16
|
+
outline:
|
|
17
|
+
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
|
|
18
|
+
secondary:
|
|
19
|
+
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
|
15
20
|
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
16
21
|
link: "text-primary underline-offset-4 hover:underline",
|
|
17
22
|
},
|
|
18
23
|
size: {
|
|
19
24
|
default: "h-9 px-4 py-2",
|
|
20
|
-
sm: "h-8 rounded-md px-3",
|
|
25
|
+
sm: "h-8 rounded-md px-3 text-xs",
|
|
21
26
|
lg: "h-10 rounded-md px-8",
|
|
22
27
|
icon: "h-9 w-9",
|
|
23
28
|
},
|
|
@@ -27,29 +32,26 @@ const buttonVariants = cva(
|
|
|
27
32
|
size: "default",
|
|
28
33
|
},
|
|
29
34
|
}
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
function Button({
|
|
33
|
-
className,
|
|
34
|
-
variant,
|
|
35
|
-
size,
|
|
36
|
-
asChild = false,
|
|
37
|
-
type,
|
|
38
|
-
...props
|
|
39
|
-
}: React.ComponentProps<"button"> &
|
|
40
|
-
VariantProps<typeof buttonVariants> & {
|
|
41
|
-
asChild?: boolean;
|
|
42
|
-
}) {
|
|
43
|
-
const Comp = asChild ? Slot : "button";
|
|
35
|
+
)
|
|
44
36
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
{...props}
|
|
50
|
-
/>
|
|
51
|
-
);
|
|
37
|
+
export interface ButtonProps
|
|
38
|
+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
39
|
+
VariantProps<typeof buttonVariants> {
|
|
40
|
+
asChild?: boolean
|
|
52
41
|
}
|
|
53
42
|
|
|
54
|
-
|
|
43
|
+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
44
|
+
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
45
|
+
const Comp = asChild ? Slot : "button"
|
|
46
|
+
return (
|
|
47
|
+
<Comp
|
|
48
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
49
|
+
ref={ref}
|
|
50
|
+
{...props}
|
|
51
|
+
/>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
)
|
|
55
|
+
Button.displayName = "Button"
|
|
55
56
|
|
|
57
|
+
export { Button, buttonVariants }
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
import { cn } from "@/lib/utils"
|
|
4
|
+
|
|
5
|
+
const Card = React.forwardRef<
|
|
6
|
+
HTMLDivElement,
|
|
7
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
8
|
+
>(({ className, ...props }, ref) => (
|
|
9
|
+
<div
|
|
10
|
+
ref={ref}
|
|
11
|
+
className={cn(
|
|
12
|
+
"rounded-xl border bg-card text-card-foreground shadow",
|
|
13
|
+
className
|
|
14
|
+
)}
|
|
15
|
+
{...props}
|
|
16
|
+
/>
|
|
17
|
+
))
|
|
18
|
+
Card.displayName = "Card"
|
|
19
|
+
|
|
20
|
+
const CardHeader = React.forwardRef<
|
|
21
|
+
HTMLDivElement,
|
|
22
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
23
|
+
>(({ className, ...props }, ref) => (
|
|
24
|
+
<div
|
|
25
|
+
ref={ref}
|
|
26
|
+
className={cn("flex flex-col space-y-1.5 p-6", className)}
|
|
27
|
+
{...props}
|
|
28
|
+
/>
|
|
29
|
+
))
|
|
30
|
+
CardHeader.displayName = "CardHeader"
|
|
31
|
+
|
|
32
|
+
const CardTitle = React.forwardRef<
|
|
33
|
+
HTMLDivElement,
|
|
34
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
35
|
+
>(({ className, ...props }, ref) => (
|
|
36
|
+
<div
|
|
37
|
+
ref={ref}
|
|
38
|
+
className={cn("font-semibold leading-none tracking-tight", className)}
|
|
39
|
+
{...props}
|
|
40
|
+
/>
|
|
41
|
+
))
|
|
42
|
+
CardTitle.displayName = "CardTitle"
|
|
43
|
+
|
|
44
|
+
const CardDescription = React.forwardRef<
|
|
45
|
+
HTMLDivElement,
|
|
46
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
47
|
+
>(({ className, ...props }, ref) => (
|
|
48
|
+
<div
|
|
49
|
+
ref={ref}
|
|
50
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
51
|
+
{...props}
|
|
52
|
+
/>
|
|
53
|
+
))
|
|
54
|
+
CardDescription.displayName = "CardDescription"
|
|
55
|
+
|
|
56
|
+
const CardContent = React.forwardRef<
|
|
57
|
+
HTMLDivElement,
|
|
58
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
59
|
+
>(({ className, ...props }, ref) => (
|
|
60
|
+
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
|
|
61
|
+
))
|
|
62
|
+
CardContent.displayName = "CardContent"
|
|
63
|
+
|
|
64
|
+
const CardFooter = React.forwardRef<
|
|
65
|
+
HTMLDivElement,
|
|
66
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
67
|
+
>(({ className, ...props }, ref) => (
|
|
68
|
+
<div
|
|
69
|
+
ref={ref}
|
|
70
|
+
className={cn("flex items-center p-6 pt-0", className)}
|
|
71
|
+
{...props}
|
|
72
|
+
/>
|
|
73
|
+
))
|
|
74
|
+
CardFooter.displayName = "CardFooter"
|
|
75
|
+
|
|
76
|
+
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
|