fix(single): align article like/favorite interaction UX with reference

The like and favorite buttons gave no in-flight feedback: the label just sat
there until the request returned, the lovestar animation never replayed on a
repeat like, duplicate clicks reported "success", and guest favorites silently
wrote a cookie instead of asking the user to sign in.

- pending state: replace the count with the reference inline spinner
  (`<i class="loading zts">`) and disable the button until the response lands
- animation: strip `action-animation` before re-adding it (forced reflow), so
  every successful like replays the reference lovestar keyframes
- duplicate: when the server reports the same state and count, skip the
  animation and surface the reference warning copy (已赞过此文章了!)
- failures: restore the original count and toast `danger`; guest-only actions
  now open the site login modal instead of dead-ending on an error
- favorite requires login server-side, matching the reference; the guest
  favourite cookie branch and its reader are removed as dead code
- unify like/favorite through one bindToggle path and keep every mirror
  button (article row + footer tabbar) in sync

Tests: new article-actions-ux suite (8 cases) drives assets/js/core/article.js
against a DOM/fetch shim — pending spinner, replay, duplicate no-op,
concurrency, rollback, guest login, mirror sync. Widget suite 828/829; the one
failure (frontend-lifecycle theme-init stub) predates this change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
kate522andClaude Opus 5 committed 2026-11-03 16:36:45 +08:00
1 parent 3c07ef7a8d
commit 93e83e1835
7 files changed
+470 -92

No files matched your search

+7
View File
@@ -6256,6 +6256,13 @@ body:has(.modal.in) .float-btn,
animation: lovestar 0.6s 0s 1 ease normal none;
}
/* 参考主题点赞/收藏的请求中状态:计数换成行内加载点,按钮仍保持普通指针。 */
.action[disabled],
.action[disabled]:hover {
cursor: pointer !important;
opacity: 0.7;
}
@-webkit-keyframes lovestar {
0% {
transform: translate3d(0, 0, 0);