From cb2d21783f7ff909ba45a5c69d998505210e76ec Mon Sep 17 00:00:00 2001 From: Avvrik Date: Mon, 25 Aug 2025 20:23:57 +0500 Subject: [PATCH] add twitter list --- app/early-stage/page.tsx | 71 +++++++++++++++++++++++++++++++++++----- next.config.js | 35 ++++++++++++++++++-- 2 files changed, 95 insertions(+), 11 deletions(-) diff --git a/app/early-stage/page.tsx b/app/early-stage/page.tsx index 68e71e7..2ddb340 100644 --- a/app/early-stage/page.tsx +++ b/app/early-stage/page.tsx @@ -5,6 +5,7 @@ import matter from 'gray-matter' import { marked } from 'marked' import Link from 'next/link' import Image from 'next/image' +import Script from 'next/script' import { ArrowLeft, Github, ExternalLink, ChevronRight } from 'lucide-react' export const runtime = 'nodejs' @@ -59,7 +60,6 @@ const containsAny = (hay: string, items: string[]) => items.some((p) => contains function classify(meta: ResourceMeta): 'tooling' | 'courses' | 'guides' | 'code' | 'other' { const hay = haystack(meta) - // Tooling Docs (official docs, references, install guides, APIs, CLI) const toolingSignals = [ 'docs','documentation','reference','api reference','api docs', 'handbook','manual','spec','specification','readme','guide (cli)', @@ -68,23 +68,17 @@ function classify(meta: ResourceMeta): 'tooling' | 'courses' | 'guides' | 'code' 'hardhat','foundry','anvil','remix','metamask','phantom', 'solana cli','anchor','etherscan','solscan','node.js','npm','nvm', ] - - // Courses (programs, bootcamps, MOOCs) const courseSignals = [ 'course','courses','bootcamp','curriculum','syllabus','academy', 'track','learning path','program','cohort','mooc','udemy','coursera','edx', 'university','certificate' ] - - // Code Samples (templates, starters, examples, scaffolds) const codeSignals = [ 'example','examples','sample','samples','snippet','snippets', 'template','templates','boilerplate','boilerplates','starter','starter kit', 'scaffold','scaffolding','reference implementation','repo','github repository', 'playground' ] - - // Guides (how-tos, tutorials, deep dives, best practices, articles) const guideSignals = [ 'guide','how to','how-to','tutorial','walkthrough','step by step','step-by-step', 'deep dive','best practices','explained','overview','article','blog','cookbook', @@ -143,7 +137,6 @@ async function getEarlyResources(): Promise<(ResourceMeta & { key: string; secti }) } - // newest first list.sort((a, b) => (new Date(b.dateAdded || 0).getTime()) - (new Date(a.dateAdded || 0).getTime())) return list } @@ -201,6 +194,8 @@ export default async function EarlyStagePage() { ) : null + const listUrl = 'https://twitter.com/i/lists/1959973436228288972' + return (
{/* Contained Banner */} @@ -250,6 +245,66 @@ export default async function EarlyStagePage() {
{other.length ?
: null} +
+

+ Selected voices to boost your dev learning on X +

+ +
+
+ Curated builders & educators worth following{' '} + + (open on X) + . +
+ + {/* Programmatic timeline container */} +
+ + {/* Hidden fallback hint */} +
+ If you see “Nothing to see here”, enable third-party cookies or disable tracker blockers + for this site, then refresh. You can also open the list directly on X. +
+
+ + {/* Load widgets.js */} + +
+ + {/* CTA */}

Share Your Knowledge

diff --git a/next.config.js b/next.config.js index 926da33..145406f 100644 --- a/next.config.js +++ b/next.config.js @@ -3,10 +3,39 @@ const nextConfig = { experimental: { appDir: true, }, + + // Add CSP headers so the X/Twitter list embed can load + async headers() { + const csp = [ + "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://platform.twitter.com", + "style-src 'self' 'unsafe-inline'", + "img-src 'self' data: blob: https://cdn.syndication.twimg.com https://abs.twimg.com https://pbs.twimg.com", + "frame-src https://platform.twitter.com https://twitter.com https://syndication.twitter.com", + "connect-src 'self' https://cdn.syndication.twimg.com https://api.twitter.com", + "font-src 'self' data: https://abs.twimg.com", + ].join('; '); + + return [ + { + source: "/(.*)", + headers: [{ key: "Content-Security-Policy", value: csp }], + }, + ]; + }, + + + // Keep your existing image settings and add Twitter domains images: { - domains: ['images.unsplash.com', 'github.com'], + domains: [ + 'images.unsplash.com', + 'github.com', + // add Twitter image/CDN domains for any usage inside your UI + 'cdn.syndication.twimg.com', + 'abs.twimg.com', + 'pbs.twimg.com', + ], unoptimized: true, }, -} +}; -module.exports = nextConfig \ No newline at end of file +module.exports = nextConfig;