File manager - Edit - /home/webapp69.cm.in.th/u69319090039/portfolio/index.html
Back
<!DOCTYPE html> <html lang="th" data-theme="light"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>นายหาญ (Han) | พอร์ตโฟลิโอส่วนตัวระดับมืออาชีพ</title> <!-- SEO Meta Tags --> <meta name="description" content="พอร์ตโฟลิโอส่วนตัวของ นายหาญ (Han) เด็กหนุ่มไทยใหญ่ผู้มีความฝันในการเป็น YouTuber, Streamer, Digital Artist, และ Content Creator ค้นหาทักษะ ประวัติการศึกษา และผลงานทั้งหมดที่นี่"> <meta name="keywords" content="หาญ, นายหาญ, Han, Portfolio, พอร์ตโฟลิโอ, YouTuber, Streamer, Digital Artist, วาดภาพดิจิทัล, แม่แจ่ม, เชียงใหม่, ไทยใหญ่, ฉาน, วิทยาลัยเทคนิคเชียงใหม่"> <meta name="author" content="นายหาญ"> <!-- Open Graph (Facebook) --> <meta property="og:type" content="website"> <meta property="og:title" content="นายหาญ (Han) | Portfolio - YouTuber, Streamer & Digital Artist"> <meta property="og:description" content="พอร์ตโฟลิโอส่วนตัวของ นายหาญ (Han) เด็กหนุ่มไทยใหญ่ผู้มีความฝันในการเป็น YouTuber, Streamer, Digital Artist, และ Content Creator"> <meta property="og:image" content="1.jpg"> <!-- Twitter --> <meta name="twitter:card" content="summary_large_image"> <meta name="twitter:title" content="นายหาญ (Han) | Portfolio"> <meta name="twitter:description" content="พอร์ตโฟลิโอส่วนตัวของ นายหาญ (Han) เด็กหนุ่มไทยใหญ่ผู้มีความฝันในการเป็น YouTuber, Streamer, Digital Artist, และ Content Creator"> <meta name="twitter:image" content="1.jpg"> <!-- Fonts: Inter & Prompt (Thai-friendly, highly modern typography) --> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=Prompt:wght@200;300;400;500;600;700&display=swap" rel="stylesheet"> <!-- FontAwesome 6 for Icons --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" integrity="sha512-iecdLmaskl7CVkqkXNQ/ZH/XLlvWZOJyj7Yy7tcenmpD1ypASozpmT/E0iPtmFIB46ZmdtAc9eNBvH0H/ZpiBw==" crossorigin="anonymous" referrerpolicy="no-referrer"> <style> /* ========================================================================== 1. Core Design System & CSS Variables ========================================================================== */ :root { /* Light Theme (Standard Mode) */ --bg-body: radial-gradient(circle at 10% 20%, rgba(243, 232, 255, 0.7) 0%, rgba(221, 214, 254, 0.6) 90%) fixed; --bg-base: #f8fafc; --bg-surface: rgba(255, 255, 255, 0.45); --bg-surface-opaque: #ffffff; --border-color: rgba(255, 255, 255, 0.5); --text-primary: #0f172a; --text-secondary: #475569; --text-muted: #64748b; --color-gold: #b45309; --color-gold-hover: #92400e; --color-gold-rgb: 180, 83, 9; --color-accent: #6366f1; --shadow-primary: rgba(109, 40, 217, 0.08); --shadow-hover: rgba(109, 40, 217, 0.15); --glass-blur: blur(16px); --nav-bg: rgba(248, 250, 252, 0.8); --nav-border: rgba(255, 255, 255, 0.3); --timeline-dot-bg: #f8fafc; --timeline-line-color: rgba(180, 83, 9, 0.25); /* Transitions */ --transition-fast: 0.2s cubic-bezier(0.4, 0, 0.2, 1); --transition-normal: 0.4s cubic-bezier(0.4, 0, 0.2, 1); --transition-slow: 0.8s cubic-bezier(0.4, 0, 0.2, 1); } [data-theme="dark"] { /* Dark Theme */ --bg-body: radial-gradient(circle at 10% 20%, #1e1b4b 0%, #0f0728 90%) fixed; --bg-base: #0b071e; --bg-surface: rgba(15, 7, 40, 0.55); --bg-surface-opaque: #0f0728; --border-color: rgba(255, 255, 255, 0.08); --text-primary: #f8fafc; --text-secondary: #cbd5e1; --text-muted: #94a3b8; --color-gold: #fbbf24; --color-gold-hover: #f59e0b; --color-gold-rgb: 251, 191, 36; --color-accent: #818cf8; --shadow-primary: rgba(0, 0, 0, 0.3); --shadow-hover: rgba(0, 0, 0, 0.55); --nav-bg: rgba(15, 7, 40, 0.85); --nav-border: rgba(255, 255, 255, 0.05); --timeline-dot-bg: #0f0728; --timeline-line-color: rgba(255, 255, 255, 0.1); } /* General Resets */ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } html { scroll-behavior: smooth; font-size: 16px; overflow-x: hidden; } body { font-family: 'Prompt', 'Inter', sans-serif; background: var(--bg-body); color: var(--text-primary); transition: background var(--transition-normal), color var(--transition-normal); overflow-x: hidden; line-height: 1.6; -webkit-font-smoothing: antialiased; } /* Hide Scrollbar for cleaner UI but allow scroll */ ::-webkit-scrollbar { width: 8px; } ::-webkit-scrollbar-track { background: var(--bg-base); } ::-webkit-scrollbar-thumb { background: var(--border-color); border-radius: 8px; } ::-webkit-scrollbar-thumb:hover { background: var(--color-gold); } a { color: inherit; text-decoration: none; transition: color var(--transition-fast); } ul { list-style: none; } img { max-width: 100%; height: auto; display: block; } section { padding: 100px 0; position: relative; z-index: 10; } /* Container */ .container { width: 100%; max-width: 1200px; margin: 0 auto; padding: 0 24px; } /* Title Helper */ .section-header { text-align: center; margin-bottom: 60px; } .section-subtitle { color: var(--color-gold); font-size: 13px; font-weight: 600; text-transform: uppercase; letter-spacing: 3px; display: block; margin-bottom: 8px; } .section-title { font-size: 36px; font-weight: 700; position: relative; display: inline-block; padding-bottom: 12px; } .section-title::after { content: ''; position: absolute; bottom: 0; left: 50%; transform: translateX(-50%); width: 60px; height: 4px; background-color: var(--color-gold); border-radius: 2px; transition: width var(--transition-normal); } /* ========================================================================== 2. Premium Glassmorphic Cards ========================================================================== */ .glass-card { background: var(--bg-surface); border: 1px solid var(--border-color); backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur); border-radius: 24px; padding: 36px; box-shadow: 0 12px 30px var(--shadow-primary); transition: transform var(--transition-normal), border-color var(--transition-normal), box-shadow var(--transition-normal); } .glass-card:hover { transform: translateY(-6px); border-color: rgba(var(--color-gold-rgb), 0.3); box-shadow: 0 16px 40px var(--shadow-hover); } /* ========================================================================== 3. Sticky Navbar (100% Custom Responsive) ========================================================================== */ header { position: fixed; top: 0; left: 0; width: 100%; z-index: 1000; transition: padding var(--transition-normal), background-color var(--transition-normal), border-bottom var(--transition-normal); } .navbar { padding: 24px 0; transition: padding var(--transition-normal); background: transparent; border-bottom: 1px solid transparent; } header.scrolled .navbar { padding: 14px 0; background-color: var(--nav-bg); backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur); border-bottom: 1px solid var(--nav-border); box-shadow: 0 4px 30px var(--shadow-primary); } .nav-container { display: flex; align-items: center; justify-content: space-between; } .logo { font-size: 24px; font-weight: 800; letter-spacing: 1px; } .logo span { color: var(--color-gold); } .nav-menu-wrapper { display: flex; align-items: center; gap: 24px; } .nav-links { display: flex; align-items: center; gap: 8px; } .nav-item { font-size: 15px; font-weight: 500; padding: 8px 16px; border-radius: 20px; position: relative; color: var(--text-secondary); } .nav-item:hover, .nav-item.active { color: var(--color-gold); } .nav-item::after { content: ''; position: absolute; bottom: 4px; left: 16px; width: 0; height: 2px; background-color: var(--color-gold); transition: width var(--transition-normal); } .nav-item:hover::after, .nav-item.active::after { width: calc(100% - 32px); } /* Nav Controls */ .nav-controls { display: flex; align-items: center; gap: 12px; } .icon-btn { width: 42px; height: 42px; border-radius: 50%; background: var(--bg-surface); border: 1px solid var(--border-color); color: var(--text-primary); display: flex; align-items: center; justify-content: center; cursor: pointer; font-size: 16px; transition: transform var(--transition-fast), background-color var(--transition-fast), color var(--transition-fast); } .icon-btn:hover { transform: scale(1.08); background-color: var(--color-gold); color: #000000; border-color: var(--color-gold); } /* Hamburger Toggle */ .menu-toggle { display: none; flex-direction: column; justify-content: space-between; width: 24px; height: 18px; cursor: pointer; background: none; border: none; outline: none; } .menu-toggle span { display: block; height: 2.5px; width: 100%; background-color: var(--text-primary); border-radius: 2px; transition: transform var(--transition-fast), opacity var(--transition-fast); } /* Mobile Responsive Navigation Drawer */ @media (max-width: 991px) { .menu-toggle { display: flex; z-index: 1100; } .nav-links { position: fixed; top: 0; right: -100%; width: 300px; height: 100vh; background-color: var(--bg-surface-opaque); border-left: 1px solid var(--border-color); box-shadow: -10px 0 30px var(--shadow-primary); flex-direction: column; justify-content: center; align-items: center; gap: 20px; transition: right var(--transition-normal); z-index: 1050; } .nav-links.open { right: 0; } .menu-toggle.open span:nth-child(1) { transform: translateY(8px) rotate(45deg); } .menu-toggle.open span:nth-child(2) { opacity: 0; } .menu-toggle.open span:nth-child(3) { transform: translateY(-8px) rotate(-45deg); } } /* ========================================================================== 4. Hero Section with Glow Ring Profile ========================================================================== */ .hero { min-height: 100vh; display: flex; align-items: center; padding-top: 130px; padding-bottom: 80px; overflow: hidden; } .hero-grid { display: grid; grid-template-columns: 1.2fr 0.8fr; gap: 60px; align-items: center; } .hero-text { display: flex; flex-direction: column; } .hero-welcome { font-size: 18px; font-weight: 600; color: var(--color-gold); text-transform: uppercase; letter-spacing: 3px; margin-bottom: 16px; } .hero-name { font-size: 60px; font-weight: 800; line-height: 1.15; margin-bottom: 16px; } .hero-name span.gold-txt { color: var(--color-gold); } .hero-sub { font-size: 24px; font-weight: 500; color: var(--text-secondary); margin-bottom: 24px; min-height: 38px; } .hero-moto { font-size: 16px; color: var(--text-muted); font-style: italic; margin-bottom: 36px; } .hero-buttons { display: flex; flex-wrap: wrap; gap: 16px; } /* Custom Button Styles */ .btn { display: inline-flex; align-items: center; justify-content: center; gap: 10px; padding: 12px 28px; font-size: 15px; font-weight: 600; border-radius: 30px; cursor: pointer; transition: transform var(--transition-fast), box-shadow var(--transition-fast), background-color var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast); } .btn-gold { background: linear-gradient(135deg, var(--color-gold) 0%, var(--color-gold-hover) 100%); color: #ffffff; border: none; box-shadow: 0 4px 15px rgba(var(--color-gold-rgb), 0.3); } .btn-gold:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(var(--color-gold-rgb), 0.45); } .btn-outline { background: var(--bg-surface); border: 2px solid var(--border-color); color: var(--text-primary); backdrop-filter: var(--glass-blur); } .btn-outline:hover { transform: translateY(-2px); border-color: var(--color-gold); color: var(--color-gold); background: rgba(var(--color-gold-rgb), 0.05); } .btn-youtube { background: rgba(220, 38, 38, 0.1); border: 2px solid rgba(220, 38, 38, 0.2); color: #dc2626; } .btn-youtube:hover { transform: translateY(-2px); background: #dc2626; border-color: #dc2626; color: #ffffff; box-shadow: 0 4px 15px rgba(220, 38, 38, 0.3); } /* Profile Image Styles */ .hero-img-col { display: flex; justify-content: center; } .profile-container { position: relative; width: 340px; height: 340px; max-width: 100%; } /* Glow animation */ .profile-glow { position: absolute; top: -15px; left: -15px; right: -15px; bottom: -15px; background: linear-gradient(135deg, var(--color-gold), var(--color-accent)); border-radius: 50%; filter: blur(20px); opacity: 0.35; z-index: 1; animation: pulseGlow 6s ease-in-out infinite alternate; } .profile-image-mask { position: relative; z-index: 2; width: 100%; height: 100%; border-radius: 50%; border: 6px solid var(--border-color); overflow: hidden; box-shadow: 0 10px 30px var(--shadow-primary); background: var(--bg-surface); } .profile-image-mask img { width: 100%; height: 100%; object-fit: cover; transition: transform var(--transition-normal); } .profile-container:hover .profile-image-mask img { transform: scale(1.06); } @keyframes pulseGlow { 0% { transform: scale(0.98); opacity: 0.3; } 100% { transform: scale(1.04); opacity: 0.55; } } @keyframes slowRotate { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @media (max-width: 991px) { .hero-grid { grid-template-columns: 1fr; gap: 48px; text-align: center; } .hero-buttons { justify-content: center; } .profile-container { width: 280px; height: 280px; } } /* ========================================================================== 5. About Me Section ========================================================================== */ .about-grid { display: grid; grid-template-columns: 1.1fr 0.9fr; gap: 40px; } .about-bio h3, .about-info h3 { font-size: 22px; font-weight: 600; color: var(--color-gold); margin-bottom: 20px; display: flex; align-items: center; gap: 10px; } .about-bio p { font-size: 15px; color: var(--text-secondary); margin-bottom: 16px; line-height: 1.8; text-indent: 30px; } .about-quote { margin-top: 30px; padding-top: 20px; border-top: 1px solid var(--border-color); font-style: italic; color: var(--text-muted); font-size: 14px; } .info-list { display: flex; flex-direction: column; gap: 16px; } .info-item { display: flex; align-items: flex-start; gap: 12px; padding-bottom: 12px; border-bottom: 1px solid var(--border-color); } .info-item:last-child { border-bottom: none; padding-bottom: 0; } .info-icon { font-size: 16px; color: var(--color-gold); margin-top: 4px; width: 20px; text-align: center; } .info-detail { display: flex; flex-direction: column; } .info-label { font-size: 13px; color: var(--text-muted); font-weight: 500; } .info-value { font-size: 15px; color: var(--text-primary); font-weight: 600; } .info-value a { color: inherit; } .info-value a:hover { color: var(--color-gold); } @media (max-width: 768px) { .about-grid { grid-template-columns: 1fr; gap: 30px; } } /* ========================================================================== 6. Education Timeline ========================================================================== */ .timeline { position: relative; max-width: 800px; margin: 0 auto; padding-left: 36px; } .timeline::before { content: ''; position: absolute; top: 6px; bottom: 6px; left: 10px; width: 2px; background-color: var(--timeline-line-color); } .timeline-item { position: relative; margin-bottom: 40px; } .timeline-item:last-child { margin-bottom: 0; } .timeline-dot { position: absolute; left: -33px; top: 6px; width: 14px; height: 14px; border-radius: 50%; background-color: var(--timeline-dot-bg); border: 3.5px solid var(--color-gold); z-index: 2; transition: transform var(--transition-fast), background-color var(--transition-fast); } .timeline-item:hover .timeline-dot { transform: scale(1.2); background-color: var(--color-gold); } .timeline-content { padding: 24px; border-radius: 20px; } .timeline-meta { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 10px; margin-bottom: 12px; } .timeline-year { display: inline-block; padding: 4px 14px; background: rgba(var(--color-gold-rgb), 0.1); color: var(--color-gold); font-size: 13px; font-weight: 600; border-radius: 20px; } .timeline-gpa { font-size: 13px; font-weight: 500; color: var(--text-secondary); background: var(--border-color); padding: 4px 10px; border-radius: 8px; } .timeline-title { font-size: 18px; font-weight: 700; margin-bottom: 6px; } .timeline-desc { font-size: 14px; color: var(--text-secondary); } /* ========================================================================== 7. Technical Skills & Counters ========================================================================== */ .skills-grid { display: grid; grid-template-columns: 1.15fr 0.85fr; gap: 50px; align-items: center; } .skills-bars { display: flex; flex-direction: column; gap: 20px; } .skill-bar-item { display: flex; flex-direction: column; } .skill-bar-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; } .skill-bar-name { font-size: 14px; font-weight: 600; color: var(--text-primary); } .skill-bar-percent { font-size: 13px; font-weight: 500; color: var(--color-gold); } .skill-bar-track { height: 8px; background-color: var(--border-color); border-radius: 10px; overflow: hidden; position: relative; } .skill-bar-fill { height: 100%; background: linear-gradient(90deg, var(--color-gold) 0%, var(--color-accent) 100%); border-radius: 10px; width: 0; /* Dynamic Transition via JS Intersection Observer */ transition: width 1.5s cubic-bezier(0.1, 0.8, 0.3, 1); } /* Counters styling */ .counters-container { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; } .counter-card { text-align: center; padding: 24px 16px; border-radius: 20px; } .counter-number { font-size: 40px; font-weight: 800; color: var(--color-gold); margin-bottom: 4px; font-family: 'Inter', sans-serif; } .counter-label { font-size: 13px; color: var(--text-secondary); font-weight: 500; text-transform: uppercase; letter-spacing: 0.5px; } @media (max-width: 768px) { .skills-grid { grid-template-columns: 1fr; gap: 40px; } } /* ========================================================================== 8. Portfolio Gallery (CSS Grid & Hover Overlays) ========================================================================== */ .portfolio-filter { display: flex; justify-content: center; gap: 12px; margin-bottom: 40px; flex-wrap: wrap; } .filter-btn { background: var(--bg-surface); border: 1px solid var(--border-color); padding: 8px 20px; font-size: 14px; font-weight: 500; border-radius: 25px; cursor: pointer; transition: background-color var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast), transform var(--transition-fast); } .filter-btn:hover, .filter-btn.active { background-color: var(--color-gold); color: #000000; border-color: var(--color-gold); transform: translateY(-2px); } .portfolio-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 28px; } .portfolio-item { border-radius: 20px; overflow: hidden; position: relative; box-shadow: 0 8px 25px var(--shadow-primary); background: var(--bg-surface); border: 1px solid var(--border-color); transition: transform var(--transition-normal), box-shadow var(--transition-normal); aspect-ratio: 16/11; } .portfolio-item:hover { transform: translateY(-6px); box-shadow: 0 16px 35px var(--shadow-hover); } .portfolio-image { width: 100%; height: 100%; object-fit: cover; transition: transform var(--transition-slow); } .portfolio-item:hover .portfolio-image { transform: scale(1.08); } .portfolio-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(15, 7, 40, 0.85); backdrop-filter: blur(4px); display: flex; flex-direction: column; justify-content: center; align-items: center; padding: 24px; text-align: center; opacity: 0; transition: opacity var(--transition-normal); z-index: 5; } .portfolio-item:hover .portfolio-overlay { opacity: 1; } .portfolio-cat { font-size: 11px; font-weight: 600; color: var(--color-gold); text-transform: uppercase; letter-spacing: 2px; margin-bottom: 8px; transform: translateY(12px); transition: transform var(--transition-normal); } .portfolio-title { font-size: 18px; font-weight: 700; color: #ffffff; margin-bottom: 12px; transform: translateY(12px); transition: transform var(--transition-normal); transition-delay: 0.05s; } .portfolio-item:hover .portfolio-cat, .portfolio-item:hover .portfolio-title { transform: translateY(0); } .lightbox-trigger-btn { width: 44px; height: 44px; background: var(--color-gold); color: #000000; border-radius: 50%; display: flex; align-items: center; justify-content: center; cursor: pointer; font-size: 16px; box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3); transition: transform var(--transition-fast), background-color var(--transition-fast); transform: translateY(15px); transition-delay: 0.1s; } .portfolio-item:hover .lightbox-trigger-btn { transform: translateY(0); } .lightbox-trigger-btn:hover { transform: scale(1.1); background-color: var(--color-gold-hover); } /* ========================================================================== 9. Goals Cards Section ========================================================================== */ .goals-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 24px; } .goal-card { text-align: center; display: flex; flex-direction: column; align-items: center; padding: 40px 24px; height: 100%; } .goal-icon-box { width: 70px; height: 70px; border-radius: 50%; background: rgba(var(--color-gold-rgb), 0.1); border: 1px solid rgba(var(--color-gold-rgb), 0.2); color: var(--color-gold); display: flex; align-items: center; justify-content: center; font-size: 26px; margin-bottom: 24px; transition: transform var(--transition-fast), background-color var(--transition-fast), color var(--transition-fast); } .goal-card:hover .goal-icon-box { transform: scale(1.08) rotate(6deg); background: var(--color-gold); color: #000000; } .goal-title { font-size: 20px; font-weight: 700; margin-bottom: 12px; } .goal-desc { font-size: 14px; color: var(--text-secondary); line-height: 1.6; } /* ========================================================================== 10. Contact Info & Interactive Form ========================================================================== */ .contact-grid { display: grid; grid-template-columns: 0.9fr 1.1fr; gap: 40px; } .contact-details-box { display: flex; flex-direction: column; justify-content: space-between; height: 100%; } .contact-methods { display: flex; flex-direction: column; gap: 24px; } .contact-card-item { display: flex; align-items: center; gap: 16px; } .contact-icon-wrapper { width: 50px; height: 50px; border-radius: 16px; background: rgba(var(--color-gold-rgb), 0.1); border: 1px solid rgba(var(--color-gold-rgb), 0.15); color: var(--color-gold); display: flex; align-items: center; justify-content: center; font-size: 18px; flex-shrink: 0; } .contact-text-box h6 { font-size: 13px; color: var(--text-muted); font-weight: 500; margin-bottom: 2px; } .contact-text-box p { font-size: 15px; font-weight: 600; color: var(--text-primary); } .contact-socials-wrapper { margin-top: 36px; padding-top: 24px; border-top: 1px solid var(--border-color); } .contact-socials-title { font-size: 14px; font-weight: 600; color: var(--text-secondary); margin-bottom: 16px; } .social-flex { display: flex; gap: 12px; } .social-link { width: 40px; height: 40px; border-radius: 50%; background: var(--bg-surface); border: 1px solid var(--border-color); display: flex; align-items: center; justify-content: center; font-size: 16px; transition: transform var(--transition-fast), background-color var(--transition-fast), color var(--transition-fast); } .social-link:hover { transform: scale(1.1); background-color: var(--color-gold); color: #000000; border-color: var(--color-gold); } /* Form Controls */ .form-group { margin-bottom: 20px; } .form-label { display: block; font-size: 13px; font-weight: 600; color: var(--text-secondary); margin-bottom: 8px; } .form-input { width: 100%; background: var(--bg-surface); border: 1px solid var(--border-color); color: var(--text-primary); padding: 12px 18px; border-radius: 14px; font-family: inherit; font-size: 14px; transition: border-color var(--transition-fast), background-color var(--transition-fast); outline: none; } .form-input:focus { border-color: var(--color-gold); background-color: var(--bg-surface-opaque); } textarea.form-input { resize: vertical; min-height: 120px; } .submit-btn { width: 100%; padding: 14px 28px; border-radius: 14px; font-size: 15px; text-transform: uppercase; letter-spacing: 1px; } @media (max-width: 768px) { .contact-grid { grid-template-columns: 1fr; gap: 40px; } } /* ========================================================================== 11. Footer ========================================================================== */ footer { background-color: var(--bg-surface); border-top: 1px solid var(--border-color); padding: 40px 0; text-align: center; backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur); font-size: 14px; color: var(--text-secondary); position: relative; z-index: 100; } .footer-logo { font-size: 20px; font-weight: 800; margin-bottom: 12px; } .footer-logo span { color: var(--color-gold); } .footer-moto { font-size: 13px; font-style: italic; color: var(--text-muted); margin-bottom: 16px; } .footer-copyright { font-size: 12px; color: var(--text-muted); } /* ========================================================================== 12. Interactive UI Accessories (Back to Top & Modal Popup Lightbox) ========================================================================== */ /* Back to top button */ .back-to-top { position: fixed; bottom: 30px; right: 30px; width: 44px; height: 44px; border-radius: 50%; background-color: var(--color-gold); color: #000000; display: flex; align-items: center; justify-content: center; font-size: 18px; box-shadow: 0 4px 15px rgba(0,0,0,0.25); cursor: pointer; z-index: 999; opacity: 0; visibility: hidden; transform: translateY(15px); transition: opacity var(--transition-fast), visibility var(--transition-fast), transform var(--transition-fast), background-color var(--transition-fast); } .back-to-top.show { opacity: 1; visibility: visible; transform: translateY(0); } .back-to-top:hover { background-color: var(--color-gold-hover); } /* Toast notifications */ .toast-container { position: fixed; bottom: 30px; left: 30px; z-index: 1500; display: flex; flex-direction: column; gap: 10px; } .toast { background-color: var(--bg-surface-opaque); border: 1px solid var(--border-color); box-shadow: 0 10px 30px var(--shadow-primary); backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur); padding: 16px 24px; border-radius: 12px; color: var(--text-primary); font-size: 14px; font-weight: 500; display: flex; align-items: center; gap: 12px; transform: translateX(-120%); transition: transform 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); } .toast.show { transform: translateX(0); } .toast-icon { font-size: 18px; } .toast-success .toast-icon { color: #10b981; } .toast-info .toast-icon { color: var(--color-gold); } /* Lightbox Modal */ .lightbox-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(11, 7, 30, 0.95); backdrop-filter: blur(8px); z-index: 2000; display: flex; justify-content: center; align-items: center; opacity: 0; visibility: hidden; transition: opacity var(--transition-normal), visibility var(--transition-normal); } .lightbox-modal.show { opacity: 1; visibility: visible; } .lightbox-content { position: relative; max-width: 90%; max-height: 85%; display: flex; flex-direction: column; align-items: center; } .lightbox-image { max-width: 100%; max-height: 75vh; border-radius: 16px; object-fit: contain; box-shadow: 0 10px 40px rgba(0,0,0,0.5); transform: scale(0.95); transition: transform var(--transition-normal); } .lightbox-modal.show .lightbox-image { transform: scale(1); } .lightbox-caption { color: #ffffff; font-size: 15px; margin-top: 16px; text-align: center; font-weight: 500; } .lightbox-close { position: absolute; top: -40px; right: 0; background: none; border: none; color: #ffffff; font-size: 24px; cursor: pointer; transition: transform var(--transition-fast); } .lightbox-close:hover { transform: scale(1.15); } /* ========================================================================== 13. Scroll Animation System (CSS Side) ========================================================================== */ .reveal { opacity: 0; transform: translateY(30px); transition: opacity 0.8s cubic-bezier(0.4, 0, 0.2, 1), transform 0.8s cubic-bezier(0.4, 0, 0.2, 1); } .reveal.active { opacity: 1; transform: translateY(0); } .reveal-left { opacity: 0; transform: translateX(-40px); transition: opacity 0.8s cubic-bezier(0.4, 0, 0.2, 1), transform 0.8s cubic-bezier(0.4, 0, 0.2, 1); } .reveal-left.active { opacity: 1; transform: translateX(0); } .reveal-right { opacity: 0; transform: translateX(40px); transition: opacity 0.8s cubic-bezier(0.4, 0, 0.2, 1), transform 0.8s cubic-bezier(0.4, 0, 0.2, 1); } .reveal-right.active { opacity: 1; transform: translateX(0); } /* Ripple Effect */ .ripple { position: relative; overflow: hidden; } .ripple-effect { position: absolute; background: rgba(255, 255, 255, 0.35); border-radius: 50%; transform: scale(0); animation: ripple-anim 0.6s linear; pointer-events: none; } @keyframes ripple-anim { to { transform: scale(4); opacity: 0; } } </style> </head> <body> <!-- Header Section --> <header id="mainHeader"> <nav class="navbar"> <div class="container nav-container"> <a href="#" class="logo">HARN<span>.</span></a> <div class="nav-menu-wrapper"> <ul class="nav-links" id="navLinks"> <li><a href="#" class="nav-item active">หน้าแรก</a></li> <li><a href="#about" class="nav-item">เกี่ยวกับ</a></li> <li><a href="#education" class="nav-item">การศึกษา</a></li> <li><a href="#skills" class="nav-item">ทักษะ</a></li> <li><a href="#portfolio" class="nav-item">ผลงาน</a></li> <li><a href="#goals" class="nav-item">เป้าหมาย</a></li> <li><a href="#contact" class="nav-item">ติดต่อ</a></li> </ul> <div class="nav-controls"> <!-- Theme Toggle Button --> <button class="icon-btn" id="themeToggleBtn" aria-label="Toggle Light/Dark Mode"> <i class="fa-regular fa-moon" id="themeIcon"></i> </button> <!-- Language Selector (Future support) --> <button class="icon-btn" id="langToggleBtn" aria-label="Language Selector"> <span style="font-size: 12px; font-weight: 800;">TH</span> </button> <!-- Hamburger Button (Mobile) --> <button class="menu-toggle" id="menuToggleBtn" aria-label="Toggle menu"> <span></span> <span></span> <span></span> </button> </div> </div> </div> </nav> </header> <main> <!-- Hero Section --> <section id="home" class="hero"> <div class="container hero-grid"> <div class="hero-text reveal-left active"> <span class="hero-welcome">ยินดีต้อนรับสู่พอร์ตโฟลิโอของผม</span> <h1 class="hero-name">สวัสดีครับ ผมชื่อ <br><span class="gold-txt">นายหาญ</span></h1> <div class="hero-sub">ผมฝันอยากเป็น <span id="typingElement" style="color: var(--color-gold); font-weight: 700; border-right: 2.5px solid var(--color-gold);"></span></div> <p class="hero-moto">" Dream • Create • Inspire "</p> <div class="hero-buttons"> <a href="#about" class="btn btn-gold ripple">ดูประวัติ <i class="fa-regular fa-user"></i></a> <a href="#portfolio" class="btn btn-outline ripple">ผลงาน <i class="fa-regular fa-folder-open"></i></a> <a href="#contact" class="btn btn-outline ripple">ติดต่อ <i class="fa-regular fa-paper-plane"></i></a> <a href="https://www.youtube.com/@sevennine8624" target="_blank" class="btn btn-youtube ripple">YouTube <i class="fa-brands fa-youtube"></i></a> </div> </div> <div class="hero-img-col reveal-right active"> <div class="profile-container"> <div class="profile-glow"></div> <div class="profile-image-mask"> <img src="1.jpg" alt="รูปโปรไฟล์นายหาญ"> </div> </div> </div> </div> </section> <!-- About Me Section --> <section id="about"> <div class="container"> <div class="section-header reveal"> <span class="section-subtitle">ABOUT ME</span> <h2 class="section-title">แนะนำตัว</h2> </div> <div class="glass-card about-grid reveal"> <div class="about-bio"> <h3><i class="fa-solid fa-feather-pointed"></i> ประวัติความเป็นมา</h3> <p>สวัสดีครับ ผมชื่อ <strong>นายหาญ</strong> ไม่มีนามสกุลครับ สาเหตุที่ไม่มีนามสกุลเพราะว่าผมเป็นคน <strong>ไทยใหญ่ (ฉาน)</strong> พ่อและแม่พาผมอพยพเดินทางมาจากประเทศเมียนมาร์ และได้เข้ามาพึ่งพิงอาศัยอยู่ในผืนแผ่นดินไทยเป็นเวลานานกว่า 10 ปีแล้วครับ</p> <p>ปัจจุบันผมมีความมุ่งมั่นและตั้งใจอย่างสูงในการเรียนรู้และพัฒนาทักษะต่าง ๆ ไม่ว่าจะเป็นด้านเทคโนโลยีคอมพิวเตอร์ การสร้างสรรค์ผลงานภาพวาดดิจิทัล (Digital Art) รวมไปถึงการผลิตและตัดต่อวิดีโอ เพื่อเตรียมความพร้อมและปูทางในการก้าวไปสู่เป้าหมายชีวิตในอนาคต</p> <p class="about-quote">"ความฝันที่ชัดเจนและการเรียนรู้อย่างไม่หยุดยั้ง คือแรงขับเคลื่อนชีวิตของผม"</p> </div> <div class="about-info"> <h3><i class="fa-solid fa-address-card"></i> ข้อมูลส่วนตัว</h3> <div class="info-list"> <div class="info-item"> <div class="info-icon"><i class="fa-regular fa-calendar-days"></i></div> <div class="info-detail"> <span class="info-label">วันเกิด</span> <span class="info-value">19 กันยายน 2546 (อายุ 22 ปี)</span> </div> </div> <div class="info-item"> <div class="info-icon"><i class="fa-solid fa-map-location-dot"></i></div> <div class="info-detail"> <span class="info-label">ที่อยู่ปัจจุบัน</span> <span class="info-value">77 หมู่ 10 บ้านแม่ปาน ต.ช่างเคิ่ง อ.แม่แจ่ม จ.เชียงใหม่</span> </div> </div> <div class="info-item"> <div class="info-icon"><i class="fa-solid fa-mobile-screen-button"></i></div> <div class="info-detail"> <span class="info-label">เบอร์โทรศัพท์</span> <span class="info-value"><a href="tel:0621562410">062-156-2410</a></span> </div> </div> <div class="info-item"> <div class="info-icon"><i class="fa-regular fa-envelope"></i></div> <div class="info-detail"> <span class="info-label">อีเมล</span> <span class="info-value"><a href="mailto:paladinxx03@gmail.com">paladinxx03@gmail.com</a></span> </div> </div> <div class="info-item"> <div class="info-icon"><i class="fa-brands fa-facebook"></i></div> <div class="info-detail"> <span class="info-label">Facebook</span> <span class="info-value"><a href="https://www.facebook.com/profile.php?id=100062402121703" target="_blank">หาญ ฯ’</a></span> </div> </div> </div> </div> </div> </div> </section> <!-- Education Section --> <section id="education"> <div class="container"> <div class="section-header reveal"> <span class="section-subtitle">EDUCATION</span> <h2 class="section-title">ประวัติการศึกษา</h2> </div> <div class="timeline"> <!-- Education 4: Chiang Mai Technical College --> <div class="timeline-item reveal"> <div class="timeline-dot"></div> <div class="glass-card timeline-content"> <div class="timeline-meta"> <span class="timeline-year">ปัจจุบัน</span> <span class="timeline-gpa"><i class="fa-solid fa-book"></i> กำลังศึกษา</span> </div> <h3 class="timeline-title">วิทยาลัยเทคนิคเชียงใหม่</h3> <p class="timeline-desc">ระดับประกาศนียบัตรวิชาชีพชั้นสูง (ปวส.) แผนกอิเล็กทรอนิกส์ สาขาวิชาเทคโนโลยีคอมพิวเตอร์</p> </div> </div> <!-- Education 3: High School --> <div class="timeline-item reveal"> <div class="timeline-dot"></div> <div class="glass-card timeline-content"> <div class="timeline-meta"> <span class="timeline-year">มัธยมศึกษาตอนปลาย</span> <span class="timeline-gpa">เกรดเฉลี่ยสะสม: 3.45</span> </div> <h3 class="timeline-title">สกร. ระดับอำเภอแม่แจ่ม</h3> <p class="timeline-desc">ส่งเสริมการเรียนรู้อำเภอแม่แจ่ม (กศน. เดิม) สำนักงานส่งเสริมการเรียนรู้จังหวัดเชียงใหม่</p> </div> </div> <!-- Education 2: Middle School --> <div class="timeline-item reveal"> <div class="timeline-dot"></div> <div class="glass-card timeline-content"> <div class="timeline-meta"> <span class="timeline-year">มัธยมศึกษาตอนต้น</span> <span class="timeline-gpa">เกรดเฉลี่ยสะสม: 3.98</span> </div> <h3 class="timeline-title">โรงเรียนราชประชานุเคราะห์ 31</h3> <p class="timeline-desc">อำเภอแม่แจ่ม จังหวัดเชียงใหม่ (โรงเรียนศึกษาสงเคราะห์)</p> </div> </div> <!-- Education 1: Primary School --> <div class="timeline-item reveal"> <div class="timeline-dot"></div> <div class="glass-card timeline-content"> <div class="timeline-meta"> <span class="timeline-year">ประถมศึกษา</span> <span class="timeline-gpa">เกรดเฉลี่ยสะสม: 3.98</span> </div> <h3 class="timeline-title">โรงเรียนบ้านแม่ปาน</h3> <p class="timeline-desc">อำเภอแม่แจ่ม จังหวัดเชียงใหม่</p> </div> </div> </div> </div> </section> <!-- Technical Skills Section --> <section id="skills"> <div class="container"> <div class="section-header reveal"> <span class="section-subtitle">MY CAPABILITIES</span> <h2 class="section-title">ทักษะและความสามารถ</h2> </div> <div class="skills-grid reveal"> <!-- Progress bars (Left Column) --> <div class="glass-card skills-bars"> <!-- Skill 1: Python --> <div class="skill-bar-item"> <div class="skill-bar-header"> <span class="skill-bar-name">ภาษา Python ระดับพื้นฐาน</span> <span class="skill-bar-percent">70%</span> </div> <div class="skill-bar-track"> <div class="skill-bar-fill" data-width="70%"></div> </div> </div> <!-- Skill 2: Drawing --> <div class="skill-bar-item"> <div class="skill-bar-header"> <span class="skill-bar-name">วาดรูป</span> <span class="skill-bar-percent">90%</span> </div> <div class="skill-bar-track"> <div class="skill-bar-fill" data-width="90%"></div> </div> </div> </div> <!-- Counters (Right Column) --> <div class="counters-container"> <div class="glass-card counter-card"> <div class="counter-number" data-target="10" data-suffix="+">0</div> <div class="counter-label">ปีที่อยู่ในประเทศไทย</div> </div> <div class="glass-card counter-card"> <div class="counter-number" data-target="4">0</div> <div class="counter-label">ระดับการศึกษา</div> </div> <div class="glass-card counter-card"> <div class="counter-number" data-target="4">0</div> <div class="counter-label">เป้าหมายสูงสุด</div> </div> <div class="glass-card counter-card"> <div class="counter-number" data-target="2" data-suffix="+">0</div> <div class="counter-label">ทักษะความสามารถ</div> </div> </div> </div> </div> </section> <!-- Portfolio Showcase Section --> <section id="portfolio"> <div class="container"> <div class="section-header reveal"> <span class="section-subtitle">CREATIVE WORKS</span> <h2 class="section-title">ผลงานล่าสุด</h2> </div> <!-- Filters Tabs --> <div class="portfolio-filter reveal"> <button class="filter-btn active" data-filter="all">ทั้งหมด</button> <button class="filter-btn" data-filter="identity">ตัวตน / อัตลักษณ์</button> <button class="filter-btn" data-filter="art">งานศิลปะดิจิทัล</button> </div> <!-- Portfolio Grid --> <div class="portfolio-grid reveal"> <!-- Item 1 --> <div class="portfolio-item" data-category="identity"> <img src="1.jpg" alt="นายหาญ (Profile Banner)" class="portfolio-image" loading="lazy"> <div class="portfolio-overlay"> <span class="portfolio-cat">รูปประจำตัว / อัตลักษณ์</span> <h4 class="portfolio-title">นายหาญ (Profile Banner)</h4> <div class="lightbox-trigger-btn" data-img="1.jpg" data-caption="รูปประจำตัวและอัตลักษณ์หลักของ นายหาญ (Han)"> <i class="fa-solid fa-up-right-and-down-left-from-center"></i> </div> </div> </div> <!-- Item 2 --> <div class="portfolio-item" data-category="art"> <img src="art1.jpg" alt="Fantasy Landscape" class="portfolio-image" loading="lazy"> <div class="portfolio-overlay"> <span class="portfolio-cat">Digital Art / วาดภาพ</span> <h4 class="portfolio-title">Fantasy Landscape</h4> <div class="lightbox-trigger-btn" data-img="art1.jpg" data-caption="ผลงานภาพวาดธรรมชาติสไตล์แฟนตาซีแนวอนิเมะ"> <i class="fa-solid fa-up-right-and-down-left-from-center"></i> </div> </div> </div> <!-- Item 3 --> <div class="portfolio-item" data-category="art"> <img src="art2.jpg" alt="Character Illustration" class="portfolio-image" loading="lazy"> <div class="portfolio-overlay"> <span class="portfolio-cat">Digital Art / คอนเซปต์อาร์ต</span> <h4 class="portfolio-title">Character Illustration</h4> <div class="lightbox-trigger-btn" data-img="art2.jpg" data-caption="ผลงานวาดภาพตัวละครแนวแฟนตาซีพร้อมแสงเงาสมจริง"> <i class="fa-solid fa-up-right-and-down-left-from-center"></i> </div> </div> </div> <!-- Item 4 --> <div class="portfolio-item" data-category="art"> <img src="art3.jpg" alt="Cozy Setup Art" class="portfolio-image" loading="lazy"> <div class="portfolio-overlay"> <span class="portfolio-cat">Digital Art / แนว Lo-Fi</span> <h4 class="portfolio-title">Cozy Setup Art</h4> <div class="lightbox-trigger-btn" data-img="art3.jpg" data-caption="ผลงานจำลองห้องคอมพิวเตอร์สตรีมเมอร์ในบรรยากาศ Lo-Fi สุดอบอุ่น"> <i class="fa-solid fa-up-right-and-down-left-from-center"></i> </div> </div> </div> </div> </div> </section> <!-- Goals Section --> <section id="goals"> <div class="container"> <div class="section-header reveal"> <span class="section-subtitle">MY VISIONS</span> <h2 class="section-title">เป้าหมายในอนาคต</h2> </div> <div class="goals-grid"> <!-- Goal 1: YouTuber --> <div class="glass-card goal-card reveal"> <div class="goal-icon-box"><i class="fa-brands fa-youtube"></i></div> <h3 class="goal-title">YouTuber</h3> <p class="goal-desc">มุ่งมั่นสร้างวิดีโอคอนเทนต์ที่มีคุณค่า แบ่งปันประสบการณ์ด้านเทคโนโลยี ความรู้ และสร้างแรงบันดาลใจให้แก่ผู้ชมผ่านทางสื่อออนไลน์</p> </div> <!-- Goal 2: Streamer --> <div class="glass-card goal-card reveal"> <div class="goal-icon-box"><i class="fa-solid fa-gamepad"></i></div> <h3 class="goal-title">Streamer</h3> <p class="goal-desc">สร้างสรรค์พื้นที่ไลฟ์สตรีมเมอร์ที่อบอุ่น เล่นเกม พูดคุยแลกเปลี่ยนความคิดเห็น แลกเปลี่ยนรอยยิ้มกับผู้ชมอย่างสร้างสรรค์และมีความรับผิดชอบ</p> </div> <!-- Goal 3: Digital Artist --> <div class="glass-card goal-card reveal"> <div class="goal-icon-box"><i class="fa-solid fa-palette"></i></div> <h3 class="goal-title">Digital Artist</h3> <p class="goal-desc">พัฒนาเอกลักษณ์ในการวาดภาพดิจิทัล 2D สไตล์ต่าง ๆ ฝึกฝนเทคนิคแสงและเงาให้ดียิ่งขึ้น เพื่อก้าวไปสู่เวทีงานศิลปะระดับมืออาชีพ</p> </div> <!-- Goal 4: Content Creator --> <div class="glass-card goal-card reveal"> <div class="goal-icon-box"><i class="fa-solid fa-wand-magic-sparkles"></i></div> <h3 class="goal-title">Content Creator</h3> <p class="goal-desc">วางแผนและสร้างสรรค์คอนเทนต์รูปแบบใหม่ ทั้งในรูปแบบสื่อวิดีโอ กราฟิก และตัวอักษร เพื่อตอบโจทย์ยุคดิจิทัลอย่างไร้พรมแดน</p> </div> </div> </div> </section> <!-- Contact Section --> <section id="contact"> <div class="container"> <div class="section-header reveal"> <span class="section-subtitle">SAY HELLO</span> <h2 class="section-title">ติดต่อฉัน</h2> </div> <div class="contact-grid"> <!-- Contact details --> <div class="glass-card contact-details-box reveal-left"> <div> <h3 class="goal-title" style="color: var(--color-gold); margin-bottom: 24px; text-align: left;"><i class="fa-regular fa-comments"></i> มาร่วมสร้างสรรค์ผลงานกัน</h3> <div class="contact-methods"> <div class="contact-card-item"> <div class="contact-icon-wrapper"><i class="fa-solid fa-phone"></i></div> <div class="contact-text-box"> <h6>เบอร์โทรศัพท์</h6> <p><a href="tel:0621562410">062-156-2410</a></p> </div> </div> <div class="contact-card-item"> <div class="contact-icon-wrapper"><i class="fa-regular fa-envelope"></i></div> <div class="contact-text-box"> <h6>ที่อยู่อีเมล</h6> <p><a href="mailto:paladinxx03@gmail.com">paladinxx03@gmail.com</a></p> </div> </div> <div class="contact-card-item"> <div class="contact-icon-wrapper"><i class="fa-solid fa-map-location-dot"></i></div> <div class="contact-text-box"> <h6>ที่อยู่จัดส่งเอกสาร</h6> <p>77 หมู่ 10 บ้านแม่ปาน ต.ช่างเคิ่ง อ.แม่แจ่ม จ.เชียงใหม่</p> </div> </div> </div> </div> <div class="contact-socials-wrapper"> <div class="contact-socials-title">ติดตามความเคลื่อนไหว</div> <div class="social-flex"> <a href="https://www.facebook.com/profile.php?id=100062402121703" target="_blank" class="social-link" aria-label="Facebook"><i class="fa-brands fa-facebook-f"></i></a> <a href="https://www.youtube.com/@sevennine8624" target="_blank" class="social-link" aria-label="YouTube"><i class="fa-brands fa-youtube"></i></a> <a href="mailto:paladinxx03@gmail.com" class="social-link" aria-label="Email"><i class="fa-regular fa-envelope"></i></a> </div> </div> </div> <!-- Contact Form --> <div class="glass-card reveal-right"> <form id="contactForm" novalidate> <div class="form-group"> <label for="nameInput" class="form-label">ชื่อผู้ติดต่อ / หน่วยงาน *</label> <input type="text" id="nameInput" class="form-input" placeholder="กรอกชื่อของคุณ" required> </div> <div class="form-group"> <label for="emailInput" class="form-label">อีเมลติดต่อกลับ *</label> <input type="email" id="emailInput" class="form-input" placeholder="example@domain.com" required> </div> <div class="form-group"> <label for="messageInput" class="form-label">รายละเอียดข้อความ *</label> <textarea id="messageInput" class="form-input" placeholder="พิมพ์ข้อความของคุณที่นี่..." required></textarea> </div> <button type="submit" class="btn btn-gold submit-btn ripple" id="submitFormBtn">ส่งข้อความ <i class="fa-regular fa-paper-plane"></i></button> </form> </div> </div> </div> </section> </main> <!-- Footer --> <footer> <div class="container"> <div class="footer-logo">HARN<span>.</span></div> <div class="footer-moto">" Dream • Create • Inspire "</div> <div class="footer-copyright"> © 2026 Harn Portfolio. All rights reserved. <br> Designed & Developed by Harn </div> </div> </footer> <!-- Back to top button --> <div class="back-to-top" id="backToTopBtn" aria-label="Back to Top"><i class="fa-solid fa-arrow-up"></i></div> <!-- Toast Notifications Container --> <div class="toast-container" id="toastContainer"></div> <!-- Lightbox Modal Popup --> <div class="lightbox-modal" id="lightboxModal"> <div class="lightbox-content"> <button class="lightbox-close" id="lightboxCloseBtn" aria-label="Close Preview"><i class="fa-solid fa-xmark"></i></button> <img src="" alt="Enlarged view" class="lightbox-image" id="lightboxImg"> <div class="lightbox-caption" id="lightboxCaption"></div> </div> </div> <!-- Embedded Javascript for Rich & Premium Interactions --> <script> document.addEventListener('DOMContentLoaded', () => { /* ========================================================================== 1. Theme System (Light/Dark Mode Toggler) ========================================================================== */ const themeToggleBtn = document.getElementById('themeToggleBtn'); const themeIcon = document.getElementById('themeIcon'); const htmlElement = document.documentElement; // Detect current theme or local preferences const getPreferredTheme = () => { const savedTheme = localStorage.getItem('portfolio-theme'); if (savedTheme) { return savedTheme; } const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; return systemPrefersDark ? 'dark' : 'light'; }; const setTheme = (theme) => { htmlElement.setAttribute('data-theme', theme); localStorage.setItem('portfolio-theme', theme); // Update Icon styles if (theme === 'dark') { themeIcon.className = 'fa-regular fa-sun'; } else { themeIcon.className = 'fa-regular fa-moon'; } }; // Initialize Theme setTheme(getPreferredTheme()); // Switch themes smoothly themeToggleBtn.addEventListener('click', () => { const currentTheme = htmlElement.getAttribute('data-theme'); const newTheme = currentTheme === 'dark' ? 'light' : 'dark'; setTheme(newTheme); showToast('เปลี่ยนเป็นธีม ' + (newTheme === 'dark' ? 'มืด' : 'สว่าง') + ' สำเร็จ', 'info'); }); /* ========================================================================== 2. Mobile Menu Navigation Drawer & Scroll spy ========================================================================== */ const menuToggleBtn = document.getElementById('menuToggleBtn'); const navLinks = document.getElementById('navLinks'); const navItems = document.querySelectorAll('.nav-item'); const header = document.getElementById('mainHeader'); const sections = document.querySelectorAll('section'); // Open/Close menu menuToggleBtn.addEventListener('click', () => { menuToggleBtn.classList.toggle('open'); navLinks.classList.toggle('open'); }); // Close menu on nav item click navItems.forEach(item => { item.addEventListener('click', () => { menuToggleBtn.classList.remove('open'); navLinks.classList.remove('open'); }); }); // Sticky Navbar and Scroll spy logic (throttled for performance) let isScrolling = false; const checkScroll = () => { const scrollPos = window.scrollY; // Sticky Navbar toggling if (scrollPos > 50) { header.classList.add('scrolled'); } else { header.classList.remove('scrolled'); } // Back to top button toggling const backToTopBtn = document.getElementById('backToTopBtn'); if (scrollPos > 300) { backToTopBtn.classList.add('show'); } else { backToTopBtn.classList.remove('show'); } // Active nav item toggling based on section visibility let currentSec = ''; sections.forEach(sec => { const secTop = sec.offsetTop - 120; const secHeight = sec.offsetHeight; if (scrollPos >= secTop && scrollPos < secTop + secHeight) { currentSec = sec.getAttribute('id'); } }); if (currentSec) { navItems.forEach(link => { link.classList.remove('active'); const href = link.getAttribute('href'); if (href === '#' + currentSec || (href === '#' && currentSec === 'home')) { link.classList.add('active'); } }); } isScrolling = false; }; window.addEventListener('scroll', () => { if (!isScrolling) { window.requestAnimationFrame(checkScroll); isScrolling = true; } }); checkScroll(); // Trigger initial check // Back to Top button click document.getElementById('backToTopBtn').addEventListener('click', () => { window.scrollTo({ top: 0, behavior: 'smooth' }); }); /* ========================================================================== 3. Fast Typewriter Effect (No library, pure RequestAnimationFrame/SetTimeout) ========================================================================== */ const typingElement = document.getElementById('typingElement'); const roles = ['YouTuber', 'Streamer', 'Digital Artist', 'Content Creator']; let roleIndex = 0; let charIndex = 0; let isDeleting = false; const typeEffect = () => { const currentText = roles[roleIndex]; if (isDeleting) { typingElement.textContent = currentText.substring(0, charIndex - 1); charIndex--; } else { typingElement.textContent = currentText.substring(0, charIndex + 1); charIndex++; } let typingSpeed = isDeleting ? 40 : 80; if (!isDeleting && charIndex === currentText.length) { typingSpeed = 2000; // Delay when finished writing word isDeleting = true; } else if (isDeleting && charIndex === 0) { isDeleting = false; roleIndex = (roleIndex + 1) % roles.length; typingSpeed = 400; // Small delay before typing next word } setTimeout(typeEffect, typingSpeed); }; setTimeout(typeEffect, 1000); /* ========================================================================== 4. Reveal on Scroll Animation (CSS Class triggers) ========================================================================== */ const revealElements = document.querySelectorAll('.reveal, .reveal-left, .reveal-right'); const revealObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('active'); // Once animate completed, we don't need to observe it again revealObserver.unobserve(entry.target); } }); }, { threshold: 0.05, rootMargin: '0px 0px -40px 0px' }); revealElements.forEach(el => revealObserver.observe(el)); /* ========================================================================== 5. Skill Bar Progress Fill & Counter Animations ========================================================================== */ // Skill progress bars const skillBars = document.querySelectorAll('.skill-bar-fill'); const skillObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const fillEl = entry.target; const width = fillEl.getAttribute('data-width'); fillEl.style.width = width; skillObserver.unobserve(fillEl); } }); }, { threshold: 0.1 }); skillBars.forEach(bar => skillObserver.observe(bar)); // Numbers stats counters const counters = document.querySelectorAll('.counter-number'); const counterObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const counter = entry.target; const target = parseInt(counter.getAttribute('data-target'), 10); const suffix = counter.getAttribute('data-suffix') || ''; const duration = 1800; // ms const start = 0; const startTime = performance.now(); const updateCounter = (now) => { const elapsed = now - startTime; const progress = Math.min(elapsed / duration, 1); const currentValue = Math.floor(progress * target); counter.textContent = currentValue + suffix; if (progress < 1) { requestAnimationFrame(updateCounter); } else { counter.textContent = target + suffix; } }; requestAnimationFrame(updateCounter); counterObserver.unobserve(counter); } }); }, { threshold: 0.5 }); counters.forEach(counter => counterObserver.observe(counter)); /* ========================================================================== 6. Portfolio Grid Filter logic ========================================================================== */ const filterBtns = document.querySelectorAll('.filter-btn'); const portfolioItems = document.querySelectorAll('.portfolio-item'); filterBtns.forEach(btn => { btn.addEventListener('click', () => { // Update active tab button filterBtns.forEach(b => b.classList.remove('active')); btn.classList.add('active'); const filter = btn.getAttribute('data-filter'); portfolioItems.forEach(item => { const category = item.getAttribute('data-category'); if (filter === 'all' || category === filter) { item.style.display = 'block'; // Quick animate setTimeout(() => { item.style.opacity = '1'; item.style.transform = 'scale(1)'; }, 50); } else { item.style.opacity = '0'; item.style.transform = 'scale(0.8)'; setTimeout(() => { item.style.display = 'none'; }, 300); } }); }); }); /* ========================================================================== 7. Lightbox Image Modal Popup logic ========================================================================== */ const lightboxModal = document.getElementById('lightboxModal'); const lightboxImg = document.getElementById('lightboxImg'); const lightboxCaption = document.getElementById('lightboxCaption'); const lightboxCloseBtn = document.getElementById('lightboxCloseBtn'); const triggers = document.querySelectorAll('.lightbox-trigger-btn'); triggers.forEach(trigger => { trigger.addEventListener('click', () => { const imgSrc = trigger.getAttribute('data-img'); const caption = trigger.getAttribute('data-caption'); lightboxImg.src = imgSrc; lightboxCaption.textContent = caption; lightboxModal.classList.add('show'); document.body.style.overflow = 'hidden'; // Stop background scroll }); }); const closeLightbox = () => { lightboxModal.classList.remove('show'); document.body.style.overflow = 'auto'; // Restore scroll setTimeout(() => { lightboxImg.src = ''; }, 300); }; lightboxCloseBtn.addEventListener('click', closeLightbox); // Close when clicking outside content area lightboxModal.addEventListener('click', (e) => { if (e.target === lightboxModal) { closeLightbox(); } }); // Close on escape key document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && lightboxModal.classList.contains('show')) { closeLightbox(); } }); /* ========================================================================== 8. Form Submission Interactivity & Custom Toast Alerts ========================================================================== */ const contactForm = document.getElementById('contactForm'); const submitBtn = document.getElementById('submitFormBtn'); contactForm.addEventListener('submit', (e) => { e.preventDefault(); // Custom validation const name = document.getElementById('nameInput').value.trim(); const email = document.getElementById('emailInput').value.trim(); const message = document.getElementById('messageInput').value.trim(); if (!name || !email || !message) { showToast('กรุณากรอกข้อมูลให้ครบถ้วนทุกช่องที่มีเครื่องหมาย *', 'info'); return; } if (!validateEmail(email)) { showToast('กรุณากรอกรูปแบบอีเมลให้ถูกต้อง', 'info'); return; } // Simulate Sending State const originalText = submitBtn.innerHTML; submitBtn.disabled = true; submitBtn.innerHTML = '<i class="fa-solid fa-spinner fa-spin me-2"></i>กำลังส่งข้อความ...'; setTimeout(() => { showToast('ส่งข้อความสำเร็จ! ขอบคุณที่ติดต่อ นายหาญ ครับ', 'success'); contactForm.reset(); submitBtn.disabled = false; submitBtn.innerHTML = originalText; }, 1500); }); const validateEmail = (email) => { const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return re.test(email); }; // Custom Toast System const showToast = (message, type = 'success') => { const toastContainer = document.getElementById('toastContainer'); const toast = document.createElement('div'); toast.className = `toast toast-${type}`; const icon = type === 'success' ? '<i class="fa-solid fa-circle-check toast-icon"></i>' : '<i class="fa-solid fa-circle-info toast-icon"></i>'; toast.innerHTML = ` ${icon} <span>${message}</span> `; toastContainer.appendChild(toast); // Show setTimeout(() => { toast.classList.add('show'); }, 50); // Remove setTimeout(() => { toast.classList.remove('show'); setTimeout(() => { toast.remove(); }, 400); }, 3500); }; /* ========================================================================== 9. Material-style Button Hover Click Ripples ========================================================================== */ const rippleBtns = document.querySelectorAll('.ripple'); rippleBtns.forEach(btn => { btn.addEventListener('click', function(e) { const x = e.clientX - e.target.getBoundingClientRect().left; const y = e.clientY - e.target.getBoundingClientRect().top; const ripples = document.createElement('span'); ripples.className = 'ripple-effect'; ripples.style.left = x + 'px'; ripples.style.top = y + 'px'; this.appendChild(ripples); setTimeout(() => { ripples.remove(); }, 600); }); }); // Lang Switcher Notification (Placeholder Future Capability) const langToggleBtn = document.getElementById('langToggleBtn'); langToggleBtn.addEventListener('click', () => { showToast('ระบบรองรับภาษาอื่น ๆ จะเปิดใช้งานในเร็ว ๆ นี้', 'info'); }); }); </script> </body> </html>
| ver. 1.4 |
Github
|
.
| PHP 7.4.33 | Generation time: 0.33 |
proxy
|
phpinfo
|
Settings