mirror of
https://github.com/multipleof4/4ev.link.git
synced 2026-01-13 23:57:55 +00:00
146 lines
8.5 KiB
HTML
146 lines
8.5 KiB
HTML
<!doctype html><html lang=en>
|
||
<head>
|
||
<meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1">
|
||
<title>4ev.link — simple forever-short links</title>
|
||
<meta name=description content="4ev.link is a minimal, fast URL shortener. Free, no account needed. Paid custom URLs coming soon.">
|
||
<link rel=preconnect href=https://fonts.googleapis.com><link rel=preconnect href=https://fonts.gstatic.com crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&family=Space+Grotesk:wght@500;700&family=Roboto+Mono:wght@400;700&display=swap" rel=stylesheet>
|
||
<script src=//unpkg.com/alpinejs defer></script>
|
||
<script src=https://unpkg.com/lucide@latest defer></script>
|
||
<style>
|
||
:root{--bg:#fff;--fg:#111;--sub:#666;--mut:#888;--br:#e5e7eb;--card:#f8fafc;--ok:#111;--err:#b91c1c;--ring:0 0 0 3px rgba(0,0,0,.08)}
|
||
*{box-sizing:border-box}html,body{height:100%}body{margin:0;background:var(--bg);color:var(--fg);font:16px/1.45 Inter,system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,'Helvetica Neue',Arial,'Apple Color Emoji','Segoe UI Emoji';-webkit-font-smoothing:antialiased}
|
||
a{color:inherit;text-decoration:none}a:hover{text-decoration:underline}
|
||
.container{max-width:980px;margin:0 auto;padding:16px}
|
||
.nav{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 0}
|
||
.brand{display:inline-flex;align-items:center;gap:8px;font-weight:700}
|
||
.badge{font:700 12px/1 Inter;background:#111;color:#fff;border-radius:999px;padding:6px 10px}
|
||
.actions{display:flex;gap:8px}
|
||
.btn{appearance:none;border:1px solid var(--br);background:#fff;color:#111;border-radius:10px;padding:10px 14px;font-weight:600;cursor:pointer}
|
||
.btn:hover{box-shadow:var(--ring)}.btn:disabled{opacity:.6;cursor:not-allowed}
|
||
.btn.black{background:#111;color:#fff;border-color:#111}
|
||
.btn.ghost{background:transparent}
|
||
.hero{display:grid;gap:14px;place-items:center;text-align:center;padding:28px 0}
|
||
h1{font:700 clamp(24px,5.5vw,42px)/1.1 'Space Grotesk',Inter,system-ui;margin:0}
|
||
h2{font:600 18px/1.2 Inter;margin:0}
|
||
.sub{color:var(--sub);font-size:14px}
|
||
.card{background:var(--card);border:1px solid var(--br);border-radius:14px;padding:14px}
|
||
.grid{display:grid;gap:12px}
|
||
@media(min-width:720px){.grid-2{grid-template-columns:1fr 1fr}}
|
||
.input{display:flex;gap:8px;align-items:center;background:#fff;border:1px solid var(--br);border-radius:12px;padding:8px 8px}
|
||
.input:focus-within{box-shadow:var(--ring)}
|
||
input[type=url],input[type=text]{border:0;outline:0;background:transparent;width:100%;padding:10px 8px;font-size:16px}
|
||
small.mono{font:14px/1.3 'Roboto Mono',monospace;color:#333;background:#fff;border:1px dashed var(--br);border-radius:8px;padding:8px 10px;display:inline-flex;gap:6px;align-items:center}
|
||
.kbd{font:600 12px/1 'Roboto Mono',monospace;border:1px solid var(--br);border-radius:6px;padding:4px 6px;background:#fff;color:#333}
|
||
.row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
|
||
hr{border:0;border-top:1px solid var(--br);margin:16px 0}
|
||
.notice{font-size:13px;color:var(--mut)}
|
||
.result{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
|
||
.copy{display:inline-flex;align-items:center;gap:6px}
|
||
.tag{border:1px solid var(--br);border-radius:999px;padding:6px 10px;background:#fff;color:#111;font-weight:600}
|
||
.pricing .plan{display:grid;gap:10px}
|
||
.plan h3{margin:0;font:700 16px/1 Inter}
|
||
.dim{color:var(--mut)}
|
||
footer{color:#777;font-size:13px;padding:24px 0}
|
||
noscript{display:block;background:#fff3f3;border:1px solid #ffdede;color:#8a1616;padding:10px;border-radius:10px}
|
||
</style>
|
||
</head>
|
||
<body x-data="{url:'',out:'',slug:'',busy:!1,err:'',copied:!1,paid:!1,shorten:async function(){this.err='';this.out='';this.copied=!1;let t=this.url?.trim();if(!t)return this.err='Enter a valid URL';try{new URL(t)}catch(_){return this.err='Enter a valid URL'}this.busy=1;try{let r=await fetch('/',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:t})});if(!r.ok)throw new Error(await r.text()||'Failed');let d=await r.json();this.out=d.shortUrl}catch(e){this.err=String(e.message||e)}this.busy=0},copy:async function(v){try{await navigator.clipboard.writeText(v||this.out);this.copied=1;setTimeout(()=>this.copied=0,1600)}catch(_){this.copied=0}}}" x-init="lucide&&lucide.createIcons()">
|
||
<noscript>4ev.link works best with JavaScript enabled.</noscript>
|
||
|
||
<div class=container>
|
||
<nav class=nav>
|
||
<div class=brand><i data-lucide=infinity></i><a href=/ aria-label="Home">4ev.link</a><span class=badge>Free</span></div>
|
||
<div class=actions>
|
||
<a class="btn ghost" href=#login>Log in</a>
|
||
<a class="btn black" href=#signup>Sign up</a>
|
||
</div>
|
||
</nav>
|
||
|
||
<header class=hero>
|
||
<h1>Get ur 4ev.link <span aria-hidden=true style=color:#e11d48>❤️</span></h1>
|
||
<p class=sub>Free. No account needed. Paste a link, get a short one. Custom aliases for paid users (coming soon).</p>
|
||
</header>
|
||
|
||
<main class=grid>
|
||
<section class="card grid" aria-label="Shorten form">
|
||
<h2>Shorten a link</h2>
|
||
<form class=grid @submit.prevent="shorten">
|
||
<div class=input>
|
||
<i data-lucide=link-2></i>
|
||
<input type=url x-model=url inputmode=url spellcheck=false placeholder="https://example.com/some/very/long/url" aria-label="Paste a long URL">
|
||
<button class="btn black" type=submit :disabled=busy x-text="busy?'Shortening…':'Shorten'"></button>
|
||
</div>
|
||
</form>
|
||
<template x-if="err"><div class="row" role=alert style="color:var(--err)"><i data-lucide=alert-triangle></i><span x-text=err></span></div></template>
|
||
|
||
<template x-if="out">
|
||
<div class="result">
|
||
<i data-lucide=check-circle style=color:#16a34a></i>
|
||
<a class="tag" :href=out target=_blank rel=noopener x-text=out></a>
|
||
<button class="btn copy" @click.prevent="copy()"><i data-lucide=copy></i><span x-text="copied?'Copied!':'Copy'"></span></button>
|
||
</div>
|
||
</template>
|
||
|
||
<hr>
|
||
|
||
<div class="row">
|
||
<small class=mono><i data-lucide=sparkles></i>Free → random slug (ex: 4ev.link/aB9Z)</small>
|
||
<small class=mono><i data-lucide=lock></i>Custom alias → <b>Paid</b> <span class=dim>(coming soon)</span></small>
|
||
</div>
|
||
|
||
<div class="grid-2 grid" aria-hidden=true>
|
||
<div class=input title="Custom alias (Pro soon)">
|
||
<i data-lucide=tag></i>
|
||
<span class=dim style="padding:10px 8px">Alias (ex: /my-handle)</span>
|
||
<button class="btn" disabled>Pro soon</button>
|
||
</div>
|
||
<div class=input>
|
||
<i data-lucide=eye></i>
|
||
<span class=dim style="padding:10px 8px">Preview page <span class=kbd>soon</span></span>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="grid card" aria-label=Why>
|
||
<h2>Why 4ev.link?</h2>
|
||
<div class=grid-2 style="gap:10px">
|
||
<div class=row><i data-lucide=zap></i><div><b>Fast</b><div class=dim>Edge redirects in ~20ms</div></div></div>
|
||
<div class=row><i data-lucide=shield-check></i><div><b>Safe</b><div class=dim>Simple, open endpoints</div></div></div>
|
||
<div class=row><i data-lucide=clock></i><div><b>Forever</b><div class=dim>No expiry on free links</div></div></div>
|
||
<div class=row><i data-lucide=wrench></i><div><b>Low-friction</b><div class=dim>No account required</div></div></div>
|
||
</div>
|
||
<p class=notice>Tip: paste a URL and hit Enter. We’ll give you a short link you can share instantly.</p>
|
||
</section>
|
||
|
||
<section class="card grid pricing" aria-label=Pricing>
|
||
<h2>Pricing</h2>
|
||
<div class="grid-2 grid">
|
||
<div class=plan>
|
||
<h3>Free</h3>
|
||
<ul class=dim style="margin:0 0 6px 18px">
|
||
<li>Random 4-char slugs</li><li>No account needed</li><li>Unlimited redirects</li>
|
||
</ul>
|
||
<a class="btn black" href=#start>Start free</a>
|
||
</div>
|
||
<div class=plan>
|
||
<h3>Pro <span class=dim>(coming soon)</span></h3>
|
||
<ul class=dim style="margin:0 0 6px 18px">
|
||
<li>Custom aliases</li><li>Analytics</li><li>Team access</li>
|
||
</ul>
|
||
<button class="btn" disabled>Notify me soon</button>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
|
||
<footer class=row style="justify-content:space-between">
|
||
<div class=row><i data-lucide=copyright></i><span>4ev.link</span><span>·</span><span class=dim>Built on Cloudflare</span></div>
|
||
<div class=row><a href=#tos>Terms</a><span>·</span><a href=#privacy>Privacy</a><span>·</span><a href=https://github.com/4ev-link/4ev.link target=_blank rel=noopener class=dim>GitHub</a></div>
|
||
</footer>
|
||
</div>
|
||
|
||
<script>document.addEventListener('alpine:init',()=>{lucide&&lucide.createIcons()});</script>
|
||
</body>
|
||
</html>
|