Skip to content

Commit 554dc0d

Browse files
authored
Update App.tsx
1 parent 7baad46 commit 554dc0d

File tree

1 file changed

+114
-86
lines changed

1 file changed

+114
-86
lines changed

source-code/App.tsx

Lines changed: 114 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,39 @@ import { Navbar } from './components/Navbar';
44
import { VersionCard } from './components/VersionCard';
55
import { WallpaperGrid } from './components/WallpaperGrid';
66
import { Settings } from './components/Settings';
7-
import { AppSection, ReleaseInfo, ThemeId } from './types';
7+
import { Gallery } from './components/Gallery';
8+
import { Team } from './components/Team';
9+
import { AppSection, ReleaseInfo, ThemeId, Language } from './types';
810
import { RELEASE_INFO_URL } from './constants';
911
import { parseHackerReleaseFile } from './utils/parser';
1012
import { Loader2, WifiOff, Terminal } from 'lucide-react';
1113
import { applyTheme } from './utils/theme';
14+
import { TRANSLATIONS } from './utils/translations';
1215

1316
export default function App() {
1417
const [currentSection, setCurrentSection] = useState<AppSection>(AppSection.RELEASES);
1518
const [releases, setReleases] = useState<ReleaseInfo[]>([]);
1619
const [loading, setLoading] = useState(true);
1720
const [error, setError] = useState<string | null>(null);
1821
const [currentTheme, setCurrentTheme] = useState<ThemeId>('hacker');
22+
const [currentLanguage, setCurrentLanguage] = useState<Language>('pl');
1923

20-
// Load saved theme on boot
24+
// Load saved settings on boot
2125
useEffect(() => {
22-
const saved = localStorage.getItem('hackeros_theme') as ThemeId;
23-
if (saved) {
24-
setCurrentTheme(saved);
25-
applyTheme(saved);
26+
// Theme
27+
const savedTheme = localStorage.getItem('hackeros_theme') as ThemeId;
28+
if (savedTheme) {
29+
setCurrentTheme(savedTheme);
30+
applyTheme(savedTheme);
2631
} else {
2732
applyTheme('hacker');
2833
}
34+
35+
// Language
36+
const savedLang = localStorage.getItem('hackeros_lang') as Language;
37+
if (savedLang) {
38+
setCurrentLanguage(savedLang);
39+
}
2940
}, []);
3041

3142
const handleThemeChange = (id: ThemeId) => {
@@ -34,13 +45,20 @@ export default function App() {
3445
localStorage.setItem('hackeros_theme', id);
3546
};
3647

48+
const handleLanguageChange = (lang: Language) => {
49+
setCurrentLanguage(lang);
50+
localStorage.setItem('hackeros_lang', lang);
51+
};
52+
53+
const t = TRANSLATIONS[currentLanguage];
54+
3755
useEffect(() => {
3856
const fetchData = async () => {
3957
try {
4058
setLoading(true);
4159
// Add cache busting
4260
const response = await fetch(`${RELEASE_INFO_URL}?t=${Date.now()}`);
43-
61+
4462
if (!response.ok) throw new Error('Network error');
4563

4664
const text = await response.text();
@@ -62,93 +80,103 @@ export default function App() {
6280
case AppSection.RELEASES:
6381
return (
6482
<div className="px-4 pb-24 pt-2 max-w-lg mx-auto">
65-
<header className="px-2 mb-6 flex flex-col justify-center">
66-
<h1 className="text-3xl font-mono font-bold text-white flex items-center gap-3">
67-
HackerOS
68-
<span className="px-2 py-0.5 rounded text-[10px] font-bold bg-primary text-background border border-primary/50">
69-
MOBILE
70-
</span>
71-
</h1>
72-
<p className="text-muted text-sm flex items-center gap-2 mt-1">
73-
<span className="w-2 h-2 rounded-full bg-green-500 animate-pulse"></span>
74-
System Systems Online
75-
</p>
76-
</header>
77-
78-
{loading ? (
79-
<div className="flex flex-col items-center justify-center h-[50vh] text-muted space-y-4">
80-
<div className="relative">
81-
<div className="absolute inset-0 bg-primary/20 blur-xl rounded-full"></div>
82-
<Loader2 className="animate-spin relative z-10 text-primary" size={48} />
83-
</div>
84-
<p className="font-mono text-xs animate-pulse">DECRYPTING_PACKETS...</p>
85-
</div>
86-
) : error ? (
87-
<div className="flex flex-col items-center justify-center h-[50vh] text-red-400 text-center px-6">
88-
<div className="bg-red-500/10 p-4 rounded-full mb-4 ring-1 ring-red-500/20">
89-
<WifiOff size={40} />
90-
</div>
91-
<p className="font-bold mb-2">SIGNAL_LOST</p>
92-
<p className="text-xs text-muted mb-6">{error}</p>
93-
<button
94-
onClick={() => window.location.reload()}
95-
className="px-6 py-2 bg-red-500 hover:bg-red-600 text-white rounded-lg text-sm font-bold shadow-lg transition-colors"
96-
>
97-
RETRY_CONNECTION
98-
</button>
99-
</div>
100-
) : (
101-
<div className="space-y-4">
102-
{releases.map((release, index) => (
103-
<motion.div
104-
key={index}
105-
initial={{ opacity: 0, y: 20 }}
106-
animate={{ opacity: 1, y: 0 }}
107-
transition={{ delay: index * 0.1 }}
108-
>
109-
<VersionCard
110-
release={release}
111-
isLatest={index === 0}
112-
/>
113-
</motion.div>
114-
))}
83+
<header className="px-2 mb-6 flex flex-col justify-center">
84+
<h1 className="text-3xl font-mono font-bold text-white flex items-center gap-3">
85+
HackerOS
86+
<span className="px-2 py-0.5 rounded text-[10px] font-bold bg-primary text-background border border-primary/50">
87+
{t.sub_releases}
88+
</span>
89+
</h1>
90+
</header>
11591

116-
<div className="text-center py-8 opacity-50">
117-
<Terminal size={24} className="mx-auto mb-2 text-muted" />
118-
<p className="text-[10px] font-mono text-muted uppercase">End of Log</p>
119-
</div>
120-
</div>
121-
)}
92+
{loading ? (
93+
<div className="flex flex-col items-center justify-center h-[50vh] text-muted space-y-4">
94+
<div className="relative">
95+
<div className="absolute inset-0 bg-primary/20 blur-xl rounded-full"></div>
96+
<Loader2 className="animate-spin relative z-10 text-primary" size={48} />
97+
</div>
98+
<p className="font-mono text-xs animate-pulse">{t.decrypting}</p>
99+
</div>
100+
) : error ? (
101+
<div className="flex flex-col items-center justify-center h-[50vh] text-red-400 text-center px-6">
102+
<div className="bg-red-500/10 p-4 rounded-full mb-4 ring-1 ring-red-500/20">
103+
<WifiOff size={40} />
104+
</div>
105+
<p className="font-bold mb-2">{t.error_signal}</p>
106+
<p className="text-xs text-muted mb-6">{t.error_network}</p>
107+
<button
108+
onClick={() => window.location.reload()}
109+
className="px-6 py-2 bg-red-500 hover:bg-red-600 text-white rounded-lg text-sm font-bold shadow-lg transition-colors"
110+
>
111+
{t.retry}
112+
</button>
113+
</div>
114+
) : (
115+
<div className="space-y-4">
116+
{releases.map((release, index) => (
117+
<motion.div
118+
key={index}
119+
initial={{ opacity: 0, y: 20 }}
120+
animate={{ opacity: 1, y: 0 }}
121+
transition={{ delay: index * 0.1 }}
122+
>
123+
<VersionCard
124+
release={release}
125+
isLatest={index === 0}
126+
language={currentLanguage}
127+
/>
128+
</motion.div>
129+
))}
130+
131+
<div className="text-center py-8 opacity-50">
132+
<Terminal size={24} className="mx-auto mb-2 text-muted" />
133+
<p className="text-[10px] font-mono text-muted uppercase">{t.end_of_log}</p>
134+
</div>
135+
</div>
136+
)}
122137
</div>
123138
);
124-
case AppSection.WALLPAPERS:
125-
return <WallpaperGrid />;
126-
case AppSection.SETTINGS:
127-
return <Settings currentTheme={currentTheme} setTheme={handleThemeChange} />;
128-
default:
129-
return null;
139+
case AppSection.WALLPAPERS:
140+
return <WallpaperGrid language={currentLanguage} />;
141+
case AppSection.GALLERY:
142+
return <Gallery language={currentLanguage} />;
143+
case AppSection.TEAM:
144+
return <Team language={currentLanguage} />;
145+
case AppSection.SETTINGS:
146+
return <Settings
147+
currentTheme={currentTheme}
148+
setTheme={handleThemeChange}
149+
language={currentLanguage}
150+
setLanguage={handleLanguageChange}
151+
/>;
152+
default:
153+
return null;
130154
}
131155
};
132156

133157
return (
134158
<div className="min-h-screen bg-background text-text selection:bg-primary/30 safe-area-top">
135-
{/* Background ambient glow */}
136-
<div className="fixed top-0 left-0 w-full h-96 bg-primary/5 blur-[100px] pointer-events-none" />
137-
138-
<AnimatePresence mode="wait">
139-
<motion.main
140-
key={currentSection}
141-
initial={{ opacity: 0, x: 10 }}
142-
animate={{ opacity: 1, x: 0 }}
143-
exit={{ opacity: 0, x: -10 }}
144-
transition={{ duration: 0.2 }}
145-
className="relative z-10"
146-
>
147-
{renderContent()}
148-
</motion.main>
149-
</AnimatePresence>
150-
151-
<Navbar currentSection={currentSection} onSectionChange={setCurrentSection} />
159+
{/* Background ambient glow */}
160+
<div className="fixed top-0 left-0 w-full h-96 bg-primary/5 blur-[100px] pointer-events-none" />
161+
162+
<AnimatePresence mode="wait">
163+
<motion.main
164+
key={currentSection}
165+
initial={{ opacity: 0, x: 10 }}
166+
animate={{ opacity: 1, x: 0 }}
167+
exit={{ opacity: 0, x: -10 }}
168+
transition={{ duration: 0.2 }}
169+
className="relative z-10"
170+
>
171+
{renderContent()}
172+
</motion.main>
173+
</AnimatePresence>
174+
175+
<Navbar
176+
currentSection={currentSection}
177+
onSectionChange={setCurrentSection}
178+
language={currentLanguage}
179+
/>
152180
</div>
153181
);
154182
}

0 commit comments

Comments
 (0)