Skip to content

Commit 987c3b5

Browse files
committed
feat: add file download and update permission
1 parent c51ae68 commit 987c3b5

File tree

3 files changed

+72
-18
lines changed

3 files changed

+72
-18
lines changed

src-tauri/capabilities/default.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
"identifier": "default",
44
"description": "Capability for the main window",
55
"windows": ["main"],
6-
"permissions": ["core:default", "opener:default", "dialog:allow-open"]
6+
"permissions": ["core:default", "opener:default", "dialog:allow-open", "dialog:allow-save"]
77
}

src-tauri/src/lib.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,11 @@ async fn read_file(path: String) -> Result<String, String> {
9999
std::fs::read_to_string(&path).map_err(|e| format!("Failed to read file '{}': {}", path, e))
100100
}
101101

102+
#[tauri::command]
103+
async fn write_file(path: String, content: String) -> Result<(), String> {
104+
std::fs::write(&path, content).map_err(|e| format!("Failed to write file '{}': {}", path, e))
105+
}
106+
102107
#[cfg_attr(mobile, tauri::mobile_entry_point)]
103108
pub fn run() {
104109
tauri::Builder::default()
@@ -109,7 +114,8 @@ pub fn run() {
109114
format_json_string,
110115
save_app_data,
111116
load_app_data,
112-
read_file
117+
read_file,
118+
write_file
113119
])
114120
.run(tauri::generate_context!())
115121
.expect("error while running tauri application");

src/App.tsx

Lines changed: 64 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import Editor, { OnChange } from '@monaco-editor/react';
22
import { invoke } from '@tauri-apps/api/core';
3-
import { open } from '@tauri-apps/plugin-dialog';
3+
import { open, save } from '@tauri-apps/plugin-dialog';
44
import { openUrl } from '@tauri-apps/plugin-opener';
55
import {
66
Bug,
77
Check,
88
Copy,
9+
Download,
910
Eraser,
1011
FolderOpen,
1112
Github,
@@ -197,6 +198,42 @@ function App() {
197198
}
198199
};
199200

201+
const handleDownload = async () => {
202+
if (!formattedString || isError) {
203+
return;
204+
}
205+
206+
try {
207+
const now = new Date();
208+
const timestamp = now.toISOString().slice(0, 19).replace(/:/g, '-');
209+
const defaultFilename = `formatted-json-${timestamp}.json`;
210+
211+
const filePath = await save({
212+
title: 'Save JSON File',
213+
defaultPath: defaultFilename,
214+
filters: [
215+
{
216+
name: 'JSON Files',
217+
extensions: ['json'],
218+
},
219+
{
220+
name: 'All Files',
221+
extensions: ['*'],
222+
},
223+
],
224+
});
225+
226+
if (filePath) {
227+
await invoke('write_file', {
228+
path: filePath,
229+
content: formattedString,
230+
});
231+
}
232+
} catch (error) {
233+
console.error('Failed to download:', error);
234+
}
235+
};
236+
200237
const updateUndoRedoState = () => {
201238
if (editorRef.current) {
202239
const model = editorRef.current.getModel();
@@ -374,21 +411,32 @@ function App() {
374411
<div
375412
className={`editor-header ${isDarkTheme ? 'dark-theme' : ''}`}
376413
style={{ fontSize: `${fontSize}px` }}>
377-
<div></div>
378-
<button
379-
onClick={handleCopy}
380-
className={`copy-button ${isCopied ? 'copied' : ''} ${
381-
isDarkTheme ? 'dark-theme' : ''
382-
}`}
383-
style={{ fontSize: `${fontSize}px` }}
384-
title={isCopied ? 'Copied!' : 'Copy to Clipboard'}
385-
disabled={formattedString === ''}>
386-
{isCopied ? (
387-
<Check size={Math.max(12, fontSize * 0.8)} />
388-
) : (
389-
<Copy size={Math.max(12, fontSize * 0.8)} />
390-
)}
391-
</button>
414+
<div className="editor-actions-left">
415+
<button
416+
onClick={handleCopy}
417+
className={`copy-button ${isCopied ? 'copied' : ''} ${
418+
isDarkTheme ? 'dark-theme' : ''
419+
}`}
420+
style={{ fontSize: `${fontSize}px` }}
421+
title={isCopied ? 'Copied!' : 'Copy to Clipboard'}
422+
disabled={formattedString === ''}>
423+
{isCopied ? (
424+
<Check size={Math.max(12, fontSize * 0.8)} />
425+
) : (
426+
<Copy size={Math.max(12, fontSize * 0.8)} />
427+
)}
428+
</button>
429+
</div>
430+
<div className="editor-actions-right">
431+
<button
432+
onClick={handleDownload}
433+
className={`action-button ${isDarkTheme ? 'dark-theme' : ''}`}
434+
style={{ fontSize: `${fontSize}px` }}
435+
title="Download JSON"
436+
disabled={formattedString === '' || isError}>
437+
<Download size={Math.max(12, fontSize * 0.8)} />
438+
</button>
439+
</div>
392440
</div>
393441
<div className={`output ${isError ? 'error' : ''}`}>
394442
<Editor

0 commit comments

Comments
 (0)