commit b46270264b322efd00f96bb471ed445da9170d83 Author: condor Date: Fri Jul 24 19:05:07 2026 +0800 init diff --git a/.workbuddy/memory/2026-07-17.md b/.workbuddy/memory/2026-07-17.md new file mode 100644 index 0000000..690915c --- /dev/null +++ b/.workbuddy/memory/2026-07-17.md @@ -0,0 +1,13 @@ +## 2026-07-17 工作记录 + +- 修复搜索结果表格显示异常: + - 问题:搜索只显示文件名(如 SimHei.ttf),缺少 Size、Last modified 列,且点击后 404。 + - 根因:`render()` 直接把抓取到的 `tr.outerHTML` 拼进新表格,浏览器解析时 `` 不能作为 `
` 子元素,导致 `div.firstChild` 是文本节点,`href` 未正确替换,最终只渲染出孤立文件名。 + - 修复:在 `theme/header.html` 和 `theme-preview.html` 的 `crawl()` 中改为提取结构化数据 `{ name, full, isDir, size, date }`,`render()` 手动生成完整 4 列表格行,并用 `escapeHtml()` 处理输出;链接统一用绝对路径 `full`,兼容 href 已以 `/` 开头的情况。 +- 修复搜索结果中目录名双斜杠:原 `render()` 对目录无条件追加 `/`,而 fancyindex 的链接文本本身已带 `/`,导致 `client-v1.3.7//`。改为仅在 `e.name` 不以 `/` 结尾时才追加 `/`。同步更新 `theme/header.html` 与 `theme-preview.html`。 +- 说明:Directory 面包屑显示的是当前页面 URL 路径,搜索时 URL 不变,所以面包屑保持当前目录路径是正确行为;点击搜索结果进入子目录后才会更新。 +- 新增「返回根目录」按钮:位于搜索框右侧,`.search-form` 改为 flex 布局,`.home-btn`(accent 色胶囊按钮 + home 图标 + 文字),href="/";窄屏 (<=480px) 只显示图标。改动在 `theme/header.html`、`theme-preview.html`、`theme/css/styles.css`。 +- 新增「返回上一级目录」按钮:位于搜索框左侧,`initUpBtn()` 用 JS 根据 `location.pathname` 计算父目录并写入 `href`(如 /a/b/ -> /a/)。`.up-btn` 用 outline 风格(透明底 + border)与根目录实心按钮区分;窄屏只显示图标。改动同上三文件。 +- 修复「上一级」按钮不显示:`initUpBtn()` 原在 `file://` 预览或站点根目录时 `display:none`,导致预览和根目录页看不到按钮。改为始终显示:预览时 `href="#"` 仅展示;http(s) 下根目录 `href="/"`、子目录指向上级 `path.slice(0, idx+1)`。 +- 关键部署修正:`theme/header.html` 第 1 行的 CSS 链接原本指向远程 `https://repo.52or.com/fancyindex/styles.css`,导致本地 `theme/css/styles.css` 的样式(含 `.up-btn`/`.home-btn`)在服务器上不生效。已改为 `/theme/css/styles.css`,与 `fancyindex.conf` 的 `/theme/...` 约定一致,主题自包含。 +- 修复按钮被旧 CSS 缓存导致换行:截图显示「上一级」与「根目录」垂直堆叠、且输入框未同行,说明浏览器仍在用旧的(或未同步的)CSS,`.search-form {display:flex}` 未生效。给 CSS 链接加 `?v=3` 缓存戳,并在 `
` 上内联 `style="display:flex;justify-content:center;align-items:center;gap:10px;"` 作为兜底。同步更新 `theme/header.html` 与 `theme-preview.html`。 diff --git a/.workbuddy/memory/2026-07-18.md b/.workbuddy/memory/2026-07-18.md new file mode 100644 index 0000000..e7b7887 --- /dev/null +++ b/.workbuddy/memory/2026-07-18.md @@ -0,0 +1,18 @@ +# 2026-07-18 工作日志 + +## 1. 诊断:部分 .zip 文件不显示 +- 现象:`Nginx-Fancyindex-Theme.zip` 不显示,`ServerStack.zip` 正常显示。 +- 根因:`fancyindex.conf` 第 8 行 `fancyindex_ignore "theme";` 本意是隐藏 `/theme/` 资源目录, + 但 `fancyindex_ignore` 在 PCRE 下是**不区分大小写 + 未锚定的子串正则**(`ngx_http_fancyindex_module.c` + 用 `NGX_REGEX_CASELESS` 编译,且按裸文件名匹配、无 `^$` 锚点),因此也命中了文件名含 `Theme` 的 zip。 +- 建议修复(尚未改动配置):改为 `fancyindex_ignore "^theme$";` 精确匹配目录名,避免误伤含 theme 的文件。 + +## 2. 修改:列标题改为 File Name / File Size / Date +- nginx 的 `ngx-fancyindex` 模块自行生成 `table#list` 的 ``,主题无法用静态 HTML 改表头文字; + 且 `styles.css` 的 `thead th { text-transform: uppercase }` 会把标题强制大写。 +- 方案:在 `theme/header.html` 的 IIFE 中新增 `renameHeaders()`,于 `onReady()` 调用, + 用 JS 改写 `table#list` 与 `table.results` 的 `` 文本为 + `['File Name','File Size','Date','']`,并通过内联 `th.style.textTransform='none'` 覆盖大写(内联优先级高于外部 CDN 样式,无需改 CSS 文件)。 +- 同步更新 `theme-preview.html` 的静态 thead 与脚本,保持预览一致。 +- 注:`header.html:1` 仍引用外部 `https://repo.52or.com/fancyindex/styles.css?v=3`,本地 `theme/css/styles.css` 不一定线上生效;JS 内联方案不受此影响。 +- **回退**:用户要求"回退到上一个版本",已将 `theme/header.html` 与 `theme-preview.html` 中本次的列标题改动全部撤销,恢复为 `Name / Size / Last modified`。主题文件当前回到改动前状态。 diff --git a/.workbuddy/memory/MEMORY.md b/.workbuddy/memory/MEMORY.md new file mode 100644 index 0000000..4edea62 --- /dev/null +++ b/.workbuddy/memory/MEMORY.md @@ -0,0 +1,10 @@ +# 项目长期记忆:Nginx-Fancyindex-Theme + +## 部署约定 +- 主题资源放在 nginx `root` 下的 `theme/`:`/theme/header.html`、`/theme/footer.html`、`/theme/css/styles.css`。 +- 依赖第三方 `ngx-fancyindex` 模块;未编译则 `fancyindex` 指令报错。 +- `fancyindex_ignore "theme"` 仅隐藏列表显示,不阻止对 `/theme/...` 的直接访问。 + +## 已知坑 +- 搜索结果显示需手动构建表格行:不可依赖抓取到的 `tr.outerHTML` 直接插入新表格,否则会出现列缺失、链接错误、只显示文件名等问题。应提取 `{ name, full, isDir, size, date }` 结构化数据后重新渲染 4 列表格(Name / Size / Last modified / 空)。 +- `header.html` 中 CSS 链接、目录路径清理、搜索递归均用前端 JS 实现,修改后刷新页面即可生效,无需 reload nginx。 diff --git a/HEADER.md b/HEADER.md new file mode 100644 index 0000000..eb8ef7e --- /dev/null +++ b/HEADER.md @@ -0,0 +1,5 @@ +# Nginx-Fancyindex-Theme +A responsive theme for Nginx Fancyindex module. Minimal, modern and simple. +Comes with a search form, aims to handle thousands of files without any problems. + +The fancyindex module can be found [here](https://github.com/aperezdc/ngx-fancyindex). diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..cb2afb5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) +Copyright © 2016 Lilian Besson (Naereen), https://github.com/naereen/ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/fancyindex.conf b/fancyindex.conf new file mode 100644 index 0000000..44c71e0 --- /dev/null +++ b/fancyindex.conf @@ -0,0 +1,9 @@ +fancyindex on; +fancyindex_localtime on; +fancyindex_time_format "%Y-%m-%d %H:%M"; +fancyindex_exact_size off; +fancyindex_header "/theme/header.html"; +fancyindex_footer "/theme/footer.html"; +fancyindex_ignore "examplefile.html"; # Ignored files will not show up in the directory listing, but will still be public. +fancyindex_ignore "^theme$"; # Making sure folder where files are don't show up in the listing. +fancyindex_name_length 255; # Maximum file name length in bytes, change as you like. diff --git a/theme-preview.html b/theme-preview.html new file mode 100644 index 0000000..dd90c04 --- /dev/null +++ b/theme-preview.html @@ -0,0 +1,246 @@ + + + + + + Nginx-Fancyindex-Theme · 预览 + + + + +
+ +

