| new file mode 100644 |
| index 000000000..2597ae982 |
| --- /dev/null |
| +++ b/internal/console/icons.go |
| @@ -0,0 +1,77 @@ |
| +// The console's icon set — every piece of interface chrome, one file. This |
| +// is the server-side twin of Eleven's web/static/icons.js: static, in-code |
| +// SVG strings in the Lucide idiom (24×24 viewBox, currentColor, stroke, round |
| +// caps and joins), inlined into the page at render time. |
| +// |
| +// Vendored, never a CDN. The console has the same hard constraint as the |
| +// fleet status page — no build step, no JavaScript framework, and no external |
| +// request, ever. A <script src> or <link href> at some icon host would be a |
| +// second origin the console cannot vouch for, cannot cache-control, and |
| +// cannot serve when it is offline. Inlining the paths is the only option, so |
| +// the paths live here. |
| +// |
| +// Icons are vendored from Lucide — https://lucide.dev — used under the ISC |
| +// licence: |
| +// |
| +// Copyright (c) for portions of Lucide are held by Cole Bemis 2013-2022 as |
| +// part of Feather (MIT). All other copyright (c) for Lucide are held by |
| +// Lucide Contributors 2022. |
| +// |
| +// Permission to use, copy, modify, and/or distribute this software for any |
| +// purpose with or without fee is hereby granted, provided that the above |
| +// copyright notice and this permission notice appear in all copies. THE |
| +// SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH |
| +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| +// MERCHANTABILITY AND FITNESS. |
| +// |
| +// Emoji policy, inherited from Eleven's docs/icons.md: emoji are CONTENT — a |
| +// mark a person or a model chose, like the footer's factor-X disclosure — and |
| +// never chrome. Interface furniture uses these icons. Adding one = paste the |
| +// Lucide SVG's paths in below, keep the (Lucide: <slug>) comment, register it |
| +// in the icons map, use it as {{icon "<slug>"}}. |
| +// |
| +// Each icon carries aria-hidden="true" because every one of them sits beside |
| +// its own text label — the label is the accessible name, and a second one |
| +// from the icon would only be read out twice. An icon used as the ONLY label |
| +// must not use these constants bare: give its button or link an aria-label. |
| +package console |
| + |
| +import "html/template" |
| + |
| +// template.HTML is used HERE AND ONLY HERE in the console, and this is why it |
| +// is safe here and nowhere else: every string in this file is a compile-time |
| +// constant of our own markup. No user input, no bucket object, no registry |
| +// row, nothing derived from a request is ever concatenated into one. Anything |
| +// from those sources must stay a plain string so html/template escapes it — |
| +// a review in this repo has already flagged template.HTML on bucket-derived |
| +// text as a Critical finding, and that judgement stands. |
| +const ( |
| + // iconOpen is the shared opening tag: no width or height, so the icon |
| + // sizes from the CSS .icon rule (1em) and tracks the text beside it. |
| + iconOpen = `<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" ` + |
| + `stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">` |
| + |
| + // The account switcher's disclosure caret (Lucide: chevron-down). |
| + iconChevronDown template.HTML = iconOpen + `<path d="m6 9 6 6 6-6"/></svg>` |
| + |
| + // The switcher menu's mark on the account you are currently in |
| + // (Lucide: check). |
| + iconCheck template.HTML = iconOpen + `<path d="M20 6 9 17l-5-5"/></svg>` |
| + |
| + // "New account", in the same column the check sits in (Lucide: plus). |
| + iconPlus template.HTML = iconOpen + `<path d="M5 12h14"/><path d="M12 5v14"/></svg>` |
| +) |
| + |
| +// icons maps each Lucide slug to its vendored markup. Slugs are the Lucide |
| +// names so the mapping back to lucide.dev stays obvious. |
| +var icons = map[string]template.HTML{ |
| + "chevron-down": iconChevronDown, |
| + "check": iconCheck, |
| + "plus": iconPlus, |
| +} |
| + |
| +// icon renders one chrome icon by its Lucide slug: {{icon "chevron-down"}}. |
| +// An unknown slug renders nothing rather than panicking a page mid-response — |
| +// a typo must cost a missing caret, not a 500. TestTemplateIconSlugsAllExist |
| +// is what actually catches the typo, at test time. |
| +func icon(slug string) template.HTML { return icons[slug] } |