ultisuite-client/components/first-launch-splash.tsx
R3D347HR4Y ad1370ea7e
Some checks are pending
E2E / Playwright e2e (push) Waiting to run
feat: enhance configuration and add new demo layouts
- Introduced turbopack alias for canvas in next.config.mjs.
- Updated package.json scripts for development and branding tasks.
- Added new dependencies for Tiptap extensions.
- Implemented new demo layouts for agenda, contacts, drive, and mail applications.
- Enhanced globals.css for improved theming and splash screen animations.
- Added OAuth callback handling for drive mounts.
- Updated layout components to integrate new demo shells and improve structure.
2026-06-12 19:10:24 +02:00

133 lines
4.2 KiB
TypeScript

"use client"
import { useEffect, useLayoutEffect, useState } from "react"
import { usePathname } from "next/navigation"
import { UltiMailLogo } from "@/components/ultimail-logo"
import {
markSuiteSplashSeen,
shouldShowSuiteSplash,
suiteSplashAppFromPath,
SUITE_SPLASH_CONFIG,
type SuiteSplashApp,
} from "@/lib/suite/suite-app-splash"
import { suitePublicAsset } from "@/lib/suite/suite-public-asset"
import { cn } from "@/lib/utils"
const SPLASH_VISIBLE_MS = 1750
const SPLASH_EXIT_MS = 500
export function FirstLaunchSplash({
children,
}: {
children: React.ReactNode
}) {
const pathname = usePathname()
const [activeApp, setActiveApp] = useState<SuiteSplashApp | null>(() =>
typeof window === "undefined"
? null
: shouldShowSuiteSplash(window.location.pathname)
)
const [isHiding, setIsHiding] = useState(false)
const [isComplete, setIsComplete] = useState(() => activeApp === null)
useLayoutEffect(() => {
const nextApp = shouldShowSuiteSplash(pathname)
const root = document.documentElement
root.dataset.splashApp = suiteSplashAppFromPath(pathname) ?? ""
root.dataset.splashSeen = nextApp ? "0" : "1"
setActiveApp(nextApp)
setIsComplete(nextApp === null)
setIsHiding(false)
}, [pathname])
useEffect(() => {
if (!activeApp) return
const hideTimer = window.setTimeout(() => {
setIsHiding(true)
}, SPLASH_VISIBLE_MS)
const completeTimer = window.setTimeout(() => {
markSuiteSplashSeen(activeApp)
document.documentElement.dataset.splashSeen = "1"
setActiveApp(null)
setIsComplete(true)
}, SPLASH_VISIBLE_MS + SPLASH_EXIT_MS)
return () => {
window.clearTimeout(hideTimer)
window.clearTimeout(completeTimer)
}
}, [activeApp])
const config = activeApp ? SUITE_SPLASH_CONFIG[activeApp] : null
return (
<>
{children}
{!isComplete && config ? (
<div
className={cn("app-first-launch-splash", isHiding && "app-first-launch-splash--hide")}
role="status"
aria-live="polite"
aria-label={config.ariaLabel}
data-suite-splash={activeApp}
>
<div className="app-first-launch-splash__aurora" aria-hidden />
<div className="app-first-launch-splash__grain" aria-hidden />
<div className="app-first-launch-splash__content">
<div className="app-first-launch-splash__pill">{config.pill}</div>
{activeApp === "mail" ? (
<UltiMailLogo href={null} className="app-first-launch-splash__logo" />
) : config.markDark ? (
<>
<img
src={suitePublicAsset(config.mark)}
alt=""
className={cn(
"app-first-launch-splash__mark dark:hidden",
config.spinMark && "app-first-launch-splash__mark--spin"
)}
width={56}
height={56}
decoding="async"
draggable={false}
/>
<img
src={suitePublicAsset(config.markDark)}
alt=""
className={cn(
"app-first-launch-splash__mark hidden dark:block",
config.spinMark && "app-first-launch-splash__mark--spin"
)}
width={56}
height={56}
decoding="async"
draggable={false}
/>
</>
) : (
<img
src={suitePublicAsset(config.mark)}
alt=""
className={cn(
"app-first-launch-splash__mark",
config.spinMark && "app-first-launch-splash__mark--spin"
)}
width={56}
height={56}
decoding="async"
draggable={false}
/>
)}
<p className="app-first-launch-splash__subtitle">{config.subtitle}</p>
<div className="app-first-launch-splash__loader" aria-hidden>
<span />
</div>
</div>
</div>
) : null}
</>
)
}