fix: Login zentrieren und CSV-Unterschrift-Platzhalter übersetzen

Auth-Screens werden per auth-screen über die volle Viewport-Höhe zentriert.
Bild-Unterschriften im CSV-Export nutzen i18n statt festem deutschen Text.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-29 16:18:01 +02:00
parent 7d28b5745a
commit 5706d1762d
6 changed files with 31 additions and 9 deletions
+18 -3
View File
@@ -4,12 +4,27 @@ body {
background: radial-gradient(circle at center, #1b264f 0%, #0b0c10 100%);
min-height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
font-family: system-ui, -apple-system, sans-serif;
}
#root:has(.auth-screen) {
width: 100%;
max-width: none;
border-inline: none;
text-align: initial;
}
.auth-screen {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
min-height: 100svh;
padding: 24px 16px calc(48px + env(safe-area-inset-bottom, 0px));
box-sizing: border-box;
}
/* Glassmorphism Auth Card */
.auth-card {
background: rgba(11, 12, 16, 0.75);
+2 -2
View File
@@ -166,7 +166,7 @@ function App() {
if (isAcceptingInvite) {
return (
<div className={`theme-${appliedTheme}`} style={{ display: 'contents' }}>
<div className={`theme-${appliedTheme} auth-screen`}>
<InvitationAcceptance
onAccepted={(logbookId, title) => {
setIsAuthenticated(true)
@@ -186,7 +186,7 @@ function App() {
if (!isAuthenticated) {
return (
<div className={`theme-${appliedTheme}`} style={{ display: 'contents' }}>
<div className={`theme-${appliedTheme} auth-screen`}>
<AuthOnboarding onAuthenticated={handleAuthenticated} />
</div>
)
+1
View File
@@ -117,6 +117,7 @@
"sign_crew": "Crew-Unterschrift",
"sign_hint": "Mit Finger, Stift oder Maus unterschreiben",
"sign_clear": "Löschen",
"sign_export_image": "[Unterschrift]",
"no_entries": "Keine Logbucheinträge für diese Yacht gefunden. Erstellen Sie Ihren ersten Reisetag!",
"back_to_list": "Zurück zur Journal-Liste",
"save": "Logbuchseite speichern",
+1
View File
@@ -117,6 +117,7 @@
"sign_crew": "Crew signature",
"sign_hint": "Sign with finger, stylus, or mouse",
"sign_clear": "Clear",
"sign_export_image": "[Signature]",
"no_entries": "No logbook entries found for this yacht. Create your first travel day to begin!",
"back_to_list": "Back to Journal List",
"save": "Save Logbook Page",
+4 -2
View File
@@ -3,6 +3,7 @@ import { getActiveMasterKey } from './auth.js'
import { getLogbookKey } from './logbookKeys.js'
import { decryptJson } from './crypto.js'
import { formatSignatureForExport } from '../utils/signatures.js'
import i18n from '../i18n/index.js'
function escapeCsvValue(val: string | number | undefined | null): string {
if (val === null || val === undefined) return '';
@@ -89,14 +90,15 @@ export async function exportLogbookToCsv(logbookId: string, preloadedData?: { ya
];
const rows: string[][] = [headers];
const signaturePlaceholder = i18n.t('logs.sign_export_image');
for (const entry of decryptedEntries) {
const dateVal = entry.date || '';
const travelDay = entry.dayOfTravel || '';
const dep = entry.departure || '';
const dest = entry.destination || '';
const signS = formatSignatureForExport(entry.signSkipper);
const signC = formatSignatureForExport(entry.signCrew);
const signS = formatSignatureForExport(entry.signSkipper, signaturePlaceholder);
const signC = formatSignatureForExport(entry.signCrew, signaturePlaceholder);
const trackDist = entry.trackDistanceNm ?? '';
const trackMax = entry.trackSpeedMaxKn ?? '';
const trackAvg = entry.trackSpeedAvgKn ?? '';
+5 -2
View File
@@ -2,8 +2,11 @@ export function isSignatureImage(value: string | undefined | null): boolean {
return typeof value === 'string' && value.startsWith('data:image/')
}
export function formatSignatureForExport(value: string | undefined | null): string {
export function formatSignatureForExport(
value: string | undefined | null,
imagePlaceholder: string
): string {
if (!value) return ''
if (isSignatureImage(value)) return '[Unterschrift]'
if (isSignatureImage(value)) return imagePlaceholder
return value
}