This is an automated email from the ASF dual-hosted git repository.
zhaoqingran pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git
The following commit(s) were added to refs/heads/master by this push:
new 88933ce0bb [feature] Update UI text and styles for website (#3934)
88933ce0bb is described below
commit 88933ce0bbc05e2fb870692e5a696206d1fb71ee
Author: Logic <[email protected]>
AuthorDate: Wed Dec 31 16:00:13 2025 +0800
[feature] Update UI text and styles for website (#3934)
Signed-off-by: Logic <[email protected]>
Signed-off-by: Duansg <[email protected]>
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Duansg <[email protected]>
Co-authored-by: aias00 <[email protected]>
---
home/i18n/en/code.json | 12 +-
home/i18n/zh-cn/code.json | 12 +-
home/src/css/custom.css | 139 +++++++++++++++++++++--
home/src/css/hero.css | 175 +++++++++++++++++++++++++---
home/src/pages/components/Feature.js | 14 ++-
home/src/pages/components/Section.js | 9 +-
home/src/pages/index.js | 138 ++++++++++------------
home/src/pages/styles.module.css | 214 +++++++++++++++++++++++++++++++++--
8 files changed, 583 insertions(+), 130 deletions(-)
diff --git a/home/i18n/en/code.json b/home/i18n/en/code.json
index e5f674d27a..17e16b67bb 100644
--- a/home/i18n/en/code.json
+++ b/home/i18n/en/code.json
@@ -200,13 +200,13 @@
"description": "The live editor label of the live codeblocks"
},
"convenient": {
- "message": "Convenient Used"
+ "message": "Easy to Use"
},
"custom-multi-support": {
- "message": "High Performance and Custom"
+ "message": "High Performance & Extensible"
},
"opensource": {
- "message": "Opensource Friendly"
+ "message": "Open Source & Community Driven"
},
"theme.ErrorPageContent.title": {
"message": "This page crashed.",
@@ -257,13 +257,13 @@
"description": "The label used by the button on the collapsible TOC
component"
},
"convenient-content": {
- "message": "{docker} {br} Monitoring-alarm-notify all in one. Support
monitoring web service, database, cache, os, web-server, middleware, bigdata,
cloud-native, network etc. {br} Easy to use and agentless, full web-based
operations with just a click of a mouse. {br} Security is the most important,
encrypt the whole secret data."
+ "message": "{docker} {br} All-in-one monitoring, alerting, and
notification system. Supports web services, databases, caching, OS, middleware,
big data, cloud-native, and network monitoring. {br} Agentless with full
web-based operations, simply point-and-click to get started. {br}
Enterprise-grade security with end-to-end encryption for all sensitive data."
},
"custom-multi-support-content": {
- "message": "Makes protocols such as Http, Jmx, Ssh, Snmp, Jdbc
configurable, you can collect any metrics by simply configuring the yml online.
{br} High performance, supports horizontal expansion of multi-collector
clusters, multi-isolated network monitoring and cloud-edge collaboration. {br}
Flexible threshold rules and timely notifications delivered via discord slack
email webhook more."
+ "message": "Configurable protocols including HTTP, JMX, SSH, SNMP, and
JDBC. Define custom metrics with simple online YAML configuration. {br}
High-performance architecture with horizontal scaling for collector clusters,
multi-network isolation, and cloud-edge collaboration. {br} Flexible alerting
rules with timely notifications via Discord, Slack, email, Webhook, and more."
},
"opensource-content": {
- "message": "Apache HertzBeat™ is open source, has an inclusive and open
community. Unlimited and anyone who are interested in it are very welcome to
contribute. No matter how small the contribution is, whether it is a code
document or a typo, respect everyone and grow together. {br} Our code is being
deployed on thousands of machines worldwide."
+ "message": "Apache HertzBeat™ is open source with an inclusive community.
We welcome contributions of all sizes—code, documentation, or bug reports. {br}
Respect every contributor and grow together. {br} Deployed on thousands of
servers worldwide."
},
"slogan": {
"message": "AI-powered Open Source Observability System"
diff --git a/home/i18n/zh-cn/code.json b/home/i18n/zh-cn/code.json
index 37741e9625..8d7bb6923a 100644
--- a/home/i18n/zh-cn/code.json
+++ b/home/i18n/zh-cn/code.json
@@ -1,12 +1,12 @@
{
"convenient": {
- "message": "开箱即用"
+ "message": "简单易用"
},
"custom-multi-support": {
- "message": "高性能与自定义"
+ "message": "高性能可扩展"
},
"opensource": {
- "message": "拥抱开源"
+ "message": "开源社区"
},
"theme.ErrorPageContent.title": {
"message": "页面已崩溃。",
@@ -431,13 +431,13 @@
"description": "The live editor label of the live codeblocks"
},
"convenient-content": {
- "message": "{docker}
{br}集监控-告警-通知为一体,支持应用服务,Web,数据库,缓存,操作系统,中间件,大数据,云原生,网络等监控阈值告警通知一步到位。{br}
易用友好,无需Agent,全WEB页面操作,鼠标点一点就能监控告警,无需学习成本。{br}安全是最重要的,数据密钥全链路加密。"
+ "message": "{docker} {br}集监控、告警、通知于一体,支持 Web
服务、数据库、缓存、操作系统、中间件、大数据、云原生、网络等全方位监控。{br}无需 Agent,全 Web
可视化操作,点点鼠标即可上手。{br}企业级安全保障,敏感数据全链路加密。"
},
"custom-multi-support-content": {
- "message": "将 Http,Jmx,Ssh,Snmp,Jdbc 等协议规范可配置模板化,只需在线配置YML就可自定义监控指标。{br}
高性能,支持多采集器集群横向扩展,支持多隔离网络监控,云边协同。{br}灵活的告警阈值规则,邮箱,短信,钉钉,企业微信,飞书,Webhook等消息及时送达。{br}
您相信只需配置下就能适配新K8s监控类型吗?"
+ "message": "支持 HTTP、JMX、SSH、SNMP、JDBC 等协议可配置化,在线配置 YAML
即可自定义监控指标。{br}高性能架构,支持多采集器集群横向扩展、多网络隔离监控、云边协同。{br}灵活的告警规则,支持邮箱、短信、钉钉、企业微信、飞书、Webhook
等多种通知方式。"
},
"opensource-content": {
- "message": "Apache HertzBeat™
是开源的,拥有一个包容开放的社区。{br}欢迎任何对此有兴趣的同学参与其中,无论是代码文档或者错别字,尊重社区的每一位,一起进步成长。{br}我们的代码正被部署到全球成千上万机器上。"
+ "message": "Apache HertzBeat™
是开源项目,拥有开放包容的社区。{br}欢迎任何形式的贡献,无论是代码、文档还是问题反馈,尊重每位贡献者,共同成长。{br}已部署至全球数千台服务器。"
},
"slogan": {
"message": "AI 驱动的下一代开源观测系统"
diff --git a/home/src/css/custom.css b/home/src/css/custom.css
index e6f9a9a4d5..7a1c4b2429 100644
--- a/home/src/css/custom.css
+++ b/home/src/css/custom.css
@@ -1,24 +1,73 @@
+@import
url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap');
@import url(navbar.css);
@import url(hero.css);
:root {
+ --md-primary: #6750A4;
+ --md-on-primary: #FFFFFF;
+ --md-primary-container: #EADDFF;
+ --md-on-primary-container: #21005D;
+ --md-secondary: #625B71;
+ --md-secondary-container: #E8DEF8;
+ --md-on-secondary-container: #1D192B;
+ --md-tertiary: #7D5260;
+ --md-tertiary-container: #FFD8E4;
+ --md-surface: #FFFBFE;
+ --md-surface-dim: #DDD8E1;
+ --md-surface-bright: #FFFBFE;
+ --md-surface-container-low: #F7F2FA;
+ --md-surface-container: #F3EDF7;
+ --md-surface-container-high: #ECE6F0;
+ --md-on-surface: #1C1B1F;
+ --md-on-surface-variant: #49454F;
+ --md-outline: #79747E;
+ --md-outline-variant: #CAC4D0;
+
--ifm-color-primary: #7228B5;
--ifm-color-primary-dark: #6228B5;
--ifm-color-primary-darker: #5228B5;
--ifm-color-primary-darkest: #5128B5;
- --ifm-color-primary-light: #7228B5;
- --ifm-color-primary-lighter: #8228B5;
- --ifm-color-primary-lightest: #9228B5;
+ --ifm-color-primary-light: #8228C5;
+ --ifm-color-primary-lighter: #9228D5;
+ --ifm-color-primary-lightest: #A228E5;
--ifm-navbar-link-hover-color: var(--ifm-color-primary);
--ifm-code-font-size: 95%;
- --ifm-font-family-base: Verdana, Arial, Helvetica, sans-serif;
- --ifm-font-family-monospace: sans-serif;
- --ifm-button-padding-horizontal: 0.55rem;
- --ifm-button-padding-vertical: .7rem;
- --ifm-navbar-height: 85px;
+
+ --ifm-font-family-base: 'Roboto', Verdana, Arial, Helvetica, sans-serif;
+ --ifm-font-family-monospace: 'Courier New', monospace;
+
+ --ifm-button-padding-horizontal: 1.5rem;
+ --ifm-button-padding-vertical: 0.75rem;
+ --ifm-button-border-radius: 9999px;
--ifm-button-border-width: 0;
+ --ifm-navbar-height: 85px;
+
+ --md-easing: cubic-bezier(0.2, 0, 0, 1);
+ --md-transition-fast: 200ms var(--md-easing);
+ --md-transition-medium: 300ms var(--md-easing);
}
+html[data-theme='dark'] {
+ --md-primary: #D0BCFF;
+ --md-on-primary: #381E72;
+ --md-primary-container: #4F378B;
+ --md-on-primary-container: #EADDFF;
+ --md-secondary: #CCC2DC;
+ --md-secondary-container: #4A4458;
+ --md-on-secondary-container: #E8DEF8;
+ --md-tertiary: #EFB8C8;
+ --md-tertiary-container: #633B48;
+ --md-surface: #141218;
+ --md-surface-dim: #141218;
+ --md-surface-bright: #3B383E;
+ --md-surface-container-low: #1D1B20;
+ --md-surface-container: #211F26;
+ --md-surface-container-high: #2B2930;
+ --md-on-surface: #E6E1E5;
+ --md-on-surface-variant: #CAC4D0;
+ --md-outline: #938F99;
+ --md-outline-variant: #49454F;
+}
h1, h2, h3 {
font-weight: 460;
}
@@ -165,3 +214,77 @@ article thead {
padding-left: 20px;
padding-right: 20px;
}
+
+body {
+ background-color: var(--md-surface);
+ color: var(--md-on-surface);
+}
+
+.button {
+ border-radius: 9999px !important;
+ transition: all var(--md-transition-medium) !important;
+ font-weight: 500;
+}
+
+.button--primary {
+ background-color: var(--ifm-color-primary) !important;
+ color: var(--md-on-primary) !important;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
+}
+
+.button--primary:hover {
+ background-color: rgba(114, 40, 181, 0.9) !important;
+ box-shadow: 0 4px 12px rgba(114, 40, 181, 0.3) !important;
+ transform: translateY(-1px);
+}
+
+.button--primary:active {
+ transform: scale(0.95) translateY(0);
+ box-shadow: 0 2px 6px rgba(114, 40, 181, 0.2) !important;
+}
+
+.button:focus-visible {
+ outline: 2px solid var(--md-primary);
+ outline-offset: 2px;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ font-weight: 500;
+ color: var(--md-on-surface);
+}
+
+h1 {
+ font-size: 2.5rem;
+ line-height: 1.2;
+}
+
+h2 {
+ font-size: 2rem;
+ line-height: 1.3;
+}
+
+h3 {
+ font-size: 1.5rem;
+ line-height: 1.4;
+}
+
+a, button {
+ transition: color var(--md-transition-fast),
+ background-color var(--md-transition-fast),
+ border-color var(--md-transition-fast),
+ box-shadow var(--md-transition-medium),
+ transform var(--md-transition-medium);
+}
+
+.card {
+ background-color: var(--md-surface-container);
+ border-radius: 24px;
+ padding: 1.5rem;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
+ transition: all var(--md-transition-medium);
+}
+
+.card:hover {
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
+ transform: scale(1.01);
+}
diff --git a/home/src/css/hero.css b/home/src/css/hero.css
index 1522b3beec..b16cd6f1b4 100644
--- a/home/src/css/hero.css
+++ b/home/src/css/hero.css
@@ -1,34 +1,181 @@
.hero--primary {
- --ifm-hero-background-color: #fff;
- --ifm-hero-text-color: #000;
+ --ifm-hero-background-color: var(--md-surface);
+ --ifm-hero-text-color: var(--md-on-surface);
+ position: relative;
+ overflow: visible;
+ min-height: 600px;
+ display: flex;
+ align-items: center;
}
html[data-theme=dark] .hero--primary {
- --ifm-hero-background-color: #0c0c0c;
- --ifm-hero-text-color: #fff;
+ --ifm-hero-background-color: #121212;
+ --ifm-hero-text-color: var(--md-surface);
+}
+
+.hero--primary::before,
+.hero--primary::after {
+ content: '';
+ position: absolute;
+ border-radius: 50%;
+ filter: blur(80px);
+ opacity: 0.25;
+ z-index: 0;
+ pointer-events: none;
+}
+
+.hero--primary::before {
+ width: 500px;
+ height: 500px;
+ background: var(--md-primary);
+ top: -100px;
+ right: -150px;
+ animation: float 8s ease-in-out infinite;
+}
+
+.hero--primary::after {
+ width: 400px;
+ height: 400px;
+ background: var(--md-secondary-container);
+ bottom: -50px;
+ left: -100px;
+ animation: float 10s ease-in-out infinite reverse;
+}
+
+@keyframes float {
+ 0%, 100% {
+ transform: translate(0, 0);
+ }
+ 50% {
+ transform: translate(20px, -20px);
+ }
+}
+
+.hero--primary .container {
+ position: relative;
+ z-index: 1;
}
.hero__title {
background-size: 110%;
color: transparent;
width: 100%;
- max-width: 600px;
+ max-width: 700px;
margin: 0 auto;
- height: 280px;
+ height: auto;
+ min-height: 200px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.hero__title img {
+ width: 100%;
+ max-width: 600px;
+ height: auto;
+ margin-top: 0;
+ filter: drop-shadow(0 4px 20px rgba(103, 80, 164, 0.15));
+ transition: transform var(--md-transition-medium);
+}
+
+.hero__title img:hover {
+ transform: scale(1.02);
}
.hero__subtitle {
- font-size: 3em;
- font-weight: bolder;
- font-family: monospace;
- color: #d97700;
+ font-size: 2.5rem;
+ font-weight: 700;
+ font-family: 'Roboto', sans-serif;
+ background: linear-gradient(135deg, var(--md-primary) 0%, #A228E5 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
width: 100%;
- margin: 0 auto;
+ max-width: 1000px;
+ margin: 1.5rem auto 2rem;
+ text-align: center;
+ letter-spacing: -0.02em;
+ white-space: nowrap;
}
-@media (max-width: 400px) {
+@media (max-width: 996px) {
+ .hero--primary {
+ min-height: 500px;
+ }
+
+ .hero--primary::before {
+ width: 300px;
+ height: 300px;
+ top: -50px;
+ right: -100px;
+ }
+
+ .hero--primary::after {
+ width: 250px;
+ height: 250px;
+ bottom: -30px;
+ left: -80px;
+ }
+
+ .hero__title {
+ max-width: 500px;
+ min-height: 150px;
+ }
+
+ .hero__subtitle {
+ font-size: 1.8rem;
+ padding: 0 1rem;
+ white-space: normal;
+ }
+}
+
+@media (max-width: 650px) {
+ .hero--primary {
+ min-height: 450px;
+ padding: 2rem 1rem 4rem;
+ }
+
+ .hero__title {
+ max-width: 350px;
+ min-height: 120px;
+ }
+
.hero__subtitle {
- font-size: 1.3em;
- font-weight: bolder;
+ font-size: 1.4rem;
+ margin: 1rem auto 1.5rem;
+ }
+
+ .hero--primary::before,
+ .hero--primary::after {
+ opacity: 0.15;
+ }
+}
+
+.buttons {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ justify-content: center;
+ gap: 1rem;
+ margin: 2rem 0 0;
+}
+
+.buttons > a {
+ margin: 0;
+ min-width: 160px;
+ text-align: center;
+}
+
+@media (max-width: 650px) {
+ .buttons {
+ flex-direction: column;
+ width: 100%;
+ max-width: 300px;
+ margin: 1.5rem auto 0;
+ }
+
+ .buttons > a {
+ width: 100%;
+ margin: 0.25rem 0;
}
}
diff --git a/home/src/pages/components/Feature.js
b/home/src/pages/components/Feature.js
index 0590cf0f0b..77a41cd5a8 100644
--- a/home/src/pages/components/Feature.js
+++ b/home/src/pages/components/Feature.js
@@ -1,11 +1,17 @@
import React from 'react'
import clsx from 'clsx'
+import styles from '../styles.module.css'
-export default function Feature({ title, description }) {
+export default function Feature({ title, description, index = 0 }) {
return (
- <div className={clsx('col col--4')}>
- <h3 style={{textAlign: 'center', fontSize: 'x-large'}}>{title}</h3>
- <p>{description}</p>
+ <div
+ className={clsx('featureCard', styles.featureCard,
styles.animateFadeInUp)}
+ style={{
+ animationDelay: `${index * 0.1}s`
+ }}
+ >
+ <h3 className={styles.featureTitle}>{title}</h3>
+ <p className={styles.featureDescription}>{description}</p>
</div>
)
}
diff --git a/home/src/pages/components/Section.js
b/home/src/pages/components/Section.js
index 24c680a6ca..bcd59b0307 100644
--- a/home/src/pages/components/Section.js
+++ b/home/src/pages/components/Section.js
@@ -1,14 +1,15 @@
import React from 'react'
+import clsx from 'clsx'
+import styles from '../styles.module.css'
-export default function Section({children }) {
+export default function Section({ children, className }) {
return (
- <section style={{padding: '4rem 0', width: '100%' }}>
+ <section className={clsx(styles.section, className)}>
<div className="container">
- <div className="row">
+ <div className={styles.sectionRow}>
{children}
</div>
</div>
</section>
)
}
-
diff --git a/home/src/pages/index.js b/home/src/pages/index.js
index e4e9faf400..ec74afae4b 100644
--- a/home/src/pages/index.js
+++ b/home/src/pages/index.js
@@ -7,16 +7,14 @@ import useBaseUrl from '@docusaurus/useBaseUrl'
import Translate from '@docusaurus/Translate'
import { Swiper, SwiperSlide } from 'swiper/react'
-import { EffectFade, Navigation, Autoplay } from 'swiper'
+import { Autoplay } from 'swiper'
import 'swiper/css'
-import 'swiper/css/navigation'
import 'swiper/css/pagination'
import Feature from './components/Feature'
-import Section from './components/Section'
import styles from './styles.module.css'
-import {features} from '../constants'
+import { features } from '../constants'
function Home() {
const context = useDocusaurusContext()
@@ -28,13 +26,13 @@ function Home() {
title={`${siteConfig.title} · ${siteConfig.tagline}`}
description={`${siteConfig.tagline}`}
>
+ {/* Hero Section */}
<header className={clsx('hero--primary', styles.heroBanner)}>
<div className="container">
<h1 className="hero__title">
<img
- style={{ width: '500px', marginTop: '100px' }}
src={'/img/hertzbeat-brand.svg'}
- alt={'#'}
+ alt={'HertzBeat Logo'}
/>
</h1>
<p className="hero__subtitle">
@@ -52,79 +50,67 @@ function Home() {
</div>
</div>
</header>
- <main>
- <div>
- <Swiper
- modules={[Autoplay, EffectFade, Navigation]}
- watchSlidesProgress={true}
- navigation={{
- nextEl: '.user-swiper-button-next',
- prevEl: '.user-swiper-button-prev',
- }}
- grabCursor
- // effect will disable when auto scroll
- // effect={'fade'}
- // fadeEffect={{
- // crossFade: true
- // }}
- // slidesPerView={1}
- // auto scroll
- loop={true}
- speed={0}
- autoplay={{
- delay: 6000,
- disableOnInteraction: false,
- waitForTransition: false,
- }}
- >
- <SwiperSlide>
- <img
- style={{ width: '1400px', display: 'block', margin: '0
auto' }}
- src={useBaseUrl('/img/docs/hertzbeat-arch.png')}
- />
- </SwiperSlide>
- <SwiperSlide>
- <img
- style={{ width: '1400px', display: 'block', margin: '0
auto' }}
- src={useBaseUrl('/img/home/status.png')}
- />
- </SwiperSlide>
- <SwiperSlide>
- <img
- style={{ width: '1400px', display: 'block', margin: '0
auto' }}
- src={useBaseUrl('/img/home/0.png')}
- />
- </SwiperSlide>
- <SwiperSlide>
- <img
- style={{ width: '1400px', display: 'block', margin: '0
auto' }}
- src={useBaseUrl('/img/home/1.png')}
- />
- </SwiperSlide>
- <SwiperSlide>
- <img
- style={{ width: '1400px', display: 'block', margin: '0
auto' }}
- src={useBaseUrl('/img/home/9.png')}
- />
- </SwiperSlide>
- </Swiper>
- </div>
- <div
- className="swiper-button-prev user-swiper-button-prev"
- style={{ top: '880px', left: '50px', color: '#000033' }}
- />
- <div
- className="swiper-button-next user-swiper-button-next"
- style={{ top: '880px', right: '50px', color: '#000033' }}
- />
+ <main>
+ {/* Features Section */}
{features && features.length > 0 && (
- <Section>
- {features.map((props, idx) => (
- <Feature key={idx} {...props} />
- ))}
- </Section>
+ <section className={styles.featuresSection}>
+ <div className="container">
+ <div className={styles.featuresRow}>
+ {features.map((props, idx) => (
+ <Feature key={idx} {...props} index={idx} />
+ ))}
+ </div>
+ </div>
+ </section>
)}
+
+ {/* Swiper Carousel Section */}
+ <div className={styles.swiperContainer}>
+ <div className="container">
+ <Swiper
+ modules={[Autoplay]}
+ grabCursor
+ loop={true}
+ speed={600}
+ autoplay={{
+ delay: 6000,
+ disableOnInteraction: false,
+ }}
+ >
+ <SwiperSlide>
+ <img
+ src={useBaseUrl('/img/docs/hertzbeat-arch.png')}
+ alt="HertzBeat Architecture"
+ />
+ </SwiperSlide>
+ <SwiperSlide>
+ <img
+ src={useBaseUrl('/img/home/status.png')}
+ alt="Monitoring Status"
+ />
+ </SwiperSlide>
+ <SwiperSlide>
+ <img
+ src={useBaseUrl('/img/home/0.png')}
+ alt="Dashboard Overview"
+ />
+ </SwiperSlide>
+ <SwiperSlide>
+ <img
+ src={useBaseUrl('/img/home/1.png')}
+ alt="Feature Demo"
+ />
+ </SwiperSlide>
+ <SwiperSlide>
+ <img
+ src={useBaseUrl('/img/home/9.png')}
+ alt="Advanced Features"
+ />
+ </SwiperSlide>
+ </Swiper>
+ </div>
+ </div>
</main>
</Layout>
</>
diff --git a/home/src/pages/styles.module.css b/home/src/pages/styles.module.css
index 3ffdb29b38..6154373175 100644
--- a/home/src/pages/styles.module.css
+++ b/home/src/pages/styles.module.css
@@ -5,37 +5,227 @@
* and scoped locally.
*/
+.section {
+ padding: 4rem 0;
+ width: 100%;
+ background: var(--md-surface);
+}
+
+.sectionRow {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 2rem;
+}
+
.heroBanner {
- padding: 1rem 0 5rem;
+ padding: 3rem 0 5rem;
text-align: center;
position: relative;
- overflow: hidden;
+ overflow: visible;
}
@media screen and (max-width: 966px) {
.heroBanner {
- padding: 2rem;
+ padding: 2rem 1rem 4rem;
}
}
-.buttons {
+.swiperContainer {
+ position: relative;
+ background: linear-gradient(180deg,
+ var(--md-surface) 0%,
+ var(--md-surface-container) 100%);
+ padding: 3rem 0;
+ overflow: hidden;
+}
+
+.swiperContainer::before {
+ content: '';
+ position: absolute;
+ width: 600px;
+ height: 600px;
+ background: var(--md-secondary-container);
+ border-radius: 50%;
+ filter: blur(100px);
+ opacity: 0.2;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ z-index: 0;
+ pointer-events: none;
+}
+
+.swiperContainer .swiper {
+ position: relative;
+ z-index: 1;
+ padding: 1rem 0;
+}
+
+.swiperContainer .swiper-slide {
display: flex;
- flex-wrap: wrap;
align-items: center;
justify-content: center;
- margin: 30px 0 0;
+ padding: 1rem;
+}
+
+.swiperContainer .swiper-slide img {
+ width: 100%;
+ max-width: 1200px;
+ height: auto;
+ border-radius: 24px;
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
+ transition: all var(--md-transition-medium);
+}
+
+.swiperContainer .swiper-slide img:hover {
+ box-shadow: 0 8px 30px rgba(103, 80, 164, 0.15);
+ transform: scale(1.01);
+}
+
+@media (max-width: 1200px) {
+ .swiperContainer .swiper-slide img {
+ max-width: 100%;
+ border-radius: 16px;
+ }
+}
+
+@media (max-width: 768px) {
+ .swiperContainer {
+ padding: 2rem 0;
+ }
+}
+
+.featuresSection {
+ background: var(--md-surface);
+ padding: 5rem 0;
+ position: relative;
+}
+
+.featuresSection::before {
+ content: '';
+ position: absolute;
+ width: 400px;
+ height: 400px;
+ background: var(--md-tertiary-container);
+ border-radius: 50%;
+ filter: blur(90px);
+ opacity: 0.15;
+ top: 20%;
+ right: -100px;
+ pointer-events: none;
+}
+
+.featuresRow {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 2rem;
+ position: relative;
+ z-index: 1;
}
-.buttons > a {
- margin: 0 5px;
+@media (max-width: 996px) {
+ .featuresRow {
+ grid-template-columns: repeat(2, 1fr);
+ gap: 1.5rem;
+ }
}
@media (max-width: 650px) {
- .buttons > a {
- margin: 10px 5px;
+ .featuresRow {
+ grid-template-columns: 1fr;
+ gap: 1rem;
+ }
+}
+
+@keyframes fadeInUp {
+ from {
+ opacity: 0;
+ transform: translateY(20px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+.featureCard {
+ background: var(--md-surface-container);
+ border-radius: 24px;
+ padding: 2rem;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
+ transition: all var(--md-transition-medium);
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ text-align: center;
+ height: 100%;
+ position: relative;
+ overflow: hidden;
+}
+
+.featureCard::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 4px;
+ background: linear-gradient(90deg,
+ var(--md-primary) 0%,
+ var(--md-tertiary) 100%);
+ opacity: 0;
+ transition: opacity var(--md-transition-medium);
+}
+
+.featureCard:hover {
+ box-shadow: 0 8px 24px rgba(103, 80, 164, 0.15);
+ transform: translateY(-4px) scale(1.02);
+ background: var(--md-surface-container-low);
+}
+
+.featureCard:hover::before {
+ opacity: 1;
+}
+
+.featureCard:active {
+ transform: translateY(-2px) scale(1.01);
+}
+
+.featureTitle {
+ font-size: 1.35rem;
+ font-weight: 600;
+ color: var(--md-on-surface);
+ margin: 0 0 0.75rem 0;
+ line-height: 1.4;
+}
+
+.featureDescription {
+ font-size: 1rem;
+ line-height: 1.6;
+ color: var(--md-on-surface-variant);
+ margin: 0;
+}
+
+.featureDescription code {
+ background: var(--md-surface-container-high);
+ padding: 0.2rem 0.5rem;
+ border-radius: 8px;
+ font-size: 0.9em;
+ color: var(--md-primary);
+ font-family: 'Courier New', monospace;
+}
+
+@media (max-width: 768px) {
+ .featureCard {
+ padding: 1.5rem;
+ border-radius: 20px;
+ }
+
+ .featureTitle {
+ font-size: 1.2rem;
}
- .frameworkLogos img {
- height: 45px;
+ .featureDescription {
+ font-size: 0.95rem;
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]