diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 21688e9..cebefb1 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,43 +1,43 @@ -name: "🕷️ Bug report" -description: "report bugs" -title: "[Bug]" +name: '🕷️ Bug report' +description: 'report bugs' +title: '[Bug]' labels: - - "bug" + - 'bug' body: -- type: markdown - attributes: - value: "Please make sure to [search for existing issues](https://github.com/lencx/ChatGPT/issues) before filing a new one!" -- type: markdown - attributes: - value: | - ## Bug report - Please fill in the following information to help us reproduce the bug: -- type: input - id: version - attributes: - label: Version - description: "Please specify the version of ChatGPT you are using, a newer version may have fixed the bug you encountered.Check the [UPDATE_LOG](https://github.com/lencx/ChatGPT/blob/main/UPDATE_LOG.md) for more information." - placeholder: "e.g. v0.1.0" - validations: - required: true -- type: textarea - id: bug - attributes: - label: Bug description - description: | - Please describe the bug here,if possible, please provide a minimal example to reproduce the bug.The content of `~/.chatgpt/chatgpt.log` may be helpful if you encounter a crash. - validations: - required: true -- type: input - id: OS - attributes: - label: OS - description: "Please specify the OS you are using." - placeholder: "e.g. Ubuntu 22.04" - validations: - required: true -- type: textarea - id: environment - attributes: - label: Environment - description: "If you think your environment may be related to the problem, please describe it here." + - type: markdown + attributes: + value: 'Please make sure to [search for existing issues](https://github.com/lencx/ChatGPT/issues) before filing a new one!' + - type: markdown + attributes: + value: | + ## Bug report + Please fill in the following information to help us reproduce the bug: + - type: input + id: version + attributes: + label: Version + description: 'Please specify the version of ChatGPT you are using, a newer version may have fixed the bug you encountered.Check the [UPDATE_LOG](https://github.com/lencx/ChatGPT/blob/main/UPDATE_LOG.md) for more information.' + placeholder: 'e.g. v0.1.0' + validations: + required: true + - type: textarea + id: bug + attributes: + label: Bug description + description: | + Please describe the bug here,if possible, please provide a minimal example to reproduce the bug.The content of `~/.chatgpt/chatgpt.log` may be helpful if you encounter a crash. + validations: + required: true + - type: input + id: OS + attributes: + label: OS + description: 'Please specify the OS you are using.' + placeholder: 'e.g. Ubuntu 22.04' + validations: + required: true + - type: textarea + id: environment + attributes: + label: Environment + description: 'If you think your environment may be related to the problem, please describe it here.' diff --git a/.github/ISSUE_TEMPLATE/build_error_report.yml b/.github/ISSUE_TEMPLATE/build_error_report.yml index 7223b20..a2db2fc 100644 --- a/.github/ISSUE_TEMPLATE/build_error_report.yml +++ b/.github/ISSUE_TEMPLATE/build_error_report.yml @@ -1,37 +1,37 @@ -name: "❌ Build error report" -description: "report errors when building by yourself" -title: "[Build Error]" +name: '❌ Build error report' +description: 'report errors when building by yourself' +title: '[Build Error]' labels: - - "build error" + - 'build error' body: -- type: markdown - attributes: - value: "Please make sure to [search for existing issues](https://github.com/lencx/ChatGPT/issues) before filing a new one!" -- type: markdown - attributes: - value: "Please make sure to build from the source code with the latest version of ChatGPT." -- type: markdown - attributes: - value: | - ## Build error report - Please fill in the following information to help us reproduce the bug: -- type: textarea - id: error - attributes: - label: Error message - description: "Please paste the error message here." - validations: - required: true -- type: input - id: OS - attributes: - label: OS - description: "Please specify the OS you are using." - placeholder: "e.g. Ubuntu 22.04" - validations: - required: true -- type: textarea - id: environment - attributes: - label: Environment - description: "If you think your environment may be related to the problem, please describe it here." \ No newline at end of file + - type: markdown + attributes: + value: 'Please make sure to [search for existing issues](https://github.com/lencx/ChatGPT/issues) before filing a new one!' + - type: markdown + attributes: + value: 'Please make sure to build from the source code with the latest version of ChatGPT.' + - type: markdown + attributes: + value: | + ## Build error report + Please fill in the following information to help us reproduce the bug: + - type: textarea + id: error + attributes: + label: Error message + description: 'Please paste the error message here.' + validations: + required: true + - type: input + id: OS + attributes: + label: OS + description: 'Please specify the OS you are using.' + placeholder: 'e.g. Ubuntu 22.04' + validations: + required: true + - type: textarea + id: environment + attributes: + label: Environment + description: 'If you think your environment may be related to the problem, please describe it here.' diff --git a/.github/ISSUE_TEMPLATE/docmentation_issue.yml b/.github/ISSUE_TEMPLATE/docmentation_issue.yml index 6aff586..fc64dbd 100644 --- a/.github/ISSUE_TEMPLATE/docmentation_issue.yml +++ b/.github/ISSUE_TEMPLATE/docmentation_issue.yml @@ -1,19 +1,19 @@ -name: "📚 Documentation Issue" -description: "report documentation issues, typos welcome!" -title: "[Doc]" +name: '📚 Documentation Issue' +description: 'report documentation issues, typos welcome!' +title: '[Doc]' labels: - - "documentation" + - 'documentation' body: -- type: markdown - attributes: - value: "Please make sure to [search for existing issues](https://github.com/lencx/ChatGPT/issues) before creating a new one." -- type: textarea - id: doc-description - attributes: - label: "Provide a description of requested docs changes" - description: "Briefly describe the requested docs changes." - validations: - required: true -- type: markdown - attributes: - value: Please limit one request per issue. \ No newline at end of file + - type: markdown + attributes: + value: 'Please make sure to [search for existing issues](https://github.com/lencx/ChatGPT/issues) before creating a new one.' + - type: textarea + id: doc-description + attributes: + label: 'Provide a description of requested docs changes' + description: 'Briefly describe the requested docs changes.' + validations: + required: true + - type: markdown + attributes: + value: Please limit one request per issue. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 75eca7e..c1f82ed 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,34 +1,34 @@ -name: "⭐ Feature or enhancement request" -description: "suggest new features or enhancements" -title: "[Feature]" +name: '⭐ Feature or enhancement request' +description: 'suggest new features or enhancements' +title: '[Feature]' labels: - - "enhancement" + - 'enhancement' body: -- type: markdown - attributes: - value: "Please make sure to [search for existing issues](https://github.com/lencx/ChatGPT/issues) before creating a new one." -- type: textarea - id: feature-description - attributes: - label: "Feature description" - description: "Describe the feature or enhancements you'd like to see." - validations: - required: true -- type: textarea - id: motivation - attributes: - label: "Motivation" - description: "Describe the motivation for this feature or enhancement." -- type: textarea - id: alternatives - attributes: - label: "Alternatives" - description: "Describe any alternatives you've considered." -- type: textarea - id: additional-context - attributes: - label: "Additional context" - description: "Add any other context or screenshots about the feature request here." -- type: markdown - attributes: - value: Please limit one request per issue. + - type: markdown + attributes: + value: 'Please make sure to [search for existing issues](https://github.com/lencx/ChatGPT/issues) before creating a new one.' + - type: textarea + id: feature-description + attributes: + label: 'Feature description' + description: "Describe the feature or enhancements you'd like to see." + validations: + required: true + - type: textarea + id: motivation + attributes: + label: 'Motivation' + description: 'Describe the motivation for this feature or enhancement.' + - type: textarea + id: alternatives + attributes: + label: 'Alternatives' + description: "Describe any alternatives you've considered." + - type: textarea + id: additional-context + attributes: + label: 'Additional context' + description: 'Add any other context or screenshots about the feature request here.' + - type: markdown + attributes: + value: Please limit one request per issue. diff --git a/.github/ISSUE_TEMPLATE/security.yml b/.github/ISSUE_TEMPLATE/security.yml index 7c0653b..0bb5b56 100644 --- a/.github/ISSUE_TEMPLATE/security.yml +++ b/.github/ISSUE_TEMPLATE/security.yml @@ -1,34 +1,34 @@ -name: "⚠️ Security&Privacy issue" -description: "Report security or privacy issues" -title: "[Security]" +name: '⚠️ Security&Privacy issue' +description: 'Report security or privacy issues' +title: '[Security]' labels: - - "security" + - 'security' body: -- type: markdown - attributes: - value: "Please make sure to [search for existing issues](https://github.com/lencx/ChatGPT/issues) before creating a new one." -- type: textarea - id: security-description - attributes: - label: "Description" - description: "Describe the security or privacy issue." - validations: - required: true -- type: textarea - id: motivation - attributes: - label: "Motivation" - description: "Describe the motivation for this security or privacy issue." -- type: textarea - id: alternatives - attributes: - label: "Alternatives" - description: "Describe any alternatives you've considered." -- type: textarea - id: additional-context - attributes: - label: "Additional context" - description: "Add any other context or screenshots about the security or privacy issue here." -- type: markdown - attributes: - value: Please limit one request per issue. \ No newline at end of file + - type: markdown + attributes: + value: 'Please make sure to [search for existing issues](https://github.com/lencx/ChatGPT/issues) before creating a new one.' + - type: textarea + id: security-description + attributes: + label: 'Description' + description: 'Describe the security or privacy issue.' + validations: + required: true + - type: textarea + id: motivation + attributes: + label: 'Motivation' + description: 'Describe the motivation for this security or privacy issue.' + - type: textarea + id: alternatives + attributes: + label: 'Alternatives' + description: "Describe any alternatives you've considered." + - type: textarea + id: additional-context + attributes: + label: 'Additional context' + description: 'Add any other context or screenshots about the security or privacy issue here.' + - type: markdown + attributes: + value: Please limit one request per issue. diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 9005581..28d01d5 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -28,4 +28,4 @@ jobs: - uses: actions-rs/cargo@v1 with: command: fmt - args: --all -- --check \ No newline at end of file + args: --all -- --check diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..c61b10f --- /dev/null +++ b/.prettierignore @@ -0,0 +1,45 @@ +package-lock.json +node_modules/ +yarn.lock +*.lock + +casks/ + +# rust +src-tauri/ +target/ +Cargo.lock +*.toml + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +assets/** +public/** + +.gitattributes +.gitignore +.prettierignore + +LICENSE \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..c36a279 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "trailingComma": "all", + "singleQuote": true, + "semi": true, + "tabWidth": 2, + "printWidth": 100 +} diff --git a/README-ZH_CN.md b/README-ZH_CN.md index f58c2c2..42b149a 100644 --- a/README-ZH_CN.md +++ b/README-ZH_CN.md @@ -10,6 +10,7 @@ [![ChatGPT downloads](https://img.shields.io/github/downloads/lencx/ChatGPT/total.svg?style=flat-square)](https://github.com/lencx/ChatGPT/releases) [![chat](https://img.shields.io/badge/chat-discord-blue?style=flat&logo=discord)](https://discord.gg/aPhCRf4zZr) [![lencx](https://img.shields.io/badge/follow-lencx__-blue?style=flat&logo=Twitter)](https://twitter.com/lencx_) + Buy Me A Coffee @@ -25,6 +26,7 @@ - [ChatGPT_0.9.2_x64_en-US.msi](https://github.com/lencx/ChatGPT/releases/download/v0.9.2/ChatGPT_0.9.2_x64_en-US.msi): - 使用 [winget](https://winstall.app/apps/lencx.ChatGPT): + ```bash # install the latest version winget install --id=lencx.ChatGPT -e diff --git a/README.md b/README.md index 7bf5fb1..2f008f6 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ [![ChatGPT downloads](https://img.shields.io/github/downloads/lencx/ChatGPT/total.svg?style=flat-square)](https://github.com/lencx/ChatGPT/releases) [![chat](https://img.shields.io/badge/chat-discord-blue?style=flat&logo=discord)](https://discord.gg/aPhCRf4zZr) [![lencx](https://img.shields.io/badge/follow-lencx__-blue?style=flat&logo=Twitter)](https://twitter.com/lencx_) + @@ -27,6 +28,7 @@ - [ChatGPT_0.9.2_x64_en-US.msi](https://github.com/lencx/ChatGPT/releases/download/v0.9.2/ChatGPT_0.9.2_x64_en-US.msi): Direct download installer - Use [winget](https://winstall.app/apps/lencx.ChatGPT): + ```bash # install the latest version winget install --id=lencx.ChatGPT -e @@ -174,6 +176,7 @@ Currently, only json and csv are supported for synchronizing custom files, and t ## 📌 TODO + - `Control Center` enhancement - `Pop-up Search` enhancement - ... diff --git a/UPDATE_LOG.md b/UPDATE_LOG.md index fd708c1..191a5ce 100644 --- a/UPDATE_LOG.md +++ b/UPDATE_LOG.md @@ -11,15 +11,18 @@ fix: slash command does not work ## v0.9.0 fix: + - export button does not work feat: + - add an export markdown button - `Control Center` adds `Notes` and `Download` menus for managing exported chat files (Markdown, PNG, PDF). `Notes` supports markdown previews. ## v0.8.1 fix: + - export button keeps blinking - export button in the old chat does not work - disable export sharing links because it is a security risk @@ -27,22 +30,26 @@ fix: ## v0.8.0 feat: + - theme enhancement (Light, Dark, System) - automatic updates support `silent` settings - pop-up search: select the ChatGPT content with the mouse, the `DALL·E 2` button appears, and click to jump (note: because the search content filled by the script cannot trigger the event directly, you need to enter a space in the input box to make the button clickable). fix: + - close the main window and hide it in the tray (windows systems) ## v0.7.4 fix: + - trying to resolve linux errors: `error while loading shared libraries` - customize global shortcuts (`Menu -> Preferences -> Control Center -> General -> Global Shortcut`) ## v0.7.3 chore: + - optimize slash command style - optimize tray menu icon and button icons - global shortcuts to the chatgpt app (mac: `Command + Shift + O`, windows: `Ctrl + Shift + O`) @@ -54,6 +61,7 @@ fix: some windows systems cannot start the application ## v0.7.1 fix: + - some windows systems cannot start the application - windows and linux add about menu (show version information) - the tray icon is indistinguishable from the background in dark mode on window and linux @@ -61,10 +69,12 @@ fix: ## v0.7.0 fix: + - mac m1 copy/paste does not work on some system versions - optimize the save chat log button to a small icon, the tray window no longer provides a save chat log button (the buttons causes the input area to become larger and the content area to become smaller) feat: + - use the keyboard `⇧` (arrow up) and `⇩` (arrow down) keys to select the slash command @@ -77,6 +87,7 @@ fix: sync failure on windows fix: path not allowed on the configured scope feat: + - optimize the generated pdf file size - menu added `Sync Prompts` - `Control Center` added `Sync Custom` @@ -86,6 +97,7 @@ feat: ## v0.6.0 fix: + - windows show Chinese when upgrading ## v0.5.1 @@ -103,11 +115,13 @@ add chatgpt log (path: `~/.chatgpt/chatgpt.log`) ## v0.4.1 fix: + - tray window style optimization ## v0.4.0 feat: + - customize the ChatGPT prompts command (https://github.com/lencx/ChatGPT#-announcement) - menu enhancement: hide application icons from the Dock (support macOS only) @@ -116,12 +130,14 @@ feat: fix: can't open ChatGPT feat: menu enhancement + - the control center of ChatGPT application - open the configuration file directory ## v0.2.2 feat: + - menu: go to config ## v0.2.1 @@ -131,12 +147,14 @@ feat: menu optimization ## v0.2.0 feat: menu enhancement + - customize user-agent to prevent security detection interception - clear all chatgpt configuration files ## v0.1.8 feat: + - menu enhancement: theme, titlebar - modify website address @@ -147,6 +165,7 @@ feat: tray window ## v0.1.6 feat: + - stay on top - export ChatGPT history @@ -157,6 +176,7 @@ fix: mac can't use shortcut keys ## v0.1.4 feat: + - beautify icons - add system tray menu diff --git a/package.json b/package.json index de5c24d..8c52719 100644 --- a/package.json +++ b/package.json @@ -12,8 +12,11 @@ "fix:tray": "tr override --json.tauri_systemTray_iconPath=\"icons/tray-icon-light.png\" --json.tauri_systemTray_iconAsTemplate=false", "fix:tray:mac": "tr override --json.tauri_systemTray_iconPath=\"icons/tray-icon.png\" --json.tauri_systemTray_iconAsTemplate=true", "download": "node ./scripts/download.js", + "fmt:rs": "cargo fmt", "tr": "tr", - "tauri": "tauri" + "tauri": "tauri", + "prettier": "prettier -c --write '**/*'", + "pretty-quick": "pretty-quick" }, "license": "MIT", "author": "lencx ", @@ -32,6 +35,11 @@ "type": "git", "url": "https://github.com/lencx/ChatGPT" }, + "husky": { + "hooks": { + "pre-commit": "pretty-quick --staged" + } + }, "dependencies": { "@ant-design/icons": "^4.8.0", "@monaco-editor/react": "^4.4.6", @@ -59,6 +67,9 @@ "@types/react-syntax-highlighter": "^15.5.6", "@types/uuid": "^9.0.0", "@vitejs/plugin-react": "^3.0.0", + "husky": "^8.0.3", + "prettier": "^2.8.3", + "pretty-quick": "^3.1.3", "sass": "^1.56.2", "typescript": "^4.9.4", "vite": "^4.0.0", diff --git a/scripts/download.js b/scripts/download.js index 86a55fe..517ff8e 100644 --- a/scripts/download.js +++ b/scripts/download.js @@ -30,4 +30,4 @@ async function init() { rewrite('README-ZH_CN.md'); } -init().catch(console.error); \ No newline at end of file +init().catch(console.error); diff --git a/src/components/FilePath/index.tsx b/src/components/FilePath/index.tsx index 8976710..1b9cd09 100644 --- a/src/components/FilePath/index.tsx +++ b/src/components/FilePath/index.tsx @@ -22,15 +22,20 @@ const FilePath: FC = ({ className, label = 'PATH', paths = '', ur setPath(url); return; } - setPath(await path.join(await chatRoot(), ...paths.split('/').filter(i => !!i))); - })() - }, [url, paths]) + setPath(await path.join(await chatRoot(), ...paths.split('/').filter((i) => !!i))); + })(); + }, [url, paths]); return (
-
{label}: shell.open(filePath)} title={filePath}>{content ? content : filePath}
+
+ {label}:{' '} + shell.open(filePath)} title={filePath}> + {content ? content : filePath} + +
); -} +}; -export default FilePath; \ No newline at end of file +export default FilePath; diff --git a/src/components/Markdown/Editor.tsx b/src/components/Markdown/Editor.tsx index 22fe339..8b36319 100644 --- a/src/components/Markdown/Editor.tsx +++ b/src/components/Markdown/Editor.tsx @@ -1,5 +1,5 @@ import { FC, useEffect, useState } from 'react'; -import Editor from "@monaco-editor/react"; +import Editor from '@monaco-editor/react'; import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels'; import Markdown from '@/components/Markdown'; @@ -17,12 +17,12 @@ const MarkdownEditor: FC = ({ value = '', onChange, mode = useEffect(() => { setContent(value); onChange && onChange(value); - }, [value]) + }, [value]); const handleEdit = (e: any) => { setContent(e); onChange && onChange(e); - } + }; const isSplit = mode === 'split'; @@ -31,11 +31,7 @@ const MarkdownEditor: FC = ({ value = '', onChange, mode = {['md', 'split'].includes(mode) && ( - + )} {isSplit && } @@ -44,9 +40,9 @@ const MarkdownEditor: FC = ({ value = '', onChange, mode = {content} )} - + - ) + ); }; -export default MarkdownEditor; \ No newline at end of file +export default MarkdownEditor; diff --git a/src/components/Markdown/index.scss b/src/components/Markdown/index.scss index 033bd36..5c0bc57 100644 --- a/src/components/Markdown/index.scss +++ b/src/components/Markdown/index.scss @@ -1,15 +1,16 @@ .markdown-body { height: 100%; overflow: auto; - font-family: -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"; - + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, + sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji'; &.edit-preview { padding: 10px; font-size: 14px; } - pre, code { + pre, + code { font-family: monospace, monospace; } } diff --git a/src/components/Markdown/index.tsx b/src/components/Markdown/index.tsx index a548cc6..7277ebf 100644 --- a/src/components/Markdown/index.tsx +++ b/src/components/Markdown/index.tsx @@ -13,7 +13,6 @@ interface MarkdownProps { } const Markdown: FC = ({ children, className }) => { - return (
@@ -22,8 +21,8 @@ const Markdown: FC = ({ children, className }) => { linkTarget="_blank" remarkPlugins={[remarkGfm]} components={{ - code({node, inline, className, children, ...props}) { - const match = /language-(\w+)/.exec(className || '') + code({ node, inline, className, children, ...props }) { + const match = /language-(\w+)/.exec(className || ''); return !inline && match ? ( = ({ children, className }) => { {children} - ) - } + ); + }, }} />
- ) -} + ); +}; -export default Markdown; \ No newline at end of file +export default Markdown; diff --git a/src/components/Tags/index.tsx b/src/components/Tags/index.tsx index dd349e4..09218d9 100644 --- a/src/components/Tags/index.tsx +++ b/src/components/Tags/index.tsx @@ -20,7 +20,7 @@ const Tags: FC = ({ max = 99, value = [], onChange, addTxt = 'New Tag useEffect(() => { setTags(value); - }, [value]) + }, [value]); useEffect(() => { if (inputVisible) { @@ -97,4 +97,4 @@ const Tags: FC = ({ max = 99, value = [], onChange, addTxt = 'New Tag ); }; -export default Tags; \ No newline at end of file +export default Tags; diff --git a/src/hooks/useChatModel.ts b/src/hooks/useChatModel.ts index 980fe1c..837cce5 100644 --- a/src/hooks/useChatModel.ts +++ b/src/hooks/useChatModel.ts @@ -15,12 +15,12 @@ export default function useChatModel(key: string, file = CHAT_MODEL_JSON) { setModelJson(data); }); - const modelSet = async (data: Record[]|Record) => { + const modelSet = async (data: Record[] | Record) => { const oData = clone(modelJson); oData[key] = data; await writeJSON(file, oData); setModelJson(oData); - } + }; return { modelJson, modelSet, modelData: modelJson?.[key] || [] }; } @@ -40,15 +40,19 @@ export function useCacheModel(file = '') { await writeJSON(newFile ? newFile : file, data, { isRoot: true }); setModelCacheJson(data); await modelCacheCmd(); - } + }; const modelCacheCmd = async () => { // Generate the `chat.model.cmd.json` file and refresh the page for the slash command to take effect. const list = await invoke('cmd_list'); - await writeJSON(CHAT_MODEL_CMD_JSON, { name: 'ChatGPT CMD', last_updated: Date.now(), data: list }); + await writeJSON(CHAT_MODEL_CMD_JSON, { + name: 'ChatGPT CMD', + last_updated: Date.now(), + data: list, + }); await invoke('window_reload', { label: 'core' }); await invoke('window_reload', { label: 'tray' }); }; return { modelCacheJson, modelCacheSet, modelCacheCmd }; -} \ No newline at end of file +} diff --git a/src/hooks/useColumns.tsx b/src/hooks/useColumns.tsx index d5562ff..ab55762 100644 --- a/src/hooks/useColumns.tsx +++ b/src/hooks/useColumns.tsx @@ -5,7 +5,7 @@ import { DISABLE_AUTO_COMPLETE } from '@/utils'; export default function useColumns(columns: any[] = []) { const [opType, setOpType] = useState(''); - const [opRecord, setRecord] = useState | null>(null); + const [opRecord, setRecord] = useState | null>(null); const [opTime, setNow] = useState(null); const [opExtra, setExtra] = useState(null); @@ -58,26 +58,26 @@ export const EditRow: FC = ({ rowKey, row, actions }) => { setEdit(true); }; const handleChange = (e: React.ChangeEvent) => { - setVal(e.target.value) + setVal(e.target.value); }; const handleSave = () => { setEdit(false); row[rowKey] = val?.trim(); - actions?.setRecord(row, 'rowedit') + actions?.setRecord(row, 'rowedit'); }; - return isEdit - ? ( - - ) - : ( -
{val}
- ); + return isEdit ? ( + + ) : ( +
+ {val} +
+ ); }; diff --git a/src/hooks/useData.ts b/src/hooks/useData.ts index 86cf9fa..de82cce 100644 --- a/src/hooks/useData.ts +++ b/src/hooks/useData.ts @@ -8,7 +8,7 @@ export default function useData(oData: any[]) { useEffect(() => { opInit(oData); - }, []) + }, []); const opAdd = (val: any) => { const v = [val, ...opData]; @@ -18,19 +18,19 @@ export default function useData(oData: any[]) { const opInit = (val: any[] = []) => { if (!val || !Array.isArray(val)) return; - const nData = val.map(i => ({ [safeKey]: v4(), ...i })); + const nData = val.map((i) => ({ [safeKey]: v4(), ...i })); setData(nData); }; const opRemove = (id: string) => { - const nData = opData.filter(i => i[safeKey] !== id); + const nData = opData.filter((i) => i[safeKey] !== id); setData(nData); return nData; }; const opReplace = (id: string, data: any) => { const nData = [...opData]; - const idx = opData.findIndex(v => v[safeKey] === id); + const idx = opData.findIndex((v) => v[safeKey] === id); nData[idx] = data; setData(nData); return nData; @@ -52,4 +52,4 @@ export default function useData(oData: any[]) { }; return { opSafeKey: safeKey, opInit, opReplace, opAdd, opRemove, opData, opReplaceItems }; -} \ No newline at end of file +} diff --git a/src/hooks/useInit.ts b/src/hooks/useInit.ts index b5438ad..aa58b53 100644 --- a/src/hooks/useInit.ts +++ b/src/hooks/useInit.ts @@ -8,5 +8,5 @@ export default function useInit(callback: () => void) { callback(); isInit.current = false; } - }) -} \ No newline at end of file + }); +} diff --git a/src/hooks/useTable.tsx b/src/hooks/useTable.tsx index 4fc2c65..9469318 100644 --- a/src/hooks/useTable.tsx +++ b/src/hooks/useTable.tsx @@ -7,14 +7,17 @@ import { safeKey } from '@/hooks/useData'; type rowSelectionOptions = { key: 'id' | string; rowType: 'id' | 'row' | 'all'; -} +}; export function useTableRowSelection(options: Partial = {}) { const { key = 'id', rowType = 'id' } = options; const [selectedRowKeys, setSelectedRowKeys] = useState([]); const [selectedRowIDs, setSelectedRowIDs] = useState([]); - const [selectedRows, setSelectedRows] = useState[]>([]); + const [selectedRows, setSelectedRows] = useState[]>([]); - const onSelectChange = (newSelectedRowKeys: React.Key[], newSelectedRows: Record[]) => { + const onSelectChange = ( + newSelectedRowKeys: React.Key[], + newSelectedRows: Record[], + ) => { const keys = newSelectedRows.map((i: any) => i[safeKey] || i[key]); setSelectedRowKeys(newSelectedRowKeys); if (rowType === 'id') { @@ -38,11 +41,7 @@ export function useTableRowSelection(options: Partial = {}) const rowSelection: TableRowSelection> = { selectedRowKeys, onChange: onSelectChange, - selections: [ - Table.SELECTION_ALL, - Table.SELECTION_INVERT, - Table.SELECTION_NONE, - ], + selections: [Table.SELECTION_ALL, Table.SELECTION_INVERT, Table.SELECTION_NONE], }; return { rowSelection, selectedRowIDs, selectedRows, rowReset }; @@ -55,4 +54,4 @@ export const TABLE_PAGINATION = { defaultPageSize: 10, pageSizeOptions: [5, 10, 15, 20], showTotal: (total: number) => Total {total} items, -}; \ No newline at end of file +}; diff --git a/src/icons/SplitIcon.tsx b/src/icons/SplitIcon.tsx index 4192674..e53bf9a 100644 --- a/src/icons/SplitIcon.tsx +++ b/src/icons/SplitIcon.tsx @@ -1,4 +1,4 @@ -import Icon from "@ant-design/icons"; +import Icon from '@ant-design/icons'; import type { CustomIconComponentProps } from '@ant-design/icons/lib/components/Icon'; interface IconProps { @@ -6,12 +6,20 @@ interface IconProps { } export default function SplitIcon(props: Partial) { - return ( - - - - )} - /> + return ( + ( + + + + )} + /> + ); } diff --git a/src/layout/index.scss b/src/layout/index.scss index 07d5cf5..a908db5 100644 --- a/src/layout/index.scss +++ b/src/layout/index.scss @@ -36,4 +36,4 @@ .ant-layout-footer { color: #666 !important; opacity: 0.7; -} \ No newline at end of file +} diff --git a/src/layout/index.tsx b/src/layout/index.tsx index e100e9b..eb027ba 100644 --- a/src/layout/index.tsx +++ b/src/layout/index.tsx @@ -21,21 +21,21 @@ export default function ChatLayout() { setAppInfo({ appName: await getName(), appVersion: await getVersion(), - appTheme: await invoke("get_theme"), + appTheme: await invoke('get_theme'), }); - }) + }); const checkAppUpdate = async () => { await invoke('run_check_update', { silent: false, hasMsg: true }); - } + }; - const isDark = appInfo.appTheme === "dark"; + const isDark = appInfo.appTheme === 'dark'; return ( setCollapsed(value)} @@ -49,41 +49,51 @@ export default function ChatLayout() { zIndex: 999, }} > -
+
+ +
{appInfo.appName} - {appInfo.appVersion} - - - + {appInfo.appVersion} + + + + +
go(i.key)} /> - + ); -}; \ No newline at end of file +} diff --git a/src/main.scss b/src/main.scss index 8bf3c9f..4f530ad 100644 --- a/src/main.scss +++ b/src/main.scss @@ -14,7 +14,8 @@ -webkit-text-size-adjust: 100%; } -html, body { +html, +body { padding: 0; margin: 0; } @@ -100,4 +101,4 @@ html, body { .chatico { cursor: pointer; -} \ No newline at end of file +} diff --git a/src/main.tsx b/src/main.tsx index 488f0cd..3dad92c 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -9,8 +9,8 @@ ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( - + - + , ); diff --git a/src/routes.tsx b/src/routes.tsx index e38d38a..3ce6080 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -23,7 +23,7 @@ import Markdown from '@/view/markdown'; export type ChatRouteMetaObject = { label: string; - icon?: React.ReactNode, + icon?: React.ReactNode; }; type ChatRouteObject = { @@ -32,7 +32,7 @@ type ChatRouteObject = { hideMenu?: boolean; meta?: ChatRouteMetaObject; children?: ChatRouteObject[]; -} +}; export const routes: Array = [ { @@ -116,14 +116,14 @@ export const routes: Array = [ type MenuItem = Required['items'][number]; export const menuItems: MenuItem[] = routes .filter((j) => !j.hideMenu) - .map(i => ({ + .map((i) => ({ ...i.meta, key: i.path || '', children: i?.children ?.filter((j) => !j.hideMenu) - ?.map((j) => ({ ...j.meta, key: `${i.path}/${j.path}` || ''})), + ?.map((j) => ({ ...j.meta, key: `${i.path}/${j.path}` || '' })), })); export default () => { return useRoutes(routes); -}; \ No newline at end of file +}; diff --git a/src/utils.ts b/src/utils.ts index c65f117..e5b2451 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -9,27 +9,28 @@ export const CHAT_DOWNLOAD_JSON = 'chat.download.json'; export const CHAT_AWESOME_JSON = 'chat.awesome.json'; export const CHAT_NOTES_JSON = 'chat.notes.json'; export const CHAT_PROMPTS_CSV = 'chat.prompts.csv'; -export const GITHUB_PROMPTS_CSV_URL = 'https://raw.githubusercontent.com/f/awesome-chatgpt-prompts/main/prompts.csv'; +export const GITHUB_PROMPTS_CSV_URL = + 'https://raw.githubusercontent.com/f/awesome-chatgpt-prompts/main/prompts.csv'; export const DISABLE_AUTO_COMPLETE = { autoCapitalize: 'off', autoComplete: 'off', - spellCheck: false + spellCheck: false, }; export const chatRoot = async () => { - return join(await homeDir(), '.chatgpt') -} + return join(await homeDir(), '.chatgpt'); +}; export const chatModelPath = async (): Promise => { return join(await chatRoot(), CHAT_MODEL_JSON); -} +}; export const chatPromptsPath = async (): Promise => { return join(await chatRoot(), CHAT_PROMPTS_CSV); -} +}; -type readJSONOpts = { defaultVal?: Record, isRoot?: boolean, isList?: boolean }; +type readJSONOpts = { defaultVal?: Record; isRoot?: boolean; isList?: boolean }; export const readJSON = async (path: string, opts: readJSONOpts = {}) => { const { defaultVal = {}, isRoot = false, isList = false } = opts; const root = await chatRoot(); @@ -39,26 +40,39 @@ export const readJSON = async (path: string, opts: readJSONOpts = {}) => { file = await join(root, path); } - if (!await exists(file)) { - if (await dirname(file) !== root) { + if (!(await exists(file))) { + if ((await dirname(file)) !== root) { await createDir(await dirname(file), { recursive: true }); } - await writeTextFile(file, isList ? '[]' : JSON.stringify({ - name: 'ChatGPT', - link: 'https://github.com/lencx/ChatGPT', - ...defaultVal, - }, null, 2)) + await writeTextFile( + file, + isList + ? '[]' + : JSON.stringify( + { + name: 'ChatGPT', + link: 'https://github.com/lencx/ChatGPT', + ...defaultVal, + }, + null, + 2, + ), + ); } try { return JSON.parse(await readTextFile(file)); - } catch(e) { + } catch (e) { return {}; } -} +}; -type writeJSONOpts = { dir?: string, isRoot?: boolean }; -export const writeJSON = async (path: string, data: Record, opts: writeJSONOpts = {}) => { +type writeJSONOpts = { dir?: string; isRoot?: boolean }; +export const writeJSON = async ( + path: string, + data: Record, + opts: writeJSONOpts = {}, +) => { const { isRoot = false } = opts; const root = await chatRoot(); let file = path; @@ -67,13 +81,17 @@ export const writeJSON = async (path: string, data: Record, opts: w file = await join(root, path); } - if (isRoot && !await exists(await dirname(file))) { + if (isRoot && !(await exists(await dirname(file)))) { await createDir(await dirname(file), { recursive: true }); } await writeTextFile(file, JSON.stringify(data, null, 2)); -} +}; export const fmtDate = (date: any) => dayjs(date).format('YYYY-MM-DD HH:mm:ss'); -export const genCmd = (act: string) => act.replace(/\s+|\/+/g, '_').replace(/[^\d\w]/g, '').toLocaleLowerCase(); \ No newline at end of file +export const genCmd = (act: string) => + act + .replace(/\s+|\/+/g, '_') + .replace(/[^\d\w]/g, '') + .toLocaleLowerCase(); diff --git a/src/view/awesome/Form.tsx b/src/view/awesome/Form.tsx index aa55668..89054ce 100644 --- a/src/view/awesome/Form.tsx +++ b/src/view/awesome/Form.tsx @@ -6,7 +6,7 @@ import Tags from '@comps/Tags'; import { DISABLE_AUTO_COMPLETE } from '@/utils'; interface AwesomeFormProps { - record?: Record | null; + record?: Record | null; } const initFormValue = { @@ -28,11 +28,7 @@ const AwesomeForm: ForwardRefRenderFunction = ({ re }, [record]); return ( -
+ = ({ re
- ) -} + ); +}; export default forwardRef(AwesomeForm); diff --git a/src/view/awesome/config.tsx b/src/view/awesome/config.tsx index 4e27247..8556a3b 100644 --- a/src/view/awesome/config.tsx +++ b/src/view/awesome/config.tsx @@ -34,7 +34,7 @@ export const awesomeColumns = () => [ dataIndex: 'category', key: 'category', width: 120, - render: (v: string) => {v} + render: (v: string) => {v}, }, { title: 'Tags', @@ -42,7 +42,11 @@ export const awesomeColumns = () => [ key: 'tags', width: 150, render: (v: string[]) => ( - {v?.map(i => {i})} + + {v?.map((i) => ( + {i} + ))} + ), }, { @@ -62,7 +66,7 @@ export const awesomeColumns = () => [ Delete - ) - } - } + ); + }, + }, ]; diff --git a/src/view/awesome/index.tsx b/src/view/awesome/index.tsx index 1660d98..6752625 100644 --- a/src/view/awesome/index.tsx +++ b/src/view/awesome/index.tsx @@ -34,7 +34,8 @@ export default function Awesome() { updateJson(data); opInfo.resetRecord(); } - }, [opInfo.opType, formRef]); + }, [opInfo.opType, + formRef]); const hide = () => { setVisible(false); @@ -46,45 +47,46 @@ export default function Awesome() { const data = opReplace(opInfo?.opRecord?.[opSafeKey], opInfo?.opRecord); updateJson(data); } - }, [opInfo.opTime]) + }, [opInfo.opTime]); - const handleDelete = () => { - - }; + const handleDelete = () => {}; const handleOk = () => { - formRef.current?.form?.validateFields() - .then(async (vals: Record) => { - if (opInfo.opType === 'new') { - const data = opAdd(vals); - await updateJson(data); - opInit(data); - message.success('Data added successfully'); - } - if (opInfo.opType === 'edit') { - const data = opReplace(opInfo?.opRecord?.[opSafeKey], vals); - await updateJson(data); - message.success('Data updated successfully'); - } - hide(); - }) + formRef.current?.form?.validateFields().then(async (vals: Record) => { + if (opInfo.opType === 'new') { + const data = opAdd(vals); + await updateJson(data); + opInit(data); + message.success('Data added successfully'); + } + if (opInfo.opType === 'edit') { + const data = opReplace(opInfo?.opRecord?.[opSafeKey], vals); + await updateJson(data); + message.success('Data updated successfully'); + } + hide(); + }); }; const handleEnable = (isEnable: boolean) => { - const data = opReplaceItems(selectedRowIDs, { enable: isEnable }) + const data = opReplaceItems(selectedRowIDs, { enable: isEnable }); updateJson(data); }; - const modalTitle = `${({ new: 'Create', edit: 'Edit' })[opInfo.opType]} URL`; + const modalTitle = `${{ new: 'Create', edit: 'Edit' }[opInfo.opType]} URL`; return (
- +
{selectedItems.length > 0 && ( <> - +
- ) -} \ No newline at end of file + ); +} diff --git a/src/view/download/config.tsx b/src/view/download/config.tsx index 274c208..4f42bb9 100644 --- a/src/view/download/config.tsx +++ b/src/view/download/config.tsx @@ -10,7 +10,7 @@ import { fmtDate, chatRoot } from '@/utils'; const colorMap: any = { pdf: 'blue', png: 'orange', -} +}; export const downloadColumns = () => [ { @@ -61,20 +61,22 @@ export const downloadColumns = () => [ Delete - ) - } - } + ); + }, + }, ]; const RenderPath = ({ row }: any) => { const [filePath, setFilePath] = useState(''); useInit(async () => { - setFilePath(await getPath(row)); - }) + setFilePath(await getPath(row)); + }); return shell.open(filePath)}>{filePath}; }; export const getPath = async (row: any) => { const isImg = ['png'].includes(row?.ext); - return await path.join(await chatRoot(), 'download', isImg ? 'img' : row.ext, row.id) + `.${row.ext}`; -} + return ( + (await path.join(await chatRoot(), 'download', isImg ? 'img' : row.ext, row.id)) + `.${row.ext}` + ); +}; diff --git a/src/view/download/index.tsx b/src/view/download/index.tsx index 4192651..5684993 100644 --- a/src/view/download/index.tsx +++ b/src/view/download/index.tsx @@ -37,7 +37,12 @@ export default function Download() { (async () => { const record = opInfo?.opRecord; const isImg = ['png'].includes(record?.ext); - const file = await path.join(await chatRoot(), 'download', isImg ? 'img' : record?.ext, `${record?.id}.${record?.ext}`); + const file = await path.join( + await chatRoot(), + 'download', + isImg ? 'img' : record?.ext, + `${record?.id}.${record?.ext}`, + ); if (opInfo.opType === 'preview') { const data = await fs.readBinaryFile(file); const sourceData = renderFile(data, record?.ext); @@ -55,8 +60,8 @@ export default function Download() { message.success('Name has been changed!'); } opInfo.resetRecord(); - })() - }, [opInfo.opType]) + })(); + }, [opInfo.opType]); const handleDelete = async () => { if (opData?.length === selectedRows.length) { @@ -69,10 +74,15 @@ export default function Download() { const rows = selectedRows.map(async (i) => { const isImg = ['png'].includes(i?.ext); - const file = await path.join(await chatRoot(), 'download', isImg ? 'img' : i?.ext, `${i?.id}.${i?.ext}`); + const file = await path.join( + await chatRoot(), + 'download', + isImg ? 'img' : i?.ext, + `${i?.id}.${i?.ext}`, + ); await fs.removeFile(file); return file; - }) + }); Promise.all(rows).then(async () => { await handleRefresh(); message.success('All files selected are cleared!'); @@ -131,5 +141,5 @@ export default function Download() {
- ) -} \ No newline at end of file + ); +} diff --git a/src/view/markdown/index.scss b/src/view/markdown/index.scss index 71f7cc5..964eb74 100644 --- a/src/view/markdown/index.scss +++ b/src/view/markdown/index.scss @@ -1,4 +1,3 @@ - .md-task { margin-bottom: 5px; display: flex; @@ -14,4 +13,4 @@ cursor: pointer; } } -} \ No newline at end of file +} diff --git a/src/view/markdown/index.tsx b/src/view/markdown/index.tsx index 088dd9b..292c7e2 100644 --- a/src/view/markdown/index.tsx +++ b/src/view/markdown/index.tsx @@ -14,7 +14,7 @@ const modeMap: any = { 0: 'split', 1: 'md', 2: 'doc', -} +}; export default function Markdown() { const [filePath, setFilePath] = useState(''); @@ -26,8 +26,8 @@ export default function Markdown() { useInit(async () => { const file = await getPath(state); setFilePath(file); - setSource(await fs.readTextFile(file)) - }) + setSource(await fs.readTextFile(file)); + }); const handleChange = async (v: string) => { await fs.writeTextFile(filePath, v); @@ -46,9 +46,7 @@ export default function Markdown() { history.go(-1)}> - shell.open(filePath)}> - {filePath} - + shell.open(filePath)}>{filePath}
@@ -57,4 +55,4 @@ export default function Markdown() { ); -} \ No newline at end of file +} diff --git a/src/view/model/SyncCustom/Form.tsx b/src/view/model/SyncCustom/Form.tsx index fbf3e3a..9166643 100644 --- a/src/view/model/SyncCustom/Form.tsx +++ b/src/view/model/SyncCustom/Form.tsx @@ -1,4 +1,10 @@ -import { useEffect, useState, ForwardRefRenderFunction, useImperativeHandle, forwardRef } from 'react'; +import { + useEffect, + useState, + ForwardRefRenderFunction, + useImperativeHandle, + forwardRef, +} from 'react'; import { Form, Input, Select, Tooltip } from 'antd'; import { v4 } from 'uuid'; import type { FormProps } from 'antd'; @@ -7,7 +13,7 @@ import { DISABLE_AUTO_COMPLETE, chatRoot } from '@/utils'; import useInit from '@/hooks/useInit'; interface SyncFormProps { - record?: Record | null; + record?: Record | null; type: string; } @@ -54,10 +60,18 @@ const SyncForm: ForwardRefRenderFunction = ({ record, const jsonTip = ( {JSON.stringify([ - { cmd: '', act: '', prompt: '' }, - { cmd: '', act: '', prompt: '' }, - ], null, 2)}} + title={ +
+          {JSON.stringify(
+            [
+              { cmd: '', act: '', prompt: '' },
+              { cmd: '', act: '', prompt: '' },
+            ],
+            null,
+            2,
+          )}
+        
+ } > JSON
@@ -65,10 +79,12 @@ const SyncForm: ForwardRefRenderFunction = ({ record, const csvTip = ( {`"cmd","act","prompt" + title={ +
{`"cmd","act","prompt"
 "cmd","act","prompt"
 "cmd","act","prompt"
-"cmd","act","prompt"`}
} +"cmd","act","prompt"`} + } > CSV
@@ -76,11 +92,7 @@ const SyncForm: ForwardRefRenderFunction = ({ record, return ( <> -
+ = ({ record, label="PATH" name="path" rules={[{ required: true, message: 'Please enter the path!' }]} - > + > = ({ record, {...DISABLE_AUTO_COMPLETE} /> - + + +
-

The file supports only {csvTip} and {jsonTip} formats.

+

+ The file supports only {csvTip} and {jsonTip} formats. +

- ) -} + ); +}; export default forwardRef(SyncForm); diff --git a/src/view/model/SyncCustom/config.tsx b/src/view/model/SyncCustom/config.tsx index d491cfc..bb3721c 100644 --- a/src/view/model/SyncCustom/config.tsx +++ b/src/view/model/SyncCustom/config.tsx @@ -26,7 +26,7 @@ export const syncColumns = () => [ dataIndex: 'path', key: 'path', width: 180, - render: (_: string, row: any) => + render: (_: string, row: any) => , }, { title: 'Last updated', @@ -36,7 +36,7 @@ export const syncColumns = () => [ render: (v: number) => (
- { v ? fmtDate(v) : ''} + {v ? fmtDate(v) : ''}
), }, @@ -56,7 +56,11 @@ export const syncColumns = () => [ > Sync - {row.last_updated && View} + {row.last_updated && ( + + View + + )} actions.setRecord(row, 'edit')}>Edit [ Delete - ) - } - } + ); + }, + }, ]; const RenderPath = ({ row }: any) => { const [filePath, setFilePath] = useState(''); useInit(async () => { - setFilePath(await getPath(row)); - }) - return shell.open(filePath)}>{filePath} + setFilePath(await getPath(row)); + }); + return shell.open(filePath)}>{filePath}; }; export const getPath = async (row: any) => { if (!/^http/.test(row.protocol)) { - return await path.join(await chatRoot(), row.path) + `.${row.ext}`; + return (await path.join(await chatRoot(), row.path)) + `.${row.ext}`; } else { return `${row.protocol}://${row.path}.${row.ext}`; } -} \ No newline at end of file +}; diff --git a/src/view/model/SyncCustom/index.tsx b/src/view/model/SyncCustom/index.tsx index 0ee3767..fec29cb 100644 --- a/src/view/model/SyncCustom/index.tsx +++ b/src/view/model/SyncCustom/index.tsx @@ -10,7 +10,13 @@ import { CHAT_MODEL_JSON, chatRoot, readJSON, genCmd } from '@/utils'; import { syncColumns, getPath } from './config'; import SyncForm from './Form'; -const fmtData = (data: Record[] = []) => (Array.isArray(data) ? data : []).map((i) => ({ ...i, cmd: i.cmd ? i.cmd : genCmd(i.act), tags: ['user-sync'], enable: true })); +const fmtData = (data: Record[] = []) => + (Array.isArray(data) ? data : []).map((i) => ({ + ...i, + cmd: i.cmd ? i.cmd : genCmd(i.act), + tags: ['user-sync'], + enable: true, + })); export default function SyncCustom() { const [isVisible, setVisible] = useState(false); @@ -37,7 +43,10 @@ export default function SyncCustom() { handleSync(filename).then((isOk: boolean) => { opInfo.resetRecord(); if (!isOk) return; - const data = opReplace(opInfo?.opRecord?.[opSafeKey], { ...opInfo?.opRecord, last_updated: Date.now() }); + const data = opReplace(opInfo?.opRecord?.[opSafeKey], { + ...opInfo?.opRecord, + last_updated: Date.now(), + }); modelSet(data); opInfo.resetRecord(); }); @@ -48,9 +57,13 @@ export default function SyncCustom() { if (['delete'].includes(opInfo.opType)) { (async () => { try { - const file = await path.join(await chatRoot(), 'cache_model', `${opInfo?.opRecord?.id}.json`); + const file = await path.join( + await chatRoot(), + 'cache_model', + `${opInfo?.opRecord?.id}.json`, + ); await fs.removeFile(file); - } catch(e) {} + } catch (e) {} const data = opRemove(opInfo?.opRecord?.[opSafeKey]); modelSet(data); opInfo.resetRecord(); @@ -94,29 +107,24 @@ export default function SyncCustom() { }; const handleOk = () => { - formRef.current?.form?.validateFields() - .then((vals: Record) => { - if (opInfo.opType === 'new') { - const data = opAdd(vals); - modelSet(data); - message.success('Data added successfully'); - } - if (opInfo.opType === 'edit') { - const data = opReplace(opInfo?.opRecord?.[opSafeKey], vals); - modelSet(data); - message.success('Data updated successfully'); - } - hide(); - }) + formRef.current?.form?.validateFields().then((vals: Record) => { + if (opInfo.opType === 'new') { + const data = opAdd(vals); + modelSet(data); + message.success('Data added successfully'); + } + if (opInfo.opType === 'edit') { + const data = opReplace(opInfo?.opRecord?.[opSafeKey], vals); + modelSet(data); + message.success('Data updated successfully'); + } + hide(); + }); }; return (
- - ) -} \ No newline at end of file + ); +} diff --git a/src/view/model/SyncPrompts/config.tsx b/src/view/model/SyncPrompts/config.tsx index b8b4ade..b6381de 100644 --- a/src/view/model/SyncPrompts/config.tsx +++ b/src/view/model/SyncPrompts/config.tsx @@ -41,8 +41,6 @@ export const syncColumns = () => [ dataIndex: 'prompt', key: 'prompt', // width: 300, - render: (v: string) => ( - {v} - ), + render: (v: string) => {v}, }, ]; diff --git a/src/view/model/SyncPrompts/index.scss b/src/view/model/SyncPrompts/index.scss index 4e3ba63..0c7fb60 100644 --- a/src/view/model/SyncPrompts/index.scss +++ b/src/view/model/SyncPrompts/index.scss @@ -1,4 +1,5 @@ -.chat-table-tip, .chat-table-btns { +.chat-table-tip, +.chat-table-btns { display: flex; justify-content: space-between; } diff --git a/src/view/model/SyncPrompts/index.tsx b/src/view/model/SyncPrompts/index.tsx index 8a26a84..e983d37 100644 --- a/src/view/model/SyncPrompts/index.tsx +++ b/src/view/model/SyncPrompts/index.tsx @@ -52,7 +52,7 @@ export default function SyncPrompts() { }, [opInfo.opTime]); const handleEnable = (isEnable: boolean) => { - const data = opReplaceItems(selectedRowIDs, { enable: isEnable }) + const data = opReplaceItems(selectedRowIDs, { enable: isEnable }); modelCacheSet(data); }; @@ -72,7 +72,9 @@ export default function SyncPrompts() {
{selectedItems.length > 0 && ( <> - + Selected {selectedItems.length} items @@ -84,7 +86,11 @@ export default function SyncPrompts() {
- {lastUpdated && Last updated on {fmtDate(lastUpdated)}} + {lastUpdated && ( + + Last updated on {fmtDate(lastUpdated)} + + )}
{record.prompt}
}} + expandable={{ + expandedRowRender: (record) =>
{record.prompt}
, + }} /> - ) -} \ No newline at end of file + ); +} diff --git a/src/view/model/SyncRecord/config.tsx b/src/view/model/SyncRecord/config.tsx index 71321ca..66ffd23 100644 --- a/src/view/model/SyncRecord/config.tsx +++ b/src/view/model/SyncRecord/config.tsx @@ -25,7 +25,11 @@ export const syncColumns = () => [ key: 'tags', // width: 150, render: (v: string[]) => ( - {v?.map(i => {i})} + + {v?.map((i) => ( + {i} + ))} + ), }, { @@ -43,8 +47,6 @@ export const syncColumns = () => [ dataIndex: 'prompt', key: 'prompt', // width: 300, - render: (v: string) => ( - {v} - ), + render: (v: string) => {v}, }, ]; diff --git a/src/view/model/SyncRecord/index.tsx b/src/view/model/SyncRecord/index.tsx index b74344a..d8b60ca 100644 --- a/src/view/model/SyncRecord/index.tsx +++ b/src/view/model/SyncRecord/index.tsx @@ -30,7 +30,7 @@ export default function SyncRecord() { useInit(async () => { setFilePath(await getPath(state)); setJsonPath(await path.join(await chatRoot(), 'cache_model', `${state?.id}.json`)); - }) + }); useEffect(() => { if (modelCacheJson.length <= 0) return; @@ -45,7 +45,7 @@ export default function SyncRecord() { }, [opInfo.opTime]); const handleEnable = (isEnable: boolean) => { - const data = opReplaceItems(selectedRowIDs, { enable: isEnable }) + const data = opReplaceItems(selectedRowIDs, { enable: isEnable }); modelCacheSet(data); }; @@ -58,7 +58,9 @@ export default function SyncRecord() {
{selectedItems.length > 0 && ( <> - + Selected {selectedItems.length} items @@ -70,7 +72,11 @@ export default function SyncRecord() {
- {state?.last_updated && Last updated on {fmtDate(state?.last_updated)}} + {state?.last_updated && ( + + Last updated on {fmtDate(state?.last_updated)} + + )}
{record.prompt}
}} + expandable={{ + expandedRowRender: (record) =>
{record.prompt}
, + }} /> - ) -} \ No newline at end of file + ); +} diff --git a/src/view/model/UserCustom/Form.tsx b/src/view/model/UserCustom/Form.tsx index c810a77..9d4e306 100644 --- a/src/view/model/UserCustom/Form.tsx +++ b/src/view/model/UserCustom/Form.tsx @@ -6,7 +6,7 @@ import Tags from '@comps/Tags'; import { DISABLE_AUTO_COMPLETE } from '@/utils'; interface UserCustomFormProps { - record?: Record | null; + record?: Record | null; } const initFormValue = { @@ -16,7 +16,10 @@ const initFormValue = { prompt: '', }; -const UserCustomForm: ForwardRefRenderFunction = ({ record }, ref) => { +const UserCustomForm: ForwardRefRenderFunction = ( + { record }, + ref, +) => { const [form] = Form.useForm(); useImperativeHandle(ref, () => ({ form })); @@ -27,11 +30,7 @@ const UserCustomForm: ForwardRefRenderFunction = }, [record]); return ( -
+ = - ) -} + ); +}; export default forwardRef(UserCustomForm); diff --git a/src/view/model/UserCustom/config.tsx b/src/view/model/UserCustom/config.tsx index 0450043..162dc66 100644 --- a/src/view/model/UserCustom/config.tsx +++ b/src/view/model/UserCustom/config.tsx @@ -7,7 +7,7 @@ export const modelColumns = () => [ fixed: 'left', width: 120, key: 'cmd', - render: (v: string) => /{v} + render: (v: string) => /{v}, }, { title: 'Act', @@ -21,7 +21,11 @@ export const modelColumns = () => [ key: 'tags', width: 150, render: (v: string[]) => ( - {v?.map(i => {i})} + + {v?.map((i) => ( + {i} + ))} + ), }, { @@ -39,9 +43,7 @@ export const modelColumns = () => [ dataIndex: 'prompt', key: 'prompt', width: 300, - render: (v: string) => ( - {v} - ), + render: (v: string) => {v}, }, { title: 'Action', @@ -61,5 +63,5 @@ export const modelColumns = () => [ ), - } + }, ]; diff --git a/src/view/model/UserCustom/index.tsx b/src/view/model/UserCustom/index.tsx index a98615a..591d35f 100644 --- a/src/view/model/UserCustom/index.tsx +++ b/src/view/model/UserCustom/index.tsx @@ -50,10 +50,10 @@ export default function LanguageModel() { const data = opReplace(opInfo?.opRecord?.[opSafeKey], opInfo?.opRecord); modelCacheSet(data); } - }, [opInfo.opTime]) + }, [opInfo.opTime]); const handleEnable = (isEnable: boolean) => { - const data = opReplaceItems(selectedRowIDs, { enable: isEnable }) + const data = opReplaceItems(selectedRowIDs, { enable: isEnable }); modelCacheSet(data); }; @@ -63,38 +63,51 @@ export default function LanguageModel() { }; const handleOk = () => { - formRef.current?.form?.validateFields() - .then(async (vals: Record) => { - if (modelCacheJson.map((i: any) => i.cmd).includes(vals.cmd) && opInfo?.opRecord?.cmd !== vals.cmd) { - message.warning(`"cmd: /${vals.cmd}" already exists, please change the "${vals.cmd}" name and resubmit.`); - return; - } - let data = []; - switch (opInfo.opType) { - case 'new': data = opAdd(vals); break; - case 'edit': data = opReplace(opInfo?.opRecord?.[opSafeKey], vals); break; - default: break; - } - await modelCacheSet(data); - opInit(data); - modelSet({ - id: 'user_custom', - last_updated: Date.now(), - }); - hide(); - }) + formRef.current?.form?.validateFields().then(async (vals: Record) => { + if ( + modelCacheJson.map((i: any) => i.cmd).includes(vals.cmd) && + opInfo?.opRecord?.cmd !== vals.cmd + ) { + message.warning( + `"cmd: /${vals.cmd}" already exists, please change the "${vals.cmd}" name and resubmit.`, + ); + return; + } + let data = []; + switch (opInfo.opType) { + case 'new': + data = opAdd(vals); + break; + case 'edit': + data = opReplace(opInfo?.opRecord?.[opSafeKey], vals); + break; + default: + break; + } + await modelCacheSet(data); + opInit(data); + modelSet({ + id: 'user_custom', + last_updated: Date.now(), + }); + hide(); + }); }; - const modalTitle = `${({ new: 'Create', edit: 'Edit' })[opInfo.opType]} Model`; + const modalTitle = `${{ new: 'Create', edit: 'Edit' }[opInfo.opType]} Model`; return (
- +
{selectedItems.length > 0 && ( <> - + Selected {selectedItems.length} items @@ -103,7 +116,11 @@ export default function LanguageModel() {
- {lastUpdated && Last updated on {fmtDate(lastUpdated)}} + {lastUpdated && ( + + Last updated on {fmtDate(lastUpdated)} + + )}
{record.prompt}
}} + expandable={{ + expandedRowRender: (record) =>
{record.prompt}
, + }} /> - ) -} \ No newline at end of file + ); +} diff --git a/src/view/notes/config.tsx b/src/view/notes/config.tsx index 224aea9..53ed522 100644 --- a/src/view/notes/config.tsx +++ b/src/view/notes/config.tsx @@ -41,7 +41,9 @@ export const notesColumns = () => [ return ( actions.setRecord(row, 'preview')}>Preview - Edit + + Edit + actions.setRecord(row, 'delete')} @@ -51,20 +53,20 @@ export const notesColumns = () => [ Delete - ) - } - } + ); + }, + }, ]; const RenderPath = ({ row }: any) => { const [filePath, setFilePath] = useState(''); useInit(async () => { - setFilePath(await getPath(row)); - }) + setFilePath(await getPath(row)); + }); return shell.open(filePath)}>{filePath}; }; export const getPath = async (row: any) => { const isImg = ['png'].includes(row?.ext); - return await path.join(await chatRoot(), 'notes', row.id) + `.${row.ext}`; -} + return (await path.join(await chatRoot(), 'notes', row.id)) + `.${row.ext}`; +}; diff --git a/src/view/notes/index.tsx b/src/view/notes/index.tsx index c007ea1..9bbc626 100644 --- a/src/view/notes/index.tsx +++ b/src/view/notes/index.tsx @@ -46,8 +46,8 @@ export default function Notes() { message.success('Name has been changed!'); } opInfo.resetRecord(); - })() - }, [opInfo.opType]) + })(); + }, [opInfo.opType]); const handleDelete = async () => { if (opData?.length === selectedRows.length) { @@ -62,7 +62,7 @@ export default function Notes() { const file = await path.join(await chatRoot(), 'notes', `${i?.id}.${i?.ext}`); await fs.removeFile(file); return file; - }) + }); Promise.all(rows).then(async () => { await handleRefresh(); message.success('All files selected are cleared!'); @@ -122,5 +122,5 @@ export default function Notes() { - ) -} \ No newline at end of file + ); +} diff --git a/src/view/settings/General.tsx b/src/view/settings/General.tsx index 9b2189d..88207b1 100644 --- a/src/view/settings/General.tsx +++ b/src/view/settings/General.tsx @@ -9,37 +9,47 @@ import { DISABLE_AUTO_COMPLETE } from '@/utils'; const AutoUpdateLabel = () => { return ( - Auto Update - {' '} - -
Auto Update Policy
-
Prompt: prompt to install
-
Silent: install silently
- {/*
Disable: disable auto update
*/} - - )}>
+ Auto Update{' '} + +
Auto Update Policy
+
+ Prompt: prompt to install +
+
+ Silent: install silently +
+ {/*
Disable: disable auto update
*/} + + } + > + +
- ) -} + ); +}; const GlobalShortcutLabel = () => { return (
- Global Shortcut - {' '} - -
Shortcut definition, modifiers and key separated by "+" e.g. CmdOrControl+Q
-
If empty, the shortcut is disabled.
- https://tauri.app/v1/api/js/globalshortcut -
- )}> + Global Shortcut{' '} + +
Shortcut definition, modifiers and key separated by "+" e.g. CmdOrControl+Q
+
If empty, the shortcut is disabled.
+ + https://tauri.app/v1/api/js/globalshortcut + + + } + >
- ) -} + ); +}; export default function General() { const [platformInfo, setPlatform] = useState(''); @@ -62,9 +72,7 @@ export default function General() { Light Dark - {["darwin", "windows"].includes(platformInfo) && ( - System - )} + {['darwin', 'windows'].includes(platformInfo) && System} } name="auto_update"> @@ -78,5 +86,5 @@ export default function General() { - ) + ); } diff --git a/src/view/settings/MainWindow.tsx b/src/view/settings/MainWindow.tsx index d5e511e..99a7378 100644 --- a/src/view/settings/MainWindow.tsx +++ b/src/view/settings/MainWindow.tsx @@ -9,25 +9,39 @@ import { DISABLE_AUTO_COMPLETE } from '@/utils'; const OriginLabel = ({ url }: { url: string }) => { return ( - Switch Origin + Switch Origin{' '} + + + - ) -} + ); +}; const PopupSearchLabel = () => { return ( - Pop-up Search - {' '} - -
Generate images according to the content: Select the ChatGPT content with the mouse, no more than 400 characters. the DALL·E 2 button appears, and click to jump (Note: because the search content filled by the script cannot trigger the event directly, you need to enter a space in the input box to make the button clickable).
-
The application is built using Tauri, and due to its security restrictions, some of the action buttons will not work, so we recommend going to your browser.
- - )}>
+ Pop-up Search{' '} + +
+ Generate images according to the content: Select the ChatGPT content with the mouse, + no more than 400 characters. the DALL·E 2 button appears, and click to jump + (Note: because the search content filled by the script cannot trigger the event + directly, you need to enter a space in the input box to make the button clickable). +
+
+ The application is built using Tauri, and due to its security restrictions, some of + the action buttons will not work, so we recommend going to your browser. +
+ + } + > + +
- ) -} + ); +}; export default function General() { const [chatConf, setChatConf] = useState(null); @@ -46,8 +60,12 @@ export default function General() { - + - ) + ); } diff --git a/src/view/settings/TrayWindow.tsx b/src/view/settings/TrayWindow.tsx index 7ee94f1..8fcab50 100644 --- a/src/view/settings/TrayWindow.tsx +++ b/src/view/settings/TrayWindow.tsx @@ -9,8 +9,12 @@ export default function General() { - + - ) + ); } diff --git a/src/view/settings/index.tsx b/src/view/settings/index.tsx index a6a442a..96f87f8 100644 --- a/src/view/settings/index.tsx +++ b/src/view/settings/index.tsx @@ -21,7 +21,7 @@ export default function Settings() { useEffect(() => { form.setFieldsValue(clone(chatConf)); - }, [chatConf]) + }, [chatConf]); const onCancel = () => { form.setFieldsValue(chatConf); @@ -31,7 +31,7 @@ export default function Settings() { const chatData = await invoke('reset_chat_conf'); setChatConf(chatData); const isOk = await dialog.ask(`Configuration reset successfully, whether to restart?`, { - title: 'ChatGPT Preferences' + title: 'ChatGPT Preferences', }); if (isOk) { process.relaunch(); @@ -44,7 +44,7 @@ export default function Settings() { if (!isEqual(omit(chatConf, ['default_origin']), values)) { await invoke('form_confirm', { data: values, label: 'main' }); const isOk = await dialog.ask(`Configuration saved successfully, whether to restart?`, { - title: 'ChatGPT Preferences' + title: 'ChatGPT Preferences', }); if (isOk) { process.relaunch(); @@ -75,11 +75,15 @@ export default function Settings() { - - + + - ) -} \ No newline at end of file + ); +} diff --git a/tsconfig.json b/tsconfig.json index 474aa73..9505215 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,7 +20,7 @@ "@/*": ["src/*"], "@view/*": ["src/view/*"], "@comps/*": ["src/components/*"], - "@layout/*": ["src/layout/*"], + "@layout/*": ["src/layout/*"] } }, "include": ["src"], diff --git a/vite.config.ts b/vite.config.ts index debf8b2..c69da5d 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,6 +1,6 @@ -import { defineConfig } from "vite"; -import react from "@vitejs/plugin-react"; -import tsconfigPaths from "vite-tsconfig-paths"; +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; +import tsconfigPaths from 'vite-tsconfig-paths'; // https://vitejs.dev/config/ export default defineConfig({ @@ -16,12 +16,12 @@ export default defineConfig({ }, // to make use of `TAURI_DEBUG` and other env variables // https://tauri.studio/v1/api/config#buildconfig.beforedevcommand - envPrefix: ["VITE_", "TAURI_"], + envPrefix: ['VITE_', 'TAURI_'], build: { // Tauri supports es2021 - target: ["es2021", "chrome100", "safari13"], + target: ['es2021', 'chrome100', 'safari13'], // don't minify for debug builds - minify: !process.env.TAURI_DEBUG ? "esbuild" : false, + minify: !process.env.TAURI_DEBUG ? 'esbuild' : false, // produce sourcemaps for debug builds sourcemap: !!process.env.TAURI_DEBUG, },