惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LangChain Blog
V
V2EX
爱范儿
爱范儿
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Martin Fowler
Martin Fowler
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Apple Machine Learning Research
Apple Machine Learning Research
WordPress大学
WordPress大学
有赞技术团队
有赞技术团队
宝玉的分享
宝玉的分享
Last Week in AI
Last Week in AI
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
罗磊的独立博客
小众软件
小众软件
Vercel News
Vercel News
博客园 - 司徒正美
阮一峰的网络日志
阮一峰的网络日志
V
Visual Studio Blog
J
Java Code Geeks
P
Proofpoint News Feed
MongoDB | Blog
MongoDB | Blog
B
Blog
美团技术团队
量子位

博客园_首页

Linux实操--组管理、权限管理和定时任务 Java + EasyExcel 实现单个接口导出多个Excel Mem0 源码解析系列(二):提示词工程的深度剖析 Openclaw TaskFlow究竟是什么?和普通Skill技能有什么区别 博文阅读密码验证 - 博客园 嘉立创开源:应该是全网MicroPython教程最多的开发板 Hermes Agent 集成实践:从协议到生产 2026年AI编程工具横评:Cursor、Codex、Claude Code、Zed、Windsurf Java程序员必看的RAG入门教程 2026 AI效率神器:Superpowers + Claude Code 保姆级教程 本地大模型部署全攻略:从 0 到 1 玩转 Ollama 【从0到1构建一个ClaudeAgent】内存管理-上下文压缩 .NET 高级开发 | 设计、实现一个事件总线框架 电子小白入门之NE555 3. WorkBuddy:隐藏玩法,一键召唤专家,让 AI 以"专家身份"给你干活 和AI一起搞事情#3:Claude Teammate 游戏开发翻车实录 【OpenClaw】通过 Nanobot 源码学习架构---(7)Memory C# .NET 周刊|2026年3月3期 我在 Debian 11 上把 K8s 单机搭起来了,过程没你想的那么顺(/opt 目录版) 深度学习进阶(七)Data-efficient Image Transformer CLI+Skill搭建浏览器AI自动化框架,告别一切重复枯燥任务 告别Token账单无底洞:OpenClaw本地部署,重塑企业数据主权的唯一解 FastAPI+Vue:文件分片上传+秒传+断点续传,这坑我帮你踩平了! SBTI 爆火后,我做了个程序员版的 CBTI。。已开源 + 附开发过程 多模态检索开始进入工程期:用 Sentence Transformers 搭建可落地的 Multimodal RAG 100多行代码实现一个最简单的Agent(用ReAct) Claude Code 通关手册(八):推荐 5 个 Hooks,代码质量提升 3 倍 老板:“有人截图了!”。安全部门:“收到,马上查暗水印!” - why技术 技术之外,皆是人间 C#/.NET/.NET Core技术前沿周刊 | 第 69 期(2026年4.01-4.12)
拿 DeepSeek 的免费对话搓了个 Everything 的静态 WebUI
树欲静·而风不止 · 2026-05-04 · via 博客园_首页

过节有点时间捣鼓 Everything 的 HTTP 共享,发现对于自己家里用 Win10 NAS 来说,无论是按目录浏览还是快速查找,直接用 Evertything 的 Web 端都太顺手了。唯一不太满意的,就是这个自带的 WebUI 是为桌面浏览器设计的,在手机上用起来就不太舒服了。在网上找了一圈没找到现成的插件定制 UI,于是我突发奇想,索性就在 DeepSeek 免费的 Web Chat 里让它搓了一个 SearchUI.html 出来。
这个手搓的过程完全是在浏览器里通过:对话提出要求 ->复制代码到文件->测试->对话提出改进要求 的方式完成的,我刻意没用平常习惯的 vscode + kilocode,就想比较一下有什么区别。

1. 每次测试修改,AI 都会重新生成完整的 html, 因为不是只修改部分代码,所以输出的速度显然比调用 API 要慢不少
2. 有一次改崩了目录显示的逻辑,然后我无论怎么提示都恢复不回去,最后只能把旧的版本文件拖给它,让在这个基础上修改才算翻过这个坎儿
3. 每次 AI 都会信誓旦旦地保证代码一定能正常工作,我开始还将信将疑,后面就完全无视了
4. 我本来是打算全程一点代码都不写的,但是现实是我发现有些关键点,我手动修改一下,远比跟 AI 啰嗦半天效率要高得多。吐糟给 AI 吧,得到的回复居然说这才是人机合作开发的最高境界?! 

