improving look and feel

This commit is contained in:
2025-04-14 20:47:26 -04:00
parent 29c358298b
commit 68ed19766d
12 changed files with 695 additions and 42 deletions

88
src/templates/error.html Normal file
View File

@@ -0,0 +1,88 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Error - File Download</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
color: #2d3748;
}
.container {
background: rgba(255, 255, 255, 0.95);
padding: 2.5rem;
border-radius: 1rem;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.05);
width: 90%;
max-width: 450px;
text-align: center;
backdrop-filter: blur(10px);
}
.error-icon {
font-size: 4rem;
color: #e53e3e;
margin-bottom: 1rem;
}
h1 {
color: #2d3748;
font-size: 1.75rem;
margin-bottom: 1rem;
font-weight: 600;
}
.error-message {
color: #4a5568;
margin-bottom: 2rem;
line-height: 1.5;
}
.back-button {
background-color: #4299e1;
color: white;
padding: 0.75rem 1.5rem;
border: none;
border-radius: 0.75rem;
font-size: 1rem;
font-weight: 500;
cursor: pointer;
text-decoration: none;
display: inline-block;
transition: all 0.2s;
}
.back-button:hover {
background-color: #3182ce;
transform: translateY(-1px);
}
.back-button:active {
transform: translateY(0);
}
</style>
</head>
<body>
<div class="container">
<div class="error-icon">⚠️</div>
<h1>{{ error_title }}</h1>
<p class="error-message">{{ error_message }}</p>
<a href="/" class="back-button">Try Another Code</a>
</div>
</body>
</html>

238
src/templates/index.html Normal file
View File

@@ -0,0 +1,238 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Download File</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
color: #2d3748;
}
.container {
background: rgba(255, 255, 255, 0.95);
padding: 2.5rem;
border-radius: 1rem;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.05);
width: 90%;
max-width: 450px;
backdrop-filter: blur(10px);
transition: transform 0.2s;
}
.container:hover {
transform: translateY(-2px);
}
h1 {
color: #2d3748;
font-size: 1.75rem;
margin-bottom: 1.5rem;
text-align: center;
font-weight: 600;
}
.code-input {
display: flex;
gap: 0.5rem;
justify-content: center;
margin-bottom: 1.5rem;
}
.code-input input {
width: 3.5rem;
height: 3.5rem;
font-size: 1.5rem;
text-align: center;
border: 2px solid #e2e8f0;
border-radius: 0.75rem;
background: white;
outline: none;
transition: all 0.2s;
}
.code-input input:focus {
border-color: #4299e1;
box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.15);
}
button {
width: 100%;
background-color: #4299e1;
color: white;
padding: 0.75rem;
border: none;
border-radius: 0.75rem;
font-size: 1rem;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
}
button:hover {
background-color: #3182ce;
transform: translateY(-1px);
}
button:active {
transform: translateY(0);
}
button:disabled {
background-color: #a0aec0;
cursor: not-allowed;
transform: none;
}
.message {
margin-top: 1rem;
padding: 0.75rem;
border-radius: 0.5rem;
text-align: center;
display: none;
}
.message.error {
background-color: #fff5f5;
color: #c53030;
border: 1px solid #feb2b2;
}
.message.success {
background-color: #f0fff4;
color: #2f855a;
border: 1px solid #9ae6b4;
}
.spinner {
display: none;
width: 1.25rem;
height: 1.25rem;
border: 2px solid white;
border-top-color: transparent;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
</style>
<script>
document.addEventListener('DOMContentLoaded', () => {
const form = document.querySelector('form');
const inputs = document.querySelectorAll('.code-input input');
const button = document.querySelector('button');
const spinner = document.querySelector('.spinner');
const message = document.querySelector('.message');
const showMessage = (text, type) => {
message.textContent = text;
message.className = 'message ' + type;
message.style.display = 'block';
setTimeout(() => {
message.style.display = 'none';
}, 5000);
};
inputs.forEach((input, index) => {
input.addEventListener('input', (e) => {
const value = e.target.value.toUpperCase().replace(/[^A-Z0-9]/g, '');
e.target.value = value;
if (value && index < inputs.length - 1) {
inputs[index + 1].focus();
}
const isComplete = Array.from(inputs).every(input => input.value.length === 1);
button.disabled = !isComplete;
});
input.addEventListener('keydown', (e) => {
if (e.key === 'Backspace' && !e.target.value && index > 0) {
inputs[index - 1].focus();
}
});
// Allow pasting the entire code
input.addEventListener('paste', (e) => {
e.preventDefault();
const pastedText = e.clipboardData.getData('text').toUpperCase().replace(/[^A-Z0-9]/g, '');
if (pastedText.length === 6) {
inputs.forEach((input, i) => {
input.value = pastedText[i] || '';
});
button.disabled = false;
}
});
});
form.addEventListener('submit', async (e) => {
e.preventDefault();
const code = Array.from(inputs).map(input => input.value).join('');
if (code.length !== 6) {
showMessage('Please enter a valid 6-character code.', 'error');
return;
}
button.disabled = true;
spinner.style.display = 'block';
button.textContent = 'Downloading...';
try {
window.location.assign(`/download/${code}`);
showMessage('Download started!', 'success');
} catch (error) {
showMessage('Error starting download. Please try again.', 'error');
} finally {
setTimeout(() => {
button.disabled = false;
spinner.style.display = 'none';
button.textContent = 'Download';
}, 2000);
}
});
});
</script>
</head>
<body>
<div class="container">
<h1>Enter Your 6-Digit Code</h1>
<form action="/download" method="GET">
<div class="code-input">
<input type="text" maxlength="1" required pattern="[A-Za-z0-9]" inputmode="text" autocomplete="off">
<input type="text" maxlength="1" required pattern="[A-Za-z0-9]" inputmode="text" autocomplete="off">
<input type="text" maxlength="1" required pattern="[A-Za-z0-9]" inputmode="text" autocomplete="off">
<input type="text" maxlength="1" required pattern="[A-Za-z0-9]" inputmode="text" autocomplete="off">
<input type="text" maxlength="1" required pattern="[A-Za-z0-9]" inputmode="text" autocomplete="off">
<input type="text" maxlength="1" required pattern="[A-Za-z0-9]" inputmode="text" autocomplete="off">
</div>
<button type="submit" disabled>
Download
<div class="spinner"></div>
</button>
<div class="message"></div>
</form>
</div>
</body>
</html>