Initial assets
This commit is contained in:
192
autoindex.css
Normal file
192
autoindex.css
Normal file
@@ -0,0 +1,192 @@
|
||||
/* =========================
|
||||
Nginx AutoIndex Theme
|
||||
========================= */
|
||||
|
||||
:root {
|
||||
--bg: #0f111a;
|
||||
--bg-soft: #151926;
|
||||
--row-hover: #1f2440;
|
||||
--text: #e6e6eb;
|
||||
--muted: #8b93a7;
|
||||
--accent: #7aa2f7;
|
||||
--folder: #9ece6a;
|
||||
--parent: #f7768e;
|
||||
--border: #2a2f4a;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: linear-gradient(135deg, #0f111a, #121626);
|
||||
color: var(--text);
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont,
|
||||
"Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue",
|
||||
Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* Title */
|
||||
h1 {
|
||||
margin: 0;
|
||||
padding: 18px 24px;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
background: var(--bg-soft);
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
/* Listing container */
|
||||
pre {
|
||||
margin: 0;
|
||||
padding: 12px 0 24px;
|
||||
white-space: pre;
|
||||
overflow-x: auto;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* Make links feel like rows */
|
||||
pre a {
|
||||
display: inline-block;
|
||||
padding: 8px 24px 8px 44px;
|
||||
position: relative;
|
||||
|
||||
color: var(--accent);
|
||||
text-decoration: none;
|
||||
|
||||
transition: background 0.15s ease, color 0.15s ease;
|
||||
}
|
||||
|
||||
/* Hover & focus = full-row highlight */
|
||||
pre a:hover,
|
||||
pre a:focus-visible {
|
||||
background: var(--row-hover);
|
||||
color: #ffffff;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Parent directory */
|
||||
pre a[href="../"] {
|
||||
color: var(--parent);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Folders */
|
||||
pre a[href$="/"] {
|
||||
color: var(--folder);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* === Icons (pure CSS, no emoji) === */
|
||||
pre a::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 20px;
|
||||
top: 50%;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
transform: translateY(-50%);
|
||||
border-radius: 2px;
|
||||
background: var(--accent);
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
/* Folder icon */
|
||||
pre a[href$="/"]::before {
|
||||
background: var(--folder);
|
||||
}
|
||||
|
||||
/* Parent directory icon */
|
||||
pre a[href="../"]::before {
|
||||
background: var(--parent);
|
||||
}
|
||||
|
||||
/* Footer note */
|
||||
pre::after {
|
||||
content: "— nginx autoindex —";
|
||||
display: block;
|
||||
margin: 24px 24px 0;
|
||||
color: var(--muted);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Scrollbar (WebKit only, safe) */
|
||||
pre::-webkit-scrollbar {
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
pre::-webkit-scrollbar-thumb {
|
||||
background: var(--border);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* Mobile improvements */
|
||||
@media (max-width: 600px) {
|
||||
h1 {
|
||||
font-size: 16px;
|
||||
padding: 14px 16px;
|
||||
}
|
||||
|
||||
pre a {
|
||||
padding: 10px 16px 10px 40px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
pre a::before {
|
||||
left: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== Header actions ===== */
|
||||
|
||||
h1 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
/* Button container */
|
||||
.autoindex-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
.ai-btn {
|
||||
appearance: none;
|
||||
border: 1px solid var(--border);
|
||||
background: transparent;
|
||||
color: var(--text);
|
||||
font-size: 12px;
|
||||
padding: 6px 10px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
line-height: 1;
|
||||
|
||||
transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
|
||||
}
|
||||
|
||||
/* Hover */
|
||||
.ai-btn:hover {
|
||||
background: var(--row-hover);
|
||||
border-color: var(--accent);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Active */
|
||||
.ai-btn:active {
|
||||
transform: translateY(1px);
|
||||
}
|
||||
|
||||
/* Mobile */
|
||||
@media (max-width: 600px) {
|
||||
.ai-btn {
|
||||
padding: 6px 8px;
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
141
autoindex.js
Normal file
141
autoindex.js
Normal file
@@ -0,0 +1,141 @@
|
||||
|
||||
/**
|
||||
* Check if a URL points to a file by extension
|
||||
*/
|
||||
function isFileLink(url) {
|
||||
const fileExtensions = [
|
||||
'pdf','zip','rar','7z',
|
||||
'mp3','mp4','mkv','avi',
|
||||
'jpg','jpeg','png','gif','webp',
|
||||
'doc','docx','xls','xlsx','ppt','pptx',
|
||||
'csv','txt','json'
|
||||
];
|
||||
|
||||
const cleanUrl = url.split('?')[0].toLowerCase();
|
||||
return fileExtensions.some(ext => cleanUrl.endsWith('.' + ext));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all file links from the page
|
||||
*/
|
||||
function getFileLinks() {
|
||||
const links = document.querySelectorAll('a');
|
||||
const result = [];
|
||||
|
||||
links.forEach(a => {
|
||||
if (!a.href) return;
|
||||
if (!isFileLink(a.href)) return;
|
||||
|
||||
result.push({
|
||||
text: a.innerText.trim(),
|
||||
href: a.href
|
||||
});
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string to kebab-case.
|
||||
*/
|
||||
function toKebabCase(str) {
|
||||
return str
|
||||
.toLowerCase()
|
||||
.trim()
|
||||
.replace(/['’]/g, '')
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.replace(/^-+|-+$/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the last directory or file name from the current page URL
|
||||
*/
|
||||
function getDirectoryName() {
|
||||
const url = new URL(window.location.href);
|
||||
const lastPart = url.pathname
|
||||
.split('/')
|
||||
.filter(Boolean)
|
||||
.pop() || 'file-links';
|
||||
|
||||
return decodeURIComponent(lastPart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download file links as Playlist
|
||||
*/
|
||||
function downloadPlaylist() {
|
||||
const files = getFileLinks();
|
||||
let content = 'DAUMPLAYLIST\n';
|
||||
|
||||
files.forEach((item, index) => {
|
||||
const text = item.text.replace(/"/g, '""');
|
||||
const href = item.href.replace(/"/g, '""');
|
||||
content += `${index+1}*file*${href}\n`;
|
||||
});
|
||||
|
||||
const blob = new Blob([content], { type: 'application/octet-stream;charset=utf-8;' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = toKebabCase(getDirectoryName()) + '.dpl';
|
||||
a.style.display = 'none';
|
||||
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy file links (one per line)
|
||||
*/
|
||||
function copyAllLinks() {
|
||||
const files = getFileLinks();
|
||||
const textToCopy = files.map(f => f.href).join('\n');
|
||||
|
||||
// Modern browsers
|
||||
if (navigator.clipboard && window.isSecureContext) {
|
||||
navigator.clipboard.writeText(textToCopy);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback (older browsers, some mobiles)
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.value = textToCopy;
|
||||
textarea.style.position = 'fixed';
|
||||
textarea.style.opacity = '0';
|
||||
|
||||
document.body.appendChild(textarea);
|
||||
textarea.focus();
|
||||
textarea.select();
|
||||
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(textarea);
|
||||
}
|
||||
|
||||
(function () {
|
||||
const header = document.querySelector('h1');
|
||||
if (!header) return;
|
||||
|
||||
// Wrapper for buttons
|
||||
const actions = document.createElement('div');
|
||||
actions.className = 'autoindex-actions';
|
||||
|
||||
// Playlist button
|
||||
const plb = document.createElement('button');
|
||||
plb.className = 'ai-btn';
|
||||
plb.textContent = 'Download Playlist';
|
||||
plb.onclick = downloadPlaylist;
|
||||
|
||||
// Copy Links button
|
||||
const clb = document.createElement('button');
|
||||
clb.className = 'ai-btn';
|
||||
clb.textContent = 'Copy Links';
|
||||
clb.onclick = copyAllLinks;
|
||||
|
||||
actions.appendChild(clb);
|
||||
actions.appendChild(plb);
|
||||
header.appendChild(actions);
|
||||
})();
|
||||
BIN
favicon.ico
Normal file
BIN
favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 50 KiB |
BIN
favicon.png
Normal file
BIN
favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
41
nais.conf
Normal file
41
nais.conf
Normal file
@@ -0,0 +1,41 @@
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name <<server_name>>;
|
||||
|
||||
# SSL certificates
|
||||
ssl_certificate <<certificates_path>>/fullchain.pem;
|
||||
ssl_certificate_key <<certificates_path>>/privkey.pem;
|
||||
|
||||
# Default root
|
||||
root <<root_path>>;
|
||||
|
||||
# Autoindex for the main folder
|
||||
location / {
|
||||
autoindex on;
|
||||
autoindex_exact_size off; # optional: show human-readable sizes
|
||||
autoindex_localtime on; # optional: show local time
|
||||
|
||||
# Add custom CSS & JS to autoindex pages
|
||||
sub_filter '</head>' '<link rel="stylesheet" href="/autoindex.css">';
|
||||
sub_filter '</body>' '<script src="/autoindex.js"></script></body>';
|
||||
sub_filter_once on;
|
||||
}
|
||||
|
||||
# Serve the assets from a separate folder
|
||||
location = /autoindex.css {
|
||||
root <<assets_path>>;
|
||||
}
|
||||
location = /autoindex.js {
|
||||
root <<assets_path>>;
|
||||
}
|
||||
location = /favicon.ico {
|
||||
root <<assets_path>>;
|
||||
}
|
||||
}
|
||||
server {
|
||||
listen 80;
|
||||
server_name <<server_name>>;
|
||||
|
||||
return 301 https://<<server_name>>$request_uri;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user