theseus/bundled-addons/screenshot/editor.css
Local Dev 7b8539fb8d feat(theseus/screenshot): 0.6.4 — Polaroid sounds, trash icon, centred cluster, filename footer + open-in-folder
Rolling every user report from the 0.6.3 rollout into one bundle:

Sounds — the Web-Audio synth palette matches the metaphor now:
- Screenshot: Polaroid shutter — sharp metallic tick + curtain-close click
  chained to a film-advance whir (band-passed noise sweeping 900→400 Hz).
- Copy: printer "chika-chika-chika" — three descending percussive noise
  bursts pinned by short sine ticks. Reads as a print-head sweep.
- Discard: paper crumple — three overlapping band-limited noise beds
  with per-sample random-amplitude crackle, descending centre freq. No
  more descending sine "boop".
- Save: soft "photo dispensing" hiss (Polaroid ejects) + a small click.
- Both the panel and editor share the design so nothing sounds different
  depending on which surface fired it.

UI polish:
- Discard button now carries a trash-can icon so it's obviously not the
  same as the close-sidebar X (they both used to be plain X's).
- Toolbar drawing tools centre themselves via a new .tool-cluster
  wrapper (flex:1 1 auto, justify-content:center); the Copy/Save actions
  stay right-anchored via margin-left:auto on their own tgroup. Fixes
  the maximized-sidebar case where the drawing groups all crowded the
  left with a big empty gap before Copy/Save on the right.
- Filename moves out of the topbar into a dedicated footer strip under
  the canvas board, alongside a new "Open in folder" button. The topbar
  is now flex-wrap:nowrap and holds only fixed-width window controls,
  so a long filename can never push discard / sound / max / close onto
  a second row (the filename ellipsises instead).
- "Open in folder" invokes a new "openFolder" addon message that calls
  Electron's shell.showItemInFolder() to open the OS file explorer with
  the specific scratch PNG highlighted (falls back to shell.openPath()
  on the scratch dir when no capture is named).

Version bump so the OTA update endpoint picks it up on the next tick.
2026-09-09 22:34:47 +02:00

164 lines
7.7 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; }
/* The topbar has fixed-size window controls only; no reason to ever wrap
its row. Filename lives in the footer now, so nothing can grow the row
past what the icons need. */
.topbar { flex-wrap: nowrap; }
/* Toolbar layout: drawing tools live inside `.tool-cluster` which is a
flex-grow container centring its own contents. Copy/Save (`.tgroup
.actions`) sit outside it and pin to the right edge. On a maximized
sidebar the cluster centres in the empty space between name-area and
the actions; at narrow widths the whole cluster shrinks and wraps by
category, and the actions can wrap to their own row on the right. */
.toolbar { align-items: flex-start; gap: 8px; row-gap: 6px; }
.tool-cluster {
display: flex; flex-wrap: wrap; align-items: center;
gap: 10px; row-gap: 6px;
flex: 1 1 auto; justify-content: center;
}
.tgroup { display: inline-flex; align-items: center; gap: 4px; flex: 0 0 auto; }
.tgroup.actions { flex: 0 0 auto; align-self: center; }
/* Close-sidebar button — reads as danger without shouting. */
#close-sidebar:hover,
#discard:hover { border-color: rgba(255,91,91,.55); color: var(--danger); }
.btn.danger { color: var(--danger); }
.btn.danger:hover { border-color: rgba(255,91,91,.55); }
.topbar .name { color: var(--dim); font-size: 11.5px; overflow: hidden;
text-overflow: ellipsis; white-space: nowrap; max-width: 200px; margin: 0 4px; }
/* Footer strip that carries the filename + "Open in folder" affordance,
sitting under the canvas board. The filename truncates first so the
button never falls off the edge; the button never wraps. */
.footer { display: flex; align-items: center; gap: 8px;
padding: 6px 10px; border-top: 1px solid var(--line);
background: var(--panel); font-size: 11.5px; }
.footer .fname { color: var(--dim); flex: 1 1 auto; min-width: 0;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.footer .fbtn { border: 1px solid var(--line); background: var(--panel2);
color: var(--ink); border-radius: 6px; cursor: pointer;
padding: 4px 8px; display: inline-flex; gap: 6px; align-items: center;
flex: 0 0 auto; font: inherit; line-height: 1; }
.footer .fbtn svg { width: 14px; height: 14px; display: block; }
.footer .fbtn:hover { border-color: rgb(from var(--acid) r g b / .55); }
.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>