frontend: switch calendar zoom to slider and add intuitive expand icons
This commit is contained in:
@@ -1909,13 +1909,6 @@ const calendarViewOptions: { value: CalendarView; label: string }[] = [
|
|||||||
{ value: "agenda", label: "Agenda" },
|
{ value: "agenda", label: "Agenda" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const calendarZoomOptions: Array<{ value: number; label: string }> = [
|
|
||||||
{ value: 1, label: "400%" },
|
|
||||||
{ value: 2, label: "250%" },
|
|
||||||
{ value: 3, label: "100%" },
|
|
||||||
{ value: 4, label: "50%" },
|
|
||||||
];
|
|
||||||
|
|
||||||
const calendarZoomLevel = computed<number>({
|
const calendarZoomLevel = computed<number>({
|
||||||
get() {
|
get() {
|
||||||
if (calendarView.value === "day") return 1;
|
if (calendarView.value === "day") return 1;
|
||||||
@@ -1941,6 +1934,13 @@ const calendarZoomLevel = computed<number>({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const calendarZoomLabel = computed(() => {
|
||||||
|
if (calendarView.value === "day") return "Day";
|
||||||
|
if (calendarView.value === "week") return "Week";
|
||||||
|
if (calendarView.value === "month" || calendarView.value === "agenda") return "Month";
|
||||||
|
return "Year";
|
||||||
|
});
|
||||||
|
|
||||||
const monthCells = computed(() => {
|
const monthCells = computed(() => {
|
||||||
const year = calendarCursor.value.getFullYear();
|
const year = calendarCursor.value.getFullYear();
|
||||||
const month = calendarCursor.value.getMonth();
|
const month = calendarCursor.value.getMonth();
|
||||||
@@ -3649,15 +3649,20 @@ async function decideFeedCard(card: FeedCard, decision: "accepted" | "rejected")
|
|||||||
|
|
||||||
<div class="justify-self-end flex items-center gap-2">
|
<div class="justify-self-end flex items-center gap-2">
|
||||||
<span class="text-[10px] uppercase tracking-wide text-base-content/60">Zoom</span>
|
<span class="text-[10px] uppercase tracking-wide text-base-content/60">Zoom</span>
|
||||||
<select v-model.number="calendarZoomLevel" class="select select-bordered select-xs w-24">
|
<div class="flex items-center gap-2 rounded-lg border border-base-300 bg-base-100 px-2 py-1">
|
||||||
<option
|
<input
|
||||||
v-for="option in calendarZoomOptions"
|
v-model.number="calendarZoomLevel"
|
||||||
:key="`calendar-zoom-${option.value}`"
|
type="range"
|
||||||
:value="option.value"
|
min="1"
|
||||||
|
max="4"
|
||||||
|
step="1"
|
||||||
|
class="range range-xs w-24 calendar-zoom-range"
|
||||||
|
aria-label="Calendar zoom level"
|
||||||
>
|
>
|
||||||
{{ option.label }}
|
<span class="min-w-[3.2rem] text-right text-[10px] font-semibold uppercase tracking-wide text-base-content/70">
|
||||||
</option>
|
{{ calendarZoomLabel }}
|
||||||
</select>
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -3711,10 +3716,14 @@ async function decideFeedCard(card: FeedCard, decision: "accepted" | "rejected")
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="calendar-hover-jump calendar-hover-jump-row"
|
class="calendar-hover-jump calendar-hover-jump-row"
|
||||||
title="Open week view"
|
title="Zoom to week"
|
||||||
|
aria-label="Zoom to week"
|
||||||
@click.stop="openWeekView(row.startKey)"
|
@click.stop="openWeekView(row.startKey)"
|
||||||
>
|
>
|
||||||
Week
|
<svg viewBox="0 0 20 20" class="h-3.5 w-3.5 fill-none stroke-current" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||||
|
<circle cx="8.5" cy="8.5" r="4.5" />
|
||||||
|
<path d="M12 12l4.2 4.2" />
|
||||||
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<div class="grid grid-cols-7 gap-1">
|
<div class="grid grid-cols-7 gap-1">
|
||||||
<button
|
<button
|
||||||
@@ -3729,13 +3738,17 @@ async function decideFeedCard(card: FeedCard, decision: "accepted" | "rejected")
|
|||||||
@click="pickDate(cell.key)"
|
@click="pickDate(cell.key)"
|
||||||
>
|
>
|
||||||
<p class="mb-1 text-xs font-semibold">{{ cell.day }}</p>
|
<p class="mb-1 text-xs font-semibold">{{ cell.day }}</p>
|
||||||
<span
|
<button
|
||||||
|
type="button"
|
||||||
class="calendar-hover-jump"
|
class="calendar-hover-jump"
|
||||||
title="Open day view"
|
title="Expand to day"
|
||||||
|
aria-label="Expand to day"
|
||||||
@click.stop="openDayView(cell.key)"
|
@click.stop="openDayView(cell.key)"
|
||||||
>
|
>
|
||||||
Day
|
<svg viewBox="0 0 20 20" class="h-3.5 w-3.5 fill-none stroke-current" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||||
</span>
|
<path d="M7 13L3 17M13 7l4-4M3 13V17h4M17 7V3h-4" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
v-for="event in monthCellEvents(cell.events)"
|
v-for="event in monthCellEvents(cell.events)"
|
||||||
:key="event.id"
|
:key="event.id"
|
||||||
@@ -3763,10 +3776,13 @@ async function decideFeedCard(card: FeedCard, decision: "accepted" | "rejected")
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="calendar-hover-jump calendar-hover-jump-week"
|
class="calendar-hover-jump calendar-hover-jump-week"
|
||||||
title="Open day view"
|
title="Expand day line"
|
||||||
|
aria-label="Expand day line"
|
||||||
@click.stop="openDayView(day.key)"
|
@click.stop="openDayView(day.key)"
|
||||||
>
|
>
|
||||||
Day
|
<svg viewBox="0 0 20 20" class="h-3.5 w-3.5 fill-none stroke-current" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||||
|
<path d="M10 3v14M6 7l4-4 4 4M6 13l4 4 4-4" />
|
||||||
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<div class="space-y-1">
|
<div class="space-y-1">
|
||||||
<button
|
<button
|
||||||
@@ -4924,16 +4940,14 @@ async function decideFeedCard(card: FeedCard, decision: "accepted" | "rejected")
|
|||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
min-width: 36px;
|
min-width: 26px;
|
||||||
height: 20px;
|
width: 26px;
|
||||||
padding: 0 8px;
|
height: 26px;
|
||||||
border-radius: 999px;
|
padding: 0;
|
||||||
|
border-radius: 8px;
|
||||||
border: 1px solid color-mix(in oklab, var(--color-primary) 35%, transparent);
|
border: 1px solid color-mix(in oklab, var(--color-primary) 35%, transparent);
|
||||||
background: color-mix(in oklab, var(--color-base-100) 86%, transparent);
|
background: color-mix(in oklab, var(--color-base-100) 86%, transparent);
|
||||||
color: color-mix(in oklab, var(--color-base-content) 78%, transparent);
|
color: color-mix(in oklab, var(--color-base-content) 78%, transparent);
|
||||||
font-size: 10px;
|
|
||||||
font-weight: 600;
|
|
||||||
letter-spacing: 0.02em;
|
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
transition: opacity 120ms ease, transform 120ms ease, background-color 120ms ease;
|
transition: opacity 120ms ease, transform 120ms ease, background-color 120ms ease;
|
||||||
@@ -4948,6 +4962,14 @@ async function decideFeedCard(card: FeedCard, decision: "accepted" | "rejected")
|
|||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.calendar-hover-jump:focus-visible {
|
||||||
|
opacity: 1;
|
||||||
|
pointer-events: auto;
|
||||||
|
transform: translateY(0);
|
||||||
|
outline: 2px solid color-mix(in oklab, var(--color-primary) 58%, transparent);
|
||||||
|
outline-offset: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
.calendar-hover-jump:hover {
|
.calendar-hover-jump:hover {
|
||||||
background: color-mix(in oklab, var(--color-primary) 12%, var(--color-base-100));
|
background: color-mix(in oklab, var(--color-primary) 12%, var(--color-base-100));
|
||||||
}
|
}
|
||||||
@@ -4956,7 +4978,11 @@ async function decideFeedCard(card: FeedCard, decision: "accepted" | "rejected")
|
|||||||
.calendar-hover-jump-row {
|
.calendar-hover-jump-row {
|
||||||
top: 8px;
|
top: 8px;
|
||||||
right: 10px;
|
right: 10px;
|
||||||
min-width: 46px;
|
}
|
||||||
|
|
||||||
|
.calendar-zoom-range {
|
||||||
|
--range-shdw: color-mix(in oklab, var(--color-primary) 72%, white 8%);
|
||||||
|
--range-bg: color-mix(in oklab, var(--color-base-300) 85%, white 10%);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 960px) {
|
@media (max-width: 960px) {
|
||||||
|
|||||||
Reference in New Issue
Block a user