135 lines
3.7 KiB
HTML
135 lines
3.7 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>HyDEV Link Shortener</title>
|
|
<script src="https://unpkg.com/vue@3"></script>
|
|
<script src="https://www.unpkg.com/jquery@3.6.0/dist/jquery.min.js"></script>
|
|
<script src="https://www.unpkg.com/jquery-ui@1.13.2/dist/jquery-ui.min.js"></script>
|
|
<style>
|
|
body {
|
|
height: 100vh;
|
|
padding: 2rem;
|
|
background: #263238;
|
|
color: #B0BEC5;
|
|
line-height: 1.1;
|
|
display: flex;
|
|
margin: 0;
|
|
box-sizing: border-box;
|
|
|
|
font-family: Monaco, Menlo, Courier, Courier New, Andale Mono, monospace;
|
|
|
|
transition: all 0.5s ease;
|
|
}
|
|
|
|
#app {
|
|
margin: 40vh auto 0;
|
|
width: 100%;
|
|
text-align: center;
|
|
}
|
|
|
|
#app > * + * {
|
|
margin-top: 20px;
|
|
}
|
|
|
|
.btn {
|
|
cursor: pointer;
|
|
}
|
|
|
|
input {
|
|
background: none;
|
|
border: none;
|
|
outline: 0;
|
|
resize: none;
|
|
overflow: auto;
|
|
color: inherit;
|
|
font-size: 1rem;
|
|
font-family: inherit;
|
|
line-height: inherit;
|
|
text-align: center;
|
|
width: 100%;
|
|
}
|
|
|
|
a {
|
|
text-decoration: none;
|
|
color: inherit;
|
|
}
|
|
|
|
.title {
|
|
color: #fff3b7;
|
|
}
|
|
|
|
.v-enter-active, .v-leave-active {
|
|
transition: opacity 0.5s ease;
|
|
}
|
|
|
|
.v-enter-from, .v-leave-to {
|
|
opacity: 0;
|
|
}
|
|
|
|
.rem {
|
|
margin-top: 5px;
|
|
font-size: 0.7em;
|
|
color: #9d9d9d;
|
|
user-select: none;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="app">
|
|
<div class="title">HyDEV Link Shortener</div>
|
|
<Transition @after-leave="input_hidden = true">
|
|
<input id="in" v-model="url" type="url" autocomplete="off" placeholder="url here..."
|
|
@keydown.enter="go" v-if="!sent">
|
|
</Transition>
|
|
<Transition>
|
|
<div v-if="short && input_hidden" :style="error ? {color: '#ff8383'} : {}">
|
|
<div v-if="error">{{short}}</div>
|
|
<a :href="'https://' + short" v-if="!error">{{short}}</a>
|
|
<div class="rem" v-if="!error">( Copied! )</div>
|
|
</div>
|
|
</Transition>
|
|
</div>
|
|
<script>
|
|
url_re = /^https?:\/\/(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/i
|
|
|
|
Vue.createApp({
|
|
data() {
|
|
return {url: '', sent: false, short: '', input_hidden: false, error: false}
|
|
},
|
|
|
|
methods: {
|
|
async go() {
|
|
console.log('🐱')
|
|
|
|
// Check url starts with a protocol
|
|
url = this.url
|
|
if (!/[a-zA-Z]+:\/\/.*/.test(url))
|
|
url = 'https://' + url
|
|
|
|
// Check valid url
|
|
if (!url_re.test(url))
|
|
{
|
|
$('#in').effect('shake')
|
|
return
|
|
}
|
|
|
|
this.sent = true
|
|
|
|
const resp = await fetch('/', {method: 'PUT', body: url})
|
|
const txt = await resp.text()
|
|
this.error = resp.status !== 200
|
|
this.short = this.error ? txt : window.location.origin.replaceAll(/https?:\/\//g, '') + txt
|
|
|
|
// Copy to clipboard
|
|
if (!this.error)
|
|
{
|
|
await navigator.clipboard.writeText(this.short)
|
|
}
|
|
},
|
|
}
|
|
}).mount('#app')
|
|
</script>
|
|
</body>
|
|
</html>
|