super-productivity/electron
Johannes Millan c1d14d501c
Experiment right side action bar (#7594)
* feat(layout): experimental vertical action strip on right edge

Teleports main-header's action-nav-right to document.body on desktop so
it escapes any ancestor containing-block, then pins it as a vertical strip
at the viewport's right edge via fixed positioning. Reserves the column
with padding-right on .app-container so the right-panel ends to its left.

* feat(layout): right-panel spans full viewport height

Restructure app shell so right-panel is a direct flex child of
.app-container (wrapping main-content via ng-content), letting its
.side extend over the full height of the viewport — including the
header area — rather than starting below the header.

* style(layout): give vertical action strip an elevated surface bg

* style(layout): match vertical action strip styling to left side nav

* fix(layout): stack play/focus buttons vertically in action strip

* style(layout): use solid surface bg for vertical action strip

* fix(layout): keep current-task title visible beside the action strip

In the teleported vertical action strip the current-task title pill was
positioned right:100% of the play button and clipped by the strip's
overflow, and the 48px mini-fab overflowed the 48px rail and got
side-clipped.

Render the title as a position:fixed flyout to the left of the strip
(the strip has no transform/filter so it is not a containing block for
fixed descendants), aligned to the play button across the web /
mac-titlebar / obsidian-header / RTL variants, and drop the play button
wrapper's horizontal margin so it fits the rail.

* fix(layout): stop tooltip overlay from blocking action strip clicks

A tooltip shown 'below' a button in the vertical action strip lands
directly over the next button. The tooltip's cdk-overlay-pane wrapper
(unlike the inner mat-tooltip-component) had no pointer-events:none, so
it intercepted clicks for real users and for Playwright actionability —
breaking ~20 focus-mode/break e2e tests.

* test(focus-mode): use teleport-robust focus-button locator

The action nav is teleported out of <main-header> into a body-level
strip, so 'main-header focus-button button' no longer matches. Drop the
main-header ancestor; 'focus-button button' is unique either way.

* fix(layout): polish vertical action strip (flyout, spacing, bg)

- Current-task title is now a hover-reveal flyout: hidden until the play
  button (or the flyout itself) is hovered. Mobile (< 1080px) unchanged
  (component still display:none's it there).
- Drop the position:fixed + magic top calc; keep the component's own
  absolute + translateY(-50%) so the flyout is pixel-perfectly centred
  on the play button regardless of theme/Material density.
- Strip now overflow: visible so the flyout can extend past the 48px
  rail (overflow-x can't be visible while overflow-y is auto).
- Re-declare --header-nav-button-gap on the strip: it is scoped to
  <main-header>'s :host but the strip is teleported to <body>, so the
  var was undefined => every strip button had gap: 0 (cramped).
- Extra margin between the play button and the focus button.
- Strip background now matches the left sidenav (--sidenav-bg).

* fix(layout): uniform vertical spacing between strip buttons

Drop the extra play-button and counters-group bottom margins; one
--header-nav-button-gap (var(--s)) now drives the spacing between every
button in the strip. Measured: all consecutive gaps = 8px.

* feat(layout): make vertical action bar a configurable opt-in

Adds misc.isVerticalActionBar (default off). The right-edge vertical
action strip was previously an unconditional experiment; it is now an
opt-in toggle in Settings > Misc that switches the layout live without
reload:

- app.component: @if branches the DOM between classic (horizontal
  header) and vertical (right-panel hoisted to full viewport height);
  .app-container gets .has-vertical-action-bar to gate CSS.
- main-header: one-shot ngAfterViewInit teleport replaced with an
  effect() that teleports/restores the action nav reactively to the
  config flag and the desktop/mobile breakpoint.
- app/right-panel SCSS: strip padding and full-height right-panel are
  now scoped to .has-vertical-action-bar; classic layout restored as
  the default.

* fix(layout): even vertical-strip spacing for panel-button wrappers

plugin-header-btns, plugin-side-panel-btns, desktop-panel-buttons and
user-profile-button are zero-height wrapper custom-elements. As direct
flex children of the vertical action strip the column gap landed on the
collapsed wrapper instead of the button(s) inside, so their icons were
unevenly spaced next to real buttons like the add button. Make each
wrapper a centered column flex item that stacks its button(s) with the
same gap, and hide truly-empty wrappers so they don't reserve a phantom
gap slot. Verified: all 7 visible strip buttons now 8px apart.

* fix(right-panel): clip transient content overflow during slide animation

.side animates width 0<->* while .side-inner keeps its min-width, so
content briefly spills past the (intentionally overflow:visible) .side
during open/close. Add an isPanelAnimating host class driven by the
@slideRightPanel start/done callbacks and clip :host for that window
only (overflow: clip — no scroll container). Mirrors the existing
resizing/windowResizing transient-state pattern. Verified: class +
clip present only during the ~200ms animation, visible when idle.

* refactor(layout): drop dual DOM for vertical action bar

Single classic layout for both modes; strip is teleported and offset by
--bar-height so the horizontal header keeps owning the title-bar zone
(native drag region + WCO + Mac traffic lights). Drops the 40px
title-bar-collision padding and the right-panel full-height override.

* feat(layout): right-panel side spans full viewport height

Move the header into right-panel's projected .content slot and make
right-panel host full-height. The panel column now starts at viewport
top with the header band only spanning the .content width, similar to
Obsidian / Linear / VS Code.

* fix(layout): only offset vertical strip below WCO band on Win/Linux

Default top inset is now 0 (web, Mac hiddenInset, native-frame Electron
all let the strip start at viewport top — none of them have a window-
control overlay clashing with the right edge). Push the strip down by
--bar-height only on Win/Linux Electron with custom title bar, where
the WCO buttons would otherwise sit on top of the strip's first row.

* style(electron): use compact 32px WCO band on Win/Linux

Shrinks the Windows Controls Overlay height from 44px to 32px so the
native min/max/close buttons sit in a slimmer band — matches VS Code /
Edge slim title bar conventions and frees more of the header zone for
app content. Width stays OS-controlled (~138px); only height is
configurable.

* style(layout): tighten WCO band to 24px and pull strip up to match

Drops WCO_HEIGHT to 24px on Win/Linux and introduces a --wco-height CSS
var mirroring it. The vertical action strip now clears the WCO band by
exactly --wco-height instead of --bar-height (48px), reclaiming the
newly-freed top zone on the right edge.

* style(layout): add breathing room above strip below WCO band

Strip top inset moves from --wco-height to --wco-height + --s so the
first action button isn't flush against the bottom of the window
controls overlay on Win/Linux.

* fix(styles): scope vertical-action-bar tooltip rule to the experiment

The pane-level `pointer-events: none` was needed only because tooltips
in the teleported vertical strip can land over the next button. Apply
it via a new `body.isVerticalActionBar` body class (toggled from
`misc.isVerticalActionBar` in GlobalThemeService, alongside the existing
`isObsidianStyleHeader` effect) so unrelated app tooltips keep their
default pane behaviour.

* refactor(styles): extract vertical-action-bar CSS to its own partial

Move the 130-line experimental strip block out of `src/styles.scss` and
into `src/styles/components/_vertical-action-bar.scss`. Wired via
`_components.scss`. No CSS rules change — pure code organisation.

* merge(master): resolve _components.scss conflict in right action bar branch

Agent-Logs-Url: https://github.com/super-productivity/super-productivity/sessions/1941dd45-72e1-4a3e-92da-912fcfcb9bed

Co-authored-by: johannesjo <1456265+johannesjo@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: johannesjo <1456265+johannesjo@users.noreply.github.com>
2026-05-23 16:11:37 +02:00
..
assets/icons fix: wrong icon for kde title bar 2025-07-22 20:42:28 +02:00
ipc-handlers fix(window): preserve maximized state for shortcut hide 2026-05-11 14:31:19 +02:00
scripts refactor(electron): bundle preload script with esbuild to support sandbox mode 2026-03-22 19:38:21 +01:00
shared-with-frontend feat(electron): suffix version string per distribution target 2026-05-19 16:42:45 +02:00
task-widget feat(task-widget): make settings per-instance and fix Mac drag/resize 2026-04-29 21:16:12 +02:00
wayland-idle-helper Add ext-idle-notify backend for Wayland idle detection (#7337) 2026-04-24 16:50:24 +02:00
backup.ts fix(backup): move shared timestamp util into electron/ for snap packaging 2026-04-22 16:14:56 +02:00
clear-stale-idb-locks.ts Feat/to me it looks like there are lots of 60dd04 (#7280) 2026-04-20 12:04:38 +02:00
clipboard-image-handler.ts Adding Ctrl-V pasting function from clipboard. (#5998) 2026-02-04 15:46:51 +01:00
common.const.ts chore: update electron to v41.x (#7097) 2026-04-17 18:12:43 +02:00
CONFIG.ts Increase ping interval and idle time in order to not waste CPU cycles. (#6227) 2026-01-28 15:37:50 +01:00
debug.ts refactor: rename overlay-indicator to task-widget 2026-03-30 22:00:47 +02:00
electronAPI.d.ts feat(electron): suffix version string per distribution target 2026-05-19 16:42:45 +02:00
error-handler-with-frontend-inform.ts fix(error-handling): prevent [object Object] from appearing in error messages 2026-01-02 15:40:14 +01:00
full-screen-blocker.ts fix(security): harden XSS sinks and add Origin check (#7413) 2026-05-06 21:37:06 +02:00
gpu-startup-guard.ts fix(electron): add GPU startup guard for confined Linux packages 2026-04-20 18:35:31 +02:00
idle-time-handler.ts fix(electron): retry Wayland idle helper startup (#7527) 2026-05-10 22:35:33 +02:00
indicator.test.cjs Caldav subtask import (#7409) 2026-05-01 13:07:03 +02:00
indicator.ts feat(electron): suffix version string per distribution target 2026-05-19 16:42:45 +02:00
ipc-handler-wrapper.ts Adding Ctrl-V pasting function from clipboard. (#5998) 2026-02-04 15:46:51 +01:00
ipc-handler.ts feat(electron): add Local REST API for desktop automation (#6981) 2026-03-28 13:35:04 +01:00
jira.ts fix: add proxy env support for jira integration #6324 (#6574) 2026-03-09 13:09:51 +01:00
local-file-sync.ts fix(settings): raise background image size caps 2026-05-21 22:56:03 +02:00
local-rest-api.ts fix(security): harden XSS sinks and add Origin check (#7413) 2026-05-06 21:37:06 +02:00
lockscreen.ts fix(electron): restore macOS lock screen by correcting osascript quoting 2026-04-16 19:47:52 +02:00
main-window.ts Experiment right side action bar (#7594) 2026-05-23 16:11:37 +02:00
main.ts fix(electron): improve protocol URL handling and register URL scheme on Linux 2026-03-05 16:45:05 +01:00
plugin-node-executor.ts refactor: improve typing 2 2025-08-12 15:27:48 +02:00
plugin-oauth.ts Improve OAuth error handling and reporting (#7445) 2026-05-01 18:45:11 +02:00
preload.ts feat(electron): suffix version string per distribution target 2026-05-19 16:42:45 +02:00
protocol-handler.ts fix(electron): restore hidden window on taskbar click 2026-01-20 17:07:23 +01:00
proxy-agent.ts fix: add proxy env support for jira integration #6324 (#6574) 2026-03-09 13:09:51 +01:00
shared-state.ts fix: refactor tray handling to use shared state for task and countdown visibility 2025-11-28 18:53:00 +01:00
simple-store.test.cjs fix(electron): harden simple store writes (#7297) 2026-04-21 15:03:30 +02:00
simple-store.ts fix(electron): harden simple store writes (#7297) 2026-04-21 15:03:30 +02:00
start-app.ts fix(macOS): quit app on system shutdown (#7704) 2026-05-21 12:25:52 +02:00
tsconfig.electron.json feat(plugins): add onReady() API with IPC ping + fix consent write delay (#7578) 2026-05-14 13:41:01 +02:00
various-shared.ts fix(electron): restore main window correctly when minimize-to-tray and task widget are both enabled 2026-04-16 17:41:39 +02:00