update save config
This commit is contained in:
parent
ce4b3baf3a
commit
6b2d980060
|
|
@ -15,15 +15,15 @@ export const defaultShortcuts: IShortcut[] = [
|
|||
{
|
||||
id: uuid(),
|
||||
links: [
|
||||
'https://int.ipsupply.com.au/erptools/001_search-vpn?search=${keyword}',
|
||||
'https://www.ebay.com/sch/i.html?_nkw=${keyword}&_sop=15'
|
||||
'https://int.ipsupply.com.au/erptools/001_search-vpn?search={keyword}',
|
||||
'https://www.ebay.com/sch/i.html?_nkw={keyword}&_sop=15'
|
||||
],
|
||||
shortcut: 'CommandOrControl+Shift+1'
|
||||
shortcut: 'Control+Shift+1'
|
||||
},
|
||||
{
|
||||
id: uuid(),
|
||||
links: ['https://esearch.danielvu.com?keyword=${keyword}'],
|
||||
shortcut: 'CommandOrControl+Shift+2'
|
||||
links: ['https://esearch.danielvu.com?keyword={keyword}'],
|
||||
shortcut: 'Control+Shift+2'
|
||||
}
|
||||
]
|
||||
|
||||
|
|
@ -86,7 +86,7 @@ const handleOpenBrowserByLink = (data: IShortcut) => {
|
|||
const query = encodeURIComponent(text)
|
||||
|
||||
data.links.forEach((link) => {
|
||||
const url = link.replace(/\$\{keyword\}/g, query) // Thay ${query} trong link
|
||||
const url = link.replace(/\$\{keyword\}|\{keyword\}/g, query)
|
||||
console.log(`[${new Date().toLocaleTimeString()}] Opening URL: ${url}`)
|
||||
shell.openExternal(url) // Mở trong browser mặc định
|
||||
})
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { getConfigFile, saveConfigFile } from './api/config'
|
|||
function App(): React.JSX.Element {
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [shotcuts, setShotcuts] = useState<IShotcut[]>([])
|
||||
const [editing, setEditing] = useState<IShotcut | null>(null)
|
||||
|
||||
// Hàm lưu config
|
||||
const saveConfig = async (newShortcuts: IShotcut[]) => {
|
||||
|
|
@ -30,6 +31,21 @@ function App(): React.JSX.Element {
|
|||
saveConfig(newShortcuts)
|
||||
}
|
||||
|
||||
// Khi nhấn edit từ list
|
||||
const handleEdit = (shotcut: IShotcut) => {
|
||||
setEditing(shotcut)
|
||||
}
|
||||
|
||||
// Submit update
|
||||
const handleUpdate = (updatedShotcut: IShotcut) => {
|
||||
const updatedList = shotcuts.map((sc) =>
|
||||
sc.id === updatedShotcut.id ? updatedShotcut : sc
|
||||
)
|
||||
setShotcuts(updatedList)
|
||||
saveConfig(updatedList)
|
||||
setEditing(null) // reset form
|
||||
}
|
||||
|
||||
// Gọi IPC để lấy dữ liệu config
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
|
|
@ -67,15 +83,22 @@ function App(): React.JSX.Element {
|
|||
>
|
||||
<Container fluid mt={'lg'}>
|
||||
<ShotcutForm
|
||||
shortcuts={shotcuts}
|
||||
onSubmit={(newItem) => {
|
||||
const updated = [newItem, ...shotcuts]
|
||||
setShotcuts(updated)
|
||||
saveConfig(updated)
|
||||
}}
|
||||
editingShotcut={editing || undefined}
|
||||
onUpdate={handleUpdate}
|
||||
/>
|
||||
|
||||
<Box py={'lg'}>
|
||||
<ShotcutList shotcuts={shotcuts} onDelete={handleDelete} />
|
||||
<ShotcutList
|
||||
onEdit={handleEdit}
|
||||
shotcuts={shotcuts}
|
||||
onDelete={handleDelete}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<LoadingOverlay
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { ActionIcon, Button, Code, Group, Paper, Stack, Text, TextInput } from '
|
|||
import { useForm, zodResolver } from '@mantine/form'
|
||||
import { IShotcut } from '@renderer/types'
|
||||
import { IconPlus, IconX } from '@tabler/icons-react'
|
||||
import { useEffect } from 'react'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
import * as z from 'zod'
|
||||
|
||||
|
|
@ -46,11 +47,16 @@ type ShotcutFormValues = z.infer<typeof ShotcutSchema>
|
|||
|
||||
interface ShotcutFormProps {
|
||||
onSubmit: (shotcut: IShotcut) => void
|
||||
onUpdate?: (shotcut: IShotcut) => void
|
||||
editingShotcut?: IShotcut
|
||||
shortcuts: IShotcut[]
|
||||
}
|
||||
|
||||
export function ShotcutForm({ onSubmit }: ShotcutFormProps) {
|
||||
export function ShotcutForm({ onSubmit, onUpdate, editingShotcut, shortcuts }: ShotcutFormProps) {
|
||||
const form = useForm<ShotcutFormValues>({
|
||||
initialValues: { shortcut: '', links: [''] },
|
||||
initialValues: editingShotcut
|
||||
? { shortcut: editingShotcut.shortcut, links: editingShotcut.links }
|
||||
: { shortcut: '', links: [''] },
|
||||
validate: zodResolver(ShotcutSchema)
|
||||
})
|
||||
|
||||
|
|
@ -58,16 +64,41 @@ export function ShotcutForm({ onSubmit }: ShotcutFormProps) {
|
|||
const removeLink = (index: number) => form.removeListItem('links', index)
|
||||
|
||||
const handleSubmit = (values: ShotcutFormValues) => {
|
||||
onSubmit({ ...values, id: uuid() })
|
||||
form.reset()
|
||||
// Kiểm tra trùng shortcut
|
||||
const isDuplicate = shortcuts.some(
|
||||
(item) =>
|
||||
item.shortcut === values.shortcut &&
|
||||
(!editingShotcut || item.id !== editingShotcut.id)
|
||||
)
|
||||
|
||||
if (isDuplicate) {
|
||||
form.setFieldError('shortcut', 'Shortcut already exists')
|
||||
return
|
||||
}
|
||||
|
||||
if (editingShotcut && onUpdate) {
|
||||
onUpdate({ ...editingShotcut, ...values })
|
||||
|
||||
form.reset()
|
||||
} else {
|
||||
onSubmit({ ...values, id: uuid() })
|
||||
form.reset()
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!editingShotcut) return
|
||||
|
||||
form.setValues(editingShotcut)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [editingShotcut])
|
||||
|
||||
return (
|
||||
<Paper shadow="sm" radius="md" p="md" withBorder maw={600} mx="auto">
|
||||
<form onSubmit={form.onSubmit(handleSubmit)}>
|
||||
<Stack>
|
||||
<Text size="lg" fw={600}>
|
||||
Create New Shortcut
|
||||
{editingShotcut ? 'Update Shortcut' : 'Create New Shortcut'}
|
||||
</Text>
|
||||
|
||||
<TextInput
|
||||
|
|
@ -117,7 +148,7 @@ export function ShotcutForm({ onSubmit }: ShotcutFormProps) {
|
|||
</Button>
|
||||
|
||||
<Button type="submit" size="sm">
|
||||
Create Shortcut
|
||||
{editingShotcut ? 'Update Shortcut' : 'Create Shortcut'}
|
||||
</Button>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
|
|
|||
|
|
@ -3,14 +3,15 @@
|
|||
import { useState } from 'react'
|
||||
import { ActionIcon, Badge, Card, Group, Stack, Text, Modal, Button, Flex } from '@mantine/core'
|
||||
import { IShotcut } from '@renderer/types'
|
||||
import { IconExternalLink, IconTrash } from '@tabler/icons-react'
|
||||
import { IconEdit, IconExternalLink, IconTrash } from '@tabler/icons-react'
|
||||
|
||||
interface ShotcutListProps {
|
||||
shotcuts: IShotcut[]
|
||||
onDelete: (shotcut: IShotcut) => void
|
||||
onEdit: (shotcut: IShotcut) => void
|
||||
}
|
||||
|
||||
export function ShotcutList({ shotcuts, onDelete }: ShotcutListProps) {
|
||||
export function ShotcutList({ shotcuts, onDelete, onEdit }: ShotcutListProps) {
|
||||
const [opened, setOpened] = useState(false)
|
||||
const [selectedShotcut, setSelectedShotcut] = useState<IShotcut | null>(null)
|
||||
|
||||
|
|
@ -58,6 +59,14 @@ export function ShotcutList({ shotcuts, onDelete }: ShotcutListProps) {
|
|||
>
|
||||
<IconTrash size={16} />
|
||||
</ActionIcon>
|
||||
<ActionIcon
|
||||
variant="outline"
|
||||
color="blue"
|
||||
onClick={() => onEdit(shotcut)}
|
||||
title="Edit shortcut"
|
||||
>
|
||||
<IconEdit size={16} />
|
||||
</ActionIcon>
|
||||
</Group>
|
||||
|
||||
{/* Content */}
|
||||
|
|
|
|||
Loading…
Reference in New Issue