SigCraft

邮箱签名生成器 · 简约 / 现代 / 经典 多种模板

点击或拖拽上传 Logo

已保存的签名

签名预览

实际尺寸渲染
填写左侧信息后自动预览
签名将在支持 HTML 的邮件客户端中生效
(function(){ window.onerror=function(m,u,l,c,e){console.error('Global:',m,e)}; window.addEventListener('unhandledrejection',function(e){console.error('Unhandled:',e.reason)}); if(typeof escHtml==='undefined'){window.escHtml=function(s){return String(s).replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"').replace(/'/g,''')}}; if(typeof updatePreview==='undefined'){window.updatePreview=function(){try{var n=nameInput.value.trim()||'姓名';var t=titleInput.value.trim()||'';var c=companyInput.value.trim()||'';var e=emailInput.value.trim()||'';var p=phoneInput.value.trim()||'';var w=websiteInput.value.trim()||'';var logo=state.logoDataURL?'Logo':'';var sd=getSocialData();var html='';if(logo)html+='';html+='';html+='';html+='
'+logo+'
'+escHtml(n)+'
';if(t)html+='
'+escHtml(t)+'
';if(c)html+='
'+escHtml(c)+'
';html+='
';if(e)html+='
📧 '+escHtml(e)+'
';if(p)html+='
📞 '+escHtml(p)+'
';if(w)html+='
🌐 '+escHtml(w)+'
';html+='
';previewBody.innerHTML=html}catch(e){console.error('updatePreview error:',e)}}}; function bindButtons(){var save=document.getElementById('saveBtn');var clear=document.getElementById('clearBtn');var copy=document.getElementById('copyHtmlBtn');var dl=document.getElementById('downloadHtmlBtn');if(save){save.addEventListener('click',function(){try{var data={name:nameInput.value,title:titleInput.value,company:companyInput.value,email:emailInput.value,phone:phoneInput.value,website:websiteInput.value,logoDataURL:state.logoDataURL,template:state.template,social:getSocialData(),customSocials:state.customSocials};localStorage.setItem('sigcraft_saved_'+Date.now(),JSON.stringify(data));loadSavedList();showToast('已保存')}catch(e){console.error('Save error',e)}})}if(clear){clear.addEventListener('click',function(){try{nameInput.value='';titleInput.value='';companyInput.value='';emailInput.value='';phoneInput.value='';websiteInput.value='';state.logoDataURL=null;logoPreview.style.display='none';logoUploadArea.style.display='block';updatePreview();showToast('已清空')}catch(e){console.error('Clear error',e)}})}if(copy){copy.addEventListener('click',function(){try{var html=previewBody.innerHTML;if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(html).then(function(){showToast('已复制 HTML')}).catch(function(){fallbackCopy(html)})}else{fallbackCopy(html)}}catch(e){console.error('Copy error',e)}})}if(dl){dl.addEventListener('click',function(){try{var html=previewBody.innerHTML;var blob=new Blob([html],{type:'text/html'});var url=URL.createObjectURL(blob);var a=document.createElement('a');a.href=url;a.download='signature.html';a.click();URL.revokeObjectURL(url);showToast('已下载')}catch(e){console.error('Download error',e)}})}} function fallbackCopy(t){var ta=document.createElement('textarea');ta.value=t;ta.style.position='fixed';ta.style.left='-9999px';document.body.appendChild(ta);ta.select();document.execCommand('copy');document.body.removeChild(ta);showToast('已复制 HTML')} function loadSavedList(){var container=document.getElementById('savedItems');if(!container)return;var keys=Object.keys(localStorage).filter(function(k){return k.startsWith('sigcraft_saved_')});if(keys.length===0){container.innerHTML='
暂无保存
';return}container.innerHTML=keys.reverse().map(function(key){var data=JSON.parse(localStorage.getItem(key)||'{}');return '
'+escHtml(data.name||'无名称')+'
'}).join('');container.querySelectorAll('.load').forEach(function(btn){btn.addEventListener('click',function(){try{var key=this.dataset.key;var data=JSON.parse(localStorage.getItem(key));if(data){nameInput.value=data.name||'';titleInput.value=data.title||'';companyInput.value=data.company||'';emailInput.value=data.email||'';phoneInput.value=data.phone||'';websiteInput.value=data.website||'';state.logoDataURL=data.logoDataURL||null;if(state.logoDataURL){logoImg.src=state.logoDataURL;logoPreview.style.display='flex';logoUploadArea.style.display='none'}else{logoPreview.style.display='none';logoUploadArea.style.display='block'}state.template=data.template||'simple';document.querySelectorAll('.mode-btn').forEach(function(b){b.classList.toggle('active',b.dataset.template===state.template)});updateSlider();state.customSocials=data.customSocials||[];renderCustomSocials();if(data.social){Object.keys(data.social).forEach(function(k){if(k==='custom')return;var toggle=document.querySelector('.social-toggle[data-key="'+k+'"]');var urlInput=document.querySelector('.social-url[data-key="'+k+'"]');if(toggle)toggle.checked=data.social[k].enabled;if(urlInput)urlInput.value=data.social[k].url||''})}updatePreview();showToast('已加载')}}catch(e){console.error('Load error',e)}})});container.querySelectorAll('.del').forEach(function(btn){btn.addEventListener('click',function(){localStorage.removeItem(this.dataset.key);loadSavedList();showToast('已删除')})})} loadSavedList(); if(!window.i18n){window.i18n=(function(){var tr={'zh-CN':{'app.name':'SigCraft','app.subtitle':'邮箱签名生成器 · 简约 / 现代 / 经典 多种模板','form.personalInfo':'个人信息','form.logo':'Logo / 头像','form.socialMedia':'社交媒体','form.template':'签名模板','preview.title':'签名预览','preview.hint':'实际尺寸渲染','preview.placeholder':'填写左侧信息后自动预览','preview.note':'签名将在支持 HTML 的邮件客户端中生效','btn.copyHtml':'复制 HTML','btn.downloadHtml':'下载 .html','btn.save':'保存到本地','btn.clear':'清空','btn.addCustomSocial':'+ 添加自定义社交','template.simple':'简约','template.modern':'现代','template.classic':'经典','saved.title':'已保存的签名','saved.empty':'暂无保存','toast.saved':'已保存','toast.cleared':'已清空','toast.copied':'已复制 HTML','toast.downloaded':'已下载','toast.loaded':'已加载','toast.deleted':'已删除'},'en':{'app.name':'SigCraft','app.subtitle':'Email Signature Generator · Simple / Modern / Classic','form.personalInfo':'Personal Info','form.logo':'Logo / Avatar','form.socialMedia':'Social Media','form.template':'Template','preview.title':'Preview','preview.hint':'Real size','preview.placeholder':'Fill left side to preview','preview.note':'Signature works in HTML email clients','btn.copyHtml':'Copy HTML','btn.downloadHtml':'Download .html','btn.save':'Save','btn.clear':'Clear','btn.addCustomSocial':'+ Add Custom Social','template.simple':'Simple','template.modern':'Modern','template.classic':'Classic','saved.title':'Saved Signatures','saved.empty':'No saved signatures','toast.saved':'Saved','toast.cleared':'Cleared','toast.copied':'HTML copied','toast.downloaded':'Downloaded','toast.loaded':'Loaded','toast.deleted':'Deleted'}};var cur='zh-CN';function t(k){return(tr[cur]&&tr[cur][k])||tr['zh-CN'][k]||k}function setLang(l){if(tr[l]){cur=l;document.querySelectorAll('[data-i18n]').forEach(function(el){el.textContent=t(el.getAttribute('data-i18n'))});document.querySelectorAll('[data-i18n-placeholder]').forEach(function(el){el.placeholder=t(el.getAttribute('data-i18n-placeholder'))})}}return{t:t,setLang:setLang,currentLang:function(){return cur}}})(); var h=document.querySelector('.header');if(h){var d=document.createElement('div');d.style.cssText='display:flex;justify-content:center;gap:10px;margin-top:8px;';var z=document.createElement('button');z.textContent='中文';z.className='btn btn-sm btn-outline';z.addEventListener('click',function(){i18n.setLang('zh-CN')});var en=document.createElement('button');en.textContent='English';en.className='btn btn-sm btn-outline';en.addEventListener('click',function(){i18n.setLang('en')});d.appendChild(z);d.appendChild(en);h.appendChild(d)}document.addEventListener('DOMContentLoaded',function(){i18n.setLang('zh-CN')})} if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',bindButtons)}else{bindButtons()} document.querySelectorAll('.text-input').forEach(function(inp){if(!inp.hasAttribute('maxlength'))inp.setAttribute('maxlength',200);if(inp.type==='email'){inp.addEventListener('blur',function(){var v=this.value.trim();if(v&&!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v)){this.style.borderColor='#ff453a';showToast('邮箱格式不正确')}else{this.style.borderColor=''}})}}); var obs=new MutationObserver(function(){document.querySelectorAll('#previewBody img').forEach(function(img){img.addEventListener('error',function(){this.alt='Image failed to load';this.style.border='1px dashed #ccc'})})});obs.observe(document.getElementById('previewBody'),{childList:true,subtree:true}); showToast('加载完成',1500); })(); `; } function updatePreview() { const data = getFormData(); const template = state.template; const sigHTML = buildSignatureHTML(data, template); previewBody.innerHTML = ''; if (sigHTML) { previewBody.innerHTML = sigHTML; } else { previewBody.innerHTML = '
填写左侧信息后自动预览
'; } } // ─── Actions ─────────────────────────────────── copyHtmlBtn.addEventListener('click', async () => { const data = getFormData(); const sigHTML = buildSignatureHTML(data, state.template); if (!sigHTML) { showToast('请先填写信息'); return; } const full = buildFullHTML(sigHTML); try { await navigator.clipboard.writeText(full); showToast('HTML 已复制到剪贴板'); } catch { showToast('复制失败'); } }); downloadHtmlBtn.addEventListener('click', () => { const data = getFormData(); const sigHTML = buildSignatureHTML(data, state.template); if (!sigHTML) { showToast('请先填写信息'); return; } const full = buildFullHTML(sigHTML); const blob = new Blob([full], { type: 'text/html;charset=utf-8' }); const link = document.createElement('a'); const name = (data.name || 'signature').replace(/\s+/g, '_'); link.download = `signature_${name}.html`; link.href = URL.createObjectURL(blob); link.click(); URL.revokeObjectURL(link.href); showToast('已下载签名文件'); }); saveBtn.addEventListener('click', () => { const data = getFormData(); if (!data.name || data.name === '您的姓名') { showToast('请先填写姓名'); return; } const sigHTML = buildSignatureHTML(data, state.template); const full = buildFullHTML(sigHTML); let saved = []; try { saved = JSON.parse(localStorage.getItem('sigcraft_saved') || '[]'); } catch { saved = []; } const entry = { id: Date.now(), name: data.name, company: data.company, template: state.template, html: full, createdAt: new Date().toISOString(), }; saved.push(entry); localStorage.setItem('sigcraft_saved', JSON.stringify(saved)); renderSavedList(); showToast('已保存到本地'); }); clearBtn.addEventListener('click', () => { nameInput.value = ''; titleInput.value = ''; companyInput.value = ''; emailInput.value = ''; phoneInput.value = ''; websiteInput.value = ''; state.logoDataURL = null; state.customSocials = []; logoPreview.style.display = 'none'; logoUploadArea.style.display = 'block'; document.querySelectorAll('.social-url').forEach(i => i.value = ''); renderCustomSocials(); updatePreview(); showToast('已清空所有内容'); }); // ─── Saved Signatures ────────────────────────── function renderSavedList() { let saved = []; try { saved = JSON.parse(localStorage.getItem('sigcraft_saved') || '[]'); } catch { saved = []; } const container = savedItems; if (saved.length === 0) { container.innerHTML = '
暂无保存的签名
'; return; } container.innerHTML = saved.slice().reverse().map(s => { const d = new Date(s.createdAt); const dateStr = `${d.getMonth()+1}/${d.getDate()}`; return `
${escHtml(s.name)}${s.company ? ' · ' + escHtml(s.company) : ''} ${dateStr}
`; }).join(''); container.querySelectorAll('.load-saved').forEach(btn => { btn.addEventListener('click', (e) => { e.stopPropagation(); loadSaved(parseInt(btn.dataset.id)); }); }); container.querySelectorAll('.del-saved').forEach(btn => { btn.addEventListener('click', (e) => { e.stopPropagation(); deleteSaved(parseInt(btn.dataset.id)); }); }); container.querySelectorAll('.saved-item').forEach(el => { el.addEventListener('click', () => { loadSaved(parseInt(el.dataset.id)); }); }); } function loadSaved(id) { let saved = []; try { saved = JSON.parse(localStorage.getItem('sigcraft_saved') || '[]'); } catch { return; } const entry = saved.find(s => s.id === id); if (!entry) { showToast('未找到该签名'); return; } showToast('已加载: ' + entry.name); } function deleteSaved(id) { let saved = []; try { saved = JSON.parse(localStorage.getItem('sigcraft_saved') || '[]'); } catch { return; } saved = saved.filter(s => s.id !== id); localStorage.setItem('sigcraft_saved', JSON.stringify(saved)); renderSavedList(); showToast('已删除'); } // ─── Toast ───────────────────────────────────── let toastTimer = null; function showToast(msg) { toastEl.textContent = msg; toastEl.classList.add('show'); clearTimeout(toastTimer); toastTimer = setTimeout(() => toastEl.classList.remove('show'), 2400); } // ─── Helpers ─────────────────────────────────── function escHtml(str) { const d = document.createElement('div'); d.textContent = str; return d.innerHTML; } // ─── Init ────────────────────────────────────── updatePreview(); renderSavedList(); renderCustomSocials();