最终结果,花了半天时间,经历了大概四十多轮对话,终于完美实现了我所需要的,适应手机的UI效果,挂到 Everything 的 HTTP 服务下面(不是替代默认页面),完美。

这是 Everything 自带的 HTTP 页面

图片

 这是我定制的页面

图片

这个静态页面本质上就是通过 JS 解析 Eveything 的 HTML,技术说穿了就不值钱,分享出来供有需要的网友参考。 

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
    <title>Everything</title>
    <style>
        * {
            box-sizing: border-box;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
            background: #f5f5f5;
            margin: 0;
            padding: 16px;
        }

        .container {
            max-width: 700px;
            margin: 0 auto;
        }

        .search-box {
            width: 100%;
            padding: 14px 16px;
            font-size: 16px;
            border: 1px solid #ddd;
            border-radius: 12px;
            outline: none;
            background: white;
            margin-bottom: 12px;
        }

        .search-box:focus {
            border-color: #007aff;
        }

        .drive-bar {
            display: flex;
            flex-wrap: wrap;
            gap: 8px;
            margin: 12px 0;
        }

        .drive-btn {
            background: #e5e5ea;
            color: #1c1c1e;
            border: none;
            padding: 8px 20px;
            border-radius: 25px;
            font-size: 14px;
            font-weight: 400;
            cursor: pointer;
        }

        .drive-btn:active {
            background: #c6c6c8;
        }

        .drive-btn.active {
            background: #007aff;
            color: white;
        }

        .breadcrumb {
            background: white;
            padding: 10px 14px;
            border-radius: 12px;
            margin-bottom: 12px;
            font-size: 13px;
            word-break: break-all;
            white-space: nowrap;
            overflow-x: auto;
            -webkit-overflow-scrolling: touch;
        }

        .breadcrumb span {
            color: #007aff;
            cursor: pointer;
        }

        .separator {
            margin: 0 4px;
            color: #888;
        }

        .results {
            list-style: none;
            padding: 0;
            margin: 16px 0 0 0;
        }

        .file-item {
            background: white;
            border-radius: 12px;
            margin-bottom: 8px;
            cursor: pointer;
        }

        .file-item:active {
            background: #e5e5ea;
        }

        .file-link {
            display: flex;
            align-items: center;
            gap: 12px;
            text-decoration: none;
            color: inherit;
            padding: 12px;
            width: 100%;
        }

        .file-icon,
        .folder-icon {
            font-size: 28px;
            flex-shrink: 0;
        }

        .file-info {
            flex: 1;
            min-width: 0;
        }

        .file-name,
        .folder-name {
            font-weight: 500;
            font-size: 15px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .file-name {
            color: #007aff;
        }

        .folder-name {
            color: #ff9500;
        }

        .file-meta {
            font-size: 12px;
            color: #888;
            margin-top: 4px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .folder-item {
            display: flex;
            align-items: center;
            gap: 12px;
            padding: 12px;
            width: 100%;
        }

        .status {
            padding: 20px;
            text-align: center;
            color: #888;
            background: white;
            border-radius: 12px;
        }

        .stats {
            font-size: 13px;
            color: #888;
            margin-top: 12px;
        }
    </style>
</head>

<body>
    <div class="container">
        <h1>Everything v1.4.1.1032</h1>
        <input type="text" id="searchInput" class="search-box" placeholder="输入文件名搜索..." autofocus>
        <div class="drive-bar" id="driveBar"></div>
        <div id="breadcrumb" class="breadcrumb" style="display:none;"></div>
        <div id="resultsContainer"></div>
    </div>

    <script>
        const searchInput = document.getElementById('searchInput');
        const resultsContainer = document.getElementById('resultsContainer');
        const breadcrumbDiv = document.getElementById('breadcrumb');
        const driveBar = document.getElementById('driveBar');

        let currentPath = '';
        let searchDebounceTimer = null;
        let driveList = [];

        // 从 Everything 默认页面获取磁盘列表
        async function fetchDriveList() {
            try {
                const response = await fetch(`/`);
                const html = await response.text();
                const parser = new DOMParser();
                const doc = parser.parseFromString(html, 'text/html');
                const table = doc.querySelector('table');
                if (!table) return [];

                const drives = [];
                const rows = table.querySelectorAll('tr');
                for (let i = 1; i < rows.length; i++) {
                    const cells = rows[i].querySelectorAll('td');
                    if (cells.length >= 1) {
                        const link = cells[0]?.querySelector('a');
                        let name = link?.textContent || cells[0]?.textContent || '';
                        if (/^[A-Z]:$/i.test(name)) {
                            drives.push(`${name}\\`);
                        }
                    }
                }
                return drives;
            } catch (err) {
                console.error('获取磁盘列表失败', err);
                return ['C:\\'];
            }
        }

        async function init() {
            const drives = await fetchDriveList();
            if (drives.length > 0) {
                driveList.length = 0;
                driveList.push(...drives);
            }
            renderDriveButtons();
        }

        function getDriveRootFromPath(path) {
            const match = path.match(/^[A-Z]:\\/i);
            return match ? match[0] : null;
        }

        function updateDriveHighlights() {
            const currentRoot = getDriveRootFromPath(currentPath);
            document.querySelectorAll('.drive-btn').forEach(btn => {
                const drive = btn.dataset.drive;
                if (drive === currentRoot) {
                    btn.classList.add('active');
                } else {
                    btn.classList.remove('active');
                }
            });
        }

        function renderDriveButtons() {
            driveBar.innerHTML = driveList.map(drive =>
                `<button class="drive-btn" data-drive="${drive}">${drive.replace('\\', '')}</button>`
            ).join('');

            document.querySelectorAll('.drive-btn').forEach(btn => {
                btn.addEventListener('click', () => {
                    browseDirectory(btn.dataset.drive);
                });
            });
            updateDriveHighlights();
        }

        function escapeAttr(str) {
            if (!str) return '';
            return str.replace(/&/g, '&amp;')
                .replace(/</g, '&lt;')
                .replace(/>/g, '&gt;')
                .replace(/"/g, '&quot;')
                .replace(/'/g, '&#39;')
                .replace(/\\/g, '&#92;');
        }

        function escapeHtml(str) {
            if (!str) return '';
            return str.replace(/[&<>]/g, (m) => {
                if (m === '&') return '&amp;';
                if (m === '<') return '&lt;';
                if (m === '>') return '&gt;';
                return m;
            });
        }

        function urlToLocalPath(url) {
            try {
                const urlObj = new URL(url);
                let pathname = decodeURIComponent(urlObj.pathname);
                if (pathname.startsWith('/')) pathname = pathname.substring(1);
                return pathname.replace(/\//g, '\\');
            } catch (e) {
                return url;
            }
        }

        // 提取路径的目录部分(去掉文件名)
        function getDirectoryPath(fullPath) {
            const lastSlash = fullPath.lastIndexOf('\\');
            if (lastSlash > 0) {
                return fullPath.substring(0, lastSlash + 1);
            }
            return fullPath;
        }

        // ==================== 搜索功能 ====================
        async function performSearch(query) {
            if (!query.trim()) {
                resultsContainer.innerHTML = '<div class="status">输入关键词开始搜索</div>';
                return;
            }
            resultsContainer.innerHTML = '<div class="status">搜索中...</div>';
            try {
                const response = await fetch(`/?search=${encodeURIComponent(query)}`);
                const html = await response.text();
                const results = parseSearchResults(html);
                renderSearchResults(results, query);
            } catch (err) {
                resultsContainer.innerHTML = '<div class="status">❌ 搜索失败</div>';
            }
        }

        function parseSearchResults(html) {
            const results = [];
            const parser = new DOMParser();
            const doc = parser.parseFromString(html, 'text/html');
            const table = doc.querySelector('table');
            if (!table) return results;
            const rows = table.querySelectorAll('tr');
            for (let i = 1; i < rows.length; i++) {
                const cells = rows[i].querySelectorAll('td');
                if (cells.length >= 3) {
                    const link = cells[0]?.querySelector('a');
                    let name = link?.textContent || cells[0]?.textContent || '';
                    const nativeUrl = link?.href || '';
                    const idxSize = cells.length > 3 ? 2 : 1;
                    const idxDate = cells.length > 3 ? 3 : 2;
                    const size = cells[idxSize]?.textContent?.trim() || '';
                    const date = cells[idxDate]?.textContent?.trim() || '';

                    if (name === '名称' || name === 'Name' || name === 'name') continue;
                    if (name.includes('\\')) {
                        name = name.split('\\').pop();
                    }
                    if (!name) continue;

                    const isFolder = (size === '' && !/^[A-Z]:$/i.test(name));
                    let folderPath = '';
                    if (isFolder) {
                        folderPath = urlToLocalPath(nativeUrl);
                    }

                    // 获取文件所在目录路径
                    const localPath = urlToLocalPath(nativeUrl);
                    const directoryPath = isFolder ? localPath : getDirectoryPath(localPath);

                    results.push({ name, nativeUrl, size, date, isFolder, folderPath, directoryPath });
                }
            }
            return results;
        }

        function renderSearchResults(results, query) {
            if (!results.length) {
                resultsContainer.innerHTML = `<div class="status">没有找到 "${escapeHtml(query)}" 相关文件</div>`;
                return;
            }

            const folders = results.filter(r => r.isFolder);
            const files = results.filter(r => !r.isFolder);

            const html = `
            <div class="stats">找到 ${results.length} 个结果(目录 ${folders.length},文件 ${files.length})</div>
            <ul class="results">
                ${folders.map(folder => `
                    <li class="file-item" data-type="folder" data-path="${escapeAttr(folder.folderPath)}">
                        <div class="folder-item">
                            <div class="folder-icon">📂</div>
                            <div class="file-info">
                                <div class="folder-name">${escapeHtml(folder.name)}</div>
                                <div class="file-meta">${escapeHtml(folder.folderPath)}</div>
                            </div>
                        </div>
                    </li>
                `).join('')}
                ${files.map(file => `
                    <li class="file-item">
                        <a href="${escapeAttr(file.nativeUrl)}" target="_blank" class="file-link">
                            <div class="file-icon">${getIcon(file.name)}</div>
                            <div class="file-info">
                                <div class="file-name">${escapeHtml(file.name)}</div>
                                <div class="file-meta">${file.size} • ${file.date} • ${escapeHtml(file.directoryPath)}</div>
                            </div>
                        </a>
                    </li>
                `).join('')}
            </ul>
        `;
            resultsContainer.innerHTML = html;

            document.querySelectorAll('#resultsContainer .file-item[data-type="folder"]').forEach(el => {
                el.addEventListener('click', (e) => {
                    e.preventDefault();
                    e.stopPropagation();
                    const path = el.dataset.path;
                    if (path) {
                        searchInput.value = '';
                        browseDirectory(path);
                    }
                });
            });
        }

        if (searchInput) {
            searchInput.addEventListener('input', (e) => {
                if (searchDebounceTimer) clearTimeout(searchDebounceTimer);
                searchDebounceTimer = setTimeout(() => {
                    performSearch(e.target.value);
                }, 300);
            });
        }

        function getIcon(filename) {
            const ext = filename.split('.').pop().toLowerCase();
            const icons = {
                'mp4': '🎬', 'mkv': '🎥', 'avi': '🎬', 'mov': '🎬', 'mp3': '🎵',
                'jpg': '🖼️', 'jpeg': '🖼️', 'png': '🖼️', 'gif': '🖼️', 'pdf': '📄',
                'doc': '📝', 'docx': '📝', 'txt': '📃', 'zip': '📦', 'rar': '📦', 'exe': '⚙️'
            };
            return icons[ext] || '📄';
        }

        async function browseDirectory(path) {
            let normalizedPath = path.trim();
            if (!normalizedPath.endsWith('\\')) {
                normalizedPath += '\\';
            }
            currentPath = normalizedPath;

            updateBreadcrumb(currentPath);
            updateDriveHighlights();
            resultsContainer.innerHTML = '<div class="status">加载中...</div>';

            try {
                const searchQuery = `parent:"${currentPath}"`;
                const response = await fetch(`/?search=${encodeURIComponent(searchQuery)}`);
                const html = await response.text();
                const items = parseBrowseResults(html, currentPath);
                renderBrowseResults(items);
            } catch (err) {
                resultsContainer.innerHTML = '<div class="status">❌ 读取目录失败</div>';
            }
        }

        function parseBrowseResults(html, currentPath) {
            const items = [];
            const parser = new DOMParser();
            const doc = parser.parseFromString(html, 'text/html');
            const table = doc.querySelector('table');
            if (!table) return items;

            const rows = table.querySelectorAll('tr');
            for (let i = 1; i < rows.length; i++) {
                const cells = rows[i].querySelectorAll('td');
                if (cells.length >= 3) {
                    const link = cells[0]?.querySelector('a');
                    let name = link?.textContent || cells[0]?.textContent || '';
                    const idxSize = cells.length > 3 ? 2 : 1;
                    const idxDate = cells.length > 3 ? 3 : 2;
                    let size = cells[idxSize]?.textContent?.trim() || '';
                    let date = cells[idxDate]?.textContent?.trim() || '';
                    const nativeUrl = link?.href || '';

                    if (name === '名称' || name === 'Name' || name === 'name') continue;
                    if (name.includes('\\')) {
                        name = name.split('\\').pop();
                    }
                    if (!name || name === '.' || name === '..') continue;
                    if (/^[A-Z]:$/i.test(name)) continue;

                    const isFolder = (size === '');

                    items.push({ name, size, date, isFolder, nativeUrl });
                }
            }

            const parentPath = getParentPath(currentPath);
            if (parentPath && parentPath !== currentPath) {
                items.unshift({
                    name: '..',
                    isFolder: true,
                    isParent: true,
                    parentPath: parentPath
                });
            }
            return items;
        }

        function getParentPath(path) {
            let p = path.replace(/\\$/, '');
            const lastSlash = p.lastIndexOf('\\');
            if (lastSlash <= 2) {
                return p.substring(0, lastSlash + 1);
            }
            if (lastSlash > 0) {
                return p.substring(0, lastSlash + 1);
            }
            return null;
        }

        function updateBreadcrumb(path) {
            const parts = path.split('\\').filter(p => p !== '');
            if (parts.length === 0) {
                breadcrumbDiv.style.display = 'none';
                return;
            }

            let html = '';
            let current = '';

            for (let i = 0; i < parts.length; i++) {
                current += parts[i] + '\\';
                if (i === parts.length - 1) {
                    html += `<span>${escapeHtml(parts[i])}</span>`;
                } else {
                    const jsPath = current.replace(/\\/g, '\\\\');
                    if (i === 0 && parts[i].includes(':')) {
                        html += `<span onclick="window.browseDirectory('${jsPath}')">${escapeHtml(parts[i])}</span><span class="separator">/</span>`;
                    } else {
                        html += `<span onclick="window.browseDirectory('${jsPath}')">${escapeHtml(parts[i])}</span><span class="separator">/</span>`;
                    }
                }
            }

            breadcrumbDiv.innerHTML = `📁 ${html}`;
            breadcrumbDiv.style.display = 'block';
        }

        function renderBrowseResults(items) {
            if (!items.length) {
                resultsContainer.innerHTML = '<div class="status">此目录为空</div>';
                return;
            }

            const regularCount = items.filter(i => !i.isParent).length;
            const html = `
            <div class="stats">共 ${regularCount} 个项目</div>
            <ul class="results">
                ${items.map(item => {
                if (item.isParent) {
                    return `
                            <li class="file-item" data-type="parent" data-path="${escapeAttr(item.parentPath)}">
                                <div class="folder-item">
                                    <div class="folder-icon">📂</div>
                                    <div class="file-info">
                                        <div class="folder-name">⬆️ 返回上级</div>
                                    </div>
                                </div>
                            </li>
                        `;
                }
                if (item.isFolder) {
                    const folderPath = currentPath + item.name + '\\';
                    return `
                            <li class="file-item" data-type="folder" data-path="${escapeAttr(folderPath)}">
                                <div class="folder-item">
                                    <div class="folder-icon">📂</div>
                                    <div class="file-info">
                                        <div class="folder-name">📁 ${escapeHtml(item.name)}</div>
                                        <div class="file-meta">${escapeHtml(folderPath)}</div>
                                    </div>
                                </div>
                            </li>
                        `;
                }
                return `
                        <li class="file-item">
                            <a href="${escapeAttr(item.nativeUrl)}" target="_blank" class="file-link">
                                <div class="file-icon">${getIcon(item.name)}</div>
                                <div class="file-info">
                                    <div class="file-name">${escapeHtml(item.name)}</div>
                                    <div class="file-meta">${item.size} • ${item.date} • ${escapeHtml(currentPath)}</div>
                                </div>
                            </a>
                        </li>
                    `;
            }).join('')}
            </ul>
        `;
            resultsContainer.innerHTML = html;

            document.querySelectorAll('#resultsContainer .file-item[data-type="parent"], #resultsContainer .file-item[data-type="folder"]').forEach(el => {
                el.addEventListener('click', (e) => {
                    e.preventDefault();
                    e.stopPropagation();
                    const path = el.dataset.path;
                    if (path) browseDirectory(path);
                });
            });
        }

        window.browseDirectory = browseDirectory;

        init();
    </script>
</body>

</html>

View Code