diff options
Diffstat (limited to 'src/components/connections/ConnectionTable.module.scss')
| -rw-r--r-- | src/components/connections/ConnectionTable.module.scss | 485 |
1 files changed, 315 insertions, 170 deletions
diff --git a/src/components/connections/ConnectionTable.module.scss b/src/components/connections/ConnectionTable.module.scss index e8e3daf..11280aa 100644 --- a/src/components/connections/ConnectionTable.module.scss +++ b/src/components/connections/ConnectionTable.module.scss @@ -1,256 +1,401 @@ -.tr { - transition: all 0.2s ease; - cursor: pointer; +.card { display: flex; - align-items: stretch; - width: 100%; - min-width: fit-content; - - &:hover { - // hover 作用到每个 td,避免 odd 行背景覆盖 - .td { - background: rgba(66, 133, 244, 0.08); - } + flex-direction: column; + flex: 1; + min-height: 0; + position: relative; + border-radius: 16px; + background: var(--color-card); + border: 1px solid var(--color-card-border); + box-shadow: var(--shadow-card); + overflow: hidden; - .odd { - background: rgba(66, 133, 244, 0.08); - } + @media (max-width: 768px) { + background: transparent; + border: none; + box-shadow: none; + border-radius: 0; } } -.th { - height: 48px; - background: var(--bg-log-info-card); - top: 0; - font-size: 0.8em; +.body { + flex: 1; + min-height: 0; + min-width: 0; + display: flex; + flex-direction: column; +} + +/* ---------- 表头 ---------- */ + +.headWrap { + overflow: hidden; + flex-shrink: 0; + background: var(--color-track); + border-bottom: 1px solid var(--color-card-border); +} + +// 列间距和左右内边距由 ConnectionTable 的 COLUMN_GAP / ROW_PADDING_X 内联施加, +// 因为列宽计算必须扣掉它们,写在这里两边会不同步 +.headRow { + display: grid; + align-items: center; + height: 42px; +} + +.headCell { + display: flex; + align-items: center; + gap: 3px; + min-width: 0; + font-size: 0.72rem; font-weight: 600; - user-select: none; - text-transform: uppercase; - letter-spacing: 0.5px; + letter-spacing: 0.02em; color: var(--color-text-secondary); - border-bottom: 2px solid var(--color-separator); - position: sticky; - z-index: 20; - padding: 0 8px; white-space: nowrap; - overflow: hidden; - flex-shrink: 0; // Ensure fixed width is respected + user-select: none; + + &:focus-visible { + outline: 2px solid var(--color-focus-blue); + outline-offset: -2px; + border-radius: 4px; + } +} + +.headCellSortable { + cursor: pointer; &:hover { color: var(--color-text-highlight); } } -.headerText { - overflow: hidden; - text-overflow: ellipsis; +.headCellActive { + color: var(--color-focus-blue); + + &:hover { + color: var(--color-focus-blue); + } } -.cellText { +.headText { overflow: hidden; text-overflow: ellipsis; - width: 100%; } -.sortIconContainer { - margin-left: 4px; +.headArrow { + font-size: 0.62rem; flex-shrink: 0; - display: flex; - align-items: center; } -.rotate180 { - transform: rotate(180deg); +/* ---------- 行 ---------- */ + +.listWrap { + flex: 1; + min-height: 0; + min-width: 0; } -.btnSection { - button { - margin-right: 15px; - } +.list { + overflow-x: auto; } -.break { - word-wrap: break-word; - word-break: break-all; - align-items: center; - text-align: left; +.mobileList { + overflow-x: hidden; } -.td { - padding: 0 8px; - font-size: 0.875em; - cursor: pointer; - vertical-align: middle; - white-space: nowrap; +.rowWrap { border-bottom: 1px solid var(--color-separator); - transition: color 0.15s ease; - box-sizing: border-box; - flex-shrink: 0; // Ensure fixed width is respected +} + +// 同上,gap / padding 见 ConnectionTable 的常量 +.row { + display: grid; + align-items: center; + height: 44px; + cursor: pointer; + user-select: none; &:hover { - color: var(--color-text-highlight); + background: var(--color-hover-soft); } - font-family: var(--font-normal); + &:focus-visible { + outline: 2px solid var(--color-focus-blue); + outline-offset: -2px; + } } -.overlay { - background: #444; +.cell { + display: flex; + align-items: center; + gap: 8px; + min-width: 0; } -.modal { - background-color: var(--bg-modal); +.cellRight { + justify-content: flex-end; } -.table { - border-collapse: separate; - border-spacing: 0; - width: 100%; - background: transparent; +/* ---------- 单元格内容 ---------- */ - @media (max-width: 768px) { - display: none; +.closeBtn { + display: inline-flex; + align-items: center; + justify-content: center; + appearance: none; + width: 22px; + height: 22px; + padding: 0; + border: none; + border-radius: 50%; + background: var(--color-badge-bg); + color: var(--color-text-secondary); + cursor: pointer; + transition: + background-color 0.15s ease, + color 0.15s ease; + + &:hover { + background: var(--color-danger-soft-bg); + color: var(--color-danger); } } -.tableWrapper { - margin-top: 0; - border-radius: 12px; - overflow: hidden; - background: transparent; - box-shadow: none; +.dot { + flex: 0 0 7px; + width: 7px; + height: 7px; + border-radius: 50%; +} - @media (max-width: 768px) { - background: transparent; - box-shadow: none; +.dotBusy { + background: var(--color-success); + box-shadow: 0 0 0 3px var(--color-success-soft-bg); + animation: pulseDot 2.4s ease-in-out infinite; +} + +.dotIdle { + background: var(--color-text-secondary); + opacity: 0.4; +} + +@keyframes pulseDot { + 0%, + 100% { + opacity: 1; + transform: scale(1); + } + 50% { + opacity: 0.45; + transform: scale(0.82); } } -.theadWrapper { - width: 100%; +.hostText { + font-size: 0.82rem; + font-weight: 500; + color: var(--color-text-highlight); overflow: hidden; - background: var(--bg-log-info-card); - border-top-left-radius: 12px; - border-top-right-radius: 12px; + text-overflow: ellipsis; + white-space: nowrap; +} + +.chip { + display: inline-block; + max-width: 100%; + padding: 3px 8px; + border-radius: 7px; + font-size: 0.7rem; + line-height: 1.4; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } -.cardsView { - display: none; +.chipTcp { + background: var(--color-accent-soft-bg); + color: var(--color-accent-soft-fg); +} - @media (max-width: 768px) { - display: block; - padding: 0 4px; - } +.chipUdp { + background: var(--color-udp-bg); + color: var(--color-udp-fg); } -.mobileSortToolbar { - display: flex; - align-items: center; - gap: 12px; - padding: 0; - margin-bottom: 12px; +.chipNeutral { + background: var(--color-badge-bg); + color: var(--color-badge-fg); } -.sortSelectWrapper { - display: flex; - align-items: center; - gap: 10px; - flex: 1; - background: var(--color-bg-card); - padding: 8px 12px; - border-radius: 12px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); +.chainGroup, +.chainFull { + font-size: 0.76rem; + color: var(--color-text-secondary); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.chainSep { + flex: 0 0 auto; + font-size: 0.7rem; + color: var(--color-text-secondary); + opacity: 0.6; +} + +.chainNode { + font-size: 0.76rem; + font-weight: 500; color: var(--color-focus-blue); - position: relative; - border: 1px solid var(--color-bg-card-border, rgba(0, 0, 0, 0.05)); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} - select { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - opacity: 0; - cursor: pointer; - z-index: 2; - } +.chainDirect { + color: var(--color-success); +} - .selectedValue { - flex: 1; - display: flex; - align-items: center; - gap: 8px; - font-size: 0.95rem; - font-weight: 600; - color: var(--color-text); - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } +.chainReject { + color: var(--color-danger); } -.selectArrow { - opacity: 0.5; +.num { + font-size: 0.75rem; color: var(--color-text-secondary); - flex-shrink: 0; + font-variant-numeric: tabular-nums; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } -.sortDirBtn { - background: var(--color-bg-card); - border: 1px solid var(--color-bg-card-border, rgba(0, 0, 0, 0.05)); +.speed { + font-size: 0.76rem; + font-weight: 500; + font-variant-numeric: tabular-nums; + white-space: nowrap; +} + +.speedDl { + color: var(--color-success); +} + +.speedUl { color: var(--color-focus-blue); +} + +.speedDim { + color: var(--color-text-secondary); + opacity: 0.55; +} + +/* ---------- 空态 ---------- */ + +.empty { display: flex; + flex-direction: column; align-items: center; justify-content: center; - width: 38px; - height: 38px; - border-radius: 12px; - cursor: pointer; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); - transition: all 0.2s ease; + gap: 6px; + height: 100%; +} - &:active { - transform: scale(0.95); - background: var(--color-bg-secondary); - } +.emptyTitle { + font-size: 0.88rem; + color: var(--color-text); } -.table thead tr:first-child th:first-child { - border-top-left-radius: 12px; +.emptyHint { + font-size: 0.78rem; + color: var(--color-text-secondary); } -.table thead tr:first-child th:last-child { - border-top-right-radius: 12px; +/* ---------- 页脚 ---------- */ + +.footer { + display: flex; + align-items: center; + gap: 14px; + height: 36px; + flex-shrink: 0; + padding: 0 18px; + border-top: 1px solid var(--color-card-border); + background: var(--color-track); + font-size: 0.72rem; + color: var(--color-text-secondary); + white-space: nowrap; + overflow: hidden; } -.table tbody tr:last-child td:first-child { - border-bottom-left-radius: 12px; +.footerNote { + margin-left: auto; + overflow: hidden; + text-overflow: ellipsis; + + @media (max-width: 768px) { + display: none; + } } -.table tbody tr:last-child td:last-child { - border-bottom-right-radius: 12px; +/* ---------- 移动端排序工具条 ---------- */ + +.mobileToolbar { + display: flex; + align-items: center; + gap: 8px; + height: 42px; + flex-shrink: 0; } -.td.odd { - background: var(--color-row-odd); +.sortSelect { + position: relative; + display: flex; + align-items: center; + gap: 8px; + flex: 1; + min-width: 0; + height: 34px; + padding: 0 10px; + border-radius: 10px; + background: var(--color-card); + border: 1px solid var(--color-card-border); + color: var(--color-text); + font-size: 0.82rem; + + span { + flex: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + select { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + opacity: 0; + cursor: pointer; + } } -/* download upload td cells */ -.center { - min-width: 7em; - text-align: center; +.sortSelectArrow { + flex-shrink: 0; + color: var(--color-text-secondary); } -.sortIconContainer { - display: inline-flex; +.sortDirBtn { + display: flex; align-items: center; justify-content: center; - margin-left: 4px; - width: 16px; - height: 16px; - opacity: 0.7; -} - -.rotate180 { - transform: rotate(180deg); + width: 34px; + height: 34px; + flex-shrink: 0; + border-radius: 10px; + border: 1px solid var(--color-card-border); + background: var(--color-card); + color: var(--color-focus-blue); + cursor: pointer; } |
