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