feat: h5 desktop shell with sidebar and dark mode

- tokens.css/app.css: Miuix dual-color tokens + HyperOS 4 soft-glass rail
- bridge.js/router.js: Promise bridge wrapper + 5-page router with top clock
- index.html: sidebar + 5 page containers
- native wallpaper transparency: Theme.Hearth (showWallpaper + transparent window) + WebView transparent background
This commit is contained in:
2026-08-16 16:15:58 +08:00
parent dcb712731d
commit bd56d89cf3
8 changed files with 174 additions and 6 deletions
+2 -1
View File
@@ -7,7 +7,8 @@
<activity
android:name=".MainActivity"
android:exported="true"
android:screenOrientation="landscape">
android:screenOrientation="landscape"
android:theme="@style/Theme.Hearth">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
+61
View File
@@ -0,0 +1,61 @@
/* Hearth 桌面样式:侧边栏 + 5 页框架 + 柔光玻璃容器 */
/* Hearth launcher styles: sidebar + 5-page frame + soft-glass containers */
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { height: 100%; }
/* 壁纸透明:html/body 不设背景,露出原生壁纸 */
/* Wallpaper transparency: html/body keep transparent to reveal native wallpaper */
html, body { background: transparent; }
body {
color: var(--text);
font-family: -apple-system, "MiSans", "PingFang SC", sans-serif;
overflow: hidden;
}
.app { display: flex; height: 100vh; }
/* 侧边栏:柔光玻璃容器,非纯色背景 */
/* Sidebar: soft-glass container, not a solid color */
.rail {
width: 80px;
background: var(--glass-bg);
backdrop-filter: blur(20px) saturate(1.2) brightness(1.05) contrast(1.1);
-webkit-backdrop-filter: blur(20px) saturate(1.2) brightness(1.05) contrast(1.1);
border-right: 1px solid var(--glass-border);
display: flex;
flex-direction: column;
align-items: center;
padding: 12px 0;
gap: 8px;
transition: width .2s;
}
.rail.expanded { width: 240px; align-items: stretch; padding: 12px 8px; }
.rail-clock { font-size: 14px; color: var(--text-dim); display: none; }
.rail-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 3px;
background: none;
border: none;
color: var(--text-dim);
padding: 8px;
border-radius: 16px;
cursor: pointer;
}
.rail-item .ico { font-size: 20px; }
.rail-item .lbl { font-size: 11px; }
.rail-item.active { background: var(--accent); color: #fff; }
.content { flex: 1; overflow: hidden; }
.page { display: none; height: 100%; }
.page.active { display: flex; flex-direction: column; }
+19
View File
@@ -0,0 +1,19 @@
/* Hearth 设计 tokenHyperOS 4 柔光玻璃 + Miuix 双色 */
/* Hearth design tokens: HyperOS 4 soft-glass + Miuix dual-color scheme */
:root {
--glass-bg: rgba(255, 255, 255, 0.4); /* 浅色半透明白 / light translucent white */
--glass-border: rgba(0, 0, 0, 0.06);
--text: #1a1a1a;
--text-dim: #8a8a90;
--accent: #ff6900;
}
@media (prefers-color-scheme: dark) {
:root {
--glass-bg: rgba(21, 21, 24, 0.55); /* 深色半透明 / dark translucent */
--glass-border: rgba(255, 255, 255, 0.08);
--text: #ffffff;
--text-dim: #9a9aa0;
--accent: #ff6900;
}
}
+37 -3
View File
@@ -2,11 +2,45 @@
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Hearth</title>
<link rel="stylesheet" href="css/tokens.css">
<link rel="stylesheet" href="css/app.css">
</head>
<body>
<h1>Hearth Launcher</h1>
<p>占位页面,后续由 WebView 加载。</p>
<div class="app">
<aside class="rail" id="rail">
<div class="rail-clock" id="rail-clock">14:30</div>
<nav id="rail-nav"></nav>
</aside>
<main class="content">
<section data-page="home" class="page active"></section>
<section data-page="immersive" class="page"></section>
<section data-page="webapplist" class="page"></section>
<section data-page="applist" class="page"></section>
<section data-page="settings" class="page"></section>
</main>
</div>
<script src="js/bridge.js"></script>
<script src="js/router.js"></script>
<script>
// 渲染侧边栏导航项 / render sidebar nav items
const nav = document.getElementById('rail-nav');
PAGES.forEach(p => {
const b = document.createElement('button');
b.className = 'rail-item';
b.innerHTML = `<span class="ico">${p.icon}</span><span class="lbl">${p.label}</span>`;
b.onclick = () => router.navigate(p.id);
nav.appendChild(b);
});
// 侧边栏顶部时间刷新 / refresh sidebar top clock
setInterval(() => {
const now = new Date();
const hh = String(now.getHours()).padStart(2, '0');
const mm = String(now.getMinutes()).padStart(2, '0');
document.getElementById('rail-clock').textContent = `${hh}:${mm}`;
}, 10000);
router.navigate('home');
</script>
</body>
</html>
+17
View File
@@ -0,0 +1,17 @@
// HearthBridge 原生桥接封装:统一 Promise 调用
// HearthBridge native bridge wrapper: unified Promise-based calls
const bridge = {
call(method, ...args) {
return new Promise((resolve, reject) => {
if (!window.HearthBridge || typeof window.HearthBridge[method] !== 'function') {
reject(new Error(`bridge method not found: ${method}`));
return;
}
try {
resolve(window.HearthBridge[method](...args));
} catch (e) {
reject(e);
}
});
}
};
+25
View File
@@ -0,0 +1,25 @@
// 桌面路由:侧边栏 5 页 + 页面切换 + 顶部时间
// Launcher router: 5 sidebar pages + page switching + top clock
const PAGES = [
{ id: 'home', label: '首页', icon: '🏠' },
{ id: 'immersive', label: '沉浸首页', icon: '🚗' },
{ id: 'webapplist', label: 'H5 应用', icon: '🌐' },
{ id: 'applist', label: '安卓 APP', icon: '📱' },
{ id: 'settings', label: '设置', icon: '⚙️' },
];
const router = {
current: 'home',
navigate(id) {
this.current = id;
document.querySelectorAll('[data-page]').forEach(el =>
el.classList.toggle('active', el.dataset.page === id));
// 非首页时侧边栏顶部显示小时间
// Show the small clock at the sidebar top when not on home
const clock = document.getElementById('rail-clock');
if (clock) clock.style.display = (id === 'home') ? 'none' : 'block';
if (id === 'home') window.updateHomeCards && window.updateHomeCards();
if (id === 'applist') window.loadAppList && window.loadAppList();
if (id === 'webapplist') window.loadWebAppList && window.loadWebAppList();
}
};
@@ -10,6 +10,9 @@ class WebViewManager(private val activity: Activity) {
@SuppressLint("SetJavaScriptEnabled")
fun attach(bridge: JsBridge): WebView {
val webView = WebView(activity)
// 透明背景,露出原生壁纸
// Transparent background to reveal native wallpaper
webView.setBackgroundColor(android.graphics.Color.TRANSPARENT)
webView.settings.apply {
javaScriptEnabled = true
useWideViewPort = true
+8
View File
@@ -0,0 +1,8 @@
<resources>
<!-- Hearth 桌面主题:显示壁纸 + 透明窗口背景,让 WebView 露出壁纸 -->
<!-- Hearth launcher theme: show wallpaper + transparent window so WebView reveals wallpaper -->
<style name="Theme.Hearth" parent="android:Theme.Material.NoActionBar">
<item name="android:windowShowWallpaper">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
</style>
</resources>