Typography

Prose

Styles for a block of article HTML (from markdown() or by hand): headings, lists, links, quotes, code, tables.

#typography#text#document#no-js

Demo

Preview

Writing a component

Each component is one file you copy into your program. It brings its own styles, follows the system's light or dark theme, and works with the keyboard. See the gallery for every one.

What goes in

Three things, in this order:

  1. A comment saying what it is, with an example.
  2. Its CSS, as let name_css = css`...`.
  3. The view or component.

Views first: a component with nothing to remember is a view, built on what the browser already does.

Checking it

scripts/build.sh
QUILLO=target/release/quillo scripts/test.sh button
KindRunsScript
viewon the servernone
componentserver, then browserits bundle
  • Colours only through the theme's variables
    • so dark mode works by itself
  • Press Tab to reach everything

Last edited today, yesterday.

Small, narrow

For a sidebar note, at 14px and 30 characters wide.

Large

For a lede or a landing page, at 18px.

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/prose.qwe
main.qwe
import ui/theme.qwe use theme_cssuse ui/prose.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>

Example

The code of the preview above.

demos/prose.qwe
view ProseDemo() =    <div.demo-stack>        <Prose id="prose-demo-article">            <h1>Writing a component</h1>            <p>Each component is <strong>one file</strong> you copy into your program. It brings its               own styles, follows the system's <em>light or dark</em> theme, and works with the               keyboard. See <a href="#prose">the gallery</a> for every one.</p>            <h2>What goes in</h2>            <p>Three things, in this order:</p>            <ol>                <li>A comment saying what it is, with an example.</li>                <li>Its CSS, as <code>let name_css = css`...`</code>.</li>                <li>The <code>view</code> or <code>component</code>.</li>            </ol>            <blockquote><p>Views first: a component with nothing to remember is a view, built on what the browser already does.</p></blockquote>            <h3>Checking it</h3>            <pre><code>scripts/build.shQUILLO=target/release/quillo scripts/test.sh button</code></pre>            <table>                <thead><tr><th>Kind</th><th>Runs</th><th>Script</th></tr></thead>                <tbody>                    <tr><td>view</td><td>on the server</td><td>none</td></tr>                    <tr><td>component</td><td>server, then browser</td><td>its bundle</td></tr>                </tbody>            </table>            <ul>                <li>Colours only through the theme's variables                    <ul><li>so dark mode works by itself</li></ul></li>                <li>Press <kbd>Tab</kbd> to reach everything</li>            </ul>            <hr/>            <p>Last edited <mark>today</mark>, <del>yesterday</del>.</p>        </Prose>        <div.demo-row>            <Prose size="sm" width="30ch" id="prose-demo-small"><h2>Small, narrow</h2><p>For a sidebar note, at 14px and 30 characters wide.</p></Prose>            <Prose size="lg" width="30ch" id="prose-demo-large"><h2>Large</h2><p>For a lede or a landing page, at 18px.</p></Prose>        </div>    </div>

Source

