add css, javascript, links

This commit is contained in:
eyedeekay
2025-03-17 20:00:40 -04:00
parent e07b0f6645
commit 81d1ffcfa2
3 changed files with 316 additions and 0 deletions

Binary file not shown.

View File

@ -0,0 +1,114 @@
document.addEventListener('DOMContentLoaded', function() {
// Form validation enhancement
const addForm = document.querySelector('form[action="/add"]');
if (addForm) {
initializeAddForm(addForm);
}
// Table sorting
const tables = document.querySelectorAll('table');
tables.forEach(initializeTableSort);
// Search form enhancement
const searchForm = document.querySelector('form[action="/search"]');
if (searchForm) {
initializeSearchForm(searchForm);
}
});
function initializeAddForm(form) {
// Tags input enhancement
const tagsInput = form.querySelector('#tags');
if (tagsInput) {
// Convert comma-separated input into tag spans
tagsInput.addEventListener('blur', function() {
const tags = this.value.split(',').map(t => t.trim()).filter(t => t);
this.value = tags.join(', ');
});
// Basic destination validation
const destInput = form.querySelector('#destination');
destInput.addEventListener('blur', function() {
const val = this.value.trim();
if (val.length < 516) {
this.setCustomValidity('Destination appears too short for a valid I2P address');
} else {
this.setCustomValidity('');
}
});
}
}
function initializeSearchForm(form) {
// Add "clear search" functionality
const queryInput = form.querySelector('#q');
if (queryInput && queryInput.value) {
const clearButton = document.createElement('button');
clearButton.type = 'button';
clearButton.textContent = 'Clear';
clearButton.className = 'clear-search';
clearButton.onclick = () => {
queryInput.value = '';
form.submit();
};
queryInput.parentNode.appendChild(clearButton);
}
}
function initializeTableSort(table) {
const headers = table.querySelectorAll('th');
headers.forEach((header, index) => {
if (!header.classList.contains('no-sort')) {
header.style.cursor = 'pointer';
header.addEventListener('click', () => sortTable(table, index));
header.title = 'Click to sort';
}
});
}
function sortTable(table, column) {
const tbody = table.querySelector('tbody');
const rows = Array.from(tbody.querySelectorAll('tr'));
const isAsc = table.querySelector('th').classList.contains('sort-asc');
// Sort the rows
rows.sort((a, b) => {
let aVal = a.cells[column].textContent.trim();
let bVal = b.cells[column].textContent.trim();
// Handle date sorting
if (isValidDate(aVal) && isValidDate(bVal)) {
return compareStandardDates(aVal, bVal);
}
// Default string comparison
return isAsc ? bVal.localeCompare(aVal) : aVal.localeCompare(bVal);
});
// Update sort indicators
table.querySelectorAll('th').forEach(th => {
th.classList.remove('sort-asc', 'sort-desc');
});
table.querySelector(`th:nth-child(${column + 1})`).classList.add(
isAsc ? 'sort-desc' : 'sort-asc'
);
// Rebuild the table body
rows.forEach(row => tbody.appendChild(row));
}
function isValidDate(dateStr) {
const date = new Date(dateStr);
return date instanceof Date && !isNaN(date);
}
function compareStandardDates(a, b) {
return new Date(a) - new Date(b);
}
// Optional: Add keyboard navigation for accessibility
document.addEventListener('keydown', function(e) {
if (e.key === 'Enter' && e.target.tagName === 'TH') {
e.target.click();
}
});

View File

@ -0,0 +1,202 @@
/* Base styles */
:root {
--primary-color: #00ff41;
--secondary-color: #0a0a0a;
--accent-color: #ff00ff;
--text-color: #e0e0e0;
--link-color: #00ff41;
--border-color: #2a2a2a;
--input-bg: #1a1a1a;
}
body {
background-color: var(--secondary-color);
color: var(--text-color);
font-family: 'Courier New', monospace;
line-height: 1.6;
margin: 0;
padding: 20px;
min-height: 100vh;
}
header {
border-bottom: 2px solid var(--primary-color);
margin-bottom: 2rem;
padding-bottom: 1rem;
}
h1, h2 {
color: var(--primary-color);
text-transform: uppercase;
letter-spacing: 2px;
}
/* Navigation */
#index-links {
margin: 1rem 0;
padding: 1rem 0;
border-bottom: 1px solid var(--border-color);
}
#index-links a {
margin-right: 1.5rem;
padding: 0.5rem 1rem;
border: 1px solid var(--primary-color);
text-decoration: none;
color: var(--primary-color);
transition: all 0.3s ease;
}
#index-links a:hover {
background-color: var(--primary-color);
color: var(--secondary-color);
box-shadow: 0 0 10px var(--primary-color);
}
/* Tables */
table {
width: 100%;
border-collapse: collapse;
margin: 1rem 0;
background: rgba(10, 10, 10, 0.8);
}
th, td {
padding: 0.8rem;
text-align: left;
border: 1px solid var(--border-color);
}
th {
background-color: var(--border-color);
color: var(--primary-color);
text-transform: uppercase;
}
tr:hover {
background-color: rgba(0, 255, 65, 0.1);
}
/* Forms */
form {
max-width: 800px;
margin: 0 auto;
}
.form-group {
margin-bottom: 1.5rem;
}
label {
display: block;
margin-bottom: 0.5rem;
color: var(--primary-color);
}
input, select, textarea {
width: 100%;
padding: 0.8rem;
background-color: var(--input-bg);
border: 1px solid var(--border-color);
color: var(--text-color);
font-family: 'Courier New', monospace;
}
input:focus, select:focus, textarea:focus {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 5px var(--primary-color);
}
button {
background-color: transparent;
color: var(--primary-color);
border: 2px solid var(--primary-color);
padding: 0.8rem 2rem;
cursor: pointer;
text-transform: uppercase;
letter-spacing: 2px;
transition: all 0.3s ease;
}
button:hover {
background-color: var(--primary-color);
color: var(--secondary-color);
box-shadow: 0 0 15px var(--primary-color);
}
/* Tags */
.tag {
display: inline-block;
padding: 0.2rem 0.5rem;
margin: 0.2rem;
background-color: var(--border-color);
border: 1px solid var(--primary-color);
border-radius: 3px;
font-size: 0.9rem;
}
/* Search Results */
#search-results {
margin-top: 2rem;
}
/* Rules Section */
#rules {
margin: 2rem 0;
padding: 1rem;
border: 1px solid var(--border-color);
background-color: rgba(10, 10, 10, 0.8);
}
#rules ul {
list-style-type: none;
padding-left: 0;
}
#rules li {
margin-bottom: 0.5rem;
padding-left: 1.5rem;
position: relative;
}
#rules li:before {
content: ">";
position: absolute;
left: 0;
color: var(--primary-color);
}
/* Responsive Design */
@media (max-width: 768px) {
body {
padding: 10px;
}
table {
display: block;
overflow-x: auto;
}
#index-links a {
display: block;
margin-bottom: 0.5rem;
text-align: center;
}
}
th.sort-asc::after {
content: " ▲";
color: var(--primary-color);
}
th.sort-desc::after {
content: " ▼";
color: var(--primary-color);
}
.clear-search {
margin-left: 0.5rem;
padding: 0.3rem 0.6rem;
font-size: 0.8rem;
}