Repository navigation
Unify attachment cards with neutral icon tiles #1548
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -58,60 +58,40 @@ | |
| display: flex; | ||
| align-items: center; | ||
| box-sizing: border-box; | ||
| gap: calc(var(--space-5) / 2); | ||
| gap: calc(var(--space-5) / 2 + var(--space-1)); | ||
| width: 21rem; | ||
| min-width: 0; | ||
| max-width: 100%; | ||
| padding: var(--space-2) calc(var(--space-5) / 2); | ||
| margin: var(--space-1) 0; | ||
| border: 1px solid var(--voice-card-border); | ||
| border-radius: var(--radius-container); | ||
| border-radius: var(--radius-icon-button); | ||
| background: var(--voice-card-background); | ||
| transition: | ||
| background-color 150ms var(--easing-state), | ||
| border-color 150ms var(--easing-state); | ||
| } | ||
| .cardSurface { | ||
| display: none; | ||
| } | ||
| .card[data-smooth-corners] { | ||
| isolation: isolate; | ||
| background: transparent; | ||
| border-color: transparent; | ||
| } | ||
| .card[data-smooth-corners] .cardSurface { | ||
| display: block; | ||
| position: absolute; | ||
| z-index: -1; | ||
| inset: -1px; | ||
| width: calc(100% + 2px); | ||
| height: calc(100% + 2px); | ||
| pointer-events: none; | ||
| clip-path: var(--media-corner-clip); | ||
| } | ||
| .cardSurface > path { | ||
| fill: var(--voice-card-background); | ||
| stroke: var(--voice-card-border); | ||
| stroke-width: 2px; | ||
| transition: | ||
| fill 150ms var(--easing-state), | ||
| stroke 150ms var(--easing-state); | ||
| } | ||
| .play { | ||
| display: inline-flex; | ||
| border-radius: var(--radius-icon-button); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤖 This |
||
| } | ||
| .play[data-smooth-corners] > button { | ||
| clip-path: var(--media-corner-clip); | ||
| background: color-mix( | ||
| in srgb, | ||
| var(--voice-card-background) 90%, | ||
| var(--text-standard) | ||
| ); | ||
| } | ||
| .play:has(:focus-visible) { | ||
| outline: 2px solid var(--border-focus); | ||
| outline-offset: 2px; | ||
| } | ||
| .play { | ||
| flex-shrink: 0; | ||
| width: 36px; | ||
| height: 36px; | ||
| width: calc(36px + 2 * var(--space-1h)); | ||
| height: calc(36px + 2 * var(--space-1h)); | ||
| margin-block: calc(-1 * var(--space-1h)); | ||
| margin-inline-start: calc(-1 * var(--space-2)); | ||
| margin-inline-end: calc(-1 * var(--space-1)); | ||
| border-radius: calc(var(--radius-icon-button) - var(--space-half) - 1px); | ||
| } | ||
| .content { | ||
| flex: 1; | ||
|
|
@@ -279,33 +259,13 @@ | |
| animation: none; | ||
| } | ||
| .card, | ||
| .cardSurface > path, | ||
| .details > *, | ||
| .playIcon > svg { | ||
| transition: none; | ||
| } | ||
| } | ||
|
|
||
| /* Composer drafts share the enclosing composer's circular inset geometry. */ | ||
| /* Draft and sent voice notes share the same card and inset play geometry. */ | ||
| [data-voice-draft] .card { | ||
| margin: 0; | ||
| border-radius: var(--radius-icon-button); | ||
| background: var(--voice-card-background); | ||
| border-color: var(--voice-card-border); | ||
| } | ||
| [data-voice-draft] .card .cardSurface { | ||
| display: none; | ||
| } | ||
|
|
||
| [data-voice-draft] .play { | ||
| /* Expand into the chip padding without moving the text/waveform column. */ | ||
| width: calc(36px + 2 * var(--space-1h)); | ||
| height: calc(36px + 2 * var(--space-1h)); | ||
| margin-block: calc(-1 * var(--space-1h)); | ||
| margin-inline-start: calc(-1 * var(--space-2)); | ||
| margin-inline-end: calc(-1 * var(--space-1)); | ||
| border-radius: calc(var(--radius-icon-button) - var(--space-half) - 1px); | ||
| } | ||
| [data-voice-draft] .play[data-smooth-corners] > button { | ||
| clip-path: none; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,7 @@ import { AttachmentView } from "../conversation/AttachmentView"; | |
| import { useConversationPresentation } from "../conversation/ConversationPresentation"; | ||
| import { useRef, useState } from "react"; | ||
| import { FileTypeIcon } from "./FileTypeIcon"; | ||
| import fileIconStyles from "./FileTypeIcon.module.css"; | ||
| import { IconButton } from "../../shared/design-system/ui/IconButton"; | ||
| import { | ||
| AnimatePresence, | ||
|
|
@@ -298,10 +299,10 @@ function AttachmentItem({ | |
| )} | ||
| </button> | ||
| ) : ( | ||
| <span className={styles.fileIcon}> | ||
| <span className={fileIconStyles.slot}> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤖 After this switch to |
||
| <IconButton | ||
| type="button" | ||
| variant="solid" | ||
| variant="bare" | ||
| size="compact" | ||
| style={{ width: "100%", height: "100%", borderRadius: "inherit" }} | ||
| data-draft-preview={item.id} | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,26 +1,24 @@ | ||
| .slot { | ||
| display: inline-flex; | ||
| flex-shrink: 0; | ||
| width: calc(36px + 2 * var(--space-1h)); | ||
| height: calc(36px + 2 * var(--space-1h)); | ||
| margin-block: calc(-1 * var(--space-1h)); | ||
| margin-inline-start: calc(-1 * var(--space-2)); | ||
| margin-inline-end: calc(-1 * var(--space-1)); | ||
| border-radius: calc(var(--radius-icon-button) - var(--space-half) - 1px); | ||
| } | ||
| .icon { | ||
| display: inline-grid; | ||
| place-items: center; | ||
| flex-shrink: 0; | ||
| width: calc(var(--space-8) + var(--space-1)); | ||
| height: calc(var(--space-8) + var(--space-1)); | ||
| border-radius: var(--radius-control); | ||
| background: var(--surface-panel); | ||
| width: calc(36px + 2 * var(--space-1h)); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤖 |
||
| height: calc(36px + 2 * var(--space-1h)); | ||
| border-radius: calc(var(--radius-icon-button) - var(--space-half) - 1px); | ||
| background: color-mix( | ||
| in srgb, | ||
| var(--surface-inset) 90%, | ||
| var(--text-standard) | ||
| ); | ||
| color: var(--text-standard); | ||
| } | ||
| .icon[data-kind="pdf"] { | ||
| background: var(--file-pdf-surface); | ||
| color: var(--file-pdf-ink); | ||
| } | ||
| .icon[data-kind="sheet"] { | ||
| background: var(--affordance-success); | ||
| color: var(--text-success); | ||
| } | ||
| .icon[data-kind="archive"] { | ||
| background: var(--affordance-warning); | ||
| color: var(--text-warning); | ||
| } | ||
| .icon[data-kind="code"] { | ||
| background: var(--affordance-selected); | ||
| color: var(--text-link); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -981,13 +981,15 @@ html[data-keyboard-navigation] .attachmentImage:focus-visible { | |
| text-align: start; | ||
| display: inline-flex; | ||
| align-items: center; | ||
| gap: var(--space-2); | ||
| width: 21rem; | ||
| gap: calc(var(--space-5) / 2 + var(--space-1)); | ||
| width: 18rem; | ||
| box-sizing: border-box; | ||
| min-height: calc(36px + 2 * var(--space-2) + 2px); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤖 Nit: this is the same value as |
||
| max-width: 100%; | ||
| margin-top: var(--space-2); | ||
| padding: var(--space-2) var(--space-3); | ||
| border: 1px solid var(--border); | ||
| border-radius: var(--radius-container); | ||
| padding: var(--space-2) calc(var(--space-5) / 2); | ||
| border: 1px solid var(--border-standard); | ||
| border-radius: var(--radius-icon-button); | ||
| background: var(--surface-inset); | ||
| color: var(--text-standard); | ||
| text-decoration: none; | ||
|
|
@@ -1024,7 +1026,7 @@ html[data-keyboard-navigation] .fileAttachment:focus-visible { | |
| min-width: 0; | ||
| max-width: 100%; | ||
| display: grid; | ||
| gap: var(--space-half); | ||
| gap: 0; | ||
| } | ||
| .fileAttachmentName, | ||
| .fileAttachmentMeta { | ||
|
|
@@ -1033,10 +1035,13 @@ html[data-keyboard-navigation] .fileAttachment:focus-visible { | |
| white-space: nowrap; | ||
| } | ||
| .fileAttachmentName { | ||
| font-weight: var(--type-weight-medium); | ||
| font-size: var(--text-label-sm); | ||
| font-weight: var(--text-label-sm--font-weight); | ||
| line-height: var(--text-label-sm--line-height); | ||
| letter-spacing: var(--text-label-sm--letter-spacing); | ||
| } | ||
| .fileAttachmentMeta { | ||
| color: var(--text-muted); | ||
| color: var(--text-subtle); | ||
| font-size: var(--text-caption); | ||
| line-height: var(--text-caption--line-height); | ||
| letter-spacing: var(--text-caption--letter-spacing); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| <!doctype html> | ||
| <html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width, initial-scale=1.0"/><title>Buzz · Attachment playground</title></head><body><div id="root"></div><script type="module" src="./attachment-playground/main.tsx"></script></body></html> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| # Attachment playground | ||
|
|
||
| Open `/tests/fixtures/attachment-playground.html` on the existing desktop Vite server. | ||
| No second server, account, upload, or relay session is started by the page. | ||
|
|
||
| Uses production `ComposerAttachments`, composer CSS, `MessageRow`, `AudioAttachment`, | ||
| `VoiceNoteCard`, and shared PanelHeader, FullPageSurface, Select, and Button. | ||
| Controls compare light/dark, six canonical accents, low/high contrast, | ||
| sent/received rows, wide/narrow frames, and 100%/200% text. Theme preferences | ||
| are confined to iframe documents and never saved to app preferences. | ||
|
|
||
| File groups cover all five FileTypeIcon branches plus office and unknown files, | ||
| long names, images/animations, video, audio, voice notes, media-only/mixed strips, | ||
| queued/preparing/uploading/ready/error, disabled removal, and missing sources. | ||
| Upload states are simulated; retry resolves locally and reset restores samples. | ||
| Audio uses a generated two-second tone. Sent audio players are mounted directly | ||
| because MessageRow requires a native/broker media source for inline audio. | ||
| The animated WebP fixture currently exercises decoder fallback in the in-app | ||
| browser. File links are illustrative; normal activation in message rows is intercepted. | ||
| Composer review uses production behavior and can offer the illustrative external URL. | ||
|
|
||
| Check fixture types with: | ||
|
|
||
| ```sh | ||
| bin/pnpm exec tsc --project tests/fixtures/attachment-playground/tsconfig.json --noEmit | ||
| bin/pnpm exec biome check tests/fixtures/attachment-playground tests/fixtures/attachment-playground.html | ||
| ``` | ||
|
|
||
| Initial manual checks: light/dark rendering, section selection with keyboard, | ||
| retry recovery, removal, narrow frames at 200% text, and all-accent frame inventory. | ||
| This fixture does not validate uploads, native IPC, persistence, or full app integration. | ||
| Current iteration: monochrome file glyphs sit in neutral 90/10 inset tiles in both | ||
| composer and sent-file cards. Sent cards share composer sizing, type, and shape; | ||
| voice-note play tiles use the same geometry in drafts and messages. Composer | ||
| previews use the shared bare IconButton variant. | ||
| Checked this iteration: light/dark composer and sent-file rendering, sent voice-note | ||
| keyboard playback, fixture typecheck, formatting, and 37 focused component tests. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤖 This looks right, but it is unrelated to attachments and affects every branch's native job. A separate small PR would let other PRs get the fix now and give it its own revert point when actions/runner-images#14594 is closed.