create-modern-react 1.0.0 → 2.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 (59) hide show
  1. package/README.md +270 -72
  2. package/bin/index.js +13 -13
  3. package/lib/install.js +103 -32
  4. package/lib/prompts.js +152 -179
  5. package/lib/setup.js +267 -159
  6. package/package.json +17 -8
  7. package/templates/base/.env.example +9 -0
  8. package/templates/base/.eslintrc.cjs +37 -0
  9. package/templates/base/.prettierrc +11 -0
  10. package/templates/base/components.json +17 -0
  11. package/templates/base/index.html +2 -1
  12. package/templates/base/package.json +33 -14
  13. package/templates/base/postcss.config.js +6 -0
  14. package/templates/base/src/App.tsx +5 -18
  15. package/templates/base/src/components/layout/error-boundary.tsx +60 -0
  16. package/templates/base/src/components/layout/index.ts +2 -0
  17. package/templates/base/src/components/layout/root-layout.tsx +36 -0
  18. package/templates/base/src/components/ui/button.tsx +55 -0
  19. package/templates/base/src/components/ui/card.tsx +85 -0
  20. package/templates/base/src/components/ui/index.ts +12 -0
  21. package/templates/base/src/components/ui/input.tsx +24 -0
  22. package/templates/base/src/components/ui/separator.tsx +29 -0
  23. package/templates/base/src/components/ui/skeleton.tsx +15 -0
  24. package/templates/base/src/hooks/index.ts +3 -0
  25. package/templates/base/src/hooks/use-cancel-token.ts +63 -0
  26. package/templates/base/src/hooks/use-debounce.ts +29 -0
  27. package/templates/base/src/hooks/use-loader.ts +39 -0
  28. package/templates/base/src/index.css +73 -60
  29. package/templates/base/src/lib/utils.ts +14 -0
  30. package/templates/base/src/main.tsx +6 -6
  31. package/templates/base/src/providers/index.tsx +27 -0
  32. package/templates/base/src/providers/theme-provider.tsx +92 -0
  33. package/templates/base/src/routes/index.tsx +40 -0
  34. package/templates/base/src/routes/routes.ts +36 -0
  35. package/templates/base/src/screens/home/index.tsx +132 -0
  36. package/templates/base/src/screens/not-found/index.tsx +29 -0
  37. package/templates/base/src/services/alertify-services.ts +133 -0
  38. package/templates/base/src/services/api/api-helpers.ts +130 -0
  39. package/templates/base/src/services/api/axios-instance.ts +77 -0
  40. package/templates/base/src/services/api/index.ts +9 -0
  41. package/templates/base/src/services/index.ts +2 -0
  42. package/templates/base/src/types/index.ts +55 -0
  43. package/templates/base/src/vite-env.d.ts +31 -0
  44. package/templates/base/tailwind.config.js +77 -0
  45. package/templates/base/tsconfig.json +4 -3
  46. package/templates/base/tsconfig.node.json +22 -0
  47. package/templates/base/vite.config.ts +65 -4
  48. package/templates/optional/antd/config-provider.tsx +33 -0
  49. package/templates/optional/antd/index.ts +2 -0
  50. package/templates/optional/antd/styles/antd-overrides.css +104 -0
  51. package/templates/optional/antd/theme.ts +75 -0
  52. package/templates/optional/husky/.husky/pre-commit +1 -0
  53. package/templates/optional/husky/.lintstagedrc.json +6 -0
  54. package/templates/optional/redux/hooks.ts +17 -0
  55. package/templates/optional/redux/index.ts +13 -0
  56. package/templates/optional/redux/provider.tsx +33 -0
  57. package/templates/optional/redux/store/index.ts +45 -0
  58. package/templates/optional/redux/store/slices/app-slice.ts +62 -0
  59. package/templates/base/src/App.css +0 -14
