feat(web): align attachment display with DeepSeek Chat via ui-attachment atoms
Single-click original preview in the composer rail and chat history; remove control inside the thumbnail, revealed on hover/focus (always on touch); hidden-scrollbar rail overflow paged by edge arrows with wheel panning and end-reveal on add; image-intake rejections and prompt failures announce as a transient top-center toast instead of inline strips. The attachment atoms move to a new zero-cordis package @deepseek-ai/dsh-client-ui-attachment (rail, message gallery, lightbox), seeded as a platform module; the toast is a ui-primitives atom. Strings arrive as label props bridged from the conversation dictionary.
This commit is contained in:
37
packages/client/ui-primitives/src/Toast.tsx
Normal file
37
packages/client/ui-primitives/src/Toast.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { useEffect } from 'react'
|
||||
import type { ReactNode } from 'react'
|
||||
import css from './Toast.module.css'
|
||||
|
||||
/** Full-opacity hold before the fade starts. Must agree with the stylesheet's
|
||||
* toast-fade delay (Toast.module.css) or the banner unmounts mid-fade. */
|
||||
const HOLD_MS = 3000
|
||||
/** Fade duration. Must agree with the stylesheet's toast-fade duration. */
|
||||
const FADE_MS = 1000
|
||||
|
||||
/**
|
||||
* Transient top-center banner: slides in, holds at full opacity, fades out,
|
||||
* then reports done so the owner can unmount it. Re-showing the same text
|
||||
* restarts the cycle when the owner remounts the component (key it by a
|
||||
* per-show sequence).
|
||||
*
|
||||
* @param props.text - resolved banner copy; the owner passes localized text.
|
||||
* @param props.icon - optional leading glyph (e.g. a warning icon).
|
||||
* @param props.onDone - called once the fade completes; unmount the toast here.
|
||||
* @returns the floating banner.
|
||||
*/
|
||||
export function Toast({ text, icon, onDone }: {
|
||||
text: string
|
||||
icon?: ReactNode
|
||||
onDone: () => void
|
||||
}) {
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(onDone, HOLD_MS + FADE_MS)
|
||||
return () => { clearTimeout(timer) }
|
||||
}, [onDone])
|
||||
return (
|
||||
<div className={css.toast} role="alert">
|
||||
{icon !== undefined && <span className={css.icon} aria-hidden>{icon}</span>}
|
||||
<span className={css.text}>{text}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user