refine Semi UI vehicle workspace
This commit is contained in:
@@ -181,7 +181,7 @@ export function AppShell() {
|
||||
</Dropdown>
|
||||
</div>
|
||||
</Header>
|
||||
<Content className={`v2-content${section === 'tracks' ? ' is-track-workspace' : ''}`}><Outlet /></Content>
|
||||
<Content key={location.pathname} className={`v2-content${section === 'tracks' ? ' is-track-workspace' : ''}`}><Outlet /></Content>
|
||||
</Layout>
|
||||
<ContextHelp section={section} visible={helpOpen} onClose={() => setHelpOpen(false)} />
|
||||
{passwordOpen ? <PasswordDialog onClose={() => setPasswordOpen(false)} onChanged={logout} /> : null}
|
||||
|
||||
@@ -172,7 +172,11 @@ test('shows deduplicated Semi vehicle candidates and opens the selected VIN', as
|
||||
expect(initialQuery!.get('limit')).toBe('10');
|
||||
expect(screen.getByRole('heading', { name: '授权车辆目录', level: 5 })).toBeInTheDocument();
|
||||
expect(await screen.findByText('本页 1 辆')).toBeInTheDocument();
|
||||
expect(screen.getByText('本页在线 1')).toBeInTheDocument();
|
||||
expect(screen.getByText('多源车辆 0')).toBeInTheDocument();
|
||||
expect(view.container.querySelector('.v2-vehicle-directory-table.semi-table-wrapper')).toBeInTheDocument();
|
||||
expect(view.container.querySelector('.v2-vehicle-directory-profile')).toHaveTextContent('测试品牌13800000000');
|
||||
expect(view.container.querySelector('.v2-vehicle-discovery-shell')).toContainElement(screen.getByLabelText('查车操作'));
|
||||
expect(screen.getByRole('button', { name: `打开 ${initialRealtime.vin} 车辆档案` })).toBeInTheDocument();
|
||||
fireEvent.focus(input);
|
||||
expect(input).toHaveAttribute('aria-expanded', 'true');
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
IconChevronRight, IconMapPin, IconSearch, IconTickCircle
|
||||
} from '@douyinfe/semi-icons';
|
||||
import { Button, Card, Descriptions, Empty, Input, List, Select, SideSheet, Table, Tag } from '@douyinfe/semi-ui';
|
||||
import { FormEvent, lazy, Suspense, useEffect, useMemo, useState } from 'react';
|
||||
import { FormEvent, lazy, Suspense, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||
import { Link, useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||
import { api } from '../../api/client';
|
||||
import type { LatestTelemetryResponse, LatestTelemetryValue, QualityIssueRow, VehicleDetail, VehicleRealtimeRow } from '../../api/types';
|
||||
@@ -35,11 +35,28 @@ const SINGLE_VEHICLE_REFRESH_MS = 10_000;
|
||||
const VehicleSearch = lazy(() => import('./VehicleSearchWorkspace'));
|
||||
|
||||
function resetWorkspaceScroll() {
|
||||
const content = document.querySelector<HTMLElement>('.v2-content');
|
||||
if (!content) return;
|
||||
content.scrollTop = 0;
|
||||
content.scrollLeft = 0;
|
||||
content.scrollTo?.({ top: 0, left: 0, behavior: 'auto' });
|
||||
const targets = [
|
||||
document.scrollingElement,
|
||||
document.documentElement,
|
||||
document.body,
|
||||
document.querySelector<HTMLElement>('.v2-shell'),
|
||||
document.querySelector<HTMLElement>('.v2-main'),
|
||||
document.querySelector<HTMLElement>('.v2-content')
|
||||
];
|
||||
for (const target of targets) {
|
||||
if (!(target instanceof HTMLElement)) continue;
|
||||
target.scrollTop = 0;
|
||||
target.scrollLeft = 0;
|
||||
target.scrollTo?.({ top: 0, left: 0, behavior: 'auto' });
|
||||
}
|
||||
}
|
||||
|
||||
function revealVehicleIdentity(root: HTMLElement | null) {
|
||||
resetWorkspaceScroll();
|
||||
if (!root) return;
|
||||
root.scrollTop = 0;
|
||||
root.scrollLeft = 0;
|
||||
root.scrollIntoView?.({ behavior: 'auto', block: 'start', inline: 'nearest' });
|
||||
}
|
||||
|
||||
function eventTimeLabel(value?: string) {
|
||||
@@ -394,6 +411,7 @@ function VehicleRecord({ detail, liveRealtime, telemetry, telemetryPending, tele
|
||||
const { session } = usePlatformSession();
|
||||
const navigate = useNavigate();
|
||||
const mobileLayout = useMobileLayout();
|
||||
const recordRootRef = useRef<HTMLDivElement>(null);
|
||||
const [sourceEvidenceOpen, setSourceEvidenceOpen] = useState(false);
|
||||
const realtime = liveRealtime ?? detail.realtimeSummary;
|
||||
const identity = detail.identity;
|
||||
@@ -406,7 +424,33 @@ function VehicleRecord({ detail, liveRealtime, telemetry, telemetryPending, tele
|
||||
...(hasMenu(session, 'statistics') ? [{ key: 'statistics', label: '里程查询', icon: <IconClock />, to: withMonitorReturn(`/statistics?vins=${encodeURIComponent(detail.vin)}`, monitorReturn), type: 'tertiary' as const }] : []),
|
||||
...(hasMenu(session, 'alerts') ? [{ key: 'alerts', label: '告警事件', icon: <IconAlarm />, to: `/alerts?vin=${encodeURIComponent(detail.vin)}`, type: 'tertiary' as const }] : [])
|
||||
];
|
||||
return <div className={`v2-vehicle-record-page${mobileLayout ? ' is-mobile-layout' : ''}`}>
|
||||
useLayoutEffect(() => {
|
||||
const root = recordRootRef.current;
|
||||
if (!root) return;
|
||||
let cancelled = false;
|
||||
const timers: number[] = [];
|
||||
const revealIdentity = () => {
|
||||
if (!cancelled) revealVehicleIdentity(root);
|
||||
};
|
||||
const cancelEntryReset = () => {
|
||||
cancelled = true;
|
||||
for (const timer of timers) window.clearTimeout(timer);
|
||||
};
|
||||
const interactionEvents = ['wheel', 'touchstart', 'pointerdown', 'keydown'] as const;
|
||||
for (const eventName of interactionEvents) window.addEventListener(eventName, cancelEntryReset, { capture: true, passive: true });
|
||||
revealIdentity();
|
||||
const frame = window.requestAnimationFrame(revealIdentity);
|
||||
// The map and live evidence arrive independently. Keep the identity band
|
||||
// anchored only during initial settlement, then immediately yield to input.
|
||||
for (const delay of [80, 180, 360, 720, 1200, 1800, 2400]) timers.push(window.setTimeout(revealIdentity, delay));
|
||||
return () => {
|
||||
cancelled = true;
|
||||
window.cancelAnimationFrame(frame);
|
||||
for (const timer of timers) window.clearTimeout(timer);
|
||||
for (const eventName of interactionEvents) window.removeEventListener(eventName, cancelEntryReset, true);
|
||||
};
|
||||
}, [detail.vin]);
|
||||
return <div ref={recordRootRef} className={`v2-vehicle-record-page${mobileLayout ? ' is-mobile-layout' : ''}`}>
|
||||
<MonitorReturnBar />
|
||||
<Card className="v2-identity-band v2-record-card v2-live-card v2-live-overview v2-vehicle-command-card" bodyStyle={{ padding: 0 }}>
|
||||
<div className="v2-vehicle-command-header">
|
||||
|
||||
@@ -20,11 +20,20 @@ import { WorkspacePanelHeader } from '../shared/WorkspacePanelHeader';
|
||||
const VehicleProfileSyncPanel = lazy(() => import('./VehicleProfileSyncPanel'));
|
||||
|
||||
function resetWorkspaceScroll() {
|
||||
const content = document.querySelector<HTMLElement>('.v2-content');
|
||||
if (!content) return;
|
||||
content.scrollTop = 0;
|
||||
content.scrollLeft = 0;
|
||||
content.scrollTo?.({ top: 0, left: 0, behavior: 'auto' });
|
||||
const targets = [
|
||||
document.scrollingElement,
|
||||
document.documentElement,
|
||||
document.body,
|
||||
document.querySelector<HTMLElement>('.v2-shell'),
|
||||
document.querySelector<HTMLElement>('.v2-main'),
|
||||
document.querySelector<HTMLElement>('.v2-content')
|
||||
];
|
||||
for (const target of targets) {
|
||||
if (!(target instanceof HTMLElement)) continue;
|
||||
target.scrollTop = 0;
|
||||
target.scrollLeft = 0;
|
||||
target.scrollTo?.({ top: 0, left: 0, behavior: 'auto' });
|
||||
}
|
||||
}
|
||||
|
||||
function vehicleLastSeenLabel(value?: string) {
|
||||
@@ -61,6 +70,8 @@ export default function VehicleSearchWorkspace() {
|
||||
const pageVehicles = useMemo(() => options.slice(0, pageSize), [options, pageSize]);
|
||||
const total = candidates.data?.total ?? 0;
|
||||
const totalPages = Math.max(1, Math.ceil(total / pageSize));
|
||||
const onlineOnPage = useMemo(() => pageVehicles.filter((vehicle) => vehicle.online).length, [pageVehicles]);
|
||||
const multiSourceOnPage = useMemo(() => pageVehicles.filter((vehicle) => vehicle.protocols.length > 1).length, [pageVehicles]);
|
||||
const administrator = canAdminister(session);
|
||||
useEffect(() => () => window.clearTimeout(closeTimerRef.current), []);
|
||||
useEffect(() => {
|
||||
@@ -79,6 +90,7 @@ export default function VehicleSearchWorkspace() {
|
||||
const normalized = value.trim();
|
||||
if (!normalized) return;
|
||||
setCandidatesOpen(false);
|
||||
if (document.activeElement instanceof HTMLElement) document.activeElement.blur();
|
||||
resetWorkspaceScroll();
|
||||
navigate(`/vehicles/${encodeURIComponent(normalized)}`);
|
||||
window.queueMicrotask(resetWorkspaceScroll);
|
||||
@@ -91,64 +103,70 @@ export default function VehicleSearchWorkspace() {
|
||||
};
|
||||
const vehicleScope = candidates.data ? `${candidates.data.total.toLocaleString('zh-CN')} 辆授权` : '授权范围';
|
||||
return <section className={`v2-vehicle-search-page${syncOpen ? ' has-sync-panel' : ''}${candidatesOpen ? ' has-candidates' : ''}`}>
|
||||
{!mobileLayout || administrator ? <WorkspaceCommandBar
|
||||
className={`v2-vehicle-command-bar${mobileLayout ? ' is-mobile-admin' : ''}`}
|
||||
ariaLabel={mobileLayout ? '车辆主档操作' : '查车操作'}
|
||||
title={mobileLayout ? '车辆主档' : '车辆快速定位'}
|
||||
description={mobileLayout ? '批量维护品牌、车型与运营属性' : '车牌、VIN 或手机号快速查车'}
|
||||
status={mobileLayout ? undefined : candidates.isPending ? '正在读取授权范围' : vehicleScope}
|
||||
statusColor={candidates.isError ? 'red' : 'blue'}
|
||||
actions={administrator ? <Button theme="light" type="tertiary" icon={mobileLayout ? <IconBox /> : undefined} onClick={() => setSyncOpen((value) => !value)}>{syncOpen ? '收起同步' : mobileLayout ? '主档同步' : '批量同步主档'}</Button> : null}
|
||||
/> : null}
|
||||
<WorkspaceFilterPanel
|
||||
className="v2-vehicle-query-panel"
|
||||
title={mobileLayout ? '车辆筛选' : '车辆定位'}
|
||||
description="车牌优先,VIN 辅助"
|
||||
mobileSummary={deferredKeyword ? `正在查找 ${deferredKeyword}` : candidates.data ? `${candidates.data.total.toLocaleString('zh-CN')} 辆授权车辆` : '正在读取授权范围'}
|
||||
expanded={!filtersCollapsed}
|
||||
status={deferredKeyword ? candidates.isFetching ? '正在查找' : `${options.length} 辆匹配` : vehicleScope}
|
||||
statusColor={deferredKeyword ? 'blue' : 'grey'}
|
||||
collapsedLabel="修改"
|
||||
onToggle={() => setFiltersCollapsed((value) => !value)}
|
||||
>
|
||||
<form className={`v2-vehicle-search-form${filtersCollapsed ? ' is-mobile-collapsed' : ''}`} onSubmit={submit}>
|
||||
<div className={`v2-vehicle-search-picker${candidatesOpen ? ' is-open' : ''}`}>
|
||||
<Input
|
||||
aria-label="搜索车辆"
|
||||
aria-controls="v2-vehicle-search-options"
|
||||
aria-expanded={candidatesOpen}
|
||||
prefix={<IconSearch />}
|
||||
value={keyword}
|
||||
onChange={(value) => { setKeyword(value); setPage(1); setCandidatesOpen(true); }}
|
||||
onFocus={openCandidates}
|
||||
onBlur={closeCandidates}
|
||||
placeholder="输入车牌 / VIN / 终端手机号"
|
||||
autoComplete="off"
|
||||
/>
|
||||
</div>
|
||||
<Button theme="solid" htmlType="submit" icon={<IconArrowRight />} iconPosition="right">查询车辆</Button>
|
||||
{candidatesOpen ? <VehicleCandidateList
|
||||
id="v2-vehicle-search-options"
|
||||
className="v2-vehicle-search-options"
|
||||
items={options}
|
||||
loading={candidates.isFetching}
|
||||
loadingText="正在搜索授权车辆"
|
||||
error={candidates.isError ? (candidates.error instanceof Error ? candidates.error.message : '车辆候选加载失败') : undefined}
|
||||
onRetry={() => candidates.refetch()}
|
||||
emptyText="没有匹配的授权车辆"
|
||||
header="车辆候选"
|
||||
meta="车牌优先 · VIN 辅助"
|
||||
showProtocols
|
||||
layout={mobileLayout ? 'list' : 'grid'}
|
||||
onSelect={(vehicle) => openVehicle(vehicle.vin)}
|
||||
/> : null}
|
||||
</form>
|
||||
</WorkspaceFilterPanel>
|
||||
<div className="v2-vehicle-discovery-shell">
|
||||
{!mobileLayout || administrator ? <WorkspaceCommandBar
|
||||
className={`v2-vehicle-command-bar${mobileLayout ? ' is-mobile-admin' : ''}`}
|
||||
ariaLabel={mobileLayout ? '车辆主档操作' : '查车操作'}
|
||||
title={mobileLayout ? '车辆主档' : '车辆快速定位'}
|
||||
description={mobileLayout ? '批量维护品牌、车型与运营属性' : '车牌、VIN 或手机号快速查车'}
|
||||
status={mobileLayout ? undefined : candidates.isPending ? '正在读取授权范围' : vehicleScope}
|
||||
statusColor={candidates.isError ? 'red' : 'blue'}
|
||||
actions={administrator ? <Button theme="light" type="tertiary" icon={mobileLayout ? <IconBox /> : undefined} onClick={() => setSyncOpen((value) => !value)}>{syncOpen ? '收起同步' : mobileLayout ? '主档同步' : '批量同步主档'}</Button> : null}
|
||||
/> : null}
|
||||
<WorkspaceFilterPanel
|
||||
className="v2-vehicle-query-panel"
|
||||
title={mobileLayout ? '车辆筛选' : '车辆定位'}
|
||||
description="车牌优先,VIN 辅助"
|
||||
mobileSummary={deferredKeyword ? `正在查找 ${deferredKeyword}` : candidates.data ? `${candidates.data.total.toLocaleString('zh-CN')} 辆授权车辆` : '正在读取授权范围'}
|
||||
expanded={!filtersCollapsed}
|
||||
status={deferredKeyword ? candidates.isFetching ? '正在查找' : `${options.length} 辆匹配` : vehicleScope}
|
||||
statusColor={deferredKeyword ? 'blue' : 'grey'}
|
||||
collapsedLabel="修改"
|
||||
onToggle={() => setFiltersCollapsed((value) => !value)}
|
||||
>
|
||||
<form className={`v2-vehicle-search-form${filtersCollapsed ? ' is-mobile-collapsed' : ''}`} onSubmit={submit}>
|
||||
<div className={`v2-vehicle-search-picker${candidatesOpen ? ' is-open' : ''}`}>
|
||||
<Input
|
||||
aria-label="搜索车辆"
|
||||
aria-controls="v2-vehicle-search-options"
|
||||
aria-expanded={candidatesOpen}
|
||||
prefix={<IconSearch />}
|
||||
value={keyword}
|
||||
onChange={(value) => { setKeyword(value); setPage(1); setCandidatesOpen(true); }}
|
||||
onFocus={openCandidates}
|
||||
onBlur={closeCandidates}
|
||||
placeholder="输入车牌 / VIN / 终端手机号"
|
||||
autoComplete="off"
|
||||
/>
|
||||
</div>
|
||||
<Button theme="solid" htmlType="submit" icon={<IconArrowRight />} iconPosition="right">查询车辆</Button>
|
||||
{candidatesOpen ? <VehicleCandidateList
|
||||
id="v2-vehicle-search-options"
|
||||
className="v2-vehicle-search-options"
|
||||
items={options}
|
||||
loading={candidates.isFetching}
|
||||
loadingText="正在搜索授权车辆"
|
||||
error={candidates.isError ? (candidates.error instanceof Error ? candidates.error.message : '车辆候选加载失败') : undefined}
|
||||
onRetry={() => candidates.refetch()}
|
||||
emptyText="没有匹配的授权车辆"
|
||||
header="车辆候选"
|
||||
meta="车牌优先 · VIN 辅助"
|
||||
showProtocols
|
||||
layout={mobileLayout ? 'list' : 'grid'}
|
||||
onSelect={(vehicle) => openVehicle(vehicle.vin)}
|
||||
/> : null}
|
||||
</form>
|
||||
</WorkspaceFilterPanel>
|
||||
</div>
|
||||
<Card className="v2-vehicle-recent-card" bodyStyle={{ padding: 0 }}>
|
||||
<WorkspacePanelHeader
|
||||
title={deferredKeyword ? '匹配车辆' : mobileLayout ? '授权车辆' : '授权车辆目录'}
|
||||
description={deferredKeyword ? '按当前搜索条件展示,可直接进入车辆数字档案' : '按照最新上报时间排列,分页浏览全部授权车辆'}
|
||||
meta={<Tag color={deferredKeyword ? 'blue' : 'grey'} type="light" size="small">{candidates.data ? `本页 ${formatZhNumber(pageVehicles.length)} 辆` : '授权范围'}</Tag>}
|
||||
meta={<span className="v2-vehicle-directory-summary">
|
||||
<Tag color={deferredKeyword ? 'blue' : 'grey'} type="light" size="small">{candidates.data ? `本页 ${formatZhNumber(pageVehicles.length)} 辆` : '授权范围'}</Tag>
|
||||
{candidates.data ? <Tag className="is-secondary" color="green" type="light" size="small">本页在线 {formatZhNumber(onlineOnPage)}</Tag> : null}
|
||||
{candidates.data ? <Tag className="is-secondary" color="blue" type="light" size="small">多源车辆 {formatZhNumber(multiSourceOnPage)}</Tag> : null}
|
||||
</span>}
|
||||
actions={<Button theme="borderless" type="tertiary" size="small" icon={<IconRefresh />} loading={candidates.isFetching} onClick={() => candidates.refetch()}>刷新</Button>}
|
||||
/>
|
||||
{candidates.isFetching && !candidates.data
|
||||
@@ -186,10 +204,16 @@ export default function VehicleSearchWorkspace() {
|
||||
width: 220,
|
||||
render: (_value: string, vehicle: VehicleCoverageRow) => <span className="v2-vehicle-directory-identity"><strong>{vehicle.plate || '未绑定车牌'}</strong><small>{vehicle.vin}</small></span>
|
||||
},
|
||||
{
|
||||
title: '车辆信息',
|
||||
dataIndex: 'oem',
|
||||
width: 260,
|
||||
render: (_value: string, vehicle: VehicleCoverageRow) => <span className="v2-vehicle-directory-profile"><strong>{vehicle.oem || '品牌待维护'}</strong><small>{vehicle.phone || '暂无终端手机号'}</small></span>
|
||||
},
|
||||
{
|
||||
title: '实时状态',
|
||||
dataIndex: 'online',
|
||||
width: 150,
|
||||
width: 180,
|
||||
render: (_value: boolean, vehicle: VehicleCoverageRow) => <span className="v2-vehicle-directory-status"><Tag color={vehicle.online ? 'green' : 'grey'} type="light" size="small">{vehicle.online ? '在线' : '离线'}</Tag><small>{vehicleLastSeenLabel(vehicle.lastSeen)}</small></span>
|
||||
},
|
||||
{
|
||||
@@ -200,13 +224,22 @@ export default function VehicleSearchWorkspace() {
|
||||
{
|
||||
title: '',
|
||||
dataIndex: 'vin',
|
||||
width: 104,
|
||||
width: 116,
|
||||
align: 'right',
|
||||
render: (vehicleVin: string) => <Button className="v2-vehicle-directory-open" theme="borderless" type="primary" size="small" icon={<IconChevronRight />} iconPosition="right" aria-label={`打开 ${vehicleVin} 车辆档案`} onClick={() => openVehicle(vehicleVin)}>查看档案</Button>
|
||||
render: (vehicleVin: string) => <Button className="v2-vehicle-directory-open" theme="borderless" type="primary" size="small" icon={<IconChevronRight />} iconPosition="right" aria-label={`打开 ${vehicleVin} 车辆档案`} onClick={(event) => { event.stopPropagation(); openVehicle(vehicleVin); }}>查看档案</Button>
|
||||
}
|
||||
]}
|
||||
dataSource={pageVehicles}
|
||||
rowKey="vin"
|
||||
onRow={(vehicle) => vehicle ? ({
|
||||
tabIndex: 0,
|
||||
onClick: () => openVehicle(vehicle.vin),
|
||||
onKeyDown: (event) => {
|
||||
if (event.key !== 'Enter' && event.key !== ' ') return;
|
||||
event.preventDefault();
|
||||
openVehicle(vehicle.vin);
|
||||
}
|
||||
}) : ({})}
|
||||
pagination={false}
|
||||
loading={candidates.isFetching}
|
||||
empty={null}
|
||||
|
||||
@@ -1983,10 +1983,11 @@
|
||||
align-content: start;
|
||||
place-items: start center;
|
||||
gap: 12px;
|
||||
overflow: auto;
|
||||
overflow: visible;
|
||||
padding: 16px var(--v2-page-gutter) 28px;
|
||||
}
|
||||
|
||||
.v2-vehicle-discovery-shell,
|
||||
.v2-vehicle-search-page > .v2-page-heading,
|
||||
.v2-vehicle-search-page > .v2-mobile-filter-toggle,
|
||||
.v2-vehicle-search-page > .v2-vehicle-query-panel,
|
||||
@@ -1996,6 +1997,32 @@
|
||||
width: min(1280px, 100%);
|
||||
}
|
||||
|
||||
.v2-vehicle-discovery-shell {
|
||||
display: grid;
|
||||
overflow: visible;
|
||||
gap: 0;
|
||||
border: 1px solid #dce4ee;
|
||||
border-radius: 14px;
|
||||
background: #fff;
|
||||
box-shadow: 0 9px 28px rgba(31, 53, 80, .055);
|
||||
}
|
||||
|
||||
.v2-vehicle-discovery-shell > .v2-workspace-command-bar {
|
||||
width: 100%;
|
||||
min-height: 50px;
|
||||
border: 0;
|
||||
border-bottom: 1px solid #e6ecf3;
|
||||
border-radius: 14px 14px 0 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.v2-vehicle-discovery-shell > .v2-vehicle-query-panel.semi-card {
|
||||
width: 100%;
|
||||
border: 0;
|
||||
border-radius: 0 0 14px 14px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.v2-vehicle-query-panel.v2-workspace-filter-panel.semi-card {
|
||||
overflow: visible;
|
||||
}
|
||||
@@ -2062,27 +2089,35 @@
|
||||
}
|
||||
|
||||
.v2-vehicle-directory-table .semi-table-tbody > .semi-table-row {
|
||||
cursor: default;
|
||||
cursor: pointer;
|
||||
transition: background-color .15s ease;
|
||||
}
|
||||
|
||||
.v2-vehicle-directory-table .semi-table-tbody > .semi-table-row:hover {
|
||||
.v2-vehicle-directory-table .semi-table-tbody > .semi-table-row:hover,
|
||||
.v2-vehicle-directory-table .semi-table-tbody > .semi-table-row:focus-visible {
|
||||
background: #f7faff;
|
||||
}
|
||||
|
||||
.v2-vehicle-directory-table .semi-table-tbody > .semi-table-row:focus-visible {
|
||||
outline: 2px solid rgba(18, 104, 243, .28);
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
.v2-vehicle-directory-table .semi-table-tbody > .semi-table-row > .semi-table-row-cell {
|
||||
height: 48px;
|
||||
border-bottom-color: #edf1f6;
|
||||
padding-block: 6px;
|
||||
}
|
||||
|
||||
.v2-vehicle-directory-identity {
|
||||
.v2-vehicle-directory-identity,
|
||||
.v2-vehicle-directory-profile {
|
||||
display: grid;
|
||||
min-width: 0;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.v2-vehicle-directory-identity strong {
|
||||
.v2-vehicle-directory-identity strong,
|
||||
.v2-vehicle-directory-profile strong {
|
||||
overflow: hidden;
|
||||
color: #1b2a3e;
|
||||
font-size: 14px;
|
||||
@@ -2091,7 +2126,14 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.v2-vehicle-directory-profile strong {
|
||||
color: #40536a;
|
||||
font-size: 11px;
|
||||
font-weight: 650;
|
||||
}
|
||||
|
||||
.v2-vehicle-directory-identity small,
|
||||
.v2-vehicle-directory-profile small,
|
||||
.v2-vehicle-directory-status small {
|
||||
overflow: hidden;
|
||||
color: #7f8da1;
|
||||
@@ -2101,6 +2143,16 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.v2-vehicle-directory-summary {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.v2-vehicle-directory-summary > .semi-tag {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.v2-vehicle-directory-status {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
@@ -2148,6 +2200,11 @@
|
||||
}
|
||||
|
||||
.v2-vehicle-record-page {
|
||||
overflow: visible !important;
|
||||
overflow-anchor: none;
|
||||
}
|
||||
|
||||
.v2-content {
|
||||
overflow-anchor: none;
|
||||
}
|
||||
|
||||
@@ -2236,9 +2293,14 @@
|
||||
@media (max-width: 700px) {
|
||||
.v2-vehicle-search-page {
|
||||
gap: 8px;
|
||||
overflow: visible;
|
||||
padding: 9px 8px 92px;
|
||||
}
|
||||
|
||||
.v2-vehicle-discovery-shell {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.v2-vehicle-command-bar.is-mobile-admin {
|
||||
min-height: 50px;
|
||||
border-color: #dce6f2;
|
||||
@@ -2309,6 +2371,10 @@
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.v2-vehicle-directory-summary > .is-secondary {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.v2-track-detail-sidesheet .semi-sidesheet-inner {
|
||||
overflow: hidden;
|
||||
border-radius: 18px 18px 0 0;
|
||||
|
||||
Reference in New Issue
Block a user