From 0fd111d16b45796086a6c1d0945dbd3de6755d8a Mon Sep 17 00:00:00 2001 From: Jesse_Chen Date: Fri, 14 Aug 2026 09:13:57 +0800 Subject: [PATCH] fix(ui): align message motion and composer button radius with DESIGN.md; tolerate unreadable staging revision state - Message entry: 300/420ms power3.out -> Standard 180ms cubic-bezier(.22,1,.36,1) (DESIGN.md section 6); update the layout contract test to the shipped values. - Composer icon button: full radius instead of 8px (DESIGN.md section 5 Button). - Staging deploy workflow: fall back to container SHA discovery when .state/deployed-revision exists but is unreadable by the deploy user (Gitea pipeline writes it as root). --- .gitea/workflows/deploy-staging.yml | 2 +- frontend/src/app/globals.css | 2 +- frontend/src/components/chat-message-row.tsx | 4 ++-- frontend/tests/session-conversation-layout.test.ts | 3 ++- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.gitea/workflows/deploy-staging.yml b/.gitea/workflows/deploy-staging.yml index 54be8627..cd5db1da 100644 --- a/.gitea/workflows/deploy-staging.yml +++ b/.gitea/workflows/deploy-staging.yml @@ -315,7 +315,7 @@ jobs: ssh "${ssh_options[@]}" "$remote" "install -d -m 700 '$incoming/.docker'" scp -i "$key_path" -P "$DEPLOY_PORT" -o BatchMode=yes -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes -o "UserKnownHostsFile=$known_hosts_path" artifacts/staging-image/controller.tar "$remote:$incoming/controller.tar" ssh "${ssh_options[@]}" "$remote" "tar -xf '$incoming/controller.tar' -C '$incoming' && rm -f -- '$incoming/controller.tar'" - previous_sha="$(ssh "${ssh_options[@]}" "$remote" "state='$DEPLOY_PATH/.state/deployed-revision'; if [ -f \"\$state\" ]; then cat \"\$state\"; else id=\$(sudo -n docker ps -aq --filter 'label=com.docker.compose.project=jyotisha-staging' --filter 'label=com.docker.compose.service=web' | head -n 1); if [ -n \"\$id\" ]; then sudo -n docker inspect --format '{{range .Config.Env}}{{println .}}{{end}}' \"\$id\" | sed -n 's/^GITHUB_SHA=//p' | head -n 1; else printf not-deployed; fi; fi")" + previous_sha="$(ssh "${ssh_options[@]}" "$remote" "state='$DEPLOY_PATH/.state/deployed-revision'; if [ -r \"\$state\" ]; then cat \"\$state\"; else id=\$(sudo -n docker ps -aq --filter 'label=com.docker.compose.project=jyotisha-staging' --filter 'label=com.docker.compose.service=web' | head -n 1); if [ -n \"\$id\" ]; then sudo -n docker inspect --format '{{range .Config.Env}}{{println .}}{{end}}' \"\$id\" | sed -n 's/^GITHUB_SHA=//p' | head -n 1; else printf not-deployed; fi; fi")" [[ "$previous_sha" == not-deployed || "$previous_sha" =~ ^[0-9a-f]{40}$ ]] || exit 1 forward_verified=false if [[ "$previous_sha" != not-deployed && "$previous_sha" != "$DEPLOY_SHA" && "$ALLOW_ROLLBACK" != true ]]; then diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css index cc9584d3..be7eb4cf 100644 --- a/frontend/src/app/globals.css +++ b/frontend/src/app/globals.css @@ -708,7 +708,7 @@ button:disabled { cursor: default; opacity: .45; } .composer { width: min(760px, 100%); display: flex; align-items: flex-end; gap: 10px; margin: 0 auto; border: 1px solid var(--color-border); transition: border-color 140ms ease-out; min-height: 60px; padding: var(--space-2) var(--space-2) var(--space-2) var(--space-4); border-color: var(--color-border-strong); border-radius: var(--radius-lg); background: var(--color-canvas); box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-border) 42%, transparent); } .composer:focus-within { border-color: var(--color-action); box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-action) 15%, transparent); } .composer textarea { min-width: 0; min-height: 44px; max-height: 128px; flex: 1; resize: none; padding: 11px 0 8px; border: 0; outline: 0; background: transparent; color: var(--color-ink); line-height: 1.5; font-size: 16px; } -.composer button { width: 44px; height: 44px; display: grid; flex: 0 0 auto; place-items: center; border: 0; color: var(--color-on-dark); cursor: pointer; transition: background-color 120ms ease-out, transform 120ms ease-out; border-radius: var(--radius-md); background: var(--color-action); } +.composer button { width: 44px; height: 44px; display: grid; flex: 0 0 auto; place-items: center; border: 0; color: var(--color-on-dark); cursor: pointer; transition: background-color 120ms ease-out, transform 120ms ease-out; border-radius: 999px; background: var(--color-action); } .composer .composer-stop { background: var(--color-action); } .composer .composer-stop:not(:disabled):hover { background: var(--color-action-hover); } .composer-footer { width: min(760px, 100%); min-height: 44px; display: flex; align-items: center; margin: var(--space-1) auto 0; } diff --git a/frontend/src/components/chat-message-row.tsx b/frontend/src/components/chat-message-row.tsx index c8a1273a..5a31fdf8 100644 --- a/frontend/src/components/chat-message-row.tsx +++ b/frontend/src/components/chat-message-row.tsx @@ -50,8 +50,8 @@ export function ChatMessageRow({ }, { autoAlpha: 1, clearProps: "opacity,transform,visibility", - duration: message.role === "user" ? 0.3 : 0.42, - ease: "power3.out", + duration: 0.18, + ease: "cubic-bezier(.22, 1, .36, 1)", y: 0, }); }); diff --git a/frontend/tests/session-conversation-layout.test.ts b/frontend/tests/session-conversation-layout.test.ts index 07ab640b..8f2ea0c3 100644 --- a/frontend/tests/session-conversation-layout.test.ts +++ b/frontend/tests/session-conversation-layout.test.ts @@ -16,7 +16,8 @@ test("aligns the session transcript and composer to one readable column", () => test("keeps message motion restrained and honors reduced-motion preferences", () => { assert.match(messageRowSource, /gsap\.matchMedia\(\)/); assert.match(messageRowSource, /prefers-reduced-motion:\s*no-preference/); - assert.match(messageRowSource, /duration:\s*message\.role === "user" \? 0\.3 : 0\.42/); + assert.match(messageRowSource, /duration:\s*0\.18/); + assert.match(messageRowSource, /ease:\s*"cubic-bezier\(\.22,\s*1,\s*\.36,\s*1\)"/); assert.match(messageRowSource, /clearProps:\s*"opacity,transform,visibility"/); });