From b955bed715d08a86f658b5b040fb2270a9746853 Mon Sep 17 00:00:00 2001 From: Fantasy Programming Date: Fri, 13 Sep 2024 22:34:46 +0000 Subject: [PATCH] better base --- .envrc | 3 + .gitignore | 10 +- bun.lockb | Bin 394710 -> 394187 bytes devenv.lock | 116 +++++++++++++++++++++ devenv.nix | 56 ++++++++++ devenv.yaml | 15 +++ package.json | 2 - src-tauri/Cargo.lock | 135 ++++++++++++++----------- src-tauri/Cargo.toml | 14 ++- src-tauri/src/config.rs | 8 +- src-tauri/src/main.rs | 8 +- src-tauri/src/parser.rs | 133 +++++++++++------------- src-tauri/src/state.rs | 16 ++- src-tauri/src/utils.rs | 58 ++++++----- src/App.tsx | 15 ++- src/components/Board/Board.hook.tsx | 5 +- src/components/Board/Board.tsx | 28 +++-- src/components/Board/Board.types.ts | 6 +- src/components/BoardItem/BoardItem.tsx | 10 +- src/components/ViewBox/ViewBox.tsx | 11 +- src/components/ViewBox/ViewBoxInfo.tsx | 6 +- src/index.tsx | 33 +++--- src/lib/commands.ts | 29 ------ src/lib/helper.ts | 8 +- src/lib/utils.ts | 7 +- src/pages/Error.tsx | 0 src/pages/Home.tsx | 12 ++- src/pages/Settings.tsx | 14 ++- src/resources/refs.resource.ts | 9 ++ src/resources/settings.resource.ts | 38 +++++++ src/services/refs.service.ts | 21 ++++ src/services/settings.service.ts | 13 +++ src/state/hook.tsx | 3 +- src/state/refstore.tsx | 9 -- src/state/settingsStore.tsx | 61 ----------- 35 files changed, 546 insertions(+), 366 deletions(-) create mode 100644 .envrc create mode 100644 devenv.lock create mode 100644 devenv.nix create mode 100644 devenv.yaml create mode 100644 src/pages/Error.tsx create mode 100644 src/resources/refs.resource.ts create mode 100644 src/resources/settings.resource.ts create mode 100644 src/services/refs.service.ts create mode 100644 src/services/settings.service.ts delete mode 100644 src/state/settingsStore.tsx diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..5bf8fc1 --- /dev/null +++ b/.envrc @@ -0,0 +1,3 @@ +source_url "https://raw.githubusercontent.com/cachix/devenv/95f329d49a8a5289d31e0982652f7058a189bfca/direnvrc" "sha256-d+8cBpDfDBj41inrADaJt+bDWhOktwslgoP5YiGJ1v0=" + +use devenv \ No newline at end of file diff --git a/.gitignore b/.gitignore index 76add87..e4345be 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,10 @@ node_modules -dist \ No newline at end of file +dist# Devenv +.devenv* +devenv.local.nix + +# direnv +.direnv + +# pre-commit +.pre-commit-config.yaml diff --git a/bun.lockb b/bun.lockb index 7525114acfbf5a84880932836330beb444b0dccd..f029b248bbc7b2480c9ceb6128a42eb05703dfc9 100755 GIT binary patch delta 73503 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 B`Gx=h delta 73334 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 PathBuf { app_data_dir.join("collections") } -pub fn init(handle: AppHandle) { - let collection_path = get_collection_path(&handle); - let settings_path = get_settings_path(&handle); +pub fn init(handle: &AppHandle) { + let collection_path = get_collection_path(handle); + let settings_path = get_settings_path(handle); if !(collection_path.exists()) { fs::create_dir_all(&collection_path).unwrap(); } if !(settings_path.exists()) { - fs::write(settings_path, DEFAULT_SETTINGS).unwrap(); + fs::write(&settings_path, DEFAULT_SETTINGS).unwrap(); } } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 8e81aaa..4c3cc77 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -1,4 +1,3 @@ -// Prevents additional console window on Windows in release, DO NOT REMOVE!! #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] #![allow(unused_imports)] use tauri::Manager; @@ -24,10 +23,10 @@ fn main() { .plugin(tauri_plugin_snapshot::init()) .setup(|app| { let handle = app.handle(); - config::init(handle); - app.manage(state::init_media_ref(app.handle())); - app.manage(state::init_settings(app.handle())); + config::init(&handle); + app.manage(state::init_media_ref(&handle)); + app.manage(state::init_settings(&handle)); // Set window shadow (macos & windows only) #[cfg(any(windows, target_os = "macos"))] @@ -35,6 +34,7 @@ fn main() { let window = app.get_window("main").unwrap(); set_shadow(&window, true).expect("Unsupported platform"); } + Ok(()) }) .invoke_handler(commands::get_handlers()) diff --git a/src-tauri/src/parser.rs b/src-tauri/src/parser.rs index 8fb8c8a..77a660f 100644 --- a/src-tauri/src/parser.rs +++ b/src-tauri/src/parser.rs @@ -1,5 +1,6 @@ use std::{ fs::read_to_string, + io, path::{Path, PathBuf}, }; @@ -9,79 +10,58 @@ use crate::state::{ImageMetadata, ImageRef, Ref, Settings, VideoMetadata, VideoR use crate::utils::convert_file_src; /// Parse a pathbuffer array into a Ref struct -pub fn parse_refs(refs: &[PathBuf]) -> Result { - if refs - .iter() - .any(|ref_path| ref_path.file_name().unwrap() == "metadata.image.json") - { - return parse_image_ref(refs); +pub fn parse_refs(refs: &[PathBuf]) -> Result { + let metadata_file = refs.iter().find_map(|ref_path| { + ref_path.file_name().and_then(|name| { + let name_str = name.to_str()?; + match name_str { + "metadata.image.json" => Some(("image", ref_path)), + "metadata.video.json" => Some(("video", ref_path)), + "metadata.audio.json" => Some(("audio", ref_path)), + "metadata.note.json" => Some(("note", ref_path)), + "metadata.link.json" => Some(("link", ref_path)), + "metadata.doc.json" => Some(("doc", ref_path)), + _ => None, + } + }) + }); + + match metadata_file { + Some(("image", _)) => parse_image_ref(refs), + Some(("video", _)) => parse_video_ref(refs), + Some(("audio", _)) => parse_audio_ref(refs), + Some(("note", _)) => parse_note_ref(refs), + Some(("link", _)) => parse_link_ref(refs), + Some(("doc", _)) => parse_doc_ref(refs), + _ => Err(io::Error::new( + io::ErrorKind::InvalidInput, + "Invalid input: neither a media nor a note reference found", + )), } - - if refs - .iter() - .any(|ref_path| ref_path.file_name().unwrap() == "metadata.video.json") - { - return parse_video_ref(refs); - } - - if refs - .iter() - .any(|ref_path| ref_path.file_name().unwrap() == "metadata.audio.json") - { - return parse_audio_ref(refs); - } - - if refs - .iter() - .any(|ref_path| ref_path.file_name().unwrap() == "metadata.note.json") - { - return parse_note_ref(refs); - } - - if refs - .iter() - .any(|ref_path| ref_path.file_name().unwrap() == "metadata.link.json") - { - return parse_link_ref(refs); - } - - if refs - .iter() - .any(|ref_path| ref_path.file_name().unwrap() == "metadata.doc.json") - { - return parse_doc_ref(refs); - } - - Err(std::io::Error::new( - std::io::ErrorKind::InvalidInput, - "Invalid input: neither a media nor a note reference found", - )) } /// Parse a image reference -fn parse_image_ref(refs: &[PathBuf]) -> Result { +fn parse_image_ref(refs: &[PathBuf]) -> Result { let mut image_ref = ImageRef::default(); for ref_path in refs { - if ref_path.file_name().unwrap() == "metadata.image.json" { - let json_txt = std::fs::read_to_string(ref_path)?; - let metadata = parse_metadata::(&json_txt)?; - image_ref.metapath = ref_path.to_str().unwrap().to_string(); - image_ref.metadata = Some(metadata); - continue; + if let Some(file_name) = ref_path.file_name().and_then(|f| f.to_str()) { + if file_name == "metadata.image.json" { + let json_txt = std::fs::read_to_string(ref_path)?; + let metadata = parse_metadata::(&json_txt)?; + image_ref.metapath = ref_path + .to_str() + .ok_or_else(|| { + std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid metapath") + })? + .to_string(); + image_ref.metadata = Some(metadata); + } else if file_name.starts_with("lower_") { + image_ref.low_res_imagepath = convert_file_src(ref_path); + } else { + image_ref.image_path = convert_file_src(ref_path); + } } - - if ref_path - .file_name() - .unwrap() - .to_str() - .unwrap() - .starts_with("lower_") - { - image_ref.low_res_imagepath = convert_file_src(ref_path); - continue; - } - image_ref.image_path = convert_file_src(ref_path); } if image_ref.low_res_imagepath.is_empty() { @@ -96,15 +76,22 @@ fn parse_video_ref(refs: &[PathBuf]) -> Result { let mut video_ref = VideoRef::default(); for ref_path in refs { - if ref_path.file_name().unwrap() == "metadata.video.json" { - let json_txt = std::fs::read_to_string(ref_path)?; - let metadata = parse_metadata::(&json_txt)?; - video_ref.metapath = ref_path.to_str().unwrap().to_string(); - video_ref.metadata = Some(metadata); - continue; + if let Some(file_name) = ref_path.file_name().and_then(|f| f.to_str()) { + if file_name == "metadata.video.json" { + let json_txt = std::fs::read_to_string(ref_path)?; + let metadata = parse_metadata::(&json_txt)?; + + video_ref.metapath = ref_path + .to_str() + .ok_or_else(|| { + std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid metapath") + })? + .to_string(); + video_ref.metadata = Some(metadata); + } else { + video_ref.video_path = convert_file_src(ref_path); + } } - - video_ref.video_path = convert_file_src(ref_path); } Ok(Ref::Video(video_ref)) diff --git a/src-tauri/src/state.rs b/src-tauri/src/state.rs index c1eac80..1d24d85 100644 --- a/src-tauri/src/state.rs +++ b/src-tauri/src/state.rs @@ -540,12 +540,18 @@ pub enum SortBy { ModificationTime, } -pub fn init_media_ref(app_handle: AppHandle) -> Mutex> { - let collections_dir = get_collection_path(&app_handle); - utils::fetch_refs(&collections_dir) +pub fn init_media_ref(app_handle: &AppHandle) -> Mutex> { + let collections_dir = get_collection_path(app_handle); + match utils::fetch_refs(&collections_dir) { + Ok(refs) => refs, + Err(e) => { + eprintln!("Error initializing media references: {}", e); + Mutex::new(Vec::new()) + } + } } -pub fn init_settings(app_handle: AppHandle) -> Mutex { - let settings = get_settings_path(&app_handle); +pub fn init_settings(app_handle: &AppHandle) -> Mutex { + let settings = get_settings_path(app_handle); utils::fetch_settings(&settings) } diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index a487186..d5f6439 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -5,7 +5,7 @@ use serde_json::Value; use std::collections::{HashMap, VecDeque}; use std::fs::read_to_string; use std::panic::PanicInfo; -use std::{fs, path::Path, path::PathBuf, sync::Mutex}; +use std::{fs, io, path::Path, path::PathBuf, sync::Mutex}; use crate::parser::parse_refs; use crate::state::{AudioMetadata, AudioRef, LinkMetadata, LinkRef, Metadata, RefMeta}; @@ -22,46 +22,48 @@ where } /// Get all subdirectories in the given path -fn get_all_refs(collections_dir: &Path) -> Vec> { - let mut refs = Vec::new(); - if let Ok(entries) = std::fs::read_dir(collections_dir) { - for entry in entries.flatten() { - if let Ok(path) = entry.path().canonicalize() { - if path.is_dir() { - let mut children = Vec::new(); - if let Ok(dir_entries) = std::fs::read_dir(&path) { - for child in dir_entries.flatten() { - children.push(child.path()); - } - } - refs.push(children); - } - } - } - } - refs +fn get_all_refs(collections_dir: &Path) -> io::Result>> { + let result = fs::read_dir(collections_dir)? + .filter_map(|entry| entry.ok()) + .filter_map(|entry| entry.path().canonicalize().ok()) + .filter(|path| path.is_dir()) + .map(|dir| { + fs::read_dir(&dir) + .map(|entries| { + entries + .filter_map(|entry| entry.ok()) + .map(|entry| entry.path()) + .collect::>() + }) + .unwrap_or_else(|_| Vec::new()) + }) + .collect::>(); + + Ok(result) } /// Get all references in the collections directory -pub fn fetch_refs(collections_dir: &Path) -> Mutex> { - let mut ref_vec: Vec = Vec::new(); - let mut error_queue: VecDeque = VecDeque::new(); +pub fn fetch_refs(collections_dir: &Path) -> io::Result>> { + let all_refs = get_all_refs(collections_dir)?; + + let mut ref_vec = Vec::new(); + let mut errors = Vec::new(); - for ref_paths in get_all_refs(collections_dir) { + for ref_paths in all_refs { match parse_refs(&ref_paths) { Ok(ref_data) => ref_vec.push(ref_data), - Err(err) => error_queue.push_back(err), + Err(err) => errors.push(err), } } - if !error_queue.is_empty() { + if !errors.is_empty() { eprintln!("Errors encountered during reference parsing:"); - for err in error_queue.drain(..) { + for err in &errors { eprintln!(" - {}", err); } } - Mutex::new(ref_vec) + Ok(Mutex::new(ref_vec)) } pub fn fetch_settings(settings_path: &Path) -> Mutex { @@ -272,7 +274,7 @@ mod tests { let _ = fs::create_dir_all(collection_dir.join("dir1")); let _ = fs::create_dir_all(collection_dir.join("dir2")); - let refs = get_all_refs(collection_dir); + let refs = get_all_refs(collection_dir).unwrap_or_default(); assert_eq!(refs.len(), 2); assert_eq!(refs[0].len(), 0); assert_eq!(refs[1].len(), 0); diff --git a/src/App.tsx b/src/App.tsx index f715652..0a8e213 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,15 +5,14 @@ import { Toaster } from 'solid-toast'; import './App.css'; -import { setupListeners } from './lib/utils'; -import { useRefSelector } from './state/refstore'; +// import { setupListeners } from './lib/utils'; +// import { useRefSelector } from './state/refstore'; import { Show, createSignal, onCleanup } from 'solid-js'; import { createShortcut } from '@solid-primitives/keyboard'; import { emit } from '@tauri-apps/api/event'; const App = (props: RouteSectionProps) => { - const root = useRefSelector(); - const unlisteners = setupListeners(root); + // const unlisteners = setupListeners(root); const [sideNavOpen, setSideNavOpen] = createSignal(true); @@ -22,10 +21,10 @@ const App = (props: RouteSectionProps) => { emit('sidebar_toggled'); }); - onCleanup(async () => { - const unlistener = await unlisteners; - unlistener.forEach((unlistener) => unlistener()); - }); + // onCleanup(async () => { + // const unlistener = await unlisteners; + // unlistener.forEach((unlistener) => unlistener()); + // }); return ( <> diff --git a/src/components/Board/Board.hook.tsx b/src/components/Board/Board.hook.tsx index 3eae9c9..9c5e880 100644 --- a/src/components/Board/Board.hook.tsx +++ b/src/components/Board/Board.hook.tsx @@ -10,7 +10,6 @@ import { createVideoRef, } from '~/lib/commands'; import { sep } from '@tauri-apps/api/path'; -import { error, info } from 'tauri-plugin-log-api'; import { verifyExtension } from '~/lib/helper'; export const useFileSelector = createRoot(() => { @@ -44,14 +43,12 @@ export const useFileSelector = createRoot(() => { const extension = fileName.split('.').pop(); if (!extension) { - error('Error: File has no extension'); return null; } const type = verifyExtension(extension); if (!type) { - info('Error: File extension not supported'); return null; } @@ -69,7 +66,7 @@ export const useFileSelector = createRoot(() => { await createDocumentRef(file, fileName, collection); break; default: - error('Error: Unknown file type'); + console.error('Error: Unknown file type'); } setProgress({ diff --git a/src/components/Board/Board.tsx b/src/components/Board/Board.tsx index e96fd59..32ce0bb 100644 --- a/src/components/Board/Board.tsx +++ b/src/components/Board/Board.tsx @@ -27,16 +27,20 @@ import { Button } from '../ui/button'; import { createLinkRef } from '~/lib/commands'; const Board = (props: BoardProps) => { - const [boardRefs, setBoardRefs] = createSignal(props.refs); - const [searching, setSearching] = createSignal(false); - const [dialogOpen, setDialogOpen] = createSignal(false); + const [searchTerm, setSearchTerm] = createSignal(''); const [link, setLink] = createSignal(''); + const [dialogOpen, setDialogOpen] = createSignal(false); const [selectF, dropFiles, progress] = useFileSelector; const [gridSize] = gridSizeHook; const breakPoints = createMemo(() => getBreakpoints(gridSize())); + const refs = createMemo(() => { + const ref = props.refs.latest; + return searchTerm() !== '' ? searchExtended(ref, searchTerm()) : ref ?? []; + }); + onMount(() => { dropFiles(props.collection); @@ -65,22 +69,14 @@ const Board = (props: BoardProps) => { { - const value = e.target.value; - if (!Boolean(value)) { - setBoardRefs(props.refs); - setSearching(false); - return; - } - setBoardRefs(searchExtended(props.refs, value)); - if (!searching()) setSearching(true); - }} + oninput={(e) => setSearchTerm(e.target.value)} />
@@ -100,8 +96,8 @@ const Board = (props: BoardProps) => { 'p-10': breakPoints()() === 5, 'p-12': breakPoints()() === 6, }} - pre={!searching() ? [NewNote] : []} - items={boardRefs()} + pre={searchTerm() === '' ? [NewNote] : []} + items={refs()} gap={20} columns={breakPoints()()} > diff --git a/src/components/Board/Board.types.ts b/src/components/Board/Board.types.ts index 75a6073..d4a3733 100644 --- a/src/components/Board/Board.types.ts +++ b/src/components/Board/Board.types.ts @@ -1,9 +1,9 @@ -import { Accessor } from 'solid-js'; -import { Ref } from '../../lib/types'; +import type { Accessor, Resource } from 'solid-js'; +import type { Ref } from '../../lib/types'; export interface BoardProps { collection: string; - refs: Ref[]; + refs: Resource; home?: boolean; } diff --git a/src/components/BoardItem/BoardItem.tsx b/src/components/BoardItem/BoardItem.tsx index 3a2afa8..54d9193 100644 --- a/src/components/BoardItem/BoardItem.tsx +++ b/src/components/BoardItem/BoardItem.tsx @@ -8,7 +8,7 @@ import { Skeleton } from '../ui/skeleton'; import { ViewBox } from '../ViewBox/ViewBox.tsx'; import { NoteContent } from './BoardNoteItem.tsx'; import { createItems } from '~/lib/helper.ts'; -import { useSettingsSelector } from '~/state/settingsStore.tsx'; +import { getSettings } from '~/resources/settings.resource.ts'; export const BoardItem = (props: BoardItemProps) => { return ( @@ -69,7 +69,7 @@ const ImageItem = (props: { mediaInfo: ImageRef }) => { // Render a video into the board const VideoItem = (props: { mediaInfo: VideoRef }) => { - const { settings } = useSettingsSelector(); + const settings = getSettings(); const showcontext = async (e: MouseEvent) => { e.preventDefault(); @@ -95,13 +95,13 @@ const VideoItem = (props: { mediaInfo: VideoRef }) => { class="absolute h-full w-full rounded-xl object-cover" src={props?.mediaInfo?.video_path} preload={ - settings.appearance.video_ref_autoplay ? 'auto' : 'metadata' + settings()?.appearance.video_ref_autoplay ? 'auto' : 'metadata' } - autoplay={settings.appearance.video_ref_autoplay} + autoplay={settings()?.appearance.video_ref_autoplay} loop muted > - +
= (props) => {
- + + + ); }; diff --git a/src/components/ViewBox/ViewBoxInfo.tsx b/src/components/ViewBox/ViewBoxInfo.tsx index 795105b..d367215 100644 --- a/src/components/ViewBox/ViewBoxInfo.tsx +++ b/src/components/ViewBox/ViewBoxInfo.tsx @@ -24,13 +24,13 @@ import { saveMediaToDisk, } from '../../lib/helper'; import { ImageMetadata } from '~/lib/types'; -import { useSettingsSelector } from '~/state/settingsStore'; import { ViewNoteEditor } from './ViewNoteEditor'; +import { getSettings } from '~/resources/settings.resource'; export const ViewBoxInfo = (props: ViewBoxInfoProps) => { const [openTagsAdder, setOpenTagsAdder] = createSignal(false); const [showAllTags, setShowAllTags] = createSignal(false); - const { settings } = useSettingsSelector(); + const settings = getSettings(); const [inputValue, setInputValue] = createSignal(''); @@ -159,7 +159,7 @@ export const ViewBoxInfo = (props: ViewBoxInfoProps) => {

diff --git a/src/index.tsx b/src/index.tsx index fcddc3c..c382dbb 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,38 +1,35 @@ /* @refresh reload */ import { Router, Route } from '@solidjs/router'; import { render, ErrorBoundary } from 'solid-js/web'; -import { ColorModeProvider, localStorageManager } from '@kobalte/core'; -import { RefProvider } from './state/refstore.tsx'; -import { disableMenu } from './lib/utils.ts'; +import { cleanState } from './lib/utils.ts'; +// Styling import '@fontsource-variable/nunito'; import '@fontsource/prociono'; import './index.css'; +// Providers +import { ColorModeProvider, localStorageManager } from '@kobalte/core'; + // Pages import App from './App'; import Home from './pages/Home'; import Boards from './pages/Boards'; import Settings from './pages/Settings'; -import { SettingsProvider } from './state/settingsStore.tsx'; -disableMenu(); +cleanState(); render( () => ( - err}> - - - - - - - - - - - - +
{err}
}> + + + + + + + +
), document.getElementById('root') as HTMLElement, diff --git a/src/lib/commands.ts b/src/lib/commands.ts index d4962a8..83a9884 100644 --- a/src/lib/commands.ts +++ b/src/lib/commands.ts @@ -1,4 +1,3 @@ -import { error, info } from 'tauri-plugin-log-api'; import { invoke } from '@tauri-apps/api'; import { createRefDir, deleteRefDir, makepath, refExist } from './helper'; import { @@ -36,9 +35,6 @@ export const createImageRef = async ( return data; } catch (e) { - error( - `Error: Failed to create new media ref for file ${imagePath} - ${e} `, - ); console.error(e); return null; } @@ -66,9 +62,6 @@ export const createVideoRef = async ( return data; } catch (e) { - error( - `Error: Failed to create new media ref for file ${videoPath} - ${e} `, - ); console.error(e); return null; } @@ -96,9 +89,6 @@ export const createAudioRef = async ( return data; } catch (e) { - error( - `Error: Failed to create new media ref for file ${audioPath} - ${e} `, - ); console.error(e); return null; } @@ -121,7 +111,6 @@ export const createNoteRef = async ( emit('ref_added', data); } } catch (e) { - error(`Error: Failed to create new note ref - ${e} `); console.error(e); } }; @@ -148,7 +137,6 @@ export const createDocumentRef = async ( return data; } catch (e) { - error(`Error: Failed to create new media ref for file ${docPath} - ${e} `); console.error(e); return null; } @@ -158,13 +146,11 @@ export const createLinkRef = async (url: string, collectionName: string) => { const linkID = await generate_id({ lenght: 13, createDir: true }); console.log('here'); - info('ongoing'); const data: LinkRef = await invoke('generate_link_metadata', { refId: linkID, url, collection: collectionName, }); - info('completed'); if (data) { emit('ref_added', data); @@ -186,9 +172,6 @@ export const renameRef = async ( newName: newName, }); } catch (e) { - error( - `Error: Failed rename_ref operation for the ref with id ${refID} - ${e}`, - ); console.error(e); } }; @@ -199,7 +182,6 @@ export const deleteRef = async (collectionID: string) => { await invoke('remove_ref', { refId: collectionID }); await deleteRefDir(collectionID); } catch (e) { - error(`Error: Failed to delete ref with id ${collectionID} - ${e} `); console.error(e); } }; @@ -209,7 +191,6 @@ export const addTag = async (id: string, path: string, tag: string) => { try { await invoke('add_tag', { refId: id, path, tag: tag }); } catch (e) { - error(`Error: Failed add_tag operation for the ref with id ${id} - ${e}`); console.error(e); } }; @@ -223,9 +204,6 @@ export const removeTag = async (id: string, path: string, tag: string) => { tag: tag, }); } catch (e) { - error( - `Error: Failed remove_tag operation for the ref with id ${id} - ${e}`, - ); console.error(e); } }; @@ -244,9 +222,6 @@ export const mutateNote = async ( noteContent: content, }); } catch (e) { - error( - `Error: Failed mutate_note operation for the ref with id ${noteID} - ${e}`, - ); console.error(e); } }; @@ -263,9 +238,6 @@ export const mutateNoteText = async ( noteText: text, }); } catch (e) { - error( - `Error: Failed mutateNoteText operation for the ref with id ${id} - ${e}`, - ); console.error(e); } }; @@ -289,7 +261,6 @@ export const generate_id = async ({ break; } } catch (e) { - error(`Error: Failed to generate_id`); console.error(e); } } diff --git a/src/lib/helper.ts b/src/lib/helper.ts index c4e646f..a85dba2 100644 --- a/src/lib/helper.ts +++ b/src/lib/helper.ts @@ -25,7 +25,6 @@ import { } from './types'; import { appDataDir, downloadDir, join } from '@tauri-apps/api/path'; import { open } from '@tauri-apps/api/dialog'; -import { error } from 'tauri-plugin-log-api'; /// Check if a ref with the given id exists export const refExist = async (collectionName: string) => { @@ -47,7 +46,6 @@ export const createRefDir = async (collectionName: string) => { }); } catch (e) { console.error(e); - error(`Error: Couln't create ${collectionName} directory`); } }; @@ -60,7 +58,6 @@ export const deleteRefDir = async (collectionID: string) => { }); } catch (e) { console.error(e); - error(`Error: Couldn't delete ${collectionID} directory`); } }; @@ -71,7 +68,6 @@ export const get_note_content = async (notepath: string) => { return content; } catch (e) { console.error(e); - error(`Error: Failed to read the file at ${notepath}`); return 'Something went wrong'; } }; @@ -88,13 +84,13 @@ export const verifyExtension = (extension: string) => { }; /// Search for Refs -export function searchExtended(refs: Ref[], searchText: string) { +export function searchExtended(refs: Ref[] | undefined, searchText: string) { const fuseOpt: IFuseOptions = { keys: ['metadata.name', 'metadata.tags'], threshold: 0.5, }; - const fuse = new Fuse(refs, fuseOpt); + const fuse = new Fuse(refs || [], fuseOpt); const results = fuse.search(searchText); return results.map((result) => result.item); diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 9fe6957..476e06e 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,4 +1,3 @@ -import { error } from 'tauri-plugin-log-api'; import { listen, UnlistenFn } from '@tauri-apps/api/event'; import type { ClassValue } from 'clsx'; import { clsx } from 'clsx'; @@ -18,7 +17,7 @@ export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } -export function disableMenu() { +export function cleanState() { if (window.location.hostname !== 'tauri.localhost') { return; } @@ -93,8 +92,8 @@ export async function setupListeners(root: RootState): Promise { unlisteners.push(tagRemovedListener); } catch (e) { - error(`Error: Error setting up listeners - ${e}`); - throw error; + console.error(e); + throw e; } return unlisteners; diff --git a/src/pages/Error.tsx b/src/pages/Error.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx index 84ceed4..3a35db3 100644 --- a/src/pages/Home.tsx +++ b/src/pages/Home.tsx @@ -1,10 +1,16 @@ +import { Suspense } from 'solid-js'; import { Component } from 'solid-js'; -import { useRefSelector } from '~/state/refstore'; import Board from '~/components/Board/Board'; +import { getRefs } from '~/resources/refs.resource'; const Home: Component = () => { - const data = useRefSelector(); - return ; + const refs = getRefs(); + + return ( + loading...}> + + + ); }; export default Home; diff --git a/src/pages/Settings.tsx b/src/pages/Settings.tsx index 350bfb0..7b9f3e8 100644 --- a/src/pages/Settings.tsx +++ b/src/pages/Settings.tsx @@ -11,10 +11,14 @@ import { SelectValue, } from '~/components/ui/select'; import { RiArrowsArrowGoBackLine } from 'solid-icons/ri'; -import { useSettingsSelector } from '~/state/settingsStore'; +import { + getSettings, + showInfo, + autoPlayVideo, +} from '~/resources/settings.resource'; const Settings = () => { - const { settings, showInfo, autoPlayVideo } = useSettingsSelector(); + const settings = getSettings(); return ( @@ -40,7 +44,7 @@ const Settings = () => {
showInfo()} /> @@ -49,7 +53,7 @@ const Settings = () => { autoPlayVideo()} />
@@ -69,7 +73,7 @@ const Settings = () => { id="sort-by" options={['Creation_Time', 'Last_Modified']} placeholder="Sort By ..." - value={settings.behavior.sort_by} + value={settings()?.behavior.sort_by} itemComponent={(props) => ( {props.item.rawValue} diff --git a/src/resources/refs.resource.ts b/src/resources/refs.resource.ts new file mode 100644 index 0000000..0e845da --- /dev/null +++ b/src/resources/refs.resource.ts @@ -0,0 +1,9 @@ +import service from '~/services/refs.service'; +import { createResource } from 'solid-js'; +import { Ref } from '~/lib/types'; + +const [refs] = createResource(service.getRefs); + +export const getRefs = () => { + return refs; +}; diff --git a/src/resources/settings.resource.ts b/src/resources/settings.resource.ts new file mode 100644 index 0000000..a0082c8 --- /dev/null +++ b/src/resources/settings.resource.ts @@ -0,0 +1,38 @@ +import service from '~/services/settings.service'; +import { createResource } from 'solid-js'; + +import { AppSettings } from '~/lib/types'; + +const [settings, { mutate }] = createResource(service.getSettings); + +export const getSettings = () => { + return settings; +}; + +export const showInfo = () => { + mutate((oldSettings) => { + if (!oldSettings) return undefined; + + return { + ...oldSettings, + appearance: { + ...oldSettings?.appearance, + show_media_info: !oldSettings?.appearance.show_media_info, + }, + }; + }); +}; + +export const autoPlayVideo = () => { + mutate((oldSettings) => { + if (!oldSettings) return undefined; + + return { + ...oldSettings, + appearance: { + ...oldSettings?.appearance, + video_ref_autoplay: !oldSettings?.appearance.video_ref_autoplay, + }, + }; + }); +}; diff --git a/src/services/refs.service.ts b/src/services/refs.service.ts new file mode 100644 index 0000000..abb901e --- /dev/null +++ b/src/services/refs.service.ts @@ -0,0 +1,21 @@ +import { getUpdatedAtTimestamp } from '~/lib/helper'; +import { NoteRef, Ref } from '~/lib/types'; +import { invoke } from '@tauri-apps/api'; + +const getRefs = async (): Promise => { + try { + const data: Ref[] = await invoke('get_all_refs'); + + data.sort((a, b) => { + const aUpdatedAt = getUpdatedAtTimestamp(a); + const bUpdatedAt = getUpdatedAtTimestamp(b); + return bUpdatedAt - aUpdatedAt; + }); + + return data; + } catch (e) { + throw new Error('Failed to fetch refs at RefProvider fetchRef'); + } +}; + +export default { getRefs }; diff --git a/src/services/settings.service.ts b/src/services/settings.service.ts new file mode 100644 index 0000000..c9aee0d --- /dev/null +++ b/src/services/settings.service.ts @@ -0,0 +1,13 @@ +import { AppSettings } from '~/lib/types'; +import { invoke } from '@tauri-apps/api'; + +const getSettings = async (): Promise => { + try { + const settings: AppSettings = await invoke('get_settings'); + return settings; + } catch (error) { + throw new Error('Failed to fetch settings at SettingProvider'); + } +}; + +export default { getSettings }; diff --git a/src/state/hook.tsx b/src/state/hook.tsx index 85d5f7e..550112f 100644 --- a/src/state/hook.tsx +++ b/src/state/hook.tsx @@ -1,4 +1,3 @@ -import { debug } from 'tauri-plugin-log-api'; import { Accessor, onMount, createRoot, createSignal } from 'solid-js'; export type IGridSize = [ @@ -18,7 +17,7 @@ export const gridSizeHook = createRoot(() => { }); const updateGridSize = (size: number) => { - debug(`Debug: Grid size updated to ${size}`); + console.debug(`Debug: Grid size updated to ${size}`); setGridSize(size); localStorage.setItem('gridSize', size.toString()); }; diff --git a/src/state/refstore.tsx b/src/state/refstore.tsx index a1162e2..bb53e5e 100644 --- a/src/state/refstore.tsx +++ b/src/state/refstore.tsx @@ -1,4 +1,3 @@ -import { debug, error } from 'tauri-plugin-log-api'; import { onMount, createContext, ParentComponent, useContext } from 'solid-js'; import { createStore, produce } from 'solid-js/store'; import { NoteRef, Ref } from '~/lib/types'; @@ -31,7 +30,6 @@ export const RefProvider: ParentComponent = (props) => { setRef(data); } catch (e) { - error('Error: Failed to fetch refs at RefProvider fetchRef'); throw new Error('Failed to fetch refs at RefProvider fetchRef'); } }; @@ -39,7 +37,6 @@ export const RefProvider: ParentComponent = (props) => { onMount(fetchRefs); const mutateTag = (id: string, tagname: string, type: string) => { - debug(`Debug: Tag of ref with id ${id} mutated`); setRef( (meta) => meta.metadata.id === id, 'metadata', @@ -60,12 +57,10 @@ export const RefProvider: ParentComponent = (props) => { const addRef = (ref: Ref) => { setRef(produce((refs) => refs.unshift(ref))); - debug('Debug: Ref added'); }; const mutateName = (id: string, name: string) => { setRef((meta) => meta.metadata.id === id, 'metadata', 'name', name); - debug(`Debug: Name of ref with id ${id} mutated`); }; const deleteRef = (id: string) => { @@ -77,7 +72,6 @@ export const RefProvider: ParentComponent = (props) => { } }), ); - debug(`Debug: Ref with the id ${id} deleted`); }; const mutateNote = (id: string, note: string) => { @@ -89,12 +83,10 @@ export const RefProvider: ParentComponent = (props) => { } }), ); - debug(`Debug: Note with the id ${id} mutated`); }; const mutateNoteText = (id: string, note: string) => { setRef((meta) => meta.metadata.id === id, 'metadata', 'note_text', note); - debug(`Debug: Note of the ref with id ${id} mutated`); }; const rootState = { @@ -117,7 +109,6 @@ export const RefProvider: ParentComponent = (props) => { export const useRefSelector = () => { const refSelector = useContext(Context); if (!refSelector) { - error('Error: useRefSelectorContext should be called inside RefProvider'); throw new Error( 'useRefSelectorContext should be called inside RefProvider', ); diff --git a/src/state/settingsStore.tsx b/src/state/settingsStore.tsx deleted file mode 100644 index 312fd52..0000000 --- a/src/state/settingsStore.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { debug, error } from 'tauri-plugin-log-api'; -import { onMount, createContext, ParentComponent, useContext } from 'solid-js'; -import { createStore } from 'solid-js/store'; -import { invoke } from '@tauri-apps/api'; -import { AppSettings } from '~/lib/types'; - -export interface SettingRootState { - readonly settings: AppSettings; - showInfo: () => void; - autoPlayVideo: () => void; -} - -const Context = createContext(); - -export const SettingsProvider: ParentComponent = (props) => { - const [settings, setSettings] = createStore({} as AppSettings); - - onMount(async () => { - try { - let data: AppSettings = await invoke('get_settings'); - debug('Debug: Settings fetched'); - setSettings(data); - } catch (e) { - error('Error: Failed to fetch settings at SettingProvider'); - throw new Error('Failed to fetch settings at SettingProvider'); - } - }); - - const showInfo = () => { - setSettings('appearance', 'show_media_info', (show) => !show); - debug(`Debug: Appearance: Show_media_info toggled`); - }; - - const autoPlayVideo = () => { - setSettings('appearance', 'video_ref_autoplay', (play) => !play); - debug(`Debug: Appearance autoPlayVideo toggled`); - }; - - const settingsState = { - get settings() { - return settings; - }, - showInfo, - autoPlayVideo, - }; - - return ( - {props.children} - ); -}; - -export const useSettingsSelector = () => { - const settingsSelector = useContext(Context); - if (!settingsSelector) { - error('Error: useSettingsSelector should be called inside SettingsContext'); - throw new Error( - 'useSettingsSelector should be called inside SettingsContext', - ); - } - return settingsSelector; -};