fix(mobile): the phone library wears the app's theme

The phone screen was painted in literals — `#101014`, `#f4f4f5` and forty more
— so it stayed dark whatever theme was set: pick Light, press Mobile Cloud,
and the reader is handed a black page with white ink.

Every surface and ink in `styles/mobile-library.css` is now one alias
(`--ml-bg`, `--ml-text`, …) that reads the theme's own tokens, the faint
linings and fills are a `color-mix` of the ink at the alpha they already
carried, and the amber the file already asked `var(--accent)` for is now what
the star, the pressed pill and the selected frame wear too. Only the four
status inks carry a light-theme override, the tokens having no word for them.

The five inline dark styles left in `MobileLibrary.tsx` read the same aliases.

Measured on the running container at 390×800, Light chosen on the desktop: the
phone was `rgb(16,16,20)` on ink `rgb(244,244,245)` whichever theme was set;
it is now `rgb(255,255,255)` on `rgb(20,24,29)` under Light and `rgb(0,0,0)` on
`rgb(242,243,245)` under Dark, held through the handover and on the way back. A
contrast sweep of the grid and the reader in both themes leaves nothing under
3:1 but the tick glyph, which its own box draws.

`mobile-pick-check` asked for one frozen amber; it asks for the accent the app
is using, which is what that outline has become.
This commit is contained in:
2026-10-15 22:03:50 +07:00
parent 3efdfb34f5
commit 4d9be1014c
3 changed files with 218 additions and 169 deletions
@@ -217,6 +217,14 @@ const read = await page.evaluate(() => {
cells: cells.length,
selected: sel.map((c) => c.querySelector('img')?.getAttribute('alt') ?? ''),
outline: sel[0] ? getComputedStyle(sel[0]).outlineColor : '',
accent: (() => {
const probe = document.createElement('div');
probe.style.background = 'var(--accent)';
document.body.append(probe);
const c = getComputedStyle(probe).backgroundColor;
probe.remove();
return c;
})(),
inView: !!(box && r && r.top >= box.top - 4 && r.bottom <= box.bottom + 4),
gridMode: !!document.querySelector('.mob-lib-grid'),
singles: document.querySelectorAll('.mob-lib-single-card').length,
@@ -226,7 +234,7 @@ step('closing hands the reader to ALL THUMBS', read.gridMode && read.singles ===
step('exactly one frame is selected', read.selected.length === 1, `${read.selected.length}`);
step('the frame swiped to is the selected one', read.selected[0] === swiped, `swiped=${swiped} selected=${read.selected[0]}`);
step('the selected frame is on screen', read.inView);
step('the selected frame is marked in CSS', read.outline === 'rgb(245, 158, 11)', read.outline);
step('the selected frame is marked in the accent', read.outline === read.accent && read.accent.startsWith('rgb('), `${read.outline} vs accent ${read.accent}`);
step('no page error', errors.length === 0, errors.join(' | '));
await browser.close();
+192 -151
View File
@@ -2,11 +2,43 @@
.mob-lib-root {
display: flex;
/* The phone paints itself from the app's theme: one alias per surface, one
per ink, the rest is colour maths, so Light/Dark and the accent reach the
phone for free — see tokens.css. */
--ml-bg: var(--bg);
--ml-bg-soft: color-mix(in srgb, var(--bg) 70%, transparent);
--ml-bg-blur: color-mix(in srgb, var(--bg) 92%, transparent);
--ml-sunken: var(--bg-sunken);
--ml-panel: var(--bg-elev);
--ml-panel-2: color-mix(in srgb, var(--text) 8%, var(--bg-elev));
--ml-popover: color-mix(in srgb, var(--bg-elev) 92%, transparent);
--ml-text: var(--text);
--ml-text-2: color-mix(in srgb, var(--text) 88%, var(--bg));
--ml-text-3: color-mix(in srgb, var(--text) 80%, var(--bg));
--ml-dim: var(--text-dim);
--ml-dim-2: color-mix(in srgb, var(--text-dim) 78%, var(--bg));
--ml-dim-3: color-mix(in srgb, var(--text-dim) 72%, var(--bg));
--ml-faint: color-mix(in srgb, var(--text) 55%, transparent);
--ml-line-faint: color-mix(in srgb, var(--text) 4%, transparent);
--ml-line-soft: color-mix(in srgb, var(--text) 7%, transparent);
--ml-line: color-mix(in srgb, var(--text) 10%, transparent);
--ml-line-strong: color-mix(in srgb, var(--text) 15%, transparent);
--ml-line-stronger: color-mix(in srgb, var(--text) 22%, transparent);
--ml-fill-faint: color-mix(in srgb, var(--text) 3%, transparent);
--ml-fill: color-mix(in srgb, var(--text) 7%, transparent);
--ml-fill-strong: color-mix(in srgb, var(--text) 13%, transparent);
--ml-fill-active: color-mix(in srgb, var(--text) 22%, transparent);
--ml-grip: color-mix(in srgb, var(--text) 30%, transparent);
--ml-grip-strong: color-mix(in srgb, var(--text) 60%, transparent);
--ml-blue: #60a5fa;
--ml-blue-2: #93c5fd;
--ml-green: #34d399;
--ml-red: #ef4444;
flex-direction: column;
height: 100%;
width: 100%;
background: #101014;
color: #f4f4f5;
background: var(--ml-bg);
color: var(--ml-text);
font-family: var(--sans, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif);
overflow: hidden;
position: relative;
@@ -14,6 +46,15 @@
-webkit-user-select: none;
}
/* Status inks are the only colours the tokens cannot express, so they get a
darker ink of their own on the light theme. */
[data-theme="light"] .mob-lib-root {
--ml-blue: #2563eb;
--ml-blue-2: #1d4ed8;
--ml-green: #0f9d63;
--ml-red: #c2402f;
}
/* --- Top Header Bar --- */
.mob-lib-header {
position: sticky;
@@ -23,10 +64,10 @@
align-items: center;
justify-content: space-between;
padding: max(10px, env(safe-area-inset-top)) 16px 10px;
background: rgba(16, 16, 20, 0.88);
background: var(--ml-bg-blur);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
border-bottom: 1px solid var(--ml-line-soft);
flex-shrink: 0;
}
@@ -41,7 +82,7 @@
align-items: center;
gap: 7px;
text-decoration: none;
color: #ffffff;
color: var(--ml-text);
}
.mob-lib-brand-img {
@@ -62,7 +103,7 @@
font-size: 18px;
font-weight: 700;
letter-spacing: -0.02em;
color: #ffffff;
color: var(--ml-text);
line-height: 1;
}
@@ -75,9 +116,9 @@
.mob-lib-header-title {
font-size: 12px;
font-weight: 600;
color: rgba(255, 255, 255, 0.55);
color: var(--ml-faint);
padding-left: 8px;
border-left: 1px solid rgba(255, 255, 255, 0.15);
border-left: 1px solid var(--ml-line-strong);
line-height: 1.2;
}
@@ -88,7 +129,7 @@
min-width: 0;
max-width: 170px;
padding-left: 8px;
border-left: 1px solid rgba(255, 255, 255, 0.15);
border-left: 1px solid var(--ml-line-strong);
}
.mob-lib-header-folder-icon {
@@ -101,7 +142,7 @@
.mob-lib-header-folder-name {
font-size: 13px;
font-weight: 600;
color: #f4f4f5;
color: var(--ml-text);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@@ -118,7 +159,7 @@
.mob-lib-folder-brand-text {
font-size: 14px;
font-weight: 700;
color: #f4f4f5;
color: var(--ml-text);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@@ -130,10 +171,10 @@
align-items: center;
justify-content: space-between;
padding: 8px 14px;
background: rgba(22, 22, 28, 0.94);
background: var(--ml-popover);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
border-bottom: 1px solid var(--ml-line);
flex-shrink: 0;
z-index: 25;
}
@@ -163,7 +204,7 @@
font-size: 15px;
font-weight: 700;
letter-spacing: -0.02em;
color: #ffffff;
color: var(--ml-text);
line-height: 1;
}
@@ -175,7 +216,7 @@
padding: 1px 6px;
border-radius: 999px;
background: rgba(66, 133, 244, 0.18);
color: #60a5fa;
color: var(--ml-blue);
border: 1px solid rgba(66, 133, 244, 0.35);
line-height: 1.4;
}
@@ -183,7 +224,7 @@
.mob-lib-immich-album-name {
font-size: 13px;
font-weight: 600;
color: #e4e4e7;
color: var(--ml-text-2);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@@ -198,7 +239,7 @@
.mob-lib-immich-count {
font-size: 11px;
color: #a1a1aa;
color: var(--ml-dim);
}
.mob-lib-header-right {
@@ -213,7 +254,7 @@
justify-content: center;
background: transparent;
border: none;
color: #d4d4d8;
color: var(--ml-text-3);
cursor: pointer;
padding: 4px;
border-radius: 50%;
@@ -229,11 +270,11 @@
height: 32px;
border-radius: 50%;
overflow: hidden;
border: 1.5px solid rgba(255, 255, 255, 0.2);
border: 1.5px solid var(--ml-line-stronger);
display: flex;
align-items: center;
justify-content: center;
background: #27272a;
background: var(--ml-panel-2);
}
.mob-lib-avatar img {
@@ -248,8 +289,8 @@
gap: 4px;
padding: 4px 10px;
border-radius: 999px;
background: rgba(255, 255, 255, 0.1);
color: #f4f4f5;
background: var(--ml-fill);
color: var(--ml-text);
font-size: 11px;
font-weight: 600;
text-decoration: none;
@@ -258,7 +299,7 @@
}
.mob-lib-studio-link:active {
background: rgba(255, 255, 255, 0.2);
background: var(--ml-fill-active);
}
/* --- Main Content Area --- */
@@ -289,7 +330,7 @@
padding: 14px 12px 8px;
font-size: 16px;
font-weight: 600;
color: #f4f4f5;
color: var(--ml-text);
letter-spacing: -0.01em;
}
@@ -297,7 +338,7 @@
width: 22px;
height: 22px;
border-radius: 50%;
border: 1.5px solid rgba(255, 255, 255, 0.3);
border: 1.5px solid var(--ml-grip);
display: flex;
align-items: center;
justify-content: center;
@@ -311,7 +352,7 @@
.mob-lib-date-check.checked {
background: var(--accent, #f59e0b);
border-color: var(--accent, #f59e0b);
color: #000;
color: var(--accent-fg);
}
/* --- 3-Column Photo Grid --- */
@@ -324,7 +365,7 @@
.mob-lib-thumb-cell {
position: relative;
aspect-ratio: 1;
background: #1c1c22;
background: var(--ml-panel-2);
overflow: hidden;
cursor: pointer;
touch-action: manipulation;
@@ -334,7 +375,7 @@
/* The frame the reader stopped at in the preview, lit up in the grid. */
.mob-lib-thumb-cell.selected {
outline: 2px solid #f59e0b;
outline: 2px solid var(--accent);
outline-offset: -2px;
}
@@ -385,7 +426,7 @@
padding: 1px 4px;
border-radius: 4px;
font-size: 10px;
color: #fbbf24;
color: var(--accent);
backdrop-filter: blur(4px);
pointer-events: none;
}
@@ -402,13 +443,13 @@
align-items: center;
justify-content: center;
gap: 5px;
background: rgba(28, 30, 38, 0.92);
background: var(--ml-popover);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border: 1px solid rgba(255, 255, 255, 0.22);
border: 1px solid var(--ml-line-stronger);
border-radius: 999px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.6);
color: #ffffff;
color: var(--ml-text);
cursor: grab;
user-select: none;
-webkit-user-select: none;
@@ -426,8 +467,8 @@
.mob-lib-scroll-handle:active {
cursor: grabbing;
transform: scale(1.08);
background: rgba(45, 48, 62, 0.98);
border-color: rgba(255, 255, 255, 0.4);
background: var(--ml-panel-2);
border-color: var(--ml-grip);
}
.mob-lib-scroll-arrow {
@@ -435,7 +476,7 @@
align-items: center;
justify-content: center;
pointer-events: none;
color: #f4f4f5;
color: var(--ml-text);
opacity: 0.9;
}
@@ -454,7 +495,7 @@
.mob-lib-search-icon {
position: absolute;
left: 12px;
color: #71717a;
color: var(--ml-dim-2);
pointer-events: none;
}
@@ -462,9 +503,9 @@
width: 100%;
padding: 10px 36px 10px 38px;
border-radius: 999px;
border: 1px solid rgba(255, 255, 255, 0.12);
background: #1c1c22;
color: #ffffff;
border: 1px solid var(--ml-line-strong);
background: var(--ml-panel);
color: var(--ml-text);
font-size: 14px;
outline: none;
transition: border-color 0.2s;
@@ -479,7 +520,7 @@
right: 12px;
background: transparent;
border: none;
color: #71717a;
color: var(--ml-dim-2);
cursor: pointer;
padding: 4px;
display: flex;
@@ -504,15 +545,15 @@
border-radius: 999px;
font-size: 12px;
font-weight: 500;
border: 1px solid rgba(255, 255, 255, 0.12);
background: #1c1c22;
color: #d4d4d8;
border: 1px solid var(--ml-line-strong);
background: var(--ml-panel);
color: var(--ml-text-3);
cursor: pointer;
}
.mob-lib-chip.active {
background: var(--accent, #f59e0b);
color: #000000;
color: var(--accent-fg);
border-color: var(--accent, #f59e0b);
font-weight: 600;
}
@@ -522,10 +563,10 @@
position: sticky;
top: 0;
z-index: 30;
background: rgba(16, 16, 20, 0.95);
background: var(--ml-bg-blur);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
border-bottom: 1px solid var(--ml-line);
padding: 10px 14px;
display: flex;
flex-direction: column;
@@ -534,9 +575,9 @@
}
.mob-lib-search-close-btn {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.15);
color: #e4e4e7;
background: var(--ml-fill);
border: 1px solid var(--ml-line-strong);
color: var(--ml-text-2);
font-size: 13px;
font-weight: 600;
width: 34px;
@@ -553,7 +594,7 @@
}
.mob-lib-search-close-btn:active {
background: rgba(255, 255, 255, 0.2);
background: var(--ml-fill-active);
}
/* --- Search Top Row with Input, View Mode Toggle, and Close --- */
@@ -567,8 +608,8 @@
.mob-lib-view-toggle {
display: inline-flex;
align-items: center;
background: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.12);
background: var(--ml-fill);
border: 1px solid var(--ml-line-strong);
border-radius: 8px;
padding: 2px;
flex-shrink: 0;
@@ -584,7 +625,7 @@
border-radius: 6px;
border: none;
background: transparent;
color: #a1a1aa;
color: var(--ml-dim);
cursor: pointer;
transition: all 0.15s ease;
padding: 0;
@@ -595,8 +636,8 @@
}
.mob-lib-view-btn.active {
background: rgba(255, 255, 255, 0.22);
color: #ffffff;
background: var(--ml-fill-active);
color: var(--ml-text);
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
}
@@ -617,7 +658,7 @@
.mob-lib-filter-scope-label {
font-size: 11px;
font-weight: 600;
color: #a1a1aa;
color: var(--ml-dim);
text-transform: uppercase;
letter-spacing: 0.5px;
flex-shrink: 0;
@@ -632,9 +673,9 @@
border-radius: 9999px;
font-size: 12px;
font-weight: 500;
color: #a1a1aa;
background: rgba(255, 255, 255, 0.06);
border: 1px solid rgba(255, 255, 255, 0.12);
color: var(--ml-dim);
background: var(--ml-fill);
border: 1px solid var(--ml-line-strong);
cursor: pointer;
white-space: nowrap;
flex-shrink: 0;
@@ -648,7 +689,7 @@
.mob-lib-scope-pill.active {
background: rgba(59, 130, 246, 0.2);
border-color: rgba(59, 130, 246, 0.6);
color: #60a5fa;
color: var(--ml-blue);
font-weight: 600;
box-shadow: 0 1px 4px rgba(59, 130, 246, 0.2);
}
@@ -673,13 +714,13 @@
display: inline-flex;
align-items: center;
flex-shrink: 0;
background: rgba(255, 255, 255, 0.07);
border: 1px solid rgba(255, 255, 255, 0.15);
background: var(--ml-fill);
border: 1px solid var(--ml-line-strong);
border-radius: 8px;
padding: 0 8px;
height: 32px;
font-size: 12px;
color: #e4e4e7;
color: var(--ml-text-2);
cursor: pointer;
transition: all 0.15s ease;
white-space: nowrap;
@@ -689,7 +730,7 @@
.mob-lib-dropbox-btn.active {
background: rgba(245, 158, 11, 0.18);
border-color: rgba(245, 158, 11, 0.6);
color: #fbbf24;
color: var(--accent);
font-weight: 600;
}
@@ -699,13 +740,13 @@
align-items: center;
gap: 4px;
flex-shrink: 0;
background: rgba(255, 255, 255, 0.07);
border: 1px solid rgba(255, 255, 255, 0.15);
background: var(--ml-fill);
border: 1px solid var(--ml-line-strong);
border-radius: 8px;
padding: 0 10px;
height: 32px;
font-size: 12px;
color: #e4e4e7;
color: var(--ml-text-2);
cursor: pointer;
transition: all 0.15s ease;
white-space: nowrap;
@@ -714,7 +755,7 @@
.mob-lib-dropbox-btn.open {
border-color: rgba(96, 165, 250, 0.7);
background: rgba(59, 130, 246, 0.18);
color: #93c5fd;
color: var(--ml-blue-2);
}
.mob-lib-dropbox-select {
@@ -732,8 +773,8 @@
}
.mob-lib-dropbox-select option {
background: #1c1c24;
color: #ffffff;
background: var(--ml-panel);
color: var(--ml-text);
}
.mob-lib-dropbox-caret {
@@ -746,8 +787,8 @@
/* --- Popover Card for Year/Month/Date & Time --- */
.mob-lib-popover-card {
margin-top: 4px;
background: #18181f;
border: 1px solid rgba(255, 255, 255, 0.14);
background: var(--ml-panel);
border: 1px solid var(--ml-line-strong);
border-radius: 12px;
padding: 12px;
display: flex;
@@ -777,14 +818,14 @@
.mob-lib-popover-title {
font-size: 12px;
font-weight: 700;
color: #d4d4d8;
color: var(--ml-text-3);
letter-spacing: 0.02em;
}
.mob-lib-popover-reset-btn {
background: transparent;
border: none;
color: #ef4444;
color: var(--ml-red);
font-size: 11px;
font-weight: 600;
cursor: pointer;
@@ -817,14 +858,14 @@
.mob-lib-popover-label {
font-size: 10px;
font-weight: 600;
color: #a1a1aa;
color: var(--ml-dim);
text-transform: uppercase;
}
.mob-lib-popover-select {
background: rgba(255, 255, 255, 0.07);
border: 1px solid rgba(255, 255, 255, 0.14);
color: #ffffff;
background: var(--ml-fill);
border: 1px solid var(--ml-line-strong);
color: var(--ml-text);
border-radius: 8px;
padding: 6px 8px;
font-size: 12px;
@@ -832,8 +873,8 @@
}
.mob-lib-popover-select option {
background: #1c1c24;
color: #ffffff;
background: var(--ml-panel);
color: var(--ml-text);
}
.mob-lib-popover-footer {
@@ -842,9 +883,9 @@
}
.mob-lib-popover-done-btn {
background: rgba(255, 255, 255, 0.12);
border: 1px solid rgba(255, 255, 255, 0.18);
color: #ffffff;
background: var(--ml-fill-strong);
border: 1px solid var(--ml-line-stronger);
color: var(--ml-text);
font-size: 11px;
font-weight: 600;
padding: 5px 14px;
@@ -853,7 +894,7 @@
}
.mob-lib-popover-done-btn:active {
background: rgba(255, 255, 255, 0.24);
background: var(--ml-fill-active);
}
/* --- Single Photo Mode (1 large card per row) --- */
@@ -865,8 +906,8 @@
}
.mob-lib-single-card {
background: rgba(255, 255, 255, 0.035);
border: 1px solid rgba(255, 255, 255, 0.08);
background: var(--ml-fill-faint);
border: 1px solid var(--ml-line);
border-radius: 14px;
overflow: hidden;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.35);
@@ -878,14 +919,14 @@
.mob-lib-single-card:active {
transform: scale(0.99);
border-color: rgba(255, 255, 255, 0.2);
border-color: var(--ml-line-stronger);
}
.mob-lib-single-img-wrap {
position: relative;
width: 100%;
aspect-ratio: 4 / 3;
background: #09090b;
background: var(--ml-sunken);
display: flex;
align-items: center;
justify-content: center;
@@ -913,13 +954,13 @@
display: flex;
flex-direction: column;
gap: 4px;
background: rgba(18, 18, 22, 0.7);
background: var(--ml-bg-soft);
}
.mob-lib-single-name {
font-size: 13px;
font-weight: 600;
color: #ffffff;
color: var(--ml-text);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@@ -927,7 +968,7 @@
.mob-lib-single-date {
font-size: 11px;
color: #a1a1aa;
color: var(--ml-dim);
}
/* --- Album Folder Tree Column (Desktop style on Mobile) --- */
@@ -944,22 +985,22 @@
align-items: center;
justify-content: space-between;
padding: 8px 12px;
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(255, 255, 255, 0.07);
background: var(--ml-fill-faint);
border: 1px solid var(--ml-line-soft);
border-radius: 10px;
}
.mob-lib-tree-toolbar-title {
font-size: 13px;
font-weight: 700;
color: #f4f4f5;
color: var(--ml-text);
}
.mob-lib-tree-list {
display: flex;
flex-direction: column;
background: rgba(255, 255, 255, 0.02);
border: 1px solid rgba(255, 255, 255, 0.07);
background: var(--ml-fill-faint);
border: 1px solid var(--ml-line-soft);
border-radius: 12px;
overflow: hidden;
}
@@ -969,11 +1010,11 @@
align-items: center;
gap: 8px;
padding: 11px 12px;
color: #d4d4d8;
color: var(--ml-text-3);
cursor: pointer;
user-select: none;
-webkit-user-select: none;
border-bottom: 1px solid rgba(255, 255, 255, 0.04);
border-bottom: 1px solid var(--ml-line-faint);
transition: background 0.15s, color 0.15s;
}
@@ -982,12 +1023,12 @@
}
.mob-lib-tree-row:active {
background: rgba(255, 255, 255, 0.08);
background: var(--ml-fill);
}
.mob-lib-tree-row.selected {
background: rgba(245, 158, 11, 0.15);
color: #f59e0b;
color: var(--accent);
}
.mob-lib-tree-caret {
@@ -996,7 +1037,7 @@
height: 0;
border-top: 5px solid transparent;
border-bottom: 5px solid transparent;
border-left: 7px solid rgba(255, 255, 255, 0.6);
border-left: 7px solid var(--ml-grip-strong);
transition: transform 0.15s;
flex-shrink: 0;
cursor: pointer;
@@ -1031,8 +1072,8 @@
.mob-lib-tree-count {
font-size: 11px;
font-family: var(--mono, ui-monospace, monospace);
color: #71717a;
background: rgba(255, 255, 255, 0.06);
color: var(--ml-dim-2);
background: var(--ml-fill);
padding: 2px 7px;
border-radius: 999px;
flex-shrink: 0;
@@ -1041,7 +1082,7 @@
.mob-lib-tree-more-btn {
background: transparent;
border: none;
color: #a1a1aa;
color: var(--ml-dim);
font-size: 18px;
padding: 4px 8px;
cursor: pointer;
@@ -1051,8 +1092,8 @@
}
.mob-lib-tree-more-btn:active {
background: rgba(255, 255, 255, 0.12);
color: #ffffff;
background: var(--ml-fill-strong);
color: var(--ml-text);
}
/* --- Context Menu Backdrop & Panel --- */
@@ -1068,8 +1109,8 @@
z-index: 61;
min-width: 200px;
padding: 6px;
background: #1c1c24;
border: 1px solid rgba(255, 255, 255, 0.15);
background: var(--ml-panel);
border: 1px solid var(--ml-line-strong);
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.8);
display: flex;
@@ -1087,10 +1128,10 @@
padding: 6px 10px 6px;
font-size: 11px;
font-weight: 700;
color: #a1a1aa;
color: var(--ml-dim);
text-transform: uppercase;
letter-spacing: 0.04em;
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
border-bottom: 1px solid var(--ml-line-soft);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@@ -1110,8 +1151,8 @@
.mob-lib-album-card {
display: flex;
flex-direction: column;
background: #18181e;
border: 1px solid rgba(255, 255, 255, 0.08);
background: var(--ml-panel);
border: 1px solid var(--ml-line);
border-radius: 12px;
overflow: hidden;
cursor: pointer;
@@ -1126,7 +1167,7 @@
.mob-lib-album-cover {
width: 100%;
aspect-ratio: 1;
background: #23232b;
background: var(--ml-panel-2);
position: relative;
overflow: hidden;
}
@@ -1144,7 +1185,7 @@
display: flex;
align-items: center;
justify-content: center;
color: #71717a;
color: var(--ml-dim-2);
}
.mob-lib-album-info {
@@ -1157,7 +1198,7 @@
.mob-lib-album-title {
font-size: 14px;
font-weight: 600;
color: #f4f4f5;
color: var(--ml-text);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@@ -1165,7 +1206,7 @@
.mob-lib-album-count {
font-size: 12px;
color: #a1a1aa;
color: var(--ml-dim);
}
/* --- Library / Cloud Management View --- */
@@ -1177,8 +1218,8 @@
}
.mob-lib-card {
background: #18181e;
border: 1px solid rgba(255, 255, 255, 0.08);
background: var(--ml-panel);
border: 1px solid var(--ml-line);
border-radius: 14px;
padding: 16px;
display: flex;
@@ -1195,7 +1236,7 @@
.mob-lib-card-title {
font-size: 15px;
font-weight: 600;
color: #f4f4f5;
color: var(--ml-text);
display: flex;
align-items: center;
gap: 8px;
@@ -1207,7 +1248,7 @@
gap: 4px;
font-size: 11px;
font-weight: 600;
color: #34d399;
color: var(--ml-green);
background: rgba(52, 211, 153, 0.12);
padding: 2px 8px;
border-radius: 999px;
@@ -1218,12 +1259,12 @@
width: 6px;
height: 6px;
border-radius: 50%;
background: #34d399;
background: var(--ml-green);
}
.mob-lib-card-meta {
font-size: 12px;
color: #a1a1aa;
color: var(--ml-dim);
display: flex;
flex-direction: column;
gap: 4px;
@@ -1245,9 +1286,9 @@
border-radius: 8px;
font-size: 12px;
font-weight: 600;
border: 1px solid rgba(255, 255, 255, 0.12);
background: #23232b;
color: #f4f4f5;
border: 1px solid var(--ml-line-strong);
background: var(--ml-panel-2);
color: var(--ml-text);
cursor: pointer;
transition: all 0.2s;
}
@@ -1258,13 +1299,13 @@
.mob-lib-btn.primary {
background: var(--accent, #f59e0b);
color: #000000;
color: var(--accent-fg);
border-color: var(--accent, #f59e0b);
}
.mob-lib-btn.danger {
background: rgba(239, 68, 68, 0.15);
color: #f87171;
color: var(--ml-red);
border-color: rgba(239, 68, 68, 0.3);
}
@@ -1311,19 +1352,19 @@
text-align: center;
padding: 48px 24px;
gap: 14px;
color: #a1a1aa;
color: var(--ml-dim);
}
.mob-lib-empty-icon {
width: 48px;
height: 48px;
color: #52525b;
color: var(--ml-dim-3);
}
.mob-lib-empty-title {
font-size: 16px;
font-weight: 600;
color: #e4e4e7;
color: var(--ml-text-2);
}
.mob-lib-empty-desc {
@@ -1341,8 +1382,8 @@
z-index: 40;
height: calc(60px + env(safe-area-inset-bottom));
padding-bottom: env(safe-area-inset-bottom);
background: #18181b;
border-top: 1px solid rgba(255, 255, 255, 0.08);
background: var(--ml-panel);
border-top: 1px solid var(--ml-line);
display: flex;
align-items: center;
justify-content: space-around;
@@ -1358,7 +1399,7 @@
gap: 3px;
background: transparent;
border: none;
color: rgba(255, 255, 255, 0.55);
color: var(--ml-faint);
cursor: pointer;
padding: 6px 0;
text-decoration: none;
@@ -1375,11 +1416,11 @@
}
.mob-lib-tab-item.active .mob-lib-tab-pill {
background: rgba(255, 255, 255, 0.14);
background: var(--ml-fill-strong);
}
.mob-lib-tab-item.active {
color: #ffffff;
color: var(--ml-text);
}
.mob-lib-tab-label {
@@ -1391,7 +1432,7 @@
.mob-lib-tab-item.active .mob-lib-tab-label {
font-weight: 600;
color: #ffffff;
color: var(--ml-text);
}
/* --- Fullscreen Photo Preview Modal --- */
@@ -1399,7 +1440,7 @@
position: fixed;
inset: 0;
z-index: 60;
background: #09090b;
background: var(--ml-sunken);
display: flex;
flex-direction: column;
overflow: hidden;
@@ -1416,9 +1457,9 @@
align-items: center;
justify-content: space-between;
padding: max(10px, env(safe-area-inset-top)) 16px 10px;
background: rgba(9, 9, 11, 0.85);
background: var(--ml-bg-blur);
backdrop-filter: blur(16px);
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
border-bottom: 1px solid var(--ml-line);
flex-shrink: 0;
z-index: 10;
}
@@ -1426,7 +1467,7 @@
.mob-lib-preview-title {
font-size: 14px;
font-weight: 600;
color: #f4f4f5;
color: var(--ml-text);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@@ -1456,9 +1497,9 @@
flex-direction: column;
gap: 12px;
padding: 12px 16px max(14px, env(safe-area-inset-bottom));
background: rgba(9, 9, 11, 0.9);
background: var(--ml-bg-blur);
backdrop-filter: blur(16px);
border-top: 1px solid rgba(255, 255, 255, 0.08);
border-top: 1px solid var(--ml-line);
flex-shrink: 0;
z-index: 10;
}
@@ -1478,14 +1519,14 @@
background: transparent;
border: none;
font-size: 20px;
color: rgba(255, 255, 255, 0.25);
color: var(--ml-dim-3);
cursor: pointer;
padding: 4px;
line-height: 1;
}
.mob-lib-star-btn.active {
color: #fbbf24;
color: var(--accent);
}
.mob-lib-preview-rot-btns {
@@ -1501,7 +1542,7 @@
font-weight: 700;
letter-spacing: 0.03em;
background: var(--accent, #f59e0b);
color: #000000;
color: var(--accent-fg);
border: none;
cursor: pointer;
display: flex;
@@ -1521,9 +1562,9 @@
flex-direction: column;
gap: 3px;
font-size: 11.5px;
color: #a1a1aa;
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(255, 255, 255, 0.07);
color: var(--ml-dim);
background: var(--ml-fill-faint);
border: 1px solid var(--ml-line-soft);
border-radius: 10px;
padding: 9px 12px;
min-width: 0;
@@ -1533,7 +1574,7 @@
}
.mob-lib-meta-name {
color: #f4f4f5;
color: var(--ml-text);
font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace);
font-size: 12.5px;
font-weight: 700;
@@ -1550,11 +1591,11 @@
}
.mob-lib-meta-place {
color: #60a5fa;
color: var(--ml-blue);
}
.mob-lib-meta-specs {
color: #e4e4e7;
color: var(--ml-text-2);
font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace);
font-size: 11px;
}
+17 -17
View File
@@ -841,7 +841,7 @@ export function MobileLibrary({
{user?.avatar ? (
<img src={user.avatar} alt="User" />
) : (
<span style={{ fontSize: '12px', fontWeight: 700, color: '#f4f4f5' }}>
<span style={{ fontSize: '12px', fontWeight: 700, color: 'var(--ml-text)' }}>
{(user?.email || 'U').charAt(0).toUpperCase()}
</span>
)}
@@ -869,7 +869,7 @@ export function MobileLibrary({
<button
type="button"
className="mob-lib-studio-link"
style={{ background: 'transparent', border: '1px solid rgba(255,255,255,0.2)', cursor: 'pointer' }}
style={{ background: 'transparent', border: '1px solid var(--ml-line-stronger)', cursor: 'pointer' }}
onClick={onSwitchToDesktop}
title="Chuyển sang giao diện Desktop"
>
@@ -1461,7 +1461,7 @@ export function MobileLibrary({
style={{
textAlign: 'center',
padding: '16px 0 24px',
color: '#71717a',
color: 'var(--ml-dim-2)',
fontSize: '12px',
}}
>
@@ -1743,7 +1743,7 @@ export function MobileLibrary({
)}
{/* Search Results Summary */}
<div style={{ fontSize: '13px', color: '#a1a1aa', margin: '4px 0 10px' }}>
<div style={{ fontSize: '13px', color: 'var(--ml-dim)', margin: '4px 0 10px' }}>
{t('lib.count', { n: searchResults.length })}
</div>
@@ -1846,8 +1846,8 @@ export function MobileLibrary({
alignItems: 'center',
gap: '8px',
padding: '8px 12px',
background: 'rgba(24, 24, 27, 0.95)',
borderBottom: '1px solid rgba(255, 255, 255, 0.08)',
background: 'var(--ml-bg-blur)',
borderBottom: '1px solid var(--ml-line)',
position: 'sticky',
top: 0,
zIndex: 10,
@@ -1859,10 +1859,10 @@ export function MobileLibrary({
display: 'flex',
alignItems: 'center',
flex: 1,
background: 'rgba(255, 255, 255, 0.06)',
background: 'var(--ml-fill)',
borderRadius: '8px',
padding: '6px 10px',
border: '1px solid rgba(255, 255, 255, 0.1)',
border: '1px solid var(--ml-fill)',
}}
>
<svg
@@ -1872,7 +1872,7 @@ export function MobileLibrary({
fill="none"
stroke="currentColor"
strokeWidth="2"
style={{ color: '#a1a1aa', marginRight: '8px', flexShrink: 0 }}
style={{ color: 'var(--ml-dim)', marginRight: '8px', flexShrink: 0 }}
>
<circle cx="11" cy="11" r="8" />
<line x1="21" y1="21" x2="16.65" y2="16.65" />
@@ -1886,7 +1886,7 @@ export function MobileLibrary({
style={{
background: 'transparent',
border: 'none',
color: '#ffffff',
color: 'var(--ml-text)',
fontSize: '13px',
width: '100%',
outline: 'none',
@@ -1899,7 +1899,7 @@ export function MobileLibrary({
style={{
background: 'transparent',
border: 'none',
color: '#71717a',
color: 'var(--ml-dim-2)',
cursor: 'pointer',
padding: '2px',
fontSize: '12px',
@@ -1960,7 +1960,7 @@ export function MobileLibrary({
<div className="mob-lib-tree-list">
{showSearch && searchQuery.trim() && treeRows.length === 0 && (
<div style={{ padding: '24px 16px', textAlign: 'center', color: '#71717a', fontSize: '13px' }}>
<div style={{ padding: '24px 16px', textAlign: 'center', color: 'var(--ml-dim-2)', fontSize: '13px' }}>
Không tìm thấy album hoặc thư mục nào khớp với &quot;{searchQuery}&quot;
</div>
)}
@@ -2106,10 +2106,10 @@ export function MobileLibrary({
<path d="M50 50 C25 50, 10 25, 25 10 C40 -5, 65 10, 65 35 Z" fill="#4285f4" />
</svg>
<div>
<div style={{ fontSize: '16px', fontWeight: 700, color: '#ffffff' }}>
<div style={{ fontSize: '16px', fontWeight: 700, color: 'var(--ml-text)' }}>
IMMICH CLOUD
</div>
<div style={{ fontSize: '12px', color: '#a1a1aa', marginTop: '4px', lineHeight: 1.4 }}>
<div style={{ fontSize: '12px', color: 'var(--ml-dim)', marginTop: '4px', lineHeight: 1.4 }}>
{t('lib.mobile.cloudDesc')}
</div>
</div>
@@ -2123,12 +2123,12 @@ export function MobileLibrary({
</div>
{/* Connected Servers List */}
<div style={{ fontSize: '13px', fontWeight: 700, color: '#a1a1aa', letterSpacing: '0.05em' }}>
<div style={{ fontSize: '13px', fontWeight: 700, color: 'var(--ml-dim)', letterSpacing: '0.05em' }}>
{t('lib.mobile.servers')}
</div>
{servers.length === 0 ? (
<div className="mob-lib-card" style={{ textAlign: 'center', color: '#71717a' }}>
<div className="mob-lib-card" style={{ textAlign: 'center', color: 'var(--ml-dim-2)' }}>
{t('lib.mobile.noServers')}
</div>
) : (
@@ -2475,7 +2475,7 @@ export function MobileLibrary({
</>
) : null}
<div style={{ height: '1px', background: 'rgba(255, 255, 255, 0.08)', margin: '4px 0' }} />
<div style={{ height: '1px', background: 'var(--ml-line)', margin: '4px 0' }} />
<button
type="button"