create-lumen 1.1.3 → 1.2.0-beta.1
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 +43 -35
- package/package.json +8 -2
- package/src/configure.js +29 -15
- package/src/css.js +73 -14
- package/src/dependencies.js +8 -3
- package/src/format.js +28 -0
- package/src/injector.js +131 -28
- package/src/main.js +17 -1
- package/src/readme.js +65 -22
- package/templates/architectures/component-based/main.tsx +1 -1
- package/templates/architectures/component-based/src/App.jsx +6 -4
- package/templates/architectures/component-based/src/App.tsx +6 -4
- package/templates/architectures/component-based/src/components/common/Button.jsx +5 -4
- package/templates/architectures/component-based/src/components/common/Button.tsx +5 -4
- package/templates/architectures/component-based/src/hooks/useApp.js +10 -0
- package/templates/architectures/component-based/src/hooks/useApp.ts +10 -0
- package/templates/architectures/component-based/src/hooks/useLocalStorage.ts +5 -5
- package/templates/architectures/component-based/src/layouts/MainLayout.jsx +12 -6
- package/templates/architectures/component-based/src/layouts/MainLayout.tsx +12 -6
- package/templates/architectures/component-based/src/pages/Home/Home.jsx +6 -2
- package/templates/architectures/component-based/src/pages/Home/Home.tsx +6 -2
- package/templates/architectures/component-based/src/providers/AppProvider.jsx +20 -0
- package/templates/architectures/component-based/src/providers/AppProvider.tsx +24 -0
- package/templates/architectures/component-based/src/providers/appcontext.js +3 -0
- package/templates/architectures/component-based/src/providers/appcontext.ts +8 -0
- package/templates/architectures/{feature-based → component-based}/src/types/index.js +7 -0
- package/templates/architectures/{feature-based → component-based}/src/types/index.ts +5 -0
- package/templates/architectures/component-based/src/utils/cn.ts +3 -1
- package/templates/architectures/feature-based/main.jsx +1 -1
- package/templates/architectures/feature-based/main.tsx +2 -2
- package/templates/architectures/feature-based/scripts/create-feature.mjs +2 -2
- package/templates/architectures/feature-based/src/app/App.jsx +15 -5
- package/templates/architectures/feature-based/src/app/App.tsx +15 -5
- package/templates/architectures/feature-based/src/app/contexts/themecontext.js +3 -0
- package/templates/architectures/feature-based/src/app/contexts/themecontext.ts +8 -0
- package/templates/architectures/feature-based/src/app/hooks/useTheme.js +10 -0
- package/templates/architectures/feature-based/src/app/hooks/useTheme.ts +10 -0
- package/templates/architectures/feature-based/src/app/providers/ThemeProvider.jsx +17 -2
- package/templates/architectures/feature-based/src/app/providers/ThemeProvider.tsx +20 -3
- package/templates/architectures/feature-based/src/features/home/pages/HomePage.jsx +18 -5
- package/templates/architectures/feature-based/src/features/home/pages/HomePage.tsx +18 -5
- package/templates/architectures/feature-based/src/shared/components/ui/Button.jsx +31 -0
- package/templates/architectures/feature-based/src/shared/components/ui/Button.tsx +36 -0
- package/templates/architectures/feature-based/src/{hooks → shared/hooks}/useLocalStorage.ts +5 -5
- package/templates/architectures/feature-based/src/shared/layouts/.gitkeep +0 -0
- package/templates/architectures/feature-based/src/shared/stores/.gitkeep +0 -0
- package/templates/architectures/feature-based/src/shared/styles/.gitkeep +0 -0
- package/templates/architectures/feature-based/src/shared/types/index.js +20 -0
- package/templates/architectures/feature-based/src/shared/types/index.ts +16 -0
- package/templates/architectures/feature-based/src/shared/utils/cn.ts +5 -0
- package/templates/conditional/axios/component-based/src/config/axios.config.js +7 -0
- package/templates/conditional/axios/component-based/src/config/axios.config.ts +7 -0
- package/templates/conditional/axios/component-based/src/services/axios.client.js +24 -0
- package/templates/conditional/axios/component-based/src/services/axios.client.ts +24 -0
- package/templates/conditional/axios/component-based/src/services/user.service.js +33 -0
- package/templates/conditional/axios/component-based/src/services/user.service.ts +29 -0
- package/templates/conditional/axios/feature-based/src/features/home/services/user.service.js +33 -0
- package/templates/conditional/axios/feature-based/src/features/home/services/user.service.ts +29 -0
- package/templates/conditional/axios/feature-based/src/shared/lib/axios/api.client.js +24 -0
- package/templates/conditional/axios/feature-based/src/shared/lib/axios/api.client.ts +24 -0
- package/templates/conditional/axios/feature-based/src/shared/lib/axios/api.config.js +7 -0
- package/templates/conditional/axios/feature-based/src/shared/lib/axios/api.config.ts +7 -0
- package/templates/conditional/axios/feature-based/src/shared/lib/axios/index.js +1 -0
- package/templates/conditional/axios/feature-based/src/shared/lib/axios/index.ts +1 -0
- package/templates/conditional/fetch/component-based/src/config/api.config.js +7 -0
- package/templates/conditional/fetch/component-based/src/config/api.config.ts +7 -0
- package/templates/conditional/fetch/component-based/src/services/api.client.js +51 -0
- package/templates/conditional/fetch/component-based/src/services/api.client.ts +55 -0
- package/templates/conditional/fetch/component-based/src/services/user.service.js +33 -0
- package/templates/conditional/fetch/component-based/src/services/user.service.ts +29 -0
- package/templates/conditional/fetch/feature-based/src/features/home/services/user.service.js +33 -0
- package/templates/conditional/fetch/feature-based/src/features/home/services/user.service.ts +29 -0
- package/templates/conditional/fetch/feature-based/src/shared/api/api.client.js +51 -0
- package/templates/conditional/fetch/feature-based/src/shared/api/api.client.ts +55 -0
- package/templates/conditional/fetch/feature-based/src/shared/api/api.config.js +7 -0
- package/templates/conditional/fetch/feature-based/src/shared/api/api.config.ts +7 -0
- package/templates/conditional/fetch/feature-based/src/shared/api/index.js +1 -0
- package/templates/conditional/fetch/feature-based/src/shared/api/index.ts +1 -0
- package/templates/conditional/formatter/oxfmt/.oxfmtrc.json +1 -1
- package/templates/conditional/formatter/prettier/.prettierrc +2 -2
- package/templates/conditional/icons/huge/component-based/bootstrap/src/pages/Home/Home.jsx +20 -0
- package/templates/conditional/icons/huge/component-based/bootstrap/src/pages/Home/Home.tsx +20 -0
- package/templates/conditional/icons/huge/component-based/src/pages/Home/Home.jsx +26 -10
- package/templates/conditional/icons/huge/component-based/src/pages/Home/Home.tsx +26 -10
- package/templates/conditional/icons/huge/component-based/tailwind/src/pages/Home/Home.jsx +20 -0
- package/templates/conditional/icons/huge/component-based/tailwind/src/pages/Home/Home.tsx +20 -0
- package/templates/conditional/icons/huge/feature-based/bootstrap/src/features/home/pages/HomePage.jsx +20 -0
- package/templates/conditional/icons/huge/feature-based/bootstrap/src/features/home/pages/HomePage.tsx +20 -0
- package/templates/conditional/icons/huge/feature-based/src/features/home/pages/HomePage.jsx +27 -11
- package/templates/conditional/icons/huge/feature-based/src/features/home/pages/HomePage.tsx +27 -11
- package/templates/conditional/icons/huge/feature-based/tailwind/src/features/home/pages/HomePage.jsx +20 -0
- package/templates/conditional/icons/huge/feature-based/tailwind/src/features/home/pages/HomePage.tsx +20 -0
- package/templates/conditional/icons/lucide/component-based/bootstrap/src/pages/Home/Home.jsx +19 -0
- package/templates/conditional/icons/lucide/component-based/bootstrap/src/pages/Home/Home.tsx +19 -0
- package/templates/conditional/icons/lucide/component-based/src/pages/Home/Home.jsx +25 -10
- package/templates/conditional/icons/lucide/component-based/src/pages/Home/Home.tsx +25 -10
- package/templates/conditional/icons/lucide/component-based/tailwind/src/pages/Home/Home.jsx +19 -0
- package/templates/conditional/icons/lucide/component-based/tailwind/src/pages/Home/Home.tsx +19 -0
- package/templates/conditional/icons/lucide/feature-based/bootstrap/src/features/home/pages/HomePage.jsx +19 -0
- package/templates/conditional/icons/lucide/feature-based/bootstrap/src/features/home/pages/HomePage.tsx +19 -0
- package/templates/conditional/icons/lucide/feature-based/src/features/home/pages/HomePage.jsx +26 -11
- package/templates/conditional/icons/lucide/feature-based/src/features/home/pages/HomePage.tsx +26 -11
- package/templates/conditional/icons/lucide/feature-based/tailwind/src/features/home/pages/HomePage.jsx +19 -0
- package/templates/conditional/icons/lucide/feature-based/tailwind/src/features/home/pages/HomePage.tsx +19 -0
- package/templates/conditional/linting/eslint/eslint.config.js +24 -2
- package/templates/conditional/linting/eslint/eslint.config.ts +25 -2
- package/templates/conditional/router/component-based/bootstrap/src/layouts/MainLayout.jsx +17 -0
- package/templates/conditional/router/component-based/bootstrap/src/layouts/MainLayout.tsx +17 -0
- package/templates/conditional/router/component-based/src/App.jsx +4 -5
- package/templates/conditional/router/component-based/src/App.tsx +4 -5
- package/templates/conditional/router/component-based/src/layouts/MainLayout.jsx +39 -0
- package/templates/conditional/router/component-based/src/layouts/MainLayout.tsx +39 -0
- package/templates/conditional/router/component-based/src/router/guards/AuthGuard.jsx +8 -0
- package/templates/conditional/router/component-based/src/router/guards/AuthGuard.tsx +14 -0
- package/templates/conditional/router/component-based/src/router/guards/GuestGuard.jsx +8 -0
- package/templates/conditional/router/component-based/src/router/guards/GuestGuard.tsx +14 -0
- package/templates/conditional/router/component-based/src/router/index.jsx +44 -0
- package/templates/conditional/router/component-based/src/router/index.tsx +44 -0
- package/templates/conditional/router/component-based/tailwind/src/layouts/MainLayout.jsx +17 -0
- package/templates/conditional/router/component-based/tailwind/src/layouts/MainLayout.tsx +17 -0
- package/templates/conditional/router/feature-based/bootstrap/src/shared/layouts/RootLayout.jsx +9 -0
- package/templates/conditional/router/feature-based/bootstrap/src/shared/layouts/RootLayout.tsx +9 -0
- package/templates/conditional/router/feature-based/src/app/App.jsx +6 -2
- package/templates/conditional/router/feature-based/src/app/App.tsx +6 -2
- package/templates/conditional/router/feature-based/src/app/router/guards/AuthGuard.jsx +8 -0
- package/templates/conditional/router/feature-based/src/app/router/guards/AuthGuard.tsx +14 -0
- package/templates/conditional/router/feature-based/src/app/router/guards/RoleGuard.jsx +8 -0
- package/templates/conditional/router/feature-based/src/app/router/guards/RoleGuard.tsx +15 -0
- package/templates/conditional/router/feature-based/src/app/router/index.jsx +16 -0
- package/templates/conditional/router/feature-based/src/app/router/index.tsx +16 -0
- package/templates/conditional/router/feature-based/src/app/router/routes/auth.routes.jsx +18 -0
- package/templates/conditional/router/feature-based/src/app/router/routes/auth.routes.tsx +18 -0
- package/templates/conditional/router/feature-based/src/app/router/routes/home.routes.jsx +8 -0
- package/templates/conditional/router/feature-based/src/app/router/routes/home.routes.tsx +8 -0
- package/templates/conditional/router/feature-based/src/shared/layouts/RootLayout.jsx +17 -0
- package/templates/conditional/router/feature-based/src/shared/layouts/RootLayout.tsx +17 -0
- package/templates/conditional/router/feature-based/tailwind/src/shared/layouts/RootLayout.jsx +9 -0
- package/templates/conditional/router/feature-based/tailwind/src/shared/layouts/RootLayout.tsx +9 -0
- package/templates/conditional/state/redux/component-based/src/pages/Home/counterSlice.ts +9 -3
- package/templates/conditional/state/redux/component-based/src/{context → providers}/StoreProvider.jsx +0 -1
- package/templates/conditional/state/redux/component-based/src/{context → providers}/StoreProvider.tsx +2 -2
- package/templates/conditional/state/redux/component-based/src/store/hooks.ts +4 -2
- package/templates/conditional/state/redux/component-based/src/store/index.ts +2 -2
- package/templates/conditional/state/redux/feature-based/src/app/providers/StoreProvider.jsx +1 -2
- package/templates/conditional/state/redux/feature-based/src/app/providers/StoreProvider.tsx +3 -3
- package/templates/conditional/state/redux/feature-based/src/features/home/store/counterSlice.ts +9 -3
- package/templates/conditional/state/redux/feature-based/src/shared/stores/hooks.ts +6 -0
- package/templates/conditional/state/redux/feature-based/src/{stores → shared/stores}/index.ts +2 -2
- package/templates/conditional/state/zustand/component-based/src/store/useCounterStore.ts +8 -1
- package/templates/conditional/state/zustand/feature-based/src/stores/useCounterStore.ts +8 -1
- package/templates/conditional/testing/jest/babel.config.cjs +7 -0
- package/templates/conditional/testing/jest/component-based/src/__tests__/App.test.jsx +10 -0
- package/templates/conditional/testing/jest/component-based/src/__tests__/App.test.tsx +11 -0
- package/templates/conditional/testing/jest/{src → feature-based/src}/__tests__/App.test.jsx +2 -1
- package/templates/conditional/testing/jest/feature-based/src/__tests__/App.test.tsx +11 -0
- package/templates/conditional/testing/jest/jest.config.js +2 -3
- package/templates/conditional/testing/jest/jest.config.ts +6 -4
- package/templates/conditional/testing/jest/jest.setup.js +6 -0
- package/templates/conditional/testing/jest/jest.setup.ts +6 -0
- package/templates/conditional/testing/vitest/component-based/src/__tests__/App.test.jsx +10 -0
- package/templates/conditional/testing/{jest → vitest/component-based}/src/__tests__/App.test.tsx +2 -1
- package/templates/css/bootstrap/src/themes.css +14 -0
- package/templates/css/component-styles/bootstrap/component-based/src/components/common/Button.jsx +17 -0
- package/templates/css/component-styles/bootstrap/component-based/src/components/common/Button.tsx +22 -0
- package/templates/css/component-styles/bootstrap/component-based/src/layouts/MainLayout.jsx +15 -0
- package/templates/css/component-styles/bootstrap/component-based/src/layouts/MainLayout.tsx +19 -0
- package/templates/css/component-styles/bootstrap/component-based/src/pages/Home/Home.jsx +13 -0
- package/templates/css/component-styles/bootstrap/component-based/src/pages/Home/Home.tsx +13 -0
- package/templates/css/component-styles/bootstrap/feature-based/src/app/App.jsx +9 -0
- package/templates/css/component-styles/bootstrap/feature-based/src/app/App.tsx +9 -0
- package/templates/css/component-styles/bootstrap/feature-based/src/features/home/pages/HomePage.jsx +13 -0
- package/templates/css/component-styles/bootstrap/feature-based/src/features/home/pages/HomePage.tsx +13 -0
- package/templates/css/component-styles/bootstrap/feature-based/src/shared/components/ui/Button.jsx +17 -0
- package/templates/css/component-styles/bootstrap/feature-based/src/shared/components/ui/Button.tsx +22 -0
- package/templates/{architectures/feature-based/src/components/ui → css/component-styles/tailwind/component-based/src/components/common}/Button.jsx +1 -3
- package/templates/{architectures/feature-based/src/components/ui → css/component-styles/tailwind/component-based/src/components/common}/Button.tsx +1 -3
- package/templates/css/component-styles/tailwind/component-based/src/layouts/MainLayout.jsx +15 -0
- package/templates/css/component-styles/tailwind/component-based/src/layouts/MainLayout.tsx +19 -0
- package/templates/css/component-styles/tailwind/component-based/src/pages/Home/Home.jsx +13 -0
- package/templates/css/component-styles/tailwind/component-based/src/pages/Home/Home.tsx +13 -0
- package/templates/css/component-styles/tailwind/feature-based/src/app/App.jsx +9 -0
- package/templates/css/component-styles/tailwind/feature-based/src/app/App.tsx +9 -0
- package/templates/css/component-styles/tailwind/feature-based/src/features/home/pages/HomePage.jsx +13 -0
- package/templates/css/component-styles/tailwind/feature-based/src/features/home/pages/HomePage.tsx +13 -0
- package/templates/css/component-styles/tailwind/feature-based/src/shared/components/ui/Button.jsx +21 -0
- package/templates/css/component-styles/tailwind/feature-based/src/shared/components/ui/Button.tsx +26 -0
- package/templates/css/none/src/{index.css → main.css} +2 -0
- package/templates/css/none/src/themes.css +19 -0
- package/templates/css/tailwind/src/themes.css +9 -0
- package/templates/architectures/component-based/src/config/constants.js +0 -2
- package/templates/architectures/component-based/src/config/constants.ts +0 -2
- package/templates/architectures/component-based/src/config/routes.js +0 -7
- package/templates/architectures/component-based/src/config/routes.ts +0 -7
- package/templates/architectures/component-based/src/context/AppContext.jsx +0 -13
- package/templates/architectures/component-based/src/context/AppContext.tsx +0 -13
- package/templates/architectures/component-based/src/hooks/index.js +0 -1
- package/templates/architectures/component-based/src/hooks/index.ts +0 -1
- package/templates/architectures/component-based/src/layouts/index.js +0 -1
- package/templates/architectures/component-based/src/layouts/index.ts +0 -1
- package/templates/architectures/component-based/src/routes/index.jsx +0 -11
- package/templates/architectures/component-based/src/routes/index.tsx +0 -11
- package/templates/architectures/component-based/src/styles/globals.css +0 -7
- package/templates/architectures/component-based/src/utils/index.js +0 -1
- package/templates/architectures/component-based/src/utils/index.ts +0 -1
- package/templates/architectures/feature-based/src/config/constants.js +0 -2
- package/templates/architectures/feature-based/src/config/constants.ts +0 -2
- package/templates/architectures/feature-based/src/hooks/index.js +0 -1
- package/templates/architectures/feature-based/src/hooks/index.ts +0 -1
- package/templates/architectures/feature-based/src/utils/cn.ts +0 -6
- package/templates/architectures/feature-based/src/utils/index.js +0 -1
- package/templates/architectures/feature-based/src/utils/index.ts +0 -1
- package/templates/conditional/axios/component-based/src/services/axios.jsx +0 -19
- package/templates/conditional/axios/component-based/src/services/axios.ts +0 -19
- package/templates/conditional/axios/component-based/src/services/index.js +0 -1
- package/templates/conditional/axios/component-based/src/services/index.ts +0 -1
- package/templates/conditional/axios/feature-based/src/lib/axios.jsx +0 -19
- package/templates/conditional/axios/feature-based/src/lib/axios.ts +0 -19
- package/templates/conditional/axios/feature-based/src/lib/index.js +0 -1
- package/templates/conditional/axios/feature-based/src/lib/index.ts +0 -1
- package/templates/conditional/fetch/component-based/src/services/api.jsx +0 -27
- package/templates/conditional/fetch/component-based/src/services/api.ts +0 -27
- package/templates/conditional/fetch/component-based/src/services/index.js +0 -1
- package/templates/conditional/fetch/component-based/src/services/index.ts +0 -1
- package/templates/conditional/fetch/feature-based/src/lib/api.jsx +0 -27
- package/templates/conditional/fetch/feature-based/src/lib/api.ts +0 -27
- package/templates/conditional/fetch/feature-based/src/lib/index.js +0 -1
- package/templates/conditional/fetch/feature-based/src/lib/index.ts +0 -1
- package/templates/conditional/router/component-based/src/routes/index.jsx +0 -13
- package/templates/conditional/router/component-based/src/routes/index.tsx +0 -13
- package/templates/conditional/router/feature-based/src/app/router.jsx +0 -13
- package/templates/conditional/router/feature-based/src/app/router.tsx +0 -13
- package/templates/conditional/state/redux/feature-based/src/stores/hooks.ts +0 -4
- package/templates/css/tailwind/src/index.css +0 -1
- /package/templates/architectures/component-based/src/{components/layout → config}/.gitkeep +0 -0
- /package/templates/architectures/{feature-based/src/features/home/interfaces → component-based/src/providers}/.gitkeep +0 -0
- /package/templates/architectures/{feature-based/src/lib → component-based/src/styles}/.gitkeep +0 -0
- /package/templates/architectures/feature-based/src/{stores → features/home/types}/.gitkeep +0 -0
- /package/templates/architectures/feature-based/src/{components → shared/components}/ui/index.js +0 -0
- /package/templates/architectures/feature-based/src/{components → shared/components}/ui/index.ts +0 -0
- /package/templates/architectures/feature-based/src/{hooks → shared/hooks}/useLocalStorage.jsx +0 -0
- /package/templates/architectures/feature-based/src/{utils → shared/utils}/cn.jsx +0 -0
- /package/templates/conditional/state/redux/feature-based/src/{stores → shared/stores}/hooks.js +0 -0
- /package/templates/conditional/state/redux/feature-based/src/{stores → shared/stores}/index.js +0 -0
- /package/templates/conditional/testing/vitest/{src → feature-based/src}/__tests__/App.test.jsx +0 -0
- /package/templates/conditional/testing/vitest/{src → feature-based/src}/__tests__/App.test.tsx +0 -0
- /package/templates/css/bootstrap/src/{index.css → globals.css} +0 -0
- /package/templates/{architectures/feature-based/src/styles → css/tailwind/src}/globals.css +0 -0
package/src/injector.js
CHANGED
|
@@ -2,7 +2,25 @@ import { promises as fsp } from "fs";
|
|
|
2
2
|
import path from "path";
|
|
3
3
|
import { copyDirRecursive, writeFileRecursive } from "@/utils/fs.js";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
// Narrow a template tree copy to the selected language: .tsx/.ts for ts,
|
|
6
|
+
// .jsx/.js for js (keeps the opposite language's files out of the project).
|
|
7
|
+
function langFileFilter(language) {
|
|
8
|
+
return (name) => {
|
|
9
|
+
if (language === "ts") {
|
|
10
|
+
if (name.endsWith(".jsx")) return false;
|
|
11
|
+
if (name.endsWith(".js")) return false;
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
if (language === "js") {
|
|
15
|
+
if (name.endsWith(".tsx")) return false;
|
|
16
|
+
if (name.endsWith(".ts")) return false;
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
return true;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function injectArchitecture(projectPath, templatesDir, architecture, language, cssFramework) {
|
|
6
24
|
const ext = language === "ts" ? "tsx" : "jsx";
|
|
7
25
|
const srcDir = path.join(templatesDir, "architectures", architecture, "src");
|
|
8
26
|
|
|
@@ -11,17 +29,13 @@ export async function injectArchitecture(projectPath, templatesDir, architecture
|
|
|
11
29
|
const defaultAppJsx = path.join(projectPath, "src", "App.jsx");
|
|
12
30
|
try { await fsp.rm(defaultAppTsx, { force: true }); } catch {}
|
|
13
31
|
try { await fsp.rm(defaultAppJsx, { force: true }); } catch {}
|
|
32
|
+
// Remove Vite's default index.css (framework CSS lives in src/styles/,
|
|
33
|
+
// copied below — never at the src/ root).
|
|
34
|
+
try { await fsp.rm(path.join(projectPath, "src", "index.css"), { force: true }); } catch {}
|
|
35
|
+
try { await fsp.rm(path.join(projectPath, "src", "App.css"), { force: true }); } catch {}
|
|
14
36
|
|
|
15
37
|
// Copy the architecture tree into the project's src/
|
|
16
|
-
await copyDirRecursive(srcDir, path.join(projectPath, "src"), (
|
|
17
|
-
// Skip files that don't match the language
|
|
18
|
-
if (language === "ts" && name.endsWith(".jsx")) return false;
|
|
19
|
-
if (language === "js" && name.endsWith(".tsx")) return false;
|
|
20
|
-
// Skip .ts files when JS, skip .js when TS (for non-component files)
|
|
21
|
-
if (language === "ts" && name.endsWith(".js") && !name.endsWith(".config.js")) return false;
|
|
22
|
-
if (language === "js" && name.endsWith(".ts") && !name.endsWith(".config.ts")) return false;
|
|
23
|
-
return true;
|
|
24
|
-
});
|
|
38
|
+
await copyDirRecursive(srcDir, path.join(projectPath, "src"), langFileFilter(language));
|
|
25
39
|
|
|
26
40
|
// Copy the architecture's main.tsx/main.jsx to src/main.{ext}
|
|
27
41
|
const mainSrc = path.join(
|
|
@@ -41,6 +55,31 @@ export async function injectArchitecture(projectPath, templatesDir, architecture
|
|
|
41
55
|
const oppositeExt = language === "ts" ? "jsx" : "tsx";
|
|
42
56
|
const oppositeMain = path.join(projectPath, "src", `main.${oppositeExt}`);
|
|
43
57
|
try { await fsp.rm(oppositeMain, { force: true }); } catch {}
|
|
58
|
+
|
|
59
|
+
// Apply the chosen CSS framework's component styling on top of the base
|
|
60
|
+
// (only where the base ships framework-agnostic inline markup). Runs here,
|
|
61
|
+
// before conditional overlays, so icons/router can still override the files
|
|
62
|
+
// they own.
|
|
63
|
+
if (cssFramework === "tailwind" || cssFramework === "bootstrap") {
|
|
64
|
+
const variantSrc = path.join(
|
|
65
|
+
templatesDir,
|
|
66
|
+
"css",
|
|
67
|
+
"component-styles",
|
|
68
|
+
cssFramework,
|
|
69
|
+
architecture,
|
|
70
|
+
"src"
|
|
71
|
+
);
|
|
72
|
+
try {
|
|
73
|
+
await fsp.access(variantSrc);
|
|
74
|
+
await copyDirRecursive(
|
|
75
|
+
variantSrc,
|
|
76
|
+
path.join(projectPath, "src"),
|
|
77
|
+
langFileFilter(language)
|
|
78
|
+
);
|
|
79
|
+
} catch {
|
|
80
|
+
// no component-styles for this arch/framework
|
|
81
|
+
}
|
|
82
|
+
}
|
|
44
83
|
}
|
|
45
84
|
|
|
46
85
|
export async function injectFormatter(projectPath, templatesDir, responses) {
|
|
@@ -72,6 +111,7 @@ export async function injectFormatter(projectPath, templatesDir, responses) {
|
|
|
72
111
|
pkg.scripts["format:check"] = "prettier --check .";
|
|
73
112
|
} else if (responses.formatter === "oxfmt") {
|
|
74
113
|
pkg.scripts.format = "oxfmt .";
|
|
114
|
+
pkg.scripts["format:check"] = "oxfmt --check .";
|
|
75
115
|
}
|
|
76
116
|
await fsp.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
|
|
77
117
|
} catch {}
|
|
@@ -105,11 +145,14 @@ async function wireEslintPrettier(projectPath, language) {
|
|
|
105
145
|
|
|
106
146
|
let result = lines.join("\n");
|
|
107
147
|
|
|
108
|
-
// Append
|
|
148
|
+
// Append prettier as the LAST element of the eslint config.
|
|
149
|
+
// eslint-config-prettier exports a flat-config object (not an iterable),
|
|
150
|
+
// so it must be passed by reference, not spread — passing `...prettier`
|
|
151
|
+
// breaks under ESLint's jiti-based TS config loading.
|
|
109
152
|
// The JS template exports an array (`export default [...]`); the TS
|
|
110
153
|
// template uses a function call (`export default tseslint.config(...)`).
|
|
111
154
|
const pushLast = (_, head, tail) =>
|
|
112
|
-
head.replace(/,\s*$/, "") + ",\n
|
|
155
|
+
head.replace(/,\s*$/, "") + ",\n prettier," + tail;
|
|
113
156
|
if (result.includes("tseslint.config(")) {
|
|
114
157
|
result = result.replace(
|
|
115
158
|
/(export default tseslint\.config\([\s\S]*?)(\n\s*\);)/,
|
|
@@ -149,20 +192,22 @@ export async function injectConditionals(projectPath, templatesDir, responses, a
|
|
|
149
192
|
|
|
150
193
|
// 2. Router (overwrites App.tsx with routed version)
|
|
151
194
|
if (responses.router) {
|
|
152
|
-
await
|
|
195
|
+
await injectOverlayVariant(
|
|
153
196
|
projectPath,
|
|
154
197
|
templatesDir,
|
|
155
|
-
`
|
|
198
|
+
`router/${architecture}`,
|
|
199
|
+
responses.cssFramework,
|
|
156
200
|
language
|
|
157
201
|
);
|
|
158
202
|
}
|
|
159
203
|
|
|
160
204
|
// 3. Icons (overwrites home page)
|
|
161
205
|
if (responses.iconLibrary && responses.iconLibrary !== "none") {
|
|
162
|
-
await
|
|
206
|
+
await injectOverlayVariant(
|
|
163
207
|
projectPath,
|
|
164
208
|
templatesDir,
|
|
165
|
-
`
|
|
209
|
+
`icons/${responses.iconLibrary}/${architecture}`,
|
|
210
|
+
responses.cssFramework,
|
|
166
211
|
language
|
|
167
212
|
);
|
|
168
213
|
}
|
|
@@ -202,19 +247,70 @@ export async function injectConditionals(projectPath, templatesDir, responses, a
|
|
|
202
247
|
if (architecture === "feature-based") {
|
|
203
248
|
await injectCreateFeatureScript(projectPath, templatesDir, language);
|
|
204
249
|
}
|
|
250
|
+
|
|
251
|
+
// A .gitkeep only keeps a folder alive when that folder holds nothing else;
|
|
252
|
+
// once an overlay writes real files into it the placeholder is redundant.
|
|
253
|
+
await pruneRedundantGitkeeps(projectPath);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Remove .gitkeep placeholders from src/ directories that now contain real
|
|
257
|
+
// files (e.g. component-based `services/.gitkeep` after the axios/fetch client
|
|
258
|
+
// overlay lands). A folder with nothing but its placeholder keeps it.
|
|
259
|
+
async function pruneRedundantGitkeeps(projectPath) {
|
|
260
|
+
const walk = async (dir) => {
|
|
261
|
+
let entries;
|
|
262
|
+
try {
|
|
263
|
+
entries = await fsp.readdir(dir, { withFileTypes: true });
|
|
264
|
+
} catch {
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
for (const entry of entries) {
|
|
268
|
+
if (entry.isDirectory()) {
|
|
269
|
+
await walk(path.join(dir, entry.name));
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
if (entries.some((e) => e.name === ".gitkeep")) {
|
|
273
|
+
const hasRealFiles = entries.some((e) => e.isFile() && e.name !== ".gitkeep");
|
|
274
|
+
if (hasRealFiles) {
|
|
275
|
+
await fsp.rm(path.join(dir, ".gitkeep"), { force: true });
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
await walk(path.join(projectPath, "src"));
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Overlays that ship presentational components (router, icons) carry optional
|
|
283
|
+
// tailwind/bootstrap subfolders. Copy the root version first — it holds the
|
|
284
|
+
// framework-agnostic skeleton (routed App, route tables) plus the inline
|
|
285
|
+
// markup defaults used for cssFramework "none" — then overlay the framework's
|
|
286
|
+
// subfolder so its markup-specific files (transitive layouts, home pages)
|
|
287
|
+
// win; `copyDirRecursive` overwrites on name collision.
|
|
288
|
+
async function injectOverlayVariant(projectPath, templatesDir, rel, cssFramework, language) {
|
|
289
|
+
const base = `conditional/${rel}`;
|
|
290
|
+
await injectOverlay(projectPath, templatesDir, base, language);
|
|
291
|
+
const variant =
|
|
292
|
+
cssFramework === "tailwind" || cssFramework === "bootstrap"
|
|
293
|
+
? cssFramework
|
|
294
|
+
: "";
|
|
295
|
+
if (variant) {
|
|
296
|
+
await injectOverlay(
|
|
297
|
+
projectPath,
|
|
298
|
+
templatesDir,
|
|
299
|
+
`${base}/${variant}`,
|
|
300
|
+
language
|
|
301
|
+
);
|
|
302
|
+
}
|
|
205
303
|
}
|
|
206
304
|
|
|
207
305
|
async function injectOverlay(projectPath, templatesDir, overlayPath, language) {
|
|
208
306
|
const srcDir = path.join(templatesDir, overlayPath, "src");
|
|
209
307
|
try {
|
|
210
308
|
await fsp.access(srcDir);
|
|
211
|
-
await copyDirRecursive(
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
return true;
|
|
217
|
-
});
|
|
309
|
+
await copyDirRecursive(
|
|
310
|
+
srcDir,
|
|
311
|
+
path.join(projectPath, "src"),
|
|
312
|
+
langFileFilter(language)
|
|
313
|
+
);
|
|
218
314
|
} catch {
|
|
219
315
|
// overlay src dir doesn't exist
|
|
220
316
|
}
|
|
@@ -247,11 +343,18 @@ async function injectTesting(projectPath, templatesDir, framework, language, arc
|
|
|
247
343
|
await fsp.access(jestSetupSrc);
|
|
248
344
|
await fsp.copyFile(jestSetupSrc, path.join(projectPath, `jest.setup.${configExt}`));
|
|
249
345
|
} catch {}
|
|
346
|
+
|
|
347
|
+
// Unified Babel transform config for Jest (env + react + typescript presets).
|
|
348
|
+
const babelSrc = path.join(testingDir, "babel.config.cjs");
|
|
349
|
+
try {
|
|
350
|
+
await fsp.access(babelSrc);
|
|
351
|
+
await fsp.copyFile(babelSrc, path.join(projectPath, "babel.config.cjs"));
|
|
352
|
+
} catch {}
|
|
250
353
|
}
|
|
251
354
|
|
|
252
|
-
// Copy test file
|
|
355
|
+
// Copy test file (architecture-scoped so the App import path resolves)
|
|
253
356
|
const testExt = language === "ts" ? "tsx" : "jsx";
|
|
254
|
-
const testSrc = path.join(testingDir, `src/__tests__/App.test.${testExt}`);
|
|
357
|
+
const testSrc = path.join(testingDir, architecture, `src/__tests__/App.test.${testExt}`);
|
|
255
358
|
try {
|
|
256
359
|
await fsp.access(testSrc);
|
|
257
360
|
const testDest = path.join(projectPath, "src", "__tests__", `App.test.${testExt}`);
|
|
@@ -321,11 +424,11 @@ async function injectCreateFeatureScript(projectPath, templatesDir, language) {
|
|
|
321
424
|
if (language === "js") {
|
|
322
425
|
// Replace .ts extensions with .js in the initialFiles
|
|
323
426
|
content = content
|
|
324
|
-
.replace(/interfaces\/index\.ts/g, "interfaces/index.js")
|
|
325
427
|
.replace(/services\/index\.ts/g, "services/index.js")
|
|
326
428
|
.replace(/store\/index\.ts/g, "store/index.js")
|
|
327
429
|
.replace(/hooks\/index\.ts/g, "hooks/index.js")
|
|
328
|
-
.replace(/pages\/index\.ts/g, "pages/index.js")
|
|
430
|
+
.replace(/pages\/index\.ts/g, "pages/index.js")
|
|
431
|
+
.replace(/types\/index\.ts/g, "types/index.js");
|
|
329
432
|
}
|
|
330
433
|
|
|
331
434
|
await writeFileRecursive(scriptDest, content);
|
|
@@ -362,7 +465,7 @@ async function updateMainWithProvider(projectPath, stateType, architecture, ext)
|
|
|
362
465
|
if (!content.includes("StoreProvider")) {
|
|
363
466
|
content = content.replace(
|
|
364
467
|
/import App from ['"]\.\/App['"]\n?/,
|
|
365
|
-
"import App from './App'\nimport { StoreProvider } from './
|
|
468
|
+
"import App from './App'\nimport { StoreProvider } from './providers/StoreProvider'\n"
|
|
366
469
|
);
|
|
367
470
|
content = content.replace(
|
|
368
471
|
/<App \/>/,
|
package/src/main.js
CHANGED
|
@@ -15,6 +15,7 @@ import { getUserInputs, onCancel } from "@/prompts.js";
|
|
|
15
15
|
import { runBaseInstall, runGitInit, runViteCreate } from "@/scaffold.js";
|
|
16
16
|
import { installAllDeps } from "@/dependencies.js";
|
|
17
17
|
import { generateReadme } from "@/readme.js";
|
|
18
|
+
import { runProjectFormat } from "@/format.js";
|
|
18
19
|
|
|
19
20
|
const __filename = fileURLToPath(import.meta.url);
|
|
20
21
|
const __dirname = path.dirname(__filename);
|
|
@@ -110,7 +111,8 @@ export async function main(options = {}) {
|
|
|
110
111
|
projectPath,
|
|
111
112
|
TEMPLATES_DIR,
|
|
112
113
|
responses.architecture,
|
|
113
|
-
responses.language
|
|
114
|
+
responses.language,
|
|
115
|
+
responses.cssFramework
|
|
114
116
|
);
|
|
115
117
|
archSpin.stop(chalk.green("Architecture scaffolding complete."));
|
|
116
118
|
} catch (err) {
|
|
@@ -174,6 +176,7 @@ export async function main(options = {}) {
|
|
|
174
176
|
templatesDir: TEMPLATES_DIR,
|
|
175
177
|
language: responses.language,
|
|
176
178
|
cssFramework: responses.cssFramework,
|
|
179
|
+
architecture: responses.architecture,
|
|
177
180
|
ext: responses.language === "ts" ? "tsx" : "jsx",
|
|
178
181
|
pkg,
|
|
179
182
|
});
|
|
@@ -215,6 +218,19 @@ export async function main(options = {}) {
|
|
|
215
218
|
}
|
|
216
219
|
}
|
|
217
220
|
|
|
221
|
+
// 13.5 Format the freshly generated project so it is canonical on init
|
|
222
|
+
if (responses.formatter && responses.formatter !== "none") {
|
|
223
|
+
const fmtPassSpin = spinner();
|
|
224
|
+
fmtPassSpin.start(`Formatting project with ${responses.formatter}...`);
|
|
225
|
+
try {
|
|
226
|
+
await runProjectFormat(projectPath, responses);
|
|
227
|
+
fmtPassSpin.stop(chalk.green("Project formatted."));
|
|
228
|
+
} catch (err) {
|
|
229
|
+
fmtPassSpin.stop(chalk.red("Failed to format project."));
|
|
230
|
+
throw err;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
218
234
|
log.step(chalk.green("\nProject setup complete!"));
|
|
219
235
|
log.message(
|
|
220
236
|
chalk.gray(
|
package/src/readme.js
CHANGED
|
@@ -77,36 +77,79 @@ function buildScripts(responses) {
|
|
|
77
77
|
|
|
78
78
|
if (responses.formatter === "prettier" || responses.formatter === "oxfmt") {
|
|
79
79
|
rows.push("| `npm run format` | Format code |");
|
|
80
|
+
rows.push("| `npm run format:check` | Verify code is formatted |");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (responses.language === "ts") {
|
|
84
|
+
rows.push("| `npm run typecheck` | Type-check the project (tsc -b) |");
|
|
80
85
|
}
|
|
81
86
|
|
|
82
87
|
return rows.join("\n");
|
|
83
88
|
}
|
|
84
89
|
|
|
85
|
-
function buildProjectStructure(
|
|
86
|
-
if (architecture === "feature-based") {
|
|
90
|
+
function buildProjectStructure(responses) {
|
|
91
|
+
if (responses.architecture === "feature-based") {
|
|
92
|
+
const shared = [];
|
|
93
|
+
if (responses.apiClient === "fetch") {
|
|
94
|
+
shared.push("api/ # HTTP client (fetch) — not an external dependency");
|
|
95
|
+
} else if (responses.apiClient === "axios") {
|
|
96
|
+
shared.push("lib/ # Third-party library init (axios client)");
|
|
97
|
+
}
|
|
98
|
+
shared.push(
|
|
99
|
+
"components/ # Shared UI components",
|
|
100
|
+
"hooks/ # Shared custom hooks",
|
|
101
|
+
"layouts/ # High-level layout wrappers",
|
|
102
|
+
"stores/ # Global state stores",
|
|
103
|
+
`styles/ # ${responses.cssFramework === "none" ? "main.css (reset) + themes.css (CSS variables)" : "globals.css (framework directives) + themes.css"}`,
|
|
104
|
+
"types/ # Global type definitions",
|
|
105
|
+
"utils/ # Pure utility functions"
|
|
106
|
+
);
|
|
107
|
+
const appChildren = [
|
|
108
|
+
"App.tsx",
|
|
109
|
+
"contexts/ # React context objects (createContext)",
|
|
110
|
+
"providers/ # Provider components (ThemeProvider, ...)",
|
|
111
|
+
"hooks/ # Hooks that read the contexts (useTheme, ...)"
|
|
112
|
+
];
|
|
87
113
|
return `src/
|
|
88
|
-
├── app/ # App shell and providers
|
|
89
|
-
|
|
90
|
-
├──
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
├── types/ # TypeScript type definitions
|
|
95
|
-
└── utils/ # Utility functions`;
|
|
114
|
+
├── app/ # App shell and global providers
|
|
115
|
+
${nestedTree(appChildren)}
|
|
116
|
+
├── features/ # Feature modules (pages, hooks, api, types)
|
|
117
|
+
│ └── home/ # Example feature (components, services, types, store)
|
|
118
|
+
└── shared/ # Reusable, business-agnostic resources
|
|
119
|
+
${nestedTree(shared)}`;
|
|
96
120
|
}
|
|
97
121
|
|
|
122
|
+
const rows = ["components/ # Reusable UI components (common, form)"];
|
|
123
|
+
if (responses.apiClient !== "none") {
|
|
124
|
+
rows.push("config/ # API configuration (axios/fetch)");
|
|
125
|
+
}
|
|
126
|
+
rows.push(
|
|
127
|
+
"hooks/ # Shared custom hooks",
|
|
128
|
+
"layouts/ # Page layout wrappers",
|
|
129
|
+
"pages/ # Page-level components",
|
|
130
|
+
"providers/ # Provider components (createContext in appcontext.{ts,js}, Provider in AppProvider.{tsx,jsx})"
|
|
131
|
+
);
|
|
132
|
+
if (responses.router) {
|
|
133
|
+
rows.push("router/ # Centralized data router (guards/, index)");
|
|
134
|
+
}
|
|
135
|
+
rows.push(
|
|
136
|
+
"services/ # API service layer",
|
|
137
|
+
"store/ # State store",
|
|
138
|
+
`styles/ # ${responses.cssFramework === "none" ? "main.css (reset) + themes.css (CSS variables)" : "globals.css (framework directives) + themes.css"}`,
|
|
139
|
+
"types/ # TypeScript type definitions",
|
|
140
|
+
"utils/ # Utility functions"
|
|
141
|
+
);
|
|
98
142
|
return `src/
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
└── utils/ # Utility functions`;
|
|
143
|
+
${nestedTree(rows, "")}`;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function nestedTree(rows, indent = " ") {
|
|
147
|
+
return rows
|
|
148
|
+
.map((label, i) => {
|
|
149
|
+
const isLast = i === rows.length - 1;
|
|
150
|
+
return `${indent}${isLast ? "└── " : "├── "}${label}`;
|
|
151
|
+
})
|
|
152
|
+
.join("\n");
|
|
110
153
|
}
|
|
111
154
|
|
|
112
155
|
function buildLicense() {
|
|
@@ -152,7 +195,7 @@ function buildDescription(projectName, responses) {
|
|
|
152
195
|
function buildReadme(projectName, responses) {
|
|
153
196
|
const builtWith = buildBuiltWith(responses);
|
|
154
197
|
const scripts = buildScripts(responses);
|
|
155
|
-
const structure = buildProjectStructure(responses
|
|
198
|
+
const structure = buildProjectStructure(responses);
|
|
156
199
|
|
|
157
200
|
return `${buildDescription(projectName, responses)}
|
|
158
201
|
|
|
@@ -3,7 +3,7 @@ import ReactDOM from "react-dom/client";
|
|
|
3
3
|
import App from "./App";
|
|
4
4
|
import "./styles/globals.css";
|
|
5
5
|
|
|
6
|
-
ReactDOM.createRoot(document.getElementById("root")).render(
|
|
6
|
+
ReactDOM.createRoot(document.getElementById("root")!).render(
|
|
7
7
|
<React.StrictMode>
|
|
8
8
|
<App />
|
|
9
9
|
</React.StrictMode>
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { AppProvider } from "@/providers/AppProvider";
|
|
2
2
|
import { MainLayout } from "@/layouts/MainLayout";
|
|
3
3
|
import { HomePage } from "@/pages/Home/Home";
|
|
4
4
|
|
|
5
5
|
export default function App() {
|
|
6
6
|
return (
|
|
7
|
-
<
|
|
8
|
-
<
|
|
9
|
-
|
|
7
|
+
<AppProvider>
|
|
8
|
+
<MainLayout>
|
|
9
|
+
<HomePage />
|
|
10
|
+
</MainLayout>
|
|
11
|
+
</AppProvider>
|
|
10
12
|
);
|
|
11
13
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { AppProvider } from "@/providers/AppProvider";
|
|
2
2
|
import { MainLayout } from "@/layouts/MainLayout";
|
|
3
3
|
import { HomePage } from "@/pages/Home/Home";
|
|
4
4
|
|
|
5
5
|
export default function App() {
|
|
6
6
|
return (
|
|
7
|
-
<
|
|
8
|
-
<
|
|
9
|
-
|
|
7
|
+
<AppProvider>
|
|
8
|
+
<MainLayout>
|
|
9
|
+
<HomePage />
|
|
10
|
+
</MainLayout>
|
|
11
|
+
</AppProvider>
|
|
10
12
|
);
|
|
11
13
|
}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
|
|
3
1
|
export function Button({
|
|
4
2
|
variant = "primary",
|
|
5
3
|
children,
|
|
@@ -7,8 +5,11 @@ export function Button({
|
|
|
7
5
|
...props
|
|
8
6
|
}) {
|
|
9
7
|
const styles = {
|
|
10
|
-
primary: { backgroundColor: "
|
|
11
|
-
secondary: {
|
|
8
|
+
primary: { backgroundColor: "var(--color-primary)", color: "white" },
|
|
9
|
+
secondary: {
|
|
10
|
+
backgroundColor: "var(--color-border)",
|
|
11
|
+
color: "var(--color-fg)",
|
|
12
|
+
},
|
|
12
13
|
};
|
|
13
14
|
|
|
14
15
|
return (
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
|
|
3
1
|
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
4
2
|
variant?: "primary" | "secondary";
|
|
5
3
|
children: React.ReactNode;
|
|
@@ -12,8 +10,11 @@ export function Button({
|
|
|
12
10
|
...props
|
|
13
11
|
}: ButtonProps) {
|
|
14
12
|
const styles = {
|
|
15
|
-
primary: { backgroundColor: "
|
|
16
|
-
secondary: {
|
|
13
|
+
primary: { backgroundColor: "var(--color-primary)", color: "white" },
|
|
14
|
+
secondary: {
|
|
15
|
+
backgroundColor: "var(--color-border)",
|
|
16
|
+
color: "var(--color-fg)",
|
|
17
|
+
},
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
return (
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
import { AppContext, type AppContextValue } from "@/providers/appcontext";
|
|
3
|
+
|
|
4
|
+
export function useApp(): AppContextValue {
|
|
5
|
+
const ctx = useContext(AppContext);
|
|
6
|
+
if (!ctx) {
|
|
7
|
+
throw new Error("useApp must be used within an AppProvider");
|
|
8
|
+
}
|
|
9
|
+
return ctx;
|
|
10
|
+
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { useState, useCallback } from "react";
|
|
2
2
|
|
|
3
|
-
export function useLocalStorage(key, initialValue) {
|
|
4
|
-
const [storedValue, setStoredValue] = useState(() => {
|
|
3
|
+
export function useLocalStorage<T>(key: string, initialValue: T) {
|
|
4
|
+
const [storedValue, setStoredValue] = useState<T>(() => {
|
|
5
5
|
try {
|
|
6
6
|
const item = window.localStorage.getItem(key);
|
|
7
|
-
return item ? JSON.parse(item) : initialValue;
|
|
7
|
+
return item ? (JSON.parse(item) as T) : initialValue;
|
|
8
8
|
} catch {
|
|
9
9
|
return initialValue;
|
|
10
10
|
}
|
|
11
11
|
});
|
|
12
12
|
|
|
13
13
|
const setValue = useCallback(
|
|
14
|
-
(value) => {
|
|
14
|
+
(value: T | ((prev: T) => T)) => {
|
|
15
15
|
try {
|
|
16
16
|
const valueToStore =
|
|
17
17
|
value instanceof Function ? value(storedValue) : value;
|
|
@@ -24,5 +24,5 @@ export function useLocalStorage(key, initialValue) {
|
|
|
24
24
|
[key, storedValue]
|
|
25
25
|
);
|
|
26
26
|
|
|
27
|
-
return [storedValue, setValue];
|
|
27
|
+
return [storedValue, setValue] as const;
|
|
28
28
|
}
|
|
@@ -1,25 +1,31 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
|
|
3
1
|
export function MainLayout({ children }) {
|
|
4
2
|
return (
|
|
5
3
|
<div style={{ minHeight: "100vh", display: "flex", flexDirection: "column" }}>
|
|
6
4
|
<header
|
|
7
5
|
style={{
|
|
8
6
|
padding: "16px 24px",
|
|
9
|
-
borderBottom: "1px solid
|
|
7
|
+
borderBottom: "1px solid var(--color-border)",
|
|
10
8
|
}}
|
|
11
9
|
>
|
|
12
10
|
<h2 style={{ fontSize: "1.25rem", fontWeight: 600 }}>Lumen</h2>
|
|
13
11
|
</header>
|
|
14
|
-
<main
|
|
12
|
+
<main
|
|
13
|
+
style={{
|
|
14
|
+
flex: 1,
|
|
15
|
+
padding: "24px",
|
|
16
|
+
display: "flex",
|
|
17
|
+
alignItems: "center",
|
|
18
|
+
justifyContent: "center",
|
|
19
|
+
}}
|
|
20
|
+
>
|
|
15
21
|
{children}
|
|
16
22
|
</main>
|
|
17
23
|
<footer
|
|
18
24
|
style={{
|
|
19
25
|
padding: "16px 24px",
|
|
20
|
-
borderTop: "1px solid
|
|
26
|
+
borderTop: "1px solid var(--color-border)",
|
|
21
27
|
textAlign: "center",
|
|
22
|
-
color: "
|
|
28
|
+
color: "var(--color-muted)",
|
|
23
29
|
}}
|
|
24
30
|
>
|
|
25
31
|
<p>Built with Lumen</p>
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
|
|
3
1
|
interface MainLayoutProps {
|
|
4
2
|
children: React.ReactNode;
|
|
5
3
|
}
|
|
@@ -10,20 +8,28 @@ export function MainLayout({ children }: MainLayoutProps) {
|
|
|
10
8
|
<header
|
|
11
9
|
style={{
|
|
12
10
|
padding: "16px 24px",
|
|
13
|
-
borderBottom: "1px solid
|
|
11
|
+
borderBottom: "1px solid var(--color-border)",
|
|
14
12
|
}}
|
|
15
13
|
>
|
|
16
14
|
<h2 style={{ fontSize: "1.25rem", fontWeight: 600 }}>Lumen</h2>
|
|
17
15
|
</header>
|
|
18
|
-
<main
|
|
16
|
+
<main
|
|
17
|
+
style={{
|
|
18
|
+
flex: 1,
|
|
19
|
+
padding: "24px",
|
|
20
|
+
display: "flex",
|
|
21
|
+
alignItems: "center",
|
|
22
|
+
justifyContent: "center",
|
|
23
|
+
}}
|
|
24
|
+
>
|
|
19
25
|
{children}
|
|
20
26
|
</main>
|
|
21
27
|
<footer
|
|
22
28
|
style={{
|
|
23
29
|
padding: "16px 24px",
|
|
24
|
-
borderTop: "1px solid
|
|
30
|
+
borderTop: "1px solid var(--color-border)",
|
|
25
31
|
textAlign: "center",
|
|
26
|
-
color: "
|
|
32
|
+
color: "var(--color-muted)",
|
|
27
33
|
}}
|
|
28
34
|
>
|
|
29
35
|
<p>Built with Lumen</p>
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import React from "react";
|
|
2
1
|
import { Button } from "@/components/common";
|
|
3
2
|
|
|
4
3
|
export function HomePage() {
|
|
@@ -7,7 +6,12 @@ export function HomePage() {
|
|
|
7
6
|
<h1 style={{ fontSize: "2.25rem", fontWeight: 700, marginBottom: "1rem" }}>
|
|
8
7
|
Welcome to Lumen
|
|
9
8
|
</h1>
|
|
10
|
-
<p
|
|
9
|
+
<p
|
|
10
|
+
style={{
|
|
11
|
+
color: "var(--color-muted)",
|
|
12
|
+
marginBottom: "2rem",
|
|
13
|
+
}}
|
|
14
|
+
>
|
|
11
15
|
Your React + Vite project is ready. Start building!
|
|
12
16
|
</p>
|
|
13
17
|
<Button>Get Started</Button>
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import React from "react";
|
|
2
1
|
import { Button } from "@/components/common";
|
|
3
2
|
|
|
4
3
|
export function HomePage() {
|
|
@@ -7,7 +6,12 @@ export function HomePage() {
|
|
|
7
6
|
<h1 style={{ fontSize: "2.25rem", fontWeight: 700, marginBottom: "1rem" }}>
|
|
8
7
|
Welcome to Lumen
|
|
9
8
|
</h1>
|
|
10
|
-
<p
|
|
9
|
+
<p
|
|
10
|
+
style={{
|
|
11
|
+
color: "var(--color-muted)",
|
|
12
|
+
marginBottom: "2rem",
|
|
13
|
+
}}
|
|
14
|
+
>
|
|
11
15
|
Your React + Vite project is ready. Start building!
|
|
12
16
|
</p>
|
|
13
17
|
<Button>Get Started</Button>
|