| | <!DOCTYPE html> |
| | <html lang="zh-TW"> |
| | <head> |
| | <meta charset="UTF-8"> |
| | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| | <title>貼文管理 - KSTools</title> |
| | <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🔑</text></svg>"> |
| | <link rel="stylesheet" href="css/style.css"> |
| | <link rel="stylesheet" href="css/posts.css"> |
| | <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet"> |
| | |
| | <script type="module"> |
| | console.log('🚀 載入 Supabase...'); |
| | |
| | try { |
| | const { createClient } = await import('https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2/+esm'); |
| | window.supabase = { createClient }; |
| | window.supabaseLoaded = true; |
| | console.log('✅ Supabase 載入成功!'); |
| | window.dispatchEvent(new CustomEvent('supabaseReady')); |
| | } catch (error) { |
| | console.error('❌ ES Module 載入失敗:', error); |
| | const script = document.createElement('script'); |
| | script.src = 'https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2/dist/umd/supabase.min.js'; |
| | script.onload = () => { |
| | window.supabaseLoaded = true; |
| | window.dispatchEvent(new CustomEvent('supabaseReady')); |
| | }; |
| | document.head.appendChild(script); |
| | } |
| | </script> |
| | <style> |
| | |
| | .posts-container { |
| | max-width: 1400px; |
| | margin: 0 auto; |
| | padding: 2rem; |
| | } |
| | |
| | .top-nav { |
| | display: flex; |
| | justify-content: space-between; |
| | align-items: center; |
| | margin-bottom: 2rem; |
| | padding-bottom: 1rem; |
| | border-bottom: 1px solid var(--border-color); |
| | } |
| | |
| | .nav-left { |
| | display: flex; |
| | align-items: center; |
| | gap: 1rem; |
| | } |
| | |
| | .nav-left h1 { |
| | margin: 0; |
| | font-size: 1.5rem; |
| | color: var(--text-primary); |
| | } |
| | |
| | .page-description { |
| | color: var(--text-secondary); |
| | font-size: 0.9rem; |
| | margin: 0; |
| | } |
| | |
| | @media (max-width: 768px) { |
| | .posts-container { |
| | padding: 1rem; |
| | } |
| | |
| | .top-nav { |
| | flex-direction: column; |
| | gap: 1rem; |
| | align-items: stretch; |
| | } |
| | |
| | .nav-left, .nav-right { |
| | display: flex; |
| | justify-content: center; |
| | } |
| | } |
| | </style> |
| | </head> |
| | <body> |
| | |
| | <div id="loading-overlay" class="loading-overlay"> |
| | <div class="spinner"></div> |
| | <p>載入中...</p> |
| | </div> |
| |
|
| | |
| | <div class="posts-container"> |
| | |
| | <div class="top-nav"> |
| | <div class="nav-left"> |
| | <button class="btn btn-sm btn-outline" onclick="window.location.href='/dashboard.html'" title="回到管理中心"> |
| | <i class="fas fa-home"></i> |
| | </button> |
| | <div> |
| | <h1><i class="fas fa-newspaper"></i> 貼文管理</h1> |
| | <p class="page-description">管理版本更新貼文與郵件通知</p> |
| | </div> |
| | </div> |
| | <div class="nav-right"> |
| | <div class="header-actions"> |
| | <button class="btn btn-secondary" onclick="window.location.href='/versions.html'" title="前往版本管理"> |
| | <i class="fas fa-rocket"></i> |
| | <span>版本管理</span> |
| | </button> |
| | <div id="userInfo" class="user-info"> |
| | |
| | </div> |
| | </div> |
| | </div> |
| | </div> |
| |
|
| | |
| | <div id="postsContent"> |
| | <div class="text-center mt-5"> |
| | <div class="spinner mb-3"></div> |
| | <p>載入貼文中...</p> |
| | </div> |
| | </div> |
| | </div> |
| |
|
| | |
| | <div id="toastContainer" class="toast-container"></div> |
| |
|
| | |
| | <div id="modalContainer"></div> |
| |
|
| | |
| | <script src="config.js"></script> |
| | <script src="js/api.js"></script> |
| | <script src="js/utils.js"></script> |
| | <script src="js/auth.js"></script> |
| | <script src="js/components.js"></script> |
| | <script src="js/pages/posts.js"></script> |
| | <script> |
| | |
| | async function initPostsPage() { |
| | console.log('🚀 初始化貼文管理頁面...'); |
| | |
| | try { |
| | const container = document.getElementById('postsContent'); |
| | if (container && window.postsPage) { |
| | await window.postsPage.render(container); |
| | } else { |
| | container.innerHTML = ` |
| | <div class="empty-state"> |
| | <i class="fas fa-exclamation-triangle"></i> |
| | <h3>載入失敗</h3> |
| | <p>貼文模組載入失敗,請重新整理頁面</p> |
| | </div> |
| | `; |
| | } |
| | } catch (error) { |
| | console.error('初始化失敗:', error); |
| | Utils.showError('載入失敗', error.message); |
| | } |
| | } |
| | |
| | |
| | async function logout() { |
| | if (window.authManager) { |
| | await window.authManager.handleLogout(); |
| | } |
| | } |
| | |
| | |
| | document.addEventListener('DOMContentLoaded', async () => { |
| | if (window.authManager) { |
| | await window.authManager.initProtectedPage('posts', initPostsPage); |
| | } else { |
| | window.addEventListener('supabaseReady', async () => { |
| | if (window.authManager) { |
| | await window.authManager.initProtectedPage('posts', initPostsPage); |
| | } |
| | }); |
| | } |
| | }); |
| | </script> |
| | </body> |
| | </html> |
| |
|