Implement generic AE_ObjectFlags and AE_MetadataFooter components

- Created AE_ObjectFlags.svelte for standardized flag management across all modules.
- Created AE_MetadataFooter.svelte for unified creation/update/original timestamp display.
- Modularized Journal Entry view by replacing manual flag and footer logic with generic elements.
- Improved code reusability and reduced main component complexity.
This commit is contained in:
Scott Idem
2026-01-08 18:08:47 -05:00
parent efe8677ab6
commit c884eed52c
3 changed files with 210 additions and 192 deletions

View File

@@ -0,0 +1,65 @@
<script lang="ts">
/**
* AE_MetadataFooter.svelte
* GENERIC Aether Metadata Display
* Reusable across all modules to standardize created/updated/original info.
*/
import { ae_util } from '$lib/ae_utils/ae_utils';
import { ae_loc } from '$lib/stores/ae_stores';
import { Clock, CalendarClock, Globe } from '@lucide/svelte';
interface Props {
obj: any;
showOriginal?: boolean;
containerClass?: string;
}
let {
obj,
showOriginal = true,
containerClass = "ae_meta flex flex-col gap-2 p-4 border-t border-surface-500/10 text-xs text-surface-500 w-full"
}: Props = $props();
</script>
<footer class={containerClass}>
<!-- Original Date/Time Info (if applicable) -->
{#if showOriginal && (obj?.original_datetime || obj?.original_timezone)}
<div class="flex flex-row flex-wrap gap-x-4 gap-y-1 items-center bg-surface-500/5 p-2 rounded">
<span class="flex items-center gap-1">
<Globe size="1.1em" class="opacity-70" />
<span class="font-bold uppercase tracking-tighter">Original:</span>
{obj?.original_datetime ? ae_util.iso_datetime_formatter(obj.original_datetime, 'datetime_iso_12_no_seconds') : '--'}
</span>
{#if obj?.original_timezone}
<span class="flex items-center gap-1">
<span class="font-bold uppercase tracking-tighter">TZ:</span>
{obj.original_timezone}
</span>
{/if}
</div>
{/if}
<!-- System Timestamps -->
<div class="flex flex-col sm:flex-row justify-between items-center gap-2 px-1">
<div class="flex flex-wrap gap-4 justify-center sm:justify-start">
<span class="flex items-center gap-1" title="Creation date">
<CalendarClock size="1.1em" class="opacity-70 text-primary-500" />
<span class="font-semibold uppercase tracking-tighter">Created:</span>
{ae_util.iso_datetime_formatter(obj?.created_on, 'datetime_iso_12_no_seconds')}
</span>
{#if obj?.updated_on}
<span class="flex items-center gap-1" title="Last update">
<Clock size="1.1em" class="opacity-70 text-secondary-500" />
<span class="font-semibold uppercase tracking-tighter">Updated:</span>
{ae_util.iso_datetime_formatter(obj.updated_on, 'datetime_iso_12_no_seconds')}
</span>
{/if}
</div>
{#if obj?.journal_entry_type || obj?.type}
<span class="badge variant-soft-surface text-[10px] uppercase font-bold tracking-widest">
Type: {obj?.journal_entry_type || obj?.type}
</span>
{/if}
</div>
</footer>

View File

@@ -0,0 +1,131 @@
<script lang="ts">
/**
* AE_ObjectFlags.svelte
* GENERIC Aether Object Flags & Visibility Toggles
* Manages: alert, private, public, personal, professional, template
*/
import {
Siren, MessageSquareWarning, Fingerprint,
Globe, BookHeart, BriefcaseBusiness, NotepadTextDashed,
Settings
} from '@lucide/svelte';
import { ae_loc } from '$lib/stores/ae_stores';
interface Props {
// The object containing the flags (bindable)
obj: any;
// Visibility configuration (optional overrides)
showLabels?: boolean;
hideAlert?: boolean;
hidePrivate?: boolean;
hidePublic?: boolean;
hidePersonal?: boolean;
hideProfessional?: boolean;
hideTemplate?: boolean;
// Callbacks
onToggle?: (prop: string, newValue: boolean) => void;
// Styling
containerClass?: string;
}
let {
obj = $bindable(),
showLabels = true,
hideAlert = false,
hidePrivate = false,
hidePublic = false,
hidePersonal = false,
hideProfessional = false,
hideTemplate = false,
onToggle,
containerClass = "flex flex-row flex-wrap gap-1 items-center justify-evenly py-2 border-y border-surface-500/10"
}: Props = $props();
function handle_toggle(prop: string) {
obj[prop] = !obj[prop];
if (onToggle) onToggle(prop, obj[prop]);
}
</script>
<div class={containerClass}>
{#if showLabels}
<span class="text-xs text-surface-500 flex items-center gap-1 uppercase font-bold tracking-wider mr-2">
<Settings size="1.1em" /> Flags:
</span>
{/if}
<!-- Alert Status -->
{#if !hideAlert}
<button
type="button"
onclick={() => handle_toggle('alert')}
class="btn-icon btn-icon-sm preset-tonal-secondary hover:preset-filled-secondary-500 transition"
title="Toggle Alert Status"
>
<Siren size="1.2em" class={obj?.alert ? 'text-error-500' : 'opacity-40'} />
</button>
{/if}
<!-- Private / E2EE -->
{#if !hidePrivate}
<button
type="button"
onclick={() => handle_toggle('private')}
class="btn-icon btn-icon-sm preset-tonal-secondary hover:preset-filled-secondary-500 transition"
title="Toggle Private/Encrypted"
>
<Fingerprint size="1.2em" class={obj?.private ? 'text-success-500' : 'opacity-40'} />
</button>
{/if}
<!-- Public Visibility -->
{#if !hidePublic}
<button
type="button"
onclick={() => handle_toggle('public')}
class="btn-icon btn-icon-sm preset-tonal-secondary hover:preset-filled-secondary-500 transition"
title="Toggle Public Visibility"
>
<Globe size="1.2em" class={obj?.public ? 'text-success-500' : 'opacity-40'} />
</button>
{/if}
<!-- Personal Scope -->
{#if !hidePersonal}
<button
type="button"
onclick={() => handle_toggle('personal')}
class="btn-icon btn-icon-sm preset-tonal-secondary hover:preset-filled-secondary-500 transition"
title="Toggle Personal Scope"
>
<BookHeart size="1.2em" class={obj?.personal ? 'text-success-500' : 'opacity-40'} />
</button>
{/if}
<!-- Professional Scope -->
{#if !hideProfessional}
<button
type="button"
onclick={() => handle_toggle('professional')}
class="btn-icon btn-icon-sm preset-tonal-secondary hover:preset-filled-secondary-500 transition"
title="Toggle Professional Scope"
>
<BriefcaseBusiness size="1.2em" class={obj?.professional ? 'text-success-500' : 'opacity-40'} />
</button>
{/if}
<!-- Template Status -->
{#if !hideTemplate && $ae_loc.edit_mode}
<button
type="button"
onclick={() => handle_toggle('template')}
class="btn-icon btn-icon-sm preset-tonal-secondary hover:preset-filled-secondary-500 transition"
title="Toggle Template Mode"
>
<NotepadTextDashed size="1.2em" class={obj?.template ? 'text-success-500' : 'opacity-40'} />
</button>
{/if}
</div>