From 16520124272818ad7f481f747bee34effaca03eb Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Wed, 7 Oct 2026 23:14:52 -0700 Subject: [PATCH 1/7] feat(changelog): publish curated product updates --- .github/PULL_REQUEST_TEMPLATE.md | 3 + apps/sim/AGENTS.md | 2 +- .../app/(landing)/changelog/[slug]/page.tsx | 36 +++ .../app/(landing)/changelog/archive/page.tsx | 45 +++ .../sim/app/(landing)/changelog/changelog.tsx | 79 +++--- .../changelog-actions/changelog-actions.tsx | 4 +- .../changelog-article/changelog-article.tsx | 70 +++++ .../components/changelog-article/index.ts | 1 + .../changelog-grid/changelog-grid.tsx | 38 +++ .../changelog-card/changelog-card.tsx | 77 +++++ .../components/changelog-card/index.ts | 1 + .../components/changelog-grid/index.ts | 1 + .../changelog-header/changelog-header.tsx | 19 ++ .../components/changelog-header/index.ts | 1 + .../changelog-image/changelog-image.tsx | 38 +++ .../components/changelog-image/index.ts | 1 + .../changelog-layout/changelog-layout.tsx | 24 ++ .../components/changelog-layout/index.ts | 1 + .../changelog-timeline/changelog-timeline.tsx | 220 --------------- .../components/changelog-timeline/index.ts | 1 - .../changelog-video/changelog-video.tsx | 41 +++ .../components/changelog-video/index.ts | 1 + .../(landing)/changelog/components/index.ts | 7 +- apps/sim/app/(landing)/changelog/page.tsx | 9 +- .../changelog/preview/[slug]/page.tsx | 32 +++ .../app/(landing)/changelog/preview/page.tsx | 27 ++ apps/sim/app/(landing)/changelog/types.ts | 26 -- apps/sim/app/(landing)/changelog/utils.ts | 46 --- .../changelog-menu-preview.tsx | 61 ++-- .../(landing)/components/prose-page/index.ts | 2 - apps/sim/app/changelog.xml/route.ts | 89 +++--- apps/sim/app/sitemap.ts | 13 +- apps/sim/content/changelog/README.md | 126 +++++++++ .../compare-workflow-deployments/index.mdx | 31 ++ .../production.md | 42 +++ .../changelog/more-reliable-runs/index.mdx | 26 ++ .../more-reliable-runs/production.md | 24 ++ .../changelog/power-bi-for-agents/index.mdx | 30 ++ .../power-bi-for-agents/production.md | 35 +++ .../changelog/review-fork-changes/index.mdx | 29 ++ .../review-fork-changes/production.md | 41 +++ apps/sim/lib/changelog/constants.ts | 10 + apps/sim/lib/changelog/index.ts | 2 + apps/sim/lib/changelog/mdx.tsx | 47 ++++ apps/sim/lib/changelog/media.ts | 14 + apps/sim/lib/changelog/registry.ts | 38 +++ apps/sim/lib/content/registry-factory.ts | 32 ++- apps/sim/lib/content/schema.ts | 8 + apps/sim/lib/core/security/csp.ts | 4 +- ...er-width.mjs => hairline-border-width.cjs} | 2 +- .../lib/postcss/hairline-border-width.test.ts | 2 +- apps/sim/lib/workflows/comparison/overlay.ts | 2 +- apps/sim/postcss.config.mjs | 2 +- apps/sim/proxy.ts | 4 +- .../compare-workflow-deployments-v1.jpg | Bin 0 -> 81781 bytes .../compare-workflow-deployments-v1.mp4 | Bin 0 -> 210561 bytes .../public/changelog/power-bi-query-v1.jpg | Bin 0 -> 62141 bytes .../changelog/review-fork-changes-v1.jpg | Bin 0 -> 53241 bytes .../changelog/review-fork-changes-v1.mp4 | Bin 0 -> 146288 bytes bun.lock | 1 + package.json | 1 + packages/emcn/src/hooks/use-scroll-edges.ts | 2 + scripts/check-library-content.test.ts | 146 +++++++++- scripts/check-library-content.ts | 266 +++++++++++++++++- scripts/check-unused-exports.baseline.json | 3 - 65 files changed, 1520 insertions(+), 466 deletions(-) create mode 100644 apps/sim/app/(landing)/changelog/[slug]/page.tsx create mode 100644 apps/sim/app/(landing)/changelog/archive/page.tsx create mode 100644 apps/sim/app/(landing)/changelog/components/changelog-article/changelog-article.tsx create mode 100644 apps/sim/app/(landing)/changelog/components/changelog-article/index.ts create mode 100644 apps/sim/app/(landing)/changelog/components/changelog-grid/changelog-grid.tsx create mode 100644 apps/sim/app/(landing)/changelog/components/changelog-grid/components/changelog-card/changelog-card.tsx create mode 100644 apps/sim/app/(landing)/changelog/components/changelog-grid/components/changelog-card/index.ts create mode 100644 apps/sim/app/(landing)/changelog/components/changelog-grid/index.ts create mode 100644 apps/sim/app/(landing)/changelog/components/changelog-header/changelog-header.tsx create mode 100644 apps/sim/app/(landing)/changelog/components/changelog-header/index.ts create mode 100644 apps/sim/app/(landing)/changelog/components/changelog-image/changelog-image.tsx create mode 100644 apps/sim/app/(landing)/changelog/components/changelog-image/index.ts create mode 100644 apps/sim/app/(landing)/changelog/components/changelog-layout/changelog-layout.tsx create mode 100644 apps/sim/app/(landing)/changelog/components/changelog-layout/index.ts delete mode 100644 apps/sim/app/(landing)/changelog/components/changelog-timeline/changelog-timeline.tsx delete mode 100644 apps/sim/app/(landing)/changelog/components/changelog-timeline/index.ts create mode 100644 apps/sim/app/(landing)/changelog/components/changelog-video/changelog-video.tsx create mode 100644 apps/sim/app/(landing)/changelog/components/changelog-video/index.ts create mode 100644 apps/sim/app/(landing)/changelog/preview/[slug]/page.tsx create mode 100644 apps/sim/app/(landing)/changelog/preview/page.tsx delete mode 100644 apps/sim/app/(landing)/changelog/types.ts delete mode 100644 apps/sim/app/(landing)/changelog/utils.ts create mode 100644 apps/sim/content/changelog/README.md create mode 100644 apps/sim/content/changelog/compare-workflow-deployments/index.mdx create mode 100644 apps/sim/content/changelog/compare-workflow-deployments/production.md create mode 100644 apps/sim/content/changelog/more-reliable-runs/index.mdx create mode 100644 apps/sim/content/changelog/more-reliable-runs/production.md create mode 100644 apps/sim/content/changelog/power-bi-for-agents/index.mdx create mode 100644 apps/sim/content/changelog/power-bi-for-agents/production.md create mode 100644 apps/sim/content/changelog/review-fork-changes/index.mdx create mode 100644 apps/sim/content/changelog/review-fork-changes/production.md create mode 100644 apps/sim/lib/changelog/constants.ts create mode 100644 apps/sim/lib/changelog/index.ts create mode 100644 apps/sim/lib/changelog/mdx.tsx create mode 100644 apps/sim/lib/changelog/media.ts create mode 100644 apps/sim/lib/changelog/registry.ts rename apps/sim/lib/postcss/{hairline-border-width.mjs => hairline-border-width.cjs} (99%) create mode 100644 apps/sim/public/changelog/compare-workflow-deployments-v1.jpg create mode 100644 apps/sim/public/changelog/compare-workflow-deployments-v1.mp4 create mode 100644 apps/sim/public/changelog/power-bi-query-v1.jpg create mode 100644 apps/sim/public/changelog/review-fork-changes-v1.jpg create mode 100644 apps/sim/public/changelog/review-fork-changes-v1.mp4 diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 3592883c5e7..85b94ab26d9 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -3,6 +3,9 @@ Brief description of what this PR does and why. Fixes #(issue) +## Product update (if relevant) +Who benefits, and what can they do now? Note rollout or plan restrictions, link the relevant Sim integration or docs guide, and include a real product demo or changelog production brief when available. + ## Type of Change - [ ] Bug fix - [ ] New feature diff --git a/apps/sim/AGENTS.md b/apps/sim/AGENTS.md index 84feeac85ce..9da2a087205 100644 --- a/apps/sim/AGENTS.md +++ b/apps/sim/AGENTS.md @@ -21,7 +21,7 @@ For a common task, start from its skill (`.agents/skills//SKILL.md`): -# This is NOT the Next.js you know +## This is NOT the Next.js you know This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` (resolved from this file's directory; in monorepos the `next` package may not be visible from the repo root) before writing any code. Heed deprecation notices. diff --git a/apps/sim/app/(landing)/changelog/[slug]/page.tsx b/apps/sim/app/(landing)/changelog/[slug]/page.tsx new file mode 100644 index 00000000000..ec1ffb7f4bf --- /dev/null +++ b/apps/sim/app/(landing)/changelog/[slug]/page.tsx @@ -0,0 +1,36 @@ +import type { Metadata } from 'next' +import { notFound } from 'next/navigation' +import { CHANGELOG_SECTION, getAllEntryMeta, getEntryBySlug } from '@/lib/changelog' +import { buildPostGraphJsonLd, buildPostMetadata } from '@/lib/content/seo' +import { ChangelogArticle, ChangelogLayout } from '@/app/(landing)/changelog/components' +import { JsonLd } from '@/app/(landing)/components/json-ld' + +export const dynamicParams = false +export const revalidate = 3600 + +interface ChangelogEntryPageProps { + params: Promise<{ slug: string }> +} + +export async function generateStaticParams() { + return (await getAllEntryMeta()).map((entry) => ({ slug: entry.slug })) +} + +export async function generateMetadata({ params }: ChangelogEntryPageProps): Promise { + const { slug } = await params + const entry = await getEntryBySlug(slug) + return entry ? buildPostMetadata(entry) : {} +} + +export default async function ChangelogEntryPage({ params }: ChangelogEntryPageProps) { + const { slug } = await params + const entry = await getEntryBySlug(slug) + if (!entry) notFound() + + return ( + + + + + ) +} diff --git a/apps/sim/app/(landing)/changelog/archive/page.tsx b/apps/sim/app/(landing)/changelog/archive/page.tsx new file mode 100644 index 00000000000..60b2a603c84 --- /dev/null +++ b/apps/sim/app/(landing)/changelog/archive/page.tsx @@ -0,0 +1,45 @@ +import { CHANGELOG_SECTION, getAllEntryMeta } from '@/lib/changelog' +import { buildCollectionPageJsonLd } from '@/lib/content/seo' +import { buildLandingMetadata } from '@/lib/landing/seo' +import { + ChangelogGrid, + ChangelogHeader, + ChangelogLayout, +} from '@/app/(landing)/changelog/components' +import { BackLink } from '@/app/(landing)/components/back-link' +import { JsonLd } from '@/app/(landing)/components/json-ld' + +export const revalidate = 3600 +export const metadata = buildLandingMetadata({ + title: 'Changelog Archive | Sim', + description: 'Browse product updates from Sim and find the full technical release history.', + path: '/changelog/archive', +}) + +export default async function ChangelogArchivePage() { + const entries = await getAllEntryMeta() + return ( + + + } + /> + + + Earlier releases and full technical history on GitHub + + + ) +} diff --git a/apps/sim/app/(landing)/changelog/changelog.tsx b/apps/sim/app/(landing)/changelog/changelog.tsx index 78842b7f5c2..879396eb76e 100644 --- a/apps/sim/app/(landing)/changelog/changelog.tsx +++ b/apps/sim/app/(landing)/changelog/changelog.tsx @@ -1,50 +1,39 @@ -import { createLogger } from '@sim/logger' -import { getErrorMessage } from '@sim/utils/errors' -import { ChangelogActions, ChangelogTimeline } from '@/app/(landing)/changelog/components' -import type { ChangelogEntry, GitHubRelease } from '@/app/(landing)/changelog/types' -import { mapReleases, releasesEndpoint } from '@/app/(landing)/changelog/utils' -import { ProseHero, ProseShell } from '@/app/(landing)/components/prose-page' - -const logger = createLogger('Changelog') - -/** - * Changelog page - reuses the shared prose primitives ({@link ProseShell} + - * {@link ProseHero}) so its headline and column match Terms and Privacy, then - * renders the GitHub-release timeline. The first page of releases is - * fetched here on the server at build/revalidate time; the {@link ChangelogTimeline} - * client leaf paginates the rest. Re-authored from the prior dark changelog onto - * the platform light tokens. - */ - -const LEAD = - 'Every new feature, improvement, and fix in Sim, the open-source AI workspace, with release notes straight from GitHub.' - -async function getInitialEntries(): Promise { - try { - // boundary-raw-fetch: external GitHub Releases API (cross-origin), not a same-origin contract - const res = await fetch(releasesEndpoint(1), { - headers: { Accept: 'application/vnd.github+json' }, - next: { revalidate: 3600 }, - }) - const releases = (await res.json()) as GitHubRelease[] - return mapReleases(releases ?? []) - } catch (error) { - logger.warn('Failed to load initial changelog releases from GitHub', { - error: getErrorMessage(error), - }) - return [] - } -} +import Link from 'next/link' +import { CHANGELOG_SECTION, getAllEntryMeta, LATEST_ENTRY_LIMIT } from '@/lib/changelog' +import { buildCollectionPageJsonLd } from '@/lib/content/seo' +import { + ChangelogActions, + ChangelogGrid, + ChangelogHeader, + ChangelogLayout, +} from '@/app/(landing)/changelog/components' +import { JsonLd } from '@/app/(landing)/components/json-ld' export default async function Changelog() { - const entries = await getInitialEntries() - + const metadata = await getAllEntryMeta() + const visible = metadata.slice(0, LATEST_ENTRY_LIMIT) return ( - - } /> -
- -
-
+ + + } + /> + +
+ + All updates + + + Earlier releases on GitHub + +
+
) } diff --git a/apps/sim/app/(landing)/changelog/components/changelog-actions/changelog-actions.tsx b/apps/sim/app/(landing)/changelog/components/changelog-actions/changelog-actions.tsx index 686696ff15b..aa8c349564d 100644 --- a/apps/sim/app/(landing)/changelog/components/changelog-actions/changelog-actions.tsx +++ b/apps/sim/app/(landing)/changelog/components/changelog-actions/changelog-actions.tsx @@ -9,20 +9,18 @@ import { GithubOutlineIcon } from '@/components/icons' * beneath the changelog headline. A small client leaf because `ChipLink` is a * Client Component and its `leftIcon` is a component reference that cannot cross * the server→client boundary as a prop (same pattern as the platform pill CTA). - * GitHub is the primary filled chip; Docs and RSS are the default pills. */ export function ChangelogActions() { return (
- View on GitHub + Technical releases +
+ +
+ {entry.draft ? Draft : null} + + {entry.release ? {entry.release.versions.join(' · ')} : null} + {updated ? : null} +
+

+ {entry.title} +

+

+ {entry.description} +

+
+
+

+ In this update +

+ +
+ + + ) +} diff --git a/apps/sim/app/(landing)/changelog/components/changelog-article/index.ts b/apps/sim/app/(landing)/changelog/components/changelog-article/index.ts new file mode 100644 index 00000000000..893299fad9c --- /dev/null +++ b/apps/sim/app/(landing)/changelog/components/changelog-article/index.ts @@ -0,0 +1 @@ +export { ChangelogArticle } from './changelog-article' diff --git a/apps/sim/app/(landing)/changelog/components/changelog-grid/changelog-grid.tsx b/apps/sim/app/(landing)/changelog/components/changelog-grid/changelog-grid.tsx new file mode 100644 index 00000000000..32152c7b53c --- /dev/null +++ b/apps/sim/app/(landing)/changelog/components/changelog-grid/changelog-grid.tsx @@ -0,0 +1,38 @@ +import type { ContentMeta } from '@/lib/content/schema' +import { ChangelogCard } from '@/app/(landing)/changelog/components/changelog-grid/components/changelog-card' + +interface ChangelogGridProps { + entries: ContentMeta[] + featureLatest?: boolean + basePath?: string +} + +/** A featured story and two-column reading grid, using the customer-story composition. */ +export function ChangelogGrid({ entries, featureLatest = false, basePath }: ChangelogGridProps) { + return ( +
+

+ Product updates +

+ {entries.length > 0 ? ( + entries.map((entry, index) => ( + + )) + ) : ( +

+ Product updates will appear here as they are published. +

+ )} +
+ ) +} diff --git a/apps/sim/app/(landing)/changelog/components/changelog-grid/components/changelog-card/changelog-card.tsx b/apps/sim/app/(landing)/changelog/components/changelog-grid/components/changelog-card/changelog-card.tsx new file mode 100644 index 00000000000..eb7a174508b --- /dev/null +++ b/apps/sim/app/(landing)/changelog/components/changelog-grid/components/changelog-card/changelog-card.tsx @@ -0,0 +1,77 @@ +import { cn } from '@sim/emcn' +import { ArrowRight } from '@sim/emcn/icons' +import Image from 'next/image' +import Link from 'next/link' +import { CHANGELOG_SECTION } from '@/lib/changelog/constants' +import type { ContentMeta } from '@/lib/content/schema' +import { formatPostDate } from '@/app/(landing)/components/content-utils' +import { HOME_TYPE, LANDING_STAGE_RADIUS } from '@/app/(landing)/components/landing-layout' + +interface ChangelogCardProps { + entry: ContentMeta + featured: boolean + priority: boolean + basePath?: string +} + +const IMAGE_SIZES = + '(min-width: 1728px) 671px, (min-width: 1280px) calc((100vw - 80px) * 5 / 12 - 16px), (min-width: 1024px) calc((100vw - 72px) * 5 / 12 - 16px), (min-width: 768px) calc(50vw - 48px), calc(100vw - 56px)' + +export function ChangelogCard({ + entry, + featured, + priority, + basePath = CHANGELOG_SECTION.basePath, +}: ChangelogCardProps) { + return ( + +
+ {entry.ogAlt +
+
+ +

+ {entry.title} +

+

+ {entry.description} +

+ + Read update + +
+ + ) +} diff --git a/apps/sim/app/(landing)/changelog/components/changelog-grid/components/changelog-card/index.ts b/apps/sim/app/(landing)/changelog/components/changelog-grid/components/changelog-card/index.ts new file mode 100644 index 00000000000..a4096ad95a9 --- /dev/null +++ b/apps/sim/app/(landing)/changelog/components/changelog-grid/components/changelog-card/index.ts @@ -0,0 +1 @@ +export { ChangelogCard } from './changelog-card' diff --git a/apps/sim/app/(landing)/changelog/components/changelog-grid/index.ts b/apps/sim/app/(landing)/changelog/components/changelog-grid/index.ts new file mode 100644 index 00000000000..e463b8df97a --- /dev/null +++ b/apps/sim/app/(landing)/changelog/components/changelog-grid/index.ts @@ -0,0 +1 @@ +export { ChangelogGrid } from './changelog-grid' diff --git a/apps/sim/app/(landing)/changelog/components/changelog-header/changelog-header.tsx b/apps/sim/app/(landing)/changelog/components/changelog-header/changelog-header.tsx new file mode 100644 index 00000000000..7a4071dd01f --- /dev/null +++ b/apps/sim/app/(landing)/changelog/components/changelog-header/changelog-header.tsx @@ -0,0 +1,19 @@ +import type { ReactNode } from 'react' +import { cn } from '@sim/emcn' +import { LANDING_TYPE } from '@/app/(landing)/components/landing-layout' + +interface ChangelogHeaderProps { + title: string + lead: string + actions?: ReactNode +} + +export function ChangelogHeader({ title, lead, actions }: ChangelogHeaderProps) { + return ( +
+

{title}

+

{lead}

+ {actions} +
+ ) +} diff --git a/apps/sim/app/(landing)/changelog/components/changelog-header/index.ts b/apps/sim/app/(landing)/changelog/components/changelog-header/index.ts new file mode 100644 index 00000000000..62956d444f2 --- /dev/null +++ b/apps/sim/app/(landing)/changelog/components/changelog-header/index.ts @@ -0,0 +1 @@ +export { ChangelogHeader } from './changelog-header' diff --git a/apps/sim/app/(landing)/changelog/components/changelog-image/changelog-image.tsx b/apps/sim/app/(landing)/changelog/components/changelog-image/changelog-image.tsx new file mode 100644 index 00000000000..8658cbafc56 --- /dev/null +++ b/apps/sim/app/(landing)/changelog/components/changelog-image/changelog-image.tsx @@ -0,0 +1,38 @@ +import { cn } from '@sim/emcn' +import Image from 'next/image' +import { LANDING_STAGE_RADIUS } from '@/app/(landing)/components/landing-layout' + +interface ChangelogImageProps { + src: string + alt: string + width: number | `${number}` + height: number | `${number}` + caption?: string +} + +/** Product screenshots reserve their intrinsic size and use the site's image optimization. */ +export function ChangelogImage({ src, alt, width, height, caption }: ChangelogImageProps) { + return ( +
+ {alt} +
+ {caption ?

{caption}

: null} + + View full-size image + +
+
+ ) +} diff --git a/apps/sim/app/(landing)/changelog/components/changelog-image/index.ts b/apps/sim/app/(landing)/changelog/components/changelog-image/index.ts new file mode 100644 index 00000000000..a29106002e5 --- /dev/null +++ b/apps/sim/app/(landing)/changelog/components/changelog-image/index.ts @@ -0,0 +1 @@ +export { ChangelogImage } from './changelog-image' diff --git a/apps/sim/app/(landing)/changelog/components/changelog-layout/changelog-layout.tsx b/apps/sim/app/(landing)/changelog/components/changelog-layout/changelog-layout.tsx new file mode 100644 index 00000000000..a829958a008 --- /dev/null +++ b/apps/sim/app/(landing)/changelog/components/changelog-layout/changelog-layout.tsx @@ -0,0 +1,24 @@ +import type { ReactNode } from 'react' +import { cn } from '@sim/emcn' +import { + HOME_INSET, + LANDING_CONTENT_WIDTH, + LANDING_GUTTER, + LANDING_HERO_TOP_PADDING, +} from '@/app/(landing)/components/landing-layout' + +interface ChangelogLayoutProps { + children: ReactNode +} + +/** Matches the marketing page frame; updates inherit the shared navbar and footer. */ +export function ChangelogLayout({ children }: ChangelogLayoutProps) { + return ( +
+
{children}
+
+ ) +} diff --git a/apps/sim/app/(landing)/changelog/components/changelog-layout/index.ts b/apps/sim/app/(landing)/changelog/components/changelog-layout/index.ts new file mode 100644 index 00000000000..ea8c7b7f3e3 --- /dev/null +++ b/apps/sim/app/(landing)/changelog/components/changelog-layout/index.ts @@ -0,0 +1 @@ +export { ChangelogLayout } from './changelog-layout' diff --git a/apps/sim/app/(landing)/changelog/components/changelog-timeline/changelog-timeline.tsx b/apps/sim/app/(landing)/changelog/components/changelog-timeline/changelog-timeline.tsx deleted file mode 100644 index eb882c155fe..00000000000 --- a/apps/sim/app/(landing)/changelog/components/changelog-timeline/changelog-timeline.tsx +++ /dev/null @@ -1,220 +0,0 @@ -'use client' - -import { type ReactNode, useRef, useState } from 'react' -import { Streamdown } from 'streamdown' -import 'streamdown/styles.css' -import { Avatar, AvatarFallback, AvatarImage, Chip, cn } from '@sim/emcn' -import { formatDate } from '@sim/utils/formatting' -import type { ChangelogEntry, GitHubRelease } from '@/app/(landing)/changelog/types' -import { mapReleases, releasesEndpoint } from '@/app/(landing)/changelog/utils' - -/** - * The changelog timeline - the single client leaf of the changelog page. Renders - * each GitHub release as a `
` (an `

` version tag + contributor - * avatars + cleaned markdown via {@link Streamdown}) and paginates further pages - * from the GitHub Releases API on demand. Re-authored from the prior dark - * timeline onto the platform light tokens; the fetch, markdown cleaning, and - * load-more behavior are preserved. - */ - -interface ChangelogTimelineProps { - initialEntries: ChangelogEntry[] -} - -function stripContributors(body: string): string { - let output = body - output = output.replace( - /(^|\n)#{1,6}\s*Contributors\s*\n[\s\S]*?(?=\n\s*\n|\n#{1,6}\s|$)/gi, - '\n' - ) - output = output.replace( - /(^|\n)\s*(?:\*\*|__)?\s*Contributors\s*(?:\*\*|__)?\s*:?\s*\n[\s\S]*?(?=\n\s*\n|\n#{1,6}\s|$)/gi, - '\n' - ) - output = output.replace( - /(^|\n)[-*+]\s*(?:@[A-Za-z0-9-]+(?:\s*,\s*|\s+))+@[A-Za-z0-9-]+\s*(?=\n)/g, - '\n' - ) - output = output.replace( - /(^|\n)\s*(?:@[A-Za-z0-9-]+(?:\s*,\s*|\s+))+@[A-Za-z0-9-]+\s*(?=\n)/g, - '\n' - ) - return output -} - -function stripPrReferences(body: string): string { - return body.replace(/\s*\(\s*\[#\d+\]\([^)]*\)\s*\)/g, '').replace(/\s*\(\s*#\d+\s*\)/g, '') -} - -function cleanMarkdown(body: string): string { - return stripPrReferences(stripContributors(body)) -} - -function isContributorsLabel(children: ReactNode): boolean { - return /^\s*contributors\s*:?\s*$/i.test(String(children)) -} - -export function ChangelogTimeline({ initialEntries }: ChangelogTimelineProps) { - const [entries, setEntries] = useState(initialEntries) - const [loading, setLoading] = useState(false) - const [done, setDone] = useState(false) - const pageRef = useRef(1) - - const loadMore = async () => { - if (loading || done) return - setLoading(true) - try { - const nextPage = pageRef.current + 1 - // boundary-raw-fetch: external GitHub Releases API (cross-origin), not a same-origin contract - const res = await fetch(releasesEndpoint(nextPage), { - headers: { Accept: 'application/vnd.github+json' }, - }) - const releases = (await res.json()) as GitHubRelease[] - const mapped = mapReleases(releases ?? []) - - if (mapped.length === 0) { - setDone(true) - } else { - setEntries((prev) => [...prev, ...mapped]) - pageRef.current = nextPage - } - } catch { - setDone(true) - } finally { - setLoading(false) - } - } - - return ( -
- {entries.map((entry) => { - const headingId = `release-${entry.tag}-heading` - return ( -
-
-
-

- {entry.tag} -

- {entry.contributors.length > 0 ? ( -
- {entry.contributors.slice(0, 5).map((contributor) => ( - - - - {contributor.slice(0, 2).toUpperCase()} - - - ))} - {entry.contributors.length > 5 ? ( -
- +{entry.contributors.length - 5} -
- ) : null} -
- ) : null} -
- - {formatDate(new Date(entry.date))} - -
- -
- ) - })} - - {!done ? ( -
- - {loading ? 'Loading…' : 'Show more'} - -
- ) : null} -
- ) -} diff --git a/apps/sim/app/(landing)/changelog/components/changelog-timeline/index.ts b/apps/sim/app/(landing)/changelog/components/changelog-timeline/index.ts deleted file mode 100644 index f7ac9baa67a..00000000000 --- a/apps/sim/app/(landing)/changelog/components/changelog-timeline/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { ChangelogTimeline } from './changelog-timeline' diff --git a/apps/sim/app/(landing)/changelog/components/changelog-video/changelog-video.tsx b/apps/sim/app/(landing)/changelog/components/changelog-video/changelog-video.tsx new file mode 100644 index 00000000000..c1557e44aa0 --- /dev/null +++ b/apps/sim/app/(landing)/changelog/components/changelog-video/changelog-video.tsx @@ -0,0 +1,41 @@ +import { cn } from '@sim/emcn' +import { isChangelogMediaSource } from '@/lib/changelog/media' +import { LANDING_STAGE_RADIUS } from '@/app/(landing)/components/landing-layout' + +interface ChangelogVideoProps { + src: string + poster: string + caption: string + captionsSrc?: string +} + +/** Product recordings load on demand and retain a readable description without playback. */ +export function ChangelogVideo({ src, poster, caption, captionsSrc }: ChangelogVideoProps) { + if (!isChangelogMediaSource(src) || (captionsSrc && !isChangelogMediaSource(captionsSrc))) { + throw new Error('Changelog recordings must use same-origin paths or the approved media CDN') + } + return ( +
+ +
{caption}
+
+ ) +} diff --git a/apps/sim/app/(landing)/changelog/components/changelog-video/index.ts b/apps/sim/app/(landing)/changelog/components/changelog-video/index.ts new file mode 100644 index 00000000000..e766a87170d --- /dev/null +++ b/apps/sim/app/(landing)/changelog/components/changelog-video/index.ts @@ -0,0 +1 @@ +export { ChangelogVideo } from './changelog-video' diff --git a/apps/sim/app/(landing)/changelog/components/index.ts b/apps/sim/app/(landing)/changelog/components/index.ts index 5af19189c40..e16dd5e219b 100644 --- a/apps/sim/app/(landing)/changelog/components/index.ts +++ b/apps/sim/app/(landing)/changelog/components/index.ts @@ -1,2 +1,7 @@ export { ChangelogActions } from './changelog-actions' -export { ChangelogTimeline } from './changelog-timeline' +export { ChangelogArticle } from './changelog-article' +export { ChangelogGrid } from './changelog-grid' +export { ChangelogHeader } from './changelog-header' +export { ChangelogImage } from './changelog-image' +export { ChangelogLayout } from './changelog-layout' +export { ChangelogVideo } from './changelog-video' diff --git a/apps/sim/app/(landing)/changelog/page.tsx b/apps/sim/app/(landing)/changelog/page.tsx index 46180cfc7c0..597ea9a1e49 100644 --- a/apps/sim/app/(landing)/changelog/page.tsx +++ b/apps/sim/app/(landing)/changelog/page.tsx @@ -1,15 +1,12 @@ +import { CHANGELOG_SECTION } from '@/lib/changelog' import { buildLandingMetadata } from '@/lib/landing/seo' import Changelog from '@/app/(landing)/changelog/changelog' export const revalidate = 3600 -const TITLE = 'Changelog | Sim, the AI Workspace' -const DESCRIPTION = - 'Every new feature, improvement, and fix in Sim, the open-source AI workspace, with release notes straight from GitHub.' - export const metadata = buildLandingMetadata({ - title: TITLE, - description: DESCRIPTION, + title: 'Changelog | Sim, the AI Workspace', + description: CHANGELOG_SECTION.description, path: '/changelog', }) diff --git a/apps/sim/app/(landing)/changelog/preview/[slug]/page.tsx b/apps/sim/app/(landing)/changelog/preview/[slug]/page.tsx new file mode 100644 index 00000000000..69caf40d571 --- /dev/null +++ b/apps/sim/app/(landing)/changelog/preview/[slug]/page.tsx @@ -0,0 +1,32 @@ +import type { Metadata } from 'next' +import { notFound } from 'next/navigation' +import { getEntryPreview } from '@/lib/changelog' +import { ChangelogArticle, ChangelogLayout } from '@/app/(landing)/changelog/components' + +export const metadata: Metadata = { + title: { absolute: 'Changelog preview | Sim' }, + robots: { index: false, follow: false }, +} + +interface ChangelogDraftPageProps { + params: Promise<{ slug: string }> +} + +export default async function ChangelogDraftPage({ params }: ChangelogDraftPageProps) { + if (process.env.NODE_ENV !== 'development') notFound() + const { slug } = await params + const entry = await getEntryPreview(slug) + if (!entry) notFound() + return ( + +

+ Local editorial preview. Verify the feature, availability, and media before publishing. +

+ +
+ ) +} diff --git a/apps/sim/app/(landing)/changelog/preview/page.tsx b/apps/sim/app/(landing)/changelog/preview/page.tsx new file mode 100644 index 00000000000..24a49c60971 --- /dev/null +++ b/apps/sim/app/(landing)/changelog/preview/page.tsx @@ -0,0 +1,27 @@ +import type { Metadata } from 'next' +import { notFound } from 'next/navigation' +import { getAllEntryPreviews } from '@/lib/changelog' +import { + ChangelogGrid, + ChangelogHeader, + ChangelogLayout, +} from '@/app/(landing)/changelog/components' + +export const metadata: Metadata = { + title: { absolute: 'Changelog preview | Sim' }, + robots: { index: false, follow: false }, +} + +export default async function ChangelogPreviewPage() { + if (process.env.NODE_ENV !== 'development') notFound() + const entries = await getAllEntryPreviews() + return ( + + + + + ) +} diff --git a/apps/sim/app/(landing)/changelog/types.ts b/apps/sim/app/(landing)/changelog/types.ts deleted file mode 100644 index c3c57754672..00000000000 --- a/apps/sim/app/(landing)/changelog/types.ts +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Changelog types shared between the server page (initial fetch) and the client - * timeline (load-more). {@link GitHubRelease} is the minimal shape we read from - * the GitHub Releases API; {@link ChangelogEntry} is the normalized entry the UI - * renders. - */ - -/** The minimal subset of a GitHub Releases API item that the changelog reads. */ -export interface GitHubRelease { - tag_name: string - name: string | null - body: string | null - published_at: string - html_url: string - prerelease: boolean -} - -/** A normalized changelog entry rendered in the timeline. */ -export interface ChangelogEntry { - tag: string - title: string - content: string - date: string - url: string - contributors: string[] -} diff --git a/apps/sim/app/(landing)/changelog/utils.ts b/apps/sim/app/(landing)/changelog/utils.ts deleted file mode 100644 index 4abdc06a042..00000000000 --- a/apps/sim/app/(landing)/changelog/utils.ts +++ /dev/null @@ -1,46 +0,0 @@ -import type { ChangelogEntry, GitHubRelease } from '@/app/(landing)/changelog/types' - -/** - * Changelog helpers shared by the server page (initial page) and the client - * timeline (subsequent pages), so the GitHub-release → entry mapping is defined - * once and both surfaces stay in sync. - */ - -/** How many releases to request per GitHub API page. */ -export const RELEASES_PER_PAGE = 10 - -/** Builds the GitHub Releases endpoint for a given 1-based page. */ -export function releasesEndpoint(page: number): string { - return `https://api.github.com/repos/simstudioai/sim/releases?per_page=${RELEASES_PER_PAGE}&page=${page}` -} - -/** Removes literal ` ` artifacts from release bodies. */ -export function sanitizeContent(body: string): string { - return body.replace(/ /g, '') -} - -/** Extracts unique `@handle` GitHub mentions from a release body. */ -export function extractMentions(body: string): string[] { - const matches = body.match(/@([A-Za-z0-9-]+)/g) ?? [] - return Array.from(new Set(matches.map((mention) => mention.slice(1)))) -} - -/** Maps non-prerelease GitHub releases to normalized {@link ChangelogEntry} items. */ -export function mapReleases(releases: GitHubRelease[]): ChangelogEntry[] { - return releases.reduce((acc, release) => { - if (release.prerelease) { - return acc - } - - const body = String(release.body ?? '') - acc.push({ - tag: release.tag_name, - title: release.name || release.tag_name, - content: sanitizeContent(body), - date: release.published_at, - url: release.html_url, - contributors: extractMentions(body), - }) - return acc - }, []) -} diff --git a/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/components/changelog-menu-preview/changelog-menu-preview.tsx b/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/components/changelog-menu-preview/changelog-menu-preview.tsx index 48001f86b35..c11cc4a0f71 100644 --- a/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/components/changelog-menu-preview/changelog-menu-preview.tsx +++ b/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/components/changelog-menu-preview/changelog-menu-preview.tsx @@ -1,46 +1,43 @@ +import { cn } from '@sim/emcn' import { Calendar } from '@sim/emcn/icons' +import Image from 'next/image' +import { LANDING_STAGE_RADIUS } from '@/app/(landing)/components/landing-layout' import { MenuPreviewFrame } from '@/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/components/menu-preview-frame' import { MenuPreviewHeader } from '@/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/components/menu-preview-header/menu-preview-header' -/** Release dates and summaries come from the checked-in release announcements. */ -const RELEASES = [ - { - date: 'Mar 17', - year: '2026', - title: 'Your agents, in one workspace', - description: 'One workspace for your agents, data, and tools.', - }, - { - date: 'Jan 22', - year: '2026', - title: 'Copilot & MCP deployment', - description: 'Build with context. Deploy any workflow as a tool.', - }, -] as const - -/** An open release timeline with quiet separators and content extending past the cropped window. */ +/** An illustrative crop of the changelog's featured update and story cards. */ export function ChangelogMenuPreview() { return (
-
-
- {RELEASES.map(({ date, year, title, description }) => ( -
-
-
{date}
-
{year}
-
- -
-
{title}
-

- {description} -

+
+
+ +
+
+ Bring Power BI data into your agents
+

+ Query models, inspect reports, and request refreshes. +

+
+
+
+
+ Review changes before syncing a workspace fork
- ))} +
Compare workflow deployments
+
diff --git a/apps/sim/app/(landing)/components/prose-page/index.ts b/apps/sim/app/(landing)/components/prose-page/index.ts index 45977944113..0a33e3ddf70 100644 --- a/apps/sim/app/(landing)/components/prose-page/index.ts +++ b/apps/sim/app/(landing)/components/prose-page/index.ts @@ -1,6 +1,4 @@ -export { ProseHero } from './components/prose-hero' export { ProseLink } from './components/prose-link' -export { ProseShell } from './components/prose-shell' export { PROSE_SPACING, PROSE_TYPE } from './constants' export { ProsePage } from './prose-page' export type { LegalBlock, LegalPageConfig, LegalSection } from './types' diff --git a/apps/sim/app/changelog.xml/route.ts b/apps/sim/app/changelog.xml/route.ts index 9aee139447d..e888bdd7f85 100644 --- a/apps/sim/app/changelog.xml/route.ts +++ b/apps/sim/app/changelog.xml/route.ts @@ -1,21 +1,13 @@ import { NextResponse } from 'next/server' +import { getAllEntryMeta } from '@/lib/changelog' import { SITE_URL } from '@/lib/core/utils/urls' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' export const dynamic = 'force-static' export const revalidate = 3600 -interface Release { - id: number - tag_name: string - name: string - body: string - html_url: string - published_at: string - prerelease: boolean -} - -function escapeXml(str: string) { - return str +function escapeXml(value: string): string { + return value .replace(/&/g, '&') .replace(//g, '>') @@ -23,47 +15,32 @@ function escapeXml(str: string) { .replace(/'/g, ''') } -export async function GET() { - try { - const res = await fetch('https://api.github.com/repos/simstudioai/sim/releases', { - headers: { Accept: 'application/vnd.github+json' }, - next: { revalidate }, - }) - const releases: Release[] = await res.json() - const items = (releases || []) - .filter((r) => !r.prerelease) - .map( - (r) => ` - - ${escapeXml(r.name || r.tag_name)} - ${r.html_url} - ${r.html_url} - ${new Date(r.published_at).toUTCString()} - - - ` - ) - .join('') - - const xml = ` - - - Sim Changelog - ${SITE_URL}/changelog - Latest changes, fixes and updates in Sim. - en-us - ${items} - - ` - - return new NextResponse(xml, { - status: 200, - headers: { - 'Content-Type': 'application/rss+xml; charset=utf-8', - 'Cache-Control': `public, s-maxage=${revalidate}, stale-while-revalidate=${revalidate}`, - }, - }) - } catch { - return new NextResponse('Service Unavailable', { status: 503 }) - } -} +/** RSS is a public XML protocol; its summaries share the website's published content source. */ +export const GET = withRouteHandler(async () => { + const entries = (await getAllEntryMeta()).slice(0, 50) + const items = entries + .map( + (entry) => ` + + ${escapeXml(entry.title)} + ${escapeXml(entry.canonical)} + ${escapeXml(entry.release?.url ?? entry.canonical)} + ${new Date(entry.date).toUTCString()} + ${escapeXml(entry.description)} + ` + ) + .join('') + const xml = ` + + Sim Changelog + ${SITE_URL}/changelog + New features, improvements, and fixes in Sim. + en-us${items} +` + return new NextResponse(xml, { + headers: { + 'Content-Type': 'application/rss+xml; charset=utf-8', + 'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=3600', + }, + }) +}) diff --git a/apps/sim/app/sitemap.ts b/apps/sim/app/sitemap.ts index cc2871c811c..74dd91e119a 100644 --- a/apps/sim/app/sitemap.ts +++ b/apps/sim/app/sitemap.ts @@ -1,5 +1,6 @@ import type { MetadataRoute } from 'next' import { getAllPostMeta as getAllBlogPostMeta } from '@/lib/blog/registry' +import { getAllEntryMeta } from '@/lib/changelog' import type { ContentMeta } from '@/lib/content/schema' import { latestModified } from '@/lib/content/utils' import { SITE_URL } from '@/lib/core/utils/urls' @@ -42,10 +43,11 @@ function buildAuthorPages(posts: ContentMeta[], basePath: string): MetadataRoute */ export default async function sitemap(): Promise { const baseUrl = SITE_URL - const [posts, libraryPosts, customerStories] = await Promise.all([ + const [posts, libraryPosts, customerStories, changelogEntries] = await Promise.all([ getAllBlogPostMeta(), getAllLibraryPostMeta(), getAllCustomerStoryMeta(), + getAllEntryMeta(), ]) const latestPostDateValue = latestModified(posts) @@ -131,6 +133,11 @@ export default async function sitemap(): Promise { }, { url: `${baseUrl}/changelog`, + lastModified: latestModified(changelogEntries), + }, + { + url: `${baseUrl}/changelog/archive`, + lastModified: latestModified(changelogEntries), }, { url: `${baseUrl}/integrations`, @@ -222,6 +229,10 @@ export default async function sitemap(): Promise { const pages: MetadataRoute.Sitemap = [ ...staticPages, + ...changelogEntries.map((entry) => ({ + url: entry.canonical, + lastModified: new Date(entry.updated ?? entry.date), + })), ...blogPages, ...authorPages, ...libraryPages, diff --git a/apps/sim/content/changelog/README.md b/apps/sim/content/changelog/README.md new file mode 100644 index 00000000000..0a5f6d013e5 --- /dev/null +++ b/apps/sim/content/changelog/README.md @@ -0,0 +1,126 @@ +# Publishing a Sim product update + +Create `content/changelog//index.mdx`. The slugs `archive` and `preview` are reserved. The website, archive, individual pages, sitemap, and RSS all read published entries from this directory through the shared content registry. + +The index features the latest update and shows up to six story cards. The archive links to every published update. Both lists read metadata only; the full article and its recordings are loaded on the individual update page. Cards use the local `ogImage` and `ogAlt`, so a reviewed demo poster also becomes the update's cover and share image. The page frame, typography, media radius, and card rhythm use Sim's shared landing styles. + +Write for a team using Sim: what changed, what they can do with it, and where to find it. Group related PRs into one product update. Keep maintenance, refactors, and routine content edits in the technical GitHub release history. + +## What earns an entry + +A public update needs one clear benefit, verified availability, a useful next step, and at least one reviewed feature image or video in the article. The cover alone is not enough. A reader should understand what they can now do and see evidence of that capability. A smaller improvement can join a related edition; it does not need its own announcement because a technical version shipped. + +Review candidates weekly and publish when a story meets that bar. Skip an edition if there is nothing meaningful to announce. Use a separate entry for a substantial launch. Aim for one lead story and a short selection of related improvements or fixes, rather than reproducing every commit. The GitHub release link carries the complete technical history. + +Always make consequential breaking changes, migrations, deprecations, and changes requiring action easy to find, including the affected version, availability, and next step. For a change with no useful product screen, a clearly labeled, accurate explanatory diagram can serve as the image. Do not delay an urgent notice to produce a polished video. + +The initial deployment-comparison, fork-comparison, and Power BI stories use current captures from the running app with sample data. Their production records identify the source changes, capture environment, and demonstration limits. The separate reliability candidate remains a draft until it has feature-specific evidence and media. Do not remove `draft: true` just to populate the page. + +## Production workflow + +Each new update has one folder containing its public `index.mdx` and a non-rendered `production.md` brief. The registry only reads `index.mdx`; the brief and announcement drafts are not website content. Start from the [deployment comparison brief](./compare-workflow-deployments/production.md). Assign one release editor and one feature owner in the PR; both must complete their review before publication. + +| Step | Owner | Output | +| --- | --- | --- | +| Gather evidence | Feature owner | Merged PRs, release version, deployment and permission availability, and a working example | +| Choose the story | Editor | One headline, the situation it helps with, and related improvements worth including | +| Prepare drafts | Editor, assisted by Codex | `index.mdx` with `draft: true`, demo shot list, and social/email copy in `production.md` | +| Produce media | Feature owner | Real product recording, poster, and captions for speech | +| Review | Feature owner and editor | Confirm the actual feature, rollout, and media; verify links and approve consistent copy | +| Deploy | Site maintainer | Merge the reviewed entry with `draft: false`; website, detail page, archive, sitemap, and RSS update together | +| Distribute | Editor | Send the reviewed announcement after the public URL and demo work | + +Codex can read PRs and diffs, group related changes, and produce copy and shot lists from that evidence. Keep commit subjects as research inputs. The editor checks the benefit, feature availability, restrictions, and the demonstration. A GitHub release and a Cloud deployment are separate events. Do not draft a launch from an unverified release title alone. + +For a new edition, `release.versions` can list several technical versions. When there is no single corresponding GitHub release, omit `release.url`; the editorial entry then has its own RSS identity. + +Open `/changelog/preview` while running `next dev` to review drafts with the same cards, typography, and article components as the public site. `/changelog/preview/` shows one draft. These routes return 404 outside development, emit `noindex`, and are excluded from the sitemap and RSS. Public routes continue to exclude drafts even during development. The preview rereads metadata after edits, so there is no need to temporarily publish a draft. + +## Contextual links + +Give readers the next useful step in the sentence that introduces a capability. Link an integration's name to its actual `/integrations/` page and link its setup instructions to the corresponding `docs.sim.ai` guide. Catalog slugs can differ from tool IDs: You.com is `/integrations/you-com`, while its guide is `/integrations/youcom` on the docs domain. + +Use the guide for the exact surface being announced. Live Search connectors have their own `/search/` guides; an ordinary workflow integration page can describe a different connection and permission model. Feature announcements should link to the feature guide, and API changes should link to the current generated operation page. Related Sim product pages and explanatory blog posts are useful when they help a reader use or understand the update. + +Choose a few relevant links instead of repeating every destination in a separate resource list. Keep link text descriptive. The content audit checks integration destinations against the generated catalog and docs destinations against the MDX source and generated OpenAPI pages. Use current canonical URLs, including the operation ID's exact case. Confirm the linked page's instructions and any deep anchor in the deployment preview; a source file alone does not establish rollout or anchor correctness. + +## Artifact delivery + +- Record one complete action and its visible result with sample data in a dedicated demo workspace. Verify the feature and permissions in that environment first. Use the product's normal theme and typography. Keep the cursor and text readable; crop around the relevant controls while preserving enough context to understand the action. +- Export an H.264 MP4 at a readable resolution, usually 1280×720 or 1920×1080. Keep it about 20–45 seconds and optimize it for web playback with `+faststart`. Prefer a focused demonstration with native playback controls over a decorative loop. Check the final crop on a 390px-wide screen. +- Take screenshots and the poster from the reviewed product capture. Choose a frame that shows the announced result, with a legible 16:9 crop for the story card. A separate 1200×630 share image can use the same frame with enough safe area for cropping. Keep the headline and benefit in the page's HTML rather than baking them into the image. Compress local JPEG, WebP, or PNG assets and retain actual screenshot dimensions in MDX. +- Use immutable, versioned media filenames, such as `compare-workflow-deployments-v1.mp4`. Upload recordings and spoken captions under `changelog/` in the existing public Academy asset store: `https://nnjgp7vypgx4myuq.public.blob.vercel-storage.com`. Put the returned public URLs in the entry. The app CSP and content audit explicitly allow this origin for recordings and captions. Small optimized walkthroughs under 1 MiB can live in `public/changelog/` and deploy atomically with their entry. Use the CDN for larger recordings. The component does not upload or proxy videos. +- Serve MP4s as `video/mp4` and spoken captions as `text/vtt`. The existing CDN supports HTTP Range requests, cross-origin playback, and caching. Use a new filename for every revision and verify those response headers on the uploaded asset. Do not overwrite an existing recording URL. +- In the deployment preview, check playback, seeking, captions, poster loading, and mobile readability. A silent recording uses the component's muted default. Spoken recordings need a WebVTT file. +- Generate social and email drafts from the reviewed product story: capability, practical benefit, and one link to the canonical entry. Use the same claims and restrictions everywhere. Keep distribution manual until the format and review process are established. + +AI can prepare storyboards, copy, captions, and clearly labeled conceptual diagrams. Screenshots and feature recordings must come from the real product. Do not generate fictional controls, results, performance numbers, or before-and-after evidence. Label a walkthrough assembled from still captures as a step-by-step walkthrough; do not describe it as a continuous recording. Keep its UI frames unmodified and record the assembly method in the production brief. + +Optional local encoding, once a real recording exists: + +```bash +ffmpeg -i recording.mov -vf "scale=1280:-2" -c:v libx264 -crf 23 -preset medium -pix_fmt yuv420p -c:a aac -movflags +faststart compare-workflow-deployments-v1.mp4 +ffmpeg -ss 25 -i compare-workflow-deployments-v1.mp4 -frames:v 1 -q:v 2 compare-workflow-deployments-poster.jpg +``` + +Choose the poster timestamp after reviewing the exported recording; `25` is an example, not a required frame. Check the compressed result rather than only the original recording. + +## Entry template + +```mdx +--- +slug: your-update +title: 'A concrete product headline' +description: 'Explain the new capability and the situation where it helps a team using Sim.' +date: '2026-10-07T18:00:00Z' +authors: [waleed] +tags: [Workflows] +ogImage: /changelog/your-update-poster.jpg +ogAlt: 'Describe the actual product view' +draft: true +technical: false +release: + versions: [v0.9.14] + url: https://github.com/simstudioai/sim/releases/tag/v0.9.14 +--- + + + +Explain where to find the feature and give one concrete example. + +### Improvements + +- Describe a noticeable improvement. + +### Fixes + +- Describe the situation that now works correctly. +``` + +## Review and media + +1. Check the source PRs and verify availability in the deployed product. A merge or GitHub release does not prove Cloud availability. Mention Enterprise restrictions and the minimum self-hosted version when relevant. +2. Use a dedicated demo workspace. Record one action from start to result in roughly 20–45 seconds, with readable text and sample data. +3. Use compressed MP4s on the approved public CDN, plus a local poster image, or same-origin MP4s under 1 MiB. Do not commit large recordings. Add WebVTT captions on the same origin for spoken recordings; omit `captionsSrc` for silent recordings. A different media provider needs an explicit CSP and content-audit change before use. +4. Use `` for a screenshot, supplying its actual dimensions as literal attributes to reserve space during loading. The MDX compiler strips JavaScript expressions such as `width={1200}`. Describe what it actually shows; do not use an older screenshot as proof of a new control. +5. Use `###` for sections inside an entry: the article owns the H1 and its details section owns an accessible H2. +6. Keep `draft: true` until the text, availability, media, and links are reviewed. Drafts are excluded from the public page, direct entry routes, archive, sitemap, and RSS. Use the development preview to review them without changing publication status. +7. Publish by removing the draft flag or setting it to false, then deploy the site. Keep the slug and original publication date stable. Add `updated` only for a substantive correction. + +Before merging, run `bun run check:library-content --slug changelog/` from the repository root. The shared content audit checks frontmatter, authors, folder slugs, reserved routes, images, MDX syntax, internal links, changelog media attributes, and the existence of local recordings and caption files. Published entries also require body media and descriptive cover alt text; future publication dates, correction dates before publication, and duplicate RSS identities fail the audit. `bun run check:audits` runs it in CI. It cannot determine whether an image proves a feature or confirm Cloud rollout, codec quality, or CDN availability; the feature owner and editor verify those in the brief and preview. + +For a migrated historical release, use its original publication timestamp and GitHub release URL. RSS retains that URL as its identifier to avoid announcing the same release twice. For a new editorial edition covering multiple releases, omit `release.url` and link to the technical releases in the body, so its RSS identity is its unique canonical URL. + +## Maintenance + +- The release editor reviews candidates weekly and checks published links and hosted media monthly. Refresh destinations when docs move and verify deep anchors manually; the audit catches missing canonical source pages during every PR. +- Keep the original slug, publication date, and RSS identity stable. Use `updated` only for a substantive correction. A future date does not schedule publication; leave the entry in draft until the intended deployment. +- If availability changes after publication, update the existing entry with its current status and a clear next step. Preserve its URL rather than deleting it or reverting it to a draft. If a slug must change, add a redirect before moving it. +- Keep historical media versioned. Record the capture date, environment, demonstrated steps, and final asset URLs in the brief. Never overwrite an existing recording. Recheck playback, seeking, captions, and mobile readability after any replacement. +- RSS includes the 50 latest published entries, the homepage shows six, and the archive retains the published history. Those collections load metadata and optimized covers; full articles and recordings load on their detail pages. +- Draft preparation can be assisted by Codex. Publication and distribution remain deliberate editorial actions; there is no automatic commit-to-changelog or auto-send job. diff --git a/apps/sim/content/changelog/compare-workflow-deployments/index.mdx b/apps/sim/content/changelog/compare-workflow-deployments/index.mdx new file mode 100644 index 00000000000..a16b5d877e6 --- /dev/null +++ b/apps/sim/content/changelog/compare-workflow-deployments/index.mdx @@ -0,0 +1,31 @@ +--- +slug: compare-workflow-deployments +title: 'See what changed before you deploy' +description: 'Compare deployed versions or review your draft against the live workflow. See prompt, block, and connection changes before you deploy.' +date: '2026-10-02T06:55:11Z' +authors: [waleed] +tags: [Workflows] +ogImage: /changelog/compare-workflow-deployments-v1.jpg +ogAlt: 'Sim compares two workflow versions, highlighting a prompt edit and an added Slack step' +technical: false +draft: false +release: + versions: [v0.9.10] + url: https://github.com/simstudioai/sim/releases/tag/v0.9.10 +--- + + + +Open a workflow's deployment history and choose **Compare** from a version's menu. Pick two versions to review their changes side by side. When a draft differs from the live workflow, **View changes** opens the same comparison before you redeploy. + +- **Review the details.** Inspect prompt edits, changed settings, and added or removed steps. +- **Follow the connections.** See which paths were added, removed, or rewired. +- **Keep your draft intact.** The comparison is read-only; opening it does not change or deploy the workflow. + +For example, review a new instruction in a support agent's prompt and the [Slack](/integrations/slack) step added to send its digest. Select a changed block to move between its visual highlight and field-level details. + +Deployment comparison is included in **v0.9.10**. Read the [deployment guide](https://docs.sim.ai/workflows/deployment), or compare versions through the [API](https://docs.sim.ai/api-reference/workflows/compareWorkflowVersionsV2). diff --git a/apps/sim/content/changelog/compare-workflow-deployments/production.md b/apps/sim/content/changelog/compare-workflow-deployments/production.md new file mode 100644 index 00000000000..522d8eae2eb --- /dev/null +++ b/apps/sim/content/changelog/compare-workflow-deployments/production.md @@ -0,0 +1,42 @@ +# Deployment comparison: production record + +Status: prepared for publication review. Only `index.mdx` is rendered publicly. + +## Evidence + +- [PR #8455](https://github.com/simstudioai/sim/pull/8455), commit `4436f825cf`, included in [v0.9.10](https://github.com/simstudioai/sim/releases/tag/v0.9.10). +- Checked the implementation and the actual Compare flow in a local self-hosted app on October 7, 2026, based on staging commit `684b228623`. +- Public copy states the released version. This local verification does not establish every Cloud organization's rollout. +- Links: [deployment guide](https://docs.sim.ai/workflows/deployment), [comparison API](https://docs.sim.ai/api-reference/workflows/compareWorkflowVersionsV2), and the Slack integration catalog. + +## Media provenance + +A dedicated local workspace contains a synthetic support-ticket workflow with two deployments. The second changes the agent prompt and adds a Slack step. No model or Slack call was executed for this capture. + +The media comes from the running product, captured through the browser. The video is a silent, edited walkthrough assembled from three unmodified UI captures with reading pauses; it is not a continuous screen recording. No generated controls or results are used. + +1. Open deployment history. +2. Open the version menu and choose Compare. +3. Inspect the changed prompt, added Slack step, and connection. + +Assets: `/changelog/compare-workflow-deployments-v1.mp4` and `/changelog/compare-workflow-deployments-v1.jpg`. The poster is the final comparison view. The short MP4 is served locally with the site; larger future recordings should use the approved media CDN. Keep filenames immutable. + +## Review notes + +The screenshot replaces the older deployment-history reference. The comparison is read-only and shows actual before/after fields. Copy covers both two-version comparison and draft-versus-live review; the media demonstrates the two-version path. The draft remains unchanged after opening and closing Compare. + +The entry keeps the historical release timestamp and RSS identity. Playback, mobile layout, asset responses, and content validation belong in the publication PR's validation record. Assign the release editor and feature reviewer in that PR; verify the public URL before distributing. + +## Announcement drafts + +Social: + +> See what changed before you deploy in Sim. Compare workflow versions, review prompt edits and new steps, and inspect changed connections. Demo and guide: https://www.sim.ai/changelog/compare-workflow-deployments + +Email subject: See what changed before you deploy + +Email body: + +> Open deployment history and choose Compare to review two workflow versions. You can also review a draft against the live workflow before redeploying. See the product walkthrough and setup guide: https://www.sim.ai/changelog/compare-workflow-deployments + +These are drafts, not sent announcements. diff --git a/apps/sim/content/changelog/more-reliable-runs/index.mdx b/apps/sim/content/changelog/more-reliable-runs/index.mdx new file mode 100644 index 00000000000..4db704cb815 --- /dev/null +++ b/apps/sim/content/changelog/more-reliable-runs/index.mdx @@ -0,0 +1,26 @@ +--- +slug: more-reliable-runs +title: 'More reliable runs and file handling' +description: 'Sim now handles large code blocks more efficiently, preserves file origins through exports and extraction, and keeps background workflow confirmations attached to the right run.' +date: '2026-10-05T08:11:57Z' +authors: [waleed] +tags: [Files, Workflows, Improvements] +ogImage: /blog/secret-provenance/cover.jpg +ogAlt: 'Tracking file and secret origins through an agent run in Sim' +technical: false +draft: true +release: + versions: [v0.9.14] + url: https://github.com/simstudioai/sim/releases/tag/v0.9.14 +--- + +### Improvements + +- Sim scans code placeholders and workflow references more efficiently as code blocks grow. See the [Function block guide](https://docs.sim.ai/workflows/blocks/function) for working with code in your agents. +- Files retain their known origins when exported as binary files or extracted from archives, so [secret tracking](/blog/secret-provenance) can follow those transformations. + +### Fixes + +- Background workflow confirmations now preserve the identity of the workflow run they belong to. + +Explore [Files in Sim](/files) and the guide to [using files in workflows](https://docs.sim.ai/files/using-in-workflows). diff --git a/apps/sim/content/changelog/more-reliable-runs/production.md b/apps/sim/content/changelog/more-reliable-runs/production.md new file mode 100644 index 00000000000..98bba106951 --- /dev/null +++ b/apps/sim/content/changelog/more-reliable-runs/production.md @@ -0,0 +1,24 @@ +# Reliability improvements: editorial candidate + +Status: draft; select for a themed edition rather than publishing solely because v0.9.14 shipped. +Feature owner: assign in the publication PR. Editor: assign in the publication PR. + +## Story selection + +The source is [v0.9.14](https://github.com/simstudioai/sim/releases/tag/v0.9.14). The current draft combines code handling, file provenance, and background confirmations. Confirm a clear audience and a practical example before treating that collection as a standalone story. Otherwise, move the relevant notes into a related feature edition and keep the remaining changes in the technical history. + +## Media assessment + +`/blog/secret-provenance/cover.jpg` is the existing secret-provenance article's illustration. It is not a product screenshot and does not demonstrate the new export or archive behavior. It may illustrate the broader subject, but it is insufficient as the sole evidence for this release. Keep the entry in draft. + +If file provenance becomes the lead story, demonstrate an export or archive extraction with safe sample files and the actual resulting origin information in Sim. Capture only information the product exposes. Alternatively, use an explicitly labeled explanatory diagram whose transformations have been verified against the feature implementation. Link to the [secret provenance article](https://www.sim.ai/blog/secret-provenance) and [Files guide](https://docs.sim.ai/files/using-in-workflows). + +Do not invent a speedup percentage or synthetic before-and-after timing for the code-handling improvement. Any performance claim needs a repeatable measurement and stated workload. + +## Completion criteria + +- [ ] Editor selects one meaningful lead story or folds these notes into a related edition. +- [ ] Feature owner verifies the demonstrated behavior and deployed availability. +- [ ] The article has a relevant, reviewed image or video; cover and caption describe it accurately. +- [ ] Capture environment, date, steps, source asset, and final filenames are recorded here. +- [ ] Links, mobile readability, content audit, and distribution copy are reviewed. diff --git a/apps/sim/content/changelog/power-bi-for-agents/index.mdx b/apps/sim/content/changelog/power-bi-for-agents/index.mdx new file mode 100644 index 00000000000..996b5b35d2e --- /dev/null +++ b/apps/sim/content/changelog/power-bi-for-agents/index.mdx @@ -0,0 +1,30 @@ +--- +slug: power-bi-for-agents +title: 'Bring Power BI data into your agents' +description: 'Query semantic models, inspect reports, and request refreshes from a Power BI block in Sim.' +date: '2026-10-03T04:32:55Z' +authors: [waleed] +tags: [Integrations] +ogImage: /changelog/power-bi-query-v1.jpg +ogAlt: 'Power BI block configured with a sample sales query in the Sim workflow builder' +technical: false +draft: false +release: + versions: [v0.9.12] +--- + +Add [Power BI](/integrations/power-bi) to a workflow to bring business data into an agent's next step. Query a semantic model with DAX, Power BI's query language, then pass the returned rows to an agent for a briefing or follow-up. + +The integration includes eight actions for finding workspaces, reading reports and semantic models, running queries, requesting refreshes, and checking refresh history. A refresh request starts the work; use the history action to check its progress. + +For example, summarize weekly revenue by region and use those results to prepare a sales update. The sample below shows query configuration; connect your Power BI account and choose a model before running it. + + + +Included in [v0.9.12](https://github.com/simstudioai/sim/releases/tag/v0.9.12). Connect an organizational Microsoft account through the dedicated Power BI connection. Queries require model Read and Build permissions and your tenant's Execute Queries setting. Follow the [Power BI setup guide](https://docs.sim.ai/integrations/powerbi) for connection requirements and supported actions. diff --git a/apps/sim/content/changelog/power-bi-for-agents/production.md b/apps/sim/content/changelog/power-bi-for-agents/production.md new file mode 100644 index 00000000000..cb37224b2a5 --- /dev/null +++ b/apps/sim/content/changelog/power-bi-for-agents/production.md @@ -0,0 +1,35 @@ +# Power BI: production record + +Status: prepared for publication review. Only `index.mdx` is rendered publicly. + +## Evidence and availability + +[PR #8538](https://github.com/simstudioai/sim/pull/8538), included in [v0.9.12](https://github.com/simstudioai/sim/releases/tag/v0.9.12). Reviewed the block, action implementations, and [setup guide](https://docs.sim.ai/integrations/powerbi). + +Eight actions cover workspaces, report metadata, semantic-model metadata, DAX queries, refresh requests, and refresh history. An accepted refresh request is not a completed refresh. The public copy preserves this distinction and the query permission requirements. + +The entry links to `/integrations/power-bi` and the matching docs guide at `/integrations/powerbi`. It has its own RSS identity because the fork-comparison story already carries the historical v0.9.12 release identity. + +## Media provenance + +Captured October 7, 2026, from the actual local self-hosted app based on staging commit `684b228623`, using a dedicated sample workspace. Asset: `/changelog/power-bi-query-v1.jpg`, 1440×900. + +The screenshot shows the Power BI block and a synthetic DAX query using sample sales table and column names. The account, workspace, and model selectors are intentionally unconnected. No Microsoft account was connected and no query or refresh was executed. The article explicitly describes a configuration example, not a successful provider call. Do not add a results screen without a real authorized connection and a verified run. + +The sample demonstrates where the query is configured. Actual table and column names must match the reader's model. The setup guide describes organizational accounts, delegated connection requirements, permission limits, and unsupported actions. + +## Review and distribution + +Assign the release editor and feature reviewer in the publication PR. Verify the local asset, mobile layout, canonical links, and public URL before distribution. Local availability does not independently verify every Cloud rollout. + +Social draft: + +> Bring Power BI data into your agents in Sim. Query semantic models, inspect reports, and request refreshes from a workflow block. Setup requirements and example: https://www.sim.ai/changelog/power-bi-for-agents + +Email subject: Connect your agents to Power BI + +Email body: + +> Sim's Power BI integration can query semantic models, inspect reports, and request refreshes. Use the returned rows in a briefing or follow-up. See the configuration example and Microsoft connection requirements: https://www.sim.ai/changelog/power-bi-for-agents + +These are drafts, not sent announcements. diff --git a/apps/sim/content/changelog/review-fork-changes/index.mdx b/apps/sim/content/changelog/review-fork-changes/index.mdx new file mode 100644 index 00000000000..b0c2aafba81 --- /dev/null +++ b/apps/sim/content/changelog/review-fork-changes/index.mdx @@ -0,0 +1,29 @@ +--- +slug: review-fork-changes +title: 'Review fork changes before syncing' +description: 'See how a source workflow has changed since its last successful sync before updating a workspace fork.' +date: '2026-10-03T04:32:55Z' +authors: [waleed] +tags: [Workspaces, Enterprise] +ogImage: /changelog/review-fork-changes-v1.jpg +ogAlt: 'Last Sync to Now comparison showing a changed renewal-reminder setting in Sim' +technical: false +draft: false +release: + versions: [v0.9.12] + url: https://github.com/simstudioai/sim/releases/tag/v0.9.12 +--- + + + +Open **Workspace forks**, choose **Edit mappings** for the parent workspace, and select **Push** or **Pull**. Then choose **Compare** from a deployed workflow's menu. **Last Sync → Now** shows changes to the source workflow since the version last brought across. + +Review prompt edits, configuration changes, and added or removed steps before syncing. Each fork and sync direction keeps its own history, so a comparison in one child workspace does not reuse another child's baseline. + +The baseline advances only after the destination deployment becomes active. If a workflow has never been synced, or its earlier snapshot is unavailable, Sim explains why there is no comparison instead of guessing. + +Included in **v0.9.12**. Workspace forks require workspace admin access and are available on Sim Cloud Enterprise when enabled for the organization, or on self-hosted deployments with Forks enabled. The [workspace forks guide](https://docs.sim.ai/platform/enterprise/forks) covers setup and sync behavior. diff --git a/apps/sim/content/changelog/review-fork-changes/production.md b/apps/sim/content/changelog/review-fork-changes/production.md new file mode 100644 index 00000000000..72eafce3bd8 --- /dev/null +++ b/apps/sim/content/changelog/review-fork-changes/production.md @@ -0,0 +1,41 @@ +# Fork comparison: production record + +Status: prepared for publication review. Only `index.mdx` is rendered publicly. + +## Evidence and availability + +[PR #8586](https://github.com/simstudioai/sim/pull/8586), commit `405cc6a835`, included in [v0.9.12](https://github.com/simstudioai/sim/releases/tag/v0.9.12). Checked the source and the actual fork comparison in the local self-hosted app based on staging commit `684b228623` on October 7, 2026. + +A dedicated sample workspace was forked through the real application operation. A real sync and its deployment outbox completed before creating the next source deployment. The subsequent preview reported an available baseline between source versions 1 and 2. This avoids inventing a Last Sync snapshot or displaying a first-sync screen as the comparison feature. + +The public copy preserves workspace admin access, Cloud Enterprise enablement, and self-hosted Forks enablement requirements from the [workspace forks guide](https://docs.sim.ai/platform/enterprise/forks). Local verification does not establish each Cloud organization's rollout. + +## Media provenance + +The running product shows a sample renewal-reminder workflow changing from seven to fourteen days and adding an account-summary setting. No customer data or external message is used. + +1. Open the fork's parent mapping settings and select Pull. +2. Choose Compare from the deployed workflow's menu. +3. Review Last Sync → Now and the actual changed code. + +Assets: `/changelog/review-fork-changes-v1.jpg` and `/changelog/review-fork-changes-v1.mp4`. The poster shows the final comparison. The silent video is an edited walkthrough assembled from three unmodified UI captures with reading pauses, not a continuous screen recording. It uses the actual product UI; no controls or results are generated. + +The previous mapping-only reference image has been removed. The new screenshot proves the announced comparison. The capture stops before performing another sync. + +## Review and edge cases + +The baseline records a successful destination activation, is specific to the source/destination relationship, and can be unavailable before the first sync or when an older snapshot has been removed. The article explains those limits. Comparison does not claim to preview destination edits or resource mappings. + +Assign the release editor and feature reviewer in the publication PR. Validate playback, asset responses, responsive layout, links, and the public URL before distribution. Keep the historical timestamp and v0.9.12 RSS identity stable. + +Social draft: + +> Review changes before syncing a workspace fork in Sim. Last Sync → Now shows what changed in the source workflow. Available with Workspace Forks; setup and demo: https://www.sim.ai/changelog/review-fork-changes + +Email subject: Review fork changes before syncing + +Email body: + +> Open your fork's mapping settings and choose Compare from a deployed workflow's menu. Inspect source changes since the last successful sync before updating the fork. Availability and demo: https://www.sim.ai/changelog/review-fork-changes + +These are drafts, not sent announcements. diff --git a/apps/sim/lib/changelog/constants.ts b/apps/sim/lib/changelog/constants.ts new file mode 100644 index 00000000000..7312c8912aa --- /dev/null +++ b/apps/sim/lib/changelog/constants.ts @@ -0,0 +1,10 @@ +import type { ContentSection } from '@/lib/content/seo' + +export const CHANGELOG_SECTION = { + name: 'Changelog', + basePath: '/changelog', + description: + 'New ways to build, deploy, and manage AI agents in Sim, plus improvements and fixes.', +} satisfies ContentSection + +export const LATEST_ENTRY_LIMIT = 6 diff --git a/apps/sim/lib/changelog/index.ts b/apps/sim/lib/changelog/index.ts new file mode 100644 index 00000000000..c0c9943b5d8 --- /dev/null +++ b/apps/sim/lib/changelog/index.ts @@ -0,0 +1,2 @@ +export { CHANGELOG_SECTION, LATEST_ENTRY_LIMIT } from './constants' +export { getAllEntryMeta, getAllEntryPreviews, getEntryBySlug, getEntryPreview } from './registry' diff --git a/apps/sim/lib/changelog/mdx.tsx b/apps/sim/lib/changelog/mdx.tsx new file mode 100644 index 00000000000..770642d458d --- /dev/null +++ b/apps/sim/lib/changelog/mdx.tsx @@ -0,0 +1,47 @@ +import type { ComponentPropsWithoutRef } from 'react' +import { cn } from '@sim/emcn' +import type { MDXRemoteProps } from 'next-mdx-remote/rsc' +import { ChangelogImage, ChangelogVideo } from '@/app/(landing)/changelog/components' +import { HOME_TYPE } from '@/app/(landing)/components/landing-layout' +import { PROSE_TYPE } from '@/app/(landing)/components/prose-page/constants' + +export const changelogComponents = { + ChangelogVideo, + ChangelogImage, + h3: ({ className, ...props }: ComponentPropsWithoutRef<'h3'>) => ( +

+ ), + h4: ({ className, ...props }: ComponentPropsWithoutRef<'h4'>) => ( +

+ ), + p: ({ className, ...props }: ComponentPropsWithoutRef<'p'>) => ( +

+ ), + ul: ({ className, ...props }: ComponentPropsWithoutRef<'ul'>) => ( +

-

- {entry.description} -

-

- By {entry.authors.map((author) => author.name).join(', ')} -

-
+

In this update

{entries.length > 0 ? ( -
    - {entries.map((entry, index) => ( -
  1. - +
      + {entries.map((entry) => ( +
    1. +
    2. ))}
    diff --git a/apps/sim/app/(landing)/changelog/components/changelog-list/components/changelog-entry/changelog-entry.tsx b/apps/sim/app/(landing)/changelog/components/changelog-list/components/changelog-entry/changelog-entry.tsx index aced42260cd..78b9a200ef7 100644 --- a/apps/sim/app/(landing)/changelog/components/changelog-list/components/changelog-entry/changelog-entry.tsx +++ b/apps/sim/app/(landing)/changelog/components/changelog-list/components/changelog-entry/changelog-entry.tsx @@ -1,24 +1,18 @@ import { cn } from '@sim/emcn' import { ArrowRight } from '@sim/emcn/icons' -import Image from 'next/image' import Link from 'next/link' import { CHANGELOG_SECTION } from '@/lib/changelog/constants' import type { ContentMeta } from '@/lib/content/schema' import { formatPostDate } from '@/app/(landing)/components/content-utils' -import { HOME_TYPE, LANDING_STAGE_RADIUS } from '@/app/(landing)/components/landing-layout' +import { HOME_TYPE } from '@/app/(landing)/components/landing-layout' interface ChangelogEntryProps { entry: ContentMeta - priority: boolean basePath?: string } -const IMAGE_SIZES = - '(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)' - export function ChangelogEntry({ entry, - priority, basePath = CHANGELOG_SECTION.basePath, }: ChangelogEntryProps) { return ( @@ -26,48 +20,22 @@ export function ChangelogEntry({ -
    -
    - - {entry.draft ? Draft : null} -
    -

    - {entry.title} -

    -

    - {entry.description} -

    - - Read update - +
    + + {entry.draft ? Draft : null}
    -
    - {entry.ogAlt -
    + {entry.title} + +