create-react-forge 1.6.0 → 1.7.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 (105) hide show
  1. package/README.md +54 -25
  2. package/dist/cli/index.d.ts +1 -1
  3. package/dist/cli/index.d.ts.map +1 -1
  4. package/dist/cli/index.js +17 -3
  5. package/dist/cli/index.js.map +1 -1
  6. package/dist/cli/parser.d.ts.map +1 -1
  7. package/dist/cli/parser.js +4 -3
  8. package/dist/cli/parser.js.map +1 -1
  9. package/dist/cli/prompts.js +1 -1
  10. package/dist/cli/prompts.js.map +1 -1
  11. package/dist/config/builder.d.ts +5 -0
  12. package/dist/config/builder.d.ts.map +1 -1
  13. package/dist/config/builder.js +32 -21
  14. package/dist/config/builder.js.map +1 -1
  15. package/dist/config/defaults.d.ts +1 -1
  16. package/dist/config/defaults.js +2 -2
  17. package/dist/config/defaults.js.map +1 -1
  18. package/dist/config/schema.d.ts +11 -9
  19. package/dist/config/schema.d.ts.map +1 -1
  20. package/dist/config/schema.js +4 -3
  21. package/dist/config/schema.js.map +1 -1
  22. package/dist/docs/architecture-generator.d.ts.map +1 -1
  23. package/dist/docs/architecture-generator.js +4 -1
  24. package/dist/docs/architecture-generator.js.map +1 -1
  25. package/dist/docs/readme-generator.d.ts.map +1 -1
  26. package/dist/docs/readme-generator.js +4 -1
  27. package/dist/docs/readme-generator.js.map +1 -1
  28. package/dist/generator/index.d.ts +9 -0
  29. package/dist/generator/index.d.ts.map +1 -1
  30. package/dist/generator/index.js +126 -22
  31. package/dist/generator/index.js.map +1 -1
  32. package/dist/templates/registry.d.ts +6 -2
  33. package/dist/templates/registry.d.ts.map +1 -1
  34. package/dist/templates/registry.js +58 -32
  35. package/dist/templates/registry.js.map +1 -1
  36. package/dist/templates/utils.js +4 -4
  37. package/dist/templates/utils.js.map +1 -1
  38. package/package.json +15 -9
  39. package/src/templates/overlays/base/manifest.json +4 -3
  40. package/src/templates/overlays/base/src/components/ui/Button.tsx +103 -31
  41. package/src/templates/overlays/base/src/components/ui/Input.tsx +55 -29
  42. package/src/templates/overlays/base/src/lib/utils.ts +0 -10
  43. package/src/templates/overlays/runtime/nextjs/src/app/error.tsx +39 -10
  44. package/src/templates/overlays/runtime/nextjs/src/app/loading.tsx +25 -7
  45. package/src/templates/overlays/runtime/nextjs/src/app/not-found.tsx +54 -13
  46. package/src/templates/overlays/runtime/nextjs/src/app/page.tsx +55 -13
  47. package/src/templates/overlays/runtime/nextjs/src/styles/globals.css +1 -1
  48. package/src/templates/overlays/runtime/vite/src/components/errors/ErrorFallback.tsx +49 -15
  49. package/src/templates/overlays/runtime/vite/src/components/ui/LoadingSpinner.tsx +33 -13
  50. package/src/templates/overlays/runtime/vite/src/features/misc/routes/Landing.tsx +78 -21
  51. package/src/templates/overlays/runtime/vite/src/features/misc/routes/NotFound.tsx +77 -19
  52. package/src/templates/overlays/runtime/vite/src/main.tsx +0 -2
  53. package/src/templates/overlays/styling/css/_nextjs/src/app/error.css +49 -0
  54. package/src/templates/overlays/styling/css/_nextjs/src/app/error.tsx +34 -0
  55. package/src/templates/overlays/styling/css/_nextjs/src/app/loading.css +28 -0
  56. package/src/templates/overlays/styling/css/_nextjs/src/app/loading.tsx +13 -0
  57. package/src/templates/overlays/styling/css/_nextjs/src/app/not-found.css +70 -0
  58. package/src/templates/overlays/styling/css/_nextjs/src/app/not-found.tsx +25 -0
  59. package/src/templates/overlays/styling/css/_nextjs/src/app/page.css +73 -0
  60. package/src/templates/overlays/styling/css/_nextjs/src/app/page.tsx +32 -0
  61. package/src/templates/overlays/styling/css/_vite/src/components/errors/ErrorFallback.css +49 -0
  62. package/src/templates/overlays/styling/css/_vite/src/components/errors/ErrorFallback.tsx +22 -0
  63. package/src/templates/overlays/styling/css/_vite/src/components/ui/LoadingSpinner.css +40 -0
  64. package/src/templates/overlays/styling/css/_vite/src/components/ui/LoadingSpinner.tsx +21 -0
  65. package/src/templates/overlays/styling/css/_vite/src/features/misc/routes/Landing.css +73 -0
  66. package/src/templates/overlays/styling/css/_vite/src/features/misc/routes/Landing.tsx +32 -0
  67. package/src/templates/overlays/styling/css/_vite/src/features/misc/routes/NotFound.css +70 -0
  68. package/src/templates/overlays/styling/css/_vite/src/features/misc/routes/NotFound.tsx +25 -0
  69. package/src/templates/overlays/styling/css/manifest.json +17 -0
  70. package/src/templates/overlays/styling/css/src/styles/globals.css +107 -0
  71. package/src/templates/overlays/styling/css-modules/_nextjs/src/app/loading.tsx +13 -0
  72. package/src/templates/overlays/styling/css-modules/_nextjs/src/app/page.module.css +73 -0
  73. package/src/templates/overlays/styling/css-modules/_nextjs/src/app/page.tsx +32 -0
  74. package/src/templates/overlays/styling/css-modules/_vite/src/components/errors/ErrorFallback.module.css +45 -0
  75. package/src/templates/overlays/styling/css-modules/_vite/src/components/errors/ErrorFallback.tsx +22 -0
  76. package/src/templates/overlays/styling/css-modules/_vite/src/components/ui/LoadingSpinner.module.css +40 -0
  77. package/src/templates/overlays/styling/css-modules/_vite/src/components/ui/LoadingSpinner.tsx +23 -0
  78. package/src/templates/overlays/styling/css-modules/_vite/src/features/misc/routes/Landing.module.css +73 -0
  79. package/src/templates/overlays/styling/css-modules/_vite/src/features/misc/routes/Landing.tsx +32 -0
  80. package/src/templates/overlays/styling/css-modules/_vite/src/features/misc/routes/NotFound.module.css +67 -0
  81. package/src/templates/overlays/styling/css-modules/_vite/src/features/misc/routes/NotFound.tsx +25 -0
  82. package/src/templates/overlays/styling/css-modules/manifest.json +6 -3
  83. package/src/templates/overlays/styling/css-modules/src/css.d.ts +13 -0
  84. package/src/templates/overlays/styling/styled-components/_nextjs/src/app/error.tsx +72 -0
  85. package/src/templates/overlays/styling/styled-components/_nextjs/src/app/layout.tsx +25 -0
  86. package/src/templates/overlays/styling/styled-components/_nextjs/src/app/loading.tsx +40 -0
  87. package/src/templates/overlays/styling/styled-components/_nextjs/src/app/not-found.tsx +91 -0
  88. package/src/templates/overlays/styling/styled-components/_nextjs/src/app/page.tsx +102 -0
  89. package/src/templates/overlays/styling/styled-components/_nextjs/src/app/providers.tsx +22 -0
  90. package/src/templates/overlays/styling/styled-components/{src → _nextjs/src}/lib/StyledComponentsRegistry.tsx +10 -2
  91. package/src/templates/overlays/styling/styled-components/_vite/src/app/provider.tsx +27 -0
  92. package/src/templates/overlays/styling/styled-components/_vite/src/components/errors/ErrorFallback.tsx +59 -0
  93. package/src/templates/overlays/styling/styled-components/_vite/src/components/ui/LoadingSpinner.tsx +47 -0
  94. package/src/templates/overlays/styling/styled-components/_vite/src/features/misc/routes/Landing.tsx +100 -0
  95. package/src/templates/overlays/styling/styled-components/_vite/src/features/misc/routes/NotFound.tsx +89 -0
  96. package/src/templates/overlays/styling/styled-components/_vite/src/main.tsx +13 -0
  97. package/src/templates/overlays/styling/styled-components/manifest.json +5 -1
  98. package/src/templates/overlays/styling/tailwind/_nextjs/src/app/error.tsx +33 -0
  99. package/src/templates/overlays/styling/tailwind/_nextjs/src/app/loading.tsx +12 -0
  100. package/src/templates/overlays/styling/tailwind/_nextjs/src/app/not-found.tsx +26 -0
  101. package/src/templates/overlays/styling/tailwind/_nextjs/src/app/page.tsx +33 -0
  102. package/src/templates/overlays/styling/tailwind/manifest.json +5 -3
  103. package/src/templates/overlays/runtime/vite/src/styles/globals.css +0 -55
  104. package/src/templates/overlays/styling/css-modules/src/components/ui/Button.module.css +0 -87
  105. package/src/templates/overlays/styling/css-modules/src/styles/globals.css +0 -91
