Files
hubproxy/src/public/index.html
2025-06-12 17:01:41 +08:00

846 lines
27 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">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Github文件加速,docker镜像加速">
<meta name="keywords" content="Github,文件加速,ghproxy,docker镜像加速">
<meta name="color-scheme" content="dark light">
<title>Github文件加速</title>
<link rel="icon" href="./favicon.ico">
<style>
:root {
--background: #ffffff;
--foreground: #0f172a;
--card: #ffffff;
--card-foreground: #0f172a;
--primary: #2563eb;
--primary-foreground: #f8fafc;
--secondary: #f1f5f9;
--secondary-foreground: #0f172a;
--muted: #f1f5f9;
--muted-foreground: #64748b;
--accent: #f1f5f9;
--accent-foreground: #0f172a;
--border: #e2e8f0;
--input: #ffffff;
--ring: #2563eb;
--radius: 0.5rem;
}
.dark {
--background: #0f172a;
--foreground: #f8fafc;
--card: #1e293b;
--card-foreground: #f8fafc;
--primary: #3b82f6;
--primary-foreground: #f8fafc;
--secondary: #1e293b;
--secondary-foreground: #f8fafc;
--muted: #1e293b;
--muted-foreground: #94a3b8;
--accent: #1e293b;
--accent-foreground: #f8fafc;
--border: #334155;
--input: #1e293b;
--ring: #3b82f6;
}
@media (prefers-color-scheme: dark) {
:root {
--background: #0f172a;
--foreground: #f8fafc;
--card: #1e293b;
--card-foreground: #f8fafc;
--primary: #3b82f6;
--primary-foreground: #f8fafc;
--secondary: #1e293b;
--secondary-foreground: #f8fafc;
--muted: #1e293b;
--muted-foreground: #94a3b8;
--accent: #1e293b;
--accent-foreground: #f8fafc;
--border: #334155;
--input: #1e293b;
--ring: #3b82f6;
}
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
background-color: var(--background);
color: var(--foreground);
line-height: 1.5;
min-height: 100vh;
display: flex;
flex-direction: column;
transition: background-color 0.3s, color 0.3s;
}
.navbar {
position: sticky;
top: 0;
z-index: 50;
width: 100%;
border-bottom: 1px solid var(--border);
background-color: var(--background);
backdrop-filter: blur(8px);
background-color: rgba(255, 255, 255, 0.95);
}
.dark .navbar {
background-color: rgba(15, 23, 42, 0.95);
}
.navbar-container {
max-width: 1200px;
margin: 0 auto;
padding: 0 1rem;
display: flex;
align-items: center;
justify-content: space-between;
height: 4rem;
}
.logo {
display: flex;
align-items: center;
gap: 0.5rem;
text-decoration: none;
color: var(--foreground);
font-weight: 600;
font-size: 1.125rem;
}
.logo-icon {
width: 2rem;
height: 2rem;
border-radius: 0.5rem;
background: linear-gradient(135deg, var(--primary), #3b82f6);
display: flex;
align-items: center;
justify-content: center;
color: white;
}
.nav-links {
display: flex;
align-items: center;
gap: 0.5rem;
}
.nav-link {
padding: 0.5rem 1rem;
border-radius: var(--radius);
text-decoration: none;
color: var(--muted-foreground);
transition: all 0.2s;
font-weight: 500;
}
.nav-link:hover,
.nav-link.active {
color: var(--foreground);
background-color: var(--muted);
}
.theme-toggle {
padding: 0.5rem;
border: none;
border-radius: var(--radius);
background-color: transparent;
color: var(--muted-foreground);
cursor: pointer;
transition: all 0.2s;
}
.theme-toggle:hover {
background-color: var(--muted);
color: var(--foreground);
}
.main {
flex: 1;
padding: 2rem 1rem;
}
.container {
max-width: 1000px;
margin: 0 auto;
}
.hero {
text-align: center;
margin-bottom: 3rem;
opacity: 0;
transform: translateY(20px);
animation: fadeInUp 0.6s ease-out forwards;
}
.hero-title {
font-size: 2.5rem;
font-weight: 700;
margin-bottom: 1rem;
background: linear-gradient(135deg, var(--primary), #3b82f6);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.hero-subtitle {
font-size: 1.125rem;
color: var(--muted-foreground);
max-width: 600px;
margin: 0 auto;
}
.card {
background-color: var(--card);
border: 1px solid var(--border);
border-radius: 0.75rem;
padding: 1.5rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
margin-bottom: 2rem;
opacity: 0;
transform: translateY(20px);
animation: fadeInUp 0.6s ease-out 0.2s forwards;
}
.card-header {
margin-bottom: 1.5rem;
}
.card-title {
font-size: 1.25rem;
font-weight: 600;
margin-bottom: 0.5rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
.card-description {
color: var(--muted-foreground);
font-size: 0.875rem;
}
.form-group {
margin-bottom: 1rem;
}
.input-container {
position: relative;
display: flex;
gap: 0.75rem;
}
.input {
flex: 1;
padding: 0.75rem 1rem;
border: 1px solid var(--border);
border-radius: var(--radius);
background-color: var(--input);
color: var(--foreground);
font-size: 1rem;
transition: all 0.2s;
}
.input:focus {
outline: none;
border-color: var(--ring);
box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.2);
}
.input::placeholder {
color: var(--muted-foreground);
}
.button {
padding: 0.75rem 1.5rem;
border: none;
border-radius: var(--radius);
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
display: inline-flex;
align-items: center;
gap: 0.5rem;
}
.button-primary {
background-color: var(--primary);
color: var(--primary-foreground);
}
.button-primary:hover {
background-color: #1d4ed8;
transform: translateY(-1px);
}
.button-secondary {
background-color: var(--secondary);
color: var(--secondary-foreground);
}
.button-secondary:hover {
background-color: var(--muted);
}
.output-container {
margin-top: 1.5rem;
display: none;
opacity: 0;
transform: translateY(10px);
transition: all 0.3s;
}
.output-container.show {
display: block;
opacity: 1;
transform: translateY(0);
}
.success-header {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 1rem;
color: #059669;
}
.output-box {
background-color: var(--muted);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 1rem;
font-family: 'Consolas', 'Monaco', monospace;
font-size: 0.875rem;
word-break: break-all;
position: relative;
margin-bottom: 1rem;
}
.output-actions {
display: flex;
gap: 0.5rem;
}
.docker-info {
opacity: 0;
transform: translateY(20px);
animation: fadeInUp 0.6s ease-out 0.4s forwards;
}
.docker-button {
width: 100%;
padding: 1rem;
background: linear-gradient(135deg, #f1f5f9, #e2e8f0);
border: 1px solid var(--border);
border-radius: var(--radius);
cursor: pointer;
transition: all 0.3s;
font-size: 1rem;
font-weight: 500;
color: var(--foreground);
}
.docker-button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.dark .docker-button {
background: linear-gradient(135deg, #374151, #4b5563);
}
.dark .docker-button:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
.modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: none;
align-items: center;
justify-content: center;
z-index: 1000;
backdrop-filter: blur(4px);
}
.modal-content {
background-color: var(--card);
border-radius: 0.75rem;
padding: 2rem;
max-width: 600px;
width: 90%;
max-height: 80vh;
overflow-y: auto;
position: relative;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
}
.modal-header {
text-align: center;
margin-bottom: 2rem;
}
.modal-title {
font-size: 1.5rem;
font-weight: 600;
margin-bottom: 0.5rem;
}
.close-button {
position: absolute;
top: 1rem;
right: 1rem;
background: none;
border: none;
font-size: 1.5rem;
cursor: pointer;
color: var(--muted-foreground);
padding: 0.25rem;
border-radius: var(--radius);
}
.close-button:hover {
background-color: var(--muted);
}
.domain-examples {
background-color: var(--muted);
border-radius: var(--radius);
padding: 1rem;
font-family: 'Consolas', 'Monaco', monospace;
font-size: 0.875rem;
line-height: 1.6;
}
.domain-examples strong {
color: var(--foreground);
display: block;
margin: 1rem 0 0.5rem 0;
}
.domain-examples strong:first-child {
margin-top: 0;
}
.toast {
position: fixed;
top: 1rem;
right: 1rem;
background-color: var(--primary);
color: var(--primary-foreground);
padding: 1rem 1.5rem;
border-radius: var(--radius);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
z-index: 1001;
display: none;
opacity: 0;
transform: translateX(100%);
transition: all 0.3s ease;
}
.toast.show {
display: block;
opacity: 1;
transform: translateX(0);
}
.footer {
padding: 2rem 1rem;
text-align: center;
border-top: 1px solid var(--border);
}
.github-link {
display: inline-flex;
align-items: center;
gap: 0.5rem;
color: var(--muted-foreground);
text-decoration: none;
transition: color 0.2s;
}
.github-link:hover {
color: var(--foreground);
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@media (max-width: 768px) {
.hero-title {
font-size: 2rem;
}
.nav-links {
position: fixed;
top: 70px;
left: 0;
right: 0;
background: var(--background);
border: 1px solid var(--border);
border-top: none;
border-radius: 0 0 12px 12px;
padding: 1rem;
flex-direction: column;
gap: 0.5rem;
z-index: 1000;
transform: translateY(-100vh);
transition: transform 0.3s ease;
}
.nav-links.active {
transform: translateY(0);
}
.mobile-menu-toggle {
display: block !important;
background: none;
border: none;
color: var(--foreground);
font-size: 1.5rem;
cursor: pointer;
padding: 0.5rem;
border-radius: var(--radius);
transition: background-color 0.2s;
}
.mobile-menu-toggle:hover {
background-color: var(--muted);
}
.navbar-container {
justify-content: space-between !important;
}
.container {
padding: 0 1rem;
}
.modal-content {
padding: 1.5rem;
}
/* 移动端快速生成加速链接区域优化 */
.input-container {
flex-direction: column;
gap: 1rem;
}
.input {
font-size: 16px; /* 防止iOS缩放 */
}
.button {
width: 100%;
justify-content: center;
padding: 0.875rem 1.5rem;
}
.output-actions {
flex-direction: column;
gap: 0.75rem;
}
}
.mobile-menu-toggle {
display: none;
}
</style>
</head>
<body>
<!-- 现代化导航栏 -->
<nav class="navbar">
<div class="navbar-container">
<a href="/" class="logo">
<div class="logo-icon">
</div>
加速服务
</a>
<button class="mobile-menu-toggle" id="mobileMenuToggle">
</button>
<div class="nav-links" id="navLinks">
<a href="/" class="nav-link active">🚀 GitHub加速</a>
<a href="/skopeo.html" class="nav-link">🐳 离线镜像下载</a>
<a href="/search.html" class="nav-link">🔍 镜像搜索</a>
<a href="https://gitee.com/if-the-wind/github-hosts/raw/main/hosts" target="_blank" class="nav-link">📄 Hosts</a>
<button class="theme-toggle" id="themeToggle">
🌙
</button>
</div>
</div>
</nav>
<!-- 主要内容 -->
<main class="main">
<div class="container">
<!-- Hero 区域 -->
<div class="hero">
<h1 class="hero-title">GitHub 文件加速</h1>
<p class="hero-subtitle">
快速下载GitHub上的文件和仓库解决国内访问GitHub速度慢的问题支持AI模型库Hugging Face
</p>
</div>
<!-- 主功能卡片 -->
<div class="card">
<div class="card-header">
<h2 class="card-title">
⚡ 快速生成加速链接
</h2>
<p class="card-description">
输入GitHub文件或仓库链接自动转换加速链接可以直接在Github域名前面加上本站域名使用。
</p>
</div>
<div class="form-group">
<div class="input-container">
<input
type="text"
class="input"
id="githubLinkInput"
placeholder="请输入GitHub链接例如https://github.com/user/repo/releases/download/..."
>
<button class="button button-primary" id="formatButton">
获取加速链接
</button>
</div>
</div>
<!-- 输出区域 -->
<div class="output-container" id="outputBlock">
<div class="success-header">
<span></span>
<strong>加速链接已生成</strong>
</div>
<div class="output-box" id="formattedLinkOutput"></div>
<div class="output-actions">
<button class="button button-secondary" id="copyButton">
📋 复制链接
</button>
<button class="button button-secondary" id="redirButton">
🔗 打开链接
</button>
</div>
</div>
</div>
<!-- Docker 信息卡片 -->
<div class="card docker-info">
<div class="card-header">
<h3 class="card-title">
🐳 Docker 镜像加速
</h3>
<p class="card-description">
支持多种Registry在镜像名前添加本站域名即可加速下载。
</p>
</div>
<button class="docker-button" id="dockerButton">
查看 Docker 镜像加速配置
</button>
</div>
</div>
</main>
<!-- Docker 模态框 -->
<div id="dockerModal" class="modal">
<div class="modal-content">
<button class="close-button" id="closeModal">&times;</button>
<div class="modal-header">
<h2 class="modal-title">Docker 镜像加速</h2>
<p>支持多种Registry在镜像名前添加本站域名即可加速下载。</p>
</div>
<div class="domain-examples">
<strong>Docker Hub 官方镜像:</strong>
docker pull <span class="domain-base"></span>/nginx
<strong>Docker Hub 第三方镜像:</strong>
docker pull <span class="domain-base"></span>/user/image
<strong>GitHub Container Registry</strong>
docker pull <span class="domain-base"></span>/ghcr.io/user/image
<strong>Quay.io Registry</strong>
docker pull <span class="domain-base"></span>/quay.io/org/image
<strong>Kubernetes Registry</strong>
docker pull <span class="domain-base"></span>/registry.k8s.io/pause:3.8
</div>
</div>
</div>
<!-- Toast 通知 -->
<div id="toast" class="toast">
链接已复制到剪贴板
</div>
<!-- 页脚 -->
<footer class="footer">
<a href="https://github.com/sky22333/hubproxy" target="_blank" class="github-link">
<svg width="20" height="20" viewBox="0 0 16 16" fill="currentColor">
<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/>
</svg>
GitHub
</a>
</footer>
<script>
const themeToggle = document.getElementById('themeToggle');
const html = document.documentElement;
const savedTheme = localStorage.getItem('theme');
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
if (savedTheme === 'dark' || (!savedTheme && prefersDark)) {
html.classList.add('dark');
themeToggle.textContent = '☀️';
}
themeToggle.addEventListener('click', () => {
html.classList.toggle('dark');
const isDark = html.classList.contains('dark');
themeToggle.textContent = isDark ? '☀️' : '🌙';
localStorage.setItem('theme', isDark ? 'dark' : 'light');
});
document.addEventListener('DOMContentLoaded', function() {
const fullDomain = window.location.host;
document.querySelectorAll('.domain-base').forEach(span => {
span.textContent = fullDomain;
});
const modal = document.getElementById('dockerModal');
const dockerButton = document.getElementById('dockerButton');
const closeButton = document.getElementById('closeModal');
dockerButton.onclick = () => modal.style.display = "flex";
closeButton.onclick = () => modal.style.display = "none";
window.onclick = (event) => {
if (event.target == modal) modal.style.display = "none";
};
});
function formatGithubLink() {
const githubLinkInput = document.getElementById('githubLinkInput');
const currentHost = window.location.host;
let formattedLink = "";
const link = githubLinkInput.value.trim();
if (link.startsWith("https://") || link.startsWith("http://")) {
formattedLink = "https://" + currentHost + "/" + link;
} else if (
link.startsWith("github.com/") ||
link.startsWith("raw.githubusercontent.com/") ||
link.startsWith("gist.githubusercontent.com/") ||
link.startsWith("huggingface.co/") ||
link.startsWith("cdn-lfs.hf.co/") ||
link.startsWith("download.docker.com/")
) {
formattedLink = "https://" + currentHost + "/https://" + link;
} else {
showToast('请输入有效的链接');
return;
}
const formattedLinkOutput = document.getElementById('formattedLinkOutput');
formattedLinkOutput.textContent = formattedLink;
const outputBlock = document.getElementById('outputBlock');
outputBlock.classList.add('show');
}
function copyToClipboard() {
const output = document.getElementById('formattedLinkOutput');
const text = output.textContent;
if (navigator.clipboard) {
navigator.clipboard.writeText(text).then(() => {
showToast('链接已复制到剪贴板');
});
} else {
const range = document.createRange();
range.selectNode(output);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
document.execCommand('copy');
window.getSelection().removeAllRanges();
showToast('链接已复制到剪贴板');
}
}
function openLink() {
const formattedLinkOutput = document.getElementById('formattedLinkOutput');
window.open(formattedLinkOutput.textContent);
}
function showToast(message) {
const toast = document.getElementById('toast');
toast.textContent = message;
toast.classList.add('show');
setTimeout(() => {
toast.classList.remove('show');
}, 3000);
}
document.getElementById('formatButton').addEventListener('click', formatGithubLink);
document.getElementById('copyButton').addEventListener('click', copyToClipboard);
document.getElementById('redirButton').addEventListener('click', openLink);
document.getElementById('githubLinkInput').addEventListener('keyup', function(event) {
if (event.key === 'Enter') {
formatGithubLink();
}
});
// 移动端菜单切换
const mobileMenuToggle = document.getElementById('mobileMenuToggle');
const navLinks = document.getElementById('navLinks');
mobileMenuToggle.addEventListener('click', () => {
navLinks.classList.toggle('active');
mobileMenuToggle.textContent = navLinks.classList.contains('active') ? '✕' : '☰';
});
// 点击页面其他地方关闭菜单
document.addEventListener('click', (e) => {
if (!e.target.closest('.navbar') && navLinks.classList.contains('active')) {
navLinks.classList.remove('active');
mobileMenuToggle.textContent = '☰';
}
});
</script>
</body>
</html>