diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 9f2b2b7..da65ed9 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -707,6 +707,7 @@ dependencies = [ "tauri", "tauri-build", "walkdir", + "window-vibrancy", ] [[package]] @@ -3436,6 +3437,18 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "window-vibrancy" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f762d9cc392fb85e6b1b5eed1ef13d73fed5149a5cbb017a7137497d14ef612" +dependencies = [ + "cocoa", + "objc", + "raw-window-handle", + "windows-sys 0.42.0", +] + [[package]] name = "windows" version = "0.39.0" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index e21b6a1..48466b0 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" tauri-build = { version = "1.3", features = [] } [dependencies] -tauri = { version = "1.3", features = ["shell-open"] } +tauri = { version = "1.3", features = [ "macos-private-api", "shell-open"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" sysinfo = "0.29.2" @@ -22,6 +22,7 @@ fuzzy-matcher = "*" rayon = "1.7.0" dirs = "5.0.1" notify = "6.0.1" +window-vibrancy = "0.3.2" [features] # this feature is used for production builds or when `devPath` points to the filesystem diff --git a/src-tauri/src/filesystem.rs b/src-tauri/src/filesystem.rs index 2ee0aed..0a6da09 100644 --- a/src-tauri/src/filesystem.rs +++ b/src-tauri/src/filesystem.rs @@ -1,20 +1,20 @@ -use crate::{CachedPath, StateSafe}; +use crate::{ CachedPath, StateSafe }; use rayon::prelude::*; -use serde::{Deserialize, Serialize}; +use serde::{ Deserialize, Serialize }; use std::collections::HashMap; use std::fs; -use std::fs::{read_dir, File}; +use std::fs::{ read_dir, File }; use std::io::Write; use std::path::PathBuf; -use std::sync::{Arc, Mutex}; -use sysinfo::{Disk, DiskExt, System, SystemExt}; +use std::sync::{ Arc, Mutex }; +use sysinfo::{ Disk, DiskExt, System, SystemExt }; use tauri::State; use walkdir::WalkDir; const CACHE_FILE_PATH: &str = "./system_cache.json"; const fn bytes_to_gb(bytes: u64) -> u16 { - (bytes / (1e+9 as u64)) as u16 + (bytes / (1e9 as u64)) as u16 } #[derive(Serialize)] @@ -90,11 +90,12 @@ impl Volume { let name = { let volume_name = disk.name().to_str().unwrap(); - match volume_name.is_empty() { - true => "Local Volume", - false => volume_name, - } - .to_string() + ( + match volume_name.is_empty() { + true => "Local Volume", + false => volume_name, + } + ).to_string() }; let mountpoint = disk.mount_point().to_path_buf(); @@ -115,8 +116,7 @@ impl Volume { fn create_cache(&self, state_mux: &StateSafe) { let state = &mut state_mux.lock().unwrap(); - let volume = state - .system_cache + let volume = state.system_cache .entry(self.mountpoint.to_string_lossy().to_string()) .or_insert_with(HashMap::new); @@ -131,21 +131,19 @@ impl Volume { let file_path = entry.path().to_string_lossy().to_string(); let walkdir_filetype = entry.file_type(); - let file_type = if walkdir_filetype.is_dir() { - "directory" - } else { - "file" - } - .to_string(); + let file_type = ( + if walkdir_filetype.is_dir() { + "directory" + } else { + "file" + } + ).to_string(); let cache_guard = &mut system_cache.lock().unwrap(); - cache_guard - .entry(file_name) - .or_insert_with(Vec::new) - .push(CachedPath { - file_path, - file_type, - }); + cache_guard.entry(file_name).or_insert_with(Vec::new).push(CachedPath { + file_path, + file_type, + }); }); } } @@ -162,10 +160,7 @@ pub fn save_system_cache(state_mux: &StateSafe) { let state = &mut state_mux.lock().unwrap(); let serialized_cache = serde_json::to_string(&state.system_cache).unwrap(); - let mut file = fs::OpenOptions::new() - .write(true) - .open(CACHE_FILE_PATH) - .unwrap(); + let mut file = fs::OpenOptions::new().write(true).open(CACHE_FILE_PATH).unwrap(); file.write_all(serialized_cache.as_bytes()).unwrap(); } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index ef21315..94fb0ab 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -1,14 +1,16 @@ // Prevents additional console window on Windows in release, DO NOT REMOVE!! -#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] +#![cfg_attr(all(not(debug_assertions), target_os = "windows"), windows_subsystem = "windows")] mod filesystem; mod search; -use filesystem::{get_volumes, open_directory}; +use filesystem::{ get_volumes, open_directory }; use search::search_directory; -use serde::{Deserialize, Serialize}; +use serde::{ Deserialize, Serialize }; use std::collections::HashMap; -use std::sync::{Arc, Mutex}; +use std::sync::{ Arc, Mutex }; +use tauri::Manager; +use window_vibrancy::{ apply_blur, apply_vibrancy, NSVisualEffectMaterial }; #[derive(Serialize, Deserialize)] pub struct CachedPath { @@ -26,14 +28,25 @@ pub struct AppState { pub type StateSafe = Arc>; fn main() { - tauri::Builder::default() - .invoke_handler(tauri::generate_handler![ - get_volumes, - open_directory, - search_directory - ]) + tauri::Builder + ::default() + .setup(|app| { + let window = app.get_window("main").unwrap(); + + #[cfg(target_os = "macos")] + apply_vibrancy(&window, NSVisualEffectMaterial::HudWindow, None, None).expect( + "Unsupported platform! 'apply_vibrancy' is only supported on macOS" + ); + + #[cfg(target_os = "windows")] + apply_blur(&window, Some((18, 18, 18, 125))).expect( + "Unsupported platform! 'apply_blur' is only supported on Windows" + ); + + Ok(()) + }) + .invoke_handler(tauri::generate_handler![get_volumes, open_directory, search_directory]) .manage(Arc::new(Mutex::new(AppState::default()))) .run(tauri::generate_context!()) .expect("error while running tauri application"); } - diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 12d61ec..413605c 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -39,8 +39,11 @@ "resizable": true, "title": "file-explorer", "width": 1024, - "height": 678 + "height": 678, + "transparent": true, + "decorations": true } - ] + ], + "macOSPrivateApi": true } } diff --git a/src/App.tsx b/src/App.tsx index 939a820..6926ddb 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -84,7 +84,7 @@ function App() { return (
-
+
any; + content: DirectoryContent[]; + onDirectoryClick: (filePath: string) => any; } -export function DirectoryContents({content, onDirectoryClick}: Props) { - return <> - {content.length === 0 ? "There are no files in this directory." : ""} +export function DirectoryContents({ content, onDirectoryClick }: Props) { + return ( +
+ {content.length === 0 ? "There are no files in this directory." : ""} - {content.map((content, idx) => { - const [fileType, [fileName, filePath]] = Object.entries(content)[0]; + {content.map((content, idx) => { + const [fileType, [fileName, filePath]] = Object.entries(content)[0]; - return ( - - fileType === "Directory" - ? onDirectoryClick(filePath) - : undefined - } - key={idx} - name={fileName} - /> - ); - })} - - ; -} \ No newline at end of file + return ( + + fileType === "Directory" ? onDirectoryClick(filePath) : undefined + } + key={idx} + name={fileName} + /> + ); + })} +
+ ); +} diff --git a/src/components/MainBody/DirectoryEntity.tsx b/src/components/MainBody/DirectoryEntity.tsx index 8219b5d..2c3bf36 100644 --- a/src/components/MainBody/DirectoryEntity.tsx +++ b/src/components/MainBody/DirectoryEntity.tsx @@ -1,23 +1,30 @@ -import {MouseEventHandler} from "react"; -import {DirectoryEntityType} from "../../types"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" -import { faFile, faFolder } from "@fortawesome/free-solid-svg-icons" +import { MouseEventHandler } from "react"; +import { DirectoryEntityType } from "../../types"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faFile, faFolder } from "@fortawesome/free-solid-svg-icons"; interface Props { - name: string; - type: DirectoryEntityType; - onClick?: MouseEventHandler; + name: string; + type: DirectoryEntityType; + onClick?: MouseEventHandler; } export default function DirectoryEntity({ name, type, onClick }: Props) { - return ( - <> - - - ) -} \ No newline at end of file + return ( + <> + + + ); +} diff --git a/src/components/MainBody/Volumes/VolumeComponent.tsx b/src/components/MainBody/Volumes/VolumeComponent.tsx index 8609fb6..8be1bc5 100644 --- a/src/components/MainBody/Volumes/VolumeComponent.tsx +++ b/src/components/MainBody/Volumes/VolumeComponent.tsx @@ -1,17 +1,23 @@ -import {Volume} from "../../../types"; -import {MouseEventHandler} from "react"; +import { Volume } from "../../../types"; +import { MouseEventHandler } from "react"; interface Props { - volume: Volume; - onClick: MouseEventHandler; + volume: Volume; + onClick: MouseEventHandler; } export default function VolumeComponent({ volume, onClick }: Props) { - return ( - - ) + return ( + + ); } diff --git a/src/components/TopBar/FolderNavigation.tsx b/src/components/TopBar/FolderNavigation.tsx index 697b2de..bff292f 100644 --- a/src/components/TopBar/FolderNavigation.tsx +++ b/src/components/TopBar/FolderNavigation.tsx @@ -1,27 +1,38 @@ -import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; -import {faArrowLeft, faArrowRight} from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faArrowLeft, faArrowRight } from "@fortawesome/free-solid-svg-icons"; export interface Props { - onBackArrowClick: () => void; - canGoBackward: boolean; - onForwardArrowClick: () => void; - canGoForward: boolean; + onBackArrowClick: () => void; + canGoBackward: boolean; + onForwardArrowClick: () => void; + canGoForward: boolean; } -export default function FolderNavigation({ onBackArrowClick, canGoBackward, onForwardArrowClick, canGoForward }: Props) { - return
-
- +export default function FolderNavigation({ + onBackArrowClick, + canGoBackward, + onForwardArrowClick, + canGoForward, +}: Props) { + return ( +
+
+ - -
-
; + +
+
+ ); } diff --git a/src/components/TopBar/SearchBar.tsx b/src/components/TopBar/SearchBar.tsx index e434507..acdb621 100644 --- a/src/components/TopBar/SearchBar.tsx +++ b/src/components/TopBar/SearchBar.tsx @@ -49,8 +49,8 @@ export default function SearchBar({ diff --git a/src/components/TopBar/SearchFilter.tsx b/src/components/TopBar/SearchFilter.tsx index dde797d..4010022 100644 --- a/src/components/TopBar/SearchFilter.tsx +++ b/src/components/TopBar/SearchFilter.tsx @@ -1,75 +1,83 @@ -import Input, {InputSize} from "../../ui/Input"; -import {ChangeEvent, Dispatch, SetStateAction} from "react"; -import {ISearchFilter} from "./SearchBar"; +import Input, { InputSize } from "../../ui/Input"; +import { ChangeEvent, Dispatch, SetStateAction } from "react"; +import { ISearchFilter } from "./SearchBar"; interface Props { - filters: ISearchFilter; - setFilters: Dispatch>; + filters: ISearchFilter; + setFilters: Dispatch>; } export default function SearchFilter({ filters, setFilters }: Props) { - function onAcceptFilesChange(e: ChangeEvent) { - if (!e.target.checked && !filters.acceptDirectories) { - setFilters({ - ...filters, - acceptFiles: false, - acceptDirectories: true, - }); + function onAcceptFilesChange(e: ChangeEvent) { + if (!e.target.checked && !filters.acceptDirectories) { + setFilters({ + ...filters, + acceptFiles: false, + acceptDirectories: true, + }); - return; - } - - setFilters({ - ...filters, - acceptFiles: e.target.checked, - }); + return; } - function onAcceptDirsChange(e: ChangeEvent) { - if (!e.target.checked && !filters.acceptFiles) { - setFilters({ - ...filters, - acceptDirectories: false, - acceptFiles: true, - }); + setFilters({ + ...filters, + acceptFiles: e.target.checked, + }); + } - return; - } + function onAcceptDirsChange(e: ChangeEvent) { + if (!e.target.checked && !filters.acceptFiles) { + setFilters({ + ...filters, + acceptDirectories: false, + acceptFiles: true, + }); - setFilters({ - ...filters, - acceptDirectories: e.target.checked, - }); + return; } - function onExtensionChange(e: ChangeEvent) { - setFilters({ - ...filters, - extension: e.target.value, - }) - } + setFilters({ + ...filters, + acceptDirectories: e.target.checked, + }); + } - return ( -
-
- - - -
+ function onExtensionChange(e: ChangeEvent) { + setFilters({ + ...filters, + extension: e.target.value, + }); + } -
- - - -
-
- ) -} \ No newline at end of file + return ( +
+
+ + + +
+ +
+ + + +
+
+ ); +} diff --git a/src/index.css b/src/index.css index 4aa5cb0..e8e339c 100644 --- a/src/index.css +++ b/src/index.css @@ -3,7 +3,8 @@ @tailwind utilities; body { - @apply m-0 p-0 box-border text-white bg-background; + @apply m-0 p-0 box-border text-white; + background-color: rgba(33, 33, 33, 0.75); } h3 { @@ -12,4 +13,4 @@ h3 { progress[value] { background-color: blue; -} \ No newline at end of file +} diff --git a/tailwind.config.js b/tailwind.config.js index e8ad1a6..0f4d8d4 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -7,8 +7,8 @@ export default { theme: { extend: { colors: { - "background": "#212121", - "darker": "#1a1a1a", + "background": "rgba(33, 33, 33, 0.5)", + "darker": "rgba(26, 26, 26, 0.5)", }, borderWidth: { "1": "1px",