Compare commits
2
Commits
main
..
9369db6e97
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9369db6e97
|
||
|
|
5a4be0ae84
|
No files matched your search
@@ -15,7 +15,6 @@
|
|||||||
"@tauri-apps/plugin-dialog": "~2",
|
"@tauri-apps/plugin-dialog": "~2",
|
||||||
"@tauri-apps/plugin-opener": "~2",
|
"@tauri-apps/plugin-opener": "~2",
|
||||||
"@tauri-apps/plugin-shell": "~2",
|
"@tauri-apps/plugin-shell": "~2",
|
||||||
"@tauri-apps/plugin-window-state": "~2",
|
|
||||||
"pretty-bytes": "^7.1.0",
|
"pretty-bytes": "^7.1.0",
|
||||||
"react": "19.2.5",
|
"react": "19.2.5",
|
||||||
"react-dom": "19.2.5",
|
"react-dom": "19.2.5",
|
||||||
@@ -159,8 +158,6 @@
|
|||||||
|
|
||||||
"@tauri-apps/plugin-shell": ["@tauri-apps/plugin-shell@2.3.5", "", { "dependencies": { "@tauri-apps/api": "^2.10.1" } }, "sha512-jewtULhiQ7lI7+owCKAjc8tYLJr92U16bPOeAa472LHJdgaibLP83NcfAF2e+wkEcA53FxKQAZ7byDzs2eeizg=="],
|
"@tauri-apps/plugin-shell": ["@tauri-apps/plugin-shell@2.3.5", "", { "dependencies": { "@tauri-apps/api": "^2.10.1" } }, "sha512-jewtULhiQ7lI7+owCKAjc8tYLJr92U16bPOeAa472LHJdgaibLP83NcfAF2e+wkEcA53FxKQAZ7byDzs2eeizg=="],
|
||||||
|
|
||||||
"@tauri-apps/plugin-window-state": ["@tauri-apps/plugin-window-state@2.4.1", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-OuvdrzyY8Q5Dbzpj+GcrnV1iCeoZbcFdzMjanZMMcAEUNy/6PH5pxZPXpaZLOR7whlzXiuzx0L9EKZbH7zpdRw=="],
|
|
||||||
|
|
||||||
"@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
|
"@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
|
||||||
|
|
||||||
"@types/react": ["@types/react@19.2.14", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w=="],
|
"@types/react": ["@types/react@19.2.14", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w=="],
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
"@tauri-apps/plugin-dialog": "~2",
|
"@tauri-apps/plugin-dialog": "~2",
|
||||||
"@tauri-apps/plugin-opener": "~2",
|
"@tauri-apps/plugin-opener": "~2",
|
||||||
"@tauri-apps/plugin-shell": "~2",
|
"@tauri-apps/plugin-shell": "~2",
|
||||||
"@tauri-apps/plugin-window-state": "~2",
|
|
||||||
"pretty-bytes": "^7.1.0",
|
"pretty-bytes": "^7.1.0",
|
||||||
"react": "19.2.5",
|
"react": "19.2.5",
|
||||||
"react-dom": "19.2.5",
|
"react-dom": "19.2.5",
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ walkdir = "2.5.0"
|
|||||||
tauri-plugin-shell = "2"
|
tauri-plugin-shell = "2"
|
||||||
tauri-plugin-dialog = "2"
|
tauri-plugin-dialog = "2"
|
||||||
tauri-plugin-opener = "2"
|
tauri-plugin-opener = "2"
|
||||||
tauri-plugin-prevent-default = "4.0.4"
|
|
||||||
|
|
||||||
[target.'cfg(any(target_os = "windows", target_os = "macos"))'.dependencies]
|
[target.'cfg(any(target_os = "windows", target_os = "macos"))'.dependencies]
|
||||||
window-vibrancy = "0.7.1"
|
window-vibrancy = "0.7.1"
|
||||||
@@ -28,10 +27,6 @@ window-vibrancy = "0.7.1"
|
|||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
windows-version = "0.1.7"
|
windows-version = "0.1.7"
|
||||||
|
|
||||||
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
|
||||||
tauri-plugin-single-instance = "2"
|
|
||||||
tauri-plugin-window-state = "2"
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
lto = "thin"
|
lto = "thin"
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -2,19 +2,13 @@
|
|||||||
"$schema": "../gen/schemas/desktop-schema.json",
|
"$schema": "../gen/schemas/desktop-schema.json",
|
||||||
"identifier": "default",
|
"identifier": "default",
|
||||||
"description": "Capability for the main window",
|
"description": "Capability for the main window",
|
||||||
"windows": ["main"],
|
"windows": [
|
||||||
|
"main"
|
||||||
|
],
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"core:default",
|
"core:default",
|
||||||
"shell:default",
|
"shell:default",
|
||||||
"dialog:default",
|
"dialog:default",
|
||||||
"opener:default",
|
"opener:default"
|
||||||
{
|
|
||||||
"identifier": "opener:allow-open-path",
|
|
||||||
"allow": [
|
|
||||||
{
|
|
||||||
"path": "**"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"identifier": "desktop-capability",
|
|
||||||
"platforms": [
|
|
||||||
"macOS",
|
|
||||||
"windows",
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"windows": [
|
|
||||||
"main"
|
|
||||||
],
|
|
||||||
"permissions": [
|
|
||||||
"window-state:default"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
+36
-61
@@ -1,17 +1,13 @@
|
|||||||
use std::{collections::HashMap, fs, path::PathBuf, sync::Mutex};
|
use std::{fs, path::PathBuf};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sysinfo::Disks;
|
use sysinfo::Disks;
|
||||||
use tauri::{Manager, State, WebviewUrl, WebviewWindowBuilder};
|
use tauri::{Emitter, WebviewUrl, WebviewWindowBuilder};
|
||||||
|
|
||||||
use tauri_plugin_shell::ShellExt;
|
use tauri_plugin_shell::ShellExt;
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
use window_vibrancy::{NSVisualEffectMaterial, apply_vibrancy};
|
use window_vibrancy::{NSVisualEffectMaterial, apply_vibrancy};
|
||||||
|
|
||||||
struct AppState {
|
|
||||||
files: Mutex<HashMap<String, Vec<FileInfo>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct DiskInfo {
|
struct DiskInfo {
|
||||||
name: String,
|
name: String,
|
||||||
@@ -29,6 +25,13 @@ pub struct FileInfo {
|
|||||||
pub is_dir: bool,
|
pub is_dir: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct DirScanResult {
|
||||||
|
pub items: Vec<FileInfo>,
|
||||||
|
pub total_size: u64,
|
||||||
|
pub error: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
fn list_disks() -> Vec<DiskInfo> {
|
fn list_disks() -> Vec<DiskInfo> {
|
||||||
Disks::new_with_refreshed_list()
|
Disks::new_with_refreshed_list()
|
||||||
@@ -50,7 +53,6 @@ fn list_disks() -> Vec<DiskInfo> {
|
|||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
async fn get_file_info_from_dirs(
|
async fn get_file_info_from_dirs(
|
||||||
app: tauri::AppHandle,
|
app: tauri::AppHandle,
|
||||||
state: State<'_, AppState>,
|
|
||||||
path: String,
|
path: String,
|
||||||
min_ratio: String,
|
min_ratio: String,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
@@ -76,18 +78,20 @@ async fn get_file_info_from_dirs(
|
|||||||
let json: serde_json::Value =
|
let json: serde_json::Value =
|
||||||
serde_json::from_slice(&output.stdout).map_err(|e| e.to_string())?;
|
serde_json::from_slice(&output.stdout).map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
let mut local_map: HashMap<String, Vec<FileInfo>> = HashMap::new();
|
|
||||||
|
|
||||||
if let Some(tree) = json.get("tree") {
|
if let Some(tree) = json.get("tree") {
|
||||||
stream(tree, "", &mut local_map);
|
let mut batch = Vec::new();
|
||||||
|
stream(tree, "", &mut batch, &app);
|
||||||
}
|
}
|
||||||
|
|
||||||
*state.files.lock().unwrap() = local_map;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stream(node: &serde_json::Value, parent: &str, map: &mut HashMap<String, Vec<FileInfo>>) {
|
fn stream(
|
||||||
|
node: &serde_json::Value,
|
||||||
|
parent: &str,
|
||||||
|
batch: &mut Vec<FileInfo>,
|
||||||
|
app: &tauri::AppHandle,
|
||||||
|
) {
|
||||||
let name = match node.get("name").and_then(|v| v.as_str()) {
|
let name = match node.get("name").and_then(|v| v.as_str()) {
|
||||||
Some(n) => n,
|
Some(n) => n,
|
||||||
None => return,
|
None => return,
|
||||||
@@ -102,86 +106,58 @@ fn stream(node: &serde_json::Value, parent: &str, map: &mut HashMap<String, Vec<
|
|||||||
format!("{}/{}", parent, name)
|
format!("{}/{}", parent, name)
|
||||||
};
|
};
|
||||||
|
|
||||||
let is_dir = children.map_or(false, |c| !c.is_empty());
|
let is_dir = children.as_ref().map(|c| !c.is_empty()).unwrap_or(false);
|
||||||
|
|
||||||
map.entry(parent.to_string()).or_default().push(FileInfo {
|
batch.push(FileInfo {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
path: path.clone(),
|
path: path.clone(),
|
||||||
size,
|
size,
|
||||||
is_dir,
|
is_dir,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if batch.len() >= 200 {
|
||||||
|
let _ = app.emit("scan-batch", batch.clone());
|
||||||
|
batch.clear();
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(children) = children {
|
if let Some(children) = children {
|
||||||
for c in children {
|
for c in children {
|
||||||
stream(c, &path, map);
|
stream(c, &path, batch, app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if parent.is_empty() && !batch.is_empty() {
|
||||||
|
let _ = app.emit("scan-batch", batch.clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
fn get_files_in_dir(path: String, state: State<'_, AppState>) -> Vec<FileInfo> {
|
fn remove_item(path: String) -> Result<(), String> {
|
||||||
state
|
let path = PathBuf::from(path);
|
||||||
.files
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.get(&path)
|
|
||||||
.cloned()
|
|
||||||
.unwrap_or_default()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tauri::command]
|
if !path.exists() {
|
||||||
fn remove_item(path: String, state: State<'_, AppState>) -> Result<(), String> {
|
|
||||||
let path_buf = PathBuf::from(&path);
|
|
||||||
|
|
||||||
if !path_buf.exists() {
|
|
||||||
return Err("path does not exist".to_string());
|
return Err("path does not exist".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
if path_buf.is_dir() {
|
if path.is_dir() {
|
||||||
fs::remove_dir_all(&path_buf).map_err(|e| e.to_string())?;
|
fs::remove_dir_all(&path).map_err(|e| e.to_string())?;
|
||||||
} else {
|
} else {
|
||||||
fs::remove_file(&path_buf).map_err(|e| e.to_string())?;
|
fs::remove_file(&path).map_err(|e| e.to_string())?;
|
||||||
}
|
|
||||||
|
|
||||||
let parent = path_buf
|
|
||||||
.parent()
|
|
||||||
.map(|p| p.to_string_lossy().to_string())
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
if let Some(files) = state.files.lock().unwrap().get_mut(&parent) {
|
|
||||||
files.retain(|f| f.path != path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
|
||||||
fn reset_scan(state: State<'_, AppState>) {
|
|
||||||
state.files.lock().unwrap().clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
.plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| {
|
|
||||||
if let Some(window) = app.get_webview_window("main") {
|
|
||||||
let _ = window.set_focus();
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
.plugin(tauri_plugin_window_state::Builder::new().build())
|
|
||||||
.plugin(tauri_plugin_prevent_default::init())
|
|
||||||
.plugin(tauri_plugin_opener::init())
|
.plugin(tauri_plugin_opener::init())
|
||||||
.plugin(tauri_plugin_dialog::init())
|
.plugin(tauri_plugin_dialog::init())
|
||||||
.plugin(tauri_plugin_shell::init())
|
.plugin(tauri_plugin_shell::init())
|
||||||
.manage(AppState {
|
|
||||||
files: Mutex::new(HashMap::new()),
|
|
||||||
})
|
|
||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
list_disks,
|
list_disks,
|
||||||
get_file_info_from_dirs,
|
get_file_info_from_dirs,
|
||||||
get_files_in_dir,
|
remove_item
|
||||||
remove_item,
|
|
||||||
reset_scan
|
|
||||||
])
|
])
|
||||||
.setup(|app| {
|
.setup(|app| {
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
@@ -215,7 +191,6 @@ pub fn run() {
|
|||||||
)
|
)
|
||||||
.title("DiskSense")
|
.title("DiskSense")
|
||||||
.inner_size(800.0, 600.0)
|
.inner_size(800.0, 600.0)
|
||||||
.min_inner_size(600.0, 400.0)
|
|
||||||
.transparent(transparency)
|
.transparent(transparency)
|
||||||
.visible(false)
|
.visible(false)
|
||||||
.build()?;
|
.build()?;
|
||||||
|
|||||||
+26
-46
@@ -12,7 +12,8 @@ import {
|
|||||||
import { v5 as uuidv5 } from 'uuid'
|
import { v5 as uuidv5 } from 'uuid'
|
||||||
import prettyBytes from 'pretty-bytes'
|
import prettyBytes from 'pretty-bytes'
|
||||||
import { ask, message, open } from '@tauri-apps/plugin-dialog'
|
import { ask, message, open } from '@tauri-apps/plugin-dialog'
|
||||||
import { openPath, revealItemInDir } from '@tauri-apps/plugin-opener'
|
import { listen } from '@tauri-apps/api/event'
|
||||||
|
import { revealItemInDir } from '@tauri-apps/plugin-opener'
|
||||||
|
|
||||||
interface Disk {
|
interface Disk {
|
||||||
name: string
|
name: string
|
||||||
@@ -43,23 +44,16 @@ export default function App () {
|
|||||||
})()
|
})()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
;(async () => {
|
|
||||||
if (currentPath && !scanning) {
|
|
||||||
const result = await invoke<FileInfo[]>('get_files_in_dir', {
|
|
||||||
path: currentPath
|
|
||||||
})
|
|
||||||
setFiles(result)
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
}, [currentPath, scanning])
|
|
||||||
|
|
||||||
const handleScan = async (path: string) => {
|
const handleScan = async (path: string) => {
|
||||||
setRootPath(path)
|
setRootPath(path)
|
||||||
setCurrentPath(path)
|
setCurrentPath(path)
|
||||||
setFiles([])
|
setFiles([])
|
||||||
setScanning(true)
|
setScanning(true)
|
||||||
|
|
||||||
|
const unlisten = await listen<FileInfo[]>('scan-batch', e => {
|
||||||
|
setFiles(prev => [...prev, ...e.payload])
|
||||||
|
})
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await invoke('get_file_info_from_dirs', {
|
await invoke('get_file_info_from_dirs', {
|
||||||
path,
|
path,
|
||||||
@@ -71,6 +65,7 @@ export default function App () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setScanning(false)
|
setScanning(false)
|
||||||
|
unlisten()
|
||||||
}
|
}
|
||||||
|
|
||||||
const breadcrumbs = useMemo(() => {
|
const breadcrumbs = useMemo(() => {
|
||||||
@@ -83,13 +78,13 @@ export default function App () {
|
|||||||
]
|
]
|
||||||
}, [rootPath, currentPath])
|
}, [rootPath, currentPath])
|
||||||
|
|
||||||
const goBackToDisks = async () => {
|
const visibleFiles = useMemo(() => {
|
||||||
setScanning(false)
|
if (!rootPath) return []
|
||||||
setRootPath(null)
|
return files.filter(f => {
|
||||||
setCurrentPath('')
|
const parent = f.path.split('/').slice(0, -1).join('/')
|
||||||
setFiles([])
|
return parent === currentPath
|
||||||
await invoke('reset_scan')
|
})
|
||||||
}
|
}, [files, currentPath, rootPath])
|
||||||
|
|
||||||
return !rootPath ? (
|
return !rootPath ? (
|
||||||
<>
|
<>
|
||||||
@@ -109,10 +104,9 @@ export default function App () {
|
|||||||
className='icon-large -ml-2'
|
className='icon-large -ml-2'
|
||||||
/>
|
/>
|
||||||
<div className='flex flex-col -ml-2 w-full'>
|
<div className='flex flex-col -ml-2 w-full'>
|
||||||
<p hidden={d.name.length == 0}>
|
<p>
|
||||||
{d.name} <span className='text-sm'>({d.mount_point})</span>
|
{d.name} <span className='text-sm'>({d.mount_point})</span>
|
||||||
</p>
|
</p>
|
||||||
<p hidden={d.name.length != 0}>{d.mount_point}</p>
|
|
||||||
<p>{prettyBytes(d.total_space)} total</p>
|
<p>{prettyBytes(d.total_space)} total</p>
|
||||||
<div className='w-full h-2 bg-(--col6) rounded overflow-hidden my-1'>
|
<div className='w-full h-2 bg-(--col6) rounded overflow-hidden my-1'>
|
||||||
<div
|
<div
|
||||||
@@ -160,64 +154,48 @@ export default function App () {
|
|||||||
</p>
|
</p>
|
||||||
) : (
|
) : (
|
||||||
<div className='p-3'>
|
<div className='p-3'>
|
||||||
<div className='flex flex-wrap gap-1 mb-3 relative'>
|
<div className='flex flex-wrap gap-1 mb-3'>
|
||||||
<div className='flex flex-nowrap gap-1 overflow-x-auto mr-14'>
|
|
||||||
{breadcrumbs.map((p, i) => (
|
{breadcrumbs.map((p, i) => (
|
||||||
<button
|
<button
|
||||||
key={p + i}
|
key={p + i}
|
||||||
className='cursor-pointer bg-(--col2)/50 hover:bg-(--col4)/50 border border-(--col4)/50 hover:border-(--col6)/50 px-2 py-1 rounded-lg transition-colors text-white'
|
className='cursor-pointer bg-(--col2)/50 hover:bg-(--col4)/50 border border-(--col4)/50 hover:border-(--col6)/50 px-2 py-1 rounded-lg transition-colors text-white/60 hover:text-white/75'
|
||||||
onClick={() => setCurrentPath(p)}
|
onClick={() => setCurrentPath(p)}
|
||||||
>
|
>
|
||||||
{i == 0 ? p : p.split('/').pop()}
|
{i == 0 ? p : p.split('/').pop()}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<button
|
|
||||||
className='cursor-pointer bg-(--col2)/50 hover:bg-(--col4)/50 border border-(--col4)/50 hover:border-(--col6)/50 px-2 py-1 rounded-lg transition-colors text-white absolute right-0'
|
|
||||||
onClick={() => goBackToDisks()}
|
|
||||||
>
|
|
||||||
Back
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className='flex flex-col gap-1'>
|
<div className='flex flex-col gap-1'>
|
||||||
{files.map(f => (
|
{visibleFiles.map(f => (
|
||||||
<div
|
<div
|
||||||
key={f.path}
|
key={f.path}
|
||||||
className='flex justify-between px-2 py-1 cursor-pointer bg-(--col2)/50 hover:bg-(--col4)/50 border border-(--col4)/50 hover:border-(--col6)/50 transition-colors rounded-lg'
|
className='flex justify-between px-2 py-1 cursor-pointer bg-(--col2)/50 hover:bg-(--col4)/50 border border-(--col4)/50 hover:border-(--col6)/50 transition-colors rounded-lg'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (f.is_dir) setCurrentPath(f.path)
|
if (f.is_dir) setCurrentPath(f.path)
|
||||||
else openPath(f.path)
|
|
||||||
}}
|
}}
|
||||||
title={f.is_dir ? undefined : 'Click to open the file'}
|
|
||||||
>
|
>
|
||||||
<p>
|
<p>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={f.is_dir ? faFolder : faFile}
|
icon={f.is_dir ? faFolder : faFile}
|
||||||
className='text-white transition-all hover:scale-110'
|
className='text-white/60 hover:text-white/75 transition-all hover:scale-110'
|
||||||
/>{' '}
|
/>{' '}
|
||||||
{f.name}
|
{f.name}
|
||||||
</p>
|
</p>
|
||||||
<div className='flex flex-row gap-2 items-center'>
|
<div className='flex flex-row gap-2 items-center'>
|
||||||
<div
|
<div className='w-4 h-6 flex justify-center items-center'>
|
||||||
className='w-4 h-6 flex justify-center items-center'
|
|
||||||
title={'Click to show the ' + f.is_dir ? 'folder' : 'file'}
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faFolderOpen}
|
icon={faFolderOpen}
|
||||||
className='text-white transition-all hover:scale-110'
|
className='text-white/60 hover:text-white/75 transition-all hover:scale-110'
|
||||||
onClick={async e => {
|
onClick={async e => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
revealItemInDir(f.path)
|
revealItemInDir(f.path)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div className='w-4 h-6 flex justify-center items-center'>
|
||||||
className='w-4 h-6 flex justify-center items-center'
|
|
||||||
title={'Click to delete the ' + f.is_dir ? 'folder' : 'file'}
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faTrashCan}
|
icon={faTrashCan}
|
||||||
className='text-red-500 transition-all hover:scale-110'
|
className='text-red-500/60 hover:text-red-500/75 transition-all hover:scale-110'
|
||||||
onClick={async e => {
|
onClick={async e => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
|
||||||
@@ -237,7 +215,9 @@ export default function App () {
|
|||||||
if (!response) return
|
if (!response) return
|
||||||
|
|
||||||
await invoke('remove_item', { path: f.path })
|
await invoke('remove_item', { path: f.path })
|
||||||
setFiles(prev => prev.filter(x => x.path !== f.path))
|
setFiles(prev =>
|
||||||
|
prev.filter(x => !x.path.startsWith(f.path))
|
||||||
|
)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in new issue
Block a user