@@ -0,0 +1,75 @@
1
+ import type { ThemeConfig } from 'antd';
2
+
3
+ /**
4
+ * Ant Design theme configuration
5
+ * Customizes the design tokens to match your brand
6
+ *
7
+ * @see https://ant.design/docs/react/customize-theme
8
+ */
9
+ export const antdTheme: ThemeConfig = {
10
+ token: {
11
+ // Primary colors
12
+ colorPrimary: '#1677ff',
13
+ colorSuccess: '#52c41a',
14
+ colorWarning: '#faad14',
15
+ colorError: '#ff4d4f',
16
+ colorInfo: '#1677ff',
17
+
18
+ // Border radius
19
+ borderRadius: 6,
20
+ borderRadiusLG: 8,
21
+ borderRadiusSM: 4,
22
+
23
+ // Font
24
+ fontFamily:
25
+ 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
26
+ fontSize: 14,
27
+
28
+ // Control height
29
+ controlHeight: 36,
30
+ controlHeightLG: 44,
31
+ controlHeightSM: 28,
32
+
33
+ // Motion
34
+ motionDurationFast: '0.1s',
35
+ motionDurationMid: '0.2s',
36
+ motionDurationSlow: '0.3s',
37
+ },
38
+ components: {
39
+ Button: {
40
+ primaryShadow: 'none',
41
+ defaultShadow: 'none',
42
+ },
43
+ Input: {
44
+ activeBorderColor: '#1677ff',
45
+ hoverBorderColor: '#4096ff',
46
+ },
47
+ Card: {
48
+ headerBg: 'transparent',
49
+ },
50
+ Table: {
51
+ headerBg: '#fafafa',
52
+ },
53
+ Menu: {
54
+ itemBg: 'transparent',
55
+ },
56
+ },
57
+ };
58
+
59
+ /**
60
+ * Dark theme configuration
61
+ */
62
+ export const antdDarkTheme: ThemeConfig = {
63
+ ...antdTheme,
64
+ token: {
65
+ ...antdTheme.token,
66
+ // Override for dark mode
67
+ colorBgContainer: '#141414',
68
+ colorBgElevated: '#1f1f1f',
69
+ colorBgLayout: '#000000',
70
+ colorBorderSecondary: '#303030',
71
+ colorText: 'rgba(255, 255, 255, 0.85)',
72
+ colorTextSecondary: 'rgba(255, 255, 255, 0.65)',
73
+ colorTextTertiary: 'rgba(255, 255, 255, 0.45)',
74
+ },
75
+ };
@@ -0,0 +1 @@
1
+ npx lint-staged
@@ -0,0 +1,6 @@
1
+ {
2
+ "*.{ts,tsx}": ["eslint --fix", "prettier --write"],
3
+ "*.{js,jsx}": ["eslint --fix", "prettier --write"],
4
+ "*.{css,scss}": ["prettier --write"],
5
+ "*.{json,md}": ["prettier --write"]
6
+ }
@@ -0,0 +1,17 @@
1
+ import { useDispatch, useSelector, type TypedUseSelectorHook } from 'react-redux';
2
+ import type { RootState, AppDispatch } from './store';
3
+
4
+ /**
5
+ * Typed version of useDispatch hook
6
+ * Use this instead of plain `useDispatch` for better type inference
7
+ */
8
+ export const useAppDispatch = () => useDispatch<AppDispatch>();
9
+
10
+ /**
11
+ * Typed version of useSelector hook
12
+ * Use this instead of plain `useSelector` for better type inference
13
+ *
14
+ * @example
15
+ * const isLoading = useAppSelector((state) => state.app.isLoading);
16
+ */
17
+ export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
@@ -0,0 +1,13 @@
1
+ export { store, persistor, type RootState, type AppDispatch } from './store';
2
+ export { useAppDispatch, useAppSelector } from './hooks';
3
+ export { ReduxProvider } from './provider';
4
+
5
+ // Re-export slice actions
6
+ export {
7
+ setLoading,
8
+ toggleSidebar,
9
+ setSidebarOpen,
10
+ addNotification,
11
+ removeNotification,
12
+ clearNotifications,
13
+ } from './store/slices/app-slice';
@@ -0,0 +1,33 @@
1
+ import { Provider } from 'react-redux';
2
+ import { PersistGate } from 'redux-persist/integration/react';
3
+ import { store, persistor } from './store';
4
+ import { Skeleton } from '~/components/ui';
5
+
6
+ interface ReduxProviderProps {
7
+ children: React.ReactNode;
8
+ }
9
+
10
+ function LoadingFallback() {
11
+ return (
12
+ <div className="flex min-h-screen items-center justify-center">
13
+ <div className="flex flex-col items-center gap-4">
14
+ <Skeleton className="h-12 w-12 rounded-full" />
15
+ <Skeleton className="h-4 w-32" />
16
+ </div>
17
+ </div>
18
+ );
19
+ }
20
+
21
+ /**
22
+ * Redux Provider with persistence
23
+ * Wraps the application with Redux store and persist gate
24
+ */
25
+ export function ReduxProvider({ children }: ReduxProviderProps) {
26
+ return (
27
+ <Provider store={store}>
28
+ <PersistGate loading={<LoadingFallback />} persistor={persistor}>
29
+ {children}
30
+ </PersistGate>
31
+ </Provider>
32
+ );
33
+ }
@@ -0,0 +1,45 @@
1
+ import { configureStore, combineReducers } from '@reduxjs/toolkit';
2
+ import {
3
+ persistStore,
4
+ persistReducer,
5
+ FLUSH,
6
+ REHYDRATE,
7
+ PAUSE,
8
+ PERSIST,
9
+ PURGE,
10
+ REGISTER,
11
+ } from 'redux-persist';
12
+ import storage from 'redux-persist/lib/storage';
13
+
14
+ import appReducer from './slices/app-slice';
15
+
16
+ const rootReducer = combineReducers({
17
+ app: appReducer,
18
+ // Add more reducers here
19
+ });
20
+
21
+ const persistConfig = {
22
+ key: 'root',
23
+ version: 1,
24
+ storage,
25
+ whitelist: ['app'], // Only persist these reducers
26
+ // blacklist: [], // Don't persist these reducers
27
+ };
28
+
29
+ const persistedReducer = persistReducer(persistConfig, rootReducer);
30
+
31
+ export const store = configureStore({
32
+ reducer: persistedReducer,
33
+ middleware: (getDefaultMiddleware) =>
34
+ getDefaultMiddleware({
35
+ serializableCheck: {
36
+ ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
37
+ },
38
+ }),
39
+ devTools: import.meta.env.DEV,
40
+ });
41
+
42
+ export const persistor = persistStore(store);
43
+
44
+ export type RootState = ReturnType<typeof store.getState>;
45
+ export type AppDispatch = typeof store.dispatch;
@@ -0,0 +1,62 @@
1
+ import { createSlice, PayloadAction } from '@reduxjs/toolkit';
2
+
3
+ interface AppState {
4
+ isLoading: boolean;
5
+ sidebarOpen: boolean;
6
+ notifications: Notification[];
7
+ }
8
+
9
+ interface Notification {
10
+ id: string;
11
+ type: 'success' | 'error' | 'warning' | 'info';
12
+ message: string;
13
+ timestamp: number;
14
+ }
15
+
16
+ const initialState: AppState = {
17
+ isLoading: false,
18
+ sidebarOpen: true,
19
+ notifications: [],
20
+ };
21
+
22
+ const appSlice = createSlice({
23
+ name: 'app',
24
+ initialState,
25
+ reducers: {
26
+ setLoading: (state, action: PayloadAction<boolean>) => {
27
+ state.isLoading = action.payload;
28
+ },
29
+ toggleSidebar: (state) => {
30
+ state.sidebarOpen = !state.sidebarOpen;
31
+ },
32
+ setSidebarOpen: (state, action: PayloadAction<boolean>) => {
33
+ state.sidebarOpen = action.payload;
34
+ },
35
+ addNotification: (state, action: PayloadAction<Omit<Notification, 'id' | 'timestamp'>>) => {
36
+ state.notifications.push({
37
+ ...action.payload,
38
+ id: crypto.randomUUID(),
39
+ timestamp: Date.now(),
40
+ });
41
+ },
42
+ removeNotification: (state, action: PayloadAction<string>) => {
43
+ state.notifications = state.notifications.filter(
44
+ (n) => n.id !== action.payload
45
+ );
46
+ },
47
+ clearNotifications: (state) => {
48
+ state.notifications = [];
49
+ },
50
+ },
51
+ });
52
+
53
+ export const {
54
+ setLoading,
55
+ toggleSidebar,
56
+ setSidebarOpen,
57
+ addNotification,
58
+ removeNotification,
59
+ clearNotifications,
60
+ } = appSlice.actions;
61
+
62
+ export default appSlice.reducer;
@@ -1,14 +0,0 @@
1
- #root {
2
- max-width: 1280px;
3
- margin: 0 auto;
4
- padding: 2rem;
5
- text-align: center;
6
- }
7
-
8
- .card {
9
- padding: 2em;
10
- }
11
-
12
- .read-the-docs {
13
- color: #888;
14
- }