mirror of
https://github.com/justhtmls/html-tools.git
synced 2026-09-01 15:32:50 +08:00
feat: add pwa and cdn fallback
This commit is contained in:
+2
-2
@@ -6,7 +6,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>贡献指南 - JustHTMLs</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/CONTRIBUTING.html">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" onerror="this.onerror=null;this.href='/assets/vendor/fontawesome/css/all.min.css';">
|
||||
<style>
|
||||
:root {
|
||||
--primary: #6366f1;
|
||||
@@ -233,7 +233,7 @@
|
||||
<ul>
|
||||
<li><strong>单文件 HTML</strong> - 所有 HTML、CSS 和 JavaScript 都在一个文件中</li>
|
||||
<li><strong>无构建步骤</strong> - 不使用 React、JSX 或需要编译的技术</li>
|
||||
<li><strong>CDN 依赖</strong> - 如需第三方库,从 CDN 加载</li>
|
||||
<li><strong>本地依赖</strong> - 第三方库放入 assets/vendor,并提供 CDN 回退</li>
|
||||
<li><strong>保持精简</strong> - 代码量控制在几百行以内,便于维护和理解</li>
|
||||
<li><strong>隐私优先</strong> - 数据在浏览器本地处理,不发送到服务器</li>
|
||||
</ul>
|
||||
|
||||
+9
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+3225
File diff suppressed because it is too large
Load Diff
+4049
File diff suppressed because it is too large
Load Diff
Vendored
+1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+8
-1
@@ -20,6 +20,7 @@
|
||||
<meta property="twitter:description" content="JustHTMLs 是一个开源的 HTML 工具集平台,汇集各种轻量级的在线工具,无需安装,即开即用。">
|
||||
|
||||
<link rel="icon" href="/favicon.svg">
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
|
||||
<!-- Structured Data (JSON-LD) -->
|
||||
<script type="application/ld+json">
|
||||
@@ -66,7 +67,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" onerror="this.onerror=null;this.href='/assets/vendor/fontawesome/css/all.min.css';">
|
||||
<style>
|
||||
:root {
|
||||
--primary: #6366f1;
|
||||
@@ -926,6 +927,12 @@
|
||||
// Initialize
|
||||
loadHomeStats();
|
||||
loadTools();
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
window.addEventListener('load', () => {
|
||||
navigator.serviceWorker.register('/service-worker.js').catch(() => {});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<script src="/assets/clicks.js" defer></script>
|
||||
</body>
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "JustHTMLs - 开源 HTML 工具集",
|
||||
"short_name": "JustHTMLs",
|
||||
"start_url": "/",
|
||||
"display": "standalone",
|
||||
"background_color": "#0f172a",
|
||||
"theme_color": "#0f172a",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/favicon.svg",
|
||||
"sizes": "any",
|
||||
"type": "image/svg+xml"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -25,7 +25,8 @@ JustHTMLs 是一个开源的 HTML 工具集平台,汇集各种轻量级的在
|
||||
- **单文件设计** - 所有工具都是独立的 HTML 文件,内联 CSS 和 JavaScript
|
||||
- **无需构建** - 不使用 React/JSX,直接从浏览器打开
|
||||
- **隐私优先** - 数据在本地处理,不发送到服务器
|
||||
- **CDN 依赖** - 第三方库从 CDN 加载,无需 npm
|
||||
- **本地依赖** - 第三方库放入 assets/vendor,离线可用
|
||||
- **可选 CDN** - CDN 优先,失败自动回退到本地资源
|
||||
- **开源免费** - MIT 许可证,欢迎贡献
|
||||
|
||||
---
|
||||
@@ -99,7 +100,7 @@ tools/
|
||||
|
||||
- 单文件 HTML,内联 CSS/JS
|
||||
- 不使用 React 或需要构建的技术
|
||||
- 从 CDN 加载第三方库
|
||||
- 从本地 assets/vendor 加载第三方库
|
||||
- 保持精简(建议 500 行以内)
|
||||
- 数据本地处理,保护隐私
|
||||
|
||||
|
||||
+5
-5
@@ -214,15 +214,15 @@
|
||||
<div class="feature-icon">⚡</div>
|
||||
<div class="feature-content">
|
||||
<h4>避免 React</h4>
|
||||
<p>使用纯 JavaScript 或从 CDN 加载轻量级框架,更快的渲染和更少的 Bug</p>
|
||||
<p>使用纯 JavaScript 或 CDN 加载轻量级框架,失败时回退到本地资源</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="feature-item">
|
||||
<div class="feature-icon">📦</div>
|
||||
<div class="feature-content">
|
||||
<h4>CDN 依赖</h4>
|
||||
<p>使用 cdnjs 或 jsDelivr 加载第三方库,使用带版本号的 URL 确保稳定性</p>
|
||||
<h4>本地依赖</h4>
|
||||
<p>第三方库放在 assets/vendor 并随仓库分发,适合离线环境</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -396,7 +396,7 @@ tools/
|
||||
<ul style="margin-left: 20px; margin-top: 15px;">
|
||||
<li>单文件 HTML,内联 CSS/JS</li>
|
||||
<li>不使用 React 或需要构建的技术</li>
|
||||
<li>从 CDN 加载第三方库</li>
|
||||
<li>从本地 assets/vendor 加载第三方库</li>
|
||||
<li>保持精简(建议 500 行以内)</li>
|
||||
<li>数据本地处理,保护隐私</li>
|
||||
</ul>
|
||||
@@ -405,7 +405,7 @@ tools/
|
||||
<div class="code-block">
|
||||
Build an HTML tool that [描述功能需求].
|
||||
No React.
|
||||
Use [特定库名] from CDN if needed.
|
||||
Use [特定库名] from CDN with local fallback if needed.
|
||||
Include [特定功能要求].
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
const CACHE_NAME = 'justhtmls-v1';
|
||||
const PRECACHE_URLS = [
|
||||
'/',
|
||||
'/index.html',
|
||||
'/index.json',
|
||||
'/favicon.svg',
|
||||
'/assets/vendor/fontawesome/css/all.min.css',
|
||||
];
|
||||
|
||||
const CACHE_FIRST_PATHS = [
|
||||
'/assets/vendor/',
|
||||
'/tools/',
|
||||
];
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
event.waitUntil(
|
||||
caches.open(CACHE_NAME).then((cache) => cache.addAll(PRECACHE_URLS))
|
||||
);
|
||||
self.skipWaiting();
|
||||
});
|
||||
|
||||
self.addEventListener('activate', (event) => {
|
||||
event.waitUntil(
|
||||
caches.keys().then((keys) =>
|
||||
Promise.all(
|
||||
keys
|
||||
.filter((key) => key !== CACHE_NAME)
|
||||
.map((key) => caches.delete(key))
|
||||
)
|
||||
)
|
||||
);
|
||||
self.clients.claim();
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', (event) => {
|
||||
const { request } = event;
|
||||
if (request.method !== 'GET' || new URL(request.url).origin !== self.location.origin) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.mode === 'navigate') {
|
||||
event.respondWith(
|
||||
fetch(request)
|
||||
.then((response) => {
|
||||
const copy = response.clone();
|
||||
caches.open(CACHE_NAME).then((cache) => cache.put(request, copy));
|
||||
return response;
|
||||
})
|
||||
.catch(() => caches.match('/index.html'))
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const { pathname } = new URL(request.url);
|
||||
if (CACHE_FIRST_PATHS.some((path) => pathname.startsWith(path))) {
|
||||
event.respondWith(
|
||||
caches.match(request).then((cached) => {
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
return fetch(request).then((response) => {
|
||||
const copy = response.clone();
|
||||
caches.open(CACHE_NAME).then((cache) => cache.put(request, copy));
|
||||
return response;
|
||||
});
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
event.respondWith(
|
||||
caches.match(request).then((cached) => {
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
return fetch(request).then((response) => {
|
||||
const copy = response.clone();
|
||||
caches.open(CACHE_NAME).then((cache) => cache.put(request, copy));
|
||||
return response;
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -6,7 +6,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Base64 编码解码 - JustHTMLs</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/base64-encode/">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" onerror="this.onerror=null;this.href='/assets/vendor/fontawesome/css/all.min.css';">
|
||||
<style>
|
||||
:root {
|
||||
--primary: #f093fb;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>颜色选择器 - JustHTMLs</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/color-picker/">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" onerror="this.onerror=null;this.href='/assets/vendor/fontawesome/css/all.min.css';">
|
||||
<style>
|
||||
:root {
|
||||
--primary: #ff6b6b;
|
||||
|
||||
@@ -205,7 +205,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/js-beautify@1.15.1/js/lib/beautify-html.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/js-beautify@1.15.1/js/lib/beautify-html.js" onerror="this.onerror=null;this.src='/assets/vendor/js-beautify/beautify-html.js';"></script>
|
||||
|
||||
<script>
|
||||
const input = document.getElementById('input');
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/js-beautify@1.15.1/js/lib/beautify.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/js-beautify@1.15.1/js/lib/beautify.js" onerror="this.onerror=null;this.src='/assets/vendor/js-beautify/beautify.js';"></script>
|
||||
|
||||
<script>
|
||||
const input = document.getElementById('input');
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>JSON 转 YAML - JustHTMLs</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/json-to-yaml/">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" onerror="this.onerror=null;this.href='/assets/vendor/fontawesome/css/all.min.css';">
|
||||
<style>
|
||||
:root {
|
||||
--primary: #6366f1;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>安全密码生成器 - JustHTMLs</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/password-generator/">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" onerror="this.onerror=null;this.href='/assets/vendor/fontawesome/css/all.min.css';">
|
||||
<style>
|
||||
:root {
|
||||
--primary: #667eea;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>二维码生成器</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/qr-generator/app.html">
|
||||
<script src="https://cdn.jsdelivr.net/npm/qrcodejs@1.0.0/qrcode.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/qrcodejs@1.0.0/qrcode.min.js" onerror="this.onerror=null;this.src='/assets/vendor/qrcodejs/qrcode.min.js';"></script>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>二维码生成器 - JustHTMLs</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/qr-generator/">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" onerror="this.onerror=null;this.href='/assets/vendor/fontawesome/css/all.min.css';">
|
||||
<style>
|
||||
:root {
|
||||
--primary: #10b981;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>正则表达式测试器 - JustHTMLs</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/regex-tester/">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" onerror="this.onerror=null;this.href='/assets/vendor/fontawesome/css/all.min.css';">
|
||||
<style>
|
||||
:root {
|
||||
--primary: #a855f7;
|
||||
|
||||
@@ -204,7 +204,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/sql-formatter@15.4.3/dist/sql-formatter.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/sql-formatter@15.4.3/dist/sql-formatter.min.js" onerror="this.onerror=null;this.src='/assets/vendor/sql-formatter/sql-formatter.min.js';"></script>
|
||||
|
||||
<script>
|
||||
const input = document.getElementById('input');
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>URL 编码解码 - JustHTMLs</title>
|
||||
<link rel="canonical" href="https://www.htmls.dev/tools/url-encode/">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" onerror="this.onerror=null;this.href='/assets/vendor/fontawesome/css/all.min.css';">
|
||||
<style>
|
||||
:root {
|
||||
--primary: #06b6d4;
|
||||
|
||||
Reference in New Issue
Block a user