Tauri native dialog for Save/Open with fs plugin
This commit is contained in:
parent
086fb7d652
commit
8d3d3444ad
6
bun.lock
6
bun.lock
|
|
@ -7,6 +7,8 @@
|
|||
"dependencies": {
|
||||
"@tailwindcss/vite": "^4.2.1",
|
||||
"@tauri-apps/api": "^2",
|
||||
"@tauri-apps/plugin-dialog": "^2.6.0",
|
||||
"@tauri-apps/plugin-fs": "^2.4.5",
|
||||
"@tauri-apps/plugin-opener": "^2",
|
||||
"@vueuse/core": "^14.2.1",
|
||||
"canvaskit-wasm": "^0.40.0",
|
||||
|
|
@ -318,6 +320,10 @@
|
|||
|
||||
"@tauri-apps/cli-win32-x64-msvc": ["@tauri-apps/cli-win32-x64-msvc@2.10.0", "", { "os": "win32", "cpu": "x64" }, "sha512-NTpyQxkpzGmU6ceWBTY2xRIEaS0ZLbVx1HE1zTA3TY/pV3+cPoPPOs+7YScr4IMzXMtOw7tLw5LEXo5oIG3qaQ=="],
|
||||
|
||||
"@tauri-apps/plugin-dialog": ["@tauri-apps/plugin-dialog@2.6.0", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-q4Uq3eY87TdcYzXACiYSPhmpBA76shgmQswGkSVio4C82Sz2W4iehe9TnKYwbq7weHiL88Yw19XZm7v28+Micg=="],
|
||||
|
||||
"@tauri-apps/plugin-fs": ["@tauri-apps/plugin-fs@2.4.5", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-dVxWWGE6VrOxC7/jlhyE+ON/Cc2REJlM35R3PJX3UvFw2XwYhLGQVAIyrehenDdKjotipjYEVc4YjOl3qq90fA=="],
|
||||
|
||||
"@tauri-apps/plugin-opener": ["@tauri-apps/plugin-opener@2.5.3", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-CCcUltXMOfUEArbf3db3kCE7Ggy1ExBEBl51Ko2ODJ6GDYHRp1nSNlQm5uNCFY5k7/ufaK5Ib3Du/Zir19IYQQ=="],
|
||||
|
||||
"@types/culori": ["@types/culori@4.0.1", "", {}, "sha512-43M51r/22CjhbOXyGT361GZ9vncSVQ39u62x5eJdBQFviI8zWp2X5jzqg7k4M6PVgDQAClpy2bUe2dtwEgEDVQ=="],
|
||||
|
|
|
|||
68
desktop/Cargo.lock
generated
68
desktop/Cargo.lock
generated
|
|
@ -698,6 +698,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38"
|
||||
dependencies = [
|
||||
"bitflags 2.11.0",
|
||||
"block2",
|
||||
"libc",
|
||||
"objc2",
|
||||
]
|
||||
|
||||
|
|
@ -2329,6 +2331,8 @@ dependencies = [
|
|||
"serde_json",
|
||||
"tauri",
|
||||
"tauri-build",
|
||||
"tauri-plugin-dialog",
|
||||
"tauri-plugin-fs",
|
||||
"tauri-plugin-opener",
|
||||
]
|
||||
|
||||
|
|
@ -2939,6 +2943,30 @@ dependencies = [
|
|||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rfd"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a15ad77d9e70a92437d8f74c35d99b4e4691128df018833e99f90bcd36152672"
|
||||
dependencies = [
|
||||
"block2",
|
||||
"dispatch2",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"gtk-sys",
|
||||
"js-sys",
|
||||
"log",
|
||||
"objc2",
|
||||
"objc2-app-kit",
|
||||
"objc2-core-foundation",
|
||||
"objc2-foundation",
|
||||
"raw-window-handle",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.1"
|
||||
|
|
@ -3625,6 +3653,46 @@ dependencies = [
|
|||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-dialog"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9204b425d9be8d12aa60c2a83a289cf7d1caae40f57f336ed1155b3a5c0e359b"
|
||||
dependencies = [
|
||||
"log",
|
||||
"raw-window-handle",
|
||||
"rfd",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
"tauri-plugin",
|
||||
"tauri-plugin-fs",
|
||||
"thiserror 2.0.18",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-fs"
|
||||
version = "2.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed390cc669f937afeb8b28032ce837bac8ea023d975a2e207375ec05afaf1804"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"dunce",
|
||||
"glob",
|
||||
"percent-encoding",
|
||||
"schemars 0.8.22",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"tauri",
|
||||
"tauri-plugin",
|
||||
"tauri-utils",
|
||||
"thiserror 2.0.18",
|
||||
"toml 0.9.12+spec-1.1.0",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-opener"
|
||||
version = "2.5.3"
|
||||
|
|
|
|||
|
|
@ -22,4 +22,6 @@ tauri = { version = "2", features = ["devtools"] }
|
|||
tauri-plugin-opener = "2"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
tauri-plugin-dialog = "2.6.0"
|
||||
tauri-plugin-fs = "2.4.5"
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,12 @@
|
|||
"windows": ["main"],
|
||||
"permissions": [
|
||||
"core:default",
|
||||
"opener:default"
|
||||
"opener:default",
|
||||
"dialog:default",
|
||||
"dialog:allow-save",
|
||||
"dialog:allow-open",
|
||||
"fs:default",
|
||||
"fs:allow-read",
|
||||
"fs:allow-write"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ use tauri::{
|
|||
pub fn run() {
|
||||
tauri::Builder::default()
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
.plugin(tauri_plugin_dialog::init())
|
||||
.plugin(tauri_plugin_fs::init())
|
||||
.on_menu_event(|app, event| {
|
||||
#[cfg(debug_assertions)]
|
||||
if event.id().0.as_str() == "dev-tools" {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
"dependencies": {
|
||||
"@tailwindcss/vite": "^4.2.1",
|
||||
"@tauri-apps/api": "^2",
|
||||
"@tauri-apps/plugin-dialog": "^2.6.0",
|
||||
"@tauri-apps/plugin-fs": "^2.4.5",
|
||||
"@tauri-apps/plugin-opener": "^2",
|
||||
"@vueuse/core": "^14.2.1",
|
||||
"canvaskit-wasm": "^0.40.0",
|
||||
|
|
|
|||
|
|
@ -3,6 +3,20 @@ import { onUnmounted } from 'vue'
|
|||
import type { EditorStore } from '../stores/editor'
|
||||
|
||||
export async function openFileDialog(store: EditorStore) {
|
||||
if ('__TAURI_INTERNALS__' in window) {
|
||||
const { open } = await import('@tauri-apps/plugin-dialog')
|
||||
const { readFile } = await import('@tauri-apps/plugin-fs')
|
||||
const path = await open({
|
||||
filters: [{ name: 'Figma file', extensions: ['fig'] }],
|
||||
multiple: false
|
||||
})
|
||||
if (!path) return
|
||||
const bytes = await readFile(path as string)
|
||||
const file = new File([bytes], (path as string).split('/').pop()!)
|
||||
await store.openFigFile(file, undefined, path as string)
|
||||
return
|
||||
}
|
||||
|
||||
if ('showOpenFilePicker' in window) {
|
||||
try {
|
||||
const [handle] = await (window as any).showOpenFilePicker({
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ export function createEditorStore() {
|
|||
const undo = new UndoManager()
|
||||
const pageViewports = new Map<string, PageViewport>()
|
||||
let fileHandle: FileSystemFileHandle | null = null
|
||||
let filePath: string | null = null
|
||||
|
||||
prefetchFigmaSchema()
|
||||
|
||||
|
|
@ -422,7 +423,7 @@ export function createEditorStore() {
|
|||
requestRender()
|
||||
}
|
||||
|
||||
async function openFigFile(file: File, handle?: FileSystemFileHandle) {
|
||||
async function openFigFile(file: File, handle?: FileSystemFileHandle, path?: string) {
|
||||
try {
|
||||
const imported = await readFigFile(file)
|
||||
graph = imported
|
||||
|
|
@ -430,6 +431,7 @@ export function createEditorStore() {
|
|||
undo.clear()
|
||||
pageViewports.clear()
|
||||
fileHandle = handle ?? null
|
||||
filePath = path ?? null
|
||||
state.selectedIds = new Set()
|
||||
const firstPage = graph.getPages()[0]
|
||||
state.currentPageId = firstPage?.id ?? graph.rootId
|
||||
|
|
@ -444,11 +446,8 @@ export function createEditorStore() {
|
|||
}
|
||||
|
||||
async function saveFigFile() {
|
||||
if (fileHandle) {
|
||||
const data = await exportFigFile(graph)
|
||||
const writable = await fileHandle.createWritable()
|
||||
await writable.write(data)
|
||||
await writable.close()
|
||||
if (filePath || fileHandle) {
|
||||
await writeFile(await exportFigFile(graph))
|
||||
} else {
|
||||
await saveFigFileAs()
|
||||
}
|
||||
|
|
@ -457,6 +456,19 @@ export function createEditorStore() {
|
|||
async function saveFigFileAs() {
|
||||
const data = await exportFigFile(graph)
|
||||
|
||||
if ('__TAURI_INTERNALS__' in window) {
|
||||
const { save } = await import('@tauri-apps/plugin-dialog')
|
||||
const path = await save({
|
||||
defaultPath: 'Untitled.fig',
|
||||
filters: [{ name: 'Figma file', extensions: ['fig'] }]
|
||||
})
|
||||
if (!path) return
|
||||
filePath = path
|
||||
fileHandle = null
|
||||
await writeFile(data)
|
||||
return
|
||||
}
|
||||
|
||||
if ('showSaveFilePicker' in window) {
|
||||
try {
|
||||
const handle = await (window as any).showSaveFilePicker({
|
||||
|
|
@ -467,9 +479,8 @@ export function createEditorStore() {
|
|||
}]
|
||||
})
|
||||
fileHandle = handle
|
||||
const writable = await handle.createWritable()
|
||||
await writable.write(data)
|
||||
await writable.close()
|
||||
filePath = null
|
||||
await writeFile(data)
|
||||
return
|
||||
} catch (e) {
|
||||
if ((e as Error).name === 'AbortError') return
|
||||
|
|
@ -485,6 +496,19 @@ export function createEditorStore() {
|
|||
URL.revokeObjectURL(url)
|
||||
}
|
||||
|
||||
async function writeFile(data: Uint8Array) {
|
||||
if (filePath && '__TAURI_INTERNALS__' in window) {
|
||||
const { writeFile: tauriWrite } = await import('@tauri-apps/plugin-fs')
|
||||
await tauriWrite(filePath, data)
|
||||
return
|
||||
}
|
||||
if (fileHandle) {
|
||||
const writable = await fileHandle.createWritable()
|
||||
await writable.write(data)
|
||||
await writable.close()
|
||||
}
|
||||
}
|
||||
|
||||
function runLayoutForNode(id: string) {
|
||||
const node = graph.getNode(id)
|
||||
if (!node) return
|
||||
|
|
|
|||
Loading…
Reference in a new issue