Docs

Tranquil Settings — Delivery Notes

Delivery summary for the Tranquil settings tab — a top-level panel in the settings pane, seeded with a Toast Duration control, plus a theming pass so the whole settings surface wears the business theme. For the decision record, read ADR-0011: A first-class Tranquil settings tab; this note says what shipped and where.

Status

Implemented; pending in-app verification. Work is isolated on a feat/tranquil-settings-panel branch in each affected repo. Not yet committed or merged.

PieceState
tranquil.* config namespace + tranquil.toastDuration (schema in tranquil-config)✅ built
“Tranquil” tab registered on settings-view via addCorePanel (reuses core SettingsPanel)✅ built
One-way bridge tranquil.toastDurationnotifications.defaultTimeout✅ built
notify() helpers read the setting (tranquil-automations + tranquil-browser)✅ built
Settings-pane theming in both business themes (settings.less)✅ built
ADR-0011 + this note✅ written
End-to-end run in the app⏳ pending

Why this shape

The trigger was trivial — toasts vanished in ~1s — but the fix was hard-coded in two places: TOAST_TIMEOUT = 1000 inside Tranquil’s own notify() helper (duplicated in tranquil-automations and tranquil-browser). Core’s notifications.defaultTimeout was not the culprit; it only governs non-dismissable direct toasts.

Rather than bump a constant, we gave Tranquil a real settings home. Two constraints shaped it:

  • settings-view exposes no service to add a top-level tab — only an internal addCorePanel(name, icon, factory) on the live SettingsView instance. We reach each instance via atom.workspace.observePaneItems (settings-view is a pane item) and call it — no third-party edits.
  • Reuse over reinvention: core’s SettingsPanel auto-renders config-bound controls for a whole namespace. Pointing it at a tranquil.* namespace gives free two-way binding and — because it emits the same markup as Core/Editor — means theming the settings surface once styles our tab too.

That last point is the payoff: the Tranquil tab needs zero bespoke CSS.

What shipped & where

tranquil-config (src/index.js) — the tab, schema, bridge

  • Schema via atom.config.setSchema('tranquil', …) (not package.json, so keys are tranquil.* not tranquil-config.*): toastDuration integer, default 3000, min 1000, max 60000.
  • Bridge: atom.config.observe('tranquil.toastDuration', v => atom.config.set('notifications.defaultTimeout', v)) so the few direct atom.notifications.add* callers (tranquil-drag-drop, tranquil-window-color) honor the same value.
  • Tab registration: atom.workspace.observePaneItems(item => …) duck-types each SettingsView instance (typeof item.addCorePanel === 'function' + constructor name) and calls addCorePanel('Tranquil', 'gear', factory), idempotent via panelCreateCallbacks['Tranquil'].
  • Panel factory: lazy-requires SettingsPanel by resolved path (atom.packages.resolvePackagePath('settings-view') + lib/settings-panel), wraps new SettingsPanel({ namespace: 'tranquil', icon: 'gear', title: 'Tranquil Settings' }) in a .panels-item shell that supplies show/focus/destroy (SettingsPanel only has destroy), mirroring core’s general-panel.js. Lazy + path-resolved so a missing internal degrades to “no tab”, never a crash (the dev-package silent-require trap).
  • The existing tree-view-sync toggle’s inline toast now also reads tranquil.toastDuration.

notify() helpers — read the setting

  • tranquil-automations/lib/notify.js — replaced TOAST_TIMEOUT = 1000 with a toastTimeout(options) reading atom.config.get('tranquil.toastDuration') (fallback 3000), still honoring a per-call options.timeout override.
  • tranquil-browser/lib/notify.js — same base timeout, but errors/warnings keep a longer floor: Math.max(LONG_TIMEOUT /* 6000 */, base), so they stay readable/copyable.

These two files are duplicated across repos and were edited in lockstep. Nothing imported the old TOAST_TIMEOUT export, so removing it is safe.

Business themes — styles/settings.less (identical in both)

Expanded the existing partial coverage into a full pass over the settings surface, all scoped under @{theme-scope} and written against colors.less tokens (so the light theme is a byte-identical copy):

  • Form widgets, matched to the design system (main-view.html mockup + the find bar): config mini text/number inputs styled as .form-input (surface-input fill, @border-strong, 6px radius, @accent focus ring); checkboxes/radios as the native control tinted with accent-color: @accent (not hand-drawn boxes); selects and color swatches in the same input family.
  • Setting rows: .setting-title / .setting-description hierarchy, .control-group spacing.
  • Buttons: neutral .btn on @surface-active; .btn-primary/.btn-info/.update-all-button/ .selected on the @accent fill; grouped-button radii.
  • Chrome: nav hover/active with accent icons, section-heading octicons, badges, breadcrumb, alerts (info/success/warning/danger tinted with semantic tokens), keybinding .is-user row, tables, search results, package cards.

The Tranquil tab inherits all of the above with no dedicated rules.

Where it lives (file map)

  • tranquil-config/src/index.js — schema, bridge, tab registration, panel factory
  • tranquil-automations/lib/notify.js, tranquil-browser/lib/notify.js — config-backed timeouts
  • tranquil-business-dark/styles/settings.less, tranquil-business-light/styles/settings.less — identical settings-pane theming
  • tranquil-clientunchanged (all work is in the sibling owned repos)

Verify

  1. nvm use && yarn start from tranquil-client.
  2. Open Settings (cmd-,) → a Tranquil tab (gear) sits in the nav at atom://config/tranquil, showing a themed Toast Duration field defaulting to 3000 and clamping 100060000.
  3. Trigger a notify() toast (browser “Saved …” on a .url save; an automations register command) → it now stays ~3s and tracks the field live (no restart); browser error/warning toasts still ~6s; atom.config.get('notifications.defaultTimeout') tracks the setting.
  4. Switch tranquil-business-dark-light → nav, inputs, checkboxes, buttons/.btn-primary, badges, breadcrumb, cards all read as Tranquil in both, and the Tranquil tab is indistinguishable from Core/Editor in styling.
  5. Confirm no regression: tree-view-sync toggle and command-palette MRU/filter still work (lazy require(settings-panel) didn’t throw at load); the pane still lays out in a left/right dock.