Skip to content

Commit 644a873

Browse files
authored
chore: compliance positioning (#1978)
* chore: compliance positioning * chore: compliance positioning * fix: footer content array length * fix: cmdk use cases * fix: content space * fix: typo * chore: increase prose heading margin
1 parent ec7c3c9 commit 644a873

File tree

25 files changed

+687
-370
lines changed

25 files changed

+687
-370
lines changed

apps/dashboard/src/data/plans.ts

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,33 +17,6 @@ export const config: Record<
1717
}[];
1818
}
1919
> = {
20-
monitors: {
21-
label: "Monitors",
22-
features: [
23-
{
24-
value: "periodicity",
25-
label: "Frequency",
26-
},
27-
{
28-
value: "monitors",
29-
label: "Number of monitors",
30-
},
31-
{
32-
value: "multi-region",
33-
label: "Multi-region monitoring",
34-
},
35-
{ value: "regions", label: "Total regions" },
36-
{ value: "max-regions", label: "Regions per monitor" },
37-
{ value: "data-retention", label: "Data retention" },
38-
{ value: "response-logs", label: "Response Logs" },
39-
{ value: "otel", label: "OTel Exporter" },
40-
{
41-
value: "synthetic-checks",
42-
label: "Synthetic API Checks",
43-
monthly: true,
44-
},
45-
],
46-
},
4720
"status-pages": {
4821
label: "Status Pages",
4922
features: [
@@ -94,6 +67,33 @@ export const config: Record<
9467
},
9568
],
9669
},
70+
monitors: {
71+
label: "Monitors",
72+
features: [
73+
{
74+
value: "periodicity",
75+
label: "Frequency",
76+
},
77+
{
78+
value: "monitors",
79+
label: "Number of monitors",
80+
},
81+
{
82+
value: "multi-region",
83+
label: "Multi-region monitoring",
84+
},
85+
{ value: "regions", label: "Total regions" },
86+
{ value: "max-regions", label: "Regions per monitor" },
87+
{ value: "data-retention", label: "Data retention" },
88+
{ value: "response-logs", label: "Response Logs" },
89+
{ value: "otel", label: "OTel Exporter" },
90+
{
91+
value: "synthetic-checks",
92+
label: "Synthetic API Checks",
93+
monthly: true,
94+
},
95+
],
96+
},
9797
notifications: {
9898
label: "Notifications",
9999
features: [

apps/web/next.config.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,21 @@ const nextConfig: NextConfig = {
7171
destination: "/status-page",
7272
permanent: true,
7373
},
74+
{
75+
source: "/api-monitoring",
76+
destination: "/uptime-monitoring",
77+
permanent: true,
78+
},
79+
{
80+
source: "/monitoring-as-code",
81+
destination: "/uptime-monitoring",
82+
permanent: true,
83+
},
84+
{
85+
source: "/private-locations",
86+
destination: "/uptime-monitoring",
87+
permanent: true,
88+
},
7489
{
7590
source: "/app/:path*",
7691
destination: "https://app.openstatus.dev/",
123 KB
Loading
123 KB
Loading
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import { CustomMDX } from "@/content/mdx";
2+
import { getUseCasePages } from "@/content/utils";
3+
import { BASE_URL, getPageMetadata } from "@/lib/metadata/shared-metadata";
4+
import {
5+
createJsonLDGraph,
6+
getJsonLDBlogPosting,
7+
getJsonLDBreadcrumbList,
8+
getJsonLDFAQPage,
9+
getJsonLDHowTo,
10+
getJsonLDOrganization,
11+
getJsonLDWebPage,
12+
} from "@/lib/metadata/structured-data";
13+
import type { Metadata } from "next";
14+
import Image from "next/image";
15+
import { notFound } from "next/navigation";
16+
import { ContentMetadata } from "../../content-metadata";
17+
import { ContentPagination } from "../../content-pagination";
18+
19+
export const dynamicParams = false;
20+
21+
export async function generateStaticParams() {
22+
const posts = getUseCasePages();
23+
24+
return posts.map((post) => ({
25+
slug: post.slug,
26+
}));
27+
}
28+
29+
export async function generateMetadata({
30+
params,
31+
}: {
32+
params: Promise<{ slug: string }>;
33+
}): Promise<Metadata | undefined> {
34+
const { slug } = await params;
35+
const post = getUseCasePages().find((post) => post.slug === slug);
36+
if (!post) {
37+
return;
38+
}
39+
40+
const metadata = getPageMetadata(post, "use-case");
41+
42+
return metadata;
43+
}
44+
45+
export default async function UseCase({
46+
params,
47+
}: {
48+
params: Promise<{ slug: string }>;
49+
}) {
50+
const { slug } = await params;
51+
const posts = getUseCasePages().sort(
52+
(a, b) =>
53+
b.metadata.publishedAt.getTime() - a.metadata.publishedAt.getTime(),
54+
);
55+
const postIndex = posts.findIndex((post) => post.slug === slug);
56+
const post = posts[postIndex];
57+
const previousPost = posts[postIndex - 1];
58+
const nextPost = posts[postIndex + 1];
59+
60+
if (!post) {
61+
notFound();
62+
}
63+
64+
const jsonLDGraph = createJsonLDGraph([
65+
getJsonLDOrganization(),
66+
getJsonLDWebPage(post),
67+
getJsonLDBlogPosting(post, "use-case"),
68+
getJsonLDBreadcrumbList([
69+
{ name: "Home", url: BASE_URL },
70+
{ name: "Use Cases", url: `${BASE_URL}/use-case` },
71+
{ name: post.metadata.title, url: `${BASE_URL}/use-case/${slug}` },
72+
]),
73+
getJsonLDHowTo(post),
74+
getJsonLDFAQPage(post),
75+
]);
76+
77+
return (
78+
<section className="prose dark:prose-invert max-w-none">
79+
<script
80+
type="application/ld+json"
81+
suppressHydrationWarning
82+
// biome-ignore lint/security/noDangerouslySetInnerHtml: jsonLd
83+
dangerouslySetInnerHTML={{
84+
__html: JSON.stringify(jsonLDGraph).replace(/</g, "\\u003c"),
85+
}}
86+
/>
87+
<h1>{post.metadata.title}</h1>
88+
<ContentMetadata data={post} />
89+
{post.metadata.image ? (
90+
<div className="relative aspect-video w-full overflow-hidden border border-border">
91+
<Image
92+
src={post.metadata.image}
93+
alt={post.metadata.title}
94+
fill
95+
className="object-contain"
96+
/>
97+
</div>
98+
) : null}
99+
<CustomMDX source={post.content} />
100+
<ContentPagination
101+
previousPost={previousPost}
102+
nextPost={nextPost}
103+
prefix="/use-case"
104+
/>
105+
</section>
106+
);
107+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { getUseCasePages } from "@/content/utils";
2+
import { defaultMetadata, ogMetadata } from "@/lib/metadata/shared-metadata";
3+
import { twitterMetadata } from "@/lib/metadata/shared-metadata";
4+
import type { Metadata } from "next";
5+
import { ContentList } from "../content-list";
6+
7+
const TITLE = "Use Cases";
8+
const DESCRIPTION =
9+
"Discover how teams use OpenStatus for compliance, open-source projects, crypto exchanges, and API infrastructure.";
10+
11+
export const metadata: Metadata = {
12+
...defaultMetadata,
13+
title: TITLE,
14+
description: DESCRIPTION,
15+
alternates: {
16+
canonical: "/use-case",
17+
},
18+
openGraph: {
19+
...ogMetadata,
20+
title: TITLE,
21+
description: DESCRIPTION,
22+
},
23+
twitter: {
24+
...twitterMetadata,
25+
title: TITLE,
26+
description: DESCRIPTION,
27+
images: [`/api/og?title=${TITLE}&description=${DESCRIPTION}`],
28+
},
29+
};
30+
31+
export default function UseCaseListPage() {
32+
const allUseCases = getUseCasePages();
33+
return (
34+
<div className="prose dark:prose-invert max-w-none">
35+
<h1>Use Cases</h1>
36+
<ContentList data={allUseCases} prefix="/use-case" withCategory />
37+
</div>
38+
);
39+
}

apps/web/src/app/api/search/route.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ function search(params: SearchParams) {
7171
...getPages("compare"),
7272
...getPages("product"),
7373
...getPages("guides"),
74+
...getPages("use-case"),
7475
...getPages("unrelated"),
7576
home,
7677
];

apps/web/src/app/sitemap.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
getProductPages,
88
getToolsPages,
99
getUnrelatedPages,
10+
getUseCasePages,
1011
} from "@/content/utils";
1112
import type { MetadataRoute } from "next";
1213

@@ -21,6 +22,7 @@ const allPlaygrounds = getToolsPages().filter(
2122
(tool) => tool.slug !== "checker-slug",
2223
);
2324
const allGuides = getGuides();
25+
const allUseCases = getUseCasePages();
2426

2527
export default function sitemap(): MetadataRoute.Sitemap {
2628
const blogs = allPosts.map((post) => ({
@@ -81,6 +83,13 @@ export default function sitemap(): MetadataRoute.Sitemap {
8183
},
8284
];
8385

86+
const useCases = allUseCases.map((useCase) => ({
87+
url: `https://www.openstatus.dev/use-case/${useCase.slug}`,
88+
lastModified: useCase.metadata.publishedAt,
89+
changeFrequency: "monthly" as const,
90+
priority: 0.8,
91+
}));
92+
8493
return [
8594
...home,
8695
...blogs,
@@ -90,5 +99,6 @@ export default function sitemap(): MetadataRoute.Sitemap {
9099
...products,
91100
...playgrounds,
92101
...guides,
102+
...useCases,
93103
];
94104
}

apps/web/src/content/cmdk.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ const CONFIG: ConfigSection[] = [
114114
heading: "Guides",
115115
page: "guides",
116116
},
117+
{
118+
type: "group",
119+
label: "Search in Use Cases...",
120+
heading: "Use Cases",
121+
page: "use-case",
122+
},
117123
{
118124
type: "item",
119125
label: "Go to About",

apps/web/src/content/listing.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
getChangelogPosts,
66
getComparePages,
77
getGuides,
8+
getUseCasePages,
89
} from "./utils";
910

1011
/**
@@ -32,6 +33,8 @@ export function generateListingForPath(pathname: string): string | null {
3233
return generatePostsList(getComparePages(), "Comparisons");
3334
case "guides":
3435
return generatePostsList(getGuides(), "Guides");
36+
case "use-case":
37+
return generatePostsList(getUseCasePages(), "Use Cases");
3538
default:
3639
return null;
3740
}
@@ -102,6 +105,7 @@ function generateRootListing(): string {
102105
{ title: "Changelog", posts: getChangelogPosts(), path: "/changelog" },
103106
{ title: "Comparisons", posts: getComparePages(), path: "/compare" },
104107
{ title: "Guides", posts: getGuides(), path: "/guides" },
108+
{ title: "Use Cases", posts: getUseCasePages(), path: "/use-case" },
105109
];
106110

107111
const content = sections

0 commit comments

Comments
 (0)