feat: add radar legend
This commit is contained in:
committed by
Mathias Schopmans
parent
4c0bfa1a65
commit
0d62c0d70b
@@ -67,12 +67,17 @@
|
|||||||
"new": {
|
"new": {
|
||||||
"color": "#f1235a",
|
"color": "#f1235a",
|
||||||
"title": "New",
|
"title": "New",
|
||||||
"titleShort": "N"
|
"titleShort": "N",
|
||||||
|
"description": "New in this version"
|
||||||
},
|
},
|
||||||
"changed": {
|
"changed": {
|
||||||
"color": "#40a7d1",
|
"color": "#40a7d1",
|
||||||
"title": "Changed",
|
"title": "Changed",
|
||||||
"titleShort": "C"
|
"titleShort": "C",
|
||||||
|
"description": "Recently changed"
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "Unchanged"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"chart": {
|
"chart": {
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ interface RingBadgeProps extends Omit<BadgeProps, "color" | "children"> {
|
|||||||
ring: string;
|
ring: string;
|
||||||
release?: string;
|
release?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function RingBadge({
|
export function RingBadge({
|
||||||
ring: ringName,
|
ring: ringName,
|
||||||
release,
|
release,
|
||||||
@@ -76,14 +77,25 @@ export function RingBadge({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Type guard to check if flag has the required attributes
|
||||||
|
function hasRequiredFlagAttributes(flag: any): flag is {
|
||||||
|
color: string;
|
||||||
|
title: string;
|
||||||
|
titleShort: string;
|
||||||
|
} {
|
||||||
|
return "color" in flag && "title" in flag && "titleShort" in flag;
|
||||||
|
}
|
||||||
|
|
||||||
interface FlagBadgeProps
|
interface FlagBadgeProps
|
||||||
extends Omit<BadgeProps, "color" | "children" | "size"> {
|
extends Omit<BadgeProps, "color" | "children" | "size"> {
|
||||||
flag: Flag;
|
flag: Flag;
|
||||||
short?: boolean;
|
short?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FlagBadge({ flag: flagName, short, ...props }: FlagBadgeProps) {
|
export function FlagBadge({ flag: flagName, short, ...props }: FlagBadgeProps) {
|
||||||
if (flagName === Flag.Default) return null;
|
if (flagName === Flag.Default) return null;
|
||||||
const flag = getFlag(flagName);
|
const flag = getFlag(flagName);
|
||||||
|
if (!flag || !hasRequiredFlagAttributes(flag)) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Badge color={flag.color} size="small" {...props}>
|
<Badge color={flag.color} size="small" {...props}>
|
||||||
|
|||||||
35
src/components/Radar/Legend.module.css
Normal file
35
src/components/Radar/Legend.module.css
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
.legend {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
margin: -2px 8px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.legend {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
bottom: 50px;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1200px) {
|
||||||
|
.legend {
|
||||||
|
bottom: auto;
|
||||||
|
left: auto;
|
||||||
|
right: 0;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/components/Radar/Legend.tsx
Normal file
37
src/components/Radar/Legend.tsx
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { ComponentPropsWithoutRef } from "react";
|
||||||
|
|
||||||
|
import styles from "./Legend.module.css";
|
||||||
|
|
||||||
|
import BlipChanged from "@/components/Icons/BlipChanged";
|
||||||
|
import BlipDefault from "@/components/Icons/BlipDefault";
|
||||||
|
import BlipNew from "@/components/Icons/BlipNew";
|
||||||
|
import { getFlags } from "@/lib/data";
|
||||||
|
import { Flag } from "@/lib/types";
|
||||||
|
|
||||||
|
function Icon({
|
||||||
|
flag,
|
||||||
|
...props
|
||||||
|
}: { flag: Flag } & ComponentPropsWithoutRef<"svg">) {
|
||||||
|
console.log("render Icon", flag);
|
||||||
|
switch (flag) {
|
||||||
|
case Flag.New:
|
||||||
|
return <BlipNew {...props} />;
|
||||||
|
case Flag.Changed:
|
||||||
|
return <BlipChanged {...props} />;
|
||||||
|
case Flag.Default:
|
||||||
|
return <BlipDefault {...props} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Legend() {
|
||||||
|
return (
|
||||||
|
<ul className={styles.legend}>
|
||||||
|
{Object.entries(getFlags()).map(([key, flag]) => (
|
||||||
|
<li key={key}>
|
||||||
|
<Icon flag={key as Flag} className={styles.icon} />
|
||||||
|
<span className={styles.label}>{flag.description}</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
padding: 0 15px;
|
padding: 0 15px;
|
||||||
margin-bottom: 60px;
|
margin-bottom: 60px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
transition: padding 200ms ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart {
|
.chart {
|
||||||
@@ -67,7 +68,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 768px) and (max-width: 1023px) {
|
@media (min-width: 768px) and (max-width: 1200px) {
|
||||||
.radar {
|
.radar {
|
||||||
padding: 150px 15px;
|
padding: 150px 15px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import styles from "./Radar.module.css";
|
|||||||
|
|
||||||
import { Chart } from "@/components/Radar/Chart";
|
import { Chart } from "@/components/Radar/Chart";
|
||||||
import { Label } from "@/components/Radar/Label";
|
import { Label } from "@/components/Radar/Label";
|
||||||
|
import { Legend } from "@/components/Radar/Legend";
|
||||||
import { Item, Quadrant, Ring } from "@/lib/types";
|
import { Item, Quadrant, Ring } from "@/lib/types";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
@@ -96,6 +97,7 @@ export const Radar: FC<RadarProps> = ({
|
|||||||
<Label key={quadrant.id} quadrant={quadrant} />
|
<Label key={quadrant.id} quadrant={quadrant} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
<Legend />
|
||||||
<span
|
<span
|
||||||
className={cn(styles.tooltip, tooltip.show && styles.isShown)}
|
className={cn(styles.tooltip, tooltip.show && styles.isShown)}
|
||||||
style={tooltipStyle}
|
style={tooltipStyle}
|
||||||
|
|||||||
@@ -16,7 +16,11 @@ export function getChartConfig() {
|
|||||||
return config.chart;
|
return config.chart;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFlag(flag: Exclude<Flag, Flag.Default>) {
|
export function getFlags() {
|
||||||
|
return config.flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getFlag(flag: Flag) {
|
||||||
return config.flags[flag];
|
return config.flags[flag];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user