diff --git a/src/components/Navbar/NavbarBody/index.tsx b/src/components/Navbar/NavbarBody/index.tsx index 6f62d036ce..9e0f0f038a 100644 --- a/src/components/Navbar/NavbarBody/index.tsx +++ b/src/components/Navbar/NavbarBody/index.tsx @@ -4,6 +4,8 @@ import dynamic from 'next/dynamic'; import useTranslation from 'next-translate/useTranslation'; import { useDispatch } from 'react-redux'; +import SettingsDrawer from '../SettingsDrawer/SettingsDrawer'; + import styles from './NavbarBody.module.scss'; import ProfileAvatarButton from './ProfileAvatarButton'; @@ -11,16 +13,13 @@ import LanguageSelector from '@/components/Navbar/LanguageSelector'; import NavbarLogoWrapper from '@/components/Navbar/Logo/NavbarLogoWrapper'; import NavigationDrawer from '@/components/Navbar/NavigationDrawer/NavigationDrawer'; import SearchDrawer from '@/components/Navbar/SearchDrawer/SearchDrawer'; -import SettingsDrawer from '@/components/Navbar/SettingsDrawer/SettingsDrawer'; import Button, { ButtonShape, ButtonVariant } from '@/dls/Button/Button'; import Spinner from '@/dls/Spinner/Spinner'; import IconMenu from '@/icons/menu.svg'; import IconSearch from '@/icons/search.svg'; -import IconSettings from '@/icons/settings.svg'; import { setIsSearchDrawerOpen, setIsNavigationDrawerOpen, - setIsSettingsDrawerOpen, setDisableSearchDrawerTransition, } from '@/redux/slices/navbar'; import { logEvent } from '@/utils/eventLogger'; @@ -58,11 +57,6 @@ const NavbarBody: React.FC = () => { dispatch({ type: setDisableSearchDrawerTransition.type, payload: false }); }; - const openSettingsDrawer = () => { - logDrawerOpenEvent('settings'); - dispatch({ type: setIsSettingsDrawerOpen.type, payload: true }); - }; - return (
@@ -87,17 +81,6 @@ const NavbarBody: React.FC = () => { <> - - <> +
diff --git a/src/components/QuranReader/ContextMenu/components/SettingsButton.module.scss b/src/components/QuranReader/ContextMenu/components/SettingsButton.module.scss new file mode 100644 index 0000000000..19edd267ba --- /dev/null +++ b/src/components/QuranReader/ContextMenu/components/SettingsButton.module.scss @@ -0,0 +1,4 @@ +.settingsButtonIcon { + color: var(--color-blue-buttons-and-icons); + fill: var(--color-blue-buttons-and-icons); +} \ No newline at end of file diff --git a/src/components/QuranReader/ContextMenu/components/SettingsButton.tsx b/src/components/QuranReader/ContextMenu/components/SettingsButton.tsx new file mode 100644 index 0000000000..7f19594c2c --- /dev/null +++ b/src/components/QuranReader/ContextMenu/components/SettingsButton.tsx @@ -0,0 +1,44 @@ +import React from 'react'; + +import useTranslation from 'next-translate/useTranslation'; +import { useDispatch } from 'react-redux'; + +import styles from './SettingsButton.module.scss'; + +import Button, { ButtonShape, ButtonVariant } from '@/dls/Button/Button'; +import IconSettings from '@/icons/settings.svg'; +import { setIsSettingsDrawerOpen } from '@/redux/slices/navbar'; +import { logEvent } from '@/utils/eventLogger'; + +interface SettingsButtonProps { + className?: string; + ariaId?: string; +} + +const SettingsButton: React.FC = ({ + className, + ariaId = 'settings-button', +}) => { + const { t } = useTranslation('common'); + const dispatch = useDispatch(); + const openSettings = () => { + logEvent('drawer_settings_open'); + dispatch(setIsSettingsDrawerOpen(true)); + }; + + return ( + + ); +}; + +export default SettingsButton; diff --git a/src/components/QuranReader/ContextMenu/index.tsx b/src/components/QuranReader/ContextMenu/index.tsx index b3607f067c..1cf8664aa0 100644 --- a/src/components/QuranReader/ContextMenu/index.tsx +++ b/src/components/QuranReader/ContextMenu/index.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useMemo } from 'react'; import classNames from 'classnames'; @@ -11,6 +11,7 @@ import ChapterNavigation from './components/ChapterNavigation'; import MobileReadingTabs from './components/MobileReadingTabs'; import PageInfo from './components/PageInfo'; import ProgressBar from './components/ProgressBar'; +import SettingsButton from './components/SettingsButton'; import useContextMenuState from './hooks/useContextMenuState'; import styles from './styles/ContextMenu.module.scss'; @@ -48,14 +49,15 @@ const ContextMenu: React.FC = (): JSX.Element | null => { handleSidebarToggle, } = useContextMenuState(); + const isMobileView = useMemo(() => isMobile(), []); + const isMobileScrolledView = !showNavbar && isMobileView; + const isNotMobileOrScrolledView = !showNavbar || !isMobileView; + // Early return if no verse key (SSR or first render) if (!verseKey || !chapterData) { return null; } - const isMobileScrolledView = !showNavbar && isMobile(); - const isNotMobileOrScrolledView = !showNavbar || !isMobile(); - return (
{
{/* Chapter Navigation Section */}
-
- +
+
+ + {showNavbar && } +
@@ -116,12 +121,17 @@ const ContextMenu: React.FC = (): JSX.Element | null => { [styles.hideReadingPreferenceSectionOnMobile]: showNavbar, })} > - +
+ + {(!isMobileView || !showNavbar) && ( + + )} +
diff --git a/src/components/QuranReader/ContextMenu/styles/ContextMenu.module.scss b/src/components/QuranReader/ContextMenu/styles/ContextMenu.module.scss index 815a09d0ae..5d925095d2 100644 --- a/src/components/QuranReader/ContextMenu/styles/ContextMenu.module.scss +++ b/src/components/QuranReader/ContextMenu/styles/ContextMenu.module.scss @@ -62,12 +62,17 @@ $pixel: 1px; padding-block: calc(var(--spacing-medium) / 2); display: flex; align-items: center; - padding-inline: calc(1.3 * var(--spacing-large)); + padding-inline: var(--spacing-medium3-px); z-index: var(--z-index-default); position: relative; background: var(--color-background-elevated); + @include breakpoints.tablet { - padding-inline: calc(1.2 * var(--spacing-mega)); + padding-inline: var(--spacing-xlarge-px); + } + + @include breakpoints.smallerThanTablet { + padding-inline: var(--spacing-medium3-px); } } @@ -100,6 +105,51 @@ $pixel: 1px; } } +.readingPreferenceContainer { + display: flex; + align-items: center; + column-gap: var(--spacing-medium); +} + +.chapterNavigationRow { + align-items: center; + flex-direction: row; +} + +.chapterNavigationWrapper { + display: flex; + align-items: center; + column-gap: var(--spacing-medium); + width: 100%; + justify-content: space-between; + + @include breakpoints.tablet { + padding-inline: var(--spacing-medium2-px); + } +} + +.visibleContainer .chapterNavigationWrapper { + @include breakpoints.smallerThanTablet { + width: 90vw; + } +} + +.settingsNextToChapter { + display: inline-flex; + + @include breakpoints.tablet { + display: none; + } + + @include breakpoints.smallerThanTablet { + display: inline-flex; + } +} + +.settingsNextToSwitcher { + display: inline-flex; +} + .hideReadingPreferenceSectionOnMobile { @include breakpoints.smallerThanTablet { visibility: hidden; @@ -153,6 +203,7 @@ $pixel: 1px; color: var(--color-text-default); } } + .bookmarkedIcon { color: var(--color-text-default); } @@ -173,6 +224,7 @@ $pixel: 1px; align-items: center; cursor: pointer; } + .chevronIconContainer { display: inline-flex; align-items: center; @@ -189,6 +241,7 @@ $pixel: 1px; .rotateAuto { transition: var(--transition-fast); transform: rotate(0); + @include breakpoints.tablet { transition: var(--transition-fast); transform: rotate(180deg); @@ -197,6 +250,7 @@ $pixel: 1px; .disabledOnMobile { pointer-events: none; + @include breakpoints.tablet { pointer-events: inherit; } @@ -207,4 +261,4 @@ $pixel: 1px; display: flex; align-items: center; font-weight: var(--font-weight-semibold); -} +} \ No newline at end of file diff --git a/tests/integration/quran-reader/settings-gear.spec.ts b/tests/integration/quran-reader/settings-gear.spec.ts new file mode 100644 index 0000000000..37ad72e923 --- /dev/null +++ b/tests/integration/quran-reader/settings-gear.spec.ts @@ -0,0 +1,37 @@ +import { test, expect } from '@playwright/test'; + +test('desktop: settings gear opens the settings drawer', async ({ page }) => { + await page.setViewportSize({ width: 1280, height: 900 }); + await page.goto('/1'); + + const settingsButtons = page.locator('#settings-button'); + await expect(settingsButtons.last()).toBeVisible(); + await settingsButtons.last().click(); + + await expect(page.locator('#settings-drawer-container')).toBeVisible(); + await expect(page.locator('#settings-drawer-body')).toBeVisible(); +}); + +test('mobile: gear works before and after scroll (navbar hidden)', async ({ page }) => { + await page.setViewportSize({ width: 390, height: 844 }); + await page.goto('/1'); + + const settingsButtons = page.locator('#settings-button'); + await expect(settingsButtons.first()).toBeVisible(); + await settingsButtons.first().click(); + await expect(page.locator('#settings-drawer-container')).toBeVisible(); + await expect(page.locator('#settings-drawer-body')).toBeVisible(); + + await page + .locator('#settings-drawer-container') + .getByRole('button', { name: /close drawer/i }) + .first() + .click(); + + await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)); + + await expect(settingsButtons.last()).toBeVisible(); + await settingsButtons.last().click(); + await expect(page.locator('#settings-drawer-container')).toBeVisible(); + await expect(page.locator('#settings-drawer-body')).toBeVisible(); +});