feat(links): redesign links directory to bryl-minimal aesthetic and add auto theme detection
- Redesign links page to clean 34rem narrow measure bryl-minimal layout - Add automatic system theme detection (prefers-color-scheme) with live adaptation - Add interactive theme toggle pill (Auto / Light / Dark) in the top navigation bar - Display natural color day/night portraits, Geist Pixel typography, and clean bryl-cards - Update navbar item ordering in Navbar.tsx
This commit is contained in:
1 parent
b7723b11d9
commit
a169dc7d7d
2 files changed
+202
-83
No files matched your search
@@ -7,8 +7,8 @@ const navItems = [
|
||||
{ label: 'projects', href: '/projects' },
|
||||
{ label: 'about', href: '/about' },
|
||||
{ label: 'certifications', href: '/certifications' },
|
||||
{ label: 'gallery', href: '/gallery' },
|
||||
{ label: 'contact', href: '/contact' },
|
||||
{ label: 'gallery', href: '/gallery' },
|
||||
];
|
||||
|
||||
interface NavbarProps {
|
||||
|
||||
+201
-82
@@ -1,6 +1,8 @@
|
||||
---
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
import { getSiteSettings, getSocialLinks } from '../lib/data';
|
||||
import ppDay from '../assets/pp-day.webp';
|
||||
import ppNight from '../assets/pp-night.webp';
|
||||
|
||||
const settings = await getSiteSettings();
|
||||
const allLinks = await getSocialLinks();
|
||||
@@ -10,13 +12,14 @@ const links = allLinks.length > 0
|
||||
? allLinks.filter(l => l.showInLinksPage !== false)
|
||||
: [
|
||||
{ platform: 'GitHub', url: 'https://github.com/ssbg04', icon: 'github', order: 1 },
|
||||
{ platform: 'Email', url: 'mailto:crischarlesgarcia345@gmail.com', icon: 'mail', order: 2 },
|
||||
{ platform: 'LinkedIn', url: 'https://linkedin.com', icon: 'linkedin', order: 3 },
|
||||
{ platform: 'TikTok', url: 'https://tiktok.com', icon: 'tiktok', order: 4 },
|
||||
{ platform: 'Facebook', url: 'https://facebook.com', icon: 'facebook', order: 5 },
|
||||
{ platform: 'LinkedIn', url: 'https://www.linkedin.com/in/cris-charles-garcia/', icon: 'linkedin', order: 2 },
|
||||
{ platform: 'Email', url: 'mailto:crischarlesgarcia345@gmail.com', icon: 'mail', order: 3 },
|
||||
{ platform: 'Facebook', url: 'https://www.facebook.com/kristyarls345/', icon: 'facebook', order: 4 },
|
||||
{ platform: 'TikTok', url: 'https://www.tiktok.com/@sisibigi', icon: 'tiktok', order: 5 },
|
||||
];
|
||||
|
||||
const profileAvatar = settings.heroImage || settings.logoImage || '/logo.png';
|
||||
const dayAvatar = settings.heroImage || (ppDay as any).src || ppDay;
|
||||
const nightAvatar = settings.heroImageNight || (ppNight as any).src || ppNight || dayAvatar;
|
||||
|
||||
const formatDisplayUrl = (url: string) => {
|
||||
try {
|
||||
@@ -30,26 +33,26 @@ const formatDisplayUrl = (url: string) => {
|
||||
const getIconSvg = (platform: string) => {
|
||||
const p = platform.toLowerCase();
|
||||
if (p.includes('github')) {
|
||||
return '<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>';
|
||||
return '<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>';
|
||||
}
|
||||
if (p.includes('linkedin')) {
|
||||
return '<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.779-1.75-1.75s.784-1.75 1.75-1.75 1.75.779 1.75 1.75-.784 1.75-1.75 1.75zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z"/></svg>';
|
||||
return '<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"><path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.779-1.75-1.75s.784-1.75 1.75-1.75 1.75.779 1.75 1.75-.784 1.75-1.75 1.75zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z"/></svg>';
|
||||
}
|
||||
if (p.includes('facebook')) {
|
||||
return '<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874V12h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/></svg>';
|
||||
return '<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874V12h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/></svg>';
|
||||
}
|
||||
if (p.includes('tiktok')) {
|
||||
return '<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M12.53.02C13.84 0 15.14.01 16.44 0c.08 1.53.63 3.09 1.75 4.17 1.12 1.11 2.7 1.62 4.24 1.79v4.03c-1.44-.05-2.89-.35-4.2-.97-.57-.26-1.1-.59-1.62-.93-.01 2.92.01 5.84-.02 8.75-.08 1.4-.54 2.79-1.35 3.94-1.31 1.92-3.58 3.17-5.91 3.21-1.43.08-2.86-.31-4.09-1.03-1.87-1.09-2.93-3.16-2.61-5.25.38-2.52 2.5-4.46 5.04-4.46.73 0 1.43.16 2.07.46.06.03.11.05.16.08v4.18c-1.38-.24-2.81-.19-4.16.14-1.12.28-2.12 1.05-2.67 2.06-.55 1.01-.58 2.22-.09 3.25.48 1.01 1.41 1.72 2.49 2.03 1.1.32 2.27.32 3.37.01.69-.2 1.34-.55 1.87-.99.53-.44.97-.99 1.25-1.61.28-.62.43-1.28.46-1.95.06-2.69.02-5.38.02-8.07z"/></svg>';
|
||||
return '<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"><path d="M12.53.02C13.84 0 15.14.01 16.44 0c.08 1.53.63 3.09 1.75 4.17 1.12 1.11 2.7 1.62 4.24 1.79v4.03c-1.44-.05-2.89-.35-4.2-.97-.57-.26-1.1-.59-1.62-.93-.01 2.92.01 5.84-.02 8.75-.08 1.4-.54 2.79-1.35 3.94-1.31 1.92-3.58 3.17-5.91 3.21-1.43.08-2.86-.31-4.09-1.03-1.87-1.09-2.93-3.16-2.61-5.25.38-2.52 2.5-4.46 5.04-4.46.73 0 1.43.16 2.07.46.06.03.11.05.16.08v4.18c-1.38-.24-2.81-.19-4.16.14-1.12.28-2.12 1.05-2.67 2.06-.55 1.01-.58 2.22-.09 3.25.48 1.01 1.41 1.72 2.49 2.03 1.1.32 2.27.32 3.37.01.69-.2 1.34-.55 1.87-.99.53-.44.97-.99 1.25-1.61.28-.62.43-1.28.46-1.95.06-2.69.02-5.38.02-8.07z"/></svg>';
|
||||
}
|
||||
if (p.includes('mail') || p.includes('email')) {
|
||||
return '<svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M21.75 6.75v10.5a2.25 2.25 0 0 1-2.25 2.25h-15a2.25 2.25 0 0 1-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0 0 19.5 4.5h-15a2.25 2.25 0 0 0-2.25 2.25m19.5 0v.243a2.25 2.25 0 0 1-1.07 1.916l-7.5 4.615a2.25 2.25 0 0 1-2.36 0L3.32 8.91a2.25 2.25 0 0 1-1.07-1.916V6.75" /></svg>';
|
||||
return '<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M21.75 6.75v10.5a2.25 2.25 0 0 1-2.25 2.25h-15a2.25 2.25 0 0 1-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0 0 19.5 4.5h-15a2.25 2.25 0 0 0-2.25 2.25m19.5 0v.243a2.25 2.25 0 0 1-1.07 1.916l-7.5 4.615a2.25 2.25 0 0 1-2.36 0L3.32 8.91a2.25 2.25 0 0 1-1.07-1.916V6.75" /></svg>';
|
||||
}
|
||||
return '<svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 0 1 1.242 7.244l-4.5 4.5a4.5 4.5 0 0 1-6.364-6.364l1.757-1.757m13.35-.622 1.757-1.757a4.5 4.5 0 0 0-6.364-6.364l-4.5 4.5a4.5 4.5 0 0 0 1.242 7.244" /></svg>';
|
||||
return '<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 0 1 1.242 7.244l-4.5 4.5a4.5 4.5 0 0 1-6.364-6.364l1.757-1.757m13.35-.622 1.757-1.757a4.5 4.5 0 0 0-6.364-6.364l-4.5 4.5a4.5 4.5 0 0 0 1.242 7.244" /></svg>';
|
||||
};
|
||||
---
|
||||
|
||||
<Layout
|
||||
title={`Links & Socials | ${settings.fullName}`}
|
||||
title={`Links & Directory | ${settings.fullName}`}
|
||||
description="Official social links, contact options, and developer directory for Cris Charles Garcia."
|
||||
canonicalURL="https://links.crischarles.com"
|
||||
>
|
||||
@@ -57,92 +60,206 @@ const getIconSvg = (platform: string) => {
|
||||
body {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
/* Reset Layout.astro defaults on links page since there is no navbar */
|
||||
#magnify-content {
|
||||
padding-top: 0 !important;
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
@media (orientation: landscape) and (max-height: 500px) {
|
||||
.links-main-container {
|
||||
padding-top: 0.75rem !important;
|
||||
padding-bottom: 2.5rem !important;
|
||||
}
|
||||
.links-profile-card {
|
||||
padding: 0.875rem !important;
|
||||
}
|
||||
.links-avatar {
|
||||
width: 3.25rem !important;
|
||||
height: 3.25rem !important;
|
||||
margin-bottom: 0.35rem !important;
|
||||
}
|
||||
.links-header-pills {
|
||||
margin-bottom: 0.625rem !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
{/* True Linktree Style: No Header Nav and No Footer */}
|
||||
<main class="min-h-screen py-8 px-4 sm:px-6 flex flex-col items-center justify-start md:justify-center relative links-main-container">
|
||||
{/* Auto-Detect Theme Script for Links Page */}
|
||||
<script is:inline>
|
||||
(function() {
|
||||
function getSystemTheme() {
|
||||
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||
}
|
||||
|
||||
function applyThemeMode(mode) {
|
||||
var resolved = mode === 'system' ? getSystemTheme() : mode;
|
||||
if (resolved === 'dark') {
|
||||
document.documentElement.classList.add('dark');
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark');
|
||||
}
|
||||
|
||||
var pillText = document.getElementById('theme-pill-text');
|
||||
var pillIcon = document.getElementById('theme-pill-icon');
|
||||
if (pillText && pillIcon) {
|
||||
if (mode === 'system') {
|
||||
pillIcon.textContent = '◐';
|
||||
pillText.textContent = 'AUTO (' + resolved + ')';
|
||||
} else if (mode === 'dark') {
|
||||
pillIcon.textContent = '☾';
|
||||
pillText.textContent = 'DARK';
|
||||
} else {
|
||||
pillIcon.textContent = '☼';
|
||||
pillText.textContent = 'LIGHT';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var currentMode = localStorage.getItem('theme') || 'system';
|
||||
applyThemeMode(currentMode);
|
||||
|
||||
// Live listener for OS theme change
|
||||
try {
|
||||
var mq = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
var changeHandler = function() {
|
||||
var stored = localStorage.getItem('theme');
|
||||
if (!stored || stored === 'system') {
|
||||
applyThemeMode('system');
|
||||
}
|
||||
};
|
||||
if (mq.addEventListener) {
|
||||
mq.addEventListener('change', changeHandler);
|
||||
} else if (mq.addListener) {
|
||||
mq.addListener(changeHandler);
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
// Toggle button click handler
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var btn = document.getElementById('theme-auto-pill');
|
||||
if (btn) {
|
||||
btn.addEventListener('click', function() {
|
||||
var stored = localStorage.getItem('theme') || 'system';
|
||||
var nextMode = 'system';
|
||||
if (stored === 'system') nextMode = 'light';
|
||||
else if (stored === 'light') nextMode = 'dark';
|
||||
else nextMode = 'system';
|
||||
|
||||
localStorage.setItem('theme', nextMode);
|
||||
applyThemeMode(nextMode);
|
||||
window.dispatchEvent(new CustomEvent('theme-change', { detail: { theme: nextMode === 'system' ? getSystemTheme() : nextMode } }));
|
||||
});
|
||||
}
|
||||
applyThemeMode(localStorage.getItem('theme') || 'system');
|
||||
});
|
||||
|
||||
// Handle page load / Astro swaps
|
||||
document.addEventListener('astro:page-load', function() {
|
||||
applyThemeMode(localStorage.getItem('theme') || 'system');
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
{/* Main Container — narrow measure (34rem) per bryl-minimal specification */}
|
||||
<main class="min-h-screen py-8 sm:py-12 px-4 sm:px-6 flex flex-col items-center justify-start relative">
|
||||
|
||||
{/* Return to Main Portfolio Pill & Status */}
|
||||
<div class="w-full max-w-[42rem] flex justify-between items-center mb-6 links-header-pills">
|
||||
<a
|
||||
href="https://crischarles.com"
|
||||
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-md bg-card-custom hover:bg-muted-custom/40 text-muted-foreground-custom hover:text-foreground-custom text-xs font-mono border border-border-custom transition-all"
|
||||
>
|
||||
<span>←</span>
|
||||
<span>portfolio</span>
|
||||
</a>
|
||||
<div class="w-full max-w-[34rem] flex flex-col gap-6 relative z-10 bryl-entrance stagger-1">
|
||||
|
||||
{settings.isAvailable !== false && (
|
||||
<span class="text-[10px] font-mono text-foreground-custom flex items-center gap-1.5 px-2.5 py-1 rounded-md border border-border-custom bg-card-custom">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-foreground-custom animate-pulse" />
|
||||
{settings.availabilityStatus || 'available for work'}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{/* Top Header Navigation: Back Link, Live Status, and Auto Theme Pill */}
|
||||
<div class="w-full flex items-center justify-between gap-2.5 pb-2 border-b border-border-custom">
|
||||
<a
|
||||
href="https://crischarles.com"
|
||||
class="inline-flex items-center gap-1.5 text-xs font-mono text-muted-foreground-custom hover:text-foreground-custom transition-colors group"
|
||||
>
|
||||
<span class="group-hover:-translate-x-1 transition-transform">←</span>
|
||||
<span>portfolio</span>
|
||||
</a>
|
||||
|
||||
{/* Content Container */}
|
||||
<div class="w-full max-w-[42rem] flex flex-col gap-4 relative z-10">
|
||||
|
||||
{/* Profile Header Card */}
|
||||
<div class="bryl-card p-6 text-center flex flex-col items-center links-profile-card">
|
||||
<div class="w-16 h-16 sm:w-20 sm:h-20 rounded-2xl overflow-hidden border border-border-custom mb-3 bg-muted-custom/20 links-avatar">
|
||||
<img
|
||||
src={profileAvatar}
|
||||
alt={settings.fullName}
|
||||
class="w-full h-full object-cover"
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
/>
|
||||
<div class="flex items-center gap-2">
|
||||
{/* Live Availability Status */}
|
||||
{settings.isAvailable !== false && (
|
||||
<span class="text-[10px] font-mono text-foreground-custom inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md border border-border-custom bg-card-custom shadow-xs">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-foreground-custom animate-pulse opacity-80" />
|
||||
<span class="hidden sm:inline lowercase">{settings.availabilityStatus || 'available for work'}</span>
|
||||
<span class="sm:hidden">available</span>
|
||||
</span>
|
||||
)}
|
||||
|
||||
{/* Interactive Auto-Detect Theme Pill */}
|
||||
<button
|
||||
id="theme-auto-pill"
|
||||
type="button"
|
||||
class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md bg-card-custom hover:bg-elevated-custom text-foreground-custom text-[10px] font-mono font-semibold border border-border-custom transition-all cursor-pointer shadow-xs active:scale-95"
|
||||
title="Auto-detects device theme. Tap to cycle: Auto → Light → Dark"
|
||||
aria-label="Theme Mode Toggle"
|
||||
>
|
||||
<span id="theme-pill-icon" class="text-[11px]">◐</span>
|
||||
<span id="theme-pill-text" class="tracking-wider uppercase">AUTO</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h1 class="text-xl sm:text-2xl font-mono lowercase font-bold text-foreground-custom tracking-tight">
|
||||
{settings.fullName}
|
||||
</h1>
|
||||
|
||||
<p class="text-xs font-mono text-muted-foreground-custom mt-1">
|
||||
{settings.title} // {settings.location}
|
||||
</p>
|
||||
|
||||
<p class="text-xs font-mono text-muted-foreground-custom max-w-sm mt-2 leading-relaxed">
|
||||
{settings.valueProposition || 'Direct links to my official profiles, repositories, and credentials.'}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Social Links List */}
|
||||
<div class="flex flex-col gap-2">
|
||||
{/* Profile Header Card */}
|
||||
<section class="bryl-card p-6 sm:p-7 text-center flex flex-col items-center relative overflow-hidden bryl-entrance stagger-2">
|
||||
{/* Subtle halftone corner garnish */}
|
||||
<div class="absolute -top-6 -right-6 w-28 h-28 halftone-bg opacity-40 pointer-events-none rounded-full mask-radial"></div>
|
||||
|
||||
{/* Natural Color Avatar (16px outer radius, 12px inner) */}
|
||||
<div class="relative w-20 h-20 sm:w-22 sm:h-22 rounded-2xl border border-border-custom p-1 bg-card-custom shadow-sm mb-3.5">
|
||||
<div class="w-full h-full rounded-[12px] overflow-hidden bg-elevated-custom">
|
||||
<img
|
||||
src={dayAvatar}
|
||||
alt={settings.fullName}
|
||||
class="w-full h-full object-cover dark:hidden transition-transform duration-500 ease-out hover:scale-105"
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
/>
|
||||
<img
|
||||
src={nightAvatar}
|
||||
alt={settings.fullName}
|
||||
class="w-full h-full object-cover hidden dark:block transition-transform duration-500 ease-out hover:scale-105"
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Name — Geist Pixel Square with clean kerning */}
|
||||
<h1 class="font-display text-2xl sm:text-3xl font-bold lowercase text-foreground-custom tracking-tight mb-1.5">
|
||||
{settings.fullName.toLowerCase()}
|
||||
</h1>
|
||||
|
||||
{/* Micro-label Role & Location */}
|
||||
<p class="micro-label text-[10px] sm:text-[11px] text-muted-foreground-custom uppercase tracking-widest">
|
||||
{settings.title ? settings.title.split('|')[0].trim() : 'Software Developer'} // {settings.location}
|
||||
</p>
|
||||
|
||||
{/* Editorial Value Proposition Body */}
|
||||
<p class="font-serif text-xs sm:text-sm text-muted-foreground-custom max-w-sm mt-3 leading-relaxed">
|
||||
{settings.valueProposition || 'Direct links to my official profiles, repositories, and credentials.'}
|
||||
</p>
|
||||
|
||||
{/* Primary Inverted Action Chip */}
|
||||
<a
|
||||
href={settings.resumeFile || '/CV-Cris-Charles-Garcia.pdf'}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="chip-inverted text-xs py-1.5 px-4 font-mono mt-4 hover:opacity-90 inline-flex items-center gap-1.5 transition-all shadow-xs"
|
||||
>
|
||||
<span>download cv</span>
|
||||
<span class="text-[10px]" aria-hidden="true">↗</span>
|
||||
</a>
|
||||
</section>
|
||||
|
||||
{/* Directory Section Header */}
|
||||
<div class="flex items-center justify-between pt-2">
|
||||
<div class="section-marker">
|
||||
<span class="section-marker-num">01 —</span>
|
||||
<span class="section-marker-title">official links</span>
|
||||
</div>
|
||||
<span class="micro-label text-[10px] text-muted-foreground-custom">
|
||||
{links.length} verified channels
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Social Links List — Hairline bryl-cards with micro-interaction hover */}
|
||||
<nav class="flex flex-col gap-2.5 bryl-entrance stagger-3" aria-label="Official Links">
|
||||
{links.map((link) => (
|
||||
<a
|
||||
href={link.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="bryl-card p-3.5 sm:p-4 flex items-center justify-between group cursor-pointer"
|
||||
class="bryl-card p-3.5 sm:p-4 flex items-center justify-between group cursor-pointer transition-all duration-300 hover:-translate-y-0.5 hover:border-border-strong hover:shadow-md"
|
||||
>
|
||||
<div class="flex items-center gap-3.5 min-w-0">
|
||||
<div class="w-8 h-8 rounded-lg bg-foreground-custom/5 border border-border-custom flex items-center justify-center text-foreground-custom shrink-0" set:html={getIconSvg(link.platform)}></div>
|
||||
<div class="w-9 h-9 rounded-xl bg-foreground-custom/[0.04] border border-border-custom flex items-center justify-center text-foreground-custom shrink-0 group-hover:bg-foreground-custom group-hover:text-background-custom transition-all duration-200">
|
||||
<Fragment set:html={getIconSvg(link.platform)} />
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col min-w-0">
|
||||
<span class="text-xs sm:text-sm font-mono lowercase font-bold text-foreground-custom leading-tight">
|
||||
<span class="text-xs sm:text-sm font-mono lowercase font-semibold text-foreground-custom leading-tight group-hover:underline">
|
||||
{link.platform}
|
||||
</span>
|
||||
<span class="text-[10px] sm:text-[11px] font-mono text-muted-foreground-custom truncate leading-tight mt-0.5" title={link.url}>
|
||||
@@ -151,17 +268,19 @@ const getIconSvg = (platform: string) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="text-xs font-mono text-muted-foreground-custom group-hover:text-foreground-custom group-hover:translate-x-0.5 transition-all shrink-0 ml-3">
|
||||
<span class="text-xs font-mono text-muted-foreground-custom group-hover:text-foreground-custom group-hover:translate-x-0.5 group-hover:-translate-y-0.5 transition-all shrink-0 ml-3">
|
||||
↗
|
||||
</span>
|
||||
</a>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
{/* Minimal Footer Stamp */}
|
||||
<p class="text-[10px] font-mono text-muted-foreground-custom text-center mt-4">
|
||||
{/* Minimal Footer Stamp */}
|
||||
<footer class="text-center pt-4 pb-2">
|
||||
<p class="micro-label text-[10px] text-muted-foreground-custom uppercase tracking-widest">
|
||||
© {new Date().getFullYear()} {settings.fullName} // directory
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
|
||||
Reference in new issue
Block a user