- 引入 SQLite (UserDBDO) 存储用户、会话与服务器凭据 - 实现基于 GitHub 的 OAuth 授权登录工作流 - 新增用户个人空间界面,支持服务器节点的增删改查 - 支持服务器凭据的一键连接(通过 one-time-token 安全传递凭据) - 修改开源协议为 Apache License 2.0 - 更新中英文 README,添加新增功能的配置与部署说明
248 lines
14 KiB
HTML
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">></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----- ...粘贴私钥内容... -----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>
|