DangerZone
A red-bordered block of destructive actions (DangerAction), each a form, link or callback that asks before it acts.
Demo
Danger zone
- Transfer
Transfer ownership
Give this project to someone else on the team.
Account
These act on your whole account.
Sign out everywhere
Every other device is signed out.
Delete account
Your projects, files and billing history go, for good.
Each button asks first; yes calls on_confirm.
Get it
It needs theme.qwe, as every component does, and button.qwe and confirm_button.qwe; or take the whole kit, quillo-ui.qwe. Each component brings its own styles to the pages that show it.
$ curl -O https://quillolang.org/components/ui/theme.qwe$ curl -O https://quillolang.org/components/ui/button.qwe$ curl -O https://quillolang.org/components/ui/confirm_button.qwe$ curl -O https://quillolang.org/components/ui/danger_zone.qwemain.qwe
import ui/theme.qwe use theme_cssuse ui/danger_zone.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>Example
The code of the preview above.
demos/danger_zone.qwe
component DangerZoneDemoLive() { state done = null <div.demo-stack> <DangerZone title="Account" description="These act on your whole account."> <DangerAction title="Sign out everywhere" text="Every other device is signed out." label="Sign out all" tone="neutral" on_confirm={() => { done = "Signed out everywhere." }}/> <DangerAction title="Delete account" text="Your projects, files and billing history go, for good." on_confirm={() => { done = "Account deleted (not really)." }}/> </DangerZone> <p.demo-note>{done ?? "Each button asks first; yes calls on_confirm."}</p> </div>}view DangerZoneDemo() = <div.demo-stack> <DangerZone id="danger-zone-demo"> <DangerAction title="Transfer ownership" text="Give this project to someone else on the team." label="Transfer" href="#danger_zone" tone="neutral" confirm={false}/> <DangerAction title="Archive project" text="Read-only for everyone; you can bring it back." label="Archive" action="#danger_zone" name="archive" value="yes" tone="neutral" message="People lose write access until you restore it."/> <DangerAction title="Delete project" text="Everything in it goes, for good, within the hour." label="Delete project" action="#danger_zone" name="delete" value="yes" message="The files, the database and the deploys go too."/> </DangerZone> <DangerZoneDemoLive/> </div>Source
ui/danger_zone.qwe
// DangerZone: the destructive actions of a settings page in a red-bordered// block, each with what it does and a button that asks before doing it.// DangerAction is one row. It uses ConfirmButton (ui/confirm_button.qwe) and// the Button styles.//// <DangerZone>// <DangerAction title="Transfer ownership" text="Give this project to someone else." label="Transfer"// href="/project/transfer" tone="neutral" confirm={false}/>// <DangerAction title="Delete project" text="Everything in it goes, for good." label="Delete project"// action="/project/delete" message="Type nothing; just be sure: the files go too."/>// </DangerZone>//// DangerZone: title ("Danger zone"), description, children (DangerActions).// DangerAction: title and text, what it does; label, the button's text (the// title by default). action: the row is a <form method="post"> to that address,// sent with name and value (if given) when confirmed. href: a link instead.// on_confirm(): inside one of your components, what yes does instead.// message: the question asked first (a sentence about the title by default);// ok: the dialog's yes button (the label). tone: "danger" (default) or// "neutral", the button's. confirm: false skips the question (for a link that// leads to a page that asks).import ui/button.qwe use Buttonimport ui/confirm_button.qwe use ConfirmButtonimport ui/theme.qwe use ui_clslet danger_zone_css = css`.ui-danger { border: 1px solid color-mix(in srgb, var(--ui-danger) 45%, var(--ui-border)); border-radius: var(--ui-radius); background: var(--ui-surface); font: 14px/1.5 var(--ui-font); color: var(--ui-fg); }.ui-danger-head { padding: 16px 20px 12px; border-bottom: 1px solid color-mix(in srgb, var(--ui-danger) 30%, var(--ui-border)); }.ui-danger-title { display: flex; align-items: center; gap: 8px; margin: 0; color: var(--ui-danger); font-size: 16px; font-weight: 600; line-height: 1.3; }.ui-danger-title svg { width: 18px; height: 18px; }.ui-danger-desc { margin: 3px 0 0; color: var(--ui-muted); }.ui-danger-rows { margin: 0; padding: 0; list-style: none; }.ui-danger-row + .ui-danger-row { border-top: 1px solid var(--ui-border); }.ui-danger-row > form, .ui-danger-row > div { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 24px; margin: 0; padding: 14px 20px; }.ui-danger-what { flex: 1 1 260px; min-width: 0; }.ui-danger-row-title { margin: 0; font-weight: 600; }.ui-danger-text { margin: 2px 0 0; color: var(--ui-muted); }`view DangerZone(title: str = "Danger zone", description: str? = null, id: str? = null, class: str? = null, children) { style global danger_zone_css let tid = id != null ? `${id}-title` : null <section id={id} class={ui_cls(["ui-danger", class])} aria-labelledby={tid} aria-label={tid == null ? title : null}> <div.ui-danger-head> <h2.ui-danger-title id={tid}> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 9v4M12 17h.01M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/></svg> {title} </h2> {description != null && <p.ui-danger-desc>{description}</p>} </div> <ul.ui-danger-rows>{children}</ul> </section>}view DangerAction(title: str, text: str? = null, label: str? = null, action: str? = null, href: str? = null, name: str? = null, value: str? = null, message: str? = null, ok: str? = null, tone: str = "danger", confirm: bool = true, on_confirm = null, class: str? = null) { style global danger_zone_css let word = label ?? title let what = <div.ui-danger-what> <p.ui-danger-row-title>{title}</p> {text != null && <p.ui-danger-text>{text}</p>} </div> let button = confirm ? <ConfirmButton message={message ?? `${title}: this cannot be undone.`} title={`${title}?`} ok={ok ?? word} tone={tone} href={href} name={name} value={value} variant="outline" size="sm" on_confirm={on_confirm}>{word}</ConfirmButton> : <Button href={href} type={action != null ? "submit" : "button"} name={name} value={value} tone={tone} variant="outline" size="sm" on_click={on_confirm}>{word}</Button> <li class={ui_cls(["ui-danger-row", class])}> {action != null && on_confirm == null ? <form method="post" action={action}>{what}{button}</form> : <div>{what}{button}</div>} </li>}Related
ApiKeyFieldA secret shown masked in a read-only field, with Show and Copy buttons and a hidden input for forms.5 views · 6 downloadsPermissionsMatrixRoles across, permissions down, a checkbox at each: a form sends the pairs ticked, a column box ticks a whole role.6 views · 6 downloadsQuickActionsA grid of big icon buttons for the common actions: links, submit buttons in a form, or on_select.6 views · 5 downloadsSessionListSigned-in devices with browser, system, place and time, this one marked, and Sign out for each or all the others.6 views · 5 downloadsSettingsSectionA titled block of settings rows, each a label and hint with its control at the right (SettingsRow).5 views · 5 downloadsTokenListAPI tokens with name, prefix, created, last used, scopes and expiry, and a Revoke that asks first.6 views · 8 downloads
Thread
Thread 0 posts
On DangerZone: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.