mirror of
https://github.com/vrcx-team/VRCX.git
synced 2026-04-06 00:32:02 +02:00
feat: Add week start day setting and apply to calendars and charts
This commit is contained in:
@@ -150,7 +150,7 @@
|
||||
|
||||
const { t, locale } = useI18n();
|
||||
const { userDialog } = storeToRefs(useUserStore());
|
||||
const { isDarkMode } = storeToRefs(useAppearanceSettingsStore());
|
||||
const { isDarkMode, weekStartsOn } = storeToRefs(useAppearanceSettingsStore());
|
||||
|
||||
const chartRef = ref(null);
|
||||
const isLoading = ref(false);
|
||||
@@ -190,16 +190,10 @@
|
||||
t('dialog.user.activity.days.sat')
|
||||
]);
|
||||
|
||||
// Reorder: Mon-Sun for display (row 0=Mon at top, row 6=Sun at bottom)
|
||||
const displayDayLabels = computed(() => [
|
||||
dayLabels.value[1], // Mon
|
||||
dayLabels.value[2], // Tue
|
||||
dayLabels.value[3], // Wed
|
||||
dayLabels.value[4], // Thu
|
||||
dayLabels.value[5], // Fri
|
||||
dayLabels.value[6], // Sat
|
||||
dayLabels.value[0] // Sun
|
||||
]);
|
||||
const displayDayLabels = computed(() => {
|
||||
const start = weekStartsOn.value;
|
||||
return Array.from({ length: 7 }, (_, i) => dayLabels.value[(start + i) % 7]);
|
||||
});
|
||||
|
||||
const hourLabels = Array.from({ length: 24 }, (_, i) => `${String(i).padStart(2, '0')}:00`);
|
||||
|
||||
@@ -230,6 +224,7 @@
|
||||
|
||||
watch(() => isDarkMode.value, rebuildChart);
|
||||
watch(locale, rebuildChart);
|
||||
watch(weekStartsOn, rebuildChart);
|
||||
watch(selectedPeriod, () => {
|
||||
if (cachedTargetSessions.length > 0 && echartsInstance) {
|
||||
initChart();
|
||||
@@ -356,10 +351,11 @@
|
||||
peakTimeText.value = peakTimeResult;
|
||||
|
||||
const data = [];
|
||||
const wso = weekStartsOn.value;
|
||||
for (let day = 0; day < 7; day++) {
|
||||
for (let hour = 0; hour < 24; hour++) {
|
||||
const count = grid[day][hour];
|
||||
const displayDay = day === 0 ? 6 : day - 1;
|
||||
const displayDay = (day - wso + 7) % 7;
|
||||
data.push([hour, displayDay, count]);
|
||||
}
|
||||
}
|
||||
@@ -685,10 +681,11 @@
|
||||
if (!overlapEchartsInstance) return;
|
||||
|
||||
const data = [];
|
||||
const wso = weekStartsOn.value;
|
||||
for (let day = 0; day < 7; day++) {
|
||||
for (let hour = 0; hour < 24; hour++) {
|
||||
const count = result.grid[day][hour];
|
||||
const displayDay = day === 0 ? 6 : day - 1;
|
||||
const displayDay = (day - wso + 7) % 7;
|
||||
data.push([hour, displayDay, count]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,15 @@
|
||||
"h": "h",
|
||||
"m": "m",
|
||||
"s": "s"
|
||||
},
|
||||
"days": {
|
||||
"sunday": "Sunday",
|
||||
"monday": "Monday",
|
||||
"tuesday": "Tuesday",
|
||||
"wednesday": "Wednesday",
|
||||
"thursday": "Thursday",
|
||||
"friday": "Friday",
|
||||
"saturday": "Saturday"
|
||||
}
|
||||
},
|
||||
"nav_tooltip": {
|
||||
@@ -874,7 +883,9 @@
|
||||
"time_format": "Time Format",
|
||||
"time_format_24": "24 Hour",
|
||||
"time_format_12": "12 Hour",
|
||||
"force_iso_date_format": "Force ISO Date Format"
|
||||
"force_iso_date_format": "Force ISO Date Format",
|
||||
"week_starts_on": "Week Starts On",
|
||||
"week_starts_on_description": "Choose the first day of the week. Affects calendars, charts, and activity views."
|
||||
},
|
||||
"theme_color": {
|
||||
"header": "Theme Color",
|
||||
|
||||
@@ -70,6 +70,7 @@ export const useAppearanceSettingsStore = defineStore(
|
||||
const tablePageSizes = ref([...DEFAULT_TABLE_PAGE_SIZES]);
|
||||
const dtHour12 = ref(false);
|
||||
const dtIsoFormat = ref(false);
|
||||
const weekStartsOn = ref(1);
|
||||
const sidebarSortMethod1 = ref('Sort Private to Bottom');
|
||||
const sidebarSortMethod2 = ref('Sort by Time in Instance');
|
||||
const sidebarSortMethod3 = ref('Sort by Last Active');
|
||||
@@ -159,6 +160,7 @@ export const useAppearanceSettingsStore = defineStore(
|
||||
tablePageSizesConfig,
|
||||
dtHour12Config,
|
||||
dtIsoFormatConfig,
|
||||
weekStartsOnConfig,
|
||||
sidebarSortMethodsConfig,
|
||||
navWidthConfig,
|
||||
isSidebarGroupByInstanceConfig,
|
||||
@@ -209,6 +211,7 @@ export const useAppearanceSettingsStore = defineStore(
|
||||
),
|
||||
configRepository.getBool('VRCX_dtHour12', false),
|
||||
configRepository.getBool('VRCX_dtIsoFormat', false),
|
||||
configRepository.getInt('VRCX_weekStartsOn', 1),
|
||||
configRepository.getString(
|
||||
'VRCX_sidebarSortMethods',
|
||||
JSON.stringify([
|
||||
@@ -250,7 +253,10 @@ export const useAppearanceSettingsStore = defineStore(
|
||||
configRepository.getBool('VRCX_navIsCollapsed', false),
|
||||
configRepository.getBool('VRCX_dataTableStriped', false),
|
||||
configRepository.getBool('VRCX_showPointerOnHover', false),
|
||||
configRepository.getBool('VRCX_accessibleStatusIndicators', false),
|
||||
configRepository.getBool(
|
||||
'VRCX_accessibleStatusIndicators',
|
||||
false
|
||||
),
|
||||
configRepository.getBool('VRCX_useOfficialStatusColors', true),
|
||||
configRepository.getBool('VRCX_showNewDashboardButton', true),
|
||||
configRepository.getString(
|
||||
@@ -317,6 +323,9 @@ export const useAppearanceSettingsStore = defineStore(
|
||||
|
||||
dtHour12.value = dtHour12Config;
|
||||
dtIsoFormat.value = dtIsoFormatConfig;
|
||||
weekStartsOn.value = [0, 1, 6].includes(weekStartsOnConfig)
|
||||
? weekStartsOnConfig
|
||||
: 1;
|
||||
|
||||
currentCulture.value = await AppApi.CurrentCulture();
|
||||
|
||||
@@ -724,6 +733,14 @@ export const useAppearanceSettingsStore = defineStore(
|
||||
dtIsoFormat.value = !dtIsoFormat.value;
|
||||
configRepository.setBool('VRCX_dtIsoFormat', dtIsoFormat.value);
|
||||
}
|
||||
/**
|
||||
* @param {number} value - 0 (Sunday), 1 (Monday), or 6 (Saturday)
|
||||
*/
|
||||
function setWeekStartsOn(value) {
|
||||
const v = [0, 1, 6].includes(value) ? value : 1;
|
||||
weekStartsOn.value = v;
|
||||
configRepository.setInt('VRCX_weekStartsOn', v);
|
||||
}
|
||||
/**
|
||||
* @param {string} method
|
||||
*/
|
||||
@@ -962,7 +979,8 @@ export const useAppearanceSettingsStore = defineStore(
|
||||
*
|
||||
*/
|
||||
function toggleAccessibleStatusIndicators() {
|
||||
accessibleStatusIndicators.value = !accessibleStatusIndicators.value;
|
||||
accessibleStatusIndicators.value =
|
||||
!accessibleStatusIndicators.value;
|
||||
configRepository.setBool(
|
||||
'VRCX_accessibleStatusIndicators',
|
||||
accessibleStatusIndicators.value
|
||||
@@ -1216,6 +1234,7 @@ export const useAppearanceSettingsStore = defineStore(
|
||||
tablePageSizes,
|
||||
dtHour12,
|
||||
dtIsoFormat,
|
||||
weekStartsOn,
|
||||
sidebarSortMethod1,
|
||||
sidebarSortMethod2,
|
||||
sidebarSortMethod3,
|
||||
@@ -1259,6 +1278,7 @@ export const useAppearanceSettingsStore = defineStore(
|
||||
setTablePageSizes,
|
||||
setDtHour12,
|
||||
setDtIsoFormat,
|
||||
setWeekStartsOn,
|
||||
setSidebarSortMethod1,
|
||||
setSidebarSortMethod2,
|
||||
setSidebarSortMethod3,
|
||||
|
||||
@@ -131,6 +131,7 @@
|
||||
:default-placeholder="defaultCalendarPlaceholder"
|
||||
:is-date-disabled="isCalendarDateDisabled"
|
||||
:prevent-deselect="true"
|
||||
:week-starts-on="weekStartsOn"
|
||||
initial-focus
|
||||
@update:modelValue="handleCalendarModelUpdate" />
|
||||
</PopoverContent>
|
||||
@@ -216,7 +217,7 @@
|
||||
const { friends, allFavoriteFriendIds } = storeToRefs(friendStore);
|
||||
const { currentUser } = storeToRefs(useUserStore());
|
||||
const { t } = useI18n();
|
||||
const { isDarkMode, dtHour12 } = storeToRefs(appearanceSettingsStore);
|
||||
const { isDarkMode, dtHour12, weekStartsOn } = storeToRefs(appearanceSettingsStore);
|
||||
|
||||
const instanceActivityRef = ref(null);
|
||||
|
||||
@@ -596,15 +597,15 @@
|
||||
const location = parseLocation(instanceData.location);
|
||||
|
||||
return `
|
||||
<div style="display: flex; align-items: center;">
|
||||
<div style="width: 10px; height: 55px; background-color: ${color}; margin-right: 6px;"></div>
|
||||
<div>
|
||||
<div>${name} #${location.instanceName} ${location.accessTypeName}</div>
|
||||
<div>${formattedJoinDateTime} - ${formattedLeftDateTime}</div>
|
||||
<div>${timeString}</div>
|
||||
<div style="display: flex; align-items: center;">
|
||||
<div style="width: 10px; height: 55px; background-color: ${color}; margin-right: 6px;"></div>
|
||||
<div>
|
||||
<div>${name} #${location.instanceName} ${location.accessTypeName}</div>
|
||||
<div>${formattedJoinDateTime} - ${formattedLeftDateTime}</div>
|
||||
<div>${timeString}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
`;
|
||||
};
|
||||
|
||||
const format = dtHour12.value ? 'hh:mm A' : 'HH:mm';
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
v-model="dateRange"
|
||||
:locale="locale"
|
||||
:max-value="todayDate"
|
||||
:number-of-months="2" />
|
||||
:number-of-months="2"
|
||||
:week-starts-on="weekStartsOn" />
|
||||
<div class="flex justify-end gap-2 mt-3">
|
||||
<Button variant="outline" size="sm" @click="clearDateFilter">
|
||||
{{ t('common.actions.clear') }}
|
||||
@@ -109,6 +110,7 @@
|
||||
const { feedTable, feedTableData } = storeToRefs(useFeedStore());
|
||||
const { feedTableLookup } = useFeedStore();
|
||||
const appearanceSettingsStore = useAppearanceSettingsStore();
|
||||
const { weekStartsOn } = storeToRefs(appearanceSettingsStore);
|
||||
const vrcxStore = useVrcxStore();
|
||||
|
||||
const { t, locale } = useI18n();
|
||||
|
||||
@@ -119,11 +119,10 @@
|
||||
" />
|
||||
</SettingsItem>
|
||||
|
||||
<SettingsItem :label="t('view.settings.appearance.appearance.age_gated_instances')"
|
||||
<SettingsItem
|
||||
:label="t('view.settings.appearance.appearance.age_gated_instances')"
|
||||
:description="t('view.settings.appearance.appearance.age_gated_instances_description')">
|
||||
<Switch
|
||||
:model-value="isAgeGatedInstancesVisible"
|
||||
@update:modelValue="setIsAgeGatedInstancesVisible" />
|
||||
<Switch :model-value="isAgeGatedInstancesVisible" @update:modelValue="setIsAgeGatedInstancesVisible" />
|
||||
</SettingsItem>
|
||||
|
||||
<SettingsItem :label="t('view.settings.appearance.appearance.striped_data_table_mode')">
|
||||
@@ -137,7 +136,9 @@
|
||||
<SettingsItem
|
||||
:label="t('view.settings.appearance.appearance.accessible_status_indicators')"
|
||||
:description="t('view.settings.appearance.appearance.accessible_status_indicators_description')">
|
||||
<Switch :model-value="accessibleStatusIndicators" @update:modelValue="toggleAccessibleStatusIndicators" />
|
||||
<Switch
|
||||
:model-value="accessibleStatusIndicators"
|
||||
@update:modelValue="toggleAccessibleStatusIndicators" />
|
||||
</SettingsItem>
|
||||
|
||||
<SettingsItem
|
||||
@@ -275,6 +276,21 @@
|
||||
<SettingsItem :label="t('view.settings.appearance.timedate.force_iso_date_format')">
|
||||
<Switch :model-value="dtIsoFormat" @update:modelValue="setDtIsoFormat" />
|
||||
</SettingsItem>
|
||||
|
||||
<SettingsItem
|
||||
:label="t('view.settings.appearance.timedate.week_starts_on')"
|
||||
:description="t('view.settings.appearance.timedate.week_starts_on_description')">
|
||||
<Select :model-value="String(weekStartsOn)" @update:modelValue="handleWeekStartsOnChange">
|
||||
<SelectTrigger size="sm">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="1">{{ t('common.days.monday') }}</SelectItem>
|
||||
<SelectItem value="0">{{ t('common.days.sunday') }}</SelectItem>
|
||||
<SelectItem value="6">{{ t('common.days.saturday') }}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</SettingsItem>
|
||||
</SettingsGroup>
|
||||
|
||||
<SettingsGroup :title="t('view.settings.appearance.user_dialog.header')">
|
||||
@@ -395,6 +411,7 @@
|
||||
instanceUsersSortAlphabetical,
|
||||
dtHour12,
|
||||
dtIsoFormat,
|
||||
weekStartsOn,
|
||||
hideUserNotes,
|
||||
hideUserMemos,
|
||||
hideUnfriends,
|
||||
@@ -419,6 +436,7 @@
|
||||
setInstanceUsersSortAlphabetical,
|
||||
setDtHour12,
|
||||
setDtIsoFormat,
|
||||
setWeekStartsOn,
|
||||
setHideUserNotes,
|
||||
setHideUserMemos,
|
||||
setHideUnfriends,
|
||||
@@ -437,8 +455,6 @@
|
||||
setAppCjkFontPack
|
||||
} = appearanceSettingsStore;
|
||||
|
||||
|
||||
|
||||
const trustColorEntries = [
|
||||
{
|
||||
key: 'untrusted',
|
||||
@@ -597,6 +613,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
function handleWeekStartsOnChange(value) {
|
||||
setWeekStartsOn(Number(value));
|
||||
}
|
||||
|
||||
const tablePageSizesModel = computed({
|
||||
get: () => tablePageSizes.value.map(String),
|
||||
set: (values) => {
|
||||
|
||||
@@ -16,9 +16,12 @@
|
||||
import { fromDate, getLocalTimeZone } from '@internationalized/date';
|
||||
import { CalendarRoot } from 'reka-ui';
|
||||
import { toDate } from 'reka-ui/date';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import { useAppearanceSettingsStore } from '../../../stores';
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Date,
|
||||
@@ -40,6 +43,7 @@
|
||||
|
||||
const emit = defineEmits(['update:modelValue']);
|
||||
|
||||
const { weekStartsOn } = storeToRefs(useAppearanceSettingsStore());
|
||||
const timeZone = getLocalTimeZone();
|
||||
|
||||
const internalValue = ref(fromDate(props.modelValue ?? new Date(), timeZone));
|
||||
@@ -123,6 +127,7 @@
|
||||
:placeholder="placeholder"
|
||||
@update:placeholder="onUpdatePlaceholder"
|
||||
:prevent-deselect="true"
|
||||
:week-starts-on="weekStartsOn"
|
||||
class="p-4">
|
||||
<CalendarHeader class="pt-0">
|
||||
<nav class="flex items-center gap-1 absolute top-0 inset-x-0 justify-between">
|
||||
|
||||
Reference in New Issue
Block a user