mirror of
https://github.com/go-i2p/go-jump-addr.git
synced 2025-07-13 11:54:45 -04:00
add css, javascript, links
This commit is contained in:
BIN
jumpserver
BIN
jumpserver
Binary file not shown.
114
static/script.js
114
static/script.js
@ -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();
|
||||||
|
}
|
||||||
|
});
|
202
static/style.css
202
static/style.css
@ -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;
|
||||||
|
}
|
Reference in New Issue
Block a user