PageSourceSearch

https://song-slide-0f2881b6.base44.app/assets/NavBar-CoQPn_U0.js

js song-slide-0f2881b6.base44.app collected 2026-10-03 03:08:53 UTC 7,977 bytes, 198 lines download raw bytes

1const e=`import { useNavigate, useLocation } from "react-router-dom";
2import { useState, useRef } from "react";
3import { Button } from "@/components/ui/button";
4
5export default function NavBar({ user }) {
6  const navigate = useNavigate();
7  const location = useLocation();
8  const [mobileOpen, setMobileOpen] = useState(false);
9  const [openDropdown, setOpenDropdown] = useState(null);
10  const hoverTimeout = useRef(null);
11
12  const handleMouseEnter = (label) => {
13    clearTimeout(hoverTimeout.current);
14    setOpenDropdown(label);
15  };
16
17  const handleMouseLeave = () => {
18    hoverTimeout.current = setTimeout(() => {
19      setOpenDropdown(null);
20    }, 150);
21  };
22
23  const path = location.pathname;
24
25  const isActive = (routes) =>
26    routes.some(r => path === r || path.startsWith(r));
27
28  const navItems = [
29    {
30      label: "Library",
31      routes: ["/Library", "/SongPreview"],
32      children: [
33        { label: "🎵 Song Library", route: "/Library" },
34        { label: "🎼 Song Sets", route: "/Library?tab=sets" },
35      ],
36    },
37    {
38      label: "Catalog",
39      routes: ["/Catalog", "/CatalogWorkspace"],
40      children: [
41        { label: "📋 Browse Catalog", route: "/Catalog" },
42        { label: "✏️ Catalog Workspace", route: "/CatalogWorkspace" },
43      ],
44    },
45    {
46      label: "Backgrounds",
47      routes: ["/BackgroundDesigner", "/Favorites"],
48      children: [
49        { label: "🎨 Background Designer", route: "/BackgroundDesigner" },
50        { label: "⭐ My Favorites", route: "/Favorites" },
51      ],
52    },
53    { label: "Team", route: "/Team", routes: ["/Team"] },
54    { label: "Settings", route: "/Settings", routes: ["/Settings"] },
55    { label: "Guide", route: "/UserGuide", routes: ["/UserGuide"] },
56  ];
57
58  const handleNav = (route) => {
59    navigate(route);
60    setMobileOpen(false);
61    setOpenDropdown(null);
62  };
63
64  const handleLogout = async () => {
65    await import("@/api/base44Client").then(m => m.base44.auth.logout());
66  };
67
68  const toggleTheme = () => {
69    const current = localStorage.getItem("theme");
70    const next = current === "dark" ? "light" : "dark";
71    localStorage.setItem("theme", next);
72    document.documentElement.classList.toggle("dark", next === "dark");
73  };
74
75  return (
76    <header className="sticky top-0 z-50 w-full bg-slate-950 border-b border-slate-800 h-14 flex items-center px-4">
77
78      {/* Logo */}
79      <div className="flex items-center gap-3 cursor-pointer flex-shrink-0" onClick={() => handleNav("/")}>
80        <img src="https://qtrypzzcjebvfcihiynt.supabase.co/storage/v1/object/public/base44-prod/public/6960417100e858f30f2881b6/488a27e39_Untitled-20260108-232326-4413-2x.png"
81          alt="SongSlide" className="h-8 w-auto" />
82      </div>
83
84      {/* Org name */}
85      {user?.tenantName && (
86        <span className="ml-3 text-xs text-slate-500 hidden md:block border border-slate-700 rounded px-2 py-0.5">
87          🏢 {user.tenantName}
88        </span>
89      )}
90
91      {/* Desktop Nav */}
92      <nav className="hidden md:flex items-center gap-1 ml-6 flex-1">
93        {navItems.map((item) => (
94          <div key={item.label} className="relative"
95            onMouseEnter={() => item.children && handleMouseEnter(item.label)}
96            onMouseLeave={handleMouseLeave}>
97
98            {item.children ? (
99              <>
100                <button
101                  onClick={() => setOpenDropdown(openDropdown === item.label ? null : item.label)}
102                  className={\`flex items-center gap-1 px-3 pt-2 pb-3 rounded-md text-sm font-medium transition-colors
103                    \${isActive(item.routes)
104                      ? "text-sky-400 bg-slate-800"
105                      : "text-slate-300 hover:text-white hover:bg-slate-800"}\`}>
106                  {item.label}
107                  <span className={\`text-xs transition-transform \${openDropdown === item.label ? "rotate-180" : ""}\`}>▾</span>
108                </button>
109
110                {openDropdown === item.label && (
111                  <div
112                    className="absolute top-full left-0 w-52 z-50"
113                    onMouseEnter={() => clearTimeout(hoverTimeout.current)}
114                    onMouseLeave={handleMouseLeave}
115                  >
116                    <div className="h-1 w-full" />
117                    <div className="w-full bg-slate-800 border border-slate-700 rounded-lg shadow-xl py-1">
118                      {item.children.map((child) => (
119                        <button key={child.route}
120                          onClick={() => handleNav(child.route)}
121                          className="w-full text-left px-4 py-2 text-sm text-slate-300 hover:text-white hover:bg-slate-700 flex items-center gap-2">
122                          {child.label}
123                        </button>
124                      ))}
125                    </div>
126                  </div>
127                )}
128              </>
129            ) : (
130              <button
131                onClick={() => handleNav(item.route)}
132                className={\`px-3 py-2 rounded-md text-sm font-medium transition-colors
133                  \${isActive(item.routes)
134                    ? "text-sky-400 bg-slate-800"
135                    : "text-slate-300 hover:text-white hover:bg-slate-800"}\`}>
136                {item.label}
137              </button>
138            )}
139          </div>
140        ))}
141      </nav>
142
143      {/* Right side — desktop */}
144      <div className="hidden md:flex items-center gap-2 ml-auto">
145        <button onClick={toggleTheme}
146          className="p-2 rounded-md text-slate-400 hover:text-white hover:bg-slate-800 transition-colors text-lg">
147          ☀️
148        </button>
149        <button onClick={handleLogout}
150          className="px-3 py-1.5 text-sm text-slate-300 hover:text-white hover:bg-slate-800 rounded-md transition-colors">
151          Logout
152        </button>
153      </div>
154
155      {/* Mobile hamburger */}
156      <button className="md:hidden ml-auto p-2 text-slate-300 hover:text-white"
157        onClick={() => setMobileOpen(!mobileOpen)}>
158        {mobileOpen ? "✕" : "☰"}
159      </button>
160
161      {/* Mobile drawer */}
162      {mobileOpen && (
163        <div className="absolute top-14 left-0 right-0 bg-slate-900 border-b border-slate-700 z-50 md:hidden">
164          {navItems.map((item) => (
165            <div key={item.label}>
166              {item.children ? (
167                <>
168                  <button
169                    onClick={() => setOpenDropdown(openDropdown === item.label ? null : item.label)}
170                    className="w-full text-left px-4 py-3 text-sm font-medium text-slate-300 hover:text-white hover:bg-slate-800 flex justify-between items-center border-b border-slate-800">
171                    {item.label} <span>{openDropdown === item.label ? "▴" : "▾"}</span>
172                  </button>
173                  {openDropdown === item.label && item.children.map((child) => (
174                    <button key={child.route}
175                      onClick={() => handleNav(child.route)}
176                      className="w-full text-left px-8 py-2.5 text-sm text-slate-400 hover:text-white hover:bg-slate-800 border-b border-slate-800">
177                      {child.label}
178                    </button>
179                  ))}
180                </>
181              ) : (
182                <button
183                  onClick={() => handleNav(item.route)}
184                  className="w-full text-left px-4 py-3 text-sm font-medium text-slate-300 hover:text-white hover:bg-slate-800 border-b border-slate-800">
185                  {item.label}
186                </button>
187              )}
188            </div>
189          ))}
190          <div className="flex items-center justify-between px-4 py-3">
191            <button onClick={toggleTheme} className="text-slate-400 hover:text-white text-lg">
191☀️</button>
192            <button onClick={handleLogout} className="text-sm text-slate-300 hover:text-white">Logout</button>
193          </div>
194        </div>
195      )}
196    </header>
197  );
198}`;export{e as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.