feat(pres_mgmt): replace time_hours/time_format/datetime_format with single use_12h toggle
Three redundant store fields encoding the same AM/PM choice replaced with a single `use_12h: boolean` in PresMgmtLocState. iso_datetime_formatter gains a third param (use_12h: boolean | null = null) that auto-resolves 24h↔12h format name variants via a symmetric FORMAT_PAIRS lookup — null default leaves all ~100 existing call sites intact. Toggle surfaces in three places: Clock icon in session time chip (hidden button, same visual), event Options modal Display section, and session Options modal Display section. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,33 @@
|
|||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
|
// Format pairs: [24h base, 12h variant]. Only formats with both variants are listed.
|
||||||
|
// Formats without a counterpart (ISO, date-only, week, etc.) are intentionally omitted —
|
||||||
|
// iso_datetime_formatter passes those through unchanged regardless of use_12h.
|
||||||
|
const FORMAT_PAIRS: [string, string][] = [
|
||||||
|
['datetime_iso_no_seconds', 'datetime_iso_12_no_seconds'],
|
||||||
|
['datetime_short', 'datetime_12_short'],
|
||||||
|
['datetime_medium', 'datetime_12_medium'],
|
||||||
|
['datetime_long', 'datetime_12_long'],
|
||||||
|
['datetime_medium_sec', 'datetime_12_medium_sec'],
|
||||||
|
['time_long', 'time_12_long'],
|
||||||
|
['time_short', 'time_12_short'],
|
||||||
|
['time_short_no_leading', 'time_12_short_no_leading'],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Build lookup maps from the pairs above. Both directions are derived from the same source.
|
||||||
|
const TO_12H: Record<string, string> = Object.fromEntries(
|
||||||
|
FORMAT_PAIRS.map(([h24, h12]) => [h24, h12])
|
||||||
|
);
|
||||||
|
const TO_24H: Record<string, string> = Object.fromEntries(
|
||||||
|
FORMAT_PAIRS.map(([h24, h12]) => [h12, h24])
|
||||||
|
);
|
||||||
|
|
||||||
export const iso_datetime_formatter = function iso_datetime_formatter(
|
export const iso_datetime_formatter = function iso_datetime_formatter(
|
||||||
raw_datetime: null | string | Date = null,
|
raw_datetime: null | string | Date = null,
|
||||||
named_format: string = 'datetime_iso_no_seconds', // date_iso, datetime_iso_no_seconds
|
named_format: string = 'datetime_iso_no_seconds', // date_iso, datetime_iso_no_seconds
|
||||||
time_24_hours: boolean = false
|
// Pass true/false to resolve to the correct 12h or 24h variant automatically.
|
||||||
|
// null (default) leaves named_format unchanged — all existing call sites unaffected.
|
||||||
|
use_12h: boolean | null = null
|
||||||
) {
|
) {
|
||||||
// console.log('*** iso_datetime_formatter() ***');
|
// console.log('*** iso_datetime_formatter() ***');
|
||||||
|
|
||||||
@@ -50,6 +74,12 @@ export const iso_datetime_formatter = function iso_datetime_formatter(
|
|||||||
raw_datetime = new Date(); // Get the current datetime if one was not passed.
|
raw_datetime = new Date(); // Get the current datetime if one was not passed.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (use_12h !== null) {
|
||||||
|
named_format = use_12h
|
||||||
|
? (TO_12H[named_format] ?? named_format)
|
||||||
|
: (TO_24H[named_format] ?? named_format);
|
||||||
|
}
|
||||||
|
|
||||||
let datetime_string = null;
|
let datetime_string = null;
|
||||||
|
|
||||||
switch (named_format) {
|
switch (named_format) {
|
||||||
|
|||||||
@@ -84,9 +84,7 @@ export interface PresMgmtLocState {
|
|||||||
lock_config: boolean;
|
lock_config: boolean;
|
||||||
|
|
||||||
// --- Query / search preferences ---
|
// --- Query / search preferences ---
|
||||||
datetime_format: string;
|
use_12h: boolean;
|
||||||
time_format: string;
|
|
||||||
time_hours: 12 | 24;
|
|
||||||
qry_enabled: 'all' | 'not_enabled' | 'enabled';
|
qry_enabled: 'all' | 'not_enabled' | 'enabled';
|
||||||
qry_hidden: 'all' | 'hidden' | 'not_hidden';
|
qry_hidden: 'all' | 'hidden' | 'not_hidden';
|
||||||
qry_limit__files: number;
|
qry_limit__files: number;
|
||||||
@@ -265,9 +263,7 @@ export const pres_mgmt_loc_defaults: PresMgmtLocState = {
|
|||||||
lock_config: false,
|
lock_config: false,
|
||||||
|
|
||||||
// Query / search
|
// Query / search
|
||||||
datetime_format: 'datetime_12_long',
|
use_12h: true,
|
||||||
time_format: 'time_12_short',
|
|
||||||
time_hours: 12,
|
|
||||||
qry_enabled: 'enabled',
|
qry_enabled: 'enabled',
|
||||||
qry_hidden: 'not_hidden',
|
qry_hidden: 'not_hidden',
|
||||||
qry_limit__files: 75,
|
qry_limit__files: 75,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { goto } from '$app/navigation';
|
|||||||
import { Modal } from 'flowbite-svelte';
|
import { Modal } from 'flowbite-svelte';
|
||||||
import {
|
import {
|
||||||
Archive,
|
Archive,
|
||||||
|
Clock,
|
||||||
Info,
|
Info,
|
||||||
MapPin,
|
MapPin,
|
||||||
Plane,
|
Plane,
|
||||||
@@ -194,6 +195,25 @@ async function on_delete(method: 'delete' | 'disable') {
|
|||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onclick={() => {
|
||||||
|
pres_mgmt_loc.current.use_12h = !pres_mgmt_loc.current.use_12h;
|
||||||
|
}}
|
||||||
|
class="btn btn-sm w-full justify-between"
|
||||||
|
class:ae_btn_surface={pres_mgmt_loc.current.use_12h}
|
||||||
|
class:ae_btn_surface_outlined={!pres_mgmt_loc.current.use_12h}>
|
||||||
|
{#if pres_mgmt_loc.current.use_12h}<ToggleRight
|
||||||
|
size="1em"
|
||||||
|
class="mr-1" />{:else}<ToggleLeft
|
||||||
|
size="1em"
|
||||||
|
class="mr-1" />{/if}
|
||||||
|
<span class="grow">
|
||||||
|
<Clock size="1em" class="mr-1" />
|
||||||
|
{pres_mgmt_loc.current.use_12h ? '12-Hour Time' : '24-Hour Time'}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
<!-- <button
|
<!-- <button
|
||||||
type="button"
|
type="button"
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
|
|||||||
@@ -15,9 +15,10 @@ let {
|
|||||||
|
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { Modal } from 'flowbite-svelte';
|
import { Modal } from 'flowbite-svelte';
|
||||||
import { Info, Send, Settings, ToggleRight, X } from '@lucide/svelte';
|
import { Clock, Info, Send, Settings, ToggleLeft, ToggleRight, X } from '@lucide/svelte';
|
||||||
import { ae_loc, ae_api } from '$lib/stores/ae_stores';
|
import { ae_loc, ae_api } from '$lib/stores/ae_stores';
|
||||||
import { events_loc, events_slct } from '$lib/stores/ae_events_stores';
|
import { events_loc, events_slct } from '$lib/stores/ae_events_stores';
|
||||||
|
import { pres_mgmt_loc } from '$lib/stores/ae_events_stores__pres_mgmt.svelte';
|
||||||
import { events_func } from '$lib/ae_events/ae_events_functions';
|
import { events_func } from '$lib/ae_events/ae_events_functions';
|
||||||
|
|
||||||
import { api } from '$lib/api/api';
|
import { api } from '$lib/api/api';
|
||||||
@@ -166,6 +167,32 @@ async function toggle_hide_launcher() {
|
|||||||
{/snippet}
|
{/snippet}
|
||||||
|
|
||||||
<div class="flex flex-col gap-4 p-4">
|
<div class="flex flex-col gap-4 p-4">
|
||||||
|
<!-- Display -->
|
||||||
|
<section>
|
||||||
|
<h4
|
||||||
|
class="text-surface-500 mb-2 text-xs font-semibold tracking-wider uppercase">
|
||||||
|
Display
|
||||||
|
</h4>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onclick={() => {
|
||||||
|
pres_mgmt_loc.current.use_12h = !pres_mgmt_loc.current.use_12h;
|
||||||
|
}}
|
||||||
|
class="btn btn-sm w-full justify-between"
|
||||||
|
class:ae_btn_surface={pres_mgmt_loc.current.use_12h}
|
||||||
|
class:ae_btn_surface_outlined={!pres_mgmt_loc.current.use_12h}>
|
||||||
|
{#if pres_mgmt_loc.current.use_12h}<ToggleRight
|
||||||
|
size="1em"
|
||||||
|
class="mr-1" />{:else}<ToggleLeft
|
||||||
|
size="1em"
|
||||||
|
class="mr-1" />{/if}
|
||||||
|
<span class="grow">
|
||||||
|
<Clock size="1em" class="mr-1" />
|
||||||
|
{pres_mgmt_loc.current.use_12h ? '12-Hour Time' : '24-Hour Time'}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- Launcher Settings -->
|
<!-- Launcher Settings -->
|
||||||
{#if $ae_loc.trusted_access}
|
{#if $ae_loc.trusted_access}
|
||||||
<section>
|
<section>
|
||||||
|
|||||||
@@ -220,8 +220,8 @@ $effect(() => {
|
|||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<!-- Skeleton placeholder while LiveQuery resolves -->
|
<!-- Skeleton placeholder while LiveQuery resolves -->
|
||||||
<div class="bg-surface-200-800 h-7 w-2/3 animate-pulse rounded">
|
<!-- <div class="bg-surface-200-800 h-7 w-2/3 animate-pulse rounded">
|
||||||
</div>
|
</div> -->
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<!-- Date/Time + Room as info chips -->
|
<!-- Date/Time + Room as info chips -->
|
||||||
@@ -229,19 +229,28 @@ $effect(() => {
|
|||||||
<div class="flex flex-wrap items-center gap-2">
|
<div class="flex flex-wrap items-center gap-2">
|
||||||
<span
|
<span
|
||||||
class="bg-primary-500/10 text-primary-700 dark:text-primary-300 inline-flex items-center gap-1.5 rounded-full px-3 py-1 text-sm font-semibold transition-colors duration-200">
|
class="bg-primary-500/10 text-primary-700 dark:text-primary-300 inline-flex items-center gap-1.5 rounded-full px-3 py-1 text-sm font-semibold transition-colors duration-200">
|
||||||
<Clock size="1em" class="text-xs" />
|
<button
|
||||||
|
type="button"
|
||||||
|
onclick={() => (pres_mgmt_loc.current.use_12h = !pres_mgmt_loc.current.use_12h)}
|
||||||
|
title={pres_mgmt_loc.current.use_12h ? 'Switch to 24-hour time' : 'Switch to 12-hour time'}
|
||||||
|
class="cursor-pointer rounded focus-visible:ring-1 focus-visible:ring-current"
|
||||||
|
aria-label={pres_mgmt_loc.current.use_12h ? 'Switch to 24-hour time' : 'Switch to 12-hour time'}>
|
||||||
|
<Clock size="1em" class="text-xs" />
|
||||||
|
</button>
|
||||||
{ae_util.iso_datetime_formatter(
|
{ae_util.iso_datetime_formatter(
|
||||||
$lq__event_session_obj.start_datetime,
|
$lq__event_session_obj.start_datetime,
|
||||||
'dddd'
|
'dddd'
|
||||||
)},
|
)},
|
||||||
{ae_util.iso_datetime_formatter(
|
{ae_util.iso_datetime_formatter(
|
||||||
$lq__event_session_obj.start_datetime,
|
$lq__event_session_obj.start_datetime,
|
||||||
pres_mgmt_loc.current.datetime_format
|
'datetime_long',
|
||||||
|
pres_mgmt_loc.current.use_12h
|
||||||
)}
|
)}
|
||||||
–
|
–
|
||||||
{ae_util.iso_datetime_formatter(
|
{ae_util.iso_datetime_formatter(
|
||||||
$lq__event_session_obj.end_datetime,
|
$lq__event_session_obj.end_datetime,
|
||||||
pres_mgmt_loc.current.time_format
|
'time_short',
|
||||||
|
pres_mgmt_loc.current.use_12h
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -270,7 +279,7 @@ $effect(() => {
|
|||||||
})}>
|
})}>
|
||||||
<span class="text-xs font-semibold opacity-60">
|
<span class="text-xs font-semibold opacity-60">
|
||||||
<Clock size="0.9em" class="inline mr-1" />Start:
|
<Clock size="0.9em" class="inline mr-1" />Start:
|
||||||
{ae_util.iso_datetime_formatter($lq__event_session_obj.start_datetime, pres_mgmt_loc.current.datetime_format)}
|
{ae_util.iso_datetime_formatter($lq__event_session_obj.start_datetime, 'datetime_long', pres_mgmt_loc.current.use_12h)}
|
||||||
</span>
|
</span>
|
||||||
</Element_ae_obj_field_editor>
|
</Element_ae_obj_field_editor>
|
||||||
</div>
|
</div>
|
||||||
@@ -290,7 +299,7 @@ $effect(() => {
|
|||||||
})}>
|
})}>
|
||||||
<span class="text-xs font-semibold opacity-60">
|
<span class="text-xs font-semibold opacity-60">
|
||||||
<Clock size="0.9em" class="inline mr-1" />End:
|
<Clock size="0.9em" class="inline mr-1" />End:
|
||||||
{ae_util.iso_datetime_formatter($lq__event_session_obj.end_datetime, pres_mgmt_loc.current.datetime_format)}
|
{ae_util.iso_datetime_formatter($lq__event_session_obj.end_datetime, 'datetime_long', pres_mgmt_loc.current.use_12h)}
|
||||||
</span>
|
</span>
|
||||||
</Element_ae_obj_field_editor>
|
</Element_ae_obj_field_editor>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -171,11 +171,10 @@ import {
|
|||||||
'dddd'
|
'dddd'
|
||||||
)}
|
)}
|
||||||
@
|
@
|
||||||
<!-- , -->
|
|
||||||
<!-- {ae_util.iso_datetime_formatter(event_presentation_obj.start_datetime, pres_mgmt_loc.current.datetime_format)} -->
|
|
||||||
{ae_util.iso_datetime_formatter(
|
{ae_util.iso_datetime_formatter(
|
||||||
event_presentation_obj.start_datetime,
|
event_presentation_obj.start_datetime,
|
||||||
pres_mgmt_loc.current.time_format
|
'time_short',
|
||||||
|
pres_mgmt_loc.current.use_12h
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
@@ -247,19 +246,7 @@ import {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
if (pres_mgmt_loc.current.time_hours == 12) {
|
pres_mgmt_loc.current.use_12h = !pres_mgmt_loc.current.use_12h;
|
||||||
pres_mgmt_loc.current.time_hours = 24;
|
|
||||||
pres_mgmt_loc.current.datetime_format =
|
|
||||||
'datetime_long';
|
|
||||||
pres_mgmt_loc.current.time_format =
|
|
||||||
'time_short';
|
|
||||||
} else {
|
|
||||||
pres_mgmt_loc.current.time_hours = 12;
|
|
||||||
pres_mgmt_loc.current.datetime_format =
|
|
||||||
'datetime_12_long';
|
|
||||||
pres_mgmt_loc.current.time_format =
|
|
||||||
'time_12_short';
|
|
||||||
}
|
|
||||||
}}>
|
}}>
|
||||||
time
|
time
|
||||||
</button>
|
</button>
|
||||||
@@ -283,7 +270,8 @@ import {
|
|||||||
)}
|
)}
|
||||||
{ae_util.iso_datetime_formatter(
|
{ae_util.iso_datetime_formatter(
|
||||||
event_presentation_obj.start_datetime,
|
event_presentation_obj.start_datetime,
|
||||||
pres_mgmt_loc.current.time_format
|
'time_short',
|
||||||
|
pres_mgmt_loc.current.use_12h
|
||||||
)}
|
)}
|
||||||
</Element_ae_obj_field_editor>
|
</Element_ae_obj_field_editor>
|
||||||
-
|
-
|
||||||
@@ -301,7 +289,8 @@ import {
|
|||||||
})}>
|
})}>
|
||||||
{ae_util.iso_datetime_formatter(
|
{ae_util.iso_datetime_formatter(
|
||||||
event_presentation_obj.end_datetime,
|
event_presentation_obj.end_datetime,
|
||||||
pres_mgmt_loc.current.time_format
|
'time_short',
|
||||||
|
pres_mgmt_loc.current.use_12h
|
||||||
)}
|
)}
|
||||||
</Element_ae_obj_field_editor>
|
</Element_ae_obj_field_editor>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user