-
Notifications
You must be signed in to change notification settings - Fork 142
feat(brand): Brand dashboard UI redesign #121
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughAdds new UI primitives (Checkbox, Progress), two state components (EmptyState, ErrorState), extends AuthContext with a role field, updates UserNav to accept Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant U as User
participant BD as BrandDashboard
participant Auth as AuthContext
participant Router as Router (useNavigate/useLocation)
U->>Router: request /brand/*
Router->>BD: render BrandDashboard
BD->>Auth: read current user & role
BD->>BD: compute dashboardPath & collapsed state
BD->>BD: render sidebar, topbar, main content
U-->>BD: click sidebar item
BD->>Router: navigate(to route)
Router-->>BD: location update
BD->>BD: highlight active item, update view
rect rgba(200,230,255,0.18)
note right of BD: Sidebar toggle flow
U-->>BD: click collapse toggle
BD->>BD: toggle collapsed state -> re-render layout
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
Tip 👮 Agentic pre-merge checks are now available in preview!Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
Please see the documentation for more information. Example: reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).Please share your feedback with us on this Discord post. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Nitpick comments (14)
Frontend/src/index.css (1)
3-3: Google Fonts import: prefer link tag or self-hosting; ensure it’s actually used.
- Loading via CSS @import delays font fetch and can hurt FCP. Prefer a + in the HTML head, or self-host for privacy/perf. Also verify the Orbitron font is applied somewhere (I don’t see a class using it).
Example utility (outside this hunk) if you intend to use it:
+.font-orbitron { font-family: "Orbitron", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial; }Frontend/src/components/ui/checkbox.tsx (1)
11-16: Add indeterminate visual state and keyboard/a11y nits.
- Radix Checkbox supports "indeterminate"; add styles for data-[state=indeterminate] and optional Minus icon so users can distinguish tri-state.
- Consider documenting/encouraging labeling (aria-label or associated ).
Possible tweak:
-import { Check } from "lucide-react" +import { Check, Minus } from "lucide-react" ... <CheckboxPrimitive.Root ref={ref} className={cn( - "peer h-4 w-4 ... data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground", + "peer h-4 w-4 ... data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=indeterminate]:bg-primary", className )} {...props} > - <CheckboxPrimitive.Indicator className={cn("flex items-center justify-center text-current")}> - <Check className="h-4 w-4" /> + <CheckboxPrimitive.Indicator className="flex items-center justify-center text-current"> + <Check className="h-4 w-4 data-[state=indeterminate]:hidden" /> + <Minus className="h-4 w-4 hidden data-[state=indeterminate]:block" /> </CheckboxPrimitive.Indicator>Frontend/src/components/ui/progress.tsx (1)
18-21: Clamp value to [0,100] and handle indeterminate.
- Without clamping, values <0 or >100 produce odd transforms. Also consider a visual for indeterminate when value is undefined.
- <ProgressPrimitive.Indicator - className="h-full w-full flex-1 bg-primary transition-all" - style={{ transform: `translateX(-${100 - (value || 0)}%)` }} - /> + {typeof value === "number" ? ( + <ProgressPrimitive.Indicator + className="h-full w-full flex-1 bg-primary transition-transform" + style={{ + transform: `translateX(-${100 - Math.min(100, Math.max(0, value))}%)`, + }} + /> + ) : ( + <ProgressPrimitive.Indicator + className="h-full w-1/3 flex-1 bg-primary animate-[progress-indeterminate_1.2s_ease_infinite]" + /> + )}Add keyframes once globally (outside this file):
@keyframes progress-indeterminate { 0%{transform: translateX(-100%)} 100%{transform: translateX(300%)} }Frontend/src/components/user-nav.tsx (1)
28-33: Avoid interactive-in-interactive (Button wrapping Link).Use Button asChild (if supported) or style Link directly to prevent nested interactive elements.
- <Button variant="ghost" size="sm" className="md:hidden"> - <Link to="/login">Login</Link> - </Button> + <Button asChild variant="ghost" size="sm" className="md:hidden"> + <Link to="/login">Login</Link> + </Button> - <Button size="sm" className="md:hidden bg-purple-600 text-white hover:bg-purple-700"> - <Link to="/signup">Sign Up</Link> - </Button> + <Button asChild size="sm" className="md:hidden bg-purple-600 text-white hover:bg-purple-700"> + <Link to="/signup">Sign Up</Link> + </Button>If Button lacks asChild, apply the button classes to Link instead.
Frontend/src/components/ui/error-state.tsx (2)
139-146: Announce errors for screen readers.Add role="alert" and aria-live so the error is read out, and optionally aria-busy when retrying.
- return ( - <Card className={`border-0 shadow-none ${className}`}> - <CardContent className={`text-center ${sizeClasses[size]}`}> + return ( + <Card className={`border-0 shadow-none ${className}`}> + <CardContent + className={`text-center ${sizeClasses[size]}`} + role="alert" + aria-live="polite" + aria-busy={retryLoading || undefined} + >
142-146: Icon container ignores size prop.The wrapper is fixed at w-16 h-16. Consider size-scaled container like in EmptyState for consistency.
- <div className={`w-16 h-16 ${config.iconBg} rounded-full ...`}> + <div className={`${size === "lg" ? "w-16 h-16" : size === "sm" ? "w-12 h-12" : "w-14 h-14"} ${config.iconBg} rounded-full ...`}>Frontend/src/components/ui/empty-state.tsx (1)
187-223: Add accessible landmark and associations.Wrap with a region landmark and tie heading/message via aria-labelledby/aria-describedby for SR context.
- return ( - <Card className={`border-0 shadow-none ${className}`}> - <CardContent className={`text-center ${sizeClasses[size]}`}> + const headingId = React.useId(); + const descId = React.useId(); + return ( + <Card className={`border-0 shadow-none ${className}`}> + <CardContent + className={`text-center ${sizeClasses[size]}`} + role="region" + aria-labelledby={headingId} + aria-describedby={descId} + > ... - <h3 className={`font-semibold text-gray-900 mb-3 ${textSizes[size].title}`}> + <h3 id={headingId} className={`font-semibold text-gray-900 mb-3 ${textSizes[size].title}`}> {displayTitle} </h3> ... - <p className={`text-gray-600 mb-8 max-w-md mx-auto leading-relaxed ${textSizes[size].message}`}> + <p id={descId} className={`text-gray-600 mb-8 max-w-md mx-auto leading-relaxed ${textSizes[size].message}`}> {displayMessage} </p>Frontend/src/pages/Brand/Dashboard.tsx (7)
10-15: Active tab detection brittle for nested routes.location.pathname === route fails on subroutes (/brand/messages/123). Prefer startsWith or NavLink.
-const isActive = location.pathname === tab.route; +const isActive = location.pathname === tab.route || location.pathname.startsWith(`${tab.route}/`);
86-110: Button needs type and focus styles (keyboard).
- Add type="button" to avoid unintended submits in forms.
- Use :hover/:focus-visible styles via CSS instead of JS onMouseEnter/Leave for a11y.
- <button style={{ ... }} + <button type="button" style={{ ... }} onMouseEnter={(e) => e.currentTarget.style.background = "#0a00b3"} onMouseLeave={(e) => e.currentTarget.style.background = PRIMARY} >
248-281: Collapse toggle needs a11y attributes; position may be hard to tap.
- Add aria-label and aria-pressed; expose collapsed state.
- The “right: -12px” control can render off-screen on mobile—consider in-flow placement.
-<button +<button + type="button" + aria-label="Toggle sidebar" + aria-pressed={sidebarCollapsed} onClick={() => setSidebarCollapsed(!sidebarCollapsed)} style={{ ... }} >
409-421: Search input lacks an accessible label.Add aria-label or associate a visually-hidden label for SR users.
- <input + <input + aria-label="Search brand campaigns, matches, and analytics" type="text" placeholder="Ask anything about your brand campaigns, creator matches, or analytics..."
367-390: Search container “grow to 110%” causes layout shift.This can induce horizontal scroll/jank on small screens. Prefer a subtle box-shadow/border-color change without resizing.
- e.currentTarget.style.width = "110%"; - e.currentTarget.style.transform = "translateX(-5%)"; + // Keep size stable; emphasize ring/border only
447-511: Quick actions: same a11y concerns as nav; add type and CSS focus styles.Avoid JS hover handlers; add type="button" and focus-visible styles.
515-537: Inline keyframes: move to global CSS and respect reduced motion.Define @Keyframes once in index.css and wrap animation in @media (prefers-reduced-motion: no-preference).
-<style>{` @keyframes gradientFlow { ... } `}</style> +/* index.css */ +@media (prefers-reduced-motion: no-preference) { + @keyframes gradientFlow { /* existing frames */ } +}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
Frontend/public/aossielogo.pngis excluded by!**/*.png
📒 Files selected for processing (7)
Frontend/src/components/ui/checkbox.tsx(1 hunks)Frontend/src/components/ui/empty-state.tsx(1 hunks)Frontend/src/components/ui/error-state.tsx(1 hunks)Frontend/src/components/ui/progress.tsx(1 hunks)Frontend/src/components/user-nav.tsx(2 hunks)Frontend/src/index.css(1 hunks)Frontend/src/pages/Brand/Dashboard.tsx(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
Frontend/src/components/ui/progress.tsx (1)
Frontend/src/lib/utils.ts (1)
cn(4-6)
Frontend/src/components/ui/error-state.tsx (2)
Frontend/src/components/ui/card.tsx (2)
Card(80-80)CardContent(85-85)Frontend/src/components/ui/button.tsx (1)
Button(54-54)
Frontend/src/components/ui/checkbox.tsx (1)
Frontend/src/lib/utils.ts (1)
cn(4-6)
Frontend/src/components/ui/empty-state.tsx (3)
Frontend/src/components/ui/calendar.tsx (1)
Calendar(73-73)Frontend/src/components/ui/card.tsx (2)
Card(80-80)CardContent(85-85)Frontend/src/components/ui/button.tsx (1)
Button(54-54)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
Frontend/src/components/user-nav.tsx(3 hunks)Frontend/src/context/AuthContext.tsx(5 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
Frontend/src/components/user-nav.tsx (1)
Frontend/src/context/AuthContext.tsx (1)
useAuth(231-237)
🪛 Biome (2.1.2)
Frontend/src/components/user-nav.tsx
[error] 44-44: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.
Hooks should not be called after an early return.
For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
(lint/correctness/useHookAtTopLevel)
🔇 Additional comments (4)
Frontend/src/context/AuthContext.tsx (3)
17-18: Good addition: exposeroleon the context.Makes role-based UI decisions straightforward for consumers.
69-70: State forroleinitialized — LGTM.No concerns with the state shape or default.
226-228: Provider value includesrole— LGTM.Matches the updated
AuthContextType.Frontend/src/components/user-nav.tsx (1)
80-84: Dashboard link now uses computed path — resolves prior route mismatch.This addresses the earlier comment about linking to /brand/dashboard for brand users.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
Frontend/src/pages/Brand/Dashboard.tsx (1)
20-35: Avoid first-paint sidebar flicker on narrow viewports.On sub‑1024px screens we still render the expanded (280px) sidebar for a frame before the resize effect collapses it. Seed the initial state from
window.innerWidthso mobile users don’t see that flash.- const [sidebarCollapsed, setSidebarCollapsed] = useState(false); + const [sidebarCollapsed, setSidebarCollapsed] = useState(() => { + if (typeof window === "undefined") { + return false; + } + return window.innerWidth < 1024; + }); @@ - if (window.innerWidth < 1024) { - setSidebarCollapsed(true); - } else { - setSidebarCollapsed(false); - } + setSidebarCollapsed(window.innerWidth < 1024);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
Frontend/src/components/user-nav.tsx(3 hunks)Frontend/src/context/AuthContext.tsx(6 hunks)Frontend/src/pages/Brand/Dashboard.tsx(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
Frontend/src/components/user-nav.tsx (1)
Frontend/src/context/AuthContext.tsx (1)
useAuth(238-244)
Frontend/src/context/AuthContext.tsx (1)
Frontend/src/utils/supabase.tsx (1)
supabase(11-11)
Frontend/src/pages/Brand/Dashboard.tsx (1)
Frontend/src/components/user-nav.tsx (1)
UserNav(22-86)
🔇 Additional comments (2)
Frontend/src/components/user-nav.tsx (1)
22-29: Synchronous dashboard path derivation looks solid.Great call deriving
dashboardPathdirectly from the user metadata/context—this kills the flicker and keeps the menu in sync with role updates.Frontend/src/context/AuthContext.tsx (1)
178-184: Stop overwriting the cached role on throttled onboarding checks.When the 2 s throttle trips,
checkUserOnboardingreturns{ role: null }, and the guardres.role !== undefinedstill passes, so we callsetRole(null)and wipe the previously resolved role—exactly the flicker/misrouting regression we flagged earlier. Mirror the startup path by falling back to the previous value whenever the response isnull.- // Only update role if userId matches current session.user.id and role is defined - if (res.role !== undefined && session.user.id === userId) { - setRole(res.role); - } + if (session.user.id === userId && res.role !== undefined) { + setRole(prev => (res.role ?? prev)); + }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
Frontend/src/pages/Brand/Dashboard.module.css(1 hunks)Frontend/src/pages/Brand/Dashboard.tsx(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
Frontend/src/pages/Brand/Dashboard.tsx (1)
Frontend/src/components/user-nav.tsx (1)
UserNav(22-86)
| .brand-nav-btn { | ||
| @apply w-full border-none rounded-xl px-4 py-3 flex items-center gap-2 text-base font-medium cursor-pointer transition-colors duration-200 bg-transparent text-[var(--muted-text)] outline-none; | ||
| } | ||
| .brand-nav-btn:hover, | ||
| .brand-nav-btn:focus-visible { | ||
| @apply bg-[var(--sidebar-active)] text-[var(--text-default)] outline outline-2 outline-[var(--accent)]; | ||
| } | ||
| .brand-nav-btn.active { | ||
| @apply bg-[var(--sidebar-active)] text-[var(--text-default)] outline-none; | ||
| } | ||
| .brand-nav-btn.collapsed { | ||
| @apply justify-center px-2 py-2; | ||
| } | ||
| .brand-new-btn { | ||
| @apply w-full bg-[var(--primary)] border-none rounded-xl px-4 py-3 flex items-center gap-2 text-base font-medium cursor-pointer transition-colors duration-200 text-[var(--text-default)] outline-none; | ||
| } | ||
| .brand-new-btn:hover, | ||
| .brand-new-btn:focus-visible { | ||
| @apply bg-[var(--primary-hover)] outline outline-2 outline-[var(--accent)]; | ||
| } | ||
| .brand-profile-btn { | ||
| @apply w-full bg-transparent border-none rounded-lg px-4 py-3 flex items-center gap-3 text-base font-medium cursor-pointer transition-colors duration-200 text-[var(--muted-text)] outline-none; | ||
| } | ||
| .brand-profile-btn:hover, | ||
| .brand-profile-btn:focus-visible { | ||
| @apply bg-[var(--sidebar-active)] text-[var(--text-default)] outline outline-2 outline-[var(--accent)]; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tailwind build will fail with @apply + arbitrary values
Tailwind 3.x still disallows @apply on arbitrary-value utilities (bg-[var(--primary)], text-[var(--muted-text)], etc.). These selectors throw a compilation error (“class … cannot be used with @apply”) and the build will stop. Please replace the @apply usages with explicit CSS declarations (or standard Tailwind tokens) so the module compiles.
-.brand-nav-btn {
- @apply w-full border-none rounded-xl px-4 py-3 flex items-center gap-2 text-base font-medium cursor-pointer transition-colors duration-200 bg-transparent text-[var(--muted-text)] outline-none;
-}
+.brand-nav-btn {
+ width: 100%;
+ border: none;
+ border-radius: 0.75rem;
+ padding: 0.75rem 1rem;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ font-size: 1rem;
+ font-weight: 500;
+ cursor: pointer;
+ transition: color 0.2s ease, background-color 0.2s ease, outline 0.2s ease;
+ background: transparent;
+ color: var(--muted-text);
+ outline: none;
+}
-.brand-nav-btn:hover,
-.brand-nav-btn:focus-visible {
- @apply bg-[var(--sidebar-active)] text-[var(--text-default)] outline outline-2 outline-[var(--accent)];
-}
+.brand-nav-btn:hover,
+.brand-nav-btn:focus-visible {
+ background: var(--sidebar-active);
+ color: var(--text-default);
+ outline: 2px solid var(--accent);
+ outline-offset: 2px;
+}Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In Frontend/src/pages/Brand/Dashboard.module.css around lines 1 to 27, the use
of Tailwind's @apply with arbitrary-value utilities (e.g. bg-[var(--primary)],
text-[var(--muted-text)]) will break the build; replace those @apply usages with
plain CSS property declarations using the same CSS variables (e.g.
background-color: var(--primary); color: var(--muted-text); outline: none;
padding/margin/border/radius as written) or swap to allowed Tailwind token
classes, and keep interactive state rules (hover/focus) as explicit CSS
properties as well so the module compiles.
| <div style={{ | ||
| background: "rgba(26, 26, 26, 0.6)", | ||
| backdropFilter: "blur(20px)", | ||
| border: "1px solid rgba(255, 255, 255, 0.1)", | ||
| borderRadius: "50px", | ||
| padding: "16px 20px", | ||
| display: "flex", | ||
| alignItems: "center", | ||
| gap: "12px", | ||
| transition: "all 0.3s ease", | ||
| boxShadow: "0 8px 32px rgba(0, 0, 0, 0.2)", | ||
| position: "relative", | ||
| overflow: "hidden", | ||
| width: "100%", | ||
| }} | ||
| onFocus={(e) => { | ||
| e.currentTarget.style.borderColor = "#87CEEB"; | ||
| e.currentTarget.style.background = "rgba(26, 26, 26, 0.8)"; | ||
| e.currentTarget.style.backdropFilter = "blur(10px)"; | ||
| e.currentTarget.style.padding = "12px 16px"; | ||
| e.currentTarget.style.gap = "8px"; | ||
| e.currentTarget.style.width = "110%"; | ||
| e.currentTarget.style.transform = "translateX(-5%)"; | ||
| // Remove glass texture | ||
| const overlay = e.currentTarget.querySelector('[data-glass-overlay]'); | ||
| if (overlay) (overlay as HTMLElement).style.opacity = "0"; | ||
| }} | ||
| onBlur={(e) => { | ||
| e.currentTarget.style.borderColor = "rgba(255, 255, 255, 0.1)"; | ||
| e.currentTarget.style.background = "rgba(26, 26, 26, 0.6)"; | ||
| e.currentTarget.style.backdropFilter = "blur(20px)"; | ||
| e.currentTarget.style.padding = "16px 20px"; | ||
| e.currentTarget.style.gap = "12px"; | ||
| e.currentTarget.style.width = "100%"; | ||
| e.currentTarget.style.transform = "translateX(0)"; | ||
| // Restore glass texture | ||
| const overlay = e.currentTarget.querySelector('[data-glass-overlay]'); | ||
| if (overlay) (overlay as HTMLElement).style.opacity = "1"; | ||
| }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Search focus animation breaks mobile layout
When the search container gains focus we inflate it to 110% width and translate it -5%. On sub-1024px viewports (e.g., 360px mobile), that expands beyond the parent, producing horizontal overflow/scroll the moment the user taps the field. This violates the responsive objective and makes the search control harder to use on phones. Please keep the container at 100% width and use non-expansive styling (box-shadow, border color, etc.) for the focus effect.
- e.currentTarget.style.padding = "12px 16px";
- e.currentTarget.style.gap = "8px";
- e.currentTarget.style.width = "110%";
- e.currentTarget.style.transform = "translateX(-5%)";
+ e.currentTarget.style.padding = "12px 16px";
+ e.currentTarget.style.gap = "8px";
+ e.currentTarget.style.boxShadow = "0 12px 40px rgba(0, 0, 0, 0.35)";
...
- e.currentTarget.style.width = "100%";
- e.currentTarget.style.transform = "translateX(0)";
+ e.currentTarget.style.boxShadow = "0 8px 32px rgba(0, 0, 0, 0.2)";📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <div style={{ | |
| background: "rgba(26, 26, 26, 0.6)", | |
| backdropFilter: "blur(20px)", | |
| border: "1px solid rgba(255, 255, 255, 0.1)", | |
| borderRadius: "50px", | |
| padding: "16px 20px", | |
| display: "flex", | |
| alignItems: "center", | |
| gap: "12px", | |
| transition: "all 0.3s ease", | |
| boxShadow: "0 8px 32px rgba(0, 0, 0, 0.2)", | |
| position: "relative", | |
| overflow: "hidden", | |
| width: "100%", | |
| }} | |
| onFocus={(e) => { | |
| e.currentTarget.style.borderColor = "#87CEEB"; | |
| e.currentTarget.style.background = "rgba(26, 26, 26, 0.8)"; | |
| e.currentTarget.style.backdropFilter = "blur(10px)"; | |
| e.currentTarget.style.padding = "12px 16px"; | |
| e.currentTarget.style.gap = "8px"; | |
| e.currentTarget.style.width = "110%"; | |
| e.currentTarget.style.transform = "translateX(-5%)"; | |
| // Remove glass texture | |
| const overlay = e.currentTarget.querySelector('[data-glass-overlay]'); | |
| if (overlay) (overlay as HTMLElement).style.opacity = "0"; | |
| }} | |
| onBlur={(e) => { | |
| e.currentTarget.style.borderColor = "rgba(255, 255, 255, 0.1)"; | |
| e.currentTarget.style.background = "rgba(26, 26, 26, 0.6)"; | |
| e.currentTarget.style.backdropFilter = "blur(20px)"; | |
| e.currentTarget.style.padding = "16px 20px"; | |
| e.currentTarget.style.gap = "12px"; | |
| e.currentTarget.style.width = "100%"; | |
| e.currentTarget.style.transform = "translateX(0)"; | |
| // Restore glass texture | |
| const overlay = e.currentTarget.querySelector('[data-glass-overlay]'); | |
| if (overlay) (overlay as HTMLElement).style.opacity = "1"; | |
| }} | |
| <div | |
| style={{ | |
| background: "rgba(26, 26, 26, 0.6)", | |
| backdropFilter: "blur(20px)", | |
| border: "1px solid rgba(255, 255, 255, 0.1)", | |
| borderRadius: "50px", | |
| padding: "16px 20px", | |
| display: "flex", | |
| alignItems: "center", | |
| gap: "12px", | |
| transition: "all 0.3s ease", | |
| boxShadow: "0 8px 32px rgba(0, 0, 0, 0.2)", | |
| position: "relative", | |
| overflow: "hidden", | |
| width: "100%", | |
| }} | |
| onFocus={(e) => { | |
| e.currentTarget.style.borderColor = "#87CEEB"; | |
| e.currentTarget.style.background = "rgba(26, 26, 26, 0.8)"; | |
| e.currentTarget.style.backdropFilter = "blur(10px)"; | |
| e.currentTarget.style.padding = "12px 16px"; | |
| e.currentTarget.style.gap = "8px"; | |
| e.currentTarget.style.boxShadow = "0 12px 40px rgba(0, 0, 0, 0.35)"; | |
| // Remove glass texture | |
| const overlay = e.currentTarget.querySelector('[data-glass-overlay]'); | |
| if (overlay) (overlay as HTMLElement).style.opacity = "0"; | |
| }} | |
| onBlur={(e) => { | |
| e.currentTarget.style.borderColor = "rgba(255, 255, 255, 0.1)"; | |
| e.currentTarget.style.background = "rgba(26, 26, 26, 0.6)"; | |
| e.currentTarget.style.backdropFilter = "blur(20px)"; | |
| e.currentTarget.style.padding = "16px 20px"; | |
| e.currentTarget.style.gap = "12px"; | |
| e.currentTarget.style.boxShadow = "0 8px 32px rgba(0, 0, 0, 0.2)"; | |
| // Restore glass texture | |
| const overlay = e.currentTarget.querySelector('[data-glass-overlay]'); | |
| if (overlay) (overlay as HTMLElement).style.opacity = "1"; | |
| }} | |
| > |
Closes #
📝 Description
Redesign and polish the Brand dashboard UI. Adds the new Brand dashboard page layout (sidebar, top bar, animated title, main search, and quick actions) and wires up the small set of shared UI primitives and auth/supabase helpers required by the page. These changes prepare the Brand UX for further integration (campaigns, messages, tracking).
🔧 Changes Made
Files touched (high level)
[Dashboard.tsx] new/updated Brand dashboard page and layout
[user-nav.tsx]header/user menu used by dashboard
[AuthContext.tsx] auth provider, session handling and supabase wiring
[supabase.tsx] supabase client
[utils.ts] small helper (cn, API_URL)
Frontend/src/components/ui/* — shared UI primitives used by the dashboard:
avatar.tsx, button.tsx, dropdown-menu.tsx, card.tsx, tabs.tsx, input.tsx, checkbox.tsx, empty-state.tsx, error-state.tsx, [progress.tsx]
Key pointers for reviewers (UX / visual)
Confirm responsive behavior:
Sidebar collapse/expand at narrow widths.
Top bar and main content remain usable on mobile.
Validate search input behavior:
Focus/blur visual transitions (border, background, glass overlay opacity).
Search button accessible and keyboard-focusable.
Check interactive states:
Hover/focus styles on buttons, nav items, quick actions, collapse toggle.
Dropdown in [UserNav]opens and items are clickable.
Visual polish:
Gradient animation on the "AI" title runs smoothly and doesn’t cause performance jank.
Glass texture overlay opacity on focus/blur is visually correct.
📷 Screenshots or Visual Changes (if applicable)
✅ Checklist
Summary by CodeRabbit
New Features
Style