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:
@@ -7,7 +7,8 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:screenOrientation="landscape">
|
android:screenOrientation="landscape"
|
||||||
|
android:theme="@style/Theme.Hearth">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.HOME" />
|
<category android:name="android.intent.category.HOME" />
|
||||||
|
|||||||
@@ -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; }
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/* Hearth 设计 token:HyperOS 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,46 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="zh-CN">
|
<html lang="zh-CN">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<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>
|
<title>Hearth</title>
|
||||||
|
<link rel="stylesheet" href="css/tokens.css">
|
||||||
|
<link rel="stylesheet" href="css/app.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Hearth Launcher</h1>
|
<div class="app">
|
||||||
<p>占位页面,后续由 WebView 加载。</p>
|
<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>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -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")
|
@SuppressLint("SetJavaScriptEnabled")
|
||||||
fun attach(bridge: JsBridge): WebView {
|
fun attach(bridge: JsBridge): WebView {
|
||||||
val webView = WebView(activity)
|
val webView = WebView(activity)
|
||||||
|
// 透明背景,露出原生壁纸
|
||||||
|
// Transparent background to reveal native wallpaper
|
||||||
|
webView.setBackgroundColor(android.graphics.Color.TRANSPARENT)
|
||||||
webView.settings.apply {
|
webView.settings.apply {
|
||||||
javaScriptEnabled = true
|
javaScriptEnabled = true
|
||||||
useWideViewPort = true
|
useWideViewPort = true
|
||||||
|
|||||||
@@ -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>
|
||||||
Reference in New Issue
Block a user