diff --git a/src/assets/login/login-hero.jpg b/src/assets/login/login-hero.jpg new file mode 100644 index 0000000..cf75ef8 Binary files /dev/null and b/src/assets/login/login-hero.jpg differ diff --git a/src/components/market/MarketChart.vue b/src/components/market/MarketChart.vue index 4cac795..154d039 100644 --- a/src/components/market/MarketChart.vue +++ b/src/components/market/MarketChart.vue @@ -18,158 +18,51 @@ import { formatNumber } from '@/utils/storage' ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Filler, Tooltip) -const gridLinesPlugin = { - id: 'marketGridLines', - beforeDatasetsDraw(chart: Chart) { - const { ctx, chartArea, scales } = chart - if (!chartArea || !scales.y) return - - const { left, right, top, bottom } = chartArea - const yScale = scales.y - - ctx.save() - ctx.strokeStyle = 'rgba(255, 255, 255, 0.07)' - ctx.lineWidth = 1 - - yScale.ticks.forEach((tick) => { - const y = yScale.getPixelForValue(tick.value) - ctx.beginPath() - ctx.moveTo(left, y) - ctx.lineTo(right, y) - ctx.stroke() - }) - - const verticalCount = 5 - for (let i = 0; i <= verticalCount; i += 1) { - const x = left + ((right - left) / verticalCount) * i - ctx.beginPath() - ctx.moveTo(x, top) - ctx.lineTo(x, bottom) - ctx.stroke() - } - - ctx.restore() - }, -} - -ChartJS.register(gridLinesPlugin) - const marketStore = useMarketStore() -const AXIS_SCALE = 6100 - -function createLineGradient(chart: Chart) { - const { ctx, chartArea } = chart - if (!chartArea) return '#32d74b' - - const gradient = ctx.createLinearGradient(chartArea.left, 0, chartArea.right, 0) - gradient.addColorStop(0, '#22e865') - gradient.addColorStop(0.45, '#6fdc3a') - gradient.addColorStop(0.78, '#c8e630') - gradient.addColorStop(1, '#ffd55e') - return gradient -} - function createFillGradient(chart: Chart) { const { ctx, chartArea } = chart - if (!chartArea) return 'rgba(50, 215, 75, 0.15)' + if (!chartArea) return 'rgba(232, 196, 92, 0.2)' - const { left, top, right, bottom } = chartArea - const width = right - left - const height = bottom - top - - // Horizontal: green (left) → purple (right) - const horizontal = ctx.createLinearGradient(left, 0, right, 0) - horizontal.addColorStop(0, 'rgba(34, 220, 100, 0.72)') - horizontal.addColorStop(0.35, 'rgba(34, 200, 90, 0.55)') - horizontal.addColorStop(0.62, 'rgba(70, 150, 120, 0.38)') - horizontal.addColorStop(0.82, 'rgba(118, 55, 201, 0.52)') - horizontal.addColorStop(1, 'rgba(156, 80, 233, 0.62)') - - // Vertical fade: opaque under line → transparent at bottom - const vertical = ctx.createLinearGradient(0, top, 0, bottom) - vertical.addColorStop(0, 'rgba(255, 255, 255, 0.92)') - vertical.addColorStop(0.35, 'rgba(255, 255, 255, 0.45)') - vertical.addColorStop(0.7, 'rgba(255, 255, 255, 0.12)') - vertical.addColorStop(1, 'rgba(255, 255, 255, 0)') - - // Composite horizontal + vertical fade on offscreen canvas - const offscreen = document.createElement('canvas') - offscreen.width = Math.max(1, Math.round(width)) - offscreen.height = Math.max(1, Math.round(height)) - const offCtx = offscreen.getContext('2d') - if (!offCtx) return horizontal - - offCtx.fillStyle = horizontal - offCtx.fillRect(0, 0, offscreen.width, offscreen.height) - offCtx.globalCompositeOperation = 'destination-in' - offCtx.fillStyle = vertical - offCtx.fillRect(0, 0, offscreen.width, offscreen.height) - - const pattern = ctx.createPattern(offscreen, 'no-repeat') - if (!pattern) return horizontal - - // Align pattern with chart area - const matrix = new DOMMatrix().translate(left, top) - pattern.setTransform(matrix) - return pattern + const gradient = ctx.createLinearGradient(0, chartArea.top, 0, chartArea.bottom) + gradient.addColorStop(0, 'rgba(244, 214, 120, 0.55)') + gradient.addColorStop(0.55, 'rgba(118, 75, 190, 0.28)') + gradient.addColorStop(1, 'rgba(118, 75, 190, 0)') + return gradient } -function isLastPoint(context: ScriptableContext<'line'>) { - const dataset = context.dataset.data as number[] - return context.dataIndex === dataset.length - 1 -} - -function buildYAxisConfig(values: number[]) { - if (!values.length) { - return { min: 0, max: 1, ticks: [0, 0.33, 0.66, 1] } - } - +function paddedDomain(values: number[]) { + if (!values.length) return { min: 0, max: 1 } const min = Math.min(...values) const max = Math.max(...values) - const range = max - min || max * 0.02 - const padding = range * 0.025 - const yMin = min - padding - const yMax = max + padding - const step = (yMax - yMin) / 3 - - return { - min: yMin, - max: yMax, - ticks: [yMin, yMin + step, yMin + step * 2, yMax], - } + const range = max - min || max * 0.04 + const padding = range * 0.18 + return { min: min - padding, max: max + padding } } -const yAxisConfig = computed(() => buildYAxisConfig(marketStore.priceHistory)) +const yDomain = computed(() => paddedDomain(marketStore.priceHistory)) const chartData = computed(() => ({ labels: marketStore.labels, datasets: [ { data: marketStore.priceHistory, - borderColor: (context: ScriptableContext<'line'>) => - createLineGradient(context.chart), - backgroundColor: (context: ScriptableContext<'line'>) => - createFillGradient(context.chart), + borderColor: '#f4d678', + backgroundColor: (context: ScriptableContext<'line'>) => createFillGradient(context.chart), fill: true, - tension: 0.42, - pointRadius: (context: ScriptableContext<'line'>) => - isLastPoint(context) ? 3 : 0, - pointHoverRadius: (context: ScriptableContext<'line'>) => - isLastPoint(context) ? 4 : 0, - pointBackgroundColor: '#ffd55e', - pointBorderColor: '#ffd55e', - pointBorderWidth: 0, - pointHoverBackgroundColor: '#ffd55e', - pointHoverBorderColor: '#fff8dc', + tension: 0.35, + pointRadius: 0, + pointHoverRadius: 5, + pointHoverBackgroundColor: '#fff8dc', + pointHoverBorderColor: '#f4d678', pointHoverBorderWidth: 2, - borderWidth: 2, + borderWidth: 2.5, }, ], })) const chartOptions = computed(() => { - const yAxis = yAxisConfig.value + const domain = yDomain.value return { responsive: true, @@ -207,22 +100,9 @@ const chartOptions = computed(() => { border: { display: false }, }, y: { - position: 'left' as const, - display: true, - min: yAxis.min, - max: yAxis.max, - afterBuildTicks: (axis: { ticks: { value: number }[] }) => { - axis.ticks = yAxis.ticks.map((value) => ({ value })) - }, - ticks: { - color: 'rgba(174, 185, 210, 0.42)', - font: { family: 'Vazirmatn', size: 10, weight: 600 }, - padding: 2, - autoSkip: false, - maxTicksLimit: 4, - callback: (value: string | number) => - formatNumber(Math.round(Number(value) / AXIS_SCALE)), - }, + display: false, + min: domain.min, + max: domain.max, grid: { display: false }, border: { display: false }, }, @@ -239,7 +119,7 @@ const chartOptions = computed(() => {