@kitn.ai/ui 0.28.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/agent-tooling/construct/public.d.ts +15 -0
- package/dist/agent-tooling/construct/schema.d.ts +111 -0
- package/dist/construct-cli.es.js +3 -3
- package/dist/construct.d.ts +5 -0
- package/dist/construct.js +327 -0
- package/dist/core-C8fzo39E.js +1 -12
- package/dist/engine-javascript-C1x7zo1_.js +1 -141
- package/dist/mcp.es.js +1 -1
- package/package.json +16 -16
- package/bin/route.test.js +0 -58
- package/src/agent-tooling/README.md +0 -192
- package/src/agent-tooling/archetypes.ts +0 -205
- package/src/agent-tooling/catalog/README.md +0 -676
- package/src/agent-tooling/catalog/catalog-types.ts +0 -231
- package/src/agent-tooling/catalog/fabrications.ts +0 -96
- package/src/agent-tooling/catalog/invariants.ts +0 -284
- package/src/agent-tooling/catalog/labs-titles.ts +0 -114
- package/src/agent-tooling/catalog/scenarios.ts +0 -87
- package/src/agent-tooling/catalog/surfaces.ts +0 -347
- package/src/agent-tooling/construct/cli-entry.ts +0 -8
- package/src/agent-tooling/construct/cli.ts +0 -147
- package/src/agent-tooling/construct/codegen.ts +0 -1635
- package/src/agent-tooling/construct/construct.v1.schema.json +0 -319
- package/src/agent-tooling/construct/dev.ts +0 -148
- package/src/agent-tooling/construct/fixtures/demo-widget.construct.json +0 -7
- package/src/agent-tooling/construct/fixtures/ops-console.construct.json +0 -44
- package/src/agent-tooling/construct/fixtures/owner-widget.construct.json +0 -32
- package/src/agent-tooling/construct/schema.ts +0 -452
- package/src/agent-tooling/integrations/anthropic.ts +0 -442
- package/src/agent-tooling/integrations/cloudflare.ts +0 -218
- package/src/agent-tooling/integrations/langgraph.ts +0 -133
- package/src/agent-tooling/integrations/mastra.ts +0 -182
- package/src/agent-tooling/integrations/mock.ts +0 -148
- package/src/agent-tooling/integrations/ollama.ts +0 -97
- package/src/agent-tooling/integrations/openai.ts +0 -95
- package/src/agent-tooling/integrations/openrouter.ts +0 -82
- package/src/agent-tooling/integrations/pi.ts +0 -176
- package/src/agent-tooling/integrations/pydantic-ai.ts +0 -108
- package/src/agent-tooling/integrations/vercel-ai-sdk.ts +0 -398
- package/src/agent-tooling/mcp/css-raw.d.ts +0 -12
- package/src/agent-tooling/mcp/manifest.ts +0 -422
- package/src/agent-tooling/mcp/server.ts +0 -116
- package/src/agent-tooling/mcp/stdio.ts +0 -18
- package/src/agent-tooling/mcp/tools/construct.ts +0 -130
- package/src/agent-tooling/mcp/tools/debug.ts +0 -621
- package/src/agent-tooling/mcp/tools/reference.ts +0 -980
- package/src/agent-tooling/mcp/tools/scaffold.ts +0 -6708
- package/src/agent-tooling/mcp/tools/theme.ts +0 -456
- package/src/agent-tooling/mcp/tools/types.ts +0 -14
- package/src/agent-tooling/mcp/validate-args.ts +0 -141
- package/src/agent-tooling/recipes/composed-thread.ts +0 -714
- package/src/agent-tooling/recipes/index.ts +0 -22
- package/src/agent-tooling/recipes/types.ts +0 -32
- package/src/agent-tooling/registry.ts +0 -132
- package/src/agent-tooling/route-emit.ts +0 -305
- package/src/agent-tooling/types.ts +0 -390
- package/src/components/artifact-card.tsx +0 -120
- package/src/components/artifact.tsx +0 -914
- package/src/components/attachment-types.ts +0 -66
- package/src/components/attachments.tsx +0 -536
- package/src/components/audio-visualizer/audio-visualizer.voice-fixture.ts +0 -257
- package/src/components/audio-visualizer/aurora.glsl.ts +0 -330
- package/src/components/audio-visualizer/fit-scale.ts +0 -112
- package/src/components/audio-visualizer/index.tsx +0 -528
- package/src/components/audio-visualizer/labs/lab-choreography.ts +0 -187
- package/src/components/audio-visualizer/labs/lab-shaders.ts +0 -363
- package/src/components/audio-visualizer/labs/lab-visualizer.tsx +0 -102
- package/src/components/audio-visualizer/shader-canvas.tsx +0 -876
- package/src/components/audio-visualizer/sizes.ts +0 -54
- package/src/components/audio-visualizer/variant-aurora.tsx +0 -305
- package/src/components/audio-visualizer/variant-bar.tsx +0 -175
- package/src/components/audio-visualizer/variant-custom.tsx +0 -344
- package/src/components/audio-visualizer/variant-grid.tsx +0 -175
- package/src/components/audio-visualizer/variant-radial.tsx +0 -163
- package/src/components/audio-visualizer/variant-wave.tsx +0 -130
- package/src/components/audio-visualizer/wave.glsl.ts +0 -130
- package/src/components/card-fallback.tsx +0 -60
- package/src/components/card-renderer.tsx +0 -220
- package/src/components/card.tsx +0 -212
- package/src/components/chain-of-thought.tsx +0 -348
- package/src/components/chat-container.tsx +0 -89
- package/src/components/chat-scope-picker.tsx +0 -57
- package/src/components/chat-thread.tsx +0 -1014
- package/src/components/checkpoint.tsx +0 -88
- package/src/components/choice-card.tsx +0 -743
- package/src/components/coachmark.tsx +0 -249
- package/src/components/code-block.tsx +0 -181
- package/src/components/composer-dom.ts +0 -159
- package/src/components/composer-highlight.ts +0 -242
- package/src/components/composer-history.ts +0 -82
- package/src/components/composer.tsx +0 -1075
- package/src/components/confirm-card.tsx +0 -402
- package/src/components/context.tsx +0 -377
- package/src/components/conversation-item.tsx +0 -241
- package/src/components/conversation-list.tsx +0 -429
- package/src/components/conversation-panel.tsx +0 -118
- package/src/components/dismissed-stub.tsx +0 -80
- package/src/components/embed.tsx +0 -200
- package/src/components/empty.tsx +0 -177
- package/src/components/feedback-bar.tsx +0 -166
- package/src/components/file-tree.tsx +0 -530
- package/src/components/file-upload.tsx +0 -167
- package/src/components/form-widgets.tsx +0 -525
- package/src/components/form.tsx +0 -1296
- package/src/components/home-panel.tsx +0 -159
- package/src/components/image.tsx +0 -65
- package/src/components/link-preview.tsx +0 -195
- package/src/components/loader.tsx +0 -367
- package/src/components/markdown.tsx +0 -162
- package/src/components/message-skills.tsx +0 -40
- package/src/components/message.tsx +0 -765
- package/src/components/model-switcher.tsx +0 -132
- package/src/components/prompt-input.tsx +0 -188
- package/src/components/prompt-suggestion.tsx +0 -150
- package/src/components/reasoning.tsx +0 -293
- package/src/components/response-compare-types.ts +0 -152
- package/src/components/response-compare.tsx +0 -455
- package/src/components/response-stream.tsx +0 -109
- package/src/components/screen.tsx +0 -181
- package/src/components/scroll-button.tsx +0 -93
- package/src/components/source.tsx +0 -192
- package/src/components/tasks-card.tsx +0 -801
- package/src/components/text-shimmer.tsx +0 -37
- package/src/components/thinking-bar.tsx +0 -50
- package/src/components/thread.tsx +0 -228
- package/src/components/toast.tsx +0 -503
- package/src/components/tool-classify.ts +0 -26
- package/src/components/tool-types.ts +0 -49
- package/src/components/tool.tsx +0 -190
- package/src/components/use-card-resolution.ts +0 -44
- package/src/components/voice-input.tsx +0 -222
- package/src/components/voice-output.tsx +0 -242
- package/src/components/widget-tab-bar.tsx +0 -73
- package/src/components/workspace-shell.tsx +0 -285
- package/src/diagnostics/hook.ts +0 -352
- package/src/diagnostics/index.ts +0 -82
- package/src/diagnostics/report-request.ts +0 -296
- package/src/elements/agent-card.tsx +0 -67
- package/src/elements/artifact.tsx +0 -194
- package/src/elements/attachments.tsx +0 -140
- package/src/elements/audio-visualizer.tsx +0 -227
- package/src/elements/autoloader.ts +0 -89
- package/src/elements/avatar.tsx +0 -33
- package/src/elements/badge.tsx +0 -32
- package/src/elements/button.tsx +0 -149
- package/src/elements/card.tsx +0 -133
- package/src/elements/cards.tsx +0 -266
- package/src/elements/chain-of-thought.tsx +0 -141
- package/src/elements/chat-scope-picker.tsx +0 -65
- package/src/elements/chat-types.ts +0 -102
- package/src/elements/chat-workspace.tsx +0 -188
- package/src/elements/chat.tsx +0 -304
- package/src/elements/checkbox-group.tsx +0 -164
- package/src/elements/checkbox.tsx +0 -134
- package/src/elements/checkpoint.tsx +0 -47
- package/src/elements/choice.tsx +0 -100
- package/src/elements/coachmark.tsx +0 -90
- package/src/elements/code-block.tsx +0 -60
- package/src/elements/command.tsx +0 -197
- package/src/elements/compare.tsx +0 -111
- package/src/elements/compiled.css +0 -2
- package/src/elements/composer.tsx +0 -162
- package/src/elements/confirm-card.tsx +0 -76
- package/src/elements/context-meter.tsx +0 -107
- package/src/elements/conversation-item.tsx +0 -120
- package/src/elements/conversation-list.tsx +0 -203
- package/src/elements/css.ts +0 -5
- package/src/elements/default-input.tsx +0 -392
- package/src/elements/define-entry.ts +0 -12
- package/src/elements/define.tsx +0 -563
- package/src/elements/diagnostic-events.ts +0 -114
- package/src/elements/dialog.tsx +0 -145
- package/src/elements/disclosure.ts +0 -95
- package/src/elements/dock.tsx +0 -215
- package/src/elements/dropdown.tsx +0 -123
- package/src/elements/editable-label.tsx +0 -140
- package/src/elements/element-data-types.ts +0 -152
- package/src/elements/element-diagnostics.ts +0 -392
- package/src/elements/element-manifest.json +0 -354
- package/src/elements/element-nonscalar.json +0 -187
- package/src/elements/element-types.d.ts +0 -4353
- package/src/elements/embed.tsx +0 -35
- package/src/elements/empty.tsx +0 -29
- package/src/elements/feedback-bar.tsx +0 -66
- package/src/elements/file-tree.tsx +0 -62
- package/src/elements/file-upload.tsx +0 -44
- package/src/elements/form.tsx +0 -94
- package/src/elements/hover-card.tsx +0 -80
- package/src/elements/icon.tsx +0 -41
- package/src/elements/image.tsx +0 -32
- package/src/elements/input.tsx +0 -492
- package/src/elements/kbd.tsx +0 -45
- package/src/elements/link-preview.tsx +0 -34
- package/src/elements/loader.tsx +0 -25
- package/src/elements/markdown.tsx +0 -38
- package/src/elements/menu.tsx +0 -241
- package/src/elements/message-skills.tsx +0 -83
- package/src/elements/message.tsx +0 -361
- package/src/elements/model-switcher.tsx +0 -121
- package/src/elements/nav.tsx +0 -87
- package/src/elements/notice.tsx +0 -53
- package/src/elements/pane-grid.tsx +0 -111
- package/src/elements/pane-group.tsx +0 -119
- package/src/elements/pane.tsx +0 -129
- package/src/elements/popover.tsx +0 -81
- package/src/elements/progress-bar.tsx +0 -39
- package/src/elements/prompt-dock.tsx +0 -82
- package/src/elements/prompt-input.tsx +0 -240
- package/src/elements/prompt-suggestions.tsx +0 -113
- package/src/elements/radio-group.tsx +0 -129
- package/src/elements/reasoning.tsx +0 -71
- package/src/elements/register-impl.ts +0 -148
- package/src/elements/register.ts +0 -76
- package/src/elements/remote.tsx +0 -225
- package/src/elements/resizable.globals.d.ts +0 -36
- package/src/elements/resizable.tsx +0 -704
- package/src/elements/response-stream.tsx +0 -40
- package/src/elements/screen.tsx +0 -90
- package/src/elements/scroll-area.tsx +0 -33
- package/src/elements/scroll-button.tsx +0 -179
- package/src/elements/search.tsx +0 -185
- package/src/elements/segmented.tsx +0 -129
- package/src/elements/select.tsx +0 -165
- package/src/elements/separator.tsx +0 -36
- package/src/elements/setting-item.tsx +0 -50
- package/src/elements/settings-group.tsx +0 -37
- package/src/elements/skeleton.tsx +0 -45
- package/src/elements/slider.tsx +0 -171
- package/src/elements/slot-text.ts +0 -73
- package/src/elements/slots.ts +0 -787
- package/src/elements/source.tsx +0 -126
- package/src/elements/status.tsx +0 -42
- package/src/elements/styles.css +0 -328
- package/src/elements/switch.tsx +0 -118
- package/src/elements/tabs.tsx +0 -95
- package/src/elements/tasks.tsx +0 -103
- package/src/elements/text-shimmer.tsx +0 -28
- package/src/elements/thinking-bar.tsx +0 -43
- package/src/elements/thread.tsx +0 -139
- package/src/elements/toast.tsx +0 -106
- package/src/elements/tool.tsx +0 -78
- package/src/elements/tooltip.tsx +0 -85
- package/src/elements/validate-messages.ts +0 -76
- package/src/elements/voice-input.tsx +0 -100
- package/src/elements/voice-output.tsx +0 -82
- package/src/index.ts +0 -430
- package/src/primitives/audio-bands.ts +0 -174
- package/src/primitives/card-component-types.ts +0 -63
- package/src/primitives/card-contract.ts +0 -80
- package/src/primitives/card-data-types.ts +0 -361
- package/src/primitives/card-host.tsx +0 -37
- package/src/primitives/card-recovery.ts +0 -160
- package/src/primitives/card-registry.tsx +0 -78
- package/src/primitives/card-resolution.ts +0 -36
- package/src/primitives/card-routing.ts +0 -85
- package/src/primitives/card-schemas/artifact.schema.json +0 -92
- package/src/primitives/card-schemas/card-envelope.schema.json +0 -14
- package/src/primitives/card-schemas/card-event.schema.json +0 -12
- package/src/primitives/card-schemas/choice.schema.json +0 -75
- package/src/primitives/card-schemas/confirm.schema.json +0 -65
- package/src/primitives/card-schemas/embed.schema.json +0 -63
- package/src/primitives/card-schemas/form.result.schema.json +0 -7
- package/src/primitives/card-schemas/form.schema.json +0 -53
- package/src/primitives/card-schemas/link.schema.json +0 -54
- package/src/primitives/card-schemas/tasks.result.schema.json +0 -16
- package/src/primitives/card-schemas/tasks.schema.json +0 -83
- package/src/primitives/card-tags.ts +0 -61
- package/src/primitives/card-validate-cards.ts +0 -255
- package/src/primitives/card-validate-schemas.ts +0 -58
- package/src/primitives/card-validate.ts +0 -131
- package/src/primitives/chat-config.tsx +0 -103
- package/src/primitives/composer-model.ts +0 -49
- package/src/primitives/composer-triggers.ts +0 -35
- package/src/primitives/controllable.ts +0 -21
- package/src/primitives/conversation-store.ts +0 -248
- package/src/primitives/create-kai-chat.ts +0 -66
- package/src/primitives/create-tween.ts +0 -266
- package/src/primitives/embed-providers.ts +0 -254
- package/src/primitives/field-mask.ts +0 -256
- package/src/primitives/field-semantics.ts +0 -115
- package/src/primitives/highlighter.ts +0 -157
- package/src/primitives/input-mask.ts +0 -853
- package/src/primitives/link-preview.ts +0 -87
- package/src/primitives/message-feedback.ts +0 -124
- package/src/primitives/pdf-preview.ts +0 -121
- package/src/primitives/toast-store.ts +0 -338
- package/src/primitives/url-scheme-policy.ts +0 -70
- package/src/primitives/use-audio-analysis.ts +0 -340
- package/src/primitives/use-auto-resize.ts +0 -31
- package/src/primitives/use-resize-observer.ts +0 -45
- package/src/primitives/use-sequencer.ts +0 -72
- package/src/primitives/use-speech-recognition.ts +0 -146
- package/src/primitives/use-stick-to-bottom.ts +0 -75
- package/src/primitives/use-text-stream.ts +0 -143
- package/src/primitives/use-voice-recorder.ts +0 -62
- package/src/primitives/visualizer-sequences.ts +0 -350
- package/src/remote/host-embed.ts +0 -345
- package/src/remote/index.ts +0 -2
- package/src/remote/origin.ts +0 -30
- package/src/remote/provider-runtime.ts +0 -262
- package/src/remote/provider.ts +0 -2
- package/src/remote/validate.ts +0 -22
- package/src/remote/version.ts +0 -12
- package/src/remote/wire.ts +0 -48
- package/src/schemas/from-tool-call.ts +0 -151
- package/src/schemas/index.ts +0 -341
- package/src/schemas/provider-subsets.ts +0 -538
- package/src/schemas/registry.ts +0 -355
- package/src/schemas/tool-defs.ts +0 -793
- package/src/solid.ts +0 -173
- package/src/state/index.ts +0 -44
- package/src/state/messages.ts +0 -53
- package/src/state/mock.ts +0 -297
- package/src/state/parts.ts +0 -295
- package/src/state/persistence.ts +0 -180
- package/src/state/stream.ts +0 -246
- package/src/state/suggestions.ts +0 -9
- package/src/state/threads.ts +0 -142
- package/src/test-utils/fake-clock.ts +0 -88
- package/src/types.ts +0 -95
- package/src/ui/action-icons.ts +0 -53
- package/src/ui/agent-card.tsx +0 -218
- package/src/ui/avatar.tsx +0 -23
- package/src/ui/badge.tsx +0 -21
- package/src/ui/button.tsx +0 -49
- package/src/ui/card.tsx +0 -245
- package/src/ui/checkbox-group.tsx +0 -153
- package/src/ui/checkbox.tsx +0 -63
- package/src/ui/collapsible.tsx +0 -163
- package/src/ui/command.tsx +0 -103
- package/src/ui/dialog.tsx +0 -223
- package/src/ui/dock.tsx +0 -630
- package/src/ui/dropdown.tsx +0 -636
- package/src/ui/editable-label.tsx +0 -112
- package/src/ui/hover-card.tsx +0 -345
- package/src/ui/icon.tsx +0 -167
- package/src/ui/input.tsx +0 -391
- package/src/ui/kbd.tsx +0 -118
- package/src/ui/nav.tsx +0 -282
- package/src/ui/notice.tsx +0 -84
- package/src/ui/overlay.tsx +0 -277
- package/src/ui/pane-grid.tsx +0 -117
- package/src/ui/pane-group.tsx +0 -291
- package/src/ui/pane.tsx +0 -193
- package/src/ui/popover.tsx +0 -106
- package/src/ui/progress-bar.tsx +0 -83
- package/src/ui/prompt-dock.tsx +0 -145
- package/src/ui/radio.tsx +0 -150
- package/src/ui/resizable.tsx +0 -693
- package/src/ui/scroll-area.tsx +0 -26
- package/src/ui/segmented.tsx +0 -109
- package/src/ui/select.tsx +0 -168
- package/src/ui/separator.tsx +0 -10
- package/src/ui/settings-group.tsx +0 -67
- package/src/ui/skeleton.tsx +0 -73
- package/src/ui/slider.tsx +0 -178
- package/src/ui/status.tsx +0 -48
- package/src/ui/switch.tsx +0 -119
- package/src/ui/tabs.tsx +0 -168
- package/src/ui/textarea.tsx +0 -21
- package/src/ui/tooltip.tsx +0 -118
- package/src/utils/cn.ts +0 -30
- package/src/wire/chunk.ts +0 -248
- package/src/wire/consume.ts +0 -599
- package/src/wire/diagnostics.ts +0 -727
- package/src/wire/encode-probe.ts +0 -214
- package/src/wire/encode.ts +0 -947
- package/src/wire/files.ts +0 -342
- package/src/wire/formats/anthropic.ts +0 -274
- package/src/wire/formats/openai.ts +0 -228
- package/src/wire/index.ts +0 -95
- package/src/wire/media-types.ts +0 -344
- package/src/wire/read.ts +0 -396
- package/src/wire/sink-helpers.ts +0 -50
- package/src/wire/sse.ts +0 -153
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import { For, Show } from 'solid-js';
|
|
2
|
-
import { cn } from '../utils/cn';
|
|
3
|
-
import { Button } from '../ui/button';
|
|
4
|
-
import { renderIcon } from '../ui/icon';
|
|
5
|
-
import { isSafeUrl } from '../primitives/url-scheme-policy';
|
|
6
|
-
import { relativeTimeShort, isConversationUnread } from './conversation-item';
|
|
7
|
-
import type { ConversationSummary, HomeLinkEntry } from '../types';
|
|
8
|
-
|
|
9
|
-
export interface HomePanelProps {
|
|
10
|
-
greeting?: { title?: string; subtitle?: string };
|
|
11
|
-
/** The most-recent conversation, host-derived. `undefined` hides the card
|
|
12
|
-
* entirely — this component never fetches or picks one itself. */
|
|
13
|
-
recent?: ConversationSummary;
|
|
14
|
-
/** Defaults to `true`. */
|
|
15
|
-
showNewConversation?: boolean;
|
|
16
|
-
/** Defaults to `'Send us a message'`. */
|
|
17
|
-
newChatLabel?: string;
|
|
18
|
-
links?: HomeLinkEntry[];
|
|
19
|
-
onSelectRecent?: (id: string) => void;
|
|
20
|
-
onNewChat: () => void;
|
|
21
|
-
/** Fired only for href-less link entries — an entry with a safe `href`
|
|
22
|
-
* navigates as a real anchor instead. */
|
|
23
|
-
onLink?: (entry: HomeLinkEntry) => void;
|
|
24
|
-
class?: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* The widget home screen (Intercom-pattern, H-1): greeting, the most-recent
|
|
29
|
-
* conversation, a "start a new conversation" CTA, and a list of host-defined
|
|
30
|
-
* links. Pure props in, events out — no fetching, no routing; a later task
|
|
31
|
-
* wires this behind `ChatThread`'s Home/Messages tab bar.
|
|
32
|
-
*
|
|
33
|
-
* Unsafe-href rule: a `links` entry with an `href` that fails `isSafeUrl`
|
|
34
|
-
* (e.g. `javascript:`) is NOT silently promoted into a button/event-emitter —
|
|
35
|
-
* that would let a host-authored-but-attacker-influenced config still fire a
|
|
36
|
-
* handler off a scheme SAFE_SCHEMES rejects. It renders as a plain,
|
|
37
|
-
* non-interactive row: label visible, no anchor, no button, no click handler.
|
|
38
|
-
*/
|
|
39
|
-
export function HomePanel(props: HomePanelProps) {
|
|
40
|
-
const title = () => props.greeting?.title ?? 'Hi there 👋';
|
|
41
|
-
|
|
42
|
-
return (
|
|
43
|
-
<div
|
|
44
|
-
data-kai-home-panel
|
|
45
|
-
class={cn('flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto p-5', props.class)}
|
|
46
|
-
>
|
|
47
|
-
<div class="flex flex-col gap-1">
|
|
48
|
-
<h2 class="text-xl font-semibold text-foreground">{title()}</h2>
|
|
49
|
-
<Show when={props.greeting?.subtitle}>
|
|
50
|
-
<p class="text-sm text-muted-foreground">{props.greeting!.subtitle}</p>
|
|
51
|
-
</Show>
|
|
52
|
-
</div>
|
|
53
|
-
|
|
54
|
-
<Show when={props.recent}>
|
|
55
|
-
{(recent) => {
|
|
56
|
-
const time = () => relativeTimeShort(recent().updatedAt ?? recent().lastMessageAt);
|
|
57
|
-
const unread = () => isConversationUnread(recent());
|
|
58
|
-
return (
|
|
59
|
-
<button
|
|
60
|
-
type="button"
|
|
61
|
-
data-kai-home-recent
|
|
62
|
-
onClick={() => props.onSelectRecent?.(recent().id)}
|
|
63
|
-
class="flex flex-col gap-1 rounded-xl border border-border p-4 text-left transition-colors hover:bg-accent"
|
|
64
|
-
>
|
|
65
|
-
<span class="flex items-center gap-2 text-sm font-semibold text-foreground">
|
|
66
|
-
<span class="min-w-0 flex-1 truncate">{recent().title}</span>
|
|
67
|
-
<Show when={unread()}>
|
|
68
|
-
<span aria-hidden="true" class="size-1.5 shrink-0 rounded-full bg-unread" />
|
|
69
|
-
</Show>
|
|
70
|
-
<Show when={time()}>
|
|
71
|
-
<span class="shrink-0 text-xs font-normal text-muted-foreground">{time()}</span>
|
|
72
|
-
</Show>
|
|
73
|
-
</span>
|
|
74
|
-
<Show when={recent().trailing}>
|
|
75
|
-
<span class="line-clamp-1 text-sm text-muted-foreground">{recent().trailing}</span>
|
|
76
|
-
</Show>
|
|
77
|
-
</button>
|
|
78
|
-
);
|
|
79
|
-
}}
|
|
80
|
-
</Show>
|
|
81
|
-
|
|
82
|
-
<Show when={props.showNewConversation !== false}>
|
|
83
|
-
<Button
|
|
84
|
-
type="button"
|
|
85
|
-
data-kai-home-new
|
|
86
|
-
full
|
|
87
|
-
align="start"
|
|
88
|
-
onClick={() => props.onNewChat()}
|
|
89
|
-
class="justify-between"
|
|
90
|
-
>
|
|
91
|
-
<span>{props.newChatLabel ?? 'Send us a message'}</span>
|
|
92
|
-
{renderIcon('arrow-right', { class: 'size-4 shrink-0' })}
|
|
93
|
-
</Button>
|
|
94
|
-
</Show>
|
|
95
|
-
|
|
96
|
-
<Show when={props.links && props.links.length > 0}>
|
|
97
|
-
<div class="flex flex-col overflow-hidden rounded-xl border border-border">
|
|
98
|
-
<For each={props.links}>
|
|
99
|
-
{(entry) => {
|
|
100
|
-
const safeHref = () => (entry.href && isSafeUrl(entry.href) ? entry.href : undefined);
|
|
101
|
-
const inner = (
|
|
102
|
-
<>
|
|
103
|
-
<span class="flex min-w-0 items-center gap-2">
|
|
104
|
-
<Show when={entry.icon}>{renderIcon(entry.icon, { class: 'size-4 shrink-0 text-muted-foreground' })}</Show>
|
|
105
|
-
<span class="flex min-w-0 flex-col text-left">
|
|
106
|
-
<span class="truncate text-sm font-medium text-foreground">{entry.label}</span>
|
|
107
|
-
<Show when={entry.description}>
|
|
108
|
-
<span class="truncate text-xs text-muted-foreground">{entry.description}</span>
|
|
109
|
-
</Show>
|
|
110
|
-
</span>
|
|
111
|
-
</span>
|
|
112
|
-
{renderIcon('chevron-right', { class: 'size-4 shrink-0 text-muted-foreground' })}
|
|
113
|
-
</>
|
|
114
|
-
);
|
|
115
|
-
const rowClass = 'flex items-center justify-between gap-2 border-b border-border p-3 last:border-b-0';
|
|
116
|
-
return (
|
|
117
|
-
<Show
|
|
118
|
-
when={!entry.href}
|
|
119
|
-
fallback={
|
|
120
|
-
<Show
|
|
121
|
-
when={safeHref()}
|
|
122
|
-
fallback={
|
|
123
|
-
// Unsafe href: a non-interactive row. No anchor, no
|
|
124
|
-
// button, no handler — the label stays visible, it
|
|
125
|
-
// just never becomes clickable.
|
|
126
|
-
<div data-kai-home-link class={rowClass}>
|
|
127
|
-
{inner}
|
|
128
|
-
</div>
|
|
129
|
-
}
|
|
130
|
-
>
|
|
131
|
-
<a
|
|
132
|
-
data-kai-home-link
|
|
133
|
-
href={safeHref()}
|
|
134
|
-
target="_blank"
|
|
135
|
-
rel="noreferrer noopener"
|
|
136
|
-
class={cn(rowClass, 'transition-colors hover:bg-accent')}
|
|
137
|
-
>
|
|
138
|
-
{inner}
|
|
139
|
-
</a>
|
|
140
|
-
</Show>
|
|
141
|
-
}
|
|
142
|
-
>
|
|
143
|
-
<button
|
|
144
|
-
type="button"
|
|
145
|
-
data-kai-home-link
|
|
146
|
-
onClick={() => props.onLink?.(entry)}
|
|
147
|
-
class={cn(rowClass, 'w-full text-left transition-colors hover:bg-accent')}
|
|
148
|
-
>
|
|
149
|
-
{inner}
|
|
150
|
-
</button>
|
|
151
|
-
</Show>
|
|
152
|
-
);
|
|
153
|
-
}}
|
|
154
|
-
</For>
|
|
155
|
-
</div>
|
|
156
|
-
</Show>
|
|
157
|
-
</div>
|
|
158
|
-
);
|
|
159
|
-
}
|
package/src/components/image.tsx
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { type JSX, splitProps, createSignal, createEffect, onCleanup, Show } from 'solid-js';
|
|
2
|
-
import { cn } from '../utils/cn';
|
|
3
|
-
import { Skeleton } from '../ui/skeleton';
|
|
4
|
-
|
|
5
|
-
export interface GeneratedImageLike {
|
|
6
|
-
base64?: string;
|
|
7
|
-
uint8Array?: Uint8Array;
|
|
8
|
-
mediaType?: string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface ImageProps extends GeneratedImageLike {
|
|
12
|
-
alt: string;
|
|
13
|
-
class?: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function getImageSrc(base64?: string, mediaType?: string): string | undefined {
|
|
17
|
-
if (base64 && mediaType) {
|
|
18
|
-
return `data:${mediaType};base64,${base64}`;
|
|
19
|
-
}
|
|
20
|
-
return undefined;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function Image(props: ImageProps) {
|
|
24
|
-
const [local, rest] = splitProps(props, ['base64', 'uint8Array', 'mediaType', 'class', 'alt']);
|
|
25
|
-
const [objectUrl, setObjectUrl] = createSignal<string | undefined>(undefined);
|
|
26
|
-
|
|
27
|
-
const mediaType = () => local.mediaType ?? 'image/png';
|
|
28
|
-
|
|
29
|
-
createEffect(() => {
|
|
30
|
-
const arr = local.uint8Array;
|
|
31
|
-
const mt = mediaType();
|
|
32
|
-
if (arr && mt) {
|
|
33
|
-
const blob = new Blob([arr as BlobPart], { type: mt });
|
|
34
|
-
const url = URL.createObjectURL(blob);
|
|
35
|
-
setObjectUrl(url);
|
|
36
|
-
onCleanup(() => URL.revokeObjectURL(url));
|
|
37
|
-
} else {
|
|
38
|
-
setObjectUrl(undefined);
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
const src = () => getImageSrc(local.base64, mediaType()) ?? objectUrl();
|
|
43
|
-
|
|
44
|
-
return (
|
|
45
|
-
<Show
|
|
46
|
-
when={src()}
|
|
47
|
-
fallback={
|
|
48
|
-
<Skeleton
|
|
49
|
-
aria-label={local.alt}
|
|
50
|
-
role="img"
|
|
51
|
-
class={cn('h-auto max-w-full overflow-hidden', local.class)}
|
|
52
|
-
/>
|
|
53
|
-
}
|
|
54
|
-
>
|
|
55
|
-
<img
|
|
56
|
-
src={src()}
|
|
57
|
-
alt={local.alt}
|
|
58
|
-
class={cn('h-auto max-w-full overflow-hidden rounded-md', local.class)}
|
|
59
|
-
role="img"
|
|
60
|
-
/>
|
|
61
|
-
</Show>
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export { Image };
|
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type JSX,
|
|
3
|
-
splitProps,
|
|
4
|
-
createSignal,
|
|
5
|
-
createEffect,
|
|
6
|
-
createMemo,
|
|
7
|
-
on,
|
|
8
|
-
onMount,
|
|
9
|
-
onCleanup,
|
|
10
|
-
Show,
|
|
11
|
-
} from 'solid-js';
|
|
12
|
-
import { cn } from '../utils/cn';
|
|
13
|
-
import { Skeleton } from '../ui/skeleton';
|
|
14
|
-
import { Link as LinkIcon } from 'lucide-solid';
|
|
15
|
-
import type { CardEvent } from '../primitives/card-contract';
|
|
16
|
-
import {
|
|
17
|
-
type LinkPreviewData,
|
|
18
|
-
deriveDomain,
|
|
19
|
-
isRenderableLink,
|
|
20
|
-
hasLinkPreviewFetcher,
|
|
21
|
-
resolveLinkMetadata,
|
|
22
|
-
} from '../primitives/link-preview';
|
|
23
|
-
|
|
24
|
-
export interface LinkPreviewProps {
|
|
25
|
-
/** The card id correlating every emitted event. */
|
|
26
|
-
cardId: string;
|
|
27
|
-
/** The link payload (data-down). */
|
|
28
|
-
data: LinkPreviewData;
|
|
29
|
-
/** Emit a contract CardEvent up (host routes it). */
|
|
30
|
-
onEmit?: (event: CardEvent) => void;
|
|
31
|
-
/** Extra classes for the card root. */
|
|
32
|
-
class?: string;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/** True when the payload already carries renderable metadata (the pure path). */
|
|
36
|
-
function hasMetadata(data: LinkPreviewData): boolean {
|
|
37
|
-
return Boolean(data.title || data.description || data.image);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* `LinkPreview` — a pure, themed, accessible rich link / OG preview. Renders from the
|
|
42
|
-
* supplied metadata; it never fetches the network itself. When the payload is a
|
|
43
|
-
* bare `{ url }` and an app has registered a `configureLinkPreview` fetcher, it
|
|
44
|
-
* shows a skeleton, calls the hook, merges the result, and renders. Activating the
|
|
45
|
-
* card (click / Enter / Space) emits the contract `open` verb (`target:'tab'`); the
|
|
46
|
-
* host policy performs the navigation so it can veto/redirect.
|
|
47
|
-
*/
|
|
48
|
-
export function LinkPreview(props: LinkPreviewProps): JSX.Element {
|
|
49
|
-
const [local] = splitProps(props, ['cardId', 'data', 'onEmit', 'class']);
|
|
50
|
-
|
|
51
|
-
const emit = (event: CardEvent) => local.onEmit?.(event);
|
|
52
|
-
|
|
53
|
-
// Bare-URL resolution state (only used when the payload lacks metadata + a fetcher exists).
|
|
54
|
-
const [fetched, setFetched] = createSignal<Partial<LinkPreviewData> | undefined>();
|
|
55
|
-
const [loading, setLoading] = createSignal(false);
|
|
56
|
-
const [imageBroken, setImageBroken] = createSignal(false);
|
|
57
|
-
|
|
58
|
-
const url = () => local.data.url;
|
|
59
|
-
const valid = createMemo(() => isRenderableLink(url()));
|
|
60
|
-
|
|
61
|
-
// The effective payload = supplied data merged with any fetched metadata.
|
|
62
|
-
const effective = createMemo<LinkPreviewData>(() => ({ ...local.data, ...fetched() }));
|
|
63
|
-
|
|
64
|
-
// Lifecycle `ready` once on mount.
|
|
65
|
-
onMount(() => emit({ kind: 'ready', cardId: local.cardId }));
|
|
66
|
-
|
|
67
|
-
// Invalid URL → emit a single `error` (belt-and-suspenders; host also rejects bad schemes on open).
|
|
68
|
-
createEffect(
|
|
69
|
-
on(valid, (ok) => {
|
|
70
|
-
if (!ok) emit({ kind: 'error', cardId: local.cardId, message: `Invalid link url: ${url()}` });
|
|
71
|
-
}),
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
// Bare-URL path: when there's no metadata AND a fetcher is configured, resolve once.
|
|
75
|
-
createEffect(
|
|
76
|
-
on(
|
|
77
|
-
() => [local.data, valid()] as const,
|
|
78
|
-
([data, ok]) => {
|
|
79
|
-
setImageBroken(false);
|
|
80
|
-
if (!ok || hasMetadata(data) || !hasLinkPreviewFetcher()) return;
|
|
81
|
-
let cancelled = false;
|
|
82
|
-
// Cancel a stale in-flight fetch if `data` changes before it resolves.
|
|
83
|
-
onCleanup(() => {
|
|
84
|
-
cancelled = true;
|
|
85
|
-
});
|
|
86
|
-
setLoading(true);
|
|
87
|
-
resolveLinkMetadata(data.url)
|
|
88
|
-
.then((meta) => {
|
|
89
|
-
if (!cancelled) setFetched(meta);
|
|
90
|
-
})
|
|
91
|
-
.catch(() => {
|
|
92
|
-
// Reject → fall back to the bare link chip; the URL itself is still usable.
|
|
93
|
-
if (!cancelled) setFetched({});
|
|
94
|
-
})
|
|
95
|
-
.finally(() => {
|
|
96
|
-
if (!cancelled) setLoading(false);
|
|
97
|
-
});
|
|
98
|
-
},
|
|
99
|
-
),
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
const domain = createMemo(() => effective().domain ?? deriveDomain(url()) ?? url());
|
|
103
|
-
const heading = createMemo(() => effective().siteName ?? domain());
|
|
104
|
-
const titleText = createMemo(() => effective().title ?? domain());
|
|
105
|
-
const showImage = createMemo(() => Boolean(effective().image) && !imageBroken());
|
|
106
|
-
|
|
107
|
-
const activate = () => {
|
|
108
|
-
if (!valid()) return;
|
|
109
|
-
emit({ kind: 'open', cardId: local.cardId, url: url(), target: 'tab' });
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
const onClick = (e: MouseEvent) => {
|
|
113
|
-
// Intercept the anchor's default navigation so it routes through host policy.
|
|
114
|
-
// (Middle-click / cmd-click still open the real href in a new tab — acceptable + safe.)
|
|
115
|
-
e.preventDefault();
|
|
116
|
-
activate();
|
|
117
|
-
};
|
|
118
|
-
const onKeyDown = (e: KeyboardEvent) => {
|
|
119
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
120
|
-
e.preventDefault();
|
|
121
|
-
activate();
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
// --- Invalid-link error chip ------------------------------------------
|
|
126
|
-
return (
|
|
127
|
-
<Show
|
|
128
|
-
when={valid()}
|
|
129
|
-
fallback={
|
|
130
|
-
<div
|
|
131
|
-
role="img"
|
|
132
|
-
aria-label="Invalid link"
|
|
133
|
-
class={cn(
|
|
134
|
-
'flex items-center gap-2 rounded-xl border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive dark:border-red-400/50 dark:bg-destructive/20 dark:text-red-400',
|
|
135
|
-
local.class,
|
|
136
|
-
)}
|
|
137
|
-
>
|
|
138
|
-
<LinkIcon size={16} aria-hidden="true" />
|
|
139
|
-
<span class="truncate">Invalid link</span>
|
|
140
|
-
</div>
|
|
141
|
-
}
|
|
142
|
-
>
|
|
143
|
-
<a
|
|
144
|
-
href={url()}
|
|
145
|
-
rel="noopener noreferrer"
|
|
146
|
-
aria-label={`Open ${titleText()} on ${domain()}`}
|
|
147
|
-
class={cn(
|
|
148
|
-
'group block overflow-hidden rounded-xl border border-border bg-card text-card-foreground no-underline outline-none transition-shadow',
|
|
149
|
-
'cursor-pointer hover:shadow-md focus-visible:ring-2 focus-visible:ring-ring',
|
|
150
|
-
local.class,
|
|
151
|
-
)}
|
|
152
|
-
onClick={onClick}
|
|
153
|
-
onKeyDown={onKeyDown}
|
|
154
|
-
>
|
|
155
|
-
<Show when={loading()}>
|
|
156
|
-
{/* Skeleton while the bare-URL fetcher resolves. */}
|
|
157
|
-
<Skeleton class="aspect-[16/9] w-full rounded-none" />
|
|
158
|
-
<div class="space-y-2 p-3">
|
|
159
|
-
<Skeleton class="h-3 w-1/3" />
|
|
160
|
-
<Skeleton class="h-4 w-2/3" />
|
|
161
|
-
<Skeleton class="h-3 w-full" />
|
|
162
|
-
</div>
|
|
163
|
-
</Show>
|
|
164
|
-
<Show when={!loading()}>
|
|
165
|
-
<Show when={showImage()}>
|
|
166
|
-
<img
|
|
167
|
-
src={effective().image}
|
|
168
|
-
alt={effective().imageAlt ?? ''}
|
|
169
|
-
role="img"
|
|
170
|
-
class="aspect-[16/9] w-full object-cover"
|
|
171
|
-
onError={() => setImageBroken(true)}
|
|
172
|
-
/>
|
|
173
|
-
</Show>
|
|
174
|
-
<div class="space-y-1 p-3">
|
|
175
|
-
<div class="flex items-center gap-1.5 text-xs text-muted-foreground">
|
|
176
|
-
<Show
|
|
177
|
-
when={effective().favicon}
|
|
178
|
-
fallback={<LinkIcon size={12} class="shrink-0 opacity-70" aria-hidden="true" />}
|
|
179
|
-
>
|
|
180
|
-
<img src={effective().favicon} alt="" class="h-3.5 w-3.5 shrink-0 rounded-sm" />
|
|
181
|
-
</Show>
|
|
182
|
-
<span class="truncate">{heading()}</span>
|
|
183
|
-
</div>
|
|
184
|
-
<div class="line-clamp-2 text-sm font-semibold text-foreground">{titleText()}</div>
|
|
185
|
-
<Show when={effective().description}>
|
|
186
|
-
<div class="line-clamp-3 text-xs text-muted-foreground">{effective().description}</div>
|
|
187
|
-
</Show>
|
|
188
|
-
</div>
|
|
189
|
-
</Show>
|
|
190
|
-
</a>
|
|
191
|
-
</Show>
|
|
192
|
-
);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
export type { LinkPreviewData } from '../primitives/link-preview';
|