diff --git a/website/theme/components/Commands.module.scss b/website/theme/components/Commands.module.scss index a22116c..813237a 100644 --- a/website/theme/components/Commands.module.scss +++ b/website/theme/components/Commands.module.scss @@ -19,7 +19,7 @@ grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); align-items: center; gap: clamp(2rem, 4vw, 3rem); - padding: 5.5rem 0; + padding: 7.5rem 0; border-top: 1px solid var(--command-border); } @@ -42,7 +42,7 @@ flex-wrap: wrap; align-items: center; gap: 0.5rem 0.75rem; - margin: 0 0 1.25rem; + margin: 0 0 0.5rem; color: var(--command-text); font-family: var(--rp-font-family-mono); font-size: 0.8125rem; diff --git a/website/theme/components/GetStarted.module.scss b/website/theme/components/GetStarted.module.scss new file mode 100644 index 0000000..cc87900 --- /dev/null +++ b/website/theme/components/GetStarted.module.scss @@ -0,0 +1,180 @@ +.getStarted { + --cta-title: #111214; + --cta-text: #727272; + --cta-border: #e8e8e8; + --cta-primary-text: #fff; + --cta-hover: #f5f5f5; + + max-width: 72rem; + margin: 0 auto; + padding: 0 2rem; +} + +:global(.dark) .getStarted { + --cta-title: #f5f5f5; + --cta-text: #9a9a9a; + --cta-border: #292929; + --cta-primary-text: #111214; + --cta-hover: #202020; +} + +.inner { + display: flex; + flex-direction: column; + align-items: center; + padding: 7.5rem 0; + text-align: center; + border-block: 1px solid var(--cta-border); + + h2 { + margin: 0; + color: var(--cta-title); + font-size: clamp(1.75rem, 3vw, 2.5rem); + font-weight: 600; + line-height: 1.25; + letter-spacing: -0.04em; + text-wrap: balance; + } +} + +.description { + max-width: 40rem; + margin: 0.75rem 0 2rem; + color: var(--cta-text); + font-size: 0.925rem; + line-height: 1.75; + text-wrap: balance; +} + +.controls { + position: relative; + max-width: 100%; +} + +.command { + display: flex; + align-items: center; + gap: 0.75rem; + width: 22.5rem; + min-height: 2.875rem; + max-width: 100%; + padding: 0.375rem 0.5rem 0.375rem 1rem; + color: var(--cta-title); + border: 1px solid var(--cta-border); + border-radius: 0.5rem; + + code { + min-width: 0; + overflow-wrap: anywhere; + text-align: left; + font-family: var(--rp-font-family-mono); + font-size: 0.875rem; + line-height: 1.6; + } +} + +.prompt { + color: var(--cta-text); + font-family: var(--rp-font-family-mono); +} + +.copyButton { + display: inline-flex; + flex: 0 0 auto; + align-items: center; + justify-content: center; + width: 2rem; + height: 2rem; + margin-left: auto; + color: var(--cta-text); + background: transparent; + border: 0; + cursor: pointer; + border-radius: 0.375rem; + + &:hover { + color: var(--cta-title); + background: var(--cta-hover); + } +} + +.status { + position: absolute; + top: 100%; + width: 100%; + margin: 0.375rem 0 0; + color: var(--cta-text); + font-size: 0.8125rem; + line-height: 1.25rem; +} + +.actions { + display: flex; + align-items: center; + justify-content: center; + gap: 0.75rem; + + a { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.625rem; + min-width: 8rem; + min-height: 2.875rem; + padding: 0.5rem 1rem; + font-size: 0.875rem; + font-weight: 500; + line-height: 1.25; + text-decoration: none; + border: 1px solid var(--cta-border); + border-radius: 0.5rem; + } +} + +.primary { + color: var(--cta-primary-text); + background: var(--cta-title); + + &:hover { + color: var(--cta-primary-text); + opacity: 0.85; + } +} + +.copyButton:focus-visible, +.actions a:focus-visible { + outline: 2px solid var(--rp-c-brand); + outline-offset: 3px; +} + +@media (max-width: 640px) { + .getStarted { + padding-inline: 1.25rem; + } + + .inner { + padding-block: 2.75rem; + } + + .description { + font-size: 0.875rem; + margin-bottom: 1.5rem; + } + + .actions { + flex-direction: column; + + a { + width: 100%; + } + } + + .command { + gap: 0.5rem; + padding-left: 0.875rem; + + code { + font-size: 0.8125rem; + } + } +} diff --git a/website/theme/components/GetStarted.tsx b/website/theme/components/GetStarted.tsx new file mode 100644 index 0000000..578c961 --- /dev/null +++ b/website/theme/components/GetStarted.tsx @@ -0,0 +1,114 @@ +import { useLang } from '@rspress/core/runtime'; +import { Link } from '@rspress/core/theme-original'; +import { useEffect, useState } from 'react'; +import { useI18nUrl } from './utils'; +import styles from './GetStarted.module.scss'; + +const command = 'pnpm create rstack@latest'; + +export function GetStarted() { + const isZh = useLang() === 'zh'; + const tUrl = useI18nUrl(); + const [copyStatus, setCopyStatus] = useState<'idle' | 'copied' | 'error'>( + 'idle', + ); + + useEffect(() => { + if (copyStatus === 'idle') return; + const timeout = setTimeout(() => setCopyStatus('idle'), 2500); + return () => clearTimeout(timeout); + }, [copyStatus]); + + async function copyCommand() { + try { + await navigator.clipboard.writeText(command); + setCopyStatus('copied'); + } catch { + setCopyStatus('error'); + } + } + + return ( +
+
+

+ {isZh + ? '用 Rstack CLI 开启下一个项目' + : 'Build your next project with Rstack CLI'} +

+

+ {isZh + ? '让工具步调一致,将时间留给你想创造的事物' + : 'Keep your tools in sync and make time for what you want to create.'} +

+
+
+
+ + {command} + +
+ + {isZh ? '开始使用' : 'Get started'} + + +
+

+ {copyStatus === 'copied' + ? isZh + ? '命令已复制' + : 'Command copied' + : copyStatus === 'error' + ? isZh + ? '复制失败,请手动复制命令' + : 'Could not copy. Please copy the command manually.' + : ''} +

+
+
+
+ ); +} diff --git a/website/theme/components/HomeFooter.module.scss b/website/theme/components/HomeFooter.module.scss index e5a678c..7bd61e8 100644 --- a/website/theme/components/HomeFooter.module.scss +++ b/website/theme/components/HomeFooter.module.scss @@ -2,8 +2,6 @@ display: none; flex-direction: column; align-items: center; - margin-top: 6rem; - border-top: 1px solid var(--rp-c-divider-light); @media (min-width: 640px) { display: flex; diff --git a/website/theme/components/HomeFooter.tsx b/website/theme/components/HomeFooter.tsx index bf2772b..b280e32 100644 --- a/website/theme/components/HomeFooter.tsx +++ b/website/theme/components/HomeFooter.tsx @@ -91,22 +91,22 @@ function useFooterData() { title: 'GitHub', link: 'https://github.com/rstackjs/rstack-cli', }, - { - title: 'npm', - link: 'https://www.npmjs.com/package/rstack', - }, { title: 'Discord', link: 'https://discord.gg/XsaKEEk4mW', }, { - title: 'X', - link: 'https://x.com/rspack_dev', + title: 'Reddit', + link: 'https://www.reddit.com/r/Rspack/', }, { title: 'Bluesky', link: 'https://bsky.app/profile/rspack.dev', }, + { + title: 'X', + link: 'https://x.com/rspack_dev', + }, ], }, ]; diff --git a/website/theme/pages/index.tsx b/website/theme/pages/index.tsx index 44c3735..4eda452 100644 --- a/website/theme/pages/index.tsx +++ b/website/theme/pages/index.tsx @@ -1,5 +1,6 @@ import { Commands } from '../components/Commands'; import { CopyRight } from '../components/Copyright'; +import { GetStarted } from '../components/GetStarted'; import { Hero } from '../components/Hero'; import { HomeFooter } from '../components/HomeFooter'; @@ -8,6 +9,7 @@ export function HomeLayout() { <> +