web_lib

Common web application libraries
git clone https://radroots.dev/git/web_lib.git
Log | Files | Refs | LICENSE

commit 58308c141f6f54321ae11e69363a042835118b03
parent ab75d8f318e25aab63317322273bc526cbdba83d
Author: triesap <137732411+triesap@users.noreply.github.com>
Date:   Wed, 23 Oct 2024 02:41:56 +0000

apps-lib: add display line component, add glyph el ui, edit entry components, edit trellis, add styles, edit stores, types, ui, utils

Diffstat:
Aapps-lib/src/lib/components/display_line.svelte | 28++++++++++++++++++++++++++++
Mapps-lib/src/lib/components/entry_line.svelte | 6+++---
Mapps-lib/src/lib/components/entry_multiline.svelte | 2+-
Mapps-lib/src/lib/components/entry_option.svelte | 2+-
Mapps-lib/src/lib/components/layout_trellis.svelte | 2+-
Mapps-lib/src/lib/components/tabs.svelte | 17+++++++++++------
Mapps-lib/src/lib/components/trellis.svelte | 4++--
Mapps-lib/src/lib/index.ts | 2++
Mapps-lib/src/lib/locales/en/common.json | 16++++++++++++++++
Mapps-lib/src/lib/locales/en/error.json | 4++++
Mapps-lib/src/lib/locales/en/icu.json | 4++++
Mapps-lib/src/lib/stores/client.ts | 2+-
Mapps-lib/src/lib/types/client.ts | 7+++++++
Mapps-lib/src/lib/types/components.ts | 12+++++++++---
Mapps-lib/src/lib/types/ui.ts | 12++++++++++--
Mapps-lib/src/lib/ui/css_styles.svelte | 4++--
Mapps-lib/src/lib/ui/glyph.svelte | 1-
Aapps-lib/src/lib/ui/glyph_el.svelte | 19+++++++++++++++++++
Mapps-lib/src/lib/ui/input_element.svelte | 51+++++++++++++++++++++++++++------------------------
Mapps-lib/src/lib/utils/routes.ts | 6+++---
Mapps-lib/src/lib/utils/styles.ts | 1+
Mapps-lib/src/lib/utils/time.ts | 21++++++++++++++++++---
22 files changed, 170 insertions(+), 53 deletions(-)

