theseus/bundled-addons/screenshot/editor.css
Local Dev bf6bcfade2 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

136 lines
6.2 KiB
CSS

/* 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; }
.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
(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); }
.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; }
.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); }
.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>