Skip to content

Commit 5507342

Browse files
committed
Add custom 404 page and update deploy workflow
Add a styled NotFound page (src/theme/NotFound/index.tsx) and its CSS module (src/pages/404.module.css) to provide a custom 404 experience with actions to return home or browse docs. Update .github/workflows/deploy.yml: rename workflow, add job/step display names, restrict GITHUB_TOKEN permissions (contents: read), and clarify Node.js setup/checkout steps (fetch-depth: 0, Node 20, yarn cache).
1 parent a6c7ce4 commit 5507342

3 files changed

Lines changed: 224 additions & 4 deletions

File tree

.github/workflows/deploy.yml

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,27 @@
1-
name: Deploy Docusaurus to Webserver
1+
name: Deploy MSK Scripts Docs
22

33
on:
44
push:
55
branches:
6-
- main # Startet das Deployment, wenn Code in 'main' gepusht wird
6+
- main
7+
8+
# SECURITY: GITHUB_TOKEN auf Minimum beschränken
9+
permissions:
10+
contents: read
711

812
jobs:
913
build-and-deploy:
14+
name: Build & Deploy
1015
runs-on: ubuntu-latest
1116

1217
steps:
13-
- uses: actions/checkout@v4
18+
- name: ⬇️ Checkout Repository
19+
uses: actions/checkout@v4
1420
with:
1521
fetch-depth: 0
16-
- uses: actions/setup-node@v4
22+
23+
- name: 🟢 Setup Node.js
24+
uses: actions/setup-node@v4
1725
with:
1826
node-version: 20
1927
cache: yarn

