Skip to content

Commit 7cc3697

Browse files
committed
first commit
0 parents  commit 7cc3697

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+2665
-0
lines changed

exercise/01-intialize-remix/README.md

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# 01. Initialize Remix
2+
3+
You can initialize a Remix project using the [create-remix CLI](https://remix.run/docs/en/main/other-api/create-remix)
4+
5+
```
6+
npx create-remix@latest
7+
```
8+
9+
Next, go to the project directory and launch
10+
11+
Congratulation! you have your application available on http://localhost:3000

exercise/02-deploy/README.md

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# 02. Deploy
2+
3+
run build script for production build
4+
5+
```
6+
npm run build
7+
```
8+
9+
Once the project built, you can launch the server and access to the Remix web application
10+
11+
```
12+
npm run start
13+
```
14+
15+
Remix is **platform agnostic**. When you build a Remix application, it produces 2 folders inside the `build` folder:
16+
17+
- **client**: it contains all public files (script, styles, assets, etc.) that can be downloaded by the browser
18+
- **server**: it has the modules that contains the functions handlers. It's just a brunch of JavaScript functions
19+
20+
Remix don't produce a server! So you still need a server that calls the server handlers. `@remix-run/serve`
21+
provides a production ready express based server.
22+
23+
```
24+
npx remix-serve ./build/server/index.js
25+
```
26+
27+
And that exactly what is in the `start` command. You can find it in the `package.json`.

exercise/03-routing/README.md

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# 03. Routing
2+
3+
Remix is a file based routing which means that the url is based on the file name. Each route is specified by
4+
a file located in `app/routes`. The displayed component need to be default exported.
5+
6+
For our pizza app, we need 2 pages: the first one is where the user specify the pizza size and toppings,
7+
the second is used to display a confirmation message.
8+
9+
Replace the template `app/routes/_index.tsx`
10+
11+
```jsx
12+
export default function Index() {
13+
return (
14+
<main>
15+
<h2>Remixez votre pizza</h2>
16+
{/* TODO: size and toppings selection */}
17+
</main>
18+
);
19+
}
20+
```
21+
22+
create a file `app/routes/confirmation.tsx`
23+
24+
```jsx
25+
export default function Confirmation() {
26+
return (
27+
<main>
28+
<h2>Merci pour votre commande</h2>
29+
<p>
30+
Votre pizza sera prête dans quelques minutes. Vous serez notifié une
31+
fois que c&apos;est pr&ecirc;t.
32+
</p>
33+
<a href="/">Lancer une nouvelle commande</a>
34+
</main>
35+
);
36+
}
37+
```
38+
39+
If you want to learn more on the convention used by Remix, you can check the
40+
[visualization](https://interactive-remix-routing-v2.netlify.app) done by Dilum Sanjaya.

exercise/04-tailwind/README.md

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# 04. Tailwind
2+
3+
Since Remix uses Vite, most of the setup of Tailwind CSS is the same as setup it on Vite project.
4+
5+
```
6+
npm install -D tailwindcss postcss autoprefixer
7+
npx tailwindcss init --ts -p
8+
```
9+
10+
In `tailwind.config.ts`, add the paths of the template files
11+
12+
```typescript
13+
import type { Config } from 'tailwindcss'
14+
15+
export default {
16+
content: ['./app/**/*.{js,jsx,ts,tsx}'], // Add the template files
17+
theme: {
18+
extend: {},
19+
},
20+
plugins: [],
21+
} satisfies Config
22+
```
23+
24+
Create `./app/tailwind.css` and add the tailwind directives
25+
26+
```css
27+
@tailwind base;
28+
@tailwind components;
29+
@tailwind utilities;
30+
```
31+
32+
In `./app/root.tsx` import the newly-created `./app/tailwind.css` file
33+
34+
```typescript
35+
import type { LinksFunction } from "@remix-run/node";
36+
import stylesheet from "~/tailwind.css?url";
37+
38+
export const links: LinksFunction = () => [
39+
{ rel: "stylesheet", href: stylesheet },
40+
];
41+
```
42+
43+
And that's it!
44+
45+
For more integration like css-in-js solutions, you can check the
46+
[examples repository](https://github.com/remix-run/examples).

exercise/05-form/README.md

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# 05. Form
2+
3+
The customer need to select the pizza size and the toppings.
4+
5+
The Remix way for managing user interaction is the html way of doing.
6+
7+
In `app/routes/_index.tsx`, create a form that contains radio input for size selection and
8+
checkbox inputs for toppings selection.
9+
10+
```jsx
11+
<h2>Remixez votre pizza</h2>
12+
13+
<form method="POST">
14+
<fieldset>
15+
<legend>Selectionnez la taille</legend>
16+
17+
<label htmlFor="small">
18+
<input id="small" type="radio" name="size" value="small" />
19+
Small
20+
</label>
21+
22+
<label htmlFor="medium">
23+
<input id="medium" type="radio" name="size" value="medium" />
24+
Medium
25+
</label>
26+
27+
<label htmlFor="large">
28+
<input id="large" type="radio" name="size" value="large" />
29+
Large
30+
</label>
31+
</fieldset>
32+
33+
<fieldset>
34+
<legend>Choisissez votre garniture</legend>
35+
36+
<label htmlFor="anchovy">
37+
<input
38+
id="anchovy"
39+
type="checkbox"
40+
name="toppings"
41+
value="anchovy"
42+
/>
43+
Anchois
44+
</label>
45+
46+
{/* do the same and create checkboxes for: bacon, basil, chili, mozzarella, mushroom, olive, onion, pepper, pepperoni, sweetcorn, tomato */}
47+
48+
<button type="submit">Commander</button>
49+
</form>
50+
```

exercise/06-action/README.md

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# 06. Action
2+
3+
Once the form is submitted, an HTTP POST is sent to the current url but since there is a parent route
4+
for the index page (which is `root.tsx`) and Remix cannot just use the url to know which file should
5+
handle the request, we need to help Remix to figure this out.
6+
7+
update the form tag to have `action="?index"`
8+
9+
```jsx
10+
<form method="POST" action="?index">
11+
```
12+
13+
Now, to handle the form submition, export a function named action. Remix will automatically call the function on
14+
POST call (non GET) on the corresponding url.
15+
16+
```typescript
17+
export function action() {
18+
console.log('form submitted !');
19+
return null;
20+
}
21+
```
22+
23+
The action function can have the request informations as argument. The request contains the user form inputs.
24+
25+
Let use it to log the command.
26+
27+
```typescript
28+
let nextOrderId = 0;
29+
30+
export async function action() {
31+
const form = await request.formData();
32+
const size = form.get('size');
33+
const toppings = form.getAll('toppings');
34+
35+
const orderId = nextOrderId++;
36+
37+
console.log(
38+
`[order #${orderId}] Ordering a ${size} pizza` +
39+
(toppings.length > 0 ? ` with ${toppings.join(', ')}!` : '')
40+
);
41+
42+
return null;
43+
}
44+
```
45+
46+
The returned value will be sent as an HTTP Response. We can construct and return a Response object.
47+
Construct and return a Response with `302` status to redirect to the confirmation page. This will interpreted
48+
by the browser.
49+
50+
```typescript
51+
export async function action() {
52+
// ...
53+
return new Response(null, {
54+
status: 302,
55+
headers: {
56+
Location: `/confirmation?orderId=${orderId}`,
57+
},
58+
});
59+
}
60+
```
61+
62+
Remix provide a helper function that shorten all of this.
63+
64+
```typescript
65+
export async function action() {
66+
// ...
67+
return redirect(`/confirmation?orderId=${orderId}`);
68+
}
69+
```
70+
71+
TODO: validation

exercise/07-loader/README.md

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# 07. Loader
2+
3+
```typescript
4+
export function loader({ request }: LoaderFunctionArgs) {
5+
const url = new URL(request.url);
6+
const orderId = url.searchParams.get('orderId');
7+
8+
if (!orderId) {
9+
throw new Response('Missing orderId', { status: 400 });
10+
}
11+
12+
return { orderId };
13+
}
14+
```
15+
16+
```tsx
17+
export default function Confirmation() {
18+
const { orderId } = useLoaderData<typeof loader>();
19+
20+
return (
21+
<main>
22+
<h2>Merci pour votre commande</h2>
23+
<p>Commande n° {orderId}</p>
24+
<p>
25+
Votre pizza sera prête dans quelques minutes. Vous serez notifié une
26+
fois que c&apos;est pr&ecirc;t.
27+
</p>
28+
<a href="/">Lancer une nouvelle commande</a>
29+
</main>
30+
);
31+
}
32+
```
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# 09. Progressive Enhanced
2+
3+
```jsx
4+
<Form method="POST" action="?index">
5+
```
6+
7+
```tsx
8+
export default function Confirmation() {
9+
// ...
10+
11+
return (
12+
<main>
13+
{/* ... */}
14+
<Link to="/">Lancer une nouvelle commande</a>
15+
</main>
16+
);
17+
}
18+
```

exercise/09-ui/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# 09. UI
2+
3+
Copy `app/components` and `public` folders

0 commit comments

Comments
 (0)