LCOV - code coverage report
Current view: top level - dashql-app/src/demos/landing_backdrop - landing_backdrop_page.tsx Coverage Total Hit
Test: DashQL d805a4b Lines: 0.0 % 179 0
Test Date: 2026-11-09 20:22:13

            Line data    Source code
       1              : import * as React from 'react';
       2              : 
       3              : import * as baseStyles from '../../ui/foundations/banner_page.module.css';
       4              : 
       5              : import { useFlavorWobbleBrand } from '../../agent/wobble.js';
       6              : import { DASHQL_BRAND, DBCOM_BRAND, OMEN_BRAND } from '@ankoh/dashql-ui/wobble/wobble_morph';
       7              : import { CLOUD_DENSITIES, DEFAULT_LANDING_BACKDROP as DEFAULTS, type BackdropStats } from '@ankoh/dashql-ui/landing_backdrop/landing_backdrop';
       8              : import { Button, ButtonSize, ButtonVariant } from '../../ui/foundations/button.js';
       9              : import { SegmentedControl, SegmentedControlSize } from '../../ui/foundations/segmented_control.js';
      10              : import { LandingBackdrop } from './landing_backdrop.js';
      11              : import * as styles from './landing_backdrop_page.module.css';
      12              : 
      13            0 : const BRANDS = [
      14            0 :     { label: 'DashQL', brand: DASHQL_BRAND },
      15            0 :     { label: 'Database.com', brand: DBCOM_BRAND },
      16            0 :     { label: 'Omen', brand: OMEN_BRAND },
      17            0 : ];
      18              : 
      19              : /// The sphere of dots that turns into the brand mark, with knobs to tune it
      20            0 : function LandingBackdropPage(): React.ReactElement {
      21            0 :     const flavorBrand = useFlavorWobbleBrand();
      22            0 :     const [brand, setBrand] = React.useState(() => Math.max(0, BRANDS.findIndex(entry => entry.brand === flavorBrand)));
      23            0 :     const [period, setPeriod] = React.useState(DEFAULTS.period);
      24            0 :     const [contrast, setContrast] = React.useState(DEFAULTS.contrast);
      25            0 :     const [density, setDensity] = React.useState(0);
      26            0 :     const [particles, setParticles] = React.useState(DEFAULTS.particles);
      27            0 :     const [ringFps, setRingFps] = React.useState(DEFAULTS.ringFps);
      28            0 :     const [ringInk, setRingInk] = React.useState(DEFAULTS.ringInk);
      29            0 :     const [outerWobble, setOuterWobble] = React.useState(DEFAULTS.outerWobble);
      30            0 :     const [gap, setGap] = React.useState(DEFAULTS.gap);
      31            0 :     const [fly, setFly] = React.useState(DEFAULTS.fly);
      32            0 :     const [lightSeconds, setLightSeconds] = React.useState(DEFAULTS.lightSeconds);
      33            0 :     const [glow, setGlow] = React.useState(DEFAULTS.glow);
      34            0 :     const [logoDensity, setLogoDensity] = React.useState(DEFAULTS.density);
      35            0 :     const [sphereDensity, setSphereDensity] = React.useState(DEFAULTS.sphereDensity);
      36            0 :     const [ringDensity, setRingDensity] = React.useState(DEFAULTS.ringDensity);
      37            0 :     const [twinkleSeconds, setTwinkleSeconds] = React.useState(DEFAULTS.twinkleSeconds);
      38            0 :     const [wobble, setWobble] = React.useState(DEFAULTS.wobble);
      39            0 :     const [markWobble, setMarkWobble] = React.useState(DEFAULTS.markWobble);
      40            0 :     const [scale, setScale] = React.useState(DEFAULTS.scale);
      41            0 :     const [eyes, setEyes] = React.useState<boolean>(DEFAULTS.eyes);
      42            0 :     const [stats, setStats] = React.useState<BackdropStats | null>(null);
      43            0 :     const [motion, setMotion] = React.useState(() => !(globalThis.matchMedia?.('(prefers-reduced-motion: reduce)').matches ?? false));
      44            0 :     const [controlsShown, setControlsShown] = React.useState(true);
      45              : 
      46            0 :     return (
      47            0 :         <div className={`${baseStyles.page} ${styles.page}`}>
      48            0 :             <LandingBackdrop brand={BRANDS[brand].brand} period={period} contrast={contrast} motion={motion} dots={CLOUD_DENSITIES[density]} wobble={wobble} markWobble={markWobble} scale={scale} eyes={eyes} particles={particles} ringFps={ringFps} ringInk={ringInk} outerWobble={outerWobble} gap={gap} fly={fly} lightSeconds={lightSeconds} glow={glow} density={logoDensity} sphereDensity={sphereDensity} ringDensity={ringDensity} twinkleSeconds={twinkleSeconds} onStats={setStats} />
      49            0 :             {controlsShown
      50              :                 ? (
      51            0 :                     <div className={styles.controls}>
      52            0 :                         <h1 className={styles.title}>Landing Backdrop</h1>
      53            0 :                         <label className={styles.knob}>
      54            0 :                             <span className={styles.control_label}>Cycle</span>
      55            0 :                             <input id="landing-backdrop-cycle" type="range" min={6} max={60} step={1} value={period}
      56            0 :                                 onChange={e => setPeriod(Number(e.target.value))} />
      57            0 :                             <span className={styles.knob_value}>{period}s</span>
      58            0 :                         </label>
      59            0 :                         <label className={styles.knob}>
      60            0 :                             <span className={styles.control_label}>Size</span>
      61            0 :                             <input id="landing-backdrop-size" type="range" min={0.3} max={1.2} step={0.01} value={scale}
      62            0 :                                 onChange={e => setScale(Number(e.target.value))} />
      63            0 :                             <span className={styles.knob_value}>{Math.round(scale * 100)}%</span>
      64            0 :                         </label>
      65            0 :                         <label className={styles.knob}>
      66            0 :                             <span className={styles.control_label}>Wobble</span>
      67            0 :                             <input id="landing-backdrop-wobble" type="range" min={0} max={0.2} step={0.005} value={wobble}
      68            0 :                                 onChange={e => setWobble(Number(e.target.value))} />
      69            0 :                             <span className={styles.knob_value}>{wobble.toFixed(3)}</span>
      70            0 :                         </label>
      71            0 :                         <label className={styles.knob}>
      72            0 :                             <span className={styles.control_label}>Logo</span>
      73            0 :                             <input id="landing-backdrop-mark-wobble" type="range" min={0} max={0.12} step={0.005} value={markWobble}
      74            0 :                                 onChange={e => setMarkWobble(Number(e.target.value))} />
      75            0 :                             <span className={styles.knob_value}>{markWobble.toFixed(3)}</span>
      76            0 :                         </label>
      77            0 :                         <label className={styles.knob}>
      78            0 :                             <span className={styles.control_label}>Light</span>
      79            0 :                             <input id="landing-backdrop-light" type="range" min={2} max={30} step={0.5} value={lightSeconds}
      80            0 :                                 onChange={e => setLightSeconds(Number(e.target.value))} />
      81            0 :                             <span className={styles.knob_value}>{lightSeconds.toFixed(1)}s</span>
      82            0 :                         </label>
      83            0 :                         <label className={styles.knob}>
      84            0 :                             <span className={styles.control_label}>Glow</span>
      85            0 :                             <input id="landing-backdrop-glow" type="range" min={0} max={2} step={0.05} value={glow}
      86            0 :                                 onChange={e => setGlow(Number(e.target.value))} />
      87            0 :                             <span className={styles.knob_value}>{glow.toFixed(2)}</span>
      88            0 :                         </label>
      89            0 :                         <label className={styles.knob}>
      90            0 :                             <span className={styles.control_label}>Logo dots</span>
      91            0 :                             <input id="landing-backdrop-density" type="range" min={0.05} max={1} step={0.01} value={logoDensity}
      92            0 :                                 onChange={e => setLogoDensity(Number(e.target.value))} />
      93            0 :                             <span className={styles.knob_value}>{Math.round(logoDensity * 100)}%</span>
      94            0 :                         </label>
      95            0 :                         <label className={styles.knob}>
      96            0 :                             <span className={styles.control_label}>Sphere</span>
      97            0 :                             <input id="landing-backdrop-sphere-density" type="range" min={0.05} max={1} step={0.01} value={sphereDensity}
      98            0 :                                 onChange={e => setSphereDensity(Number(e.target.value))} />
      99            0 :                             <span className={styles.knob_value}>{Math.round(sphereDensity * 100)}%</span>
     100            0 :                         </label>
     101            0 :                         <label className={styles.knob}>
     102            0 :                             <span className={styles.control_label}>Ring</span>
     103            0 :                             <input id="landing-backdrop-ring-density" type="range" min={0.05} max={1} step={0.01} value={ringDensity}
     104            0 :                                 onChange={e => setRingDensity(Number(e.target.value))} />
     105            0 :                             <span className={styles.knob_value}>{Math.round(ringDensity * 100)}%</span>
     106            0 :                         </label>
     107            0 :                         <label className={styles.knob}>
     108            0 :                             <span className={styles.control_label}>Twinkle</span>
     109            0 :                             <input id="landing-backdrop-twinkle" type="range" min={0.5} max={15} step={0.1} value={twinkleSeconds}
     110            0 :                                 onChange={e => setTwinkleSeconds(Number(e.target.value))} />
     111            0 :                             <span className={styles.knob_value}>{twinkleSeconds.toFixed(1)}s</span>
     112            0 :                         </label>
     113            0 :                         <label className={styles.knob}>
     114            0 :                             <span className={styles.control_label}>Contrast</span>
     115            0 :                             <input id="landing-backdrop-contrast" type="range" min={0.25} max={3} step={0.05} value={contrast}
     116            0 :                                 onChange={e => setContrast(Number(e.target.value))} />
     117            0 :                             <span className={styles.knob_value}>{contrast.toFixed(2)}</span>
     118            0 :                         </label>
     119            0 :                         <div className={styles.control_row}>
     120            0 :                             <span className={styles.control_label}>Dots</span>
     121            0 :                             <SegmentedControl aria-label="Dots" size={SegmentedControlSize.Small} onChange={setDensity}>
     122            0 :                                 {CLOUD_DENSITIES.map((count, i) => (
     123            0 :                                     <SegmentedControl.Button key={count} selected={density === i}>{`${count / 1000}k`}</SegmentedControl.Button>
     124            0 :                                 ))}
     125            0 :                             </SegmentedControl>
     126            0 :                             <span className={styles.knob_value}>{stats == null ? '' : `${stats.fps} fps`}</span>
     127            0 :                         </div>
     128            0 :                         <label className={styles.knob}>
     129            0 :                             <span className={styles.control_label}>Particles</span>
     130            0 :                             <input id="landing-backdrop-particles" type="range" min={0} max={10000} step={100} value={particles}
     131            0 :                                 onChange={e => setParticles(Number(e.target.value))} />
     132            0 :                             <span className={styles.knob_value}>{particles}</span>
     133            0 :                         </label>
     134            0 :                         <label className={styles.knob}>
     135            0 :                             <span className={styles.control_label}>Ring ink</span>
     136            0 :                             <input id="landing-backdrop-ring-ink" type="range" min={0.2} max={3} step={0.05} value={ringInk}
     137            0 :                                 onChange={e => setRingInk(Number(e.target.value))} />
     138            0 :                             <span className={styles.knob_value}>{ringInk.toFixed(2)}</span>
     139            0 :                         </label>
     140            0 :                         <label className={styles.knob}>
     141            0 :                             <span className={styles.control_label}>Ring fps</span>
     142            0 :                             <input id="landing-backdrop-ring-fps" type="range" min={5} max={60} step={1} value={ringFps}
     143            0 :                                 onChange={e => setRingFps(Number(e.target.value))} />
     144            0 :                             <span className={styles.knob_value}>{ringFps}</span>
     145            0 :                         </label>
     146            0 :                         <label className={styles.knob}>
     147            0 :                             <span className={styles.control_label}>Fly</span>
     148            0 :                             <input id="landing-backdrop-fly" type="range" min={0.2} max={4} step={0.05} value={fly}
     149            0 :                                 onChange={e => setFly(Number(e.target.value))} />
     150            0 :                             <span className={styles.knob_value}>{fly.toFixed(2)}s</span>
     151            0 :                         </label>
     152            0 :                         <label className={styles.knob}>
     153            0 :                             <span className={styles.control_label}>Gap</span>
     154            0 :                             <input id="landing-backdrop-gap" type="range" min={1.05} max={3} step={0.01} value={gap}
     155            0 :                                 onChange={e => setGap(Number(e.target.value))} />
     156            0 :                             <span className={styles.knob_value}>{gap.toFixed(2)}</span>
     157            0 :                         </label>
     158            0 :                         <label className={styles.knob}>
     159            0 :                             <span className={styles.control_label}>Outer</span>
     160            0 :                             <input id="landing-backdrop-outer-wobble" type="range" min={0} max={0.3} step={0.005} value={outerWobble}
     161            0 :                                 onChange={e => setOuterWobble(Number(e.target.value))} />
     162            0 :                             <span className={styles.knob_value}>{outerWobble.toFixed(3)}</span>
     163            0 :                         </label>
     164            0 :                         <div className={styles.renderer} data-testid="backdrop-renderer">{stats?.renderer}</div>
     165            0 :                         <div className={styles.control_row}>
     166            0 :                             <span className={styles.control_label}>Eyes</span>
     167            0 :                             <SegmentedControl aria-label="Eyes" size={SegmentedControlSize.Small} onChange={index => setEyes(index === 0)}>
     168            0 :                                 <SegmentedControl.Button selected={eyes}>Shown</SegmentedControl.Button>
     169            0 :                                 <SegmentedControl.Button selected={!eyes}>Hidden</SegmentedControl.Button>
     170            0 :                             </SegmentedControl>
     171            0 :                         </div>
     172            0 :                         <div className={styles.control_row}>
     173            0 :                             <span className={styles.control_label}>Brand</span>
     174            0 :                             <SegmentedControl aria-label="Brand" size={SegmentedControlSize.Small} onChange={setBrand}>
     175            0 :                                 {BRANDS.map((entry, i) => (
     176            0 :                                     <SegmentedControl.Button key={entry.label} selected={brand === i}>{entry.label}</SegmentedControl.Button>
     177            0 :                                 ))}
     178            0 :                             </SegmentedControl>
     179            0 :                         </div>
     180            0 :                         <div className={styles.control_row}>
     181            0 :                             <span className={styles.control_label}>Motion</span>
     182            0 :                             <SegmentedControl aria-label="Motion" size={SegmentedControlSize.Small} onChange={index => setMotion(index === 0)}>
     183            0 :                                 <SegmentedControl.Button selected={motion}>On</SegmentedControl.Button>
     184            0 :                                 <SegmentedControl.Button selected={!motion}>Still</SegmentedControl.Button>
     185            0 :                             </SegmentedControl>
     186            0 :                         </div>
     187            0 :                         <Button size={ButtonSize.Small} variant={ButtonVariant.Default} onClick={() => setControlsShown(false)}>
     188              :                             Hide controls
     189            0 :                         </Button>
     190            0 :                     </div>
     191              :                 )
     192              :                 : (
     193            0 :                     <div className={styles.controls_collapsed}>
     194            0 :                         <Button size={ButtonSize.Small} variant={ButtonVariant.Default} onClick={() => setControlsShown(true)}>
     195              :                             Show controls
     196            0 :                         </Button>
     197            0 :                     </div>
     198              :                 )}
     199            0 :         </div>
     200              :     );
     201            0 : }
     202              : 
     203              : export default LandingBackdropPage;
        

Generated by: LCOV version 2.0-1