better theme for tv

This commit is contained in:
2026-09-10 19:46:35 +03:30
parent d4e3a99e61
commit 0da9f68353
7 changed files with 80 additions and 32 deletions
+1
View File
@@ -86,6 +86,7 @@ import {
productsFirstItems,
productsItems,
productsPageLoading,
productsTypeItems,
changeProductsTab,
initProductsPageData,
onProductsPageProviderMounted,
@@ -73,6 +73,7 @@ import {
productsFirstItems,
productsItems,
productsPageLoading,
productsTypeItems,
changeProductsTab,
} from '@/views/base/products/composables/useProductsPageData'
+9 -21
View File
@@ -1,12 +1,10 @@
import { onMounted, onUnmounted, reactive } from 'vue'
const AUTO_RESUME_MS = 6000
const AUTO_PX_PER_FRAME = 0.45
const AUTO_PX_PER_FRAME = 0.55
export function useTvColAutoScroll(keys: string[]) {
const paused = reactive(Object.fromEntries(keys.map((key) => [key, false])) as Record<string, boolean>)
const listEls: Record<string, HTMLElement | null> = Object.fromEntries(keys.map((key) => [key, null]))
const resumeTimers: Record<string, ReturnType<typeof setTimeout> | undefined> = {}
let rafId = 0
function reduceMotion() {
@@ -20,20 +18,10 @@ export function useTvColAutoScroll(keys: string[]) {
function pauseColAuto(key: string) {
paused[key] = true
if (resumeTimers[key]) {
clearTimeout(resumeTimers[key])
resumeTimers[key] = undefined
}
}
function scheduleColAuto(key: string) {
if (resumeTimers[key]) {
clearTimeout(resumeTimers[key])
}
resumeTimers[key] = setTimeout(() => {
paused[key] = false
resumeTimers[key] = undefined
}, AUTO_RESUME_MS)
function resumeColAuto(key: string) {
paused[key] = false
}
function tick() {
@@ -42,11 +30,14 @@ export function useTvColAutoScroll(keys: string[]) {
if (paused[key]) continue
const el = listEls[key]
if (!el) continue
const overflow = el.scrollHeight - el.clientHeight
if (overflow <= 1) continue
const half = el.scrollHeight / 2
if (half <= el.clientHeight + 8) continue
el.scrollTop += AUTO_PX_PER_FRAME
if (el.scrollTop >= half) {
if (half > el.clientHeight && el.scrollTop >= half) {
el.scrollTop -= half
} else if (el.scrollTop >= overflow) {
el.scrollTop = 0
}
}
}
@@ -59,15 +50,12 @@ export function useTvColAutoScroll(keys: string[]) {
onUnmounted(() => {
cancelAnimationFrame(rafId)
for (const key of keys) {
if (resumeTimers[key]) clearTimeout(resumeTimers[key])
}
})
return {
pausedCols: paused,
setColListRef,
pauseColAuto,
scheduleColAuto,
resumeColAuto,
}
}
+4 -1
View File
@@ -38,7 +38,10 @@ function isParsianCoin(product: Product) {
function isBankCoin(product: Product) {
if (isParsianCoin(product)) return false
const group = (product.group_type ?? '').trim()
return group === 'سکه' || group === 'سکه بانکی' || (group.includes('سکه') && !group.includes('پارسیان'))
const title = (product.title ?? '').trim()
if (group === 'سکه' || group === 'سکه بانکی') return true
if (group.includes('سکه') && !group.includes('پارسیان')) return true
return title.includes('بانکی')
}
function bankCoinRank(product: Product) {
+22 -7
View File
@@ -90,7 +90,7 @@
:ref="(el) => setColListRef(col.key, el)"
class="tv-col__list"
@mouseenter="pauseColAuto(col.key)"
@mouseleave="scheduleColAuto(col.key)"
@mouseleave="resumeColAuto(col.key)"
>
<div
v-if="col.items.length"
@@ -251,7 +251,7 @@ const {
toggleFullscreen,
} = useTvMonitorPage()
const { setColListRef, pauseColAuto, scheduleColAuto } = useTvColAutoScroll(['parsian', 'bank'])
const { setColListRef, pauseColAuto, resumeColAuto } = useTvColAutoScroll(['parsian', 'bank'])
function prefersReducedMotion() {
return typeof window !== 'undefined'
@@ -259,12 +259,13 @@ function prefersReducedMotion() {
}
function marqueeCopies(count: number) {
return count >= 2 && !prefersReducedMotion() ? [0, 1] : [0]
return count >= 1 && !prefersReducedMotion() ? [0, 1] : [0]
}
function loopTicker(items: Product[]) {
if (!items.length) return []
return [0, 1].flatMap((copy) => items.map((product) => ({ product, copy })))
const copies = items.length >= 2 && !prefersReducedMotion() ? [0, 1] : [0]
return copies.flatMap((copy) => items.map((product) => ({ product, copy })))
}
const shamsTickerLoop = computed(() => loopTicker(tickerProducts.value))
@@ -281,7 +282,7 @@ const coinColumns = computed(() => [
},
{
key: 'bank',
title: 'سکه بانکی',
title: 'سکه',
hint: 'دسته سکه',
empty: 'سکه‌ای برای نمایش نیست',
items: bankCoins.value,
@@ -592,10 +593,20 @@ const coinColumns = computed(() => [
flex-direction: column;
overflow-x: hidden;
overflow-y: auto;
scrollbar-width: thin;
scrollbar-color: color-mix(in srgb, var(--tv-primary) 42%, transparent) transparent;
overscroll-behavior: contain;
container-type: size;
scrollbar-width: none;
&:hover {
scrollbar-width: thin;
scrollbar-color: color-mix(in srgb, var(--tv-primary) 42%, transparent) transparent;
}
&::-webkit-scrollbar {
width: 0;
}
&:hover::-webkit-scrollbar {
width: 6px;
}
@@ -611,13 +622,17 @@ const coinColumns = computed(() => [
.tv-col__track {
display: flex;
flex-shrink: 0;
flex-direction: column;
}
.tv-col__group {
display: flex;
flex-shrink: 0;
flex-direction: column;
gap: 8px;
box-sizing: border-box;
min-height: 100cqh;
padding-bottom: 8px;
}