create-lumen 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +115 -0
  3. package/bin/cli.js +17 -0
  4. package/package.json +42 -0
  5. package/src/cleanup.js +7 -0
  6. package/src/config-cache.js +27 -0
  7. package/src/configure.js +161 -0
  8. package/src/confirm-empty-folder.js +45 -0
  9. package/src/css.js +59 -0
  10. package/src/dependencies.js +101 -0
  11. package/src/injector.js +276 -0
  12. package/src/main.js +197 -0
  13. package/src/prompts.js +232 -0
  14. package/src/readme.js +178 -0
  15. package/src/scaffold.js +29 -0
  16. package/src/utils/dev-server.js +34 -0
  17. package/src/utils/fs.js +74 -0
  18. package/src/utils/pkg-manager.js +17 -0
  19. package/src/utils/yarn-v1.js +10 -0
  20. package/templates/architectures/component-based/main.jsx +10 -0
  21. package/templates/architectures/component-based/main.tsx +10 -0
  22. package/templates/architectures/component-based/src/App.jsx +11 -0
  23. package/templates/architectures/component-based/src/App.tsx +11 -0
  24. package/templates/architectures/component-based/src/components/common/Button.jsx +30 -0
  25. package/templates/architectures/component-based/src/components/common/Button.tsx +35 -0
  26. package/templates/architectures/component-based/src/components/common/index.js +1 -0
  27. package/templates/architectures/component-based/src/components/common/index.ts +1 -0
  28. package/templates/architectures/component-based/src/components/form/.gitkeep +0 -0
  29. package/templates/architectures/component-based/src/components/layout/.gitkeep +0 -0
  30. package/templates/architectures/component-based/src/config/constants.js +2 -0
  31. package/templates/architectures/component-based/src/config/constants.ts +2 -0
  32. package/templates/architectures/component-based/src/config/routes.js +7 -0
  33. package/templates/architectures/component-based/src/config/routes.ts +7 -0
  34. package/templates/architectures/component-based/src/context/AppContext.jsx +13 -0
  35. package/templates/architectures/component-based/src/context/AppContext.tsx +13 -0
  36. package/templates/architectures/component-based/src/hooks/index.js +1 -0
  37. package/templates/architectures/component-based/src/hooks/index.ts +1 -0
  38. package/templates/architectures/component-based/src/hooks/useLocalStorage.jsx +28 -0
  39. package/templates/architectures/component-based/src/hooks/useLocalStorage.ts +28 -0
  40. package/templates/architectures/component-based/src/layouts/MainLayout.jsx +29 -0
  41. package/templates/architectures/component-based/src/layouts/MainLayout.tsx +33 -0
  42. package/templates/architectures/component-based/src/layouts/index.js +1 -0
  43. package/templates/architectures/component-based/src/layouts/index.ts +1 -0
  44. package/templates/architectures/component-based/src/pages/Home/Home.jsx +16 -0
  45. package/templates/architectures/component-based/src/pages/Home/Home.tsx +16 -0
  46. package/templates/architectures/component-based/src/pages/Home/index.js +1 -0
  47. package/templates/architectures/component-based/src/pages/Home/index.ts +1 -0
  48. package/templates/architectures/component-based/src/routes/index.jsx +11 -0
  49. package/templates/architectures/component-based/src/routes/index.tsx +11 -0
  50. package/templates/architectures/component-based/src/services/.gitkeep +0 -0
  51. package/templates/architectures/component-based/src/store/.gitkeep +0 -0
  52. package/templates/architectures/component-based/src/styles/globals.css +7 -0
  53. package/templates/architectures/component-based/src/utils/cn.jsx +3 -0
  54. package/templates/architectures/component-based/src/utils/cn.ts +3 -0
  55. package/templates/architectures/component-based/src/utils/index.js +1 -0
  56. package/templates/architectures/component-based/src/utils/index.ts +1 -0
  57. package/templates/architectures/feature-based/main.jsx +10 -0
  58. package/templates/architectures/feature-based/main.tsx +10 -0
  59. package/templates/architectures/feature-based/scripts/create-feature.mjs +65 -0
  60. package/templates/architectures/feature-based/src/app/App.jsx +10 -0
  61. package/templates/architectures/feature-based/src/app/App.tsx +10 -0
  62. package/templates/architectures/feature-based/src/app/providers/ThemeProvider.jsx +5 -0
  63. package/templates/architectures/feature-based/src/app/providers/ThemeProvider.tsx +5 -0
  64. package/templates/architectures/feature-based/src/components/ui/Button.jsx +23 -0
  65. package/templates/architectures/feature-based/src/components/ui/Button.tsx +28 -0
  66. package/templates/architectures/feature-based/src/components/ui/index.js +1 -0
  67. package/templates/architectures/feature-based/src/components/ui/index.ts +1 -0
  68. package/templates/architectures/feature-based/src/config/constants.js +2 -0
  69. package/templates/architectures/feature-based/src/config/constants.ts +2 -0
  70. package/templates/architectures/feature-based/src/features/home/components/.gitkeep +0 -0
  71. package/templates/architectures/feature-based/src/features/home/hooks/.gitkeep +0 -0
  72. package/templates/architectures/feature-based/src/features/home/index.js +1 -0
  73. package/templates/architectures/feature-based/src/features/home/index.ts +1 -0
  74. package/templates/architectures/feature-based/src/features/home/interfaces/.gitkeep +0 -0
  75. package/templates/architectures/feature-based/src/features/home/layouts/.gitkeep +0 -0
  76. package/templates/architectures/feature-based/src/features/home/pages/HomePage.jsx +14 -0
  77. package/templates/architectures/feature-based/src/features/home/pages/HomePage.tsx +14 -0
  78. package/templates/architectures/feature-based/src/features/home/services/.gitkeep +0 -0
  79. package/templates/architectures/feature-based/src/features/home/store/.gitkeep +0 -0
  80. package/templates/architectures/feature-based/src/hooks/index.js +1 -0
  81. package/templates/architectures/feature-based/src/hooks/index.ts +1 -0
  82. package/templates/architectures/feature-based/src/hooks/useLocalStorage.jsx +28 -0
  83. package/templates/architectures/feature-based/src/hooks/useLocalStorage.ts +28 -0
  84. package/templates/architectures/feature-based/src/lib/.gitkeep +0 -0
  85. package/templates/architectures/feature-based/src/stores/.gitkeep +0 -0
  86. package/templates/architectures/feature-based/src/styles/globals.css +1 -0
  87. package/templates/architectures/feature-based/src/types/index.js +13 -0
  88. package/templates/architectures/feature-based/src/types/index.ts +11 -0
  89. package/templates/architectures/feature-based/src/utils/cn.jsx +3 -0
  90. package/templates/architectures/feature-based/src/utils/cn.ts +6 -0
  91. package/templates/architectures/feature-based/src/utils/index.js +1 -0
  92. package/templates/architectures/feature-based/src/utils/index.ts +1 -0
  93. package/templates/conditional/axios/component-based/src/services/axios.jsx +19 -0
  94. package/templates/conditional/axios/component-based/src/services/axios.ts +19 -0
  95. package/templates/conditional/axios/component-based/src/services/index.js +1 -0
  96. package/templates/conditional/axios/component-based/src/services/index.ts +1 -0
  97. package/templates/conditional/axios/feature-based/src/lib/axios.jsx +19 -0
  98. package/templates/conditional/axios/feature-based/src/lib/axios.ts +19 -0
  99. package/templates/conditional/axios/feature-based/src/lib/index.js +1 -0
  100. package/templates/conditional/axios/feature-based/src/lib/index.ts +1 -0
  101. package/templates/conditional/icons/huge/component-based/src/pages/Home/Home.jsx +20 -0
  102. package/templates/conditional/icons/huge/component-based/src/pages/Home/Home.tsx +20 -0
  103. package/templates/conditional/icons/huge/feature-based/src/features/home/pages/HomePage.jsx +20 -0
  104. package/templates/conditional/icons/huge/feature-based/src/features/home/pages/HomePage.tsx +20 -0
  105. package/templates/conditional/icons/lucide/component-based/src/pages/Home/Home.jsx +20 -0
  106. package/templates/conditional/icons/lucide/component-based/src/pages/Home/Home.tsx +20 -0
  107. package/templates/conditional/icons/lucide/feature-based/src/features/home/pages/HomePage.jsx +20 -0
  108. package/templates/conditional/icons/lucide/feature-based/src/features/home/pages/HomePage.tsx +20 -0
  109. package/templates/conditional/linting/eslint/eslint.config.js +31 -0
  110. package/templates/conditional/linting/eslint/eslint.config.ts +28 -0
  111. package/templates/conditional/linting/oxlint/oxlintrc.json +9 -0
  112. package/templates/conditional/router/component-based/src/App.jsx +11 -0
  113. package/templates/conditional/router/component-based/src/App.tsx +11 -0
  114. package/templates/conditional/router/component-based/src/routes/index.jsx +13 -0
  115. package/templates/conditional/router/component-based/src/routes/index.tsx +13 -0
  116. package/templates/conditional/router/feature-based/src/app/App.jsx +6 -0
  117. package/templates/conditional/router/feature-based/src/app/App.tsx +6 -0
  118. package/templates/conditional/router/feature-based/src/app/router.jsx +13 -0
  119. package/templates/conditional/router/feature-based/src/app/router.tsx +13 -0
  120. package/templates/conditional/state/redux/component-based/src/context/StoreProvider.jsx +7 -0
  121. package/templates/conditional/state/redux/component-based/src/context/StoreProvider.tsx +7 -0
  122. package/templates/conditional/state/redux/component-based/src/pages/Home/counterSlice.jsx +20 -0
  123. package/templates/conditional/state/redux/component-based/src/pages/Home/counterSlice.ts +20 -0
  124. package/templates/conditional/state/redux/component-based/src/store/hooks.js +4 -0
  125. package/templates/conditional/state/redux/component-based/src/store/hooks.ts +4 -0
  126. package/templates/conditional/state/redux/component-based/src/store/index.js +8 -0
  127. package/templates/conditional/state/redux/component-based/src/store/index.ts +11 -0
  128. package/templates/conditional/state/redux/feature-based/src/app/providers/StoreProvider.jsx +7 -0
  129. package/templates/conditional/state/redux/feature-based/src/app/providers/StoreProvider.tsx +7 -0
  130. package/templates/conditional/state/redux/feature-based/src/features/home/store/counterSlice.jsx +20 -0
  131. package/templates/conditional/state/redux/feature-based/src/features/home/store/counterSlice.ts +20 -0
  132. package/templates/conditional/state/redux/feature-based/src/stores/hooks.js +4 -0
  133. package/templates/conditional/state/redux/feature-based/src/stores/hooks.ts +4 -0
  134. package/templates/conditional/state/redux/feature-based/src/stores/index.js +8 -0
  135. package/templates/conditional/state/redux/feature-based/src/stores/index.ts +11 -0
  136. package/templates/conditional/state/zustand/component-based/src/store/useCounterStore.jsx +9 -0
  137. package/templates/conditional/state/zustand/component-based/src/store/useCounterStore.ts +9 -0
  138. package/templates/conditional/state/zustand/feature-based/src/stores/useCounterStore.jsx +9 -0
  139. package/templates/conditional/state/zustand/feature-based/src/stores/useCounterStore.ts +9 -0
  140. package/templates/conditional/testing/jest/jest.config.js +12 -0
  141. package/templates/conditional/testing/jest/jest.config.ts +13 -0
  142. package/templates/conditional/testing/jest/jest.setup.js +1 -0
  143. package/templates/conditional/testing/jest/jest.setup.ts +1 -0
  144. package/templates/conditional/testing/jest/src/__tests__/App.test.jsx +9 -0
  145. package/templates/conditional/testing/jest/src/__tests__/App.test.tsx +9 -0
  146. package/templates/conditional/testing/vitest/src/__tests__/App.test.jsx +10 -0
  147. package/templates/conditional/testing/vitest/src/__tests__/App.test.tsx +10 -0
  148. package/templates/conditional/testing/vitest/src/test/setup.js +1 -0
  149. package/templates/conditional/testing/vitest/src/test/setup.ts +1 -0
  150. package/templates/conditional/testing/vitest/vitest.config.js +18 -0
  151. package/templates/conditional/testing/vitest/vitest.config.ts +18 -0
  152. package/templates/css/bootstrap/src/index.css +1 -0
  153. package/templates/css/none/src/index.css +18 -0
  154. package/templates/css/tailwind/src/index.css +1 -0
  155. package/templates/css/tailwind/vite.config.js +15 -0
  156. package/templates/css/tailwind/vite.config.ts +15 -0
