Skip to content

Commit 4e8c4f1

Browse files
committed
save point
1 parent d269d2d commit 4e8c4f1

14 files changed

Lines changed: 637 additions & 173 deletions

package-lock.json

Lines changed: 396 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
"@carbon/react": "^1.100.0",
1818
"gh-pages": "^6.3.0",
1919
"react": "^19.1.0",
20-
"react-dom": "^19.1.0"
20+
"react-dom": "^19.1.0",
21+
"react-router-dom": "^7.0.1"
2122
},
2223
"devDependencies": {
2324
"@eslint/js": "^9.30.1",

src/App.jsx

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,44 @@
1-
import { useState } from 'react'
2-
import { Theme } from '@carbon/react'
1+
import { Content, Theme } from '@carbon/react'
2+
import {
3+
Navigate,
4+
Outlet,
5+
RouterProvider,
6+
createHashRouter,
7+
} from 'react-router-dom'
38
import AppHeader from './components/AppHeader'
9+
import AppContent from './components/AppContent'
10+
import Home from './content/Home'
411
import Projects from './content/Projects'
512
import Contact from './content/Contact'
13+
import { useState } from 'react'
614

7-
function App() {
8-
const [activeSection, setActiveSection] = useState('about')
15+
const AppLayout = () => {
16+
const defaultDarkMode = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
17+
const [darkMode, setDarkMode] = useState(defaultDarkMode);
918

10-
const renderContent = () => {
11-
switch (activeSection) {
12-
case 'about':
13-
return <h1>About Me</h1>
14-
case 'projects':
15-
return <Projects />
16-
case 'contact':
17-
return <Contact />
18-
default:
19-
return <h1>About Me</h1>
20-
}
21-
}
19+
return (
20+
<Theme theme={darkMode ? 'g100' : 'g10'}>
21+
<AppHeader darkMode={darkMode} setDarkMode={setDarkMode} />
22+
<AppContent><Outlet /></AppContent>
23+
</Theme>
24+
);
25+
};
2226

23-
return (
24-
<>
25-
<Theme theme="g100">
26-
<AppHeader
27-
activeSection={activeSection}
28-
onSectionChange={setActiveSection}
29-
/>
30-
<div className="app-content">
31-
{renderContent()}
32-
</div>
33-
</Theme>
34-
</>
35-
)
27+
const router = createHashRouter([
28+
{
29+
path: '/',
30+
element: <AppLayout />,
31+
children: [
32+
{ index: true, element: <Home /> },
33+
{ path: 'projects', element: <Projects /> },
34+
{ path: 'contact', element: <Contact /> },
35+
{ path: '*', element: <Navigate to="/" replace /> },
36+
],
37+
},
38+
])
39+
40+
function App() {
41+
return <RouterProvider router={router} />
3642
}
3743

3844
export default App

src/assets/projects.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,10 @@
88
"name" : "hyperpage",
99
"description" : "Fast and efficient solution for storing web content.",
1010
"documentation" : "https://maxtek6.github.io/docs/hyperpage"
11+
},
12+
{
13+
"name" : "sigfn",
14+
"description" : "C++ library for handling signals.",
15+
"documentation" : "https://maxtek6.github.io/docs/sigfn"
1116
}
1217
]

src/components/AppContent.jsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Content } from '@carbon/react';
2+
3+
function AppContent({ children, ...props }) {
4+
return (
5+
<Content
6+
style={{
7+
display: 'flex',
8+
justifyContent: 'center',
9+
alignItems: 'center',
10+
minHeight: 'calc(100vh - 3rem)',
11+
}}
12+
{...props}>
13+
{children}
14+
</Content>
15+
)
16+
}
17+
18+
export default AppContent;

src/components/AppHeader.jsx

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,43 +2,65 @@
22
import {
33
Header,
44
HeaderContainer,
5+
HeaderGlobalBar,
6+
HeaderGlobalAction,
57
HeaderName,
68
HeaderNavigation,
79
HeaderMenuItem,
810
SkipToContent,
911
} from '@carbon/react'
12+
import { Moon, Sun } from '@carbon/icons-react';
13+
import { useLocation, useNavigate } from 'react-router-dom'
1014

