improvement: changelog

This commit is contained in:
Emir Karabeg
2026-03-06 12:52:59 -08:00
parent be4ea4be05
commit 49cd0beebc
21 changed files with 2889 additions and 688 deletions

View File

@@ -21,12 +21,12 @@ body {
.dark {
--color-fd-primary: #33c482;
--color-fd-background: #1C1C1C;
--color-fd-background: #1c1c1c;
--color-fd-card: #1b1b1b;
--color-fd-muted: #1b1b1b;
--color-fd-secondary: #1b1b1b;
--color-fd-popover: #1b1b1b;
--color-fd-border: #2A2A2A;
--color-fd-border: #2a2a2a;
--color-fd-accent: rgba(255, 255, 255, 0.08);
}
@@ -492,7 +492,7 @@ pre code {
.dark :not(pre) > code {
background-color: #1b1b1b;
color: rgb(248 113 113);
border: 1px solid #2A2A2A;
border: 1px solid #2a2a2a;
}
/* Code block container improvements */

View File

@@ -1,8 +1,8 @@
'use client'
import { useTheme } from 'next-themes'
import { useEffect, useState } from 'react'
import Image from 'next/image'
import { useTheme } from 'next-themes'
/**
* Static block pattern SVG rects matching the hero page's color palette.
@@ -60,11 +60,27 @@ export function DocsBackground() {
<rect opacity='1' width='16.8626' height='16.8626' rx={RX} fill='#2ABBF8' />
<rect opacity='0.6' x='34.2403' width='34.2403' height='33.7252' rx={RX} fill='#2ABBF8' />
<rect opacity='1' x='34.2403' width='16.8626' height='16.8626' rx={RX} fill='#2ABBF8' />
<rect opacity='1' x='51.6188' y='16.8626' width='16.8626' height='16.8626' rx={RX} fill='#2ABBF8' />
<rect
opacity='1'
x='51.6188'
y='16.8626'
width='16.8626'
height='16.8626'
rx={RX}
fill='#2ABBF8'
/>
<rect opacity='1' x='68.4812' width='54.6502' height='16.8626' rx={RX} fill='#00F701' />
<rect opacity='0.6' x='106.268' width='34.2403' height='33.7252' rx={RX} fill='#00F701' />
<rect opacity='0.6' x='106.268' width='51.103' height='16.8626' rx={RX} fill='#00F701' />
<rect opacity='1' x='123.6484' y='16.8626' width='16.8626' height='16.8626' rx={RX} fill='#00F701' />
<rect
opacity='1'
x='123.6484'
y='16.8626'
width='16.8626'
height='16.8626'
rx={RX}
fill='#00F701'
/>
<rect opacity='0.6' x='157.371' width='34.2403' height='16.8626' rx={RX} fill='#FFCC02' />
<rect opacity='1' x='157.371' width='16.8626' height='16.8626' rx={RX} fill='#FFCC02' />
<rect opacity='0.6' x='208.993' width='68.4805' height='16.8626' rx={RX} fill='#FA4EDF' />
@@ -72,7 +88,15 @@ export function DocsBackground() {
<rect opacity='0.6' x='243.233' width='34.2403' height='33.7252' rx={RX} fill='#FA4EDF' />
<rect opacity='1' x='243.233' width='16.8626' height='16.8626' rx={RX} fill='#FA4EDF' />
<rect opacity='0.6' x='260.096' width='34.04' height='16.8626' rx={RX} fill='#FA4EDF' />
<rect opacity='1' x='260.611' y='16.8626' width='16.8626' height='16.8626' rx={RX} fill='#FA4EDF' />
<rect
opacity='1'
x='260.611'
y='16.8626'
width='16.8626'
height='16.8626'
rx={RX}
fill='#FA4EDF'
/>
</svg>
</div>
@@ -90,11 +114,27 @@ export function DocsBackground() {
<rect opacity='1' width='16.8626' height='16.8626' rx={RX} fill='#00F701' />
<rect opacity='0.6' x='34.2403' width='34.2403' height='33.7252' rx={RX} fill='#00F701' />
<rect opacity='1' x='34.2403' width='16.8626' height='16.8626' rx={RX} fill='#00F701' />
<rect opacity='1' x='51.6188' y='16.8626' width='16.8626' height='16.8626' rx={RX} fill='#00F701' />
<rect
opacity='1'
x='51.6188'
y='16.8626'
width='16.8626'
height='16.8626'
rx={RX}
fill='#00F701'
/>
<rect opacity='1' x='68.4812' width='54.6502' height='16.8626' rx={RX} fill='#FFCC02' />
<rect opacity='0.6' x='106.268' width='34.2403' height='33.7252' rx={RX} fill='#FFCC02' />
<rect opacity='0.6' x='106.268' width='51.103' height='16.8626' rx={RX} fill='#FFCC02' />
<rect opacity='1' x='123.6484' y='16.8626' width='16.8626' height='16.8626' rx={RX} fill='#FFCC02' />
<rect
opacity='1'
x='123.6484'
y='16.8626'
width='16.8626'
height='16.8626'
rx={RX}
fill='#FFCC02'
/>
<rect opacity='0.6' x='157.371' width='34.2403' height='16.8626' rx={RX} fill='#FA4EDF' />
<rect opacity='1' x='157.371' width='16.8626' height='16.8626' rx={RX} fill='#FA4EDF' />
<rect opacity='0.6' x='208.993' width='68.4805' height='16.8626' rx={RX} fill='#2ABBF8' />
@@ -102,12 +142,20 @@ export function DocsBackground() {
<rect opacity='0.6' x='243.233' width='34.2403' height='33.7252' rx={RX} fill='#2ABBF8' />
<rect opacity='1' x='243.233' width='16.8626' height='16.8626' rx={RX} fill='#2ABBF8' />
<rect opacity='0.6' x='260.096' width='34.04' height='16.8626' rx={RX} fill='#2ABBF8' />
<rect opacity='1' x='260.611' y='16.8626' width='16.8626' height='16.8626' rx={RX} fill='#2ABBF8' />
<rect
opacity='1'
x='260.611'
y='16.8626'
width='16.8626'
height='16.8626'
rx={RX}
fill='#2ABBF8'
/>
</svg>
</div>
{/* Vertical block strip — left edge */}
<div className='absolute top-[50%] left-0 w-[calc(16px_+_1.25vw)] max-w-[34px] -translate-y-1/2 opacity-60'>
<div className='-translate-y-1/2 absolute top-[50%] left-0 w-[calc(16px_+_1.25vw)] max-w-[34px] opacity-60'>
<svg
width={34}
height={226}
@@ -116,20 +164,87 @@ export function DocsBackground() {
xmlns='http://www.w3.org/2000/svg'
className='h-auto w-full'
>
<rect opacity='0.6' width='34.240' height='33.725' rx={RX} fill='#FA4EDF' transform='matrix(0 1 1 0 0 0)' />
<rect opacity='0.6' width='16.8626' height='68.480' rx={RX} fill='#FA4EDF' transform='matrix(-1 0 0 1 33.727 0)' />
<rect opacity='1' width='16.8626' height='16.8626' rx={RX} fill='#FA4EDF' transform='matrix(-1 0 0 1 33.727 17.378)' />
<rect opacity='0.6' width='16.8626' height='33.986' rx={RX} fill='#FA4EDF' transform='matrix(0 1 1 0 0 51.616)' />
<rect opacity='0.6' width='16.8626' height='140.507' rx={RX} fill='#00F701' transform='matrix(-1 0 0 1 33.986 85.335)' />
<rect opacity='0.4' x='17.119' y='136.962' width='34.240' height='16.8626' rx={RX} fill='#FFCC02' transform='rotate(-90 17.119 136.962)' />
<rect opacity='1' x='17.119' y='136.962' width='16.8626' height='16.8626' rx={RX} fill='#FFCC02' transform='rotate(-90 17.119 136.962)' />
<rect opacity='0.5' width='34.240' height='33.725' rx={RX} fill='#00F701' transform='matrix(0 1 1 0 0.257 153.825)' />
<rect opacity='1' width='16.8626' height='16.8626' rx={RX} fill='#00F701' transform='matrix(0 1 1 0 0.257 153.825)' />
<rect
opacity='0.6'
width='34.240'
height='33.725'
rx={RX}
fill='#FA4EDF'
transform='matrix(0 1 1 0 0 0)'
/>
<rect
opacity='0.6'
width='16.8626'
height='68.480'
rx={RX}
fill='#FA4EDF'
transform='matrix(-1 0 0 1 33.727 0)'
/>
<rect
opacity='1'
width='16.8626'
height='16.8626'
rx={RX}
fill='#FA4EDF'
transform='matrix(-1 0 0 1 33.727 17.378)'
/>
<rect
opacity='0.6'
width='16.8626'
height='33.986'
rx={RX}
fill='#FA4EDF'
transform='matrix(0 1 1 0 0 51.616)'
/>
<rect
opacity='0.6'
width='16.8626'
height='140.507'
rx={RX}
fill='#00F701'
transform='matrix(-1 0 0 1 33.986 85.335)'
/>
<rect
opacity='0.4'
x='17.119'
y='136.962'
width='34.240'
height='16.8626'
rx={RX}
fill='#FFCC02'
transform='rotate(-90 17.119 136.962)'
/>
<rect
opacity='1'
x='17.119'
y='136.962'
width='16.8626'
height='16.8626'
rx={RX}
fill='#FFCC02'
transform='rotate(-90 17.119 136.962)'
/>
<rect
opacity='0.5'
width='34.240'
height='33.725'
rx={RX}
fill='#00F701'
transform='matrix(0 1 1 0 0.257 153.825)'
/>
<rect
opacity='1'
width='16.8626'
height='16.8626'
rx={RX}
fill='#00F701'
transform='matrix(0 1 1 0 0.257 153.825)'
/>
</svg>
</div>
{/* Vertical block strip — right edge */}
<div className='absolute top-[50%] right-0 w-[calc(16px_+_1.25vw)] max-w-[34px] -translate-y-1/2 opacity-60'>
<div className='-translate-y-1/2 absolute top-[50%] right-0 w-[calc(16px_+_1.25vw)] max-w-[34px] opacity-60'>
<svg
width={34}
height={205}
@@ -138,15 +253,82 @@ export function DocsBackground() {
xmlns='http://www.w3.org/2000/svg'
className='h-auto w-full'
>
<rect opacity='0.6' width='16.8626' height='33.726' rx={RX} fill='#FA4EDF' transform='matrix(0 1 1 0 0 0)' />
<rect opacity='0.6' width='34.241' height='16.8626' rx={RX} fill='#FA4EDF' transform='matrix(0 1 1 0 16.891 0)' />
<rect opacity='0.6' width='16.8626' height='68.482' rx={RX} fill='#FA4EDF' transform='matrix(-1 0 0 1 33.739 16.888)' />
<rect opacity='0.6' width='16.8626' height='33.726' rx={RX} fill='#FA4EDF' transform='matrix(0 1 1 0 0 33.776)' />
<rect opacity='1' width='16.8626' height='16.8626' rx={RX} fill='#FA4EDF' transform='matrix(-1 0 0 1 33.739 34.272)' />
<rect opacity='0.6' width='16.8626' height='33.726' rx={RX} fill='#FA4EDF' transform='matrix(0 1 1 0 0.012 68.510)' />
<rect opacity='0.6' width='16.8626' height='102.384' rx={RX} fill='#2ABBF8' transform='matrix(-1 0 0 1 33.787 102.384)' />
<rect opacity='0.4' x='17.131' y='153.859' width='34.241' height='16.8626' rx={RX} fill='#00F701' transform='rotate(-90 17.131 153.859)' />
<rect opacity='1' x='17.131' y='153.859' width='16.8626' height='16.8626' rx={RX} fill='#00F701' transform='rotate(-90 17.131 153.859)' />
<rect
opacity='0.6'
width='16.8626'
height='33.726'
rx={RX}
fill='#FA4EDF'
transform='matrix(0 1 1 0 0 0)'
/>
<rect
opacity='0.6'
width='34.241'
height='16.8626'
rx={RX}
fill='#FA4EDF'
transform='matrix(0 1 1 0 16.891 0)'
/>
<rect
opacity='0.6'
width='16.8626'
height='68.482'
rx={RX}
fill='#FA4EDF'
transform='matrix(-1 0 0 1 33.739 16.888)'
/>
<rect
opacity='0.6'
width='16.8626'
height='33.726'
rx={RX}
fill='#FA4EDF'
transform='matrix(0 1 1 0 0 33.776)'
/>
<rect
opacity='1'
width='16.8626'
height='16.8626'
rx={RX}
fill='#FA4EDF'
transform='matrix(-1 0 0 1 33.739 34.272)'
/>
<rect
opacity='0.6'
width='16.8626'
height='33.726'
rx={RX}
fill='#FA4EDF'
transform='matrix(0 1 1 0 0.012 68.510)'
/>
<rect
opacity='0.6'
width='16.8626'
height='102.384'
rx={RX}
fill='#2ABBF8'
transform='matrix(-1 0 0 1 33.787 102.384)'
/>
<rect
opacity='0.4'
x='17.131'
y='153.859'
width='34.241'
height='16.8626'
rx={RX}
fill='#00F701'
transform='rotate(-90 17.131 153.859)'
/>
<rect
opacity='1'
x='17.131'
y='153.859'
width='16.8626'
height='16.8626'
rx={RX}
fill='#00F701'
transform='rotate(-90 17.131 153.859)'
/>
</svg>
</div>
</div>

View File

@@ -528,7 +528,10 @@ interface AnimatedBlockProps {
}
/** Two-row horizontal strip at the top-right of the hero. */
export function BlocksTopRightAnimated({ animState = 'entering', reverseExit }: AnimatedBlockProps) {
export function BlocksTopRightAnimated({
animState = 'entering',
reverseExit,
}: AnimatedBlockProps) {
return (
<AnimatedBlocksSvg
width={295}
@@ -570,7 +573,10 @@ export function BlocksLeftAnimated({ animState = 'entering', reverseExit }: Anim
}
/** Two-column vertical strip on the right edge of the screenshot. */
export function BlocksRightSideAnimated({ animState = 'entering', reverseExit }: AnimatedBlockProps) {
export function BlocksRightSideAnimated({
animState = 'entering',
reverseExit,
}: AnimatedBlockProps) {
return (
<AnimatedBlocksSvg
width={34}

View File

@@ -63,7 +63,9 @@ export default function StatusIndicator() {
aria-label={`System status: ${message}`}
>
<StatusDotIcon status={status} className='h-[6px] w-[6px]' aria-hidden='true' />
<span className='font-[family-name:var(--font-martian-mono)] font-medium uppercase tracking-[-0.24px]'>{message}</span>
<span className='font-[family-name:var(--font-martian-mono)] font-medium uppercase tracking-[-0.24px]'>
{message}
</span>
</Link>
)
}

View File

@@ -23,7 +23,7 @@ export default function Footer({ fullWidth = false }: FooterProps) {
{/* Dot grid separator */}
<div
aria-hidden='true'
className='border-y border-[#2A2A2A] bg-[#1C1C1C] p-[6px]'
className='border-[#2A2A2A] border-y bg-[#1C1C1C] p-[6px]'
style={{
display: 'grid',
gridTemplateColumns: 'repeat(120, 1fr)',
@@ -48,18 +48,45 @@ export default function Footer({ fullWidth = false }: FooterProps) {
{/* Logo and status — left aligned */}
<div className='flex flex-col gap-[24px]'>
<Link href='/' aria-label='Sim home'>
<svg width='71' height='22' viewBox='0 0 71 22' fill='none' xmlns='http://www.w3.org/2000/svg'>
<svg
width='71'
height='22'
viewBox='0 0 71 22'
fill='none'
xmlns='http://www.w3.org/2000/svg'
>
<g transform='scale(0.07483)'>
<path fillRule='evenodd' clipRule='evenodd' d='M142.793 124.175C142.793 128.925 140.913 133.487 137.577 136.846L137.099 137.327C133.765 140.696 129.236 142.579 124.519 142.579H17.8063C7.97854 142.579 0 150.605 0 160.503V275.91C0 285.808 7.97854 293.834 17.8063 293.834H132.383C142.211 293.834 150.179 285.808 150.179 275.91V167.858C150.179 163.453 151.914 159.226 155.009 156.109C158.095 153.001 162.292 151.253 166.666 151.253H275.166C284.994 151.253 292.962 143.229 292.962 133.33V17.9231C292.962 8.02512 284.994 0 275.166 0H160.588C150.761 0 142.793 8.02512 142.793 17.9231V124.175ZM177.564 24.5671H258.181C263.925 24.5671 268.57 29.2545 268.57 35.0301V116.224C268.57 121.998 263.925 126.687 258.181 126.687H177.564C171.83 126.687 167.175 121.998 167.175 116.224V35.0301C167.175 29.2545 171.83 24.5671 177.564 24.5671Z' fill='white'/>
<path d='M275.293 171.578H190.106C179.779 171.578 171.406 180.01 171.406 190.412V275.162C171.406 285.564 179.779 293.996 190.106 293.996H275.293C285.621 293.996 293.994 285.564 293.994 275.162V190.412C293.994 180.01 285.621 171.578 275.293 171.578Z' fill='white'/>
<path d='M275.293 171.18H190.106C179.779 171.18 171.406 179.612 171.406 190.014V274.763C171.406 285.165 179.779 293.596 190.106 293.596H275.293C285.621 293.596 293.994 285.165 293.994 274.763V190.014C293.994 179.612 285.621 171.18 275.293 171.18Z' fill='white' fillOpacity='0.2'/>
<path
fillRule='evenodd'
clipRule='evenodd'
d='M142.793 124.175C142.793 128.925 140.913 133.487 137.577 136.846L137.099 137.327C133.765 140.696 129.236 142.579 124.519 142.579H17.8063C7.97854 142.579 0 150.605 0 160.503V275.91C0 285.808 7.97854 293.834 17.8063 293.834H132.383C142.211 293.834 150.179 285.808 150.179 275.91V167.858C150.179 163.453 151.914 159.226 155.009 156.109C158.095 153.001 162.292 151.253 166.666 151.253H275.166C284.994 151.253 292.962 143.229 292.962 133.33V17.9231C292.962 8.02512 284.994 0 275.166 0H160.588C150.761 0 142.793 8.02512 142.793 17.9231V124.175ZM177.564 24.5671H258.181C263.925 24.5671 268.57 29.2545 268.57 35.0301V116.224C268.57 121.998 263.925 126.687 258.181 126.687H177.564C171.83 126.687 167.175 121.998 167.175 116.224V35.0301C167.175 29.2545 171.83 24.5671 177.564 24.5671Z'
fill='white'
/>
<path
d='M275.293 171.578H190.106C179.779 171.578 171.406 180.01 171.406 190.412V275.162C171.406 285.564 179.779 293.996 190.106 293.996H275.293C285.621 293.996 293.994 285.564 293.994 275.162V190.412C293.994 180.01 285.621 171.578 275.293 171.578Z'
fill='white'
/>
<path
d='M275.293 171.18H190.106C179.779 171.18 171.406 179.612 171.406 190.014V274.763C171.406 285.165 179.779 293.596 190.106 293.596H275.293C285.621 293.596 293.994 285.165 293.994 274.763V190.014C293.994 179.612 285.621 171.18 275.293 171.18Z'
fill='white'
fillOpacity='0.2'
/>
</g>
<path d='M31.5718 15.845H34.1583C34.1583 16.5591 34.4169 17.1285 34.9342 17.5531C35.4515 17.9584 36.1508 18.1611 37.0321 18.1611C37.9901 18.1611 38.7277 17.9777 39.245 17.611C39.7623 17.225 40.021 16.7135 40.021 16.0766C40.021 15.6134 39.8773 15.2274 39.5899 14.9186C39.3217 14.6098 38.8235 14.3589 38.0955 14.1659L35.6239 13.5869C34.3786 13.2781 33.4494 12.8052 32.8363 12.1683C32.2423 11.5314 31.9454 10.6918 31.9454 9.64957C31.9454 8.78105 32.1657 8.02833 32.6064 7.39142C33.0662 6.7545 33.6889 6.26234 34.4744 5.91494C35.2791 5.56753 36.1987 5.39382 37.2333 5.39382C38.2679 5.39382 39.1588 5.57718 39.906 5.94389C40.6724 6.31059 41.2663 6.82206 41.6878 7.47827C42.1285 8.13449 42.3584 8.91615 42.3776 9.82327H39.7911C39.7719 9.08986 39.5324 8.52049 39.0726 8.11518C38.6128 7.70988 37.9709 7.50722 37.1471 7.50722C36.3041 7.50722 35.6527 7.69058 35.1929 8.05728C34.733 8.42399 34.5031 8.9258 34.5031 9.56272C34.5031 10.5084 35.1929 11.155 36.5723 11.5024L39.0439 12.1104C40.2317 12.3806 41.1226 12.8245 41.7166 13.4421C42.3105 14.0404 42.6075 14.8607 42.6075 15.9029C42.6075 16.7907 42.368 17.5724 41.889 18.2479C41.41 18.9041 40.749 19.4156 39.906 19.7823C39.0822 20.1297 38.1051 20.3034 36.9747 20.3034C35.327 20.3034 34.0146 19.8981 33.0375 19.0875C32.0603 18.2769 31.5718 17.196 31.5718 15.845Z' fill='white'/>
<path d='M44.5096 19.956V5.79913C45.5868 6.19296 46.0617 6.19296 47.211 5.79913V19.956H44.5096ZM45.8316 4.86332C45.3526 4.86332 44.9311 4.68962 44.5671 4.34221C44.2222 3.9755 44.0498 3.55089 44.0498 3.06838C44.0498 2.56657 44.2222 2.14196 44.5671 1.79455C44.9311 1.44714 45.3526 1.27344 45.8316 1.27344C46.3297 1.27344 46.7512 1.44714 47.0961 1.79455C47.441 2.14196 47.6134 2.56657 47.6134 3.06838C47.6134 3.55089 47.441 3.9755 47.0961 4.34221C46.7512 4.68962 46.3297 4.86332 45.8316 4.86332Z' fill='white'/>
<path d='M51.976 19.956H49.2746V5.79913H51.6887V8.18778C51.976 7.39647 52.5317 6.72555 53.298 6.20444C54.0835 5.66403 55.0319 5.39382 56.1432 5.39382C57.3885 5.39382 58.4231 5.73158 59.247 6.4071C60.0708 7.08261 60.6073 7.98008 60.8563 9.09951H60.3678C60.5594 7.98008 61.0862 7.08261 61.9484 6.4071C62.8106 5.73158 63.8739 5.39382 65.1384 5.39382C66.7478 5.39382 68.0123 5.86668 68.9319 6.8124C69.8516 7.75813 70.3114 9.05126 70.3114 10.6918V19.956H67.6674V11.3577C67.6674 10.2382 67.38 9.37936 66.8053 8.78105C66.2496 8.16344 65.4928 7.85463 64.5349 7.85463C63.8643 7.85463 63.2704 8.00903 62.7531 8.31784C62.2549 8.60735 61.8622 9.03196 61.5748 9.59167C61.2874 10.1514 61.1437 10.8076 61.1437 11.5603V19.956H58.471V11.3287C58.471 10.2093 58.1932 9.36006 57.6376 8.78105C57.082 8.18274 56.3252 7.88358 55.3672 7.88358C54.6966 7.88358 54.1027 8.03798 53.5854 8.34679C53.0873 8.6363 52.6945 9.06091 52.4071 9.62062C52.1197 10.161 51.976 10.8076 51.976 11.5603V19.956Z' fill='white'/>
<path
d='M31.5718 15.845H34.1583C34.1583 16.5591 34.4169 17.1285 34.9342 17.5531C35.4515 17.9584 36.1508 18.1611 37.0321 18.1611C37.9901 18.1611 38.7277 17.9777 39.245 17.611C39.7623 17.225 40.021 16.7135 40.021 16.0766C40.021 15.6134 39.8773 15.2274 39.5899 14.9186C39.3217 14.6098 38.8235 14.3589 38.0955 14.1659L35.6239 13.5869C34.3786 13.2781 33.4494 12.8052 32.8363 12.1683C32.2423 11.5314 31.9454 10.6918 31.9454 9.64957C31.9454 8.78105 32.1657 8.02833 32.6064 7.39142C33.0662 6.7545 33.6889 6.26234 34.4744 5.91494C35.2791 5.56753 36.1987 5.39382 37.2333 5.39382C38.2679 5.39382 39.1588 5.57718 39.906 5.94389C40.6724 6.31059 41.2663 6.82206 41.6878 7.47827C42.1285 8.13449 42.3584 8.91615 42.3776 9.82327H39.7911C39.7719 9.08986 39.5324 8.52049 39.0726 8.11518C38.6128 7.70988 37.9709 7.50722 37.1471 7.50722C36.3041 7.50722 35.6527 7.69058 35.1929 8.05728C34.733 8.42399 34.5031 8.9258 34.5031 9.56272C34.5031 10.5084 35.1929 11.155 36.5723 11.5024L39.0439 12.1104C40.2317 12.3806 41.1226 12.8245 41.7166 13.4421C42.3105 14.0404 42.6075 14.8607 42.6075 15.9029C42.6075 16.7907 42.368 17.5724 41.889 18.2479C41.41 18.9041 40.749 19.4156 39.906 19.7823C39.0822 20.1297 38.1051 20.3034 36.9747 20.3034C35.327 20.3034 34.0146 19.8981 33.0375 19.0875C32.0603 18.2769 31.5718 17.196 31.5718 15.845Z'
fill='white'
/>
<path
d='M44.5096 19.956V5.79913C45.5868 6.19296 46.0617 6.19296 47.211 5.79913V19.956H44.5096ZM45.8316 4.86332C45.3526 4.86332 44.9311 4.68962 44.5671 4.34221C44.2222 3.9755 44.0498 3.55089 44.0498 3.06838C44.0498 2.56657 44.2222 2.14196 44.5671 1.79455C44.9311 1.44714 45.3526 1.27344 45.8316 1.27344C46.3297 1.27344 46.7512 1.44714 47.0961 1.79455C47.441 2.14196 47.6134 2.56657 47.6134 3.06838C47.6134 3.55089 47.441 3.9755 47.0961 4.34221C46.7512 4.68962 46.3297 4.86332 45.8316 4.86332Z'
fill='white'
/>
<path
d='M51.976 19.956H49.2746V5.79913H51.6887V8.18778C51.976 7.39647 52.5317 6.72555 53.298 6.20444C54.0835 5.66403 55.0319 5.39382 56.1432 5.39382C57.3885 5.39382 58.4231 5.73158 59.247 6.4071C60.0708 7.08261 60.6073 7.98008 60.8563 9.09951H60.3678C60.5594 7.98008 61.0862 7.08261 61.9484 6.4071C62.8106 5.73158 63.8739 5.39382 65.1384 5.39382C66.7478 5.39382 68.0123 5.86668 68.9319 6.8124C69.8516 7.75813 70.3114 9.05126 70.3114 10.6918V19.956H67.6674V11.3577C67.6674 10.2382 67.38 9.37936 66.8053 8.78105C66.2496 8.16344 65.4928 7.85463 64.5349 7.85463C63.8643 7.85463 63.2704 8.00903 62.7531 8.31784C62.2549 8.60735 61.8622 9.03196 61.5748 9.59167C61.2874 10.1514 61.1437 10.8076 61.1437 11.5603V19.956H58.471V11.3287C58.471 10.2093 58.1932 9.36006 57.6376 8.78105C57.082 8.18274 56.3252 7.88358 55.3672 7.88358C54.6966 7.88358 54.1027 8.03798 53.5854 8.34679C53.0873 8.6363 52.6945 9.06091 52.4071 9.62062C52.1197 10.161 51.976 10.8076 51.976 11.5603V19.956Z'
fill='white'
/>
</svg>
</Link>
<div className='[&_a]:text-[#808080] [&_a:hover]:text-white'>
<div className='[&_a:hover]:text-white [&_a]:text-[#808080]'>
<StatusIndicator />
</div>
</div>
@@ -68,7 +95,7 @@ export default function Footer({ fullWidth = false }: FooterProps) {
<div className='flex flex-col gap-[48px] sm:flex-row sm:gap-[80px]'>
{/* Company links */}
<div>
<h2 className='mb-[24px] font-[family-name:var(--font-season)] text-[20px] font-medium tracking-[-0.4px] text-white'>
<h2 className='mb-[24px] font-[family-name:var(--font-season)] font-medium text-[20px] text-white tracking-[-0.4px]'>
Company
</h2>
<div className='flex flex-col gap-[10px]'>
@@ -137,7 +164,7 @@ export default function Footer({ fullWidth = false }: FooterProps) {
{/* Blocks section */}
<div className='hidden sm:block'>
<h2 className='mb-[24px] font-[family-name:var(--font-season)] text-[20px] font-medium tracking-[-0.4px] text-white'>
<h2 className='mb-[24px] font-[family-name:var(--font-season)] font-medium text-[20px] text-white tracking-[-0.4px]'>
Blocks
</h2>
<div className='flex flex-col gap-[10px]'>
@@ -157,7 +184,7 @@ export default function Footer({ fullWidth = false }: FooterProps) {
href='https://docs.sim.ai/blocks'
target='_blank'
rel='noopener noreferrer'
className='mt-[24px] inline-block font-[family-name:var(--font-season)] text-[14px] font-medium tracking-[-0.28px] text-white transition-opacity hover:opacity-80'
className='mt-[24px] inline-block font-[family-name:var(--font-season)] font-medium text-[14px] text-white tracking-[-0.28px] transition-opacity hover:opacity-80'
>
View all Blocks &rarr;
</Link>
@@ -165,7 +192,7 @@ export default function Footer({ fullWidth = false }: FooterProps) {
{/* Tools section */}
<div className='hidden sm:block'>
<h2 className='mb-[24px] font-[family-name:var(--font-season)] text-[20px] font-medium tracking-[-0.4px] text-white'>
<h2 className='mb-[24px] font-[family-name:var(--font-season)] font-medium text-[20px] text-white tracking-[-0.4px]'>
Tools
</h2>
<div className='flex flex-col gap-[10px]'>
@@ -185,7 +212,7 @@ export default function Footer({ fullWidth = false }: FooterProps) {
href='https://docs.sim.ai/tools'
target='_blank'
rel='noopener noreferrer'
className='mt-[24px] inline-block font-[family-name:var(--font-season)] text-[14px] font-medium tracking-[-0.28px] text-white transition-opacity hover:opacity-80'
className='mt-[24px] inline-block font-[family-name:var(--font-season)] font-medium text-[14px] text-white tracking-[-0.28px] transition-opacity hover:opacity-80'
>
View all Tools &rarr;
</Link>
@@ -194,7 +221,7 @@ export default function Footer({ fullWidth = false }: FooterProps) {
</div>
{/* Social links — bottom */}
<div className='[&_a]:text-[#808080] [&_a:hover]:text-white'>
<div className='[&_a:hover]:text-white [&_a]:text-[#808080]'>
<SocialLinks />
</div>
</div>

View File

@@ -10,7 +10,7 @@ export function BackLink() {
return (
<Link
href='/studio'
className='group flex items-center gap-1 font-season font-[430] text-[#F6F6F0]/50 text-sm hover:text-[#F6F6F0]/80'
className='group flex items-center gap-1 font-[430] font-season text-[#F6F6F0]/50 text-sm hover:text-[#F6F6F0]/80'
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>

View File

@@ -50,11 +50,7 @@ export default async function Page({ params }: { params: Promise<{ slug: string
const related = await getRelatedPosts(slug, 3)
return (
<article
className='w-full'
itemScope
itemType='https://schema.org/BlogPosting'
>
<article className='w-full' itemScope itemType='https://schema.org/BlogPosting'>
<script
type='application/ld+json'
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
@@ -69,18 +65,18 @@ export default async function Page({ params }: { params: Promise<{ slug: string
</div>
<div className='flex flex-col'>
<h1
className='font-season font-[430] text-[36px] text-white leading-tight tracking-[-0.02em] sm:text-[48px] md:text-[56px] lg:text-[64px]'
className='font-[430] font-season text-[36px] text-white leading-tight tracking-[-0.02em] sm:text-[48px] md:text-[56px] lg:text-[64px]'
itemProp='headline'
>
{post.title}
</h1>
<p className='mt-4 font-season font-[430] text-[16px] text-[#F6F6F0]/80 leading-[1.5] sm:text-[18px] md:text-[22px]'>
<p className='mt-4 font-[430] font-season text-[#F6F6F0]/80 text-[16px] leading-[1.5] sm:text-[18px] md:text-[22px]'>
{post.description}
</p>
<div className='mt-6 flex items-center justify-between'>
<div className='flex items-center gap-3'>
<time
className='font-season font-[430] text-[14px] text-[#F6F6F0]/50 leading-[1.5] sm:text-[16px]'
className='font-[430] font-season text-[#F6F6F0]/50 text-[14px] leading-[1.5] sm:text-[16px]'
dateTime={post.date}
itemProp='datePublished'
>
@@ -104,7 +100,7 @@ export default async function Page({ params }: { params: Promise<{ slug: string
href={a?.url || '#'}
target='_blank'
rel='noopener noreferrer author'
className='font-season font-[430] text-[14px] text-[#F6F6F0]/50 leading-[1.5] hover:text-[#F6F6F0]/80 sm:text-[16px]'
className='font-[430] font-season text-[#F6F6F0]/50 text-[14px] leading-[1.5] hover:text-[#F6F6F0]/80 sm:text-[16px]'
itemProp='author'
itemScope
itemType='https://schema.org/Person'
@@ -120,7 +116,10 @@ export default async function Page({ params }: { params: Promise<{ slug: string
<hr className='mt-8 border-[#2A2A2A] border-t sm:mt-12' />
</header>
<div className='mx-auto max-w-[900px] px-6 py-10 pb-20 sm:px-8 md:px-12' itemProp='articleBody'>
<div
className='mx-auto max-w-[900px] px-6 py-10 pb-20 sm:px-8 md:px-12'
itemProp='articleBody'
>
<div className={PROSE_CLASSES}>
<Article />
{post.faq && post.faq.length > 0 ? <FAQ items={post.faq} /> : null}
@@ -128,7 +127,9 @@ export default async function Page({ params }: { params: Promise<{ slug: string
</div>
{related.length > 0 && (
<div className='mx-auto max-w-[900px] px-6 pb-24 sm:px-8 md:px-12'>
<h2 className='mb-4 font-season font-[430] text-[24px] text-white tracking-[-0.02em]'>Related posts</h2>
<h2 className='mb-4 font-[430] font-season text-[24px] text-white tracking-[-0.02em]'>
Related posts
</h2>
<div className='grid grid-cols-1 gap-4 sm:grid-cols-2 sm:gap-6 lg:grid-cols-3'>
{related.map((p) => (
<Link key={p.slug} href={`/studio/${p.slug}`} className='group'>
@@ -144,14 +145,16 @@ export default async function Page({ params }: { params: Promise<{ slug: string
unoptimized
/>
<div className='p-3'>
<div className='mb-1 font-season font-[430] text-[#F6F6F0]/50 text-xs'>
<div className='mb-1 font-[430] font-season text-[#F6F6F0]/50 text-xs'>
{new Date(p.date).toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric',
})}
</div>
<div className='font-season font-[430] text-white text-sm leading-tight'>{p.title}</div>
<div className='font-[430] font-season text-sm text-white leading-tight'>
{p.title}
</div>
</div>
</div>
</Link>

View File

@@ -24,7 +24,7 @@ export function ShareButton({ url }: ShareButtonProps) {
return (
<button
onClick={handleCopy}
className='flex items-center gap-1.5 font-season font-[430] text-[#F6F6F0]/50 text-sm hover:text-[#F6F6F0]/80'
className='flex items-center gap-1.5 font-[430] font-season text-[#F6F6F0]/50 text-sm hover:text-[#F6F6F0]/80'
aria-label='Copy link'
>
<Share2 className='h-4 w-4' />

View File

@@ -11,7 +11,9 @@ export default async function AuthorPage({ params }: { params: Promise<{ id: str
if (!author) {
return (
<main className='mx-auto max-w-[900px] px-6 py-10 sm:px-8 md:px-12'>
<h1 className='font-season font-[430] text-[32px] text-white tracking-[-0.02em]'>Author not found</h1>
<h1 className='font-[430] font-season text-[32px] text-white tracking-[-0.02em]'>
Author not found
</h1>
</main>
)
}
@@ -40,7 +42,9 @@ export default async function AuthorPage({ params }: { params: Promise<{ id: str
unoptimized
/>
) : null}
<h1 className='font-season font-[430] text-[32px] text-white leading-tight tracking-[-0.02em]'>{author.name}</h1>
<h1 className='font-[430] font-season text-[32px] text-white leading-tight tracking-[-0.02em]'>
{author.name}
</h1>
</div>
<div className='grid grid-cols-1 gap-8 sm:grid-cols-2'>
{posts.map((p) => (
@@ -55,14 +59,16 @@ export default async function AuthorPage({ params }: { params: Promise<{ id: str
unoptimized
/>
<div className='p-3'>
<div className='mb-1 font-season font-[430] text-[#F6F6F0]/50 text-xs'>
<div className='mb-1 font-[430] font-season text-[#F6F6F0]/50 text-xs'>
{new Date(p.date).toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric',
})}
</div>
<div className='font-season font-[430] text-white text-sm leading-tight'>{p.title}</div>
<div className='font-[430] font-season text-sm text-white leading-tight'>
{p.title}
</div>
</div>
</div>
</Link>

View File

@@ -1,7 +1,7 @@
import Navbar from '@/app/(home)/components/navbar/navbar'
import { Footer } from '@/app/(landing)/components'
import { martianMono } from '@/app/_styles/fonts/martian-mono/martian-mono'
import { season } from '@/app/_styles/fonts/season/season'
import Navbar from '@/app/(home)/components/navbar/navbar'
import { Footer } from '@/app/(landing)/components'
export default function StudioLayout({ children }: { children: React.ReactNode }) {
const orgJsonLd = {

View File

@@ -45,10 +45,10 @@ export default async function StudioIndex({
/>
<main className='relative z-10 mx-auto max-w-[1400px] px-4 py-16 sm:px-6 md:px-8 md:py-24'>
<h1 className='mt-6 font-season font-[430] text-4xl text-white tracking-[-0.02em] sm:text-5xl'>
<h1 className='mt-6 font-[430] font-season text-4xl text-white tracking-[-0.02em] sm:text-5xl'>
Sim Studio
</h1>
<p className='mt-3 font-season font-[430] text-[#F6F6F0]/50 text-[14px] leading-[125%] tracking-[0.02em] sm:text-[16px]'>
<p className='mt-3 font-[430] font-season text-[#F6F6F0]/50 text-[14px] leading-[125%] tracking-[0.02em] sm:text-[16px]'>
Announcements, insights, and guides for building AI agent workflows.
</p>
@@ -61,18 +61,18 @@ export default async function StudioIndex({
{pageNum > 1 && (
<Link
href={`/studio?page=${pageNum - 1}${tag ? `&tag=${encodeURIComponent(tag)}` : ''}`}
className='rounded-[5px] border border-[#2A2A2A] bg-[rgba(246,246,240,0.06)] px-3 py-1 font-season font-[430] text-[14px] text-[#F6F6F6] transition-all hover:bg-[rgba(246,246,240,0.1)]'
className='rounded-[5px] border border-[#2A2A2A] bg-[rgba(246,246,240,0.06)] px-3 py-1 font-[430] font-season text-[#F6F6F6] text-[14px] transition-all hover:bg-[rgba(246,246,240,0.1)]'
>
Previous
</Link>
)}
<span className='font-season font-[430] text-[#F6F6F0]/50 text-[14px]'>
<span className='font-[430] font-season text-[#F6F6F0]/50 text-[14px]'>
Page {pageNum} of {totalPages}
</span>
{pageNum < totalPages && (
<Link
href={`/studio?page=${pageNum + 1}${tag ? `&tag=${encodeURIComponent(tag)}` : ''}`}
className='rounded-[5px] border border-[#2A2A2A] bg-[rgba(246,246,240,0.06)] px-3 py-1 font-season font-[430] text-[14px] text-[#F6F6F6] transition-all hover:bg-[rgba(246,246,240,0.1)]'
className='rounded-[5px] border border-[#2A2A2A] bg-[rgba(246,246,240,0.06)] px-3 py-1 font-[430] font-season text-[#F6F6F6] text-[14px] transition-all hover:bg-[rgba(246,246,240,0.1)]'
>
Next
</Link>

View File

@@ -66,10 +66,10 @@ export function PostGrid({ posts }: { posts: Post[] }) {
/>
</div>
<div className='flex flex-1 flex-col gap-2 p-4'>
<h3 className='font-season font-[430] text-[17px] text-white leading-snug'>
<h3 className='font-[430] font-season text-[17px] text-white leading-snug'>
{p.title}
</h3>
<span className='font-season font-[430] text-[12px] text-[#F6F6F0]/50'>
<span className='font-[430] font-season text-[#F6F6F0]/50 text-[12px]'>
{new Date(p.date).toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
@@ -89,7 +89,7 @@ export function PostGrid({ posts }: { posts: Post[] }) {
<button
type='button'
onClick={() => setShowAll(true)}
className='rounded-[5px] border border-[#2A2A2A] bg-[rgba(246,246,240,0.06)] px-4 py-2 font-season font-[430] text-[14px] text-[#F6F6F6] transition-all hover:bg-[rgba(246,246,240,0.1)]'
className='rounded-[5px] border border-[#2A2A2A] bg-[rgba(246,246,240,0.06)] px-4 py-2 font-[430] font-season text-[#F6F6F6] text-[14px] transition-all hover:bg-[rgba(246,246,240,0.1)]'
>
Show more
</button>

View File

@@ -5,16 +5,21 @@ export default async function TagsIndex() {
const tags = await getAllTags()
return (
<main className='mx-auto max-w-[900px] px-6 py-10 sm:px-8 md:px-12'>
<h1 className='mb-6 font-season font-[430] text-[32px] text-white leading-tight tracking-[-0.02em]'>Browse by tag</h1>
<h1 className='mb-6 font-[430] font-season text-[32px] text-white leading-tight tracking-[-0.02em]'>
Browse by tag
</h1>
<div className='flex flex-wrap gap-3'>
<Link href='/studio' className='rounded-full border border-[#2A2A2A] bg-[rgba(246,246,240,0.06)] px-3 py-1 font-season font-[430] text-[14px] text-[#F6F6F6] transition-all hover:bg-[rgba(246,246,240,0.1)]'>
<Link
href='/studio'
className='rounded-full border border-[#2A2A2A] bg-[rgba(246,246,240,0.06)] px-3 py-1 font-[430] font-season text-[#F6F6F6] text-[14px] transition-all hover:bg-[rgba(246,246,240,0.1)]'
>
All
</Link>
{tags.map((t) => (
<Link
key={t.tag}
href={`/studio?tag=${encodeURIComponent(t.tag)}`}
className='rounded-full border border-[#2A2A2A] bg-[rgba(246,246,240,0.06)] px-3 py-1 font-season font-[430] text-[14px] text-[#F6F6F6] transition-all hover:bg-[rgba(246,246,240,0.1)]'
className='rounded-full border border-[#2A2A2A] bg-[rgba(246,246,240,0.06)] px-3 py-1 font-[430] font-season text-[#F6F6F6] text-[14px] transition-all hover:bg-[rgba(246,246,240,0.1)]'
>
{t.tag} ({t.count})
</Link>

File diff suppressed because it is too large Load Diff

View File

@@ -2,9 +2,9 @@ import { BookOpen, Github, Rss } from 'lucide-react'
import Image from 'next/image'
import Link from 'next/link'
import { ChangelogBlocks } from '@/app/changelog/components/changelog-blocks'
import ChangelogList from '@/app/changelog/components/timeline-list'
import { Breaks } from '@/app/changelog/components/variants/breaks'
import { Scroll } from '@/app/changelog/components/variants/scroll'
import ChangelogList from '@/app/changelog/components/timeline-list'
export interface ChangelogEntry {
tag: string
@@ -123,10 +123,10 @@ export default async function ChangelogContent({ variant }: ChangelogContentProp
<ChangelogBlocks />
<div className='relative z-10 mx-auto h-full max-w-xl md:flex md:flex-col md:justify-center'>
<h1 className='mt-6 font-season font-[430] text-4xl text-white tracking-[-0.02em] sm:text-5xl'>
<h1 className='mt-6 font-[430] font-season text-4xl text-white tracking-[-0.02em] sm:text-5xl'>
Changelog
</h1>
<p className='mt-3 font-season font-[430] text-[#F6F6F0]/50 text-[14px] leading-[125%] tracking-[0.02em] sm:text-[16px]'>
<p className='mt-3 font-[430] font-season text-[#F6F6F0]/50 text-[14px] leading-[125%] tracking-[0.02em] sm:text-[16px]'>
Stay up-to-date with the latest features, improvements, and bug fixes in Sim. All
changes are documented here with detailed release notes.
</p>
@@ -136,21 +136,21 @@ export default async function ChangelogContent({ variant }: ChangelogContentProp
href='https://github.com/simstudioai/sim/releases'
target='_blank'
rel='noopener noreferrer'
className='inline-flex h-[32px] items-center gap-[6px] rounded-[5px] border border-[#33C482] bg-[#33C482] px-[10px] font-season font-[430] text-[14px] text-black transition-[filter] hover:brightness-110'
className='inline-flex h-[32px] items-center gap-[6px] rounded-[5px] border border-[#33C482] bg-[#33C482] px-[10px] font-[430] font-season text-[14px] text-black transition-[filter] hover:brightness-110'
>
<Github className='h-4 w-4' />
View on GitHub
</Link>
<Link
href='https://docs.sim.ai'
className='inline-flex h-[32px] items-center gap-[6px] rounded-[5px] border border-[#2A2A2A] bg-[rgba(246,246,240,0.06)] px-[10px] font-season font-[430] text-[14px] text-[#F6F6F6] transition-all hover:bg-[rgba(246,246,240,0.1)]'
className='inline-flex h-[32px] items-center gap-[6px] rounded-[5px] border border-[#2A2A2A] bg-[rgba(246,246,240,0.06)] px-[10px] font-[430] font-season text-[#F6F6F6] text-[14px] transition-all hover:bg-[rgba(246,246,240,0.1)]'
>
<BookOpen className='h-4 w-4' />
Documentation
</Link>
<Link
href='/changelog.xml'
className='inline-flex h-[32px] items-center gap-[6px] rounded-[5px] border border-[#2A2A2A] bg-[rgba(246,246,240,0.06)] px-[10px] font-season font-[430] text-[14px] text-[#F6F6F6] transition-all hover:bg-[rgba(246,246,240,0.1)]'
className='inline-flex h-[32px] items-center gap-[6px] rounded-[5px] border border-[#2A2A2A] bg-[rgba(246,246,240,0.06)] px-[10px] font-[430] font-season text-[#F6F6F6] text-[14px] transition-all hover:bg-[rgba(246,246,240,0.1)]'
>
<Rss className='h-4 w-4' />
RSS Feed

View File

@@ -6,8 +6,18 @@ import type { ChangelogEntry } from '@/app/changelog/components/changelog-conten
const HEATMAP_COLORS = ['#2ABBF8', '#00F701', '#FFCC02', '#FA4EDF'] as const
const GREEN_BASE = '#39d353'
const MONTH_NAMES = [
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec',
] as const
const CELL_SIZE = 10
@@ -16,11 +26,13 @@ const CELL_RADIUS = 2
const DAY_LABEL_WIDTH = 28
const MONTH_ROW_HEIGHT = 16
const MAX_HEATMAP_WEEKS = 26
const SNAKE_LENGTH = 12
const EASING_K = 8
/** Cells (days) from the active date to the edge of the colored glow. */
const GLOW_RADIUS = 7
const EASING_K = 5
const SNAP_CELLS = 10
const SETTLE_THRESHOLD = 0.0001
const SETTLE_THRESHOLD = 0.05
interface CellData {
date: string
@@ -33,6 +45,7 @@ interface CellData {
interface GridData {
cells: CellData[]
dates: Date[]
dateToSeqIndex: Map<string, number>
monthLabels: Array<{ label: string; weekIndex: number }>
dayLabels: Array<{ label: string; dayIndex: number }>
numWeeks: number
@@ -66,13 +79,10 @@ function cellPixel(cell: CellData): [number, number] {
function computeGrid(entries: ChangelogEntry[]): GridData | null {
if (!entries.length) return null
const earliestEntry = entries.reduce(
(earliest, entry) => {
const d = entry.date.split('T')[0]
return d < earliest ? d : earliest
},
entries[0].date.split('T')[0]
)
const earliestEntry = entries.reduce((earliest, entry) => {
const d = entry.date.split('T')[0]
return d < earliest ? d : earliest
}, entries[0].date.split('T')[0])
const earliestDate = new Date(`${earliestEntry}T00:00:00`)
earliestDate.setDate(earliestDate.getDate() - earliestDate.getDay())
@@ -153,6 +163,11 @@ function computeGrid(entries: ChangelogEntry[]): GridData | null {
monthLabels.pop()
}
const dateToSeqIndex = new Map<string, number>()
for (const cell of cells) {
dateToSeqIndex.set(cell.date, cell.seqIndex)
}
const gridWidth = numWeeks * (CELL_SIZE + CELL_GAP) - CELL_GAP
const gridHeight = 7 * (CELL_SIZE + CELL_GAP) - CELL_GAP
const svgWidth = DAY_LABEL_WIDTH + gridWidth + 16
@@ -161,6 +176,7 @@ function computeGrid(entries: ChangelogEntry[]): GridData | null {
return {
cells,
dates,
dateToSeqIndex,
monthLabels,
dayLabels: [
{ label: 'Mon', dayIndex: 1 },
@@ -174,23 +190,20 @@ function computeGrid(entries: ChangelogEntry[]): GridData | null {
}
export interface CommitHeatmapHandle {
setProgress: (progress: number) => void
setActiveDate: (date: string) => void
}
interface CommitHeatmapProps {
entries: ChangelogEntry[]
activeDate?: string
progress?: number
}
export const CommitHeatmap = forwardRef<CommitHeatmapHandle, CommitHeatmapProps>(
function CommitHeatmap({ entries, progress }, ref) {
function CommitHeatmap({ entries, activeDate: activeDateProp }, ref) {
const canvasRef = useRef<HTMLCanvasElement>(null)
const gridRef = useRef<GridData | null>(null)
const targetRef = useRef(0)
const currentRef = useRef(0)
const prevPosRef = useRef(-1)
const directionRef = useRef<1 | -1>(1)
const targetRef = useRef(-1)
const currentRef = useRef(-1)
const rafRef = useRef(0)
const lastTsRef = useRef(0)
const runningRef = useRef(false)
@@ -198,6 +211,18 @@ export const CommitHeatmap = forwardRef<CommitHeatmapHandle, CommitHeatmapProps>
const grid = useMemo(() => computeGrid(entries), [entries])
gridRef.current = grid
const resolveSeqIndex = useCallback((date: string): number => {
const g = gridRef.current
if (!g || g.cells.length === 0) return -1
const idx = g.dateToSeqIndex.get(date)
if (idx !== undefined) return idx
const first = g.cells[0].date
const last = g.cells[g.cells.length - 1].date
if (date < first) return 0
if (date > last) return g.cells.length - 1
return -1
}, [])
const draw = useCallback(() => {
const canvas = canvasRef.current
const g = gridRef.current
@@ -207,21 +232,7 @@ export const CommitHeatmap = forwardRef<CommitHeatmapHandle, CommitHeatmapProps>
if (!ctx) return
const { cells, monthLabels, dayLabels, svgWidth, svgHeight } = g
const p = currentRef.current
const totalCells = Math.max(0, cells.length - 1)
const effectivePos = p * totalCells
if (prevPosRef.current >= 0) {
if (effectivePos > prevPosRef.current) directionRef.current = 1
else if (effectivePos < prevPosRef.current) directionRef.current = -1
}
prevPosRef.current = effectivePos
const goingBack = directionRef.current === 1
const maxTail = goingBack ? effectivePos : totalCells - effectivePos
const snakeLen = Math.min(SNAKE_LENGTH, maxTail)
const snakeStart = goingBack ? effectivePos - snakeLen : effectivePos
const snakeEnd = goingBack ? effectivePos : effectivePos + snakeLen
const activeSeq = currentRef.current
const dpr = window.devicePixelRatio || 1
const rect = canvas.getBoundingClientRect()
@@ -273,86 +284,73 @@ export const CommitHeatmap = forwardRef<CommitHeatmapHandle, CommitHeatmapProps>
for (const cell of cells) {
const [x, y] = cellPixel(cell)
const greenOp = greenOpacity(cell.seqIndex)
const isInSnake =
effectivePos > 0 &&
cell.traversalIndex >= snakeStart &&
cell.traversalIndex <= snakeEnd
ctx.fillStyle = GREEN_BASE
ctx.globalAlpha = greenOp
ctx.globalAlpha = greenOpacity(cell.seqIndex)
fillRR(x, y, CELL_SIZE, CELL_SIZE, CELL_RADIUS)
if (isInSnake) {
const distFromHead = Math.abs(cell.traversalIndex - effectivePos)
const t = snakeLen > 0 ? distFromHead / snakeLen : 0
const colorOp = 0.9 - t * 0.75
const colorIdx = Math.floor(pseudoRandom(cell.seqIndex + 1) * HEATMAP_COLORS.length)
ctx.fillStyle = HEATMAP_COLORS[colorIdx]
ctx.globalAlpha = colorOp
fillRR(x, y, CELL_SIZE, CELL_SIZE, CELL_RADIUS)
}
ctx.globalAlpha = 1
}
if (effectivePos > 0 && cells.length > 1) {
const floorT = Math.floor(effectivePos)
const ceilT = Math.min(floorT + 1, totalCells)
const frac = effectivePos - floorT
const cellA = cells[cells.length - 1 - floorT]
const cellB = cells[cells.length - 1 - ceilT]
if (cellA && cellB) {
const [ax, ay] = cellPixel(cellA)
const [bx, by] = cellPixel(cellB)
const hx = ax + (bx - ax) * frac
const hy = ay + (by - ay) * frac
ctx.save()
ctx.shadowColor = '#ffffff'
ctx.shadowBlur = 6
ctx.fillStyle = '#ffffff'
ctx.globalAlpha = 0.7
fillRR(hx, hy, CELL_SIZE, CELL_SIZE, CELL_RADIUS)
ctx.restore()
if (activeSeq >= 0) {
const dist = Math.abs(cell.seqIndex - activeSeq)
if (dist < GLOW_RADIUS) {
const t = 1 - dist / GLOW_RADIUS
const smooth = t * t * (3 - 2 * t)
const colorIdx = Math.floor(pseudoRandom(cell.seqIndex) * HEATMAP_COLORS.length)
const baseOpacity = 0.6 + pseudoRandom(cell.seqIndex + 100) * 0.4
const overlay = smooth * baseOpacity
if (overlay > 0.01) {
ctx.fillStyle = HEATMAP_COLORS[colorIdx]
ctx.globalAlpha = overlay
fillRR(x, y, CELL_SIZE, CELL_SIZE, CELL_RADIUS)
}
}
}
}
ctx.globalAlpha = 1
}, [])
const animate = useCallback((timestamp: number) => {
const g = gridRef.current
if (!g) {
runningRef.current = false
return
}
const animate = useCallback(
(timestamp: number) => {
const g = gridRef.current
if (!g) {
runningRef.current = false
return
}
const target = targetRef.current
const current = currentRef.current
const delta = target - current
const totalCells = Math.max(1, g.cells.length - 1)
const cellDelta = Math.abs(delta) * totalCells
const target = targetRef.current
const current = currentRef.current
if (target < 0) {
currentRef.current = target
draw()
runningRef.current = false
lastTsRef.current = 0
return
}
const delta = target - current
const cellDelta = Math.abs(delta)
if (cellDelta < SETTLE_THRESHOLD) {
currentRef.current = target
draw()
runningRef.current = false
lastTsRef.current = 0
return
}
const dt =
lastTsRef.current > 0 ? Math.min((timestamp - lastTsRef.current) / 1000, 0.1) : 1 / 60
lastTsRef.current = timestamp
const k = cellDelta > SNAP_CELLS ? 20 : EASING_K
const factor = 1 - Math.exp(-k * dt)
currentRef.current = current + delta * factor
if (cellDelta < SETTLE_THRESHOLD) {
currentRef.current = target
draw()
runningRef.current = false
lastTsRef.current = 0
return
}
const dt =
lastTsRef.current > 0
? Math.min((timestamp - lastTsRef.current) / 1000, 0.1)
: 1 / 60
lastTsRef.current = timestamp
const k = cellDelta > SNAP_CELLS ? 20 : EASING_K
const factor = 1 - Math.exp(-k * dt)
currentRef.current = current + delta * factor
draw()
rafRef.current = requestAnimationFrame(animate)
}, [draw])
rafRef.current = requestAnimationFrame(animate)
},
[draw]
)
const startLoop = useCallback(() => {
if (runningRef.current) return
@@ -361,23 +359,22 @@ export const CommitHeatmap = forwardRef<CommitHeatmapHandle, CommitHeatmapProps>
rafRef.current = requestAnimationFrame(animate)
}, [animate])
useImperativeHandle(
ref,
() => ({
setProgress(p: number) {
targetRef.current = Math.max(0, Math.min(1, p))
startLoop()
},
}),
[startLoop]
const setActiveDate = useCallback(
(date: string) => {
const seqIdx = resolveSeqIndex(date)
if (seqIdx < 0) return
targetRef.current = seqIdx
if (currentRef.current < 0) currentRef.current = seqIdx
startLoop()
},
[resolveSeqIndex, startLoop]
)
useImperativeHandle(ref, () => ({ setActiveDate }), [setActiveDate])
useEffect(() => {
if (progress !== undefined) {
targetRef.current = progress
startLoop()
}
}, [progress, startLoop])
if (activeDateProp) setActiveDate(activeDateProp)
}, [activeDateProp, setActiveDate])
useEffect(() => {
if (grid) draw()

View File

@@ -115,9 +115,7 @@ export default function ChangelogList({
const [page, setPage] = React.useState<number>(1)
const [loading, setLoading] = React.useState<boolean>(false)
const [done, setDone] = React.useState<boolean>(!!pageSize)
const [visibleCount, setVisibleCount] = React.useState<number>(
pageSize ?? initialEntries.length
)
const [visibleCount, setVisibleCount] = React.useState<number>(pageSize ?? initialEntries.length)
const [activeTag, setActiveTag] = React.useState<string | null>(initialEntries[0]?.tag ?? null)
const shouldTrackActiveEntry = Boolean(onActiveEntryChange)
const cardRefs = React.useRef<Array<HTMLDivElement | null>>([])
@@ -233,7 +231,7 @@ export default function ChangelogList({
h2: ({ children, ...props }: any) =>
isContributorsLabel(children) ? null : (
<h3
className='mt-5 mb-2 font-season font-[430] text-[13px] text-[#F6F6F6] tracking-[-0.02em] [&:first-child]:mt-0'
className='mt-5 mb-2 font-[430] font-season text-[#F6F6F6] text-[13px] tracking-[-0.02em] [&:first-child]:mt-0'
{...props}
>
{children}
@@ -242,7 +240,7 @@ export default function ChangelogList({
h3: ({ children, ...props }: any) =>
isContributorsLabel(children) ? null : (
<h4
className='mt-4 mb-1 font-season font-[430] text-[13px] text-[#F6F6F6] tracking-[-0.02em] [&:first-child]:mt-0'
className='mt-4 mb-1 font-[430] font-season text-[#F6F6F6] text-[13px] tracking-[-0.02em] [&:first-child]:mt-0'
{...props}
>
{children}
@@ -258,7 +256,7 @@ export default function ChangelogList({
if (/^\s*contributors\s*:?\s*$/i.test(text)) return null
return (
<li
className='font-season font-normal text-[13px] text-[#F6F6F0]/50 leading-[125%] tracking-[0.02em]'
className='font-normal font-season text-[#F6F6F0]/50 text-[13px] leading-[125%] tracking-[0.02em]'
{...props}
>
{children}
@@ -268,7 +266,7 @@ export default function ChangelogList({
p: ({ children, ...props }: any) =>
/^\s*contributors\s*:?\s*$/i.test(String(children)) ? null : (
<p
className='mb-3 font-season font-normal text-[13px] text-[#F6F6F0]/50 leading-[125%] tracking-[0.02em]'
className='mb-3 font-normal font-season text-[#F6F6F0]/50 text-[13px] leading-[125%] tracking-[0.02em]'
{...props}
>
{children}
@@ -294,12 +292,7 @@ export default function ChangelogList({
),
img: () => null,
a: ({ className, ...props }: any) => (
<a
{...props}
className={`underline ${className ?? ''}`}
target='_blank'
rel='noreferrer'
/>
<a {...props} className={`underline ${className ?? ''}`} target='_blank' rel='noreferrer' />
),
}
@@ -323,83 +316,10 @@ export default function ChangelogList({
return (
<React.Fragment key={entry.tag}>
{index > 0 && (
<div className='relative left-1/2 w-[100vw] -translate-x-1/2 md:w-[50vw]'>
<div className='-translate-x-1/2 relative left-1/2 w-[100vw] md:w-[50vw]'>
<DotSeparator />
</div>
)}
<div
ref={setRef}
data-entry-index={index}
data-tag={entry.tag}
className='py-8'
>
<div className='mb-5 flex items-center justify-between gap-4'>
<div className='flex items-center gap-3'>
<a
href={entry.url}
target='_blank'
rel='noreferrer noopener'
className='group/tag font-season font-[600] text-[#fdfdf8] text-xl tracking-[-0.02em]'
>
<span className='relative'>
{entry.tag}
<span className='absolute bottom-0 left-0 h-[1px] w-0 bg-[#fdfdf8] transition-[width] duration-200 group-hover/tag:w-full' />
</span>
</a>
{entry.contributors && entry.contributors.length > 0 && (
<div className='-space-x-2 flex'>
{entry.contributors.slice(0, 5).map((contributor) => (
<a
key={contributor}
href={`https://github.com/${contributor}`}
target='_blank'
rel='noreferrer noopener'
aria-label={`View @${contributor} on GitHub`}
title={`@${contributor}`}
className='block'
>
<Avatar className='size-6 ring-2 ring-[#1C1C1C]'>
<AvatarImage
src={`https://avatars.githubusercontent.com/${contributor}`}
alt={`@${contributor}`}
className='hover:z-10'
/>
<AvatarFallback className='bg-[#2a2a2a] text-[#F6F6F6] text-[10px]'>
{contributor.slice(0, 2).toUpperCase()}
</AvatarFallback>
</Avatar>
</a>
))}
{entry.contributors.length > 5 && (
<div className='relative flex size-6 items-center justify-center rounded-full bg-[#2A2A2A] text-[10px] text-[#F6F6F6] ring-2 ring-[#1C1C1C] hover:z-10'>
+{entry.contributors.length - 5}
</div>
)}
</div>
)}
</div>
<div className={`${inter.className} shrink-0 text-[#F6F6F6]/50 text-xs`}>
{new Date(entry.date).toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
})}
</div>
</div>
<div className='prose prose-sm prose-invert max-w-none prose-a:text-brand-primary prose-a:no-underline hover:prose-a:underline'>
<ReactMarkdown components={markdownComponents}>
{cleanMarkdown(entry.content)}
</ReactMarkdown>
</div>
</div>
</React.Fragment>
)
}
if (variant === 'flat') {
return (
<React.Fragment key={entry.tag}>
{index > 0 && <DotSeparator />}
<div ref={setRef} data-entry-index={index} data-tag={entry.tag} className='py-8'>
<div className='mb-5 flex items-center justify-between gap-4'>
<div className='flex items-center gap-3'>
@@ -407,7 +327,7 @@ export default function ChangelogList({
href={entry.url}
target='_blank'
rel='noreferrer noopener'
className='group/tag font-season font-[600] text-[#fdfdf8] text-xl tracking-[-0.02em]'
className='group/tag font-[600] font-season text-[#fdfdf8] text-xl tracking-[-0.02em]'
>
<span className='relative'>
{entry.tag}
@@ -439,7 +359,75 @@ export default function ChangelogList({
</a>
))}
{entry.contributors.length > 5 && (
<div className='relative flex size-6 items-center justify-center rounded-full bg-[#2A2A2A] text-[10px] text-[#F6F6F6] ring-2 ring-[#1C1C1C] hover:z-10'>
<div className='relative flex size-6 items-center justify-center rounded-full bg-[#2A2A2A] text-[#F6F6F6] text-[10px] ring-2 ring-[#1C1C1C] hover:z-10'>
+{entry.contributors.length - 5}
</div>
)}
</div>
)}
</div>
<div className={`${inter.className} shrink-0 text-[#F6F6F6]/50 text-xs`}>
{new Date(entry.date).toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
})}
</div>
</div>
<div className='prose prose-sm prose-invert max-w-none prose-a:text-brand-primary prose-a:no-underline hover:prose-a:underline'>
<ReactMarkdown components={markdownComponents}>
{cleanMarkdown(entry.content)}
</ReactMarkdown>
</div>
</div>
</React.Fragment>
)
}
if (variant === 'flat') {
return (
<React.Fragment key={entry.tag}>
{index > 0 && <DotSeparator />}
<div ref={setRef} data-entry-index={index} data-tag={entry.tag} className='py-8'>
<div className='mb-5 flex items-center justify-between gap-4'>
<div className='flex items-center gap-3'>
<a
href={entry.url}
target='_blank'
rel='noreferrer noopener'
className='group/tag font-[600] font-season text-[#fdfdf8] text-xl tracking-[-0.02em]'
>
<span className='relative'>
{entry.tag}
<span className='absolute bottom-0 left-0 h-[1px] w-0 bg-[#fdfdf8] transition-[width] duration-200 group-hover/tag:w-full' />
</span>
</a>
{entry.contributors && entry.contributors.length > 0 && (
<div className='-space-x-2 flex'>
{entry.contributors.slice(0, 5).map((contributor) => (
<a
key={contributor}
href={`https://github.com/${contributor}`}
target='_blank'
rel='noreferrer noopener'
aria-label={`View @${contributor} on GitHub`}
title={`@${contributor}`}
className='block'
>
<Avatar className='size-6 ring-2 ring-[#1C1C1C]'>
<AvatarImage
src={`https://avatars.githubusercontent.com/${contributor}`}
alt={`@${contributor}`}
className='hover:z-10'
/>
<AvatarFallback className='bg-[#2a2a2a] text-[#F6F6F6] text-[10px]'>
{contributor.slice(0, 2).toUpperCase()}
</AvatarFallback>
</Avatar>
</a>
))}
{entry.contributors.length > 5 && (
<div className='relative flex size-6 items-center justify-center rounded-full bg-[#2A2A2A] text-[#F6F6F6] text-[10px] ring-2 ring-[#1C1C1C] hover:z-10'>
+{entry.contributors.length - 5}
</div>
)}
@@ -474,7 +462,7 @@ export default function ChangelogList({
>
{/* Card header with dot grid pattern */}
<div
className='relative flex items-center justify-between gap-4 border-b border-[#2a2a2a] px-5 py-4'
className='relative flex items-center justify-between gap-4 border-[#2a2a2a] border-b px-5 py-4'
style={dotGridStyle}
>
<div className='flex items-center gap-3'>
@@ -482,7 +470,7 @@ export default function ChangelogList({
href={entry.url}
target='_blank'
rel='noreferrer noopener'
className='group/tag font-season font-[600] text-[#fdfdf8] text-xl tracking-[-0.02em]'
className='group/tag font-[600] font-season text-[#fdfdf8] text-xl tracking-[-0.02em]'
>
<span className='relative'>
{entry.tag}
@@ -514,7 +502,7 @@ export default function ChangelogList({
</a>
))}
{entry.contributors.length > 5 && (
<div className='relative flex size-6 items-center justify-center rounded-full bg-[#2A2A2A] text-[10px] text-[#F6F6F6] ring-2 ring-[#1C1C1C] hover:z-10'>
<div className='relative flex size-6 items-center justify-center rounded-full bg-[#2A2A2A] text-[#F6F6F6] text-[10px] ring-2 ring-[#1C1C1C] hover:z-10'>
+{entry.contributors.length - 5}
</div>
)}
@@ -548,7 +536,7 @@ export default function ChangelogList({
type='button'
onClick={handleShowMore}
disabled={loading}
className='rounded-[5px] border border-[#2A2A2A] bg-[rgba(246,246,240,0.06)] px-3 py-1.5 text-[13px] text-[#F6F6F6] hover:bg-[rgba(246,246,240,0.1)] disabled:opacity-60'
className='rounded-[5px] border border-[#2A2A2A] bg-[rgba(246,246,240,0.06)] px-3 py-1.5 text-[#F6F6F6] text-[13px] hover:bg-[rgba(246,246,240,0.1)] disabled:opacity-60'
>
{loading ? 'Loading…' : 'Show more'}
</button>

View File

@@ -16,19 +16,23 @@ export function Breaks({ entries }: BreaksProps) {
const [loadedEntries, setLoadedEntries] = useState<ChangelogEntry[]>(entries)
const [activeTag, setActiveTag] = useState<string | null>(entries[0]?.tag ?? null)
const heatmapRef = useRef<CommitHeatmapHandle>(null)
const entriesRef = useRef(loadedEntries)
entriesRef.current = loadedEntries
const handleActiveEntryChange = useCallback((tag: string | null) => {
setActiveTag(tag)
if (tag) {
const entry = entriesRef.current.find((e) => e.tag === tag)
if (entry) {
heatmapRef.current?.setActiveDate(entry.date.split('T')[0])
}
}
}, [])
const handleEntriesChange = useCallback((nextEntries: ChangelogEntry[]) => {
setLoadedEntries(nextEntries)
}, [])
const handleProgressChange = useCallback((p: number) => {
heatmapRef.current?.setProgress(p)
}, [])
return (
<div className='min-h-screen bg-[#1C1C1C]'>
<div id='changelog-grid' className='relative grid md:grid-cols-2'>
@@ -57,10 +61,10 @@ export function Breaks({ entries }: BreaksProps) {
</div>
<div className='relative z-10 mx-auto h-full max-w-xl md:flex md:flex-col md:justify-center'>
<h1 className='mt-6 font-season font-[430] text-4xl text-white tracking-[-0.02em] sm:text-5xl'>
<h1 className='mt-6 font-[430] font-season text-4xl text-white tracking-[-0.02em] sm:text-5xl'>
Changelog
</h1>
<p className='mt-3 font-season font-[430] text-[#F6F6F0]/50 text-[14px] leading-[125%] tracking-[0.02em] sm:text-[16px]'>
<p className='mt-3 font-[430] font-season text-[#F6F6F0]/50 text-[14px] leading-[125%] tracking-[0.02em] sm:text-[16px]'>
Stay up-to-date with the latest features, improvements, and bug fixes in Sim. All
changes are documented here with detailed release notes.
</p>
@@ -70,28 +74,32 @@ export function Breaks({ entries }: BreaksProps) {
href='https://github.com/simstudioai/sim/releases'
target='_blank'
rel='noopener noreferrer'
className='inline-flex h-[32px] items-center gap-[6px] rounded-[5px] border border-[#33C482] bg-[#33C482] px-[10px] font-season font-[430] text-[14px] text-black transition-[filter] hover:brightness-110'
className='inline-flex h-[32px] items-center gap-[6px] rounded-[5px] border border-[#33C482] bg-[#33C482] px-[10px] font-[430] font-season text-[14px] text-black transition-[filter] hover:brightness-110'
>
<Github className='h-4 w-4' />
View on GitHub
</Link>
<Link
href='https://docs.sim.ai'
className='inline-flex h-[32px] items-center gap-[6px] rounded-[5px] border border-[#2A2A2A] bg-[rgba(246,246,240,0.06)] px-[10px] font-season font-[430] text-[14px] text-[#F6F6F6] transition-all hover:bg-[rgba(246,246,240,0.1)]'
className='inline-flex h-[32px] items-center gap-[6px] rounded-[5px] border border-[#2A2A2A] bg-[rgba(246,246,240,0.06)] px-[10px] font-[430] font-season text-[#F6F6F6] text-[14px] transition-all hover:bg-[rgba(246,246,240,0.1)]'
>
<BookOpen className='h-4 w-4' />
Documentation
</Link>
<Link
href='/changelog.xml'
className='inline-flex h-[32px] items-center gap-[6px] rounded-[5px] border border-[#2A2A2A] bg-[rgba(246,246,240,0.06)] px-[10px] font-season font-[430] text-[14px] text-[#F6F6F6] transition-all hover:bg-[rgba(246,246,240,0.1)]'
className='inline-flex h-[32px] items-center gap-[6px] rounded-[5px] border border-[#2A2A2A] bg-[rgba(246,246,240,0.06)] px-[10px] font-[430] font-season text-[#F6F6F6] text-[14px] transition-all hover:bg-[rgba(246,246,240,0.1)]'
>
<Rss className='h-4 w-4' />
RSS Feed
</Link>
</div>
<CommitHeatmap ref={heatmapRef} entries={loadedEntries} />
<CommitHeatmap
ref={heatmapRef}
entries={loadedEntries}
activeDate={entries[0]?.date.split('T')[0]}
/>
</div>
</div>
@@ -104,7 +112,6 @@ export function Breaks({ entries }: BreaksProps) {
pageSize={10}
onEntriesChange={handleEntriesChange}
onActiveEntryChange={handleActiveEntryChange}
onProgressChange={handleProgressChange}
/>
</div>
</div>

View File

@@ -40,10 +40,10 @@ export function Scroll({ entries }: ScrollProps) {
<ChangelogBlocks mode='scroll' />
<div className='relative z-10 mx-auto h-full max-w-xl md:flex md:flex-col md:justify-center'>
<h1 className='mt-6 font-season font-[430] text-4xl text-white tracking-[-0.02em] sm:text-5xl'>
<h1 className='mt-6 font-[430] font-season text-4xl text-white tracking-[-0.02em] sm:text-5xl'>
Changelog
</h1>
<p className='mt-3 font-season font-[430] text-[#F6F6F0]/50 text-[14px] leading-[125%] tracking-[0.02em] sm:text-[16px]'>
<p className='mt-3 font-[430] font-season text-[#F6F6F0]/50 text-[14px] leading-[125%] tracking-[0.02em] sm:text-[16px]'>
Stay up-to-date with the latest features, improvements, and bug fixes in Sim. All
changes are documented here with detailed release notes.
</p>
@@ -53,21 +53,21 @@ export function Scroll({ entries }: ScrollProps) {
href='https://github.com/simstudioai/sim/releases'
target='_blank'
rel='noopener noreferrer'
className='inline-flex h-[32px] items-center gap-[6px] rounded-[5px] border border-[#33C482] bg-[#33C482] px-[10px] font-season font-[430] text-[14px] text-black transition-[filter] hover:brightness-110'
className='inline-flex h-[32px] items-center gap-[6px] rounded-[5px] border border-[#33C482] bg-[#33C482] px-[10px] font-[430] font-season text-[14px] text-black transition-[filter] hover:brightness-110'
>
<Github className='h-4 w-4' />
View on GitHub
</Link>
<Link
href='https://docs.sim.ai'
className='inline-flex h-[32px] items-center gap-[6px] rounded-[5px] border border-[#2A2A2A] bg-[rgba(246,246,240,0.06)] px-[10px] font-season font-[430] text-[14px] text-[#F6F6F6] transition-all hover:bg-[rgba(246,246,240,0.1)]'
className='inline-flex h-[32px] items-center gap-[6px] rounded-[5px] border border-[#2A2A2A] bg-[rgba(246,246,240,0.06)] px-[10px] font-[430] font-season text-[#F6F6F6] text-[14px] transition-all hover:bg-[rgba(246,246,240,0.1)]'
>
<BookOpen className='h-4 w-4' />
Documentation
</Link>
<Link
href='/changelog.xml'
className='inline-flex h-[32px] items-center gap-[6px] rounded-[5px] border border-[#2A2A2A] bg-[rgba(246,246,240,0.06)] px-[10px] font-season font-[430] text-[14px] text-[#F6F6F6] transition-all hover:bg-[rgba(246,246,240,0.1)]'
className='inline-flex h-[32px] items-center gap-[6px] rounded-[5px] border border-[#2A2A2A] bg-[rgba(246,246,240,0.06)] px-[10px] font-[430] font-season text-[#F6F6F6] text-[14px] transition-all hover:bg-[rgba(246,246,240,0.1)]'
>
<Rss className='h-4 w-4' />
RSS Feed

View File

@@ -1,6 +1,6 @@
import type { Metadata } from 'next'
import ChangelogContent from '@/app/changelog/components/changelog-content'
import type { ChangelogVariant } from '@/app/changelog/components/changelog-content'
import ChangelogContent from '@/app/changelog/components/changelog-content'
export const metadata: Metadata = {
title: 'Changelog',

View File

@@ -9,7 +9,7 @@ export function ContactButton({ href, children }: ContactButtonProps) {
href={href}
target='_blank'
rel='noopener noreferrer'
className='inline-flex items-center h-[32px] rounded-[5px] border gap-[8px] border-[#33C482] bg-[#33C482] px-[10px] font-[430] font-season text-[14px] !text-black !no-underline transition-[filter] hover:brightness-110'
className='!text-black !no-underline inline-flex h-[32px] items-center gap-[8px] rounded-[5px] border border-[#33C482] bg-[#33C482] px-[10px] font-[430] font-season text-[14px] transition-[filter] hover:brightness-110'
>
{children}
</a>