@@ -0,0 +1,20 @@
1
+ import React from "react";
2
+ import { Sun, Moon, Github } from "lucide-react";
3
+ import { Button } from "@/components/common";
4
+
5
+ export function HomePage() {
6
+ return (
7
+ <div className="text-center">
8
+ <div className="flex justify-center gap-4 mb-6">
9
+ <Sun className="w-8 h-8 text-yellow-500" />
10
+ <Moon className="w-8 h-8 text-blue-500" />
11
+ <Github className="w-8 h-8 text-gray-800" />
12
+ </div>
13
+ <h1 className="text-4xl font-bold text-gray-900 mb-4">Welcome to Lumen</h1>
14
+ <p className="text-gray-600 mb-8">
15
+ Your React + Vite project is ready. Start building!
16
+ </p>
17
+ <Button>Get Started</Button>
18
+ </div>
19
+ );
20
+ }
@@ -0,0 +1,20 @@
1
+ import React from "react";
2
+ import { Sun, Moon, Github } from "lucide-react";
3
+ import { Button } from "@/components/common";
4
+
5
+ export function HomePage() {
6
+ return (
7
+ <div className="text-center">
8
+ <div className="flex justify-center gap-4 mb-6">
9
+ <Sun className="w-8 h-8 text-yellow-500" />
10
+ <Moon className="w-8 h-8 text-blue-500" />
11
+ <Github className="w-8 h-8 text-gray-800" />
12
+ </div>
13
+ <h1 className="text-4xl font-bold text-gray-900 mb-4">Welcome to Lumen</h1>
14
+ <p className="text-gray-600 mb-8">
15
+ Your React + Vite project is ready. Start building!
16
+ </p>
17
+ <Button>Get Started</Button>
18
+ </div>
19
+ );
20
+ }
@@ -0,0 +1,20 @@
1
+ import React from "react";
2
+ import { Sun, Moon, Github } from "lucide-react";
3
+ import { Button } from "@/components/ui";
4
+
5
+ export function HomePage() {
6
+ return (
7
+ <div className="text-center">
8
+ <div className="flex justify-center gap-4 mb-6">
9
+ <Sun className="w-8 h-8 text-yellow-500" />
10
+ <Moon className="w-8 h-8 text-blue-500" />
11
+ <Github className="w-8 h-8 text-gray-800" />
12
+ </div>
13
+ <h1 className="text-4xl font-bold text-gray-900 mb-4">Welcome to Lumen</h1>
14
+ <p className="text-gray-600 mb-8">
15
+ Your React + Vite project is ready. Start building!
16
+ </p>
17
+ <Button>Get Started</Button>
18
+ </div>
19
+ );
20
+ }
@@ -0,0 +1,20 @@
1
+ import React from "react";
2
+ import { Sun, Moon, Github } from "lucide-react";
3
+ import { Button } from "@/components/ui";
4
+
5
+ export function HomePage() {
6
+ return (
7
+ <div className="text-center">
8
+ <div className="flex justify-center gap-4 mb-6">
9
+ <Sun className="w-8 h-8 text-yellow-500" />
10
+ <Moon className="w-8 h-8 text-blue-500" />
11
+ <Github className="w-8 h-8 text-gray-800" />
12
+ </div>
13
+ <h1 className="text-4xl font-bold text-gray-900 mb-4">Welcome to Lumen</h1>
14
+ <p className="text-gray-600 mb-8">
15
+ Your React + Vite project is ready. Start building!
16
+ </p>
17
+ <Button>Get Started</Button>
18
+ </div>
19
+ );
20
+ }
@@ -0,0 +1,31 @@
1
+ import js from "@eslint/js";
2
+ import globals from "globals";
3
+ import reactHooks from "eslint-plugin-react-hooks";
4
+ import reactRefresh from "eslint-plugin-react-refresh";
5
+
6
+ export default [
7
+ { ignores: ["dist"] },
8
+ {
9
+ files: ["**/*.{js,jsx}"],
10
+ languageOptions: {
11
+ ecmaVersion: 2020,
12
+ globals: globals.browser,
13
+ parserOptions: {
14
+ ecmaVersion: "latest",
15
+ ecmaFeatures: { jsx: true },
16
+ sourceType: "module",
17
+ },
18
+ },
19
+ plugins: {
20
+ "react-hooks": reactHooks,
21
+ "react-refresh": reactRefresh,
22
+ },
23
+ rules: {
24
+ ...reactHooks.configs.recommended.rules,
25
+ "react-refresh/only-export-components": [
26
+ "warn",
27
+ { allowConstantExport: true },
28
+ ],
29
+ },
30
+ },
31
+ ];
@@ -0,0 +1,28 @@
1
+ import js from "@eslint/js";
2
+ import globals from "globals";
3
+ import reactHooks from "eslint-plugin-react-hooks";
4
+ import reactRefresh from "eslint-plugin-react-refresh";
5
+ import tseslint from "typescript-eslint";
6
+
7
+ export default tseslint.config(
8
+ { ignores: ["dist"] },
9
+ {
10
+ extends: [js.configs.recommended, ...tseslint.configs.recommended],
11
+ files: ["**/*.{ts,tsx}"],
12
+ languageOptions: {
13
+ ecmaVersion: 2020,
14
+ globals: globals.browser,
15
+ },
16
+ plugins: {
17
+ "react-hooks": reactHooks,
18
+ "react-refresh": reactRefresh,
19
+ },
20
+ rules: {
21
+ ...reactHooks.configs.recommended.rules,
22
+ "react-refresh/only-export-components": [
23
+ "warn",
24
+ { allowConstantExport: true },
25
+ ],
26
+ },
27
+ }
28
+ );
@@ -0,0 +1,9 @@
1
+ {
2
+ "$schema": "./oxlintrc.json",
3
+ "rules": {
4
+ "correctness": "error",
5
+ "suspicious": "warn",
6
+ "nursery": "warn"
7
+ },
8
+ "plugins": ["react", "react-hooks", "import"]
9
+ }
@@ -0,0 +1,11 @@
1
+ import React from "react";
2
+ import { MainLayout } from "@/layouts/MainLayout";
3
+ import { AppRoutes } from "@/routes";
4
+
5
+ export default function App() {
6
+ return (
7
+ <MainLayout>
8
+ <AppRoutes />
9
+ </MainLayout>
10
+ );
11
+ }
@@ -0,0 +1,11 @@
1
+ import React from "react";
2
+ import { MainLayout } from "@/layouts/MainLayout";
3
+ import { AppRoutes } from "@/routes";
4
+
5
+ export default function App() {
6
+ return (
7
+ <MainLayout>
8
+ <AppRoutes />
9
+ </MainLayout>
10
+ );
11
+ }
@@ -0,0 +1,13 @@
1
+ import React from "react";
2
+ import { BrowserRouter, Routes, Route } from "react-router-dom";
3
+ import { HomePage } from "@/pages/Home";
4
+
5
+ export function AppRoutes() {
6
+ return (
7
+ <BrowserRouter>
8
+ <Routes>
9
+ <Route path="/" element={<HomePage />} />
10
+ </Routes>
11
+ </BrowserRouter>
12
+ );
13
+ }
@@ -0,0 +1,13 @@
1
+ import React from "react";
2
+ import { BrowserRouter, Routes, Route } from "react-router-dom";
3
+ import { HomePage } from "@/pages/Home";
4
+
5
+ export function AppRoutes() {
6
+ return (
7
+ <BrowserRouter>
8
+ <Routes>
9
+ <Route path="/" element={<HomePage />} />
10
+ </Routes>
11
+ </BrowserRouter>
12
+ );
13
+ }
@@ -0,0 +1,6 @@
1
+ import React from "react";
2
+ import { AppRouter } from "./router";
3
+
4
+ export default function App() {
5
+ return <AppRouter />;
6
+ }
@@ -0,0 +1,6 @@
1
+ import React from "react";
2
+ import { AppRouter } from "./router";
3
+
4
+ export default function App() {
5
+ return <AppRouter />;
6
+ }
@@ -0,0 +1,13 @@
1
+ import { createBrowserRouter, RouterProvider } from "react-router-dom";
2
+ import { HomePage } from "@/features/home/pages/HomePage";
3
+
4
+ const router = createBrowserRouter([
5
+ {
6
+ path: "/",
7
+ element: <HomePage />,
8
+ },
9
+ ]);
10
+
11
+ export function AppRouter() {
12
+ return <RouterProvider router={router} />;
13
+ }
@@ -0,0 +1,13 @@
1
+ import { createBrowserRouter, RouterProvider } from "react-router-dom";
2
+ import { HomePage } from "@/features/home/pages/HomePage";
3
+
4
+ const router = createBrowserRouter([
5
+ {
6
+ path: "/",
7
+ element: <HomePage />,
8
+ },
9
+ ]);
10
+
11
+ export function AppRouter() {
12
+ return <RouterProvider router={router} />;
13
+ }
@@ -0,0 +1,7 @@
1
+ import React from "react";
2
+ import { Provider } from "react-redux";
3
+ import { store } from "@/store";
4
+
5
+ export function StoreProvider({ children }) {
6
+ return <Provider store={store}>{children}</Provider>;
7
+ }
@@ -0,0 +1,7 @@
1
+ import React from "react";
2
+ import { Provider } from "react-redux";
3
+ import { store } from "@/store";
4
+
5
+ export function StoreProvider({ children }) {
6
+ return <Provider store={store}>{children}</Provider>;
7
+ }
@@ -0,0 +1,20 @@
1
+ import { createSlice } from "@reduxjs/toolkit";
2
+
3
+ const counterSlice = createSlice({
4
+ name: "counter",
5
+ initialState: { value: 0 },
6
+ reducers: {
7
+ increment: (state) => {
8
+ state.value += 1;
9
+ },
10
+ decrement: (state) => {
11
+ state.value -= 1;
12
+ },
13
+ incrementByAmount: (state, action) => {
14
+ state.value += action.payload;
15
+ },
16
+ },
17
+ });
18
+
19
+ export const { increment, decrement, incrementByAmount } = counterSlice.actions;
20
+ export default counterSlice.reducer;
@@ -0,0 +1,20 @@
1
+ import { createSlice } from "@reduxjs/toolkit";
2
+
3
+ const counterSlice = createSlice({
4
+ name: "counter",
5
+ initialState: { value: 0 },
6
+ reducers: {
7
+ increment: (state) => {
8
+ state.value += 1;
9
+ },
10
+ decrement: (state) => {
11
+ state.value -= 1;
12
+ },
13
+ incrementByAmount: (state, action) => {
14
+ state.value += action.payload;
15
+ },
16
+ },
17
+ });
18
+
19
+ export const { increment, decrement, incrementByAmount } = counterSlice.actions;
20
+ export default counterSlice.reducer;
@@ -0,0 +1,4 @@
1
+ import { useDispatch, useSelector } from "react-redux";
2
+
3
+ export const useAppDispatch = useDispatch;
4
+ export const useAppSelector = useSelector;
@@ -0,0 +1,4 @@
1
+ import { useDispatch, useSelector } from "react-redux";
2
+
3
+ export const useAppDispatch = useDispatch;
4
+ export const useAppSelector = useSelector;
@@ -0,0 +1,8 @@
1
+ import { configureStore } from "@reduxjs/toolkit";
2
+ import counterReducer from "@/pages/Home/counterSlice";
3
+
4
+ export const store = configureStore({
5
+ reducer: {
6
+ counter: counterReducer,
7
+ },
8
+ });
@@ -0,0 +1,11 @@
1
+ import { configureStore } from "@reduxjs/toolkit";
2
+ import counterReducer from "@/pages/Home/counterSlice";
3
+
4
+ export const store = configureStore({
5
+ reducer: {
6
+ counter: counterReducer,
7
+ },
8
+ });
9
+
10
+ export const RootState = store.getState;
11
+ export const AppDispatch = store.dispatch;
@@ -0,0 +1,7 @@
1
+ import React from "react";
2
+ import { Provider } from "react-redux";
3
+ import { store } from "@/stores";
4
+
5
+ export function StoreProvider({ children }) {
6
+ return <Provider store={store}>{children}</Provider>;
7
+ }
@@ -0,0 +1,7 @@
1
+ import React from "react";
2
+ import { Provider } from "react-redux";
3
+ import { store } from "@/stores";
4
+
5
+ export function StoreProvider({ children }) {
6
+ return <Provider store={store}>{children}</Provider>;
7
+ }
@@ -0,0 +1,20 @@
1
+ import { createSlice } from "@reduxjs/toolkit";
2
+
3
+ const counterSlice = createSlice({
4
+ name: "counter",
5
+ initialState: { value: 0 },
6
+ reducers: {
7
+ increment: (state) => {
8
+ state.value += 1;
9
+ },
10
+ decrement: (state) => {
11
+ state.value -= 1;
12
+ },
13
+ incrementByAmount: (state, action) => {
14
+ state.value += action.payload;
15
+ },
16
+ },
17
+ });
18
+
19
+ export const { increment, decrement, incrementByAmount } = counterSlice.actions;
20
+ export default counterSlice.reducer;
@@ -0,0 +1,20 @@
1
+ import { createSlice } from "@reduxjs/toolkit";
2
+
3
+ const counterSlice = createSlice({
4
+ name: "counter",
5
+ initialState: { value: 0 },
6
+ reducers: {
7
+ increment: (state) => {
8
+ state.value += 1;
9
+ },
10
+ decrement: (state) => {
11
+ state.value -= 1;
12
+ },
13
+ incrementByAmount: (state, action) => {
14
+ state.value += action.payload;
15
+ },
16
+ },
17
+ });
18
+
19
+ export const { increment, decrement, incrementByAmount } = counterSlice.actions;
20
+ export default counterSlice.reducer;
@@ -0,0 +1,4 @@
1
+ import { useDispatch, useSelector } from "react-redux";
2
+
3
+ export const useAppDispatch = useDispatch;
4
+ export const useAppSelector = useSelector;
@@ -0,0 +1,4 @@
1
+ import { useDispatch, useSelector } from "react-redux";
2
+
3
+ export const useAppDispatch = useDispatch;
4
+ export const useAppSelector = useSelector;
@@ -0,0 +1,8 @@
1
+ import { configureStore } from "@reduxjs/toolkit";
2
+ import counterReducer from "@/features/home/store/counterSlice";
3
+
4
+ export const store = configureStore({
5
+ reducer: {
6
+ counter: counterReducer,
7
+ },
8
+ });
@@ -0,0 +1,11 @@
1
+ import { configureStore } from "@reduxjs/toolkit";
2
+ import counterReducer from "@/features/home/store/counterSlice";
3
+
4
+ export const store = configureStore({
5
+ reducer: {
6
+ counter: counterReducer,
7
+ },
8
+ });
9
+
10
+ export const RootState = store.getState;
11
+ export const AppDispatch = store.dispatch;
@@ -0,0 +1,9 @@
1
+ import { create } from "zustand";
2
+
3
+ export const useCounterStore = create((set) => ({
4
+ count: 0,
5
+ increment: () => set((state) => ({ count: state.count + 1 })),
6
+ decrement: () => set((state) => ({ count: state.count - 1 })),
7
+ incrementByAmount: (amount) =>
8
+ set((state) => ({ count: state.count + amount })),
9
+ }));
@@ -0,0 +1,9 @@
1
+ import { create } from "zustand";
2
+
3
+ export const useCounterStore = create((set) => ({
4
+ count: 0,
5
+ increment: () => set((state) => ({ count: state.count + 1 })),
6
+ decrement: () => set((state) => ({ count: state.count - 1 })),
7
+ incrementByAmount: (amount) =>
8
+ set((state) => ({ count: state.count + amount })),
9
+ }));
@@ -0,0 +1,9 @@
1
+ import { create } from "zustand";
2
+
3
+ export const useCounterStore = create((set) => ({
4
+ count: 0,
5
+ increment: () => set((state) => ({ count: state.count + 1 })),
6
+ decrement: () => set((state) => ({ count: state.count - 1 })),
7
+ incrementByAmount: (amount) =>
8
+ set((state) => ({ count: state.count + amount })),
9
+ }));
@@ -0,0 +1,9 @@
1
+ import { create } from "zustand";
2
+
3
+ export const useCounterStore = create((set) => ({
4
+ count: 0,
5
+ increment: () => set((state) => ({ count: state.count + 1 })),
6
+ decrement: () => set((state) => ({ count: state.count - 1 })),
7
+ incrementByAmount: (amount) =>
8
+ set((state) => ({ count: state.count + amount })),
9
+ }));
@@ -0,0 +1,12 @@
1
+ /** @type {import('jest').Config} */
2
+ module.exports = {
3
+ testEnvironment: "jsdom",
4
+ roots: ["<rootDir>/src"],
5
+ setupFilesAfterSetup: ["<rootDir>/jest.setup.js"],
6
+ moduleNameMapper: {
7
+ "^@/(.*)$": "<rootDir>/src/$1",
8
+ },
9
+ transform: {
10
+ "^.+\\.jsx?$": "babel-jest",
11
+ },
12
+ };
@@ -0,0 +1,13 @@
1
+ /** @type {import('ts-jest').JestConfigWithTsJest} */
2
+ module.exports = {
3
+ preset: "ts-jest",
4
+ testEnvironment: "jsdom",
5
+ roots: ["<rootDir>/src"],
6
+ setupFilesAfterSetup: ["<rootDir>/jest.setup.ts"],
7
+ moduleNameMapper: {
8
+ "^@/(.*)$": "<rootDir>/src/$1",
9
+ },
10
+ transform: {
11
+ "^.+\\.tsx?$": "ts-jest",
12
+ },
13
+ };
@@ -0,0 +1 @@
1
+ import "@testing-library/jest-dom";
@@ -0,0 +1 @@
1
+ import "@testing-library/jest-dom";
@@ -0,0 +1,9 @@
1
+ import { render, screen } from "@testing-library/react";
2
+ import App from "@/app/App";
3
+
4
+ describe("App", () => {
5
+ it("renders without crashing", () => {
6
+ render(<App />);
7
+ expect(screen.getByText(/Welcome/i)).toBeInTheDocument();
8
+ });
9
+ });
@@ -0,0 +1,9 @@
1
+ import { render, screen } from "@testing-library/react";
2
+ import App from "@/app/App";
3
+
4
+ describe("App", () => {
5
+ it("renders without crashing", () => {
6
+ render(<App />);
7
+ expect(screen.getByText(/Welcome/i)).toBeInTheDocument();
8
+ });
9
+ });
@@ -0,0 +1,10 @@
1
+ import { render, screen } from "@testing-library/react";
2
+ import { describe, it, expect } from "vitest";
3
+ import App from "@/app/App";
4
+
5
+ describe("App", () => {
6
+ it("renders without crashing", () => {
7
+ render(<App />);
8
+ expect(screen.getByText(/Welcome/i)).toBeInTheDocument();
9
+ });
10
+ });
@@ -0,0 +1,10 @@
1
+ import { render, screen } from "@testing-library/react";
2
+ import { describe, it, expect } from "vitest";
3
+ import App from "@/app/App";
4
+
5
+ describe("App", () => {
6
+ it("renders without crashing", () => {
7
+ render(<App />);
8
+ expect(screen.getByText(/Welcome/i)).toBeInTheDocument();
9
+ });
10
+ });
@@ -0,0 +1 @@
1
+ import "@testing-library/jest-dom/vitest";
@@ -0,0 +1 @@
1
+ import "@testing-library/jest-dom/vitest";
@@ -0,0 +1,18 @@
1
+ import { defineConfig } from "vitest/config";
2
+ import react from "@vitejs/plugin-react";
3
+ import path from "path";
4
+
5
+ export default defineConfig({
6
+ plugins: [react()],
7
+ resolve: {
8
+ alias: {
9
+ "@": path.resolve(__dirname, "./src"),
10
+ },
11
+ },
12
+ test: {
13
+ globals: true,
14
+ environment: "jsdom",
15
+ setupFiles: "./src/test/setup.js",
16
+ css: true,
17
+ },
18
+ });
@@ -0,0 +1,18 @@
1
+ import { defineConfig } from "vitest/config";
2
+ import react from "@vitejs/plugin-react";
3
+ import path from "path";
4
+
5
+ export default defineConfig({
6
+ plugins: [react()],
7
+ resolve: {
8
+ alias: {
9
+ "@": path.resolve(__dirname, "./src"),
10
+ },
11
+ },
12
+ test: {
13
+ globals: true,
14
+ environment: "jsdom",
15
+ setupFiles: "./src/test/setup.ts",
16
+ css: true,
17
+ },
18
+ });
@@ -0,0 +1,18 @@
1
+ *,
2
+ *::before,
3
+ *::after {
4
+ box-sizing: border-box;
5
+ margin: 0;
6
+ padding: 0;
7
+ }
8
+
9
+ html {
10
+ -webkit-font-smoothing: antialiased;
11
+ -moz-osx-font-smoothing: grayscale;
12
+ }
13
+
14
+ body {
15
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
16
+ sans-serif;
17
+ line-height: 1.5;
18
+ }
@@ -0,0 +1 @@
1
+ @import "tailwindcss";