diff --git a/apps-lib/src/lib/components/display_line.svelte b/apps-lib/src/lib/components/display_line.svelte @@ -0,0 +1,28 @@ +<script lang="ts"> + import { fmt_cl, parse_layer, type IDisplayLine } from "$lib"; + + export let basis: IDisplayLine; + $: basis = basis; + + $: layer = + typeof basis?.layer === `boolean` + ? false + : parse_layer(basis?.layer, 1); + $: classes_layer = + typeof layer === `boolean` + ? `bg-transparent` + : `bg-layer-${layer}-surface`; + $: clases_style = + basis.style === `guide` ? `h-entry_guide rounded-touch` : ``; +</script> + +<div + id={basis.id_wrap || null} + class={`${fmt_cl(basis.classes)} relative el-re entry-line-wrap px-2 ${classes_layer} ${clases_style}`} +> + <p + class={`${fmt_cl(basis.label.classes)} font-sans font-[400] text-layer-0-glyph`} + > + {basis.label.value} + </p> +</div> diff --git a/apps-lib/src/lib/components/entry_line.svelte b/apps-lib/src/lib/components/entry_line.svelte @@ -29,12 +29,12 @@ <div id={basis.id_wrap || null} - class={`${fmt_cl(basis.classes)} relative el-responsive entry-line-wrap px-2 ${classes_layer} ${clases_style}`} + class={`${fmt_cl(basis.classes)} relative el-re entry-line-wrap px-2 ${classes_layer} ${clases_style}`} > <InputElement basis={basis.el} /> {#if basis.loading} <div - class={`z-5 absolute el-responsive right-0 top-0 flex flex-row h-full pr-4 justify-end items-center fade-in`} + class={`z-5 absolute el-re right-0 top-0 flex flex-row h-full pr-4 justify-end items-center fade-in`} > <Loading basis={{ @@ -45,7 +45,7 @@ {:else if basis.notify_inline} {#if `glyph` in basis.notify_inline} <div - class={`z-5 absolute el-responsive right-0 top-0 flex flex-row h-full pr-3 justify-end items-center translate-x-[34px] fade-in`} + class={`z-5 absolute el-re right-0 top-0 flex flex-row h-full pr-3 justify-end items-center translate-x-[34px] fade-in`} > <Glyph basis={typeof basis.notify_inline.glyph === `string` diff --git a/apps-lib/src/lib/components/entry_multiline.svelte b/apps-lib/src/lib/components/entry_multiline.svelte @@ -17,7 +17,7 @@ <div id={basis.id_wrap || null} - class={`${fmt_cl(basis.classes_wrap)} relative el-responsive entry-textarea-wrap ${classes_layer}`} + class={`${fmt_cl(basis.classes_wrap)} relative el-re entry-textarea-wrap ${classes_layer}`} > <TextareaElement basis={basis.el} /> {#if basis.notify_inline} diff --git a/apps-lib/src/lib/components/entry_option.svelte b/apps-lib/src/lib/components/entry_option.svelte @@ -28,7 +28,7 @@ <div id={basis.id_wrap || null} tabindex={-1} - class={`${fmt_cl(basis.classes_wrap)} relative el-responsive entry-line-wrap ${classes_layer}`} + class={`${fmt_cl(basis.classes_wrap)} relative el-re entry-line-wrap ${classes_layer}`} > {#if basis.loading} <div class={`flex flex-row w-full justify-center items-center`}> diff --git a/apps-lib/src/lib/components/layout_trellis.svelte b/apps-lib/src/lib/components/layout_trellis.svelte @@ -6,7 +6,7 @@ </script> <div - class={`${fmt_cl(basis?.classes)} flex flex-col w-full pt-4 px-2 pb-12 gap-4 justify-center items-center scroll-hide`} + class={`${fmt_cl(basis?.classes)} flex flex-col w-full pt-4 pb-12 gap-4 justify-center items-center scroll-hide`} > <slot /> </div> diff --git a/apps-lib/src/lib/components/tabs.svelte b/apps-lib/src/lib/components/tabs.svelte @@ -40,21 +40,21 @@ <div bind:this={el} - class={`${fmt_cl(basis?.classes)} z-10 absolute bottom-0 left-0 flex flex-col w-full justify-start items-start transition-all backdrop-blur-md h-tabs_${$app_layout} ${classes_blur}`} + class={`${fmt_cl(basis?.classes)} z-10 absolute bottom-0 left-0 flex flex-col w-full justify-start items-start bg-base-100/40 backdrop-blur-md h-tabs_${$app_layout} ${classes_blur} el-re`} > <div bind:this={el_inner} - class={`relative flex flex-col h-full w-full justify-start items-center`} + class={`relative flex flex-col h-full w-full justify-start items-start`} > <div - class={`absolute top-4 left-0 grid grid-cols-12 flex flex-row w-full justify-center items-center`} + class={`absolute top-3 left-0 grid grid-cols-12 flex flex-row w-full justify-center items-center`} > {#if $$slots.default} <slot /> {:else} {#each basis?.list || [] as tab, tab_i} <button - class={`col-span-3 flex flex-col h-full justify-start items-center transition-all`} + class={`group col-span-3 flex flex-col h-full gap-[2px] justify-start items-center el-re`} on:click={async () => { tab_focus = tab_i; if (!tab.hide_active) tabs_active.set(tab_i); @@ -67,8 +67,8 @@ basis={{ classes: !basis.hide_active && $tabs_active === tab_i - ? `text-layer-2-glyph text-lineActiveBlue` - : `text-layer-2-glyph text-lineMd`, + ? `text-layer-1-glyph text-lineActiveBlue` + : `text-layer-1-glyph text-lineMd`, key: tab.icon, dim: `md`, weight: tab.force_weight @@ -82,6 +82,11 @@ : `bold`, }} /> + <p + class={`font-circ font-[400] text-layer-1-glyph text-xs tracking-tight`} + > + {tab.label || ``} + </p> </button> {/each} {/if} diff --git a/apps-lib/src/lib/components/trellis.svelte b/apps-lib/src/lib/components/trellis.svelte @@ -1,5 +1,5 @@ <script lang="ts"> - import { fmt_cl, parse_layer, t, type ITrellis } from ".."; + import { app_layout, fmt_cl, parse_layer, t, type ITrellis } from ".."; import TrellisDefaultLabel from "./trellis_default_label.svelte"; import TrellisInput from "./trellis_input.svelte"; import TrellisOffset from "./trellis_offset.svelte"; @@ -34,7 +34,7 @@ data-view={basis.args.view || ""} > <div - class={`relative flex flex-col h-auto w-auto gap-[3px] ${set_title_background ? `bg-layer-${args.layer}-surface` : ``}`} + class={`relative flex flex-col h-auto w-${$app_layout} gap-[3px] ${set_title_background ? `bg-layer-${args.layer}-surface` : ``}`} > {#if args.title && (!args.default_el || (args.default_el && args.default_el.show_title))} <TrellisTitle diff --git a/apps-lib/src/lib/index.ts b/apps-lib/src/lib/index.ts @@ -5,6 +5,7 @@ export { default as Toast } from "./ui/toast.svelte"; export { default as GlyphCircle } from "./ui/glyph_circle.svelte"; export { default as TextareaElement } from "./ui/textarea_element.svelte"; export { default as CssStatic } from "./ui/css_static.svelte"; +export { default as GlyphEl } from "./ui/glyph_el.svelte"; export { default as Divider } from "./ui/divider.svelte"; export { default as LabelSwap } from "./ui/label_swap.svelte"; export { default as Glyph } from "./ui/glyph.svelte"; @@ -32,6 +33,7 @@ export { default as EnvelopeLower } from "./components/envelope_lower.svelte"; export { default as TrellisInput } from "./components/trellis_input.svelte"; export { default as TrellisEnd } from "./components/trellis_end.svelte"; export { default as Envelope } from "./components/envelope.svelte"; +export { default as DisplayLine } from "./components/display_line.svelte"; export { default as LayoutTrellis } from "./components/layout_trellis.svelte"; export { default as Tabs } from "./components/tabs.svelte"; export { default as TrellisTitle } from "./components/trellis_title.svelte"; diff --git a/apps-lib/src/lib/locales/en/common.json b/apps-lib/src/lib/locales/en/common.json @@ -1,5 +1,18 @@ { + "overview": "Overview", + "month_to_date": "Month to date", + "all_accounts": "All accounts", + "outflows": "Outflows", + "inflows": "Inflows", + "lowest_price": "Lowest price", + "highest_price": "Highest price", + "end_date": "End date", + "start_date": "Start date", + "filters": "Filters", + "month": "Month", + "available_balance": "Available balance", "accept": "Accept", + "activation": "Activation", "active": "Active", "add": "Add", "add_current_location": "Add current location", @@ -38,6 +51,7 @@ "lot": "Lot", "lot_name": "Lot name", "map": "Map", + "market": "Market", "message": "Message", "messages": "Messages", "no": "No", @@ -52,6 +66,7 @@ "per": "Per", "personal": "Personal", "photos": "Photos", + "post": "Post", "preview": "Preview", "price": "Price", "process": "Process", @@ -67,6 +82,7 @@ "quit": "Quit", "relay": "Relay", "relays": "Relays", + "reset": "Reset", "review": "Review", "secret_key": "Secret key", "settings": "Settings", diff --git a/apps-lib/src/lib/locales/en/error.json b/apps-lib/src/lib/locales/en/error.json @@ -9,6 +9,10 @@ "request_failure": "The request was not successful", "unhandled": "There was an error during your request" }, + "device": { + "configuration_failure": "There was an error configuring the device", + "public_key_not_derived": "Error deriving public key" + }, "geolocation": { "request": { "current": "Geolocation request failure" diff --git a/apps-lib/src/lib/locales/en/icu.json b/apps-lib/src/lib/locales/en/icu.json @@ -1,9 +1,13 @@ { + "month_of_*": "Month of {value}", + "this_*": "This {value}", + "last_*": "Last {value}", "*_as": "{value} as", "*_available": "{value} Available", "*_copied": "{value} copied", "*_description": "{value} description", "*_details": "{value} details", + "*_failure": "{value} failure", "*_name": "{value} name", "*_summary": "{value} summary", "*_title": "{value} title", diff --git a/apps-lib/src/lib/stores/client.ts b/apps-lib/src/lib/stores/client.ts @@ -29,7 +29,7 @@ export const app_submit_route = writable<NavigationPreviousParam | undefined>(un export const app_blur = writable<boolean>(false); export const app_db = writable<boolean>(false); export const app_geoc = writable<boolean>(false); -export const app_thc = writable<ColorMode>(`dark`); +export const app_thc = writable<ColorMode>(`light`); export const app_th = writable<ThemeKey>(`os`); export const app_nostr_key = writable<string>(``); export const app_pwa_polyfills = writable<boolean>(false); diff --git a/apps-lib/src/lib/types/client.ts b/apps-lib/src/lib/types/client.ts @@ -132,6 +132,13 @@ export type ILabel = { label: ILableFields; }; +export type ILabelValue = { + label: IClOpt & { + value: string; + }; +}; + + export type ILabelOpt = { label?: ILableFields; }; diff --git a/apps-lib/src/lib/types/components.ts b/apps-lib/src/lib/types/components.ts @@ -1,5 +1,5 @@ import type { NavigationRoute } from "$lib/utils/routes"; -import type { CallbackPromise, CallbackPromiseGeneric, ICb, ICbG, ICbGOpt, ICbOpt, IClOpt, IClWrapOpt, IGl, IGlOpt, IIdOpt, IIdWrapOpt, ILabel, ILabelFieldsOpt, ILabelOpt, ILabelOptFieldsOpt, ILoadingOpt, ILyOpt, ILyOptTs, NavigationParamTuple } from "./client"; +import type { CallbackPromise, CallbackPromiseGeneric, ICb, ICbG, ICbGOpt, ICbOpt, IClOpt, IClWrapOpt, IGl, IGlOpt, IIdOpt, IIdWrapOpt, ILabel, ILabelFieldsOpt, ILabelOpt, ILabelOptFieldsOpt, ILabelValue, ILoadingOpt, ILyOpt, ILyOptTs, NavigationParamTuple } from "./client"; import type { GlyphKey, GlyphWeight, IGlyph, IInputElement, ITextAreaElement } from "./ui"; export type ITabsBasisList = IClOpt & { @@ -9,6 +9,7 @@ export type ITabsBasisList = IClOpt & { indicator?: string; hide_active?: boolean; callback: CallbackPromiseGeneric<number>; + label?: string; }; export type ITabsBasis = IClOpt & { @@ -23,10 +24,10 @@ export type IFormField = { validate_keypress?: boolean; }; -export type IEntryLineStyle = `guide`; +export type ILineStyle = `guide`; export type IEntryLine = IIdWrapOpt & IClOpt & ILoadingOpt & { el: IInputElement; - style?: IEntryLineStyle + style?: ILineStyle notify_inline?: { glyph: GlyphKey | IGlyph; }; @@ -94,3 +95,7 @@ export type INavBasis = { option?: INavBasisOption; }; + +export type IDisplayLine = IIdWrapOpt & IClOpt & ILabelValue & ILyOpt & { + style?: ILineStyle +} +\ No newline at end of file diff --git a/apps-lib/src/lib/types/ui.ts b/apps-lib/src/lib/types/ui.ts @@ -1,9 +1,17 @@ -import type { CallbackPromiseGeneric, GeometryCardinalDirection, GeometryDimension, GeometryGlyphDimension, ICbGOpt, ICbOpt, IClOpt, IFormField, IId, ILy, ILyOptTs } from "$lib"; +import type { CallbackPromiseGeneric, GeometryCardinalDirection, GeometryDimension, GeometryGlyphDimension, ICbGOpt, ICbOpt, IClOpt, IFormField, IId, IIdOpt, ILy, ILyOptTs } from "$lib"; import type { ThemeLayer } from "@radroots/theme"; export type GlyphKeyCurrency = `dollar` | `eur`; export type GlyphKey = | + `arrow-left` | + `arrows-down-up` | + `basket` | + `arrow-right` | + `upload-simple` | + `printer` | + `download-simple` | + `list` | `asterisk` | `asterisk-simple` | `subtitles-slash` | @@ -93,7 +101,7 @@ export type GlyphKey = | export type GlyphWeight = `light` | `regular` | `fill` | `bold`; // `thin` `duotone` -export type IGlyph = ICbOpt & { +export type IGlyph = ICbOpt & IIdOpt & { layer?: ThemeLayer; classes?: string; weight?: GlyphWeight; diff --git a/apps-lib/src/lib/ui/css_styles.svelte b/apps-lib/src/lib/ui/css_styles.svelte @@ -1,3 +1,3 @@ -<div class="hidden h-[12px] w-[12px] h-[16px] w-[16px] h-[17px] w-[17px] h-[18px] w-[18px] h-[20px] w-[20px] h-[24px] w-[24px] h-[28px] w-[28px] h-[36px] w-[36px]"></div> -<div class="hidden text-[12px] text-[15px] text-[16px] text-[18px] text-[20px] text-[21px] text-[23px] text-[24px] text-[26px] text-[28px] text-[30px] text-[36px] text-[40px]"></div> +<div class="hidden h-[12px] w-[12px] h-[16px] w-[16px] h-[17px] w-[17px] h-[18px] w-[18px] h-[20px] w-[20px] h-[22px] w-[22px] h-[24px] w-[24px] h-[28px] w-[28px] h-[36px] w-[36px]"></div> +<div class="hidden text-[12px] text-[15px] text-[16px] text-[18px] text-[19px] text-[20px] text-[21px] text-[23px] text-[24px] text-[26px] text-[28px] text-[30px] text-[36px] text-[40px]"></div> <div class="hidden h-tabs_mobile_base pt-h_tabs_mobile_base pb-h_tabs_mobile_base translate-y-h_tabs_mobile_base -translate-y-h_tabs_mobile_base h-tabs_mobile_y pt-h_tabs_mobile_y pb-h_tabs_mobile_y translate-y-h_tabs_mobile_y -translate-y-h_tabs_mobile_y h-nav_mobile_base pt-h_nav_mobile_base pb-h_nav_mobile_base translate-y-h_nav_mobile_base -translate-y-h_nav_mobile_base h-nav_mobile_y pt-h_nav_mobile_y pb-h_nav_mobile_y translate-y-h_nav_mobile_y -translate-y-h_nav_mobile_y h-view_mobile_base pt-h_view_mobile_base pb-h_view_mobile_base translate-y-h_view_mobile_base -translate-y-h_view_mobile_base h-view_mobile_y pt-h_view_mobile_y pb-h_view_mobile_y translate-y-h_view_mobile_y -translate-y-h_view_mobile_y h-view_offset_mobile_base pt-h_view_offset_mobile_base pb-h_view_offset_mobile_base translate-y-h_view_offset_mobile_base -translate-y-h_view_offset_mobile_base h-view_offset_mobile_y pt-h_view_offset_mobile_y pb-h_view_offset_mobile_y translate-y-h_view_offset_mobile_y -translate-y-h_view_offset_mobile_y w-mobile_base w-mobile_y top-dim_map_offset_top_mobile_base top-dim_map_offset_top_mobile_y"></div> \ No newline at end of file diff --git a/apps-lib/src/lib/ui/glyph.svelte b/apps-lib/src/lib/ui/glyph.svelte @@ -8,7 +8,6 @@ $: weight = !basis?.weight || basis?.weight === `regular` ? `` : `-${basis.weight}`; - $: styles = basis?.dim ? glyph_style_map.get(basis.dim) : glyph_style_map.get(`sm`); diff --git a/apps-lib/src/lib/ui/glyph_el.svelte b/apps-lib/src/lib/ui/glyph_el.svelte @@ -0,0 +1,19 @@ +<script lang="ts"> + import { fmt_cl, glyph_style_map, type IGlyph } from "$lib"; + + export let basis: IGlyph; + $: basis = basis; + + $: weight = + !basis?.weight || basis?.weight === `regular` ? `` : `-${basis.weight}`; + $: styles = basis?.dim + ? glyph_style_map.get(basis.dim) + : glyph_style_map.get(`sm`); +</script> + +<div + id={basis.id || null} + class={`${fmt_cl(basis.classes)} flex flex-row text-[${styles?.gl_1}px] justify-center items-center`} +> + <i class={`ph${weight} ph-${basis.key}`}></i> +</div> diff --git a/apps-lib/src/lib/ui/input_element.svelte b/apps-lib/src/lib/ui/input_element.svelte @@ -13,27 +13,27 @@ export let basis: IInputElement; $: basis = basis; - $: id = basis.id ? basis.id : null; + $: id = basis?.id ? basis?.id : null; $: layer = - typeof basis.layer === `boolean` ? 0 : parse_layer(basis.layer, 1); //@todo + typeof basis?.layer === `boolean` ? 0 : parse_layer(basis?.layer, 1); //@todo onMount(async () => { try { - if (basis.id) { - if (basis.sync_init) + if (basis?.id) { + if (basis?.sync_init) await kv.set( - basis.id, - typeof basis.sync_init === `string` - ? basis.sync_init + basis?.id, + typeof basis?.sync_init === `string` + ? basis?.sync_init : ``, ); - if (basis.sync) { - const kv_val = await kv.get(basis.id); - if (kv_val) el.value = kv_val; - else await kv.set(basis.id, ``); + if (basis?.sync) { + const kv_val = await kv.get(basis?.id); + if (kv_val && el) el.value = kv_val; + else await kv.set(basis?.id, ``); } } - if (basis.on_mount) await basis.on_mount(el); + if (basis?.on_mount) await basis?.on_mount(el); } catch (e) { console.log(`e input mount`, e); } @@ -44,27 +44,30 @@ bind:this={el} {id} type="text" - class={`${fmt_cl(basis.classes)} el-input text-layer-${layer}-glyph placeholder:text-layer-${layer}-glyph_pl caret-layer-${layer}-glyph`} - placeholder={basis.placeholder || ""} + class={`${fmt_cl(basis?.classes)} el-input text-layer-${layer}-glyph placeholder:text-layer-${layer}-glyph_pl caret-layer-${layer}-glyph`} + placeholder={basis?.placeholder || ""} on:input={async ({ currentTarget: el }) => { let pass = true; - let val = el.value; - if (basis.field) { - val = value_constrain(basis.field.charset, val); + let val = el?.value; + if (basis?.field && el) { + val = value_constrain(basis?.field.charset, val); el.value = val; if ( - !basis.field.validate.test(val) && - basis.field.validate_keypress + !basis?.field.validate.test(val) && + basis?.field.validate_keypress ) { //@todo set styles } - pass = basis.field.validate.test(val); + pass = basis?.field.validate.test(val); } - if (basis.sync) await kv.set(basis.id, val); - if (basis.callback) await basis.callback({ value: val, pass }); + if (basis?.sync) await kv.set(basis?.id, val); + if (basis?.callback) await basis?.callback({ value: val, pass }); }} on:keydown={async (ev) => { - if (basis.callback_keydown) - await basis.callback_keydown({ key: ev.key, el: ev.currentTarget }); + if (basis?.callback_keydown) + await basis?.callback_keydown({ + key: ev.key, + el: ev.currentTarget, + }); }} /> diff --git a/apps-lib/src/lib/utils/routes.ts b/apps-lib/src/lib/utils/routes.ts @@ -1,5 +1,6 @@ export type NavigationRoute = | "/" + | "/market" | "/models/location-gcs" | "/models/nostr-profile" | "/models/nostr-profile/edit/field" @@ -11,12 +12,12 @@ export type NavigationRoute = | "/settings" | "/test" | "/device/error" - | "/device/init" - | "/device/test"; + | "/device/init"; export function parse_route(route: string): NavigationRoute { switch (route) { case "/": + case "/market": case "/models/location-gcs": case "/models/nostr-profile": case "/models/nostr-profile/edit/field": @@ -29,7 +30,6 @@ export function parse_route(route: string): NavigationRoute { case "/test": case "/device/error": case "/device/init": - case "/device/test": return route; default: return "/"; diff --git a/apps-lib/src/lib/utils/styles.ts b/apps-lib/src/lib/utils/styles.ts @@ -5,6 +5,7 @@ export const glyph_style_map: Map<GeometryGlyphDimension, { gl_1: number; dim_1? ["xs-", { gl_1: 12, dim_1: 17 }], ["xs", { gl_1: 15, dim_1: 18 }], ["xs+", { gl_1: 18, dim_1: 20 }], + ["sm-", { gl_1: 19, dim_1: 22 }], ["sm", { gl_1: 20, dim_1: 24 }], ["sm+", { gl_1: 21 }], ["md-", { gl_1: 23 }], diff --git a/apps-lib/src/lib/utils/time.ts b/apps-lib/src/lib/utils/time.ts @@ -1,4 +1,6 @@ +import { locale } from "$lib/locales/i18n"; import { DateTime, type DateTimeFormatOptions } from "luxon"; +import { get } from "svelte/store"; const time_fmt: Record<string, DateTimeFormatOptions> = { default: DateTime.DATE_SHORT, @@ -13,9 +15,22 @@ export function time_fmt_epoch_s(locale: string, epoch_s: number | undefined, fm return time; }; -export function time_fmt_iso(locale: string, iso: string, fmt_key: keyof typeof time_fmt = `default`): string { +export function time_iso(locale: string, iso: string, fmt_key: keyof typeof time_fmt = `default`): string { const dt = DateTime.fromISO(iso); if (!dt.isValid) return ``; const time = dt.setLocale(locale).toLocaleString(time_fmt[fmt_key]); return time; -}; -\ No newline at end of file +}; + + +export function time_iso_fmt(iso: string, fmt_str: string): string { + const dt = DateTime.fromISO(iso); + if (!dt.isValid) return ``; + const time = dt.setLocale(get(locale)).toFormat(fmt_str); + return time; +}; + +export function format_month_abbrev(month_num: number): string { + if (month_num < 1 || month_num > 12) return ``; + return DateTime.fromObject({ month: month_num }).setLocale(get(locale)).toFormat('MMM'); +} +\ No newline at end of file