Skip to content

Commit 10fa7c4

Browse files
committed
fix(landing): refresh content previews and remove legacy logos
1 parent 8ec065f commit 10fa7c4

29 files changed

Lines changed: 139 additions & 22 deletions

File tree

apps/docs/public/static/logo.png

-10.7 KB
Loading

apps/sim/content/authors/sim.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
"name": "The Sim Team",
44
"url": "https://x.com/simdotai",
55
"xHandle": "simdotai",
6-
"avatarUrl": "/logo/primary/small.png"
6+
"avatarUrl": "/brandbook/logo/small.png"
77
}

apps/sim/lib/content/seo.test.ts

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/**
2+
* @vitest-environment node
3+
*/
4+
import path from 'node:path'
5+
import sharp from 'sharp'
6+
import { describe, expect, it, vi } from 'vitest'
7+
import type { ContentMeta } from '@/lib/content/schema'
8+
import {
9+
buildArticleJsonLd,
10+
buildCollectionPageJsonLd,
11+
buildIndexMetadata,
12+
buildPostMetadata,
13+
} from '@/lib/content/seo'
14+
import { buildLandingMetadata, LANDING_SOCIAL_IMAGE } from '@/lib/landing/seo'
15+
import teamAuthor from '@/content/authors/sim.json'
16+
17+
vi.mock('@/lib/core/utils/urls', () => ({ SITE_URL: 'https://example.com' }))
18+
19+
const SECTIONS = [
20+
{ name: 'Blog', basePath: '/blog', description: 'Latest posts' },
21+
{ name: 'Library', basePath: '/library', description: 'Guides and comparisons' },
22+
{ name: 'Customers', basePath: '/customers', description: 'Customer stories' },
23+
]
24+
25+
const POST: ContentMeta = {
26+
slug: 'example',
27+
title: 'Example article',
28+
description: 'An article with its own cover image.',
29+
date: '2026-01-01T00:00:00.000Z',
30+
author: teamAuthor,
31+
authors: [teamAuthor],
32+
tags: ['guides'],
33+
ogImage: '/blog/example/cover.jpg',
34+
ogImageWidth: 1600,
35+
ogImageHeight: 900,
36+
canonical: 'https://example.com/blog/example',
37+
draft: false,
38+
featured: false,
39+
technical: true,
40+
}
41+
42+
describe('content social images', () => {
43+
it.each(SECTIONS)('$name shares the landing image across Open Graph and Twitter', (section) => {
44+
const metadata = buildIndexMetadata(section, { pageNum: 1 })
45+
const landing = buildLandingMetadata({
46+
title: 'Home',
47+
description: 'The workspace',
48+
path: '',
49+
})
50+
51+
expect(metadata.openGraph?.images).toEqual([
52+
{
53+
...LANDING_SOCIAL_IMAGE,
54+
url: `https://example.com${LANDING_SOCIAL_IMAGE.url}`,
55+
alt: `Sim ${section.name}`,
56+
},
57+
])
58+
expect(metadata.twitter?.images).toEqual({
59+
url: `https://example.com${LANDING_SOCIAL_IMAGE.url}`,
60+
alt: `Sim ${section.name}`,
61+
})
62+
expect(landing.openGraph?.images).toEqual([{ ...LANDING_SOCIAL_IMAGE, alt: 'Home' }])
63+
expect(metadata.alternates?.canonical).toBe(`https://example.com${section.basePath}`)
64+
})
65+
66+
it('declares the actual dimensions and format of the shared image', async () => {
67+
const metadata = await sharp(path.join('public', LANDING_SOCIAL_IMAGE.url)).metadata()
68+
69+
expect(metadata).toMatchObject({
70+
width: LANDING_SOCIAL_IMAGE.width,
71+
height: LANDING_SOCIAL_IMAGE.height,
72+
format: 'png',
73+
})
74+
expect(LANDING_SOCIAL_IMAGE.type).toBe('image/png')
75+
})
76+
77+
it('preserves filtered titles, canonical URLs, and noindex policy', () => {
78+
const metadata = buildIndexMetadata(SECTIONS[0], { tag: 'guides', pageNum: 2 })
79+
80+
expect(metadata.title).toBe('Blog | guides | Page 2')
81+
expect(metadata.alternates?.canonical).toBe('https://example.com/blog')
82+
expect(metadata.robots).toEqual({ index: false, follow: true })
83+
expect(metadata.openGraph?.images).toEqual(
84+
buildIndexMetadata(SECTIONS[0], { pageNum: 1 }).openGraph?.images
85+
)
86+
})
87+
88+
it('retains article-specific artwork and dimensions', () => {
89+
const metadata = buildPostMetadata(POST)
90+
91+
expect(metadata.openGraph?.images).toEqual([
92+
{
93+
url: `https://example.com${POST.ogImage}`,
94+
width: 1600,
95+
height: 900,
96+
alt: POST.title,
97+
},
98+
])
99+
expect(metadata.twitter?.images).toEqual([POST.ogImage])
100+
expect(buildArticleJsonLd(POST).image[0].url).toBe(`https://example.com${POST.ogImage}`)
101+
})
102+
103+
it('uses the current square logo for publishers and the team avatar', async () => {
104+
const article = buildArticleJsonLd(POST)
105+
const collection = buildCollectionPageJsonLd(SECTIONS[0], [POST])
106+
107+
expect(teamAuthor.avatarUrl).toBe('/brandbook/logo/small.png')
108+
expect(article.publisher.logo.url).toBe(`https://example.com${teamAuthor.avatarUrl}`)
109+
expect(collection.publisher.logo.url).toBe(article.publisher.logo.url)
110+
expect(await sharp(path.join('public', teamAuthor.avatarUrl)).metadata()).toMatchObject({
111+
width: 1200,
112+
height: 1200,
113+
format: 'png',
114+
})
115+
})
116+
})

