new UI and handle cashing
This commit is contained in:
@@ -24,6 +24,14 @@ export function useTowDecimal(num: string | number): string | number {
|
|||||||
return formatGroupedPrice(Math.round(+num * 100) / 100, false)
|
return formatGroupedPrice(Math.round(+num * 100) / 100, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function formatSignedPercentChange(value: number): string {
|
||||||
|
if (!value) return '0%'
|
||||||
|
|
||||||
|
const formatted = useTowDecimal(Math.abs(value))
|
||||||
|
const prefix = value > 0 ? '+' : '-'
|
||||||
|
return `${prefix}${formatted}%`
|
||||||
|
}
|
||||||
|
|
||||||
export function useFormat(num: string | number, unit = '') {
|
export function useFormat(num: string | number, unit = '') {
|
||||||
return usePrice(Math.abs(+useTowDecimal(num)), true, unit)
|
return usePrice(Math.abs(+useTowDecimal(num)), true, unit)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,23 +4,22 @@
|
|||||||
<div class="w-full items-center flex justify-center">
|
<div class="w-full items-center flex justify-center">
|
||||||
<div v-if="price" class="flex gap-1 text-xs items-center">
|
<div v-if="price" class="flex gap-1 text-xs items-center">
|
||||||
<div
|
<div
|
||||||
v-if="percentPriceChanged() !== 0"
|
v-if="percentChange !== 0"
|
||||||
class="flex flex-row-reverse rounded-lg justify-between items-center gap-2 px-3"
|
class="price-change-badge"
|
||||||
:class="percentPriceChanged() >= 0 ? 'bg-green-100 text-green-600' : 'bg-red-100 text-red-600'"
|
:class="percentChange > 0 ? 'price-change-badge--up' : 'price-change-badge--down'"
|
||||||
>
|
>
|
||||||
<div dir="ltr">{{ useTowDecimal(percentPriceChanged()) }}%</div>
|
<Icon
|
||||||
<div>
|
:key="displayGoldVal"
|
||||||
<Icon
|
:size="15"
|
||||||
:size="15"
|
:icon="percentChange > 0 ? 'vuesax-linear:send' : 'vuesax-linear:received'"
|
||||||
:icon="percentPriceChanged() < 0 ? 'vuesax-linear:received' : 'vuesax-linear:send'"
|
:color="percentChange > 0 ? 'green-600' : 'red-600'"
|
||||||
:color="percentPriceChanged() < 0 ? 'red-600' : 'green-600'"
|
/>
|
||||||
/>
|
<span class="price-change-badge__value">{{ formatSignedPercentChange(percentChange) }}</span>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<Vue3Odometer
|
<Vue3Odometer
|
||||||
:value="displayGoldVal"
|
:value="displayGoldVal"
|
||||||
class="o-text !text-xl font-bold"
|
class="o-text !text-xl font-bold"
|
||||||
style="font-family: iran-sans; direction: ltr"
|
style="font-family: iran-sans; direction: ltr"
|
||||||
/>
|
/>
|
||||||
ریال
|
ریال
|
||||||
</div>
|
</div>
|
||||||
@@ -29,33 +28,55 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue'
|
||||||
import Icon from '@/components/BasicPacks/BasicIcon.vue'
|
import Icon from '@/components/BasicPacks/BasicIcon.vue'
|
||||||
import { useConfigStore } from '@/store/configStore'
|
import { useConfigStore } from '@/store/configStore'
|
||||||
import { getTradeBuyPrice, lastPrice, percentPriceChanged, price } from '@/utils/price'
|
import { getTradeBuyPrice, lastPrice, percentPriceChanged, price } from '@/utils/price'
|
||||||
import Vue3Odometer from 'vue3-odometer'
|
import Vue3Odometer from 'vue3-odometer'
|
||||||
import 'odometer/themes/odometer-theme-default.css'
|
import 'odometer/themes/odometer-theme-default.css'
|
||||||
import {useTowDecimal} from "../../../../utils/usePrice";
|
import { formatSignedPercentChange } from '@/utils/usePrice'
|
||||||
import {computed} from "vue";
|
|
||||||
|
|
||||||
|
|
||||||
const config = useConfigStore()
|
const config = useConfigStore()
|
||||||
|
|
||||||
// محاسبه درصد تغییرات به صورت reactive
|
|
||||||
const percentChange = computed(() => {
|
const percentChange = computed(() => {
|
||||||
if (!getTradeBuyPrice(lastPrice.value)) return 0
|
if (!getTradeBuyPrice(lastPrice.value)) return 0
|
||||||
return percentPriceChanged()
|
return percentPriceChanged()
|
||||||
})
|
})
|
||||||
|
|
||||||
// بررسی بسته بودن بازار
|
|
||||||
const isMarketClosed = computed(() => {
|
const isMarketClosed = computed(() => {
|
||||||
return lastPrice?.value?.goldir === 0 && getTradeBuyPrice(lastPrice.value) === 0
|
return lastPrice?.value?.goldir === 0 && getTradeBuyPrice(lastPrice.value) === 0
|
||||||
})
|
})
|
||||||
|
|
||||||
// مقدار نمایشی برای ادومتر (با مدیریت خطا)
|
|
||||||
const displayGoldVal = computed(() => {
|
const displayGoldVal = computed(() => {
|
||||||
if (isMarketClosed.value) return 0
|
if (isMarketClosed.value) return 0
|
||||||
return getTradeBuyPrice(lastPrice.value)
|
return getTradeBuyPrice(lastPrice.value)
|
||||||
})
|
})
|
||||||
|
|
||||||
// انیمیشن fade-in
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.price-change-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.35rem;
|
||||||
|
padding: 0.2rem 0.65rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.price-change-badge--up {
|
||||||
|
background: #dcfce7;
|
||||||
|
color: #16a34a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.price-change-badge--down {
|
||||||
|
background: #fee2e2;
|
||||||
|
color: #dc2626;
|
||||||
|
}
|
||||||
|
|
||||||
|
.price-change-badge__value {
|
||||||
|
direction: ltr;
|
||||||
|
unicode-bidi: isolate;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
letter-spacing: 0.01em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -6,9 +6,13 @@
|
|||||||
<span
|
<span
|
||||||
v-if="percentChange !== 0"
|
v-if="percentChange !== 0"
|
||||||
class="dhome-hero-price__delta"
|
class="dhome-hero-price__delta"
|
||||||
:class="percentChange >= 0 ? 'dhome-hero-price__delta--up' : 'dhome-hero-price__delta--down'"
|
:class="percentChange > 0 ? 'dhome-hero-price__delta--up' : 'dhome-hero-price__delta--down'"
|
||||||
>
|
>
|
||||||
{{ useTowDecimal(percentChange) }}%
|
<BasicIcon
|
||||||
|
:icon="percentChange > 0 ? 'vuesax-linear:arrow-up-2' : 'vuesax-linear:arrow-down-2'"
|
||||||
|
size="14"
|
||||||
|
/>
|
||||||
|
<span class="dhome-hero-price__delta-value">{{ formatSignedPercentChange(percentChange) }}</span>
|
||||||
</span>
|
</span>
|
||||||
<Vue3Odometer
|
<Vue3Odometer
|
||||||
:value="displayGoldVal"
|
:value="displayGoldVal"
|
||||||
@@ -24,9 +28,10 @@
|
|||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import Vue3Odometer from 'vue3-odometer'
|
import Vue3Odometer from 'vue3-odometer'
|
||||||
import 'odometer/themes/odometer-theme-default.css'
|
import 'odometer/themes/odometer-theme-default.css'
|
||||||
|
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||||
import { useConfigStore } from '@/store/configStore'
|
import { useConfigStore } from '@/store/configStore'
|
||||||
import { getTradeBuyPrice, lastPrice, percentPriceChanged } from '@/utils/price'
|
import { getTradeBuyPrice, lastPrice, percentPriceChanged } from '@/utils/price'
|
||||||
import { useTowDecimal } from '@/utils/usePrice'
|
import { formatSignedPercentChange } from '@/utils/usePrice'
|
||||||
|
|
||||||
const config = useConfigStore()
|
const config = useConfigStore()
|
||||||
|
|
||||||
|
|||||||
@@ -172,11 +172,17 @@
|
|||||||
&__delta {
|
&__delta {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
direction: ltr;
|
|
||||||
|
&-value {
|
||||||
|
direction: ltr;
|
||||||
|
unicode-bidi: isolate;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
}
|
||||||
|
|
||||||
&--up {
|
&--up {
|
||||||
background: #ecfdf3;
|
background: #ecfdf3;
|
||||||
|
|||||||
Reference in New Issue
Block a user