diff --git a/.changeset/pre.json b/.changeset/pre.json index 989fb8b..17c237a 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -1,6 +1,6 @@ { "mode": "pre", - "tag": "alpha", + "tag": "beta", "initialVersions": { "portfolio": "1.0.4" }, diff --git a/.changeset/release-1780454025.md b/.changeset/release-1780454025.md new file mode 100644 index 0000000..eaa1d9f --- /dev/null +++ b/.changeset/release-1780454025.md @@ -0,0 +1,14 @@ +--- +"portfolio": patch +--- + +- release: switch 1.0.4 from alpha to beta +- chore: remove old file of changeset +- chore(config): adjust allowed dev origins and remote patterns in next.config.ts +- feat(config): support explicit id fields for social link redirects +- chore(config): remove legacy redirects from next.config.ts +- chore(config): dynamically generate redirects for social links +- chore(portfolio): configure experiences, sponsors, social links, and tech stack +- ui(tech-stack): re-order entries and add linux, bash, and antigravity +- ui(tech-stack): fetch technology logos dynamically from GitHub repos +- ui(projects): fallback to github avatar for projects and update OG assets diff --git a/next.config.ts b/next.config.ts index c1154c3..2589f87 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,15 +1,22 @@ import type { NextConfig } from "next" +import { SOCIAL_LINKS } from "./src/data/portfolio/social-links" + const nextConfig: NextConfig = { reactStrictMode: true, transpilePackages: ["next-mdx-remote"], - allowedDevOrigins: ["ncdai.localhost", "ncdai.local"], + allowedDevOrigins: ["wistant.localhost", "wistant.local"], devIndicators: false, images: { remotePatterns: [ { protocol: "https", - hostname: "assets.chanhdai.com", + hostname: "github.com", + port: "", + }, + { + protocol: "https", + hostname: "avatars.githubusercontent.com", port: "", }, { @@ -29,53 +36,38 @@ const nextConfig: NextConfig = { } : undefined, async redirects() { - return [ - { - source: "/:section(blog|components)/writing-effect-inspired-by-apple", - destination: "/:section/apple-hello-effect", - permanent: true, - }, - { - source: "/:section(blog|components)/work-experience", - destination: "/:section/work-experience-component", - permanent: true, - }, - { - source: "/:section(blog|components)/theme-switcher-component", - destination: "/:section/theme-switcher", - permanent: true, - }, - { - source: "/wall-of-love", - destination: "/testimonials", - permanent: true, - }, - { - source: "/blocks/content", - destination: "/blocks/marketing", - permanent: true, - }, - { - source: "/blocks/content/blog-01", - destination: "/blocks/marketing/blog-01", - permanent: true, - }, - { - source: "/blocks/content/blog-02", - destination: "/blocks/marketing/blog-02", - permanent: true, - }, - { - source: "/blocks/content/experience-01", - destination: "/blocks/marketing/experience-01", - permanent: true, - }, - { - source: "/blocks/content/team-01", - destination: "/blocks/marketing/team-01", - permanent: true, - }, - ] + const socialRedirects = SOCIAL_LINKS.flatMap((link) => { + const primarySlug = + link.id || link.title.toLowerCase().replace(/[^a-z0-9]/g, "") + const aliases = [primarySlug] + if ( + primarySlug === "x" || + primarySlug === "twitter" || + primarySlug === "xtwitter" + ) { + if (!aliases.includes("x")) aliases.push("x") + if (!aliases.includes("twitter")) aliases.push("twitter") + } + if (primarySlug === "github" || primarySlug === "git") { + if (!aliases.includes("github")) aliases.push("github") + if (!aliases.includes("git")) aliases.push("git") + } + if (primarySlug === "telegram" || primarySlug === "tg") { + if (!aliases.includes("telegram")) aliases.push("telegram") + if (!aliases.includes("tg")) aliases.push("tg") + } + if (primarySlug === "bluesky" || primarySlug === "bsky") { + if (!aliases.includes("bluesky")) aliases.push("bluesky") + if (!aliases.includes("bsky")) aliases.push("bsky") + } + return aliases.map((alias) => ({ + source: `/${alias}`, + destination: link.href, + permanent: false, + })) + }) + + return socialRedirects }, async rewrites() { return [ diff --git a/src/app/(app)/components/experiences/index.tsx b/src/app/(app)/components/experiences/index.tsx index f22832b..ceaaccc 100644 --- a/src/app/(app)/components/experiences/index.tsx +++ b/src/app/(app)/components/experiences/index.tsx @@ -18,7 +18,7 @@ export function Experiences() { return ( - Work Experiences 🧿 + Work Experiences 💼
diff --git a/src/app/(app)/components/projects/project-item.tsx b/src/app/(app)/components/projects/project-item.tsx index 8dada09..2759820 100644 --- a/src/app/(app)/components/projects/project-item.tsx +++ b/src/app/(app)/components/projects/project-item.tsx @@ -1,6 +1,7 @@ import Image from "next/image" import Link from "next/link" import { getDocBySlug } from "@/data/doc/documents" +import { USER } from "@/data/portfolio/user" import { addQueryParams } from "@/utils/url" import { BoxIcon, InfinityIcon, LinkIcon } from "lucide-react" @@ -36,17 +37,19 @@ export function ProjectItem({ const isSinglePeriod = end === start const hasLocalPage = !!getDocBySlug(project.id) + const logoSrc = project.logo || USER.logo || USER.avatar + return (
- {project.logo ? ( + {logoSrc ? ( {project.title} diff --git a/src/app/(app)/components/sponsors.tsx b/src/app/(app)/components/sponsors.tsx new file mode 100644 index 0000000..112c366 --- /dev/null +++ b/src/app/(app)/components/sponsors.tsx @@ -0,0 +1,90 @@ +import Link from "next/link" +import { SPONSORS } from "@/data/sponsor-data" +import { addQueryParams } from "@/utils/url" +import { ArrowUpRightIcon, HeartIcon } from "lucide-react" + +import { SPONSORSHIP_URL, UTM_PARAMS } from "@/config/site" +import { Button } from "@/components/base/ui/button" + +import { + Panel, + PanelContent, + PanelHeader, + PanelTitle, + PanelTitleSup, +} from "./panel" + +export function Sponsors() { + const featuredSponsors = SPONSORS.slice(0, 6) + + return ( + + + + Sponsors 💖 + [{SPONSORS.length}] + + + + +

+ Grateful to the partners and individuals supporting this open-source + work. You can sponsor my projects by choosing a tier (Platinum, Gold, + Silver, or Spark Supporter) directly on GitHub. +

+ + {featuredSponsors.length > 0 && ( +
+
+
+
+
+
+ +
    + {featuredSponsors.map((item) => ( +
  • + + + +
  • + ))} +
+
+ )} + +
+ + + +
+ + + ) +} diff --git a/src/app/(app)/components/tech-stack.tsx b/src/app/(app)/components/tech-stack.tsx index 6fff691..8dd87d0 100644 --- a/src/app/(app)/components/tech-stack.tsx +++ b/src/app/(app)/components/tech-stack.tsx @@ -20,6 +20,9 @@ export function TechStack() {