feat(ui): Beta-Badge in Login-, Dashboard- und Logbuch-Titelzeile

Wiederverwendbare BetaBadge-Komponente mit i18n-Tooltip.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-30 15:10:11 +02:00
co-authored by Cursor
parent 1524321afd
commit c2d620025e
7 changed files with 70 additions and 5 deletions
+33 -1
View File
@@ -63,6 +63,16 @@ body {
margin-bottom: 15px; margin-bottom: 15px;
} }
.auth-brand-title-row {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
gap: 10px;
margin-bottom: 14px;
}
.auth-brand-title-row h1,
.auth-brand h1 { .auth-brand h1 {
font-size: 32px; font-size: 32px;
font-weight: 700; font-weight: 700;
@@ -71,7 +81,7 @@ body {
-webkit-background-clip: text; -webkit-background-clip: text;
background-clip: text; background-clip: text;
-webkit-text-fill-color: transparent; -webkit-text-fill-color: transparent;
margin: 0 0 14px 0; margin: 0;
line-height: 1.25; line-height: 1.25;
letter-spacing: -0.5px; letter-spacing: -0.5px;
} }
@@ -3191,6 +3201,28 @@ html.theme-cupertino .events-scroll-container {
border: 1px solid rgba(251, 191, 36, 0.25); border: 1px solid rgba(251, 191, 36, 0.25);
} }
.beta-badge {
display: inline-flex;
align-items: center;
padding: 2px 8px;
border-radius: 999px;
font-size: 11px;
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--app-accent-light);
background: var(--app-accent-bg);
border: 1px solid var(--app-accent-focus-ring);
flex-shrink: 0;
}
.header-brand-title-row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 10px;
}
.role-badge { .role-badge {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
+2
View File
@@ -28,6 +28,7 @@ import PwaInstallPrompt from './components/PwaInstallPrompt.tsx'
import PwaUpdatePrompt from './components/PwaUpdatePrompt.tsx' import PwaUpdatePrompt from './components/PwaUpdatePrompt.tsx'
import AppFooter from './components/AppFooter.tsx' import AppFooter from './components/AppFooter.tsx'
import LogbookRoleBadge from './components/LogbookRoleBadge.tsx' import LogbookRoleBadge from './components/LogbookRoleBadge.tsx'
import BetaBadge from './components/BetaBadge.tsx'
import { db } from './services/db.js' import { db } from './services/db.js'
import { getLogbookAccess } from './services/logbookAccess.js' import { getLogbookAccess } from './services/logbookAccess.js'
import type { LogbookAccessRole } from './services/logbook.js' import type { LogbookAccessRole } from './services/logbook.js'
@@ -452,6 +453,7 @@ function App() {
<div className="app-title-area"> <div className="app-title-area">
<div className="app-title-row"> <div className="app-title-row">
<h2>{activeLogbookTitle}</h2> <h2>{activeLogbookTitle}</h2>
<BetaBadge />
{activeAccessRole && activeAccessRole !== 'OWNER' && ( {activeAccessRole && activeAccessRole !== 'OWNER' && (
<LogbookRoleBadge role={activeAccessRole} /> <LogbookRoleBadge role={activeAccessRole} />
)} )}
+5 -1
View File
@@ -13,6 +13,7 @@ import {
} from '../services/auth.js' } from '../services/auth.js'
import { KeyRound, ShieldAlert, Languages, HelpCircle, UserRound, X } from 'lucide-react' import { KeyRound, ShieldAlert, Languages, HelpCircle, UserRound, X } from 'lucide-react'
import RegistrationDisclaimer from './RegistrationDisclaimer.tsx' import RegistrationDisclaimer from './RegistrationDisclaimer.tsx'
import BetaBadge from './BetaBadge.tsx'
interface AuthOnboardingProps { interface AuthOnboardingProps {
onAuthenticated: () => void onAuthenticated: () => void
@@ -408,7 +409,10 @@ export default function AuthOnboarding({ onAuthenticated, onOpenDemo }: AuthOnbo
<div className="auth-card glass"> <div className="auth-card glass">
<div className="auth-brand"> <div className="auth-brand">
<img src="/logo.png" alt="Kapteins Daagbok" className="auth-logo-img" /> <img src="/logo.png" alt="Kapteins Daagbok" className="auth-logo-img" />
<h1>{t('app.name')}</h1> <div className="auth-brand-title-row">
<h1>{t('app.name')}</h1>
<BetaBadge />
</div>
<p className="tagline">{t('auth.tagline')}</p> <p className="tagline">{t('auth.tagline')}</p>
</div> </div>
+19
View File
@@ -0,0 +1,19 @@
import { useTranslation } from 'react-i18next'
interface BetaBadgeProps {
className?: string
}
export default function BetaBadge({ className = '' }: BetaBadgeProps) {
const { t } = useTranslation()
return (
<span
className={`beta-badge ${className}`.trim()}
title={t('app.beta_hint')}
aria-label={t('app.beta_hint')}
>
{t('app.beta')}
</span>
)
}
+5 -1
View File
@@ -4,6 +4,7 @@ import { useLiveQuery } from 'dexie-react-hooks'
import { db } from '../services/db.js' import { db } from '../services/db.js'
import { fetchLogbooks, createLogbook, deleteLogbook, type DecryptedLogbook } from '../services/logbook.js' import { fetchLogbooks, createLogbook, deleteLogbook, type DecryptedLogbook } from '../services/logbook.js'
import LogbookRoleBadge from './LogbookRoleBadge.tsx' import LogbookRoleBadge from './LogbookRoleBadge.tsx'
import BetaBadge from './BetaBadge.tsx'
import { PlausibleEvents, trackPlausibleEvent } from '../services/analytics.js' import { PlausibleEvents, trackPlausibleEvent } from '../services/analytics.js'
import { logoutUser } from '../services/auth.js' import { logoutUser } from '../services/auth.js'
import { useDialog } from './ModalDialog.tsx' import { useDialog } from './ModalDialog.tsx'
@@ -177,7 +178,10 @@ export default function LogbookDashboard({ onSelectLogbook, onLogout }: LogbookD
<div className="header-brand"> <div className="header-brand">
<Ship className="header-logo" size={32} /> <Ship className="header-logo" size={32} />
<div> <div>
<h1>{t('app.name')}</h1> <div className="header-brand-title-row">
<h1>{t('app.name')}</h1>
<BetaBadge />
</div>
<p className="subtitle">{t('app.tagline')}</p> <p className="subtitle">{t('app.tagline')}</p>
</div> </div>
</div> </div>
+3 -1
View File
@@ -2,7 +2,9 @@
"translation": { "translation": {
"app": { "app": {
"name": "Kapteins Daagbok", "name": "Kapteins Daagbok",
"tagline": "Privates Yacht-Logbuch" "tagline": "Privates Yacht-Logbuch",
"beta": "Beta",
"beta_hint": "Beta-Version — Funktionen können sich noch ändern"
}, },
"nav": { "nav": {
"dashboard": "Dashboard", "dashboard": "Dashboard",
+3 -1
View File
@@ -2,7 +2,9 @@
"translation": { "translation": {
"app": { "app": {
"name": "Kapteins Daagbok", "name": "Kapteins Daagbok",
"tagline": "Private Yacht Logbook" "tagline": "Private Yacht Logbook",
"beta": "Beta",
"beta_hint": "Beta release — features may still change"
}, },
"nav": { "nav": {
"dashboard": "Dashboard", "dashboard": "Dashboard",