ui/prose.qwe
// Prose: styles for a block of article HTML, from markdown() or written by hand:// headings, paragraphs, lists, links, quotes, code, tables, images and rules all// read well, in the theme, without a style of their own.////   <Prose>{markdown(post.body)}</Prose>//   <Prose size="lg" width="60ch"><h1>Title</h1><p>...</p></Prose>//// children: the article's HTML. size: "sm", "md" (default) or "lg", the body text's size;// the rest scale with it. width: the measure, a CSS max-width ("68ch" by default;// null for none). id: the element's id, for a TableOfContents or a link.import ui/theme.qwe use ui_clslet prose_css = css`.ui-prose { max-width: 68ch; font: 16px/1.7 var(--ui-font); color: var(--ui-fg); overflow-wrap: anywhere; }.ui-prose-sm { font-size: 14px; line-height: 1.65; }.ui-prose-lg { font-size: 18px; line-height: 1.75; }.ui-prose > :first-child { margin-top: 0; }.ui-prose > :last-child { margin-bottom: 0; }.ui-prose p, .ui-prose ul, .ui-prose ol, .ui-prose blockquote, .ui-prose pre, .ui-prose table, .ui-prose figure,.ui-prose dl, .ui-prose details { margin: 0 0 1.1em; }.ui-prose h1, .ui-prose h2, .ui-prose h3, .ui-prose h4, .ui-prose h5, .ui-prose h6 {  margin: 1.7em 0 .55em; font-weight: 650; line-height: 1.25; letter-spacing: -.015em; color: var(--ui-fg); }.ui-prose h1 { font-size: 2em; line-height: 1.15; letter-spacing: -.02em; }.ui-prose h2 { font-size: 1.5em; }.ui-prose h3 { font-size: 1.25em; }.ui-prose h4 { font-size: 1.1em; }.ui-prose h5 { font-size: 1em; }.ui-prose h6 { font-size: .85em; letter-spacing: .05em; text-transform: uppercase; color: var(--ui-muted); }.ui-prose :is(h1, h2, h3, h4, h5, h6) + :is(h1, h2, h3, h4, h5, h6) { margin-top: .4em; }.ui-prose a { color: var(--ui-accent); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px; }.ui-prose a:hover { text-decoration-thickness: 2px; }.ui-prose a:focus-visible { outline: none; border-radius: 3px; box-shadow: var(--ui-focus); }.ui-prose strong { font-weight: 600; }.ui-prose ul, .ui-prose ol { padding-left: 1.5em; }.ui-prose li { margin: .3em 0; }.ui-prose li > ul, .ui-prose li > ol { margin: .3em 0; }.ui-prose li::marker { color: var(--ui-muted); }.ui-prose ul:has(> li > input[type="checkbox"]) { padding-left: .25em; list-style: none; }.ui-prose li > input[type="checkbox"] { margin: 0 .5em 0 0; vertical-align: -.1em; }.ui-prose blockquote { margin-left: 0; padding: .25em 0 .25em 1.1em; border-left: 3px solid var(--ui-accent); color: var(--ui-muted); }.ui-prose blockquote > :last-child { margin-bottom: 0; }.ui-prose code { padding: .12em .35em; border-radius: 4px; background: var(--ui-subtle); font: .9em var(--ui-mono); }.ui-prose pre { padding: 14px 16px; overflow: auto; border: 1px solid var(--ui-border); border-radius: var(--ui-radius-sm);  background: var(--ui-subtle); font: .875em/1.6 var(--ui-mono); tab-size: 4; }.ui-prose pre code { padding: 0; border-radius: 0; background: none; font: inherit; }.ui-prose kbd { padding: .1em .4em; border: 1px solid var(--ui-border); border-bottom-width: 2px; border-radius: 4px;  background: var(--ui-surface); font: .85em var(--ui-mono); }.ui-prose mark { padding: 0 .15em; border-radius: 3px; background: color-mix(in srgb, var(--ui-warning) 28%, transparent); color: inherit; }.ui-prose table { width: 100%; border-collapse: collapse; font-size: .95em; line-height: 1.5; }.ui-prose th, .ui-prose td { padding: .5em .75em; border-bottom: 1px solid var(--ui-border); text-align: left; vertical-align: top; }.ui-prose th { font-weight: 600; border-bottom-color: var(--ui-strong); }.ui-prose tbody tr:last-child td { border-bottom-color: var(--ui-strong); }.ui-prose img, .ui-prose video { max-width: 100%; height: auto; border-radius: var(--ui-radius-sm); }.ui-prose figcaption { margin-top: .5em; font-size: .875em; color: var(--ui-muted); text-align: center; }.ui-prose hr { margin: 2em 0; border: 0; border-top: 1px solid var(--ui-border); }.ui-prose dt { font-weight: 600; }.ui-prose dd { margin: 0 0 .5em 1.5em; }.ui-prose del { color: var(--ui-muted); }.ui-prose sup, .ui-prose sub { font-size: .75em; line-height: 0; }`view Prose(size: str = "md", width: str? = "68ch", id: str? = null, class: str? = null, children) {    style global prose_css    <div class={ui_cls(["ui-prose", size != "md" && `ui-prose-${size}`, class])} id={id}         style={width != "68ch" ? `max-width: ${width ?? "none"}` : null}>{children}</div>}
Thread
65Useful? Like it, or add to its thread below.

Thread 0 posts

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

No posts yet. The first one opens the thread.