ZDDC/shared/icons.js
2026-06-11 13:32:31 -05:00

168 lines
9.1 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// shared/icons.js — minimal outline SVG sprite for ZDDC tools.
//
// Vendored from Lucide (https://lucide.dev, ISC). Only the 16
// file-type glyphs the browse tree maps to are bundled; total weight
// is ~4.5 KB of SVG path data. Each symbol viewBox is 0 0 24 24 with
// no stroke/fill attributes — those are applied at the call site via
// CSS so the icons inherit `currentColor` and tint with the theme.
//
// API:
// window.zddc.icons.inject() // mount sprite into <body> once
// window.zddc.icons.html('icon-foo') // → '<svg viewBox="0 0 24 24"><use href="#icon-foo"/></svg>'
// window.zddc.icons.ID // string set of valid symbol ids
//
// Callers concat html() output into innerHTML the same way they
// previously concat'd emoji glyphs. The injected sprite is hidden
// (`display:none` on the outer <svg>) so it costs zero layout.
//
// Why a sprite (rather than per-row inline paths): a hundred tree
// rows × 300 bytes of duplicated path data is 30 KB of churn on
// every re-render. With <use>, each row carries only a ~60-byte
// reference. The sprite is parsed once.
(function () {
'use strict';
if (!window.zddc) window.zddc = {};
if (window.zddc.icons) return;
// ── Sprite (Lucide outline glyphs, viewBox 24×24) ──────────────────────
// Concatenated from upstream lucide-static@1.16.0 SVGs; class/style
// attributes stripped. Order matches the icons-mapped block below
// so a diff against Lucide's source stays readable.
var SYMBOLS = ''
+ '<symbol id="icon-folder" viewBox="0 0 24 24">'
+ '<path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z"/>'
+ '</symbol>'
+ '<symbol id="icon-folder-archive" viewBox="0 0 24 24">'
+ '<circle cx="15" cy="19" r="2"/>'
+ '<path d="M20.9 19.8A2 2 0 0 0 22 18V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2h5.1"/>'
+ '<path d="M15 11v-1"/>'
+ '<path d="M15 17v-2"/>'
+ '</symbol>'
+ '<symbol id="icon-file" viewBox="0 0 24 24">'
+ '<path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"/>'
+ '<path d="M14 2v5a1 1 0 0 0 1 1h5"/>'
+ '</symbol>'
+ '<symbol id="icon-file-text" viewBox="0 0 24 24">'
+ '<path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"/>'
+ '<path d="M14 2v5a1 1 0 0 0 1 1h5"/>'
+ '<path d="M10 9H8"/><path d="M16 13H8"/><path d="M16 17H8"/>'
+ '</symbol>'
+ '<symbol id="icon-file-image" viewBox="0 0 24 24">'
+ '<path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"/>'
+ '<path d="M14 2v5a1 1 0 0 0 1 1h5"/>'
+ '<circle cx="10" cy="12" r="2"/>'
+ '<path d="m20 17-1.296-1.296a2.41 2.41 0 0 0-3.408 0L9 22"/>'
+ '</symbol>'
+ '<symbol id="icon-file-video" viewBox="0 0 24 24">'
+ '<path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"/>'
+ '<path d="M14 2v5a1 1 0 0 0 1 1h5"/>'
+ '<path d="M15.033 13.44a.647.647 0 0 1 0 1.12l-4.065 2.352a.645.645 0 0 1-.968-.56v-4.704a.645.645 0 0 1 .967-.56z"/>'
+ '</symbol>'
+ '<symbol id="icon-file-audio" viewBox="0 0 24 24">'
+ '<path d="M4 6.835V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.706.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2h-.343"/>'
+ '<path d="M14 2v5a1 1 0 0 0 1 1h5"/>'
+ '<path d="M2 19a2 2 0 0 1 4 0v1a2 2 0 0 1-4 0v-4a6 6 0 0 1 12 0v4a2 2 0 0 1-4 0v-1a2 2 0 0 1 4 0"/>'
+ '</symbol>'
+ '<symbol id="icon-file-archive" viewBox="0 0 24 24">'
+ '<path d="M13.659 22H18a2 2 0 0 0 2-2V8a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 14 2H6a2 2 0 0 0-2 2v11.5"/>'
+ '<path d="M14 2v5a1 1 0 0 0 1 1h5"/>'
+ '<path d="M8 12v-1"/><path d="M8 18v-2"/><path d="M8 7V6"/>'
+ '<circle cx="8" cy="20" r="2"/>'
+ '</symbol>'
+ '<symbol id="icon-file-spreadsheet" viewBox="0 0 24 24">'
+ '<path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"/>'
+ '<path d="M14 2v5a1 1 0 0 0 1 1h5"/>'
+ '<path d="M8 13h2"/><path d="M14 13h2"/><path d="M8 17h2"/><path d="M14 17h2"/>'
+ '</symbol>'
+ '<symbol id="icon-file-code" viewBox="0 0 24 24">'
+ '<path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"/>'
+ '<path d="M14 2v5a1 1 0 0 0 1 1h5"/>'
+ '<path d="M10 12.5 8 15l2 2.5"/>'
+ '<path d="m14 12.5 2 2.5-2 2.5"/>'
+ '</symbol>'
+ '<symbol id="icon-file-cog" viewBox="0 0 24 24">'
+ '<path d="M15 8a1 1 0 0 1-1-1V2a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8z"/>'
+ '<path d="M20 8v12a2 2 0 0 1-2 2h-4.182"/>'
+ '<path d="m3.305 19.53.923-.382"/>'
+ '<path d="M4 10.592V4a2 2 0 0 1 2-2h8"/>'
+ '<path d="m4.228 16.852-.924-.383"/>'
+ '<path d="m5.852 15.228-.383-.923"/>'
+ '<path d="m5.852 20.772-.383.924"/>'
+ '<path d="m8.148 15.228.383-.923"/>'
+ '<path d="m8.53 21.696-.382-.924"/>'
+ '<path d="m9.773 16.852.922-.383"/>'
+ '<path d="m9.773 19.148.922.383"/>'
+ '<circle cx="7" cy="18" r="3"/>'
+ '</symbol>'
+ '<symbol id="icon-file-pen" viewBox="0 0 24 24">'
+ '<path d="M12.659 22H18a2 2 0 0 0 2-2V8a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 14 2H6a2 2 0 0 0-2 2v9.34"/>'
+ '<path d="M14 2v5a1 1 0 0 0 1 1h5"/>'
+ '<path d="M10.378 12.622a1 1 0 0 1 3 3.003L8.36 20.637a2 2 0 0 1-.854.506l-2.867.837a.5.5 0 0 1-.62-.62l.836-2.869a2 2 0 0 1 .506-.853z"/>'
+ '</symbol>'
+ '<symbol id="icon-book-marked" viewBox="0 0 24 24">'
+ '<path d="M10 2v8l3-3 3 3V2"/>'
+ '<path d="M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H19a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H6.5a1 1 0 0 1 0-5H20"/>'
+ '</symbol>'
+ '<symbol id="icon-presentation" viewBox="0 0 24 24">'
+ '<path d="M2 3h20"/>'
+ '<path d="M21 3v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V3"/>'
+ '<path d="m7 21 5-5 5 5"/>'
+ '</symbol>'
+ '<symbol id="icon-ruler" viewBox="0 0 24 24">'
+ '<path d="M21.3 15.3a2.4 2.4 0 0 1 0 3.4l-2.6 2.6a2.4 2.4 0 0 1-3.4 0L2.7 8.7a2.41 2.41 0 0 1 0-3.4l2.6-2.6a2.41 2.41 0 0 1 3.4 0Z"/>'
+ '<path d="m14.5 12.5 2-2"/>'
+ '<path d="m11.5 9.5 2-2"/>'
+ '<path d="m8.5 6.5 2-2"/>'
+ '<path d="m17.5 15.5 2-2"/>'
+ '</symbol>'
+ '<symbol id="icon-globe" viewBox="0 0 24 24">'
+ '<circle cx="12" cy="12" r="10"/>'
+ '<path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/>'
+ '<path d="M2 12h20"/>'
+ '</symbol>'
// Lightweight outline chevron — used by the tree as the
// expand/collapse affordance. The single glyph rotates 90°
// via CSS to indicate the expanded state, so we only ship
// one path instead of two.
+ '<symbol id="icon-chevron-right" viewBox="0 0 24 24">'
+ '<path d="m9 18 6-6-6-6"/>'
+ '</symbol>'
// Horizontal three-dot "kebab" — the per-row actions affordance.
+ '<symbol id="icon-ellipsis" viewBox="0 0 24 24">'
+ '<circle cx="12" cy="12" r="1"/>'
+ '<circle cx="19" cy="12" r="1"/>'
+ '<circle cx="5" cy="12" r="1"/>'
+ '</symbol>';
var injected = false;
function inject() {
if (injected) return;
// insertAdjacentHTML on body parses the SVG namespace correctly
// across all modern browsers (innerHTML on a <div> wrapper has
// historically tripped over <symbol> in some engines).
var sprite = '<svg xmlns="http://www.w3.org/2000/svg" '
+ 'aria-hidden="true" style="position:absolute;width:0;height:0;'
+ 'overflow:hidden" focusable="false">'
+ SYMBOLS
+ '</svg>';
if (document.body) {
document.body.insertAdjacentHTML('afterbegin', sprite);
injected = true;
} else {
document.addEventListener('DOMContentLoaded', inject, { once: true });
}
}
// Produces the per-row markup callers concat into innerHTML.
// Bundles the size + stroke defaults inline so the SVG renders
// correctly even before the page CSS runs (e.g. mid-paint).
function html(symbolId) {
return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" '
+ 'stroke-width="2" stroke-linecap="round" stroke-linejoin="round" '
+ 'aria-hidden="true"><use href="#' + symbolId + '"/></svg>';
}
window.zddc.icons = { inject: inject, html: html };
})();