From f283ebcba3b9d986629d684605590682a3e02934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Fri, 7 Aug 2026 01:35:50 +0000 Subject: [PATCH] code block copy button is always visible hover-revealed means most people never find it, and touch has no hover at all. 70% white on the dark block, brightening on hover; the pre reserves right padding so a long first line scrolls up to the button instead of under it. Co-Authored-By: Claude Opus 5 --- docs/chat-ui-walkthrough.md | 7 +++++-- src/apps/officer-web/styles/prose.css | 2 ++ .../officerdev/src/apps/Chat/components/CodeBlock.tsx | 9 +++++---- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/docs/chat-ui-walkthrough.md b/docs/chat-ui-walkthrough.md index 7db9b08b..d7ab0cb1 100644 --- a/docs/chat-ui-walkthrough.md +++ b/docs/chat-ui-walkthrough.md @@ -497,8 +497,11 @@ reasoned, not observed. Typecheck and the sidecar tests are clean. The bubble's copy button copies the _whole reply_. When the reply is prose ending in one command you're meant to run, that's the wrong unit, and you end up selecting the line by hand — the one chore a command -in a chat exists to save you. Fenced blocks now carry a button in their top-right corner. Hover-revealed -on a pointer device, always visible on touch, because there is no hover there to reveal it with. +in a chat exists to save you. Fenced blocks now carry a button in their top-right corner, **always +visible** — a control you have to discover by waving the pointer at it is one most people never find, and +on touch there is no hover to find it with at all. It sits at 70% white on the block's dark background +and brightens on hover; the block reserves right padding for it, so a long first line scrolls up to the +button rather than under it. Inline `` `code` `` deliberately gets nothing: it's short enough to select, and a button per backticked word would be noise. diff --git a/src/apps/officer-web/styles/prose.css b/src/apps/officer-web/styles/prose.css index 8b21b14c..31797bdf 100644 --- a/src/apps/officer-web/styles/prose.css +++ b/src/apps/officer-web/styles/prose.css @@ -138,6 +138,8 @@ .chat-md .chat-code pre { margin: 0; + /* Room for the copy button, so a long first line scrolls up to it rather than under it. */ + padding-right: 2.75em; } .chat-md pre { diff --git a/src/workspaces/officerdev/src/apps/Chat/components/CodeBlock.tsx b/src/workspaces/officerdev/src/apps/Chat/components/CodeBlock.tsx index 0ad5efe2..867c5049 100644 --- a/src/workspaces/officerdev/src/apps/Chat/components/CodeBlock.tsx +++ b/src/workspaces/officerdev/src/apps/Chat/components/CodeBlock.tsx @@ -33,7 +33,7 @@ export const CodeBlock = ({ children, ...props }: ComponentPropsWithoutRef<'pre' }; return ( -
+
         {children}
       
@@ -42,9 +42,10 @@ export const CodeBlock = ({ children, ...props }: ComponentPropsWithoutRef<'pre' onClick={handleCopy} title="Copy code" aria-label="Copy code" - // Hover-revealed on a pointer device, always visible on touch — there is no hover to reveal it - // with. Colours are hardcoded light-on-dark because the block behind it is #0d1117 in both themes. - className="absolute top-1.5 right-1.5 cursor-pointer rounded border border-white/15 bg-white/10 p-1 text-white/80 opacity-70 transition-opacity hover:!opacity-100 focus-visible:opacity-100 md:opacity-0 md:group-hover/code:opacity-70" + // Always visible, not hover-revealed: a control you have to discover by waving the pointer at it + // is a control most people never find, and on touch there is no hover to find it with at all. + // Colours are hardcoded light-on-dark because the block behind it is #0d1117 in both themes. + className="absolute top-1.5 right-1.5 cursor-pointer rounded border border-white/15 bg-white/10 p-1 text-white/70 transition-colors hover:border-white/30 hover:bg-white/20 hover:text-white" > {copied ? : }