@@ -1,23 +1,43 @@
1
+ import styled, { keyframes } from 'styled-components';
2
+
1
3
  type LoadingSpinnerProps = {
2
4
  size?: 'sm' | 'md' | 'lg';
3
- className?: string;
4
5
  };
5
6
 
7
+ const spin = keyframes`
8
+ from {
9
+ transform: rotate(0deg);
10
+ }
11
+ to {
12
+ transform: rotate(360deg);
13
+ }
14
+ `;
15
+
6
16
  const sizes = {
7
- sm: 'h-4 w-4',
8
- md: 'h-8 w-8',
9
- lg: 'h-16 w-16',
17
+ sm: '1rem',
18
+ md: '2rem',
19
+ lg: '4rem',
10
20
  };
11
21
 
12
- export function LoadingSpinner({ size = 'md', className = '' }: LoadingSpinnerProps) {
22
+ const SpinnerContainer = styled.div`
23
+ display: flex;
24
+ align-items: center;
25
+ justify-content: center;
26
+ `;
27
+
28
+ const Spinner = styled.div<{ $size: 'sm' | 'md' | 'lg' }>`
29
+ width: ${(props) => sizes[props.$size]};
30
+ height: ${(props) => sizes[props.$size]};
31
+ border: 2px solid #d1d5db;
32
+ border-top-color: #4f46e5;
33
+ border-radius: 50%;
34
+ animation: ${spin} 1s linear infinite;
35
+ `;
36
+
37
+ export function LoadingSpinner({ size = 'md' }: LoadingSpinnerProps) {
13
38
  return (
14
- <div className="flex items-center justify-center">
15
- <div
16
- className={`animate-spin rounded-full border-2 border-gray-300 border-t-indigo-600 ${sizes[size]} ${className}`}
17
- role="status"
18
- aria-label="Loading"
19
- />
20
- </div>
39
+ <SpinnerContainer>
40
+ <Spinner $size={size} role="status" aria-label="Loading" />
41
+ </SpinnerContainer>
21
42
  );
22
43
  }
23
-
@@ -1,33 +1,90 @@
1
1
  import { Link } from 'react-router-dom';
2
+ import styled from 'styled-components';
3
+
4
+ const Container = styled.div`
5
+ display: flex;
6
+ min-height: 100vh;
7
+ flex-direction: column;
8
+ align-items: center;
9
+ justify-content: center;
10
+ `;
11
+
12
+ const Content = styled.div`
13
+ text-align: center;
14
+ `;
15
+
16
+ const Title = styled.h1`
17
+ font-size: 2.25rem;
18
+ font-weight: 700;
19
+ letter-spacing: -0.025em;
20
+
21
+ @media (min-width: 640px) {
22
+ font-size: 3.75rem;
23
+ }
24
+ `;
25
+
26
+ const Description = styled.p`
27
+ margin-top: 1.5rem;
28
+ font-size: 1.125rem;
29
+ line-height: 2rem;
30
+ color: #4b5563;
31
+ `;
32
+
33
+ const Actions = styled.div`
34
+ margin-top: 2.5rem;
35
+ display: flex;
36
+ align-items: center;
37
+ justify-content: center;
38
+ gap: 1.5rem;
39
+ `;
40
+
41
+ const PrimaryLink = styled(Link)`
42
+ padding: 0.625rem 0.875rem;
43
+ font-size: 0.875rem;
44
+ font-weight: 600;
45
+ color: white;
46
+ background-color: #4f46e5;
47
+ border-radius: 0.375rem;
48
+ box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
49
+ text-decoration: none;
50
+ transition: background-color 0.2s;
51
+
52
+ &:hover {
53
+ background-color: #6366f1;
54
+ }
55
+ `;
56
+
57
+ const SecondaryLink = styled.a`
58
+ font-size: 0.875rem;
59
+ font-weight: 600;
60
+ line-height: 1.5rem;
61
+ color: inherit;
62
+ text-decoration: none;
63
+
64
+ &:hover {
65
+ text-decoration: underline;
66
+ }
67
+ `;
2
68
 
3
69
  export function Landing() {
4
70
  return (
5
- <div className="flex min-h-screen flex-col items-center justify-center">
6
- <div className="text-center">
7
- <h1 className="text-4xl font-bold tracking-tight sm:text-6xl">
8
- Welcome to Your App
9
- </h1>
10
- <p className="mt-6 text-lg leading-8 text-gray-600">
71
+ <Container>
72
+ <Content>
73
+ <Title>Welcome to Your App</Title>
74
+ <Description>
11
75
  A production-ready React application scaffolded with create-react-forge.
12
- </p>
13
- <div className="mt-10 flex items-center justify-center gap-x-6">
14
- <Link
15
- to="/dashboard"
16
- className="rounded-md bg-indigo-600 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
17
- >
18
- Get started
19
- </Link>
20
- <a
76
+ </Description>
77
+ <Actions>
78
+ <PrimaryLink to="/dashboard">Get started</PrimaryLink>
79
+ <SecondaryLink
21
80
  href="https://github.com/alan2207/bulletproof-react"
22
- className="text-sm font-semibold leading-6"
23
81
  target="_blank"
24
82
  rel="noopener noreferrer"
25
83
  >
26
84
  Learn more <span aria-hidden="true">→</span>
27
- </a>
28
- </div>
29
- </div>
30
- </div>
85
+ </SecondaryLink>
86
+ </Actions>
87
+ </Content>
88
+ </Container>
31
89
  );
32
90
  }
33
-
@@ -1,26 +1,84 @@
1
1
  import { Link } from 'react-router-dom';
2
+ import styled from 'styled-components';
3
+
4
+ const Container = styled.div`
5
+ display: flex;
6
+ min-height: 100vh;
7
+ flex-direction: column;
8
+ align-items: center;
9
+ justify-content: center;
10
+ `;
11
+
12
+ const Content = styled.div`
13
+ text-align: center;
14
+ `;
15
+
16
+ const ErrorCode = styled.p`
17
+ font-size: 1rem;
18
+ font-weight: 600;
19
+ color: #4f46e5;
20
+ `;
21
+
22
+ const Title = styled.h1`
23
+ margin-top: 1rem;
24
+ font-size: 1.875rem;
25
+ font-weight: 700;
26
+ letter-spacing: -0.025em;
27
+
28
+ @media (min-width: 640px) {
29
+ font-size: 3rem;
30
+ }
31
+ `;
32
+
33
+ const Description = styled.p`
34
+ margin-top: 1.5rem;
35
+ font-size: 1rem;
36
+ line-height: 1.75rem;
37
+ color: #4b5563;
38
+ `;
39
+
40
+ const Actions = styled.div`
41
+ margin-top: 2.5rem;
42
+ display: flex;
43
+ align-items: center;
44
+ justify-content: center;
45
+ gap: 1.5rem;
46
+ `;
47
+
48
+ const HomeLink = styled(Link)`
49
+ padding: 0.625rem 0.875rem;
50
+ font-size: 0.875rem;
51
+ font-weight: 600;
52
+ color: white;
53
+ background-color: #4f46e5;
54
+ border-radius: 0.375rem;
55
+ box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
56
+ text-decoration: none;
57
+ transition: background-color 0.2s;
58
+
59
+ &:hover {
60
+ background-color: #6366f1;
61
+ }
62
+
63
+ &:focus-visible {
64
+ outline: 2px solid #4f46e5;
65
+ outline-offset: 2px;
66
+ }
67
+ `;
2
68
 
3
69
  export function NotFound() {
4
70
  return (
5
- <div className="flex min-h-screen flex-col items-center justify-center">
6
- <div className="text-center">
7
- <p className="text-base font-semibold text-indigo-600">404</p>
8
- <h1 className="mt-4 text-3xl font-bold tracking-tight sm:text-5xl">
9
- Page not found
10
- </h1>
11
- <p className="mt-6 text-base leading-7 text-gray-600">
71
+ <Container>
72
+ <Content>
73
+ <ErrorCode>404</ErrorCode>
74
+ <Title>Page not found</Title>
75
+ <Description>
12
76
  Sorry, we couldn't find the page you're looking for.
13
- </p>
14
- <div className="mt-10 flex items-center justify-center gap-x-6">
15
- <Link
16
- to="/"
17
- className="rounded-md bg-indigo-600 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
18
- >
19
- Go back home
20
- </Link>
21
- </div>
22
- </div>
23
- </div>
77
+ </Description>
78
+ <Actions>
79
+ <HomeLink to="/">Go back home</HomeLink>
80
+ </Actions>
81
+ </Content>
82
+ </Container>
24
83
  );
25
84
  }
26
-
@@ -1,5 +1,4 @@
1
1
  import { App } from '@/app/App';
2
- import '@/styles/globals.css';
3
2
  import React from 'react';
4
3
  import ReactDOM from 'react-dom/client';
5
4
 
@@ -8,4 +7,3 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
8
7
  <App />
9
8
  </React.StrictMode>
10
9
  );
