Add copy to clipboard button in editor

Claude-Session: https://claude.ai/code/session_01PoLmSR1pFVyHf8i5b1rNWk
This commit is contained in:
2026-07-21 11:29:24 -04:00
parent 62f2f8483f
commit d7b113c59a
8 changed files with 343 additions and 7 deletions
+3
View File
@@ -168,6 +168,9 @@ export const exportTarget = (
destination: string,
) => invoke<string>("export_target", { path, format, destination });
export const renderTargetPng = (path: string) =>
invoke<number[]>("render_target_png", { path });
export interface Asset {
name: string;
kind: "font" | "image" | "file";
+43
View File
@@ -2,6 +2,7 @@
import Icon from "@iconify/svelte";
import { onMount } from "svelte";
import { save } from "@tauri-apps/plugin-dialog";
import { writeImage, writeText } from "@tauri-apps/plugin-clipboard-manager";
import { revealItemInDir } from "@tauri-apps/plugin-opener";
import { getCurrentWebview } from "@tauri-apps/api/webview";
import { listen } from "@tauri-apps/api/event";
@@ -370,6 +371,27 @@
}
}
async function copyAs(format: string) {
if (!app.target) return;
try {
if (format === "png") {
const bytes = await api.renderTargetPng(app.target.path);
await writeImage(new Uint8Array(bytes));
} else if (format === "svg") {
const svg = app.compiled?.pages[0];
if (!svg) {
setStatus("Nothing to copy yet");
return;
}
await writeText(svg);
}
setStatus(`Copied ${format.toUpperCase()} to clipboard`);
} catch (error) {
setError(error);
}
}
const resolveDocumentConflicts = (resolutions: api.Resolution[]) =>
guard(async () => {
for (const resolution of resolutions) {
@@ -595,6 +617,27 @@
</div>
</div>
<div class="group relative">
<button
class="flex items-center gap-1.5 rounded-md px-2.5 py-1.5 text-xs text-[var(--color-ink-muted)] transition hover:bg-[var(--color-surface-muted)] hover:text-[var(--color-ink)]"
>
<Icon icon="ph:copy" />
Copy
</button>
<div
class="invisible absolute right-0 top-full z-20 flex w-32 flex-col rounded-md border border-[var(--color-line)] bg-[var(--color-surface)] py-1 text-xs shadow-lg group-hover:visible"
>
{#each ["png", "svg"] as format}
<button
class="px-3 py-1.5 text-left uppercase hover:bg-[var(--color-surface-sunken)]"
onclick={() => copyAs(format)}
>
{format}
</button>
{/each}
</div>
</div>
{#if app.target?.cloud_project_id || app.documentLink}
<button
class="flex items-center gap-1.5 rounded-md bg-[var(--color-accent)] px-2.5 py-1.5 text-xs font-medium text-white transition hover:opacity-90 disabled:opacity-50"