Skip to content
Draft

Hack 25 #13554

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion scripts/bundleSize/bundleSizeConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@
export const VARIANCE = 5;

export const MIN_SIZE = 916;
export const MAX_SIZE = 1267;
export const MAX_SIZE = 1286;
4 changes: 2 additions & 2 deletions src/app/components/Heading/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/** @jsx jsx */

import React, { FC, HTMLAttributes, ForwardedRef, forwardRef } from 'react';
import React, { HTMLAttributes, ForwardedRef, forwardRef } from 'react';
import { jsx } from '@emotion/react';

import { GelFontSize, FontVariant } from '../../models/types/theming';
Expand Down Expand Up @@ -30,7 +30,7 @@ const sizes: Sizes = {
h4: 'greatPrimer',
};

const Heading: FC<Props> = forwardRef(
const Heading = forwardRef(
(
{
children,
Expand Down
123 changes: 123 additions & 0 deletions src/app/components/Riddle/Components/Card/index.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import pixelsToRem from '#app/utilities/pixelsToRem';
import { css, Theme } from '@emotion/react';

// border: `${pixelsToRem(7)}rem solid transparent`,
// borderImage: `url(https://www.dropbox.com/scl/fi/5p4y98asfvgrxksxlgwqs/back23.png?rlkey=cu9mmwhnxq5vph4lvcacy2v15&st=z3pwywc4&raw=1) 33% round`,
// borderRadius: `${pixelsToRem(7)}rem`,

export default {
container: ({ mq }: Theme) =>
css({
display: 'flex',
flexWrap: 'wrap',
[mq.GROUP_2_MAX_WIDTH]: {
flexDirection: 'column-reverse',
},
}),
hidden: () =>
css({
display: 'none',
}),
playArea: ({ spacings, palette }: Theme) =>
css({
flex: 1,
color: palette.GHOST,
background: palette.POSTBOX,
padding: `${spacings.FULL}rem`,
}),
fixedHeight: () =>
css({
minHeight: '13.5rem',
}),
question: ({ palette }: Theme) =>
css({
background: palette.GHOST,
}),
heading: ({ palette, spacings }: Theme) =>
css({
color: palette.WHITE,
textAlign: 'end',
marginBottom: `${spacings.FULL}rem`,
}),
answerHeading: ({ palette, spacings }: Theme) =>
css({
margin: `${spacings.TRIPLE}rem 0`,
color: palette.WHITE,
}),
didYouKnow: ({ palette }: Theme) =>
css({
color: palette.WHITE,
}),
inputContainer: ({ spacings }: Theme) =>
css({
display: 'flex',
alignTracks: 'flex-end',
marginBottom: `${spacings.FULL}rem`,
}),
inputUnderline: () =>
css({
display: 'flex',
alignTracks: 'flex-end',
position: 'relative',
}),
underline: ({ palette }: Theme) =>
css({
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
height: '0.1rem',
backgroundColor: palette.GHOST,
}),
input: ({ fontSizes, fontVariants, palette }: Theme) =>
css({
...fontSizes.greatPrimer,
...fontVariants.serifLight,
color: palette.GHOST,
outline: 0,
border: 0,
background: palette.POSTBOX,
'&::placeholder': {
...fontVariants.serifLight,
fontStyle: 'oblique',
color: palette.GHOST,
},
'&:focus + div': {
height: '0.20rem',
backgroundColor: palette.GHOST,
},
}),
submitButton: ({ palette, spacings }: Theme) =>
css({
cursor: 'pointer',
padding: `${spacings.FULL}rem`,
marginInlineStart: `${spacings.FULL}rem`,
border: `${0.15}rem solid ${palette.GHOST}`,
background: palette.POSTBOX,
'& span': {
color: palette.GHOST,
},
'&:hover': {
background: palette.GHOST,
'& span': {
color: palette.BLACK,
},
},
}),
hintsArea: ({ spacings }: Theme) =>
css({
margin: `${spacings.TRIPLE}rem 0 ${2.5}rem`,
}),
detailsArea: ({ spacings, mq, palette }: Theme) =>
css({
padding: `${spacings.FULL}rem`,
minWidth: `${pixelsToRem(200)}rem`,
backgroundColor: `${palette.GREY_2}`,
display: 'grid',
gridTemplateColumns: '1fr',
[mq.GROUP_2_MAX_WIDTH]: {
minWidth: '100%',
gridTemplateColumns: '1fr 1fr 1fr',
},
}),
};
185 changes: 185 additions & 0 deletions src/app/components/Riddle/Components/Card/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
/** @jsxFrag React.Fragment */
/** @jsx jsx */
import { jsx } from '@emotion/react';
import { use, useLayoutEffect, useRef, useState } from 'react';
import Heading from '#app/components/Heading';
import Text from '../../../Text';
import style from './index.styles';
import Hint, { HintData } from '../HintButton';
import Detail from '../Detail';
import { GameState, RiddleContext } from '../../RiddleProvider';
import { LocalStorageContext } from '../../LocalStorageProvider';

export type GameData = {
expire: string;
question: string;
hint1: HintData;
hint2: HintData;
answer: string;
funFact: string;
};

const getTimeDiff = (a: Date, b: Date) => {
const timeDelta = a.getTime() - b.getTime();
const secondsDelta = timeDelta / 1000;
const minutesDelta = Math.floor(timeDelta / (1000 * 60));
const hoursToGo = Math.floor(timeDelta / (1000 * 60 * 60));
const minutesToGo = minutesDelta - hoursToGo * 60;
const secondsToGo = Math.floor(secondsDelta - minutesDelta * 60);

return [hoursToGo, minutesToGo, secondsToGo];
};

const capitalise = (str: string) => {
if (!str) return '';
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
};

export default () => {
const {
gameData,
devTime,
gameIndex,
submitAttempt,
gameState,
revealAnswer,
} = use(RiddleContext);
const { goes, coins } = use(LocalStorageContext);
const inputRef = useRef<HTMLInputElement>(null);
const { question, hint1, hint2, answer, expire, funFact } = gameData;
const failedMessageRef = useRef<HTMLHeadingElement>(null);
const winnerMessageRef = useRef<HTMLHeadingElement>(null);
const [isInvoked, setIsInvoked] = useState(false);
const expiryDate = new Date(expire);
const currTime = devTime;
const [hour, minute, second] = getTimeDiff(expiryDate, currTime);

let timeString = `-`;
if (hour > -1) {
timeString = `${hour < 10 ? '0' : ''}${hour}h ${minute < 10 ? '0' : ''}${minute}m ${second < 10 ? '0' : ''}${second}s`;
}

const goesString = `${goes}/5`;
const coinsString = `🪙 ${coins}`;

useLayoutEffect(() => {
if (isInvoked) {
if (gameState === GameState.WINNER) {
winnerMessageRef.current?.focus();
}
if (gameState === GameState.FAILED) {
failedMessageRef.current?.focus();
}
setIsInvoked(false);
}
}, [isInvoked, gameState]);

return (
<div css={style.container} key={gameIndex}>
<div css={style.playArea}>
<Heading
level={2}
size="brevier"
fontVariant="sansBold"
css={style.heading}
>
Riddle of the day
</Heading>
<Text css={style.question} size="greatPrimer" fontVariant="sansBold">
{question}
</Text>
{gameState === GameState.PLAY && (
<div css={style.fixedHeight}>
<div css={style.hintsArea}>
<Hint {...hint1} index={0} />
<Hint {...hint2} index={1} />
<Hint
title="Answer"
hintText={answer}
price={2500}
paidSymbol="Answer"
index={2}
onClickFn={() => {
revealAnswer(2500);
setIsInvoked(true);
}}
/>
</div>
<form css={style.inputContainer}>
<div css={style.inputUnderline}>
<input
type="text"
placeholder="Answer here..."
css={style.input}
ref={inputRef}
/>
<div css={style.underline} />
</div>
<button
type="submit"
css={style.submitButton}
onClick={event => {
event.preventDefault();
const userInput = inputRef.current?.value;
if (userInput) {
const isCorrect = submitAttempt(userInput);
if (isCorrect !== GameState.PLAY) {
setIsInvoked(true);
}
}
}}
>
<Text size="longPrimer" fontVariant="sansBold">
Submit
</Text>
</button>
</form>
</div>
)}
{gameState === GameState.WINNER && (
<div css={style.fixedHeight}>
<Heading
level={3}
css={style.answerHeading}
ref={winnerMessageRef}
tabIndex={-1}
>
{capitalise(answer)}
</Heading>
<Text as="p" css={style.didYouKnow}>
{funFact}
</Text>
</div>
)}
{gameState === GameState.FAILED && (
<div css={style.fixedHeight}>
<Heading
level={3}
css={style.answerHeading}
ref={failedMessageRef}
tabIndex={-1}
>
{`You've run out of attempts!`}
</Heading>
<Hint
title="Answer"
hintText={answer}
price={2500}
paidSymbol="Answer"
index={2}
onClickFn={() => {
revealAnswer(2500);
setIsInvoked(true);
}}
/>
</div>
)}
</div>
<div css={style.detailsArea}>
<Detail label="Expires in" content={timeString} as="time" />
<Detail label="Attempts" content={goesString} />
<Detail label="Credits" content={coinsString} />
</div>
</div>
);
};
28 changes: 28 additions & 0 deletions src/app/components/Riddle/Components/Card/usefulStuff.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

// const [initialTime, expiryTime] = useMemo(() => {
// const currDate = devTime;
// const expiryDate = new Date(expire);
// return [currDate, expiryDate];
// }, [devTime, expire]);

// const [initialHourDelta, initialMinuteDelta, initialSecondDelta] =
// getTimeDiff(expiryTime, initialTime);

// const [hour, setHour] = useState(initialHourDelta);
// const [minute, setMinute] = useState(initialMinuteDelta);
// const [second, setSecond] = useState(initialSecondDelta);

// useEffect(() => {
// const timer = setInterval(() => {
// const currTime = devTime;
// const [hoursToGo, minutesToGo, secondsToGo] = getTimeDiff(
// expiryTime,
// currTime,
// );
// setHour(hoursToGo);
// setMinute(minutesToGo);
// setSecond(secondsToGo);
// }, 500);

// return () => clearInterval(timer);
// }, [initialTime, expiryTime, devTime]);
34 changes: 34 additions & 0 deletions src/app/components/Riddle/Components/Detail/index.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { css, Theme } from '@emotion/react';

export default {
detailContainer: ({ mq }: Theme) =>
css({
alignContent: 'center',
textAlign: 'center',
[mq.GROUP_2_MAX_WIDTH]: {
alignContent: 'start',
},
}),
detailLabel: ({ palette, spacings, fontSizes, fontVariants, mq }: Theme) =>
css({
display: 'inline-block',
background: palette.BLACK,
color: palette.WHITE,
marginBottom: `${spacings.FULL}rem`,
...fontVariants.sansBold,
...fontSizes.greatPrimer,
[mq.GROUP_2_MAX_WIDTH]: {
...fontSizes.minion,
},
}),
detailContent: ({ spacings, fontSizes, fontVariants, mq }: Theme) =>
css({
display: 'inline-block',
marginBottom: `${spacings.FULL}rem`,
...fontVariants.serifLight,
...fontSizes.doublePica,
[mq.GROUP_2_MAX_WIDTH]: {
...fontSizes.brevier,
},
}),
};
Loading