fix(settings): remove sticky header mask wrapper

中文: 移除设置页标题条的外层 sticky 容器和向上遮罩,避免滚动到底部时出现大面积空白边框;改回单层 sticky 标题按钮,并保留放大字号、灰色粗边框和无阴影样式。

English: Remove the sticky wrapper and upward mask from settings section headers to prevent large blank bordered areas near the bottom of the settings page, while keeping a single-layer sticky button with enlarged text, a thicker gray border, and no shadow.
This commit is contained in:
Dusk 2026-04-25 15:58:30 +08:00
parent 997aa5bc14
commit 496cb0fc09
2 changed files with 13 additions and 48 deletions

View file

@ -520,32 +520,20 @@ describe("PluginSettingTab", () => {
for (const cardId of ["card-types", "sync-content", "scope", "deck", "commands"] as const) {
const card = queryByDataset(tab.containerEl, "settingsCard", cardId);
const stickyHeader = queryByDataset(tab.containerEl, "settingsCardStickyHeader", cardId);
const stickyMask = queryByDataset(tab.containerEl, "settingsCardStickyMask", cardId);
const header = queryByDataset(tab.containerEl, "settingsCardToggle", cardId);
const body = queryByDataset(tab.containerEl, "settingsCardBody", cardId);
expect(card.style.position).toBe("relative");
expect(card.style.zIndex).toBe("0");
expect(stickyHeader.style.position).toBe("sticky");
expect(stickyHeader.style.top).toBe("0");
expect(stickyHeader.style.zIndex).toBe("80");
expect(stickyHeader.style.width).toBe("100%");
expect(stickyHeader.style.background).toBe("var(--background-primary)");
expect(stickyHeader.style.border).toBe("2px solid var(--background-modifier-border)");
expect(stickyHeader.style.boxShadow).toBe("none");
expect(stickyMask.style.position).toBe("absolute");
expect(stickyMask.style.top).toBe("-96px");
expect(stickyMask.style.height).toBe("96px");
expect(stickyMask.style.background).toBe("var(--background-primary)");
expect(stickyMask.style.pointerEvents).toBe("none");
expect(header.style.position).toBe("relative");
expect(header.style.position).toBe("sticky");
expect(header.style.top).toBe("0");
expect(header.style.zIndex).toBe("80");
expect(header.style.display).toBe("flex");
expect(header.style.width).toBe("100%");
expect(header.style.background).toBe("transparent");
expect(header.style.background).toBe("var(--background-primary)");
expect(header.style.fontSize).toBe("1.5em");
expect(header.style.fontWeight).toBe("600");
expect(header.style.border).toBe("none");
expect(header.style.border).toBe("2px solid var(--background-modifier-border)");
expect(header.style.boxShadow).toBe("none");
expect(body.style.position).toBe("relative");
expect(body.style.zIndex).toBe("0");

View file

@ -36,14 +36,12 @@ const FOLDER_TREE_STATUS_LOADING: UserFacingMessage = { key: "settings.scope.loa
const TEXT_SAVE_DEBOUNCE_MS = 500;
const SETTINGS_CARD_ORDER = ["card-types", "sync-content", "scope", "deck", "commands"] as const;
const VISIBLE_CARD_TYPE_CONFIG_IDS = ["basic", "qa-group", "cloze"] as const;
const STICKY_HEADER_MASK_HEIGHT = "96px";
type SettingsCardId = (typeof SETTINGS_CARD_ORDER)[number];
type NoteTypeCacheCheckStatus = "idle" | "checking" | "same" | "changed" | "failed";
interface SettingsCardShell {
cardEl: HTMLElement;
stickyHeaderEl: HTMLElement;
headerEl: HTMLButtonElement;
bodyEl: HTMLElement;
}
@ -118,45 +116,25 @@ export class AnkiHeadingSyncSettingTab extends PluginSettingTab {
cardEl.style.position = "relative";
cardEl.style.zIndex = "0";
const stickyHeaderEl = cardEl.createDiv();
stickyHeaderEl.dataset.settingsCardStickyHeader = cardId;
stickyHeaderEl.style.position = "sticky";
stickyHeaderEl.style.top = "0";
stickyHeaderEl.style.zIndex = "80";
stickyHeaderEl.style.display = "block";
stickyHeaderEl.style.width = "100%";
stickyHeaderEl.style.maxWidth = "100%";
stickyHeaderEl.style.boxSizing = "border-box";
stickyHeaderEl.style.background = "var(--background-primary)";
stickyHeaderEl.style.border = "2px solid var(--background-modifier-border)";
stickyHeaderEl.style.borderRadius = "0";
stickyHeaderEl.style.boxShadow = "none";
const stickyHeaderMaskEl = stickyHeaderEl.createDiv();
stickyHeaderMaskEl.dataset.settingsCardStickyMask = cardId;
stickyHeaderMaskEl.style.position = "absolute";
stickyHeaderMaskEl.style.left = "0";
stickyHeaderMaskEl.style.right = "0";
stickyHeaderMaskEl.style.top = `-${STICKY_HEADER_MASK_HEIGHT}`;
stickyHeaderMaskEl.style.height = STICKY_HEADER_MASK_HEIGHT;
stickyHeaderMaskEl.style.background = "var(--background-primary)";
stickyHeaderMaskEl.style.pointerEvents = "none";
const headerEl = stickyHeaderEl.createEl("button") as HTMLButtonElement;
const headerEl = cardEl.createEl("button") as HTMLButtonElement;
headerEl.type = "button";
headerEl.dataset.settingsCardToggle = cardId;
headerEl.style.position = "relative";
headerEl.style.position = "sticky";
headerEl.style.top = "0";
headerEl.style.zIndex = "80";
headerEl.style.display = "flex";
headerEl.style.alignItems = "center";
headerEl.style.justifyContent = "flex-start";
headerEl.style.width = "100%";
headerEl.style.maxWidth = "100%";
headerEl.style.boxSizing = "border-box";
headerEl.style.padding = "10px 14px";
headerEl.style.fontSize = "1.5em";
headerEl.style.fontWeight = "600";
headerEl.style.background = "transparent";
headerEl.style.border = "none";
headerEl.style.background = "var(--background-primary)";
headerEl.style.border = "2px solid var(--background-modifier-border)";
headerEl.style.borderRadius = "0";
headerEl.style.marginBottom = "8px";
headerEl.style.textAlign = "left";
headerEl.style.boxShadow = "none";
headerEl.addEventListener("click", () => {
@ -171,7 +149,6 @@ export class AnkiHeadingSyncSettingTab extends PluginSettingTab {
this.cardShells.set(cardId, {
cardEl,
stickyHeaderEl,
headerEl,
bodyEl,
});