# -*- coding: utf-8 -*-
r'''官网的"产品展示"部分:手表界面 mockup + 连接方式示意。
为什么用 HTML/CSS 画手表界面,而不是放截图:
* 手表是安卓设备,没有真机/模拟器就拍不到界面
* CSS 画的图在任何屏幕上都是清晰的(截图放大会糊)
* 用的颜色和布局**直接从 MainActivity.java 抄**,
所以不是"想象的样子",是真实界面
手表真实参数(android/.../MainActivity.java):
C_BG = 0xFFF5F7FA 页面底色(浅灰)
C_FG = 0xFF1F2328 主文字(近黑)
C_ACCENT = 0xFF185CE8 强调蓝
C_DIM = 0xFF656D76 次要文字
十个分页:媒体 屏幕 文件 语音 电脑 网络 系统 教室 效率 娱乐
'''
from __future__ import annotations
# 和手表代码一致的颜色
W_BG = "#F5F7FA"
W_FG = "#1F2328"
W_ACCENT = "#185CE8"
W_DIM = "#656D76"
W_CARD = "#FFFFFF"
W_BORDER = "#E3E7ED"
TABS = ["媒体", "屏幕", "文件", "语音", "电脑",
"网络", "系统", "教室", "效率", "娱乐"]
# "媒体"分页的真实操作(从 TabDef 抄的)
MEDIA_ACTIONS = [
("放音频", "🔊"), ("放视频", "▶"), ("暂停", "⏸"),
("继续", "⏵"), ("音量 +", "+"), ("音量 −", "−"),
("静音", "🔇"), ("下一首", "⏭"), ("投图到屏幕", "🖼"),
]
# "教室"分页(老师的核心场景)
CLASSROOM_ACTIONS = [
("上课:开投影", "📽"), ("打开课件", "📂"), ("课堂专注", "🎯"),
("恢复桌面", "↩"), ("看屏幕", "👁"), ("下课关机", "⏻"),
]
TAB_ACTIONS = {"媒体": MEDIA_ACTIONS, "教室": CLASSROOM_ACTIONS}
def _watch_card(active_tab: str) -> str:
"""画一个手表界面。active_tab 决定显示哪个分页的内容。"""
actions = TAB_ACTIONS.get(active_tab, MEDIA_ACTIONS)
# 顶部标签条
tabs = []
for name in TABS:
on = name == active_tab
tabs.append(
'%s' % (" on" if on else "", name))
tabs_html = "".join(tabs)
# 操作网格
buttons = []
for label, icon in actions:
buttons.append(
'
%s'
'%s
' % (icon, label))
grid_html = "".join(buttons)
return (
''
'
'
'
ykxmz'
'● 局域网 3 ms
'
'
%s
'
'
'
''
'
' % (tabs_html, active_tab, grid_html)
)
def _pc_card() -> str:
"""电脑端 —— 用真实截图(_build/site_shots/pc-main.png)。"""
return (
''
'
'
'电脑端:装完填个 6 位配对码就行'
''
)
def _flow_diagram() -> str:
"""连接方式示意:局域网直连 vs 跨网络走中转。"""
return '''
同一个 WiFi
直连,不经过任何服务器。几十毫秒,画面基本跟手。
不在同一个网络
两边都主动连到中转,绕过 NAT。办公室也能管教室。
'''
def render_showcase() -> str:
"""整个"产品展示"区块。"""
return '''
怎么连上的
同一个 WiFi 就走局域网直连,不同网络自动切中转
%(flow)s
''' % {"watch": _watch_card("媒体"), "pc": _pc_card(),
"flow": _flow_diagram()}
SHOWCASE_CSS = """
/* ---------- 产品展示 ---------- */
.showcase{display:grid;gap:34px;align-items:start;
justify-items:center}
@media(min-width:820px){.showcase{grid-template-columns:1fr 1fr}}
/* 手表 mockup。尺寸按真实手表屏幕比例 */
.watch{width:300px;padding:10px;border-radius:34px;
background:linear-gradient(160deg,#2b3038,#14171c);
box-shadow:0 18px 40px rgba(16,24,40,.18);
position:relative}
.watch::after{content:'';position:absolute;right:-3px;top:110px;
width:5px;height:44px;border-radius:3px;background:#3a4048}
.w-screen{background:%(W_BG)s;border-radius:26px;overflow:hidden;
font-size:11px;color:%(W_FG)s}
.w-status{display:flex;justify-content:space-between;align-items:center;
padding:11px 12px 7px;font-size:9px;font-weight:600;
gap:6px;white-space:nowrap}
.w-conn{color:#16a34a;font-weight:600}
.w-tabs{display:flex;gap:4px;overflow:hidden;padding:0 11px 8px;
border-bottom:1px solid %(W_BORDER)s}
.w-tab{flex:none;padding:3px 8px;border-radius:999px;color:%(W_DIM)s;
font-size:10px;white-space:nowrap}
.w-tab.on{background:%(W_ACCENT)s;color:#fff;font-weight:600}
.w-body{padding:12px 13px 14px}
.w-head{font-size:12px;font-weight:700;margin-bottom:10px}
.w-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:7px}
.w-btn{background:%(W_CARD)s;border:1px solid %(W_BORDER)s;
border-radius:11px;padding:11px 4px 9px;text-align:center;
display:flex;flex-direction:column;align-items:center;gap:5px}
.w-ic{font-size:15px;line-height:1}
.w-lb{font-size:9px;color:%(W_FG)s;white-space:nowrap}
.w-foot{padding:9px 13px 12px;color:%(W_DIM)s;font-size:9px;
border-top:1px solid %(W_BORDER)s}
/* 电脑端截图 */
.pcshot{margin:0;text-align:center}
.pcshot img{width:100%%;max-width:352px;height:auto;
border-radius:10px;display:block;margin:0 auto;
box-shadow:0 18px 40px rgba(16,24,40,.16)}
.pcshot{padding:14px;background:#f2f4f7;border-radius:16px;
border:1px solid %(W_BORDER)s}
.pcshot figcaption{margin-top:14px;color:%(W_DIM)s;font-size:13px}
/* 连接方式示意 */
.flow{display:grid;gap:18px}
@media(min-width:760px){.flow{grid-template-columns:1fr 1fr}}
.flow-col{border:1px solid #e6e8eb;border-radius:14px;padding:24px 20px;
background:#fafbfc}
.flow-tag{display:inline-block;padding:3px 11px;border-radius:999px;
font-size:12px;font-weight:600;margin-bottom:20px}
.flow-tag.ok{background:#dcfce7;color:#15803d}
.flow-tag.warn{background:#fef3c7;color:#a16207}
.flow-row{display:flex;align-items:center;justify-content:center;
gap:2px;margin-bottom:16px;flex-wrap:nowrap}
.node{display:flex;flex-direction:column;align-items:center;gap:6px;
font-size:26px;flex:none;width:64px}
.node span{font-size:12px;color:#4b5563;font-weight:500}
.node.relay{font-size:24px}
.link{flex:1;min-width:16px;position:relative;display:flex;
align-items:center;justify-content:center}
.link .line{width:100%%;height:2px;background:#c7cdd6;
border-radius:2px}
.link .ms{position:absolute;top:-15px;font-size:10px;color:#15803d;
font-weight:600;white-space:nowrap}
.flow-col p{color:#6b7280;font-size:13px;line-height:1.7;margin:0}
""" % {"W_BG": W_BG, "W_FG": W_FG, "W_ACCENT": W_ACCENT, "W_DIM": W_DIM,
"W_CARD": W_CARD, "W_BORDER": W_BORDER}