refactor: 根级 src/src-tauri/server 布局 + 设置左导航搜索 + 语言切换 + DataGrip 高亮 + 断连横幅移除

This commit is contained in:
logan committed 2026-10-14 20:51:59 +08:00
1 parent 456fa6954b
commit b3542cb458
32 files changed
+148 -58

No files matched your search

+26 -7
View File
@@ -82,6 +82,7 @@ export function SettingsModal({ onClose }: { onClose: () => void }) {
const openConnectionList = useWorkspaceStore((s) => s.openConnectionList);
const [drivers, setDrivers] = useState<DriverStatusItem[] | null>(null);
const [navSearch, setNavSearch] = useState("");
const [version, setVersion] = useState<string>("");
useEffect(() => {
@@ -99,19 +100,37 @@ export function SettingsModal({ onClose }: { onClose: () => void }) {
return (
<OpsModal variant="info" title="设置" onOk={onClose}>
<div className="flex" style={{ minWidth: 560, minHeight: 340 }}>
{/* 左导航 */}
<nav className="w-36 shrink-0 space-y-px border-r pr-1" style={{ borderColor: "var(--ops-border-soft)" }}>
{TABS.map((t) => (
{/* 左导航:搜索 + 图标主标题 + 副文案(对齐 opsxshell 质感) */}
<nav className="w-52 shrink-0 border-r pr-1" style={{ borderColor: "var(--ops-border-soft)" }}>
<input
className="ops-input mb-2 h-7 w-full text-[12px]"
placeholder="搜索设置…"
value={navSearch}
onChange={(e) => setNavSearch(e.target.value)}
/>
{TABS.filter((t) => {
const q = navSearch.trim().toLowerCase();
if (!q) return true;
return (t.label + t.desc).toLowerCase().includes(q);
}).map((t) => (
<button
key={t.id}
type="button"
className={`flex w-full items-center gap-2 rounded px-2 py-1.5 text-left text-[12px] transition ${
tab === t.id ? "ops-tree-item-active font-medium" : "opacity-70 hover:opacity-100"
className={`flex w-full items-center gap-2 rounded px-2 py-2 text-left transition ${
tab === t.id
? "bg-[color-mix(in_srgb,var(--ops-accent)_12%,transparent)]"
: "opacity-75 hover:opacity-100"
}`}
style={tab === t.id ? { boxShadow: "inset 2px 0 0 var(--ops-accent)" } : undefined}
onClick={() => setTab(t.id)}
>
<span className="w-4 text-center">{t.icon}</span>
<span>{t.label}</span>
<span className="w-4 text-center text-[13px]" style={tab === t.id ? { color: "var(--ops-accent)" } : { color: "var(--ops-muted)" }}>
{t.icon}
</span>
<span className="min-w-0 flex-1">
<span className="block text-[12px] font-medium">{t.label}</span>
<span className="block text-[10px]" style={{ color: "var(--ops-muted)" }}>{t.desc}</span>
</span>
</button>
))}
</nav>
+15 -15
View File
@@ -58,27 +58,27 @@ function redisComplete(ctx: CompletionContext): CompletionResult | null {
}
/**
* SQL 高亮走克制的四色方案(VS Code Dark+ 观感):
* 关键字+数字 = 蓝,字符串 = 橙,注释 = 绿,标识符/运算符 = 前景浅白。
* 注册在 oneDark 之后,覆盖其默认的五彩配色。
* SQL 高亮:DataGrip Dark 风格(用户点单对照截图)——
* 关键字 = 亮蓝加粗,字符串 = 红,数字 = 浅绿,标识符 = 浅灰白,注释 = 灰斜体。
* 注册在 oneDark 之后,覆盖其默认配色。
*/
const sqlDarkHighlight = HighlightStyle.define([
{ tag: [t.keyword, t.controlKeyword, t.moduleKeyword, t.operatorKeyword, t.definitionKeyword], color: "#569CD6" },
{ tag: [t.number, t.integer, t.bool, t.null, t.atom], color: "#569CD6" },
{ tag: [t.string, t.special(t.string)], color: "#CE9178" },
{ tag: [t.lineComment, t.blockComment, t.docComment], color: "#6A9955" },
{ tag: [t.variableName, t.typeName, t.propertyName, t.operator, t.punctuation, t.definition(t.variableName)], color: "#D4D4D4" },
{ tag: [t.function(t.variableName), t.function(t.propertyName)], color: "#D4D4D4" },
{ tag: [t.keyword, t.controlKeyword, t.moduleKeyword, t.operatorKeyword, t.definitionKeyword], color: "#39A5FF", fontWeight: "700" },
{ tag: [t.number, t.integer, t.bool, t.null, t.atom], color: "#98C379" },
{ tag: [t.string, t.special(t.string)], color: "#E06C75" },
{ tag: [t.lineComment, t.blockComment, t.docComment], color: "#7A7A7A", fontStyle: "italic" },
{ tag: [t.variableName, t.typeName, t.propertyName, t.operator, t.punctuation, t.definition(t.variableName)], color: "#A9B7C6" },
{ tag: [t.function(t.variableName), t.function(t.propertyName)], color: "#E8E8E8" },
]);
/** 浅色主题四色方案:关键字蓝、字符串枣红、注释绿、标识符近黑 */
const sqlLightHighlight = HighlightStyle.define([
{ tag: [t.keyword, t.controlKeyword, t.moduleKeyword, t.operatorKeyword, t.definitionKeyword], color: "#0000FF" },
{ tag: [t.number, t.integer, t.bool, t.null, t.atom], color: "#0000FF" },
{ tag: [t.string, t.special(t.string)], color: "#A31515" },
{ tag: [t.lineComment, t.blockComment, t.docComment], color: "#008000" },
{ tag: [t.variableName, t.typeName, t.propertyName, t.operator, t.punctuation, t.definition(t.variableName)], color: "#24292F" },
{ tag: [t.function(t.variableName), t.function(t.propertyName)], color: "#24292F" },
{ tag: [t.keyword, t.controlKeyword, t.moduleKeyword, t.operatorKeyword, t.definitionKeyword], color: "#0033B3", fontWeight: "700" },
{ tag: [t.number, t.integer, t.bool, t.null, t.atom], color: "#1750EB" },
{ tag: [t.string, t.special(t.string)], color: "#067D17" },
{ tag: [t.lineComment, t.blockComment, t.docComment], color: "#8C8C8C", fontStyle: "italic" },
{ tag: [t.variableName, t.typeName, t.propertyName, t.operator, t.punctuation, t.definition(t.variableName)], color: "#000000" },
{ tag: [t.function(t.variableName), t.function(t.propertyName)], color: "#000000" },
]);
export type SqlEditorHandle = {
-24
View File
@@ -1365,7 +1365,6 @@ export function OpsxWorkspace() {
const activeConnectionId = useWorkspaceStore((s) => s.activeConnectionId);
const connections = useWorkspaceStore((s) => s.connections);
const connState = useWorkspaceStore((s) => s.connState);
const [dismissDown, setDismissDown] = useState(false);
const conn = useWorkspaceStore((s) => s.connections.find((c) => c.id === s.activeConnectionId)); const set = useWorkspaceStore((s) => s.set);
useEffect(() => {
@@ -1498,7 +1497,6 @@ export function OpsxWorkspace() {
// 新断开时重新显示提示(用户上次关闭后,再次断开要能看见)。必须位于 view 早退之前,否则切到选择器视图时 hooks 数量变化会崩溃。
useEffect(() => {
if (connState === "down") setDismissDown(false);
}, [connState]);
if (view === "picker") {
@@ -1515,28 +1513,6 @@ export function OpsxWorkspace() {
<div className="ops-shell flex h-screen min-h-[640px] flex-col">
<TopNav />
{launchStrip}
{connState === "down" && !dismissDown && (
<div
className="flex shrink-0 items-center gap-2 border-b px-2.5 text-[11px]"
style={{
height: 28,
borderColor: "color-mix(in srgb, var(--ops-danger) 35%, var(--ops-border))",
background: "color-mix(in srgb, var(--ops-danger) 8%, transparent)",
color: "var(--ops-danger)",
}}
>
<span>⚠ {conn ? `${conn.name} 已断开` : "连接已断开"}</span>
<button
type="button"
className="ml-auto px-1 text-[13px] leading-none"
style={{ color: "var(--ops-muted)" }}
title="关闭提示"
onClick={() => setDismissDown(true)}
>
×
</button>
</div>
)}
<div className="flex min-h-0 flex-1">
<aside className="ops-panel flex h-full shrink-0 flex-col border-r" style={{ width: leftWidth }}>
<div className="min-h-0 flex-1 overflow-auto">