feat(desktop): add promotion marquee and proxy fix

This commit is contained in:
leokun
2026-09-04 23:07:41 +08:00
parent 900364229e
commit 8fbbcd5ae9
20 changed files with 145 additions and 154 deletions
+30 -3
View File
@@ -1,4 +1,5 @@
import type { RefObject } from "react";
import { useLayoutEffect, useRef, useState, type RefObject } from "react";
import { Marquee } from "react-css-marquee";
import { Icon } from "../../shared/ui/Icon";
import { windowCloseIcon } from "../../shared/ui/icons";
import type { AdSlot } from "./types";
@@ -14,6 +15,32 @@ type AdMenuProps = {
onDismiss: (ad: AdSlot) => void;
};
type OverflowTextProps = {
children: string;
className: string;
};
function OverflowText({ children, className }: OverflowTextProps) {
const text = useRef<HTMLSpanElement>(null);
const [overflowing, setOverflowing] = useState(false);
useLayoutEffect(() => {
const element = text.current;
if (!element) return;
const update = () => setOverflowing(element.scrollWidth > element.clientWidth + 1);
update();
const observer = new ResizeObserver(update);
observer.observe(element);
if (element.parentElement) observer.observe(element.parentElement);
return () => observer.disconnect();
}, [children]);
if (!overflowing) return <span ref={text} className={className}>{children}</span>;
return <Marquee className={styles.menuMarquee} repeat loop={0} speed={4} gap={24}>
<span ref={text} className={className}>{children}</span>
</Marquee>;
}
export function AdMenu({ ads, activeAdId, dismissingAdId, readAdIds, triggerRefs, onOpen, onDismiss }: AdMenuProps) {
return <div className={styles.menuSlots} aria-label={t("推荐内容")}>
{ads.map((ad) => <div key={ad.id} className={styles.menuSlotContainer}>
@@ -34,8 +61,8 @@ export function AdMenu({ ads, activeAdId, dismissingAdId, readAdIds, triggerRefs
{!readAdIds.has(ad.id) && <span className={styles.unreadDot} aria-hidden="true" />}
<img className={styles.menuImage} src={ad.target.imageUrl} alt="" />
<span className={styles.menuCopy}>
<span className={styles.menuTitle}>{ad.target.title}</span>
<span className={styles.menuSubtitle}>{ad.target.description}</span>
<OverflowText className={styles.menuTitle}>{ad.target.title}</OverflowText>
<OverflowText className={styles.menuSubtitle}>{ad.target.description}</OverflowText>
</span>
</button>
<button
+26 -10
View File
@@ -25,18 +25,13 @@
color: inherit;
text-align: left;
background: color-mix(in srgb, var(--vscode-foreground) 4%, transparent);
border: 1px solid var(--vscode-sideBar-border);
border: 2px solid #be8d180d;
border-radius: 6px;
&:hover,
&[aria-expanded="true"] {
background: color-mix(in srgb, var(--vscode-foreground) 9%, transparent);
border-color: var(--vscode-sideBar-border);
}
&:focus-visible {
outline: 1px solid var(--vscode-focusBorder);
outline-offset: 1px;
border-color: #be8d180d;
}
}
@@ -47,7 +42,7 @@
width: 16px;
height: 16px;
padding: 0;
display: flex;
display: none;
align-items: center;
justify-content: center;
color: color-mix(in srgb, var(--vscode-descriptionForeground) 42%, transparent);
@@ -66,6 +61,10 @@
}
}
.menuSlotContainer:hover .menuDismiss {
display: flex;
}
.unreadDot {
position: absolute;
top: 5px;
@@ -93,11 +92,24 @@
.menuTitle,
.menuSubtitle {
display: block;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.menuMarquee {
min-width: 0;
overflow: hidden;
}
.menuMarquee .menuTitle,
.menuMarquee .menuSubtitle {
width: max-content;
overflow: visible;
text-overflow: clip;
}
.menuTitle {
font-size: type.$font-size-xs;
font-weight: 500;
@@ -121,9 +133,9 @@
flex-direction: column;
overflow: hidden;
color: var(--vscode-foreground);
background: var(--vscode-editorWidget-background);
background: color-mix(in srgb, var(--vscode-editorWidget-background) 92%, var(--vscode-foreground) 8%);
border-radius: 15px;
border: none;
border: 1px solid color-mix(in srgb, var(--vscode-foreground) 12%, transparent);
box-shadow: 0 24px 20px rgb(0 0 0 / 28%);
animation: ad-enter 180ms ease-out;
@@ -132,6 +144,10 @@
}
}
:global(:root[data-theme="default-light"]) .floatingAd {
background: var(--vscode-editorWidget-background);
}
.hero {
flex: 0 0 112px;
position: relative;