Skip to content

Instantly share code, notes, and snippets.

@MarkAtOmniux
Last active September 11, 2024 15:32
Show Gist options
  • Save MarkAtOmniux/37f2f096cc8057f641e40e5734576d94 to your computer and use it in GitHub Desktop.
Save MarkAtOmniux/37f2f096cc8057f641e40e5734576d94 to your computer and use it in GitHub Desktop.
Example of a Payload Block with a swappable font on a NextJS frontend. This will lazy load fonts by default so any unwanted fonts won't contribute to page bloat.
// app/src/components/blocks/CustomTextBlock.tsx
import { styled } from "styled-components";
import React from 'react';
const TextElement: FC<any> = styled(p)`
${(props: any) => `font-family: ${fonts[props.$font.replace("-", "_").toLocaleLowerCase()].style.fontFamily}`}
`;
type Props = {
text: string;
font: 'inter' | 'comic_neue' | 'my_custom_font'
}
export const CustomTextBlock = ({ text, font }: ) => {
return <TextElement $font={font}>{text}</TextElement>
}
// app/src/lib/fonts.ts
import { NextFont, NextFontWithVariable } from "@next/font";
import {
Inter,
Comic_Neue,
} from "@next/font/google";
import localFont from "next/font/local";
const inter = Inter({
subsets: ["latin"],
weight: ["300", "400", "500", "600", "700"],
preload: false,
});
const comic_neue = Comic_Neue({
weight: ["300", "400", "700"],
subsets: ["latin"],
preload: false,
});
export const my_custom_font = localFont({
src: "./custom-font.otf",
weight: "400",
});
export default {
comic_neue,
inter,
my_custom_font,
} as {
[key: string]: NextFont | NextFontWithVariable;
};
app/src/app/(www)/layout.tsx
import StyledComponentsRegistry from './lib/registry'
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html>
<body>
<StyledComponentsRegistry>{children}</StyledComponentsRegistry>
</body>
</html>
)
}
// app/next.config.mjs
import { withPayload } from '@payloadcms/next/withPayload'
/** @type {import('next').NextConfig} */
const nextConfig = {
compiler: {
styledComponents: true,
},
}
export default withPayload(nextConfig)
// app/src/lib/registry.tsx
'use client'
import React, { useState } from 'react'
import { useServerInsertedHTML } from 'next/navigation'
import { ServerStyleSheet, StyleSheetManager } from 'styled-components'
export default function StyledComponentsRegistry({
children,
}: {
children: React.ReactNode
}) {
// Only create stylesheet once with lazy initial state
// x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet())
useServerInsertedHTML(() => {
const styles = styledComponentsStyleSheet.getStyleElement()
styledComponentsStyleSheet.instance.clearTag()
return <>{styles}</>
})
if (typeof window !== 'undefined') return <>{children}</>
return (
<StyleSheetManager sheet={styledComponentsStyleSheet.instance}>
{children}
</StyleSheetManager>
)
}
// app/src/blocks/TextBlock.ts
import { Block } from "payload/types";
export const TextBlock: Block = {
slug: "text-block",
labels: {
singular: "Text Block",
plural: "Text Blocks",
},
fields: [
{
type: 'text',
name: 'context'
},
{
type: 'select',
name: 'font',
options: ['inter', 'comic_neue', 'my_custom_font']
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment