summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src/pages
diff options
context:
space:
mode:
authorshuv <[email protected]>2026-01-04 16:39:15 -0800
committerGitHub <[email protected]>2026-01-04 18:39:15 -0600
commit52ad134d554bef8a4e017f7dc4c5002fcf12a785 (patch)
tree0bf8b971f29d57fd4ff7c4fd04f604adda9d91ea /packages/app/src/pages
parent3e09abbfda931a91e31282cff0f6af64307f8d36 (diff)
downloadopencode-52ad134d554bef8a4e017f7dc4c5002fcf12a785.tar.gz
opencode-52ad134d554bef8a4e017f7dc4c5002fcf12a785.zip
feat(app): add SVG preview support in session viewer (#6868)
Diffstat (limited to 'packages/app/src/pages')
-rw-r--r--packages/app/src/pages/session.tsx52
1 files changed, 50 insertions, 2 deletions
diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx
index 4011ea890..1aeb4757b 100644
--- a/packages/app/src/pages/session.tsx
+++ b/packages/app/src/pages/session.tsx
@@ -24,7 +24,7 @@ import { useSync } from "@/context/sync"
import { useTerminal, type LocalPTY } from "@/context/terminal"
import { useLayout } from "@/context/layout"
import { Terminal } from "@/components/terminal"
-import { checksum } from "@opencode-ai/util/encode"
+import { checksum, base64Decode } from "@opencode-ai/util/encode"
import { useDialog } from "@opencode-ai/ui/context/dialog"
import { DialogSelectFile } from "@/components/dialog-select-file"
import { DialogSelectModel } from "@/components/dialog-select-model"
@@ -1013,7 +1013,29 @@ export default function Page() {
const cacheKey = createMemo(() => checksum(contents()))
const isImage = createMemo(() => {
const c = state()?.content
- return c?.encoding === "base64" && c?.mimeType?.startsWith("image/")
+ return (
+ c?.encoding === "base64" &&
+ c?.mimeType?.startsWith("image/") &&
+ c?.mimeType !== "image/svg+xml"
+ )
+ })
+ const isSvg = createMemo(() => {
+ const c = state()?.content
+ return c?.mimeType === "image/svg+xml"
+ })
+ const svgContent = createMemo(() => {
+ if (!isSvg()) return
+ const c = state()?.content
+ if (!c) return
+ if (c.encoding === "base64") return base64Decode(c.content)
+ return c.content
+ })
+ const svgPreviewUrl = createMemo(() => {
+ if (!isSvg()) return
+ const c = state()?.content
+ if (!c) return
+ if (c.encoding === "base64") return `data:image/svg+xml;base64,${c.content}`
+ return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(c.content)}`
})
const imageDataUrl = createMemo(() => {
if (!isImage()) return
@@ -1144,6 +1166,32 @@ export default function Page() {
<img src={imageDataUrl()} alt={path()} class="max-w-full" />
</div>
</Match>
+ <Match when={state()?.loaded && isSvg()}>
+ <div class="flex flex-col gap-4 px-6 py-4">
+ <Dynamic
+ component={codeComponent}
+ file={{
+ name: path() ?? "",
+ contents: svgContent() ?? "",
+ cacheKey: cacheKey(),
+ }}
+ enableLineSelection
+ selectedLines={selectedLines()}
+ onLineSelected={(range: SelectedLineRange | null) => {
+ const p = path()
+ if (!p) return
+ file.setSelectedLines(p, range)
+ }}
+ overflow="scroll"
+ class="select-text"
+ />
+ <Show when={svgPreviewUrl()}>
+ <div class="flex justify-center pb-40">
+ <img src={svgPreviewUrl()} alt={path()} class="max-w-full max-h-96" />
+ </div>
+ </Show>
+ </div>
+ </Match>
<Match when={state()?.loaded}>
<Dynamic
component={codeComponent}