diff --git a/AGENTS.md b/AGENTS.md index cbc05c08..0fa1f28f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -21,7 +21,8 @@ This repository contains documentation for multiple Flanksource projects built w ## Guidelines -- Never write yaml examples directly. The examples/fixtures should come from the submodules mission-control | duty | config-db | canary-checker. +- Never write yaml examples directly in the documentation. Yaml examples on the blog posts are fine though. + The examples/fixtures should come from the submodules mission-control | duty | config-db | canary-checker. use code blocks with file=directive to import the fixtures. Example: ```yaml title="canary.yaml" file=/modules/canary-checker/fixtures/minimal/http_simple.yaml diff --git a/common/src/components/Card.jsx b/common/src/components/Card.jsx index 01bf4197..1c053edc 100644 --- a/common/src/components/Card.jsx +++ b/common/src/components/Card.jsx @@ -11,6 +11,8 @@ export const Card = ({ link, href, variant = 'primary', + bordered = true, + padded = true, sidebar, children }) => { @@ -26,7 +28,7 @@ export const Card = ({ icon = } const cardContent = ( -
+
{icon && icon}{title} @@ -52,5 +54,3 @@ export const Cards = ({ columns = 3, children }) => { }; - - diff --git a/common/src/css/custom.css b/common/src/css/custom.css index 1575f8af..a54645cd 100644 --- a/common/src/css/custom.css +++ b/common/src/css/custom.css @@ -21,7 +21,8 @@ html { --gray-950: #030712; --font-sans: SuisseIntl, -apple-system, BlinkMacSystemFont, Helvetica, Arial; --font-serif: 'Merriweather', Georgia, serif; - --font-mono: 'Fira Code', monospace; + --font-mono: ui-monospace, 'SFMono-Regular', 'Cascadia Code', 'Roboto Mono', + Menlo, Monaco, Consolas, 'Liberation Mono', monospace; --ifm-font-sans: var(--font-sans); --ifm-font-family-base: var(--font-sans); @@ -52,6 +53,7 @@ html { 0px 4px 4px hsla(0, 0%, 0%, 0.16), 0px 4px 2px hsla(0, 0%, 0%, 0.04); --white: white; --ifm-font-size-base: 16px; + --ifm-font-family-monospace: var(--font-mono); --ifm-code-font-size: 14px; --ifm-font-color-base: #061431; --ifm-color-primary: #3578e5; @@ -267,6 +269,11 @@ footer { font-size: 1.1rem; } + article .markdown h2, + article .markdown h3 { + font-weight: 400; + } + h4, h5, h6 { @@ -289,6 +296,40 @@ footer { } } +@media (max-width: 996px) { + .navbar__items--right + > a[href^='https://demo.flanksource.com/'], + .navbar__items--right > a[href='https://app.flanksource.com/'] { + display: none; + } + + .navbar__items--right + > a[href^='https://accounts.flanksource.com/sign-up'] { + margin-right: 2.5rem; + margin-left: auto; + } + + .blog-post-page .theme-code-block [class*='codeBlockContent'], + .blog-post-page .theme-code-block pre, + .blog-post-page .theme-code-block pre code { + width: 100%; + max-width: 100%; + min-width: 0; + } + + footer [class~='gap-x-[1.88rem]'] { + flex-direction: column; + align-items: flex-start; + } + + footer [class~='gap-x-[5.63rem]'] { + width: 100%; + max-width: 100%; + flex-wrap: wrap; + column-gap: 2rem; + } +} + .hidden { display: none; } @@ -551,6 +592,13 @@ li.popular > a::after { padding: 0px !important ; } +.theme-code-block pre, +.theme-code-block pre code { + font-family: var(--font-mono); + font-size: var(--ifm-code-font-size); + line-height: 1.5; +} + span.step-container { margin-top: 10px; } @@ -958,5 +1006,3 @@ html[data-theme='dark'] .header-github-link:before { transform: scale(1.05); filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.1)) brightness(1.05); } - - diff --git a/common/src/theme/BlogPostItem/Card/index.js b/common/src/theme/BlogPostItem/Card/index.js index 9fae5900..0c467312 100644 --- a/common/src/theme/BlogPostItem/Card/index.js +++ b/common/src/theme/BlogPostItem/Card/index.js @@ -16,16 +16,13 @@ function useContainerClassName() { export default function BlogPostCard({ children, post, url, }) { const containerClassName = useContainerClassName(); return ( - + - {post.metadata.description} + {post.metadata.description} ); } - - - diff --git a/common/src/theme/BlogPostItem/Footer/index.js b/common/src/theme/BlogPostItem/Footer/index.js index 830eeb46..11ee56e7 100644 --- a/common/src/theme/BlogPostItem/Footer/index.js +++ b/common/src/theme/BlogPostItem/Footer/index.js @@ -42,8 +42,8 @@ export default function BlogPostItemFooter() { lastUpdatedBy={lastUpdatedBy} /> )} - Written By - + Written By + {tagsExists && ( )} diff --git a/common/src/theme/BlogPostItem/Header/Authors/index.js b/common/src/theme/BlogPostItem/Header/Authors/index.js index f2fc0767..fab0d1da 100644 --- a/common/src/theme/BlogPostItem/Header/Authors/index.js +++ b/common/src/theme/BlogPostItem/Header/Authors/index.js @@ -4,7 +4,7 @@ import { useBlogPost } from '@docusaurus/plugin-content-blog/client'; import BlogAuthor from '@theme/Blog/Components/Author'; import styles from './styles.module.css'; // Component responsible for the authors layout -export default function BlogPostItemHeaderAuthors({ className, short = false }) { +export default function BlogPostItemHeaderAuthors({ className, short = false, compact = false }) { const { metadata: { authors }, assets, @@ -18,7 +18,7 @@ export default function BlogPostItemHeaderAuthors({ className, short = false }) return (
diff --git a/common/src/theme/BlogPostItem/Header/Title/index.js b/common/src/theme/BlogPostItem/Header/Title/index.js index cbcf9f03..a44028fa 100644 --- a/common/src/theme/BlogPostItem/Header/Title/index.js +++ b/common/src/theme/BlogPostItem/Header/Title/index.js @@ -1,15 +1,21 @@ -import React from 'react'; -import clsx from 'clsx'; -import Link from '@docusaurus/Link'; -import { useBlogPost } from '@docusaurus/plugin-content-blog/client'; -import styles from './styles.module.css'; +import React from 'react' +import clsx from 'clsx' +import Link from '@docusaurus/Link' +import { useBlogPost } from '@docusaurus/plugin-content-blog/client' +import styles from './styles.module.css' export default function BlogPostItemHeaderTitle({ className }) { - const { metadata, isBlogPostPage } = useBlogPost(); - const { permalink, title } = metadata; - const TitleHeading = isBlogPostPage ? 'h1' : 'h2'; + const { metadata, isBlogPostPage } = useBlogPost() + const { permalink, title } = metadata + const TitleHeading = isBlogPostPage ? 'h1' : 'h2' return ( - + {isBlogPostPage ? title : {title}} - ); + ) } diff --git a/common/src/theme/BlogPostItem/Header/Title/styles.module.css b/common/src/theme/BlogPostItem/Header/Title/styles.module.css index 04a8d6ad..c3183d07 100644 --- a/common/src/theme/BlogPostItem/Header/Title/styles.module.css +++ b/common/src/theme/BlogPostItem/Header/Title/styles.module.css @@ -2,11 +2,22 @@ font-size: 3rem; } +.title.postTitle { + max-width: 1000px; + margin: 0 auto; + font-size: 48px; + font-weight: 400; + letter-spacing: -0.045em; + line-height: 1; + text-wrap: balance; +} + /** Blog post title should be smaller on smaller devices **/ @media (max-width: 576px) { - .title { + .title, + .title.postTitle { font-size: 2rem; } } diff --git a/common/src/theme/BlogPostItem/Header/index.js b/common/src/theme/BlogPostItem/Header/index.js index c022d96f..bc6b7891 100644 --- a/common/src/theme/BlogPostItem/Header/index.js +++ b/common/src/theme/BlogPostItem/Header/index.js @@ -1,17 +1,20 @@ -import React from 'react'; -import BlogPostItemHeaderTitle from '@theme/BlogPostItem/Header/Title'; -import BlogPostItemHeaderInfo from '@theme/BlogPostItem/Header/Info'; -import BlogPostItemHeaderAuthors from '@theme/BlogPostItem/Header/Authors'; -import { useBlogPost } from '@docusaurus/plugin-content-blog/client'; -import clsx from 'clsx'; +import React from 'react' +import BlogPostItemHeaderTitle from '@theme/BlogPostItem/Header/Title' +import BlogPostItemHeaderInfo from '@theme/BlogPostItem/Header/Info' +import BlogPostItemHeaderAuthors from '@theme/BlogPostItem/Header/Authors' +import { useBlogPost } from '@docusaurus/plugin-content-blog/client' +import clsx from 'clsx' +import styles from './styles.module.css' + export default function BlogPostItemHeader() { + const { isBlogPostPage } = useBlogPost() return ( -
- {/* Blog: {blog} */} +
+ {isBlogPostPage && } - - + {!isBlogPostPage && } + {!isBlogPostPage && }
- ); + ) } diff --git a/common/src/theme/BlogPostItem/Header/styles.module.css b/common/src/theme/BlogPostItem/Header/styles.module.css new file mode 100644 index 00000000..578ff65e --- /dev/null +++ b/common/src/theme/BlogPostItem/Header/styles.module.css @@ -0,0 +1,13 @@ +.postHeader { + width: min(100%, calc(100vw - 2rem)); + max-width: 1100px; + box-sizing: border-box; + margin: 0 auto; + padding: clamp(4rem, 9vw, 7rem) 1rem clamp(2rem, 4vw, 3rem); + text-align: center; +} + +.postInfo { + margin-bottom: 2rem; + color: var(--ifm-color-emphasis-700); +} diff --git a/common/src/theme/BlogPostItem/index.js b/common/src/theme/BlogPostItem/index.js index 85f09c96..6e805783 100644 --- a/common/src/theme/BlogPostItem/index.js +++ b/common/src/theme/BlogPostItem/index.js @@ -1,22 +1,41 @@ -import React from 'react'; -import clsx from 'clsx'; -import {useBlogPost} from '@docusaurus/plugin-content-blog/client'; -import BlogPostItemContainer from '@theme/BlogPostItem/Container'; -import BlogPostItemHeader from '@theme/BlogPostItem/Header'; -import BlogPostItemContent from '@theme/BlogPostItem/Content'; -import BlogPostItemFooter from '@theme/BlogPostItem/Footer'; -// apply a bottom margin in list view +import React from 'react' +import clsx from 'clsx' +import { useBlogPost } from '@docusaurus/plugin-content-blog/client' +import BlogPostItemContainer from '@theme/BlogPostItem/Container' +import BlogPostItemHeader from '@theme/BlogPostItem/Header' +import BlogPostItemContent from '@theme/BlogPostItem/Content' +import BlogPostItemFooter from '@theme/BlogPostItem/Footer' +import styles from './styles.module.css' + function useContainerClassName() { - const {isBlogPostPage} = useBlogPost(); - return !isBlogPostPage ? 'margin-bottom--xl' : undefined; + const { isBlogPostPage } = useBlogPost() + return !isBlogPostPage ? 'margin-bottom--xl' : undefined } -export default function BlogPostItem({children, className}) { - const containerClassName = useContainerClassName(); +export default function BlogPostItem({ children, className, toc }) { + const containerClassName = useContainerClassName() + + if (toc) { + return ( + + +
+
+ {children} + +
+ +
+
+ ) + } + return ( {children} - ); + ) } diff --git a/common/src/theme/BlogPostItem/styles.module.css b/common/src/theme/BlogPostItem/styles.module.css new file mode 100644 index 00000000..0b89ef26 --- /dev/null +++ b/common/src/theme/BlogPostItem/styles.module.css @@ -0,0 +1,30 @@ +.postArticle.postArticle { + width: calc(100vw - 2rem); + max-width: 1200px; +} + +.postBody { + display: grid; + grid-template-columns: minmax(0, 900px) minmax(180px, 220px); + gap: 3rem; + align-items: start; +} + +.postContent { + min-width: 0; +} + +.postToc { + min-width: 0; + align-self: stretch; +} + +@media (max-width: 996px) { + .postBody { + display: block; + } + + .postToc { + display: none; + } +} diff --git a/common/src/theme/BlogPostItems/index.js b/common/src/theme/BlogPostItems/index.js index 5582881a..14c05f1f 100644 --- a/common/src/theme/BlogPostItems/index.js +++ b/common/src/theme/BlogPostItems/index.js @@ -8,8 +8,7 @@ export default function BlogPostItems({ component: BlogPostItemComponent = BlogPostItem, }) { return ( -
-

Flanksource Blog

+
{items.map(({ content: BlogPostContent }) => ( ); } - diff --git a/common/src/theme/BlogPostPage/index.js b/common/src/theme/BlogPostPage/index.js new file mode 100644 index 00000000..27cfd140 --- /dev/null +++ b/common/src/theme/BlogPostPage/index.js @@ -0,0 +1,66 @@ +import React from 'react' +import clsx from 'clsx' +import { + HtmlClassNameProvider, + ThemeClassNames +} from '@docusaurus/theme-common' +import { + BlogPostProvider, + useBlogPost +} from '@docusaurus/plugin-content-blog/client' +import BlogLayout from '@theme/BlogLayout' +import BlogPostItem from '@theme/BlogPostItem' +import BlogPostPaginator from '@theme/BlogPostPaginator' +import BlogPostPageMetadata from '@theme/BlogPostPage/Metadata' +import BlogPostPageStructuredData from '@theme/BlogPostPage/StructuredData' +import TOC from '@theme/TOC' +import ContentVisibility from '@theme/ContentVisibility' + +function BlogPostPageContent({ sidebar, children }) { + const { metadata, toc } = useBlogPost() + const { nextItem, prevItem, frontMatter } = metadata + const { + hide_table_of_contents: hideTableOfContents, + toc_min_heading_level: tocMinHeadingLevel, + toc_max_heading_level: tocMaxHeadingLevel + } = frontMatter + const tableOfContents = + !hideTableOfContents && toc.length > 0 ? ( + + ) : undefined + + return ( + + + {children} + {(nextItem || prevItem) && ( + + )} + + ) +} + +export default function BlogPostPage(props) { + const BlogPostContent = props.content + + return ( + + + + + + + + + + ) +} diff --git a/common/src/theme/BlogPostPaginator/index.js b/common/src/theme/BlogPostPaginator/index.js index 8bc04b33..8914d449 100644 --- a/common/src/theme/BlogPostPaginator/index.js +++ b/common/src/theme/BlogPostPaginator/index.js @@ -3,7 +3,6 @@ import Translate, {translate} from '@docusaurus/Translate'; import PaginatorNavLink from '@theme/PaginatorNavLink'; export default function BlogPostPaginator(props) { const {nextItem, prevItem} = props; - return null; return (