/**
* actionIcons β menu/toolbar ACTION key β inline SVG icon mapping.
*
* The sibling of `lib/fileIcons.ts`, for the other half of the problem: that
* module draws what a row IS (a folder, a sheet, an archive), this one draws
* what a row DOES (open, rename, move to trash).
*
* Why it exists: the action rows used to carry emoji (`β π β¬ π β¦`). Emoji are
* not one icon set β they are a dozen sets, rendered by whatever font the OS
* happens to ship, at whatever weight and colour that font's designer chose.
* Two rows of the same menu could come out flat-grey and full-colour, one
* hairline and one bold, and none of them matched the file glyphs drawn four
* pixels to the left. A stroked set on `currentColor` gives the menu one voice
* and lets the row's own colour reach the icon β which is how the destructive
* entry, and only the destructive entry, comes out red.
*
* Conventions are `fileIcons.ts`'s, deliberately: static strings (so `v-html`
* is injecting markup this file wrote, never user input), one cache, 24Γ24
* viewBox, 1.6 stroke, round caps/joins, `currentColor`.
*
* Adding a key: draw it here. Nothing else has to change β the renderers ask
* for the icon by the action's own key, so a new action gets its icon the
* moment its glyph lands in GLYPHS, and an action with no glyph renders
* nothing (the caller falls back to whatever `icon` string it was handed, so
* an embedder's custom emoji still shows).
*/
/* Shared fragments β the arrow/tray pair reads as one family when download and
* upload sit two rows apart. */
const TRAY = '';
const EYE =
'' +
'';
const STAR_PATH =
'M12 3.6l2.6 5.3 5.85.85-4.23 4.12 1 5.83L12 16.97l-5.22 2.73 1-5.83L3.55 9.75l5.85-.85z';
/* The push-pin, shared by the two "keep on this device" states. */
const PIN =
'' +
'' +
'';
/* A window/panel with one edge split off β nav and inspector are the same
* shape mirrored, which is exactly what the two panels are. */
const PANEL = '';
/* The bin. `delete` moves a thing INTO it and `open-trash` opens it; those are
* two actions on one object, so they are one drawing (Drive and Finder draw
* them the same way too). */
const BIN =
'' +
'' +
'' +
'';
/* The ribbon a saved search hangs on β `bookmark` is the saved thing,
* `save-search` is the same ribbon with the "add" plus in it. */
const BOOKMARK =
'';
const GLYPHS: Record = {
/* ββ opening βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
open:
'' +
'' +
'',
'open-tab':
'' +
'' +
'',
preview: EYE,
download: TRAY + '',
upload:
'' +
'',
convert:
'' +
'',
/* "PaylaΕ / Δ°zinler" β the three-node share, not a chain link: this row
opens permissions as well as a link, and people are the subject. */
access:
'' +
'' +
'' +
'',
details:
'' +
'' +
'',
/* ββ identity / clipboard ββββββββββββββββββββββββββββββββββββββββββββββ */
'copy-id':
'' +
'' +
'' +
'',
/* A clipboard carrying a path separator β this copies the location, not the
thing that lives at it. */
'copy-path':
'' +
'' +
'',
rename: '',
cut:
'' +
'' +
'',
copy:
'' +
'',
paste:
'' +
'',
/* ββ metadata ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
/* star = "not starred yet, do it" (outline); unstar = the state you are in
(filled). The renderer picks between them by name, see FileExplorer. */
star: ``,
unstar: ``,
tags:
'' +
'',
/* ββ destructive / recovery ββββββββββββββββββββββββββββββββββββββββββββ */
delete: BIN,
'open-trash': BIN,
/* The undo arrow, not a rotating one: "Geri YΓΌkle" puts a thing back where
it was, and that is the gesture people already read as undo. */
restore: '',
/* ββ folder-level ββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
'new-folder':
'' +
'',
/* belge:n1 β a page with a plus: "make me a new document of some type".
Keyed by the action's own key, so the menu row carries no icon of its
own and no emoji enters the markup. */
'new-document':
'' +
'',
refresh: '',
/* ββ desktop sync ("keep on this device") ββββββββββββββββββββββββββββββ */
'keep-local': PIN,
'keep-online':
'',
/* Kept because a parent folder is kept β the pin, with the branch it came
down. The row is disabled; the glyph says why. */
'keep-inherited': PIN + '',
'keep-reveal':
'' +
'',
/* ββ view preferences ββββββββββββββββββββββββββββββββββββββββββββββββββ */
'toggle-hidden':
'' +
'' +
'' +
'',
density: '',
'view-list':
'' +
'',
'view-grid':
'' +
'' +
'' +
'',
'view-gallery':
'' +
'' +
'',
nav: PANEL + '',
inspector: PANEL + '',
/* ββ explorer settings βββββββββββββββββββββββββββββββββββββββββββββββββ */
'shortcut-settings':
'' +
'' +
'' +
'',
/* Light/dark as the thing it actually switches: one disc, half of it inked. */
theme:
'' +
'',
/* zaman:z3 β a clock face, for the Time zone row. */
timezone: '',
tour:
'' +
'',
/* "Dosya Δ°ste" β the public drop link. A chain, because what this makes is
a URL to hand somebody. */
'request-files':
'' +
'',
/* ββ toolbar chrome that is not a ContextAction ββββββββββββββββββββββββ */
'go-up': '',
/* === gorunum:v2-topbar β the breadcrumb row's own controls ============
The crumb trail gained the reference shell's three affordances: a home
crumb in place of the bare "/" root, a chevron on the last crumb that
lists what is inside it, and the path editor we already had (its glyph
moves here from Breadcrumb.vue so every mark in the row comes from one
file). */
home:
'' +
'' +
'',
subfolders: '',
'edit-path': '',
/* === gorunum:v2-topbar β the header's trailing cluster ================
The page chrome around the explorer is gone, so the account-level doors
are drawn by the header itself (the host fills them through the
`header-actions` slot). The glyphs live here so an embedder's cluster
comes out the same weight and colour as everything beside it. */
admin:
'' +
'' +
'' +
'',
/* β A PERSON, not a cog. The first draft drew the gear as a ringed disc with
eight spokes and at 16px it came out as a SUN β sitting in the very row
the light/dark toggle had just been removed from, which is the one thing
the mark must not be mistaken for (measured at 1440 and 390: it read as a
theme switch in both). The account bust is what the reference hangs this
menu on, and the tooltip says which settings. */
account: '',
'sign-out':
'' +
'' +
'',
/* The AI assistant, drawn but not yet wired β a spark, the mark every
assistant in this class of product wears, so the day it does something
the icon does not have to change under people's fingers. */
ai:
'' +
'',
/* The notification bell, for the host's header cluster (web/src
NotificationBell.vue). β Drawn HERE, not taken from the app's icon
library: it sits in the same row as refresh, the spark and the avatar,
and a glyph at a foreign stroke weight in that row is the exact mismatch
this set exists to prevent. A dome on a flared rim, the clapper below. */
bell:
'' +
'',
/* === /gorunum:v2-topbar === */
search: '',
/* gorunum:v1-advsearch β sliders, not a funnel. A funnel says "throw rows
away"; this control opens a dialog where you SET things, and two of its
three rows are exactly a slider's job (a size range, a time window). */
filter:
'' +
'',
more:
'' +
'' +
'',
close: '',
/* A share link. Two half-chains, which is what a link IS. The details
panel's "Not shared / Create link" row used to draw a chain EMOJI
there, i.e. whatever glyph the OS happened to ship, full-colour,
beside a column of stroked grey ones. */
link:
'' +
'',
/* === ikon:emoji β the command palette's own rows =======================
* The palette printed `{{ it.icon }}` as TEXT: `β π β¬ β¦ π β³ β π¨ β¨ π β§ β«
* πΎ π`. Thirteen marks from four different type families, in a list whose
* neighbours β the context menu it duplicates and the toolbar it launches β
* had already moved here. Most of the keys it needed were drawn already
* (`tour` is the mortarboard, `shortcut-settings` the keyboard, the three
* `view-*` the mode chips); these six are what was genuinely missing. */
/* "Go to path" β the arrow goes INTO the box, the mirror of `sign-out`.
A bare arrow would have said "next", which this row is not. */
goto:
'' +
'' +
'',
/* A second pane opened beside the first β `nav`/`inspector`'s panel with the
divider down the middle, because that is literally what split view is. */
split: PANEL + '',
/* A new tab: `open-tab`'s window, with the plus in the body rather than on
the tab strip (at 16px a plus up there merges into the tab). */
'tab-new':
'' +
'' +
'' +
'',
bookmark: BOOKMARK,
'save-search': BOOKMARK + '',
/* The padlock, for the rows and strips that talk ABOUT encryption ("create
an encrypted folder", "this one is unlocked"). The listing marker is a
different drawing on purpose β there the lock is cut out of the folder,
because the row still has to read as a folder. */
lock:
'' +
'' +
'',
/* === ikon:emoji β states the viewers and modals report ================
* `β β β οΈ β³` in the viewer chrome. The first two are typographic and came
* out at whatever weight the UI font had; the last two are colour emoji, so
* a fallback screen's 48px mark was the only full-colour thing on a grey
* page. `progress` is drawn as an open ring because it is SPUN by CSS
* (`@keyframes fe-spin`) β an hourglass cannot say "still going". */
check: '',
alert:
'' +
'' +
'',
progress: '',
};
const SVG_CACHE = new Map();
/**
* Inline SVG markup for an action key, or `''` when nothing is drawn for it.
*
* The empty string is a contract, not a failure: the caller renders nothing
* (or falls back to the `icon` string an embedder supplied) rather than a
* placeholder box, so an unknown key costs a gap and never a broken glyph.
*/
export function actionIconSvg(key: string): string {
if (!key) return '';
const cached = SVG_CACHE.get(key);
if (cached !== undefined) return cached;
const glyph = GLYPHS[key];
const svg = glyph
? '`
: '';
SVG_CACHE.set(key, svg);
return svg;
}
/** Every key this module draws β handy for tests and for a gallery page. */
export function actionIconKeys(): string[] {
return Object.keys(GLYPHS);
}