Feature: Pin Screenshot (#22)

* feat: add pin screenshot builtin command

* feat: pin screenshot command nows zoom and scroll
This commit is contained in:
Huakun Shen 2024-11-10 09:12:33 -05:00 committed by GitHub
parent f29fe00dcf
commit 0600eca59a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 117 additions and 0 deletions

View File

@ -32,6 +32,7 @@
"svelte-radix": "^2.0.1", "svelte-radix": "^2.0.1",
"svelte-sonner": "^0.3.28", "svelte-sonner": "^0.3.28",
"sveltekit-superforms": "^2.20.0", "sveltekit-superforms": "^2.20.0",
"tauri-plugin-clipboard-api": "^2.1.11",
"uuid": "^11.0.2" "uuid": "^11.0.2"
}, },
"devDependencies": { "devDependencies": {

View File

@ -23,6 +23,7 @@
"core:path:default", "core:path:default",
"core:event:default", "core:event:default",
"core:window:default", "core:window:default",
"core:window:allow-set-size",
"core:window:allow-start-dragging", "core:window:allow-start-dragging",
"core:window:allow-set-focus", "core:window:allow-set-focus",
"core:window:allow-toggle-maximize", "core:window:allow-toggle-maximize",

View File

@ -6,6 +6,7 @@ import { WebviewWindow } from "@tauri-apps/api/webviewWindow"
import { exit } from "@tauri-apps/plugin-process" import { exit } from "@tauri-apps/plugin-process"
import { goto } from "$app/navigation" import { goto } from "$app/navigation"
import { toast } from "svelte-sonner" import { toast } from "svelte-sonner"
import * as clipboard from "tauri-plugin-clipboard-api"
import { v4 as uuidv4 } from "uuid" import { v4 as uuidv4 } from "uuid"
export const builtinCmds: BuiltinCmd[] = [ export const builtinCmds: BuiltinCmd[] = [
@ -202,6 +203,29 @@ export const builtinCmds: BuiltinCmd[] = [
appState.clearSearchTerm() appState.clearSearchTerm()
} }
}, },
{
name: "Pin Current Screenshot",
iconifyIcon: "material-symbols:screenshot-monitor-outline",
description: "Pin the current screenshot",
function: async () => {
appState.clearSearchTerm()
if (!(await clipboard.hasImage())) {
toast.error("No screenshot in clipboard")
return
}
const window = new WebviewWindow(`main:pinned-screenshot-${uuidv4()}`, {
url: "/extension/pin-screenshot",
title: "Pinned Screenshot",
hiddenTitle: true,
titleBarStyle: "transparent",
decorations: false,
visible: false
})
setTimeout(() => {
window.show()
}, 2_000)
}
},
{ {
name: "Toggle Hide On Blur", name: "Toggle Hide On Blur",
iconifyIcon: "ri:toggle-line", iconifyIcon: "ri:toggle-line",

View File

@ -0,0 +1,88 @@
<script lang="ts">
import { Button } from "@kksh/svelte5"
import { Layouts } from "@kksh/ui"
import { LogicalSize } from "@tauri-apps/api/dpi"
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow"
import { CircleX } from "lucide-svelte"
import { onMount } from "svelte"
import * as clipboard from "tauri-plugin-clipboard-api"
let image = $state<string | null>(null)
const appWin = getCurrentWebviewWindow()
let originalSize = $state<{ width: number; height: number } | null>(null)
let originalScaleFactor = $state<number | null>(null)
let scale = $state<number>(1)
let currentSize = $derived(
originalSize ? { width: originalSize.width * scale, height: originalSize.height * scale } : null
)
$effect(() => {
if (currentSize) {
appWin.setSize(new LogicalSize(currentSize.width, currentSize.height))
}
})
async function getWindowSize() {
const size = await appWin.outerSize()
const scaleFactor = originalScaleFactor ?? (await appWin.scaleFactor())
const logicalSize = size.toLogical(scaleFactor)
return { logicalSize, scaleFactor }
}
onMount(async () => {
clipboard
.readImageBase64()
.then((b64) => {
image = b64
})
.finally(() => {
appWin.show()
})
const { logicalSize, scaleFactor } = await getWindowSize()
originalSize = { width: logicalSize.width, height: logicalSize.height }
originalScaleFactor = scaleFactor
})
async function onWheel(e: WheelEvent) {
scale += (e.deltaY < 0 ? 1 : -1) * 0.05
}
function onGestureChange(e: any) {
e.preventDefault()
scale = e.scale
}
$effect(() => {
document.addEventListener("wheel", onWheel)
document.addEventListener("gesturechange", onGestureChange)
return () => {
document.removeEventListener("wheel", onWheel)
document.removeEventListener("gesturechange", onGestureChange)
}
})
</script>
<svelte:window
on:keydown={(e) => {
if (e.key === "Escape") {
appWin.close()
}
}}
/>
<Button size="icon" variant="ghost" class="fixed left-2 top-2" onclick={() => appWin.close()}
><CircleX /></Button
>
<main class="z-50 h-screen w-screen overflow-hidden" data-tauri-drag-region>
{#if image}
<img
src={`data:image/png;base64,${image}`}
alt="screenshot"
class="pointer-events-none h-full w-full object-contain"
/>
{:else}
<Layouts.Center>
<p class="text-2xl font-bold">No image found in clipboard</p>
</Layouts.Center>
{/if}
</main>

3
pnpm-lock.yaml generated
View File

@ -168,6 +168,9 @@ importers:
sveltekit-superforms: sveltekit-superforms:
specifier: ^2.20.0 specifier: ^2.20.0
version: 2.20.0(@sveltejs/kit@2.7.4(@sveltejs/vite-plugin-svelte@4.0.0(svelte@5.1.9)(vite@5.4.10(@types/node@22.8.7)(terser@5.36.0)))(svelte@5.1.9)(vite@5.4.10(@types/node@22.8.7)(terser@5.36.0)))(@types/json-schema@7.0.15)(svelte@5.1.9)(typescript@5.6.3) version: 2.20.0(@sveltejs/kit@2.7.4(@sveltejs/vite-plugin-svelte@4.0.0(svelte@5.1.9)(vite@5.4.10(@types/node@22.8.7)(terser@5.36.0)))(svelte@5.1.9)(vite@5.4.10(@types/node@22.8.7)(terser@5.36.0)))(@types/json-schema@7.0.15)(svelte@5.1.9)(typescript@5.6.3)
tauri-plugin-clipboard-api:
specifier: ^2.1.11
version: 2.1.11(typescript@5.6.3)
uuid: uuid:
specifier: ^11.0.2 specifier: ^11.0.2
version: 11.0.2 version: 11.0.2