feat: add abs alias, refresh extension panel, and bump to 0.16.1-fork.1

This commit is contained in:
leeguooooo
2026-03-04 09:57:56 +09:00
parent eedf824af7
commit 66a39f3c83
9 changed files with 288 additions and 171 deletions
+164 -55
View File
@@ -1,119 +1,192 @@
:root {
color-scheme: light dark;
--bg: #111827;
--card: #1f2937;
--border: #374151;
--text: #f9fafb;
--muted: #d1d5db;
--accent: #22c55e;
--bg: #0d1117;
--panel: #161b22;
--item-bg: rgba(255, 255, 255, 0.03);
--item-hover: rgba(255, 255, 255, 0.06);
--border: #30363d;
--border-focus: #484f58;
--text-main: #e6edf3;
--text-muted: #848d97;
--accent: #2f81f7;
--accent-soft: rgba(47, 129, 247, 0.1);
--success: #3fb950;
--warning: #d29922;
--font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
}
* {
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
}
body {
margin: 0;
padding: 12px;
background: radial-gradient(circle at top left, #1f2937, #111827);
color: var(--text);
font:
13px/1.5 -apple-system,
BlinkMacSystemFont,
'Segoe UI',
sans-serif;
padding: 20px;
background-color: var(--bg);
color: var(--text-main);
font-family: var(--font-family);
font-size: 13px;
line-height: 1.5;
}
/* Scrollbar */
::-webkit-scrollbar { width: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 10px; }
::-webkit-scrollbar-thumb:hover { background: var(--border-focus); }
header {
display: flex;
gap: 8px;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
flex-direction: column;
gap: 16px;
margin-bottom: 24px;
}
h1 {
font-size: 15px;
font-size: 16px;
font-weight: 600;
margin: 0;
display: flex;
align-items: center;
gap: 8px;
}
button {
background: #0f172a;
color: var(--text);
border: 1px solid var(--border);
border-radius: 8px;
padding: 6px 8px;
cursor: pointer;
}
button:hover {
border-color: var(--accent);
h1::before {
content: "";
display: block;
width: 12px;
height: 12px;
background: var(--accent);
border-radius: 3px;
box-shadow: 0 0 10px var(--accent);
}
.actions {
display: flex;
gap: 6px;
gap: 8px;
}
button {
all: unset;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 6px 12px;
background: var(--panel);
border: 1px solid var(--border);
border-radius: 6px;
color: var(--text-main);
font-size: 12px;
font-weight: 500;
cursor: pointer;
transition: all 0.15s ease;
}
button:hover {
background: var(--item-hover);
border-color: var(--border-focus);
}
#refresh-btn {
background: var(--accent);
border-color: var(--accent);
color: #ffffff;
}
#refresh-btn:hover {
background: #4493f8;
border-color: #4493f8;
}
.card {
background: color-mix(in srgb, var(--card) 88%, #000 12%);
background: var(--panel);
border: 1px solid var(--border);
border-radius: 10px;
padding: 10px;
margin-bottom: 10px;
padding: 16px;
margin-bottom: 20px;
overflow: hidden;
}
h3 {
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-muted);
margin: 0 0 12px 0;
font-weight: 600;
}
.stack {
display: flex;
flex-direction: column;
gap: 10px;
gap: 16px;
}
.session-title {
display: flex;
justify-content: space-between;
align-items: center;
gap: 8px;
margin-bottom: 6px;
margin-bottom: 12px;
}
.session-title strong {
.session-title h4 {
font-size: 14px;
font-weight: 600;
margin: 0;
color: var(--accent);
}
.tags {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin: 6px 0;
gap: 4px;
margin: 8px 0;
}
.tag {
border: 1px solid var(--border);
border-radius: 999px;
padding: 2px 7px;
color: var(--muted);
font-size: 12px;
background: var(--accent-soft);
color: var(--accent);
border: 1px solid transparent;
padding: 1px 6px;
border-radius: 4px;
font-size: 11px;
font-weight: 500;
}
.list {
display: flex;
flex-direction: column;
gap: 4px;
gap: 1px; /* Divider effect */
background: var(--border);
border: 1px solid var(--border);
border-radius: 6px;
overflow: hidden;
margin-top: 12px;
}
.item {
border: 1px solid color-mix(in srgb, var(--border) 85%, #000 15%);
border-radius: 8px;
padding: 6px 7px;
background: rgba(255, 255, 255, 0.03);
overflow: hidden;
background: var(--panel);
padding: 10px 12px;
display: flex;
flex-direction: column;
gap: 2px;
transition: background 0.1s ease;
}
.item:hover {
background: var(--item-hover);
}
.item-title {
font-weight: 500;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: var(--text-main);
}
.item-url {
color: var(--muted);
color: var(--text-muted);
font-size: 11px;
white-space: nowrap;
overflow: hidden;
@@ -122,9 +195,45 @@ button:hover {
.row-actions {
display: flex;
gap: 6px;
gap: 4px;
margin-top: 12px;
padding-top: 12px;
border-top: 1px solid var(--border);
}
.row-actions button {
padding: 4px 8px;
font-size: 11px;
background: transparent;
}
.empty {
color: var(--muted);
color: var(--text-muted);
text-align: center;
padding: 40px 0;
font-size: 12px;
}
code {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
background: rgba(110, 118, 129, 0.4);
padding: 2px 5px;
border-radius: 4px;
font-size: 11px;
}
#summary code {
color: var(--warning);
}
/* Summary Grid */
#summary .tags {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
gap: 8px;
}
#summary .tag {
text-align: center;
padding: 6px;
}
+109 -109
View File
@@ -16,86 +16,89 @@ function createTag(text) {
}
function renderSummary(state) {
summaryEl.innerHTML = '';
summaryEl.innerHTML = '<h3>Overview</h3>';
const options = state.options || {};
const title = document.createElement('div');
title.innerHTML = `<strong>Overview</strong> · extensionId: <code>${state.extensionId}</code>`;
const idInfo = document.createElement('div');
idInfo.style.marginBottom = '12px';
idInfo.style.fontSize = '11px';
idInfo.style.color = 'var(--text-muted)';
idInfo.innerHTML = `Extension ID: <code>${state.extensionId}</code>`;
summaryEl.appendChild(idInfo);
const tags = document.createElement('div');
tags.className = 'tags';
tags.appendChild(createTag(`sessions: ${state.totals.sessions}`));
tags.appendChild(createTag(`tabs: ${state.totals.tabs}`));
tags.appendChild(createTag(`Sessions: ${state.totals.sessions}`));
tags.appendChild(createTag(`Tabs: ${state.totals.tabs}`));
tags.appendChild(
createTag(`isolation: ${options.strictWindowIsolation === false ? 'off' : 'on'}`)
createTag(`Isolation: ${options.strictWindowIsolation === false ? 'Off' : 'On'}`)
);
tags.appendChild(
createTag(`activation-guard: ${options.suppressCrossWindowActivation === false ? 'off' : 'on'}`)
createTag(`Guard: ${options.suppressCrossWindowActivation === false ? 'Off' : 'On'}`)
);
tags.appendChild(
createTag(`auto-clean: ${options.autoCleanEmptyGroups === false ? 'off' : 'on'}`)
createTag(`Auto-Clean: ${options.autoCleanEmptyGroups === false ? 'Off' : 'On'}`)
);
const optionActions = document.createElement('div');
optionActions.className = 'row-actions';
const isolationBtn = document.createElement('button');
isolationBtn.type = 'button';
isolationBtn.textContent =
options.strictWindowIsolation === false ? 'Enable Isolation' : 'Disable Isolation';
isolationBtn.addEventListener('click', async () => {
await send({
type: 'AB_PANEL_SET_OPTIONS',
options: { ...options, strictWindowIsolation: options.strictWindowIsolation === false },
});
await refresh();
});
const createOptionBtn = (text, active, onClick) => {
const btn = document.createElement('button');
btn.type = 'button';
btn.textContent = text;
if (active) btn.style.borderColor = 'var(--accent)';
btn.addEventListener('click', onClick);
return btn;
};
const guardBtn = document.createElement('button');
guardBtn.type = 'button';
guardBtn.textContent =
options.suppressCrossWindowActivation === false ? 'Enable Guard' : 'Disable Guard';
guardBtn.addEventListener('click', async () => {
await send({
type: 'AB_PANEL_SET_OPTIONS',
options: {
...options,
suppressCrossWindowActivation: options.suppressCrossWindowActivation === false,
},
});
await refresh();
});
optionActions.appendChild(
createOptionBtn('Strict Isolation', options.strictWindowIsolation !== false, async () => {
await send({
type: 'AB_PANEL_SET_OPTIONS',
options: { ...options, strictWindowIsolation: options.strictWindowIsolation === false },
});
await refresh();
})
);
const autoCleanBtn = document.createElement('button');
autoCleanBtn.type = 'button';
autoCleanBtn.textContent =
options.autoCleanEmptyGroups === false ? 'Enable Auto-Clean' : 'Disable Auto-Clean';
autoCleanBtn.addEventListener('click', async () => {
await send({
type: 'AB_PANEL_SET_OPTIONS',
options: {
...options,
autoCleanEmptyGroups: options.autoCleanEmptyGroups === false,
},
});
await refresh();
});
optionActions.appendChild(
createOptionBtn('Activation Guard', options.suppressCrossWindowActivation !== false, async () => {
await send({
type: 'AB_PANEL_SET_OPTIONS',
options: {
...options,
suppressCrossWindowActivation: options.suppressCrossWindowActivation === false,
},
});
await refresh();
})
);
optionActions.appendChild(isolationBtn);
optionActions.appendChild(guardBtn);
optionActions.appendChild(autoCleanBtn);
optionActions.appendChild(
createOptionBtn('Auto-Clean', options.autoCleanEmptyGroups !== false, async () => {
await send({
type: 'AB_PANEL_SET_OPTIONS',
options: {
...options,
autoCleanEmptyGroups: options.autoCleanEmptyGroups === false,
},
});
await refresh();
})
);
summaryEl.appendChild(title);
summaryEl.appendChild(tags);
summaryEl.appendChild(optionActions);
}
function renderSessions(state) {
sessionsEl.innerHTML = '';
sessionsEl.innerHTML = '<h3>Active Sessions</h3>';
if (!state.sessions || state.sessions.length === 0) {
const empty = document.createElement('div');
empty.className = 'card empty';
empty.textContent = 'No managed sessions yet.';
empty.textContent = 'No active sessions monitored.';
sessionsEl.appendChild(empty);
return;
}
@@ -107,31 +110,71 @@ function renderSessions(state) {
const titleRow = document.createElement('div');
titleRow.className = 'session-title';
const titleLeft = document.createElement('strong');
const titleLeft = document.createElement('h4');
titleLeft.textContent = session.session;
const actions = document.createElement('div');
actions.className = 'row-actions';
const focusBtn = document.createElement('button');
focusBtn.type = 'button';
focusBtn.textContent = 'Focus';
focusBtn.addEventListener('click', async () => {
await send({ type: 'AB_PANEL_FOCUS_SESSION', session: session.session });
await refresh();
});
titleRow.appendChild(titleLeft);
titleRow.appendChild(focusBtn);
const tags = document.createElement('div');
tags.className = 'tags';
tags.appendChild(createTag(`Window: ${session.windowId ?? 'N/A'}`));
tags.appendChild(createTag(`Tabs: ${session.tabs.length}`));
if (session.group) {
tags.appendChild(createTag(`G: ${session.group.title || 'Untitled'}`));
}
if (session.allowedDomains && session.allowedDomains.length > 0) {
tags.appendChild(createTag(`Allowlist: ${session.allowedDomains.length} domains`));
}
const list = document.createElement('div');
list.className = 'list';
for (const tab of session.tabs.slice(0, 10)) {
const item = document.createElement('div');
item.className = 'item';
const t = document.createElement('div');
t.className = 'item-title';
if (tab.active) {
const dot = document.createElement('span');
dot.textContent = '●';
dot.style.color = 'var(--success)';
dot.style.marginRight = '6px';
dot.style.fontSize = '10px';
t.appendChild(dot);
}
t.appendChild(document.createTextNode(tab.title || '(Untitled)'));
const u = document.createElement('div');
u.className = 'item-url';
u.textContent = tab.url || 'about:blank';
item.appendChild(t);
item.appendChild(u);
list.appendChild(item);
}
const footerActions = document.createElement('div');
footerActions.className = 'row-actions';
const keepBtn = document.createElement('button');
keepBtn.type = 'button';
keepBtn.textContent = 'Keep Only This';
keepBtn.textContent = 'Isolate Session';
keepBtn.addEventListener('click', async () => {
await send({ type: 'AB_PANEL_CLOSE_OTHER_SESSION_TABS', session: session.session });
await refresh();
});
const policyBtn = document.createElement('button');
policyBtn.type = 'button';
policyBtn.textContent = 'Set Allowlist';
policyBtn.textContent = 'Config Policy';
policyBtn.addEventListener('click', async () => {
const current = (session.allowedDomains || []).join(',');
const input = window.prompt('Allowed domains (comma-separated)', current);
@@ -144,62 +187,19 @@ function renderSessions(state) {
await refresh();
});
actions.appendChild(focusBtn);
actions.appendChild(keepBtn);
actions.appendChild(policyBtn);
titleRow.appendChild(titleLeft);
titleRow.appendChild(actions);
const tags = document.createElement('div');
tags.className = 'tags';
tags.appendChild(createTag(`window: ${session.windowId ?? 'n/a'}`));
tags.appendChild(createTag(`tabs: ${session.tabs.length}`));
if (session.group) {
tags.appendChild(createTag(`group: ${session.group.title || session.group.id}`));
tags.appendChild(createTag(`color: ${session.group.color}`));
tags.appendChild(createTag(`collapsed: ${session.group.collapsed}`));
}
if (session.allowedDomains && session.allowedDomains.length > 0) {
tags.appendChild(createTag(`allowlist: ${session.allowedDomains.join(', ')}`));
}
if (session.riskHints && session.riskHints.length > 0) {
for (const hint of session.riskHints) {
tags.appendChild(createTag(`risk: ${hint}`));
}
}
const list = document.createElement('div');
list.className = 'list';
for (const tab of session.tabs.slice(0, 10)) {
const item = document.createElement('div');
item.className = 'item';
const t = document.createElement('div');
t.className = 'item-title';
t.textContent = `${tab.active ? '● ' : ''}${tab.title || '(untitled)'}`;
const u = document.createElement('div');
u.className = 'item-url';
u.textContent = tab.url || 'about:blank';
item.appendChild(t);
item.appendChild(u);
list.appendChild(item);
}
footerActions.appendChild(keepBtn);
footerActions.appendChild(policyBtn);
card.appendChild(titleRow);
card.appendChild(tags);
card.appendChild(list);
card.appendChild(footerActions);
sessionsEl.appendChild(card);
}
}
function renderDownloads(state) {
downloadsEl.innerHTML = '<strong>Recent Downloads</strong>';
downloadsEl.innerHTML = '<h3>Recent Downloads</h3>';
const list = document.createElement('div');
list.className = 'list';