Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions index.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@
"id": "bennett-ui-improvements",
"name": "Bennett UI Improvements",
"description": "迁移自 b-nnett Bennett UI 的 renderer-only UI 增强",
"version": "1.0.6-bigpizza.1",
"version": "1.0.8-bigpizza.1",
"author": "bennett; JHees",
"tags": [
"codex",
Expand All @@ -133,7 +133,7 @@
],
"homepage": "",
"script_url": "https://raw.githubusercontent.com/BigPizzaV3/CodexPlusPlusScriptMarket/main/scripts/bennett-ui-improvements.js",
"sha256": "087a96fd4b407eb86c15e21cf7612debd7c27575638f64b840322e43675aef5d"
"sha256": "20b439e067ffa8a16580c750b63478f4220dcafdfe6e490ed15c8d76753c7ae4"
}
]
}
88 changes: 81 additions & 7 deletions scripts/bennett-ui-improvements.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"use strict";

const INSTALL_KEY = "__bennettUiImprovementsBigPizza";
const VERSION = "1.0.6-bigpizza.1";
const VERSION = "1.0.8-bigpizza.1";
const previous = window[INSTALL_KEY];
if (previous && typeof previous.stop === "function") {
try {
Expand Down Expand Up @@ -1148,16 +1148,61 @@ const FEATURES = {
.trim()
.toLowerCase();

const controlLabelText = (node) =>
[node.getAttribute?.("aria-label"), node.getAttribute?.("title")]
.filter(Boolean)
.join(" ")
.replace(/\s+/g, " ")
.trim()
.toLowerCase();

const isDeviceButton = (button) => {
const label = controlLabelText(button);
if (/\bmobile\b|\bphone\b|\bdevice\b|手机|移动|设备|连接/.test(label)) return true;
const text = controlText(button);
return /\bmobile\b|\bphone\b|\bdevice\b|手机|移动|设备|连接/.test(text);
return text.length <= 28 && /\bmobile\b|\bphone\b|\bdevice\b|手机|移动|设备|连接/.test(text);
};

const isSettingsButton = (button) => {
const text = controlText(button);
return /\bsettings?\b|preferences?|设置|偏好/.test(text);
};

const isNearSidebarBottom = (sidebar, node) => {
if (!(sidebar instanceof HTMLElement) || !(node instanceof HTMLElement)) return false;
const sidebarRect = sidebar.getBoundingClientRect();
const rect = node.getBoundingClientRect();
const bottomBand = Math.min(Math.max(sidebarRect.height * 0.22, 120), 240);
return rect.bottom >= sidebarRect.bottom - bottomBand;
};

const isCompactIconControl = (control) => {
const rect = control.getBoundingClientRect();
const text = controlText(control);
return rect.width > 0 && rect.width <= 56 && rect.height > 0 && rect.height <= 56 && text.length <= 32;
};

const isUsageControlNode = (node) =>
node.closest?.('[data-codexpp="usage-slot"], [data-codexpp="usage-box"], [data-codexpp="usage-boxes"]');

const rowControls = (row) =>
Array.from(row.querySelectorAll('button, a, [role="button"]'))
.filter((control) =>
control instanceof HTMLElement &&
isVisibleElement(control) &&
!isUsageControlNode(control),
);

const isSlotAfterRightmostControl = (slot) => {
const row = slot.parentElement;
if (!(row instanceof HTMLElement)) return false;
const controls = rowControls(row);
if (!controls.length) return true;
const slotRect = slot.getBoundingClientRect();
const rightmostControl = Math.max(...controls.map((control) => control.getBoundingClientRect().right));
return slotRect.right >= rightmostControl - 2;
};

const nearestControlRow = (sidebar, button) => {
const sidebarRect = sidebar.getBoundingClientRect();
let row = button.parentElement;
Expand All @@ -1169,15 +1214,17 @@ const FEATURES = {
const insideSidebar =
rect.left >= sidebarRect.left - 8 &&
rect.right <= sidebarRect.right + 8;
const nearBottom = isNearSidebarBottom(sidebar, row);
const looksLikeControlLayer =
insideSidebar &&
nearBottom &&
rect.height > 0 &&
rect.height <= 88 &&
(style.display === "flex" || style.display === "grid" || buttonCount >= 2);
if (looksLikeControlLayer) return row;
row = row.parentElement;
}
return button.parentElement instanceof HTMLElement ? button.parentElement : null;
return null;
};

const createInlineSlot = (row, anchor) => {
Expand All @@ -1197,18 +1244,45 @@ const FEATURES = {
const findSidebarSlot = () => {
const sidebar = findUsageSidebar();
if (!sidebar) return null;
const existingSlot = sidebar.querySelector('[data-codexpp="usage-slot"]');
for (const slot of sidebar.querySelectorAll('[data-codexpp="usage-slot"]')) {
const row = slot.parentElement;
if (
!(slot instanceof HTMLElement) ||
!(row instanceof HTMLElement) ||
!isNearSidebarBottom(sidebar, row) ||
!isSlotAfterRightmostControl(slot)
) {
slot.remove();
}
}
const existingSlot = Array.from(sidebar.querySelectorAll('[data-codexpp="usage-slot"]'))
.find((slot) =>
slot instanceof HTMLElement &&
slot.parentElement instanceof HTMLElement &&
isNearSidebarBottom(sidebar, slot.parentElement) &&
isSlotAfterRightmostControl(slot),
);
if (existingSlot instanceof HTMLElement) return existingSlot;

const controls = Array.from(sidebar.querySelectorAll('button, a, [role="button"]'))
.filter((button) => button instanceof HTMLElement && isVisibleElement(button));
.filter((button) =>
button instanceof HTMLElement &&
isVisibleElement(button) &&
isNearSidebarBottom(sidebar, button) &&
!isUsageControlNode(button),
);
const deviceControls = controls.filter(isDeviceButton);
const settingsControls = controls.filter(isSettingsButton);
const preferredControls = deviceControls.length ? deviceControls : settingsControls;
const compactControls = controls.filter(isCompactIconControl);
const preferredControls = deviceControls.length
? deviceControls
: compactControls.length
? compactControls
: settingsControls;
const ordered = (preferredControls.length ? preferredControls : controls).sort((a, b) => {
const ar = a.getBoundingClientRect();
const br = b.getBoundingClientRect();
return br.bottom - ar.bottom;
return br.right - ar.right || br.bottom - ar.bottom;
});

for (const button of ordered) {
Expand Down