diff --git a/shine-UI/js/pages/channel-view.js b/shine-UI/js/pages/channel-view.js index 83dc6ef1..b49895a6 100644 --- a/shine-UI/js/pages/channel-view.js +++ b/shine-UI/js/pages/channel-view.js @@ -255,6 +255,14 @@ function scrollRootBy(delta, smooth = false) { window.scrollBy({ top: delta, behavior }); } +function getUnreadAnchorViewportFraction(unreadCount = 0) { + const count = Math.max(0, Number(unreadCount || 0)); + if (count <= 1) return 0.68; + if (count <= 3) return 0.56; + if (count <= 7) return 0.48; + return 0.42; +} + function scrollElementToViewportFraction(element, fraction = 1 / 3, smooth = false) { if (!element) return false; const root = getChannelScrollRoot(); @@ -267,8 +275,12 @@ function scrollElementToViewportFraction(element, fraction = 1 / 3, smooth = fal return true; } -function scrollChannelToUnreadLine(screen, smooth = false) { - return scrollElementToViewportFraction(screen.querySelector('.channel-unread-line'), 0.42, smooth); +function scrollChannelToUnreadLine(screen, unreadCount = 0, smooth = false) { + return scrollElementToViewportFraction( + screen.querySelector('.channel-unread-line'), + getUnreadAnchorViewportFraction(unreadCount), + smooth, + ); } function createChannelReadTracker({ @@ -285,6 +297,7 @@ function createChannelReadTracker({ const safeMessagesCount = Math.max(0, Number(messagesCount || 0)); const safeInitialSeenCount = Math.max(0, Math.min(Number(initialSeenCount || 0), safeMessagesCount)); const unreadLine = unreadCount > 0 ? screen.querySelector('.channel-unread-line') : null; + const unreadAnchorFraction = getUnreadAnchorViewportFraction(unreadCount); let desiredSeenCount = safeInitialSeenCount; let persistedSeenCount = safeInitialSeenCount; @@ -344,7 +357,7 @@ function createChannelReadTracker({ const root = getChannelScrollRoot(); const viewportHeight = root?.clientHeight || window.innerHeight || document.documentElement.clientHeight || 0; - const thresholdTop = Math.max(0, Math.round(viewportHeight / 3)); + const thresholdTop = Math.max(0, Math.round(viewportHeight * unreadAnchorFraction)); let seen = safeInitialSeenCount; for (const card of cards) { const localNumber = Number(card.dataset.localNumber || 0); @@ -2208,7 +2221,7 @@ function renderBody(screen, navigate, routeKey, channelData, handlers) { const hasPendingScrollTarget = pendingScrollByRoute.has(routeKey); applyPendingScroll(screen, routeKey, channelData.isOwnChannel || channelData.isDiary || unreadCount === 0); if (!hasPendingScrollTarget && unreadCount > 0 && !channelData.isOwnChannel && !channelData.isDiary) { - window.setTimeout(() => scrollChannelToUnreadLine(screen, false), 40); + window.setTimeout(() => scrollChannelToUnreadLine(screen, unreadCount, false), 40); } const tracker = createChannelReadTracker({ diff --git a/shine-UI/styles/components.css b/shine-UI/styles/components.css index 1588c746..3b4021fd 100644 --- a/shine-UI/styles/components.css +++ b/shine-UI/styles/components.css @@ -4248,6 +4248,36 @@ textarea.input { gap: 10px; } +.channel-unread-line { + display: flex; + align-items: center; + gap: 10px; + margin: 10px 0 12px; + padding: 10px 14px; + border-radius: 999px; + border: 1px solid rgba(244, 202, 102, 0.46); + background: + linear-gradient(180deg, rgba(50, 39, 14, 0.9), rgba(22, 25, 39, 0.9)); + color: #ffe6a7; + font-size: 11px; + font-weight: 800; + letter-spacing: 0.08em; + line-height: 1; + text-transform: uppercase; + text-align: center; + justify-content: center; + box-shadow: 0 0 0 1px rgba(255, 226, 155, 0.08), 0 10px 24px rgba(6, 10, 20, 0.35); +} + +.channel-unread-line::before, +.channel-unread-line::after { + content: ''; + flex: 1 1 0; + height: 1px; + min-width: 18px; + background: linear-gradient(90deg, transparent, rgba(244, 202, 102, 0.8), transparent); +} + .channels-screen--channel .channel-feed { gap: 2px; margin-left: -7px;