Files
HolodoriCalc/src/lib/components/AnalyticsConsent.svelte
T
dal4segno b97a4008bb
Publish GitHub Pages output / publish (push) Successful in 43s
feat: collect consented analysis usage statistics
2026-09-06 20:56:08 +09:00

114 lines
3.8 KiB
Svelte

<script lang="ts">
import { onMount } from 'svelte';
import { analytics } from '$lib/analytics.ts';
export let pagePath: string;
let mounted = false;
let dialogOpen = false;
let lastTrackedPath = '';
onMount(() => {
mounted = true;
dialogOpen = analytics.available && analytics.readConsent() === null;
});
$: if (mounted && analytics.readConsent() === 'granted' && pagePath !== lastTrackedPath) {
analytics.trackPageView(pagePath);
lastTrackedPath = pagePath;
}
function grantConsent() {
analytics.grantConsent();
dialogOpen = false;
analytics.trackPageView(pagePath);
lastTrackedPath = pagePath;
}
function denyConsent() {
analytics.denyConsent();
dialogOpen = false;
lastTrackedPath = '';
}
</script>
{#if analytics.available}
{#if dialogOpen}
<div class="analytics-consent" role="dialog" aria-labelledby="analytics-consent-title" aria-describedby="analytics-consent-description">
<div class="consent-copy">
<strong id="analytics-consent-title">방문 및 기능 이용 통계 수집</strong>
<p id="analytics-consent-description">
서비스 개선을 위해 페이지 방문 경로와 기기·지역의 대략적인 통계를 Google Analytics로 수집합니다.
동의하면 배치 분석 실행 시 선택한 카드 5장과 각 카드의 개화 단계, 악곡·난이도도 전송합니다.
전체 보유 카드 목록, 검색어와 계산 결과는 전송하지 않습니다.
수집 항목이 추가되어 기존 이용자에게도 다시 동의를 요청합니다. 거부해도 모든 기능을 이용할 수 있으며, 분석 설정에서 언제든 변경할 수 있습니다.
</p>
<a href="https://policies.google.com/privacy" target="_blank" rel="noreferrer">Google 개인정보처리방침 ↗</a>
</div>
<div class="consent-actions">
<button type="button" class="secondary" on:click={denyConsent}>거부</button>
<button type="button" class="primary" on:click={grantConsent}>동의</button>
</div>
</div>
{:else}
<button type="button" class="analytics-settings" on:click={() => dialogOpen = true}>분석 설정</button>
{/if}
{/if}
<style>
.analytics-consent {
position: fixed;
z-index: 100;
right: 18px;
bottom: 18px;
display: flex;
width: min(620px, calc(100% - 36px));
align-items: flex-end;
gap: 20px;
padding: 18px;
border: 1px solid rgb(239 139 182 / 45%);
border-radius: 14px;
background: rgb(24 28 36 / 97%);
box-shadow: 0 18px 50px rgb(0 0 0 / 42%);
color: #e8ebf1;
}
.consent-copy { min-width: 0; flex: 1; }
strong { display: block; margin-bottom: 6px; color: #f4c0d6; font-size: 15px; }
p { margin: 0 0 7px; color: #c3cad5; font-size: 13px; line-height: 1.55; }
a { color: #aeb9ca; font-size: 12px; }
.consent-actions { display: flex; flex: 0 0 auto; gap: 8px; }
button {
min-height: 38px;
padding: 8px 14px;
border: 1px solid transparent;
border-radius: 9px;
font: inherit;
font-size: 13px;
font-weight: 800;
cursor: pointer;
}
button:focus-visible { outline: 3px solid rgb(239 139 182 / 28%); outline-offset: 2px; }
.primary { color: #21121a; background: #ef8bb6; }
.secondary { border-color: #596273; color: #d4dae4; background: #303641; }
.analytics-settings {
position: fixed;
z-index: 90;
right: 12px;
bottom: 12px;
min-height: 30px;
padding: 5px 9px;
border-color: rgb(255 255 255 / 12%);
color: #8e98a8;
background: rgb(25 29 37 / 88%);
font-size: 11px;
}
@media (max-width: 560px) {
.analytics-consent { right: 12px; bottom: 12px; width: calc(100% - 24px); align-items: stretch; flex-direction: column; gap: 14px; }
.consent-actions { justify-content: flex-end; }
}
</style>