Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2281c98b1b | |||
| 7cb51e70a3 | |||
| 44318e0e4d | |||
| da577299a0 |
@@ -3,11 +3,16 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class SettingsProvider with ChangeNotifier {
|
||||
// Use 10.0.2.2 for Android emulator to access host's localhost
|
||||
static String get _defaultUrl =>
|
||||
(defaultTargetPlatform == TargetPlatform.android && !kIsWeb)
|
||||
? "http://10.0.2.2:8080"
|
||||
: "http://localhost:8080";
|
||||
// On web: use empty string so API calls use same origin (works behind any proxy)
|
||||
// On Android emulator: 10.0.2.2 maps to host localhost
|
||||
// On other platforms: localhost
|
||||
static String get _defaultUrl {
|
||||
if (kIsWeb) return "";
|
||||
if (defaultTargetPlatform == TargetPlatform.android) {
|
||||
return "http://10.0.2.2:8080";
|
||||
}
|
||||
return "http://localhost:8080";
|
||||
}
|
||||
|
||||
String _baseUrl = _defaultUrl;
|
||||
Color _themeColor = Colors.blue;
|
||||
@@ -38,7 +43,7 @@ class SettingsProvider with ChangeNotifier {
|
||||
}
|
||||
_livePreviewThumbnailsEnabled =
|
||||
prefs.getBool('livePreviewThumbnailsEnabled') ?? false;
|
||||
|
||||
|
||||
final languageCode = prefs.getString('languageCode');
|
||||
final scriptCode = prefs.getString('scriptCode');
|
||||
final countryCode = prefs.getString('countryCode');
|
||||
@@ -49,7 +54,7 @@ class SettingsProvider with ChangeNotifier {
|
||||
countryCode: countryCode,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@@ -106,8 +111,18 @@ class SettingsProvider with ChangeNotifier {
|
||||
|
||||
// Also provide the RTMP URL based on the same hostname
|
||||
String get rtmpUrl {
|
||||
final uri = Uri.parse(_baseUrl);
|
||||
return "rtmp://${uri.host}:1935/live";
|
||||
final host = _baseUrl.isEmpty ? _effectiveHost : Uri.parse(_baseUrl).host;
|
||||
return "rtmp://$host:1935/live";
|
||||
}
|
||||
|
||||
// Fallback hostname when baseUrl is empty (web same-origin mode)
|
||||
String get _effectiveHost {
|
||||
if (kIsWeb) {
|
||||
final host = Uri.base.host;
|
||||
if (host.isNotEmpty) return host;
|
||||
return 'localhost';
|
||||
}
|
||||
return 'localhost';
|
||||
}
|
||||
|
||||
String playbackUrl(String roomId, {String? quality}) {
|
||||
|
||||
@@ -45,7 +45,7 @@ class ChatService {
|
||||
Stream<ChatMessage> get messages => _messageController.stream;
|
||||
|
||||
void connect(String baseUrl, String roomId, String username) {
|
||||
final wsUri = Uri.parse(baseUrl).replace(
|
||||
final wsUri = _webSocketUri(baseUrl).replace(
|
||||
scheme: 'ws',
|
||||
path: '/api/ws/room/$roomId',
|
||||
queryParameters: {'username': username},
|
||||
@@ -83,6 +83,21 @@ class ChatService {
|
||||
}
|
||||
}
|
||||
|
||||
Uri _webSocketUri(String baseUrl) {
|
||||
if (baseUrl.isEmpty) {
|
||||
if (kIsWeb) {
|
||||
return Uri.base.replace(
|
||||
scheme: Uri.base.scheme == 'https' ? 'wss' : 'ws',
|
||||
);
|
||||
}
|
||||
return Uri.parse('http://localhost:8080');
|
||||
}
|
||||
|
||||
final uri = Uri.parse(baseUrl);
|
||||
final scheme = uri.scheme == 'https' ? 'wss' : 'ws';
|
||||
return uri.replace(scheme: scheme);
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_channel?.sink.close();
|
||||
_messageController.close();
|
||||
|
||||
BIN
website/hightube/assets/hightube-icon.png
Normal file
BIN
website/hightube/assets/hightube-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.9 KiB |
395
website/hightube/index.html
Normal file
395
website/hightube/index.html
Normal file
File diff suppressed because one or more lines are too long
804
website/hightube/styles.css
Normal file
804
website/hightube/styles.css
Normal file
@@ -0,0 +1,804 @@
|
||||
:root {
|
||||
color-scheme: light dark;
|
||||
--primary: #0b57d0;
|
||||
--on-primary: #ffffff;
|
||||
--primary-container: #d7e3ff;
|
||||
--on-primary-container: #001b3f;
|
||||
--secondary: #565f71;
|
||||
--tertiary: #705575;
|
||||
--surface: #fbfcff;
|
||||
--surface-rgb: 251 252 255;
|
||||
--surface-container: #eef3fb;
|
||||
--surface-container-high: #e5ebf5;
|
||||
--outline: #727782;
|
||||
--outline-rgb: 114 119 130;
|
||||
--text: #191c20;
|
||||
--muted: #42474f;
|
||||
--success: #146c2e;
|
||||
--warning: #7a5900;
|
||||
--shadow: 0 24px 60px rgba(11, 87, 208, 0.16);
|
||||
--topbar-bg: rgba(251, 252, 255, 0.68);
|
||||
--topbar-border: rgba(114, 119, 130, 0.18);
|
||||
--topbar-shadow: 0 12px 36px rgba(11, 87, 208, 0.08);
|
||||
--grid-divider: rgba(114, 119, 130, 0.24);
|
||||
--card-border: rgba(114, 119, 130, 0.24);
|
||||
--device-border: rgba(114, 119, 130, 0.32);
|
||||
--status-available-bg: rgba(20, 108, 46, 0.12);
|
||||
--status-planned-bg: rgba(122, 89, 0, 0.12);
|
||||
}
|
||||
|
||||
/* ---- Dark theme: forced ---- */
|
||||
[data-theme="dark"] {
|
||||
--primary: #a8c7ff;
|
||||
--on-primary: #001b3f;
|
||||
--primary-container: #003a7a;
|
||||
--on-primary-container: #d7e3ff;
|
||||
--secondary: #bcc7db;
|
||||
--tertiary: #d7bde0;
|
||||
--surface: #111318;
|
||||
--surface-rgb: 17 19 24;
|
||||
--surface-container: #1a1d25;
|
||||
--surface-container-high: #21242d;
|
||||
--outline: #8b909c;
|
||||
--outline-rgb: 139 144 156;
|
||||
--text: #e3e3e8;
|
||||
--muted: #b0b3bd;
|
||||
--success: #81c784;
|
||||
--warning: #ffe08a;
|
||||
--shadow: 0 24px 60px rgba(0, 0, 0, 0.4);
|
||||
--topbar-bg: rgba(17, 19, 24, 0.72);
|
||||
--topbar-border: rgba(139, 144, 156, 0.18);
|
||||
--topbar-shadow: 0 12px 36px rgba(0, 0, 0, 0.28);
|
||||
--grid-divider: rgba(139, 144, 156, 0.2);
|
||||
--card-border: rgba(139, 144, 156, 0.2);
|
||||
--device-border: rgba(139, 144, 156, 0.28);
|
||||
--status-available-bg: rgba(129, 199, 132, 0.15);
|
||||
--status-planned-bg: rgba(255, 224, 138, 0.15);
|
||||
}
|
||||
|
||||
/* ---- Dark theme: auto (system preference, no manual override) ---- */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root:not([data-theme="light"]) {
|
||||
--primary: #a8c7ff;
|
||||
--on-primary: #001b3f;
|
||||
--primary-container: #003a7a;
|
||||
--on-primary-container: #d7e3ff;
|
||||
--secondary: #bcc7db;
|
||||
--tertiary: #d7bde0;
|
||||
--surface: #111318;
|
||||
--surface-rgb: 17 19 24;
|
||||
--surface-container: #1a1d25;
|
||||
--surface-container-high: #21242d;
|
||||
--outline: #8b909c;
|
||||
--outline-rgb: 139 144 156;
|
||||
--text: #e3e3e8;
|
||||
--muted: #b0b3bd;
|
||||
--success: #81c784;
|
||||
--warning: #ffe08a;
|
||||
--shadow: 0 24px 60px rgba(0, 0, 0, 0.4);
|
||||
--topbar-bg: rgba(17, 19, 24, 0.72);
|
||||
--topbar-border: rgba(139, 144, 156, 0.18);
|
||||
--topbar-shadow: 0 12px 36px rgba(0, 0, 0, 0.28);
|
||||
--grid-divider: rgba(139, 144, 156, 0.2);
|
||||
--card-border: rgba(139, 144, 156, 0.2);
|
||||
--device-border: rgba(139, 144, 156, 0.28);
|
||||
--status-available-bg: rgba(129, 199, 132, 0.15);
|
||||
--status-planned-bg: rgba(255, 224, 138, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
min-width: 320px;
|
||||
background: var(--surface);
|
||||
color: var(--text);
|
||||
font-family:
|
||||
Inter, Roboto, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
|
||||
sans-serif;
|
||||
line-height: 1.6;
|
||||
transition: background-color 300ms ease, color 300ms ease;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.topbar {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 24px;
|
||||
padding: 14px clamp(20px, 5vw, 72px);
|
||||
background: var(--topbar-bg);
|
||||
border-bottom: 1px solid var(--topbar-border);
|
||||
box-shadow: var(--topbar-shadow);
|
||||
-webkit-backdrop-filter: blur(22px) saturate(160%);
|
||||
backdrop-filter: blur(22px) saturate(160%);
|
||||
}
|
||||
|
||||
.brand {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
color: var(--text);
|
||||
font-weight: 800;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.brand img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.nav a {
|
||||
min-height: 40px;
|
||||
padding: 8px 14px;
|
||||
border-radius: 20px;
|
||||
color: var(--muted);
|
||||
font-size: 0.94rem;
|
||||
font-weight: 650;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.nav a:hover {
|
||||
background: var(--surface-container);
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
/* 立即尝试 CTA button in nav */
|
||||
.nav-cta {
|
||||
background: var(--primary) !important;
|
||||
color: var(--on-primary) !important;
|
||||
margin-left: 8px;
|
||||
font-weight: 800 !important;
|
||||
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.2);
|
||||
transition: transform 160ms ease, box-shadow 160ms ease, background 160ms ease;
|
||||
}
|
||||
|
||||
.nav-cta:hover {
|
||||
filter: brightness(0.88);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.26);
|
||||
}
|
||||
|
||||
/* Hamburger menu button — hidden on desktop */
|
||||
.hamburger {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 5px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
padding: 8px;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.hamburger span {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 2.5px;
|
||||
border-radius: 2px;
|
||||
background: var(--text);
|
||||
transition: transform 200ms ease, opacity 200ms ease;
|
||||
}
|
||||
|
||||
.hamburger[aria-expanded="true"] span:nth-child(1) {
|
||||
transform: translateY(7.5px) rotate(45deg);
|
||||
}
|
||||
|
||||
.hamburger[aria-expanded="true"] span:nth-child(2) {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.hamburger[aria-expanded="true"] span:nth-child(3) {
|
||||
transform: translateY(-7.5px) rotate(-45deg);
|
||||
}
|
||||
|
||||
/* Right-side controls group (theme + hamburger) */
|
||||
.topbar-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Theme toggle button */
|
||||
.theme-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
padding: 0;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
background: transparent;
|
||||
color: var(--text);
|
||||
font-size: 1.25rem;
|
||||
cursor: pointer;
|
||||
transition: background 200ms ease, transform 200ms ease;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.theme-toggle:hover {
|
||||
background: var(--surface-container);
|
||||
transform: scale(1.08);
|
||||
}
|
||||
|
||||
.theme-toggle:active {
|
||||
transform: scale(0.94);
|
||||
}
|
||||
|
||||
.theme-toggle svg {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
stroke-width: 2;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
/* hide all icons by default, show based on data-state */
|
||||
.theme-toggle .icon-sun,
|
||||
.theme-toggle .icon-moon,
|
||||
.theme-toggle .icon-auto {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.theme-toggle[data-state="light"] .icon-sun {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.theme-toggle[data-state="dark"] .icon-moon {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.theme-toggle[data-state="auto"] .icon-auto {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.hero {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.05fr) minmax(320px, 0.95fr);
|
||||
gap: clamp(28px, 6vw, 84px);
|
||||
align-items: center;
|
||||
min-height: calc(100vh - 68px);
|
||||
padding: clamp(48px, 7vw, 96px) clamp(20px, 5vw, 72px);
|
||||
}
|
||||
|
||||
.hero-copy {
|
||||
max-width: 680px;
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
margin: 0 0 12px;
|
||||
color: var(--primary);
|
||||
font-size: 0.85rem;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
p {
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
color: var(--text);
|
||||
font-size: clamp(3.5rem, 11vw, 8rem);
|
||||
line-height: 0.9;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-size: clamp(2rem, 4vw, 3.5rem);
|
||||
line-height: 1.05;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: 0;
|
||||
font-size: 1.2rem;
|
||||
line-height: 1.2;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.lead {
|
||||
max-width: 620px;
|
||||
margin: 28px 0 0;
|
||||
color: var(--muted);
|
||||
font-size: clamp(1.1rem, 2vw, 1.35rem);
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
margin-top: 34px;
|
||||
}
|
||||
|
||||
.button,
|
||||
.download-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 48px;
|
||||
padding: 12px 22px;
|
||||
border-radius: 24px;
|
||||
font-weight: 800;
|
||||
text-decoration: none;
|
||||
transition:
|
||||
transform 160ms ease,
|
||||
box-shadow 160ms ease,
|
||||
background 160ms ease;
|
||||
}
|
||||
|
||||
.button:hover,
|
||||
.download-link:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.primary {
|
||||
background: var(--primary);
|
||||
color: var(--on-primary);
|
||||
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
|
||||
.secondary {
|
||||
background: var(--primary-container);
|
||||
color: var(--on-primary-container);
|
||||
}
|
||||
|
||||
.hero-panel {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.device-window {
|
||||
width: min(100%, 560px);
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--device-border);
|
||||
border-radius: 28px;
|
||||
background: var(--surface-container);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.window-bar {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
padding: 16px 18px;
|
||||
border-bottom: 1px solid var(--card-border);
|
||||
}
|
||||
|
||||
.window-bar span {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
background: var(--outline);
|
||||
}
|
||||
|
||||
.window-bar span:first-child {
|
||||
background: #ba1a1a;
|
||||
}
|
||||
|
||||
.window-bar span:nth-child(2) {
|
||||
background: #a46700;
|
||||
}
|
||||
|
||||
.window-bar span:nth-child(3) {
|
||||
background: #146c2e;
|
||||
}
|
||||
|
||||
.stream-preview {
|
||||
position: relative;
|
||||
display: grid;
|
||||
min-height: 280px;
|
||||
place-items: center;
|
||||
background:
|
||||
linear-gradient(135deg, rgba(11, 87, 208, 0.94), rgba(112, 85, 117, 0.9)),
|
||||
radial-gradient(circle at 30% 30%, #d7e3ff, transparent 32%);
|
||||
}
|
||||
|
||||
.live-badge {
|
||||
position: absolute;
|
||||
top: 18px;
|
||||
left: 18px;
|
||||
padding: 6px 12px;
|
||||
border-radius: 16px;
|
||||
background: #ba1a1a;
|
||||
color: #ffffff;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.play-symbol {
|
||||
width: 86px;
|
||||
height: 86px;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.88);
|
||||
clip-path: polygon(28% 18%, 28% 82%, 82% 50%);
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 1px;
|
||||
background: var(--grid-divider);
|
||||
}
|
||||
|
||||
.stats-grid div {
|
||||
min-width: 0;
|
||||
padding: 18px 14px;
|
||||
background: var(--surface);
|
||||
}
|
||||
|
||||
.stats-grid strong,
|
||||
.stats-grid span {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.stats-grid strong {
|
||||
color: var(--primary);
|
||||
font-size: 1.02rem;
|
||||
}
|
||||
|
||||
.stats-grid span {
|
||||
color: var(--muted);
|
||||
font-size: 0.88rem;
|
||||
}
|
||||
|
||||
.section {
|
||||
padding: clamp(64px, 8vw, 112px) clamp(20px, 5vw, 72px);
|
||||
}
|
||||
|
||||
.section-heading {
|
||||
max-width: 820px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.section-heading p:not(.eyebrow) {
|
||||
max-width: 760px;
|
||||
color: var(--muted);
|
||||
font-size: 1.06rem;
|
||||
}
|
||||
|
||||
.architecture-grid,
|
||||
.download-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.architecture-card,
|
||||
.download-card {
|
||||
min-width: 0;
|
||||
padding: 24px;
|
||||
border: 1px solid var(--card-border);
|
||||
border-radius: 24px;
|
||||
background: var(--surface-container);
|
||||
}
|
||||
|
||||
.architecture-card .icon {
|
||||
display: grid;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
margin-bottom: 20px;
|
||||
place-items: center;
|
||||
border-radius: 16px;
|
||||
background: var(--primary);
|
||||
color: var(--on-primary);
|
||||
}
|
||||
|
||||
.architecture-card .icon svg {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
}
|
||||
|
||||
.architecture-card p,
|
||||
.download-card p,
|
||||
.feature-item p,
|
||||
.source-section p {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.feature-band {
|
||||
background: var(--surface-container);
|
||||
}
|
||||
|
||||
.feature-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 1px;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--card-border);
|
||||
border-radius: 28px;
|
||||
background: var(--grid-divider);
|
||||
}
|
||||
|
||||
.feature-item {
|
||||
min-width: 0;
|
||||
padding: 28px;
|
||||
background: var(--surface);
|
||||
}
|
||||
|
||||
.feature-icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
margin-bottom: 14px;
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.feature-icon svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.download-grid {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.download-card {
|
||||
display: flex;
|
||||
min-height: 240px;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.download-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin-bottom: 14px;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.download-icon svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.status {
|
||||
margin-bottom: 18px;
|
||||
padding: 5px 10px;
|
||||
border-radius: 14px;
|
||||
background: var(--status-available-bg);
|
||||
color: var(--success);
|
||||
font-size: 0.78rem;
|
||||
font-weight: 850;
|
||||
}
|
||||
|
||||
.status.muted {
|
||||
background: var(--status-planned-bg);
|
||||
color: var(--warning);
|
||||
}
|
||||
|
||||
.download-link {
|
||||
margin-top: auto;
|
||||
background: var(--primary);
|
||||
color: var(--on-primary);
|
||||
}
|
||||
|
||||
.planned {
|
||||
background: var(--surface-container-high);
|
||||
}
|
||||
|
||||
.source-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 24px;
|
||||
background: #001b3f;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.source-section .eyebrow,
|
||||
.source-section p {
|
||||
color: #d7e3ff;
|
||||
}
|
||||
|
||||
.source-section div {
|
||||
max-width: 820px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 28px clamp(20px, 5vw, 72px);
|
||||
background: #001533;
|
||||
color: #d7e3ff;
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
|
||||
.footer span:nth-child(2) {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.footer span:last-child {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.topbar {
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.hamburger {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.nav {
|
||||
display: none;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
padding: 8px 0 4px;
|
||||
border-top: 1px solid var(--topbar-border);
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.nav.open {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.nav a {
|
||||
width: 100%;
|
||||
padding: 12px 16px;
|
||||
border-radius: 14px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.nav-cta {
|
||||
margin-left: 0 !important;
|
||||
margin-top: 6px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hero {
|
||||
grid-template-columns: 1fr;
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
.architecture-grid,
|
||||
.download-grid {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.source-section {
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.topbar {
|
||||
padding: 10px 16px;
|
||||
}
|
||||
|
||||
.hero,
|
||||
.section {
|
||||
padding-right: 16px;
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.hero {
|
||||
padding-top: 32px;
|
||||
padding-bottom: 32px;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: clamp(2.8rem, 10vw, 4rem);
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: clamp(1.6rem, 5vw, 2.4rem);
|
||||
}
|
||||
|
||||
.lead {
|
||||
font-size: 1rem;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.hero-panel {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.device-window {
|
||||
width: 100%;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.stream-preview {
|
||||
min-height: 180px;
|
||||
}
|
||||
|
||||
.play-symbol {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.architecture-grid,
|
||||
.download-grid,
|
||||
.feature-list {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.architecture-card,
|
||||
.download-card {
|
||||
padding: 20px;
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
.feature-item {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.button,
|
||||
.download-link {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.nav a {
|
||||
min-height: 48px;
|
||||
padding: 14px 16px;
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
.nav-cta {
|
||||
min-height: 50px;
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
.footer {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 8px;
|
||||
padding: 24px 16px;
|
||||
}
|
||||
|
||||
.footer-hide-mobile {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,20 @@
|
||||
<a href="#features">Features</a>
|
||||
<a href="#downloads">Downloads</a>
|
||||
<a href="#source">Source</a>
|
||||
<a class="nav-cta" href="https://stream.nudt.space" target="_blank" rel="noopener">Try Now</a>
|
||||
</nav>
|
||||
<div class="topbar-actions">
|
||||
<button class="theme-toggle" data-state="auto" aria-label="Theme: Auto" title="Theme: Auto — click to force Light">
|
||||
<svg class="icon-sun" viewBox="0 0 24 24"><circle cx="12" cy="12" r="5"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg>
|
||||
<svg class="icon-moon" viewBox="0 0 24 24"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
|
||||
<svg class="icon-auto" viewBox="0 0 24 24"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/></svg>
|
||||
</button>
|
||||
<button class="hamburger" aria-label="Toggle navigation" aria-expanded="false">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main id="home">
|
||||
@@ -159,9 +172,8 @@
|
||||
<p class="eyebrow">Downloads</p>
|
||||
<h2>Get the current executable builds</h2>
|
||||
<p>
|
||||
These files are hosted in the local website resources directory.
|
||||
Windows server and client builds will be added later. Apple device
|
||||
builds are not provided at this time.
|
||||
All builds are distributed through the project release page. Apple
|
||||
device builds are not provided at this time.
|
||||
</p>
|
||||
</div>
|
||||
<div class="download-grid">
|
||||
@@ -171,8 +183,8 @@
|
||||
<p>Backend service for self-hosted streaming deployments.</p>
|
||||
<a
|
||||
class="download-link"
|
||||
href="resources/hightube-server/hightube-server_amd64_v1.0.0"
|
||||
download
|
||||
href="https://git.nudt.space/Highground-Soft/Hightube/releases/download/v1.0.0/hightube-server_amd64_v1.0.0"
|
||||
rel="noopener"
|
||||
>
|
||||
Download Linux server
|
||||
</a>
|
||||
@@ -183,8 +195,8 @@
|
||||
<p>Desktop Flutter client packaged as an AppImage.</p>
|
||||
<a
|
||||
class="download-link"
|
||||
href="resources/hightube-client/hightube-linux-amd64-v1.0.0.AppImage"
|
||||
download
|
||||
href="https://git.nudt.space/Highground-Soft/Hightube/releases/download/v1.0.0/hightube-linux-amd64-v1.0.0.AppImage"
|
||||
rel="noopener"
|
||||
>
|
||||
Download Linux AppImage
|
||||
</a>
|
||||
@@ -195,8 +207,8 @@
|
||||
<p>ARM64 Android APK build for mobile viewing and interaction.</p>
|
||||
<a
|
||||
class="download-link"
|
||||
href="resources/hightube-client/hightube-android-arm64-v8a-v1.0.0.apk"
|
||||
download
|
||||
href="https://git.nudt.space/Highground-Soft/Hightube/releases/download/v1.0.0/hightube-android-arm64-v8a-v1.0.0.apk"
|
||||
rel="noopener"
|
||||
>
|
||||
Download Android APK
|
||||
</a>
|
||||
@@ -207,21 +219,35 @@
|
||||
<p>Static web build archive for hosting the Flutter web frontend.</p>
|
||||
<a
|
||||
class="download-link"
|
||||
href="resources/hightube-client/hightube-web-v1.0.0.tar.gz"
|
||||
download
|
||||
href="https://git.nudt.space/Highground-Soft/Hightube/releases/download/v1.0.0/hightube-web-v1.0.0.tar.gz"
|
||||
rel="noopener"
|
||||
>
|
||||
Download Web archive
|
||||
</a>
|
||||
</article>
|
||||
<article class="download-card planned">
|
||||
<span class="status muted">Coming later</span>
|
||||
<article class="download-card available">
|
||||
<span class="status">Available</span>
|
||||
<h3>Windows server</h3>
|
||||
<p>Planned server executable for Windows environments.</p>
|
||||
<p>Server executable for Windows environments.</p>
|
||||
<a
|
||||
class="download-link"
|
||||
href="https://git.nudt.space/Highground-Soft/Hightube/releases/download/v1.0.0/hightube-server_amd64_v1.0.0.exe"
|
||||
rel="noopener"
|
||||
>
|
||||
Download Windows server
|
||||
</a>
|
||||
</article>
|
||||
<article class="download-card planned">
|
||||
<span class="status muted">Coming later</span>
|
||||
<article class="download-card available">
|
||||
<span class="status">Available</span>
|
||||
<h3>Windows client</h3>
|
||||
<p>Planned desktop client build for Windows users.</p>
|
||||
<p>Desktop client build for Windows users.</p>
|
||||
<a
|
||||
class="download-link"
|
||||
href="https://git.nudt.space/Highground-Soft/Hightube/releases/download/v1.0.0/hightube-win_amd64_v1.0.0.zip"
|
||||
rel="noopener"
|
||||
>
|
||||
Download Windows client
|
||||
</a>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
@@ -246,10 +272,73 @@
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
/* ---- hamburger menu ---- */
|
||||
var btn = document.querySelector('.hamburger');
|
||||
var nav = document.querySelector('.nav');
|
||||
if (btn && nav) {
|
||||
btn.addEventListener('click', function () {
|
||||
var open = nav.classList.toggle('open');
|
||||
btn.setAttribute('aria-expanded', open);
|
||||
});
|
||||
}
|
||||
|
||||
/* ---- theme toggle ---- */
|
||||
var toggle = document.querySelector('.theme-toggle');
|
||||
if (!toggle) return;
|
||||
|
||||
var STATES = ['auto', 'light', 'dark'];
|
||||
var LABELS = {
|
||||
auto: 'Theme: Auto — click to force Light',
|
||||
light: 'Theme: Light — click to force Dark',
|
||||
dark: 'Theme: Dark — click to return to Auto'
|
||||
};
|
||||
|
||||
function getTheme() {
|
||||
return localStorage.getItem('theme') || 'auto';
|
||||
}
|
||||
|
||||
function applyTheme(state) {
|
||||
if (state === 'light') {
|
||||
document.documentElement.setAttribute('data-theme', 'light');
|
||||
} else if (state === 'dark') {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
} else {
|
||||
document.documentElement.removeAttribute('data-theme');
|
||||
}
|
||||
toggle.setAttribute('data-state', state);
|
||||
toggle.setAttribute('aria-label', 'Theme: ' + state.charAt(0).toUpperCase() + state.slice(1));
|
||||
toggle.setAttribute('title', LABELS[state]);
|
||||
localStorage.setItem('theme', state);
|
||||
}
|
||||
|
||||
function nextTheme(current) {
|
||||
var idx = STATES.indexOf(current);
|
||||
return STATES[(idx + 1) % STATES.length];
|
||||
}
|
||||
|
||||
// init
|
||||
var current = getTheme();
|
||||
applyTheme(current);
|
||||
|
||||
toggle.addEventListener('click', function () {
|
||||
applyTheme(nextTheme(getTheme()));
|
||||
});
|
||||
|
||||
// listen for system changes (only matters in auto mode)
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function () {
|
||||
if (getTheme() === 'auto') {
|
||||
// force a repaint by re-applying auto
|
||||
applyTheme('auto');
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
<footer class="footer">
|
||||
<span>Hightube</span>
|
||||
<span class="footer-hide-mobile">Hightube</span>
|
||||
<span>Built with ❤️ by HighGround-soft 2026</span>
|
||||
<span>Open Source Live Platform</span>
|
||||
<span class="footer-hide-mobile">Open Source Live Platform</span>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,19 +1,90 @@
|
||||
:root {
|
||||
color-scheme: light;
|
||||
color-scheme: light dark;
|
||||
--primary: #0b57d0;
|
||||
--on-primary: #ffffff;
|
||||
--primary-container: #d7e3ff;
|
||||
--on-primary-container: #001b3f;
|
||||
--secondary: #565f71;
|
||||
--tertiary: #705575;
|
||||
--surface: #fbfcff;
|
||||
--surface-rgb: 251 252 255;
|
||||
--surface-container: #eef3fb;
|
||||
--surface-container-high: #e5ebf5;
|
||||
--outline: #727782;
|
||||
--outline-rgb: 114 119 130;
|
||||
--text: #191c20;
|
||||
--muted: #42474f;
|
||||
--success: #146c2e;
|
||||
--warning: #7a5900;
|
||||
--shadow: 0 24px 60px rgba(11, 87, 208, 0.16);
|
||||
--topbar-bg: rgba(251, 252, 255, 0.68);
|
||||
--topbar-border: rgba(114, 119, 130, 0.18);
|
||||
--topbar-shadow: 0 12px 36px rgba(11, 87, 208, 0.08);
|
||||
--grid-divider: rgba(114, 119, 130, 0.24);
|
||||
--card-border: rgba(114, 119, 130, 0.24);
|
||||
--device-border: rgba(114, 119, 130, 0.32);
|
||||
--status-available-bg: rgba(20, 108, 46, 0.12);
|
||||
--status-planned-bg: rgba(122, 89, 0, 0.12);
|
||||
}
|
||||
|
||||
/* ---- Dark theme: forced ---- */
|
||||
[data-theme="dark"] {
|
||||
--primary: #a8c7ff;
|
||||
--on-primary: #001b3f;
|
||||
--primary-container: #003a7a;
|
||||
--on-primary-container: #d7e3ff;
|
||||
--secondary: #bcc7db;
|
||||
--tertiary: #d7bde0;
|
||||
--surface: #111318;
|
||||
--surface-rgb: 17 19 24;
|
||||
--surface-container: #1a1d25;
|
||||
--surface-container-high: #21242d;
|
||||
--outline: #8b909c;
|
||||
--outline-rgb: 139 144 156;
|
||||
--text: #e3e3e8;
|
||||
--muted: #b0b3bd;
|
||||
--success: #81c784;
|
||||
--warning: #ffe08a;
|
||||
--shadow: 0 24px 60px rgba(0, 0, 0, 0.4);
|
||||
--topbar-bg: rgba(17, 19, 24, 0.72);
|
||||
--topbar-border: rgba(139, 144, 156, 0.18);
|
||||
--topbar-shadow: 0 12px 36px rgba(0, 0, 0, 0.28);
|
||||
--grid-divider: rgba(139, 144, 156, 0.2);
|
||||
--card-border: rgba(139, 144, 156, 0.2);
|
||||
--device-border: rgba(139, 144, 156, 0.28);
|
||||
--status-available-bg: rgba(129, 199, 132, 0.15);
|
||||
--status-planned-bg: rgba(255, 224, 138, 0.15);
|
||||
}
|
||||
|
||||
/* ---- Dark theme: auto (system preference, no manual override) ---- */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root:not([data-theme="light"]) {
|
||||
--primary: #a8c7ff;
|
||||
--on-primary: #001b3f;
|
||||
--primary-container: #003a7a;
|
||||
--on-primary-container: #d7e3ff;
|
||||
--secondary: #bcc7db;
|
||||
--tertiary: #d7bde0;
|
||||
--surface: #111318;
|
||||
--surface-rgb: 17 19 24;
|
||||
--surface-container: #1a1d25;
|
||||
--surface-container-high: #21242d;
|
||||
--outline: #8b909c;
|
||||
--outline-rgb: 139 144 156;
|
||||
--text: #e3e3e8;
|
||||
--muted: #b0b3bd;
|
||||
--success: #81c784;
|
||||
--warning: #ffe08a;
|
||||
--shadow: 0 24px 60px rgba(0, 0, 0, 0.4);
|
||||
--topbar-bg: rgba(17, 19, 24, 0.72);
|
||||
--topbar-border: rgba(139, 144, 156, 0.18);
|
||||
--topbar-shadow: 0 12px 36px rgba(0, 0, 0, 0.28);
|
||||
--grid-divider: rgba(139, 144, 156, 0.2);
|
||||
--card-border: rgba(139, 144, 156, 0.2);
|
||||
--device-border: rgba(139, 144, 156, 0.28);
|
||||
--status-available-bg: rgba(129, 199, 132, 0.15);
|
||||
--status-planned-bg: rgba(255, 224, 138, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
@@ -33,6 +104,7 @@ body {
|
||||
Inter, Roboto, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
|
||||
sans-serif;
|
||||
line-height: 1.6;
|
||||
transition: background-color 300ms ease, color 300ms ease;
|
||||
}
|
||||
|
||||
a {
|
||||
@@ -48,9 +120,9 @@ a {
|
||||
justify-content: space-between;
|
||||
gap: 24px;
|
||||
padding: 14px clamp(20px, 5vw, 72px);
|
||||
background: rgba(251, 252, 255, 0.68);
|
||||
border-bottom: 1px solid rgba(114, 119, 130, 0.18);
|
||||
box-shadow: 0 12px 36px rgba(11, 87, 208, 0.08);
|
||||
background: var(--topbar-bg);
|
||||
border-bottom: 1px solid var(--topbar-border);
|
||||
box-shadow: var(--topbar-shadow);
|
||||
-webkit-backdrop-filter: blur(22px) saturate(160%);
|
||||
backdrop-filter: blur(22px) saturate(160%);
|
||||
}
|
||||
@@ -91,6 +163,123 @@ a {
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
/* 立即尝试 CTA button in nav */
|
||||
.nav-cta {
|
||||
background: var(--primary) !important;
|
||||
color: var(--on-primary) !important;
|
||||
margin-left: 8px;
|
||||
font-weight: 800 !important;
|
||||
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.2);
|
||||
transition: transform 160ms ease, box-shadow 160ms ease, background 160ms ease;
|
||||
}
|
||||
|
||||
.nav-cta:hover {
|
||||
filter: brightness(0.88);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.26);
|
||||
}
|
||||
|
||||
/* Hamburger menu button — hidden on desktop */
|
||||
.hamburger {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 5px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
padding: 8px;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.hamburger span {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 2.5px;
|
||||
border-radius: 2px;
|
||||
background: var(--text);
|
||||
transition: transform 200ms ease, opacity 200ms ease;
|
||||
}
|
||||
|
||||
.hamburger[aria-expanded="true"] span:nth-child(1) {
|
||||
transform: translateY(7.5px) rotate(45deg);
|
||||
}
|
||||
|
||||
.hamburger[aria-expanded="true"] span:nth-child(2) {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.hamburger[aria-expanded="true"] span:nth-child(3) {
|
||||
transform: translateY(-7.5px) rotate(-45deg);
|
||||
}
|
||||
|
||||
/* Right-side controls group (theme + hamburger) */
|
||||
.topbar-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Theme toggle button */
|
||||
.theme-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
padding: 0;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
background: transparent;
|
||||
color: var(--text);
|
||||
font-size: 1.25rem;
|
||||
cursor: pointer;
|
||||
transition: background 200ms ease, transform 200ms ease;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.theme-toggle:hover {
|
||||
background: var(--surface-container);
|
||||
transform: scale(1.08);
|
||||
}
|
||||
|
||||
.theme-toggle:active {
|
||||
transform: scale(0.94);
|
||||
}
|
||||
|
||||
.theme-toggle svg {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
stroke-width: 2;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
/* hide all icons by default, show based on data-state */
|
||||
.theme-toggle .icon-sun,
|
||||
.theme-toggle .icon-moon,
|
||||
.theme-toggle .icon-auto {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.theme-toggle[data-state="light"] .icon-sun {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.theme-toggle[data-state="dark"] .icon-moon {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.theme-toggle[data-state="auto"] .icon-auto {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.hero {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.05fr) minmax(320px, 0.95fr);
|
||||
@@ -180,12 +369,12 @@ h3 {
|
||||
.primary {
|
||||
background: var(--primary);
|
||||
color: var(--on-primary);
|
||||
box-shadow: 0 10px 24px rgba(11, 87, 208, 0.22);
|
||||
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
|
||||
.secondary {
|
||||
background: var(--primary-container);
|
||||
color: #001b3f;
|
||||
color: var(--on-primary-container);
|
||||
}
|
||||
|
||||
.hero-panel {
|
||||
@@ -196,7 +385,7 @@ h3 {
|
||||
.device-window {
|
||||
width: min(100%, 560px);
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(114, 119, 130, 0.32);
|
||||
border: 1px solid var(--device-border);
|
||||
border-radius: 28px;
|
||||
background: var(--surface-container);
|
||||
box-shadow: var(--shadow);
|
||||
@@ -206,7 +395,7 @@ h3 {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
padding: 16px 18px;
|
||||
border-bottom: 1px solid rgba(114, 119, 130, 0.24);
|
||||
border-bottom: 1px solid var(--card-border);
|
||||
}
|
||||
|
||||
.window-bar span {
|
||||
@@ -262,7 +451,7 @@ h3 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 1px;
|
||||
background: rgba(114, 119, 130, 0.24);
|
||||
background: var(--grid-divider);
|
||||
}
|
||||
|
||||
.stats-grid div {
|
||||
@@ -312,7 +501,7 @@ h3 {
|
||||
.download-card {
|
||||
min-width: 0;
|
||||
padding: 24px;
|
||||
border: 1px solid rgba(114, 119, 130, 0.24);
|
||||
border: 1px solid var(--card-border);
|
||||
border-radius: 24px;
|
||||
background: var(--surface-container);
|
||||
}
|
||||
@@ -345,9 +534,9 @@ h3 {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 1px;
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(114, 119, 130, 0.24);
|
||||
border: 1px solid var(--card-border);
|
||||
border-radius: 28px;
|
||||
background: rgba(114, 119, 130, 0.24);
|
||||
background: var(--grid-divider);
|
||||
}
|
||||
|
||||
.feature-item {
|
||||
@@ -371,14 +560,14 @@ h3 {
|
||||
margin-bottom: 18px;
|
||||
padding: 5px 10px;
|
||||
border-radius: 14px;
|
||||
background: rgba(20, 108, 46, 0.12);
|
||||
background: var(--status-available-bg);
|
||||
color: var(--success);
|
||||
font-size: 0.78rem;
|
||||
font-weight: 850;
|
||||
}
|
||||
|
||||
.status.muted {
|
||||
background: rgba(122, 89, 0, 0.12);
|
||||
background: var(--status-planned-bg);
|
||||
color: var(--warning);
|
||||
}
|
||||
|
||||
@@ -431,14 +620,41 @@ h3 {
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.topbar {
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.hamburger {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.nav {
|
||||
display: none;
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
padding-bottom: 2px;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
padding: 8px 0 4px;
|
||||
border-top: 1px solid var(--topbar-border);
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.nav.open {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.nav a {
|
||||
width: 100%;
|
||||
padding: 12px 16px;
|
||||
border-radius: 14px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.nav-cta {
|
||||
margin-left: 0 !important;
|
||||
margin-top: 6px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hero {
|
||||
@@ -462,34 +678,97 @@ h3 {
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.topbar {
|
||||
padding: 10px 16px;
|
||||
}
|
||||
|
||||
.hero,
|
||||
.section {
|
||||
padding-right: 16px;
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.hero {
|
||||
padding-top: 32px;
|
||||
padding-bottom: 32px;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: clamp(2.8rem, 10vw, 4rem);
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: clamp(1.6rem, 5vw, 2.4rem);
|
||||
}
|
||||
|
||||
.lead {
|
||||
font-size: 1rem;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.hero-panel {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.device-window {
|
||||
width: 100%;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.stream-preview {
|
||||
min-height: 180px;
|
||||
}
|
||||
|
||||
.play-symbol {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.architecture-grid,
|
||||
.download-grid,
|
||||
.feature-list {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.actions,
|
||||
.architecture-card,
|
||||
.download-card {
|
||||
padding: 20px;
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
.feature-item {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.button,
|
||||
.download-link {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.stream-preview {
|
||||
min-height: 220px;
|
||||
.nav a {
|
||||
min-height: 48px;
|
||||
padding: 14px 16px;
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
.nav-cta {
|
||||
min-height: 50px;
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
.footer {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 8px;
|
||||
padding: 24px 16px;
|
||||
}
|
||||
|
||||
.footer span,
|
||||
.footer span:last-child {
|
||||
text-align: left;
|
||||
.footer-hide-mobile {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user