diff --git a/resources/dist.rc b/resources/dist.rc index 74b6109..2e9c41f 100644 Binary files a/resources/dist.rc and b/resources/dist.rc differ diff --git a/src/celemod-ui/src/context/modManage.tsx b/src/celemod-ui/src/context/modManage.tsx index 0fe0a4d..f2632f5 100644 --- a/src/celemod-ui/src/context/modManage.tsx +++ b/src/celemod-ui/src/context/modManage.tsx @@ -6,6 +6,7 @@ import { useStorage, initGamePath, useCurrentEverestVersion, + initModComments, } from '../states'; import { useEffect, useMemo } from 'preact/hooks'; import { createPopup } from 'src/components/Popup'; @@ -14,6 +15,8 @@ import { ProgressIndicator } from 'src/components/Progress'; let lastGamePath = ''; export const createModManageContext = () => { + initModComments(); + const { setInstalledMods } = useInstalledMods(); const [gamePath] = useGamePath(); diff --git a/src/celemod-ui/src/routes/Manage.scss b/src/celemod-ui/src/routes/Manage.scss index 320c045..47e1aa7 100644 --- a/src/celemod-ui/src/routes/Manage.scss +++ b/src/celemod-ui/src/routes/Manage.scss @@ -7,6 +7,7 @@ .modList { .title { + html[lang="pt-BR"] &, html[lang="ru-RU"] & { font-size: 16px; @@ -36,8 +37,9 @@ } button { - html[lang="pt-BR"] & , - html[lang="ru-RU"] &{ + + html[lang="pt-BR"] &, + html[lang="ru-RU"] & { font-size: 10px !important; } } @@ -157,7 +159,7 @@ border-radius: 100px; } - + } } @@ -170,8 +172,26 @@ .modVersion { font-size: 10px; - margin: 0 6px; + margin-left: 6px; display: inline-block; color: rgba(255, 255, 255, 0.4); } + + .modComment { + font-size: 15px; + margin-left: 6px; + display: inline-block; + color: rgba(255, 255, 255, 0.575); + cursor: text; + } + + .modCommentInput { + margin: 0 6px; + padding: 0 6px; + border-radius: 10px; + border: none; + background: #222; + color: theme.$fg; + box-shadow: 0 2px 5px #00000040; + } } \ No newline at end of file diff --git a/src/celemod-ui/src/routes/Manage.tsx b/src/celemod-ui/src/routes/Manage.tsx index dd8a86f..57ca3e1 100644 --- a/src/celemod-ui/src/routes/Manage.tsx +++ b/src/celemod-ui/src/routes/Manage.tsx @@ -8,6 +8,7 @@ import { useCurrentBlacklistProfile, useGamePath, useInstalledMods, + useModComments, useStorage, } from '../states'; import { useContext, useEffect, useMemo, useRef, useState } from 'preact/hooks'; @@ -69,6 +70,8 @@ const modListContext = createContext<{ version: string; gb_file: string; }[]; + modComments: { [name: string]: string }; + setModComment: (name: string, comment: string) => void; } | null>({} as any); const ModBadge = ({ @@ -128,20 +131,20 @@ const ModMissing = ({ name, version, optional }: MissingModDepInfo) => { onClick={ gbFileID !== null ? async () => { - setState(_i18n.t('下载中')); - download.downloadMod(name, gbFileID, { - onProgress: (task, progress) => { - setState(`${progress}% (${task.subtasks.length})`); - }, - onFinished: () => { - setState(_i18n.t('下载完成')); - ctx?.reloadMods(); - }, - onFailed: () => { - setState(_i18n.t('下载失败')); - }, - }); - } + setState(_i18n.t('下载中')); + download.downloadMod(name, gbFileID, { + onProgress: (task, progress) => { + setState(`${progress}% (${task.subtasks.length})`); + }, + onFinished: () => { + setState(_i18n.t('下载完成')); + ctx?.reloadMods(); + }, + onFailed: () => { + setState(_i18n.t('下载失败')); + }, + }); + } : undefined } > @@ -214,12 +217,19 @@ const ModLocal = ({ const isAlwaysOn = ctx?.alwaysOnMods.includes(name); + const [editingComment, setEditingComment] = useState(false); + const refCommentInput = useRef(null); + useEffect(() => { + if (editingComment) { + refCommentInput.current?.focus(); + } + }, [editingComment]); + return (
setExpanded(!expanded)} > {hasDeps && (!optional || ctx?.fullTree) ? ( @@ -245,8 +255,8 @@ const ModLocal = ({ {isAlwaysOn ? _i18n.t('始终开启') : enabled - ? _i18n.t('已启用') - : _i18n.t('已禁用')} + ? _i18n.t('已启用') + : _i18n.t('已禁用')} {enabled && @@ -324,7 +334,28 @@ const ModLocal = ({ )} - {name} + setEditingComment(true)} + >{name} + {!editingComment && ctx?.modComments[name] && ( + { + setEditingComment(true); + }}>{ctx?.modComments[name]} + )} + { + editingComment && ( + ctx?.setModComment(name, (e.target as any).value)} + onKeyUp={(e) => { + if (e.keyCode === 257 || e.keyCode === 256) { // enter or esc + setEditingComment(false); + } + }} + onBlur={() => setEditingComment(false)} /> + ) + } + {version} {(!optional || ctx?.fullTree) && expanded && (
@@ -660,6 +691,7 @@ export const Manage = () => { modsTreeRef.current?.scrollTo(0, 0); }, [excludeDependents]); const globalCtx = useGlobalContext(); + const [modComments, setModComments] = useModComments() const manageCtx = useMemo( () => ({ hasUpdateMods, @@ -668,6 +700,12 @@ export const Manage = () => { else setAlwaysOnMods(alwaysOnMods.filter((v) => v !== name)); }, alwaysOnMods, + modComments, setModComment(name: string, comment: string) { + setModComments({ + ...modComments, + [name]: comment + }); + }, batchSwitchMod: (names: string[], enabled: boolean) => { if (!enabled) names = names.filter((v) => !alwaysOnMods.includes(v)); if (!currentProfile) return; @@ -804,6 +842,7 @@ export const Manage = () => { fullTree, showUpdate, alwaysOnMods, + modComments ] ); diff --git a/src/celemod-ui/src/states.ts b/src/celemod-ui/src/states.ts index c3be2ee..e937880 100644 --- a/src/celemod-ui/src/states.ts +++ b/src/celemod-ui/src/states.ts @@ -162,4 +162,6 @@ export const [initUseMultiThread, useUseMultiThread] = createPersistedStateByKey export const [initAlwaysOnMods, useAlwaysOnMods] = createPersistedStateByKey('alwaysOnMods', []) -export const [initSearchSort, useSearchSort] = createPersistedStateByKey<'new' | 'updateAdded' | 'updated' | 'views' | 'likes'>('searchSort', 'likes') \ No newline at end of file +export const [initSearchSort, useSearchSort] = createPersistedStateByKey<'new' | 'updateAdded' | 'updated' | 'views' | 'likes'>('searchSort', 'likes') + +export const [initModComments, useModComments] = createPersistedStateByKey('modComments', {}) \ No newline at end of file