⚡ TECHNO-TODO v1.0: 90s cyberpunk todo app with PostgreSQL
This commit is contained in:
+301
@@ -0,0 +1,301 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>⚡ TECHNO-TODO v1.0</title>
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Share+Tech+Mono&display=swap');
|
||||
|
||||
:root {
|
||||
--neon-green: #00ff41;
|
||||
--neon-pink: #ff00ff;
|
||||
--neon-blue: #00ffff;
|
||||
--neon-yellow: #ffff00;
|
||||
--dark-bg: #0a0a0a;
|
||||
--panel-bg: #111;
|
||||
--border-glow: #00ff41;
|
||||
}
|
||||
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
background: var(--dark-bg);
|
||||
color: var(--neon-green);
|
||||
font-family: 'Share Tech Mono', 'Courier New', monospace;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-image:
|
||||
repeating-linear-gradient(0deg, transparent, transparent 2px, rgba(0,255,65,0.03) 2px, rgba(0,255,65,0.03) 4px),
|
||||
repeating-linear-gradient(90deg, transparent, transparent 2px, rgba(0,255,65,0.02) 2px, rgba(0,255,65,0.02) 4px);
|
||||
}
|
||||
|
||||
/* CRT scanlines */
|
||||
body::before {
|
||||
content: '';
|
||||
position: fixed;
|
||||
top: 0; left: 0; right: 0; bottom: 0;
|
||||
background: repeating-linear-gradient(0deg, rgba(0,0,0,0.15) 0px, rgba(0,0,0,0.15) 1px, transparent 1px, transparent 3px);
|
||||
pointer-events: none;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 90%;
|
||||
max-width: 600px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
border: 2px solid var(--neon-pink);
|
||||
padding: 20px;
|
||||
background: var(--panel-bg);
|
||||
box-shadow: 0 0 20px rgba(255, 0, 255, 0.3), inset 0 0 20px rgba(255, 0, 255, 0.05);
|
||||
animation: borderPulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes borderPulse {
|
||||
0%, 100% { border-color: var(--neon-pink); box-shadow: 0 0 20px rgba(255,0,255,0.3), inset 0 0 20px rgba(255,0,255,0.05); }
|
||||
50% { border-color: var(--neon-blue); box-shadow: 0 0 30px rgba(0,255,255,0.4), inset 0 0 30px rgba(0,255,255,0.08); }
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.2em;
|
||||
color: var(--neon-pink);
|
||||
text-shadow: 0 0 10px var(--neon-pink), 0 0 30px var(--neon-pink), 0 0 50px var(--neon-pink);
|
||||
letter-spacing: 4px;
|
||||
animation: glitch 3s infinite;
|
||||
}
|
||||
|
||||
@keyframes glitch {
|
||||
0%, 100% { transform: translate(0); }
|
||||
2% { transform: translate(-2px, 1px); }
|
||||
4% { transform: translate(2px, -1px); }
|
||||
6% { transform: translate(0); }
|
||||
}
|
||||
|
||||
.header .subtitle {
|
||||
color: var(--neon-green);
|
||||
font-size: 0.9em;
|
||||
margin-top: 5px;
|
||||
text-shadow: 0 0 5px var(--neon-green);
|
||||
}
|
||||
|
||||
.blink { animation: blink 1s steps(1) infinite; }
|
||||
@keyframes blink { 50% { opacity: 0; } }
|
||||
|
||||
/* Add form */
|
||||
.add-form {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.add-form input {
|
||||
flex: 1;
|
||||
background: #000;
|
||||
border: 2px solid var(--neon-green);
|
||||
color: var(--neon-green);
|
||||
padding: 12px 15px;
|
||||
font-family: inherit;
|
||||
font-size: 1em;
|
||||
outline: none;
|
||||
box-shadow: 0 0 10px rgba(0, 255, 65, 0.2);
|
||||
transition: box-shadow 0.3s;
|
||||
}
|
||||
|
||||
.add-form input:focus {
|
||||
box-shadow: 0 0 20px rgba(0, 255, 65, 0.5), 0 0 40px rgba(0, 255, 65, 0.2);
|
||||
}
|
||||
|
||||
.add-form input::placeholder {
|
||||
color: rgba(0, 255, 65, 0.3);
|
||||
}
|
||||
|
||||
.btn {
|
||||
background: #000;
|
||||
border: 2px solid var(--neon-blue);
|
||||
color: var(--neon-blue);
|
||||
padding: 12px 20px;
|
||||
font-family: inherit;
|
||||
font-size: 1em;
|
||||
cursor: pointer;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 2px;
|
||||
text-shadow: 0 0 5px var(--neon-blue);
|
||||
box-shadow: 0 0 10px rgba(0, 255, 255, 0.2);
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: var(--neon-blue);
|
||||
color: #000;
|
||||
box-shadow: 0 0 30px rgba(0, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
padding: 6px 12px;
|
||||
font-size: 0.75em;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.btn-done {
|
||||
border-color: var(--neon-green);
|
||||
color: var(--neon-green);
|
||||
text-shadow: 0 0 5px var(--neon-green);
|
||||
}
|
||||
|
||||
.btn-done:hover {
|
||||
background: var(--neon-green);
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.btn-del {
|
||||
border-color: #ff3333;
|
||||
color: #ff3333;
|
||||
text-shadow: 0 0 5px #ff3333;
|
||||
}
|
||||
|
||||
.btn-del:hover {
|
||||
background: #ff3333;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/* Todo list */
|
||||
.todo-list {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.todo-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 12px 15px;
|
||||
margin-bottom: 8px;
|
||||
background: var(--panel-bg);
|
||||
border: 1px solid rgba(0, 255, 65, 0.2);
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.todo-item:hover {
|
||||
border-color: var(--neon-green);
|
||||
box-shadow: 0 0 15px rgba(0, 255, 65, 0.15);
|
||||
}
|
||||
|
||||
.todo-item.done {
|
||||
opacity: 0.4;
|
||||
border-color: rgba(0, 255, 65, 0.1);
|
||||
}
|
||||
|
||||
.todo-item.done .todo-text {
|
||||
text-decoration: line-through;
|
||||
color: rgba(0, 255, 65, 0.4);
|
||||
}
|
||||
|
||||
.todo-text {
|
||||
flex: 1;
|
||||
font-size: 1em;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.todo-actions {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.empty {
|
||||
text-align: center;
|
||||
padding: 40px;
|
||||
color: rgba(0, 255, 65, 0.3);
|
||||
border: 1px dashed rgba(0, 255, 65, 0.2);
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.count {
|
||||
text-align: right;
|
||||
margin-top: 15px;
|
||||
font-size: 0.8em;
|
||||
color: rgba(0, 255, 65, 0.5);
|
||||
}
|
||||
|
||||
.error-msg {
|
||||
background: rgba(255, 0, 0, 0.1);
|
||||
border: 1px solid #ff3333;
|
||||
color: #ff3333;
|
||||
padding: 10px;
|
||||
margin-bottom: 15px;
|
||||
text-align: center;
|
||||
text-shadow: 0 0 5px #ff3333;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
.footer {
|
||||
text-align: center;
|
||||
margin-top: 30px;
|
||||
padding: 15px;
|
||||
border-top: 1px solid rgba(0, 255, 65, 0.2);
|
||||
color: rgba(0, 255, 65, 0.3);
|
||||
font-size: 0.7em;
|
||||
}
|
||||
|
||||
.footer .dot {
|
||||
color: var(--neon-green);
|
||||
animation: blink 0.5s steps(1) infinite;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>⚡ TECHNO-TODO</h1>
|
||||
<div class="subtitle">// version 1.0-beta :: neon edition<br><span class="blink">█ SYSTEM ACTIVE █</span></div>
|
||||
</div>
|
||||
|
||||
<% if (error) { %>
|
||||
<div class="error-msg">⚠ <%= error %> ⚠</div>
|
||||
<% } %>
|
||||
|
||||
<form class="add-form" action="/add" method="POST">
|
||||
<input type="text" name="text" placeholder="> ENTER NEW TASK..." maxlength="200" required autofocus>
|
||||
<button type="submit" class="btn">ADD</button>
|
||||
</form>
|
||||
|
||||
<% if (todos.length === 0) { %>
|
||||
<div class="empty">// NO TASKS IN MEMORY<br>> READY FOR INPUT_</div>
|
||||
<% } else { %>
|
||||
<ul class="todo-list">
|
||||
<% todos.forEach(todo => { %>
|
||||
<li class="todo-item <%= todo.done ? 'done' : '' %>">
|
||||
<span class="todo-text">
|
||||
<%= todo.done ? '✓' : '▸' %> <%= todo.text %>
|
||||
</span>
|
||||
<span class="todo-actions">
|
||||
<form action="/toggle/<%= todo.id %>" method="POST" style="display:inline">
|
||||
<button class="btn btn-done btn-sm"><%= todo.done ? 'UNDO' : 'DONE' %></button>
|
||||
</form>
|
||||
<form action="/delete/<%= todo.id %>" method="POST" style="display:inline">
|
||||
<button class="btn btn-del btn-sm">DEL</button>
|
||||
</form>
|
||||
</span>
|
||||
</li>
|
||||
<% }) %>
|
||||
</ul>
|
||||
<% } %>
|
||||
|
||||
<div class="count">
|
||||
> TOTAL: <%= todos.length %> | DONE: <%= todos.filter(t => t.done).length %> | PENDING: <%= todos.filter(t => !t.done).length %>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
⚡ TECHNO-TODO v1.0 <span class="dot">█</span> Powered by Dokploy <span class="dot">█</span> PostgreSQL <span class="dot">█</span> Node.js<br>
|
||||
EST. 2026 // THE FUTURE IS NOW
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user