From 2c8609ca987d8d5a799084d896b003ceab5b12ef Mon Sep 17 00:00:00 2001 From: Salastil Date: Thu, 8 Oct 2026 14:53:09 -0400 Subject: [PATCH] Buttons: primary, subtle and one danger; the restarts ask first (#316) Cancel is the quiet button next to a filled one, in every dialog; Decline on an invitation is quiet too. There is one filled red danger button, with the outline version in theme.css gone. Restart Tor and Restart daemon ask again in place. Co-Authored-By: Claude Sonnet 5.5 --- scripts/ui-shots.mjs | 12 ++++ src/renderer/src/app.css | 11 ++-- src/renderer/src/components/AccountsPanel.tsx | 2 +- src/renderer/src/components/ConfirmButton.tsx | 58 +++++++++++++++++++ src/renderer/src/components/ExportDialog.tsx | 2 +- src/renderer/src/components/InvitePanel.tsx | 2 +- src/renderer/src/components/LeaveConfirm.tsx | 2 +- src/renderer/src/components/ReasonPrompt.tsx | 2 +- .../src/components/settings/SettingsPanel.tsx | 27 +++++---- src/renderer/src/theme.css | 7 ++- 10 files changed, 98 insertions(+), 27 deletions(-) create mode 100644 src/renderer/src/components/ConfirmButton.tsx diff --git a/scripts/ui-shots.mjs b/scripts/ui-shots.mjs index f775676..dd58f72 100644 --- a/scripts/ui-shots.mjs +++ b/scripts/ui-shots.mjs @@ -569,6 +569,18 @@ const SCENES = [ }, clip: { x: 0, y: 380, width: 280, height: 260 } }, + { + // Restarting Tor asks first (#316). + name: 'settings-tor-confirm', + setup: async (p) => { + await p.evaluate(`window.__mohoShots.store.setActivePanel('settings')`) + await sleep(300) + await p.evaluate(click('.settings-rail-item', 'Tor')) + await sleep(300) + await p.evaluate(click('button', 'Restart Tor from scratch')) + await sleep(300) + } + }, // Motion, recorded rather than photographed. { name: 'motion-hover-rows', diff --git a/src/renderer/src/app.css b/src/renderer/src/app.css index 8843757..fd91db2 100644 --- a/src/renderer/src/app.css +++ b/src/renderer/src/app.css @@ -2488,11 +2488,12 @@ img.composer-emoji { outline-offset: -10px; } -/* The one button in the app that destroys something. Not --error, which is a - pale text colour and reads as decorative when used as a fill. */ -.button.danger { - background: var(--danger); - color: var(--on-accent); +/* Asking again, in place of the button that was pressed. */ +.confirm-button { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: var(--spacing-s); } /* --- mentions ---------------------------------------------------------- */ diff --git a/src/renderer/src/components/AccountsPanel.tsx b/src/renderer/src/components/AccountsPanel.tsx index b009acd..8a8ff3a 100644 --- a/src/renderer/src/components/AccountsPanel.tsx +++ b/src/renderer/src/components/AccountsPanel.tsx @@ -488,7 +488,7 @@ function AccountRow({ account }: { account: Account }): JSX.Element { > Remove - diff --git a/src/renderer/src/components/ConfirmButton.tsx b/src/renderer/src/components/ConfirmButton.tsx new file mode 100644 index 0000000..9aa82f5 --- /dev/null +++ b/src/renderer/src/components/ConfirmButton.tsx @@ -0,0 +1,58 @@ +import { useEffect, useState } from 'react' + +/** + * A button for something that interrupts - restarting Tor, restarting the + * daemon - that asks once more before doing it, in place. + * + * Not a dialog: the question is about the thing in front of you and answers + * itself in a click, and it takes itself back after a few seconds so a + * forgotten question is not left lying about as a loaded button. + */ +export function ConfirmButton({ + label, + question, + confirmLabel, + onConfirm, + danger +}: { + label: string + /** What is being asked, in a few words: "Restart Tor and lose its circuits?" */ + question: string + confirmLabel: string + onConfirm: () => void + danger?: boolean +}): JSX.Element { + const [asking, setAsking] = useState(false) + + useEffect(() => { + if (!asking) return + const t = setTimeout(() => setAsking(false), 6000) + return () => clearTimeout(t) + }, [asking]) + + if (!asking) { + return ( + + ) + } + return ( +
+ {question} + + +
+ ) +} diff --git a/src/renderer/src/components/ExportDialog.tsx b/src/renderer/src/components/ExportDialog.tsx index b15d719..a870efd 100644 --- a/src/renderer/src/components/ExportDialog.tsx +++ b/src/renderer/src/components/ExportDialog.tsx @@ -162,7 +162,7 @@ export function ExportDialog({ )}
- -
diff --git a/src/renderer/src/components/LeaveConfirm.tsx b/src/renderer/src/components/LeaveConfirm.tsx index f6dcee5..7399630 100644 --- a/src/renderer/src/components/LeaveConfirm.tsx +++ b/src/renderer/src/components/LeaveConfirm.tsx @@ -50,7 +50,7 @@ export function LeaveConfirm(props: {

{detail}

- - + />
@@ -1173,16 +1173,15 @@ function AboutSettings(): JSX.Element { {linkUp ? 'connected' : 'not connected'} - + /> {status && !status.available && (

The nobilis binary wasn't found. Run cargo build --release, or start diff --git a/src/renderer/src/theme.css b/src/renderer/src/theme.css index b698349..c32d73c 100644 --- a/src/renderer/src/theme.css +++ b/src/renderer/src/theme.css @@ -376,9 +376,10 @@ a:hover { } .button.danger { - background: transparent; - color: var(--error); - border: 1px solid var(--outline-medium); + /* The one button that destroys something: filled red, white text. Not + --error, a pale pink for text that went wrong, which cannot be a fill. */ + background: var(--danger); + color: var(--on-accent); } .muted {