@green-on-grey/ui-kit 1.13.0 → 1.14.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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["Switch","useToast","GitHubIcon","Icon","Tabs","Empty","ToastProvider","Loading","useOutside","Avatar","Markdown","useKitT","UIKIT_NS","Button","rest","cls","variant","size","className","IconButton","fill","on","label","Menu","ref","onClose","useEffect","opener","TopBar","t","profileOpen","setProfileOpen","useState","sectionsOpen","setSectionsOpen","closeSections","useCallback","closeProfile","links","sections","Link","s","home","logo","name","center","actions","v","avatar","menu","profileMenu","W","H","radius","zoomed","k","factor","neighbours","near","from","frontier","d","depth","next","id","e","edges","other","layout","placed","nodes","n","ids","sim","forceSimulation","forceLink","l","forceManyBody","forceCenter","forceCollide","i","Graph","arrow","useId","hover","setHover","view","setView","drag","useRef","svg","useMemo","p","focused","focus","byId","active","selected","dimmed","edgeOn","zoom","pick","onSelect","pinned","el","wheel","ariaLabel","box","dx","dy","panned","a","b","x2","y2","len","nodeLabel","onOpen","legend","Modal"],"sources":["../src/components/Button.tsx","../src/components/Menu.tsx","../src/components/TopBar.tsx","../src/components/Graph.tsx"],"sourcesContent":["import type { ButtonHTMLAttributes } from \"react\";\n\ntype Native = ButtonHTMLAttributes<HTMLButtonElement>;\n\n/** `button.btn` with its variants. The classes stay a legitimate way to use a\n * button (FTR.NAB.CMN-0005 tech, decision 1); the component is for new code. */\nexport function Button({ variant, size, className, type = \"button\", ...rest }: Native & {\n variant?: \"primary\" | \"ghost\" | \"danger\"; size?: \"sm\";\n}) {\n const cls = [\"btn\", variant, size, className].filter(Boolean).join(\" \");\n return <button type={type} className={cls} {...rest} />;\n}\n\n/** `button.iconbtn`: a button with an icon only, so the label is required. */\nexport function IconButton({ label, fill, on, className, type = \"button\", ...rest }: Omit<Native, \"aria-label\"> & {\n label: string; fill?: boolean; on?: boolean;\n}) {\n const cls = [\"iconbtn\", fill && \"fill\", on && \"on\", className].filter(Boolean).join(\" \");\n return <button type={type} className={cls} aria-label={label} {...rest} />;\n}\n","import { useEffect, type ReactNode } from \"react\";\nimport { useOutside } from \"./ui\";\n\n/** `.menu`: a popover closed by Escape and by a click outside; it is mounted while\n * open. `onClose` must keep its identity between renders. What is inside\n * (sections `.sec`, lines `.line`, actions `.action`) belongs to the product. */\nexport function Menu({ onClose, label, className, children }: {\n onClose: () => void; label?: string; className?: string; children: ReactNode;\n}) {\n const ref = useOutside<HTMLDivElement>(true, onClose);\n // the focus returns to what opened the menu (CMP-05)\n useEffect(() => {\n const opener = document.activeElement as HTMLElement | null;\n return () => opener?.focus?.();\n }, []);\n return (\n <div className={`menu${className ? ` ${className}` : \"\"}`} role=\"dialog\" aria-label={label} ref={ref}>\n {children}\n </div>\n );\n}\n","import { useCallback, useState, type ReactNode } from \"react\";\nimport { useKitT } from \"../i18n\";\nimport { Icon } from \"./Icon\";\nimport { useOutside } from \"./ui\";\n\n/** The link of the product: the kit does not depend on a router (arch §4.2). */\nexport type LinkComponent = (props: {\n href: string; className?: string; onClick?: () => void; \"aria-current\"?: \"page\"; children: ReactNode;\n}) => ReactNode;\n\nexport interface TopBarSection { key: string; label: ReactNode; href: string; active: boolean }\n\n/** The top bar (FTR.NAB.CMN-0005 R5, design §4): the logo and the name, the\n * sections in a row and behind the burger on a phone, the actions of the product,\n * the avatar that opens the profile menu. The profile menu and the list of\n * sections are never open together. A part of the product with its own\n * navigation (the administration) puts it behind the burger in place of the\n * sections: `menu`, with the side panel marked `in-burger`, hidden on a phone. */\nexport function TopBar({ logo, name, home = \"/\", sections, Link, center, actions, avatar, profileMenu, menu }: {\n logo: string; name: string; home?: string; sections: TopBarSection[]; Link: LinkComponent;\n /** Between the sections and the actions: the search of Hammurapi. */\n center?: ReactNode;\n /** Before the avatar. */\n actions?: ReactNode;\n avatar: ReactNode;\n profileMenu: (close: () => void) => ReactNode;\n /** The burger of a phone in place of the sections: the navigation of the current part of the product and\n * its name, which the burger is called by. */\n menu?: { label: string; render: (close: () => void) => ReactNode };\n}) {\n const t = useKitT();\n const [profileOpen, setProfileOpen] = useState(false);\n const [sectionsOpen, setSectionsOpen] = useState(false);\n const closeSections = useCallback(() => setSectionsOpen(false), []);\n const closeProfile = useCallback(() => setProfileOpen(false), []);\n const ref = useOutside<HTMLDivElement>(sectionsOpen, closeSections);\n const links = sections.map((s) => (\n <Link key={s.key} href={s.href} className={s.active ? \"on\" : undefined} aria-current={s.active ? \"page\" : undefined} onClick={closeSections}>\n {s.label}\n </Link>\n ));\n return (\n <div className=\"topbar\">\n <Link href={home} className=\"brand\">\n <img src={logo} alt=\"\" />\n <span className=\"hide-m\">{name}</span>\n </Link>\n <nav className=\"nav hide-m\" aria-label={t(\"topbar.sections\")}>{links}</nav>\n {center}\n <div className=\"top-actions\">\n {actions}\n <button className=\"avatar\" style={profileOpen ? { boxShadow: \"0 0 0 2px var(--violet)\" } : undefined}\n onClick={() => { setSectionsOpen(false); setProfileOpen((v) => !v); }} aria-label={t(\"topbar.profile\")} aria-expanded={profileOpen}>\n {avatar}\n </button>\n <div className=\"burger\" ref={ref}>\n <button className={`iconbtn${sectionsOpen ? \" on\" : \"\"}`} onClick={() => { setProfileOpen(false); setSectionsOpen((v) => !v); }}\n aria-label={menu?.label ?? t(\"topbar.sections\")} aria-expanded={sectionsOpen} aria-controls=\"nav-sections\">\n <Icon name={sectionsOpen ? \"x\" : \"menu\"} />\n </button>\n {sectionsOpen && (menu\n ? <div id=\"nav-sections\" className=\"navmenu\">{menu.render(closeSections)}</div>\n : <nav id=\"nav-sections\" className=\"navmenu\" aria-label={t(\"topbar.sections\")}>{links}</nav>)}\n </div>\n </div>\n {profileOpen && profileMenu(closeProfile)}\n </div>\n );\n}\n","import { useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { forceCenter, forceCollide, forceLink, forceManyBody, forceSimulation } from \"d3-force\";\nimport { useKitT } from \"../i18n\";\n\nconst W = 760;\nconst H = 500;\n\n/** A node: `group` picks the colour (g-c1…g-c6), `size` the radius. */\nexport type GraphNode = {\n id: string; label: string; title?: string; group?: number; size?: number;\n /** Not in the data of the product, only referred to: a dashed outline. */\n dashed?: boolean;\n /** Context around the shown set: drawn faded. */\n muted?: boolean;\n /** The label shows only on hover, focus or highlight. */\n hideLabel?: boolean;\n};\nexport type GraphEdge = { source: string; target: string; weight?: number; directed?: boolean; dashed?: boolean; title?: string };\nexport type GraphSelection = { kind: \"node\"; id: string } | { kind: \"edge\"; source: string; target: string } | null;\n\n/** A node with its place; the fields of d3-force are spelled out, so the types of the kit need no d3 types. */\ntype Placed = GraphNode & { r: number; index?: number; x?: number; y?: number; vx?: number; vy?: number; fx?: number | null; fy?: number | null };\n\nconst radius = (size = 1) => 7 + Math.sqrt(size) * 3.2;\n\ntype View = { k: number; x: number; y: number };\n/** The view zoomed by `factor`, between 0.5 and 4, keeping the centre of the field in place. */\nconst zoomed = (v: View, factor: number): View => {\n const k = Math.max(0.5, Math.min(4, v.k * factor));\n return { k, x: W / 2 - ((W / 2 - v.x) / v.k) * k, y: H / 2 - ((H / 2 - v.y) / v.k) * k };\n};\n\n/** Ids within `depth` steps of `from`, edges taken both ways. */\nexport function neighbours(edges: GraphEdge[], from: string, depth: number): Set<string> {\n const near = new Set([from]);\n let frontier = [from];\n for (let d = 0; d < depth; d++) {\n const next: string[] = [];\n for (const id of frontier) {\n for (const e of edges) {\n const other = e.source === id ? e.target : e.target === id ? e.source : null;\n if (other && !near.has(other)) { near.add(other); next.push(other); }\n }\n }\n frontier = next;\n }\n return near;\n}\n\n/** Positions of the nodes (exported for the tests): a force layout computed once per data. The start of\n * d3-force is deterministic, so the same data gives the same picture. */\nexport function layout(nodes: GraphNode[], edges: GraphEdge[]): Placed[] {\n const placed: Placed[] = nodes.map((n) => ({ ...n, r: radius(n.size) }));\n const ids = new Set(placed.map((n) => n.id));\n const links = edges.filter((e) => ids.has(e.source) && ids.has(e.target)).map((e) => ({ source: e.source, target: e.target, weight: e.weight ?? 1 }));\n const sim = forceSimulation(placed)\n .force(\"link\", forceLink<Placed, (typeof links)[number]>(links).id((d) => d.id).distance(90).strength((l) => Math.min(1, 0.2 + l.weight * 0.08)))\n .force(\"charge\", forceManyBody().strength(-260))\n .force(\"center\", forceCenter(W / 2, H / 2))\n .force(\"collide\", forceCollide<Placed>().radius((d) => d.r + 14))\n .stop();\n for (let i = 0; i < 260; i++) sim.tick();\n for (const n of placed) { // keep the labels inside the field\n n.x = Math.max(n.r + 30, Math.min(W - n.r - 30, n.x ?? W / 2));\n n.y = Math.max(n.r + 10, Math.min(H - n.r - 24, n.y ?? H / 2));\n }\n return placed;\n}\n\n/** A graph of nodes and links (FTR.NAB.CMN-0003 R19, FTR.HMR.DEV-0002 R15, R16).\n * Hovering highlights the neighbours, a click pins the selection; the wheel zooms,\n * dragging moves. `focus` highlights a node and its neighbours within `depth`\n * steps; `onOpen` is called on a double click or Enter on a node. The kit knows\n * nothing of what the nodes are: labels and the legend come from the product.\n * The layout runs when `nodes` or `edges` change identity: keep them stable (useMemo). */\nexport function Graph({ nodes, edges, ariaLabel, selected, onSelect, focus, depth = 1, onOpen, legend, nodeLabel }: {\n nodes: GraphNode[]; edges: GraphEdge[]; ariaLabel: string;\n selected: GraphSelection; onSelect: (s: GraphSelection) => void;\n focus?: string; depth?: 1 | 2;\n onOpen?: (id: string) => void;\n legend?: { group: number; label: string }[];\n nodeLabel?: (n: GraphNode) => string;\n}) {\n const t = useKitT();\n const arrow = `g-arrow-${useId().replace(/:/g, \"\")}`;\n const [hover, setHover] = useState<string | null>(null);\n const [view, setView] = useState<View>({ k: 1, x: 0, y: 0 });\n const drag = useRef<{ x: number; y: number; moved: boolean } | null>(null);\n const svg = useRef<SVGSVGElement>(null);\n\n const { placed, byId } = useMemo(() => {\n const p = layout(nodes, edges);\n return { placed: p, byId: new Map(p.map((n) => [n.id, n])) };\n }, [nodes, edges]);\n\n const focused = focus !== undefined && byId.has(focus) ? focus : undefined; // a focus outside the data fades nothing\n const active = hover ?? (selected?.kind === \"node\" ? selected.id : null);\n const near = useMemo(() => {\n if (selected?.kind === \"edge\" && !hover) return new Set([selected.source, selected.target]);\n if (active) return neighbours(edges, active, 1);\n if (focused) return neighbours(edges, focused, depth);\n return new Set<string>();\n }, [active, selected, hover, focused, depth, edges]);\n const dimmed = near.size > 0;\n const edgeOn = (e: GraphEdge) => {\n if (selected?.kind === \"edge\" && !hover) return selected.source === e.source && selected.target === e.target;\n if (active) return e.source === active || e.target === active;\n return focused !== undefined && near.has(e.source) && near.has(e.target);\n };\n\n const zoom = (factor: number) => setView((v) => zoomed(v, factor));\n const pick = (id: string, pinned: boolean) => onSelect(pinned ? null : { kind: \"node\", id });\n\n // The wheel zooms and does not scroll the page: React's onWheel is passive.\n useEffect(() => {\n const el = svg.current;\n if (!el) return;\n const wheel = (e: WheelEvent) => { e.preventDefault(); setView((v) => zoomed(v, e.deltaY < 0 ? 1.15 : 1 / 1.15)); };\n el.addEventListener(\"wheel\", wheel, { passive: false });\n return () => el.removeEventListener(\"wheel\", wheel);\n }, []);\n\n return (\n <div className=\"gwrap\">\n <svg ref={svg} viewBox={`0 0 ${W} ${H}`} role=\"group\" aria-label={ariaLabel} className={dimmed ? \"dimmed\" : undefined}\n onPointerDown={(e) => { if (e.target === e.currentTarget) { drag.current = { x: e.clientX, y: e.clientY, moved: false }; e.currentTarget.setPointerCapture(e.pointerId); } }}\n onPointerMove={(e) => {\n if (!drag.current) return;\n const box = e.currentTarget.getBoundingClientRect();\n const dx = ((e.clientX - drag.current.x) / box.width) * W;\n const dy = ((e.clientY - drag.current.y) / box.height) * H;\n drag.current = { x: e.clientX, y: e.clientY, moved: drag.current.moved || dx !== 0 || dy !== 0 };\n setView((v) => ({ ...v, x: v.x + dx, y: v.y + dy }));\n }}\n onPointerUp={() => { if (!drag.current?.moved) drag.current = null; }}\n onClick={(e) => {\n const panned = drag.current?.moved; // a pan ends with a click on the field: it keeps the selection\n drag.current = null;\n if (!panned && e.target === e.currentTarget) onSelect(null);\n }}>\n {edges.some((e) => e.directed) && (\n <defs>\n <marker id={arrow} viewBox=\"0 0 10 10\" refX=\"10\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\">\n <path d=\"M0,0 L10,5 L0,10 z\" />\n </marker>\n </defs>\n )}\n <g transform={`translate(${view.x} ${view.y}) scale(${view.k})`}>\n {edges.map((e, i) => {\n const a = byId.get(e.source), b = byId.get(e.target);\n if (!a || !b) return null;\n let x2 = b.x ?? 0, y2 = b.y ?? 0;\n if (e.directed) { // the arrow ends at the circle of the target\n const dx = x2 - (a.x ?? 0), dy = y2 - (a.y ?? 0), len = Math.hypot(dx, dy) || 1;\n x2 -= (dx / len) * (b.r + 2);\n y2 -= (dy / len) * (b.r + 2);\n }\n return (\n <g key={`${e.source}\\u0000${e.target}\\u0000${i}`} className={`g-e${e.dashed ? \" dashed\" : \"\"}${edgeOn(e) ? \" hl\" : \"\"}`}\n onClick={() => onSelect({ kind: \"edge\", source: e.source, target: e.target })}>\n <line x1={a.x} y1={a.y} x2={x2} y2={y2} strokeWidth={1 + (e.weight ?? 1) * 0.5} markerEnd={e.directed ? `url(#${arrow})` : undefined} />\n <line className=\"hit\" x1={a.x} y1={a.y} x2={b.x} y2={b.y} />\n {e.title && <title>{e.title}</title>}\n </g>\n );\n })}\n {placed.map((n) => {\n const pinned = selected?.kind === \"node\" && selected.id === n.id;\n const cls = [\"g-n\", `g-c${n.group ?? 1}`, n.hideLabel && \"small\", n.dashed && \"dashed\", n.muted && \"muted\",\n near.has(n.id) && \"hl\", pinned && \"pin\", focused === n.id && \"focus\"].filter(Boolean).join(\" \");\n return (\n <g key={n.id} className={cls}\n tabIndex={0} role=\"button\" aria-pressed={pinned} aria-label={nodeLabel ? nodeLabel(n) : n.label}\n onMouseEnter={() => setHover(n.id)} onMouseLeave={() => setHover(null)} onFocus={() => setHover(n.id)} onBlur={() => setHover(null)}\n onClick={() => pick(n.id, pinned)}\n onDoubleClick={() => onOpen?.(n.id)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && onOpen) { e.preventDefault(); onOpen(n.id); return; }\n if (e.key === \"Enter\" || e.key === \" \") { e.preventDefault(); pick(n.id, pinned); }\n }}>\n <circle cx={n.x} cy={n.y} r={n.r} />\n <text x={n.x} y={(n.y ?? 0) + n.r + 14}>{n.label}</text>\n {n.title && <title>{n.title}</title>}\n </g>\n );\n })}\n </g>\n </svg>\n {legend && legend.length > 0 && (\n <div className=\"gleg\">{legend.map((l) => <span key={l.group}><i className={`g-c${l.group}`} />{l.label}</span>)}</div>\n )}\n <div className=\"gzoom\">\n <button type=\"button\" onClick={() => zoom(1.3)} aria-label={t(\"graph.zoomIn\")}>+</button>\n <button type=\"button\" onClick={() => zoom(1 / 1.3)} aria-label={t(\"graph.zoomOut\")}>−</button>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["_Fragment","Switch","useToast","GitHubIcon","Icon","Tabs","Empty","ToastProvider","Loading","useOutside","Avatar","Markdown","useKitT","UIKIT_NS","Button","rest","cls","variant","size","className","IconButton","fill","on","label","Menu","ref","onClose","useEffect","opener","TopBar","t","profileOpen","setProfileOpen","useState","sectionsOpen","setSectionsOpen","closeSections","useCallback","closeProfile","links","sections","Link","s","home","logo","name","center","actions","v","avatar","menu","profileMenu","W","H","radius","zoomed","k","factor","f","neighbours","near","from","frontier","d","depth","next","id","e","edges","other","layout","placed","nodes","n","ids","sim","forceSimulation","forceLink","l","forceManyBody","forceCenter","forceCollide","i","GUTTER","COL","ROW","rowLayout","index","rows","r","byRow","used","a","b","bw","bh","field","x0","y0","y","j","edgeLine","x1","y1","bx","by","x2","y2","arc","arcs","cx","cy","directed","fx","fy","dx","dy","len","Graph","arrow","useId","hover","setHover","view","setView","drag","useRef","nodeDrag","movedAt","svg","layoutEdges","base","useMemo","moved","setMoved","at","p","focused","focus","byId","active","selected","dimmed","edgeOn","zoom","pick","onSelect","pinned","unit","box","el","wheel","ariaLabel","u","panned","marker","Fragment","nodeLabel","draggable","m","wasMoved","onOpen","legend","Modal"],"sources":["../src/components/Button.tsx","../src/components/Menu.tsx","../src/components/TopBar.tsx","../src/components/Graph.tsx"],"sourcesContent":["import type { ButtonHTMLAttributes } from \"react\";\n\ntype Native = ButtonHTMLAttributes<HTMLButtonElement>;\n\n/** `button.btn` with its variants. The classes stay a legitimate way to use a\n * button (FTR.NAB.CMN-0005 tech, decision 1); the component is for new code. */\nexport function Button({ variant, size, className, type = \"button\", ...rest }: Native & {\n variant?: \"primary\" | \"ghost\" | \"danger\"; size?: \"sm\";\n}) {\n const cls = [\"btn\", variant, size, className].filter(Boolean).join(\" \");\n return <button type={type} className={cls} {...rest} />;\n}\n\n/** `button.iconbtn`: a button with an icon only, so the label is required. */\nexport function IconButton({ label, fill, on, className, type = \"button\", ...rest }: Omit<Native, \"aria-label\"> & {\n label: string; fill?: boolean; on?: boolean;\n}) {\n const cls = [\"iconbtn\", fill && \"fill\", on && \"on\", className].filter(Boolean).join(\" \");\n return <button type={type} className={cls} aria-label={label} {...rest} />;\n}\n","import { useEffect, type ReactNode } from \"react\";\nimport { useOutside } from \"./ui\";\n\n/** `.menu`: a popover closed by Escape and by a click outside; it is mounted while\n * open. `onClose` must keep its identity between renders. What is inside\n * (sections `.sec`, lines `.line`, actions `.action`) belongs to the product. */\nexport function Menu({ onClose, label, className, children }: {\n onClose: () => void; label?: string; className?: string; children: ReactNode;\n}) {\n const ref = useOutside<HTMLDivElement>(true, onClose);\n // the focus returns to what opened the menu (CMP-05)\n useEffect(() => {\n const opener = document.activeElement as HTMLElement | null;\n return () => opener?.focus?.();\n }, []);\n return (\n <div className={`menu${className ? ` ${className}` : \"\"}`} role=\"dialog\" aria-label={label} ref={ref}>\n {children}\n </div>\n );\n}\n","import { useCallback, useState, type ReactNode } from \"react\";\nimport { useKitT } from \"../i18n\";\nimport { Icon } from \"./Icon\";\nimport { useOutside } from \"./ui\";\n\n/** The link of the product: the kit does not depend on a router (arch §4.2). */\nexport type LinkComponent = (props: {\n href: string; className?: string; onClick?: () => void; \"aria-current\"?: \"page\"; children: ReactNode;\n}) => ReactNode;\n\nexport interface TopBarSection { key: string; label: ReactNode; href: string; active: boolean }\n\n/** The top bar (FTR.NAB.CMN-0005 R5, design §4): the logo and the name, the\n * sections in a row and behind the burger on a phone, the actions of the product,\n * the avatar that opens the profile menu. The profile menu and the list of\n * sections are never open together. A part of the product with its own\n * navigation (the administration) puts it behind the burger in place of the\n * sections: `menu`, with the side panel marked `in-burger`, hidden on a phone. */\nexport function TopBar({ logo, name, home = \"/\", sections, Link, center, actions, avatar, profileMenu, menu }: {\n logo: string; name: string; home?: string; sections: TopBarSection[]; Link: LinkComponent;\n /** Between the sections and the actions: the search of Hammurapi. */\n center?: ReactNode;\n /** Before the avatar. */\n actions?: ReactNode;\n avatar: ReactNode;\n profileMenu: (close: () => void) => ReactNode;\n /** The burger of a phone in place of the sections: the navigation of the current part of the product and\n * its name, which the burger is called by. */\n menu?: { label: string; render: (close: () => void) => ReactNode };\n}) {\n const t = useKitT();\n const [profileOpen, setProfileOpen] = useState(false);\n const [sectionsOpen, setSectionsOpen] = useState(false);\n const closeSections = useCallback(() => setSectionsOpen(false), []);\n const closeProfile = useCallback(() => setProfileOpen(false), []);\n const ref = useOutside<HTMLDivElement>(sectionsOpen, closeSections);\n const links = sections.map((s) => (\n <Link key={s.key} href={s.href} className={s.active ? \"on\" : undefined} aria-current={s.active ? \"page\" : undefined} onClick={closeSections}>\n {s.label}\n </Link>\n ));\n return (\n <div className=\"topbar\">\n <Link href={home} className=\"brand\">\n <img src={logo} alt=\"\" />\n <span className=\"hide-m\">{name}</span>\n </Link>\n <nav className=\"nav hide-m\" aria-label={t(\"topbar.sections\")}>{links}</nav>\n {center}\n <div className=\"top-actions\">\n {actions}\n <button className=\"avatar\" style={profileOpen ? { boxShadow: \"0 0 0 2px var(--violet)\" } : undefined}\n onClick={() => { setSectionsOpen(false); setProfileOpen((v) => !v); }} aria-label={t(\"topbar.profile\")} aria-expanded={profileOpen}>\n {avatar}\n </button>\n <div className=\"burger\" ref={ref}>\n <button className={`iconbtn${sectionsOpen ? \" on\" : \"\"}`} onClick={() => { setProfileOpen(false); setSectionsOpen((v) => !v); }}\n aria-label={menu?.label ?? t(\"topbar.sections\")} aria-expanded={sectionsOpen} aria-controls=\"nav-sections\">\n <Icon name={sectionsOpen ? \"x\" : \"menu\"} />\n </button>\n {sectionsOpen && (menu\n ? <div id=\"nav-sections\" className=\"navmenu\">{menu.render(closeSections)}</div>\n : <nav id=\"nav-sections\" className=\"navmenu\" aria-label={t(\"topbar.sections\")}>{links}</nav>)}\n </div>\n </div>\n {profileOpen && profileMenu(closeProfile)}\n </div>\n );\n}\n","import { useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { forceCenter, forceCollide, forceLink, forceManyBody, forceSimulation } from \"d3-force\";\nimport { useKitT } from \"../i18n\";\nimport { Icon } from \"./Icon\";\n\nconst W = 760;\nconst H = 500;\n\n/** A node: `group` picks the colour (g-c1…g-c6), `size` the radius. */\nexport type GraphNode = {\n id: string; label: string; title?: string; group?: number; size?: number;\n /** Not in the data of the product, only referred to: a dashed outline. */\n dashed?: boolean;\n /** Context around the shown set: drawn faded. */\n muted?: boolean;\n /** The label shows only on hover, focus or highlight. */\n hideLabel?: boolean;\n /** With `rows` on the graph: the id of the row of the node and its place in it, ascending left to right. */\n row?: string;\n order?: number;\n};\nexport type GraphEdge = { source: string; target: string; weight?: number; directed?: boolean; dashed?: boolean; title?: string };\nexport type GraphSelection = { kind: \"node\"; id: string } | { kind: \"edge\"; source: string; target: string } | null;\n/** A row of the row layout, top to bottom in the order given; the label is drawn at its left. */\nexport type GraphRow = { id: string; label: string };\n\n/** A node with its place; the fields of d3-force are spelled out, so the types of the kit need no d3 types. */\ntype Placed = GraphNode & { r: number; index?: number; x?: number; y?: number; vx?: number; vy?: number; fx?: number | null; fy?: number | null };\ntype Field = { w: number; h: number };\n/** The places of the nodes, the size of the field and, in the row layout, the rows with their middle line. */\ntype Placement = { placed: Placed[]; field: Field; rows?: { id: string; label: string; y: number; x: number; x2: number }[] };\ntype Point = { x: number; y: number };\n\nconst radius = (size = 1) => 7 + Math.sqrt(size) * 3.2;\n\ntype View = { k: number; x: number; y: number };\n/** The view zoomed by `factor`, between 0.5 and 4, keeping the centre of the field in place. */\nconst zoomed = (v: View, factor: number, f: Field): View => {\n const k = Math.max(0.5, Math.min(4, v.k * factor));\n return { k, x: f.w / 2 - ((f.w / 2 - v.x) / v.k) * k, y: f.h / 2 - ((f.h / 2 - v.y) / v.k) * k };\n};\n\n/** Ids within `depth` steps of `from`, edges taken both ways. */\nexport function neighbours(edges: GraphEdge[], from: string, depth: number): Set<string> {\n const near = new Set([from]);\n let frontier = [from];\n for (let d = 0; d < depth; d++) {\n const next: string[] = [];\n for (const id of frontier) {\n for (const e of edges) {\n const other = e.source === id ? e.target : e.target === id ? e.source : null;\n if (other && !near.has(other)) { near.add(other); next.push(other); }\n }\n }\n frontier = next;\n }\n return near;\n}\n\n/** Positions of the nodes (exported for the tests): a force layout computed once per data. The start of\n * d3-force is deterministic, so the same data gives the same picture. */\nexport function layout(nodes: GraphNode[], edges: GraphEdge[]): Placed[] {\n const placed: Placed[] = nodes.map((n) => ({ ...n, r: radius(n.size) }));\n const ids = new Set(placed.map((n) => n.id));\n const links = edges.filter((e) => ids.has(e.source) && ids.has(e.target)).map((e) => ({ source: e.source, target: e.target, weight: e.weight ?? 1 }));\n const sim = forceSimulation(placed)\n .force(\"link\", forceLink<Placed, (typeof links)[number]>(links).id((d) => d.id).distance(90).strength((l) => Math.min(1, 0.2 + l.weight * 0.08)))\n .force(\"charge\", forceManyBody().strength(-260))\n .force(\"center\", forceCenter(W / 2, H / 2))\n .force(\"collide\", forceCollide<Placed>().radius((d) => d.r + 14))\n .stop();\n for (let i = 0; i < 260; i++) sim.tick();\n for (const n of placed) { // keep the labels inside the field\n n.x = Math.max(n.r + 30, Math.min(W - n.r - 30, n.x ?? W / 2));\n n.y = Math.max(n.r + 10, Math.min(H - n.r - 24, n.y ?? H / 2));\n }\n return placed;\n}\n\nconst GUTTER = 130; // the labels of the rows\nconst COL = 104;\nconst ROW = 76;\n\n/** The row layout (FTR.HMR.DEV-0002 R15, exported for the tests): a row per `rows` entry that has nodes, top to\n * bottom in the given order; in a row the nodes by `order`, then id, left to right. A node whose row is not\n * among `rows` goes to a last row without a label. The block is centred in a field at least as big as that of\n * the force layout. */\nexport function rowLayout(nodes: GraphNode[], rows: GraphRow[]): Placement {\n const index = new Map(rows.map((r, i) => [r.id, i]));\n const byRow = new Map<number, Placed[]>();\n const placed: Placed[] = nodes.map((n) => ({ ...n, r: radius(n.size) }));\n for (const n of placed) {\n const i = index.get(n.row ?? \"\") ?? rows.length;\n byRow.set(i, [...(byRow.get(i) ?? []), n]);\n }\n const used = [...byRow.keys()].toSorted((a, b) => a - b);\n const cols = Math.max(1, ...used.map((i) => byRow.get(i)!.length));\n const bw = GUTTER + cols * COL, bh = used.length * ROW;\n const field = { w: Math.max(W, bw + 40), h: Math.max(H, bh + 40) };\n const x0 = (field.w - bw) / 2, y0 = (field.h - bh) / 2;\n const lines = used.map((i, k) => {\n const y = y0 + ROW * (k + 0.5) - 8; // the label under a node takes the lower part of the row\n const inRow = byRow.get(i)!.toSorted((a, b) => (a.order ?? Infinity) - (b.order ?? Infinity) || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));\n inRow.forEach((n, j) => { n.x = x0 + GUTTER + COL * (j + 0.5); n.y = y; });\n return { id: rows[i]?.id ?? \"\", label: rows[i]?.label ?? \"\", y, x: x0 + 8, x2: x0 + bw };\n });\n return { placed, field, rows: lines };\n}\n\n/** The line of an edge: straight, or in the row layout an arc between two nodes of one row — above when it goes\n * right, below when it goes left, so links both ways do not cover each other. A directed line ends at the\n * circle of the target. */\nexport function edgeLine(a: Placed, b: Placed, directed: boolean, arcs: boolean): { d?: string; hit?: string; x1: number; y1: number; x2: number; y2: number } {\n const x1 = a.x ?? 0, y1 = a.y ?? 0;\n const bx = b.x ?? 0, by = b.y ?? 0;\n let x2 = bx, y2 = by;\n const arc = arcs && Math.abs(y2 - y1) < 1 && x1 !== x2;\n const cx = (x1 + x2) / 2;\n const cy = y1 - Math.sign(x2 - x1) * Math.min(ROW * 0.8, 14 + Math.abs(x2 - x1) * 0.25);\n if (directed) {\n const fx = arc ? cx : x1, fy = arc ? cy : y1; // the direction at the end: from the control point of the arc\n const dx = x2 - fx, dy = y2 - fy, len = Math.hypot(dx, dy) || 1;\n x2 -= (dx / len) * (b.r + 2);\n y2 -= (dy / len) * (b.r + 2);\n }\n // the line to click runs to the centre of the target, as the straight one does\n return arc ? { d: `M${x1},${y1} Q${cx},${cy} ${x2},${y2}`, hit: `M${x1},${y1} Q${cx},${cy} ${bx},${by}`, x1, y1, x2, y2 } : { x1, y1, x2, y2 };\n}\n\n/** A graph of nodes and links (FTR.NAB.CMN-0003 R19, FTR.HMR.DEV-0002 R15, R16).\n * Hovering highlights the neighbours, a click pins the selection; the wheel zooms,\n * dragging the field moves it. `focus` highlights a node and its neighbours within `depth`\n * steps; `onOpen` is called on a double click or Enter on a node. With `rows` the nodes stand in\n * rows (`GraphNode.row`, `order`) instead of the force layout; with `draggable` a node can be moved\n * and a button puts the moved nodes back. The kit knows nothing of what the nodes are: labels,\n * rows and the legend come from the product.\n * The layout runs when `nodes`, `edges` or `rows` change identity: keep them stable (useMemo). */\nexport function Graph({ nodes, edges, ariaLabel, selected, onSelect, focus, depth = 1, onOpen, legend, nodeLabel, rows, draggable }: {\n nodes: GraphNode[]; edges: GraphEdge[]; ariaLabel: string;\n selected: GraphSelection; onSelect: (s: GraphSelection) => void;\n focus?: string; depth?: 1 | 2;\n onOpen?: (id: string) => void;\n legend?: { group: number; label: string }[];\n nodeLabel?: (n: GraphNode) => string;\n rows?: GraphRow[];\n draggable?: boolean;\n}) {\n const t = useKitT();\n const arrow = `g-arrow-${useId().replace(/:/g, \"\")}`;\n const [hover, setHover] = useState<string | null>(null);\n const [view, setView] = useState<View>({ k: 1, x: 0, y: 0 });\n const drag = useRef<{ x: number; y: number; moved: boolean } | null>(null);\n const nodeDrag = useRef<{ id: string; x: number; y: number; moved: boolean } | null>(null);\n const movedAt = useRef(-Infinity); // the time of the end of the last move: a double click right after it opens nothing\n const svg = useRef<SVGSVGElement>(null);\n\n const layoutEdges = rows ? undefined : edges; // the rows do not depend on the edges: new edges keep the moved nodes\n const base = useMemo<Placement>(() => (rows ? rowLayout(nodes, rows) : { placed: layout(nodes, layoutEdges ?? []), field: { w: W, h: H } }), [nodes, layoutEdges, rows]);\n const { field } = base;\n // the moved nodes belong to one layout: new data puts every node back in its place\n const [moved, setMoved] = useState<{ of: Placement; at: Map<string, Point> } | null>(null);\n const at = moved?.of === base ? moved.at : undefined;\n const { placed, byId } = useMemo(() => {\n const p = at ? base.placed.map((n) => (at.has(n.id) ? { ...n, ...at.get(n.id) } : n)) : base.placed;\n return { placed: p, byId: new Map(p.map((n) => [n.id, n])) };\n }, [base, at]);\n\n const focused = focus !== undefined && byId.has(focus) ? focus : undefined; // a focus outside the data fades nothing\n const active = hover ?? (selected?.kind === \"node\" ? selected.id : null);\n const near = useMemo(() => {\n if (selected?.kind === \"edge\" && !hover) return new Set([selected.source, selected.target]);\n if (active) return neighbours(edges, active, 1);\n if (focused) return neighbours(edges, focused, depth);\n return new Set<string>();\n }, [active, selected, hover, focused, depth, edges]);\n const dimmed = near.size > 0;\n const edgeOn = (e: GraphEdge) => {\n if (selected?.kind === \"edge\" && !hover) return selected.source === e.source && selected.target === e.target;\n if (active) return e.source === active || e.target === active;\n return focused !== undefined && near.has(e.source) && near.has(e.target);\n };\n\n const zoom = (factor: number) => setView((v) => zoomed(v, factor, field));\n const pick = (id: string, pinned: boolean) => onSelect(pinned ? null : { kind: \"node\", id });\n /** Units of the field per pixel of the screen: the field is fitted into the box keeping its proportions. */\n const unit = (el: Element) => {\n const box = el.getBoundingClientRect();\n return 1 / (Math.min(box.width / field.w, box.height / field.h) || 1);\n };\n\n // The wheel zooms and does not scroll the page: React's onWheel is passive.\n useEffect(() => {\n const el = svg.current;\n if (!el) return;\n const wheel = (e: WheelEvent) => { e.preventDefault(); setView((v) => zoomed(v, e.deltaY < 0 ? 1.15 : 1 / 1.15, field)); };\n el.addEventListener(\"wheel\", wheel, { passive: false });\n return () => el.removeEventListener(\"wheel\", wheel);\n }, [field]);\n\n return (\n <div className=\"gwrap\">\n <svg ref={svg} viewBox={`0 0 ${field.w} ${field.h}`} role=\"group\" aria-label={ariaLabel} className={dimmed ? \"dimmed\" : undefined}\n onPointerDown={(e) => { if (e.target === e.currentTarget) { drag.current = { x: e.clientX, y: e.clientY, moved: false }; e.currentTarget.setPointerCapture(e.pointerId); } }}\n onPointerMove={(e) => {\n if (!drag.current) return;\n const u = unit(e.currentTarget);\n const dx = (e.clientX - drag.current.x) * u;\n const dy = (e.clientY - drag.current.y) * u;\n drag.current = { x: e.clientX, y: e.clientY, moved: drag.current.moved || dx !== 0 || dy !== 0 };\n setView((v) => ({ ...v, x: v.x + dx, y: v.y + dy }));\n }}\n onPointerUp={() => { if (!drag.current?.moved) drag.current = null; }}\n onClick={(e) => {\n const panned = drag.current?.moved; // a pan ends with a click on the field: it keeps the selection\n drag.current = null;\n if (!panned && e.target === e.currentTarget) onSelect(null);\n }}>\n {edges.some((e) => e.directed) && (\n <defs>\n <marker id={arrow} viewBox=\"0 0 10 10\" refX=\"10\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\">\n <path d=\"M0,0 L10,5 L0,10 z\" />\n </marker>\n </defs>\n )}\n <g transform={`translate(${view.x} ${view.y}) scale(${view.k})`}>\n {base.rows?.map((r, i) => (\n <g key={`${r.id}\\u0000${i}`} className=\"g-row\">\n {i > 0 && <line x1={r.x} x2={r.x2} y1={r.y - ROW / 2 + 8} y2={r.y - ROW / 2 + 8} />}\n <text x={r.x} y={r.y}>{r.label}</text>\n </g>\n ))}\n {edges.map((e, i) => {\n const a = byId.get(e.source), b = byId.get(e.target);\n if (!a || !b) return null;\n const l = edgeLine(a, b, !!e.directed, !!rows);\n const marker = e.directed ? `url(#${arrow})` : undefined;\n return (\n <g key={`${e.source}\\u0000${e.target}\\u0000${i}`} className={`g-e${e.dashed ? \" dashed\" : \"\"}${edgeOn(e) ? \" hl\" : \"\"}`}\n onClick={() => onSelect({ kind: \"edge\", source: e.source, target: e.target })}>\n {l.d ? (\n <>\n <path d={l.d} strokeWidth={1 + (e.weight ?? 1) * 0.5} markerEnd={marker} />\n <path className=\"hit\" d={l.hit} />\n </>\n ) : (\n <>\n <line x1={l.x1} y1={l.y1} x2={l.x2} y2={l.y2} strokeWidth={1 + (e.weight ?? 1) * 0.5} markerEnd={marker} />\n <line className=\"hit\" x1={a.x} y1={a.y} x2={b.x} y2={b.y} />\n </>\n )}\n {e.title && <title>{e.title}</title>}\n </g>\n );\n })}\n {placed.map((n) => {\n const pinned = selected?.kind === \"node\" && selected.id === n.id;\n const cls = [\"g-n\", `g-c${n.group ?? 1}`, n.hideLabel && \"small\", n.dashed && \"dashed\", n.muted && \"muted\",\n near.has(n.id) && \"hl\", pinned && \"pin\", focused === n.id && \"focus\"].filter(Boolean).join(\" \");\n return (\n <g key={n.id} className={cls}\n tabIndex={0} role=\"button\" aria-pressed={pinned} aria-label={nodeLabel ? nodeLabel(n) : n.label}\n onMouseEnter={() => setHover(n.id)} onMouseLeave={() => setHover(null)} onFocus={() => setHover(n.id)} onBlur={() => setHover(null)}\n onPointerDown={draggable ? (e) => {\n if (e.button !== 0) return;\n nodeDrag.current = { id: n.id, x: e.clientX, y: e.clientY, moved: false };\n e.currentTarget.setPointerCapture(e.pointerId);\n } : undefined}\n onPointerMove={draggable ? (e) => {\n const d = nodeDrag.current;\n if (!d || d.id !== n.id) return;\n if (!d.moved && Math.hypot(e.clientX - d.x, e.clientY - d.y) < 4) return; // a click is not a move\n const u = svg.current ? unit(svg.current) / view.k : 1;\n const dx = (e.clientX - d.x) * u, dy = (e.clientY - d.y) * u;\n nodeDrag.current = { id: n.id, x: e.clientX, y: e.clientY, moved: true };\n setMoved((m) => {\n const next = new Map(m?.of === base ? m.at : []);\n const p = next.get(n.id) ?? { x: n.x ?? 0, y: n.y ?? 0 };\n next.set(n.id, { x: p.x + dx, y: p.y + dy });\n return { of: base, at: next };\n });\n } : undefined}\n onPointerUp={draggable ? (e) => {\n if (!nodeDrag.current?.moved) return;\n movedAt.current = e.timeStamp;\n // the click that ends a move comes right after: if none comes, the move must not swallow the next one\n setTimeout(() => { nodeDrag.current = null; }, 0);\n } : undefined}\n onPointerCancel={draggable ? () => { nodeDrag.current = null; } : undefined}\n onClick={() => {\n const wasMoved = nodeDrag.current?.moved; // a move ends with a click on the node: it neither pins nor opens\n nodeDrag.current = null;\n if (!wasMoved) pick(n.id, pinned);\n }}\n onDoubleClick={(e) => { if (e.timeStamp - movedAt.current > 600) onOpen?.(n.id); }}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && onOpen) { e.preventDefault(); onOpen(n.id); return; }\n if (e.key === \"Enter\" || e.key === \" \") { e.preventDefault(); pick(n.id, pinned); }\n }}>\n <circle cx={n.x} cy={n.y} r={n.r} />\n <text x={n.x} y={(n.y ?? 0) + n.r + 14}>{n.label}</text>\n {n.title && <title>{n.title}</title>}\n </g>\n );\n })}\n </g>\n </svg>\n {legend && legend.length > 0 && (\n <div className=\"gleg\">{legend.map((l) => <span key={l.group}><i className={`g-c${l.group}`} />{l.label}</span>)}</div>\n )}\n <div className=\"gzoom\">\n <button type=\"button\" onClick={() => zoom(1.3)} aria-label={t(\"graph.zoomIn\")}>+</button>\n <button type=\"button\" onClick={() => zoom(1 / 1.3)} aria-label={t(\"graph.zoomOut\")}>−</button>\n {at && at.size > 0 && (\n <button type=\"button\" onClick={() => setMoved(null)} aria-label={t(\"graph.resetLayout\")} title={t(\"graph.resetLayout\")}>\n <Icon name=\"reset\" size={14} />\n </button>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -149,6 +149,7 @@ export declare const resources: {
149
149
  graph: {
150
150
  zoomIn: string;
151
151
  zoomOut: string;
152
+ resetLayout: string;
152
153
  };
153
154
  };
