M9: PWA — 홈 화면에 추가, 오프라인 안내
- 매니페스트·아이콘(192/512/maskable/apple-touch, scripts/pwa-icons.ts로 다시 만들기) - 손으로 쓴 서비스 워커(apps/web/sw.js): 빌드 때 Vite 플러그인이 빌드 ID를 넣음. 페이지는 네트워크만(오프라인이면 offline.html), /assets/*만 캐시 먼저(200개까지), /api·/ws·/healthz·/internal은 손대지 않음 - 오프라인 안내 페이지, 방 밖에서도 "인터넷 연결이 없어요" 띠 - 홈 아래 "홈 화면에 추가" 카드(설치 버튼, iOS는 공유 메뉴 안내, 닫으면 기억) - 테스트: apps/web/src/sw.test.ts, e2e/pwa.e2e.ts(E2E_PORT), a11y.e2e.ts도 E2E_PORT 읽기 - 문서: 07 §11, 11 배포(no-cache 대상), README 확인 목록 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
BIN
apps/web/public/icons/apple-touch-icon.png
Normal file
BIN
apps/web/public/icons/apple-touch-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
BIN
apps/web/public/icons/icon-192.png
Normal file
BIN
apps/web/public/icons/icon-192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.0 KiB |
BIN
apps/web/public/icons/icon-512.png
Normal file
BIN
apps/web/public/icons/icon-512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
BIN
apps/web/public/icons/icon-maskable-512.png
Normal file
BIN
apps/web/public/icons/icon-maskable-512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.0 KiB |
19
apps/web/public/manifest.webmanifest
Normal file
19
apps/web/public/manifest.webmanifest
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"id": "/",
|
||||
"name": "같이 놀자 보드게임",
|
||||
"short_name": "같이 놀자",
|
||||
"description": "광고 없이 가볍게, 링크 하나로 친구·가족과 바로 즐기는 온라인 보드게임",
|
||||
"lang": "ko",
|
||||
"dir": "ltr",
|
||||
"start_url": "/",
|
||||
"scope": "/",
|
||||
"display": "standalone",
|
||||
"background_color": "#f7f5f0",
|
||||
"theme_color": "#f7f5f0",
|
||||
"categories": ["games", "entertainment"],
|
||||
"icons": [
|
||||
{ "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png", "purpose": "any" },
|
||||
{ "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any" },
|
||||
{ "src": "/icons/icon-maskable-512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" }
|
||||
]
|
||||
}
|
||||
95
apps/web/public/offline.html
Normal file
95
apps/web/public/offline.html
Normal file
@@ -0,0 +1,95 @@
|
||||
<!doctype html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<meta name="theme-color" content="#F7F5F0" />
|
||||
<!-- Served by the service worker when a page can't load. No scripts (CSP blocks inline JS) and no other files. -->
|
||||
<title>인터넷 연결이 없어요 · 같이 놀자 보드게임</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #f7f5f0;
|
||||
--surface: #fff;
|
||||
--text: #1c1e21;
|
||||
--text-sub: #4a4f57;
|
||||
--primary: #2563eb;
|
||||
--primary-text: #fff;
|
||||
--focus: #f59e0b;
|
||||
color-scheme: light dark;
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--bg: #16181d;
|
||||
--surface: #20232a;
|
||||
--text: #f2f3f5;
|
||||
--text-sub: #b8bcc4;
|
||||
--primary: #5b8def;
|
||||
--primary-text: #0b1020;
|
||||
}
|
||||
}
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
min-height: 100%;
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
font: 500 17px/1.5 -apple-system, BlinkMacSystemFont, 'Apple SD Gothic Neo', 'Malgun Gothic', 'Noto Sans KR', sans-serif;
|
||||
}
|
||||
main {
|
||||
box-sizing: border-box;
|
||||
min-height: 100vh;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
padding: 24px;
|
||||
}
|
||||
.card {
|
||||
background: var(--surface);
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
|
||||
padding: 32px 24px;
|
||||
max-width: 420px;
|
||||
text-align: center;
|
||||
}
|
||||
.icon {
|
||||
font-size: 48px;
|
||||
line-height: 1;
|
||||
}
|
||||
h1 {
|
||||
font-size: 1.4rem;
|
||||
font-weight: 700;
|
||||
margin: 16px 0 8px;
|
||||
}
|
||||
p {
|
||||
color: var(--text-sub);
|
||||
margin: 0 0 24px;
|
||||
}
|
||||
a.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 56px;
|
||||
padding: 0 28px;
|
||||
border-radius: 12px;
|
||||
background: var(--primary);
|
||||
color: var(--primary-text);
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
}
|
||||
a.btn:focus-visible {
|
||||
outline: 3px solid var(--focus);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="card">
|
||||
<div class="icon" aria-hidden="true">📡</div>
|
||||
<h1>인터넷 연결이 없어요</h1>
|
||||
<p>와이파이나 데이터가 켜져 있는지 확인한 뒤 [다시 시도]를 눌러 주세요.</p>
|
||||
<a class="btn" href="">다시 시도</a>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user