Skip to content

Commit f3582ed

Browse files
authored
feat(branding): sim wordmark favicon/OG, docs footer parity, footer peel (#5587)
* feat(branding): sim wordmark favicon/OG, docs footer parity, footer peel - replace apps/sim favicon and default OG image with the sim wordmark logo (OG image widened, logo kept at native size) - swap the docs navbar logo to the icon-only mark (no wordmark text) - add a scroll "peel" reveal effect to the landing footer using a sticky-positioned illustration, pure CSS, no scroll listeners - port the same footer (link directory + peel effect) to the docs app so both apps are visually consistent; add Academy to Resources - rebuild the docs OG image template to match the site's existing blog/library cover style (wordmark top-left, arrow top-right, title bottom-left), working around a Satori text-measurement bug that doubled the gap after certain words * fix(docs): correct OG font, mobile logo, and footer stacking - switch the docs OG image title font from Geist to the site's real brand font (Season Sans), instantiated as a static TTF weight since Satori can't parse WOFF2 or variable fonts; served from /static/ so the i18n proxy's matcher (which excludes static but not fonts) doesn't intercept it - fix DocsLayout's nav.title (fumadocs' own mobile menu slot) to show the wordmark instead of the icon mark - add an isolated stacking context + higher z-index to both the docs and sim app footers so fumadocs' sticky z-20 sidebar can't paint over the footer content or the peel reveal * fix(docs): match OG template exactly, fix gradient/origin bugs - recalibrate the OG image to the reference cover template's actual measured values: 1200x675 canvas (was 630), ~26px margins (was 56-64px), ink #525252 (was #3f3f3f), larger wordmark/arrow/title sizing — confirmed by direct pixel measurement of the reference cover.jpg, not estimation - fix SimLogoIcon/SimLogoFull's SVG gradient ids to be unique via useId() instead of a fixed string, so multiple instances on one page don't collide (Greptile P2) - fix SIM_SITE_URL to be a hardcoded sim.ai constant instead of deriving from NEXT_PUBLIC_APP_URL, which reflects wherever this deployment runs, not the fixed public marketing site (Greptile P1) * fix(docs): route Jira footer link to the docs guide, not sim.ai Every other integration in the footer's Integrations column links to its own docs.sim.ai guide; Jira was the only one pointing at the marketing site's landing page instead, despite docs having its own /integrations/jira guide. Matches the established pattern. * fix(docs): fix sidebar-divider grid regression, footer-peel path/positioning, OG sizing, and prune stray comments - #nd-docs-layout::before divider now spans the full grid explicitly (grid-row/grid-column: 1 / -1) instead of being auto-placed into a real content cell, which was pushing page content down - footer-peel.jpg moved under /static/landing/ (was 404ing behind the i18n proxy's non-static path matcher) and wrapped in a relative div so next/image's fill positioning is valid under the sticky container - OG route: corrected title font sizes and char-width ratio so long titles wrap to 2 lines instead of 3, and resized the corner arrow to match the reference cover template's proportions - swapped the icon-only desktop navbar logo back to the wordmark - removed stray non-TSDoc comments, folded into TSDoc where the explanation was worth keeping * fix(footer): remove sticky peel reveal, keep clean footer link directory The peel's "reveal window" relied on position: sticky bottom-detaching into a containing block whose extra height came from padding-bottom — that combination doesn't reliably work in WebKit/Safari (sticky never gets room to engage when the surplus height is padding rather than an explicit height or content), so the peel stayed permanently covered by the footer regardless of viewport size. Rather than carry that unreliable technique further, removing it entirely from both apps and reverting to the plain footer link directory.
1 parent 1c60415 commit f3582ed

22 files changed

Lines changed: 375 additions & 80 deletions

apps/docs/app/[lang]/[[...slug]]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ export async function generateMetadata(props: {
323323
{
324324
url: ogImageUrl,
325325
width: 1200,
326-
height: 630,
326+
height: 675,
327327
alt: data.title,
328328
},
329329
],

apps/docs/app/[lang]/layout.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ import {
99
SidebarItem,
1010
SidebarSeparator,
1111
} from '@/components/docs-layout/sidebar-components'
12+
import { Footer } from '@/components/footer/footer'
1213
import { Navbar } from '@/components/navbar/navbar'
13-
import { SimLogoFull } from '@/components/ui/sim-logo'
14+
import { SimWordmark } from '@/components/ui/sim-logo'
1415
import { i18n } from '@/lib/i18n'
1516
import { serializeJsonLd } from '@/lib/json-ld'
1617
import { source } from '@/lib/source'
@@ -101,7 +102,7 @@ export default async function Layout({ children, params }: LayoutProps) {
101102
<DocsLayout
102103
tree={source.pageTree[lang]}
103104
nav={{
104-
title: <SimLogoFull className='h-[22px] w-auto' />,
105+
title: <SimWordmark className='h-[18px]' />,
105106
}}
106107
sidebar={{
107108
tabs: false,
@@ -121,6 +122,7 @@ export default async function Layout({ children, params }: LayoutProps) {
121122
>
122123
{children}
123124
</DocsLayout>
125+
<Footer />
124126
<AskAI locale={lang} />
125127
</RootProvider>
126128
</body>

apps/docs/app/api/og/route.tsx

Lines changed: 107 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -5,37 +5,39 @@ import type { NextRequest } from 'next/server'
55
export const runtime = 'edge'
66

77
const TITLE_FONT_SIZE = {
8-
large: 64,
9-
medium: 56,
10-
small: 48,
8+
large: 105,
9+
medium: 91,
10+
small: 81,
1111
} as const
12+
/** Average glyph width as a fraction of font size, for this weight/family — used to pack words into lines. */
13+
const AVG_CHAR_WIDTH_EM = 0.46
14+
const TITLE_BOX_WIDTH = 1020
1215
const FONT_CACHE_REVALIDATE_SECONDS = 60 * 60 * 24 * 30
16+
/** Measured off the reference cover template (`apps/sim/public/library/best-zapier-alternatives/cover.jpg`). */
17+
const INK_COLOR = '#525252'
1318
const OG_CONTAINER_STYLE = {
1419
height: '100%',
1520
width: '100%',
1621
display: 'flex',
1722
flexDirection: 'column',
1823
justifyContent: 'space-between',
19-
padding: '56px 64px',
20-
background: '#121212',
21-
fontFamily: 'Geist',
24+
padding: '26px',
25+
background: '#c3c3c3',
26+
fontFamily: 'Season',
2227
} satisfies CSSProperties
23-
const OG_TITLE_STYLE = {
24-
fontWeight: 500,
25-
color: '#fafafa',
26-
lineHeight: 1.2,
27-
letterSpacing: '-0.02em',
28-
} satisfies CSSProperties
29-
const OG_FOOTER_STYLE = {
28+
const OG_HEADER_STYLE = {
3029
display: 'flex',
3130
justifyContent: 'space-between',
32-
alignItems: 'center',
31+
alignItems: 'flex-start',
3332
width: '100%',
3433
} satisfies CSSProperties
35-
const OG_DOMAIN_STYLE = {
36-
fontSize: 24,
37-
fontWeight: 400,
38-
color: '#71717a',
34+
const OG_TITLE_STYLE = {
35+
display: 'flex',
36+
flexDirection: 'column',
37+
fontWeight: 600,
38+
color: INK_COLOR,
39+
lineHeight: 1.15,
40+
width: `${TITLE_BOX_WIDTH}px`,
3941
} satisfies CSSProperties
4042

4143
function getTitleFontSize(title: string): number {
@@ -52,90 +54,131 @@ function getTitleStyle(title: string): CSSProperties {
5254
}
5355

5456
/**
55-
* Loads a Google Font dynamically by fetching the CSS and extracting the font URL.
57+
* Greedily packs words into lines that fit `TITLE_BOX_WIDTH` at `fontSize`,
58+
* then joins each line with U+00A0 instead of a plain space. Satori
59+
* (`next/og`'s renderer) has a text-measurement bug where the first plain
60+
* space (U+0020) in a text node renders at roughly double width — a
61+
* non-breaking space measures correctly and reads identically at this size,
62+
* so it sidesteps the bug instead of fighting Satori's own line-wrapping
63+
* (which is also disabled here — lines are pre-split, not auto-wrapped).
5664
*/
57-
async function loadGoogleFont(font: string, weights: string, text: string): Promise<ArrayBuffer> {
58-
const url = `https://fonts.googleapis.com/css2?family=${font}:wght@${weights}&text=${encodeURIComponent(text)}`
59-
const cssResponse = await fetch(url, {
60-
next: { revalidate: FONT_CACHE_REVALIDATE_SECONDS },
61-
})
65+
function wrapTitleLines(title: string, fontSize: number): string[] {
66+
const maxCharsPerLine = Math.floor(TITLE_BOX_WIDTH / (fontSize * AVG_CHAR_WIDTH_EM))
67+
const words = title.split(' ')
68+
const lines: string[] = []
69+
let current = ''
6270

63-
if (!cssResponse.ok) {
64-
throw new Error(`Failed to load font CSS: ${cssResponse.status} ${cssResponse.statusText}`)
65-
}
66-
67-
const css = await cssResponse.text()
68-
const resource = css.match(/src: url\((.+)\) format\('(opentype|truetype)'\)/)
69-
70-
if (resource) {
71-
const response = await fetch(resource[1], {
72-
next: { revalidate: FONT_CACHE_REVALIDATE_SECONDS },
73-
})
74-
if (response.ok) {
75-
return await response.arrayBuffer()
71+
for (const word of words) {
72+
const candidate = current ? `${current} ${word}` : word
73+
if (candidate.length > maxCharsPerLine && current) {
74+
lines.push(current)
75+
current = word
76+
} else {
77+
current = candidate
7678
}
7779
}
80+
if (current) lines.push(current)
7881

79-
throw new Error('Failed to load font data')
82+
return lines.map((line) => line.replace(/ /g, ' '))
8083
}
8184

8285
/**
83-
* Sim logo with icon and "Sim" text for OG image.
86+
* Loads a static (600/semibold) TTF instance of the site's own Season Sans
87+
* font — the platform's real brand/body font, also used by the library/blog
88+
* cover template this OG image matches. Instantiated from the variable font
89+
* at `apps/docs/app/fonts/SeasonSansUprightsVF.woff2` (`fonttools
90+
* varLib.instancer wght=600`, then flavor-stripped to plain TTF) rather than
91+
* loading the variable WOFF2 directly: Satori (`next/og`'s renderer) can't
92+
* parse variable fonts without excessive memory use, and can't parse WOFF2
93+
* at all ("Unsupported OpenType signature wOF2") — it needs an uncompressed
94+
* TTF/OTF. Fetched over HTTP since the edge runtime has no filesystem access
95+
* — served from `/static/fonts/` (not `/fonts/`) so it isn't intercepted by
96+
* the site's i18n proxy (`proxy.ts`), whose matcher excludes `static` but
97+
* not `fonts`.
8498
*/
85-
function SimLogoFull() {
99+
async function loadSeasonFont(baseUrl: string): Promise<ArrayBuffer> {
100+
const response = await fetch(new URL('/static/fonts/SeasonSans-600-static.ttf', baseUrl), {
101+
next: { revalidate: FONT_CACHE_REVALIDATE_SECONDS },
102+
})
103+
104+
if (!response.ok) {
105+
throw new Error(`Failed to load font data: ${response.status} ${response.statusText}`)
106+
}
107+
108+
return await response.arrayBuffer()
109+
}
110+
111+
/** "sim" wordmark, no icon — same brandbook workmark geometry as the docs navbar/landing OG cards. */
112+
function SimWordmark() {
86113
return (
87-
<svg height='34' viewBox='720 440 1020 320' fill='none'>
88-
{/* Green icon - top left shape with cutout */}
114+
<svg width='118' height='57' viewBox='0 0 800 386' fill='none'>
115+
<path
116+
d='M0 293.75h53.4128c0 14.748 5.3413 26.506 16.0239 35.275 10.6826 8.37 25.1238 12.555 43.3233 12.555 19.783 0 35.016-3.786 45.698-11.36 10.683-7.971 16.024-18.534 16.024-31.687 0-9.566-2.967-17.538-8.902-23.915-5.539-6.378-15.826-11.559-30.861-15.545l-51.0389-11.958c-25.7173-6.377-44.9063-16.142-57.5672-29.296-12.2651-13.153-18.39771-30.491-18.39771-52.015 0-17.936 4.55001-33.481 13.64991-46.635 9.4957-13.153 22.3543-23.3169 38.576-30.4914 16.6173-7.1745 35.6086-10.7619 56.9739-10.7619 21.365 0 39.763 3.7866 55.193 11.3598 15.826 7.5731 28.091 18.1355 36.796 31.6875 9.1 13.552 13.847 29.695 14.243 48.428h-53.413c-.395-15.146-5.341-26.904-14.837-35.275-9.495-8.37-22.75-12.555-39.763-12.555-17.4083 0-30.8604 3.786-40.356 11.36-9.4956 7.573-14.2434 17.936-14.2434 31.089 0 19.531 14.2434 32.884 42.7304 40.058l51.039 12.556c24.53 5.58 42.928 14.747 55.193 27.502 12.265 12.356 18.398 29.296 18.398 50.82 0 18.335-4.946 34.477-14.837 48.428-9.891 13.552-23.541 24.114-40.95 31.687-17.013 7.175-37.191 10.762-60.534 10.762-34.0265 0-61.1285-8.37-81.3067-25.111-20.1782-16.74-30.2673-39.061-30.2673-66.962z'
117+
fill={INK_COLOR}
118+
/>
89119
<path
90-
fillRule='evenodd'
91-
clipRule='evenodd'
92-
d='M875.791 577.171C875.791 581.922 873.911 586.483 870.576 589.842L870.098 590.323C866.764 593.692 862.234 595.575 857.517 595.575H750.806C740.978 595.575 733 603.6 733 613.498V728.902C733 738.799 740.978 746.826 750.806 746.826H865.382C875.209 746.826 883.177 738.799 883.177 728.902V620.853C883.177 616.448 884.912 612.222 888.008 609.104C891.093 605.997 895.29 604.249 899.664 604.249H1008.16C1017.99 604.249 1025.96 596.224 1025.96 586.327V470.923C1025.96 461.025 1017.99 453 1008.16 453H893.586C883.759 453 875.791 461.025 875.791 470.923V577.171ZM910.562 477.566H991.178C996.922 477.566 1001.57 482.254 1001.57 488.029V569.22C1001.57 574.995 996.922 579.683 991.178 579.683H910.562C904.828 579.683 900.173 574.995 900.173 569.22V488.029C900.173 482.254 904.828 477.566 910.562 477.566Z'
93-
fill='#33C482'
120+
d='m267.175 385.826v-292.3631c22.244 8.1331 32.053 8.1331 55.787 0v292.3631zm27.3-311.6891c-9.891 0-18.596-3.5872-26.113-10.7618-7.122-7.5731-10.683-16.342-10.683-26.3067 0-10.3632 3.561-19.132 10.683-26.3066 7.517-7.17453 16.222-10.7618 26.113-10.7618 10.287 0 18.991 3.58727 26.113 10.7618 7.122 7.1746 10.682 15.9434 10.682 26.3066 0 9.9647-3.56 18.7336-10.682 26.3067-7.122 7.1746-15.826 10.7618-26.113 10.7618z'
121+
fill={INK_COLOR}
94122
/>
95-
{/* Green icon - bottom right square */}
96123
<path
97-
d='M1008.3 624.59H923.113C912.786 624.59 904.414 633.022 904.414 643.423V728.171C904.414 738.572 912.786 747.004 923.113 747.004H1008.3C1018.63 747.004 1027 738.572 1027 728.171V643.423C1027 633.022 1018.63 624.59 1008.3 624.59Z'
98-
fill='#33C482'
124+
d='m421.362 385.823h-55.786v-292.3624h49.852v49.3294c5.934-16.342 17.408-30.197 33.234-40.959 16.222-11.1605 35.807-16.7407 58.754-16.7407 25.718 0 47.083 6.9752 64.096 20.9257 17.013 13.951 28.091 32.485 33.234 55.603h-10.089c3.957-23.118 14.837-41.652 32.642-55.603 17.804-13.9505 39.762-20.9257 65.875-20.9257 33.235 0 59.348 9.7653 78.339 29.2957 18.991 19.531 28.487 46.236 28.487 80.116v191.321h-54.6v-177.57c0-23.118-5.934-40.855-17.804-53.211-11.474-12.755-27.102-19.132-46.885-19.132-13.847 0-26.113 3.189-36.795 9.566-10.287 5.979-18.398 14.748-24.333 26.307-5.934 11.559-8.902 25.111-8.902 40.655v173.385h-55.193v-178.168c0-23.118-5.737-40.655-17.211-52.613-11.474-12.356-27.102-18.534-46.885-18.534-13.847 0-26.112 3.189-36.795 9.566-10.287 5.979-18.398 14.748-24.333 26.307-5.934 11.16-8.902 24.513-8.902 40.057z'
125+
fill={INK_COLOR}
99126
/>
100-
{/* "Sim" text - white for dark background */}
127+
</svg>
128+
)
129+
}
130+
131+
/** Diagonal "open" arrow, top-right — matches the library/blog cover template. */
132+
function CornerArrow() {
133+
return (
134+
<svg width='58' height='58' viewBox='0 0 24 24' fill='none'>
101135
<path
102-
d='M1210.54 515.657C1226.65 515.657 1240.59 518.51 1252.31 524.257H1252.31C1264.3 529.995 1273.63 538.014 1280.26 548.319H1280.26C1287.19 558.635 1290.78 570.899 1291.08 585.068L1291.1 586.089H1249.11L1249.09 585.115C1248.8 574.003 1245.18 565.493 1238.32 559.451C1231.45 553.399 1221.79 550.308 1209.21 550.308C1196.3 550.308 1186.48 553.113 1179.61 558.588C1172.76 564.046 1169.33 571.499 1169.33 581.063C1169.33 588.092 1171.88 593.978 1177.01 598.783C1182.17 603.618 1189.99 607.399 1200.56 610.061H1200.56L1238.77 619.451C1257.24 623.65 1271.21 630.571 1280.57 640.293L1281.01 640.739C1290.13 650.171 1294.64 662.97 1294.64 679.016C1294.64 692.923 1290.88 705.205 1283.34 715.822L1283.33 715.834C1275.81 726.134 1265.44 734.14 1252.26 739.866L1252.25 739.871C1239.36 745.302 1224.12 748 1206.54 748C1180.9 748 1160.36 741.696 1145.02 728.984C1129.67 716.258 1122 699.269 1122 678.121V677.121H1163.99V678.121C1163.99 688.869 1167.87 697.367 1175.61 703.722L1176.34 704.284C1184.04 709.997 1194.37 712.902 1207.43 712.902C1222.13 712.902 1233.3 710.087 1241.07 704.588C1248.8 698.812 1252.64 691.21 1252.64 681.699C1252.64 674.769 1250.5 669.057 1246.25 664.49L1246.23 664.478L1246.22 664.464C1242.28 659.929 1234.83 656.119 1223.64 653.152L1185.43 644.208L1185.42 644.204C1166.05 639.407 1151.49 632.035 1141.83 622.012L1141.83 622.006L1141.82 622C1132.43 611.94 1127.78 598.707 1127.78 582.405C1127.78 568.81 1131.23 556.976 1138.17 546.949L1138.18 546.941L1138.19 546.933C1145.41 536.936 1155.18 529.225 1167.48 523.793L1167.48 523.79C1180.07 518.36 1194.43 515.657 1210.54 515.657ZM1323.39 521.979C1331.68 525.008 1337.55 526.482 1343.51 526.482C1349.48 526.482 1355.64 525.005 1364.49 521.973L1365.82 521.52V742.633H1322.05V521.489L1323.39 521.979ZM1642.01 515.657C1667.11 515.657 1686.94 523.031 1701.39 537.876C1715.83 552.716 1723 572.968 1723 598.507V742.633H1680.12V608.794C1680.12 591.666 1675.72 578.681 1667.07 569.681L1667.06 569.669L1667.04 569.656C1658.67 560.359 1647.26 555.675 1632.68 555.675C1622.47 555.675 1613.47 558.022 1605.64 562.69L1605.63 562.696C1598.11 567.064 1592.17 573.475 1587.8 581.968C1583.44 590.448 1581.25 600.424 1581.25 611.925V742.633H1537.92V608.347C1537.92 591.208 1533.67 578.376 1525.31 569.68L1525.31 569.674L1525.3 569.668C1516.93 560.664 1505.52 556.122 1490.93 556.122C1480.72 556.122 1471.72 558.469 1463.89 563.138L1463.88 563.144C1456.36 567.511 1450.41 573.922 1446.05 582.415L1446.05 582.422L1446.04 582.428C1441.69 590.602 1439.5 600.423 1439.5 611.925V742.633H1395.72V521.919H1435.05V554.803C1439.92 544.379 1447.91 535.465 1458.37 528.356C1470.71 519.875 1485.58 515.657 1502.93 515.657C1522.37 515.657 1538.61 520.931 1551.55 531.538C1560.38 538.771 1567.1 547.628 1571.72 558.091C1576.05 547.619 1582.83 538.757 1592.07 531.524C1605.61 520.93 1622.28 515.657 1642.01 515.657ZM1343.49 452C1351.45 452 1358.23 454.786 1363.75 460.346C1369.27 465.905 1372.04 472.721 1372.04 480.73C1372.04 488.452 1369.27 495.254 1363.77 501.096L1363.76 501.105L1363.75 501.115C1358.23 506.675 1351.45 509.461 1343.49 509.461C1335.81 509.461 1329.05 506.669 1323.25 501.134L1323.23 501.115L1323.21 501.096C1317.71 495.254 1314.94 488.452 1314.94 480.73C1314.94 472.721 1317.7 465.905 1323.23 460.346L1323.24 460.337L1323.25 460.327C1329.05 454.792 1335.81 452 1343.49 452Z'
103-
fill='#fafafa'
136+
d='M2 22 22 2M22 2H12M22 2V12'
137+
stroke={INK_COLOR}
138+
strokeWidth={3.6}
139+
strokeLinecap='round'
140+
strokeLinejoin='round'
104141
/>
105142
</svg>
106143
)
107144
}
108145

109146
/**
110-
* Generates dynamic Open Graph images for documentation pages.
111-
* Style matches Cursor docs: dark background, title at top, logo bottom-left, domain bottom-right.
147+
* Generates dynamic Open Graph images for documentation pages. Matches the
148+
* site's library/blog cover template: light gray background, "sim" wordmark
149+
* top-left, an open/diagonal arrow top-right, and the page title large and
150+
* bold at the bottom-left.
112151
*/
113152
export async function GET(request: NextRequest) {
114153
const { searchParams } = new URL(request.url)
115154
const title = searchParams.get('title') || 'Documentation'
116155

117-
const allText = `${title}docs.sim.ai`
118-
const fontData = await loadGoogleFont('Geist', '400;500;600', allText)
156+
const fontData = await loadSeasonFont(request.url)
157+
const fontSize = getTitleFontSize(title)
158+
const titleLines = wrapTitleLines(title, fontSize)
119159

120160
return new ImageResponse(
121161
<div style={OG_CONTAINER_STYLE}>
122-
{/* Title at top */}
123-
<span style={getTitleStyle(title)}>{title}</span>
162+
<div style={OG_HEADER_STYLE}>
163+
<SimWordmark />
164+
<CornerArrow />
165+
</div>
124166

125-
{/* Footer: icon left, domain right */}
126-
<div style={OG_FOOTER_STYLE}>
127-
<SimLogoFull />
128-
<span style={OG_DOMAIN_STYLE}>docs.sim.ai</span>
167+
<div style={getTitleStyle(title)}>
168+
{titleLines.map((line, index) => (
169+
<span key={index}>{line}</span>
170+
))}
129171
</div>
130172
</div>,
131173
{
132174
width: 1200,
133-
height: 630,
175+
height: 675,
134176
fonts: [
135177
{
136-
name: 'Geist',
178+
name: 'Season',
137179
data: fontData,
138180
style: 'normal',
181+
weight: 600,
139182
},
140183
],
141184
}

apps/docs/app/global.css

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -296,12 +296,20 @@ aside#nd-sidebar [data-radix-scroll-area-viewport] {
296296
min-height: var(--fd-docs-height) !important;
297297
}
298298

299-
/* Sidebar divider line — fixed to viewport, full height from navbar to bottom */
299+
/* Sidebar divider line — sticky within the docs layout box, so it ends where
300+
the layout does instead of bleeding into (or past) the footer below it.
301+
#nd-docs-layout is a CSS grid (see fumadocs' Container slot); a sticky
302+
pseudo-element stays in normal flow, so without an explicit grid-area it
303+
gets auto-placed into a real content cell and skews that cell's sizing.
304+
Spanning the full grid keeps it purely decorative/overlaid instead. */
300305
#nd-docs-layout::before {
301306
content: "";
302-
position: fixed;
307+
display: block;
308+
position: sticky;
309+
grid-row: 1 / -1;
310+
grid-column: 1 / -1;
303311
top: 92px; /* below navbar */
304-
bottom: 0;
312+
height: calc(100dvh - 92px);
305313
left: calc(var(--sidebar-offset) + var(--fd-sidebar-width));
306314
width: 1px;
307315
background-color: var(--surface-active);

apps/docs/app/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export const metadata = {
7272
{
7373
url: `${DOCS_BASE_URL}/api/og?title=Sim%20Documentation`,
7474
width: 1200,
75-
height: 630,
75+
height: 675,
7676
alt: 'Sim Documentation',
7777
},
7878
],

0 commit comments

Comments
 (0)