fix(ui): improve Export/Import section layout (#24)

* fix(ui): improve Export/Import section layout and styling

- Redesign as two-column card layout with icons
- Remove CAPSLOCK from labels
- Add proper descriptions for export and import sections
- Improve checkbox and button styling
- Make responsive for mobile

* fix(ui): clean up Export/Import section design

- Remove ugly folder icons
- Replace hint text box with info tooltip on title
- Cleaner h3 styling with uppercase letters
- Better visual hierarchy
This commit is contained in:
Daniel Volz
2026-01-16 20:32:39 +01:00
committed by GitHub
parent 9cfbf89d46
commit 4081e03970
4 changed files with 127 additions and 34 deletions
+17 -26
View File
@@ -2412,15 +2412,18 @@ function AppContent() {
{/* Export/Import Section */}
<article className="card">
<div className="card-head">
<h2>{t('exportImport.title')}</h2>
<h2>
{t('exportImport.title')}
<span className="info-tooltip" data-tooltip={t('exportImport.description')}></span>
</h2>
</div>
<div className="setting-section">
<p className="hint-text" style={{marginBottom: "16px"}}>{t('exportImport.description')}</p>
{/* Export */}
<div className="setting-group" style={{marginBottom: "24px"}}>
<div className="export-controls">
<label className="checkbox-label" style={{marginBottom: "12px", display: "flex", alignItems: "center", gap: "8px"}}>
<div className="export-import-grid">
{/* Export */}
<div className="export-import-card">
<h3>{t('exportImport.exportTitle')}</h3>
<p className="export-import-desc">{t('exportImport.exportDesc')}</p>
<label className="export-import-checkbox">
<input
type="checkbox"
checked={includeSensitiveData}
@@ -2429,7 +2432,7 @@ function AppContent() {
<span>{t('exportImport.includeSensitive')}</span>
</label>
{includeSensitiveData && (
<p className="hint-text warning-text" style={{marginBottom: "12px", color: "var(--warning)", fontSize: "0.85rem"}}>
<p className="export-import-warning">
{t('exportImport.sensitiveWarning')}
</p>
)}
@@ -2438,34 +2441,22 @@ function AppContent() {
className="secondary"
onClick={handleExport}
disabled={exporting}
style={{marginRight: "12px"}}
>
{exporting ? t('exportImport.exporting') : t('exportImport.export')}
</button>
</div>
</div>
{/* Import */}
<div className="setting-group">
<div className="import-controls">
<label className="secondary" style={{
cursor: "pointer",
display: "inline-block",
padding: "0.7rem 1.25rem",
borderRadius: "var(--btn-radius)",
background: "var(--bg-tertiary)",
color: "var(--text-primary)",
border: "1px solid var(--border-secondary)",
fontWeight: 600,
fontSize: "0.9rem"
}}>
{/* Import */}
<div className="export-import-card">
<h3>{t('exportImport.importTitle')}</h3>
<p className="export-import-desc">{t('exportImport.importDesc')}</p>
<label className="export-import-file-btn">
{importing ? t('exportImport.importing') : t('exportImport.import')}
<input
type="file"
accept=".json,application/json"
onChange={handleImportFileSelect}
disabled={importing}
style={{display: "none"}}
/>
</label>
</div>
+8 -4
View File
@@ -351,14 +351,18 @@
},
"exportImport": {
"title": "Daten Export / Import",
"description": "Exportiere deine Daten zur Sicherung oder Übertragung auf ein anderes Gerät. Import ersetzt ALLE deine bestehenden Daten.",
"description": "Sichere deine Daten oder übertrage sie auf ein anderes Gerät.",
"exportTitle": "Export",
"exportDesc": "Lade alle deine Daten als JSON-Datei herunter.",
"importTitle": "Import",
"importDesc": "Stelle Daten aus einer Sicherung wieder her. Dies ersetzt alle bestehenden Daten.",
"export": "Daten exportieren",
"exporting": "Exportiere...",
"import": "Daten importieren",
"import": "Datei auswählen",
"importing": "Importiere...",
"selectFile": "Datei auswählen",
"includeSensitive": "Sensible Daten einschließen",
"sensitiveWarning": "Warnung: Dies fügt Benachrichtigungs-URLs (können Passwörter enthalten) im Klartext in die Exportdatei ein.",
"includeSensitive": "Sensible Daten einschließen (Benachrichtigungs-URLs)",
"sensitiveWarning": "Benachrichtigungs-URLs können Passwörter enthalten und werden im Klartext gespeichert.",
"confirmImport": "Alle Daten ersetzen?",
"confirmImportMessage": "Dies löscht dauerhaft alle deine aktuellen Medikamente, Einnahmehistorie, Einstellungen und Teilen-Links und ersetzt sie durch die importierten Daten.",
"confirmImportWarning": "Diese Aktion kann nicht rückgängig gemacht werden!",
+8 -4
View File
@@ -353,14 +353,18 @@
},
"exportImport": {
"title": "Data Export / Import",
"description": "Export your data for backup or transfer to another device. Import will replace ALL your existing data.",
"description": "Backup your data or transfer it to another device.",
"exportTitle": "Export",
"exportDesc": "Download all your data as a JSON file.",
"importTitle": "Import",
"importDesc": "Restore data from a backup file. This will replace all existing data.",
"export": "Export Data",
"exporting": "Exporting...",
"import": "Import Data",
"import": "Select File",
"importing": "Importing...",
"selectFile": "Select File",
"includeSensitive": "Include sensitive data",
"sensitiveWarning": "Warning: This will include notification URLs (may contain passwords) in plain text in the export file.",
"includeSensitive": "Include sensitive data (notification URLs)",
"sensitiveWarning": "Notification URLs may contain passwords and will be stored in plain text.",
"confirmImport": "Replace All Data?",
"confirmImportMessage": "This will permanently delete all your current medications, dose history, settings, and share links, then replace them with the imported data.",
"confirmImportWarning": "This action cannot be undone!",
+94
View File
@@ -3977,3 +3977,97 @@ h3 .reminder-icon.info-tooltip {
margin-top: 0.5rem;
width: 100%;
}
/* Export/Import Section */
.export-import-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1.5rem;
}
@media (max-width: 640px) {
.export-import-grid {
grid-template-columns: 1fr;
}
}
.export-import-card {
background: var(--bg-tertiary);
border: 1px solid var(--border-secondary);
border-radius: var(--card-radius);
padding: 1.5rem;
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.export-import-card h3 {
margin: 0;
font-size: 1rem;
font-weight: 600;
color: var(--text-primary);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.export-import-desc {
color: var(--text-secondary);
font-size: 0.85rem;
margin: 0;
line-height: 1.5;
flex: 1;
}
.export-import-checkbox {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.85rem;
color: var(--text-secondary);
cursor: pointer;
text-transform: none !important;
}
.export-import-checkbox input[type="checkbox"] {
width: 16px;
height: 16px;
cursor: pointer;
}
.export-import-warning {
font-size: 0.8rem;
color: var(--warning);
margin: 0;
padding: 0.5rem;
background: rgba(234, 179, 8, 0.1);
border-radius: 4px;
line-height: 1.4;
}
.export-import-card button,
.export-import-file-btn {
margin-top: auto;
align-self: flex-start;
}
.export-import-file-btn {
cursor: pointer;
display: inline-block;
padding: 0.7rem 1.25rem;
border-radius: var(--btn-radius);
background: var(--bg-secondary);
color: var(--text-primary);
border: 1px solid var(--border-secondary);
font-weight: 600;
font-size: 0.9rem;
transition: all 0.2s ease;
}
.export-import-file-btn:hover {
background: var(--bg-hover);
border-color: var(--border-primary);
}
.export-import-file-btn input {
display: none;
}