Skip to content

Commit 0dabce9

Browse files
beihailiclaude
andcommitted
feat: add service worker for offline support and SEO enhancements
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent a497ae3 commit 0dabce9

4 files changed

Lines changed: 129 additions & 6 deletions

File tree

index.html

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,47 @@
1818
<meta property="og:url" content="https://beihaili.github.io/Get-Started-with-Web3/">
1919
<meta property="og:site_name" content="Get Started With Web3">
2020
<meta property="og:locale" content="zh_CN">
21+
<meta property="og:image" content="https://beihaili.github.io/Get-Started-with-Web3/logo.png">
22+
<meta property="og:image:width" content="512">
23+
<meta property="og:image:height" content="512">
2124

2225
<!-- Twitter Card -->
2326
<meta name="twitter:card" content="summary_large_image">
2427
<meta name="twitter:site" content="@bhbtc1337">
2528
<meta name="twitter:title" content="Get Started With Web3 - Web3区块链入门教程">
2629
<meta name="twitter:description" content="开源Web3教育平台,系统化学习Web3和比特币技术">
30+
<meta name="twitter:image" content="https://beihaili.github.io/Get-Started-with-Web3/logo.png">
31+
32+
<!-- JSON-LD 结构化数据 -->
33+
<script type="application/ld+json">
34+
{
35+
"@context": "https://schema.org",
36+
"@type": "Course",
37+
"name": "Get Started With Web3",
38+
"description": "开源Web3教育平台,系统化学习Web3和比特币技术。包含21讲比特币技术课程和6讲Web3快速入门。",
39+
"provider": {
40+
"@type": "Organization",
41+
"name": "Get Started With Web3",
42+
"url": "https://beihaili.github.io/Get-Started-with-Web3/"
43+
},
44+
"inLanguage": "zh-CN",
45+
"isAccessibleForFree": true,
46+
"url": "https://beihaili.github.io/Get-Started-with-Web3/",
47+
"image": "https://beihaili.github.io/Get-Started-with-Web3/logo.png",
48+
"hasCourseInstance": [
49+
{
50+
"@type": "CourseInstance",
51+
"name": "Web3 快速入门",
52+
"courseMode": "online"
53+
},
54+
{
55+
"@type": "CourseInstance",
56+
"name": "比特币技术深度解析",
57+
"courseMode": "online"
58+
}
59+
]
60+
}
61+
</script>
2762

2863
<!-- Favicon -->
2964
<link rel="icon" type="image/svg+xml" href="/Get-Started-with-Web3/favicon.svg">

public/manifest.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,19 @@
2929
"type": "image/png",
3030
"purpose": "any"
3131
}
32+
],
33+
"shortcuts": [
34+
{
35+
"name": "开始学习",
36+
"short_name": "学习",
37+
"url": "/Get-Started-with-Web3/dashboard",
38+
"description": "进入课程仪表板"
39+
},
40+
{
41+
"name": "我的徽章",
42+
"short_name": "徽章",
43+
"url": "/Get-Started-with-Web3/badges",
44+
"description": "查看学习成就和徽章"
45+
}
3246
]
3347
}

public/sw.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
const CACHE_VERSION = 'web3-starter-v1';
2+
const APP_SHELL = [
3+
'/Get-Started-with-Web3/',
4+
'/Get-Started-with-Web3/index.html',
5+
'/Get-Started-with-Web3/favicon.svg',
6+
'/Get-Started-with-Web3/logo-192.png',
7+
];
8+
9+
// Install: pre-cache app shell
10+
self.addEventListener('install', (event) => {
11+
event.waitUntil(
12+
caches.open(CACHE_VERSION).then((cache) => cache.addAll(APP_SHELL))
13+
);
14+
self.skipWaiting();
15+
});
16+
17+
// Activate: clean old caches
18+
self.addEventListener('activate', (event) => {
19+
event.waitUntil(
20+
caches.keys().then((keys) =>
21+
Promise.all(
22+
keys
23+
.filter((key) => key !== CACHE_VERSION)
24+
.map((key) => caches.delete(key))
25+
)
26+
)
27+
);
28+
self.clients.claim();
29+
});
30+
31+
// Fetch: content paths use cache-first, others use network-first
32+
self.addEventListener('fetch', (event) => {
33+
const url = new URL(event.request.url);
34+
35+
// Cache-first for content (markdown tutorials)
36+
if (url.pathname.includes('/content/')) {
37+
event.respondWith(
38+
caches.match(event.request).then(
39+
(cached) =>
40+
cached ||
41+
fetch(event.request).then((response) => {
42+
if (response.ok) {
43+
const clone = response.clone();
44+
caches.open(CACHE_VERSION).then((cache) => cache.put(event.request, clone));
45+
}
46+
return response;
47+
})
48+
)
49+
);
50+
return;
51+
}
52+
53+
// Network-first for everything else
54+
event.respondWith(
55+
fetch(event.request)
56+
.then((response) => {
57+
if (response.ok && event.request.method === 'GET') {
58+
const clone = response.clone();
59+
caches.open(CACHE_VERSION).then((cache) => cache.put(event.request, clone));
60+
}
61+
return response;
62+
})
63+
.catch(() => caches.match(event.request))
64+
);
65+
});

src/main.jsx

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
1-
import React from 'react'
2-
import ReactDOM from 'react-dom/client'
3-
import App from './App.jsx'
4-
import './index.css'
1+
import React from 'react';
2+
import ReactDOM from 'react-dom/client';
3+
import App from './App.jsx';
4+
import './index.css';
55

66
ReactDOM.createRoot(document.getElementById('root')).render(
77
<React.StrictMode>
88
<App />
9-
</React.StrictMode>,
10-
)
9+
</React.StrictMode>
10+
);
11+
12+
// Register service worker
13+
if ('serviceWorker' in navigator) {
14+
window.addEventListener('load', () => {
15+
navigator.serviceWorker.register('/Get-Started-with-Web3/sw.js').catch(() => {
16+
// SW registration failed silently — app works without it
17+
});
18+
});
19+
}

0 commit comments

Comments
 (0)