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:
65
src/lib/ae_elements/AE_MetadataFooter.svelte
Normal file
65
src/lib/ae_elements/AE_MetadataFooter.svelte
Normal 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>
|
||||
131
src/lib/ae_elements/AE_ObjectFlags.svelte
Normal file
131
src/lib/ae_elements/AE_ObjectFlags.svelte
Normal 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>
|
||||
Reference in New Issue
Block a user