├── 10_todo_redux
└── todoredux
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ └── vite.svg
│ ├── src
│ ├── App.css
│ ├── App.jsx
│ ├── assets
│ │ └── react.svg
│ ├── components
│ │ ├── AddTodo.jsx
│ │ └── TodoList.jsx
│ ├── index.css
│ ├── main.jsx
│ ├── slices
│ │ └── todoSlice.js
│ └── store.js
│ └── vite.config.js
├── 11_gerador_pdf
└── geradorpdf
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ └── vite.svg
│ ├── src
│ ├── App.css
│ ├── App.jsx
│ ├── assets
│ │ └── react.svg
│ ├── components
│ │ ├── GeneratePDF.jsx
│ │ ├── ImageUpload.jsx
│ │ └── TextStyleConfig.jsx
│ ├── index.css
│ └── main.jsx
│ └── vite.config.js
├── 12_calculadora_imposto
└── calcimposto
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ └── vite.svg
│ ├── src
│ ├── App.css
│ ├── App.jsx
│ ├── assets
│ │ └── react.svg
│ ├── components
│ │ ├── TaxForm.jsx
│ │ └── TaxReport.jsx
│ ├── index.css
│ └── main.jsx
│ └── vite.config.js
├── 13_pomodoro
└── pomodoro
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ └── vite.svg
│ ├── src
│ ├── App.css
│ ├── App.jsx
│ ├── assets
│ │ └── react.svg
│ ├── components
│ │ └── PomodoroTimer.jsx
│ ├── index.css
│ └── main.jsx
│ └── vite.config.js
├── 14_carousel
└── carousel
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ └── vite.svg
│ ├── src
│ ├── App.css
│ ├── App.jsx
│ ├── assets
│ │ └── react.svg
│ ├── components
│ │ ├── Carousel.jsx
│ │ ├── Indicators.jsx
│ │ └── Slide.jsx
│ ├── index.css
│ └── main.jsx
│ └── vite.config.js
├── 15_tabela_ordenavel
└── tabelaordenavel
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ └── vite.svg
│ ├── src
│ ├── App.css
│ ├── App.jsx
│ ├── assets
│ │ └── react.svg
│ ├── components
│ │ ├── SearchBar.jsx
│ │ ├── TableHeader.jsx
│ │ └── TableRow.jsx
│ ├── index.css
│ └── main.jsx
│ └── vite.config.js
├── 16_infinite_scroll
└── infinitescroll
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ └── vite.svg
│ ├── src
│ ├── App.css
│ ├── App.jsx
│ ├── assets
│ │ └── react.svg
│ ├── components
│ │ └── InfiniteScroll.jsx
│ ├── index.css
│ └── main.jsx
│ └── vite.config.js
├── 18_blog_com_axios
├── .gitignore
├── index.html
├── package-lock.json
├── package.json
├── public
│ └── vite.svg
├── src
│ ├── App.css
│ ├── App.jsx
│ ├── assets
│ │ └── react.svg
│ ├── axios
│ │ └── config.js
│ ├── components
│ │ ├── Navbar.css
│ │ └── Navbar.jsx
│ ├── index.css
│ ├── main.jsx
│ └── routes
│ │ ├── Admin.css
│ │ ├── Admin.jsx
│ │ ├── EditPost.jsx
│ │ ├── Home.css
│ │ ├── Home.jsx
│ │ ├── NewPost.css
│ │ ├── NewPost.jsx
│ │ ├── Post.css
│ │ └── Post.jsx
└── vite.config.js
├── 19_multistep_form
├── .gitignore
├── index.html
├── package-lock.json
├── package.json
├── public
│ └── vite.svg
├── src
│ ├── App.css
│ ├── App.jsx
│ ├── components
│ │ ├── ReviewForm.css
│ │ ├── ReviewForm.jsx
│ │ ├── Steps.css
│ │ ├── Steps.jsx
│ │ ├── Thanks.css
│ │ ├── Thanks.jsx
│ │ └── UserForm.jsx
│ ├── hooks
│ │ └── useForm.jsx
│ ├── index.css
│ └── main.jsx
└── vite.config.js
├── 1_calculadora
└── calculadora
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ └── vite.svg
│ ├── src
│ ├── App.css
│ ├── App.jsx
│ ├── assets
│ │ └── react.svg
│ ├── components
│ │ ├── Calculator.css
│ │ └── Calculator.jsx
│ ├── index.css
│ └── main.jsx
│ └── vite.config.js
├── 20_github_api
├── .gitignore
├── index.html
├── package-lock.json
├── package.json
├── public
│ └── vite.svg
├── src
│ ├── App.module.css
│ ├── App.tsx
│ ├── components
│ │ ├── BackBtn.module.css
│ │ ├── BackBtn.tsx
│ │ ├── Error.tsx
│ │ ├── Loader.module.css
│ │ ├── Loader.tsx
│ │ ├── Repo.module.css
│ │ ├── Repo.tsx
│ │ ├── Search.module.css
│ │ ├── Search.tsx
│ │ ├── User.module.css
│ │ └── User.tsx
│ ├── index.css
│ ├── main.tsx
│ ├── routes
│ │ ├── Home.tsx
│ │ ├── Repos.module.css
│ │ └── Repos.tsx
│ ├── types
│ │ ├── repo.ts
│ │ └── user.ts
│ └── vite-env.d.ts
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
├── 22_form_com_react_hook_e_ts
├── .eslintrc.cjs
├── .gitignore
├── README.md
├── index.html
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
│ └── vite.svg
├── src
│ ├── App.tsx
│ ├── assets
│ │ └── react.svg
│ ├── components
│ │ └── Form
│ │ │ └── Form.tsx
│ ├── hooks
│ │ └── useForms.tsx
│ ├── index.css
│ ├── main.tsx
│ ├── schemas
│ │ └── formSchema.ts
│ └── vite-env.d.ts
├── tailwind.config.js
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
├── 25_newsletter_form
├── .eslintrc.cjs
├── .gitignore
├── README.md
├── index.html
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
│ └── vite.svg
├── src
│ ├── App.tsx
│ ├── assets
│ │ └── react.svg
│ ├── components
│ │ └── Form.tsx
│ ├── index.css
│ ├── main.tsx
│ ├── types
│ │ └── User.ts
│ ├── utils
│ │ └── validate.ts
│ └── vite-env.d.ts
├── tailwind.config.js
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
├── 2_cronometro
└── cronometro
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ └── vite.svg
│ ├── src
│ ├── App.css
│ ├── App.jsx
│ ├── assets
│ │ └── react.svg
│ ├── components
│ │ ├── LapList.jsx
│ │ ├── Timer.css
│ │ ├── Timer.jsx
│ │ ├── TimerControls.jsx
│ │ └── TimerDisplay.jsx
│ ├── index.css
│ └── main.jsx
│ └── vite.config.js
├── 3_conversor_moeda
└── conversor_moeda
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ └── vite.svg
│ ├── src
│ ├── App.css
│ ├── App.jsx
│ ├── assets
│ │ └── react.svg
│ ├── components
│ │ ├── CurrencyConverter.css
│ │ └── CurrencyConverter.jsx
│ ├── index.css
│ └── main.jsx
│ └── vite.config.js
├── 4_clima
└── clima
│ ├── .env
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ └── vite.svg
│ ├── src
│ ├── App.jsx
│ ├── AppStyles.js
│ ├── assets
│ │ └── react.svg
│ ├── components
│ │ ├── Busca.jsx
│ │ ├── BuscaStyles.js
│ │ ├── ClimaAtual.jsx
│ │ ├── ClimaAtualStyles.js
│ │ ├── Previsao.jsx
│ │ └── PrevisaoStyles.js
│ ├── index.css
│ └── main.jsx
│ └── vite.config.js
├── 5_citacoes
└── citacoes
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ └── vite.svg
│ ├── src
│ ├── App.css
│ ├── App.jsx
│ ├── assets
│ │ └── react.svg
│ ├── components
│ │ └── Citacao.jsx
│ ├── data.js
│ ├── index.css
│ └── main.jsx
│ └── vite.config.js
├── 6_album
└── album
│ ├── .env
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ └── vite.svg
│ ├── src
│ ├── App.css
│ ├── App.jsx
│ ├── assets
│ │ └── react.svg
│ ├── components
│ │ ├── Foto.jsx
│ │ ├── FotoAmpliada.jsx
│ │ ├── FotoList.jsx
│ │ └── SearchBar.jsx
│ ├── index.css
│ └── main.jsx
│ └── vite.config.js
├── 7_markdown_viewer
└── markdownviewer
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ └── vite.svg
│ ├── src
│ ├── App.css
│ ├── App.jsx
│ ├── assets
│ │ └── react.svg
│ ├── components
│ │ └── Toolbar.jsx
│ ├── index.css
│ └── main.jsx
│ └── vite.config.js
├── 8_relogio_mundial
└── relogiomundial
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ └── vite.svg
│ ├── src
│ ├── App.css
│ ├── App.jsx
│ ├── assets
│ │ └── react.svg
│ ├── components
│ │ └── TimeZoneClock.jsx
│ ├── index.css
│ └── main.jsx
│ └── vite.config.js
└── 9_jogo_da_velha_com_ia
└── jogodavelhaia
├── .eslintrc.cjs
├── .gitignore
├── README.md
├── index.html
├── package-lock.json
├── package.json
├── public
└── vite.svg
├── src
├── App.css
├── App.jsx
├── assets
│ └── react.svg
├── components
│ ├── Board.jsx
│ └── Square.jsx
├── index.css
└── main.jsx
└── vite.config.js
/10_todo_redux/todoredux/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: { browser: true, es2020: true },
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:react/recommended',
7 | 'plugin:react/jsx-runtime',
8 | 'plugin:react-hooks/recommended',
9 | ],
10 | ignorePatterns: ['dist', '.eslintrc.cjs'],
11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
12 | settings: { react: { version: '18.2' } },
13 | plugins: ['react-refresh'],
14 | rules: {
15 | 'react-refresh/only-export-components': [
16 | 'warn',
17 | { allowConstantExport: true },
18 | ],
19 | },
20 | }
21 |
--------------------------------------------------------------------------------
/10_todo_redux/todoredux/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/10_todo_redux/todoredux/README.md:
--------------------------------------------------------------------------------
1 | # React + Vite
2 |
3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4 |
5 | Currently, two official plugins are available:
6 |
7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9 |
--------------------------------------------------------------------------------
/10_todo_redux/todoredux/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/10_todo_redux/todoredux/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "todoredux",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "@reduxjs/toolkit": "^1.9.5",
14 | "react": "^18.2.0",
15 | "react-dom": "^18.2.0",
16 | "react-redux": "^8.1.2",
17 | "redux": "^4.2.1"
18 | },
19 | "devDependencies": {
20 | "@types/react": "^18.2.15",
21 | "@types/react-dom": "^18.2.7",
22 | "@vitejs/plugin-react": "^4.0.3",
23 | "eslint": "^8.45.0",
24 | "eslint-plugin-react": "^7.32.2",
25 | "eslint-plugin-react-hooks": "^4.6.0",
26 | "eslint-plugin-react-refresh": "^0.4.3",
27 | "vite": "^4.4.5"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/10_todo_redux/todoredux/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/10_todo_redux/todoredux/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | max-width: 1280px;
3 | margin: 0 auto;
4 | padding: 2rem;
5 | text-align: center;
6 | }
7 |
8 | .logo {
9 | height: 6em;
10 | padding: 1.5em;
11 | will-change: filter;
12 | transition: filter 300ms;
13 | }
14 | .logo:hover {
15 | filter: drop-shadow(0 0 2em #646cffaa);
16 | }
17 | .logo.react:hover {
18 | filter: drop-shadow(0 0 2em #61dafbaa);
19 | }
20 |
21 | @keyframes logo-spin {
22 | from {
23 | transform: rotate(0deg);
24 | }
25 | to {
26 | transform: rotate(360deg);
27 | }
28 | }
29 |
30 | @media (prefers-reduced-motion: no-preference) {
31 | a:nth-of-type(2) .logo {
32 | animation: logo-spin infinite 20s linear;
33 | }
34 | }
35 |
36 | .card {
37 | padding: 2em;
38 | }
39 |
40 | .read-the-docs {
41 | color: #888;
42 | }
43 |
--------------------------------------------------------------------------------
/10_todo_redux/todoredux/src/App.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import TodoList from "./components/TodoList";
3 | import AddTodo from "./components/AddTodo";
4 |
5 | const App = () => {
6 | return (
7 |
8 |
Lista de Tarefas com Redux
9 |
10 |
11 |
12 | );
13 | };
14 |
15 | export default App;
16 |
--------------------------------------------------------------------------------
/10_todo_redux/todoredux/src/components/AddTodo.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { useDispatch } from "react-redux";
3 | import { addTodo } from "../slices/todoSlice";
4 |
5 | function AddTodo() {
6 | const [input, setInput] = useState("");
7 | const dispatch = useDispatch();
8 |
9 | const handleSubmit = (e) => {
10 | e.preventDefault();
11 | if (input.trim() === "") return;
12 | dispatch(addTodo(input));
13 | setInput("");
14 | };
15 |
16 | return (
17 |
26 | );
27 | }
28 |
29 | export default AddTodo;
30 |
--------------------------------------------------------------------------------
/10_todo_redux/todoredux/src/components/TodoList.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useSelector, useDispatch } from "react-redux";
3 | import { toggleTodo, removeTodo, filterTodos } from "../slices/todoSlice";
4 |
5 | function TodoList() {
6 | const { list, filter } = useSelector((state) => state.todos);
7 | const dispatch = useDispatch();
8 |
9 | const filteredList = list.filter((todo) => {
10 | if (filter === "all") return true;
11 | if (filter === "completed") return todo.completed;
12 | if (filter === "incomplete") return !todo.completed;
13 | return true;
14 | });
15 |
16 | return (
17 |
18 |
19 |
22 |
25 |
26 | {filteredList.map((todo) => (
27 | -
28 | dispatch(toggleTodo(todo.id))}
30 | style={{
31 | textDecoration: todo.completed ? "line-through" : "none",
32 | }}
33 | >
34 | {todo.text}
35 |
36 |
39 |
40 | ))}
41 |
42 |
43 | );
44 | }
45 |
46 | export default TodoList;
47 |
--------------------------------------------------------------------------------
/10_todo_redux/todoredux/src/index.css:
--------------------------------------------------------------------------------
1 | body,
2 | h1,
3 | ul,
4 | li {
5 | margin: 0;
6 | padding: 0;
7 | }
8 |
9 | body {
10 | background-color: #f4f4f4;
11 | font-family: Helvetica;
12 | }
13 |
14 | h1 {
15 | text-align: center;
16 | margin-bottom: 20px;
17 | }
18 |
19 | .container {
20 | max-width: 500px;
21 | margin: 50px auto;
22 | background-color: #fff;
23 | padding: 20px;
24 | border-radius: 5px;
25 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
26 | }
27 |
28 | ul {
29 | list-style: none;
30 | }
31 |
32 | li {
33 | background: #eee;
34 | margin: 8px 0;
35 | padding: 12px;
36 | text-align: left;
37 | border-radius: 4px;
38 | display: flex;
39 | justify-content: space-between;
40 | align-items: center;
41 | }
42 |
43 | form {
44 | margin-bottom: 20px;
45 | }
46 |
47 | input,
48 | button {
49 | padding: 10px 20px;
50 | margin-right: 10px;
51 | }
52 |
53 | button {
54 | border: none;
55 | border-radius: 4px;
56 | cursor: pointer;
57 | }
58 |
59 | button:hover {
60 | background-color: #ccc;
61 | }
62 |
63 | li span {
64 | cursor: pointer;
65 | }
66 |
67 | li span.line-through {
68 | text-decoration: line-through;
69 | color: #888;
70 | }
71 |
--------------------------------------------------------------------------------
/10_todo_redux/todoredux/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 | import "./index.css";
5 |
6 | import { Provider } from "react-redux";
7 | import { store } from "./store";
8 |
9 | ReactDOM.createRoot(document.getElementById("root")).render(
10 |
11 |
12 |
13 |
14 |
15 | );
16 |
--------------------------------------------------------------------------------
/10_todo_redux/todoredux/src/slices/todoSlice.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from "@reduxjs/toolkit";
2 |
3 | export const todoSlice = createSlice({
4 | name: "todos",
5 | initialState: {
6 | list: [],
7 | filter: "all", // 'all', 'completed', 'incomplete'
8 | },
9 | reducers: {
10 | addTodo: (state, action) => {
11 | state.list.push({
12 | id: new Date().toISOString(),
13 | text: action.payload,
14 | completed: false,
15 | });
16 | },
17 | toggleTodo: (state, action) => {
18 | const todo = state.list.find((todo) => todo.id === action.payload);
19 | if (todo) {
20 | todo.completed = !todo.completed;
21 | }
22 | },
23 | removeTodo: (state, action) => {
24 | state.list = state.list.filter((todo) => todo.id !== action.payload);
25 | },
26 | filterTodos: (state, action) => {
27 | state.filter = action.payload;
28 | },
29 | },
30 | });
31 |
32 | export const { addTodo, toggleTodo, removeTodo, filterTodos } =
33 | todoSlice.actions;
34 |
35 | export default todoSlice.reducer;
36 |
--------------------------------------------------------------------------------
/10_todo_redux/todoredux/src/store.js:
--------------------------------------------------------------------------------
1 | import { configureStore } from "@reduxjs/toolkit";
2 | import todoReducer from "./slices/todoSlice";
3 |
4 | export const store = configureStore({
5 | reducer: {
6 | todos: todoReducer,
7 | },
8 | });
9 |
--------------------------------------------------------------------------------
/10_todo_redux/todoredux/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/11_gerador_pdf/geradorpdf/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: { browser: true, es2020: true },
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:react/recommended',
7 | 'plugin:react/jsx-runtime',
8 | 'plugin:react-hooks/recommended',
9 | ],
10 | ignorePatterns: ['dist', '.eslintrc.cjs'],
11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
12 | settings: { react: { version: '18.2' } },
13 | plugins: ['react-refresh'],
14 | rules: {
15 | 'react-refresh/only-export-components': [
16 | 'warn',
17 | { allowConstantExport: true },
18 | ],
19 | },
20 | }
21 |
--------------------------------------------------------------------------------
/11_gerador_pdf/geradorpdf/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/11_gerador_pdf/geradorpdf/README.md:
--------------------------------------------------------------------------------
1 | # React + Vite
2 |
3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4 |
5 | Currently, two official plugins are available:
6 |
7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9 |
--------------------------------------------------------------------------------
/11_gerador_pdf/geradorpdf/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/11_gerador_pdf/geradorpdf/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "geradorpdf",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "pdfmake": "^0.2.7",
14 | "react": "^18.2.0",
15 | "react-dom": "^18.2.0"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^18.2.15",
19 | "@types/react-dom": "^18.2.7",
20 | "@vitejs/plugin-react": "^4.0.3",
21 | "eslint": "^8.45.0",
22 | "eslint-plugin-react": "^7.32.2",
23 | "eslint-plugin-react-hooks": "^4.6.0",
24 | "eslint-plugin-react-refresh": "^0.4.3",
25 | "vite": "^4.4.5"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/11_gerador_pdf/geradorpdf/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/11_gerador_pdf/geradorpdf/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | max-width: 1280px;
3 | margin: 0 auto;
4 | padding: 2rem;
5 | text-align: center;
6 | }
7 |
8 | .logo {
9 | height: 6em;
10 | padding: 1.5em;
11 | will-change: filter;
12 | transition: filter 300ms;
13 | }
14 | .logo:hover {
15 | filter: drop-shadow(0 0 2em #646cffaa);
16 | }
17 | .logo.react:hover {
18 | filter: drop-shadow(0 0 2em #61dafbaa);
19 | }
20 |
21 | @keyframes logo-spin {
22 | from {
23 | transform: rotate(0deg);
24 | }
25 | to {
26 | transform: rotate(360deg);
27 | }
28 | }
29 |
30 | @media (prefers-reduced-motion: no-preference) {
31 | a:nth-of-type(2) .logo {
32 | animation: logo-spin infinite 20s linear;
33 | }
34 | }
35 |
36 | .card {
37 | padding: 2em;
38 | }
39 |
40 | .read-the-docs {
41 | color: #888;
42 | }
43 |
--------------------------------------------------------------------------------
/11_gerador_pdf/geradorpdf/src/App.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import GeneratePDF from "./components/GeneratePDF";
3 |
4 | function App() {
5 | return (
6 |
7 |
Gerador de PDF Dinâmico
8 |
9 |
10 | );
11 | }
12 |
13 | export default App;
14 |
--------------------------------------------------------------------------------
/11_gerador_pdf/geradorpdf/src/components/ImageUpload.jsx:
--------------------------------------------------------------------------------
1 | const ImageUpload = ({ setImage }) => {
2 | const handleImageUpload = (e) => {
3 | const file = e.target.files[0];
4 | const reader = new FileReader();
5 |
6 | reader.readAsDataURL(file);
7 | reader.onloadend = () => {
8 | setImage(reader.result);
9 | };
10 | };
11 |
12 | return (
13 |
14 |
23 |
24 | );
25 | };
26 |
27 | export default ImageUpload;
28 |
--------------------------------------------------------------------------------
/11_gerador_pdf/geradorpdf/src/components/TextStyleConfig.jsx:
--------------------------------------------------------------------------------
1 | const TextStyleConfig = ({
2 | fontSize,
3 | setFontSize,
4 | fontColor,
5 | setFontColor,
6 | isBold,
7 | setIsBold,
8 | }) => {
9 | return (
10 |
11 |
20 |
29 |
37 |
38 | );
39 | };
40 |
41 | export default TextStyleConfig;
42 |
--------------------------------------------------------------------------------
/11_gerador_pdf/geradorpdf/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: Courier;
3 | }
4 |
5 | h1 {
6 | text-align: center;
7 | }
8 |
9 | .container {
10 | padding: 20px;
11 | max-width: 500px;
12 | margin: 0 auto;
13 | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
14 | background-color: #fff;
15 | }
16 |
17 | .label {
18 | display: flex;
19 | flex-direction: column;
20 | margin-bottom: 20px;
21 | font-size: 16px;
22 | }
23 |
24 | .input {
25 | padding: 10px;
26 | font-size: 16px;
27 | border: 1px solid #ccc;
28 | border-radius: 4px;
29 | }
30 |
31 | .button {
32 | padding: 10px 20px;
33 | font-size: 16px;
34 | background-color: #007bff;
35 | color: #fff;
36 | border: none;
37 | border-radius: 4px;
38 | cursor: pointer;
39 | }
40 |
41 | .button:hover {
42 | background-color: #0056b3;
43 | }
44 |
45 | .textStyleConfig {
46 | padding: 10px;
47 | border: 1px solid #ccc;
48 | border-radius: 4px;
49 | margin-bottom: 20px;
50 | display: flex;
51 | flex-direction: column;
52 | gap: 15px;
53 | }
54 |
55 | .imageUpload {
56 | padding: 10px;
57 | border: 1px solid #ccc;
58 | border-radius: 4px;
59 | margin-bottom: 20px;
60 | }
61 |
62 | .configLabel {
63 | font-size: 16px;
64 | margin-bottom: 10px;
65 | }
66 |
67 | .colorPicker {
68 | cursor: pointer;
69 | }
70 |
71 | .fileInput {
72 | cursor: pointer;
73 | }
74 |
--------------------------------------------------------------------------------
/11_gerador_pdf/geradorpdf/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.jsx'
4 | import './index.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root')).render(
7 |
8 |
9 | ,
10 | )
11 |
--------------------------------------------------------------------------------
/11_gerador_pdf/geradorpdf/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/12_calculadora_imposto/calcimposto/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: { browser: true, es2020: true },
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:react/recommended',
7 | 'plugin:react/jsx-runtime',
8 | 'plugin:react-hooks/recommended',
9 | ],
10 | ignorePatterns: ['dist', '.eslintrc.cjs'],
11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
12 | settings: { react: { version: '18.2' } },
13 | plugins: ['react-refresh'],
14 | rules: {
15 | 'react-refresh/only-export-components': [
16 | 'warn',
17 | { allowConstantExport: true },
18 | ],
19 | },
20 | }
21 |
--------------------------------------------------------------------------------
/12_calculadora_imposto/calcimposto/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/12_calculadora_imposto/calcimposto/README.md:
--------------------------------------------------------------------------------
1 | # React + Vite
2 |
3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4 |
5 | Currently, two official plugins are available:
6 |
7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9 |
--------------------------------------------------------------------------------
/12_calculadora_imposto/calcimposto/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/12_calculadora_imposto/calcimposto/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "calcimposto",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "@emotion/react": "^11.11.1",
14 | "@emotion/styled": "^11.11.0",
15 | "@mui/material": "^5.14.7",
16 | "formik": "^2.4.3",
17 | "react": "^18.2.0",
18 | "react-dom": "^18.2.0",
19 | "react-scripts": "^5.0.1",
20 | "yup": "^1.2.0"
21 | },
22 | "devDependencies": {
23 | "@types/react": "^18.2.15",
24 | "@types/react-dom": "^18.2.7",
25 | "@vitejs/plugin-react": "^4.0.3",
26 | "eslint": "^8.45.0",
27 | "eslint-plugin-react": "^7.32.2",
28 | "eslint-plugin-react-hooks": "^4.6.0",
29 | "eslint-plugin-react-refresh": "^0.4.3",
30 | "vite": "^4.4.5"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/12_calculadora_imposto/calcimposto/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/12_calculadora_imposto/calcimposto/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | max-width: 1280px;
3 | margin: 0 auto;
4 | padding: 2rem;
5 | text-align: center;
6 | }
7 |
8 | .logo {
9 | height: 6em;
10 | padding: 1.5em;
11 | will-change: filter;
12 | transition: filter 300ms;
13 | }
14 | .logo:hover {
15 | filter: drop-shadow(0 0 2em #646cffaa);
16 | }
17 | .logo.react:hover {
18 | filter: drop-shadow(0 0 2em #61dafbaa);
19 | }
20 |
21 | @keyframes logo-spin {
22 | from {
23 | transform: rotate(0deg);
24 | }
25 | to {
26 | transform: rotate(360deg);
27 | }
28 | }
29 |
30 | @media (prefers-reduced-motion: no-preference) {
31 | a:nth-of-type(2) .logo {
32 | animation: logo-spin infinite 20s linear;
33 | }
34 | }
35 |
36 | .card {
37 | padding: 2em;
38 | }
39 |
40 | .read-the-docs {
41 | color: #888;
42 | }
43 |
--------------------------------------------------------------------------------
/12_calculadora_imposto/calcimposto/src/App.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { Container, Typography } from "@mui/material";
3 | import TaxForm from "./components/TaxForm";
4 | import TaxReport from "./components/TaxReport";
5 |
6 | const App = () => {
7 | const [taxData, setTaxData] = useState(null);
8 |
9 | const calculateTax = (values) => {
10 | let tax = 0;
11 | const income = parseFloat(values.income);
12 |
13 | if (income <= 10000) {
14 | tax = income * 0.05;
15 | } else if (income <= 20000) {
16 | tax = income * 0.1;
17 | } else {
18 | tax = income * 0.15;
19 | }
20 |
21 | const taxData = {
22 | ...values,
23 | tax,
24 | };
25 |
26 | setTaxData(taxData);
27 | };
28 |
29 | console.log(taxData);
30 |
31 | return (
32 |
33 |
34 | Calculadora de Impostos
35 |
36 |
37 | {taxData && }
38 |
39 | );
40 | };
41 |
42 | export default App;
43 |
--------------------------------------------------------------------------------
/12_calculadora_imposto/calcimposto/src/components/TaxReport.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Container, Typography } from "@mui/material";
3 |
4 | const TaxReport = ({ taxData }) => {
5 | return (
6 |
7 | Relatório de Impostos
8 | Nome: {taxData.name}
9 | Idade: {taxData.age} anos
10 |
11 | Renda:
12 | {parseFloat(taxData.income).toLocaleString("pt-BR", {
13 | style: "currency",
14 | currency: "BRL",
15 | })}
16 |
17 |
18 | Imposto a Pagar:
19 | {parseFloat(taxData.tax).toLocaleString("pt-BR", {
20 | style: "currency",
21 | currency: "BRL",
22 | })}
23 |
24 |
25 | );
26 | };
27 |
28 | export default TaxReport;
29 |
--------------------------------------------------------------------------------
/12_calculadora_imposto/calcimposto/src/index.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matheusbattisti/projetos_react/992dfa03ff6f17b6d328471db595404494c26f7a/12_calculadora_imposto/calcimposto/src/index.css
--------------------------------------------------------------------------------
/12_calculadora_imposto/calcimposto/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.jsx'
4 | import './index.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root')).render(
7 |
8 |
9 | ,
10 | )
11 |
--------------------------------------------------------------------------------
/12_calculadora_imposto/calcimposto/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/13_pomodoro/pomodoro/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: { browser: true, es2020: true },
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:react/recommended',
7 | 'plugin:react/jsx-runtime',
8 | 'plugin:react-hooks/recommended',
9 | ],
10 | ignorePatterns: ['dist', '.eslintrc.cjs'],
11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
12 | settings: { react: { version: '18.2' } },
13 | plugins: ['react-refresh'],
14 | rules: {
15 | 'react-refresh/only-export-components': [
16 | 'warn',
17 | { allowConstantExport: true },
18 | ],
19 | },
20 | }
21 |
--------------------------------------------------------------------------------
/13_pomodoro/pomodoro/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/13_pomodoro/pomodoro/README.md:
--------------------------------------------------------------------------------
1 | # React + Vite
2 |
3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4 |
5 | Currently, two official plugins are available:
6 |
7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9 |
--------------------------------------------------------------------------------
/13_pomodoro/pomodoro/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/13_pomodoro/pomodoro/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pomodoro",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "@chakra-ui/react": "^2.8.0",
14 | "@emotion/react": "^11.11.1",
15 | "@emotion/styled": "^11.11.0",
16 | "framer-motion": "^10.16.2",
17 | "react": "^18.2.0",
18 | "react-dom": "^18.2.0"
19 | },
20 | "devDependencies": {
21 | "@types/react": "^18.2.15",
22 | "@types/react-dom": "^18.2.7",
23 | "@vitejs/plugin-react": "^4.0.3",
24 | "eslint": "^8.45.0",
25 | "eslint-plugin-react": "^7.32.2",
26 | "eslint-plugin-react-hooks": "^4.6.0",
27 | "eslint-plugin-react-refresh": "^0.4.3",
28 | "vite": "^4.4.5"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/13_pomodoro/pomodoro/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/13_pomodoro/pomodoro/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | max-width: 1280px;
3 | margin: 0 auto;
4 | padding: 2rem;
5 | text-align: center;
6 | }
7 |
8 | .logo {
9 | height: 6em;
10 | padding: 1.5em;
11 | will-change: filter;
12 | transition: filter 300ms;
13 | }
14 | .logo:hover {
15 | filter: drop-shadow(0 0 2em #646cffaa);
16 | }
17 | .logo.react:hover {
18 | filter: drop-shadow(0 0 2em #61dafbaa);
19 | }
20 |
21 | @keyframes logo-spin {
22 | from {
23 | transform: rotate(0deg);
24 | }
25 | to {
26 | transform: rotate(360deg);
27 | }
28 | }
29 |
30 | @media (prefers-reduced-motion: no-preference) {
31 | a:nth-of-type(2) .logo {
32 | animation: logo-spin infinite 20s linear;
33 | }
34 | }
35 |
36 | .card {
37 | padding: 2em;
38 | }
39 |
40 | .read-the-docs {
41 | color: #888;
42 | }
43 |
--------------------------------------------------------------------------------
/13_pomodoro/pomodoro/src/App.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { ChakraProvider, CSSReset, Box, Text } from "@chakra-ui/react";
3 | import PomodoroTimer from "./components/PomodoroTimer";
4 |
5 | function App() {
6 | return (
7 |
8 |
9 |
10 | Pomodoro
11 |
12 |
13 |
14 | );
15 | }
16 |
17 | export default App;
18 |
--------------------------------------------------------------------------------
/13_pomodoro/pomodoro/src/index.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matheusbattisti/projetos_react/992dfa03ff6f17b6d328471db595404494c26f7a/13_pomodoro/pomodoro/src/index.css
--------------------------------------------------------------------------------
/13_pomodoro/pomodoro/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.jsx'
4 | import './index.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root')).render(
7 |
8 |
9 | ,
10 | )
11 |
--------------------------------------------------------------------------------
/13_pomodoro/pomodoro/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/14_carousel/carousel/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: { browser: true, es2020: true },
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:react/recommended',
7 | 'plugin:react/jsx-runtime',
8 | 'plugin:react-hooks/recommended',
9 | ],
10 | ignorePatterns: ['dist', '.eslintrc.cjs'],
11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
12 | settings: { react: { version: '18.2' } },
13 | plugins: ['react-refresh'],
14 | rules: {
15 | 'react-refresh/only-export-components': [
16 | 'warn',
17 | { allowConstantExport: true },
18 | ],
19 | },
20 | }
21 |
--------------------------------------------------------------------------------
/14_carousel/carousel/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/14_carousel/carousel/README.md:
--------------------------------------------------------------------------------
1 | # React + Vite
2 |
3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4 |
5 | Currently, two official plugins are available:
6 |
7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9 |
--------------------------------------------------------------------------------
/14_carousel/carousel/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/14_carousel/carousel/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "carousel",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "react": "^18.2.0",
14 | "react-dom": "^18.2.0"
15 | },
16 | "devDependencies": {
17 | "@types/react": "^18.2.15",
18 | "@types/react-dom": "^18.2.7",
19 | "@vitejs/plugin-react": "^4.0.3",
20 | "eslint": "^8.45.0",
21 | "eslint-plugin-react": "^7.32.2",
22 | "eslint-plugin-react-hooks": "^4.6.0",
23 | "eslint-plugin-react-refresh": "^0.4.3",
24 | "vite": "^4.4.5"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/14_carousel/carousel/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/14_carousel/carousel/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | max-width: 1280px;
3 | margin: 0 auto;
4 | padding: 2rem;
5 | text-align: center;
6 | }
7 |
8 | .logo {
9 | height: 6em;
10 | padding: 1.5em;
11 | will-change: filter;
12 | transition: filter 300ms;
13 | }
14 | .logo:hover {
15 | filter: drop-shadow(0 0 2em #646cffaa);
16 | }
17 | .logo.react:hover {
18 | filter: drop-shadow(0 0 2em #61dafbaa);
19 | }
20 |
21 | @keyframes logo-spin {
22 | from {
23 | transform: rotate(0deg);
24 | }
25 | to {
26 | transform: rotate(360deg);
27 | }
28 | }
29 |
30 | @media (prefers-reduced-motion: no-preference) {
31 | a:nth-of-type(2) .logo {
32 | animation: logo-spin infinite 20s linear;
33 | }
34 | }
35 |
36 | .card {
37 | padding: 2em;
38 | }
39 |
40 | .read-the-docs {
41 | color: #888;
42 | }
43 |
--------------------------------------------------------------------------------
/14_carousel/carousel/src/App.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "./App.css";
3 | import Carousel from "./components/Carousel";
4 |
5 | const imageUrls = [
6 | "https://images.unsplash.com/photo-1501854140801-50d01698950b?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1950&q=80",
7 | "https://images.unsplash.com/photo-1426604966848-d7adac402bff?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2070&q=80",
8 | "https://images.unsplash.com/photo-1470252649378-9c29740c9fa8?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2070&q=80",
9 | ];
10 |
11 | const App = () => {
12 | return (
13 |
14 |
Carousel
15 |
16 |
17 | );
18 | };
19 |
20 | export default App;
21 |
--------------------------------------------------------------------------------
/14_carousel/carousel/src/components/Carousel.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import Slide from "./Slide";
3 | import Indicators from "./Indicators";
4 |
5 | const Carousel = ({ imageUrls }) => {
6 | const [activeIndex, setActiveIndex] = useState(0);
7 | const [manualChange, setManualChange] = useState(false);
8 |
9 | useEffect(() => {
10 | const interval = setInterval(() => {
11 | if (!manualChange) {
12 | setActiveIndex((prevIndex) => (prevIndex + 1) % imageUrls.length);
13 | }
14 | setManualChange(false); // Reset manual change
15 | }, 5000);
16 |
17 | return () => clearInterval(interval);
18 | }, [manualChange, imageUrls.length]);
19 |
20 | const goPrev = () => {
21 | setManualChange(true);
22 | setActiveIndex(
23 | (prevIndex) => (prevIndex - 1 + imageUrls.length) % imageUrls.length
24 | );
25 | };
26 |
27 | const goNext = () => {
28 | setManualChange(true);
29 | setActiveIndex((prevIndex) => (prevIndex + 1) % imageUrls.length);
30 | };
31 |
32 | return (
33 |
34 | {imageUrls.map((url, index) => (
35 |
36 | ))}
37 |
38 |
41 |
44 |
45 | );
46 | };
47 |
48 | export default Carousel;
49 |
--------------------------------------------------------------------------------
/14_carousel/carousel/src/components/Indicators.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const Indicators = ({ activeIndex, length }) => {
4 | return (
5 |
6 | {Array.from({ length }, (_, index) => (
7 |
11 | ))}
12 |
13 | );
14 | };
15 |
16 | export default Indicators;
17 |
--------------------------------------------------------------------------------
/14_carousel/carousel/src/components/Slide.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const Slide = ({ url, isActive }) => {
4 | return (
5 |
6 | {isActive &&

}
7 |
8 | );
9 | };
10 |
11 | export default Slide;
12 |
--------------------------------------------------------------------------------
/14_carousel/carousel/src/index.css:
--------------------------------------------------------------------------------
1 | * {
2 | font-family: Helvetica;
3 | }
4 |
5 | /* Estilos para o carrossel */
6 | h1 {
7 | text-align: center;
8 | }
9 |
10 | .carousel {
11 | width: 100%;
12 | max-width: 800px;
13 | margin: auto;
14 | overflow: hidden;
15 | position: relative;
16 | }
17 |
18 | /* Estilos para cada slide */
19 | .slide {
20 | opacity: 0;
21 | position: absolute;
22 | width: 100%;
23 | transition: opacity 1s;
24 | }
25 |
26 | /* Estilo para o slide ativo */
27 | .slide.active {
28 | opacity: 1;
29 | position: relative;
30 | transition: opacity 1s;
31 | }
32 |
33 | /* Imagens dentro dos slides */
34 | .slide img {
35 | width: 100%;
36 | }
37 |
38 | /* Estilos para os indicadores */
39 | .indicators {
40 | position: absolute;
41 | bottom: 0;
42 | width: 100%;
43 | display: flex;
44 | justify-content: center;
45 | padding: 15px;
46 | }
47 |
48 | /* Estilo de cada indicador */
49 | .indicator {
50 | width: 10px;
51 | height: 10px;
52 | background: #6e6b6b;
53 | border-radius: 50%;
54 | margin: 0 5px;
55 | transition: background 0.3s;
56 | }
57 |
58 | /* Estilo para o indicador ativo */
59 | .indicator.active {
60 | background: #fff;
61 | }
62 |
63 | /* Estilos para os botões */
64 | .carousel-button {
65 | position: absolute;
66 | top: 50%;
67 | transform: translateY(-50%);
68 | background: rgba(0, 0, 0, 0.5);
69 | color: #fff;
70 | border: none;
71 | padding: 10px;
72 | cursor: pointer;
73 | z-index: 10;
74 | }
75 |
76 | .carousel-button.prev {
77 | left: 0;
78 | }
79 |
80 | .carousel-button.next {
81 | right: 0;
82 | }
83 |
--------------------------------------------------------------------------------
/14_carousel/carousel/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.jsx'
4 | import './index.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root')).render(
7 |
8 |
9 | ,
10 | )
11 |
--------------------------------------------------------------------------------
/14_carousel/carousel/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/15_tabela_ordenavel/tabelaordenavel/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: { browser: true, es2020: true },
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:react/recommended',
7 | 'plugin:react/jsx-runtime',
8 | 'plugin:react-hooks/recommended',
9 | ],
10 | ignorePatterns: ['dist', '.eslintrc.cjs'],
11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
12 | settings: { react: { version: '18.2' } },
13 | plugins: ['react-refresh'],
14 | rules: {
15 | 'react-refresh/only-export-components': [
16 | 'warn',
17 | { allowConstantExport: true },
18 | ],
19 | },
20 | }
21 |
--------------------------------------------------------------------------------
/15_tabela_ordenavel/tabelaordenavel/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/15_tabela_ordenavel/tabelaordenavel/README.md:
--------------------------------------------------------------------------------
1 | # React + Vite
2 |
3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4 |
5 | Currently, two official plugins are available:
6 |
7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9 |
--------------------------------------------------------------------------------
/15_tabela_ordenavel/tabelaordenavel/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/15_tabela_ordenavel/tabelaordenavel/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tabelaordenavel",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "react": "^18.2.0",
14 | "react-dom": "^18.2.0"
15 | },
16 | "devDependencies": {
17 | "@types/react": "^18.2.15",
18 | "@types/react-dom": "^18.2.7",
19 | "@vitejs/plugin-react": "^4.0.3",
20 | "eslint": "^8.45.0",
21 | "eslint-plugin-react": "^7.32.2",
22 | "eslint-plugin-react-hooks": "^4.6.0",
23 | "eslint-plugin-react-refresh": "^0.4.3",
24 | "vite": "^4.4.5"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/15_tabela_ordenavel/tabelaordenavel/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/15_tabela_ordenavel/tabelaordenavel/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | max-width: 1280px;
3 | margin: 0 auto;
4 | padding: 2rem;
5 | text-align: center;
6 | }
7 |
8 | .logo {
9 | height: 6em;
10 | padding: 1.5em;
11 | will-change: filter;
12 | transition: filter 300ms;
13 | }
14 | .logo:hover {
15 | filter: drop-shadow(0 0 2em #646cffaa);
16 | }
17 | .logo.react:hover {
18 | filter: drop-shadow(0 0 2em #61dafbaa);
19 | }
20 |
21 | @keyframes logo-spin {
22 | from {
23 | transform: rotate(0deg);
24 | }
25 | to {
26 | transform: rotate(360deg);
27 | }
28 | }
29 |
30 | @media (prefers-reduced-motion: no-preference) {
31 | a:nth-of-type(2) .logo {
32 | animation: logo-spin infinite 20s linear;
33 | }
34 | }
35 |
36 | .card {
37 | padding: 2em;
38 | }
39 |
40 | .read-the-docs {
41 | color: #888;
42 | }
43 |
--------------------------------------------------------------------------------
/15_tabela_ordenavel/tabelaordenavel/src/components/SearchBar.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const SearchBar = ({ searchTerm, setSearchTerm }) => {
4 | return (
5 | setSearchTerm(e.target.value)}
10 | />
11 | );
12 | };
13 |
14 | export default SearchBar;
15 |
--------------------------------------------------------------------------------
/15_tabela_ordenavel/tabelaordenavel/src/components/TableHeader.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const TableHeader = ({ onColumnClick }) => {
4 | return (
5 |
6 |
7 | onColumnClick("nome")}>Nome |
8 | onColumnClick("idade")}>Idade |
9 | onColumnClick("cargo")}>Cargo |
10 |
11 |
12 | );
13 | };
14 |
15 | export default TableHeader;
16 |
--------------------------------------------------------------------------------
/15_tabela_ordenavel/tabelaordenavel/src/components/TableRow.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const TableRow = ({ row }) => {
4 | return (
5 |
6 | {row.nome} |
7 | {row.idade} |
8 | {row.cargo} |
9 |
10 | );
11 | };
12 |
13 | export default TableRow;
14 |
--------------------------------------------------------------------------------
/15_tabela_ordenavel/tabelaordenavel/src/index.css:
--------------------------------------------------------------------------------
1 | * {
2 | font-family: Verdana;
3 | }
4 |
5 | .container {
6 | max-width: 800px;
7 | margin: 20px auto;
8 | }
9 |
10 | table {
11 | width: 100%;
12 | border-collapse: collapse;
13 | margin-top: 20px;
14 | }
15 |
16 | th,
17 | td {
18 | border: 1px solid #ddd;
19 | text-align: left;
20 | padding: 8px;
21 | }
22 |
23 | th {
24 | background-color: #f2f2f2;
25 | cursor: pointer;
26 | }
27 |
28 | tr:nth-child(even) {
29 | background-color: #f2f2f2;
30 | }
31 |
32 | /* Estilo para a barra de pesquisa */
33 | .search-bar {
34 | margin: 20px 0;
35 | padding: 10px;
36 | width: 100%;
37 | border: 1px solid #ccc;
38 | border-radius: 4px;
39 | box-sizing: border-box;
40 | }
41 |
--------------------------------------------------------------------------------
/15_tabela_ordenavel/tabelaordenavel/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.jsx'
4 | import './index.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root')).render(
7 |
8 |
9 | ,
10 | )
11 |
--------------------------------------------------------------------------------
/15_tabela_ordenavel/tabelaordenavel/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/16_infinite_scroll/infinitescroll/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: { browser: true, es2020: true },
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:react/recommended',
7 | 'plugin:react/jsx-runtime',
8 | 'plugin:react-hooks/recommended',
9 | ],
10 | ignorePatterns: ['dist', '.eslintrc.cjs'],
11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
12 | settings: { react: { version: '18.2' } },
13 | plugins: ['react-refresh'],
14 | rules: {
15 | 'react-refresh/only-export-components': [
16 | 'warn',
17 | { allowConstantExport: true },
18 | ],
19 | },
20 | }
21 |
--------------------------------------------------------------------------------
/16_infinite_scroll/infinitescroll/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/16_infinite_scroll/infinitescroll/README.md:
--------------------------------------------------------------------------------
1 | # React + Vite
2 |
3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4 |
5 | Currently, two official plugins are available:
6 |
7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9 |
--------------------------------------------------------------------------------
/16_infinite_scroll/infinitescroll/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/16_infinite_scroll/infinitescroll/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "infinitescroll",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "axios": "^1.5.0",
14 | "react": "^18.2.0",
15 | "react-dom": "^18.2.0"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^18.2.15",
19 | "@types/react-dom": "^18.2.7",
20 | "@vitejs/plugin-react": "^4.0.3",
21 | "eslint": "^8.45.0",
22 | "eslint-plugin-react": "^7.32.2",
23 | "eslint-plugin-react-hooks": "^4.6.0",
24 | "eslint-plugin-react-refresh": "^0.4.3",
25 | "vite": "^4.4.5"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/16_infinite_scroll/infinitescroll/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/16_infinite_scroll/infinitescroll/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | max-width: 1280px;
3 | margin: 0 auto;
4 | padding: 2rem;
5 | text-align: center;
6 | }
7 |
8 | .logo {
9 | height: 6em;
10 | padding: 1.5em;
11 | will-change: filter;
12 | transition: filter 300ms;
13 | }
14 | .logo:hover {
15 | filter: drop-shadow(0 0 2em #646cffaa);
16 | }
17 | .logo.react:hover {
18 | filter: drop-shadow(0 0 2em #61dafbaa);
19 | }
20 |
21 | @keyframes logo-spin {
22 | from {
23 | transform: rotate(0deg);
24 | }
25 | to {
26 | transform: rotate(360deg);
27 | }
28 | }
29 |
30 | @media (prefers-reduced-motion: no-preference) {
31 | a:nth-of-type(2) .logo {
32 | animation: logo-spin infinite 20s linear;
33 | }
34 | }
35 |
36 | .card {
37 | padding: 2em;
38 | }
39 |
40 | .read-the-docs {
41 | color: #888;
42 | }
43 |
--------------------------------------------------------------------------------
/16_infinite_scroll/infinitescroll/src/App.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import InfiniteScroll from "./components/InfiniteScroll";
3 |
4 | function App() {
5 | return (
6 |
7 |
8 |
9 | );
10 | }
11 |
12 | export default App;
13 |
--------------------------------------------------------------------------------
/16_infinite_scroll/infinitescroll/src/index.css:
--------------------------------------------------------------------------------
1 | /* Estilo global */
2 | body {
3 | font-family: Arial, sans-serif;
4 | margin: 0;
5 | padding: 0;
6 | }
7 |
8 | /* Estilo para o componente InfiniteScroll */
9 | h1 {
10 | text-align: center;
11 | margin-top: 20px;
12 | }
13 |
14 | ul {
15 | list-style: none;
16 | padding: 0;
17 | margin: 20px auto;
18 | max-width: 800px;
19 | }
20 |
21 | li {
22 | border: 1px solid #ccc;
23 | margin: 8px 0;
24 | padding: 16px;
25 | }
26 |
27 | p {
28 | margin: 0;
29 | }
30 |
31 | /* Estilo para a mensagem de carregamento */
32 | p {
33 | text-align: center;
34 | font-size: 18px;
35 | color: #333;
36 | }
37 |
--------------------------------------------------------------------------------
/16_infinite_scroll/infinitescroll/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.jsx'
4 | import './index.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root')).render(
7 |
8 |
9 | ,
10 | )
11 |
--------------------------------------------------------------------------------
/16_infinite_scroll/infinitescroll/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/18_blog_com_axios/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/18_blog_com_axios/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/18_blog_com_axios/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-axios",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "dependencies": {
12 | "axios": "^1.1.3",
13 | "react": "^18.2.0",
14 | "react-dom": "^18.2.0",
15 | "react-router-dom": "^6.4.3"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^18.0.24",
19 | "@types/react-dom": "^18.0.8",
20 | "@vitejs/plugin-react": "^2.2.0",
21 | "vite": "^3.2.3"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/18_blog_com_axios/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/18_blog_com_axios/src/App.css:
--------------------------------------------------------------------------------
1 | .container {
2 | max-width: 1000px;
3 | margin: 2rem auto;
4 | }
5 |
--------------------------------------------------------------------------------
/18_blog_com_axios/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { Outlet } from "react-router-dom";
2 |
3 | import Navbar from "./components/Navbar";
4 |
5 | import "./App.css";
6 |
7 | function App() {
8 | return (
9 |
15 | );
16 | }
17 |
18 | export default App;
19 |
--------------------------------------------------------------------------------
/18_blog_com_axios/src/axios/config.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | const blogFetch = axios.create({
4 | baseURL: "https://jsonplaceholder.typicode.com",
5 | headers: {
6 | "Content-Type": "application/json",
7 | },
8 | });
9 |
10 | export default blogFetch;
11 |
--------------------------------------------------------------------------------
/18_blog_com_axios/src/components/Navbar.css:
--------------------------------------------------------------------------------
1 | .navbar {
2 | display: flex;
3 | align-items: center;
4 | justify-content: space-between;
5 | padding: 1rem 2rem;
6 | background-color: #17191f;
7 | }
8 |
9 | .navbar h2 a {
10 | opacity: 1;
11 | }
12 |
13 | .navbar ul {
14 | display: flex;
15 | gap: 1rem;
16 | }
17 |
18 | .new-btn {
19 | font-weight: bold;
20 | border: 1px solid #fff;
21 | padding: 0.5rem 1rem;
22 | border-radius: 1rem;
23 | opacity: 1;
24 | }
25 |
--------------------------------------------------------------------------------
/18_blog_com_axios/src/components/Navbar.jsx:
--------------------------------------------------------------------------------
1 | import { Link } from "react-router-dom";
2 |
3 | import "./Navbar.css";
4 |
5 | const Navbar = () => {
6 | return (
7 |
25 | );
26 | };
27 |
28 | export default Navbar;
29 |
--------------------------------------------------------------------------------
/18_blog_com_axios/src/index.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | font-family: "Blinker", sans-serif;
5 | }
6 |
7 | body {
8 | background-color: #0e1217;
9 | color: #fff;
10 | }
11 |
12 | ul {
13 | list-style: none;
14 | }
15 |
16 | a {
17 | text-decoration: none;
18 | color: #fff;
19 | opacity: 0.7;
20 | transition: 0.3s;
21 | }
22 |
23 | a:hover {
24 | opacity: 1;
25 | }
26 |
27 | p {
28 | color: #a9abb3;
29 | }
30 |
--------------------------------------------------------------------------------
/18_blog_com_axios/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 |
4 | import { createBrowserRouter, RouterProvider, Route } from "react-router-dom";
5 |
6 | import App from "./App";
7 |
8 | import Home from "./routes/Home";
9 | import Post from "./routes/Post";
10 | import NewPost from "./routes/NewPost";
11 | import Admin from "./routes/Admin";
12 | import EditPost from "./routes/EditPost";
13 |
14 | import "./index.css";
15 |
16 | const router = createBrowserRouter([
17 | {
18 | element: ,
19 | children: [
20 | {
21 | path: "/",
22 | element: ,
23 | },
24 | {
25 | path: "/posts/:id",
26 | element: ,
27 | },
28 | {
29 | path: "/new",
30 | element: ,
31 | },
32 | {
33 | path: "/admin",
34 | element: ,
35 | },
36 | ,
37 | {
38 | path: "/posts/edit/:id",
39 | element: ,
40 | },
41 | ],
42 | },
43 | ]);
44 |
45 | ReactDOM.createRoot(document.getElementById("root")).render(
46 |
47 |
48 |
49 | );
50 |
--------------------------------------------------------------------------------
/18_blog_com_axios/src/routes/Admin.css:
--------------------------------------------------------------------------------
1 | .admin h1 {
2 | text-align: center;
3 | margin-bottom: 2rem;
4 | }
5 |
6 | .actions {
7 | display: flex;
8 | gap: 1rem;
9 | }
10 |
11 | .edit-btn {
12 | background-color: #13c9e9;
13 | color: #fff;
14 | }
15 |
16 | .delete-btn {
17 | background-color: #eb1717;
18 | color: #fff;
19 | }
20 |
--------------------------------------------------------------------------------
/18_blog_com_axios/src/routes/Home.css:
--------------------------------------------------------------------------------
1 | .home h1 {
2 | text-transform: uppercase;
3 | text-align: center;
4 | margin-bottom: 1.5rem;
5 | }
6 |
7 | .post {
8 | display: flex;
9 | flex-direction: column;
10 | margin-bottom: 1.5rem;
11 | padding-bottom: 1.5rem;
12 | border-bottom: 1px solid #777;
13 | }
14 |
15 | .post h2,
16 | .post p {
17 | margin-bottom: 1rem;
18 | }
19 |
20 | .post h2::first-letter {
21 | text-transform: uppercase;
22 | }
23 |
24 | .btn {
25 | background-color: #fff;
26 | color: #0e1217;
27 | border: 1px solid #fff;
28 | opacity: 1;
29 | padding: 0.5rem 1rem;
30 | border-radius: 1rem;
31 | max-width: 100px;
32 | text-align: center;
33 | cursor: pointer;
34 | transition: 0.3s;
35 | }
36 |
37 | .btn:hover {
38 | color: #fff;
39 | background-color: #0e1217;
40 | }
41 |
--------------------------------------------------------------------------------
/18_blog_com_axios/src/routes/Home.jsx:
--------------------------------------------------------------------------------
1 | import blogFetch from "../axios/config";
2 |
3 | import { useState, useEffect } from "react";
4 |
5 | import { Link } from "react-router-dom";
6 |
7 | import "./Home.css";
8 |
9 | const Home = () => {
10 | const [posts, setPosts] = useState([]);
11 |
12 | const getPosts = async () => {
13 | try {
14 | const response = await blogFetch.get("/posts");
15 |
16 | const data = response.data;
17 |
18 | setPosts(data);
19 | } catch (error) {
20 | console.log(error);
21 | }
22 | };
23 |
24 | useEffect(() => {
25 | getPosts();
26 | }, []);
27 |
28 | return (
29 |
30 |
Últimos posts
31 | {posts.length === 0 ? (
32 |
Carregando...
33 | ) : (
34 | posts.map((post) => (
35 |
36 |
{post.title}
37 |
{post.body}
38 |
39 | Ler mais
40 |
41 |
42 | ))
43 | )}
44 |
45 | );
46 | };
47 |
48 | export default Home;
49 |
--------------------------------------------------------------------------------
/18_blog_com_axios/src/routes/NewPost.css:
--------------------------------------------------------------------------------
1 | .new-post h2 {
2 | text-align: center;
3 | margin-bottom: 1rem;
4 | }
5 |
6 | form {
7 | max-width: 500px;
8 | width: 100%;
9 | margin: 0 auto;
10 | }
11 |
12 | .form-control {
13 | display: flex;
14 | flex-direction: column;
15 | margin-bottom: 1rem;
16 | }
17 |
18 | .form-control label {
19 | margin-bottom: 0.5rem;
20 | }
21 |
22 | .form-control input,
23 | .form-control textarea {
24 | padding: 0.5rem;
25 | border-radius: 5px;
26 | border: none;
27 | }
28 |
--------------------------------------------------------------------------------
/18_blog_com_axios/src/routes/NewPost.jsx:
--------------------------------------------------------------------------------
1 | import blogFetch from "../axios/config";
2 |
3 | import { useState } from "react";
4 |
5 | import { useNavigate } from "react-router-dom";
6 |
7 | import "./NewPost.css";
8 |
9 | const NewPost = () => {
10 | const navigate = useNavigate();
11 |
12 | const [title, setTitle] = useState();
13 | const [body, setBody] = useState();
14 |
15 | const createPost = async (e) => {
16 | e.preventDefault();
17 |
18 | const post = { title, body, userId: 1 };
19 |
20 | await blogFetch.post("/posts", {
21 | body: post,
22 | });
23 |
24 | navigate("/");
25 | };
26 |
27 | return (
28 |
29 |
Inserir novo Post:
30 |
52 |
53 | );
54 | };
55 |
56 | export default NewPost;
57 |
--------------------------------------------------------------------------------
/18_blog_com_axios/src/routes/Post.css:
--------------------------------------------------------------------------------
1 | .post-container h2 {
2 | text-align: center;
3 | }
4 |
5 | .post-container .post {
6 | border: none;
7 | }
8 |
--------------------------------------------------------------------------------
/18_blog_com_axios/src/routes/Post.jsx:
--------------------------------------------------------------------------------
1 | import blogFetch from "../axios/config";
2 |
3 | import { useState, useEffect } from "react";
4 |
5 | import { useParams } from "react-router-dom";
6 |
7 | import './Post.css'
8 |
9 | const Post = () => {
10 | const { id } = useParams();
11 | const [post, setPost] = useState([]);
12 |
13 | const getPost = async () => {
14 | try {
15 | const response = await blogFetch.get(`/posts/${id}`);
16 |
17 | const data = response.data;
18 |
19 | setPost(data);
20 | } catch (error) {
21 | console.log(error);
22 | }
23 | };
24 |
25 | useEffect(() => {
26 | getPost();
27 | }, []);
28 |
29 | return (
30 |
31 | {!post.title ? (
32 |
Carregando...
33 | ) : (
34 |
35 |
{post.title}
36 |
{post.body}
37 |
38 | )}
39 |
40 | );
41 | };
42 |
43 | export default Post;
44 |
--------------------------------------------------------------------------------
/18_blog_com_axios/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()]
7 | })
8 |
--------------------------------------------------------------------------------
/19_multistep_form/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/19_multistep_form/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Formulário Multistep com React
8 |
9 |
10 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/19_multistep_form/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-multistep-form",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "dependencies": {
12 | "react": "^18.2.0",
13 | "react-dom": "^18.2.0",
14 | "react-icons": "^4.6.0"
15 | },
16 | "devDependencies": {
17 | "@types/react": "^18.0.24",
18 | "@types/react-dom": "^18.0.8",
19 | "@vitejs/plugin-react": "^2.2.0",
20 | "vite": "^3.2.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/19_multistep_form/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/19_multistep_form/src/App.css:
--------------------------------------------------------------------------------
1 | .app {
2 | padding: 2rem;
3 | }
4 |
5 | .header {
6 | text-align: center;
7 | margin-bottom: 2rem;
8 | }
9 |
10 | .header h2 {
11 | font-size: 2rem;
12 | margin-bottom: 1rem;
13 | }
14 |
15 | /* Forms */
16 | .form-container {
17 | max-width: 600px;
18 | margin: 0 auto;
19 | background-color: #fff;
20 | padding: 1.5rem;
21 | box-shadow: rgba(100, 100, 111, 0.2) 0px 7px 29px 0px;
22 | }
23 |
24 | .inputs-container {
25 | min-height: 280px;
26 | }
27 |
28 | .form-container form {
29 | max-width: 400px;
30 | margin: 0 auto;
31 | }
32 |
33 | .form-control {
34 | display: flex;
35 | flex-direction: column;
36 | gap: 0.6rem;
37 | margin-bottom: 2rem;
38 | }
39 |
40 | label {
41 | font-weight: bold;
42 | color: #777;
43 | font-size: 0.9rem;
44 | }
45 |
46 | input,
47 | textarea {
48 | padding: 0.6rem;
49 | border: none;
50 | border-radius: 3px;
51 | box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px;
52 | }
53 |
54 | textarea {
55 | height: 120px;
56 | }
57 |
58 | /* Actions */
59 | .actions {
60 | display: flex;
61 | justify-content: flex-end;
62 | gap: 1rem;
63 | }
64 |
65 | .actions button {
66 | font-size: 0.9rem;
67 | padding: 0.5rem 1rem;
68 | gap: 0.5rem;
69 | display: flex;
70 | align-items: center;
71 | border: 2px solid transparent;
72 | border-radius: 3px;
73 | background-color: #dfdfdf;
74 | cursor: pointer;
75 | transition: 0.3s;
76 | }
77 |
78 | .actions button:hover {
79 | background-color: #cfcfcf;
80 | }
81 |
--------------------------------------------------------------------------------
/19_multistep_form/src/components/ReviewForm.css:
--------------------------------------------------------------------------------
1 | .form-control.score-container {
2 | flex-direction: row;
3 | justify-content: center;
4 | gap: 2rem;
5 | }
6 |
7 | .score-container svg {
8 | font-size: 1.6rem;
9 | cursor: pointer;
10 | transition: 0.3s;
11 | }
12 |
13 | .score-container svg:hover {
14 | fill: #7076f4;
15 | }
16 |
17 | .score-container input:checked ~ svg {
18 | fill: #7076f4;
19 | }
20 |
21 | .radio-container {
22 | text-align: center;
23 | position: relative;
24 | }
25 |
26 | .radio-container input {
27 | opacity: 0;
28 | top: 15px;
29 | left: 20px;
30 | position: absolute;
31 | }
32 |
33 | .radio-container p {
34 | font-style: italic;
35 | font-weight: 300;
36 | font-size: 0.7rem;
37 | margin-top: 0.4rem;
38 | }
39 |
--------------------------------------------------------------------------------
/19_multistep_form/src/components/Steps.css:
--------------------------------------------------------------------------------
1 | .steps {
2 | display: flex;
3 | gap: 4rem;
4 | justify-content: center;
5 | align-items: center;
6 | max-width: 400px;
7 | margin: 0 auto;
8 | position: relative;
9 | margin-bottom: 2rem;
10 | }
11 |
12 | .steps::after {
13 | content: "";
14 | width: 380px;
15 | border-bottom: 1px solid #ccc;
16 | position: absolute;
17 | top: 20px;
18 | }
19 |
20 | .step {
21 | text-align: center;
22 | background-color: #fff;
23 | z-index: 1;
24 | padding: 0.5rem;
25 | width: 120px;
26 | }
27 |
28 | .step svg {
29 | font-size: 1.6rem;
30 | margin-bottom: 0.2rem;
31 | }
32 |
33 | .active {
34 | font-weight: bold;
35 | }
36 |
37 | .active > svg {
38 | fill: #7076f4;
39 | }
40 |
--------------------------------------------------------------------------------
/19_multistep_form/src/components/Steps.jsx:
--------------------------------------------------------------------------------
1 | import { AiOutlineUser, AiOutlineStar } from "react-icons/ai";
2 | import { FiSend } from "react-icons/fi";
3 |
4 | import "./Steps.css";
5 |
6 | const Steps = ({ currentStep }) => {
7 | return (
8 |
9 |
10 |
11 |
Identificação
12 |
13 |
= 1 ? "active" : ""}`}>
14 |
15 |
Avaliação
16 |
17 |
= 2 ? "active" : ""}`}>
18 |
19 |
Envio
20 |
21 |
22 | );
23 | };
24 |
25 | export default Steps;
26 |
--------------------------------------------------------------------------------
/19_multistep_form/src/components/Thanks.css:
--------------------------------------------------------------------------------
1 | .thanks-container {
2 | text-align: center;
3 | }
4 |
5 | .thanks-container h2 {
6 | margin-bottom: 1rem;
7 | }
8 |
9 | .thanks-container p {
10 | font-size: 0.9rem;
11 | margin-bottom: 0.5rem;
12 | }
13 |
14 | .thanks-container h3 {
15 | margin: 1rem 0;
16 | }
17 |
18 | .review-data {
19 | text-align: left;
20 | }
21 |
22 | .review-data svg {
23 | margin-left: 5px;
24 | }
25 |
26 | .review-data span {
27 | font-weight: bold;
28 | }
29 |
--------------------------------------------------------------------------------
/19_multistep_form/src/components/Thanks.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | BsFillEmojiHeartEyesFill,
3 | BsFillEmojiSmileFill,
4 | BsFillEmojiNeutralFill,
5 | BsFillEmojiFrownFill,
6 | } from "react-icons/bs";
7 |
8 | import "./Thanks.css";
9 |
10 | const emojiData = {
11 | unsatisfied: ,
12 | neutral: ,
13 | satisfied: ,
14 | very_satisfied: ,
15 | };
16 |
17 | const Thanks = ({ data }) => {
18 | return (
19 |
20 |
Falta pouco...
21 |
22 | A sua opinião é muito importante, em breve você receberá um cupom de 10%
23 | de desconto para a sua próxima compra.
24 |
25 |
Para concluir sua avaliação clique no botão de Enviar abaixo.
26 |
Aqui está o resumo da sua avaliação {data.name}:
27 |
28 | Satisfação com o produto:
29 | {emojiData[data.review]}
30 |
31 |
32 | Comentário: {data.comment}
33 |
34 |
35 | );
36 | };
37 |
38 | export default Thanks;
39 |
--------------------------------------------------------------------------------
/19_multistep_form/src/components/UserForm.jsx:
--------------------------------------------------------------------------------
1 | const UserForm = ({ data, updateFieldHandler }) => {
2 | return (
3 |
29 | );
30 | };
31 |
32 | export default UserForm;
33 |
--------------------------------------------------------------------------------
/19_multistep_form/src/hooks/useForm.jsx:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 |
3 | export function useForm(steps) {
4 | const [currentStep, setCurrentStep] = useState(0);
5 |
6 | function changeStep(i, e) {
7 | if (e) e.preventDefault();
8 |
9 | if (i < 0 || i >= steps.length) return;
10 |
11 | setCurrentStep(i);
12 | }
13 |
14 | return {
15 | currentStep,
16 | isLastStep: currentStep + 1 === steps.length ? true : false,
17 | currentComponent: steps[currentStep],
18 | changeStep,
19 | };
20 | }
21 |
--------------------------------------------------------------------------------
/19_multistep_form/src/index.css:
--------------------------------------------------------------------------------
1 | * {
2 | padding: 0;
3 | margin: 0;
4 | box-sizing: border-box;
5 | font-family: "Barlow", sans-serif;
6 | color: #333;
7 | }
8 |
9 | p {
10 | color: #777;
11 | }
12 |
13 | body {
14 | background-color: #f9fafc;
15 | }
16 |
--------------------------------------------------------------------------------
/19_multistep_form/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root')).render(
7 |
8 |
9 |
10 | )
11 |
--------------------------------------------------------------------------------
/19_multistep_form/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()]
7 | })
8 |
--------------------------------------------------------------------------------
/1_calculadora/calculadora/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | /* eslint-env node */
2 |
3 | module.exports = {
4 | env: { browser: true, es2020: true },
5 | extends: [
6 | 'eslint:recommended',
7 | 'plugin:react/recommended',
8 | 'plugin:react/jsx-runtime',
9 | 'plugin:react-hooks/recommended',
10 | ],
11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
12 | settings: { react: { version: '18.2' } },
13 | plugins: ['react-refresh'],
14 | rules: {
15 | 'react-refresh/only-export-components': [
16 | 'warn',
17 | { allowConstantExport: true },
18 | ],
19 | },
20 | }
21 |
--------------------------------------------------------------------------------
/1_calculadora/calculadora/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/1_calculadora/calculadora/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/1_calculadora/calculadora/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "calculadora",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint src --ext js,jsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "react": "^18.2.0",
14 | "react-dom": "^18.2.0"
15 | },
16 | "devDependencies": {
17 | "@types/react": "^18.2.14",
18 | "@types/react-dom": "^18.2.6",
19 | "@vitejs/plugin-react": "^4.0.1",
20 | "eslint": "^8.44.0",
21 | "eslint-plugin-react": "^7.32.2",
22 | "eslint-plugin-react-hooks": "^4.6.0",
23 | "eslint-plugin-react-refresh": "^0.4.1",
24 | "vite": "^4.4.0"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/1_calculadora/calculadora/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/1_calculadora/calculadora/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | max-width: 1280px;
3 | margin: 0 auto;
4 | padding: 2rem;
5 | text-align: center;
6 | }
7 |
8 | .logo {
9 | height: 6em;
10 | padding: 1.5em;
11 | will-change: filter;
12 | transition: filter 300ms;
13 | }
14 | .logo:hover {
15 | filter: drop-shadow(0 0 2em #646cffaa);
16 | }
17 | .logo.react:hover {
18 | filter: drop-shadow(0 0 2em #61dafbaa);
19 | }
20 |
21 | @keyframes logo-spin {
22 | from {
23 | transform: rotate(0deg);
24 | }
25 | to {
26 | transform: rotate(360deg);
27 | }
28 | }
29 |
30 | @media (prefers-reduced-motion: no-preference) {
31 | a:nth-of-type(2) .logo {
32 | animation: logo-spin infinite 20s linear;
33 | }
34 | }
35 |
36 | .card {
37 | padding: 2em;
38 | }
39 |
40 | .read-the-docs {
41 | color: #888;
42 | }
43 |
--------------------------------------------------------------------------------
/1_calculadora/calculadora/src/App.jsx:
--------------------------------------------------------------------------------
1 |
2 | import Calculator from './components/Calculator'
3 | import './App.css'
4 |
5 | function App() {
6 |
7 | return (
8 | <>
9 |
10 | >
11 | )
12 | }
13 |
14 | export default App
15 |
--------------------------------------------------------------------------------
/1_calculadora/calculadora/src/components/Calculator.css:
--------------------------------------------------------------------------------
1 | .calculator {
2 | display: flex;
3 | flex-direction: column;
4 | align-items: center;
5 | justify-content: center;
6 | width: 200px;
7 | margin: auto;
8 | }
9 |
10 | .display {
11 | width: 100%;
12 | height: 50px;
13 | border: 1px solid #000;
14 | margin-bottom: 10px;
15 | text-align: right;
16 | padding: 5px;
17 | }
18 |
19 | .complete-operation {
20 | width: 100%;
21 | min-height: 30px;
22 | border: 1px solid #000;
23 | margin-bottom: 10px;
24 | text-align: right;
25 | padding: 5px;
26 | font-size: 0.8rem;
27 | overflow: auto;
28 | }
29 |
30 | .buttons {
31 | display: grid;
32 | grid-template-columns: repeat(4, 1fr);
33 | gap: 10px;
34 | }
35 |
36 | button {
37 | padding: 10px;
38 | font-size: 16px;
39 | }
40 |
--------------------------------------------------------------------------------
/1_calculadora/calculadora/src/index.css:
--------------------------------------------------------------------------------
1 | :root {
2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
3 | line-height: 1.5;
4 | font-weight: 400;
5 |
6 | color-scheme: light dark;
7 | color: rgba(255, 255, 255, 0.87);
8 | background-color: #242424;
9 |
10 | font-synthesis: none;
11 | text-rendering: optimizeLegibility;
12 | -webkit-font-smoothing: antialiased;
13 | -moz-osx-font-smoothing: grayscale;
14 | -webkit-text-size-adjust: 100%;
15 | }
16 |
17 | a {
18 | font-weight: 500;
19 | color: #646cff;
20 | text-decoration: inherit;
21 | }
22 | a:hover {
23 | color: #535bf2;
24 | }
25 |
26 | body {
27 | margin: 0;
28 | display: flex;
29 | place-items: center;
30 | min-width: 320px;
31 | min-height: 100vh;
32 | }
33 |
34 | h1 {
35 | font-size: 3.2em;
36 | line-height: 1.1;
37 | }
38 |
39 | button {
40 | border-radius: 8px;
41 | border: 1px solid transparent;
42 | padding: 0.6em 1.2em;
43 | font-size: 1em;
44 | font-weight: 500;
45 | font-family: inherit;
46 | background-color: #1a1a1a;
47 | cursor: pointer;
48 | transition: border-color 0.25s;
49 | }
50 | button:hover {
51 | border-color: #646cff;
52 | }
53 | button:focus,
54 | button:focus-visible {
55 | outline: 4px auto -webkit-focus-ring-color;
56 | }
57 |
58 | @media (prefers-color-scheme: light) {
59 | :root {
60 | color: #213547;
61 | background-color: #ffffff;
62 | }
63 | a:hover {
64 | color: #747bff;
65 | }
66 | button {
67 | background-color: #f9f9f9;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/1_calculadora/calculadora/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.jsx'
4 | import './index.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root')).render(
7 |
8 |
9 | ,
10 | )
11 |
--------------------------------------------------------------------------------
/1_calculadora/calculadora/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/20_github_api/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/20_github_api/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | GitHub Finder
8 |
9 |
10 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/20_github_api/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "github_react",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "tsc && vite build",
9 | "preview": "vite preview"
10 | },
11 | "dependencies": {
12 | "react": "^18.2.0",
13 | "react-dom": "^18.2.0",
14 | "react-icons": "^4.7.1",
15 | "react-router-dom": "^6.5.0"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^18.0.26",
19 | "@types/react-dom": "^18.0.9",
20 | "@vitejs/plugin-react": "^3.0.0",
21 | "typescript": "^4.9.3",
22 | "vite": "^4.0.0"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/20_github_api/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/20_github_api/src/App.module.css:
--------------------------------------------------------------------------------
1 | .app {
2 | max-width: 500px;
3 | margin: 0 auto;
4 | }
5 |
6 | .app h1 {
7 | text-align: center;
8 | margin-bottom: 1rem;
9 | }
10 |
--------------------------------------------------------------------------------
/20_github_api/src/App.tsx:
--------------------------------------------------------------------------------
1 | import { Outlet } from "react-router-dom";
2 |
3 | import classes from "./App.module.css";
4 |
5 | function App() {
6 | return (
7 |
8 |
GitHub Finder
9 |
10 |
11 | );
12 | }
13 |
14 | export default App;
15 |
--------------------------------------------------------------------------------
/20_github_api/src/components/BackBtn.module.css:
--------------------------------------------------------------------------------
1 | .back_btn {
2 | position: absolute;
3 | top: 1rem;
4 | left: 1rem;
5 | padding: 0.5rem 1rem;
6 | color: #9da5d1;
7 | background-color: #2b3566;
8 | cursor: pointer;
9 | border: none;
10 | border-radius: 5px;
11 | opacity: 0.9;
12 | }
13 |
14 | .back_btn:hover {
15 | opacity: 1;
16 | }
17 |
--------------------------------------------------------------------------------
/20_github_api/src/components/BackBtn.tsx:
--------------------------------------------------------------------------------
1 | import { useNavigate } from "react-router-dom";
2 |
3 | import classes from "./BackBtn.module.css";
4 |
5 | const BackBtn = () => {
6 | const navigate = useNavigate();
7 |
8 | return (
9 | <>
10 |
13 | >
14 | );
15 | };
16 |
17 | export default BackBtn;
18 |
--------------------------------------------------------------------------------
/20_github_api/src/components/Error.tsx:
--------------------------------------------------------------------------------
1 | const Error = () => {
2 | return (
3 |
4 |
Usuário não encontrado!
5 |
6 | );
7 | };
8 |
9 | export default Error;
10 |
--------------------------------------------------------------------------------
/20_github_api/src/components/Loader.module.css:
--------------------------------------------------------------------------------
1 | @keyframes rotate {
2 | from {
3 | -webkit-transform: rotate(0deg);
4 | }
5 | to {
6 | -webkit-transform: rotate(360deg);
7 | }
8 | }
9 |
10 | .loader {
11 | animation: rotate 2s linear infinite;
12 | position: absolute;
13 | left: 50%;
14 | margin-top: 40px;
15 | font-size: 50px;
16 | margin-left: -25px;
17 | }
18 |
--------------------------------------------------------------------------------
/20_github_api/src/components/Loader.tsx:
--------------------------------------------------------------------------------
1 | import { FaSpinner } from "react-icons/fa";
2 |
3 | import classes from "./Loader.module.css";
4 |
5 | const Loader = () => {
6 | return (
7 | <>
8 |
9 | >
10 | );
11 | };
12 |
13 | export default Loader;
14 |
--------------------------------------------------------------------------------
/20_github_api/src/components/Repo.module.css:
--------------------------------------------------------------------------------
1 | .repo {
2 | background-color: #0e1129;
3 | padding: 2rem;
4 | border-radius: 10px;
5 | border: 2px solid #9da5d1;
6 | display: flex;
7 | flex-direction: column;
8 | align-items: start;
9 | gap: 1rem;
10 | flex: 1 0 50%;
11 | }
12 |
13 | .stats {
14 | display: flex;
15 | gap: 1rem;
16 | }
17 |
18 | .stats div {
19 | display: flex;
20 | align-items: center;
21 | justify-content: center;
22 | gap: 0.4rem;
23 | border-radius: 3px;
24 | border: 1px solid #9da5d1;
25 | padding-right: 0.4rem;
26 | }
27 |
28 | .stats svg {
29 | background-color: #4ed8c7;
30 | padding: 0.2rem 0.4rem;
31 | border-radius: 3px;
32 | font-size: 2rem;
33 | }
34 |
35 | .repo_btn {
36 | display: flex;
37 | align-items: center;
38 | padding: 0.5rem 1rem;
39 | color: #9da5d1;
40 | background-color: #2b3566;
41 | border-radius: 5px;
42 | gap: 0.5rem;
43 | }
44 |
--------------------------------------------------------------------------------
/20_github_api/src/components/Repo.tsx:
--------------------------------------------------------------------------------
1 | import { RepoProps } from "../types/repo";
2 |
3 | import { AiOutlineStar, AiOutlineFork } from "react-icons/ai";
4 | import { BsCodeSlash } from "react-icons/bs";
5 | import { RiGitRepositoryLine } from "react-icons/ri";
6 |
7 | import classes from "./Repo.module.css";
8 |
9 | const Repo = ({
10 | name,
11 | language,
12 | html_url,
13 | forks_count,
14 | stargazers_count,
15 | }: RepoProps) => {
16 | return (
17 |
18 |
{name}
19 |
20 | {language}
21 |
22 |
23 |
24 |
25 |
{stargazers_count}
26 |
27 |
28 |
29 |
{forks_count}
30 |
31 |
32 |
33 | Ver código
34 |
35 |
36 |
37 | );
38 | };
39 |
40 | export default Repo;
41 |
--------------------------------------------------------------------------------
/20_github_api/src/components/Search.module.css:
--------------------------------------------------------------------------------
1 | .search {
2 | background-color: #2b3566;
3 | padding: 2rem;
4 | border-radius: 1rem;
5 | display: flex;
6 | justify-content: center;
7 | align-items: center;
8 | flex-direction: column;
9 | gap: 1rem;
10 | margin-bottom: 1.5rem;
11 | }
12 |
13 | .search p {
14 | color: #9da5d1;
15 | }
16 |
17 | .search_container {
18 | display: flex;
19 | gap: 0.5rem;
20 | }
21 |
22 | .search_container input,
23 | .search_container button {
24 | padding: 0.6rem;
25 | border-radius: 3px;
26 | border: none;
27 | color: #2b3566;
28 | }
29 |
30 | .search_container button {
31 | background-color: #0e1129;
32 | cursor: pointer;
33 | }
34 |
--------------------------------------------------------------------------------
/20_github_api/src/components/Search.tsx:
--------------------------------------------------------------------------------
1 | type SearchProps = {
2 | loadUser: (userName: string) => Promise;
3 | };
4 |
5 | import { useState, KeyboardEvent } from "react";
6 |
7 | import { BsSearch } from "react-icons/bs";
8 |
9 | import classes from "./Search.module.css";
10 |
11 | const Search = ({ loadUser }: SearchProps) => {
12 | const [userName, setUserName] = useState("");
13 |
14 | const handleKeyDown = (e: KeyboardEvent) => {
15 | if (e.key === "Enter") {
16 | loadUser(userName);
17 | }
18 | };
19 |
20 | return (
21 |
22 |
Busque por um usuário:
23 |
Conheça seus melhores repositórios
24 |
25 | setUserName(e.target.value)}
28 | onKeyDown={handleKeyDown}
29 | placeholder="Digite o nome do usuário"
30 | />
31 |
34 |
35 |
36 | );
37 | };
38 |
39 | export default Search;
40 |
--------------------------------------------------------------------------------
/20_github_api/src/components/User.module.css:
--------------------------------------------------------------------------------
1 | .user {
2 | background-color: #2b3566;
3 | padding: 2rem;
4 | border-radius: 1rem;
5 | display: flex;
6 | justify-content: center;
7 | align-items: center;
8 | flex-direction: column;
9 | gap: 1.2rem;
10 | }
11 |
12 | .user img {
13 | width: 140px;
14 | height: 140px;
15 | border: 4px solid #644aff;
16 | border-radius: 50%;
17 | }
18 |
19 | .location {
20 | display: flex;
21 | align-items: center;
22 | gap: 0.4rem;
23 | }
24 |
25 | .location svg {
26 | fill: #4ed8c7;
27 | font-size: 1.5rem;
28 | }
29 |
30 | .location span {
31 | color: #9da5d1;
32 | font-weight: bold;
33 | }
34 |
35 | .stats {
36 | display: flex;
37 | }
38 |
39 | .stats div {
40 | padding: 0 1rem;
41 | display: flex;
42 | flex-direction: column;
43 | gap: 0.4rem;
44 | }
45 |
46 | .stats div:first-child {
47 | border-right: 1px solid #9da5d1;
48 | }
49 |
50 | .stats .number {
51 | background-color: #4ed8c7;
52 | padding: 0.2rem 0.4rem;
53 | border-radius: 3px;
54 | }
55 |
56 | .user a {
57 | text-align: center;
58 | background-color: #644aff;
59 | padding: 1rem;
60 | border-radius: 5px;
61 | opacity: 0.8;
62 | transition: 0.3s;
63 | }
64 |
65 | .user a:hover {
66 | opacity: 1;
67 | }
68 |
--------------------------------------------------------------------------------
/20_github_api/src/components/User.tsx:
--------------------------------------------------------------------------------
1 | import { UserProps } from "../types/user";
2 |
3 | import { MdLocationPin } from "react-icons/md";
4 |
5 | import { Link } from "react-router-dom";
6 |
7 | import classes from "./User.module.css";
8 |
9 | const User = ({
10 | login,
11 | avatar_url,
12 | followers,
13 | following,
14 | location,
15 | }: UserProps) => {
16 | return (
17 |
18 |

19 |
{login}
20 |
21 | {location}
22 |
23 |
24 |
25 |
Seguidores:
26 |
{followers}
27 |
28 |
29 |
Seguindo:
30 |
{following}
31 |
32 |
33 |
Ver melhores projetos
34 |
35 | );
36 | };
37 |
38 | export default User;
39 |
--------------------------------------------------------------------------------
/20_github_api/src/index.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | box-sizing: border-box;
5 | font-family: "Inter", sans-serif;
6 | color: #fff;
7 | }
8 |
9 | body {
10 | background-color: #0e1129;
11 | padding: 2rem;
12 | }
13 |
14 | p {
15 | text-align: center;
16 | }
17 |
18 | a {
19 | text-decoration: none;
20 | }
21 |
--------------------------------------------------------------------------------
/20_github_api/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App";
4 | import "./index.css";
5 |
6 | import { createBrowserRouter, RouterProvider } from "react-router-dom";
7 |
8 | // Pages
9 | import Home from "./routes/Home";
10 | import Repos from "./routes/Repos";
11 |
12 | const router = createBrowserRouter([
13 | {
14 | path: "/",
15 | element: ,
16 | children: [
17 | {
18 | path: "/",
19 | element: ,
20 | },
21 | {
22 | path: "/repos/:username",
23 | element: ,
24 | },
25 | ],
26 | },
27 | ]);
28 |
29 | ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
30 |
31 |
32 |
33 | );
34 |
--------------------------------------------------------------------------------
/20_github_api/src/routes/Home.tsx:
--------------------------------------------------------------------------------
1 | import { UserProps } from "../types/user";
2 |
3 | import { useState } from "react";
4 |
5 | import Search from "../components/Search";
6 | import User from "../components/User";
7 | import Error from "../components/Error";
8 | import Loader from "../components/Loader";
9 |
10 | const Home = () => {
11 | const [user, setUser] = useState(null);
12 | const [error, setError] = useState(false);
13 | const [isLoading, setIsLoading] = useState(false);
14 |
15 | const loadUser = async function (userName: string) {
16 | setUser(null);
17 | setIsLoading(true);
18 |
19 | const res = await fetch(`https://api.github.com/users/${userName}`);
20 |
21 | const data = await res.json();
22 |
23 | setIsLoading(false);
24 |
25 | if (res.status === 404) {
26 | setError(true);
27 | return;
28 | }
29 |
30 | setError(false);
31 |
32 | const { avatar_url, login, location, followers, following } = data;
33 |
34 | const userData: UserProps = {
35 | avatar_url,
36 | login,
37 | location,
38 | followers,
39 | following,
40 | };
41 |
42 | setUser(userData);
43 | };
44 |
45 | return (
46 |
47 |
48 | {isLoading && }
49 | {user && }
50 | {error && }
51 |
52 | );
53 | };
54 |
55 | export default Home;
56 |
--------------------------------------------------------------------------------
/20_github_api/src/routes/Repos.module.css:
--------------------------------------------------------------------------------
1 | .repos h2 {
2 | font-size: 1.2rem;
3 | text-align: center;
4 | margin-bottom: 2rem;
5 | }
6 |
7 | .repos_container {
8 | background-color: #2b3566;
9 | padding: 2rem;
10 | border-radius: 1rem;
11 | display: flex;
12 | align-items: center;
13 | flex-wrap: wrap;
14 | gap: 1.2rem;
15 | }
16 |
--------------------------------------------------------------------------------
/20_github_api/src/types/repo.ts:
--------------------------------------------------------------------------------
1 | export type RepoProps = {
2 | name: string;
3 | html_url: string;
4 | language: string;
5 | stargazers_count: number;
6 | forks_count: number;
7 | };
8 |
--------------------------------------------------------------------------------
/20_github_api/src/types/user.ts:
--------------------------------------------------------------------------------
1 | export type UserProps = {
2 | avatar_url: string;
3 | login: string;
4 | location: string;
5 | followers: number;
6 | following: number;
7 | };
8 |
--------------------------------------------------------------------------------
/20_github_api/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/20_github_api/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx"
18 | },
19 | "include": ["src"],
20 | "references": [{ "path": "./tsconfig.node.json" }]
21 | }
22 |
--------------------------------------------------------------------------------
/20_github_api/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "module": "ESNext",
5 | "moduleResolution": "Node",
6 | "allowSyntheticDefaultImports": true
7 | },
8 | "include": ["vite.config.ts"]
9 | }
10 |
--------------------------------------------------------------------------------
/20_github_api/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/22_form_com_react_hook_e_ts/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: { browser: true, es2020: true },
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:@typescript-eslint/recommended',
7 | 'plugin:react-hooks/recommended',
8 | ],
9 | ignorePatterns: ['dist', '.eslintrc.cjs'],
10 | parser: '@typescript-eslint/parser',
11 | plugins: ['react-refresh'],
12 | rules: {
13 | 'react-refresh/only-export-components': [
14 | 'warn',
15 | { allowConstantExport: true },
16 | ],
17 | },
18 | }
19 |
--------------------------------------------------------------------------------
/22_form_com_react_hook_e_ts/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/22_form_com_react_hook_e_ts/README.md:
--------------------------------------------------------------------------------
1 | # React + TypeScript + Vite
2 |
3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4 |
5 | Currently, two official plugins are available:
6 |
7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9 |
10 | ## Expanding the ESLint configuration
11 |
12 | If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
13 |
14 | - Configure the top-level `parserOptions` property like this:
15 |
16 | ```js
17 | parserOptions: {
18 | ecmaVersion: 'latest',
19 | sourceType: 'module',
20 | project: ['./tsconfig.json', './tsconfig.node.json'],
21 | tsconfigRootDir: __dirname,
22 | },
23 | ```
24 |
25 | - Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
26 | - Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
27 | - Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list
28 |
--------------------------------------------------------------------------------
/22_form_com_react_hook_e_ts/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | React Hook Form com TS
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/22_form_com_react_hook_e_ts/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hook-form-ts",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "tsc && vite build",
9 | "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "@hookform/resolvers": "^3.2.0",
14 | "react": "^18.2.0",
15 | "react-dom": "^18.2.0",
16 | "react-hook-form": "^7.45.4",
17 | "zod": "^3.21.4"
18 | },
19 | "devDependencies": {
20 | "@types/react": "^18.2.15",
21 | "@types/react-dom": "^18.2.7",
22 | "@typescript-eslint/eslint-plugin": "^6.0.0",
23 | "@typescript-eslint/parser": "^6.0.0",
24 | "@vitejs/plugin-react": "^4.0.3",
25 | "autoprefixer": "^10.4.14",
26 | "eslint": "^8.45.0",
27 | "eslint-plugin-react-hooks": "^4.6.0",
28 | "eslint-plugin-react-refresh": "^0.4.3",
29 | "postcss": "^8.4.27",
30 | "tailwindcss": "^3.3.3",
31 | "typescript": "^5.0.2",
32 | "vite": "^4.4.5"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/22_form_com_react_hook_e_ts/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/22_form_com_react_hook_e_ts/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/22_form_com_react_hook_e_ts/src/App.tsx:
--------------------------------------------------------------------------------
1 | import { Form } from "./components/Form/Form";
2 |
3 | export const App = () => {
4 | return (
5 |
6 |
React Hook Form Com TypeScript
7 |
8 |
9 | );
10 | };
11 |
--------------------------------------------------------------------------------
/22_form_com_react_hook_e_ts/src/hooks/useForms.tsx:
--------------------------------------------------------------------------------
1 | import { zodResolver } from "@hookform/resolvers/zod";
2 | import { useForm } from "react-hook-form";
3 | import { FormSchema, formSchema } from "../schemas/formSchema";
4 |
5 | export const useForms = () => {
6 | const {
7 | register,
8 | handleSubmit,
9 | formState: { errors },
10 | } = useForm({
11 | resolver: zodResolver(formSchema),
12 | });
13 |
14 | return { register, handleSubmit, errors };
15 | };
16 |
--------------------------------------------------------------------------------
/22_form_com_react_hook_e_ts/src/index.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
--------------------------------------------------------------------------------
/22_form_com_react_hook_e_ts/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import { App } from "./App.tsx";
4 | import "./index.css";
5 |
6 | ReactDOM.createRoot(document.getElementById("root")!).render(
7 |
8 |
9 |
10 | );
11 |
--------------------------------------------------------------------------------
/22_form_com_react_hook_e_ts/src/schemas/formSchema.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 |
3 | export const formSchema = z
4 | .object({
5 | name: z
6 | .string()
7 | .nonempty("Campo obrigatório.")
8 | .min(3, "O número de mínimo de caracteres é 3."),
9 | lastname: z
10 | .string()
11 | .nonempty("Campo obrigatório.")
12 | .min(3, "O número de mínimo de caracteres é 3."),
13 | gender: z.string().refine((field) => field !== "select", {
14 | message: "Você precisa escolher um gênero.",
15 | }),
16 | email: z
17 | .string()
18 | .nonempty("Campo obrigatório.")
19 | .email("Utilize um e-mail válido."),
20 | password: z.string().min(6, "A senha precisa ter no mínimo 6 caracteres."),
21 | confirmpassword: z
22 | .string()
23 | .min(6, "A senha precisa ter no mínimo 6 caracteres."),
24 | agree: z.boolean().refine((field) => field === true, {
25 | message: "Você precisa concordar com os termos.",
26 | }),
27 | })
28 | .refine((field) => field.password === field.confirmpassword, {
29 | message: "As senhas precisam ser iguais",
30 | path: ["confirmpassword"],
31 | });
32 |
33 | export type FormSchema = z.infer;
34 |
--------------------------------------------------------------------------------
/22_form_com_react_hook_e_ts/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/22_form_com_react_hook_e_ts/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | export default {
3 | content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
4 | theme: {
5 | extend: {},
6 | },
7 | plugins: [],
8 | };
9 |
--------------------------------------------------------------------------------
/22_form_com_react_hook_e_ts/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "useDefineForClassFields": true,
5 | "lib": ["ES2020", "DOM", "DOM.Iterable"],
6 | "module": "ESNext",
7 | "skipLibCheck": true,
8 |
9 | /* Bundler mode */
10 | "moduleResolution": "bundler",
11 | "allowImportingTsExtensions": true,
12 | "resolveJsonModule": true,
13 | "isolatedModules": true,
14 | "noEmit": true,
15 | "jsx": "react-jsx",
16 |
17 | /* Linting */
18 | "strict": true,
19 | "noUnusedLocals": true,
20 | "noUnusedParameters": true,
21 | "noFallthroughCasesInSwitch": true
22 | },
23 | "include": ["src"],
24 | "references": [{ "path": "./tsconfig.node.json" }]
25 | }
26 |
--------------------------------------------------------------------------------
/22_form_com_react_hook_e_ts/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "skipLibCheck": true,
5 | "module": "ESNext",
6 | "moduleResolution": "bundler",
7 | "allowSyntheticDefaultImports": true
8 | },
9 | "include": ["vite.config.ts"]
10 | }
11 |
--------------------------------------------------------------------------------
/22_form_com_react_hook_e_ts/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/25_newsletter_form/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: { browser: true, es2020: true },
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:@typescript-eslint/recommended',
7 | 'plugin:react-hooks/recommended',
8 | ],
9 | ignorePatterns: ['dist', '.eslintrc.cjs'],
10 | parser: '@typescript-eslint/parser',
11 | plugins: ['react-refresh'],
12 | rules: {
13 | 'react-refresh/only-export-components': [
14 | 'warn',
15 | { allowConstantExport: true },
16 | ],
17 | },
18 | }
19 |
--------------------------------------------------------------------------------
/25_newsletter_form/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/25_newsletter_form/README.md:
--------------------------------------------------------------------------------
1 | # React + TypeScript + Vite
2 |
3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4 |
5 | Currently, two official plugins are available:
6 |
7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9 |
10 | ## Expanding the ESLint configuration
11 |
12 | If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
13 |
14 | - Configure the top-level `parserOptions` property like this:
15 |
16 | ```js
17 | parserOptions: {
18 | ecmaVersion: 'latest',
19 | sourceType: 'module',
20 | project: ['./tsconfig.json', './tsconfig.node.json'],
21 | tsconfigRootDir: __dirname,
22 | },
23 | ```
24 |
25 | - Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
26 | - Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
27 | - Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list
28 |
--------------------------------------------------------------------------------
/25_newsletter_form/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Formulário com TypeScript
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/25_newsletter_form/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "newsletter-form",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "tsc && vite build",
9 | "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "react": "^18.2.0",
14 | "react-dom": "^18.2.0"
15 | },
16 | "devDependencies": {
17 | "@types/react": "^18.2.15",
18 | "@types/react-dom": "^18.2.7",
19 | "@typescript-eslint/eslint-plugin": "^6.0.0",
20 | "@typescript-eslint/parser": "^6.0.0",
21 | "@vitejs/plugin-react": "^4.0.3",
22 | "autoprefixer": "^10.4.16",
23 | "eslint": "^8.45.0",
24 | "eslint-plugin-react-hooks": "^4.6.0",
25 | "eslint-plugin-react-refresh": "^0.4.3",
26 | "postcss": "^8.4.31",
27 | "tailwindcss": "^3.3.5",
28 | "typescript": "^5.0.2",
29 | "vite": "^4.4.5"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/25_newsletter_form/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/25_newsletter_form/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/25_newsletter_form/src/App.tsx:
--------------------------------------------------------------------------------
1 | import { Form } from "./components/Form";
2 |
3 | function App() {
4 | return (
5 |
6 |
Inscreva-se
7 |
8 | Assine nossa Newsletter e mantenha-se informado
9 |
10 |
11 |
12 |
13 |
14 | Ao se inscrever, você passará a receber os nossos e-mails com as
15 | melhores dicas, novidades e ofertas.
16 |
17 |
18 | );
19 | }
20 |
21 | export default App;
22 |
--------------------------------------------------------------------------------
/25_newsletter_form/src/index.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
--------------------------------------------------------------------------------
/25_newsletter_form/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.tsx'
4 | import './index.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root')!).render(
7 |
8 |
9 | ,
10 | )
11 |
--------------------------------------------------------------------------------
/25_newsletter_form/src/types/User.ts:
--------------------------------------------------------------------------------
1 | export type User = {
2 | name?: string;
3 | email?: string;
4 | agree?: boolean | string;
5 | };
6 |
--------------------------------------------------------------------------------
/25_newsletter_form/src/utils/validate.ts:
--------------------------------------------------------------------------------
1 | import { User } from "../types/User";
2 |
3 | type Error = {
4 | [key: string]: string;
5 | };
6 |
7 | export const validate = (data: User) => {
8 | const errors: Error = {};
9 |
10 | if (!data.name) {
11 | errors["name"] = "O nome é obrigatório";
12 | }
13 |
14 | if (!data.email) {
15 | errors["email"] = "O e-mail é obrigatório";
16 | }
17 |
18 | if (!data.agree) {
19 | errors["agree"] = "Você precisa concordar com os termos";
20 | }
21 |
22 | return errors;
23 | };
24 |
--------------------------------------------------------------------------------
/25_newsletter_form/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/25_newsletter_form/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | export default {
3 | content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
4 | theme: {
5 | extend: {},
6 | },
7 | plugins: [],
8 | };
9 |
--------------------------------------------------------------------------------
/25_newsletter_form/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "useDefineForClassFields": true,
5 | "lib": ["ES2020", "DOM", "DOM.Iterable"],
6 | "module": "ESNext",
7 | "skipLibCheck": true,
8 |
9 | /* Bundler mode */
10 | "moduleResolution": "bundler",
11 | "allowImportingTsExtensions": true,
12 | "resolveJsonModule": true,
13 | "isolatedModules": true,
14 | "noEmit": true,
15 | "jsx": "react-jsx",
16 |
17 | /* Linting */
18 | "strict": true,
19 | "noUnusedLocals": true,
20 | "noUnusedParameters": true,
21 | "noFallthroughCasesInSwitch": true
22 | },
23 | "include": ["src"],
24 | "references": [{ "path": "./tsconfig.node.json" }]
25 | }
26 |
--------------------------------------------------------------------------------
/25_newsletter_form/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "skipLibCheck": true,
5 | "module": "ESNext",
6 | "moduleResolution": "bundler",
7 | "allowSyntheticDefaultImports": true
8 | },
9 | "include": ["vite.config.ts"]
10 | }
11 |
--------------------------------------------------------------------------------
/25_newsletter_form/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/2_cronometro/cronometro/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | /* eslint-env node */
2 |
3 | module.exports = {
4 | env: { browser: true, es2020: true },
5 | extends: [
6 | 'eslint:recommended',
7 | 'plugin:react/recommended',
8 | 'plugin:react/jsx-runtime',
9 | 'plugin:react-hooks/recommended',
10 | ],
11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
12 | settings: { react: { version: '18.2' } },
13 | plugins: ['react-refresh'],
14 | rules: {
15 | 'react-refresh/only-export-components': [
16 | 'warn',
17 | { allowConstantExport: true },
18 | ],
19 | },
20 | }
21 |
--------------------------------------------------------------------------------
/2_cronometro/cronometro/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/2_cronometro/cronometro/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/2_cronometro/cronometro/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cronometro",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint src --ext js,jsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "react": "^18.2.0",
14 | "react-dom": "^18.2.0"
15 | },
16 | "devDependencies": {
17 | "@types/react": "^18.2.14",
18 | "@types/react-dom": "^18.2.6",
19 | "@vitejs/plugin-react": "^4.0.1",
20 | "eslint": "^8.44.0",
21 | "eslint-plugin-react": "^7.32.2",
22 | "eslint-plugin-react-hooks": "^4.6.0",
23 | "eslint-plugin-react-refresh": "^0.4.1",
24 | "vite": "^4.4.0"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/2_cronometro/cronometro/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/2_cronometro/cronometro/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | max-width: 1280px;
3 | margin: 0 auto;
4 | padding: 2rem;
5 | text-align: center;
6 | }
7 |
8 | .logo {
9 | height: 6em;
10 | padding: 1.5em;
11 | will-change: filter;
12 | transition: filter 300ms;
13 | }
14 | .logo:hover {
15 | filter: drop-shadow(0 0 2em #646cffaa);
16 | }
17 | .logo.react:hover {
18 | filter: drop-shadow(0 0 2em #61dafbaa);
19 | }
20 |
21 | @keyframes logo-spin {
22 | from {
23 | transform: rotate(0deg);
24 | }
25 | to {
26 | transform: rotate(360deg);
27 | }
28 | }
29 |
30 | @media (prefers-reduced-motion: no-preference) {
31 | a:nth-of-type(2) .logo {
32 | animation: logo-spin infinite 20s linear;
33 | }
34 | }
35 |
36 | .card {
37 | padding: 2em;
38 | }
39 |
40 | .read-the-docs {
41 | color: #888;
42 | }
43 |
--------------------------------------------------------------------------------
/2_cronometro/cronometro/src/App.jsx:
--------------------------------------------------------------------------------
1 | import "./App.css";
2 | import Timer from "./components/Timer";
3 |
4 | function App() {
5 | return (
6 | <>
7 |
8 | >
9 | );
10 | }
11 |
12 | export default App;
13 |
--------------------------------------------------------------------------------
/2_cronometro/cronometro/src/components/LapList.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const LapList = ({ laps }) => {
4 | return (
5 |
6 |
Voltas:
7 |
8 | {laps.map((lap, index) => (
9 | -
10 | Volta {index + 1}: {lap}
11 |
12 | ))}
13 |
14 |
15 | )
16 | };
17 |
18 | export default LapList;
19 |
--------------------------------------------------------------------------------
/2_cronometro/cronometro/src/components/Timer.css:
--------------------------------------------------------------------------------
1 | .timer-container {
2 | display: flex;
3 | flex-direction: column;
4 | align-items: center;
5 | justify-content: center;
6 | min-height: 50vh;
7 | width: 400px;
8 | background-color: #f5f5f5;
9 | font-family: Arial, sans-serif;
10 | padding: 20px;
11 | }
12 |
13 | .timer-display {
14 | border: 2px solid #333;
15 | padding: 20px;
16 | margin: 20px;
17 | font-size: 48px;
18 | background-color: #fff;
19 | }
20 |
21 | .timer-controls {
22 | display: flex;
23 | justify-content: center;
24 | }
25 |
26 | .timer-controls button {
27 | background-color: #007bff;
28 | border: none;
29 | color: white;
30 | padding: 15px 32px;
31 | text-align: center;
32 | text-decoration: none;
33 | display: inline-block;
34 | font-size: 16px;
35 | margin: 4px 2px;
36 | cursor: pointer;
37 | border-radius: 4px;
38 | }
39 |
40 | .timer-controls button:hover {
41 | background-color: #0046d5;
42 | }
43 |
44 | .timer-laps {
45 | width: 100%;
46 | margin: auto;
47 | }
48 |
49 | .timer-laps ul {
50 | list-style-type: none;
51 | display: flex;
52 | flex-wrap: wrap;
53 | }
54 |
55 | .timer-laps li {
56 | border-bottom: 1px solid #ddd;
57 | padding: 8px 16px;
58 | }
59 |
60 | .timer-laps li:nth-child(odd) {
61 | background-color: #ddd;
62 | }
63 |
--------------------------------------------------------------------------------
/2_cronometro/cronometro/src/components/TimerControls.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const TimerControls = ({ timerOn, onStart, onStop, onReset, onLap }) => {
4 | return (
5 |
6 | {!timerOn && }
7 | {timerOn && }
8 | {timerOn && }
9 |
10 |
11 | )
12 | };
13 |
14 | export default TimerControls;
15 |
--------------------------------------------------------------------------------
/2_cronometro/cronometro/src/components/TimerDisplay.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const TimerDisplay = ({ time }) => {
4 | return (
5 |
6 | {time}
7 |
8 | )
9 | };
10 |
11 | export default TimerDisplay;
12 |
--------------------------------------------------------------------------------
/2_cronometro/cronometro/src/index.css:
--------------------------------------------------------------------------------
1 | :root {
2 | font-family: Inter;
3 | line-height: 1.5;
4 | font-weight: 400;
5 | }
6 |
7 | body {
8 | margin: 0;
9 | display: flex;
10 | place-items: center;
11 | }
12 |
--------------------------------------------------------------------------------
/2_cronometro/cronometro/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.jsx'
4 | import './index.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root')).render(
7 |
8 |
9 | ,
10 | )
11 |
--------------------------------------------------------------------------------
/2_cronometro/cronometro/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/3_conversor_moeda/conversor_moeda/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | /* eslint-env node */
2 |
3 | module.exports = {
4 | env: { browser: true, es2020: true },
5 | extends: [
6 | 'eslint:recommended',
7 | 'plugin:react/recommended',
8 | 'plugin:react/jsx-runtime',
9 | 'plugin:react-hooks/recommended',
10 | ],
11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
12 | settings: { react: { version: '18.2' } },
13 | plugins: ['react-refresh'],
14 | rules: {
15 | 'react-refresh/only-export-components': [
16 | 'warn',
17 | { allowConstantExport: true },
18 | ],
19 | },
20 | }
21 |
--------------------------------------------------------------------------------
/3_conversor_moeda/conversor_moeda/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/3_conversor_moeda/conversor_moeda/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/3_conversor_moeda/conversor_moeda/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "conversor_moeda",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint src --ext js,jsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "axios": "^1.4.0",
14 | "react": "^18.2.0",
15 | "react-dom": "^18.2.0"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^18.2.14",
19 | "@types/react-dom": "^18.2.6",
20 | "@vitejs/plugin-react": "^4.0.1",
21 | "eslint": "^8.44.0",
22 | "eslint-plugin-react": "^7.32.2",
23 | "eslint-plugin-react-hooks": "^4.6.0",
24 | "eslint-plugin-react-refresh": "^0.4.1",
25 | "vite": "^4.4.0"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/3_conversor_moeda/conversor_moeda/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/3_conversor_moeda/conversor_moeda/src/App.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matheusbattisti/projetos_react/992dfa03ff6f17b6d328471db595404494c26f7a/3_conversor_moeda/conversor_moeda/src/App.css
--------------------------------------------------------------------------------
/3_conversor_moeda/conversor_moeda/src/App.jsx:
--------------------------------------------------------------------------------
1 | import "./App.css";
2 | import CurrencyConverter from "./components/CurrencyConverter";
3 |
4 | function App() {
5 | return (
6 | <>
7 |
8 | >
9 | );
10 | }
11 |
12 | export default App;
13 |
--------------------------------------------------------------------------------
/3_conversor_moeda/conversor_moeda/src/components/CurrencyConverter.css:
--------------------------------------------------------------------------------
1 | .converter {
2 | display: flex;
3 | flex-direction: column;
4 | align-items: center;
5 | padding: 2rem;
6 | border-radius: 10px;
7 | width: 400px;
8 | margin: 2rem auto;
9 | background-color: #f8f9fa;
10 | box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
11 | }
12 |
13 | .converter h2 {
14 | color: #343a40;
15 | font-size: 1.8rem;
16 | margin-bottom: 2rem;
17 | }
18 |
19 | .converter input,
20 | .converter select {
21 | width: 100%;
22 | padding: 0.7rem 1rem;
23 | box-sizing: border-box;
24 | border-radius: 4px;
25 | font-size: 1rem;
26 | color: #495057;
27 | background-color: #fff;
28 | border: 1px solid #ced4da;
29 | }
30 |
31 | .converter input {
32 | margin-bottom: 30px;
33 | }
34 |
35 | .converter span,
36 | .converter p {
37 | margin: 0.5rem;
38 | font-size: 1rem;
39 | color: #495057;
40 | }
41 |
42 | .converter p {
43 | font-size: 1.2rem;
44 | }
45 |
--------------------------------------------------------------------------------
/3_conversor_moeda/conversor_moeda/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: Helvetica;
4 | }
5 |
--------------------------------------------------------------------------------
/3_conversor_moeda/conversor_moeda/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.jsx'
4 | import './index.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root')).render(
7 |
8 |
9 | ,
10 | )
11 |
--------------------------------------------------------------------------------
/3_conversor_moeda/conversor_moeda/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/4_clima/clima/.env:
--------------------------------------------------------------------------------
1 | VITE_API_KEY=ba605efc18f1572f61892fe426f18a1a
--------------------------------------------------------------------------------
/4_clima/clima/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: { browser: true, es2020: true },
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:react/recommended',
7 | 'plugin:react/jsx-runtime',
8 | 'plugin:react-hooks/recommended',
9 | ],
10 | ignorePatterns: ['dist', '.eslintrc.cjs'],
11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
12 | settings: { react: { version: '18.2' } },
13 | plugins: ['react-refresh'],
14 | rules: {
15 | 'react-refresh/only-export-components': [
16 | 'warn',
17 | { allowConstantExport: true },
18 | ],
19 | },
20 | }
21 |
--------------------------------------------------------------------------------
/4_clima/clima/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/4_clima/clima/README.md:
--------------------------------------------------------------------------------
1 | # React + Vite
2 |
3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4 |
5 | Currently, two official plugins are available:
6 |
7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9 |
--------------------------------------------------------------------------------
/4_clima/clima/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/4_clima/clima/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "clima",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "axios": "^1.4.0",
14 | "react": "^18.2.0",
15 | "react-dom": "^18.2.0",
16 | "styled-components": "^6.0.7"
17 | },
18 | "devDependencies": {
19 | "@types/react": "^18.2.15",
20 | "@types/react-dom": "^18.2.7",
21 | "@vitejs/plugin-react": "^4.0.3",
22 | "eslint": "^8.45.0",
23 | "eslint-plugin-react": "^7.32.2",
24 | "eslint-plugin-react-hooks": "^4.6.0",
25 | "eslint-plugin-react-refresh": "^0.4.3",
26 | "vite": "^4.4.5"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/4_clima/clima/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/4_clima/clima/src/components/Busca.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { BuscaContainer, InputCidade, BotaoBuscar } from "./BuscaStyles";
3 |
4 | const Busca = ({ cidade, setCidade, buscarClima }) => {
5 | return (
6 |
7 | setCidade(e.target.value)}
11 | placeholder="Digite uma cidade"
12 | />
13 | Buscar
14 |
15 | );
16 | };
17 |
18 | export default Busca;
19 |
--------------------------------------------------------------------------------
/4_clima/clima/src/components/BuscaStyles.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 |
3 | export const BuscaContainer = styled.div`
4 | display: flex;
5 | align-items: center;
6 | justify-content: center;
7 | margin-bottom: 20px;
8 | `;
9 |
10 | export const InputCidade = styled.input`
11 | padding: 10px 15px;
12 | border: none;
13 | border-radius: 4px;
14 | box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
15 | font-size: 16px;
16 | outline: none;
17 | width: 60%;
18 | margin-right: 10px;
19 |
20 | &:focus {
21 | border: 1px solid #007bff;
22 | }
23 | `;
24 |
25 | export const BotaoBuscar = styled.button`
26 | padding: 10px 15px;
27 | background-color: #007bff;
28 | color: #fff;
29 | border: none;
30 | border-radius: 4px;
31 | cursor: pointer;
32 | font-size: 16px;
33 | transition: background-color 0.2s ease;
34 |
35 | &:hover {
36 | background-color: #0056b3;
37 | }
38 | `;
39 |
--------------------------------------------------------------------------------
/4_clima/clima/src/components/ClimaAtual.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { ClimaInfo } from "./ClimaAtualStyles";
3 |
4 | const ClimaAtual = ({ clima }) => {
5 | return (
6 |
7 | {clima.name}
8 |
12 | {clima.main.temp}°C
13 | {clima.weather[0].description}
14 |
15 | );
16 | };
17 |
18 | export default ClimaAtual;
19 |
--------------------------------------------------------------------------------
/4_clima/clima/src/components/ClimaAtualStyles.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 |
3 | export const ClimaInfo = styled.div`
4 | text-align: center;
5 |
6 | h3 {
7 | font-size: 1.5rem;
8 | margin-bottom: 10px;
9 | }
10 |
11 | img {
12 | width: 80px;
13 | height: 80px;
14 | margin-bottom: 10px;
15 | }
16 |
17 | p {
18 | margin-bottom: 5px;
19 | }
20 | `;
21 |
--------------------------------------------------------------------------------
/4_clima/clima/src/components/Previsao.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { PrevisaoContainer } from "./PrevisaoStyles";
3 |
4 | const Previsao = ({ previsoes }) => {
5 | return (
6 |
7 | Previsão para as próximas horas
8 |
9 | {previsoes.map((previsao, index) => (
10 | -
11 |
15 | {previsao.main.temp}°C - {previsao.weather[0].description}
16 |
17 | ))}
18 |
19 |
20 | );
21 | };
22 |
23 | export default Previsao;
24 |
--------------------------------------------------------------------------------
/4_clima/clima/src/components/PrevisaoStyles.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 |
3 | export const PrevisaoContainer = styled.div`
4 | margin-top: 20px;
5 | padding: 15px;
6 | background-color: #f7f7f7;
7 | border-radius: 5px;
8 | box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
9 |
10 | h4 {
11 | text-align: center;
12 | margin-bottom: 10px;
13 | color: #333;
14 | }
15 |
16 | ul {
17 | list-style-type: none;
18 | padding: 0;
19 |
20 | li {
21 | display: flex;
22 | align-items: center;
23 | justify-content: space-between;
24 | padding: 10px;
25 | margin-bottom: 5px;
26 | background-color: #fff;
27 | border-radius: 3px;
28 | box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.1);
29 | color: #333;
30 |
31 | img {
32 | margin-right: 10px;
33 | }
34 | }
35 | }
36 | `;
37 |
--------------------------------------------------------------------------------
/4_clima/clima/src/index.css:
--------------------------------------------------------------------------------
1 | * {
2 | padding: 0;
3 | margin: 0;
4 | }
5 |
--------------------------------------------------------------------------------
/4_clima/clima/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.jsx'
4 | import './index.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root')).render(
7 |
8 |
9 | ,
10 | )
11 |
--------------------------------------------------------------------------------
/4_clima/clima/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/5_citacoes/citacoes/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: { browser: true, es2020: true },
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:react/recommended',
7 | 'plugin:react/jsx-runtime',
8 | 'plugin:react-hooks/recommended',
9 | ],
10 | ignorePatterns: ['dist', '.eslintrc.cjs'],
11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
12 | settings: { react: { version: '18.2' } },
13 | plugins: ['react-refresh'],
14 | rules: {
15 | 'react-refresh/only-export-components': [
16 | 'warn',
17 | { allowConstantExport: true },
18 | ],
19 | },
20 | }
21 |
--------------------------------------------------------------------------------
/5_citacoes/citacoes/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/5_citacoes/citacoes/README.md:
--------------------------------------------------------------------------------
1 | # React + Vite
2 |
3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4 |
5 | Currently, two official plugins are available:
6 |
7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9 |
--------------------------------------------------------------------------------
/5_citacoes/citacoes/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/5_citacoes/citacoes/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "citacoes",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "bootstrap": "^5.3.1",
14 | "react": "^18.2.0",
15 | "react-dom": "^18.2.0"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^18.2.15",
19 | "@types/react-dom": "^18.2.7",
20 | "@vitejs/plugin-react": "^4.0.3",
21 | "eslint": "^8.45.0",
22 | "eslint-plugin-react": "^7.32.2",
23 | "eslint-plugin-react-hooks": "^4.6.0",
24 | "eslint-plugin-react-refresh": "^0.4.3",
25 | "vite": "^4.4.5"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/5_citacoes/citacoes/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/5_citacoes/citacoes/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | max-width: 1280px;
3 | margin: 0 auto;
4 | padding: 2rem;
5 | text-align: center;
6 | }
7 |
8 | .logo {
9 | height: 6em;
10 | padding: 1.5em;
11 | will-change: filter;
12 | transition: filter 300ms;
13 | }
14 | .logo:hover {
15 | filter: drop-shadow(0 0 2em #646cffaa);
16 | }
17 | .logo.react:hover {
18 | filter: drop-shadow(0 0 2em #61dafbaa);
19 | }
20 |
21 | @keyframes logo-spin {
22 | from {
23 | transform: rotate(0deg);
24 | }
25 | to {
26 | transform: rotate(360deg);
27 | }
28 | }
29 |
30 | @media (prefers-reduced-motion: no-preference) {
31 | a:nth-of-type(2) .logo {
32 | animation: logo-spin infinite 20s linear;
33 | }
34 | }
35 |
36 | .card {
37 | padding: 2em;
38 | }
39 |
40 | .read-the-docs {
41 | color: #888;
42 | }
43 |
--------------------------------------------------------------------------------
/5_citacoes/citacoes/src/App.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import Citacao from "./components/Citacao";
3 | import citacoes from "./data";
4 |
5 | function App() {
6 | const [indice, setIndice] = useState(0);
7 |
8 | function proximaCitacao() {
9 | setIndice((indiceAtual) => (indiceAtual + 1) % citacoes.length);
10 | }
11 |
12 | return (
13 |
14 |
15 |
18 |
19 | );
20 | }
21 |
22 | export default App;
23 |
--------------------------------------------------------------------------------
/5_citacoes/citacoes/src/components/Citacao.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 |
3 | function Citacao({ texto, autor }) {
4 | const [traducao, setTraducao] = useState("");
5 |
6 | // Resetar a tradução quando o texto da citação mudar
7 | useEffect(() => {
8 | setTraducao("");
9 | }, [texto]);
10 |
11 | async function traduzirCitação(idioma) {
12 | try {
13 | const resposta = await fetch("https://libretranslate.de/translate", {
14 | method: "POST",
15 | body: JSON.stringify({
16 | q: texto,
17 | source: "pt",
18 | target: idioma,
19 | }),
20 | headers: { "Content-Type": "application/json" },
21 | });
22 |
23 | const data = await resposta.json();
24 | setTraducao(data.translatedText);
25 | } catch (erro) {
26 | console.error("Erro ao traduzir citação:", erro);
27 | }
28 | }
29 |
30 | return (
31 |
32 |
33 | {traducao ? traducao : texto}
34 |
35 |
36 |
42 |
48 |
49 | );
50 | }
51 |
52 | export default Citacao;
53 |
--------------------------------------------------------------------------------
/5_citacoes/citacoes/src/index.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
--------------------------------------------------------------------------------
/5_citacoes/citacoes/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 | import "./index.css";
5 |
6 | import "bootstrap/dist/css/bootstrap.min.css";
7 |
8 | ReactDOM.createRoot(document.getElementById("root")).render(
9 |
10 |
11 |
12 | );
13 |
--------------------------------------------------------------------------------
/5_citacoes/citacoes/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/6_album/album/.env:
--------------------------------------------------------------------------------
1 | VITE_UNSPLASH_API_KEY=d0MPOt4hyt1U3sMLR3I83-9Oqqw3PHnYfHoaBL4mqXA
--------------------------------------------------------------------------------
/6_album/album/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: { browser: true, es2020: true },
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:react/recommended',
7 | 'plugin:react/jsx-runtime',
8 | 'plugin:react-hooks/recommended',
9 | ],
10 | ignorePatterns: ['dist', '.eslintrc.cjs'],
11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
12 | settings: { react: { version: '18.2' } },
13 | plugins: ['react-refresh'],
14 | rules: {
15 | 'react-refresh/only-export-components': [
16 | 'warn',
17 | { allowConstantExport: true },
18 | ],
19 | },
20 | }
21 |
--------------------------------------------------------------------------------
/6_album/album/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/6_album/album/README.md:
--------------------------------------------------------------------------------
1 | # React + Vite
2 |
3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4 |
5 | Currently, two official plugins are available:
6 |
7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9 |
--------------------------------------------------------------------------------
/6_album/album/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/6_album/album/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "album",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "axios": "^1.5.0",
14 | "react": "^18.2.0",
15 | "react-dom": "^18.2.0"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^18.2.15",
19 | "@types/react-dom": "^18.2.7",
20 | "@vitejs/plugin-react": "^4.0.3",
21 | "eslint": "^8.45.0",
22 | "eslint-plugin-react": "^7.32.2",
23 | "eslint-plugin-react-hooks": "^4.6.0",
24 | "eslint-plugin-react-refresh": "^0.4.3",
25 | "vite": "^4.4.5"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/6_album/album/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/6_album/album/src/App.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matheusbattisti/projetos_react/992dfa03ff6f17b6d328471db595404494c26f7a/6_album/album/src/App.css
--------------------------------------------------------------------------------
/6_album/album/src/components/Foto.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const Foto = ({ dados, setFotoAmpliada }) => {
4 | return (
5 | setFotoAmpliada(dados)}>
6 |

7 |
8 | );
9 | };
10 |
11 | export default Foto;
12 |
--------------------------------------------------------------------------------
/6_album/album/src/components/FotoAmpliada.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const FotoAmpliada = ({ foto, setFotoAmpliada }) => {
4 | return (
5 | setFotoAmpliada(null)}
8 | >
9 |
10 |

11 |
12 |
13 | );
14 | };
15 |
16 | export default FotoAmpliada;
17 |
--------------------------------------------------------------------------------
/6_album/album/src/components/FotoList.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Foto from "./Foto";
3 |
4 | const FotoList = ({ fotos, setFotoAmpliada }) => {
5 | return (
6 |
7 | {fotos.map((foto) => (
8 |
9 | ))}
10 |
11 | );
12 | };
13 |
14 | export default FotoList;
15 |
--------------------------------------------------------------------------------
/6_album/album/src/components/SearchBar.jsx:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 |
3 | const SearchBar = ({ setQuery, setCategoria, setActivateSearch }) => {
4 | const [localQuery, setLocalQuery] = useState("");
5 | const categorias = [
6 | "Natureza",
7 | "Pessoas",
8 | "Tecnologia",
9 | "Animais",
10 | "Esportes",
11 | ];
12 |
13 | return (
14 |
15 | setLocalQuery(e.target.value)}
19 | placeholder="Pesquisar fotos..."
20 | />
21 |
29 |
42 |
43 | );
44 | };
45 |
46 | export default SearchBar;
47 |
--------------------------------------------------------------------------------
/6_album/album/src/index.css:
--------------------------------------------------------------------------------
1 | /* Container geral */
2 | .container {
3 | margin: 20px auto;
4 | width: 80%;
5 | text-align: center;
6 | }
7 |
8 | /* Estilo da barra de pesquisa */
9 | .search-bar {
10 | display: flex;
11 | justify-content: center;
12 | margin-bottom: 20px;
13 | }
14 |
15 | .search-bar input {
16 | width: 300px;
17 | padding: 10px;
18 | margin-right: 10px;
19 | }
20 |
21 | .search-bar button {
22 | padding: 11px 20px;
23 | }
24 |
25 | .search-bar select {
26 | padding: 10px;
27 | margin-left: 10px;
28 | }
29 |
30 | /* Estilo para a lista de fotos */
31 | .album {
32 | display: grid;
33 | grid-template-columns: repeat(4, 1fr);
34 | gap: 16px;
35 | }
36 |
37 | .foto img {
38 | width: 100%;
39 | height: 100%;
40 | max-height: 400px;
41 | border-radius: 8px;
42 | cursor: pointer;
43 | }
44 |
45 | /* Estilo para a foto ampliada */
46 | .foto-ampliada-backdrop {
47 | position: fixed;
48 | top: 0;
49 | left: 0;
50 | width: 100%;
51 | height: 100%;
52 | background: rgba(0, 0, 0, 0.8);
53 | display: flex;
54 | justify-content: center;
55 | align-items: center;
56 | }
57 |
58 | .foto-ampliada-container {
59 | max-width: 90%;
60 | max-height: 90%;
61 | }
62 |
63 | .foto-ampliada-container img {
64 | max-width: 45%;
65 | max-height: 100%;
66 | border-radius: 8px;
67 | }
68 |
--------------------------------------------------------------------------------
/6_album/album/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.jsx'
4 | import './index.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root')).render(
7 |
8 |
9 | ,
10 | )
11 |
--------------------------------------------------------------------------------
/6_album/album/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/7_markdown_viewer/markdownviewer/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: { browser: true, es2020: true },
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:react/recommended',
7 | 'plugin:react/jsx-runtime',
8 | 'plugin:react-hooks/recommended',
9 | ],
10 | ignorePatterns: ['dist', '.eslintrc.cjs'],
11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
12 | settings: { react: { version: '18.2' } },
13 | plugins: ['react-refresh'],
14 | rules: {
15 | 'react-refresh/only-export-components': [
16 | 'warn',
17 | { allowConstantExport: true },
18 | ],
19 | },
20 | }
21 |
--------------------------------------------------------------------------------
/7_markdown_viewer/markdownviewer/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/7_markdown_viewer/markdownviewer/README.md:
--------------------------------------------------------------------------------
1 | # React + Vite
2 |
3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4 |
5 | Currently, two official plugins are available:
6 |
7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9 |
--------------------------------------------------------------------------------
/7_markdown_viewer/markdownviewer/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/7_markdown_viewer/markdownviewer/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "markdownviewer",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "marked": "^7.0.5",
14 | "react": "^18.2.0",
15 | "react-dom": "^18.2.0"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^18.2.15",
19 | "@types/react-dom": "^18.2.7",
20 | "@vitejs/plugin-react": "^4.0.3",
21 | "eslint": "^8.45.0",
22 | "eslint-plugin-react": "^7.32.2",
23 | "eslint-plugin-react-hooks": "^4.6.0",
24 | "eslint-plugin-react-refresh": "^0.4.3",
25 | "vite": "^4.4.5"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/7_markdown_viewer/markdownviewer/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/7_markdown_viewer/markdownviewer/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | max-width: 1280px;
3 | margin: 0 auto;
4 | padding: 2rem;
5 | text-align: center;
6 | }
7 |
8 | .logo {
9 | height: 6em;
10 | padding: 1.5em;
11 | will-change: filter;
12 | transition: filter 300ms;
13 | }
14 | .logo:hover {
15 | filter: drop-shadow(0 0 2em #646cffaa);
16 | }
17 | .logo.react:hover {
18 | filter: drop-shadow(0 0 2em #61dafbaa);
19 | }
20 |
21 | @keyframes logo-spin {
22 | from {
23 | transform: rotate(0deg);
24 | }
25 | to {
26 | transform: rotate(360deg);
27 | }
28 | }
29 |
30 | @media (prefers-reduced-motion: no-preference) {
31 | a:nth-of-type(2) .logo {
32 | animation: logo-spin infinite 20s linear;
33 | }
34 | }
35 |
36 | .card {
37 | padding: 2em;
38 | }
39 |
40 | .read-the-docs {
41 | color: #888;
42 | }
43 |
--------------------------------------------------------------------------------
/7_markdown_viewer/markdownviewer/src/App.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useRef } from "react";
2 | import { marked } from "marked";
3 | import Toolbar from "./components/Toolbar";
4 |
5 | const App = () => {
6 | const [text, setText] = useState(
7 | localStorage.getItem("markdownText") || "# Hello, Markdown!"
8 | );
9 | const textAreaRef = useRef(null);
10 |
11 | useEffect(() => {
12 | localStorage.setItem("markdownText", text);
13 | }, [text]);
14 |
15 | const insertText = (before, after) => {
16 | const textArea = textAreaRef.current;
17 | const start = textArea.selectionStart;
18 | const end = textArea.selectionEnd;
19 | const previousText = textArea.value;
20 | const beforeText = previousText.substring(0, start);
21 | const selectedText = previousText.substring(start, end);
22 | const afterText = previousText.substring(end);
23 |
24 | const newText = `${beforeText}${before}${selectedText}${after}${afterText}`;
25 | setText(newText);
26 | textArea.focus();
27 | };
28 |
29 | const renderText = () => {
30 | return { __html: marked(text) };
31 | };
32 |
33 | return (
34 |
35 |
36 |
43 | );
44 | };
45 |
46 | export default App;
47 |
--------------------------------------------------------------------------------
/7_markdown_viewer/markdownviewer/src/components/Toolbar.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const Toolbar = ({ insertText }) => {
4 | return (
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | );
16 | };
17 |
18 | export default Toolbar;
19 |
--------------------------------------------------------------------------------
/7_markdown_viewer/markdownviewer/src/index.css:
--------------------------------------------------------------------------------
1 | /* Estilos para o App */
2 | .app-container {
3 | display: flex;
4 | flex-direction: column;
5 | align-items: center;
6 | max-width: 60%;
7 | margin: 50px auto;
8 | }
9 |
10 | /* Estilos para a barra de ferramentas */
11 | .toolbar {
12 | margin-bottom: 20px;
13 | }
14 |
15 | .toolbar button {
16 | margin-right: 5px;
17 | padding: 10px 20px;
18 | }
19 |
20 | /* Estilos para a área de texto e visualização */
21 | textarea {
22 | width: 100%;
23 | height: 300px;
24 | }
25 |
26 | div[dangerouslySetInnerHTML] {
27 | border: 1px solid #ccc;
28 | padding: 20px;
29 | width: 100%;
30 | height: auto;
31 | overflow-y: auto;
32 | }
33 |
--------------------------------------------------------------------------------
/7_markdown_viewer/markdownviewer/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.jsx'
4 | import './index.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root')).render(
7 |
8 |
9 | ,
10 | )
11 |
--------------------------------------------------------------------------------
/7_markdown_viewer/markdownviewer/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/8_relogio_mundial/relogiomundial/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: { browser: true, es2020: true },
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:react/recommended',
7 | 'plugin:react/jsx-runtime',
8 | 'plugin:react-hooks/recommended',
9 | ],
10 | ignorePatterns: ['dist', '.eslintrc.cjs'],
11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
12 | settings: { react: { version: '18.2' } },
13 | plugins: ['react-refresh'],
14 | rules: {
15 | 'react-refresh/only-export-components': [
16 | 'warn',
17 | { allowConstantExport: true },
18 | ],
19 | },
20 | }
21 |
--------------------------------------------------------------------------------
/8_relogio_mundial/relogiomundial/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/8_relogio_mundial/relogiomundial/README.md:
--------------------------------------------------------------------------------
1 | # React + Vite
2 |
3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4 |
5 | Currently, two official plugins are available:
6 |
7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9 |
--------------------------------------------------------------------------------
/8_relogio_mundial/relogiomundial/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/8_relogio_mundial/relogiomundial/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "relogiomundial",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "react": "^18.2.0",
14 | "react-dom": "^18.2.0"
15 | },
16 | "devDependencies": {
17 | "@types/react": "^18.2.15",
18 | "@types/react-dom": "^18.2.7",
19 | "@vitejs/plugin-react": "^4.0.3",
20 | "eslint": "^8.45.0",
21 | "eslint-plugin-react": "^7.32.2",
22 | "eslint-plugin-react-hooks": "^4.6.0",
23 | "eslint-plugin-react-refresh": "^0.4.3",
24 | "vite": "^4.4.5"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/8_relogio_mundial/relogiomundial/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/8_relogio_mundial/relogiomundial/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | max-width: 1280px;
3 | margin: 0 auto;
4 | padding: 2rem;
5 | text-align: center;
6 | }
7 |
8 | .logo {
9 | height: 6em;
10 | padding: 1.5em;
11 | will-change: filter;
12 | transition: filter 300ms;
13 | }
14 | .logo:hover {
15 | filter: drop-shadow(0 0 2em #646cffaa);
16 | }
17 | .logo.react:hover {
18 | filter: drop-shadow(0 0 2em #61dafbaa);
19 | }
20 |
21 | @keyframes logo-spin {
22 | from {
23 | transform: rotate(0deg);
24 | }
25 | to {
26 | transform: rotate(360deg);
27 | }
28 | }
29 |
30 | @media (prefers-reduced-motion: no-preference) {
31 | a:nth-of-type(2) .logo {
32 | animation: logo-spin infinite 20s linear;
33 | }
34 | }
35 |
36 | .card {
37 | padding: 2em;
38 | }
39 |
40 | .read-the-docs {
41 | color: #888;
42 | }
43 |
--------------------------------------------------------------------------------
/8_relogio_mundial/relogiomundial/src/App.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import TimeZoneClock from "./components/TimeZoneClock";
3 |
4 | const fusosHorarios = [
5 | "UTC",
6 | "GMT",
7 | "America/New_York",
8 | "America/Chicago",
9 | "America/Denver",
10 | "America/Los_Angeles",
11 | "Europe/London",
12 | "Europe/Berlin",
13 | "Asia/Tokyo",
14 | ];
15 |
16 | function App() {
17 | const fusoHorarioLocal = Intl.DateTimeFormat().resolvedOptions().timeZone;
18 | const [fusosHorariosSelecionados, setFusosHorariosSelecionados] = useState([
19 | fusoHorarioLocal,
20 | ]);
21 |
22 | const adicionarFusoHorario = (e) => {
23 | const novoFuso = e.target.value;
24 | if (!fusosHorariosSelecionados.includes(novoFuso)) {
25 | setFusosHorariosSelecionados([...fusosHorariosSelecionados, novoFuso]);
26 | }
27 | };
28 |
29 | return (
30 |
31 |
Relógio Mundial
32 |
42 |
43 |
44 | {fusosHorariosSelecionados.map((fuso) => (
45 |
46 | ))}
47 |
48 |
49 | );
50 | }
51 |
52 | export default App;
53 |
--------------------------------------------------------------------------------
/8_relogio_mundial/relogiomundial/src/components/TimeZoneClock.jsx:
--------------------------------------------------------------------------------
1 | // TimeZoneClock.js
2 | import React, { useState, useEffect } from "react";
3 |
4 | function TimeZoneClock({ timeZone }) {
5 | const [time, setTime] = useState("");
6 |
7 | useEffect(() => {
8 | const intervalId = setInterval(() => {
9 | const date = new Date();
10 | const options = {
11 | timeZone,
12 | hour: "2-digit",
13 | minute: "2-digit",
14 | second: "2-digit",
15 | };
16 | const timeString = date.toLocaleTimeString("en-US", options);
17 | setTime(timeString);
18 | }, 1000);
19 |
20 | return () => clearInterval(intervalId);
21 | }, [timeZone]);
22 |
23 | return (
24 |
25 |
{timeZone}
26 | {time}
27 |
28 | );
29 | }
30 |
31 | export default TimeZoneClock;
32 |
--------------------------------------------------------------------------------
/8_relogio_mundial/relogiomundial/src/index.css:
--------------------------------------------------------------------------------
1 | /* Estilos globais para a aplicação */
2 | body {
3 | font-family: Arial, sans-serif;
4 | margin: 0;
5 | padding: 0;
6 | background-color: #f4f4f4;
7 | }
8 |
9 | /* Container principal */
10 | div {
11 | text-align: center;
12 | }
13 |
14 | /* Cabeçalho */
15 | h1 {
16 | background-color: #6200ea;
17 | color: white;
18 | margin: 0;
19 | padding: 1rem;
20 | }
21 |
22 | /* Dropdown de fusos horários */
23 | select {
24 | margin: 1rem;
25 | padding: 0.5rem;
26 | }
27 |
28 | /* Relógios individuais */
29 | .TimeZoneClock {
30 | display: inline-block;
31 | margin: 1rem;
32 | background-color: #fff;
33 | border-radius: 0.5rem;
34 | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
35 | padding: 1rem;
36 | }
37 |
--------------------------------------------------------------------------------
/8_relogio_mundial/relogiomundial/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.jsx'
4 | import './index.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root')).render(
7 |
8 |
9 | ,
10 | )
11 |
--------------------------------------------------------------------------------
/8_relogio_mundial/relogiomundial/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/9_jogo_da_velha_com_ia/jogodavelhaia/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: { browser: true, es2020: true },
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:react/recommended',
7 | 'plugin:react/jsx-runtime',
8 | 'plugin:react-hooks/recommended',
9 | ],
10 | ignorePatterns: ['dist', '.eslintrc.cjs'],
11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
12 | settings: { react: { version: '18.2' } },
13 | plugins: ['react-refresh'],
14 | rules: {
15 | 'react-refresh/only-export-components': [
16 | 'warn',
17 | { allowConstantExport: true },
18 | ],
19 | },
20 | }
21 |
--------------------------------------------------------------------------------
/9_jogo_da_velha_com_ia/jogodavelhaia/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/9_jogo_da_velha_com_ia/jogodavelhaia/README.md:
--------------------------------------------------------------------------------
1 | # React + Vite
2 |
3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4 |
5 | Currently, two official plugins are available:
6 |
7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9 |
--------------------------------------------------------------------------------
/9_jogo_da_velha_com_ia/jogodavelhaia/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/9_jogo_da_velha_com_ia/jogodavelhaia/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jogodavelhaia",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "react": "^18.2.0",
14 | "react-dom": "^18.2.0"
15 | },
16 | "devDependencies": {
17 | "@types/react": "^18.2.15",
18 | "@types/react-dom": "^18.2.7",
19 | "@vitejs/plugin-react": "^4.0.3",
20 | "eslint": "^8.45.0",
21 | "eslint-plugin-react": "^7.32.2",
22 | "eslint-plugin-react-hooks": "^4.6.0",
23 | "eslint-plugin-react-refresh": "^0.4.3",
24 | "vite": "^4.4.5"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/9_jogo_da_velha_com_ia/jogodavelhaia/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/9_jogo_da_velha_com_ia/jogodavelhaia/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | max-width: 1280px;
3 | margin: 0 auto;
4 | padding: 2rem;
5 | text-align: center;
6 | }
7 |
8 | .logo {
9 | height: 6em;
10 | padding: 1.5em;
11 | will-change: filter;
12 | transition: filter 300ms;
13 | }
14 | .logo:hover {
15 | filter: drop-shadow(0 0 2em #646cffaa);
16 | }
17 | .logo.react:hover {
18 | filter: drop-shadow(0 0 2em #61dafbaa);
19 | }
20 |
21 | @keyframes logo-spin {
22 | from {
23 | transform: rotate(0deg);
24 | }
25 | to {
26 | transform: rotate(360deg);
27 | }
28 | }
29 |
30 | @media (prefers-reduced-motion: no-preference) {
31 | a:nth-of-type(2) .logo {
32 | animation: logo-spin infinite 20s linear;
33 | }
34 | }
35 |
36 | .card {
37 | padding: 2em;
38 | }
39 |
40 | .read-the-docs {
41 | color: #888;
42 | }
43 |
--------------------------------------------------------------------------------
/9_jogo_da_velha_com_ia/jogodavelhaia/src/App.jsx:
--------------------------------------------------------------------------------
1 | import Board from "./components/Board";
2 |
3 | function App() {
4 | return (
5 |
6 |
Jogo da Velha
7 |
8 |
9 | );
10 | }
11 |
12 | export default App;
13 |
--------------------------------------------------------------------------------
/9_jogo_da_velha_com_ia/jogodavelhaia/src/components/Square.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | function Square({ value, onClick }) {
4 | return (
5 |
8 | );
9 | }
10 |
11 | export default Square;
12 |
--------------------------------------------------------------------------------
/9_jogo_da_velha_com_ia/jogodavelhaia/src/index.css:
--------------------------------------------------------------------------------
1 | /* Estilos globais para centralizar todo o conteúdo */
2 | body,
3 | html {
4 | height: 100%;
5 | margin: 0;
6 | display: flex;
7 | justify-content: center;
8 | align-items: center;
9 | background-color: #f4f4f4;
10 | font-family: Helvetica;
11 | text-align: center;
12 | }
13 |
14 | /* Estilo para cada quadrado */
15 | .square {
16 | width: 100px;
17 | height: 100px;
18 | background-color: #ddd;
19 | border: 1px solid #ccc;
20 | font-size: 32px;
21 | font-weight: bold;
22 | text-align: center;
23 | vertical-align: middle;
24 | cursor: pointer;
25 | }
26 |
27 | /* Estilo para o vencedor */
28 | .winner {
29 | background-color: #ffcc00;
30 | }
31 |
32 | /* Estilo para o status do jogo */
33 | .status {
34 | margin: 20px 0;
35 | text-align: center;
36 | font-size: 24px;
37 | color: #333;
38 | }
39 |
40 | /* Estilo para o botão de reiniciar */
41 | .reset-button {
42 | margin-top: 20px;
43 | padding: 10px 20px;
44 | font-size: 18px;
45 | background-color: #007bff;
46 | color: #fff;
47 | border: none;
48 | border-radius: 4px;
49 | cursor: pointer;
50 | }
51 |
52 | /* Estilo para o botão de reiniciar no hover */
53 | .reset-button:hover {
54 | background-color: #0056b3;
55 | }
56 |
--------------------------------------------------------------------------------
/9_jogo_da_velha_com_ia/jogodavelhaia/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.jsx'
4 | import './index.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root')).render(
7 |
8 |
9 | ,
10 | )
11 |
--------------------------------------------------------------------------------
/9_jogo_da_velha_com_ia/jogodavelhaia/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------