src/pages/404.module.css

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
.root {
2+
position: relative;
3+
display: flex;
4+
align-items: center;
5+
justify-content: center;
6+
min-height: calc(100vh - var(--ifm-navbar-height) - 200px);
7+
padding: 64px 32px;
8+
text-align: center;
9+
overflow: hidden;
10+
isolation: isolate;
11+
}
12+
13+
/* Radial glow blob — MSK Grün */
14+
.glow {
15+
position: absolute;
16+
top: -80px;
17+
left: 50%;
18+
transform: translateX(-50%);
19+
width: 700px;
20+
height: 320px;
21+
background: radial-gradient(ellipse at 50% 0%,
22+
rgba(38, 112, 10, 0.22) 0%,
23+
rgba(38, 112, 10, 0.07) 40%,
24+
transparent 70%);
25+
pointer-events: none;
26+
z-index: 0;
27+
}
28+
29+
[data-theme='light'] .glow {
30+
background: radial-gradient(ellipse at 50% 0%,
31+
rgba(38, 112, 10, 0.12) 0%,
32+
rgba(38, 112, 10, 0.04) 40%,
33+
transparent 70%);
34+
}
35+
36+
/* Top accent line — MSK Grün */
37+
.topline {
38+
position: absolute;
39+
top: 0;
40+
left: 50%;
41+
transform: translateX(-50%);
42+
width: 260px;
43+
height: 2px;
44+
background: linear-gradient(90deg,
45+
transparent,
46+
var(--ifm-color-primary),
47+
transparent);
48+
pointer-events: none;
49+
z-index: 0;
50+
}
51+
52+
.inner {
53+
position: relative;
54+
z-index: 1;
55+
animation: fadeUp 0.5s cubic-bezier(0.16, 1, 0.3, 1) both;
56+
}
57+
58+
@keyframes fadeUp {
59+
from {
60+
opacity: 0;
61+
transform: translateY(20px);
62+
}
63+
to {
64+
opacity: 1;
65+
transform: translateY(0);
66+
}
67+
}
68+
69+
/* Large 404 number — MSK Grün Gradient */
70+
.code {
71+
font-size: clamp(5rem, 18vw, 9rem);
72+
font-weight: 800;
73+
line-height: 1;
74+
letter-spacing: -0.04em;
75+
background: linear-gradient(135deg,
76+
var(--ifm-color-primary-darkest) 0%,
77+
var(--ifm-color-primary) 45%,
78+
var(--ifm-color-primary-lightest) 100%);
79+
-webkit-background-clip: text;
80+
-webkit-text-fill-color: transparent;
81+
background-clip: text;
82+
margin: 0 0 16px;
83+
user-select: none;
84+
}
85+
86+
.title {
87+
font-size: clamp(1.5rem, 4vw, 2.2rem) !important;
88+
font-weight: 700 !important;
89+
letter-spacing: -0.02em !important;
90+
color: var(--ifm-font-color-base) !important;
91+
margin: 0 0 12px !important;
92+
}
93+
94+
.sub {
95+
font-size: 0.95rem;
96+
color: var(--ifm-color-emphasis-600);
97+
max-width: 380px;
98+
margin: 0 auto 32px;
99+
line-height: 1.65;
100+
}
101+
102+
/* ─── Buttons ─────────────────────────────────────────────────────────────── */
103+
104+
.actions {
105+
display: flex;
106+
gap: 10px;
107+
justify-content: center;
108+
flex-wrap: wrap;
109+
}
110+
111+
.btnPrimary {
112+
display: inline-flex;
113+
align-items: center;
114+
background: var(--ifm-color-primary) !important;
115+
border: 1px solid var(--ifm-color-primary) !important;
116+
color: #fff !important;
117+
font-weight: 600 !important;
118+
font-size: 0.9rem !important;
119+
font-family: var(--ifm-font-family-base) !important;
120+
border-radius: 8px !important;
121+
padding: 10px 22px !important;
122+
text-decoration: none !important;
123+
transition: background 0.15s, border-color 0.15s !important;
124+
}
125+
126+
.btnPrimary:hover {
127+
background: var(--ifm-color-primary-dark) !important;
128+
border-color: var(--ifm-color-primary-dark) !important;
129+
color: #fff !important;
130+
}
131+
132+
.btnGhost {
133+
display: inline-flex;
134+
align-items: center;
135+
background: transparent !important;
136+
border: 1px solid var(--ifm-color-emphasis-300) !important;
137+
color: var(--ifm-color-emphasis-700) !important;
138+
font-weight: 600 !important;
139+
font-size: 0.9rem !important;
140+
font-family: var(--ifm-font-family-base) !important;
141+
border-radius: 8px !important;
142+
padding: 10px 22px !important;
143+
text-decoration: none !important;
144+
transition: background 0.15s, border-color 0.15s, color 0.15s !important;
145+
}
146+
147+
.btnGhost:hover {
148+
background: var(--ifm-color-emphasis-100) !important;
149+
border-color: var(--ifm-color-primary) !important;
150+
color: var(--ifm-color-primary) !important;
151+
}
152+
153+
/* ─── Responsive ──────────────────────────────────────────────────────────── */
154+
155+
@media (max-width: 600px) {
156+
.root {
157+
padding: 48px 16px;
158+
}
159+
160+
.code {
161+
font-size: clamp(4rem, 22vw, 6rem);
162+
}
163+
164+
.actions {
165+
flex-direction: column;
166+
align-items: center;
167+
}
168+
}

src/theme/NotFound/index.tsx

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import type {ReactNode} from 'react';
2+
import Link from '@docusaurus/Link';
3+
import {PageMetadata} from '@docusaurus/theme-common';
4+
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
5+
import Layout from '@theme/Layout';
6+
import Heading from '@theme/Heading';
7+
import styles from '@site/src/pages/404.module.css';
8+
9+
export default function NotFound(): ReactNode {
10+
const {siteConfig} = useDocusaurusContext();
11+
12+
return (
13+
<>
14+
<PageMetadata title={`404 – ${siteConfig.title}`} />
15+
<Layout>
16+
<main className={styles.root}>
17+
<div className={styles.glow} aria-hidden="true" />
18+
<div className={styles.topline} aria-hidden="true" />
19+
20+
<div className={styles.inner}>
21+
<p className={styles.code}>404</p>
22+
23+
<Heading as="h1" className={styles.title}>
24+
Page not found
25+
</Heading>
26+
27+
<p className={styles.sub}>
28+
The requested page does not exist or has been moved.
29+
</p>
30+
31+
<div className={styles.actions}>
32+
<Link className={styles.btnPrimary} to="/">
33+
← Back to Home
34+
</Link>
35+
<Link className={styles.btnGhost} to="/docs">
36+
Browse Docs
37+
</Link>
38+
</div>
39+
</div>
40+
</main>
41+
</Layout>
42+
</>
43+
);
44+
}

0 commit comments

Comments
 (0)