[Init] Initial commit - NetMesh terminal manager
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
This commit is contained in:
187
domain/hostIcon.ts
Normal file
187
domain/hostIcon.ts
Normal file
@@ -0,0 +1,187 @@
|
||||
import type { Host, HostIconColorId, HostIconColorMode, HostIconId, HostIconMode } from "./models";
|
||||
|
||||
export const DEFAULT_HOST_ICON_ID: HostIconId = "server";
|
||||
export const DEFAULT_HOST_ICON_COLOR: HostIconColorId = "blue";
|
||||
|
||||
export const HOST_ICON_IDS = [
|
||||
"server",
|
||||
"terminal",
|
||||
"database",
|
||||
"cloud",
|
||||
"router",
|
||||
"shield",
|
||||
"code",
|
||||
"box",
|
||||
"globe",
|
||||
"cpu",
|
||||
"hard-drive",
|
||||
"network",
|
||||
"wifi",
|
||||
"lock",
|
||||
"key",
|
||||
"monitor",
|
||||
"container",
|
||||
"activity",
|
||||
"zap",
|
||||
"server-cog",
|
||||
] as const satisfies readonly HostIconId[];
|
||||
|
||||
export const HOST_ICON_COLORS = [
|
||||
{ id: "blue", hex: "#2563EB" },
|
||||
{ id: "green", hex: "#16A34A" },
|
||||
{ id: "red", hex: "#DC2626" },
|
||||
{ id: "amber", hex: "#B45309" },
|
||||
{ id: "purple", hex: "#9333EA" },
|
||||
{ id: "cyan", hex: "#0891B2" },
|
||||
{ id: "orange", hex: "#EA580C" },
|
||||
{ id: "slate", hex: "#475569" },
|
||||
{ id: "violet", hex: "#7C3AED" },
|
||||
{ id: "pink", hex: "#DB2777" },
|
||||
{ id: "rose", hex: "#E11D48" },
|
||||
{ id: "lime", hex: "#65A30D" },
|
||||
{ id: "teal", hex: "#0D9488" },
|
||||
{ id: "sky", hex: "#0284C7" },
|
||||
{ id: "indigo", hex: "#4F46E5" },
|
||||
{ id: "zinc", hex: "#52525B" },
|
||||
] as const satisfies readonly { id: HostIconColorId; hex: string }[];
|
||||
|
||||
export const HOST_ICON_DEFAULT_COLORS = {
|
||||
"server": "blue",
|
||||
"terminal": "slate",
|
||||
"database": "cyan",
|
||||
"cloud": "sky",
|
||||
"router": "orange",
|
||||
"shield": "green",
|
||||
"code": "violet",
|
||||
"box": "amber",
|
||||
"globe": "teal",
|
||||
"cpu": "indigo",
|
||||
"hard-drive": "zinc",
|
||||
"network": "lime",
|
||||
"wifi": "purple",
|
||||
"lock": "rose",
|
||||
"key": "amber",
|
||||
"monitor": "sky",
|
||||
"container": "teal",
|
||||
"activity": "red",
|
||||
"zap": "orange",
|
||||
"server-cog": "slate",
|
||||
} as const satisfies Record<HostIconId, HostIconColorId>;
|
||||
|
||||
export type HostIconAppearance = {
|
||||
iconId: HostIconId;
|
||||
colorId?: HostIconColorId;
|
||||
colorHex: string;
|
||||
};
|
||||
|
||||
export type HostIconColorAppearance = {
|
||||
colorId?: HostIconColorId;
|
||||
colorHex: string;
|
||||
};
|
||||
|
||||
export const isHostIconMode = (value: unknown): value is HostIconMode =>
|
||||
value === "auto" || value === "custom";
|
||||
|
||||
export const isHostIconId = (value: unknown): value is HostIconId =>
|
||||
typeof value === "string" && (HOST_ICON_IDS as readonly string[]).includes(value);
|
||||
|
||||
export const isHostIconColorId = (value: unknown): value is HostIconColorId =>
|
||||
typeof value === "string" && HOST_ICON_COLORS.some((color) => color.id === value);
|
||||
|
||||
export const isHostIconColorMode = (value: unknown): value is HostIconColorMode =>
|
||||
value === "auto" || value === "manual";
|
||||
|
||||
export const isHostIconCustomColor = (value: unknown): value is string =>
|
||||
typeof value === "string" && /^#[0-9a-fA-F]{6}$/.test(value);
|
||||
|
||||
const resolveColorHex = (colorId: HostIconColorId): string =>
|
||||
HOST_ICON_COLORS.find((color) => color.id === colorId)?.hex || HOST_ICON_COLORS[0].hex;
|
||||
|
||||
export const resolveHostIconDefaultColorHex = (iconId: HostIconId): string =>
|
||||
resolveColorHex(HOST_ICON_DEFAULT_COLORS[iconId] || DEFAULT_HOST_ICON_COLOR);
|
||||
|
||||
export const resolveHostIconColorAppearance = (
|
||||
host: Partial<Pick<Host, "iconColorMode" | "iconColor" | "iconColorCustom">>,
|
||||
): HostIconColorAppearance | null => {
|
||||
const manualColor = host.iconColorMode === "manual" ||
|
||||
(host.iconColorMode !== "auto" && (isHostIconColorId(host.iconColor) || isHostIconCustomColor(host.iconColorCustom)));
|
||||
if (!manualColor) return null;
|
||||
if (isHostIconCustomColor(host.iconColorCustom)) {
|
||||
return {
|
||||
colorHex: host.iconColorCustom,
|
||||
};
|
||||
}
|
||||
return {
|
||||
colorId: isHostIconColorId(host.iconColor) ? host.iconColor : DEFAULT_HOST_ICON_COLOR,
|
||||
colorHex: resolveColorHex(isHostIconColorId(host.iconColor) ? host.iconColor : DEFAULT_HOST_ICON_COLOR),
|
||||
};
|
||||
};
|
||||
|
||||
export const resolveHostIconAppearance = (
|
||||
host: Partial<Pick<Host, "iconMode" | "iconId" | "iconColorMode" | "iconColor" | "iconColorCustom">>,
|
||||
): HostIconAppearance | null => {
|
||||
if (host.iconMode !== "custom") return null;
|
||||
if (!isHostIconId(host.iconId)) return null;
|
||||
const color = resolveHostIconColorAppearance(host);
|
||||
return {
|
||||
iconId: host.iconId,
|
||||
...(color?.colorId ? { colorId: color.colorId } : {}),
|
||||
colorHex: color?.colorHex || resolveHostIconDefaultColorHex(host.iconId),
|
||||
};
|
||||
};
|
||||
|
||||
export const normalizeHostIconSelection = <T extends Partial<Pick<Host, "iconMode" | "iconId" | "iconColorMode" | "iconColor" | "iconColorCustom">>>(
|
||||
host: T,
|
||||
): Pick<Host, "iconMode" | "iconId" | "iconColorMode" | "iconColor" | "iconColorCustom"> => {
|
||||
const iconColorMode = host.iconColorMode === "manual" ||
|
||||
(host.iconColorMode !== "auto" && (isHostIconColorId(host.iconColor) || isHostIconCustomColor(host.iconColorCustom)))
|
||||
? "manual"
|
||||
: undefined;
|
||||
const iconColor = iconColorMode === "manual" && isHostIconColorId(host.iconColor) ? host.iconColor : undefined;
|
||||
const iconColorCustom = iconColorMode === "manual" && isHostIconCustomColor(host.iconColorCustom) ? host.iconColorCustom : undefined;
|
||||
const colorFields = {
|
||||
...(iconColorMode ? { iconColorMode } : {}),
|
||||
...(iconColor ? { iconColor } : {}),
|
||||
...(iconColorCustom ? { iconColorCustom } : {}),
|
||||
};
|
||||
if (host.iconMode !== "custom") {
|
||||
return iconColorMode ? { iconMode: "auto", ...colorFields } : {};
|
||||
}
|
||||
const iconId = isHostIconId(host.iconId) ? host.iconId : DEFAULT_HOST_ICON_ID;
|
||||
return { iconMode: "custom", iconId, ...colorFields };
|
||||
};
|
||||
|
||||
export const sanitizeHostIconFields = <T extends Partial<Pick<Host, "iconMode" | "iconId" | "iconColorMode" | "iconColor" | "iconColorCustom">>>(
|
||||
host: T,
|
||||
): Pick<Host, "iconMode" | "iconId" | "iconColorMode" | "iconColor" | "iconColorCustom"> => {
|
||||
const iconColorMode = host.iconColorMode === "manual" ||
|
||||
(host.iconColorMode !== "auto" && (isHostIconColorId(host.iconColor) || isHostIconCustomColor(host.iconColorCustom)))
|
||||
? "manual"
|
||||
: undefined;
|
||||
const iconColor = iconColorMode === "manual" && isHostIconColorId(host.iconColor) ? host.iconColor : undefined;
|
||||
const iconColorCustom = iconColorMode === "manual" && isHostIconCustomColor(host.iconColorCustom) ? host.iconColorCustom : undefined;
|
||||
const colorFields = {
|
||||
...(iconColorMode ? { iconColorMode } : {}),
|
||||
...(iconColor ? { iconColor } : {}),
|
||||
...(iconColorCustom ? { iconColorCustom } : {}),
|
||||
};
|
||||
if (host.iconMode !== "custom") {
|
||||
return iconColorMode ? { iconMode: "auto", ...colorFields } : {};
|
||||
}
|
||||
if (!isHostIconId(host.iconId)) return {};
|
||||
return { iconMode: "custom", iconId: host.iconId, ...colorFields };
|
||||
};
|
||||
|
||||
export const clearHostIconAppearance = <T extends Record<string, unknown>>(
|
||||
host: T,
|
||||
): Omit<T, "iconMode" | "iconId" | "iconColorMode" | "iconColor" | "iconColorCustom"> => {
|
||||
const {
|
||||
iconMode: _iconMode,
|
||||
iconId: _iconId,
|
||||
iconColorMode: _iconColorMode,
|
||||
iconColor: _iconColor,
|
||||
iconColorCustom: _iconColorCustom,
|
||||
...rest
|
||||
} = host;
|
||||
return rest;
|
||||
};
|
||||
Reference in New Issue
Block a user