Files
CloudSSH/frontend/index.html
T
GreenhandTan c60b004fb4 feat: 新增 GitHub OAuth 登录与个人空间服务器管理功能
- 引入 SQLite (UserDBDO) 存储用户、会话与服务器凭据
- 实现基于 GitHub 的 OAuth 授权登录工作流
- 新增用户个人空间界面,支持服务器节点的增删改查
- 支持服务器凭据的一键连接(通过 one-time-token 安全传递凭据)
- 修改开源协议为 Apache License 2.0
- 更新中英文 README,添加新增功能的配置与部署说明
2026-06-21 10:25:45 +08:00

248 lines
14 KiB
HTML

<!DOCTYPE html>
<html class="dark" lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<title>CloudSSH</title>
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;600;700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet">
<script>
tailwind.config = {
darkMode: "class",
theme: {
extend: {
colors: {
"background": "#131313",
"on-surface": "#e5e2e1",
"on-surface-variant": "#bbccb0",
"outline": "#86957d",
"outline-variant": "#3c4b36",
"primary-container": "#4af626",
"on-primary-fixed": "#022100",
"surface": "#131313",
"surface-variant": "#353534",
"secondary-container": "#14d1ff",
"secondary-fixed": "#b7eaff",
"error": "#ffb4ab",
"error-container": "#93000a",
"surface-container-lowest": "#0e0e0e"
},
fontFamily: {
"body": ["JetBrains Mono"],
"headline": ["JetBrains Mono"],
"label": ["JetBrains Mono"],
"code": ["JetBrains Mono"]
}
}
}
}
</script>
<link rel="stylesheet" href="/src/style.css" />
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
</head>
<body class="min-h-screen font-body text-sm overflow-hidden">
<div id="app">
<!-- Login Page (匿名连接) -->
<div id="auth-section" class="min-h-screen flex items-center justify-center p-6 relative">
<div class="scanlines"></div>
<div class="flicker"></div>
<main class="w-full max-w-md relative z-10">
<div class="mb-8 text-center">
<div class="text-3xl font-bold text-[#4af626] tracking-tighter mb-2">CloudSSH<span class="blinking-cursor"></span></div>
</div>
<div class="cyber-box p-6 shadow-2xl relative">
<div class="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-[#4af626] to-transparent opacity-50"></div>
<div class="flex items-center justify-between mb-8 pb-4 border-b border-[#3c4b36]">
<span class="text-xs font-bold tracking-[0.1em] text-[#14d1ff]">CONNECTION_PARAMETERS</span>
<span class="material-symbols-outlined text-[#14d1ff]" style="font-variation-settings: 'FILL' 0;">terminal</span>
</div>
<div id="connection-form-container"></div>
</div>
<div class="mt-8 text-center text-[13px] text-[#bbccb0] opacity-60">SYSTEM READY. WAITING FOR INPUT.</div>
<div class="mt-4 text-center">
<a href="https://github.com/newbietan/CloudSSH" class="text-[13px] text-[#4af626] opacity-60 hover:opacity-100 transition-colors tracking-widest uppercase">[ GitHub Open Source ]</a>
</div>
</main>
</div>
<!-- User Space Page (登录后) -->
<div id="user-space-section" class="hidden min-h-screen flex-col bg-background text-on-surface">
<!-- TopAppBar -->
<header class="flex justify-between items-center w-full px-6 h-16 bg-background border-b border-outline-variant z-50">
<div class="flex items-center gap-6">
<h1 class="text-2xl font-bold text-primary-container tracking-tighter cursor-pointer" id="user-space-logo">CloudSSH</h1>
</div>
<div class="flex items-center gap-4">
<div id="user-info" class="flex items-center gap-3">
<!-- 动态渲染:头像 + 用户名 -->
</div>
<button id="logout-btn" class="hover:opacity-80 transition-opacity cursor-pointer p-1 flex items-center justify-center text-[#ffb4ab]" title="Logout">
<span class="material-symbols-outlined" style="font-variation-settings: 'FILL' 0;">logout</span>
</button>
</div>
</header>
<!-- Server List Area -->
<main class="flex-1 p-6 relative overflow-auto custom-scrollbar">
<div class="scanlines pointer-events-none"></div>
<div class="max-w-5xl mx-auto">
<!-- 顶部操作栏 -->
<div class="flex justify-between items-center mb-6">
<div>
<h2 class="text-lg font-bold text-[#4af626] tracking-[0.1em]">SERVER_LIST</h2>
<p class="text-xs text-[#bbccb0] opacity-60 mt-1">Manage your SSH connections</p>
</div>
<button id="add-server-btn" class="cyber-button py-2 px-4 text-xs font-bold tracking-[0.1em] uppercase flex items-center gap-2">
<span class="material-symbols-outlined" style="font-size: 16px;">add</span>
ADD_SERVER
</button>
</div>
<!-- 服务器卡片网格 -->
<div id="server-grid" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<!-- 由 JS 动态渲染 -->
</div>
<!-- 空状态 -->
<div id="empty-state" class="hidden flex-col items-center justify-center py-20">
<span class="material-symbols-outlined text-[#3c4b36] mb-4" style="font-size: 64px; font-variation-settings: 'FILL' 0;">dns</span>
<p class="text-[#bbccb0] text-sm tracking-[0.1em] mb-2">NO_SERVERS_CONFIGURED</p>
<p class="text-[#3c4b36] text-xs mb-6">Add a server to get started</p>
<button id="empty-add-btn" class="cyber-button py-2 px-6 text-xs font-bold tracking-[0.1em] uppercase flex items-center gap-2">
<span class="material-symbols-outlined" style="font-size: 16px;">add</span>
ADD_FIRST_SERVER
</button>
</div>
</div>
</main>
<!-- Footer -->
<footer class="px-6 py-2 flex justify-between items-center z-50 bg-background/80 backdrop-blur-md border-t border-outline-variant text-xs h-12">
<div class="text-secondary-container opacity-60">© <span id="user-copyright-year"></span> CLOUD_SSH_TERMINAL - https://github.com/newbietan/CloudSSH</div>
<div class="flex gap-4">
<a class="text-on-surface-variant opacity-60 hover:opacity-100 transition-opacity" href="https://github.com/newbietan/CloudSSH">Documentation</a>
</div>
</footer>
</div>
<!-- Server Modal (添加/编辑) -->
<div id="server-modal" class="hidden fixed inset-0 z-[100] flex items-center justify-center">
<div class="modal-overlay absolute inset-0" id="modal-backdrop"></div>
<div class="cyber-box p-6 shadow-2xl relative z-10 w-full max-w-md mx-4">
<div class="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-[#14d1ff] to-transparent opacity-50"></div>
<div class="flex items-center justify-between mb-6 pb-4 border-b border-[#3c4b36]">
<span id="modal-title" class="text-xs font-bold tracking-[0.1em] text-[#14d1ff]">ADD_SERVER</span>
<button id="modal-close-btn" class="text-[#bbccb0] hover:text-[#4af626] transition-colors cursor-pointer">
<span class="material-symbols-outlined" style="font-size: 20px;">close</span>
</button>
</div>
<form id="server-form" class="space-y-4">
<div>
<label class="block text-xs font-bold tracking-[0.1em] text-[#bbccb0] mb-2">SERVER_NAME</label>
<div class="flex items-center">
<span class="material-symbols-outlined text-[#bbccb0] mr-2" style="font-size: 16px;">label</span>
<input id="server-name" class="terminal-input text-[13px]" placeholder="My Server" type="text" required>
</div>
</div>
<div class="grid grid-cols-4 gap-4">
<div class="col-span-3">
<label class="block text-xs font-bold tracking-[0.1em] text-[#bbccb0] mb-2">HOST_ADDRESS</label>
<div class="flex items-center">
<span class="text-[#bbccb0] mr-2">&gt;</span>
<input id="server-host" class="terminal-input text-[13px]" placeholder="192.168.1.1" type="text" required>
</div>
</div>
<div class="col-span-1">
<label class="block text-xs font-bold tracking-[0.1em] text-[#bbccb0] mb-2">PORT</label>
<div class="flex items-center">
<span class="text-[#bbccb0] mr-2">:</span>
<input id="server-port" class="terminal-input text-[13px]" placeholder="22" type="text" value="22">
</div>
</div>
</div>
<div>
<label class="block text-xs font-bold tracking-[0.1em] text-[#bbccb0] mb-2">AUTH_USER</label>
<div class="flex items-center">
<span class="material-symbols-outlined text-[#bbccb0] mr-2" style="font-size: 16px;">person</span>
<input id="server-username" class="terminal-input text-[13px]" placeholder="root" type="text" required>
</div>
</div>
<div>
<label class="block text-xs font-bold tracking-[0.1em] text-[#bbccb0] mb-2">AUTH_METHOD</label>
<div class="flex gap-2 mb-3">
<button type="button" id="modal-auth-tab-password" class="auth-tab px-3 py-1 text-[11px] font-bold tracking-[0.1em] border border-[#4af626] text-[#4af626] bg-transparent cursor-pointer transition-all" style="background:#4af626;color:#0a0a0a;">PASSWORD</button>
<button type="button" id="modal-auth-tab-key" class="auth-tab px-3 py-1 text-[11px] font-bold tracking-[0.1em] border border-[#3c4b36] text-[#bbccb0] bg-transparent cursor-pointer transition-all">PRIVATE_KEY</button>
</div>
<div id="modal-password-section">
<div class="flex items-center">
<span class="material-symbols-outlined text-[#bbccb0] mr-2" style="font-size: 16px;">key</span>
<input id="server-password" class="terminal-input text-[13px]" placeholder="••••••••" type="password">
</div>
</div>
<div id="modal-key-section" style="display:none;">
<textarea id="server-private-key" class="terminal-input text-[11px] w-full" rows="4" placeholder="-----BEGIN OPENSSH PRIVATE KEY-----&#10;...粘贴私钥内容...&#10;-----END OPENSSH PRIVATE KEY-----" style="resize:vertical;border:1px solid #3c4b36;padding:8px;"></textarea>
</div>
</div>
<div class="pt-2">
<button id="server-submit-btn" class="cyber-button w-full py-3 px-4 text-xs font-bold tracking-[0.1em] uppercase flex items-center justify-center gap-2 bg-[#4af626] text-[#022100]" type="button">
<span class="material-symbols-outlined" style="font-size: 18px;">save</span>
SAVE_SERVER
</button>
</div>
</form>
</div>
</div>
<!-- Terminal Page -->
<div id="terminal-section" class="hidden h-screen flex-col bg-background text-on-surface">
<!-- TopAppBar -->
<header class="flex justify-between items-center w-full px-6 h-16 bg-background border-b border-outline-variant z-50">
<div class="flex items-center gap-6">
<h1 class="text-2xl font-bold text-primary-container tracking-tighter cursor-pointer">CloudSSH</h1>
</div>
<div class="flex items-center gap-4 text-primary-container">
<select id="theme-selector" class="bg-surface-variant text-on-surface-variant text-xs py-1 px-2 border-none outline-none cursor-pointer rounded">
<option value="cyberpunk">Cyberpunk</option>
<option value="glacier">Glacier</option>
<option value="gruvbox">Gruvbox</option>
</select>
<button id="disconnect-btn" class="hover:opacity-80 transition-opacity cursor-pointer p-1 flex items-center justify-center" title="Disconnect">
<span class="material-symbols-outlined" style="font-variation-settings: 'FILL' 0;">power_settings_new</span>
</button>
</div>
</header>
<!-- Main Terminal -->
<main class="flex-1 p-6 pb-14 relative bg-surface-container-lowest overflow-hidden">
<div class="absolute inset-0 scanline pointer-events-none z-10 opacity-30"></div>
<div id="terminal-wrapper" class="h-full w-full border border-outline-variant bg-[#0a0a0a] p-4 overflow-hidden font-code text-[13px] text-primary-container relative z-0 flex flex-col">
<!-- Status Bar -->
<div class="flex justify-between items-center border-b border-surface-variant pb-2 mb-4 text-on-surface-variant opacity-80 text-[11px]">
<div class="flex gap-6">
<span id="term-status" class="flex items-center gap-1"><div class="w-2 h-2 bg-primary-container"></div> Connected</span>
<span id="term-host">Host: -</span>
<span id="term-user">User: -</span>
<span id="term-port">Port: -</span>
</div>
<div>
<span id="term-info"></span>
</div>
</div>
<!-- Terminal Output -->
<div id="terminal-container" class="flex-1 overflow-hidden"></div>
</div>
</main>
<!-- Footer -->
<footer class="fixed bottom-0 left-0 w-full px-6 py-2 flex justify-between items-center z-50 bg-background/80 backdrop-blur-md border-t border-outline-variant text-xs h-12">
<div class="text-secondary-container opacity-60">© <span id="copyright-year"></span> CLOUD_SSH_TERMINAL - https://github.com/newbietan/CloudSSH</div>
<div class="flex gap-4">
<a class="text-on-surface-variant opacity-60 hover:opacity-100 transition-opacity" href="https://github.com/newbietan/CloudSSH">Documentation</a>
</div>
</footer>
</div>
</div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>