From 4dc0ba5af568f4bc5b4544d588c2e21dd775c2bd Mon Sep 17 00:00:00 2001 From: Max Wofford Date: Tue, 20 Feb 2024 12:45:09 -0500 Subject: [PATCH] Bring Woz component above the fold (#1080) * Break out recap to own component * Create sleep.js * Add woz quote above fold for onboard --- components/announcement.js | 15 ++- components/onboard/recap.js | 256 +++++++++++++++++++++++++++++++++++ lib/sleep.js | 4 + pages/onboard/index.js | 259 ++---------------------------------- 4 files changed, 288 insertions(+), 246 deletions(-) create mode 100644 components/onboard/recap.js create mode 100644 lib/sleep.js diff --git a/components/announcement.js b/components/announcement.js index 57536346..a34c5e68 100644 --- a/components/announcement.js +++ b/components/announcement.js @@ -1,6 +1,7 @@ -import { Card, Text } from 'theme-ui' +import { Card, Text, Box } from 'theme-ui' import { keyframes } from '@emotion/react' import Icon from './icon' +import Image from 'next/image' const unfold = keyframes({ from: { transform: 'scaleY(0)' }, @@ -12,6 +13,8 @@ const Announcement = ({ copy, iconLeft, iconRight, + imgSrc, + imgAlt, color = 'accent', sx = {}, ...props @@ -48,6 +51,16 @@ const Announcement = ({ sx={{ mr: [2, 3], ml: 2, color, display: ['none', 'block'] }} /> )} + {imgSrc && ( + + {imgAlt} + + )} { + const prefersReducedMotion = usePrefersReducedMotion() + // Fancy lights animation + const lightsScrollTrigger = useRef() + const lightsAnimated = useRef(false) + useEffect(() => { + let canceled = false + + const setAtIndex = (i, color) => { + if (canceled) return + + // Going outside of React for performance + const el = document.getElementById(`pixel-${i}`) + if (!el) return + + if (recapPixels[i]) { + el.style.background = color + el.style.boxShadow = `0 0 10px ${color}` + } else { + el.style.background = dimBg + el.style.boxShadow = 'none' + } + } + const setAll = color => { + for (let i = 0; i < recapPixels.length; i++) setAtIndex(i, color) + } + + const animate = async () => { + if (lightsAnimated.current) return + lightsAnimated.current = true + + // Illuminate lights in diagonal lines starting with only top left. + for ( + let curColumn = 0; + curColumn < recapWidth + recapHeight; + curColumn++ + ) { + for ( + let offset = curColumn; + offset >= Math.max(0, curColumn - recapHeight); + offset-- + ) { + const i = curColumn * recapWidth + offset - offset * recapWidth + setAtIndex(i, '#ffffff') + if (!recapPixels[i]) await sleep(4) + if (canceled) return + } + // await sleep(2); if (canceled) return + } + + // Flash the lights twice + await sleep(600) + if (canceled) return + + setAll(dimBg) + await sleep(80) + if (canceled) return + + setAll('#aaaaaa') + await sleep(20) + if (canceled) return + + setAll(dimBg) + await sleep(30) + if (canceled) return + + setAll('#aaaaaa') + await sleep(100) + if (canceled) return + + setAll(dimBg) + await sleep(200) + if (canceled) return + + // Animate rainbow 2-column increments + for (let x = 0; x < recapWidth; x++) { + const color = `hsl(${(x * 360) / recapWidth}, 100%, 65%)` + for (let y = 0; y < recapHeight; y++) { + const i = y * recapWidth + x + setAtIndex(i, color) + } + if (x % 2 === 1) await sleep(35) + } + } + + if (prefersReducedMotion) { + if (!lightsAnimated.current) setAll('#ffffff') + return () => (canceled = true) + } else { + const observer = new IntersectionObserver( + ([entry]) => { + if (entry.isIntersecting) animate() + }, + { threshold: 0.5 } + ) + observer.observe(lightsScrollTrigger.current) + return () => { + canceled = true + observer.disconnect() + } + } + }, [prefersReducedMotion]) + + return ( + + {recapPixels.map((_, i) => ( + + ))} + + + ) +} + +export default Recap \ No newline at end of file diff --git a/lib/sleep.js b/lib/sleep.js new file mode 100644 index 00000000..75200d76 --- /dev/null +++ b/lib/sleep.js @@ -0,0 +1,4 @@ +// Beloved classic utility function :3 +const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)) + +export default sleep \ No newline at end of file diff --git a/pages/onboard/index.js b/pages/onboard/index.js index f822df49..5dd5be2f 100644 --- a/pages/onboard/index.js +++ b/pages/onboard/index.js @@ -7,8 +7,11 @@ import Footer from '../../components/footer' import FadeIn from '../../components/fade-in' import Sparkles from '../../components/sparkles' import Tilt from '../../components/tilt' +import Recap from '../../components/onboard/recap' import usePrefersReducedMotion from '../../lib/use-prefers-reduced-motion' import { useEffect, useRef, useState } from 'react' +import sleep from '../../lib/sleep' +import Announcement from '../../components/announcement' /** * @type {import('theme-ui').ThemeUIStyleObject} @@ -23,135 +26,6 @@ const traceSx = { const dimBg = '#151515' -// Beloved classic utility function :3 -const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)) - -// "LET'S RECAP" pixel art (exported from Piskel) -// Original: https://doggo.ninja/fiK0nk.piskel -const recapWidth = 71 -const recapHeight = 10 -const recapPixels = [ - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, - 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, - 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, - 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, - 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, - 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, - 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, - 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, - 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, - 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, - 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, - 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, - 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, - 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, - 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, - 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, - 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, - 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, - 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, - 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, - 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, - 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, - 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, - 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xffffffff -] - const slackLink = '/slack/?event=onboard' const stickerButtonText = 'Click 4 Stickers' @@ -255,106 +129,6 @@ const ShipPage = () => { return () => observer.disconnect() }, []) - // Fancy lights animation - const lightsScrollTrigger = useRef() - const lightsAnimated = useRef(false) - useEffect(() => { - let canceled = false - - const setAtIndex = (i, color) => { - if (canceled) return - - // Going outside of React for performance - const el = document.getElementById(`pixel-${i}`) - if (!el) return - - if (recapPixels[i]) { - el.style.background = color - el.style.boxShadow = `0 0 10px ${color}` - } else { - el.style.background = dimBg - el.style.boxShadow = 'none' - } - } - const setAll = color => { - for (let i = 0; i < recapPixels.length; i++) setAtIndex(i, color) - } - - const animate = async () => { - if (lightsAnimated.current) return - lightsAnimated.current = true - - // Illuminate lights in diagonal lines starting with only top left. - for ( - let curColumn = 0; - curColumn < recapWidth + recapHeight; - curColumn++ - ) { - for ( - let offset = curColumn; - offset >= Math.max(0, curColumn - recapHeight); - offset-- - ) { - const i = curColumn * recapWidth + offset - offset * recapWidth - setAtIndex(i, '#ffffff') - if (!recapPixels[i]) await sleep(4) - if (canceled) return - } - // await sleep(2); if (canceled) return - } - - // Flash the lights twice - await sleep(600) - if (canceled) return - - setAll(dimBg) - await sleep(80) - if (canceled) return - - setAll('#aaaaaa') - await sleep(20) - if (canceled) return - - setAll(dimBg) - await sleep(30) - if (canceled) return - - setAll('#aaaaaa') - await sleep(100) - if (canceled) return - - setAll(dimBg) - await sleep(200) - if (canceled) return - - // Animate rainbow 2-column increments - for (let x = 0; x < recapWidth; x++) { - const color = `hsl(${(x * 360) / recapWidth}, 100%, 65%)` - for (let y = 0; y < recapHeight; y++) { - const i = y * recapWidth + x - setAtIndex(i, color) - } - if (x % 2 === 1) await sleep(35) - } - } - - if (prefersReducedMotion) { - if (!lightsAnimated.current) setAll('#ffffff') - return () => (canceled = true) - } else { - const observer = new IntersectionObserver( - ([entry]) => { - if (entry.isIntersecting) animate() - }, - { threshold: 0.5 } - ) - observer.observe(lightsScrollTrigger.current) - return () => { - canceled = true - observer.disconnect() - } - } - }, [prefersReducedMotion]) return ( <> @@ -425,9 +199,18 @@ const ShipPage = () => { position: 'relative' }} > + + + { Let's Recap - - {recapPixels.map((_, i) => ( - - ))} - - +