Skip to content

Commit

Permalink
feat: Optional frontmatter logo for page (#1888)
Browse files Browse the repository at this point in the history
Co-authored-by: Sami Belkadi <[email protected]>
Co-authored-by: Andrew Jiang <[email protected]>
  • Loading branch information
3 people authored Dec 13, 2024
1 parent 894c4b9 commit 8605b12
Show file tree
Hide file tree
Showing 20 changed files with 202 additions and 45 deletions.
18 changes: 18 additions & 0 deletions fern/apis/fdr/definition/docs/latest/frontmatter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ types:
docs: |
The subtitle of the page. This is a markdown string that is rendered below the title.
If `description` is not set, this will be used for the <meta name="description"> tag in the HTML.
logo:
type: optional<Logo>
docs: The logo for this page.
image:
type: optional<commons.FileIdOrUrl>
docs: The URL to this page's image. This is currently an alias for `og:image`, but its purpose may change to a be a cover-image (pre-title).
Expand Down Expand Up @@ -67,6 +70,21 @@ types:
type: optional<string>
docs: The canonical URL of the page. This is used for the <link rel="canonical"> tag in the HTML.

Logo:
discriminated: false
union:
- commons.FileIdOrUrl
- LogoConfiguration

LogoConfiguration:
properties:
light:
type: optional<commons.FileIdOrUrl>
docs: The URL to this page's light theme logo.
dark:
type: optional<commons.FileIdOrUrl>
docs: The URL to this page's dark theme logo.

Layout:
enum:
- value: guide
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/fdr-sdk/src/docs/frontmatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@ export const EMPTY_FRONTMATTER: Frontmatter = {
nofollow: undefined,
"jsonld:breadcrumb": undefined,
keywords: undefined,
logo: undefined,
};

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 10 additions & 2 deletions packages/ui/app/src/atoms/files.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { DocsV1Read } from "@fern-api/fdr-sdk/client/types";
import { DocsV1Read } from "@fern-api/fdr-sdk/client/types";
import { isEqual } from "es-toolkit/predicate";
import { atom, useAtomValue } from "jotai";
import { selectAtom } from "jotai/utils";
Expand All @@ -9,5 +9,13 @@ export const FILES_ATOM = selectAtom(DOCS_ATOM, (docs) => docs.files, isEqual);
FILES_ATOM.debugLabel = "FILES_ATOM";

export function useFile(fileId: DocsV1Read.FileId): DocsV1Read.File_ | undefined {
return useAtomValue(useMemoOne(() => atom((get) => get(FILES_ATOM)[fileId]), [fileId]));
return useAtomValue(
useMemoOne(
() =>
atom(
(get) => get(FILES_ATOM)[DocsV1Read.FileId(fileId.startsWith("file:") ? fileId.slice(5) : fileId)],
),
[fileId],
),
);
}
48 changes: 48 additions & 0 deletions packages/ui/app/src/atoms/logo.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { EMPTY_FRONTMATTER, FileIdOrUrl, Logo, LogoConfiguration } from "@fern-api/fdr-sdk/docs";
import { atom, useAtomValue } from "jotai";
import { DOCS_ATOM } from "./docs";
import { FEATURE_FLAGS_ATOM } from "./flags";
Expand All @@ -17,3 +18,50 @@ LOGO_HEIGHT_ATOM.debugLabel = "LOGO_HEIGHT_ATOM";
export function useLogoHeight(): number {
return useAtomValue(LOGO_HEIGHT_ATOM);
}

function isFileIdOrUrl(logo: Logo | undefined): logo is FileIdOrUrl {
if (logo == null) {
return false;
}
if (typeof logo !== "object") {
return false;
}
if (!("type" in logo && "value" in logo)) {
return false;
}
return logo.type === "fileId" || logo.type === "url";
}

export const LOGO_IMAGE_ATOM = atom<LogoConfiguration>((get) => {
const { content, colors } = get(DOCS_ATOM);
const markdownText =
content.type === "markdown-page"
? content.content
: content.type === "changelog" && content.node.overviewPageId != null
? content.pages[content.node.overviewPageId]
: content.type === "changelog-entry"
? content.page
: undefined;

const { logo } = typeof markdownText === "object" ? markdownText.frontmatter : EMPTY_FRONTMATTER;

if (logo != null && typeof logo === "object") {
if ("light" in logo && "dark" in logo && isFileIdOrUrl(logo.light) && isFileIdOrUrl(logo.dark)) {
return { light: logo.light, dark: logo.dark };
}
if ("light" in logo && isFileIdOrUrl(logo.light)) {
return { light: logo.light, dark: logo.light };
}
if ("dark" in logo && isFileIdOrUrl(logo.dark)) {
return { light: logo.dark, dark: logo.dark };
}
if (isFileIdOrUrl(logo)) {
return { light: logo, dark: logo };
}
}

const light = colors.light?.logo != null ? { type: "fileId" as const, value: colors.light.logo } : undefined;
const dark = colors.dark?.logo != null ? { type: "fileId" as const, value: colors.dark.logo } : undefined;

return { light: light ?? dark, dark: dark ?? light };
});
93 changes: 50 additions & 43 deletions packages/ui/app/src/header/HeaderLogoImage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { DocsV1Read } from "@fern-api/fdr-sdk";
import { useAtomValue } from "jotai";
import { ReactElement } from "react";
import { DOCS_ATOM, useColors, useFile, useLogoHeight } from "../atoms";
import { DOCS_ATOM, LOGO_IMAGE_ATOM, useFile, useLogoHeight } from "../atoms";
import { FernImage } from "../components/FernImage";

function FernFileImage({
Expand All @@ -11,57 +11,64 @@ function FernFileImage({
return <FernImage src={useFile(fileId)} {...props} />;
}

function FernFileOrUrlImage({
fileIdOrUrl,
...props
}: Omit<FernImage.Props, "src"> & { fileIdOrUrl: DocsV1Read.FileIdOrUrl }): ReactElement {
if (fileIdOrUrl.type === "fileId") {
return <FernFileImage fileId={fileIdOrUrl.value} {...props} />;
}
return <FernImage src={{ type: "url", url: fileIdOrUrl.value }} {...props} />;
}

export function HeaderLogoImage(): ReactElement | null {
const colors = useColors();
const logoImageHeight = useLogoHeight();
const title = useAtomValue(DOCS_ATOM).title ?? "Logo";
const { light, dark } = useAtomValue(LOGO_IMAGE_ATOM);

if (colors.dark != null && colors.light != null) {
if (light != null && dark != null) {
return (
<>
{colors.light.logo != null && (
<FernFileImage
alt={title}
fileId={colors.light.logo}
className="fern-logo-light"
height={logoImageHeight}
style={{ height: logoImageHeight }}
priority={true}
loading="eager"
quality={100}
/>
)}
{colors.dark.logo != null && (
<FernFileImage
alt={title}
fileId={colors.dark.logo}
className="fern-logo-dark"
height={logoImageHeight}
style={{ height: logoImageHeight }}
priority={true}
loading="eager"
quality={100}
/>
)}
<FernFileOrUrlImage
alt={title}
fileIdOrUrl={light}
className="fern-logo-light"
height={logoImageHeight}
style={{ height: logoImageHeight }}
priority={true}
loading="eager"
quality={100}
/>
<FernFileOrUrlImage
alt={title}
fileIdOrUrl={dark}
className="fern-logo-dark"
height={logoImageHeight}
style={{ height: logoImageHeight }}
priority={true}
loading="eager"
quality={100}
/>
</>
);
} else {
const logoFile = colors.light?.logo ?? colors.dark?.logo;
}

if (logoFile == null) {
return null;
}
const logoFile = light ?? dark;

return (
<FernFileImage
fileId={logoFile}
className="fern-logo"
height={logoImageHeight}
style={{ height: logoImageHeight }}
priority={true}
loading="eager"
quality={100}
/>
);
if (logoFile == null) {
return null;
}

return (
<FernFileOrUrlImage
alt={title}
fileIdOrUrl={logoFile}
className="fern-logo"
height={logoImageHeight}
style={{ height: logoImageHeight }}
priority={true}
loading="eager"
quality={100}
/>
);
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 8605b12

Please sign in to comment.