create-wordpress-theme-ts 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.
- package/LICENSE +21 -0
- package/README.md +249 -0
- package/bin/index.js +179 -0
- package/package.json +43 -0
- package/template/.eslintignore +2 -0
- package/template/.eslintrc.json +34 -0
- package/template/.prettierrc +7 -0
- package/template/index.html +21 -0
- package/template/package-lock.json +6323 -0
- package/template/package.json +48 -0
- package/template/php/functions.php +34 -0
- package/template/php/index.php +17 -0
- package/template/public/images/README.md +8 -0
- package/template/public/style.css +48 -0
- package/template/src/App.tsx +19 -0
- package/template/src/components/Layout.tsx +88 -0
- package/template/src/index.tsx +15 -0
- package/template/src/pages/About.tsx +66 -0
- package/template/src/pages/Home.tsx +133 -0
- package/template/src/pages/NotFound.tsx +57 -0
- package/template/src/styles/global.css +90 -0
- package/template/src/vite-env.d.ts +7 -0
- package/template/tsconfig.json +20 -0
- package/template/vite.config.ts +109 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "my-wp-react-site",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "vite",
|
|
7
|
+
"build": "vite build",
|
|
8
|
+
"build:dev": "vite build --mode development",
|
|
9
|
+
"build:prod": "vite build --mode production",
|
|
10
|
+
"preview": "vite preview",
|
|
11
|
+
"format": "prettier --write \"src/**/*.{ts,tsx,js,jsx,css}\" \"*.{json,ts}\""
|
|
12
|
+
},
|
|
13
|
+
"keywords": [],
|
|
14
|
+
"author": "",
|
|
15
|
+
"license": "ISC",
|
|
16
|
+
"description": "A custom WordPress theme built with React and Vite",
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@fortawesome/fontawesome-svg-core": "^6.6.0",
|
|
19
|
+
"@fortawesome/free-brands-svg-icons": "^6.6.0",
|
|
20
|
+
"@fortawesome/free-regular-svg-icons": "^6.6.0",
|
|
21
|
+
"@fortawesome/free-solid-svg-icons": "^6.6.0",
|
|
22
|
+
"@fortawesome/react-fontawesome": "^0.2.2",
|
|
23
|
+
"react": "^18.3.1",
|
|
24
|
+
"react-dom": "^18.3.1",
|
|
25
|
+
"react-router-dom": "^6.26.2",
|
|
26
|
+
"styled-components": "^6.1.13"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/node": "^25.0.3",
|
|
30
|
+
"@types/react": "^18.3.8",
|
|
31
|
+
"@types/react-dom": "^18.3.0",
|
|
32
|
+
"@types/styled-components": "^5.1.34",
|
|
33
|
+
"@typescript-eslint/eslint-plugin": "^8.6.0",
|
|
34
|
+
"@typescript-eslint/parser": "^8.6.0",
|
|
35
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
36
|
+
"eslint": "^8.57.1",
|
|
37
|
+
"eslint-config-prettier": "^9.1.0",
|
|
38
|
+
"eslint-plugin-prettier": "^5.2.1",
|
|
39
|
+
"eslint-plugin-react": "^7.36.1",
|
|
40
|
+
"eslint-plugin-react-hooks": "^4.6.2",
|
|
41
|
+
"prettier": "^3.3.3",
|
|
42
|
+
"typescript": "^5.6.2",
|
|
43
|
+
"vite": "^6.0.7",
|
|
44
|
+
"vite-plugin-eslint": "^1.8.1",
|
|
45
|
+
"vite-plugin-static-copy": "^2.2.0",
|
|
46
|
+
"vite-plugin-zip-pack": "^1.2.4"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
/**
|
|
3
|
+
* Theme functions and definitions
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Enqueue styles and scripts
|
|
7
|
+
function theme_enqueue_scripts() {
|
|
8
|
+
// Enqueue the bundled CSS from Vite build
|
|
9
|
+
wp_enqueue_style('react-app', get_template_directory_uri() . '/bundle.css', array(), '1.0.0');
|
|
10
|
+
|
|
11
|
+
// Enqueue the React bundle
|
|
12
|
+
wp_enqueue_script('react-app', get_template_directory_uri() . '/bundle.js', array(), '1.0.0', true);
|
|
13
|
+
}
|
|
14
|
+
add_action('wp_enqueue_scripts', 'theme_enqueue_scripts');
|
|
15
|
+
|
|
16
|
+
// Add theme support
|
|
17
|
+
function theme_setup() {
|
|
18
|
+
// Add support for title tag
|
|
19
|
+
add_theme_support('title-tag');
|
|
20
|
+
|
|
21
|
+
// Add support for post thumbnails
|
|
22
|
+
add_theme_support('post-thumbnails');
|
|
23
|
+
|
|
24
|
+
// Add support for HTML5
|
|
25
|
+
add_theme_support('html5', array(
|
|
26
|
+
'search-form',
|
|
27
|
+
'comment-form',
|
|
28
|
+
'comment-list',
|
|
29
|
+
'gallery',
|
|
30
|
+
'caption',
|
|
31
|
+
));
|
|
32
|
+
}
|
|
33
|
+
add_action('after_setup_theme', 'theme_setup');
|
|
34
|
+
?>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html <?php language_attributes(); ?>>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="<?php bloginfo('charset'); ?>">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<?php wp_head(); ?>
|
|
7
|
+
</head>
|
|
8
|
+
<body <?php body_class(); ?>>
|
|
9
|
+
<?php wp_body_open(); ?>
|
|
10
|
+
|
|
11
|
+
<main>
|
|
12
|
+
<div id="root"></div>
|
|
13
|
+
</main>
|
|
14
|
+
|
|
15
|
+
<?php wp_footer(); ?>
|
|
16
|
+
</body>
|
|
17
|
+
</html>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Theme Name: My WordPress Theme
|
|
3
|
+
Theme URI:
|
|
4
|
+
Author:
|
|
5
|
+
Author URI:
|
|
6
|
+
Description: A custom WordPress theme built with React and Vite
|
|
7
|
+
Version: 1.0.0
|
|
8
|
+
License: MIT
|
|
9
|
+
Text Domain: my-wp-theme
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/* Base Reset */
|
|
13
|
+
*, *::before, *::after {
|
|
14
|
+
box-sizing: border-box;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
* {
|
|
18
|
+
margin: 0;
|
|
19
|
+
padding: 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
html, body {
|
|
23
|
+
height: 100%;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
body {
|
|
27
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
|
28
|
+
line-height: 1.5;
|
|
29
|
+
-webkit-font-smoothing: antialiased;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
img, picture, video, canvas, svg {
|
|
33
|
+
display: block;
|
|
34
|
+
max-width: 100%;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
input, button, textarea, select {
|
|
38
|
+
font: inherit;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
p, h1, h2, h3, h4, h5, h6 {
|
|
42
|
+
overflow-wrap: break-word;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
#root {
|
|
46
|
+
isolation: isolate;
|
|
47
|
+
min-height: 100vh;
|
|
48
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Routes, Route } from 'react-router-dom';
|
|
2
|
+
import Layout from './components/Layout';
|
|
3
|
+
import Home from './pages/Home';
|
|
4
|
+
import About from './pages/About';
|
|
5
|
+
import NotFound from './pages/NotFound';
|
|
6
|
+
|
|
7
|
+
function App() {
|
|
8
|
+
return (
|
|
9
|
+
<Routes>
|
|
10
|
+
<Route path="/" element={<Layout />}>
|
|
11
|
+
<Route index element={<Home />} />
|
|
12
|
+
<Route path="about" element={<About />} />
|
|
13
|
+
<Route path="*" element={<NotFound />} />
|
|
14
|
+
</Route>
|
|
15
|
+
</Routes>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default App;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Outlet, Link } from 'react-router-dom';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
|
|
4
|
+
const LayoutContainer = styled.div`
|
|
5
|
+
min-height: 100vh;
|
|
6
|
+
display: flex;
|
|
7
|
+
flex-direction: column;
|
|
8
|
+
`;
|
|
9
|
+
|
|
10
|
+
const Header = styled.header`
|
|
11
|
+
background: #1a1a2e;
|
|
12
|
+
color: white;
|
|
13
|
+
padding: 1rem 2rem;
|
|
14
|
+
`;
|
|
15
|
+
|
|
16
|
+
const Nav = styled.nav`
|
|
17
|
+
display: flex;
|
|
18
|
+
gap: 2rem;
|
|
19
|
+
align-items: center;
|
|
20
|
+
max-width: 1200px;
|
|
21
|
+
margin: 0 auto;
|
|
22
|
+
width: 100%;
|
|
23
|
+
`;
|
|
24
|
+
|
|
25
|
+
const Logo = styled(Link)`
|
|
26
|
+
font-size: 1.5rem;
|
|
27
|
+
font-weight: bold;
|
|
28
|
+
color: white;
|
|
29
|
+
text-decoration: none;
|
|
30
|
+
|
|
31
|
+
&:hover {
|
|
32
|
+
color: #4a9eff;
|
|
33
|
+
}
|
|
34
|
+
`;
|
|
35
|
+
|
|
36
|
+
const NavLinks = styled.div`
|
|
37
|
+
display: flex;
|
|
38
|
+
gap: 1.5rem;
|
|
39
|
+
margin-left: auto;
|
|
40
|
+
`;
|
|
41
|
+
|
|
42
|
+
const NavLink = styled(Link)`
|
|
43
|
+
color: white;
|
|
44
|
+
text-decoration: none;
|
|
45
|
+
font-weight: 500;
|
|
46
|
+
transition: color 0.2s ease;
|
|
47
|
+
|
|
48
|
+
&:hover {
|
|
49
|
+
color: #4a9eff;
|
|
50
|
+
}
|
|
51
|
+
`;
|
|
52
|
+
|
|
53
|
+
const Main = styled.main`
|
|
54
|
+
flex: 1;
|
|
55
|
+
`;
|
|
56
|
+
|
|
57
|
+
const Footer = styled.footer`
|
|
58
|
+
background: #1a1a2e;
|
|
59
|
+
color: white;
|
|
60
|
+
padding: 1.5rem 2rem;
|
|
61
|
+
text-align: center;
|
|
62
|
+
`;
|
|
63
|
+
|
|
64
|
+
function Layout() {
|
|
65
|
+
return (
|
|
66
|
+
<LayoutContainer>
|
|
67
|
+
<Header>
|
|
68
|
+
<Nav>
|
|
69
|
+
<Logo to="/">My Site</Logo>
|
|
70
|
+
<NavLinks>
|
|
71
|
+
<NavLink to="/">Home</NavLink>
|
|
72
|
+
<NavLink to="/about">About</NavLink>
|
|
73
|
+
</NavLinks>
|
|
74
|
+
</Nav>
|
|
75
|
+
</Header>
|
|
76
|
+
|
|
77
|
+
<Main>
|
|
78
|
+
<Outlet />
|
|
79
|
+
</Main>
|
|
80
|
+
|
|
81
|
+
<Footer>
|
|
82
|
+
<p>© {new Date().getFullYear()} My Site. All rights reserved.</p>
|
|
83
|
+
</Footer>
|
|
84
|
+
</LayoutContainer>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export default Layout;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import ReactDOM from 'react-dom/client';
|
|
3
|
+
import { BrowserRouter } from 'react-router-dom';
|
|
4
|
+
import App from './App';
|
|
5
|
+
import './styles/global.css';
|
|
6
|
+
|
|
7
|
+
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
|
|
8
|
+
|
|
9
|
+
root.render(
|
|
10
|
+
<React.StrictMode>
|
|
11
|
+
<BrowserRouter>
|
|
12
|
+
<App />
|
|
13
|
+
</BrowserRouter>
|
|
14
|
+
</React.StrictMode>
|
|
15
|
+
);
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import styled from 'styled-components';
|
|
2
|
+
|
|
3
|
+
const Container = styled.div`
|
|
4
|
+
max-width: 800px;
|
|
5
|
+
margin: 0 auto;
|
|
6
|
+
padding: 4rem 2rem;
|
|
7
|
+
`;
|
|
8
|
+
|
|
9
|
+
const Title = styled.h1`
|
|
10
|
+
font-size: 2.5rem;
|
|
11
|
+
color: #1a1a2e;
|
|
12
|
+
margin-bottom: 1.5rem;
|
|
13
|
+
`;
|
|
14
|
+
|
|
15
|
+
const Content = styled.div`
|
|
16
|
+
color: #444;
|
|
17
|
+
line-height: 1.8;
|
|
18
|
+
|
|
19
|
+
p {
|
|
20
|
+
margin-bottom: 1.5rem;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
h2 {
|
|
24
|
+
font-size: 1.5rem;
|
|
25
|
+
color: #1a1a2e;
|
|
26
|
+
margin: 2rem 0 1rem;
|
|
27
|
+
}
|
|
28
|
+
`;
|
|
29
|
+
|
|
30
|
+
function About() {
|
|
31
|
+
return (
|
|
32
|
+
<Container>
|
|
33
|
+
<Title>About</Title>
|
|
34
|
+
<Content>
|
|
35
|
+
<p>
|
|
36
|
+
Welcome to our site! This is a custom WordPress theme built with modern
|
|
37
|
+
web technologies including React, TypeScript, and Vite.
|
|
38
|
+
</p>
|
|
39
|
+
|
|
40
|
+
<h2>Our Technology Stack</h2>
|
|
41
|
+
<p>
|
|
42
|
+
We use React 18 for building interactive user interfaces, TypeScript for
|
|
43
|
+
type safety and better developer experience, and Vite for lightning-fast
|
|
44
|
+
builds and hot module replacement during development.
|
|
45
|
+
</p>
|
|
46
|
+
|
|
47
|
+
<h2>WordPress Integration</h2>
|
|
48
|
+
<p>
|
|
49
|
+
This theme seamlessly integrates with WordPress, allowing you to leverage
|
|
50
|
+
the power of the world's most popular CMS while building with modern
|
|
51
|
+
frontend tools. The production build creates a standard WordPress theme
|
|
52
|
+
zip file that can be uploaded directly to your WordPress installation.
|
|
53
|
+
</p>
|
|
54
|
+
|
|
55
|
+
<h2>Get Started</h2>
|
|
56
|
+
<p>
|
|
57
|
+
Edit this page by modifying <code>src/pages/About.tsx</code>. Your changes
|
|
58
|
+
will be reflected instantly in development mode thanks to Vite's hot
|
|
59
|
+
module replacement.
|
|
60
|
+
</p>
|
|
61
|
+
</Content>
|
|
62
|
+
</Container>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export default About;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import styled from 'styled-components';
|
|
2
|
+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
3
|
+
import { faRocket, faCode, faGlobe } from '@fortawesome/free-solid-svg-icons';
|
|
4
|
+
|
|
5
|
+
const Container = styled.div`
|
|
6
|
+
max-width: 1200px;
|
|
7
|
+
margin: 0 auto;
|
|
8
|
+
padding: 4rem 2rem;
|
|
9
|
+
`;
|
|
10
|
+
|
|
11
|
+
const Hero = styled.section`
|
|
12
|
+
text-align: center;
|
|
13
|
+
padding: 4rem 0;
|
|
14
|
+
`;
|
|
15
|
+
|
|
16
|
+
const Title = styled.h1`
|
|
17
|
+
font-size: 3rem;
|
|
18
|
+
color: #1a1a2e;
|
|
19
|
+
margin-bottom: 1rem;
|
|
20
|
+
|
|
21
|
+
@media (max-width: 768px) {
|
|
22
|
+
font-size: 2rem;
|
|
23
|
+
}
|
|
24
|
+
`;
|
|
25
|
+
|
|
26
|
+
const Subtitle = styled.p`
|
|
27
|
+
font-size: 1.25rem;
|
|
28
|
+
color: #666;
|
|
29
|
+
max-width: 600px;
|
|
30
|
+
margin: 0 auto 2rem;
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
const FeatureGrid = styled.div`
|
|
34
|
+
display: grid;
|
|
35
|
+
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
|
36
|
+
gap: 2rem;
|
|
37
|
+
margin-top: 4rem;
|
|
38
|
+
`;
|
|
39
|
+
|
|
40
|
+
const FeatureCard = styled.div`
|
|
41
|
+
background: white;
|
|
42
|
+
border-radius: 12px;
|
|
43
|
+
padding: 2rem;
|
|
44
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
45
|
+
text-align: center;
|
|
46
|
+
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
47
|
+
|
|
48
|
+
&:hover {
|
|
49
|
+
transform: translateY(-4px);
|
|
50
|
+
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
|
|
51
|
+
}
|
|
52
|
+
`;
|
|
53
|
+
|
|
54
|
+
const IconWrapper = styled.div`
|
|
55
|
+
font-size: 2.5rem;
|
|
56
|
+
color: #4a9eff;
|
|
57
|
+
margin-bottom: 1rem;
|
|
58
|
+
`;
|
|
59
|
+
|
|
60
|
+
const FeatureTitle = styled.h3`
|
|
61
|
+
font-size: 1.25rem;
|
|
62
|
+
color: #1a1a2e;
|
|
63
|
+
margin-bottom: 0.75rem;
|
|
64
|
+
`;
|
|
65
|
+
|
|
66
|
+
const FeatureDescription = styled.p`
|
|
67
|
+
color: #666;
|
|
68
|
+
line-height: 1.6;
|
|
69
|
+
`;
|
|
70
|
+
|
|
71
|
+
const CTAButton = styled.a`
|
|
72
|
+
display: inline-block;
|
|
73
|
+
background: #4a9eff;
|
|
74
|
+
color: white;
|
|
75
|
+
padding: 1rem 2rem;
|
|
76
|
+
border-radius: 8px;
|
|
77
|
+
text-decoration: none;
|
|
78
|
+
font-weight: 600;
|
|
79
|
+
transition: background 0.2s ease;
|
|
80
|
+
|
|
81
|
+
&:hover {
|
|
82
|
+
background: #3a8eef;
|
|
83
|
+
}
|
|
84
|
+
`;
|
|
85
|
+
|
|
86
|
+
function Home() {
|
|
87
|
+
return (
|
|
88
|
+
<Container>
|
|
89
|
+
<Hero>
|
|
90
|
+
<Title>Welcome to Your New Site</Title>
|
|
91
|
+
<Subtitle>
|
|
92
|
+
A modern WordPress theme powered by React, TypeScript, and Vite.
|
|
93
|
+
Fast, flexible, and ready for customization.
|
|
94
|
+
</Subtitle>
|
|
95
|
+
<CTAButton href="#features">Explore Features</CTAButton>
|
|
96
|
+
</Hero>
|
|
97
|
+
|
|
98
|
+
<FeatureGrid id="features">
|
|
99
|
+
<FeatureCard>
|
|
100
|
+
<IconWrapper>
|
|
101
|
+
<FontAwesomeIcon icon={faRocket} />
|
|
102
|
+
</IconWrapper>
|
|
103
|
+
<FeatureTitle>Lightning Fast</FeatureTitle>
|
|
104
|
+
<FeatureDescription>
|
|
105
|
+
Built with Vite for instant hot module replacement and optimized production builds.
|
|
106
|
+
</FeatureDescription>
|
|
107
|
+
</FeatureCard>
|
|
108
|
+
|
|
109
|
+
<FeatureCard>
|
|
110
|
+
<IconWrapper>
|
|
111
|
+
<FontAwesomeIcon icon={faCode} />
|
|
112
|
+
</IconWrapper>
|
|
113
|
+
<FeatureTitle>Modern Stack</FeatureTitle>
|
|
114
|
+
<FeatureDescription>
|
|
115
|
+
React 18, TypeScript, and styled-components for a great developer experience.
|
|
116
|
+
</FeatureDescription>
|
|
117
|
+
</FeatureCard>
|
|
118
|
+
|
|
119
|
+
<FeatureCard>
|
|
120
|
+
<IconWrapper>
|
|
121
|
+
<FontAwesomeIcon icon={faGlobe} />
|
|
122
|
+
</IconWrapper>
|
|
123
|
+
<FeatureTitle>WordPress Ready</FeatureTitle>
|
|
124
|
+
<FeatureDescription>
|
|
125
|
+
Builds directly to a WordPress theme zip file ready for deployment.
|
|
126
|
+
</FeatureDescription>
|
|
127
|
+
</FeatureCard>
|
|
128
|
+
</FeatureGrid>
|
|
129
|
+
</Container>
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export default Home;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import styled from 'styled-components';
|
|
2
|
+
import { Link } from 'react-router-dom';
|
|
3
|
+
|
|
4
|
+
const Container = styled.div`
|
|
5
|
+
max-width: 600px;
|
|
6
|
+
margin: 0 auto;
|
|
7
|
+
padding: 8rem 2rem;
|
|
8
|
+
text-align: center;
|
|
9
|
+
`;
|
|
10
|
+
|
|
11
|
+
const ErrorCode = styled.h1`
|
|
12
|
+
font-size: 8rem;
|
|
13
|
+
color: #1a1a2e;
|
|
14
|
+
margin-bottom: 0;
|
|
15
|
+
line-height: 1;
|
|
16
|
+
`;
|
|
17
|
+
|
|
18
|
+
const Title = styled.h2`
|
|
19
|
+
font-size: 1.5rem;
|
|
20
|
+
color: #666;
|
|
21
|
+
margin-bottom: 1.5rem;
|
|
22
|
+
`;
|
|
23
|
+
|
|
24
|
+
const Description = styled.p`
|
|
25
|
+
color: #888;
|
|
26
|
+
margin-bottom: 2rem;
|
|
27
|
+
`;
|
|
28
|
+
|
|
29
|
+
const HomeLink = styled(Link)`
|
|
30
|
+
display: inline-block;
|
|
31
|
+
background: #4a9eff;
|
|
32
|
+
color: white;
|
|
33
|
+
padding: 0.75rem 1.5rem;
|
|
34
|
+
border-radius: 8px;
|
|
35
|
+
text-decoration: none;
|
|
36
|
+
font-weight: 600;
|
|
37
|
+
transition: background 0.2s ease;
|
|
38
|
+
|
|
39
|
+
&:hover {
|
|
40
|
+
background: #3a8eef;
|
|
41
|
+
}
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
function NotFound() {
|
|
45
|
+
return (
|
|
46
|
+
<Container>
|
|
47
|
+
<ErrorCode>404</ErrorCode>
|
|
48
|
+
<Title>Page Not Found</Title>
|
|
49
|
+
<Description>
|
|
50
|
+
Sorry, we couldn't find the page you're looking for.
|
|
51
|
+
</Description>
|
|
52
|
+
<HomeLink to="/">Go Home</HomeLink>
|
|
53
|
+
</Container>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export default NotFound;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/* Global Styles */
|
|
2
|
+
|
|
3
|
+
*,
|
|
4
|
+
*::before,
|
|
5
|
+
*::after {
|
|
6
|
+
box-sizing: border-box;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
* {
|
|
10
|
+
margin: 0;
|
|
11
|
+
padding: 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
html {
|
|
15
|
+
font-size: 16px;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
html,
|
|
19
|
+
body {
|
|
20
|
+
height: 100%;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
body {
|
|
24
|
+
font-family:
|
|
25
|
+
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans',
|
|
26
|
+
'Helvetica Neue', sans-serif;
|
|
27
|
+
line-height: 1.5;
|
|
28
|
+
-webkit-font-smoothing: antialiased;
|
|
29
|
+
-moz-osx-font-smoothing: grayscale;
|
|
30
|
+
background-color: #f5f5f5;
|
|
31
|
+
color: #333;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
img,
|
|
35
|
+
picture,
|
|
36
|
+
video,
|
|
37
|
+
canvas,
|
|
38
|
+
svg {
|
|
39
|
+
display: block;
|
|
40
|
+
max-width: 100%;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
input,
|
|
44
|
+
button,
|
|
45
|
+
textarea,
|
|
46
|
+
select {
|
|
47
|
+
font: inherit;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
p,
|
|
51
|
+
h1,
|
|
52
|
+
h2,
|
|
53
|
+
h3,
|
|
54
|
+
h4,
|
|
55
|
+
h5,
|
|
56
|
+
h6 {
|
|
57
|
+
overflow-wrap: break-word;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
a {
|
|
61
|
+
color: inherit;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
#root {
|
|
65
|
+
isolation: isolate;
|
|
66
|
+
min-height: 100vh;
|
|
67
|
+
display: flex;
|
|
68
|
+
flex-direction: column;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* Utility Classes */
|
|
72
|
+
.visually-hidden {
|
|
73
|
+
position: absolute;
|
|
74
|
+
width: 1px;
|
|
75
|
+
height: 1px;
|
|
76
|
+
padding: 0;
|
|
77
|
+
margin: -1px;
|
|
78
|
+
overflow: hidden;
|
|
79
|
+
clip: rect(0, 0, 0, 0);
|
|
80
|
+
white-space: nowrap;
|
|
81
|
+
border: 0;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
code {
|
|
85
|
+
font-family: 'Fira Code', 'Consolas', 'Monaco', monospace;
|
|
86
|
+
background-color: #e9e9e9;
|
|
87
|
+
padding: 0.2em 0.4em;
|
|
88
|
+
border-radius: 4px;
|
|
89
|
+
font-size: 0.9em;
|
|
90
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
2
|
+
|
|
3
|
+
// Type declaration for vite-plugin-eslint (no @types package available)
|
|
4
|
+
declare module 'vite-plugin-eslint' {
|
|
5
|
+
import { Plugin } from 'vite';
|
|
6
|
+
export default function eslint(options?: Record<string, unknown>): Plugin;
|
|
7
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"moduleResolution": "bundler",
|
|
4
|
+
"jsx": "react-jsx",
|
|
5
|
+
"target": "ES2020",
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
|
8
|
+
"types": ["vite/client", "node"],
|
|
9
|
+
"allowJs": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"allowSyntheticDefaultImports": true,
|
|
13
|
+
"strict": true,
|
|
14
|
+
"forceConsistentCasingInFileNames": true,
|
|
15
|
+
"noFallthroughCasesInSwitch": true,
|
|
16
|
+
"isolatedModules": true,
|
|
17
|
+
"noEmit": true
|
|
18
|
+
},
|
|
19
|
+
"include": ["src", "vite.config.ts"]
|
|
20
|
+
}
|