fix(style): change tab style in 'server config' modal

This commit is contained in:
KodekaTeam committed 2026-06-23 23:20:26 +07:00
1 parent ec73a52aa9
commit 96c58c73ed
1 file changed
+90 -42
@@ -1,19 +1,13 @@
"use client";
import { type ReactNode, useCallback, useEffect, useState } from "react";
import { useCallback, useEffect, useState } from "react";
import { createPortal } from "react-dom";
import {
AlertTriangle,
Eye,
EyeOff,
Globe,
HardDrive,
Loader2,
Power,
RefreshCw,
Settings2,
Users,
Wrench,
X,
} from "lucide-react";
import {
@@ -87,6 +81,14 @@ export default function ServerConfigModal({
const deleteConfirmed = resetConfirmation.trim() === "DELETE";
const hasSelectedDockerPruneOption =
Object.values(dockerPruneOptions).some(Boolean);
const tabs: Array<{ id: ServerConfigTab; label: string }> = [
{ id: "overview", label: "Overview" },
{ id: "users", label: "Users" },
{ id: "services", label: "Services" },
{ id: "web-server", label: "Web Server" },
{ id: "mounts", label: "Disk Mounts" },
{ id: "actions", label: "Actions" },
];
const publishNotice = useCallback((nextNotice: ServerConfigNotice) => {
setNotice(nextNotice);
@@ -602,26 +604,26 @@ export default function ServerConfigModal({
}
};
const tabButton = (id: ServerConfigTab, label: string, icon: ReactNode) => (
const tabButton = (id: ServerConfigTab, label: string) => (
<button
type="button"
key={id}
onClick={() => setActiveTab(id)}
className="btn btn-ghost"
style={{
padding: "9px 14px",
borderRadius: 10,
border: `1px solid ${activeTab === id ? "rgba(59,130,246,0.35)" : "var(--border)"}`,
background:
activeTab === id ? "rgba(59,130,246,0.12)" : "var(--bg-input)",
color: activeTab === id ? "#3b82f6" : "var(--text-secondary)",
display: "inline-flex",
alignItems: "center",
gap: 8,
cursor: "pointer",
height: 28,
minHeight: 28,
padding: "5px 12px",
borderRadius: 4,
boxSizing: "border-box",
borderColor: activeTab === id ? "rgba(59,130,246,0.5)" : "transparent",
background: activeTab === id ? "rgba(59,130,246,0.16)" : "transparent",
color:
activeTab === id ? "var(--accent-blue)" : "var(--text-secondary)",
flex: "0 0 auto",
fontSize: 12,
fontWeight: 600,
}}
>
{icon}
{label}
</button>
);
@@ -643,10 +645,12 @@ export default function ServerConfigModal({
position: "relative",
width: "100%",
maxWidth: 920,
maxHeight: "90vh",
padding: 24,
display: "flex",
flexDirection: "column",
gap: 18,
overflow: "hidden",
}}
>
{pendingConfirm && typeof document !== "undefined"
@@ -675,7 +679,9 @@ export default function ServerConfigModal({
}}
>
<div>
<strong style={{ color: "var(--text-primary)", fontSize: 16 }}>
<strong
style={{ color: "var(--text-primary)", fontSize: 16 }}
>
{pendingConfirm.title}
</strong>
<p
@@ -715,7 +721,8 @@ export default function ServerConfigModal({
{
key: "containers",
label: "Stopped containers",
description: "Equivalent to docker container prune.",
description:
"Equivalent to docker container prune.",
},
{
key: "networks",
@@ -808,7 +815,9 @@ export default function ServerConfigModal({
padding: "12px 14px",
fontSize: 12,
color:
pendingConfirm.tone === "danger" ? "#ef4444" : "#b45309",
pendingConfirm.tone === "danger"
? "#ef4444"
: "#b45309",
background:
pendingConfirm.tone === "danger"
? "rgba(239,68,68,0.08)"
@@ -823,7 +832,11 @@ export default function ServerConfigModal({
interruption or cleanup change on the host.
</div>
<div
style={{ display: "flex", gap: 10, justifyContent: "flex-end" }}
style={{
display: "flex",
gap: 10,
justifyContent: "flex-end",
}}
>
<button
className="btn"
@@ -864,7 +877,9 @@ export default function ServerConfigModal({
}
if (currentConfirm.kind === "service") {
void handleServiceRestart(currentConfirm.serviceName);
void handleServiceRestart(
currentConfirm.serviceName,
);
return;
}
@@ -885,7 +900,9 @@ export default function ServerConfigModal({
? "rgba(239,68,68,0.12)"
: "rgba(245,158,11,0.12)",
color:
pendingConfirm.tone === "danger" ? "#ef4444" : "#f59e0b",
pendingConfirm.tone === "danger"
? "#ef4444"
: "#f59e0b",
border:
pendingConfirm.tone === "danger"
? "1px solid rgba(239,68,68,0.22)"
@@ -944,15 +961,23 @@ export default function ServerConfigModal({
/>
</div>
<p
style={{ color: "var(--text-muted)", fontSize: 13, marginTop: 6 }}
style={{
color: "var(--text-muted)",
fontSize: 13,
marginTop: 6,
}}
>
{server.name} • {server.ip}:{server.sshPort}
</p>
<p
style={{ color: "var(--text-muted)", fontSize: 12, marginTop: 6 }}
style={{
color: "var(--text-muted)",
fontSize: 12,
marginTop: 6,
}}
>
Snapshot refresh runs only when this modal opens or when you click
Refresh.
Snapshot refresh runs only when this modal opens or when you
click Refresh.
</p>
</div>
<div style={{ display: "flex", gap: 8, paddingRight: 36 }}>
@@ -966,15 +991,33 @@ export default function ServerConfigModal({
</div>
</div>
<div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
{tabButton("overview", "Overview", <Settings2 size={14} />)}
{tabButton("users", "Users", <Users size={14} />)}
{tabButton("services", "Services", <Wrench size={14} />)}
{tabButton("web-server", "Web Server", <Globe size={14} />)}
{tabButton("mounts", "Disk Mounts", <HardDrive size={14} />)}
{tabButton("actions", "Actions", <Power size={14} />)}
</div>
<nav
className="ui-tab-scroll no-scrollbar"
style={{
width: "100%",
borderRadius: 6,
background: "var(--bg-card)",
minWidth: 0,
minHeight: 38,
alignItems: "center",
overflowY: "hidden",
flex: "0 0 auto",
}}
aria-label="Server config sections"
>
{tabs.map((tab) => tabButton(tab.id, tab.label))}
</nav>
<div
style={{
display: "grid",
flex: "1 1 auto",
gap: 18,
minHeight: 0,
overflowY: "auto",
paddingRight: 2,
}}
>
{notice && notice.tab === activeTab ? (
<div
style={{
@@ -1048,7 +1091,11 @@ export default function ServerConfigModal({
onClick={() => setNoticeExpanded((current) => !current)}
style={{ width: "fit-content" }}
>
{noticeExpanded ? <EyeOff size={12} /> : <Eye size={12} />}
{noticeExpanded ? (
<EyeOff size={12} />
) : (
<Eye size={12} />
)}
{noticeExpanded ? "Hide detail" : "More detail"}
</button>
{noticeExpanded ? (
@@ -1127,9 +1174,9 @@ export default function ServerConfigModal({
lineHeight: 1.6,
}}
>
The server did not return a full config snapshot, so this modal
is showing fallback information. Recovery actions remain
available, especially in the Actions tab.
The server did not return a full config snapshot, so this
modal is showing fallback information. Recovery actions
remain available, especially in the Actions tab.
</p>
</div>
<IssueDetailsSummary
@@ -1157,5 +1204,6 @@ export default function ServerConfigModal({
</div>
</div>
</div>
</div>
);
}