@nextclaw/ui 0.12.7 → 0.12.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +85 -0
- package/dist/assets/ChannelsList-Ita2Zm1_.js +8 -0
- package/dist/assets/{DocBrowser-Cse_F8Nn.js → DocBrowser-6ReNjvzF.js} +1 -1
- package/dist/assets/DocBrowser-BNwbPHf4.js +1 -0
- package/dist/assets/{DocBrowserContext-Bai1WU2H.js → DocBrowserContext-B6SpA7Qs.js} +1 -1
- package/dist/assets/{LogoBadge-BdxMPc9v.js → LogoBadge-ByNLYg65.js} +1 -1
- package/dist/assets/MarketplacePage-CjX2MWww.js +1 -0
- package/dist/assets/{MarketplacePage-BbpAkllU.js → MarketplacePage-D0sDlYX4.js} +1 -1
- package/dist/assets/McpMarketplacePage-BGKJm1sJ.js +40 -0
- package/dist/assets/{ModelConfig-3GLqQ5GY.js → ModelConfig-BzZenCH-.js} +1 -1
- package/dist/assets/{ProviderScopedModelInput-BYNouw-i.js → ProviderScopedModelInput-Da7khnBA.js} +1 -1
- package/dist/assets/{ProvidersList-BR1gJ4Dm.js → ProvidersList-BbVzRxjY.js} +1 -1
- package/dist/assets/RemoteAccessPage-BaDH_X1Q.js +1 -0
- package/dist/assets/RuntimeConfig-F_XKGgLm.js +1 -0
- package/dist/assets/{SearchConfig-DTeJvp8m.js → SearchConfig-BGkzXQP-.js} +1 -1
- package/dist/assets/{SecretsConfig-CCYO6NcV.js → SecretsConfig-D281Rotl.js} +2 -2
- package/dist/assets/{SessionsConfig-Du39vDgt.js → SessionsConfig-ChHQ7M5c.js} +2 -2
- package/dist/assets/{app-query-client-Dr5d-K8d.js → app-query-client-VnFElj4E.js} +1 -1
- package/dist/assets/{book-open-Da4OEPqB.js → book-open-BdcxxoQu.js} +1 -1
- package/dist/assets/chat-page-Doe0yTtB.js +58 -0
- package/dist/assets/chat-session-display-cw78aiI_.js +1 -0
- package/dist/assets/{chunk-JZWAC4HX-CoFVxHXV.js → chunk-JZWAC4HX-DK5HPmIK.js} +1 -1
- package/dist/assets/{client-CSk58DcF.js → client-_i4MU2bB.js} +1 -1
- package/dist/assets/{config-D8KzikVB.js → config-DtIQwrHF.js} +1 -1
- package/dist/assets/{createLucideIcon-83gaZMtv.js → createLucideIcon-BSeTgkZW.js} +1 -1
- package/dist/assets/desktop-update-config-Dpcf4BKG.js +1 -0
- package/dist/assets/{dist-toEYs-MZ.js → dist-6TrrnPCR.js} +1 -1
- package/dist/assets/{dist-aTmhMDVh.js → dist-ccBFUi-o.js} +1 -1
- package/dist/assets/download-BhDxnyvU.js +1 -0
- package/dist/assets/{external-link-QQ0TC6X4.js → external-link-BgErLCNT.js} +1 -1
- package/dist/assets/{hash-DaFBEkmi.js → hash-Bl7dr_UG.js} +1 -1
- package/dist/assets/i18n-eDHeDY0n.js +1 -0
- package/dist/assets/index-CF9xve0E.js +6 -0
- package/dist/assets/index-FgA52VBt.css +1 -0
- package/dist/assets/{infiniteQueryBehavior-BmHX_ayZ.js → infiniteQueryBehavior-ZDS92Qpp.js} +1 -1
- package/dist/assets/loader-circle-ACM1s51e.js +1 -0
- package/dist/assets/{logos-Dzlz30M3.js → logos-x89HbrZ4.js} +1 -1
- package/dist/assets/{page-layout-D2eRufRQ.js → page-layout-vZnghcFy.js} +1 -1
- package/dist/assets/play-CFUwCA2E.js +1 -0
- package/dist/assets/plus-rYsv72JG.js +1 -0
- package/dist/assets/{popover-BSXxm5bj.js → popover-Bg1VoTZ6.js} +1 -1
- package/dist/assets/{refresh-ccw-B3zMtN-_.js → refresh-ccw-DT98i__E.js} +1 -1
- package/dist/assets/{refresh-cw-DlZkIHnJ.js → refresh-cw-C47QSEwg.js} +1 -1
- package/dist/assets/rotate-cw-JtFzpNn6.js +1 -0
- package/dist/assets/{save-Us9fg4Sj.js → save-3S6-H3Xw.js} +1 -1
- package/dist/assets/search-3kFR_zh9.js +1 -0
- package/dist/assets/{security-config-BGWYwxNr.js → security-config-BWaiARNk.js} +1 -1
- package/dist/assets/{select-DLYqySQK.js → select-DJ2MUjBB.js} +1 -1
- package/dist/assets/skeleton-ByQepn0M.js +1 -0
- package/dist/assets/{status-dot-DGayudyB.js → status-dot-vbanNPFU.js} +1 -1
- package/dist/assets/{switch-Dz2ScsKx.js → switch-BsLtHOH-.js} +1 -1
- package/dist/assets/{tabs-custom-CdKyjiGk.js → tabs-custom-D3HYMt6k.js} +1 -1
- package/dist/assets/{trash-2-Db-mZOZs.js → trash-2-G48scll7.js} +1 -1
- package/dist/assets/{use-infinite-scroll-loader-DBJX5hj0.js → use-infinite-scroll-loader-DkNhD-42.js} +1 -1
- package/dist/assets/{useConfirmDialog-DL0a-oGC.js → useConfirmDialog-BkvTN-vd.js} +1 -1
- package/dist/assets/{useMutation-BdZm-9PL.js → useMutation-CBWjE2uj.js} +1 -1
- package/dist/assets/x-ByDbItbq.js +1 -0
- package/dist/index.html +95 -21
- package/dist/manifest.webmanifest +30 -0
- package/dist/offline.html +102 -0
- package/dist/pwa-192.png +0 -0
- package/dist/pwa-512.png +0 -0
- package/dist/sw.js +80 -0
- package/index.html +73 -1
- package/package.json +6 -6
- package/public/manifest.webmanifest +30 -0
- package/public/offline.html +102 -0
- package/public/pwa-192.png +0 -0
- package/public/pwa-512.png +0 -0
- package/public/sw.js +80 -0
- package/src/api/runtime-control.ts +34 -0
- package/src/api/runtime-control.types.ts +58 -0
- package/src/api/server-path.ts +27 -4
- package/src/api/types.ts +30 -10
- package/src/{App.test.tsx → app.test.tsx} +1 -1
- package/src/{App.tsx → app.tsx} +10 -1
- package/src/components/chat/ChatSidebar.test.tsx +79 -8
- package/src/components/chat/ChatSidebar.tsx +43 -26
- package/src/components/chat/adapters/chat-message.summary-truncation.test.ts +66 -0
- package/src/components/chat/adapters/file-operation/card.ts +9 -0
- package/src/components/chat/adapters/file-operation/diff.ts +14 -0
- package/src/components/chat/{ChatConversationPanel.test.tsx → chat-conversation-panel.test.tsx} +118 -155
- package/src/components/chat/chat-conversation-panel.tsx +412 -0
- package/src/components/chat/chat-page-runtime.test.ts +1 -1
- package/src/components/chat/chat-page-shell.tsx +1 -1
- package/src/components/chat/{ChatPage.tsx → chat-page.tsx} +1 -1
- package/src/components/chat/chat-session-workspace-file-preview.test.tsx +91 -0
- package/src/components/chat/chat-session-workspace-file-preview.tsx +307 -0
- package/src/components/chat/chat-session-workspace-panel-nav.tsx +197 -0
- package/src/components/chat/chat-session-workspace-panel.tsx +318 -0
- package/src/components/chat/chat-sidebar-session-item.tsx +32 -2
- package/src/components/chat/containers/chat-message-list.container.test.tsx +49 -0
- package/src/components/chat/containers/chat-message-list.container.tsx +4 -0
- package/src/components/chat/managers/chat-session-list.manager.test.ts +94 -31
- package/src/components/chat/managers/chat-session-list.manager.ts +86 -14
- package/src/components/chat/managers/chat-ui.manager.ts +2 -0
- package/src/components/chat/ncp/README.md +1 -1
- package/src/components/chat/ncp/ncp-chat-input.manager.ts +7 -1
- package/src/components/chat/ncp/ncp-chat-page-data.test.ts +1 -1
- package/src/components/chat/ncp/{NcpChatPage.tsx → ncp-chat-page.tsx} +7 -7
- package/src/components/chat/ncp/ncp-chat-thread.manager.ts +179 -41
- package/src/components/chat/ncp/ncp-session-adapter.test.ts +40 -2
- package/src/components/chat/ncp/ncp-session-adapter.ts +29 -0
- package/src/components/chat/ncp/page/ncp-chat-derived-state.ts +54 -11
- package/src/components/chat/ncp/session-conversation/use-ncp-child-session-tabs-view.ts +4 -0
- package/src/components/chat/ncp/tests/ncp-chat-input.manager.test.ts +99 -0
- package/src/components/chat/ncp/tests/ncp-chat-thread.manager.test.ts +189 -0
- package/src/components/chat/presenter/chat-presenter-context.tsx +13 -2
- package/src/components/chat/session-header/chat-session-header-actions.test.tsx +26 -0
- package/src/components/chat/session-header/chat-session-header-actions.tsx +19 -1
- package/src/components/chat/stores/chat-session-list.store.ts +25 -54
- package/src/components/chat/stores/chat-thread.store.ts +24 -0
- package/src/components/common/ProviderScopedModelInput.tsx +12 -2
- package/src/components/config/ModelConfig.test.tsx +108 -2
- package/src/components/config/RuntimeConfig.tsx +154 -7
- package/src/components/config/desktop-update-config.test.tsx +85 -0
- package/src/components/config/desktop-update-config.tsx +44 -3
- package/src/components/config/runtime-control-card.test.tsx +255 -0
- package/src/components/config/runtime-control-card.tsx +301 -0
- package/src/components/config/runtime-presence-card.test.tsx +154 -0
- package/src/components/config/runtime-presence-card.tsx +163 -0
- package/src/components/layout/AppLayout.tsx +1 -1
- package/src/components/providers/ThemeProvider.tsx +5 -0
- package/src/desktop/desktop-update.types.ts +25 -0
- package/src/desktop/managers/desktop-presence.manager.ts +91 -0
- package/src/desktop/managers/desktop-update.manager.ts +37 -1
- package/src/desktop/stores/desktop-presence.store.ts +18 -0
- package/src/desktop/stores/desktop-update.store.ts +7 -1
- package/src/hooks/server-path/use-server-path-read.ts +20 -0
- package/src/hooks/use-runtime-control.ts +24 -0
- package/src/lib/chat-message.ts +14 -3
- package/src/lib/desktop-update-labels.utils.ts +28 -2
- package/src/lib/i18n.chat.ts +12 -1
- package/src/lib/i18n.pwa.ts +62 -0
- package/src/lib/i18n.runtime-control.ts +120 -0
- package/src/lib/i18n.ts +4 -6
- package/src/main.tsx +1 -1
- package/src/pwa/components/pwa-install-entry.test.tsx +110 -0
- package/src/pwa/components/pwa-install-entry.tsx +205 -0
- package/src/pwa/managers/pwa-install.manager.test.ts +160 -0
- package/src/pwa/managers/pwa-install.manager.ts +232 -0
- package/src/pwa/managers/pwa-runtime.manager.ts +196 -0
- package/src/pwa/managers/pwa-shell-theme.manager.test.ts +30 -0
- package/src/pwa/managers/pwa-shell-theme.manager.ts +46 -0
- package/src/pwa/pwa-install-banner.storage.ts +55 -0
- package/src/pwa/pwa.types.ts +22 -0
- package/src/pwa/register-pwa.ts +14 -0
- package/src/pwa/stores/pwa.store.ts +17 -0
- package/src/runtime-control/runtime-control.manager.ts +118 -0
- package/src/vite-env.d.ts +9 -0
- package/dist/assets/ChannelsList-D8p4OlM6.js +0 -8
- package/dist/assets/ChatPage-A45t1Rmf.js +0 -58
- package/dist/assets/DocBrowser-B2MpsnU9.js +0 -1
- package/dist/assets/MarketplacePage-BNZ3Jx5d.js +0 -1
- package/dist/assets/McpMarketplacePage-CxPFOgxv.js +0 -40
- package/dist/assets/RemoteAccessPage-DyYVWsyK.js +0 -1
- package/dist/assets/RuntimeConfig-ChdfK4Y_.js +0 -1
- package/dist/assets/chat-session-display-CAlPrnlV.js +0 -1
- package/dist/assets/desktop-update-config-CfoVwf-w.js +0 -1
- package/dist/assets/i18n-C3jb83S6.js +0 -1
- package/dist/assets/index-CE4N7ItL.css +0 -1
- package/dist/assets/index-riX7Sg0_.js +0 -6
- package/dist/assets/loader-circle-BjMg63eu.js +0 -1
- package/dist/assets/plus-CIXME2pD.js +0 -1
- package/dist/assets/search-B_Qr0f6C.js +0 -1
- package/dist/assets/skeleton-CYQJazv6.js +0 -1
- package/dist/assets/x-B8Tho_xC.js +0 -1
- package/src/components/chat/ChatConversationPanel.tsx +0 -256
- package/src/components/chat/chat-child-session-panel.tsx +0 -262
- /package/dist/assets/{config-hints-GSUMvmSo.js → config-hints-BhTmc9P1.js} +0 -0
- /package/dist/assets/{config-layout-CgBMG7OL.js → config-layout-CHs0mAaR.js} +0 -0
package/dist/index.html
CHANGED
|
@@ -4,32 +4,106 @@
|
|
|
4
4
|
<head>
|
|
5
5
|
<meta charset="UTF-8" />
|
|
6
6
|
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
|
|
7
|
+
<link rel="manifest" href="/manifest.webmanifest" />
|
|
8
|
+
<link rel="apple-touch-icon" href="/pwa-192.png" />
|
|
9
|
+
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
10
|
+
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
|
|
11
|
+
<meta name="apple-mobile-web-app-title" content="NextClaw" />
|
|
12
|
+
<meta name="mobile-web-app-capable" content="yes" />
|
|
7
13
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
14
|
+
<meta name="theme-color" content="#F9F8F5" />
|
|
15
|
+
<meta name="color-scheme" content="light" />
|
|
16
|
+
<style>
|
|
17
|
+
html,
|
|
18
|
+
body,
|
|
19
|
+
#root {
|
|
20
|
+
background: #f9f8f5;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
html[data-theme="cool"],
|
|
24
|
+
html[data-theme="cool"] body,
|
|
25
|
+
html[data-theme="cool"] #root {
|
|
26
|
+
background: #f8fafb;
|
|
27
|
+
}
|
|
28
|
+
</style>
|
|
29
|
+
<script>
|
|
30
|
+
(() => {
|
|
31
|
+
const storageKey = 'nextclaw.ui.theme';
|
|
32
|
+
const storedTheme = window.localStorage.getItem(storageKey);
|
|
33
|
+
const nextTheme = storedTheme === 'cool' ? 'cool' : 'warm';
|
|
34
|
+
const themeColor = nextTheme === 'cool' ? '#F8FAFB' : '#F9F8F5';
|
|
35
|
+
document.documentElement.setAttribute('data-theme', nextTheme);
|
|
36
|
+
document.documentElement.style.backgroundColor = themeColor;
|
|
37
|
+
document.documentElement.style.colorScheme = 'light';
|
|
38
|
+
const themeMeta = document.querySelector('meta[name="theme-color"]');
|
|
39
|
+
if (themeMeta) {
|
|
40
|
+
themeMeta.setAttribute('content', themeColor);
|
|
41
|
+
}
|
|
42
|
+
})();
|
|
43
|
+
</script>
|
|
44
|
+
<script>
|
|
45
|
+
(() => {
|
|
46
|
+
const devResetKey = 'nextclaw-pwa-dev-sw-reset';
|
|
47
|
+
const isViteDevServer = 'production' === 'development';
|
|
48
|
+
if (!isViteDevServer || !('serviceWorker' in navigator)) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
void navigator.serviceWorker.getRegistrations().then(async (registrations) => {
|
|
53
|
+
const nextclawRegistrations = registrations.filter((registration) => {
|
|
54
|
+
const scriptUrls = [registration.active?.scriptURL, registration.installing?.scriptURL, registration.waiting?.scriptURL]
|
|
55
|
+
.filter(Boolean);
|
|
56
|
+
return scriptUrls.some((scriptUrl) => scriptUrl.endsWith('/sw.js'));
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
if (nextclawRegistrations.length === 0) {
|
|
60
|
+
window.sessionStorage.removeItem(devResetKey);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
await Promise.all(nextclawRegistrations.map(async (registration) => await registration.unregister()));
|
|
65
|
+
if ('caches' in window) {
|
|
66
|
+
const keys = await caches.keys();
|
|
67
|
+
await Promise.all(keys.filter((key) => key.startsWith('nextclaw-ui-')).map(async (key) => await caches.delete(key)));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (navigator.serviceWorker.controller && window.sessionStorage.getItem(devResetKey) !== '1') {
|
|
71
|
+
window.sessionStorage.setItem(devResetKey, '1');
|
|
72
|
+
window.location.reload();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
window.sessionStorage.removeItem(devResetKey);
|
|
77
|
+
});
|
|
78
|
+
})();
|
|
79
|
+
</script>
|
|
8
80
|
<title>NextClaw</title>
|
|
9
|
-
<script type="module" crossorigin src="/assets/index-
|
|
10
|
-
<link rel="modulepreload" crossorigin href="/assets/i18n-
|
|
11
|
-
<link rel="modulepreload" crossorigin href="/assets/chunk-JZWAC4HX-
|
|
12
|
-
<link rel="modulepreload" crossorigin href="/assets/dist-
|
|
13
|
-
<link rel="modulepreload" crossorigin href="/assets/createLucideIcon-
|
|
14
|
-
<link rel="modulepreload" crossorigin href="/assets/select-
|
|
15
|
-
<link rel="modulepreload" crossorigin href="/assets/dist-
|
|
16
|
-
<link rel="modulepreload" crossorigin href="/assets/client-
|
|
17
|
-
<link rel="modulepreload" crossorigin href="/assets/infiniteQueryBehavior-
|
|
18
|
-
<link rel="modulepreload" crossorigin href="/assets/app-query-client-
|
|
19
|
-
<link rel="modulepreload" crossorigin href="/assets/useMutation-
|
|
20
|
-
<link rel="modulepreload" crossorigin href="/assets/book-open-
|
|
21
|
-
<link rel="modulepreload" crossorigin href="/assets/external-link-
|
|
22
|
-
<link rel="modulepreload" crossorigin href="/assets/plus-
|
|
23
|
-
<link rel="modulepreload" crossorigin href="/assets/search-
|
|
24
|
-
<link rel="modulepreload" crossorigin href="/assets/x-
|
|
25
|
-
<link rel="modulepreload" crossorigin href="/assets/DocBrowserContext-
|
|
26
|
-
<link rel="modulepreload" crossorigin href="/assets/DocBrowser-
|
|
27
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
28
|
-
<link rel="
|
|
81
|
+
<script type="module" crossorigin src="/assets/index-CF9xve0E.js"></script>
|
|
82
|
+
<link rel="modulepreload" crossorigin href="/assets/i18n-eDHeDY0n.js">
|
|
83
|
+
<link rel="modulepreload" crossorigin href="/assets/chunk-JZWAC4HX-DK5HPmIK.js">
|
|
84
|
+
<link rel="modulepreload" crossorigin href="/assets/dist-ccBFUi-o.js">
|
|
85
|
+
<link rel="modulepreload" crossorigin href="/assets/createLucideIcon-BSeTgkZW.js">
|
|
86
|
+
<link rel="modulepreload" crossorigin href="/assets/select-DJ2MUjBB.js">
|
|
87
|
+
<link rel="modulepreload" crossorigin href="/assets/dist-6TrrnPCR.js">
|
|
88
|
+
<link rel="modulepreload" crossorigin href="/assets/client-_i4MU2bB.js">
|
|
89
|
+
<link rel="modulepreload" crossorigin href="/assets/infiniteQueryBehavior-ZDS92Qpp.js">
|
|
90
|
+
<link rel="modulepreload" crossorigin href="/assets/app-query-client-VnFElj4E.js">
|
|
91
|
+
<link rel="modulepreload" crossorigin href="/assets/useMutation-CBWjE2uj.js">
|
|
92
|
+
<link rel="modulepreload" crossorigin href="/assets/book-open-BdcxxoQu.js">
|
|
93
|
+
<link rel="modulepreload" crossorigin href="/assets/external-link-BgErLCNT.js">
|
|
94
|
+
<link rel="modulepreload" crossorigin href="/assets/plus-rYsv72JG.js">
|
|
95
|
+
<link rel="modulepreload" crossorigin href="/assets/search-3kFR_zh9.js">
|
|
96
|
+
<link rel="modulepreload" crossorigin href="/assets/x-ByDbItbq.js">
|
|
97
|
+
<link rel="modulepreload" crossorigin href="/assets/DocBrowserContext-B6SpA7Qs.js">
|
|
98
|
+
<link rel="modulepreload" crossorigin href="/assets/DocBrowser-6ReNjvzF.js">
|
|
99
|
+
<link rel="modulepreload" crossorigin href="/assets/download-BhDxnyvU.js">
|
|
100
|
+
<link rel="modulepreload" crossorigin href="/assets/refresh-cw-C47QSEwg.js">
|
|
101
|
+
<link rel="modulepreload" crossorigin href="/assets/config-DtIQwrHF.js">
|
|
102
|
+
<link rel="stylesheet" crossorigin href="/assets/index-FgA52VBt.css">
|
|
29
103
|
</head>
|
|
30
104
|
|
|
31
105
|
<body>
|
|
32
106
|
<div id="root"></div>
|
|
33
107
|
</body>
|
|
34
108
|
|
|
35
|
-
</html>
|
|
109
|
+
</html>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "NextClaw",
|
|
3
|
+
"short_name": "NextClaw",
|
|
4
|
+
"description": "NextClaw is your installable AI operating layer for chat, configuration, orchestration, and local runtime control.",
|
|
5
|
+
"start_url": "/",
|
|
6
|
+
"scope": "/",
|
|
7
|
+
"display": "standalone",
|
|
8
|
+
"background_color": "#f9f8f5",
|
|
9
|
+
"theme_color": "#f9f8f5",
|
|
10
|
+
"icons": [
|
|
11
|
+
{
|
|
12
|
+
"src": "/pwa-192.png",
|
|
13
|
+
"sizes": "192x192",
|
|
14
|
+
"type": "image/png",
|
|
15
|
+
"purpose": "any"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"src": "/pwa-512.png",
|
|
19
|
+
"sizes": "512x512",
|
|
20
|
+
"type": "image/png",
|
|
21
|
+
"purpose": "any"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"src": "/logo.svg",
|
|
25
|
+
"sizes": "any",
|
|
26
|
+
"type": "image/svg+xml",
|
|
27
|
+
"purpose": "any"
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<meta name="theme-color" content="#F9F8F5" />
|
|
8
|
+
<title>NextClaw Offline</title>
|
|
9
|
+
<style>
|
|
10
|
+
:root {
|
|
11
|
+
color-scheme: light;
|
|
12
|
+
--bg: #f9f8f5;
|
|
13
|
+
--card: rgba(255, 255, 255, 0.92);
|
|
14
|
+
--text: #17120f;
|
|
15
|
+
--muted: #6d645c;
|
|
16
|
+
--border: rgba(23, 18, 15, 0.1);
|
|
17
|
+
--accent: #fbbf24;
|
|
18
|
+
--shadow: 0 18px 50px rgba(26, 21, 18, 0.12);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
* {
|
|
22
|
+
box-sizing: border-box;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
body {
|
|
26
|
+
margin: 0;
|
|
27
|
+
min-height: 100vh;
|
|
28
|
+
display: grid;
|
|
29
|
+
place-items: center;
|
|
30
|
+
padding: 24px;
|
|
31
|
+
font-family: "SF Pro Display", "Segoe UI", sans-serif;
|
|
32
|
+
background:
|
|
33
|
+
radial-gradient(circle at top left, rgba(251, 191, 36, 0.16), transparent 30%),
|
|
34
|
+
radial-gradient(circle at bottom right, rgba(26, 21, 18, 0.1), transparent 28%),
|
|
35
|
+
var(--bg);
|
|
36
|
+
color: var(--text);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.card {
|
|
40
|
+
width: min(100%, 520px);
|
|
41
|
+
border-radius: 28px;
|
|
42
|
+
border: 1px solid var(--border);
|
|
43
|
+
background: var(--card);
|
|
44
|
+
padding: 28px;
|
|
45
|
+
box-shadow: var(--shadow);
|
|
46
|
+
backdrop-filter: blur(12px);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.brand {
|
|
50
|
+
display: inline-flex;
|
|
51
|
+
align-items: center;
|
|
52
|
+
gap: 12px;
|
|
53
|
+
margin-bottom: 18px;
|
|
54
|
+
font-weight: 700;
|
|
55
|
+
letter-spacing: 0.01em;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.brand img {
|
|
59
|
+
width: 44px;
|
|
60
|
+
height: 44px;
|
|
61
|
+
border-radius: 14px;
|
|
62
|
+
background: #1a1512;
|
|
63
|
+
padding: 8px;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
h1 {
|
|
67
|
+
margin: 0;
|
|
68
|
+
font-size: 28px;
|
|
69
|
+
line-height: 1.15;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
p {
|
|
73
|
+
margin: 14px 0 0;
|
|
74
|
+
color: var(--muted);
|
|
75
|
+
line-height: 1.7;
|
|
76
|
+
font-size: 15px;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.hint {
|
|
80
|
+
margin-top: 18px;
|
|
81
|
+
padding: 14px 16px;
|
|
82
|
+
border-radius: 18px;
|
|
83
|
+
background: rgba(251, 191, 36, 0.12);
|
|
84
|
+
color: #5f4a00;
|
|
85
|
+
font-size: 14px;
|
|
86
|
+
}
|
|
87
|
+
</style>
|
|
88
|
+
</head>
|
|
89
|
+
|
|
90
|
+
<body>
|
|
91
|
+
<main class="card">
|
|
92
|
+
<div class="brand">
|
|
93
|
+
<img src="/logo.svg" alt="NextClaw logo" />
|
|
94
|
+
<span>NextClaw</span>
|
|
95
|
+
</div>
|
|
96
|
+
<h1>应用壳已加载,但当前无法连接服务。</h1>
|
|
97
|
+
<p>NextClaw 的 PWA 主要用于更自然地进入本地或远端运行中的 NextClaw UI,而不是提供完整离线能力。请确认本地 runtime 或远端服务当前可访问,然后刷新重试。</p>
|
|
98
|
+
<div class="hint">如果你是通过本机访问,请先确认 NextClaw 服务已经启动;如果你是通过服务器访问,请确认当前网络连接正常。</div>
|
|
99
|
+
</main>
|
|
100
|
+
</body>
|
|
101
|
+
|
|
102
|
+
</html>
|
package/dist/pwa-192.png
ADDED
|
Binary file
|
package/dist/pwa-512.png
ADDED
|
Binary file
|
package/dist/sw.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/* global caches, self */
|
|
2
|
+
|
|
3
|
+
const SHELL_CACHE = 'nextclaw-ui-shell-v1';
|
|
4
|
+
const RUNTIME_CACHE = 'nextclaw-ui-runtime-v1';
|
|
5
|
+
const SHELL_ASSETS = ['/', '/offline.html', '/manifest.webmanifest', '/logo.svg', '/pwa-192.png', '/pwa-512.png'];
|
|
6
|
+
|
|
7
|
+
self.addEventListener('install', (event) => {
|
|
8
|
+
event.waitUntil(
|
|
9
|
+
caches.open(SHELL_CACHE).then((cache) => {
|
|
10
|
+
return cache.addAll(SHELL_ASSETS);
|
|
11
|
+
})
|
|
12
|
+
);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
self.addEventListener('activate', (event) => {
|
|
16
|
+
event.waitUntil(
|
|
17
|
+
caches.keys().then(async (keys) => {
|
|
18
|
+
await Promise.all(keys.filter((key) => key !== SHELL_CACHE && key !== RUNTIME_CACHE).map((key) => caches.delete(key)));
|
|
19
|
+
await self.clients.claim();
|
|
20
|
+
})
|
|
21
|
+
);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
self.addEventListener('message', (event) => {
|
|
25
|
+
if (event.data?.type === 'SKIP_WAIT') {
|
|
26
|
+
self.skipWaiting();
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
self.addEventListener('fetch', (event) => {
|
|
31
|
+
const { request } = event;
|
|
32
|
+
if (request.method !== 'GET') {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const url = new URL(request.url);
|
|
37
|
+
if (request.mode === 'navigate') {
|
|
38
|
+
event.respondWith(handleNavigation(request));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (url.origin !== self.location.origin) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (url.pathname.startsWith('/api') || url.pathname.startsWith('/ws')) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (['script', 'style', 'image', 'font'].includes(request.destination) || url.pathname === '/manifest.webmanifest') {
|
|
51
|
+
event.respondWith(handleStaticAsset(request));
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
async function handleNavigation(request) {
|
|
56
|
+
try {
|
|
57
|
+
const response = await fetch(request);
|
|
58
|
+
const runtimeCache = await caches.open(RUNTIME_CACHE);
|
|
59
|
+
runtimeCache.put(request, response.clone());
|
|
60
|
+
return response;
|
|
61
|
+
} catch {
|
|
62
|
+
const cachedResponse = await caches.match(request);
|
|
63
|
+
if (cachedResponse) {
|
|
64
|
+
return cachedResponse;
|
|
65
|
+
}
|
|
66
|
+
return caches.match('/offline.html');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function handleStaticAsset(request) {
|
|
71
|
+
const cachedResponse = await caches.match(request);
|
|
72
|
+
if (cachedResponse) {
|
|
73
|
+
return cachedResponse;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const response = await fetch(request);
|
|
77
|
+
const runtimeCache = await caches.open(RUNTIME_CACHE);
|
|
78
|
+
runtimeCache.put(request, response.clone());
|
|
79
|
+
return response;
|
|
80
|
+
}
|
package/index.html
CHANGED
|
@@ -4,7 +4,79 @@
|
|
|
4
4
|
<head>
|
|
5
5
|
<meta charset="UTF-8" />
|
|
6
6
|
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
|
|
7
|
+
<link rel="manifest" href="/manifest.webmanifest" />
|
|
8
|
+
<link rel="apple-touch-icon" href="/pwa-192.png" />
|
|
9
|
+
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
10
|
+
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
|
|
11
|
+
<meta name="apple-mobile-web-app-title" content="NextClaw" />
|
|
12
|
+
<meta name="mobile-web-app-capable" content="yes" />
|
|
7
13
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
14
|
+
<meta name="theme-color" content="#F9F8F5" />
|
|
15
|
+
<meta name="color-scheme" content="light" />
|
|
16
|
+
<style>
|
|
17
|
+
html,
|
|
18
|
+
body,
|
|
19
|
+
#root {
|
|
20
|
+
background: #f9f8f5;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
html[data-theme="cool"],
|
|
24
|
+
html[data-theme="cool"] body,
|
|
25
|
+
html[data-theme="cool"] #root {
|
|
26
|
+
background: #f8fafb;
|
|
27
|
+
}
|
|
28
|
+
</style>
|
|
29
|
+
<script>
|
|
30
|
+
(() => {
|
|
31
|
+
const storageKey = 'nextclaw.ui.theme';
|
|
32
|
+
const storedTheme = window.localStorage.getItem(storageKey);
|
|
33
|
+
const nextTheme = storedTheme === 'cool' ? 'cool' : 'warm';
|
|
34
|
+
const themeColor = nextTheme === 'cool' ? '#F8FAFB' : '#F9F8F5';
|
|
35
|
+
document.documentElement.setAttribute('data-theme', nextTheme);
|
|
36
|
+
document.documentElement.style.backgroundColor = themeColor;
|
|
37
|
+
document.documentElement.style.colorScheme = 'light';
|
|
38
|
+
const themeMeta = document.querySelector('meta[name="theme-color"]');
|
|
39
|
+
if (themeMeta) {
|
|
40
|
+
themeMeta.setAttribute('content', themeColor);
|
|
41
|
+
}
|
|
42
|
+
})();
|
|
43
|
+
</script>
|
|
44
|
+
<script>
|
|
45
|
+
(() => {
|
|
46
|
+
const devResetKey = 'nextclaw-pwa-dev-sw-reset';
|
|
47
|
+
const isViteDevServer = '%MODE%' === 'development';
|
|
48
|
+
if (!isViteDevServer || !('serviceWorker' in navigator)) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
void navigator.serviceWorker.getRegistrations().then(async (registrations) => {
|
|
53
|
+
const nextclawRegistrations = registrations.filter((registration) => {
|
|
54
|
+
const scriptUrls = [registration.active?.scriptURL, registration.installing?.scriptURL, registration.waiting?.scriptURL]
|
|
55
|
+
.filter(Boolean);
|
|
56
|
+
return scriptUrls.some((scriptUrl) => scriptUrl.endsWith('/sw.js'));
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
if (nextclawRegistrations.length === 0) {
|
|
60
|
+
window.sessionStorage.removeItem(devResetKey);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
await Promise.all(nextclawRegistrations.map(async (registration) => await registration.unregister()));
|
|
65
|
+
if ('caches' in window) {
|
|
66
|
+
const keys = await caches.keys();
|
|
67
|
+
await Promise.all(keys.filter((key) => key.startsWith('nextclaw-ui-')).map(async (key) => await caches.delete(key)));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (navigator.serviceWorker.controller && window.sessionStorage.getItem(devResetKey) !== '1') {
|
|
71
|
+
window.sessionStorage.setItem(devResetKey, '1');
|
|
72
|
+
window.location.reload();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
window.sessionStorage.removeItem(devResetKey);
|
|
77
|
+
});
|
|
78
|
+
})();
|
|
79
|
+
</script>
|
|
8
80
|
<title>NextClaw</title>
|
|
9
81
|
</head>
|
|
10
82
|
|
|
@@ -13,4 +85,4 @@
|
|
|
13
85
|
<script type="module" src="/src/main.tsx"></script>
|
|
14
86
|
</body>
|
|
15
87
|
|
|
16
|
-
</html>
|
|
88
|
+
</html>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/ui",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.9",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -28,11 +28,11 @@
|
|
|
28
28
|
"tailwind-merge": "^2.5.4",
|
|
29
29
|
"zod": "^3.23.8",
|
|
30
30
|
"zustand": "^5.0.2",
|
|
31
|
-
"@nextclaw/
|
|
32
|
-
"@nextclaw/agent-chat-ui": "0.3.
|
|
33
|
-
"@nextclaw/ncp
|
|
34
|
-
"@nextclaw/agent-
|
|
35
|
-
"@nextclaw/ncp-
|
|
31
|
+
"@nextclaw/agent-chat": "0.1.10",
|
|
32
|
+
"@nextclaw/agent-chat-ui": "0.3.6",
|
|
33
|
+
"@nextclaw/ncp": "0.5.2",
|
|
34
|
+
"@nextclaw/ncp-http-agent-client": "0.3.14",
|
|
35
|
+
"@nextclaw/ncp-react": "0.4.22"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@testing-library/react": "^16.3.0",
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "NextClaw",
|
|
3
|
+
"short_name": "NextClaw",
|
|
4
|
+
"description": "NextClaw is your installable AI operating layer for chat, configuration, orchestration, and local runtime control.",
|
|
5
|
+
"start_url": "/",
|
|
6
|
+
"scope": "/",
|
|
7
|
+
"display": "standalone",
|
|
8
|
+
"background_color": "#f9f8f5",
|
|
9
|
+
"theme_color": "#f9f8f5",
|
|
10
|
+
"icons": [
|
|
11
|
+
{
|
|
12
|
+
"src": "/pwa-192.png",
|
|
13
|
+
"sizes": "192x192",
|
|
14
|
+
"type": "image/png",
|
|
15
|
+
"purpose": "any"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"src": "/pwa-512.png",
|
|
19
|
+
"sizes": "512x512",
|
|
20
|
+
"type": "image/png",
|
|
21
|
+
"purpose": "any"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"src": "/logo.svg",
|
|
25
|
+
"sizes": "any",
|
|
26
|
+
"type": "image/svg+xml",
|
|
27
|
+
"purpose": "any"
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<meta name="theme-color" content="#F9F8F5" />
|
|
8
|
+
<title>NextClaw Offline</title>
|
|
9
|
+
<style>
|
|
10
|
+
:root {
|
|
11
|
+
color-scheme: light;
|
|
12
|
+
--bg: #f9f8f5;
|
|
13
|
+
--card: rgba(255, 255, 255, 0.92);
|
|
14
|
+
--text: #17120f;
|
|
15
|
+
--muted: #6d645c;
|
|
16
|
+
--border: rgba(23, 18, 15, 0.1);
|
|
17
|
+
--accent: #fbbf24;
|
|
18
|
+
--shadow: 0 18px 50px rgba(26, 21, 18, 0.12);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
* {
|
|
22
|
+
box-sizing: border-box;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
body {
|
|
26
|
+
margin: 0;
|
|
27
|
+
min-height: 100vh;
|
|
28
|
+
display: grid;
|
|
29
|
+
place-items: center;
|
|
30
|
+
padding: 24px;
|
|
31
|
+
font-family: "SF Pro Display", "Segoe UI", sans-serif;
|
|
32
|
+
background:
|
|
33
|
+
radial-gradient(circle at top left, rgba(251, 191, 36, 0.16), transparent 30%),
|
|
34
|
+
radial-gradient(circle at bottom right, rgba(26, 21, 18, 0.1), transparent 28%),
|
|
35
|
+
var(--bg);
|
|
36
|
+
color: var(--text);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.card {
|
|
40
|
+
width: min(100%, 520px);
|
|
41
|
+
border-radius: 28px;
|
|
42
|
+
border: 1px solid var(--border);
|
|
43
|
+
background: var(--card);
|
|
44
|
+
padding: 28px;
|
|
45
|
+
box-shadow: var(--shadow);
|
|
46
|
+
backdrop-filter: blur(12px);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.brand {
|
|
50
|
+
display: inline-flex;
|
|
51
|
+
align-items: center;
|
|
52
|
+
gap: 12px;
|
|
53
|
+
margin-bottom: 18px;
|
|
54
|
+
font-weight: 700;
|
|
55
|
+
letter-spacing: 0.01em;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.brand img {
|
|
59
|
+
width: 44px;
|
|
60
|
+
height: 44px;
|
|
61
|
+
border-radius: 14px;
|
|
62
|
+
background: #1a1512;
|
|
63
|
+
padding: 8px;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
h1 {
|
|
67
|
+
margin: 0;
|
|
68
|
+
font-size: 28px;
|
|
69
|
+
line-height: 1.15;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
p {
|
|
73
|
+
margin: 14px 0 0;
|
|
74
|
+
color: var(--muted);
|
|
75
|
+
line-height: 1.7;
|
|
76
|
+
font-size: 15px;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.hint {
|
|
80
|
+
margin-top: 18px;
|
|
81
|
+
padding: 14px 16px;
|
|
82
|
+
border-radius: 18px;
|
|
83
|
+
background: rgba(251, 191, 36, 0.12);
|
|
84
|
+
color: #5f4a00;
|
|
85
|
+
font-size: 14px;
|
|
86
|
+
}
|
|
87
|
+
</style>
|
|
88
|
+
</head>
|
|
89
|
+
|
|
90
|
+
<body>
|
|
91
|
+
<main class="card">
|
|
92
|
+
<div class="brand">
|
|
93
|
+
<img src="/logo.svg" alt="NextClaw logo" />
|
|
94
|
+
<span>NextClaw</span>
|
|
95
|
+
</div>
|
|
96
|
+
<h1>应用壳已加载,但当前无法连接服务。</h1>
|
|
97
|
+
<p>NextClaw 的 PWA 主要用于更自然地进入本地或远端运行中的 NextClaw UI,而不是提供完整离线能力。请确认本地 runtime 或远端服务当前可访问,然后刷新重试。</p>
|
|
98
|
+
<div class="hint">如果你是通过本机访问,请先确认 NextClaw 服务已经启动;如果你是通过服务器访问,请确认当前网络连接正常。</div>
|
|
99
|
+
</main>
|
|
100
|
+
</body>
|
|
101
|
+
|
|
102
|
+
</html>
|
|
Binary file
|
|
Binary file
|
package/public/sw.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/* global caches, self */
|
|
2
|
+
|
|
3
|
+
const SHELL_CACHE = 'nextclaw-ui-shell-v1';
|
|
4
|
+
const RUNTIME_CACHE = 'nextclaw-ui-runtime-v1';
|
|
5
|
+
const SHELL_ASSETS = ['/', '/offline.html', '/manifest.webmanifest', '/logo.svg', '/pwa-192.png', '/pwa-512.png'];
|
|
6
|
+
|
|
7
|
+
self.addEventListener('install', (event) => {
|
|
8
|
+
event.waitUntil(
|
|
9
|
+
caches.open(SHELL_CACHE).then((cache) => {
|
|
10
|
+
return cache.addAll(SHELL_ASSETS);
|
|
11
|
+
})
|
|
12
|
+
);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
self.addEventListener('activate', (event) => {
|
|
16
|
+
event.waitUntil(
|
|
17
|
+
caches.keys().then(async (keys) => {
|
|
18
|
+
await Promise.all(keys.filter((key) => key !== SHELL_CACHE && key !== RUNTIME_CACHE).map((key) => caches.delete(key)));
|
|
19
|
+
await self.clients.claim();
|
|
20
|
+
})
|
|
21
|
+
);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
self.addEventListener('message', (event) => {
|
|
25
|
+
if (event.data?.type === 'SKIP_WAIT') {
|
|
26
|
+
self.skipWaiting();
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
self.addEventListener('fetch', (event) => {
|
|
31
|
+
const { request } = event;
|
|
32
|
+
if (request.method !== 'GET') {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const url = new URL(request.url);
|
|
37
|
+
if (request.mode === 'navigate') {
|
|
38
|
+
event.respondWith(handleNavigation(request));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (url.origin !== self.location.origin) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (url.pathname.startsWith('/api') || url.pathname.startsWith('/ws')) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (['script', 'style', 'image', 'font'].includes(request.destination) || url.pathname === '/manifest.webmanifest') {
|
|
51
|
+
event.respondWith(handleStaticAsset(request));
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
async function handleNavigation(request) {
|
|
56
|
+
try {
|
|
57
|
+
const response = await fetch(request);
|
|
58
|
+
const runtimeCache = await caches.open(RUNTIME_CACHE);
|
|
59
|
+
runtimeCache.put(request, response.clone());
|
|
60
|
+
return response;
|
|
61
|
+
} catch {
|
|
62
|
+
const cachedResponse = await caches.match(request);
|
|
63
|
+
if (cachedResponse) {
|
|
64
|
+
return cachedResponse;
|
|
65
|
+
}
|
|
66
|
+
return caches.match('/offline.html');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function handleStaticAsset(request) {
|
|
71
|
+
const cachedResponse = await caches.match(request);
|
|
72
|
+
if (cachedResponse) {
|
|
73
|
+
return cachedResponse;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const response = await fetch(request);
|
|
77
|
+
const runtimeCache = await caches.open(RUNTIME_CACHE);
|
|
78
|
+
runtimeCache.put(request, response.clone());
|
|
79
|
+
return response;
|
|
80
|
+
}
|