OrgChart
A tree of people as boxes joined by lines, drawn with CSS on nested lists, with pictures, titles, notes and the reader's place marked.
Demo
Grace HopperCompilers, 2 reports
- Jean SammetLanguages
- Frances AllenOptimisation
- Alan TuringResearch, 1 report
- Joan ClarkeCryptanalysis
- Hedy LamarrRadioHiring
- Chair, 1 report
- Treasurer
Get it
It needs theme.qwe, as every component does, and avatar.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/avatar.qwe$ curl -O https://quillolang.org/components/ui/org_chart.qwemain.qwe
import ui/theme.qwe use theme_cssuse ui/org_chart.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>Example
The code of the preview above.
demos/org_chart.qwe
let org_chart_demo_team = { name: "Ada Lovelace", title: "CTO", href: "#org_chart", note: "3 reports", children: [ { name: "Grace Hopper", title: "Compilers", src: "https://i.pravatar.cc/80?img=47", children: [ { name: "Jean Sammet", title: "Languages" }, { id: "fran", name: "Frances Allen", title: "Optimisation" }, ] }, { name: "Alan Turing", title: "Research", children: [{ name: "Joan Clarke", title: "Cryptanalysis" }] }, { name: "Hedy Lamarr", title: "Radio", note: "Hiring" },] }view OrgChartDemo() = <div.demo-stack> <OrgChart id="org-chart-demo-full" label="Engineering" root={org_chart_demo_team} highlight="fran"/> <OrgChart id="org-chart-demo-compact" compact={true} label="Board" root={{ name: "Chair", children: [{ name: "Treasurer" }] }}/> </div>Source
ui/org_chart.qwe
// OrgChart: who reports to whom: a tree of people as boxes, each joined to the one// above by lines, drawn with CSS on nested lists (so screen readers hear the// nesting). It scrolls sideways when it is wider than its place.//// <OrgChart label="Engineering" root={{ name: "Ada Lovelace", title: "CTO", children: [// { name: "Grace Hopper", title: "Compilers", children: [{ name: "Jean Sammet", title: "Languages" }] },// { name: "Alan Turing", title: "Research" },// ] }}/>//// root: the person at the top, a map of { name, title?, src?, href?, id?, note?,// children? }: src a picture (initials without one), href makes the name a link,// note a small line under the title ("4 reports", "Hiring"), children the people// who report to them, the same shape. highlight: a person's id (or name) to mark,// as the reader's place ("you"). compact: smaller boxes, without pictures.// label: what screen readers call the chart ("Organisation chart"). id: its id.// Needs avatar.qwe.import ui/avatar.qwe use Avatarimport ui/theme.qwe use ui_clslet org_chart_css = css`.ui-org-chart { min-width: 0; overflow-x: auto; padding: 4px 4px 8px; font: 13px/1.35 var(--ui-font); color: var(--ui-fg); --ui-org-chart-line: var(--ui-strong); }.ui-org-chart ul { position: relative; display: flex; justify-content: center; margin: 0; padding: 22px 0 0; list-style: none; }.ui-org-chart > ul { padding-top: 0; width: max-content; min-width: 100%; }.ui-org-chart li { position: relative; display: flex; flex-direction: column; align-items: center; padding: 22px 8px 0; }.ui-org-chart > ul > li { padding-top: 0; }.ui-org-chart li::before, .ui-org-chart li::after { content: ""; position: absolute; top: 0; right: 50%; width: 50%; height: 22px; border-top: 2px solid var(--ui-org-chart-line); }.ui-org-chart li::after { right: auto; left: 50%; border-left: 2px solid var(--ui-org-chart-line); }.ui-org-chart li:only-child::before, .ui-org-chart li:only-child::after { display: none; }.ui-org-chart li:only-child { padding-top: 0; }.ui-org-chart li:first-child::before, .ui-org-chart li:last-child::after { border: 0 none; }.ui-org-chart li:last-child::before { border-right: 2px solid var(--ui-org-chart-line); border-radius: 0 8px 0 0; }.ui-org-chart li:first-child::after { border-radius: 8px 0 0 0; }.ui-org-chart ul ul::before { content: ""; position: absolute; top: 0; left: 50%; width: 0; height: 22px; border-left: 2px solid var(--ui-org-chart-line); }.ui-org-chart > ul > li::before, .ui-org-chart > ul > li::after { display: none; }.ui-org-chart-box { display: grid; justify-items: center; gap: 2px; width: 150px; padding: 12px 10px 10px; border: 1px solid var(--ui-border); border-radius: var(--ui-radius); background: var(--ui-surface); text-align: center; box-shadow: 0 1px 2px color-mix(in srgb, var(--ui-fg) 6%, transparent); }.ui-org-chart-box .ui-org-chart-pic { margin-bottom: 6px; }.ui-org-chart-name { font-size: 14px; font-weight: 650; overflow-wrap: anywhere; }.ui-org-chart-name a { color: inherit; text-decoration: none; }.ui-org-chart-name a:hover { color: var(--ui-accent); text-decoration: underline; }.ui-org-chart-name a:focus-visible { outline: none; border-radius: 4px; box-shadow: var(--ui-focus); }.ui-org-chart-title { color: var(--ui-muted); }.ui-org-chart-note { margin-top: 4px; padding: 1px 8px; border-radius: 999px; background: var(--ui-subtle); color: var(--ui-muted); font-size: 11px; }.ui-org-chart-here { border-color: var(--ui-accent); background: var(--ui-accent-soft); box-shadow: 0 0 0 1px var(--ui-accent); }.ui-org-chart-here .ui-org-chart-title { color: var(--ui-accent); }.ui-org-chart-compact .ui-org-chart-box { width: 120px; padding: 8px; }.ui-org-chart-compact .ui-org-chart-name { font-size: 13px; }`// One person and, under them, those who report to them.fn org_chart_node(p: map, highlight, compact: bool) { let here = highlight != null && (p.id ?? p.name) == highlight let kids = p.children ?? [] <li key={p.id ?? p.name}> <div class={ui_cls(["ui-org-chart-box", here && "ui-org-chart-here"])} aria-current={here ? "true" : null}> {!compact && <Avatar name={p.name} src={p.src} size="md" class="ui-org-chart-pic"/>} <span.ui-org-chart-name>{p.href != null ? <a href={p.href}>{p.name}</a> : p.name}</span> {p.title != null && <span.ui-org-chart-title>{p.title}</span>} {p.note != null && <span.ui-org-chart-note>{p.note}</span>} {len(kids) > 0 && <span.ui-sr>, {len(kids)} {len(kids) == 1 ? "report" : "reports"}</span>} </div> {len(kids) > 0 && <ul>{for k in kids => org_chart_node(k, highlight, compact)}</ul>} </li>}view OrgChart(root: map, highlight = null, compact: bool = false, label: str = "Organisation chart", id: str? = null, class: str? = null) { style global org_chart_css <div class={ui_cls(["ui-org-chart", compact && "ui-org-chart-compact", class])} id={id} role="group" aria-label={label} tabindex="0"> <ul>{org_chart_node(root, highlight, compact)}</ul> </div>}Related
AvatarStackOverlapping avatars with names in tooltips, links to each person, and a +N that names the rest.5 views · 9 downloadsFlowStepsA process as boxes joined by arrows, with words on the arrows, tones and done, current or coming steps; horizontal, or vertical where narrow.6 views · 7 downloadsLeaderboardPeople ranked by score with medals for the top three, shared places for ties, and your own row kept in view.7 views · 7 downloadsDirectoryNavA long list of names grouped under sticky letter headers, with a row of letters at the top that jumps to each group.5 views · 5 downloadsActivityFeedA stream of what people did, with their pictures, an icon for each kind of action, when, quotes and day headings.5 views · 7 downloadsAvatarA picture, or initials on a colour of the person's own, with a status dot; and overlapping groups with +N.6 views · 5 downloads
Thread
Thread 0 posts
On OrgChart: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.