From 42a9f1d31a0b8e2f6a461f6a973ea195470afd6c Mon Sep 17 00:00:00 2001 From: David Culbreth Date: Mon, 2 Mar 2026 12:03:20 -0600 Subject: [PATCH] branding v1 --- web/index.html | 20 +- web/public/attune-favicon.svg | 44 ++ web/public/attune-logo-full.svg | 152 ++++++ web/public/attune-logo-icon.svg | 71 +++ web/public/attune-logo-navbar.svg | 124 +++++ web/public/attune-logo-static.svg | 83 +++ web/public/attune-logo-watermark-tile.svg | 65 +++ web/public/attune-logo.svg | 139 +++++ web/src/components/layout/MainLayout.tsx | 477 ++++++++++-------- web/src/components/workflows/TaskNode.tsx | 4 +- .../components/workflows/WorkflowCanvas.tsx | 44 +- .../components/workflows/WorkflowEdges.tsx | 8 +- web/src/index.css | 8 + web/src/pages/actions/ActionsPage.tsx | 2 +- web/src/pages/actions/WorkflowBuilderPage.tsx | 4 +- web/src/pages/executions/ExecutionsPage.tsx | 2 +- web/src/pages/packs/PacksPage.tsx | 2 +- web/src/pages/rules/RulesPage.tsx | 2 +- web/src/pages/sensors/SensorsPage.tsx | 2 +- web/src/pages/triggers/TriggersPage.tsx | 2 +- 20 files changed, 1014 insertions(+), 241 deletions(-) create mode 100644 web/public/attune-favicon.svg create mode 100644 web/public/attune-logo-full.svg create mode 100644 web/public/attune-logo-icon.svg create mode 100644 web/public/attune-logo-navbar.svg create mode 100644 web/public/attune-logo-static.svg create mode 100644 web/public/attune-logo-watermark-tile.svg create mode 100644 web/public/attune-logo.svg diff --git a/web/index.html b/web/index.html index af88f03..da887f8 100644 --- a/web/index.html +++ b/web/index.html @@ -1,13 +1,13 @@ - - - - - web - - -
- - + + + + + Attune + + +
+ + diff --git a/web/public/attune-favicon.svg b/web/public/attune-favicon.svg new file mode 100644 index 0000000..c5dfa0a --- /dev/null +++ b/web/public/attune-favicon.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/public/attune-logo-full.svg b/web/public/attune-logo-full.svg new file mode 100644 index 0000000..6095e52 --- /dev/null +++ b/web/public/attune-logo-full.svg @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ttune + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/public/attune-logo-icon.svg b/web/public/attune-logo-icon.svg new file mode 100644 index 0000000..6a81e86 --- /dev/null +++ b/web/public/attune-logo-icon.svg @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/public/attune-logo-navbar.svg b/web/public/attune-logo-navbar.svg new file mode 100644 index 0000000..a0971be --- /dev/null +++ b/web/public/attune-logo-navbar.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ttune + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/public/attune-logo-static.svg b/web/public/attune-logo-static.svg new file mode 100644 index 0000000..805f4c8 --- /dev/null +++ b/web/public/attune-logo-static.svg @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/public/attune-logo-watermark-tile.svg b/web/public/attune-logo-watermark-tile.svg new file mode 100644 index 0000000..fa6e02e --- /dev/null +++ b/web/public/attune-logo-watermark-tile.svg @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/public/attune-logo.svg b/web/public/attune-logo.svg new file mode 100644 index 0000000..5d5cdd0 --- /dev/null +++ b/web/public/attune-logo.svg @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/src/components/layout/MainLayout.tsx b/web/src/components/layout/MainLayout.tsx index 73a39c9..e345bae 100644 --- a/web/src/components/layout/MainLayout.tsx +++ b/web/src/components/layout/MainLayout.tsx @@ -18,6 +18,152 @@ import { Home, } from "lucide-react"; +// Color mappings for navigation items — defined outside component for stable reference +const colorClasses = { + gray: { + inactive: "text-gray-300 hover:text-white hover:bg-gray-800", + active: "bg-gray-800 text-white", + icon: "text-gray-400", + }, + cyan: { + inactive: "text-cyan-300 hover:text-cyan-100 hover:bg-cyan-950/30", + active: "bg-cyan-950/50 text-cyan-100 shadow-lg shadow-cyan-900/50", + icon: "text-cyan-400", + }, + blue: { + inactive: "text-blue-300 hover:text-blue-100 hover:bg-blue-950/30", + active: "bg-blue-950/50 text-blue-100 shadow-lg shadow-blue-900/50", + icon: "text-blue-400", + }, + violet: { + inactive: "text-violet-300 hover:text-violet-100 hover:bg-violet-950/30", + active: "bg-violet-950/50 text-violet-100 shadow-lg shadow-violet-900/50", + icon: "text-violet-400", + }, + purple: { + inactive: "text-purple-300 hover:text-purple-100 hover:bg-purple-950/30", + active: "bg-purple-950/50 text-purple-100 shadow-lg shadow-purple-900/50", + icon: "text-purple-400", + }, + fuchsia: { + inactive: "text-fuchsia-300 hover:text-fuchsia-100 hover:bg-fuchsia-950/30", + active: + "bg-fuchsia-950/50 text-fuchsia-100 shadow-lg shadow-fuchsia-900/50", + icon: "text-fuchsia-400", + }, + rose: { + inactive: "text-rose-300 hover:text-rose-100 hover:bg-rose-950/30", + active: "bg-rose-950/50 text-rose-100 shadow-lg shadow-rose-900/50", + icon: "text-rose-400", + }, + orange: { + inactive: "text-orange-300 hover:text-orange-100 hover:bg-orange-950/30", + active: "bg-orange-950/50 text-orange-100 shadow-lg shadow-orange-900/50", + icon: "text-orange-400", + }, +}; + +// Navigation sections with dividers and colors +const navSections = [ + { + items: [{ to: "/", label: "Dashboard", icon: Home, color: "gray" }], + }, + { + // Component Management - Cool colors (cyan -> blue -> violet) + items: [ + { to: "/actions", label: "Actions", icon: SquarePlay, color: "cyan" }, + { to: "/rules", label: "Rules", icon: SquareArrowRight, color: "blue" }, + { + to: "/triggers", + label: "Triggers", + icon: SquareDot, + color: "violet", + }, + { + to: "/sensors", + label: "Sensors", + icon: SquareAsterisk, + color: "purple", + }, + ], + }, + { + // Runtime Logs - Warm colors (fuchsia -> rose -> orange) + items: [ + { + to: "/executions", + label: "Execution History", + icon: CirclePlay, + color: "fuchsia", + }, + { + to: "/enforcements", + label: "Enforcement History", + icon: CircleArrowRight, + color: "rose", + }, + { + to: "/events", + label: "Event History", + icon: CircleDot, + color: "orange", + }, + ], + }, + { + items: [ + { to: "/keys", label: "Keys & Secrets", icon: KeyRound, color: "gray" }, + { + to: "/packs", + label: "Pack Management", + icon: Package, + color: "gray", + }, + ], + }, +]; + +// NavLink extracted outside MainLayout so React preserves DOM identity across +// re-renders, which is required for CSS transitions to work on collapse/expand. +function NavLink({ + to, + label, + icon: Icon, + color = "gray", + isCollapsed, + isActive, +}: { + to: string; + label: string; + icon: React.ElementType; + color?: string; + isCollapsed: boolean; + isActive: boolean; +}) { + const colors = + colorClasses[color as keyof typeof colorClasses] || colorClasses.gray; + + return ( + + + + {label} + + + ); +} + export default function MainLayout() { const { user, logout } = useAuth(); const navigate = useNavigate(); @@ -34,184 +180,63 @@ export default function MainLayout() { localStorage.setItem("sidebar-collapsed", isCollapsed.toString()); }, [isCollapsed]); + // Close user menu when expanding sidebar + useEffect(() => { + if (!isCollapsed) { + setShowUserMenu(false); + } + }, [isCollapsed]); + const handleLogout = () => { logout(); navigate("/login"); }; - // Navigation sections with dividers and colors - const navSections = [ - { - items: [{ to: "/", label: "Dashboard", icon: Home, color: "gray" }], - }, - { - // Component Management - Cool colors (cyan -> blue -> violet) - items: [ - { to: "/actions", label: "Actions", icon: SquarePlay, color: "cyan" }, - { to: "/rules", label: "Rules", icon: SquareArrowRight, color: "blue" }, - { - to: "/triggers", - label: "Triggers", - icon: SquareDot, - color: "violet", - }, - { - to: "/sensors", - label: "Sensors", - icon: SquareAsterisk, - color: "purple", - }, - ], - }, - { - // Runtime Logs - Warm colors (fuchsia -> rose -> orange) - items: [ - { - to: "/executions", - label: "Execution History", - icon: CirclePlay, - color: "fuchsia", - }, - { - to: "/enforcements", - label: "Enforcement History", - icon: CircleArrowRight, - color: "rose", - }, - { - to: "/events", - label: "Event History", - icon: CircleDot, - color: "orange", - }, - ], - }, - { - items: [ - { to: "/keys", label: "Keys & Secrets", icon: KeyRound, color: "gray" }, - { - to: "/packs", - label: "Pack Management", - icon: Package, - color: "gray", - }, - ], - }, - ]; - - // Color mappings for navigation items - const colorClasses = { - gray: { - inactive: "text-gray-300 hover:text-white hover:bg-gray-800", - active: "bg-gray-800 text-white", - icon: "text-gray-400", - }, - cyan: { - inactive: "text-cyan-300 hover:text-cyan-100 hover:bg-cyan-950/30", - active: "bg-cyan-950/50 text-cyan-100 shadow-lg shadow-cyan-900/50", - icon: "text-cyan-400", - }, - blue: { - inactive: "text-blue-300 hover:text-blue-100 hover:bg-blue-950/30", - active: "bg-blue-950/50 text-blue-100 shadow-lg shadow-blue-900/50", - icon: "text-blue-400", - }, - violet: { - inactive: "text-violet-300 hover:text-violet-100 hover:bg-violet-950/30", - active: "bg-violet-950/50 text-violet-100 shadow-lg shadow-violet-900/50", - icon: "text-violet-400", - }, - purple: { - inactive: "text-purple-300 hover:text-purple-100 hover:bg-purple-950/30", - active: "bg-purple-950/50 text-purple-100 shadow-lg shadow-purple-900/50", - icon: "text-purple-400", - }, - fuchsia: { - inactive: - "text-fuchsia-300 hover:text-fuchsia-100 hover:bg-fuchsia-950/30", - active: - "bg-fuchsia-950/50 text-fuchsia-100 shadow-lg shadow-fuchsia-900/50", - icon: "text-fuchsia-400", - }, - rose: { - inactive: "text-rose-300 hover:text-rose-100 hover:bg-rose-950/30", - active: "bg-rose-950/50 text-rose-100 shadow-lg shadow-rose-900/50", - icon: "text-rose-400", - }, - orange: { - inactive: "text-orange-300 hover:text-orange-100 hover:bg-orange-950/30", - active: "bg-orange-950/50 text-orange-100 shadow-lg shadow-orange-900/50", - icon: "text-orange-400", - }, - }; - - const NavLink = ({ - to, - label, - icon: Icon, - color = "gray", - }: { - to: string; - label: string; - icon: React.ElementType; - color?: string; - }) => { - const isActive = - location.pathname === to || - (to !== "/" && location.pathname.startsWith(to)); - - const colors = - colorClasses[color as keyof typeof colorClasses] || colorClasses.gray; - - return ( - - - {!isCollapsed && {label}} - - ); - }; - return ( -
+
+ {/* Sidebar */}
{/* Header */} -
- - {isCollapsed ? "A" : "Attune"} +
+ + Attune + Attune
{/* Navigation */} -