Files
homelable/frontend/src/components/canvas/nodes/ProxmoxGroupNode.tsx
T
Pouzor 92d505f78c feat: add logo, favicon, and theme system
- Add custom SVG favicon and Logo component (house + network nodes motif)
- Update page title to Homelable with meta description
- Show Logo in sidebar header and toolbar
- Add theme store and ThemeModal for canvas style switching
- Refactor node colors and edge styles for theme support
2026-03-11 14:29:15 +01:00

146 lines
4.9 KiB
TypeScript

import { Handle, Position, NodeResizer, type NodeProps, type Node } from '@xyflow/react'
import { Layers } from 'lucide-react'
import type { NodeData } from '@/types'
import { resolveNodeColors } from '@/utils/nodeColors'
import { useThemeStore } from '@/stores/themeStore'
import { THEMES } from '@/utils/themes'
import { BaseNode } from './BaseNode'
export function ProxmoxGroupNode(props: NodeProps<Node<NodeData>>) {
const { data, selected } = props
const activeTheme = useThemeStore((s) => s.activeTheme)
const theme = THEMES[activeTheme]
const colors = resolveNodeColors(data, activeTheme)
// Render as a regular node when container mode is disabled
if (data.container_mode === false) {
const proxmoxAccent = theme.colors.nodeAccents.proxmox.border
return (
<>
<BaseNode {...props} icon={Layers} />
<Handle
type="source"
position={Position.Left}
id="cluster-left"
title="Same cluster"
style={{ background: proxmoxAccent, borderColor: `${proxmoxAccent}88`, width: 6, height: 6 }}
/>
<Handle
type="source"
position={Position.Right}
id="cluster-right"
title="Same cluster"
style={{ background: proxmoxAccent, borderColor: `${proxmoxAccent}88`, width: 6, height: 6 }}
/>
</>
)
}
const statusColor = theme.colors.statusColors[data.status]
const isOnline = data.status === 'online'
const glow = colors.border
const proxmoxAccent = theme.colors.nodeAccents.proxmox.border
return (
<>
<NodeResizer
minWidth={220}
minHeight={160}
isVisible={selected}
lineStyle={{ borderColor: glow, opacity: 0.6 }}
handleStyle={{ borderColor: glow, backgroundColor: theme.colors.nodeCardBackground }}
/>
{/* Group border */}
<div
className="w-full h-full rounded-xl border-2 flex flex-col overflow-hidden"
style={{
borderColor: selected ? glow : `${glow}88`,
background: isOnline ? `${colors.background}cc` : `${colors.background}aa`,
boxShadow: isOnline
? `0 0 20px ${glow}1a, inset 0 0 40px ${glow}08`
: selected
? `0 0 12px ${glow}33`
: 'none',
}}
>
{/* Header bar */}
<div
className="flex items-center gap-2 px-2.5 py-1.5 shrink-0"
style={{
background: isOnline ? `${glow}18` : `${theme.colors.nodeIconBackground}88`,
borderBottom: `1px solid ${isOnline ? `${glow}33` : theme.colors.handleBackground}`,
}}
>
<div
className="flex items-center justify-center w-5 h-5 rounded-md shrink-0"
style={{
color: isOnline ? colors.icon : theme.colors.nodeSubtextColor,
background: theme.colors.nodeIconBackground,
}}
>
<Layers size={12} />
</div>
<div className="flex flex-col min-w-0 flex-1">
<span
className="text-[11px] font-semibold leading-tight truncate"
style={{ color: isOnline ? glow : theme.colors.nodeLabelColor }}
>
{data.label}
</span>
{data.ip && (
<span
className="font-mono text-[9px] truncate"
style={{ color: theme.colors.nodeSubtextColor }}
>
{data.ip}
</span>
)}
</div>
{/* Status dot */}
<div
className="w-1.5 h-1.5 rounded-full shrink-0"
style={{ backgroundColor: statusColor }}
title={data.status}
/>
</div>
{/* Inner area — React Flow places children here */}
<div className="flex-1 relative" />
</div>
<Handle
type="source"
position={Position.Top}
id="top"
style={{ background: theme.colors.handleBackground, borderColor: theme.colors.handleBorder }}
/>
<Handle type="target" position={Position.Top} id="top-t" style={{ opacity: 0, width: 12, height: 12 }} />
<Handle
type="source"
position={Position.Bottom}
id="bottom"
style={{ background: theme.colors.handleBackground, borderColor: theme.colors.handleBorder }}
/>
<Handle type="target" position={Position.Bottom} id="bottom-t" style={{ opacity: 0, width: 12, height: 12 }} />
{/* Cluster handles */}
<Handle
type="source"
position={Position.Left}
id="cluster-left"
title="Same cluster"
style={{ background: proxmoxAccent, borderColor: `${proxmoxAccent}88`, width: 6, height: 6 }}
/>
<Handle
type="source"
position={Position.Right}
id="cluster-right"
title="Same cluster"
style={{ background: proxmoxAccent, borderColor: `${proxmoxAccent}88`, width: 6, height: 6 }}
/>
</>
)
}