apps/sim/lib/content/seo.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import type { Metadata } from 'next'
22
import type { Author, ContentMeta } from '@/lib/content/schema'
33
import { SITE_URL } from '@/lib/core/utils/urls'
4-
import { withFilteredNoindex } from '@/lib/landing/seo'
4+
import { LANDING_SOCIAL_IMAGE, withFilteredNoindex } from '@/lib/landing/seo'
5+
6+
const PUBLISHER_LOGO_URL = `${SITE_URL}/brandbook/logo/small.png`
57

68
/**
79
* Identifies the content section a post/collection belongs to, so the
@@ -113,7 +115,7 @@ export function buildArticleJsonLd(post: ContentMeta) {
113115
url: SITE_URL,
114116
logo: {
115117
'@type': 'ImageObject',
116-
url: `${SITE_URL}/logo/primary/medium.png`,
118+
url: PUBLISHER_LOGO_URL,
117119
},
118120
},
119121
mainEntityOfPage: {
@@ -215,9 +217,8 @@ export function buildIndexMetadata(
215217
type: 'website',
216218
images: [
217219
{
218-
url: `${SITE_URL}/logo/primary/medium.png`,
219-
width: 1200,
220-
height: 630,
220+
...LANDING_SOCIAL_IMAGE,
221+
url: `${SITE_URL}${LANDING_SOCIAL_IMAGE.url}`,
221222
alt: `Sim ${section.name}`,
222223
},
223224
],
@@ -227,6 +228,10 @@ export function buildIndexMetadata(
227228
title: `${title} | Sim`,
228229
description,
229230
site: '@simdotai',
231+
images: {
232+
url: `${SITE_URL}${LANDING_SOCIAL_IMAGE.url}`,
233+
alt: `Sim ${section.name}`,
234+
},
230235
},
231236
},
232237
isFiltered
@@ -389,7 +394,7 @@ export function buildCollectionPageJsonLd(
389394
url: SITE_URL,
390395
logo: {
391396
'@type': 'ImageObject',
392-
url: `${SITE_URL}/logo/primary/medium.png`,
397+
url: PUBLISHER_LOGO_URL,
393398
},
394399
},
395400
inLanguage: 'en-US',

apps/sim/lib/landing/seo.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import type { Metadata } from 'next'
22
import { SITE_URL } from '@/lib/core/utils/urls'
33

4-
/** Shared OpenGraph/Twitter card image for landing pages. */
5-
const OG_IMAGE_URL = '/logo/426-240/reverse/small.png'
6-
const OG_IMAGE_WIDTH = 2130
7-
const OG_IMAGE_HEIGHT = 1200
4+
/** Shared Open Graph/Twitter image for landing pages and content indexes. */
5+
export const LANDING_SOCIAL_IMAGE = {
6+
url: '/logo/426-240/reverse/small.png',
7+
width: 2130,
8+
height: 1200,
9+
type: 'image/png',
10+
} as const
811

912
interface LandingMetadataInput {
1013
/** Absolute `<title>`, rendered as-is (no site template applied). */
@@ -59,11 +62,8 @@ export function buildLandingMetadata({
5962
locale: 'en_US',
6063
images: [
6164
{
62-
url: OG_IMAGE_URL,
63-
width: OG_IMAGE_WIDTH,
64-
height: OG_IMAGE_HEIGHT,
65+
...LANDING_SOCIAL_IMAGE,
6566
alt: ogAlt,
66-
type: 'image/png',
6767
},
6868
],
6969
},
@@ -73,7 +73,7 @@ export function buildLandingMetadata({
7373
creator: '@simdotai',
7474
title,
7575
description,
76-
images: { url: OG_IMAGE_URL, alt: twitterAlt },
76+
images: { url: LANDING_SOCIAL_IMAGE.url, alt: twitterAlt },
7777
},
7878
alternates: {
7979
canonical: url,
-327 KB
Binary file not shown.
-96.7 KB
Binary file not shown.

apps/sim/public/logo/426-240/primary/primary.svg

Lines changed: 0 additions & 1 deletion
This file was deleted.
-8.12 KB
Binary file not shown.
-326 KB
Binary file not shown.

0 commit comments

Comments
 (0)