diff --git a/website/i18n.json b/website/i18n.json index ba475596..a00be44e 100644 --- a/website/i18n.json +++ b/website/i18n.json @@ -3,13 +3,29 @@ "en": "Quick start", "zh": "快速上手" }, + "viewSource": { + "en": "View the code", + "zh": "查看源码" + }, + "copyCommand": { + "en": "Copy command", + "zh": "复制命令" + }, + "copiedCommand": { + "en": "Command copied", + "zh": "命令已复制" + }, + "title": { + "en": "Unified Toolchain for", + "zh": "统一工具链" + }, "subtitle": { - "en": "The Unified JavaScript Toolchain", - "zh": "统一的 JavaScript 工具链" + "en": "Shipping JavaScript Faster", + "zh": "加速 JavaScript 开发" }, "slogan": { - "en": "One CLI, one configuration, one consistent workflow", - "zh": "一个命令行、一份配置、一致的工作流" + "en": "One CLI unifies development, builds, testing, linting, and formatting across all your JavaScript projects. Powered by the Rspack ecosystem.", + "zh": "只需一个 CLI,即可统一所有 JavaScript 项目的开发、构建、测试、代码检查与格式化。由 Rspack 生态驱动。" }, "unifiedCli": { "en": "One CLI", diff --git a/website/theme/components/Hero.module.scss b/website/theme/components/Hero.module.scss index 972082a0..3b4452c9 100644 --- a/website/theme/components/Hero.module.scss +++ b/website/theme/components/Hero.module.scss @@ -1,8 +1,241 @@ -:global { - .rs-oval { - width: 70% !important; - height: 70% !important; - top: calc(50% + 20px) !important; - left: calc(50% + 5px) !important; +.hero { + --hero-title: #111214; + --hero-title-muted: #747474; + --hero-text: #707174; + --hero-border: #d9dbde; + --hero-command-bg: rgba(255, 255, 255, 0.72); + --hero-link: #686a6d; + --hero-link-hover: #111214; + + position: relative; + display: flex; + align-items: center; + justify-content: center; + box-sizing: border-box; + min-height: calc(100svh - var(--rp-nav-height)); + padding: clamp(4.5rem, 9vh, 7rem) 2rem; + overflow: hidden; + background: var(--rp-c-bg); +} + +:global(.dark) .hero { + --hero-title: #f5f5f5; + --hero-title-muted: #9a9a9a; + --hero-text: #a1a3a6; + --hero-border: #3a3c40; + --hero-command-bg: rgba(255, 255, 255, 0.025); + --hero-link: #a6a8ab; + --hero-link-hover: #f5f5f5; +} + +.inner { + display: flex; + flex-direction: column; + align-items: center; + width: 100%; + max-width: 64rem; + text-align: center; + transform: translateY(-1.5rem); +} + +.title { + margin: 0; + color: var(--hero-title); + font-size: clamp(3rem, 4.5vw, 4rem); + font-weight: 600; + line-height: 1.1; + letter-spacing: -0.055em; + text-wrap: balance; + + span { + display: block; + } +} + +.subtitle { + color: var(--hero-title-muted); +} + +.description { + max-width: 42rem; + margin: clamp(2.5rem, 5vh, 3.75rem) 0 0; + color: var(--hero-text); + font-size: clamp(1rem, 1.25vw, 1.25rem); + font-weight: 400; + line-height: 1.5; + letter-spacing: -0.02em; + text-wrap: balance; +} + +.command { + display: grid; + grid-template-columns: auto minmax(0, 1fr) auto; + align-items: center; + box-sizing: border-box; + width: min(100%, 20rem); + min-height: 3.125rem; + margin-top: clamp(2.75rem, 6vh, 4rem); + padding: 0 0.5rem 0 1rem; + color: var(--hero-title); + text-align: left; + border: 1px solid var(--hero-border); + border-radius: 0.5rem; + background: var(--hero-command-bg); + + code, + .prompt { + font-family: + ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', monospace; + font-size: clamp(0.8125rem, 1vw, 0.9375rem); + line-height: 1.4; + } + + code { + padding: 0 0.625rem; + overflow: hidden; + color: inherit; + text-overflow: ellipsis; + white-space: nowrap; + background: transparent; + } +} + +.prompt { + color: var(--hero-text); +} + +.copyButton { + display: inline-flex; + align-items: center; + justify-content: center; + width: 2rem; + height: 2rem; + padding: 0; + color: var(--hero-text); + cursor: pointer; + border: 0; + border-radius: 0.5rem; + background: transparent; + transition: + color 0.2s ease, + background-color 0.2s ease; + + svg { + width: 1.125rem; + height: 1.125rem; + } + + &:hover { + color: var(--hero-link-hover); + background: color-mix(in srgb, var(--hero-title) 7%, transparent); + } + + &:focus-visible { + outline: 2px solid var(--rp-c-brand); + outline-offset: 2px; + } +} + +.links { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: center; + gap: 1rem 2.5rem; + margin-top: clamp(2rem, 4vh, 2.5rem); +} + +.link { + display: inline-flex; + align-items: center; + gap: 0.5rem; + color: var(--hero-link); + font-size: 0.9375rem; + font-weight: 500; + line-height: 1.5; + text-decoration: none; + transition: color 0.2s ease; + + svg { + width: 0.75rem; + height: 0.75rem; + transition: transform 0.2s ease; + } + + &:hover { + color: var(--hero-link-hover); + + svg { + transform: translateX(0.2rem); + } + } + + &:focus-visible { + border-radius: 0.25rem; + outline: 2px solid var(--rp-c-brand); + outline-offset: 4px; + } +} + +@media (max-width: 640px) { + .hero { + min-height: calc(100svh - var(--rp-nav-height)); + padding: 4rem 1.25rem; + } + + .title { + font-size: clamp(2.25rem, 10vw, 2.75rem); + line-height: 1.04; + letter-spacing: -0.055em; + } + + .description { + max-width: 28rem; + margin-top: 2rem; + font-size: 0.9375rem; + line-height: 1.55; + } + + .command { + min-height: 3.25rem; + margin-top: 2.25rem; + padding: 0 0.5rem 0 0.875rem; + border-radius: 0.625rem; + + code, + .prompt { + font-size: 0.8125rem; + } + + code { + padding: 0 0.625rem; + } + } + + .copyButton { + width: 2rem; + height: 2rem; + + svg { + width: 1.125rem; + height: 1.125rem; + } + } + + .links { + gap: 1rem 1.75rem; + margin-top: 2rem; + } + + .link { + font-size: 0.875rem; + } +} + +@media (prefers-reduced-motion: reduce) { + .copyButton, + .link, + .link svg { + transition: none; } } diff --git a/website/theme/components/Hero.tsx b/website/theme/components/Hero.tsx index 7bf503f6..5edc0cf2 100644 --- a/website/theme/components/Hero.tsx +++ b/website/theme/components/Hero.tsx @@ -1,22 +1,76 @@ -import { useI18n, useNavigate } from '@rspress/core/runtime'; -import { Hero as BaseHero } from '@rstack-dev/doc-ui/hero'; +import { useI18n } from '@rspress/core/runtime'; +import { + IconArrowRight, + IconCopy, + IconSuccess, + Link, + SvgWrapper, + copyToClipboard, +} from '@rspress/core/theme-original'; +import { useCallback, useEffect, useRef, useState } from 'react'; import { useI18nUrl } from './utils'; -import './Hero.module.scss'; +import styles from './Hero.module.scss'; + +const createCommand = 'pnpm create rstack'; +const githubUrl = 'https://github.com/rstackjs/rstack-cli'; export function Hero() { - const navigate = useNavigate(); const tUrl = useI18nUrl(); const t = useI18n(); + const [copied, setCopied] = useState(false); + const resetTimer = useRef(undefined); + + const handleCopy = useCallback(async () => { + const copiedSuccessfully = await copyToClipboard(createCommand); + + if (!copiedSuccessfully) { + return; + } + + setCopied(true); + window.clearTimeout(resetTimer.current); + resetTimer.current = window.setTimeout(() => setCopied(false), 1600); + }, []); + + useEffect(() => () => window.clearTimeout(resetTimer.current), []); return ( - navigate(tUrl('/guide/quick-start'))} - title="Rstack CLI" - subTitle={t('subtitle')} - description={t('slogan')} - getStartedButtonText={t('quickStart')} - githubURL="https://github.com/rstackjs/rstack-cli" - /> +
+
+

+ {t('title')} + {t('subtitle')} +

+ +

{t('slogan')}

+ +
+ + {createCommand} + +
+ +
+ + {t('quickStart')} + + + + {t('viewSource')} + + +
+
+
); } diff --git a/website/theme/components/ToolStack.tsx b/website/theme/components/ToolStack.tsx deleted file mode 100644 index c5e3fc57..00000000 --- a/website/theme/components/ToolStack.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { useLang } from '@rspress/core/runtime'; -import { containerStyle } from '@rstack-dev/doc-ui/section-style'; -import { ToolStack as BaseToolStack } from '@rstack-dev/doc-ui/tool-stack'; - -export function ToolStack() { - const lang = useLang(); - - return ( -
- -
- ); -} diff --git a/website/theme/index.scss b/website/theme/index.scss index 9fde95d7..a210d25d 100644 --- a/website/theme/index.scss +++ b/website/theme/index.scss @@ -13,6 +13,10 @@ } } +body:has(#home-hero-title) .rp-nav { + border-bottom: none; +} + .rspress-logo { height: 1.8rem; } diff --git a/website/theme/pages/index.tsx b/website/theme/pages/index.tsx index 084a27d2..cbeb03a2 100644 --- a/website/theme/pages/index.tsx +++ b/website/theme/pages/index.tsx @@ -1,19 +1,15 @@ -import { BackgroundImage } from '@rstack-dev/doc-ui/background-image'; import { CopyRight } from '../components/Copyright'; import { Features } from '../components/Features'; import { Hero } from '../components/Hero'; import { HomeFooter } from '../components/HomeFooter'; -import { ToolStack } from '../components/ToolStack'; export function HomeLayout() { return ( -
- + <> - -
+ ); }