Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 4923 - Scrollbar/navbar with aesthetic scrolling to facilitate easier website navigation. #4976

Open
wants to merge 8 commits into
base: gh-pages
Choose a base branch
from
86 changes: 86 additions & 0 deletions _includes/navbar.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<nav class="nav-menu">
<ul>
<li><a href="#i-want-to-get-involved">Get Involved</a></li>
<li><a href="#projects">Projects</a></li>
<li><a href="#i-maintain-a-project">Maintain a Project</a></li>
</ul>
</nav>

<style>
.nav-menu {
padding: 15px 0;
text-align: center;
background-color: #fff;
margin: 20px 0;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}

.nav-menu ul {
margin: 0;
padding: 0;
list-style: none;
display: flex;
justify-content: center;
gap: 30px;
}

.nav-menu li {
display: inline-block;
}

.nav-menu a {
color: #2F4F6A;
text-decoration: none;
font-weight: 500;
font-size: 16px;
padding: 5px 0;
cursor: pointer;
}

.nav-menu a:hover {
color: #1a2f40;
}
</style>

<script>
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('.nav-menu a').forEach(anchor => {
anchor.addEventListener('click', function(e) {
e.preventDefault();
const targetId = this.getAttribute('href');
const targetElement = document.querySelector(targetId);

if (targetElement) {
// Calculate distance to scroll
const startPosition = window.pageYOffset;
const targetPosition = targetElement.getBoundingClientRect().top + startPosition;
const distance = targetPosition - startPosition;

// Slower, smoother scroll animation
const duration = 1500; // Increased duration (in milliseconds)
const start = performance.now();

function animate(currentTime) {
const timeElapsed = currentTime - start;
const progress = Math.min(timeElapsed / duration, 1);

// Easing function for smoother acceleration/deceleration
const easeInOutCubic = progress => {
return progress < 0.5
? 4 * progress * progress * progress
: 1 - Math.pow(-2 * progress + 2, 3) / 2;
};

window.scrollTo(0, startPosition + (distance * easeInOutCubic(progress)));

if (progress < 1) {
requestAnimationFrame(animate);
}
}

requestAnimationFrame(animate);
}
});
});
});
</script>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
</script>
</script>

2 changes: 2 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
layout: default
---

{% include navbar.html %}

<section id="i-want-to-get-involved" class="block">
{% include before.html %}
</section>
Expand Down
83 changes: 83 additions & 0 deletions tests/spec/NavbarTests.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
const { JSDOM } = require('jsdom');

describe('Navbar', () => {
let window, document;

beforeEach(() => {
// Set up a simple DOM environment
const dom = new JSDOM(
`
<nav class="nav-menu">
<ul>
<li><a href="#i-want-to-get-involved">Get Involved</a></li>
<li><a href="#projects">Projects</a></li>
<li><a href="#i-maintain-a-project">Maintain a Project</a></li>
</ul>
</nav>
<div id="i-want-to-get-involved">Section 1</div>
<div id="projects">Section 2</div>
<div id="i-maintain-a-project">Section 3</div>
`,
{
url: 'http://localhost',
runScripts: 'dangerously',
}
);

window = dom.window;
document = window.document;

// Simple mock for scrollTo
window.scrollTo = jest.fn();
window.performance = { now: () => Date.now() };
window.requestAnimationFrame = (callback) => setTimeout(callback, 0);
});

// Test 1: Basic structure
it('should have navigation menu', () => {
const nav = document.querySelector('.nav-menu');
expect(nav).not.toBeNull();
});

// Test 2: Number of links
it('should have three navigation links', () => {
const links = document.querySelectorAll('.nav-menu a');
expect(links).toHaveLength(3);
});

// Test 3: Link hrefs
it('should have correct href attributes', () => {
const links = document.querySelectorAll('.nav-menu a');
expect(links[0].getAttribute('href')).toBe('#i-want-to-get-involved');
expect(links[1].getAttribute('href')).toBe('#projects');
expect(links[2].getAttribute('href')).toBe('#i-maintain-a-project');
});

// Test 4: Link text
it('should have correct link text', () => {
const links = document.querySelectorAll('.nav-menu a');
expect(links[0].textContent).toBe('Get Involved');
expect(links[1].textContent).toBe('Projects');
expect(links[2].textContent).toBe('Maintain a Project');
});

// Test 5: Basic scroll check
it('should call scrollTo when link is clicked', async () => {
// Setup click handler
document
.querySelector('.nav-menu a')
.addEventListener('click', function (e) {
e.preventDefault();
window.scrollTo(0, 100);
});

// Click the link
document.querySelector('.nav-menu a').click();

// Wait for any async operations
await new Promise((resolve) => setTimeout(resolve, 50));

// Check if scrollTo was called
expect(window.scrollTo).toHaveBeenCalled();
});
});
Loading