Skip to content
Merged
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
12 changes: 12 additions & 0 deletions src/app/wrapped/wrapped.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,18 @@ export const WRAPPED_DEFAULTS: WrappedSettings = {
progress: "bars",
};

// --- Navbar promo button ---------------------------------------------------

/**
* The navbar "Wrapped" button is shown until this moment (local time).
* After it passes the button disappears; the /wrapped page itself stays up.
*/
export const WRAPPED_PROMO_ENDS_AT = new Date("2026-08-01T00:00:00");

export function isWrappedPromoActive(now: Date = new Date()): boolean {
return now < WRAPPED_PROMO_ENDS_AT;
}

// --- Logo easter egg -------------------------------------------------------

/** Clicks on the logo (in a row) that trigger a random theme. */
Expand Down
2 changes: 2 additions & 0 deletions src/components/navbar/mobile-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { AuthButtons } from "./auth-buttons";
import { LogoutButton } from "./logout-button";
import { NavLinks } from "./nav-links";
import { NavbarActions } from "./navbar-actions";
import { WrappedButton } from "./wrapped-button";

interface MobileMenuProps {
onNavigate?: () => void;
Expand All @@ -20,6 +21,7 @@ export function MobileMenu({ onNavigate }: MobileMenuProps) {
<nav className="flex flex-col gap-2 border-t pt-2 md:hidden">
<NavLinks variant="mobile" onNavigate={onNavigate} />
<div className="flex flex-wrap gap-2 pt-2">
<WrappedButton onNavigate={onNavigate} />
<AuthButtons onNavigate={onNavigate} />
<NavbarActions />
{isAuthenticated ? <LogoutButton onLogout={onNavigate} /> : null}
Expand Down
2 changes: 2 additions & 0 deletions src/components/navbar/navbar-client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { MobileMenu } from "./mobile-menu";
import { MobileMenuButton } from "./mobile-menu-button";
import { NavLinks } from "./nav-links";
import { NavbarActions } from "./navbar-actions";
import { WrappedButton } from "./wrapped-button";

export function NavbarClient() {
const [expanded, setExpanded] = useState(false);
Expand All @@ -36,6 +37,7 @@ export function NavbarClient() {
<NavLinks variant="desktop" />
</nav>
<div className="hidden items-center gap-2 md:flex">
<WrappedButton />
<AuthButtons />
<NavbarActions />
{isAuthenticated ? <LogoutButton /> : null}
Expand Down
43 changes: 43 additions & 0 deletions src/components/navbar/wrapped-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"use client";

import { SparklesIcon } from "lucide-react";
import { useContext } from "react";

import { AppContext } from "@/app-context";
import { isWrappedPromoActive } from "@/app/wrapped/wrapped.config";
import { ButtonLink } from "@/components/ui/button";
import { PermissionAction } from "@/lib/auth/permissions";

interface WrappedButtonProps {
onNavigate?: () => void;
}

export function WrappedButton({ onNavigate }: WrappedButtonProps) {
const { checkPermission } = useContext(AppContext);

if (
!isWrappedPromoActive() ||
!checkPermission(PermissionAction.VIEW_WRAPPED)
) {
return null;
}

return (
<ButtonLink
href="/wrapped"
onClick={onNavigate}
className="relative isolate overflow-hidden border border-orange-200/60 bg-linear-to-br from-violet-500 via-pink-500 to-orange-400 text-white shadow-[0_8px_22px_-14px_rgba(217,70,239,0.95)] duration-300 hover:scale-105 hover:border-orange-100/80 hover:shadow-[0_12px_32px_-12px_rgba(217,70,239,1)] active:scale-95 active:duration-75"
>
<span
aria-hidden
className="absolute inset-0 -z-10 bg-linear-to-br from-orange-400 via-pink-500 to-violet-500 opacity-0 transition-opacity duration-300 group-hover/button:opacity-100"
/>
<span
aria-hidden
className="absolute inset-y-0 left-0 -z-10 w-full -translate-x-full bg-linear-to-r from-transparent via-white/30 to-transparent transition-transform duration-700 ease-out group-hover/button:translate-x-full"
/>
<SparklesIcon className="transition-transform duration-300 group-hover/button:scale-110 group-hover/button:rotate-12" />
Wrapped
</ButtonLink>
);
}
Loading