Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@
</head>
<body>
<div id="root"></div>

<div id="cookie-banner" class="cookie-banner" style="display: none;">
<div class="cookie-banner-content">
<h3>隱私與 Cookie 政策</h3>
<p>我們使用 Cookie 來確保您在我們的網站上獲得最佳體驗。點擊「同意」表示您接受我們的 Cookie 政策。</p>
</div>
<div class="cookie-banner-actions">
<button id="cookie-btn-decline" class="cookie-btn btn-secondary">拒絕 (Decline)</button>
<button id="cookie-btn-accept" class="cookie-btn btn-primary">同意 (Accept)</button>
</div>
</div>

<script type="module" src="/src/cookie-consent.js"></script>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
88 changes: 88 additions & 0 deletions src/cookie-consent.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#cookie-banner {
position: fixed;
bottom: 24px;
right: 24px;
z-index: 99999;
background-color: #ffffff;
color: #1e293b;
width: 100%;
max-width: 400px;
padding: 24px;
border-radius: 12px;
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
display: none;
flex-direction: column;
gap: 16px;
border: 1px solid #e2e8f0;
font-family: 'Inter', 'Noto Sans TC', sans-serif;

/* Initial hidden state */
opacity: 0;
transform: translateY(30px);
transition: opacity 0.4s ease, transform 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}

#cookie-banner.visible {
opacity: 1;
transform: translateY(0);
}

.cookie-banner-content h3 {
margin: 0 0 8px 0;
font-size: 1.125rem;
font-weight: 600;
color: #0f172a;
}

.cookie-banner-content p {
margin: 0;
font-size: 0.875rem;
line-height: 1.5;
color: #475569;
}

.cookie-banner-actions {
display: flex;
gap: 12px;
justify-content: flex-end;
}

.cookie-btn {
padding: 8px 16px;
border-radius: 6px;
font-size: 0.875rem;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
border: none;
font-family: inherit;
}

.cookie-btn.btn-primary {
background-color: #3b82f6;
color: #ffffff;
}

.cookie-btn.btn-primary:hover {
background-color: #2563eb;
}

.cookie-btn.btn-secondary {
background-color: #f1f5f9;
color: #475569;
}

.cookie-btn.btn-secondary:hover {
background-color: #e2e8f0;
}

/* RWD */
@media (max-width: 480px) {
#cookie-banner {
bottom: 16px;
right: 16px;
left: 16px;
width: auto;
max-width: none;
}
}
42 changes: 42 additions & 0 deletions src/cookie-consent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import './cookie-consent.css';

const COOKIE_CONSENT_ACKNOWLEDGED = 'COOKIE_CONSENT_ACKNOWLEDGED';

function initCookieConsent() {
const banner = document.getElementById('cookie-banner');
if (!banner) return;

const hasConsented = localStorage.getItem(COOKIE_CONSENT_ACKNOWLEDGED);
if (hasConsented) {
return;
}

// Show banner
banner.style.display = 'flex';

// Wait for next frame to trigger CSS transition
requestAnimationFrame(() => {
requestAnimationFrame(() => {
banner.classList.add('visible');
});
});

const hideBanner = (value) => {
localStorage.setItem(COOKIE_CONSENT_ACKNOWLEDGED, value);
banner.classList.remove('visible');
banner.addEventListener('transitionend', () => {
if (!banner.classList.contains('visible')) {
banner.style.display = 'none';
}
}, { once: true });
};

document.getElementById('cookie-btn-accept')?.addEventListener('click', () => hideBanner('true'));
document.getElementById('cookie-btn-decline')?.addEventListener('click', () => hideBanner('false'));
}

if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initCookieConsent);
} else {
initCookieConsent();
}