Browse Source

feat: language switch button in top-right corner

- LangSwitch component: shows 'ru' on EN pages, 'en' on RU pages
- Tapping navigates between / and /ru/
- Present on all three screens (Rules, Game, Results)
- Styled: no border, small font, muted color

Co-Authored-By: Claude <noreply@anthropic.com>
Oleg Panashchenko 2 tuần trước cách đây
mục cha
commit
a437a9cfc3

+ 33 - 0
client/src/components/LangSwitch.tsx

@@ -0,0 +1,33 @@
+import { detectLang } from '../messages/index.js';
+
+const OTHER: Record<string, { label: string; href: string }> = {
+  en: { label: 'ru', href: '/ru' },
+  ru: { label: 'en', href: '/' },
+};
+
+export function LangSwitch() {
+  const lang = detectLang();
+  const { label, href } = OTHER[lang];
+
+  return (
+    <a
+      href={href}
+      style={{
+        position: 'absolute',
+        top: '8px',
+        right: '12px',
+        fontSize: '0.7rem',
+        fontWeight: 'bold',
+        color: '#787c7e',
+        textDecoration: 'none',
+        border: 'none',
+        background: 'none',
+        cursor: 'pointer',
+        fontFamily: 'monospace',
+        textTransform: 'uppercase',
+      }}
+    >
+      {label}
+    </a>
+  );
+}

+ 3 - 1
client/src/screens/Screen1Rules.tsx

@@ -1,4 +1,5 @@
 import { getMessages } from '../messages/index.js';
+import { LangSwitch } from '../components/LangSwitch.js';
 
 interface Screen1RulesProps {
   onPlay: () => void;
@@ -8,7 +9,8 @@ export function Screen1Rules({ onPlay }: Screen1RulesProps) {
   const { rules, title } = getMessages();
 
   return (
-    <div style={{ maxWidth: '400px', margin: '40px auto', padding: '16px', fontFamily: 'sans-serif' }}>
+    <div style={{ maxWidth: '400px', margin: '40px auto', padding: '16px', fontFamily: 'sans-serif', position: 'relative' }}>
+      <LangSwitch />
       <h1 style={{ textAlign: 'center', fontSize: '2rem', marginBottom: '24px' }}>{title}</h1>
 
       <h2 style={{ fontSize: '1.2rem', marginBottom: '8px' }}>{rules.heading}</h2>

+ 3 - 1
client/src/screens/Screen2Game.tsx

@@ -3,6 +3,7 @@ import type { GuessEntry } from '@wordle/shared';
 import { Grid } from '../components/Grid.js';
 import { Keyboard } from '../components/Keyboard.js';
 import { getMessages } from '../messages/index.js';
+import { LangSwitch } from '../components/LangSwitch.js';
 
 interface Screen2GameProps {
   guesses: GuessEntry[];
@@ -71,7 +72,8 @@ export function Screen2Game({ guesses, letterColors, message, onGuess, onDismiss
   );
 
   return (
-    <div style={{ maxWidth: '400px', margin: '20px auto', padding: '8px', fontFamily: 'sans-serif' }}>
+    <div style={{ maxWidth: '400px', margin: '20px auto', padding: '8px', fontFamily: 'sans-serif', position: 'relative' }}>
+      <LangSwitch />
       <h1 style={{ textAlign: 'center', fontSize: '1.6rem', marginBottom: '16px' }}>{getMessages().title}</h1>
 
       <div style={{ position: 'relative' }}>

+ 3 - 1
client/src/screens/Screen3Results.tsx

@@ -1,5 +1,6 @@
 import type { GameStats, SolverReplay } from '@wordle/shared';
 import { getMessages } from '../messages/index.js';
+import { LangSwitch } from '../components/LangSwitch.js';
 
 interface Screen3ResultsProps {
   won: boolean;
@@ -68,7 +69,8 @@ export function Screen3Results({ won, attemptCount, revealedWord, stats, replays
   const r = getMessages().results;
 
   return (
-    <div style={{ maxWidth: '400px', margin: '24px auto', padding: '16px', fontFamily: 'sans-serif', textAlign: 'center' }}>
+    <div style={{ maxWidth: '400px', margin: '24px auto', padding: '16px', fontFamily: 'sans-serif', textAlign: 'center', position: 'relative' }}>
+      <LangSwitch />
       <h1 style={{ fontSize: '1.6rem', marginBottom: '12px' }}>
         {won ? r.congratulations : r.betterLuck}
       </h1>