From 8a5c972ad823928177d35fc2cb1945a121f0de1d Mon Sep 17 00:00:00 2001 From: Harri Lehtola Date: Sat, 28 Dec 2024 13:32:36 +0200 Subject: [PATCH] Extract header component --- app/src/components/app.ts | 51 +++--------------------------------- app/src/components/header.ts | 44 +++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 48 deletions(-) create mode 100644 app/src/components/header.ts diff --git a/app/src/components/app.ts b/app/src/components/app.ts index 160502a..3c0ceb6 100644 --- a/app/src/components/app.ts +++ b/app/src/components/app.ts @@ -1,4 +1,4 @@ -import { MainDOMSource, VNode, button, div, h1, header, main, span } from '@cycle/dom'; +import { MainDOMSource, VNode, div, main, span } from '@cycle/dom'; import { HTTPSource, Response } from '@cycle/http'; import classNames from 'classnames'; import xs, { Stream } from 'xstream'; @@ -11,14 +11,13 @@ import type { GameUpdateGoal, Goal, Scores, - ScoresDate, } from '../types'; import type { Animations } from '../utils/animations'; import { delayAtLeast } from '../utils/delay'; import { getGameAnimationIndexes } from '../utils/utils'; import Clock from './clock'; import Game from './game'; -import Icon from './icon'; +import Header from './header'; type Sources = { DOM: MainDOMSource; @@ -217,52 +216,12 @@ function view(state$: Stream): Stream { return state$.map( ({ scores, currentGoals, isPlaying, status, clockVtree, event, gameDisplays, gameCount }) => div([ - header( - '.header', - renderHeader({ - clockVtree, - event, - gameCount, - isPlaying, - date: scores.date, - }), - ), + Header({ clockVtree, event, date: scores.date, gameCount, isPlaying }), main(renderScores({ games: scores.games, currentGoals, status, gameDisplays })), ]), ); } -function renderHeader( - state: Pick & { date: Scores['date'] }, -): VNode { - const hasNotStarted = !state.event; - const isFinished = state.event?.type === 'end'; - const buttonText = state.isPlaying ? 'Pause' : 'Play'; - const buttonType = state.isPlaying ? 'pause' : 'play'; - const showIcon = state.gameCount > 0; - - const dynamicClassNames = { - [`button--${buttonType}`]: showIcon, - 'expand--last': state.gameCount > 0 && hasNotStarted, - 'button--hidden': isFinished, - }; - - return div('.header__container', [ - h1('.header__title', [span('.all-caps', 'NHL'), ' Recap']), - button( - '.button.play-pause-button', - { props: { ariaLive: 'polite' }, class: dynamicClassNames }, - [ - span('.visible-button', [ - showIcon ? Icon(buttonType) : null, - span('.visually-hidden', buttonText), - ]), - ], - ), - hasNotStarted && state.date ? renderDate(state.date) : state.clockVtree, - ]); -} - function renderScores( state: Pick & { games: Scores['games'] }, ): VNode { @@ -287,7 +246,3 @@ function renderScores( state.status.message, ]); } - -function renderDate(date: ScoresDate): VNode { - return span('.date.fade-in-slow', date.pretty); -} diff --git a/app/src/components/header.ts b/app/src/components/header.ts new file mode 100644 index 0000000..8637243 --- /dev/null +++ b/app/src/components/header.ts @@ -0,0 +1,44 @@ +import { button, div, h1, header, span, VNode } from '@cycle/dom'; + +import type { GameEvent, Scores } from '../types'; +import Icon from './icon'; + +type Props = { + clockVtree: VNode; + date: Scores['date']; + event: GameEvent | null; + gameCount: number; + isPlaying: boolean; +}; + +export default function Header({ clockVtree, date, event, gameCount, isPlaying }: Props) { + const hasNotStarted = !event; + const isFinished = event?.type === 'end'; + const buttonText = isPlaying ? 'Pause' : 'Play'; + const buttonType = isPlaying ? 'pause' : 'play'; + const showIcon = gameCount > 0; + + const dynamicClassNames = { + [`button--${buttonType}`]: showIcon, + 'expand--last': gameCount > 0 && hasNotStarted, + 'button--hidden': isFinished, + }; + + return header( + '.header', + div('.header__container', [ + h1('.header__title', [span('.all-caps', 'NHL'), ' Recap']), + button( + '.button.play-pause-button', + { props: { ariaLive: 'polite' }, class: dynamicClassNames }, + [ + span('.visible-button', [ + showIcon ? Icon(buttonType) : null, + span('.visually-hidden', buttonText), + ]), + ], + ), + hasNotStarted && date ? span('.date.fade-in-slow', date.pretty) : clockVtree, + ]), + ); +}