this repo has no description atmosphereconf-vods.wisp.place/
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

autoplay next

+49 -16
+1
src/routes/tracks.$trackSlug.tsx
··· 215 215 key={session.id} 216 216 to="/videos/$videoSlug" 217 217 params={{ videoSlug: session.slug }} 218 + search={{ autoplay: false }} 218 219 {...stylex.props(styles.sessionLink)} 219 220 > 220 221 <Card style={styles.sessionCard}>
+48 -16
src/routes/videos.$videoSlug.tsx
··· 42 42 const RouterLink = createLink(DSLink); 43 43 44 44 export const Route = createFileRoute("/videos/$videoSlug")({ 45 + validateSearch: (search: Record<string, unknown>) => ({ 46 + autoplay: search.autoplay === true || search.autoplay === "true", 47 + }), 45 48 component: VideoRouteComponent, 46 49 }); 47 50 ··· 61 64 metadataCard: { 62 65 backgroundColor: uiColor.bgSubtle, 63 66 borderColor: uiColor.border2, 67 + marginTop: verticalSpace["8xl"], 64 68 }, 65 69 tag: { 66 70 borderColor: uiColor.border2, ··· 197 201 function VideoRouteComponent() { 198 202 const router = useRouter(); 199 203 const { videoSlug } = Route.useParams(); 204 + const { autoplay } = Route.useSearch(); 200 205 const session = getSessionBySlug(videoSlug); 201 206 202 207 if (!session) { ··· 215 220 216 221 const track = getTrackBySlug(session.trackSlug); 217 222 const day = getConferenceDay(session.dayId); 218 - const siblings = getSessionsForTrack(session.trackSlug) 223 + const trackSessions = getSessionsForTrack(session.trackSlug); 224 + const currentSessionIndex = trackSessions.findIndex( 225 + (candidate) => candidate.id === session.id, 226 + ); 227 + const nextRecordedSession = 228 + currentSessionIndex >= 0 229 + ? trackSessions 230 + .slice(currentSessionIndex + 1) 231 + .find((candidate) => candidate.playlistUrl) 232 + : undefined; 233 + const siblings = trackSessions 219 234 .filter((candidate) => candidate.id !== session.id) 220 235 .slice(0, 4); 221 236 const hasRsvpAttendees = 222 237 session.rsvpAttendees.going.length > 0 || 223 238 session.rsvpAttendees.interested.length > 0; 239 + 240 + function handleVideoEnded() { 241 + if (!nextRecordedSession) { 242 + return; 243 + } 244 + 245 + void router.navigate({ 246 + to: "/videos/$videoSlug", 247 + params: { videoSlug: nextRecordedSession.slug }, 248 + search: { autoplay: true }, 249 + }); 250 + } 224 251 225 252 return ( 226 253 <Page.Root style={styles.root}> ··· 284 311 style={styles.player} 285 312 aria-label={session.title} 286 313 aspectRatio={16 / 9} 314 + autoPlay={autoplay} 315 + onEnded={handleVideoEnded} 287 316 /> 288 317 ) : ( 289 318 <Card style={styles.metadataCard}> 290 319 <CardBody> 291 - <Text 292 - font="title" 293 - size={{ default: "lg", sm: "xl" }} 294 - weight="semibold" 295 - > 296 - This session was not recorded 297 - </Text> 298 - <Text> 299 - This session appears in the schedule, but there is no matching 300 - Streamplace recording for it. 301 - </Text> 302 - {session.note && ( 303 - <Text variant="secondary" style={ui.textDim}> 304 - {session.note} 320 + <Flex direction="column" gap="4xl"> 321 + <Text 322 + font="title" 323 + size={{ default: "lg", sm: "xl" }} 324 + weight="semibold" 325 + > 326 + This session was not recorded 327 + </Text> 328 + <Text variant="secondary"> 329 + This session appears in the schedule, but there is no matching 330 + Streamplace recording for it. 305 331 </Text> 306 - )} 332 + {session.note && ( 333 + <Text variant="secondary" style={ui.textDim}> 334 + {session.note} 335 + </Text> 336 + )} 337 + </Flex> 307 338 </CardBody> 308 339 </Card> 309 340 )} ··· 343 374 key={candidate.id} 344 375 to="/videos/$videoSlug" 345 376 params={{ videoSlug: candidate.slug }} 377 + search={{ autoplay: false }} 346 378 {...stylex.props(styles.relatedLink)} 347 379 > 348 380 <Card style={styles.relatedCard}>