File manager - Edit - /home/webapp69.cm.in.th/u69319090001/Portfolio/index.html
Back
<!DOCTYPE html> <html lang="th" class="scroll-smooth dark"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Portfolio | กรกฎ ใจมูล</title> <!-- Tailwind CSS CDN --> <script src="https://cdn.tailwindcss.com"></script> <script> tailwind.config = { darkMode: 'class', theme: { extend: { colors: { brand: { cyan: '#22d3ee', purple: '#a855f7', darkBg: '#020617', cardBg: 'rgba(15, 23, 42, 0.45)' } }, fontFamily: { sans: ['Inter', 'sans-serif'], outfit: ['Outfit', 'sans-serif'] } } } } </script> <!-- Custom styles --> <link rel="stylesheet" href="style.css"> <!-- Lucide Icons CDN --> <script src="https://unpkg.com/lucide@latest"></script> <!-- ══ INTRO OVERLAY STYLES ══ --> <style> /* ─ Root vars ─ */ #intro-overlay { --ic: #22d3ee; --ip: #a855f7; --ik: #ec4899; } /* ─ Overlay shell ─ */ #intro-overlay { position: fixed; inset: 0; z-index: 9000; overflow: hidden; font-family: 'Outfit', 'Inter', sans-serif; cursor: none; background: #000; transition: opacity .65s ease; } #intro-overlay.intro-hidden { opacity: 0; pointer-events: none; } /* ─ Custom cursor ─ */ #i-cursor { position: fixed; width: 12px; height: 12px; border-radius: 50%; background: var(--ic); pointer-events: none; z-index: 9999; transform: translate(-50%,-50%); box-shadow: 0 0 14px var(--ic), 0 0 36px rgba(34,211,238,.4); mix-blend-mode: screen; transition: width .2s, height .2s, background .2s; } #i-cursor-ring { position: fixed; width: 40px; height: 40px; border-radius: 50%; border: 1.5px solid rgba(168,85,247,.55); pointer-events: none; z-index: 9998; transform: translate(-50%,-50%); transition: width .3s, height .3s; } /* ─ Background ─ */ #i-bg { position: absolute; inset: -8%; background: url('3d/3465281285/preview.gif') center/cover no-repeat; filter: brightness(.9) saturate(1.2); will-change: transform; } #i-overlay { position: absolute; inset: 0; background: radial-gradient(ellipse 76% 56% at 50% 50%, transparent 35%, rgba(2,6,23,.55) 100%), linear-gradient(to bottom, rgba(2,6,23,.35) 0%, transparent 25%, transparent 75%, rgba(2,6,23,.5) 100%); } /* ─ Cinematic bars ─ */ #i-bar-top, #i-bar-bottom { position: absolute; left: 0; width: 100%; background: #000; z-index: 10; transition: height 1s cubic-bezier(.77,0,.175,1); } #i-bar-top { top: 0; height: 20vh; } #i-bar-bottom { bottom: 0; height: 20vh; } #intro-overlay.bars-open #i-bar-top { height: 0; } #intro-overlay.bars-open #i-bar-bottom { height: 0; } /* ─ Particles ─ */ #i-canvas { position: absolute; inset: 0; z-index: 1; pointer-events: none; } /* ─ FX ─ */ .i-vignette { position: absolute; inset: 0; z-index: 2; pointer-events: none; box-shadow: inset 0 0 240px rgba(0,0,0,.75); } .i-scanlines { position: absolute; inset: 0; z-index: 3; pointer-events: none; background: repeating-linear-gradient(0deg,transparent,transparent 2px,rgba(0,0,0,.04) 2px,rgba(0,0,0,.04) 4px); } /* ─ HUD ─ */ #i-hud { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; z-index: 20; pointer-events: none; } .i-sub-label { letter-spacing: .35em; font-size: .72rem; font-weight: 300; color: #22d3ee; text-transform: uppercase; opacity: 0; animation: iFadeUp .8s .5s forwards; } .i-name { font-size: clamp(3rem, 9vw, 7.5rem); font-weight: 900; line-height: 1; text-align: center; margin-top: .4rem; background: linear-gradient(135deg,#fff 0%,#22d3ee 45%,#a855f7 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; opacity: 0; animation: iFadeScale .9s 1s cubic-bezier(.22,1,.36,1) forwards; filter: drop-shadow(0 0 48px rgba(168,85,247,.4)); } .i-divider { width: 0; height: 1px; margin: 1.4rem auto; background: linear-gradient(90deg,transparent,#22d3ee,#a855f7,transparent); animation: iExpand .8s 1.5s cubic-bezier(.22,1,.36,1) forwards; } .i-tw-wrap { height: 1.8rem; display: flex; align-items: center; justify-content: center; opacity: 0; animation: iFadeIn .6s 1.8s forwards; } #i-tw { font-size: 1rem; font-weight: 300; color: rgba(255,255,255,.78); letter-spacing: .1em; border-right: 2px solid #22d3ee; padding-right: 3px; white-space: nowrap; } #i-enter-btn { pointer-events: all; margin-top: 2.4rem; padding: .78rem 3rem; border: 1px solid rgba(34,211,238,.45); border-radius: 100px; background: rgba(34,211,238,.06); color: #22d3ee; font-family: 'Outfit','Inter',sans-serif; font-size: .88rem; font-weight: 600; letter-spacing: .22em; text-transform: uppercase; cursor: none; opacity: 0; animation: iFadeUp .8s 2.5s forwards; transition: background .3s, box-shadow .3s, transform .2s; position: relative; overflow: hidden; } #i-enter-btn::before { content:''; position:absolute; inset:0; background: linear-gradient(135deg,rgba(34,211,238,.2),rgba(168,85,247,.15)); opacity:0; transition:opacity .3s; } #i-enter-btn:hover::before { opacity:1; } #i-enter-btn:hover { box-shadow: 0 0 32px rgba(34,211,238,.4), 0 0 70px rgba(168,85,247,.22); transform: translateY(-2px) scale(1.04); } #i-enter-btn::after { content:''; position:absolute; inset:-5px; border-radius:100px; border:1px solid rgba(34,211,238,.5); opacity:0; animation:iPulseRing 2s 3.1s ease-out infinite; } .i-key-hint { margin-top:.9rem; font-size:.7rem; color:rgba(255,255,255,.28); letter-spacing:.12em; opacity:0; animation:iFadeIn .6s 2.9s forwards; } .i-key-hint kbd { border:1px solid rgba(255,255,255,.3); padding:1px 7px; border-radius:4px; font-family:inherit; } /* ─ Music pill ─ */ #i-music-pill { position: absolute; bottom:24px; left:50%; transform: translateX(-50%) translateY(90px); opacity:0; display:flex; align-items:center; gap:14px; padding:10px 20px; border-radius:100px; background:rgba(10,16,35,.72); border:1px solid rgba(255,255,255,.1); backdrop-filter:blur(24px); z-index:25; animation:iSlideUp .8s .8s cubic-bezier(.22,1,.36,1) forwards; pointer-events:all; cursor:none; } #i-disc { width:36px; height:36px; border-radius:50%; flex-shrink:0; background:conic-gradient(#22d3ee 0%,#a855f7 60%,#ec4899 100%); display:flex; align-items:center; justify-content:center; animation:iSpin 4s linear infinite; animation-play-state:paused; } #i-disc.playing { animation-play-state:running; } #i-disc-inner { width:13px; height:13px; border-radius:50%; background:#090f1e; } #i-minfo { flex:1; min-width:110px; } #i-mtitle { font-size:.78rem; font-weight:600; color:#fff; } #i-martist { font-size:.68rem; color:rgba(255,255,255,.4); } #i-mtoggle { background:none; border:none; color:#22d3ee; cursor:none; display:flex; align-items:center; padding:4px; transition:transform .2s,color .2s; } #i-mtoggle:hover { transform:scale(1.25); color:#a855f7; } #i-wavebars { display:flex; align-items:center; gap:2px; height:20px; } .i-wb { width:3px; border-radius:2px; background:#22d3ee; height:8px; animation:iWave .9s ease-in-out infinite alternate; } .i-wb:nth-child(1){animation-delay:0s; animation-duration:.7s;} .i-wb:nth-child(2){animation-delay:.12s; animation-duration:.9s;} .i-wb:nth-child(3){animation-delay:.24s; animation-duration:.8s;} .i-wb:nth-child(4){animation-delay:.36s; animation-duration:.7s;} .i-wb:nth-child(5){animation-delay:.2s; animation-duration:.95s;} .i-wb:nth-child(6){animation-delay:.08s; animation-duration:.85s;} #i-wavebars.paused .i-wb { animation-play-state:paused; height:4px !important; } /* ─ Keyframes ─ */ @keyframes iFadeUp { from{opacity:0;transform:translateY(26px)} to{opacity:1;transform:translateY(0)} } @keyframes iFadeScale { from{opacity:0;transform:translateY(30px) scale(.95)} to{opacity:1;transform:translateY(0) scale(1)} } @keyframes iFadeIn { from{opacity:0} to{opacity:1} } @keyframes iExpand { from{width:0} to{width:min(300px,70vw)} } @keyframes iSpin { to{transform:rotate(360deg)} } @keyframes iWave { from{height:4px} to{height:18px} } @keyframes iPulseRing { 0% {opacity:.8;transform:scale(1)} 100%{opacity:0; transform:scale(1.3)} } @keyframes iSlideUp { from{transform:translateX(-50%) translateY(90px);opacity:0} to {transform:translateX(-50%) translateY(0); opacity:1} } @keyframes iGlitch { 0% {clip-path:inset(5% 0 80% 0);transform:translate(-4px,0) skewX(-2deg)} 25%{clip-path:inset(60% 0 15% 0);transform:translate(4px,0) skewX(2deg)} 50%{clip-path:inset(30% 0 50% 0);transform:translate(-2px,0)} 75%{clip-path:inset(80% 0 5% 0);transform:translate(3px,0) skewX(-1deg)} 100%{clip-path:none;transform:none} } </style> </head> <body class="bg-slate-50 text-slate-900 dark:bg-[#020617] dark:text-slate-100 min-h-screen relative bg-grid-pattern selection:bg-cyan-500/30 selection:text-cyan-200 transition-colors duration-300" style="overflow:hidden"> <!-- ══════════════════════════════════════════════ INTRO / CUTSCENE OVERLAY ══════════════════════════════════════════════ --> <div id="intro-overlay"> <!-- Cursors --> <div id="i-cursor"></div> <div id="i-cursor-ring"></div> <!-- Cinematic bars --> <div id="i-bar-top"></div> <div id="i-bar-bottom"></div> <!-- Background parallax --> <div id="i-bg"></div> <div id="i-overlay"></div> <!-- FX --> <div class="i-vignette"></div> <div class="i-scanlines"></div> <canvas id="i-canvas"></canvas> <!-- HUD --> <div id="i-hud"> <p class="i-sub-label">✦ P O R T F O L I O ✦</p> <h2 class="i-name" id="i-name">กรกฎ ใจมูล</h2> <div class="i-divider"></div> <div class="i-tw-wrap"><span id="i-tw"></span></div> <button id="i-enter-btn">E N T E R</button> <p class="i-key-hint">กด <kbd>Enter</kbd> หรือคลิกเพื่อเข้าสู่เนื้อหา</p> </div> <!-- Music pill --> <div id="i-music-pill"> <div id="i-disc"> <div id="i-disc-inner"></div> </div> <div id="i-minfo"> <div id="i-mtitle">Circle With Me</div> <div id="i-martist">Spiritbox</div> </div> <div id="i-wavebars"> <div class="i-wb"></div><div class="i-wb"></div><div class="i-wb"></div> <div class="i-wb"></div><div class="i-wb"></div><div class="i-wb"></div> </div> <button id="i-mtoggle" title="Play / Pause"> <svg id="i-icon-pause" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="currentColor" style="display:none"><rect x="6" y="4" width="4" height="16"/><rect x="14" y="4" width="4" height="16"/></svg> <svg id="i-icon-play" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><polygon points="5,3 19,12 5,21"/></svg> </button> </div> <!-- Local audio file: autoplay muted → JS unmutes after load --> <audio id="i-audio" loop autoplay muted preload="auto"> <source src="3d/Spiritbox Circle With Me Official Music Video.mp3" type="audio/mpeg"> </audio> </div> <!-- ══ END INTRO ══ --> <!-- Glow Background Accents --> <div class="absolute top-[-10%] left-[-10%] w-[50vw] h-[50vw] rounded-full bg-cyan-500/10 blur-[120px] pointer-events-none animate-pulse-slow"> </div> <div class="absolute top-[40%] right-[-10%] w-[45vw] h-[45vw] rounded-full bg-purple-500/10 blur-[120px] pointer-events-none animate-pulse-slow"> </div> <div class="absolute bottom-[-10%] left-[20%] w-[50vw] h-[50vw] rounded-full bg-indigo-500/10 blur-[120px] pointer-events-none animate-pulse-slow"> </div> <!-- Header / Navbar --> <header class="fixed top-0 left-0 w-full z-50 transition-all duration-300" id="main-header"> <nav class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-20 flex items-center justify-between"> <!-- Logo --> <a href="#hero" class="flex items-center space-x-2 group"> <div class="w-10 h-10 rounded-xl bg-gradient-to-tr from-cyan-400 to-purple-500 flex items-center justify-center shadow-lg shadow-cyan-500/20 group-hover:scale-105 transition-transform duration-300"> <span class="text-white font-bold text-xl font-outfit">P</span> </div> <span class="font-outfit text-xl font-bold bg-gradient-to-r from-white via-slate-100 to-slate-400 bg-clip-text text-transparent group-hover:to-cyan-400 transition-all duration-300">Portfolio</span> </a> <!-- Desktop Nav Menu --> <div class="hidden md:flex items-center space-x-1 lg:space-x-2"> <a href="#hero" class="nav-link px-4 py-2 text-sm font-medium text-slate-300 hover:text-cyan-400 transition-colors duration-300 relative" data-section="hero">หน้าแรก</a> <a href="#about" class="nav-link px-4 py-2 text-sm font-medium text-slate-300 hover:text-cyan-400 transition-colors duration-300 relative" data-section="about">เกี่ยวกับฉัน</a> <a href="#projects" class="nav-link px-4 py-2 text-sm font-medium text-slate-300 hover:text-cyan-400 transition-colors duration-300 relative" data-section="projects">ผลงาน</a> <a href="#contact" class="nav-link px-4 py-2 text-sm font-medium text-slate-300 hover:text-cyan-400 transition-colors duration-300 relative" data-section="contact">ติดต่อ</a> <!-- Contact CTA Button --> <a href="#contact" class="ml-4 px-5 py-2.5 rounded-xl bg-slate-900/80 border border-slate-700 hover:border-cyan-500/50 hover:bg-slate-800 text-sm font-semibold text-cyan-400 hover:text-cyan-300 transition-all duration-300 flex items-center gap-2 shadow-inner"> <i data-lucide="send" class="w-4 h-4"></i> Let's Talk </a> <!-- Theme Toggle Button (Desktop) --> <button id="theme-toggle" class="ml-2 px-3.5 py-2.5 rounded-xl bg-slate-900/80 border border-slate-700 hover:border-cyan-500/50 hover:bg-slate-800 text-slate-300 hover:text-cyan-400 transition-all duration-300 flex items-center justify-center min-h-[44px]" aria-label="Toggle Theme"> <i data-lucide="sun" id="theme-toggle-icon" class="w-4 h-4"></i> </button> </div> <!-- Mobile Menu Button --> <button id="mobile-menu-btn" class="md:hidden w-12 h-12 flex items-center justify-center rounded-xl bg-slate-900/50 border border-slate-800 hover:border-slate-700 text-slate-300 hover:text-white transition-all focus:outline-none" aria-label="Toggle Menu"> <i data-lucide="menu" id="menu-icon" class="w-6 h-6 transition-transform duration-300"></i> </button> </nav> <!-- Mobile Dropdown Menu --> <div id="mobile-dropdown" class="absolute top-20 left-0 w-full glass-panel border-t border-slate-800/80 hidden flex-col px-4 py-6 space-y-3 shadow-2xl transition-all duration-300 ease-in-out origin-top scale-y-95 opacity-0"> <a href="#hero" class="mobile-nav-link flex items-center space-x-3 px-4 py-3 rounded-xl hover:bg-slate-800/50 text-slate-300 hover:text-cyan-400 transition-all duration-200" data-section="hero"> <i data-lucide="home" class="w-5 h-5"></i> <span class="font-medium">หน้าแรก</span> </a> <a href="#about" class="mobile-nav-link flex items-center space-x-3 px-4 py-3 rounded-xl hover:bg-slate-800/50 text-slate-300 hover:text-cyan-400 transition-all duration-200" data-section="about"> <i data-lucide="user" class="w-5 h-5"></i> <span class="font-medium">เกี่ยวกับฉัน</span> </a> <a href="#projects" class="mobile-nav-link flex items-center space-x-3 px-4 py-3 rounded-xl hover:bg-slate-800/50 text-slate-300 hover:text-cyan-400 transition-all duration-200" data-section="projects"> <i data-lucide="folder-git-2" class="w-5 h-5"></i> <span class="font-medium">ผลงาน</span> </a> <a href="#contact" class="mobile-nav-link flex items-center space-x-3 px-4 py-3 rounded-xl hover:bg-slate-800/50 text-slate-300 hover:text-cyan-400 transition-all duration-200" data-section="contact"> <i data-lucide="mail" class="w-5 h-5"></i> <span class="font-medium">ติดต่อ</span> </a> <hr class="border-slate-800 my-2"> <a href="#contact" class="flex items-center justify-center space-x-2 px-4 py-3.5 rounded-xl bg-gradient-to-r from-cyan-500 to-purple-600 hover:from-cyan-400 hover:to-purple-500 text-white font-semibold text-center transition-all duration-300 shadow-lg shadow-cyan-500/10"> <i data-lucide="send" class="w-5 h-5"></i> <span>ติดต่อฉันตอนนี้</span> </a> </div> </header> <main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pt-24 pb-16"> <!-- Hero Section --> <section id="hero" class="min-h-[85vh] flex flex-col md:flex-row items-center justify-between py-12 md:py-20 gap-12 md:gap-8"> <!-- Hero Details --> <div class="flex-1 space-y-6 text-center md:text-left order-2 md:order-1"> <div class="inline-flex items-center space-x-2 px-3.5 py-1.5 rounded-full bg-cyan-500/10 border border-cyan-500/30 text-cyan-400 text-sm font-semibold tracking-wide"> <span class="w-2 h-2 rounded-full bg-cyan-400 animate-ping"></span> <span>พร้อมรับงาน / Available for Hire</span> </div> <h1 class="text-4xl sm:text-5xl lg:text-6xl font-extrabold tracking-tight leading-none"> สวัสดีครับ, ผมคือ <br class="hidden sm:inline"> <span class="bg-gradient-to-r from-cyan-400 via-teal-300 to-purple-500 bg-clip-text text-transparent">กรกฎ ใจมูล</span> </h1> <!-- CTAs --> <div class="flex flex-col sm:flex-row items-center justify-center md:justify-start gap-4 pt-4"> <a href="#projects" class="w-full sm:w-auto px-8 py-4 rounded-xl bg-gradient-to-r from-cyan-500 to-purple-600 hover:from-cyan-400 hover:to-purple-500 text-white font-bold transition-all duration-300 shadow-lg hover:shadow-cyan-500/25 flex items-center justify-center gap-2 hover:-translate-y-0.5"> ดูผลงานของฉัน <i data-lucide="arrow-right" class="w-5 h-5"></i> </a> <a href="#contact" class="w-full sm:w-auto px-8 py-4 rounded-xl bg-slate-900/60 border border-slate-800 hover:border-slate-700 hover:bg-slate-800/80 text-slate-300 font-bold transition-all duration-300 flex items-center justify-center gap-2"> ติดต่อฉัน <i data-lucide="mail" class="w-5 h-5"></i> </a> </div> <!-- Social Badges --> <div class="flex items-center justify-center md:justify-start gap-4 pt-6 text-slate-400"> <a href="https://github.com/thban554" target="_blank" class="hover:text-cyan-400 transition-colors" aria-label="GitHub"> <i data-lucide="github" class="w-6 h-6"></i> </a> <a href="tel:097-056-6414" class="hover:text-cyan-400 transition-colors" aria-label="Phone"> <i data-lucide="phone" class="w-6 h-6"></i> </a> <a href="mailto:thban554@gmail.com" class="hover:text-cyan-400 transition-colors" aria-label="Email"> <i data-lucide="mail" class="w-6 h-6"></i> </a> </div> </div> <!-- Hero Graphic --> <div class="flex-grow flex justify-center order-1 md:order-2"> <div class="relative w-72 h-72 sm:w-80 sm:h-80 lg:w-[350px] lg:h-[350px] animate-float group"> <!-- Aura rings --> <div class="absolute inset-0 rounded-3xl bg-gradient-to-tr from-cyan-500 to-purple-500 opacity-20 blur-xl group-hover:opacity-35 transition-opacity duration-500"> </div> <!-- Outer border ring --> <div class="absolute inset-0 rounded-3xl border border-cyan-500/30 p-2"> <!-- Glass Box Inner Container --> <div class="w-full h-full rounded-2xl glass-panel overflow-hidden relative border-slate-800 bg-slate-900/40 backdrop-blur-md"> <img src="profile.jpg" alt="กรกฎ ใจมูล" class="w-full h-full object-cover rounded-xl group-hover:scale-105 transition-transform duration-500" loading="eager"> <!-- Name overlay badge --> <div class="absolute bottom-4 left-4 right-4 glass-panel px-4 py-3 rounded-xl border-slate-700/50 flex justify-between items-center"> <div> <h3 class="text-sm font-bold text-white font-outfit">กรกฎ ใจมูล</h3> <p class="text-[10px] text-cyan-400">Full-Stack Student / Developer</p> </div> <span class="text-xs bg-cyan-500/20 text-cyan-300 px-2.5 py-1 rounded-md border border-cyan-500/30 font-semibold">ฮาร์ทบิท</span> </div> </div> </div> </div> </div> </section> <!-- About Me Section --> <section id="about" class="py-16 md:py-24 border-t border-slate-900"> <div class="text-center max-w-3xl mx-auto mb-16"> <h2 class="text-3xl sm:text-4xl font-bold mb-4 font-outfit"> เกี่ยวกับฉัน & ทักษะความสามารถ </h2> <div class="h-1.5 w-20 bg-gradient-to-r from-cyan-400 to-purple-500 mx-auto rounded-full"></div> <p class="text-slate-400 mt-6 text-sm sm:text-base"> ประวัติการเรียนรู้ ความเชี่ยวชาญด้านเทคโนโลยีที่คัดสรรมาเพื่อตอบโจทย์งานระบบเว็บยุคใหม่ </p> </div> <!-- Tabbed Profile & Contact Row --> <div class="grid grid-cols-1 lg:grid-cols-12 gap-8 items-stretch mb-12"> <!-- Left Column (Profile Tab Card) --> <div class="lg:col-span-5 flex flex-col"> <!-- Tab Title --> <div class="flex"> <div class="px-6 py-2.5 rounded-t-xl bg-slate-900 border-t border-x border-slate-800 text-slate-200 font-semibold text-sm flex items-center gap-2"> <i data-lucide="user" class="w-4 h-4 text-cyan-400"></i> โปรไฟล์ </div> </div> <!-- Card Body --> <div class="flex-grow glass-panel p-6 rounded-b-2xl rounded-r-2xl border-slate-800/80 flex flex-col items-center justify-center text-center space-y-4"> <div class="relative w-48 h-48 rounded-2xl overflow-hidden border-2 border-cyan-500/20 shadow-lg shadow-cyan-500/5 group"> <img src="profile.jpg" alt="กรกฎ ใจมูล" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500"> </div> <div> <h3 class="text-2xl font-bold text-slate-100 font-outfit">กรกฎ ใจมูล</h3> <p class="text-sm text-cyan-400 mt-1">Student / Web Developer</p> </div> </div> </div> <!-- Right Column (About Me Tab Card) --> <div class="lg:col-span-7 flex flex-col"> <!-- Tab Title --> <div class="flex"> <div class="px-6 py-2.5 rounded-t-xl bg-gradient-to-r from-cyan-500/20 to-purple-500/20 border-t border-x border-cyan-500/30 text-cyan-300 font-semibold text-sm flex items-center gap-2"> <i data-lucide="info" class="w-4 h-4 text-cyan-400"></i> เกี่ยวกับฉัน </div> </div> <!-- Card Body --> <div class="flex-grow glass-panel p-6 sm:p-8 rounded-b-2xl rounded-l-2xl border-cyan-500/20 space-y-6"> <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> <!-- ข้อมูลส่วนตัว --> <div class="space-y-4"> <h4 class="text-lg font-bold text-slate-100 flex items-center gap-2 pb-2 border-b border-slate-800"> <i data-lucide="user-check" class="w-5 h-5 text-cyan-400"></i> ข้อมูลส่วนตัว </h4> <div class="space-y-3 text-sm"> <div class="flex justify-between border-b border-slate-900 pb-1.5"> <span class="text-slate-500">ชื่อจริง</span> <strong class="text-slate-200">กรกฎ ใจมูล</strong> </div> <div class="flex justify-between border-b border-slate-900 pb-1.5"> <span class="text-slate-500">ชื่อเล่น</span> <strong class="text-slate-200">ฮาร์ทบิท</strong> </div> <div class="flex justify-between border-b border-slate-900 pb-1.5"> <span class="text-slate-500">อายุ</span> <strong class="text-slate-200">18 ปี</strong> </div> </div> </div> <!-- ช่องทางการติดต่อ --> <div class="space-y-4"> <h4 class="text-lg font-bold text-slate-100 flex items-center gap-2 pb-2 border-b border-slate-800"> <i data-lucide="contact" class="w-5 h-5 text-purple-400"></i> ช่องทางการติดต่อ </h4> <div class="space-y-3 text-sm"> <a href="tel:097-056-6414" class="flex justify-between border-b border-slate-900 pb-1.5 hover:text-cyan-400 transition-colors group"> <span class="text-slate-500">โทร</span> <strong class="text-slate-200 group-hover:text-cyan-400">097-056-6414</strong> </a> <div class="flex justify-between border-b border-slate-900 pb-1.5"> <span class="text-slate-500">ที่อยู่</span> <strong class="text-slate-200 text-right">62 ถ.หลังตลาดทิพยเนตร ต.หายยา</strong> </div> <a href="mailto:thban554@gmail.com" class="flex justify-between border-b border-slate-900 pb-1.5 hover:text-cyan-400 transition-colors group"> <span class="text-slate-500">อีเมล</span> <strong class="text-slate-200 group-hover:text-cyan-400 text-xs sm:text-sm">thban554@gmail.com</strong> </a> </div> </div> </div> </div> </div> </div> <!-- Education, Work Experience & Activities Row --> <div class="grid grid-cols-1 lg:grid-cols-12 gap-8 items-stretch mb-12"> <!-- Education & Work Experience Card --> <div class="lg:col-span-6 glass-panel p-6 sm:p-8 rounded-2xl border-slate-800/80 space-y-6"> <!-- ประวัติทางการศึกษา --> <div class="space-y-4"> <h3 class="text-xl font-bold text-slate-100 flex items-center gap-3"> <i data-lucide="graduation-cap" class="w-6 h-6 text-cyan-400"></i> ประวัติทางการศึกษา </h3> <div class="relative pl-6 border-l border-slate-800 space-y-4"> <!-- Item 1 --> <div class="relative"> <div class="absolute -left-[30px] top-1.5 w-3.5 h-3.5 rounded-full bg-cyan-400 border-4 border-slate-950"></div> <h4 class="text-sm font-semibold text-slate-200">ประถมศึกษา</h4> <p class="text-xs text-slate-400 mt-0.5">โรงเรียนพุทธิโศภน</p> </div> <!-- Item 2 --> <div class="relative"> <div class="absolute -left-[30px] top-1.5 w-3.5 h-3.5 rounded-full bg-cyan-400 border-4 border-slate-950"></div> <h4 class="text-sm font-semibold text-slate-200">มัธยมต้น</h4> <p class="text-xs text-slate-400 mt-0.5">โรงเรียนวัฒโนทัยพายัพ</p> </div> <!-- Item 3 --> <div class="relative"> <div class="absolute -left-[30px] top-1.5 w-3.5 h-3.5 rounded-full bg-purple-500 border-4 border-slate-950"></div> <h4 class="text-sm font-semibold text-cyan-300">ปัจจุบัน</h4> <p class="text-xs text-slate-400 mt-0.5">วิทยาลัยเทคนิคเชียงใหม่</p> </div> </div> </div> <!-- ประสบการณ์ทำงาน --> <div class="space-y-4 pt-4 border-t border-slate-800"> <h3 class="text-xl font-bold text-slate-100 flex items-center gap-3"> <i data-lucide="briefcase" class="w-6 h-6 text-purple-400"></i> ประสบการณ์ทำงาน </h3> <div class="relative pl-6 border-l border-slate-800"> <div class="relative"> <div class="absolute -left-[30px] top-1.5 w-3.5 h-3.5 rounded-full bg-purple-500 border-4 border-slate-950"></div> <h4 class="text-sm font-semibold text-slate-200">ฝึกงานร้านซ่อม Macbook</h4> <p class="text-xs text-slate-400 mt-0.5">เคยฝึกงานอยู่ร้านซ่อม macbook เชียงใหม่</p> </div> </div> </div> </div> <!-- Favorite Activities Card --> <div class="lg:col-span-6 glass-panel p-6 sm:p-8 rounded-2xl border-slate-800/80 flex flex-col justify-between space-y-6"> <div class="space-y-4"> <h3 class="text-xl font-bold text-slate-100 flex items-center gap-3"> <i data-lucide="heart" class="w-6 h-6 text-pink-500 animate-pulse"></i> กิจกรรมที่ชอบ </h3> <div class="grid grid-cols-1 sm:grid-cols-2 gap-4 items-center"> <ul class="space-y-3 text-slate-300 text-sm"> <li class="flex items-center gap-2"> <span class="w-1.5 h-1.5 rounded-full bg-cyan-400"></span> เล่น rov, roblox </li> <li class="flex items-center gap-2"> <span class="w-1.5 h-1.5 rounded-full bg-cyan-400"></span> เล่นกับแมว </li> <li class="flex items-center gap-2"> <span class="w-1.5 h-1.5 rounded-full bg-cyan-400"></span> อ่านการ์ตูน </li> </ul> <!-- Cat Picture Container --> <div class="flex justify-center sm:justify-end"> <div class="relative w-36 h-36 rounded-2xl overflow-hidden border border-slate-800 shadow-md group"> <img src="cat.jpg" alt="น้องแมวสุดโปรด" class="w-full h-full object-cover group-hover:scale-110 transition-transform duration-500"> <div class="absolute bottom-2 left-2 right-2 bg-slate-950/70 backdrop-blur-sm px-2 py-0.5 rounded-lg text-center border border-slate-800"> <span class="text-[10px] text-slate-300 font-semibold">เล่นกับแมว 🐱</span> </div> </div> </div> </div> </div> <div class="pt-4 border-t border-slate-800"> <h4 class="text-xs font-bold uppercase text-slate-500 tracking-wider mb-2">ทักษะที่เกี่ยวข้องกับการฝึกงาน</h4> <div class="flex flex-wrap gap-1.5"> <span class="px-2 py-0.5 text-xs rounded bg-slate-900 border border-slate-800 text-slate-300">Mac Diagnostics</span> <span class="px-2 py-0.5 text-xs rounded bg-slate-900 border border-slate-800 text-slate-300">Hardware Assembly</span> <span class="px-2 py-0.5 text-xs rounded bg-slate-900 border border-slate-800 text-slate-300">macOS Troubleshooting</span> </div> </div> </div> </div> <!-- Skills Matrix (Underneath) --> <div class="space-y-6"> <h3 class="text-xl sm:text-2xl font-bold text-slate-100 flex items-center gap-3 px-2"> <i data-lucide="code-2" class="w-6 h-6 text-purple-400"></i> ทักษะการพัฒนา (Skills Matrix) </h3> <div class="grid grid-cols-1 md:grid-cols-3 gap-4"> <!-- Frontend Glass Card --> <div class="glass-panel p-5 rounded-2xl border-slate-800"> <div class="flex items-center space-x-2.5 text-cyan-400 mb-4"> <i data-lucide="layout" class="w-5 h-5"></i> <h4 class="font-bold text-slate-100">Frontend</h4> </div> <div class="flex flex-wrap gap-2"> <span class="px-2.5 py-1 text-xs rounded-lg bg-slate-900 border border-slate-800 text-slate-300">HTML5 / CSS3</span> <span class="px-2.5 py-1 text-xs rounded-lg bg-slate-900 border border-slate-800 text-slate-300">JavaScript (ES6+)</span> <span class="px-2.5 py-1 text-xs rounded-lg bg-slate-900 border border-slate-800 text-slate-300">React.js</span> <span class="px-2.5 py-1 text-xs rounded-lg bg-slate-900 border border-slate-800 text-slate-300">Next.js</span> <span class="px-2.5 py-1 text-xs rounded-lg bg-slate-900 border border-slate-800 text-slate-300">Tailwind CSS</span> <span class="px-2.5 py-1 text-xs rounded-lg bg-slate-900 border border-slate-800 text-slate-300">Bootstrap</span> </div> </div> <!-- Backend Glass Card --> <div class="glass-panel p-5 rounded-2xl border-slate-800"> <div class="flex items-center space-x-2.5 text-purple-400 mb-4"> <i data-lucide="server" class="w-5 h-5"></i> <h4 class="font-bold text-slate-100">Backend</h4> </div> <div class="flex flex-wrap gap-2"> <span class="px-2.5 py-1 text-xs rounded-lg bg-slate-900 border border-slate-800 text-slate-300">Node.js</span> <span class="px-2.5 py-1 text-xs rounded-lg bg-slate-900 border border-slate-800 text-slate-300">Express.js</span> <span class="px-2.5 py-1 text-xs rounded-lg bg-slate-900 border border-slate-800 text-slate-300">PHP (Laravel)</span> <span class="px-2.5 py-1 text-xs rounded-lg bg-slate-900 border border-slate-800 text-slate-300">FastAPI</span> <span class="px-2.5 py-1 text-xs rounded-lg bg-slate-900 border border-slate-800 text-slate-300">RESTful APIs</span> </div> </div> <!-- Databases & DevOps --> <div class="glass-panel p-5 rounded-2xl border-slate-800"> <div class="flex items-center space-x-2.5 text-teal-400 mb-4"> <i data-lucide="database" class="w-5 h-5"></i> <h4 class="font-bold text-slate-100">Database / DevOps</h4> </div> <div class="flex flex-wrap gap-2"> <span class="px-2.5 py-1 text-xs rounded-lg bg-slate-900 border border-slate-800 text-slate-300">MySQL</span> <span class="px-2.5 py-1 text-xs rounded-lg bg-slate-900 border border-slate-800 text-slate-300">PostgreSQL</span> <span class="px-2.5 py-1 text-xs rounded-lg bg-slate-900 border border-slate-800 text-slate-300">MongoDB</span> <span class="px-2.5 py-1 text-xs rounded-lg bg-slate-900 border border-slate-800 text-slate-300">Git / GitHub</span> <span class="px-2.5 py-1 text-xs rounded-lg bg-slate-900 border border-slate-800 text-slate-300">Docker</span> <span class="px-2.5 py-1 text-xs rounded-lg bg-slate-900 border border-slate-800 text-slate-300">Firebase</span> </div> </div> </div> </div> </section> <!-- Projects Portfolio Section --> <section id="projects" class="py-16 md:py-24 border-t border-slate-900"> <div class="text-center max-w-3xl mx-auto mb-12"> <h2 class="text-3xl sm:text-4xl font-bold mb-4 font-outfit"> แฟ้มสะสมผลงาน (Portfolio) </h2> <div class="h-1.5 w-20 bg-gradient-to-r from-cyan-400 to-purple-500 mx-auto rounded-full"></div> <p class="text-slate-400 mt-6 text-sm sm:text-base"> โปรเจกต์ที่ผ่านการพัฒนาด้วยความประณีต รองรับการแสดงผลหน้าจอมือถือและเดสก์ท็อปอย่างสมบูรณ์แบบ </p> </div> <!-- Filter Controls --> <div class="flex flex-wrap items-center justify-center gap-2 mb-12"> <button class="filter-btn px-5 py-2 rounded-xl text-sm font-semibold border border-slate-800 bg-slate-900/60 text-slate-300 hover:border-cyan-500/50 hover:text-cyan-400 transition-all duration-300" data-filter="all">ทั้งหมด</button> <button class="filter-btn px-5 py-2 rounded-xl text-sm font-semibold border border-slate-800 bg-slate-900/60 text-slate-300 hover:border-cyan-500/50 hover:text-cyan-400 transition-all duration-300" data-filter="frontend">Frontend</button> <button class="filter-btn px-5 py-2 rounded-xl text-sm font-semibold border border-slate-800 bg-slate-900/60 text-slate-300 hover:border-purple-500/50 hover:text-purple-400 transition-all duration-300" data-filter="backend">Backend</button> <button class="filter-btn px-5 py-2 rounded-xl text-sm font-semibold border border-slate-800 bg-slate-900/60 text-slate-300 hover:border-teal-500/50 hover:text-teal-400 transition-all duration-300" data-filter="fullstack">Full-Stack</button> </div> <!-- Projects Grid --> <div id="projects-grid" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8"> <!-- Rendered Dynamically via JS --> </div> </section> <!-- Contact Section --> <section id="contact" class="py-16 md:py-24 border-t border-slate-900"> <div class="text-center max-w-3xl mx-auto mb-16"> <h2 class="text-3xl sm:text-4xl font-bold mb-4 font-outfit"> ติดต่อฉัน (Contact Me) </h2> <div class="h-1.5 w-20 bg-gradient-to-r from-cyan-400 to-purple-500 mx-auto rounded-full"></div> <p class="text-slate-400 mt-6 text-sm sm:text-base"> หากมีข้อเสนอแนะ ข้อซักถาม หรือสนใจร่วมงาน สามารถส่งข้อความหาผมได้โดยตรงผ่านช่องทางด้านล่างครับ </p> </div> <div class="grid grid-cols-1 lg:grid-cols-12 gap-12 items-stretch"> <!-- Contact Channels (Left) --> <div class="lg:col-span-5 space-y-6 flex flex-col justify-between"> <div class="space-y-6"> <h3 class="text-xl sm:text-2xl font-bold text-slate-100 flex items-center gap-3"> <i data-lucide="message-square-plus" class="w-6 h-6 text-cyan-400"></i> พูดคุยและแลกเปลี่ยน </h3> <p class="text-slate-300 leading-relaxed text-sm sm:text-base"> ยินดีรับคำแนะนำ โปรเจกต์ฟรีแลนซ์ และโอกาสร่วมงานทุกประเภท ยินดีที่จะพูดคุยเกี่ยวกับสถาปัตยกรรมเว็บแอปพลิเคชันและการออกแบบระบบที่รองรับการปรับขยาย </p> </div> <!-- Cards representing contact channels --> <div class="space-y-4 pt-6"> <a href="mailto:thban554@gmail.com" class="flex items-center space-x-4 p-4 rounded-2xl glass-panel glass-panel-hover border-slate-800 transition-all duration-300"> <div class="w-12 h-12 rounded-xl bg-cyan-500/10 flex items-center justify-center text-cyan-400"> <i data-lucide="mail" class="w-6 h-6"></i> </div> <div> <span class="text-slate-500 text-xs block font-semibold uppercase">Email</span> <span class="text-slate-200 text-sm sm:text-base font-medium">thban554@gmail.com</span> </div> </a> <a href="tel:097-056-6414" class="flex items-center space-x-4 p-4 rounded-2xl glass-panel glass-panel-hover border-slate-800 transition-all duration-300"> <div class="w-12 h-12 rounded-xl bg-purple-500/10 flex items-center justify-center text-purple-400"> <i data-lucide="phone" class="w-6 h-6"></i> </div> <div> <span class="text-slate-500 text-xs block font-semibold uppercase">Phone</span> <span class="text-slate-200 text-sm sm:text-base font-medium">097-056-6414</span> </div> </a> <a href="https://github.com/thban554" target="_blank" class="flex items-center space-x-4 p-4 rounded-2xl glass-panel glass-panel-hover border-slate-800 transition-all duration-300"> <div class="w-12 h-12 rounded-xl bg-slate-500/15 flex items-center justify-center text-slate-300"> <i data-lucide="github" class="w-6 h-6"></i> </div> <div> <span class="text-slate-500 text-xs block font-semibold uppercase">GitHub</span> <span class="text-slate-200 text-sm sm:text-base font-medium">github.com/thban554</span> </div> </a> </div> </div> <!-- Contact Form (Right) --> <div class="lg:col-span-7"> <form id="contact-form" class="glass-panel p-6 sm:p-8 rounded-2xl border-slate-800 space-y-6 flex flex-col justify-between h-full"> <div class="space-y-4"> <!-- Name Input --> <div> <label for="name" class="block text-sm font-semibold text-slate-300 mb-2">ชื่อของคุณ *</label> <input type="text" id="name" required class="w-full px-4 py-3 rounded-xl bg-slate-950 border border-slate-800 text-slate-200 focus:outline-none focus:border-cyan-500/70 focus:ring-1 focus:ring-cyan-500/30 transition-all duration-300 placeholder:text-slate-600 text-sm sm:text-base" placeholder="ระบุชื่อ-นามสกุล"> </div> <!-- Email Input --> <div> <label for="email" class="block text-sm font-semibold text-slate-300 mb-2">อีเมลติดต่อกลับ *</label> <input type="email" id="email" required class="w-full px-4 py-3 rounded-xl bg-slate-950 border border-slate-800 text-slate-200 focus:outline-none focus:border-cyan-500/70 focus:ring-1 focus:ring-cyan-500/30 transition-all duration-300 placeholder:text-slate-600 text-sm sm:text-base" placeholder="example@email.com"> </div> <!-- Subject Input --> <div> <label for="subject" class="block text-sm font-semibold text-slate-300 mb-2">หัวข้อ *</label> <input type="text" id="subject" required class="w-full px-4 py-3 rounded-xl bg-slate-950 border border-slate-800 text-slate-200 focus:outline-none focus:border-cyan-500/70 focus:ring-1 focus:ring-cyan-500/30 transition-all duration-300 placeholder:text-slate-600 text-sm sm:text-base" placeholder="หัวข้อการติดต่อ"> </div> <!-- Message Textarea --> <div> <label for="message" class="block text-sm font-semibold text-slate-300 mb-2">ข้อความ *</label> <textarea id="message" rows="5" required class="w-full px-4 py-3 rounded-xl bg-slate-950 border border-slate-800 text-slate-200 focus:outline-none focus:border-cyan-500/70 focus:ring-1 focus:ring-cyan-500/30 transition-all duration-300 placeholder:text-slate-600 text-sm sm:text-base resize-none" placeholder="ระบุรายละเอียดข้อความของคุณที่นี่..."></textarea> </div> </div> <!-- Submit Button --> <button type="submit" id="submit-btn" class="w-full mt-4 px-6 py-4 rounded-xl bg-gradient-to-r from-cyan-500 to-purple-600 hover:from-cyan-400 hover:to-purple-500 text-white font-bold transition-all duration-300 shadow-lg hover:shadow-cyan-500/20 flex items-center justify-center gap-2"> <i data-lucide="send" class="w-5 h-5"></i> ส่งข้อความ </button> </form> </div> </div> </section> </main> <!-- Footer --> <footer class="border-t border-slate-900 bg-slate-950/80 backdrop-blur-md py-12 relative z-10"> <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 flex flex-col md:flex-row items-center justify-between gap-6"> <div class="flex items-center space-x-2"> <div class="w-8 h-8 rounded-lg bg-gradient-to-tr from-cyan-400 to-purple-500 flex items-center justify-center"> <span class="text-white font-bold text-base font-outfit">P</span> </div> <span class="font-outfit font-bold text-slate-200 text-sm">Portfolio © 2026</span> </div> <p class="text-slate-500 text-xs sm:text-sm text-center md:text-right"> Designed & Built with ❤️ using Tailwind CSS & Vanilla JS. All rights reserved. </p> </div> </footer> <!-- Glass Toast Notification --> <div id="toast" class="fixed bottom-6 right-6 z-50 transform translate-y-24 opacity-0 transition-all duration-300 max-w-sm w-full"> <div class="glass-panel p-4 rounded-2xl border-emerald-500/30 bg-slate-900/90 shadow-2xl flex items-start space-x-3"> <div class="w-10 h-10 rounded-xl bg-emerald-500/10 flex items-center justify-center text-emerald-400 flex-shrink-0"> <i data-lucide="check-circle" class="w-6 h-6"></i> </div> <div> <h4 class="font-bold text-slate-100 text-sm">ส่งข้อความสำเร็จ!</h4> <p class="text-slate-400 text-xs mt-1">ได้รับข้อความเรียบร้อยแล้ว ผมจะติดต่อกลับให้เร็วที่สุดครับ</p> </div> <button id="close-toast" class="text-slate-500 hover:text-slate-200 transition-colors ml-auto self-start"> <i data-lucide="x" class="w-4 h-4"></i> </button> </div> </div> <!-- Sticky Bottom Navigation for Mobile --> <div class="fixed bottom-6 left-1/2 -translate-x-1/2 w-[92%] max-w-md bg-slate-950/85 border border-slate-800/80 backdrop-blur-lg rounded-2xl h-16 flex items-center justify-between px-6 z-50 shadow-2xl md:hidden"> <a href="#hero" class="mobile-bottom-link flex flex-col items-center justify-center text-slate-400 hover:text-cyan-400 transition-colors py-1 min-h-[44px]" data-section="hero"> <i data-lucide="home" class="w-5 h-5"></i> <span class="text-[10px] mt-1 font-medium">หน้าแรก</span> </a> <a href="#about" class="mobile-bottom-link flex flex-col items-center justify-center text-slate-400 hover:text-cyan-400 transition-colors py-1 min-h-[44px]" data-section="about"> <i data-lucide="user" class="w-5 h-5"></i> <span class="text-[10px] mt-1 font-medium">เกี่ยวกับฉัน</span> </a> <a href="#projects" class="mobile-bottom-link flex flex-col items-center justify-center text-slate-400 hover:text-cyan-400 transition-colors py-1 min-h-[44px]" data-section="projects"> <i data-lucide="folder-git-2" class="w-5 h-5"></i> <span class="text-[10px] mt-1 font-medium">ผลงาน</span> </a> <a href="#contact" class="mobile-bottom-link flex flex-col items-center justify-center text-slate-400 hover:text-cyan-400 transition-colors py-1 min-h-[44px]" data-section="contact"> <i data-lucide="mail" class="w-5 h-5"></i> <span class="text-[10px] mt-1 font-medium">ติดต่อ</span> </a> <!-- Divider --> <div class="h-8 w-[1px] bg-slate-800/80"></div> <!-- Burger Menu Button on Bottom Nav --> <button id="bottom-menu-btn" class="flex flex-col items-center justify-center text-slate-400 hover:text-cyan-400 transition-colors py-1 min-h-[44px] focus:outline-none"> <i data-lucide="menu" id="bottom-menu-icon" class="w-5 h-5 transition-transform duration-300"></i> <span class="text-[10px] mt-1 font-medium">เมนู</span> </button> </div> <!-- Bottom Menu Drawer Overlay --> <div id="bottom-drawer" class="fixed inset-0 bg-slate-950/60 backdrop-blur-sm z-40 hidden transition-opacity duration-300 opacity-0 md:hidden"></div> <div id="bottom-drawer-content" class="fixed bottom-0 left-0 right-0 bg-slate-900/95 border-t border-slate-800/80 rounded-t-3xl z-50 p-6 pb-12 space-y-4 shadow-2xl transition-all duration-300 transform translate-y-full md:hidden backdrop-blur-lg"> <div class="w-12 h-1.5 bg-slate-800 rounded-full mx-auto mb-2"></div> <div class="flex items-center justify-between pb-3 border-b border-slate-800/60"> <h3 class="font-outfit font-bold text-lg text-white">เมนูเพิ่มเติม</h3> <div class="flex items-center gap-2"> <!-- Theme Toggle Button (Mobile) --> <button id="theme-toggle-mobile" class="p-2 rounded-xl bg-slate-950/40 border border-slate-800/60 text-slate-300 hover:text-cyan-400 transition-all min-h-[44px] flex items-center justify-center" aria-label="Toggle Theme"> <i data-lucide="sun" id="theme-toggle-icon-mobile" class="w-4.5 h-4.5"></i> </button> <button id="close-drawer-btn" class="text-slate-400 hover:text-white transition-colors min-h-[44px] flex items-center justify-center"> <i data-lucide="x" class="w-5 h-5"></i> </button> </div> </div> <div class="grid grid-cols-2 gap-3 py-2"> <a href="#hero" class="drawer-nav-link flex flex-col items-center p-4 rounded-xl bg-slate-950/40 border border-slate-800/60 hover:border-cyan-500/30 text-slate-300 hover:text-cyan-400 transition-all min-h-[44px]" data-section="hero"> <i data-lucide="home" class="w-6 h-6 text-cyan-400"></i> <span class="text-xs font-semibold mt-2">หน้าแรก</span> </a> <a href="#about" class="drawer-nav-link flex flex-col items-center p-4 rounded-xl bg-slate-950/40 border border-slate-800/60 hover:border-cyan-500/30 text-slate-300 hover:text-cyan-400 transition-all min-h-[44px]" data-section="about"> <i data-lucide="user" class="w-6 h-6 text-purple-400"></i> <span class="text-xs font-semibold mt-2">เกี่ยวกับฉัน</span> </a> <a href="#projects" class="drawer-nav-link flex flex-col items-center p-4 rounded-xl bg-slate-950/40 border border-slate-800/60 hover:border-cyan-500/30 text-slate-300 hover:text-cyan-400 transition-all min-h-[44px]" data-section="projects"> <i data-lucide="folder-git-2" class="w-6 h-6 text-emerald-400"></i> <span class="text-xs font-semibold mt-2">ผลงาน</span> </a> <a href="#contact" class="drawer-nav-link flex flex-col items-center p-4 rounded-xl bg-slate-950/40 border border-slate-800/60 hover:border-cyan-500/30 text-slate-300 hover:text-cyan-400 transition-all min-h-[44px]" data-section="contact"> <i data-lucide="mail" class="w-6 h-6 text-pink-400"></i> <span class="text-xs font-semibold mt-2">ติดต่อ</span> </a> </div> <!-- Social channels in Drawer --> <div class="flex items-center justify-around py-3 border-t border-slate-800/60"> <a href="https://github.com/thban554" target="_blank" class="flex items-center gap-2 text-slate-400 hover:text-cyan-400 transition-colors text-xs py-2 min-h-[44px]"> <i data-lucide="github" class="w-4 h-4"></i> GitHub </a> <a href="tel:097-056-6414" class="flex items-center gap-2 text-slate-400 hover:text-cyan-400 transition-colors text-xs py-2 min-h-[44px]"> <i data-lucide="phone" class="w-4 h-4"></i> โทร </a> <a href="mailto:thban554@gmail.com" class="flex items-center gap-2 text-slate-400 hover:text-cyan-400 transition-colors text-xs py-2 min-h-[44px]"> <i data-lucide="mail" class="w-4 h-4"></i> อีเมล </a> </div> </div> <!-- Javascript Logic --> <script src="projects.js"></script> <script> // Initialize Lucide Icons lucide.createIcons(); // Elements const mainHeader = document.getElementById('main-header'); const mobileMenuBtn = document.getElementById('mobile-menu-btn'); const mobileDropdown = document.getElementById('mobile-dropdown'); const menuIcon = document.getElementById('menu-icon'); const projectsGrid = document.getElementById('projects-grid'); const filterBtns = document.querySelectorAll('.filter-btn'); const contactForm = document.getElementById('contact-form'); const toast = document.getElementById('toast'); const closeToast = document.getElementById('close-toast'); const navLinks = document.querySelectorAll('.nav-link'); const mobileNavLinks = document.querySelectorAll('.mobile-nav-link'); const mobileBottomLinks = document.querySelectorAll('.mobile-bottom-link'); const drawerNavLinks = document.querySelectorAll('.drawer-nav-link'); const bottomMenuBtn = document.getElementById('bottom-menu-btn'); const bottomMenuIcon = document.getElementById('bottom-menu-icon'); const bottomDrawer = document.getElementById('bottom-drawer'); const bottomDrawerContent = document.getElementById('bottom-drawer-content'); const closeDrawerBtn = document.getElementById('close-drawer-btn'); const themeToggle = document.getElementById('theme-toggle'); const themeToggleMobile = document.getElementById('theme-toggle-mobile'); const themeToggleIcon = document.getElementById('theme-toggle-icon'); const themeToggleIconMobile = document.getElementById('theme-toggle-icon-mobile'); // Theme Switcher Logic const htmlEl = document.documentElement; // Check local storage or default to dark const currentTheme = localStorage.getItem('theme') || 'dark'; if (currentTheme === 'light') { htmlEl.classList.remove('dark'); setTimeout(() => updateThemeIcons('light'), 50); } else { htmlEl.classList.add('dark'); setTimeout(() => updateThemeIcons('dark'), 50); } function updateThemeIcons(theme) { if (theme === 'dark') { themeToggleIcon.setAttribute('data-lucide', 'sun'); themeToggleIconMobile.setAttribute('data-lucide', 'sun'); } else { themeToggleIcon.setAttribute('data-lucide', 'moon'); themeToggleIconMobile.setAttribute('data-lucide', 'moon'); } lucide.createIcons(); } function toggleTheme() { if (htmlEl.classList.contains('dark')) { htmlEl.classList.remove('dark'); localStorage.setItem('theme', 'light'); updateThemeIcons('light'); } else { htmlEl.classList.add('dark'); localStorage.setItem('theme', 'dark'); updateThemeIcons('dark'); } } themeToggle.addEventListener('click', toggleTheme); themeToggleMobile.addEventListener('click', toggleTheme); // Mobile Drawer Toggle let isDrawerOpen = false; function openDrawer() { isDrawerOpen = true; bottomDrawer.classList.remove('hidden'); // Force reflow void bottomDrawer.offsetWidth; bottomDrawer.classList.remove('opacity-0'); bottomDrawer.classList.add('opacity-100'); bottomDrawerContent.classList.remove('translate-y-full'); bottomDrawerContent.classList.add('translate-y-0'); bottomMenuIcon.setAttribute('data-lucide', 'x'); lucide.createIcons(); } function closeDrawer() { isDrawerOpen = false; bottomDrawer.classList.remove('opacity-100'); bottomDrawer.classList.add('opacity-0'); bottomDrawerContent.classList.remove('translate-y-0'); bottomDrawerContent.classList.add('translate-y-full'); bottomMenuIcon.setAttribute('data-lucide', 'menu'); lucide.createIcons(); setTimeout(() => { if (!isDrawerOpen) { bottomDrawer.classList.add('hidden'); } }, 300); } bottomMenuBtn.addEventListener('click', () => { if (isDrawerOpen) { closeDrawer(); } else { openDrawer(); } }); closeDrawerBtn.addEventListener('click', closeDrawer); bottomDrawer.addEventListener('click', closeDrawer); // Close drawer when clicking any link inside drawerNavLinks.forEach(link => { link.addEventListener('click', closeDrawer); }); mobileBottomLinks.forEach(link => { link.addEventListener('click', closeDrawer); }); // 1. Navbar scroll states window.addEventListener('scroll', () => { if (window.scrollY > 20) { mainHeader.classList.add('bg-slate-950/80', 'backdrop-blur-md', 'border-b', 'border-slate-900', 'shadow-lg'); mainHeader.classList.remove('h-20'); mainHeader.classList.add('h-16'); } else { mainHeader.classList.remove('bg-slate-950/80', 'backdrop-blur-md', 'border-b', 'border-slate-900', 'shadow-lg'); mainHeader.classList.remove('h-16'); mainHeader.classList.add('h-20'); } }); // 2. Mobile Menu Toggle let isMenuOpen = false; mobileMenuBtn.addEventListener('click', () => { isMenuOpen = !isMenuOpen; if (isMenuOpen) { mobileDropdown.classList.remove('hidden'); // Trigger reflow for transition void mobileDropdown.offsetWidth; mobileDropdown.classList.remove('scale-y-95', 'opacity-0'); mobileDropdown.classList.add('scale-y-100', 'opacity-100'); menuIcon.setAttribute('data-lucide', 'x'); lucide.createIcons(); } else { closeMobileMenu(); } }); function closeMobileMenu() { isMenuOpen = false; mobileDropdown.classList.remove('scale-y-100', 'opacity-100'); mobileDropdown.classList.add('scale-y-95', 'opacity-0'); menuIcon.setAttribute('data-lucide', 'menu'); lucide.createIcons(); setTimeout(() => { if (!isMenuOpen) mobileDropdown.classList.add('hidden'); }, 300); } // Close menu when clicking mobile links mobileNavLinks.forEach(link => { link.addEventListener('click', closeMobileMenu); }); // 3. Populate & Filter Projects Grid function renderProjects(filterValue = 'all') { projectsGrid.innerHTML = ''; const filtered = projects.filter(project => { return filterValue === 'all' || project.category === filterValue; }); filtered.forEach(project => { const card = document.createElement('div'); card.className = 'project-card glass-panel rounded-2xl border-slate-800/80 overflow-hidden flex flex-col justify-between group transition-all duration-300 hover:border-cyan-500/30 hover:shadow-xl hover:shadow-cyan-500/5 hover:-translate-y-1'; // Tags elements markup const tagsMarkup = project.tags.map(tag => `<span class="px-2 py-0.5 text-[10px] sm:text-xs rounded bg-slate-900 border border-slate-800 text-slate-400">${tag}</span>` ).join(''); card.innerHTML = ` <div> <!-- Project Image Container --> <div class="relative overflow-hidden aspect-video border-b border-slate-900"> <img src="${project.image}" alt="${project.title}" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500" loading="lazy"> <div class="absolute inset-0 bg-gradient-to-t from-slate-950/80 to-transparent opacity-60"></div> </div> <!-- Details --> <div class="p-5 space-y-3"> <h3 class="text-lg sm:text-xl font-bold text-slate-100 group-hover:text-cyan-400 transition-colors duration-300">${project.title}</h3> <p class="text-slate-400 text-xs sm:text-sm leading-relaxed">${project.description}</p> </div> </div> <div class="p-5 pt-0 space-y-4"> <!-- Tech Badges --> <div class="flex flex-wrap gap-1.5"> ${tagsMarkup} </div> <!-- Links --> <div class="flex items-center gap-3 pt-2 border-t border-slate-900"> <a href="${project.githubUrl}" target="_blank" class="flex-1 py-2 px-3 rounded-lg bg-slate-900/50 hover:bg-slate-800/80 border border-slate-800 text-xs font-semibold text-slate-300 hover:text-white flex items-center justify-center gap-1.5 transition-all"> <i data-lucide="github" class="w-3.5 h-3.5"></i> Source Code </a> <a href="${project.liveUrl}" target="_blank" class="flex-1 py-2 px-3 rounded-lg bg-cyan-500/10 hover:bg-cyan-500/20 border border-cyan-500/20 hover:border-cyan-500/40 text-xs font-semibold text-cyan-400 flex items-center justify-center gap-1.5 transition-all"> <i data-lucide="external-link" class="w-3.5 h-3.5"></i> Live Demo </a> </div> </div> `; projectsGrid.appendChild(card); }); // Re-trigger icon creation for the newly generated elements lucide.createIcons(); } // Set Active Filter Button Style function updateActiveFilterButton(activeBtn) { filterBtns.forEach(btn => { btn.classList.remove('bg-gradient-to-r', 'from-cyan-500/20', 'to-purple-500/20', 'border-cyan-500/50', 'text-cyan-400'); btn.classList.add('bg-slate-900/60', 'text-slate-300', 'border-slate-800'); }); activeBtn.classList.remove('bg-slate-900/60', 'text-slate-300', 'border-slate-800'); activeBtn.classList.add('bg-gradient-to-r', 'from-cyan-500/20', 'to-purple-500/20', 'border-cyan-500/50', 'text-cyan-400'); } // Setup Filter Button Click Listeners filterBtns.forEach(btn => { btn.addEventListener('click', (e) => { const filterValue = e.target.getAttribute('data-filter'); updateActiveFilterButton(e.target); renderProjects(filterValue); }); }); // Initial Render of Projects renderProjects(); updateActiveFilterButton(filterBtns[0]); // default 'all' // 4. Contact Form Submission contactForm.addEventListener('submit', (e) => { e.preventDefault(); const submitBtn = document.getElementById('submit-btn'); const originalContent = submitBtn.innerHTML; // Show sending loader simulation submitBtn.disabled = true; submitBtn.innerHTML = `<svg class="animate-spin h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg> กำลังส่ง...`; setTimeout(() => { // Success State showToast(); contactForm.reset(); submitBtn.disabled = false; submitBtn.innerHTML = originalContent; }, 1500); }); // 5. Toast Notification System function showToast() { toast.classList.remove('translate-y-24', 'opacity-0'); toast.classList.add('translate-y-0', 'opacity-100'); setTimeout(() => { hideToast(); }, 5000); } function hideToast() { toast.classList.remove('translate-y-0', 'opacity-100'); toast.classList.add('translate-y-24', 'opacity-0'); } closeToast.addEventListener('click', hideToast); // 6. Intersection Observer to Highlight Active Nav Section const sections = document.querySelectorAll('section'); const observerOptions = { root: null, rootMargin: '-30% 0px -60% 0px', // triggers when section is in the middle of viewport threshold: 0 }; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const sectionId = entry.target.getAttribute('id'); highlightNav(sectionId); } }); }, observerOptions); sections.forEach(section => observer.observe(section)); function highlightNav(sectionId) { navLinks.forEach(link => { if (link.getAttribute('data-section') === sectionId) { link.classList.add('active-nav-link'); link.classList.remove('text-slate-300'); } else { link.classList.remove('active-nav-link'); link.classList.add('text-slate-300'); } }); mobileNavLinks.forEach(link => { if (link.getAttribute('data-section') === sectionId) { link.classList.add('bg-cyan-500/10', 'text-cyan-400'); link.classList.remove('text-slate-300'); } else { link.classList.remove('bg-cyan-500/10', 'text-cyan-400'); link.classList.add('text-slate-300'); } }); mobileBottomLinks.forEach(link => { if (link.getAttribute('data-section') === sectionId) { link.classList.add('text-cyan-400'); link.classList.remove('text-slate-400'); } else { link.classList.remove('text-cyan-400'); link.classList.add('text-slate-400'); } }); drawerNavLinks.forEach(link => { if (link.getAttribute('data-section') === sectionId) { link.classList.add('border-cyan-500/30', 'bg-slate-900/60', 'text-cyan-400'); link.classList.remove('border-slate-800/60', 'bg-slate-950/40', 'text-slate-300'); } else { link.classList.remove('border-cyan-500/30', 'bg-slate-900/60', 'text-cyan-400'); link.classList.add('border-slate-800/60', 'bg-slate-950/40', 'text-slate-300'); } }); } </script> <!-- ══ INTRO OVERLAY SCRIPT ══ --> <script> (function(){ const OV = document.getElementById('intro-overlay'); const body = document.body; // ── Skip if already seen this session ───────────────── // (Remove these 3 lines if you always want the intro) // if(sessionStorage.getItem('intro-done')){ dismissIntro(true); return; } // ── Cursor ──────────────────────────────────────────── const cur = document.getElementById('i-cursor'); const ring = document.getElementById('i-cursor-ring'); let mx=innerWidth/2, my=innerHeight/2, rx=mx, ry=my; OV.addEventListener('mousemove', e=>{ mx=e.clientX; my=e.clientY; cur.style.left=mx+'px'; cur.style.top=my+'px'; }); (function aRing(){ rx+=(mx-rx)*.12; ry+=(my-ry)*.12; ring.style.left=rx+'px'; ring.style.top=ry+'px'; if(!OV.classList.contains('intro-hidden')) requestAnimationFrame(aRing); else requestAnimationFrame(aRing); // keep running silently })(); OV.querySelectorAll('button').forEach(el=>{ el.addEventListener('mouseenter',()=>{ cur.style.width='20px'; cur.style.height='20px'; cur.style.background='#a855f7'; ring.style.width='56px'; ring.style.height='56px'; }); el.addEventListener('mouseleave',()=>{ cur.style.width='12px'; cur.style.height='12px'; cur.style.background='#22d3ee'; ring.style.width='40px'; ring.style.height='40px'; }); }); // ── Parallax ────────────────────────────────────────── const ibg = document.getElementById('i-bg'); let tX=0,tY=0,cX=0,cY=0; OV.addEventListener('mousemove',e=>{ tX=((e.clientX-innerWidth/2) /(innerWidth/2)) *24; tY=((e.clientY-innerHeight/2)/(innerHeight/2))*14; }); (function para(){ cX+=(tX-cX)*.045; cY+=(tY-cY)*.045; ibg.style.transform=`translate(${cX}px,${cY}px) scale(1.1)`; requestAnimationFrame(para); })(); // ── Particles ───────────────────────────────────────── const cv = document.getElementById('i-canvas'); const ctx = cv.getContext('2d'); let pts=[]; function resizeCV(){ cv.width=innerWidth; cv.height=innerHeight; } resizeCV(); window.addEventListener('resize',resizeCV); function mkPt(){ return{x:Math.random()*cv.width,y:cv.height+10, r:Math.random()*1.4+.4,spd:Math.random()*.7+.25, col:Math.random()>.5?'34,211,238':'168,85,247', op:Math.random()*.5+.3,life:0,max:Math.random()*180+100}; } for(let i=0;i<65;i++){ const p=mkPt(); p.y=Math.random()*cv.height; p.life=Math.random()*p.max; pts.push(p); } (function dp(){ ctx.clearRect(0,0,cv.width,cv.height); pts.forEach((p,i)=>{ p.life++; const r=p.life/p.max, fade=r<.1?r/.1:r>.87?(1-r)/.13:1; p.y-=p.spd; p.x+=Math.sin(p.life*.025+i*.3)*.35; ctx.beginPath(); ctx.arc(p.x,p.y,p.r,0,Math.PI*2); ctx.fillStyle=`rgba(${p.col},${p.op*fade})`; ctx.fill(); if(p.life>=p.max) pts[i]=mkPt(); }); requestAnimationFrame(dp); })(); // ── Open cinematic bars ──────────────────────────────── setTimeout(()=>OV.classList.add('bars-open'),250); // ── Typewriter ──────────────────────────────────────── const phrases=['นักพัฒนาเว็บไซต์','Web Developer','UI / UX Designer','Full Stack Developer','Creative Coder','Student Developer']; let pi=0,ci=0,del=false; const tw=document.getElementById('i-tw'); function typeLoop(){ const w=phrases[pi]; if(!del){ tw.textContent=w.slice(0,++ci); if(ci===w.length){del=true;setTimeout(typeLoop,1800);return;} setTimeout(typeLoop,82); } else{ tw.textContent=w.slice(0,--ci); if(ci===0){del=false;pi=(pi+1)%phrases.length;setTimeout(typeLoop,340);return;} setTimeout(typeLoop,46); } } setTimeout(typeLoop,2100); // ── Glitch name ─────────────────────────────────────── const nm=document.getElementById('i-name'); setInterval(()=>{ if(Math.random()>.82){ nm.style.animation='iGlitch .28s steps(3) forwards'; setTimeout(()=>nm.style.animation='',320); } },3500); // ── Audio (local MP3) ─────────────────────────────── const disc = document.getElementById('i-disc'); const wb = document.getElementById('i-wavebars'); const ipause = document.getElementById('i-icon-pause'); const iplay = document.getElementById('i-icon-play'); const aud = document.getElementById('i-audio'); let playing = false; // ── Audio: autoplay muted → unmute + fade in ───────── // The <audio autoplay muted> attribute starts playback immediately. // We then unmute and fade volume from 0 to 0.65. aud.volume = 0; function fadeInAudio() { aud.muted = false; let v = 0; const t = setInterval(() => { v = Math.min(v + 0.015, 0.65); aud.volume = v; if (v >= 0.65) clearInterval(t); }, 80); } // Show playing UI and unmute as soon as audio actually starts playing aud.addEventListener('play', () => { if (!playing) { playing = true; disc.classList.add('playing'); wb.classList.remove('paused'); ipause.style.display = 'block'; iplay.style.display = 'none'; setTimeout(fadeInAudio, 500); // slight delay for smooth unmute } }, { once: true }); // Safety fallback: if browser still blocks autoplay → unlock on first click aud.addEventListener('error', () => { iplay.style.display = 'block'; ipause.style.display = 'none'; }); document.addEventListener('click', function tryUnlock() { if (!playing) { aud.muted = false; aud.play().then(() => { playing = true; disc.classList.add('playing'); wb.classList.remove('paused'); ipause.style.display = 'block'; iplay.style.display = 'none'; fadeInAudio(); }).catch(() => {}); } document.removeEventListener('click', tryUnlock); }); // Play/Pause toggle button document.getElementById('i-mtoggle').addEventListener('click', () => { if (playing) { aud.pause(); playing = false; disc.classList.remove('playing'); wb.classList.add('paused'); ipause.style.display = 'none'; iplay.style.display = 'block'; } else { aud.muted = false; aud.play(); playing = true; disc.classList.add('playing'); wb.classList.remove('paused'); ipause.style.display = 'block'; iplay.style.display = 'none'; if (aud.volume < 0.05) fadeInAudio(); } }); // ── Dismiss ─────────────────────────────────────────── function dismissIntro(instant) { // Fade out audio if (aud && !aud.paused) { let v = aud.volume; const ft = setInterval(() => { v = Math.max(v - 0.05, 0); aud.volume = v; if (v <= 0) { clearInterval(ft); aud.pause(); } }, 50); } // close bars OV.classList.remove('bars-open'); if(instant){ OV.remove(); body.style.overflow=''; cur.style.display='none'; ring.style.display='none'; return; } setTimeout(()=>{ OV.classList.add('intro-hidden'); setTimeout(()=>{ OV.remove(); body.style.overflow=''; }, 700); },350); // hide custom cursors so site cursor shows setTimeout(()=>{ cur.style.display='none'; ring.style.display='none'; body.style.cursor=''; },400); sessionStorage.setItem('intro-done','1'); } document.getElementById('i-enter-btn').addEventListener('click', ()=>dismissIntro(false)); document.addEventListener('keydown', e=>{ if(e.key==='Enter'||e.key===' ') dismissIntro(false); }); // key-hint pulse const kh=OV.querySelector('.i-key-hint'); setInterval(()=>{ if(kh) kh.style.opacity=kh.style.opacity==='0.5'?'0.2':'0.5'; },900); })(); </script> </body> </html>
| ver. 1.4 |
Github
|
.
| PHP 7.4.33 | Generation time: 0.31 |
proxy
|
phpinfo
|
Settings