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]

Reply via email to