Compare commits

..
Author SHA1 Message Date
renovate[bot] 9f39935821 fix(deps): update major dependencies 2026-10-09 23:24:27 +00:00
Dayuan Jiang f0f0bc0dc0 feat(ui): tidy the start screen and the chat panel details (#962)
Start screen
- The five examples are one row of picture tiles (title under the picture); the old cards cut their descriptions off with an ellipsis
- "Open .drawio file" leaves the example grid and sits with "Start with a blank canvas" below it, both as outlined buttons
- The "Paper to diagram" example gets a thumbnail of its result (public/paper_demo.svg) like the other four
- The caption says what happens: examples use saved answers, so they appear at once and do not call the AI
- Shorter lede

Chat panel
- The version card's "</>" icon button becomes a "Show XML" text link in the summary line; the summary runs under the title row, so Undo is the card's only button
- Settings uses the gear icon; new diagram uses a file-plus icon instead of the pen that reads as "edit"
- The message box has the same side padding as the message column

Copy
- The model picker says "Server model" instead of "Default" when the server's model is in use
- The theme description no longer claims the diagram always stays on a white sheet (the canvas follows the theme)
- en, zh, ja and zh-Hant dictionaries updated together
2026-10-10 08:22:36 +09:00
Dayuan Jiang d5096b9628 docs: restructure the README around the new promo video (#961)
* docs: restructure the README around the new promo video

The three READMEs now follow the reader's path: what it is (video and
two paragraphs), highlights grouped as draw / edit / use, examples, how
to use it (demo, desktop app, MCP), how to self-host (local run, a
one-click deploy table, models and providers), and support.

Removed the table of contents, the sponsor blocks, the "How It Works"
section, the duplicated demo button and the model recommendation list.
The provider list now matches env.example (24 providers). The video is
the new 30-second promo. Bold markers inside the HTML example table are
now <strong> tags, so they render.

* docs: keep the TrendShift badge under the language switch

* chore: remove the sponsor material for Doubao and Atlas Cloud

The about pages lose the "Sponsored by ByteDance Doubao" card, the
promotional links in the provider list and the thanks paragraph; the
"bring your own key" note stays. The quota toast no longer shows the
Volcengine sign-up paragraph, and its messages in the four languages no
longer mention a sponsor. The provider guides lose the "free tokens"
promo line. The logo and invite images used only by that material are
deleted. Doubao and Atlas Cloud remain supported providers.
2026-10-10 08:22:16 +09:00
20 changed files with 1795 additions and 2044 deletions
+2 -2
View File
@@ -12,13 +12,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
ref: ${{ github.event.pull_request.head.sha }}
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: '24'
+2 -2
View File
@@ -20,10 +20,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: '24'
cache: 'npm'
+6 -6
View File
@@ -26,14 +26,14 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
- name: Log in to GitHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -41,7 +41,7 @@ jobs:
- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v6
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
@@ -54,7 +54,7 @@ jobs:
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
uses: docker/build-push-action@v6
uses: docker/build-push-action@v7
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
@@ -71,7 +71,7 @@ jobs:
# Push to AWS ECR for App Runner auto-deploy
- name: Configure AWS credentials
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
uses: aws-actions/configure-aws-credentials@v5
uses: aws-actions/configure-aws-credentials@v6
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
+7 -7
View File
@@ -26,10 +26,10 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: 24
cache: "npm"
@@ -50,10 +50,10 @@ jobs:
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: 24
cache: "npm"
@@ -69,7 +69,7 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload unsigned artifacts for signing
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v7
id: upload-unsigned
with:
name: windows-unsigned
@@ -77,7 +77,7 @@ jobs:
retention-days: 1
- name: Sign with SignPath
uses: signpath/github-action-submit-signing-request@v2
uses: signpath/github-action-submit-signing-request@v3
with:
api-token: ${{ secrets.SIGNPATH_API_TOKEN }}
organization-id: '880a211d-2cd3-4e7b-8d04-3d1f8eb39df5'
@@ -89,7 +89,7 @@ jobs:
output-artifact-directory: release-signed
- name: Upload signed artifacts to release
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v3
with:
files: release-signed/*.exe
env:
+2 -2
View File
@@ -28,10 +28,10 @@ jobs:
working-directory: packages/mcp-server
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: 24
cache: "npm"
+8 -8
View File
@@ -11,12 +11,12 @@ jobs:
name: Lint & Unit Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: "20"
node-version: "24"
cache: "npm"
- name: Install dependencies
@@ -52,19 +52,19 @@ jobs:
matrix:
shard: [1, 2, 3, 4, 5, 6]
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: "20"
node-version: "24"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Cache Playwright browsers
uses: actions/cache@v5
uses: actions/cache@v6
id: playwright-cache
with:
path: ~/.cache/ms-playwright
@@ -87,7 +87,7 @@ jobs:
CI: true
- name: Upload test results
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v7
if: always()
with:
name: playwright-report-${{ matrix.shard }}
+5 -5
View File
@@ -1,10 +1,10 @@
import {
ChevronDown,
Download,
FilePlus,
MessageSquareDashed,
PanelRightClose,
Settings2,
SquarePen,
Settings,
} from "lucide-react"
import { useRef } from "react"
import { DevXmlSimulator } from "@/components/dev-xml-simulator"
@@ -139,14 +139,14 @@ export function ChatPanel({
disabled={engine.isBusy}
data-testid="new-chat-button"
>
<SquarePen />
<FilePlus />
</IconButton>
<IconButton
label={dict.nav.settings}
onClick={() => openSettings()}
data-testid="settings-button"
>
<Settings2 />
<Settings />
</IconButton>
{!mobile && (
<IconButton
@@ -173,7 +173,7 @@ export function ChatPanel({
/>
)}
<div className="shrink-0 p-2.5 pt-1">
<div className="shrink-0 px-4 pt-1 pb-3">
<Composer
placeholder={
engine.messages.length > 0 &&
+32 -42
View File
@@ -18,14 +18,18 @@ interface Example {
file?: { path: string; name: string; type: string }
}
/** Secondary start buttons: outlined, so they read as clickable */
const startButtonClass =
"inline-flex h-8 items-center gap-1.5 rounded-lg border border-border bg-card px-3 text-[13px] text-foreground transition-colors hover:bg-accent [&_svg]:text-muted-foreground"
async function loadExampleFile(file: NonNullable<Example["file"]>) {
const response = await fetch(getAssetUrl(file.path))
const blob = await response.blob()
return new File([blob], file.name, { type: file.type })
}
/** One start-screen choice: a small picture, a title and one line */
function ExampleCard({
/** One start-screen example: a small picture over its title */
function ExampleTile({
onClick,
title,
description,
@@ -35,6 +39,7 @@ function ExampleCard({
}: {
onClick: () => void
title: string
/** Shown as the tooltip: the title alone names the example */
description: string
picture: React.ReactNode
/** An icon on a tinted tile instead of a diagram on paper */
@@ -45,24 +50,20 @@ function ExampleCard({
<button
type="button"
onClick={onClick}
className="group/example flex min-w-0 items-center gap-2.5 rounded-xl border border-border bg-card p-1.5 pr-2.5 text-left transition-colors hover:border-foreground/25"
title={description}
className="group/example flex min-w-0 flex-col gap-2 rounded-xl border border-border bg-card p-1.5 pb-2.5 text-left transition-colors hover:border-foreground/25"
data-testid={testId}
>
<span
className={cn(
"flex h-12 w-16 shrink-0 items-center justify-center overflow-hidden rounded-lg",
"flex h-16 w-full items-center justify-center overflow-hidden rounded-lg",
plain ? "bg-muted" : "sheet-light bg-white",
)}
>
{picture}
</span>
<span className="min-w-0 flex-1">
<span className="line-clamp-2 text-[13px] leading-snug font-medium text-foreground">
{title}
</span>
<span className="mt-0.5 block truncate text-xs text-muted-foreground">
{description}
</span>
<span className="px-1 text-[13px] leading-snug font-medium text-foreground">
{title}
</span>
</button>
)
@@ -92,6 +93,7 @@ export function LobbyHero({
key: "paper",
title: dict.examples.paperToDiagram,
description: dict.examples.paperDescription,
image: "/paper_demo.svg",
prompt: "Summarize this paper as a diagram",
file: {
path: "/chain-of-thought.txt",
@@ -185,10 +187,12 @@ export function LobbyHero({
placeholder={t.placeholder}
/>
{/* Examples: one row of tiles; the ways to bring your own
diagram follow as a separate group */}
<div
className={cn(
"mt-5 grid gap-2",
compact ? "grid-cols-1" : "grid-cols-3",
compact ? "grid-cols-1" : "grid-cols-5",
)}
>
{examples.map((example) =>
@@ -209,7 +213,7 @@ export function LobbyHero({
</span>
</button>
) : (
<ExampleCard
<ExampleTile
key={example.key}
onClick={() => pickExample(example)}
title={example.title}
@@ -221,7 +225,7 @@ export function LobbyHero({
<img
src={getAssetUrl(example.image)}
alt=""
className="max-h-10 max-w-[56px] object-contain transition-transform duration-300 group-hover/example:scale-[1.06]"
className="max-h-14 max-w-[88%] object-contain transition-transform duration-300 group-hover/example:scale-[1.06]"
/>
) : (
<FileText className="size-5 text-muted-foreground" />
@@ -231,48 +235,34 @@ export function LobbyHero({
/>
),
)}
{!compact && (
<ExampleCard
onClick={onOpenFile}
title={dict.workspace.openFile}
description={t.openFileHint}
picture={
<FileUp className="size-5 text-muted-foreground" />
}
plain
/>
)}
</div>
<p className="mt-3 text-center text-xs text-faint">
<p className="mt-2.5 text-center text-xs text-faint">
{dict.examples.cachedNote}
</p>
<div className="mt-6 flex flex-wrap items-center justify-center gap-x-5 gap-y-2 text-[13px] text-muted-foreground">
{/* Ways to start without an example, as plain buttons */}
<div className="mt-6 flex flex-wrap items-center justify-center gap-2">
{engine.sessions.length > 0 && (
<SessionMenu align="center" onOpenFile={onOpenFile}>
<button
type="button"
className="inline-flex items-center gap-1.5 hover:text-foreground"
>
<button type="button" className={startButtonClass}>
<History className="size-4" />
{t.recent}
</button>
</SessionMenu>
)}
{compact && (
<button
type="button"
onClick={onOpenFile}
className="inline-flex items-center gap-1.5 hover:text-foreground"
>
<FileUp className="size-4" />
{dict.workspace.openFile}
</button>
)}
<button
type="button"
onClick={onOpenFile}
className={startButtonClass}
data-testid="open-file"
>
<FileUp className="size-4" />
{dict.workspace.openFile}
</button>
<button
type="button"
onClick={onDrawYourself}
className="inline-flex items-center gap-1.5 hover:text-foreground"
className={startButtonClass}
data-testid="draw-yourself"
>
<Pencil className="size-4" />
+26 -26
View File
@@ -2,7 +2,6 @@ import {
AlertCircle,
Check,
ChevronDown,
Code2,
Copy,
Library,
PenTool,
@@ -180,17 +179,23 @@ function VersionCard({
</button>
)
// What the AI wrote, on every card (main showed it on every tool call)
const codeButton = (
<button
type="button"
onClick={() => setShowCode((v) => !v)}
aria-label={showCode ? t.hideCode : t.showCode}
title={showCode ? t.hideCode : t.showCode}
className="inline-flex size-7 shrink-0 items-center justify-center rounded-lg text-muted-foreground hover:bg-accent hover:text-foreground"
>
<Code2 className="size-4" />
</button>
// What the AI wrote: a text link in the summary line, so the card's
// only button is the action (undo or restore)
const summaryLine = (
<div className="text-xs text-muted-foreground">
{summary}
{/* The link wraps as one unit with its separator */}
<span className="whitespace-nowrap">
<span aria-hidden> · </span>
<button
type="button"
onClick={() => setShowCode((v) => !v)}
className="underline decoration-foreground/30 underline-offset-2 hover:text-foreground hover:decoration-foreground"
>
{showCode ? t.hideCode : t.showCode}
</button>
</span>
</div>
)
const codePanel = showCode && (
<div className="relative border-t border-border bg-surface-1 px-3 py-2.5">
@@ -231,15 +236,12 @@ function VersionCard({
/>
</button>
{badge}
<div className="min-w-0 flex-1" title={summary}>
<div className="min-w-0 flex-1">
<div className="truncate text-[13px] text-foreground">
{title}
</div>
<div className="truncate text-xs text-muted-foreground">
{summary}
</div>
{summaryLine}
</div>
{codeButton}
{restoreButton}
</div>
{codePanel}
@@ -271,17 +273,12 @@ function VersionCard({
{t.compare}
</span>
</button>
<div className="flex items-center gap-2.5 px-3 py-2.5">
{/* Title row with the action; the summary runs under both */}
<div className="grid grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-x-2.5 px-3 py-2.5">
{badge}
<div className="min-w-0 flex-1" title={summary}>
<div className="truncate text-[13px] font-medium text-foreground">
{title}
</div>
<div className="line-clamp-2 text-xs text-muted-foreground">
{summary}
</div>
<div className="truncate text-[13px] font-medium text-foreground">
{title}
</div>
{codeButton}
{canUndo ? (
<button
type="button"
@@ -300,6 +297,9 @@ function VersionCard({
) : (
restoreButton
)}
<div className="col-span-2 col-start-2 mt-0.5">
{summaryLine}
</div>
</div>
{codePanel}
</div>
+2 -2
View File
@@ -220,14 +220,14 @@ export function ModelSelector({
<span className="min-w-0 truncate text-xs">
{selectedModel
? shortModelName(selectedModel.modelId)
: dict.modelConfig.default}
: dict.modelConfig.serverDefault}
</span>
) : (
// Keep an sr-only label for screen readers when hidden
<span className="sr-only">
{selectedModel
? selectedModel.modelId
: dict.modelConfig.default}
: dict.modelConfig.serverDefault}
</span>
)}
<ChevronDown className="h-3 w-3 flex-shrink-0 text-muted-foreground" />
+2 -2
View File
@@ -1,6 +1,6 @@
"use client"
import { MessageSquare, PanelRightOpen, Settings2, Shapes } from "lucide-react"
import { MessageSquare, PanelRightOpen, Settings, Shapes } from "lucide-react"
import { usePathname, useRouter } from "next/navigation"
import { useEffect, useRef, useState } from "react"
import { CanvasStage } from "@/components/canvas/canvas-stage"
@@ -100,7 +100,7 @@ function StartBar({
onClick={() => openSettings()}
data-testid="settings-button"
>
<Settings2 />
<Settings />
</IconButton>
</div>
)
+4 -4
View File
@@ -72,7 +72,7 @@
"replicateDescription": "Upload and replicate an existing flowchart",
"creativeDrawing": "Creative drawing",
"creativeDescription": "Draw something fun and creative",
"cachedNote": "Examples open instantly and don't use your model.",
"cachedNote": "Examples use saved answers: they appear instantly and don't call the AI.",
"mcpServer": "MCP Server",
"mcpDescription": "Use in Claude Desktop, VS Code & Cursor"
},
@@ -96,7 +96,7 @@
"language": "Language",
"languageDescription": "Choose your interface language.",
"theme": "Theme",
"themeDescription": "Light or dark interface. The diagram always stays on a white sheet, the way it exports.",
"themeDescription": "Light or dark interface. The canvas follows the same theme.",
"diagramStyle": "Diagram style",
"diagramStyleDescription": "How the AI draws new diagrams: Styled uses colors and icons, Minimal keeps shapes plain.",
"sendShortcut": "Send shortcut",
@@ -399,7 +399,7 @@
"searchModels": "Search models...",
"noModelsFound": "No models found.",
"default": "Default",
"serverDefault": "Server Default",
"serverDefault": "Server model",
"serverModels": "Server Models",
"userModels": "User Models",
"configureModels": "Configure Models...",
@@ -694,7 +694,7 @@
},
"lobby": {
"title": "What would you like to draw?",
"lede": "Describe a diagram, or upload a screenshot or PDF. You get a regular draw.io diagram that you can keep editing and export.",
"lede": "Describe a diagram or upload a screenshot or PDF. You get a draw.io diagram you can keep editing and export.",
"placeholder": "For example: a login sequence diagram with SMS codes and retries",
"recent": "Recent diagrams",
"drawYourself": "Start with a blank canvas",
+4 -4
View File
@@ -72,7 +72,7 @@
"replicateDescription": "既存のフローチャートをアップロードして複製",
"creativeDrawing": "自由なイラスト",
"creativeDescription": "楽しくてクリエイティブなものを描く",
"cachedNote": "例はすぐに開き、モデルは使いません。",
"cachedNote": "例は保存済みの回答を使うので、すぐに表示され、AI を呼び出しません。",
"mcpServer": "MCP サーバー",
"mcpDescription": "Claude Desktop、VS Code、Cursor で使用"
},
@@ -96,7 +96,7 @@
"language": "言語",
"languageDescription": "インターフェース言語を選択します。",
"theme": "テーマ",
"themeDescription": "画面をライトにするかダークにするか。図はエクスポートしたときと同じく、常に白い用紙の上に表示されます。",
"themeDescription": "画面をライトにするかダークにするか。キャンバスも同じテーマになります。",
"diagramStyle": "図のスタイル",
"diagramStyleDescription": "AI が新しい図を描くときのスタイル。スタイル付きは色やアイコンを使い、ミニマルは素朴な図形だけにします。",
"sendShortcut": "送信のショートカット",
@@ -354,7 +354,7 @@
"searchModels": "モデルを検索...",
"noModelsFound": "モデルが見つかりません。",
"default": "デフォルト",
"serverDefault": "サーバーデフォルト",
"serverDefault": "サーバーのモデル",
"serverModels": "サーバーモデル",
"userModels": "ユーザーモデル",
"configureModels": "モデルを設定...",
@@ -694,7 +694,7 @@
},
"lobby": {
"title": "どんな図を描きますか?",
"lede": "図の内容を説明するか、スクリーンショットや PDF をアップロードしてください。できあがるのは通常の draw.io の図なので、続けて編集もエクスポートもできます。",
"lede": "図を説明するか、スクリーンショットや PDF をアップロードしてください。できあがるのは編集もエクスポートもできる draw.io の図です。",
"placeholder": "例:SMS 認証とリトライを含むログインのシーケンス図",
"recent": "最近の図",
"drawYourself": "白紙のキャンバスから始める",
+4 -4
View File
@@ -72,7 +72,7 @@
"replicateDescription": "上傳並複製現有流程圖",
"creativeDrawing": "創意繪畫",
"creativeDescription": "繪製有趣且富有創意的內容",
"cachedNote": "範例會立即開啟,不呼叫模型。",
"cachedNote": "範例使用保存好的答案,立即顯示,不呼叫 AI。",
"mcpServer": "MCP 伺服器",
"mcpDescription": "在 Claude Desktop、VS Code 和 Cursor 中使用"
},
@@ -96,7 +96,7 @@
"language": "語言",
"languageDescription": "選擇介面語言。",
"theme": "主題",
"themeDescription": "介面用淺色還是深色。圖紙始終是白底,和匯出後的樣子一致。",
"themeDescription": "介面用淺色還是深色,畫布跟隨同一主題。",
"diagramStyle": "圖形風格",
"diagramStyleDescription": "AI 畫新圖時的風格:精緻會用顏色和圖示,簡約只用樸素的圖形。",
"sendShortcut": "傳送快速鍵",
@@ -399,7 +399,7 @@
"searchModels": "搜尋模型...",
"noModelsFound": "未找到模型。",
"default": "預設",
"serverDefault": "伺服器預設",
"serverDefault": "伺服器模型",
"serverModels": "伺服器模型",
"userModels": "使用者模型",
"configureModels": "配置模型...",
@@ -694,7 +694,7 @@
},
"lobby": {
"title": "說說你要畫什麼",
"lede": "描述一張圖,或上傳截圖、PDF。畫出來的是標準的 draw.io 圖表,可以接著改,也可以匯出。",
"lede": "描述一張圖,或上傳截圖、PDF。得到的是可以繼續編輯和匯出的 draw.io 圖。",
"placeholder": "例如:使用者登入的時序圖,包含簡訊驗證碼和失敗重試",
"recent": "最近的圖紙",
"drawYourself": "從空白畫布開始",
+4 -4
View File
@@ -72,7 +72,7 @@
"replicateDescription": "上传并复制现有流程图",
"creativeDrawing": "创意绘画",
"creativeDescription": "绘制有趣且富有创意的内容",
"cachedNote": "示例会立即打开,不调用模型。",
"cachedNote": "示例使用保存好的答案,立即显示,不调用 AI。",
"mcpServer": "MCP 服务器",
"mcpDescription": "在 Claude Desktop、VS Code 和 Cursor 中使用"
},
@@ -96,7 +96,7 @@
"language": "语言",
"languageDescription": "选择界面语言。",
"theme": "主题",
"themeDescription": "界面用浅色还是深色。图纸始终是白底,和导出后的样子一致。",
"themeDescription": "界面用浅色还是深色,画布跟随同一主题。",
"diagramStyle": "图形风格",
"diagramStyleDescription": "AI 画新图时的风格:精致会用颜色和图标,简约只用朴素的图形。",
"sendShortcut": "发送快捷键",
@@ -399,7 +399,7 @@
"searchModels": "搜索模型...",
"noModelsFound": "未找到模型。",
"default": "默认",
"serverDefault": "服务器默认",
"serverDefault": "服务器模型",
"serverModels": "服务器模型",
"userModels": "用户模型",
"configureModels": "配置模型...",
@@ -694,7 +694,7 @@
},
"lobby": {
"title": "说说你要画什么",
"lede": "描述一张图,或者上传截图、PDF。画出来的是标准的 draw.io 图表,可以接着改,也可以导出。",
"lede": "描述一张图,或上传截图、PDF。得到的是可以继续编辑和导出的 draw.io 图。",
"placeholder": "比如:用户登录的时序图,包含短信验证码和失败重试",
"recent": "最近的图纸",
"drawYourself": "从空白画布开始",
+1136 -1686
View File
File diff suppressed because it is too large Load Diff
+17 -17
View File
@@ -45,11 +45,11 @@
"@aihubmix/ai-sdk-provider": "^2.2.1",
"@aws-sdk/client-dynamodb": "^3.957.0",
"@aws-sdk/credential-providers": "^3.943.0",
"@extractus/article-extractor": "^8.0.18",
"@extractus/article-extractor": "^9.0.0",
"@formatjs/intl-localematcher": "^0.9.0",
"@langfuse/client": "^4.4.9",
"@langfuse/otel": "^4.4.4",
"@langfuse/tracing": "^4.4.9",
"@langfuse/client": "^5.0.0",
"@langfuse/otel": "^5.0.0",
"@langfuse/tracing": "^5.0.0",
"@next/third-parties": "^16.0.6",
"@opennextjs/cloudflare": "^1.17.1",
"@openrouter/ai-sdk-provider": "^2.10.0",
@@ -74,13 +74,13 @@
"cmdk": "^1.1.1",
"idb": "^8.0.3",
"jsonrepair": "^3.13.1",
"lucide-react": "^0.577.0",
"motion": "^12.23.25",
"nanoid": "^5.0.0",
"lucide-react": "^1.0.0",
"motion": "^14.0.0",
"nanoid": "^6.0.0",
"negotiator": "^1.0.0",
"next": "^16.0.7",
"ollama-ai-provider-v2": "^3.6.0",
"pako": "^2.1.0",
"pako": "^3.0.0",
"prism-react-renderer": "^2.4.1",
"react": "^19.1.2",
"react-dom": "^19.1.2",
@@ -119,27 +119,27 @@
"@testing-library/user-event": "^14.6.1",
"@types/negotiator": "^0.6.4",
"@types/node": "^24.0.0",
"@types/pako": "^2.0.3",
"@types/pako": "^3.0.0",
"@types/react": "^19",
"@types/react-dom": "^19",
"@types/turndown": "^5.0.6",
"@vitejs/plugin-react": "^5.1.2",
"@vitest/coverage-v8": "^4.0.16",
"concurrently": "^9.2.1",
"@vitejs/plugin-react": "^6.0.0",
"@vitest/coverage-v8": "^5.0.0",
"concurrently": "^10.0.0",
"cross-env": "^10.1.0",
"electron": "^39.2.7",
"electron-builder": "^26.0.12",
"esbuild": "^0.28.0",
"eslint": "9.39.5",
"eslint": "10.12.0",
"eslint-config-next": "16.1.6",
"husky": "^9.1.7",
"jsdom": "^27.4.0",
"lint-staged": "^16.2.7",
"jsdom": "^30.0.0",
"lint-staged": "^17.0.0",
"shx": "^0.4.0",
"tailwindcss": "^4",
"typescript": "^5",
"typescript": "^7.0.0",
"vite-tsconfig-paths": "^6.0.3",
"vitest": "^4.0.16",
"vitest": "^5.0.0",
"wait-on": "^9.0.3",
"wrangler": "^4.60.0"
},
+527 -217
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -42,16 +42,16 @@
"@modelcontextprotocol/sdk": "^1.31.0",
"linkedom": "^0.18.0",
"open": "^11.0.0",
"pako": "^2.2.0",
"pako": "^3.0.0",
"saxes": "^6.0.0",
"zod": "^4.0.0"
},
"devDependencies": {
"@types/node": "^24.0.0",
"@types/pako": "^2.0.4",
"@types/pako": "^3.0.0",
"tsx": "^4.19.0",
"typescript": "^5",
"vitest": "^4.1.8"
"typescript": "^7.0.0",
"vitest": "^5.0.0"
},
"engines": {
"node": ">=18"
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 67 KiB