Skip to content

Commit 77b7c1e

Browse files
committed
fix オフライン対応
1 parent 08bd618 commit 77b7c1e

7 files changed

Lines changed: 75 additions & 21 deletions

File tree

frontend/src/lib/components/PWAUpdateNotification.svelte

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,23 @@
22
import { onMount } from "svelte";
33
import { _ } from "svelte-i18n";
44
import "$lib/i18n";
5-
let pwaInfo: unknown = null;
6-
75
let showUpdatePrompt = false;
86
let updateServiceWorker: (() => Promise<void>) | null = null;
97
108
onMount(async () => {
119
try {
1210
// @ts-expect-error
13-
const pwaModule = await import("virtual:pwa-info");
14-
pwaInfo = pwaModule.pwaInfo;
15-
16-
if (pwaInfo) {
17-
// @ts-expect-error
18-
const { registerSW } = await import("virtual:pwa-register");
11+
const { registerSW } = await import("virtual:pwa-register");
1912
20-
updateServiceWorker = registerSW({
21-
immediate: true,
22-
onNeedRefresh() {
23-
showUpdatePrompt = true;
24-
},
25-
onOfflineReady() {
26-
// PWA is ready for offline use
27-
},
28-
});
29-
}
13+
updateServiceWorker = registerSW({
14+
immediate: true,
15+
onNeedRefresh() {
16+
showUpdatePrompt = true;
17+
},
18+
onOfflineReady() {
19+
// PWA is ready for offline use
20+
},
21+
});
3022
} catch (error) {
3123
// PWA modules not available - this is expected in development
3224
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<script lang="ts">
2+
import { _ } from "svelte-i18n";
3+
import "$lib/i18n";
4+
import { isOnline } from "$lib/online-store";
5+
</script>
6+
7+
{#if !$isOnline}
8+
<div
9+
role="status"
10+
aria-live="polite"
11+
class="fixed bottom-0 left-0 right-0 z-50 bg-yellow-500 dark:bg-yellow-600 text-white px-4 py-2 flex items-center justify-center gap-2 text-sm shadow-lg"
12+
>
13+
<svg
14+
class="w-4 h-4 flex-shrink-0"
15+
fill="none"
16+
stroke="currentColor"
17+
viewBox="0 0 24 24"
18+
aria-hidden="true"
19+
>
20+
<path
21+
stroke-linecap="round"
22+
stroke-linejoin="round"
23+
stroke-width="2"
24+
d="M18.364 5.636l-12.728 12.728m0 0L5.636 18.364m12.728-12.728L18.364 18.364M12 12h.01"
25+
/>
26+
</svg>
27+
<span>{$_("offline.banner.message")}</span>
28+
</div>
29+
{/if}

frontend/src/lib/online-store.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { readable } from "svelte/store";
2+
import { browser } from "$app/environment";
3+
4+
// ネットワーク接続状態を管理するストア
5+
export const isOnline = readable<boolean>(true, (set) => {
6+
if (!browser) return;
7+
8+
// 初期値をnavigator.onLineから取得
9+
set(navigator.onLine);
10+
11+
const handleOnline = () => set(true);
12+
const handleOffline = () => set(false);
13+
14+
window.addEventListener("online", handleOnline);
15+
window.addEventListener("offline", handleOffline);
16+
17+
return () => {
18+
window.removeEventListener("online", handleOnline);
19+
window.removeEventListener("offline", handleOffline);
20+
};
21+
});

frontend/src/locales/en.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@
3030
},
3131
"connectionStatus": "When connection is restored, click the button below to refresh the page.",
3232
"retryConnection": "Retry Connection",
33-
"backToHome": "Back to Home"
33+
"backToHome": "Back to Home",
34+
"banner": {
35+
"message": "You are offline. Previously visited pages are available from cache."
36+
}
3437
},
3538
"pwa": {
3639
"install": {

frontend/src/locales/ja.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@
3030
},
3131
"connectionStatus": "接続が復旧したら、下のボタンをクリックしてページを更新してください。",
3232
"retryConnection": "接続を再試行",
33-
"backToHome": "ホームに戻る"
33+
"backToHome": "ホームに戻る",
34+
"banner": {
35+
"message": "オフライン中です。過去に閲覧したページはキャッシュから表示されます。"
36+
}
3437
},
3538
"pwa": {
3639
"install": {

frontend/src/routes/+layout.svelte

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import { autoPhraseEnabled } from "$lib/auto-phrase-store";
1414
import PWAInstallPrompt from "$lib/components/PWAInstallPrompt.svelte";
1515
import PWAUpdateNotification from "$lib/components/PWAUpdateNotification.svelte";
16+
import OfflineBanner from "$lib/components/atoms/OfflineBanner.svelte";
1617
import type { LayoutData } from "./$types";
1718
1819
export let data: LayoutData;
@@ -94,4 +95,5 @@
9495

9596
<!-- PWA Components -->
9697
<PWAInstallPrompt />
97-
<PWAUpdateNotification />
98+
<PWAUpdateNotification />
99+
<OfflineBanner />

frontend/vite.config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ export default defineConfig({
2020
process.env.NODE_ENV === "development" ? "development" : "production",
2121
workbox: {
2222
globPatterns: ["**/*.{js,css,html,ico,png,svg}"],
23+
// オフライン時にナビゲーションが失敗した場合のフォールバックページ
24+
navigateFallback: "/offline",
25+
// APIルートはフォールバック対象から除外
26+
navigateFallbackDenylist: [/^\/api\//],
2327
runtimeCaching: [
2428
{
2529
// SvelteKitのナビゲーションリクエスト(HTMLページ)をキャッシュ

0 commit comments

Comments
 (0)