Sidenote
Notes in the margin beside the line they belong to, numbered or not; on a narrow page they fold, and the number opens each under its line.
Demo
Quillo pages are rendered on the serverEvery route, every time: nothing is prerendered, and a cached view is the exception you ask for. and then resumed in the browser, which takes the server's elements as its own instead of drawing them again. A component's state travels with it, as JSON, in an attribute of its island.
That is why an image does not load twice and a scrolled list stays where it wasThe browser checks that the elements are the same; one that differs is made again, for that component only. See the guide.. What someone typed before the bundle came is kept, and done once it is there. Islands are woken when they are reachedPointed at, touched, focused, or a key pressed in them., which keeps a long page light.
On a phone the notes foldPress the number to open one under its line, and again to close it. and their numbers open them.
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/sidenote.qweimport ui/theme.qwe use theme_cssuse ui/sidenote.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>Example
The code of the preview above.
view SidenoteDemoText() = [ <p>Quillo pages are rendered on the server<Sidenote n={1} id="sidenote-demo-">Every route, every time: nothing is prerendered, and a cached view is the exception you ask for.</Sidenote> and then resumed in the browser, which takes the server's elements as its own instead of drawing them again. A component's state travels with it, as JSON, in an attribute of its island.</p>, <p>That is why an image does not load twice and a scrolled list stays where it was<Sidenote n={2} id="sidenote-demo-">The browser checks that the elements are the same; one that differs is made again, for that component only. See <a href="#sidenote">the guide</a>.</Sidenote>. What someone typed before the bundle came is kept, and done once it is there. Islands are woken when they are reached<Sidenote id="sidenote-demo-margin">Pointed at, touched, focused, or a key pressed in them.</Sidenote>, which keeps a long page light.</p>,]view SidenoteDemo() = <div.demo-stack style="gap: 28px"> <SidenoteText id="sidenote-demo-wide" width={210}><SidenoteDemoText/></SidenoteText> <div style="max-width: 420px; padding: 14px; border: 1px dashed var(--ui-border); border-radius: 8px"> <SidenoteText id="sidenote-demo-narrow"> <p>On a phone the notes fold<Sidenote n={1} id="sidenote-demo-n">Press the number to open one under its line, and again to close it.</Sidenote>{" "} and their numbers open them.</p> </SidenoteText> </div> </div>Source
// Sidenote: a note in the margin beside the line it belongs to, as books and long// essays have them, instead of at the end. Sidenote goes in the text where the number// should be; SidenoteText holds the text and keeps a column at its side for the notes.// Where that is too narrow (the whole under 640 pixels, on a phone), the notes fold and the// number becomes a button that opens its note under the line, without JavaScript.//// <SidenoteText>// <p>Pages render on the server<Sidenote n={1}>Every route, every time: nothing is// prerendered.</Sidenote> and resume in the browser.</p>// <p>A margin note has no number<Sidenote id="sn-islands">Islands are <em>reached</em>, not loaded.</Sidenote>.</p>// </SidenoteText>//// Sidenote: children, the note (text, links, emphasis: what goes inside a line). n: its// number, shown at the mark and before the note; none makes it a margin note, opened by// a small ⊕ on a narrow page. id: the note's id is id + n ("sn1", "sn2"), or id itself// for a margin note (give each its own); the toggle's is that + "-toggle". label: what the// toggle is called for screen readers ("Note"; "Note 1" with a number).// SidenoteText: children, the text. width: of the notes' column in pixels (220). gap:// between the text and that column (32). id, class: of its element. A Sidenote outside// a SidenoteText is always folded. A note is role="note"; on a wide page it is read// where it stands in the text.import ui/theme.qwe use ui_clslet sidenote_css = css`.ui-bsnote-text { container-type: inline-size; --ui-bsnote-w: 220px; --ui-bsnote-gap: 32px; }.ui-bsnote { font-style: normal; }.ui-bsnote-ref { display: inline-block; margin: 0 1px; padding: 0 3px; border-radius: 4px; color: var(--ui-accent); font: 700 .7em/1 var(--ui-font); vertical-align: super; cursor: pointer; }.ui-bsnote-ref:hover { background: var(--ui-accent-soft); }.ui-bsnote-mark { font-size: .8em; font-weight: 400; }.ui-bsnote-toggle { position: absolute; width: 1px; height: 1px; margin: 0; overflow: hidden; clip: rect(0 0 0 0); opacity: 0; }.ui-bsnote:has(.ui-bsnote-toggle:focus-visible) .ui-bsnote-ref { box-shadow: var(--ui-focus); }.ui-bsnote-note { display: none; margin: 8px 0; padding: 8px 12px; border-left: 3px solid var(--ui-accent); border-radius: 0 var(--ui-radius-sm) var(--ui-radius-sm) 0; background: var(--ui-subtle); color: var(--ui-muted); font: 13.5px/1.5 var(--ui-font); text-align: start; }.ui-bsnote-toggle:checked ~ .ui-bsnote-note { display: block; }.ui-bsnote-n { margin-right: 6px; color: var(--ui-accent); font-weight: 700; }.ui-bsnote-note a { color: var(--ui-accent); }@container (min-width: 640px) { .ui-bsnote-flow { padding-right: calc(var(--ui-bsnote-w) + var(--ui-bsnote-gap)); } .ui-bsnote-text .ui-bsnote .ui-bsnote-note { display: block; float: right; clear: right; position: relative; width: var(--ui-bsnote-w); margin: 4px calc(-1 * (var(--ui-bsnote-w) + var(--ui-bsnote-gap))) 10px 0; padding: 0 0 0 10px; border-left: 2px solid var(--ui-border); border-radius: 0; background: none; } .ui-bsnote-text .ui-bsnote-ref { padding: 0 1px; cursor: default; } .ui-bsnote-text .ui-bsnote-ref:hover { background: none; } .ui-bsnote-text .ui-bsnote-mark { display: none; } .ui-bsnote-text .ui-bsnote-toggle { display: none; }}`view Sidenote(n: int? = null, id: str = "sn", label: str = "Note", children) { style global sidenote_css let note_id = n != null ? `${id}${n}` : id <span.ui-bsnote> <label.ui-bsnote-ref for={`${note_id}-toggle`}>{n != null ? str(n) : <span.ui-bsnote-mark aria-hidden="true">⊕</span>}</label> <input.ui-bsnote-toggle type="checkbox" id={`${note_id}-toggle`} aria-label={n != null ? `${label} ${n}` : label} aria-controls={note_id}/> <span.ui-bsnote-note id={note_id} role="note">{n != null && <span.ui-bsnote-n aria-hidden="true">{n}</span>}{children}</span> </span>}view SidenoteText(width: int = 220, gap: int = 32, id: str? = null, class: str? = null, children) { style global sidenote_css <div id={id} class={ui_cls(["ui-bsnote-text", class])} style={`--ui-bsnote-w: ${width}px; --ui-bsnote-gap: ${gap}px`}> <div.ui-bsnote-flow>{children}</div> </div>}Related
Thread 0 posts
On Sidenote: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.