UX improvements

This commit is contained in:
2026-01-18 12:33:59 -05:00
parent 3f51053ff6
commit 4f6450d5f3
6 changed files with 92 additions and 8 deletions

View File

@@ -18,6 +18,7 @@ const DEFAULT_SETTINGS = {
shortcuts: [], shortcuts: [],
theme: "system", theme: "system",
toolbarAutoHide: true, toolbarAutoHide: true,
alwaysShowOutput: false,
workspaces: [] workspaces: []
}; };

View File

@@ -1,7 +1,7 @@
{ {
"manifest_version": 3, "manifest_version": 3,
"name": "SiteCompanion", "name": "SiteCompanion",
"version": "0.4.3", "version": "0.4.4",
"description": "AI companion for site-bound text extraction and tasks.", "description": "AI companion for site-bound text extraction and tasks.",
"permissions": ["storage", "activeTab"], "permissions": ["storage", "activeTab"],
"host_permissions": ["<all_urls>"], "host_permissions": ["<all_urls>"],

View File

@@ -38,6 +38,10 @@
<label for="urlPatternInput">URL Match Pattern</label> <label for="urlPatternInput">URL Match Pattern</label>
<input type="text" id="urlPatternInput" placeholder="example.com/*" /> <input type="text" id="urlPatternInput" placeholder="example.com/*" />
</div> </div>
<div class="field">
<label for="workspaceSelect">Workspace</label>
<select id="workspaceSelect"></select>
</div>
<div class="row"> <div class="row">
<button id="retryExtractBtn" class="ghost">Retry</button> <button id="retryExtractBtn" class="ghost">Retry</button>
<button id="confirmSiteBtn" class="accent">Confirm</button> <button id="confirmSiteBtn" class="accent">Confirm</button>

View File

@@ -11,6 +11,7 @@ const settingsBtn = document.getElementById("settingsBtn");
const copyRenderedBtn = document.getElementById("copyRenderedBtn"); const copyRenderedBtn = document.getElementById("copyRenderedBtn");
const copyRawBtn = document.getElementById("copyRawBtn"); const copyRawBtn = document.getElementById("copyRawBtn");
const clearOutputBtn = document.getElementById("clearOutputBtn"); const clearOutputBtn = document.getElementById("clearOutputBtn");
const outputSection = document.querySelector(".output");
const OUTPUT_STORAGE_KEY = "lastOutput"; const OUTPUT_STORAGE_KEY = "lastOutput";
const AUTO_RUN_KEY = "autoRunDefaultTask"; const AUTO_RUN_KEY = "autoRunDefaultTask";
@@ -30,6 +31,7 @@ const extractFullBtn = document.getElementById("extractFullBtn");
const extractedPreview = document.getElementById("extractedPreview"); const extractedPreview = document.getElementById("extractedPreview");
const siteNameInput = document.getElementById("siteNameInput"); const siteNameInput = document.getElementById("siteNameInput");
const urlPatternInput = document.getElementById("urlPatternInput"); const urlPatternInput = document.getElementById("urlPatternInput");
const workspaceSelect = document.getElementById("workspaceSelect");
const retryExtractBtn = document.getElementById("retryExtractBtn"); const retryExtractBtn = document.getElementById("retryExtractBtn");
const confirmSiteBtn = document.getElementById("confirmSiteBtn"); const confirmSiteBtn = document.getElementById("confirmSiteBtn");
const currentWorkspaceName = document.getElementById("currentWorkspaceName"); const currentWorkspaceName = document.getElementById("currentWorkspaceName");
@@ -54,7 +56,8 @@ const state = {
siteTextTarget: null, siteTextTarget: null,
selectedTaskId: "", selectedTaskId: "",
selectedEnvId: "", selectedEnvId: "",
selectedProfileId: "" selectedProfileId: "",
alwaysShowOutput: false
}; };
async function switchState(stateName) { async function switchState(stateName) {
@@ -66,11 +69,13 @@ async function switchState(stateName) {
if (stateName === "unknown") { if (stateName === "unknown") {
unknownSiteState.classList.remove("hidden"); unknownSiteState.classList.remove("hidden");
} else if (stateName === "review") { } else if (stateName === "review") {
updateWorkspaceOptions();
extractionReviewState.classList.remove("hidden"); extractionReviewState.classList.remove("hidden");
} else if (stateName === "normal") { } else if (stateName === "normal") {
normalExecutionState.classList.remove("hidden"); normalExecutionState.classList.remove("hidden");
} }
setMinimalStatus(""); setMinimalStatus("");
updateOutputVisibility();
await chrome.storage.local.set({ lastPopupState: stateName }); await chrome.storage.local.set({ lastPopupState: stateName });
} }
@@ -80,7 +85,8 @@ function buildPopupDraft() {
siteText: state.siteText || "", siteText: state.siteText || "",
urlPattern: urlPatternInput?.value?.trim() || "", urlPattern: urlPatternInput?.value?.trim() || "",
siteName: siteNameInput?.value?.trim() || "", siteName: siteNameInput?.value?.trim() || "",
siteTextTarget: state.siteTextTarget siteTextTarget: state.siteTextTarget,
workspaceId: workspaceSelect?.value || "global"
}; };
} }
@@ -104,6 +110,9 @@ function applyPopupDraft(draft) {
if (typeof draft.siteName === "string") { if (typeof draft.siteName === "string") {
siteNameInput.value = draft.siteName; siteNameInput.value = draft.siteName;
} }
if (typeof draft.workspaceId === "string" && workspaceSelect) {
workspaceSelect.value = draft.workspaceId;
}
if (draft.siteTextTarget) { if (draft.siteTextTarget) {
state.siteTextTarget = draft.siteTextTarget; state.siteTextTarget = draft.siteTextTarget;
} else if (typeof draft.siteTextSelector === "string") { } else if (typeof draft.siteTextSelector === "string") {
@@ -245,6 +254,31 @@ function normalizeStoredExtractTarget(site) {
return null; return null;
} }
function updateWorkspaceOptions() {
if (!workspaceSelect) return;
const selected = workspaceSelect.value || "global";
workspaceSelect.innerHTML = "";
const globalOpt = document.createElement("option");
globalOpt.value = "global";
globalOpt.textContent = "Global";
workspaceSelect.appendChild(globalOpt);
for (const workspace of state.workspaces || []) {
const opt = document.createElement("option");
opt.value = workspace.id;
opt.textContent = workspace.name || "Untitled Workspace";
workspaceSelect.appendChild(opt);
}
if (selected) {
workspaceSelect.value = selected;
}
if (!workspaceSelect.value) {
workspaceSelect.value = "global";
}
}
function filterApiConfigsForScope(apiConfigs, workspace, site) { function filterApiConfigsForScope(apiConfigs, workspace, site) {
const workspaceDisabled = workspace?.disabledInherited?.apiConfigs || []; const workspaceDisabled = workspace?.disabledInherited?.apiConfigs || [];
const siteDisabled = site?.disabledInherited?.apiConfigs || []; const siteDisabled = site?.disabledInherited?.apiConfigs || [];
@@ -527,6 +561,13 @@ function setAnalyzing(isAnalyzing) {
updateProfileSelectState(); updateProfileSelectState();
} }
function updateOutputVisibility() {
if (!outputSection) return;
const shouldHide =
state.currentPopupState !== "normal" && !state.alwaysShowOutput;
outputSection.classList.toggle("hidden", shouldHide);
}
function updateSiteTextCount() { function updateSiteTextCount() {
postingCountEl.textContent = `Site Text: ${state.siteText.length} chars`; postingCountEl.textContent = `Site Text: ${state.siteText.length} chars`;
} }
@@ -766,6 +807,7 @@ async function loadConfig() {
"workspaces", "workspaces",
"sites", "sites",
"theme", "theme",
"alwaysShowOutput",
LAST_TASK_KEY, LAST_TASK_KEY,
LAST_ENV_KEY, LAST_ENV_KEY,
LAST_PROFILE_KEY LAST_PROFILE_KEY
@@ -789,6 +831,7 @@ async function loadConfig() {
: state.workspaces; : state.workspaces;
state.sites = sites; state.sites = sites;
state.workspaces = workspaces; state.workspaces = workspaces;
updateWorkspaceOptions();
if (needsSiteUpdate) { if (needsSiteUpdate) {
await chrome.storage.local.set({ sites }); await chrome.storage.local.set({ sites });
} }
@@ -810,7 +853,9 @@ async function loadConfig() {
if (stored.theme) { if (stored.theme) {
state.globalTheme = stored.theme; state.globalTheme = stored.theme;
} }
state.alwaysShowOutput = Boolean(stored.alwaysShowOutput);
applyTheme(resolveThemeForPopup(state.globalTheme)); applyTheme(resolveThemeForPopup(state.globalTheme));
updateOutputVisibility();
const effectiveEnvs = resolveEffectiveList( const effectiveEnvs = resolveEffectiveList(
envs, envs,
@@ -1206,12 +1251,18 @@ urlPatternInput.addEventListener("input", () => {
void persistPopupDraft(); void persistPopupDraft();
}); });
workspaceSelect?.addEventListener("change", () => {
if (state.currentPopupState !== "review") return;
void persistPopupDraft();
});
retryExtractBtn.addEventListener("click", () => { retryExtractBtn.addEventListener("click", () => {
switchState("unknown"); switchState("unknown");
partialTextPaste.value = ""; partialTextPaste.value = "";
extractedPreview.textContent = ""; extractedPreview.textContent = "";
urlPatternInput.value = ""; urlPatternInput.value = "";
siteNameInput.value = ""; siteNameInput.value = "";
if (workspaceSelect) workspaceSelect.value = "global";
state.siteText = ""; state.siteText = "";
state.siteTextTarget = null; state.siteTextTarget = null;
setMinimalStatus(""); setMinimalStatus("");
@@ -1246,17 +1297,29 @@ confirmSiteBtn.addEventListener("click", async () => {
id: `site-${Date.now()}`, id: `site-${Date.now()}`,
name, name,
urlPattern: pattern, urlPattern: pattern,
workspaceId: "global", // Default to global for now workspaceId: workspaceSelect?.value || "global",
extractTarget: state.siteTextTarget extractTarget: state.siteTextTarget
}; };
state.sites.push(newSite); state.sites.push(newSite);
await chrome.storage.local.set({ sites: state.sites }); state.outputRaw = "";
renderOutput();
await persistOutputNow();
await chrome.storage.local.set({
sites: state.sites,
[LAST_TASK_KEY]: "",
[LAST_ENV_KEY]: "",
[LAST_PROFILE_KEY]: "",
lastPopupState: "normal"
});
await clearPopupDraft(); await clearPopupDraft();
state.currentSite = newSite; state.currentSite = newSite;
state.currentWorkspace = { name: "Global", id: "global" }; const selectedWorkspace =
currentWorkspaceName.textContent = "Global"; state.workspaces.find((entry) => entry.id === newSite.workspaceId) || null;
switchState("normal"); state.currentWorkspace = selectedWorkspace || { name: "Global", id: "global" };
currentWorkspaceName.textContent = state.currentWorkspace.name || "Global";
await loadConfig();
await switchState("normal");
updateSiteTextCount(); updateSiteTextCount();
setStatus("Site saved."); setStatus("Site saved.");
}); });
@@ -1423,4 +1486,8 @@ chrome.storage.onChanged.addListener((changes) => {
state.globalTheme = changes.theme.newValue || "system"; state.globalTheme = changes.theme.newValue || "system";
applyTheme(resolveThemeForPopup(state.globalTheme)); applyTheme(resolveThemeForPopup(state.globalTheme));
} }
if (changes.alwaysShowOutput) {
state.alwaysShowOutput = Boolean(changes.alwaysShowOutput.newValue);
updateOutputVisibility();
}
}); });

View File

@@ -87,6 +87,12 @@
Auto-hide toolbar on unknown sites Auto-hide toolbar on unknown sites
</label> </label>
</div> </div>
<div class="field">
<label class="toggle-label">
<input id="alwaysShowOutput" type="checkbox" />
Always show output buffer in popup UI
</label>
</div>
</div> </div>
</details> </details>

View File

@@ -20,6 +20,7 @@ const sidebarErrorsEl = document.getElementById("sidebarErrors");
const themeSelect = document.getElementById("themeSelect"); const themeSelect = document.getElementById("themeSelect");
const toolbarPositionSelect = document.getElementById("toolbarPositionSelect"); const toolbarPositionSelect = document.getElementById("toolbarPositionSelect");
const toolbarAutoHide = document.getElementById("toolbarAutoHide"); const toolbarAutoHide = document.getElementById("toolbarAutoHide");
const alwaysShowOutput = document.getElementById("alwaysShowOutput");
const globalSitesContainer = document.getElementById("globalSites"); const globalSitesContainer = document.getElementById("globalSites");
const toc = document.querySelector(".toc"); const toc = document.querySelector(".toc");
const tocResizer = document.getElementById("tocResizer"); const tocResizer = document.getElementById("tocResizer");
@@ -3527,6 +3528,7 @@ async function loadSettings() {
sites = [], sites = [],
toolbarPosition = "bottom-right", toolbarPosition = "bottom-right",
toolbarAutoHide: storedToolbarAutoHide = true, toolbarAutoHide: storedToolbarAutoHide = true,
alwaysShowOutput: storedAlwaysShowOutput = false,
sidebarWidth sidebarWidth
} = await getStorage([ } = await getStorage([
"apiKey", "apiKey",
@@ -3563,6 +3565,9 @@ async function loadSettings() {
if (toolbarAutoHide) { if (toolbarAutoHide) {
toolbarAutoHide.checked = Boolean(storedToolbarAutoHide); toolbarAutoHide.checked = Boolean(storedToolbarAutoHide);
} }
if (alwaysShowOutput) {
alwaysShowOutput.checked = Boolean(storedAlwaysShowOutput);
}
if (Number.isFinite(sidebarWidth)) { if (Number.isFinite(sidebarWidth)) {
applySidebarWidth(sidebarWidth); applySidebarWidth(sidebarWidth);
} }
@@ -3962,6 +3967,7 @@ async function saveSettings() {
? toolbarPositionSelect.value ? toolbarPositionSelect.value
: "bottom-right", : "bottom-right",
toolbarAutoHide: toolbarAutoHide ? toolbarAutoHide.checked : true, toolbarAutoHide: toolbarAutoHide ? toolbarAutoHide.checked : true,
alwaysShowOutput: alwaysShowOutput ? alwaysShowOutput.checked : false,
workspaces, workspaces,
sites sites
}); });