Skip to content

Commit

Permalink
Merge pull request #8094 from ethereum/learnQuizzes
Browse files Browse the repository at this point in the history
Learn quizzes
  • Loading branch information
wackerow authored Oct 27, 2022
2 parents 287aa2f + c094343 commit d349c54
Show file tree
Hide file tree
Showing 30 changed files with 1,844 additions and 11 deletions.
5 changes: 5 additions & 0 deletions src/@chakra-ui/gatsby-plugin/foundations/colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,15 @@ const colors = {
800: "#451900",
},
red: {
100: "#F7C8C8",
500: "#b80000",
900: "#1B0C0C",
},
green: {
100: "#C8F7D8",
400: "#48BB78",
500: "#109e62",
900: "#0A160E",
},
yellow: {
200: "#fff8df",
Expand Down
1 change: 1 addition & 0 deletions src/@chakra-ui/gatsby-plugin/foundations/shadows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const shadows = {
outline: "0 0 0 4px var(--eth-colors-primaryHover)",
table:
"0 14px 66px rgba(0,0,0,.07), 0 10px 17px rgba(0,0,0,.03), 0 4px 7px rgba(0,0,0,.05)",
drop: "0 4px 17px 0 var(--eth-colors-blackAlpha-200)",
tableBox: {
light:
"0 14px 66px rgba(0,0,0,.07), 0 10px 17px rgba(0,0,0,.03), 0 4px 7px rgba(0,0,0,.05)",
Expand Down
7 changes: 6 additions & 1 deletion src/@chakra-ui/gatsby-plugin/semanticTokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,17 @@ const semanticTokens = {
primaryLight: { _light: "blue.100", _dark: "orange.100" },
primaryDark: { _light: "blue.700", _dark: "orange.800" },
primaryHover: { _light: "blue.300", _dark: "orange.300" },
primaryPressed: { _light: "blue.300", _dark: "orange.800" },
body: { _light: "gray.700", _dark: "gray.100" },
bodyInverted: { _light: "gray.100", _dark: "gray.700" },
bodyLight: { _light: "gray.500", _dark: "gray.100" },
disabled: { _light: "gray.400", _dark: "gray.500" },
background: { _light: "white", _dark: "gray.700" },
success: "green.500",
neutral: { _light: "white", _dark: "gray.900" },
success: { _light: "green.500", _dark: "green.400" },
successNeutral: { _light: "green.100", _dark: "green.900" },
error: "red.500",
errorNeutral: { _light: "red.100", _dark: "red.900" },
attention: "yellow.200",
},
}
Expand Down
3 changes: 3 additions & 0 deletions src/assets/quiz/correct.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/quiz/incorrect.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions src/assets/quiz/star-confetti.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/assets/quiz/trophy.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/components/CopyToClipboard.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState, useEffect, useRef } from "react"
import ClipboardJS from "clipboard"
import { Box } from '@chakra-ui/react'
import { Box } from "@chakra-ui/react"

export interface IProps {
text: string
Expand Down
7 changes: 1 addition & 6 deletions src/components/EventCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,7 @@ const EventCard: React.FC<IProps> = ({
</Text>
<Emoji text=":round_pushpin:" fontSize="md" marginLeft={2} />
</Text>
<Heading
as="h3"
marginTop={0}
fontWeight="semibold"
lineHeight={1.4}
>
<Heading as="h3" marginTop={0} fontWeight="semibold" lineHeight={1.4}>
{title}
</Heading>
<Text opacity={0.8}>{description}</Text>
Expand Down
153 changes: 153 additions & 0 deletions src/components/Quiz/QuizRadioGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
// Import libraries
import React, { useMemo } from "react"
import {
Box,
chakra,
Circle,
Flex,
RadioProps,
Text,
useRadio,
useRadioGroup,
} from "@chakra-ui/react"

// Import types
import { Question } from "../../types"

// Interfaces
export interface CustomRadioProps extends RadioProps {
index: number
label: string
}
export interface IProps {
questionData: Question
showAnswer: boolean
handleSelection: (answerId: string) => void
selectedAnswer: string | null
}

// Component
const QuizRadioGroup: React.FC<IProps> = ({
questionData,
showAnswer,
handleSelection,
selectedAnswer,
}) => {
const { getRadioProps, getRootProps } = useRadioGroup({
onChange: handleSelection,
})
const { prompt, answers, correctAnswerId } = questionData

// Memoized values
const explanation = useMemo<string>(() => {
if (!selectedAnswer) return ""
return answers.filter(({ id }) => id === selectedAnswer)[0].explanation
}, [selectedAnswer])

const isSelectedCorrect = useMemo<boolean>(
() => correctAnswerId === selectedAnswer,
[selectedAnswer]
)

// Custom radio button component
const CustomRadio: React.FC<CustomRadioProps> = ({
index,
label,
...radioProps
}) => {
const { state, getInputProps, getCheckboxProps, htmlProps } =
useRadio(radioProps)

// Memoized values
const buttonBg = useMemo<string>(() => {
if (!state.isChecked) return "bodyInverted"
if (!showAnswer) return "primary"
if (!isSelectedCorrect) return "error"
return "success"
}, [state.isChecked, showAnswer, isSelectedCorrect])

// Render CustomRadio component
return (
<chakra.label {...htmlProps} cursor="pointer" data-group w="100%">
<input {...getInputProps({})} hidden />
<Flex
{...getCheckboxProps()}
w="100%"
p={2}
alignItems="center"
bg={buttonBg}
color={state.isChecked ? "white" : "text"}
borderRadius="base"
_hover={{
boxShadow: showAnswer ? "none" : "primary",
outline: showAnswer
? "none"
: "1px solid var(--eth-colors-primary)",
cursor: showAnswer ? "default" : "pointer",
}}
>
<Circle
size="25px"
bg={
showAnswer
? "white"
: state.isChecked
? "primaryPressed"
: "disabled"
}
_groupHover={{
bg: showAnswer ? "white" : "primaryPressed",
}}
me={2}
>
<Text
m="0"
fontWeight="700"
fontSize="lg"
color={
!showAnswer ? "white" : isSelectedCorrect ? "success" : "error"
}
>
{String.fromCharCode(97 + index).toUpperCase()}
</Text>
</Circle>
{label}
</Flex>
</chakra.label>
)
}

// Render QuizRadioGroup
return (
<Flex {...getRootProps()} direction="column" w="100%">
<Text fontWeight="700" fontSize="2xl" mb={6}>
{prompt}
</Text>
<Flex direction="column" gap={4}>
{answers.map(({ id, label }, index) => {
const display =
!showAnswer || id === selectedAnswer ? "inline-flex" : "none"
return (
<CustomRadio
key={id}
display={display}
index={index}
label={label}
{...getRadioProps({ value: id })}
/>
)
})}
</Flex>
{showAnswer && (
<Box mt={5}>
<Text fontWeight="bold" mt={0} mb={2}>
Explanation
</Text>
<Text m={0}>{explanation}</Text>
</Box>
)}
</Flex>
)
}

export default QuizRadioGroup
75 changes: 75 additions & 0 deletions src/components/Quiz/QuizSummary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Import libraries
import React, { useMemo } from "react"
import { Box, Flex, Text, useMediaQuery } from "@chakra-ui/react"
import { useIntl } from "react-intl"

// Import utilities
import { numberToPercent } from "../../utils/numberToPercent"

// Interfaces
export interface IProps {
correctCount: number
isPassingScore: boolean
questionCount: number
ratioCorrect: number
}

// Component
const QuizSummary: React.FC<IProps> = ({
correctCount,
isPassingScore,
questionCount,
ratioCorrect,
}) => {
const { locale } = useIntl()
const [largerThanMobile] = useMediaQuery("(min-width: 30em)")

const valueStyles = { fontWeight: "700", mb: 2 }
const labelStyles = { fontSize: "sm", m: 0, color: "disabled" }

// Render QuizSummary component
return (
<Box w="full" fontSize={["xl", "2xl"]}>
<Text fontWeight="700" textAlign="center">
{isPassingScore ? "You passed the quiz!" : "Your results"}
</Text>
<Flex
p={4}
justify="center"
boxShadow="drop"
bg="background"
mx="auto"
w="fit-content"
sx={{
"div:not(:last-of-type)": {
borderEnd: "1px",
borderColor: "disabled",
},
div: {
p: 4,
flexDirection: "column",
alignItems: "center",
},
}}
overflowX="hidden"
>
<Flex>
<Text {...valueStyles}>{numberToPercent(ratioCorrect, locale)}</Text>
<Text {...labelStyles}>Score</Text>
</Flex>
<Flex>
<Text {...valueStyles}>+{correctCount}</Text>
<Text {...labelStyles}>Correct</Text>
</Flex>
{largerThanMobile && (
<Flex>
<Text {...valueStyles}>{questionCount}</Text>
<Text {...labelStyles}>Total</Text>
</Flex>
)}
</Flex>
</Box>
)
}

export default QuizSummary
Loading

0 comments on commit d349c54

Please sign in to comment.