+ Directory + +

+ + + + + + + + + + + + +
NameSizeLast modified
../---
ubuntu-24.04.iso5.1 GiB2026-01-12 09:24
docs/-2026-03-04 18:02
backup.tar.gz842 MiB2026-05-21 22:47
README.md3.3 KiB2026-06-30 11:15
scripts/-2026-07-01 07:53
+ +
+ + diff --git a/theme/css/styles.css b/theme/css/styles.css new file mode 100644 index 0000000..551025d --- /dev/null +++ b/theme/css/styles.css @@ -0,0 +1,348 @@ +/* ============================================================ + Nginx-Fancyindex-Theme — modernized stylesheet + - System font stack (no external font dependency → works offline) + - CSS variables for light / dark mode + - Card-style listing, refined search box, smooth hover states + ============================================================ */ + +:root { + --bg: #f6f7f9; + --surface: #ffffff; + --text: #2b2f36; + --text-muted: #8a929e; + --border: #e8ebf0; + --accent: #3b82f6; + --accent-strong: #2563eb; + --row-hover: #f1f5fb; + --row-stripe: #eef2f8; + --shadow: 0 1px 2px rgba(16, 24, 40, .06), 0 10px 30px rgba(16, 24, 40, .05); + --radius: 14px; +} + +@media (prefers-color-scheme: dark) { + :root { + --bg: #0f1115; + --surface: #171a21; + --text: #e6e9ef; + --text-muted: #8b93a3; + --border: #262b34; + --accent: #60a5fa; + --accent-strong: #93c5fd; + --row-hover: #1d212a; + --row-stripe: #1c212b; + --shadow: 0 1px 2px rgba(0, 0, 0, .5), 0 10px 30px rgba(0, 0, 0, .35); + } +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +html { + font-size: 16px; + color: var(--text); + line-height: 1.6; + background: var(--bg); + -webkit-font-smoothing: antialiased; + font-family: 'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', + Roboto, 'Helvetica Neue', Arial, 'PingFang SC', 'Microsoft YaHei', sans-serif; +} + +body { + padding: 40px 16px 56px; + background: var(--bg); +} + +a { + color: var(--accent-strong); + text-decoration: none; + transition: color .2s ease; +} + +a:hover { + color: var(--accent); + text-decoration: underline; +} + +/* ---------- Layout ---------- */ +.wrapper { + max-width: 880px; + margin: 0 auto; +} + +.site-header { + text-align: center; + margin-bottom: 6px; +} + +/* ---------- Directory breadcrumb (same line) ---------- */ +.dir-title { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: .5rem; + margin: 24px 6px 14px; + padding: 10px 14px; + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius); + box-shadow: var(--shadow); + font-size: .95rem; +} + +.dir-label { + font-size: .68rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: .09em; + color: var(--text-muted); +} + +.breadcrumb { + display: flex; + flex-wrap: wrap; + align-items: center; + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; + font-size: .9rem; + line-height: 1.4; + word-break: break-all; +} + +.breadcrumb a { + color: var(--accent-strong); +} + +.breadcrumb a:hover { + color: var(--accent); + text-decoration: underline; +} + +.breadcrumb .sep { + color: var(--text-muted); + user-select: none; + white-space: pre; +} + +/* ---------- Search ---------- */ +.search-form { + display: flex; + align-items: center; + justify-content: center; + gap: 10px; + margin: 16px 0 4px; +} + +input[type="search"] { + display: block; + width: min(380px, 100%); + margin: 0; + padding: 11px 18px; + font-size: 14px; + color: var(--text); + background: var(--surface); + border: 1px solid var(--border); + border-radius: 999px; + outline: none; + box-shadow: var(--shadow); + transition: border-color .2s ease, box-shadow .2s ease; +} + +input[type="search"]::placeholder { + color: var(--text-muted); +} + +input[type="search"]:focus { + border-color: var(--accent); + box-shadow: 0 0 0 4px rgba(59, 130, 246, .18); +} + +input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} + +/* 返回根目录按钮 */ +.home-btn { + display: inline-flex; + align-items: center; + gap: 6px; + flex: none; + padding: 10px 16px; + font-size: 13px; + font-weight: 600; + color: #fff; + background: var(--accent); + border: 1px solid transparent; + border-radius: 999px; + box-shadow: var(--shadow); + white-space: nowrap; + transition: background .2s ease, transform .1s ease; +} + +.home-btn:hover { + color: #fff; + background: var(--accent-strong); + text-decoration: none; +} + +.home-btn:active { + transform: translateY(1px); +} + +.home-btn svg { + display: block; +} + +/* 返回上一级目录按钮(outline 风格,与根目录按钮区分) */ +.up-btn { + display: inline-flex; + align-items: center; + gap: 6px; + flex: none; + padding: 10px 16px; + font-size: 13px; + font-weight: 600; + color: var(--accent); + background: var(--surface); + border: 1px solid var(--border); + border-radius: 999px; + box-shadow: var(--shadow); + white-space: nowrap; + transition: background .2s ease, transform .1s ease, border-color .2s ease; +} + +.up-btn:hover { + color: var(--accent-strong); + border-color: var(--accent); + background: var(--row-hover); + text-decoration: none; +} + +.up-btn:active { + transform: translateY(1px); +} + +.up-btn svg { + display: block; +} + +@media (max-width: 480px) { + .home-btn span { + display: none; /* 窄屏只留图标 */ + } + .home-btn { + padding: 10px 12px; + } + .up-btn span { + display: none; + } + .up-btn { + padding: 10px 12px; + } +} + +/* ---------- Search results (recursive) ---------- */ +#search-results { + margin-top: 4px; +} + +.search-status { + margin: 6px 6px 12px; + font-size: .82rem; + color: var(--text-muted); +} + +table.results { + margin-top: 10px; +} + +/* ---------- Listing table ---------- */ +table { + width: 100%; + border-collapse: collapse; + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius); + overflow: hidden; + box-shadow: var(--shadow); + font-size: .92rem; +} + +thead th { + text-align: left; + font-weight: 600; + font-size: .72rem; + letter-spacing: .06em; + text-transform: uppercase; + color: var(--text-muted); + padding: 14px 16px; + background: color-mix(in srgb, var(--surface) 92%, var(--border)); + border-bottom: 1px solid var(--border); +} + +th + th { width: 22%; } +th + th + th + th { width: 6%; } + +tr { + outline: 0; + border: 0; + transition: background .2s ease; +} + +/* 隔行底色(斑马纹) */ +tbody tr:nth-child(even) td { + background: var(--row-stripe); +} + +tbody tr:hover td { + background: var(--row-hover); +} + +/* Parent directory link: replace nginx's "../" text with a readable label */ +tr.parent a { + color: var(--text-muted); + font-weight: 500; + font-size: 0; /* hide the original "../" text */ +} + +tr.parent a::before { + content: "Parent directory/"; + font-size: 0.92rem; /* restore a readable size */ +} + +tr.parent a:hover { + color: var(--accent-strong); +} + +td { + padding: 11px 16px; + border-bottom: 1px solid var(--border); + vertical-align: middle; + text-align: left; + color: var(--text); +} + +tr:last-child td { + border-bottom: 0; +} + +td a { + display: block; + font-weight: 500; +} + +td:last-child, +th:last-child { + text-align: right; + padding-right: 16px; + color: var(--text-muted); + font-variant-numeric: tabular-nums; +} + +/* ---------- Responsive ---------- */ +@media (max-width: 600px) { + body { padding: 28px 12px 40px; } + table { font-size: .85rem; } + td, thead th { padding: 10px 12px; } +} diff --git a/theme/footer.html b/theme/footer.html new file mode 100644 index 0000000..b6be1b5 --- /dev/null +++ b/theme/footer.html @@ -0,0 +1 @@ +
diff --git a/theme/header.html b/theme/header.html new file mode 100644 index 0000000..7e9efa8 --- /dev/null +++ b/theme/header.html @@ -0,0 +1,231 @@ + +
+ +

+ Directory + +

+