| <!DOCTYPE html> |
|
|
| <html lang="en"><head> |
| <meta charset="utf-8"/> |
| <meta content="width=device-width, initial-scale=1.0" name="viewport"/> |
| <title>CV Maker Pro | Professional Resume Builder</title> |
| <script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script> |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=Playfair+Display:wght@700&family=Fira+Code:wght@400;500&display=swap" rel="stylesheet"/> |
| <link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" rel="stylesheet"/> |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script> |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script> |
| <style> |
| :root { |
| --primary: #4f46e5; |
| --primary-dark: #4338ca; |
| --slate-50: #f8fafc; |
| --slate-100: #f1f5f9; |
| --slate-200: #e2e8f0; |
| --slate-300: #cbd5e1; |
| --slate-400: #94a3b8; |
| --slate-700: #334155; |
| --slate-800: #1e293b; |
| --slate-900: #0f172a; |
| } |
| |
| body { |
| font-family: 'Inter', sans-serif; |
| background-color: var(--slate-100); |
| color: var(--slate-900); |
| overflow: hidden; |
| } |
| |
| |
| ::-webkit-scrollbar { width: 5px; height: 5px; } |
| ::-webkit-scrollbar-track { background: transparent; } |
| ::-webkit-scrollbar-thumb { background: var(--slate-300); border-radius: 10px; } |
| ::-webkit-scrollbar-thumb:hover { background: var(--slate-400); } |
| |
| .app-container { |
| display: grid; |
| grid-template-columns: 400px 1fr; |
| height: 100vh; |
| padding-bottom: 56px; |
| } |
| |
| |
| .sidebar { |
| background: white; |
| border-right: 1px solid var(--slate-200); |
| display: flex; |
| flex-direction: column; |
| overflow: hidden; |
| z-index: 20; |
| } |
| |
| .sidebar-content { |
| flex: 1; |
| overflow-y: auto; |
| padding: 20px; |
| } |
| |
| |
| .preview-panel { |
| background: var(--slate-200); |
| overflow: auto; |
| display: flex; |
| justify-content: center; |
| padding: 40px 20px; |
| position: relative; |
| scroll-behavior: smooth; |
| } |
| |
| |
| #cv-preview { |
| width: 210mm; |
| min-height: 297mm; |
| background: white; |
| box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1); |
| transform-origin: top center; |
| transition: transform 0.2s ease; |
| } |
| |
| |
| @media (max-width: 1023px) { |
| .app-container { grid-template-columns: 1fr; overflow-y: auto; height: auto; padding-bottom: 100px; } |
| .sidebar { height: auto; border-right: none; max-height: none; } |
| .preview-panel { min-height: 400px; padding: 20px 10px; overflow: hidden; } |
| |
| |
| #cv-preview { |
| transform: scale(calc((100vw - 40px) / 794)); |
| margin-bottom: calc(-297mm + (297mm * (100vw - 40px) / 794) + 20px); |
| } |
| } |
| |
| @media (min-width: 1024px) and (max-width: 1366px) { |
| .app-container { grid-template-columns: 350px 1fr; } |
| #cv-preview { transform: scale(0.65); margin-bottom: -100mm; } |
| } |
| |
| @media (min-width: 1367px) and (max-width: 1599px) { |
| #cv-preview { transform: scale(0.8); margin-bottom: -60mm; } |
| } |
| |
| @media (min-width: 1600px) { |
| #cv-preview { transform: scale(0.9); margin-bottom: -30mm; } |
| } |
| |
| |
| .form-label { |
| display: block; |
| font-size: 0.75rem; |
| font-weight: 700; |
| color: var(--slate-700); |
| margin-bottom: 4px; |
| text-transform: uppercase; |
| letter-spacing: 0.025em; |
| } |
| .form-input { |
| width: 100%; |
| border: 1px solid var(--slate-200); |
| border-radius: 6px; |
| padding: 8px 10px; |
| font-size: 0.9rem; |
| transition: all 0.2s; |
| } |
| .form-input:focus { |
| border-color: var(--primary); |
| box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1); |
| outline: none; |
| } |
| |
| |
| .nav-tabs { |
| display: flex; |
| gap: 2px; |
| padding: 4px; |
| background: var(--slate-100); |
| border-radius: 10px; |
| margin-bottom: 20px; |
| overflow-x: auto; |
| -ms-overflow-style: none; |
| scrollbar-width: none; |
| } |
| .nav-tabs::-webkit-scrollbar { display: none; } |
| |
| .nav-tab { |
| flex: 1; |
| min-width: 70px; |
| padding: 8px 4px; |
| font-size: 0.75rem; |
| font-weight: 600; |
| border-radius: 7px; |
| white-space: nowrap; |
| cursor: pointer; |
| transition: all 0.2s; |
| color: var(--slate-700); |
| text-align: center; |
| } |
| .nav-tab.active { |
| background: white; |
| color: var(--primary); |
| box-shadow: 0 1px 3px rgba(0,0,0,0.1); |
| } |
| |
| |
| .theme-grid { |
| display: grid; |
| grid-template-columns: repeat(2, 1fr); |
| gap: 10px; |
| } |
| .theme-option { |
| border: 2px solid var(--slate-100); |
| border-radius: 8px; |
| padding: 6px; |
| cursor: pointer; |
| transition: all 0.2s; |
| text-align: center; |
| background: white; |
| } |
| .theme-option:hover { border-color: var(--slate-300); } |
| .theme-option.active { border-color: var(--primary); background: rgba(79, 70, 229, 0.05); } |
| .theme-preview-box { height: 40px; border-radius: 4px; margin-bottom: 6px; } |
| |
| |
| .cv-text-xs { font-size: 10px; } |
| .cv-text-sm { font-size: 12px; } |
| .cv-text-base { font-size: 14px; } |
| .cv-text-lg { font-size: 18px; } |
| .cv-bold { font-weight: 700; } |
| |
| |
| #cv-preview.theme-midnight { color: #fff; background: #0f172a; } |
| .theme-midnight .cv-sidebar { background: #1e293b; width: 30%; padding: 30px; height: 297mm; float: left; } |
| .theme-midnight .cv-main { width: 70%; padding: 40px; float: left; color: #f1f5f9; } |
| .theme-midnight .accent { color: #38bdf8; } |
| |
| |
| #cv-preview.theme-autumn { background: #fffdf5; color: #1e293b; } |
| .theme-autumn .cv-header { background: #d97706; color: white; padding: 40px; } |
| .theme-autumn .cv-body { display: flex; padding: 40px; gap: 30px; } |
| .theme-autumn .cv-sidebar { width: 35%; } |
| .theme-autumn .cv-main { flex: 1; } |
| .theme-autumn .section-h { border-bottom: 2px solid #d97706; padding-bottom: 5px; margin-bottom: 15px; font-family: 'Playfair Display', serif; } |
| |
| |
| #cv-preview.theme-skyline { background: white; border-top: 15px solid #0369a1; color: #1e293b; } |
| .theme-skyline .cv-header { padding: 40px; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #e0e7ff; } |
| .theme-skyline .cv-body { display: flex; padding: 40px; gap: 40px; } |
| .theme-skyline .cv-left { width: 200px; } |
| .theme-skyline .cv-right { flex: 1; } |
| .theme-skyline .section-h { color: #0369a1; text-transform: uppercase; letter-spacing: 2px; font-weight: 800; font-size: 12px; } |
| |
| |
| #cv-preview.theme-rose { background: #fff; color: #4c1d95; } |
| .theme-rose .cv-container { padding: 40px; } |
| .theme-rose .cv-header { text-align: center; margin-bottom: 30px; border: 4px double #ddd6fe; padding: 20px; } |
| .theme-rose .section-h { background: #f5f3ff; padding: 5px 15px; border-radius: 50px; margin-bottom: 15px; } |
| |
| |
| #cv-preview.theme-emerald { background: white; color: #1e293b; } |
| .theme-emerald .cv-top { height: 180px; background: #064e3b; padding: 40px; display: flex; align-items: center; color: white; gap: 30px; } |
| .theme-emerald .cv-body { display: grid; grid-template-columns: 2fr 1fr; padding: 40px; gap: 40px; } |
| .theme-emerald .section-h { color: #059669; font-weight: 800; border-left: 4px solid #059669; padding-left: 10px; } |
| |
| |
| #cv-preview.theme-industrial { background: #e5e7eb; color: #1e293b; } |
| .theme-industrial .cv-inner { background: #f9fafb; margin: 40px; padding: 40px; border: 10px solid #374151; height: calc(297mm - 80px); } |
| .theme-industrial .section-h { background: #374151; color: white; padding: 4px 12px; width: fit-content; } |
| |
| |
| #cv-preview.theme-royal { background: #1a1a1a; color: #d4af37; font-family: 'Playfair Display', serif; } |
| .theme-royal .cv-inner { padding: 50px; border: 2px solid #d4af37; margin: 30px; height: calc(297mm - 60px); } |
| .theme-royal .section-h { border-bottom: 1px solid #d4af37; padding-bottom: 5px; text-transform: uppercase; font-size: 14px; letter-spacing: 3px; } |
| |
| |
| .theme-executive .cv-sidebar-col { |
| width: 260px; min-height: 1123px; background: #0f3460; color: white; |
| padding: 40px 24px; float: left; |
| } |
| .theme-executive .cv-main-col { margin-left: 260px; padding: 40px 32px; } |
| .theme-executive .cv-photo { width: 120px; height: 120px; border-radius: 50%; border: 4px solid rgba(255,255,255,0.3); object-fit: cover; display: block; margin: 0 auto 20px; } |
| .theme-executive .cv-photo-placeholder { width: 120px; height: 120px; border-radius: 50%; border: 4px solid rgba(255,255,255,0.3); background: rgba(255,255,255,0.1); display: flex; align-items: center; justify-content: center; font-size: 40px; margin: 0 auto 20px; } |
| .theme-executive .cv-name { font-size: 28px; font-weight: 700; color: #0f3460; margin-bottom: 4px; } |
| .theme-executive .cv-title { font-size: 14px; color: #e94560; font-weight: 600; margin-bottom: 24px; text-transform: uppercase; letter-spacing: 1px; } |
| .theme-executive .sidebar-section-title { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 1.5px; color: rgba(255,255,255,0.5); margin: 20px 0 10px; border-bottom: 1px solid rgba(255,255,255,0.1); padding-bottom: 6px; } |
| .theme-executive .sidebar-item { font-size: 12px; color: rgba(255,255,255,0.9); margin-bottom: 8px; line-height: 1.5; } |
| .theme-executive .section-title { font-size: 13px; font-weight: 700; text-transform: uppercase; letter-spacing: 1.5px; color: #0f3460; border-bottom: 2px solid #e94560; padding-bottom: 6px; margin: 24px 0 14px; } |
| .theme-executive .entry-title { font-size: 14px; font-weight: 700; color: #1a1a2e; } |
| .theme-executive .entry-sub { font-size: 12px; color: #e94560; font-weight: 600; margin: 2px 0; } |
| .theme-executive .entry-date { font-size: 11px; color: #888; margin-bottom: 4px; } |
| .theme-executive .entry-desc { font-size: 12px; color: #555; line-height: 1.6; } |
| .theme-executive .tag { display: inline-block; background: rgba(255,255,255,0.15); color: white; padding: 3px 10px; border-radius: 20px; font-size: 11px; margin: 2px; } |
| .theme-executive .contact-item { display: flex; align-items: center; gap: 8px; font-size: 11px; color: rgba(255,255,255,0.85); margin-bottom: 8px; word-break: break-all; } |
| |
| |
| .theme-minimal { padding: 0; } |
| .theme-minimal .cv-top-bar { background: #1a1a1a; padding: 40px; color: white; display: flex; align-items: center; gap: 30px; } |
| .theme-minimal .cv-photo-wrap img { width: 90px; height: 90px; border-radius: 50%; object-fit: cover; border: 3px solid #f5a623; } |
| .theme-minimal .cv-photo-wrap .ph { width: 90px; height: 90px; border-radius: 50%; background: #333; display: flex; align-items: center; justify-content: center; font-size: 36px; border: 3px solid #f5a623; } |
| .theme-minimal .cv-name { font-size: 30px; font-weight: 800; color: white; letter-spacing: -1px; } |
| .theme-minimal .cv-title { font-size: 13px; color: #f5a623; text-transform: uppercase; letter-spacing: 2px; margin-top: 4px; } |
| .theme-minimal .cv-body { display: flex; padding: 0; } |
| .theme-minimal .cv-left { width: 240px; flex-shrink: 0; background: #f8f8f8; padding: 30px 24px; border-right: 1px solid #eee; } |
| .theme-minimal .cv-right { flex: 1; padding: 30px 32px; } |
| .theme-minimal .section-title { font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: 2px; color: #1a1a1a; margin: 20px 0 12px; } |
| .theme-minimal .left-label { font-size: 10px; font-weight: 700; color: #888; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 2px; } |
| .theme-minimal .left-value { font-size: 12px; color: #333; margin-bottom: 10px; word-break: break-all; } |
| .theme-minimal .skill-pill { display: inline-block; background: #1a1a1a; color: white; padding: 4px 12px; border-radius: 20px; font-size: 11px; margin: 2px; } |
| .theme-minimal .entry-card { border-left: 3px solid #f5a623; padding-left: 14px; margin-bottom: 18px; } |
| .theme-minimal .entry-title { font-size: 14px; font-weight: 700; color: #1a1a1a; } |
| .theme-minimal .entry-sub { font-size: 12px; color: #f5a623; font-weight: 600; } |
| .theme-minimal .entry-date { font-size: 11px; color: #999; margin: 2px 0; } |
| .theme-minimal .entry-desc { font-size: 12px; color: #666; line-height: 1.6; margin-top: 4px; } |
| |
| |
| .theme-coral { padding: 0; } |
| .theme-coral .cv-header { background: linear-gradient(135deg, #e94560 0%, #f5a623 100%); padding: 40px; display: flex; gap: 24px; align-items: center; } |
| .theme-coral .cv-photo img { width: 100px; height: 100px; border-radius: 16px; object-fit: cover; border: 3px solid rgba(255,255,255,0.6); } |
| .theme-coral .cv-photo .ph { width: 100px; height: 100px; border-radius: 16px; background: rgba(255,255,255,0.2); display: flex; align-items: center; justify-content: center; font-size: 40px; border: 3px solid rgba(255,255,255,0.6); } |
| .theme-coral .cv-name { font-size: 32px; font-weight: 800; color: white; letter-spacing: -1px; } |
| .theme-coral .cv-title { font-size: 13px; color: rgba(255,255,255,0.85); margin-top: 4px; letter-spacing: 1px; } |
| .theme-coral .contact-row { display: flex; gap: 20px; margin-top: 12px; flex-wrap: wrap; } |
| .theme-coral .contact-chip { font-size: 11px; color: rgba(255,255,255,0.9); background: rgba(255,255,255,0.2); padding: 4px 12px; border-radius: 20px; } |
| .theme-coral .cv-body { display: flex; } |
| .theme-coral .cv-left { width: 230px; flex-shrink: 0; padding: 28px 22px; background: #fff8f6; border-right: 1px solid #fde2d8; } |
| .theme-coral .cv-right { flex: 1; padding: 28px 30px; } |
| .theme-coral .section-title { font-size: 13px; font-weight: 800; color: #e94560; text-transform: uppercase; letter-spacing: 1px; margin: 20px 0 10px; } |
| .theme-coral .skill-tag { display: inline-block; background: white; border: 1.5px solid #e94560; color: #e94560; padding: 3px 10px; border-radius: 20px; font-size: 11px; margin: 2px; } |
| .theme-coral .entry-title { font-size: 14px; font-weight: 700; color: #1a1a1a; } |
| .theme-coral .entry-sub { font-size: 12px; color: #e94560; font-weight: 600; margin: 2px 0; } |
| .theme-coral .entry-date { font-size: 11px; color: #999; margin-bottom: 4px; } |
| .theme-coral .entry-desc { font-size: 12px; color: #666; line-height: 1.6; } |
| .theme-coral .entry-wrap { margin-bottom: 14px; } |
| |
| |
| .theme-forest .cv-sidebar-col, .theme-clean .cv-sidebar-col { width: 230px; min-height: 1123px; background: #1b4332; color: white; padding: 36px 22px; float: left; } |
| .theme-forest .cv-main-col, .theme-clean .cv-main-col { margin-left: 230px; padding: 36px 30px; } |
| .theme-forest .entry-title, .theme-clean .entry-title { font-size: 14px; font-weight: 700; color: #1b4332; } |
| .theme-forest .entry-sub, .theme-clean .entry-sub { font-size: 12px; color: #40916c; font-weight: 600; margin: 2px 0; } |
| .theme-forest .entry-date, .theme-clean .entry-date { font-size: 11px; color: #999; margin-bottom: 4px; } |
| .theme-forest .entry-desc, .theme-clean .entry-desc { font-size: 12px; color: #555; line-height: 1.6; } |
| |
| .theme-portfolio .cv-top, .theme-slate .cv-header, .theme-ocean .cv-header { padding: 40px; display: flex; align-items: center; gap: 28px; } |
| .theme-portfolio .cv-body, .theme-slate .cv-body, .theme-ocean .cv-body { display: flex; padding: 40px; } |
| .theme-modern .cv-header, .theme-tech .cv-header, .theme-elegant .cv-header { background: linear-gradient(135deg, #111827, #6366f1); padding: 40px; color: white; } |
| |
| .clearfix::after { content: ""; clear: both; display: table; } |
| |
| |
| .footer-fixed { |
| position: fixed; |
| bottom: 0; |
| left: 0; |
| right: 0; |
| height: 56px; |
| background: white; |
| border-top: 1px solid var(--slate-200); |
| display: flex; |
| align-items: center; |
| justify-content: space-between; |
| padding: 0 24px; |
| z-index: 50; |
| } |
| @media (max-width: 640px) { |
| .footer-fixed { flex-direction: column; height: auto; padding: 12px; gap: 8px; text-align: center; } |
| .footer-fixed > div { width: 100%; justify-content: center; } |
| } |
| |
| |
| @media (max-width: 900px) { |
| body { overflow:auto; } |
| .app-container { grid-template-columns:1fr; height:auto; min-height:100vh; padding-bottom:70px; } |
| .sidebar { height:auto; max-height:none; } |
| .preview-panel { min-height:100vh; padding:15px; overflow:auto; } |
| #cv-preview { transform:none !important; width:100% !important; min-height:auto !important; } |
| .theme-grid { grid-template-columns:repeat(3,1fr); } |
| } |
| @media (max-width:520px) { |
| .sidebar-content { padding:12px; } |
| .theme-grid { grid-template-columns:repeat(2,1fr); } |
| .preview-panel { padding:8px; } |
| } |
| </style> |
| </head> |
| <body> |
| <div class="app-container"> |
| |
| <aside class="sidebar"> |
| <div class="p-4 border-b border-slate-100 flex items-center justify-between bg-white sticky top-0 z-10"> |
| <div class="flex items-center gap-2"> |
| <span class="material-symbols-outlined text-indigo-600 text-2xl">description</span> |
| <h1 class="text-lg font-bold tracking-tight text-slate-800">CV Maker Pro</h1> |
| </div> |
| <button class="bg-indigo-600 hover:bg-indigo-700 text-white px-3 py-1.5 rounded-lg text-xs font-bold flex items-center gap-1.5 transition-all shadow-lg shadow-indigo-100 active:scale-95" onclick="downloadPDF()"> |
| <span class="material-symbols-outlined text-sm">download</span> Export |
| </button> |
| </div> |
| <div class="sidebar-content"> |
| <nav class="nav-tabs" id="main-tabs"> |
| <div class="nav-tab active" data-tab="personal">Personal</div> |
| <div class="nav-tab" data-tab="education">Education</div> |
| <div class="nav-tab" data-tab="experience">Work</div> |
| <div class="nav-tab" data-tab="skills">Skills</div> |
| <div class="nav-tab" data-tab="themes">Themes</div> |
| </nav> |
| |
| <div class="tab-panel" id="panel-personal"> |
| <div class="mb-5"> |
| <label class="form-label">Profile Picture</label> |
| <div class="border-2 border-dashed border-slate-200 rounded-lg p-4 text-center cursor-pointer hover:border-indigo-400 hover:bg-indigo-50 transition-all group" onclick="document.getElementById('photo-input').click()"> |
| <input accept="image/*" class="hidden" id="photo-input" onchange="handlePhoto(event)" type="file"/> |
| <div id="photo-drop-zone"> |
| <span class="material-symbols-outlined text-slate-400 text-3xl group-hover:text-indigo-500 transition-colors">add_a_photo</span> |
| <p class="text-[10px] text-slate-500 font-medium mt-1 uppercase tracking-wider">Click to upload</p> |
| </div> |
| </div> |
| </div> |
| <div class="space-y-4"> |
| <div class="form-group"> |
| <label class="form-label">Full Name</label> |
| <input class="form-input" id="f-name" oninput="updateCV()" placeholder="Muhammad Abdullah" type="text"/> |
| </div> |
| <div class="form-group"> |
| <label class="form-label">Professional Title</label> |
| <input class="form-input" id="f-title" oninput="updateCV()" placeholder="Web Developer & Content Creator" type="text"/> |
| </div> |
| <div class="form-group"> |
| <label class="form-label">Bio / Summary</label> |
| <textarea class="form-input" id="f-summary" oninput="updateCV()" placeholder="Brief professional summary..." rows="4"></textarea> |
| </div> |
| <div class="grid grid-cols-1 sm:grid-cols-2 gap-4"> |
| <div class="form-group"> |
| <label class="form-label">Email</label> |
| <input class="form-input" id="f-email" oninput="updateCV()" placeholder="your@email.com" type="email"/> |
| </div> |
| <div class="form-group"> |
| <label class="form-label">Phone</label> |
| <input class="form-input" id="f-phone" oninput="updateCV()" placeholder="+92 342 4844392" type="text"/> |
| </div> |
| </div> |
| <div class="form-group"> |
| <label class="form-label">Location</label> |
| <input class="form-input" id="f-location" oninput="updateCV()" placeholder="Lahore, Pakistan" type="text"/> |
| </div> |
| <div class="form-group"> |
| <label class="form-label">Website / Portfolio</label> |
| <input class="form-input" id="f-website" oninput="updateCV()" placeholder="www.portfolio.com" type="text"/> |
| </div> |
| </div> |
| </div> |
| <div class="tab-panel hidden" id="panel-education"> |
| <div class="space-y-4" id="education-list"></div> |
| <button class="w-full mt-4 py-3 border-2 border-dashed border-slate-200 rounded-xl text-slate-500 text-sm font-bold hover:bg-slate-50 hover:border-slate-300 transition-all flex items-center justify-center gap-2" onclick="addEntry('education')"> |
| <span class="material-symbols-outlined text-base">add</span> Add Education |
| </button> |
| </div> |
| <div class="tab-panel hidden" id="panel-experience"> |
| <div class="space-y-4" id="experience-list"></div> |
| <button class="w-full mt-4 py-3 border-2 border-dashed border-slate-200 rounded-xl text-slate-500 text-sm font-bold hover:bg-slate-50 hover:border-slate-300 transition-all flex items-center justify-center gap-2" onclick="addEntry('experience')"> |
| <span class="material-symbols-outlined text-base">add</span> Add Experience |
| </button> |
| </div> |
| <div class="tab-panel hidden" id="panel-skills"> |
| <div class="space-y-4"> |
| <div class="form-group"> |
| <label class="form-label">Technical Skills (Comma separated)</label> |
| <textarea class="form-input" id="f-skills" oninput="updateCV()" placeholder="JavaScript, Python, React..." rows="3"></textarea> |
| </div> |
| <div class="form-group"> |
| <label class="form-label">Languages</label> |
| <input class="form-input" id="f-languages" oninput="updateCV()" placeholder="English, Urdu, German" type="text"/> |
| </div> |
| <div class="form-group"> |
| <label class="form-label">Certifications (One per line)</label> |
| <textarea class="form-input" id="f-diplomas" oninput="updateCV()" placeholder="AWS Certified Architect..." rows="3"></textarea> |
| </div> |
| </div> |
| </div> |
| <div class="tab-panel hidden" id="panel-themes"> |
| <div class="theme-grid"><div class="theme-option active" data-theme="midnight" onclick="setTheme('midnight')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,hsl(0,70%,45%),#fff)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Midnight</span> |
| </div><div class="theme-option " data-theme="autumn" onclick="setTheme('autumn')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,hsl(18,70%,45%),#fff)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Autumn</span> |
| </div><div class="theme-option " data-theme="skyline" onclick="setTheme('skyline')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,hsl(36,70%,45%),#fff)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Skyline</span> |
| </div><div class="theme-option " data-theme="rose" onclick="setTheme('rose')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,hsl(54,70%,45%),#fff)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Rose</span> |
| </div><div class="theme-option " data-theme="emerald" onclick="setTheme('emerald')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,hsl(72,70%,45%),#fff)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Emerald</span> |
| </div><div class="theme-option " data-theme="industrial" onclick="setTheme('industrial')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,hsl(144,70%,45%),#fff)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Industrial</span> |
| </div><div class="theme-option " data-theme="royal" onclick="setTheme('royal')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,hsl(162,70%,45%),#fff)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Royal</span> |
| </div><div class="theme-option " data-theme="minimal" onclick="setTheme('minimal')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,hsl(180,70%,45%),#fff)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Minimal</span> |
| </div><div class="theme-option " data-theme="executive" onclick="setTheme('executive')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,hsl(216,70%,45%),#fff)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Executive</span> |
| </div><div class="theme-option " data-theme="modern" onclick="setTheme('modern')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,hsl(234,70%,45%),#fff)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Modern</span> |
| </div><div class="theme-option " data-theme="classic" onclick="setTheme('classic')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,hsl(252,70%,45%),#fff)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Classic</span> |
| </div><div class="theme-option " data-theme="tech" onclick="setTheme('tech')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,hsl(270,70%,45%),#fff)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Tech</span> |
| </div><div class="theme-option " data-theme="elegant" onclick="setTheme('elegant')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,hsl(288,70%,45%),#fff)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Elegant</span> |
| </div><div class="theme-option " data-theme="bold" onclick="setTheme('bold')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,hsl(306,70%,45%),#fff)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Bold</span> |
| </div><div class="theme-option " data-theme="clean" onclick="setTheme('clean')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,hsl(324,70%,45%),#fff)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Clean</span> |
| </div><div class="theme-option " data-theme="portfolio" onclick="setTheme('portfolio')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,hsl(342,70%,45%),#fff)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Portfolio</span> |
| </div><div class="theme-option " data-theme="coral" onclick="setTheme('coral')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,#e94560,#f5a623)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Coral</span> |
| </div><div class="theme-option " data-theme="forest" onclick="setTheme('forest')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,#1b4332,#40916c)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Forest</span> |
| </div><div class="theme-option " data-theme="purple" onclick="setTheme('purple')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,#4a0e8f,#9b59b6)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Purple</span> |
| </div><div class="theme-option " data-theme="slate" onclick="setTheme('slate')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,#2d3748,#718096)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Slate</span> |
| </div><div class="theme-option " data-theme="ocean" onclick="setTheme('ocean')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,#006BA6,#0496FF)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Ocean</span> |
| </div><div class="theme-option " data-theme="sunsetorange" onclick="setTheme('sunsetorange')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,#FF6B35,#F7931E)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Sunset Org</span> |
| </div><div class="theme-option " data-theme="mint" onclick="setTheme('mint')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,#00D9C0,#00B4A0)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Mint</span> |
| </div><div class="theme-option " data-theme="rosegold" onclick="setTheme('rosegold')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,#C9A9A6,#E8B4B8)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Rose Gold</span> |
| </div><div class="theme-option " data-theme="dark" onclick="setTheme('dark')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,#000,#FFD700)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Dark Night</span> |
| </div><div class="theme-option " data-theme="crimson" onclick="setTheme('crimson')"> |
| <div class="theme-preview-box" style="background:linear-gradient(135deg,#8B0000,#DC143C)"></div> |
| <span class="text-[10px] font-bold uppercase tracking-wide">Crimson</span> |
| </div></div> |
| </div> |
| </div> |
| </aside> |
| |
| <main class="preview-panel"> |
| <div id="cv-preview"> |
| |
| </div> |
| </main> |
| </div> |
| |
| <footer class="footer-fixed"> |
| <div class="flex items-center gap-2 text-[11px] text-slate-500 font-bold uppercase tracking-widest"> |
| <span class="w-2 h-2 bg-green-500 rounded-full animate-pulse"></span> Live Sync |
| </div> |
| <div class="text-[11px] font-semibold text-slate-400"> |
| Built with <span class="text-rose-500">โฅ</span> by <a class="text-slate-800 hover:text-indigo-600 transition-colors" href="https://famstagency.com/about-developer.html" target="_blank">Abdullah Tarar</a> |
| </div> |
| <div class="flex items-center gap-3"> |
| <button class="text-slate-400 hover:text-slate-800 transition-colors" onclick="zoom('out')"><span class="material-symbols-outlined text-lg">zoom_out</span></button> |
| <div class="h-4 w-[1px] bg-slate-200"></div> |
| <button class="text-slate-400 hover:text-slate-800 transition-colors" onclick="zoom('in')"><span class="material-symbols-outlined text-lg">zoom_in</span></button> |
| </div> |
| </footer> |
| <script> |
| let currentTheme = 'midnight'; |
| let photoDataURL = null; |
| let eduEntries = []; |
| let expEntries = []; |
| let currentScale = 0.9; |
| |
| // Adjust initial scale based on screen width |
| if (window.innerWidth < 1024) { |
| currentScale = (window.innerWidth - 40) / 794; |
| } else if (window.innerWidth < 1440) { |
| currentScale = 0.7; |
| } |
| |
| function zoom(dir) { |
| if (dir === 'in') currentScale += 0.05; |
| else currentScale -= 0.05; |
| |
| const cv = document.getElementById('cv-preview'); |
| cv.style.transform = `scale(${currentScale})`; |
| // Update margin to fix layout gap after scaling |
| const heightCorrection = (297 * 3.78) * (1 - currentScale); // mm to px approx |
| cv.style.marginBottom = `-${heightCorrection}px`; |
| } |
| |
| // App initialization |
| function init() { |
| document.getElementById('f-name').value = "Muhammad Abdullah"; |
| document.getElementById('f-title').value = "Content Creator & Web Developer"; |
| document.getElementById('f-summary').value = "Passionate digital professional with expertise in ethical hacking, content creation, and web development. Experienced in managing content strategy and delivering freelance projects across diverse industries."; |
| document.getElementById('f-phone').value = "+92 342 4844392"; |
| document.getElementById('f-email').value = "muhammadabdullahtarar392@gmail.com"; |
| document.getElementById('f-location').value = "Lahore, Pakistan"; |
| document.getElementById('f-website').value = "libsi.pk"; |
| document.getElementById('f-skills').value = "Ethical Hacking, Photoshop, Web Development, SEO, WordPress, Social Media"; |
| document.getElementById('f-languages').value = "Urdu (Native), English (Professional)"; |
| document.getElementById('f-diplomas').value = "Diploma in Ethical Hacking\nPhotoshop Course Certificate"; |
| |
| addEntry('education', { degree: 'Intermediate (F.Sc)', institution: 'BISE Lahore', year: '2020-2022' }); |
| addEntry('experience', { role: 'Content Head', company: 'Libsi.pk', period: '2022-Present', desc: 'Led content strategy and team of 5 writers.' }); |
| |
| updateCV(); |
| setupTabs(); |
| } |
| |
| function setupTabs() { |
| const tabs = document.querySelectorAll('.nav-tab'); |
| tabs.forEach(tab => { |
| tab.addEventListener('click', () => { |
| tabs.forEach(t => t.classList.remove('active')); |
| tab.classList.add('active'); |
| |
| const targetPanel = tab.getAttribute('data-tab'); |
| document.querySelectorAll('.tab-panel').forEach(panel => { |
| panel.classList.add('hidden'); |
| }); |
| document.getElementById('panel-' + targetPanel).classList.remove('hidden'); |
| |
| // On mobile, scroll to top of sidebar content when tab changes |
| if (window.innerWidth < 1024) { |
| document.querySelector('.sidebar-content').scrollTop = 0; |
| } |
| }); |
| }); |
| } |
| |
| function setTheme(theme) { |
| currentTheme = theme; |
| document.querySelectorAll('.theme-option').forEach(opt => { |
| opt.classList.toggle('active', opt.getAttribute('data-theme') === theme); |
| }); |
| updateCV(); |
| } |
| |
| function handlePhoto(e) { |
| const file = e.target.files[0]; |
| if (!file) return; |
| const reader = new FileReader(); |
| reader.onload = (ev) => { |
| photoDataURL = ev.target.result; |
| document.getElementById('photo-drop-zone').innerHTML = ` |
| <img src="${photoDataURL}" class="w-14 h-14 rounded-full mx-auto object-cover border-2 border-indigo-500 shadow-md"> |
| <p class="text-[10px] text-indigo-500 font-bold mt-1 uppercase">Change</p> |
| `; |
| updateCV(); |
| }; |
| reader.readAsDataURL(file); |
| } |
| |
| function addEntry(type, data = {}) { |
| const listId = type + '-list'; |
| const id = Date.now() + Math.random().toString(36).substr(2, 9); |
| const entry = { id, ...data }; |
| |
| if (type === 'education') eduEntries.push(entry); |
| else expEntries.push(entry); |
| |
| const entryEl = document.createElement('div'); |
| entryEl.id = 'entry-' + id; |
| entryEl.className = 'p-3 bg-slate-50 rounded-lg border border-slate-200 relative group'; |
| |
| const fields = type === 'education' ? |
| `<div class="space-y-2"> |
| <input type="text" placeholder="Degree" class="form-input text-xs" value="${data.degree || ''}" oninput="updateEntry('${type}','${id}','degree',this.value)"> |
| <input type="text" placeholder="Institution" class="form-input text-xs" value="${data.institution || ''}" oninput="updateEntry('${type}','${id}','institution',this.value)"> |
| <input type="text" placeholder="Year Range" class="form-input text-xs" value="${data.year || ''}" oninput="updateEntry('${type}','${id}','year',this.value)"> |
| </div>` : |
| `<div class="space-y-2"> |
| <input type="text" placeholder="Job Title" class="form-input text-xs" value="${data.role || ''}" oninput="updateEntry('${type}','${id}','role',this.value)"> |
| <input type="text" placeholder="Company" class="form-input text-xs" value="${data.company || ''}" oninput="updateEntry('${type}','${id}','company',this.value)"> |
| <input type="text" placeholder="Period" class="form-input text-xs" value="${data.period || ''}" oninput="updateEntry('${type}','${id}','period',this.value)"> |
| <textarea placeholder="Description" class="form-input text-xs" oninput="updateEntry('${type}','${id}','desc',this.value)">${data.desc || ''}</textarea> |
| </div>`; |
| |
| entryEl.innerHTML = ` |
| <button onclick="removeEntry('${type}','${id}')" class="absolute -top-2 -right-2 bg-rose-500 text-white p-1 rounded-full opacity-0 group-hover:opacity-100 transition-opacity z-10 shadow-sm"> |
| <span class="material-symbols-outlined text-[14px]">close</span> |
| </button> |
| ${fields} |
| `; |
| |
| document.getElementById(listId).appendChild(entryEl); |
| updateCV(); |
| } |
| |
| function updateEntry(type, id, field, value) { |
| const list = type === 'education' ? eduEntries : expEntries; |
| const item = list.find(e => e.id === id); |
| if (item) { |
| item[field] = value; |
| updateCV(); |
| } |
| } |
| |
| function removeEntry(type, id) { |
| if (type === 'education') eduEntries = eduEntries.filter(e => e.id !== id); |
| else expEntries = expEntries.filter(e => e.id !== id); |
| document.getElementById('entry-' + id).remove(); |
| updateCV(); |
| } |
| |
| function updateCV() { |
| const data = { |
| name: document.getElementById('f-name').value || 'John Doe', |
| title: document.getElementById('f-title').value || 'Professional Role', |
| summary: document.getElementById('f-summary').value, |
| email: document.getElementById('f-email').value, |
| phone: document.getElementById('f-phone').value, |
| location: document.getElementById('f-location').value, |
| website: document.getElementById('f-website').value, |
| skills: document.getElementById('f-skills').value.split(',').filter(s => s.trim()), |
| langs: document.getElementById('f-languages').value.split(',').filter(l => l.trim()), |
| certs: document.getElementById('f-diplomas').value.split('\n').filter(c => c.trim()), |
| edu: eduEntries, |
| exp: expEntries, |
| photo: photoDataURL |
| }; |
| |
| const preview = document.getElementById('cv-preview'); |
| preview.className = 'theme-' + currentTheme; |
| preview.innerHTML = generateThemeHTML(data); |
| } |
| |
| function generateThemeHTML(d) { |
| const profileImg = d.photo ? `<img src="${d.photo}" style="width:100px; height:100px; object-fit:cover; border-radius:50%; border:3px solid rgba(255,255,255,0.2);">` : `<div style="width:100px;height:100px;background:rgba(255,255,255,0.1);border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:40px;">๐ค</div>`; |
| const skillList = d.skills.map(s => `<span style="display:inline-block; margin-right:8px; margin-bottom:8px; padding:2px 10px; background:rgba(128,128,128,0.1); border-radius:4px; font-size:10px;">${s.trim()}</span>`).join(''); |
| const eduList = d.edu.map(e => `<div style="margin-bottom:15px;"><div class="cv-bold cv-text-base">${e.degree}</div><div class="cv-text-sm">${e.institution} | ${e.year}</div></div>`).join(''); |
| const expList = d.exp.map(e => `<div style="margin-bottom:20px;"><div class="cv-bold cv-text-base">${e.role}</div><div class="accent cv-bold cv-text-sm">${e.company} | ${e.period}</div><div class="cv-text-sm" style="margin-top:5px; opacity:0.8;">${e.desc}</div></div>`).join(''); |
| |
| switch(currentTheme) { |
| case 'midnight': |
| return ` |
| <div class="cv-sidebar clearfix"> |
| <div style="text-align:center; margin-bottom:30px;">${profileImg}</div> |
| <div class="cv-bold cv-text-sm accent" style="margin-bottom:10px;">CONTACT</div> |
| <div class="cv-text-xs" style="margin-bottom:20px;"><div>${d.email}</div><div>${d.phone}</div><div>${d.location}</div><div>${d.website}</div></div> |
| <div class="cv-bold cv-text-sm accent" style="margin-bottom:10px;">SKILLS</div> |
| <div style="margin-bottom:20px;">${skillList}</div> |
| <div class="cv-bold cv-text-sm accent" style="margin-bottom:10px;">LANGUAGES</div> |
| <div class="cv-text-xs">${d.langs.join(', ')}</div> |
| </div> |
| <div class="cv-main"> |
| <div class="cv-bold cv-text-lg" style="font-size:32px;">${d.name.toUpperCase()}</div> |
| <div class="accent cv-bold" style="letter-spacing:2px; margin-bottom:30px;">${d.title.toUpperCase()}</div> |
| <div style="margin-bottom:30px;" class="cv-text-sm">${d.summary}</div> |
| <div class="cv-bold cv-text-sm accent" style="margin-bottom:15px; border-bottom:1px solid #334155; padding-bottom:5px;">EXPERIENCE</div> |
| ${expList} |
| <div class="cv-bold cv-text-sm accent" style="margin-bottom:15px; border-bottom:1px solid #334155; padding-bottom:5px; margin-top:30px;">EDUCATION</div> |
| ${eduList} |
| </div> |
| `; |
| case 'autumn': |
| return ` |
| <div class="cv-header"> |
| <div style="font-size:36px; font-weight:700; font-family:'Playfair Display';">${d.name}</div> |
| <div style="font-size:16px; opacity:0.9;">${d.title}</div> |
| </div> |
| <div class="cv-body"> |
| <div class="cv-sidebar"> |
| <div class="section-h">Contact</div> |
| <div class="cv-text-sm">${d.email}<br>${d.phone}<br>${d.location}</div> |
| <div class="section-h" style="margin-top:30px;">Skills</div> |
| <div class="cv-text-sm">${d.skills.join(' โข ')}</div> |
| </div> |
| <div class="cv-main"> |
| <div class="section-h">Profile</div> |
| <div class="cv-text-sm" style="margin-bottom:30px;">${d.summary}</div> |
| <div class="section-h">Experience</div> |
| ${expList} |
| <div class="section-h" style="margin-top:30px;">Education</div> |
| ${eduList} |
| </div> |
| </div> |
| `; |
| case 'skyline': |
| return ` |
| <div class="cv-header"> |
| <div><div style="font-size:28px; font-weight:900;">${d.name.toUpperCase()}</div><div class="accent" style="font-weight:700;">${d.title}</div></div> |
| <div class="cv-text-xs" style="text-align:right;">${d.email}<br>${d.phone}<br>${d.location}</div> |
| </div> |
| <div class="cv-body"> |
| <div class="cv-left"> |
| <div class="section-h">Skills</div> |
| <div style="margin:10px 0 30px;">${d.skills.join(', ')}</div> |
| <div class="section-h">Languages</div> |
| <div style="margin:10px 0;">${d.langs.join(', ')}</div> |
| </div> |
| <div class="cv-right"> |
| <div class="section-h">About Me</div> |
| <div class="cv-text-sm" style="margin:10px 0 30px;">${d.summary}</div> |
| <div class="section-h">History</div> |
| <div style="margin-top:15px;">${expList}</div> |
| </div> |
| </div> |
| `; |
| case 'rose': |
| return ` |
| <div class="cv-container"> |
| <div class="cv-header"> |
| <div style="font-size:32px; font-weight:800;">${d.name}</div> |
| <div style="color:#7c3aed; font-weight:600;">${d.title}</div> |
| <div class="cv-text-xs" style="margin-top:10px;">${d.email} โข ${d.phone} โข ${d.location}</div> |
| </div> |
| <div class="section-h cv-bold cv-text-sm">ABOUT</div> |
| <div class="cv-text-sm" style="margin-bottom:25px;">${d.summary}</div> |
| <div class="section-h cv-bold cv-text-sm">EXPERIENCE</div> |
| ${expList} |
| </div> |
| `; |
| case 'emerald': |
| return ` |
| <div class="cv-top"> |
| ${profileImg} |
| <div><div style="font-size:32px; font-weight:800;">${d.name}</div><div style="font-size:14px; opacity:0.8;">${d.title}</div></div> |
| </div> |
| <div class="cv-body"> |
| <div class="cv-main"> |
| <div class="section-h cv-text-sm">PROFILE</div> |
| <div class="cv-text-sm" style="margin:15px 0 30px;">${d.summary}</div> |
| <div class="section-h cv-text-sm">EXPERIENCE</div> |
| ${expList} |
| </div> |
| <div class="cv-sidebar"> |
| <div class="section-h cv-text-sm">CONTACT</div> |
| <div class="cv-text-xs" style="margin:15px 0 30px;">${d.email}<br>${d.phone}</div> |
| <div class="section-h cv-text-sm">SKILLS</div> |
| <div style="margin:15px 0;">${skillList}</div> |
| </div> |
| </div> |
| `; |
| case 'industrial': |
| return `<div class="cv-inner"><div style="display:flex; justify-content:space-between; margin-bottom:40px;"><div><div style="font-size:32px; font-weight:900;">${d.name.toUpperCase()}</div><div style="font-weight:700;">${d.title}</div></div><div class="cv-text-xs">${d.email}</div></div><div class="section-h">SUMMARY</div><div class="cv-text-sm" style="margin:10px 0 30px;">${d.summary}</div><div class="section-h">EXPERIENCE</div>${expList}</div>`; |
| case 'royal': |
| return `<div class="cv-inner"><div style="text-align:center; margin-bottom:40px;"><div style="font-size:38px; font-weight:700;">${d.name}</div><div style="font-size:14px; letter-spacing:4px;">${d.title.toUpperCase()}</div></div><div class="section-h">Profile</div><div class="cv-text-sm" style="margin:15px 0 35px; text-align:center;">${d.summary}</div><div class="section-h">Experience</div>${expList}</div>`; |
| |
| case 'executive': |
| const execSkillTags = d.skills.filter(s=>s.trim()).map(s => `<span class="tag">${s.trim()}</span>`).join(''); |
| const execEdu = d.edu.map(e => `<div style="margin-bottom:12px;"><div class="sidebar-item"><strong>${e.degree||''}</strong>${e.institution||''}</div><div style="font-size:11px;color:rgba(255,255,255,0.5);margin-top:2px;">${e.year||''}</div></div>`).join(''); |
| const execExp = d.exp.map(e => `<div class="entry-wrap" style="margin-bottom:16px;"><div class="entry-title">${e.role||''}</div><div class="entry-sub">${e.company||''}</div><div class="entry-date">${e.period||''}</div><div class="entry-desc">${e.desc||''}</div></div>`).join(''); |
| const execCerts = d.certs.map(c => `<div class="sidebar-item">โฆ ${c}</div>`).join(''); |
| return ` |
| <div class="theme-executive clearfix"> |
| <div class="cv-sidebar-col"> |
| ${d.photo ? `<img src="${d.photo}" class="cv-photo" alt="Profile">` : `<div class="cv-photo-placeholder">๐ค</div>`} |
| <div style="text-align:center;color:white;font-size:16px;font-weight:700;margin-bottom:2px;">${d.name}</div> |
| <div style="text-align:center;color:#f5a623;font-size:11px;letter-spacing:1px;margin-bottom:20px;">${d.title}</div> |
| <div class="sidebar-section-title">Contact</div> |
| ${d.phone?`<div class="contact-item">๐ ${d.phone}</div>`:''} |
| ${d.email?`<div class="contact-item">โ ${d.email}</div>`:''} |
| ${d.location?`<div class="contact-item">๐ ${d.location}</div>`:''} |
| ${d.website?`<div class="contact-item">๐ ${d.website}</div>`:''} |
| ${d.skills.length?`<div class="sidebar-section-title">Skills</div><div>${execSkillTags}</div>`:''} |
| ${d.langs.length?`<div class="sidebar-section-title">Languages</div>${d.langs.filter(l=>l.trim()).map(l=>`<div class="sidebar-item">โข ${l.trim()}</div>`).join('')}`:''} |
| ${d.certs.length?`<div class="sidebar-section-title">Certifications</div>${execCerts}`:''} |
| </div> |
| <div class="cv-main-col"> |
| <div class="cv-name">${d.name}</div> |
| <div class="cv-title">${d.title}</div> |
| ${d.summary?`<div class="section-title">Profile</div><div class="entry-desc">${d.summary}</div>`:''} |
| ${execExp?`<div class="section-title">Experience</div>${execExp}`:''} |
| ${execEdu?`<div class="section-title">Education</div>${execEdu}`:''} |
| </div> |
| </div>`; |
| |
| case 'minimal': |
| const minSkillPills = d.skills.filter(s=>s.trim()).map(s=>`<span class="skill-pill">${s.trim()}</span>`).join(''); |
| const minEdu = d.edu.map(e=>`<div class="entry-card"><div class="entry-title">${e.degree||''}</div><div class="entry-sub">${e.institution||''}</div><div class="entry-date">${e.year||''}</div></div>`).join(''); |
| const minExp = d.exp.map(e=>`<div class="entry-card"><div class="entry-title">${e.role||''}</div><div class="entry-sub">${e.company||''}</div><div class="entry-date">${e.period||''}</div><div class="entry-desc">${e.desc||''}</div></div>`).join(''); |
| return ` |
| <div class="theme-minimal"> |
| <div class="cv-top-bar"> |
| <div class="cv-photo-wrap">${d.photo?`<img src="${d.photo}" alt="Profile">`:`<div class="ph">๐ค</div>`}</div> |
| <div><div class="cv-name">${d.name}</div><div class="cv-title">${d.title}</div></div> |
| </div> |
| <div class="cv-body"> |
| <div class="cv-left"> |
| <div class="section-title">Contact</div> |
| ${d.phone?`<div class="left-label">Phone</div><div class="left-value">${d.phone}</div>`:''} |
| ${d.email?`<div class="left-label">Email</div><div class="left-value">${d.email}</div>`:''} |
| ${d.location?`<div class="left-label">Location</div><div class="left-value">${d.location}</div>`:''} |
| ${d.skills.length?`<div class="section-title" style="margin-top:20px;">Skills</div><div>${minSkillPills}</div>`:''} |
| </div> |
| <div class="cv-right"> |
| ${d.summary?`<div class="section-title">About</div><p class="entry-desc" style="margin-bottom:16px;">${d.summary}</p>`:''} |
| ${minExp?`<div class="section-title">Experience</div>${minExp}`:''} |
| ${minEdu?`<div class="section-title">Education</div>${minEdu}`:''} |
| </div> |
| </div> |
| </div>`; |
| |
| case 'coral': |
| const coralSkillTags = d.skills.filter(s=>s.trim()).map(s=>`<span class="skill-tag">${s.trim()}</span>`).join(''); |
| const coralEdu = d.edu.map(e=>`<div class="entry-wrap"><div class="entry-title">${e.degree||''}</div><div class="entry-sub">${e.institution||''}</div><div class="entry-date">${e.year||''}</div></div>`).join(''); |
| const coralExp = d.exp.map(e=>`<div class="entry-wrap"><div class="entry-title">${e.role||''}</div><div class="entry-sub">${e.company||''}</div><div class="entry-date">${e.period||''}</div><div class="entry-desc">${e.desc||''}</div></div>`).join(''); |
| return ` |
| <div class="theme-coral"> |
| <div class="cv-header"> |
| <div class="cv-photo">${d.photo?`<img src="${d.photo}" alt="Profile">`:`<div class="ph">๐ค</div>`}</div> |
| <div> |
| <div class="cv-name">${d.name}</div> |
| <div class="cv-title">${d.title}</div> |
| <div class="contact-row"> |
| ${d.phone?`<span class="contact-chip">๐ ${d.phone}</span>`:''} |
| ${d.email?`<span class="contact-chip">โ ${d.email}</span>`:''} |
| ${d.location?`<span class="contact-chip">๐ ${d.location}</span>`:''} |
| </div> |
| </div> |
| </div> |
| <div class="cv-body"> |
| <div class="cv-left"> |
| ${d.skills.length?`<div class="section-title">Skills</div><div>${coralSkillTags}</div>`:''} |
| ${d.langs.length?`<div class="section-title" style="margin-top:16px;">Languages</div>${d.langs.filter(l=>l.trim()).map(l=>`<div style="margin-bottom:8px;">โข ${l.trim()}</div>`).join('')}`:''} |
| </div> |
| <div class="cv-right"> |
| ${d.summary?`<div class="section-title">About Me</div><div class="entry-desc" style="margin-bottom:16px;">${d.summary}</div>`:''} |
| ${coralExp?`<div class="section-title">Experience</div>${coralExp}`:''} |
| ${coralEdu?`<div class="section-title">Education</div>${coralEdu}`:''} |
| </div> |
| </div> |
| </div>`; |
| |
| case 'forest': |
| case 'clean': |
| const forestSkills = d.skills.filter(s=>s.trim()).map(s=>`<div style="font-size:12px;color:rgba(255,255,255,0.85);margin-bottom:6px;"><span style="display:inline-block;width:8px;height:8px;border-radius:50%;background:#40916c;margin:2px 4px 2px 0;vertical-align:middle;"></span>${s.trim()}</div>`).join(''); |
| const forestEdu = d.edu.map(e=>`<div style="margin-bottom:14px;padding-bottom:14px;border-bottom:1px solid #eee;"><div class="entry-title">${e.degree||''}</div><div class="entry-sub">${e.institution||''}</div><div class="entry-date">${e.year||''}</div></div>`).join(''); |
| const forestExp = d.exp.map(e=>`<div style="margin-bottom:14px;padding-bottom:14px;border-bottom:1px solid #eee;"><div class="entry-title">${e.role||''}</div><div class="entry-sub">${e.company||''}</div><div class="entry-date">${e.period||''}</div><div class="entry-desc">${e.desc||''}</div></div>`).join(''); |
| return ` |
| <div class="theme-forest clearfix" style="padding:0;"> |
| <div class="cv-sidebar-col"> |
| <div class="cv-photo">${d.photo?`<img src="${d.photo}" alt="Profile" style="width:110px;height:110px;border-radius:50%;object-fit:cover;border:4px solid #40916c;display:block;margin:0 auto 16px;">`:`<div class="ph" style="width:110px;height:110px;border-radius:50%;background:#40916c;display:flex;align-items:center;justify-content:center;font-size:40px;border:4px solid #74c69d;margin:0 auto 16px;">๐ค</div>`}</div> |
| <div style="text-align:center;color:white;font-size:15px;font-weight:700;">${d.name}</div> |
| <div style="text-align:center;color:#74c69d;font-size:10px;letter-spacing:1.5px;margin-bottom:20px;margin-top:4px;">${d.title}</div> |
| <div style="font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:2px;color:#74c69d;margin:18px 0 8px;">Contact</div> |
| ${d.phone?`<div style="font-size:11px;color:rgba(255,255,255,0.85);margin-bottom:6px;">๐ ${d.phone}</div>`:''} |
| ${d.email?`<div style="font-size:11px;color:rgba(255,255,255,0.85);margin-bottom:6px;">โ ${d.email}</div>`:''} |
| ${d.location?`<div style="font-size:11px;color:rgba(255,255,255,0.85);margin-bottom:6px;">๐ ${d.location}</div>`:''} |
| ${d.skills.length?`<div style="font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:2px;color:#74c69d;margin:18px 0 8px;">Skills</div>${forestSkills}`:''} |
| </div> |
| <div class="cv-main-col"> |
| <div style="font-size:26px;font-weight:700;color:#1b4332;margin-bottom:4px;">${d.name}</div> |
| <div style="font-size:12px;color:#40916c;font-weight:700;text-transform:uppercase;letter-spacing:1.5px;margin-bottom:28px;">${d.title}</div> |
| ${d.summary?`<div style="font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:2px;color:#1b4332;border-left:4px solid #40916c;padding-left:10px;margin:22px 0 12px;">Profile</div><div class="entry-desc" style="margin-bottom:8px;">${d.summary}</div>`:''} |
| ${forestExp?`<div style="font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:2px;color:#1b4332;border-left:4px solid #40916c;padding-left:10px;margin:22px 0 12px;">Work Experience</div>${forestExp}`:''} |
| ${forestEdu?`<div style="font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:2px;color:#1b4332;border-left:4px solid #40916c;padding-left:10px;margin:22px 0 12px;">Education</div>${forestEdu}`:''} |
| </div> |
| </div>`; |
| |
| case 'purple': |
| case 'tech': |
| const purpleSkillBars = d.skills.filter(s=>s.trim()).slice(0,8).map(s=>`<div style="font-size:11px;color:#555;margin-bottom:4px;display:flex;justify-content:space-between;"><span>${s.trim()}</span></div><div style="background:#e9d5ff;border-radius:4px;height:5px;margin-bottom:8px;"><div style="background:linear-gradient(90deg,#4a0e8f,#9b59b6);border-radius:4px;height:5px;width:${Math.floor(Math.random()*30+65)}%"></div></div>`).join(''); |
| const purpleEdu = d.edu.map(e=>`<div style="display:flex;gap:12px;margin-bottom:16px;"><div style="display:flex;flex-direction:column;align-items:center;width:12px;flex-shrink:0;"><div style="width:8px;height:8px;background:#4a0e8f;border-radius:50%;flex-shrink:0;margin-top:5px;"></div></div><div style="flex:1;"><div class="entry-title">${e.degree||''}</div><div style="font-size:12px;color:#7d3c98;font-weight:600;margin:2px 0;">${e.institution||''}</div><div class="entry-date">${e.year||''}</div></div></div>`).join(''); |
| const purpleExp = d.exp.map(e=>`<div style="display:flex;gap:12px;margin-bottom:16px;"><div style="display:flex;flex-direction:column;align-items:center;width:12px;flex-shrink:0;"><div style="width:8px;height:8px;background:#4a0e8f;border-radius:50%;flex-shrink:0;margin-top:5px;"></div></div><div style="flex:1;"><div class="entry-title">${e.role||''}</div><div class="entry-sub">${e.company||''}</div><div class="entry-date">${e.period||''}</div><div class="entry-desc">${e.desc||''}</div></div></div>`).join(''); |
| return ` |
| <div style="padding:0;"> |
| <div style="background:#4a0e8f;padding:0;display:flex;min-height:180px;"> |
| <div style="width:240px;flex-shrink:0;background:#3a0b70;padding:36px 24px;display:flex;flex-direction:column;align-items:center;"> |
| ${d.photo?`<img src="${d.photo}" style="width:100px;height:100px;border-radius:50%;object-fit:cover;border:3px solid #9b59b6;" alt="Profile">`:`<div style="width:100px;height:100px;border-radius:50%;background:#6c3483;display:flex;align-items:center;justify-content:center;font-size:40px;border:3px solid #9b59b6;">๐ค</div>`} |
| </div> |
| <div style="flex:1;padding:36px 30px;display:flex;flex-direction:column;justify-content:center;"> |
| <div style="font-size:28px;font-weight:800;color:white;letter-spacing:-0.5px;">${d.name}</div> |
| <div style="font-size:13px;color:#c39bd3;margin-top:6px;letter-spacing:1px;">${d.title}</div> |
| <div style="display:flex;flex-wrap:wrap;gap:10px;margin-top:16px;"> |
| ${d.phone?`<div style="font-size:11px;color:rgba(255,255,255,0.85);">๐ ${d.phone}</div>`:''} |
| ${d.email?`<div style="font-size:11px;color:rgba(255,255,255,0.85);">โ ${d.email}</div>`:''} |
| </div> |
| </div> |
| </div> |
| <div style="display:flex;"> |
| <div style="width:240px;flex-shrink:0;background:#f9f5ff;padding:24px;border-right:1px solid #e9d5ff;"> |
| ${purpleSkillBars?`<div style="font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:2px;color:#4a0e8f;margin:18px 0 10px;border-bottom:2px solid #c39bd3;padding-bottom:4px;">Skills</div>${purpleSkillBars}`:''} |
| </div> |
| <div style="flex:1;padding:24px 30px;"> |
| ${d.summary?`<div style="font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:2px;color:#4a0e8f;margin:18px 0 10px;border-bottom:2px solid #c39bd3;padding-bottom:4px;">About</div><div class="entry-desc" style="margin-bottom:12px;">${d.summary}</div>`:''} |
| ${purpleExp?`<div style="font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:2px;color:#4a0e8f;margin:18px 0 10px;border-bottom:2px solid #c39bd3;padding-bottom:4px;">Experience</div>${purpleExp}`:''} |
| </div> |
| </div> |
| </div>`; |
| |
| case 'slate': |
| case 'modern': |
| const slateSkillDots = d.skills.filter(s=>s.trim()).slice(0,7).map(s => { |
| const lvl = Math.floor(Math.random()*2+4); |
| const dots = Array.from({length:5},(_,i)=>`<div style="width:8px;height:8px;border-radius:50%;${i<lvl?'background:#2d3748':'background:#e2e8f0'}"></div>`).join(''); |
| return `<div style="display:flex;justify-content:space-between;align-items:center;font-size:12px;color:#4a5568;margin-bottom:6px;"><span>${s.trim()}</span><div style="display:flex;gap:3px;">${dots}</div></div>`; |
| }).join(''); |
| const slateEdu = d.edu.map(e=>`<div style="margin-bottom:14px;padding-bottom:14px;border-bottom:1px solid #edf2f7;"><div class="entry-title">${e.degree||''}</div><div style="font-size:12px;color:#4a5568;font-weight:600;margin:2px 0;">${e.institution||''}</div><div style="font-size:11px;color:#718096;margin-bottom:4px;">${e.year||''}</div></div>`).join(''); |
| const slateExp = d.exp.map(e=>`<div style="margin-bottom:14px;padding-bottom:14px;border-bottom:1px solid #edf2f7;"><div class="entry-title">${e.role||''}</div><div style="font-size:12px;color:#4a5568;font-weight:600;margin:2px 0;">${e.company||''}</div><div style="font-size:11px;color:#718096;margin-bottom:4px;">${e.period||''}</div><div style="font-size:12px;color:#718096;line-height:1.6;">${e.desc||''}</div></div>`).join(''); |
| return ` |
| <div style="padding:0;"> |
| <div style="background:#2d3748;padding:36px 40px;display:flex;align-items:center;gap:28px;"> |
| ${d.photo?`<img src="${d.photo}" style="width:95px;height:95px;border-radius:12px;object-fit:cover;border:3px solid #4a5568;" alt="Profile">`:`<div style="width:95px;height:95px;border-radius:12px;background:#4a5568;display:flex;align-items:center;justify-content:center;font-size:38px;border:3px solid #718096;">๐ค</div>`} |
| <div> |
| <div style="font-size:30px;font-weight:800;color:white;">${d.name}</div> |
| <div style="font-size:13px;color:#a0aec0;margin-top:4px;">${d.title}</div> |
| <div style="display:flex;gap:16px;margin-top:12px;flex-wrap:wrap;"> |
| ${d.phone?`<span style="font-size:11px;color:#a0aec0;">๐ ${d.phone}</span>`:''} |
| ${d.email?`<span style="font-size:11px;color:#a0aec0;">โ ${d.email}</span>`:''} |
| </div> |
| </div> |
| </div> |
| <div style="display:flex;"> |
| <div style="width:220px;flex-shrink:0;background:#f7fafc;padding:24px 20px;border-right:2px solid #edf2f7;"> |
| ${slateSkillDots?`<div style="font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:2px;color:#2d3748;background:#edf2f7;padding:6px 10px;border-radius:4px;margin:18px 0 10px;">Skills</div>${slateSkillDots}`:''} |
| </div> |
| <div style="flex:1;padding:24px 30px;"> |
| ${d.summary?`<div style="font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:2px;color:#2d3748;background:#edf2f7;padding:6px 10px;border-radius:4px;margin:18px 0 10px;">Profile</div><div class="entry-desc" style="margin-bottom:12px;">${d.summary}</div>`:''} |
| ${slateExp?`<div style="font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:2px;color:#2d3748;background:#edf2f7;padding:6px 10px;border-radius:4px;margin:18px 0 10px;">Experience</div>${slateExp}`:''} |
| </div> |
| </div> |
| </div>`; |
| |
| case 'ocean': |
| case 'elegant': |
| const oceanSkillBadges = d.skills.filter(s=>s.trim()).map(s=>`<span style="display:inline-block;background:#006BA6;color:white;padding:5px 14px;border-radius:20px;font-size:11px;margin:3px;font-weight:600;">${s.trim()}</span>`).join(''); |
| const oceanEdu = d.edu.map(e=>`<div style="background:#f0f9ff;border-left:4px solid #0496FF;padding:14px;margin-bottom:14px;border-radius:6px;"><div class="entry-title">${e.degree||''}</div><div style="font-size:12px;color:#006BA6;font-weight:600;margin:2px 0;">${e.institution||''}</div><div style="font-size:11px;color:#999;margin-bottom:4px;">${e.year||''}</div></div>`).join(''); |
| const oceanExp = d.exp.map(e=>`<div style="background:#f0f9ff;border-left:4px solid #0496FF;padding:14px;margin-bottom:14px;border-radius:6px;"><div class="entry-title">${e.role||''}</div><div style="font-size:12px;color:#006BA6;font-weight:600;margin:2px 0;">${e.company||''}</div><div style="font-size:11px;color:#999;margin-bottom:4px;">${e.period||''}</div><div class="entry-desc">${e.desc||''}</div></div>`).join(''); |
| return ` |
| <div style="padding:0;"> |
| <div style="background:linear-gradient(135deg,#006BA6 0%,#0496FF 100%);padding:40px;text-align:center;color:white;"> |
| ${d.photo?`<img src="${d.photo}" style="width:110px;height:110px;border-radius:50%;object-fit:cover;border:4px solid rgba(255,255,255,0.4);display:block;margin:0 auto 16px;" alt="Profile">`:`<div style="width:110px;height:110px;border-radius:50%;background:rgba(255,255,255,0.2);display:flex;align-items:center;justify-content:center;font-size:42px;border:4px solid rgba(255,255,255,0.4);margin:0 auto 16px;">๐ค</div>`} |
| <div style="font-size:32px;font-weight:800;color:white;letter-spacing:-1px;">${d.name}</div> |
| <div style="font-size:14px;color:rgba(255,255,255,0.9);margin-top:6px;letter-spacing:1px;">${d.title}</div> |
| <div style="display:flex;gap:14px;justify-content:center;margin-top:16px;flex-wrap:wrap;"> |
| ${d.phone?`<span style="font-size:11px;color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.15);padding:5px 14px;border-radius:20px;">๐ ${d.phone}</span>`:''} |
| ${d.email?`<span style="font-size:11px;color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.15);padding:5px 14px;border-radius:20px;">โ ${d.email}</span>`:''} |
| </div> |
| </div> |
| <div style="padding:32px 36px;"> |
| ${d.summary?`<div style="font-size:13px;font-weight:800;text-transform:uppercase;letter-spacing:1.5px;color:#006BA6;border-bottom:3px solid #0496FF;padding-bottom:6px;margin:24px 0 14px;">Professional Summary</div><div class="entry-desc" style="margin-bottom:16px;">${d.summary}</div>`:''} |
| ${oceanSkillBadges?`<div style="font-size:13px;font-weight:800;text-transform:uppercase;letter-spacing:1.5px;color:#006BA6;border-bottom:3px solid #0496FF;padding-bottom:6px;margin:24px 0 14px;">Skills</div><div style="margin-bottom:16px;">${oceanSkillBadges}</div>`:''} |
| ${oceanExp?`<div style="font-size:13px;font-weight:800;text-transform:uppercase;letter-spacing:1.5px;color:#006BA6;border-bottom:3px solid #0496FF;padding-bottom:6px;margin:24px 0 14px;">Work Experience</div>${oceanExp}`:''} |
| ${oceanEdu?`<div style="font-size:13px;font-weight:800;text-transform:uppercase;letter-spacing:1.5px;color:#006BA6;border-bottom:3px solid #0496FF;padding-bottom:6px;margin:24px 0 14px;">Education</div>${oceanEdu}`:''} |
| </div> |
| </div>`; |
| |
| case 'sunsetorange': |
| case 'bold': |
| const sunsetSkills = d.skills.filter(s=>s.trim()).map(s=>`<div style="font-size:11px;color:rgba(255,255,255,0.9);margin-bottom:8px;line-height:1.5;"><span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:white;margin-right:6px;vertical-align:middle;"></span>${s.trim()}</div>`).join(''); |
| const sunsetEdu = d.edu.map(e=>`<div style="margin-bottom:16px;"><div class="entry-title">${e.degree||''}</div><div style="font-size:12px;color:#FF6B35;font-weight:600;margin:2px 0;">${e.institution||''}</div><div style="font-size:11px;color:#999;margin-bottom:4px;">${e.year||''}</div></div>`).join(''); |
| const sunsetExp = d.exp.map(e=>`<div style="margin-bottom:16px;"><div class="entry-title">${e.role||''}</div><div style="font-size:12px;color:#FF6B35;font-weight:600;margin:2px 0;">${e.company||''}</div><div style="font-size:11px;color:#999;margin-bottom:4px;">${e.period||''}</div><div class="entry-desc">${e.desc||''}</div></div>`).join(''); |
| return ` |
| <div class="clearfix" style="padding:0;"> |
| <div style="width:250px;min-height:1123px;background:linear-gradient(180deg,#FF6B35 0%,#F7931E 100%);color:white;padding:36px 24px;float:left;"> |
| ${d.photo?`<img src="${d.photo}" style="width:115px;height:115px;border-radius:20px;object-fit:cover;border:4px solid rgba(255,255,255,0.4);display:block;margin:0 auto 18px;" alt="Profile">`:`<div style="width:115px;height:115px;border-radius:20px;background:rgba(255,255,255,0.2);display:flex;align-items:center;justify-content:center;font-size:44px;border:4px solid rgba(255,255,255,0.4);margin:0 auto 18px;">๐ค</div>`} |
| <div style="text-align:center;font-size:18px;font-weight:700;color:white;margin-bottom:4px;">${d.name}</div> |
| <div style="text-align:center;font-size:11px;color:rgba(255,255,255,0.8);letter-spacing:1px;margin-bottom:24px;">${d.title}</div> |
| <div style="font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:1.5px;color:white;margin:20px 0 10px;border-bottom:2px solid rgba(255,255,255,0.3);padding-bottom:6px;">Contact</div> |
| ${d.phone?`<div style="font-size:11px;color:rgba(255,255,255,0.9);margin-bottom:8px;">๐ ${d.phone}</div>`:''} |
| ${d.email?`<div style="font-size:11px;color:rgba(255,255,255,0.9);margin-bottom:8px;">โ ${d.email}</div>`:''} |
| ${sunsetSkills?`<div style="font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:1.5px;color:white;margin:20px 0 10px;border-bottom:2px solid rgba(255,255,255,0.3);padding-bottom:6px;">Skills</div>${sunsetSkills}`:''} |
| </div> |
| <div style="margin-left:250px;padding:36px 32px;"> |
| <div style="font-size:28px;font-weight:700;color:#1a1a2e;margin-bottom:4px;">${d.name}</div> |
| <div style="font-size:13px;color:#FF6B35;font-weight:700;text-transform:uppercase;letter-spacing:1.5px;margin-bottom:28px;">${d.title}</div> |
| ${d.summary?`<div style="font-size:13px;font-weight:800;text-transform:uppercase;letter-spacing:1.5px;color:#FF6B35;margin:24px 0 14px;display:flex;align-items:center;gap:8px;"><span style="color:#F7931E;font-size:16px;">โ</span>About</div><div class="entry-desc" style="margin-bottom:12px;">${d.summary}</div>`:''} |
| ${sunsetExp?`<div style="font-size:13px;font-weight:800;text-transform:uppercase;letter-spacing:1.5px;color:#FF6B35;margin:24px 0 14px;display:flex;align-items:center;gap:8px;"><span style="color:#F7931E;font-size:16px;">โ</span>Experience</div>${sunsetExp}`:''} |
| ${sunsetEdu?`<div style="font-size:13px;font-weight:800;text-transform:uppercase;letter-spacing:1.5px;color:#FF6B35;margin:24px 0 14px;display:flex;align-items:center;gap:8px;"><span style="color:#F7931E;font-size:16px;">โ</span>Education</div>${sunsetEdu}`:''} |
| </div> |
| </div>`; |
| |
| case 'mint': |
| case 'classic': |
| const mintSkillBoxes = d.skills.filter(s=>s.trim()).map(s=>`<span style="display:inline-block;background:white;border:2px solid #00D9C0;color:#00B4A0;padding:4px 12px;border-radius:6px;font-size:11px;margin:3px;font-weight:600;">${s.trim()}</span>`).join(''); |
| const mintEdu = d.edu.map(e=>`<div style="margin-bottom:14px;padding-bottom:14px;border-bottom:1px solid #e8f8f6;"><div class="entry-title">${e.degree||''}</div><div style="font-size:12px;color:#00B4A0;font-weight:600;margin:2px 0;">${e.institution||''}</div><div style="font-size:11px;color:#999;margin-bottom:4px;">${e.year||''}</div></div>`).join(''); |
| const mintExp = d.exp.map(e=>`<div style="margin-bottom:14px;padding-bottom:14px;border-bottom:1px solid #e8f8f6;"><div class="entry-title">${e.role||''}</div><div style="font-size:12px;color:#00B4A0;font-weight:600;margin:2px 0;">${e.company||''}</div><div style="font-size:11px;color:#999;margin-bottom:4px;">${e.period||''}</div><div class="entry-desc">${e.desc||''}</div></div>`).join(''); |
| return ` |
| <div style="padding:0;"> |
| <div style="background:#00D9C0;padding:40px;display:flex;align-items:center;gap:30px;"> |
| ${d.photo?`<img src="${d.photo}" style="width:105px;height:105px;border-radius:50%;object-fit:cover;border:5px solid white;box-shadow:0 4px 12px rgba(0,0,0,0.15);" alt="Profile">`:`<div style="width:105px;height:105px;border-radius:50%;background:#00B4A0;display:flex;align-items:center;justify-content:center;font-size:42px;border:5px solid white;box-shadow:0 4px 12px rgba(0,0,0,0.15);">๐ค</div>`} |
| <div> |
| <div style="font-size:32px;font-weight:800;color:white;letter-spacing:-1px;">${d.name}</div> |
| <div style="font-size:14px;color:rgba(255,255,255,0.95);margin-top:6px;">${d.title}</div> |
| <div style="display:flex;gap:18px;margin-top:14px;flex-wrap:wrap;"> |
| ${d.phone?`<div style="font-size:11px;color:rgba(255,255,255,0.95);">๐ ${d.phone}</div>`:''} |
| ${d.email?`<div style="font-size:11px;color:rgba(255,255,255,0.95);">โ ${d.email}</div>`:''} |
| </div> |
| </div> |
| </div> |
| <div style="display:grid;grid-template-columns:1fr 1fr;gap:0;"> |
| <div style="padding:30px;background:#f0fffe;border-right:1px solid #d0f5f1;"> |
| ${d.summary?`<div style="font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:1.5px;color:#00B4A0;margin:20px 0 12px;position:relative;padding-left:16px;"><span style="position:absolute;left:0;top:50%;transform:translateY(-50%);width:8px;height:8px;background:#00D9C0;border-radius:50%;"></span>About</div><div class="entry-desc" style="margin-bottom:12px;">${d.summary}</div>`:''} |
| ${mintSkillBoxes?`<div style="font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:1.5px;color:#00B4A0;margin:20px 0 12px;position:relative;padding-left:16px;"><span style="position:absolute;left:0;top:50%;transform:translateY(-50%);width:8px;height:8px;background:#00D9C0;border-radius:50%;"></span>Skills</div><div style="margin-bottom:12px;">${mintSkillBoxes}</div>`:''} |
| </div> |
| <div style="padding:30px;"> |
| ${mintExp?`<div style="font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:1.5px;color:#00B4A0;margin:20px 0 12px;position:relative;padding-left:16px;"><span style="position:absolute;left:0;top:50%;transform:translateY(-50%);width:8px;height:8px;background:#00D9C0;border-radius:50%;"></span>Experience</div>${mintExp}`:''} |
| ${mintEdu?`<div style="font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:1.5px;color:#00B4A0;margin:20px 0 12px;position:relative;padding-left:16px;"><span style="position:absolute;left:0;top:50%;transform:translateY(-50%);width:8px;height:8px;background:#00D9C0;border-radius:50%;"></span>Education</div>${mintEdu}`:''} |
| </div> |
| </div> |
| </div>`; |
| |
| case 'rosegold': |
| case 'portfolio': |
| const roseSkillTags = d.skills.filter(s=>s.trim()).map(s=>`<span style="display:inline-block;background:#E8B4B8;color:#5D3A3A;padding:4px 12px;border-radius:20px;font-size:11px;margin:3px;font-weight:600;">${s.trim()}</span>`).join(''); |
| const roseEdu = d.edu.map(e=>`<div style="margin-bottom:14px;"><div class="entry-title">${e.degree||''}</div><div style="font-size:12px;color:#C9A9A6;font-weight:600;margin:2px 0;">${e.institution||''}</div><div style="font-size:11px;color:#999;margin-bottom:4px;">${e.year||''}</div></div>`).join(''); |
| const roseExp = d.exp.map(e=>`<div style="margin-bottom:14px;"><div class="entry-title">${e.role||''}</div><div style="font-size:12px;color:#C9A9A6;font-weight:600;margin:2px 0;">${e.company||''}</div><div style="font-size:11px;color:#999;margin-bottom:4px;">${e.period||''}</div><div class="entry-desc">${e.desc||''}</div></div>`).join(''); |
| return ` |
| <div style="padding:0;"> |
| <div style="background:linear-gradient(135deg,#C9A9A6 0%,#E8B4B8 100%);padding:38px 40px;"> |
| <div style="display:flex;align-items:center;gap:26px;"> |
| ${d.photo?`<img src="${d.photo}" style="width:100px;height:100px;border-radius:16px;object-fit:cover;border:3px solid rgba(255,255,255,0.6);" alt="Profile">`:`<div style="width:100px;height:100px;border-radius:16px;background:rgba(255,255,255,0.3);display:flex;align-items:center;justify-content:center;font-size:40px;border:3px solid rgba(255,255,255,0.6);">๐ค</div>`} |
| <div> |
| <div style="font-size:30px;font-weight:800;color:#5D3A3A;">${d.name}</div> |
| <div style="font-size:13px;color:#8B6B6B;margin-top:4px;letter-spacing:0.5px;">${d.title}</div> |
| <div style="display:flex;gap:16px;margin-top:14px;flex-wrap:wrap;"> |
| ${d.phone?`<span style="font-size:11px;color:#8B6B6B;background:rgba(255,255,255,0.5);padding:4px 12px;border-radius:20px;">๐ ${d.phone}</span>`:''} |
| ${d.email?`<span style="font-size:11px;color:#8B6B6B;background:rgba(255,255,255,0.5);padding:4px 12px;border-radius:20px;">โ ${d.email}</span>`:''} |
| </div> |
| </div> |
| </div> |
| </div> |
| <div style="display:flex;"> |
| <div style="width:235px;flex-shrink:0;background:#FAF4F4;padding:26px 22px;border-right:2px solid #F0E5E5;"> |
| ${roseSkillTags?`<div style="font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:1.5px;color:#C9A9A6;margin:20px 0 12px;padding-bottom:6px;border-bottom:2px solid #E8B4B8;">Skills</div><div style="margin-bottom:12px;">${roseSkillTags}</div>`:''} |
| </div> |
| <div style="flex:1;padding:26px 32px;"> |
| ${d.summary?`<div style="font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:1.5px;color:#C9A9A6;margin:20px 0 12px;padding-bottom:6px;border-bottom:2px solid #E8B4B8;">About Me</div><div class="entry-desc" style="margin-bottom:14px;">${d.summary}</div>`:''} |
| ${roseExp?`<div style="font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:1.5px;color:#C9A9A6;margin:20px 0 12px;padding-bottom:6px;border-bottom:2px solid #E8B4B8;">Experience</div>${roseExp}`:''} |
| ${roseEdu?`<div style="font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:1.5px;color:#C9A9A6;margin:20px 0 12px;padding-bottom:6px;border-bottom:2px solid #E8B4B8;">Education</div>${roseEdu}`:''} |
| </div> |
| </div> |
| </div>`; |
| |
| case 'dark': |
| const darkSkillPills = d.skills.filter(s=>s.trim()).map(s=>`<span style="display:inline-block;background:#FFD700;color:#000;padding:4px 12px;border-radius:20px;font-size:11px;margin:3px;font-weight:700;">${s.trim()}</span>`).join(''); |
| const darkEdu = d.edu.map(e=>`<div style="margin-bottom:14px;padding-bottom:14px;border-bottom:1px solid #333;"><div class="entry-title">${e.degree||''}</div><div style="font-size:12px;color:#FFD700;font-weight:600;margin:2px 0;">${e.institution||''}</div><div style="font-size:11px;color:#999;margin-bottom:4px;">${e.year||''}</div></div>`).join(''); |
| const darkExp = d.exp.map(e=>`<div style="margin-bottom:14px;padding-bottom:14px;border-bottom:1px solid #333;"><div class="entry-title">${e.role||''}</div><div style="font-size:12px;color:#FFD700;font-weight:600;margin:2px 0;">${e.company||''}</div><div style="font-size:11px;color:#999;margin-bottom:4px;">${e.period||''}</div><div style="font-size:12px;color:#ccc;line-height:1.6;">${e.desc||''}</div></div>`).join(''); |
| return ` |
| <div style="padding:0;background:#1a1a1a;"> |
| <div style="background:#000;padding:40px;border-bottom:3px solid #FFD700;"> |
| <div style="display:flex;align-items:center;gap:28px;"> |
| ${d.photo?`<img src="${d.photo}" style="width:100px;height:100px;border-radius:50%;object-fit:cover;border:4px solid #FFD700;" alt="Profile">`:`<div style="width:100px;height:100px;border-radius:50%;background:#333;display:flex;align-items:center;justify-content:center;font-size:40px;border:4px solid #FFD700;">๐ค</div>`} |
| <div> |
| <div style="font-size:32px;font-weight:800;color:white;letter-spacing:-1px;">${d.name}</div> |
| <div style="font-size:14px;color:#FFD700;margin-top:6px;letter-spacing:1px;text-transform:uppercase;">${d.title}</div> |
| <div style="display:flex;gap:18px;margin-top:14px;flex-wrap:wrap;"> |
| ${d.phone?`<div style="font-size:11px;color:#ccc;">๐ ${d.phone}</div>`:''} |
| ${d.email?`<div style="font-size:11px;color:#ccc;">โ ${d.email}</div>`:''} |
| </div> |
| </div> |
| </div> |
| </div> |
| <div style="display:flex;"> |
| <div style="width:240px;flex-shrink:0;background:#222;padding:28px 24px;border-right:1px solid #333;"> |
| ${darkSkillPills?`<div style="font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:2px;color:#FFD700;margin:20px 0 12px;">Skills</div><div style="margin-bottom:12px;">${darkSkillPills}</div>`:''} |
| </div> |
| <div style="flex:1;padding:28px 32px;background:#1a1a1a;"> |
| ${d.summary?`<div style="font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:2px;color:#FFD700;margin:20px 0 12px;">About</div><div style="font-size:12px;color:#ccc;line-height:1.6;margin-bottom:14px;">${d.summary}</div>`:''} |
| ${darkExp?`<div style="font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:2px;color:#FFD700;margin:20px 0 12px;">Experience</div>${darkExp}`:''} |
| ${darkEdu?`<div style="font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:2px;color:#FFD700;margin:20px 0 12px;">Education</div>${darkEdu}`:''} |
| </div> |
| </div> |
| </div>`; |
| |
| case 'crimson': |
| const crimsonSkillRects = d.skills.filter(s=>s.trim()).map(s=>`<span style="display:inline-block;background:#8B0000;color:white;padding:5px 12px;border-radius:4px;font-size:11px;margin:3px;font-weight:600;">${s.trim()}</span>`).join(''); |
| const crimsonEdu = d.edu.map(e=>`<div style="margin-bottom:14px;"><div class="entry-title">${e.degree||''}</div><div style="font-size:12px;color:#8B0000;font-weight:600;margin:2px 0;">${e.institution||''}</div><div style="font-size:11px;color:#999;margin-bottom:4px;">${e.year||''}</div></div>`).join(''); |
| const crimsonExp = d.exp.map(e=>`<div style="margin-bottom:14px;"><div class="entry-title">${e.role||''}</div><div style="font-size:12px;color:#8B0000;font-weight:600;margin:2px 0;">${e.company||''}</div><div style="font-size:11px;color:#999;margin-bottom:4px;">${e.period||''}</div><div class="entry-desc">${e.desc||''}</div></div>`).join(''); |
| return ` |
| <div style="padding:0;"> |
| <div style="background:#8B0000;padding:36px 40px;color:white;"> |
| <div style="display:flex;align-items:center;gap:26px;"> |
| ${d.photo?`<img src="${d.photo}" style="width:95px;height:95px;border-radius:12px;object-fit:cover;border:3px solid rgba(255,255,255,0.4);" alt="Profile">`:`<div style="width:95px;height:95px;border-radius:12px;background:#A52A2A;display:flex;align-items:center;justify-content:center;font-size:38px;border:3px solid rgba(255,255,255,0.4);">๐ค</div>`} |
| <div> |
| <div style="font-size:30px;font-weight:800;color:white;letter-spacing:-0.5px;">${d.name}</div> |
| <div style="font-size:13px;color:rgba(255,255,255,0.85);margin-top:4px;">${d.title}</div> |
| <div style="display:flex;gap:16px;margin-top:12px;flex-wrap:wrap;"> |
| ${d.phone?`<div style="font-size:11px;color:rgba(255,255,255,0.85);">๐ ${d.phone}</div>`:''} |
| ${d.email?`<div style="font-size:11px;color:rgba(255,255,255,0.85);">โ ${d.email}</div>`:''} |
| </div> |
| </div> |
| </div> |
| </div> |
| <div style="padding:32px 40px;"> |
| ${d.summary?`<div style="font-size:13px;font-weight:800;text-transform:uppercase;letter-spacing:1.5px;color:#8B0000;margin:24px 0 14px;border-left:5px solid #8B0000;padding-left:12px;">Professional Profile</div><div class="entry-desc" style="margin-bottom:16px;">${d.summary}</div>`:''} |
| <div style="display:grid;grid-template-columns:1fr 1fr;gap:32px;"> |
| <div> |
| ${crimsonExp?`<div style="font-size:13px;font-weight:800;text-transform:uppercase;letter-spacing:1.5px;color:#8B0000;margin:24px 0 14px;border-left:5px solid #8B0000;padding-left:12px;">Experience</div>${crimsonExp}`:''} |
| </div> |
| <div> |
| ${crimsonEdu?`<div style="font-size:13px;font-weight:800;text-transform:uppercase;letter-spacing:1.5px;color:#8B0000;margin:24px 0 14px;border-left:5px solid #8B0000;padding-left:12px;">Education</div>${crimsonEdu}`:''} |
| ${crimsonSkillRects?`<div style="font-size:13px;font-weight:800;text-transform:uppercase;letter-spacing:1.5px;color:#8B0000;margin:24px 0 14px;border-left:5px solid #8B0000;padding-left:12px;">Skills</div><div style="margin-bottom:12px;">${crimsonSkillRects}</div>`:''} |
| </div> |
| </div> |
| </div> |
| </div>`; |
| |
| default: |
| return ` |
| <div class="cv-header" style="padding:40px;background:linear-gradient(135deg,#111827,#6366f1);color:white"> |
| <div style="font-size:36px;font-weight:800">${d.name}</div> |
| <div>${d.title}</div> |
| </div> |
| <div class="cv-body" style="display:flex;padding:35px;gap:30px"> |
| <div class="cv-sidebar" style="width:35%"><b>Skills</b><p>${d.skills.join(', ')}</p></div> |
| <div class="cv-main"><b>Profile</b><p>${d.summary}</p><b>Experience</b>${expList}<b>Education</b>${eduList}</div> |
| </div>`; |
| |
| } |
| } |
| |
| async function downloadPDF() { |
| const btn = document.querySelector('button[onclick="downloadPDF()"]'); |
| const originalText = btn.innerHTML; |
| btn.innerHTML = '<span class="material-symbols-outlined animate-spin text-[14px]">sync</span> Exporting...'; |
| btn.disabled = true; |
| |
| const cv = document.getElementById('cv-preview'); |
| const originalTransform = cv.style.transform; |
| const originalMargin = cv.style.margin; |
| |
| cv.style.transform = 'none'; |
| cv.style.margin = '0'; |
| |
| try { |
| const canvas = await html2canvas(cv, { |
| scale: 2, |
| useCORS: true, |
| allowTaint: true, |
| backgroundColor: '#ffffff', |
| width: 794, |
| height: 1123 |
| }); |
| |
| const imgData = canvas.toDataURL('image/jpeg', 0.95); |
| const { jsPDF } = window.jspdf; |
| const pdf = new jsPDF('p', 'mm', 'a4'); |
| pdf.addImage(imgData, 'JPEG', 0, 0, 210, 297); |
| const name = document.getElementById('f-name').value || 'CV'; |
| pdf.save(`${name.replace(/\s+/g, '_')}_CV.pdf`); |
| |
| btn.innerHTML = '<span class="material-symbols-outlined text-[14px]">check</span> Done!'; |
| setTimeout(() => { |
| btn.innerHTML = originalText; |
| btn.disabled = false; |
| }, 2000); |
| } catch (err) { |
| console.error(err); |
| btn.innerHTML = '<span class="material-symbols-outlined text-[14px]">error</span> Failed'; |
| setTimeout(() => { |
| btn.innerHTML = originalText; |
| btn.disabled = false; |
| }, 2000); |
| } finally { |
| cv.style.transform = originalTransform; |
| cv.style.margin = originalMargin; |
| updateCV(); |
| } |
| } |
| |
| // Start the app |
| init(); |
| </script> |
| </body></html> |