From 146dedea21061d8bd7ca04e411007822bafd539b Mon Sep 17 00:00:00 2001 From: WJQSERVER Date: Tue, 18 Feb 2025 10:34:24 +0800 Subject: [PATCH] 25w14a --- CHANGELOG.md | 13 ++ DEV-VERSION | 2 +- main.go | 2 + pages/bootstrap/index.html | 341 +------------------------------------ pages/bootstrap/script.js | 84 +++++++++ pages/bootstrap/style.css | 259 ++++++++++++++++++++++++++++ pages/nebula/index.html | 310 +-------------------------------- pages/nebula/script.js | 131 ++++++++++++++ pages/nebula/style.css | 157 +++++++++++++++++ 9 files changed, 651 insertions(+), 648 deletions(-) create mode 100644 pages/bootstrap/script.js create mode 100644 pages/bootstrap/style.css create mode 100644 pages/nebula/script.js create mode 100644 pages/nebula/style.css diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f57a7c..ec95b6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # 更新日志 +25w14a +--- +- PRE-RELEASE: 此版本是v2.3.0的预发布版本,请勿在生产环境中使用; +- CHANGE: 使用`touka-httpc`封装`HTTP Client`, 更新到`v0.2.0`版本, 参看`touka-httpc` +- CHANGE: 重构前端页面, 见[#49](https://github.com/WJQSERVER-STUDIO/ghproxy/pull/49) +- CHANGE: 重构`blacklist`实现 +- CHANGE: 优化404处理 +- CHANGE: 重构`whitelist`实现 +- CHANGE: 对`proxy`进行结构性调整 +- CHANGE: `chunckedreq`与`gitreq`共用`BufferPool`和`HTTP Client` +- CHANGE: 新增`HTTP Client`配置块 +- CHANGE: 加入内置主题配置, 支持通过配置切换主题 + 25w14t-2 --- - PRE-RELEASE: 此版本是测试验证版本,请勿在生产环境中使用; diff --git a/DEV-VERSION b/DEV-VERSION index b0f9cf0..678daff 100644 --- a/DEV-VERSION +++ b/DEV-VERSION @@ -1 +1 @@ -25w14t-2 \ No newline at end of file +25w14a \ No newline at end of file diff --git a/main.go b/main.go index 863caa6..cc2eecc 100644 --- a/main.go +++ b/main.go @@ -181,6 +181,8 @@ func init() { } router.GET("/", gin.WrapH(http.FileServer(http.FS(pages)))) router.GET("/favicon.ico", gin.WrapH(http.FileServer(http.FS(pages)))) + router.GET("/script.js", gin.WrapH(http.FileServer(http.FS(pages)))) + router.GET("/style.css", gin.WrapH(http.FileServer(http.FS(pages)))) } router.NoRoute(func(c *gin.Context) { diff --git a/pages/bootstrap/index.html b/pages/bootstrap/index.html index 066332a..b785d42 100644 --- a/pages/bootstrap/index.html +++ b/pages/bootstrap/index.html @@ -8,259 +8,7 @@ - + @@ -349,92 +97,7 @@
- + \ No newline at end of file diff --git a/pages/bootstrap/script.js b/pages/bootstrap/script.js new file mode 100644 index 0000000..a1c333e --- /dev/null +++ b/pages/bootstrap/script.js @@ -0,0 +1,84 @@ +const githubForm = document.getElementById('github-form'); +const githubLinkInput = document.getElementById('githubLinkInput'); +const formattedLinkOutput = document.getElementById('formattedLinkOutput'); +const output = document.getElementById('output'); +const copyButton = document.getElementById('copyButton'); +const openButton = document.getElementById('openButton'); +const toast = new bootstrap.Toast(document.getElementById('toast')); + +function showToast(message) { + const toastBody = document.querySelector('.toast-body'); + toastBody.textContent = message; + toast.show(); +} + +function formatGithubLink(githubLink) { + const currentHost = window.location.host; + let formattedLink = ""; + + if (githubLink.startsWith("https://github.com/") || githubLink.startsWith("http://github.com/")) { + formattedLink = window.location.protocol + "//" + currentHost + "/github.com" + githubLink.substring(githubLink.indexOf("/", 8)); + } else if (githubLink.startsWith("github.com/")) { + formattedLink = window.location.protocol + "//" + currentHost + "/" + githubLink; + } else if (githubLink.startsWith("https://raw.githubusercontent.com/") || githubLink.startsWith("http://raw.githubusercontent.com/")) { + formattedLink = window.location.protocol + "//" + currentHost + githubLink.substring(githubLink.indexOf("/", 7)); + } else if (githubLink.startsWith("raw.githubusercontent.com/")) { + formattedLink = window.location.protocol + "//" + currentHost + "/" + githubLink; + } else if (githubLink.startsWith("https://gist.githubusercontent.com/") || githubLink.startsWith("http://gist.githubusercontent.com/")) { + formattedLink = window.location.protocol + "//" + currentHost + "/gist.github.com" + githubLink.substring(githubLink.indexOf("/", 18)); + } else if (githubLink.startsWith("gist.githubusercontent.com/")) { + formattedLink = window.location.protocol + "//" + currentHost + "/" + githubLink; + } else { + showToast('请输入有效的GitHub链接'); + return null; + } + + return formattedLink; +} + +githubForm.addEventListener('submit', function (e) { + e.preventDefault(); + const formattedLink = formatGithubLink(githubLinkInput.value); + if (formattedLink) { + formattedLinkOutput.textContent = formattedLink; + output.style.display = 'block'; + } +}); + +copyButton.addEventListener('click', function () { + navigator.clipboard.writeText(formattedLinkOutput.textContent).then(() => { + showToast('链接已复制到剪贴板'); + }); +}); + +openButton.addEventListener('click', function () { + window.open(formattedLinkOutput.textContent, '_blank'); +}); + +function fetchAPI() { + fetch('/api/size_limit') + .then(response => response.json()) + .then(data => { + document.getElementById('sizeLimitDisplay').textContent = `${data.MaxResponseBodySize} MB`; + }); + + fetch('/api/whitelist/status') + .then(response => response.json()) + .then(data => { + document.getElementById('whiteListStatus').textContent = data.Whitelist ? '已开启' : '已关闭'; + }); + + fetch('/api/blacklist/status') + .then(response => response.json()) + .then(data => { + document.getElementById('blackListStatus').textContent = data.Blacklist ? '已开启' : '已关闭'; + }); + + fetch('/api/version') + .then(response => response.json()) + .then(data => { + document.getElementById('versionBadge').textContent = data.Version; + }); +} + +document.addEventListener('DOMContentLoaded', fetchAPI); \ No newline at end of file diff --git a/pages/bootstrap/style.css b/pages/bootstrap/style.css new file mode 100644 index 0000000..c6e7041 --- /dev/null +++ b/pages/bootstrap/style.css @@ -0,0 +1,259 @@ + /* 通用样式 */ + :root { + --primary-color: #007aff; + /* 主要按钮颜色 */ + --secondary-color: #34c759; + /* 次要按钮颜色 */ + --background-color: #f9f9f9; + /* 亮色模式背景 */ + --card-background: #ffffff; + /* 卡片背景 */ + --text-color: #333333; + /* 亮色模式文本颜色 */ + --border-color: #e0e0e0; + /* 边框颜色 */ + --input-background: #ffffff; + /* 输入框背景 */ + --input-border: #d1d1d6; + /* 输入框边框 */ + --pre-background: #f1f3f4; + /* 代码块背景 */ + --pre-text-color: #333333; + /* 代码块文本颜色 */ + --version-badge-hover: #39c5bb; + /* 说明文字颜色 */ + --muted-text-color: #6c757d; + } + + body { + background-color: var(--background-color); + color: var(--text-color); + font-family: sans-serif; + line-height: 1.8; + font-size: 15px; + margin: 0; + padding: 0; + } + + h1, + h2, + h3, + h4, + h5, + h6 { + color: var(--text-color); + font-weight: 800; + letter-spacing: 0.5px; + margin: 1rem 0; + } + + p, + span, + a, + li { + color: var(--text-color); + margin-bottom: 1rem; + } + + a { + text-decoration: none; + color: var(--primary-color); + } + + a:hover { + color: #0056b3; + } + + .card { + background-color: var(--card-background); + border: 1px solid var(--border-color); + border-radius: 8px; + padding: 16px; + margin: 16px 0; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + transition: transform 0.2s, box-shadow 0.2s; + } + + .card:hover { + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); + transform: translateY(-4px); + } + + .btn-outline-secondary { + border-radius: 50%; + padding: 6px; + transition: #e9e9e9 0.3s ease-in-out, color 0.3s ease-in-out; + } + + .btn-outline-secondary:hover { + background-color: var(--primary-color); + color: white; + } + + .form-control { + background-color: var(--input-background); + border: 1px solid var(--input-border); + color: var(--text-color); + padding: 10px; + border-radius: 4px; + font-size: 14px; + outline: none; + transition: border-color 0.2s, box-shadow 0.2s; + } + + .form-control:focus { + border-color: var(--primary-color); + box-shadow: 0 0 0 3px rgba(10, 132, 255, 0.3); + } + + .text-muted { + color: var(--muted-text-color) !important; + } + + .bg-light { + background-color: var(--card-background) !important; + } + + pre { + background-color: var(--pre-background); + color: var(--pre-text-color); + padding: 16px; + border-radius: 8px; + overflow-x: auto; + font-size: 14px; + line-height: 1.6; + } + + .version-badge { + position: fixed; + bottom: 20px; + right: 20px; + background-color: var(--secondary-color); + color: white; + padding: 6px 12px; + border-radius: 20px; + font-size: 0.8rem; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + transition: background-color 0.3s ease-in-out; + } + + .version-badge:hover { + background-color: var(--version-badge-hover); + } + + footer { + padding: 16px; + text-align: center; + color: var(--text-color); + font-size: 0.9rem; + background-color: var(--card-background); + } + + footer a { + color: var(--primary-color); + } + + footer a:hover { + color: #0056b3; + } + + /* 暗色模式 */ + @media (prefers-color-scheme: dark) { + :root { + --background-color: #121212; + /* 深灰色背景 */ + --card-background: #1e1e1e; + /* 卡片背景稍浅 */ + --text-color: #ffffff; + /* 纯白文本 */ + --primary-color: #0a84ff; + /* 按钮蓝色 */ + --secondary-color: #30d158; + /* 次要按钮绿色 */ + --border-color: #3a3a3a; + /* 边框颜色 */ + --input-background: #2c2c2c; + /* 输入框背景 */ + --input-border: #4a4a4a; + /* 输入框边框 */ + --pre-background: #3b3636; + /* 代码块背景 */ + --pre-text-color: #ffffff; + /* 代码块文本颜色 */ + --version-badge-hover: #39c5bc9a; + /* 说明文字颜色 */ + --muted-text-color: #a0a0a0; + } + + body { + background-color: var(--background-color); + color: var(--text-color); + } + + h1, + h2, + h3, + h4, + h5, + h6, + p, + span, + a, + li { + color: var(--text-color); + } + + .card { + background-color: var(--card-background); + color: var(--text-color); + border: 1px solid var(--border-color); + } + + .btn-outline-secondary { + border-radius: 50%; + padding: 6px; + transition: background-color 0.3s ease-in-out, color 0.3s ease-in-out; + } + + .btn-outline-secondary:hover { + background-color: var(--primary-color); + color: white; + } + + .toast { + background-color: var(--card-background); + color: var(--text-color); + border: 1px solid var(--border-color); + border-radius: 8px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + } + + .toast-body { + padding: 12px; + } + + + .form-control { + background-color: var(--input-background); + border: 1px solid var(--input-border); + color: var(--text-color); + } + + .bg-light { + background-color: var(--card-background) !important; + } + + pre { + background-color: var(--pre-background); + color: var(--pre-text-color); + } + + footer { + background-color: var(--card-background); + color: var(--text-color); + } + + footer a { + color: var(--primary-color); + } + } \ No newline at end of file diff --git a/pages/nebula/index.html b/pages/nebula/index.html index 466700f..f01a39a 100644 --- a/pages/nebula/index.html +++ b/pages/nebula/index.html @@ -6,174 +6,15 @@ GitHub加速服务 - +
-

GitHub加速服务

高速稳定的 GitHub 资源访问解决方案

- -
@@ -201,8 +42,6 @@
- -
@@ -238,8 +77,6 @@
- -

📚 详细使用指南

@@ -253,7 +90,6 @@
  • ❌ 不支持 SSH Git Clone
  • -

    基础用法示例

    @@ -273,10 +109,8 @@ class="d-block">curl -LO https://example.com/https://github.com/user/project/releases/download/v1.0.0/project_1.0.0.amd64.tar.gz
    -

    支持的文件类型

    -
    @@ -285,14 +119,12 @@ class="d-block text-muted fs-sm">https://raw.githubusercontent.com/user/repo/main/file.txt
    -

    分支源码

    https://github.com/user/repo/archive/main.zip
    -

    版本发布

    @@ -300,7 +132,6 @@ class="d-block text-muted fs-sm">https://github.com/user/repo/releases/download/v1.0.0/app.zip
    -

    Gist 文件

    @@ -308,7 +139,6 @@ class="d-block text-muted fs-sm">https://gist.githubusercontent.com/user/gist_id/raw/file.txt
    -

    HTTPS Git Clone

    @@ -318,7 +148,6 @@
    -

    v

    Copyright © 2024 - WJQSERVER-STUDIO
    @@ -327,148 +156,13 @@

    - -
    - - + \ No newline at end of file diff --git a/pages/nebula/script.js b/pages/nebula/script.js new file mode 100644 index 0000000..4516f9c --- /dev/null +++ b/pages/nebula/script.js @@ -0,0 +1,131 @@ +(() => { + 'use strict'; + + // 初始化基础配置 + const currentYear = new Date().getFullYear(); + document.getElementById('currentYear').textContent = currentYear; + const toast = new bootstrap.Toast('#liveToast'); + + // DOM 元素 + const form = document.getElementById('mainForm'); + const input = document.getElementById('inputUrl'); + const output = document.getElementById('output'); + const outputLink = document.getElementById('outputLink'); + + // 获取当前域名 + const CURRENT_PROTOCOL = window.location.protocol.replace(':', ''); + const CURRENT_HOST = window.location.host; + // 替换协议部分 + document.querySelectorAll('code .protocol').forEach(span => { + span.textContent = CURRENT_PROTOCOL; + }); + // 替换域名部分 + document.querySelectorAll('code .host').forEach(span => { + span.textContent = CURRENT_HOST; + }); + + // URL 转换规则 + const URL_RULES = [ + { + regex: /^(?:https?:\/\/)?(?:www\.)?(github\.com\/.*)/i, + build: path => `${location.protocol}//${location.host}/${path}` + }, + { + regex: /^(?:https?:\/\/)?(raw\.githubusercontent\.com\/.*)/i, + build: path => `${location.protocol}//${location.host}/${path}` + }, + { + regex: /^(?:https?:\/\/)?(gist\.(?:githubusercontent|github)\.com\/.*)/i, + build: path => `${location.protocol}//${location.host}/${path}` + } + ]; + + // 核心功能:链接转换 + function transformGitHubURL(url) { + const cleanURL = url.trim().replace(/^https?:\/\//i, ''); + for (const rule of URL_RULES) { + const match = cleanURL.match(rule.regex); + if (match) return rule.build(match[1]); + } + return null; + } + + // 事件处理 + form.addEventListener('submit', e => { + e.preventDefault(); + + if (!input.checkValidity()) { + input.classList.add('is-invalid'); + showToast('⚠️ 请输入有效的 GitHub 链接'); + return; + } + + const result = transformGitHubURL(input.value); + if (!result) { + showToast('❌ 不支持的链接格式'); + return; + } + + outputLink.textContent = result; + output.hidden = false; + window.scrollTo({ top: output.offsetTop - 100, behavior: 'smooth' }); + }); + + document.getElementById('copyBtn').addEventListener('click', async () => { + try { + await navigator.clipboard.writeText(outputLink.textContent); + showToast('✅ 链接已复制'); + } catch { + showToast('❌ 复制失败'); + } + }); + + document.getElementById('openBtn').addEventListener('click', () => { + window.open(outputLink.textContent, '_blank', 'noopener,noreferrer'); + }); + + // 服务状态监控 + async function loadServiceStatus() { + try { + const [size, whitelist, blacklist, version] = await Promise.all([ + fetchJSON('/api/size_limit'), + fetchJSON('/api/whitelist/status'), + fetchJSON('/api/blacklist/status'), + fetchJSON('/api/version') + ]); + + updateStatus('sizeLimit', `${size.MaxResponseBodySize}MB`); + updateStatus('whitelistStatus', whitelist.Whitelist ? '已开启' : '已关闭'); + updateStatus('blacklistStatus', blacklist.Blacklist ? '已开启' : '已关闭'); + updateStatus('version', `Version ${version.Version}`); + } catch { + showToast('⚠️ 服务状态获取失败'); + } + } + + async function fetchJSON(url) { + const response = await fetch(url); + if (!response.ok) throw new Error('API Error'); + return response.json(); + } + + function updateStatus(elementId, text) { + const element = document.getElementById(elementId); + if (element) element.textContent = text; + } + + // 工具函数 + function showToast(message) { + const toastBody = document.querySelector('.toast-body'); + toastBody.textContent = message; + toast.show(); + } + + // 初始化 + input.addEventListener('input', () => { + input.classList.remove('is-invalid'); + if (output.hidden === false) output.hidden = true; + }); + + loadServiceStatus(); +})(); \ No newline at end of file diff --git a/pages/nebula/style.css b/pages/nebula/style.css new file mode 100644 index 0000000..81f40a8 --- /dev/null +++ b/pages/nebula/style.css @@ -0,0 +1,157 @@ +:root { + --primary: #007aff; + --secondary: #007aff; + --background: #f9f9f9; + --card-bg: #ffffff; + --text: #333333; + --border: #d1d1d6; + --muted: #64748b; + --success: #00a83ed2; + --danger: #ce0000dd; +} + +@media (prefers-color-scheme: dark) { + :root { + --background: #121212; + --card-bg: #1e1e1e; + --text: #ffffff; + --border: #334155; + --muted: #94a3b8; + } + + .form-control::placeholder { + color: var(--muted); + } + + .text-muted { + color: var(--muted) !important; + } + + .btn-outline-secondary { + color: var(--muted); + border-color: var(--border); + } + + .status-badge { + color: var(--text) !important; + } + + .code-block { + background: rgba(255, 255, 255, 0.05); + } + + .command-example { + background: rgba(255, 255, 255, 0.03); + } + + .btn-primary { + --bs-btn-bg: var(--primary); + --bs-btn-border-color: var(--primary); + --bs-btn-hover-bg: var(--secondary); + --bs-btn-hover-border-color: var(--secondary); + } + + .form-control { + background-color: rgba(255, 255, 255, 0.05); + border-color: var(--border); + color: var(--text); + } + + a { + color: var(--secondary); + } +} + +body { + background: var(--background); + color: var(--text); + font-family: 'Inter', system-ui, sans-serif; + line-height: 1.6; +} + +.main-card { + background: var(--card-bg); + border: 1px solid var(--border); + border-radius: 12px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); + transition: transform 0.2s, box-shadow 0.2s; +} + +.main-card:hover { + transform: translateY(-2px); + box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1); +} + +.code-block { + background: rgba(37, 99, 235, 0.05); + border-left: 3px solid var(--primary); + border-radius: 6px; + padding: 1rem; + position: relative; + overflow-x: auto; +} + +.status-badge { + padding: 6px 12px; + border-radius: 20px; + font-size: 0.9rem; + font-weight: 500; +} + +.guide-section { + border-left: 3px solid var(--primary); + padding-left: 1rem; + margin: 2rem 0; +} + +.command-example { + position: relative; + padding: 1.25rem; + background: rgba(37, 99, 235, 0.03); + border-radius: 8px; + margin: 1rem 0; +} + +.command-example::before { + content: "➜"; + position: absolute; + left: -1.5rem; + color: var(--muted); +} + +.toast { + position: fixed; + top: 1%; + right: 1%; + background-color: var(--card-background); + color: var(--text-color); + border: 1px solid var(--border-color); + border-radius: 8px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); +} + +.toast-body { + padding: 12px; +} + +#version { + text-align: center; + font-size: 13px; + line-height: 26px; + color: #747474; +} + +.bg-primary { + --bs-bg-opacity: 1; + background-color: #2c82de !important; +} + +.bg-success { + --bs-bg-opacity: 1; + background-color: #2c82de !important; +} + +.bg-danger { + --bs-bg-opacity: 1; + background-color: #2c82de !important; +} \ No newline at end of file