feat(game page): add dismissible plugin CTA banner above Performance Entries
Promotes the DeckyVault Decky plugin to Steam Deck owners browsing game pages. Soft primary-tinted card with Gamepad2 icon, value-prop copy, and 'Get the plugin' CTA linking to /plugin. Dismissible via localStorage (dv-plugin-cta-dismissed) so it stays gone across all games once closed. Controller-navigable (data-gamepad-focusable), responsive layout.
This commit is contained in:
@@ -18,6 +18,7 @@ import {
|
|||||||
GaugeIcon,
|
GaugeIcon,
|
||||||
ChevronDownIcon,
|
ChevronDownIcon,
|
||||||
PencilIcon,
|
PencilIcon,
|
||||||
|
X as XIcon,
|
||||||
} from "lucide-react"
|
} from "lucide-react"
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import { useSession } from "@/lib/auth-client"
|
import { useSession } from "@/lib/auth-client"
|
||||||
@@ -641,6 +642,23 @@ export function GamePageClient({
|
|||||||
)
|
)
|
||||||
const presetsRef = useRef<HTMLDivElement>(null)
|
const presetsRef = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
|
// DeckyVault plugin CTA dismissal (persisted across games in localStorage)
|
||||||
|
const [showPluginCta, setShowPluginCta] = useState(false)
|
||||||
|
useEffect(() => {
|
||||||
|
if (typeof window === "undefined") return
|
||||||
|
if (localStorage.getItem("dv-plugin-cta-dismissed") !== "1") {
|
||||||
|
setShowPluginCta(true)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
const dismissPluginCta = () => {
|
||||||
|
setShowPluginCta(false)
|
||||||
|
try {
|
||||||
|
localStorage.setItem("dv-plugin-cta-dismissed", "1")
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// On mount, auto-open preset from URL
|
// On mount, auto-open preset from URL
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const presetId = searchParams.get("preset")
|
const presetId = searchParams.get("preset")
|
||||||
@@ -1425,6 +1443,39 @@ export function GamePageClient({
|
|||||||
className='px-4 md:px-[10svw]'
|
className='px-4 md:px-[10svw]'
|
||||||
>
|
>
|
||||||
<div className='max-w-7xl mx-auto flex flex-col gap-4'>
|
<div className='max-w-7xl mx-auto flex flex-col gap-4'>
|
||||||
|
{showPluginCta && (
|
||||||
|
<div
|
||||||
|
data-gamepad-focusable
|
||||||
|
className='flex flex-col sm:flex-row sm:items-center gap-3 sm:gap-4 p-3 sm:pr-2 rounded-xl border border-primary/20 bg-primary/5'
|
||||||
|
>
|
||||||
|
<div className='flex items-center gap-3 flex-1 min-w-0'>
|
||||||
|
<div className='shrink-0 w-9 h-9 rounded-lg bg-primary/10 border border-primary/20 flex items-center justify-center'>
|
||||||
|
<Gamepad2Icon className='h-5 w-5 text-primary' />
|
||||||
|
</div>
|
||||||
|
<div className='min-w-0 flex-1'>
|
||||||
|
<p className='text-sm text-text leading-snug'>
|
||||||
|
Have a Steam Deck? Record benchmarks automatically with the DeckyVault Decky plugin — one tap, no manual screenshots.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='flex items-center gap-2 shrink-0'>
|
||||||
|
<Link
|
||||||
|
href='/plugin'
|
||||||
|
className='inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-primary text-white text-xs font-semibold hover:bg-primary/90 transition-colors'
|
||||||
|
>
|
||||||
|
Get the plugin
|
||||||
|
<ExternalLinkIcon className='h-3 w-3' />
|
||||||
|
</Link>
|
||||||
|
<button
|
||||||
|
onClick={dismissPluginCta}
|
||||||
|
className='p-1.5 rounded-md text-text/40 hover:text-text hover:bg-text/5 transition-colors'
|
||||||
|
aria-label='Dismiss'
|
||||||
|
>
|
||||||
|
<XIcon className='h-4 w-4' />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div className='flex items-center justify-between'>
|
<div className='flex items-center justify-between'>
|
||||||
<h2 className='text-lg font-semibold'>
|
<h2 className='text-lg font-semibold'>
|
||||||
Performance Entries
|
Performance Entries
|
||||||
|
|||||||
Reference in New Issue
Block a user