Standard.site landing page built in Next.js
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fix ClickableHeading types and add UTM params to LinkCard

+23 -16
+2 -2
app/components/docs/ClickableHeading.tsx
··· 25 25 setTimeout(() => setCopied(false), 2000) 26 26 } 27 27 28 - const Tag = `h${level}` as keyof JSX.IntrinsicElements 28 + const Tag = `h${level}` as keyof React.JSX.IntrinsicElements 29 29 30 30 const baseClasses = "font-display font-semibold leading-tight tracking-tighter text-base-content group cursor-pointer hover:text-muted transition-colors relative scroll-mt-32" 31 31 const levelClasses = { ··· 64 64 if (typeof node === 'number') return String(node) 65 65 if (Array.isArray(node)) return node.map(extractText).join('') 66 66 if (node && typeof node === 'object' && 'props' in node) { 67 - return extractText(node.props.children) 67 + return extractText((node as { props: { children: React.ReactNode } }).props.children) 68 68 } 69 69 return '' 70 70 }
+21 -14
app/components/docs/LinkCard.tsx
··· 59 59 } 60 60 61 61 export async function LinkCard({ title, description, url, image }: LinkCardProps) { 62 - const hostname = new URL(url).hostname.replace('www.', '') 62 + const urlObj = new URL(url) 63 + const hostname = urlObj.hostname.replace('www.', '') 63 64 64 65 // Fetch OG metadata if not provided 65 66 const metadata = await fetchOGMetadata(url) ··· 68 69 const finalDescription = description || metadata?.description || '' 69 70 const finalImage = image || metadata?.image 70 71 72 + urlObj.searchParams.set('utm_source', 'standard.site') 73 + urlObj.searchParams.set('utm_medium', 'docs') 74 + urlObj.searchParams.set('utm_campaign', 'implementations') 75 + 71 76 return ( 72 77 <a 73 - href={url} 78 + href={urlObj.toString()} 74 79 target="_blank" 75 80 rel="noopener noreferrer" 76 - className="group flex gap-4 rounded-2xl border border-border bg-gradient-to-br from-base-200/50 to-base-200 p-4 transition-all hover:border-border/60 hover:shadow-lg not-prose mb-4" 81 + className="group flex rounded-2xl border border-border bg-linear-to-br from-base-200/50 to-base-200 transition-all hover:border-border/60 hover:shadow-lg not-prose mb-4" 77 82 > 78 - <div className="flex min-w-0 flex-1 flex-col gap-2"> 79 - <h3 className="font-mono text-lg font-medium tracking-tight text-base-content group-hover:underline"> 80 - {finalTitle} 81 - </h3> 82 - {finalDescription && ( 83 - <p className="text-sm leading-relaxed tracking-tight text-muted-content"> 84 - {finalDescription} 85 - </p> 86 - )} 87 - <div className="mt-auto text-xs font-medium text-muted-content"> 83 + <div className="flex min-w-0 flex-1 flex-col gap-2 px-3 py-2"> 84 + <hgroup className="flex flex-col gap-0"> 85 + <h3 className="font-bold tracking-tight text-base-content group-hover:underline line-clamp-2"> 86 + {finalTitle} 87 + </h3> 88 + {finalDescription && ( 89 + <p className="text-sm tracking-tight text-muted-content line-clamp-2"> 90 + {finalDescription} 91 + </p> 92 + )} 93 + </hgroup> 94 + <div className="mt-auto text-xs @md/content:pt-2 @md/content:border-t border-base-300/50 font-medium text-muted-content"> 88 95 <span className="font-mono">{hostname}</span> 89 96 </div> 90 97 </div> 91 98 {finalImage && ( 92 99 <div className="shrink-0"> 93 - <div className="h-24 w-40 overflow-hidden rounded-xl bg-base-100"> 100 + <div className="size-26 @md/content:h-29 @md/content:aspect-[1.91/1] @md/content:w-auto overflow-hidden rounded-r-2xl bg-base-100"> 94 101 <img 95 102 src={finalImage} 96 103 alt={finalTitle}