feat: add tag filter on homepage

This commit is contained in:
Mathias Schopmans
2024-02-27 16:17:24 +01:00
committed by Mathias Schopmans
parent e42b175ab7
commit 13591b9672
9 changed files with 127 additions and 8 deletions

View File

@@ -1,3 +1,14 @@
.header {
display: flex;
flex-wrap: wrap;
align-items: center;
margin: 0 0 20px;
}
.title {
margin: 0 30px 0 0;
}
.revision {
padding: 30px 0 15px 35px;
margin-left: 5px;

View File

@@ -2,6 +2,7 @@ import styles from "./ItemDetail.module.css";
import { RingBadge } from "@/components/Badge/Badge";
import Attention from "@/components/Icons/Attention";
import { Tag } from "@/components/Tags/Tags";
import { getReleases } from "@/lib/data";
import { Item } from "@/lib/types";
import { cn } from "@/lib/utils";
@@ -19,7 +20,12 @@ interface ItemProps {
export function ItemDetail({ item }: ItemProps) {
return (
<>
<h1 className={styles.title}>{item.title}</h1>
<div className={styles.header}>
<h1 className={styles.title}>{item.title}</h1>
{item.tags.map((tag) => (
<Tag key={tag} tag={tag} />
))}
</div>
<div className={styles.revisions}>
{isNotMaintained(item.release) && (
<div className={cn(styles.revision, styles.hint)}>

View File

@@ -1,6 +1,5 @@
.radar {
padding: 0 15px;
margin-bottom: 60px;
padding: 0 15px 30px;
position: relative;
transition: padding 200ms ease-in-out;
}

View File

@@ -0,0 +1,43 @@
.icon {
width: 16px;
height: 16px;
display: inline-block;
vertical-align: middle;
margin: -2px 6px 0 -5px;
}
.tag {
position: relative;
display: inline-block;
vertical-align: middle;
padding: 6px 15px 5px;
margin: 6px;
text-transform: uppercase;
border: 1px solid var(--tag);
border-radius: 13px;
background: var(--tag);
font-size: 14px;
line-height: 1;
overflow: hidden;
text-decoration: none;
transition: all 150ms ease-in-out;
&:hover,
&:focus,
&.active {
background: var(--foreground);
color: var(--background);
}
&.active {
.icon {
transform: scale(0.8);
}
}
}
.tags {
text-align: center;
margin: 0 auto 60px;
max-width: 600px;
}

View File

@@ -0,0 +1,45 @@
import Link, { LinkProps } from "next/link";
import { ComponentPropsWithoutRef } from "react";
import styles from "./Tags.module.css";
import IconRemove from "@/components/Icons/Close";
import IconTag from "@/components/Icons/Tag";
import { cn } from "@/lib/utils";
type TagProps = {
tag: string;
isActive?: boolean;
} & Omit<LinkProps, "href"> &
ComponentPropsWithoutRef<"a">;
export function Tag({ tag, isActive, className, ...props }: TagProps) {
const Icon = isActive ? IconRemove : IconTag;
return (
<Link
{...props}
className={cn(styles.tag, className, isActive && styles.active)}
href={isActive ? "/" : `/?tag=${tag}`}
>
<Icon className={cn(styles.icon)} />
<span className={styles.label}>{tag}</span>
</Link>
);
}
interface TagsProps {
tags: string[];
activeTag?: string;
className?: string;
}
export function Tags({ tags, activeTag, className }: TagsProps) {
return (
<div className={cn(styles.tags, className)}>
<h3>Filter by Tag</h3>
{tags.map((tag) => (
<Tag key={tag} tag={tag} isActive={activeTag == tag} scroll={false} />
))}
</div>
);
}

1
src/icons/tag.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" ?><svg version="1.1" viewBox="0 0 30 30" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M23,3h-6c-0.512,0-1.024,0.195-1.414,0.586l-12,12c-0.781,0.781-0.781,2.047,0,2.828l8,8c0.781,0.781,2.047,0.781,2.828,0 c0.391-0.391,11.609-11.609,12-12C26.805,14.024,27,13.512,27,13V7C27,4.791,25.209,3,23,3z M23,9c-1.105,0-2-0.895-2-2 c0-1.105,0.895-2,2-2s2,0.895,2,2C25,8.105,24.105,9,23,9z"/></svg>

After

Width:  |  Height:  |  Size: 470 B

View File

@@ -36,6 +36,10 @@ export function getReleases(): string[] {
return data.releases;
}
export function getTags(): string[] {
return data.tags;
}
export function getQuadrants(): Quadrant[] {
return config.quadrants;
}

View File

@@ -1,20 +1,30 @@
import { useRouter } from "next/router";
import { QuadrantList } from "@/components/QuadrantList/QuadrantList";
import { Radar } from "@/components/Radar/Radar";
import { Tags } from "@/components/Tags/Tags";
import {
getAppName,
getItems,
getQuadrants,
getReleases,
getRings,
getTags,
} from "@/lib/data";
import { CustomPage } from "@/pages/_app";
const Home: CustomPage = () => {
const router = useRouter();
const tag = router.query.tag as string | undefined;
const appName = getAppName();
const version = getReleases().length;
const rings = getRings();
const quadrants = getQuadrants();
const items = getItems(undefined, true);
const tags = getTags();
const items = getItems(undefined, true).filter(
(item) => !tag || item.tags.includes(tag),
);
return (
<>
<h1>
@@ -24,6 +34,7 @@ const Home: CustomPage = () => {
</span>
</h1>
<Radar quadrants={quadrants} rings={rings} items={items} />
<Tags tags={tags} activeTag={tag} />
<QuadrantList items={items} />
</>
);

View File

@@ -10,6 +10,7 @@
--text: #575757;
--highlight: #029df7;
--border: rgba(255, 255, 255, 0.1);
--tag: rgba(255, 255, 255, 0.1);
--overlay: #081a37b5;
--dialog-bg: #173d7a;
@@ -24,12 +25,9 @@
margin: 0;
}
html {
scroll-behavior: smooth;
}
html,
body {
scroll-behavior: smooth;
max-width: 100vw;
margin: 0;
padding: 0;
@@ -62,6 +60,7 @@ img {
svg {
display: block;
fill: currentColor;
}
h1,