Skip to content

Feat/layout test#4

Open
tronicum wants to merge 16 commits into
mainfrom
feat/layout-test
Open

Feat/layout test#4
tronicum wants to merge 16 commits into
mainfrom
feat/layout-test

Conversation

@tronicum

Copy link
Copy Markdown
Owner

No description provided.

tronicum@qvest added 16 commits July 17, 2026 20:41
…d README for Notion + vault

The Notion export subagent added a fetch() to api.notion.com but never
declared it in manifest.json's host_permissions (same class of drift as
the earlier SUPPORTED_HOSTS/supported-sites.json issue this session) —
would likely be blocked under Firefox's stricter MV3 permission enforcement
and is inconsistent with how api.github.com is already explicitly listed.

PRIVACY.md and README.md's Privacy/Integrations sections still only
mentioned Gist + webhook, making the privacy policy inaccurate now that
Notion (a new external endpoint) and direct-to-vault (new local file
writes) both exist. Updated both docs and the permissions table.
Live-investigated on a real logged-in ChatGPT account. Canvas code blocks
turned out to already extract clean code correctly (the existing 'pre'
handler's querySelector('code') happens to reach through the CodeMirror
markup) — the original TODO's assumption of a whole unhandled side-panel
UI didn't hold up. The one real gap: the language name lives as plain text
in a '.sticky' toolbar header (alongside Copy/Run buttons) inside the same
<pre>, which none of the three existing language-detection heuristics
catch, so every Canvas export shipped with no language tag on the fence.

Added a 4th heuristic, gated on an actual CodeMirror editor being present
(.cm-editor/.cm-content/#code-block-viewer) so it can't misfire on some
other platform's unrelated '.sticky' element.

Also confirmed real selectors for ChatGPT's history sidebar for Batch 8
(a[href^="/c/"], data-sidebarItem, scrollable nav container) — documented
in TODOs.md. Text-canvas variant and pagination/virtualization behavior at
scale remain unverified (free-tier canvas tool call misfired; account only
had ~28 conversations, too few to observe lazy-load).

4 new JSDOM tests, confirmed to fail pre-fix and pass post-fix. Full suite
267→271 passed, 0 failed, before and after.
…idebar (Batch 8)

Live-investigated against a real logged-in Claude account (two artifacts
created: Python + JS).

Claude Artifacts: confirmed this genuinely needs the side-panel handling
the original TODO assumed (unlike ChatGPT Canvas, which turned out
in-line). extractClaude()'s current artifactSuffix logic queries for
code/pre inside .artifact-block-cell, but that only ever contains a
title+filetype preview card with zero code inside — so Claude Artifacts
exports currently ship with NO artifact content at all. The real code
lives in a separate #wiggle-file-content panel outside any message turn,
with line-number-gutter text baked into textContent (needs per-line
stripping), and only the most-recently-opened artifact's content is ever
mounted — extracting all artifacts in a conversation needs click-through
per card (confirmed a bare el.click() doesn't trigger the swap; only a
real synthetic mouse click does). Not fixed this session — genuinely
multi-session work as originally scoped, unlike Canvas.

Claude sidebar (Batch 8): confirmed a[href^="/chat/"] selector, and that
naive textContent doubles the title (a hidden .sr-only span + a visible
aria-hidden duplicate) — use .sr-only for a clean title. Found Claude's
dedicated /recents page (full searchable list + native multi-select) as a
better Batch 8 enumeration target than the sidebar preview.
Instant scrollTop jump doesn't trigger lazy-load; confirmed via bulk-create
test that genuine incremental scroll + dispatched scroll events does
(28 -> 56 conversations, stabilizing at true max scrollTop). Corrects the
earlier 'inconclusive' note and documents the implementation implication
for Batch 8 orchestration code.
Adds src/content.js getConversationList() + {action:'getConversationList'}
message handler for ChatGPT/Claude, returning de-duplicated {title,url}
pairs from the current tab's history sidebar. Feature-detects by returning
[] on unsupported/logged-out pages, so the future popup UI can gate purely
on conversations.length without touching the existing single-conversation
extraction path.

7 new JSDOM tests (271 -> 278 passed, 0 failed). Selectors also re-verified
live against real open ChatGPT (28 convos) and Claude (8 convos) tabs.

Popup UI + background.js tab-cycling orchestration (steps 2-5) still TODO.
…ch 7)

Re-tested live with a full pointerdown/mousedown/pointerup/mouseup/click
sequence (bubbles, cancelable, real coordinates) against a real 2-artifact
conversation - still no panel swap. Only genuine OS-level input (CDP/
chrome.debugger) works, and chrome.debugger is a heavy permission with a
persistent browser-wide warning banner - poor trade for a read-only export
feature. Downgrades this item from 'more engineering time needed' to
effectively blocked pending a non-click extraction path.
Backfills one ## [x.y.z.w] section per existing git tag (v0.2.0 through
v0.4.28.1) plus an Unreleased section for work since the last tag (Notion
export, vault writes, Canvas fix, AI Mode dedup fix, footnote fix, etc).
Entries are short and user-facing, matching what Batch 10's future
automated store-publishing workflow will extract and submit as AMO's
release_notes / the GitHub Release body.

