mirror of
https://github.com/multipleof4/4ev.link.git
synced 2026-01-13 15:57:53 +00:00
62 lines
3.2 KiB
HTML
62 lines
3.2 KiB
HTML
<!doctype html><html lang=en>
|
|
<head>
|
|
<meta charset=utf-8>
|
|
<meta name=viewport content="width=device-width,initial-scale=1,viewport-fit=cover">
|
|
<title>4ev.link — Shorten URLs</title>
|
|
<meta name=color-scheme content=light>
|
|
<link rel="icon" href="data:,">
|
|
<style>
|
|
*{box-sizing:border-box}html,body{height:100%}body{margin:0;font:16px/1.35 system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif;background:#fff;color:#111;-webkit-font-smoothing:antialiased}
|
|
a{color:inherit}
|
|
header{padding:16px}
|
|
.brand{font-weight:700;text-decoration:none}
|
|
main{max-width:720px;margin:14vh auto 0;padding:0 16px}
|
|
form{display:flex;gap:8px}
|
|
input{flex:1;padding:14px 12px;border:1px solid #e5e7eb;border-radius:0;outline-offset:2px}
|
|
button{padding:0 14px;border:1px solid #e5e7eb;border-radius:0;background:#111;color:#fff;display:inline-grid;place-items:center;min-width:48px}
|
|
button:disabled{opacity:.7;cursor:not-allowed}
|
|
i[data-lucide]{width:22px;height:22px}
|
|
#o{margin-top:12px}
|
|
.msg{margin-top:8px;color:#666;display:flex;gap:8px;align-items:center}
|
|
.err{color:#b00020}
|
|
.result{display:flex;align-items:center;gap:8px;margin-top:12px;flex-wrap:wrap}
|
|
.tag{padding:8px 10px;border:1px solid #e5e7eb;background:#fafafa}
|
|
.copy{border:1px solid #e5e7eb;background:#fff;color:#111;padding:8px 10px}
|
|
.spin{animation:sp 1s linear infinite}@keyframes sp{to{transform:rotate(1turn)}}
|
|
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<header><a class=brand href="/">4ev.link</a></header>
|
|
<main>
|
|
<form id=f autocomplete=off>
|
|
<input id=i type=url inputmode=url placeholder="Paste a long URL" aria-label="Long URL" required>
|
|
<button id=b type=submit title=Shorten aria-label=Shorten><i data-lucide=link-2></i><span class=sr-only>Shorten</span></button>
|
|
</form>
|
|
<output id=o role=status aria-live=polite></output>
|
|
</main>
|
|
<script src="https://unpkg.com/lucide@latest"></script>
|
|
<script>
|
|
(()=>{const $=q=>document.querySelector(q),f=$('#f'),I=$('#i'),B=$('#b'),O=$('#o'),ico=()=>{try{lucide.createIcons()}catch{}},set=(h)=>{O.innerHTML=h,ico()}
|
|
ico();
|
|
f.onsubmit=async e=>{
|
|
e.preventDefault();
|
|
let v=I.value.trim(); if(!v)return;
|
|
if(!/^https?:\/\//i.test(v))v='https://'+v;
|
|
B.disabled=1;const i=B.querySelector('i');i.setAttribute('data-lucide','loader-2');i.classList.add('spin');ico();
|
|
try{
|
|
const r=await fetch('/api/create',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:v})});
|
|
if(!r.ok)throw 0;const j=await r.json(),u=j.shortUrl;
|
|
set(`<div class=result><a class=tag href="${u}" target=_blank rel=noopener>${u}</a><button id=c class=copy type=button title=Copy><i data-lucide=copy></i></button></div><p class=msg>Tap to open, or copy to share.</p>`);
|
|
$('#c').onclick=async()=>{try{await navigator.clipboard.writeText(u);const k=$('#c i');k.setAttribute('data-lucide','check');ico();setTimeout(()=>{k.setAttribute('data-lucide','copy');ico()},1200)}catch{}}
|
|
}catch{
|
|
set(`<p class="msg err"><i data-lucide=alert-circle></i>Invalid URL</p>`)
|
|
}finally{
|
|
B.disabled=0;i.classList.remove('spin');i.setAttribute('data-lucide','link-2');ico()
|
|
}
|
|
};
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|