From 1715266a56b4940222ffb72183c22bae5860b3a7 Mon Sep 17 00:00:00 2001 From: Evyatar Date: Sat, 6 Dec 2025 07:02:31 -0500 Subject: [PATCH 1/2] Revamp website visuals --- website/docusaurus.config.js | 41 ++- website/src/components/HomepageFeatures.js | 116 ++++---- .../components/HomepageFeatures.module.css | 144 +++++++--- website/src/css/custom.css | 124 +++++---- website/src/pages/index.js | 97 ++++--- website/src/pages/index.module.css | 259 +++++++++++++----- 6 files changed, 482 insertions(+), 299 deletions(-) diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 735585071..3699f4316 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -1,18 +1,25 @@ // @ts-check // Note: type annotations allow type checking and IDEs autocompletion -import { Highlight, themes } from 'prism-react-renderer'; +import path from 'path'; +import { themes } from 'prism-react-renderer'; +import { fileURLToPath } from 'url'; -// const darkCodeTheme = require('prism-react-renderer/themes/dracula'); -// const lightCodeTheme = require('prism-react-renderer/themes/github'); +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +function badgeLink(url, badge, name) { + return ` + ${name} + `; +} /** @type {import('@docusaurus/types').Config} */ const config = { baseUrl: '/', favicon: 'favicon.ico', title: 'Vest', - tagline: - 'Declarative validations framework inspired by unit testing libraries', + tagline: 'Declarative validations framework inspired by unit testing libraries', url: 'https://vestjs.dev', onBrokenLinks: 'throw', markdown: { @@ -23,12 +30,6 @@ const config = { }, organizationName: 'ealush', // Usually your GitHub org/user name. plugins: [ - // [ - // require.resolve('@easyops-cn/docusaurus-search-local'), - // { - // indexBlog: false, - // }, - // ], [ '@docusaurus/plugin-google-gtag', { @@ -43,7 +44,7 @@ const config = { /** @type {import('@docusaurus/preset-classic').Options} */ ({ docs: { - sidebarPath: require.resolve('./sidebars.js'), + sidebarPath: path.resolve(__dirname, './sidebars.js'), // Please change this to your repo. editUrl: 'https://github.com/ealush/vest/edit/latest/website/', lastVersion: 'current', @@ -76,7 +77,7 @@ const config = { beforeDefaultRehypePlugins: [], }, theme: { - customCss: require.resolve('./src/css/custom.css'), + customCss: path.resolve(__dirname, './src/css/custom.css'), }, }), ], @@ -195,10 +196,6 @@ const config = { { title: 'More', items: [ - // { - // label: "Blog", - // to: "/blog", - // }, { label: 'GitHub', href: 'https://github.com/ealush/vest', @@ -210,7 +207,7 @@ const config = { }, prism: { theme: themes.github, - darkTheme: themes.dracula, + darkTheme: themes.vsDark, }, announcementBar: { id: 'announcementBar-vest-6', @@ -232,10 +229,4 @@ const config = { }), }; -module.exports = config; - -function badgeLink(url, badge, name) { - return ` - ${name} - `; -} +export default config; diff --git a/website/src/components/HomepageFeatures.js b/website/src/components/HomepageFeatures.js index dba6e308a..5ca137730 100644 --- a/website/src/components/HomepageFeatures.js +++ b/website/src/components/HomepageFeatures.js @@ -5,97 +5,75 @@ import styles from './HomepageFeatures.module.css'; const FeatureList = [ { - title: 'Easy to learn', - emoji: '💡', - description: ( - <> - Vest adopts the syntax and style of unit testing frameworks, so you can - leverage the knowledge you already have to write your form validations. - - ), + title: 'Declarative by design', + emoji: '🧾', + category: 'DX', + description: + 'Author validations like unit tests with suites, hooks, and familiar assertions.', }, { - title: 'Framework Agnostic', - emoji: '🎨', - description: ( - <> - Bring your own UI. Vest is framework agnostic, so you can use it with - any UI framework you have. - - ), + title: 'Framework agnostic', + emoji: '🌐', + category: 'Flexible', + description: 'Use Vest anywhere—React, Vue, Svelte, vanilla JS, or your favorite stack.', }, { - title: 'Really smart', - emoji: '🧠', - description: ( - <> - Vest takes care of all the annoying parts for you. It manages its own - state, handles async validations and much more. - - ), + title: 'Async ready', + emoji: '⚡️', + category: 'Performance', + description: 'Handle async flows out of the box with deterministic state management.', }, { - title: 'Extendable', + title: 'Extendable core', emoji: '🧩', - description: ( - <> - You can easily add new custom types of validations to Vest according to - your needs. - - ), + category: 'Composable', + description: 'Add custom validation rules and share suites across teams with ease.', }, { - title: 'Reusable', - emoji: '♻️', - description: ( - <> - Validation logic in Vest can be shared across multiple features in your - app. - - ), + title: 'Tiny footprint', + emoji: '🎯', + category: 'Shipping', + description: 'Zero dependencies and a few KBs—perfect for modern, lean bundles.', }, { - title: 'Tiny', - emoji: '🐜', - description: ( - <> - Packed with features, but optimized for size. Vest brings no - dependencies, and only takes a few KBs. - - ), + title: 'Test-like ergonomics', + emoji: '✅', + category: 'Productivity', + description: 'Readable error messages, deterministic runs, and intuitive APIs.', }, ]; -function Feature({ emoji, title, description }) { +function Feature({ emoji, title, category, description }) { return ( -
-
-
- {emoji} -
-
-