11
-
@@ -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,34 @@
1
+ 'use client';
2
+
3
+ import { useEffect } from 'react';
4
+ import './error.css';
5
+
6
+ export default function Error({
7
+ error,
8
+ reset,
9
+ }: {
10
+ error: Error & { digest?: string };
11
+ reset: () => void;
12
+ }) {
13
+ useEffect(() => {
14
+ console.error(error);
15
+ }, [error]);
16
+
17
+ return (
18
+ <div className="error-container" role="alert">
19
+ <div className="error-content">
20
+ <h1 className="error-title">Something went wrong</h1>
21
+ <p className="error-message">
22
+ {error.message || 'An unexpected error occurred'}
23
+ </p>
24
+ <button onClick={reset} className="btn btn-primary">
25
+ Try again
26
+ </button>
27
+ </div>
28
+ </div>
29
+ );
30
+ }
31
+
32
+
33
+
34
+
@@ -0,0 +1,28 @@
1
+ .spinner-container {
2
+ display: flex;
3
+ min-height: 100vh;
4
+ align-items: center;
5
+ justify-content: center;
6
+ }
7
+
8
+ .spinner {
9
+ width: 2rem;
10
+ height: 2rem;
11
+ border-radius: 50%;
12
+ border: 2px solid var(--color-border);
13
+ border-top-color: var(--color-primary);
14
+ animation: spin 1s linear infinite;
15
+ }
16
+
17
+ @keyframes spin {
18
+ from {
19
+ transform: rotate(0deg);
20
+ }
21
+ to {
22
+ transform: rotate(360deg);
23
+ }
24
+ }
25
+
26
+
27
+
28
+
@@ -0,0 +1,13 @@
1
+ import './loading.css';
2
+
3
+ export default function Loading() {
4
+ return (
5
+ <div className="spinner-container">
6
+ <div className="spinner" role="status" aria-label="Loading" />
7
+ </div>
8
+ );
9
+ }
10
+
11
+
12
+
13
+
@@ -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 'next/link';
2
+ import './not-found.css';
3
+
4
+ export default 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 href="/" 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,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 '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
+