-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3340e9b
commit a834cf2
Showing
24 changed files
with
12,422 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
node_modules | ||
|
||
/.cache | ||
/build | ||
/public/build | ||
.env | ||
/app/tailwind.css |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# WIP Remix site | ||
|
||
This is the site we implemented in lesson 3 based on [this video tutorial by Brad Traversy](https://www.youtube.com/watch?v=d_BhzHVV4aQ), although swapping in [lowdb](https://github.com/typicode/lowdb) as a simpler alternative to setting up Prisma and SQLite. | ||
|
||
The original README follows below. | ||
|
||
--- | ||
|
||
# Welcome to Remix! | ||
|
||
- [Remix Docs](https://remix.run/docs) | ||
|
||
## Development | ||
|
||
From your terminal: | ||
|
||
```sh | ||
npm run dev | ||
``` | ||
|
||
This starts your app in development mode, rebuilding assets on file changes. | ||
|
||
## Deployment | ||
|
||
First, build your app for production: | ||
|
||
```sh | ||
npm run build | ||
``` | ||
|
||
Then run the app in production mode: | ||
|
||
```sh | ||
npm start | ||
``` | ||
|
||
Now you'll need to pick a host to deploy it to. | ||
|
||
### DIY | ||
|
||
If you're familiar with deploying node applications, the built-in Remix app server is production-ready. | ||
|
||
Make sure to deploy the output of `remix build` | ||
|
||
- `build/` | ||
- `public/build/` | ||
|
||
### Using a Template | ||
|
||
When you ran `npx create-remix@latest` there were a few choices for hosting. You can run that again to create a new project, then copy over your `app/` folder to the new project that's pre-configured for your target server. | ||
|
||
```sh | ||
cd .. | ||
# create a new project, and pick a pre-configured host | ||
npx create-remix@latest | ||
cd my-new-remix-app | ||
# remove the new project's app (not the old one!) | ||
rm -rf app | ||
# copy your app over | ||
cp -R ../my-old-remix-app/app app | ||
``` |
21 changes: 21 additions & 0 deletions
21
lesson-05/remix-shopping-with-api/app/components/Breadcrumb.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { Link } from "remix"; | ||
|
||
export default function Breadcrumb({ links = [] }) { | ||
import React from "react"; | ||
const breadcrumbs = [{ to: "/", title: "Home" }, ...links]; | ||
|
||
return ( | ||
<nav className="mb-4 text-sm font-semibold"> | ||
{breadcrumbs.map((link, i) => ( | ||
<React.Fragment key={i}> | ||
{i !== 0 && ( | ||
<span className="inline-block mx-2 text-gray-400">/</span> | ||
)} | ||
<Link to={link.to} className="text-blue-700 hover:underline"> | ||
{link.title} | ||
</Link> | ||
</React.Fragment> | ||
))} | ||
</nav> | ||
); | ||
} |
13 changes: 13 additions & 0 deletions
13
lesson-05/remix-shopping-with-api/app/components/Button.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { Link } from "remix"; | ||
|
||
export default function Button({ type, destructive = false, children }) { | ||
let className = `${ | ||
destructive ? "bg-red-500" : "bg-blue-500" | ||
} text-white font-bold py-2 px-4 rounded my-3 inline-block`; | ||
|
||
return ( | ||
<button className={className} type={type}> | ||
{children} | ||
</button> | ||
); | ||
} |
11 changes: 11 additions & 0 deletions
11
lesson-05/remix-shopping-with-api/app/components/LinkButton.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { Link } from "remix"; | ||
|
||
export default function Button({ to, children }) { | ||
return ( | ||
<Link | ||
className="bg-blue-500 text-white font-bold py-2 px-4 rounded my-3 inline-block" | ||
to={to}> | ||
{children} | ||
</Link> | ||
); | ||
} |
13 changes: 13 additions & 0 deletions
13
lesson-05/remix-shopping-with-api/app/components/PageHeader.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
export default function PageHeader({ title, subtitle, children }) { | ||
return ( | ||
<div className="flex items-center justify-between mb-5"> | ||
<div> | ||
<h1 className="text-2xl font-bold">{title}</h1> | ||
{subtitle && ( | ||
<h2 className="font-semibold text-gray-400">{subtitle}</h2> | ||
)} | ||
</div> | ||
{children} | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{ | ||
"products": [ | ||
{ | ||
"id": "1", | ||
"title": "Small suitcase", | ||
"description": "The smallest we have." | ||
}, | ||
{ | ||
"id": "2", | ||
"title": "Medium suitcase", | ||
"description": "A decent size." | ||
}, | ||
{ | ||
"id": "3", | ||
"title": "Large suitcase", | ||
"description": "If you have a lot of stuff." | ||
} | ||
] | ||
} |
9 changes: 9 additions & 0 deletions
9
lesson-05/remix-shopping-with-api/app/db/luggage/db.server.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import path from "path"; | ||
import { JSONFileSync, LowSync } from "lowdb"; | ||
|
||
const file = path.join(__dirname, "../app/db/luggage/db.json"); | ||
const adapter = new JSONFileSync(file); | ||
const db = new LowSync(adapter); | ||
|
||
db.read(); | ||
export default db; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import { hydrate } from "react-dom"; | ||
import { RemixBrowser } from "remix"; | ||
|
||
hydrate(<RemixBrowser />, document); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { renderToString } from "react-dom/server"; | ||
import { RemixServer } from "remix"; | ||
|
||
export default function handleRequest( | ||
request, | ||
responseStatusCode, | ||
responseHeaders, | ||
remixContext | ||
) { | ||
const markup = renderToString( | ||
<RemixServer context={remixContext} url={request.url} /> | ||
); | ||
|
||
responseHeaders.set("Content-Type", "text/html"); | ||
|
||
return new Response("<!DOCTYPE html>" + markup, { | ||
status: responseStatusCode, | ||
headers: responseHeaders, | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
import { | ||
Link, | ||
NavLink, | ||
Outlet, | ||
LiveReload, | ||
Links, | ||
Meta, | ||
Scripts, | ||
useCatch, | ||
} from "remix"; | ||
import styles from "~/tailwind.css"; | ||
|
||
export const links = () => [ | ||
{ | ||
rel: "stylesheet", | ||
href: styles, | ||
}, | ||
]; | ||
|
||
export const meta = () => ({ | ||
description: "A collection of great recipes", | ||
keywords: "cooking, food, recipes", | ||
}); | ||
|
||
export default function App() { | ||
return ( | ||
<Document title="Remixed Recipes"> | ||
<Layout> | ||
<Outlet /> | ||
</Layout> | ||
</Document> | ||
); | ||
} | ||
|
||
function Document({ children, title }) { | ||
return ( | ||
<html lang="en"> | ||
<head> | ||
<meta charSet="utf-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1" /> | ||
<Meta /> | ||
<Links /> | ||
<title>{title}</title> | ||
</head> | ||
<body className="bg-slate-100 text-gray-800"> | ||
{children} | ||
{process.env.NODE_ENV === "development" ? <LiveReload /> : null} | ||
<Scripts /> | ||
</body> | ||
</html> | ||
); | ||
} | ||
|
||
function Layout({ children }) { | ||
return ( | ||
<> | ||
<header className="container mx-auto"> | ||
<nav className="text-left"> | ||
<Link to="/" className="group transition-colors mt-5 mb-6 block"> | ||
<span className="block font-extrabold text-4xl text-amber-500 group-hover:text-orange-400 "> | ||
Kablamazon | ||
</span> | ||
<span className="block font-semibold italic text-gray-400 group-hover:text-orange-400 "> | ||
Shop for anything | ||
</span> | ||
</Link> | ||
</nav> | ||
</header> | ||
<div className="container mx-auto flex flex-row"> | ||
<nav className="bg-gray-50 border border-gray-200 rounded mr-6 shadow-inner"> | ||
<MenuLink to="/luggage">Luggage</MenuLink> | ||
<MenuLink to="/books">Books</MenuLink> | ||
<MenuLink to="/electronics">Electronics</MenuLink> | ||
<MenuLink to="/computers">Computers</MenuLink> | ||
<MenuLink to="/toys">Toys</MenuLink> | ||
<MenuLink to="/music">Music</MenuLink> | ||
<MenuLink to="/musical-instruments">Musical instruments</MenuLink> | ||
<MenuLink to="/movies">Movies</MenuLink> | ||
<MenuLink to="/sports">Sports equipment</MenuLink> | ||
<MenuLink to="/video-games">Video games</MenuLink> | ||
<MenuLink to="/home-and-kitchen">Home and kitchen</MenuLink> | ||
<MenuLink to="/crafts">Arts and crafts</MenuLink> | ||
<MenuLink to="/beauty">Beauty and personal care</MenuLink> | ||
<MenuLink to="/womens-fashion">Women's fashion</MenuLink> | ||
<MenuLink to="/mens-fashion">Men's fashion</MenuLink> | ||
<MenuLink to="/kids-fashion">Kid's fashion</MenuLink> | ||
<MenuLink to="/pet-supplies">Pet supplies</MenuLink> | ||
</nav> | ||
<main className="flex-grow">{children}</main> | ||
</div> | ||
</> | ||
); | ||
} | ||
|
||
function MenuLink({ to, children }) { | ||
return ( | ||
<NavLink | ||
to={to} | ||
className={({ isActive }) => | ||
`block hover:bg-gray-200 transition-all text-lg font-bold px-4 py-1 ${ | ||
isActive ? "bg-gray-200" : "" | ||
}` | ||
}> | ||
{children} | ||
</NavLink> | ||
); | ||
} | ||
|
||
export function ErrorBoundary({ error }) { | ||
return ( | ||
<Document> | ||
<Layout> | ||
<div className="bg-red-100 text-red-700 border border-red-200 p-4 rounded"> | ||
<h1 className="text-2xl mb-3 font-bold">Error</h1> | ||
<p>{error.message}</p> | ||
</div> | ||
</Layout> | ||
</Document> | ||
); | ||
} | ||
|
||
export function CatchBoundary() { | ||
const caught = useCatch(); | ||
return ( | ||
<Document> | ||
<Layout> | ||
<div className="bg-red-100 text-red-700 border border-red-200 p-4 rounded"> | ||
<h1 className="text-2xl mb-3 font-bold">Whoops</h1> | ||
<p> | ||
{caught.status} {caught.statusText} | ||
</p> | ||
</div> | ||
</Layout> | ||
</Document> | ||
); | ||
} |
6 changes: 6 additions & 0 deletions
6
lesson-05/remix-shopping-with-api/app/routes/api/luggage/$productId.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import db from "~/db/luggage/db.server.js"; | ||
|
||
export async function loader({ params }) { | ||
const product = db.data.products?.find((p) => p.id === params.productId); | ||
return product; | ||
} |
5 changes: 5 additions & 0 deletions
5
lesson-05/remix-shopping-with-api/app/routes/api/luggage/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import db from "~/db/luggage/db.server.js"; | ||
|
||
export async function loader() { | ||
return db.data.products ?? []; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import LinkButton from "~/components/LinkButton.jsx"; | ||
|
||
export default function Home() { | ||
return ( | ||
<section className="flex-grow items-center justify-center"> | ||
<h1 className="text-4xl font-bold text-gray-400"> | ||
The web's premiere destination for shopping absolutely{" "} | ||
<i className="italic">anything</i>. | ||
</h1> | ||
</section> | ||
); | ||
} |
45 changes: 45 additions & 0 deletions
45
lesson-05/remix-shopping-with-api/app/routes/luggage/$productId.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { redirect, Link } from "remix"; | ||
import { useLoaderData } from "remix"; | ||
import PageHeader from "~/components/PageHeader"; | ||
import Button from "~/components/Button.jsx"; | ||
import Breadcrumb from "~/components/Breadcrumb.jsx"; | ||
import db from "~/db/luggage/db.server"; | ||
|
||
export const loader = async function ({ params }) { | ||
const product = await fetch( | ||
`http://localhost:3000/api/luggage/${params.productId}` | ||
); | ||
|
||
if (!product) { | ||
throw new Error("Product not found"); | ||
} | ||
|
||
return product; | ||
}; | ||
|
||
export const action = async function ({ request, params }) { | ||
const form = await request.formData(); | ||
if (form.get("_method") === "delete") { | ||
// TODO: Create an API route and send a DELETE request to it | ||
throw new Error("Delete not implemented"); | ||
return redirect("/luggage"); | ||
} | ||
}; | ||
|
||
export default function Post() { | ||
const product = useLoaderData(); | ||
|
||
return ( | ||
<div> | ||
<Breadcrumb links={[{ to: "/luggage", title: "Luggage" }]} /> | ||
<PageHeader title={product.title} /> | ||
<p>{product.description}</p> | ||
<form method="post" className="mt-5 pt-2 border-t border-gray-200"> | ||
<input type="hidden" name="_method" value="delete" /> | ||
<Button type="submit" destructive> | ||
Delete | ||
</Button> | ||
</form> | ||
</div> | ||
); | ||
} |
Oops, something went wrong.