create-react-forge 1.5.2 → 1.6.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.
Files changed (104) hide show
  1. package/README.md +6 -5
  2. package/dist/cli/index.d.ts +2 -2
  3. package/dist/cli/parser.d.ts.map +1 -1
  4. package/dist/cli/parser.js +3 -2
  5. package/dist/cli/parser.js.map +1 -1
  6. package/dist/cli/prompts.d.ts.map +1 -1
  7. package/dist/cli/prompts.js +21 -7
  8. package/dist/cli/prompts.js.map +1 -1
  9. package/dist/config/defaults.d.ts +2 -2
  10. package/dist/config/defaults.d.ts.map +1 -1
  11. package/dist/config/defaults.js +3 -2
  12. package/dist/config/defaults.js.map +1 -1
  13. package/dist/config/schema.d.ts +15 -13
  14. package/dist/config/schema.d.ts.map +1 -1
  15. package/dist/config/schema.js +5 -4
  16. package/dist/config/schema.js.map +1 -1
  17. package/dist/docs/index.d.ts +1 -0
  18. package/dist/docs/index.d.ts.map +1 -1
  19. package/dist/docs/index.js +1 -0
  20. package/dist/docs/index.js.map +1 -1
  21. package/dist/docs/readme-generator.d.ts +6 -0
  22. package/dist/docs/readme-generator.d.ts.map +1 -0
  23. package/dist/docs/readme-generator.js +276 -0
  24. package/dist/docs/readme-generator.js.map +1 -0
  25. package/dist/generator/index.d.ts.map +1 -1
  26. package/dist/generator/index.js +5 -2
  27. package/dist/generator/index.js.map +1 -1
  28. package/dist/templates/registry.d.ts +6 -2
  29. package/dist/templates/registry.d.ts.map +1 -1
  30. package/dist/templates/registry.js +31 -16
  31. package/dist/templates/registry.js.map +1 -1
  32. package/dist/templates/utils.js +4 -4
  33. package/dist/templates/utils.js.map +1 -1
  34. package/package.json +1 -1
  35. package/src/templates/overlays/base/manifest.json +4 -3
  36. package/src/templates/overlays/base/src/components/ui/Button.tsx +103 -31
  37. package/src/templates/overlays/base/src/components/ui/Input.tsx +55 -29
  38. package/src/templates/overlays/base/src/lib/utils.ts +0 -10
  39. package/src/templates/overlays/runtime/nextjs/src/app/error.tsx +39 -10
  40. package/src/templates/overlays/runtime/nextjs/src/app/loading.tsx +25 -7
  41. package/src/templates/overlays/runtime/nextjs/src/app/not-found.tsx +54 -13
  42. package/src/templates/overlays/runtime/nextjs/src/app/page.tsx +55 -13
  43. package/src/templates/overlays/runtime/nextjs/src/styles/globals.css +1 -1
  44. package/src/templates/overlays/runtime/vite/src/components/errors/ErrorFallback.tsx +49 -15
  45. package/src/templates/overlays/runtime/vite/src/components/ui/LoadingSpinner.tsx +33 -13
  46. package/src/templates/overlays/runtime/vite/src/features/misc/routes/Landing.tsx +78 -21
  47. package/src/templates/overlays/runtime/vite/src/features/misc/routes/NotFound.tsx +77 -19
  48. package/src/templates/overlays/runtime/vite/src/main.tsx +0 -2
  49. package/src/templates/overlays/state/jotai/manifest.json +16 -0
  50. package/src/templates/overlays/state/jotai/src/stores/atoms.ts +52 -0
  51. package/src/templates/overlays/state/jotai/src/stores/index.ts +30 -0
  52. package/src/templates/overlays/styling/css/_nextjs/src/app/error.css +49 -0
  53. package/src/templates/overlays/styling/css/_nextjs/src/app/error.tsx +34 -0
  54. package/src/templates/overlays/styling/css/_nextjs/src/app/loading.css +28 -0
  55. package/src/templates/overlays/styling/css/_nextjs/src/app/loading.tsx +13 -0
  56. package/src/templates/overlays/styling/css/_nextjs/src/app/not-found.css +70 -0
  57. package/src/templates/overlays/styling/css/_nextjs/src/app/not-found.tsx +25 -0
  58. package/src/templates/overlays/styling/css/_nextjs/src/app/page.css +73 -0
  59. package/src/templates/overlays/styling/css/_nextjs/src/app/page.tsx +32 -0
  60. package/src/templates/overlays/styling/css/_vite/src/components/errors/ErrorFallback.css +49 -0
  61. package/src/templates/overlays/styling/css/_vite/src/components/errors/ErrorFallback.tsx +22 -0
  62. package/src/templates/overlays/styling/css/_vite/src/components/ui/LoadingSpinner.css +40 -0
  63. package/src/templates/overlays/styling/css/_vite/src/components/ui/LoadingSpinner.tsx +21 -0
  64. package/src/templates/overlays/styling/css/_vite/src/features/misc/routes/Landing.css +73 -0
  65. package/src/templates/overlays/styling/css/_vite/src/features/misc/routes/Landing.tsx +32 -0
  66. package/src/templates/overlays/styling/css/_vite/src/features/misc/routes/NotFound.css +70 -0
  67. package/src/templates/overlays/styling/css/_vite/src/features/misc/routes/NotFound.tsx +25 -0
  68. package/src/templates/overlays/styling/css/manifest.json +17 -0
  69. package/src/templates/overlays/styling/css/src/styles/globals.css +107 -0
  70. package/src/templates/overlays/styling/css-modules/_nextjs/src/app/loading.tsx +13 -0
  71. package/src/templates/overlays/styling/css-modules/_nextjs/src/app/page.module.css +73 -0
  72. package/src/templates/overlays/styling/css-modules/_nextjs/src/app/page.tsx +32 -0
  73. package/src/templates/overlays/styling/css-modules/_vite/src/components/errors/ErrorFallback.module.css +45 -0
  74. package/src/templates/overlays/styling/css-modules/_vite/src/components/errors/ErrorFallback.tsx +22 -0
  75. package/src/templates/overlays/styling/css-modules/_vite/src/components/ui/LoadingSpinner.module.css +40 -0
  76. package/src/templates/overlays/styling/css-modules/_vite/src/components/ui/LoadingSpinner.tsx +23 -0
  77. package/src/templates/overlays/styling/css-modules/_vite/src/features/misc/routes/Landing.module.css +73 -0
  78. package/src/templates/overlays/styling/css-modules/_vite/src/features/misc/routes/Landing.tsx +32 -0
  79. package/src/templates/overlays/styling/css-modules/_vite/src/features/misc/routes/NotFound.module.css +67 -0
  80. package/src/templates/overlays/styling/css-modules/_vite/src/features/misc/routes/NotFound.tsx +25 -0
  81. package/src/templates/overlays/styling/css-modules/manifest.json +6 -3
  82. package/src/templates/overlays/styling/css-modules/src/css.d.ts +13 -0
  83. package/src/templates/overlays/styling/styled-components/_nextjs/src/app/error.tsx +72 -0
  84. package/src/templates/overlays/styling/styled-components/_nextjs/src/app/layout.tsx +25 -0
  85. package/src/templates/overlays/styling/styled-components/_nextjs/src/app/loading.tsx +40 -0
  86. package/src/templates/overlays/styling/styled-components/_nextjs/src/app/not-found.tsx +91 -0
  87. package/src/templates/overlays/styling/styled-components/_nextjs/src/app/page.tsx +102 -0
  88. package/src/templates/overlays/styling/styled-components/_nextjs/src/app/providers.tsx +22 -0
  89. package/src/templates/overlays/styling/styled-components/{src → _nextjs/src}/lib/StyledComponentsRegistry.tsx +10 -2
  90. package/src/templates/overlays/styling/styled-components/_vite/src/app/provider.tsx +27 -0
  91. package/src/templates/overlays/styling/styled-components/_vite/src/components/errors/ErrorFallback.tsx +59 -0
  92. package/src/templates/overlays/styling/styled-components/_vite/src/components/ui/LoadingSpinner.tsx +47 -0
  93. package/src/templates/overlays/styling/styled-components/_vite/src/features/misc/routes/Landing.tsx +100 -0
  94. package/src/templates/overlays/styling/styled-components/_vite/src/features/misc/routes/NotFound.tsx +89 -0
  95. package/src/templates/overlays/styling/styled-components/_vite/src/main.tsx +13 -0
  96. package/src/templates/overlays/styling/styled-components/manifest.json +5 -1
  97. package/src/templates/overlays/styling/tailwind/_nextjs/src/app/error.tsx +33 -0
  98. package/src/templates/overlays/styling/tailwind/_nextjs/src/app/loading.tsx +12 -0
  99. package/src/templates/overlays/styling/tailwind/_nextjs/src/app/not-found.tsx +26 -0
  100. package/src/templates/overlays/styling/tailwind/_nextjs/src/app/page.tsx +33 -0
  101. package/src/templates/overlays/styling/tailwind/manifest.json +5 -3
  102. package/src/templates/overlays/runtime/vite/src/styles/globals.css +0 -55
  103. package/src/templates/overlays/styling/css-modules/src/components/ui/Button.module.css +0 -87
  104. package/src/templates/overlays/styling/css-modules/src/styles/globals.css +0 -91
