@@ -23,6 +23,8 @@ type PhotoMoment = {
2323 xCompact : number ;
2424 y : number ;
2525 yCompact : number ;
26+ href ?: string ;
27+ linkLabel ?: string ;
2628} ;
2729
2830type Jam2026PhotoMomentsProps = {
@@ -70,6 +72,8 @@ const PHOTO_MOMENTS = [
7072 xCompact : - 136 ,
7173 y : 571 ,
7274 yCompact : 365 ,
75+ href : "https://shop.remix.run/products/remix-tee?discount=START_YOUR_ENGINES" ,
76+ linkLabel : "Shop Remix tee" ,
7377 } ,
7478 {
7579 id : "speaker-ryan" ,
@@ -223,17 +227,23 @@ export let Jam2026PhotoMoments = clientEntry(
223227 let state = runtime [ moment . id ] ;
224228 if ( ! state ?. isOpen ) return null ;
225229
230+ let { href, linkLabel = moment . filename } : PhotoMoment = moment ;
231+ let draggable = ! href ;
232+
226233 return (
227234 < article
228235 key = { moment . id }
229236 data-dragging = { drag ?. id === moment . id ? "true" : undefined }
230237 data-photo-window-id = { moment . id }
231238 mix = { [
232239 photoMomentPositionStyle ,
240+ draggable ? photoMomentDraggableStyle : undefined ,
233241 moment . anchor === "right"
234242 ? photoMomentRightStyle
235243 : photoMomentLeftStyle ,
236- on ( "pointerdown" , ( event ) => handleStart ( event , moment . id ) ) ,
244+ draggable
245+ ? on ( "pointerdown" , ( event ) => handleStart ( event , moment . id ) )
246+ : undefined ,
237247 on ( "focusin" , ( ) => {
238248 bringToFront ( moment . id ) ;
239249 handle . update ( ) ;
@@ -288,15 +298,34 @@ export let Jam2026PhotoMoments = clientEntry(
288298 </ button >
289299 < p mix = { jam2026WindowTitleStyle } > { moment . filename } </ p >
290300 </ div >
291- < div mix = { photoMomentImageFrameStyle } >
292- < img
293- alt = ""
294- decoding = "async"
295- draggable = { false }
296- loading = "eager"
297- src = { moment . src }
298- />
299- </ div >
301+ { href ? (
302+ < a
303+ aria-label = { linkLabel }
304+ href = { href }
305+ mix = { [
306+ photoMomentImageFrameStyle ,
307+ photoMomentImageLinkStyle ,
308+ ] }
309+ >
310+ < img
311+ alt = ""
312+ decoding = "async"
313+ draggable = { false }
314+ loading = "eager"
315+ src = { moment . src }
316+ />
317+ </ a >
318+ ) : (
319+ < div mix = { photoMomentImageFrameStyle } >
320+ < img
321+ alt = ""
322+ decoding = "async"
323+ draggable = { false }
324+ loading = "eager"
325+ src = { moment . src }
326+ />
327+ </ div >
328+ ) }
300329 </ div >
301330 </ div >
302331 </ article >
@@ -326,19 +355,22 @@ let photoLayerStyle = css({
326355} ) ;
327356
328357let photoMomentPositionStyle = css ( {
329- cursor : "grab" ,
330358 pointerEvents : "auto" ,
331359 position : "absolute" ,
332360 top : "var(--jam-2026-photo-y)" ,
361+ [ breakpointMedia . xl ] : {
362+ top : "var(--jam-2026-photo-y-wide)" ,
363+ } ,
364+ } ) ;
365+
366+ let photoMomentDraggableStyle = css ( {
367+ cursor : "grab" ,
333368 touchAction : "none" ,
334369 userSelect : "none" ,
335370 WebkitUserSelect : "none" ,
336371 '&[data-dragging="true"]' : {
337372 cursor : "grabbing" ,
338373 } ,
339- [ breakpointMedia . xl ] : {
340- top : "var(--jam-2026-photo-y-wide)" ,
341- } ,
342374} ) ;
343375
344376let photoMomentLeftStyle = css ( {
@@ -385,9 +417,10 @@ let photoMomentSurfaceStyle = css({
385417 transformOrigin : "50% 50%" ,
386418 transition :
387419 "transform 350ms cubic-bezier(0.22, 1.5, 0.36, 1), box-shadow 350ms cubic-bezier(0.22, 1.5, 0.36, 1)" ,
388- "[data-photo-window-id]:hover &" : {
389- transform : "rotate(-2deg)" ,
390- } ,
420+ "[data-photo-window-id]:hover &, [data-photo-window-id]:has(:focus-visible) &" :
421+ {
422+ transform : "rotate(-2deg)" ,
423+ } ,
391424 "[data-dragging='true'] &" : {
392425 boxShadow :
393426 "0 2px 4px light-dark(rgb(8 40 69 / 0.08), rgb(0 0 0 / 0.24)), 0 8px 16px light-dark(rgb(8 40 69 / 0.07), rgb(0 0 0 / 0.28)), 0 20px 36px light-dark(rgb(8 40 69 / 0.08), rgb(0 0 0 / 0.32)), 0 40px 72px light-dark(rgb(8 40 69 / 0.1), rgb(0 0 0 / 0.38))" ,
@@ -398,9 +431,10 @@ let photoMomentSurfaceStyle = css({
398431 } ,
399432 "@media (prefers-reduced-motion: reduce)" : {
400433 transition : "none" ,
401- "[data-photo-window-id]:hover &" : {
402- transform : "rotate(0deg)" ,
403- } ,
434+ "[data-photo-window-id]:hover &, [data-photo-window-id]:has(:focus-visible) &" :
435+ {
436+ transform : "rotate(0deg)" ,
437+ } ,
404438 "[data-dragging='true'] &" : {
405439 transform : "none" ,
406440 } ,
@@ -466,3 +500,15 @@ let photoMomentImageFrameStyle = css({
466500 WebkitUserDrag : "none" ,
467501 } ,
468502} ) ;
503+
504+ let photoMomentImageLinkStyle = css ( {
505+ color : "inherit" ,
506+ cursor : "pointer" ,
507+ display : "block" ,
508+ outline : "none" ,
509+ textDecoration : "none" ,
510+ "&:focus-visible" : {
511+ outline : `2px solid ${ jamTheme . brandRed } ` ,
512+ outlineOffset : "2px" ,
513+ } ,
514+ } ) ;
0 commit comments