{title}

-

{description}

-
+
+
+ {emoji} + {category}
+

{title}

+

{description}

); } export default function HomepageFeatures() { return ( - <> -
-
-
- {FeatureList.map((props, idx) => ( - - ))} -
+
+
+
+

Built for modern DX

+

Everything you need to trust your forms

+

+ Vest pairs a lightweight core with a familiar testing-inspired API, so you can ship + confident experiences without fighting your validation layer. +

-
- +
+ {FeatureList.map((feature) => ( + + ))} +
+
+
); } diff --git a/website/src/components/HomepageFeatures.module.css b/website/src/components/HomepageFeatures.module.css index 3418ceb2e..23a5809d6 100644 --- a/website/src/components/HomepageFeatures.module.css +++ b/website/src/components/HomepageFeatures.module.css @@ -1,62 +1,130 @@ .features { - display: flex; - align-items: center; - padding: 6rem 0; + padding: 5rem 0; width: 100%; } +.sectionHeader { + max-width: 760px; + margin: 0 auto 3rem; + text-align: center; + display: flex; + flex-direction: column; + gap: 0.75rem; +} + +.sectionEyebrow { + text-transform: uppercase; + letter-spacing: 0.12em; + font-weight: 700; + color: var(--ifm-color-primary); + margin: 0; + font-size: 0.9rem; +} + +.sectionTitle { + font-size: 2.25rem; + margin: 0; +} + +.sectionDescription { + margin: 0; + color: var(--ifm-color-emphasis-700); + line-height: 1.7; +} + +.featuresGrid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); + gap: 1.5rem; +} + .featureCard { + background: var(--ifm-card-background-color); + border: 1px solid var(--ifm-color-emphasis-200); + border-radius: 16px; + padding: 1.5rem; height: 100%; - padding: 2rem; - border-radius: 24px; - transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); - background: transparent; - border: 1px solid transparent; - margin-bottom: 2rem; /* Add vertical gap */ + transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease; + position: relative; + overflow: hidden; + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.04); +} + +.featureCard::before { + content: ''; + position: absolute; + inset: 0; + background: radial-gradient(circle at 20% 20%, rgba(99, 102, 241, 0.12), transparent 45%); + opacity: 0; + transition: opacity 0.25s ease; } .featureCard:hover { - background: rgba(255, 255, 255, 0.5); - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.05); - backdrop-filter: blur(4px); + transform: translateY(-6px); + border-color: var(--ifm-color-primary); + box-shadow: 0 20px 35px rgba(0, 0, 0, 0.08), 0 10px 20px rgba(99, 102, 241, 0.08); +} + +.featureCard:hover::before { + opacity: 1; +} + +html[data-theme='dark'] .featureCard { + background: rgba(30, 41, 59, 0.6); + border-color: rgba(255, 255, 255, 0.08); + box-shadow: 0 15px 30px rgba(0, 0, 0, 0.35); } html[data-theme='dark'] .featureCard:hover { - background: rgba(255, 255, 255, 0.05); + border-color: var(--ifm-color-primary); + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.45), 0 0 40px rgba(99, 102, 241, 0.15); } -.emoji { - font-size: 3rem; - margin-bottom: 1.5rem; +.featureHeader { display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1rem; +} + +.emoji { + font-size: 1.9rem; + background: rgba(99, 102, 241, 0.12); + width: 54px; + height: 54px; + border-radius: 14px; + display: inline-flex; align-items: center; justify-content: center; - width: 80px; - height: 80px; - border-radius: 24px; - background: var(--ifm-color-emphasis-100); /* Simple background */ - margin-left: auto; - margin-right: auto; - transition: transform 0.3s ease; +} + +.category { + padding: 0.35rem 0.75rem; + border-radius: 999px; + background: rgba(99, 102, 241, 0.1); + color: var(--ifm-color-primary-darkest); + font-weight: 700; + letter-spacing: 0.04em; + font-size: 0.8rem; } .featureTitle { - font-size: 1.5rem; - font-weight: 800; - margin-bottom: 1rem; - background: linear-gradient( - 90deg, - var(--ifm-color-primary) 0%, - var(--ifm-color-primary-dark) 100% - ); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; + font-size: 1.3rem; + margin: 0 0 0.5rem; } .featureDescription { - color: var(--ifm-color-emphasis-600); - line-height: 1.8; - font-size: 1.1rem; - font-weight: 500; + margin: 0; + color: var(--ifm-color-emphasis-700); + line-height: 1.6; +} + +html[data-theme='dark'] .sectionDescription, +html[data-theme='dark'] .featureDescription { + color: #cbd5e1; +} + +html[data-theme='dark'] .category { + background: rgba(129, 140, 248, 0.16); + color: var(--ifm-color-primary-lightest); } diff --git a/website/src/css/custom.css b/website/src/css/custom.css index 4d26596dc..62138b350 100644 --- a/website/src/css/custom.css +++ b/website/src/css/custom.css @@ -1,88 +1,80 @@ -@import url('https://fonts.googleapis.com/css2?family=Rubik:wght@300;400;700&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap'); -/** - * Any CSS included here will be global. The classic template - * bundles Infima by default. Infima is a CSS framework designed to - * work well for content-centric websites. - */ - -/* You can override the default Infima variables here. */ :root { - --ifm-color-primary-lightest: #fdfdfd; - --ifm-color-primary-lighter: #4b6889; - --ifm-color-primary-light: #486383; - --ifm-color-primary: #697098; - --ifm-color-primary-dark: #3b516b; - --ifm-color-primary-darker: #374d65; - --ifm-color-primary-darkest: #212432; - --ifm-font-family-base: 'Rubik', sans-serif; + --ifm-font-family-base: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; + --ifm-font-family-monospace: 'JetBrains Mono', SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; --ifm-code-font-size: 95%; - --ifm-heading-color: var(--ifm-font-color-base); - --main-content-background-color: none; - --darkest-alt: #171819; - --announcement-bar-background: var(--ifm-color-primary-lightest); - --announcement-bar-color: var(--darkest-alt); + --ifm-border-radius-base: 12px; + + /* Midnight & Neon palette (light mode) */ + --ifm-color-primary: #6366f1; + --ifm-color-primary-dark: #4f46e5; + --ifm-color-primary-darker: #4338ca; + --ifm-color-primary-darkest: #3730a3; + --ifm-color-primary-light: #818cf8; + --ifm-color-primary-lighter: #a5b4fc; + --ifm-color-primary-lightest: #c7d2fe; + + --ifm-background-color: #ffffff; + --ifm-navbar-background-color: rgba(255, 255, 255, 0.82); + --ifm-navbar-shadow: none; + --ifm-heading-color: #0f172a; + --ifm-font-color-base: #111827; + --ifm-card-background-color: #f8fafc; + --docusaurus-highlighted-code-line-bg: rgba(99, 102, 241, 0.08); } html[data-theme='dark'] { - --ifm-background-color: var(--darkest-alt); - --announcement-bar-background: var(--ifm-color-primary-light); - --announcement-bar-color: var(--ifm-color-primary-lightest); + --ifm-background-color: #0f172a; + --ifm-font-color-base: #e2e8f0; + --ifm-heading-color: #f8fafc; + --ifm-navbar-background-color: rgba(15, 23, 42, 0.78); + --ifm-card-background-color: rgba(30, 41, 59, 0.5); + --docusaurus-highlighted-code-line-bg: rgba(255, 255, 255, 0.08); +} + +body { + background: radial-gradient(circle at 20% 20%, rgba(99, 102, 241, 0.06), transparent 25%), + radial-gradient(circle at 80% 0%, rgba(79, 70, 229, 0.05), transparent 20%), + var(--ifm-background-color); + color: var(--ifm-font-color-base); } main { - background-color: var(--main-content-background-color); + background-color: transparent; } -.aa-DetachedSearchButton { - color: blue; +.navbar { + backdrop-filter: blur(12px); + border-bottom: 1px solid var(--ifm-color-emphasis-200); + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.04); } -h1 { - padding-bottom: 1rem; +html[data-theme='dark'] .navbar { + border-bottom: 1px solid rgba(255, 255, 255, 0.08); + box-shadow: 0 20px 50px rgba(0, 0, 0, 0.35); } .docusaurus-highlight-code-line { - background-color: rgba(0, 0, 0, 0.1); display: block; margin: 0 calc(-1 * var(--ifm-pre-padding)); padding: 0 var(--ifm-pre-padding); + background-color: var(--docusaurus-highlighted-code-line-bg); } .footer { - background-color: #272a36; -} - -html[data-theme='dark'] .docusaurus-highlight-code-line { - background-color: rgba(0, 0, 0, 0.3); -} - -html[data-theme='dark'] .navbar { - background-color: var(--ifm-background-color); - border-bottom: 1px solid var(--ifm-color-primary-darker); -} - -html[data-theme='light'] .hero__primary.hero { - background-color: var(--ifm-color-primary-lightest); - color: var(--ifm-color-primary-darkest); -} - -html[data-theme='dark'] .hero__primary.hero { - background-color: var(--ifm-background-color); - color: var(--ifm-color-primary-darkest); + background: linear-gradient(180deg, rgba(79, 70, 229, 0.12), rgba(15, 23, 42, 0.92)); + color: #e2e8f0; } -html[data-theme='dark'] .hero__title { - color: var(--ifm-color-primary-lightest); -} - -.hero__title { - text-transform: uppercase; +.hero__title, +.hero__subtitle { color: var(--ifm-heading-color); } -.hero__subtitle { - color: var(--ifm-heading-color); +html[data-theme='dark'] .hero__title, +html[data-theme='dark'] .hero__subtitle { + color: var(--ifm-color-primary-lightest); } .header-badge { @@ -91,7 +83,7 @@ html[data-theme='dark'] .hero__title { .header-github-link { content: ''; - background-color: var(--ifm-color-primary-darkest); + background-color: var(--ifm-font-color-base); mask-image: url('/img/github.svg'); mask-size: contain; mask-repeat: no-repeat; @@ -99,8 +91,22 @@ html[data-theme='dark'] .hero__title { width: 1.5rem; height: 1.5rem; margin-right: 0.5rem; + transition: background-color 0.2s ease, transform 0.2s ease; +} + +.header-github-link:hover { + background-color: var(--ifm-color-primary); + transform: translateY(-1px); } html[data-theme='dark'] .header-github-link { background-color: var(--ifm-color-primary-lightest); } + +.aa-DetachedSearchButton { + color: var(--ifm-color-primary); +} + +h1 { + padding-bottom: 1rem; +} diff --git a/website/src/pages/index.js b/website/src/pages/index.js index ddd02eff5..fc12741da 100644 --- a/website/src/pages/index.js +++ b/website/src/pages/index.js @@ -2,10 +2,8 @@ import Link from '@docusaurus/Link'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import Layout from '@theme/Layout'; import clsx from 'clsx'; -import React from 'react'; +import React, { useState } from 'react'; -import GithubLogo from '../../static/img/github.svg'; -import LogoSvg from '../../static/img/logo.svg'; import Demo from '../components/Demo'; import HomepageFeatures from '../components/HomepageFeatures'; import RawExample from '../components/RawExample'; @@ -14,39 +12,70 @@ import styles from './index.module.css'; function HomepageHeader() { const { siteConfig } = useDocusaurusContext(); + const [copied, setCopied] = useState(false); + const installCommand = 'npm i vest'; + + const handleCopy = () => { + if (typeof navigator !== 'undefined' && navigator.clipboard) { + navigator.clipboard.writeText(installCommand); + setCopied(true); + setTimeout(() => setCopied(false), 1800); + } + }; + return (
-
- -
-
-

{siteConfig.title}

-

- {siteConfig.tagline} -

-
-
- - Quick Start Guide - - - - Github - - - Try V6 instead - +
+
+
+

Modern validations for ambitious teams

+

+ Declarative validations +
+ inspired by unit testing +

+

+ {siteConfig.tagline} +

+
+ + Get started + + + Explore the API + + +
+
+ {installCommand} +
+
+
+
Confidence without ceremony
+
+
Zero deps
+
+              
+                {`suite('signup', () => {
+  test('username', async () => {
+    await enforce(username).isNotBlank();
+  });
+
+  test('password', () => {
+    enforce(password).longerThan(8);
+  });
+});`}
+              
+            
+
+ Framework agnostic + + Async ready +
+
+
); diff --git a/website/src/pages/index.module.css b/website/src/pages/index.module.css index ffe17e712..923898b62 100644 --- a/website/src/pages/index.module.css +++ b/website/src/pages/index.module.css @@ -1,131 +1,242 @@ -/** - * CSS files with the .module.css suffix will be treated as CSS modules - * and scoped locally. - */ - .heroBanner { - text-align: center; position: relative; overflow: hidden; - padding: 4rem 2rem; - display: flex; - flex-direction: column; - align-items: center; - background: linear-gradient( - 180deg, - var(--ifm-color-primary-lightest) 0%, - #ffffff 100% - ); + padding: 6rem 1.5rem 4rem; + background: radial-gradient(circle at 10% 20%, rgba(99, 102, 241, 0.15), transparent 30%), + radial-gradient(circle at 80% 10%, rgba(79, 70, 229, 0.12), transparent 25%), + linear-gradient(180deg, rgba(255, 255, 255, 0.92) 0%, rgba(247, 248, 252, 0.75) 100%); } html[data-theme='dark'] .heroBanner { - background: linear-gradient(180deg, #1b1b1d 0%, #000000 100%); + background: radial-gradient(circle at 15% 20%, rgba(129, 140, 248, 0.28), transparent 28%), + radial-gradient(circle at 80% 0%, rgba(99, 102, 241, 0.2), transparent 20%), + linear-gradient(180deg, rgba(15, 23, 42, 0.9) 0%, rgba(15, 23, 42, 0.7) 100%); +} + +.heroGlow { + position: absolute; + inset: 0; + background: radial-gradient(circle at 40% 30%, rgba(99, 102, 241, 0.25), transparent 35%), + radial-gradient(circle at 70% 70%, rgba(52, 211, 153, 0.2), transparent 30%); + filter: blur(40px); + opacity: 0.9; + pointer-events: none; } -.logoContainer { - margin-bottom: 2rem; +.heroGrid { position: relative; - z-index: 10; + z-index: 1; + display: grid; + gap: 2.5rem; + grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); + align-items: center; + max-width: 1200px; + margin: 0 auto; +} + +.heroContent { + display: flex; + flex-direction: column; + gap: 1.25rem; } -.vestLogo { - width: 150px; - height: 150px; - filter: drop-shadow(0 10px 20px rgba(0, 0, 0, 0.15)); +.heroOverline { + font-weight: 600; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--ifm-color-primary); + font-size: 0.9rem; + margin: 0; } -.titleContainer { - max-width: 800px; - margin: 0 auto 2rem; +.heroHighlight { + color: var(--ifm-color-primary); } .heroTagline { - font-size: 1.5rem; - line-height: 1.5; + font-size: 1.2rem; + line-height: 1.7; color: var(--ifm-color-emphasis-700); - margin-top: 1rem; - font-weight: 400; + max-width: 640px; } -.buttons { +.ctaGroup { display: flex; + flex-wrap: wrap; + gap: 0.75rem; align-items: center; - justify-content: center; - gap: 1.5rem; - margin-top: 2rem; } -.btn { - display: inline-flex; - align-items: center; - justify-content: center; +.primaryCta, +.secondaryCta, +.copyButton { + border-radius: 999px; font-weight: 700; - font-size: 1.1rem; - padding: 0.8rem 2rem; - border-radius: 50px; - transition: all 0.2s ease; - text-decoration: none !important; - box-shadow: 0 4px 14px 0 rgba(0, 0, 0, 0.1); + padding: 0.85rem 1.5rem; + border: 1px solid transparent; + transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease; } -.btn:hover { +.primaryCta { + box-shadow: 0 15px 30px rgba(99, 102, 241, 0.25); +} + +.primaryCta:hover { transform: translateY(-2px); - box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15); + box-shadow: 0 20px 35px rgba(99, 102, 241, 0.35); } -.btnQuickStart { - background-color: var(--ifm-color-primary); - color: #fff; - border: 2px solid var(--ifm-color-primary); +.secondaryCta { + background: transparent; + color: var(--ifm-color-primary); + border-color: rgba(99, 102, 241, 0.35); } -.btnQuickStart:hover { - background-color: var(--ifm-color-primary-dark); - border-color: var(--ifm-color-primary-dark); - color: #fff; +.secondaryCta:hover { + border-color: var(--ifm-color-primary); + transform: translateY(-2px); } -.btnGit { - background-color: var(--ifm-color-emphasis-200); +.copyButton { + background: var(--ifm-card-background-color); color: var(--ifm-color-emphasis-900); - border: 2px solid transparent; + border-color: rgba(99, 102, 241, 0.25); } -.btnGit:hover { - background-color: var(--ifm-color-emphasis-300); - border-color: transparent; - color: var(--ifm-color-emphasis-900); +.copyButton:hover { + border-color: var(--ifm-color-primary); + transform: translateY(-2px); +} + +html[data-theme='dark'] .copyButton { + color: #f8fafc; +} + +.installBar { + display: inline-flex; + align-items: center; + gap: 0.75rem; + padding: 0.9rem 1.1rem; + border-radius: 12px; + background: rgba(99, 102, 241, 0.06); + border: 1px solid rgba(99, 102, 241, 0.15); + font-family: var(--ifm-font-family-monospace); + color: var(--ifm-color-primary-darkest); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.6); +} + +html[data-theme='dark'] .installBar { + background: rgba(129, 140, 248, 0.08); + border-color: rgba(129, 140, 248, 0.25); + color: var(--ifm-color-primary-lightest); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05); +} + +.heroPanel { + background: linear-gradient(135deg, rgba(99, 102, 241, 0.28), rgba(15, 23, 42, 0.8)); + border: 1px solid rgba(99, 102, 241, 0.3); + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.12), 0 15px 30px rgba(99, 102, 241, 0.12); + border-radius: 20px; + overflow: hidden; + position: relative; } -html[data-theme='dark'] .btnGit { - background-color: rgba(255, 255, 255, 0.1); - color: #fff; +.heroPanel::after { + content: ''; + position: absolute; + inset: 0; + background: radial-gradient(circle at 80% 10%, rgba(255, 255, 255, 0.15), transparent 35%); + pointer-events: none; } -html[data-theme='dark'] .btnGit:hover { - background-color: rgba(255, 255, 255, 0.2); +.panelHeader { + padding: 1rem 1.25rem; + font-weight: 700; + color: #f8fafc; + letter-spacing: 0.01em; } -.btnPromote { - display: none; /* Hiding promote button for cleaner look, or we can restyle it */ +.panelBody { + position: relative; + z-index: 1; + padding: 0 1.25rem 1.25rem; + display: flex; + flex-direction: column; + gap: 1rem; +} + +.panelBadge { + align-self: flex-start; + padding: 0.4rem 0.8rem; + border-radius: 999px; + background: rgba(15, 23, 42, 0.4); + color: #e0e7ff; + border: 1px solid rgba(255, 255, 255, 0.12); + font-weight: 600; + letter-spacing: 0.03em; +} + +.panelCode { + background: rgba(15, 23, 42, 0.7); + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 14px; + padding: 1rem 1.25rem; + color: #e2e8f0; + font-family: var(--ifm-font-family-monospace); + font-size: 0.95rem; + line-height: 1.7; + margin: 0; + overflow-x: auto; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06); +} + +.panelFooter { + display: flex; + align-items: center; + gap: 0.75rem; + color: #cbd5e1; + font-weight: 600; + letter-spacing: 0.01em; +} + +.pulse { + width: 8px; + height: 8px; + border-radius: 50%; + background: #22d3ee; + box-shadow: 0 0 0 0 rgba(34, 211, 238, 0.8); + animation: pulse 2s infinite; +} + +@keyframes pulse { + 0% { + box-shadow: 0 0 0 0 rgba(34, 211, 238, 0.7); + } + + 70% { + box-shadow: 0 0 0 14px rgba(34, 211, 238, 0); + } + + 100% { + box-shadow: 0 0 0 0 rgba(34, 211, 238, 0); + } } @media screen and (max-width: 768px) { .heroBanner { - padding: 3rem 1rem; + padding: 4rem 1.25rem 3rem; } .heroTagline { - font-size: 1.2rem; + font-size: 1.05rem; } - .buttons { + .ctaGroup { flex-direction: column; - width: 100%; + align-items: flex-start; } - .btn { + .installBar { width: 100%; - max-width: 300px; } } From d607b06337bd74b7453b5a998868c71d21e24aad Mon Sep 17 00:00:00 2001 From: Evyatar Date: Sat, 6 Dec 2025 10:09:31 -0500 Subject: [PATCH 2/2] Polish hero CTAs and feature polish --- .../components/HomepageFeatures.module.css | 36 ++++- website/src/pages/index.js | 12 +- website/src/pages/index.module.css | 144 +++++++++++++++--- 3 files changed, 162 insertions(+), 30 deletions(-) diff --git a/website/src/components/HomepageFeatures.module.css b/website/src/components/HomepageFeatures.module.css index 23a5809d6..2000ae0b4 100644 --- a/website/src/components/HomepageFeatures.module.css +++ b/website/src/components/HomepageFeatures.module.css @@ -44,7 +44,7 @@ border-radius: 16px; padding: 1.5rem; height: 100%; - transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease; + transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease; position: relative; overflow: hidden; box-shadow: 0 10px 20px rgba(0, 0, 0, 0.04); @@ -56,13 +56,13 @@ inset: 0; background: radial-gradient(circle at 20% 20%, rgba(99, 102, 241, 0.12), transparent 45%); opacity: 0; - transition: opacity 0.25s ease; + transition: opacity 0.18s ease; } .featureCard:hover { - transform: translateY(-6px); - border-color: var(--ifm-color-primary); - box-shadow: 0 20px 35px rgba(0, 0, 0, 0.08), 0 10px 20px rgba(99, 102, 241, 0.08); + transform: translateY(-3px); + border-color: rgba(99, 102, 241, 0.55); + box-shadow: 0 14px 26px rgba(0, 0, 0, 0.07), 0 10px 18px rgba(99, 102, 241, 0.06); } .featureCard:hover::before { @@ -76,8 +76,8 @@ html[data-theme='dark'] .featureCard { } html[data-theme='dark'] .featureCard:hover { - border-color: var(--ifm-color-primary); - box-shadow: 0 20px 40px rgba(0, 0, 0, 0.45), 0 0 40px rgba(99, 102, 241, 0.15); + border-color: rgba(129, 140, 248, 0.85); + box-shadow: 0 16px 32px rgba(0, 0, 0, 0.42), 0 0 30px rgba(99, 102, 241, 0.12); } .featureHeader { @@ -89,7 +89,7 @@ html[data-theme='dark'] .featureCard:hover { .emoji { font-size: 1.9rem; - background: rgba(99, 102, 241, 0.12); + background: rgba(99, 102, 241, 0.1); width: 54px; height: 54px; border-radius: 14px; @@ -128,3 +128,23 @@ html[data-theme='dark'] .category { background: rgba(129, 140, 248, 0.16); color: var(--ifm-color-primary-lightest); } + +@media screen and (max-width: 768px) { + .features { + padding: 4.5rem 0; + } + + .featuresGrid { + gap: 1.25rem; + } +} + +@media screen and (max-width: 540px) { + .sectionHeader { + padding: 0 0.5rem; + } + + .featureCard { + padding: 1.25rem; + } +} diff --git a/website/src/pages/index.js b/website/src/pages/index.js index fc12741da..20d89a884 100644 --- a/website/src/pages/index.js +++ b/website/src/pages/index.js @@ -44,12 +44,16 @@ function HomepageHeader() { Explore the API - + + Try Vest v6 +
- {installCommand} + {installCommand} +
diff --git a/website/src/pages/index.module.css b/website/src/pages/index.module.css index 923898b62..477f2caf7 100644 --- a/website/src/pages/index.module.css +++ b/website/src/pages/index.module.css @@ -1,7 +1,7 @@ .heroBanner { position: relative; overflow: hidden; - padding: 6rem 1.5rem 4rem; + padding: 6rem 2rem 4.5rem; background: radial-gradient(circle at 10% 20%, rgba(99, 102, 241, 0.15), transparent 30%), radial-gradient(circle at 80% 10%, rgba(79, 70, 229, 0.12), transparent 25%), linear-gradient(180deg, rgba(255, 255, 255, 0.92) 0%, rgba(247, 248, 252, 0.75) 100%); @@ -32,12 +32,14 @@ html[data-theme='dark'] .heroBanner { align-items: center; max-width: 1200px; margin: 0 auto; + width: 100%; } .heroContent { display: flex; flex-direction: column; gap: 1.25rem; + min-width: 0; } .heroOverline { @@ -58,6 +60,7 @@ html[data-theme='dark'] .heroBanner { line-height: 1.7; color: var(--ifm-color-emphasis-700); max-width: 640px; + margin: 0; } .ctaGroup { @@ -69,7 +72,7 @@ html[data-theme='dark'] .heroBanner { .primaryCta, .secondaryCta, -.copyButton { +.tertiaryCta { border-radius: 999px; font-weight: 700; padding: 0.85rem 1.5rem; @@ -87,51 +90,113 @@ html[data-theme='dark'] .heroBanner { } .secondaryCta { - background: transparent; - color: var(--ifm-color-primary); - border-color: rgba(99, 102, 241, 0.35); + background: rgba(99, 102, 241, 0.08); + color: #1e1b4b; + border-color: rgba(99, 102, 241, 0.25); } .secondaryCta:hover { border-color: var(--ifm-color-primary); transform: translateY(-2px); + box-shadow: 0 15px 28px rgba(99, 102, 241, 0.18); +} + +html[data-theme='dark'] .secondaryCta { + background: rgba(129, 140, 248, 0.16); + color: #e2e8f0; + border-color: rgba(129, 140, 248, 0.45); + box-shadow: 0 12px 26px rgba(0, 0, 0, 0.35); +} + +html[data-theme='dark'] .secondaryCta:hover { + border-color: var(--ifm-color-primary-lightest); + box-shadow: 0 16px 30px rgba(0, 0, 0, 0.4), 0 0 26px rgba(129, 140, 248, 0.2); } -.copyButton { - background: var(--ifm-card-background-color); - color: var(--ifm-color-emphasis-900); +.tertiaryCta { + background: transparent; + color: var(--ifm-color-primary-darkest); border-color: rgba(99, 102, 241, 0.25); } -.copyButton:hover { +.tertiaryCta:hover { border-color: var(--ifm-color-primary); + box-shadow: 0 12px 24px rgba(99, 102, 241, 0.16); transform: translateY(-2px); } -html[data-theme='dark'] .copyButton { - color: #f8fafc; +html[data-theme='dark'] .tertiaryCta { + color: var(--ifm-color-primary-lightest); + border-color: rgba(129, 140, 248, 0.4); +} + +html[data-theme='dark'] .tertiaryCta:hover { + border-color: var(--ifm-color-primary-lightest); + box-shadow: 0 12px 24px rgba(129, 140, 248, 0.2); } .installBar { - display: inline-flex; + display: flex; align-items: center; - gap: 0.75rem; - padding: 0.9rem 1.1rem; - border-radius: 12px; + gap: 0.85rem; + padding: 0.95rem 1.15rem; + border-radius: 14px; background: rgba(99, 102, 241, 0.06); - border: 1px solid rgba(99, 102, 241, 0.15); + border: 1px solid rgba(99, 102, 241, 0.18); font-family: var(--ifm-font-family-monospace); color: var(--ifm-color-primary-darkest); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.6); + max-width: 520px; + width: 100%; + flex-wrap: wrap; } html[data-theme='dark'] .installBar { background: rgba(129, 140, 248, 0.08); - border-color: rgba(129, 140, 248, 0.25); + border-color: rgba(129, 140, 248, 0.3); color: var(--ifm-color-primary-lightest); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05); } +.installCommand { + flex: 1; + min-width: 0; + white-space: nowrap; + overflow-x: auto; + font-size: 0.95rem; +} + +.copyPill { + display: inline-flex; + align-items: center; + gap: 0.4rem; + padding: 0.5rem 0.9rem; + border-radius: 999px; + background: rgba(99, 102, 241, 0.12); + border: 1px solid rgba(99, 102, 241, 0.25); + color: var(--ifm-color-primary-darkest); + font-weight: 700; + cursor: pointer; + transition: transform 0.15s ease, box-shadow 0.2s ease, border-color 0.2s ease; +} + +.copyPill:hover { + transform: translateY(-1px); + border-color: var(--ifm-color-primary); + box-shadow: 0 10px 18px rgba(99, 102, 241, 0.18); +} + +html[data-theme='dark'] .copyPill { + background: rgba(129, 140, 248, 0.14); + color: #e2e8f0; + border-color: rgba(129, 140, 248, 0.35); +} + +.copyText { + font-family: var(--ifm-font-family-base); + font-size: 0.95rem; +} + .heroPanel { background: linear-gradient(135deg, rgba(99, 102, 241, 0.28), rgba(15, 23, 42, 0.8)); border: 1px solid rgba(99, 102, 241, 0.3); @@ -139,6 +204,10 @@ html[data-theme='dark'] .installBar { border-radius: 20px; overflow: hidden; position: relative; + min-height: 100%; + max-width: 560px; + width: 100%; + justify-self: center; } .heroPanel::after { @@ -197,6 +266,7 @@ html[data-theme='dark'] .installBar { color: #cbd5e1; font-weight: 600; letter-spacing: 0.01em; + flex-wrap: wrap; } .pulse { @@ -224,11 +294,12 @@ html[data-theme='dark'] .installBar { @media screen and (max-width: 768px) { .heroBanner { - padding: 4rem 1.25rem 3rem; + padding: 3.5rem 1.25rem 3.5rem; } .heroTagline { font-size: 1.05rem; + line-height: 1.6; } .ctaGroup { @@ -236,7 +307,44 @@ html[data-theme='dark'] .installBar { align-items: flex-start; } + .heroGrid { + grid-template-columns: 1fr; + } + + .heroPanel { + order: 2; + } + + .heroContent { + order: 1; + gap: 1rem; + } + .installBar { width: 100%; + padding: 0.9rem 0.95rem; + } + + .installCommand { + font-size: 0.9rem; + } +} + +@media screen and (max-width: 540px) { + .heroBanner { + padding: 3rem 1rem 3.25rem; } + + .heroGrid { + gap: 2rem; + } + + .heroPanel { + border-radius: 16px; + } + + .installBar { + gap: 0.6rem; + } +} }