create-alistt69-kit 0.1.14 → 0.1.18

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-alistt69-kit",
3
- "version": "0.1.14",
3
+ "version": "0.1.18",
4
4
  "description": "Opinionated React + TypeScript + Webpack project generator by alistt69",
5
5
  "keywords": [
6
6
  "create",
@@ -131,4 +131,4 @@ export default [
131
131
  }],
132
132
  },
133
133
  },
134
- ];
134
+ ];
@@ -1,9 +1,12 @@
1
- import { RouterProvider } from 'react-router-dom';
1
+ import { ReactNode } from 'react';
2
2
  import Logo from '../../public/create-alistt69-kit-logo.svg';
3
- import { appRouter } from './providers/router/config/router';
4
3
  import styles from './styles.module.scss';
5
4
 
6
- function App() {
5
+ interface AppProps {
6
+ children: ReactNode;
7
+ }
8
+
9
+ function App({ children }: AppProps) {
7
10
  return (
8
11
  <div className={styles.app_wrapper}>
9
12
  <div className={styles.created_by_section}>
@@ -12,7 +15,7 @@ function App() {
12
15
  created by create-alistt69-kit
13
16
  </p>
14
17
  </div>
15
- <RouterProvider router={appRouter} />
18
+ {children}
16
19
  </div>
17
20
  );
18
21
  }
@@ -1,36 +1,39 @@
1
1
  import clsx from 'clsx';
2
2
  import { NavLink, Outlet } from 'react-router-dom';
3
+ import { AppErrorBoundary } from '@/app/providers';
3
4
  import styles from './styles.module.scss';
4
5
 
5
6
  export default function AppLayout() {
6
7
  return (
7
- <div className={styles.layout_wrapper}>
8
- <aside className={styles.sidebar}>
9
- <nav>
10
- <NavLink
11
- className={({ isActive }) => clsx({
12
- [styles.active]: isActive,
13
- })}
14
- to="/"
15
- >
16
- Main
17
- </NavLink>
18
- </nav>
19
- <nav>
20
- <NavLink
21
- className={({ isActive }) => clsx({
22
- [styles.active]: isActive,
23
- })}
24
- to="/error-route"
25
- >
26
- Error
27
- </NavLink>
28
- </nav>
29
- </aside>
8
+ <AppErrorBoundary>
9
+ <div className={styles.layout_wrapper}>
10
+ <aside className={styles.sidebar}>
11
+ <nav>
12
+ <NavLink
13
+ className={({ isActive }) => clsx({
14
+ [styles.active]: isActive,
15
+ })}
16
+ to="/"
17
+ >
18
+ Main
19
+ </NavLink>
20
+ </nav>
21
+ <nav>
22
+ <NavLink
23
+ className={({ isActive }) => clsx({
24
+ [styles.active]: isActive,
25
+ })}
26
+ to="/error-route"
27
+ >
28
+ Error
29
+ </NavLink>
30
+ </nav>
31
+ </aside>
30
32
 
31
- <main>
32
- <Outlet />
33
- </main>
34
- </div>
33
+ <main>
34
+ <Outlet />
35
+ </main>
36
+ </div>
37
+ </AppErrorBoundary>
35
38
  );
36
39
  }
@@ -0,0 +1,44 @@
1
+ import { Component, ErrorInfo, ReactNode } from 'react';
2
+ import ErrorScreen from '../../ui/error-screen';
3
+
4
+ type ErrorBoundaryProps = {
5
+ children: ReactNode;
6
+ };
7
+
8
+ type ErrorBoundaryState = {
9
+ hasError: boolean;
10
+ error: Error | null;
11
+ };
12
+
13
+ class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
14
+ constructor(props: ErrorBoundaryProps) {
15
+ super(props);
16
+ this.state = { hasError: false, error: null };
17
+ }
18
+
19
+ static getDerivedStateFromError(error: Error) {
20
+ return {
21
+ hasError: true,
22
+ error,
23
+ };
24
+ }
25
+
26
+ componentDidCatch(error: Error, errorInfo: ErrorInfo) {
27
+ console.error('ErrorBoundary caught:', error, errorInfo);
28
+ }
29
+
30
+ public render(): ReactNode {
31
+ if (this.state.hasError) {
32
+ return (
33
+ <ErrorScreen
34
+ errorMessage={this.state.error?.message}
35
+ onRetry={() => window.location.reload()}
36
+ />
37
+ );
38
+ }
39
+
40
+ return this.props.children;
41
+ }
42
+ }
43
+
44
+ export default ErrorBoundary;
@@ -0,0 +1,151 @@
1
+ type ErrorScreenProps = {
2
+ title?: string;
3
+ description?: string;
4
+ errorMessage?: string;
5
+ onRetry?: () => void;
6
+ };
7
+
8
+ function ErrorScreen({
9
+ title = 'Something went wrong',
10
+ description = 'An unexpected error occurred. Try again or reload the page.',
11
+ errorMessage,
12
+ onRetry,
13
+ }: ErrorScreenProps) {
14
+ return (
15
+ <main
16
+ style={{
17
+ minHeight: '100vh',
18
+ display: 'grid',
19
+ placeItems: 'center',
20
+ padding: '24px',
21
+ background:
22
+ 'radial-gradient(circle at top, rgba(255,255,255,0.06), transparent 40%), #0b0d12',
23
+ color: '#f5f7fa',
24
+ }}
25
+ >
26
+ <section
27
+ style={{
28
+ width: '100%',
29
+ maxWidth: '560px',
30
+ padding: '32px',
31
+ borderRadius: '24px',
32
+ border: '1px solid rgba(255,255,255,0.08)',
33
+ background: 'rgba(255,255,255,0.04)',
34
+ backdropFilter: 'blur(12px)',
35
+ boxShadow: '0 20px 80px rgba(0,0,0,0.35)',
36
+ }}
37
+ >
38
+ <div
39
+ style={{
40
+ width: '56px',
41
+ height: '56px',
42
+ borderRadius: '16px',
43
+ display: 'grid',
44
+ placeItems: 'center',
45
+ fontSize: '28px',
46
+ background: 'rgba(255,255,255,0.08)',
47
+ marginBottom: '20px',
48
+ }}
49
+ >
50
+ ⚠️
51
+ </div>
52
+
53
+ <h1
54
+ style={{
55
+ margin: 0,
56
+ fontSize: '32px',
57
+ lineHeight: 1.1,
58
+ fontWeight: 700,
59
+ }}
60
+ >
61
+ {title}
62
+ </h1>
63
+
64
+ <p
65
+ style={{
66
+ marginTop: '12px',
67
+ marginBottom: 0,
68
+ fontSize: '16px',
69
+ lineHeight: 1.6,
70
+ color: 'rgba(245,247,250,0.78)',
71
+ }}
72
+ >
73
+ {description}
74
+ </p>
75
+
76
+ {errorMessage ? (
77
+ <pre
78
+ style={{
79
+ marginTop: '20px',
80
+ padding: '16px',
81
+ overflowX: 'auto',
82
+ borderRadius: '16px',
83
+ background: 'rgba(0,0,0,0.28)',
84
+ border: '1px solid rgba(255,255,255,0.08)',
85
+ color: '#ffb4b4',
86
+ fontSize: '13px',
87
+ lineHeight: 1.5,
88
+ whiteSpace: 'pre-wrap',
89
+ wordBreak: 'break-word',
90
+ }}
91
+ >
92
+ {errorMessage}
93
+ </pre>
94
+ ) : null}
95
+
96
+ <div
97
+ style={{
98
+ display: 'flex',
99
+ gap: '12px',
100
+ flexWrap: 'wrap',
101
+ marginTop: '24px',
102
+ }}
103
+ >
104
+ {onRetry ? (
105
+ <button
106
+ type="button"
107
+ onClick={onRetry}
108
+ style={buttonPrimaryStyle}
109
+ >
110
+ Try again
111
+ </button>
112
+ ) : null}
113
+
114
+ <button
115
+ type="button"
116
+ onClick={() => window.location.reload()}
117
+ style={buttonSecondaryStyle}
118
+ >
119
+ Reload page
120
+ </button>
121
+ </div>
122
+ </section>
123
+ </main>
124
+ );
125
+ }
126
+
127
+ const buttonBaseStyle: React.CSSProperties = {
128
+ appearance: 'none',
129
+ border: 'none',
130
+ cursor: 'pointer',
131
+ borderRadius: '14px',
132
+ padding: '12px 16px',
133
+ fontSize: '14px',
134
+ fontWeight: 600,
135
+ transition: 'transform 0.15s ease, opacity 0.15s ease',
136
+ };
137
+
138
+ const buttonPrimaryStyle: React.CSSProperties = {
139
+ ...buttonBaseStyle,
140
+ background: '#ffffff',
141
+ color: '#0b0d12',
142
+ };
143
+
144
+ const buttonSecondaryStyle: React.CSSProperties = {
145
+ ...buttonBaseStyle,
146
+ background: 'rgba(255,255,255,0.08)',
147
+ color: '#f5f7fa',
148
+ border: '1px solid rgba(255,255,255,0.1)',
149
+ };
150
+
151
+ export default ErrorScreen;
@@ -0,0 +1,7 @@
1
+ import ErrorBoundary from './error-boundary/lib/provider'
2
+ import Router from './router/lib/provider'
3
+
4
+ export {
5
+ Router as AppRouter,
6
+ ErrorBoundary as AppErrorBoundary,
7
+ };
@@ -0,0 +1,10 @@
1
+ import { RouterProvider } from 'react-router-dom';
2
+ import { router } from '../router';
3
+
4
+ function Router() {
5
+ return (
6
+ <RouterProvider router={router} />
7
+ );
8
+ }
9
+
10
+ export default Router;
@@ -1,9 +1,9 @@
1
1
  import { createBrowserRouter, createRoutesFromElements, Route } from 'react-router-dom';
2
- import { Error } from '../../../../pages/error';
3
- import { Main } from '../../../../pages/main';
4
- import AppLayout from '../../../layouts/app';
2
+ import { Error } from '../../../../../pages/error';
3
+ import { Main } from '../../../../../pages/main';
4
+ import AppLayout from '../../../../layouts/app';
5
5
 
6
- export const appRouter = createBrowserRouter(
6
+ export const router = createBrowserRouter(
7
7
  createRoutesFromElements(
8
8
  <Route path="/" element={<AppLayout />}>
9
9
  <Route index element={<Main />} />
@@ -0,0 +1,19 @@
1
+ import { StrictMode } from 'react';
2
+ import { createRoot } from 'react-dom/client';
3
+ import App from '@/app/App';
4
+ import { AppRouter } from '@/app/providers';
5
+ import './styles/index.scss';
6
+
7
+ const container = document.getElementById('root');
8
+
9
+ if (!container) {
10
+ throw new Error('Root container not found');
11
+ }
12
+
13
+ createRoot(container).render(
14
+ <StrictMode>
15
+ <App>
16
+ <AppRouter />
17
+ </App>
18
+ </StrictMode>,
19
+ );
@@ -0,0 +1,44 @@
1
+ import { Component, ErrorInfo, ReactNode } from 'react';
2
+ import ErrorScreen from '../../ui/error-screen';
3
+
4
+ type ErrorBoundaryProps = {
5
+ children: ReactNode;
6
+ };
7
+
8
+ type ErrorBoundaryState = {
9
+ hasError: boolean;
10
+ error: Error | null;
11
+ };
12
+
13
+ class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
14
+ constructor(props: ErrorBoundaryProps) {
15
+ super(props);
16
+ this.state = { hasError: false, error: null };
17
+ }
18
+
19
+ static getDerivedStateFromError(error: Error) {
20
+ return {
21
+ hasError: true,
22
+ error,
23
+ };
24
+ }
25
+
26
+ componentDidCatch(error: Error, errorInfo: ErrorInfo) {
27
+ console.error('ErrorBoundary caught:', error, errorInfo);
28
+ }
29
+
30
+ public render(): ReactNode {
31
+ if (this.state.hasError) {
32
+ return (
33
+ <ErrorScreen
34
+ errorMessage={this.state.error?.message}
35
+ onRetry={() => window.location.reload()}
36
+ />
37
+ );
38
+ }
39
+
40
+ return this.props.children;
41
+ }
42
+ }
43
+
44
+ export default ErrorBoundary;
@@ -0,0 +1,151 @@
1
+ type ErrorScreenProps = {
2
+ title?: string;
3
+ description?: string;
4
+ errorMessage?: string;
5
+ onRetry?: () => void;
6
+ };
7
+
8
+ function ErrorScreen({
9
+ title = 'Something went wrong',
10
+ description = 'An unexpected error occurred. Try again or reload the page.',
11
+ errorMessage,
12
+ onRetry,
13
+ }: ErrorScreenProps) {
14
+ return (
15
+ <main
16
+ style={{
17
+ minHeight: '100vh',
18
+ display: 'grid',
19
+ placeItems: 'center',
20
+ padding: '24px',
21
+ background:
22
+ 'radial-gradient(circle at top, rgba(255,255,255,0.06), transparent 40%), #0b0d12',
23
+ color: '#f5f7fa',
24
+ }}
25
+ >
26
+ <section
27
+ style={{
28
+ width: '100%',
29
+ maxWidth: '560px',
30
+ padding: '32px',
31
+ borderRadius: '24px',
32
+ border: '1px solid rgba(255,255,255,0.08)',
33
+ background: 'rgba(255,255,255,0.04)',
34
+ backdropFilter: 'blur(12px)',
35
+ boxShadow: '0 20px 80px rgba(0,0,0,0.35)',
36
+ }}
37
+ >
38
+ <div
39
+ style={{
40
+ width: '56px',
41
+ height: '56px',
42
+ borderRadius: '16px',
43
+ display: 'grid',
44
+ placeItems: 'center',
45
+ fontSize: '28px',
46
+ background: 'rgba(255,255,255,0.08)',
47
+ marginBottom: '20px',
48
+ }}
49
+ >
50
+ ⚠️
51
+ </div>
52
+
53
+ <h1
54
+ style={{
55
+ margin: 0,
56
+ fontSize: '32px',
57
+ lineHeight: 1.1,
58
+ fontWeight: 700,
59
+ }}
60
+ >
61
+ {title}
62
+ </h1>
63
+
64
+ <p
65
+ style={{
66
+ marginTop: '12px',
67
+ marginBottom: 0,
68
+ fontSize: '16px',
69
+ lineHeight: 1.6,
70
+ color: 'rgba(245,247,250,0.78)',
71
+ }}
72
+ >
73
+ {description}
74
+ </p>
75
+
76
+ {errorMessage ? (
77
+ <pre
78
+ style={{
79
+ marginTop: '20px',
80
+ padding: '16px',
81
+ overflowX: 'auto',
82
+ borderRadius: '16px',
83
+ background: 'rgba(0,0,0,0.28)',
84
+ border: '1px solid rgba(255,255,255,0.08)',
85
+ color: '#ffb4b4',
86
+ fontSize: '13px',
87
+ lineHeight: 1.5,
88
+ whiteSpace: 'pre-wrap',
89
+ wordBreak: 'break-word',
90
+ }}
91
+ >
92
+ {errorMessage}
93
+ </pre>
94
+ ) : null}
95
+
96
+ <div
97
+ style={{
98
+ display: 'flex',
99
+ gap: '12px',
100
+ flexWrap: 'wrap',
101
+ marginTop: '24px',
102
+ }}
103
+ >
104
+ {onRetry ? (
105
+ <button
106
+ type="button"
107
+ onClick={onRetry}
108
+ style={buttonPrimaryStyle}
109
+ >
110
+ Try again
111
+ </button>
112
+ ) : null}
113
+
114
+ <button
115
+ type="button"
116
+ onClick={() => window.location.reload()}
117
+ style={buttonSecondaryStyle}
118
+ >
119
+ Reload page
120
+ </button>
121
+ </div>
122
+ </section>
123
+ </main>
124
+ );
125
+ }
126
+
127
+ const buttonBaseStyle: React.CSSProperties = {
128
+ appearance: 'none',
129
+ border: 'none',
130
+ cursor: 'pointer',
131
+ borderRadius: '14px',
132
+ padding: '12px 16px',
133
+ fontSize: '14px',
134
+ fontWeight: 600,
135
+ transition: 'transform 0.15s ease, opacity 0.15s ease',
136
+ };
137
+
138
+ const buttonPrimaryStyle: React.CSSProperties = {
139
+ ...buttonBaseStyle,
140
+ background: '#ffffff',
141
+ color: '#0b0d12',
142
+ };
143
+
144
+ const buttonSecondaryStyle: React.CSSProperties = {
145
+ ...buttonBaseStyle,
146
+ background: 'rgba(255,255,255,0.08)',
147
+ color: '#f5f7fa',
148
+ border: '1px solid rgba(255,255,255,0.1)',
149
+ };
150
+
151
+ export default ErrorScreen;
@@ -0,0 +1,5 @@
1
+ import ErrorBoundary from './error-boundary/lib/provider'
2
+
3
+ export {
4
+ ErrorBoundary as AppErrorBoundary,
5
+ };
@@ -1,6 +1,7 @@
1
1
  import { StrictMode } from 'react';
2
2
  import { createRoot } from 'react-dom/client';
3
- import App from './app/App';
3
+ import App from '@/app/App';
4
+ import { AppErrorBoundary } from '@/app/providers';
4
5
  import './styles/index.scss';
5
6
 
6
7
  const container = document.getElementById('root');
@@ -11,6 +12,8 @@ if (!container) {
11
12
 
12
13
  createRoot(container).render(
13
14
  <StrictMode>
14
- <App />
15
+ <AppErrorBoundary>
16
+ <App />
17
+ </AppErrorBoundary>
15
18
  </StrictMode>,
16
19
  );