mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-26 18:23:47 +02:00
replace element plus components
This commit is contained in:
@@ -42,11 +42,7 @@
|
||||
|
||||
const timeZone = getLocalTimeZone();
|
||||
|
||||
// JSDoc casts: this project can end up with nominal-type mismatches for DateValue
|
||||
// due to duplicate @internationalized/date copies in tooling.
|
||||
/** @type {import('vue').Ref<any>} */
|
||||
const internalValue = ref(fromDate(props.modelValue ?? new Date(), timeZone));
|
||||
/** @type {import('vue').Ref<any>} */
|
||||
const placeholder = ref(fromDate(props.modelValue ?? new Date(), timeZone));
|
||||
|
||||
watch(
|
||||
@@ -147,6 +143,10 @@
|
||||
:class="hasFollowingFor(weekDate) ? 'has-following' : 'no-following'">
|
||||
{{ eventCountFor(weekDate) }}
|
||||
</div>
|
||||
<!-- <div
|
||||
v-if="eventCountFor(weekDate) > 0"
|
||||
class="calendar-event-dot"
|
||||
aria-hidden="true" /> -->
|
||||
</div>
|
||||
</div>
|
||||
</CalendarCellTrigger>
|
||||
@@ -165,7 +165,6 @@
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.date {
|
||||
@@ -193,21 +192,20 @@
|
||||
|
||||
.calendar-event-badge {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
right: 2px;
|
||||
min-width: 18px;
|
||||
height: 18px;
|
||||
top: -4px;
|
||||
right: -4px;
|
||||
min-width: 14px;
|
||||
height: 14px;
|
||||
border-radius: 9px;
|
||||
color: var(--el-color-white, #fff);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
font-size: 10px;
|
||||
box-shadow: var(--el-box-shadow-lighter);
|
||||
z-index: 10;
|
||||
padding: 0 5px;
|
||||
line-height: 18px;
|
||||
line-height: 14px;
|
||||
}
|
||||
|
||||
.calendar-event-badge.has-following {
|
||||
@@ -217,4 +215,18 @@
|
||||
.calendar-event-badge.no-following {
|
||||
background-color: var(--group-calendar-badge-normal, var(--el-color-primary));
|
||||
}
|
||||
|
||||
.calendar-event-dot {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 4px;
|
||||
transform: translateX(-50%);
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 9999px;
|
||||
background-color: var(--group-calendar-event-dot, #ef4444);
|
||||
box-shadow: var(--el-box-shadow-lighter);
|
||||
z-index: 5;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<Dialog :open="visible" @update:open="(open) => (open ? null : closeDialog())">
|
||||
<DialogContent class="x-dialog w-[90vw] max-w-[90vw] sm:max-w-[70vw] h-[60vh] overflow-hidden">
|
||||
<DialogContent class="x-dialog sm:max-w-[50vw] h-[60vh] overflow-hidden">
|
||||
<DialogHeader>
|
||||
<div class="dialog-title-container">
|
||||
<DialogTitle>{{ t('dialog.group_calendar.header') }}</DialogTitle>
|
||||
@@ -18,82 +18,77 @@
|
||||
</div>
|
||||
</DialogHeader>
|
||||
<div class="top-content">
|
||||
<transition name="el-fade-in-linear" mode="out-in">
|
||||
<div v-if="viewMode === 'timeline'" key="timeline" class="timeline-view">
|
||||
<div class="timeline-container">
|
||||
<el-timeline v-if="groupedTimelineEvents.length">
|
||||
<el-timeline-item
|
||||
v-for="(timeGroup, key) of groupedTimelineEvents"
|
||||
:key="key"
|
||||
:timestamp="
|
||||
dayjs(timeGroup.startsAt).format('MM-DD ddd') + ' ' + timeGroup.startTime
|
||||
"
|
||||
placement="top">
|
||||
<div class="time-group-container">
|
||||
<GroupCalendarEventCard
|
||||
v-for="value in timeGroup.events"
|
||||
:key="value.id"
|
||||
:event="value"
|
||||
mode="timeline"
|
||||
:is-following="isEventFollowing(value.id)"
|
||||
:card-class="{ 'grouped-card': timeGroup.events.length > 1 }"
|
||||
@update-following-calendar-data="updateFollowingCalendarData"
|
||||
@click-action="showGroupDialog(value.ownerId)" />
|
||||
</div>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
<div v-else>{{ t('dialog.group_calendar.no_events') }}</div>
|
||||
</div>
|
||||
|
||||
<div class="calendar-container">
|
||||
<GroupCalendarMonth
|
||||
v-model="selectedDay"
|
||||
:is-loading="isLoading"
|
||||
:events-by-date="filteredCalendar"
|
||||
:following-by-date="followingCalendarDate" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-else key="grid" class="grid-view">
|
||||
<div class="search-container">
|
||||
<InputGroupSearch
|
||||
v-model="searchQuery"
|
||||
size="sm"
|
||||
:placeholder="t('dialog.group_calendar.search_placeholder')"
|
||||
class="search-input" />
|
||||
</div>
|
||||
|
||||
<div class="groups-grid" v-loading="isLoading">
|
||||
<div v-if="filteredGroupEvents.length" class="groups-container">
|
||||
<div v-for="group in filteredGroupEvents" :key="group.groupId" class="group-row">
|
||||
<div class="group-header" @click="toggleGroup(group.groupId)">
|
||||
<ArrowRight
|
||||
class="rotation-transition"
|
||||
:class="{ rotate: !groupCollapsed[group.groupId] }" />
|
||||
{{ group.groupName }}
|
||||
</div>
|
||||
<div class="events-row" v-show="!groupCollapsed[group.groupId]">
|
||||
<GroupCalendarEventCard
|
||||
v-for="event in group.events"
|
||||
:key="event.id"
|
||||
:event="event"
|
||||
mode="grid"
|
||||
:is-following="isEventFollowing(event.id)"
|
||||
@update-following-calendar-data="updateFollowingCalendarData"
|
||||
@click-action="showGroupDialog(event.ownerId)"
|
||||
card-class="grid-card" />
|
||||
</div>
|
||||
<div v-if="viewMode === 'timeline'" key="timeline" class="timeline-view">
|
||||
<div class="timeline-container">
|
||||
<div v-if="groupedTimelineEvents.length" class="timeline-list">
|
||||
<div v-for="(timeGroup, key) of groupedTimelineEvents" :key="key" class="timeline-group">
|
||||
<div class="timeline-timestamp">
|
||||
{{ dayjs(timeGroup.startsAt).format('MM-DD ddd') }} {{ timeGroup.startTime }}
|
||||
</div>
|
||||
<div class="time-group-container">
|
||||
<GroupCalendarEventCard
|
||||
v-for="value in timeGroup.events"
|
||||
:key="value.id"
|
||||
:event="value"
|
||||
mode="timeline"
|
||||
:is-following="isEventFollowing(value.id)"
|
||||
:card-class="{ 'grouped-card': timeGroup.events.length > 1 }"
|
||||
@update-following-calendar-data="updateFollowingCalendarData"
|
||||
@click-action="showGroupDialog(value.ownerId)" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="no-events">
|
||||
{{
|
||||
searchQuery
|
||||
? t('dialog.group_calendar.search_no_matching')
|
||||
: t('dialog.group_calendar.search_no_this_month')
|
||||
}}
|
||||
</div>
|
||||
<div v-else class="timeline-empty">{{ t('dialog.group_calendar.no_events') }}</div>
|
||||
</div>
|
||||
|
||||
<div class="calendar-container">
|
||||
<GroupCalendarMonth
|
||||
v-model="selectedDay"
|
||||
:is-loading="isLoading"
|
||||
:events-by-date="filteredCalendar"
|
||||
:following-by-date="followingCalendarDate" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-else key="grid" class="grid-view">
|
||||
<div class="search-container">
|
||||
<InputGroupSearch
|
||||
v-model="searchQuery"
|
||||
size="sm"
|
||||
:placeholder="t('dialog.group_calendar.search_placeholder')"
|
||||
class="search-input" />
|
||||
</div>
|
||||
|
||||
<div class="groups-grid" v-loading="isLoading">
|
||||
<div v-if="filteredGroupEvents.length" class="groups-container">
|
||||
<div v-for="group in filteredGroupEvents" :key="group.groupId" class="group-row">
|
||||
<div class="group-header" @click="toggleGroup(group.groupId)">
|
||||
<ArrowRight
|
||||
class="rotation-transition"
|
||||
:class="{ rotate: !groupCollapsed[group.groupId] }" />
|
||||
{{ group.groupName }}
|
||||
</div>
|
||||
<div class="events-row" v-show="!groupCollapsed[group.groupId]">
|
||||
<GroupCalendarEventCard
|
||||
v-for="event in group.events"
|
||||
:key="event.id"
|
||||
:event="event"
|
||||
mode="grid"
|
||||
:is-following="isEventFollowing(event.id)"
|
||||
@update-following-calendar-data="updateFollowingCalendarData"
|
||||
@click-action="showGroupDialog(event.ownerId)"
|
||||
card-class="grid-card" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="no-events">
|
||||
{{
|
||||
searchQuery
|
||||
? t('dialog.group_calendar.search_no_matching')
|
||||
: t('dialog.group_calendar.search_no_this_month')
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
@@ -334,7 +329,8 @@
|
||||
.sort((a, b) => dayjs(a.startsAt).diff(dayjs(b.startsAt)));
|
||||
});
|
||||
|
||||
const formatDateKey = (date) => formatDateFilter(date, 'date');
|
||||
// Use a stable key for calendar maps (independent of locale/appearance date formatting).
|
||||
const formatDateKey = (date) => dayjs(date).format('YYYY-MM-DD');
|
||||
|
||||
function getGroupNameFromCache(groupId) {
|
||||
if (!groupNamesCache.has(groupId)) {
|
||||
@@ -462,18 +458,36 @@
|
||||
overflow: hidden;
|
||||
.timeline-view {
|
||||
.timeline-container {
|
||||
:deep(.el-timeline) {
|
||||
width: 100%;
|
||||
min-width: 200px;
|
||||
padding-left: 4px;
|
||||
padding-right: 16px;
|
||||
margin-left: 10px;
|
||||
margin-right: 6px;
|
||||
overflow: auto;
|
||||
|
||||
.timeline-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.timeline-group {
|
||||
padding: 0 20px 6px 10px;
|
||||
}
|
||||
|
||||
.timeline-timestamp {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-secondary);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.timeline-empty {
|
||||
height: 100%;
|
||||
min-width: 200px;
|
||||
padding-left: 4px;
|
||||
padding-right: 16px;
|
||||
margin-left: 10px;
|
||||
margin-right: 6px;
|
||||
overflow: auto;
|
||||
.el-timeline-item {
|
||||
padding: 0 20px 20px 10px;
|
||||
}
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
.time-group-container {
|
||||
display: flex;
|
||||
@@ -571,7 +585,6 @@
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.calendar-container {
|
||||
width: 609px;
|
||||
|
||||
Reference in New Issue
Block a user