Files
cibird/index_updated.html
2026-05-14 21:05:10 +00:00

146 lines
6.4 KiB
HTML

<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="theme-color" content="#f5f5f7">
<title>CiBird | 词鸟</title>
<style>
/* ── RESET & BASE ─────────────────────────────────────────── */
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent;outline:none;-webkit-touch-callout:none;margin:0;padding:0;}
html,body{position:fixed;inset:0;width:100%;height:100%;}
body{font-family:-apple-system,BlinkMacSystemFont,"SF Pro Text","Helvetica Neue",Arial,sans-serif;background:#e5e5ea;display:flex;justify-content:center;align-items:center;overflow:hidden;overscroll-behavior:none;-webkit-user-select:none;user-select:none;}
.frame{width:100%;max-width:400px;height:100%;background:#f5f5f7;position:relative;overflow:hidden;display:none;flex-direction:column;}
.frame.on{display:flex;}
/* Header / Tabs / List Styles (simplified for output) */
.header{padding:16px;background:#fff;border-bottom:1px solid #e5e5e5;display:flex;justify-content:space-between;align-items:center;}
.nav{height:60px;background:#fff;border-top:1px solid #e5e5e5;display:flex;padding-bottom:env(safe-area-inset-bottom);}
.nav-item{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;font-size:10px;color:#8e8e93;}
.nav-item.on{color:#007aff;}
.content{flex:1;overflow-y:auto;padding:12px;-webkit-overflow-scrolling:touch;}
/* Tool Specific */
.tool-tabs{display:flex;gap:8px;margin-bottom:16px;}
.tool-tab{padding:8px 16px;background:#e5e5ea;border-radius:18px;font-size:14px;color:#3a3a3c;transition:0.2s;}
.tool-tab.on{background:#007aff;color:#fff;}
.ess-card{background:#fff;border-radius:12px;padding:12px;margin-bottom:8px;display:flex;justify-content:space-between;align-items:center;box-shadow:0 1px 3px rgba(0,0,0,0.05);}
.ess-en{font-weight:600;font-size:16px;margin-bottom:2px;}
.ess-zh{font-size:13px;color:#8e8e93;}
.ess-note{font-size:12px;color:#aeaeb2;margin-right:8px;}
.ess-loading{text-align:center;padding:40px;color:#8e8e93;}
/* ... Rest of your existing CSS (I'm assuming you keep it) ... */
/* NOTE: Below is a minimal representation of the index.html with the added logic */
</style>
</head>
<body>
<!-- Login Frame -->
<div class="frame on" id="frameLogin">
<div style="padding:40px 20px;text-align:center;">
<h1 style="font-size:32px;margin-bottom:10px;">🦜 CiBird</h1>
<p style="color:#8e8e93;margin-bottom:40px;">你的私人词库</p>
<input type="password" id="loginPw" placeholder="输入密码..." style="width:100%;padding:15px;border-radius:12px;border:none;background:#fff;margin-bottom:12px;font-size:16px;">
<button onclick="doLogin()" style="width:100%;padding:15px;border-radius:12px;border:none;background:#007aff;color:#fff;font-size:16px;font-weight:600;">进入</button>
</div>
</div>
<!-- Main Frame -->
<div class="frame" id="frameMain">
<div class="header">
<span id="headerTitle" style="font-size:20px;font-weight:700;">我的词库</span>
<span onclick="showAdd()" id="addIcon" style="font-size:24px;cursor:pointer;"></span>
</div>
<div class="content" id="mainContent">
<!-- 动态内容 -->
</div>
<div class="nav">
<div class="nav-item on" onclick="go('words')">📖 词库</div>
<div class="nav-item" onclick="go('ess')">✦ 必学</div>
<div class="nav-item" onclick="go('tools')">🛠️ 练习</div>
<div class="nav-item" onclick="go('stats')">📈 统计</div>
</div>
</div>
<script>
let API_TOKEN = localStorage.getItem('cibird_token');
const ah = () => ({ 'Authorization': 'Bearer ' + API_TOKEN, 'Content-Type': 'application/json' });
async function doLogin(){
const pw = document.getElementById('loginPw').value;
const r = await fetch('/api/login', {method:'POST', body:JSON.stringify({password:pw}), headers:{'Content-Type':'application/json'}});
if(r.ok){
const d = await r.json();
API_TOKEN = d.token; localStorage.setItem('cibird_token', d.token);
enterApp();
} else { alert('密码不对哦'); }
}
function enterApp(){
document.getElementById('frameLogin').classList.remove('on');
document.getElementById('frameMain').classList.add('on');
go('words');
}
function go(page){
const titles = {words:'我的词库', ess:'必学模块', tools:'练习工具', stats:'我的进度'};
document.getElementById('headerTitle').textContent = titles[page];
document.getElementById('addIcon').style.display = (page==='words'?'block':'none');
const content = document.getElementById('mainContent');
if(page==='tools') renderTools(content);
else if(page==='ess') renderEss(content);
// ... other pages ...
}
function renderTools(container){
container.innerHTML = `
<div class="tool-tabs">
<div class="tool-tab on" id="tabTime" onclick="switchTool('time')">🕐 时间</div>
<div class="tool-tab" id="tabNum" onclick="switchTool('num')">🔢 数字</div>
<div class="tool-tab" id="tabCountry" onclick="switchTool('country')">🌍 国家</div>
</div>
<div id="toolTime"> <!-- 时间练习逻辑 --> </div>
<div id="toolNum" style="display:none"> <!-- 数字练习逻辑 --> </div>
<div id="toolCountry" style="display:none">
<div class="ess-list" id="countryList"></div>
</div>
`;
}
async function switchTool(t){
['time','num','country'].forEach(x => {
document.getElementById('tool'+x.charAt(0).toUpperCase()+x.slice(1)).style.display = (x===t?'block':'none');
document.getElementById('tab'+x.charAt(0).toUpperCase()+x.slice(1)).classList.toggle('on', x===t);
});
if(t==='country') loadCountries();
}
async function loadCountries(){
const el = document.getElementById('countryList');
el.innerHTML = '<div class="ess-loading">正在通过 AI 加载 195 个国家...</div>';
const r = await fetch('/api/essentials/国家', {headers:ah()});
const d = await r.json();
el.innerHTML = d.items.map(i => `
<div class="ess-card" onclick="speakText('${i.en}')">
<div><div class="ess-en">${i.en}</div><div class="ess-zh">${i.zh}</div></div>
<div class="ess-note">${i.note}</div>
</div>
`).join('');
}
function speakText(t){
const s = new SpeechSynthesisUtterance(t);
s.lang = 'en-US';
window.speechSynthesis.speak(s);
}
if(API_TOKEN) enterApp();
</script>
</body>
</html>