Skip to content

Commit

Permalink
Replace references to CRA with Vite in writeup
Browse files Browse the repository at this point in the history
  • Loading branch information
wllmwu committed Apr 6, 2024
1 parent aaff985 commit 78a7b8f
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 75 deletions.
19 changes: 17 additions & 2 deletions frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,24 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
<meta name="theme-color" content="#0c2b35" />
<meta name="description" content="Demo webapp for new Triton Software Engineering developers" />
<title>TSE Todos</title>
<!-- Google fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="anonymous" />
<link
href="https://fonts.googleapis.com/css2?family=Rubik:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&display=swap"
rel="stylesheet"
/>
<!-- site favicon - based on output from realfavicongenerator.net -->
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="%PUBLIC_URL%/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="%PUBLIC_URL%/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="%PUBLIC_URL%/favicon-16x16.png" />
<link rel="mask-icon" href="%PUBLIC_URL%/safari-pinned-tab.svg" color="#16404f" />
<meta name="msapplication-TileColor" content="#00aba9" />
</head>
<body>
<div id="root"></div>
Expand Down
2 changes: 1 addition & 1 deletion writeup/Introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ Websites are rendered (displayed) in a browser through a combination of HTML, CS

However, it's tedious to write lots of individual HTML, CSS, and JS files. React makes development easier by **combining structure and functionality** under one unified JavaScript framework. See [Part 0](./part-0/) for some illustration with the files in the starter code.

