├── .editorconfig
├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
├── android-chrome-192x192.png
├── android-chrome-512x512.png
├── apple-touch-icon.png
├── favicon-16x16.png
├── favicon-32x32.png
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
├── sandbox.config.json
├── src
├── components
│ ├── application.tsx
│ ├── controls.jsx
│ └── name-badge.tsx
├── global.d.ts
├── index.css
├── index.tsx
├── lib
│ └── sleep.ts
└── react-app-env.d.ts
├── tailwind.config.js
└── tsconfig.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = lf
5 | insert_final_newline = true
6 |
7 | [*.{js,ts,jsx,tsx}]
8 | indent_style = space
9 | indent_size = 2
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 |
5 | /node_modules
6 | /.pnp
7 | .pnp.js
8 |
9 | # testing
10 |
11 | /coverage
12 |
13 | # production
14 |
15 | /build
16 |
17 | # misc
18 |
19 | .DS_Store
20 | .env.local
21 | .env.development.local
22 | .env.test.local
23 | .env.production.local
24 |
25 | npm-debug.log*
26 | yarn-debug.log*
27 | yarn-error.log\*
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React and TypeScript Example
2 |
3 | This is an exmaple application from Steve's React and TypeScript course.
4 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "name-badge",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@reduxjs/toolkit": "^1.9.0",
7 | "clsx": "^1.2.1",
8 | "lodash.shuffle": "^4.2.0",
9 | "prop-types": "^15.8.1",
10 | "react": "^18.2.0",
11 | "react-dom": "^18.2.0",
12 | "react-redux": "^8.0.5",
13 | "react-scripts": "^5.0.1",
14 | "uuid": "^9.0.0"
15 | },
16 | "scripts": {
17 | "start": "react-scripts start",
18 | "build": "react-scripts build",
19 | "test": "react-scripts test",
20 | "eject": "react-scripts eject"
21 | },
22 | "eslintConfig": {
23 | "extends": [
24 | "react-app",
25 | "react-app/jest"
26 | ]
27 | },
28 | "browserslist": {
29 | "production": [
30 | ">0.2%",
31 | "not dead",
32 | "not op_mini all"
33 | ],
34 | "development": [
35 | "last 1 chrome version",
36 | "last 1 firefox version",
37 | "last 1 safari version"
38 | ]
39 | },
40 | "devDependencies": {
41 | "@testing-library/jest-dom": "^5.16.5",
42 | "@testing-library/react": "^13.4.0",
43 | "@testing-library/user-event": "^14.4.3",
44 | "@types/jest": "^29.2.2",
45 | "@types/node": "^18.11.9",
46 | "@types/react": "^18.0.24",
47 | "@types/react-dom": "^18.0.8",
48 | "autoprefixer": "^10.4.13",
49 | "postcss": "^8.4.18",
50 | "prettier": "^2.7.1",
51 | "prettier-plugin-tailwindcss": "^0.1.13",
52 | "tailwindcss": "^3.2.2",
53 | "typescript": "^4.8.4"
54 | },
55 | "prettier": {
56 | "printWidth": 80,
57 | "tabWidth": 2,
58 | "useTabs": false,
59 | "semi": true,
60 | "singleQuote": true,
61 | "trailingComma": "all",
62 | "bracketSpacing": true,
63 | "jsxBracketSameLine": false,
64 | "fluid": false
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/public/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stevekinney/name-badges/d8cc8537659bdcf69a862d16099b88b76b65adf3/public/android-chrome-192x192.png
--------------------------------------------------------------------------------
/public/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stevekinney/name-badges/d8cc8537659bdcf69a862d16099b88b76b65adf3/public/android-chrome-512x512.png
--------------------------------------------------------------------------------
/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stevekinney/name-badges/d8cc8537659bdcf69a862d16099b88b76b65adf3/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stevekinney/name-badges/d8cc8537659bdcf69a862d16099b88b76b65adf3/public/favicon-16x16.png
--------------------------------------------------------------------------------
/public/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stevekinney/name-badges/d8cc8537659bdcf69a862d16099b88b76b65adf3/public/favicon-32x32.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stevekinney/name-badges/d8cc8537659bdcf69a862d16099b88b76b65adf3/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | TypeScript Example
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stevekinney/name-badges/d8cc8537659bdcf69a862d16099b88b76b65adf3/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stevekinney/name-badges/d8cc8537659bdcf69a862d16099b88b76b65adf3/public/logo512.png
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "An Example Application",
3 | "short_name": "Example",
4 | "icons": [
5 | {
6 | "src": "/android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "/android-chrome-512x512.png",
12 | "sizes": "512x512",
13 | "type": "image/png"
14 | }
15 | ],
16 | "theme_color": "#ffffff",
17 | "background_color": "#ffffff",
18 | "display": "standalone"
19 | }
20 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": false,
4 | "view": "browser"
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/application.tsx:
--------------------------------------------------------------------------------
1 | // import ControlPanel from './controls';
2 | import NameBadge from './name-badge';
3 |
4 | const Application = () => (
5 |
6 |
7 |
8 | );
9 |
10 | export default Application;
11 |
--------------------------------------------------------------------------------
/src/components/controls.jsx:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 |
3 | const ControlPanel = ({ name, onChange }) => {
4 | return (
5 |
20 | );
21 | };
22 |
23 | ControlPanel.propTypes = {
24 | name: PropTypes.string,
25 | onChange: PropTypes.func,
26 | };
27 |
28 | export default ControlPanel;
29 |
--------------------------------------------------------------------------------
/src/components/name-badge.tsx:
--------------------------------------------------------------------------------
1 | const NameBadge = () => {
2 | return (
3 |
4 |
5 | HELLO
6 | My name is…
7 |
8 |
11 |
12 |
13 | );
14 | };
15 |
16 | export default NameBadge;
17 |
--------------------------------------------------------------------------------
/src/global.d.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stevekinney/name-badges/d8cc8537659bdcf69a862d16099b88b76b65adf3/src/global.d.ts
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | *,
6 | html,
7 | body {
8 | @apply box-border;
9 | }
10 |
11 | html,
12 | body {
13 | @apply m-0 h-screen w-screen p-0;
14 | }
15 |
16 | #root {
17 | @apply h-screen w-screen;
18 | }
19 |
20 | h1,
21 | h2,
22 | h3,
23 | h4,
24 | h5,
25 | h6 {
26 | @apply font-bold leading-tight first:mt-0;
27 | }
28 |
29 | h1 {
30 | @apply text-4xl leading-tight;
31 | }
32 |
33 | h2 {
34 | @apply text-3xl;
35 | }
36 |
37 | h3 {
38 | @apply text-2xl;
39 | }
40 |
41 | h4 {
42 | @apply text-xl;
43 | }
44 |
45 | h5 {
46 | @apply text-lg;
47 | }
48 |
49 | h6 {
50 | @apply text-base;
51 | }
52 |
53 | p,
54 | ul,
55 | ol,
56 | dl {
57 | @apply leading-relaxed;
58 | }
59 |
60 | input {
61 | @apply rounded-sm border-2 border-primary-700 bg-primary-100 p-2 placeholder-primary-400 accent-primary-600 shadow-sm transition-all ease-in invalid:border-red-800 invalid:bg-red-200 out-of-range:border-red-800 out-of-range:bg-red-200 hover:bg-primary-200 hover:accent-primary-700 focus:bg-primary-50 focus:outline-none disabled:border-slate-500 disabled:bg-slate-100 disabled:placeholder-slate-400;
62 | }
63 |
64 | button,
65 | button[type='button'],
66 | button[type='reset'],
67 | button[type='submit'] input[type='button'],
68 | input[type='submit'],
69 | input[type='reset'] {
70 | @apply inline-flex items-center justify-center border-2 border-primary-700 bg-primary-100 px-4 py-2 transition-colors ease-in hover:bg-primary-200 active:bg-primary-300;
71 | }
72 |
73 | input[type='checkbox'],
74 | input[type='radio'] {
75 | @apply hover:accent-primary-700;
76 | }
77 |
78 | input[type='range'] {
79 | @apply h-2 w-full cursor-pointer appearance-none rounded-lg bg-primary-100;
80 | }
81 |
82 | input[type='submit'],
83 | button[type='submit'] {
84 | @apply bg-primary-500 font-semibold text-white hover:bg-primary-600 active:bg-primary-700;
85 | }
86 |
87 | input[type='color'] {
88 | @apply h-12 p-1;
89 | }
90 |
91 | input[type='file']::-webkit-file-upload-button {
92 | @apply placeholder-red-400 accent-red-800;
93 | }
94 |
95 | input[type='date'],
96 | input[type='datetime'],
97 | input[type='datetime-local'],
98 | input[type='month'],
99 | input[type='week'],
100 | input[type='time'] {
101 | @apply text-primary-900;
102 | }
103 |
104 | label {
105 | @apply font-normal;
106 | }
107 |
108 | input:checked + label {
109 | @apply pl-2 font-semibold text-primary-900 transition-colors hover:text-primary-800;
110 | }
111 |
112 | select {
113 | @apply block w-full rounded border-2 border-purple-700 px-4 py-2 pr-8 shadow hover:bg-primary-200 hover:accent-primary-700 focus:bg-primary-50 focus:outline-none disabled:border-slate-500 disabled:bg-slate-100 disabled:placeholder-slate-400;
114 | }
115 |
116 | .application {
117 | @apply flex h-full flex-col place-content-center items-center gap-8 bg-slate-600;
118 | }
119 |
120 | .badge {
121 | @apply flex h-96 w-[600px] flex-col rounded-xl border-2 border-slate-900 bg-red-700 shadow-lg;
122 | }
123 |
124 | .badge-header {
125 | @apply rounded-t-xl py-3 text-center font-black uppercase text-white;
126 | }
127 |
128 | .badge-body {
129 | @apply flex flex-grow place-content-center items-center bg-white;
130 | }
131 |
132 | .badge-name {
133 | @apply font-serif text-6xl;
134 | }
135 |
136 | .badge-footer {
137 | @apply h-11 rounded-b-xl bg-red-700;
138 | }
139 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom/client';
3 | import Application from './components/application';
4 |
5 | import './index.css';
6 |
7 | const root = ReactDOM.createRoot(
8 | document.getElementById('root') as HTMLElement,
9 | );
10 |
11 | root.render(
12 |
13 |
14 | ,
15 | );
16 |
--------------------------------------------------------------------------------
/src/lib/sleep.ts:
--------------------------------------------------------------------------------
1 | const defaultDuration = 500;
2 |
3 | export const sleep = (duration = defaultDuration): Promise => {
4 | return new Promise((resolve) => {
5 | setTimeout(() => {
6 | resolve(undefined);
7 | }, duration);
8 | });
9 | };
10 |
11 | export const block = (duration = defaultDuration) => {
12 | const start = performance.now();
13 | while (performance.now() < start + duration) {}
14 | };
15 |
16 | export const makeExpensive = any>(
17 | fn: T,
18 | duration = defaultDuration,
19 | ): ((...args: Parameters) => ReturnType) => {
20 | return (...args: Parameters): ReturnType => {
21 | block(duration);
22 | return fn(...args);
23 | };
24 | };
25 |
--------------------------------------------------------------------------------
/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 |
3 | const colors = require('tailwindcss/colors');
4 |
5 | module.exports = {
6 | content: ['./src/**/*.{js,jsx,ts,tsx}'],
7 | theme: {
8 | extend: {
9 | colors: { ...colors, primary: colors.slate },
10 | },
11 | },
12 | plugins: [],
13 | };
14 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "strict": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "noFallthroughCasesInSwitch": true,
16 | "module": "esnext",
17 | "moduleResolution": "node",
18 | "resolveJsonModule": true,
19 | "isolatedModules": true,
20 | "noEmit": true,
21 | "jsx": "react-jsx"
22 | },
23 | "include": [
24 | "src"
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------