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 bee48d00e56 [chore](download) flatten the file panel and add copy link 
to the Download button (#4129)
bee48d00e56 is described below

commit bee48d00e56ee065395bfb3e934d03bc8403b873
Author: Mingyu Chen (Rayner) <[email protected]>
AuthorDate: Fri Sep 11 11:39:00 2026 +0800

    [chore](download) flatten the file panel and add copy link to the Download 
button (#4129)
    
    ## What
    
    Two changes to the resolved-file row of the quick download card on
    `/download`:
    
    **1. One frame instead of three.** The block stacked a dashed outer box,
    Infima's inline-`code` box around the filename, and a row of underlined
    links, and the filename and the verification links were set in nearly
    the same size and weight. Now:
    
    - a single soft panel with a hairline border; the `<code>` chrome is
    reset so the filename no longer sits in a second box (the dashed border
    is gone — it read as a placeholder/drop zone)
    - the filename is the only strong element (ink, 15px/600)
    - `ASC` / `SHA-512` / `KEYS` drop to a small muted line with a faint
    underline that becomes the brand colour on hover; `How to verify` is a
    document rather than a sibling file, so a hairline separates it from the
    three
    
    **2. Copy link on the Download button.** The button is now a split
    button: `DOWNLOAD` on the left, a copy zone on the right that copies the
    tarball URL (`copy-to-clipboard`, the same dependency the all-release
    and tools forms use). On click the zone inverts to a check for 1.8 s,
    then resets; it also resets when the version / architecture / tarball
    selection changes. `aria-label` + `title`, plus an `aria-live` region
    for screen readers. On screens ≤960px the group stretches to full width.
    
    ## Files
    
    - `src/components/download-form-next/DownloadFormNext.tsx`
    - `src/components/download-form-next/download-page.scss`
    
    All colours go through the existing brand tokens, so the six brand
    themes are unaffected.
    
    ## Verified
    
    Dev server (`LANDING_ONLY=true yarn start`) in headless Chrome at 1440 /
    820 / 390 px, in default, hover, copied and Source-tarball states.
    Clicking copy puts
    
`https://apache-doris-releases.oss-accelerate.aliyuncs.com/apache-doris-4.1.4-bin-x64.tar.gz`
    on the clipboard and the copied state clears after the timeout. No new
    console errors.
    
    🤖 Generated with [Claude Code](https://claude.com/claude-code)
    
    https://claude.ai/code/session_01PEMMz8BeXq1CPNUuxmEaxj
    
    Co-authored-by: morningman <[email protected]>
    Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
---
 .../download-form-next/DownloadFormNext.tsx        |  89 +++++++++++-
 .../download-form-next/download-page.scss          | 151 +++++++++++++++++----
 2 files changed, 204 insertions(+), 36 deletions(-)

diff --git a/src/components/download-form-next/DownloadFormNext.tsx 
b/src/components/download-form-next/DownloadFormNext.tsx
index 52f3c490041..c9e104875d6 100644
--- a/src/components/download-form-next/DownloadFormNext.tsx
+++ b/src/components/download-form-next/DownloadFormNext.tsx
@@ -1,7 +1,8 @@
 import Translate, { translate } from '@docusaurus/Translate';
-import React, { useEffect, useMemo, useState } from 'react';
+import React, { useEffect, useMemo, useRef, useState } from 'react';
 import Link from '@docusaurus/Link';
 import clsx from 'clsx';
+import copy from 'copy-to-clipboard';
 import DownloadFormAllRelease from 
'@site/src/components/download-form/download-form-all-release';
 import DownloadFormArchive from 
'@site/src/components/download-form/download-form-archive';
 import DownloadFormTools from 
'@site/src/components/download-form/download-form-tools';
@@ -75,6 +76,24 @@ export default function DownloadFormNext(): JSX.Element {
         };
     }, [build, isSource]);
 
+    /** Copy-link feedback: the button's icon flips to a check for a moment. */
+    const [copied, setCopied] = useState(false);
+    const copiedTimer = useRef<ReturnType<typeof setTimeout>>();
+
+    useEffect(() => {
+        setCopied(false);
+        clearTimeout(copiedTimer.current);
+        return () => clearTimeout(copiedTimer.current);
+    }, [asset?.gz]);
+
+    function onCopyLink() {
+        if (!asset?.gz) return;
+        copy(asset.gz);
+        setCopied(true);
+        clearTimeout(copiedTimer.current);
+        copiedTimer.current = setTimeout(() => setCopied(false), 1800);
+    }
+
     function onCoreVersionChange(values: any) {
         const [branch, release] = values.version || [];
         if (branch && release) setReleaseNote(releaseNotePath(branch, 
release));
@@ -201,16 +220,74 @@ export default function DownloadFormNext(): JSX.Element {
                                     <span 
className="download-next__quick-label" aria-hidden="true" />
                                     <div className="download-next__file">
                                         <code 
className="download-next__file-name">{asset.filename}</code>
-                                        <div 
className="download-next__file-links">
+                                        <div 
className="download-next__file-verify">
                                             <Link to={asset.asc}>ASC</Link>
                                             <Link 
to={asset.sha512}>SHA-512</Link>
                                             <Link to={KEYS_URL}>KEYS</Link>
-                                            <Link to={VERIFY_URL}>How to 
verify</Link>
+                                            <Link 
className="download-next__file-verify-guide" to={VERIFY_URL}>
+                                                How to verify
+                                            </Link>
                                         </div>
                                     </div>
-                                    <Link 
className="download-next__download-btn" to={asset.gz}>
-                                        Download
-                                    </Link>
+                                    <div className="download-next__actions">
+                                        <Link 
className="download-next__download-btn" to={asset.gz}>
+                                            Download
+                                        </Link>
+                                        <button
+                                            type="button"
+                                            
className={clsx('download-next__copy-btn', { 'is-copied': copied })}
+                                            aria-label={copied ? 'Download 
link copied' : 'Copy download link'}
+                                            title={copied ? 'Copied' : 'Copy 
download link'}
+                                            onClick={onCopyLink}
+                                        >
+                                            {copied ? (
+                                                <svg
+                                                    aria-hidden="true"
+                                                    
xmlns="http://www.w3.org/2000/svg";
+                                                    width="16"
+                                                    height="16"
+                                                    viewBox="0 0 16 16"
+                                                    fill="none"
+                                                >
+                                                    <path
+                                                        d="M2.5 8.5L6 12L13.5 
4.5"
+                                                        stroke="currentColor"
+                                                        strokeWidth="1.8"
+                                                        strokeLinecap="round"
+                                                        strokeLinejoin="round"
+                                                    />
+                                                </svg>
+                                            ) : (
+                                                <svg
+                                                    aria-hidden="true"
+                                                    
xmlns="http://www.w3.org/2000/svg";
+                                                    width="16"
+                                                    height="16"
+                                                    viewBox="0 0 16 16"
+                                                    fill="none"
+                                                >
+                                                    <rect
+                                                        x="5.5"
+                                                        y="5.5"
+                                                        width="8"
+                                                        height="8"
+                                                        rx="1.2"
+                                                        stroke="currentColor"
+                                                        strokeWidth="1.5"
+                                                    />
+                                                    <path
+                                                        d="M10.5 4V3.2A1.2 1.2 
0 0 0 9.3 2H3.2A1.2 1.2 0 0 0 2 3.2v6.1a1.2 1.2 0 0 0 1.2 1.2H4"
+                                                        stroke="currentColor"
+                                                        strokeWidth="1.5"
+                                                        strokeLinecap="round"
+                                                    />
+                                                </svg>
+                                            )}
+                                            <span 
className="download-next__sr-only" aria-live="polite">
+                                                {copied ? 'Download link 
copied' : ''}
+                                            </span>
+                                        </button>
+                                    </div>
                                 </div>
                             )}
 
diff --git a/src/components/download-form-next/download-page.scss 
b/src/components/download-form-next/download-page.scss
index 3c7414eca83..855b5c4733d 100644
--- a/src/components/download-form-next/download-page.scss
+++ b/src/components/download-form-next/download-page.scss
@@ -172,49 +172,130 @@
     margin-top: 22px;
 }
 
-.download-next__file-links {
+// The verification line under the filename: one muted row of small links.
+// Everything here is secondary to the filename above it, so it is lighter,
+// smaller, and underlined only faintly until hovered.
+.download-next__file-verify {
     display: flex;
     flex-wrap: wrap;
-    gap: 14px;
+    align-items: center;
+    gap: 6px 16px;
     margin-top: 7px;
     @include type.mono-text(12px, 500, 1.4, 0.02em);
 
     a {
         color: var(--dl-text-muted);
-        border-bottom: 1px solid var(--dl-drained-line);
+        text-decoration: underline;
+        text-decoration-thickness: 1px;
+        text-decoration-color: rgb(var(--brand-ink-rgb) / 22%);
+        text-underline-offset: 3px;
 
         &:hover {
             color: var(--ifm-color-primary);
-            border-bottom-color: var(--ifm-color-primary);
-            text-decoration: none;
+            text-decoration-color: currentColor;
         }
     }
 }
 
+// The guide is a document, not a sibling file of the tarball: a hairline
+// keeps it apart from ASC / SHA-512 / KEYS.
+.download-next__file-verify-guide {
+    position: relative;
+    padding-left: 17px;
+
+    &::before {
+        content: '';
+        position: absolute;
+        left: 0;
+        top: 50%;
+        width: 1px;
+        height: 12px;
+        transform: translateY(-50%);
+        background: var(--dl-border);
+    }
+}
+
+// One physical button with two zones: Download, and copy its link. The
+// shadow and the hover lift belong to the whole button; the backgrounds
+// respond per zone.
+.download-next__actions {
+    display: inline-flex;
+    align-items: stretch;
+    border-radius: 6px;
+    box-shadow: 0 2px 0 rgb(var(--brand-ink-rgb) / 18%);
+    transition:
+        transform 0.14s ease,
+        box-shadow 0.18s ease;
+
+    &:hover {
+        transform: translateY(-1px);
+        box-shadow: 0 4px 0 rgb(var(--brand-ink-rgb) / 18%);
+    }
+}
+
 .download-next__download-btn {
     display: inline-flex;
     align-items: center;
     justify-content: center;
     padding: 15px 28px;
-    border-radius: 6px;
+    border-radius: 6px 0 0 6px;
     background: var(--dl-yellow);
     color: var(--dl-ink) !important;
     white-space: nowrap;
     @include type.mono-text(13px, 800, 1, 0.05em, uppercase);
-    box-shadow: 0 2px 0 rgb(var(--brand-ink-rgb) / 18%);
-    transition:
-        transform 0.14s ease,
-        box-shadow 0.18s ease,
-        background 0.18s ease;
+    transition: background 0.18s ease;
 
     &:hover {
         background: var(--dl-yellow-bright);
-        transform: translateY(-1px);
-        box-shadow: 0 4px 0 rgb(var(--brand-ink-rgb) / 18%);
         text-decoration: none !important;
     }
 }
 
+.download-next__copy-btn {
+    display: inline-flex;
+    align-items: center;
+    justify-content: center;
+    width: 46px;
+    padding: 0;
+    border: 0;
+    border-left: 1px solid rgb(var(--brand-ink-rgb) / 18%);
+    border-radius: 0 6px 6px 0;
+    background: var(--dl-yellow);
+    color: var(--dl-ink);
+    cursor: pointer;
+    transition:
+        background 0.18s ease,
+        color 0.18s ease;
+
+    svg {
+        display: block;
+    }
+
+    &:hover {
+        background: var(--dl-yellow-bright);
+    }
+
+    // Copied: the zone inverts for a moment, so the change reads from across
+    // the room rather than as a 16px icon swap.
+    &.is-copied {
+        background: var(--dl-ink);
+        border-left-color: var(--dl-ink);
+        color: var(--dl-yellow);
+    }
+}
+
+.download-next__sr-only {
+    position: absolute;
+    width: 1px;
+    height: 1px;
+    margin: -1px;
+    padding: 0;
+    overflow: hidden;
+    clip: rect(0 0 0 0);
+    white-space: nowrap;
+    border: 0;
+}
+
 .download-next__quick-label {
     @include type.mono-text(12.5px, 700, 1.2, 0.12em, uppercase);
     color: var(--dl-text-muted);
@@ -285,28 +366,26 @@
     opacity: 0.45;
 }
 
+// The resolved file: a single quiet surface. The filename is the only strong
+// element on it; nothing inside carries a frame of its own.
 .download-next__file {
-    @include type.mono-text(14px, 500, 1.5, 0);
-    color: var(--ifm-color-primary);
-    padding: 10px 14px;
+    width: 100%;
+    min-width: 0;
+    padding: 13px 18px 12px;
     background: var(--dl-bg-soft);
-    border: 1px dashed rgb(var(--brand-primary-rgb) / 45%);
+    border: 1px solid var(--dl-border);
     border-radius: 6px;
-    width: 100%;
-    word-break: break-word;
-
-    a {
-        color: var(--ifm-color-primary);
-
-        &:hover {
-            text-decoration: underline;
-        }
-    }
 }
 
 .download-next__file-name {
     display: block;
-    font-weight: 600;
+    // Reset Infima's inline-code chrome so the name does not sit in a second 
box.
+    padding: 0;
+    border: 0;
+    border-radius: 0;
+    background: none;
+    @include type.mono-text(15px, 600, 1.4, 0);
+    color: var(--dl-ink);
     word-break: break-all;
 }
 
@@ -757,6 +836,15 @@
         gap: 14px;
     }
 
+    .download-next__actions {
+        display: flex;
+        width: 100%;
+    }
+
+    .download-next__download-btn {
+        flex: 1;
+    }
+
     .download-next__quick-label {
         margin-bottom: 0;
     }
@@ -835,8 +923,11 @@
     }
 
     .download-next__file {
-        font-size: 13px;
-        padding: 12px 14px;
+        padding: 12px 14px 11px;
+    }
+
+    .download-next__file-name {
+        font-size: 13.5px;
     }
 
     .download-next__file-meta {


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to