Head tags

This commit is contained in:
Stan Wohlwend 2024-03-08 06:23:02 +01:00
parent f1dec75d1e
commit df2130d36a
7 changed files with 57 additions and 1 deletions

View File

@ -1 +1,2 @@
STACKFRAME_URL=https://stackframe.co
STACK_HEAD_TAGS=[]

View File

@ -26,6 +26,8 @@ const config = {
onBrokenLinks: "throw",
onBrokenMarkdownLinks: "warn",
headTags: JSON.parse((console.log(process.env.STACK_HEAD_TAGS), process.env.STACK_HEAD_TAGS) || "[]"),
// Even if you don't use internationalization, you can use this field to set
// useful metadata like html lang. For example, if your site is Chinese, you
// may want to replace "en" with "zh-Hans".

View File

@ -20,4 +20,7 @@ DIRECT_DATABASE_CONNECTION_STRING=# enter your direct (unpooled or session mode)
STACK_ACCESS_TOKEN_EXPIRATION_TIME=# enter the expiration time for the access token here
NEXT_PUBLIC_DOC_URL=http://localhost:8104
NEXT_PUBLIC_STACK_HEAD_TAGS=[{ "tagName": "script", "attributes": {}, "innerHTML": "// insert head tags here" }]
NEXT_PUBLIC_DOC_URL=https://docs.stackframe.co

View File

@ -31,6 +31,7 @@
"node": ">=20.0.0"
},
"dependencies": {
"@vercel/analytics": "^1.2.2",
"@emotion/react": "^11.11.3",
"@emotion/styled": "^11.11.0",
"@mdx-js/loader": "^3",

View File

@ -2,10 +2,13 @@ import type { Metadata } from 'next';
import {GeistSans} from 'geist/font/sans';
import {GeistMono} from "geist/font/mono";
import { SnackbarProvider } from '@/hooks/use-snackbar';
import { Analytics } from "@vercel/analytics/react";
import './globals.css';
import ThemeProvider from '@/theme';
import { StyleLink } from '@/components/style-link';
import { getEnvVariable } from '@stackframe/stack-shared/dist/utils/env';
import React from 'react';
export const metadata: Metadata = {
title: {
@ -15,17 +18,34 @@ export const metadata: Metadata = {
description: 'Some frontend with auth built by N2D4',
};
type TagConfigJson = {
tagName: string,
attributes: { [key: string]: string },
innerHTML: string,
};
export default function RootLayout({
children,
}: {
children: React.ReactNode,
}) {
const headTags: TagConfigJson[] = JSON.parse(getEnvVariable('NEXT_PUBLIC_STACK_HEAD_TAGS'));
return (
<html lang="en" className={`${GeistSans.variable} ${GeistMono.variable}`}>
<head>
<link rel="preconnect" href="https://fonts.gstatic.com" />
<StyleLink href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded&display=block" />
<StyleLink defer href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.css" integrity="sha384-OH8qNTHoMMVNVcKdKewlipV4SErXqccxxlg6HC9Cwjr5oZu2AdBej1TndeCirael" crossOrigin="anonymous" />
{headTags.map((tag, index) => {
const { tagName, attributes, innerHTML } = tag;
return React.createElement(tagName, {
key: index,
dangerouslySetInnerHTML: { __html: innerHTML ?? "" },
...attributes,
});
})}
</head>
<body
style={{
@ -38,6 +58,7 @@ export default function RootLayout({
fontFamily: '"Brush Script MT", "Zapfino", "Comic Sans MS", cursive',
}}
>
<Analytics />
<ThemeProvider>
<SnackbarProvider>
{children}

View File

@ -1,8 +1,17 @@
import { throwErr } from "./errors";
import { deindent } from "./strings";
/**
* Returns the environment variable with the given name, throwing an error if it's undefined or the empty string.
*/
export function getEnvVariable(name: string): string {
if (typeof window !== 'undefined') {
throw new Error(deindent`
Can't use getEnvVariable on the client because Next.js transpiles expressions of the kind process.env.XYZ at build-time on the client.
Use process.env.XYZ directly instead.
`);
}
return (process.env[name] ?? throwErr(`Missing environment variable: ${name}`)) || throwErr(`Empty environment variable: ${name}`);
}

View File

@ -340,6 +340,9 @@ importers:
'@types/mdx':
specifier: ^2
version: 2.0.11
'@vercel/analytics':
specifier: ^1.2.2
version: 1.2.2(next@14.1.0)(react@18.2.0)
bcrypt:
specifier: ^5.1.1
version: 5.1.1
@ -6202,6 +6205,22 @@ packages:
/@ungap/structured-clone@1.2.0:
resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
/@vercel/analytics@1.2.2(next@14.1.0)(react@18.2.0):
resolution: {integrity: sha512-X0rctVWkQV1e5Y300ehVNqpOfSOufo7ieA5PIdna8yX/U7Vjz0GFsGf4qvAhxV02uQ2CVt7GYcrFfddXXK2Y4A==}
peerDependencies:
next: '>= 13'
react: ^18 || ^19
peerDependenciesMeta:
next:
optional: true
react:
optional: true
dependencies:
next: 14.1.0(react-dom@18.2.0)(react@18.2.0)
react: 18.2.0
server-only: 0.0.1
dev: false
/@vitest/expect@1.2.2:
resolution: {integrity: sha512-3jpcdPAD7LwHUUiT2pZTj2U82I2Tcgg2oVPvKxhn6mDI2On6tfvPQTjAI4628GUGDZrCm4Zna9iQHm5cEexOAg==}
dependencies: