102 lines
3.8 KiB
JavaScript
102 lines
3.8 KiB
JavaScript
/**
|
|
* date-header.js
|
|
* ===============
|
|
* A single date-column header cell.
|
|
* Shows weekday, day number, holiday / event icons, highlight toggle.
|
|
*/
|
|
|
|
import {
|
|
formatDateForId,
|
|
isWeekend,
|
|
weekendsAreWorkingDays,
|
|
crosshairActive,
|
|
hoveredDateStr,
|
|
highlightedDateStr,
|
|
toggleColHighlight
|
|
} from '../../services/planner-state.js';
|
|
|
|
import { getHoliday, getSpecialDay } from '../../services/data-service.js';
|
|
|
|
export default {
|
|
name: 'DateHeader',
|
|
props: {
|
|
date: { type: Date, required: true }
|
|
},
|
|
setup(props) {
|
|
const dateStr = Vue.computed(() => formatDateForId(props.date));
|
|
|
|
const rootClass = Vue.computed(() => {
|
|
const cls = ['date-header-root', 'date-header-hover-trigger'];
|
|
if (isWeekend(props.date) && !weekendsAreWorkingDays.value) cls.push('date-header-bg-weekend');
|
|
if (highlightedDateStr.value === dateStr.value) cls.push('date-header-reading-active');
|
|
if (crosshairActive.value && hoveredDateStr.value === dateStr.value) cls.push('date-header-col-hovered');
|
|
return cls.join(' ');
|
|
});
|
|
|
|
const isWkndNonWorking = Vue.computed(() => isWeekend(props.date) && !weekendsAreWorkingDays.value);
|
|
const isSat = Vue.computed(() => props.date.getDay() === 6);
|
|
|
|
const dayLabelClass = Vue.computed(() => {
|
|
if (isWkndNonWorking.value) return isSat.value ? 'date-header-text-sat' : 'date-header-text-sun';
|
|
return 'text-grey-5';
|
|
});
|
|
const dayNumClass = Vue.computed(() => {
|
|
if (isWkndNonWorking.value) return isSat.value ? 'date-header-text-sat' : 'date-header-text-sun';
|
|
return 'text-grey-9';
|
|
});
|
|
|
|
const weekdayShort = Vue.computed(() =>
|
|
props.date.toLocaleDateString('en-US', { weekday: 'short' })
|
|
);
|
|
const dayNum = Vue.computed(() => props.date.getDate());
|
|
const monthShort = Vue.computed(() =>
|
|
props.date.toLocaleDateString('en-US', { month: 'short' })
|
|
);
|
|
|
|
const holiday = Vue.computed(() => getHoliday(props.date));
|
|
const specialDay = Vue.computed(() => getSpecialDay(props.date));
|
|
const isHighlighted = Vue.computed(() => highlightedDateStr.value === dateStr.value);
|
|
|
|
const onEnter = () => { hoveredDateStr.value = dateStr.value; };
|
|
const onLeave = () => { hoveredDateStr.value = null; };
|
|
const onToggle = () => { toggleColHighlight(props.date); };
|
|
|
|
return {
|
|
rootClass, dayLabelClass, dayNumClass,
|
|
weekdayShort, dayNum, monthShort,
|
|
holiday, specialDay, isHighlighted, dateStr,
|
|
onEnter, onLeave, onToggle
|
|
};
|
|
},
|
|
template: `
|
|
<div :class="rootClass"
|
|
@mouseenter="onEnter"
|
|
@mouseleave="onLeave">
|
|
|
|
<div class="absolute-top-right q-pa-xs">
|
|
<q-icon v-if="holiday" name="celebration" size="10px" color="red-5" class="cursor-help">
|
|
<q-tooltip class="bg-red-9 text-white shadow-4 q-pa-sm">Holiday: {{ holiday }}</q-tooltip>
|
|
</q-icon>
|
|
<q-icon v-else-if="specialDay" name="bookmark" size="10px" color="indigo-4" class="cursor-help">
|
|
<q-tooltip class="bg-indigo-9 text-white shadow-4 q-pa-sm">Event: {{ specialDay }}</q-tooltip>
|
|
</q-icon>
|
|
</div>
|
|
|
|
<div class="text-[10px] uppercase text-weight-bold" :class="dayLabelClass">{{ weekdayShort }}</div>
|
|
<div class="text-subtitle2 text-weight-bold leading-none" :class="dayNumClass">{{ dayNum }}. {{ monthShort }}</div>
|
|
|
|
<q-btn round flat dense
|
|
:icon="isHighlighted ? 'visibility_off' : 'visibility'"
|
|
:color="isHighlighted ? 'amber-9' : 'grey-5'"
|
|
size="sm"
|
|
class="date-header-highlight-btn absolute-bottom-right q-ma-xs"
|
|
:class="{ 'date-header-is-active': isHighlighted }"
|
|
@click.stop="onToggle">
|
|
<q-tooltip>{{ isHighlighted ? 'Turn off column mode' : 'Highlight Column' }}</q-tooltip>
|
|
</q-btn>
|
|
|
|
<div v-if="isHighlighted" class="date-header-active-bar"></div>
|
|
</div>
|
|
`
|
|
};
|