diff --git a/config/index.d.ts b/config/index.d.ts index 5f87de873..240aa0662 100644 --- a/config/index.d.ts +++ b/config/index.d.ts @@ -22,7 +22,7 @@ export type BookTabConfig = { bookTabID: string; type: string; file: string; - features: any; + features: FeatureConfig; chapters?: number; chaptersN?: string; style?: StyleConfig; @@ -78,7 +78,7 @@ export type BookConfig = { export type BookCollectionConfig = { id: string; - features: any; + features: FeatureConfig; books: BookConfig[]; style?: StyleConfig; fonts: string[]; @@ -251,7 +251,7 @@ export type AppConfig = { export type ScriptureConfig = AppConfig & { programType: 'SAB'; - traits?: any; + traits?: FeatureConfig; bookCollections?: BookCollectionConfig[]; videos?: { id: string; @@ -304,20 +304,22 @@ export type ScriptureConfig = AppConfig & { features: { [key: string]: string; }; - plans: { - id: string; - days: number; - title: { - [lang: string]: string; - }; - filename: string; - jsonFilename: string; - image?: { - width: number; - height: number; - file: string; - }; - }[]; + plans: PlanItem[]; + }; +}; + +export type PlanItem = { + id: string; + days: number; + title: { + [lang: string]: string; + }; + filename: string; + jsonFilename: string; + image?: { + width: number; + height: number; + file: string; }; }; @@ -396,7 +398,7 @@ export type LinkMeta = { export type ContentItem = { id: number; heading?: boolean; - features?: any; + features?: FeatureConfig; title: LangContainer; subtitle?: LangContainer; audioFilename?: LangContainer; @@ -425,7 +427,7 @@ export type ContentsData = { title?: { [lang: string]: string; }; - features?: any; + features?: FeatureConfig; items?: ContentItem[]; nestedItems?: boolean; screens?: ContentScreen[]; diff --git a/convert/convertBooks.ts b/convert/convertBooks.ts index be23fa957..5757ee15e 100644 --- a/convert/convertBooks.ts +++ b/convert/convertBooks.ts @@ -466,7 +466,7 @@ export async function convertBooks( //loop through books in collection const ignoredBooks = []; // If the collection has a glossary, load it - if (scriptureConfig.traits['has-glossary']) { + if (scriptureConfig.traits?.['has-glossary']) { bcGlossary = loadGlossary(collection, dataDir); } //add empty array of quizzes for book collection @@ -777,7 +777,7 @@ function convertScriptureBook( '\n' + remainingLines; } - if (context.scriptureConfig.traits['has-glossary']) { + if (context.scriptureConfig.traits?.['has-glossary']) { content = verifyGlossaryEntries(content, bcGlossary); } if (context.scriptureConfig.mainFeatures['hide-empty-verses'] === true) { diff --git a/convert/convertConfig.ts b/convert/convertConfig.ts index 295bd527b..318413394 100644 --- a/convert/convertConfig.ts +++ b/convert/convertConfig.ts @@ -337,7 +337,10 @@ function convertConfig(dataDir: string, verbose: number) { if (videos.length > 0) { data.videos = videos; } - data.traits['has-video'] = data.videos && data.videos.length > 0; + const hasVideo = !!data.videos && data.videos.length > 0; + data.traits = data.traits + ? { ...data.traits, 'has-video': hasVideo } + : { 'has-video': hasVideo }; data.illustrations = parseIllustrations(document, verbose); const { layouts, defaultLayout } = parseLayouts(document, data.bookCollections, verbose); diff --git a/src/app.d.ts b/src/app.d.ts index 4fd9e41a5..14a93d478 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -1,6 +1,7 @@ /// /// /// +/// // See https://kit.svelte.dev/docs/types#app // for information about these interfaces @@ -40,14 +41,16 @@ declare namespace App { penColor: string; } + type MenuActionHandler = (args: { text: string; url: string }) => void; + + type TabMenuActionHandler = (args: { text: string; url: string; tab: string }) => void; + interface TabMenuOptions { [key: string]: { tab?: { - component: any; - props?: any; + icon?: Snippet<[string]>; }; - component: any; - props: any; + snippet?: Snippet<[string, TabMenuActionHandler]>; visible: boolean; }; } @@ -75,8 +78,8 @@ declare namespace App { interface CollectionGroup { singlePane?: CollectionEntry; - sideBySide?: FixedLengthArray<[CollectionEntry, CollectionEntry]>; - verseByVerse?: FixedLengthArray<[CollectionEntry, CollectionEntry, CollectionEntry]>; + sideBySide?: [CollectionEntry, CollectionEntry]; + verseByVerse?: [CollectionEntry, CollectionEntry, CollectionEntry]; } interface UserPreferenceSetting { diff --git a/src/lib/components/AudioBar.svelte b/src/lib/components/AudioBar.svelte index 84848ff0a..bcecc7c09 100644 --- a/src/lib/components/AudioBar.svelte +++ b/src/lib/components/AudioBar.svelte @@ -25,13 +25,14 @@ TODO: refs, s, t, - userSettings + userSettings, + type PlayModeSettings } from '$lib/data/stores'; import { AudioIcon } from '$lib/icons'; import PlayButton from './PlayButton.svelte'; import RepeatButton from './RepeatButton.svelte'; - function mayResetPlayMode(hasTiming) { + function mayResetPlayMode(hasTiming: boolean) { // If the current mode is repeatSelection and the reference is changed to something without timing // (even chapter without audio), then reset the playMode. This matches how the Android app behaves. if (!hasTiming && $playMode.mode === 'repeatSelection') { @@ -39,18 +40,19 @@ TODO: } } - function seekAudio(event) { + function seekAudio(event: MouseEvent) { if (!$audioPlayer.loaded) { return; } const progressBar = document.getElementById('progress-bar'); - const percent = (event.clientX - progressBar.offsetLeft) / progressBar.offsetWidth; + const percent = + (event.clientX - (progressBar?.offsetLeft ?? 0)) / (progressBar?.offsetWidth ?? 1); // Set the current time of the audio element to the corresponding time based on the percent seek($audioPlayer.duration * percent); } let lastPlayMode = ''; - function playModeChanged(value) { + function playModeChanged(value: PlayModeSettings) { let key = ''; switch (value.mode) { @@ -77,8 +79,8 @@ TODO: let hintText = $state(''); let showHint = $state(false); - let hintTimeoutId = null; - function startShowHint(text) { + let hintTimeoutId: NodeJS.Timeout | null = null; + function startShowHint(text: string) { showHint = true; hintText = text; if (hintTimeoutId) { @@ -92,14 +94,14 @@ TODO: const showSpeed = config.mainFeatures['settings-audio-speed']; const showRepeatMode = config.mainFeatures['audio-repeat-mode-button']; - const hintStyle = convertStyle($s['ui.bar.audio.hint.text']); + const hintStyle = convertStyle($s?.['ui.bar.audio.hint.text']); const playButtonState = $derived($audioPlayer.playing ? 'pause' : 'play'); - const iconColor = $derived($s['ui.bar.audio.icon']['color']); - const iconPlayColor = $derived($s['ui.bar.audio.play.icon']['color']); - const backgroundColor = $derived($s['ui.bar.audio']['background-color']); + const iconColor = $derived($s?.['ui.bar.audio.icon']['color']); + const iconPlayColor = $derived($s?.['ui.bar.audio.play.icon']['color']); + const backgroundColor = $derived($s?.['ui.bar.audio']['background-color']); const audioBarClass = $derived($refs.hasAudio?.timingFile ? 'audio-bar' : 'audio-bar-progress'); $effect(() => mayResetPlayMode($refs.hasAudio?.timing)); - $effect(() => updatePlaybackSpeed($userSettings['audio-speed'])); + $effect(() => updatePlaybackSpeed($userSettings['audio-speed'] as string));
diff --git a/src/lib/components/AudioPlaybackSpeed.svelte b/src/lib/components/AudioPlaybackSpeed.svelte index d6657a8dd..bcb4c116a 100644 --- a/src/lib/components/AudioPlaybackSpeed.svelte +++ b/src/lib/components/AudioPlaybackSpeed.svelte @@ -1,4 +1,4 @@ - - +

{$t['Settings_Audio_Speed']} @@ -41,7 +41,7 @@ type="radio" name="speed" {value} - on:click={setPlaySpeed} + on:click={(e) => setPlaySpeed(e.currentTarget.value)} checked={$userSettings['audio-speed'] === value} /> {label} diff --git a/src/lib/components/BookSelector.svelte b/src/lib/components/BookSelector.svelte index f63fca56f..5197df54a 100644 --- a/src/lib/components/BookSelector.svelte +++ b/src/lib/components/BookSelector.svelte @@ -2,8 +2,9 @@ @component The navbar component. --> - +{#snippet selectList(bcv: string, menuaction: App.MenuActionHandler)} + +{/snippet} + +{#snippet selectGrid(bcv: string, menuaction: App.MenuActionHandler)} + +{/snippet} + {#if showSelectors} {#snippet label()} -
+
{labelDisplayed}
@@ -309,7 +347,7 @@ The navbar component. {:else} -
+
{labelDisplayed}
{/if} diff --git a/src/lib/components/BookTabs.svelte b/src/lib/components/BookTabs.svelte index 57a274657..79bbe0859 100644 --- a/src/lib/components/BookTabs.svelte +++ b/src/lib/components/BookTabs.svelte @@ -2,43 +2,31 @@ @component A component that displays the book tabs and allows the user to switch between them. --> - @@ -46,23 +34,23 @@ A component that displays the book tabs and allows the user to switch between th - {#each bookTabs.tabs as bookTab, i} + {#each bookTabs?.tabs as bookTab, i} diff --git a/src/lib/components/ContentCarousel.svelte b/src/lib/components/ContentCarousel.svelte index c23fb6ba3..700f086b7 100644 --- a/src/lib/components/ContentCarousel.svelte +++ b/src/lib/components/ContentCarousel.svelte @@ -1,42 +1,42 @@ @@ -32,12 +33,12 @@
- {#if features['show-titles'] === true} + {#if features?.['show-titles'] === true}
{item.title?.[$language] ?? item.title?.default ?? ''}
{/if} - {#if features['show-subtitles'] === true} + {#if features?.['show-subtitles'] === true}
{item.subtitle?.[$language] ?? item.subtitle?.default ?? ''}
@@ -49,8 +50,8 @@