1
0
mirror of https://github.com/prometheus/docs.git synced 2026-02-05 15:45:27 +01:00

More work

Signed-off-by: Julius Volz <julius.volz@gmail.com>
This commit is contained in:
Julius Volz
2025-05-14 09:43:26 +02:00
parent 8c8f108f0a
commit 2f8368d003
14 changed files with 652 additions and 215 deletions

70
package-lock.json generated
View File

@@ -25,6 +25,7 @@
"react-dom": "^19.0.0",
"react-markdown": "^10.1.0",
"rehype-autolink-headings": "^7.1.0",
"rehype-raw": "^7.0.0",
"rehype-slug": "^6.0.0",
"remark-frontmatter": "^5.0.0",
"remark-gfm": "^4.0.1",
@@ -5280,6 +5281,31 @@
"url": "https://opencollective.com/unified"
}
},
"node_modules/hast-util-raw": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz",
"integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==",
"license": "MIT",
"dependencies": {
"@types/hast": "^3.0.0",
"@types/unist": "^3.0.0",
"@ungap/structured-clone": "^1.0.0",
"hast-util-from-parse5": "^8.0.0",
"hast-util-to-parse5": "^8.0.0",
"html-void-elements": "^3.0.0",
"mdast-util-to-hast": "^13.0.0",
"parse5": "^7.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0",
"vfile": "^6.0.0",
"web-namespaces": "^2.0.0",
"zwitch": "^2.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/hast-util-select": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/hast-util-select/-/hast-util-select-6.0.4.tgz",
@@ -5357,6 +5383,35 @@
"url": "https://opencollective.com/unified"
}
},
"node_modules/hast-util-to-parse5": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz",
"integrity": "sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==",
"license": "MIT",
"dependencies": {
"@types/hast": "^3.0.0",
"comma-separated-tokens": "^2.0.0",
"devlop": "^1.0.0",
"property-information": "^6.0.0",
"space-separated-tokens": "^2.0.0",
"web-namespaces": "^2.0.0",
"zwitch": "^2.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/hast-util-to-parse5/node_modules/property-information": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz",
"integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/hast-util-to-string": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.1.tgz",
@@ -8254,6 +8309,21 @@
"url": "https://opencollective.com/unified"
}
},
"node_modules/rehype-raw": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz",
"integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==",
"license": "MIT",
"dependencies": {
"@types/hast": "^3.0.0",
"hast-util-raw": "^9.0.0",
"vfile": "^6.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/rehype-slug": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/rehype-slug/-/rehype-slug-6.0.0.tgz",

View File

@@ -31,6 +31,7 @@
"react-dom": "^19.0.0",
"react-markdown": "^10.1.0",
"rehype-autolink-headings": "^7.1.0",
"rehype-raw": "^7.0.0",
"rehype-slug": "^6.0.0",
"remark-frontmatter": "^5.0.0",
"remark-gfm": "^4.0.1",

View File

@@ -3,7 +3,10 @@ import { Title } from "@mantine/core";
export default function BlogPage() {
return (
<>
<Title order={1}>Blog</Title>Under construction - stay tuned.
<Title order={1} fw={600}>
Blog
</Title>
Under construction - stay tuned.
</>
);
}

View File

@@ -3,7 +3,9 @@ import { Title } from "@mantine/core";
export default function CommunityPage() {
return (
<>
<Title order={1}>Community</Title>Under construction - stay tuned.
<Title order={1} fw={600}>
Community
</Title>
</>
);
}

View File

@@ -7,9 +7,11 @@ import rehypeSlug from "rehype-slug";
import rehypeAutolinkHeadings from "rehype-autolink-headings";
import rehypeConfigLinker from "@/rehypeConfigLinker";
import rehypeShiki from "@shikijs/rehype";
import { IconLink } from "@tabler/icons-react";
import { IconAlertCircle, IconInfoCircle, IconLink } from "@tabler/icons-react";
import { docsCollection } from "@/docs-collection";
import {
Alert,
Blockquote,
em,
Table,
TableTbody,
@@ -20,7 +22,10 @@ import {
Title,
TitleProps,
} from "@mantine/core";
import rehypeRaw from "rehype-raw";
import { Children } from "react";
// TODO: Move to global config.
const SITE_URL = "https://prometheus.io";
function isAbsoluteUrl(url: string) {
@@ -41,6 +46,24 @@ export async function generateStaticParams() {
return params;
}
export async function generateMetadata({
params,
}: {
params: Promise<{ slug: string[] }>;
}) {
const slug = (await params).slug;
const docMeta = docsCollection[slug.join("/")];
return {
title: `${docMeta.title} | Prometheus`,
// description: docMeta.description,
openGraph: {
title: `${docMeta.title} | Prometheus`,
// description: docMeta.description,
url: `${SITE_URL}/docs/${slug.join("/")}`,
},
};
}
const h = (order: 1 | 2 | 3 | 4 | 5 | 6) => {
const HeadingComponent = (props: TitleProps) => (
<Title order={order} id={props.id}>
@@ -67,7 +90,12 @@ export default async function DocsPage({
<MarkdownAsync
remarkPlugins={[remarkFrontmatter, remarkGfm]}
rehypePlugins={[
// "rehypeRaw" is required for raw HTML in some old Markdown files to work.
// See https://github.com/remarkjs/react-markdown?tab=readme-ov-file#appendix-a-html-in-markdown
rehypeRaw,
// Add "id" attributes to headings so links can point to them.
rehypeSlug,
// Add "<a>" tags with a link symbol to headings to link to themselves.
() =>
rehypeAutolinkHeadings({
properties: {
@@ -77,6 +105,7 @@ export default async function DocsPage({
// Don't link top-level page headings (h1).
test: (el) => el.tagName !== "h1",
}),
// Highlight code blocks with Shiki.
[
rehypeShiki,
{
@@ -87,7 +116,10 @@ export default async function DocsPage({
},
},
],
// Custom plugin: On the configuration page, link from placeholders like
// <string> or <scrape_config> in code blocks to their corresponding type
// definitions in the same file.
//
// Important: this has to run after rehypeSlug, since it
// relies on the headers to already have IDs.
rehypeConfigLinker,
@@ -104,20 +136,21 @@ export default async function DocsPage({
);
}
// For local docs, keep links as is.
// For local docs, keep links as is. If they're wrong, they should
// be fixed in the local Markdown files, not here.
const href = props.href;
if (!href || docMeta.type === "local-doc") {
return <a {...rest}>{children}</a>;
}
// For external docs, do some postprocessing on the hrefs to make
// For external repo docs, do some postprocessing on the hrefs to make
// sure they point to the right place.
let normalizedHref = href;
if (href.startsWith(SITE_URL)) {
// Remove the "https://prometheus.io" from links that start with it.
normalizedHref = href.slice(SITE_URL.length);
} else if (href.startsWith("/")) {
// Turn "/<path>" into e.g. "https://github.com/prometheus/prometheus/blob/release-3.3.0/<path>"
// Turn "/<path>" into e.g. "https://github.com/prometheus/prometheus/blob/release-3.3/<path>"
normalizedHref = `https://github.com/prometheus/prometheus/blob/release-${docMeta.version}${href}`;
} else if (href.includes(".md") && !isAbsoluteUrl(href)) {
// Turn "foo/bar/baz.md" into "foo/bar/baz" for relative links between Markdown pages.
@@ -130,6 +163,46 @@ export default async function DocsPage({
</a>
);
},
p: (props) => {
const { children, node: _node, ...rest } = props;
// The React children can either be an array or a single element, and
// each element can be a string or something else. The Children.toArray()
// method from React helps us convert either situation into an array.
const arrayChildren = Children.toArray(children);
const fc = arrayChildren[0];
if (fc && typeof fc === "string") {
// Paragraphs that start with "TIP:", "NOTE:", "CAUTION:", or "TODO:"
// are rendered as blockquotes with an icon.
const alertRegex = new RegExp(
/^(TIP|NOTE|CAUTION|TODO): (.*)$/,
"s"
);
const match = fc.match(alertRegex);
if (match) {
const alertType = match[1];
const alertText = match[2];
return (
<Blockquote
py="lg"
my="xl"
color={alertType === "CAUTION" ? "yellow" : "blue"}
icon={
alertType === "CAUTION" ? (
<IconAlertCircle size={30} />
) : (
<IconInfoCircle size={30} />
)
}
>
<strong>{alertType}</strong>: {alertText}
{arrayChildren.slice(1)}
</Blockquote>
);
}
}
return <p {...rest}>{children}</p>;
},
img: (props) => {
const { src, node: _node, ...rest } = props;
if (
@@ -141,6 +214,7 @@ export default async function DocsPage({
let srcUrl = src;
if (typeof srcUrl === "string") {
// Remove the "https://prometheus.io" from links that start with it.
// TODO: Fix this in the old Markdown files instead.
srcUrl = srcUrl.replace(/^\/assets\//, "/assets/docs/");
}
// eslint-disable-next-line jsx-a11y/alt-text
@@ -151,17 +225,19 @@ export default async function DocsPage({
return <img {...rest} src={`${docMeta.assetsRoot}/${src}`} />;
},
pre: (props) => {
const firstChild = props.node?.children[0];
const { children, node, ...rest } = props;
const firstChild = node?.children[0];
if (
!firstChild ||
firstChild?.type !== "element" ||
firstChild?.tagName !== "code"
) {
return <pre>{props.children}</pre>;
return <pre {...rest}>{children}</pre>;
}
return (
<pre
{...rest}
style={{
fontSize: 14,
backgroundColor:
@@ -173,7 +249,7 @@ export default async function DocsPage({
overflow: "auto",
}}
>
{props.children}
{children}
</pre>
);
},

View File

@@ -16,6 +16,7 @@ import {
Button,
Popover,
Text,
ScrollArea,
} from "@mantine/core";
import Link from "next/link";
import { usePathname, useRouter } from "next/navigation";
@@ -370,20 +371,24 @@ export default function DocsLayout({
<Group wrap="nowrap" align="flex-start" gap={50}>
{/* The left-hand side main nav */}
<Box
component="nav"
w={250}
flex="0 0 auto"
mih={300}
h="calc(100vh - var(--header-height) - var(--header-to-content-margin))"
pos="sticky"
top="calc(var(--header-height) + var(--header-to-content-margin))"
visibleFrom="sm"
style={{
borderRight:
borderInlineEnd:
"1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-gray-7))",
}}
>
<ScrollAreaAutosize mah="calc(100vh - var(--header-height))">
<Box pr="xs">{buildRecursiveNav(docsTree, pageSlug, router)}</Box>
</ScrollAreaAutosize>
<ScrollArea
h="calc(100vh - var(--header-height) - var(--header-to-content-margin))"
type="never"
>
<Box p="xs">{buildRecursiveNav(docsTree, pageSlug, router)}</Box>
</ScrollArea>
</Box>
{/* The main docs page content */}

View File

@@ -11,6 +11,7 @@ import {
Select,
Stack,
Table,
TableTbody,
TableTd,
TableTh,
TableThead,
@@ -34,7 +35,9 @@ export default function DownloadPage() {
return (
<>
<Title order={1}>Download</Title>
<Title order={1} fw={600}>
Download
</Title>
<Group wrap="nowrap" align="flex-start">
<Box>
@@ -61,10 +64,11 @@ export default function DownloadPage() {
scrollSpyOptions={{
selector: "h2",
}}
visibleFrom="sm"
/>
</Group>
<Stack mt="xl" gap="md">
<Stack mt="xl" gap="md" style={{ overflowX: "scroll" }}>
<Group>
<Select
label="Operating System"
@@ -149,39 +153,41 @@ export default function DownloadPage() {
<TableTh>SHA256 Checksum</TableTh>
</TableTr>
</TableThead>
{release.binaries
.filter((b) => {
if (
osList.includes(b.os) &&
arch === "popular" &&
(b.arch === "amd64" ||
(b.os === "darwin" && b.arch === "arm64"))
) {
return true;
} else if (
osList.includes(b.os) &&
(arch === "all" || b.arch === arch)
) {
return true;
} else {
return false;
}
})
.map((binary) => (
<TableTr key={binary.name}>
<TableTd>
<a className="download" href={binary.url}>
{binary.name}
</a>
</TableTd>
<TableTd>{binary.os}</TableTd>
<TableTd>{binary.arch}</TableTd>
<TableTd>
{(binary.sizeBytes / 1024 / 1024).toFixed(2)} MiB
</TableTd>
<TableTd fz="xs">{binary.checksum}</TableTd>
</TableTr>
))}
<TableTbody>
{release.binaries
.filter((b) => {
if (
osList.includes(b.os) &&
arch === "popular" &&
(b.arch === "amd64" ||
(b.os === "darwin" && b.arch === "arm64"))
) {
return true;
} else if (
osList.includes(b.os) &&
(arch === "all" || b.arch === arch)
) {
return true;
} else {
return false;
}
})
.map((binary) => (
<TableTr key={binary.name}>
<TableTd>
<a className="download" href={binary.url}>
{binary.name}
</a>
</TableTd>
<TableTd>{binary.os}</TableTd>
<TableTd>{binary.arch}</TableTd>
<TableTd>
{(binary.sizeBytes / 1024 / 1024).toFixed(2)} MiB
</TableTd>
<TableTd fz="xs">{binary.checksum}</TableTd>
</TableTr>
))}
</TableTbody>
</React.Fragment>
))}
</Table>

View File

@@ -16,15 +16,23 @@ h6 {
margin-top: calc(var(--mantine-spacing-xl) * 1.2);
margin-bottom: calc(var(--mantine-spacing-md) * 1.2);
scroll-margin-top: calc(
var(--header-height) + var(--header-to-content-margin)
);
&:is(h1) {
margin-top: 0;
}
}
h1,
h2,
h3,
h4,
h5,
h6,
code {
scroll-margin-top: calc(
var(--header-height) + var(--header-to-content-margin)
);
}
.docs-content a {
color: var(--mantine-color-blue-8);
text-decoration: none;
@@ -69,11 +77,20 @@ pre > code a {
}
/* Important: only target "pre > code > span" and not "pre > code" so we
don't invert non-highlighted code boxes. */
don't invert code boxes where shiki didn't apply any highlighting. */
.invertInDarkMode,
.docs-content img[src$=".svg"],
pre > code > span {
filter: light-dark("", invert(1));
@mixin dark {
filter: invert(1);
}
}
.docs-content img[src$=".svg"] {
@mixin dark {
background-color: var(--mantine-color-gray-2);
border-radius: 0.3em;
padding: 0.1em 0.3em;
}
}
:not(pre) > code {
@@ -84,4 +101,7 @@ pre > code > span {
font-size: 0.9em;
padding: 0.1em 0.3em;
border-radius: 0.3em;
/* There are some long words in <code> tags that break the layout
if we don't force them to wrap. */
overflow-wrap: break-word;
}

View File

@@ -4,6 +4,7 @@
import { Inter } from "next/font/google";
import {
Anchor,
AppShell,
ColorSchemeScript,
Container,
Group,
@@ -24,6 +25,7 @@ import { theme } from "@/theme";
// import docsearch from "@docsearch/js";
import "@docsearch/css";
import { useDisclosure } from "@mantine/hooks";
// import { useEffect } from "react";
const interFont = Inter({
@@ -41,6 +43,8 @@ export default function RootLayout({
}: Readonly<{
children: React.ReactNode;
}>) {
const [burgerOpened, { toggle: toggleBurger }] = useDisclosure();
// useEffect(() => {
// docsearch({
// container: "#docsearch",
@@ -57,46 +61,57 @@ export default function RootLayout({
</head>
<body>
<MantineProvider theme={theme}>
<Header />
{/* <div id="docsearch" /> */}
<Container
size="xl"
mt="xl"
mih="calc(100vh - var(--header-height) - var(--header-to-content-margin))"
>
{children}
<Space h={50} />
</Container>
<footer
style={{
backgroundColor:
"light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-9))",
<AppShell
header={{ height: "var(--header-height)" }}
navbar={{
width: 300,
breakpoint: "sm",
collapsed: { desktop: true, mobile: !burgerOpened },
}}
>
<Container size="xl" p="xl">
<Group h={100}>
<Text c="dimmed" fz="sm">
&copy; Prometheus Authors 2014-{new Date().getFullYear()} |
Documentation Distributed under CC-BY-4.0
</Text>
<Text c="dimmed" fz="sm">
&copy; {new Date().getFullYear()} The Linux Foundation. All
rights reserved. The Linux Foundation has registered
trademarks and uses trademarks. For a list of trademarks of
The Linux Foundation, please see our{" "}
<Anchor
inherit
href="https://www.linuxfoundation.org/trademark-usage"
target="_blank"
>
Trademark Usage
</Anchor>{" "}
page.
</Text>
</Group>
</Container>
</footer>
<Header burgerOpened={burgerOpened} toggleBurger={toggleBurger} />
{/* <div id="docsearch" /> */}
<AppShell.Main>
<Container
size="xl"
mt="xl"
// mih="calc(100vh - var(--header-height) - var(--header-to-content-margin))"
>
{children}
<Space h={50} />
</Container>
</AppShell.Main>
<footer
style={{
backgroundColor:
"light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-9))",
}}
>
<Container size="xl" p="xl">
<Group h={100}>
<Text c="dimmed" fz="sm">
&copy; Prometheus Authors 2014-{new Date().getFullYear()} |
Documentation Distributed under CC-BY-4.0
</Text>
<Text c="dimmed" fz="sm">
&copy; {new Date().getFullYear()} The Linux Foundation. All
rights reserved. The Linux Foundation has registered
trademarks and uses trademarks. For a list of trademarks of
The Linux Foundation, please see our{" "}
<Anchor
inherit
href="https://www.linuxfoundation.org/trademark-usage"
target="_blank"
>
Trademark Usage
</Anchor>{" "}
page.
</Text>
</Group>
</Container>
</footer>
</AppShell>
</MantineProvider>
</body>
</html>

View File

@@ -10,6 +10,12 @@ import cncfLogoDarkMode from "../assets/cncf-logo-white.svg";
import githubLogo from "../assets/github-logo.svg";
import { GitHubStars } from "@/components/GitHubStars";
export const metadata = {
title: "Prometheus - Monitoring system & time series database",
description:
"An open-source monitoring system with a dimensional data model, flexible query language, efficient time series database and modern alerting approach.",
};
export default function Home() {
return (
<>

View File

@@ -1,10 +1,246 @@
import { Title } from "@mantine/core";
import {
Title,
Text,
Image,
Card,
CardProps,
SimpleGrid,
Group,
Button,
Stack,
} from "@mantine/core";
type ProviderCardProps = {
name: string;
logo?: string;
url: string;
cardProps?: CardProps;
aspectRatio?: string;
};
const trainingProviders: ProviderCardProps[] = [
{
name: "Linux Foundation",
logo: "/assets/docs/commercial-support-logos/linux-foundation.png",
url: "https://training.linuxfoundation.org/training/monitoring-systems-and-services-with-prometheus-lfs241/",
},
{
name: "PromLabs",
logo: "/assets/docs/commercial-support-logos/promlabs.svg",
url: "https://training.promlabs.com/",
},
{
name: "Robust Perception",
logo: "/assets/docs/commercial-support-logos/robust-perception.png",
url: "https://training.robustperception.io/",
},
{
name: "acend",
logo: "/assets/docs/commercial-support-logos/acend.svg",
url: "https://acend.ch/en/trainings/prometheus/",
},
];
const commercialSupportProviders: ProviderCardProps[] = [
{
name: "Container Solutions",
logo: "/assets/docs/commercial-support-logos/container-solutions.svg",
url: "https://www.container-solutions.com/",
cardProps: { bg: "gray.5" },
},
{
name: "Cloudraft",
logo: "/assets/docs/commercial-support-logos/cloudraft.png",
url: "https://cloudraft.io/",
},
{
name: "Fullstaq",
logo: "/assets/docs/commercial-support-logos/fullstaq.png",
url: "https://fullstaq.com/",
},
{
name: "Grafana Labs",
logo: "/assets/docs/commercial-support-logos/grafana-labs.svg",
url: "https://grafana.com/oss/prometheus/",
},
{
name: "InfraCloud",
logo: "/assets/docs/commercial-support-logos/infracloud.svg",
url: "https://www.infracloud.io/prometheus-commercial-support/",
},
{
name: "IT-Schulungen.com",
logo: "/assets/docs/commercial-support-logos/it-schulungen.png",
url: "https://www.it-schulungen.com/seminare/netzwerktechnologien/prometheus/index.html",
},
{
name: "LabyrinthLabs",
logo: "/assets/docs/commercial-support-logos/lablabs.svg",
url: "https://lablabs.io/",
},
{
name: "Martina Ferrari (Independent Contractor)",
url: "https://tina.pm/",
},
{
name: "CGI",
logo: "/assets/docs/commercial-support-logos/cgi.png",
url: "https://www.cgi.com/en",
},
{
name: "O11y",
logo: "/assets/docs/commercial-support-logos/o11y.svg",
url: "https://o11y.eu/prometheus-support/",
},
{
name: "OpenObserve",
logo: "/assets/docs/commercial-support-logos/openobserve.png",
url: "https://openobserve.ai",
},
{
name: "PlatformEngineers.io",
logo: "/assets/docs/commercial-support-logos/platformengineers.png",
url: "https://platformengineers.io/",
},
{
name: "PromLabs",
logo: "/assets/docs/commercial-support-logos/promlabs.svg",
url: "https://promlabs.com/",
},
{
name: "Puzzle ITC",
logo: "/assets/docs/commercial-support-logos/puzzle.svg",
url: "https://www.puzzle.ch/de/prometheus",
},
{
name: "Robust Perception",
logo: "/assets/docs/commercial-support-logos/robust-perception.png",
url: "https://www.robustperception.io/",
},
{
name: "SentinelFox",
logo: "/assets/docs/commercial-support-logos/sentinelfox.svg",
url: "https://sentinelfox.com/services/observability/prometheus/",
},
{
name: "Sysdig",
logo: "/assets/docs/commercial-support-logos/sysdig.svg",
url: "https://sysdig.com/solutions/prometheus-monitoring/",
},
{
name: "Tasrie IT Services",
logo: "/assets/docs/commercial-support-logos/tasrie-it-services.png",
url: "https://tasrieit.com/cloudnativeconsulting/",
},
{
name: "xamira networks",
logo: "/assets/docs/commercial-support-logos/xamira_networks.png",
url: "https://www.xamira.de/en/technologies/monitoring/",
},
];
function ProviderCard({
name,
logo,
url,
cardProps,
aspectRatio = "2/1",
}: ProviderCardProps) {
return (
<a
href={url}
target="_blank"
rel="noopener noreferrer"
style={{ textDecoration: "none" }}
>
<Card
withBorder
style={{
display: "flex",
justifyContent: "center",
aspectRatio,
}}
{...cardProps}
>
{logo ? (
<Image src={logo} alt={`${name} logo`} />
) : (
<Text fz="sm" ta="center">
{name}
</Text>
)}
</Card>
</a>
);
}
export default function SupportTrainingPage() {
return (
<>
<Title order={1}>Support and Training</Title>Under construction - stay
tuned.
<Title order={1} fw={600}>
Support and Training
</Title>
<Text>
This page lists organizations and companies that provide support,
training, or other services around Prometheus. This list is provided in
alphabetical order.
</Text>
<Title order={2} fw={500}>
Certifications
</Title>
<SimpleGrid cols={{ base: 1, xs: 2, sm: 4 }}>
<ProviderCard
name="PCA"
logo="/assets/docs/certification-logos/pca-logo.png"
url="https://www.cncf.io/training/certification/pca/"
aspectRatio="1/1"
/>
</SimpleGrid>
<Text mt="lg">
<strong>Note:</strong> While the Linux Foundation is the only
organization offering an official certification exam for Prometheus,
there are multiple independent training providers (listed below) that
can help you prepare for the PCA certification.
</Text>
<Title order={2} mt={65} fw={500}>
Courses and Trainings
</Title>
<SimpleGrid cols={{ base: 1, xs: 2, sm: 4 }}>
{trainingProviders.map((provider) => (
<ProviderCard key={provider.name} {...provider} />
))}
</SimpleGrid>
<Title order={2} mt={65} fw={500}>
Commercial support
</Title>
<SimpleGrid cols={{ base: 1, xs: 2, sm: 4 }}>
{commercialSupportProviders.map((provider) => (
<ProviderCard key={provider.name} {...provider} />
))}
</SimpleGrid>
<Title order={2} mt={65} fw={500}>
Add a resource
</Title>
<Stack gap="xl">
<Text>
If you are a training provider or a company that provides commercial
support for Prometheus and would like to be listed here, please open a
pull request to add yourself to the list.
</Text>
<Button
size="xl"
component="a"
href="https://github.com/prometheus/docs"
target="_blank"
w="fit-content"
m="auto"
>
Add your company
</Button>
</Stack>
</>
);
}

View File

@@ -1,16 +1,17 @@
.header {
height: var(--header-height);
/* height: var(--header-height); */
/* padding-left: var(--mantine-spacing-md);
padding-right: var(--mantine-spacing-md); */
position: sticky;
top: 0;
/* position: sticky;
top: 0; */
/* max-width: 100vw; */
background-color: color-mix(
in srgb,
var(--mantine-color-body),
transparent 15%
);
backdrop-filter: blur(5px);
z-index: 1000;
border-bottom: none;
}
.inner {

View File

@@ -6,9 +6,9 @@ import {
Container,
TextInput,
ActionIcon,
AppShell,
} from "@mantine/core";
import Image from "next/image";
import { useDisclosure } from "@mantine/hooks";
import {
IconDashboard,
IconFileText,
@@ -55,9 +55,13 @@ const actions: SpotlightActionData[] = [
},
];
export const Header: FC = () => {
const [opened, { toggle }] = useDisclosure(false);
export const Header = ({
burgerOpened,
toggleBurger,
}: {
burgerOpened: boolean;
toggleBurger: () => void;
}) => {
const items = links.map((link) => (
<Link key={link.label} href={link.link} className={classes.link}>
{link.label}
@@ -65,120 +69,110 @@ export const Header: FC = () => {
));
return (
<header className={classes.header}>
<Container size="xl">
<div className={classes.inner}>
{/* Logo + Text */}
<Link href="/" style={{ textDecoration: "none", color: "inherit" }}>
<Group wrap="nowrap" align="center">
<Image src={prometheusLogo} height={32} alt="Prometheus logo" />
<Text
fz={25}
ff="Lato Light"
c="light-dark(var(--mantine-color-gray-7), var(--mantine-color-gray-0))"
>
Prometheus
</Text>
</Group>
</Link>
<>
<AppShell.Header className={classes.header} px="md">
<Container size="xl">
<div className={classes.inner}>
{/* Logo + Text */}
<Link href="/" style={{ textDecoration: "none", color: "inherit" }}>
<Group wrap="nowrap" align="center">
<Image src={prometheusLogo} height={32} alt="Prometheus logo" />
<Text
fz={25}
ff="Lato Light"
c="light-dark(var(--mantine-color-gray-7), var(--mantine-color-gray-0))"
>
Prometheus
</Text>
</Group>
</Link>
{/* Menu items + search */}
<Group align="center">
<Group gap={5} visibleFrom="sm" align="center">
{items}
</Group>
{/* Menu items + search */}
<Group align="center">
<Group gap={5} visibleFrom="sm" align="center">
{items}
</Group>
<Group visibleFrom="md" gap="xs">
<TextInput
placeholder="Search"
w={220}
mx="lg"
leftSection={
<Group visibleFrom="md" gap="xs">
<TextInput
placeholder="Search"
w={220}
mx="lg"
leftSection={
<IconSearch
style={{ width: rem(16), height: rem(16) }}
stroke={1.5}
/>
}
rightSection={
<Text
size="xs"
mx={5}
p={6}
fw={700}
bg="light-dark(var(--mantine-color-gray-1), var(--mantine-color-dark-7))"
lh={1}
style={{ borderRadius: "0.25em" }}
>
Ctrl + K
</Text>
}
onClick={spotlight.open}
rightSectionWidth="fit-content"
visibleFrom="lg"
/>
<ActionIcon
hiddenFrom="lg"
color="gray"
variant="subtle"
onClick={spotlight.open}
>
<IconSearch
style={{ width: rem(16), height: rem(16) }}
stroke={1.5}
{...{
style: {
width: rem(20),
height: rem(20),
display: "block",
},
stroke: 2,
}}
/>
}
rightSection={
<Text
size="xs"
mx={5}
p={6}
fw={700}
bg="light-dark(var(--mantine-color-gray-1), var(--mantine-color-dark-7))"
lh={1}
style={{ borderRadius: "0.25em" }}
>
Ctrl + K
</Text>
}
onClick={spotlight.open}
rightSectionWidth="fit-content"
visibleFrom="lg"
</ActionIcon>
<ThemeSelector />
<ActionIcon
component="a"
href="https://github.com/prometheus"
target="_blank"
color="gray"
variant="subtle"
>
<Image
src={githubLogo}
style={{
height: 20,
width: 20,
opacity: 0.9,
verticalAlign: "middle",
}}
className="invertInDarkMode"
alt="GitHub Logo"
/>
</ActionIcon>
</Group>
<Burger
opened={burgerOpened}
onClick={toggleBurger}
color="gray.3"
size="sm"
hiddenFrom="sm"
/>
<ActionIcon
hiddenFrom="lg"
color="gray"
variant="subtle"
onClick={spotlight.open}
>
<IconSearch
{...{
style: {
width: rem(20),
height: rem(20),
display: "block",
},
stroke: 2,
}}
/>
</ActionIcon>
<ThemeSelector />
<ActionIcon
component="a"
href="https://github.com/prometheus"
target="_blank"
color="gray"
variant="subtle"
>
<Image
src={githubLogo}
style={{
height: 20,
width: 20,
opacity: 0.9,
verticalAlign: "middle",
}}
className="invertInDarkMode"
alt="GitHub Logo"
/>
</ActionIcon>
{/* <a href="https://github.com/prometheus" target="_blank">
<Image
src={githubLogo}
style={{
height: 20,
width: 20,
opacity: 0.9,
verticalAlign: "middle",
}}
className="invertInDarkMode"
alt="GitHub Logo"
/>
</a> */}
</Group>
<Burger
opened={opened}
onClick={toggle}
color="gray.3"
size="sm"
hiddenFrom="sm"
/>
</Group>
</div>
</Container>
</div>
</Container>
</AppShell.Header>
<AppShell.Navbar px="lg">{items}</AppShell.Navbar>
<Spotlight
actions={actions}
nothingFound="Nothing found..."
@@ -188,6 +182,6 @@ export const Header: FC = () => {
placeholder: "Search...",
}}
/>
</header>
</>
);
};

View File

@@ -37,6 +37,8 @@ export function Hero() {
Get started
</Button>
<Button
component={Link}
href="/download/"
variant="default"
color="gray"
size="lg"