Modified - [navbar] [sticky-ui] [user-settings] Added a show/hide toggle tab for the persistent navigation bar.
- 1 - I updated `templates/base/head_navbar.tmpl`, `web_src/css/modules/navbar.css`, and `web_src/css/modules/flexcontainer.css` so pages with `Keep the navigation bar visible while scrolling` now show a small bottom-right toggle tab that collapses the sticky navbar to a minimal visible handle and restores it on demand while keeping sticky offsets aligned. - 2 - I updated `web_src/js/features/common-page.ts` so the toggle state is applied on page load and stored in local user settings under `persistent-navbar-collapsed`, preserving the chosen shown/hidden state across navigation. - 3 - I added the new show/hide navbar labels to `options/locale/locale_en-US.json` and `options/locale/locale_ro-RO.json`. - 4 - I refined the navbar toggle geometry in `web_src/css/modules/navbar.css` and `web_src/css/modules/flexcontainer.css` so the handle now sits like a slim tab just below the navbar border, is pushed closer to the right edge, and leaves only the handle visible when the persistent navbar is collapsed.
This commit is contained in:
@@ -793,3 +793,9 @@ History search guidance:
|
|||||||
158 - [2026-05-18 23:03:13] - v1.27.0-dev-169-g69356f6de0 - Type: Modified - [repo-diff] [sticky-ui] [navbar] Prevented sticky diff headers from sliding under the persistent navigation bar.
|
158 - [2026-05-18 23:03:13] - v1.27.0-dev-169-g69356f6de0 - Type: Modified - [repo-diff] [sticky-ui] [navbar] Prevented sticky diff headers from sliding under the persistent navigation bar.
|
||||||
- 1 - I updated `web_src/css/repo.css` so the sticky repository diff summary bar, the sticky second-row file headers, and the diff file scroll anchor margin now all include `--persistent-navbar-offset`, keeping them visible below the navbar when `Keep the navigation bar visible while scrolling` is enabled.
|
- 1 - I updated `web_src/css/repo.css` so the sticky repository diff summary bar, the sticky second-row file headers, and the diff file scroll anchor margin now all include `--persistent-navbar-offset`, keeping them visible below the navbar when `Keep the navigation bar visible while scrolling` is enabled.
|
||||||
- 2 - I extended the same offset handling to `#diff-file-tree` so the sticky diff file tree no longer slides under the diff summary bar after the persistent-navbar preference shifts the sticky stack downward.
|
- 2 - I extended the same offset handling to `#diff-file-tree` so the sticky diff file tree no longer slides under the diff summary bar after the persistent-navbar preference shifts the sticky stack downward.
|
||||||
|
|
||||||
|
159 - [2026-05-19 01:10:25] - v1.27.0-dev-171-gc40e1cf08f - Type: Modified - [navbar] [sticky-ui] [user-settings] Added a show/hide toggle tab for the persistent navigation bar.
|
||||||
|
- 1 - I updated `templates/base/head_navbar.tmpl`, `web_src/css/modules/navbar.css`, and `web_src/css/modules/flexcontainer.css` so pages with `Keep the navigation bar visible while scrolling` now show a small bottom-right toggle tab that collapses the sticky navbar to a minimal visible handle and restores it on demand while keeping sticky offsets aligned.
|
||||||
|
- 2 - I updated `web_src/js/features/common-page.ts` so the toggle state is applied on page load and stored in local user settings under `persistent-navbar-collapsed`, preserving the chosen shown/hidden state across navigation.
|
||||||
|
- 3 - I added the new show/hide navbar labels to `options/locale/locale_en-US.json` and `options/locale/locale_ro-RO.json`.
|
||||||
|
- 4 - I refined the navbar toggle geometry in `web_src/css/modules/navbar.css` and `web_src/css/modules/flexcontainer.css` so the handle now sits like a slim tab just below the navbar border, is pushed closer to the right edge, and leaves only the handle visible when the persistent navbar is collapsed.
|
||||||
|
|||||||
@@ -189,6 +189,8 @@
|
|||||||
"search.pull_kind": "Search pull requests…",
|
"search.pull_kind": "Search pull requests…",
|
||||||
"search.keyword_search_unavailable": "Searching by keyword is currently not available. Please contact the site administrator.",
|
"search.keyword_search_unavailable": "Searching by keyword is currently not available. Please contact the site administrator.",
|
||||||
"aria.navbar": "Navigation Bar",
|
"aria.navbar": "Navigation Bar",
|
||||||
|
"navbar.show": "Show navigation bar",
|
||||||
|
"navbar.hide": "Hide navigation bar",
|
||||||
"aria.footer": "Footer",
|
"aria.footer": "Footer",
|
||||||
"aria.footer.software": "About Software",
|
"aria.footer.software": "About Software",
|
||||||
"aria.footer.links": "Links",
|
"aria.footer.links": "Links",
|
||||||
|
|||||||
@@ -189,6 +189,8 @@
|
|||||||
"search.pull_kind": "Caută cereri de pull...",
|
"search.pull_kind": "Caută cereri de pull...",
|
||||||
"search.keyword_search_unavailable": "Căutarea după cuvânt cheie nu este disponibilă momentan. Te rugăm să contactezi administratorul site-ului.",
|
"search.keyword_search_unavailable": "Căutarea după cuvânt cheie nu este disponibilă momentan. Te rugăm să contactezi administratorul site-ului.",
|
||||||
"aria.navbar": "Bara de navigare",
|
"aria.navbar": "Bara de navigare",
|
||||||
|
"navbar.show": "Arată bara de navigare",
|
||||||
|
"navbar.hide": "Ascunde bara de navigare",
|
||||||
"aria.footer": "Subsol",
|
"aria.footer": "Subsol",
|
||||||
"aria.footer.software": "Despre software",
|
"aria.footer.software": "Despre software",
|
||||||
"aria.footer.links": "Link-uri",
|
"aria.footer.links": "Link-uri",
|
||||||
|
|||||||
@@ -162,6 +162,21 @@
|
|||||||
</div><!-- end full right menu -->
|
</div><!-- end full right menu -->
|
||||||
|
|
||||||
{{$activeStopwatch := and .PageGlobalData (call .PageGlobalData.GetActiveStopwatch)}}
|
{{$activeStopwatch := and .PageGlobalData (call .PageGlobalData.GetActiveStopwatch)}}
|
||||||
|
{{if .ShowPersistentNavbar}}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
id="persistent-navbar-visibility-toggle"
|
||||||
|
data-show-text="{{ctx.Locale.Tr "navbar.show"}}"
|
||||||
|
data-hide-text="{{ctx.Locale.Tr "navbar.hide"}}"
|
||||||
|
data-tooltip-content="{{ctx.Locale.Tr "navbar.hide"}}"
|
||||||
|
data-tooltip-placement="left"
|
||||||
|
aria-label="{{ctx.Locale.Tr "navbar.hide"}}"
|
||||||
|
aria-pressed="false"
|
||||||
|
>
|
||||||
|
{{svg "octicon-chevron-down" 16 "persistent-navbar-visibility-icon persistent-navbar-visibility-icon-show tw-hidden"}}
|
||||||
|
{{svg "octicon-chevron-up" 16 "persistent-navbar-visibility-icon persistent-navbar-visibility-icon-hide"}}
|
||||||
|
</button>
|
||||||
|
{{end}}
|
||||||
{{if $activeStopwatch}}
|
{{if $activeStopwatch}}
|
||||||
<div class="active-stopwatch-popup tippy-target">
|
<div class="active-stopwatch-popup tippy-target">
|
||||||
<div class="flex-text-block tw-p-3">
|
<div class="flex-text-block tw-p-3">
|
||||||
|
|||||||
@@ -93,7 +93,13 @@ body.show-sticky-side-menus .page-content.admin .flex-container-nav > .ui.vertic
|
|||||||
|
|
||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
body.show-persistent-navbar {
|
body.show-persistent-navbar {
|
||||||
--persistent-navbar-offset: 49px;
|
--persistent-navbar-height: 49px;
|
||||||
|
--persistent-navbar-collapsed-peek: 8px;
|
||||||
|
--persistent-navbar-offset: var(--persistent-navbar-height);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.show-persistent-navbar.persistent-navbar-collapsed {
|
||||||
|
--persistent-navbar-offset: var(--persistent-navbar-collapsed-peek);
|
||||||
}
|
}
|
||||||
|
|
||||||
body.show-sticky-side-menus .page-content.user.settings .flex-container-nav > .ui.vertical.menu,
|
body.show-sticky-side-menus .page-content.user.settings .flex-container-nav > .ui.vertical.menu,
|
||||||
|
|||||||
@@ -2,9 +2,12 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
position: relative;
|
||||||
|
overflow: visible;
|
||||||
background: var(--color-nav-bg);
|
background: var(--color-nav-bg);
|
||||||
border-bottom: 1px solid var(--color-secondary);
|
border-bottom: 1px solid var(--color-secondary);
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
|
transition: transform 0.2s ease, margin-bottom 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.show-persistent-navbar #navbar {
|
body.show-persistent-navbar #navbar {
|
||||||
@@ -13,6 +16,10 @@ body.show-persistent-navbar #navbar {
|
|||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#persistent-navbar-visibility-toggle {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* When notification message is present after navbar, hide border to avoid double border */
|
/* When notification message is present after navbar, hide border to avoid double border */
|
||||||
#navbar:has(+ .ui.message) {
|
#navbar:has(+ .ui.message) {
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
@@ -112,6 +119,43 @@ body.show-persistent-navbar #navbar {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
body.show-persistent-navbar.persistent-navbar-collapsed #navbar {
|
||||||
|
transform: translateY(calc(var(--persistent-navbar-offset, 0px) - var(--persistent-navbar-height, 49px)));
|
||||||
|
margin-bottom: calc(var(--persistent-navbar-offset, 0px) - var(--persistent-navbar-height, 49px));
|
||||||
|
}
|
||||||
|
|
||||||
|
body.show-persistent-navbar #persistent-navbar-visibility-toggle {
|
||||||
|
position: absolute;
|
||||||
|
right: 5px;
|
||||||
|
bottom: -11px;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: center;
|
||||||
|
width: 50px;
|
||||||
|
height: 11px;
|
||||||
|
padding: 0;
|
||||||
|
/* padding-bottom: 1px; */
|
||||||
|
color: var(--color-nav-text);
|
||||||
|
background: var(--color-nav-bg);
|
||||||
|
border: 1px solid var(--color-secondary);
|
||||||
|
border-top: none;
|
||||||
|
border-radius: 0 0 10px 10px;
|
||||||
|
box-shadow: 0 2px 6px var(--color-shadow);
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.show-persistent-navbar #persistent-navbar-visibility-toggle:hover {
|
||||||
|
background: var(--color-nav-hover-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.show-persistent-navbar #persistent-navbar-visibility-toggle .svg {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#navbar a.item:hover .notification_count,
|
#navbar a.item:hover .notification_count,
|
||||||
#navbar a.item:hover .header-stopwatch-dot,
|
#navbar a.item:hover .header-stopwatch-dot,
|
||||||
#navbar .item.active .navbar-admin-badge {
|
#navbar .item.active .navbar-admin-badge {
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import {GET, POST} from '../modules/fetch.ts';
|
import {GET, POST} from '../modules/fetch.ts';
|
||||||
import {showGlobalErrorMessage} from '../modules/errors.ts';
|
import {showGlobalErrorMessage} from '../modules/errors.ts';
|
||||||
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
||||||
|
import {localUserSettings} from '../modules/user-settings.ts';
|
||||||
import {addDelegatedEventListener, queryElems} from '../utils/dom.ts';
|
import {addDelegatedEventListener, queryElems} from '../utils/dom.ts';
|
||||||
import {registerGlobalInitFunc, registerGlobalSelectorFunc} from '../modules/observer.ts';
|
import {registerGlobalInitFunc, registerGlobalSelectorFunc} from '../modules/observer.ts';
|
||||||
import {initAvatarUploaderWithCropper} from './comp/Cropper.ts';
|
import {initAvatarUploaderWithCropper} from './comp/Cropper.ts';
|
||||||
import {initCompSearchRepoBox} from './comp/SearchRepoBox.ts';
|
import {initCompSearchRepoBox} from './comp/SearchRepoBox.ts';
|
||||||
|
|
||||||
const {appUrl, appSubUrl} = window.config;
|
const {appUrl, appSubUrl} = window.config;
|
||||||
|
const persistentNavbarCollapsedKey = 'persistent-navbar-collapsed';
|
||||||
|
|
||||||
function initHeadNavbarContentToggle() {
|
function initHeadNavbarContentToggle() {
|
||||||
const navbar = document.querySelector('#navbar');
|
const navbar = document.querySelector('#navbar');
|
||||||
@@ -20,6 +22,35 @@ function initHeadNavbarContentToggle() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setPersistentNavbarCollapsedState(collapsed: boolean) {
|
||||||
|
document.body.classList.toggle('persistent-navbar-collapsed', collapsed);
|
||||||
|
|
||||||
|
const btn = document.querySelector<HTMLButtonElement>('#persistent-navbar-visibility-toggle');
|
||||||
|
if (!btn) return;
|
||||||
|
|
||||||
|
const text = btn.getAttribute(collapsed ? 'data-show-text' : 'data-hide-text') ?? '';
|
||||||
|
btn.setAttribute('aria-pressed', String(collapsed));
|
||||||
|
btn.setAttribute('aria-label', text);
|
||||||
|
btn.setAttribute('data-tooltip-content', text);
|
||||||
|
btn.querySelector('.persistent-navbar-visibility-icon-show')?.classList.toggle('tw-hidden', !collapsed);
|
||||||
|
btn.querySelector('.persistent-navbar-visibility-icon-hide')?.classList.toggle('tw-hidden', collapsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initPersistentNavbarVisibilityToggle() {
|
||||||
|
if (!document.body.classList.contains('show-persistent-navbar')) return;
|
||||||
|
|
||||||
|
const btn = document.querySelector<HTMLButtonElement>('#persistent-navbar-visibility-toggle');
|
||||||
|
if (!btn) return;
|
||||||
|
|
||||||
|
setPersistentNavbarCollapsedState(localUserSettings.getBoolean(persistentNavbarCollapsedKey, false));
|
||||||
|
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
const collapsed = !document.body.classList.contains('persistent-navbar-collapsed');
|
||||||
|
localUserSettings.setBoolean(persistentNavbarCollapsedKey, collapsed);
|
||||||
|
setPersistentNavbarCollapsedState(collapsed);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function initFooterLanguageMenu() {
|
function initFooterLanguageMenu() {
|
||||||
document.querySelector('.ui.dropdown .menu.language-menu')?.addEventListener('click', async (e) => {
|
document.querySelector('.ui.dropdown .menu.language-menu')?.addEventListener('click', async (e) => {
|
||||||
const item = (e.target as HTMLElement).closest('.item');
|
const item = (e.target as HTMLElement).closest('.item');
|
||||||
@@ -57,8 +88,8 @@ export function initStickySideMenuIndicators(root: ParentNode = document) {
|
|||||||
const repoActionsMenuScrollKey = 'sticky-side-menu-scroll:repo-actions';
|
const repoActionsMenuScrollKey = 'sticky-side-menu-scroll:repo-actions';
|
||||||
|
|
||||||
for (const menu of menus) {
|
for (const menu of menus) {
|
||||||
if (menu.dataset.stickySideMenuIndicatorsInitialized === 'true') continue;
|
if (menu.getAttribute('data-sticky-side-menu-indicators-initialized') === 'true') continue;
|
||||||
menu.dataset.stickySideMenuIndicatorsInitialized = 'true';
|
menu.setAttribute('data-sticky-side-menu-indicators-initialized', 'true');
|
||||||
|
|
||||||
const isUserSettingsMenu = Boolean(menu.closest('.page-content.user.settings'));
|
const isUserSettingsMenu = Boolean(menu.closest('.page-content.user.settings'));
|
||||||
const isRepoActionsMenu = Boolean(menu.closest('.page-content.repository.actions'));
|
const isRepoActionsMenu = Boolean(menu.closest('.page-content.repository.actions'));
|
||||||
@@ -112,6 +143,7 @@ export function initStickySideMenuIndicators(root: ParentNode = document) {
|
|||||||
|
|
||||||
export function initCommmPageComponents() {
|
export function initCommmPageComponents() {
|
||||||
initHeadNavbarContentToggle();
|
initHeadNavbarContentToggle();
|
||||||
|
initPersistentNavbarVisibilityToggle();
|
||||||
initFooterLanguageMenu();
|
initFooterLanguageMenu();
|
||||||
initFooterThemeSelector();
|
initFooterThemeSelector();
|
||||||
initStickySideMenuIndicators();
|
initStickySideMenuIndicators();
|
||||||
|
|||||||
Reference in New Issue
Block a user