DEV Community

Cover image for A simple responsive navbar component with Juris
ArtyProg
ArtyProg

Posted on • Edited on

A simple responsive navbar component with Juris

A very simple responsivr Navbar with Juris.
Pure Javascript, no JSX, hooks, memo, no blunder.
Notice, that a great part of the script deals with styling

Navbar

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Juris Responsive Header Component - Fixed</title>  <script src="https://unpkg.com/juris@0.87.1/juris.mini.js"></script>  <style> body { margin: 0; padding: 0; font-family: sans-serif; background: linear-gradient(135deg, #f0f0f0 0%, #e0e0e0 100%); } li:hover { color: red !important; text-decoration: underline; } /* Additional smooth transitions */ nav { transition: all 0.3s ease; } .hamb { transition: transform 0.2s ease; } .hamb:hover { transform: scale(1.7) !important; } </style> </head>  <body> <div id="app"></div>  <script> const ResponsiveHeader = (props, context) => { // Correct: Using getState and setState from context const { getState, setState } = context; // Improved: Better media query handling const setupMediaQuery = () => { const mq = window.matchMedia("(max-width: 640px)"); const updateMobile = (e) => { setState("is_mobile", e.matches); if (!e.matches) setState("menu_is_open", false); }; // Initial check updateMobile(mq); // Add listener mq.addEventListener("change", updateMobile); }; // Setup media query on component creation setupMediaQuery(); const li_Style = () => { if (getState("is_mobile", false)) { return { display: "block", margin: "0 0.5rem", cursor: "pointer", padding: "0.5rem", borderRadius: "4px", transition: "background-color 0.2s ease" }; } else { return { display: "inline-block", margin: "0 0.5rem", cursor: "pointer", padding: "0.25rem 0.5rem", borderRadius: "4px", transition: "background-color 0.2s ease" }; } }; return { header: { style: { display: "flex", justifyContent: "space-between", alignItems: "center", flexWrap: "wrap", background: "#2F2F2F", color: "white", padding: "1rem", position: "fixed", inset: "0 0 auto", fontFamily: "sans-serif", boxShadow: "0 2px 4px rgba(0,0,0,0.1)", zIndex: "1000" }, children: [ { section: { className: "left", style: { display: "flex", alignItems: "center", flex: 1, fontSize: "1.2rem", fontWeight: "bold" }, text: "BRAND", }, }, { section: { className: "center", style: { display: "flex", flexDirection: "column", alignItems: "center", }, children: [ { div: { className: "hamb", text: "", role: "button", tabIndex: "0", "aria-label": "Toggle menu", "aria-expanded": () => getState("menu_is_open", false), onClick: () => setState("menu_is_open", !getState("menu_is_open", false)), onKeyDown: (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); setState("menu_is_open", !getState("menu_is_open", false)); } }, style: { fontWeight: "bold", transform: "scale(1.5)", cursor: "pointer", display: () => (getState("is_mobile", false) ? "block" : "none"), padding: "0.5rem", borderRadius: "4px", }, }, }, { nav: { role: "navigation", "aria-label": "Main navigation", style: { width: "320px", textAlign: "center", display: () => { const isMobile = getState("is_mobile", false); const isOpen = getState("menu_is_open", false); return isMobile ? (isOpen ? "block" : "none") : "block"; }, position: () => (getState("is_mobile", false) ? "absolute" : "static"), top: () => (getState("is_mobile", false) ? "55px" : "auto"), background: "#2F2F2F", borderRadius: () => (getState("is_mobile", false) ? "0 0 8px 8px" : "0"), boxShadow: () => (getState("is_mobile", false) ? "0 4px 6px rgba(0,0,0,0.1)" : "none"), }, children: { ul: { onClick: (e) => { setState("menu_is_open", false); setState("menu-item", e.target.textContent); }, style: { listStyle: "none", padding: 0, margin: 0, }, children: [ { li: { text: "HOME", style: li_Style } }, { li: { text: "BLOG", style: li_Style } }, { li: { text: "ABOUT", style: li_Style } }, ], }, }, }, }, ], }, }, { section: { className: "right", style: { display: "flex", alignItems: "center", flex: 1, justifyContent: "flex-end", fontSize: "0.9rem" }, text: "HELP", }, }, ], }, }; }; const PageComponent = (props, context) => { const { getState } = context; return { div: { style: { color: "#333", fontFamily: "sans-serif", paddingTop: "60px", textAlign: "center", minHeight: "calc(100vh - 60px)", background: "linear-gradient(135deg, #ff9a56 0%, #ffad56 100%)", }, children: [ { h1: { text: () => { const menuItem = getState("menu-item", "HOME"); return `Current Page: ${menuItem}`; }, style: { fontSize: "1.5rem", color: "#2F2F2F", margin: "1rem 0" } } }, { p: { text: "This is a responsive header demo. Try resizing your browser window to see the mobile menu in action. This is a responsive header demo. Try resizing your browser window to see the mobile menu in action. This is a responsive header demo. Try resizing your browser window to see the mobile menu in action. This is a responsive header demo. Try resizing your browser window to see the mobile menu in action. This is a responsive header demo. Try resizing your browser window to see the mobile menu in action. This is a responsive header demo. Try resizing your browser window to see the mobile menu in action. This is a responsive header demo. Try resizing your browser window to see the mobile menu in action. This is a responsive header demo. Try resizing your browser window to see the mobile menu in action. This is a responsive header demo. Try resizing your browser window to see the mobile menu in action. This is a responsive header demo. Try resizing your browser window to see the mobile menu in action. This is a responsive header demo. Try resizing your browser window to see the mobile menu in action. This is a responsive header demo. Try resizing your browser window to see the mobile menu in action. This is a responsive header demo. Try resizing your browser window to see the mobile menu in action. This is a responsive header demo. Try resizing your browser window to see the mobile menu in action. This is a responsive header demo. Try resizing your browser window to see the mobile menu in action. This is a responsive header demo. Try resizing your browser window to see the mobile menu in action. This is a responsive header demo. Try resizing your browser window to see the mobile menu in action. This is a responsive header demo. Try resizing your browser window to see the mobile menu in action. This is a responsive header demo. Try resizing your browser window to see the mobile menu in action. This is a responsive header demo. Try resizing your browser window to see the mobile menu in action!", style: { maxWidth: "600px", margin: "2rem auto", lineHeight: "1.6", fontSize: "1.1rem" } } } ] } } } const FooterComponent = () => ({ div: { style: { color: "white", background: "linear-gradient(135deg, #2F2F2F 0%, #1a1a1a 100%)", fontFamily: "sans-serif", position: "fixed", inset: "auto 0 0", height: "4rem", display: "flex", alignItems: "center", justifyContent: "center", fontSize: "0.9rem", boxShadow: "0 -2px 4px rgba(0,0,0,0.1)" }, text: "© 2024 BRAND - All Rights Reserved" } }); const juris = new Juris({ states: { "menu-item": "HOME", "is_mobile": false, "menu_is_open": false }, components: { ResponsiveHeader, PageComponent, FooterComponent }, layout: [ { ResponsiveHeader: {} }, { PageComponent: {} }, { FooterComponent: {} } ], }); juris.render(); </script>  </body>  </html>  
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
jurisauthor profile image
jurisauthor

impressive and clever style-based theming here
{style: li_Style}

and it just worked!