diff --git a/public/experiences/devia.jpg b/public/experiences/devia.jpg new file mode 100644 index 0000000..52b1c82 Binary files /dev/null and b/public/experiences/devia.jpg differ diff --git a/public/experiences/unity-link.jpg b/public/experiences/unity-link.jpg new file mode 100644 index 0000000..f132f1f Binary files /dev/null and b/public/experiences/unity-link.jpg differ diff --git a/public/gallery/1.jpg b/public/gallery/1.jpg new file mode 100644 index 0000000..adbe248 Binary files /dev/null and b/public/gallery/1.jpg differ diff --git a/public/gallery/2.webp b/public/gallery/2.webp new file mode 100644 index 0000000..e89b474 Binary files /dev/null and b/public/gallery/2.webp differ diff --git a/public/gallery/3.JPG b/public/gallery/3.JPG new file mode 100644 index 0000000..258a34f Binary files /dev/null and b/public/gallery/3.JPG differ diff --git a/public/gallery/5.webp b/public/gallery/5.webp new file mode 100644 index 0000000..fc06f8a Binary files /dev/null and b/public/gallery/5.webp differ diff --git a/public/gallery/6.jpg b/public/gallery/6.jpg new file mode 100644 index 0000000..1d879d0 Binary files /dev/null and b/public/gallery/6.jpg differ diff --git a/public/gallery/7.jpg b/public/gallery/7.jpg new file mode 100644 index 0000000..5fbf7f1 Binary files /dev/null and b/public/gallery/7.jpg differ diff --git a/public/gallery/8.JPG b/public/gallery/8.JPG new file mode 100644 index 0000000..1911f34 Binary files /dev/null and b/public/gallery/8.JPG differ diff --git a/public/gallery/9.jpg b/public/gallery/9.jpg new file mode 100755 index 0000000..62230a8 Binary files /dev/null and b/public/gallery/9.jpg differ diff --git a/public/preview-light.png b/public/preview-light.png index 4c33657..ecc05fa 100644 Binary files a/public/preview-light.png and b/public/preview-light.png differ diff --git a/src/app/(app)/components/overview/index.tsx b/src/app/(app)/components/overview/index.tsx index 2276f93..f8ad8c0 100644 --- a/src/app/(app)/components/overview/index.tsx +++ b/src/app/(app)/components/overview/index.tsx @@ -1,26 +1,7 @@ import { USER } from "@/data/portfolio/user" -import { urlToName } from "@/utils/url" -import { - LinkIcon, - MapPinIcon, - MarsIcon, - NonBinaryIcon, - VenusIcon, -} from "lucide-react" - -import type { User } from "@/types/user" import { Panel, PanelContent } from "../panel" -import { CurrentLocalTimeItem } from "./current-local-time-item" -import { EmailItem } from "./email-item" -import { - IntroItem, - IntroItemContent, - IntroItemIcon, - IntroItemLink, -} from "./intro-item" import { JobItem } from "./job-item" -import { PhoneItem } from "./phone-item" export function Overview() { return ( @@ -37,61 +18,7 @@ export function Overview() { /> ) })} - -
- - - - - - - {USER.address} - - - - - - - - - - - - - - - - - {urlToName(USER.website)} - - - - - - {getGenderIcon(USER.gender)} - - {USER.pronouns} - - -
) } - -function getGenderIcon(gender: User["gender"]) { - switch (gender) { - case "male": - return - case "female": - return - case "non-binary": - return - } -} diff --git a/src/app/(app)/components/profile-cover.tsx b/src/app/(app)/components/profile-cover.tsx index 3c0832e..b57d905 100644 --- a/src/app/(app)/components/profile-cover.tsx +++ b/src/app/(app)/components/profile-cover.tsx @@ -5,8 +5,6 @@ import { useTheme } from "next-themes" import { cn } from "@/lib/utils" import { DotGridSpotlight } from "@/components/dot-grid-spotlight" -import { Magnet } from "@/components/react-bits/magnet" -import { WistantMark } from "@/components/wistant-mark" const DOT_COLOR = { light: { @@ -31,7 +29,7 @@ export function ProfileCover() { className={cn( "relative flex aspect-2.5/1 items-center justify-center border-x border-line select-none sm:aspect-3.5/1", "screen-line-top screen-line-bottom before:-top-px after:-bottom-px", - "bg-black/0.75 dark:bg-white/1" + "overflow-hidden bg-black/0.75 dark:bg-white/1" )} > - - - + {/* Creative Cyber-Premium Badges in the corners */} +
+ + + + + SYS_OP // ACTIVE_NODE_0x7E4 +
+ +
+ wistant.me // dev_env_v4.2 +
) } diff --git a/src/app/(app)/components/profile-header.tsx b/src/app/(app)/components/profile-header.tsx index ef26564..c7c2c8a 100644 --- a/src/app/(app)/components/profile-header.tsx +++ b/src/app/(app)/components/profile-header.tsx @@ -1,58 +1,150 @@ +"use client" + import { USER } from "@/data/portfolio/user" +import { urlToName } from "@/utils/url" +import { + LinkIcon, + MapPinIcon, + MarsIcon, + NonBinaryIcon, + VenusIcon, +} from "lucide-react" +import type { User } from "@/types/user" import { AvatarLights } from "@/components/avatar-lights" +import { Button } from "@/components/base/ui/button" import { AvatarLightsToggle } from "./avatar-lights-toggle" import { FlipSentences } from "./flip-sentences" +// Import interactive metadata items from Overview +import { CurrentLocalTimeItem } from "./overview/current-local-time-item" +import { EmailItem } from "./overview/email-item" +import { PhoneItem } from "./overview/phone-item" import { PronounceMyName } from "./pronounce-my-name" import { VerifiedIcon } from "./verified-icon" +function getGenderIcon(gender: User["gender"]) { + switch (gender) { + case "male": + return + case "female": + return + case "non-binary": + return ( + + ) + } +} + export function ProfileHeader() { return ( -
-
- +
+ {/* Left side: Avatar Profile */} +
+
-
-
-
- {"text-3xl "} - API - UI - {" font-medium"} + {/* Right side: details */} +
+ {/* Row: Name, Gold Badge, Handle, and Contact Actions */} +
+
+
+

+ {USER.displayName} +

+ +
+
+ @{USER.username} +
-
- -
-
-

- {USER.displayName} -

- - + {/* Contact Button & Name Pronunciation (Hidden on mobile) */} +
{USER.namePronunciationUrl && ( )} + +
+
- - {USER.flipSentences} - + {/* Metadata List */} +
+ {/* Location */} + + + {/* Website */} + + + {/* Pronouns */} +
+
+ {getGenderIcon(USER.gender)} +
+ {USER.pronouns} +
+ + {/* Current Local Time */} + + + {/* Phone */} + + + {/* Email */} + + + {/* Scrolling posts/sentences (FlipSentences) placed right after the email inside the metadata list box */} +
+
+ +
+ + {USER.flipSentences} + +
diff --git a/src/app/(app)/components/social-links/social-link-item.tsx b/src/app/(app)/components/social-links/social-link-item.tsx index 1cbd500..23b7fe6 100644 --- a/src/app/(app)/components/social-links/social-link-item.tsx +++ b/src/app/(app)/components/social-links/social-link-item.tsx @@ -7,6 +7,8 @@ import { UTM_PARAMS } from "@/config/site" import { cn } from "@/lib/utils" export function SocialLinkItem({ icon, title, href }: SocialLink) { + const isInvertible = title === "X" || title === "GitHub" + return (
{title}*/}
- - diff --git a/src/components/avatar-lights.tsx b/src/components/avatar-lights.tsx index b909bbe..f2be492 100644 --- a/src/components/avatar-lights.tsx +++ b/src/components/avatar-lights.tsx @@ -10,14 +10,20 @@ export type AvatarLightsVariants = { export function AvatarLights({ className, variants, + shape = "circle", ...props }: Omit, "children"> & { variants: AvatarLightsVariants + shape?: "circle" | "square" }) { + const roundedClass = + shape === "square" ? "rounded-2xl sm:rounded-[18%]" : "rounded-full" + return (
@@ -35,6 +42,7 @@ export function AvatarLights({ src={variants.lightOn} alt="Avatar with lights on in light mode" fetchPriority="high" + shape={shape} /> @@ -43,6 +51,7 @@ export function AvatarLights({ src={variants.darkOff} alt="Avatar with lights off in dark mode" fetchPriority="high" + shape={shape} /> @@ -51,11 +60,15 @@ export function AvatarLights({ src={variants.darkOn} alt="Avatar with lights on in dark mode" fetchPriority="high" + shape={shape} />
@@ -78,12 +91,16 @@ function AvatarImage({ className, src, alt, + shape = "circle", ...props -}: React.ComponentProps<"img">) { +}: React.ComponentProps<"img"> & { shape?: "circle" | "square" }) { + const roundedClass = + shape === "square" ? "rounded-2xl sm:rounded-[18%]" : "rounded-full" return ( , - description: - "- Work on the registry and React component library.\n- Design and build Pro application components and blocks, from Figma to production-ready React.", + employmentType: "Internship", + icon: , + description: `- Engineered high-performance, robust REST and GraphQL APIs using NestJS and TypeScript. +- Adhered strictly to SOLID principles, design patterns (Factory, Dependency Injection, Repository, and Singleton), and clean modular architectures. +- Designed scalable database architectures, optimized complex SQL queries, and handled migrations and schema designs using Prisma and TypeORM. +- Engineered sleek, dynamic, and responsive front-end dashboard panels and server-side rendered pages using Next.js.`, skills: [ "TypeScript", + "NestJS", "Next.js", - "Tailwind CSS", - "shadcn/registry", - "Figma", + "SQL", + "Prisma", + "TypeORM", + "SOLID Principles", + "Design Patterns", + "REST APIs", + "GraphQL", ], isExpanded: true, }, ], - isCurrentEmployer: true, - }, - { - id: "quaric", - companyName: "Quaric", - companyLogo: "https://assets.chanhdai.com/images/companies/quaric.svg", - companyWebsite: "https://quaric.com", - positions: [ - { - id: "2", - title: "Design Engineer", - employmentPeriod: { - start: "03.2024", - }, - employmentType: "Part-time", - icon: , - description: `- Created Quaric Brand Identity. -- Created the Quaric Design System to standardize design practices and accelerate development. - -In-house Project: [Quaric Website](https://quaric.com) -- Designed the UI/UX for Quaric Website, delivering a seamless experience. -- Developed online ordering to streamline purchases. -- Integrated VNPAY-QR for secure transactions. -- Registered the e-commerce site with [online.gov.vn](http://online.gov.vn/website/chi-tiet-115855) for compliance. - -In-house Project: [ZaDark](https://zadark.com) -- Build and maintain ZaDark.com with Docusaurus, integrating AdSense. -- Develop and maintain the ZaDark extension for Zalo Web on Chrome, Safari, Edge, and Firefox — with 20k+ active users via Chrome Web Store (as of Sep 2025).`, - skills: [ - "Next.js", - "Strapi", - "Auth0", - "VNPAY-QR", - "Docker", - "NGINX", - "Google Cloud", - "Docusaurus", - "Extension", - "UI/UX Design", - "UX Writing", - "Design System", - "Brand Design", - "Figma", - "Research", - ], - }, - { - id: "1", - title: "Founder", - employmentPeriod: { - start: "03.2024", - }, - employmentType: "Part-time", - icon: , - skills: ["Business Ownership", "Business Law", "Business Tax"], - }, - ], - isCurrentEmployer: true, }, { - id: "simplamo", - companyName: "Simplamo", - companyLogo: "https://assets.chanhdai.com/images/companies/simplamo.webp", + id: "devia-technologies", + companyName: "Devia Technologies", + companyLogo: "/experiences/devia.jpg", positions: [ - { - id: "2", - title: "Senior Frontend Developer", - employmentPeriod: { - start: "10.2022", - end: "01.2026", - }, - employmentType: "Full-time", - icon: , - description: `- Built Tree & Gantt views features to improve goal organization, visibility, and progress tracking. -- Developed [AI Chat](https://help.simplamo.com/features/simplamo-ai/ai-chat/guide_simplamo_ai_chat?ref=IN-926722) and [AI Assistant](https://help.simplamo.com/features/simplamo-ai/ai-expert/aiexpert-rockdiscribe?ref=IN-926722) features. -- Developed [Whiteboards](https://help.simplamo.com/features/whiteboard/overview?ref=IN-926722) with real-time collaboration. -- Built and maintained the [Zalo Mini App](https://zalo.me/s/1736112917405511258/) for Simplamo with seamless integration. -- Developed interactive chart and analytics widgets for the [Dashboard](https://help.simplamo.com/features/dashboard/overview) to enhance data visualization. -- Developed and maintained core features to enhance functionality and user experience. -- Ensured UI/UX consistency and adherence to standards. -- Implemented robust frontend solutions for web and mobile platforms. -- Analyzed technical capabilities and provided optimal solutions.`, - skills: [ - "TypeScript", - "Next.js", - "React Native", - "MobX", - "MobX-State-Tree", - "Tailwind CSS", - "Dify", - "Zalo Mini App", - "Agile", - "Teamwork", - "Research", - "Problem-solving", - ], - }, - { - id: "1", - title: "UI Lead", - employmentPeriod: { - start: "10.2022", - end: "01.2026", - }, - employmentType: "Full-time", - icon: , - description: `- Ensured UI/UX consistency and high-quality standards. -- Designed intuitive, user-focused interfaces aligned with business goals. -- Defined and established a cohesive UI style for Simplamo.`, - skills: ["Creativity", "UI/UX Design", "Figma"], - }, - ], - }, - { - id: "tungtung", - companyName: "Tung Tung", - companyLogo: "https://assets.chanhdai.com/images/companies/tungtung.webp", - positions: [ - { - id: "3", - title: "Web Developer", - employmentPeriod: { - start: "2020", - end: "2022", - }, - employmentType: "Full-time", - description: `- Built a scalable design system for consistency and efficiency. -- Built a complex rich-text editor based on ProseMirror and Slate for customizable content creation. -- Integrated APIs with the Backend Team to enhance functionality.`, - icon: , - skills: [ - "React", - "Redux", - "Storybook", - "Lerna", - "Agile", - "Teamwork", - "Research", - ], - }, - { - id: "2", - title: "Mobile Developer", - employmentPeriod: { - start: "2019", - end: "2020", - }, - employmentType: "Full-time", - description: `- Rebuilt the app with React Native for better UX and performance. -- Integrated MoMo and in-app purchases for seamless payments. -- Optimized deployment for staging and production. -- Published on App Store and Google Play, ensuring compliance.`, - icon: , - skills: [ - "React Native", - "Redux", - "MoMo Payment API", - "App Store", - "Google Play Store", - "App Center", - "Agile", - "Teamwork", - "Research", - ], - }, { id: "1", - title: "UI/UX Designer", + title: "Front-End & API Developer", employmentPeriod: { - start: "2018", - end: "2019", + start: "05.2024", + end: "12.2025", }, employmentType: "Full-time", - description: `- Designed a Landing Page for enterprise clients. -- Redesigned the Online Quiz Platform for a modern look on web and mobile. -- Redesigned the Pricing interface for individual customers. -- Enhanced UX by improving usability, navigation, and user flow.`, - icon: , - skills: ["UI/UX Design", "Sketch"], - }, - ], - }, - { - id: "freelance", - companyName: "Freelance", - companyIcon: , - positions: [ - { - id: "2", - title: "Full-stack Developer", - employmentPeriod: { - start: "2018", - end: "2020", - }, - employmentType: "Part-time", - description: `- Built an order management website with real-time delivery tracking. -- Developed an e-commerce site for bird’s nest products. -- Created a map to display monitoring station data. -- Designed a customizable WordPress landing page.`, icon: , + description: `- Developed highly interactive, responsive, and cross-browser compatible user interfaces using HTML/CSS and vanilla JavaScript. +- Deployed dynamic front-end scripts, optimized page rendering speed, and handled complex DOM manipulation and state management. +- Architected and built lightweight, fast, and scalable REST APIs using raw (brut) Node.js and Express without heavy external framework abstractions. +- Integrated third-party APIs and orchestrated seamless client-server data flows.`, skills: [ - "Laravel", - "React", - "Express.js", - "Socket.IO", - "MongoDB", - "Firebase", - "WordPress", - "Docker", - "NGINX", - ], - }, - { - id: "1", - title: "Graphic & UI/UX Designer", - employmentPeriod: { - start: "2018", - end: "2019", - }, - employmentType: "Part-time", - description: "Designed logos, posters, ads, and UI.", - icon: , - skills: [ - "Creativity", - "UI/UX Design", - "Graphic Design", - "Sketch", - "Adobe Photoshop", - "Adobe Illustrator", - ], - }, - ], - }, - { - id: "education", - companyName: "Education", - companyIcon: , - positions: [ - { - id: "3", - title: "University of Science — VNUHCM", - employmentPeriod: { - start: "08.2018", - end: "10.2026", - }, - icon: , - description: `- Currently studying for a Bachelor’s degree in Information Systems. -- Language Proficiency: B1 level in English (CEFR). -- Achieved several awards, including: - - Bronze Medal — 10th Design, Manufacturing, and Application Award 2022 - - 2nd Prize — Business Startup Competition 2019`, - skills: [ - "C++", - "Java", - "Python", - "PHP", - "DSA", - "Advanced Databases", - "Systems Design", - "Distributed Systems", - "Software Engineering", - "Teamwork", - ], - }, - { - id: "2", - title: "Ly Tu Trong High School for the Gifted — Can Tho City", - employmentPeriod: { - start: "08.2015", - end: "06.2018", - }, - icon: , - description: `- Student of the Specialized Computer Science Program. -- Granted direct admission to university due to achieving 3rd Prize at the national level. -- [Achieved numerous awards](https://baocantho.com.vn/nguyen-chanh-dai-17-tuoi-va-19-giai-thuong-a97348.html) at city and national levels, including: - - [3rd Prize](https://muctim.tuoitre.vn/cong-cu-ho-tro-viec-day-va-hoc-55107.htm) — National Science and Engineering Fair 2018 (ViSEF) - - 1st Prize — Can Tho City Science and Engineering Fair 2018 - - Creativity Award — Binh Duong Hackathon 2017 - - Consolation Prize — National Youth and Children’s Creativity Contest 2016 - - [1st Prize](https://www.youtube.com/watch?v=OYgugvjqU4A) — Can Tho City Youth and Children’s Creativity Contest 2016 - - 3rd Prize — National Young Informatics Contest 2016 -- Achieved the title of Outstanding Student from Grade 10-12. -- Selected for the National Excellent Student Contest in Informatics for two consecutive years during high school. -- Honored on the school’s “Hall of Fame” for academic achievements. -- Developed a feature using Node.js and Pandoc to recognize multiple-choice questions from .docx files and upload them to an [online quiz platform](https://youtu.be/QjR99wdmTyo) I created. -- Developed websites based on Laravel framework. -- Built websites with PHP and MySQL, following the MVC architecture.`, - skills: [ - "Algorithms", - "C++", - "PHP", - "MySQL", - "Laravel", + "JavaScript", + "HTML5", + "CSS3", + "DOM Manipulation", "Node.js", - "Pandoc", + "Express", + "REST APIs", + "Web Performance", + "API Integration", ], - }, - { - id: "1", - title: "Thuan Hung Secondary School", - employmentPeriod: { - start: "08.2011", - end: "06.2015", - }, - icon: , - description: `- Recognized as the most outstanding student of the district. -- Achieved numerous awards at city and national levels: - - Consolation Prize — National Young Informatics Contest 2015 - - Consolation Prize — National Young Informatics Contest 2014 - - 1st Prize — Can Tho City Young Informatics Contest 2014 -- Achieved the title of Outstanding Student from Grade 6-9. -- Developed websites using the open-source NukeViet CMS.`, - skills: ["Pascal", "NukeViet", "HTML", "CSS", "JavaScript"], + isExpanded: true, }, ], }, diff --git a/src/data/portfolio/github-contributions.ts b/src/data/portfolio/github-contributions.ts index 7dc0646..7be9aa7 100644 --- a/src/data/portfolio/github-contributions.ts +++ b/src/data/portfolio/github-contributions.ts @@ -1,6 +1,7 @@ import "server-only" import { unstable_cache } from "next/cache" +import { formatISO, subDays } from "date-fns" import { GITHUB_USERNAME } from "@/config/site" import type { Activity } from "@/components/contribution-graph" @@ -9,20 +10,58 @@ type GitHubContributionsResponse = { contributions: Activity[] } -export const getGitHubContributions = unstable_cache( - async () => { - try { - const baseUrl = - process.env.GITHUB_CONTRIBUTIONS_API_URL || - `https://github-contributions-api.jogruber.de` - const res = await fetch(`${baseUrl}/v4/${GITHUB_USERNAME}?y=last`) - if (!res.ok) return [] - const data = (await res.json()) as GitHubContributionsResponse - return data.contributions - } catch { - return [] +function generateMockContributions(): Activity[] { + const contributions: Activity[] = [] + const today = new Date() + for (let i = 365; i >= 0; i--) { + const date = formatISO(subDays(today, i), { representation: "date" }) + // Simulate realistic contributions (mostly 0s, with some levels 1-4) + const rand = Math.random() + let level = 0 + if (rand > 0.85) level = 4 + else if (rand > 0.7) level = 3 + else if (rand > 0.5) level = 2 + else if (rand > 0.3) level = 1 + + const count = level === 0 ? 0 : level * 2 + Math.floor(Math.random() * 3) + contributions.push({ date, count, level }) + } + return contributions +} + +async function fetchContributions(): Promise { + try { + const baseUrl = + process.env.GITHUB_CONTRIBUTIONS_API_URL || + `https://github-contributions-api.jogruber.de` + const res = await fetch(`${baseUrl}/v4/${GITHUB_USERNAME}?y=last`, { + next: { revalidate: 3600 }, // Cache at fetch level for 1 hour + }) + if (!res.ok) { + console.warn( + `GitHub API responded with status ${res.status}. Falling back to mock data.` + ) + return generateMockContributions() } - }, - ["github-contributions"], - { revalidate: 86400 } // Cache for 1 day (86400 seconds) -) + const data = (await res.json()) as GitHubContributionsResponse + if (!data.contributions || data.contributions.length === 0) { + return generateMockContributions() + } + return data.contributions + } catch (error) { + console.warn( + "Failed to fetch GitHub contributions, using mock data fallback.", + error + ) + return generateMockContributions() + } +} + +export const getGitHubContributions = + process.env.NODE_ENV === "development" + ? fetchContributions + : unstable_cache( + fetchContributions, + ["github-contributions"], + { revalidate: 86400 } // Cache for 1 day in production + ) diff --git a/src/data/portfolio/social-links.ts b/src/data/portfolio/social-links.ts index b49b70d..dbe7e52 100644 --- a/src/data/portfolio/social-links.ts +++ b/src/data/portfolio/social-links.ts @@ -2,21 +2,33 @@ import type { SocialLink } from "@/types/social-links" export const SOCIAL_LINKS: SocialLink[] = [ { - icon: "/public/icons/x.svg", - title: "X", + icon: "/icons/x.svg", + title: "X (Twitter)", subtitle: "@iamwistant", href: "https://x.com/iamwistant", }, { - icon: "https://assets.chanhdai.com/images/link-icons/github.webp?v=2", + icon: "/icons/github.svg", title: "GitHub", subtitle: "@Wistant", href: "https://github.com/wistant", }, { - icon: "https://assets.chanhdai.com/images/link-icons/linkedin.webp?v=2", + icon: "/icons/SocialIcons/linkedin.svg", title: "LinkedIn", subtitle: "Wistant", href: "https://linkedin.com/in/wistant", }, + { + icon: "/icons/SocialIcons/reddit.svg", + title: "Reddit", + subtitle: "wistant", + href: "https://reddit.com/user/wistant", + }, + { + icon: "/icons/bluesky.svg", + title: "Bluesky", + subtitle: "wistant.me", + href: "https://bsky.app/profile/wistant.me", + }, ]