Skip to content

Commit 7732495

Browse files
committed
feat: input history
1 parent 17e32bb commit 7732495

File tree

9 files changed

+432
-110
lines changed

9 files changed

+432
-110
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
},
2525
"dependencies": {
2626
"@nextui-org/button": "^2.0.34",
27+
"@nextui-org/dropdown": "^2.1.26",
2728
"@nextui-org/input": "^2.2.2",
2829
"@nextui-org/modal": "^2.0.36",
2930
"@nextui-org/radio": "^2.1.2",

pnpm-lock.yaml

Lines changed: 327 additions & 79 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/App.tsx

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,18 @@ import FileView from '@/components/FileView.tsx'
55
import OperationBar from '@/components/OperationBar.tsx'
66
import Settings from '@/components/settings/Settings.tsx'
77
import { useDragging, useFiles } from '@/hooks'
8+
import { useInputFormat } from '@/hooks/useInputFormat.ts'
89
import { AnimatePresence } from 'framer-motion'
910
import { Flip, ToastContainer } from 'react-toastify'
1011

1112
import 'react-toastify/dist/ReactToastify.css'
1213

1314
function App() {
14-
const {
15+
const { inputValue, setInputValue, format, setFormat, formatOptions, addFormatOption } = useInputFormat()
16+
const { setSelectedKey, files, selectedFile, handleOpenFolder, handleDropFiles, handleClickRename } = useFiles({
1517
format,
16-
setFormat,
17-
setSelectedKey,
18-
files,
19-
selectedFile,
20-
handleOpenFolder,
21-
handleDropFiles,
22-
handleClickRename,
23-
} = useFiles()
18+
onRenamed: () => addFormatOption(format),
19+
})
2420
const hasFiles = files.length > 0
2521
const { isDragging } = useDragging({ onDrop: handleDropFiles })
2622
const showDropModal = hasFiles && isDragging
@@ -29,9 +25,12 @@ function App() {
2925
<div className="flex h-[100vh] p-4">
3026
<div className="flex w-full flex-col">
3127
<OperationBar
28+
inputValue={inputValue}
3229
format={format}
33-
onFormatChange={setFormat}
30+
formatOptions={formatOptions}
3431
hasFiles={hasFiles}
32+
onInputValueChange={setInputValue}
33+
onFormatChange={setFormat}
3534
onClickOpen={handleOpenFolder}
3635
onClickRename={handleClickRename}
3736
/>

src/components/OperationBar.tsx

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
1-
import { RiFolderOpenLine } from '@/components/icon'
1+
import { RiChatHistoryLine, RiFolderOpenLine } from '@/components/icon'
22
import { Button } from '@nextui-org/button'
3+
import { Dropdown, DropdownItem, DropdownMenu, DropdownTrigger } from '@nextui-org/dropdown'
34
import { Input } from '@nextui-org/input'
45
import { clsx } from 'clsx'
5-
import { KeyboardEvent, useRef, useState } from 'react'
6+
import { KeyboardEvent, useRef } from 'react'
67
import { useTranslation } from 'react-i18next'
78

89
function OperationBar({
10+
inputValue,
11+
onInputValueChange,
912
format,
13+
formatOptions,
1014
onFormatChange,
1115
hasFiles,
1216
onClickOpen,
1317
onClickRename,
1418
}: {
19+
inputValue: string
20+
onInputValueChange: (value: string) => void
1521
format: string
1622
onFormatChange: (format: string) => void
23+
formatOptions: string[]
1724
hasFiles: boolean
1825
onClickOpen: () => void
1926
onClickRename: () => void
@@ -22,17 +29,17 @@ function OperationBar({
2229

2330
const inputRef = useRef<HTMLInputElement>(null)
2431
const compositionRef = useRef(false)
25-
const [value, setValue] = useState(format)
32+
const items = formatOptions.map(option => ({ key: option, value: option }))
2633

2734
const handleCompositionStart = () => {
2835
compositionRef.current = true
2936
}
3037
const handleCompositionEnd = () => {
3138
compositionRef.current = false
32-
onFormatChange(value.trim())
39+
onFormatChange(inputValue.trim())
3340
}
3441
const handleValueChange = (val: string) => {
35-
setValue(val)
42+
onInputValueChange(val)
3643
if (!compositionRef.current) {
3744
onFormatChange(val.trim())
3845
}
@@ -43,8 +50,14 @@ function OperationBar({
4350
}
4451
}
4552
const handleBlur = () => {
46-
const val = value.trim()
47-
setValue(val)
53+
const val = inputValue.trim()
54+
onInputValueChange(val)
55+
onFormatChange(val)
56+
}
57+
58+
const handleSelect = (selection: any) => {
59+
const [val] = [...selection]
60+
onInputValueChange(val)
4861
onFormatChange(val)
4962
}
5063

@@ -63,7 +76,7 @@ function OperationBar({
6376
<div className={clsx(hasFiles ? 'flex' : 'hidden', 'w-full items-center justify-end pl-20')}>
6477
<Input
6578
ref={inputRef}
66-
value={value}
79+
value={inputValue}
6780
className="max-w-80"
6881
variant="underlined"
6982
color="primary"
@@ -74,6 +87,24 @@ function OperationBar({
7487
onKeyDown={handleKeydown}
7588
onBlur={handleBlur}
7689
/>
90+
<Dropdown placement="bottom-end" offset={14}>
91+
<DropdownTrigger>
92+
<div>
93+
<RiChatHistoryLine className="cursor-pointer text-large text-default-500" />
94+
</div>
95+
</DropdownTrigger>
96+
<DropdownMenu
97+
color="secondary"
98+
variant="light"
99+
disallowEmptySelection
100+
selectionMode="single"
101+
selectedKeys={[format]}
102+
onSelectionChange={handleSelect}
103+
items={items}
104+
>
105+
{item => <DropdownItem key={item.key}>{item.value}</DropdownItem>}
106+
</DropdownMenu>
107+
</Dropdown>
77108
<Button radius="sm" size="sm" className="btn--grad-pink ml-4 shrink-0" onClick={onClickRename}>
78109
{t('Rename')}
79110
<span>🚀</span>

src/components/icon/index.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,3 +112,14 @@ export function RiInformationLine(props: SVGProps<SVGSVGElement>) {
112112
</svg>
113113
)
114114
}
115+
116+
export function RiChatHistoryLine(props: SVGProps<SVGSVGElement>) {
117+
return (
118+
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" {...props}>
119+
<path
120+
fill="currentColor"
121+
d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10a9.96 9.96 0 0 1-4.708-1.175L2 22l1.176-5.29A9.96 9.96 0 0 1 2 12C2 6.477 6.477 2 12 2m0 2a8 8 0 0 0-8 8c0 1.335.326 2.618.94 3.766l.35.654l-.656 2.946l2.948-.654l.653.349A7.96 7.96 0 0 0 12 20a8 8 0 1 0 0-16m1 3v5h4v2h-6V7z"
122+
/>
123+
</svg>
124+
)
125+
}

src/const/index.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ export const enum ExifStatus {
1212

1313
export const enum StorageKey {
1414
LANGUAGE = 'LANGUAGE',
15-
FORMAT = 'FORMAT',
1615
MODE_EXIF = 'MODE_EXIF',
16+
INPUT_HISTORY = 'INPUT_HISTORY',
1717
}
1818

1919
export const enum Language {
@@ -43,8 +43,3 @@ export const formatVars: FormatVar[] = [
4343
'{Current}',
4444
'{current}',
4545
]
46-
47-
export function getInitialFormat() {
48-
const defaultVal = '{Make} {YYYY}.{MM}.{DD} {hh}.{mm}.{ss}'
49-
return localStorage.getItem(StorageKey.FORMAT) || defaultVal
50-
}

src/hooks/useFiles.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ExifStatus, getInitialFormat, StorageKey, TauriCommand } from '@/const'
1+
import { ExifStatus, TauriCommand } from '@/const'
22
import { useError } from '@/hooks'
33
import { useConfigStore } from '@/store/useConfigStore.ts'
44
import { transformIpcFiles } from '@/util'
@@ -8,11 +8,10 @@ import { useMemo, useState } from 'react'
88
import { useTranslation } from 'react-i18next'
99
import { toast } from 'react-toastify'
1010

11-
export function useFiles() {
11+
export function useFiles({ format, onRenamed }: { format: string; onRenamed: () => void }) {
1212
const exifMode = useConfigStore(state => state.mode.exif)
1313
const { t } = useTranslation()
1414
const { handleError } = useError()
15-
const [format, setFormat] = useState(getInitialFormat())
1615
const [ipcFiles, setIpcFiles] = useState<IpcFiles>([])
1716
const files = useMemo(() => transformIpcFiles({ ipcFiles, exifMode, format, t }), [ipcFiles, exifMode, format, t])
1817
const [selectedKey, setSelectedKey] = useState<string | null>(null)
@@ -62,7 +61,6 @@ export function useFiles() {
6261
return
6362
}
6463

65-
localStorage.setItem(StorageKey.FORMAT, format)
6664
setIsRenaming(true)
6765
invoke<string[]>(TauriCommand.RENAME_FILES, { renamePathData })
6866
.then(res => {
@@ -76,14 +74,13 @@ export function useFiles() {
7674
.concat(res)
7775
handleDropFiles(pathnameList)
7876
toast.success(t('Rename Success!'))
77+
onRenamed()
7978
})
8079
.catch(err => handleError({ err, title: t('Rename Files Error') }))
8180
.finally(() => setIsRenaming(false))
8281
}
8382

8483
return {
85-
format,
86-
setFormat,
8784
setSelectedKey,
8885
files,
8986
selectedFile,

src/hooks/useInputFormat.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { StorageKey } from '@/const'
2+
import { useEffect, useState } from 'react'
3+
4+
export function useInputFormat() {
5+
const [format, setFormat] = useState('')
6+
const [inputValue, setInputValue] = useState('')
7+
const [formatOptions, setFormatOptions] = useState<string[]>([])
8+
9+
useEffect(() => {
10+
let history = localStorage.getItem(StorageKey.INPUT_HISTORY) || ''
11+
if (!history) {
12+
const history = JSON.stringify(['{YYYY}{MM}{DD} {hh}.{mm}.{ss}'])
13+
localStorage.setItem(StorageKey.INPUT_HISTORY, history)
14+
}
15+
try {
16+
const newHistory = JSON.parse(history)
17+
setInputValue(newHistory[0])
18+
setFormat(newHistory[0])
19+
setFormatOptions(newHistory)
20+
} catch (e) {}
21+
}, [])
22+
23+
function addFormatOption(val: string) {
24+
const index = formatOptions.indexOf(val)
25+
if (index !== -1) formatOptions.splice(index, 1)
26+
27+
const newHistory = [val, ...formatOptions].slice(0, 5)
28+
setFormatOptions(newHistory)
29+
localStorage.setItem(StorageKey.INPUT_HISTORY, JSON.stringify(newHistory))
30+
}
31+
32+
return {
33+
format,
34+
setFormat,
35+
inputValue,
36+
setInputValue,
37+
formatOptions,
38+
addFormatOption,
39+
}
40+
}

tailwind.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { Config } from 'tailwindcss'
44
const config: Config = {
55
content: [
66
'./src/**/*.{js,ts,jsx,tsx,mdx}',
7-
'./node_modules/@nextui-org/theme/dist/components/(button|input|modal|radio|scroll-shadow|snippet|toggle|table|tabs|popover|ripple|spinner|checkbox|spacer).js',
7+
'./node_modules/@nextui-org/theme/dist/components/(button|dropdown|input|modal|radio|scroll-shadow|snippet|toggle|table|tabs|popover|ripple|spinner|menu|divider|checkbox|spacer).js',
88
],
99
theme: {
1010
extend: {

0 commit comments

Comments
 (0)