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]