mirror of
https://github.com/runyanjake/jakesphotos.git
synced 2026-03-26 05:23:18 -07:00
Update navigation
This commit is contained in:
parent
753112ff46
commit
51845db643
@ -23,7 +23,9 @@ const App = () => (
|
|||||||
<ContentProvider>
|
<ContentProvider>
|
||||||
<>
|
<>
|
||||||
<Navbar />
|
<Navbar />
|
||||||
|
<main className="app-content">
|
||||||
<PageRoutes />
|
<PageRoutes />
|
||||||
|
</main>
|
||||||
<Footer />
|
<Footer />
|
||||||
</>
|
</>
|
||||||
</ContentProvider>
|
</ContentProvider>
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
.navbar {
|
.navbar {
|
||||||
display: grid;
|
position: relative;
|
||||||
grid-template-columns: 1fr auto 1fr;
|
display: flex;
|
||||||
column-gap: 24px;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
background-color: var(--color-bg-nav);
|
background-color: var(--color-bg-nav);
|
||||||
padding: 10px 20px;
|
padding: 0 20px;
|
||||||
height: var(--nav-height);
|
height: var(--nav-height);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
@ -13,6 +13,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-left .logo {
|
.navbar-left .logo {
|
||||||
@ -23,7 +24,6 @@
|
|||||||
|
|
||||||
.navbar-links {
|
.navbar-links {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,8 +42,13 @@
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Absolutely positioned so it's always centered relative to the full navbar width */
|
||||||
.navbar-center {
|
.navbar-center {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-center h1 {
|
.navbar-center h1 {
|
||||||
@ -55,23 +60,107 @@
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-right {
|
.navbar-right {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-end;
|
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-right .icon {
|
.navbar-social {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
height: 28px;
|
height: 28px;
|
||||||
width: 28px;
|
width: 28px;
|
||||||
opacity: 0.75;
|
opacity: 0.75;
|
||||||
transition: opacity var(--transition-fast), transform var(--transition-fast);
|
transition: opacity var(--transition-fast), transform var(--transition-fast);
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-right .icon:hover {
|
.icon:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: scale(1.1);
|
transform: scale(1.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.navbar-hamburger {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 5px;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-hamburger span {
|
||||||
|
display: block;
|
||||||
|
width: 22px;
|
||||||
|
height: 2px;
|
||||||
|
background-color: var(--color-text-nav);
|
||||||
|
border-radius: 2px;
|
||||||
|
transition: transform 0.2s ease, opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-hamburger.open span:nth-child(1) {
|
||||||
|
transform: translateY(7px) rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-hamburger.open span:nth-child(2) {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-hamburger.open span:nth-child(3) {
|
||||||
|
transform: translateY(-7px) rotate(-45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile dropdown menu */
|
||||||
|
.navbar-mobile-menu {
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background-color: var(--color-bg-nav);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 16px 20px 20px;
|
||||||
|
gap: 16px;
|
||||||
|
z-index: 100;
|
||||||
|
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-mobile-menu a {
|
||||||
|
color: var(--color-text-nav);
|
||||||
|
text-decoration: none;
|
||||||
|
font-family: var(--font-heading);
|
||||||
|
font-size: var(--font-size-base);
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
opacity: 0.75;
|
||||||
|
transition: opacity var(--transition-fast);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-mobile-menu a:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-menu-icons {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 20px;
|
||||||
|
padding-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-menu-icons .icon {
|
||||||
|
height: 22px;
|
||||||
|
width: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Nav links are always in the dropdown, never inline */
|
||||||
|
.navbar-links {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { useSiteConfig } from '../framework/ContentProvider';
|
import { useSiteConfig } from '../framework/ContentProvider';
|
||||||
import './Navbar.css';
|
import './Navbar.css';
|
||||||
@ -18,6 +18,7 @@ const darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|||||||
const Navbar = () => {
|
const Navbar = () => {
|
||||||
const { siteTitle, nav, social } = useSiteConfig();
|
const { siteTitle, nav, social } = useSiteConfig();
|
||||||
const [isDarkMode, setIsDarkMode] = useState(darkModeQuery.matches);
|
const [isDarkMode, setIsDarkMode] = useState(darkModeQuery.matches);
|
||||||
|
const [menuOpen, setMenuOpen] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handler = (e) => setIsDarkMode(e.matches);
|
const handler = (e) => setIsDarkMode(e.matches);
|
||||||
@ -25,6 +26,22 @@ const Navbar = () => {
|
|||||||
return () => darkModeQuery.removeEventListener('change', handler);
|
return () => darkModeQuery.removeEventListener('change', handler);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleResize = () => { if (window.innerWidth > 640) setMenuOpen(false); };
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
return () => window.removeEventListener('resize', handleResize);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const SocialIcons = () => social.map(({ label, url, icon }) => {
|
||||||
|
const icons = ICON_MAP[icon];
|
||||||
|
const src = icons ? (isDarkMode ? icons.dark : icons.light) : null;
|
||||||
|
return (
|
||||||
|
<a key={icon} href={url} target="_blank" rel="noopener noreferrer">
|
||||||
|
{src && <img src={src} alt={label} className="icon" title={label} />}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className="navbar">
|
<nav className="navbar">
|
||||||
<div className="navbar-left">
|
<div className="navbar-left">
|
||||||
@ -37,20 +54,35 @@ const Navbar = () => {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="navbar-center">
|
<div className="navbar-center">
|
||||||
<h1>{siteTitle}</h1>
|
<h1>{siteTitle}</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="navbar-right">
|
<div className="navbar-right">
|
||||||
{social.map(({ label, url, icon }) => {
|
<div className="navbar-social">
|
||||||
const icons = ICON_MAP[icon];
|
<SocialIcons />
|
||||||
const src = icons ? (isDarkMode ? icons.dark : icons.light) : null;
|
|
||||||
return (
|
|
||||||
<a key={icon} href={url} target="_blank" rel="noopener noreferrer">
|
|
||||||
{src && <img src={src} alt={label} className="icon" title={label} />}
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
|
<button
|
||||||
|
className={`navbar-hamburger${menuOpen ? ' open' : ''}`}
|
||||||
|
onClick={() => setMenuOpen(o => !o)}
|
||||||
|
aria-label="Toggle menu"
|
||||||
|
aria-expanded={menuOpen}
|
||||||
|
>
|
||||||
|
<span /><span /><span />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{menuOpen && (
|
||||||
|
<div className="navbar-mobile-menu">
|
||||||
|
{nav.map(({ label, path }) => (
|
||||||
|
<Link key={path} to={path} onClick={() => setMenuOpen(false)}>{label}</Link>
|
||||||
|
))}
|
||||||
|
<div className="mobile-menu-icons">
|
||||||
|
<SocialIcons />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</nav>
|
</nav>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -7,6 +7,19 @@ body {
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#root {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-content {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background-color: var(--color-bg);
|
||||||
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||||
monospace;
|
monospace;
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
.gallery {
|
.gallery {
|
||||||
display: grid;
|
width: 100%;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
background-color: var(--color-bg);
|
background-color: var(--color-bg);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user