style: refine market toolbar layout

This commit is contained in:
wxs
2026-06-30 17:44:31 +08:00
parent ccfb8f14fe
commit 4b5515f6ec
9 changed files with 1694 additions and 62 deletions
+180 -47
View File
@@ -162,10 +162,10 @@ export function ensurePluginToolbar(
dataGroup.dataset.pluginToolbarGroup = "data";
applyToolbarGroupStyles(dataGroup);
dataGroup.append(
createToolbarGroupTitle(document, "达人数据"),
audienceProfileExportButton,
audienceProfileByIdExportButton,
audienceProfileFieldButton
audienceProfileFieldButton,
batchSubmitButton
);
const videoGroup = document.createElement("div");
@@ -181,30 +181,23 @@ export function ensurePluginToolbar(
const thresholdGroup = document.createElement("div");
thresholdGroup.dataset.pluginToolbarGroup = "thresholds";
applyToolbarGroupStyles(thresholdGroup);
applyThresholdGroupStyles(thresholdGroup);
thresholdGroup.append(
createToolbarGroupTitle(document, "传播指标"),
...Object.values(spreadThresholdInputs)
...createSpreadThresholdControls(document, spreadThresholdInputs)
);
const divider = document.createElement("span");
applyToolbarDividerStyles(divider);
const thresholdTitle = createToolbarGroupTitle(document, "传播指标筛选");
const thresholdRule = createSpreadThresholdRule(document);
const actions = document.createElement("div");
actions.dataset.pluginToolbarActions = "root";
applyToolbarActionStyles(actions);
actions.append(batchSubmitButton);
firstRow.append(dataGroup, divider, videoGroup, exportStatusText);
secondRow.append(thresholdGroup);
firstRow.append(dataGroup, videoGroup, exportStatusText);
secondRow.append(thresholdTitle, thresholdRule, thresholdGroup);
panel.append(firstRow, secondRow);
root.append(
exportRangeSelect,
exportCustomPagesInput,
exportButton,
panel,
actions
panel
);
document.body.appendChild(root);
@@ -220,7 +213,7 @@ export function ensurePluginToolbar(
spreadFilterOnlyAssignSelect,
spreadFilterRangeSelect,
spreadFilterTypeSelect,
...Object.values(spreadThresholdInputs)
...spreadThresholdInputs
});
ensureToolbarMounted(root, document);
@@ -249,11 +242,19 @@ export function ensurePluginToolbar(
exportCustomPagesInput,
exportRangeSelect,
exportStatusText,
root
root,
spreadFilterFlowTypeSelect,
spreadFilterOnlyAssignSelect,
spreadFilterRangeSelect,
spreadFilterTypeSelect,
spreadThresholdInputs
});
});
spreadFilterTypeSelect.addEventListener("change", () => {
syncSpreadFilterControlState({
audienceProfileByIdExportButton,
audienceProfileExportButton,
audienceProfileFieldButton,
batchSubmitButton,
exportButton,
exportCustomPagesInput,
@@ -345,6 +346,67 @@ function createSpreadThresholdInput(
return input;
}
function createSpreadThresholdControls(
document: Document,
inputs: Record<keyof SpreadThresholdFilter["thresholds"], HTMLInputElement>
): HTMLElement[] {
const controls: HTMLElement[] = [];
const entries: Array<[string, HTMLInputElement]> = [
["评论", inputs.averageCommentCount],
["时长", inputs.averageDuration],
["点赞", inputs.averageLikeCount],
["转发", inputs.averageShareCount],
["完播率", inputs.finishRate],
["互动率", inputs.interactionRate],
["播放中位数", inputs.playMedian]
];
entries.forEach(([label, input], index) => {
if (index > 0) {
controls.push(createSpreadThresholdConjunction(document));
}
const wrapper = document.createElement("label");
wrapper.dataset.pluginSpreadThresholdControl = input.dataset.pluginSpreadThreshold;
applySpreadThresholdControlStyles(wrapper);
const labelText = document.createElement("span");
labelText.textContent = label;
const operator = document.createElement("b");
operator.dataset.pluginSpreadThresholdOperator = "gte";
operator.textContent = "≥";
wrapper.append(labelText, operator, input);
controls.push(wrapper);
});
return controls;
}
function createSpreadThresholdConjunction(document: Document): HTMLElement {
const conjunction = document.createElement("span");
conjunction.dataset.pluginSpreadThresholdConjunction = "and";
conjunction.textContent = "且";
applySpreadThresholdConjunctionStyles(conjunction);
return conjunction;
}
function createSpreadThresholdRule(document: Document): HTMLElement {
const rule = document.createElement("span");
rule.dataset.pluginSpreadThresholdRule = "and-gte";
applySpreadThresholdRuleStyles(rule);
const emphasis = document.createElement("strong");
emphasis.textContent = "AND";
const detail = document.createElement("small");
detail.textContent = "每项取值 >= 输入值";
rule.append("全部满足", emphasis, detail);
return rule;
}
function readSpreadThresholdInputs(
root: HTMLElement
): Record<keyof SpreadThresholdFilter["thresholds"], HTMLInputElement> {
@@ -719,8 +781,8 @@ function findNativeActionButton(
}
const candidates = Array.from(root.querySelectorAll("button")).filter(
(element): element is HTMLElement =>
element instanceof document.defaultView!.HTMLElement
(element): element is HTMLButtonElement =>
element instanceof document.defaultView!.HTMLButtonElement
);
return (
candidates.find((element) => normalizeText(element.textContent) === text) ?? null
@@ -739,12 +801,12 @@ function applyToolbarRootStyles(root: HTMLElement): void {
function applyToolbarPanelStyles(panel: HTMLElement): void {
panel.style.display = "flex";
panel.style.flexDirection = "column";
panel.style.alignItems = "stretch";
panel.style.alignItems = "center";
panel.style.gap = "6px";
panel.style.flex = "1 1 auto";
panel.style.minWidth = "0";
panel.style.padding = "2px 0";
panel.style.overflowX = "visible";
panel.style.padding = "0";
panel.style.overflowX = "hidden";
panel.style.overflowY = "hidden";
}
@@ -762,41 +824,42 @@ function applyToolbarRowStyles(row: HTMLElement): void {
function applyToolbarGroupStyles(group: HTMLElement): void {
group.style.display = "flex";
group.style.alignItems = "center";
group.style.gap = "6px";
group.style.gap = "8px";
group.style.minWidth = "0";
group.style.flex = "0 0 auto";
group.style.flexWrap = "nowrap";
}
function applyThresholdGroupStyles(group: HTMLElement): void {
group.style.display = "flex";
group.style.alignItems = "center";
group.style.gap = "7px";
group.style.minWidth = "0";
group.style.flex = "1 1 auto";
group.style.flexWrap = "nowrap";
group.style.overflowX = "auto";
group.style.overflowY = "hidden";
}
function createToolbarGroupTitle(document: Document, label: string): HTMLElement {
const title = document.createElement("span");
title.dataset.pluginToolbarTitle = label;
title.textContent = label;
title.style.color = "#64748b";
title.style.display = "flex";
title.style.alignItems = "center";
title.style.height = "32px";
title.style.padding = "0 10px";
title.style.border = "1px solid #cfe0ff";
title.style.borderRadius = "8px";
title.style.background = "#eef5ff";
title.style.color = "#2563eb";
title.style.fontSize = "12px";
title.style.fontWeight = "700";
title.style.lineHeight = "32px";
title.style.fontWeight = "900";
title.style.flex = "0 0 auto";
title.style.whiteSpace = "nowrap";
return title;
}
function applyToolbarDividerStyles(divider: HTMLElement): void {
divider.style.width = "1px";
divider.style.height = "24px";
divider.style.background = "#e5e7eb";
divider.style.flex = "0 0 auto";
}
function applyToolbarActionStyles(actions: HTMLElement): void {
actions.style.display = "flex";
actions.style.alignItems = "center";
actions.style.gap = "8px";
actions.style.flex = "0 0 auto";
actions.style.paddingLeft = "10px";
actions.style.borderLeft = "1px solid #e5e7eb";
}
function applyNativeControlStyles(
document: Document,
controls: {
@@ -876,7 +939,14 @@ function applyNativeControlStyles(
element.dataset.pluginSpreadThreshold
) {
element.style.width =
element.dataset.pluginSpreadThreshold === "playMedian" ? "104px" : "78px";
element.dataset.pluginSpreadThreshold === "playMedian" ? "82px" : "58px";
element.style.minWidth = "0";
element.style.height = "26px";
element.style.border = "0";
element.style.borderRadius = "0";
element.style.padding = "0";
element.style.outline = "0";
element.style.fontWeight = "700";
}
});
}
@@ -896,11 +966,61 @@ function applyPrimaryButtonStyles(
"background-color 0.16s ease, border-color 0.16s ease, box-shadow 0.16s ease, transform 0.16s ease";
}
function applySpreadThresholdControlStyles(control: HTMLElement): void {
control.style.display = "grid";
control.style.gridTemplateColumns = "auto auto 1fr";
control.style.alignItems = "center";
control.style.gap = "6px";
control.style.height = "32px";
control.style.padding = "0 8px";
control.style.border = "1px solid #dbe2ec";
control.style.borderRadius = "8px";
control.style.background = "#ffffff";
control.style.flex = "0 0 auto";
}
function applySpreadThresholdConjunctionStyles(conjunction: HTMLElement): void {
conjunction.style.color = "#0f8a5f";
conjunction.style.fontSize = "12px";
conjunction.style.fontWeight = "900";
conjunction.style.whiteSpace = "nowrap";
conjunction.style.flex = "0 0 auto";
}
function applySpreadThresholdRuleStyles(rule: HTMLElement): void {
rule.style.display = "flex";
rule.style.alignItems = "center";
rule.style.height = "32px";
rule.style.padding = "0 10px";
rule.style.border = "1px solid #d9efe7";
rule.style.borderRadius = "8px";
rule.style.background = "#f0fbf6";
rule.style.color = "#0f8a5f";
rule.style.fontSize = "12px";
rule.style.fontWeight = "900";
rule.style.whiteSpace = "nowrap";
rule.style.flex = "0 0 auto";
Array.from(rule.children).forEach((child) => {
if (child instanceof rule.ownerDocument.defaultView!.HTMLElement) {
child.style.marginLeft = child.tagName === "SMALL" ? "6px" : "3px";
if (child.tagName === "SMALL") {
child.style.color = "#64748b";
child.style.fontSize = "12px";
child.style.fontWeight = "700";
}
}
});
}
function applyStatusStyles(statusText: HTMLElement): void {
statusText.style.color = "#64748b";
statusText.style.fontSize = "12px";
statusText.style.lineHeight = "20px";
statusText.style.marginLeft = "4px";
statusText.style.marginLeft = "0";
statusText.style.flex = "1 1 auto";
statusText.style.minWidth = "120px";
statusText.style.textAlign = "center";
statusText.style.whiteSpace = "nowrap";
}
@@ -949,6 +1069,19 @@ function ensurePluginActionButtonTheme(document: Document): void {
transform: none !important;
box-shadow: none !important;
}
[data-plugin-spread-threshold-control] span,
[data-plugin-spread-threshold-control] b {
color: #667085 !important;
font-size: 12px !important;
font-weight: 700 !important;
white-space: nowrap !important;
}
[data-plugin-spread-threshold-control] b {
color: #0f8a5f !important;
font-weight: 900 !important;
}
`;
document.head.appendChild(style);
}
@@ -967,8 +1100,8 @@ function findButtonContainingText(
}
const candidates = Array.from(root.querySelectorAll("button")).filter(
(element): element is HTMLElement =>
element instanceof document.defaultView!.HTMLElement
(element): element is HTMLButtonElement =>
element instanceof document.defaultView!.HTMLButtonElement
);
return candidates.find((element) => normalizeText(element.textContent).includes(text)) ?? null;
+1 -1
View File
@@ -1 +1 @@
export const DEFAULT_BATCH_SUBMIT_BASE_URL = "http://192.168.31.21:8083";
export const DEFAULT_BATCH_SUBMIT_BASE_URL = "http://localhost:8083";