Feat: Redesign homepage as a modern landing page

This commit is contained in:
2025-09-26 20:33:18 -07:00
parent 8f4f7b8465
commit c81ec0068c

View File

@@ -1,24 +1,88 @@
<!doctype html><html lang=en><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><title>4ev.link — shorten URLs</title><meta name=color-scheme content="light dark"><meta name=theme-color content=#ffffff media="(prefers-color-scheme: light)"><meta name=theme-color content=#000000 media="(prefers-color-scheme: dark)"><style> <!doctype html>
*{box-sizing:border-box}body{margin:0;display:grid;place-items:center;min-height:100dvh;background:#fff;color:#111;font:16px/1.4 system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,"Helvetica Neue",Arial}::selection{background:#0001}@media(prefers-color-scheme:dark){body{background:#000;color:#ddd}input,button{background:#111;color:#eee;border-color:#333}.muted{color:#999}}.w{width:min(680px,92vw)}h1{margin:0 0 12px;font:600 28px/1.1 system-ui,-apple-system,Segoe UI,Roboto}form{display:flex;gap:8px}input[type=text],#o{flex:1;padding:12px 14px;border:1px solid #ddd;border-radius:12px;outline:0;transition:.15s}input:focus{border-color:#000}button{padding:12px 16px;border:1px solid #000;background:#000;color:#fff;border-radius:12px;cursor:pointer;transition:.15s}button:disabled{opacity:.6;cursor:wait}#res{display:flex;gap:8px;margin-top:12px;align-items:center}.muted{font-size:12px;color:#666;margin-top:8px}#m{color:#c00;margin-top:8px;font-size:14px} <html lang="en" class="dark">
</style><main class=w> <head>
<h1><a href=/ style="text-decoration:none;color:inherit">4ev.link</a></h1> <meta charset="utf-8">
<form id=f autocomplete=on> <meta name="viewport" content="width=device-width,initial-scale=1">
<input id=i type=text placeholder="Paste a link or type: google.com" autocapitalize=off spellcheck=false autofocus> <title>4ev.link — Permanent, Short & Simple URL Shortener</title>
<button id=b type=submit>Shorten</button> <meta name="description" content="Create short, memorable, and permanent links for your long URLs. Fast, free, and easy to use. Perfect for sharing on social media.">
</form> <meta name="keywords" content="url shortener, link shortener, short url, permanent links, free url shortener">
<div id=res hidden> <link rel="canonical" href="https://4ev.link/">
<input id=o type=text readonly title="Your short link"> <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🔗</text></svg>">
<button id=c type=button>Copy</button> <meta property="og:type" content="website">
<a id=a target=_blank rel=noopener>Open</a> <meta property="og:url" content="https://4ev.link/">
<meta property="og:title" content="4ev.link — Permanent, Short & Simple URL Shortener">
<meta property="og:description" content="Create short, memorable, and permanent links for your long URLs. Fast, free, and easy to use.">
<meta property="twitter:card" content="summary">
<meta property="twitter:title" content="4ev.link — Permanent, Short & Simple URL Shortener">
<meta property="twitter:description" content="Create short, memorable, and permanent links for your long URLs. Fast, free, and easy to use.">
<meta name="color-scheme" content="light dark">
<meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#000000" media="(prefers-color-scheme: dark)">
<script src="https://cdn.tailwindcss.com"></script>
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lucide@latest/dist/lucide.min.js"></script>
</head>
<body class="bg-white dark:bg-black text-gray-800 dark:text-gray-200 antialiased font-sans">
<div class="min-h-screen flex flex-col">
<header class="w-full max-w-5xl mx-auto p-4 sm:p-6">
<nav class="flex items-center justify-between">
<a href="/" class="flex items-center gap-2 font-bold text-xl hover:opacity-80 transition-opacity">
<i data-lucide="link-2" class="w-6 h-6"></i><span>4ev.link</span>
</a>
<a href="#" class="px-4 py-2 text-sm font-semibold bg-gray-100 dark:bg-gray-800 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors">Sign In</a>
</nav>
</header>
<main class="flex-grow flex flex-col items-center justify-center p-4" x-data="shortener()">
<div class="w-full max-w-2xl text-center">
<h1 class="text-4xl sm:text-5xl md:text-6xl font-extrabold tracking-tight mb-4">
Shorten URLs that <span class="bg-clip-text text-transparent bg-gradient-to-r from-blue-500 to-teal-400">last</span>.
</h1>
<p class="text-lg text-gray-600 dark:text-gray-400 max-w-xl mx-auto mb-8">Create short, memorable, and permanent links. Paste your long URL below to get started.</p>
<form class="flex flex-col sm:flex-row gap-2" @submit.prevent="submit">
<input type="text" x-model="i" @input="e='';s=''" placeholder="https://your-long-url.com/goes/here" class="flex-grow w-full px-4 py-3 bg-white dark:bg-gray-900 border border-gray-300 dark:border-gray-700 rounded-lg focus:ring-2 focus:ring-blue-500 focus:outline-none transition" autocapitalize="off" spellcheck="false" autofocus>
<button type="submit" :disabled="l" class="inline-flex items-center justify-center gap-2 px-6 py-3 font-semibold text-white bg-blue-600 rounded-lg hover:bg-blue-700 disabled:bg-blue-400 dark:disabled:bg-blue-800 disabled:cursor-wait transition-colors">
<span x-show="!l"><i data-lucide="zap" class="w-5 h-5"></i></span>
<span x-show="l"><i data-lucide="loader-2" class="w-5 h-5 animate-spin"></i></span>
<span x-text="l?'Working...':'Shorten'"></span>
</button>
</form>
<div x-show="s" x-transition class="mt-4 p-3 bg-gray-50 dark:bg-gray-900/50 border border-gray-200 dark:border-gray-800 rounded-lg flex flex-col sm:flex-row items-center gap-3">
<input x-ref="output" :value="s" type="text" readonly class="flex-grow w-full px-3 py-2 bg-transparent focus:outline-none text-center sm:text-left" @click="$refs.output.select()">
<div class="flex gap-2">
<button @click="copy" class="inline-flex items-center gap-1.5 px-4 py-2 text-sm font-semibold bg-gray-200 dark:bg-gray-800 rounded-lg hover:bg-gray-300 dark:hover:bg-gray-700 transition-colors w-28 justify-center">
<span x-show="!c"><i data-lucide="copy" class="w-4 h-4"></i></span>
<span x-show="c"><i data-lucide="check" class="w-4 h-4 text-green-500"></i></span>
<span x-text="c?'Copied!':'Copy'"></span>
</button>
<a :href="s" target="_blank" rel="noopener" class="inline-flex items-center gap-1.5 px-4 py-2 text-sm font-semibold bg-gray-200 dark:bg-gray-800 rounded-lg hover:bg-gray-300 dark:hover:bg-gray-700 transition-colors">
<i data-lucide="arrow-up-right-from-square" class="w-4 h-4"></i><span>Open</span>
</a>
</div>
</div>
<p x-show="e" x-text="e" x-transition class="mt-4 text-red-500"></p>
</div>
<section class="w-full max-w-5xl mx-auto mt-24 sm:mt-32 text-center">
<h2 class="text-3xl font-bold mb-2">Simple. Fast. Reliable.</h2>
<p class="text-gray-600 dark:text-gray-400 mb-12">All the features you need, none of the bloat.</p>
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
<div class="p-6 bg-gray-50 dark:bg-gray-900/50 rounded-lg"><i data-lucide="infinity" class="w-10 h-10 mx-auto mb-4 text-blue-500"></i><h3 class="text-xl font-semibold mb-2">Permanent Links</h3><p class="text-gray-600 dark:text-gray-400">Your links will never expire. We mean it. 4ev-link stands for 'forever'.</p></div>
<div class="p-6 bg-gray-50 dark:bg-gray-900/50 rounded-lg"><i data-lucide="bar-chart-3" class="w-10 h-10 mx-auto mb-4 text-blue-500"></i><h3 class="text-xl font-semibold mb-2">Analytics</h3><p class="text-gray-600 dark:text-gray-400">Track clicks and get insights into your audience. (Coming Soon)</p></div>
<div class="p-6 bg-gray-50 dark:bg-gray-900/50 rounded-lg"><i data-lucide="braces" class="w-10 h-10 mx-auto mb-4 text-blue-500"></i><h3 class="text-xl font-semibold mb-2">Developer API</h3><p class="text-gray-600 dark:text-gray-400">Integrate our shortener into your own application with a simple JSON API.</p></div>
</div>
</section>
</main>
<footer class="w-full max-w-5xl mx-auto p-4 sm:p-6 text-center text-sm text-gray-500">&copy; <span x-text="new Date().getFullYear()"></span> 4ev.link. All Rights Reserved.</footer>
</div> </div>
<p id=m></p>
<p class=muted>Shorten URLs that last. Works with domains or full links.</p>
<noscript class=muted>Enable JavaScript to shorten links.</noscript>
</main>
<script> <script>
const $=q=>document.querySelector(q),f=$('#f'),i=$('#i'),b=$('#b'),m=$('#m'),R=$('#res'),o=$('#o'),c=$('#c'),a=$('#a'),norm=u=>{try{return new URL(u).href}catch(_){try{return new URL('https://'+u).href}catch(_){}}}; lucide.createIcons();
f.onsubmit=async e=>{e.preventDefault();m.textContent='';let u=norm(i.value.trim());if(!u)return m.textContent='Enter a valid URL';b.disabled=1;b.textContent='…';try{let r=await fetch('/api/create',{method:'POST',headers:{'Content-Type':'application/json','Accept':'application/json'},body:JSON.stringify({url:u})});if(!r.ok)throw new Error(await r.text()||r.statusText);let d=await r.json();R.hidden=0;o.value=d.shortUrl;a.href=d.shortUrl;o.focus();o.select()}catch(err){R.hidden=1;m.textContent=err.message||'Something went wrong'}b.disabled=0;b.textContent='Shorten'}; document.addEventListener('alpine:init',()=>{Alpine.data('shortener',()=>({i:'',s:'',e:'',l:!1,c:!1,norm(t){try{return new URL(t).href}catch(o){try{return new URL('https://'+t).href}catch(o){return null}}},async submit(){this.e='',this.s='';const t=this.norm(this.i.trim());if(!t)return void(this.e='Please enter a valid URL.');this.l=!0;try{const o=await fetch('/api/create',{method:'POST',headers:{'Content-Type':'application/json','Accept':'application/json'},body:JSON.stringify({url:t})});if(!o.ok)throw new Error(await o.text()||o.statusText);const n=await o.json();this.s=n.shortUrl,this.i=''}catch(o){this.e=o.message||'An unknown error occurred.'}finally{this.l=!1}},copy(){this.s&&navigator.clipboard.writeText(this.s).then(()=>{this.c=!0,setTimeout(()=>this.c=!1,2e3)})}}))})
c.onclick=async()=>{o.select();try{await navigator.clipboard.writeText(o.value);c.textContent='Copied!';setTimeout(_=>c.textContent='Copy',800)}catch(_){document.execCommand('copy')}};
o.onclick=_=>o.select();i.oninput=_=>{R.hidden=1;m.textContent=''};
</script> </script>
</body>
</html> </html>