From d5cb8410e75cde00394448d9fba2a5f3a116b7a8 Mon Sep 17 00:00:00 2001 From: Mathias Schopmans Date: Thu, 22 Feb 2024 17:03:21 +0100 Subject: [PATCH] feat: add revisions to detail page --- scripts/buildData.ts | 18 ++-- src/components/Filter/QueryFilter.module.css | 4 + src/components/Filter/QueryFilter.tsx | 3 +- .../ItemDetail/ItemDetail.module.css | 71 ++++++++++++++ src/components/ItemDetail/ItemDetail.tsx | 48 ++++++++++ src/components/ItemList/ItemList.module.css | 1 + src/pages/[quadrant]/[id].module.css | 22 +++++ src/pages/[quadrant]/[id].tsx | 16 +++- src/pages/_app.tsx | 1 + src/styles/globals.css | 9 ++ src/styles/hljs.css | 96 +++++++++++++++++++ 11 files changed, 276 insertions(+), 13 deletions(-) create mode 100644 src/components/ItemDetail/ItemDetail.module.css create mode 100644 src/components/ItemDetail/ItemDetail.tsx create mode 100644 src/pages/[quadrant]/[id].module.css create mode 100644 src/styles/hljs.css diff --git a/scripts/buildData.ts b/scripts/buildData.ts index 76ee33f..2e8cffb 100644 --- a/scripts/buildData.ts +++ b/scripts/buildData.ts @@ -150,13 +150,17 @@ function postProcessItems(items: Item[]): { random: [Math.sqrt(Math.random()), Math.random()] as [number, number], flag: getFlag(item, latestRelease), // only keep revision which ring or body is different - revisions: item.revisions?.filter((revision, index, revisions) => { - const { ring, body } = revision; - return ( - ring !== item.ring || - (body != "" && body != item.body && body !== revisions[index - 1]?.body) - ); - }), + revisions: item.revisions + ?.filter((revision, index, revisions) => { + const { ring, body } = revision; + return ( + ring !== item.ring || + (body != "" && + body != item.body && + body !== revisions[index - 1]?.body) + ); + }) + .reverse(), })); return { releases, tags, items: processedItems }; diff --git a/src/components/Filter/QueryFilter.module.css b/src/components/Filter/QueryFilter.module.css index 91ed846..457ebcb 100644 --- a/src/components/Filter/QueryFilter.module.css +++ b/src/components/Filter/QueryFilter.module.css @@ -18,6 +18,10 @@ border: none; } +.icon { + fill: var(--highlight); +} + @media (min-width: 768px) { .filter { flex: 1 1 auto; diff --git a/src/components/Filter/QueryFilter.tsx b/src/components/Filter/QueryFilter.tsx index 4fe9cf1..947250b 100644 --- a/src/components/Filter/QueryFilter.tsx +++ b/src/components/Filter/QueryFilter.tsx @@ -7,7 +7,6 @@ interface QueryFilterProps { value?: string; onChange: (value: string) => void; } - export function QueryFilter({ value, onChange }: QueryFilterProps) { const _onChange = (e: ChangeEvent) => { onChange(e.target.value); @@ -22,7 +21,7 @@ export function QueryFilter({ value, onChange }: QueryFilterProps) { onChange={_onChange} /> ); diff --git a/src/components/ItemDetail/ItemDetail.module.css b/src/components/ItemDetail/ItemDetail.module.css new file mode 100644 index 0000000..4fdb602 --- /dev/null +++ b/src/components/ItemDetail/ItemDetail.module.css @@ -0,0 +1,71 @@ +.revision { + padding: 30px 0 15px 35px; + margin-left: 5px; + border-left: 1px solid var(--border); +} + +.release { + display: block; + text-align: center; + text-transform: uppercase; + font-size: 12px; + line-height: 1.2; + width: 50px; + height: 50px; + padding: 10px 0; + border-radius: 50%; + border: 1px solid var(--border); + background: var(--background); + float: left; + margin: -15px 0 0 -60px; +} + +.ring { + float: left; + margin: -45px 0 0 0; +} + +.content { + background: var(--foreground); + color: var(--text); + border-radius: 6px; + padding: 30px 15px; +} + +.content a { + color: var(--highlight); +} + +@media (min-width: 768px) { + .revision { + padding: 30px 0 15px 50px; + margin-left: 38px; + } + + .release { + font-size: 18px; + width: 75px; + height: 75px; + padding: 15px 0; + margin: -15px 0 0 -90px; + } + + .ring { + margin-left: -15px; + } + + .content { + padding: 30px; + } +} + +/* special styles for revisions without content */ +.revision.noContent { + .content { + background: none; + } + + .ring { + margin-top: -20px; + } +} diff --git a/src/components/ItemDetail/ItemDetail.tsx b/src/components/ItemDetail/ItemDetail.tsx new file mode 100644 index 0000000..aa439e6 --- /dev/null +++ b/src/components/ItemDetail/ItemDetail.tsx @@ -0,0 +1,48 @@ +import styles from "./ItemDetail.module.css"; + +import { RingBadge } from "@/components/Badge/Badge"; +import { Item } from "@/lib/types"; +import { cn } from "@/lib/utils"; + +interface ItemProps { + item: Item; +} + +export function ItemDetail({ item }: ItemProps) { + return ( + <> +

{item.title}

+
+ + {item.revisions?.map((revision, index) => ( + + ))} +
+ + ); +} + +interface RevisionProps { + release: string; + ring: string; + body?: string; +} + +function Revision({ release, ring, body }: RevisionProps) { + const date = new Date(release); + const formattedDate = date.toLocaleDateString("en-US", { + month: "short", + year: "numeric", + }); + return ( +
+ +
+ + {body ?
: null} +
+
+ ); +} diff --git a/src/components/ItemList/ItemList.module.css b/src/components/ItemList/ItemList.module.css index 9c41190..185c6ea 100644 --- a/src/components/ItemList/ItemList.module.css +++ b/src/components/ItemList/ItemList.module.css @@ -34,6 +34,7 @@ .link { display: block; padding: 10px; + border-radius: 6px; &.isFadedOut { opacity: 0.65; diff --git a/src/pages/[quadrant]/[id].module.css b/src/pages/[quadrant]/[id].module.css new file mode 100644 index 0000000..c919be9 --- /dev/null +++ b/src/pages/[quadrant]/[id].module.css @@ -0,0 +1,22 @@ +.layout { +} + +.sidebar { +} + +.content { + margin-bottom: 60px; +} + +@media (min-width: 1024px) { + .layout { + display: flex; + } + .sidebar { + width: 360px; + padding: 110px 0 0 60px; + } + .content { + flex: 1; + } +} diff --git a/src/pages/[quadrant]/[id].tsx b/src/pages/[quadrant]/[id].tsx index a8b376a..ea1d495 100644 --- a/src/pages/[quadrant]/[id].tsx +++ b/src/pages/[quadrant]/[id].tsx @@ -2,7 +2,10 @@ import Head from "next/head"; import { useRouter } from "next/router"; import { useMemo } from "react"; +import styles from "./[id].module.css"; + import { RingBadge } from "@/components/Badge/Badge"; +import { ItemDetail } from "@/components/ItemDetail/ItemDetail"; import { ItemList } from "@/components/ItemList/ItemList"; import { getItem, @@ -33,10 +36,15 @@ const ItemPage: CustomPage = () => { -

{item.title}

- -
- +
+
+ +
+ +
); }; diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index b141b7e..473ca61 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -6,6 +6,7 @@ import { Layout, type LayoutClass } from "@/components/Layout/Layout"; import { formatTitle } from "@/lib/format"; import { assetUrl } from "@/lib/utils"; import "@/styles/globals.css"; +import "@/styles/hljs.css"; export type CustomPage

= NextPage & { layoutClass?: LayoutClass; diff --git a/src/styles/globals.css b/src/styles/globals.css index 646af5a..30eff85 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -7,6 +7,7 @@ --foreground: #fff; --background: #173d7a; + --text: #575757; --highlight: #029df7; --border: rgba(255, 255, 255, 0.1); @@ -95,6 +96,14 @@ ol { margin-bottom: 1em; } +pre { + margin-bottom: 1em; +} + +code { + font-family: var(--font-mono); +} + input { background: var(--foreground); color: var(--background); diff --git a/src/styles/hljs.css b/src/styles/hljs.css new file mode 100644 index 0000000..91257f3 --- /dev/null +++ b/src/styles/hljs.css @@ -0,0 +1,96 @@ +.hljs-subst { + /* var(--highlight-color) */ + color: #2f3337; +} + +.hljs-comment { + /* var(--highlight-comment) */ + color: #656e77; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-meta .hljs-keyword, +.hljs-doctag, +.hljs-section { + /* var(--highlight-keyword) */ + color: #015692; +} + +.hljs-attr { + /* var(--highlight-attribute); */ + color: #015692; +} + +.hljs-attribute { + /* var(--highlight-symbol) */ + color: #803378; +} + +.hljs-name, +.hljs-type, +.hljs-number, +.hljs-selector-id, +.hljs-quote, +.hljs-template-tag { + /* var(--highlight-namespace) */ + color: #b75501; +} + +.hljs-selector-class { + /* var(--highlight-keyword) */ + color: #015692; +} + +.hljs-string, +.hljs-regexp, +.hljs-symbol, +.hljs-variable, +.hljs-template-variable, +.hljs-link, +.hljs-selector-attr { + /* var(--highlight-variable) */ + color: #54790d; +} + +.hljs-meta, +.hljs-selector-pseudo { + /* var(--highlight-keyword) */ + color: #015692; +} + +.hljs-built_in, +.hljs-title, +.hljs-literal { + /* var(--highlight-literal) */ + color: #b75501; +} + +.hljs-bullet, +.hljs-code { + /* var(--highlight-punctuation) */ + color: #535a60; +} + +.hljs-meta .hljs-string { + /* var(--highlight-variable) */ + color: #54790d; +} + +.hljs-deletion { + /* var(--highlight-deletion) */ + color: #c02d2e; +} + +.hljs-addition { + /* var(--highlight-addition) */ + color: #2f6f44; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +}