fix(frontend): policy card keeps its wells in the light theme, folder rules show their content, opened rule scrolls into view, rule removal asks first

This commit is contained in:
hh committed 2026-10-14 04:27:59 +02:00
1 parent cb01d7dff8
commit dfc726976b
4 files changed
+201 -77

No files matched your search

+54 -35
View File
@@ -45,6 +45,7 @@ const SHOWN_CHIPS = 3;
const SHORT_LIST = 2;
export interface Chip {
hint?: string;
label: string;
sign: "plus" | "minus";
}
@@ -76,6 +77,19 @@ export function sameToggles(a: CaptureToggles, b: CaptureToggles): boolean {
return TOGGLE_KEYS.every((key) => a[key] === b[key]);
}
const EXCEPT_LABELS: Record<ToggleKey, string> = {
backfill: "бэкфилла",
media: "медиа",
messages: "сообщений",
presence: "присутствия",
profile_history: "истории профиля",
reactions: "реакций",
self_destruct_media: "исчезающих",
stories: "сторис",
stt: "расшифровки",
track_edits_deletes: "правок и удалений",
};
export function summary(toggles: CaptureToggles): string {
const on = TOGGLE_KEYS.filter((key) => toggles[key]);
const off = TOGGLE_KEYS.filter((key) => !toggles[key]);
@@ -89,8 +103,7 @@ export function summary(toggles: CaptureToggles): string {
return "Только сообщения";
}
if (off.length <= SHORT_LIST) {
const names = off.map((key) => TOGGLE_LABELS[key].toLowerCase());
return `Всё, кроме: ${names.join(", ")}`;
return `Всё, кроме ${off.map((key) => EXCEPT_LABELS[key]).join(" и ")}`;
}
const names = on.slice(0, SHORT_LIST).map((key) => TOGGLE_LABELS[key]);
const rest = on.length - names.length;
@@ -107,42 +120,48 @@ export function parentLabel(
return PARENT_LABELS[scopeType] ?? "по умолчанию";
}
function settings(count: number): string {
return `${count} ${plural(count, "настройка", "настройки", "настроек")}`;
function labelList(keys: ToggleKey[]): string {
return keys.map((key) => TOGGLE_LABELS[key]).join(", ");
}
function collapse(
keys: ToggleKey[],
sign: Chip["sign"],
whole: string
): Chip[] {
if (keys.length === 0) {
return [];
}
if (keys.length > SHOWN_CHIPS) {
return [{ label: whole, sign }];
}
function named(keys: ToggleKey[], sign: Chip["sign"]): Chip[] {
return keys.map((key) => ({ label: TOGGLE_LABELS[key], sign }));
}
export function diffChips(
rule: CaptureToggles,
bases: CaptureToggles[]
): Chip[] {
const plus = TOGGLE_KEYS.filter(
(key) => rule[key] && bases.some((base) => !base[key])
);
const minus = TOGGLE_KEYS.filter(
(key) => !rule[key] && bases.some((base) => base[key])
);
const allOn = TOGGLE_KEYS.every((key) => rule[key]);
const allOff = TOGGLE_KEYS.every((key) => !rule[key]);
return [
...collapse(plus, "plus", allOn ? "Всё включено" : settings(plus.length)),
...collapse(
minus,
"minus",
allOff ? "Всё выключено" : settings(minus.length)
),
];
function counted(keys: ToggleKey[], sign: Chip["sign"]): Chip[] {
if (keys.length === 0) {
return [];
}
if (keys.length <= SHOWN_CHIPS) {
return named(keys, sign);
}
const word = plural(keys.length, "настройка", "настройки", "настроек");
return [{ hint: labelList(keys), label: `${keys.length} ${word}`, sign }];
}
export function contentChips(rule: CaptureToggles): Chip[] {
const on = TOGGLE_KEYS.filter((key) => rule[key]);
const off = TOGGLE_KEYS.filter((key) => !rule[key]);
if (off.length === 0) {
return [{ label: "Всё включено", sign: "plus" }];
}
if (on.length === 0) {
return [{ label: "Всё выключено", sign: "minus" }];
}
if (off.length <= SHOWN_CHIPS) {
return [{ label: "Всё", sign: "plus" }, ...named(off, "minus")];
}
return [...counted(on, "plus"), ...counted(off, "minus")];
}
export function diffChips(rule: CaptureToggles, base: CaptureToggles): Chip[] {
const plus = TOGGLE_KEYS.filter((key) => rule[key] && !base[key]);
const minus = TOGGLE_KEYS.filter((key) => !rule[key] && base[key]);
if (plus.length > SHOWN_CHIPS && TOGGLE_KEYS.every((key) => rule[key])) {
return [{ label: "Всё включено", sign: "plus" }];
}
if (minus.length > SHOWN_CHIPS && TOGGLE_KEYS.every((key) => !rule[key])) {
return [{ label: "Всё выключено", sign: "minus" }];
}
return [...counted(plus, "plus"), ...counted(minus, "minus")];
}