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:
112
packages/client/ui-attachment/src/AttachmentRail.module.css
Normal file
112
packages/client/ui-attachment/src/AttachmentRail.module.css
Normal file
@@ -0,0 +1,112 @@
|
||||
/* Thumbnail geometry mirrors DeepSeek Chat's composer rail: 64px cards with a
|
||||
16px radius, remove control fully inside the card, arrows overlaid at the
|
||||
edges instead of a scrollbar. */
|
||||
|
||||
.root {
|
||||
position: relative;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.rail {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
/* Edge arrows page the overflow; the scrollbar stays hidden (both engines). */
|
||||
scrollbar-width: none;
|
||||
/* The rail scrolls on the composer's elevated input surface: bind the l2
|
||||
pair (ui-theme styles/scrollbar.css rebinding contract) so anything that
|
||||
does draw a thumb here matches the surface. */
|
||||
--dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);
|
||||
--dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2);
|
||||
}
|
||||
|
||||
.rail::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.item {
|
||||
position: relative;
|
||||
flex: 0 0 64px;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
.thumbnail {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--dsw-alias-border-l2-darkmode-thin);
|
||||
border-radius: 16px;
|
||||
background: var(--dsw-alias-interactive-bg-hover);
|
||||
cursor: zoom-in;
|
||||
}
|
||||
|
||||
.thumbnail img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.remove {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 4px;
|
||||
z-index: 1;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
padding: 0;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
background: var(--dsw-alias-button-contrast-fill);
|
||||
color: var(--dsw-alias-label-primary-inverted);
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.item:hover .remove,
|
||||
.remove:focus-visible {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Touch surfaces have no hover to reveal the control. */
|
||||
@media (pointer: coarse) {
|
||||
.remove {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.arrow {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
z-index: 2;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding: 0;
|
||||
border: 1px solid var(--dsw-alias-border-l2-darkmode-thin);
|
||||
border-radius: 999px;
|
||||
background: var(--dsw-specific-input-major);
|
||||
color: var(--dsw-alias-label-secondary);
|
||||
box-shadow: var(--dsw-shadow-lv2);
|
||||
cursor: pointer;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.arrow:hover {
|
||||
background: var(--dsw-alias-interactive-bg-hover-solid);
|
||||
}
|
||||
|
||||
.arrowLeft {
|
||||
left: 4px;
|
||||
}
|
||||
|
||||
.arrowRight {
|
||||
right: 4px;
|
||||
}
|
||||
Reference in New Issue
Block a user