feat: refine responsive hero and preference dropdowns
This commit is contained in:
+149
-64
@@ -207,57 +207,81 @@
|
||||
.nav-link.active::after { opacity: 1; transform: translateX(-50%) scale(1); }
|
||||
|
||||
.nav-actions { display: flex; align-items: center; gap: 10px; }
|
||||
.theme-switch {
|
||||
.preference-menu { position: relative; }
|
||||
.preference-trigger {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
gap: 8px;
|
||||
min-height: 38px;
|
||||
padding: 3px;
|
||||
padding: 0 11px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 9px;
|
||||
background: rgba(255, 255, 255, .025);
|
||||
transition: border-color .2s ease, background .2s ease;
|
||||
color: var(--text-soft);
|
||||
font: 600 12px/1 var(--mono);
|
||||
cursor: pointer;
|
||||
transition: border-color .2s ease, background .2s ease, color .2s ease;
|
||||
}
|
||||
.theme-switch:hover { border-color: var(--line-strong); background: rgba(54, 228, 218, .04); }
|
||||
.theme-option {
|
||||
position: relative;
|
||||
.preference-trigger:hover,
|
||||
.preference-menu.open .preference-trigger {
|
||||
border-color: var(--line-strong);
|
||||
background: rgba(54, 228, 218, .06);
|
||||
color: var(--text);
|
||||
}
|
||||
.preference-icon {
|
||||
display: inline-grid;
|
||||
place-items: center;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: var(--text);
|
||||
font: 500 17px/1 "Segoe UI Symbol", "Noto Sans Symbols", sans-serif;
|
||||
}
|
||||
.preference-icon--globe { font-size: 16px; }
|
||||
.preference-chevron { color: var(--text-faint); font: 700 13px/1 var(--mono); transition: transform .2s ease; }
|
||||
.preference-menu.open .preference-chevron { transform: rotate(180deg); }
|
||||
.preference-popover {
|
||||
position: absolute;
|
||||
top: calc(100% + 10px);
|
||||
right: 0;
|
||||
z-index: 1100;
|
||||
display: grid;
|
||||
min-width: 174px;
|
||||
padding: 6px;
|
||||
border: 1px solid var(--line-strong);
|
||||
border-radius: 10px;
|
||||
background: color-mix(in srgb, var(--ink-900) 94%, transparent);
|
||||
box-shadow: 0 18px 44px rgba(0, 0, 0, .2), 0 0 0 1px rgba(255, 255, 255, .035);
|
||||
backdrop-filter: blur(18px) saturate(135%);
|
||||
-webkit-backdrop-filter: blur(18px) saturate(135%);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transform: translateY(-6px) scale(.98);
|
||||
transform-origin: top right;
|
||||
transition: opacity .18s ease, transform .18s var(--ease);
|
||||
}
|
||||
.preference-menu.open .preference-popover { opacity: 1; pointer-events: auto; transform: translateY(0) scale(1); }
|
||||
.preference-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
padding: 0;
|
||||
gap: 10px;
|
||||
width: 100%;
|
||||
min-height: 38px;
|
||||
padding: 0 10px;
|
||||
border: 0;
|
||||
border-radius: 6px;
|
||||
border-radius: 7px;
|
||||
background: transparent;
|
||||
color: var(--text-soft);
|
||||
font: 600 12px/1.4 var(--mono);
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
transition: background .2s ease, box-shadow .2s ease, transform .2s ease;
|
||||
transition: color .18s ease, background .18s ease;
|
||||
}
|
||||
.theme-option:hover { background: color-mix(in srgb, var(--cyan) 8%, transparent); transform: translateY(-1px); }
|
||||
.theme-option[aria-checked="true"] { background: color-mix(in srgb, var(--cyan) 14%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--cyan) 28%, transparent); }
|
||||
.theme-option-icon { width: 13px; height: 13px; border: 1px solid var(--line-strong); border-radius: 50%; box-shadow: 0 0 10px color-mix(in srgb, var(--cyan) 16%, transparent); }
|
||||
.theme-option-icon.system { background: linear-gradient(90deg, #f7fbff 0 49%, #0a1721 51% 100%); }
|
||||
.theme-option-icon.light { background: #eef7ff; box-shadow: 0 0 0 2px rgba(51, 92, 255, .11), 0 0 9px rgba(74, 141, 255, .22); }
|
||||
.theme-option-icon.dark { background: #07131d; box-shadow: inset -3px 0 0 #54ddea, 0 0 9px rgba(54, 228, 218, .18); }
|
||||
.lang-switch {
|
||||
display: inline-flex;
|
||||
padding: 3px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 9px;
|
||||
background: rgba(255, 255, 255, .025);
|
||||
}
|
||||
.lang-btn {
|
||||
min-width: 34px;
|
||||
padding: 5px 8px;
|
||||
border: 0;
|
||||
border-radius: 6px;
|
||||
background: transparent;
|
||||
color: var(--text-faint);
|
||||
font: 650 12px/1.4 var(--mono);
|
||||
cursor: pointer;
|
||||
}
|
||||
.lang-btn.active { color: var(--ink-1000); background: var(--cyan); }
|
||||
.preference-item:hover,
|
||||
.preference-item[aria-checked="true"] { color: var(--text); background: color-mix(in srgb, var(--cyan) 12%, transparent); }
|
||||
.preference-item[aria-checked="true"] { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--cyan) 25%, transparent); }
|
||||
.preference-item-label { flex: 1; }
|
||||
.preference-item-check { color: var(--cyan); opacity: 0; font-size: 13px; }
|
||||
.preference-item[aria-checked="true"] .preference-item-check { opacity: 1; }
|
||||
|
||||
.nav-cta, .button {
|
||||
display: inline-flex;
|
||||
@@ -694,12 +718,10 @@
|
||||
|
||||
:root[data-theme="light"] .navbar { background: rgba(250, 252, 255, .72); }
|
||||
:root[data-theme="light"] .navbar.scrolled { background: rgba(250, 252, 255, .93); box-shadow: 0 12px 40px rgba(35, 53, 87, .08); }
|
||||
:root[data-theme="light"] .lang-switch,
|
||||
:root[data-theme="light"] .theme-switch,
|
||||
:root[data-theme="light"] .preference-trigger,
|
||||
:root[data-theme="light"] .menu-btn { background: rgba(255, 255, 255, .58); }
|
||||
:root[data-theme="light"] .nav-cta,
|
||||
:root[data-theme="light"] .button-primary,
|
||||
:root[data-theme="light"] .lang-btn.active { color: #fff; }
|
||||
:root[data-theme="light"] .button-primary { color: #fff; }
|
||||
:root[data-theme="light"] .button-secondary { background: rgba(255, 255, 255, .58); }
|
||||
|
||||
:root[data-theme="light"] .hero {
|
||||
@@ -733,6 +755,13 @@
|
||||
.hero-spatial { width: min(100%, 760px); min-height: 420px; margin-left: auto; }
|
||||
}
|
||||
|
||||
/* Let desktop layouts use the available canvas on ultrawide screens. */
|
||||
@media (min-width: 1440px) {
|
||||
:root { --max-width: 88vw; }
|
||||
.hero-layout { gap: clamp(64px, 6vw, 132px); }
|
||||
.section-header { gap: clamp(48px, 6vw, 120px); }
|
||||
}
|
||||
|
||||
@media (max-width: 860px) {
|
||||
:root[data-theme="light"] .nav-links { background: rgba(250, 252, 255, .98); }
|
||||
}
|
||||
@@ -901,20 +930,38 @@
|
||||
<a class="nav-link" href="#advantages" data-i18n="nav_advantages">核心优势</a>
|
||||
<a class="nav-link" href="#offices" data-i18n="nav_offices">交付网络</a>
|
||||
<div class="nav-actions">
|
||||
<div class="theme-switch" id="themeSwitch" role="radiogroup" aria-label="外观模式" data-i18n-aria="theme_label">
|
||||
<button class="theme-option" type="button" role="radio" aria-checked="true" data-theme-option="system" aria-label="跟随系统" data-i18n-aria="theme_system">
|
||||
<span class="theme-option-icon system" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button class="theme-option" type="button" role="radio" aria-checked="false" data-theme-option="light" aria-label="浅色外观" data-i18n-aria="theme_light">
|
||||
<span class="theme-option-icon light" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button class="theme-option" type="button" role="radio" aria-checked="false" data-theme-option="dark" aria-label="深色外观" data-i18n-aria="theme_dark">
|
||||
<span class="theme-option-icon dark" aria-hidden="true"></span>
|
||||
<div class="preference-menu" id="themeSwitch">
|
||||
<button class="preference-trigger" type="button" aria-haspopup="menu" aria-expanded="false" aria-label="外观模式" data-i18n-aria="theme_label">
|
||||
<span class="preference-icon" data-theme-current-icon aria-hidden="true">◐</span>
|
||||
<span class="preference-trigger-label" data-theme-current>Auto</span>
|
||||
<span class="preference-chevron" aria-hidden="true">⌄</span>
|
||||
</button>
|
||||
<div class="preference-popover" role="menu">
|
||||
<button class="preference-item" type="button" role="menuitemradio" aria-checked="true" data-theme-option="system" aria-label="跟随系统" data-i18n-aria="theme_system">
|
||||
<span class="preference-icon" aria-hidden="true">◐</span><span class="preference-item-label" data-i18n="theme_system_short">Auto</span><span class="preference-item-check" aria-hidden="true">✓</span>
|
||||
</button>
|
||||
<button class="preference-item" type="button" role="menuitemradio" aria-checked="false" data-theme-option="dark" aria-label="深色外观" data-i18n-aria="theme_dark">
|
||||
<span class="preference-icon" aria-hidden="true">☾</span><span class="preference-item-label" data-i18n="theme_dark_short">Dark</span><span class="preference-item-check" aria-hidden="true">✓</span>
|
||||
</button>
|
||||
<button class="preference-item" type="button" role="menuitemradio" aria-checked="false" data-theme-option="light" aria-label="浅色外观" data-i18n-aria="theme_light">
|
||||
<span class="preference-icon" aria-hidden="true">☼</span><span class="preference-item-label" data-i18n="theme_light_short">Light</span><span class="preference-item-check" aria-hidden="true">✓</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lang-switch" id="langSwitch" aria-label="语言切换" data-i18n-aria="lang_label">
|
||||
<button class="lang-btn active" type="button" data-lang="zh" aria-pressed="true">中</button>
|
||||
<button class="lang-btn" type="button" data-lang="en" aria-pressed="false">EN</button>
|
||||
<div class="preference-menu" id="langSwitch">
|
||||
<button class="preference-trigger" type="button" aria-haspopup="menu" aria-expanded="false" aria-label="语言切换" data-i18n-aria="lang_label">
|
||||
<span class="preference-icon preference-icon--globe" aria-hidden="true">◎</span>
|
||||
<span class="preference-trigger-label" data-language-current>简体中文</span>
|
||||
<span class="preference-chevron" aria-hidden="true">⌄</span>
|
||||
</button>
|
||||
<div class="preference-popover" role="menu">
|
||||
<button class="preference-item" type="button" role="menuitemradio" aria-checked="true" data-lang="zh">
|
||||
<span class="preference-icon preference-icon--globe" aria-hidden="true">◎</span><span class="preference-item-label" data-i18n="language_zh">简体中文</span><span class="preference-item-check" aria-hidden="true">✓</span>
|
||||
</button>
|
||||
<button class="preference-item" type="button" role="menuitemradio" aria-checked="false" data-lang="en">
|
||||
<span class="preference-icon preference-icon--globe" aria-hidden="true">◎</span><span class="preference-item-label" data-i18n="language_en">English</span><span class="preference-item-check" aria-hidden="true">✓</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<a class="nav-cta" href="#contact" data-i18n="nav_contact">预约咨询</a>
|
||||
</div>
|
||||
@@ -1109,7 +1156,7 @@
|
||||
const i18n = {
|
||||
zh: {
|
||||
title: '海南荣刻科技有限公司 - 数据筑基 · AI 落地', skip: '跳到主要内容', brand: '荣刻科技', nav_label: '主导航', home_label: '荣刻科技首页', lang_label: '语言切换', menu_open: '打开导航菜单', menu_close: '关闭导航菜单',
|
||||
theme_label: '外观模式选择', theme_system: '跟随系统', theme_light: '浅色外观', theme_dark: '深色外观',
|
||||
theme_label: '外观模式选择', theme_system: '跟随系统', theme_light: '浅色外观', theme_dark: '深色外观', theme_system_short: 'Auto', theme_light_short: 'Light', theme_dark_short: 'Dark', language_zh: '简体中文', language_en: 'English',
|
||||
nav_about: '能力链路', nav_services: '解决方案', nav_advantages: '核心优势', nav_offices: '交付网络', nav_contact: '预约咨询',
|
||||
hero_eyebrow: 'AI 与数据基础设施', hero_line1: '让企业数据', hero_line2: '成为 AI 生产力',
|
||||
hero_desc: '从数据治理、模型优化到私有化部署,荣刻科技为企业构建可落地、可持续、可掌控的 AI 能力体系。',
|
||||
@@ -1143,7 +1190,7 @@
|
||||
},
|
||||
en: {
|
||||
title: 'Hainan Roncarve Technology - Data Foundation · AI Delivery', skip: 'Skip to main content', brand: 'Roncarve Tech', nav_label: 'Main navigation', home_label: 'Roncarve Tech home', lang_label: 'Language selector', menu_open: 'Open navigation menu', menu_close: 'Close navigation menu',
|
||||
theme_label: 'Appearance selector', theme_system: 'Follow System', theme_light: 'Light appearance', theme_dark: 'Dark appearance',
|
||||
theme_label: 'Appearance selector', theme_system: 'Follow System', theme_light: 'Light appearance', theme_dark: 'Dark appearance', theme_system_short: 'Auto', theme_light_short: 'Light', theme_dark_short: 'Dark', language_zh: '简体中文', language_en: 'English',
|
||||
nav_about: 'Capabilities', nav_services: 'Solutions', nav_advantages: 'Advantages', nav_offices: 'Delivery', nav_contact: 'Book a Call',
|
||||
hero_eyebrow: 'AI + DATA INFRASTRUCTURE', hero_line1: 'Turn enterprise data', hero_line2: 'into AI productivity',
|
||||
hero_desc: 'From data governance and model optimization to private deployment, Roncarve builds practical, sustainable and controllable enterprise AI systems.',
|
||||
@@ -1187,6 +1234,8 @@
|
||||
const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
let currentLanguage = 'zh';
|
||||
let themePreference = document.documentElement.dataset.themePreference || 'system';
|
||||
const themeLabels = { system: 'theme_system_short', light: 'theme_light_short', dark: 'theme_dark_short' };
|
||||
const themeIcons = { system: '◐', light: '☼', dark: '☾' };
|
||||
|
||||
function resolvedTheme(preference) {
|
||||
return preference === 'system' ? (themeQuery.matches ? 'dark' : 'light') : preference;
|
||||
@@ -1201,6 +1250,10 @@
|
||||
document.querySelectorAll('[data-theme-option]').forEach(function (button) {
|
||||
button.setAttribute('aria-checked', String(button.dataset.themeOption === selected));
|
||||
});
|
||||
const themeCurrent = document.querySelector('[data-theme-current]');
|
||||
const themeCurrentIcon = document.querySelector('[data-theme-current-icon]');
|
||||
if (themeCurrent) themeCurrent.textContent = i18n[currentLanguage][themeLabels[selected]];
|
||||
if (themeCurrentIcon) themeCurrentIcon.textContent = themeIcons[selected];
|
||||
const themeColors = { light: '#f7faff', dark: '#05070a' };
|
||||
const themeMeta = document.querySelector('meta[name="theme-color"]');
|
||||
if (themeMeta) themeMeta.setAttribute('content', themeColors[resolved]);
|
||||
@@ -1224,11 +1277,17 @@
|
||||
if (i18n[selected][key]) element.setAttribute('aria-label', i18n[selected][key]);
|
||||
});
|
||||
menuBtn.setAttribute('aria-label', i18n[selected][navLinks.classList.contains('open') ? 'menu_close' : 'menu_open']);
|
||||
document.querySelectorAll('.lang-btn').forEach(function (button) {
|
||||
document.querySelectorAll('[data-lang]').forEach(function (button) {
|
||||
const active = button.dataset.lang === selected;
|
||||
button.classList.toggle('active', active);
|
||||
button.setAttribute('aria-pressed', String(active));
|
||||
button.setAttribute('aria-checked', String(active));
|
||||
});
|
||||
const languageCurrent = document.querySelector('[data-language-current]');
|
||||
if (languageCurrent) languageCurrent.textContent = i18n[selected].language_zh;
|
||||
if (languageCurrent && selected === 'en') languageCurrent.textContent = i18n[selected].language_en;
|
||||
if (themePreference) {
|
||||
const themeCurrent = document.querySelector('[data-theme-current]');
|
||||
if (themeCurrent) themeCurrent.textContent = i18n[selected][themeLabels[themePreference]];
|
||||
}
|
||||
try { localStorage.setItem('site_lang', selected); } catch (error) { /* Storage may be disabled. */ }
|
||||
}
|
||||
|
||||
@@ -1240,19 +1299,39 @@
|
||||
document.body.classList.remove('menu-open');
|
||||
}
|
||||
|
||||
function closePreferenceMenus(except) {
|
||||
document.querySelectorAll('.preference-menu.open').forEach(function (menu) {
|
||||
if (menu !== except) {
|
||||
menu.classList.remove('open');
|
||||
menu.querySelector('.preference-trigger').setAttribute('aria-expanded', 'false');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[themeSwitch, langSwitch].forEach(function (menu) {
|
||||
const trigger = menu.querySelector('.preference-trigger');
|
||||
trigger.addEventListener('click', function () {
|
||||
const open = !menu.classList.contains('open');
|
||||
closePreferenceMenus(menu);
|
||||
menu.classList.toggle('open', open);
|
||||
trigger.setAttribute('aria-expanded', String(open));
|
||||
});
|
||||
});
|
||||
|
||||
langSwitch.addEventListener('click', function (event) {
|
||||
const button = event.target.closest('.lang-btn');
|
||||
if (button) applyLanguage(button.dataset.lang);
|
||||
const button = event.target.closest('[data-lang]');
|
||||
if (!button) return;
|
||||
applyLanguage(button.dataset.lang);
|
||||
langSwitch.classList.remove('open');
|
||||
langSwitch.querySelector('.preference-trigger').setAttribute('aria-expanded', 'false');
|
||||
});
|
||||
|
||||
themeSwitch.addEventListener('click', function (event) {
|
||||
const button = event.target.closest('[data-theme-option]');
|
||||
if (!button) return;
|
||||
applyTheme(button.dataset.themeOption, true);
|
||||
if (window.matchMedia('(max-width: 860px)').matches) {
|
||||
closeMenu();
|
||||
menuBtn.focus();
|
||||
}
|
||||
themeSwitch.classList.remove('open');
|
||||
themeSwitch.querySelector('.preference-trigger').setAttribute('aria-expanded', 'false');
|
||||
});
|
||||
|
||||
const handleSystemTheme = function () {
|
||||
@@ -1272,7 +1351,13 @@
|
||||
|
||||
navLinks.querySelectorAll('a').forEach(function (link) { link.addEventListener('click', closeMenu); });
|
||||
document.addEventListener('keydown', function (event) {
|
||||
if (event.key === 'Escape') closeMenu();
|
||||
if (event.key === 'Escape') {
|
||||
closeMenu();
|
||||
closePreferenceMenus();
|
||||
}
|
||||
});
|
||||
document.addEventListener('click', function (event) {
|
||||
if (!event.target.closest('.preference-menu')) closePreferenceMenus();
|
||||
});
|
||||
|
||||
window.addEventListener('scroll', function () { navbar.classList.toggle('scrolled', window.scrollY > 24); }, { passive: true });
|
||||
|
||||
Reference in New Issue
Block a user