Install menu in Settings + logout icon + drawer install link

- Settings: Install section (Android APK, PWA, iOS soon, F-Droid soon)
- Logout: icon only (red door), no text
- Avatar: initials only, name in drawer
- Drawer: Install link to /settings#install
- Translations: install key in cs/he/ru/ua

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-29 21:00:14 +00:00
parent 867482c674
commit bb8763bca1
6 changed files with 61 additions and 13 deletions

View File

@@ -70,6 +70,37 @@ export default function SettingsPage() {
</div> </div>
</div> </div>
{/* Install section */}
<section id="install" className="bg-white dark:bg-gray-900 rounded-xl p-4 border border-gray-200 dark:border-gray-700">
<h2 className="font-semibold mb-3">{t("settings.install") || "Instalace"}</h2>
<div className="space-y-2">
<a href="https://expo.dev/accounts/it-enterprise/projects/task-team/builds/b31c63a8-0e4f-44d6-80e9-98cb24174037"
target="_blank" rel="noopener"
className="flex items-center gap-3 px-4 py-3 bg-green-600 text-white rounded-lg font-medium hover:bg-green-700 transition-colors">
<span className="text-xl">&#x1F916;</span>
<span>Android APK</span>
<span className="ml-auto text-sm opacity-75">St&#xe1;hnout</span>
</a>
<a href="https://tasks.hasdo.info"
target="_blank" rel="noopener"
className="flex items-center gap-3 px-4 py-3 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 transition-colors">
<span className="text-xl">&#x1F310;</span>
<span>PWA Web App</span>
<span className="ml-auto text-sm opacity-75">Otev&#x159;&#xed;t</span>
</a>
<div className="flex items-center gap-3 px-4 py-3 bg-gray-200 dark:bg-gray-700 text-gray-500 rounded-lg">
<span className="text-xl">&#x1F34E;</span>
<span>iOS (App Store)</span>
<span className="ml-auto text-sm">P&#x159;ipravujeme</span>
</div>
<div className="flex items-center gap-3 px-4 py-3 bg-gray-200 dark:bg-gray-700 text-gray-500 rounded-lg">
<span className="text-xl">&#x1F4E6;</span>
<span>F-Droid</span>
<span className="ml-auto text-sm">P&#x159;ipravujeme</span>
</div>
</div>
</section>
{/* Appearance */} {/* Appearance */}
<div className="bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-2xl p-5"> <div className="bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-2xl p-5">
<h2 className="text-sm font-semibold text-muted uppercase tracking-wide mb-4">{t("settings.appearance")}</h2> <h2 className="text-sm font-semibold text-muted uppercase tracking-wide mb-4">{t("settings.appearance")}</h2>

View File

@@ -41,7 +41,7 @@ export default function Header() {
<> <>
<header className="sticky top-0 z-50 bg-white/80 dark:bg-gray-950/80 backdrop-blur-md border-b border-gray-200 dark:border-gray-800"> <header className="sticky top-0 z-50 bg-white/80 dark:bg-gray-950/80 backdrop-blur-md border-b border-gray-200 dark:border-gray-800">
<div className="max-w-4xl mx-auto px-4 h-11 flex items-center justify-end gap-2"> <div className="max-w-4xl mx-auto px-4 h-11 flex items-center justify-end gap-2">
{/* Right side only: avatar + hamburger */} {/* Right side only: avatar (no name text) + hamburger */}
{token && user && ( {token && user && (
<button <button
onClick={openDrawer} onClick={openDrawer}
@@ -73,7 +73,7 @@ export default function Header() {
/> />
{/* Drawer panel */} {/* Drawer panel */}
<div className="absolute right-0 top-0 bottom-0 w-72 bg-white dark:bg-gray-900 shadow-2xl animate-slideInRight"> <div className="absolute right-0 top-0 bottom-0 w-72 bg-white dark:bg-gray-900 shadow-2xl animate-slideInRight flex flex-col">
{/* Close button */} {/* Close button */}
<div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-800"> <div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-800">
<span className="font-semibold text-lg">{t("common.menu")}</span> <span className="font-semibold text-lg">{t("common.menu")}</span>
@@ -88,7 +88,7 @@ export default function Header() {
</button> </button>
</div> </div>
{/* User info */} {/* User info - full name + email */}
{token && user && ( {token && user && (
<div className="p-4 border-b border-gray-200 dark:border-gray-800"> <div className="p-4 border-b border-gray-200 dark:border-gray-800">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
@@ -104,7 +104,7 @@ export default function Header() {
)} )}
{/* Menu items */} {/* Menu items */}
<div className="p-2 space-y-1"> <div className="p-2 space-y-1 flex-1 overflow-y-auto">
<Link <Link
href="/tasks" href="/tasks"
onClick={closeDrawer} onClick={closeDrawer}
@@ -150,6 +150,18 @@ export default function Header() {
<span className="text-sm font-medium">{t("nav.settings")}</span> <span className="text-sm font-medium">{t("nav.settings")}</span>
</Link> </Link>
{/* Install link */}
<Link
href="/settings#install"
onClick={closeDrawer}
className="flex items-center gap-3 px-4 py-3 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors min-h-[48px]"
>
<svg className="w-5 h-5 text-muted" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
<path strokeLinecap="round" strokeLinejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
</svg>
<span className="text-sm font-medium">{t("settings.install") || "Instalace"}</span>
</Link>
{/* Theme toggle */} {/* Theme toggle */}
<button <button
onClick={() => { toggleTheme(); }} onClick={() => { toggleTheme(); }}
@@ -170,17 +182,18 @@ export default function Header() {
</button> </button>
</div> </div>
{/* Logout at bottom */} {/* Logout icon at bottom */}
{token && ( {token && (
<div className="absolute bottom-0 left-0 right-0 p-4 border-t border-gray-200 dark:border-gray-800 safe-area-bottom"> <div className="p-4 border-t border-gray-200 dark:border-gray-800 safe-area-bottom">
<button <button
onClick={handleLogout} onClick={handleLogout}
className="w-full flex items-center justify-center gap-2 px-4 py-3 rounded-lg border border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors min-h-[48px]" title={t("auth.logout")}
className="p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors min-w-[44px] min-h-[44px] flex items-center justify-center"
aria-label={t("auth.logout")}
> >
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}> <svg className="w-5 h-5 text-red-500" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
<path strokeLinecap="round" strokeLinejoin="round" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" /> <path strokeLinecap="round" strokeLinejoin="round" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />
</svg> </svg>
<span className="text-sm font-medium">{t("auth.logout")}</span>
</button> </button>
</div> </div>
)} )}

View File

@@ -114,7 +114,8 @@
"saved": "Uloženo!", "saved": "Uloženo!",
"profile": "Profil", "profile": "Profil",
"appearance": "Vzhled", "appearance": "Vzhled",
"user": "Uživatel" "user": "Uživatel",
"install": "Instalace"
}, },
"goals": { "goals": {
"title": "Cíle", "title": "Cíle",

View File

@@ -114,7 +114,8 @@
"saved": "נשמר!", "saved": "נשמר!",
"profile": "פרופיל", "profile": "פרופיל",
"appearance": "מראה", "appearance": "מראה",
"user": "משתמש" "user": "משתמש",
"install": "התקנה"
}, },
"goals": { "goals": {
"title": "מטרות", "title": "מטרות",

View File

@@ -114,7 +114,8 @@
"saved": "Сохранено!", "saved": "Сохранено!",
"profile": "Профиль", "profile": "Профиль",
"appearance": "Внешний вид", "appearance": "Внешний вид",
"user": "Пользователь" "user": "Пользователь",
"install": "Установка"
}, },
"goals": { "goals": {
"title": "Цели", "title": "Цели",

View File

@@ -114,7 +114,8 @@
"saved": "Збережено!", "saved": "Збережено!",
"profile": "Профіль", "profile": "Профіль",
"appearance": "Зовнішній вигляд", "appearance": "Зовнішній вигляд",
"user": "Користувач" "user": "Користувач",
"install": "Встановлення"
}, },
"goals": { "goals": {
"title": "Цілі", "title": "Цілі",