Files
workspace/code/base-project/base-app/test2.html
T
2025-11-20 17:30:28 +08:00

338 lines
11 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover" />
<title>共享空间 — 邀请 / 加入</title>
<style>
:root{
--bg: #f6f7fb;
--card: #ffffff;
--muted: #9aa4b2;
--accent: #5b8cff;
--danger: #ff6b6b;
--radius: 12px;
--gap: 12px;
--shadow: 0 6px 18px rgba(22,27,40,0.06);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial;
}
/* Reset / basic */
*{box-sizing:border-box}
html,body{height:100%}
body{
margin:0;
background:linear-gradient(180deg, var(--bg), #eef2ff 60%);
color:#0f1724;
-webkit-font-smoothing:antialiased;
-moz-osx-font-smoothing:grayscale;
padding:16px;
}
/* Container */
.screen{
max-width:480px;
margin:0 auto;
}
header.appbar{
display:flex;
align-items:center;
gap:12px;
padding:8px 4px;
margin-bottom:12px;
}
.title{
font-size:18px;
font-weight:600;
}
.subtitle{
display:block;
font-size:12px;
color:var(--muted);
margin-top:2px;
}
/* Cards */
.card{
background:var(--card);
border-radius:var(--radius);
box-shadow:var(--shadow);
padding:14px;
margin-bottom:var(--gap);
}
/* Invite area */
.invite-top{
display:flex;
gap:12px;
align-items:center;
}
.space-avatar{
width:56px;height:56px;border-radius:12px;background:linear-gradient(135deg,#7fb6ff,#5b8cff);
display:flex;align-items:center;justify-content:center;color:#fff;font-weight:700;font-size:20px;
}
.space-info{
flex:1;
}
.space-name{font-weight:600;font-size:16px}
.space-meta{font-size:12px;color:var(--muted);margin-top:4px}
.invite-row{
margin-top:12px;display:flex;gap:8px;
}
.btn{
flex:1;
border:0;padding:10px 12px;border-radius:10px;font-weight:600;
background:var(--accent);color:#fff;cursor:pointer;
box-shadow:0 6px 12px rgba(91,140,255,0.18);
}
.btn.ghost{background:transparent;color:var(--accent);border:1px solid rgba(91,140,255,0.12);box-shadow:none}
.btn.danger{background:var(--danger);box-shadow:0 6px 12px rgba(255,107,107,0.16)}
/* Invite code box */
.code-box{display:flex;align-items:center;justify-content:space-between;padding:10px;border-radius:10px;background:#f4f7ff;border:1px dashed rgba(91,140,255,0.18)}
.code-text{font-weight:700;letter-spacing:2px;font-size:16px}
.code-actions{display:flex;gap:8px}
/* Join section */
.join-input{
display:flex;gap:8px;margin-top:8px;
}
.input{
flex:1;padding:10px;border-radius:10px;border:1px solid #e6e9ef;background:#fff;
font-size:14px;
}
.help-line{font-size:12px;color:var(--muted);margin-top:8px}
/* Recent invites / list */
.list-row{display:flex;align-items:center;justify-content:space-between;padding:10px 0;border-top:1px solid #f2f4f8}
.list-left{display:flex;align-items:center;gap:10px}
.small-avatar{width:36px;height:36px;border-radius:8px;background:#eef4ff;display:flex;align-items:center;justify-content:center;color:#3759c8;font-weight:700}
.list-title{font-weight:600}
.list-sub{font-size:12px;color:var(--muted)}
/* Modal (simple) */
.overlay{position:fixed;left:0;right:0;top:0;bottom:0;background:rgba(8,10,15,0.45);display:flex;align-items:center;justify-content:center;padding:20px;z-index:80}
.modal{width:100%;max-width:420px;border-radius:14px;background:var(--card);padding:16px;box-shadow:var(--shadow)}
.modal .h1{font-weight:700;margin-bottom:8px}
.modal .muted{color:var(--muted);font-size:13px;margin-bottom:12px}
.share-grid{display:flex;gap:8px;flex-wrap:wrap}
.share-chip{flex:0 0 30%;min-width:84px;padding:10px;border-radius:10px;background:#f7f9ff;text-align:center;font-size:13px;color:#123;background:linear-gradient(180deg,#fff,#f7f9ff);cursor:pointer}
.copy-toast{position:fixed;left:50%;transform:translateX(-50%);bottom:22px;padding:8px 14px;background:rgba(0,0,0,0.7);color:#fff;border-radius:20px;font-size:13px;z-index:90}
/* Footer hint */
.hint{font-size:12px;color:var(--muted);text-align:center;margin-top:12px}
/* small screens */
@media (max-width:360px){
.btn{padding:10px}
.space-avatar{width:48px;height:48px;font-size:18px}
}
</style>
</head>
<body>
<div class="screen">
<header class="appbar">
<div style="width:44px;"></div>
<div>
<div class="title">共享空间</div>
<div class="subtitle">邀请别人加入你的空间,或输入邀请码加入别人空间</div>
</div>
</header>
<!-- Invite card -->
<section class="card">
<div class="invite-top">
<div class="space-avatar" id="spaceAvatar">A</div>
<div class="space-info">
<div class="space-name" id="spaceName">工作协作空间</div>
<div class="space-meta">成员 12 • 权限 管理者</div>
</div>
<div style="width:68px;text-align:right"><button class="btn ghost" id="manageBtn">管理</button></div>
</div>
<div style="margin-top:14px">
<div class="code-box" id="codeBox">
<div class="code-text" id="inviteCode">AB12-CD34</div>
<div class="code-actions">
<button class="btn ghost" id="copyBtn">复制</button>
<button class="btn" id="shareBtn">分享</button>
</div>
</div>
<div class="invite-row">
<button class="btn ghost" id="qrBtn">二维码</button>
<button class="btn ghost" id="linkBtn">链接</button>
<button class="btn danger" id="revokeBtn">撤销并重置</button>
</div>
</div>
<div class="hint">邀请码有效期:24小时 · 点击分享可选择渠道</div>
</section>
<!-- Join other -->
<section class="card" aria-label="加入他人空间">
<div style="display:flex;align-items:center;justify-content:space-between;">
<div style="font-weight:700">加入别人的空间</div>
<div class="list-sub">通过邀请码或扫码加入</div>
</div>
<div class="join-input">
<input class="input" id="joinInput" placeholder="输入邀请码或链接(例如:AB12-CD34)" />
<button class="btn" id="joinBtn">加入</button>
</div>
<div class="help-line">若对方使用链接邀请,可直接粘贴链接;扫码请使用 App 内相机。</div>
<div style="margin-top:12px">
<div style="font-weight:600;margin-bottom:8px">最近加入的空间</div>
<div class="list-row">
<div class="list-left">
<div class="small-avatar">P</div>
<div>
<div class="list-title">产品设计空间</div>
<div class="list-sub">邀请人:小李 · 2 天前</div>
</div>
</div>
<div style="text-align:right;">
<div class="list-sub">成员 8</div>
</div>
</div>
<div class="list-row">
<div class="list-left">
<div class="small-avatar">M</div>
<div>
<div class="list-title">市场推广</div>
<div class="list-sub">邀请人:小王 · 1 周前</div>
</div>
</div>
<div style="text-align:right;">
<div class="list-sub">成员 20</div>
</div>
</div>
</div>
</section>
<!-- footer actions -->
<div style="display:flex;gap:8px;margin-top:8px">
<button class="btn ghost" style="flex:1" id="createSpace">创建新空间</button>
<button class="btn" style="flex:1" id="explore">发现空间</button>
</div>
<div style="height:40px"></div>
</div>
<!-- Modal markup (hidden initially) -->
<div id="modalOverlay" class="overlay" style="display:none;">
<div class="modal" role="dialog" aria-modal="true">
<div class="h1">分享邀请</div>
<div class="muted">选择一种方式邀请你的成员</div>
<div class="share-grid" style="margin-bottom:12px;">
<div class="share-chip" data-action="wechat">微信</div>
<div class="share-chip" data-action="qq">QQ</div>
<div class="share-chip" data-action="link">复制链接</div>
<div class="share-chip" data-action="sms">短信</div>
<div class="share-chip" data-action="email">邮件</div>
<div class="share-chip" data-action="more">更多</div>
</div>
<div style="display:flex;gap:8px;justify-content:flex-end">
<button class="btn ghost" onclick="closeModal()">取消</button>
<button class="btn" id="modalShare">分享</button>
</div>
</div>
</div>
<!-- toast -->
<div id="copyToast" class="copy-toast" style="display:none;">已复制到剪贴板</div>
<script>
// demo interactions
const inviteCodeEl = document.getElementById('inviteCode');
const copyBtn = document.getElementById('copyBtn');
const shareBtn = document.getElementById('shareBtn');
const modal = document.getElementById('modalOverlay');
const copyToast = document.getElementById('copyToast');
const joinInput = document.getElementById('joinInput');
const joinBtn = document.getElementById('joinBtn');
// copy code
copyBtn.addEventListener('click', async () => {
const code = inviteCodeEl.textContent.trim();
try {
await navigator.clipboard.writeText(code);
showToast('已复制邀请码');
} catch (e) {
showToast('复制失败,请手动复制');
}
});
// open share modal
shareBtn.addEventListener('click', () => openModal());
document.getElementById('qrBtn').addEventListener('click', ()=> {
alert('打开二维码生成器(示例占位)');
});
document.getElementById('linkBtn').addEventListener('click', ()=> {
alert('打开链接分享(示例占位)');
});
document.getElementById('revokeBtn').addEventListener('click', ()=> {
const newCode = randomCode();
inviteCodeEl.textContent = newCode;
showToast('邀请码已重置');
});
// join
joinBtn.addEventListener('click', ()=> {
const v = (joinInput.value || '').trim();
if (!v) return showToast('请输入邀请码或链接');
// 简单验证格式示例
const matched = /^[A-Z0-9]{2,}-[A-Z0-9]{2,}$/.test(v) || v.includes('http');
if (!matched) return showToast('邀请码格式不正确');
showToast('加入请求已发送');
// TODO: 调用后端 API 加入空间
});
// modal actions
function openModal(){ modal.style.display='flex'; }
function closeModal(){ modal.style.display='none'; }
document.getElementById('modalShare').addEventListener('click', ()=>{
// 示例:复制链接并关闭
const fakeLink = location.href + '?invite=' + inviteCodeEl.textContent.trim();
navigator.clipboard.writeText(fakeLink).catch(()=>{});
showToast('邀请链接已复制');
closeModal();
});
// copy chips
document.querySelectorAll('.share-chip').forEach(el=>{
el.addEventListener('click', ()=> {
const action = el.getAttribute('data-action');
if (action === 'link') {
const fakeLink = location.href + '?invite=' + inviteCodeEl.textContent.trim();
navigator.clipboard.writeText(fakeLink).then(()=> showToast('链接已复制'));
} else {
showToast('已选择:' + action);
}
})
});
// small utilities
function showToast(text){
copyToast.textContent = text;
copyToast.style.display = 'block';
setTimeout(()=> copyToast.style.display='none', 1500);
}
function randomCode(){
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const pick = (n)=> Array.from({length:n}).map(()=>chars[Math.floor(Math.random()*chars.length)]).join('');
return pick(2)+'-'+pick(4);
}
</script>
</body>
</html>