Skip to content

Commit a8c54d6

Browse files
committed
Add new 404 page as UI fallback
1 parent 3d45eb7 commit a8c54d6

2 files changed

Lines changed: 158 additions & 0 deletions

File tree

ui/src/i18n/ui.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,12 @@ export const ui = {
1515
en: {
1616
"site.title": "Ultimate Python",
1717
"nav.start": "Start Learning",
18+
"nav.home": "Back to home",
1819
"nav.github": "View on GitHub",
1920

21+
"notFound.title": "Page not found",
22+
"notFound.message": "This page doesn't exist or may have moved. Search the sidebar or start from the first lesson.",
23+
2024
"welcome.title": "Master Python by example",
2125
"welcome.subtitle": "An interactive study guide for newcomers and professionals. Learn from clean, heavily-commented code runnable on Replit or locally with zero dependencies.",
2226
"card.lessons.title": "Standalone Lessons",
@@ -38,8 +42,12 @@ export const ui = {
3842
ko: {
3943
"site.title": "Ultimate Python",
4044
"nav.start": "학습 시작하기",
45+
"nav.home": "홈으로 돌아가기",
4146
"nav.github": "GitHub에서 보기",
4247

48+
"notFound.title": "페이지를 찾을 수 없습니다",
49+
"notFound.message": "이 페이지가 없거나 이동했을 수 있습니다. 사이드바에서 검색하거나 첫 레슨부터 시작하세요.",
50+
4351
"welcome.title": "예제로 마스터하는 Python",
4452
"welcome.subtitle": "초보자와 전문가 모두를 위한 대화형 학습 가이드. Replit이나 로컬에서 의존성 없이 실행 가능한 깨끗하고 주석이 잘 달린 코드로 학습하세요.",
4553
"card.lessons.title": "독립형 레슨",
@@ -61,8 +69,12 @@ export const ui = {
6169
"zh-tw": {
6270
"site.title": "Ultimate Python",
6371
"nav.start": "開始學習",
72+
"nav.home": "返回首頁",
6473
"nav.github": "在 GitHub 上查看",
6574

75+
"notFound.title": "找不到頁面",
76+
"notFound.message": "此頁面不存在或可能已移動。請使用側邊欄搜尋,或從第一課開始。",
77+
6678
"welcome.title": "通過範例掌握 Python",
6779
"welcome.subtitle": "適合初學者和專業人士的互動式學習指南。通過可在 Replit 或本地無依賴運行的乾淨、注釋豐富的程式碼進行學習。",
6880
"card.lessons.title": "獨立課程",
@@ -84,8 +96,12 @@ export const ui = {
8496
es: {
8597
"site.title": "Ultimate Python",
8698
"nav.start": "Comenzar a Aprender",
99+
"nav.home": "Volver al inicio",
87100
"nav.github": "Ver en GitHub",
88101

102+
"notFound.title": "Página no encontrada",
103+
"notFound.message": "Esta página no existe o puede haberse movido. Busca en la barra lateral o empieza desde la primera lección.",
104+
89105
"welcome.title": "Domina Python a través de ejemplos",
90106
"welcome.subtitle": "Una guía de estudio interactiva para principiantes y profesionales. Aprende con código limpio y comentado, ejecutable localmente o en Replit sin dependencias.",
91107
"card.lessons.title": "Lecciones Independientes",
@@ -107,8 +123,12 @@ export const ui = {
107123
de: {
108124
"site.title": "Ultimate Python",
109125
"nav.start": "Lernen starten",
126+
"nav.home": "Zur Startseite",
110127
"nav.github": "Auf GitHub anzeigen",
111128

129+
"notFound.title": "Seite nicht gefunden",
130+
"notFound.message": "Diese Seite existiert nicht oder wurde verschoben. Nutze die Seitenleiste oder starte mit der ersten Lektion.",
131+
112132
"welcome.title": "Python an Beispielen meistern",
113133
"welcome.subtitle": "Ein interaktiver Leitfaden für Einsteiger und Profis. Lerne mit sauberem, gut kommentiertem Code, der lokal oder in Replit ohne Abhängigkeiten läuft.",
114134
"card.lessons.title": "Eigenständige Lektionen",
@@ -130,8 +150,12 @@ export const ui = {
130150
fr: {
131151
"site.title": "Ultimate Python",
132152
"nav.start": "Commencer l'apprentissage",
153+
"nav.home": "Retour à l'accueil",
133154
"nav.github": "Voir sur GitHub",
134155

156+
"notFound.title": "Page introuvable",
157+
"notFound.message": "Cette page n'existe pas ou a peut-être été déplacée. Utilisez la barre latérale ou commencez par la première leçon.",
158+
135159
"welcome.title": "Maîtrisez Python par l'exemple",
136160
"welcome.subtitle": "Un guide d'étude interactif pour débutants et professionnels. Apprenez grâce à un code propre et commenté, exécutable localement ou sur Replit sans dépendances.",
137161
"card.lessons.title": "Leçons Autonomes",
@@ -153,8 +177,12 @@ export const ui = {
153177
hi: {
154178
"site.title": "Ultimate Python",
155179
"nav.start": "सीखना शुरू करें",
180+
"nav.home": "होम पर वापस जाएँ",
156181
"nav.github": "GitHub पर देखें",
157182

183+
"notFound.title": "पृष्ठ नहीं मिला",
184+
"notFound.message": "यह पृष्ठ मौजूद नहीं है या स्थान बदल गया हो सकता है। साइडबार में खोजें या पहले पाठ से शुरू करें।",
185+
158186
"welcome.title": "उदाहरणों के माध्यम से पायथन को मास्टर करें",
159187
"welcome.subtitle": "शुरुआती और पेशेवरों के लिए एक इंटरैक्टिव स्टडी गाइड। बिना किसी निर्भरता के स्थानीय रूप से या Replit पर चलने वाले स्पष्ट, टिप्पणियों से युक्त कोड से सीखें।",
160188
"card.lessons.title": "स्वतंत्र पाठ",
@@ -176,8 +204,12 @@ export const ui = {
176204
"pt-br": {
177205
"site.title": "Ultimate Python",
178206
"nav.start": "Começar a Aprender",
207+
"nav.home": "Voltar ao início",
179208
"nav.github": "Ver no GitHub",
180209

210+
"notFound.title": "Página não encontrada",
211+
"notFound.message": "Esta página não existe ou pode ter sido movida. Pesquise na barra lateral ou comece pela primeira lição.",
212+
181213
"welcome.title": "Domine o Python através de exemplos",
182214
"welcome.subtitle": "Um guia de estudo interativo para iniciantes e profissionais. Aprenda com código limpo e comentado, executável localmente ou no Replit sem dependências.",
183215
"card.lessons.title": "Lições Independentes",

ui/src/pages/404.astro

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
---
2+
import Layout from '../layouts/Layout.astro';
3+
import Sidebar from '../components/Sidebar.astro';
4+
import { getLangFromUrl, useTranslations } from '../i18n/ui';
5+
import { ArrowRight } from '@lucide/astro';
6+
7+
const lang = getLangFromUrl(Astro.url);
8+
const t = useTranslations(lang);
9+
10+
Astro.response.status = 404;
11+
---
12+
13+
<Layout title={t('notFound.title')}>
14+
<div class="app-container" id="app-container">
15+
<Sidebar activeLang={lang} />
16+
17+
<main class="not-found-container animate-fade-in">
18+
<div class="not-found-content">
19+
<p class="not-found-code">404</p>
20+
<h1>{t('notFound.title')}</h1>
21+
<p class="not-found-message">{t('notFound.message')}</p>
22+
23+
<div class="cta-group">
24+
<a href={`/ultimate-python/${lang}/`} class="btn btn-secondary">
25+
{t('nav.home')}
26+
</a>
27+
<a href={`/ultimate-python/${lang}/fundamentals/variable/`} class="btn btn-primary">
28+
{t('nav.start')}
29+
<ArrowRight size={16} class="btn-arrow" />
30+
</a>
31+
</div>
32+
</div>
33+
</main>
34+
</div>
35+
</Layout>
36+
37+
<style>
38+
.not-found-container {
39+
flex: 1;
40+
overflow-y: auto;
41+
padding: 4rem 2rem;
42+
display: flex;
43+
justify-content: center;
44+
align-items: center;
45+
background-color: var(--bg-primary);
46+
}
47+
48+
.not-found-content {
49+
max-width: 560px;
50+
width: 100%;
51+
text-align: center;
52+
display: flex;
53+
flex-direction: column;
54+
align-items: center;
55+
gap: 1rem;
56+
}
57+
58+
.not-found-code {
59+
font-family: var(--font-mono);
60+
font-size: 0.9rem;
61+
font-weight: 500;
62+
letter-spacing: 0.08em;
63+
color: var(--forest-green-light);
64+
}
65+
66+
h1 {
67+
font-size: 2.25rem;
68+
line-height: 1.2;
69+
}
70+
71+
.not-found-message {
72+
font-size: 1.05rem;
73+
color: var(--text-secondary);
74+
line-height: 1.6;
75+
margin-bottom: 0.5rem;
76+
}
77+
78+
.cta-group {
79+
display: flex;
80+
gap: 1rem;
81+
align-items: center;
82+
flex-wrap: wrap;
83+
justify-content: center;
84+
margin-top: 0.5rem;
85+
}
86+
87+
.btn {
88+
padding: 0.8rem 1.6rem;
89+
border-radius: 6px;
90+
font-weight: 500;
91+
transition: all var(--transition-speed);
92+
display: inline-flex;
93+
align-items: center;
94+
gap: 0.5rem;
95+
}
96+
97+
.btn-primary {
98+
background-color: var(--forest-green);
99+
color: var(--bg-primary);
100+
}
101+
102+
.btn-primary:hover {
103+
background-color: var(--forest-green-light);
104+
color: var(--bg-primary);
105+
transform: translateY(-1px);
106+
}
107+
108+
.btn-secondary {
109+
border: 1px solid var(--border-color);
110+
background-color: var(--bg-secondary);
111+
color: var(--text-primary);
112+
}
113+
114+
.btn-secondary:hover {
115+
background-color: var(--bg-tertiary);
116+
transform: translateY(-1px);
117+
}
118+
119+
.btn-arrow {
120+
transition: transform var(--transition-speed);
121+
}
122+
123+
.btn-primary:hover .btn-arrow {
124+
transform: translateX(4px);
125+
}
126+
</style>

0 commit comments

Comments
 (0)