diff options
| author | 2024-12-04 22:30:04 +0100 | |
|---|---|---|
| committer | 2024-12-04 22:30:04 +0100 | |
| commit | be9b6c7290dddcd8b8b6a8926bd101b7123528b3 (patch) | |
| tree | 4cc15beac7620c8665028b3f1a9800e38bf2a0a2 | |
| parent | e9f392201006c907a20ba5046252d056bd5c4426 (diff) | |
Implement showing and hiding header depending on scroll (#7029)
* Implement showing and hiding header depending on scroll
References #7011.
* header.phtml: adjust indentation
* minor efficiency improvement
* Update p/scripts/main.js
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
---------
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
| -rw-r--r-- | app/layout/header.phtml | 230 | ||||
| -rw-r--r-- | p/scripts/main.js | 18 | ||||
| -rw-r--r-- | p/themes/base-theme/frss.css | 13 | ||||
| -rw-r--r-- | p/themes/base-theme/frss.rtl.css | 13 |
4 files changed, 160 insertions, 114 deletions
diff --git a/app/layout/header.phtml b/app/layout/header.phtml index ad0a5e8e2..71272af87 100644 --- a/app/layout/header.phtml +++ b/app/layout/header.phtml @@ -2,124 +2,126 @@ declare(strict_types=1); /** @var FreshRSS_View $this */ ?> -<header class="header"> - <div class="item title"> - <a href="<?= Minz_Url::display(['c' => 'index', 'a' => 'index'], 'html', 'root') ?>"> - <?php if (FreshRSS_Context::systemConf()->logo_html == '') { ?> - <img class="logo" src="<?= _i('FreshRSS-logo', FreshRSS_Themes::ICON_URL) ?>" alt="FreshRSS" loading="lazy" /> - <?php - } else { - echo FreshRSS_Context::systemConf()->logo_html; - } - ?> - </a> - </div> +<div class="header-wrapper"> + <header class="header"> + <div class="item title"> + <a href="<?= Minz_Url::display(['c' => 'index', 'a' => 'index'], 'html', 'root') ?>"> + <?php if (FreshRSS_Context::systemConf()->logo_html == '') { ?> + <img class="logo" src="<?= _i('FreshRSS-logo', FreshRSS_Themes::ICON_URL) ?>" alt="FreshRSS" loading="lazy" /> + <?php + } else { + echo FreshRSS_Context::systemConf()->logo_html; + } + ?> + </a> + </div> - <div class="item search"> - <?php if (FreshRSS_Auth::hasAccess() || FreshRSS_Context::systemConf()->allow_anonymous) { ?> - <form action="<?= $this->html_url ?>" method="get"> - <?php if (Minz_Request::controllerName() === 'index'): ?> - <?php if (in_array(Minz_Request::actionName(), ['normal', 'global', 'reader'], true)) { ?> - <input type="hidden" name="a" value="<?= Minz_Request::actionName() ?>" /> - <?php } if (Minz_Request::paramString('get') !== '') { ?> - <input type="hidden" name="get" value="<?= FreshRSS_Context::currentGet() ?>" /> - <?php } if (Minz_Request::paramInt('state') !== 0) { ?> - <input type="hidden" name="state" value="<?= Minz_Request::paramInt('state') ?>" /> + <div class="item search"> + <?php if (FreshRSS_Auth::hasAccess() || FreshRSS_Context::systemConf()->allow_anonymous) { ?> + <form action="<?= $this->html_url ?>" method="get"> + <?php if (Minz_Request::controllerName() === 'index'): ?> + <?php if (in_array(Minz_Request::actionName(), ['normal', 'global', 'reader'], true)) { ?> + <input type="hidden" name="a" value="<?= Minz_Request::actionName() ?>" /> + <?php } if (Minz_Request::paramString('get') !== '') { ?> + <input type="hidden" name="get" value="<?= FreshRSS_Context::currentGet() ?>" /> + <?php } if (Minz_Request::paramInt('state') !== 0) { ?> + <input type="hidden" name="state" value="<?= Minz_Request::paramInt('state') ?>" /> + <?php } ?> + <?php endif; ?> + <?php if (Minz_Request::paramString('user') !== '') { ?> + <input type="hidden" name="user" value="<?= Minz_User::name() ?>" /> + <?php } if (ctype_alnum(Minz_Request::paramString('t'))) { ?> + <input type="hidden" name="t" value="<?= Minz_Request::paramString('t') ?>" /> + <?php } if (ctype_upper(Minz_Request::paramString('order'))) { ?> + <input type="hidden" name="order" value="<?= FreshRSS_Context::$order ?>" /> + <?php } if (ctype_lower(Minz_Request::paramString('f'))) { ?> + <input type="hidden" name="f" value="<?= Minz_Request::paramString('f') ?>" /> <?php } ?> - <?php endif; ?> - <?php if (Minz_Request::paramString('user') !== '') { ?> - <input type="hidden" name="user" value="<?= Minz_User::name() ?>" /> - <?php } if (ctype_alnum(Minz_Request::paramString('t'))) { ?> - <input type="hidden" name="t" value="<?= Minz_Request::paramString('t') ?>" /> - <?php } if (ctype_upper(Minz_Request::paramString('order'))) { ?> - <input type="hidden" name="order" value="<?= FreshRSS_Context::$order ?>" /> - <?php } if (ctype_lower(Minz_Request::paramString('f'))) { ?> - <input type="hidden" name="f" value="<?= Minz_Request::paramString('f') ?>" /> + <div class="stick"> + <input type="search" name="search" id="search" + value="<?= htmlspecialchars(htmlspecialchars_decode(Minz_Request::paramString('search'), ENT_QUOTES), ENT_COMPAT, 'UTF-8') ?>" + placeholder="<?= _t('gen.menu.search') ?>" /> + <button class="btn" type="submit"><?= _i('search') ?></button> + </div> + </form> <?php } ?> - <div class="stick"> - <input type="search" name="search" id="search" - value="<?= htmlspecialchars(htmlspecialchars_decode(Minz_Request::paramString('search'), ENT_QUOTES), ENT_COMPAT, 'UTF-8') ?>" - placeholder="<?= _t('gen.menu.search') ?>" /> - <button class="btn" type="submit"><?= _i('search') ?></button> - </div> - </form> - <?php } ?> - </div> + </div> - <?php if (FreshRSS_Auth::hasAccess()) { ?> - <nav class="item configure"> - <div class="dropdown"> - <div id="dropdown-configure" class="dropdown-target"></div> - <a class="btn dropdown-toggle" href="#dropdown-configure"><?= _i('configure') ?></a> - <ul class="dropdown-menu scrollbar-thin"> - <li class="dropdown-header-close"><a class="toggle_aside" href="#close"><?= _i('close') ?></a></li> + <?php if (FreshRSS_Auth::hasAccess()) { ?> + <nav class="item configure"> + <div class="dropdown"> + <div id="dropdown-configure" class="dropdown-target"></div> + <a class="btn dropdown-toggle" href="#dropdown-configure"><?= _i('configure') ?></a> + <ul class="dropdown-menu scrollbar-thin"> + <li class="dropdown-header-close"><a class="toggle_aside" href="#close"><?= _i('close') ?></a></li> - <li class="item dropdown-section"> - <div class="dropdown-section-title"> - <?= _t('gen.menu.account') ?>: <?= htmlspecialchars(Minz_User::name() ?? '', ENT_NOQUOTES, 'UTF-8') ?> - </div> - <ul> - <li class="item"><a href="<?= _url('user', 'profile') ?>"><?= _t('gen.menu.user_profile') ?></a></li> - <?php if (FreshRSS_Auth::accessNeedsAction()): ?> - <li class="item"><a class="signout" href="<?= _url('auth', 'logout') ?>"><?= _t('gen.auth.logout'); ?><?= _i('logout') ?></a></li> - <?php else: ?> - <li class="item"><span class="signout">(<?= htmlspecialchars(Minz_User::name() ?? '', ENT_NOQUOTES, 'UTF-8') ?>)</span></li> - <?php endif; ?> - </ul> - </li> - <li class="item dropdown-section"> - <div class="dropdown-section-title"> - <?= _t('gen.menu.configuration') ?> - </div> - <ul> - <li class="item"><a href="<?= _url('configure', 'display') ?>"><?= _t('gen.menu.display') ?></a></li> - <li class="item"><a href="<?= _url('configure', 'reading') ?>"><?= _t('gen.menu.reading') ?></a></li> - <li class="item"><a href="<?= _url('configure', 'archiving') ?>"><?= _t('gen.menu.archiving') ?></a></li> - <li class="item"><a href="<?= _url('configure', 'integration') ?>"><?= _t('gen.menu.sharing') ?></a></li> - <li class="item"><a href="<?= _url('configure', 'shortcut') ?>"><?= _t('gen.menu.shortcuts') ?></a></li> - <li class="item"><a href="<?= _url('configure', 'queries') ?>"><?= _t('gen.menu.queries') ?></a></li> - <li class="item"><a href="<?= _url('extension', 'index') ?>"><?= _t('gen.menu.extensions') ?></a></li> - <li class="item"><a href="<?= _url('configure', 'privacy') ?>"><?= _t('gen.menu.privacy') ?></a></li> - <?= Minz_ExtensionManager::callHookString('menu_configuration_entry') ?> - </ul> - </li> - <?php if (FreshRSS_Auth::hasAccess('admin')) { ?> - <li class="item dropdown-section"> - <div class="dropdown-section-title"> - <?= _t('gen.menu.admin') ?> - </div> - <ul> - <li class="item"><a href="<?= _url('configure', 'system') ?>"><?= _t('gen.menu.system') ?></a></li> - <li class="item"><a href="<?= _url('user', 'manage') ?>"><?= _t('gen.menu.user_management') ?></a></li> - <li class="item"><a href="<?= _url('auth', 'index') ?>"><?= _t('gen.menu.authentication') ?></a></li> - <li class="item"><a href="<?= _url('update', 'checkInstall') ?>"><?= _t('gen.menu.check_install') ?></a></li> - <?php if (!FreshRSS_Context::systemConf()->disable_update) { ?> - <li class="item"><a href="<?= _url('update', 'index') ?>"><?= _t('gen.menu.update') ?></a></li> - <?php } ?> - <?= Minz_ExtensionManager::callHookString('menu_admin_entry') ?> - </ul> - </li> - <?php } ?> + <li class="item dropdown-section"> + <div class="dropdown-section-title"> + <?= _t('gen.menu.account') ?>: <?= htmlspecialchars(Minz_User::name() ?? '', ENT_NOQUOTES, 'UTF-8') ?> + </div> + <ul> + <li class="item"><a href="<?= _url('user', 'profile') ?>"><?= _t('gen.menu.user_profile') ?></a></li> + <?php if (FreshRSS_Auth::accessNeedsAction()): ?> + <li class="item"><a class="signout" href="<?= _url('auth', 'logout') ?>"><?= _t('gen.auth.logout'); ?><?= _i('logout') ?></a></li> + <?php else: ?> + <li class="item"><span class="signout">(<?= htmlspecialchars(Minz_User::name() ?? '', ENT_NOQUOTES, 'UTF-8') ?>)</span></li> + <?php endif; ?> + </ul> + </li> + <li class="item dropdown-section"> + <div class="dropdown-section-title"> + <?= _t('gen.menu.configuration') ?> + </div> + <ul> + <li class="item"><a href="<?= _url('configure', 'display') ?>"><?= _t('gen.menu.display') ?></a></li> + <li class="item"><a href="<?= _url('configure', 'reading') ?>"><?= _t('gen.menu.reading') ?></a></li> + <li class="item"><a href="<?= _url('configure', 'archiving') ?>"><?= _t('gen.menu.archiving') ?></a></li> + <li class="item"><a href="<?= _url('configure', 'integration') ?>"><?= _t('gen.menu.sharing') ?></a></li> + <li class="item"><a href="<?= _url('configure', 'shortcut') ?>"><?= _t('gen.menu.shortcuts') ?></a></li> + <li class="item"><a href="<?= _url('configure', 'queries') ?>"><?= _t('gen.menu.queries') ?></a></li> + <li class="item"><a href="<?= _url('extension', 'index') ?>"><?= _t('gen.menu.extensions') ?></a></li> + <li class="item"><a href="<?= _url('configure', 'privacy') ?>"><?= _t('gen.menu.privacy') ?></a></li> + <?= Minz_ExtensionManager::callHookString('menu_configuration_entry') ?> + </ul> + </li> + <?php if (FreshRSS_Auth::hasAccess('admin')) { ?> + <li class="item dropdown-section"> + <div class="dropdown-section-title"> + <?= _t('gen.menu.admin') ?> + </div> + <ul> + <li class="item"><a href="<?= _url('configure', 'system') ?>"><?= _t('gen.menu.system') ?></a></li> + <li class="item"><a href="<?= _url('user', 'manage') ?>"><?= _t('gen.menu.user_management') ?></a></li> + <li class="item"><a href="<?= _url('auth', 'index') ?>"><?= _t('gen.menu.authentication') ?></a></li> + <li class="item"><a href="<?= _url('update', 'checkInstall') ?>"><?= _t('gen.menu.check_install') ?></a></li> + <?php if (!FreshRSS_Context::systemConf()->disable_update) { ?> + <li class="item"><a href="<?= _url('update', 'index') ?>"><?= _t('gen.menu.update') ?></a></li> + <?php } ?> + <?= Minz_ExtensionManager::callHookString('menu_admin_entry') ?> + </ul> + </li> + <?php } ?> - <li class="item dropdown-section"> - <ul> - <li class="item"><a href="<?= _url('index', 'logs') ?>"><?= _t('gen.menu.logs') ?></a></li> - <li class="item"><a href="<?= _url('index', 'about') ?>"><?= _t('gen.menu.about') ?></a></li> - <?php if (file_exists(TOS_FILENAME)) { ?> - <li class="item"> - <a href="<?= _url('index', 'tos') ?>"><?= _t('index.tos.title')?></a> - </li> - <?php } ?> - <?= Minz_ExtensionManager::callHookString('menu_other_entry') ?> - </ul> - </li> - </ul> - <a class="dropdown-close" href="#close">❌</a> + <li class="item dropdown-section"> + <ul> + <li class="item"><a href="<?= _url('index', 'logs') ?>"><?= _t('gen.menu.logs') ?></a></li> + <li class="item"><a href="<?= _url('index', 'about') ?>"><?= _t('gen.menu.about') ?></a></li> + <?php if (file_exists(TOS_FILENAME)) { ?> + <li class="item"> + <a href="<?= _url('index', 'tos') ?>"><?= _t('index.tos.title')?></a> + </li> + <?php } ?> + <?= Minz_ExtensionManager::callHookString('menu_other_entry') ?> + </ul> + </li> + </ul> + <a class="dropdown-close" href="#close">❌</a> + </div> + </nav> + <?php } elseif (FreshRSS_Auth::accessNeedsAction()) { ?> + <div class="item configure"> + <a class="signin" href="<?= Minz_Url::display(['c' => 'auth', 'a' => 'login'], 'html', 'root') ?>"><?= _i('login') ?><?= _t('gen.auth.login') ?></a> </div> - </nav> - <?php } elseif (FreshRSS_Auth::accessNeedsAction()) { ?> - <div class="item configure"> - <a class="signin" href="<?= Minz_Url::display(['c' => 'auth', 'a' => 'login'], 'html', 'root') ?>"><?= _i('login') ?><?= _t('gen.auth.login') ?></a> - </div> - <?php } ?> -</header> + <?php } ?> + </header> +</div> diff --git a/p/scripts/main.js b/p/scripts/main.js index f74e36553..4da89f228 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1954,6 +1954,23 @@ function init_confirm_action() { document.querySelectorAll('button.confirm').forEach(function (b) { b.disabled = false; }); } +function init_scroll_header() { + const header = document.querySelector('header.header'); + if (header) { + const headerHeight = parseInt(getComputedStyle(header).height); + header.previousScroll = 0; + window.addEventListener('scroll', function () { + const currentScroll = window.scrollY; + if (currentScroll > headerHeight && currentScroll > header.previousScroll) { + header.classList.add('hide'); + } else { + header.classList.remove('hide'); + } + header.previousScroll = currentScroll; + }); + } +} + function faviconNbUnread(n) { if (typeof n === 'undefined') { const t = document.querySelector('.category.all .title'); @@ -2040,6 +2057,7 @@ function init_main_afterDOM() { removeFirstLoadSpinner(); init_notifications(); init_confirm_action(); + init_scroll_header(); const stream = document.getElementById('stream'); if (stream) { init_load_more(stream); diff --git a/p/themes/base-theme/frss.css b/p/themes/base-theme/frss.css index b1825c96d..1412ac5f0 100644 --- a/p/themes/base-theme/frss.css +++ b/p/themes/base-theme/frss.css @@ -1159,11 +1159,24 @@ li.drag-hover { /*=== STRUCTURE */ /*===============*/ /*=== Header */ +.header-wrapper { + height: calc(2.5rem + 2 * var(--frss-padding-top-bottom)); +} + .header { + position: fixed; + top: 0; + left: 0; display: table; width: 100%; height: calc(2.5rem + 2 * var(--frss-padding-top-bottom)); table-layout: fixed; + transition: transform 0.3s; + z-index: 110; +} + +.header.hide { + transform: translateY(calc(-2.5rem - 2 * var(--frss-padding-top-bottom))); } .header > .item { diff --git a/p/themes/base-theme/frss.rtl.css b/p/themes/base-theme/frss.rtl.css index 460756cbc..b5234bc49 100644 --- a/p/themes/base-theme/frss.rtl.css +++ b/p/themes/base-theme/frss.rtl.css @@ -1159,11 +1159,24 @@ li.drag-hover { /*=== STRUCTURE */ /*===============*/ /*=== Header */ +.header-wrapper { + height: calc(2.5rem + 2 * var(--frss-padding-top-bottom)); +} + .header { + position: fixed; + top: 0; + right: 0; display: table; width: 100%; height: calc(2.5rem + 2 * var(--frss-padding-top-bottom)); table-layout: fixed; + transition: transform 0.3s; + z-index: 110; +} + +.header.hide { + transform: translateY(calc(-2.5rem - 2 * var(--frss-padding-top-bottom))); } .header > .item { |
