Feedback

Notices

The styles for Quillo's own notify() toasts and ask() dialogs, in every tone and position.

#feedback#toast#dialog#no-js

Demo

Preview
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.qwe
main.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            &lt;body data-notices="dialog-center toasts-bottom-right"&gt;.        </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() = null
Thread
56Useful? Like it, or add to its thread below.

Thread 0 posts

On Notices: questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.