refactor(channels): collapse the stats row into a Stats hover chip (R13 S3)
The six inline catalog stats crammed into the tab row become one compact "Stats" chip that reveals the numbers on hover — a new ChannelStatsPopover on the AnchoredPopover hover mode, one icon-per-row (channels, recent synced, full history, [ETA], my videos, quota left). Kept in the manager's own toolbar (the header SyncStatus is global; these are channel-catalog figures). Retires the local Stat helper + the now-unused formatEta import. i18n channels.stats.label (HU+EN). Self-E2E'd: hover reveals the list. gate green (tsc/eslint-0/prettier).
This commit is contained in:
@@ -7,7 +7,6 @@ import ExcludedChannelList from "./ExcludedChannelList";
|
||||
import { api, type ManagedChannel } from "../lib/api";
|
||||
import { notifyYouTubeActionError } from "../lib/youtubeErrors";
|
||||
import { accountKey, LS } from "../lib/storage";
|
||||
import { formatEta } from "../lib/format";
|
||||
import { buildChannelColumns } from "./channelColumns";
|
||||
import { notify } from "../lib/notifications";
|
||||
import Tooltip from "./Tooltip";
|
||||
@@ -21,6 +20,7 @@ import ViewSwitcher, { type ViewOption } from "./ViewSwitcher";
|
||||
import ColumnSortControl from "./ColumnSortControl";
|
||||
import FilterChipGroup, { filterChipClass } from "./FilterChipGroup";
|
||||
import ActionMenu, { type ActionMenuItem } from "./ActionMenu";
|
||||
import ChannelStatsPopover from "./ChannelStatsPopover";
|
||||
import Pager from "./Pager";
|
||||
import { CHANNEL_LAYOUTS, type ChannelLayout } from "../lib/channelLayout";
|
||||
import { sortRows } from "../lib/columnSort";
|
||||
@@ -305,48 +305,9 @@ export default function Channels() {
|
||||
/>
|
||||
);
|
||||
|
||||
// The catalog-wide stats ride on the right of the tab row (subscribed only), leaving room for
|
||||
// future tabs on the left.
|
||||
const statsBlock = (
|
||||
<div className="flex flex-wrap items-center justify-end gap-x-5 gap-y-1 text-sm text-muted">
|
||||
{s && (
|
||||
<>
|
||||
<Stat
|
||||
label={t("channels.stats.channels")}
|
||||
value={s.channels_total}
|
||||
hint={t("channels.stats.channelsHint")}
|
||||
/>
|
||||
<Stat
|
||||
label={t("channels.stats.recentSynced")}
|
||||
value={`${s.channels_recent_synced}/${s.channels_total}`}
|
||||
hint={t("channels.stats.recentSyncedHint")}
|
||||
/>
|
||||
<Stat
|
||||
label={t("channels.stats.fullHistory")}
|
||||
value={`${s.channels_deep_done}/${s.channels_deep_requested}`}
|
||||
hint={t("channels.stats.fullHistoryHint")}
|
||||
/>
|
||||
{s.deep_pending_count > 0 && (
|
||||
<Stat
|
||||
label={t("channels.stats.left")}
|
||||
value={formatEta(s.deep_eta_seconds)}
|
||||
hint={t("channels.stats.leftHint", { count: s.deep_pending_count })}
|
||||
/>
|
||||
)}
|
||||
<Stat
|
||||
label={t("channels.stats.myVideos")}
|
||||
value={s.my_videos.toLocaleString()}
|
||||
hint={t("channels.stats.myVideosHint")}
|
||||
/>
|
||||
<Stat
|
||||
label={t("channels.stats.quotaLeft")}
|
||||
value={s.quota_remaining_today.toLocaleString()}
|
||||
hint={t("channels.stats.quotaLeftHint")}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
// The catalog-wide stats collapse into a compact "Stats" hover chip (right of the tab row, subscribed
|
||||
// only) instead of a crowded inline row.
|
||||
const statsBlock = s ? <ChannelStatsPopover status={s} /> : null;
|
||||
|
||||
// Catalog-wide, occasional actions — tucked into a shared ⋯ overflow menu so they stop crowding the
|
||||
// tags row. Pending mutations keep the item visible but disabled, with a spinning icon.
|
||||
@@ -596,13 +557,3 @@ export default function Channels() {
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function Stat({ label, value, hint }: { label: string; value: string | number; hint?: string }) {
|
||||
return (
|
||||
<Tooltip hint={hint ?? ""}>
|
||||
<span className={hint ? "cursor-help" : ""}>
|
||||
<span className="text-fg font-semibold">{value}</span> {label}
|
||||
</span>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user