124 lines
4.3 KiB
TypeScript
124 lines
4.3 KiB
TypeScript
import { Compass } from '../../lib/icons'
|
|
|
|
export interface TimeSlot {
|
|
title: string
|
|
subtitle: string
|
|
genres: string[]
|
|
}
|
|
|
|
export function pickTimeOfDaySlot(): TimeSlot {
|
|
const hour = new Date().getHours()
|
|
if (hour >= 5 && hour < 12) {
|
|
return {
|
|
title: 'A gentle start',
|
|
subtitle: 'Morning picks - light comedy, animation, and feel-good',
|
|
genres: ['Comedy', 'Animation', 'Family'],
|
|
}
|
|
}
|
|
if (hour >= 12 && hour < 17) {
|
|
return {
|
|
title: 'Afternoon adventure',
|
|
subtitle: 'Action, sci-fi, and adventure for the daylight hours',
|
|
genres: ['Action', 'Adventure', 'Science Fiction'],
|
|
}
|
|
}
|
|
if (hour >= 17 && hour < 22) {
|
|
return {
|
|
title: 'Evening watch',
|
|
subtitle: 'Prestige drama and thrillers for prime time',
|
|
genres: ['Drama', 'Thriller', 'Mystery'],
|
|
}
|
|
}
|
|
return {
|
|
title: 'After hours',
|
|
subtitle: 'Horror, noir, and the dark stuff for late nights',
|
|
genres: ['Horror', 'Crime', 'Thriller'],
|
|
}
|
|
}
|
|
|
|
/** Day-bucketed shuffle - rotates a few times a day, stable within a session. */
|
|
export function dailyBucket(): number {
|
|
// Changes every 6 hours so the order rotates a few times a day
|
|
return Math.floor(Date.now() / (6 * 3600 * 1000))
|
|
}
|
|
|
|
export function seededShuffle<T>(arr: T[], seed: number): T[] {
|
|
const out = [...arr]
|
|
let s = seed | 0
|
|
const random = () => {
|
|
s = (s + 0x6D2B79F5) | 0
|
|
let t = Math.imul(s ^ (s >>> 15), 1 | s)
|
|
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t
|
|
return ((t ^ (t >>> 14)) >>> 0) / 4294967296
|
|
}
|
|
for (let i = out.length - 1; i > 0; i--) {
|
|
const j = Math.floor(random() * (i + 1))
|
|
;[out[i], out[j]] = [out[j], out[i]]
|
|
}
|
|
return out
|
|
}
|
|
|
|
export function Dot() {
|
|
return <span className="text-white/30">·</span>
|
|
}
|
|
|
|
export function HomeSkeleton() {
|
|
return (
|
|
<div className="pb-12">
|
|
<div className="relative h-[60vh] min-h-[440px] -mt-14 mb-2 overflow-hidden">
|
|
<div className="absolute inset-0 skeleton" />
|
|
<div className="absolute inset-0 bg-gradient-to-r from-void via-void/50 to-transparent" />
|
|
<div className="absolute inset-0 bg-gradient-to-t from-void via-transparent to-transparent" />
|
|
<div className="relative h-full flex items-end pb-16 px-7">
|
|
<div className="max-w-2xl space-y-3 w-full">
|
|
<div className="skeleton h-5 w-24 rounded" />
|
|
<div className="skeleton h-12 w-2/3 rounded" />
|
|
<div className="skeleton h-4 w-1/3 rounded" />
|
|
<div className="skeleton h-12 w-1/2 rounded mt-4" />
|
|
<div className="flex gap-2 mt-2">
|
|
<div className="skeleton h-10 w-24 rounded-lg" />
|
|
<div className="skeleton h-10 w-28 rounded-lg" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="-mt-4 relative z-10 space-y-10">
|
|
{[0, 1, 2].map(i => (
|
|
<div key={i}>
|
|
<div className="px-7 mb-3.5">
|
|
<div className="skeleton h-5 w-40 rounded mb-1.5" />
|
|
<div className="skeleton h-3 w-56 rounded" />
|
|
</div>
|
|
<div className="px-7 flex gap-3">
|
|
{Array.from({ length: 6 }).map((_, j) => (
|
|
<div key={j} className="shrink-0 w-[160px]">
|
|
<div className="skeleton aspect-[2/3] rounded-lg" />
|
|
<div className="skeleton h-3 w-3/4 mt-2 rounded" />
|
|
<div className="skeleton h-2.5 w-1/2 mt-1 rounded" />
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export function EmptyHome() {
|
|
return (
|
|
<div className="flex flex-col items-center justify-center min-h-[70vh] text-center px-6">
|
|
<div className="relative w-20 h-20 mb-5">
|
|
<div className="absolute inset-0 rounded-full bg-accent/10 blur-2xl" />
|
|
<div className="relative w-full h-full rounded-full bg-gradient-to-br from-accent/20 to-accent/5 ring-1 ring-accent/20 grid place-items-center">
|
|
<Compass size={28} className="text-accent" />
|
|
</div>
|
|
</div>
|
|
<h2 className="text-[20px] font-semibold text-text-1 mb-1.5 tracking-tight">Welcome to Jellybloom</h2>
|
|
<p className="text-[13px] text-text-3 max-w-md leading-relaxed">
|
|
Your library is quiet. Add movies, shows, or music to your server and they'll appear here.
|
|
</p>
|
|
</div>
|
|
)
|
|
}
|