Skip to content

Commit 2bd4360

Browse files
committed
improvement(changelog): present updates in a crawlable list
1 parent c3696fa commit 2bd4360

18 files changed

Lines changed: 157 additions & 137 deletions

File tree

‎apps/sim/app/(landing)/changelog/archive/page.tsx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import { CHANGELOG_SECTION, getAllEntryMeta } from '@/lib/changelog'
22
import { buildCollectionPageJsonLd } from '@/lib/content/seo'
33
import { buildLandingMetadata } from '@/lib/landing/seo'
44
import {
5-
ChangelogGrid,
65
ChangelogHeader,
76
ChangelogLayout,
7+
ChangelogList,
88
} from '@/app/(landing)/changelog/components'
99
import { BackLink } from '@/app/(landing)/components/back-link'
1010
import { JsonLd } from '@/app/(landing)/components/json-ld'
@@ -31,7 +31,7 @@ export default async function ChangelogArchivePage() {
3131
lead='New capabilities, improvements, and fixes in Sim, with the details in one place.'
3232
actions={<BackLink href='/changelog' label='Back to changelog' />}
3333
/>
34-
<ChangelogGrid entries={entries} />
34+
<ChangelogList entries={entries} />
3535
<a
3636
href='https://github.com/simstudioai/sim/releases'
3737
target='_blank'

‎apps/sim/app/(landing)/changelog/changelog.tsx‎

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@ import { CHANGELOG_SECTION, getAllEntryMeta, LATEST_ENTRY_LIMIT } from '@/lib/ch
33
import { buildCollectionPageJsonLd } from '@/lib/content/seo'
44
import {
55
ChangelogActions,
6-
ChangelogGrid,
76
ChangelogHeader,
87
ChangelogLayout,
8+
ChangelogList,
99
} from '@/app/(landing)/changelog/components'
1010
import { JsonLd } from '@/app/(landing)/components/json-ld'
1111

1212
export default async function Changelog() {
1313
const metadata = await getAllEntryMeta()
1414
const visible = metadata.slice(0, LATEST_ENTRY_LIMIT)
15+
const firstOlderEntry = metadata[LATEST_ENTRY_LIMIT]
1516
return (
1617
<ChangelogLayout>
1718
<JsonLd data={buildCollectionPageJsonLd(CHANGELOG_SECTION, visible)} />
@@ -20,11 +21,16 @@ export default async function Changelog() {
2021
lead={CHANGELOG_SECTION.description}
2122
actions={<ChangelogActions />}
2223
/>
23-
<ChangelogGrid entries={visible} featureLatest />
24+
<ChangelogList entries={visible} />
2425
<div className='flex flex-wrap gap-6 border-[var(--border)] border-t pt-6 text-[var(--text-secondary)] text-sm'>
25-
<Link href='/changelog/archive' className='underline underline-offset-4'>
26-
All updates
27-
</Link>
26+
{firstOlderEntry ? (
27+
<Link
28+
href={`/changelog/archive#${firstOlderEntry.slug}`}
29+
className='underline underline-offset-4'
30+
>
31+
Older updates
32+
</Link>
33+
) : null}
2834
<a
2935
href='https://github.com/simstudioai/sim/releases'
3036
target='_blank'

‎apps/sim/app/(landing)/changelog/components/changelog-article/changelog-article.tsx‎

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,12 @@ export function ChangelogArticle({
2121
? entry.updated
2222
: undefined
2323
return (
24-
<article id={entry.slug} className='mx-auto w-full max-w-[900px]'>
24+
<article
25+
id={entry.slug}
26+
className='mx-auto w-full max-w-[900px]'
27+
itemScope
28+
itemType='https://schema.org/BlogPosting'
29+
>
2530
<header className='flex flex-col items-start gap-6'>
2631
<BackLink href={backHref} label='Back to changelog' />
2732
<div className='flex flex-wrap items-center gap-x-4 gap-y-2 text-[var(--text-secondary)] text-sm'>
@@ -30,12 +35,21 @@ export function ChangelogArticle({
3035
{entry.release ? <span>{entry.release.versions.join(' · ')}</span> : null}
3136
{updated ? <time dateTime={entry.updated}>Updated {formatPostDate(updated)}</time> : null}
3237
</div>
33-
<h1 className={cn('text-balance text-[var(--text-primary)]', LANDING_TYPE.proof)}>
38+
<h1
39+
itemProp='headline'
40+
className={cn('text-balance text-[var(--text-primary)]', LANDING_TYPE.proof)}
41+
>
3442
{entry.title}
3543
</h1>
36-
<p className={cn('text-pretty text-[var(--text-secondary)]', LANDING_TYPE.lead)}>
44+
<p
45+
itemProp='description'
46+
className={cn('text-pretty text-[var(--text-secondary)]', LANDING_TYPE.lead)}
47+
>
3748
{entry.description}
3849
</p>
50+
<p className='text-[var(--text-secondary)] text-sm'>
51+
By {entry.authors.map((author) => author.name).join(', ')}
52+
</p>
3953
</header>
4054
<section
4155
id='update-details'

‎apps/sim/app/(landing)/changelog/components/changelog-grid/changelog-grid.tsx‎

Lines changed: 0 additions & 38 deletions
This file was deleted.

‎apps/sim/app/(landing)/changelog/components/changelog-grid/components/changelog-card/changelog-card.tsx‎

Lines changed: 0 additions & 77 deletions
This file was deleted.

‎apps/sim/app/(landing)/changelog/components/changelog-grid/components/changelog-card/index.ts‎

Lines changed: 0 additions & 1 deletion
This file was deleted.

‎apps/sim/app/(landing)/changelog/components/changelog-grid/index.ts‎

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import type { ContentMeta } from '@/lib/content/schema'
2+
import { ChangelogEntry } from '@/app/(landing)/changelog/components/changelog-list/components/changelog-entry'
3+
4+
interface ChangelogListProps {
5+
entries: ContentMeta[]
6+
basePath?: string
7+
}
8+
9+
/** Chronological rows share the landing frame, with copy beside media and a stacked mobile layout. */
10+
export function ChangelogList({ entries, basePath }: ChangelogListProps) {
11+
return (
12+
<section id='updates' aria-labelledby='updates-heading'>
13+
<h2 id='updates-heading' className='sr-only'>
14+
Product updates
15+
</h2>
16+
{entries.length > 0 ? (
17+
<ol className='divide-y divide-[var(--border)]'>
18+
{entries.map((entry, index) => (
19+
<li key={entry.slug} className='py-12 first:pt-0 last:pb-0 max-sm:py-8'>
20+
<ChangelogEntry entry={entry} priority={index === 0} basePath={basePath} />
21+
</li>
22+
))}
23+
</ol>
24+
) : (
25+
<p className='py-12 text-[var(--text-secondary)] text-md'>
26+
Product updates will appear here as they are published.
27+
</p>
28+
)}
29+
</section>
30+
)
31+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { cn } from '@sim/emcn'
2+
import { ArrowRight } from '@sim/emcn/icons'
3+
import Image from 'next/image'
4+
import Link from 'next/link'
5+
import { CHANGELOG_SECTION } from '@/lib/changelog/constants'
6+
import type { ContentMeta } from '@/lib/content/schema'
7+
import { formatPostDate } from '@/app/(landing)/components/content-utils'
8+
import { HOME_TYPE, LANDING_STAGE_RADIUS } from '@/app/(landing)/components/landing-layout'
9+
10+
interface ChangelogEntryProps {
11+
entry: ContentMeta
12+
priority: boolean
13+
basePath?: string
14+
}
15+
16+
const IMAGE_SIZES =
17+
'(min-width: 1728px) 663px, (min-width: 1280px) calc((100vw - 80px) * 5 / 12 - 24px), (min-width: 1024px) calc((100vw - 72px) * 5 / 12 - 24px), (min-width: 768px) calc(100vw - 64px), calc(100vw - 56px)'
18+
19+
export function ChangelogEntry({
20+
entry,
21+
priority,
22+
basePath = CHANGELOG_SECTION.basePath,
23+
}: ChangelogEntryProps) {
24+
return (
25+
<article id={entry.slug} aria-labelledby={`${entry.slug}-heading`} className='scroll-mt-28'>
26+
<Link
27+
href={`${basePath}/${entry.slug}`}
28+
aria-labelledby={`${entry.slug}-heading`}
29+
className={cn(
30+
'group grid min-w-0 grid-cols-2 items-center gap-12 focus-visible:outline focus-visible:outline-2 focus-visible:outline-[var(--text-primary)] focus-visible:outline-offset-8 max-lg:grid-cols-1 max-lg:gap-6',
31+
LANDING_STAGE_RADIUS
32+
)}
33+
>
34+
<div className='flex min-w-0 flex-col items-start gap-4'>
35+
<div className='flex flex-wrap items-center gap-x-4 gap-y-2 text-[var(--text-secondary)] text-sm'>
36+
<time dateTime={entry.date}>{formatPostDate(entry.date)}</time>
37+
{entry.draft ? <span>Draft</span> : null}
38+
</div>
39+
<h3
40+
id={`${entry.slug}-heading`}
41+
className={cn('text-balance text-[var(--text-primary)]', HOME_TYPE.h3)}
42+
>
43+
{entry.title}
44+
</h3>
45+
<p className={cn('text-pretty text-[var(--text-secondary)]', HOME_TYPE.body)}>
46+
{entry.description}
47+
</p>
48+
<span className='inline-flex items-center gap-2 text-[var(--text-primary)] text-sm'>
49+
Read update
50+
<ArrowRight
51+
aria-hidden='true'
52+
className='size-4 text-[var(--text-icon)] transition-transform duration-200 group-hover:translate-x-0.5 motion-reduce:transition-none'
53+
/>
54+
</span>
55+
</div>
56+
<div
57+
className={cn(
58+
'relative aspect-video overflow-hidden border border-[var(--border)] bg-[var(--surface-2)]',
59+
LANDING_STAGE_RADIUS
60+
)}
61+
>
62+
<Image
63+
src={entry.ogImage}
64+
alt={entry.ogAlt ?? entry.title}
65+
fill
66+
sizes={IMAGE_SIZES}
67+
priority={priority}
68+
className='object-contain'
69+
/>
70+
</div>
71+
</Link>
72+
</article>
73+
)
74+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { ChangelogEntry } from './changelog-entry'

0 commit comments

Comments
 (0)