This is an automated email from the ASF dual-hosted git repository.
morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris-website.git
The following commit(s) were added to refs/heads/master by this push:
new dde83e94df7 [refactor](next) add user stories landing page (#3649)
dde83e94df7 is described below
commit dde83e94df73403df92377ef268c4fb197d9836f
Author: Mingyu Chen (Rayner) <[email protected]>
AuthorDate: Thu May 14 15:48:45 2026 -0700
[refactor](next) add user stories landing page (#3649)
---
src/components/home-next/NavbarNext.tsx | 2 +-
src/components/why-doris-next/UsersNext.scss | 291 +++++++++++++++++++++++++++
src/components/why-doris-next/UsersNext.tsx | 189 +++++++++++++++++
src/pages/why-doris/users/index.tsx | 6 +
4 files changed, 487 insertions(+), 1 deletion(-)
diff --git a/src/components/home-next/NavbarNext.tsx
b/src/components/home-next/NavbarNext.tsx
index 996e59b261e..1ee5471e9ec 100644
--- a/src/components/home-next/NavbarNext.tsx
+++ b/src/components/home-next/NavbarNext.tsx
@@ -38,7 +38,7 @@ function buildNavItems(docsHref: string, releasesHref:
string): NavItem[] {
{ label: 'Doris vs. Others', href: '/why-doris/compare' },
{ label: 'Benchmarks', href: '/why-doris/benchmarks' },
{ label: 'Key Features', href: '/why-doris/key-features' },
- { label: 'User Stories (coming soon)', href: '#' },
+ { label: 'User Stories', href: '/why-doris/users' },
],
},
{
diff --git a/src/components/why-doris-next/UsersNext.scss
b/src/components/why-doris-next/UsersNext.scss
new file mode 100644
index 00000000000..fa59530763b
--- /dev/null
+++ b/src/components/why-doris-next/UsersNext.scss
@@ -0,0 +1,291 @@
+.users-next {
+ --un-green-dark: #06805F;
+ --un-green-darker: #054C39;
+ --un-green-darkest: #033A2C;
+ --un-cream-light: #FAF6EE;
+ --un-cream-warm: #EFE6D2;
+ --un-paper: #FFFCF5;
+ --un-yellow: #FFD23F;
+ --un-yellow-bright: #FFE066;
+ --un-ink: #0F1A14;
+ --un-mono: 'JetBrains Mono', 'IBM Plex Mono', ui-monospace,
SFMono-Regular, Menlo, monospace;
+ --un-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI',
sans-serif;
+ --un-container: 1320px;
+ --un-gutter: 56px;
+
+ position: relative;
+ background: var(--un-paper);
+ color: var(--un-ink);
+ font-family: var(--un-sans);
+ overflow-x: hidden;
+
+ * {
+ box-sizing: border-box;
+ }
+}
+
+.users-next__container {
+ max-width: var(--un-container);
+ margin: 0 auto;
+ padding: 0 var(--un-gutter);
+ width: 100%;
+}
+
+.users-next__accent {
+ color: var(--un-yellow);
+}
+
+[data-reveal] {
+ opacity: 0;
+ transform: translateY(24px);
+ transition:
+ opacity 0.7s cubic-bezier(.2, .8, .2, 1),
+ transform 0.7s cubic-bezier(.2, .8, .2, 1);
+}
+
+[data-reveal].is-visible {
+ opacity: 1;
+ transform: none;
+}
+
+[data-reveal-delay='1'] {
+ transition-delay: 0.08s;
+}
+
+[data-reveal-delay='2'] {
+ transition-delay: 0.16s;
+}
+
+[data-reveal-delay='3'] {
+ transition-delay: 0.24s;
+}
+
+/* ---------------- Hero ---------------- */
+
+.users-next__hero {
+ position: relative;
+ background: var(--un-green-dark);
+ color: var(--un-cream-light);
+ overflow: hidden;
+ padding: 96px 0 88px;
+}
+
+.users-next__hero-bg {
+ position: absolute;
+ inset: 0;
+ z-index: 0;
+ background:
+ radial-gradient(ellipse 60% 50% at 78% 22%, rgba(45, 223, 168, 0.18),
transparent 70%),
+ radial-gradient(ellipse 50% 70% at 0% 100%, rgba(255, 210, 63, 0.05),
transparent 70%);
+}
+
+.users-next__hero-grid {
+ position: absolute;
+ inset: 0;
+ background-image: radial-gradient(rgba(245, 239, 228, 0.09) 1.2px,
transparent 1.2px);
+ background-size: 28px 28px;
+ mask-image: linear-gradient(180deg, black, black 75%, transparent);
+ -webkit-mask-image: linear-gradient(180deg, black, black 75%, transparent);
+}
+
+.users-next__hero-stack {
+ position: relative;
+ z-index: 5;
+ max-width: 1040px;
+}
+
+.users-next__hero-title {
+ font-family: var(--un-mono);
+ font-weight: 700;
+ text-transform: uppercase;
+ letter-spacing: -0.035em;
+ word-spacing: -0.18em;
+ line-height: 0.92;
+ color: var(--un-cream-light);
+ margin: 0;
+ font-size: clamp(40px, 4.4vw, 62px);
+}
+
+.users-next__bolt-inline {
+ display: inline-block;
+ vertical-align: -0.12em;
+ margin: 0 0.06em 0 0.04em;
+}
+
+.users-next__hero-sub {
+ font-size: 16px;
+ line-height: 1.5;
+ word-spacing: -0.12em;
+ color: rgba(245, 239, 228, 0.85);
+ margin: 22px 0 0;
+ max-width: 620px;
+ font-weight: 400;
+}
+
+.users-next__hero-cta {
+ margin-top: 32px;
+}
+
+.users-next__cta {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ padding: 14px 28px;
+ background: var(--un-yellow);
+ color: var(--un-ink);
+ font-family: var(--un-mono);
+ font-weight: 700;
+ font-size: 14px;
+ letter-spacing: 0.04em;
+ border-radius: 4px;
+ text-decoration: none;
+ transition:
+ transform 0.2s cubic-bezier(.2, .8, .2, 1),
+ box-shadow 0.2s cubic-bezier(.2, .8, .2, 1),
+ background 0.2s ease;
+}
+
+.users-next__cta:hover {
+ transform: translateY(-2px);
+ background: var(--un-yellow-bright);
+ box-shadow: 0 14px 30px -16px rgba(0, 0, 0, 0.5);
+ color: var(--un-ink);
+ text-decoration: none;
+}
+
+/* ---------------- Grid section ---------------- */
+
+.users-next__section {
+ position: relative;
+ background: var(--un-paper);
+ padding: 88px 0 120px;
+}
+
+.users-next__cats {
+ list-style: none;
+ margin: 0 auto;
+ padding: 0;
+ display: flex;
+ flex-wrap: wrap;
+ gap: 12px 24px;
+ justify-content: center;
+ max-width: 58rem;
+ color: #4C576C;
+}
+
+.users-next__cats li {
+ padding: 1px 0;
+}
+
+.users-next__cat {
+ display: block;
+ cursor: pointer;
+ white-space: nowrap;
+ border: 0;
+ border-radius: 2.5rem;
+ padding: 12px 24px;
+ font-size: 16px;
+ color: inherit;
+ background: #fff;
+ box-shadow: 0px 1px 4px 0px rgba(0, 89, 68, 0.10);
+ transition: background 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
+}
+
+.users-next__cat:hover {
+ background: var(--ifm-color-primary, #11A679);
+ color: #fff;
+}
+
+.users-next__cat.is-active {
+ background: var(--ifm-color-primary, #11A679);
+ color: #fff;
+}
+
+.users-next__grid {
+ list-style: none;
+ padding: 0;
+ margin: 48px 0 0;
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ gap: 32px;
+}
+
+.users-next__more-wrap {
+ display: flex;
+ justify-content: center;
+ margin-top: 36px;
+}
+
+.users-next__more {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ cursor: pointer;
+ padding: 16px 32px;
+ border: 1px solid var(--ifm-color-primary, #11A679);
+ background: transparent;
+ border-radius: 4px;
+ color: var(--ifm-color-primary, #11A679);
+ font-size: 16px;
+ transition: background 0.2s ease, color 0.2s ease;
+}
+
+.users-next__more:hover {
+ background: var(--ifm-color-primary, #11A679);
+ color: #fff;
+}
+
+/* ---------------- Responsive ---------------- */
+
+@media (max-width: 1100px) {
+ .users-next {
+ --un-gutter: 36px;
+ }
+
+ .users-next__grid {
+ grid-template-columns: repeat(3, 1fr);
+ gap: 24px;
+ }
+}
+
+@media (max-width: 768px) {
+ .users-next {
+ --un-gutter: 22px;
+ }
+
+ .users-next__hero {
+ padding: 64px 0 56px;
+ }
+
+ .users-next__section {
+ padding: 56px 0 72px;
+ }
+
+ .users-next__cats {
+ gap: 12px;
+ justify-content: flex-start;
+ flex-wrap: nowrap;
+ overflow-x: auto;
+ scrollbar-width: none;
+ -ms-overflow-style: none;
+ }
+
+ .users-next__cats::-webkit-scrollbar {
+ display: none;
+ }
+
+ .users-next__cat {
+ padding: 8px 16px;
+ font-size: 14px;
+ }
+
+ .users-next__grid {
+ grid-template-columns: repeat(2, 1fr);
+ gap: 12px;
+ margin-top: 24px;
+ }
+
+ .users-next__hero-sub {
+ font-size: 15px;
+ }
+}
diff --git a/src/components/why-doris-next/UsersNext.tsx
b/src/components/why-doris-next/UsersNext.tsx
new file mode 100644
index 00000000000..872a309b0aa
--- /dev/null
+++ b/src/components/why-doris-next/UsersNext.tsx
@@ -0,0 +1,189 @@
+import React, { JSX, useEffect, useMemo, useState } from 'react';
+import { LayoutNext } from '../home-next/LayoutNext';
+import { USER_STORIES_CATEGORIES } from '@site/src/constant/user.data';
+import USERS from '@site/src/constant/users.data.json';
+import UserItem from '../user-item/user-item';
+import './UsersNext.scss';
+
+const ALL_TEXT = 'All';
+const PAGE_SIZE = 32;
+
+function useRevealObserver(): void {
+ useEffect(() => {
+ const items = document.querySelectorAll<HTMLElement>('[data-reveal]');
+ if (!('IntersectionObserver' in window)) {
+ items.forEach((item) => item.classList.add('is-visible'));
+ return undefined;
+ }
+
+ const observer = new IntersectionObserver(
+ (entries) => {
+ entries.forEach((entry) => {
+ if (entry.isIntersecting) {
+ entry.target.classList.add('is-visible');
+ observer.unobserve(entry.target);
+ }
+ });
+ },
+ { threshold: 0.12, rootMargin: '0px 0px -8% 0px' }
+ );
+
+ items.forEach((item) => observer.observe(item));
+ return () => observer.disconnect();
+ }, []);
+}
+
+function BoltIcon({ size = 24, color = '#FFD23F' }: { size?: number | string;
color?: string }) {
+ return (
+ <svg width={size} height={size} viewBox="0 0 24 24" fill="none"
aria-hidden="true">
+ <path
+ d="M13 2L3 14h7l-1 8 11-13h-7l1-7z"
+ fill={color}
+ stroke={color}
+ strokeWidth="0.5"
+ strokeLinejoin="round"
+ />
+ </svg>
+ );
+}
+
+function UsersHero(): JSX.Element {
+ return (
+ <section className="users-next__hero" id="hero">
+ <div className="users-next__hero-bg" aria-hidden="true" />
+ <div className="users-next__hero-grid" aria-hidden="true" />
+ <div className="users-next__container">
+ <div className="users-next__hero-stack">
+ <h1 className="users-next__hero-title" data-reveal
data-reveal-delay="1">
+ Start real-time journey
+ <br />
+ with{' '}
+ <span className="users-next__accent">
+ innovators
+ <span className="users-next__bolt-inline">
+ <BoltIcon size="0.85em" />
+ </span>
+ </span>
+ </h1>
+ <p className="users-next__hero-sub" data-reveal
data-reveal-delay="2">
+ Over 10,000+ global leaders and enterprises are
powered by Apache Doris.
+ </p>
+ <div className="users-next__hero-cta" data-reveal
data-reveal-delay="3">
+ <a
+ className="users-next__cta"
+
href="https://github.com/apache/doris/discussions/27683"
+ target="_blank"
+ rel="noreferrer"
+ >
+ Share your story
+ </a>
+ </div>
+ </div>
+ </div>
+ </section>
+ );
+}
+
+function UsersGridSection(): JSX.Element {
+ const [active, setActive] = useState<string>(ALL_TEXT);
+ const [currentSize, setCurrentSize] = useState<number>(PAGE_SIZE);
+
+ const users = useMemo(() => {
+ const source = active === ALL_TEXT ? USERS : USERS.filter((user) =>
user.category === active);
+ return [...source].sort((a, b) => a.name.localeCompare(b.name, 'en', {
sensitivity: 'base' }));
+ }, [active]);
+
+ function changeCategory(category: string) {
+ setCurrentSize(PAGE_SIZE);
+ if (USER_STORIES_CATEGORIES.includes(category)) {
+ setActive(category);
+ } else {
+ setActive(ALL_TEXT);
+ }
+ }
+
+ return (
+ <section className="users-next__section" id="users">
+ <div className="users-next__container">
+ <ul className="users-next__cats" data-reveal>
+ {USER_STORIES_CATEGORIES.map((item) => (
+ <li key={item}>
+ <button
+ type="button"
+ onClick={() => changeCategory(item)}
+ className={`users-next__cat ${active === item
? 'is-active' : ''}`}
+ >
+ {item}
+ </button>
+ </li>
+ ))}
+ </ul>
+
+ <ul className="users-next__grid" data-reveal
data-reveal-delay="1">
+ {users.slice(0, currentSize).map((user) => (
+ <UserItem key={user.name} {...user} />
+ ))}
+ </ul>
+
+ {currentSize < users.length && (
+ <div className="users-next__more-wrap">
+ <button
+ type="button"
+ onClick={() =>
+ setCurrentSize((size) => Math.min(size +
PAGE_SIZE, users.length))
+ }
+ className="users-next__more"
+ >
+ <span>View more</span>
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ width="17"
+ height="17"
+ viewBox="0 0 17 17"
+ fill="none"
+ aria-hidden="true"
+ >
+ <path
+ d="M4.5 9.82226L8.5 13.8222L12.5 9.82227"
+ stroke="currentColor"
+ strokeWidth="1.37143"
+ strokeLinecap="round"
+ strokeLinejoin="round"
+ />
+ <path
+ d="M8.49951 3.82227L8.49951 13.8223"
+ stroke="currentColor"
+ strokeWidth="1.37143"
+ strokeLinecap="round"
+ strokeLinejoin="round"
+ />
+ </svg>
+ </button>
+ </div>
+ )}
+ </div>
+ </section>
+ );
+}
+
+function UsersContent(): JSX.Element {
+ useRevealObserver();
+
+ return (
+ <div className="users-next">
+ <UsersHero />
+ <UsersGridSection />
+ </div>
+ );
+}
+
+export default function UsersNext(): JSX.Element {
+ return (
+ <LayoutNext
+ title="Apache Doris - User Stories | Start real-time journey with
innovators"
+ description="Over 4000 global leaders and enterprises are powered
by Apache Doris, using OLAP DBMS to drive real-world applications, from
lakehouse and ad-hoc analytics to user behavior analytics and more."
+ >
+ <UsersContent />
+ </LayoutNext>
+ );
+}
diff --git a/src/pages/why-doris/users/index.tsx
b/src/pages/why-doris/users/index.tsx
new file mode 100644
index 00000000000..ffed7c7a16c
--- /dev/null
+++ b/src/pages/why-doris/users/index.tsx
@@ -0,0 +1,6 @@
+import React, { JSX } from 'react';
+import UsersNext from '@site/src/components/why-doris-next/UsersNext';
+
+export default function UsersPage(): JSX.Element {
+ return <UsersNext />;
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]