feat: Light Mode mit System-Erkennung und konfigurierbarem Erscheinungsbild.
Stellt hell/dunkel für Ocean, Material und Cupertino bereit, migriert die Kern-UI auf CSS-Variablen und ergänzt die Einstellungen inkl. i18n und Select-Kontrast. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+168
-332
@@ -1,10 +1,11 @@
|
||||
/* Kapteins Daagbok App styling */
|
||||
|
||||
body {
|
||||
background: radial-gradient(circle at center, #1b264f 0%, #0b0c10 100%);
|
||||
background: var(--app-body-bg);
|
||||
min-height: 100vh;
|
||||
margin: 0;
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
color: var(--app-text);
|
||||
}
|
||||
|
||||
#root:has(.auth-screen) {
|
||||
@@ -27,15 +28,15 @@ body {
|
||||
|
||||
/* Glassmorphism Auth Card */
|
||||
.auth-card {
|
||||
background: rgba(11, 12, 16, 0.75);
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(212, 175, 55, 0.25);
|
||||
border-radius: 20px;
|
||||
background: var(--app-surface);
|
||||
backdrop-filter: var(--app-backdrop);
|
||||
-webkit-backdrop-filter: var(--app-backdrop);
|
||||
border: 1px solid var(--app-border);
|
||||
border-radius: var(--app-radius-card);
|
||||
padding: 40px;
|
||||
width: 450px;
|
||||
max-width: 90%;
|
||||
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.6), inset 0 0 0 1px rgba(255, 255, 255, 0.05);
|
||||
box-shadow: var(--app-shadow);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
@@ -65,8 +66,8 @@ body {
|
||||
.auth-brand h1 {
|
||||
font-size: 32px;
|
||||
font-weight: 700;
|
||||
color: #f8fafc;
|
||||
background: linear-gradient(135deg, #fef08a 0%, #d97706 100%);
|
||||
color: var(--app-text-heading);
|
||||
background: var(--app-accent-gradient);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
@@ -77,7 +78,7 @@ body {
|
||||
|
||||
.auth-brand .tagline {
|
||||
font-size: 14.5px;
|
||||
color: #94a3b8;
|
||||
color: var(--app-text-muted);
|
||||
margin: 0;
|
||||
line-height: 1.45;
|
||||
}
|
||||
@@ -96,31 +97,41 @@ body {
|
||||
|
||||
.input-text {
|
||||
width: 100%;
|
||||
background: rgba(11, 12, 16, 0.85);
|
||||
border: 1px solid rgba(148, 163, 184, 0.25);
|
||||
border-radius: 10px;
|
||||
background: var(--app-input-bg);
|
||||
border: 1px solid var(--app-input-border);
|
||||
border-radius: var(--app-radius-input);
|
||||
padding: 14px 16px;
|
||||
font-size: 16px;
|
||||
color: #f1f5f9;
|
||||
color: var(--app-input-text);
|
||||
outline: none;
|
||||
box-sizing: border-box;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.input-text:focus {
|
||||
border-color: #d97706;
|
||||
box-shadow: 0 0 0 3px rgba(217, 119, 6, 0.2);
|
||||
background: #0b0c10;
|
||||
border-color: var(--app-accent);
|
||||
box-shadow: 0 0 0 3px var(--app-accent-focus-ring);
|
||||
background: var(--app-input-bg-focus);
|
||||
}
|
||||
|
||||
select.input-text {
|
||||
color-scheme: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
select.input-text option {
|
||||
background-color: var(--app-input-bg);
|
||||
color: var(--app-input-text);
|
||||
}
|
||||
|
||||
.input-textarea {
|
||||
width: 100%;
|
||||
background: rgba(11, 12, 16, 0.85);
|
||||
border: 1px solid rgba(148, 163, 184, 0.25);
|
||||
border-radius: 10px;
|
||||
background: var(--app-input-bg);
|
||||
border: 1px solid var(--app-input-border);
|
||||
border-radius: var(--app-radius-input);
|
||||
padding: 14px;
|
||||
font-size: 15px;
|
||||
color: #f1f5f9;
|
||||
color: var(--app-input-text);
|
||||
outline: none;
|
||||
box-sizing: border-box;
|
||||
resize: none;
|
||||
@@ -129,9 +140,9 @@ body {
|
||||
}
|
||||
|
||||
.input-textarea:focus {
|
||||
border-color: #d97706;
|
||||
box-shadow: 0 0 0 3px rgba(217, 119, 6, 0.2);
|
||||
background: #0b0c10;
|
||||
border-color: var(--app-accent);
|
||||
box-shadow: 0 0 0 3px var(--app-accent-focus-ring);
|
||||
background: var(--app-input-bg-focus);
|
||||
}
|
||||
|
||||
.auth-submit-actions {
|
||||
@@ -148,7 +159,7 @@ body {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
border-radius: var(--app-radius-btn);
|
||||
cursor: pointer;
|
||||
transition: all 0.25s ease;
|
||||
display: flex;
|
||||
@@ -158,14 +169,15 @@ body {
|
||||
}
|
||||
|
||||
.btn.primary {
|
||||
background: linear-gradient(135deg, #fbbf24 0%, #d97706 100%);
|
||||
color: #0b0c10;
|
||||
box-shadow: 0 4px 15px rgba(217, 119, 6, 0.3);
|
||||
background-color: var(--app-accent);
|
||||
background-image: var(--app-accent-gradient);
|
||||
color: var(--app-btn-primary-text);
|
||||
box-shadow: 0 4px 15px var(--app-accent-focus-ring);
|
||||
}
|
||||
|
||||
.btn.primary:hover:not(:disabled) {
|
||||
transform: translateY(-1.5px);
|
||||
box-shadow: 0 6px 20px rgba(217, 119, 6, 0.45);
|
||||
filter: brightness(1.05);
|
||||
}
|
||||
|
||||
.btn.primary:active:not(:disabled) {
|
||||
@@ -173,14 +185,13 @@ body {
|
||||
}
|
||||
|
||||
.btn.secondary {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
color: #e2e8f0;
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
background: var(--app-btn-secondary-bg);
|
||||
color: var(--app-btn-secondary-text);
|
||||
border: 1px solid var(--app-btn-secondary-border);
|
||||
}
|
||||
|
||||
.btn.secondary:hover:not(:disabled) {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
color: #ffffff;
|
||||
background: var(--app-btn-secondary-hover-bg);
|
||||
}
|
||||
|
||||
.btn:disabled {
|
||||
@@ -213,15 +224,15 @@ body {
|
||||
.auth-card h2 {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #f8fafc;
|
||||
color: var(--app-text-heading);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.recovery-warning {
|
||||
font-size: 13.5px;
|
||||
color: #f43f5e;
|
||||
background: rgba(244, 63, 94, 0.08);
|
||||
border: 1px solid rgba(244, 63, 94, 0.2);
|
||||
color: var(--app-warning-text);
|
||||
background: var(--app-warning-bg);
|
||||
border: 1px solid var(--app-warning-border);
|
||||
border-radius: 8px;
|
||||
padding: 12px 14px;
|
||||
line-height: 145%;
|
||||
@@ -238,18 +249,18 @@ body {
|
||||
}
|
||||
|
||||
.phrase-word {
|
||||
background: rgba(11, 12, 16, 0.9);
|
||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||
background: var(--app-input-bg);
|
||||
border: 1px solid var(--app-border-subtle);
|
||||
border-radius: 6px;
|
||||
padding: 12px 8px;
|
||||
font-size: 14.5px;
|
||||
color: #f1f5f9;
|
||||
color: var(--app-text);
|
||||
text-align: center;
|
||||
font-family: ui-monospace, monospace;
|
||||
}
|
||||
|
||||
.word-num {
|
||||
color: #d97706;
|
||||
color: var(--app-accent);
|
||||
font-size: 11px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
@@ -262,9 +273,9 @@ body {
|
||||
|
||||
.auth-error {
|
||||
width: 100%;
|
||||
background: rgba(244, 63, 94, 0.08);
|
||||
color: #fda4af;
|
||||
border-left: 3px solid #f43f5e;
|
||||
background: var(--app-error-bg);
|
||||
color: var(--app-error-text);
|
||||
border-left: 3px solid var(--app-error-border);
|
||||
padding: 10px 12px;
|
||||
font-size: 14px;
|
||||
border-radius: 4px;
|
||||
@@ -275,7 +286,7 @@ body {
|
||||
.auth-footer {
|
||||
margin-top: 30px;
|
||||
width: 100%;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.06);
|
||||
border-top: 1px solid var(--app-divider);
|
||||
padding-top: 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -285,7 +296,7 @@ body {
|
||||
.btn-icon-text {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #94a3b8;
|
||||
color: var(--app-text-muted);
|
||||
font-size: 13.5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -298,16 +309,16 @@ body {
|
||||
}
|
||||
|
||||
.btn-icon-text:hover {
|
||||
color: #d97706;
|
||||
background: rgba(217, 119, 6, 0.06);
|
||||
color: var(--app-accent);
|
||||
background: var(--app-accent-bg);
|
||||
}
|
||||
|
||||
.btn-icon-text.link-sec {
|
||||
color: #4b5563;
|
||||
color: var(--app-text-subtle);
|
||||
}
|
||||
|
||||
.btn-icon-text.link-sec:hover {
|
||||
color: #9ca3af;
|
||||
color: var(--app-text-muted);
|
||||
}
|
||||
|
||||
/* Dashboard Mock Layout (for verified state) */
|
||||
@@ -346,7 +357,7 @@ body {
|
||||
flex-direction: column;
|
||||
padding: 24px;
|
||||
box-sizing: border-box;
|
||||
color: #f1f5f9;
|
||||
color: var(--app-text);
|
||||
}
|
||||
|
||||
.dashboard-header {
|
||||
@@ -355,7 +366,7 @@ body {
|
||||
align-items: center;
|
||||
margin-bottom: 32px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px solid rgba(212, 175, 55, 0.15);
|
||||
border-bottom: 1px solid var(--app-header-border);
|
||||
}
|
||||
|
||||
.header-brand {
|
||||
@@ -365,15 +376,15 @@ body {
|
||||
}
|
||||
|
||||
.header-logo {
|
||||
color: #fbbf24;
|
||||
filter: drop-shadow(0 0 8px rgba(251, 191, 36, 0.4));
|
||||
color: var(--app-accent-light);
|
||||
filter: drop-shadow(0 0 8px var(--app-accent-focus-ring));
|
||||
}
|
||||
|
||||
.header-brand h1 {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
margin: 0;
|
||||
background: linear-gradient(135deg, #fef08a 0%, #d97706 100%);
|
||||
background: var(--app-accent-gradient);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
@@ -381,7 +392,7 @@ body {
|
||||
|
||||
.header-brand .subtitle {
|
||||
font-size: 12px;
|
||||
color: #94a3b8;
|
||||
color: var(--app-text-muted);
|
||||
margin: 2px 0 0 0;
|
||||
}
|
||||
|
||||
@@ -420,15 +431,15 @@ body {
|
||||
font-size: 13px;
|
||||
padding: 6px 12px;
|
||||
border-radius: 20px;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
color: #e2e8f0;
|
||||
background: var(--app-btn-secondary-bg);
|
||||
border: 1px solid var(--app-btn-secondary-border);
|
||||
color: var(--app-btn-secondary-text);
|
||||
}
|
||||
|
||||
.btn-icon {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
color: #94a3b8;
|
||||
background: var(--app-icon-btn-bg);
|
||||
border: 1px solid var(--app-icon-btn-border);
|
||||
color: var(--app-text-muted);
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
@@ -440,9 +451,9 @@ body {
|
||||
}
|
||||
|
||||
.btn-icon:hover {
|
||||
background: rgba(217, 119, 6, 0.1);
|
||||
border-color: #d97706;
|
||||
color: #fbbf24;
|
||||
background: var(--app-accent-bg);
|
||||
border-color: var(--app-accent);
|
||||
color: var(--app-accent-light);
|
||||
}
|
||||
|
||||
.btn-icon.logout:hover {
|
||||
@@ -511,11 +522,11 @@ body {
|
||||
}
|
||||
|
||||
.create-section {
|
||||
background: rgba(11, 12, 16, 0.6);
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(212, 175, 55, 0.2);
|
||||
border-radius: 16px;
|
||||
background: var(--app-surface-alt);
|
||||
backdrop-filter: var(--app-backdrop);
|
||||
-webkit-backdrop-filter: var(--app-backdrop);
|
||||
border: 1px solid var(--app-border-muted);
|
||||
border-radius: var(--app-radius-card);
|
||||
padding: 24px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -524,7 +535,7 @@ body {
|
||||
font-size: 18px;
|
||||
margin-top: 0;
|
||||
margin-bottom: 20px;
|
||||
color: #f8fafc;
|
||||
color: var(--app-text-heading);
|
||||
}
|
||||
|
||||
.dashboard-form {
|
||||
@@ -574,13 +585,13 @@ body {
|
||||
.section-title-bar h2 {
|
||||
font-size: 20px;
|
||||
margin: 0;
|
||||
color: #f8fafc;
|
||||
color: var(--app-text-heading);
|
||||
}
|
||||
|
||||
.btn-refresh {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #94a3b8;
|
||||
color: var(--app-text-muted);
|
||||
cursor: pointer;
|
||||
padding: 6px;
|
||||
border-radius: 4px;
|
||||
@@ -591,7 +602,7 @@ body {
|
||||
}
|
||||
|
||||
.btn-refresh:hover {
|
||||
color: #fbbf24;
|
||||
color: var(--app-accent-light);
|
||||
}
|
||||
|
||||
.spin {
|
||||
@@ -619,11 +630,11 @@ body {
|
||||
}
|
||||
|
||||
.logbook-card {
|
||||
background: rgba(11, 12, 16, 0.6);
|
||||
backdrop-filter: blur(15px);
|
||||
-webkit-backdrop-filter: blur(15px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-radius: 12px;
|
||||
background: var(--app-surface-alt);
|
||||
backdrop-filter: var(--app-backdrop);
|
||||
-webkit-backdrop-filter: var(--app-backdrop);
|
||||
border: 1px solid var(--app-border-subtle);
|
||||
border-radius: var(--app-radius-card);
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -635,14 +646,14 @@ body {
|
||||
|
||||
.logbook-card:hover {
|
||||
transform: translateY(-2px);
|
||||
border-color: rgba(212, 175, 55, 0.4);
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
|
||||
background: rgba(11, 12, 16, 0.75);
|
||||
border-color: var(--app-border);
|
||||
box-shadow: var(--app-card-shadow);
|
||||
background: var(--app-surface-hover);
|
||||
}
|
||||
|
||||
.card-icon {
|
||||
background: rgba(217, 119, 6, 0.1);
|
||||
color: #fbbf24;
|
||||
background: var(--app-accent-bg);
|
||||
color: var(--app-accent-light);
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 10px;
|
||||
@@ -650,7 +661,7 @@ body {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
border: 1px solid rgba(217, 119, 6, 0.2);
|
||||
border: 1px solid var(--app-accent-border);
|
||||
}
|
||||
|
||||
.card-info {
|
||||
@@ -662,7 +673,7 @@ body {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #f1f5f9;
|
||||
color: var(--app-text);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@@ -693,7 +704,7 @@ body {
|
||||
}
|
||||
|
||||
.date-badge {
|
||||
color: #64748b;
|
||||
color: var(--app-text-subtle);
|
||||
}
|
||||
|
||||
.btn-delete {
|
||||
@@ -757,7 +768,7 @@ body {
|
||||
flex-direction: column;
|
||||
padding: 24px;
|
||||
box-sizing: border-box;
|
||||
color: #f1f5f9;
|
||||
color: var(--app-text);
|
||||
}
|
||||
|
||||
.app-header {
|
||||
@@ -766,7 +777,7 @@ body {
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px solid rgba(212, 175, 55, 0.15);
|
||||
border-bottom: 1px solid var(--app-header-border);
|
||||
}
|
||||
|
||||
.app-header-left {
|
||||
@@ -776,9 +787,9 @@ body {
|
||||
}
|
||||
|
||||
.btn-back {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
color: #fbbf24;
|
||||
background: var(--app-btn-secondary-bg);
|
||||
border: 1px solid var(--app-btn-secondary-border);
|
||||
color: var(--app-accent-light);
|
||||
padding: 8px 16px;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
@@ -790,19 +801,19 @@ body {
|
||||
}
|
||||
|
||||
.btn-back:hover {
|
||||
background: rgba(217, 119, 6, 0.1);
|
||||
border-color: #d97706;
|
||||
background: var(--app-accent-bg);
|
||||
border-color: var(--app-accent);
|
||||
}
|
||||
|
||||
.app-title-area h2 {
|
||||
font-size: 20px;
|
||||
margin: 0;
|
||||
color: #f8fafc;
|
||||
color: var(--app-text-heading);
|
||||
}
|
||||
|
||||
.app-title-area .app-subtitle {
|
||||
font-size: 12px;
|
||||
color: #94a3b8;
|
||||
color: var(--app-text-muted);
|
||||
margin: 2px 0 0 0;
|
||||
}
|
||||
|
||||
@@ -823,10 +834,10 @@ body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
background: rgba(11, 12, 16, 0.6);
|
||||
backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-radius: 12px;
|
||||
background: var(--app-surface-alt);
|
||||
backdrop-filter: var(--app-backdrop);
|
||||
border: 1px solid var(--app-border-subtle);
|
||||
border-radius: var(--app-radius-card);
|
||||
padding: 16px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -834,7 +845,7 @@ body {
|
||||
.sidebar-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #94a3b8;
|
||||
color: var(--app-text-muted);
|
||||
padding: 12px 16px;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
@@ -849,21 +860,21 @@ body {
|
||||
}
|
||||
|
||||
.sidebar-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
color: #f1f5f9;
|
||||
background: var(--app-surface-inset);
|
||||
color: var(--app-text);
|
||||
}
|
||||
|
||||
.sidebar-btn.active {
|
||||
background: rgba(217, 119, 6, 0.1);
|
||||
border: 1px solid rgba(217, 119, 6, 0.2);
|
||||
color: #fbbf24;
|
||||
background: var(--app-sidebar-active-bg);
|
||||
border: 1px solid var(--app-accent-border);
|
||||
color: var(--app-sidebar-active-text);
|
||||
}
|
||||
|
||||
.app-content {
|
||||
background: rgba(11, 12, 16, 0.6);
|
||||
backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(212, 175, 55, 0.2);
|
||||
border-radius: 16px;
|
||||
background: var(--app-surface-alt);
|
||||
backdrop-filter: var(--app-backdrop);
|
||||
border: 1px solid var(--app-border-muted);
|
||||
border-radius: var(--app-radius-card);
|
||||
padding: 32px;
|
||||
min-height: 400px;
|
||||
box-sizing: border-box;
|
||||
@@ -877,12 +888,12 @@ body {
|
||||
justify-content: center;
|
||||
min-height: 300px;
|
||||
text-align: center;
|
||||
color: #94a3b8;
|
||||
color: var(--app-text-muted);
|
||||
}
|
||||
|
||||
.tab-placeholder h3 {
|
||||
font-size: 24px;
|
||||
color: #fbbf24;
|
||||
color: var(--app-accent-light);
|
||||
margin-top: 16px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
@@ -895,11 +906,11 @@ body {
|
||||
|
||||
/* Form and Editor layout structures */
|
||||
.form-card {
|
||||
background: rgba(11, 12, 16, 0.6);
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(212, 175, 55, 0.2);
|
||||
border-radius: 16px;
|
||||
background: var(--app-surface-alt);
|
||||
backdrop-filter: var(--app-backdrop);
|
||||
-webkit-backdrop-filter: var(--app-backdrop);
|
||||
border: 1px solid var(--app-border-muted);
|
||||
border-radius: var(--app-radius-card);
|
||||
padding: 32px;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
@@ -915,14 +926,14 @@ body {
|
||||
.form-header h2 {
|
||||
font-size: 20px;
|
||||
margin: 0;
|
||||
color: #fbbf24;
|
||||
color: var(--app-accent-light);
|
||||
min-width: 0;
|
||||
flex-shrink: 1;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.form-icon {
|
||||
color: #fbbf24;
|
||||
color: var(--app-accent-light);
|
||||
}
|
||||
|
||||
.vessel-form {
|
||||
@@ -951,7 +962,7 @@ body {
|
||||
.vessel-form label {
|
||||
display: block;
|
||||
font-size: 13.5px;
|
||||
color: #94a3b8;
|
||||
color: var(--app-text-muted);
|
||||
margin-bottom: 6px;
|
||||
font-weight: 500;
|
||||
}
|
||||
@@ -986,9 +997,9 @@ body {
|
||||
}
|
||||
|
||||
.member-editor-card {
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
border: 1px solid rgba(212, 175, 55, 0.15);
|
||||
border-radius: 12px;
|
||||
background: var(--app-surface-inset);
|
||||
border: 1px solid var(--app-border-muted);
|
||||
border-radius: var(--app-radius-card);
|
||||
padding: 24px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -1002,7 +1013,7 @@ body {
|
||||
.editor-header h3 {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
color: #fbbf24;
|
||||
color: var(--app-accent-light);
|
||||
}
|
||||
|
||||
.editor-actions {
|
||||
@@ -1187,7 +1198,7 @@ body {
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
background: linear-gradient(90deg, #fbbf24, #d97706, #fbbf24);
|
||||
background: var(--app-progress-bar);
|
||||
background-size: 200% 100%;
|
||||
animation: sync-slide 1.5s infinite linear;
|
||||
z-index: 9999;
|
||||
@@ -1228,232 +1239,57 @@ body {
|
||||
|
||||
/* ========================================== */
|
||||
/* PHASE 4: OS-ADAPTIVE UI THEMES */
|
||||
/* Color tokens: themes.css · classes on html */
|
||||
/* ========================================== */
|
||||
|
||||
/* Body Overrides via :has() */
|
||||
body:has(.theme-material) {
|
||||
background: #121212 !important;
|
||||
}
|
||||
body:has(.theme-cupertino) {
|
||||
background: #000000 !important;
|
||||
html.theme-material {
|
||||
font-family: 'Roboto', 'Noto Sans', system-ui, -apple-system, sans-serif;
|
||||
}
|
||||
|
||||
/* --- MATERIAL THEME (ANDROID/LINUX) --- */
|
||||
.theme-material {
|
||||
font-family: 'Roboto', 'Noto Sans', system-ui, -apple-system, sans-serif !important;
|
||||
html.theme-cupertino {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
/* Color & Text overrides */
|
||||
.theme-material h1,
|
||||
.theme-material h2,
|
||||
.theme-material h3,
|
||||
.theme-material h4,
|
||||
.theme-material .form-header h2,
|
||||
.theme-material .form-icon,
|
||||
.theme-material .header-logo,
|
||||
.theme-material .card-icon,
|
||||
.theme-material .btn-back,
|
||||
.theme-material .cell-label {
|
||||
color: #00adb5 !important;
|
||||
html.theme-material .sidebar-btn {
|
||||
border-radius: 0;
|
||||
border-left: 4px solid transparent;
|
||||
}
|
||||
|
||||
/* Card Overrides */
|
||||
.theme-material .auth-card,
|
||||
.theme-material .form-card,
|
||||
.theme-material .create-section,
|
||||
.theme-material .app-sidebar,
|
||||
.theme-material .app-content,
|
||||
.theme-material .logbook-card,
|
||||
.theme-material .crew-member-card,
|
||||
.theme-material .member-editor-card {
|
||||
background: #1e1e1e !important;
|
||||
backdrop-filter: none !important;
|
||||
-webkit-backdrop-filter: none !important;
|
||||
border: 1px solid #2d2d2d !important;
|
||||
border-radius: 4px !important;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3) !important;
|
||||
html.theme-material .sidebar-btn.active {
|
||||
border-left: 4px solid var(--app-sidebar-active-border);
|
||||
border-top: none;
|
||||
border-right: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
/* Input Overrides */
|
||||
.theme-material .input-text,
|
||||
.theme-material .input-textarea,
|
||||
.theme-material select.input-text {
|
||||
background: #2a2a2a !important;
|
||||
border: 1px solid #3d3d3d !important;
|
||||
border-radius: 4px !important;
|
||||
color: #f1f5f9 !important;
|
||||
}
|
||||
.theme-material .input-text:focus,
|
||||
.theme-material .input-textarea:focus {
|
||||
border-color: #00adb5 !important;
|
||||
box-shadow: 0 0 0 2px rgba(0, 173, 181, 0.2) !important;
|
||||
html.theme-material .btn.primary {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
/* Button Overrides */
|
||||
.theme-material .btn.primary {
|
||||
background: #00adb5 !important;
|
||||
color: #ffffff !important;
|
||||
border-radius: 4px !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
.theme-material .btn.primary:hover {
|
||||
background: #008f95 !important;
|
||||
transform: none !important;
|
||||
}
|
||||
.theme-material .btn.secondary,
|
||||
.theme-material .btn-back {
|
||||
background: #2a2a2a !important;
|
||||
border: 1px solid #3d3d3d !important;
|
||||
color: #f1f5f9 !important;
|
||||
border-radius: 4px !important;
|
||||
}
|
||||
.theme-material .btn.secondary:hover,
|
||||
.theme-material .btn-back:hover {
|
||||
background: #333333 !important;
|
||||
html.theme-cupertino .btn.primary,
|
||||
html.theme-cupertino .btn.secondary,
|
||||
html.theme-cupertino .btn-back {
|
||||
border-radius: var(--app-radius-btn);
|
||||
}
|
||||
|
||||
/* Sidebar Overrides */
|
||||
.theme-material .sidebar-btn {
|
||||
border-radius: 0 !important;
|
||||
border-left: 4px solid transparent !important;
|
||||
}
|
||||
.theme-material .sidebar-btn.active {
|
||||
background: rgba(0, 173, 181, 0.08) !important;
|
||||
border-left: 4px solid #00adb5 !important;
|
||||
color: #00adb5 !important;
|
||||
border-top: none !important;
|
||||
border-right: none !important;
|
||||
border-bottom: none !important;
|
||||
html.theme-material .events-table th,
|
||||
html.theme-cupertino .events-table th {
|
||||
color: var(--app-accent);
|
||||
border-bottom-color: var(--app-table-border);
|
||||
}
|
||||
|
||||
/* Header Overrides */
|
||||
.theme-material .app-header {
|
||||
border-bottom: 1px solid #2d2d2d !important;
|
||||
html.theme-material .events-table td,
|
||||
html.theme-cupertino .events-table td {
|
||||
border-bottom-color: var(--app-table-border);
|
||||
}
|
||||
|
||||
/* Tables and Grids */
|
||||
.theme-material .events-table th {
|
||||
color: #00adb5 !important;
|
||||
border-bottom: 2px solid #2d2d2d !important;
|
||||
}
|
||||
.theme-material .events-table td {
|
||||
border-bottom: 1px solid #2d2d2d !important;
|
||||
}
|
||||
.theme-material .events-scroll-container {
|
||||
border: 1px solid #2d2d2d !important;
|
||||
html.theme-material .events-scroll-container,
|
||||
html.theme-cupertino .events-scroll-container {
|
||||
border-color: var(--app-table-border);
|
||||
}
|
||||
|
||||
/* Progress bar override for Material */
|
||||
.theme-material ~ .sync-progress-bar {
|
||||
background: linear-gradient(90deg, #00adb5, #008f95, #00adb5) !important;
|
||||
}
|
||||
|
||||
|
||||
/* --- CUPERTINO THEME (iOS/macOS) --- */
|
||||
.theme-cupertino {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", Helvetica, Arial, sans-serif !important;
|
||||
}
|
||||
|
||||
/* Color & Text overrides */
|
||||
.theme-cupertino h1,
|
||||
.theme-cupertino h2,
|
||||
.theme-cupertino h3,
|
||||
.theme-cupertino h4,
|
||||
.theme-cupertino .form-header h2,
|
||||
.theme-cupertino .form-icon,
|
||||
.theme-cupertino .header-logo,
|
||||
.theme-cupertino .card-icon,
|
||||
.theme-cupertino .btn-back,
|
||||
.theme-cupertino .cell-label {
|
||||
color: #0a84ff !important;
|
||||
}
|
||||
|
||||
/* Card Overrides */
|
||||
.theme-cupertino .auth-card,
|
||||
.theme-cupertino .form-card,
|
||||
.theme-cupertino .create-section,
|
||||
.theme-cupertino .app-sidebar,
|
||||
.theme-cupertino .app-content,
|
||||
.theme-cupertino .logbook-card,
|
||||
.theme-cupertino .crew-member-card,
|
||||
.theme-cupertino .member-editor-card {
|
||||
background: rgba(28, 28, 30, 0.7) !important;
|
||||
backdrop-filter: blur(25px) !important;
|
||||
-webkit-backdrop-filter: blur(25px) !important;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1) !important;
|
||||
border-radius: 12px !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
/* Input Overrides */
|
||||
.theme-cupertino .input-text,
|
||||
.theme-cupertino .input-textarea,
|
||||
.theme-cupertino select.input-text {
|
||||
background: rgba(255, 255, 255, 0.05) !important;
|
||||
border: 1px solid rgba(255, 255, 255, 0.12) !important;
|
||||
border-radius: 8px !important;
|
||||
color: #ffffff !important;
|
||||
}
|
||||
.theme-cupertino .input-text:focus,
|
||||
.theme-cupertino .input-textarea:focus {
|
||||
border-color: #0a84ff !important;
|
||||
box-shadow: 0 0 0 2px rgba(10, 132, 255, 0.25) !important;
|
||||
}
|
||||
|
||||
/* Button Overrides */
|
||||
.theme-cupertino .btn.primary {
|
||||
background: #0a84ff !important;
|
||||
color: #ffffff !important;
|
||||
border-radius: 9999px !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
.theme-cupertino .btn.primary:hover {
|
||||
background: #007aff !important;
|
||||
transform: none !important;
|
||||
}
|
||||
.theme-cupertino .btn.secondary,
|
||||
.theme-cupertino .btn-back {
|
||||
background: rgba(255, 255, 255, 0.08) !important;
|
||||
border: 1px solid rgba(255, 255, 255, 0.12) !important;
|
||||
color: #ffffff !important;
|
||||
border-radius: 9999px !important;
|
||||
}
|
||||
.theme-cupertino .btn.secondary:hover,
|
||||
.theme-cupertino .btn-back:hover {
|
||||
background: rgba(255, 255, 255, 0.12) !important;
|
||||
}
|
||||
|
||||
/* Sidebar Overrides */
|
||||
.theme-cupertino .sidebar-btn {
|
||||
border-radius: 8px !important;
|
||||
}
|
||||
.theme-cupertino .sidebar-btn.active {
|
||||
background: rgba(10, 132, 255, 0.12) !important;
|
||||
color: #0a84ff !important;
|
||||
border: 1px solid rgba(10, 132, 255, 0.2) !important;
|
||||
}
|
||||
|
||||
/* Header Overrides */
|
||||
.theme-cupertino .app-header {
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1) !important;
|
||||
}
|
||||
|
||||
/* Tables and Grids */
|
||||
.theme-cupertino .events-table th {
|
||||
color: #0a84ff !important;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.15) !important;
|
||||
}
|
||||
.theme-cupertino .events-table td {
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.08) !important;
|
||||
}
|
||||
.theme-cupertino .events-scroll-container {
|
||||
border: 1px solid rgba(255, 255, 255, 0.1) !important;
|
||||
background: rgba(28, 28, 30, 0.5) !important;
|
||||
}
|
||||
|
||||
/* Progress bar override for Cupertino */
|
||||
.theme-cupertino ~ .sync-progress-bar {
|
||||
background: linear-gradient(90deg, #0a84ff, #007aff, #0a84ff) !important;
|
||||
html.theme-cupertino .events-scroll-container {
|
||||
background: var(--app-surface-inset);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+19
-25
@@ -11,6 +11,12 @@ import LogEntriesList from './components/LogEntriesList.tsx'
|
||||
import SettingsForm from './components/SettingsForm.tsx'
|
||||
import InvitationAcceptance from './components/InvitationAcceptance.tsx'
|
||||
import { getActiveMasterKey, logoutUser } from './services/auth.js'
|
||||
import {
|
||||
applyAppearanceToDocument,
|
||||
resolveAppTheme,
|
||||
resolveColorScheme,
|
||||
subscribeToSystemColorScheme
|
||||
} from './services/appearance.js'
|
||||
import { startBackgroundSync, stopBackgroundSync, syncAllLogbooks, subscribeToSyncState } from './services/sync.js'
|
||||
import ReadOnlyViewer from './components/ReadOnlyViewer.tsx'
|
||||
import PwaInstallPrompt from './components/PwaInstallPrompt.tsx'
|
||||
@@ -28,7 +34,6 @@ function App() {
|
||||
const [activeTab, setActiveTab] = useState<'vessel' | 'crew' | 'logs' | 'settings'>('logs')
|
||||
const [online, setOnline] = useState(navigator.onLine)
|
||||
const [isSyncing, setIsSyncing] = useState(false)
|
||||
const [appliedTheme, setAppliedTheme] = useState<'ocean' | 'material' | 'cupertino'>('ocean')
|
||||
const [isAcceptingInvite, setIsAcceptingInvite] = useState(false)
|
||||
|
||||
// Viewer mode for read-only shared links
|
||||
@@ -41,27 +46,16 @@ function App() {
|
||||
[activeLogbookId]
|
||||
)
|
||||
|
||||
const updateAppliedTheme = () => {
|
||||
const configTheme = localStorage.getItem('active_theme') || 'auto'
|
||||
if (configTheme === 'auto') {
|
||||
const userAgent = navigator.userAgent || navigator.vendor || (window as any).opera
|
||||
if (/iPad|iPhone|iPod|Macintosh/.test(userAgent)) {
|
||||
setAppliedTheme('cupertino')
|
||||
} else if (/Android|Linux/.test(userAgent)) {
|
||||
setAppliedTheme('material')
|
||||
} else {
|
||||
setAppliedTheme('ocean')
|
||||
}
|
||||
} else {
|
||||
setAppliedTheme(configTheme as 'ocean' | 'material' | 'cupertino')
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
updateAppliedTheme()
|
||||
window.addEventListener('theme-changed', updateAppliedTheme)
|
||||
const syncAppearance = () => {
|
||||
applyAppearanceToDocument(resolveAppTheme(), resolveColorScheme())
|
||||
}
|
||||
syncAppearance()
|
||||
window.addEventListener('appearance-changed', syncAppearance)
|
||||
const unsubscribeSystem = subscribeToSystemColorScheme(syncAppearance)
|
||||
return () => {
|
||||
window.removeEventListener('theme-changed', updateAppliedTheme)
|
||||
window.removeEventListener('appearance-changed', syncAppearance)
|
||||
unsubscribeSystem()
|
||||
}
|
||||
}, [])
|
||||
|
||||
@@ -159,7 +153,7 @@ function App() {
|
||||
|
||||
if (isViewerMode) {
|
||||
return (
|
||||
<div className={`theme-${appliedTheme}`} style={{ display: 'contents' }}>
|
||||
<div style={{ display: 'contents' }}>
|
||||
<ReadOnlyViewer token={shareToken} hexKey={shareKey} />
|
||||
</div>
|
||||
)
|
||||
@@ -167,7 +161,7 @@ function App() {
|
||||
|
||||
if (isAcceptingInvite) {
|
||||
return (
|
||||
<div className={`theme-${appliedTheme} auth-screen`}>
|
||||
<div className="auth-screen">
|
||||
<InvitationAcceptance
|
||||
onAccepted={(logbookId, title) => {
|
||||
setIsAuthenticated(true)
|
||||
@@ -187,7 +181,7 @@ function App() {
|
||||
|
||||
if (!isAuthenticated) {
|
||||
return (
|
||||
<div className={`theme-${appliedTheme} auth-screen`}>
|
||||
<div className="auth-screen">
|
||||
<AuthOnboarding onAuthenticated={handleAuthenticated} />
|
||||
</div>
|
||||
)
|
||||
@@ -197,7 +191,7 @@ function App() {
|
||||
|
||||
if (!activeLogbookId) {
|
||||
return (
|
||||
<div className={`theme-${appliedTheme}`} style={{ display: 'contents' }}>
|
||||
<div style={{ display: 'contents' }}>
|
||||
{pwaInstallBanner}
|
||||
<LogbookDashboard
|
||||
onSelectLogbook={handleSelectLogbook}
|
||||
@@ -208,7 +202,7 @@ function App() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`theme-${appliedTheme}`} style={{ display: 'contents' }}>
|
||||
<div style={{ display: 'contents' }}>
|
||||
{pwaInstallBanner}
|
||||
{isSyncing && <div className="sync-progress-bar" />}
|
||||
<div className="app-layout">
|
||||
|
||||
@@ -5,6 +5,7 @@ import { ensureLogbookKey } from '../services/logbookKeys.js'
|
||||
import AccountDangerZone from './AccountDangerZone.tsx'
|
||||
import PwaInstallPrompt from './PwaInstallPrompt.tsx'
|
||||
import { useDialog } from './ModalDialog.tsx'
|
||||
import { notifyAppearanceChanged } from '../services/appearance.js'
|
||||
|
||||
interface SettingsFormProps {
|
||||
logbookId?: string | null
|
||||
@@ -30,6 +31,7 @@ export default function SettingsForm({ logbookId }: SettingsFormProps) {
|
||||
const { showConfirm, showAlert } = useDialog()
|
||||
const [apiKey, setApiKey] = useState(localStorage.getItem('owm_api_key') || '')
|
||||
const [theme, setTheme] = useState(localStorage.getItem('active_theme') || 'auto')
|
||||
const [colorScheme, setColorScheme] = useState(localStorage.getItem('active_color_scheme') || 'auto')
|
||||
const [saving, setSaving] = useState(false)
|
||||
const [success, setSuccess] = useState(false)
|
||||
|
||||
@@ -245,17 +247,29 @@ export default function SettingsForm({ logbookId }: SettingsFormProps) {
|
||||
}
|
||||
}
|
||||
|
||||
const persistAppearance = (nextTheme: string, nextColorScheme: string) => {
|
||||
localStorage.setItem('active_theme', nextTheme)
|
||||
localStorage.setItem('active_color_scheme', nextColorScheme)
|
||||
notifyAppearanceChanged()
|
||||
}
|
||||
|
||||
const handleThemeChange = (nextTheme: string) => {
|
||||
setTheme(nextTheme)
|
||||
persistAppearance(nextTheme, colorScheme)
|
||||
}
|
||||
|
||||
const handleColorSchemeChange = (nextColorScheme: string) => {
|
||||
setColorScheme(nextColorScheme)
|
||||
persistAppearance(theme, nextColorScheme)
|
||||
}
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
setSaving(true)
|
||||
setSuccess(false)
|
||||
|
||||
// Save to localStorage
|
||||
localStorage.setItem('owm_api_key', apiKey.trim())
|
||||
localStorage.setItem('active_theme', theme)
|
||||
|
||||
// Notify App of theme change
|
||||
window.dispatchEvent(new Event('theme-changed'))
|
||||
persistAppearance(theme, colorScheme)
|
||||
|
||||
setSaving(false)
|
||||
setSuccess(true)
|
||||
@@ -316,9 +330,8 @@ export default function SettingsForm({ logbookId }: SettingsFormProps) {
|
||||
id="app-theme"
|
||||
className="input-text"
|
||||
value={theme}
|
||||
onChange={(e) => setTheme(e.target.value)}
|
||||
onChange={(e) => handleThemeChange(e.target.value)}
|
||||
disabled={saving}
|
||||
style={{ background: 'rgba(11, 12, 16, 0.85)', color: '#f1f5f9' }}
|
||||
>
|
||||
<option value="auto">{t('settings.theme_auto')}</option>
|
||||
<option value="ocean">{t('settings.theme_ocean')}</option>
|
||||
@@ -328,6 +341,29 @@ export default function SettingsForm({ logbookId }: SettingsFormProps) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="member-editor-card glass mt-4">
|
||||
<h3 style={{ marginTop: 0, marginBottom: '12px', color: 'var(--app-accent-light)', fontSize: '16px' }}>
|
||||
{t('settings.color_scheme_title')}
|
||||
</h3>
|
||||
<p className="text-muted" style={{ fontSize: '13.5px', lineHeight: '145%', margin: '0 0 16px 0' }}>
|
||||
{t('settings.color_scheme_label')}
|
||||
</p>
|
||||
|
||||
<div className="input-group">
|
||||
<select
|
||||
id="app-color-scheme"
|
||||
className="input-text"
|
||||
value={colorScheme}
|
||||
onChange={(e) => handleColorSchemeChange(e.target.value)}
|
||||
disabled={saving}
|
||||
>
|
||||
<option value="auto">{t('settings.color_scheme_auto')}</option>
|
||||
<option value="light">{t('settings.color_scheme_light')}</option>
|
||||
<option value="dark">{t('settings.color_scheme_dark')}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="form-actions mt-4 mb-6">
|
||||
{success && (
|
||||
<div className="success-toast">
|
||||
|
||||
@@ -286,6 +286,11 @@
|
||||
"theme_ocean": "Ocean (Glassmorphismus)",
|
||||
"theme_material": "Material (Android)",
|
||||
"theme_cupertino": "Cupertino (iOS)",
|
||||
"color_scheme_title": "Erscheinungsbild",
|
||||
"color_scheme_label": "Hell- oder Dunkelmodus (Standard: Systemeinstellung)",
|
||||
"color_scheme_auto": "Automatisch (System)",
|
||||
"color_scheme_light": "Hell",
|
||||
"color_scheme_dark": "Dunkel",
|
||||
"share_title": "Logbuch teilen (Schreibgeschützt)",
|
||||
"share_desc": "Aktivieren Sie diese Option, um einen öffentlichen, schreibgeschützten Link zu erstellen. Jeder mit dem Link kann Ihre Reisen, Yacht-Profile und Besatzung ansehen. Die Verschlüsselungsschlüssel werden niemals an den Server übertragen (sie bleiben im Hash-Teil der URL).",
|
||||
"share_enable": "Öffentlichen Link aktivieren",
|
||||
|
||||
@@ -286,6 +286,11 @@
|
||||
"theme_ocean": "Ocean (Glassmorphism)",
|
||||
"theme_material": "Material (Android)",
|
||||
"theme_cupertino": "Cupertino (iOS)",
|
||||
"color_scheme_title": "Appearance",
|
||||
"color_scheme_label": "Light or dark mode (default: follow system)",
|
||||
"color_scheme_auto": "Auto (System)",
|
||||
"color_scheme_light": "Light",
|
||||
"color_scheme_dark": "Dark",
|
||||
"share_title": "Share Logbook (Read-Only)",
|
||||
"share_desc": "Enable this to generate a public, read-only link. Anyone with the link can view your travels, yacht profile, and crew members. Decryption keys are never transmitted to the server (they stay in the hash part of the URL).",
|
||||
"share_enable": "Enable Public Link",
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import { StrictMode } from 'react'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import 'leaflet/dist/leaflet.css'
|
||||
import './themes.css'
|
||||
import './index.css'
|
||||
import App from './App.tsx'
|
||||
import './i18n'
|
||||
import { applyAppearanceToDocument } from './services/appearance.ts'
|
||||
|
||||
applyAppearanceToDocument()
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
export type ColorSchemePreference = 'auto' | 'light' | 'dark'
|
||||
export type ResolvedColorScheme = 'light' | 'dark'
|
||||
export type AppTheme = 'ocean' | 'material' | 'cupertino'
|
||||
|
||||
const THEME_CLASSES = ['theme-ocean', 'theme-material', 'theme-cupertino'] as const
|
||||
const SCHEME_CLASSES = ['scheme-light', 'scheme-dark'] as const
|
||||
|
||||
export function getColorSchemePreference(): ColorSchemePreference {
|
||||
const stored = localStorage.getItem('active_color_scheme')
|
||||
if (stored === 'light' || stored === 'dark' || stored === 'auto') return stored
|
||||
return 'auto'
|
||||
}
|
||||
|
||||
export function resolveColorScheme(pref?: ColorSchemePreference): ResolvedColorScheme {
|
||||
const preference = pref ?? getColorSchemePreference()
|
||||
if (preference === 'light') return 'light'
|
||||
if (preference === 'dark') return 'dark'
|
||||
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
|
||||
}
|
||||
|
||||
export function resolveAppTheme(): AppTheme {
|
||||
const configTheme = localStorage.getItem('active_theme') || 'auto'
|
||||
if (configTheme === 'material' || configTheme === 'cupertino' || configTheme === 'ocean') {
|
||||
return configTheme
|
||||
}
|
||||
const userAgent = navigator.userAgent || navigator.vendor || ''
|
||||
if (/iPad|iPhone|iPod|Macintosh/.test(userAgent)) return 'cupertino'
|
||||
if (/Android|Linux/.test(userAgent)) return 'material'
|
||||
return 'ocean'
|
||||
}
|
||||
|
||||
export function applyAppearanceToDocument(
|
||||
theme: AppTheme = resolveAppTheme(),
|
||||
scheme: ResolvedColorScheme = resolveColorScheme()
|
||||
): void {
|
||||
const root = document.documentElement
|
||||
root.classList.remove(...THEME_CLASSES, ...SCHEME_CLASSES)
|
||||
root.classList.add(`theme-${theme}`, `scheme-${scheme}`)
|
||||
root.style.colorScheme = scheme
|
||||
}
|
||||
|
||||
export function subscribeToSystemColorScheme(onChange: () => void): () => void {
|
||||
const media = window.matchMedia('(prefers-color-scheme: dark)')
|
||||
const handler = () => {
|
||||
if (getColorSchemePreference() === 'auto') onChange()
|
||||
}
|
||||
media.addEventListener('change', handler)
|
||||
return () => media.removeEventListener('change', handler)
|
||||
}
|
||||
|
||||
export function notifyAppearanceChanged(): void {
|
||||
window.dispatchEvent(new Event('appearance-changed'))
|
||||
}
|
||||
@@ -0,0 +1,398 @@
|
||||
/**
|
||||
* Appearance tokens: scheme (light/dark) × theme (ocean/material/cupertino)
|
||||
* Applied on document.documentElement via appearance.ts
|
||||
*/
|
||||
|
||||
/* Fallback before JS hydrates (ocean · dark) */
|
||||
html {
|
||||
color-scheme: dark;
|
||||
--app-body-bg: radial-gradient(circle at center, #1b264f 0%, #0b0c10 100%);
|
||||
--app-text: #f1f5f9;
|
||||
--app-text-heading: #f8fafc;
|
||||
--app-text-muted: #94a3b8;
|
||||
--app-text-subtle: #64748b;
|
||||
--app-surface: rgba(11, 12, 16, 0.75);
|
||||
--app-surface-alt: rgba(11, 12, 16, 0.6);
|
||||
--app-surface-hover: rgba(11, 12, 16, 0.85);
|
||||
--app-surface-inset: rgba(255, 255, 255, 0.02);
|
||||
--app-border: rgba(212, 175, 55, 0.25);
|
||||
--app-border-subtle: rgba(255, 255, 255, 0.08);
|
||||
--app-border-muted: rgba(212, 175, 55, 0.15);
|
||||
--app-input-bg: rgba(11, 12, 16, 0.85);
|
||||
--app-input-bg-focus: #0b0c10;
|
||||
--app-input-border: rgba(148, 163, 184, 0.25);
|
||||
--app-input-text: #f1f5f9;
|
||||
--app-accent: #d97706;
|
||||
--app-accent-light: #fbbf24;
|
||||
--app-accent-gradient: linear-gradient(135deg, #fef08a 0%, #d97706 100%);
|
||||
--app-accent-bg: rgba(217, 119, 6, 0.1);
|
||||
--app-accent-border: rgba(217, 119, 6, 0.2);
|
||||
--app-accent-focus-ring: rgba(217, 119, 6, 0.2);
|
||||
--app-btn-primary-text: #0b0c10;
|
||||
--app-btn-secondary-bg: rgba(255, 255, 255, 0.05);
|
||||
--app-btn-secondary-border: rgba(255, 255, 255, 0.12);
|
||||
--app-btn-secondary-text: #e2e8f0;
|
||||
--app-btn-secondary-hover-bg: rgba(255, 255, 255, 0.08);
|
||||
--app-icon-btn-bg: rgba(255, 255, 255, 0.05);
|
||||
--app-icon-btn-border: rgba(255, 255, 255, 0.1);
|
||||
--app-divider: rgba(255, 255, 255, 0.06);
|
||||
--app-shadow: 0 20px 50px rgba(0, 0, 0, 0.6), inset 0 0 0 1px rgba(255, 255, 255, 0.05);
|
||||
--app-card-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
|
||||
--app-error-bg: rgba(244, 63, 94, 0.08);
|
||||
--app-error-text: #fda4af;
|
||||
--app-error-border: #f43f5e;
|
||||
--app-warning-text: #f43f5e;
|
||||
--app-warning-bg: rgba(244, 63, 94, 0.08);
|
||||
--app-warning-border: rgba(244, 63, 94, 0.2);
|
||||
--app-empty-border: rgba(255, 255, 255, 0.08);
|
||||
--app-empty-bg: rgba(255, 255, 255, 0.02);
|
||||
--app-sidebar-active-bg: rgba(217, 119, 6, 0.12);
|
||||
--app-sidebar-active-border: #d97706;
|
||||
--app-sidebar-active-text: #fbbf24;
|
||||
--app-header-border: rgba(212, 175, 55, 0.15);
|
||||
--app-table-border: rgba(255, 255, 255, 0.08);
|
||||
--app-progress-bar: linear-gradient(90deg, #d97706, #fbbf24, #d97706);
|
||||
--app-backdrop: blur(20px);
|
||||
--app-radius-card: 16px;
|
||||
--app-radius-input: 10px;
|
||||
--app-radius-btn: 10px;
|
||||
}
|
||||
|
||||
/* ===== OCEAN · DARK (default) ===== */
|
||||
html.scheme-dark.theme-ocean {
|
||||
color-scheme: dark;
|
||||
--app-body-bg: radial-gradient(circle at center, #1b264f 0%, #0b0c10 100%);
|
||||
--app-text: #f1f5f9;
|
||||
--app-text-heading: #f8fafc;
|
||||
--app-text-muted: #94a3b8;
|
||||
--app-text-subtle: #64748b;
|
||||
--app-surface: rgba(11, 12, 16, 0.75);
|
||||
--app-surface-alt: rgba(11, 12, 16, 0.6);
|
||||
--app-surface-hover: rgba(11, 12, 16, 0.85);
|
||||
--app-surface-inset: rgba(255, 255, 255, 0.02);
|
||||
--app-border: rgba(212, 175, 55, 0.25);
|
||||
--app-border-subtle: rgba(255, 255, 255, 0.08);
|
||||
--app-border-muted: rgba(212, 175, 55, 0.15);
|
||||
--app-input-bg: rgba(11, 12, 16, 0.85);
|
||||
--app-input-bg-focus: #0b0c10;
|
||||
--app-input-border: rgba(148, 163, 184, 0.25);
|
||||
--app-input-text: #f1f5f9;
|
||||
--app-accent: #d97706;
|
||||
--app-accent-light: #fbbf24;
|
||||
--app-accent-gradient: linear-gradient(135deg, #fef08a 0%, #d97706 100%);
|
||||
--app-accent-bg: rgba(217, 119, 6, 0.1);
|
||||
--app-accent-border: rgba(217, 119, 6, 0.2);
|
||||
--app-accent-focus-ring: rgba(217, 119, 6, 0.2);
|
||||
--app-btn-primary-text: #0b0c10;
|
||||
--app-btn-secondary-bg: rgba(255, 255, 255, 0.05);
|
||||
--app-btn-secondary-border: rgba(255, 255, 255, 0.12);
|
||||
--app-btn-secondary-text: #e2e8f0;
|
||||
--app-btn-secondary-hover-bg: rgba(255, 255, 255, 0.08);
|
||||
--app-icon-btn-bg: rgba(255, 255, 255, 0.05);
|
||||
--app-icon-btn-border: rgba(255, 255, 255, 0.1);
|
||||
--app-divider: rgba(255, 255, 255, 0.06);
|
||||
--app-shadow: 0 20px 50px rgba(0, 0, 0, 0.6), inset 0 0 0 1px rgba(255, 255, 255, 0.05);
|
||||
--app-card-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
|
||||
--app-error-bg: rgba(244, 63, 94, 0.08);
|
||||
--app-error-text: #fda4af;
|
||||
--app-error-border: #f43f5e;
|
||||
--app-warning-text: #f43f5e;
|
||||
--app-warning-bg: rgba(244, 63, 94, 0.08);
|
||||
--app-warning-border: rgba(244, 63, 94, 0.2);
|
||||
--app-empty-border: rgba(255, 255, 255, 0.08);
|
||||
--app-empty-bg: rgba(255, 255, 255, 0.02);
|
||||
--app-sidebar-active-bg: rgba(217, 119, 6, 0.12);
|
||||
--app-sidebar-active-border: #d97706;
|
||||
--app-sidebar-active-text: #fbbf24;
|
||||
--app-header-border: rgba(212, 175, 55, 0.15);
|
||||
--app-table-border: rgba(255, 255, 255, 0.08);
|
||||
--app-progress-bar: linear-gradient(90deg, #d97706, #fbbf24, #d97706);
|
||||
--app-backdrop: blur(20px);
|
||||
--app-radius-card: 16px;
|
||||
--app-radius-input: 10px;
|
||||
--app-radius-btn: 10px;
|
||||
}
|
||||
|
||||
/* ===== OCEAN · LIGHT ===== */
|
||||
html.scheme-light.theme-ocean {
|
||||
color-scheme: light;
|
||||
--app-body-bg: linear-gradient(165deg, #dbeafe 0%, #f8fafc 42%, #e2e8f0 100%);
|
||||
--app-text: #1e293b;
|
||||
--app-text-heading: #0f172a;
|
||||
--app-text-muted: #475569;
|
||||
--app-text-subtle: #64748b;
|
||||
--app-surface: rgba(255, 255, 255, 0.88);
|
||||
--app-surface-alt: rgba(255, 255, 255, 0.78);
|
||||
--app-surface-hover: rgba(255, 255, 255, 0.96);
|
||||
--app-surface-inset: rgba(15, 23, 42, 0.03);
|
||||
--app-border: rgba(217, 119, 6, 0.28);
|
||||
--app-border-subtle: rgba(15, 23, 42, 0.1);
|
||||
--app-border-muted: rgba(217, 119, 6, 0.18);
|
||||
--app-input-bg: #ffffff;
|
||||
--app-input-bg-focus: #ffffff;
|
||||
--app-input-border: rgba(100, 116, 139, 0.35);
|
||||
--app-input-text: #0f172a;
|
||||
--app-accent: #b45309;
|
||||
--app-accent-light: #d97706;
|
||||
--app-accent-gradient: linear-gradient(135deg, #fcd34d 0%, #b45309 100%);
|
||||
--app-accent-bg: rgba(217, 119, 6, 0.12);
|
||||
--app-accent-border: rgba(217, 119, 6, 0.25);
|
||||
--app-accent-focus-ring: rgba(217, 119, 6, 0.25);
|
||||
--app-btn-primary-text: #0b0c10;
|
||||
--app-btn-secondary-bg: rgba(15, 23, 42, 0.04);
|
||||
--app-btn-secondary-border: rgba(15, 23, 42, 0.12);
|
||||
--app-btn-secondary-text: #334155;
|
||||
--app-btn-secondary-hover-bg: rgba(15, 23, 42, 0.07);
|
||||
--app-icon-btn-bg: rgba(15, 23, 42, 0.04);
|
||||
--app-icon-btn-border: rgba(15, 23, 42, 0.1);
|
||||
--app-divider: rgba(15, 23, 42, 0.08);
|
||||
--app-shadow: 0 16px 40px rgba(15, 23, 42, 0.12), inset 0 0 0 1px rgba(255, 255, 255, 0.6);
|
||||
--app-card-shadow: 0 8px 24px rgba(15, 23, 42, 0.1);
|
||||
--app-error-bg: rgba(244, 63, 94, 0.08);
|
||||
--app-error-text: #be123c;
|
||||
--app-error-border: #e11d48;
|
||||
--app-warning-text: #be123c;
|
||||
--app-warning-bg: rgba(244, 63, 94, 0.06);
|
||||
--app-warning-border: rgba(244, 63, 94, 0.2);
|
||||
--app-empty-border: rgba(15, 23, 42, 0.12);
|
||||
--app-empty-bg: rgba(15, 23, 42, 0.02);
|
||||
--app-sidebar-active-bg: rgba(217, 119, 6, 0.1);
|
||||
--app-sidebar-active-border: #d97706;
|
||||
--app-sidebar-active-text: #b45309;
|
||||
--app-header-border: rgba(217, 119, 6, 0.2);
|
||||
--app-table-border: rgba(15, 23, 42, 0.1);
|
||||
--app-progress-bar: linear-gradient(90deg, #d97706, #fbbf24, #d97706);
|
||||
--app-backdrop: blur(20px);
|
||||
--app-radius-card: 16px;
|
||||
--app-radius-input: 10px;
|
||||
--app-radius-btn: 10px;
|
||||
}
|
||||
|
||||
/* ===== MATERIAL · DARK ===== */
|
||||
html.scheme-dark.theme-material {
|
||||
color-scheme: dark;
|
||||
--app-body-bg: #121212;
|
||||
--app-text: #f1f5f9;
|
||||
--app-text-heading: #f8fafc;
|
||||
--app-text-muted: #94a3b8;
|
||||
--app-text-subtle: #64748b;
|
||||
--app-surface: #1e1e1e;
|
||||
--app-surface-alt: #1e1e1e;
|
||||
--app-surface-hover: #252525;
|
||||
--app-surface-inset: #2a2a2a;
|
||||
--app-border: #2d2d2d;
|
||||
--app-border-subtle: #2d2d2d;
|
||||
--app-border-muted: #2d2d2d;
|
||||
--app-input-bg: #2a2a2a;
|
||||
--app-input-bg-focus: #2a2a2a;
|
||||
--app-input-border: #3d3d3d;
|
||||
--app-input-text: #f1f5f9;
|
||||
--app-accent: #00adb5;
|
||||
--app-accent-light: #00adb5;
|
||||
--app-accent-gradient: linear-gradient(135deg, #00adb5 0%, #008f95 100%);
|
||||
--app-accent-bg: rgba(0, 173, 181, 0.12);
|
||||
--app-accent-border: rgba(0, 173, 181, 0.3);
|
||||
--app-accent-focus-ring: rgba(0, 173, 181, 0.2);
|
||||
--app-btn-primary-text: #ffffff;
|
||||
--app-btn-secondary-bg: #2a2a2a;
|
||||
--app-btn-secondary-border: #3d3d3d;
|
||||
--app-btn-secondary-text: #f1f5f9;
|
||||
--app-btn-secondary-hover-bg: #333333;
|
||||
--app-icon-btn-bg: #2a2a2a;
|
||||
--app-icon-btn-border: #3d3d3d;
|
||||
--app-divider: #2d2d2d;
|
||||
--app-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
|
||||
--app-card-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
|
||||
--app-error-bg: rgba(244, 63, 94, 0.08);
|
||||
--app-error-text: #fda4af;
|
||||
--app-error-border: #f43f5e;
|
||||
--app-warning-text: #f43f5e;
|
||||
--app-warning-bg: rgba(244, 63, 94, 0.08);
|
||||
--app-warning-border: rgba(244, 63, 94, 0.2);
|
||||
--app-empty-border: #2d2d2d;
|
||||
--app-empty-bg: #1a1a1a;
|
||||
--app-sidebar-active-bg: rgba(0, 173, 181, 0.08);
|
||||
--app-sidebar-active-border: #00adb5;
|
||||
--app-sidebar-active-text: #00adb5;
|
||||
--app-header-border: #2d2d2d;
|
||||
--app-table-border: #2d2d2d;
|
||||
--app-progress-bar: linear-gradient(90deg, #00adb5, #008f95, #00adb5);
|
||||
--app-backdrop: none;
|
||||
--app-radius-card: 4px;
|
||||
--app-radius-input: 4px;
|
||||
--app-radius-btn: 4px;
|
||||
}
|
||||
|
||||
/* ===== MATERIAL · LIGHT ===== */
|
||||
html.scheme-light.theme-material {
|
||||
color-scheme: light;
|
||||
--app-body-bg: #fafafa;
|
||||
--app-text: #212121;
|
||||
--app-text-heading: #111827;
|
||||
--app-text-muted: #616161;
|
||||
--app-text-subtle: #757575;
|
||||
--app-surface: #ffffff;
|
||||
--app-surface-alt: #ffffff;
|
||||
--app-surface-hover: #f5f5f5;
|
||||
--app-surface-inset: #f5f5f5;
|
||||
--app-border: #e0e0e0;
|
||||
--app-border-subtle: #eeeeee;
|
||||
--app-border-muted: #e0e0e0;
|
||||
--app-input-bg: #ffffff;
|
||||
--app-input-bg-focus: #ffffff;
|
||||
--app-input-border: #bdbdbd;
|
||||
--app-input-text: #212121;
|
||||
--app-accent: #00838f;
|
||||
--app-accent-light: #00838f;
|
||||
--app-accent-gradient: linear-gradient(135deg, #00838f 0%, #006064 100%);
|
||||
--app-accent-bg: rgba(0, 131, 143, 0.1);
|
||||
--app-accent-border: rgba(0, 131, 143, 0.25);
|
||||
--app-accent-focus-ring: rgba(0, 131, 143, 0.2);
|
||||
--app-btn-primary-text: #ffffff;
|
||||
--app-btn-secondary-bg: #f5f5f5;
|
||||
--app-btn-secondary-border: #e0e0e0;
|
||||
--app-btn-secondary-text: #424242;
|
||||
--app-btn-secondary-hover-bg: #eeeeee;
|
||||
--app-icon-btn-bg: #f5f5f5;
|
||||
--app-icon-btn-border: #e0e0e0;
|
||||
--app-divider: #e0e0e0;
|
||||
--app-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
|
||||
--app-card-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||
--app-error-bg: rgba(244, 63, 94, 0.08);
|
||||
--app-error-text: #be123c;
|
||||
--app-error-border: #e11d48;
|
||||
--app-warning-text: #be123c;
|
||||
--app-warning-bg: rgba(244, 63, 94, 0.06);
|
||||
--app-warning-border: rgba(244, 63, 94, 0.2);
|
||||
--app-empty-border: #e0e0e0;
|
||||
--app-empty-bg: #fafafa;
|
||||
--app-sidebar-active-bg: rgba(0, 131, 143, 0.08);
|
||||
--app-sidebar-active-border: #00838f;
|
||||
--app-sidebar-active-text: #00838f;
|
||||
--app-header-border: #e0e0e0;
|
||||
--app-table-border: #e0e0e0;
|
||||
--app-progress-bar: linear-gradient(90deg, #00838f, #00adb5, #00838f);
|
||||
--app-backdrop: none;
|
||||
--app-radius-card: 4px;
|
||||
--app-radius-input: 4px;
|
||||
--app-radius-btn: 4px;
|
||||
}
|
||||
|
||||
/* ===== CUPERTINO · DARK ===== */
|
||||
html.scheme-dark.theme-cupertino {
|
||||
color-scheme: dark;
|
||||
--app-body-bg: #000000;
|
||||
--app-text: #ffffff;
|
||||
--app-text-heading: #ffffff;
|
||||
--app-text-muted: #aeaeb2;
|
||||
--app-text-subtle: #8e8e93;
|
||||
--app-surface: rgba(28, 28, 30, 0.72);
|
||||
--app-surface-alt: rgba(28, 28, 30, 0.72);
|
||||
--app-surface-hover: rgba(44, 44, 46, 0.85);
|
||||
--app-surface-inset: rgba(255, 255, 255, 0.05);
|
||||
--app-border: rgba(255, 255, 255, 0.1);
|
||||
--app-border-subtle: rgba(255, 255, 255, 0.1);
|
||||
--app-border-muted: rgba(255, 255, 255, 0.08);
|
||||
--app-input-bg: rgba(255, 255, 255, 0.05);
|
||||
--app-input-bg-focus: rgba(255, 255, 255, 0.07);
|
||||
--app-input-border: rgba(255, 255, 255, 0.12);
|
||||
--app-input-text: #ffffff;
|
||||
--app-accent: #0a84ff;
|
||||
--app-accent-light: #0a84ff;
|
||||
--app-accent-gradient: linear-gradient(135deg, #0a84ff 0%, #007aff 100%);
|
||||
--app-accent-bg: rgba(10, 132, 255, 0.12);
|
||||
--app-accent-border: rgba(10, 132, 255, 0.3);
|
||||
--app-accent-focus-ring: rgba(10, 132, 255, 0.25);
|
||||
--app-btn-primary-text: #ffffff;
|
||||
--app-btn-secondary-bg: rgba(255, 255, 255, 0.08);
|
||||
--app-btn-secondary-border: rgba(255, 255, 255, 0.12);
|
||||
--app-btn-secondary-text: #ffffff;
|
||||
--app-btn-secondary-hover-bg: rgba(255, 255, 255, 0.12);
|
||||
--app-icon-btn-bg: rgba(255, 255, 255, 0.08);
|
||||
--app-icon-btn-border: rgba(255, 255, 255, 0.12);
|
||||
--app-divider: rgba(255, 255, 255, 0.08);
|
||||
--app-shadow: none;
|
||||
--app-card-shadow: none;
|
||||
--app-error-bg: rgba(255, 69, 58, 0.12);
|
||||
--app-error-text: #ff6961;
|
||||
--app-error-border: #ff453a;
|
||||
--app-warning-text: #ff6961;
|
||||
--app-warning-bg: rgba(255, 69, 58, 0.12);
|
||||
--app-warning-border: rgba(255, 69, 58, 0.25);
|
||||
--app-empty-border: rgba(255, 255, 255, 0.1);
|
||||
--app-empty-bg: rgba(255, 255, 255, 0.04);
|
||||
--app-sidebar-active-bg: rgba(10, 132, 255, 0.15);
|
||||
--app-sidebar-active-border: #0a84ff;
|
||||
--app-sidebar-active-text: #0a84ff;
|
||||
--app-header-border: rgba(255, 255, 255, 0.1);
|
||||
--app-table-border: rgba(255, 255, 255, 0.1);
|
||||
--app-progress-bar: linear-gradient(90deg, #0a84ff, #007aff, #0a84ff);
|
||||
--app-backdrop: blur(25px);
|
||||
--app-radius-card: 12px;
|
||||
--app-radius-input: 8px;
|
||||
--app-radius-btn: 9999px;
|
||||
}
|
||||
|
||||
/* ===== CUPERTINO · LIGHT ===== */
|
||||
html.scheme-light.theme-cupertino {
|
||||
color-scheme: light;
|
||||
--app-body-bg: #f2f2f7;
|
||||
--app-text: #1c1c1e;
|
||||
--app-text-heading: #000000;
|
||||
--app-text-muted: #636366;
|
||||
--app-text-subtle: #8e8e93;
|
||||
--app-surface: rgba(255, 255, 255, 0.82);
|
||||
--app-surface-alt: rgba(255, 255, 255, 0.82);
|
||||
--app-surface-hover: rgba(255, 255, 255, 0.95);
|
||||
--app-surface-inset: rgba(0, 0, 0, 0.03);
|
||||
--app-border: rgba(0, 0, 0, 0.08);
|
||||
--app-border-subtle: rgba(0, 0, 0, 0.06);
|
||||
--app-border-muted: rgba(0, 0, 0, 0.08);
|
||||
--app-input-bg: #ffffff;
|
||||
--app-input-bg-focus: #ffffff;
|
||||
--app-input-border: rgba(0, 0, 0, 0.12);
|
||||
--app-input-text: #1c1c1e;
|
||||
--app-accent: #007aff;
|
||||
--app-accent-light: #007aff;
|
||||
--app-accent-gradient: linear-gradient(135deg, #007aff 0%, #0a84ff 100%);
|
||||
--app-accent-bg: rgba(0, 122, 255, 0.1);
|
||||
--app-accent-border: rgba(0, 122, 255, 0.25);
|
||||
--app-accent-focus-ring: rgba(0, 122, 255, 0.2);
|
||||
--app-btn-primary-text: #ffffff;
|
||||
--app-btn-secondary-bg: rgba(0, 0, 0, 0.05);
|
||||
--app-btn-secondary-border: rgba(0, 0, 0, 0.08);
|
||||
--app-btn-secondary-text: #1c1c1e;
|
||||
--app-btn-secondary-hover-bg: rgba(0, 0, 0, 0.08);
|
||||
--app-icon-btn-bg: rgba(0, 0, 0, 0.05);
|
||||
--app-icon-btn-border: rgba(0, 0, 0, 0.08);
|
||||
--app-divider: rgba(0, 0, 0, 0.08);
|
||||
--app-shadow: none;
|
||||
--app-card-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
||||
--app-error-bg: rgba(255, 59, 48, 0.1);
|
||||
--app-error-text: #d70015;
|
||||
--app-error-border: #ff3b30;
|
||||
--app-warning-text: #d70015;
|
||||
--app-warning-bg: rgba(255, 59, 48, 0.08);
|
||||
--app-warning-border: rgba(255, 59, 48, 0.2);
|
||||
--app-empty-border: rgba(0, 0, 0, 0.08);
|
||||
--app-empty-bg: rgba(0, 0, 0, 0.02);
|
||||
--app-sidebar-active-bg: rgba(0, 122, 255, 0.1);
|
||||
--app-sidebar-active-border: #007aff;
|
||||
--app-sidebar-active-text: #007aff;
|
||||
--app-header-border: rgba(0, 0, 0, 0.08);
|
||||
--app-table-border: rgba(0, 0, 0, 0.08);
|
||||
--app-progress-bar: linear-gradient(90deg, #007aff, #0a84ff, #007aff);
|
||||
--app-backdrop: blur(25px);
|
||||
--app-radius-card: 12px;
|
||||
--app-radius-input: 8px;
|
||||
--app-radius-btn: 9999px;
|
||||
}
|
||||
|
||||
/* Utility classes for inline-style migration */
|
||||
.text-muted { color: var(--app-text-muted); }
|
||||
.text-subtle { color: var(--app-text-subtle); }
|
||||
.text-heading { color: var(--app-text-heading); }
|
||||
|
||||
html.scheme-light #root {
|
||||
border-inline-color: var(--app-border-subtle);
|
||||
}
|
||||
Reference in New Issue
Block a user