Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a67575f4d2 | |||
| c2d620025e | |||
| 1524321afd | |||
| ab8a188fa0 | |||
| bb98af040e | |||
| 333c36db21 | |||
| 3bd1970c59 | |||
| 75c1369c75 | |||
| 9ce1e384b7 | |||
| 3eee42a30c | |||
| 90ffff0da6 |
+33
-1
@@ -63,6 +63,16 @@ body {
|
||||
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 {
|
||||
font-size: 32px;
|
||||
font-weight: 700;
|
||||
@@ -71,7 +81,7 @@ body {
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
margin: 0 0 14px 0;
|
||||
margin: 0;
|
||||
line-height: 1.25;
|
||||
letter-spacing: -0.5px;
|
||||
}
|
||||
@@ -3191,6 +3201,28 @@ html.theme-cupertino .events-scroll-container {
|
||||
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 {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -28,6 +28,7 @@ import PwaInstallPrompt from './components/PwaInstallPrompt.tsx'
|
||||
import PwaUpdatePrompt from './components/PwaUpdatePrompt.tsx'
|
||||
import AppFooter from './components/AppFooter.tsx'
|
||||
import LogbookRoleBadge from './components/LogbookRoleBadge.tsx'
|
||||
import BetaBadge from './components/BetaBadge.tsx'
|
||||
import { db } from './services/db.js'
|
||||
import { getLogbookAccess } from './services/logbookAccess.js'
|
||||
import type { LogbookAccessRole } from './services/logbook.js'
|
||||
@@ -452,6 +453,7 @@ function App() {
|
||||
<div className="app-title-area">
|
||||
<div className="app-title-row">
|
||||
<h2>{activeLogbookTitle}</h2>
|
||||
<BetaBadge />
|
||||
{activeAccessRole && activeAccessRole !== 'OWNER' && (
|
||||
<LogbookRoleBadge role={activeAccessRole} />
|
||||
)}
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
} from '../services/auth.js'
|
||||
import { KeyRound, ShieldAlert, Languages, HelpCircle, UserRound, X } from 'lucide-react'
|
||||
import RegistrationDisclaimer from './RegistrationDisclaimer.tsx'
|
||||
import BetaBadge from './BetaBadge.tsx'
|
||||
|
||||
interface AuthOnboardingProps {
|
||||
onAuthenticated: () => void
|
||||
@@ -408,7 +409,10 @@ export default function AuthOnboarding({ onAuthenticated, onOpenDemo }: AuthOnbo
|
||||
<div className="auth-card glass">
|
||||
<div className="auth-brand">
|
||||
<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>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import { useLiveQuery } from 'dexie-react-hooks'
|
||||
import { db } from '../services/db.js'
|
||||
import { fetchLogbooks, createLogbook, deleteLogbook, type DecryptedLogbook } from '../services/logbook.js'
|
||||
import LogbookRoleBadge from './LogbookRoleBadge.tsx'
|
||||
import BetaBadge from './BetaBadge.tsx'
|
||||
import { PlausibleEvents, trackPlausibleEvent } from '../services/analytics.js'
|
||||
import { logoutUser } from '../services/auth.js'
|
||||
import { useDialog } from './ModalDialog.tsx'
|
||||
@@ -177,7 +178,10 @@ export default function LogbookDashboard({ onSelectLogbook, onLogout }: LogbookD
|
||||
<div className="header-brand">
|
||||
<Ship className="header-logo" size={32} />
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { decryptJson } from '../services/crypto.js'
|
||||
import { PlausibleEvents, trackPlausibleEvent } from '../services/analytics.js'
|
||||
import VesselForm from './VesselForm.tsx'
|
||||
import CrewForm from './CrewForm.tsx'
|
||||
import LogEntriesList from './LogEntriesList.tsx'
|
||||
@@ -124,6 +125,7 @@ export default function ReadOnlyViewer({ token, hexKey }: ReadOnlyViewerProps) {
|
||||
}
|
||||
}
|
||||
setGpsTracks(decGpsTracks)
|
||||
trackPlausibleEvent(PlausibleEvents.PUBLIC_LINK_OPENED)
|
||||
|
||||
} catch (err: any) {
|
||||
console.error(err)
|
||||
|
||||
@@ -111,6 +111,7 @@ export default function SettingsForm({ logbookId, onLogbookRestored }: SettingsF
|
||||
const logbookKey = await ensureLogbookKey(logbookId)
|
||||
const hexKey = bufferToHex(logbookKey)
|
||||
setShareLink(`${window.location.origin}/share?token=${data.token}#key=${hexKey}`)
|
||||
trackPlausibleEvent(PlausibleEvents.LOGBOOK_SHARED)
|
||||
showAlert('Public share link enabled!')
|
||||
} else {
|
||||
setShareEnabled(false)
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
"translation": {
|
||||
"app": {
|
||||
"name": "Kapteins Daagbok",
|
||||
"tagline": "Privates Yacht-Logbuch"
|
||||
"tagline": "Privates Yacht-Logbuch",
|
||||
"beta": "Beta",
|
||||
"beta_hint": "Beta-Version — Funktionen können sich noch ändern"
|
||||
},
|
||||
"nav": {
|
||||
"dashboard": "Dashboard",
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
"translation": {
|
||||
"app": {
|
||||
"name": "Kapteins Daagbok",
|
||||
"tagline": "Private Yacht Logbook"
|
||||
"tagline": "Private Yacht Logbook",
|
||||
"beta": "Beta",
|
||||
"beta_hint": "Beta release — features may still change"
|
||||
},
|
||||
"nav": {
|
||||
"dashboard": "Dashboard",
|
||||
|
||||
@@ -14,6 +14,8 @@ export const PlausibleEvents = {
|
||||
ONBOARDING_TOUR_SKIPPED: 'Onboarding Tour Skipped',
|
||||
INVITE_GENERATED: 'Invite Generated',
|
||||
INVITE_ACCEPTED: 'Invite Accepted',
|
||||
LOGBOOK_SHARED: 'Logbook Shared',
|
||||
PUBLIC_LINK_OPENED: 'Public Link Opened',
|
||||
PDF_EXPORTED: 'PDF Exported',
|
||||
CSV_EXPORTED: 'CSV Exported',
|
||||
CSV_SHARED: 'CSV Shared',
|
||||
|
||||
@@ -242,20 +242,24 @@
|
||||
</header>
|
||||
|
||||
<p class="intro">
|
||||
Führe dein Bordlogbuch digital: Reisetage, GPS-Tracks, Crew und Schiffsdaten —
|
||||
<strong>End-to-End-verschlüsselt</strong>, als App installierbar und
|
||||
Führe dein Bordlogbuch digital: Reisetage, GPS-Tracks, Crew- und Schiffsdaten —
|
||||
<strong>Ende-zu-Ende-verschlüsselt</strong>, als App installierbar und
|
||||
<strong>auch offline</strong> auf See nutzbar.
|
||||
</p>
|
||||
|
||||
<section class="features" aria-label="Funktionen">
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Reisetage im nautischen Logbuch-Format (Hafen, Wetter, Tankstände)</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Offline-fähige PWA — installierbar auf Smartphone & Tablet</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Passkey-Anmeldung & clientseitige Verschlüsselung</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>GPS-Tracks (GPX/KML), Karte & Streckenstatistik</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Reisetage im nautischen Logbuch-Format (Hafen, Wetter, Besegelung, Crew, Tankstände, etc.)</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Offline-fähige PWA — läuft auf jedem Smartphone & Tablet</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Passwortlose Passkey-Anmeldung & Ende-zu-Ende Verschlüsselung</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>GPS-Track Upload (GPX/KML), Karte & Streckenstatistik</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Foto-Anhänge pro Reisetag</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Crew einladen — gemeinsam am Logbuch arbeiten</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>PDF- & CSV-Export, verschlüsseltes Backup</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Mehrere Logbücher · Deutsch & Englisch</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>PDF- & CSV-Export</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Verschlüsseltes Backup & Wiederherstellung</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Logbuch mit Freunden teilen</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Beliebig viele Schiffe und Logbücher</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Deutsch & Englisch</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Crafted in Kiel.Sailing.City.</span></div>
|
||||
</section>
|
||||
|
||||
<section class="beta-box">
|
||||
|
||||
Binary file not shown.
@@ -29,6 +29,8 @@ Kapteins Daagbok nutzt [Plausible Analytics](https://plausible.io/) mit dem Scri
|
||||
| Demo Opened | Public-Demo unter `/demo` geöffnet (`DemoViewer.tsx`) | — |
|
||||
| Invite Generated | Einladungslink erzeugt (`SettingsForm.tsx`) | — |
|
||||
| Invite Accepted | Einladung angenommen und Logbuch beigetreten (`InvitationAcceptance.tsx`) | — |
|
||||
| Logbook Shared | Öffentlicher Freigabelink aktiviert (`SettingsForm.tsx`) | — |
|
||||
| Public Link Opened | Freigabelink unter `/share` erfolgreich geladen (`ReadOnlyViewer.tsx`) | — |
|
||||
| PDF Exported | PDF-Export eines Reisetags (`LogEntryEditor.tsx`, `LogEntriesList.tsx`) | `scope`: `entry` |
|
||||
| CSV Exported | CSV-Download aus der Eintragsliste (`LogEntriesList.tsx`) | — |
|
||||
| CSV Shared | CSV über Web Share API geteilt (`LogEntriesList.tsx`) | — |
|
||||
@@ -52,8 +54,9 @@ Empfohlene Goal-Ketten für Auswertung:
|
||||
1. **Aktivierung:** Account Created → Logbook Created → Travel Day Created → Travel Day Saved
|
||||
2. **Onboarding:** Account Created → Onboarding Tour Completed (vs. Onboarding Tour Skipped)
|
||||
3. **Kollaboration:** Invite Generated → Invite Accepted
|
||||
4. **Export:** Travel Day Saved → PDF Exported / CSV Exported
|
||||
5. **Datensicherung:** Backup Exported → Backup Restored
|
||||
4. **Öffentliche Freigabe:** Logbook Shared → Public Link Opened
|
||||
5. **Export:** Travel Day Saved → PDF Exported / CSV Exported
|
||||
6. **Datensicherung:** Backup Exported → Backup Restored
|
||||
|
||||
## Entwicklung
|
||||
|
||||
|
||||
Reference in New Issue
Block a user