diff --git a/web/src/assets/styles/components/document-list-shared.css b/web/src/assets/styles/components/document-list-shared.css index b8187c2..fa63b44 100644 --- a/web/src/assets/styles/components/document-list-shared.css +++ b/web/src/assets/styles/components/document-list-shared.css @@ -16,6 +16,7 @@ color: #64748b; font-size: 14px; font-weight: 750; + overflow: visible; } .status-tabs button.active { @@ -33,20 +34,33 @@ background: var(--theme-primary); } +.scope-tab-label { + position: relative; + display: inline-flex; + align-items: center; + line-height: 1.2; +} + .scope-tab-badge { - min-width: 18px; - height: 18px; + position: absolute; + top: -8px; + right: -15px; + min-width: 15px; + height: 15px; display: inline-flex; align-items: center; justify-content: center; - padding: 0 5px; + padding: 0 4px; + border: 1px solid #fff; border-radius: 999px; background: #ef4444; color: #fff; - font-size: 11px; + font-size: 10px; font-weight: 850; line-height: 1; - box-shadow: 0 6px 14px rgba(239, 68, 68, 0.22); + box-shadow: + 0 0 0 2px rgba(239, 68, 68, 0.1), + 0 6px 14px rgba(239, 68, 68, 0.22); } .document-toolbar { @@ -167,6 +181,38 @@ filter: none; } +.mark-read-btn { + min-height: 34px; + display: inline-flex; + align-items: center; + justify-content: center; + gap: 6px; + padding: 0 12px; + border: 1px solid #fecaca; + border-radius: 4px; + background: #fff; + color: #dc2626; + font-size: 13px; + font-weight: 800; + white-space: nowrap; + transition: + border-color 160ms ease, + background 160ms ease, + color 160ms ease, + box-shadow 160ms ease; +} + +.mark-read-btn .mdi { + font-size: 16px; +} + +.mark-read-btn:hover { + border-color: #fca5a5; + background: #fff5f5; + color: #b91c1c; + box-shadow: 0 8px 18px rgba(239, 68, 68, 0.1); +} + .table-wrap { min-height: 400px; margin-top: 10px; @@ -495,6 +541,7 @@ td small { .document-actions, .list-search, .filter-btn, + .mark-read-btn, .page-size-select { width: 100%; } diff --git a/web/src/assets/styles/components/sidebar-rail.css b/web/src/assets/styles/components/sidebar-rail.css index 5004b53..45654ea 100644 --- a/web/src/assets/styles/components/sidebar-rail.css +++ b/web/src/assets/styles/components/sidebar-rail.css @@ -216,11 +216,14 @@ flex: 1; min-width: 0; max-width: 128px; + position: relative; + display: inline-flex; + align-items: center; color: currentColor; font-size: 14px; font-weight: 700; white-space: nowrap; - overflow: hidden; + overflow: visible; opacity: 1; transition: max-width var(--rail-motion-duration) var(--rail-motion-ease), @@ -229,6 +232,16 @@ will-change: max-width, opacity, transform; } +.nav-label-text { + position: relative; + min-width: 0; + max-width: 100%; + display: inline-flex; + align-items: center; + overflow: visible; + line-height: 1.2; +} + .nav-badge { flex: 0 0 auto; min-width: 34px; @@ -251,13 +264,24 @@ } .nav-unread-dot { - flex: 0 0 auto; - width: 8px; - height: 8px; + width: 9px; + height: 9px; border: 2px solid #fff; border-radius: 999px; background: #ef4444; - box-shadow: 0 6px 14px rgba(239, 68, 68, 0.26); + box-shadow: + 0 0 0 3px rgba(239, 68, 68, 0.12), + 0 6px 14px rgba(239, 68, 68, 0.32); +} + +.nav-unread-dot-label { + position: absolute; + top: -8px; + right: -10px; +} + +.nav-unread-dot-collapsed { + display: none; } .rail-user { @@ -469,8 +493,13 @@ transition-delay: 0ms; } -.rail-collapsed .nav-unread-dot { +.rail-collapsed .nav-unread-dot-label { + display: none; +} + +.rail-collapsed .nav-unread-dot-collapsed { position: absolute; + display: block; top: 10px; right: 11px; width: 9px; diff --git a/web/src/components/layout/SidebarRail.vue b/web/src/components/layout/SidebarRail.vue index cbf3982..d37755c 100644 --- a/web/src/components/layout/SidebarRail.vue +++ b/web/src/components/layout/SidebarRail.vue @@ -50,8 +50,13 @@ @click="emit('navigate', item.id)" > - {{ item.displayLabel }} - + + + {{ item.displayLabel }} + + + + {{ item.badge }} diff --git a/web/src/utils/documentCenterNewState.js b/web/src/utils/documentCenterNewState.js index 2423174..87a9864 100644 --- a/web/src/utils/documentCenterNewState.js +++ b/web/src/utils/documentCenterNewState.js @@ -77,3 +77,26 @@ export function markDocumentViewed(row, viewedKeys, storage = getStorage()) { writeViewedDocumentKeys(nextKeys, storage) return nextKeys } + +export function markDocumentsViewed(rows, viewedKeys, storage = getStorage()) { + const nextKeys = new Set(viewedKeys) + let changed = false + + ;(Array.isArray(rows) ? rows : []).forEach((row) => { + if (!isNewDocument(row, nextKeys)) { + return + } + + const key = resolveDocumentNewKey(row) + if (key) { + nextKeys.add(key) + changed = true + } + }) + + if (changed) { + writeViewedDocumentKeys(nextKeys, storage) + } + + return nextKeys +} diff --git a/web/src/views/DocumentsCenterView.vue b/web/src/views/DocumentsCenterView.vue index 68a20af..cbd0107 100644 --- a/web/src/views/DocumentsCenterView.vue +++ b/web/src/views/DocumentsCenterView.vue @@ -9,9 +9,11 @@ :class="{ active: activeScopeTab === tab.value }" @click="activeScopeTab = tab.value" > - {{ tab.label }} - - {{ tab.badgeCount > 99 ? '99+' : tab.badgeCount }} + + {{ tab.label }} + + {{ tab.badgeCount > 99 ? '99+' : tab.badgeCount }} + @@ -122,7 +124,16 @@ -
+
+