From 83216b2765dfddbdc2b8beb7c5a007a9cc227dea Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Wed, 13 May 2026 01:04:58 +0800 Subject: [PATCH] =?UTF-8?q?feat(docs):=20=E5=8D=87=E7=BA=A7=E9=A6=96?= =?UTF-8?q?=E9=A1=B5=E4=B8=8E=E6=9B=B4=E6=96=B0=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/dbx-core/src/lib.rs | 1 + docs/app/[lang]/layout.tsx | 4 +- docs/app/[lang]/page.tsx | 386 ++++++-- docs/app/global.css | 904 ++++++++++++++++-- docs/app/layout.tsx | 6 +- .../aceternity/HeroProductStage.tsx | 21 + .../aceternity/InfiniteMovingCards.tsx | 42 + docs/components/aceternity/Spotlight.tsx | 19 + docs/components/landing/InstallTabs.tsx | 127 +++ docs/components/landing/RevealSection.tsx | 43 + docs/content/docs/changelog.cn.mdx | 197 ++++ docs/content/docs/changelog.mdx | 197 ++++ docs/content/docs/meta.cn.json | 1 + docs/content/docs/meta.json | 1 + docs/package.json | 1 + docs/pnpm-lock.yaml | 3 + docs/public/avatars/acane.png | Bin 0 -> 74514 bytes docs/public/avatars/ar414.jpg | Bin 0 -> 7280 bytes docs/public/avatars/cyano.jpg | Bin 0 -> 9388 bytes docs/public/avatars/dongxuyang85.jpg | Bin 0 -> 8633 bytes docs/public/avatars/guangguang.jpg | Bin 0 -> 7476 bytes docs/public/avatars/husky.jpg | Bin 0 -> 9355 bytes docs/public/avatars/itkui.jpg | Bin 0 -> 8361 bytes docs/public/avatars/mebiuw.jpg | Bin 0 -> 4275 bytes docs/public/avatars/momo.jpg | Bin 0 -> 6322 bytes docs/public/avatars/patrickz.jpg | Bin 0 -> 8661 bytes docs/public/avatars/ryan.jpg | Bin 0 -> 8369 bytes docs/public/avatars/sunzhigang.jpg | Bin 0 -> 2653 bytes docs/public/avatars/vbvb.png | Bin 0 -> 66110 bytes docs/public/avatars/xuyuan.jpg | Bin 0 -> 8769 bytes docs/public/avatars/yanxuecan.jpg | Bin 0 -> 22376 bytes docs/public/avatars/ydwang.png | Bin 0 -> 67553 bytes docs/public/avatars/yingtao.jpg | Bin 0 -> 8943 bytes docs/public/avatars/zhufeng.jpg | Bin 0 -> 9129 bytes docs/public/favicon.png | Bin 0 -> 88141 bytes docs/public/icons/database/clickhouse.svg | 1 + docs/public/icons/database/cockroachdb.svg | 1 + docs/public/icons/database/dm.svg | 1 + docs/public/icons/database/doris.svg | 1 + docs/public/icons/database/duckdb.svg | 1 + docs/public/icons/database/elasticsearch.svg | 1 + docs/public/icons/database/gaussdb.svg | 1 + docs/public/icons/database/kingbase.svg | 1 + docs/public/icons/database/mongodb.svg | 1 + docs/public/icons/database/mysql.svg | 1 + docs/public/icons/database/oceanbase.svg | 1 + docs/public/icons/database/opengauss.svg | 1 + docs/public/icons/database/oracle.svg | 1 + docs/public/icons/database/postgres.svg | 1 + docs/public/icons/database/redis.svg | 1 + docs/public/icons/database/redshift.svg | 1 + docs/public/icons/database/selectdb.svg | 1 + docs/public/icons/database/sqlite.svg | 1 + docs/public/icons/database/sqlserver.svg | 1 + docs/public/icons/database/starrocks.svg | 1 + docs/public/icons/database/tdengine.svg | 1 + docs/public/icons/database/tidb.svg | 1 + src-tauri/src/commands/mod.rs | 1 + src-tauri/src/lib.rs | 2 + src-web/src/main.rs | 4 + src-web/src/routes/mod.rs | 1 + 61 files changed, 1836 insertions(+), 147 deletions(-) create mode 100644 docs/components/aceternity/HeroProductStage.tsx create mode 100644 docs/components/aceternity/InfiniteMovingCards.tsx create mode 100644 docs/components/aceternity/Spotlight.tsx create mode 100644 docs/components/landing/InstallTabs.tsx create mode 100644 docs/components/landing/RevealSection.tsx create mode 100644 docs/content/docs/changelog.cn.mdx create mode 100644 docs/content/docs/changelog.mdx create mode 100644 docs/public/avatars/acane.png create mode 100644 docs/public/avatars/ar414.jpg create mode 100644 docs/public/avatars/cyano.jpg create mode 100644 docs/public/avatars/dongxuyang85.jpg create mode 100644 docs/public/avatars/guangguang.jpg create mode 100644 docs/public/avatars/husky.jpg create mode 100644 docs/public/avatars/itkui.jpg create mode 100644 docs/public/avatars/mebiuw.jpg create mode 100644 docs/public/avatars/momo.jpg create mode 100644 docs/public/avatars/patrickz.jpg create mode 100644 docs/public/avatars/ryan.jpg create mode 100644 docs/public/avatars/sunzhigang.jpg create mode 100644 docs/public/avatars/vbvb.png create mode 100644 docs/public/avatars/xuyuan.jpg create mode 100644 docs/public/avatars/yanxuecan.jpg create mode 100644 docs/public/avatars/ydwang.png create mode 100644 docs/public/avatars/yingtao.jpg create mode 100644 docs/public/avatars/zhufeng.jpg create mode 100644 docs/public/favicon.png create mode 100644 docs/public/icons/database/clickhouse.svg create mode 100644 docs/public/icons/database/cockroachdb.svg create mode 100644 docs/public/icons/database/dm.svg create mode 100644 docs/public/icons/database/doris.svg create mode 100644 docs/public/icons/database/duckdb.svg create mode 100644 docs/public/icons/database/elasticsearch.svg create mode 100644 docs/public/icons/database/gaussdb.svg create mode 100644 docs/public/icons/database/kingbase.svg create mode 100644 docs/public/icons/database/mongodb.svg create mode 100644 docs/public/icons/database/mysql.svg create mode 100644 docs/public/icons/database/oceanbase.svg create mode 100644 docs/public/icons/database/opengauss.svg create mode 100644 docs/public/icons/database/oracle.svg create mode 100644 docs/public/icons/database/postgres.svg create mode 100644 docs/public/icons/database/redis.svg create mode 100644 docs/public/icons/database/redshift.svg create mode 100644 docs/public/icons/database/selectdb.svg create mode 100644 docs/public/icons/database/sqlite.svg create mode 100644 docs/public/icons/database/sqlserver.svg create mode 100644 docs/public/icons/database/starrocks.svg create mode 100644 docs/public/icons/database/tdengine.svg create mode 100644 docs/public/icons/database/tidb.svg diff --git a/crates/dbx-core/src/lib.rs b/crates/dbx-core/src/lib.rs index cd34fdf92e..d561104d41 100644 --- a/crates/dbx-core/src/lib.rs +++ b/crates/dbx-core/src/lib.rs @@ -1,6 +1,7 @@ pub mod ai; pub mod connection; pub mod connection_secrets; +pub mod database_export; pub mod db; pub mod external; pub mod history; diff --git a/docs/app/[lang]/layout.tsx b/docs/app/[lang]/layout.tsx index 2a5fa06831..4443f5b8ad 100644 --- a/docs/app/[lang]/layout.tsx +++ b/docs/app/[lang]/layout.tsx @@ -12,9 +12,9 @@ export default async function LangLayout({ const { lang } = await params; return ( - + - + {children} diff --git a/docs/app/[lang]/page.tsx b/docs/app/[lang]/page.tsx index 362bf52e81..9aee24ffc1 100644 --- a/docs/app/[lang]/page.tsx +++ b/docs/app/[lang]/page.tsx @@ -1,4 +1,10 @@ import Link from 'next/link'; +import type { CSSProperties } from 'react'; +import { HeroProductStage } from '@/components/aceternity/HeroProductStage'; +import { InfiniteMovingCards } from '@/components/aceternity/InfiniteMovingCards'; +import { Spotlight } from '@/components/aceternity/Spotlight'; +import { InstallTabs } from '@/components/landing/InstallTabs'; +import { RevealSection } from '@/components/landing/RevealSection'; import { ArrowRight, Bot, @@ -14,20 +20,75 @@ import { Zap, } from 'lucide-react'; -const languages = ['MySQL', 'PostgreSQL', 'SQLite', 'Redis', 'MongoDB', 'DuckDB', 'ClickHouse', 'SQL Server', 'Oracle']; +const fallbackStarLabel = '1.3k+'; -const metrics = { - en: [ +function formatStars(count: number) { + if (count >= 1000) { + return `${(Math.floor(count / 100) / 10).toFixed(1)}k+`; + } + + return `${count}+`; +} + +async function getGitHubStarLabel() { + try { + const response = await fetch('https://api.github.com/repos/t8y2/dbx', { + headers: { Accept: 'application/vnd.github+json' }, + next: { revalidate: 60 * 60 * 6 }, + }); + + if (!response.ok) return fallbackStarLabel; + + const data = (await response.json()) as { stargazers_count?: number }; + return typeof data.stargazers_count === 'number' ? formatStars(data.stargazers_count) : fallbackStarLabel; + } catch { + return fallbackStarLabel; + } +} + +function metrics(starLabel: string) { + return { + en: [ { value: '~15 MB', label: 'desktop installer' }, { value: '25+', label: 'database engines' }, { value: '2 modes', label: 'desktop and Docker' }, - ], - cn: [ + { value: starLabel, label: 'GitHub stars, fully open-source' }, + ], + cn: [ { value: '~15 MB', label: '桌面安装包' }, { value: '25+', label: '数据库引擎' }, { value: '2 种模式', label: '桌面与 Docker' }, - ], -}; + { value: starLabel, label: 'GitHub Star,完全开源' }, + ], + }; +} + +const databaseSupport = [ + { name: 'MySQL', icon: '/icons/database/mysql.svg', tone: '#4479a1' }, + { name: 'PostgreSQL', icon: '/icons/database/postgres.svg', tone: '#4169e1' }, + { name: 'SQLite', icon: '/icons/database/sqlite.svg', tone: '#5aa6d6' }, + { name: 'Redis', icon: '/icons/database/redis.svg', tone: '#ff4438' }, + { name: 'DuckDB', icon: '/icons/database/duckdb.svg', tone: '#fff000' }, + { name: 'ClickHouse', icon: '/icons/database/clickhouse.svg', tone: '#ffcc01' }, + { name: 'SQL Server', icon: '/icons/database/sqlserver.svg', tone: '#9ca3af' }, + { name: 'MongoDB', icon: '/icons/database/mongodb.svg', tone: '#47a248' }, + { name: 'Oracle', icon: '/icons/database/oracle.svg', tone: '#f80000' }, + { name: 'Elasticsearch', icon: '/icons/database/elasticsearch.svg', tone: '#00bfb3' }, + { name: 'Doris', icon: '/icons/database/doris.svg', tone: '#5b7cfa' }, + { name: 'StarRocks', icon: '/icons/database/starrocks.svg', tone: '#6750ff' }, + { name: 'Redshift', icon: '/icons/database/redshift.svg', tone: '#8c4fff' }, + { name: 'Dameng', icon: '/icons/database/dm.svg', tone: '#3857ff' }, + { name: 'GaussDB', icon: '/icons/database/gaussdb.svg', tone: '#ff5a3d' }, + { name: 'JDBC', initials: 'JDBC', tone: '#6ea8ff' }, + { name: 'TiDB', icon: '/icons/database/tidb.svg', tone: '#e60012' }, + { name: 'OceanBase', icon: '/icons/database/oceanbase.svg', tone: '#2285ff' }, + { name: 'SelectDB', icon: '/icons/database/selectdb.svg', tone: '#22c1c3' }, + { name: 'TDengine', icon: '/icons/database/tdengine.svg', tone: '#2f6fff' }, + { name: 'openGauss', icon: '/icons/database/opengauss.svg', tone: '#1488c9' }, + { name: 'KingBase', icon: '/icons/database/kingbase.svg', tone: '#e1212d' }, + { name: 'CockroachDB', icon: '/icons/database/cockroachdb.svg', tone: '#6933ff' }, + { name: 'More', initials: '···', tone: '#6ea8ff' }, +]; const workflows = { en: [ @@ -103,9 +164,188 @@ const capabilities = { ], }; +const latestUpdates = { + en: { + version: 'v0.5.4', + title: 'Latest updates', + desc: 'Mirrored from the latest GitHub release notes.', + link: 'Read the changelog', + items: [ + 'JDBC SSH tunnels and proxy support', + 'Grouped object browser with context menus', + 'Redis batch operations and command runner', + 'LIKE / NOT LIKE filters in the data grid', + ], + }, + cn: { + version: 'v0.5.4', + title: '最近更新', + desc: '同步 GitHub 最新 Release Notes。', + link: '查看更新日志', + items: [ + 'JDBC SSH 隧道和代理支持', + '对象浏览器分组与右键菜单', + 'Redis 批量操作和命令行', + '数据表格 LIKE / NOT LIKE 过滤', + ], + }, +}; + +const testimonials = { + en: [ + { + name: '@cyano', + role: 'PostgreSQL and Redis workflows', + avatar: '/avatars/cyano.jpg', + quote: 'DBX keeps query work, schema checks, and Redis inspection in one small app. It feels focused instead of overloaded.', + }, + { + name: '@vbvb', + role: 'Daily reporting', + avatar: '/avatars/vbvb.png', + quote: 'The data grid and export flow are the parts I reach for every day. Filters, previews, and edits stay close to the data.', + }, + { + name: '@ar414', + role: 'Self-hosted tooling', + avatar: '/avatars/ar414.jpg', + quote: 'Desktop mode is light enough for local work, and Docker mode makes it easy to give the team browser access.', + }, + { + name: '@ryan', + role: 'Multi-database projects', + avatar: '/avatars/ryan.jpg', + quote: 'I can jump between SQLite, MySQL, MongoDB, and DuckDB without changing tools or waiting on a heavy runtime.', + }, + { + name: '@acane', + role: 'Schema review', + avatar: '/avatars/acane.png', + quote: 'Schema browsing, ER diagrams, and diff tools make reviews faster because the important context is already connected.', + }, + { + name: '@ydwang', + role: 'Agent workflows', + avatar: '/avatars/ydwang.png', + quote: 'The MCP server is a practical touch. It lets coding agents inspect database context without inventing another bridge.', + }, + { + name: '@guangguang', + role: 'Schema navigation', + avatar: '/avatars/guangguang.jpg', + quote: 'Sidebar search and grouped objects make large schemas manageable. I can find what I need without scrolling through hundreds of tables.', + }, + { + name: '@xuyuan', + role: 'SQL editing', + avatar: '/avatars/xuyuan.jpg', + quote: 'Code completion in the SQL editor picks up column names and table aliases automatically. It saves a lot of tab-switching to check schema.', + }, + { + name: '@itkui', + role: 'Data export', + avatar: '/avatars/itkui.jpg', + quote: "Export options cover CSV, Excel, and SQL inserts. For daily data pulls, the workflow is quick and doesn't need extra scripting.", + }, + { + name: '@mebiuw', + role: 'Secure connections', + avatar: '/avatars/mebiuw.jpg', + quote: 'SSH tunnel setup is straightforward — fill in the fields and connect. No need to manage port forwarding manually in a terminal.', + }, + { + name: '@patrickz', + role: 'Database design', + avatar: '/avatars/patrickz.jpg', + quote: 'ER diagrams give a clear picture of table relationships. Useful during design reviews when the team needs a shared visual reference.', + }, + { + name: '@yanxuecan', + role: 'AI-assisted queries', + avatar: '/avatars/yanxuecan.jpg', + quote: 'The AI assistant helps draft queries from natural language. It handles routine JOINs and aggregations well enough to speed things up.', + }, + ], + cn: [ + { + name: '不剪发的Tony老师', + role: 'PostgreSQL 与 Redis 工作流', + avatar: '/avatars/dongxuyang85.jpg', + quote: 'DBX 把查询、结构检查和 Redis 查看放在一个轻量工具里,日常数据库工作不会被复杂界面打断。', + }, + { + name: 'Husky明夋', + role: '报表与数据核对', + avatar: '/avatars/husky.jpg', + quote: '数据表格、过滤、预览和导出都离数据很近,用起来像是为高频操作专门整理过。', + }, + { + name: '孙志岗', + role: '团队自托管工具', + avatar: '/avatars/sunzhigang.jpg', + quote: '本地桌面版足够轻,自托管 Web 版又方便团队共用,同一个项目覆盖了两种场景。', + }, + { + name: 'zhufeng', + role: '多数据库项目', + avatar: '/avatars/zhufeng.jpg', + quote: 'SQLite、MySQL、MongoDB、DuckDB 来回切换不用换工具,也不用拖着很重的运行时。', + }, + { + name: '樱桃小财主', + role: '结构审查', + avatar: '/avatars/yingtao.jpg', + quote: '结构浏览、ER 图和 Schema 对比放在一起,做 review 时上下文更完整。', + }, + { + name: 'momo', + role: 'Agent 数据库上下文', + avatar: '/avatars/momo.jpg', + quote: 'MCP Server 很实用,能让编码 Agent 读取数据库上下文,不需要再额外搭桥。', + }, + { + name: '逛逛GitHub', + role: '结构导航', + avatar: '/avatars/guangguang.jpg', + quote: '侧边栏搜索和分组浏览让大型 Schema 也不会迷路,不用在几百张表里翻来翻去。', + }, + { + name: '序员先生', + role: 'SQL 编辑', + avatar: '/avatars/xuyuan.jpg', + quote: 'SQL 编辑器的补全能自动识别列名和别名,不用反复切到结构面板去确认字段。', + }, + { + name: 'IT老魁', + role: '数据导出', + avatar: '/avatars/itkui.jpg', + quote: '导出支持 CSV、Excel 和 INSERT 语句,日常取数据很快,不用再额外写脚本。', + }, + { + name: 'MebiuW', + role: '安全连接', + avatar: '/avatars/mebiuw.jpg', + quote: 'SSH 隧道设置很直接,填好参数就能连,不用在终端里手动转发端口。', + }, + { + name: 'Patrick Zhang', + role: '数据库设计', + avatar: '/avatars/patrickz.jpg', + quote: 'ER 图把表关系展示得很清楚,团队做设计评审时有个共同的可视化参考。', + }, + { + name: '闫学灿', + role: 'AI 辅助查询', + avatar: '/avatars/yanxuecan.jpg', + quote: 'AI 助手能从自然语言生成查询,常规的 JOIN 和聚合写得不错,省了不少手敲时间。', + }, + ], +}; + const i18nText = { en: { navDocs: 'Docs', + navChangelog: 'Changelog', navCommunity: 'Community', lang: '中文', eyebrow: 'Open-source database workspace', @@ -114,14 +354,15 @@ const i18nText = { 'DBX brings connections, SQL editing, data grids, schema tools, AI assistance, and self-hosted access into one lightweight product.', download: 'Download DBX', readDocs: 'Read the docs', - installLabel: 'Install on macOS', - installCommand: 'brew install --cask t8y2/tap/dbx', docsStart: 'Start here', docsStartDesc: 'Install DBX, create your first connection, and learn the main workflow.', workflowsTitle: 'Core workflows', workflowsDesc: 'The docs are organized around what you actually do in a database client.', - supportTitle: 'Database coverage', - supportDesc: 'SQL, NoSQL, embedded databases, and popular MySQL/PostgreSQL-compatible engines.', + supportTitle: 'Supports many databases', + supportDesc: + 'Connect and manage SQL, NoSQL, embedded databases, and MySQL/PostgreSQL-compatible engines without switching tools.', + testimonialsTitle: 'What DBX is good at', + testimonialsDesc: 'A closer look at the everyday database workflows DBX is built to make smoother.', capabilitiesTitle: 'Built for real database work', footerTitle: 'Ready to try DBX?', footerDesc: 'Use the desktop app for local work, or deploy the Docker version for browser-based access.', @@ -130,6 +371,7 @@ const i18nText = { }, cn: { navDocs: '文档', + navChangelog: '更新日志', navCommunity: '社区', lang: 'English', eyebrow: '开源数据库工作台', @@ -137,14 +379,15 @@ const i18nText = { heroSubtitle: 'DBX 将连接管理、SQL 编辑、数据表格、结构工具、AI 助手和自托管访问放进一个轻量产品里。', download: '下载 DBX', readDocs: '查看文档', - installLabel: 'macOS 安装', - installCommand: 'brew install --cask t8y2/tap/dbx', docsStart: '从这里开始', docsStartDesc: '安装 DBX、创建第一个连接,并了解主要工作流。', workflowsTitle: '核心工作流', workflowsDesc: '文档围绕数据库客户端里的真实任务组织,而不是堆功能清单。', - supportTitle: '数据库覆盖', - supportDesc: '覆盖 SQL、NoSQL、嵌入式数据库,以及常见 MySQL/PostgreSQL 兼容数据库。', + supportTitle: '支持多种数据库', + supportDesc: + '告别频繁切换工具的烦恼。DBX 可以连接和管理多种数据库类型,让你更专注于查询、分析和数据本身。', + testimonialsTitle: 'DBX 适合什么样的工作', + testimonialsDesc: '从连接管理、数据浏览到 AI 辅助,DBX 围绕高频数据库工作流打磨体验。', capabilitiesTitle: '面向真实数据库工作的能力', footerTitle: '准备试试 DBX?', footerDesc: '本地工作使用桌面版,需要浏览器访问时部署 Docker 版。', @@ -163,7 +406,10 @@ export default async function LandingPage({ const t = i18nText[l]; const workflowItems = workflows[l]; const capabilityItems = capabilities[l]; - const metricItems = metrics[l]; + const starLabel = await getGitHubStarLabel(); + const metricItems = metrics(starLabel)[l]; + const latest = latestUpdates[l]; + const testimonialItems = testimonials[l]; return (
@@ -174,7 +420,12 @@ export default async function LandingPage({ DBX
- {t.navDocs} + + {t.navDocs} + + + {t.navChangelog} + GitHub @@ -186,62 +437,53 @@ export default async function LandingPage({
+
{t.eyebrow}

{t.heroTitle}

{t.heroSubtitle}

- + {t.download} - + {t.readDocs}
-
- {t.installLabel} - {t.installCommand} -
-
-
-
- - - -
- DBX product screenshot +
+
-
+ {metricItems.map((item) => (
{item.value} {item.label}
))} -
+ -
+

{t.docsStart}

{t.docsStartDesc}

- + {t.readDocs} -
+ -
+

{t.workflowsTitle}

{t.workflowsDesc}

{workflowItems.map((item) => ( - +

{item.title}

{item.desc}

@@ -252,25 +494,37 @@ export default async function LandingPage({ ))}
-
+ -
+

{t.supportTitle}

{t.supportDesc}

-
- {languages.map((db) => ( - - - {db} - +
+ {databaseSupport.map((db) => ( +
+
+ {db.icon ? : {db.initials}} +
+ {db.name} +
))} - + more
-
+ -
+ +
+

{t.testimonialsTitle}

+

{t.testimonialsDesc}

+
+
+ + +
+
+ +

{t.capabilitiesTitle}

@@ -282,18 +536,42 @@ export default async function LandingPage({
))} - + -
+ +
{latest.version}
+
+

{latest.title}

+

{latest.desc}

+
+
    + {latest.items.map((item) => ( +
  • + + {item} +
  • + ))} +
+ + {latest.link} + + +
+ +

{t.footerTitle}

{t.footerDesc}

- {t.release} - {t.docker} + + {t.release} + + + {t.docker} +
-
+
); } diff --git a/docs/app/global.css b/docs/app/global.css index aeaad1ff4a..d6133811ed 100644 --- a/docs/app/global.css +++ b/docs/app/global.css @@ -282,32 +282,111 @@ a { .landing { --landing-max: 1180px; - --landing-panel: color-mix(in srgb, var(--color-fd-card) 82%, transparent); - --landing-panel-strong: color-mix(in srgb, var(--color-fd-card) 94%, var(--color-fd-background)); - --landing-line: color-mix(in srgb, var(--color-fd-border) 86%, transparent); - --landing-soft: color-mix(in srgb, var(--color-fd-muted) 54%, transparent); - --landing-blue: #2563eb; - --landing-sky: #0ea5e9; - --landing-green: #0f9f6e; + --landing-ink: #f7fbff; + --landing-muted: #9aa9bc; + --landing-panel: color-mix(in srgb, #11151d 84%, transparent); + --landing-panel-strong: color-mix(in srgb, #171c26 94%, transparent); + --landing-line: rgba(155, 176, 205, 0.18); + --landing-soft: rgba(148, 163, 184, 0.1); + --landing-blue: #6ea8ff; + --landing-sky: #52d5ff; + --landing-green: #44d19d; min-height: 100vh; - color: var(--color-fd-foreground); + color: var(--landing-ink); background: - radial-gradient(circle at 14% 6%, color-mix(in srgb, var(--landing-sky) 12%, transparent), transparent 330px), - radial-gradient(circle at 86% 4%, color-mix(in srgb, var(--landing-blue) 10%, transparent), transparent 360px), - linear-gradient(180deg, color-mix(in srgb, var(--color-fd-muted) 38%, transparent), transparent 440px), - var(--color-fd-background); + linear-gradient(180deg, #07090d 0%, #0d1118 44%, #10151d 100%), + #0d1118; + overflow: hidden; } .landing a { text-decoration: none; } +.landing-reveal { + opacity: 0; + transform: translateY(26px); + transition: + opacity 0.72s ease, + transform 0.72s cubic-bezier(0.16, 1, 0.3, 1); + transition-delay: var(--reveal-delay, 0ms); + will-change: opacity, transform; +} + +.landing-reveal.is-visible { + opacity: 1; + transform: translateY(0); +} + +.landing-reveal .landing-workflow-card, +.landing-reveal .landing-db-card, +.landing-reveal .landing-capability, +.landing-reveal .landing-update-list li, +.landing-reveal .landing-metrics div { + opacity: 0; + transform: translateY(14px); + transition: + opacity 0.58s ease, + transform 0.58s cubic-bezier(0.16, 1, 0.3, 1); +} + +.landing-reveal.is-visible .landing-workflow-card, +.landing-reveal.is-visible .landing-db-card, +.landing-reveal.is-visible .landing-capability, +.landing-reveal.is-visible .landing-update-list li, +.landing-reveal.is-visible .landing-metrics div { + opacity: 1; + transform: translateY(0); +} + +.landing-reveal.is-visible .landing-workflow-card:nth-child(2), +.landing-reveal.is-visible .landing-db-card:nth-child(2), +.landing-reveal.is-visible .landing-capability:nth-child(2), +.landing-reveal.is-visible .landing-update-list li:nth-child(2), +.landing-reveal.is-visible .landing-metrics div:nth-child(2) { + transition-delay: 70ms; +} + +.landing-reveal.is-visible .landing-workflow-card:nth-child(3), +.landing-reveal.is-visible .landing-db-card:nth-child(3), +.landing-reveal.is-visible .landing-capability:nth-child(3), +.landing-reveal.is-visible .landing-update-list li:nth-child(3), +.landing-reveal.is-visible .landing-metrics div:nth-child(3) { + transition-delay: 120ms; +} + +.landing-reveal.is-visible .landing-workflow-card:nth-child(4), +.landing-reveal.is-visible .landing-db-card:nth-child(4), +.landing-reveal.is-visible .landing-capability:nth-child(4), +.landing-reveal.is-visible .landing-update-list li:nth-child(4), +.landing-reveal.is-visible .landing-metrics div:nth-child(4) { + transition-delay: 170ms; +} + +.landing-reveal.is-visible .landing-db-card:nth-child(8n + 5), +.landing-reveal.is-visible .landing-capability:nth-child(5) { + transition-delay: 210ms; +} + +.landing-reveal.is-visible .landing-db-card:nth-child(8n + 6), +.landing-reveal.is-visible .landing-capability:nth-child(6) { + transition-delay: 250ms; +} + +.landing-reveal.is-visible .landing-db-card:nth-child(8n + 7) { + transition-delay: 290ms; +} + +.landing-reveal.is-visible .landing-db-card:nth-child(8n) { + transition-delay: 330ms; +} + .landing-nav { position: sticky; top: 0; z-index: 20; border-bottom: 1px solid var(--landing-line); - background: color-mix(in srgb, var(--color-fd-background) 88%, transparent); + background: color-mix(in srgb, #080b10 82%, transparent); backdrop-filter: blur(18px); } @@ -325,7 +404,6 @@ a { .landing-nav-links, .landing-hero-cta, .landing-inline-link, -.landing-db-list span, .landing-final-actions, .landing-capability { display: flex; @@ -334,7 +412,7 @@ a { .landing-logo { gap: 10px; - color: var(--color-fd-foreground); + color: var(--landing-ink); font-size: 15px; font-weight: 700; } @@ -350,14 +428,19 @@ a { .landing-nav-links a { border-radius: 7px; padding: 8px 11px; - color: var(--color-fd-muted-foreground); + color: var(--landing-muted); font-size: 13px; font-weight: 500; + transition: + background 0.16s ease, + color 0.16s ease, + transform 0.16s ease; } .landing-nav-links a:hover { background: var(--landing-soft); - color: var(--color-fd-foreground); + color: var(--landing-ink); + transform: translateY(-1px); } .landing-lang-switch { @@ -366,17 +449,67 @@ a { } .landing-hero { + position: relative; display: grid; - grid-template-columns: minmax(0, 0.9fr) minmax(500px, 1.1fr); - gap: 42px; - align-items: center; + grid-template-columns: minmax(0, 470px) minmax(520px, 1fr); + gap: 56px; + align-items: start; max-width: var(--landing-max); + min-height: 570px; margin: 0 auto; - padding: 82px 28px 36px; + padding: 76px 28px 42px; + isolation: isolate; +} + +.landing-hero::before { + content: ''; + position: absolute; + inset: 0 -40px auto; + height: 100%; + border-bottom: 1px solid var(--landing-line); + background: + radial-gradient(circle at 68% 22%, rgba(82, 213, 255, 0.1), transparent 360px), + linear-gradient(90deg, rgba(7, 9, 13, 0.98) 0%, rgba(7, 9, 13, 0.92) 48%, rgba(7, 9, 13, 0.68) 100%), + linear-gradient(180deg, rgba(7, 9, 13, 0.12) 0%, #0d1118 100%); + z-index: -3; +} + +.landing-hero::after { + content: ''; + position: absolute; + inset: 86px 12px 20px; + background-image: + linear-gradient(rgba(110, 168, 255, 0.1) 1px, transparent 1px), + linear-gradient(90deg, rgba(110, 168, 255, 0.1) 1px, transparent 1px); + background-size: 54px 54px; + mask-image: radial-gradient(circle at 66% 48%, black 0%, transparent 62%); + opacity: 0.46; + pointer-events: none; + transform: perspective(1200px) rotateX(58deg) translateY(90px); + transform-origin: center bottom; + animation: landing-grid-drift 13s linear infinite; + z-index: -2; +} + +.aceternity-spotlight { + position: absolute; + inset: -18% auto auto 6%; + width: min(760px, 68vw); + height: 620px; + border-radius: 999px; + background: + radial-gradient(circle at 28% 28%, rgba(255, 255, 255, 0.2), transparent 14%), + radial-gradient(circle at 38% 34%, rgba(82, 213, 255, 0.26), transparent 34%), + radial-gradient(circle at 50% 50%, rgba(110, 168, 255, 0.18), transparent 58%); + filter: blur(44px); + mix-blend-mode: screen; + pointer-events: none; + z-index: -1; } .landing-hero-copy { - max-width: 520px; + max-width: 470px; + animation: landing-rise 0.72s ease-out both; } .landing-eyebrow { @@ -385,24 +518,30 @@ a { border-radius: 999px; margin-bottom: 18px; padding: 6px 10px; - color: var(--color-fd-muted-foreground); + background: rgba(255, 255, 255, 0.04); + color: color-mix(in srgb, var(--landing-sky) 74%, white); font-size: 12px; font-weight: 600; + box-shadow: + 0 0 0 1px rgba(82, 213, 255, 0.04) inset, + 0 0 28px rgba(82, 213, 255, 0.13); + animation: landing-pulse 3.8s ease-in-out infinite; } .landing-hero h1 { - max-width: 620px; + max-width: 470px; margin: 0; - font-size: clamp(38px, 4.6vw, 58px); + font-size: clamp(38px, 4.2vw, 56px); font-weight: 760; letter-spacing: 0; line-height: 1.06; + color: var(--landing-ink); } .landing-hero p { - max-width: 560px; + max-width: 470px; margin: 22px 0 0; - color: var(--color-fd-muted-foreground); + color: var(--landing-muted); font-size: 17px; line-height: 1.72; } @@ -428,64 +567,218 @@ a { .landing-btn-primary { gap: 8px; - background: var(--color-fd-foreground); - color: var(--color-fd-background); + background: #f7fbff; + color: #090d13; + box-shadow: + 0 14px 36px rgba(110, 168, 255, 0.18), + 0 0 0 1px rgba(255, 255, 255, 0.4) inset; + transition: + opacity 0.16s ease, + transform 0.16s ease, + box-shadow 0.16s ease; + animation: landing-cta-glow 3.4s ease-in-out infinite; } .landing-btn-primary:hover { opacity: 0.88; + transform: translateY(-1px); + box-shadow: 0 18px 42px rgba(110, 168, 255, 0.25); } .landing-btn-secondary, .landing-final-actions a { border: 1px solid var(--landing-line); background: var(--landing-panel); - color: var(--color-fd-foreground); + color: var(--landing-ink); + transition: + border-color 0.16s ease, + background 0.16s ease, + transform 0.16s ease; } .landing-btn-secondary:hover, .landing-final-actions a:hover { - border-color: color-mix(in srgb, var(--color-fd-muted-foreground) 42%, var(--landing-line)); + border-color: rgba(178, 200, 230, 0.34); background: var(--landing-panel-strong); + transform: translateY(-1px); } .landing-install { - display: grid; - grid-template-columns: max-content minmax(0, 1fr); - gap: 12px; - align-items: center; - max-width: 500px; + display: block; + max-width: 540px; + min-height: 174px; border: 1px solid var(--landing-line); border-radius: 8px; margin-top: 18px; - padding: 10px 12px; - background: color-mix(in srgb, var(--color-fd-background) 72%, transparent); + padding: 8px; + background: rgba(10, 14, 20, 0.72); + backdrop-filter: blur(14px); } -.landing-install span { - color: var(--color-fd-muted-foreground); - font-size: 12px; - font-weight: 600; +.landing-install-tabs { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 6px; + margin-bottom: 8px; } -.landing-install code { +.landing-install-tab { + display: grid; + gap: 2px; + min-width: 0; + border: 1px solid transparent; + border-radius: 6px; + padding: 8px 6px; + background: transparent; + color: var(--landing-muted); + text-align: center; + cursor: pointer; + transition: + border-color 0.16s ease, + background 0.16s ease, + color 0.16s ease; +} + +.landing-install-tab:hover, +.landing-install-tab[aria-selected='true'] { + border-color: rgba(178, 200, 230, 0.2); + background: rgba(255, 255, 255, 0.055); + color: var(--landing-ink); +} + +.landing-install-tab span { overflow: hidden; - color: var(--color-fd-foreground); font-size: 12px; + font-weight: 700; text-overflow: ellipsis; white-space: nowrap; } +.landing-install-tab small { + overflow: hidden; + color: var(--landing-muted); + font-size: 10px; + font-weight: 600; + line-height: 1.2; + text-overflow: ellipsis; + white-space: nowrap; +} + +.landing-install-command { + display: grid; + grid-template-columns: minmax(0, 1fr) 34px; + gap: 8px; + align-items: stretch; +} + +.landing-install-command code { + display: flex; + align-items: center; + min-height: 38px; + overflow: hidden; + border: 1px solid rgba(155, 176, 205, 0.14); + border-radius: 6px; + padding: 8px 10px; + background: rgba(3, 7, 12, 0.45); + color: var(--landing-ink); + font-size: 12px; + line-height: 1.5; + white-space: normal; + overflow-wrap: anywhere; +} + +.landing-install-copy { + display: grid; + place-items: center; + border: 1px solid rgba(155, 176, 205, 0.16); + border-radius: 6px; + background: rgba(255, 255, 255, 0.045); + color: var(--landing-ink); + cursor: pointer; + transition: + border-color 0.16s ease, + background 0.16s ease, + transform 0.16s ease; +} + +.landing-install-copy:hover { + border-color: rgba(178, 200, 230, 0.34); + background: rgba(255, 255, 255, 0.075); + transform: translateY(-1px); +} + +.landing-install-release { + display: inline-flex; + gap: 6px; + align-items: center; + margin-top: 8px; + color: var(--landing-blue); + font-size: 12px; + font-weight: 650; +} + .landing-product { position: relative; + align-self: center; + width: min(600px, 100%); + margin: 64px 0 0; overflow: hidden; border: 1px solid var(--landing-line); - border-radius: 10px; + border-radius: 12px; background: #0d1117; - box-shadow: 0 26px 74px rgba(0, 0, 0, 0.22); + box-shadow: + 0 34px 90px rgba(0, 0, 0, 0.38), + 0 0 0 1px rgba(255, 255, 255, 0.03) inset; + transform-style: preserve-3d; + transition: + box-shadow 0.24s ease, + transform 0.24s ease; +} + +.landing-product::before { + content: ''; + position: absolute; + inset: 0; + border-radius: inherit; + padding: 1px; + background: conic-gradient( + from 180deg, + transparent, + rgba(110, 168, 255, 0.04), + rgba(82, 213, 255, 0.28), + rgba(68, 209, 157, 0.18), + rgba(110, 168, 255, 0.04), + transparent + ); + -webkit-mask: + linear-gradient(#000 0 0) content-box, + linear-gradient(#000 0 0); + -webkit-mask-composite: xor; + mask-composite: exclude; + pointer-events: none; + z-index: 4; +} + +.landing-product::after { + content: ''; + position: absolute; + inset: 34px 0 0; + background: + radial-gradient(circle at 72% 18%, rgba(82, 213, 255, 0.1), transparent 18%), + linear-gradient(180deg, transparent 64%, rgba(68, 209, 157, 0.035)); + mix-blend-mode: screen; + pointer-events: none; + z-index: 3; +} + +.landing-product:hover { + transform: translateY(-4px) scale(1.01); + box-shadow: 0 42px 110px rgba(0, 0, 0, 0.48); } .landing-window-bar { + position: relative; + z-index: 2; display: flex; gap: 7px; height: 34px; @@ -515,6 +808,8 @@ a { } .landing-product img { + position: relative; + z-index: 1; display: block; width: 100%; aspect-ratio: 16 / 10; @@ -524,6 +819,7 @@ a { .landing-metrics, .landing-doc-start, +.landing-updates, .landing-section, .landing-final { max-width: var(--landing-max); @@ -534,20 +830,30 @@ a { .landing-metrics { display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 0; - padding-top: 18px; + grid-template-columns: repeat(4, 1fr); + gap: 12px; + padding-top: 24px; padding-bottom: 44px; + animation: landing-rise 0.72s ease-out 0.1s both; } .landing-metrics div { - border-top: 1px solid var(--landing-line); - padding: 22px 22px 0 0; + min-height: 118px; + border: 1px solid rgba(155, 176, 205, 0.14); + border-radius: 10px; + padding: 22px; + background: + radial-gradient(circle at 78% 12%, rgba(110, 168, 255, 0.12), transparent 44%), + linear-gradient(180deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.018)), + rgba(12, 15, 22, 0.72); + box-shadow: + 0 18px 44px rgba(0, 0, 0, 0.14), + 0 0 0 1px rgba(255, 255, 255, 0.02) inset; } .landing-metrics strong { display: block; - color: var(--color-fd-foreground); + color: var(--landing-ink); font-size: 24px; font-weight: 720; } @@ -555,7 +861,7 @@ a { .landing-metrics span { display: block; margin-top: 4px; - color: var(--color-fd-muted-foreground); + color: var(--landing-muted); font-size: 13px; } @@ -564,10 +870,17 @@ a { align-items: center; justify-content: space-between; gap: 22px; - border-top: 1px solid var(--landing-line); - border-bottom: 1px solid var(--landing-line); - padding-top: 24px; - padding-bottom: 24px; + border: 1px solid rgba(155, 176, 205, 0.14); + border-radius: 10px; + padding-top: 28px; + padding-bottom: 28px; + background: + radial-gradient(circle at 78% 16%, rgba(68, 209, 157, 0.1), transparent 34%), + linear-gradient(180deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.018)), + rgba(12, 15, 22, 0.72); + box-shadow: + 0 18px 44px rgba(0, 0, 0, 0.14), + 0 0 0 1px rgba(255, 255, 255, 0.02) inset; } .landing-doc-start h2, @@ -577,13 +890,14 @@ a { font-size: 25px; font-weight: 720; letter-spacing: 0; + color: var(--landing-ink); } .landing-doc-start p, .landing-section-heading p, .landing-final p { margin: 8px 0 0; - color: var(--color-fd-muted-foreground); + color: var(--landing-muted); font-size: 14px; line-height: 1.65; } @@ -594,10 +908,14 @@ a { color: var(--landing-blue); font-size: 14px; font-weight: 650; + transition: + color 0.16s ease, + transform 0.16s ease; } .landing-inline-link:hover { - color: color-mix(in srgb, var(--landing-blue) 78%, var(--color-fd-foreground)); + color: color-mix(in srgb, var(--landing-sky) 70%, white); + transform: translateX(2px); } .landing-section { @@ -605,6 +923,67 @@ a { padding-bottom: 4px; } +.landing-updates { + display: grid; + grid-template-columns: minmax(86px, 0.16fr) minmax(210px, 0.32fr) minmax(0, 0.38fr) max-content; + gap: 22px; + align-items: center; + border-top: 1px solid var(--landing-line); + border-bottom: 1px solid var(--landing-line); + margin-top: 62px; + padding-top: 24px; + padding-bottom: 24px; +} + +.landing-update-version { + width: max-content; + border: 1px solid var(--landing-line); + border-radius: 7px; + padding: 7px 10px; + background: var(--landing-panel); + color: var(--landing-blue); + font-size: 13px; + font-weight: 720; +} + +.landing-update-copy h2 { + margin: 0; + font-size: 21px; + font-weight: 720; + letter-spacing: 0; +} + +.landing-update-copy p { + margin: 6px 0 0; + color: var(--landing-muted); + font-size: 13px; + line-height: 1.55; +} + +.landing-update-list { + display: grid; + gap: 8px; + margin: 0; + padding: 0; + list-style: none; +} + +.landing-update-list li { + display: flex; + gap: 8px; + align-items: center; + min-width: 0; + color: color-mix(in srgb, var(--landing-ink) 88%, var(--landing-muted)); + font-size: 13px; + font-weight: 560; + line-height: 1.45; +} + +.landing-update-list svg { + flex: 0 0 auto; + color: var(--landing-green); +} + .landing-section-heading { display: grid; grid-template-columns: minmax(220px, 0.42fr) minmax(0, 0.58fr); @@ -626,10 +1005,12 @@ a { min-height: 250px; border-right: 1px solid var(--landing-line); padding: 24px; - color: var(--color-fd-foreground); + color: var(--landing-ink); transition: + border-color 0.16s ease, background 0.16s ease, - transform 0.16s ease; + transform 0.16s ease, + box-shadow 0.16s ease; } .landing-workflow-card:last-child { @@ -638,7 +1019,9 @@ a { .landing-workflow-card:hover { background: var(--landing-panel-strong); - transform: translateY(-1px); + border-color: rgba(110, 168, 255, 0.24); + transform: translateY(-3px); + box-shadow: 0 24px 50px rgba(0, 0, 0, 0.18); } .landing-workflow-card > svg { @@ -653,7 +1036,7 @@ a { .landing-workflow-card p { margin: 10px 0 0; - color: var(--color-fd-muted-foreground); + color: var(--landing-muted); font-size: 13px; line-height: 1.62; } @@ -663,43 +1046,221 @@ a { align-items: center; gap: 6px; margin-top: 18px; - color: var(--color-fd-foreground); + color: var(--landing-ink); font-size: 13px; font-weight: 650; } .landing-support { + position: relative; +} + +.landing-testimonials { + overflow: hidden; +} + +.landing-testimonial-wall { + position: relative; display: grid; - grid-template-columns: minmax(260px, 0.42fr) minmax(0, 0.58fr); - gap: 36px; - align-items: start; + gap: 14px; + margin-right: -28px; + margin-left: -28px; + padding: 4px 0; +} + +.landing-testimonial-wall::before, +.landing-testimonial-wall::after { + content: ''; + position: absolute; + top: 0; + bottom: 0; + z-index: 2; + width: min(180px, 18vw); + pointer-events: none; +} + +.landing-testimonial-wall::before { + left: 0; + background: linear-gradient(90deg, #0d1118, rgba(13, 17, 24, 0)); +} + +.landing-testimonial-wall::after { + right: 0; + background: linear-gradient(270deg, #0d1118, rgba(13, 17, 24, 0)); +} + +.landing-testimonial-marquee { + display: flex; + overflow: hidden; + user-select: none; +} + +.landing-testimonial-marquee[data-speed='slow'] { + --testimonial-duration: 58s; +} + +.landing-testimonial-marquee[data-speed='normal'] { + --testimonial-duration: 42s; +} + +.landing-testimonial-track { + display: flex; + width: max-content; + min-width: 100%; + gap: 14px; + padding: 0 7px; + animation: landing-testimonial-scroll var(--testimonial-duration, 48s) linear infinite; + animation-play-state: running !important; +} + +.landing-testimonial-marquee[data-direction='right'] .landing-testimonial-track { + animation-direction: reverse; +} + +.landing-testimonial-wall:hover .landing-testimonial-track, +.landing-testimonial-marquee:hover .landing-testimonial-track, +.landing-testimonial-card:hover { + animation-play-state: running !important; +} + +.landing-testimonial-card { + flex: 0 0 340px; + min-height: 188px; + border: 1px solid rgba(155, 176, 205, 0.14); + border-radius: 9px; + margin: 0; + padding: 22px; + background: + linear-gradient(180deg, rgba(255, 255, 255, 0.055), rgba(255, 255, 255, 0.025)), + rgba(13, 18, 26, 0.78); + box-shadow: + 0 18px 45px rgba(0, 0, 0, 0.18), + 0 0 0 1px rgba(255, 255, 255, 0.025) inset; +} + +.landing-testimonial-author { + display: flex; + gap: 12px; + align-items: center; +} + +.landing-testimonial-avatar { + width: 42px; + height: 42px; + flex: 0 0 auto; + border: 1px solid rgba(178, 200, 230, 0.18); + border-radius: 50%; + background: rgba(255, 255, 255, 0.04); + object-fit: cover; +} + +.landing-testimonial-author strong { + display: block; + color: var(--landing-ink); + font-size: 15px; + font-weight: 740; + line-height: 1.25; +} + +.landing-testimonial-author span { + display: block; + margin-top: 3px; + color: var(--landing-muted); + font-size: 12px; + line-height: 1.35; +} + +.landing-testimonial-card blockquote { + margin: 18px 0 0; + color: color-mix(in srgb, var(--landing-ink) 88%, var(--landing-muted)); + font-size: 14px; + font-weight: 560; + line-height: 1.58; } .landing-support .landing-section-heading { + grid-template-columns: minmax(260px, 0.28fr) minmax(0, 0.72fr); + margin-bottom: 30px; +} + +.landing-support .landing-section-heading p { + max-width: 760px; + justify-self: end; + text-align: right; +} + +.landing-db-grid { + display: grid; + grid-template-columns: repeat(8, minmax(0, 1fr)); + gap: 12px; +} + +.landing-db-card { + display: grid; + place-items: center; + min-height: 126px; + border: 1px solid rgba(155, 176, 205, 0.14); + border-radius: 10px; + padding: 18px 10px; + background: + radial-gradient(circle at 50% 112%, color-mix(in srgb, var(--db-tone) 20%, transparent), transparent 62%), + linear-gradient(180deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.018)), + rgba(12, 15, 22, 0.74); + box-shadow: + 0 18px 44px rgba(0, 0, 0, 0.15), + 0 0 0 1px rgba(255, 255, 255, 0.02) inset; + transition: + border-color 0.16s ease, + background 0.16s ease, + transform 0.16s ease; +} + +.landing-db-card:hover { + border-color: color-mix(in srgb, var(--db-tone) 42%, rgba(155, 176, 205, 0.18)); + background: + radial-gradient(circle at 50% 112%, color-mix(in srgb, var(--db-tone) 26%, transparent), transparent 62%), + linear-gradient(180deg, rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0.024)), + rgba(14, 18, 27, 0.9); + transform: translateY(-3px); +} + +.landing-db-icon { + display: grid; + place-items: center; + width: 48px; + height: 48px; + margin-bottom: 15px; +} + +.landing-db-icon img { display: block; - margin-bottom: 0; + width: 38px; + height: 38px; + object-fit: contain; + filter: drop-shadow(0 10px 20px color-mix(in srgb, var(--db-tone) 20%, transparent)); } -.landing-db-list { - display: flex; - flex-wrap: wrap; - gap: 8px; +.landing-db-icon span { + display: grid; + place-items: center; + min-width: 46px; + height: 32px; + border-radius: 8px; + padding: 0 8px; + background: color-mix(in srgb, var(--db-tone) 78%, #10151d); + color: #fff; + box-shadow: 0 10px 20px color-mix(in srgb, var(--db-tone) 22%, transparent); + font-size: 12px; + font-weight: 780; + letter-spacing: 0; } -.landing-db-list span { - gap: 7px; - border: 1px solid var(--landing-line); - border-radius: 7px; - min-height: 34px; - padding: 0 11px; - background: var(--landing-panel); - color: var(--color-fd-muted-foreground); - font-size: 13px; - font-weight: 600; -} - -.landing-db-list svg { - color: var(--landing-green); +.landing-db-card strong { + color: color-mix(in srgb, var(--landing-ink) 92%, var(--landing-muted)); + font-size: 14px; + font-weight: 650; + line-height: 1.2; + text-align: center; } .landing-capability-grid { @@ -715,6 +1276,16 @@ a { border-radius: 8px; padding: 14px 15px; background: var(--landing-panel); + transition: + border-color 0.16s ease, + background 0.16s ease, + transform 0.16s ease; +} + +.landing-capability:hover { + border-color: rgba(110, 168, 255, 0.24); + background: var(--landing-panel-strong); + transform: translateY(-2px); } .landing-capability svg { @@ -723,7 +1294,7 @@ a { } .landing-capability span { - color: var(--color-fd-foreground); + color: var(--landing-ink); font-size: 13px; font-weight: 560; line-height: 1.45; @@ -751,7 +1322,7 @@ a { @media (max-width: 1040px) { .landing-hero { - grid-template-columns: 1fr; + display: block; padding-top: 56px; } @@ -760,7 +1331,9 @@ a { } .landing-product { + width: auto; max-width: 860px; + margin-top: 44px; } .landing-workflow-grid, @@ -768,6 +1341,15 @@ a { grid-template-columns: repeat(2, minmax(0, 1fr)); } + .landing-updates { + grid-template-columns: minmax(0, 1fr) max-content; + } + + .landing-update-copy, + .landing-update-list { + grid-column: 1 / -1; + } + .landing-workflow-card:nth-child(2n) { border-right: 0; } @@ -791,6 +1373,7 @@ a { .landing-hero, .landing-metrics, .landing-doc-start, + .landing-updates, .landing-section, .landing-final { padding-right: 18px; @@ -799,6 +1382,7 @@ a { .landing-hero { padding-top: 44px; + min-height: 0; } .landing-hero h1 { @@ -806,6 +1390,27 @@ a { line-height: 1.05; } + .landing-hero::before { + right: -18px; + background: + radial-gradient(circle at 50% 16%, rgba(82, 213, 255, 0.12), transparent 260px), + linear-gradient(180deg, rgba(7, 9, 13, 0.9) 0%, #0d1118 88%); + } + + .landing-hero::after { + inset: 130px -90px 0; + opacity: 0.3; + } + + .aceternity-spotlight { + inset: -12% auto auto -20%; + width: 92vw; + } + + .landing-product { + margin-top: 34px; + } + .landing-install { grid-template-columns: 1fr; gap: 5px; @@ -817,10 +1422,12 @@ a { } .landing-metrics div { - padding: 16px 0; + min-height: 96px; + padding: 18px; } .landing-doc-start, + .landing-updates, .landing-section-heading, .landing-support, .landing-final { @@ -831,6 +1438,11 @@ a { margin-top: 16px; } + .landing-update-copy, + .landing-update-list { + margin-top: 16px; + } + .landing-workflow-grid, .landing-capability-grid { grid-template-columns: 1fr; @@ -846,9 +1458,121 @@ a { border-bottom: 0; } - .landing-db-list, + .landing-db-grid, + .landing-testimonial-wall, .landing-capability-grid, .landing-final-actions { margin-top: 18px; } + + .landing-db-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 10px; + } + + .landing-db-card { + min-height: 122px; + padding: 16px 10px; + } + + .landing-testimonial-wall { + margin-right: -18px; + margin-left: -18px; + } + + .landing-testimonial-wall::before, + .landing-testimonial-wall::after { + width: 46px; + } + + .landing-testimonial-card { + flex-basis: 286px; + min-height: 210px; + padding: 18px; + } +} + +@keyframes landing-rise { + from { + opacity: 0; + transform: translateY(18px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes landing-grid-drift { + from { + background-position: 0 0; + } + + to { + background-position: 54px 54px; + } +} + +@keyframes landing-pulse { + 0%, + 100% { + border-color: rgba(155, 176, 205, 0.18); + box-shadow: + 0 0 0 1px rgba(82, 213, 255, 0.04) inset, + 0 0 28px rgba(82, 213, 255, 0.13); + } + + 50% { + border-color: rgba(82, 213, 255, 0.34); + box-shadow: + 0 0 0 1px rgba(82, 213, 255, 0.12) inset, + 0 0 42px rgba(82, 213, 255, 0.22); + } +} + +@keyframes landing-cta-glow { + 0%, + 100% { + box-shadow: + 0 14px 36px rgba(110, 168, 255, 0.18), + 0 0 0 1px rgba(255, 255, 255, 0.4) inset; + } + + 50% { + box-shadow: + 0 18px 48px rgba(82, 213, 255, 0.32), + 0 0 0 1px rgba(255, 255, 255, 0.52) inset; + } +} + +@keyframes landing-testimonial-scroll { + from { + transform: translateX(0); + } + + to { + transform: translateX(calc(-50% - 7px)); + } +} + +@media (prefers-reduced-motion: reduce) { + .landing *, + .landing *::before, + .landing *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + scroll-behavior: auto !important; + transition-duration: 0.01ms !important; + } + + .landing-reveal, + .landing-reveal .landing-workflow-card, + .landing-reveal .landing-db-card, + .landing-reveal .landing-capability, + .landing-reveal .landing-update-list li, + .landing-reveal .landing-metrics div { + opacity: 1 !important; + transform: none !important; + } } diff --git a/docs/app/layout.tsx b/docs/app/layout.tsx index e29180b769..22dbf7c3ad 100644 --- a/docs/app/layout.tsx +++ b/docs/app/layout.tsx @@ -7,7 +7,11 @@ export const metadata = { template: '%s | DBX', }, description: '25+ databases in 15 MB. Desktop & Docker self-hosting, with built-in AI assistant.', - icons: { icon: '/logo.png' }, + icons: { + icon: '/favicon.png', + shortcut: '/favicon.png', + apple: '/logo.png', + }, }; export default function RootLayout({ children }: { children: ReactNode }) { diff --git a/docs/components/aceternity/HeroProductStage.tsx b/docs/components/aceternity/HeroProductStage.tsx new file mode 100644 index 0000000000..0b10109878 --- /dev/null +++ b/docs/components/aceternity/HeroProductStage.tsx @@ -0,0 +1,21 @@ +'use client'; + +import { motion } from 'motion/react'; + +export function HeroProductStage() { + return ( + +
+ + + +
+ DBX product screenshot +
+ ); +} diff --git a/docs/components/aceternity/InfiniteMovingCards.tsx b/docs/components/aceternity/InfiniteMovingCards.tsx new file mode 100644 index 0000000000..218e46fa65 --- /dev/null +++ b/docs/components/aceternity/InfiniteMovingCards.tsx @@ -0,0 +1,42 @@ +'use client'; + +type Testimonial = { + name: string; + role: string; + quote: string; + avatar: string; +}; + +type InfiniteMovingCardsProps = { + items: Testimonial[]; + direction?: 'left' | 'right'; + speed?: 'slow' | 'normal'; +}; + +export function InfiniteMovingCards({ items, direction = 'left', speed = 'normal' }: InfiniteMovingCardsProps) { + const repeatedItems = [...items, ...items]; + + return ( +
+
+ {repeatedItems.map((item, index) => ( +
+
+ +
+ {item.name} + {item.role} +
+
+
{item.quote}
+
+ ))} +
+
+ ); +} diff --git a/docs/components/aceternity/Spotlight.tsx b/docs/components/aceternity/Spotlight.tsx new file mode 100644 index 0000000000..3c7158787d --- /dev/null +++ b/docs/components/aceternity/Spotlight.tsx @@ -0,0 +1,19 @@ +'use client'; + +import { motion } from 'motion/react'; + +type SpotlightProps = { + className?: string; +}; + +export function Spotlight({ className = '' }: SpotlightProps) { + return ( +