Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/santiagonieto09/portafolio/llms.txt

Use this file to discover all available pages before exploring further.

The profile section occupies the top of the portfolio page and is the first thing visitors see. All data it displays flows from a single Profile domain object that is populated server-side by fetching the authenticated user’s data from the GitHub REST API. Because the page is server-rendered with TanStack Start, the profile information is embedded in the initial HTML — no client-side fetch is needed before the avatar and bio appear.

ProfileHero component

Source: src/components/portfolio/profile-hero.tsx ProfileHero accepts a single prop:
function ProfileHero({ profile }: { profile: Profile })
The component renders a two-column grid on medium screens (avatar column + details column) that collapses to a centered single column on mobile. Avatar — The avatar is an <img> tag pointing to profile.avatarUrl, which is always a URL on GitHub’s CDN (avatars.githubusercontent.com). It is loaded eagerly (loading="eager") because it is the largest contentful element on the page. Identity block — Displays profile.name as an <h1>, followed by the GitHub username as @{profile.login} in a monospace style. Bio — Rendered only when profile.bio is not null. Fact chips — A <dl> grid of metadata chips, built from an array of Fact objects. Each entry that is non-null produces a chip:
FieldLabelNotes
profile.locationUbicaciónOmitted if null
profile.companyEmpresaOmitted if null
profile.publicReposRepositorios públicosFormatted with formatNumber()
profile.followers / profile.followingSeguidoresShown as {followers} · sigue a {following}
profile.createdAtEn GitHub desdeFormatted with formatDate()
Social buttons — Rendered via the SocialButtons component (see below). The component receives profile.socials with all email kind entries replaced by a fixed Gmail compose link constructed from the CONTACT_EMAIL constant.

StatsGrid component

Source: src/components/portfolio/stats-grid.tsx StatsGrid accepts a single prop:
function StatsGrid({ stats }: { stats: PortfolioStats })
It renders a heading section and a responsive grid (grid-cols-2sm:grid-cols-3lg:grid-cols-6) of six metric cards:
MetricFieldIcon
Repositoriosstats.totalReposFolderGit2
Estrellasstats.totalStarsStar
Forksstats.totalForksGitFork
Con releasestats.totalReleasesRocket
Activosstats.activeReposZap
Archivadosstats.archivedReposArchive
Each card shows a Lucide icon, a large formatted number (formatNumber(item.value)), and a text label below it. The section header also includes a chip showing “Sincronizado , where lastSynced is the result of calling useRelativeTime(stats.lastSyncedAt) — a client-side hook that turns the ISO timestamp into a human-readable relative string (e.g. “hace 2 minutos”).

SocialButtons component

Source: src/components/portfolio/social-buttons.tsx SocialButtons accepts a single prop:
function SocialButtons({ links }: { links: SocialLink[] })
It renders a <ul> of anchor buttons, one per SocialLink. Each button shows a Lucide icon and the link’s label text. The icon is selected by mapping link.kind through the ICONS lookup table:
kindLucide icon
githubGithub
linkedinLinkedin
xTwitter
instagramInstagram
facebookFacebook
youtubeYoutube
websiteGlobe
blogNewspaper
emailMail
If a kind is not found in the table, Globe is used as the fallback. All links open in a new tab (target="_blank") except mailto: links, which omit the target attribute so the browser opens the mail client directly. Every anchor includes rel="noopener noreferrer me".

Profile domain type

The Profile interface is the canonical data contract shared between the server data-fetching layer and the UI components. It is defined in src/domain/github/types.ts:
interface Profile {
  login: string;
  name: string;
  avatarUrl: string;
  bio: string | null;
  location: string | null;
  company: string | null;
  blog: string | null;
  email: string | null;
  publicRepos: number;
  followers: number;
  following: number;
  createdAt: string;
  htmlUrl: string;
  socials: SocialLink[];
}
All date fields (createdAt) are stored as ISO 8601 strings and formatted for display by the formatDate / useRelativeTime utilities.
The SocialLink interface is also defined in src/domain/github/types.ts:
interface SocialLink {
  kind:
    | "github"
    | "linkedin"
    | "x"
    | "instagram"
    | "facebook"
    | "youtube"
    | "website"
    | "blog"
    | "email";
  label: string;
  url: string;
}
Supported kind values: github, linkedin, x, instagram, facebook, youtube, website, blog, email. Building links (server side) — The socialsFrom() helper in the GitHub API server module constructs the SocialLink[] array from three sources:
  1. user.blog — If the field is a non-empty string, it is classified as website or blog depending on whether the URL matches a known blogging platform.
  2. user.twitter_username — If present, produces a kind: "x" link pointing to https://x.com/{username}.
  3. /social_accounts endpoint — GitHub’s dedicated endpoint that returns typed social account objects (provider + url). Each entry is mapped to the closest matching kind (e.g. linkedinlinkedin, instagraminstagram).
Entries are deduplicated by URL before the final array is returned, so a user who has their GitHub profile URL in both blog and the social accounts list will not see it twice.

Build docs developers (and LLMs) love