Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 92 additions & 81 deletions src/components/DashboardHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ import KeyboardShortcuts from "@/components/KeyboardShortcuts";
import { Moon, Sun } from "lucide-react";
import { toast } from "sonner";

import { useIsMobile } from "@/hooks/useIsMobile";


type DashboardSyncContextValue = {
lastSynced: Date | null;
};
Expand Down Expand Up @@ -99,6 +102,8 @@ export default function DashboardHeader() {
const [isNightOwl, setIsNightOwl] = useState<boolean>(false);
const [isEarlyBird, setIsEarlyBird] = useState<boolean>(false);

const isMobile = useIsMobile();

useEffect(() => {
const computeCurrentGreeting = () => {
const currentHour = new Date().getHours();
Expand Down Expand Up @@ -204,7 +209,7 @@ export default function DashboardHeader() {
<header className="relative mb-8 overflow-hidden rounded-3xl border border-[var(--border)] bg-[var(--card)]/95 p-5 shadow-[var(--shadow-soft)] backdrop-blur-md transition-all duration-300 hover:shadow-[var(--shadow-medium)] md:p-6">
<div className="pointer-events-none absolute inset-x-0 top-0 h-px bg-gradient-to-r from-transparent via-[var(--accent)]/40 to-transparent" />
<div className="pointer-events-none absolute -right-10 -top-12 h-32 w-32 rounded-full bg-[var(--accent)]/10 blur-3xl" />
<div className="flex min-w-0 flex-col gap-5 md:flex-row md:items-end md:justify-between">
<div className="flex min-w-0 gap-5 items-end justify-between">

{/* Left Section */}
<div>
Expand Down Expand Up @@ -260,92 +265,98 @@ export default function DashboardHeader() {
</div>

{/* Right Section */}
<div className="flex min-w-0 flex-col gap-3 sm:items-end">
<div className="flex flex-wrap items-center gap-3">
{isPublic === true && session?.githubLogin && (
<a
href={`/u/${session.githubLogin}`}
target="_blank"
rel="noopener noreferrer"
className="primary-button inline-flex items-center justify-center rounded-xl px-4 py-2 text-sm font-semibold"
title="View your public profile"
>
Share Profile
</a>
)}

<div className="flex items-center gap-2 rounded-2xl border border-[var(--border)] bg-[var(--card-muted)]/50 p-2 shadow-sm backdrop-blur-sm">
<div className="transition-transform duration-200 hover:scale-[1.05]">
<KeyboardShortcuts />
</div>

<div className="transition-transform duration-200 hover:scale-[1.05]">
<NotificationBell />
</div>

<div className="transition-transform duration-200 hover:scale-[1.05]">
<UserAvatar />
</div>

<div className="transition-transform duration-200 hover:rotate-12">
<ThemeToggle />
</div>

<div className="transition-transform duration-200 hover:scale-[1.05]">
<SignOutButton />
</div>
</div>
</div>
</div>

{/* Mobile hamburger button */}
{!isMobile &&
<div className="flex min-w-0 flex-col gap-3 sm:items-end">
<div className="flex flex-wrap items-center gap-3">
{isPublic === true && session?.githubLogin && (
<a
href={`/u/${session.githubLogin}`}
target="_blank"
rel="noopener noreferrer"
className="primary-button inline-flex items-center justify-center rounded-xl px-4 py-2 text-sm font-semibold"
title="View your public profile"
>
Share Profile
</a>
)}

<div className="flex items-center gap-2 rounded-2xl border border-[var(--border)] bg-[var(--card-muted)]/50 p-2 shadow-sm backdrop-blur-sm">
<div className="transition-transform duration-200 hover:scale-[1.05]">
<KeyboardShortcuts />
</div>

<div className="transition-transform duration-200 hover:scale-[1.05]">
<NotificationBell />
</div>

<div className="transition-transform duration-200 hover:scale-[1.05]">
<UserAvatar />
</div>

<div className="transition-transform duration-200 hover:rotate-12">
<ThemeToggle />
</div>

<div className="transition-transform duration-200 hover:scale-[1.05]">
<SignOutButton />
</div>
</div>
</div>
</div>


}
{/* Mobile hamburger button */}
{isMobile &&
<button
type="button"
className="inline-flex items-center justify-center self-start rounded-xl border border-[var(--border)] bg-[var(--card-muted)]/70 p-2 text-[var(--card-foreground)] shadow-sm transition-all duration-200 hover:border-[var(--accent)] hover:text-[var(--accent)] sm:hidden"
onClick={() => setMenuOpen((v) => !v)}
aria-label="Toggle menu"
aria-expanded={menuOpen}
>
{menuOpen ? (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="h-5 w-5"
aria-hidden="true"
>
<path d="M18 6 6 18" />
<path d="m6 6 12 12" />
</svg>
) : (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="h-5 w-5"
aria-hidden="true"
>
<path d="M4 6h16" />
<path d="M4 12h16" />
<path d="M4 18h16" />
</svg>
)}
</button>
type="button"
className="inline-flex items-center justify-center self-start rounded-xl border border-[var(--border)] bg-[var(--card-muted)]/70 p-2 text-[var(--card-foreground)] shadow-sm transition-all duration-200 hover:border-[var(--accent)] hover:text-[var(--accent)] "
onClick={() => setMenuOpen((v) => !v)}
aria-label="Toggle menu"
aria-expanded={menuOpen}
>
{menuOpen ? (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="h-5 w-5"
aria-hidden="true"
>
<path d="M18 6 6 18" />
<path d="m6 6 12 12" />
</svg>
) : (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="h-5 w-5"
aria-hidden="true"
>
<path d="M4 6h16" />
<path d="M4 12h16" />
<path d="M4 18h16" />
</svg>
)}
</button>
}
</div>

{/* Mobile dropdown */}
{menuOpen && (
<div className="mt-4 space-y-3 rounded-2xl border border-[var(--border)] bg-[var(--card-muted)]/70 p-4 shadow-sm backdrop-blur-sm sm:hidden">
<div className="mt-4 space-y-3 rounded-2xl border border-[var(--border)] bg-[var(--card-muted)]/70 p-4 shadow-sm backdrop-blur-sm ">
<div className="flex flex-wrap items-center gap-2">
<div className="transition-transform duration-200 hover:scale-[1.05]">
<div className="transition-transform duration-200 hover:scale-[1.05] flex-1">
<KeyboardShortcuts />
</div>

Expand All @@ -357,7 +368,7 @@ export default function DashboardHeader() {
<UserAvatar />
</div>

<div className="transition-transform duration-200 hover:rotate-12">
<div className="transition-transform duration-200 hover:rotate-12 flex-1">
<ThemeToggle />
</div>

Expand Down
2 changes: 1 addition & 1 deletion src/components/ThemeToggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export default function ThemeToggle() {
const currentDescription = themeDefinition?.description ?? "Customize the dashboard palette";

return (
<label className="inline-flex min-h-12 w-full max-w-[260px] cursor-pointer items-center gap-3 rounded-2xl border border-[var(--border)] bg-[var(--card)] px-4 py-3 text-[var(--card-foreground)] shadow-sm transition-all duration-300 hover:bg-[var(--control)] focus-within:border-[var(--accent)]">
<label className="inline-flex min-h-12 w-full max-w-[220px] md:max-w-[260px] cursor-pointer items-center gap-3 rounded-2xl border border-[var(--border)] bg-[var(--card)] px-4 py-3 text-[var(--card-foreground)] shadow-sm transition-all duration-300 hover:bg-[var(--control)] focus-within:border-[var(--accent)]">
<span className="flex h-9 w-9 items-center justify-center rounded-xl bg-[var(--accent-soft)] text-[var(--accent)]">
<PaletteIcon className="h-4 w-4" aria-hidden="true" />
</span>
Expand Down
21 changes: 21 additions & 0 deletions src/hooks/useIsMobile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { useEffect,useState } from "react";

export function useIsMobile(){

const [isMobile, setIsMobile] = useState(false);

useEffect(()=>{
const handleResize = ()=>{
setIsMobile(window.innerWidth <769);
};

handleResize();

window.addEventListener("resize",handleResize);

return ()=>
window.removeEventListener("resize", handleResize);
},[]);

return isMobile;
}
Loading