Skip to content

Commit 84f7c86

Browse files
feat: finessing
1 parent c0c4988 commit 84f7c86

File tree

15 files changed

+1124
-293
lines changed

15 files changed

+1124
-293
lines changed

apps/sim/app/(home)/components/landing-preview/landing-preview.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ export function LandingPreview() {
9696
/>
9797
</motion.div>
9898
<div className='flex min-w-0 flex-1 flex-col py-[8px] pr-[8px] pl-[8px] lg:pl-0'>
99-
<div className='flex flex-1 overflow-hidden rounded-[8px] border border-[#2c2c2c] bg-[#1b1b1b]'>
99+
<div className='flex flex-1 overflow-hidden rounded border border-[#2c2c2c] bg-[#1b1b1b]'>
100100
<div
101101
className={
102102
isWorkflowView
Lines changed: 5 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,15 @@
1-
import Image from 'next/image'
2-
import Link from 'next/link'
3-
import type { Author, BlogMeta } from '@/lib/blog/schema'
4-
import { formatDate } from '@/lib/core/utils/formatting'
51
import { TableOfContents } from '@/app/(landing)/blog/[slug]/table-of-contents'
6-
import { getTagColor } from '@/app/(landing)/blog/tag-colors'
72

83
interface ArticleSidebarProps {
9-
author: Author
10-
authors: Author[]
11-
headings: { text: string; id: string }[]
12-
related: BlogMeta[]
4+
headings: { text: string; id: string; level: number }[]
135
}
146

15-
export function ArticleSidebar({ author, authors, headings, related }: ArticleSidebarProps) {
16-
const displayAuthors = authors.length > 0 ? authors : [author]
7+
export function ArticleSidebar({ headings }: ArticleSidebarProps) {
8+
if (headings.length === 0) return null
179

1810
return (
19-
<aside className='w-full shrink-0 space-y-6 xl:sticky xl:top-[76px] xl:w-72'>
20-
{displayAuthors.map((a) => (
21-
<div
22-
key={a.id}
23-
className='flex items-start gap-4 border border-[#2A2A2A] bg-[#232323] p-5'
24-
style={{ borderRadius: '5px' }}
25-
>
26-
<div
27-
className='flex h-12 w-12 shrink-0 items-center justify-center overflow-hidden border border-[#2A2A2A] bg-[#1C1C1C] font-season text-lg text-[#2ABBF8]'
28-
style={{ borderRadius: '5px' }}
29-
>
30-
{a.avatarUrl ? (
31-
<Image
32-
src={a.avatarUrl}
33-
alt={a.name}
34-
width={48}
35-
height={48}
36-
className='h-full w-full object-cover'
37-
unoptimized
38-
/>
39-
) : (
40-
a.name.slice(0, 2).toUpperCase()
41-
)}
42-
</div>
43-
<div>
44-
<div className='mb-1 font-season text-[10px] uppercase tracking-widest text-[#FA4EDF]'>
45-
Author
46-
</div>
47-
<h3 className='font-[500] text-[#ECECEC]'>{a.name}</h3>
48-
{a.url && (
49-
<Link
50-
href={a.url}
51-
target='_blank'
52-
rel='noopener noreferrer'
53-
className='font-season text-[11px] text-[#999] transition-colors hover:text-[#ECECEC]'
54-
>
55-
{a.xHandle ? `@${a.xHandle}` : 'Profile'}
56-
</Link>
57-
)}
58-
</div>
59-
</div>
60-
))}
61-
{headings.length > 0 && (
62-
<div className='border border-[#2A2A2A] bg-[#232323] p-5' style={{ borderRadius: '5px' }}>
63-
<TableOfContents headings={headings} />
64-
</div>
65-
)}
66-
67-
{related.length > 0 && (
68-
<div className='border border-[#2A2A2A] bg-[#232323] p-5' style={{ borderRadius: '5px' }}>
69-
<div className='mb-4 flex items-center gap-2 pb-3 font-season text-[11px] uppercase tracking-widest text-[#ECECEC]'>
70-
<span className='inline-block h-1.5 w-1.5 bg-[#FFCC02]' aria-hidden='true' />
71-
Recent Logs
72-
</div>
73-
<div className='space-y-4'>
74-
{related.map((p) => {
75-
const color = getTagColor(p.tags[0]) || '#999'
76-
return (
77-
<Link key={p.slug} href={`/blog/${p.slug}`} className='group block'>
78-
<div
79-
className='mb-1 font-season text-[9px] uppercase tracking-widest'
80-
style={{ color }}
81-
>
82-
{p.tags[0] || 'Post'}
83-
</div>
84-
<h4 className='mb-1 text-[13px] font-[500] leading-tight text-[#ECECEC] transition-colors group-hover:text-[#FFCC02]'>
85-
{p.title}
86-
</h4>
87-
<div className='font-season text-[10px] text-[#666]'>
88-
{formatDate(new Date(p.date))}
89-
</div>
90-
</Link>
91-
)
92-
})}
93-
</div>
94-
</div>
95-
)}
11+
<aside className='hidden w-full shrink-0 xl:sticky xl:top-[76px] xl:block xl:w-72 xl:pt-16 mr-2'>
12+
<TableOfContents headings={headings} />
9613
</aside>
9714
)
9815
}

apps/sim/app/(landing)/blog/[slug]/page.tsx

Lines changed: 139 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import { ArrowLeft } from 'lucide-react'
22
import type { Metadata } from 'next'
3+
import Image from 'next/image'
34
import Link from 'next/link'
45
import { FAQ } from '@/lib/blog/faq'
56
import '@/app/(landing)/blog/[slug]/prose-studio.css'
67
import { getAllPostMeta, getPostBySlug, getRelatedPosts } from '@/lib/blog/registry'
8+
import type { Author, BlogMeta } from '@/lib/blog/schema'
79
import { buildArticleJsonLd, buildBreadcrumbJsonLd, buildPostMetadata } from '@/lib/blog/seo'
10+
import { formatDate } from '@/lib/core/utils/formatting'
811
import { getBaseUrl } from '@/lib/core/utils/urls'
912
import {
1013
AnimatedColorBlocks,
@@ -13,7 +16,7 @@ import {
1316
import { ArticleHeaderItem, ArticleHeaderMotion } from '@/app/(landing)/blog/[slug]/article-header'
1417
import { ArticleSidebar } from '@/app/(landing)/blog/[slug]/article-sidebar'
1518
import { ShareButtons } from '@/app/(landing)/blog/[slug]/share-button'
16-
import { getPrimaryCategory, getTagCategory } from '@/app/(landing)/blog/tag-colors'
19+
import { getPrimaryCategory, getTagCategory, getTagColor } from '@/app/(landing)/blog/tag-colors'
1720

1821
export async function generateStaticParams() {
1922
const posts = await getAllPostMeta()
@@ -53,8 +56,8 @@ export default async function Page({ params }: { params: Promise<{ slug: string
5356
dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumbLd) }}
5457
/>
5558

56-
<div className='mx-auto flex w-full max-w-[1400px] flex-col items-start gap-8 px-6 pb-24 pt-16 xl:flex-row'>
57-
<div className='max-w-4xl flex-grow xl:mx-auto'>
59+
<div className='mx-auto flex w-full max-w-[1500px] flex-col items-start gap-2 pb-24 pt-16 xl:flex-row'>
60+
<div className='max-w-5xl flex-grow mx-auto'>
5861
<Link
5962
href='/blog'
6063
className='group mb-8 inline-flex items-center gap-2 border border-[#2A2A2A] bg-[#232323] px-4 py-2 font-season text-[11px] uppercase tracking-widest text-[#999] transition-colors hover:text-[#ECECEC]'
@@ -66,30 +69,30 @@ export default async function Page({ params }: { params: Promise<{ slug: string
6669
/>
6770
All Posts
6871
</Link>
69-
<header className='relative mb-12 border-b border-[#2A2A2A] pb-8'>
70-
<div className='absolute right-0 top-0'>
71-
<AnimatedColorBlocks />
72-
<div className='absolute right-0 top-[12px]'>
73-
<AnimatedColorBlocksVertical />
74-
</div>
75-
</div>
72+
<header className='mb-12 border-b border-[#2A2A2A] pb-8'>
7673
<ArticleHeaderMotion>
77-
<ArticleHeaderItem className='mb-6 flex items-center gap-3'>
78-
<span
79-
className='inline-block h-3 w-3'
80-
style={{ backgroundColor: categoryColor }}
81-
aria-hidden='true'
82-
/>
83-
<div className='font-season text-[11px] uppercase tracking-widest text-[#999]'>
84-
<time dateTime={post.date} itemProp='datePublished'>
85-
{new Date(post.date).toLocaleDateString('en-US', {
86-
month: 'short',
87-
day: '2-digit',
88-
year: 'numeric',
89-
})}
90-
</time>
91-
{' // '}
92-
<span style={{ color: categoryColor }}>{category.label}</span>
74+
<ArticleHeaderItem className='mb-6 flex w-full flex-col gap-4 sm:flex-row sm:items-center sm:justify-between'>
75+
<div className='flex items-center gap-3'>
76+
<span
77+
className='inline-block h-3 w-3'
78+
style={{ backgroundColor: categoryColor }}
79+
aria-hidden='true'
80+
/>
81+
<div className='font-season text-[11px] uppercase tracking-widest text-[#999]'>
82+
<time dateTime={post.date} itemProp='datePublished'>
83+
{new Date(post.date).toLocaleDateString('en-US', {
84+
month: 'short',
85+
day: '2-digit',
86+
year: 'numeric',
87+
})}
88+
</time>
89+
{' // '}
90+
<span style={{ color: categoryColor }}>{category.label}</span>
91+
</div>
92+
</div>
93+
94+
<div className='shrink-0'>
95+
<ShareButtons url={shareUrl} title={post.title} />
9396
</div>
9497
</ArticleHeaderItem>
9598
<ArticleHeaderItem>
@@ -135,17 +138,15 @@ export default async function Page({ params }: { params: Promise<{ slug: string
135138
{post.faq && post.faq.length > 0 ? <FAQ items={post.faq} /> : null}
136139
</div>
137140
</div>
138-
<div className='mt-16 flex items-center justify-between border-t border-[#2A2A2A] pt-8'>
139-
<div className='font-season text-[11px] text-[#999]'>Share this entry:</div>
140-
<ShareButtons url={shareUrl} title={post.title} />
141-
</div>
141+
142+
{/* Authors */}
143+
<ArticleAuthors authors={displayAuthors} />
144+
145+
{/* Related articles */}
146+
{related.length > 0 && <RelatedArticles posts={related} />}
142147
</div>
143-
<ArticleSidebar
144-
author={post.author}
145-
authors={displayAuthors}
146-
headings={post.headings ?? []}
147-
related={related}
148-
/>
148+
149+
<ArticleSidebar headings={post.headings ?? []} />
149150
</div>
150151

151152
<meta itemProp='publisher' content='Sim' />
@@ -160,3 +161,105 @@ export default async function Page({ params }: { params: Promise<{ slug: string
160161
</article>
161162
)
162163
}
164+
165+
interface ArticleAuthorsProps {
166+
authors: Author[]
167+
}
168+
169+
function ArticleAuthors({ authors }: ArticleAuthorsProps) {
170+
return (
171+
<div className='mt-12'>
172+
<div className='mb-6 flex items-center gap-2 font-season text-[11px] uppercase tracking-widest text-[#666]'>
173+
<span className='inline-block h-2 w-2 bg-[#FA4EDF]' aria-hidden='true' />
174+
{authors.length > 1 ? 'Authors' : 'Written by'}
175+
</div>
176+
<div className='flex flex-wrap gap-6'>
177+
{authors.map((a) => (
178+
<div
179+
key={a.id}
180+
className='flex items-center gap-4 border border-[#2A2A2A] bg-[#232323] p-5'
181+
style={{ borderRadius: '2px' }}
182+
>
183+
<div
184+
className='flex h-12 w-12 shrink-0 items-center justify-center overflow-hidden border border-[#2A2A2A] bg-[#1C1C1C] font-season text-lg text-[#2ABBF8]'
185+
style={{ borderRadius: '2px' }}
186+
>
187+
{a.avatarUrl ? (
188+
<Image
189+
src={a.avatarUrl}
190+
alt={a.name}
191+
width={48}
192+
height={48}
193+
className='h-full w-full object-cover'
194+
unoptimized
195+
/>
196+
) : (
197+
a.name.slice(0, 2).toUpperCase()
198+
)}
199+
</div>
200+
<div>
201+
<h3 className='font-[500] text-[#ECECEC]'>{a.name}</h3>
202+
{a.url && (
203+
<Link
204+
href={a.url}
205+
target='_blank'
206+
rel='noopener noreferrer'
207+
className='font-season text-[11px] text-[#999] transition-colors hover:text-[#ECECEC]'
208+
>
209+
{a.xHandle ? `@${a.xHandle}` : 'Profile'}
210+
</Link>
211+
)}
212+
</div>
213+
</div>
214+
))}
215+
</div>
216+
</div>
217+
)
218+
}
219+
220+
interface RelatedArticlesProps {
221+
posts: BlogMeta[]
222+
}
223+
224+
function RelatedArticles({ posts }: RelatedArticlesProps) {
225+
return (
226+
<div className='mt-12 border-t border-[#2A2A2A] pt-8'>
227+
<div className='mb-6 flex items-center gap-2 font-season text-[11px] uppercase tracking-widest text-[#666]'>
228+
<span className='inline-block h-2 w-2 bg-[#FFCC02]' aria-hidden='true' />
229+
Related articles
230+
</div>
231+
<div className='grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3'>
232+
{posts.map((p) => {
233+
const color = getTagColor(p.tags[0]) || '#999'
234+
const cat = getPrimaryCategory(p.tags)
235+
return (
236+
<Link
237+
key={p.slug}
238+
href={`/blog/${p.slug}`}
239+
className='group flex flex-col border border-[#2A2A2A] bg-[#232323] p-5 transition-[border-color,background-color,transform] duration-200 ease-out [@media(hover:hover)]:hover:border-[#3d3d3d] [@media(hover:hover)]:hover:bg-[#282828] [@media(hover:hover)]:hover:-translate-y-0.5'
240+
style={{ borderRadius: '2px' }}
241+
>
242+
<div className='mb-3 flex items-center gap-3'>
243+
<span
244+
className='inline-block px-2 py-0.5 font-season text-[10px] font-bold uppercase tracking-wider text-black'
245+
style={{ backgroundColor: color }}
246+
>
247+
{cat.label}
248+
</span>
249+
</div>
250+
<h4 className='mb-2 text-[15px] font-[500] leading-tight text-[#ECECEC] transition-colors duration-150 [@media(hover:hover)]:group-hover:text-[#FFCC02]'>
251+
{p.title}
252+
</h4>
253+
<p className='mb-4 line-clamp-2 text-[13px] leading-relaxed text-[#999]'>
254+
{p.description}
255+
</p>
256+
<div className='mt-auto font-season text-[10px] text-[#666]'>
257+
{formatDate(new Date(p.date))}
258+
</div>
259+
</Link>
260+
)
261+
})}
262+
</div>
263+
</div>
264+
)
265+
}

apps/sim/app/(landing)/blog/[slug]/prose-studio.css

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,20 @@
11
.prose-studio h2 {
2-
display: flex;
3-
align-items: center;
42
border-bottom: 1px solid #2a2a2a;
53
padding-bottom: 1.5rem;
64
font-weight: 500;
7-
font-size: 1.5rem;
5+
font-size: 30px;
86
color: #ececec;
9-
margin-top: 1rem !important;
7+
margin-top: 3rem !important;
108
margin-bottom: 1.5rem;
119
letter-spacing: -0.025em;
1210
}
1311

14-
.prose-studio h2::before {
15-
content: "\25A0";
16-
color: #00f701;
17-
font-size: 0.6em;
18-
margin-right: 0.75rem;
19-
flex-shrink: 0;
20-
}
21-
2212
.prose-studio h3 {
2313
font-weight: 500;
24-
font-size: 1.25rem;
14+
font-size: 24px;
2515
color: #ececec;
26-
margin-top: 2rem;
27-
margin-bottom: 1rem;
16+
margin-top: 1.5rem;
17+
margin-bottom: 0.75rem;
2818
letter-spacing: -0.015em;
2919
}
3020

@@ -86,7 +76,7 @@
8676
margin: 2.5rem 0;
8777
background: #232323;
8878
border-left: 2px solid #fa4edf;
89-
border-radius: 0 5px 5px 0;
79+
border-radius: 0 2px 2px 0;
9080
font-style: italic;
9181
font-size: 1.125rem;
9282
color: #cccccc;
@@ -120,7 +110,7 @@
120110

121111
/* Images */
122112
.prose-studio img {
123-
border-radius: 5px;
113+
border-radius: 2px;
124114
border: 1px solid #2a2a2a;
125115
}
126116

0 commit comments

Comments
 (0)