diff --git a/config/index.d.ts b/config/index.d.ts index 2faad1c67..42fcb01e1 100644 --- a/config/index.d.ts +++ b/config/index.d.ts @@ -113,7 +113,23 @@ export type DictionaryWritingSystemConfig = WritingSystemConfig & { [name: string]: boolean; }; }; - +export type MenuItemConfig = { + type: string; + title: { + [lang: string]: string; + }; + link?: { + [lang: string]: string; + }; + linkId?: { + [lang: string]: string; + }; + images?: { + width: number; + height: number; + file: string; + }[]; +}; export type AppConfig = { name?: string; package?: string; @@ -172,23 +188,8 @@ export type AppConfig = { [name: string]: boolean; }; }; - menuItems?: { - type: string; - title: { - [lang: string]: string; - }; - link?: { - [lang: string]: string; - }; - linkId?: { - [lang: string]: string; - }; - images?: { - width: number; - height: number; - file: string; - }[]; - }[]; + menuItems?: MenuItemConfig[]; + bottomNavBarItems?: MenuItemConfig[]; security?: { // TODO features?: { diff --git a/convert/convertConfig.ts b/convert/convertConfig.ts index 83f9371ee..ec5a23532 100644 --- a/convert/convertConfig.ts +++ b/convert/convertConfig.ts @@ -329,11 +329,16 @@ function convertConfig(dataDir: string, verbose: number) { data.watermarkImages = watermarkImages; } - const menuItems = parseMenuItems(document, verbose); + const menuItems = parseMenuItems(document, 'drawer', verbose); if (menuItems.length > 0) { data.menuItems = menuItems; } + const bottomNavigationItems = parseMenuItems(document, 'bottom', verbose); + if (bottomNavigationItems.length > 0) { + data.bottomNavBarItems = bottomNavigationItems; + } + const { features, plans } = parsePlans(document, verbose); if (plans.length > 0) { data.plans = { @@ -1139,12 +1144,11 @@ function parseWatermarkImages(document: Document, verbose: number) { return watermarkImages; } -function parseMenuItems(document: Document, verbose: number) { - const menuItemTags = document - .getElementsByTagName('menu-items')[0] - ?.getElementsByTagName('menu-item'); +function parseMenuItems(document: Document, type: string, verbose: number) { + const firstMenuItemsByType = document.querySelector(`menu-items[type="${type}"]`); + const menuItemTags = firstMenuItemsByType?.getElementsByTagName('menu-item'); const menuItems = []; - if (menuItemTags?.length > 0) { + if (menuItemTags && menuItemTags?.length > 0) { for (const menuItem of menuItemTags) { const type = menuItem.attributes.getNamedItem('type')!.value; if (verbose >= 2) console.log(`.. Converting menuItem: ${type}`); diff --git a/src/lib/components/BottomNavigationBar.svelte b/src/lib/components/BottomNavigationBar.svelte new file mode 100644 index 000000000..fa2279ae4 --- /dev/null +++ b/src/lib/components/BottomNavigationBar.svelte @@ -0,0 +1,153 @@ + + + +
+
+
+ + {#if bottomNavBarItems} + {#each bottomNavBarItems as item} + {#if showButton(item.type)} + + {/if} + {/each} + {/if} +
+
+
diff --git a/src/routes/about/+page.svelte b/src/routes/about/+page.svelte index 5b082ea50..6c47ef13d 100644 --- a/src/routes/about/+page.svelte +++ b/src/routes/about/+page.svelte @@ -1,8 +1,12 @@
@@ -20,4 +24,7 @@ {@html data.partial}
+ {#if bottomNavBarEnabled} + + {/if} diff --git a/src/routes/contents/[id]/+page.svelte b/src/routes/contents/[id]/+page.svelte index e9e260ea7..b29e7a407 100644 --- a/src/routes/contents/[id]/+page.svelte +++ b/src/routes/contents/[id]/+page.svelte @@ -20,6 +20,7 @@ import { goto } from '$app/navigation'; import config from '$lib/data/config'; import { AudioIcon, TextAppearanceIcon } from '$lib/icons'; + import BottomNavigationBar from '$lib/components/BottomNavigationBar.svelte'; const imageFolder = compareVersions(config.programVersion, '12.0') < 0 ? 'illustrations' : 'contents'; @@ -167,6 +168,8 @@ } } $: showBackButton = $contentsStack.length > 0; + const bottomNavBarEnabled = config?.bottomNavBarItems && config?.bottomNavBarItems.length > 0; + const barType = 'contents';
@@ -260,4 +263,7 @@ {/each}
+ {#if bottomNavBarEnabled} + + {/if} diff --git a/src/routes/plans/+page.svelte b/src/routes/plans/+page.svelte index 820241c62..9945d4b58 100644 --- a/src/routes/plans/+page.svelte +++ b/src/routes/plans/+page.svelte @@ -17,6 +17,7 @@ import { getLastPlanState } from '$lib/data/planStates'; import { compareVersions } from '$lib/scripts/stringUtils'; import { goto } from '$app/navigation'; + import BottomNavigationBar from '$lib/components/BottomNavigationBar.svelte'; const imageFolder = compareVersions(config.programVersion, '12.0') < 0 ? 'illustrations' : 'plans'; @@ -57,6 +58,8 @@ ); usedPlans = plansInUse; } + const bottomNavBarEnabled = config?.bottomNavBarItems && config?.bottomNavBarItems.length > 0; + const barType = 'plans';
@@ -212,4 +215,7 @@ {/if}
+ {#if bottomNavBarEnabled} + + {/if} diff --git a/src/routes/plans/[id]/+page.svelte b/src/routes/plans/[id]/+page.svelte index d2ef2cd0b..c48db00b7 100644 --- a/src/routes/plans/[id]/+page.svelte +++ b/src/routes/plans/[id]/+page.svelte @@ -81,13 +81,7 @@ } return completed; } - function checkSelection(day) { - if (day === selectedDay) { - return 'selected plan-day-box-selected'; - } else { - return 'plan-day-box-unselected'; - } - } + function getReferenceString(ref) { // Reminder - get book collection id let currentBookCollectionId = $refs.collection; diff --git a/src/routes/text/+page.svelte b/src/routes/text/+page.svelte index 5e35d49c7..4937b7f99 100644 --- a/src/routes/text/+page.svelte +++ b/src/routes/text/+page.svelte @@ -56,12 +56,27 @@ import { page } from '$app/stores'; import { goto } from '$app/navigation'; import { onDestroy, onMount, afterUpdate } from 'svelte'; + import { slide } from 'svelte/transition'; import { navigateToTextChapterInDirection } from '$lib/navigate'; + import BottomNavigationBar from '$lib/components/BottomNavigationBar.svelte'; + let scrollingUp = true; let savedScrollPosition = 0; + let lastChangeTime = 0; function saveScrollPosition() { if (scrollingDiv) { + const now = Date.now(); + const oldSavedScroll = savedScrollPosition; savedScrollPosition = scrollingDiv.scrollTop; + const newScrollingUp = oldSavedScroll - savedScrollPosition > 0; + if (newScrollingUp != scrollingUp) { + if (now - lastChangeTime > 500) { + // The timing thing fixes a problem with occasional vibrating + // when you hit the bottom of the screen + scrollingUp = newScrollingUp; + lastChangeTime = now; + } + } } } afterUpdate(() => { @@ -86,6 +101,9 @@ } } + const bottomNavBarEnabled = config?.bottomNavBarItems && config?.bottomNavBarItems.length > 0; + const barType = 'book'; + async function prevChapter() { await navigateToTextChapterInDirection(-1); } @@ -503,6 +521,9 @@ {/if} + {#if scrollingUp && bottomNavBarEnabled && !$selectedVerses.length > 0} + + {/if}