├── .gitignore
├── base-projects
├── vite-base-js
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ └── main.jsx
│ └── vite.config.js
└── vite-base-ts
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ ├── App.tsx
│ ├── main.tsx
│ └── vite-env.d.ts
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
├── ch02
├── dark-mode-dedicated
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ └── main.jsx
│ └── vite.config.js
├── dark-mode-selector
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ └── main.jsx
│ └── vite.config.js
├── dark-mode-typed
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── App.tsx
│ │ ├── main.tsx
│ │ └── vite-env.d.ts
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
├── dark-mode
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ └── main.jsx
│ └── vite.config.js
├── radio-complex
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ ├── RadioGroup.jsx
│ │ └── main.jsx
│ └── vite.config.js
├── radio-composite
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ ├── main.jsx
│ │ └── radiogroup
│ │ │ ├── Details.jsx
│ │ │ ├── Option.jsx
│ │ │ ├── RadioGroup.jsx
│ │ │ ├── contexts.js
│ │ │ └── index.js
│ └── vite.config.js
├── radio-simple
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ ├── RadioGroup.jsx
│ │ └── main.jsx
│ └── vite.config.js
├── radio-summary
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ ├── main.jsx
│ │ └── radiogroup
│ │ │ ├── Details.jsx
│ │ │ ├── Option.jsx
│ │ │ ├── RadioGroup.jsx
│ │ │ ├── contexts.js
│ │ │ ├── index.js
│ │ │ └── useContextValue.js
│ └── vite.config.js
├── task-summary
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ ├── CompactTaskManager.jsx
│ │ ├── LongTaskManager.jsx
│ │ ├── main.jsx
│ │ ├── useNewTask.js
│ │ └── useTaskList.js
│ └── vite.config.js
└── user-summary
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ ├── App.jsx
│ ├── CompactUserProfile.jsx
│ ├── LongUserProfile.jsx
│ ├── UserDataForm.jsx
│ ├── UserDetails.jsx
│ ├── UserPreferences.jsx
│ ├── main.jsx
│ ├── useAPI.js
│ └── useUserProfile.js
│ └── vite.config.js
├── ch03
├── employees
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ └── main.jsx
│ └── vite.config.js
├── rerender
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ ├── NoRerenderWithPropsChange.jsx
│ │ ├── RerenderWithoutPropsChange.jsx
│ │ ├── Rerenderable.jsx
│ │ └── main.jsx
│ └── vite.config.js
├── strict-mode
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ └── main.jsx
│ └── vite.config.js
├── todo-delete
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ └── main.jsx
│ └── vite.config.js
├── todo-fixed
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ └── main.jsx
│ └── vite.config.js
├── todo-memo
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ └── main.jsx
│ └── vite.config.js
├── todo-simple
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ └── main.jsx
│ └── vite.config.js
└── todo-usememo
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ ├── App.jsx
│ └── main.jsx
│ └── vite.config.js
├── ch04
├── dark-mode
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ └── main.jsx
│ └── vite.config.js
└── prettier
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ ├── App.jsx
│ └── main.jsx
│ └── vite.config.js
├── ch05
├── book-review
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── App.tsx
│ │ ├── BookReview.css
│ │ ├── BookReview.tsx
│ │ ├── Rating.css
│ │ ├── Rating.tsx
│ │ ├── index.css
│ │ ├── main.tsx
│ │ └── vite-env.d.ts
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
├── employee
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── App.tsx
│ │ ├── EmployeeCard.tsx
│ │ ├── app.css
│ │ ├── employee.css
│ │ ├── main.tsx
│ │ └── vite-env.d.ts
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
├── employees
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── App.tsx
│ │ ├── EmployeeCard.tsx
│ │ ├── app.css
│ │ ├── employee.css
│ │ ├── main.tsx
│ │ └── vite-env.d.ts
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
└── product-card
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ ├── App.css
│ ├── App.tsx
│ ├── ProductCard.css
│ ├── ProductCard.tsx
│ ├── index.css
│ ├── main.tsx
│ └── vite-env.d.ts
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
├── ch06
├── appointment
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── App.tsx
│ │ ├── AppointmentResponse.tsx
│ │ ├── index.css
│ │ ├── main.tsx
│ │ └── vite-env.d.ts
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
├── dark-mode
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── App.tsx
│ │ ├── main.tsx
│ │ └── vite-env.d.ts
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
├── paginable
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── App.tsx
│ │ ├── EmployeeCard.tsx
│ │ ├── HighscoreEntry.tsx
│ │ ├── Paginable.tsx
│ │ ├── app.css
│ │ ├── employee.css
│ │ ├── highscore.css
│ │ ├── main.tsx
│ │ ├── paginable.css
│ │ ├── types.ts
│ │ └── vite-env.d.ts
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
├── playlist
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── App.tsx
│ │ ├── Playlist.tsx
│ │ ├── PlaylistItem.tsx
│ │ ├── main.tsx
│ │ ├── playlist.css
│ │ ├── types.ts
│ │ ├── useReorderable.ts
│ │ └── vite-env.d.ts
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
├── tag-form
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── App.tsx
│ │ ├── TagForm.tsx
│ │ ├── main.tsx
│ │ └── vite-env.d.ts
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
└── use-reorderable
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ ├── App.tsx
│ ├── Playlist.tsx
│ ├── main.tsx
│ ├── playlist.css
│ ├── useReorderable.ts
│ └── vite-env.d.ts
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
├── ch07
├── classnames
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ ├── Button.jsx
│ │ ├── app.css
│ │ ├── button.css
│ │ └── main.jsx
│ └── vite.config.js
├── cssmodules
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ ├── Button.jsx
│ │ ├── app.module.css
│ │ ├── button.module.css
│ │ └── main.jsx
│ └── vite.config.js
├── inline
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ ├── Button.jsx
│ │ └── main.jsx
│ └── vite.config.js
├── styled
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ ├── Button.jsx
│ │ └── main.jsx
│ └── vite.config.js
└── tailwind
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── postcss.config.js
│ ├── src
│ ├── App.jsx
│ ├── Button.jsx
│ ├── index.css
│ └── main.jsx
│ ├── tailwind.config.js
│ └── vite.config.js
├── ch08
├── context
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ ├── data
│ │ │ ├── DataContext.js
│ │ │ ├── DataProvider.jsx
│ │ │ ├── index.js
│ │ │ ├── useAddThing.js
│ │ │ ├── useAllThings.js
│ │ │ ├── useCurrentThing.js
│ │ │ ├── useData.js
│ │ │ └── useThing.js
│ │ ├── main.jsx
│ │ └── things
│ │ │ ├── AddAThing.jsx
│ │ │ ├── AllThings.jsx
│ │ │ ├── Button.jsx
│ │ │ ├── Grid.jsx
│ │ │ ├── Progress.jsx
│ │ │ ├── RemoveButton.jsx
│ │ │ ├── SingleThing.jsx
│ │ │ ├── Thing.jsx
│ │ │ ├── ThingTitle.jsx
│ │ │ ├── Things.jsx
│ │ │ └── index.js
│ └── vite.config.js
├── reducer
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ ├── data
│ │ │ ├── DataContext.js
│ │ │ ├── DataProvider.jsx
│ │ │ ├── index.js
│ │ │ ├── useAddThing.js
│ │ │ ├── useAllThings.js
│ │ │ ├── useCurrentThing.js
│ │ │ ├── useData.js
│ │ │ └── useThing.js
│ │ ├── main.jsx
│ │ └── things
│ │ │ ├── AddAThing.jsx
│ │ │ ├── AllThings.jsx
│ │ │ ├── Button.jsx
│ │ │ ├── Grid.jsx
│ │ │ ├── Progress.jsx
│ │ │ ├── RemoveButton.jsx
│ │ │ ├── SingleThing.jsx
│ │ │ ├── Thing.jsx
│ │ │ ├── ThingTitle.jsx
│ │ │ ├── Things.jsx
│ │ │ └── index.js
│ └── vite.config.js
├── redux
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ ├── data
│ │ │ ├── DataProvider.jsx
│ │ │ ├── index.js
│ │ │ ├── store.js
│ │ │ ├── useAddThing.js
│ │ │ ├── useAllThings.js
│ │ │ ├── useCurrentThing.js
│ │ │ ├── useData.js
│ │ │ └── useThing.js
│ │ ├── main.jsx
│ │ └── things
│ │ │ ├── AddAThing.jsx
│ │ │ ├── AllThings.jsx
│ │ │ ├── Button.jsx
│ │ │ ├── Grid.jsx
│ │ │ ├── Progress.jsx
│ │ │ ├── RemoveButton.jsx
│ │ │ ├── SingleThing.jsx
│ │ │ ├── Thing.jsx
│ │ │ ├── ThingTitle.jsx
│ │ │ ├── Things.jsx
│ │ │ └── index.js
│ └── vite.config.js
├── xstate
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ ├── data
│ │ │ ├── DataContext.js
│ │ │ ├── DataProvider.jsx
│ │ │ ├── actions.js
│ │ │ ├── index.js
│ │ │ ├── machine.js
│ │ │ ├── useAddThing.js
│ │ │ ├── useAllThings.js
│ │ │ ├── useCurrentThing.js
│ │ │ ├── useData.js
│ │ │ ├── useSend.js
│ │ │ ├── useThatThing.js
│ │ │ └── useThisThing.js
│ │ ├── main.jsx
│ │ └── things
│ │ │ ├── AddAThing.jsx
│ │ │ ├── AllThings.jsx
│ │ │ ├── Button.jsx
│ │ │ ├── Grid.jsx
│ │ │ ├── Progress.jsx
│ │ │ ├── RemoveButton.jsx
│ │ │ ├── SingleThing.jsx
│ │ │ ├── Thing.jsx
│ │ │ ├── ThingTitle.jsx
│ │ │ ├── Things.jsx
│ │ │ └── index.js
│ └── vite.config.js
└── zustand
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ ├── App.jsx
│ ├── data
│ │ ├── DataProvider.jsx
│ │ ├── index.js
│ │ ├── useAddThing.js
│ │ ├── useAllThings.js
│ │ ├── useCurrentThing.js
│ │ ├── useData.js
│ │ └── useThing.js
│ ├── main.jsx
│ └── things
│ │ ├── AddAThing.jsx
│ │ ├── AllThings.jsx
│ │ ├── Button.jsx
│ │ ├── Grid.jsx
│ │ ├── Progress.jsx
│ │ ├── RemoveButton.jsx
│ │ ├── SingleThing.jsx
│ │ ├── Thing.jsx
│ │ ├── ThingTitle.jsx
│ │ ├── Things.jsx
│ │ └── index.js
│ └── vite.config.js
├── ch09
├── better-reactive
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── public
│ │ └── mockServiceWorker.js
│ ├── src
│ │ ├── App.jsx
│ │ ├── backend
│ │ │ └── index.js
│ │ ├── data
│ │ │ ├── DataProvider.jsx
│ │ │ ├── Loader.jsx
│ │ │ ├── api
│ │ │ │ ├── api.js
│ │ │ │ ├── useAddThing.js
│ │ │ │ ├── useDoThing.js
│ │ │ │ ├── useLoginSignup.js
│ │ │ │ ├── useLogout.js
│ │ │ │ ├── useRemoveThing.js
│ │ │ │ └── useUndoThing.js
│ │ │ ├── index.js
│ │ │ ├── useAllThings.js
│ │ │ ├── useCurrent.js
│ │ │ ├── useHasCurrent.js
│ │ │ ├── useThatThing.js
│ │ │ ├── useThisThing.js
│ │ │ └── useUser.js
│ │ ├── main.jsx
│ │ └── view
│ │ │ ├── AddAThing.jsx
│ │ │ ├── AllThings.jsx
│ │ │ ├── Button.jsx
│ │ │ ├── Form.jsx
│ │ │ ├── Grid.jsx
│ │ │ ├── Login.jsx
│ │ │ ├── LoginSignup.jsx
│ │ │ ├── Logout.jsx
│ │ │ ├── Progress.jsx
│ │ │ ├── RemoveButton.jsx
│ │ │ ├── Signup.jsx
│ │ │ ├── SingleThing.jsx
│ │ │ ├── Thing.jsx
│ │ │ ├── ThingTitle.jsx
│ │ │ ├── Things.jsx
│ │ │ ├── View.jsx
│ │ │ └── index.js
│ └── vite.config.js
├── reactive
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── public
│ │ └── mockServiceWorker.js
│ ├── src
│ │ ├── App.jsx
│ │ ├── backend
│ │ │ └── index.js
│ │ ├── data
│ │ │ ├── DataProvider.jsx
│ │ │ ├── Loader.jsx
│ │ │ ├── api
│ │ │ │ ├── api.js
│ │ │ │ ├── useAddThing.js
│ │ │ │ ├── useDoThing.js
│ │ │ │ ├── useLoginSignup.js
│ │ │ │ ├── useLogout.js
│ │ │ │ ├── useRemoveThing.js
│ │ │ │ └── useUndoThing.js
│ │ │ ├── index.js
│ │ │ ├── useAllThings.js
│ │ │ ├── useCurrent.js
│ │ │ ├── useHasCurrent.js
│ │ │ ├── useThatThing.js
│ │ │ ├── useThisThing.js
│ │ │ └── useUser.js
│ │ ├── main.jsx
│ │ └── view
│ │ │ ├── AddAThing.jsx
│ │ │ ├── AllThings.jsx
│ │ │ ├── Button.jsx
│ │ │ ├── Form.jsx
│ │ │ ├── Grid.jsx
│ │ │ ├── Login.jsx
│ │ │ ├── LoginSignup.jsx
│ │ │ ├── Logout.jsx
│ │ │ ├── Progress.jsx
│ │ │ ├── RemoveButton.jsx
│ │ │ ├── Signup.jsx
│ │ │ ├── SingleThing.jsx
│ │ │ ├── Thing.jsx
│ │ │ ├── ThingTitle.jsx
│ │ │ ├── Things.jsx
│ │ │ ├── View.jsx
│ │ │ └── index.js
│ └── vite.config.js
└── things
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── public
│ └── mockServiceWorker.js
│ ├── src
│ ├── App.jsx
│ ├── backend
│ │ └── index.js
│ ├── data
│ │ ├── DataContext.js
│ │ ├── DataProvider.jsx
│ │ ├── Loader.jsx
│ │ ├── index.js
│ │ ├── useAPI.js
│ │ ├── useAddThing.js
│ │ ├── useAllThings.js
│ │ ├── useCurrentThing.js
│ │ ├── useData.js
│ │ ├── useLoginSignup.js
│ │ ├── useLogout.js
│ │ ├── useThatThing.js
│ │ ├── useThisThing.js
│ │ └── useUser.js
│ ├── main.jsx
│ └── view
│ │ ├── AddAThing.jsx
│ │ ├── AllThings.jsx
│ │ ├── Button.jsx
│ │ ├── Form.jsx
│ │ ├── Grid.jsx
│ │ ├── Login.jsx
│ │ ├── LoginSignup.jsx
│ │ ├── Logout.jsx
│ │ ├── Progress.jsx
│ │ ├── RemoveButton.jsx
│ │ ├── Signup.jsx
│ │ ├── SingleThing.jsx
│ │ ├── Thing.jsx
│ │ ├── ThingTitle.jsx
│ │ ├── Things.jsx
│ │ ├── View.jsx
│ │ └── index.js
│ └── vite.config.js
├── ch10
├── axios
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ ├── StarshipList.jsx
│ │ ├── StarshipList.test.jsx
│ │ └── main.jsx
│ └── vite.config.js
├── click-counter
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ ├── Counter.jsx
│ │ ├── Counter.test.jsx
│ │ └── main.jsx
│ └── vite.config.js
├── dark-mode
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ ├── Button.jsx
│ │ ├── Button.test.jsx
│ │ ├── DarkModeContext.jsx
│ │ ├── Header.jsx
│ │ ├── Page.jsx
│ │ ├── ToggleButton.jsx
│ │ ├── ToggleButton.test.jsx
│ │ └── main.jsx
│ └── vite.config.js
├── geo
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ ├── WhereAmI.jsx
│ │ ├── WhereAmI.test.jsx
│ │ └── main.jsx
│ └── vite.config.js
├── keypress
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ ├── main.jsx
│ │ ├── useIsKeyPressed.js
│ │ └── useIsKeyPressed.test.js
│ └── vite.config.js
├── menuitem-icon
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── public
│ │ └── images
│ │ │ └── link.png
│ ├── src
│ │ ├── App.jsx
│ │ ├── MenuItem.jsx
│ │ ├── MenuItem.test.jsx
│ │ └── main.jsx
│ └── vite.config.js
├── menuitem
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ ├── MenuItem.jsx
│ │ ├── MenuItem.test.jsx
│ │ └── main.jsx
│ └── vite.config.js
├── timer
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── public
│ │ └── icons
│ │ │ ├── pause.svg
│ │ │ ├── play.svg
│ │ │ ├── restart.svg
│ │ │ └── trash.svg
│ ├── src
│ │ ├── AddTimer.jsx
│ │ ├── AddTimer.test.jsx
│ │ ├── App.jsx
│ │ ├── Button.jsx
│ │ ├── Input.jsx
│ │ ├── Number.jsx
│ │ ├── TimeDisplay.jsx
│ │ ├── Timer.jsx
│ │ ├── TimerManager.jsx
│ │ ├── main.jsx
│ │ ├── style.css
│ │ └── useTimer.js
│ └── vite.config.js
└── todo
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ ├── App.jsx
│ ├── Items.jsx
│ ├── Items.test.jsx
│ ├── Todo.jsx
│ └── main.jsx
│ └── vite.config.js
├── ch11
├── nextjs
│ ├── .env
│ ├── .env.example
│ ├── .eslintrc.json
│ ├── .gitignore
│ ├── README.md
│ ├── components
│ │ ├── cityCard.js
│ │ ├── cityCard.module.css
│ │ ├── cityCardList.js
│ │ ├── cityDisplay.js
│ │ ├── cityDisplay.module.css
│ │ ├── getWeatherImage.js
│ │ ├── index.js
│ │ ├── myCity.js
│ │ ├── myCity.module.css
│ │ ├── swap.js
│ │ └── swap.module.css
│ ├── format
│ │ ├── context.js
│ │ ├── formatProvider.js
│ │ ├── index.js
│ │ ├── useTemperature.js
│ │ └── useTime.js
│ ├── jsconfig.json
│ ├── next.config.js
│ ├── package-lock.json
│ ├── package.json
│ ├── pages
│ │ ├── [cc]
│ │ │ ├── [city].js
│ │ │ └── index.js
│ │ ├── _app.js
│ │ ├── api
│ │ │ └── geocode.js
│ │ └── index.js
│ ├── prisma
│ │ ├── countries.mjs
│ │ ├── data.db
│ │ ├── migrations
│ │ │ ├── 20221117222351_init
│ │ │ │ └── migration.sql
│ │ │ ├── 20221118201753_latlng
│ │ │ │ └── migration.sql
│ │ │ ├── 20221118232851_citydata
│ │ │ │ └── migration.sql
│ │ │ ├── 20221119001055_invert
│ │ │ │ └── migration.sql
│ │ │ ├── 20221119002223_lowername
│ │ │ │ └── migration.sql
│ │ │ ├── 20221119002453_uniquecity
│ │ │ │ └── migration.sql
│ │ │ ├── 20221119003016_namedindex
│ │ │ │ └── migration.sql
│ │ │ ├── 20221121191205_cc
│ │ │ │ └── migration.sql
│ │ │ └── migration_lock.toml
│ │ ├── schema.prisma
│ │ └── seed.mjs
│ ├── public
│ │ ├── android-chrome-192x192.png
│ │ ├── android-chrome-512x512.png
│ │ ├── apple-touch-icon.png
│ │ ├── browserconfig.xml
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── favicon.ico
│ │ ├── icons
│ │ │ └── swap.svg
│ │ ├── mstile-144x144.png
│ │ ├── mstile-150x150.png
│ │ ├── mstile-310x150.png
│ │ ├── mstile-310x310.png
│ │ ├── mstile-70x70.png
│ │ ├── safari-pinned-tab.svg
│ │ ├── site.webmanifest
│ │ └── weathers
│ │ │ ├── cloudy.png
│ │ │ ├── dreary.png
│ │ │ ├── night.png
│ │ │ ├── rainy.png
│ │ │ ├── snowy.png
│ │ │ ├── sunny.png
│ │ │ ├── thunder.png
│ │ │ └── windy.png
│ ├── services
│ │ ├── api.js
│ │ ├── cookies.js
│ │ └── data.js
│ └── styles
│ │ └── globals.css
└── remix
│ ├── .env.example
│ ├── .eslintrc.js
│ ├── .gitignore
│ ├── .prettierignore
│ ├── app
│ ├── components
│ │ ├── cityCard.js
│ │ ├── cityCard.module.css
│ │ ├── cityCardList.jsx
│ │ ├── cityDisplay.jsx
│ │ ├── cityDisplay.module.css
│ │ ├── getWeatherImage.js
│ │ ├── myCity.jsx
│ │ ├── myCity.module.css
│ │ ├── swap.jsx
│ │ └── swap.module.css
│ ├── cookies.server.js
│ ├── db.server.ts
│ ├── entry.client.tsx
│ ├── entry.server.tsx
│ ├── format
│ │ ├── context.js
│ │ ├── formatProvider.js
│ │ ├── index.js
│ │ ├── useTemperature.js
│ │ └── useTime.js
│ ├── globals.css
│ ├── globals.json
│ ├── root.jsx
│ ├── routes
│ │ ├── $cc.$city.jsx
│ │ ├── $cc.index.jsx
│ │ ├── _index.js
│ │ └── api.geocode.js
│ ├── services
│ │ ├── api.js
│ │ ├── cookies.js
│ │ └── data.js
│ └── singleton.server.ts
│ ├── package-lock.json
│ ├── package.json
│ ├── postcss.config.js
│ ├── prisma
│ ├── countries.mjs
│ ├── migrations
│ │ ├── 20221122003110_init
│ │ │ └── migration.sql
│ │ └── migration_lock.toml
│ ├── schema.prisma
│ └── seed.mjs
│ ├── public
│ ├── android-chrome-192x192.png
│ ├── android-chrome-512x512.png
│ ├── apple-touch-icon.png
│ ├── browserconfig.xml
│ ├── favicon copy.ico
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── favicon.ico
│ ├── fonts
│ │ ├── montserrat-v25-latin-100.eot
│ │ ├── montserrat-v25-latin-100.svg
│ │ ├── montserrat-v25-latin-100.ttf
│ │ ├── montserrat-v25-latin-100.woff
│ │ └── montserrat-v25-latin-100.woff2
│ ├── icons
│ │ └── swap.svg
│ ├── mstile-144x144.png
│ ├── mstile-150x150.png
│ ├── mstile-310x150.png
│ ├── mstile-310x310.png
│ ├── mstile-70x70.png
│ ├── safari-pinned-tab.svg
│ ├── site.webmanifest
│ └── weathers
│ │ ├── cloudy.png
│ │ ├── dreary.png
│ │ ├── night.png
│ │ ├── rainy.png
│ │ ├── snowy.png
│ │ ├── sunny.png
│ │ ├── thunder.png
│ │ └── windy.png
│ ├── remix.config.js
│ ├── remix.env.d.ts
│ ├── test
│ └── setup-test-env.ts
│ ├── tsconfig.json
│ └── vitest.config.ts
├── ch12
├── backend-only
│ ├── .env.example
│ ├── .eslintrc.js
│ ├── .gitignore
│ ├── .prettierignore
│ ├── app
│ │ ├── components
│ │ │ ├── Body.module.css
│ │ │ ├── Body.tsx
│ │ │ ├── FormMenuItem.tsx
│ │ │ ├── Main.module.css
│ │ │ ├── Main.tsx
│ │ │ ├── Menu.module.css
│ │ │ ├── Menu.tsx
│ │ │ └── MenuItem.tsx
│ │ ├── db.server.ts
│ │ ├── entry.client.tsx
│ │ ├── entry.server.tsx
│ │ ├── models
│ │ │ ├── category.server.ts
│ │ │ ├── expense.server.ts
│ │ │ ├── types.client.ts
│ │ │ └── user.server.ts
│ │ ├── root.css
│ │ ├── root.tsx
│ │ ├── routes
│ │ │ ├── _index.tsx
│ │ │ ├── expenses.add.tsx
│ │ │ ├── expenses.tsx
│ │ │ ├── income.tsx
│ │ │ ├── join.tsx
│ │ │ ├── login.tsx
│ │ │ └── logout.tsx
│ │ ├── session.server.ts
│ │ ├── singleton.server.ts
│ │ ├── utils.test.ts
│ │ └── utils.ts
│ ├── package-lock.json
│ ├── package.json
│ ├── postcss.config.js
│ ├── prisma
│ │ ├── migrations
│ │ │ ├── 20221015205634_init
│ │ │ │ └── migration.sql
│ │ │ └── migration_lock.toml
│ │ ├── schema.prisma
│ │ └── seed.ts
│ ├── public
│ │ ├── android-chrome-192x192.png
│ │ ├── android-chrome-512x512.png
│ │ ├── apple-touch-icon.png
│ │ ├── browserconfig.xml
│ │ ├── favicon copy.ico
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── favicon.ico
│ │ ├── fonts
│ │ │ ├── montserrat-v25-latin-100.eot
│ │ │ ├── montserrat-v25-latin-100.svg
│ │ │ ├── montserrat-v25-latin-100.ttf
│ │ │ ├── montserrat-v25-latin-100.woff
│ │ │ └── montserrat-v25-latin-100.woff2
│ │ ├── icons
│ │ │ └── swap.svg
│ │ ├── mstile-144x144.png
│ │ ├── mstile-150x150.png
│ │ ├── mstile-310x150.png
│ │ ├── mstile-310x310.png
│ │ ├── mstile-70x70.png
│ │ ├── safari-pinned-tab.svg
│ │ ├── site.webmanifest
│ │ └── weathers
│ │ │ ├── cloudy.png
│ │ │ ├── dreary.png
│ │ │ ├── night.png
│ │ │ ├── rainy.png
│ │ │ ├── snowy.png
│ │ │ ├── sunny.png
│ │ │ ├── thunder.png
│ │ │ └── windy.png
│ ├── remix.config.js
│ ├── remix.env.d.ts
│ ├── tsconfig.json
│ └── vitest.config.ts
├── complete
│ ├── .env.example
│ ├── .eslintrc.js
│ ├── .gitignore
│ ├── .prettierignore
│ ├── app
│ │ ├── components
│ │ │ ├── Balance.module.css
│ │ │ ├── Balance.tsx
│ │ │ ├── Body.module.css
│ │ │ ├── Body.tsx
│ │ │ ├── Dialog.module.css
│ │ │ ├── Dialog.tsx
│ │ │ ├── Expenses.module.css
│ │ │ ├── Expenses.tsx
│ │ │ ├── Form.module.css
│ │ │ ├── Form.tsx
│ │ │ ├── FormMenuItem.tsx
│ │ │ ├── IncomeInput.module.css
│ │ │ ├── IncomeInput.tsx
│ │ │ ├── Main.module.css
│ │ │ ├── Main.tsx
│ │ │ ├── Menu.module.css
│ │ │ ├── Menu.tsx
│ │ │ ├── MenuItem.tsx
│ │ │ ├── PieChart.module.css
│ │ │ └── PieChart.tsx
│ │ ├── db.server.ts
│ │ ├── entry.client.tsx
│ │ ├── entry.server.tsx
│ │ ├── models
│ │ │ ├── category.server.ts
│ │ │ ├── expense.server.ts
│ │ │ ├── types.client.ts
│ │ │ └── user.server.ts
│ │ ├── root.css
│ │ ├── root.tsx
│ │ ├── routes
│ │ │ ├── _index.tsx
│ │ │ ├── expenses.add.tsx
│ │ │ ├── expenses.tsx
│ │ │ ├── income.tsx
│ │ │ ├── join.tsx
│ │ │ ├── login.tsx
│ │ │ └── logout.tsx
│ │ ├── session.server.ts
│ │ ├── singleton.server.ts
│ │ ├── utils.test.ts
│ │ └── utils.ts
│ ├── package-lock.json
│ ├── package.json
│ ├── postcss.config.js
│ ├── prisma
│ │ ├── migrations
│ │ │ ├── 20221015205634_init
│ │ │ │ └── migration.sql
│ │ │ └── migration_lock.toml
│ │ ├── schema.prisma
│ │ └── seed.ts
│ ├── public
│ │ ├── android-chrome-192x192.png
│ │ ├── android-chrome-512x512.png
│ │ ├── apple-touch-icon.png
│ │ ├── browserconfig.xml
│ │ ├── favicon copy.ico
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── favicon.ico
│ │ ├── fonts
│ │ │ ├── montserrat-v25-latin-100.eot
│ │ │ ├── montserrat-v25-latin-100.svg
│ │ │ ├── montserrat-v25-latin-100.ttf
│ │ │ ├── montserrat-v25-latin-100.woff
│ │ │ └── montserrat-v25-latin-100.woff2
│ │ ├── icons
│ │ │ └── swap.svg
│ │ ├── mstile-144x144.png
│ │ ├── mstile-150x150.png
│ │ ├── mstile-310x150.png
│ │ ├── mstile-310x310.png
│ │ ├── mstile-70x70.png
│ │ ├── safari-pinned-tab.svg
│ │ ├── site.webmanifest
│ │ └── weathers
│ │ │ ├── cloudy.png
│ │ │ ├── dreary.png
│ │ │ ├── night.png
│ │ │ ├── rainy.png
│ │ │ ├── snowy.png
│ │ │ ├── sunny.png
│ │ │ ├── thunder.png
│ │ │ └── windy.png
│ ├── remix.config.js
│ ├── remix.env.d.ts
│ └── tsconfig.json
├── frontend-only
│ ├── .env.example
│ ├── .eslintrc.js
│ ├── .gitignore
│ ├── .prettierignore
│ ├── app
│ │ ├── components
│ │ │ ├── Balance.module.css
│ │ │ ├── Balance.tsx
│ │ │ ├── Body.module.css
│ │ │ ├── Body.tsx
│ │ │ ├── Dialog.module.css
│ │ │ ├── Dialog.tsx
│ │ │ ├── Expenses.module.css
│ │ │ ├── Expenses.tsx
│ │ │ ├── Form.module.css
│ │ │ ├── Form.tsx
│ │ │ ├── FormMenuItem.tsx
│ │ │ ├── IncomeInput.module.css
│ │ │ ├── IncomeInput.tsx
│ │ │ ├── Main.module.css
│ │ │ ├── Main.tsx
│ │ │ ├── Menu.module.css
│ │ │ ├── Menu.tsx
│ │ │ ├── MenuItem.tsx
│ │ │ ├── PieChart.module.css
│ │ │ └── PieChart.tsx
│ │ ├── db.server.ts
│ │ ├── entry.client.tsx
│ │ ├── entry.server.tsx
│ │ ├── models
│ │ │ └── user.server.ts
│ │ ├── root.css
│ │ ├── root.tsx
│ │ ├── routes
│ │ │ ├── _index.tsx
│ │ │ ├── expenses.add.tsx
│ │ │ ├── expenses.tsx
│ │ │ ├── income.tsx
│ │ │ ├── join.tsx
│ │ │ ├── login.tsx
│ │ │ └── logout.tsx
│ │ ├── session.server.ts
│ │ ├── singleton.server.ts
│ │ ├── utils.test.ts
│ │ └── utils.ts
│ ├── package-lock.json
│ ├── package.json
│ ├── postcss.config.js
│ ├── prisma
│ │ ├── migrations
│ │ │ ├── 20221015205634_init
│ │ │ │ └── migration.sql
│ │ │ └── migration_lock.toml
│ │ ├── schema.prisma
│ │ └── seed.ts
│ ├── public
│ │ ├── android-chrome-192x192.png
│ │ ├── android-chrome-512x512.png
│ │ ├── apple-touch-icon.png
│ │ ├── browserconfig.xml
│ │ ├── favicon copy.ico
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── favicon.ico
│ │ ├── fonts
│ │ │ ├── montserrat-v25-latin-100.eot
│ │ │ ├── montserrat-v25-latin-100.svg
│ │ │ ├── montserrat-v25-latin-100.ttf
│ │ │ ├── montserrat-v25-latin-100.woff
│ │ │ └── montserrat-v25-latin-100.woff2
│ │ ├── icons
│ │ │ └── swap.svg
│ │ ├── mstile-144x144.png
│ │ ├── mstile-150x150.png
│ │ ├── mstile-310x150.png
│ │ ├── mstile-310x310.png
│ │ ├── mstile-70x70.png
│ │ ├── safari-pinned-tab.svg
│ │ ├── site.webmanifest
│ │ └── weathers
│ │ │ ├── cloudy.png
│ │ │ ├── dreary.png
│ │ │ ├── night.png
│ │ │ ├── rainy.png
│ │ │ ├── snowy.png
│ │ │ ├── sunny.png
│ │ │ ├── thunder.png
│ │ │ └── windy.png
│ ├── remix.config.js
│ ├── remix.env.d.ts
│ ├── tsconfig.json
│ └── vitest.config.ts
└── skeleton
│ ├── .env.example
│ ├── .eslintrc.js
│ ├── .gitignore
│ ├── .prettierignore
│ ├── app
│ ├── db.server.ts
│ ├── entry.client.tsx
│ ├── entry.server.tsx
│ ├── models
│ │ └── user.server.ts
│ ├── root.tsx
│ ├── routes
│ │ ├── _index.tsx
│ │ ├── join.tsx
│ │ ├── login.tsx
│ │ └── logout.tsx
│ ├── session.server.ts
│ ├── singleton.server.ts
│ ├── utils.test.ts
│ └── utils.ts
│ ├── package-lock.json
│ ├── package.json
│ ├── postcss.config.js
│ ├── prisma
│ ├── migrations
│ │ ├── 20221015205634_init
│ │ │ └── migration.sql
│ │ └── migration_lock.toml
│ ├── schema.prisma
│ └── seed.ts
│ ├── public
│ ├── android-chrome-192x192.png
│ ├── android-chrome-512x512.png
│ ├── apple-touch-icon.png
│ ├── browserconfig.xml
│ ├── favicon copy.ico
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── favicon.ico
│ ├── fonts
│ │ ├── montserrat-v25-latin-100.eot
│ │ ├── montserrat-v25-latin-100.svg
│ │ ├── montserrat-v25-latin-100.ttf
│ │ ├── montserrat-v25-latin-100.woff
│ │ └── montserrat-v25-latin-100.woff2
│ ├── icons
│ │ └── swap.svg
│ ├── mstile-144x144.png
│ ├── mstile-150x150.png
│ ├── mstile-310x150.png
│ ├── mstile-310x310.png
│ ├── mstile-70x70.png
│ ├── safari-pinned-tab.svg
│ ├── site.webmanifest
│ └── weathers
│ │ ├── cloudy.png
│ │ ├── dreary.png
│ │ ├── night.png
│ │ ├── rainy.png
│ │ ├── snowy.png
│ │ ├── sunny.png
│ │ ├── thunder.png
│ │ └── windy.png
│ ├── remix.config.js
│ ├── remix.env.d.ts
│ ├── tsconfig.json
│ └── vitest.config.ts
├── ch13
├── base
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── .storybook
│ │ ├── main.js
│ │ └── preview.jsx
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.jsx
│ │ ├── library
│ │ │ ├── button
│ │ │ │ ├── Button.jsx
│ │ │ │ ├── Button.stories.jsx
│ │ │ │ ├── Button.test.jsx
│ │ │ │ ├── ButtonGroup.stories.jsx
│ │ │ │ ├── ButtonGroup.test.jsx
│ │ │ │ └── index.js
│ │ │ └── index.js
│ │ └── main.jsx
│ ├── vite.config.js
│ └── vitest.setup.js
└── complete
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── .storybook
│ ├── main.js
│ └── preview.jsx
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ ├── App.jsx
│ ├── library
│ │ ├── accordion
│ │ │ ├── Accordion.jsx
│ │ │ ├── Accordion.stories.jsx
│ │ │ ├── Accordion.test.jsx
│ │ │ ├── AccordionContext.jsx
│ │ │ ├── AccordionItem.jsx
│ │ │ ├── index.js
│ │ │ ├── useAccordionContext.js
│ │ │ └── useKeyboard.js
│ │ ├── button
│ │ │ ├── Button.jsx
│ │ │ ├── Button.stories.jsx
│ │ │ ├── Button.test.jsx
│ │ │ ├── ButtonGroup.stories.jsx
│ │ │ ├── ButtonGroup.test.jsx
│ │ │ └── index.js
│ │ ├── index.js
│ │ ├── switch
│ │ │ ├── Switch.jsx
│ │ │ ├── Switch.stories.jsx
│ │ │ ├── Switch.test.jsx
│ │ │ └── index.js
│ │ └── toast
│ │ │ ├── Toast.jsx
│ │ │ ├── Toast.stories.jsx
│ │ │ ├── Toast.test.jsx
│ │ │ ├── ToastMaster.jsx
│ │ │ ├── ToastProvider.jsx
│ │ │ ├── context.js
│ │ │ ├── index.js
│ │ │ └── useToast.js
│ └── main.jsx
│ ├── vite.config.js
│ └── vitest.setup.js
├── ch14
└── wordle
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── .storybook
│ ├── main.ts
│ └── preview.tsx
│ ├── README.md
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ ├── App.tsx
│ ├── WordGame.tsx
│ ├── components
│ │ ├── game
│ │ │ ├── Game.tsx
│ │ │ ├── gameMachine.ts
│ │ │ ├── index.ts
│ │ │ └── useGameMachine.ts
│ │ ├── gamedata
│ │ │ ├── GameDataProvider.tsx
│ │ │ ├── context.ts
│ │ │ ├── index.ts
│ │ │ ├── persistProfile.ts
│ │ │ ├── useGameData.ts
│ │ │ ├── useGameDialogs.ts
│ │ │ └── useProfile.ts
│ │ ├── grid
│ │ │ ├── Cell.stories.jsx
│ │ │ ├── Cell.tsx
│ │ │ ├── Grid.stories.jsx
│ │ │ ├── Grid.tsx
│ │ │ ├── RevealRow.stories.jsx
│ │ │ ├── RevealRow.tsx
│ │ │ ├── Row.stories.jsx
│ │ │ ├── Row.tsx
│ │ │ ├── WinRow.stories.jsx
│ │ │ ├── WinRow.tsx
│ │ │ └── useEffectMachine.ts
│ │ ├── keyboard
│ │ │ ├── Key.stories.jsx
│ │ │ ├── Key.tsx
│ │ │ ├── Keyboard.stories.jsx
│ │ │ ├── Keyboard.tsx
│ │ │ └── useHandleCharacter.ts
│ │ ├── menu
│ │ │ ├── Menu.tsx
│ │ │ └── index.ts
│ │ └── overlay
│ │ │ ├── Dialog.tsx
│ │ │ ├── OverlayProvider.tsx
│ │ │ ├── context.ts
│ │ │ ├── dialogs
│ │ │ ├── Countdown.tsx
│ │ │ ├── ResultDialog.tsx
│ │ │ ├── WelcomeDialog.tsx
│ │ │ └── styles.tsx
│ │ │ ├── index.ts
│ │ │ ├── useAlert.ts
│ │ │ └── useDialog.tsx
│ ├── main.tsx
│ ├── styles
│ │ ├── GlobalStyles.tsx
│ │ ├── Provider.tsx
│ │ ├── emotion.d.ts
│ │ ├── index.ts
│ │ └── theme.ts
│ ├── types.ts
│ ├── utils
│ │ ├── constants.ts
│ │ ├── getLabel.ts
│ │ ├── getToday.ts
│ │ ├── getWordOfTheDay.ts
│ │ ├── goodWords.ts
│ │ ├── isValidWord.ts
│ │ ├── localStorage.ts
│ │ ├── tryWord.test.ts
│ │ ├── tryWord.ts
│ │ ├── updateKeyboard.ts
│ │ └── validWords.ts
│ └── vite-env.d.ts
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
├── package-lock.json
├── package.json
└── scripts
├── build.js
└── create.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/base-projects/vite-base-js/.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 |
--------------------------------------------------------------------------------
/base-projects/vite-base-js/src/App.jsx:
--------------------------------------------------------------------------------
1 | export default function App() {
2 | return (
3 |
4 | Vite Example with JS
5 |
6 | );
7 | }
8 |
--------------------------------------------------------------------------------
/base-projects/vite-base-js/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/base-projects/vite-base-js/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 |
--------------------------------------------------------------------------------
/base-projects/vite-base-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 |
--------------------------------------------------------------------------------
/base-projects/vite-base-ts/src/App.tsx:
--------------------------------------------------------------------------------
1 | export default function App() {
2 | return (
3 |
4 | Vite Example with TS
5 |
6 | );
7 | }
8 |
--------------------------------------------------------------------------------
/base-projects/vite-base-ts/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.tsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")!).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/base-projects/vite-base-ts/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/base-projects/vite-base-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 |
--------------------------------------------------------------------------------
/base-projects/vite-base-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 |
--------------------------------------------------------------------------------
/ch02/dark-mode-dedicated/.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 |
--------------------------------------------------------------------------------
/ch02/dark-mode-dedicated/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch02/dark-mode-dedicated/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 |
--------------------------------------------------------------------------------
/ch02/dark-mode-selector/.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 |
--------------------------------------------------------------------------------
/ch02/dark-mode-selector/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch02/dark-mode-selector/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 |
--------------------------------------------------------------------------------
/ch02/dark-mode-typed/.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 |
--------------------------------------------------------------------------------
/ch02/dark-mode-typed/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.tsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")!).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch02/dark-mode-typed/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/ch02/dark-mode-typed/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 |
--------------------------------------------------------------------------------
/ch02/dark-mode-typed/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 |
--------------------------------------------------------------------------------
/ch02/dark-mode/.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 |
--------------------------------------------------------------------------------
/ch02/dark-mode/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch02/dark-mode/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 |
--------------------------------------------------------------------------------
/ch02/radio-complex/.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 |
--------------------------------------------------------------------------------
/ch02/radio-complex/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch02/radio-complex/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 |
--------------------------------------------------------------------------------
/ch02/radio-composite/.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 |
--------------------------------------------------------------------------------
/ch02/radio-composite/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch02/radio-composite/src/radiogroup/Details.jsx:
--------------------------------------------------------------------------------
1 | import { useContext } from "react";
2 | import { RadioOptionContext } from "./contexts";
3 |
4 | export function Details({ children }) {
5 | const isSelected = useContext(RadioOptionContext);
6 | return isSelected ? children : null;
7 | }
8 |
--------------------------------------------------------------------------------
/ch02/radio-composite/src/radiogroup/contexts.js:
--------------------------------------------------------------------------------
1 | import { createContext } from "react";
2 |
3 | export const RadioGroupContext = createContext();
4 | export const RadioOptionContext = createContext();
5 |
--------------------------------------------------------------------------------
/ch02/radio-composite/src/radiogroup/index.js:
--------------------------------------------------------------------------------
1 | export { RadioGroup } from "./RadioGroup";
2 |
--------------------------------------------------------------------------------
/ch02/radio-composite/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 |
--------------------------------------------------------------------------------
/ch02/radio-simple/.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 |
--------------------------------------------------------------------------------
/ch02/radio-simple/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch02/radio-simple/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 |
--------------------------------------------------------------------------------
/ch02/radio-summary/.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 |
--------------------------------------------------------------------------------
/ch02/radio-summary/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch02/radio-summary/src/radiogroup/Details.jsx:
--------------------------------------------------------------------------------
1 | import { useContext } from "react";
2 | import { RadioOptionContext } from "./contexts";
3 |
4 | export function Details({ children }) {
5 | const isSelected = useContext(RadioOptionContext);
6 | return isSelected ? children : null;
7 | }
8 |
--------------------------------------------------------------------------------
/ch02/radio-summary/src/radiogroup/contexts.js:
--------------------------------------------------------------------------------
1 | import { createContext } from "react";
2 |
3 | export const RadioGroupContext = createContext();
4 | export const RadioOptionContext = createContext();
5 |
--------------------------------------------------------------------------------
/ch02/radio-summary/src/radiogroup/index.js:
--------------------------------------------------------------------------------
1 | export { RadioGroup } from "./RadioGroup";
2 |
--------------------------------------------------------------------------------
/ch02/radio-summary/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 |
--------------------------------------------------------------------------------
/ch02/task-summary/.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 |
--------------------------------------------------------------------------------
/ch02/task-summary/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { LongTaskManager } from "./LongTaskManager";
2 |
3 | export default function App() {
4 | return ;
5 | }
6 |
--------------------------------------------------------------------------------
/ch02/task-summary/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch02/task-summary/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 |
--------------------------------------------------------------------------------
/ch02/user-summary/.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 |
--------------------------------------------------------------------------------
/ch02/user-summary/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { LongUserProfile } from "./LongUserProfile";
2 |
3 | export default function App() {
4 | return (
5 |
6 |
7 |
8 | );
9 | }
10 |
--------------------------------------------------------------------------------
/ch02/user-summary/src/UserDetails.jsx:
--------------------------------------------------------------------------------
1 | export function UserDetails({ userData }) {
2 | return (
3 |
4 |
Personal Information
5 |
6 | Name: {userData.name}
7 |
8 |
9 | Email: {userData.email}
10 |
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/ch02/user-summary/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch02/user-summary/src/useAPI.js:
--------------------------------------------------------------------------------
1 | import { useMemo } from "react";
2 |
3 | export function useAPI() {
4 | return useMemo(
5 | () => ({
6 | fetchUser: (userId) =>
7 | fetch(`https://api.company.invalid/users/${userId}`),
8 | }),
9 | []
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/ch02/user-summary/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 |
--------------------------------------------------------------------------------
/ch03/employees/.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 |
--------------------------------------------------------------------------------
/ch03/employees/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch03/employees/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 |
--------------------------------------------------------------------------------
/ch03/rerender/.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 |
--------------------------------------------------------------------------------
/ch03/rerender/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | rerender from React in Depth
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch03/rerender/src/NoRerenderWithPropsChange.jsx:
--------------------------------------------------------------------------------
1 | import { useRef } from "react";
2 | import { Rerenderable } from "./Rerenderable";
3 |
4 | export function NoRerenderWithPropsChange() {
5 | const count = useRef(0);
6 | return (
7 |
8 |
11 |
12 |
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/ch03/rerender/src/RerenderWithoutPropsChange.jsx:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import { Rerenderable } from "./Rerenderable";
3 |
4 | export function RerenderWithoutPropsChange() {
5 | const [, setCount] = useState(0);
6 | return (
7 |
8 |
11 |
12 |
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/ch03/rerender/src/Rerenderable.jsx:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 | import { useRef } from "react";
3 |
4 | export function Rerenderable() {
5 | const isFirst = useRef(true);
6 | useEffect(() => {
7 | isFirst.current = false;
8 | }, []);
9 | const style = { color: isFirst.current ? "red" : "blue" };
10 | const text = isFirst.current ? "First render" : "Not first render";
11 | return {text}
;
12 | }
13 |
--------------------------------------------------------------------------------
/ch03/rerender/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch03/rerender/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 |
--------------------------------------------------------------------------------
/ch03/strict-mode/.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 |
--------------------------------------------------------------------------------
/ch03/strict-mode/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch03/strict-mode/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 |
--------------------------------------------------------------------------------
/ch03/todo-delete/.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 |
--------------------------------------------------------------------------------
/ch03/todo-delete/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch03/todo-delete/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 |
--------------------------------------------------------------------------------
/ch03/todo-fixed/.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 |
--------------------------------------------------------------------------------
/ch03/todo-fixed/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch03/todo-fixed/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 |
--------------------------------------------------------------------------------
/ch03/todo-memo/.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 |
--------------------------------------------------------------------------------
/ch03/todo-memo/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch03/todo-memo/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 |
--------------------------------------------------------------------------------
/ch03/todo-simple/.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 |
--------------------------------------------------------------------------------
/ch03/todo-simple/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch03/todo-simple/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 |
--------------------------------------------------------------------------------
/ch03/todo-usememo/.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 |
--------------------------------------------------------------------------------
/ch03/todo-usememo/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch03/todo-usememo/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 |
--------------------------------------------------------------------------------
/ch04/dark-mode/.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 |
--------------------------------------------------------------------------------
/ch04/dark-mode/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch04/dark-mode/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 |
--------------------------------------------------------------------------------
/ch04/prettier/.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 |
--------------------------------------------------------------------------------
/ch04/prettier/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | prettier from React in Depth
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch04/prettier/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch04/prettier/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 |
--------------------------------------------------------------------------------
/ch05/book-review/.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 |
--------------------------------------------------------------------------------
/ch05/book-review/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 |
--------------------------------------------------------------------------------
/ch05/book-review/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/ch05/book-review/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 |
--------------------------------------------------------------------------------
/ch05/book-review/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 |
--------------------------------------------------------------------------------
/ch05/employee/.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 |
--------------------------------------------------------------------------------
/ch05/employee/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | employee from React in Depth
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch05/employee/src/App.tsx:
--------------------------------------------------------------------------------
1 | import EmployeeCard from "./EmployeeCard";
2 | import "./app.css";
3 |
4 | function App() {
5 | return (
6 |
7 |
10 |
11 | );
12 | }
13 |
14 | export default App;
15 |
--------------------------------------------------------------------------------
/ch05/employee/src/app.css:
--------------------------------------------------------------------------------
1 | @import url("https://fonts.googleapis.com/css2?family=Open+Sans:wght@300&display=swap");
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: #eee;
9 | font-family: "Open Sans", sans-serif;
10 | }
11 |
12 | main {
13 | display: flex;
14 | align-items: center;
15 | justify-content: center;
16 | margin: 2em;
17 | }
18 |
--------------------------------------------------------------------------------
/ch05/employee/src/employee.css:
--------------------------------------------------------------------------------
1 | .employee {
2 | background: white;
3 | flex: 0 0 300px;
4 | border-radius: 1em;
5 | padding: 1em 1.5em;
6 | box-shadow: 4px 4px 2px rgba(0 0 0 / 0.2);
7 | }
8 | .employee__name {
9 | margin: 0 0 0.5em;
10 | font-size: 24px;
11 | }
12 | .employee__title {
13 | margin: 0;
14 | text-transform: uppercase;
15 | font-size: 16px;
16 | color: #222;
17 | }
18 |
--------------------------------------------------------------------------------
/ch05/employee/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.tsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")!).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch05/employee/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/ch05/employee/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 |
--------------------------------------------------------------------------------
/ch05/employee/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 |
--------------------------------------------------------------------------------
/ch05/employees/.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 |
--------------------------------------------------------------------------------
/ch05/employees/src/app.css:
--------------------------------------------------------------------------------
1 | @import url("https://fonts.googleapis.com/css2?family=Open+Sans:wght@300&display=swap");
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: #eee;
9 | font-family: "Open Sans", sans-serif;
10 | }
11 |
12 | main {
13 | display: flex;
14 | flex-direction: column;
15 | align-items: center;
16 | justify-content: center;
17 | margin: 2em;
18 | gap: 1em;
19 | }
20 |
--------------------------------------------------------------------------------
/ch05/employees/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.tsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")!).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch05/employees/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/ch05/employees/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 |
--------------------------------------------------------------------------------
/ch05/employees/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 |
--------------------------------------------------------------------------------
/ch05/product-card/.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 |
--------------------------------------------------------------------------------
/ch05/product-card/src/App.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | margin: 0;
4 | padding: 0;
5 | background-color: #f4f4f4;
6 | color: #333;
7 | }
8 |
9 | main {
10 | width: 100%;
11 | padding: 20px;
12 | display: flex;
13 | flex-direction: column;
14 | align-items: center;
15 | gap: 20px;
16 | }
17 |
--------------------------------------------------------------------------------
/ch05/product-card/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 |
7 | *,
8 | *::before,
9 | *::after {
10 | box-sizing: border-box;
11 | }
12 |
--------------------------------------------------------------------------------
/ch05/product-card/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 |
--------------------------------------------------------------------------------
/ch05/product-card/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/ch05/product-card/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 |
--------------------------------------------------------------------------------
/ch05/product-card/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 |
--------------------------------------------------------------------------------
/ch06/appointment/.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 |
--------------------------------------------------------------------------------
/ch06/appointment/src/App.tsx:
--------------------------------------------------------------------------------
1 | import { AppointmentResponse } from "./AppointmentResponse";
2 |
3 | function App() {
4 | return (
5 | <>
6 | Incoming appointment
7 | From: John Doe
8 | Date: 2021-09-01
9 |
10 | >
11 | );
12 | }
13 |
14 | export default App;
15 |
--------------------------------------------------------------------------------
/ch06/appointment/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 | font-synthesis: none;
7 | text-rendering: optimizeLegibility;
8 | -webkit-font-smoothing: antialiased;
9 | -moz-osx-font-smoothing: grayscale;
10 | -webkit-text-size-adjust: 100%;
11 | }
12 |
--------------------------------------------------------------------------------
/ch06/appointment/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 |
--------------------------------------------------------------------------------
/ch06/appointment/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/ch06/appointment/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 |
--------------------------------------------------------------------------------
/ch06/appointment/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 |
--------------------------------------------------------------------------------
/ch06/dark-mode/.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 |
--------------------------------------------------------------------------------
/ch06/dark-mode/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.tsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")!).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch06/dark-mode/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/ch06/dark-mode/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 |
--------------------------------------------------------------------------------
/ch06/dark-mode/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 |
--------------------------------------------------------------------------------
/ch06/paginable/.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 |
--------------------------------------------------------------------------------
/ch06/paginable/src/EmployeeCard.tsx:
--------------------------------------------------------------------------------
1 | import "./employee.css";
2 | import { Employee } from "./types";
3 |
4 | interface CardProps {
5 | item: Employee;
6 | }
7 |
8 | export function EmployeeCard({ item }: CardProps) {
9 | return (
10 |
11 | {item.name}
12 | {item.title}
13 |
14 | );
15 | }
16 |
--------------------------------------------------------------------------------
/ch06/paginable/src/employee.css:
--------------------------------------------------------------------------------
1 | .employee {
2 | background: white;
3 | flex: 0 0 300px;
4 | border-radius: 1em;
5 | padding: 1em 1.5em;
6 | box-shadow: 4px 4px 2px rgba(0 0 0 / 0.2);
7 | }
8 | .employee__name {
9 | margin: 0 0 0.5em;
10 | font-size: 24px;
11 | }
12 | .employee__title {
13 | margin: 0;
14 | text-transform: uppercase;
15 | font-size: 16px;
16 | color: #222;
17 | }
18 |
--------------------------------------------------------------------------------
/ch06/paginable/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.tsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")!).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch06/paginable/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface Employee {
2 | name: string;
3 | title: string;
4 | }
5 |
6 | export interface Entry {
7 | name: string;
8 | points: number;
9 | }
10 |
--------------------------------------------------------------------------------
/ch06/paginable/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/ch06/paginable/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 |
--------------------------------------------------------------------------------
/ch06/paginable/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 |
--------------------------------------------------------------------------------
/ch06/playlist/.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 |
--------------------------------------------------------------------------------
/ch06/playlist/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.tsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")!).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch06/playlist/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface Song {
2 | id: number;
3 | title: string;
4 | artist: string;
5 | }
6 |
7 | export type Action =
8 | | { type: "up"; index: number }
9 | | { type: "down"; index: number }
10 | | { type: "first"; index: number }
11 | | { type: "last"; index: number };
12 |
13 | export type ActionType = Action["type"];
14 |
--------------------------------------------------------------------------------
/ch06/playlist/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/ch06/playlist/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 |
--------------------------------------------------------------------------------
/ch06/playlist/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 |
--------------------------------------------------------------------------------
/ch06/tag-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 |
--------------------------------------------------------------------------------
/ch06/tag-form/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | tag-form from React in Depth
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch06/tag-form/src/App.tsx:
--------------------------------------------------------------------------------
1 | import { TagForm } from "./TagForm";
2 |
3 | export default function App() {
4 | return (
5 |
6 | {}} />
7 |
8 | );
9 | }
10 |
--------------------------------------------------------------------------------
/ch06/tag-form/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.tsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")!).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch06/tag-form/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/ch06/tag-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 |
--------------------------------------------------------------------------------
/ch06/tag-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 |
--------------------------------------------------------------------------------
/ch06/use-reorderable/.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 |
--------------------------------------------------------------------------------
/ch06/use-reorderable/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.tsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")!).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch06/use-reorderable/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/ch06/use-reorderable/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 |
--------------------------------------------------------------------------------
/ch06/use-reorderable/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 |
--------------------------------------------------------------------------------
/ch07/classnames/.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 |
--------------------------------------------------------------------------------
/ch07/classnames/src/app.css:
--------------------------------------------------------------------------------
1 | .custom-button {
2 | background-color: purple;
3 | border-color: purple;
4 | }
5 |
--------------------------------------------------------------------------------
/ch07/classnames/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch07/classnames/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 |
--------------------------------------------------------------------------------
/ch07/cssmodules/.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 |
--------------------------------------------------------------------------------
/ch07/cssmodules/src/app.module.css:
--------------------------------------------------------------------------------
1 | button.customButton {
2 | background-color: purple;
3 | border-color: purple;
4 | }
5 |
--------------------------------------------------------------------------------
/ch07/cssmodules/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch07/cssmodules/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 |
--------------------------------------------------------------------------------
/ch07/inline/.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 |
--------------------------------------------------------------------------------
/ch07/inline/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | inline from React in Depth
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch07/inline/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch07/inline/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 |
--------------------------------------------------------------------------------
/ch07/styled/.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 |
--------------------------------------------------------------------------------
/ch07/styled/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | styled from React in Depth
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch07/styled/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch07/styled/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 |
--------------------------------------------------------------------------------
/ch07/tailwind/.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 |
--------------------------------------------------------------------------------
/ch07/tailwind/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | tailwind from React in Depth
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch07/tailwind/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/ch07/tailwind/src/index.css:
--------------------------------------------------------------------------------
1 | @tailwind components;
2 | @tailwind utilities;
3 |
--------------------------------------------------------------------------------
/ch07/tailwind/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch07/tailwind/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 |
--------------------------------------------------------------------------------
/ch08/context/.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 |
--------------------------------------------------------------------------------
/ch08/context/src/data/DataContext.js:
--------------------------------------------------------------------------------
1 | import { createContext } from "react";
2 |
3 | export const DataContext = createContext({ state: {}, actions: {} });
4 |
--------------------------------------------------------------------------------
/ch08/context/src/data/index.js:
--------------------------------------------------------------------------------
1 | export { DataProvider } from "./DataProvider";
2 | export { useAddThing } from "./useAddThing";
3 | export { useAllThings } from "./useAllThings";
4 | export { useThing } from "./useThing";
5 | export { useCurrentThing } from "./useCurrentThing";
6 |
--------------------------------------------------------------------------------
/ch08/context/src/data/useAddThing.js:
--------------------------------------------------------------------------------
1 | import { useData } from "./useData";
2 |
3 | export function useAddThing() {
4 | return useData().actions.addThing;
5 | }
6 |
--------------------------------------------------------------------------------
/ch08/context/src/data/useAllThings.js:
--------------------------------------------------------------------------------
1 | import { useData } from "./useData";
2 |
3 | export function useAllThings() {
4 | return useData().state.things.map(({ id }) => id);
5 | }
6 |
--------------------------------------------------------------------------------
/ch08/context/src/data/useCurrentThing.js:
--------------------------------------------------------------------------------
1 | import { useData } from "./useData";
2 |
3 | export function useCurrentThing() {
4 | return useData().state.currentThing;
5 | }
6 |
--------------------------------------------------------------------------------
/ch08/context/src/data/useData.js:
--------------------------------------------------------------------------------
1 | import { useContext } from "react";
2 | import { DataContext } from "./DataContext";
3 |
4 | export function useData() {
5 | return useContext(DataContext);
6 | }
7 |
--------------------------------------------------------------------------------
/ch08/context/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch08/context/src/things/Things.jsx:
--------------------------------------------------------------------------------
1 | import { useCurrentThing } from "../data";
2 | import { AllThings } from "./AllThings";
3 | import { SingleThing } from "./SingleThing";
4 |
5 | export function Things() {
6 | const currentThing = useCurrentThing();
7 | if (currentThing) {
8 | return ;
9 | }
10 | return ;
11 | }
12 |
--------------------------------------------------------------------------------
/ch08/context/src/things/index.js:
--------------------------------------------------------------------------------
1 | export { Things } from "./Things";
2 |
--------------------------------------------------------------------------------
/ch08/context/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 |
--------------------------------------------------------------------------------
/ch08/reducer/.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 |
--------------------------------------------------------------------------------
/ch08/reducer/src/data/DataContext.js:
--------------------------------------------------------------------------------
1 | import { createContext } from "use-context-selector";
2 |
3 | export const DataContext = createContext({});
4 |
--------------------------------------------------------------------------------
/ch08/reducer/src/data/index.js:
--------------------------------------------------------------------------------
1 | export { DataProvider } from "./DataProvider";
2 | export { useAddThing } from "./useAddThing";
3 | export { useAllThings } from "./useAllThings";
4 | export { useThing } from "./useThing";
5 | export { useCurrentThing } from "./useCurrentThing";
6 |
--------------------------------------------------------------------------------
/ch08/reducer/src/data/useAddThing.js:
--------------------------------------------------------------------------------
1 | import { useData } from "./useData";
2 |
3 | export function useAddThing() {
4 | return useData(({ actions }) => actions.addThing);
5 | }
6 |
--------------------------------------------------------------------------------
/ch08/reducer/src/data/useAllThings.js:
--------------------------------------------------------------------------------
1 | import { useData } from "./useData";
2 |
3 | export function useAllThings() {
4 | return useData(({ state }) => state.things).map(({ id }) => id);
5 | }
6 |
--------------------------------------------------------------------------------
/ch08/reducer/src/data/useCurrentThing.js:
--------------------------------------------------------------------------------
1 | import { useData } from "./useData";
2 |
3 | export function useCurrentThing() {
4 | return useData(({ state }) => state.currentThing);
5 | }
6 |
--------------------------------------------------------------------------------
/ch08/reducer/src/data/useData.js:
--------------------------------------------------------------------------------
1 | import { useContextSelector } from "use-context-selector";
2 | import { DataContext } from "./DataContext";
3 |
4 | export function useData(selector) {
5 | return useContextSelector(DataContext, selector);
6 | }
7 |
--------------------------------------------------------------------------------
/ch08/reducer/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch08/reducer/src/things/Things.jsx:
--------------------------------------------------------------------------------
1 | import { useCurrentThing } from "../data";
2 | import { AllThings } from "./AllThings";
3 | import { SingleThing } from "./SingleThing";
4 |
5 | export function Things() {
6 | const currentThing = useCurrentThing();
7 | if (currentThing) {
8 | return ;
9 | }
10 | return ;
11 | }
12 |
--------------------------------------------------------------------------------
/ch08/reducer/src/things/index.js:
--------------------------------------------------------------------------------
1 | export { Things } from "./Things";
2 |
--------------------------------------------------------------------------------
/ch08/reducer/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 |
--------------------------------------------------------------------------------
/ch08/redux/.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 |
--------------------------------------------------------------------------------
/ch08/redux/src/data/index.js:
--------------------------------------------------------------------------------
1 | export { DataProvider } from "./DataProvider";
2 | export { useAddThing } from "./useAddThing";
3 | export { useAllThings } from "./useAllThings";
4 | export { useThing } from "./useThing";
5 | export { useCurrentThing } from "./useCurrentThing";
6 |
--------------------------------------------------------------------------------
/ch08/redux/src/data/useAddThing.js:
--------------------------------------------------------------------------------
1 | import { actions } from "./store";
2 | import { useDispatch } from "react-redux";
3 |
4 | export function useAddThing() {
5 | const dispatch = useDispatch();
6 | return (name) => dispatch(actions.addThing(name));
7 | }
8 |
--------------------------------------------------------------------------------
/ch08/redux/src/data/useAllThings.js:
--------------------------------------------------------------------------------
1 | import { useData } from "./useData";
2 |
3 | export function useAllThings() {
4 | return useData((store) => store.data.things).map(({ id }) => id);
5 | }
6 |
--------------------------------------------------------------------------------
/ch08/redux/src/data/useCurrentThing.js:
--------------------------------------------------------------------------------
1 | import { useData } from "./useData";
2 |
3 | export function useCurrentThing() {
4 | return useData((store) => store.data.currentThing);
5 | }
6 |
--------------------------------------------------------------------------------
/ch08/redux/src/data/useData.js:
--------------------------------------------------------------------------------
1 | import { useSelector } from "react-redux";
2 |
3 | export function useData(selector) {
4 | return useSelector(selector);
5 | }
6 |
--------------------------------------------------------------------------------
/ch08/redux/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch08/redux/src/things/Things.jsx:
--------------------------------------------------------------------------------
1 | import { useCurrentThing } from "../data";
2 | import { AllThings } from "./AllThings";
3 | import { SingleThing } from "./SingleThing";
4 |
5 | export function Things() {
6 | const currentThing = useCurrentThing();
7 | if (currentThing) {
8 | return ;
9 | }
10 | return ;
11 | }
12 |
--------------------------------------------------------------------------------
/ch08/redux/src/things/index.js:
--------------------------------------------------------------------------------
1 | export { Things } from "./Things";
2 |
--------------------------------------------------------------------------------
/ch08/redux/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 |
--------------------------------------------------------------------------------
/ch08/xstate/.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 |
--------------------------------------------------------------------------------
/ch08/xstate/src/data/DataContext.js:
--------------------------------------------------------------------------------
1 | import { createContext } from "react";
2 |
3 | export const DataContext = createContext({});
4 |
--------------------------------------------------------------------------------
/ch08/xstate/src/data/index.js:
--------------------------------------------------------------------------------
1 | export { DataProvider } from "./DataProvider";
2 | export { useAddThing } from "./useAddThing";
3 | export { useAllThings } from "./useAllThings";
4 | export { useThatThing } from "./useThatThing";
5 | export { useThisThing } from "./useThisThing";
6 | export { useCurrentThing } from "./useCurrentThing";
7 |
--------------------------------------------------------------------------------
/ch08/xstate/src/data/useAddThing.js:
--------------------------------------------------------------------------------
1 | import { useSend } from "./useSend";
2 |
3 | export function useAddThing() {
4 | const send = useSend();
5 | return (name) => send({ type: "ADD", name });
6 | }
7 |
--------------------------------------------------------------------------------
/ch08/xstate/src/data/useAllThings.js:
--------------------------------------------------------------------------------
1 | import { useData } from "./useData";
2 |
3 | export function useAllThings() {
4 | return useData((state) => state.context.things).map(({ id }) => id);
5 | }
6 |
--------------------------------------------------------------------------------
/ch08/xstate/src/data/useCurrentThing.js:
--------------------------------------------------------------------------------
1 | import { useData } from "./useData";
2 |
3 | export function useCurrentThing() {
4 | return useData(({ context }) => context.currentThing);
5 | }
6 |
--------------------------------------------------------------------------------
/ch08/xstate/src/data/useData.js:
--------------------------------------------------------------------------------
1 | import { useContext } from "react";
2 | import { DataContext } from "./DataContext";
3 | import { useSelector } from "@xstate/react";
4 |
5 | export function useData(selector) {
6 | const service = useContext(DataContext);
7 | return useSelector(service, selector);
8 | }
9 |
--------------------------------------------------------------------------------
/ch08/xstate/src/data/useSend.js:
--------------------------------------------------------------------------------
1 | import { useContext } from "react";
2 | import { DataContext } from "./DataContext";
3 |
4 | export function useSend() {
5 | return useContext(DataContext).send;
6 | }
7 |
--------------------------------------------------------------------------------
/ch08/xstate/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch08/xstate/src/things/Things.jsx:
--------------------------------------------------------------------------------
1 | import { useCurrentThing } from "../data";
2 | import { AllThings } from "./AllThings";
3 | import { SingleThing } from "./SingleThing";
4 |
5 | export function Things() {
6 | const currentThing = useCurrentThing();
7 | if (currentThing) {
8 | return ;
9 | }
10 | return ;
11 | }
12 |
--------------------------------------------------------------------------------
/ch08/xstate/src/things/index.js:
--------------------------------------------------------------------------------
1 | export { Things } from "./Things";
2 |
--------------------------------------------------------------------------------
/ch08/xstate/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 |
--------------------------------------------------------------------------------
/ch08/zustand/.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 |
--------------------------------------------------------------------------------
/ch08/zustand/src/data/DataProvider.jsx:
--------------------------------------------------------------------------------
1 | import "./useData";
2 | export function DataProvider({ children }) {
3 | return children;
4 | }
5 |
--------------------------------------------------------------------------------
/ch08/zustand/src/data/index.js:
--------------------------------------------------------------------------------
1 | export { DataProvider } from "./DataProvider";
2 | export { useAddThing } from "./useAddThing";
3 | export { useAllThings } from "./useAllThings";
4 | export { useThing } from "./useThing";
5 | export { useCurrentThing } from "./useCurrentThing";
6 |
--------------------------------------------------------------------------------
/ch08/zustand/src/data/useAddThing.js:
--------------------------------------------------------------------------------
1 | import { useData } from "./useData";
2 |
3 | export function useAddThing() {
4 | return useData((state) => state.addThing);
5 | }
6 |
--------------------------------------------------------------------------------
/ch08/zustand/src/data/useAllThings.js:
--------------------------------------------------------------------------------
1 | import { useData } from "./useData";
2 |
3 | export function useAllThings() {
4 | return useData((state) => state.things).map(({ id }) => id);
5 | }
6 |
--------------------------------------------------------------------------------
/ch08/zustand/src/data/useCurrentThing.js:
--------------------------------------------------------------------------------
1 | import { useData } from "./useData";
2 |
3 | export function useCurrentThing() {
4 | return useData((state) => state.currentThing);
5 | }
6 |
--------------------------------------------------------------------------------
/ch08/zustand/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch08/zustand/src/things/Things.jsx:
--------------------------------------------------------------------------------
1 | import { useCurrentThing } from "../data";
2 | import { AllThings } from "./AllThings";
3 | import { SingleThing } from "./SingleThing";
4 |
5 | export function Things() {
6 | const currentThing = useCurrentThing();
7 | if (currentThing) {
8 | return ;
9 | }
10 | return ;
11 | }
12 |
--------------------------------------------------------------------------------
/ch08/zustand/src/things/index.js:
--------------------------------------------------------------------------------
1 | export { Things } from "./Things";
2 |
--------------------------------------------------------------------------------
/ch08/zustand/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 |
--------------------------------------------------------------------------------
/ch09/better-reactive/.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 |
--------------------------------------------------------------------------------
/ch09/better-reactive/src/data/DataProvider.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | QueryClient,
3 | QueryClientProvider,
4 | } from "@tanstack/react-query";
5 | import { Loader } from "./Loader";
6 |
7 | const queryClient = new QueryClient();
8 |
9 | export function DataProvider({ children }) {
10 | return (
11 |
12 |
13 | {children}
14 |
15 | );
16 | }
17 |
--------------------------------------------------------------------------------
/ch09/better-reactive/src/data/api/useDoThing.js:
--------------------------------------------------------------------------------
1 | import { useMutation } from "@tanstack/react-query";
2 | import * as API from "./api";
3 |
4 | export function useDoThing(onSuccess) {
5 | const { mutate: doThing } = useMutation({
6 | mutationFn: API.doThing,
7 | onSuccess,
8 | });
9 | return doThing;
10 | }
11 |
--------------------------------------------------------------------------------
/ch09/better-reactive/src/data/api/useLogout.js:
--------------------------------------------------------------------------------
1 | import { useQueryClient, useMutation } from "@tanstack/react-query";
2 | import * as API from "./api";
3 |
4 | export function useLogout() {
5 | const queryClient = useQueryClient();
6 | const onSuccess = () => queryClient.setQueryData(["user"], null);
7 | const { mutate: logout } = useMutation({
8 | mutationFn: API.logout,
9 | onSuccess,
10 | });
11 | return logout;
12 | }
13 |
--------------------------------------------------------------------------------
/ch09/better-reactive/src/data/api/useUndoThing.js:
--------------------------------------------------------------------------------
1 | import { useMutation } from "@tanstack/react-query";
2 | import * as API from "./api";
3 |
4 | export function useUndoThing(onSuccess) {
5 | const { mutate: undoThing } = useMutation({
6 | mutationFn: API.undoThing,
7 | onSuccess,
8 | });
9 | return undoThing;
10 | }
11 |
--------------------------------------------------------------------------------
/ch09/better-reactive/src/data/useAllThings.js:
--------------------------------------------------------------------------------
1 | import { useQuery } from "@tanstack/react-query";
2 | import { loadThings } from "./api/api";
3 |
4 | export function useAllThings() {
5 | const { data = [] } = useQuery({
6 | queryKey: ["things"],
7 | queryFn: loadThings,
8 | });
9 | return data.map(({ id }) => id) || [];
10 | }
11 |
--------------------------------------------------------------------------------
/ch09/better-reactive/src/data/useCurrent.js:
--------------------------------------------------------------------------------
1 | import { create } from "zustand";
2 |
3 | export const useCurrent = create((set) => ({
4 | currentId: null,
5 | seeThing: (id) => set(() => ({ currentId: id })),
6 | seeAllThings: () => set(() => ({ currentId: null })),
7 | }));
8 |
--------------------------------------------------------------------------------
/ch09/better-reactive/src/data/useHasCurrent.js:
--------------------------------------------------------------------------------
1 | import { useCurrent } from "./useCurrent";
2 |
3 | export function useHasCurrent() {
4 | return useCurrent((state) => !!state.currentId);
5 | }
6 |
--------------------------------------------------------------------------------
/ch09/better-reactive/src/data/useUser.js:
--------------------------------------------------------------------------------
1 | import { useQuery } from "@tanstack/react-query";
2 | import { getUser } from "./api/api";
3 |
4 | export function useUser() {
5 | const { data } = useQuery({
6 | queryKey: ["user"],
7 | queryFn: getUser,
8 | });
9 | return data;
10 | }
11 |
--------------------------------------------------------------------------------
/ch09/better-reactive/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 | import { worker } from "./backend";
5 |
6 | worker.start();
7 |
8 | ReactDOM.createRoot(document.getElementById("root")).render(
9 |
10 |
11 |
12 | );
13 |
--------------------------------------------------------------------------------
/ch09/better-reactive/src/view/Logout.jsx:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 | import { useLogout } from "../data";
3 | import { Button } from "./Button";
4 |
5 | const LogoutButton = styled(Button)`
6 | display: flex;
7 | align-self: flex-end;
8 | `;
9 |
10 | export function Logout() {
11 | const logout = useLogout();
12 | return Log out;
13 | }
14 |
--------------------------------------------------------------------------------
/ch09/better-reactive/src/view/Things.jsx:
--------------------------------------------------------------------------------
1 | import { useHasCurrent } from "../data";
2 | import { AllThings } from "./AllThings";
3 | import { SingleThing } from "./SingleThing";
4 |
5 | export function Things() {
6 | const hasCurrent = useHasCurrent();
7 | if (hasCurrent) {
8 | return ;
9 | }
10 | return ;
11 | }
12 |
--------------------------------------------------------------------------------
/ch09/better-reactive/src/view/View.jsx:
--------------------------------------------------------------------------------
1 | import { useUser } from "../data";
2 | import { Things } from "./Things";
3 | import { LoginSignup } from "./LoginSignup";
4 |
5 | export function View() {
6 | const hasUser = useUser();
7 | if (hasUser) {
8 | return ;
9 | }
10 | return ;
11 | }
12 |
--------------------------------------------------------------------------------
/ch09/better-reactive/src/view/index.js:
--------------------------------------------------------------------------------
1 | export { View } from "./View";
2 |
--------------------------------------------------------------------------------
/ch09/better-reactive/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 |
--------------------------------------------------------------------------------
/ch09/reactive/.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 |
--------------------------------------------------------------------------------
/ch09/reactive/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | reactive from React in Depth
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch09/reactive/src/data/DataProvider.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | QueryClient,
3 | QueryClientProvider,
4 | } from "@tanstack/react-query";
5 | import { Loader } from "./Loader";
6 |
7 | const queryClient = new QueryClient();
8 |
9 | export function DataProvider({ children }) {
10 | return (
11 |
12 |
13 | {children}
14 |
15 | );
16 | }
17 |
--------------------------------------------------------------------------------
/ch09/reactive/src/data/useAllThings.js:
--------------------------------------------------------------------------------
1 | import { useQuery } from "@tanstack/react-query";
2 | import { loadThings } from "./api/api";
3 |
4 | export function useAllThings() {
5 | const { data } = useQuery({
6 | queryKey: ["things"],
7 | queryFn: loadThings,
8 | });
9 | return data?.map(({ id }) => id) || [];
10 | }
11 |
--------------------------------------------------------------------------------
/ch09/reactive/src/data/useCurrent.js:
--------------------------------------------------------------------------------
1 | import { create } from "zustand";
2 |
3 | export const useCurrent = create((set) => ({
4 | currentId: null,
5 | seeThing: (id) => set(() => ({ currentId: id })),
6 | seeAllThings: () => set(() => ({ currentId: null })),
7 | }));
8 |
--------------------------------------------------------------------------------
/ch09/reactive/src/data/useHasCurrent.js:
--------------------------------------------------------------------------------
1 | import { useCurrent } from "./useCurrent";
2 |
3 | export function useHasCurrent() {
4 | return useCurrent((state) => !!state.currentId);
5 | }
6 |
--------------------------------------------------------------------------------
/ch09/reactive/src/data/useUser.js:
--------------------------------------------------------------------------------
1 | import { useQuery } from "@tanstack/react-query";
2 | import { getUser } from "./api/api";
3 |
4 | export function useUser() {
5 | const { data } = useQuery({
6 | queryKey: ["user"],
7 | queryFn: getUser,
8 | });
9 | return data;
10 | }
11 |
--------------------------------------------------------------------------------
/ch09/reactive/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 | import { worker } from "./backend";
5 |
6 | worker.start();
7 |
8 | ReactDOM.createRoot(document.getElementById("root")).render(
9 |
10 |
11 |
12 | );
13 |
--------------------------------------------------------------------------------
/ch09/reactive/src/view/Logout.jsx:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 | import { useLogout } from "../data";
3 | import { Button } from "./Button";
4 |
5 | const LogoutButton = styled(Button)`
6 | display: flex;
7 | align-self: flex-end;
8 | `;
9 |
10 | export function Logout() {
11 | const logout = useLogout();
12 | return Log out;
13 | }
14 |
--------------------------------------------------------------------------------
/ch09/reactive/src/view/Things.jsx:
--------------------------------------------------------------------------------
1 | import { useHasCurrent } from "../data";
2 | import { AllThings } from "./AllThings";
3 | import { SingleThing } from "./SingleThing";
4 |
5 | export function Things() {
6 | const hasCurrent = useHasCurrent();
7 | if (hasCurrent) {
8 | return ;
9 | }
10 | return ;
11 | }
12 |
--------------------------------------------------------------------------------
/ch09/reactive/src/view/View.jsx:
--------------------------------------------------------------------------------
1 | import { useUser } from "../data";
2 | import { Things } from "./Things";
3 | import { LoginSignup } from "./LoginSignup";
4 |
5 | export function View() {
6 | const hasUser = useUser();
7 | if (hasUser) {
8 | return ;
9 | }
10 | return ;
11 | }
12 |
--------------------------------------------------------------------------------
/ch09/reactive/src/view/index.js:
--------------------------------------------------------------------------------
1 | export { View } from "./View";
2 |
--------------------------------------------------------------------------------
/ch09/reactive/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 |
--------------------------------------------------------------------------------
/ch09/things/.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 |
--------------------------------------------------------------------------------
/ch09/things/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | things from React in Depth
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch09/things/src/data/DataContext.js:
--------------------------------------------------------------------------------
1 | import { createContext } from "use-context-selector";
2 |
3 | export const DataContext = createContext({ state: {}, actions: {} });
4 |
--------------------------------------------------------------------------------
/ch09/things/src/data/useAddThing.js:
--------------------------------------------------------------------------------
1 | import { useData } from "./useData";
2 |
3 | export function useAddThing() {
4 | return useData(({ actions }) => actions.addThing);
5 | }
6 |
--------------------------------------------------------------------------------
/ch09/things/src/data/useAllThings.js:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 | import { useData } from "./useData";
3 |
4 | export function useAllThings() {
5 | const loadThings = useData(({ actions }) => actions.loadThings);
6 | useEffect(() => void loadThings(), [loadThings]);
7 | return useData(({ state }) => state.things).map(({ id }) => id);
8 | }
9 |
--------------------------------------------------------------------------------
/ch09/things/src/data/useCurrentThing.js:
--------------------------------------------------------------------------------
1 | import { useData } from "./useData";
2 |
3 | export function useCurrentThing() {
4 | return useData(({ state }) => state.currentId);
5 | }
6 |
--------------------------------------------------------------------------------
/ch09/things/src/data/useData.js:
--------------------------------------------------------------------------------
1 | import { useContextSelector } from "use-context-selector";
2 | import { DataContext } from "./DataContext";
3 |
4 | export function useData(selector) {
5 | return useContextSelector(DataContext, selector ?? ((i) => i));
6 | }
7 |
--------------------------------------------------------------------------------
/ch09/things/src/data/useLoginSignup.js:
--------------------------------------------------------------------------------
1 | import { useData } from "./useData";
2 |
3 | export function useLoginSignup() {
4 | const login = useData(({ actions }) => actions.login);
5 | const signup = useData(({ actions }) => actions.signup);
6 | return { login, signup };
7 | }
8 |
--------------------------------------------------------------------------------
/ch09/things/src/data/useLogout.js:
--------------------------------------------------------------------------------
1 | import { useData } from "./useData";
2 |
3 | export function useLogout() {
4 | const logout = useData(({ actions }) => actions.logout);
5 | return logout;
6 | }
7 |
--------------------------------------------------------------------------------
/ch09/things/src/data/useUser.js:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 | import { useData } from "./useData";
3 |
4 | export function useUser() {
5 | const getUser = useData(({ actions }) => actions.getUser);
6 | const isAuthorized = useData(({ state }) => state.isAuthorized);
7 | useEffect(() => void getUser(), [getUser]);
8 | return isAuthorized;
9 | }
10 |
--------------------------------------------------------------------------------
/ch09/things/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 | import { worker } from "./backend";
5 |
6 | worker.start();
7 |
8 | ReactDOM.createRoot(document.getElementById("root")).render(
9 |
10 |
11 |
12 | );
13 |
--------------------------------------------------------------------------------
/ch09/things/src/view/Logout.jsx:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 | import { useLogout } from "../data";
3 | import { Button } from "./Button";
4 |
5 | const LogoutButton = styled(Button)`
6 | display: flex;
7 | align-self: flex-end;
8 | `;
9 |
10 | export function Logout() {
11 | const logout = useLogout();
12 | return Log out;
13 | }
14 |
--------------------------------------------------------------------------------
/ch09/things/src/view/Things.jsx:
--------------------------------------------------------------------------------
1 | import { useCurrentThing } from "../data";
2 | import { AllThings } from "./AllThings";
3 | import { SingleThing } from "./SingleThing";
4 |
5 | export function Things() {
6 | const currentThing = useCurrentThing();
7 | if (currentThing) {
8 | return ;
9 | }
10 | return ;
11 | }
12 |
--------------------------------------------------------------------------------
/ch09/things/src/view/View.jsx:
--------------------------------------------------------------------------------
1 | import { useUser } from "../data";
2 | import { Things } from "./Things";
3 | import { LoginSignup } from "./LoginSignup";
4 |
5 | export function View() {
6 | const hasUser = useUser();
7 | if (hasUser) {
8 | return ;
9 | }
10 | return ;
11 | }
12 |
--------------------------------------------------------------------------------
/ch09/things/src/view/index.js:
--------------------------------------------------------------------------------
1 | export { View } from "./View";
2 |
--------------------------------------------------------------------------------
/ch09/things/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 |
--------------------------------------------------------------------------------
/ch10/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 |
--------------------------------------------------------------------------------
/ch10/axios/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | axios from React in Depth
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch10/axios/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { StarshipList } from "./StarshipList";
2 |
3 | export default function App() {
4 | return ;
5 | }
6 |
--------------------------------------------------------------------------------
/ch10/axios/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch10/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 | test: { globals: true, environment: "jsdom" },
8 | });
9 |
--------------------------------------------------------------------------------
/ch10/click-counter/.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 |
--------------------------------------------------------------------------------
/ch10/click-counter/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { Counter } from "./Counter";
2 |
3 | export default function App() {
4 | return ;
5 | }
6 |
--------------------------------------------------------------------------------
/ch10/click-counter/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch10/click-counter/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 | test: { globals: true, environment: "jsdom" },
8 | });
9 |
--------------------------------------------------------------------------------
/ch10/dark-mode/.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 |
--------------------------------------------------------------------------------
/ch10/dark-mode/src/DarkModeContext.jsx:
--------------------------------------------------------------------------------
1 | import { createContext } from "use-context-selector";
2 |
3 | export const DarkModeContext = createContext({});
4 |
--------------------------------------------------------------------------------
/ch10/dark-mode/src/ToggleButton.jsx:
--------------------------------------------------------------------------------
1 | import { useContextSelector } from "use-context-selector";
2 | import { Button } from "./Button";
3 | import { DarkModeContext } from "./DarkModeContext";
4 |
5 | export function ToggleButton() {
6 | const toggleDarkMode = useContextSelector(
7 | DarkModeContext,
8 | (contextValue) => contextValue.toggleDarkMode
9 | );
10 | return ;
11 | }
12 |
--------------------------------------------------------------------------------
/ch10/dark-mode/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch10/dark-mode/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 | test: { globals: true, environment: "jsdom" },
8 | });
9 |
--------------------------------------------------------------------------------
/ch10/geo/.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 |
--------------------------------------------------------------------------------
/ch10/geo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | geo from React in Depth
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch10/geo/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { WhereAmI } from "./WhereAmI.jsx";
2 |
3 | export default function App() {
4 | return ;
5 | }
6 |
--------------------------------------------------------------------------------
/ch10/geo/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch10/geo/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 | test: { globals: true, environment: "jsdom" },
8 | });
9 |
--------------------------------------------------------------------------------
/ch10/keypress/.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 |
--------------------------------------------------------------------------------
/ch10/keypress/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { useIsKeyPressed } from "./useIsKeyPressed";
2 |
3 | export default function App() {
4 | const isShiftDown = useIsKeyPressed("Shift");
5 | return (
6 |
7 |
8 | is Shift currently pressed down?
9 |
10 | {isShiftDown ? "YES" : "NO"}
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/ch10/keypress/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch10/keypress/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 | test: { globals: true, environment: "jsdom" },
8 | });
9 |
--------------------------------------------------------------------------------
/ch10/menuitem-icon/.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 |
--------------------------------------------------------------------------------
/ch10/menuitem-icon/public/images/link.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch10/menuitem-icon/public/images/link.png
--------------------------------------------------------------------------------
/ch10/menuitem-icon/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { MenuItem } from "./MenuItem";
2 |
3 | export default function App() {
4 | return (
5 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/ch10/menuitem-icon/src/MenuItem.jsx:
--------------------------------------------------------------------------------
1 | export function MenuItem({ href, label }) {
2 | return (
3 |
4 |
5 |
6 | {label}
7 |
8 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/ch10/menuitem-icon/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch10/menuitem-icon/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 | test: { globals: true, environment: "jsdom" },
8 | });
9 |
--------------------------------------------------------------------------------
/ch10/menuitem/.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 |
--------------------------------------------------------------------------------
/ch10/menuitem/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { MenuItem } from "./MenuItem";
2 |
3 | export default function App() {
4 | return (
5 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/ch10/menuitem/src/MenuItem.jsx:
--------------------------------------------------------------------------------
1 | export function MenuItem({ href, label }) {
2 | return (
3 |
4 |
5 | {label}
6 |
7 |
8 | );
9 | }
10 |
--------------------------------------------------------------------------------
/ch10/menuitem/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch10/menuitem/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 | test: { globals: true, environment: "jsdom" },
8 | });
9 |
--------------------------------------------------------------------------------
/ch10/timer/.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 |
--------------------------------------------------------------------------------
/ch10/timer/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | timer from React in Depth
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch10/timer/src/App.jsx:
--------------------------------------------------------------------------------
1 | import "./style.css";
2 |
3 | import { TimerManager } from "./TimerManager";
4 |
5 | export default function App() {
6 | return (
7 |
8 | Countdown
9 |
10 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/ch10/timer/src/Button.jsx:
--------------------------------------------------------------------------------
1 | import { memo } from "react";
2 |
3 | export const Button = memo(function Button({ icon, label, ...rest }) {
4 | return (
5 |
8 | );
9 | });
10 |
--------------------------------------------------------------------------------
/ch10/timer/src/Number.jsx:
--------------------------------------------------------------------------------
1 | export function Number({ value, label }) {
2 | return (
3 |
4 | {String(value).padStart(2, "0")}
5 | {label}
6 |
7 | );
8 | }
9 |
--------------------------------------------------------------------------------
/ch10/timer/src/TimeDisplay.jsx:
--------------------------------------------------------------------------------
1 | import { Number } from "./Number";
2 |
3 | export function TimeDisplay({ time }) {
4 | const minutes = Math.floor(time / 60);
5 | const seconds = time % 60;
6 |
7 | return (
8 |
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/ch10/timer/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch10/timer/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 | test: { globals: true, environment: "jsdom" },
8 | });
9 |
--------------------------------------------------------------------------------
/ch10/todo/.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 |
--------------------------------------------------------------------------------
/ch10/todo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | todo from React in Depth
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch10/todo/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { Todo } from "./Todo";
2 |
3 | export default function App() {
4 | return ;
5 | }
6 |
--------------------------------------------------------------------------------
/ch10/todo/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch10/todo/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 | test: { globals: true, environment: "jsdom" },
8 | });
9 |
--------------------------------------------------------------------------------
/ch11/nextjs/.env:
--------------------------------------------------------------------------------
1 | NEXT_TELEMETRY_DISABLED=1
--------------------------------------------------------------------------------
/ch11/nextjs/.env.example:
--------------------------------------------------------------------------------
1 | OPENWEATHER_API_KEY=""
2 | DATABASE_URL="file:./data.db?connection_limit=1"
--------------------------------------------------------------------------------
/ch11/nextjs/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["next/babel", "next/core-web-vitals"]
3 | }
4 |
--------------------------------------------------------------------------------
/ch11/nextjs/components/index.js:
--------------------------------------------------------------------------------
1 | export { Swap } from "./swap";
2 | export { getWeatherImage } from "./getWeatherImage";
3 | export { CityCard } from "./cityCard";
4 | export { CityCardList } from "./cityCardList";
5 | export { CityDisplay } from "./cityDisplay";
6 | export { MyCity } from "./myCity";
7 |
--------------------------------------------------------------------------------
/ch11/nextjs/components/myCity.module.css:
--------------------------------------------------------------------------------
1 | .link {
2 | text-decoration: underline;
3 | }
4 |
--------------------------------------------------------------------------------
/ch11/nextjs/components/swap.js:
--------------------------------------------------------------------------------
1 | import Image from "next/image";
2 | import styles from "./swap.module.css";
3 |
4 | export function Swap({ title, ...rest }) {
5 | return (
6 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/ch11/nextjs/components/swap.module.css:
--------------------------------------------------------------------------------
1 | .swap {
2 | background: none;
3 | border: 0;
4 | padding: 0;
5 | cursor: pointer;
6 | position: relative;
7 | top: -0.8em;
8 | }
9 |
--------------------------------------------------------------------------------
/ch11/nextjs/format/context.js:
--------------------------------------------------------------------------------
1 | import { createContext } from "react";
2 |
3 | export const FormatContext = createContext({});
4 |
--------------------------------------------------------------------------------
/ch11/nextjs/format/index.js:
--------------------------------------------------------------------------------
1 | export { FormatProvider } from "./formatProvider";
2 | export { useTemperature } from "./useTemperature";
3 | export { useTime } from "./useTime";
4 |
--------------------------------------------------------------------------------
/ch11/nextjs/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "paths": {
4 | "@/*": ["./*"]
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/ch11/nextjs/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {}
3 |
4 | module.exports = nextConfig
5 |
--------------------------------------------------------------------------------
/ch11/nextjs/prisma/data.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/prisma/data.db
--------------------------------------------------------------------------------
/ch11/nextjs/prisma/migrations/20221119002453_uniquecity/migration.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Warnings:
3 |
4 | - A unique constraint covering the columns `[countryId,lowerName]` on the table `City` will be added. If there are existing duplicate values, this will fail.
5 |
6 | */
7 | -- CreateIndex
8 | CREATE UNIQUE INDEX "City_countryId_lowerName_key" ON "City"("countryId", "lowerName");
9 |
--------------------------------------------------------------------------------
/ch11/nextjs/prisma/migrations/20221119003016_namedindex/migration.sql:
--------------------------------------------------------------------------------
1 | -- This is an empty migration.
--------------------------------------------------------------------------------
/ch11/nextjs/prisma/migrations/migration_lock.toml:
--------------------------------------------------------------------------------
1 | # Please do not edit this file manually
2 | # It should be added in your version-control system (i.e. Git)
3 | provider = "sqlite"
--------------------------------------------------------------------------------
/ch11/nextjs/public/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/android-chrome-192x192.png
--------------------------------------------------------------------------------
/ch11/nextjs/public/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/android-chrome-512x512.png
--------------------------------------------------------------------------------
/ch11/nextjs/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/ch11/nextjs/public/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #da532c
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/ch11/nextjs/public/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/favicon-16x16.png
--------------------------------------------------------------------------------
/ch11/nextjs/public/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/favicon-32x32.png
--------------------------------------------------------------------------------
/ch11/nextjs/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/favicon.ico
--------------------------------------------------------------------------------
/ch11/nextjs/public/mstile-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/mstile-144x144.png
--------------------------------------------------------------------------------
/ch11/nextjs/public/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/mstile-150x150.png
--------------------------------------------------------------------------------
/ch11/nextjs/public/mstile-310x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/mstile-310x150.png
--------------------------------------------------------------------------------
/ch11/nextjs/public/mstile-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/mstile-310x310.png
--------------------------------------------------------------------------------
/ch11/nextjs/public/mstile-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/mstile-70x70.png
--------------------------------------------------------------------------------
/ch11/nextjs/public/weathers/cloudy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/weathers/cloudy.png
--------------------------------------------------------------------------------
/ch11/nextjs/public/weathers/dreary.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/weathers/dreary.png
--------------------------------------------------------------------------------
/ch11/nextjs/public/weathers/night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/weathers/night.png
--------------------------------------------------------------------------------
/ch11/nextjs/public/weathers/rainy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/weathers/rainy.png
--------------------------------------------------------------------------------
/ch11/nextjs/public/weathers/snowy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/weathers/snowy.png
--------------------------------------------------------------------------------
/ch11/nextjs/public/weathers/sunny.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/weathers/sunny.png
--------------------------------------------------------------------------------
/ch11/nextjs/public/weathers/thunder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/weathers/thunder.png
--------------------------------------------------------------------------------
/ch11/nextjs/public/weathers/windy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/weathers/windy.png
--------------------------------------------------------------------------------
/ch11/nextjs/services/cookies.js:
--------------------------------------------------------------------------------
1 | import { getCookie } from "cookies-next";
2 |
3 | export function getDefaultFormats(context) {
4 | const isCelsius = getCookie("nextjs-isCelsius", context);
5 | const hour12 = getCookie("nextjs-hour12", context);
6 | return {
7 | isCelsius: isCelsius !== "false",
8 | hour12: hour12 === "true",
9 | };
10 | }
11 |
--------------------------------------------------------------------------------
/ch11/remix/.env.example:
--------------------------------------------------------------------------------
1 | DATABASE_URL="file:./data.db?connection_limit=1"
2 | SESSION_SECRET="super-duper-s3cret"
3 | OPENWEATHER_API_KEY=""
4 |
--------------------------------------------------------------------------------
/ch11/remix/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
3 | /build
4 | /public/build
5 | .env
6 |
7 | /cypress/screenshots
8 | /cypress/videos
9 | /prisma/data.db
10 | /prisma/data.db-journal
11 |
12 | /app/styles/
--------------------------------------------------------------------------------
/ch11/remix/.prettierignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
3 | /build
4 | /public/build
5 | .env
6 |
7 | /app/styles/tailwind.css
8 |
--------------------------------------------------------------------------------
/ch11/remix/app/components/myCity.module.css:
--------------------------------------------------------------------------------
1 | .link {
2 | text-decoration: underline;
3 | }
4 |
--------------------------------------------------------------------------------
/ch11/remix/app/components/swap.module.css:
--------------------------------------------------------------------------------
1 | .button {
2 | background: none;
3 | border: 0;
4 | padding: 0;
5 | cursor: pointer;
6 | position: relative;
7 | top: -0.8em;
8 | }
9 | .form {
10 | display: inline;
11 | }
12 |
--------------------------------------------------------------------------------
/ch11/remix/app/cookies.server.js:
--------------------------------------------------------------------------------
1 | import { createCookie } from "@remix-run/node";
2 |
3 | const maxAge = 86_400 * 365; // one year
4 | export const temperatureCookie = createCookie("temperature", { maxAge });
5 | export const timeCookie = createCookie("time", { maxAge });
6 | export const myCityCookie = createCookie("myCity", { maxAge });
7 |
--------------------------------------------------------------------------------
/ch11/remix/app/db.server.ts:
--------------------------------------------------------------------------------
1 | import { PrismaClient } from "@prisma/client";
2 |
3 | import { singleton } from "./singleton.server";
4 |
5 | // Hard-code a unique key, so we can look up the client when this module gets re-imported
6 | const prisma = singleton("prisma", () => new PrismaClient());
7 | prisma.$connect();
8 |
9 | export { prisma };
10 |
--------------------------------------------------------------------------------
/ch11/remix/app/format/context.js:
--------------------------------------------------------------------------------
1 | import { createContext } from "react";
2 |
3 | const FormatContext = createContext({});
4 | export default FormatContext;
5 |
--------------------------------------------------------------------------------
/ch11/remix/app/format/index.js:
--------------------------------------------------------------------------------
1 | export { default as FormatProvider } from "./formatProvider";
2 | export { default as useTemperature } from "./useTemperature";
3 | export { default as useTime } from "./useTime";
4 |
--------------------------------------------------------------------------------
/ch11/remix/app/globals.json:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/ch11/remix/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {},
4 | },
5 | };
6 |
--------------------------------------------------------------------------------
/ch11/remix/prisma/migrations/migration_lock.toml:
--------------------------------------------------------------------------------
1 | # Please do not edit this file manually
2 | # It should be added in your version-control system (i.e. Git)
3 | provider = "sqlite"
--------------------------------------------------------------------------------
/ch11/remix/public/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/android-chrome-192x192.png
--------------------------------------------------------------------------------
/ch11/remix/public/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/android-chrome-512x512.png
--------------------------------------------------------------------------------
/ch11/remix/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/ch11/remix/public/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #da532c
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/ch11/remix/public/favicon copy.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/favicon copy.ico
--------------------------------------------------------------------------------
/ch11/remix/public/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/favicon-16x16.png
--------------------------------------------------------------------------------
/ch11/remix/public/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/favicon-32x32.png
--------------------------------------------------------------------------------
/ch11/remix/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/favicon.ico
--------------------------------------------------------------------------------
/ch11/remix/public/fonts/montserrat-v25-latin-100.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/fonts/montserrat-v25-latin-100.eot
--------------------------------------------------------------------------------
/ch11/remix/public/fonts/montserrat-v25-latin-100.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/fonts/montserrat-v25-latin-100.ttf
--------------------------------------------------------------------------------
/ch11/remix/public/fonts/montserrat-v25-latin-100.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/fonts/montserrat-v25-latin-100.woff
--------------------------------------------------------------------------------
/ch11/remix/public/fonts/montserrat-v25-latin-100.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/fonts/montserrat-v25-latin-100.woff2
--------------------------------------------------------------------------------
/ch11/remix/public/mstile-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/mstile-144x144.png
--------------------------------------------------------------------------------
/ch11/remix/public/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/mstile-150x150.png
--------------------------------------------------------------------------------
/ch11/remix/public/mstile-310x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/mstile-310x150.png
--------------------------------------------------------------------------------
/ch11/remix/public/mstile-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/mstile-310x310.png
--------------------------------------------------------------------------------
/ch11/remix/public/mstile-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/mstile-70x70.png
--------------------------------------------------------------------------------
/ch11/remix/public/weathers/cloudy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/weathers/cloudy.png
--------------------------------------------------------------------------------
/ch11/remix/public/weathers/dreary.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/weathers/dreary.png
--------------------------------------------------------------------------------
/ch11/remix/public/weathers/night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/weathers/night.png
--------------------------------------------------------------------------------
/ch11/remix/public/weathers/rainy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/weathers/rainy.png
--------------------------------------------------------------------------------
/ch11/remix/public/weathers/snowy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/weathers/snowy.png
--------------------------------------------------------------------------------
/ch11/remix/public/weathers/sunny.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/weathers/sunny.png
--------------------------------------------------------------------------------
/ch11/remix/public/weathers/thunder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/weathers/thunder.png
--------------------------------------------------------------------------------
/ch11/remix/public/weathers/windy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/weathers/windy.png
--------------------------------------------------------------------------------
/ch11/remix/remix.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('@remix-run/dev').AppConfig} */
2 | module.exports = {
3 | cacheDirectory: "./node_modules/.cache/remix",
4 | ignoredRouteFiles: ["**/.*", "**/*.test.{ts,tsx}"],
5 | serverModuleFormat: "cjs",
6 | };
7 |
--------------------------------------------------------------------------------
/ch11/remix/remix.env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
--------------------------------------------------------------------------------
/ch11/remix/test/setup-test-env.ts:
--------------------------------------------------------------------------------
1 | import { installGlobals } from "@remix-run/node";
2 | import "@testing-library/jest-dom/vitest";
3 |
4 | installGlobals();
5 |
--------------------------------------------------------------------------------
/ch12/backend-only/.env.example:
--------------------------------------------------------------------------------
1 | DATABASE_URL="file:./data.db?connection_limit=1"
2 | SESSION_SECRET="super-duper-s3cret"
--------------------------------------------------------------------------------
/ch12/backend-only/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
3 | /build
4 | /public/build
5 | .env
6 |
7 | /cypress/screenshots
8 | /cypress/videos
9 | /prisma/data.db
10 | /prisma/data.db-journal
11 |
12 | /app/styles/
--------------------------------------------------------------------------------
/ch12/backend-only/.prettierignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
3 | /build
4 | /public/build
5 | .env
6 |
--------------------------------------------------------------------------------
/ch12/backend-only/app/components/Body.module.css:
--------------------------------------------------------------------------------
1 | .body {
2 | background-color: #ddd;
3 | min-height: 100vh;
4 | display: flex;
5 | justify-content: center;
6 | padding: 1em;
7 | }
8 |
--------------------------------------------------------------------------------
/ch12/backend-only/app/components/Body.tsx:
--------------------------------------------------------------------------------
1 | import { PropsWithChildren } from "react";
2 |
3 | import styles from "./body.module.css";
4 |
5 | export function Body({ children }: PropsWithChildren) {
6 | return {children};
7 | }
8 |
--------------------------------------------------------------------------------
/ch12/backend-only/app/components/Main.module.css:
--------------------------------------------------------------------------------
1 | .main {
2 | background-color: #eee;
3 | border-radius: 1em;
4 | width: 80em;
5 | padding: 0.5em;
6 | }
7 |
--------------------------------------------------------------------------------
/ch12/backend-only/app/components/Main.tsx:
--------------------------------------------------------------------------------
1 | import { PropsWithChildren } from "react";
2 |
3 | import styles from "./main.module.css";
4 |
5 | export function Main({ children }: PropsWithChildren) {
6 | return {children};
7 | }
8 |
--------------------------------------------------------------------------------
/ch12/backend-only/app/db.server.ts:
--------------------------------------------------------------------------------
1 | import { PrismaClient } from "@prisma/client";
2 |
3 | import { singleton } from "./singleton.server";
4 |
5 | // Hard-code a unique key, so we can look up the client when this module gets re-imported
6 | const prisma = singleton("prisma", () => new PrismaClient());
7 | prisma.$connect();
8 |
9 | export { prisma };
10 |
--------------------------------------------------------------------------------
/ch12/backend-only/app/models/types.client.ts:
--------------------------------------------------------------------------------
1 | export type User = {
2 | id: string;
3 | email: string;
4 | name: string;
5 | categories: Category[];
6 | expenses: Expense[];
7 | };
8 |
9 | export type Category = {
10 | id: string;
11 | name: string;
12 | color: string;
13 | };
14 |
15 | export type Expense = {
16 | id: string;
17 | item: string;
18 | value: number;
19 | category: Omit;
20 | };
21 |
--------------------------------------------------------------------------------
/ch12/backend-only/app/routes/logout.tsx:
--------------------------------------------------------------------------------
1 | import type { ActionFunctionArgs } from "@remix-run/node";
2 | import { redirect } from "@remix-run/node";
3 |
4 | import { logout } from "~/session.server";
5 |
6 | export async function action({ request }: ActionFunctionArgs) {
7 | return logout(request);
8 | }
9 |
10 | export async function loader() {
11 | return redirect("/");
12 | }
13 |
--------------------------------------------------------------------------------
/ch12/backend-only/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {},
4 | },
5 | };
6 |
--------------------------------------------------------------------------------
/ch12/backend-only/prisma/migrations/migration_lock.toml:
--------------------------------------------------------------------------------
1 | # Please do not edit this file manually
2 | # It should be added in your version-control system (i.e. Git)
3 | provider = "sqlite"
--------------------------------------------------------------------------------
/ch12/backend-only/public/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/android-chrome-192x192.png
--------------------------------------------------------------------------------
/ch12/backend-only/public/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/android-chrome-512x512.png
--------------------------------------------------------------------------------
/ch12/backend-only/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/ch12/backend-only/public/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #da532c
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/ch12/backend-only/public/favicon copy.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/favicon copy.ico
--------------------------------------------------------------------------------
/ch12/backend-only/public/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/favicon-16x16.png
--------------------------------------------------------------------------------
/ch12/backend-only/public/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/favicon-32x32.png
--------------------------------------------------------------------------------
/ch12/backend-only/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/favicon.ico
--------------------------------------------------------------------------------
/ch12/backend-only/public/fonts/montserrat-v25-latin-100.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/fonts/montserrat-v25-latin-100.eot
--------------------------------------------------------------------------------
/ch12/backend-only/public/fonts/montserrat-v25-latin-100.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/fonts/montserrat-v25-latin-100.ttf
--------------------------------------------------------------------------------
/ch12/backend-only/public/fonts/montserrat-v25-latin-100.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/fonts/montserrat-v25-latin-100.woff
--------------------------------------------------------------------------------
/ch12/backend-only/public/fonts/montserrat-v25-latin-100.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/fonts/montserrat-v25-latin-100.woff2
--------------------------------------------------------------------------------
/ch12/backend-only/public/mstile-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/mstile-144x144.png
--------------------------------------------------------------------------------
/ch12/backend-only/public/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/mstile-150x150.png
--------------------------------------------------------------------------------
/ch12/backend-only/public/mstile-310x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/mstile-310x150.png
--------------------------------------------------------------------------------
/ch12/backend-only/public/mstile-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/mstile-310x310.png
--------------------------------------------------------------------------------
/ch12/backend-only/public/mstile-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/mstile-70x70.png
--------------------------------------------------------------------------------
/ch12/backend-only/public/weathers/cloudy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/weathers/cloudy.png
--------------------------------------------------------------------------------
/ch12/backend-only/public/weathers/dreary.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/weathers/dreary.png
--------------------------------------------------------------------------------
/ch12/backend-only/public/weathers/night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/weathers/night.png
--------------------------------------------------------------------------------
/ch12/backend-only/public/weathers/rainy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/weathers/rainy.png
--------------------------------------------------------------------------------
/ch12/backend-only/public/weathers/snowy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/weathers/snowy.png
--------------------------------------------------------------------------------
/ch12/backend-only/public/weathers/sunny.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/weathers/sunny.png
--------------------------------------------------------------------------------
/ch12/backend-only/public/weathers/thunder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/weathers/thunder.png
--------------------------------------------------------------------------------
/ch12/backend-only/public/weathers/windy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/weathers/windy.png
--------------------------------------------------------------------------------
/ch12/backend-only/remix.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('@remix-run/dev').AppConfig} */
2 | module.exports = {
3 | cacheDirectory: "./node_modules/.cache/remix",
4 | ignoredRouteFiles: ["**/.*", "**/*.test.{ts,tsx}"],
5 | serverModuleFormat: "cjs",
6 | };
7 |
--------------------------------------------------------------------------------
/ch12/backend-only/remix.env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
--------------------------------------------------------------------------------
/ch12/complete/.env.example:
--------------------------------------------------------------------------------
1 | DATABASE_URL="file:./data.db?connection_limit=1"
2 | SESSION_SECRET="super-duper-s3cret"
--------------------------------------------------------------------------------
/ch12/complete/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
3 | /build
4 | /public/build
5 | .env
6 |
7 | /cypress/screenshots
8 | /cypress/videos
9 | /prisma/data.db
10 | /prisma/data.db-journal
11 |
12 | /app/styles/
--------------------------------------------------------------------------------
/ch12/complete/.prettierignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
3 | /build
4 | /public/build
5 | .env
6 |
--------------------------------------------------------------------------------
/ch12/complete/app/components/Body.module.css:
--------------------------------------------------------------------------------
1 | .body {
2 | background-color: #ddd;
3 | min-height: 100vh;
4 | display: flex;
5 | justify-content: center;
6 | padding: 1em;
7 | }
8 |
--------------------------------------------------------------------------------
/ch12/complete/app/components/Body.tsx:
--------------------------------------------------------------------------------
1 | import { PropsWithChildren } from "react";
2 |
3 | import styles from "./Body.module.css";
4 |
5 | export function Body({ children }: PropsWithChildren) {
6 | return {children};
7 | }
8 |
--------------------------------------------------------------------------------
/ch12/complete/app/components/Dialog.module.css:
--------------------------------------------------------------------------------
1 | .background {
2 | position: fixed;
3 | inset: 0;
4 | background-color: rgba(0 0 0 / 0.5);
5 | }
6 |
7 | .dialog {
8 | position: absolute;
9 | inset: 1em 50%;
10 | background-color: white;
11 | padding: 1em;
12 | border-radius: 1em;
13 | --width: min(calc(100vw - 2em), 40em);
14 | width: var(--width);
15 | margin-left: calc(var(--width) / -2);
16 | }
17 |
--------------------------------------------------------------------------------
/ch12/complete/app/components/Dialog.tsx:
--------------------------------------------------------------------------------
1 | import { PropsWithChildren } from "react";
2 |
3 | import styles from "./Dialog.module.css";
4 |
5 | export function Dialog({ children }: PropsWithChildren) {
6 | return (
7 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/ch12/complete/app/components/Main.module.css:
--------------------------------------------------------------------------------
1 | .main {
2 | background-color: #eee;
3 | border-radius: 1em;
4 | width: 80em;
5 | padding: 0.5em;
6 | }
7 |
--------------------------------------------------------------------------------
/ch12/complete/app/components/Main.tsx:
--------------------------------------------------------------------------------
1 | import { PropsWithChildren } from "react";
2 |
3 | import styles from "./Main.module.css";
4 |
5 | export function Main({ children }: PropsWithChildren) {
6 | return {children};
7 | }
8 |
--------------------------------------------------------------------------------
/ch12/complete/app/db.server.ts:
--------------------------------------------------------------------------------
1 | import { PrismaClient } from "@prisma/client";
2 |
3 | import { singleton } from "./singleton.server";
4 |
5 | // Hard-code a unique key, so we can look up the client when this module gets re-imported
6 | const prisma = singleton("prisma", () => new PrismaClient());
7 | prisma.$connect();
8 |
9 | export { prisma };
10 |
--------------------------------------------------------------------------------
/ch12/complete/app/models/types.client.ts:
--------------------------------------------------------------------------------
1 | export type User = {
2 | id: string;
3 | email: string;
4 | name: string;
5 | categories: Category[];
6 | expenses: Expense[];
7 | };
8 |
9 | export type Category = {
10 | id: string;
11 | name: string;
12 | color: string;
13 | };
14 |
15 | export type Expense = {
16 | id: string;
17 | item: string;
18 | value: number;
19 | category: Omit;
20 | };
21 |
--------------------------------------------------------------------------------
/ch12/complete/app/routes/logout.tsx:
--------------------------------------------------------------------------------
1 | import type { ActionFunctionArgs } from "@remix-run/node";
2 | import { redirect } from "@remix-run/node";
3 |
4 | import { logout } from "~/session.server";
5 |
6 | export async function action({ request }: ActionFunctionArgs) {
7 | return logout(request);
8 | }
9 |
10 | export async function loader() {
11 | return redirect("/");
12 | }
13 |
--------------------------------------------------------------------------------
/ch12/complete/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {},
4 | },
5 | };
6 |
--------------------------------------------------------------------------------
/ch12/complete/prisma/migrations/migration_lock.toml:
--------------------------------------------------------------------------------
1 | # Please do not edit this file manually
2 | # It should be added in your version-control system (i.e. Git)
3 | provider = "sqlite"
--------------------------------------------------------------------------------
/ch12/complete/public/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/android-chrome-192x192.png
--------------------------------------------------------------------------------
/ch12/complete/public/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/android-chrome-512x512.png
--------------------------------------------------------------------------------
/ch12/complete/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/ch12/complete/public/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #da532c
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/ch12/complete/public/favicon copy.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/favicon copy.ico
--------------------------------------------------------------------------------
/ch12/complete/public/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/favicon-16x16.png
--------------------------------------------------------------------------------
/ch12/complete/public/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/favicon-32x32.png
--------------------------------------------------------------------------------
/ch12/complete/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/favicon.ico
--------------------------------------------------------------------------------
/ch12/complete/public/fonts/montserrat-v25-latin-100.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/fonts/montserrat-v25-latin-100.eot
--------------------------------------------------------------------------------
/ch12/complete/public/fonts/montserrat-v25-latin-100.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/fonts/montserrat-v25-latin-100.ttf
--------------------------------------------------------------------------------
/ch12/complete/public/fonts/montserrat-v25-latin-100.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/fonts/montserrat-v25-latin-100.woff
--------------------------------------------------------------------------------
/ch12/complete/public/fonts/montserrat-v25-latin-100.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/fonts/montserrat-v25-latin-100.woff2
--------------------------------------------------------------------------------
/ch12/complete/public/mstile-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/mstile-144x144.png
--------------------------------------------------------------------------------
/ch12/complete/public/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/mstile-150x150.png
--------------------------------------------------------------------------------
/ch12/complete/public/mstile-310x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/mstile-310x150.png
--------------------------------------------------------------------------------
/ch12/complete/public/mstile-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/mstile-310x310.png
--------------------------------------------------------------------------------
/ch12/complete/public/mstile-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/mstile-70x70.png
--------------------------------------------------------------------------------
/ch12/complete/public/weathers/cloudy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/weathers/cloudy.png
--------------------------------------------------------------------------------
/ch12/complete/public/weathers/dreary.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/weathers/dreary.png
--------------------------------------------------------------------------------
/ch12/complete/public/weathers/night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/weathers/night.png
--------------------------------------------------------------------------------
/ch12/complete/public/weathers/rainy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/weathers/rainy.png
--------------------------------------------------------------------------------
/ch12/complete/public/weathers/snowy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/weathers/snowy.png
--------------------------------------------------------------------------------
/ch12/complete/public/weathers/sunny.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/weathers/sunny.png
--------------------------------------------------------------------------------
/ch12/complete/public/weathers/thunder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/weathers/thunder.png
--------------------------------------------------------------------------------
/ch12/complete/public/weathers/windy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/weathers/windy.png
--------------------------------------------------------------------------------
/ch12/complete/remix.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('@remix-run/dev').AppConfig} */
2 | module.exports = {
3 | cacheDirectory: "./node_modules/.cache/remix",
4 | ignoredRouteFiles: ["**/.*", "**/*.test.{ts,tsx}"],
5 | serverModuleFormat: "cjs",
6 | };
7 |
--------------------------------------------------------------------------------
/ch12/complete/remix.env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
--------------------------------------------------------------------------------
/ch12/frontend-only/.env.example:
--------------------------------------------------------------------------------
1 | DATABASE_URL="file:./data.db?connection_limit=1"
2 | SESSION_SECRET="super-duper-s3cret"
--------------------------------------------------------------------------------
/ch12/frontend-only/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
3 | /build
4 | /public/build
5 | .env
6 |
7 | /cypress/screenshots
8 | /cypress/videos
9 | /prisma/data.db
10 | /prisma/data.db-journal
11 |
12 | /app/styles/
--------------------------------------------------------------------------------
/ch12/frontend-only/.prettierignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
3 | /build
4 | /public/build
5 | .env
6 |
--------------------------------------------------------------------------------
/ch12/frontend-only/app/components/Body.module.css:
--------------------------------------------------------------------------------
1 | .body {
2 | background-color: #ddd;
3 | min-height: 100vh;
4 | display: flex;
5 | justify-content: center;
6 | padding: 1em;
7 | }
8 |
--------------------------------------------------------------------------------
/ch12/frontend-only/app/components/Body.tsx:
--------------------------------------------------------------------------------
1 | import { PropsWithChildren } from "react";
2 |
3 | import styles from "./body.module.css";
4 |
5 | export function Body({ children }: PropsWithChildren) {
6 | return {children};
7 | }
8 |
--------------------------------------------------------------------------------
/ch12/frontend-only/app/components/Dialog.module.css:
--------------------------------------------------------------------------------
1 | .background {
2 | position: fixed;
3 | inset: 0;
4 | background-color: rgba(0 0 0 / 0.5);
5 | }
6 |
7 | .dialog {
8 | position: absolute;
9 | inset: 1em 50%;
10 | background-color: white;
11 | padding: 1em;
12 | border-radius: 1em;
13 | --width: min(calc(100vw - 2em), 40em);
14 | width: var(--width);
15 | margin-left: calc(var(--width) / -2);
16 | }
17 |
--------------------------------------------------------------------------------
/ch12/frontend-only/app/components/Dialog.tsx:
--------------------------------------------------------------------------------
1 | import { PropsWithChildren } from "react";
2 |
3 | import styles from "./Dialog.module.css";
4 |
5 | export function Dialog({ children }: PropsWithChildren) {
6 | return (
7 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/ch12/frontend-only/app/components/Main.module.css:
--------------------------------------------------------------------------------
1 | .main {
2 | background-color: #eee;
3 | border-radius: 1em;
4 | width: 80em;
5 | padding: 0.5em;
6 | }
7 |
--------------------------------------------------------------------------------
/ch12/frontend-only/app/components/Main.tsx:
--------------------------------------------------------------------------------
1 | import { PropsWithChildren } from "react";
2 |
3 | import styles from "./main.module.css";
4 |
5 | export function Main({ children }: PropsWithChildren) {
6 | return {children};
7 | }
8 |
--------------------------------------------------------------------------------
/ch12/frontend-only/app/db.server.ts:
--------------------------------------------------------------------------------
1 | import { PrismaClient } from "@prisma/client";
2 |
3 | import { singleton } from "./singleton.server";
4 |
5 | // Hard-code a unique key, so we can look up the client when this module gets re-imported
6 | const prisma = singleton("prisma", () => new PrismaClient());
7 | prisma.$connect();
8 |
9 | export { prisma };
10 |
--------------------------------------------------------------------------------
/ch12/frontend-only/app/routes/logout.tsx:
--------------------------------------------------------------------------------
1 | import type { ActionFunctionArgs } from "@remix-run/node";
2 | import { redirect } from "@remix-run/node";
3 |
4 | import { logout } from "~/session.server";
5 |
6 | export async function action({ request }: ActionFunctionArgs) {
7 | return logout(request);
8 | }
9 |
10 | export async function loader() {
11 | return redirect("/");
12 | }
13 |
--------------------------------------------------------------------------------
/ch12/frontend-only/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {},
4 | },
5 | };
6 |
--------------------------------------------------------------------------------
/ch12/frontend-only/prisma/migrations/migration_lock.toml:
--------------------------------------------------------------------------------
1 | # Please do not edit this file manually
2 | # It should be added in your version-control system (i.e. Git)
3 | provider = "sqlite"
--------------------------------------------------------------------------------
/ch12/frontend-only/public/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/android-chrome-192x192.png
--------------------------------------------------------------------------------
/ch12/frontend-only/public/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/android-chrome-512x512.png
--------------------------------------------------------------------------------
/ch12/frontend-only/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/ch12/frontend-only/public/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #da532c
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/ch12/frontend-only/public/favicon copy.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/favicon copy.ico
--------------------------------------------------------------------------------
/ch12/frontend-only/public/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/favicon-16x16.png
--------------------------------------------------------------------------------
/ch12/frontend-only/public/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/favicon-32x32.png
--------------------------------------------------------------------------------
/ch12/frontend-only/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/favicon.ico
--------------------------------------------------------------------------------
/ch12/frontend-only/public/fonts/montserrat-v25-latin-100.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/fonts/montserrat-v25-latin-100.eot
--------------------------------------------------------------------------------
/ch12/frontend-only/public/fonts/montserrat-v25-latin-100.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/fonts/montserrat-v25-latin-100.ttf
--------------------------------------------------------------------------------
/ch12/frontend-only/public/fonts/montserrat-v25-latin-100.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/fonts/montserrat-v25-latin-100.woff
--------------------------------------------------------------------------------
/ch12/frontend-only/public/fonts/montserrat-v25-latin-100.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/fonts/montserrat-v25-latin-100.woff2
--------------------------------------------------------------------------------
/ch12/frontend-only/public/mstile-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/mstile-144x144.png
--------------------------------------------------------------------------------
/ch12/frontend-only/public/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/mstile-150x150.png
--------------------------------------------------------------------------------
/ch12/frontend-only/public/mstile-310x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/mstile-310x150.png
--------------------------------------------------------------------------------
/ch12/frontend-only/public/mstile-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/mstile-310x310.png
--------------------------------------------------------------------------------
/ch12/frontend-only/public/mstile-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/mstile-70x70.png
--------------------------------------------------------------------------------
/ch12/frontend-only/public/weathers/cloudy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/weathers/cloudy.png
--------------------------------------------------------------------------------
/ch12/frontend-only/public/weathers/dreary.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/weathers/dreary.png
--------------------------------------------------------------------------------
/ch12/frontend-only/public/weathers/night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/weathers/night.png
--------------------------------------------------------------------------------
/ch12/frontend-only/public/weathers/rainy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/weathers/rainy.png
--------------------------------------------------------------------------------
/ch12/frontend-only/public/weathers/snowy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/weathers/snowy.png
--------------------------------------------------------------------------------
/ch12/frontend-only/public/weathers/sunny.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/weathers/sunny.png
--------------------------------------------------------------------------------
/ch12/frontend-only/public/weathers/thunder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/weathers/thunder.png
--------------------------------------------------------------------------------
/ch12/frontend-only/public/weathers/windy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/weathers/windy.png
--------------------------------------------------------------------------------
/ch12/frontend-only/remix.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('@remix-run/dev').AppConfig} */
2 | module.exports = {
3 | cacheDirectory: "./node_modules/.cache/remix",
4 | ignoredRouteFiles: ["**/.*", "**/*.test.{ts,tsx}"],
5 | serverModuleFormat: "cjs",
6 | };
7 |
--------------------------------------------------------------------------------
/ch12/frontend-only/remix.env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
--------------------------------------------------------------------------------
/ch12/skeleton/.env.example:
--------------------------------------------------------------------------------
1 | DATABASE_URL="file:./data.db?connection_limit=1"
2 | SESSION_SECRET="super-duper-s3cret"
--------------------------------------------------------------------------------
/ch12/skeleton/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
3 | /build
4 | /public/build
5 | .env
6 |
7 | /cypress/screenshots
8 | /cypress/videos
9 | /prisma/data.db
10 | /prisma/data.db-journal
11 |
12 | /app/styles/
--------------------------------------------------------------------------------
/ch12/skeleton/.prettierignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
3 | /build
4 | /public/build
5 | .env
6 |
--------------------------------------------------------------------------------
/ch12/skeleton/app/db.server.ts:
--------------------------------------------------------------------------------
1 | import { PrismaClient } from "@prisma/client";
2 |
3 | import { singleton } from "./singleton.server";
4 |
5 | // Hard-code a unique key, so we can look up the client when this module gets re-imported
6 | const prisma = singleton("prisma", () => new PrismaClient());
7 | prisma.$connect();
8 |
9 | export { prisma };
10 |
--------------------------------------------------------------------------------
/ch12/skeleton/app/routes/logout.tsx:
--------------------------------------------------------------------------------
1 | import type { ActionFunctionArgs } from "@remix-run/node";
2 | import { redirect } from "@remix-run/node";
3 |
4 | import { logout } from "~/session.server";
5 |
6 | export async function action({ request }: ActionFunctionArgs) {
7 | return logout(request);
8 | }
9 |
10 | export async function loader() {
11 | return redirect("/");
12 | }
13 |
--------------------------------------------------------------------------------
/ch12/skeleton/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {},
4 | },
5 | };
6 |
--------------------------------------------------------------------------------
/ch12/skeleton/prisma/migrations/migration_lock.toml:
--------------------------------------------------------------------------------
1 | # Please do not edit this file manually
2 | # It should be added in your version-control system (i.e. Git)
3 | provider = "sqlite"
--------------------------------------------------------------------------------
/ch12/skeleton/public/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/android-chrome-192x192.png
--------------------------------------------------------------------------------
/ch12/skeleton/public/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/android-chrome-512x512.png
--------------------------------------------------------------------------------
/ch12/skeleton/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/ch12/skeleton/public/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #da532c
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/ch12/skeleton/public/favicon copy.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/favicon copy.ico
--------------------------------------------------------------------------------
/ch12/skeleton/public/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/favicon-16x16.png
--------------------------------------------------------------------------------
/ch12/skeleton/public/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/favicon-32x32.png
--------------------------------------------------------------------------------
/ch12/skeleton/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/favicon.ico
--------------------------------------------------------------------------------
/ch12/skeleton/public/fonts/montserrat-v25-latin-100.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/fonts/montserrat-v25-latin-100.eot
--------------------------------------------------------------------------------
/ch12/skeleton/public/fonts/montserrat-v25-latin-100.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/fonts/montserrat-v25-latin-100.ttf
--------------------------------------------------------------------------------
/ch12/skeleton/public/fonts/montserrat-v25-latin-100.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/fonts/montserrat-v25-latin-100.woff
--------------------------------------------------------------------------------
/ch12/skeleton/public/fonts/montserrat-v25-latin-100.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/fonts/montserrat-v25-latin-100.woff2
--------------------------------------------------------------------------------
/ch12/skeleton/public/mstile-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/mstile-144x144.png
--------------------------------------------------------------------------------
/ch12/skeleton/public/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/mstile-150x150.png
--------------------------------------------------------------------------------
/ch12/skeleton/public/mstile-310x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/mstile-310x150.png
--------------------------------------------------------------------------------
/ch12/skeleton/public/mstile-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/mstile-310x310.png
--------------------------------------------------------------------------------
/ch12/skeleton/public/mstile-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/mstile-70x70.png
--------------------------------------------------------------------------------
/ch12/skeleton/public/weathers/cloudy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/weathers/cloudy.png
--------------------------------------------------------------------------------
/ch12/skeleton/public/weathers/dreary.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/weathers/dreary.png
--------------------------------------------------------------------------------
/ch12/skeleton/public/weathers/night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/weathers/night.png
--------------------------------------------------------------------------------
/ch12/skeleton/public/weathers/rainy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/weathers/rainy.png
--------------------------------------------------------------------------------
/ch12/skeleton/public/weathers/snowy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/weathers/snowy.png
--------------------------------------------------------------------------------
/ch12/skeleton/public/weathers/sunny.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/weathers/sunny.png
--------------------------------------------------------------------------------
/ch12/skeleton/public/weathers/thunder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/weathers/thunder.png
--------------------------------------------------------------------------------
/ch12/skeleton/public/weathers/windy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/weathers/windy.png
--------------------------------------------------------------------------------
/ch12/skeleton/remix.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('@remix-run/dev').AppConfig} */
2 | module.exports = {
3 | cacheDirectory: "./node_modules/.cache/remix",
4 | ignoredRouteFiles: ["**/.*", "**/*.test.{ts,tsx}"],
5 | serverModuleFormat: "cjs",
6 | };
7 |
--------------------------------------------------------------------------------
/ch12/skeleton/remix.env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
--------------------------------------------------------------------------------
/ch13/base/.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 | coverage
15 |
16 | # Editor directories and files
17 | .vscode/*
18 | !.vscode/extensions.json
19 | .idea
20 | .DS_Store
21 | *.suo
22 | *.ntvs*
23 | *.njsproj
24 | *.sln
25 | *.sw?
26 |
--------------------------------------------------------------------------------
/ch13/base/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | base from React in Depth
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch13/base/src/App.jsx:
--------------------------------------------------------------------------------
1 | export default function App() {
2 | return (
3 |
4 | Check storybook, please
5 |
6 | );
7 | }
8 |
--------------------------------------------------------------------------------
/ch13/base/src/library/button/index.js:
--------------------------------------------------------------------------------
1 | export { Button } from "./Button";
2 |
--------------------------------------------------------------------------------
/ch13/base/src/library/index.js:
--------------------------------------------------------------------------------
1 | export * from "./button";
2 |
--------------------------------------------------------------------------------
/ch13/base/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch13/base/vitest.setup.js:
--------------------------------------------------------------------------------
1 | import { setProjectAnnotations } from "@storybook/react";
2 | import * as globalStorybookConfig from "./.storybook/preview";
3 |
4 | setProjectAnnotations(globalStorybookConfig);
5 |
--------------------------------------------------------------------------------
/ch13/complete/.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 | coverage
15 |
16 | # Editor directories and files
17 | .vscode/*
18 | !.vscode/extensions.json
19 | .idea
20 | .DS_Store
21 | *.suo
22 | *.ntvs*
23 | *.njsproj
24 | *.sln
25 | *.sw?
26 |
--------------------------------------------------------------------------------
/ch13/complete/src/App.jsx:
--------------------------------------------------------------------------------
1 | export default function App() {
2 | return (
3 |
4 | Check storybook, please
5 |
6 | );
7 | }
8 |
--------------------------------------------------------------------------------
/ch13/complete/src/library/accordion/AccordionContext.jsx:
--------------------------------------------------------------------------------
1 | import { createContext } from "react";
2 |
3 | export const AccordionContext = createContext(null);
4 |
--------------------------------------------------------------------------------
/ch13/complete/src/library/accordion/index.js:
--------------------------------------------------------------------------------
1 | export { Accordion } from "./Accordion";
2 |
--------------------------------------------------------------------------------
/ch13/complete/src/library/button/index.js:
--------------------------------------------------------------------------------
1 | export { Button } from "./Button";
2 |
--------------------------------------------------------------------------------
/ch13/complete/src/library/index.js:
--------------------------------------------------------------------------------
1 | export * from "./accordion";
2 | export * from "./button";
3 | export * from "./switch";
4 | export * from "./toast";
5 |
--------------------------------------------------------------------------------
/ch13/complete/src/library/switch/index.js:
--------------------------------------------------------------------------------
1 | export { Switch } from "./Switch";
2 |
--------------------------------------------------------------------------------
/ch13/complete/src/library/toast/context.js:
--------------------------------------------------------------------------------
1 | import { createContext } from "react";
2 |
3 | export const ToastContext = createContext(null);
4 |
--------------------------------------------------------------------------------
/ch13/complete/src/library/toast/index.js:
--------------------------------------------------------------------------------
1 | export { useToast } from "./useToast";
2 | export { ToastProvider } from "./ToastProvider";
3 |
--------------------------------------------------------------------------------
/ch13/complete/src/library/toast/useToast.js:
--------------------------------------------------------------------------------
1 | import { useContext } from "react";
2 | import { ToastContext } from "./context";
3 |
4 | export function useToast() {
5 | return useContext(ToastContext);
6 | }
7 |
--------------------------------------------------------------------------------
/ch13/complete/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.jsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch13/complete/vitest.setup.js:
--------------------------------------------------------------------------------
1 | import { setProjectAnnotations } from "@storybook/react";
2 | import * as globalStorybookConfig from "./.storybook/preview";
3 |
4 | setProjectAnnotations(globalStorybookConfig);
5 |
--------------------------------------------------------------------------------
/ch14/wordle/.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 |
--------------------------------------------------------------------------------
/ch14/wordle/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | wordle from React in Depth
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch14/wordle/src/components/game/index.ts:
--------------------------------------------------------------------------------
1 | export { Game } from "./Game";
2 |
--------------------------------------------------------------------------------
/ch14/wordle/src/components/gamedata/index.ts:
--------------------------------------------------------------------------------
1 | export { GameDataProvider } from "./GameDataProvider";
2 | export { useGameData } from "./useGameData";
3 | export { useGameDialogs } from "./useGameDialogs";
4 |
--------------------------------------------------------------------------------
/ch14/wordle/src/components/gamedata/useGameData.ts:
--------------------------------------------------------------------------------
1 | import { useGameDataContext } from "./context";
2 |
3 | export function useGameData() {
4 | const { wordInfo, profile, updateState, showResults } =
5 | useGameDataContext();
6 |
7 | return {
8 | updateState,
9 | showResults,
10 | initialGrid: profile?.today.rows,
11 | word: wordInfo?.word || "",
12 | };
13 | }
14 |
--------------------------------------------------------------------------------
/ch14/wordle/src/components/gamedata/useGameDialogs.ts:
--------------------------------------------------------------------------------
1 | import { useGameDataContext } from "./context";
2 |
3 | export function useGameDialogs() {
4 | const { showResults, showWelcome } = useGameDataContext();
5 |
6 | return {
7 | showResults: () => showResults?.(),
8 | showWelcome: () => showWelcome?.(),
9 | };
10 | }
11 |
--------------------------------------------------------------------------------
/ch14/wordle/src/components/menu/index.ts:
--------------------------------------------------------------------------------
1 | export { Menu } from "./Menu";
2 |
--------------------------------------------------------------------------------
/ch14/wordle/src/components/overlay/index.ts:
--------------------------------------------------------------------------------
1 | export { OverlayProvider } from "./OverlayProvider";
2 | export { useAlert } from "./useAlert";
3 | export { useDialog } from "./useDialog";
4 |
--------------------------------------------------------------------------------
/ch14/wordle/src/components/overlay/useAlert.ts:
--------------------------------------------------------------------------------
1 | import { useOverlay } from "./context";
2 |
3 | export function useAlert() {
4 | return useOverlay().alert;
5 | }
6 |
--------------------------------------------------------------------------------
/ch14/wordle/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.tsx";
4 |
5 | ReactDOM.createRoot(document.getElementById("root")!).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/ch14/wordle/src/styles/Provider.tsx:
--------------------------------------------------------------------------------
1 | import { ThemeProvider } from "@emotion/react";
2 | import { PropsWithChildren } from "react";
3 | import { theme } from "./theme";
4 |
5 | export function StyleProvider({ children }: PropsWithChildren) {
6 | return {children};
7 | }
8 |
--------------------------------------------------------------------------------
/ch14/wordle/src/styles/emotion.d.ts:
--------------------------------------------------------------------------------
1 | import "@emotion/react";
2 | import { EmotionTheme } from "../types";
3 |
4 | declare module "@emotion/react" {
5 | export interface Theme extends EmotionTheme {}
6 | }
7 |
--------------------------------------------------------------------------------
/ch14/wordle/src/styles/index.ts:
--------------------------------------------------------------------------------
1 | export { StyleProvider } from "./Provider";
2 | export { theme } from "./theme";
3 | export { GlobalStyles } from "./GlobalStyles";
4 |
--------------------------------------------------------------------------------
/ch14/wordle/src/utils/getLabel.ts:
--------------------------------------------------------------------------------
1 | import { Status } from "../types";
2 |
3 | export function getLabel(label: string, status: Status) {
4 | if (status === Status.Unknown) {
5 | return label;
6 | }
7 | return [label, status].join(" ");
8 | }
9 |
--------------------------------------------------------------------------------
/ch14/wordle/src/utils/getToday.ts:
--------------------------------------------------------------------------------
1 | export function getToday(offset = 0) {
2 | const now = new Date();
3 | return new Date(
4 | now.getFullYear(),
5 | now.getMonth(),
6 | now.getDate() + offset
7 | ).getTime();
8 | }
9 |
10 | export function getYesterday() {
11 | return getToday(-1);
12 | }
13 |
14 | export function getTomorrow() {
15 | return getToday(1);
16 | }
17 |
--------------------------------------------------------------------------------
/ch14/wordle/src/utils/isValidWord.ts:
--------------------------------------------------------------------------------
1 | import { VALID_WORDS } from "./validWords";
2 |
3 | export function isValidWord(word: string) {
4 | return VALID_WORDS.includes(word);
5 | }
6 |
--------------------------------------------------------------------------------
/ch14/wordle/src/utils/localStorage.ts:
--------------------------------------------------------------------------------
1 | const CACHE_KEY = "JobReadyReact--Wordle";
2 |
3 | export function getData(): T | null {
4 | const data = localStorage.getItem(CACHE_KEY);
5 | if (data) {
6 | return JSON.parse(data) as T;
7 | }
8 | return null;
9 | }
10 |
11 | export function saveData(data: T) {
12 | localStorage.setItem(CACHE_KEY, JSON.stringify(data));
13 | }
14 |
--------------------------------------------------------------------------------
/ch14/wordle/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/ch14/wordle/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 |
--------------------------------------------------------------------------------
/ch14/wordle/vite.config.ts:
--------------------------------------------------------------------------------
1 | ///
2 | import { defineConfig } from "vite";
3 | import react from "@vitejs/plugin-react";
4 |
5 | // https://vitejs.dev/config/
6 | export default defineConfig({
7 | plugins: [react()],
8 | test: {
9 | include: ["**/*.test.tsx", "**/*.test.ts"],
10 | globals: true,
11 | },
12 | });
13 |
--------------------------------------------------------------------------------