Notices
The styles for Quillo's own notify() toasts and ask() dialogs, in every tone and position.
Demo
Nothing asked yet.
Styles for notify() and ask(). Place them with <body data-notices="dialog-center toasts-bottom-right">.
Get it
It needs theme.qwe, as every component does; 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/notices.qwemain.qwe
import ui/theme.qwe use theme_cssuse ui/notices.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>Example
The code of the preview above.
demos/notices.qwe
component NoticesDemoLive() { state answer = "Nothing asked yet." <div.demo-stack> <div.demo-row> <Button variant="soft" tone="neutral" on_click={() => notify("Draft saved.")}>Neutral</Button> <Button variant="soft" on_click={() => notify("Your invite is on its way.", { title: "Sent", tone: "success" })}>Success</Button> <Button variant="soft" on_click={() => notify("Your card expires this month.", { title: "Heads up", tone: "warning", seconds: 6 })}>Warning</Button> <Button variant="soft" tone="danger" on_click={() => notify("We could not reach the server.", { title: "Offline", tone: "danger" })}>Danger</Button> <Button variant="soft" on_click={() => notify("A new version is out.", { tone: "info" })}>Info</Button> </div> <div.demo-row> <Button variant="outline" on_click={() => { answer = ask("Publish these changes to the site?", { title: "Publish", ok: "Publish" }) ? "You said publish." : "You said not now." }}>Ask</Button> <Button variant="outline" tone="danger" on_click={() => { let yes = ask("This removes the project and its 214 files. It cannot be undone.", { title: "Delete project?", ok: "Delete", cancel: "Keep it", tone: "danger" }) answer = yes ? "Deleted (not really)." : "Kept." }}>Ask (danger)</Button> <span.demo-note>{answer}</span> </div> </div>}view NoticesDemo() = <div.demo-stack> <NoticesDemoLive/> <p.demo-note> Styles for notify() and ask(). Place them with <body data-notices="dialog-center toasts-bottom-right">. </p> </div>Source
ui/notices.qwe
// Notices: the styles for Quillo's own notify() toasts and ask() dialogs. This// file is styles only: the runtime makes the markup (q- classes in a #q-notices// host it adds to <body>), and handles focus, Escape and screen readers.//// notify("Saved", { tone: "success" })// notify("Could not reach the server", { title: "Offline", tone: "danger", seconds: 8 })// if ask("Delete this project?", { title: "Delete", ok: "Delete", tone: "danger" }) { ... }//// tone: "neutral" (default), "success", "warning", "danger" or "info".// Where they show comes from <body data-notices="...">, which the host takes as its// classes (default "dialog-center toasts-top-right"):// toasts-top-right, toasts-top-left, toasts-top-center,// toasts-bottom-right, toasts-bottom-left, toasts-bottom-center;// dialog-center, dialog-top, dialog-sheet (from the bottom), dialog-side (from the right).// On a phone, toasts take the full width at the top or bottom.// Notices() renders nothing; it is here so the file has a name like the others.// Its styles are the page's, in `ui_css` with the theme: the runtime makes the// markup for whichever page calls notify() or ask().let notices_css = css`.q-notices { position: relative; z-index: 1000; font: 14px/1.45 var(--ui-font); color: var(--ui-fg); }.q-notices .q-backdrop { position: fixed; inset: 0; z-index: 1001; display: flex; align-items: center; justify-content: center; padding: 16px; background: var(--ui-overlay); opacity: 0; transition: opacity .16s;}.q-notices .q-backdrop.q-open { opacity: 1; }.q-notices .q-dialog { --q-tone: var(--ui-accent); --q-tone-fg: var(--ui-accent-fg); width: min(420px, 100%); max-height: calc(100vh - 32px); overflow: auto; padding: 20px 22px 18px; background: var(--ui-surface); color: var(--ui-fg); border: 1px solid var(--ui-border); border-radius: var(--ui-radius); box-shadow: var(--ui-shadow-lg); transform: translateY(8px) scale(.98); transition: transform .16s ease-out;}.q-notices .q-open .q-dialog { transform: none; }.q-notices .q-dialog .q-title { margin: 0 0 6px; font-size: 17px; font-weight: 600; line-height: 1.3; }.q-notices .q-dialog .q-message { margin: 0 0 20px; color: var(--ui-muted); }.q-notices .q-dialog .q-title + .q-message { margin-top: 0; }.q-notices .q-actions { display: flex; justify-content: flex-end; flex-wrap: wrap; gap: 8px; }.q-notices .q-actions button { height: 36px; padding: 0 16px; border-radius: var(--ui-radius-sm); border: 1px solid var(--ui-border); background: var(--ui-surface); color: var(--ui-fg); font: 500 14px/1 var(--ui-font); cursor: pointer; transition: background .15s, border-color .15s, box-shadow .15s;}.q-notices .q-actions .q-cancel:hover { background: var(--ui-subtle); border-color: var(--ui-strong); }.q-notices .q-actions .q-ok { background: var(--q-tone); border-color: transparent; color: var(--q-tone-fg); }.q-notices .q-actions .q-ok:hover { background: color-mix(in srgb, var(--q-tone) 88%, var(--ui-fg)); }.q-notices .q-actions button:focus-visible { outline: none; box-shadow: var(--ui-focus); }.q-notices .q-dialog.q-danger { --q-tone: var(--ui-danger); --q-tone-fg: #fff; }.q-notices .q-dialog.q-warning { --q-tone: var(--ui-warning); --q-tone-fg: var(--ui-surface); }.q-notices .q-dialog.q-success { --q-tone: var(--ui-success); --q-tone-fg: var(--ui-surface); }.q-notices .q-dialog.q-info { --q-tone: var(--ui-info); --q-tone-fg: var(--ui-surface); }.q-notices .q-dialog.q-neutral { --q-tone: var(--ui-fg); --q-tone-fg: var(--ui-bg); }.q-notices .q-dialog:is(.q-danger, .q-warning, .q-success, .q-info) .q-title::before { content: ""; display: inline-block; width: 8px; height: 8px; margin: 0 8px 2px 0; border-radius: 50%; background: var(--q-tone);}.q-notices.dialog-top .q-backdrop { align-items: flex-start; padding-top: 10vh; }.q-notices.dialog-sheet .q-backdrop { align-items: flex-end; padding: 0; }.q-notices.dialog-sheet .q-dialog { width: min(640px, 100%); border-radius: var(--ui-radius) var(--ui-radius) 0 0; border-bottom: 0; transform: translateY(40px); }.q-notices.dialog-side .q-backdrop { justify-content: flex-end; align-items: stretch; padding: 0; }.q-notices.dialog-side .q-dialog { display: flex; flex-direction: column; justify-content: center; width: min(400px, 100%); max-height: none; border-radius: 0; border-width: 0 0 0 1px; transform: translateX(40px);}.q-notices.dialog-sheet .q-open .q-dialog, .q-notices.dialog-side .q-open .q-dialog { transform: none; }.q-notices .q-toasts { position: fixed; z-index: 1002; top: 0; right: 0; display: flex; flex-direction: column; gap: 8px; width: min(400px, 100%); padding: 16px; pointer-events: none;}.q-notices.toasts-top-left .q-toasts { right: auto; left: 0; }.q-notices.toasts-top-center .q-toasts { right: auto; left: 50%; transform: translateX(-50%); }.q-notices:is(.toasts-bottom-right, .toasts-bottom-left, .toasts-bottom-center) .q-toasts { top: auto; bottom: 0; flex-direction: column-reverse; }.q-notices.toasts-bottom-left .q-toasts { right: auto; left: 0; }.q-notices.toasts-bottom-center .q-toasts { right: auto; left: 50%; transform: translateX(-50%); }.q-notices .q-toast { --q-tone: var(--ui-strong); pointer-events: auto; display: grid; grid-template-columns: 1fr auto; gap: 2px 10px; align-items: start; padding: 11px 8px 11px 14px; background: var(--ui-surface); color: var(--ui-fg); border: 1px solid var(--ui-border); border-left: 3px solid var(--q-tone); border-radius: var(--ui-radius-sm); box-shadow: var(--ui-shadow-lg); opacity: 0; transform: translateY(-8px); transition: opacity .16s, transform .16s ease-out;}.q-notices:is(.toasts-bottom-right, .toasts-bottom-left, .toasts-bottom-center) .q-toast { transform: translateY(8px); }.q-notices .q-toast.q-open { opacity: 1; transform: none; }.q-notices .q-toast .q-title { grid-column: 1; font-weight: 600; }.q-notices .q-toast .q-message { grid-column: 1; min-width: 0; overflow-wrap: anywhere; }.q-notices .q-toast .q-title + .q-message { color: var(--ui-muted); }.q-notices .q-toast .q-close { grid-column: 2; grid-row: 1 / span 2; width: 26px; height: 26px; margin: -3px 0; padding: 0; border: 0; border-radius: var(--ui-radius-sm); background: transparent; color: var(--ui-muted); font-size: 18px; line-height: 1; cursor: pointer;}.q-notices .q-toast .q-close:hover { background: var(--ui-subtle); color: var(--ui-fg); }.q-notices .q-toast .q-close:focus-visible { outline: none; box-shadow: var(--ui-focus); }.q-notices .q-toast.q-success { --q-tone: var(--ui-success); }.q-notices .q-toast.q-warning { --q-tone: var(--ui-warning); }.q-notices .q-toast.q-danger { --q-tone: var(--ui-danger); }.q-notices .q-toast.q-info { --q-tone: var(--ui-info); }.q-notices .q-toast.q-neutral { --q-tone: var(--ui-fg); }@media (max-width: 480px) { .q-notices .q-toasts { width: 100%; padding: 10px; } .q-notices.toasts-top-center .q-toasts, .q-notices.toasts-bottom-center .q-toasts { transform: none; left: 0; }}@media (prefers-reduced-motion: reduce) { .q-notices .q-backdrop, .q-notices .q-dialog, .q-notices .q-toast { transition: opacity .16s; transform: none; }}`view Notices() = nullRelated
SnackbarA short message along the bottom of the window with one action, shown from anywhere by calling snackbar_show().6 views · 6 downloadsAlertA message in the page in six tones and three variants, with an icon, announced to screen readers, and dismissable.5 views · 9 downloadsBadgeA small pill for a status or a count: six tones, soft, solid or outline, a status dot, and 99+.8 views · 6 downloadsBannerAn announcement across the top of the page in six tones, with a link, closed for the session once dismissed.7 views · 6 downloadsCoachmarkA small callout pointing at an element by id, explaining it once, dismissed with Got it; several make a tour.6 views · 8 downloadsConnectionStatusSays when the browser goes offline, as a bar across the top or a pill, and that it is back online for a moment.6 views · 7 downloads
Thread
Thread 0 posts
On Notices: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.