@@ -0,0 +1,32 @@
1
+ import Link from 'next/link';
2
+ import './page.css';
3
+
4
+ export default function HomePage() {
5
+ return (
6
+ <div className="landing-container">
7
+ <div className="landing-content">
8
+ <h1 className="landing-title">Welcome to Your App</h1>
9
+ <p className="landing-description">
10
+ A production-ready Next.js application scaffolded with create-react-forge.
11
+ </p>
12
+ <div className="landing-buttons">
13
+ <Link href="/dashboard" className="btn btn-primary">
14
+ Get started
15
+ </Link>
16
+ <a
17
+ href="https://github.com/alan2207/bulletproof-react"
18
+ className="btn btn-link"
19
+ target="_blank"
20
+ rel="noopener noreferrer"
21
+ >
22
+ Learn more <span aria-hidden="true">→</span>
23
+ </a>
24
+ </div>
25
+ </div>
26
+ </div>
27
+ );
28
+ }
29
+
30
+
31
+
32
+
@@ -0,0 +1,49 @@
1
+ .error-container {
2
+ display: flex;
3
+ min-height: 100vh;
4
+ flex-direction: column;
5
+ align-items: center;
6
+ justify-content: center;
7
+ }
8
+
9
+ .error-content {
10
+ text-align: center;
11
+ }
12
+
13
+ .error-title {
14
+ font-size: 1.5rem;
15
+ font-weight: 700;
16
+ color: var(--color-danger);
17
+ }
18
+
19
+ .error-message {
20
+ margin-top: 1rem;
21
+ color: var(--color-text-muted);
22
+ }
23
+
24
+ .btn {
25
+ display: inline-block;
26
+ font-weight: 600;
27
+ text-decoration: none;
28
+ transition: all 0.2s;
29
+ border: none;
30
+ cursor: pointer;
31
+ }
32
+
33
+ .btn-primary {
34
+ margin-top: 1.5rem;
35
+ border-radius: var(--radius-md);
36
+ background-color: var(--color-primary);
37
+ padding: 0.625rem 0.875rem;
38
+ font-size: 0.875rem;
39
+ color: white;
40
+ box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
41
+ }
42
+
43
+ .btn-primary:hover {
44
+ background-color: var(--color-primary-hover);
45
+ }
46
+
47
+
48
+
49
+
@@ -0,0 +1,22 @@
1
+ import { FallbackProps } from 'react-error-boundary';
2
+ import './ErrorFallback.css';
3
+
4
+ export function ErrorFallback({ error, resetErrorBoundary }: FallbackProps) {
5
+ return (
6
+ <div className="error-container" role="alert">
7
+ <div className="error-content">
8
+ <h1 className="error-title">Something went wrong</h1>
9
+ <p className="error-message">
10
+ {error.message || 'An unexpected error occurred'}
11
+ </p>
12
+ <button onClick={resetErrorBoundary} className="btn btn-primary">
13
+ Try again
14
+ </button>
15
+ </div>
16
+ </div>
17
+ );
18
+ }
19
+
20
+
21
+
22
+
@@ -0,0 +1,40 @@
1
+ .spinner-container {
2
+ display: flex;
3
+ align-items: center;
4
+ justify-content: center;
5
+ }
6
+
7
+ .spinner {
8
+ border-radius: 50%;
9
+ border: 2px solid var(--color-border);
10
+ border-top-color: var(--color-primary);
11
+ animation: spin 1s linear infinite;
12
+ }
13
+
14
+ .spinner-sm {
15
+ width: 1rem;
16
+ height: 1rem;
17
+ }
18
+
19
+ .spinner-md {
20
+ width: 2rem;
21
+ height: 2rem;
22
+ }
23
+
24
+ .spinner-lg {
25
+ width: 4rem;
26
+ height: 4rem;
27
+ }
28
+
29
+ @keyframes spin {
30
+ from {
31
+ transform: rotate(0deg);
32
+ }
33
+ to {
34
+ transform: rotate(360deg);
35
+ }
36
+ }
37
+
38
+
39
+
40
+
@@ -0,0 +1,21 @@
1
+ import './LoadingSpinner.css';
2
+
3
+ type LoadingSpinnerProps = {
4
+ size?: 'sm' | 'md' | 'lg';
5
+ };
6
+
7
+ export function LoadingSpinner({ size = 'md' }: LoadingSpinnerProps) {
8
+ return (
9
+ <div className="spinner-container">
10
+ <div
11
+ className={`spinner spinner-${size}`}
12
+ role="status"
13
+ aria-label="Loading"
14
+ />
15
+ </div>
16
+ );
17
+ }
18
+
19
+
20
+
21
+
@@ -0,0 +1,73 @@
1
+ .landing-container {
2
+ display: flex;
3
+ min-height: 100vh;
4
+ flex-direction: column;
5
+ align-items: center;
6
+ justify-content: center;
7
+ }
8
+
9
+ .landing-content {
10
+ text-align: center;
11
+ }
12
+
13
+ .landing-title {
14
+ font-size: 2.25rem;
15
+ font-weight: 700;
16
+ letter-spacing: -0.025em;
17
+ color: var(--color-text);
18
+ }
19
+
20
+ @media (min-width: 640px) {
21
+ .landing-title {
22
+ font-size: 3.75rem;
23
+ }
24
+ }
25
+
26
+ .landing-description {
27
+ margin-top: 1.5rem;
28
+ font-size: 1.125rem;
29
+ line-height: 2rem;
30
+ color: var(--color-text-muted);
31
+ }
32
+
33
+ .landing-buttons {
34
+ margin-top: 2.5rem;
35
+ display: flex;
36
+ align-items: center;
37
+ justify-content: center;
38
+ gap: 1.5rem;
39
+ }
40
+
41
+ .btn {
42
+ display: inline-block;
43
+ font-weight: 600;
44
+ text-decoration: none;
45
+ transition: all 0.2s;
46
+ }
47
+
48
+ .btn-primary {
49
+ border-radius: var(--radius-md);
50
+ background-color: var(--color-primary);
51
+ padding: 0.625rem 0.875rem;
52
+ font-size: 0.875rem;
53
+ color: white;
54
+ box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
55
+ }
56
+
57
+ .btn-primary:hover {
58
+ background-color: var(--color-primary-hover);
59
+ }
60
+
61
+ .btn-link {
62
+ font-size: 0.875rem;
63
+ line-height: 1.5rem;
64
+ color: var(--color-text);
65
+ }
66
+
67
+ .btn-link:hover {
68
+ color: var(--color-primary);
69
+ }
70
+
71
+
72
+
73
+
@@ -0,0 +1,32 @@
1
+ import { Link } from 'react-router-dom';
2
+ import './Landing.css';
3
+
4
+ export function Landing() {
5
+ return (
6
+ <div className="landing-container">
7
+ <div className="landing-content">
8
+ <h1 className="landing-title">Welcome to Your App</h1>
9
+ <p className="landing-description">
10
+ A production-ready React application scaffolded with create-react-forge.
11
+ </p>
12
+ <div className="landing-buttons">
13
+ <Link to="/dashboard" className="btn btn-primary">
14
+ Get started
15
+ </Link>
16
+ <a
17
+ href="https://github.com/alan2207/bulletproof-react"
18
+ className="btn btn-link"
19
+ target="_blank"
20
+ rel="noopener noreferrer"
21
+ >
22
+ Learn more <span aria-hidden="true">→</span>
23
+ </a>
24
+ </div>
25
+ </div>
26
+ </div>
27
+ );
28
+ }
29
+
30
+
31
+
32
+
@@ -0,0 +1,70 @@
1
+ .not-found-container {
2
+ display: flex;
3
+ min-height: 100vh;
4
+ flex-direction: column;
5
+ align-items: center;
6
+ justify-content: center;
7
+ }
8
+
9
+ .not-found-content {
10
+ text-align: center;
11
+ }
12
+
13
+ .not-found-code {
14
+ font-size: 1rem;
15
+ font-weight: 600;
16
+ color: var(--color-primary);
17
+ }
18
+
19
+ .not-found-title {
20
+ margin-top: 1rem;
21
+ font-size: 1.875rem;
22
+ font-weight: 700;
23
+ letter-spacing: -0.025em;
24
+ color: var(--color-text);
25
+ }
26
+
27
+ @media (min-width: 640px) {
28
+ .not-found-title {
29
+ font-size: 3rem;
30
+ }
31
+ }
32
+
33
+ .not-found-description {
34
+ margin-top: 1.5rem;
35
+ font-size: 1rem;
36
+ line-height: 1.75rem;
37
+ color: var(--color-text-muted);
38
+ }
39
+
40
+ .not-found-buttons {
41
+ margin-top: 2.5rem;
42
+ display: flex;
43
+ align-items: center;
44
+ justify-content: center;
45
+ gap: 1.5rem;
46
+ }
47
+
48
+ .btn {
49
+ display: inline-block;
50
+ font-weight: 600;
51
+ text-decoration: none;
52
+ transition: all 0.2s;
53
+ }
54
+
55
+ .btn-primary {
56
+ border-radius: var(--radius-md);
57
+ background-color: var(--color-primary);
58
+ padding: 0.625rem 0.875rem;
59
+ font-size: 0.875rem;
60
+ color: white;
61
+ box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
62
+ }
63
+
64
+ .btn-primary:hover {
65
+ background-color: var(--color-primary-hover);
66
+ }
67
+
68
+
69
+
70
+
@@ -0,0 +1,25 @@
1
+ import { Link } from 'react-router-dom';
2
+ import './NotFound.css';
3
+
4
+ export function NotFound() {
5
+ return (
6
+ <div className="not-found-container">
7
+ <div className="not-found-content">
8
+ <p className="not-found-code">404</p>
9
+ <h1 className="not-found-title">Page not found</h1>
10
+ <p className="not-found-description">
11
+ Sorry, we couldn't find the page you're looking for.
12
+ </p>
13
+ <div className="not-found-buttons">
14
+ <Link to="/" className="btn btn-primary">
15
+ Go back home
16
+ </Link>
17
+ </div>
18
+ </div>
19
+ </div>
20
+ );
21
+ }
22
+
23
+
24
+
25
+
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "styling-css",
3
+ "version": "1.0.0",
4
+ "description": "Plain CSS styling solution",
5
+ "compatibleWith": ["runtime-vite"],
6
+ "dependencies": {},
7
+ "devDependencies": {},
8
+ "scripts": {},
9
+ "filePatterns": {
10
+ "include": ["**/*"],
11
+ "exclude": ["manifest.json", "_vite"]
12
+ },
13
+ "runtimeOverrides": {
14
+ "vite": "_vite"
15
+ }
16
+ }
17
+
@@ -0,0 +1,107 @@
1
+ /* CSS Reset and Base Styles */
2
+ *,
3
+ *::before,
4
+ *::after {
5
+ box-sizing: border-box;
6
+ margin: 0;
7
+ padding: 0;
8
+ }
9
+
10
+ :root {
11
+ /* Colors */
12
+ --color-primary: #4f46e5;
13
+ --color-primary-hover: #6366f1;
14
+ --color-secondary: #64748b;
15
+ --color-success: #22c55e;
16
+ --color-warning: #f59e0b;
17
+ --color-danger: #ef4444;
18
+ --color-text: #111827;
19
+ --color-text-muted: #4b5563;
20
+ --color-background: #ffffff;
21
+ --color-border: #e5e7eb;
22
+
23
+ /* Spacing */
24
+ --spacing-xs: 0.25rem;
25
+ --spacing-sm: 0.5rem;
26
+ --spacing-md: 1rem;
27
+ --spacing-lg: 1.5rem;
28
+ --spacing-xl: 2rem;
29
+ --spacing-2xl: 2.5rem;
30
+
31
+ /* Border Radius */
32
+ --radius-sm: 0.25rem;
33
+ --radius-md: 0.375rem;
34
+ --radius-lg: 0.5rem;
35
+ --radius-full: 9999px;
36
+
37
+ /* Font */
38
+ --font-sans: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
39
+ --font-mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace;
40
+ }
41
+
42
+ html {
43
+ font-family: var(--font-sans);
44
+ line-height: 1.5;
45
+ -webkit-text-size-adjust: 100%;
46
+ }
47
+
48
+ body {
49
+ color: var(--color-text);
50
+ background-color: var(--color-background);
51
+ }
52
+
53
+ a {
54
+ color: inherit;
55
+ text-decoration: none;
56
+ }
57
+
58
+ button {
59
+ font-family: inherit;
60
+ font-size: inherit;
61
+ cursor: pointer;
62
+ }
63
+
64
+ /* Utility Classes */
65
+ .flex {
66
+ display: flex;
67
+ }
68
+
69
+ .flex-col {
70
+ flex-direction: column;
71
+ }
72
+
73
+ .items-center {
74
+ align-items: center;
75
+ }
76
+
77
+ .justify-center {
78
+ justify-content: center;
79
+ }
80
+
81
+ .text-center {
82
+ text-align: center;
83
+ }
84
+
85
+ .min-h-screen {
86
+ min-height: 100vh;
87
+ }
88
+
89
+ .gap-6 {
90
+ gap: var(--spacing-lg);
91
+ }
92
+
93
+ .mt-4 {
94
+ margin-top: var(--spacing-md);
95
+ }
96
+
97
+ .mt-6 {
98
+ margin-top: var(--spacing-lg);
99
+ }
100
+
101
+ .mt-10 {
102
+ margin-top: var(--spacing-2xl);
103
+ }
104
+
105
+
106
+
107
+
@@ -0,0 +1,13 @@
1
+ import styles from './loading.module.css';
2
+
3
+ export default function Loading() {
4
+ return (
5
+ <div className={styles.container}>
6
+ <div className={styles.spinner} role="status" aria-label="Loading" />
7
+ </div>
8
+ );
9
+ }
10
+
11
+
12
+
13
+
@@ -0,0 +1,73 @@
1
+ .container {
2
+ display: flex;
3
+ min-height: 100vh;
4
+ flex-direction: column;
5
+ align-items: center;
6
+ justify-content: center;
7
+ }
8
+
9
+ .content {
10
+ text-align: center;
11
+ }
12
+
13
+ .title {
14
+ font-size: 2.25rem;
15
+ font-weight: 700;
16
+ letter-spacing: -0.025em;
17
+ color: var(--color-text);
18
+ }
19
+
20
+ @media (min-width: 640px) {
21
+ .title {
22
+ font-size: 3.75rem;
23
+ }
24
+ }
25
+
26
+ .description {
27
+ margin-top: 1.5rem;
28
+ font-size: 1.125rem;
29
+ line-height: 2rem;
30
+ color: var(--color-text-muted);
31
+ }
32
+
33
+ .buttons {
34
+ margin-top: 2.5rem;
35
+ display: flex;
36
+ align-items: center;
37
+ justify-content: center;
38
+ gap: 1.5rem;
39
+ }
40
+
41
+ .primaryBtn {
42
+ display: inline-block;
43
+ border-radius: var(--radius-md);
44
+ background-color: var(--color-primary);
45
+ padding: 0.625rem 0.875rem;
46
+ font-size: 0.875rem;
47
+ font-weight: 600;
48
+ color: white;
49
+ text-decoration: none;
50
+ box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
51
+ transition: background-color 0.2s;
52
+ }
53
+
54
+ .primaryBtn:hover {
55
+ background-color: var(--color-primary-hover);
56
+ }
57
+
58
+ .linkBtn {
59
+ font-size: 0.875rem;
60
+ font-weight: 600;
61
+ line-height: 1.5rem;
62
+ color: var(--color-text);
63
+ text-decoration: none;
64
+ transition: color 0.2s;
65
+ }
66
+
67
+ .linkBtn:hover {
68
+ color: var(--color-primary);
69
+ }
70
+
71
+
72
+
73
+
@@ -0,0 +1,32 @@
1
+ import Link from 'next/link';
2
+ import styles from './page.module.css';
3
+
4
+ export default function HomePage() {
5
+ return (
6
+ <div className={styles.container}>
7
+ <div className={styles.content}>
8
+ <h1 className={styles.title}>Welcome to Your App</h1>
9
+ <p className={styles.description}>
10
+ A production-ready Next.js application scaffolded with create-react-forge.
11
+ </p>
12
+ <div className={styles.buttons}>
13
+ <Link href="/dashboard" className={styles.primaryBtn}>
14
+ Get started
15
+ </Link>
16
+ <a
17
+ href="https://github.com/alan2207/bulletproof-react"
18
+ className={styles.linkBtn}
19
+ target="_blank"
20
+ rel="noopener noreferrer"
21
+ >
22
+ Learn more <span aria-hidden="true">→</span>
23
+ </a>
24
+ </div>
25
+ </div>
26
+ </div>
27
+ );
28
+ }
29
+
30
+
31
+
32
+
@@ -0,0 +1,45 @@
1
+ .container {
2
+ display: flex;
3
+ min-height: 100vh;
4
+ flex-direction: column;
5
+ align-items: center;
6
+ justify-content: center;
7
+ }
8
+
9
+ .content {
10
+ text-align: center;
11
+ }
12
+
13
+ .title {
14
+ font-size: 1.5rem;
15
+ font-weight: 700;
16
+ color: var(--color-danger);
17
+ }
18
+
19
+ .message {
20
+ margin-top: 1rem;
21
+ color: var(--color-text-muted);
22
+ }
23
+
24
+ .button {
25
+ margin-top: 1.5rem;
26
+ display: inline-block;
27
+ border-radius: var(--radius-md);
28
+ background-color: var(--color-primary);
29
+ padding: 0.625rem 0.875rem;
30
+ font-size: 0.875rem;
31
+ font-weight: 600;
32
+ color: white;
33
+ border: none;
34
+ cursor: pointer;
35
+ box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
36
+ transition: background-color 0.2s;
37
+ }
38
+
39
+ .button:hover {
40
+ background-color: var(--color-primary-hover);
41
+ }
42
+
43
+
44
+
45
+
@@ -0,0 +1,22 @@
1
+ import { FallbackProps } from 'react-error-boundary';
2
+ import styles from './ErrorFallback.module.css';
3
+
4
+ export function ErrorFallback({ error, resetErrorBoundary }: FallbackProps) {
5
+ return (
6
+ <div className={styles.container} role="alert">
7
+ <div className={styles.content}>
8
+ <h1 className={styles.title}>Something went wrong</h1>
9
+ <p className={styles.message}>
10
+ {error.message || 'An unexpected error occurred'}
11
+ </p>
12
+ <button onClick={resetErrorBoundary} className={styles.button}>
13
+ Try again
14
+ </button>
15
+ </div>
16
+ </div>
17
+ );
18
+ }
19
+
20
+
21
+
22
+