${exp.role}
${exp.period}${exp.description}
-
${exp.achievements.map(a => `
- ${a} `).join('')}
/** * Web Resume & Technical Portfolio Controller * TEERASAK PROMSEN - Senior Software Engineer | Backend Engineer | System Engineer */ // Application State const state = { lang: localStorage.getItem('profile_lang') || 'th', theme: localStorage.getItem('profile_theme') || 'light', view: 'portfolio', // 'portfolio' | 'cv' skillFilter: 'all' }; // Initialize Application on DOM Ready document.addEventListener('DOMContentLoaded', () => { applyTheme(state.theme); setupEventListeners(); renderApp(); initVisitorSessionCounter(); }); /** * Visitor & Session Counter (No Database required) * Uses CounterAPI + sessionStorage to increment once per browser session */ async function initVisitorSessionCounter() { const badgeEl = document.getElementById('visitor-count-val'); if (!badgeEl) return; const isTh = state.lang === 'th'; const labelEl = document.getElementById('visitor-count-label'); if (labelEl) labelEl.textContent = isTh ? 'ผู้เข้าชม:' : 'Views:'; const namespace = 'teerasak-promsen-profile-v1'; const key = 'visits'; const hasVisitedInSession = sessionStorage.getItem('visited_session_flag'); try { const url = !hasVisitedInSession ? `https://api.counterapi.dev/v1/${namespace}/${key}/up` : `https://api.counterapi.dev/v1/${namespace}/${key}`; if (!hasVisitedInSession) { sessionStorage.setItem('visited_session_flag', 'true'); } const res = await fetch(url); if (!res.ok) throw new Error(`Status ${res.status}`); const data = await res.json(); if (data && typeof data.count !== 'undefined') { badgeEl.textContent = Number(data.count).toLocaleString(); } } catch (e) { badgeEl.textContent = '1+'; } } /** * Render the entire view based on current state */ function renderApp() { const data = PROFILE_DATA[state.lang]; if (!data) return; // Update HTML lang attribute document.documentElement.lang = state.lang; // Render Both Portfolio and CV Views renderHero(data.personal); renderSkills(data.skills); renderExperiences(data.experiences); renderExtraProjects(data.extraProjects); renderProjects(data.projects); renderArchitecture(data.architectureHighlights); renderEducation(data.education, data.certifications); renderCV(data); updateStaticTexts(); } /** * Set and apply visual theme */ function applyTheme(theme) { state.theme = theme; document.documentElement.setAttribute('data-theme', theme); localStorage.setItem('profile_theme', theme); const themeIcon = document.getElementById('theme-icon'); if (themeIcon) { themeIcon.className = theme === 'dark' ? 'fas fa-sun' : 'fas fa-moon'; } } /** * Switch Language (en / th) */ function setLanguage(lang) { if (lang !== 'en' && lang !== 'th') return; state.lang = lang; localStorage.setItem('profile_lang', lang); const langBtn = document.getElementById('lang-toggle-btn'); if (langBtn) { langBtn.textContent = lang === 'en' ? 'TH' : 'EN'; } renderApp(); } /** * Switch View Mode (Interactive Portfolio vs Print-Ready CV) */ function setViewMode(mode) { state.view = mode; const portfolioContainer = document.getElementById('portfolio-view-container'); const cvContainer = document.getElementById('cv-view-container'); const modePortfolioBtn = document.getElementById('mode-btn-portfolio'); const modeCvBtn = document.getElementById('mode-btn-cv'); if (mode === 'cv') { if (portfolioContainer) portfolioContainer.style.display = 'none'; if (cvContainer) cvContainer.style.display = 'block'; if (modePortfolioBtn) modePortfolioBtn.classList.remove('active'); if (modeCvBtn) modeCvBtn.classList.add('active'); window.scrollTo({ top: 0, behavior: 'smooth' }); } else { if (portfolioContainer) portfolioContainer.style.display = 'block'; if (cvContainer) cvContainer.style.display = 'none'; if (modePortfolioBtn) modePortfolioBtn.classList.add('active'); if (modeCvBtn) modeCvBtn.classList.remove('active'); } } /** * Render Header / Profile Overview */ function renderHero(personal) { const nameEl = document.getElementById('hero-name'); const titleEl = document.getElementById('hero-title'); const bioEl = document.getElementById('hero-bio'); const statusEl = document.getElementById('hero-status-text'); if (nameEl) nameEl.textContent = personal.name; if (titleEl) titleEl.textContent = personal.title; if (bioEl) bioEl.textContent = personal.bio; if (statusEl) statusEl.textContent = personal.status; } /** * Render Skills Matrix with Filter */ function renderSkills(skillsData) { const filterContainer = document.getElementById('skills-filter-container'); const gridContainer = document.getElementById('skills-grid-container'); if (filterContainer && skillsData.categories) { filterContainer.innerHTML = skillsData.categories.map(cat => ` `).join(''); } if (gridContainer && skillsData.items) { const filtered = state.skillFilter === 'all' ? skillsData.items : skillsData.items.filter(s => s.category === state.skillFilter); gridContainer.innerHTML = filtered.map(skill => `
${exp.description}
${proj.description}
${proj.description}
${item.desc}
${education[0].details}
${personal.bio}
${proj.description}
${isTh ? 'เส้นทางเติบโต:' : 'Progression:'} ${careerGoals.progression}