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}
-
-
-
-
-
-
-
-
-

+
+
-
+
{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 (
+
+
+
+
+
+
+
+
+ );
+}
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 (
+
+ );
+}
diff --git a/docs/components/landing/InstallTabs.tsx b/docs/components/landing/InstallTabs.tsx
new file mode 100644
index 0000000000..0ac828c2f4
--- /dev/null
+++ b/docs/components/landing/InstallTabs.tsx
@@ -0,0 +1,127 @@
+'use client';
+
+import { Check, Copy, ExternalLink } from 'lucide-react';
+import { useState } from 'react';
+
+type InstallTabsProps = {
+ lang: 'en' | 'cn';
+};
+
+const releaseUrl = 'https://github.com/t8y2/dbx/releases/latest';
+
+const installOptions = {
+ en: [
+ {
+ id: 'macos',
+ label: 'macOS',
+ note: 'Homebrew',
+ command: 'brew install --cask t8y2/tap/dbx',
+ linkText: 'GitHub Releases',
+ },
+ {
+ id: 'windows',
+ label: 'Windows',
+ note: 'Scoop',
+ command: 'scoop bucket add dbx https://github.com/t8y2/scoop-bucket; scoop install dbx',
+ linkText: 'GitHub Releases',
+ },
+ {
+ id: 'linux',
+ label: 'Linux',
+ note: '.deb / AppImage',
+ command: 'chmod +x DBX*.AppImage',
+ linkText: 'Download packages',
+ },
+ {
+ id: 'docker',
+ label: 'Docker',
+ note: 'Self-hosted',
+ command: 'docker run -d --name dbx -p 4224:4224 -v dbx-data:/app/data t8y2/dbx',
+ linkText: 'Docker docs',
+ href: '/en/docs/getting-started#docker',
+ },
+ ],
+ cn: [
+ {
+ id: 'macos',
+ label: 'macOS',
+ note: 'Homebrew',
+ command: 'brew install --cask t8y2/tap/dbx',
+ linkText: 'GitHub Releases',
+ },
+ {
+ id: 'windows',
+ label: 'Windows',
+ note: 'Scoop',
+ command: 'scoop bucket add dbx https://github.com/t8y2/scoop-bucket; scoop install dbx',
+ linkText: 'GitHub Releases',
+ },
+ {
+ id: 'linux',
+ label: 'Linux',
+ note: '.deb / AppImage',
+ command: 'chmod +x DBX*.AppImage',
+ linkText: '下载安装包',
+ },
+ {
+ id: 'docker',
+ label: 'Docker',
+ note: '自托管',
+ command: 'docker run -d --name dbx -p 4224:4224 -v dbx-data:/app/data t8y2/dbx',
+ linkText: 'Docker 文档',
+ href: '/cn/docs/getting-started#docker',
+ },
+ ],
+};
+
+export function InstallTabs({ lang }: InstallTabsProps) {
+ const options = installOptions[lang];
+ const [activeId, setActiveId] = useState(options[0].id);
+ const [copied, setCopied] = useState(false);
+ const active = options.find((item) => item.id === activeId) ?? options[0];
+
+ async function copyCommand() {
+ await navigator.clipboard.writeText(active.command);
+ setCopied(true);
+ window.setTimeout(() => setCopied(false), 1600);
+ }
+
+ return (
+
+
+ {options.map((item) => (
+
+ ))}
+
+
+ {active.command}
+
+
+
+ {active.linkText}
+
+
+
+ );
+}
diff --git a/docs/components/landing/RevealSection.tsx b/docs/components/landing/RevealSection.tsx
new file mode 100644
index 0000000000..a1cdd7bd6c
--- /dev/null
+++ b/docs/components/landing/RevealSection.tsx
@@ -0,0 +1,43 @@
+'use client';
+
+import type { CSSProperties, ReactNode } from 'react';
+import { useEffect, useRef, useState } from 'react';
+
+type RevealSectionProps = {
+ children: ReactNode;
+ className?: string;
+ delay?: number;
+};
+
+export function RevealSection({ children, className = '', delay = 0 }: RevealSectionProps) {
+ const ref = useRef(null);
+ const [visible, setVisible] = useState(false);
+
+ useEffect(() => {
+ const node = ref.current;
+ if (!node) return;
+
+ const observer = new IntersectionObserver(
+ ([entry]) => {
+ if (entry.isIntersecting) {
+ setVisible(true);
+ observer.unobserve(entry.target);
+ }
+ },
+ { rootMargin: '0px 0px -14% 0px', threshold: 0.18 },
+ );
+
+ observer.observe(node);
+ return () => observer.disconnect();
+ }, []);
+
+ return (
+
+ );
+}
diff --git a/docs/content/docs/changelog.cn.mdx b/docs/content/docs/changelog.cn.mdx
new file mode 100644
index 0000000000..e3542eabd0
--- /dev/null
+++ b/docs/content/docs/changelog.cn.mdx
@@ -0,0 +1,197 @@
+---
+title: 更新日志
+description: 按版本查看 DBX 的新增功能、体验改进和问题修复,内容同步自 GitHub Releases。
+---
+
+这里整理 DBX 的版本变化,按版本号从新到旧排列。内容以 GitHub Releases 为准,保留功能、改进和修复条目,下载安装说明请查看对应 GitHub Release 页面。
+
+## v0.5.4
+
+[GitHub Release](https://github.com/t8y2/dbx/releases/tag/v0.5.4)
+
+### 新功能
+
+- **JDBC SSH 隧道和代理支持** — JDBC 连接新增 SSH 隧道和代理支持,自动解析和改写 JDBC URL 中的 host:port,通过隧道安全访问远程数据库
+- **对象浏览器分组与右键菜单** — 对象浏览器按类型分组显示数据库对象,新增右键上下文菜单操作
+- **Redis 批量操作和命令行** — Redis 新增批量键操作和命令执行器
+- **数据库代理支持** — 新增数据库连接和 AI 的代理 (Proxy) 支持
+- **数据表格 LIKE/NOT LIKE 过滤** — 右键菜单新增 LIKE、NOT LIKE、大于、小于等过滤条件
+- **数据库对象源码编辑** — 支持查看和编辑数据库对象(存储过程、函数、视图等)的源码
+- **Connection URL 动态占位符** — 连接对话框根据数据库类型动态显示对应的 URL 格式示例 (contributed by @Abeautifulsnow)
+- **AI Thinking 开关** — AI 设置新增 thinking 开关,可关闭本地模型(如 Ollama/vLLM)的思考输出以节省 token (contributed by @rarnu)
+- **PostgreSQL 新类型支持** — 新增 PostgreSQL 整数数组和 float4 类型支持 (contributed by @xKrah)
+- **西班牙语支持** — 新增西班牙语本地化,重构语言切换为下拉菜单 (contributed by @Max29xD)
+
+### 改进
+
+- **设置页面优化** — AI 模型设置移至全局设置页面,优化设置页面布局和选中项样式 (contributed by @rarnu)
+- **单元格值不再截断** — 修复详情面板和复制/导出操作中单元格值被截断为 256 字符的问题,现在显示完整内容 (contributed by @Abeautifulsnow)
+- **虚拟滚动优化** — 优化数据表格虚拟滚动,减少快速滚动时的白屏闪烁
+- **数据表格工具栏** — 优化数据表格工具栏布局
+- **Redis 键浏览器国际化** — Redis 键浏览器新增国际化支持 (contributed by @xKrah)
+- **设置页面链接** — 改进设置对话框中的链接显示
+
+### 修复
+
+- **Oracle RAC/SCAN 连接** — 修复 Oracle RAC/SCAN 连接重定向问题 (closes #209)
+- **Oracle 表数据加载与编辑** — 修复 Oracle 表数据加载和编辑功能异常
+- **Oracle Schema 切换** — 简化编辑器选择器并支持 schema 切换 (closes #205)
+- **Oracle 非英文 Windows 连接错误** — 修复 Oracle 在非英文 Windows 系统上的连接错误检测 (closes #208)
+- **Oracle Schema Diff** — 加速 Oracle schema diff 并增加注释同步 (closes #198)
+- **侧边栏性能** — 修复 100+ 数据库时侧边栏 UI 卡顿 (closes #201)
+- **侧边栏搜索** — 修复侧边栏搜索无法找到被对象浏览器隐藏的表
+- **侧边栏刷新** — 修复展开节点刷新时子节点缓存未清除的问题
+- **WHERE 过滤持久化** — 修复 WHERE 过滤条件在 tab 切换时丢失的问题 (closes #210)
+- **数据表格分页** — 修复保存数据后分页大小被重置的问题
+- **Enter 键补全** — 修复 Enter 键优先选中自动补全建议项 (closes #202)
+- **SQL Server 对象源码** — 修复 SQL Server 对象源码定义保存问题
+- **构建修复** — 修复单引号导致构建失败的问题 (contributed by @xKrah)
+- **侧边栏双击** — 修复侧边栏需要双击才能打开对象浏览器的问题
+- **虚拟树优化** — 修复非空树的虚拟化判断函数
+
+## v0.5.3
+
+[GitHub Release](https://github.com/t8y2/dbx/releases/tag/v0.5.3)
+
+### 新功能
+
+- **AI SQL 智能执行** — AI 助手支持自动执行 SQL 语句,内置安全防护策略,根据语句类型自动判断是否允许执行
+- **MongoDB 表视图** — 新增 MongoDB 集合的表格视图,支持内联编辑数据
+- **导入 DBeaver 连接** — 支持从 DBeaver 导入数据库连接配置
+- **导入 Navicat 连接** — 支持从 Navicat NCX 文件导入数据库连接配置
+- **存储过程/函数浏览** — 对象浏览器支持显示存储过程和函数
+- **虚拟对象浏览器** — 新增虚拟对象浏览器,统一展示数据库对象
+- **数据库活动历史** — 支持追踪和查看数据库操作历史记录
+- **外部表格数据源基础** — 新增外部表格数据源的通用底座架构,为后续接入 CSV/XLSX/在线表格等数据源奠定基础 (contributed by @BlueSkyXN)
+- **数据表格加载指示器** — 数据表格新增加载遮罩层和耗时计时器,查询执行状态一目了然
+
+### 改进
+
+- **编辑器增强** — 编辑器功能增强、DataGrid 重构和侧边栏交互改进
+- **XLSX 导出** — 表格右键菜单新增 XLSX 导出选项
+- **全栈性能优化** — 全栈性能优化和安全加固
+- **Oracle 加载提速** — 优化 Oracle 数据库初始表加载速度
+- **DuckDB 编译优化** — DuckDB 捆绑编译改为可选,减小构建体积
+
+### 修复
+
+- **侧边栏树状态** — 修复侧边栏树状态显示问题
+- **GitHub 链接** — 修复设置页面 About 中 GitHub 链接不可点击的问题
+- **Web 连接池** — 修复带前缀的 Web 连接池被意外断开的问题
+- **连接配置缓存** — 修复 Web 连接配置缓存同步问题
+- **Oracle Schema 缓存** — 修复 Oracle Schema 缓存刷新和表列表不完整的问题
+- **Oracle NCHAR 解码** — 修复 Oracle NCHAR 值解码不正确的问题
+- **侧边栏搜索折叠** — 修复侧边栏搜索结果无法折叠的问题
+
+## v0.5.2
+
+[GitHub Release](https://github.com/t8y2/dbx/releases/tag/v0.5.2)
+
+### 新功能
+
+- **JDBC 插件支持** — 新增可选的 JDBC 插件模块,支持通过 JDBC 驱动连接更多数据库类型
+- **SQL 代码库** — 支持保存和管理常用 SQL 语句,存储在应用数据库中,随时复用
+- **DataGrip 风格列过滤器** — 数据表格支持类似 DataGrip 的列过滤功能,快速筛选数据
+- **数据对比与结构同步** — 新增数据对比和表结构同步功能
+- **连接 URL 和 XLSX 导出** — 支持通过连接 URL 快速创建连接,支持导出数据为 XLSX 格式
+- **连接颜色标识** — 连接支持自定义颜色标识,方便区分不同环境
+- **表格剪贴板快捷键** — 数据表格支持复制粘贴等剪贴板快捷键操作
+- **布局偏好设置** — 支持自定义界面布局偏好
+- **SSH 超时配置** — SSH 隧道连接支持配置超时时间
+
+### 改进
+
+- **界面外观优化** — 优化面板、标签页和应用整体外观布局
+
+### 修复
+
+- **Redis 键表列对齐** — 修复 Redis 键表格列宽未对齐的问题
+- **连接状态同步** — 修复展开缓存树时连接状态未同步的问题
+- **连接对话框错误** — 修复连接对话框的错误提示问题
+- **SQL 注释后查询检测** — 修复 SQL 注释后的结果查询未被正确检测的问题
+- **列过滤弹窗优化** — 优化列过滤弹窗的交互体验
+- **查询标签页持久化** — 修复未保存的查询标签页丢失的问题
+- **隐藏系统数据库对象** — 修复侧栏显示系统数据库对象的问题
+- **文件选择器行为** — 修复 Web 版文件选择器的行为不一致问题
+
+## v0.5.1
+
+[GitHub Release](https://github.com/t8y2/dbx/releases/tag/v0.5.1)
+
+### 新功能
+
+- **设置页关于标签** — 设置对话框新增"关于"标签页,方便查看版本信息
+- **数据库对象列表缓存** — 侧栏数据库对象列表支持缓存,减少重复查询,加速切换
+- **从分组菜单创建连接** — 侧栏分组右键菜单支持直接创建新连接
+- **编辑器 Tab 缩进** — SQL 编辑器支持 Tab 键缩进
+- **Windows 绿色版压缩包** — 新增 Windows 便携版(ZIP),无需安装即可使用
+
+### 改进
+
+- **查询结果流式加载** — 查询结果使用流式传输并限制行数,提升大数据量查询的响应速度
+- **侧栏搜索性能优化** — 侧栏搜索匹配算法优化,过滤速度更快
+- **表格右键菜单增强** — 数据表格右键菜单功能增强
+- **数据表工具栏条件刷新** — 修复表数据编辑的工具栏,条件过滤和刷新不再丢失状态 (contributed by @rarnu)
+- **AI 对话历史可切换** — AI 助手对话历史支持开关控制
+
+### 修复
+
+- **SQL Server 编辑支持** — 修复 SQL Server 数据编辑相关问题
+- **更新后重启** — 修复应用更新后重启失败的问题
+- **表格翻页滚动位置** — 修复翻页后表格滚动位置未重置的问题
+- **MySQL 事务编辑** — 修复 MySQL 事务编辑使用原始 SQL 执行的问题
+- **侧栏刷新保持展开** — 修复侧栏刷新后树节点展开状态丢失的问题
+- **标题栏双击切换** — 修复标题栏双击时窗口状态重复切换的问题 (#179)
+- **默认库过滤数据库树** — 修复默认数据库配置过滤数据库树显示的问题 (#175)
+- **标签文字被箭头遮挡** — 修复标签页滚动箭头与文字重叠的问题
+- **表格与弹窗布局** — 优化表格与 SQL 文件弹窗的布局显示
+- **事务状态位置** — 事务状态指示移至操作按钮旁边,更直观
+- **WHERE/ORDER BY 条件** — 修复 WHERE 和 ORDER BY 输入框条件重复和状态丢失的问题
+- **默认数据库处理** — 统一默认数据库的处理逻辑
+
+## v0.5.0
+
+[GitHub Release](https://github.com/t8y2/dbx/releases/tag/v0.5.0)
+
+### 新功能
+
+- **Redis 浏览器全面重构** — 键浏览器升级为 Navicat 风格表格视图,支持键值编辑、分页浏览和全库键扫描 (contributed by @Bacon2994)
+- **自定义标题栏** — 窗口标题栏改为自定义样式,集成窗口控制按钮
+- **数据表格 WHERE/ORDER BY 过滤** — 数据表格新增独立的 WHERE 和 ORDER BY 输入框,支持自定义条件过滤和排序 (#165)
+- **结果集数据过滤** — 查询结果集内支持对已加载数据进行实时过滤 (contributed by @rarnu)
+- **单元格值编辑器** — 单元格详情面板支持直接编辑值和设置 NULL
+- **列宽自适应** — 数据表格自动根据表头文字和数据内容调整最佳列宽
+- **复制为 INSERT** — 数据表格右键菜单新增"复制为 INSERT 语句"功能 (#166)
+- **创建/删除数据库和 Schema** — 侧栏右键菜单支持创建和删除数据库及 Schema
+- **SQL Server CROSS APPLY 补全** — SQL 编辑器支持 CROSS APPLY / OUTER APPLY 语法补全 (#168)
+- **OceanBase Oracle 模式** — 自动检测 OceanBase Oracle 模式,使用 Oracle 风格的 Schema 查询 (#155)
+- **鼠标中键关闭标签** — 支持鼠标中键点击关闭标签页 (#162)
+- **排序提示图标** — 鼠标悬停列标题时显示可排序提示图标
+- **窗口状态记忆** — 窗口位置和大小在关闭后自动保存,重新打开时恢复
+- **MCP 连接管理** — MCP 工具新增 `dbx_add_connection` 和 `dbx_remove_connection`,操作后自动通知桌面端刷新
+
+### 改进
+
+- **DataGrid 工具栏增强** — 数据表格工具栏和数据集交互优化 (contributed by @rarnu)
+- **JSON/JSONB 渲染性能** — 预序列化 JSON/JSONB 值并截断单元格显示,大幅提升大数据量渲染性能
+- **信息栏合并** — 数据表底部信息栏和事务工具栏合并为一行,节省屏幕空间
+- **标签页样式优化** — 标签模式切换改用图标,标签标题改为 Navicat 风格
+
+### 修复
+
+- **标签页右键菜单** — 修复关闭所有/关闭其他/关闭右侧等标签页右键菜单不可用的问题
+- **查询结果表头和排序** — 修复查询结果表头提示和全量排序问题 (contributed by @Bacon2994)
+- **MCP 连接配置** — 修复 MCP 写入的 config_json 与 Rust ConnectionConfig 结构不匹配的问题,改为从 SQLite 读取连接
+- **Tailwind 样式丢失** — 修复 tmpfs 环境下 Tailwind 样式缺失的问题 (#167)
+- **数据表格滚动抖动** — 禁用数据表格过度滚动回弹,防止表头和数据错位 (#156)
+- **GaussDB Schema 列表** — 移除 GaussDB list_schemas 的 EXISTS 过滤以保持一致性 (#154)
+- **侧栏数据库过滤** — 连接配置指定数据库时,侧栏只显示该数据库 (#160)
+- **Oracle 11g 兼容性** — 修复 Oracle 11g 连接兼容性问题和侧栏改进
+- **MySQL 全 NULL 显示** — 增加 MySQL 类型回退,防止缺少类型映射时所有列值显示为 NULL (#40)
+- **AI 执行 SQL** — 修复 AI 执行时传递过期 SQL 状态的问题 (#153)
+- **JSONB 编辑显示** — 修复 JSONB 值在编辑模式和详情面板中未正确显示为 JSON 字符串的问题 (#152)
+- **MongoDB 副本集 SSH** — 修复 MongoDB 副本集通过 SSH 隧道连接失败的问题 (#151)
+- **Redis 二进制误判** — 修复反斜杠字符串被误判为二进制数据的问题 (contributed by @Bacon2994)
+- **Toast 通知层级** — 修复 Toast 通知被对话框遮挡的问题
+- **DDL 面板文本选择** — 修复 DDL 面板无法选中文本的问题
+- **原生右键菜单** — 禁用浏览器原生右键菜单,新增侧栏刷新按钮 (#159)
diff --git a/docs/content/docs/changelog.mdx b/docs/content/docs/changelog.mdx
new file mode 100644
index 0000000000..9aa0d02e15
--- /dev/null
+++ b/docs/content/docs/changelog.mdx
@@ -0,0 +1,197 @@
+---
+title: Changelog
+description: Track DBX release notes by version, mirrored from GitHub Releases.
+---
+
+This page mirrors the user-facing release notes from GitHub Releases. It keeps feature, improvement, and fix entries in the docs site; download tables and installer details remain on each GitHub Release page.
+
+## v0.5.4
+
+[GitHub Release](https://github.com/t8y2/dbx/releases/tag/v0.5.4)
+
+### Added
+
+- **JDBC SSH tunnels and proxy support** — JDBC connections can use SSH tunnels and proxies, with host:port values parsed and rewritten from JDBC URLs.
+- **Grouped object browser and context menus** — Database objects are grouped by type and expose context-menu actions.
+- **Redis batch operations and command runner** — Redis adds batch key operations and a command executor.
+- **Database proxy support** — Database connections and AI settings now support proxy configuration.
+- **Data grid LIKE / NOT LIKE filters** — Grid context menus add LIKE, NOT LIKE, greater-than, and less-than filters.
+- **Database object source editing** — View and edit source for database objects such as procedures, functions, and views.
+- **Dynamic Connection URL placeholders** — The connection dialog shows URL examples that match the selected database type (contributed by @Abeautifulsnow).
+- **AI Thinking toggle** — AI settings can hide thinking output from local models such as Ollama or vLLM to save tokens (contributed by @rarnu).
+- **PostgreSQL type support** — Adds support for integer arrays and float4 (contributed by @xKrah).
+- **Spanish localization** — Adds Spanish UI text and refactors language switching into a dropdown (contributed by @Max29xD).
+
+### Improved
+
+- **Settings page** — Moves AI model settings into global settings and improves the settings layout (contributed by @rarnu).
+- **Full cell values** — Details, copy, and export flows no longer truncate cell values to 256 characters (contributed by @Abeautifulsnow).
+- **Virtual scrolling** — Reduces blank flashing during fast grid scrolling.
+- **Data grid toolbar** — Refines the grid toolbar layout.
+- **Redis browser i18n** — Adds localization support to the Redis key browser (contributed by @xKrah).
+- **Settings links** — Improves link presentation in the settings dialog.
+
+### Fixed
+
+- Fixes Oracle RAC/SCAN redirects (closes #209).
+- Fixes Oracle table loading and editing.
+- Simplifies Oracle selector behavior and supports schema switching (closes #205).
+- Fixes Oracle connection error detection on non-English Windows systems (closes #208).
+- Speeds up Oracle schema diff and adds comment synchronization (closes #198).
+- Fixes sidebar lag with 100+ databases (closes #201).
+- Fixes sidebar search missing tables hidden by the object browser.
+- Fixes stale child caches when refreshing expanded sidebar nodes.
+- Preserves WHERE filters across tab switches (closes #210).
+- Keeps data grid page size after saving data.
+- Makes Enter prefer autocomplete suggestions when available (closes #202).
+- Fixes SQL Server object source saving.
+- Fixes a build failure caused by single quotes (contributed by @xKrah).
+- Fixes object browser items requiring double-click to open.
+- Fixes virtual tree detection for non-empty trees.
+
+## v0.5.3
+
+[GitHub Release](https://github.com/t8y2/dbx/releases/tag/v0.5.3)
+
+### Added
+
+- **AI SQL smart execution** — The AI assistant can execute SQL with built-in statement safety checks.
+- **MongoDB table view** — MongoDB collections can be viewed and edited in a grid.
+- **DBeaver import** — Import database connection configs from DBeaver.
+- **Navicat import** — Import database connections from Navicat NCX files.
+- **Procedure and function browsing** — The object browser can show procedures and functions.
+- **Virtual object browser** — A unified browser for database objects.
+- **Database activity history** — Track and review database operation history.
+- **External table data source foundation** — Adds the shared architecture for future CSV, XLSX, and online sheet sources (contributed by @BlueSkyXN).
+- **Data grid loading indicator** — Adds a loading mask and elapsed-time display for query execution.
+
+### Improved
+
+- Editor features, DataGrid internals, and sidebar interactions.
+- XLSX export from the table context menu.
+- Full-stack performance and safety hardening.
+- Faster initial Oracle table loading.
+- Optional DuckDB bundling to reduce build size.
+
+### Fixed
+
+- Sidebar tree state display.
+- GitHub link clickability in Settings > About.
+- Unexpected disconnection of prefixed web connection pools.
+- Web connection config cache synchronization.
+- Oracle schema cache refresh and incomplete table lists.
+- Oracle NCHAR decoding.
+- Sidebar search result collapsing.
+
+## v0.5.2
+
+[GitHub Release](https://github.com/t8y2/dbx/releases/tag/v0.5.2)
+
+### Added
+
+- Optional JDBC plugin support for connecting to more database types through JDBC drivers.
+- Saved SQL library for reusable SQL snippets.
+- DataGrip-style column filters in the data grid.
+- Data comparison and table structure synchronization.
+- Connection URL creation and XLSX export.
+- Custom connection colors for distinguishing environments.
+- Clipboard shortcuts in the data grid.
+- Layout preference settings.
+- SSH tunnel timeout configuration.
+
+### Improved
+
+- Panels, tabs, and general application layout.
+
+### Fixed
+
+- Redis key table column alignment.
+- Connection state synchronization when expanding cached trees.
+- Connection dialog error messages.
+- Result-query detection after SQL comments.
+- Column filter popup interactions.
+- Unsaved query tab persistence.
+- Hidden system database objects in the sidebar.
+- Web file picker inconsistencies.
+
+## v0.5.1
+
+[GitHub Release](https://github.com/t8y2/dbx/releases/tag/v0.5.1)
+
+### Added
+
+- About tab in Settings.
+- Cached database object lists in the sidebar.
+- Create new connections from group context menus.
+- Tab indentation in the SQL editor.
+- Windows portable ZIP builds.
+
+### Improved
+
+- Streaming query results with row limits for large result sets.
+- Faster sidebar search filtering.
+- More capable grid context menus.
+- Better toolbar state retention for data editing filters and refresh (contributed by @rarnu).
+- Toggleable AI conversation history.
+
+### Fixed
+
+- SQL Server data editing issues.
+- Restart after app updates.
+- Grid scroll position after pagination.
+- MySQL transaction editing through raw SQL.
+- Sidebar expanded state after refresh.
+- Repeated title-bar double-click state toggles (#179).
+- Default database filtering in the database tree (#175).
+- Tab text overlapping scroll arrows.
+- Table and SQL file dialog layouts.
+- Transaction status placement.
+- Duplicate or lost WHERE / ORDER BY state.
+- Default database handling consistency.
+
+## v0.5.0
+
+[GitHub Release](https://github.com/t8y2/dbx/releases/tag/v0.5.0)
+
+### Added
+
+- Fully rebuilt Redis browser with a Navicat-style table view, value editing, pagination, and full keyspace scanning (contributed by @Bacon2994).
+- Custom window title bar with integrated window controls.
+- Dedicated WHERE and ORDER BY inputs for data-grid filtering and sorting (#165).
+- In-result filtering for loaded query data (contributed by @rarnu).
+- Editable cell details panel with explicit NULL support.
+- Auto-fit column widths based on headers and data.
+- Copy selected rows as INSERT statements (#166).
+- Create and drop databases and schemas from the sidebar.
+- SQL Server CROSS APPLY / OUTER APPLY completion (#168).
+- OceanBase Oracle mode detection (#155).
+- Middle-click tab close (#162).
+- Sort hint icons on column hover.
+- Window position and size persistence.
+- MCP connection management with `dbx_add_connection` and `dbx_remove_connection`.
+
+### Improved
+
+- DataGrid toolbar and dataset interactions (contributed by @rarnu).
+- JSON / JSONB rendering performance for large data sets.
+- Combined data-grid information and transaction toolbar row.
+- Navicat-style tab presentation.
+
+### Fixed
+
+- Tab context-menu actions such as close all, close others, and close right.
+- Query result headers and full sorting (contributed by @Bacon2994).
+- MCP config_json compatibility with Rust `ConnectionConfig`.
+- Tailwind styles missing under tmpfs (#167).
+- Data-grid overscroll causing header and data misalignment (#156).
+- GaussDB schema-list filtering (#154).
+- Sidebar database filtering when a connection specifies a database (#160).
+- Oracle 11g compatibility and sidebar behavior.
+- MySQL fallback type mapping to avoid all-NULL columns (#40).
+- AI execution receiving stale SQL state (#153).
+- JSONB display in edit mode and the details panel (#152).
+- MongoDB replica-set connections through SSH tunnels (#151).
+- Redis backslash strings being misclassified as binary data (contributed by @Bacon2994).
+- Toast notifications hidden behind dialogs.
+- Text selection in the DDL panel.
+- Browser-native context menu conflicts and adds a sidebar refresh button (#159).
diff --git a/docs/content/docs/meta.cn.json b/docs/content/docs/meta.cn.json
index 9469b63700..c3fb37cd67 100644
--- a/docs/content/docs/meta.cn.json
+++ b/docs/content/docs/meta.cn.json
@@ -3,6 +3,7 @@
"pages": [
"---介绍---",
"what-is-dbx",
+ "changelog",
"getting-started",
"databases",
"---核心功能---",
diff --git a/docs/content/docs/meta.json b/docs/content/docs/meta.json
index 48e70b6bb0..d820036b87 100644
--- a/docs/content/docs/meta.json
+++ b/docs/content/docs/meta.json
@@ -3,6 +3,7 @@
"pages": [
"---Introduction---",
"what-is-dbx",
+ "changelog",
"getting-started",
"databases",
"---Core Features---",
diff --git a/docs/package.json b/docs/package.json
index f18d422e7a..0d25e0364d 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -16,6 +16,7 @@
"fumadocs-mdx": "^14.3.2",
"fumadocs-ui": "^16.8.7",
"lucide-react": "^0.515.0",
+ "motion": "^12.38.0",
"next": "^16.2.4",
"postcss": "^8.5.14",
"react": "^19.2.5",
diff --git a/docs/pnpm-lock.yaml b/docs/pnpm-lock.yaml
index fa79a2a282..77239b432f 100644
--- a/docs/pnpm-lock.yaml
+++ b/docs/pnpm-lock.yaml
@@ -32,6 +32,9 @@ importers:
lucide-react:
specifier: ^0.515.0
version: 0.515.0(react@19.2.5)
+ motion:
+ specifier: ^12.38.0
+ version: 12.38.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
next:
specifier: ^16.2.4
version: 16.2.4(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
diff --git a/docs/public/avatars/acane.png b/docs/public/avatars/acane.png
new file mode 100644
index 0000000000..9711f2bb31
Binary files /dev/null and b/docs/public/avatars/acane.png differ
diff --git a/docs/public/avatars/ar414.jpg b/docs/public/avatars/ar414.jpg
new file mode 100644
index 0000000000..f771337456
Binary files /dev/null and b/docs/public/avatars/ar414.jpg differ
diff --git a/docs/public/avatars/cyano.jpg b/docs/public/avatars/cyano.jpg
new file mode 100644
index 0000000000..7dc96a028e
Binary files /dev/null and b/docs/public/avatars/cyano.jpg differ
diff --git a/docs/public/avatars/dongxuyang85.jpg b/docs/public/avatars/dongxuyang85.jpg
new file mode 100644
index 0000000000..6195132a35
Binary files /dev/null and b/docs/public/avatars/dongxuyang85.jpg differ
diff --git a/docs/public/avatars/guangguang.jpg b/docs/public/avatars/guangguang.jpg
new file mode 100644
index 0000000000..8681b6f2bb
Binary files /dev/null and b/docs/public/avatars/guangguang.jpg differ
diff --git a/docs/public/avatars/husky.jpg b/docs/public/avatars/husky.jpg
new file mode 100644
index 0000000000..d7880e9bc8
Binary files /dev/null and b/docs/public/avatars/husky.jpg differ
diff --git a/docs/public/avatars/itkui.jpg b/docs/public/avatars/itkui.jpg
new file mode 100644
index 0000000000..68dc9475b9
Binary files /dev/null and b/docs/public/avatars/itkui.jpg differ
diff --git a/docs/public/avatars/mebiuw.jpg b/docs/public/avatars/mebiuw.jpg
new file mode 100644
index 0000000000..4dd6dc0052
Binary files /dev/null and b/docs/public/avatars/mebiuw.jpg differ
diff --git a/docs/public/avatars/momo.jpg b/docs/public/avatars/momo.jpg
new file mode 100644
index 0000000000..90ee768439
Binary files /dev/null and b/docs/public/avatars/momo.jpg differ
diff --git a/docs/public/avatars/patrickz.jpg b/docs/public/avatars/patrickz.jpg
new file mode 100644
index 0000000000..d06729fa30
Binary files /dev/null and b/docs/public/avatars/patrickz.jpg differ
diff --git a/docs/public/avatars/ryan.jpg b/docs/public/avatars/ryan.jpg
new file mode 100644
index 0000000000..b628f4dc00
Binary files /dev/null and b/docs/public/avatars/ryan.jpg differ
diff --git a/docs/public/avatars/sunzhigang.jpg b/docs/public/avatars/sunzhigang.jpg
new file mode 100644
index 0000000000..834a3bbda9
Binary files /dev/null and b/docs/public/avatars/sunzhigang.jpg differ
diff --git a/docs/public/avatars/vbvb.png b/docs/public/avatars/vbvb.png
new file mode 100644
index 0000000000..3450d14945
Binary files /dev/null and b/docs/public/avatars/vbvb.png differ
diff --git a/docs/public/avatars/xuyuan.jpg b/docs/public/avatars/xuyuan.jpg
new file mode 100644
index 0000000000..f56408bfe5
Binary files /dev/null and b/docs/public/avatars/xuyuan.jpg differ
diff --git a/docs/public/avatars/yanxuecan.jpg b/docs/public/avatars/yanxuecan.jpg
new file mode 100644
index 0000000000..ac3414c583
Binary files /dev/null and b/docs/public/avatars/yanxuecan.jpg differ
diff --git a/docs/public/avatars/ydwang.png b/docs/public/avatars/ydwang.png
new file mode 100644
index 0000000000..a6e433be6b
Binary files /dev/null and b/docs/public/avatars/ydwang.png differ
diff --git a/docs/public/avatars/yingtao.jpg b/docs/public/avatars/yingtao.jpg
new file mode 100644
index 0000000000..cbc5161e43
Binary files /dev/null and b/docs/public/avatars/yingtao.jpg differ
diff --git a/docs/public/avatars/zhufeng.jpg b/docs/public/avatars/zhufeng.jpg
new file mode 100644
index 0000000000..7b14f4b596
Binary files /dev/null and b/docs/public/avatars/zhufeng.jpg differ
diff --git a/docs/public/favicon.png b/docs/public/favicon.png
new file mode 100644
index 0000000000..407755f554
Binary files /dev/null and b/docs/public/favicon.png differ
diff --git a/docs/public/icons/database/clickhouse.svg b/docs/public/icons/database/clickhouse.svg
new file mode 100644
index 0000000000..7c0e072c43
--- /dev/null
+++ b/docs/public/icons/database/clickhouse.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/public/icons/database/cockroachdb.svg b/docs/public/icons/database/cockroachdb.svg
new file mode 100644
index 0000000000..862e86f313
--- /dev/null
+++ b/docs/public/icons/database/cockroachdb.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/public/icons/database/dm.svg b/docs/public/icons/database/dm.svg
new file mode 100644
index 0000000000..53151566e0
--- /dev/null
+++ b/docs/public/icons/database/dm.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/public/icons/database/doris.svg b/docs/public/icons/database/doris.svg
new file mode 100644
index 0000000000..e18c60e400
--- /dev/null
+++ b/docs/public/icons/database/doris.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/public/icons/database/duckdb.svg b/docs/public/icons/database/duckdb.svg
new file mode 100644
index 0000000000..14dc392a65
--- /dev/null
+++ b/docs/public/icons/database/duckdb.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/public/icons/database/elasticsearch.svg b/docs/public/icons/database/elasticsearch.svg
new file mode 100644
index 0000000000..48ef8a349f
--- /dev/null
+++ b/docs/public/icons/database/elasticsearch.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/public/icons/database/gaussdb.svg b/docs/public/icons/database/gaussdb.svg
new file mode 100644
index 0000000000..f115a85c35
--- /dev/null
+++ b/docs/public/icons/database/gaussdb.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/public/icons/database/kingbase.svg b/docs/public/icons/database/kingbase.svg
new file mode 100644
index 0000000000..9d7f076a68
--- /dev/null
+++ b/docs/public/icons/database/kingbase.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/public/icons/database/mongodb.svg b/docs/public/icons/database/mongodb.svg
new file mode 100644
index 0000000000..ee4700342e
--- /dev/null
+++ b/docs/public/icons/database/mongodb.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/public/icons/database/mysql.svg b/docs/public/icons/database/mysql.svg
new file mode 100644
index 0000000000..0a3adb7c67
--- /dev/null
+++ b/docs/public/icons/database/mysql.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/public/icons/database/oceanbase.svg b/docs/public/icons/database/oceanbase.svg
new file mode 100644
index 0000000000..2ace40536b
--- /dev/null
+++ b/docs/public/icons/database/oceanbase.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/public/icons/database/opengauss.svg b/docs/public/icons/database/opengauss.svg
new file mode 100644
index 0000000000..6f469714c3
--- /dev/null
+++ b/docs/public/icons/database/opengauss.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/public/icons/database/oracle.svg b/docs/public/icons/database/oracle.svg
new file mode 100644
index 0000000000..20e98a456c
--- /dev/null
+++ b/docs/public/icons/database/oracle.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/public/icons/database/postgres.svg b/docs/public/icons/database/postgres.svg
new file mode 100644
index 0000000000..a24c0a6fcc
--- /dev/null
+++ b/docs/public/icons/database/postgres.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/public/icons/database/redis.svg b/docs/public/icons/database/redis.svg
new file mode 100644
index 0000000000..2df1a4fa06
--- /dev/null
+++ b/docs/public/icons/database/redis.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/public/icons/database/redshift.svg b/docs/public/icons/database/redshift.svg
new file mode 100644
index 0000000000..83b1036ea1
--- /dev/null
+++ b/docs/public/icons/database/redshift.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/public/icons/database/selectdb.svg b/docs/public/icons/database/selectdb.svg
new file mode 100644
index 0000000000..f19f6261e8
--- /dev/null
+++ b/docs/public/icons/database/selectdb.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/public/icons/database/sqlite.svg b/docs/public/icons/database/sqlite.svg
new file mode 100644
index 0000000000..ebf14c38d1
--- /dev/null
+++ b/docs/public/icons/database/sqlite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/public/icons/database/sqlserver.svg b/docs/public/icons/database/sqlserver.svg
new file mode 100644
index 0000000000..360df61de1
--- /dev/null
+++ b/docs/public/icons/database/sqlserver.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/public/icons/database/starrocks.svg b/docs/public/icons/database/starrocks.svg
new file mode 100644
index 0000000000..25d035193d
--- /dev/null
+++ b/docs/public/icons/database/starrocks.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/public/icons/database/tdengine.svg b/docs/public/icons/database/tdengine.svg
new file mode 100644
index 0000000000..9d20ae0f3a
--- /dev/null
+++ b/docs/public/icons/database/tdengine.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/public/icons/database/tidb.svg b/docs/public/icons/database/tidb.svg
new file mode 100644
index 0000000000..ee0b723cc9
--- /dev/null
+++ b/docs/public/icons/database/tidb.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src-tauri/src/commands/mod.rs b/src-tauri/src/commands/mod.rs
index 57442c8b21..ce374a7315 100644
--- a/src-tauri/src/commands/mod.rs
+++ b/src-tauri/src/commands/mod.rs
@@ -2,6 +2,7 @@ pub mod ai;
pub mod connection;
#[allow(dead_code, unused_imports)]
mod connection_secrets;
+pub mod database_export;
pub mod history;
pub mod mcp_bridge;
pub mod mongo_cmd;
diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs
index cc5c97a11d..1699980490 100644
--- a/src-tauri/src/lib.rs
+++ b/src-tauri/src/lib.rs
@@ -141,6 +141,8 @@ pub fn run() {
commands::update::check_for_updates,
commands::transfer::start_transfer,
commands::transfer::cancel_transfer,
+ commands::database_export::export_database_sql,
+ commands::database_export::cancel_database_export,
])
.build(tauri::generate_context!())
.expect("error while building tauri application")
diff --git a/src-web/src/main.rs b/src-web/src/main.rs
index 5cc3d235f9..6f2c14992a 100644
--- a/src-web/src/main.rs
+++ b/src-web/src/main.rs
@@ -152,6 +152,10 @@ async fn main() {
.route("/transfer/start", post(routes::transfer::start_transfer))
.route("/transfer/progress/{transferId}", get(routes::transfer::transfer_progress))
.route("/transfer/cancel", post(routes::transfer::cancel_transfer))
+ // Database export
+ .route("/export/database", post(routes::database_export::start_database_export))
+ .route("/export/database/progress/{exportId}", get(routes::database_export::database_export_progress))
+ .route("/export/database/cancel", post(routes::database_export::cancel_database_export))
// SQL file
.route("/sql-file/preview", post(routes::sql_file::preview_sql_file))
.route("/sql-file/execute", post(routes::sql_file::execute_sql_file))
diff --git a/src-web/src/routes/mod.rs b/src-web/src/routes/mod.rs
index 8f5a128675..d163fe782a 100644
--- a/src-web/src/routes/mod.rs
+++ b/src-web/src/routes/mod.rs
@@ -1,5 +1,6 @@
pub mod ai;
pub mod connection;
+pub mod database_export;
pub mod history;
pub mod layout;
pub mod mongo;