We used [Create React App](https://create-react-app.dev) (CRA) to initialize our React project in the `frontend` folder. It can be quite involved to get React, TypeScript, and all the other packages to work together, but CRA takes care of that for us. Some of the frontend code, therefore, was auto-generated.
We used [Vite](https://vitejs.dev) to initialize our React project in the `frontend` folder. It can be quite involved to get React, TypeScript, and all the other packages to work together, but Vite takes care of that for us. Some of the frontend code, therefore, was auto-generated.

Alternatives to React include AngularJS and Vue.js.

Expand Down
24 changes: 18 additions & 6 deletions writeup/part-0/0-2-Clone.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ We're almost ready to run the project for the first time! Before we can do that,
```
PORT=3001
MONGODB_URI="mongodb://127.0.0.1:27017/todoList"
FRONTEND_ORIGIN="http://localhost:3000"
FRONTEND_ORIGIN="http://localhost:5173"
```
3. Create another `.env` in the `frontend` folder:
```
REACT_APP_API_BASE_URL="http://localhost:3001"
VITE_API_BASE_URL="http://localhost:3001"
```
<details>
Expand All @@ -67,6 +67,8 @@ _`.env` files are a standard way to provide environment variables to a program.

</details>

**Note:** In a Vite project like our frontend, all variable names in a `.env` file should [start with `VITE_`](https://vitejs.dev/guide/env-and-mode.html#env-files).

Finally, we can run our application! Follow the steps below to run both the frontend and backend. If you'd like to know more about some of the commands, see the next section. If anything fails and you can't figure out why, ping us in the **#onboarding** Slack channel.

1. Make sure MongoDB is running on your computer (see [Part 0.0](./0-0-Install.md)). You can leave it running after you're done working, or stop it and restart it when you come back.
Expand All @@ -79,15 +81,13 @@ Finally, we can run our application! Follow the steps below to run both the fron
```shell
npm start
```
4. In another instance of the command prompt (new tab or window), repeat the above steps for the frontend folder.
4. In another instance of the command prompt (new tab or window), start the frontend.
```shell
cd frontend
npm install
npm start
npm run dev
```

If the frontend is running correctly, your browser should open and display the Home page of our todo app.

If the backend is running correctly, you should see output like the following in your command prompt:

```
Expand All @@ -103,6 +103,18 @@ Mongoose connected!
Server running on 3001.
```

And if the frontend is running correctly, you should see output like the following:

```
VITE v5.2.8 ready in 498 ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
➜ press h + enter to show help
```

In your Internet browser, visit http://localhost:5173 and you should see the Home page of our todo app.

<details>
<summary><strong>🤔 For new developers: Running npm install</strong></summary>

Expand Down
4 changes: 2 additions & 2 deletions writeup/part-0/0-3-Explore.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ Let's trace the code path from `src/server.ts` to `src/controllers/task.ts` to u
### Frontend files

- [`package.json`](/frontend/package.json), like the one in the backend folder, **denotes a Node package.** Similarly, we also have a `package-lock.json` file and a `node_modules` folder.
- [`public/index.html`](/frontend/public/index.html) contains the actual HTML document **where React injects all of its generated HTML** in the browser. Since we write all our pages and components in React, this is the only HTML file in the entire project. The file itself was generated by CRA, and we added some extra code to download the Rubik font from Google Fonts and tell the browser where the site favicon is located. Most of the other files in the public folder are related to the favicon.
- [`src/index.tsx`](/frontend/src/index.tsx) is our **frontend's entry point.** It tells React where to inject our content in `index.html` and renders the `App` component from `src/App.tsx`.
- [`index.html`](/frontend/index.html) contains the actual HTML document **where React injects all of its generated HTML** in the browser. Since we write all our pages and components in React, this is the only HTML file needed in the entire project. The file itself was generated by Vite, and we added some extra code to download the Rubik font from Google Fonts and tell the browser where the site favicon is located.
- [`src/main.tsx`](/frontend/src/main.tsx) is our **frontend's entry point.** It tells React where to inject our content in `index.html` and renders the `App` component from `src/App.tsx`.
- [`src/App.tsx`](/frontend/src/App.tsx) is the **root of our React application** code, where we set up `react-router` with our frontend pages. Note that the "routes" in this file are different from our backend API routes—here, we map each page to its own URL for the purpose of client-side routing. In general, the only other code in `App.tsx` should be things that we want to make available to all parts of the application.
- [`src/pages`](/frontend/src/pages/) stores the **pages of our frontend.** We currently have two pages: Home and About. The Home page displays a form for creating new tasks, while the About page contains some simple text (mainly to demonstrate how to link to another page).
<details>
Expand Down
140 changes: 76 additions & 64 deletions writeup/part-1/1-1-Task-list.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,20 @@ _In a real project, we could use a route like this to search and sort/filter Tas
As you can see, the `TaskItem` component only has one prop, which is of type `Task`. We don't need any other information to render the component.

4. For later convenience, add the following line to `frontend/src/components/index.ts`:

```typescript
export { TaskItem } from "./TaskItem";
```

This allows us to import `TaskItem` from `"src/components"` together with other components, instead of individually specifying `"src/components/TaskItem"`.

<details>
<summary><strong>✅ Good practice: No barrel files</strong></summary>

_This `index.ts` file is known as a "barrel file." It's common to use these in order to simplify imports, but [Vite actually recommends against using them](https://vitejs.dev/guide/performance.html#avoid-barrel-files) for performance reasons. Maybe one day we'll get around to removing them from this repo._

</details>

5. First, we'll complete the structure of this component. It's mostly done already in the skeleton code (using divs and spans), but we need to display the data from the task object.
1. Fill in the placeholders to render `task.title` and `task.description`. Refer to `components/Button.tsx` for an example of how to render a string (the `label` variable in that case). Note that we use [JavaScript shortcutting to conditionally render](https://react.dev/learn/conditional-rendering#logical-and-operator-) the description.
2. Fill in the placeholder to render a `CheckButton` component. Refer to `components/TaskForm.tsx` for an example of how to use other custom components (`TextField` and `Button` in that case). For now, just pass in the prop `checked={task.isChecked}`the button won't do anything until [Part 1.2](./1-2-Task-checkoff.md).
Expand All @@ -176,72 +186,74 @@ _In a real project, we could use a route like this to search and sort/filter Tas
/>
```
Also add `TaskItem` to the import from `"src/components"`.
7. Start the frontend if it's not already running and open http://localhost:3000. You should see a check mark, "My title", and "My description" somewhere on the page, although it won't look like the design yet.
7. Start the frontend if it's not already running and open http://localhost:5173. You should see a check mark, "My title", and "My description" somewhere on the page, although it won't look like the design yet.
8. Next, we'll implement styles for `TaskItem`. With CSS Modules, we add styles by writing a CSS class (such as `.exampleClass`) in `TaskItem.module.css`, then assigning it to a particular React element using the prop `className={styles.exampleClass}`. Refer to `components/TextField.tsx` and the corresponding `TextField.module.css` for an example.

There are many valid approaches to writing CSSwe'll use flexbox layout, which is highly versatile. Note that the `<div>`s in `TaskItem.tsx` correspond directly to the frame elements within a `TaskItem` in Figma.

1. Copy the following CSS class for the **outermost** `<div>` into `TaskItem.module.css`, then add the corresponding `className` prop (`className={styles.item}`) to that `<div>` in `TaskItem.tsx`.

```css
.item {
height: 3rem;
border-bottom: 1px solid var(--color-text-secondary);
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
column-gap: 0.25rem;
}
```

This sets the `<div>` to use flexbox layout, have its content axis in the row direction (so its children will be laid out side-by-side), center its children on the cross axis (so they will be vertically centered), and add a gap of 0.25rem (4px) between children. Refer to the [CSS-Tricks flexbox guide](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) or the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/CSS/flex-direction) for more information on each property and its possible values.

2. Add another CSS class for the **inner** `<div>`, which contains the title and description labels. It should be similar to the previous class, but we want the children to be laid out in the column direction (vertical), to be centered vertically, and to stretch out as much as possible horizontally. We also want the `<div>` itself to take up all remaining space in the parent `<div>` and to have a bottom border. You can copy and fill in the template below.

```css
.textContainer {
height: 100%;
flex-grow: ???;
display: flex;
flex-direction: ???;
justify-content: ???;
align-items: ???;
overflow: hidden;
}
.textContainer span {
width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
```

Remember to add the new `className` prop in `TaskItem.tsx` as well.
<details>
<summary><strong>❓ Hint: Truncating overflowing text</strong></summary>

_It can be surprisingly complicated to truncate overflowing text using only CSS. The `.textContainer span` styles in the above code block achieve this in combination with the `overflow: hidden;` on `.textContainer`. This may come in handy when implementing other components! (Credit to this [CSS-Tricks snippet](https://css-tricks.com/snippets/css/truncate-string-with-ellipsis/) and this particular [comment](https://css-tricks.com/snippets/css/truncate-string-with-ellipsis/#comment-1607839).)_
</details>

3. Add two more CSS classes, one for the title label and one for the description label. For both, you only need to set the font property using one of the app fonts in `globals.css`. The `TaskItem` title uses the label font and the description uses the body font. Here's CSS for the title:
```css
.title {
font: var(--font-label);
}
```
Follow the same pattern for the description label. Apply these classes to the corresponding `<span>` elements in `TaskItem.tsx`.
4. Add one last CSS class which will adjust the appearance when the task is checked. Currently, all we need is to change the text color to --color-text-secondary.
```css
.checked {
color: var(--color-text-secondary);
}
```
Refactor the `className` on the text container `<div>` to work as follows: if `task.isChecked`, then use `styles.textContainer + " " + styles.checked`; else, use `styles.textContainer`. See `components/TextField.tsx` for one way to do this.

9. View the temporary `TaskItem` on the Home page. It should look like the Figma design now, besides possibly the width. Edit the fake `Task` in `pages/Home.tsx` to test all 4 variations of the `TaskItem` (this is part of "manual testing"). If something still looks wrong and you can't figure out the problem, ping us in **#onboarding** on Slack.
10. When you're done testing, remove the temporary `TaskItem` from the Home page. Be sure to remove it from the imports too.
There are many valid approaches to writing CSSwe'll use flexbox layout, which is highly versatile. Note that the `<div>`s in `TaskItem.tsx` correspond directly to the frame elements within a `TaskItem` in Figma.

1. Copy the following CSS class for the **outermost** `<div>` into `TaskItem.module.css`, then add the corresponding `className` prop (`className={styles.item}`) to that `<div>` in `TaskItem.tsx`.

```css
.item {
height: 3rem;
border-bottom: 1px solid var(--color-text-secondary);
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
column-gap: 0.25rem;
}
```

This sets the `<div>` to use flexbox layout, have its content axis in the row direction (so its children will be laid out side-by-side), center its children on the cross axis (so they will be vertically centered), and add a gap of 0.25rem (4px) between children. Refer to the [CSS-Tricks flexbox guide](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) or the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/CSS/flex-direction) for more information on each property and its possible values.

2. Add another CSS class for the **inner** `<div>`, which contains the title and description labels. It should be similar to the previous class, but we want the children to be laid out in the column direction (vertical), to be centered vertically, and to stretch out as much as possible horizontally. We also want the `<div>` itself to take up all remaining space in the parent `<div>` and to have a bottom border. You can copy and fill in the template below.

```css
.textContainer {
height: 100%;
flex-grow: ???;
display: flex;
flex-direction: ???;
justify-content: ???;
align-items: ???;
overflow: hidden;
}
.textContainer span {
width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
```

Remember to add the new `className` prop in `TaskItem.tsx` as well.
<details>
<summary><strong>❓ Hint: Truncating overflowing text</strong></summary>

_It can be surprisingly complicated to truncate overflowing text using only CSS. The `.textContainer span` styles in the above code block achieve this in combination with the `overflow: hidden;` on `.textContainer`. This may come in handy when implementing other components! (Credit to this [CSS-Tricks snippet](https://css-tricks.com/snippets/css/truncate-string-with-ellipsis/) and this particular [comment](https://css-tricks.com/snippets/css/truncate-string-with-ellipsis/#comment-1607839).)_
</details>

3. Add two more CSS classes, one for the title label and one for the description label. For both, you only need to set the font property using one of the app fonts in `globals.css`. The `TaskItem` title uses the label font and the description uses the body font. Here's CSS for the title:
```css
.title {
font: var(--font-label);
}
```
Follow the same pattern for the description label. Apply these classes to the corresponding `<span>` elements in `TaskItem.tsx`.
4. Add one last CSS class which will adjust the appearance when the task is checked. Currently, all we need is to change the text color to --color-text-secondary.

```css
.checked {
color: var(--color-text-secondary);
}
```

Refactor the `className` on the text container `<div>` to work as follows: if `task.isChecked`, then use `styles.textContainer + " " + styles.checked`; else, use `styles.textContainer`. See `components/TextField.tsx` for one way to do this.

5. View the temporary `TaskItem` on the Home page. It should look like the Figma design now, besides possibly the width. Edit the fake `Task` in `pages/Home.tsx` to test all 4 variations of the `TaskItem` (this is part of "manual testing"). If something still looks wrong and you can't figure out the problem, ping us in **#onboarding** on Slack.
6. When you're done testing, remove the temporary `TaskItem` from the Home page. Be sure to remove it from the imports too.

## New component: `TaskList`

Expand Down

0 comments on commit 78a7b8f

Please sign in to comment.