157 lines
9.7 KiB
HTML
157 lines
9.7 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>工作台 - Project Vibe</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<link rel="stylesheet" href="./css/main.css">
|
|
</head>
|
|
<body class="h-screen w-screen bg-[#1e293b] font-sans text-slate-100 flex flex-col overflow-hidden relative">
|
|
|
|
<!-- 顶栏 -->
|
|
<header class="h-16 bg-slate-900/80 backdrop-blur-md border-b border-slate-700 flex items-center justify-between px-8 z-50">
|
|
<h1 class="text-xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-blue-400 to-emerald-400 tracking-wider">
|
|
WORKSTATION 🚀
|
|
</h1>
|
|
<div class="flex items-center gap-4">
|
|
<span class="text-sm text-slate-400">工号: DEV-9527</span>
|
|
<button onclick="window.location.href='login.html'" class="text-xs bg-slate-800 hover:bg-rose-900/50 text-slate-300 hover:text-rose-400 px-3 py-1.5 rounded border border-slate-700 transition-colors">注销</button>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- 主容器 -->
|
|
<div class="flex-1 flex overflow-hidden p-6 gap-6 relative z-10">
|
|
|
|
<!-- 左侧:新建项目 -->
|
|
<div class="w-1/3 max-w-sm flex flex-col gap-6">
|
|
<div class="bg-gradient-to-br from-slate-800/80 to-slate-900/80 border border-slate-600 rounded-2xl p-8 flex flex-col items-center text-center shadow-lg">
|
|
<div class="text-6xl mb-6">📝</div>
|
|
<h2 class="text-2xl font-bold text-white mb-2">新的 Sprint</h2>
|
|
<p class="text-sm text-slate-400 mb-8 leading-relaxed">你的上一个项目由于经费见底被公司强制终止。<br>准备好接手这个充满技术债的屎山新盘了吗?</p>
|
|
<button onclick="window.location.href='index.html'" class="w-full bg-blue-600 hover:bg-blue-500 text-white font-bold py-4 px-6 rounded-xl shadow-[0_0_20px_rgba(37,99,235,0.4)] transition-transform hover:scale-105 tracking-widest text-lg uppercase flex justify-center items-center gap-2">
|
|
<span>开始接锅</span>
|
|
<span class="text-2xl">➔</span>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="bg-slate-800/50 border border-slate-700 rounded-xl p-4 flex gap-4 text-sm text-slate-400 items-center">
|
|
<div class="text-3xl">🏆</div>
|
|
<div>
|
|
<div class="font-bold text-slate-200 mb-1">历史最高纪录</div>
|
|
<div class="font-mono text-emerald-400">总资金: $ 25,000</div>
|
|
<div class="font-mono text-blue-400">存活 Sprint: 3</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 右侧:我的卡组与图鉴 -->
|
|
<div class="flex-1 bg-slate-800/60 border border-slate-600 rounded-2xl flex flex-col overflow-hidden shadow-lg">
|
|
<div class="p-4 border-b border-slate-700 bg-slate-900/40 flex justify-between items-center">
|
|
<h2 class="text-lg font-bold text-white flex items-center gap-2">🗃️ 我的卡组 (Deck Library)</h2>
|
|
<span class="text-xs bg-slate-800 text-slate-400 px-2 py-1 rounded">当前已解锁 5/12 张</span>
|
|
</div>
|
|
|
|
<!-- 卡片网格区 -->
|
|
<div class="flex-1 overflow-y-auto p-6" id="deck-container">
|
|
<div class="text-center text-slate-400 py-10">加载卡池数据中...</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="./js/main.js"></script>
|
|
<script>
|
|
// Override game loop in dashboard so it doesn't crash or run
|
|
window.gameInterval = null;
|
|
window.secondInterval = null;
|
|
|
|
function renderDeck() {
|
|
const container = document.getElementById('deck-container');
|
|
const goodCards = [];
|
|
const badCards = [];
|
|
|
|
Object.values(CardTemplates).forEach(tpl => {
|
|
if (tpl.type === 'negative' || tpl.type === 'crisis' || tpl.tags.includes('bad') || tpl.tags.includes('crisis')) {
|
|
badCards.push(tpl);
|
|
} else {
|
|
goodCards.push(tpl);
|
|
}
|
|
});
|
|
|
|
// Find recipes for a card
|
|
const getRecipes = (cardId) => {
|
|
return Recipes.filter(r => r.inputs.includes(cardId)).map(r => {
|
|
const otherInput = r.inputs.find(i => i !== cardId) || cardId;
|
|
const out1 = r.outputs[0]?.templateId;
|
|
|
|
const icon1 = `<span title="${CardTemplates[otherInput]?.name || '?'}" class="cursor-help border-b border-dashed border-slate-500">${CardTemplates[otherInput]?.icon || '?'}</span>`;
|
|
const icon2 = `<span title="${CardTemplates[cardId]?.name || '?'}" class="cursor-help border-b border-dashed border-slate-500">${CardTemplates[cardId]?.icon || '?'}</span>`;
|
|
const outIcon = out1 ? `<span title="${CardTemplates[out1]?.name}" class="cursor-help border-b border-dashed border-emerald-500">${CardTemplates[out1]?.icon}</span>` : '?';
|
|
|
|
return `<div class="flex items-center gap-1">${icon1} <span>+</span> ${icon2} <span class="text-emerald-400 font-bold ml-1">➔</span> ${outIcon}</div>`;
|
|
}).join('');
|
|
};
|
|
|
|
const buildGrid = (cards, isBad) => {
|
|
let html = '<div class="grid grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">';
|
|
cards.forEach(tpl => {
|
|
const isLocked = !isBad && tpl.unlocked === false;
|
|
const recs = getRecipes(tpl.id);
|
|
|
|
let colorClasses = '';
|
|
if (isLocked) {
|
|
colorClasses = 'bg-slate-900/60 border-slate-700/50 grayscale opacity-50 relative pointer-events-none';
|
|
} else if (isBad) {
|
|
colorClasses = 'bg-red-900/20 border-red-600/50 hover:border-red-400 shadow-[0_0_8px_rgba(220,38,38,0.2)] hover:scale-105 group relative overflow-hidden transition-transform';
|
|
} else {
|
|
colorClasses = 'bg-blue-900/20 border-blue-600/50 hover:border-blue-400 shadow-[0_0_8px_rgba(37,99,235,0.2)] hover:scale-105 group relative overflow-hidden transition-transform';
|
|
}
|
|
|
|
const textClass = isBad ? 'text-red-300' : (isLocked ? 'text-slate-400' : 'text-blue-200');
|
|
const tagClass = isBad ? 'bg-red-900 text-red-300' : (isLocked ? 'bg-slate-800 text-slate-500' : 'bg-blue-900 text-blue-300');
|
|
|
|
const lockOverlay = isLocked ? `<div class="absolute inset-0 bg-slate-950/20 flex items-center justify-center backdrop-blur-[2px] z-10"><span class="text-3xl text-slate-300">🔒</span></div>` : '';
|
|
|
|
html += `
|
|
<div class="${colorClasses} border-2 rounded-xl p-4 flex flex-col items-center text-center">
|
|
${lockOverlay}
|
|
<div class="text-5xl mb-2 relative z-0">${tpl.icon}</div>
|
|
<h3 class="font-bold ${textClass} mb-1 relative z-0">${isLocked ? '???' : tpl.name}</h3>
|
|
<span class="text-[10px] ${tagClass} px-2 py-0.5 rounded mb-3 relative z-0">${tpl.type}</span>
|
|
<p class="text-xs text-slate-400 mb-4 h-10 relative z-0">${isLocked ? '在后续迭代中解锁。' : tpl.desc}</p>
|
|
<div class="w-full bg-slate-900/60 rounded p-2 text-left min-h-[60px] relative z-20">
|
|
<div class="text-[10px] ${isBad ? 'text-rose-500' : 'text-slate-500'} uppercase tracking-widest mb-1 font-bold">${isBad ? (tpl.trigger === 'countdown' ? '倒计时惩罚' : '惩罚结果') : '相关配方'}</div>
|
|
<div class="text-xs text-slate-300 flex flex-col gap-1 mb-2">${isBad ? ('<span class="text-rose-400">' + (tpl.penalty || '无') + '</span>') : (recs || '<span class="text-slate-600">无配方</span>')}</div>
|
|
|
|
${isBad ? `
|
|
<div class="text-[10px] text-emerald-500 uppercase tracking-widest mb-1 font-bold">化解方案</div>
|
|
<div class="text-xs text-emerald-300 flex flex-wrap items-center gap-1">拖入 ${tpl.cancelWith ? tpl.cancelWith.map(id => `<span title="${CardTemplates[id]?.name}" class="cursor-help border-b border-dashed border-emerald-500 text-lg">${CardTemplates[id]?.icon}</span>`).join(' <span class="text-emerald-500/50">/</span> ') : ''} 抵消</div>
|
|
` : ''}
|
|
</div>
|
|
</div>`;
|
|
});
|
|
html += '</div>';
|
|
return html;
|
|
};
|
|
|
|
container.innerHTML = `
|
|
<div class="mb-4">
|
|
<h3 class="text-sm font-bold text-blue-400 uppercase tracking-widest mb-4">🗃️ 己方手牌 (${goodCards.length} 张)</h3>
|
|
${buildGrid(goodCards, false)}
|
|
</div>
|
|
|
|
<div class="mt-8 mb-4 flex items-center gap-4">
|
|
<div class="h-px bg-slate-700 flex-1"></div>
|
|
<h3 class="text-sm font-bold text-rose-400 uppercase tracking-widest">⚠️ 系统风险 (${badCards.length} 张)</h3>
|
|
<div class="h-px bg-slate-700 flex-1"></div>
|
|
</div>
|
|
${buildGrid(badCards, true)}
|
|
`;
|
|
|
|
document.querySelector('.text-xs.bg-slate-800').textContent = `当前已录入 ${goodCards.length + badCards.length} 张卡`;
|
|
}
|
|
|
|
renderDeck();
|
|
</script>
|
|
</body>
|
|
</html> |