ready to play
This commit is contained in:
+23
@@ -0,0 +1,23 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"semi": true,
|
||||
"trailingComma": "none",
|
||||
"singleQuote": true,
|
||||
"printWidth": 80
|
||||
}
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
||||
@@ -1 +1,35 @@
|
||||
# react-quiz-app
|
||||
# React Shop
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
|
||||
---
|
||||
## Description
|
||||
---
|
||||
The React Quiz App does exactly what you would expect. Depending on the level, number, and category, you receive a list of questions from [Open Trivia Database](https://opentdb.com) to test yourself. The app is created with React and Typescript and the styles are made with styled-components.
|
||||
|
||||
|
||||
|
||||
## Installation
|
||||
---
|
||||
### Under the repository name, click on clone or download. In the terminal paste this command:
|
||||
|
||||
```git clone https://dadobos.github.io/react-quiz-app.git```
|
||||
|
||||
### Open the project in VSCode or move inside the folder with:
|
||||
|
||||
```cd react-quiz-app```
|
||||
|
||||
### Install the npm packages:
|
||||
|
||||
```npm install```
|
||||
|
||||
### Run the application with:
|
||||
|
||||
```npm start```
|
||||
|
||||
### In the browser open the "3000" port:
|
||||
|
||||
```http://localhost:3000/```
|
||||
|
||||
Generated
+29071
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "react-quiz-app",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"@types/jest": "^27.5.2",
|
||||
"@types/node": "^16.18.11",
|
||||
"@types/react": "^18.0.27",
|
||||
"@types/react-dom": "^18.0.10",
|
||||
"@types/styled-components": "^5.1.26",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"styled-components": "^5.3.6",
|
||||
"typescript": "^4.9.5",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#335c67" />
|
||||
<meta name="description" content="Quiz app" />
|
||||
<link
|
||||
rel="icon"
|
||||
href="https://res.cloudinary.com/dadobos/image/upload/v1642766520/web/favicon_ugvc88.ico"
|
||||
type="image/x-icon"
|
||||
/>
|
||||
<link
|
||||
rel="preload"
|
||||
as="style"
|
||||
crossorigin="anonymous"
|
||||
href="https://fonts.googleapis.com/css2?family=Nanum+Gothic+Coding:wght@400;700&display=swap"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
crossorigin="anonymous"
|
||||
href="https://fonts.googleapis.com/css2?family=Nanum+Gothic+Coding:wght@400;700&display=swap"
|
||||
/>
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React Quiz App</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"short_name": "Quiz App",
|
||||
"name": "React Quiz App",
|
||||
"icons": [],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#335c67",
|
||||
"background_color": "#335c67"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
import { shuffleArray } from './Utils';
|
||||
import { QuestionType } from './Types';
|
||||
|
||||
export const fetchQuizQuestions = async (
|
||||
amount: number,
|
||||
category: number,
|
||||
difficulty: string
|
||||
) => {
|
||||
try {
|
||||
let anyCategory: string = category === 1 ? '' : '&category=' + category;
|
||||
const endpoint = `https://opentdb.com/api.php?amount=${amount}${anyCategory}&difficulty=${difficulty}&type=multiple`;
|
||||
const data = await (await fetch(endpoint)).json();
|
||||
return data.results.map((question: QuestionType) => ({
|
||||
...question,
|
||||
answers: shuffleArray([
|
||||
...question.incorrect_answers,
|
||||
question.correct_answer
|
||||
])
|
||||
}));
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
|
||||
export const fetchCategories = async () => {
|
||||
try {
|
||||
const endpoint = `https://opentdb.com/api_category.php`;
|
||||
const response = await fetch(endpoint);
|
||||
const categories = await response.json();
|
||||
return categories.trivia_categories;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,122 @@
|
||||
import styled, { createGlobalStyle } from 'styled-components';
|
||||
|
||||
export const GlobalStyle = createGlobalStyle`
|
||||
// reset
|
||||
* {
|
||||
font-family: "Nanum Gothic Coding", monospace;
|
||||
box-sizing: border-box;
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
html {
|
||||
min-height:100vh;
|
||||
}
|
||||
|
||||
body {
|
||||
margin:0;
|
||||
padding:0;
|
||||
height: 100%;
|
||||
min-height:100vh;
|
||||
background-color:#22363c;
|
||||
color:#009688;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}`;
|
||||
|
||||
export const Wrapper = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0.5rem;
|
||||
color: white;
|
||||
width: 70rem;
|
||||
max-width: 100vw;
|
||||
|
||||
h1 {
|
||||
font-size: 3rem;
|
||||
text-align: center;
|
||||
margin-bottom: 2rem;
|
||||
@media (max-width: 768px) {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.question-card-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.details {
|
||||
margin: 2rem 0;
|
||||
font-size: 1.4rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
@media (max-width: 768px) {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.question {
|
||||
margin: 2rem 0;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.start,
|
||||
.next {
|
||||
cursor: pointer;
|
||||
padding: 1rem;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
background-color: #009688;
|
||||
font-size: 1.4rem;
|
||||
color: white;
|
||||
border: 1px transparent;
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
|
||||
type ButtonWrapperProps = {
|
||||
correct: boolean;
|
||||
userClicked: boolean;
|
||||
};
|
||||
|
||||
export const ButtonWrapper = styled.div<ButtonWrapperProps>`
|
||||
transition: all 0.3s ease;
|
||||
:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
button {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
font-size: 1.4rem;
|
||||
color: white;
|
||||
width: 100%;
|
||||
max-width: 100vw;
|
||||
margin: 5px 0;
|
||||
background: ${({ correct, userClicked }) =>
|
||||
correct ? '#84c318' : !correct && userClicked ? '#92374d' : '#22363c'};
|
||||
@media (max-width: 768px) {
|
||||
font-size: 1.2rem;
|
||||
margin: 8px 0;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const SelectWrapper = styled.select`
|
||||
width: 100%;
|
||||
max-width: 70rem;
|
||||
font-size: 1.6rem;
|
||||
background-color: #22363c;
|
||||
color: white;
|
||||
padding: 0.24rem;
|
||||
margin-top: 1rem;
|
||||
text-align: center;
|
||||
|
||||
:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
`;
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { fetchQuizQuestions, fetchCategories } from './API';
|
||||
import QuestionCard from './components/QuestionCard';
|
||||
import { GlobalStyle, Wrapper } from './App.style';
|
||||
import SelectDifficulty, { Difficulty } from './components/SelectDifficulty';
|
||||
import SelectQuestions, { TotalQuestions } from './components/SelectQuestions';
|
||||
import SelectCategory from './components/SelectCategory';
|
||||
import { Category, QuestionState, AnswerObject } from './Types';
|
||||
|
||||
const App = () => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [questions, setQuestions] = useState<QuestionState[]>([]);
|
||||
const [number, setNumber] = useState(0);
|
||||
const [userAnswers, setUserAnswers] = useState<AnswerObject[]>([]);
|
||||
const [score, setScore] = useState(0);
|
||||
const [gameOver, setGameOver] = useState(true);
|
||||
const [difficulty, setDifficulty] = useState<string>(Difficulty.EASY);
|
||||
const [totalQuestionNumber, setTotalQuestionNumber] = useState<number>(
|
||||
TotalQuestions.TEN
|
||||
);
|
||||
|
||||
const [category, setCategory] = useState<number>(1);
|
||||
const [categoryList, setCategoryList] = useState<Array<Category>>([]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchCategories().then((data) => setCategoryList(data));
|
||||
}, []);
|
||||
|
||||
const startTrivia = async () => {
|
||||
setLoading(true);
|
||||
setGameOver(false);
|
||||
|
||||
const newQuestions = await fetchQuizQuestions(
|
||||
totalQuestionNumber,
|
||||
category,
|
||||
difficulty
|
||||
);
|
||||
|
||||
setQuestions(newQuestions);
|
||||
setScore(0);
|
||||
setUserAnswers([]);
|
||||
setNumber(0);
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
const checkAnswer = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
if (!gameOver) {
|
||||
const answer = e.currentTarget.value;
|
||||
|
||||
const correct = questions[number].correct_answer === answer;
|
||||
|
||||
if (correct) {
|
||||
setScore((prev) => prev + 1);
|
||||
}
|
||||
|
||||
const answerObject = {
|
||||
question: questions[number].question,
|
||||
answer,
|
||||
correct,
|
||||
correctAnswer: questions[number].correct_answer
|
||||
};
|
||||
|
||||
setUserAnswers((prev) => [...prev, answerObject]);
|
||||
}
|
||||
};
|
||||
|
||||
const nextQuestion = () => {
|
||||
const nextNumber = number + 1;
|
||||
if (nextNumber === totalQuestionNumber) {
|
||||
setGameOver(true);
|
||||
} else {
|
||||
setNumber(nextNumber);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<GlobalStyle />
|
||||
<Wrapper className="App">
|
||||
<h1>Quiz</h1>
|
||||
|
||||
{gameOver || number + 1 === totalQuestionNumber ? (
|
||||
<div>
|
||||
<SelectDifficulty
|
||||
difficulty={difficulty}
|
||||
setDifficulty={setDifficulty}
|
||||
/>
|
||||
<SelectQuestions
|
||||
totalQuestionNumber={totalQuestionNumber}
|
||||
setTotalQuestionNumber={setTotalQuestionNumber}
|
||||
/>
|
||||
<SelectCategory
|
||||
category={category}
|
||||
categoryList={categoryList}
|
||||
setCategory={setCategory}
|
||||
/>
|
||||
<button className="start" onClick={startTrivia}>
|
||||
Start
|
||||
{number + 1 === totalQuestionNumber && ' again'}
|
||||
</button>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{loading ?? <p>Load Questions...</p>}
|
||||
|
||||
{!loading && !gameOver && (
|
||||
<QuestionCard
|
||||
difficulty={difficulty}
|
||||
score={score}
|
||||
questionNr={number + 1}
|
||||
totalQuestions={totalQuestionNumber}
|
||||
question={questions[number].question}
|
||||
answers={questions[number].answers}
|
||||
category={questions[number].category}
|
||||
userAnswer={userAnswers ? userAnswers[number] : undefined}
|
||||
callback={checkAnswer}
|
||||
/>
|
||||
)}
|
||||
|
||||
{!gameOver &&
|
||||
!loading &&
|
||||
userAnswers.length === number + 1 &&
|
||||
number + 1 !== totalQuestionNumber ? (
|
||||
<button className="next" onClick={nextQuestion}>
|
||||
Next Question
|
||||
</button>
|
||||
) : null}
|
||||
</Wrapper>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
@@ -0,0 +1,21 @@
|
||||
export type Category = {
|
||||
id: number;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type QuestionType = {
|
||||
category: string;
|
||||
correct_answer: string;
|
||||
incorrect_answers: string[];
|
||||
question: string;
|
||||
type: string;
|
||||
};
|
||||
|
||||
export type QuestionState = QuestionType & { answers: string[] };
|
||||
|
||||
export type AnswerObject = {
|
||||
question: string;
|
||||
answer: string;
|
||||
correct: boolean;
|
||||
correctAnswer: string;
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
export const shuffleArray = (array: any[]) =>
|
||||
[...array].sort(() => Math.random() - 0.5);
|
||||
|
||||
export const Capitalize = (text: string) => {
|
||||
return text
|
||||
.replace(/[_-]/g, ' ')
|
||||
.replace(
|
||||
/(^\w|\s\w)(\S*)/g,
|
||||
(_, m1, m2) => m1.toUpperCase() + m2.toLowerCase()
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,65 @@
|
||||
import React from 'react';
|
||||
import { ButtonWrapper } from '../App.style';
|
||||
import { AnswerObject } from '../Types';
|
||||
import { Capitalize } from '../Utils';
|
||||
|
||||
type Props = {
|
||||
answers: string[];
|
||||
callback: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
||||
difficulty: string;
|
||||
question: string;
|
||||
category: string;
|
||||
questionNr: number;
|
||||
score: number;
|
||||
totalQuestions: number;
|
||||
userAnswer: AnswerObject | undefined;
|
||||
};
|
||||
|
||||
const QuestionCard: React.FC<Props> = ({
|
||||
answers,
|
||||
callback,
|
||||
difficulty,
|
||||
question,
|
||||
category,
|
||||
questionNr,
|
||||
score,
|
||||
totalQuestions,
|
||||
userAnswer
|
||||
}) => (
|
||||
<div className="question-card-wrapper">
|
||||
<div className="details">
|
||||
<div>Difficulty: {Capitalize(difficulty)}</div>
|
||||
<div>{category}</div>
|
||||
</div>
|
||||
<div className="details">
|
||||
<div>
|
||||
Question: {questionNr}/{totalQuestions}
|
||||
</div>
|
||||
<div>Score: {score}</div>
|
||||
</div>
|
||||
|
||||
{!(questionNr === totalQuestions) && (
|
||||
<>
|
||||
<p
|
||||
className="question"
|
||||
dangerouslySetInnerHTML={{ __html: question }}
|
||||
/>
|
||||
<div>
|
||||
{answers.map((answer) => (
|
||||
<ButtonWrapper
|
||||
correct={userAnswer?.correctAnswer === answer}
|
||||
userClicked={userAnswer?.answer === answer}
|
||||
key={answer}
|
||||
>
|
||||
<button disabled={!!userAnswer} onClick={callback} value={answer}>
|
||||
<span dangerouslySetInnerHTML={{ __html: answer }} />
|
||||
</button>
|
||||
</ButtonWrapper>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
export default QuestionCard;
|
||||
@@ -0,0 +1,31 @@
|
||||
import React from 'react';
|
||||
|
||||
import { SelectWrapper } from '../App.style';
|
||||
import { Category } from '../Types';
|
||||
|
||||
type Props = {
|
||||
category: number;
|
||||
categoryList: Array<Category>;
|
||||
setCategory: (category: number) => void;
|
||||
};
|
||||
|
||||
const SelectCategory = ({ category, categoryList, setCategory }: Props) => {
|
||||
return (
|
||||
<SelectWrapper
|
||||
value={category}
|
||||
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
|
||||
e.preventDefault();
|
||||
setCategory(e.target.value as number);
|
||||
}}
|
||||
>
|
||||
<option value={1}>Any Category</option>
|
||||
{categoryList.map((cat) => (
|
||||
<option value={cat.id} key={cat.id}>
|
||||
{cat.name}
|
||||
</option>
|
||||
))}
|
||||
</SelectWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelectCategory;
|
||||
@@ -0,0 +1,32 @@
|
||||
import React from 'react';
|
||||
|
||||
import { SelectWrapper } from '../App.style';
|
||||
|
||||
export enum Difficulty {
|
||||
EASY = 'easy',
|
||||
MEDIUM = 'medium',
|
||||
HARD = 'hard'
|
||||
}
|
||||
|
||||
type Props = {
|
||||
difficulty: string;
|
||||
setDifficulty: (difficulty: string) => void;
|
||||
};
|
||||
|
||||
const SelectDifficulty = ({ difficulty, setDifficulty }: Props) => {
|
||||
return (
|
||||
<SelectWrapper
|
||||
value={difficulty}
|
||||
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
e.preventDefault();
|
||||
setDifficulty(e.target.value);
|
||||
}}
|
||||
>
|
||||
<option value={Difficulty.EASY}>Easy</option>
|
||||
<option value={Difficulty.MEDIUM}>Medium</option>
|
||||
<option value={Difficulty.HARD}>Hard</option>
|
||||
</SelectWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelectDifficulty;
|
||||
@@ -0,0 +1,42 @@
|
||||
import React from 'react';
|
||||
import { SelectWrapper } from '../App.style';
|
||||
|
||||
export enum TotalQuestions {
|
||||
FIVE = 5,
|
||||
TEN = 10,
|
||||
FIFTEEN = 15,
|
||||
TWENTY = 20,
|
||||
TWENTYFIVE = 25,
|
||||
FIFTY = 50
|
||||
}
|
||||
|
||||
type Props = {
|
||||
totalQuestionNumber: number;
|
||||
setTotalQuestionNumber: (totalQuestionNumber: number) => void;
|
||||
};
|
||||
|
||||
const SelectQuestions = ({
|
||||
totalQuestionNumber,
|
||||
setTotalQuestionNumber
|
||||
}: Props) => {
|
||||
return (
|
||||
<SelectWrapper
|
||||
value={totalQuestionNumber}
|
||||
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
|
||||
e.preventDefault();
|
||||
setTotalQuestionNumber(e.target.value as number);
|
||||
}}
|
||||
>
|
||||
<option value={TotalQuestions.FIVE}>{TotalQuestions.FIVE}</option>
|
||||
<option value={TotalQuestions.TEN}>{TotalQuestions.TEN}</option>
|
||||
<option value={TotalQuestions.FIFTEEN}>{TotalQuestions.FIFTEEN}</option>
|
||||
<option value={TotalQuestions.TWENTY}>{TotalQuestions.TWENTY}</option>
|
||||
<option value={TotalQuestions.TWENTYFIVE}>
|
||||
{TotalQuestions.TWENTYFIVE}
|
||||
</option>
|
||||
<option value={TotalQuestions.FIFTY}>{TotalQuestions.FIFTY}</option>
|
||||
</SelectWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelectQuestions;
|
||||
@@ -0,0 +1,13 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
|
||||
import App from './App';
|
||||
|
||||
const root = ReactDOM.createRoot(
|
||||
document.getElementById('root') as HTMLElement
|
||||
);
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
/// <reference types="react-scripts" />
|
||||
@@ -0,0 +1,5 @@
|
||||
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom';
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2016",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user