From 69857c26f8c80e9fc71bae3622526dabbf0bad11 Mon Sep 17 00:00:00 2001 From: Marwan Ansari <8071158+marwan@users.noreply.github.com> Date: Wed, 4 Dec 2024 01:48:56 +0530 Subject: [PATCH] wip: morphology modal (#216) --- .../display/verses/SingleArabicVerse.svelte | 4 +- .../display/verses/WordsBlock.svelte | 14 +- src/components/ui/HomepageTabs.svelte | 4 +- .../ui/Modals/MorphologyModal.svelte | 15 ++ .../SettingsDrawer/QuranFontSelector.svelte | 17 -- src/routes/+layout.svelte | 2 + src/routes/bookmarks/+page.svelte | 12 +- src/routes/morphology/[key]/+page.svelte | 159 +--------------- .../morphology/[key]/MorphologyView.svelte | 169 ++++++++++++++++++ .../morphology/[key]}/Table.svelte | 0 src/routes/search/+page.svelte | 10 +- src/utils/fetchData.js | 35 ++-- src/utils/stores.js | 3 + src/views/Supplications.svelte | 10 +- static/css/global.css | 4 + 15 files changed, 249 insertions(+), 209 deletions(-) create mode 100644 src/components/ui/Modals/MorphologyModal.svelte create mode 100644 src/routes/morphology/[key]/MorphologyView.svelte rename src/{components/display/morphology => routes/morphology/[key]}/Table.svelte (100%) diff --git a/src/components/display/verses/SingleArabicVerse.svelte b/src/components/display/verses/SingleArabicVerse.svelte index 8c22bbf9..2afc7083 100644 --- a/src/components/display/verses/SingleArabicVerse.svelte +++ b/src/components/display/verses/SingleArabicVerse.svelte @@ -2,12 +2,12 @@ export let key; import Spinner from '$svgs/Spinner.svelte'; - import { fetchSingleVerseData } from '$utils/fetchData'; + import { fetchVersesData } from '$utils/fetchData'; import { __fontType } from '$utils/stores'; import { splitDelimiter } from '$data/websiteSettings'; $: fontType = [1, 2, 3].includes($__fontType) ? 1 : 4; - $: fetchData = fetchSingleVerseData(key, fontType); + $: fetchData = fetchVersesData({ verses: key, fontType: fontType, skipSave: true }); {#await fetchData} diff --git a/src/components/display/verses/WordsBlock.svelte b/src/components/display/verses/WordsBlock.svelte index 6b536222..21dda603 100644 --- a/src/components/display/verses/WordsBlock.svelte +++ b/src/components/display/verses/WordsBlock.svelte @@ -4,7 +4,7 @@ import Tooltip from '$ui/FlowbiteSvelte/tooltip/Tooltip.svelte'; import { goto } from '$app/navigation'; import { selectableDisplays, selectableThemes } from '$data/options'; - import { __currentPage, __fontType, __displayType, __userSettings, __audioSettings, __morphologyKey, __verseKey, __websiteTheme } from '$utils/stores'; + import { __currentPage, __fontType, __displayType, __userSettings, __audioSettings, __morphologyKey, __verseKey, __websiteTheme, __morphologyModalVisible } from '$utils/stores'; import { loadFont } from '$utils/loadFont'; import { wordAudioController } from '$utils/audioController'; import { updateSettings } from '$utils/updateSettings'; @@ -33,10 +33,20 @@ // 2. On other pages, play word's audio // 3. On any page, show verse options dropdown for end verse icon function wordClickHandler(props) { + // For morphology page if ($__currentPage === 'morphology' && props.type === 'word') { __morphologyKey.set(props.key); goto(`/morphology/${props.key}`, { replaceState: false }); - } else { + } + + // If the user clicks on a word in a non-Morphology page + // else if ($__currentPage !== 'morphology' && props.type === 'word') { + // __morphologyKey.set(props.key); + // __morphologyModalVisible.set(true); + // } + + // All other options + else { __verseKey.set(props.key); if (props.type === 'word') { wordAudioController({ diff --git a/src/components/ui/HomepageTabs.svelte b/src/components/ui/HomepageTabs.svelte index c95e64b0..bc530f5d 100644 --- a/src/components/ui/HomepageTabs.svelte +++ b/src/components/ui/HomepageTabs.svelte @@ -10,7 +10,7 @@ import { buttonClasses, buttonOutlineClasses } from '$data/commonClasses'; import { checkTimeSpecificChapters } from '$utils/checkTimeSpecificChapters'; import { term } from '$utils/terminologies'; - import { fetchSingleVerseData } from '$utils/fetchData'; + import { fetchVersesData } from '$utils/fetchData'; import { splitDelimiter } from '$data/websiteSettings'; // CSS classes for chapter cards and tabs @@ -33,7 +33,7 @@ } // Reactive variable to fetch bookmarks data when on the bookmarks tab - $: fetchData = activeTab === 3 && totalBookmarks !== 0 ? fetchSingleVerseData($__userBookmarks.toString(), 1) : null; + $: fetchData = activeTab === 3 && totalBookmarks !== 0 ? fetchVersesData({ verses: $__userBookmarks.toString(), fontType: 1 }) : null; $: totalBookmarks = $__userBookmarks.length; $: totalNotes = Object.keys($__userNotes).length; diff --git a/src/components/ui/Modals/MorphologyModal.svelte b/src/components/ui/Modals/MorphologyModal.svelte new file mode 100644 index 00000000..b9171e2d --- /dev/null +++ b/src/components/ui/Modals/MorphologyModal.svelte @@ -0,0 +1,15 @@ + + + +
+ +
+
diff --git a/src/components/ui/SettingsDrawer/QuranFontSelector.svelte b/src/components/ui/SettingsDrawer/QuranFontSelector.svelte index 7c4a3078..a45032f3 100644 --- a/src/components/ui/SettingsDrawer/QuranFontSelector.svelte +++ b/src/components/ui/SettingsDrawer/QuranFontSelector.svelte @@ -5,25 +5,8 @@ import { selectableFontTypes } from '$data/options'; import { updateSettings } from '$utils/updateSettings'; import { selectedRadioClasses } from '$data/commonClasses'; - - // fetching verse data - // $: fetchData = fetchVersesData('1:1', $__fontType, 1, 1, true); - -
{#each Object.entries(selectableFontTypes) as [id, font]} {#if !font.disallowedIn.includes($__currentPage)} diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 59c05959..5c8b7ec5 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -14,6 +14,7 @@ import SettingsSelectorModal from '$ui/Modals/SettingsSelectorModal.svelte'; import NewSiteChangelogModal from '$ui/Modals/NewSiteChangelogModal.svelte'; import VerseTranslationModal from '$ui/Modals/VerseTranslationModal.svelte'; + import MorphologyModal from '$ui/Modals/MorphologyModal.svelte'; import { __websiteOnline, __currentPage, __chapterNumber, __settingsDrawerHidden, __wakeLockEnabled, __userToken, __fontType, __wordTranslation, __verseTranslations, __selectedDisplayId, __mushafMinimalModeEnabled, __topNavbarVisible, __bottomToolbarVisible } from '$utils/stores'; import { checkOldBookmarks } from '$utils/checkOldBookmarks'; @@ -154,6 +155,7 @@ +
diff --git a/src/routes/bookmarks/+page.svelte b/src/routes/bookmarks/+page.svelte index 42c450f9..f4487e1d 100644 --- a/src/routes/bookmarks/+page.svelte +++ b/src/routes/bookmarks/+page.svelte @@ -2,12 +2,20 @@ import PageHead from '$misc/PageHead.svelte'; import Individual from '$display/verses/modes/Individual.svelte'; import Spinner from '$svgs/Spinner.svelte'; - import { __currentPage, __fontType, __displayType, __wordTranslation, __verseTranslations, __wordTransliteration, __userBookmarks } from '$utils/stores'; + import { __currentPage, __fontType, __displayType, __userBookmarks, __wordTranslation, __wordTransliteration, __verseTranslations } from '$utils/stores'; import { fetchVersesData } from '$utils/fetchData'; import { errorLoadingDataMessage } from '$data/websiteSettings'; // fetch verses whenever there's a change - $: fetchData = $__userBookmarks.length > 0 && fetchVersesData($__userBookmarks.toString(), $__fontType, $__wordTranslation, $__wordTransliteration, $__verseTranslations); + $: fetchData = + $__userBookmarks.length > 0 && + fetchVersesData({ + verses: $__userBookmarks.toString(), + fontType: $__fontType, + wordTranslation: $__wordTranslation, + wordTransliteration: $__wordTransliteration, + verseTranslations: $__verseTranslations + }); // only allow display type 1 & 2, and don't save the layout in settings if ([3, 4, 5].includes($__displayType)) $__displayType = 1; diff --git a/src/routes/morphology/[key]/+page.svelte b/src/routes/morphology/[key]/+page.svelte index 28fa87d9..f65c9264 100644 --- a/src/routes/morphology/[key]/+page.svelte +++ b/src/routes/morphology/[key]/+page.svelte @@ -2,69 +2,8 @@ export let data; import PageHead from '$misc/PageHead.svelte'; - import Spinner from '$svgs/Spinner.svelte'; - import WordsBlock from '$display/verses/WordsBlock.svelte'; - import Table from '$display/morphology/Table.svelte'; - import { quranMetaData } from '$data/quranMeta'; - import { apiEndpoint, errorLoadingDataMessage } from '$data/websiteSettings'; - import { __currentPage, __fontType, __wordTranslation, __wordTransliteration, __morphologyKey, __pageURL, __displayType, __lexiconModalVisible, __wordRoot } from '$utils/stores'; - import { buttonOutlineClasses } from '$data/commonClasses'; - import { fetchVersesData } from '$utils/fetchData'; - import { term } from '$utils/terminologies'; - - let fetchWordsData, fetchWordsData1, fetchWordSummary; - let chapter, verse, word; - - // Split the key to get chapter, verse, and word numbers - $: { - const keySplit = data.key.split(':'); - chapter = +keySplit[0]; - verse = +keySplit[1]; - word = keySplit.length === 2 ? 1 : +keySplit[2]; - - if (isNaN(word)) word = 1; - - __morphologyKey.set(`${chapter}:${verse}:${word}`); - } - - // Fetch verse data based on chapter and verse - $: fetchData = fetchVersesData(`${chapter}:${verse}`, $__fontType, $__wordTranslation, $__wordTransliteration); - - // Fetch words data for morphology - $: { - fetchWordsData = (async () => { - try { - const response = await fetch(`${apiEndpoint}/morphology?words=${$__morphologyKey}&word_translation=${$__wordTranslation}`); - const data = await response.json(); - fetchWordsData1 = data.data; - return data.data; - } catch (error) { - console.error(errorLoadingDataMessage, error); - return []; - } - })(); - - // Fetch word summary data - fetchWordSummary = (async () => { - try { - const response = await fetch(`${apiEndpoint}/morphology/summary?word=${$__morphologyKey}&version=2`); - const data = await response.json(); - return data.data; - } catch (error) { - console.error(errorLoadingDataMessage, error); - return {}; - } - })(); - } - - // Set the word root and show the lexicon modal - function showLexiconModal() { - const root = fetchWordsData1?.[0]?.morphology?.root?.root; - if (root) { - __wordRoot.set(root); - __lexiconModalVisible.set(true); - } - } + import MorphologyView from './MorphologyView.svelte'; + import { __currentPage, __morphologyKey, __displayType } from '$utils/stores'; // Restrict display types to 1 or 2 if (![1, 2].includes($__displayType)) $__displayType = 1; @@ -75,96 +14,4 @@ -
-
- - {#if verse === 1 && chapter > 1} - {@html '←'} {term('chapter')} {+chapter - 1} - {/if} - - - {#if verse > 1} - {@html '←'} {term('verse')} {chapter}:{+verse - 1} - {/if} - - - {#if verse < quranMetaData[chapter].verses} - {term('verse')} {chapter}:{+verse + 1} {@html '→'} - {/if} - - - {#if verse === quranMetaData[chapter].verses && chapter < 114} - {term('chapter')} {+chapter + 1} {@html '→'} - {/if} -
- -
- {#await fetchData} - - {:then fetchData} -
- {#each Object.entries(fetchData) as [key, value]} - - {/each} -
- {:catch error} -

{errorLoadingDataMessage}

- {/await} -
- -
- {#await fetchWordSummary} - ... - {:then fetchWordSummary} -
- {@html fetchWordSummary.summary} - -
- {:catch error} -

{errorLoadingDataMessage}

- {/await} -
- -
- {#await fetchWordsData} - - {:then fetchWordsData} - {#if !Object.values(fetchWordsData[0].morphology.verbs).every((o) => o === null)} -
- {#if Object.keys(fetchWordsData[0].morphology.root.words_with_same_root).length > 0} -
-
-
-
- {#each Object.entries(fetchWordsData[0].morphology.verbs) as [key, value]} - {#if value !== null} -
-
-

{value}

-
-

{key.replace('_', ' ')}

-
- {/if} - {/each} -
-
-
-
- {:else} -
Root data for this word is not available.
- {/if} -
- {/if} - -
- - - -
-
- - {:catch error} -

{errorLoadingDataMessage}

- {/await} - - + diff --git a/src/routes/morphology/[key]/MorphologyView.svelte b/src/routes/morphology/[key]/MorphologyView.svelte new file mode 100644 index 00000000..ab647da2 --- /dev/null +++ b/src/routes/morphology/[key]/MorphologyView.svelte @@ -0,0 +1,169 @@ + + +
+ {#if $__currentPage === 'morphology'} +
+ + {#if verse === 1 && chapter > 1} + {@html '←'} {term('chapter')} {+chapter - 1} + {/if} + + + {#if verse > 1} + {@html '←'} {term('verse')} {chapter}:{+verse - 1} + {/if} + + + {#if verse < quranMetaData[chapter].verses} + {term('verse')} {chapter}:{+verse + 1} {@html '→'} + {/if} + + + {#if verse === quranMetaData[chapter].verses && chapter < 114} + {term('chapter')} {+chapter + 1} {@html '→'} + {/if} +
+ {/if} + +
+ {#await fetchData} + + {:then fetchData} +
+ {#each Object.entries(fetchData) as [key, value]} + + {/each} +
+ {:catch error} +

{errorLoadingDataMessage}

+ {/await} +
+ +
+ {#await fetchWordSummary} + ... + {:then fetchWordSummary} +
+ {@html fetchWordSummary.summary} + +
+ {:catch error} +

{errorLoadingDataMessage}

+ {/await} +
+ +
+ {#await fetchWordsData} + + {:then fetchWordsData} + {#if !Object.values(fetchWordsData[0].morphology.verbs).every((o) => o === null)} +
+ {#if Object.keys(fetchWordsData[0].morphology.root.words_with_same_root).length > 0} +
+
+
+
+ {#each Object.entries(fetchWordsData[0].morphology.verbs) as [key, value]} + {#if value !== null} +
+
+

{value}

+
+

{key.replace('_', ' ')}

+
+ {/if} + {/each} +
+
+
+
+ {:else} +
Root data for this word is not available.
+ {/if} +
+ {/if} + +
+
+ + +
+
+ + {:catch error} +

{errorLoadingDataMessage}

+ {/await} + + diff --git a/src/components/display/morphology/Table.svelte b/src/routes/morphology/[key]/Table.svelte similarity index 100% rename from src/components/display/morphology/Table.svelte rename to src/routes/morphology/[key]/Table.svelte diff --git a/src/routes/search/+page.svelte b/src/routes/search/+page.svelte index 528f2feb..5052b1d4 100644 --- a/src/routes/search/+page.svelte +++ b/src/routes/search/+page.svelte @@ -6,7 +6,7 @@ import Individual from '$display/verses/modes/Individual.svelte'; import VerseTranslationSelector from '$ui/SettingsDrawer/VerseTranslationSelector.svelte'; import { goto } from '$app/navigation'; - import { __currentPage, __fontType, __wordTranslation, __verseTranslations, __wordTransliteration, __settingsSelectorModal } from '$utils/stores'; + import { __currentPage, __fontType, __wordTranslation, __wordTransliteration, __verseTranslations, __settingsSelectorModal } from '$utils/stores'; import { fetchVersesData } from '$utils/fetchData'; import { apiEndpoint, errorLoadingDataMessage } from '$data/websiteSettings'; import { buttonOutlineClasses } from '$data/commonClasses'; @@ -53,7 +53,13 @@ totalResults = pagination.total_records; pagePagination = pagination; - return await fetchVersesData(generateKeys(versesKeyData), $__fontType, $__wordTranslation, $__wordTransliteration, selectedTranslations); + return await fetchVersesData({ + verses: generateKeys(versesKeyData), + fontType: $__fontType, + wordTranslation: $__wordTranslation, + wordTransliteration: $__wordTransliteration, + verseTranslation: selectedTranslations + }); } } catch (error) { console.error(errorLoadingDataMessage, error); diff --git a/src/utils/fetchData.js b/src/utils/fetchData.js index 8c3ce3de..4a4ff345 100644 --- a/src/utils/fetchData.js +++ b/src/utils/fetchData.js @@ -51,41 +51,28 @@ export async function fetchVerseTranslationData(chapter, translations = get(__ve } // Fetch individual verses -export async function fetchVersesData(verses, fontType, wordTranslation, extras) { - __chapterData.set(null); +export async function fetchVersesData(props) { + if (!props.skipSave) __chapterData.set(null); - // we don't actuall need this data, but just have to pass it in this function so the page can re-render - console.log(extras); + // Set default props, we still try to get the props from function invokations for reactivity + if (!props.fontType) props.fontType = get(__fontType); + if (!props.wordTranslation) props.wordTranslation = get(__wordTranslation); + if (!props.wordTransliteration) props.wordTransliteration = get(__wordTransliteration); const apiURL = `${apiEndpoint}/verses?` + new URLSearchParams({ - verses: verses, - word_type: selectableFontTypes[fontType].apiId, - word_translation: wordTranslation, - word_transliteration: get(__wordTransliteration), + verses: props.verses, + word_type: selectableFontTypes[props.fontType].apiId, + word_translation: props.wordTranslation, + word_transliteration: props.wordTransliteration, verse_translation: '1,3', version: apiVersion }); const response = await fetch(apiURL); const data = await response.json(); - __chapterData.set(data.data.verses); - return data.data.verses; -} - -// Fetch single verses -export async function fetchSingleVerseData(verses, fontType) { - const apiURL = - `${apiEndpoint}/verses?` + - new URLSearchParams({ - verses: verses, - word_type: selectableFontTypes[fontType].apiId, - version: apiVersion - }); - - const response = await fetch(apiURL); - const data = await response.json(); + if (!props.skipSave) __chapterData.set(data.data.verses); return data.data.verses; } diff --git a/src/utils/stores.js b/src/utils/stores.js index 889b269f..e50ccbc3 100644 --- a/src/utils/stores.js +++ b/src/utils/stores.js @@ -54,6 +54,7 @@ let __websiteOnline, __lexiconModalVisible, __newSiteChangelogModalVisible, __verseTranslationModalVisible, + __morphologyModalVisible, __wakeLockEnabled, __quizCorrectAnswers, __quizWrongAnswers, @@ -214,6 +215,7 @@ if (browser) { __lexiconModalVisible = writable(false); __newSiteChangelogModalVisible = writable(false); __verseTranslationModalVisible = writable(false); + __morphologyModalVisible = writable(false); // wake lock settings __wakeLockEnabled = writable(userSettings.displaySettings.wakeLockEnabled); @@ -301,6 +303,7 @@ export { __lexiconModalVisible, __newSiteChangelogModalVisible, __verseTranslationModalVisible, + __morphologyModalVisible, __wakeLockEnabled, __quizCorrectAnswers, __quizWrongAnswers, diff --git a/src/views/Supplications.svelte b/src/views/Supplications.svelte index 10466116..241fed53 100644 --- a/src/views/Supplications.svelte +++ b/src/views/Supplications.svelte @@ -3,14 +3,20 @@ import PageHead from '$misc/PageHead.svelte'; import Individual from '$display/verses/modes/Individual.svelte'; import Spinner from '$svgs/Spinner.svelte'; - import { __currentPage, __fontType, __displayType, __wordTranslation, __verseTranslations, __wordTransliteration } from '$utils/stores'; + import { __currentPage, __fontType, __wordTranslation, __wordTransliteration, __verseTranslations } from '$utils/stores'; import { fetchVersesData } from '$utils/fetchData'; import { errorLoadingDataMessage } from '$data/websiteSettings'; import { term } from '$utils/terminologies'; import { supplicationsFromQuran } from '$data/quranMeta'; // Fetch supplication verses whenever necessary - $: fetchData = fetchVersesData(getSupplicationKeys(), $__fontType, $__wordTranslation, $__wordTransliteration, $__verseTranslations); + $: fetchData = fetchVersesData({ + verses: getSupplicationKeys(), + fontType: $__fontType, + wordTranslation: $__wordTranslation, + wordTransliteration: $__wordTransliteration, + verseTranslation: $__verseTranslations + }); // Function to get a string of all supplications chapter:verses function getSupplicationKeys() { diff --git a/static/css/global.css b/static/css/global.css index a4b3b2f2..0c2fc7cb 100644 --- a/static/css/global.css +++ b/static/css/global.css @@ -1482,6 +1482,10 @@ input[type="range"].range-lg::-moz-range-thumb { max-height: 70vh; } +.max-h-\[80vh\] { + max-height: 80vh; +} + .max-h-\[90\%\] { max-height: 90%; }