@ai-ecoverse/slicc-spectrum 1.73.2 → 1.74.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/slicc-ui.js +242 -84
- package/dist/slicc-ui.js.map +3 -3
- package/dist/types/app/agents.d.ts +2 -0
- package/dist/types/app/sprinkle.d.ts +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -136,7 +136,7 @@ Text is Adobe Clean Spectrum VF, falling back to Adobe Clean, and code is Spectr
|
|
|
136
136
|
| :--- | :--- |
|
|
137
137
|
| `<slicc-app>` | The shell: header with the agent picker, status items, the update status, the network indicator, the tray, the View menu and the theme switch, rails, and a `<slicc-dock>`. Saves the dock layout per screen class to `storage` (default `localStorage`) under `layoutKey`. While connected it sets `overscroll-behavior` to `none !important` on the page's `html` and `body`, so only scroll areas inside panels rubber-band. It sets the page's `color-scheme` to its resolved theme, and when the page has a `theme-color` meta per `prefers-color-scheme`, gives every one of them the content of the meta for that theme, so the page and the installed app's title bar follow the app's setting instead of the OS. When the last app on the page is removed, the page's own inline values and `theme-color` contents come back. With a `follow` port, the header shows a `<slicc-follow>` chip, and while the follower connects, waits to be allowed, is unlinked or fails, a `<slicc-follow page>` (`.alone[data-follow]` with the page kind) takes the place of the panels; without Terminal access, the terminal surface and New terminal aren't offered, and open terminals close when it's taken away. |
|
|
138
138
|
| `<slicc-dock>` | Generic. [dockview-core](https://dockview.dev/) 8 with a theme mapped to Spectrum tokens, in its own shadow root. Panels come from `factories` (`name → (params) => HTMLElement`). `open`, `close`, `has`, `content`, `focusPanel`, `cycleGroup`, `cycleTab`, `toJSON`, `restore`, `clear`, and the full `api`. Tabs have a context menu (close, close others, float, maximize). Events: `layout-change`, `active-panel-change`, `panel-close`. |
|
|
139
|
-
| `<slicc-agents>` |
|
|
139
|
+
| `<slicc-agents>` | A tree (`role="tree"`) of cones, with their scoops hidden under them. A row's first line starts with one circle: its unread count when there are unread messages (`9+` from ten up, white on the accent fill), otherwise a dot coloured by status. Then comes the name; the context fill, when it's high, sits in the top right corner. Every row has up to two lines starting with its status in words (`.state`, such as "Working"), then its conversation title, so the status stays visible when the unread count takes the circle; the accessible name says the status and the exact unread count too. A cone's row also has a ribbon along its bottom with one fixed-width segment per scoop, coloured by status; it's `aria-hidden`, and the cone's `aria-description` sums it up, as in "2 scoops: 1 working, 1 idle". On hover, on keyboard focus of the row, or when <kbd>Tab</kbd> from the selected row reaches its drop or delete button, a strip the full height of the row's right edge holds that button over the text; the context fill stays on top of it, and it hides again once a pointer that clicked it leaves. A click, <kbd>Enter</kbd> or <kbd>Space</kbd> on a cone expands or collapses it, as do <kbd>→</kbd> and <kbd>←</kbd> (<kbd>→</kbd> on an expanded cone moves to its first scoop, <kbd>←</kbd> on a scoop to its cone); only the focused cone is expanded, and its scoops list below it. A cone with scoops carries `aria-expanded`, and `aria-controls` names its scoop rows while they show. Expanding and collapsing have no motion. **New cone** sits at the bottom. The conversation title is also shown in the header's cone picker: `Agent.title`, or else the first line of the first user message, or "No messages yet". When cones share a name, their accessible names and the Delete cone, Freezer and confirmation labels add the title, as in "Delete cone sliccy (Hello from Bedrock)". Selecting one makes it the active agent. |
|
|
140
140
|
| `<slicc-chat>` | One thread's conversation (its `agent`, or the active agent if unset), by day. A message's time shows only when it is at least two minutes newer than the last time shown, and the first one after each day separator always shows; a hidden time stays for screen readers (`time.sr` with `datetime`, or `.sr` on licks and cards), and a meta row left empty isn't rendered. User messages (with attachments and a quiet timestamp, `time.when`, by that rule; the reader's own carry no name or delivery tag, while `data-mode` and `data-delivered` still say how they went; a message from another cone, a follower or a guest says who sent it, and an agent's request carries its name and an Agent badge; a message from another agent, an agent's request or a message `from` a cone (`origin` `agent`, or `from` set without `origin` `follower` or `guest`), is `[data-remote]`: a subtle indigo bubble and a 🤖 pill on its bottom edge, `aria-hidden` since the byline names the sender; people, the reader included, never get it), assistant messages (with the time by that rule, and the model only on the first reply and whenever it changes from the previous one, `.meta .model` with the usage as its tooltip; without a model the usage is the time's tooltip, and with neither it is the reply's own (`.reply[title]`); the turn always carries the usage as its `aria-description`; the cone's name isn't repeated; Markdown with tables, task lists, quotes, code and images; thinking; tool runs, one icon per run (`<slicc-tool-runs>`): three or more runs in a row form a cluster, a strip of icon buttons (`data-action="open-run"`, `data-target` the call's id, named by its `title` and status, `aria-expanded`) that each open one run's card below it, and on the right the model's label for the run, a button (`data-action="open-cluster"`, `aria-expanded`, named "Show all runs" while it has no text) that opens every card; the strip's tooltip and the group's accessible name sum it up, such as "3 commands, 1 read. Done"; prose breaks a run, hidden thinking and source links don't, and a standalone tool message or a done reply with only tool calls continues the run before it on the same day, its `data-id` moving onto its first card (`.tool[data-id]`); a single run is a strip of one, its icon and its `title` as the label, which opens with <kbd>Enter</kbd> or <kbd>Space</kbd> like the strip's buttons. A strip and its cards share one width, the column less a wide margin on each side, so they read as centred, and their edges line up. Icons fill from the start of a space kept for five, so a run that grows doesn't move its strip or its label; past five, the strip shows the newest five and scrolls back to the older ones, with <kbd>Tab</kbd> or a swipe, and returns to the newest when a run is added or the strip comes back into view. The label sits at the end and is cut with an ellipsis before it reaches that space. Under 480 px of column width the label takes a row of its own under the icons, which then show as many whole icons as fit. A cluster's label comes from the agent port's optional `toolLabel(agentId, callIds)`, asked once for each agent port, agent and set of runs; while a growing run waits for its new label, it keeps its last one, and without `toolLabel` the label is empty. A command's icon is the favicon of the site it names when an open browser tab already has a `data:` favicon for it (nothing is fetched; otherwise the globe), else the file browser's icon for the file it names, else the code icon; other tools show their kind's icon. A running run pulses (still, with a dashed ring, under `prefers-reduced-motion`), a done or cancelled one is grey and a failed one red, each with a corner glyph. The card (`.tool[data-tool][data-status][data-kind]`, a `details.run` under a pill and a `div[role=region]` named by its `title` and status under a strip) has no header of its own, no chevron, title, tool name or status: its input (a shell command after `$`), an edit's `diff` shown as a diff view, its output wrapped rather than cut off, an `image`, such as a screenshot, an optional `meta` such as a timeout, a standalone tool message's time ("Ran at 16:12", `.ran`, by the two-minute rule), and its `notes` (`{ severity, text }`, such as "Exited with code 5" or "Full output in /tmp/…") as lines under the output, `li[data-note][data-severity]`: `error` with an alert icon in the negative colour, `warn` with an alert icon and `info` with an info icon, both subdued; media galleries with images, video and audio; action cards for tools, pull requests and status; plans and checklists; inline diffs; question prompts; delegations; link previews; errors with a fix-it action, as a grey card (`.error-card[role=alert]`, `data-id` on system errors) inset by a wide margin on each side, a narrower one under 480 px: a red alert icon, the title in bold, the detail subdued and the action on the right, or under the detail below 360 px, announced as "Error: " and the title; a content-filter stop offers **Drop the last turn**, which rewinds that turn and puts its prompt back into the composer; when the turns right before it failed too, the button reads **Drop N failed turns** and rewinds to before the first of them, putting the latest prompt back), system messages (error cards; compactions and notices, rewinds and model changes included, as full-width dividers with a line on each side, like the day: a compaction shows only its title, its `text` kept for screen readers, one that lost messages (`state: 'fallback'`, by default "Compaction failed, transcript truncated", or `discarded`, "Context discarded") an alert icon in the negative colour, and a notice its title and text on one line, `role="note"`; a divider that wraps keeps a short line on each side) and licks, SLICC's events into a cone, on every channel, with their time by the two-minute rule; a lick's `severity` (`warn` or `error`) turns its channel badge into a notice or negative one with an alert icon. Permission requests are allowed or denied in place. The header is one row: the status, a model picker that names each model's provider and leaves out classifiers and models with `tools: false` (with no model on offer, **Set up a model**, `data-action="set-up-model"`, opens Settings), the thinking picker, the context meter and **New conversation**, which calls `clear` and puts focus back in the composer; on a cone, when the port can freeze, its tooltip says the old conversation stays in the Freezer. It never wraps: when it's short of room, the model picker's label is cut with an ellipsis, and under 560px wide (`header[data-compact]`) New conversation is icon-only, with `accessible-label` and its tooltip. The pickers re-read `models()` on `settings`, `accounts` and `agents`. When a live agent's model, or `Settings.model`, is no longer offered and its provider (the id before `/`) isn't a connected account, it moves to the offered chat model with `default: true`, else the first one; frozen agents are left alone, and so is everything on a follower unless it has Control and is connected. The chat re-runs this on `follow` too, and `<slicc-app>` does it as well, when it binds, on those events and on `follow`, so a new cone that starts on a provider that isn't set up moves at once. The transcript pads its end, and its `scroll-padding-block-end`, by the composer's measured height, so at the bottom the last message sits above the composer and a focused element scrolls clear of it. While a reply streams, its status icon follows what it is doing: a pencil for an edit, a page for a read, a magnifier for a search, an eye for the browser and an hourglass for any other tool; thinking and text keep the AI logo. Between the header and the transcript, a `<slicc-notices>` shows the model's notices. On a follower without Control, a note (`p[data-follow="watch"]`) takes the composer's place, the header shows the model's name instead of the pickers and New conversation, and there's no suggested follow-up. |
|
|
141
141
|
| `<slicc-notices>` | The model's `notices` as in-line alerts with their actions and a close button, after a banner from the `tabs` port when another tab is paused or runs a different SLICC, and a warning for each waiting approval when the `approvals` port has no `decide` (`[data-approval-notice]`); renders nothing without any. |
|
|
142
142
|
| `<slicc-approvals>` | The model's waiting `approvals` as a modal alert dialog, one at a time, oldest first; `<slicc-app>` mounts it. Renders nothing without `approvals.decide`. A request that `secretRules()` flags shows a warning (`[data-secret-rules]`, the path or token) and no **Always allow (**Always allow in this directory**, with the cwd in its hint, when the approval has `alwaysScope: 'cwd'` and a `cwd`)**. Focus starts on Deny and goes back, after Deny, Always allow, Allow once, <kbd>Esc</kbd> or Close, to what had it when the dialog opened; inside a terminal, to that `<slicc-terminal>` through its own `focus()`, even when it remounted meanwhile. |
|
|
@@ -156,7 +156,7 @@ Text is Adobe Clean Spectrum VF, falling back to Adobe Clean, and code is Spectr
|
|
|
156
156
|
| `<slicc-memory>` | What agents remember, grouped by section: search, filter by scope and tag, expand, edit, add and forget. The scope picker starts on **Everyone** (`*`), which lists every memory with its scope on it (`.scope[data-scope]`); `global` reads **Shared** whatever the port calls it, and the cones and roles follow. The count (“N of M memories”) counts the memories in the picked scope. With a search or tag filter that hides everything it says “No memories match.”, otherwise “No memories yet.”, “No shared memories yet.” or “No memories for {scope} yet.” Each memory is a row (`li.row[data-id]`) that opens in place: open rows (`data-open`) take the accent's subtle background and turn their chevron down, and show the body with **Edit** and **Forget** (`data-action="edit"`, `data-action="forget"`). Under the summary, the tag is a subtle badge (`swc-badge[data-tag]`: User indigo, Feedback purple, Project seafoam), then the scope and, for free text outside an entry, “From MEMORY.md” (`.from`). Below 560 px of panel width, the search takes its own line over the two pickers. The search field is the shared one from `search.ts` (`sp-search[data-action=search]`), as in Files. |
|
|
157
157
|
| `<slicc-monitor>` | The live monitor: vitals (`.vital[data-id]`), each a meter when it has a `ratio` (budget, fullest context) and otherwise a value, its unit and delta on one line and a sparkline from its `series` (spend, active agents, processes, process memory). Each card keeps its place whatever it shows: the value line never wraps (a unit or delta that doesn't fit is left out whole rather than cut, and stays in the line's `title` and its text; a vital's optional `hint` replaces that tooltip, such as the exact reset time behind "resets in 4 days"), a card without a `series` keeps the sparkline's room, a meter keeps its description's line, and a card left alone on the last row spans it, so short and long values, 0% and 100%, and missing data move nothing below them. Then alerts (an alert's optional `command` shows after its detail, led by its `commandLabel` or "Run", as unwrapped code with **Copy**, `[data-command]` and `data-action="copy-command"`), and the sections (the agent's Tasks, Processes and Recent problems, then terminals, tabs, pending changes and tray followers; cones and sprinkles have their own panels; any other section an agent sends, such as an older agent's `agents` or `sprinkles`, renders the same way). Each section (`li.section[data-id]`) shows its count and an attention badge, and opens its surface with **Open** where one exists; the counts line up in one column whether or not a section has **Open**, and a section without rows keeps its name in line with the others (`agents`, `terminals` and `processes` → terminal, `tabs`, `changes`). A section with rows expands into them with its toggle (`.toggle`, `aria-expanded`; `data-open` on the section): collapsed by default, expanded while a row is `warn` or `error`, until the user toggles it. Each row (`li.row[data-status]`, `data-id` from the row's `id`) shows a status light (blue active, gray idle, orange warn, red error, with the status spoken), the name, the meta line and its badges, indented by `depth` (`data-depth`, up to 6). |
|
|
158
158
|
| `<slicc-freezer>` | Every conversation in the session, from `frozen()`: cones, scoops and agent runs, each with a kind badge, live ones first with a Live light, then the newest first. A live row offers **Open**, which selects that agent; a stopped one offers **Thaw** and **Remove**, which deletes its working folders after a confirmation. A thawed scoop or agent run keeps its row, which says what it was thawed as. **Delete cone**, in the agents list (or <kbd>Delete</kbd> on a cone's row) and the header's cone picker, stops a cone after a confirmation; `/freeze` does it at once. Either way its conversation stays here, and a row without a `kind` counts as a cone. |
|
|
159
|
-
| `<slicc-sprinkle>` | A SLICC sprinkle (`.shtml`), as a panel or, with `inline`, as a dip in the chat that grows to fit. A dip has a tab-like handle: drag it into the dock (or onto a rail, or use its open-as-panel button) and it lives on as a sprinkle panel, with a note in the chat where it was; which dips are out is saved in `slicc-ui.dips`. It runs in a sandboxed frame (`allow-scripts` only) with SLICC's sprinkle theme (the `--s2-*` tokens and `.sprinkle-*` classes), the app's fonts, and Lucide icons (`<i data-lucide>`, `LucideIcons.render()`). It talks back through `slicc.lick({ action, data })`, which reaches the owning cone as a `sprinkle` lick, and, when the port has `call`, reads files and keeps state (see [Sprinkle bridge](#sprinkle-bridge)). Panel sprinkles sit at the top of the right rail with their Lucide icon. |
|
|
159
|
+
| `<slicc-sprinkle>` | A SLICC sprinkle (`.shtml`), as a panel or, with `inline`, as a dip in the chat that grows to fit, even when it loads out of view (the frame measures itself on load, after icons and fonts arrive, and on every resize). A dip has a tab-like handle: drag it into the dock (or onto a rail, or use its open-as-panel button) and it lives on as a sprinkle panel, with a note in the chat where it was; which dips are out is saved in `slicc-ui.dips`. It runs in a sandboxed frame (`allow-scripts` only) with SLICC's sprinkle theme (the `--s2-*` tokens and `.sprinkle-*` classes), the app's fonts, and Lucide icons (`<i data-lucide>`, `LucideIcons.render()`). It talks back through `slicc.lick({ action, data })`, which reaches the owning cone as a `sprinkle` lick, and, when the port has `call`, reads files and keeps state (see [Sprinkle bridge](#sprinkle-bridge)). Panel sprinkles sit at the top of the right rail with their Lucide icon. |
|
|
160
160
|
| `<slicc-network>` | Network: the route and its health in plain words with the bios `detail`, a line on browser automation (`data-browser`: through the SLICC extension, through slicc on this computer (`proxy`, or a linked device on this computer), through a linked device's browser, that slicc on this computer has no browser to control when it carries the traffic and `via` is `null`, or not available with how to get it) when the status has `browser`, **Check again** (`data-action="check"`) when the port has `check`, an **Internet traffic** picker (`data-action="exit"`, in `[data-exit-picker]` with the exit's kind) when the port has `setExit`, the route line saying where traffic goes, and under the picker a warning that traffic waits while the chosen device isn't connected (`data-exit="device"`, `data-held`, with **Send directly**, `data-action="exit-direct"`, which calls `setExit(null)`) or, when `route` isn't `tailnet`, the Tailscale exit node in use (`data-exit="node"`), a **Tailscale** section (`data-tailnet` with the state) when the status has `tailnet`, a **Linked devices** section (`data-links`: `linked`, `connecting`, `reconnecting`, `offline`, `none` or `permission`; each device row has a **Prompting** or **Watching** badge, `data-controlling`, while it controls the agent, and **Allow remote control**, `sp-switch[data-action="remote-control"]`, behind a confirm when turned on, or `data-control="fixed"` for a device on this computer; with `access`, an **Allow** group of **View**, **Control** and **Terminal** switches, `data-action="access-view"`, `access-control` and `access-terminal`, each confirmed when turned on, Terminal's saying it gives a root shell, and Control disabled while View is off; a device that asks to follow shows **Asks to follow** and **Allow**, `data-action="allow-follow"`; a **Terminal open** badge, `data-terminals`, counts its terminals; with `followUrl`, the join details add **Open on another device** with a QR code and the link, `data-join="follow"` and `data-copy="follow-url"`) when the status has `links`, **Get the whole web** with the Chrome extension link (`data-action="install-extension"`, when `extensionUrl` is set) and the commands to run slicc, each in a `.command[data-command]` block with a copy button: `curl -fsSL https://get.sliccy.ai/slicc | sh` (its button is `data-action="copy-command"`), `slicc`, and, with Node, `npx sliccy@next`; folded away when the route already reaches the whole web (`proxy`, `extension`, `link` or `tailnet`, whose line names `tailnet.exitNode`) or a linked device is the exit (`exit.kind` `link`: the route line says "Through slicc on this computer" for a `local` device, or names a remote device and its `policy`, or says it's waiting for it, and `data-route` is `link`, whatever `route` says), and recent failures with host, error and time. When the model has a `tray` port, a **Sync** section (`data-sync` with the connection) follows the connection: the tray's state, the float's name, role and runtime, the join link, masked (`…/join/••••••`) until **Show** (`data-action="reveal-tray-join"`, which turns into **Hide**), with **Copy** (`data-action="copy-tray-join"`), the followers (`li[data-follower]`), and **Disconnect** (`data-action="tray-disconnect"`, confirmed) or **Reconnect** (`data-action="tray-reconnect"`). When the status has `leaders`, a **Leaders** section (`section[data-leaders]` with the count) follows Sync, since it's the other direction of the same tray link: Sync is this SLICC's own tray and who follows it, Leaders the SLICCs it follows. Each leader is an `li[data-leader]` (the id) with `data-state`: its name, its hub as a quiet second line and a status light with the state in words (Connecting, Reconnecting, Connected, Disconnected, Failed, Unlinked); `failed` adds its `error` as plain text (`[data-leader-error]`, "Couldn’t reach its hub." without one) and **Retry** (`data-action="retry-leader"`), and `unlinked` says "{name} stopped sharing with this SLICC." (`[data-unlinked]`) without actions. **Disconnect** (`data-action="disconnect-leader"`) runs at once, without a confirm, since it's reversible: the row stays as Disconnected (a neutral light), with **Reconnect** (`data-action="reconnect-leader"`) and **Forget** and no Disconnect or Retry. **Forget** (`data-action="forget-leader"`) asks "Forget {name}?" ("To follow it again, you’ll need a new invite from it.") with a negative confirm, and the row goes. Each shows only when the port has its method; while one runs, the row's buttons are disabled, and a failure shows in the row (`data-error="leader"`). The header's **Network** indicator (`data-network`, `data-health`) opens it: a status light, green for `ok`, yellow for `limited` and red for `failing`, with the state in its text and label and `detail` as its tooltip, which adds "Tailscale is connected." while the tailnet runs; on a phone, a cloud icon for the state. While a linked device asks to follow, controls the agent, watches it or has a terminal open, an indicator (`data-remote`, `ask`, `prompt`, `terminal` or `watch`) sits before it, **{name} asks to follow**, **Controlled by**, **Terminal open from** or **Watched by** the device's name (or the number of devices; in that order of precedence), says who does what in its tooltip and opens the panel too. Offered only when the model has a `network` port. |
|
|
161
161
|
| `<slicc-tray>` | The tray items in the header, each opening a panel when that panel is in `panels`: the connection (`#chip`, a status light with the float's name and followers, `data-surface="network"`) opens Network at its **Sync** section, and the budget (`#usage`, `data-surface="monitor"`) opens the Monitor. Without the panel an item is a plain status with its label. |
|
|
162
162
|
| `<slicc-confirm>` | The confirmation dialog `confirm()` opens. Not for direct use. |
|
package/dist/slicc-ui.js
CHANGED
|
@@ -10646,7 +10646,7 @@ function watchTitles(model, update) {
|
|
|
10646
10646
|
const seen = /* @__PURE__ */ new Map();
|
|
10647
10647
|
const check3 = (id) => {
|
|
10648
10648
|
const agent = model.agent.list().find((candidate) => candidate.id === id);
|
|
10649
|
-
if (agent
|
|
10649
|
+
if (!agent) return;
|
|
10650
10650
|
const title = agentTitle(model, agent);
|
|
10651
10651
|
if (seen.get(id) === title) return;
|
|
10652
10652
|
seen.set(id, title);
|
|
@@ -11406,11 +11406,25 @@ async function createCone(model, trigger2) {
|
|
|
11406
11406
|
if (created) port.select(created.id);
|
|
11407
11407
|
return created;
|
|
11408
11408
|
}
|
|
11409
|
+
var statusOrder = ["working", "thinking", "waiting", "error", "idle"];
|
|
11410
|
+
function scoopSummary(scoops) {
|
|
11411
|
+
if (scoops.length === 0) return "";
|
|
11412
|
+
const counts = statusOrder.map((status2) => [status2, scoops.filter((scoop) => scoop.status === status2).length]).filter(([, count]) => count > 0).map(([status2, count]) => `${count} ${statusLabel[status2].toLowerCase()}`);
|
|
11413
|
+
return `${scoops.length} scoop${scoops.length === 1 ? "" : "s"}: ${counts.join(", ")}`;
|
|
11414
|
+
}
|
|
11415
|
+
function unreadCount(unread) {
|
|
11416
|
+
return unread > 9 ? "9+" : String(unread);
|
|
11417
|
+
}
|
|
11409
11418
|
function fillShown(fill2) {
|
|
11410
11419
|
return fill2 >= 0.5;
|
|
11411
11420
|
}
|
|
11412
11421
|
var SliccAgents = class extends ModelElement {
|
|
11413
11422
|
static properties = { ...ModelElement.properties, errors: { state: true } };
|
|
11423
|
+
#expanded = null;
|
|
11424
|
+
#pointer = false;
|
|
11425
|
+
#modality = (event2) => {
|
|
11426
|
+
this.#pointer = event2.type === "pointerdown";
|
|
11427
|
+
};
|
|
11414
11428
|
constructor() {
|
|
11415
11429
|
super();
|
|
11416
11430
|
this.errors = {};
|
|
@@ -11419,16 +11433,22 @@ var SliccAgents = class extends ModelElement {
|
|
|
11419
11433
|
shared,
|
|
11420
11434
|
i`
|
|
11421
11435
|
:host {
|
|
11422
|
-
display:
|
|
11436
|
+
display: flex;
|
|
11437
|
+
flex-direction: column;
|
|
11423
11438
|
height: 100%;
|
|
11424
|
-
overflow
|
|
11439
|
+
overflow: hidden;
|
|
11425
11440
|
background: var(--swc-background-layer-1-color);
|
|
11426
11441
|
color: var(--swc-neutral-content-color-default);
|
|
11427
11442
|
font-size: var(--swc-font-size-100);
|
|
11428
11443
|
}
|
|
11444
|
+
.list {
|
|
11445
|
+
flex: 1;
|
|
11446
|
+
min-block-size: 0;
|
|
11447
|
+
overflow-y: auto;
|
|
11448
|
+
}
|
|
11429
11449
|
.actions {
|
|
11430
11450
|
display: flex;
|
|
11431
|
-
padding: var(--swc-spacing-75) var(--swc-spacing-100)
|
|
11451
|
+
padding: var(--swc-spacing-75) var(--swc-spacing-100);
|
|
11432
11452
|
}
|
|
11433
11453
|
ul {
|
|
11434
11454
|
list-style: none;
|
|
@@ -11436,31 +11456,67 @@ var SliccAgents = class extends ModelElement {
|
|
|
11436
11456
|
padding: var(--swc-spacing-75) 0;
|
|
11437
11457
|
}
|
|
11438
11458
|
li {
|
|
11459
|
+
--row-background: var(--swc-background-layer-1-color);
|
|
11460
|
+
--row-head: 1lh;
|
|
11461
|
+
--row-description: calc(2 * 1.4 * var(--swc-font-size-75));
|
|
11462
|
+
position: relative;
|
|
11439
11463
|
display: grid;
|
|
11440
|
-
grid-template-columns: minmax(0, 1fr) auto
|
|
11441
|
-
grid-template-areas: '
|
|
11464
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
11465
|
+
grid-template-areas: 'head fill' 'description description' 'ribbon ribbon' 'error error';
|
|
11466
|
+
grid-template-rows: var(--row-head) var(--row-description) var(--swc-spacing-100);
|
|
11442
11467
|
align-items: center;
|
|
11443
11468
|
column-gap: var(--swc-spacing-100);
|
|
11444
11469
|
padding: var(--swc-spacing-75) var(--swc-spacing-200);
|
|
11470
|
+
background: var(--row-background);
|
|
11445
11471
|
cursor: pointer;
|
|
11446
11472
|
}
|
|
11447
11473
|
li.scoop {
|
|
11448
|
-
grid-template-areas: 'name unread fill drop' 'status unread fill drop' 'error error error error';
|
|
11449
11474
|
padding-inline-start: calc(var(--swc-spacing-200) + var(--swc-spacing-300));
|
|
11450
11475
|
}
|
|
11451
11476
|
li:hover {
|
|
11452
|
-
background: var(--swc-gray-100);
|
|
11477
|
+
--row-background: var(--swc-gray-100);
|
|
11453
11478
|
}
|
|
11454
11479
|
li[aria-selected='true'] {
|
|
11455
|
-
background: var(--swc-gray-200);
|
|
11456
|
-
box-shadow: inset var(--swc-spacing-50) 0 0 var(--swc-accent-visual-color);
|
|
11480
|
+
--row-background: var(--swc-gray-200);
|
|
11457
11481
|
}
|
|
11458
11482
|
li:focus-visible {
|
|
11459
11483
|
outline: var(--swc-focus-indicator-thickness) solid var(--swc-focus-indicator-color);
|
|
11460
11484
|
outline-offset: calc(-1 * var(--swc-focus-indicator-thickness));
|
|
11461
11485
|
}
|
|
11486
|
+
.head {
|
|
11487
|
+
grid-area: head;
|
|
11488
|
+
display: flex;
|
|
11489
|
+
align-items: center;
|
|
11490
|
+
gap: var(--swc-spacing-75);
|
|
11491
|
+
min-inline-size: 0;
|
|
11492
|
+
}
|
|
11493
|
+
.head > * {
|
|
11494
|
+
flex: none;
|
|
11495
|
+
}
|
|
11496
|
+
.marker {
|
|
11497
|
+
flex: none;
|
|
11498
|
+
display: inline-flex;
|
|
11499
|
+
align-items: center;
|
|
11500
|
+
justify-content: center;
|
|
11501
|
+
inline-size: var(--swc-spacing-200);
|
|
11502
|
+
block-size: var(--swc-spacing-200);
|
|
11503
|
+
border-radius: var(--swc-corner-radius-full);
|
|
11504
|
+
font-size: var(--swc-font-size-25);
|
|
11505
|
+
font-variant-numeric: tabular-nums;
|
|
11506
|
+
line-height: 1;
|
|
11507
|
+
}
|
|
11508
|
+
.marker.unread {
|
|
11509
|
+
box-sizing: border-box;
|
|
11510
|
+
inline-size: auto;
|
|
11511
|
+
min-inline-size: var(--swc-spacing-200);
|
|
11512
|
+
padding-inline: var(--swc-spacing-50);
|
|
11513
|
+
background: var(--swc-accent-background-color-default);
|
|
11514
|
+
color: var(--swc-white);
|
|
11515
|
+
font-weight: var(--swc-bold-font-weight);
|
|
11516
|
+
}
|
|
11462
11517
|
.name {
|
|
11463
|
-
|
|
11518
|
+
flex: 0 1 auto;
|
|
11519
|
+
min-inline-size: 0;
|
|
11464
11520
|
overflow: hidden;
|
|
11465
11521
|
text-overflow: ellipsis;
|
|
11466
11522
|
white-space: nowrap;
|
|
@@ -11469,29 +11525,58 @@ var SliccAgents = class extends ModelElement {
|
|
|
11469
11525
|
font-weight: var(--swc-bold-font-weight);
|
|
11470
11526
|
}
|
|
11471
11527
|
.title {
|
|
11472
|
-
grid-area:
|
|
11528
|
+
grid-area: description;
|
|
11529
|
+
display: -webkit-box;
|
|
11530
|
+
-webkit-box-orient: vertical;
|
|
11531
|
+
-webkit-line-clamp: 2;
|
|
11473
11532
|
overflow: hidden;
|
|
11474
|
-
|
|
11475
|
-
|
|
11533
|
+
overflow-wrap: anywhere;
|
|
11534
|
+
line-height: 1.4;
|
|
11476
11535
|
font-size: var(--swc-font-size-75);
|
|
11477
11536
|
color: var(--swc-neutral-subdued-content-color-default);
|
|
11478
11537
|
}
|
|
11479
|
-
.
|
|
11480
|
-
|
|
11481
|
-
|
|
11482
|
-
|
|
11483
|
-
|
|
11484
|
-
|
|
11485
|
-
|
|
11486
|
-
|
|
11538
|
+
.state {
|
|
11539
|
+
color: var(--swc-neutral-content-color-default);
|
|
11540
|
+
}
|
|
11541
|
+
.ribbon {
|
|
11542
|
+
grid-area: ribbon;
|
|
11543
|
+
display: flex;
|
|
11544
|
+
align-items: center;
|
|
11545
|
+
gap: var(--swc-spacing-50);
|
|
11546
|
+
overflow: hidden;
|
|
11547
|
+
}
|
|
11548
|
+
.status,
|
|
11549
|
+
.segment {
|
|
11550
|
+
background: var(--swc-neutral-visual-color);
|
|
11551
|
+
}
|
|
11552
|
+
.status[data-status='thinking'],
|
|
11553
|
+
.status[data-status='working'],
|
|
11554
|
+
.segment[data-status='thinking'],
|
|
11555
|
+
.segment[data-status='working'] {
|
|
11556
|
+
background: var(--swc-informative-visual-color);
|
|
11557
|
+
}
|
|
11558
|
+
.status[data-status='waiting'],
|
|
11559
|
+
.segment[data-status='waiting'] {
|
|
11560
|
+
background: var(--swc-notice-visual-color);
|
|
11561
|
+
}
|
|
11562
|
+
.status[data-status='error'],
|
|
11563
|
+
.segment[data-status='error'] {
|
|
11564
|
+
background: var(--swc-negative-visual-color);
|
|
11565
|
+
}
|
|
11566
|
+
.segment {
|
|
11567
|
+
flex: none;
|
|
11568
|
+
inline-size: var(--swc-spacing-200);
|
|
11569
|
+
block-size: var(--swc-spacing-50);
|
|
11570
|
+
border-radius: var(--swc-corner-radius-full);
|
|
11487
11571
|
}
|
|
11488
11572
|
.fill {
|
|
11489
11573
|
grid-area: fill;
|
|
11574
|
+
position: relative;
|
|
11575
|
+
z-index: 1;
|
|
11576
|
+
align-self: start;
|
|
11490
11577
|
font-size: var(--swc-font-size-75);
|
|
11491
11578
|
font-variant-numeric: tabular-nums;
|
|
11492
11579
|
color: var(--swc-neutral-subdued-content-color-default);
|
|
11493
|
-
min-width: 4ch;
|
|
11494
|
-
text-align: end;
|
|
11495
11580
|
}
|
|
11496
11581
|
.fill[data-variant='notice'] {
|
|
11497
11582
|
color: var(--swc-notice-color-1000);
|
|
@@ -11501,18 +11586,20 @@ var SliccAgents = class extends ModelElement {
|
|
|
11501
11586
|
color: var(--swc-negative-color-1000);
|
|
11502
11587
|
font-weight: var(--swc-bold-font-weight);
|
|
11503
11588
|
}
|
|
11504
|
-
|
|
11505
|
-
|
|
11506
|
-
|
|
11507
|
-
|
|
11508
|
-
|
|
11509
|
-
|
|
11510
|
-
|
|
11511
|
-
|
|
11589
|
+
.drop-cell {
|
|
11590
|
+
position: absolute;
|
|
11591
|
+
inset-block: 0;
|
|
11592
|
+
inset-inline-end: 0;
|
|
11593
|
+
display: flex;
|
|
11594
|
+
align-items: center;
|
|
11595
|
+
padding-inline: var(--swc-spacing-100);
|
|
11596
|
+
background: var(--row-background);
|
|
11597
|
+
opacity: 0;
|
|
11512
11598
|
}
|
|
11513
|
-
li:hover .drop,
|
|
11514
|
-
li:focus-
|
|
11515
|
-
|
|
11599
|
+
li:hover .drop-cell,
|
|
11600
|
+
li:focus-visible .drop-cell,
|
|
11601
|
+
.drop-cell[data-shown] {
|
|
11602
|
+
opacity: 1;
|
|
11516
11603
|
}
|
|
11517
11604
|
.error {
|
|
11518
11605
|
grid-area: error;
|
|
@@ -11529,23 +11616,46 @@ var SliccAgents = class extends ModelElement {
|
|
|
11529
11616
|
white-space: nowrap;
|
|
11530
11617
|
}
|
|
11531
11618
|
@media (hover: none), (pointer: coarse) {
|
|
11532
|
-
.drop {
|
|
11533
|
-
|
|
11619
|
+
.drop-cell {
|
|
11620
|
+
opacity: 1;
|
|
11534
11621
|
}
|
|
11535
11622
|
}
|
|
11536
11623
|
`
|
|
11537
11624
|
];
|
|
11538
11625
|
subscribe(model) {
|
|
11626
|
+
const focused2 = this.#focused(model);
|
|
11627
|
+
this.#expanded = focused2?.kind === "scoop" ? focused2.parentId : null;
|
|
11539
11628
|
return [
|
|
11540
11629
|
model.agent.on("agents", () => this.requestUpdate()),
|
|
11541
|
-
model.agent.on("active", () =>
|
|
11630
|
+
model.agent.on("active", () => {
|
|
11631
|
+
const next = this.#focused(model);
|
|
11632
|
+
if (next) this.#expanded = next.kind === "cone" ? next.id : next.parentId;
|
|
11633
|
+
this.requestUpdate();
|
|
11634
|
+
}),
|
|
11542
11635
|
watchTitles(model, () => this.requestUpdate()),
|
|
11543
|
-
...model.follow ? [model.follow.on("follow", () => this.requestUpdate())] : []
|
|
11636
|
+
...model.follow ? [model.follow.on("follow", () => this.requestUpdate())] : [],
|
|
11637
|
+
this.#watchPointer()
|
|
11544
11638
|
];
|
|
11545
11639
|
}
|
|
11640
|
+
#watchPointer() {
|
|
11641
|
+
const types = ["pointerdown", "keydown"];
|
|
11642
|
+
for (const type of types) globalThis.addEventListener(type, this.#modality, true);
|
|
11643
|
+
return () => {
|
|
11644
|
+
for (const type of types) globalThis.removeEventListener(type, this.#modality, true);
|
|
11645
|
+
};
|
|
11646
|
+
}
|
|
11647
|
+
#focused(model) {
|
|
11648
|
+
return model.agent.list().find((agent) => agent.id === model.agent.active());
|
|
11649
|
+
}
|
|
11546
11650
|
#select(id) {
|
|
11547
11651
|
this.model?.agent.select(id);
|
|
11548
11652
|
}
|
|
11653
|
+
#pick(agent) {
|
|
11654
|
+
const open = agent.kind === "cone" && this.#expanded !== agent.id;
|
|
11655
|
+
this.#select(agent.id);
|
|
11656
|
+
if (agent.kind === "cone") this.#expanded = open ? agent.id : null;
|
|
11657
|
+
this.requestUpdate();
|
|
11658
|
+
}
|
|
11549
11659
|
focus() {
|
|
11550
11660
|
this.focusOn('li[tabindex="0"]');
|
|
11551
11661
|
}
|
|
@@ -11564,21 +11674,44 @@ var SliccAgents = class extends ModelElement {
|
|
|
11564
11674
|
if (event2.key in moves) {
|
|
11565
11675
|
event2.preventDefault();
|
|
11566
11676
|
items[Math.max(0, Math.min(items.length - 1, moves[event2.key]))]?.focus();
|
|
11567
|
-
|
|
11677
|
+
return;
|
|
11678
|
+
}
|
|
11679
|
+
const agent = this.model?.agent.list().find((item2) => item2.id === items[index]?.dataset.id);
|
|
11680
|
+
if (!agent) return;
|
|
11681
|
+
if (event2.key === "Enter" || event2.key === " ") {
|
|
11682
|
+
event2.preventDefault();
|
|
11683
|
+
this.#pick(agent);
|
|
11684
|
+
} else if (event2.key === "ArrowRight" && this.#scoops(agent).length > 0) {
|
|
11568
11685
|
event2.preventDefault();
|
|
11569
|
-
|
|
11570
|
-
|
|
11686
|
+
if (this.#expanded === agent.id) items[index + 1].focus();
|
|
11687
|
+
else this.#pick(agent);
|
|
11688
|
+
} else if (event2.key === "ArrowLeft" && agent.kind === "scoop") {
|
|
11689
|
+
event2.preventDefault();
|
|
11690
|
+
items.find((item2) => item2.dataset.id === agent.parentId)?.focus();
|
|
11691
|
+
} else if (event2.key === "ArrowLeft" && this.#expanded === agent.id) {
|
|
11692
|
+
event2.preventDefault();
|
|
11693
|
+
this.#pick(agent);
|
|
11571
11694
|
} else if (event2.key === "Delete") {
|
|
11572
|
-
|
|
11573
|
-
if (agent && this.#droppable(agent)) {
|
|
11695
|
+
if (this.#droppable(agent)) {
|
|
11574
11696
|
event2.preventDefault();
|
|
11575
11697
|
void this.#drop(agent, items[index]);
|
|
11576
|
-
} else if (
|
|
11698
|
+
} else if (this.#deletable(agent)) {
|
|
11577
11699
|
event2.preventDefault();
|
|
11578
11700
|
void this.#deleteCone(agent, items[index]);
|
|
11579
11701
|
}
|
|
11580
11702
|
}
|
|
11581
11703
|
}
|
|
11704
|
+
#scoops(agent) {
|
|
11705
|
+
if (agent.kind !== "cone") return [];
|
|
11706
|
+
return this.model.agent.list().filter((other) => other.parentId === agent.id);
|
|
11707
|
+
}
|
|
11708
|
+
#focusin(event2) {
|
|
11709
|
+
const cell = event2.target.closest(".drop-cell");
|
|
11710
|
+
cell?.toggleAttribute("data-shown", !this.#pointer);
|
|
11711
|
+
}
|
|
11712
|
+
#focusout(event2) {
|
|
11713
|
+
event2.target.closest(".drop-cell")?.removeAttribute("data-shown");
|
|
11714
|
+
}
|
|
11582
11715
|
#droppable(agent) {
|
|
11583
11716
|
return agent.kind === "scoop" && Boolean(this.model?.agent.drop) && !watchOnly(this.model);
|
|
11584
11717
|
}
|
|
@@ -11616,69 +11749,89 @@ var SliccAgents = class extends ModelElement {
|
|
|
11616
11749
|
await this.updateComplete;
|
|
11617
11750
|
this.focus();
|
|
11618
11751
|
}
|
|
11619
|
-
#dropButton(agent) {
|
|
11752
|
+
#dropButton(agent, selected) {
|
|
11620
11753
|
if (!this.#droppable(agent)) return A;
|
|
11621
11754
|
const id = `drop-${agent.id}`;
|
|
11622
11755
|
const label = `Drop scoop ${agent.name}`;
|
|
11623
|
-
return b`<
|
|
11624
|
-
|
|
11625
|
-
|
|
11626
|
-
|
|
11627
|
-
|
|
11628
|
-
|
|
11629
|
-
|
|
11630
|
-
|
|
11631
|
-
|
|
11756
|
+
return b`<span class="drop-cell"
|
|
11757
|
+
><swc-action-button
|
|
11758
|
+
id=${id}
|
|
11759
|
+
class="drop"
|
|
11760
|
+
size="l"
|
|
11761
|
+
quiet
|
|
11762
|
+
tabindex=${selected ? "0" : "-1"}
|
|
11763
|
+
data-action="drop"
|
|
11764
|
+
accessible-label=${label}
|
|
11765
|
+
@click=${(event2) => {
|
|
11632
11766
|
event2.stopPropagation();
|
|
11633
11767
|
void this.#drop(agent, event2.currentTarget);
|
|
11634
11768
|
}}
|
|
11635
|
-
|
|
11636
|
-
|
|
11769
|
+
><swc-icon-close slot="icon"></swc-icon-close></swc-action-button
|
|
11770
|
+
><swc-tooltip for=${id} placement="start">${label}</swc-tooltip></span
|
|
11771
|
+
>`;
|
|
11637
11772
|
}
|
|
11638
|
-
#deleteButton(agent) {
|
|
11773
|
+
#deleteButton(agent, selected) {
|
|
11639
11774
|
if (!this.#deletable(agent)) return A;
|
|
11640
11775
|
const id = `delete-${agent.id}`;
|
|
11641
11776
|
const label = `Delete cone ${coneLabel(this.model, agent)}`;
|
|
11642
|
-
return b`<
|
|
11643
|
-
|
|
11644
|
-
|
|
11645
|
-
|
|
11646
|
-
|
|
11647
|
-
|
|
11648
|
-
|
|
11649
|
-
|
|
11650
|
-
|
|
11777
|
+
return b`<span class="drop-cell"
|
|
11778
|
+
><swc-action-button
|
|
11779
|
+
id=${id}
|
|
11780
|
+
class="drop"
|
|
11781
|
+
size="l"
|
|
11782
|
+
quiet
|
|
11783
|
+
tabindex=${selected ? "0" : "-1"}
|
|
11784
|
+
data-action="delete-cone"
|
|
11785
|
+
accessible-label=${label}
|
|
11786
|
+
@click=${(event2) => {
|
|
11651
11787
|
event2.stopPropagation();
|
|
11652
11788
|
void this.#deleteCone(agent, event2.currentTarget);
|
|
11653
11789
|
}}
|
|
11654
|
-
|
|
11655
|
-
|
|
11790
|
+
><swc-icon-delete slot="icon"></swc-icon-delete></swc-action-button
|
|
11791
|
+
><swc-tooltip for=${id} placement="start">${label}</swc-tooltip></span
|
|
11792
|
+
>`;
|
|
11793
|
+
}
|
|
11794
|
+
#ribbon(scoops) {
|
|
11795
|
+
if (scoops.length === 0) return A;
|
|
11796
|
+
return b`<span class="ribbon" aria-hidden="true">${scoops.map(
|
|
11797
|
+
(scoop) => b`<span class="segment" data-status=${scoop.status}></span>`
|
|
11798
|
+
)}</span>`;
|
|
11656
11799
|
}
|
|
11657
11800
|
#row(agent, active) {
|
|
11658
11801
|
const selected = agent.id === active;
|
|
11659
11802
|
const error = this.errors[agent.id];
|
|
11660
11803
|
const model = this.model;
|
|
11661
|
-
const title =
|
|
11804
|
+
const title = agentTitle(model, agent);
|
|
11805
|
+
const scoops = this.#scoops(agent);
|
|
11806
|
+
const open = this.#expanded === agent.id;
|
|
11662
11807
|
const unread = selected ? 0 : agent.unread;
|
|
11663
11808
|
const label = `${coneLabel(model, agent)}: ${statusLabel[agent.status]}, ${percent(agent.contextFill)} context${unread ? `, ${unread} unread` : ""}${error ? `. ${error}` : ""}`;
|
|
11809
|
+
const summary = scoopSummary(scoops);
|
|
11664
11810
|
return b`<li
|
|
11665
|
-
role="
|
|
11811
|
+
role="treeitem"
|
|
11812
|
+
id=${`row-${agent.id}`}
|
|
11666
11813
|
class=${agent.kind}
|
|
11667
11814
|
data-id=${agent.id}
|
|
11815
|
+
aria-level=${agent.kind === "cone" ? "1" : "2"}
|
|
11668
11816
|
aria-selected=${selected ? "true" : "false"}
|
|
11817
|
+
aria-expanded=${scoops.length ? String(open) : A}
|
|
11818
|
+
aria-controls=${open && scoops.length ? scoops.map((scoop) => `row-${scoop.id}`).join(" ") : A}
|
|
11669
11819
|
aria-label=${label}
|
|
11820
|
+
aria-description=${summary || A}
|
|
11670
11821
|
tabindex=${selected ? "0" : "-1"}
|
|
11671
11822
|
aria-keyshortcuts=${this.#droppable(agent) || this.#deletable(agent) ? "Delete" : A}
|
|
11672
|
-
title=${label}
|
|
11673
|
-
@click=${() => this.#
|
|
11823
|
+
title=${summary ? `${label}. ${summary}` : label}
|
|
11824
|
+
@click=${() => this.#pick(agent)}
|
|
11674
11825
|
>
|
|
11675
|
-
<
|
|
11676
|
-
|
|
11677
|
-
|
|
11826
|
+
<div class="head">
|
|
11827
|
+
${unread ? b`<span class="marker unread" aria-hidden="true">${unreadCount(unread)}</span>` : b`<span class="marker status" data-status=${agent.status} aria-hidden="true"></span>`}
|
|
11828
|
+
<span class="name">${agent.name}</span>
|
|
11829
|
+
</div>
|
|
11678
11830
|
${fillShown(agent.contextFill) ? b`<span class="fill" data-variant=${meterVariant2(agent.contextFill)}>${percent(agent.contextFill)}</span>` : A}
|
|
11679
|
-
|
|
11680
|
-
${this.#
|
|
11681
|
-
${this.#
|
|
11831
|
+
<span class="title"><span class="state">${statusLabel[agent.status]}</span> · ${title || untitled}</span>
|
|
11832
|
+
${this.#ribbon(scoops)}
|
|
11833
|
+
${this.#dropButton(agent, selected)}
|
|
11834
|
+
${this.#deleteButton(agent, selected)}
|
|
11682
11835
|
${error ? b`<span class="error">${error}</span>` : A}
|
|
11683
11836
|
</li>`;
|
|
11684
11837
|
}
|
|
@@ -11696,12 +11849,15 @@ var SliccAgents = class extends ModelElement {
|
|
|
11696
11849
|
</div>`;
|
|
11697
11850
|
}
|
|
11698
11851
|
render() {
|
|
11699
|
-
const
|
|
11852
|
+
const list5 = this.model?.agent.list() ?? [];
|
|
11700
11853
|
const active = this.model?.agent.active() ?? "";
|
|
11701
11854
|
const errors = Object.values(this.errors);
|
|
11702
|
-
|
|
11703
|
-
|
|
11704
|
-
|
|
11855
|
+
const rows = ordered(list5).filter(
|
|
11856
|
+
(agent) => agent.kind === "cone" || agent.parentId === this.#expanded
|
|
11857
|
+
);
|
|
11858
|
+
return b`<div class="list"><ul role="tree" aria-label="Cones and scoops" @keydown=${this.#keydown} @focusin=${this.#focusin} @focusout=${this.#focusout}>
|
|
11859
|
+
${rows.map((agent) => this.#row(agent, active))}
|
|
11860
|
+
</ul></div>${this.#actions()}
|
|
11705
11861
|
<div class="sr" role="status">${errors.at(-1) ?? ""}</div>`;
|
|
11706
11862
|
}
|
|
11707
11863
|
};
|
|
@@ -41110,12 +41266,13 @@ var bridge = `(() => {
|
|
|
41110
41266
|
}
|
|
41111
41267
|
node.replaceWith(svg);
|
|
41112
41268
|
}
|
|
41269
|
+
size();
|
|
41113
41270
|
};
|
|
41114
41271
|
const fonts = (list) => {
|
|
41115
41272
|
for (const font of list) {
|
|
41116
41273
|
const face = new FontFace(font.family, font.data, { weight: String(font.weight) });
|
|
41117
41274
|
document.fonts.add(face);
|
|
41118
|
-
face.load().
|
|
41275
|
+
face.load().then(size, () => {});
|
|
41119
41276
|
}
|
|
41120
41277
|
};
|
|
41121
41278
|
addEventListener('message', (event) => {
|
|
@@ -41131,6 +41288,7 @@ var bridge = `(() => {
|
|
|
41131
41288
|
};
|
|
41132
41289
|
document.addEventListener('DOMContentLoaded', () => {
|
|
41133
41290
|
window.LucideIcons.render();
|
|
41291
|
+
size();
|
|
41134
41292
|
new ResizeObserver(size).observe(document.body);
|
|
41135
41293
|
});
|
|
41136
41294
|
post({ type: 'slicc-ready' });
|