@oh-my-pi/pi-web-ui 1.337.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/CHANGELOG.md +96 -0
- package/README.md +609 -0
- package/example/README.md +61 -0
- package/example/index.html +13 -0
- package/example/package.json +24 -0
- package/example/src/app.css +1 -0
- package/example/src/custom-messages.ts +99 -0
- package/example/src/main.ts +420 -0
- package/example/tsconfig.json +23 -0
- package/example/vite.config.ts +6 -0
- package/package.json +57 -0
- package/scripts/count-prompt-tokens.ts +88 -0
- package/src/ChatPanel.ts +218 -0
- package/src/app.css +68 -0
- package/src/components/AgentInterface.ts +390 -0
- package/src/components/AttachmentTile.ts +107 -0
- package/src/components/ConsoleBlock.ts +74 -0
- package/src/components/CustomProviderCard.ts +96 -0
- package/src/components/ExpandableSection.ts +46 -0
- package/src/components/Input.ts +113 -0
- package/src/components/MessageEditor.ts +404 -0
- package/src/components/MessageList.ts +97 -0
- package/src/components/Messages.ts +384 -0
- package/src/components/ProviderKeyInput.ts +152 -0
- package/src/components/SandboxedIframe.ts +626 -0
- package/src/components/StreamingMessageContainer.ts +107 -0
- package/src/components/ThinkingBlock.ts +45 -0
- package/src/components/message-renderer-registry.ts +28 -0
- package/src/components/sandbox/ArtifactsRuntimeProvider.ts +219 -0
- package/src/components/sandbox/AttachmentsRuntimeProvider.ts +66 -0
- package/src/components/sandbox/ConsoleRuntimeProvider.ts +186 -0
- package/src/components/sandbox/FileDownloadRuntimeProvider.ts +110 -0
- package/src/components/sandbox/RuntimeMessageBridge.ts +82 -0
- package/src/components/sandbox/RuntimeMessageRouter.ts +216 -0
- package/src/components/sandbox/SandboxRuntimeProvider.ts +52 -0
- package/src/dialogs/ApiKeyPromptDialog.ts +75 -0
- package/src/dialogs/AttachmentOverlay.ts +640 -0
- package/src/dialogs/CustomProviderDialog.ts +274 -0
- package/src/dialogs/ModelSelector.ts +314 -0
- package/src/dialogs/PersistentStorageDialog.ts +146 -0
- package/src/dialogs/ProvidersModelsTab.ts +212 -0
- package/src/dialogs/SessionListDialog.ts +157 -0
- package/src/dialogs/SettingsDialog.ts +216 -0
- package/src/index.ts +115 -0
- package/src/prompts/prompts.ts +282 -0
- package/src/storage/app-storage.ts +60 -0
- package/src/storage/backends/indexeddb-storage-backend.ts +193 -0
- package/src/storage/store.ts +33 -0
- package/src/storage/stores/custom-providers-store.ts +62 -0
- package/src/storage/stores/provider-keys-store.ts +33 -0
- package/src/storage/stores/sessions-store.ts +136 -0
- package/src/storage/stores/settings-store.ts +34 -0
- package/src/storage/types.ts +206 -0
- package/src/tools/artifacts/ArtifactElement.ts +14 -0
- package/src/tools/artifacts/ArtifactPill.ts +26 -0
- package/src/tools/artifacts/Console.ts +102 -0
- package/src/tools/artifacts/DocxArtifact.ts +213 -0
- package/src/tools/artifacts/ExcelArtifact.ts +231 -0
- package/src/tools/artifacts/GenericArtifact.ts +118 -0
- package/src/tools/artifacts/HtmlArtifact.ts +203 -0
- package/src/tools/artifacts/ImageArtifact.ts +116 -0
- package/src/tools/artifacts/MarkdownArtifact.ts +83 -0
- package/src/tools/artifacts/PdfArtifact.ts +201 -0
- package/src/tools/artifacts/SvgArtifact.ts +82 -0
- package/src/tools/artifacts/TextArtifact.ts +148 -0
- package/src/tools/artifacts/artifacts-tool-renderer.ts +371 -0
- package/src/tools/artifacts/artifacts.ts +713 -0
- package/src/tools/artifacts/index.ts +7 -0
- package/src/tools/extract-document.ts +271 -0
- package/src/tools/index.ts +46 -0
- package/src/tools/javascript-repl.ts +316 -0
- package/src/tools/renderer-registry.ts +127 -0
- package/src/tools/renderers/BashRenderer.ts +52 -0
- package/src/tools/renderers/CalculateRenderer.ts +58 -0
- package/src/tools/renderers/DefaultRenderer.ts +95 -0
- package/src/tools/renderers/GetCurrentTimeRenderer.ts +92 -0
- package/src/tools/types.ts +15 -0
- package/src/utils/attachment-utils.ts +472 -0
- package/src/utils/auth-token.ts +22 -0
- package/src/utils/format.ts +42 -0
- package/src/utils/i18n.ts +653 -0
- package/src/utils/model-discovery.ts +277 -0
- package/src/utils/proxy-utils.ts +134 -0
- package/src/utils/test-sessions.ts +2357 -0
- package/tsconfig.build.json +20 -0
- package/tsconfig.json +7 -0
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@oh-my-pi/pi-web-ui",
|
|
3
|
+
"version": "1.337.0",
|
|
4
|
+
"description": "Reusable web UI components for AI chat interfaces powered by @oh-my-pi/pi-ai",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.ts",
|
|
7
|
+
"types": "src/index.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./src/index.ts",
|
|
10
|
+
"./app.css": "./src/app.css"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"dev:css": "tailwindcss -i ./src/app.css -o ./dist/app.css --watch",
|
|
14
|
+
"dev:example": "bun --cwd=example run dev",
|
|
15
|
+
"dev": "bun run dev:css & bun run dev:example",
|
|
16
|
+
"build:css": "tailwindcss -i ./src/app.css -o ./dist/app.css --minify",
|
|
17
|
+
"check": "biome check --write . && tsgo --noEmit && bun --cwd=example run check"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@lmstudio/sdk": "^1.5.0",
|
|
21
|
+
"@oh-my-pi/pi-agent-core": "workspace:*",
|
|
22
|
+
"@oh-my-pi/pi-ai": "workspace:*",
|
|
23
|
+
"@oh-my-pi/pi-tui": "workspace:*",
|
|
24
|
+
"docx-preview": "^0.3.7",
|
|
25
|
+
"highlight.js": "^11.11.1",
|
|
26
|
+
"jszip": "^3.10.1",
|
|
27
|
+
"lucide": "^0.544.0",
|
|
28
|
+
"ollama": "^0.6.0",
|
|
29
|
+
"pdfjs-dist": "5.4.394",
|
|
30
|
+
"tailwindcss": "^4.1.18",
|
|
31
|
+
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"@mariozechner/mini-lit": "^0.2.0",
|
|
35
|
+
"lit": "^3.3.1"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@mariozechner/mini-lit": "^0.2.0",
|
|
39
|
+
"@tailwindcss/cli": "^4.0.0-beta.14"
|
|
40
|
+
},
|
|
41
|
+
"keywords": [
|
|
42
|
+
"ai",
|
|
43
|
+
"chat",
|
|
44
|
+
"ui",
|
|
45
|
+
"components",
|
|
46
|
+
"llm",
|
|
47
|
+
"web-components",
|
|
48
|
+
"mini-lit"
|
|
49
|
+
],
|
|
50
|
+
"author": "Mario Zechner",
|
|
51
|
+
"license": "MIT",
|
|
52
|
+
"repository": {
|
|
53
|
+
"type": "git",
|
|
54
|
+
"url": "git+https://github.com/can1357/oh-my-pi.git",
|
|
55
|
+
"directory": "packages/web-ui"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Count tokens in system prompts using Anthropic's token counter API
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as prompts from "../src/prompts/prompts.js";
|
|
7
|
+
|
|
8
|
+
const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY;
|
|
9
|
+
|
|
10
|
+
if (!ANTHROPIC_API_KEY) {
|
|
11
|
+
console.error("Error: ANTHROPIC_API_KEY environment variable not set");
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface TokenCountResponse {
|
|
16
|
+
input_tokens: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async function countTokens(text: string): Promise<number> {
|
|
20
|
+
const response = await fetch("https://api.anthropic.com/v1/messages/count_tokens", {
|
|
21
|
+
method: "POST",
|
|
22
|
+
headers: {
|
|
23
|
+
"Content-Type": "application/json",
|
|
24
|
+
"x-api-key": ANTHROPIC_API_KEY,
|
|
25
|
+
"anthropic-version": "2023-06-01",
|
|
26
|
+
},
|
|
27
|
+
body: JSON.stringify({
|
|
28
|
+
model: "claude-3-5-sonnet-20241022",
|
|
29
|
+
messages: [
|
|
30
|
+
{
|
|
31
|
+
role: "user",
|
|
32
|
+
content: text,
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
}),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
if (!response.ok) {
|
|
39
|
+
const error = await response.text();
|
|
40
|
+
throw new Error(`API error: ${response.status} ${error}`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const data = (await response.json()) as TokenCountResponse;
|
|
44
|
+
return data.input_tokens;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function main() {
|
|
48
|
+
console.log("Counting tokens in prompts...\n");
|
|
49
|
+
|
|
50
|
+
const promptsToCount: Array<{ name: string; content: string }> = [
|
|
51
|
+
{
|
|
52
|
+
name: "ARTIFACTS_RUNTIME_PROVIDER_DESCRIPTION_RW",
|
|
53
|
+
content: prompts.ARTIFACTS_RUNTIME_PROVIDER_DESCRIPTION_RW,
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: "ARTIFACTS_RUNTIME_PROVIDER_DESCRIPTION_RO",
|
|
57
|
+
content: prompts.ARTIFACTS_RUNTIME_PROVIDER_DESCRIPTION_RO,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: "ATTACHMENTS_RUNTIME_DESCRIPTION",
|
|
61
|
+
content: prompts.ATTACHMENTS_RUNTIME_DESCRIPTION,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: "JAVASCRIPT_REPL_TOOL_DESCRIPTION (without runtime providers)",
|
|
65
|
+
content: prompts.JAVASCRIPT_REPL_TOOL_DESCRIPTION([]),
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: "ARTIFACTS_TOOL_DESCRIPTION (without runtime providers)",
|
|
69
|
+
content: prompts.ARTIFACTS_TOOL_DESCRIPTION([]),
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
let total = 0;
|
|
74
|
+
|
|
75
|
+
for (const prompt of promptsToCount) {
|
|
76
|
+
try {
|
|
77
|
+
const tokens = await countTokens(prompt.content);
|
|
78
|
+
total += tokens;
|
|
79
|
+
console.log(`${prompt.name}: ${tokens.toLocaleString()} tokens`);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error(`Error counting tokens for ${prompt.name}:`, error);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
console.log(`\nTotal: ${total.toLocaleString()} tokens`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
main();
|
package/src/ChatPanel.ts
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { Badge } from "@mariozechner/mini-lit/dist/Badge.js";
|
|
2
|
+
import { html, LitElement } from "lit";
|
|
3
|
+
import { customElement, state } from "lit/decorators.js";
|
|
4
|
+
import "./components/AgentInterface.js";
|
|
5
|
+
import type { Agent, AgentTool } from "@oh-my-pi/pi-agent-core";
|
|
6
|
+
import type { AgentInterface } from "./components/AgentInterface.js";
|
|
7
|
+
import { ArtifactsRuntimeProvider } from "./components/sandbox/ArtifactsRuntimeProvider.js";
|
|
8
|
+
import { AttachmentsRuntimeProvider } from "./components/sandbox/AttachmentsRuntimeProvider.js";
|
|
9
|
+
import type { SandboxRuntimeProvider } from "./components/sandbox/SandboxRuntimeProvider.js";
|
|
10
|
+
import { ArtifactsPanel, ArtifactsToolRenderer } from "./tools/artifacts/index.js";
|
|
11
|
+
import { registerToolRenderer } from "./tools/renderer-registry.js";
|
|
12
|
+
import type { Attachment } from "./utils/attachment-utils.js";
|
|
13
|
+
import { i18n } from "./utils/i18n.js";
|
|
14
|
+
|
|
15
|
+
const BREAKPOINT = 800; // px - switch between overlay and side-by-side
|
|
16
|
+
|
|
17
|
+
@customElement("pi-chat-panel")
|
|
18
|
+
export class ChatPanel extends LitElement {
|
|
19
|
+
@state() public agent?: Agent;
|
|
20
|
+
@state() public agentInterface?: AgentInterface;
|
|
21
|
+
@state() public artifactsPanel?: ArtifactsPanel;
|
|
22
|
+
@state() private hasArtifacts = false;
|
|
23
|
+
@state() private artifactCount = 0;
|
|
24
|
+
@state() private showArtifactsPanel = false;
|
|
25
|
+
@state() private windowWidth = 0;
|
|
26
|
+
|
|
27
|
+
private resizeHandler = () => {
|
|
28
|
+
this.windowWidth = window.innerWidth;
|
|
29
|
+
this.requestUpdate();
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
createRenderRoot() {
|
|
33
|
+
return this;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
override connectedCallback() {
|
|
37
|
+
super.connectedCallback();
|
|
38
|
+
this.windowWidth = window.innerWidth; // Set initial width after connection
|
|
39
|
+
window.addEventListener("resize", this.resizeHandler);
|
|
40
|
+
this.style.display = "flex";
|
|
41
|
+
this.style.flexDirection = "column";
|
|
42
|
+
this.style.height = "100%";
|
|
43
|
+
this.style.minHeight = "0";
|
|
44
|
+
// Update width after initial render
|
|
45
|
+
requestAnimationFrame(() => {
|
|
46
|
+
this.windowWidth = window.innerWidth;
|
|
47
|
+
this.requestUpdate();
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
override disconnectedCallback() {
|
|
52
|
+
super.disconnectedCallback();
|
|
53
|
+
window.removeEventListener("resize", this.resizeHandler);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async setAgent(
|
|
57
|
+
agent: Agent,
|
|
58
|
+
config?: {
|
|
59
|
+
onApiKeyRequired?: (provider: string) => Promise<boolean>;
|
|
60
|
+
onBeforeSend?: () => void | Promise<void>;
|
|
61
|
+
onCostClick?: () => void;
|
|
62
|
+
sandboxUrlProvider?: () => string;
|
|
63
|
+
toolsFactory?: (
|
|
64
|
+
agent: Agent,
|
|
65
|
+
agentInterface: AgentInterface,
|
|
66
|
+
artifactsPanel: ArtifactsPanel,
|
|
67
|
+
runtimeProvidersFactory: () => SandboxRuntimeProvider[],
|
|
68
|
+
) => AgentTool<any>[];
|
|
69
|
+
},
|
|
70
|
+
) {
|
|
71
|
+
this.agent = agent;
|
|
72
|
+
|
|
73
|
+
// Create AgentInterface
|
|
74
|
+
this.agentInterface = document.createElement("agent-interface") as AgentInterface;
|
|
75
|
+
this.agentInterface.session = agent;
|
|
76
|
+
this.agentInterface.enableAttachments = true;
|
|
77
|
+
this.agentInterface.enableModelSelector = true;
|
|
78
|
+
this.agentInterface.enableThinkingSelector = true;
|
|
79
|
+
this.agentInterface.showThemeToggle = false;
|
|
80
|
+
this.agentInterface.onApiKeyRequired = config?.onApiKeyRequired;
|
|
81
|
+
this.agentInterface.onBeforeSend = config?.onBeforeSend;
|
|
82
|
+
this.agentInterface.onCostClick = config?.onCostClick;
|
|
83
|
+
|
|
84
|
+
// Set up artifacts panel
|
|
85
|
+
this.artifactsPanel = new ArtifactsPanel();
|
|
86
|
+
this.artifactsPanel.agent = agent; // Pass agent for HTML artifact runtime providers
|
|
87
|
+
if (config?.sandboxUrlProvider) {
|
|
88
|
+
this.artifactsPanel.sandboxUrlProvider = config.sandboxUrlProvider;
|
|
89
|
+
}
|
|
90
|
+
// Register the standalone tool renderer (not the panel itself)
|
|
91
|
+
registerToolRenderer("artifacts", new ArtifactsToolRenderer(this.artifactsPanel));
|
|
92
|
+
|
|
93
|
+
// Runtime providers factory for REPL tools (read-write access)
|
|
94
|
+
const runtimeProvidersFactory = () => {
|
|
95
|
+
const attachments: Attachment[] = [];
|
|
96
|
+
for (const message of this.agent!.state.messages) {
|
|
97
|
+
if (message.role === "user-with-attachments") {
|
|
98
|
+
message.attachments?.forEach((a) => {
|
|
99
|
+
attachments.push(a);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const providers: SandboxRuntimeProvider[] = [];
|
|
104
|
+
|
|
105
|
+
// Add attachments provider if there are attachments
|
|
106
|
+
if (attachments.length > 0) {
|
|
107
|
+
providers.push(new AttachmentsRuntimeProvider(attachments));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Add artifacts provider with read-write access (for REPL)
|
|
111
|
+
providers.push(new ArtifactsRuntimeProvider(this.artifactsPanel!, this.agent!, true));
|
|
112
|
+
|
|
113
|
+
return providers;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
this.artifactsPanel.onArtifactsChange = () => {
|
|
117
|
+
const count = this.artifactsPanel?.artifacts?.size ?? 0;
|
|
118
|
+
const created = count > this.artifactCount;
|
|
119
|
+
this.hasArtifacts = count > 0;
|
|
120
|
+
this.artifactCount = count;
|
|
121
|
+
if (this.hasArtifacts && created) {
|
|
122
|
+
this.showArtifactsPanel = true;
|
|
123
|
+
}
|
|
124
|
+
this.requestUpdate();
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
this.artifactsPanel.onClose = () => {
|
|
128
|
+
this.showArtifactsPanel = false;
|
|
129
|
+
this.requestUpdate();
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
this.artifactsPanel.onOpen = () => {
|
|
133
|
+
this.showArtifactsPanel = true;
|
|
134
|
+
this.requestUpdate();
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
// Set tools on the agent
|
|
138
|
+
// Pass runtimeProvidersFactory so consumers can configure their own REPL tools
|
|
139
|
+
const additionalTools =
|
|
140
|
+
config?.toolsFactory?.(agent, this.agentInterface, this.artifactsPanel, runtimeProvidersFactory) || [];
|
|
141
|
+
const tools = [this.artifactsPanel.tool, ...additionalTools];
|
|
142
|
+
this.agent.setTools(tools);
|
|
143
|
+
|
|
144
|
+
// Reconstruct artifacts from existing messages
|
|
145
|
+
// Temporarily disable the onArtifactsChange callback to prevent auto-opening on load
|
|
146
|
+
const originalCallback = this.artifactsPanel.onArtifactsChange;
|
|
147
|
+
this.artifactsPanel.onArtifactsChange = undefined;
|
|
148
|
+
await this.artifactsPanel.reconstructFromMessages(this.agent.state.messages);
|
|
149
|
+
this.artifactsPanel.onArtifactsChange = originalCallback;
|
|
150
|
+
|
|
151
|
+
this.hasArtifacts = this.artifactsPanel.artifacts.size > 0;
|
|
152
|
+
this.artifactCount = this.artifactsPanel.artifacts.size;
|
|
153
|
+
|
|
154
|
+
this.requestUpdate();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
render() {
|
|
158
|
+
if (!this.agent || !this.agentInterface) {
|
|
159
|
+
return html`<div class="flex items-center justify-center h-full">
|
|
160
|
+
<div class="text-muted-foreground">No agent set</div>
|
|
161
|
+
</div>`;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const isMobile = this.windowWidth < BREAKPOINT;
|
|
165
|
+
|
|
166
|
+
// Set panel props
|
|
167
|
+
if (this.artifactsPanel) {
|
|
168
|
+
this.artifactsPanel.collapsed = !this.showArtifactsPanel;
|
|
169
|
+
this.artifactsPanel.overlay = isMobile;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return html`
|
|
173
|
+
<div class="relative w-full h-full overflow-hidden flex">
|
|
174
|
+
<div
|
|
175
|
+
class="h-full"
|
|
176
|
+
style="${!isMobile && this.showArtifactsPanel && this.hasArtifacts ? "width: 50%;" : "width: 100%;"}"
|
|
177
|
+
>
|
|
178
|
+
${this.agentInterface}
|
|
179
|
+
</div>
|
|
180
|
+
|
|
181
|
+
<!-- Floating pill when artifacts exist and panel is collapsed -->
|
|
182
|
+
${
|
|
183
|
+
this.hasArtifacts && !this.showArtifactsPanel
|
|
184
|
+
? html`
|
|
185
|
+
<button
|
|
186
|
+
class="absolute z-30 top-4 left-1/2 -translate-x-1/2 pointer-events-auto"
|
|
187
|
+
@click=${() => {
|
|
188
|
+
this.showArtifactsPanel = true;
|
|
189
|
+
this.requestUpdate();
|
|
190
|
+
}}
|
|
191
|
+
title=${i18n("Show artifacts")}
|
|
192
|
+
>
|
|
193
|
+
${Badge(html`
|
|
194
|
+
<span class="inline-flex items-center gap-1">
|
|
195
|
+
<span>${i18n("Artifacts")}</span>
|
|
196
|
+
<span
|
|
197
|
+
class="text-[10px] leading-none bg-primary-foreground/20 text-primary-foreground rounded px-1 font-mono tabular-nums"
|
|
198
|
+
>${this.artifactCount}</span
|
|
199
|
+
>
|
|
200
|
+
</span>
|
|
201
|
+
`)}
|
|
202
|
+
</button>
|
|
203
|
+
`
|
|
204
|
+
: ""
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
<div
|
|
208
|
+
class="h-full ${isMobile ? "absolute inset-0 pointer-events-none" : ""}"
|
|
209
|
+
style="${
|
|
210
|
+
!isMobile ? (!this.hasArtifacts || !this.showArtifactsPanel ? "display: none;" : "width: 50%;") : ""
|
|
211
|
+
}"
|
|
212
|
+
>
|
|
213
|
+
${this.artifactsPanel}
|
|
214
|
+
</div>
|
|
215
|
+
</div>
|
|
216
|
+
`;
|
|
217
|
+
}
|
|
218
|
+
}
|
package/src/app.css
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/* Import Claude theme from mini-lit */
|
|
2
|
+
@import "@mariozechner/mini-lit/styles/themes/default.css";
|
|
3
|
+
|
|
4
|
+
/* Tell Tailwind to scan mini-lit components */
|
|
5
|
+
/* biome-ignore lint/suspicious/noUnknownAtRules: Tailwind 4 source directive */
|
|
6
|
+
@source "../../../node_modules/@mariozechner/mini-lit/dist";
|
|
7
|
+
|
|
8
|
+
/* Import Tailwind */
|
|
9
|
+
/* biome-ignore lint/correctness/noInvalidPositionAtImportRule: fuck you */
|
|
10
|
+
@import "tailwindcss";
|
|
11
|
+
|
|
12
|
+
body {
|
|
13
|
+
font-size: 16px;
|
|
14
|
+
-webkit-font-smoothing: antialiased;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
* {
|
|
18
|
+
scrollbar-width: thin;
|
|
19
|
+
scrollbar-color: var(--color-border) rgba(0, 0, 0, 0);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
*::-webkit-scrollbar {
|
|
23
|
+
width: 8px;
|
|
24
|
+
height: 8px;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
*::-webkit-scrollbar-track {
|
|
28
|
+
background: transparent;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
*::-webkit-scrollbar-thumb {
|
|
32
|
+
background-color: var(--color-border);
|
|
33
|
+
border-radius: 4px;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
*::-webkit-scrollbar-thumb:hover {
|
|
37
|
+
background-color: rgba(0, 0, 0, 0);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* Fix cursor for dialog close buttons */
|
|
41
|
+
.fixed.inset-0 button[aria-label*="Close"],
|
|
42
|
+
.fixed.inset-0 button[type="button"] {
|
|
43
|
+
cursor: pointer;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Shimmer animation for thinking text */
|
|
47
|
+
@keyframes shimmer {
|
|
48
|
+
0% {
|
|
49
|
+
background-position: -200% 0;
|
|
50
|
+
}
|
|
51
|
+
100% {
|
|
52
|
+
background-position: 200% 0;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.animate-shimmer {
|
|
57
|
+
animation: shimmer 2s ease-in-out infinite;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/* User message with fancy pill styling */
|
|
61
|
+
.user-message-container {
|
|
62
|
+
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
63
|
+
position: relative;
|
|
64
|
+
background: linear-gradient(135deg, rgba(217, 79, 0, 0.12), rgba(255, 107, 0, 0.12), rgba(212, 165, 0, 0.12));
|
|
65
|
+
border: 1px solid rgba(255, 107, 0, 0.25);
|
|
66
|
+
backdrop-filter: blur(10px);
|
|
67
|
+
max-width: 100%;
|
|
68
|
+
}
|