278 lines
3.8 KiB
HTML
278 lines
3.8 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>see</title>
|
|
<link rel="icon" type="image/png" href="favicon.png">
|
|
<style>
|
|
*{
|
|
margin:0;
|
|
padding:0;
|
|
box-sizing:border-box;
|
|
}
|
|
|
|
body{
|
|
background:#0f0f10;
|
|
color:#e6e6e6;
|
|
font-family:monospace;
|
|
margin:0;
|
|
height:100vh;
|
|
display:flex;
|
|
align-items:center;
|
|
justify-content:center;
|
|
padding:20px;
|
|
}
|
|
|
|
.container{
|
|
width:100%;
|
|
max-width:600px;
|
|
}
|
|
|
|
.header{
|
|
display:flex;
|
|
align-items:center;
|
|
gap:14px;
|
|
margin-bottom:24px;
|
|
}
|
|
|
|
.logo{
|
|
font-size:28px;
|
|
color:#fff;
|
|
}
|
|
|
|
form{
|
|
display:flex;
|
|
}
|
|
|
|
input{
|
|
flex:1;
|
|
background:#111;
|
|
border:1px solid #333;
|
|
border-right:none;
|
|
color:#eee;
|
|
font-family:monospace;
|
|
font-size:14px;
|
|
padding:10px;
|
|
}
|
|
|
|
input:focus{
|
|
outline:none;
|
|
border-color:#666;
|
|
}
|
|
|
|
button{
|
|
background:#1c1c1c;
|
|
border:1px solid #333;
|
|
color:#fff;
|
|
font-family:monospace;
|
|
padding:0 18px;
|
|
cursor:pointer;
|
|
}
|
|
|
|
button:hover{
|
|
background:#2a2a2a;
|
|
}
|
|
|
|
button:disabled{
|
|
opacity:.5;
|
|
cursor:not-allowed;
|
|
}
|
|
|
|
.output{
|
|
display:none;
|
|
margin-top:20px;
|
|
border:1px solid #333;
|
|
padding:14px;
|
|
}
|
|
|
|
.output.show{
|
|
display:block;
|
|
}
|
|
|
|
.label{
|
|
font-size:11px;
|
|
color:#666;
|
|
text-transform:uppercase;
|
|
margin-bottom:10px;
|
|
}
|
|
|
|
.output a{
|
|
display:block;
|
|
color:#66ff99;
|
|
text-decoration:none;
|
|
word-break:break-all;
|
|
font-size:15px;
|
|
}
|
|
|
|
.output a:hover{
|
|
text-decoration:underline;
|
|
}
|
|
|
|
.original{
|
|
margin-top:8px;
|
|
font-size:12px;
|
|
color:#777;
|
|
word-break:break-all;
|
|
}
|
|
|
|
.copy{
|
|
margin-top:14px;
|
|
padding:6px 16px;
|
|
}
|
|
|
|
.error{
|
|
margin-top:12px;
|
|
font-size:12px;
|
|
color:#d66;
|
|
}
|
|
|
|
.footer{
|
|
display:flex;
|
|
justify-content:space-between;
|
|
align-items:center;
|
|
margin-top:24px;
|
|
padding-top:12px;
|
|
border-top:1px solid #222;
|
|
font-size:12px;
|
|
color:#666;
|
|
}
|
|
|
|
.footer code{
|
|
font-family:inherit;
|
|
color:#888;
|
|
}
|
|
|
|
@media(max-width:600px){
|
|
|
|
.header{
|
|
flex-wrap:wrap;
|
|
}
|
|
|
|
form{
|
|
flex-direction:column;
|
|
}
|
|
|
|
input{
|
|
border-right:1px solid #333;
|
|
border-bottom:none;
|
|
}
|
|
|
|
button{
|
|
padding:10px;
|
|
}
|
|
|
|
.footer{
|
|
flex-direction:column;
|
|
align-items:flex-start;
|
|
gap:6px;
|
|
}
|
|
|
|
}
|
|
</style>
|
|
|
|
</head>
|
|
<body>
|
|
|
|
<div class="container">
|
|
|
|
<div class="header">
|
|
<div class="logo">see</div>
|
|
</div>
|
|
|
|
<form id="f">
|
|
<input
|
|
type="url"
|
|
id="u"
|
|
placeholder="https://example.com"
|
|
autocomplete="off"
|
|
required>
|
|
<button type="submit" id="b">shorten</button>
|
|
</form>
|
|
|
|
<div id="e" class="error"></div>
|
|
|
|
<div id="o" class="output">
|
|
|
|
<div class="label">Short URL</div>
|
|
|
|
<a href="#" id="l" target="_blank"></a>
|
|
|
|
<div class="original" id="r"></div>
|
|
|
|
<button class="copy" id="c" type="button">copy</button>
|
|
|
|
</div>
|
|
|
|
<div class="footer">
|
|
<div><code>POST /api/</code></div>
|
|
<div>curl -X POST -d "url=LINK" <span id="h"></span>/api/</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<script>
|
|
const $ = id => document.getElementById(id);
|
|
|
|
$("h").textContent = location.origin;
|
|
|
|
$("f").addEventListener("submit", async e => {
|
|
e.preventDefault();
|
|
|
|
$("b").disabled = true;
|
|
$("e").textContent = "";
|
|
$("o").classList.remove("show");
|
|
|
|
try {
|
|
|
|
const response = await fetch("/api/", {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type":"application/x-www-form-urlencoded"
|
|
},
|
|
body: "url=" + encodeURIComponent($("u").value)
|
|
});
|
|
|
|
const text = await response.text();
|
|
|
|
if (!response.ok) {
|
|
const json = JSON.parse(text);
|
|
throw new Error(json.error || "failed");
|
|
}
|
|
|
|
const shortURL = text.trim();
|
|
|
|
$("l").href = shortURL;
|
|
$("l").textContent = shortURL;
|
|
|
|
$("r").textContent = $("u").value;
|
|
|
|
$("o").classList.add("show");
|
|
|
|
} catch(err) {
|
|
|
|
$("e").textContent = err.message;
|
|
|
|
} finally {
|
|
|
|
$("b").disabled = false;
|
|
|
|
}
|
|
});
|
|
|
|
$("c").addEventListener("click", async () => {
|
|
|
|
await navigator.clipboard.writeText($("l").href);
|
|
|
|
const old = $("c").textContent;
|
|
$("c").textContent = "copied";
|
|
|
|
setTimeout(() => {
|
|
$("c").textContent = old;
|
|
}, 1200);
|
|
|
|
});
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|