From 857c528369473a66518407dee6f6cac89bbc538c Mon Sep 17 00:00:00 2001 From: Maksymilian Jopek Date: Wed, 15 Nov 2023 19:29:24 +0100 Subject: Initial commit, v1.0.0 --- src/App.tsx | 25 +++++++++++ src/Router.tsx | 30 +++++++++++++ src/Search.tsx | 54 ++++++++++++++++++++++++ src/Table.tsx | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/data.ts | 16 +++++++ src/index.css | 91 +++++++++++++++++++++++++++++++++++++++ src/main.tsx | 10 +++++ src/vite-env.d.ts | 1 + 8 files changed, 351 insertions(+) create mode 100644 src/App.tsx create mode 100644 src/Router.tsx create mode 100644 src/Search.tsx create mode 100644 src/Table.tsx create mode 100644 src/data.ts create mode 100644 src/index.css create mode 100644 src/main.tsx create mode 100644 src/vite-env.d.ts (limited to 'src') diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..8845354 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,25 @@ +import { useEffect, useState } from "react"; +import Router from "./Router"; +import { setNobelPrizes } from "./data"; + +let loadOnce = false; +function App() { + const [loading, setLoading] = useState(true); + useEffect(() => { + (async () => { + if (loadOnce === false) { + loadOnce = true; + await setNobelPrizes(); + setLoading(false); + } + })(); + }, []); + + if (loading) { + return <>Loading nobel prizes; + } else { + return ; + } +} + +export default App; diff --git a/src/Router.tsx b/src/Router.tsx new file mode 100644 index 0000000..eb4cf21 --- /dev/null +++ b/src/Router.tsx @@ -0,0 +1,30 @@ +import { useEffect, useState } from "react"; +import Search from "./Search"; +import Table from "./Table"; + +const startPath = + location.pathname.at(-1) === "/" + ? location.pathname + : location.pathname + "/"; +export default function Router() { + const [path, setPath] = useState(""); + useEffect(() => { + setPath(location.pathname); + }, []); + window.addEventListener("popstate", () => { + setPath(location.pathname); + }); + + function updatePath(newPath: string) { + console.log({ newPath, startPath }); + const path = startPath + newPath; + history.pushState({}, "", path); + setPath(path); + } + + if (path.includes("/nagrody/")) { + return ; + } else { + return ; + } +} diff --git a/src/Search.tsx b/src/Search.tsx new file mode 100644 index 0000000..cca6e42 --- /dev/null +++ b/src/Search.tsx @@ -0,0 +1,54 @@ +import { useEffect, useState } from "react"; +import { nobelPrizes } from "./data"; + +export default function Search({ setPath }: { setPath: (a: string) => void }) { + const languages = { Angielski: "en", Norweski: "no", Szwedzki: "se" }; + const languagesFlags = { Angielski: "🇬🇧", Norweski: "🇳🇴", Szwedzki: "🇸🇪" }; + const langs = Object.keys(languages) as (keyof typeof languages)[]; + + const [language, setLanguage] = useState(langs[0]); + const [years, setYears] = useState([]); + const [year, setYear] = useState(null); + + function changeLanguage() { + let i = langs.findIndex((l) => language === l) + 1; + if (i >= langs.length) i = 0; + setLanguage(langs[i]); + } + + useEffect(() => { + setYears([...new Set(nobelPrizes.map((np) => parseInt(np.awardYear)))]); + }, []); + + return ( + <> +

Wybierz z którego roku nagrody Nobla chcesz zobaczyć

+ +
+
+ +
+ + Język: {language} {languagesFlags[language]} + +
+ + ); +} diff --git a/src/Table.tsx b/src/Table.tsx new file mode 100644 index 0000000..26c08c7 --- /dev/null +++ b/src/Table.tsx @@ -0,0 +1,124 @@ +import { ReactNode, useEffect, useState } from "react"; +import { nobelPrizes } from "./data"; + +export default function Table() { + const year = location.pathname.split("/").pop(); + //@ts-expect-error Split exists on this type + const lang = location.pathname.match(/\/nagrody\/.*\//g)[0].split("/")[2] as + | "en" + | "no" + | "se"; + const cols = { + awardYear: "Rok przyznania", + category: "Kategoria", + dateAwarded: "Data przyznania nagrody", + prizeAmount: "Kwota nagrody", + }; + const colsKeys = Object.keys(cols) as (keyof typeof cols)[]; + const [filterText, setFilterText] = useState(""); + const [sortCol, setSortCol] = useState("awardYear"); + //eslint-disable-next-line + let [sortDir, setSortDir] = useState(true); + const [trs, setTrs] = useState([]); + + function updateTrs(col: string, inverseDir = true) { + if (inverseDir && col === sortCol) sortDir = !sortDir; + if (col !== sortCol) setSortCol(col); + + const npz = nobelPrizes.filter((np) => { + if (np.awardYear !== year) return false; + if (filterText === "") return true; + + const ft = filterText.toLowerCase(); + + return ( + np.awardYear.toLowerCase().includes(ft) || + np.category[lang].toLowerCase().includes(ft) || + formatDate(np.dateAwarded)?.toLowerCase().includes(ft) || + np.prizeAmount.toString().toLowerCase().includes(ft) + ); + }); + npz.sort((npA, npB) => { + switch (col) { + case "awardYear": + return ( + (parseInt(npA.awardYear) - parseInt(npB.awardYear)) * + (sortDir ? 1 : -1) + ); + case "category": + return sortDir + ? npA.category[lang].localeCompare(npB.category[lang]) + : npB.category[lang].localeCompare(npA.category[lang]); + case "dateAwarded": + return ( + // @ts-expect-error Subtracting dates return the difference in their unix timestamps + (new Date(npA.dateAwarded) - new Date(npB.dateAwarded)) * + (sortDir ? 1 : -1) + ); + case "prizeAmount": + return (npA.prizeAmount - npB.prizeAmount) * (sortDir ? 1 : -1); + default: + return 1; + } + }); + let key = 0; + setTrs( + npz.map((np) => ( +
+ + + + + + )), + ); + if (inverseDir && col === sortCol) setSortDir(sortDir); + } + function formatDate(date: string) { + return date ? new Date(date).toLocaleDateString("pl-PL") : "-"; + } + useEffect(() => updateTrs(sortCol, false), [filterText]); + + return ( + <> +

Nagrody nobla w roku {year}

+
{np.awardYear}{np.category[lang]}{formatDate(np.dateAwarded)} + {np.prizeAmount + .toString() + .match(/.{1,3}/g) + ?.join(" ")} +  kr +
+ + + {colsKeys.map((col) => ( + + ))} + + + {trs} +
updateTrs(col)}> + {cols[col]}   + {sortCol === col && (sortDir ? <>🡅 : <>🡇)} +
+
+
+ +
+
+ + + ); +} diff --git a/src/data.ts b/src/data.ts new file mode 100644 index 0000000..116308d --- /dev/null +++ b/src/data.ts @@ -0,0 +1,16 @@ +export let nobelPrizes: NobelPrize[] = []; +export async function setNobelPrizes() { + nobelPrizes = ( + await fetch("https://api.nobelprize.org/2.1/nobelPrizes").then((res) => + res.json(), + ) + ).nobelPrizes; +} + +export interface NobelPrize { + awardYear: string; + category: { en: string; no: string; se: string }; + dateAwarded: string; + prizeAmount: number; + prizeAmountAdjusted: number; +} diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..503e8af --- /dev/null +++ b/src/index.css @@ -0,0 +1,91 @@ +:root { + font-family: monospace; + line-height: 1.5; + font-weight: 400; + font-size: 20px; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-text-size-adjust: 100%; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 1.8rem; + line-height: 1.1; + font-weight: 550; +} +h2 { + font-size: 1.5rem; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + button { + background-color: #f9f9f9; + } +} + +#root { + margin: 0 auto; + text-align: center; +} +select, +input { + padding: 0.2rem; +} +.year-select { + padding: 1rem; +} +span, +th { + user-select: none; +} + +th, +td { + padding-inline: 1rem; + padding-block: 0.5rem; +} + +table { + border-collapse: collapse; +} +td { + border-top: 1px solid white; +} diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 0000000..3d7150d --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,10 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' +import './index.css' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1 @@ +/// -- cgit v1.3.1