feat/optimization-and-audio #1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "frontend",
|
"name": "frontend",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.1.3",
|
"version": "0.1.4",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
126
src/App.tsx
126
src/App.tsx
@@ -137,9 +137,6 @@ const renderInlineLinks = (text: string): JSX.Element[] => {
|
|||||||
const App: ParentComponent = (props) => {
|
const App: ParentComponent = (props) => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const [version] = createResource(versionApi);
|
const [version] = createResource(versionApi);
|
||||||
const [copyState, setCopyState] = createSignal<"idle" | "done" | "error">(
|
|
||||||
"idle",
|
|
||||||
);
|
|
||||||
const [updateDialogOpen, setUpdateDialogOpen] = createSignal(false);
|
const [updateDialogOpen, setUpdateDialogOpen] = createSignal(false);
|
||||||
const [updateCheckState, setUpdateCheckState] =
|
const [updateCheckState, setUpdateCheckState] =
|
||||||
createSignal<UpdateCheckState>("idle");
|
createSignal<UpdateCheckState>("idle");
|
||||||
@@ -197,31 +194,6 @@ const App: ParentComponent = (props) => {
|
|||||||
|
|
||||||
return error instanceof Error ? error.message : "版本信息获取失败";
|
return error instanceof Error ? error.message : "版本信息获取失败";
|
||||||
});
|
});
|
||||||
const versionPayloadText = createMemo(() =>
|
|
||||||
[
|
|
||||||
`Version: ${versionText()}`,
|
|
||||||
`Mode: ${modeText()}`,
|
|
||||||
`Commit: ${commitText()}`,
|
|
||||||
`Build: ${buildText()}`,
|
|
||||||
`Author: ${authorText()}`,
|
|
||||||
`Email: ${emailText()}`,
|
|
||||||
].join("\n"),
|
|
||||||
);
|
|
||||||
const updateSummaryText = createMemo(() => {
|
|
||||||
if (updateCheckState() === "checking") {
|
|
||||||
return "更新检查中...";
|
|
||||||
}
|
|
||||||
if (updateCheckState() === "available") {
|
|
||||||
return `发现新版本:${latestRelease()?.tag_name ?? "-"}`;
|
|
||||||
}
|
|
||||||
if (updateCheckState() === "latest") {
|
|
||||||
return "已是最新版本";
|
|
||||||
}
|
|
||||||
if (updateCheckState() === "error") {
|
|
||||||
return updateCheckError() || "更新检查失败";
|
|
||||||
}
|
|
||||||
return "未检查更新";
|
|
||||||
});
|
|
||||||
const releaseNotesBlocks = createMemo(() =>
|
const releaseNotesBlocks = createMemo(() =>
|
||||||
parseMarkdownBlocks(latestRelease()?.body ?? ""),
|
parseMarkdownBlocks(latestRelease()?.body ?? ""),
|
||||||
);
|
);
|
||||||
@@ -231,6 +203,14 @@ const App: ParentComponent = (props) => {
|
|||||||
const releaseLink = createMemo(
|
const releaseLink = createMemo(
|
||||||
() => latestRelease()?.html_url || RELEASES_PAGE_URL,
|
() => latestRelease()?.html_url || RELEASES_PAGE_URL,
|
||||||
);
|
);
|
||||||
|
const safeValue = (value: string) => (value === "unknown" ? "-" : value);
|
||||||
|
const hasUpdateBadge = createMemo(() => updateCheckState() === "available");
|
||||||
|
const updateDialogTitle = createMemo(() => {
|
||||||
|
if (updateCheckState() === "available") {
|
||||||
|
return `发现更新 ${latestRelease()?.tag_name ?? ""}`;
|
||||||
|
}
|
||||||
|
return "更新信息";
|
||||||
|
});
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
const unsubscribe = settingsStore.subscribe((state) => {
|
const unsubscribe = settingsStore.subscribe((state) => {
|
||||||
@@ -242,16 +222,6 @@ const App: ParentComponent = (props) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleCopyVersion = async () => {
|
|
||||||
try {
|
|
||||||
await navigator.clipboard.writeText(versionPayloadText());
|
|
||||||
setCopyState("done");
|
|
||||||
} catch {
|
|
||||||
setCopyState("error");
|
|
||||||
}
|
|
||||||
|
|
||||||
window.setTimeout(() => setCopyState("idle"), 1800);
|
|
||||||
};
|
|
||||||
const performUpdateCheck = async (manual = false) => {
|
const performUpdateCheck = async (manual = false) => {
|
||||||
if (updateCheckState() === "checking") {
|
if (updateCheckState() === "checking") {
|
||||||
return;
|
return;
|
||||||
@@ -276,17 +246,17 @@ const App: ParentComponent = (props) => {
|
|||||||
setRuntimeTarget(target);
|
setRuntimeTarget(target);
|
||||||
|
|
||||||
const hasNewVersion = isRemoteVersionNewer(versionText(), release.tag_name);
|
const hasNewVersion = isRemoteVersionNewer(versionText(), release.tag_name);
|
||||||
|
setLatestRelease(release);
|
||||||
|
setMatchedAsset(resolveAssetForRuntime(release.assets, target));
|
||||||
|
|
||||||
if (!hasNewVersion) {
|
if (!hasNewVersion) {
|
||||||
setUpdateCheckState("latest");
|
setUpdateCheckState("latest");
|
||||||
if (manual) {
|
if (manual) {
|
||||||
setLatestRelease(release);
|
setUpdateDialogOpen(true);
|
||||||
setMatchedAsset(resolveAssetForRuntime(release.assets, target));
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setLatestRelease(release);
|
|
||||||
setMatchedAsset(resolveAssetForRuntime(release.assets, target));
|
|
||||||
setUpdateCheckState("available");
|
setUpdateCheckState("available");
|
||||||
setUpdateDialogOpen(true);
|
setUpdateDialogOpen(true);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -425,48 +395,48 @@ const App: ParentComponent = (props) => {
|
|||||||
<p class="mt-1 text-sm text-zinc-500">
|
<p class="mt-1 text-sm text-zinc-500">
|
||||||
{asideList().find((item) => isActive(item.url))?.label ?? "账号"}
|
{asideList().find((item) => isActive(item.url))?.label ?? "账号"}
|
||||||
</p>
|
</p>
|
||||||
<p class="mt-1 text-xs text-zinc-500">
|
<div class="mt-3 border-t border-zinc-200/80 pt-3">
|
||||||
模式: {modeText()}
|
|
||||||
</p>
|
|
||||||
<p class="mt-1 text-xs text-zinc-500">
|
|
||||||
调试: {isDebugMode() ? "已开启" : "已关闭"}
|
|
||||||
</p>
|
|
||||||
<p class="mt-3 text-xs font-medium tracking-[0.18em] text-cyan-700/75 uppercase">
|
|
||||||
Runtime
|
|
||||||
</p>
|
|
||||||
<div class="mt-2 grid gap-1 text-xs text-zinc-500 xl:block">
|
|
||||||
<p>Version: {versionText()}</p>
|
|
||||||
<p>Commit: {commitText()}</p>
|
|
||||||
<p>Build: {buildText()}</p>
|
|
||||||
<p>Author: {authorText()}</p>
|
|
||||||
<p>Email: {emailText()}</p>
|
|
||||||
</div>
|
|
||||||
<p
|
|
||||||
class={`mt-2 text-xs ${updateCheckState() === "error" ? "text-rose-500" : "text-zinc-500"}`}
|
|
||||||
>
|
|
||||||
更新: {updateSummaryText()}
|
|
||||||
</p>
|
|
||||||
<div class="mt-3 flex flex-wrap items-center gap-2">
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="rounded-lg border border-zinc-200 bg-white px-3 py-1.5 text-xs text-zinc-700 transition active:bg-zinc-200 hover:bg-zinc-100"
|
class="flex w-full min-w-0 items-center gap-2 rounded-lg border border-zinc-200 bg-white/80 px-2.5 py-1.5 text-left text-xs text-zinc-500 transition hover:bg-white disabled:cursor-not-allowed disabled:opacity-60"
|
||||||
onClick={() => void handleCopyVersion()}
|
|
||||||
>
|
|
||||||
{copyState() === "done"
|
|
||||||
? "已复制"
|
|
||||||
: copyState() === "error"
|
|
||||||
? "复制失败"
|
|
||||||
: "复制版本信息"}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="rounded-lg border border-cyan-200 bg-cyan-50 px-3 py-1.5 text-xs text-cyan-700 transition active:bg-cyan-200 hover:bg-cyan-100 disabled:cursor-not-allowed disabled:opacity-60"
|
|
||||||
disabled={updateCheckState() === "checking"}
|
disabled={updateCheckState() === "checking"}
|
||||||
onClick={() => void performUpdateCheck(true)}
|
onClick={() => void performUpdateCheck(true)}
|
||||||
|
title="点击查看更新内容"
|
||||||
>
|
>
|
||||||
{updateCheckState() === "checking" ? "检查中..." : "检查更新"}
|
<span class="text-zinc-400">版本</span>
|
||||||
|
<span class="shrink-0 rounded-full border border-zinc-200 bg-zinc-100 px-2 py-0.5 text-[11px] font-medium text-zinc-700">
|
||||||
|
{safeValue(versionText())}
|
||||||
|
</span>
|
||||||
|
{hasUpdateBadge() ? (
|
||||||
|
<span
|
||||||
|
class="h-2 w-2 shrink-0 rounded-full bg-rose-500"
|
||||||
|
title={`新版本:${latestRelease()?.tag_name ?? "-"}`}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
<span class="ml-auto text-[11px] text-zinc-400">
|
||||||
|
{updateCheckState() === "checking" ? "检查中..." : "查看更新"}
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
<details class="mt-2 rounded-lg border border-zinc-200/80 bg-white/70 px-2.5 py-2">
|
||||||
|
<summary class="cursor-pointer select-none text-[11px] text-zinc-500">
|
||||||
|
系统诊断信息
|
||||||
|
</summary>
|
||||||
|
<div class="mt-2 space-y-1 text-xs">
|
||||||
|
<p class={isDebugMode() ? "text-amber-600" : "text-zinc-600"}>
|
||||||
|
Mode: {safeValue(modeText())}
|
||||||
|
</p>
|
||||||
|
<p class="truncate text-zinc-600">Commit: {safeValue(commitText())}</p>
|
||||||
|
<p class="truncate text-zinc-600">Build: {safeValue(buildText())}</p>
|
||||||
|
<p class="truncate text-zinc-600">Author: {safeValue(authorText())}</p>
|
||||||
|
<p class="truncate text-zinc-600">Email: {safeValue(emailText())}</p>
|
||||||
</div>
|
</div>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
{updateCheckState() === "error" ? (
|
||||||
|
<p class="mt-2 text-xs text-rose-500">
|
||||||
|
{updateCheckError() || "更新检查失败"}
|
||||||
|
</p>
|
||||||
|
) : null}
|
||||||
{versionErrorText() ? (
|
{versionErrorText() ? (
|
||||||
<p class="mt-2 text-xs text-rose-500">{versionErrorText()}</p>
|
<p class="mt-2 text-xs text-rose-500">{versionErrorText()}</p>
|
||||||
) : null}
|
) : null}
|
||||||
@@ -488,7 +458,7 @@ const App: ParentComponent = (props) => {
|
|||||||
}
|
}
|
||||||
setUpdateDialogOpen(false);
|
setUpdateDialogOpen(false);
|
||||||
}}
|
}}
|
||||||
title={`发现更新 ${latestRelease()?.tag_name ?? ""}`}
|
title={updateDialogTitle()}
|
||||||
widthClass="max-w-3xl"
|
widthClass="max-w-3xl"
|
||||||
closeOnOverlay={downloadState() !== "downloading"}
|
closeOnOverlay={downloadState() !== "downloading"}
|
||||||
footer={
|
footer={
|
||||||
|
|||||||
@@ -283,7 +283,13 @@ const CourseWorkspace = (props: CourseWorkspaceProps) => {
|
|||||||
>
|
>
|
||||||
<For each={props.recordTypeOptions}>
|
<For each={props.recordTypeOptions}>
|
||||||
{(item) => (
|
{(item) => (
|
||||||
<option value={item.value}>{item.label}</option>
|
<option
|
||||||
|
value={item.value}
|
||||||
|
disabled={item.value === "/discuss"}
|
||||||
|
class={item.value === "/discuss" ? "text-zinc-400" : ""}
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</option>
|
||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
</select>
|
</select>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { createMemo, createSignal, For, onCleanup, onMount } from "solid-js";
|
import { createMemo, createSignal, For, onCleanup, onMount } from "solid-js";
|
||||||
import { fetchDebugConfig, updateDebugConfig } from "~/service/debugLog";
|
import { fetchDebugConfig, updateDebugConfig } from "~/service/debugLog";
|
||||||
import { hostApi } from "~/service/wk";
|
import { hostApi } from "~/service/wk";
|
||||||
import { getMergedHosts, settingsStore } from "~/store/settings";
|
import { getMergedHosts, settingsStore } from "~/store/settings";
|
||||||
@@ -117,56 +117,59 @@ const Setting = () => {
|
|||||||
void refreshDebugConfig();
|
void refreshDebugConfig();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const panelClass =
|
||||||
|
"rounded-[28px] border border-white/80 bg-white/85 p-5 shadow-[0_18px_50px_-28px_rgba(15,23,42,0.25)]";
|
||||||
|
const sectionCardClass = "rounded-2xl border border-zinc-200 bg-zinc-50/80 p-4";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="flex h-full min-h-0 flex-col overflow-hidden">
|
<div class="flex h-full min-h-0 flex-col overflow-hidden">
|
||||||
<div class="flex shrink-0 items-center justify-between gap-4 rounded-[28px] border border-white/80 bg-[linear-gradient(135deg,rgba(255,255,255,0.92),rgba(240,249,255,0.96))] px-5 py-4 shadow-[0_18px_45px_-28px_rgba(15,23,42,0.18)]">
|
<div class="flex shrink-0 items-center justify-between gap-4 rounded-[28px] border border-white/80 bg-[linear-gradient(125deg,rgba(255,255,255,0.96),rgba(240,249,255,0.95)_55%,rgba(236,254,255,0.9))] px-6 py-5 shadow-[0_22px_50px_-32px_rgba(15,23,42,0.22)]">
|
||||||
<div>
|
<div>
|
||||||
<p class="text-xs font-medium tracking-[0.26em] text-cyan-700/75 uppercase">
|
<p class="text-xs font-semibold tracking-[0.28em] text-cyan-700/80 uppercase">
|
||||||
Settings Center
|
Preference Center
|
||||||
</p>
|
</p>
|
||||||
<h1 class="mt-2 text-2xl font-semibold text-zinc-900">偏好设置</h1>
|
<h1 class="mt-2 text-2xl font-semibold text-zinc-900">偏好设置</h1>
|
||||||
<p class="mt-1 text-sm text-zinc-500">
|
<p class="mt-1 text-sm text-zinc-500">
|
||||||
管理本地缓存、界面偏好和 Host 来源策略
|
统一管理本地缓存、界面体验和 Host 来源策略
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="rounded-2xl border border-zinc-200 bg-white/90 px-4 py-3 text-right shadow-sm">
|
<div class="rounded-2xl border border-zinc-200/80 bg-white/90 px-4 py-3 text-right shadow-sm">
|
||||||
<p class="text-sm font-medium text-zinc-800">本地优先</p>
|
<p class="text-sm font-medium text-zinc-800">策略:本地优先</p>
|
||||||
<p class="mt-1 text-xs text-zinc-500">
|
<p class="mt-1 text-xs leading-5 text-zinc-500">
|
||||||
远端 Host 获取后会与本地列表合并去重
|
远端 Host 获取后会与本地列表合并去重
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-4 min-h-0 flex-1 overflow-y-auto pr-1">
|
<div class="mt-5 min-h-0 flex-1 overflow-hidden">
|
||||||
<div class="grid gap-4 xl:grid-cols-[minmax(0,1.1fr)_minmax(0,0.9fr)]">
|
<div class="grid h-full min-h-full w-full gap-5 lg:grid-cols-2">
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex min-h-0 h-full flex-col gap-5 overflow-y-auto pr-1">
|
||||||
<div class="rounded-[28px] border border-white/80 bg-white/85 p-4 shadow-[0_18px_50px_-28px_rgba(15,23,42,0.25)]">
|
<section class={panelClass}>
|
||||||
<div class="flex items-center justify-between gap-4">
|
<div class="flex items-center justify-between gap-4">
|
||||||
<div>
|
<div>
|
||||||
<p class="text-base font-semibold text-zinc-900">本地数据</p>
|
<p class="text-lg font-semibold text-zinc-900">本地数据</p>
|
||||||
<p class="mt-0.5 text-xs text-zinc-500">
|
<p class="mt-1 text-xs text-zinc-500">管理本地缓存数据</p>
|
||||||
管理本地缓存数据
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="rounded-lg border border-rose-200 bg-rose-50 px-2.5 py-1.5 text-xs text-rose-600 transition hover:bg-rose-100 active:bg-rose-200"
|
class="rounded-lg border border-rose-200 bg-rose-50 px-3 py-1.5 text-xs text-rose-600 transition hover:bg-rose-100 active:bg-rose-200"
|
||||||
onClick={() => settingsStore.getState().clearAllPersistedData()}
|
onClick={() => settingsStore.getState().clearAllPersistedData()}
|
||||||
>
|
>
|
||||||
清空全部
|
清空全部
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-3 grid gap-2">
|
<div class="mt-4 grid gap-3">
|
||||||
<div class="flex items-center justify-between gap-2 rounded-xl border border-zinc-200 bg-zinc-50/80 px-3 py-2">
|
<div class={sectionCardClass}>
|
||||||
|
<div class="flex items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<p class="text-sm font-medium text-zinc-900">账号缓存</p>
|
<p class="text-sm font-medium text-zinc-900">账号缓存</p>
|
||||||
<p class="text-xs text-zinc-500">账号、课程和登录信息</p>
|
<p class="mt-1 text-xs text-zinc-500">账号、课程和登录信息</p>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="rounded-lg border border-zinc-200 bg-white px-2 py-1 text-xs text-zinc-700 transition hover:bg-zinc-100 active:bg-zinc-200"
|
class="rounded-lg border border-zinc-200 bg-white px-2.5 py-1.5 text-xs text-zinc-700 transition hover:bg-zinc-100 active:bg-zinc-200"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
settingsStore.getState().clearPersistedSection("accounts")
|
settingsStore.getState().clearPersistedSection("accounts")
|
||||||
}
|
}
|
||||||
@@ -174,15 +177,17 @@ const Setting = () => {
|
|||||||
清空
|
清空
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center justify-between gap-2 rounded-xl border border-zinc-200 bg-zinc-50/80 px-3 py-2">
|
<div class={sectionCardClass}>
|
||||||
|
<div class="flex items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<p class="text-sm font-medium text-zinc-900">记录缓存</p>
|
<p class="text-sm font-medium text-zinc-900">记录缓存</p>
|
||||||
<p class="text-xs text-zinc-500">课程记录和筛选类型</p>
|
<p class="mt-1 text-xs text-zinc-500">课程记录和筛选类型</p>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="rounded-lg border border-zinc-200 bg-white px-2 py-1 text-xs text-zinc-700 transition hover:bg-zinc-100 active:bg-zinc-200"
|
class="rounded-lg border border-zinc-200 bg-white px-2.5 py-1.5 text-xs text-zinc-700 transition hover:bg-zinc-100 active:bg-zinc-200"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
settingsStore.getState().clearPersistedSection("records")
|
settingsStore.getState().clearPersistedSection("records")
|
||||||
}
|
}
|
||||||
@@ -190,15 +195,17 @@ const Setting = () => {
|
|||||||
清空
|
清空
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center justify-between gap-2 rounded-xl border border-zinc-200 bg-zinc-50/80 px-3 py-2">
|
<div class={sectionCardClass}>
|
||||||
|
<div class="flex items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<p class="text-sm font-medium text-zinc-900">日志缓存</p>
|
<p class="text-sm font-medium text-zinc-900">日志缓存</p>
|
||||||
<p class="text-xs text-zinc-500">任务日志历史</p>
|
<p class="mt-1 text-xs text-zinc-500">任务日志历史</p>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="rounded-lg border border-zinc-200 bg-white px-2 py-1 text-xs text-zinc-700 transition hover:bg-zinc-100 active:bg-zinc-200"
|
class="rounded-lg border border-zinc-200 bg-white px-2.5 py-1.5 text-xs text-zinc-700 transition hover:bg-zinc-100 active:bg-zinc-200"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
settingsStore.getState().clearPersistedSection("logs")
|
settingsStore.getState().clearPersistedSection("logs")
|
||||||
}
|
}
|
||||||
@@ -208,16 +215,18 @@ const Setting = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<div class="rounded-[28px] border border-white/80 bg-white/85 p-5 shadow-[0_18px_50px_-28px_rgba(15,23,42,0.25)]">
|
<section class={panelClass}>
|
||||||
|
<div class="border-b border-zinc-200/70 pb-4">
|
||||||
<p class="text-lg font-semibold text-zinc-900">界面偏好</p>
|
<p class="text-lg font-semibold text-zinc-900">界面偏好</p>
|
||||||
<p class="mt-1 text-sm text-zinc-500">
|
<p class="mt-1 text-sm text-zinc-500">
|
||||||
根据你的使用习惯调整侧栏、日志和展示密度
|
根据使用习惯调整日志行为、展示密度和侧栏尺寸
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-4 grid gap-4">
|
<div class="mt-4 grid gap-4 md:grid-cols-2">
|
||||||
<div class="rounded-2xl border border-zinc-200 bg-zinc-50/80 p-4">
|
<div class={`${sectionCardClass} md:col-span-2`}>
|
||||||
<div class="flex items-center justify-between gap-3">
|
<div class="flex items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<p class="font-medium text-zinc-900">手动开启调试</p>
|
<p class="font-medium text-zinc-900">手动开启调试</p>
|
||||||
@@ -236,9 +245,7 @@ const Setting = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div class="mt-3 rounded-xl border border-zinc-200 bg-white px-4 py-3 text-sm text-zinc-600">
|
<div class="mt-3 rounded-xl border border-zinc-200 bg-white px-4 py-3 text-sm text-zinc-600">
|
||||||
<p>后端状态:{backendDebugState()?.enabled ? "已开启" : "已关闭"}</p>
|
<p>后端状态:{backendDebugState()?.enabled ? "已开启" : "已关闭"}</p>
|
||||||
<p class="mt-1">
|
<p class="mt-1">编译模式:{backendDebugState()?.buildMode ?? "-"}</p>
|
||||||
编译模式:{backendDebugState()?.buildMode ?? "-"}
|
|
||||||
</p>
|
|
||||||
<p class="mt-1">
|
<p class="mt-1">
|
||||||
本地代理:
|
本地代理:
|
||||||
{backendDebugState()?.proxyConfigured
|
{backendDebugState()?.proxyConfigured
|
||||||
@@ -257,13 +264,11 @@ const Setting = () => {
|
|||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="rounded-2xl border border-zinc-200 bg-zinc-50/80 p-4">
|
<div class={sectionCardClass}>
|
||||||
<div class="flex items-center justify-between gap-3">
|
<div class="flex items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<p class="font-medium text-zinc-900">日志自动滚动</p>
|
<p class="font-medium text-zinc-900">日志自动滚动</p>
|
||||||
<p class="mt-1 text-sm text-zinc-500">
|
<p class="mt-1 text-sm text-zinc-500">新日志出现时自动滚动到底部</p>
|
||||||
新日志出现时自动滚动到最底部
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -277,13 +282,11 @@ const Setting = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="rounded-2xl border border-zinc-200 bg-zinc-50/80 p-4">
|
<div class={sectionCardClass}>
|
||||||
<div class="flex items-center justify-between gap-3">
|
<div class="flex items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<p class="font-medium text-zinc-900">显示日志时间戳</p>
|
<p class="font-medium text-zinc-900">显示日志时间戳</p>
|
||||||
<p class="mt-1 text-sm text-zinc-500">
|
<p class="mt-1 text-sm text-zinc-500">日志输出追加格式化时间</p>
|
||||||
后续日志输出可以追加格式化时间
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -297,12 +300,10 @@ const Setting = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="rounded-2xl border border-zinc-200 bg-zinc-50/80 p-4">
|
<div class={sectionCardClass}>
|
||||||
<label class="block">
|
<label class="block">
|
||||||
<p class="font-medium text-zinc-900">界面密度</p>
|
<p class="font-medium text-zinc-900">界面密度</p>
|
||||||
<p class="mt-1 text-sm text-zinc-500">
|
<p class="mt-1 text-sm text-zinc-500">选择更舒适或更紧凑的展示方式</p>
|
||||||
选择更舒适或更紧凑的展示方式
|
|
||||||
</p>
|
|
||||||
<select
|
<select
|
||||||
class="mt-3 w-full rounded-xl border border-zinc-200 bg-white px-4 py-3 transition outline-none focus:border-cyan-400"
|
class="mt-3 w-full rounded-xl border border-zinc-200 bg-white px-4 py-3 transition outline-none focus:border-cyan-400"
|
||||||
value={state().densityMode}
|
value={state().densityMode}
|
||||||
@@ -322,14 +323,12 @@ const Setting = () => {
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="rounded-2xl border border-zinc-200 bg-zinc-50/80 p-4">
|
<div class={sectionCardClass}>
|
||||||
<label class="block">
|
<label class="block">
|
||||||
<div class="flex items-center justify-between gap-3">
|
<div class="flex items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<p class="font-medium text-zinc-900">日志字号</p>
|
<p class="font-medium text-zinc-900">日志字号</p>
|
||||||
<p class="mt-1 text-sm text-zinc-500">
|
<p class="mt-1 text-sm text-zinc-500">当前:{state().logFontSize}px</p>
|
||||||
当前:{state().logFontSize}px
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
@@ -347,14 +346,12 @@ const Setting = () => {
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="rounded-2xl border border-zinc-200 bg-zinc-50/80 p-4">
|
<div class={`${sectionCardClass} md:col-span-2`}>
|
||||||
<label class="block">
|
<label class="block">
|
||||||
<div class="flex items-center justify-between gap-3">
|
<div class="flex items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<p class="font-medium text-zinc-900">侧栏宽度</p>
|
<p class="font-medium text-zinc-900">侧栏宽度</p>
|
||||||
<p class="mt-1 text-sm text-zinc-500">
|
<p class="mt-1 text-sm text-zinc-500">当前:{state().sidebarWidth}px</p>
|
||||||
当前:{state().sidebarWidth}px
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
@@ -373,20 +370,19 @@ const Setting = () => {
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex min-h-0 h-full flex-col gap-5 overflow-y-auto pr-1">
|
||||||
<div class="rounded-[28px] border border-white/80 bg-white/85 p-5 shadow-[0_18px_50px_-28px_rgba(15,23,42,0.25)]">
|
<section class={panelClass}>
|
||||||
<div class="border-b border-zinc-200 pb-4">
|
<div class="border-b border-zinc-200 pb-4">
|
||||||
<p class="text-lg font-semibold text-zinc-900">Host 配置策略</p>
|
<p class="text-lg font-semibold text-zinc-900">Host 配置策略</p>
|
||||||
<p class="mt-1 text-sm text-zinc-500">
|
<p class="mt-1 text-sm text-zinc-500">
|
||||||
远端 Host 后续通过接口请求,本地 Host
|
远端 Host 后续通过接口请求,本地 Host 手动添加,最终合并并去重,优先保留本地配置。
|
||||||
手动添加,最终合并并去重,优先保留本地配置。
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-4 rounded-2xl border border-zinc-200 bg-zinc-50/80 p-4">
|
<div class={`${sectionCardClass} mt-4`}>
|
||||||
<div class="flex items-center justify-between gap-3">
|
<div class="flex items-center justify-between gap-3">
|
||||||
<p class="font-medium text-zinc-900">添加本地 Host</p>
|
<p class="font-medium text-zinc-900">添加本地 Host</p>
|
||||||
<button
|
<button
|
||||||
@@ -426,9 +422,16 @@ const Setting = () => {
|
|||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class={panelClass}>
|
||||||
|
<div class="flex items-center justify-between border-b border-zinc-200 pb-4">
|
||||||
|
<p class="text-lg font-semibold text-zinc-900">Host 列表</p>
|
||||||
|
<p class="text-xs text-zinc-500">本地配置优先覆盖远端</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="mt-4 grid gap-4 xl:grid-cols-2">
|
<div class="mt-4 grid gap-4 xl:grid-cols-2">
|
||||||
<div class="rounded-2xl border border-zinc-200 bg-zinc-50/80 p-4">
|
<div class={sectionCardClass}>
|
||||||
<p class="font-medium text-zinc-900">本地 Host</p>
|
<p class="font-medium text-zinc-900">本地 Host</p>
|
||||||
<div class="mt-3 flex flex-col gap-3">
|
<div class="mt-3 flex flex-col gap-3">
|
||||||
<For each={state().localHosts}>
|
<For each={state().localHosts}>
|
||||||
@@ -436,20 +439,14 @@ const Setting = () => {
|
|||||||
<div class="rounded-xl border border-zinc-200 bg-white px-4 py-3">
|
<div class="rounded-xl border border-zinc-200 bg-white px-4 py-3">
|
||||||
<div class="flex items-start justify-between gap-3">
|
<div class="flex items-start justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<p class="font-medium text-zinc-900">
|
<p class="font-medium text-zinc-900">{item.label}</p>
|
||||||
{item.label}
|
<p class="mt-1 text-sm text-zinc-500">{item.host}</p>
|
||||||
</p>
|
|
||||||
<p class="mt-1 text-sm text-zinc-500">
|
|
||||||
{item.host}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="rounded-lg border border-rose-200 px-3 py-1 text-xs text-rose-600 transition hover:bg-rose-50 active:bg-rose-100"
|
class="rounded-lg border border-rose-200 px-3 py-1 text-xs text-rose-600 transition hover:bg-rose-50 active:bg-rose-100"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
settingsStore
|
settingsStore.getState().removeLocalHost(item.host)
|
||||||
.getState()
|
|
||||||
.removeLocalHost(item.host)
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
删除
|
删除
|
||||||
@@ -461,7 +458,7 @@ const Setting = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="rounded-2xl border border-zinc-200 bg-zinc-50/80 p-4">
|
<div class={sectionCardClass}>
|
||||||
<p class="font-medium text-zinc-900">合并结果</p>
|
<p class="font-medium text-zinc-900">合并结果</p>
|
||||||
<div class="mt-3 flex flex-col gap-3">
|
<div class="mt-3 flex flex-col gap-3">
|
||||||
<For each={mergedHosts()}>
|
<For each={mergedHosts()}>
|
||||||
@@ -478,6 +475,7 @@ const Setting = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user