154
155
  ru: {
@@ -299,6 +300,7 @@ export declare const resources: {
299
300
  graph: {
300
301
  zoomIn: string;
301
302
  zoomOut: string;
303
+ resetLayout: string;
302
304
  };
303
305
  };
304
306
  de: {
@@ -449,6 +451,7 @@ export declare const resources: {
449
451
  graph: {
450
452
  zoomIn: string;
451
453
  zoomOut: string;
454
+ resetLayout: string;
452
455
  };
453
456
  };
454
457
  es: {
@@ -599,6 +602,7 @@ export declare const resources: {
599
602
  graph: {
600
603
  zoomIn: string;
601
604
  zoomOut: string;
605
+ resetLayout: string;
602
606
  };
603
607
  };
604
608
  zh: {
@@ -749,6 +753,7 @@ export declare const resources: {
749
753
  graph: {
750
754
  zoomIn: string;
751
755
  zoomOut: string;
756
+ resetLayout: string;
752
757
  };
753
758
  };
754
759
  };
package/dist/locales.js CHANGED
@@ -147,7 +147,8 @@ var t = {
147
147
  },
148
148
  graph: {
149
149
  zoomIn: "Zoom in",
150
- zoomOut: "Zoom out"
150
+ zoomOut: "Zoom out",
151
+ resetLayout: "Put the nodes back"
151
152
  }
152
153
  },
153
154
  ru: {
@@ -295,7 +296,8 @@ var t = {
295
296
  },
296
297
  graph: {
297
298
  zoomIn: "Приблизить",
298
- zoomOut: "Отдалить"
299
+ zoomOut: "Отдалить",
300
+ resetLayout: "Вернуть узлы на места"
299
301
  }
300
302
  },
301
303
  de: {
@@ -443,7 +445,8 @@ var t = {
443
445
  },
444
446
  graph: {
445
447
  zoomIn: "Vergrößern",
446
- zoomOut: "Verkleinern"
448
+ zoomOut: "Verkleinern",
449
+ resetLayout: "Knoten zurücksetzen"
447
450
  }
448
451
  },
449
452
  es: {
@@ -591,7 +594,8 @@ var t = {
591
594
  },
592
595
  graph: {
593
596
  zoomIn: "Acercar",
594
- zoomOut: "Alejar"
597
+ zoomOut: "Alejar",
598
+ resetLayout: "Devolver los nodos a su sitio"
595
599
  }
596
600
  },
597
601
  zh: {
@@ -739,7 +743,8 @@ var t = {
739
743
  },
740
744
  graph: {
741
745
  zoomIn: "放大",
742
- zoomOut: "缩小"
746
+ zoomOut: "缩小",
747
+ resetLayout: "恢复节点位置"
743
748
  }
744
749
  }
745
750
  };
@@ -1 +1 @@
1
- {"version":3,"file":"locales.js","names":["loading","cancel","create","close","remove","agentName","topbar","chat","agent","graph","loading","cancel","create","close","remove","agentName","topbar","chat","agent","graph","loading","cancel","create","close","remove","agentName","topbar","chat","agent","graph","loading","cancel","create","close","remove","agentName","topbar","chat","agent","graph","UIKIT_NS","resources","\"delete\"","\"sections\"","\"profile\"","\"title\"","\"conversations\"","\"conversation\"","\"topics\"","\"archive\"","\"noTopics\"","\"newTopic\"","\"topicTitle\"","\"topicHint\"","\"loadOlder\"","\"emptyTitle\"","\"placeholder\"","\"send\"","\"attach\"","\"typing\"","\"moreSteps\"","\"hideSteps\"","\"unread\"","\"retry\"","\"tooLarge\"","\"stop\"","\"voice\"","\"hold\"","\"recording\"","\"review\"","\"notRecognized\"","\"micDenied\"","\"unsupported\"","\"start\"","\"done\"","\"recognizing\"","\"recordingNow\"","\"failed\"","\"confirm\"","\"text\"","\"approve\"","\"reject\"","\"wait\"","\"starting\"","\"queued\"","\"palette\"","\"commands\"","\"skills\"","\"noSkills\"","\"empty\"","\"unknownCommand\"","\"sendAsText\"","\"skillPlaceholder\"","\"context\"","\"meter\"","\"full\"","\"compact\"","\"reset\"","\"waitTurn\"","\"waitQueue\"","\"event\"","\"details\"","\"files\"","\"open\"","\"download\"","\"save\"","\"notUtf8\"","\"rows\"","\"source\"","\"page\"","\"converted\"","\"pagesShown\"","\"firstPages\"","\"cols\"","\"preparing\"","\"preparingHint\"","\"unavailable\"","\"formulaHint\"","\"sheets\"","\"reasons\"","\"too_large\"","\"timeout\"","\"broken\"","\"busy\"","\"notice\"","\"more\"","\"less\"","\"queuePlaceholder\"","\"queue\"","\"position\"","\"cancel\"","\"stopAnswer\"","\"stopping\"","\"stopped\"","\"subagents\"","\"tools\"","\"state\"","\"running\"","\"aborted\"","\"turnStopped\"","\"retryQueued\"","\"menu\"","\"options\"","\"model\"","\"modelDefault\"","\"noModels\"","\"modelCompactWarn\"","\"everywhere\"","\"capImage\"","\"capReasoning\"","\"zoomIn\"","\"zoomOut\""],"sources":["../src/locales/en.json","../src/locales/ru.json","../src/locales/de.json","../src/locales/es.json","../src/locales/zh.json","../src/locales/index.ts"],"sourcesContent":["{\n \"loading\": \"Loading…\",\n \"cancel\": \"Cancel\",\n \"create\": \"Create\",\n \"close\": \"Close\",\n \"delete\": \"Delete\",\n \"remove\": \"Remove\",\n \"agentName\": \"Agent name\",\n \"topbar\": {\n \"sections\": \"Sections\",\n \"profile\": \"Profile\"\n },\n \"chat\": {\n \"title\": \"Chat\",\n \"conversations\": \"Conversations\",\n \"conversation\": \"Conversation\",\n \"topics\": \"Topics\",\n \"archive\": \"Archive\",\n \"noTopics\": \"No topics yet\",\n \"newTopic\": \"New topic\",\n \"topicTitle\": \"Topic\",\n \"topicHint\": \"A topic has its own history and the same memory and space.\",\n \"loadOlder\": \"Earlier messages\",\n \"emptyTitle\": \"Hi, I am {name}\",\n \"placeholder\": \"Message {name}…\",\n \"send\": \"Send\",\n \"attach\": \"Attach files\",\n \"typing\": \"The agent is typing\",\n \"moreSteps\": \"{count, plural, one {# more step} other {# more steps}}\",\n \"hideSteps\": \"Hide steps\",\n \"unread\": \"{count, plural, one {# unread answer} other {# unread answers}}\",\n \"retry\": \"Retry\",\n \"tooLarge\": \"The file is too large.\",\n \"stop\": \"Stop\",\n \"voice\": {\n \"hold\": \"Hold to record\",\n \"stop\": \"Stop recording\",\n \"recording\": \"Recording… {seconds} s\",\n \"review\": \"Check the transcript before sending\",\n \"notRecognized\": \"The speech was not recognized\",\n \"micDenied\": \"No access to the microphone\",\n \"unsupported\": \"Voice input is not supported in this browser\",\n \"start\": \"Record a voice message\",\n \"done\": \"Stop\",\n \"recognizing\": \"Recognizing…\",\n \"recordingNow\": \"Recording\",\n \"failed\": \"The voice message could not be recognized\",\n \"retry\": \"Retry\"\n },\n \"confirm\": {\n \"title\": \"Confirm the action\",\n \"text\": \"The agent wants to perform: {action}\",\n \"approve\": \"Execute\",\n \"reject\": \"Reject\"\n },\n \"wait\": {\n \"starting\": \"The agent is starting…\",\n \"queued\": \"{count, plural, =0 {In the queue · you are next} one {In the queue · # ahead of you} other {In the queue · # ahead of you}}\"\n },\n \"palette\": {\n \"title\": \"Commands and skills\",\n \"commands\": \"Commands\",\n \"skills\": \"Skills\",\n \"noSkills\": \"No skills are granted to you\",\n \"empty\": \"Nothing found\"\n },\n \"unknownCommand\": \"Unknown command {name}\",\n \"sendAsText\": \"Send as text\",\n \"skillPlaceholder\": \"What to do with the skill?\",\n \"context\": {\n \"meter\": \"Context: {used} of {total} tokens ({pct}%)\",\n \"full\": \"Answers get more expensive and the agent may get confused.\",\n \"compact\": \"Compact\",\n \"reset\": \"Start over\",\n \"waitTurn\": \"Wait for the answer or stop it\",\n \"waitQueue\": \"Wait for the answers to the queued messages\"\n },\n \"event\": {\n \"details\": \"Summary\"\n },\n \"files\": {\n \"open\": \"Open {name}\",\n \"download\": \"Download\",\n \"failed\": \"Could not open the file\",\n \"tooLarge\": \"The file is too large to preview — download it\",\n \"save\": \"Download {name}\",\n \"notUtf8\": \"The file is not in UTF-8 — download it\",\n \"rows\": \"Showing {shown} of {total, plural, one {# row} other {# rows}}\",\n \"source\": \"Code\",\n \"page\": \"Page\",\n \"converted\": \"Preview · converted from {format}\",\n \"pagesShown\": \"Showing {shown} of {total} pages\",\n \"firstPages\": \"Showing the first {shown} pages\",\n \"cols\": \"and {shown} of {total} columns\",\n \"preparing\": \"Preparing the preview…\",\n \"preparingHint\": \"Usually a few seconds\",\n \"unavailable\": \"Preview unavailable\",\n \"formulaHint\": \"The value is calculated when opened in Excel\",\n \"sheets\": \"Sheets\",\n \"reasons\": {\n \"too_large\": \"The file is over {limit} MB\",\n \"timeout\": \"Took longer than 30 seconds\",\n \"broken\": \"The file is damaged or the format is not supported\",\n \"busy\": \"The service is busy, try again later\"\n }\n },\n \"notice\": {\n \"more\": \"Show in full\",\n \"less\": \"Collapse\"\n },\n \"queuePlaceholder\": \"The message will wait in the queue\",\n \"queue\": {\n \"position\": \"In the queue · {n}\",\n \"cancel\": \"Cancel\"\n },\n \"stopAnswer\": \"Stop the answer\",\n \"stopping\": \"Stopping…\",\n \"stopped\": \"Stopped\",\n \"subagents\": {\n \"title\": \"{count, plural, one {Subagents · #} other {Subagents · #}}\",\n \"done\": \"done\",\n \"failed\": \"{count, plural, one {# not done} other {# not done}}\",\n \"tools\": \"{count, plural, one {# tool} other {# tools}}\",\n \"state\": {\n \"running\": \"running\",\n \"done\": \"done\",\n \"failed\": \"error\",\n \"timeout\": \"stopped · out of time\",\n \"aborted\": \"stopped\",\n \"turnStopped\": \"stopped · the turn was stopped\"\n }\n },\n \"retryQueued\": \"The retry waits in the queue\"\n },\n \"agent\": {\n \"menu\": \"Agent\",\n \"options\": \"Tone\",\n \"model\": \"Model\",\n \"modelDefault\": \"Default\",\n \"noModels\": \"No models granted — ask an administrator\",\n \"modelCompactWarn\": \"The context will be compacted before the next answer\",\n \"everywhere\": \"The change applies in every channel and connected service.\",\n \"capImage\": \"images\",\n \"capReasoning\": \"reasoning\"\n },\n \"graph\": {\n \"zoomIn\": \"Zoom in\",\n \"zoomOut\": \"Zoom out\"\n }\n}\n","{\n \"loading\": \"Загрузка…\",\n \"cancel\": \"Отмена\",\n \"create\": \"Создать\",\n \"close\": \"Закрыть\",\n \"delete\": \"Удалить\",\n \"remove\": \"Убрать\",\n \"agentName\": \"Имя агента\",\n \"topbar\": {\n \"sections\": \"Разделы\",\n \"profile\": \"Профиль\"\n },\n \"chat\": {\n \"title\": \"Чат\",\n \"conversations\": \"Разговоры\",\n \"conversation\": \"Разговор\",\n \"topics\": \"Темы\",\n \"archive\": \"Архив\",\n \"noTopics\": \"Тем пока нет\",\n \"newTopic\": \"Новая тема\",\n \"topicTitle\": \"Тема\",\n \"topicHint\": \"У темы своя история, а память и пространство — те же.\",\n \"loadOlder\": \"Более ранние сообщения\",\n \"emptyTitle\": \"Привет, я {name}\",\n \"placeholder\": \"Сообщение для {name}…\",\n \"send\": \"Отправить\",\n \"attach\": \"Прикрепить файлы\",\n \"typing\": \"Агент печатает\",\n \"moreSteps\": \"{count, plural, one {ещё # шаг} few {ещё # шага} many {ещё # шагов} other {ещё # шага}}\",\n \"hideSteps\": \"Скрыть шаги\",\n \"unread\": \"{count, plural, one {# непрочитанный ответ} few {# непрочитанных ответа} many {# непрочитанных ответов} other {# непрочитанных ответа}}\",\n \"retry\": \"Повторить\",\n \"tooLarge\": \"Файл слишком большой.\",\n \"stop\": \"Остановить\",\n \"voice\": {\n \"hold\": \"Удерживайте для записи\",\n \"stop\": \"Остановить запись\",\n \"recording\": \"Запись… {seconds} с\",\n \"review\": \"Проверьте расшифровку перед отправкой\",\n \"notRecognized\": \"Речь не распознана\",\n \"micDenied\": \"Нет доступа к микрофону\",\n \"unsupported\": \"Голосовой ввод не поддерживается этим браузером\",\n \"start\": \"Записать голосом\",\n \"done\": \"Стоп\",\n \"recognizing\": \"Распознаём…\",\n \"recordingNow\": \"Запись\",\n \"failed\": \"Не удалось распознать голосовое сообщение\",\n \"retry\": \"Повторить\"\n },\n \"confirm\": {\n \"title\": \"Подтвердите действие\",\n \"text\": \"Агент хочет выполнить: {action}\",\n \"approve\": \"Выполнить\",\n \"reject\": \"Отклонить\"\n },\n \"wait\": {\n \"starting\": \"Агент запускается…\",\n \"queued\": \"{count, plural, =0 {В очереди · вы следующий} other {В очереди · перед вами #}}\"\n },\n \"palette\": {\n \"title\": \"Команды и скиллы\",\n \"commands\": \"Команды\",\n \"skills\": \"Скиллы\",\n \"noSkills\": \"Вам не выдан ни один скилл\",\n \"empty\": \"Ничего не найдено\"\n },\n \"unknownCommand\": \"Неизвестная команда {name}\",\n \"sendAsText\": \"Отправить как текст\",\n \"skillPlaceholder\": \"Что сделать по скиллу?\",\n \"context\": {\n \"meter\": \"Контекст: {used} из {total} токенов ({pct} %)\",\n \"full\": \"Ответы дорожают, агент может путаться.\",\n \"compact\": \"Сжать\",\n \"reset\": \"Начать заново\",\n \"waitTurn\": \"Дождитесь ответа или остановите его\",\n \"waitQueue\": \"Дождитесь ответов на сообщения в очереди\"\n },\n \"event\": {\n \"details\": \"Изложение\"\n },\n \"files\": {\n \"open\": \"Открыть {name}\",\n \"download\": \"Скачать\",\n \"failed\": \"Не удалось открыть файл\",\n \"tooLarge\": \"Файл слишком большой для просмотра — скачайте его\",\n \"save\": \"Скачать {name}\",\n \"notUtf8\": \"Файл не в кодировке UTF-8 — скачайте его\",\n \"rows\": \"Показаны {shown} из {total, plural, one {# строки} other {# строк}}\",\n \"source\": \"Код\",\n \"page\": \"Страница\",\n \"converted\": \"Предпросмотр · сконвертировано из {format}\",\n \"pagesShown\": \"Показаны {shown} из {total} страниц\",\n \"firstPages\": \"Показаны первые {shown} страниц\",\n \"cols\": \"и {shown} из {total} столбцов\",\n \"preparing\": \"Готовим предпросмотр…\",\n \"preparingHint\": \"Обычно несколько секунд\",\n \"unavailable\": \"Предпросмотр недоступен\",\n \"formulaHint\": \"Значение посчитается при открытии в Excel\",\n \"sheets\": \"Листы\",\n \"reasons\": {\n \"too_large\": \"Файл больше {limit} МБ\",\n \"timeout\": \"Не успели за 30 секунд\",\n \"broken\": \"Файл повреждён или формат не поддерживается\",\n \"busy\": \"Сервис занят, попробуйте позже\"\n }\n },\n \"notice\": {\n \"more\": \"Показать полностью\",\n \"less\": \"Свернуть\"\n },\n \"queuePlaceholder\": \"Сообщение встанет в очередь\",\n \"queue\": {\n \"position\": \"В очереди · {n}\",\n \"cancel\": \"Отменить\"\n },\n \"stopAnswer\": \"Остановить ответ\",\n \"stopping\": \"Останавливаю…\",\n \"stopped\": \"Остановлено\",\n \"subagents\": {\n \"title\": \"Субагенты · {count}\",\n \"done\": \"готово\",\n \"failed\": \"{count, plural, one {# с ошибкой} few {# с ошибкой} other {# с ошибкой}}\",\n \"tools\": \"{count} инстр.\",\n \"state\": {\n \"running\": \"работает\",\n \"done\": \"готово\",\n \"failed\": \"ошибка\",\n \"timeout\": \"прервано · по времени\",\n \"aborted\": \"прервано\",\n \"turnStopped\": \"прервано · ход остановлен\"\n }\n },\n \"retryQueued\": \"Повтор в очереди\"\n },\n \"agent\": {\n \"menu\": \"Агент\",\n \"options\": \"Тон\",\n \"model\": \"Модель\",\n \"modelDefault\": \"По умолчанию\",\n \"noModels\": \"Модели не выданы — обратитесь к администратору\",\n \"modelCompactWarn\": \"Контекст будет сжат перед следующим ответом\",\n \"everywhere\": \"Изменение действует во всех каналах и подключённых сервисах.\",\n \"capImage\": \"изображения\",\n \"capReasoning\": \"рассуждение\"\n },\n \"graph\": {\n \"zoomIn\": \"Приблизить\",\n \"zoomOut\": \"Отдалить\"\n }\n}\n","{\n \"loading\": \"Wird geladen…\",\n \"cancel\": \"Abbrechen\",\n \"create\": \"Erstellen\",\n \"close\": \"Schließen\",\n \"delete\": \"Löschen\",\n \"remove\": \"Entfernen\",\n \"agentName\": \"Name des Agenten\",\n \"topbar\": {\n \"sections\": \"Bereiche\",\n \"profile\": \"Profil\"\n },\n \"chat\": {\n \"title\": \"Chat\",\n \"conversations\": \"Gespräche\",\n \"conversation\": \"Gespräch\",\n \"topics\": \"Themen\",\n \"archive\": \"Archiv\",\n \"noTopics\": \"Noch keine Themen\",\n \"newTopic\": \"Neues Thema\",\n \"topicTitle\": \"Thema\",\n \"topicHint\": \"Ein Thema hat einen eigenen Verlauf, aber dasselbe Gedächtnis und denselben Arbeitsbereich.\",\n \"loadOlder\": \"Frühere Nachrichten\",\n \"emptyTitle\": \"Hallo, ich bin {name}\",\n \"placeholder\": \"Nachricht an {name}…\",\n \"send\": \"Senden\",\n \"attach\": \"Dateien anhängen\",\n \"typing\": \"Der Agent schreibt\",\n \"moreSteps\": \"{count, plural, one {# weiterer Schritt} other {# weitere Schritte}}\",\n \"hideSteps\": \"Schritte ausblenden\",\n \"unread\": \"{count, plural, one {# ungelesene Antwort} other {# ungelesene Antworten}}\",\n \"retry\": \"Wiederholen\",\n \"tooLarge\": \"Die Datei ist zu groß.\",\n \"stop\": \"Stoppen\",\n \"voice\": {\n \"hold\": \"Zum Aufnehmen gedrückt halten\",\n \"stop\": \"Aufnahme beenden\",\n \"recording\": \"Aufnahme… {seconds} s\",\n \"review\": \"Prüfen Sie die Transkription vor dem Senden\",\n \"notRecognized\": \"Die Sprache wurde nicht erkannt\",\n \"micDenied\": \"Kein Zugriff auf das Mikrofon\",\n \"unsupported\": \"Spracheingabe wird von diesem Browser nicht unterstützt\",\n \"start\": \"Sprachnachricht aufnehmen\",\n \"done\": \"Stopp\",\n \"recognizing\": \"Wird erkannt…\",\n \"recordingNow\": \"Aufnahme\",\n \"failed\": \"Die Sprachnachricht konnte nicht erkannt werden\",\n \"retry\": \"Wiederholen\"\n },\n \"confirm\": {\n \"title\": \"Aktion bestätigen\",\n \"text\": \"Der Agent möchte ausführen: {action}\",\n \"approve\": \"Ausführen\",\n \"reject\": \"Ablehnen\"\n },\n \"wait\": {\n \"starting\": \"Der Agent startet…\",\n \"queued\": \"{count, plural, =0 {In der Warteschlange · Sie sind als Nächstes dran} other {In der Warteschlange · # vor Ihnen}}\"\n },\n \"palette\": {\n \"title\": \"Befehle und Skills\",\n \"commands\": \"Befehle\",\n \"skills\": \"Skills\",\n \"noSkills\": \"Ihnen ist kein Skill freigegeben\",\n \"empty\": \"Nichts gefunden\"\n },\n \"unknownCommand\": \"Unbekannter Befehl {name}\",\n \"sendAsText\": \"Als Text senden\",\n \"skillPlaceholder\": \"Was soll mit dem Skill getan werden?\",\n \"context\": {\n \"meter\": \"Kontext: {used} von {total} Tokens ({pct} %)\",\n \"full\": \"Antworten werden teurer, der Agent kann durcheinanderkommen.\",\n \"compact\": \"Komprimieren\",\n \"reset\": \"Neu beginnen\",\n \"waitTurn\": \"Warten Sie auf die Antwort oder stoppen Sie sie\",\n \"waitQueue\": \"Warten Sie auf die Antworten auf die Nachrichten in der Warteschlange\"\n },\n \"event\": {\n \"details\": \"Zusammenfassung\"\n },\n \"files\": {\n \"open\": \"{name} öffnen\",\n \"download\": \"Herunterladen\",\n \"failed\": \"Die Datei konnte nicht geöffnet werden\",\n \"tooLarge\": \"Die Datei ist zu groß für die Vorschau — bitte herunterladen\",\n \"save\": \"{name} herunterladen\",\n \"notUtf8\": \"Die Datei ist nicht in UTF-8 — bitte herunterladen\",\n \"rows\": \"{shown} von {total, plural, one {# Zeile} other {# Zeilen}} angezeigt\",\n \"source\": \"Code\",\n \"page\": \"Seite\",\n \"converted\": \"Vorschau · konvertiert aus {format}\",\n \"pagesShown\": \"{shown} von {total} Seiten werden angezeigt\",\n \"firstPages\": \"Die ersten {shown} Seiten werden angezeigt\",\n \"cols\": \"und {shown} von {total} Spalten\",\n \"preparing\": \"Vorschau wird vorbereitet…\",\n \"preparingHint\": \"Meist nur wenige Sekunden\",\n \"unavailable\": \"Vorschau nicht verfügbar\",\n \"formulaHint\": \"Der Wert wird beim Öffnen in Excel berechnet\",\n \"sheets\": \"Blätter\",\n \"reasons\": {\n \"too_large\": \"Die Datei ist größer als {limit} MB\",\n \"timeout\": \"Hat länger als 30 Sekunden gedauert\",\n \"broken\": \"Die Datei ist beschädigt oder das Format wird nicht unterstützt\",\n \"busy\": \"Der Dienst ist ausgelastet, versuchen Sie es später erneut\"\n }\n },\n \"notice\": {\n \"more\": \"Vollständig anzeigen\",\n \"less\": \"Einklappen\"\n },\n \"queuePlaceholder\": \"Die Nachricht wartet in der Warteschlange\",\n \"queue\": {\n \"position\": \"In der Warteschlange · {n}\",\n \"cancel\": \"Abbrechen\"\n },\n \"stopAnswer\": \"Antwort stoppen\",\n \"stopping\": \"Wird gestoppt…\",\n \"stopped\": \"Gestoppt\",\n \"subagents\": {\n \"title\": \"Subagenten · {count}\",\n \"done\": \"fertig\",\n \"failed\": \"{count} nicht fertig\",\n \"tools\": \"{count, plural, one {# Werkzeug} other {# Werkzeuge}}\",\n \"state\": {\n \"running\": \"läuft\",\n \"done\": \"fertig\",\n \"failed\": \"Fehler\",\n \"timeout\": \"abgebrochen · Zeit abgelaufen\",\n \"aborted\": \"abgebrochen\",\n \"turnStopped\": \"abgebrochen · Antwort gestoppt\"\n }\n },\n \"retryQueued\": \"Die Wiederholung wartet in der Warteschlange\"\n },\n \"agent\": {\n \"menu\": \"Agent\",\n \"options\": \"Ton\",\n \"model\": \"Modell\",\n \"modelDefault\": \"Standard\",\n \"noModels\": \"Keine Modelle freigegeben — wenden Sie sich an einen Administrator\",\n \"modelCompactWarn\": \"Der Kontext wird vor der nächsten Antwort komprimiert\",\n \"everywhere\": \"Die Änderung gilt in allen Kanälen und verbundenen Diensten.\",\n \"capImage\": \"Bilder\",\n \"capReasoning\": \"Reasoning\"\n },\n \"graph\": {\n \"zoomIn\": \"Vergrößern\",\n \"zoomOut\": \"Verkleinern\"\n }\n}\n","{\n \"loading\": \"Cargando…\",\n \"cancel\": \"Cancelar\",\n \"create\": \"Crear\",\n \"close\": \"Cerrar\",\n \"delete\": \"Eliminar\",\n \"remove\": \"Quitar\",\n \"agentName\": \"Nombre del agente\",\n \"topbar\": {\n \"sections\": \"Secciones\",\n \"profile\": \"Perfil\"\n },\n \"chat\": {\n \"title\": \"Chat\",\n \"conversations\": \"Conversaciones\",\n \"conversation\": \"Conversación\",\n \"topics\": \"Temas\",\n \"archive\": \"Archivo\",\n \"noTopics\": \"Aún no hay temas\",\n \"newTopic\": \"Nuevo tema\",\n \"topicTitle\": \"Tema\",\n \"topicHint\": \"Un tema tiene su propio historial y la misma memoria y espacio.\",\n \"loadOlder\": \"Mensajes anteriores\",\n \"emptyTitle\": \"Hola, soy {name}\",\n \"placeholder\": \"Mensaje para {name}…\",\n \"send\": \"Enviar\",\n \"attach\": \"Adjuntar archivos\",\n \"typing\": \"El agente está escribiendo\",\n \"moreSteps\": \"{count, plural, one {# paso más} other {# pasos más}}\",\n \"hideSteps\": \"Ocultar pasos\",\n \"unread\": \"{count, plural, one {# respuesta sin leer} other {# respuestas sin leer}}\",\n \"retry\": \"Reintentar\",\n \"tooLarge\": \"El archivo es demasiado grande.\",\n \"stop\": \"Detener\",\n \"voice\": {\n \"hold\": \"Mantenga pulsado para grabar\",\n \"stop\": \"Detener la grabación\",\n \"recording\": \"Grabando… {seconds} s\",\n \"review\": \"Revise la transcripción antes de enviar\",\n \"notRecognized\": \"No se reconoció la voz\",\n \"micDenied\": \"Sin acceso al micrófono\",\n \"unsupported\": \"Este navegador no admite la entrada de voz\",\n \"start\": \"Grabar un mensaje de voz\",\n \"done\": \"Detener\",\n \"recognizing\": \"Reconociendo…\",\n \"recordingNow\": \"Grabando\",\n \"failed\": \"No se pudo reconocer el mensaje de voz\",\n \"retry\": \"Reintentar\"\n },\n \"confirm\": {\n \"title\": \"Confirme la acción\",\n \"text\": \"El agente quiere ejecutar: {action}\",\n \"approve\": \"Ejecutar\",\n \"reject\": \"Rechazar\"\n },\n \"wait\": {\n \"starting\": \"El agente se está iniciando…\",\n \"queued\": \"{count, plural, =0 {En cola · usted es el siguiente} other {En cola · # por delante}}\"\n },\n \"palette\": {\n \"title\": \"Comandos y skills\",\n \"commands\": \"Comandos\",\n \"skills\": \"Skills\",\n \"noSkills\": \"No tiene skills disponibles\",\n \"empty\": \"No se encontró nada\"\n },\n \"unknownCommand\": \"Comando desconocido {name}\",\n \"sendAsText\": \"Enviar como texto\",\n \"skillPlaceholder\": \"¿Qué hacer con el skill?\",\n \"context\": {\n \"meter\": \"Contexto: {used} de {total} tokens ({pct} %)\",\n \"full\": \"Las respuestas se encarecen y el agente puede confundirse.\",\n \"compact\": \"Compactar\",\n \"reset\": \"Empezar de nuevo\",\n \"waitTurn\": \"Espere la respuesta o deténgala\",\n \"waitQueue\": \"Espere las respuestas a los mensajes en la cola\"\n },\n \"event\": {\n \"details\": \"Resumen\"\n },\n \"files\": {\n \"open\": \"Abrir {name}\",\n \"download\": \"Descargar\",\n \"failed\": \"No se pudo abrir el archivo\",\n \"tooLarge\": \"El archivo es demasiado grande para la vista previa: descárguelo\",\n \"save\": \"Descargar {name}\",\n \"notUtf8\": \"El archivo no está en UTF-8: descárguelo\",\n \"rows\": \"Se muestran {shown} de {total, plural, one {# fila} other {# filas}}\",\n \"source\": \"Código\",\n \"page\": \"Página\",\n \"converted\": \"Vista previa · convertido desde {format}\",\n \"pagesShown\": \"Se muestran {shown} de {total} páginas\",\n \"firstPages\": \"Se muestran las primeras {shown} páginas\",\n \"cols\": \"y {shown} de {total} columnas\",\n \"preparing\": \"Preparando la vista previa…\",\n \"preparingHint\": \"Suele tardar unos segundos\",\n \"unavailable\": \"Vista previa no disponible\",\n \"formulaHint\": \"El valor se calcula al abrir el archivo en Excel\",\n \"sheets\": \"Hojas\",\n \"reasons\": {\n \"too_large\": \"El archivo supera {limit} MB\",\n \"timeout\": \"Tardó más de 30 segundos\",\n \"broken\": \"El archivo está dañado o el formato no es compatible\",\n \"busy\": \"El servicio está ocupado, inténtalo más tarde\"\n }\n },\n \"notice\": {\n \"more\": \"Mostrar completo\",\n \"less\": \"Contraer\"\n },\n \"queuePlaceholder\": \"El mensaje esperará en la cola\",\n \"queue\": {\n \"position\": \"En la cola · {n}\",\n \"cancel\": \"Cancelar\"\n },\n \"stopAnswer\": \"Detener la respuesta\",\n \"stopping\": \"Deteniendo…\",\n \"stopped\": \"Detenida\",\n \"subagents\": {\n \"title\": \"Subagentes · {count}\",\n \"done\": \"listo\",\n \"failed\": \"{count, plural, one {# sin terminar} other {# sin terminar}}\",\n \"tools\": \"{count, plural, one {# herramienta} other {# herramientas}}\",\n \"state\": {\n \"running\": \"en curso\",\n \"done\": \"listo\",\n \"failed\": \"error\",\n \"timeout\": \"interrumpido · sin tiempo\",\n \"aborted\": \"interrumpido\",\n \"turnStopped\": \"interrumpido · respuesta detenida\"\n }\n },\n \"retryQueued\": \"El reintento espera en la cola\"\n },\n \"agent\": {\n \"menu\": \"Agente\",\n \"options\": \"Tono\",\n \"model\": \"Modelo\",\n \"modelDefault\": \"Predeterminado\",\n \"noModels\": \"No hay modelos disponibles: consulte a un administrador\",\n \"modelCompactWarn\": \"El contexto se compactará antes de la próxima respuesta\",\n \"everywhere\": \"El cambio se aplica en todos los canales y servicios conectados.\",\n \"capImage\": \"imágenes\",\n \"capReasoning\": \"razonamiento\"\n },\n \"graph\": {\n \"zoomIn\": \"Acercar\",\n \"zoomOut\": \"Alejar\"\n }\n}\n","{\n \"loading\": \"加载中…\",\n \"cancel\": \"取消\",\n \"create\": \"创建\",\n \"close\": \"关闭\",\n \"delete\": \"删除\",\n \"remove\": \"移除\",\n \"agentName\": \"智能体名称\",\n \"topbar\": {\n \"sections\": \"栏目\",\n \"profile\": \"个人资料\"\n },\n \"chat\": {\n \"title\": \"聊天\",\n \"conversations\": \"对话\",\n \"conversation\": \"对话\",\n \"topics\": \"话题\",\n \"archive\": \"归档\",\n \"noTopics\": \"暂无话题\",\n \"newTopic\": \"新话题\",\n \"topicTitle\": \"话题\",\n \"topicHint\": \"话题有独立的历史记录,记忆和空间与主对话相同。\",\n \"loadOlder\": \"更早的消息\",\n \"emptyTitle\": \"你好,我是 {name}\",\n \"placeholder\": \"给 {name} 发消息…\",\n \"send\": \"发送\",\n \"attach\": \"附加文件\",\n \"typing\": \"智能体正在输入\",\n \"moreSteps\": \"{count, plural, other {另外 # 个步骤}}\",\n \"hideSteps\": \"隐藏步骤\",\n \"unread\": \"{count} 条未读回复\",\n \"retry\": \"重试\",\n \"tooLarge\": \"文件太大。\",\n \"stop\": \"停止\",\n \"voice\": {\n \"hold\": \"按住录音\",\n \"stop\": \"停止录音\",\n \"recording\": \"录音中… {seconds} 秒\",\n \"review\": \"发送前请检查转写文本\",\n \"notRecognized\": \"未能识别语音\",\n \"micDenied\": \"无法访问麦克风\",\n \"unsupported\": \"此浏览器不支持语音输入\",\n \"start\": \"录制语音\",\n \"done\": \"停止\",\n \"recognizing\": \"正在识别…\",\n \"recordingNow\": \"录音中\",\n \"failed\": \"无法识别语音消息\",\n \"retry\": \"重试\"\n },\n \"confirm\": {\n \"title\": \"确认操作\",\n \"text\": \"代理想要执行:{action}\",\n \"approve\": \"执行\",\n \"reject\": \"拒绝\"\n },\n \"wait\": {\n \"starting\": \"代理正在启动…\",\n \"queued\": \"{count, plural, =0 {排队中 · 您是下一位} other {排队中 · 前面还有 # 位}}\"\n },\n \"palette\": {\n \"title\": \"命令和技能\",\n \"commands\": \"命令\",\n \"skills\": \"技能\",\n \"noSkills\": \"您没有可用的技能\",\n \"empty\": \"未找到\"\n },\n \"unknownCommand\": \"未知命令 {name}\",\n \"sendAsText\": \"作为文本发送\",\n \"skillPlaceholder\": \"用这个技能做什么?\",\n \"context\": {\n \"meter\": \"上下文:{used} / {total} 个令牌({pct}%)\",\n \"full\": \"回答变得更贵,代理可能会混淆。\",\n \"compact\": \"压缩\",\n \"reset\": \"重新开始\",\n \"waitTurn\": \"请等待回答或停止它\",\n \"waitQueue\": \"请等待队列中消息的回答\"\n },\n \"event\": {\n \"details\": \"摘要\"\n },\n \"files\": {\n \"open\": \"打开 {name}\",\n \"download\": \"下载\",\n \"failed\": \"无法打开文件\",\n \"tooLarge\": \"文件太大,无法预览,请下载\",\n \"save\": \"下载 {name}\",\n \"notUtf8\": \"文件不是 UTF-8 编码,请下载\",\n \"rows\": \"显示 {total} 行中的 {shown} 行\",\n \"source\": \"代码\",\n \"page\": \"页面\",\n \"converted\": \"预览 · 由 {format} 转换\",\n \"pagesShown\": \"显示 {shown} / {total} 页\",\n \"firstPages\": \"显示前 {shown} 页\",\n \"cols\": \"以及 {shown} / {total} 列\",\n \"preparing\": \"正在准备预览…\",\n \"preparingHint\": \"通常只需几秒\",\n \"unavailable\": \"无法预览\",\n \"formulaHint\": \"在 Excel 中打开时计算该值\",\n \"sheets\": \"工作表\",\n \"reasons\": {\n \"too_large\": \"文件大于 {limit} MB\",\n \"timeout\": \"超过 30 秒未完成\",\n \"broken\": \"文件已损坏或格式不受支持\",\n \"busy\": \"服务繁忙,请稍后重试\"\n }\n },\n \"notice\": {\n \"more\": \"显示全部\",\n \"less\": \"收起\"\n },\n \"queuePlaceholder\": \"消息将在队列中等待\",\n \"queue\": {\n \"position\": \"排队中 · {n}\",\n \"cancel\": \"取消\"\n },\n \"stopAnswer\": \"停止回答\",\n \"stopping\": \"正在停止…\",\n \"stopped\": \"已停止\",\n \"subagents\": {\n \"title\": \"子代理 · {count}\",\n \"done\": \"完成\",\n \"failed\": \"{count} 个未完成\",\n \"tools\": \"{count} 个工具\",\n \"state\": {\n \"running\": \"运行中\",\n \"done\": \"完成\",\n \"failed\": \"错误\",\n \"timeout\": \"已中断 · 超时\",\n \"aborted\": \"已中断\",\n \"turnStopped\": \"已中断 · 回答已停止\"\n }\n },\n \"retryQueued\": \"重试正在队列中等待\"\n },\n \"agent\": {\n \"menu\": \"智能体\",\n \"options\": \"语气\",\n \"model\": \"模型\",\n \"modelDefault\": \"默认\",\n \"noModels\": \"没有可用的模型——请联系管理员\",\n \"modelCompactWarn\": \"下次回答前将压缩上下文\",\n \"everywhere\": \"更改在所有渠道和已连接的服务中生效。\",\n \"capImage\": \"图片\",\n \"capReasoning\": \"推理\"\n },\n \"graph\": {\n \"zoomIn\": \"放大\",\n \"zoomOut\": \"缩小\"\n }\n}\n","import en from \"./en.json\";\nimport ru from \"./ru.json\";\nimport de from \"./de.json\";\nimport es from \"./es.json\";\nimport zh from \"./zh.json\";\n\n/** Strings of the components in the five languages of the products. A product adds\n * them to its i18next instance under the namespace `uikit`. */\nexport const resources = { en, ru, de, es, zh };\nexport type KitLanguage = keyof typeof resources;\nexport { UIKIT_NS } from \"../i18n\";\n"],"mappings":";;;AKQA,IAAayC,IAAY;CAAE,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;CAAI,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;CAAI,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;CAAI,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;CAAI,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;AAAG"}
1
+ {"version":3,"file":"locales.js","names":["loading","cancel","create","close","remove","agentName","topbar","chat","agent","graph","loading","cancel","create","close","remove","agentName","topbar","chat","agent","graph","loading","cancel","create","close","remove","agentName","topbar","chat","agent","graph","loading","cancel","create","close","remove","agentName","topbar","chat","agent","graph","UIKIT_NS","resources","\"delete\"","\"sections\"","\"profile\"","\"title\"","\"conversations\"","\"conversation\"","\"topics\"","\"archive\"","\"noTopics\"","\"newTopic\"","\"topicTitle\"","\"topicHint\"","\"loadOlder\"","\"emptyTitle\"","\"placeholder\"","\"send\"","\"attach\"","\"typing\"","\"moreSteps\"","\"hideSteps\"","\"unread\"","\"retry\"","\"tooLarge\"","\"stop\"","\"voice\"","\"hold\"","\"recording\"","\"review\"","\"notRecognized\"","\"micDenied\"","\"unsupported\"","\"start\"","\"done\"","\"recognizing\"","\"recordingNow\"","\"failed\"","\"confirm\"","\"text\"","\"approve\"","\"reject\"","\"wait\"","\"starting\"","\"queued\"","\"palette\"","\"commands\"","\"skills\"","\"noSkills\"","\"empty\"","\"unknownCommand\"","\"sendAsText\"","\"skillPlaceholder\"","\"context\"","\"meter\"","\"full\"","\"compact\"","\"reset\"","\"waitTurn\"","\"waitQueue\"","\"event\"","\"details\"","\"files\"","\"open\"","\"download\"","\"save\"","\"notUtf8\"","\"rows\"","\"source\"","\"page\"","\"converted\"","\"pagesShown\"","\"firstPages\"","\"cols\"","\"preparing\"","\"preparingHint\"","\"unavailable\"","\"formulaHint\"","\"sheets\"","\"reasons\"","\"too_large\"","\"timeout\"","\"broken\"","\"busy\"","\"notice\"","\"more\"","\"less\"","\"queuePlaceholder\"","\"queue\"","\"position\"","\"cancel\"","\"stopAnswer\"","\"stopping\"","\"stopped\"","\"subagents\"","\"tools\"","\"state\"","\"running\"","\"aborted\"","\"turnStopped\"","\"retryQueued\"","\"menu\"","\"options\"","\"model\"","\"modelDefault\"","\"noModels\"","\"modelCompactWarn\"","\"everywhere\"","\"capImage\"","\"capReasoning\"","\"zoomIn\"","\"zoomOut\"","\"resetLayout\""],"sources":["../src/locales/en.json","../src/locales/ru.json","../src/locales/de.json","../src/locales/es.json","../src/locales/zh.json","../src/locales/index.ts"],"sourcesContent":["{\n \"loading\": \"Loading…\",\n \"cancel\": \"Cancel\",\n \"create\": \"Create\",\n \"close\": \"Close\",\n \"delete\": \"Delete\",\n \"remove\": \"Remove\",\n \"agentName\": \"Agent name\",\n \"topbar\": {\n \"sections\": \"Sections\",\n \"profile\": \"Profile\"\n },\n \"chat\": {\n \"title\": \"Chat\",\n \"conversations\": \"Conversations\",\n \"conversation\": \"Conversation\",\n \"topics\": \"Topics\",\n \"archive\": \"Archive\",\n \"noTopics\": \"No topics yet\",\n \"newTopic\": \"New topic\",\n \"topicTitle\": \"Topic\",\n \"topicHint\": \"A topic has its own history and the same memory and space.\",\n \"loadOlder\": \"Earlier messages\",\n \"emptyTitle\": \"Hi, I am {name}\",\n \"placeholder\": \"Message {name}…\",\n \"send\": \"Send\",\n \"attach\": \"Attach files\",\n \"typing\": \"The agent is typing\",\n \"moreSteps\": \"{count, plural, one {# more step} other {# more steps}}\",\n \"hideSteps\": \"Hide steps\",\n \"unread\": \"{count, plural, one {# unread answer} other {# unread answers}}\",\n \"retry\": \"Retry\",\n \"tooLarge\": \"The file is too large.\",\n \"stop\": \"Stop\",\n \"voice\": {\n \"hold\": \"Hold to record\",\n \"stop\": \"Stop recording\",\n \"recording\": \"Recording… {seconds} s\",\n \"review\": \"Check the transcript before sending\",\n \"notRecognized\": \"The speech was not recognized\",\n \"micDenied\": \"No access to the microphone\",\n \"unsupported\": \"Voice input is not supported in this browser\",\n \"start\": \"Record a voice message\",\n \"done\": \"Stop\",\n \"recognizing\": \"Recognizing…\",\n \"recordingNow\": \"Recording\",\n \"failed\": \"The voice message could not be recognized\",\n \"retry\": \"Retry\"\n },\n \"confirm\": {\n \"title\": \"Confirm the action\",\n \"text\": \"The agent wants to perform: {action}\",\n \"approve\": \"Execute\",\n \"reject\": \"Reject\"\n },\n \"wait\": {\n \"starting\": \"The agent is starting…\",\n \"queued\": \"{count, plural, =0 {In the queue · you are next} one {In the queue · # ahead of you} other {In the queue · # ahead of you}}\"\n },\n \"palette\": {\n \"title\": \"Commands and skills\",\n \"commands\": \"Commands\",\n \"skills\": \"Skills\",\n \"noSkills\": \"No skills are granted to you\",\n \"empty\": \"Nothing found\"\n },\n \"unknownCommand\": \"Unknown command {name}\",\n \"sendAsText\": \"Send as text\",\n \"skillPlaceholder\": \"What to do with the skill?\",\n \"context\": {\n \"meter\": \"Context: {used} of {total} tokens ({pct}%)\",\n \"full\": \"Answers get more expensive and the agent may get confused.\",\n \"compact\": \"Compact\",\n \"reset\": \"Start over\",\n \"waitTurn\": \"Wait for the answer or stop it\",\n \"waitQueue\": \"Wait for the answers to the queued messages\"\n },\n \"event\": {\n \"details\": \"Summary\"\n },\n \"files\": {\n \"open\": \"Open {name}\",\n \"download\": \"Download\",\n \"failed\": \"Could not open the file\",\n \"tooLarge\": \"The file is too large to preview — download it\",\n \"save\": \"Download {name}\",\n \"notUtf8\": \"The file is not in UTF-8 — download it\",\n \"rows\": \"Showing {shown} of {total, plural, one {# row} other {# rows}}\",\n \"source\": \"Code\",\n \"page\": \"Page\",\n \"converted\": \"Preview · converted from {format}\",\n \"pagesShown\": \"Showing {shown} of {total} pages\",\n \"firstPages\": \"Showing the first {shown} pages\",\n \"cols\": \"and {shown} of {total} columns\",\n \"preparing\": \"Preparing the preview…\",\n \"preparingHint\": \"Usually a few seconds\",\n \"unavailable\": \"Preview unavailable\",\n \"formulaHint\": \"The value is calculated when opened in Excel\",\n \"sheets\": \"Sheets\",\n \"reasons\": {\n \"too_large\": \"The file is over {limit} MB\",\n \"timeout\": \"Took longer than 30 seconds\",\n \"broken\": \"The file is damaged or the format is not supported\",\n \"busy\": \"The service is busy, try again later\"\n }\n },\n \"notice\": {\n \"more\": \"Show in full\",\n \"less\": \"Collapse\"\n },\n \"queuePlaceholder\": \"The message will wait in the queue\",\n \"queue\": {\n \"position\": \"In the queue · {n}\",\n \"cancel\": \"Cancel\"\n },\n \"stopAnswer\": \"Stop the answer\",\n \"stopping\": \"Stopping…\",\n \"stopped\": \"Stopped\",\n \"subagents\": {\n \"title\": \"{count, plural, one {Subagents · #} other {Subagents · #}}\",\n \"done\": \"done\",\n \"failed\": \"{count, plural, one {# not done} other {# not done}}\",\n \"tools\": \"{count, plural, one {# tool} other {# tools}}\",\n \"state\": {\n \"running\": \"running\",\n \"done\": \"done\",\n \"failed\": \"error\",\n \"timeout\": \"stopped · out of time\",\n \"aborted\": \"stopped\",\n \"turnStopped\": \"stopped · the turn was stopped\"\n }\n },\n \"retryQueued\": \"The retry waits in the queue\"\n },\n \"agent\": {\n \"menu\": \"Agent\",\n \"options\": \"Tone\",\n \"model\": \"Model\",\n \"modelDefault\": \"Default\",\n \"noModels\": \"No models granted — ask an administrator\",\n \"modelCompactWarn\": \"The context will be compacted before the next answer\",\n \"everywhere\": \"The change applies in every channel and connected service.\",\n \"capImage\": \"images\",\n \"capReasoning\": \"reasoning\"\n },\n \"graph\": {\n \"zoomIn\": \"Zoom in\",\n \"zoomOut\": \"Zoom out\",\n \"resetLayout\": \"Put the nodes back\"\n }\n}\n","{\n \"loading\": \"Загрузка…\",\n \"cancel\": \"Отмена\",\n \"create\": \"Создать\",\n \"close\": \"Закрыть\",\n \"delete\": \"Удалить\",\n \"remove\": \"Убрать\",\n \"agentName\": \"Имя агента\",\n \"topbar\": {\n \"sections\": \"Разделы\",\n \"profile\": \"Профиль\"\n },\n \"chat\": {\n \"title\": \"Чат\",\n \"conversations\": \"Разговоры\",\n \"conversation\": \"Разговор\",\n \"topics\": \"Темы\",\n \"archive\": \"Архив\",\n \"noTopics\": \"Тем пока нет\",\n \"newTopic\": \"Новая тема\",\n \"topicTitle\": \"Тема\",\n \"topicHint\": \"У темы своя история, а память и пространство — те же.\",\n \"loadOlder\": \"Более ранние сообщения\",\n \"emptyTitle\": \"Привет, я {name}\",\n \"placeholder\": \"Сообщение для {name}…\",\n \"send\": \"Отправить\",\n \"attach\": \"Прикрепить файлы\",\n \"typing\": \"Агент печатает\",\n \"moreSteps\": \"{count, plural, one {ещё # шаг} few {ещё # шага} many {ещё # шагов} other {ещё # шага}}\",\n \"hideSteps\": \"Скрыть шаги\",\n \"unread\": \"{count, plural, one {# непрочитанный ответ} few {# непрочитанных ответа} many {# непрочитанных ответов} other {# непрочитанных ответа}}\",\n \"retry\": \"Повторить\",\n \"tooLarge\": \"Файл слишком большой.\",\n \"stop\": \"Остановить\",\n \"voice\": {\n \"hold\": \"Удерживайте для записи\",\n \"stop\": \"Остановить запись\",\n \"recording\": \"Запись… {seconds} с\",\n \"review\": \"Проверьте расшифровку перед отправкой\",\n \"notRecognized\": \"Речь не распознана\",\n \"micDenied\": \"Нет доступа к микрофону\",\n \"unsupported\": \"Голосовой ввод не поддерживается этим браузером\",\n \"start\": \"Записать голосом\",\n \"done\": \"Стоп\",\n \"recognizing\": \"Распознаём…\",\n \"recordingNow\": \"Запись\",\n \"failed\": \"Не удалось распознать голосовое сообщение\",\n \"retry\": \"Повторить\"\n },\n \"confirm\": {\n \"title\": \"Подтвердите действие\",\n \"text\": \"Агент хочет выполнить: {action}\",\n \"approve\": \"Выполнить\",\n \"reject\": \"Отклонить\"\n },\n \"wait\": {\n \"starting\": \"Агент запускается…\",\n \"queued\": \"{count, plural, =0 {В очереди · вы следующий} other {В очереди · перед вами #}}\"\n },\n \"palette\": {\n \"title\": \"Команды и скиллы\",\n \"commands\": \"Команды\",\n \"skills\": \"Скиллы\",\n \"noSkills\": \"Вам не выдан ни один скилл\",\n \"empty\": \"Ничего не найдено\"\n },\n \"unknownCommand\": \"Неизвестная команда {name}\",\n \"sendAsText\": \"Отправить как текст\",\n \"skillPlaceholder\": \"Что сделать по скиллу?\",\n \"context\": {\n \"meter\": \"Контекст: {used} из {total} токенов ({pct} %)\",\n \"full\": \"Ответы дорожают, агент может путаться.\",\n \"compact\": \"Сжать\",\n \"reset\": \"Начать заново\",\n \"waitTurn\": \"Дождитесь ответа или остановите его\",\n \"waitQueue\": \"Дождитесь ответов на сообщения в очереди\"\n },\n \"event\": {\n \"details\": \"Изложение\"\n },\n \"files\": {\n \"open\": \"Открыть {name}\",\n \"download\": \"Скачать\",\n \"failed\": \"Не удалось открыть файл\",\n \"tooLarge\": \"Файл слишком большой для просмотра — скачайте его\",\n \"save\": \"Скачать {name}\",\n \"notUtf8\": \"Файл не в кодировке UTF-8 — скачайте его\",\n \"rows\": \"Показаны {shown} из {total, plural, one {# строки} other {# строк}}\",\n \"source\": \"Код\",\n \"page\": \"Страница\",\n \"converted\": \"Предпросмотр · сконвертировано из {format}\",\n \"pagesShown\": \"Показаны {shown} из {total} страниц\",\n \"firstPages\": \"Показаны первые {shown} страниц\",\n \"cols\": \"и {shown} из {total} столбцов\",\n \"preparing\": \"Готовим предпросмотр…\",\n \"preparingHint\": \"Обычно несколько секунд\",\n \"unavailable\": \"Предпросмотр недоступен\",\n \"formulaHint\": \"Значение посчитается при открытии в Excel\",\n \"sheets\": \"Листы\",\n \"reasons\": {\n \"too_large\": \"Файл больше {limit} МБ\",\n \"timeout\": \"Не успели за 30 секунд\",\n \"broken\": \"Файл повреждён или формат не поддерживается\",\n \"busy\": \"Сервис занят, попробуйте позже\"\n }\n },\n \"notice\": {\n \"more\": \"Показать полностью\",\n \"less\": \"Свернуть\"\n },\n \"queuePlaceholder\": \"Сообщение встанет в очередь\",\n \"queue\": {\n \"position\": \"В очереди · {n}\",\n \"cancel\": \"Отменить\"\n },\n \"stopAnswer\": \"Остановить ответ\",\n \"stopping\": \"Останавливаю…\",\n \"stopped\": \"Остановлено\",\n \"subagents\": {\n \"title\": \"Субагенты · {count}\",\n \"done\": \"готово\",\n \"failed\": \"{count, plural, one {# с ошибкой} few {# с ошибкой} other {# с ошибкой}}\",\n \"tools\": \"{count} инстр.\",\n \"state\": {\n \"running\": \"работает\",\n \"done\": \"готово\",\n \"failed\": \"ошибка\",\n \"timeout\": \"прервано · по времени\",\n \"aborted\": \"прервано\",\n \"turnStopped\": \"прервано · ход остановлен\"\n }\n },\n \"retryQueued\": \"Повтор в очереди\"\n },\n \"agent\": {\n \"menu\": \"Агент\",\n \"options\": \"Тон\",\n \"model\": \"Модель\",\n \"modelDefault\": \"По умолчанию\",\n \"noModels\": \"Модели не выданы — обратитесь к администратору\",\n \"modelCompactWarn\": \"Контекст будет сжат перед следующим ответом\",\n \"everywhere\": \"Изменение действует во всех каналах и подключённых сервисах.\",\n \"capImage\": \"изображения\",\n \"capReasoning\": \"рассуждение\"\n },\n \"graph\": {\n \"zoomIn\": \"Приблизить\",\n \"zoomOut\": \"Отдалить\",\n \"resetLayout\": \"Вернуть узлы на места\"\n }\n}\n","{\n \"loading\": \"Wird geladen…\",\n \"cancel\": \"Abbrechen\",\n \"create\": \"Erstellen\",\n \"close\": \"Schließen\",\n \"delete\": \"Löschen\",\n \"remove\": \"Entfernen\",\n \"agentName\": \"Name des Agenten\",\n \"topbar\": {\n \"sections\": \"Bereiche\",\n \"profile\": \"Profil\"\n },\n \"chat\": {\n \"title\": \"Chat\",\n \"conversations\": \"Gespräche\",\n \"conversation\": \"Gespräch\",\n \"topics\": \"Themen\",\n \"archive\": \"Archiv\",\n \"noTopics\": \"Noch keine Themen\",\n \"newTopic\": \"Neues Thema\",\n \"topicTitle\": \"Thema\",\n \"topicHint\": \"Ein Thema hat einen eigenen Verlauf, aber dasselbe Gedächtnis und denselben Arbeitsbereich.\",\n \"loadOlder\": \"Frühere Nachrichten\",\n \"emptyTitle\": \"Hallo, ich bin {name}\",\n \"placeholder\": \"Nachricht an {name}…\",\n \"send\": \"Senden\",\n \"attach\": \"Dateien anhängen\",\n \"typing\": \"Der Agent schreibt\",\n \"moreSteps\": \"{count, plural, one {# weiterer Schritt} other {# weitere Schritte}}\",\n \"hideSteps\": \"Schritte ausblenden\",\n \"unread\": \"{count, plural, one {# ungelesene Antwort} other {# ungelesene Antworten}}\",\n \"retry\": \"Wiederholen\",\n \"tooLarge\": \"Die Datei ist zu groß.\",\n \"stop\": \"Stoppen\",\n \"voice\": {\n \"hold\": \"Zum Aufnehmen gedrückt halten\",\n \"stop\": \"Aufnahme beenden\",\n \"recording\": \"Aufnahme… {seconds} s\",\n \"review\": \"Prüfen Sie die Transkription vor dem Senden\",\n \"notRecognized\": \"Die Sprache wurde nicht erkannt\",\n \"micDenied\": \"Kein Zugriff auf das Mikrofon\",\n \"unsupported\": \"Spracheingabe wird von diesem Browser nicht unterstützt\",\n \"start\": \"Sprachnachricht aufnehmen\",\n \"done\": \"Stopp\",\n \"recognizing\": \"Wird erkannt…\",\n \"recordingNow\": \"Aufnahme\",\n \"failed\": \"Die Sprachnachricht konnte nicht erkannt werden\",\n \"retry\": \"Wiederholen\"\n },\n \"confirm\": {\n \"title\": \"Aktion bestätigen\",\n \"text\": \"Der Agent möchte ausführen: {action}\",\n \"approve\": \"Ausführen\",\n \"reject\": \"Ablehnen\"\n },\n \"wait\": {\n \"starting\": \"Der Agent startet…\",\n \"queued\": \"{count, plural, =0 {In der Warteschlange · Sie sind als Nächstes dran} other {In der Warteschlange · # vor Ihnen}}\"\n },\n \"palette\": {\n \"title\": \"Befehle und Skills\",\n \"commands\": \"Befehle\",\n \"skills\": \"Skills\",\n \"noSkills\": \"Ihnen ist kein Skill freigegeben\",\n \"empty\": \"Nichts gefunden\"\n },\n \"unknownCommand\": \"Unbekannter Befehl {name}\",\n \"sendAsText\": \"Als Text senden\",\n \"skillPlaceholder\": \"Was soll mit dem Skill getan werden?\",\n \"context\": {\n \"meter\": \"Kontext: {used} von {total} Tokens ({pct} %)\",\n \"full\": \"Antworten werden teurer, der Agent kann durcheinanderkommen.\",\n \"compact\": \"Komprimieren\",\n \"reset\": \"Neu beginnen\",\n \"waitTurn\": \"Warten Sie auf die Antwort oder stoppen Sie sie\",\n \"waitQueue\": \"Warten Sie auf die Antworten auf die Nachrichten in der Warteschlange\"\n },\n \"event\": {\n \"details\": \"Zusammenfassung\"\n },\n \"files\": {\n \"open\": \"{name} öffnen\",\n \"download\": \"Herunterladen\",\n \"failed\": \"Die Datei konnte nicht geöffnet werden\",\n \"tooLarge\": \"Die Datei ist zu groß für die Vorschau — bitte herunterladen\",\n \"save\": \"{name} herunterladen\",\n \"notUtf8\": \"Die Datei ist nicht in UTF-8 — bitte herunterladen\",\n \"rows\": \"{shown} von {total, plural, one {# Zeile} other {# Zeilen}} angezeigt\",\n \"source\": \"Code\",\n \"page\": \"Seite\",\n \"converted\": \"Vorschau · konvertiert aus {format}\",\n \"pagesShown\": \"{shown} von {total} Seiten werden angezeigt\",\n \"firstPages\": \"Die ersten {shown} Seiten werden angezeigt\",\n \"cols\": \"und {shown} von {total} Spalten\",\n \"preparing\": \"Vorschau wird vorbereitet…\",\n \"preparingHint\": \"Meist nur wenige Sekunden\",\n \"unavailable\": \"Vorschau nicht verfügbar\",\n \"formulaHint\": \"Der Wert wird beim Öffnen in Excel berechnet\",\n \"sheets\": \"Blätter\",\n \"reasons\": {\n \"too_large\": \"Die Datei ist größer als {limit} MB\",\n \"timeout\": \"Hat länger als 30 Sekunden gedauert\",\n \"broken\": \"Die Datei ist beschädigt oder das Format wird nicht unterstützt\",\n \"busy\": \"Der Dienst ist ausgelastet, versuchen Sie es später erneut\"\n }\n },\n \"notice\": {\n \"more\": \"Vollständig anzeigen\",\n \"less\": \"Einklappen\"\n },\n \"queuePlaceholder\": \"Die Nachricht wartet in der Warteschlange\",\n \"queue\": {\n \"position\": \"In der Warteschlange · {n}\",\n \"cancel\": \"Abbrechen\"\n },\n \"stopAnswer\": \"Antwort stoppen\",\n \"stopping\": \"Wird gestoppt…\",\n \"stopped\": \"Gestoppt\",\n \"subagents\": {\n \"title\": \"Subagenten · {count}\",\n \"done\": \"fertig\",\n \"failed\": \"{count} nicht fertig\",\n \"tools\": \"{count, plural, one {# Werkzeug} other {# Werkzeuge}}\",\n \"state\": {\n \"running\": \"läuft\",\n \"done\": \"fertig\",\n \"failed\": \"Fehler\",\n \"timeout\": \"abgebrochen · Zeit abgelaufen\",\n \"aborted\": \"abgebrochen\",\n \"turnStopped\": \"abgebrochen · Antwort gestoppt\"\n }\n },\n \"retryQueued\": \"Die Wiederholung wartet in der Warteschlange\"\n },\n \"agent\": {\n \"menu\": \"Agent\",\n \"options\": \"Ton\",\n \"model\": \"Modell\",\n \"modelDefault\": \"Standard\",\n \"noModels\": \"Keine Modelle freigegeben — wenden Sie sich an einen Administrator\",\n \"modelCompactWarn\": \"Der Kontext wird vor der nächsten Antwort komprimiert\",\n \"everywhere\": \"Die Änderung gilt in allen Kanälen und verbundenen Diensten.\",\n \"capImage\": \"Bilder\",\n \"capReasoning\": \"Reasoning\"\n },\n \"graph\": {\n \"zoomIn\": \"Vergrößern\",\n \"zoomOut\": \"Verkleinern\",\n \"resetLayout\": \"Knoten zurücksetzen\"\n }\n}\n","{\n \"loading\": \"Cargando…\",\n \"cancel\": \"Cancelar\",\n \"create\": \"Crear\",\n \"close\": \"Cerrar\",\n \"delete\": \"Eliminar\",\n \"remove\": \"Quitar\",\n \"agentName\": \"Nombre del agente\",\n \"topbar\": {\n \"sections\": \"Secciones\",\n \"profile\": \"Perfil\"\n },\n \"chat\": {\n \"title\": \"Chat\",\n \"conversations\": \"Conversaciones\",\n \"conversation\": \"Conversación\",\n \"topics\": \"Temas\",\n \"archive\": \"Archivo\",\n \"noTopics\": \"Aún no hay temas\",\n \"newTopic\": \"Nuevo tema\",\n \"topicTitle\": \"Tema\",\n \"topicHint\": \"Un tema tiene su propio historial y la misma memoria y espacio.\",\n \"loadOlder\": \"Mensajes anteriores\",\n \"emptyTitle\": \"Hola, soy {name}\",\n \"placeholder\": \"Mensaje para {name}…\",\n \"send\": \"Enviar\",\n \"attach\": \"Adjuntar archivos\",\n \"typing\": \"El agente está escribiendo\",\n \"moreSteps\": \"{count, plural, one {# paso más} other {# pasos más}}\",\n \"hideSteps\": \"Ocultar pasos\",\n \"unread\": \"{count, plural, one {# respuesta sin leer} other {# respuestas sin leer}}\",\n \"retry\": \"Reintentar\",\n \"tooLarge\": \"El archivo es demasiado grande.\",\n \"stop\": \"Detener\",\n \"voice\": {\n \"hold\": \"Mantenga pulsado para grabar\",\n \"stop\": \"Detener la grabación\",\n \"recording\": \"Grabando… {seconds} s\",\n \"review\": \"Revise la transcripción antes de enviar\",\n \"notRecognized\": \"No se reconoció la voz\",\n \"micDenied\": \"Sin acceso al micrófono\",\n \"unsupported\": \"Este navegador no admite la entrada de voz\",\n \"start\": \"Grabar un mensaje de voz\",\n \"done\": \"Detener\",\n \"recognizing\": \"Reconociendo…\",\n \"recordingNow\": \"Grabando\",\n \"failed\": \"No se pudo reconocer el mensaje de voz\",\n \"retry\": \"Reintentar\"\n },\n \"confirm\": {\n \"title\": \"Confirme la acción\",\n \"text\": \"El agente quiere ejecutar: {action}\",\n \"approve\": \"Ejecutar\",\n \"reject\": \"Rechazar\"\n },\n \"wait\": {\n \"starting\": \"El agente se está iniciando…\",\n \"queued\": \"{count, plural, =0 {En cola · usted es el siguiente} other {En cola · # por delante}}\"\n },\n \"palette\": {\n \"title\": \"Comandos y skills\",\n \"commands\": \"Comandos\",\n \"skills\": \"Skills\",\n \"noSkills\": \"No tiene skills disponibles\",\n \"empty\": \"No se encontró nada\"\n },\n \"unknownCommand\": \"Comando desconocido {name}\",\n \"sendAsText\": \"Enviar como texto\",\n \"skillPlaceholder\": \"¿Qué hacer con el skill?\",\n \"context\": {\n \"meter\": \"Contexto: {used} de {total} tokens ({pct} %)\",\n \"full\": \"Las respuestas se encarecen y el agente puede confundirse.\",\n \"compact\": \"Compactar\",\n \"reset\": \"Empezar de nuevo\",\n \"waitTurn\": \"Espere la respuesta o deténgala\",\n \"waitQueue\": \"Espere las respuestas a los mensajes en la cola\"\n },\n \"event\": {\n \"details\": \"Resumen\"\n },\n \"files\": {\n \"open\": \"Abrir {name}\",\n \"download\": \"Descargar\",\n \"failed\": \"No se pudo abrir el archivo\",\n \"tooLarge\": \"El archivo es demasiado grande para la vista previa: descárguelo\",\n \"save\": \"Descargar {name}\",\n \"notUtf8\": \"El archivo no está en UTF-8: descárguelo\",\n \"rows\": \"Se muestran {shown} de {total, plural, one {# fila} other {# filas}}\",\n \"source\": \"Código\",\n \"page\": \"Página\",\n \"converted\": \"Vista previa · convertido desde {format}\",\n \"pagesShown\": \"Se muestran {shown} de {total} páginas\",\n \"firstPages\": \"Se muestran las primeras {shown} páginas\",\n \"cols\": \"y {shown} de {total} columnas\",\n \"preparing\": \"Preparando la vista previa…\",\n \"preparingHint\": \"Suele tardar unos segundos\",\n \"unavailable\": \"Vista previa no disponible\",\n \"formulaHint\": \"El valor se calcula al abrir el archivo en Excel\",\n \"sheets\": \"Hojas\",\n \"reasons\": {\n \"too_large\": \"El archivo supera {limit} MB\",\n \"timeout\": \"Tardó más de 30 segundos\",\n \"broken\": \"El archivo está dañado o el formato no es compatible\",\n \"busy\": \"El servicio está ocupado, inténtalo más tarde\"\n }\n },\n \"notice\": {\n \"more\": \"Mostrar completo\",\n \"less\": \"Contraer\"\n },\n \"queuePlaceholder\": \"El mensaje esperará en la cola\",\n \"queue\": {\n \"position\": \"En la cola · {n}\",\n \"cancel\": \"Cancelar\"\n },\n \"stopAnswer\": \"Detener la respuesta\",\n \"stopping\": \"Deteniendo…\",\n \"stopped\": \"Detenida\",\n \"subagents\": {\n \"title\": \"Subagentes · {count}\",\n \"done\": \"listo\",\n \"failed\": \"{count, plural, one {# sin terminar} other {# sin terminar}}\",\n \"tools\": \"{count, plural, one {# herramienta} other {# herramientas}}\",\n \"state\": {\n \"running\": \"en curso\",\n \"done\": \"listo\",\n \"failed\": \"error\",\n \"timeout\": \"interrumpido · sin tiempo\",\n \"aborted\": \"interrumpido\",\n \"turnStopped\": \"interrumpido · respuesta detenida\"\n }\n },\n \"retryQueued\": \"El reintento espera en la cola\"\n },\n \"agent\": {\n \"menu\": \"Agente\",\n \"options\": \"Tono\",\n \"model\": \"Modelo\",\n \"modelDefault\": \"Predeterminado\",\n \"noModels\": \"No hay modelos disponibles: consulte a un administrador\",\n \"modelCompactWarn\": \"El contexto se compactará antes de la próxima respuesta\",\n \"everywhere\": \"El cambio se aplica en todos los canales y servicios conectados.\",\n \"capImage\": \"imágenes\",\n \"capReasoning\": \"razonamiento\"\n },\n \"graph\": {\n \"zoomIn\": \"Acercar\",\n \"zoomOut\": \"Alejar\",\n \"resetLayout\": \"Devolver los nodos a su sitio\"\n }\n}\n","{\n \"loading\": \"加载中…\",\n \"cancel\": \"取消\",\n \"create\": \"创建\",\n \"close\": \"关闭\",\n \"delete\": \"删除\",\n \"remove\": \"移除\",\n \"agentName\": \"智能体名称\",\n \"topbar\": {\n \"sections\": \"栏目\",\n \"profile\": \"个人资料\"\n },\n \"chat\": {\n \"title\": \"聊天\",\n \"conversations\": \"对话\",\n \"conversation\": \"对话\",\n \"topics\": \"话题\",\n \"archive\": \"归档\",\n \"noTopics\": \"暂无话题\",\n \"newTopic\": \"新话题\",\n \"topicTitle\": \"话题\",\n \"topicHint\": \"话题有独立的历史记录,记忆和空间与主对话相同。\",\n \"loadOlder\": \"更早的消息\",\n \"emptyTitle\": \"你好,我是 {name}\",\n \"placeholder\": \"给 {name} 发消息…\",\n \"send\": \"发送\",\n \"attach\": \"附加文件\",\n \"typing\": \"智能体正在输入\",\n \"moreSteps\": \"{count, plural, other {另外 # 个步骤}}\",\n \"hideSteps\": \"隐藏步骤\",\n \"unread\": \"{count} 条未读回复\",\n \"retry\": \"重试\",\n \"tooLarge\": \"文件太大。\",\n \"stop\": \"停止\",\n \"voice\": {\n \"hold\": \"按住录音\",\n \"stop\": \"停止录音\",\n \"recording\": \"录音中… {seconds} 秒\",\n \"review\": \"发送前请检查转写文本\",\n \"notRecognized\": \"未能识别语音\",\n \"micDenied\": \"无法访问麦克风\",\n \"unsupported\": \"此浏览器不支持语音输入\",\n \"start\": \"录制语音\",\n \"done\": \"停止\",\n \"recognizing\": \"正在识别…\",\n \"recordingNow\": \"录音中\",\n \"failed\": \"无法识别语音消息\",\n \"retry\": \"重试\"\n },\n \"confirm\": {\n \"title\": \"确认操作\",\n \"text\": \"代理想要执行:{action}\",\n \"approve\": \"执行\",\n \"reject\": \"拒绝\"\n },\n \"wait\": {\n \"starting\": \"代理正在启动…\",\n \"queued\": \"{count, plural, =0 {排队中 · 您是下一位} other {排队中 · 前面还有 # 位}}\"\n },\n \"palette\": {\n \"title\": \"命令和技能\",\n \"commands\": \"命令\",\n \"skills\": \"技能\",\n \"noSkills\": \"您没有可用的技能\",\n \"empty\": \"未找到\"\n },\n \"unknownCommand\": \"未知命令 {name}\",\n \"sendAsText\": \"作为文本发送\",\n \"skillPlaceholder\": \"用这个技能做什么?\",\n \"context\": {\n \"meter\": \"上下文:{used} / {total} 个令牌({pct}%)\",\n \"full\": \"回答变得更贵,代理可能会混淆。\",\n \"compact\": \"压缩\",\n \"reset\": \"重新开始\",\n \"waitTurn\": \"请等待回答或停止它\",\n \"waitQueue\": \"请等待队列中消息的回答\"\n },\n \"event\": {\n \"details\": \"摘要\"\n },\n \"files\": {\n \"open\": \"打开 {name}\",\n \"download\": \"下载\",\n \"failed\": \"无法打开文件\",\n \"tooLarge\": \"文件太大,无法预览,请下载\",\n \"save\": \"下载 {name}\",\n \"notUtf8\": \"文件不是 UTF-8 编码,请下载\",\n \"rows\": \"显示 {total} 行中的 {shown} 行\",\n \"source\": \"代码\",\n \"page\": \"页面\",\n \"converted\": \"预览 · 由 {format} 转换\",\n \"pagesShown\": \"显示 {shown} / {total} 页\",\n \"firstPages\": \"显示前 {shown} 页\",\n \"cols\": \"以及 {shown} / {total} 列\",\n \"preparing\": \"正在准备预览…\",\n \"preparingHint\": \"通常只需几秒\",\n \"unavailable\": \"无法预览\",\n \"formulaHint\": \"在 Excel 中打开时计算该值\",\n \"sheets\": \"工作表\",\n \"reasons\": {\n \"too_large\": \"文件大于 {limit} MB\",\n \"timeout\": \"超过 30 秒未完成\",\n \"broken\": \"文件已损坏或格式不受支持\",\n \"busy\": \"服务繁忙,请稍后重试\"\n }\n },\n \"notice\": {\n \"more\": \"显示全部\",\n \"less\": \"收起\"\n },\n \"queuePlaceholder\": \"消息将在队列中等待\",\n \"queue\": {\n \"position\": \"排队中 · {n}\",\n \"cancel\": \"取消\"\n },\n \"stopAnswer\": \"停止回答\",\n \"stopping\": \"正在停止…\",\n \"stopped\": \"已停止\",\n \"subagents\": {\n \"title\": \"子代理 · {count}\",\n \"done\": \"完成\",\n \"failed\": \"{count} 个未完成\",\n \"tools\": \"{count} 个工具\",\n \"state\": {\n \"running\": \"运行中\",\n \"done\": \"完成\",\n \"failed\": \"错误\",\n \"timeout\": \"已中断 · 超时\",\n \"aborted\": \"已中断\",\n \"turnStopped\": \"已中断 · 回答已停止\"\n }\n },\n \"retryQueued\": \"重试正在队列中等待\"\n },\n \"agent\": {\n \"menu\": \"智能体\",\n \"options\": \"语气\",\n \"model\": \"模型\",\n \"modelDefault\": \"默认\",\n \"noModels\": \"没有可用的模型——请联系管理员\",\n \"modelCompactWarn\": \"下次回答前将压缩上下文\",\n \"everywhere\": \"更改在所有渠道和已连接的服务中生效。\",\n \"capImage\": \"图片\",\n \"capReasoning\": \"推理\"\n },\n \"graph\": {\n \"zoomIn\": \"放大\",\n \"zoomOut\": \"缩小\",\n \"resetLayout\": \"恢复节点位置\"\n }\n}\n","import en from \"./en.json\";\nimport ru from \"./ru.json\";\nimport de from \"./de.json\";\nimport es from \"./es.json\";\nimport zh from \"./zh.json\";\n\n/** Strings of the components in the five languages of the products. A product adds\n * them to its i18next instance under the namespace `uikit`. */\nexport const resources = { en, ru, de, es, zh };\nexport type KitLanguage = keyof typeof resources;\nexport { UIKIT_NS } from \"../i18n\";\n"],"mappings":";;;AKQA,IAAayC,IAAY;CAAE,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;CAAI,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;CAAI,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;CAAI,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;CAAI,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;AAAG"}
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.13.0",
2
+ "version": "1.14.0",
3
3
  "classes": [
4
4
  "a",
5
5
  "action",
@@ -104,6 +104,7 @@
104
104
  "g-c6",
105
105
  "g-e",
106
106
  "g-n",
107
+ "g-row",
107
108
  "gap",
108
109
  "ghost",
109
110
  "gleg",
@@ -320,6 +321,7 @@
320
321
  "g-c6",
321
322
  "g-e",
322
323
  "g-n",
324
+ "g-row",
323
325
  "gleg",
324
326
  "grow",
325
327
  "gwrap",
package/dist/styles.css CHANGED
@@ -510,8 +510,10 @@ h3.sec {
510
510
  touch-action: none;
511
511
  cursor: grab;
512
512
  }
513
- .g-e line {
513
+ .g-e line,
514
+ .g-e path {
514
515
  stroke: var(--border-strong);
516
+ fill: none;
515
517
  transition: opacity 0.15s;
516
518
  }
517
519
  .g-e .hit {
@@ -519,7 +521,8 @@ h3.sec {
519
521
  stroke-width: 12;
520
522
  cursor: pointer;
521
523
  }
522
- .g-e.dashed line:first-child {
524
+ .g-e.dashed line:first-child,
525
+ .g-e.dashed path:first-child {
523
526
  stroke: var(--violet);
524
527
  stroke-dasharray: 6 4;
525
528
  }
@@ -599,15 +602,31 @@ h3.sec {
599
602
  svg.dimmed .g-n:not(.hl) {
600
603
  opacity: 0.22;
601
604
  }
602
- svg.dimmed .g-e:not(.hl) line {
605
+ svg.dimmed .g-e:not(.hl) line,
606
+ svg.dimmed .g-e:not(.hl) path {
603
607
  opacity: 0.12;
604
608
  }
605
- svg.dimmed .g-e.hl line:first-child {
609
+ svg.dimmed .g-e.hl line:first-child,
610
+ svg.dimmed .g-e.hl path:first-child {
606
611
  stroke: var(--text-2);
607
612
  }
608
- svg.dimmed .g-e.dashed.hl line:first-child {
613
+ svg.dimmed .g-e.dashed.hl line:first-child,
614
+ svg.dimmed .g-e.dashed.hl path:first-child {
609
615
  stroke: var(--violet);
610
616
  }
617
+ /* FTR.HMR.DEV-0002 R15: the rows of the row layout, a label at the left and a line between rows */
618
+ .g-row {
619
+ pointer-events: none;
620
+ }
621
+ .g-row text {
622
+ font: 600 12px var(--font);
623
+ fill: var(--text-2);
624
+ dominant-baseline: middle;
625
+ }
626
+ .g-row line {
627
+ stroke: var(--border);
628
+ stroke-dasharray: 2 4;
629
+ }
611
630
  .gleg {
612
631
  position: absolute;
613
632
  right: 10px;
@@ -646,6 +665,10 @@ svg.dimmed .g-e.dashed.hl line:first-child {
646
665
  color: var(--text-2);
647
666
  cursor: pointer;
648
667
  }
668
+ .gzoom button svg {
669
+ display: block;
670
+ margin: auto;
671
+ }
649
672
  @media (max-width: 860px) {
650
673
  .gzoom {
651
674
  display: none;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@green-on-grey/ui-kit",
3
- "version": "1.13.0",
3
+ "version": "1.14.0",
4
4
  "description": "UI kit of the Nabu and Hammurapi products: styles, components, the chat and the sign-in screen",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {