Initial commit. Basic functional page.

This commit is contained in:
DebaucheryLibrarian 2025-02-17 01:05:03 +00:00
commit d514bd2a72
9 changed files with 298 additions and 0 deletions

BIN
apple-touch-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

1
base32.min.js vendored Executable file
View File

@ -0,0 +1 @@
!function(){function t(){var t=0,e=0;this.output="",this.readByte=function(r){return"string"==typeof r&&(r=r.charCodeAt(0)),0>t?e|=r>>-t:e=r<<t&248,t>3?(t-=8,1):(4>t&&(this.output+=i[e>>3],t+=5),0)},this.finish=function(r){var n=this.output+(0>t?i[e>>3]:"")+(r?"$":"");return this.output="",n}}function e(){var t=0,e=0;this.output="",this.readChar=function(r){"string"!=typeof r&&"number"==typeof r&&(r=String.fromCharCode(r)),r=r.toLowerCase();var n=s()[r];"undefined"!=typeof n&&(n<<=3,e|=n>>>t,t+=5,t>=8&&(this.output+=String.fromCharCode(e),t-=8,e=t>0?n<<5-t&255:0))},this.finish=function(e){var r=this.output+(0>t?i[bits>>3]:"")+(e?"$":"");return this.output="",r}}function r(e){var r=new t,n=r.update(e,!0);return n}function n(t){var r=new e,n=r.update(t,!0);return n}function u(t,e){"undefined"==typeof f&&(f=require("crypto"));var n=f.createHash("sha1");if(n.digest=function(t){return function(){return r(t.call(this,"binary"))}}(n.digest),e){if("string"==typeof t||Buffer.isBuffer(t))try{return e(null,u(t))}catch(i){return e(i,null)}return t.on("data",function(t){n.update(t)}),void t.on("end",function(){e(null,n.digest())})}return t?n.update(t).digest():n}var i="0123456789abcdefghjkmnpqrtuvwxyz",o={o:0,i:1,l:1,s:5},s=function(){for(var t={},e=0;e<i.length;e++)t[i[e]]=e;for(var r in o)o.hasOwnProperty(r)&&(t[r]=t[""+o[r]]);return s=function(){return t},t};t.prototype.update=function(t,e){for(var r=0;r<t.length;)r+=this.readByte(t[r]);var n=this.output;return this.output="",e&&(n+=this.finish()),n},e.prototype.update=function(t,e){for(var r=0;r<t.length;r++)this.readChar(t[r]);var n=this.output;return this.output="",e&&(n+=this.finish()),n};var f,a;u.file=function(t,e){return"-"==t?(process.stdin.resume(),u(process.stdin,e)):("undefined"==typeof a&&(a=require("fs")),a.stat(t,function(r,n){return r?e(r,null):n.isDirectory()?e({dir:!0,message:"Is a directory"}):u(require("fs").createReadStream(t),e)}))};var d={Decoder:e,Encoder:t,encode:r,decode:n,sha1:u};"undefined"!=typeof window&&(window.base32=d),"undefined"!=typeof module&&module.exports&&(module.exports=d)}();

BIN
favicon-96x96.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 957 B

BIN
favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

7
favicon.svg Normal file
View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.dev/svgjs" width="16" height="16"><svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path d="M11 4h3.627c-0.078-0.126-0.172-0.266-0.286-0.421-0.347-0.473-0.831-1.027-1.362-1.558s-1.085-1.015-1.558-1.362c-0.155-0.114-0.295-0.208-0.421-0.286v3.627z"></path>
<path d="M7 7h2v2h-2v-2z"></path>
<path d="M10.5 5c-0.276 0-0.5-0.224-0.5-0.5v-4.5h-7.75c-0.689 0-1.25 0.561-1.25 1.25v13.5c0 0.689 0.561 1.25 1.25 1.25h11.5c0.689 0 1.25-0.561 1.25-1.25v-9.75h-4.5zM11 13.5c0 0.275-0.225 0.5-0.5 0.5h-5c-0.275 0-0.5-0.225-0.5-0.5v-4c0-0.275 0.225-0.5 0.5-0.5h0.5v-2.5c0-0.276 0.224-0.5 0.5-0.5h3c0.276 0 0.5 0.224 0.5 0.5v2.5h0.5c0.275 0 0.5 0.225 0.5 0.5v4z"></path>
</svg><style>@media (prefers-color-scheme: light) { :root { filter: none; } }
@media (prefers-color-scheme: dark) { :root { filter: invert(100%); } }
</style></svg>

After

Width:  |  Height:  |  Size: 992 B

269
index.html Normal file
View File

@ -0,0 +1,269 @@
<!doctype html>
<html lang="en">
<head>
<title>Based</title>
<link rel="icon" type="image/png" href="//favicon-96x96.png" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="./favicon.svg" />
<link rel="shortcut icon" href="./favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="./apple-touch-icon.png" />
<link rel="manifest" href="./site.webmanifest" />
<meta name="apple-mobile-web-app-title" content="Based" />
<meta name="viewport" content="width=device-width,height=device-height,initial-scale=.75,maximum-scale=.75,user-scalable=no,interactive-widget=resizes-content">
<style>
:root {
--primary: #0ad;
--shadow: rgba(0, 0, 0, .25);
}
html,
body {
width: 100%;
height: 100%:
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 1.25rem;
font-family: sans-serif;
background: #fafafa;
color: #333;
}
.header {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
margin-bottom: .25rem;
background: #111;
color: #fff;
}
.title {
padding: .5rem 1rem;
margin: 0;
font-size: 1.75rem;
}
.feedback {
width: 100%;
height: 1.5rem;
margin-top: 1rem;
text-align: center;
opacity: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.feedback.hidden {
opacity: 0;
transition: opacity 1s ease-out;
}
.section {
width: 100%;
max-width: 1500px;
display: flex;
flex-direction: column;
justify-content: center;
box-sizing: border-box;
padding: 1rem;
margin-bottom: 1rem;
}
.section-heading {
margin: 0 0 1rem 0;
}
.row {
width: 100%;
display: flex;
align-items: center;
gap: 1rem;
}
.input {
font-size: 1.25rem;
flex-grow: 1;
box-sizing: border-box;
padding: .5rem .75rem;
border: solid 1px var(--shadow);
border-radius: .25rem;
outline: none;
}
.input:focus {
border-color: var(--primary);
box-shadow: 0 0 3px var(--shadow);
}
.arrow-down {
display: none;
}
@media(max-width: 1000px) {
body {
font-size: 1rem;
}
.row {
flex-direction: column;
gap: .5rem;
}
.input {
width: 100%;
font-size: 1rem;
}
.arrow-right{
display: none;
}
.arrow-down {
display: inline-block;
}
}
</style>
<script src="./base32.min.js"></script>
</head>
<body>
<header class="header">
<h1 class="title">Based</h1>
</header>
<span
id="feedback"
class="feedback feedback-copy hidden"
>Copied '<span id="feedbackValue" class="feedback-value"></span>' to clipboard!</span>
<section class="section">
<h2 class="section-heading">Encode</h2>
<div class="row">
<input
id="nameInput"
placeholder="Name"
class="input"
>
<span class="arrow arrow-right">&#x27A1;</span>
<span class="arrow arrow-down"> &#x2B07;</span>
<input
id="codeOutput"
placeholder="Code"
class="input"
readonly
>
</div>
</section>
<section class="section">
<h2 class="section-heading">Decode</h2>
<div class="row">
<input
id="codeInput"
placeholder="Code"
class="input"
>
<span class="arrow arrow-right">&#x27A1;</span>
<span class="arrow arrow-down"> &#x2B07;</span>
<input
id="nameOutput"
placeholder="Name"
class="input"
readonly
>
</div>
</section>
</body>
<script>
const nameInput = document.querySelector('#nameInput');
const codeOutput = document.querySelector('#codeOutput');
const codeInput = document.querySelector('#codeInput');
const nameOutput = document.querySelector('#nameOutput');
const feedback = document.querySelector('#feedback');
const feedbackValue = document.querySelector('#feedbackValue');
function normalize(text) {
return text
.normalize("NFD")
.toLowerCase()
.replace(/\p{Diacritic}/gu, "")
.replace(/[^a-z0-9]/g, ' ')
.replace(/\s+/g, ' ')
.trim();
}
function getCode() {
const normalized = normalize(nameInput.value);
const encoded = base32.encode(normalized).toUpperCase();
codeOutput.value = encoded;
}
function getName() {
const decoded = base32.decode(codeInput.value);
const capitalized = decoded.split(' ').map((word) => `${word.slice(0, 1).toUpperCase()}${word.slice(1)}`).join(' ');
nameOutput.value = capitalized;
}
nameInput.addEventListener('input', () => getCode());
codeInput.addEventListener('input', () => getName());
function selectCopy(event) {
const text = event.target.value;
if (!text) {
return;
}
event.target.select();
navigator.clipboard.writeText(text);
feedbackValue.textContent = text;
feedback.classList.remove('hidden');
setTimeout(() => {
feedback.classList.add('hidden');
}, 1000);
}
codeOutput.addEventListener('focus', selectCopy);
nameOutput.addEventListener('focus', selectCopy);
nameInput.addEventListener('focus', (event) => event.target.select());
codeInput.addEventListener('focus', (event) => event.target.select());
const query = new URL(window.location);
const urlName = query.searchParams.get('name');
const urlCode = query.searchParams.get('code');
if (urlName) {
nameInput.value = urlName;
getCode();
}
if (urlCode) {
codeInput.value = urlCode;
getName();
}
</script>
</html>

21
site.webmanifest Normal file
View File

@ -0,0 +1,21 @@
{
"name": "Based",
"short_name": "Based",
"icons": [
{
"src": "/web-app-manifest-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "/web-app-manifest-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB