Skip to content

Commit 43ae87b

Browse files
mmarinhenaorpokorny
authored andcommitted
nav-pill-iq
Added a component that already exist in iq the nav pill scroll to navigation to the component library for general use
1 parent 89996ee commit 43ae87b

14 files changed

Lines changed: 1573 additions & 0 deletions
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Copyright (c) 2019-present Sonatype, Inc.
3+
* This program and the accompanying materials are made available under
4+
* the terms of the Eclipse Public License 2.0 which accompanies this
5+
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/.
6+
*/
7+
import React from 'react';
8+
import { NxNavPillMenu, NavPillMenuItem } from '@sonatype/react-shared-components';
9+
10+
const items: NavPillMenuItem[] = [
11+
{ id: 'dashboard', label: 'Dashboard', scrollTarget: 'dashboard-section' },
12+
{ id: 'analytics', label: 'Analytics', scrollTarget: 'analytics-section' },
13+
{ id: 'reports', label: 'Reports', scrollTarget: 'reports-section', disabled: true },
14+
{ id: 'settings', label: 'Settings', scrollTarget: 'settings-section' },
15+
{ id: 'help', label: 'Help Center', href: 'https://help.sonatype.com', disabled: false },
16+
{ id: 'admin', label: 'Admin Panel', scrollTarget: 'admin-section', disabled: true }
17+
];
18+
19+
export default function NxNavPillMenuDisabledExample() {
20+
const handleItemClick = (item: NavPillMenuItem) => {
21+
if (item.disabled) {
22+
console.log('Disabled item clicked:', item.label);
23+
return;
24+
}
25+
26+
if (item.href) {
27+
console.log('External link clicked:', item.label, item.href);
28+
} else {
29+
console.log('Navigation pill clicked:', item.label);
30+
}
31+
};
32+
33+
return (
34+
<div
35+
data-scroll-container="true"
36+
style={{
37+
height: '500px',
38+
overflow: 'hidden',
39+
padding: '20px'
40+
}}>
41+
<div style={{ position: 'relative' }}>
42+
<NxNavPillMenu
43+
items={items}
44+
onItemClick={handleItemClick}
45+
scrollBehavior="smooth"
46+
scrollOffset={0}
47+
/>
48+
49+
{/* Scrollable content container */}
50+
<div
51+
data-nav-scroll-area="true"
52+
style={{
53+
height: 'calc(480px - 41px)', // Subtract nav height and container padding
54+
overflowY: 'auto',
55+
marginTop: '0px' // No gap between nav and content
56+
}}>
57+
<section id="dashboard-section" style={{ padding: '20px', marginBottom: '20px', backgroundColor: 'white', borderRadius: '8px', border: '1px solid #e0e0e0' }}>
58+
<h3>Dashboard</h3>
59+
<p>Main dashboard view with key metrics and overview information.</p>
60+
<p>This example demonstrates disabled states within a scrollable container.</p>
61+
</section>
62+
63+
<section id="analytics-section" style={{ padding: '20px', marginBottom: '20px', backgroundColor: 'white', borderRadius: '8px', border: '1px solid #e0e0e0' }}>
64+
<h3>Analytics</h3>
65+
<p>Detailed analytics and data visualization section.</p>
66+
<p>The navigation bar stays sticky at the top of this container.</p>
67+
</section>
68+
69+
<section id="reports-section" style={{ padding: '20px', marginBottom: '20px', backgroundColor: 'white', borderRadius: '8px', border: '1px solid #e0e0e0', opacity: 0.6 }}>
70+
<h3>Reports (Disabled)</h3>
71+
<p>Reports section is currently disabled. The corresponding pill cannot be clicked.</p>
72+
<p>Disabled pills show proper visual feedback and prevent interaction.</p>
73+
</section>
74+
75+
<section id="settings-section" style={{ padding: '20px', marginBottom: '20px', backgroundColor: 'white', borderRadius: '8px', border: '1px solid #e0e0e0' }}>
76+
<h3>Settings</h3>
77+
<p>Application settings and configuration options.</p>
78+
<p>The contained scroll area works seamlessly with all pill states.</p>
79+
</section>
80+
81+
<div style={{ padding: '20px', marginBottom: '20px', backgroundColor: 'white', borderRadius: '8px', border: '2px dashed #1976d2' }}>
82+
<h3>External Link Example</h3>
83+
<p>The "Help Center" pill links to an external URL (https://help.sonatype.com).</p>
84+
<p>External links work normally even within the contained scroll area.</p>
85+
</div>
86+
87+
<section id="admin-section" style={{ padding: '20px', marginBottom: '20px', backgroundColor: 'white', borderRadius: '8px', border: '1px solid #e0e0e0', opacity: 0.6 }}>
88+
<h3>Admin Panel (Disabled)</h3>
89+
<p>Admin panel access is restricted. This pill is disabled for regular users.</p>
90+
<p>The scroll container ensures proper navigation behavior for all states.</p>
91+
</section>
92+
</div>
93+
</div>
94+
</div>
95+
);
96+
}
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/*
2+
* Copyright (c) 2019-present Sonatype, Inc.
3+
* This program and the accompanying materials are made available under
4+
* the terms of the Eclipse Public License 2.0 which accompanies this
5+
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/.
6+
*/
7+
import React, { useState, useRef, useEffect } from 'react';
8+
import { NxNavPillMenu, NavPillMenuItem, NxFontAwesomeIcon } from '@sonatype/react-shared-components';
9+
import { faArrowUp } from '@fortawesome/free-solid-svg-icons';
10+
11+
const items: NavPillMenuItem[] = [
12+
{ id: 'overview', label: 'Overview', scrollTarget: 'overview-section' },
13+
{ id: 'features', label: 'Features', scrollTarget: 'features-section' },
14+
{ id: 'getting-started', label: 'Getting Started', scrollTarget: 'getting-started-section' },
15+
{ id: 'api', label: 'API Reference', scrollTarget: 'api-section' },
16+
{ id: 'examples', label: 'Examples', scrollTarget: 'examples-section' }
17+
];
18+
19+
export default function NxNavPillMenuExample() {
20+
const [showBackToTop, setShowBackToTop] = useState(false);
21+
const scrollContainerRef = useRef<HTMLDivElement>(null);
22+
23+
const handleItemClick = (item: NavPillMenuItem) => {
24+
console.log('Clicked nav pill:', item.label);
25+
};
26+
27+
// Back to top functionality
28+
const scrollToTop = () => {
29+
if (scrollContainerRef.current) {
30+
scrollContainerRef.current.scrollTo({
31+
top: 0,
32+
behavior: 'smooth'
33+
});
34+
}
35+
};
36+
37+
// Monitor scroll position to show/hide back-to-top button
38+
useEffect(() => {
39+
const handleScroll = () => {
40+
if (scrollContainerRef.current) {
41+
const scrollTop = scrollContainerRef.current.scrollTop;
42+
setShowBackToTop(scrollTop > 200); // Show after scrolling 200px
43+
}
44+
};
45+
46+
const scrollContainer = scrollContainerRef.current;
47+
if (scrollContainer) {
48+
scrollContainer.addEventListener('scroll', handleScroll);
49+
return () => scrollContainer.removeEventListener('scroll', handleScroll);
50+
}
51+
52+
return undefined; // Explicit return for when scrollContainer is null
53+
}, []);
54+
55+
return (
56+
<div
57+
data-scroll-container="true"
58+
style={{
59+
height: '500px',
60+
overflow: 'hidden',
61+
padding: '20px'
62+
}}>
63+
<div style={{ position: 'relative' }}>
64+
<NxNavPillMenu
65+
items={items}
66+
onItemClick={handleItemClick}
67+
scrollBehavior="smooth"
68+
scrollOffset={0}
69+
/>
70+
71+
{/* Scrollable content container */}
72+
<div
73+
ref={scrollContainerRef}
74+
data-nav-scroll-area="true"
75+
style={{
76+
height: 'calc(480px - 41px)', // Subtract nav height and container padding
77+
overflowY: 'auto',
78+
marginTop: '0px' // No gap between nav and content
79+
}}>
80+
<section id="overview-section" style={{ padding: '20px', marginBottom: '20px', backgroundColor: 'white', borderRadius: '8px', border: '1px solid #e0e0e0' }}>
81+
<h3>Overview Section</h3>
82+
<p>This is the overview section. Clicking the "Overview" pill will scroll to this section within this container.</p>
83+
<p>The navigation bar stays at the top of this container, not the entire page.</p>
84+
</section>
85+
86+
<section id="features-section" style={{ padding: '20px', marginBottom: '20px', backgroundColor: 'white', borderRadius: '8px', border: '1px solid #e0e0e0' }}>
87+
<h3>Features Section</h3>
88+
<p>This is the features section. Notice how the navigation scrolls within this bounded area.</p>
89+
<p>This prevents conflicts with the main page scroll.</p>
90+
</section>
91+
92+
<section id="getting-started-section" style={{ padding: '20px', marginBottom: '20px', backgroundColor: 'white', borderRadius: '8px', border: '1px solid #e0e0e0' }}>
93+
<h3>Getting Started Section</h3>
94+
<p>This is the getting started section. Click the pill to scroll here.</p>
95+
<p>The scroll behavior is contained within this example area.</p>
96+
</section>
97+
98+
<section id="api-section" style={{ padding: '20px', marginBottom: '20px', backgroundColor: 'white', borderRadius: '8px', border: '1px solid #e0e0e0' }}>
99+
<h3>API Reference Section</h3>
100+
<p>This is the API reference section with detailed documentation.</p>
101+
<p>Each section has enough content to demonstrate the scroll behavior.</p>
102+
</section>
103+
104+
<section id="examples-section" style={{ padding: '20px', marginBottom: '20px', backgroundColor: 'white', borderRadius: '8px', border: '1px solid #e0e0e0' }}>
105+
<h3>Examples Section</h3>
106+
<p>This is the examples section showing various use cases.</p>
107+
<p>The contained scroll area ensures the sticky navigation works properly.</p>
108+
</section>
109+
</div>
110+
111+
{/* Back to top button - demo pattern for nav pill menu */}
112+
{showBackToTop && (
113+
<button
114+
onClick={scrollToTop}
115+
style={{
116+
position: 'absolute',
117+
bottom: '20px',
118+
right: '20px',
119+
width: '48px',
120+
height: '48px',
121+
borderRadius: '24px',
122+
backgroundColor: 'white',
123+
border: 'none',
124+
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)', // Lighter shadow
125+
cursor: 'pointer',
126+
display: 'flex',
127+
alignItems: 'center',
128+
justifyContent: 'center',
129+
fontSize: '16px',
130+
color: 'var(--nx-swatch-indigo-40)',
131+
transition: 'all 0.2s ease-in-out',
132+
zIndex: 1000
133+
}}
134+
onMouseEnter={(e) => {
135+
e.currentTarget.style.transform = 'translateY(-2px)';
136+
e.currentTarget.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.15)';
137+
}}
138+
onMouseLeave={(e) => {
139+
e.currentTarget.style.transform = 'translateY(0)';
140+
e.currentTarget.style.boxShadow = '0 2px 8px rgba(0, 0, 0, 0.1)';
141+
}}
142+
aria-label="Back to top"
143+
>
144+
<NxFontAwesomeIcon icon={faArrowUp} />
145+
</button>
146+
)}
147+
</div>
148+
</div>
149+
);
150+
}

0 commit comments

Comments
 (0)