diff --git a/docs/app/[lang]/page.tsx b/docs/app/[lang]/page.tsx index 4a9c0557c..8e0c27b6b 100644 --- a/docs/app/[lang]/page.tsx +++ b/docs/app/[lang]/page.tsx @@ -3,6 +3,7 @@ import type { CSSProperties } from 'react'; import { HeroProductStage } from '@/components/aceternity/HeroProductStage'; import { InfiniteMovingCards } from '@/components/aceternity/InfiniteMovingCards'; import { Spotlight } from '@/components/aceternity/Spotlight'; +import { LandingNav } from '@/components/landing/LandingNav'; import { InstallTabs } from '@/components/landing/InstallTabs'; import { RevealSection } from '@/components/landing/RevealSection'; import { @@ -349,11 +350,11 @@ const i18nText = { navChangelog: 'Changelog', navCommunity: 'Community', lang: '中文', - eyebrow: 'Open-source database workspace', - heroTitle: 'A focused database client for daily work.', + heroTitle: 'A focused database client for daily work', heroSubtitle: 'DBX brings connections, SQL editing, data grids, schema tools, AI assistance, and self-hosted access into one lightweight product.', download: 'Download DBX', + downloadName: 'Download DBX', readDocs: 'Read the docs', docsStart: 'Start here', docsStartDesc: 'Install DBX, create your first connection, and learn the main workflow.', @@ -375,10 +376,10 @@ const i18nText = { navChangelog: '更新日志', navCommunity: '社区', lang: 'English', - eyebrow: '开源数据库工作台', - heroTitle: '专注日常工作的数据库客户端。', + heroTitle: '专注日常工作的数据库客户端', heroSubtitle: 'DBX 将连接管理、SQL 编辑、数据表格、结构工具、AI 助手和自托管访问放进一个轻量产品里。', download: '下载 DBX', + downloadName: '下载 DBX', readDocs: '查看文档', docsStart: '从这里开始', docsStartDesc: '安装 DBX、创建第一个连接,并了解主要工作流。', @@ -414,81 +415,90 @@ export default async function LandingPage({ return (
- + + {/* Hero */}
-
-
{t.eyebrow}
-

{t.heroTitle}

-

{t.heroSubtitle}

-
- - {t.download} - - - - {t.readDocs} - +
+
+

+ {t.heroTitle} +

+

+ {t.heroSubtitle} +

+
+ +
- +
-
- + {/* Metrics */} + {metricItems.map((item) => ( -
- {item.value} - {item.label} +
+ {item.value} + {item.label}
))} - + {/* Doc start */} +
-

{t.docsStart}

-

{t.docsStartDesc}

+

{t.docsStart}

+

{t.docsStartDesc}

- + {t.readDocs}
- -
-

{t.workflowsTitle}

-

{t.workflowsDesc}

+ {/* Workflows */} + +
+

{t.workflowsTitle}

+

{t.workflowsDesc}

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

{item.title}

-

{item.desc}

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

{item.title}

+

{item.desc}

+ {t.readDocs} @@ -497,78 +507,83 @@ export default async function LandingPage({
- -
-

{t.supportTitle}

-

{t.supportDesc}

+ {/* Database support */} + +
+

{t.supportTitle}

+

{t.supportDesc}

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

{t.testimonialsTitle}

-

{t.testimonialsDesc}

+ {/* Testimonials */} + +
+

{t.testimonialsTitle}

+

{t.testimonialsDesc}

-
+
- -
-

{t.capabilitiesTitle}

+ {/* Capabilities */} + +
+

{t.capabilitiesTitle}

-
+
{capabilityItems.map((item) => ( -
- - {item.label} +
+ + {item.label}
))}
- -
{latest.version}
-
-

{latest.title}

-

{latest.desc}

+ {/* Updates */} + +
{latest.version}
+
+

{latest.title}

+

{latest.desc}

-
    +
      {latest.items.map((item) => ( -
    • - +
    • + {item}
    • ))}
    - + {latest.link} - + {/* Final CTA */} +
    -

    {t.footerTitle}

    -

    {t.footerDesc}

    +

    {t.footerTitle}

    +

    {t.footerDesc}

    -
    - +
    + {t.release} - + {t.docker}
    diff --git a/docs/app/global.css b/docs/app/global.css index 45ee52ba4..7853b9e3b 100644 --- a/docs/app/global.css +++ b/docs/app/global.css @@ -2,6 +2,18 @@ @import 'fumadocs-ui/css/ocean.css'; @import 'fumadocs-ui/css/preset.css'; +@theme { + --color-landing-ink: #f7fbff; + --color-landing-muted: #9aa9bc; + --color-landing-blue: #6ea8ff; + --color-landing-sky: #52d5ff; + --color-landing-green: #44d19d; + --color-landing-line: rgba(155, 176, 205, 0.18); + --color-landing-soft: rgba(148, 163, 184, 0.1); + --color-landing-panel: rgba(17, 21, 29, 0.84); + --color-landing-panel-strong: rgba(23, 28, 38, 0.94); +} + :root { --color-fd-background: hsl(210 58% 98.8%); --color-fd-foreground: hsl(222 48% 9%); @@ -280,22 +292,12 @@ a { -webkit-tap-highlight-color: transparent; } + .landing { --landing-max: 1180px; - --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(--landing-ink); - background: - linear-gradient(180deg, #07090d 0%, #0d1118 44%, #10151d 100%), - #0d1118; + color: var(--color-landing-ink); + background: #10151d; overflow: hidden; } @@ -303,6 +305,8 @@ a { text-decoration: none; } +/* Reveal animation */ + .landing-reveal { opacity: 0; transform: translateY(26px); @@ -318,11 +322,7 @@ a { 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 { +.landing-reveal [data-stagger] { opacity: 0; transform: translateY(14px); transition: @@ -330,243 +330,143 @@ a { 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 { +.landing-reveal.is-visible [data-stagger] { 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 [data-stagger]:nth-child(2) { transition-delay: 70ms; } +.landing-reveal.is-visible [data-stagger]:nth-child(3) { transition-delay: 120ms; } +.landing-reveal.is-visible [data-stagger]:nth-child(4) { transition-delay: 170ms; } +.landing-reveal.is-visible [data-stagger]:nth-child(8n+5) { transition-delay: 210ms; } +.landing-reveal.is-visible [data-stagger]:nth-child(8n+6) { transition-delay: 250ms; } +.landing-reveal.is-visible [data-stagger]:nth-child(8n+7) { transition-delay: 290ms; } +.landing-reveal.is-visible [data-stagger]:nth-child(8n) { transition-delay: 330ms; } -.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; -} +/* Nav */ .landing-nav { - position: sticky; + position: fixed; top: 0; - z-index: 20; - border-bottom: 1px solid var(--landing-line); - background: color-mix(in srgb, #080b10 82%, transparent); + left: 0; + right: 0; + z-index: 80; + border-bottom: 1px solid transparent; + background: transparent; + transition: + background 0.3s ease, + border-color 0.3s ease; +} + +.landing-nav::before { + content: ''; + position: absolute; + inset: 0; backdrop-filter: blur(18px); + opacity: 0; + transition: opacity 0.3s ease; + z-index: -1; } -.landing-nav-inner { - display: flex; - align-items: center; - justify-content: space-between; - max-width: var(--landing-max); - height: 64px; - margin: 0 auto; - padding: 0 28px; +.landing-nav.is-scrolled { + border-bottom-color: var(--color-landing-line); + background: color-mix(in srgb, #0c1120 62%, transparent); } -.landing-logo, -.landing-nav-links, -.landing-hero-cta, -.landing-inline-link, -.landing-final-actions, -.landing-capability { - display: flex; - align-items: center; +.landing-nav.is-scrolled::before { + opacity: 1; } -.landing-logo { - gap: 10px; - color: var(--landing-ink); - font-size: 15px; - font-weight: 700; -} - -.landing-logo img { - border-radius: 7px; -} - -.landing-nav-links { - gap: 4px; -} - -.landing-nav-links a { - border-radius: 7px; - padding: 8px 11px; - color: var(--landing-muted); - font-size: 13px; - font-weight: 500; +.landing-nav-link { transition: background 0.16s ease, color 0.16s ease, transform 0.16s ease; } -.landing-nav-links a:hover { - background: var(--landing-soft); - color: var(--landing-ink); +.landing-nav-link:hover { + background: var(--color-landing-soft); + color: var(--color-landing-ink); transform: translateY(-1px); } -.landing-lang-switch { - margin-left: 6px; - border: 1px solid var(--landing-line); -} +/* Hero */ .landing-hero { position: relative; - display: grid; - 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: 76px 28px 42px; + min-height: calc(100vh - 64px); + padding-top: 148px; + overflow: hidden; isolation: isolate; } .landing-hero::before { content: ''; position: absolute; - inset: 0 -40px auto; - height: 100%; - border-bottom: 1px solid var(--landing-line); + inset: 0; 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%); + radial-gradient(ellipse at 50% 34%, rgba(44, 88, 174, 0.42), transparent 46%), + radial-gradient(ellipse at 18% 16%, rgba(82, 213, 255, 0.13), transparent 34%), + radial-gradient(ellipse at 76% 22%, rgba(68, 209, 157, 0.1), transparent 30%), + linear-gradient(180deg, #10151d 0%, #0c1528 48%, #10151d 82%, #10151d 100%); z-index: -3; } .landing-hero::after { content: ''; position: absolute; - inset: 86px 12px 20px; + inset: 134px -12vw -140px; 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; + linear-gradient(rgba(110, 168, 255, 0.08) 1px, transparent 1px), + linear-gradient(90deg, rgba(110, 168, 255, 0.08) 1px, transparent 1px); + background-size: 58px 58px; + mask-image: radial-gradient(ellipse at 50% 56%, black 0%, transparent 64%); + opacity: 0.5; pointer-events: none; - transform: perspective(1200px) rotateX(58deg) translateY(90px); + transform: perspective(1200px) rotateX(60deg) translateY(84px); transform-origin: center bottom; - animation: landing-grid-drift 13s linear infinite; + animation: landing-grid-drift 15s linear infinite; z-index: -2; } .aceternity-spotlight { position: absolute; - inset: -18% auto auto 6%; - width: min(760px, 68vw); - height: 620px; + inset: -210px auto auto 50%; + width: min(980px, 82vw); + height: 720px; 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); + radial-gradient(circle at 50% 28%, rgba(255, 255, 255, 0.16), transparent 12%), + radial-gradient(circle at 46% 38%, rgba(82, 213, 255, 0.2), transparent 34%), + radial-gradient(circle at 58% 52%, rgba(110, 168, 255, 0.16), transparent 60%); + filter: blur(52px); mix-blend-mode: screen; pointer-events: none; + transform: translateX(-50%); z-index: -1; } .landing-hero-copy { - max-width: 470px; animation: landing-rise 0.72s ease-out both; } +.landing-hero-subtitle { + color: color-mix(in srgb, var(--color-landing-muted) 86%, white); +} + .landing-eyebrow { - width: max-content; - border: 1px solid var(--landing-line); - border-radius: 999px; - margin-bottom: 18px; - padding: 6px 10px; + border: 1px solid var(--color-landing-line); background: rgba(255, 255, 255, 0.04); - color: color-mix(in srgb, var(--landing-sky) 74%, white); - font-size: 12px; - font-weight: 600; + color: color-mix(in srgb, var(--color-landing-sky) 74%, white); 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: 470px; - margin: 0; - 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: 470px; - margin: 22px 0 0; - color: var(--landing-muted); - font-size: 17px; - line-height: 1.72; -} - -.landing-hero-cta { - gap: 10px; - flex-wrap: wrap; - margin-top: 30px; -} - -.landing-btn-primary, -.landing-btn-secondary, -.landing-final-actions a { - display: inline-flex; - align-items: center; - justify-content: center; - min-height: 42px; - border-radius: 7px; - padding: 0 15px; - font-size: 14px; - font-weight: 650; -} +/* Buttons */ .landing-btn-primary { - gap: 8px; background: #f7fbff; color: #090d13; box-shadow: @@ -585,149 +485,113 @@ a { 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(--landing-ink); +.landing-btn-secondary { + border: 1px solid var(--color-landing-line); + background: var(--color-landing-panel); + color: var(--color-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 { +.landing-btn-secondary:hover { border-color: rgba(178, 200, 230, 0.34); - background: var(--landing-panel-strong); + background: var(--color-landing-panel-strong); transform: translateY(-1px); } -.landing-install { +/* Install dropdown */ + +.landing-install::after { + content: ''; + position: absolute; + top: 100%; + left: 0; display: block; - max-width: 540px; - min-height: 174px; - border: 1px solid var(--landing-line); - border-radius: 8px; - margin-top: 18px; - padding: 8px; - background: rgba(10, 14, 20, 0.72); - backdrop-filter: blur(14px); + width: 100%; + height: 24px; } -.landing-install-tabs { - display: grid; - grid-template-columns: repeat(4, minmax(0, 1fr)); - gap: 6px; - margin-bottom: 8px; +.landing-install-trigger { + background: + linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(239, 244, 250, 0.96)), + #fff; + color: #070b12; + box-shadow: + 0 18px 54px rgba(0, 0, 0, 0.24), + 0 0 0 1px rgba(255, 255, 255, 0.72) inset; + transition: box-shadow 0.16s ease; } -.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; +.landing-install-trigger:hover, +.landing-install[data-open='true'] .landing-install-trigger { + box-shadow: + 0 24px 68px rgba(0, 0, 0, 0.3), + 0 0 0 1px rgba(255, 255, 255, 0.78) inset; +} + +.landing-install-trigger > svg:first-child { + fill: currentColor; + stroke-width: 0; +} + +.landing-install-trigger > svg:last-child { + color: #5f6876; + transition: transform 0.16s ease; +} + +.landing-install[data-open='true'] .landing-install-trigger > svg:last-child { + transform: rotate(180deg); +} + +.landing-install-menu { + background: rgba(4, 5, 8, 0.94); + box-shadow: + 0 26px 64px rgba(0, 0, 0, 0.34), + 0 0 0 1px rgba(255, 255, 255, 0.035) inset; + backdrop-filter: blur(18px); + opacity: 0; + pointer-events: none; + transition: + opacity 0.16s ease, + transform 0.16s ease, + visibility 0.16s ease; + visibility: hidden; +} + +.landing-install:hover .landing-install-menu, +.landing-install[data-open='true'] .landing-install-menu { + opacity: 1; + pointer-events: auto; + visibility: visible; +} + +.landing-install-option { + color: color-mix(in srgb, var(--color-landing-ink) 88%, var(--color-landing-muted)); 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); +.landing-install-option:hover { background: rgba(255, 255, 255, 0.055); - color: var(--landing-ink); + color: var(--color-landing-ink); } -.landing-install-tab span { - overflow: hidden; - font-size: 12px; - font-weight: 700; - text-overflow: ellipsis; - white-space: nowrap; +.landing-install-option svg { + fill: currentColor; + stroke-width: 1.8; } -.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; -} +/* Product showcase */ .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: 12px; + border: 1px solid var(--color-landing-line); background: #0d1117; box-shadow: - 0 34px 90px rgba(0, 0, 0, 0.38), + 0 38px 110px rgba(0, 0, 0, 0.5), + 0 0 80px rgba(82, 213, 255, 0.1), 0 0 0 1px rgba(255, 255, 255, 0.03) inset; transform-style: preserve-3d; transition: @@ -763,85 +627,61 @@ a { 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)); + background: radial-gradient(circle at 72% 18%, rgba(82, 213, 255, 0.1), transparent 18%); 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); + transform: translateY(-4px) scale(1.005); + box-shadow: + 0 46px 122px rgba(0, 0, 0, 0.58), + 0 0 100px rgba(82, 213, 255, 0.13); } -.landing-window-bar { - position: relative; - z-index: 2; - display: flex; - gap: 7px; - height: 34px; - align-items: center; - border-bottom: 1px solid rgba(255, 255, 255, 0.08); - padding: 0 13px; - background: #111827; +.landing-product-slide { + opacity: 0; + transition: opacity 0.45s ease; } -.landing-window-bar span { - width: 10px; - height: 10px; - border-radius: 50%; - background: rgba(255, 255, 255, 0.22); +.landing-product-slide[data-active='true'] { + opacity: 1; } -.landing-window-bar span:nth-child(1) { - background: #ff5f57; +.landing-product-dots { + border: 1px solid rgba(155, 176, 205, 0.16); + background: rgba(5, 8, 13, 0.66); + backdrop-filter: blur(16px); } -.landing-window-bar span:nth-child(2) { - background: #ffbd2e; +.landing-product-dots button { + background: rgba(226, 232, 240, 0.38); + color: transparent; + transition: + width 0.2s ease, + background 0.2s ease, + opacity 0.2s ease; } -.landing-window-bar span:nth-child(3) { - background: #28c840; +.landing-product-dots button[aria-current='true'] { + width: 28px; + background: color-mix(in srgb, var(--color-landing-sky) 84%, white); } -.landing-product img { - position: relative; - z-index: 1; - display: block; - width: 100%; - aspect-ratio: 16 / 10; - object-fit: cover; - object-position: left top; +.landing-product-dots span { + position: absolute; + width: 1px; + height: 1px; + overflow: hidden; + clip: rect(0 0 0 0); + white-space: nowrap; } -.landing-metrics, -.landing-doc-start, -.landing-updates, -.landing-section, -.landing-final { - max-width: var(--landing-max); - margin: 0 auto; - padding-right: 28px; - padding-left: 28px; -} +/* Glass cards */ -.landing-metrics { - display: grid; - 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 { - min-height: 118px; +.landing-glass-card { 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)), @@ -851,30 +691,8 @@ a { 0 0 0 1px rgba(255, 255, 255, 0.02) inset; } -.landing-metrics strong { - display: block; - color: var(--landing-ink); - font-size: 24px; - font-weight: 720; -} - -.landing-metrics span { - display: block; - margin-top: 4px; - color: var(--landing-muted); - font-size: 13px; -} - -.landing-doc-start { - display: flex; - align-items: center; - justify-content: space-between; - gap: 22px; - max-width: calc(var(--landing-max) - 56px); +.landing-glass-card-green { 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)), @@ -884,135 +702,29 @@ a { 0 0 0 1px rgba(255, 255, 255, 0.02) inset; } -.landing-doc-start h2, -.landing-section-heading h2, -.landing-final h2 { - margin: 0; - 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(--landing-muted); - font-size: 14px; - line-height: 1.65; -} - -.landing-section-heading p { - max-width: 650px; - justify-self: end; - text-align: right; -} +/* Inline link */ .landing-inline-link { - flex-shrink: 0; - gap: 7px; - color: var(--landing-blue); - font-size: 14px; - font-weight: 650; + color: var(--color-landing-blue); transition: color 0.16s ease, transform 0.16s ease; } .landing-inline-link:hover { - color: color-mix(in srgb, var(--landing-sky) 70%, white); + color: color-mix(in srgb, var(--color-landing-sky) 70%, white); transform: translateX(2px); } -.landing-section { - padding-top: 70px; - 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); - gap: 36px; - align-items: end; - margin-bottom: 22px; -} +/* Workflow card */ .landing-workflow-grid { - display: grid; - grid-template-columns: repeat(4, minmax(0, 1fr)); - border: 1px solid var(--landing-line); - border-radius: 10px; - overflow: hidden; - background: var(--landing-panel); + border: 1px solid var(--color-landing-line); + background: var(--color-landing-panel); } .landing-workflow-card { - min-height: 250px; - border-right: 1px solid var(--landing-line); - padding: 24px; - color: var(--landing-ink); + color: var(--color-landing-ink); transition: border-color 0.16s ease, background 0.16s ease, @@ -1020,195 +732,25 @@ a { box-shadow 0.16s ease; } -.landing-workflow-card:last-child { - border-right: 0; -} - .landing-workflow-card:hover { - background: var(--landing-panel-strong); + background: var(--color-landing-panel-strong); 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 { - color: var(--landing-blue); +/* Update version badge */ + +.landing-update-version { + border: 1px solid var(--color-landing-line); + background: var(--color-landing-panel); + color: var(--color-landing-blue); } -.landing-workflow-card h3 { - margin: 18px 0 0; - font-size: 16px; - font-weight: 700; -} - -.landing-workflow-card p { - margin: 10px 0 0; - color: var(--landing-muted); - font-size: 13px; - line-height: 1.62; -} - -.landing-workflow-card span { - display: inline-flex; - align-items: center; - gap: 6px; - margin-top: 18px; - 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; - 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; -} +/* DB card */ .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)), @@ -1231,58 +773,70 @@ a { transform: translateY(-3px); } -.landing-db-icon { - display: grid; - place-items: center; - width: 48px; - height: 48px; - margin-bottom: 15px; -} - .landing-db-icon img { - display: block; - width: 38px; - height: 38px; - object-fit: contain; filter: drop-shadow(0 10px 20px color-mix(in srgb, var(--db-tone) 20%, transparent)); } .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-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; +/* Testimonials */ + +.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-capability-grid { - display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 10px; +.landing-testimonial-wall::before { + left: 0; + background: linear-gradient(90deg, #10151d, rgba(16, 21, 29, 0)); } +.landing-testimonial-wall::after { + right: 0; + background: linear-gradient(270deg, #10151d, rgba(16, 21, 29, 0)); +} + +.landing-testimonial-marquee[data-speed='slow'] { + --testimonial-duration: 58s; +} + +.landing-testimonial-marquee[data-speed='normal'] { + --testimonial-duration: 42s; +} + +.landing-testimonial-track { + 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-card { + border: 1px solid rgba(155, 176, 205, 0.14); + 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; +} + +/* Capability card */ + .landing-capability { - gap: 10px; - min-height: 72px; - border: 1px solid var(--landing-line); - border-radius: 8px; - padding: 14px 15px; - background: var(--landing-panel); + border: 1px solid var(--color-landing-line); + background: var(--color-landing-panel); transition: border-color 0.16s ease, background 0.16s ease, @@ -1291,70 +845,33 @@ a { .landing-capability:hover { border-color: rgba(110, 168, 255, 0.24); - background: var(--landing-panel-strong); + background: var(--color-landing-panel-strong); transform: translateY(-2px); } -.landing-capability svg { - flex: 0 0 auto; - color: var(--landing-blue); +/* Final CTA link */ + +.landing-final-link { + border: 1px solid var(--color-landing-line); + background: var(--color-landing-panel); + color: var(--color-landing-ink); + transition: + border-color 0.16s ease, + background 0.16s ease, + transform 0.16s ease; } -.landing-capability span { - color: var(--landing-ink); - font-size: 13px; - font-weight: 560; - line-height: 1.45; +.landing-final-link:hover { + border-color: rgba(178, 200, 230, 0.34); + background: var(--color-landing-panel-strong); + transform: translateY(-1px); } -.landing-final { - display: flex; - align-items: center; - justify-content: space-between; - gap: 24px; - border: 1px solid var(--landing-line); - border-radius: 10px; - margin-top: 72px; - margin-bottom: 56px; - padding-top: 30px; - padding-bottom: 30px; - background: var(--landing-panel); -} - -.landing-final-actions { - gap: 10px; - flex-wrap: wrap; - justify-content: flex-end; -} +/* Responsive */ @media (max-width: 1040px) { .landing-hero { - display: block; - padding-top: 56px; - } - - .landing-hero-copy { - max-width: 760px; - } - - .landing-product { - width: auto; - max-width: 860px; - margin-top: 44px; - } - - .landing-workflow-grid, - .landing-capability-grid { - 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; + padding-top: 120px; } .landing-workflow-card:nth-child(2n) { @@ -1362,46 +879,22 @@ a { } .landing-workflow-card:nth-child(-n + 2) { - border-bottom: 1px solid var(--landing-line); + border-bottom: 1px solid var(--color-landing-line); } } @media (max-width: 760px) { - .landing-nav-inner { - height: auto; - min-height: 58px; - padding: 10px 18px; - } - - .landing-nav-links a:not(.landing-lang-switch) { - display: none; - } - - .landing-hero, - .landing-metrics, - .landing-doc-start, - .landing-updates, - .landing-section, - .landing-final { - padding-right: 18px; - padding-left: 18px; - } - .landing-hero { - padding-top: 44px; + padding-top: 104px; min-height: 0; } - .landing-hero h1 { - font-size: 42px; - line-height: 1.05; - } - .landing-hero::before { - right: -18px; + right: 0; 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%); + radial-gradient(circle at 50% 18%, rgba(82, 213, 255, 0.18), transparent 280px), + radial-gradient(circle at 76% 26%, rgba(68, 209, 157, 0.08), transparent 220px), + linear-gradient(180deg, #10151d 0%, #0c1528 44%, #10151d 94%); } .landing-hero::after { @@ -1410,83 +903,24 @@ a { } .aceternity-spotlight { - inset: -12% auto auto -20%; - width: 92vw; + inset: -18% auto auto 50%; + width: 96vw; } - .landing-product { - margin-top: 34px; - } - - .landing-install { - grid-template-columns: 1fr; - gap: 5px; - } - - .landing-metrics { - grid-template-columns: 1fr; - padding-bottom: 32px; - } - - .landing-metrics div { - min-height: 96px; - padding: 18px; - } - - .landing-doc-start, - .landing-updates, - .landing-section-heading, - .landing-support, - .landing-final { - display: block; - } - - .landing-section-heading p { - max-width: none; - text-align: left; - } - - .landing-inline-link { - margin-top: 16px; - } - - .landing-update-copy, - .landing-update-list { - margin-top: 16px; - } - - .landing-workflow-grid, - .landing-capability-grid { - grid-template-columns: 1fr; + .landing-product-dots { + right: 12px; + bottom: 11px; } .landing-workflow-card { - min-height: 0; border-right: 0; - border-bottom: 1px solid var(--landing-line); + border-bottom: 1px solid var(--color-landing-line); } .landing-workflow-card:last-child { border-bottom: 0; } - .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; @@ -1496,20 +930,15 @@ a { .landing-testimonial-wall::after { width: 46px; } - - .landing-testimonial-card { - flex-basis: 286px; - min-height: 210px; - padding: 18px; - } } +/* Keyframes */ + @keyframes landing-rise { from { opacity: 0; transform: translateY(18px); } - to { opacity: 1; transform: translateY(0); @@ -1517,24 +946,17 @@ a { } @keyframes landing-grid-drift { - from { - background-position: 0 0; - } - - to { - background-position: 54px 54px; - } + from { background-position: 0 0; } + to { background-position: 54px 54px; } } @keyframes landing-pulse { - 0%, - 100% { + 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: @@ -1544,13 +966,11 @@ a { } @keyframes landing-cta-glow { - 0%, - 100% { + 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), @@ -1559,13 +979,8 @@ a { } @keyframes landing-testimonial-scroll { - from { - transform: translateX(0); - } - - to { - transform: translateX(calc(-50% - 7px)); - } + from { transform: translateX(0); } + to { transform: translateX(calc(-50% - 7px)); } } @media (prefers-reduced-motion: reduce) { @@ -1579,11 +994,7 @@ a { } .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 { + .landing-reveal [data-stagger] { opacity: 1 !important; transform: none !important; } diff --git a/docs/components/aceternity/HeroProductStage.tsx b/docs/components/aceternity/HeroProductStage.tsx index 0b1010987..2adb4ff17 100644 --- a/docs/components/aceternity/HeroProductStage.tsx +++ b/docs/components/aceternity/HeroProductStage.tsx @@ -1,21 +1,76 @@ 'use client'; import { motion } from 'motion/react'; +import { useEffect, useState } from 'react'; + +const productSlides = [ + { + src: '/screenshot-dark.png', + alt: 'DBX data grid and AI assistant screenshot', + label: 'Data grid', + }, + { + src: '/screenshot-connections.jpg', + alt: 'DBX connection management screenshot', + label: 'Connections', + }, + { + src: '/screenshot-grid.png', + alt: 'DBX table data grid screenshot', + label: 'Tables', + }, + { + src: '/screenshot-ai.jpg', + alt: 'DBX AI assistant screenshot', + label: 'AI', + }, +]; export function HeroProductStage() { + const [activeSlide, setActiveSlide] = useState(0); + + useEffect(() => { + const timer = window.setInterval(() => { + setActiveSlide((current) => (current + 1) % productSlides.length); + }, 4200); + + return () => window.clearInterval(timer); + }, []); + return ( -
    - - - +
    + {productSlides.map((slide, index) => ( + {slide.alt} + ))} +
    +
    + {productSlides.map((slide, index) => ( + + ))}
    - DBX product screenshot ); } diff --git a/docs/components/aceternity/InfiniteMovingCards.tsx b/docs/components/aceternity/InfiniteMovingCards.tsx index 218e46fa6..69b040c34 100644 --- a/docs/components/aceternity/InfiniteMovingCards.tsx +++ b/docs/components/aceternity/InfiniteMovingCards.tsx @@ -18,22 +18,22 @@ export function InfiniteMovingCards({ items, direction = 'left', speed = 'normal return (
    -
    +
    {repeatedItems.map((item, index) => ( -
    -
    - +
    +
    +
    - {item.name} - {item.role} + {item.name} + {item.role}
    -
    {item.quote}
    +
    {item.quote}
    ))}
    diff --git a/docs/components/landing/InstallTabs.tsx b/docs/components/landing/InstallTabs.tsx index 0ac828c2f..350fec9f1 100644 --- a/docs/components/landing/InstallTabs.tsx +++ b/docs/components/landing/InstallTabs.tsx @@ -1,127 +1,127 @@ 'use client'; -import { Check, Copy, ExternalLink } from 'lucide-react'; -import { useState } from 'react'; +import { ChevronDown, Download, Server } from 'lucide-react'; +import { useEffect, useMemo, useState } from 'react'; type InstallTabsProps = { lang: 'en' | 'cn'; }; -const releaseUrl = 'https://github.com/t8y2/dbx/releases/latest'; +type InstallOption = { + id: string; + label: string; + href: string; +}; -const installOptions = { +const allOptions: Record = { 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', - }, + { id: 'macos-arm', label: 'For macOS (Apple Silicon)', href: 'https://dl.dbxio.com/releases/latest/DBX_0.5.9_aarch64.dmg' }, + { id: 'macos-intel', label: 'For macOS (Intel)', href: 'https://dl.dbxio.com/releases/latest/DBX_0.5.9_x64.dmg' }, + { id: 'windows', label: 'For Windows', href: 'https://dl.dbxio.com/releases/latest/DBX_0.5.9_x64-setup.exe' }, + { id: 'linux', label: 'For Linux x64', href: 'https://dl.dbxio.com/releases/latest/DBX_0.5.9_amd64.AppImage' }, + { id: 'linux-arm', label: 'For Linux ARM64', href: 'https://dl.dbxio.com/releases/latest/DBX_0.5.9_aarch64.AppImage' }, ], 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', - }, + { id: 'macos-arm', label: '适用于 macOS (Apple Silicon)', href: 'https://dl.dbxio.com/releases/latest/DBX_0.5.9_aarch64.dmg' }, + { id: 'macos-intel', label: '适用于 macOS (Intel)', href: 'https://dl.dbxio.com/releases/latest/DBX_0.5.9_x64.dmg' }, + { id: 'windows', label: '适用于 Windows', href: 'https://dl.dbxio.com/releases/latest/DBX_0.5.9_x64-setup.exe' }, + { id: 'linux', label: '适用于 Linux x64', href: 'https://dl.dbxio.com/releases/latest/DBX_0.5.9_amd64.AppImage' }, + { id: 'linux-arm', label: '适用于 Linux ARM64', href: 'https://dl.dbxio.com/releases/latest/DBX_0.5.9_aarch64.AppImage' }, ], }; -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]; +const downloadLabel = { en: 'Download DBX', cn: '下载 DBX' }; - async function copyCommand() { - await navigator.clipboard.writeText(active.command); - setCopied(true); - window.setTimeout(() => setCopied(false), 1600); - } +const platformIconPaths = { + dark: { + 'linux-arm': '/icons/platform/linux.svg', + linux: '/icons/platform/linux.svg', + 'macos-arm': '/icons/platform/macos.png', + 'macos-intel': '/icons/platform/macos.png', + windows: '/icons/platform/windows.png', + }, + light: { + 'linux-arm': '/icons/platform/linux.svg', + linux: '/icons/platform/linux.svg', + 'macos-arm': '/icons/platform/macos-white.png', + 'macos-intel': '/icons/platform/macos-white.png', + windows: '/icons/platform/windows.png', + }, +}; + +function detectPlatformId(): string { + if (typeof navigator === 'undefined') return 'macos-arm'; + const ua = navigator.userAgent.toLowerCase(); + if (ua.includes('win')) return 'windows'; + if (ua.includes('linux')) return ua.includes('aarch64') || ua.includes('arm') ? 'linux-arm' : 'linux'; + return 'macos-arm'; +} + +function PlatformIcon({ id, size, variant }: { id: string; size: number; variant: 'dark' | 'light' }) { + const src = platformIconPaths[variant][id as keyof (typeof platformIconPaths)['dark']]; + if (!src) return ; + return ; +} + +export function InstallTabs({ lang }: InstallTabsProps) { + const options = allOptions[lang]; + const [open, setOpen] = useState(false); + const [platformId, setPlatformId] = useState('macos-arm'); + + useEffect(() => { + setPlatformId(detectPlatformId()); + }, []); + + const primary = useMemo(() => options.find((o) => o.id === platformId) ?? options[0], [options, platformId]); + const menuOptions = useMemo(() => options.filter((o) => o.id !== platformId), [options, platformId]); return ( -
    -
    - {options.map((item) => ( - + + {item.label} + ))}
    -
    - {active.command} - -
    - - {active.linkText} - -
    ); } diff --git a/docs/components/landing/LandingNav.tsx b/docs/components/landing/LandingNav.tsx new file mode 100644 index 000000000..9c70927af --- /dev/null +++ b/docs/components/landing/LandingNav.tsx @@ -0,0 +1,26 @@ +'use client'; + +import { useEffect, useRef } from 'react'; + +export function LandingNav({ children }: { children: React.ReactNode }) { + const ref = useRef(null); + + useEffect(() => { + const node = ref.current; + if (!node) return; + + function onScroll() { + node!.classList.toggle('is-scrolled', window.scrollY > 60); + } + + onScroll(); + window.addEventListener('scroll', onScroll, { passive: true }); + return () => window.removeEventListener('scroll', onScroll); + }, []); + + return ( + + ); +} diff --git a/docs/public/favicon.png b/docs/public/favicon.png index 407755f55..23c91bcfa 100644 Binary files a/docs/public/favicon.png and b/docs/public/favicon.png differ diff --git a/docs/public/logo.png b/docs/public/logo.png index 61508574f..23c91bcfa 100644 Binary files a/docs/public/logo.png and b/docs/public/logo.png differ