11-
const AppHeader = ({ activeSection, onSectionChange }) => (
12-
<HeaderContainer
13-
render={() => (
14-
<Header aria-label="Maxtek">
15-
<SkipToContent />
16-
<HeaderName href="/" prefix="">
17-
Maxtek
18-
</HeaderName>
19-
<HeaderNavigation aria-label="Main navigation">
20-
<HeaderMenuItem
21-
isActive={activeSection === 'about'}
22-
onClick={() => onSectionChange('about')}
23-
>
24-
About
25-
</HeaderMenuItem>
26-
<HeaderMenuItem
27-
isActive={activeSection === 'projects'}
28-
onClick={() => onSectionChange('projects')}
29-
>
30-
Projects
31-
</HeaderMenuItem>
32-
<HeaderMenuItem
33-
isActive={activeSection === 'contact'}
34-
onClick={() => onSectionChange('contact')}
15+
const NAV_ITEMS = [
16+
{ label: 'Home', path: '/' },
17+
{ label: 'Projects', path: '/projects' },
18+
{ label: 'Contact', path: '/contact' },
19+
]
20+
21+
const AppHeader = ({ darkMode, setDarkMode }) => {
22+
const location = useLocation()
23+
const navigate = useNavigate()
24+
25+
return (
26+
<HeaderContainer
27+
render={() => (
28+
<Header aria-label="Maxtek">
29+
<SkipToContent href="#main-content" />
30+
<HeaderName
31+
href="/"
32+
prefix=""
33+
onClick={(event) => {
34+
event.preventDefault()
35+
navigate('/')
36+
}}
3537
>
36-
Contact
37-
</HeaderMenuItem>
38-
</HeaderNavigation>
39-
</Header>
40-
)}
41-
/>
42-
)
38+
Maxtek
39+
</HeaderName>
40+
<HeaderNavigation aria-label="Main navigation">
41+
{NAV_ITEMS.map((item) => (
42+
<HeaderMenuItem
43+
key={item.path}
44+
isActive={location.pathname === item.path}
45+
onClick={() => navigate(item.path)}
46+
>
47+
{item.label}
48+
</HeaderMenuItem>
49+
))}
50+
</HeaderNavigation>
51+
<HeaderGlobalBar>
52+
<HeaderGlobalAction
53+
aria-label="Toggle dark mode"
54+
onClick={() => setDarkMode(!darkMode)}
55+
isActive={darkMode}
56+
>
57+
{darkMode ? <Moon /> : <Sun />}
58+
</HeaderGlobalAction>
59+
</HeaderGlobalBar>
60+
</Header>
61+
)}
62+
/>
63+
)
64+
}
4365

4466
export default AppHeader

src/components/ContactForm.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ function ContactForm({ onSubmitSuccess = () => {}, onSubmitError = () => {} }) {
5454
};
5555

5656
return (
57-
<Form onSubmit={handleSubmit} style={{ maxWidth: '400px' }}>
57+
<Form onSubmit={handleSubmit}>
5858
<Stack gap={5}>
5959
<TextInput labelText="Name" id="name" name="name" required />
6060
<TextInput labelText="Email" id="email" name="email" type="email" required />

src/components/ProjectList.jsx

Lines changed: 16 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,29 @@
11
import projects from '../assets/projects.json';
2-
import { Link, Tile } from '@carbon/react';
2+
import { Column, Grid, Link, Stack, Tile } from '@carbon/react';
33
import { Code, Doc } from '@carbon/react/icons';
44

55
function Project({ name, description, documentation }) {
6-
const projectLink = `https://github.com/maxtek6/${name}`;
7-
return (
8-
<Tile className="project-tile">
9-
<div className="project-tile__content">
10-
<h3 className="project-tile__name">{name}</h3>
11-
<p className="project-tile__description">{description}</p>
12-
</div>
13-
<div className="project-tile__links">
14-
<Link
15-
className="project-tile__link"
16-
href={projectLink}
17-
renderIcon={(props) => <Code {...props} size={24} />}
18-
target="_blank"
19-
rel="noopener noreferrer"
20-
/>
21-
<Link
22-
className="project-tile__link"
23-
href={documentation}
24-
renderIcon={(props) => <Doc {...props} size={24} />}
25-
target="_blank"
26-
rel="noopener noreferrer"
27-
/>
28-
</div>
29-
</Tile>
30-
)
6+
const projectLink = `https://github.com/maxtek6/${name}`;
7+
return (
8+
<Tile>
9+
</Tile>
10+
)
3111
}
3212

3313
function ProjectList() {
3414
return (
35-
<>
15+
<Grid condensed align='center'>
3616
{projects.map(({ name, description, documentation }) => (
37-
<Project key={name} name={name} description={description} documentation={documentation} />
17+
<Column sm={4} md={4} lg={6}>
18+
<Project
19+
key={name}
20+
name={name}
21+
description={description}
22+
documentation={documentation}
23+
/>
24+
</Column>
3825
))}
39-
</>
26+
</Grid>
4027
);
4128
}
4229

src/components/ProjectTile.jsx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { Column, Grid, Link, Stack, Tile } from '@carbon/react';
2+
import {Code, Doc} from '@carbon/react/icons';
3+
4+
function LinkStack({ projectLink, documentation }) {
5+
return (
6+
<Stack orientation='horizontal'>
7+
<Link href={projectLink} target='_blank' rel='noopener noreferrer'>
8+
<Code size={24}/>
9+
</Link>
10+
{documentation && (
11+
<Link href={documentation} target='_blank' rel='noopener noreferrer'>
12+
<Doc size={24}/>
13+
</Link>
14+
)}
15+
</Stack>
16+
)
17+
}
18+
19+
function ProjectTile({ name, description, documentation }) {
20+
const projectLink = `https://github.com/maxtek6/${name}`;
21+
return (
22+
<Tile className='project-tile'>
23+
<Grid>
24+
<Column span={3}>
25+
<h3>{name}</h3>
26+
</Column>
27+
<Column span={1}>
28+
<LinkStack projectLink={projectLink} documentation={documentation} />
29+
</Column>
30+
</Grid>
31+
<Grid>
32+
<Column span={4}>
33+
<p>{description}</p>
34+
</Column>
35+
</Grid>
36+
</Tile>
37+
)
38+
}
39+
40+
export default ProjectTile;

src/content/About.jsx

Whitespace-only changes.

0 commit comments

Comments
 (0)