From 2e4e57be450e80a6e2580ca20dbf26861d5056da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=B2=81=E6=A0=91=E4=BA=BA?= Date: Sun, 18 May 2025 02:41:20 +0900 Subject: [PATCH] refactor: batch 3 --- src/App.css | 6 +- src/components/AddKey.tsx | 36 ++- .../AdbInstructionTemplate.tsx | 57 +++++ .../AndroidADBPullInstruction.tsx | 212 +++++------------ .../RootExplorerGuide.tsx | 64 +++++ src/components/ExtLink.tsx | 2 +- src/components/FilePathBlock.tsx | 4 +- src/components/HelpText/Headers.tsx | 23 +- src/components/HelpText/HiWord.tsx | 10 +- src/components/HelpText/VQuote.tsx | 8 +- src/components/InstructionsTabs.tsx | 11 +- src/components/Key/MacCommandKey.tsx | 15 +- src/components/Key/ShiftKey.tsx | 15 +- src/components/KeyInput.tsx | 65 ++++-- src/components/KeyListContainer.tsx | 21 ++ src/components/ProjectIssue.tsx | 6 +- src/faq/KugouFAQ.tsx | 30 +-- src/faq/KuwoFAQ.tsx | 65 +++--- src/faq/OtherFAQ.tsx | 218 ++++++++++-------- src/faq/QQMusicFAQ.tsx | 151 +----------- src/faq/SegmentAddKeyDropdown.tsx | 27 +-- src/faq/SegmentKeyImportInstructions.tsx | 38 ++- src/faq/SegmentTryOfficialPlayer.tsx | 12 +- src/faq/assets/ld_settings_misc.webp | Bin 8132 -> 0 bytes src/faq/assets/ld_settings_misc@2x.webp | Bin 0 -> 31180 bytes src/faq/assets/mumu_settings_misc@2x.webp | Bin 0 -> 23026 bytes src/features/file-listing/AlbumImage.tsx | 24 -- src/features/file-listing/FileError.tsx | 67 ++++-- src/features/file-listing/FileRow.tsx | 2 +- src/features/file-listing/SongMetadata.tsx | 22 -- .../settings/panels/KWMv2/InstructionsIOS.tsx | 45 ++-- .../settings/panels/KWMv2/InstructionsPC.tsx | 8 +- .../panels/KWMv2/KWMv2AllInstructions.tsx | 34 +-- .../settings/panels/KWMv2/KWMv2EKeyItem.tsx | 98 +++----- .../settings/panels/Kugou/InstructionsPC.tsx | 66 ++++-- .../panels/Kugou/KugouAllInstructions.tsx | 29 +-- .../settings/panels/Kugou/KugouEKeyItem.tsx | 74 ++---- src/features/settings/panels/PanelKGGKey.tsx | 61 ++--- .../settings/panels/PanelKWMv2Key.tsx | 105 ++------- .../settings/panels/PanelQMCv2Key.tsx | 63 ++--- .../settings/panels/PanelQingTing.tsx | 122 +++++----- .../settings/panels/QMCv2/InstructionsMac.tsx | 4 +- .../settings/panels/QMCv2/InstructionsPC.tsx | 53 ++++- .../settings/panels/QMCv2/assets/noop.asm.txt | 16 ++ .../settings/panels/QMCv2/assets/noop.exe | Bin 0 -> 1536 bytes src/tabs/FaqTab.tsx | 21 +- src/tabs/SettingsTab.tsx | 6 +- src/util/applyTemplate.ts | 3 + src/util/toastImportResult.tsx | 28 +++ src/vite-env.d.ts | 5 + support/b64-loader.ts | 15 ++ vite.config.ts | 2 + 52 files changed, 933 insertions(+), 1136 deletions(-) create mode 100644 src/components/AndroidADBPullInstruction/AdbInstructionTemplate.tsx create mode 100644 src/components/AndroidADBPullInstruction/RootExplorerGuide.tsx create mode 100644 src/components/KeyListContainer.tsx delete mode 100644 src/faq/assets/ld_settings_misc.webp create mode 100644 src/faq/assets/ld_settings_misc@2x.webp create mode 100644 src/faq/assets/mumu_settings_misc@2x.webp delete mode 100644 src/features/file-listing/AlbumImage.tsx delete mode 100644 src/features/file-listing/SongMetadata.tsx create mode 100644 src/features/settings/panels/QMCv2/assets/noop.asm.txt create mode 100644 src/features/settings/panels/QMCv2/assets/noop.exe create mode 100644 src/util/applyTemplate.ts create mode 100644 src/util/toastImportResult.tsx create mode 100644 support/b64-loader.ts diff --git a/src/App.css b/src/App.css index 0199195..387b613 100644 --- a/src/App.css +++ b/src/App.css @@ -1,5 +1,9 @@ @import 'tailwindcss'; -@plugin "daisyui"; +@plugin "daisyui" { + themes: + emerald --default, + dracula --prefersdark; +} @theme { --font-display: system-ui, Sarasa UI SC, Source Han Sans CN, Noto Sans CJK SC, sans-serif, Apple Color Emoji, Segoe UI Emoji; diff --git a/src/components/AddKey.tsx b/src/components/AddKey.tsx index 8f504d3..204583a 100644 --- a/src/components/AddKey.tsx +++ b/src/components/AddKey.tsx @@ -1,24 +1,46 @@ +import type { RefObject } from 'react'; import { MdAdd, MdDeleteForever, MdFileUpload } from 'react-icons/md'; export interface AddKeyProps { addKey: () => void; importKeyFromFile?: () => void; clearKeys?: () => void; + refContainer?: RefObject; } -export function AddKey({ addKey, importKeyFromFile, clearKeys }: AddKeyProps) { +export function AddKey({ addKey, refContainer, importKeyFromFile, clearKeys }: AddKeyProps) { + const scrollToLastKey = () => { + const container = refContainer?.current; + if (container) { + const inputs = container.querySelectorAll('input[data-name="key-input--name"]'); + const lastInput = inputs[inputs.length - 1] as HTMLInputElement | null; + if (lastInput) { + lastInput.focus({ preventScroll: true }); + lastInput.scrollIntoView({ + behavior: 'smooth', + block: 'center', + }); + } + } + }; + + const handleAddKey = () => { + addKey(); + setTimeout(scrollToLastKey); + }; + return (
- - -
diff --git a/src/components/AndroidADBPullInstruction/AdbInstructionTemplate.tsx b/src/components/AndroidADBPullInstruction/AdbInstructionTemplate.tsx new file mode 100644 index 0000000..8d78871 --- /dev/null +++ b/src/components/AndroidADBPullInstruction/AdbInstructionTemplate.tsx @@ -0,0 +1,57 @@ +import { Light as SyntaxHighlighter } from 'react-syntax-highlighter'; +import hljsStyleGitHub from 'react-syntax-highlighter/dist/esm/styles/hljs/github'; +import { ExtLink } from '../ExtLink'; +import PowerShellAdbDumpCommandTemplate from './adb_dump.ps1?raw'; +import ShellAdbDumpCommandTemplate from './adb_dump.sh?raw'; +import { applyTemplate } from '~/util/applyTemplate'; + +export interface AdbInstructionTemplateProps { + dir: string; + file: string; + platform: 'win32' | 'linux'; +} + +const URL_USB_DEBUGGING = 'https://developer.android.com/studio/debug/dev-options?hl=zh-cn#Enable-debugging'; + +const LANGUAGE_MAP = { + win32: { language: 'ps1', template: PowerShellAdbDumpCommandTemplate }, + linux: { language: 'sh', template: ShellAdbDumpCommandTemplate }, +}; + +export function AdbInstructionTemplate({ dir, file, platform }: AdbInstructionTemplateProps) { + const { language, template } = LANGUAGE_MAP[platform]; + const command = applyTemplate(template, { dir, file }); + + return ( +
    +
  1. +

    + 确保 adb 命令可用。 +

    + + {platform === 'win32' && ( +
    + + 💡 如果没有,可以 + 使用 Scoop 安装。 + +
    + )} +
  2. +
  3. 启动终端,进入 PowerShell 环境。
  4. +
  5. + 在手机启用 USB 调试 +
  6. +
  7. 将安卓设备连接到电脑。
  8. +
  9. +

    粘贴执行下述代码执行。若设备提示「是否允许 USB 调试」或「超级用户请求」,选择允许:

    + + {command} + +
  10. +
  11. + 提交当前目录下的 {file} 文件。 +
  12. +
+ ); +} diff --git a/src/components/AndroidADBPullInstruction/AndroidADBPullInstruction.tsx b/src/components/AndroidADBPullInstruction/AndroidADBPullInstruction.tsx index d2e5736..869daf2 100644 --- a/src/components/AndroidADBPullInstruction/AndroidADBPullInstruction.tsx +++ b/src/components/AndroidADBPullInstruction/AndroidADBPullInstruction.tsx @@ -1,171 +1,73 @@ -import { - Accordion, - AccordionButton, - AccordionIcon, - AccordionItem, - AccordionPanel, - Box, - Code, - Heading, - ListItem, - OrderedList, - Text, - chakra, -} from '@chakra-ui/react'; -import { ExternalLinkIcon } from '@chakra-ui/icons'; -import { Light as SyntaxHighlighter } from 'react-syntax-highlighter'; -import hljsStyleGitHub from 'react-syntax-highlighter/dist/esm/styles/hljs/github'; - -import PowerShellAdbDumpCommandTemplate from './adb_dump.ps1?raw'; -import ShellAdbDumpCommandTemplate from './adb_dump.sh?raw'; import { ExtLink } from '../ExtLink'; - -const applyTemplate = (tpl: string, values: Record) => { - return tpl.replace(/\{\{\s*(\w+)\s*\}\}/g, (_, key) => (Object.hasOwn(values, key) ? String(values[key]) : '')); -}; +import { Ruby } from '../Ruby'; +import { useId } from 'react'; +import { RootExplorerGuide } from './RootExplorerGuide'; +import { AdbInstructionTemplate } from './AdbInstructionTemplate'; +import { HiWord } from '../HelpText/HiWord'; export interface AndroidADBPullInstructionProps { dir: string; file: string; } +const URL_AMAZE = 'https://github.com/TeamAmaze/AmazeFileManager/releases/latest'; +const URL_MT2 = 'https://mt2.cn/download/'; + export function AndroidADBPullInstruction({ dir, file }: AndroidADBPullInstructionProps) { - const psAdbDumpCommand = applyTemplate(PowerShellAdbDumpCommandTemplate, { dir, file }); - const shAdbDumpCommand = applyTemplate(ShellAdbDumpCommandTemplate, { dir, file }); + const androidInstructionId = useId(); return ( <> - - 你需要 - - 超级管理员 - ( - - root - - ) - - 访问权限来访问安卓应用的私有数据。 - - +

+ 你需要超级管理员访问权限来访问安卓应用的私有数据。 +

+

⚠️ 请注意,获取管理员权限通常意味着你的安卓设备 - 将失去保修资格。 - + 将失去保修资格。 +

- - - - - - 在安卓手机端操作 - - - - - - - - - 启动具有 root 特权的文件浏览器 - - - - - 访问 {dir}/ 目录。 - - - - - 将文件 {file} 复制到浏览器可访问的目录。 -
- (例如下载目录) -
-
- - 提交该数据库文件。 - -
-
-
- - - - - - 在 PC 端操作(ADB / PowerShell) - - - - - - - - - 确保 adb 命令可用。 - - - 💡 如果没有,可以 - - 使用 Scoop 安装 - - 。 - - - - 启动终端并进入 PowerShell 7 环境。 - - - 将安卓设备连接到电脑,并允许调试。 - - - 粘贴执行下述代码。若设备提示「超级用户请求」请允许: - - {psAdbDumpCommand} - - - - - 提交当前目录下的 {file} 文件。 - - - - - - - - - - - 在 Linux / Mac 系统下操作(ADB / Shell) - - - - - - - - - 确保 adb 命令可用。 - - - - 将安卓设备连接到电脑,并允许调试。 - - - 粘贴执行下述代码。若设备提示「超级用户请求」请允许: - - {shAdbDumpCommand} - - - - - 提交当前目录下的 {file} 文件。 - - - - - -
+
+
+ +
在安卓手机端操作
+
+
    +
  1. + 启动支持 root 特权的文件浏览器,如 Amaze 文件浏览器、 + MT 管理器 等。 +
  2. +
  3. + ※ 记得启用 root 特权! + +
  4. +
  5. +

    + 访问 {dir}/ 目录。 +

    +

    ※ 从侧边栏选择根目录开始。

    +
  6. +
  7. + 将文件 {file} 复制到浏览器可访问的目录(例如下载目录)。 +
  8. +
  9. 提交该数据库文件。
  10. +
+
+
+
+ +
在 PC 端操作(使用 ADB / PowerShell)
+
+ +
+
+
+ +
在 Linux / Mac 系统下操作(使用 ADB / Shell)
+
+ +
+
+
); } diff --git a/src/components/AndroidADBPullInstruction/RootExplorerGuide.tsx b/src/components/AndroidADBPullInstruction/RootExplorerGuide.tsx new file mode 100644 index 0000000..29e6d18 --- /dev/null +++ b/src/components/AndroidADBPullInstruction/RootExplorerGuide.tsx @@ -0,0 +1,64 @@ +import { FiMenu, FiMoreVertical } from 'react-icons/fi'; +import { Header5 } from '../HelpText/Headers'; +import { Ruby } from '../Ruby'; +import { VQuote } from '../HelpText/VQuote'; + +export function RootExplorerGuide() { + return ( +
+
+
+ Amaze 文件浏览器 +
    +
  • +
    + 点触主界面左上角的 打开侧边栏 +
    +
  • +
  • + 滑动到最底端,点触 + + 设置 + +
  • +
  • + 点触 + + 行为 + +
  • +
  • + 找到 + + 高级 + + ,勾选 + + 根目录浏览器 + +
  • +
+
+
+ MT 管理器 +
    +
  • +
    + 点触主界面左上角的 打开侧边栏 +
    +
  • +
  • +
    + 点触侧边栏右上方的 + ,点触设置 +
    +
  • +
  • + 勾选请求 Root 权限 +
  • +
+
+
+
+ ); +} diff --git a/src/components/ExtLink.tsx b/src/components/ExtLink.tsx index 83c78b5..d3daa3c 100644 --- a/src/components/ExtLink.tsx +++ b/src/components/ExtLink.tsx @@ -7,7 +7,7 @@ export type ExtLinkProps = AnchorHTMLAttributes & { export function ExtLink({ className, icon = true, children, ...props }: ExtLinkProps) { return ( - + {children} {icon && } diff --git a/src/components/FilePathBlock.tsx b/src/components/FilePathBlock.tsx index 753ff98..4c5411f 100644 --- a/src/components/FilePathBlock.tsx +++ b/src/components/FilePathBlock.tsx @@ -1,6 +1,6 @@ -import React from 'react'; +import type { ReactNode } from 'react'; -export function FilePathBlock({ children }: { children: React.ReactNode }) { +export function FilePathBlock({ children }: { children: ReactNode }) { return (
       {children}
diff --git a/src/components/HelpText/Headers.tsx b/src/components/HelpText/Headers.tsx
index f2a9e8b..cb55286 100644
--- a/src/components/HelpText/Headers.tsx
+++ b/src/components/HelpText/Headers.tsx
@@ -1,4 +1,3 @@
-import { Heading } from '@chakra-ui/react';
 import React from 'react';
 
 export interface HeaderProps {
@@ -9,34 +8,24 @@ export interface HeaderProps {
 
 export function Header3({ children, className, id }: HeaderProps) {
   return (
-    
+    

{children} - +

); } export function Header4({ children, className, id }: HeaderProps) { return ( - +

{children} - +

); } export function Header5({ children, className, id }: HeaderProps) { return ( - +
{children} - +
); } diff --git a/src/components/HelpText/HiWord.tsx b/src/components/HelpText/HiWord.tsx index 54bee0f..054828c 100644 --- a/src/components/HelpText/HiWord.tsx +++ b/src/components/HelpText/HiWord.tsx @@ -1,9 +1,3 @@ -import { Mark } from '@chakra-ui/react'; - -export function HiWord({ children }: { children: React.ReactNode }) { - return ( - - {children} - - ); +export function HiWord({ className = '', children }: { className?: string; children: React.ReactNode }) { + return {children}; } diff --git a/src/components/HelpText/VQuote.tsx b/src/components/HelpText/VQuote.tsx index 274637c..6e42996 100644 --- a/src/components/HelpText/VQuote.tsx +++ b/src/components/HelpText/VQuote.tsx @@ -1,13 +1,9 @@ -import { chakra, css } from '@chakra-ui/react'; - -const cssUnselectable = css({ pointerEvents: 'none', userSelect: 'none' }); - export function VQuote({ children }: { children: React.ReactNode }) { return ( <> - + {children} - + ); } diff --git a/src/components/InstructionsTabs.tsx b/src/components/InstructionsTabs.tsx index f3860e2..5edbe93 100644 --- a/src/components/InstructionsTabs.tsx +++ b/src/components/InstructionsTabs.tsx @@ -13,21 +13,18 @@ export interface InstructionsTabsProps { export function InstructionsTabs({ tabs }: InstructionsTabsProps) { const id = useId(); return ( -
+
{tabs.map(({ id: _tabId, label, content }, index) => ( -
{content}
+
+ {content} +
))} - {/**/} - {/*
*/} - {/**/}
); } diff --git a/src/components/Key/MacCommandKey.tsx b/src/components/Key/MacCommandKey.tsx index 85c609f..d7f990e 100644 --- a/src/components/Key/MacCommandKey.tsx +++ b/src/components/Key/MacCommandKey.tsx @@ -1,15 +1,12 @@ -import { Icon, Kbd } from '@chakra-ui/react'; import { BsCommand } from 'react-icons/bs'; +import { Ruby } from '../Ruby'; export function MacCommandKey() { return ( - - - - - ( - command - ) - + + + + + ); } diff --git a/src/components/Key/ShiftKey.tsx b/src/components/Key/ShiftKey.tsx index 9af49b8..ff98bbb 100644 --- a/src/components/Key/ShiftKey.tsx +++ b/src/components/Key/ShiftKey.tsx @@ -1,15 +1,12 @@ -import { Icon, Kbd } from '@chakra-ui/react'; import { BsShift } from 'react-icons/bs'; +import { Ruby } from '../Ruby'; export function ShiftKey() { return ( - - - - - ( - shift - ) - + + + + + ); } diff --git a/src/components/KeyInput.tsx b/src/components/KeyInput.tsx index 489b2c2..8aa0c57 100644 --- a/src/components/KeyInput.tsx +++ b/src/components/KeyInput.tsx @@ -1,6 +1,6 @@ import { PiFileAudio } from 'react-icons/pi'; import { MdDelete, MdVpnKey } from 'react-icons/md'; -import React from 'react'; +import type { ReactNode } from 'react'; export interface KeyInputProps { sequence: number; @@ -12,24 +12,34 @@ export interface KeyInputProps { onSetValue: (value: string) => void; onDelete: () => void; - nameLabel?: React.ReactNode; - valueLabel?: React.ReactNode; + quality?: string; + onSetQuality?: (quality: string) => void; + + nameLabel?: ReactNode; + valueLabel?: ReactNode; + qualityLabel?: ReactNode; + namePlaceholder?: string; valuePlaceholder?: string; + qualityPlaceholder?: string; } export function KeyInput(props: KeyInputProps) { const { nameLabel, valueLabel, + qualityLabel, namePlaceholder, + qualityPlaceholder, valuePlaceholder, sequence, name, + quality, value, onSetName, onSetValue, onDelete, + onSetQuality, isValidKey, } = props; @@ -40,22 +50,39 @@ export function KeyInput(props: KeyInputProps) {
- +
+ + {onSetQuality && ( + + )} +