diff --git a/data/config.json b/data/config.json
index bbee01f..fee8722 100644
--- a/data/config.json
+++ b/data/config.json
@@ -54,5 +54,17 @@
"description": "This category is a bit special. Unlike the others, we recommend to stop doing or using something. That does not mean that they are bad and it often might be ok to use them in existing projects. But we move things here if we think we shouldn't do them anymore - because we see better options or alternatives now.",
"color": "#688190"
}
- ]
+ ],
+ "flags": {
+ "new": {
+ "color": "#f1235a",
+ "title": "New",
+ "titleShort": "N"
+ },
+ "changed": {
+ "color": "#40a7d1",
+ "title": "Changed",
+ "titleShort": "C"
+ }
+ }
}
diff --git a/src/components/Badge/Badge.module.css b/src/components/Badge/Badge.module.css
new file mode 100644
index 0000000..3ef0dfe
--- /dev/null
+++ b/src/components/Badge/Badge.module.css
@@ -0,0 +1,28 @@
+.badge {
+ position: relative;
+ display: inline-block;
+ vertical-align: middle;
+ padding: 6px 15px;
+ text-transform: uppercase;
+ border: 1px solid transparent;
+ border-radius: 13px;
+ font-size: 12px;
+ overflow: hidden;
+ text-decoration: none;
+}
+
+.size-small {
+ padding: 4px 8px;
+ font-size: 9px;
+}
+
+.size-large {
+ padding: 7px 20px;
+ font-size: 14px;
+ border-radius: 15px;
+}
+
+.colored {
+ color: var(--foreground);
+ background-color: var(--badge);
+}
diff --git a/src/components/Badge/Badge.tsx b/src/components/Badge/Badge.tsx
new file mode 100644
index 0000000..5cdb260
--- /dev/null
+++ b/src/components/Badge/Badge.tsx
@@ -0,0 +1,84 @@
+import {
+ CSSProperties,
+ ComponentPropsWithoutRef,
+ ReactNode,
+ useMemo,
+} from "react";
+
+import styles from "./Badge.module.css";
+
+import { getFlag, getRing } from "@/lib/data";
+import { formatRelease } from "@/lib/format";
+import { Flag } from "@/lib/types";
+import { cn } from "@/lib/utils";
+
+interface BadgeProps extends ComponentPropsWithoutRef<"span"> {
+ children?: ReactNode;
+ color?: string;
+ size?: "small" | "medium" | "large";
+}
+
+export function Badge({
+ children,
+ color,
+ size = "medium",
+ ...props
+}: BadgeProps) {
+ const style = useMemo(
+ () => (color ? ({ "--badge": color } as CSSProperties) : undefined),
+ [color],
+ );
+ return (
+
+ );
+}
+
+interface RingBadgeProps extends Omit {
+ ring: string;
+ release?: string;
+}
+export function RingBadge({
+ ring: ringName,
+ release,
+ ...props
+}: RingBadgeProps) {
+ const ring = getRing(ringName);
+ if (!ring) return null;
+
+ const label = release
+ ? `${ring.title} | ${formatRelease(release)}`
+ : ring.title;
+
+ return (
+
+ {label}
+
+ );
+}
+
+interface FlagBadgeProps
+ extends Omit {
+ flag: Flag;
+ short?: boolean;
+}
+export function FlagBadge({ flag: flagName, short, ...props }: FlagBadgeProps) {
+ if (flagName === Flag.Default) return null;
+ const flag = getFlag(flagName);
+
+ return (
+
+ {short ? flag.titleShort : flag.title}
+
+ );
+}