chore: sync project updates

This commit is contained in:
root
2026-03-11 21:15:06 +08:00
parent 5a56af2ce8
commit f1b4dfc44e
35 changed files with 20688 additions and 20031 deletions

View File

@@ -1,16 +1,51 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#90EE90" />
<meta name="description" content="萌芽密码管理器" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo.png" />
<title>萌芽密码管理器</title>
</head>
<body>
<noscript>您需要启用JavaScript才能运行此应用程序。</noscript>
<div id="root"></div>
</body>
</html>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<!-- 图标 -->
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo.png" />
<!-- 视口 & 主题色 -->
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta name="theme-color" content="#4caf50" />
<!-- SEO & 描述 -->
<meta name="description" content="萌芽密码管理器 - 安全、便捷的个人密码管理工具" />
<meta name="keywords" content="密码管理器,密码,安全,萌芽" />
<meta name="author" content="萌芽密码管理器" />
<!-- PWA: Manifest -->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!-- iOS PWA 支持 -->
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="apple-mobile-web-app-title" content="萌芽密码" />
<!-- Android PWA / Chrome -->
<meta name="mobile-web-app-capable" content="yes" />
<meta name="application-name" content="萌芽密码" />
<!-- Windows 磁贴 -->
<meta name="msapplication-TileColor" content="#4caf50" />
<meta name="msapplication-TileImage" content="%PUBLIC_URL%/logo.png" />
<meta name="msapplication-tap-highlight" content="no" />
<!-- 禁止自动识别电话号码 -->
<meta name="format-detection" content="telephone=no" />
<!-- Open Graph -->
<meta property="og:title" content="萌芽密码管理器" />
<meta property="og:description" content="安全、便捷的个人密码管理工具" />
<meta property="og:image" content="%PUBLIC_URL%/logo.png" />
<meta property="og:type" content="website" />
<title>萌芽密码管理器</title>
</head>
<body>
<noscript>您需要启用JavaScript才能运行此应用程序。</noscript>
<div id="root"></div>
</body>
</html>

View File

@@ -0,0 +1,34 @@
{
"name": "萌芽密码管理器",
"short_name": "萌芽密码",
"description": "安全、便捷的个人密码管理工具",
"start_url": "/",
"display": "standalone",
"orientation": "any",
"background_color": "#f0fdf0",
"theme_color": "#4caf50",
"lang": "zh-CN",
"scope": "/",
"icons": [
{
"src": "/favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "/logo.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/logo.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}
],
"categories": ["productivity", "utilities"],
"screenshots": [],
"prefer_related_applications": false
}

View File

@@ -0,0 +1,53 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#4caf50" />
<title>离线 - 萌芽密码管理器</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
background: linear-gradient(135deg, #f0fdf0 0%, #e8f5e9 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
padding: 20px;
}
.container {
background: rgba(255,255,255,0.95);
border-radius: 24px;
padding: 48px 40px;
box-shadow: 0 8px 32px rgba(76,175,80,0.15);
max-width: 400px;
width: 100%;
}
.icon { font-size: 64px; margin-bottom: 24px; }
h1 { font-size: 22px; color: #1b5e20; margin-bottom: 12px; font-weight: 700; }
p { font-size: 15px; color: #666; line-height: 1.6; margin-bottom: 24px; }
button {
background: linear-gradient(135deg, #66bb6a, #4caf50);
color: #fff;
border: none;
border-radius: 12px;
padding: 12px 28px;
font-size: 15px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
}
button:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(76,175,80,0.4); }
</style>
</head>
<body>
<div class="container">
<div class="icon">🌱</div>
<h1>当前处于离线状态</h1>
<p>无法连接到网络,请检查您的网络连接后重试。<br>已缓存的数据仍可查看。</p>
<button onclick="window.location.reload()">重新连接</button>
</div>
</body>
</html>

View File

@@ -0,0 +1,146 @@
/* =====================================================
* 萌芽密码管理器 Service Worker
* 策略:
* - 静态资源Shell: Cache First优先缓存
* - API 请求: Network First优先网络失败时返回离线页
* - 导航请求: Network First → 回退到缓存的 index.html
* ===================================================== */
const CACHE_NAME = 'mengyakeyvault-v1';
const OFFLINE_URL = '/offline.html';
// 预缓存的应用 Shell 资源
const PRECACHE_URLS = [
'/',
'/index.html',
'/offline.html',
'/manifest.json',
'/favicon.ico',
'/logo.png',
];
// ── Install ──────────────────────────────────────────
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
return cache.addAll(PRECACHE_URLS).catch((err) => {
console.warn('[SW] 预缓存部分资源失败:', err);
});
})
);
// 强制新 SW 立即激活,不等旧 SW 退出
self.skipWaiting();
});
// ── Activate ─────────────────────────────────────────
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames
.filter((name) => name !== CACHE_NAME)
.map((name) => caches.delete(name))
);
})
);
// 立即接管所有页面
self.clients.claim();
});
// ── Fetch ─────────────────────────────────────────────
self.addEventListener('fetch', (event) => {
const { request } = event;
const url = new URL(request.url);
// 只处理 http/https忽略 chrome-extension 等
if (!url.protocol.startsWith('http')) return;
// API 请求Network First
if (url.pathname.startsWith('/api') || url.hostname.includes('keyvault.api')) {
event.respondWith(networkFirst(request));
return;
}
// 第三方资源favicon API 等Network First不缓存
if (url.hostname !== self.location.hostname) {
event.respondWith(networkOnly(request));
return;
}
// 导航请求HTML页面Network First → 回退 index.html
if (request.mode === 'navigate') {
event.respondWith(navigationHandler(request));
return;
}
// 静态资源JS/CSS/图片等Cache First
event.respondWith(cacheFirst(request));
});
// ── 策略函数 ──────────────────────────────────────────
// Cache First先查缓存没有再请求网络并写入缓存
async function cacheFirst(request) {
const cached = await caches.match(request);
if (cached) return cached;
try {
const response = await fetch(request);
if (response.ok) {
const cache = await caches.open(CACHE_NAME);
cache.put(request, response.clone());
}
return response;
} catch {
return new Response('资源暂时无法访问', { status: 503 });
}
}
// Network First先请求网络失败时查缓存
async function networkFirst(request) {
try {
const response = await fetch(request);
if (response.ok) {
const cache = await caches.open(CACHE_NAME);
cache.put(request, response.clone());
}
return response;
} catch {
const cached = await caches.match(request);
return cached || new Response(
JSON.stringify({ error: '网络不可用,请检查连接' }),
{ status: 503, headers: { 'Content-Type': 'application/json' } }
);
}
}
// Network Only仅网络不缓存
async function networkOnly(request) {
try {
return await fetch(request);
} catch {
return new Response('', { status: 503 });
}
}
// 导航处理Network First → 回退缓存的 index.html
async function navigationHandler(request) {
try {
const response = await fetch(request);
if (response.ok) {
const cache = await caches.open(CACHE_NAME);
cache.put(request, response.clone());
}
return response;
} catch {
const cached = await caches.match('/index.html');
if (cached) return cached;
return caches.match(OFFLINE_URL);
}
}
// ── 消息处理(支持主线程主动触发更新)──────────────────
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') {
self.skipWaiting();
}
});