theseus/bundled-addons/screenshot/editor.css

137 lines
6.2 KiB
CSS
Raw Normal View History

feat(theseus/screenshot): 0.5.0 — sidebar-first editor, direct save/copy, sounds Two problems the old editor kept hitting: - __pending drain race: opening the editor a second time (refresh, back-and- forth navigation) found the storage entry already consumed and bailed to a blank canvas silently. - Cross-origin img loading: editor.html at file:///…/addons/screenshot/ loading a scratch PNG at file:///…/addons-data/ counts as cross-origin under Chromium's file-URL policy; setting crossOrigin="anonymous" made the load fail outright. Rebuilt editor v2: - Load path is idempotent: silentmode.invoke("getBytes", {name}) → addon reads the scratch file and returns a data URL. No __pending drain, no cross-origin trickery — data: URLs are same-origin and never taint the canvas, so getImageData / toBlob keep working. - Two-canvas model (#base + #over, over is pointer-events:none) so live previews don't cost a full re-composite per mousemove. - Tools: cursor, arrow, rect, ellipse, pen, text. 6 swatches, 3 widths, undo / redo (25-deep). Copy + Save at the top bar. Back and Maximize buttons in the same top bar so navigation controls stay reachable when the toolbar wraps at narrow widths. - Keyboard: A/R/O/P/T select tool, Esc = cursor, Ctrl+Z/Shift+Z undo/redo, Ctrl+S save, Ctrl+C copy. - Toast surface for save/copy/error feedback. Sidebar panel gains a direct raw-save path so the user can copy or save the capture without entering the editor: - Two-row actions: [Copy] [Save] on top, [Discard] [Edit] below. - Copy uses navigator.clipboard.write(ClipboardItem); Save uses <a download> with a Blob URL — same path Chromium's will-download tracker already handles, so the file lands in Downloads and the chip updates like any other save. Inline "clear all" confirmation replaces the native confirm() — the old system-modal opened over the tab area (out of the sidebar's visual context) and looked like Windows 95. Now a compact red strip appears under the Recent header with Cancel / Delete buttons. Sounds + a sound-on/off toggle in both surfaces: - Web Audio oscillator-synthesized (no .wav shipped): shutter click on capture, two-tone bloop on copy, descending pair on discard/back, ascending triad on save. - Preference stored in silentmode.storage under "soundOn" (default on), shared between the panel and the editor. Simplifications: - Dropped the addon's "arm" onMessage handler (superseded by getBytes). - Manifest capabilities: sidebar-panel + capture-tab (no open-tab, no toolbar-menu). Bundled but not shipped — parent session handles the OTA sign + push.
2026-09-09 00:56:41 +02:00
/* Screenshot editor v2 sidebar-embedded. Compact but not cramped; scales
the canvas to fit whatever width the sidebar has, up to full window when
the user hits the maximize button in the topbar. */
:root { color-scheme: light dark;
--bg:#0e131c; --panel:#141a24; --panel2:#191f2b; --line:rgba(255,255,255,.09);
--ink:#e7eaf1; --mut:#8b98a9; --dim:#5e6678; --acid:#d6ff3d;
--danger:#ff5b5b; --board:#0a0d13; }
@media (prefers-color-scheme: light) {
:root { --bg:#f8faff; --panel:#ffffff; --panel2:#eff3fb; --line:rgba(0,0,0,.10);
--ink:#1a1f2b; --mut:#5c6577; --dim:#8a93a5; --acid:#0AC18E;
--board:#dde3ee; }
}
* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }
body { background: var(--bg); color: var(--ink);
font: 13px/1.5 system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
display: flex; flex-direction: column; overflow: hidden; }
/* Author styles set `display: flex` on .empty/.stage plain [hidden]
loses the cascade fight and the "Loading capture" pill stayed visible
over the drawn image. Force-hide takes it out for real. */
[hidden] { display: none !important; }
feat(theseus/screenshot): 0.5.0 — sidebar-first editor, direct save/copy, sounds Two problems the old editor kept hitting: - __pending drain race: opening the editor a second time (refresh, back-and- forth navigation) found the storage entry already consumed and bailed to a blank canvas silently. - Cross-origin img loading: editor.html at file:///…/addons/screenshot/ loading a scratch PNG at file:///…/addons-data/ counts as cross-origin under Chromium's file-URL policy; setting crossOrigin="anonymous" made the load fail outright. Rebuilt editor v2: - Load path is idempotent: silentmode.invoke("getBytes", {name}) → addon reads the scratch file and returns a data URL. No __pending drain, no cross-origin trickery — data: URLs are same-origin and never taint the canvas, so getImageData / toBlob keep working. - Two-canvas model (#base + #over, over is pointer-events:none) so live previews don't cost a full re-composite per mousemove. - Tools: cursor, arrow, rect, ellipse, pen, text. 6 swatches, 3 widths, undo / redo (25-deep). Copy + Save at the top bar. Back and Maximize buttons in the same top bar so navigation controls stay reachable when the toolbar wraps at narrow widths. - Keyboard: A/R/O/P/T select tool, Esc = cursor, Ctrl+Z/Shift+Z undo/redo, Ctrl+S save, Ctrl+C copy. - Toast surface for save/copy/error feedback. Sidebar panel gains a direct raw-save path so the user can copy or save the capture without entering the editor: - Two-row actions: [Copy] [Save] on top, [Discard] [Edit] below. - Copy uses navigator.clipboard.write(ClipboardItem); Save uses <a download> with a Blob URL — same path Chromium's will-download tracker already handles, so the file lands in Downloads and the chip updates like any other save. Inline "clear all" confirmation replaces the native confirm() — the old system-modal opened over the tab area (out of the sidebar's visual context) and looked like Windows 95. Now a compact red strip appears under the Recent header with Cancel / Delete buttons. Sounds + a sound-on/off toggle in both surfaces: - Web Audio oscillator-synthesized (no .wav shipped): shutter click on capture, two-tone bloop on copy, descending pair on discard/back, ascending triad on save. - Preference stored in silentmode.storage under "soundOn" (default on), shared between the panel and the editor. Simplifications: - Dropped the addon's "arm" onMessage handler (superseded by getBytes). - Manifest capabilities: sidebar-panel + capture-tab (no open-tab, no toolbar-menu). Bundled but not shipped — parent session handles the OTA sign + push.
2026-09-09 00:56:41 +02:00
.topbar, .toolbar { display: flex; align-items: center; gap: 4px; padding: 6px 8px;
border-bottom: 1px solid var(--line); background: var(--panel);
user-select: none; flex-wrap: wrap; }
/* Older versions grouped the drawing tools in the middle of the bar keep
the drawing / swatch / width / undo cluster centred while the top-bar
feat(theseus/screenshot): 0.6.1 — text tool fix, category wrap, sidebar close X Four user reports from the 0.6.0 rollout: - Text tool never committed. openTextInput placed the box correctly but a couple of Chromium quirks stopped a normal type-Enter cycle: focus() called synchronously right after appendChild lost the race in some builds, and the input's own mousedown / click was bubbling through to #base and re-firing openTextInput on every subsequent keystroke click-through, so what looked like "nothing happens" was actually "a new empty box spawned on top of the last one every time". Now: focus after requestAnimationFrame, contain pointerdown / mousedown / click inside the input so they don't bubble to the canvas, track the font size on the state so commit uses the same one openTextInput measured against, and preventDefault on the base pointerdown so Chromium doesn't reset focus back to <body>. - Toolbar wrapped one dot at a time when the sidebar was narrow (a lonely thin/medium/thick width would jump to a second row while the swatches stayed above it). Toolbar items are now wrapped in `<div class="tgroup">` per category — tools / swatches / widths / undo-redo — with `flex: 0 0 auto`, so a whole row wraps as a unit and lands cleanly under the previous one. `gap: 10px / row-gap: 6px` keeps the visual grouping obvious. - No way to close the sidebar without hunting for the dock icon. Added an X button in the top-right of both the sidebar panel and the editor toolbar. Both wire through a new `silentmode.sidebar.close()` preload method that calls the existing `sidebar-close` IPC. - Tightened the pointerdown text branch so preventDefault + explicit focus-after-frame make the click-through races impossible. Bundled but not shipped separately — parent session signs and pushes.
2026-09-09 10:55:21 +02:00
(back / name save / copy / sound / max / close) stays edge-anchored. */
.toolbar { justify-content: center; gap: 10px; row-gap: 6px; }
/* Each visible group of tools wraps as a unit when the sidebar gets
narrow, the whole swatch row moves to the next line instead of a
single dot spilling by itself. */
.tgroup { display: inline-flex; align-items: center; gap: 4px; flex: 0 0 auto; }
/* Close-sidebar button — reads as danger without shouting. */
#close-sidebar:hover { border-color: rgba(255,91,91,.55); color: var(--danger); }
feat(theseus/screenshot): 0.5.0 — sidebar-first editor, direct save/copy, sounds Two problems the old editor kept hitting: - __pending drain race: opening the editor a second time (refresh, back-and- forth navigation) found the storage entry already consumed and bailed to a blank canvas silently. - Cross-origin img loading: editor.html at file:///…/addons/screenshot/ loading a scratch PNG at file:///…/addons-data/ counts as cross-origin under Chromium's file-URL policy; setting crossOrigin="anonymous" made the load fail outright. Rebuilt editor v2: - Load path is idempotent: silentmode.invoke("getBytes", {name}) → addon reads the scratch file and returns a data URL. No __pending drain, no cross-origin trickery — data: URLs are same-origin and never taint the canvas, so getImageData / toBlob keep working. - Two-canvas model (#base + #over, over is pointer-events:none) so live previews don't cost a full re-composite per mousemove. - Tools: cursor, arrow, rect, ellipse, pen, text. 6 swatches, 3 widths, undo / redo (25-deep). Copy + Save at the top bar. Back and Maximize buttons in the same top bar so navigation controls stay reachable when the toolbar wraps at narrow widths. - Keyboard: A/R/O/P/T select tool, Esc = cursor, Ctrl+Z/Shift+Z undo/redo, Ctrl+S save, Ctrl+C copy. - Toast surface for save/copy/error feedback. Sidebar panel gains a direct raw-save path so the user can copy or save the capture without entering the editor: - Two-row actions: [Copy] [Save] on top, [Discard] [Edit] below. - Copy uses navigator.clipboard.write(ClipboardItem); Save uses <a download> with a Blob URL — same path Chromium's will-download tracker already handles, so the file lands in Downloads and the chip updates like any other save. Inline "clear all" confirmation replaces the native confirm() — the old system-modal opened over the tab area (out of the sidebar's visual context) and looked like Windows 95. Now a compact red strip appears under the Recent header with Cancel / Delete buttons. Sounds + a sound-on/off toggle in both surfaces: - Web Audio oscillator-synthesized (no .wav shipped): shutter click on capture, two-tone bloop on copy, descending pair on discard/back, ascending triad on save. - Preference stored in silentmode.storage under "soundOn" (default on), shared between the panel and the editor. Simplifications: - Dropped the addon's "arm" onMessage handler (superseded by getBytes). - Manifest capabilities: sidebar-panel + capture-tab (no open-tab, no toolbar-menu). Bundled but not shipped — parent session handles the OTA sign + push.
2026-09-09 00:56:41 +02:00
.topbar .name { color: var(--dim); font-size: 11.5px; overflow: hidden;
text-overflow: ellipsis; white-space: nowrap; max-width: 200px; margin: 0 4px; }
.topbar .spacer, .toolbar .spacer { flex: 1; }
.btn, .tool {
border: 1px solid var(--line); background: var(--panel2); color: var(--ink);
width: 30px; height: 30px; border-radius: 6px; cursor: pointer;
display: inline-flex; align-items: center; justify-content: center;
padding: 0; transition: background 100ms, border-color 100ms;
font: inherit; line-height: 0;
}
.btn:hover, .tool:hover { border-color: rgb(from var(--acid) r g b / .5); }
.btn:disabled, .tool:disabled { opacity: .4; cursor: default; }
.btn:disabled:hover, .tool:disabled:hover { border-color: var(--line); }
.tool.active {
background: rgb(from var(--acid) r g b / .15);
border-color: rgb(from var(--acid) r g b / .7);
color: var(--acid);
}
.btn svg, .tool svg { width: 16px; height: 16px; display: block; }
.btn.wide {
width: auto; padding: 0 10px; gap: 6px; line-height: 1;
}
.btn.wide span { font-size: 12px; }
.btn.primary {
background: var(--acid); color: #101418; border-color: transparent; font-weight: 600;
}
.btn.primary:hover { filter: brightness(1.06); border-color: transparent; }
.sep { width: 1px; height: 20px; background: var(--line); margin: 0 3px; }
.swatch {
width: 22px; height: 22px; border-radius: 50%; padding: 0;
border: 2px solid var(--line); cursor: pointer;
}
.swatch.active {
border-color: var(--acid);
outline: 1px solid rgb(from var(--acid) r g b / .35); outline-offset: 1px;
}
.width {
border: 1px solid var(--line); background: var(--panel2); color: var(--ink);
width: 30px; height: 30px; border-radius: 6px; cursor: pointer;
display: inline-flex; align-items: center; justify-content: center; padding: 0;
}
.width.active {
border-color: rgb(from var(--acid) r g b / .7);
background: rgb(from var(--acid) r g b / .15);
}
.width .dot { border-radius: 50%; background: currentColor; color: var(--ink); }
.width.active .dot { color: var(--acid); }
/* Canvas board -------------------------------------------------------- */
.board {
flex: 1; overflow: auto; background: var(--board);
display: flex; align-items: flex-start; justify-content: center;
padding: 12px;
}
.empty { color: var(--dim); font-size: 13px; padding: 40px 20px; text-align: center;
display: flex; align-items: center; justify-content: center; height: 100%; }
.empty.err { color: var(--danger); }
.stage { position: relative; transform-origin: top left;
box-shadow: 0 2px 12px rgba(0,0,0,.35); background: #fff; }
.stage canvas { display: block; position: absolute; left: 0; top: 0; }
.stage #base { position: static; }
.stage #over { pointer-events: none; }
.stage[data-tool="arrow"] { cursor: crosshair; }
.stage[data-tool="rect"] { cursor: crosshair; }
.stage[data-tool="ellipse"]{ cursor: crosshair; }
.stage[data-tool="pen"] { cursor: crosshair; }
.stage[data-tool="text"] { cursor: text; }
feat(theseus/screenshot): 0.6.0 — crop + mosaic redaction, right-anchored sidebar controls, real shutter+print sounds Editor: - Crop tool restored — drag to select, marquee sits with a dashed acid border and a dimmed backdrop for the area you'll discard, then the topbar shows Apply crop / Cancel. Applying trims #base to the rect, resets undo (dimensions changed), and drops back into the select tool. Enter / Esc keyboard shortcuts while a crop is pending. - Blur / mosaic redaction tool back — drag a rectangle, editor downsamples that region of #base to ~12-block granularity and paints the blocks back nearest-neighbour. Commits directly (no confirm step). - Sidebar-window controls (Back, name, Copy, Save, Sound, Maximize) reflow: Back + name on the left, Copy + Save + Sound + Maximize on the right so the "put the sidebar back to normal size" affordance lives where users expect it. Toolbar's drawing tools stay centred. - Back arrow icon swapped from a chevron to a proper flat arrow (line + arrowhead), matching the new browser back/forward glyphs. Sounds — modeled on Firefox Screenshots' feedback rather than beeps: - Shutter is now a real photoshoot click: two mirror-slaps built from a band-passed noise burst (metallic ping) plus a very short square-wave thud each. Sounds like a camera, not a beep. - Copy is a two-chirp "printer feed" — filtered noise burst on top of a sine chirp per beat, staccato ascending pair. Same shape Firefox Easy Screenshot uses for "copied to clipboard". - Save keeps its ascending triad; Discard keeps its descending pair; new small ascending pair for Apply crop. Chrome: - Browser Back / Forward chevrons (M10 3 L5 8 L10 13 — two segments meeting at a point, no shaft) replaced with straight-arrow glyphs (line + arrowhead). Reads as a navigation arrow, not an angle bracket. Bundled but not shipped separately — parent session OTA-signs and pushes.
2026-09-09 10:24:03 +02:00
.stage[data-tool="crop"] { cursor: crosshair; }
.stage[data-tool="blur"] { cursor: crosshair; }
/* Apply-crop is the primary action while a crop marquee is up. */
#apply-crop {
background: var(--acid); color: #101418; border-color: transparent; font-weight: 600;
}
#apply-crop:hover { filter: brightness(1.06); background: var(--acid); border-color: transparent; }
#cancel-crop:hover { border-color: rgba(255,91,91,.5); color: var(--danger); }
feat(theseus/screenshot): 0.5.0 — sidebar-first editor, direct save/copy, sounds Two problems the old editor kept hitting: - __pending drain race: opening the editor a second time (refresh, back-and- forth navigation) found the storage entry already consumed and bailed to a blank canvas silently. - Cross-origin img loading: editor.html at file:///…/addons/screenshot/ loading a scratch PNG at file:///…/addons-data/ counts as cross-origin under Chromium's file-URL policy; setting crossOrigin="anonymous" made the load fail outright. Rebuilt editor v2: - Load path is idempotent: silentmode.invoke("getBytes", {name}) → addon reads the scratch file and returns a data URL. No __pending drain, no cross-origin trickery — data: URLs are same-origin and never taint the canvas, so getImageData / toBlob keep working. - Two-canvas model (#base + #over, over is pointer-events:none) so live previews don't cost a full re-composite per mousemove. - Tools: cursor, arrow, rect, ellipse, pen, text. 6 swatches, 3 widths, undo / redo (25-deep). Copy + Save at the top bar. Back and Maximize buttons in the same top bar so navigation controls stay reachable when the toolbar wraps at narrow widths. - Keyboard: A/R/O/P/T select tool, Esc = cursor, Ctrl+Z/Shift+Z undo/redo, Ctrl+S save, Ctrl+C copy. - Toast surface for save/copy/error feedback. Sidebar panel gains a direct raw-save path so the user can copy or save the capture without entering the editor: - Two-row actions: [Copy] [Save] on top, [Discard] [Edit] below. - Copy uses navigator.clipboard.write(ClipboardItem); Save uses <a download> with a Blob URL — same path Chromium's will-download tracker already handles, so the file lands in Downloads and the chip updates like any other save. Inline "clear all" confirmation replaces the native confirm() — the old system-modal opened over the tab area (out of the sidebar's visual context) and looked like Windows 95. Now a compact red strip appears under the Recent header with Cancel / Delete buttons. Sounds + a sound-on/off toggle in both surfaces: - Web Audio oscillator-synthesized (no .wav shipped): shutter click on capture, two-tone bloop on copy, descending pair on discard/back, ascending triad on save. - Preference stored in silentmode.storage under "soundOn" (default on), shared between the panel and the editor. Simplifications: - Dropped the addon's "arm" onMessage handler (superseded by getBytes). - Manifest capabilities: sidebar-panel + capture-tab (no open-tab, no toolbar-menu). Bundled but not shipped — parent session handles the OTA sign + push.
2026-09-09 00:56:41 +02:00
.text-input {
position: absolute; z-index: 10;
background: rgba(20,26,36,.92); color: var(--ink);
border: 1px solid var(--acid); padding: 2px 6px;
font: 15px/1.2 system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
outline: none; border-radius: 3px; min-width: 80px;
}
.toast {
position: fixed; left: 50%; bottom: 20px; transform: translateX(-50%) translateY(20px);
padding: 8px 14px; border-radius: 6px; background: rgba(11,14,20,.94);
color: var(--ink); font-size: 12.5px; border: 1px solid var(--line);
opacity: 0; pointer-events: none; transition: opacity 180ms, transform 180ms;
z-index: 100; max-width: 80vw; text-align: center;
}
.toast.on { opacity: 1; transform: translateX(-50%) translateY(0); }
.toast.err { border-color: rgba(255,91,91,.5); color: var(--danger); }
</style>