diff --git a/deno.json b/deno.json index 3148938..abd096d 100644 --- a/deno.json +++ b/deno.json @@ -1,6 +1,7 @@ { "imports": { "@oak/oak": "jsr:@oak/oak@^17.0.0", - "@tajpouria/cors": "jsr:@tajpouria/cors@^1.2.1" + "@tajpouria/cors": "jsr:@tajpouria/cors@^1.2.1", + "react-router-dom": "npm:react-router-dom@^6.26.2" } } diff --git a/deno.lock b/deno.lock index 1099a48..22a56bd 100644 --- a/deno.lock +++ b/deno.lock @@ -25,6 +25,7 @@ "npm:eslint@^8.57.0": "npm:eslint@8.57.1", "npm:path-to-regexp@6.2.1": "npm:path-to-regexp@6.2.1", "npm:react-dom@^18.3.1": "npm:react-dom@18.3.1_react@18.3.1", + "npm:react-router-dom@^6.26.2": "npm:react-router-dom@6.26.2_react@18.3.1_react-dom@18.3.1__react@18.3.1", "npm:react@^18.3.1": "npm:react@18.3.1", "npm:typescript@^5.2.2": "npm:typescript@5.6.2", "npm:vite": "npm:vite@5.4.8", @@ -435,6 +436,10 @@ "fastq": "fastq@1.17.1" } }, + "@remix-run/router@1.19.2": { + "integrity": "sha512-baiMx18+IMuD1yyvOGaHM9QrVUPGGG0jC+z+IPHnRJWUAUvaKuWKyE8gjDj2rzv3sz9zOGoRSPgeBVHRhZnBlA==", + "dependencies": {} + }, "@rollup/rollup-android-arm-eabi@4.22.4": { "integrity": "sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w==", "dependencies": {} @@ -1314,6 +1319,22 @@ "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", "dependencies": {} }, + "react-router-dom@6.26.2_react@18.3.1_react-dom@18.3.1__react@18.3.1": { + "integrity": "sha512-z7YkaEW0Dy35T3/QKPYB1LjMK2R1fxnHO8kWpUMTBdfVzZrWOiY9a7CtN8HqdWtDUWd5FY6Dl8HFsqVwH4uOtQ==", + "dependencies": { + "@remix-run/router": "@remix-run/router@1.19.2", + "react": "react@18.3.1", + "react-dom": "react-dom@18.3.1_react@18.3.1", + "react-router": "react-router@6.26.2_react@18.3.1" + } + }, + "react-router@6.26.2_react@18.3.1": { + "integrity": "sha512-tvN1iuT03kHgOFnLPfLJ8V95eijteveqdOSk+srqfePtQvqCExB8eHOYnlilbOcyJyKnYkr1vJvf7YqotAJu1A==", + "dependencies": { + "@remix-run/router": "@remix-run/router@1.19.2", + "react": "react@18.3.1" + } + }, "react@18.3.1": { "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "dependencies": { @@ -1502,7 +1523,8 @@ "workspace": { "dependencies": [ "jsr:@oak/oak@^17.0.0", - "jsr:@tajpouria/cors@^1.2.1" + "jsr:@tajpouria/cors@^1.2.1", + "npm:react-router-dom@^6.26.2" ], "packageJson": { "dependencies": [ diff --git a/src/App.css b/src/App.css index b9d355d..2e90a2e 100644 --- a/src/App.css +++ b/src/App.css @@ -33,10 +33,6 @@ } } -.card { - padding: 2em; -} - -.read-the-docs { - color: #888; +.dinosaur { + display: block; } diff --git a/src/App.tsx b/src/App.tsx index afe48ac..19af08d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,35 +1,17 @@ -import { useState } from 'react' -import reactLogo from './assets/react.svg' -import viteLogo from '/vite.svg' -import './App.css' +import { Route, Routes } from "react-router-dom"; +import Index from "./pages/index"; +import Dinosaur from "./pages/Dinosaur"; +import "./App.css"; function App() { - const [count, setCount] = useState(0) - return ( - <> -
- - Vite logo - - - React logo - -
-

Vite + React

-
- -

- Edit src/App.tsx and save to test HMR -

-
-

- Click on the Vite and React logos to learn more -

- - ) +
+ + } /> + } /> + +
+ ); } -export default App +export default App; diff --git a/src/main.tsx b/src/main.tsx index 3d7150d..f6249b8 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,10 +1,10 @@ -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' -import './index.css' +import ReactDOM from "react-dom/client"; +import App from "./App"; +import { BrowserRouter } from "react-router-dom"; +import "./index.css"; -ReactDOM.createRoot(document.getElementById('root')!).render( - +ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( + - , -) + , +); diff --git a/src/pages/Dinosaur.tsx b/src/pages/Dinosaur.tsx new file mode 100644 index 0000000..f3677bc --- /dev/null +++ b/src/pages/Dinosaur.tsx @@ -0,0 +1,26 @@ +import React, { useEffect, useState } from "react"; +import { Link, useParams } from "react-router-dom"; +import { Dino } from "../../types"; + +export default function Dinosaur() { + const { selectedDinosaur } = useParams(); + const [dinosaur, setDino] = useState({ name: "", description: "" }); + + useEffect(() => { + (async () => { + const resp = await fetch( + `http://localhost:8000/dinosaurs/${selectedDinosaur}`, + ); + const dino = await resp.json() as Dino; + setDino(dino); + })(); + }, []); + + return ( +
+

{dinosaur.name}

+

{dinosaur.description}

+ 🠠 Back to all dinosaurs +
+ ); +} diff --git a/src/pages/index.tsx b/src/pages/index.tsx new file mode 100644 index 0000000..4b3aa27 --- /dev/null +++ b/src/pages/index.tsx @@ -0,0 +1,29 @@ +import React, { useEffect, useState } from "react"; +import { Link } from "react-router-dom"; +import { Dino } from "../../types.ts"; + +export default function Index() { + const [dinosaurs, setDinosaurs] = useState([]); + + useEffect(() => { + (async () => { + const response = await fetch(`http://localhost:8000/dinosaurs/`); + const allDinosaurs = await response.json() as Dino[]; + setDinosaurs(allDinosaurs); + })(); + }, []); + + return ( +
+

Welcome to the Dinosaur app

+

Click on a dinosaur below to learn more.

+ {dinosaurs.map((dinosaur: Dino) => { + return ( + + {dinosaur.name} + + ); + })} +
+ ); +} diff --git a/types.ts b/types.ts new file mode 100644 index 0000000..230481c --- /dev/null +++ b/types.ts @@ -0,0 +1 @@ +export type Dino = { name: string; description: string };