Files
Cloud-Index/templates/index.html
2025-11-02 16:10:27 +08:00

404 lines
15 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>R2 存储浏览器</title>
<link rel="icon" type="image/svg+xml" href="{{ url_for('static', filename='favicon.svg') }}" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" />
<style>
:root {
--bg-color: #f5f5f5;
--container-bg: white;
--text-color: #2c3e50;
--border-color: #eee;
--hover-bg: #f8f9fa;
--secondary-text: #6c757d;
--link-color: #007bff;
--folder-color: #ffc107;
--file-color: #6c757d;
--shadow-color: rgba(0, 0, 0, 0.1);
}
[data-theme="dark"] {
--bg-color: #1a1a1a;
--container-bg: #2d2d2d;
--text-color: #e1e1e1;
--border-color: #404040;
--hover-bg: #363636;
--secondary-text: #a0a0a0;
--link-color: #66b3ff;
--folder-color: #ffd54f;
--file-color: #b0b0b0;
--shadow-color: rgba(0, 0, 0, 0.3);
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background-color: var(--bg-color);
color: var(--text-color);
transition: background-color 0.3s ease, color 0.3s ease;
}
.container {
background-color: var(--container-bg);
border-radius: 8px;
box-shadow: 0 2px 4px var(--shadow-color);
padding: 20px;
}
h1 {
color: var(--text-color);
margin-bottom: 30px;
border-bottom: 2px solid var(--border-color);
padding-bottom: 10px;
display: flex;
justify-content: space-between;
align-items: center;
}
.theme-toggle {
background: none;
border: none;
color: var(--secondary-text);
cursor: pointer;
padding: 8px;
border-radius: 4px;
font-size: 1.2em;
}
.theme-toggle:hover {
background-color: var(--hover-bg);
}
.view-toggle {
background: none;
border: none;
color: var(--secondary-text);
cursor: pointer;
padding: 8px;
border-radius: 4px;
font-size: 1.2em;
margin-left: 8px;
}
.view-toggle:hover {
background-color: var(--hover-bg);
}
/* Grid view styles */
.grid-container {
display: none; /* 默认隐藏,只有 data-view="grid" 时显示 */
margin-top: 20px;
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
gap: 12px;
}
.grid-card {
background: var(--container-bg);
border: 1px solid var(--border-color);
border-radius: 8px;
padding: 10px;
text-align: center;
box-shadow: 0 1px 2px var(--shadow-color);
}
.grid-thumb {
width: 100%;
height: 100px;
object-fit: cover;
border-radius: 6px;
margin-bottom: 8px;
background-color: #f0f0f0;
}
.grid-name {
display: block;
font-size: 0.95em;
color: var(--text-color);
margin-bottom: 6px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* Toggle visibility based on data-view on root */
:root[data-view="grid"] .files-table {
display: none;
}
:root[data-view="grid"] .grid-container {
display: grid;
}
.files-table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
.files-table th,
.files-table td {
padding: 12px;
text-align: left;
border-bottom: 1px solid var(--border-color);
}
.files-table th {
background-color: var(--hover-bg);
color: var(--text-color);
font-weight: 600;
}
.files-table tr:hover {
background-color: var(--hover-bg);
}
.file-icon {
margin-right: 8px;
}
.folder {
color: var(--folder-color);
}
.file {
color: var(--file-color);
}
a {
color: var(--link-color);
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
.file-size {
color: var(--secondary-text);
font-size: 0.9em;
}
.last-modified {
color: var(--secondary-text);
font-size: 0.9em;
}
.empty-message {
text-align: center;
padding: 40px;
color: var(--secondary-text);
}
.breadcrumb {
margin-bottom: 12px;
font-size: 0.95em;
color: var(--secondary-text);
background-color: var(--container-bg);
padding: 8px 12px;
border-radius: 4px;
}
/* 页脚样式 */
.site-footer {
margin-top: 20px;
text-align: center;
color: var(--secondary-text);
font-size: 0.9em;
padding: 14px 12px;
}
.site-footer a {
color: var(--link-color);
text-decoration: none;
margin: 0 6px;
}
.site-footer a:hover {
text-decoration: underline;
}
@media (max-width: 600px) {
.site-footer {
font-size: 0.85em;
padding: 12px 8px;
}
}
</style>
</head>
<body>
<div class="container">
<h1>
RhenCloud's R2 Drive
<div>
<button class="theme-toggle" aria-label="切换深色模式">
<i class="fas fa-moon"></i>
</button>
<button class="view-toggle" aria-label="切换视图">
<i class="fas fa-th-list"></i>
</button>
</div>
</h1>
<div class="breadcrumb">
<a href="/">Home</a>
{% if crumbs %} &nbsp;/&nbsp; {% for c in crumbs %}
<a href="/{{ c.prefix.rstrip('/') }}">{{ c.name }}</a>{% if not loop.last %} / {% endif %} {% endfor %}
{% endif %}
</div>
{% if entries %}
<table class="files-table">
<thead>
<tr>
<th>名称</th>
<th>大小</th>
<th>最后修改时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for entry in entries %}
<tr>
<td>
{% if entry.is_dir %}
<i class="file-icon folder fas fa-folder"></i>
<a href="/{{ entry.key.rstrip('/') }}">{{ entry.name }}</a>
{% else %}
<i class="file-icon file {{ entry.name|fileicon }}"></i>
<a href="{{ entry.file_url }}" target="_blank">{{ entry.name }}</a>
{% endif %}
</td>
<td class="file-size">
{% if not entry.is_dir %} {{ entry.size|filesizeformat }} {% else %} - {% endif %}
</td>
<td class="last-modified">
{% if not entry.is_dir %} {{ entry.last_modified }} {% else %} - {% endif %}
</td>
<td>
{% if not entry.is_dir %}
<a href="{{ entry.file_url }}" target="_blank">预览</a>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="grid-container" id="gridContainer">
{% for entry in entries %}
<div class="grid-card">
{% if entry.is_dir %}
<i class="fas fa-folder fa-2x" style="color: var(--folder-color)"></i>
<a class="grid-name" href="/{{ entry.key.rstrip('/') }}">{{ entry.name }}</a>
{% else %} {% if entry.name|fileicon == 'fas fa-image' %}
<a href="{{ entry.file_url }}" target="_blank">
<img class="grid-thumb" src="{{ entry.file_url }}" alt="{{ entry.name }}" />
</a>
{% else %}
<i class="{{ entry.name|fileicon }} fa-2x" style="color: var(--file-color)"></i>
{% endif %}
<a class="grid-name" href="{{ entry.file_url }}" target="_blank">{{ entry.name }}</a>
<div class="file-size">{% if not entry.is_dir %} {{ entry.size|filesizeformat }} {% endif %}</div>
{% endif %}
</div>
{% endfor %}
</div>
{% else %}
<div class="empty-message">
<p>存储桶为空或未找到任何文件</p>
</div>
{% endif %}
</div>
{% include 'footer.html' %}
<script>
// 主题切换功能
document.addEventListener("DOMContentLoaded", () => {
const themeToggle = document.querySelector(".theme-toggle");
const themeIcon = themeToggle.querySelector("i");
// 检查用户之前的主题偏好
const savedTheme = localStorage.getItem("theme");
if (savedTheme === "dark") {
document.documentElement.setAttribute("data-theme", "dark");
themeIcon.classList.remove("fa-moon");
themeIcon.classList.add("fa-sun");
}
// 视图切换(列表 / 网格)
const viewToggle = document.querySelector(".view-toggle");
const viewIcon = viewToggle.querySelector("i");
// 初始化视图(从 localStorage 或默认 list
const savedView = localStorage.getItem("view") || "list";
document.documentElement.setAttribute("data-view", savedView);
if (savedView === "grid") {
viewIcon.classList.remove("fa-th-list");
viewIcon.classList.add("fa-th-large");
} else {
viewIcon.classList.remove("fa-th-large");
viewIcon.classList.add("fa-th-list");
}
viewToggle.addEventListener("click", () => {
const current = document.documentElement.getAttribute("data-view") || "list";
const next = current === "grid" ? "list" : "grid";
document.documentElement.setAttribute("data-view", next);
localStorage.setItem("view", next);
if (next === "grid") {
viewIcon.classList.remove("fa-th-list");
viewIcon.classList.add("fa-th-large");
} else {
viewIcon.classList.remove("fa-th-large");
viewIcon.classList.add("fa-th-list");
}
});
// 切换主题
themeToggle.addEventListener("click", () => {
const currentTheme = document.documentElement.getAttribute("data-theme");
const newTheme = currentTheme === "dark" ? "light" : "dark";
document.documentElement.setAttribute("data-theme", newTheme);
localStorage.setItem("theme", newTheme);
// 更新图标
if (newTheme === "dark") {
themeIcon.classList.remove("fa-moon");
themeIcon.classList.add("fa-sun");
} else {
themeIcon.classList.remove("fa-sun");
themeIcon.classList.add("fa-moon");
}
});
// 检查系统主题偏好
if (!savedTheme) {
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
if (prefersDark) {
document.documentElement.setAttribute("data-theme", "dark");
themeIcon.classList.remove("fa-moon");
themeIcon.classList.add("fa-sun");
localStorage.setItem("theme", "dark");
}
}
// 注册 Service Worker 来处理缩略图缓存
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/static/sw.js')
.then(function(registration) {
console.log('SW registered: ', registration);
})
.catch(function(registrationError) {
console.log('SW registration failed: ', registrationError);
});
});
}
});
</script>
</body>
</html>