Skip to content

Commit 2d4fa0e

Browse files
committed
New style and logic
1 parent affffd6 commit 2d4fa0e

File tree

7 files changed

+147
-157
lines changed

7 files changed

+147
-157
lines changed

website/src/css/_signalwire.scss

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -36,22 +36,6 @@ This includes gradients for Navbar and links.
3636
}
3737
}
3838

39-
// Hide main navbar border when secondary navbar is present
40-
// COMMENTED OUT FOR TESTING - showing both navbar borders
41-
// .navbar.has-secondary-navbar {
42-
// border-bottom: none;
43-
// border-image: none;
44-
// }
45-
46-
// Apply gradient border to secondary navbar (matches main navbar styling)
47-
.secondaryNavbar {
48-
border-bottom: 0.2rem solid transparent;
49-
border-image: var(--sw-horizontal-active-line-color) 1;
50-
transition: 200ms linear;
51-
font-size: 14px;
52-
box-shadow: none; // remove default shadow
53-
}
54-
5539
// Apply same gradient effect to version badge dropdown items
5640
.version-badge-dropdown-container .dropdown__link {
5741
transition: color 100ms ease;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import React from 'react';
2+
import OriginalNavbarContent from '@theme-original/Navbar/Content';
3+
import type {Props} from '@theme/Navbar/Content';
4+
5+
export default function NavbarContent(props: Props): React.JSX.Element {
6+
return (
7+
<div style={{width: '100%', display: 'flex'}}>
8+
<OriginalNavbarContent {...props} />
9+
</div>
10+
);
11+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import React, {type ComponentProps, type ReactNode} from 'react';
2+
import clsx from 'clsx';
3+
import {ThemeClassNames, useThemeConfig} from '@docusaurus/theme-common';
4+
import {useHideableNavbar, useNavbarMobileSidebar} from '@docusaurus/theme-common/internal';
5+
import {translate} from '@docusaurus/Translate';
6+
import NavbarMobileSidebar from '@theme/Navbar/MobileSidebar';
7+
import type {Props} from '@theme/Navbar/Layout';
8+
import styles from './styles.module.css';
9+
10+
function NavbarBackdrop(props: ComponentProps<'div'>) {
11+
return (
12+
<div
13+
role="presentation"
14+
{...props}
15+
className={clsx('navbar-sidebar__backdrop', props.className)}
16+
/>
17+
);
18+
}
19+
20+
export default function NavbarLayout({children}: Props): ReactNode {
21+
const {navbar: {hideOnScroll, style}} = useThemeConfig();
22+
const mobileSidebar = useNavbarMobileSidebar();
23+
const {navbarRef, isNavbarVisible} = useHideableNavbar(hideOnScroll);
24+
25+
return (
26+
<nav
27+
ref={navbarRef}
28+
aria-label={translate({
29+
id: 'theme.NavBar.navAriaLabel',
30+
message: 'Main',
31+
description: 'The ARIA label for the main navigation',
32+
})}
33+
className={clsx(
34+
ThemeClassNames.layout.navbar.container,
35+
'navbar',
36+
'navbar--fixed-top',
37+
hideOnScroll && [
38+
styles.navbarHideable,
39+
!isNavbarVisible && styles.navbarHidden,
40+
],
41+
{
42+
'navbar--dark': style === 'dark',
43+
'navbar--primary': style === 'primary',
44+
'navbar-sidebar--show': mobileSidebar.shown,
45+
},
46+
)}>
47+
{/* Container with flex-column for multiple rows */}
48+
<div className={styles.navbarRows}>
49+
{children}
50+
</div>
51+
<NavbarBackdrop onClick={mobileSidebar.toggle} />
52+
<NavbarMobileSidebar />
53+
</nav>
54+
);
55+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/* Override navbar height to account for both primary and secondary navbar rows */
2+
:root {
3+
--ifm-navbar-height: 100px;
4+
}
5+
6+
/* Navbar hide/show animation styles */
7+
.navbarHideable {
8+
transition: transform var(--ifm-transition-fast) ease;
9+
}
10+
11+
.navbarHidden {
12+
transform: translate3d(0, calc(-100% - 2px), 0);
13+
}
14+
15+
/* Container for multiple navbar rows */
16+
.navbarRows {
17+
display: flex;
18+
flex-direction: column;
19+
width: 100%;
20+
}

website/src/theme/Navbar/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ export default function Navbar(): ReactNode {
1313
<ModalContext.Provider value={{ isModalOpen, setModalOpen, currentProduct, setCurrentProduct }}>
1414
<NavbarLayout>
1515
<NavbarContent />
16+
<SecondaryNavbar />
1617
</NavbarLayout>
17-
<SecondaryNavbar />
1818
<ProductModal
1919
isOpen={isModalOpen}
2020
onClose={() => setModalOpen(false)}
Lines changed: 50 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1,130 +1,66 @@
1-
import React, { useEffect, useRef, useState } from 'react';
1+
import React from 'react';
22
import Link from '@docusaurus/Link';
33
import clsx from 'clsx';
44
import { FaChevronDown } from 'react-icons/fa';
55
import { useSecondaryNavState } from '@theme/Navbar/hooks/useSecondaryNavState';
66
import { ProductLink, DropdownItem } from '@site/secondaryNavbar';
77
import styles from './styles.module.scss';
88

9-
export default function SecondaryNavbar(): React.JSX.Element | null {
10-
const navbarRef = useRef<HTMLDivElement>(null);
11-
const placeholderRef = useRef<HTMLDivElement>(null);
12-
const [isFixed, setIsFixed] = useState(false);
13-
9+
export default function SecondaryNavbar(): React.JSX.Element {
1410
// Get secondary navbar state from shared hook
1511
const { product, productLinks, activeSidebar } = useSecondaryNavState();
1612

17-
// Handle fixed positioning when scrolling past main navbar
18-
useEffect(() => {
19-
const handleScroll = () => {
20-
const mainNavbar = document.querySelector('.navbar') as HTMLElement | null;
21-
if (mainNavbar && navbarRef.current) {
22-
// Check if we've scrolled past the main navbar
23-
if (window.scrollY > mainNavbar.offsetHeight) {
24-
setIsFixed(true);
25-
} else {
26-
setIsFixed(false);
27-
}
28-
}
29-
};
30-
31-
// Check initial position (handles anchor links on page load)
32-
handleScroll();
33-
34-
window.addEventListener('scroll', handleScroll);
35-
window.addEventListener('load', handleScroll);
36-
37-
return () => {
38-
window.removeEventListener('scroll', handleScroll);
39-
window.removeEventListener('load', handleScroll);
40-
};
41-
}, []);
42-
43-
// Signal to main navbar that secondary navbar exists
44-
// COMMENTED OUT FOR TESTING - showing both navbar borders
45-
// useEffect(() => {
46-
// // Only add class if we're actually going to show the secondary navbar
47-
// if (!product || !productLinks || productLinks.length <= 1) {
48-
// return; // Don't add class if not rendering
49-
// }
50-
51-
// const mainNavbar = document.querySelector('.navbar:not(.secondaryNavbar)');
52-
// if (mainNavbar) {
53-
// mainNavbar.classList.add('has-secondary-navbar');
54-
// }
55-
56-
// return () => {
57-
// const mainNavbar = document.querySelector('.navbar:not(.secondaryNavbar)');
58-
// if (mainNavbar) {
59-
// mainNavbar.classList.remove('has-secondary-navbar');
60-
// }
61-
// };
62-
// }, [product, productLinks]);
63-
64-
// Don't show if no product or only 1 link
65-
if (!product || !productLinks || productLinks.length <= 1) {
66-
return null;
67-
}
68-
6913
return (
70-
<>
71-
<nav
72-
ref={navbarRef}
73-
className={clsx('navbar', styles.secondaryNavbar, isFixed && styles.fixedTop)}
74-
>
75-
<div className="navbar__inner">
76-
<div className="navbar__items">
77-
{productLinks.map((item: ProductLink, index: number) => {
78-
if (item.dropdown) {
79-
// Dropdown support (optional)
80-
return (
81-
<div key={index} className="navbar__item dropdown dropdown--hoverable">
82-
<a href="#" className="navbar__link" onClick={(e) => e.preventDefault()}>
83-
{item.label}
84-
<FaChevronDown aria-hidden="true" style={{ marginLeft: '0.3em', fontSize: '0.8em' }} />
85-
</a>
86-
<ul className="dropdown__menu">
87-
{item.dropdown.map((subItem: DropdownItem, subIndex: number) => (
88-
<li key={subIndex}>
89-
<Link
90-
to={subItem.link}
91-
className="dropdown__link"
92-
>
93-
{subItem.label}
94-
</Link>
95-
</li>
96-
))}
97-
</ul>
98-
</div>
99-
);
100-
}
101-
102-
// Regular link - determine if active based on sidebar name
103-
const isActive = activeSidebar && item.sidebar === activeSidebar;
104-
14+
<div className={styles.secondaryNavbar}>
15+
<div className="navbar__inner">
16+
{/* LEFT CONTAINER - Product navigation links */}
17+
<div className="theme-layout-navbar-left navbar__items">
18+
{productLinks && productLinks.length > 1 && productLinks.map((item: ProductLink, index: number) => {
19+
if (item.dropdown) {
20+
// Dropdown support (optional)
10521
return (
106-
<Link
107-
key={index}
108-
to={item.link}
109-
className={clsx(
110-
'navbar__item navbar__link',
111-
isActive && 'navbar__link--active' // Infima active class (color, no underline)
112-
)}
113-
>
114-
{item.label}
115-
</Link>
22+
<div key={index} className="navbar__item dropdown dropdown--hoverable">
23+
<a href="#" className="navbar__link" onClick={(e) => e.preventDefault()}>
24+
{item.label}
25+
<FaChevronDown aria-hidden="true" style={{ marginLeft: '0.3em', fontSize: '0.8em' }} />
26+
</a>
27+
<ul className="dropdown__menu">
28+
{item.dropdown.map((subItem: DropdownItem, subIndex: number) => (
29+
<li key={subIndex}>
30+
<Link
31+
to={subItem.link}
32+
className="dropdown__link"
33+
>
34+
{subItem.label}
35+
</Link>
36+
</li>
37+
))}
38+
</ul>
39+
</div>
11640
);
117-
})}
118-
</div>
119-
<div className="navbar__items navbar__items--right">
120-
{/* Empty - provides proper flex layout for full width */}
121-
</div>
41+
}
42+
43+
// Regular link - determine if active based on sidebar name
44+
const isActive = activeSidebar && item.sidebar === activeSidebar;
45+
46+
return (
47+
<Link
48+
key={index}
49+
to={item.link}
50+
className={clsx(
51+
'navbar__item navbar__link',
52+
isActive && 'navbar__link--active' // Infima active class (color, no underline)
53+
)}
54+
>
55+
{item.label}
56+
</Link>
57+
);
58+
})}
59+
</div>
60+
{/* RIGHT CONTAINER - Empty for now, ready for future right-aligned items */}
61+
<div className="theme-layout-navbar-right navbar__items navbar__items--right">
12262
</div>
123-
</nav>
124-
{/* Placeholder to prevent content jump when navbar becomes fixed */}
125-
{isFixed && (
126-
<div ref={placeholderRef} className={styles.placeholder} />
127-
)}
128-
</>
63+
</div>
64+
</div>
12965
);
13066
}

website/src/theme/SecondaryNavbar/styles.module.scss

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,28 @@
11
:root {
2-
--secondary-navbar-height: var(--ifm-navbar-height);
2+
--secondary-navbar-height: 60px;
33
}
44

5-
// Secondary navbar container - extends base navbar with custom positioning
5+
// Secondary navbar container - now a row inside main navbar
66
.secondaryNavbar {
7-
// Remove horizontal padding to allow border to extend truly edge-to-edge
8-
padding-left: 0;
9-
padding-right: 0;
107

118
// Ensure navbar extends full viewport width
129
width: 100%;
1310

14-
// Positioning - initially sticky below main navbar
15-
position: sticky;
16-
top: var(--ifm-navbar-height);
17-
z-index: calc(var(--ifm-z-index-fixed) - 1); // 199 - below main navbar
18-
19-
// Custom height
11+
// Height matching primary navbar
2012
height: var(--secondary-navbar-height);
2113

22-
// All other navbar styling (colors, shadows) inherited from .navbar class
14+
// Background color inherited from navbar
15+
background: inherit;
2316
}
2417

25-
// Apply padding to inner container for content spacing
18+
// Apply padding to inner container for content spacing and fix vertical centering
2619
.secondaryNavbar :global(.navbar__inner) {
27-
padding-left: var(--ifm-navbar-padding-horizontal);
28-
padding-right: var(--ifm-navbar-padding-horizontal);
29-
}
30-
31-
// Fixed positioning when scrolled past main navbar
32-
.secondaryNavbar.fixedTop {
33-
position: fixed;
34-
top: 0;
35-
z-index: calc(var(--ifm-z-index-fixed) + 1); // 201 - above main navbar when scrolling
20+
height: var(--secondary-navbar-height); // Explicit height for proper centering
3621
}
3722

38-
// Placeholder to prevent layout shift when navbar becomes fixed
39-
.placeholder {
40-
height: var(--secondary-navbar-height);
41-
width: 100%;
23+
// Fix dropdown vertical alignment conflict with Infima
24+
.secondaryNavbar :global(.navbar__item.dropdown) {
25+
vertical-align: middle; // Override Infima's 'top' which conflicts with flexbox
4226
}
4327

4428
// All link styling (colors, hover, padding, active states) is inherited from Infima classes:

0 commit comments

Comments
 (0)