feat(layout):完成基本界面布局以及文件夹扫描功能。
This commit is contained in:
		
							
								
								
									
										101
									
								
								src-tauri/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										101
									
								
								src-tauri/Cargo.lock
									
									
									
										generated
									
									
									
								
							| @@ -1626,6 +1626,17 @@ dependencies = [ | ||||
|  "objc_exception", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "objc-foundation" | ||||
| version = "0.1.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" | ||||
| dependencies = [ | ||||
|  "block", | ||||
|  "objc", | ||||
|  "objc_id", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "objc_exception" | ||||
| version = "0.1.2" | ||||
| @@ -2088,6 +2099,30 @@ version = "0.6.28" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" | ||||
|  | ||||
| [[package]] | ||||
| name = "rfd" | ||||
| version = "0.10.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "0149778bd99b6959285b0933288206090c50e2327f47a9c463bfdbf45c8823ea" | ||||
| dependencies = [ | ||||
|  "block", | ||||
|  "dispatch", | ||||
|  "glib-sys", | ||||
|  "gobject-sys", | ||||
|  "gtk-sys", | ||||
|  "js-sys", | ||||
|  "lazy_static", | ||||
|  "log", | ||||
|  "objc", | ||||
|  "objc-foundation", | ||||
|  "objc_id", | ||||
|  "raw-window-handle", | ||||
|  "wasm-bindgen", | ||||
|  "wasm-bindgen-futures", | ||||
|  "web-sys", | ||||
|  "windows 0.37.0", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "rustc_version" | ||||
| version = "0.4.0" | ||||
| @@ -2536,6 +2571,7 @@ dependencies = [ | ||||
|  "rand 0.8.5", | ||||
|  "raw-window-handle", | ||||
|  "regex", | ||||
|  "rfd", | ||||
|  "semver", | ||||
|  "serde", | ||||
|  "serde_json", | ||||
| @@ -3081,6 +3117,18 @@ dependencies = [ | ||||
|  "wasm-bindgen-shared", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "wasm-bindgen-futures" | ||||
| version = "0.4.34" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" | ||||
| dependencies = [ | ||||
|  "cfg-if", | ||||
|  "js-sys", | ||||
|  "wasm-bindgen", | ||||
|  "web-sys", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "wasm-bindgen-macro" | ||||
| version = "0.2.84" | ||||
| @@ -3110,6 +3158,16 @@ version = "0.2.84" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" | ||||
|  | ||||
| [[package]] | ||||
| name = "web-sys" | ||||
| version = "0.3.61" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" | ||||
| dependencies = [ | ||||
|  "js-sys", | ||||
|  "wasm-bindgen", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "webkit2gtk" | ||||
| version = "0.18.2" | ||||
| @@ -3226,6 +3284,19 @@ version = "0.4.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" | ||||
|  | ||||
| [[package]] | ||||
| name = "windows" | ||||
| version = "0.37.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647" | ||||
| dependencies = [ | ||||
|  "windows_aarch64_msvc 0.37.0", | ||||
|  "windows_i686_gnu 0.37.0", | ||||
|  "windows_i686_msvc 0.37.0", | ||||
|  "windows_x86_64_gnu 0.37.0", | ||||
|  "windows_x86_64_msvc 0.37.0", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "windows" | ||||
| version = "0.39.0" | ||||
| @@ -3326,6 +3397,12 @@ version = "0.42.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" | ||||
|  | ||||
| [[package]] | ||||
| name = "windows_aarch64_msvc" | ||||
| version = "0.37.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a" | ||||
|  | ||||
| [[package]] | ||||
| name = "windows_aarch64_msvc" | ||||
| version = "0.39.0" | ||||
| @@ -3338,6 +3415,12 @@ version = "0.42.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" | ||||
|  | ||||
| [[package]] | ||||
| name = "windows_i686_gnu" | ||||
| version = "0.37.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1" | ||||
|  | ||||
| [[package]] | ||||
| name = "windows_i686_gnu" | ||||
| version = "0.39.0" | ||||
| @@ -3350,6 +3433,12 @@ version = "0.42.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" | ||||
|  | ||||
| [[package]] | ||||
| name = "windows_i686_msvc" | ||||
| version = "0.37.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c" | ||||
|  | ||||
| [[package]] | ||||
| name = "windows_i686_msvc" | ||||
| version = "0.39.0" | ||||
| @@ -3362,6 +3451,12 @@ version = "0.42.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" | ||||
|  | ||||
| [[package]] | ||||
| name = "windows_x86_64_gnu" | ||||
| version = "0.37.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d" | ||||
|  | ||||
| [[package]] | ||||
| name = "windows_x86_64_gnu" | ||||
| version = "0.39.0" | ||||
| @@ -3380,6 +3475,12 @@ version = "0.42.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" | ||||
|  | ||||
| [[package]] | ||||
| name = "windows_x86_64_msvc" | ||||
| version = "0.37.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d" | ||||
|  | ||||
| [[package]] | ||||
| name = "windows_x86_64_msvc" | ||||
| version = "0.39.0" | ||||
|   | ||||
| @@ -14,7 +14,7 @@ tauri-build = { version = "1.2", features = [] } | ||||
|  | ||||
| [dependencies] | ||||
| once_cell = "1.17.0" | ||||
| tauri = { version = "1.2", features = ["shell-open"] } | ||||
| tauri = { version = "1.2", features = ["dialog-open", "shell-open"] } | ||||
| serde = { version = "1.0", features = ["derive"] } | ||||
| serde_json = "1.0" | ||||
| chrono = { version = "0.4.23", features = ["serde"] } | ||||
|   | ||||
							
								
								
									
										36
									
								
								src-tauri/src/commands/files.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src-tauri/src/commands/files.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| use anyhow::anyhow; | ||||
| use serde::Serialize; | ||||
| use walkdir::WalkDir; | ||||
|  | ||||
| #[derive(Debug, Clone, Serialize)] | ||||
| pub struct FileItem { | ||||
|     pub filename: String, | ||||
|     pub path: String, | ||||
| } | ||||
|  | ||||
| #[tauri::command] | ||||
| pub fn scan_directory(target: String) -> Result<Vec<FileItem>, String> { | ||||
|     WalkDir::new(target) | ||||
|         .into_iter() | ||||
|         .filter_map(|f| f.ok()) | ||||
|         .filter(|f| f.path().is_file()) | ||||
|         .map(|f| { | ||||
|             Ok(FileItem { | ||||
|                 filename: f | ||||
|                     .path() | ||||
|                     .file_name() | ||||
|                     .ok_or(anyhow!("不能获取到文件名。"))? | ||||
|                     .to_owned() | ||||
|                     .into_string() | ||||
|                     .unwrap(), | ||||
|                 path: f | ||||
|                     .path() | ||||
|                     .clone() | ||||
|                     .to_str() | ||||
|                     .ok_or(anyhow!("不能获取到文件路径。"))? | ||||
|                     .to_string(), | ||||
|             }) | ||||
|         }) | ||||
|         .collect::<Result<Vec<FileItem>, anyhow::Error>>() | ||||
|         .map_err(|e| e.to_string()) | ||||
| } | ||||
| @@ -1,5 +1,11 @@ | ||||
| use tauri::{App, AppHandle, Runtime, Window}; | ||||
|  | ||||
| mod files; | ||||
|  | ||||
| pub mod prelude { | ||||
|     pub use super::files::*; | ||||
| } | ||||
|  | ||||
| /// 用于持有应用实例,可存放不同的应用实例。 | ||||
| pub enum AppHold<'a, R: Runtime> { | ||||
|     Instance(&'a App<R>), | ||||
|   | ||||
| @@ -8,7 +8,7 @@ use tauri::Manager; | ||||
|  | ||||
| fn main() { | ||||
|     tauri::Builder::default() | ||||
|         .invoke_handler(tauri::generate_handler![]) | ||||
|         .invoke_handler(tauri::generate_handler![commands::prelude::scan_directory]) | ||||
|         .setup(|app| { | ||||
|             let main_window = app.get_window("main").unwrap(); | ||||
|             #[cfg(debug_assertions)] | ||||
|   | ||||
| @@ -16,6 +16,14 @@ | ||||
|       "shell": { | ||||
|         "all": false, | ||||
|         "open": true | ||||
|       }, | ||||
|       "dialog": { | ||||
|         "all": false, | ||||
|         "ask": false, | ||||
|         "confirm": false, | ||||
|         "message": false, | ||||
|         "open": true, | ||||
|         "save": false | ||||
|       } | ||||
|     }, | ||||
|     "bundle": { | ||||
|   | ||||
| @@ -1,15 +1,17 @@ | ||||
| import { Box, Group } from "@mantine/core"; | ||||
| import { FC } from "react"; | ||||
| import { Outlet } from "react-router-dom"; | ||||
| import { NavMenu } from "./NavMenu"; | ||||
| import { Group, Stack } from '@mantine/core'; | ||||
| import { FC } from 'react'; | ||||
| import { ComicView } from './components/ComicView'; | ||||
| import { PicToolbar } from './components/PicToolbar'; | ||||
| import { NavMenu } from './NavMenu'; | ||||
|  | ||||
| export const MainLayout: FC = () => { | ||||
|   return ( | ||||
|     <Group grow noWrap spacing={0} h="100%" w="100%"> | ||||
|       <NavMenu /> | ||||
|       <Box h="inherit" w="inherit" maw="100%" sx={{ flexGrow: 5 }}> | ||||
|         <Outlet /> | ||||
|       </Box> | ||||
|       <Stack h="inherit" w="inherit" maw="100%" sx={{ flexGrow: 5 }} spacing={0}> | ||||
|         <PicToolbar /> | ||||
|         <ComicView /> | ||||
|       </Stack> | ||||
|     </Group> | ||||
|   ); | ||||
| }; | ||||
|   | ||||
| @@ -1,32 +1,38 @@ | ||||
| import { Stack, useMantineTheme } from "@mantine/core"; | ||||
| import { ifElse, path, propEq } from "ramda"; | ||||
| import { FC, useMemo } from "react"; | ||||
| import { Stack, useMantineTheme } from '@mantine/core'; | ||||
| import { ifElse, path, propEq } from 'ramda'; | ||||
| import { FC, useMemo } from 'react'; | ||||
| import { FileList } from './components/FileList'; | ||||
| import { FileToolbar } from './components/FileTools'; | ||||
|  | ||||
| const bgSelectFn = ifElse( | ||||
|   propEq("colorScheme", "dark"), | ||||
|   path(["colors", "cbg", 2]), | ||||
|   path(["colors", "cbg", 7]) | ||||
|   propEq('colorScheme', 'dark'), | ||||
|   path(['colors', 'cbg', 2]), | ||||
|   path(['colors', 'cbg', 7]) | ||||
| ); | ||||
|  | ||||
| export const NavMenu: FC = () => { | ||||
|   const theme = useMantineTheme(); | ||||
|   const normalColor = useMemo(() => path(["violet", 7])(theme.colors), [theme.colors]); | ||||
|   const activatedColor = useMemo(() => path<string>(["violet", 3])(theme.colors), [theme.colors]); | ||||
|   const disabledColor = useMemo(() => path<string>(["gray", 7])(theme.colors), [theme.colors]); | ||||
|   const normalColor = useMemo(() => path(['violet', 7])(theme.colors), [theme.colors]); | ||||
|   const activatedColor = useMemo(() => path<string>(['violet', 3])(theme.colors), [theme.colors]); | ||||
|   const disabledColor = useMemo(() => path<string>(['gray', 7])(theme.colors), [theme.colors]); | ||||
|   const navMenuBg = useMemo(() => bgSelectFn(theme), [theme, theme]); | ||||
|  | ||||
|   return ( | ||||
|     <Stack | ||||
|       spacing={24} | ||||
|       maw={64} | ||||
|       spacing={8} | ||||
|       miw={200} | ||||
|       h="inherit" | ||||
|       sx={(theme) => ({ | ||||
|       sx={theme => ({ | ||||
|         flexGrow: 1, | ||||
|         backgroundColor: navMenuBg, | ||||
|         overflow: 'hidden' | ||||
|       })} | ||||
|       px={4} | ||||
|       py={4} | ||||
|       align="center" | ||||
|       px={16} | ||||
|       py={16} | ||||
|     ></Stack> | ||||
|     > | ||||
|       <FileToolbar /> | ||||
|       <FileList /> | ||||
|     </Stack> | ||||
|   ); | ||||
| }; | ||||
|   | ||||
							
								
								
									
										6
									
								
								src/components/ComicView.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/components/ComicView.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| import { Box } from '@mantine/core'; | ||||
| import { FC } from 'react'; | ||||
|  | ||||
| export const ComicView: FC = () => { | ||||
|   return <Box w="100%" h="100%" sx={{ overflow: 'hidden' }}></Box>; | ||||
| }; | ||||
							
								
								
									
										23
									
								
								src/components/FileList.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/components/FileList.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| import { Box, Center, Text } from '@mantine/core'; | ||||
| import { isEmpty, map, pipe, sort } from 'ramda'; | ||||
| import { FC } from 'react'; | ||||
| import { useFileListStore } from '../states/files'; | ||||
|  | ||||
| export const FileList: FC = () => { | ||||
|   const files = useFileListStore.use.files(); | ||||
|   console.log('[debug]files from store: ', files); | ||||
|  | ||||
|   return ( | ||||
|     <Box w="100%" h="100%" pl={4} sx={{ flexGrow: 1, overflowY: 'auto', overflowX: 'hidden' }}> | ||||
|       {pipe( | ||||
|         sort((fa, fb) => fa.sort - fb.sort), | ||||
|         map(item => <div key={item.filename}>{item.filename}</div>) | ||||
|       )(files)} | ||||
|       {isEmpty(files) && ( | ||||
|         <Center h="100%"> | ||||
|           <Text size="xs">请先打开一个文件夹。</Text> | ||||
|         </Center> | ||||
|       )} | ||||
|     </Box> | ||||
|   ); | ||||
| }; | ||||
							
								
								
									
										42
									
								
								src/components/FileTools.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/components/FileTools.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| import { Button, Group, Tooltip } from '@mantine/core'; | ||||
| import { notifications } from '@mantine/notifications'; | ||||
| import { IconFolder } from '@tabler/icons-react'; | ||||
| import { invoke } from '@tauri-apps/api'; | ||||
| import { open } from '@tauri-apps/api/dialog'; | ||||
| import { FC, useCallback } from 'react'; | ||||
| import { useFileListStore } from '../states/files'; | ||||
|  | ||||
| export const FileToolbar: FC = () => { | ||||
|   const storeFiles = useFileListStore.use.updateFiles(); | ||||
|   const handleOpenAction = useCallback(async () => { | ||||
|     try { | ||||
|       const directory = await open({ | ||||
|         title: '打开要浏览的漫画所在的文件夹', | ||||
|         directory: true, | ||||
|         multiple: false | ||||
|       }); | ||||
|       const files = await invoke('scan_directory', { target: directory }); | ||||
|       console.log('[debug]file list: ', files); | ||||
|       storeFiles(files); | ||||
|     } catch (e) { | ||||
|       console.error('[error]打开文件夹', e); | ||||
|       notifications.show({ title: '未能成功打开指定文件夹,请重试。', color: 'red' }); | ||||
|     } | ||||
|   }, [storeFiles]); | ||||
|  | ||||
|   return ( | ||||
|     <Group align="start" w="100%" spacing={4}> | ||||
|       <Tooltip label="打开漫画所在文件夹"> | ||||
|         <Button | ||||
|           size="xs" | ||||
|           variant="subtle" | ||||
|           fullWidth | ||||
|           leftIcon={<IconFolder stroke={1.5} size={14} />} | ||||
|           onClick={handleOpenAction} | ||||
|         > | ||||
|           打开文件夹 | ||||
|         </Button> | ||||
|       </Tooltip> | ||||
|     </Group> | ||||
|   ); | ||||
| }; | ||||
							
								
								
									
										61
									
								
								src/components/PicToolbar.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/components/PicToolbar.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| import { ActionIcon, Group, NumberInput, rem, SegmentedControl, Tooltip } from '@mantine/core'; | ||||
| import { | ||||
|   IconArrowAutofitWidth, | ||||
|   IconLock, | ||||
|   IconPercentage, | ||||
|   IconZoomIn, | ||||
|   IconZoomOut | ||||
| } from '@tabler/icons-react'; | ||||
| import { FC } from 'react'; | ||||
| import { useZoomState } from '../states/zoom'; | ||||
|  | ||||
| export const PicToolbar: FC = () => { | ||||
|   const { lock, autoFit, currentZoom, viewMode } = useZoomState(); | ||||
|  | ||||
|   return ( | ||||
|     <Group w="100%" position="right" spacing={8} px={4} py={4}> | ||||
|       <Tooltip label="锁定缩放"> | ||||
|         <ActionIcon variant={lock ? 'filled' : 'subtle'} color="grape"> | ||||
|           <IconLock stroke={1.5} size={24} /> | ||||
|         </ActionIcon> | ||||
|       </Tooltip> | ||||
|       <Tooltip label="适应窗口宽度"> | ||||
|         <ActionIcon variant={autoFit ? 'filled' : 'subtle'} color="grape"> | ||||
|           <IconArrowAutofitWidth stroke={1.5} size={24} /> | ||||
|         </ActionIcon> | ||||
|       </Tooltip> | ||||
|       <Tooltip label="缩小"> | ||||
|         <ActionIcon variant="subtle" color="grape"> | ||||
|           <IconZoomOut stroke={1.5} size={24} /> | ||||
|         </ActionIcon> | ||||
|       </Tooltip> | ||||
|       <NumberInput | ||||
|         hideControls | ||||
|         size="xs" | ||||
|         min={20} | ||||
|         max={100} | ||||
|         step={5} | ||||
|         value={currentZoom} | ||||
|         styles={{ input: { width: rem(58), textAlign: 'center' } }} | ||||
|         rightSection={<IconPercentage stroke={1.5} size={16} />} | ||||
|       /> | ||||
|       <Tooltip label="放大"> | ||||
|         <ActionIcon variant="subtle" color="grape"> | ||||
|           <IconZoomIn stroke={1.5} size={24} /> | ||||
|         </ActionIcon> | ||||
|       </Tooltip> | ||||
|       <Tooltip label="翻页模式"> | ||||
|         <SegmentedControl | ||||
|           size="xs" | ||||
|           value={viewMode} | ||||
|           color="grape" | ||||
|           data={[ | ||||
|             { label: '单页', value: 'single' }, | ||||
|             { label: '双页', value: 'double' }, | ||||
|             { label: '连续', value: 'continuation' } | ||||
|           ]} | ||||
|         /> | ||||
|       </Tooltip> | ||||
|     </Group> | ||||
|   ); | ||||
| }; | ||||
							
								
								
									
										5
									
								
								src/models.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/models.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| export type FileItem = { | ||||
|   sort: number; | ||||
|   filename: string; | ||||
|   path: string; | ||||
| }; | ||||
							
								
								
									
										28
									
								
								src/states/files.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/states/files.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| import { addIndex, map, mergeRight } from 'ramda'; | ||||
| import { FileItem } from '../models'; | ||||
| import { SyncObjectCallback } from '../types'; | ||||
| import { createStoreHook } from '../utils/store_creator'; | ||||
|  | ||||
| interface FileListState { | ||||
|   files: FileItem[]; | ||||
| } | ||||
|  | ||||
| type FileListActions = { | ||||
|   updateFiles: SyncObjectCallback<Omit<FileItem, 'sort'>[]>; | ||||
| }; | ||||
|  | ||||
| const initialState: FileListState = { | ||||
|   files: [] | ||||
| }; | ||||
|  | ||||
| export const useFileListStore = createStoreHook<FileListState & FileListActions>(set => ({ | ||||
|   ...initialState, | ||||
|   updateFiles(files) { | ||||
|     set(df => { | ||||
|       df.files = addIndex<Omit<FileItem, 'sort'>, FileItem>(map)( | ||||
|         (item, index) => mergeRight({ sort: index * 10 }, item), | ||||
|         files | ||||
|       ); | ||||
|     }); | ||||
|   } | ||||
| })); | ||||
							
								
								
									
										19
									
								
								src/states/zoom.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/states/zoom.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| import { createStoreHook } from '../utils/store_creator'; | ||||
|  | ||||
| interface ZoomState { | ||||
|   lock: boolean; | ||||
|   autoFit: boolean; | ||||
|   currentZoom: number; | ||||
|   viewMode: 'single' | 'double' | 'continuation'; | ||||
| } | ||||
|  | ||||
| const initialState: ZoomState = { | ||||
|   lock: true, | ||||
|   autoFit: false, | ||||
|   currentZoom: 100, | ||||
|   viewMode: 'continuation' | ||||
| }; | ||||
|  | ||||
| export const useZoomState = createStoreHook<ZoomState>(set => ({ | ||||
|   ...initialState | ||||
| })); | ||||
		Reference in New Issue
	
	Block a user