Adds a JSDOM regression suite (281 total, 0 failed) that fails if the
current manifest version has no matching section, if Unreleased goes
missing, or if a heading doesn't match a real git tag - guards against the
file silently drifting out of sync with what's actually shipped.

Also documents in TODOs.md Batch 10 exactly how the future workflow should
consume this file (extract text between this tag's heading and the next).
Converts all 5 settings.html sections (Language, Export, Direct-to-vault,
Integrations, Advanced) from <section><h2> to
<details class="settings-section" open><summary><h2>, all starting open
so the default view is unchanged - scannability only, not a way to hide
settings. Custom rotating chevron marker replaces the native triangle.
The vault section's existing Chrome-only hidden/display feature-detect
toggle in settings.js is untouched and confirmed to still work correctly
alongside the details/open attribute.

281 tests still pass, 0 failed - no test or JS file referenced the
<section> tag name.
…ration

popup.html/popup.js: a 'Batch export past conversations...' toggle appears
only when content.js's getConversationList() (Batch 8 step 1) finds a
history sidebar on the current tab - stays hidden/silent everywhere else,
so the existing single-conversation export path is untouched.

background.js: new runBatchExport() - sequential background-tab automation
(create tab, wait for load, extract, collect markdown, remove tab, small
delay) living in the service worker so it survives the popup closing.
Aggregates one .md file per conversation into a single ZIP via the
existing buildZip()/buildFilename()/safeDownload() helpers - no new
export-building code, all reused from the existing extraction paths.

9 new i18n keys, real translations added to all 26 locales (25 via
parallel subagents, spot-checked + full key-set diff verified - zero
mismatches). One new Playwright e2e test asserting the toggle stays
hidden with no chat page open (syntax-verified via node -c; couldn't
execute in this sandbox - Chromium binary download blocked by network
restrictions - needs a real CI/local run to confirm it passes).

281 JSDOM tests still pass, 0 failed. Per TODOs.md: this is implemented
and internally consistent but NOT live-tested end-to-end yet, same status
Batch 5 (Notion) and Batch 6 (vault) shipped in - needs a real small-N
(3-5 conversations) run on Stefan's own accounts before being called done.
Per-platform timeout tuning and safe-batch-size limits remain open
questions, same as the original design sketch flagged.
Stefan compared the old 'ON' badge to uBlock/Bitwarden's much more visible
toolbar badges and wanted something bigger, passive (no click needed),
not a number. The native OS badge corner turned out to be a dead end -
its size is fixed by the browser, no API controls it - so the signal moves
into the icon bitmap instead, which we fully control.

Added icons/icon-{16,32,48,96,128}-active.png (generated via Pillow: a
white-ringed green checkmark circle, ~62% of icon width, bottom-right;
16px drops the checkmark detail, too small to survive downscaling).
background.js's existing updateBadge() now calls action.setIcon() per tab
instead of setBadgeText('ON'), and explicitly clears any stale badge text
a previous version may have left on an already-open tab.

5 new JSDOM tests: all 4 manifest icon sizes have a referenced -active
file, each file exists/is non-empty, each is confirmed to actually differ
from its default (byte comparison, catches a copy-paste no-op), each is a
structurally valid PNG at its declared size (parsed IHDR directly, no new
dependency), and the stale-badge-clear call is present. Also added the 4
active icons to CI's required-files check. 281 -> 286 passed, 0 failed.

Not verified: actual rendering in a real browser toolbar (DPI, dark/light
theme contrast, Firefox's icon padding) - image generation and JSDOM
checks only, no way to render a real toolbar in this sandbox.
Stefan looked at the real 32px rendering of the checkmark-badge version
and flagged that it visibly overlapped/clipped the arrow logo - legible,
but now covering the brand mark, a regression in a different direction.

Replaced with a full-icon recolor: icon-*-active.png is the same logo art
with its background hue-shifted from purple/blue to green (#16a34a's hue),
nothing drawn on top. HSV hue-shift only touches pixels above a saturation
threshold, cleanly separating the colorful background gradient (sat.
~146-148) from the pure-white glyph (sat. 0) - so the arrow/lines stay
100% intact and legible at every size down to 16px, and the gradient's
original shading is preserved (just green instead of purple/blue).

Same file names/paths, same background.js wiring, same 5 JSDOM tests -
only the pixel content changed. 286 passed, 0 failed.
Stefan reloaded the unpacked extension while sitting on an already-open,
already-focused supported tab and saw no green icon at all. Root cause:
updateBadge() only ran from tabs.onUpdated (navigation) and
tabs.onActivated (switching tabs) - reloading the extension fires neither
for a tab that was already open and already focused, so nothing ever told
that tab's icon to update.

Added syncAllTabIcons(), wired to runtime.onInstalled (install/update/every
unpacked-reload) and runtime.onStartup (browser restart restoring tabs) -
queries every open tab and runs the existing updateBadge() logic on each.

2 new JSDOM tests (288 total, 0 failed).
Stefan flagged the popup as crowded (up to 11 buttons visible at once).
Brainstormed 3 directions, landed on a GitHub-style split button: a
primary face (remembers the most recently used format) + a caret that
opens a menu with everything else, including Gist/Notion folded into the
same menu instead of separate always-there buttons.

Critically, the menu contains the exact same 11 button elements/ids
(mdBtn, pdfBtn, ..., gistBtn, notionBtn) that used to sit in the grid -
only their container/CSS changed - so every existing click handler
(extraction, vault-write branching, Gist/Notion upload, webhook firing,
history persistence) keeps running completely unmodified. New code is
just a thin layer: FORMAT_TO_BTN maps format -> button, the primary face
proxies its click to FORMAT_TO_BTN[preferredFormat], preferredFormat is
seeded from the existing inkpour_last_export.format (no new storage key)
falling back to the Settings default format, and setLoading() got one
additive line mirroring state onto the primary face.

2 new i18n keys (More export options tooltip, short 'All' label),
translated to all 26 locales. 8 new structural JSDOM tests (popup.js/html
aren't executed by this harness, same as background.js - these parse/grep
instead). Updated 5 stale e2e tests that referenced the old grid, added 5
new ones for menu open/close/pick behavior (not run in this sandbox -
Chromium binary download blocked by network restrictions, same limitation
as before - syntax-verified only).

296 passed, 0 failed. Not yet verified: actual visual rendering/spacing in
a real 320px popup - CSS reuses existing variables/patterns and cascade
order was verified by parsing, not rendering.
…-Execute for the rest

Reworks the split-button popup from the previous commit per live usage
feedback: Copy MD and ZIP move back out to always-visible quick buttons
(they were the two most-used actions and got buried in the collapsed
menu); everything else (MD/PDF/HTML/JSON/DOCX/Copy HTML/Export All/
Gist/Notion) is now picked from a menu that only updates the selection,
with a separate Export button that actually fires it. Real handlers are
unchanged, just relocated into a permanently-hidden container so a menu
row click structurally cannot reach them — only the Export button's
click proxies through. Fixes the specific complaint that picking Gist/
Notion from the old menu fired the upload instantly with no chance to
back out.

- popup.html: quick-actions row (copyBtn/zipBtn), new .export-picker
  (exportSelectBtn + exportGoBtn), inert data-format menu rows, hidden
  #realExportActions housing the original 9 buttons.
- popup.js: FORMAT_TO_BTN drops copy-md/zip; setSelectedFormat() only
  updates UI; exportGoBtn is the sole .click() proxy; gist/notion
  token-gating retargeted to the menu stand-ins.
- 1 new i18n key (popupExportGoBtn), translated to all 26 locales.
- Rewrote the JSDOM structural suite + Playwright e2e spec to match
  (300 passed, 0 failed; e2e not run in this sandbox, Playwright
  Chromium download still blocked — node -c only).
- TODOs.md Batch 4d + CHANGELOG.md Unreleased updated.
Feedback: Copy MD (quick button) vs Copy HTML (buried in an unrelated
copy cluster in the dropdown) felt arbitrary with no visible reason for
the split. Considered dropping Copy HTML outright, but it's kept as the
clipboard alternative to the HTML file export.

- popup.html: copy-html menu row moved to sit directly under the html
  row (dropped the old copy-cluster divider), styled .sub-item (indented,
  muted) so it reads as HTML's clipboard variant rather than a peer
  action. Label changed from "Copy HTML" to "Copy to clipboard" (same
  popupBtnCopyHtml i18n key, new message only).
- Translated the new wording to all 26 locales.
- Copy MD's quick-button position is unchanged.
- 300 passed, 0 failed.
Two more rounds of live feedback on the popup export picker:
- The selector's caret was too small to read as a toggle. Now bigger
  (10px -> 15px) and rotates 180 degrees while the menu is open.
- Calling out "Copy to clipboard" by name made the other rows' silent
  destination (file download vs. external upload) feel unexplained by
  contrast. Added a small non-translated inline SVG icon to every quick
  button and menu row: download-arrow for file exports, copy-icon for
  clipboard-bound ones, upload-arrow for Gist/Notion -- matching the
  "up" cue Gist/Notion already implied.

Icons are plain <svg> markup outside any data-i18n span, so future
wording tweaks never touch translations again. Correspondingly stripped
the symbols that used to be baked into translated strings themselves
(popupBtnExportAll's leading arrow, popupBtnGist/popupBtnNotion's
trailing arrow, popupBtnCopyHtml shortened to "Copy"), re-translated
across all 26 locales. 300 passed, 0 failed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant