v0.1.54 - 통계 그래프 반응형 폭 조정
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
import GuideTooltip from './GuideTooltip.vue'
|
||||
|
||||
defineProps({
|
||||
const props = defineProps({
|
||||
overviewCards: {
|
||||
type: Array,
|
||||
required: true,
|
||||
@@ -37,6 +37,98 @@ const emit = defineEmits(['update:range-start', 'update:range-end', 'quick-range
|
||||
|
||||
const flowScrollerRef = ref(null)
|
||||
const flowDragState = ref(null)
|
||||
const hoveredFlowRecord = ref(null)
|
||||
const flowTooltipPosition = ref({ x: 0, y: 0 })
|
||||
|
||||
const flowGapClass = computed(() => {
|
||||
if (props.weeklyRecords.length > 14) {
|
||||
return 'gap-1'
|
||||
}
|
||||
|
||||
return 'gap-3'
|
||||
})
|
||||
|
||||
const flowItemStyle = computed(() => {
|
||||
const count = props.weeklyRecords.length
|
||||
|
||||
if (count <= 0) {
|
||||
return {}
|
||||
}
|
||||
|
||||
const gap = count > 14 ? 4 : 12
|
||||
const minWidth = count <= 7 ? 76 : count <= 14 ? 46 : 18
|
||||
|
||||
if (count <= 31) {
|
||||
return {
|
||||
flex: '0 0 auto',
|
||||
width: `max(${minWidth}px, calc((100% - ${(count - 1) * gap}px) / ${count}))`,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
flex: '0 0 auto',
|
||||
width: '18px',
|
||||
}
|
||||
})
|
||||
|
||||
const flowBarWidth = computed(() => {
|
||||
if (props.weeklyRecords.length <= 7) {
|
||||
return '48px'
|
||||
}
|
||||
|
||||
if (props.weeklyRecords.length <= 14) {
|
||||
return '30px'
|
||||
}
|
||||
|
||||
return '12px'
|
||||
})
|
||||
|
||||
const shouldShowFlowTime = computed(() => props.weeklyRecords.length <= 14)
|
||||
|
||||
function shouldShowFlowLabel(index) {
|
||||
const count = props.weeklyRecords.length
|
||||
|
||||
if (count <= 14) {
|
||||
return true
|
||||
}
|
||||
|
||||
const interval = Math.ceil(count / 8)
|
||||
return index === 0 || index === count - 1 || index % interval === 0
|
||||
}
|
||||
|
||||
function updateFlowTooltipPosition(event) {
|
||||
const tooltipWidth = 176
|
||||
const tooltipHeight = 86
|
||||
const margin = 12
|
||||
const viewportWidth = window.innerWidth || tooltipWidth
|
||||
const safeX = Math.min(
|
||||
Math.max(event.clientX, margin + tooltipWidth / 2),
|
||||
viewportWidth - margin - tooltipWidth / 2,
|
||||
)
|
||||
const safeY = Math.max(event.clientY - 18, margin + tooltipHeight)
|
||||
|
||||
flowTooltipPosition.value = {
|
||||
x: safeX,
|
||||
y: safeY,
|
||||
}
|
||||
}
|
||||
|
||||
function showFlowTooltip(record, event) {
|
||||
hoveredFlowRecord.value = record
|
||||
updateFlowTooltipPosition(event)
|
||||
}
|
||||
|
||||
function moveFlowTooltip(event) {
|
||||
if (!hoveredFlowRecord.value) {
|
||||
return
|
||||
}
|
||||
|
||||
updateFlowTooltipPosition(event)
|
||||
}
|
||||
|
||||
function hideFlowTooltip() {
|
||||
hoveredFlowRecord.value = null
|
||||
}
|
||||
|
||||
function startFlowDrag(event) {
|
||||
if (!flowScrollerRef.value || event.button !== 0) {
|
||||
@@ -151,7 +243,8 @@ function stopFlowDrag(event) {
|
||||
|
||||
<div
|
||||
ref="flowScrollerRef"
|
||||
class="mt-8 flex h-[260px] select-none items-stretch gap-3 overflow-x-auto overscroll-x-contain border-b border-stone-200 pb-4 cursor-grab active:cursor-grabbing"
|
||||
class="mt-8 flex h-[268px] select-none items-stretch overflow-x-auto overscroll-x-contain border-b border-stone-200 pb-4 cursor-grab active:cursor-grabbing"
|
||||
:class="flowGapClass"
|
||||
@pointerdown="startFlowDrag"
|
||||
@pointermove="moveFlowDrag"
|
||||
@pointerup="stopFlowDrag"
|
||||
@@ -159,20 +252,31 @@ function stopFlowDrag(event) {
|
||||
@pointerleave="stopFlowDrag"
|
||||
>
|
||||
<div
|
||||
v-for="record in weeklyRecords"
|
||||
v-for="(record, index) in weeklyRecords"
|
||||
:key="record.key"
|
||||
class="flex min-w-[64px] flex-col items-center justify-end gap-3"
|
||||
class="relative flex flex-col items-center justify-end gap-3"
|
||||
:style="flowItemStyle"
|
||||
@mouseenter="showFlowTooltip(record, $event)"
|
||||
@mousemove="moveFlowTooltip"
|
||||
@mouseleave="hideFlowTooltip"
|
||||
>
|
||||
<div class="flex h-44 items-end">
|
||||
<div
|
||||
class="w-11 rounded-t-full bg-stone-900/90 transition-all"
|
||||
:style="{ height: `${record.barHeight}%` }"
|
||||
class="rounded-t-full bg-stone-900/90 transition-all"
|
||||
:style="{ width: flowBarWidth, height: `${record.barHeight}%` }"
|
||||
/>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<p class="select-none text-[11px] font-bold tracking-[0.12em] text-stone-500">{{ record.dateLabel }}</p>
|
||||
<p class="mt-1 select-none text-[10px] font-bold tracking-[0.12em] text-stone-400">{{ record.weekday }}</p>
|
||||
<p class="mt-1 select-none text-[11px] font-semibold text-stone-800">{{ record.focusedTime }}</p>
|
||||
<div class="h-14 text-center">
|
||||
<template v-if="shouldShowFlowLabel(index)">
|
||||
<p class="select-none text-[11px] font-bold tracking-[0.12em] text-stone-500">{{ record.dateLabel }}</p>
|
||||
<p class="mt-1 select-none text-[10px] font-bold tracking-[0.12em] text-stone-400">{{ record.weekday }}</p>
|
||||
</template>
|
||||
<p
|
||||
v-if="shouldShowFlowTime"
|
||||
class="mt-1 select-none text-[11px] font-semibold text-stone-800"
|
||||
>
|
||||
{{ record.focusedTime }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<p
|
||||
@@ -182,6 +286,21 @@ function stopFlowDrag(event) {
|
||||
선택 기간에 기록이 없습니다.
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
v-if="hoveredFlowRecord"
|
||||
class="pointer-events-none fixed z-[80] w-44 -translate-x-1/2 -translate-y-full rounded-2xl border border-stone-200 bg-white px-3 py-2 text-left shadow-[0_16px_40px_rgba(28,25,23,0.14)]"
|
||||
:style="{ left: `${flowTooltipPosition.x}px`, top: `${flowTooltipPosition.y}px` }"
|
||||
>
|
||||
<p class="text-[10px] font-bold tracking-[0.16em] text-stone-500">
|
||||
{{ hoveredFlowRecord.dateLabel }} {{ hoveredFlowRecord.weekday }}
|
||||
</p>
|
||||
<p class="mt-1 text-[11px] font-semibold text-stone-900">
|
||||
FOCUSED {{ hoveredFlowRecord.focusedTime }}
|
||||
</p>
|
||||
<p class="mt-1 text-[10px] font-semibold tracking-[0.04em] text-stone-500">
|
||||
TASKS {{ hoveredFlowRecord.completedTasks }} / {{ hoveredFlowRecord.totalTasks }}
|
||||
</p>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<div class="grid gap-6">
|
||||
|
||||
Reference in New Issue
Block a user