Skip to content

Commit 207785c

Browse files
authored
v0.7.30: md editor improvements, og image updates, spacexai hosted keys, cmd-k speedups, pagespeed optimizations, security hardening
2 parents 6c3d11b + f477faa commit 207785c

112 files changed

Lines changed: 3853 additions & 728 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

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

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

77
const TITLE_FONT_SIZE = {
8-
large: 105,
9-
medium: 91,
10-
small: 81,
8+
large: 110,
9+
medium: 96,
10+
small: 85,
1111
} as const
1212
/** 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
13+
const LATIN_CHAR_WIDTH_EM = 0.42
14+
/** CJK glyphs (docs ships `ja`/`zh` locales) render near-square, roughly 2.4x a Latin glyph at this weight. */
15+
const CJK_CHAR_WIDTH_EM = 1
16+
const CJK_RANGE = /[\u3000-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uff00-\uffef]/
1417
const TITLE_BOX_WIDTH = 1020
1518
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'
19+
/** Exact hex from a vector trace of the reference cover template, not an estimate off compressed JPEG pixels. */
20+
const INK_COLOR = '#515151'
1821
const OG_CONTAINER_STYLE = {
1922
height: '100%',
2023
width: '100%',
2124
display: 'flex',
2225
flexDirection: 'column',
2326
justifyContent: 'space-between',
2427
padding: '26px',
25-
background: '#c3c3c3',
26-
fontFamily: 'Season',
28+
background: '#c1c1c1',
29+
fontFamily: 'Soehne',
2730
} satisfies CSSProperties
2831
const OG_HEADER_STYLE = {
2932
display: 'flex',
@@ -34,10 +37,12 @@ const OG_HEADER_STYLE = {
3437
const OG_TITLE_STYLE = {
3538
display: 'flex',
3639
flexDirection: 'column',
37-
fontWeight: 600,
40+
fontWeight: 500,
3841
color: INK_COLOR,
39-
lineHeight: 1.15,
42+
lineHeight: 1.1,
4043
width: `${TITLE_BOX_WIDTH}px`,
44+
/** Compensates for Satori adding extra invisible leading below the last line instead of splitting it evenly. */
45+
transform: 'translateY(14px)',
4146
} satisfies CSSProperties
4247

4348
function getTitleFontSize(title: string): number {
@@ -53,6 +58,41 @@ function getTitleStyle(title: string): CSSProperties {
5358
}
5459
}
5560

61+
/** Sums per-character em-widths rather than counting characters, so wide CJK glyphs (docs ships `ja`/`zh`) don't under-wrap. */
62+
function estimateWidthEm(text: string): number {
63+
let width = 0
64+
for (const char of text) {
65+
width += CJK_RANGE.test(char) ? CJK_CHAR_WIDTH_EM : LATIN_CHAR_WIDTH_EM
66+
}
67+
return width
68+
}
69+
70+
/**
71+
* Splits a single word wider than `maxWidthEm` into character-level chunks
72+
* that each fit. CJK titles (docs ships `ja`/`zh` locales) are often
73+
* space-free, so a whole run can arrive as one "word" from `wrapTitleLines`'
74+
* space-based split. Breaking mid-word is correct for CJK, where each glyph
75+
* is independently readable; Latin words never reach this path since they
76+
* stay under `maxWidthEm` in practice.
77+
*/
78+
function splitOversizedWord(word: string, maxWidthEm: number): string[] {
79+
const chunks: string[] = []
80+
let chunk = ''
81+
82+
for (const char of word) {
83+
const candidate = chunk + char
84+
if (estimateWidthEm(candidate) > maxWidthEm && chunk) {
85+
chunks.push(chunk)
86+
chunk = char
87+
} else {
88+
chunk = candidate
89+
}
90+
}
91+
if (chunk) chunks.push(chunk)
92+
93+
return chunks
94+
}
95+
5696
/**
5797
* Greedily packs words into lines that fit `TITLE_BOX_WIDTH` at `fontSize`,
5898
* then joins each line with U+00A0 instead of a plain space. Satori
@@ -63,14 +103,25 @@ function getTitleStyle(title: string): CSSProperties {
63103
* (which is also disabled here — lines are pre-split, not auto-wrapped).
64104
*/
65105
function wrapTitleLines(title: string, fontSize: number): string[] {
66-
const maxCharsPerLine = Math.floor(TITLE_BOX_WIDTH / (fontSize * AVG_CHAR_WIDTH_EM))
106+
const maxWidthEm = TITLE_BOX_WIDTH / fontSize
67107
const words = title.split(' ')
68108
const lines: string[] = []
69109
let current = ''
70110

71111
for (const word of words) {
112+
if (estimateWidthEm(word) > maxWidthEm) {
113+
if (current) {
114+
lines.push(current)
115+
current = ''
116+
}
117+
const chunks = splitOversizedWord(word, maxWidthEm)
118+
lines.push(...chunks.slice(0, -1))
119+
current = chunks[chunks.length - 1] ?? ''
120+
continue
121+
}
122+
72123
const candidate = current ? `${current} ${word}` : word
73-
if (candidate.length > maxCharsPerLine && current) {
124+
if (estimateWidthEm(candidate) > maxWidthEm && current) {
74125
lines.push(current)
75126
current = word
76127
} else {
@@ -83,21 +134,16 @@ function wrapTitleLines(title: string, fontSize: number): string[] {
83134
}
84135

85136
/**
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`.
137+
* Loads Söhne Kräftig (weight 500), the typeface used on the reference cover
138+
* template this OG image matches. Converted to a plain TTF from the
139+
* last-shipped `soehne-kraftig.woff2` since Satori (`next/og`'s renderer)
140+
* can't parse WOFF2 or variable fonts. Fetched over HTTP since the edge
141+
* runtime has no filesystem access — served from `/static/fonts/` (not
142+
* `/fonts/`) so it isn't intercepted by the site's i18n proxy (`proxy.ts`),
143+
* whose matcher excludes `static` but not `fonts`.
98144
*/
99-
async function loadSeasonFont(baseUrl: string): Promise<ArrayBuffer> {
100-
const response = await fetch(new URL('/static/fonts/SeasonSans-600-static.ttf', baseUrl), {
145+
async function loadTitleFont(baseUrl: string): Promise<ArrayBuffer> {
146+
const response = await fetch(new URL('/static/fonts/Soehne-Kraftig.ttf', baseUrl), {
101147
next: { revalidate: FONT_CACHE_REVALIDATE_SECONDS },
102148
})
103149

@@ -128,16 +174,16 @@ function SimWordmark() {
128174
)
129175
}
130176

131-
/** Diagonal "open" arrow, top-right — matches the library/blog cover template. */
177+
/** Diagonal "open" arrow, top-right — square caps and a miter join to match the reference's sharp corners. */
132178
function CornerArrow() {
133179
return (
134180
<svg width='58' height='58' viewBox='0 0 24 24' fill='none'>
135181
<path
136182
d='M2 22 22 2M22 2H12M22 2V12'
137183
stroke={INK_COLOR}
138184
strokeWidth={3.6}
139-
strokeLinecap='round'
140-
strokeLinejoin='round'
185+
strokeLinecap='square'
186+
strokeLinejoin='miter'
141187
/>
142188
</svg>
143189
)
@@ -153,7 +199,7 @@ export async function GET(request: NextRequest) {
153199
const { searchParams } = new URL(request.url)
154200
const title = searchParams.get('title') || 'Documentation'
155201

156-
const fontData = await loadSeasonFont(request.url)
202+
const fontData = await loadTitleFont(request.url)
157203
const fontSize = getTitleFontSize(title)
158204
const titleLines = wrapTitleLines(title, fontSize)
159205

@@ -175,10 +221,10 @@ export async function GET(request: NextRequest) {
175221
height: 675,
176222
fonts: [
177223
{
178-
name: 'Season',
224+
name: 'Soehne',
179225
data: fontData,
180226
style: 'normal',
181-
weight: 600,
227+
weight: 500,
182228
},
183229
],
184230
}

apps/docs/app/llms.txt/route.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ Sim is the open-source AI workspace where teams build, deploy, and manage AI age
4444
4545
## Documentation Overview
4646
47-
This file provides an overview of our documentation. For full content of all pages, see ${baseUrl}/llms-full.txt
47+
This file provides an overview of our documentation. For full content of all pages, see [llms-full.txt](${baseUrl}/llms-full.txt).
4848
4949
## Main Sections
5050
@@ -54,16 +54,16 @@ ${Object.entries(sections)
5454
.split('-')
5555
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
5656
.join(' ')
57-
return `### ${sectionTitle}\n\n${items.map((item) => `- ${item.title}: ${item.url}${item.description ? `\n ${item.description}` : ''}`).join('\n')}`
57+
return `### ${sectionTitle}\n\n${items.map((item) => `- [${item.title}](${item.url})${item.description ? `\n ${item.description}` : ''}`).join('\n')}`
5858
})
5959
.join('\n\n')}
6060
6161
## Additional Resources
6262
63-
- Full documentation content: ${baseUrl}/llms-full.txt
63+
- [Full documentation content](${baseUrl}/llms-full.txt)
6464
- Individual page content: ${baseUrl}/llms.mdx/[page-path]
65-
- API documentation: ${baseUrl}/api-reference/
66-
- Tool integrations: ${baseUrl}/tools/
65+
- [API documentation](${baseUrl}/api-reference/)
66+
- [Tool integrations](${baseUrl}/tools/)
6767
6868
## Statistics
6969

apps/docs/public/llms.txt

Lines changed: 0 additions & 51 deletions
This file was deleted.
-155 KB
Binary file not shown.
94.7 KB
Binary file not shown.

apps/sim/app/(landing)/components/content-index-page/content-index-page.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ export function ContentIndexPage({
9696
sizes='(max-width: 768px) 100vw, (max-width: 1024px) 50vw, 33vw'
9797
className='object-cover'
9898
priority={index < 3}
99+
fetchPriority={index === 0 ? 'high' : undefined}
99100
unoptimized
100101
/>
101102
</div>

apps/sim/app/(landing)/components/content-post-page/content-post-page.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export function ContentPostPage({
5252
className='h-auto w-full'
5353
sizes='(max-width: 768px) 100vw, 450px'
5454
priority
55+
fetchPriority='high'
5556
itemProp='image'
5657
unoptimized
5758
/>

apps/sim/app/(landing)/components/cta/cta.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { ChipLink } from '@sim/emcn'
2+
import { DEMO_HREF, SIGNUP_HREF } from '@/app/(landing)/constants'
23

34
/**
45
* Landing pre-footer CTA - the page's final conversion band. A tall, centered
@@ -28,10 +29,10 @@ export function Cta() {
2829
Build your first agent today.
2930
</h2>
3031
<div className='flex items-center gap-1'>
31-
<ChipLink variant='primary' href='/signup'>
32+
<ChipLink variant='primary' href={SIGNUP_HREF}>
3233
Get started
3334
</ChipLink>
34-
<ChipLink href='/demo' className='border border-[var(--border-1)]'>
35+
<ChipLink href={DEMO_HREF} className='border border-[var(--border-1)]'>
3536
Contact sales
3637
</ChipLink>
3738
</div>

apps/sim/app/(landing)/components/features/components/integrations-callout/integrations-callout.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,18 @@ import { CalloutFrame } from '@/app/(landing)/components/features/components/cal
1717
* the right AND bottom edges bleed past the media stage's clip - a zoomed-in
1818
* peek at part of the product rather than a complete miniature, scaling
1919
* proportionally with the aspect-locked stage. Decorative.
20+
*
21+
* `sizes` is derived directly from the section's grid math rather than
22+
* approximated, then rounded up to the worst-case (peak render/viewport
23+
* ratio) in each tier so the browser never under-fetches:
24+
* `callout = 1.25 * (viewport - 2*gutter - 32px card padding - [40px gap +
25+
* 386px fixed copy column, desktop only])`, gutter = `px-20`/`max-lg:px-8`/
26+
* `max-sm:px-5` from `Features`'s grid, matching `FeatureCard`'s
27+
* `max-lg:grid-cols-1` stack. Peak ratios (verified against a static
28+
* reproduction of this exact layout rendered at each Tailwind breakpoint):
29+
* ~113.3% at the `max-width: 1023px` stacked tier's own upper edge, ~108.6%
30+
* at `1460px` (the container's cap, where render width stops growing with
31+
* viewport - hence the final tier is a flat px value, not a vw fraction).
2032
*/
2133
export function IntegrationsCallout() {
2234
return (
@@ -29,7 +41,7 @@ export function IntegrationsCallout() {
2941
src='/landing/feature-integrate-ui.png'
3042
alt=''
3143
fill
32-
sizes='1050px'
44+
sizes='(max-width: 1023px) 114vw, (max-width: 1460px) 109vw, 1053px'
3345
className='object-cover'
3446
/>
3547
</CalloutFrame>

apps/sim/app/(landing)/components/hero-cta/hero-cta.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { ChipLink, cn } from '@sim/emcn'
2+
import { DEMO_HREF, SIGNUP_HREF } from '@/app/(landing)/constants'
23

34
/**
45
* Hero-scale sizing shared by both CTAs - one step up from the navbar's 30px
@@ -24,11 +25,11 @@ const CTA_SIZE = 'h-[36px] px-[0.571em] text-[15px] [&>span]:[font-size:inherit]
2425
export function HeroCta() {
2526
return (
2627
<div className='flex items-center gap-2 max-sm:w-full max-sm:flex-col max-sm:items-stretch'>
27-
<ChipLink variant='primary' href='/demo' className={CTA_SIZE}>
28+
<ChipLink variant='primary' href={DEMO_HREF} className={CTA_SIZE}>
2829
Request a demo
2930
</ChipLink>
3031
<ChipLink
31-
href='/signup'
32+
href={SIGNUP_HREF}
3233
prefetch={false}
3334
className={cn(CTA_SIZE, 'border border-[var(--border-1)] max-sm:justify-center')}
3435
>

0 commit comments

Comments
 (0)