Skip to content

Commit 11164a7

Browse files
Merge pull request #140 from lsprr/lsprr/accessibility/sidebar
Refactor Menu and Social Media Components for Improved Accessibility
2 parents 64638ac + 2acf851 commit 11164a7

File tree

4 files changed

+115
-83
lines changed

4 files changed

+115
-83
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import React from "react";
2+
import { NavLink } from "react-router-dom";
3+
4+
const Menu = ({ item, isOpen, closeSidebar }) => {
5+
return (
6+
<li key={item.title} role="none">
7+
<NavLink
8+
to={`/${item.pageType}/${item.objectId}`}
9+
className="mx-auto flex items-center hover:bg-[#eef1f5] p-3 lg:p-4"
10+
onClick={closeSidebar}
11+
tabIndex={isOpen ? 0 : -1}
12+
role="menuitem"
13+
>
14+
<i className={`${item.icon} text-[18px]`} aria-hidden="true"></i>
15+
<span className="ml-3 lg:ml-4">{item.title}</span>
16+
</NavLink>
17+
</li>
18+
)
19+
}
20+
21+
export default Menu;

apps/OpenSign/src/components/sidebar/Sidebar.js

Lines changed: 34 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,115 +1,77 @@
11
import React, { useState, useEffect } from "react";
2-
import { Link, NavLink } from "react-router-dom";
2+
3+
import Menu from './Menu';
34
import Submenu from "./SubMenu";
4-
import dp from "../../assets/images/dp.png";
5+
import SocialMedia from './SocialMedia';
6+
57
import Parse from "parse";
8+
import dp from "../../assets/images/dp.png";
9+
610
const Sidebar = ({ isOpen, closeSidebar }) => {
11+
const [menuList, setmenuList] = useState([]);
712
let username = localStorage.getItem("username");
813
const image = localStorage.getItem("profileImg") || dp;
914
const tenantname = localStorage.getItem("TenantName");
10-
const [menuList, setmenuList] = useState([]);
1115

1216
useEffect(() => {
1317
if (localStorage.getItem("accesstoken")) {
1418
menuItem();
1519
}
1620
}, []);
21+
1722
const menuItem = async () => {
1823
const parseBaseUrl = localStorage.getItem("baseUrl");
1924
const parseAppId = localStorage.getItem("parseAppId");
25+
2026
try {
2127
Parse.serverURL = parseBaseUrl;
2228
Parse.initialize(parseAppId);
2329
var sideMenu = Parse.Object.extend("w_menu");
2430
var query = new Parse.Query(sideMenu);
2531
query.equalTo("objectId", localStorage.getItem("defaultmenuid"));
26-
32+
2733
const results = await query.first();
2834
const resultjson = results.toJSON();
29-
// console.log("resultjson ", resultjson);
3035
let result = resultjson;
3136
setmenuList(result.menuItems);
3237
} catch (e) {
3338
console.error("Problem", e);
3439
}
40+
3541
};
3642

3743
return (
38-
<div
39-
className={`${
40-
isOpen ? "block" : "hidden"
41-
} bg-white text-[#444] h-screen w-full md:w-[300px] overflow-y-auto transform transition-transform z-40 ${
42-
isOpen ? "translate-x-0" : "-translate-x-full"
43-
}`}
44+
<aside
45+
className={`${isOpen ? "block" : "hidden"
46+
} bg-white text-[#444] h-screen w-full md:w-[300px] overflow-y-auto transform transition-transform z-40 ${isOpen ? "translate-x-0" : "-translate-x-full"
47+
}`}
4448
>
4549
<div className="flex px-2 py-3 gap-2 items-center shadow-md">
4650
<div className="w-[75px] h-[75px] rounded-full ring-[2px] ring-offset-2 ring-gray-400 overflow-hidden">
47-
<img className="w-full h-full object-contain" src={image} alt="img" />
51+
<img className="w-full h-full object-cover" src={image} alt="Profile" />
4852
</div>
4953
<div>
50-
<p className="text-[14px] font-bold">{username && username}</p>
51-
<p
52-
className={`text-[12px] ${tenantname && tenantname ? "mt-2" : ""}`}
53-
>
54-
{tenantname && tenantname}
54+
<p className="text-[14px] font-bold">{username}</p>
55+
<p className={`text-[12px] ${tenantname ? "mt-2" : ""}`}>
56+
{tenantname}
5557
</p>
5658
</div>
5759
</div>
58-
<ul className="text-sm">
59-
{menuList.length > 0 && (
60-
<>
61-
{menuList.map((item) =>
62-
!item.children ? (
63-
<li key={item.title} onClick={() => closeSidebar()}>
64-
<Link
65-
className={`mx-auto flex items-center hover:bg-[#eef1f5] p-3 lg:p-4 hover:no-underline cursor-pointer`}
66-
to={`/${item.pageType}/${item.objectId}`}
67-
>
68-
<i className={item.icon + " text-[18px]"}></i>
69-
<span title={item.description} className="ml-3 lg:ml-4">
70-
{item.title}
71-
</span>
72-
</Link>
73-
</li>
74-
) : (
75-
<Submenu key={item.title} icon={item.icon} title={item.title}>
76-
{item.children.map((item) => (
77-
<li key={item.title} onClick={() => closeSidebar()} className="pl-6 md:pl-8 hover:bg-[#eef1f5] cursor-pointer">
78-
<Link
79-
className={`mx-auto flex items-center p-2 lg:p-3 hover:no-underline`}
80-
to={`/${item.pageType}/${item.objectId}`}
81-
>
82-
<i className={item.icon + " text-[18px]"}></i>
83-
<span title={item.description} className="ml-3 lg:ml-4">
84-
{item.title}
85-
</span>
86-
</Link>
87-
</li>
88-
))}
89-
</Submenu>
90-
)
91-
)}
92-
</>
93-
)}
94-
</ul>
95-
<div className="mt-4 flex justify-center items-center text-[25px] text-black gap-3">
96-
<NavLink to="https://github.com/opensignlabs/opensign" target="_blank">
97-
<i className="fa-brands fa-github"></i>
98-
</NavLink>
99-
<NavLink
100-
to="https://www.linkedin.com/company/opensign%E2%84%A2/"
101-
target="_blank"
102-
>
103-
<i className="fa-brands fa-linkedin"></i>
104-
</NavLink>
105-
<NavLink to="https://www.twitter.com/opensignlabs" target="_blank">
106-
<i className="fa-brands fa-square-x-twitter"></i>
107-
</NavLink>
108-
<NavLink to="https://discord.com/invite/xe9TDuyAyj" target="_blank">
109-
<i className="fa-brands fa-discord"></i>
110-
</NavLink>
111-
</div>
112-
</div>
60+
<nav aria-label="OpenSign Sidebar Navigation">
61+
<ul className="text-sm" role="menubar" aria-label="OpenSign Sidebar Navigation">
62+
{menuList.map((item) => (
63+
!item.children ? (
64+
<Menu key={item.title} item={item} isOpen={isOpen} closeSidebar={closeSidebar} />
65+
) : (
66+
<Submenu key={item.title} item={item} closeSidebar={closeSidebar} />
67+
)
68+
))}
69+
</ul>
70+
</nav>
71+
<footer className="mt-4 flex justify-center items-center text-[25px] text-black gap-3">
72+
<SocialMedia />
73+
</footer>
74+
</aside>
11375
);
11476
};
11577

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from "react";
2+
import { NavLink } from "react-router-dom";
3+
4+
const SocialMedia = () => {
5+
return (
6+
<React.Fragment>
7+
<NavLink to="https://github.com/opensignlabs/opensign" target="_blank" rel="noopener noreferrer">
8+
<i aria-hidden="true" className="fa-brands fa-github"></i>
9+
<span className="fa-sr-only">OpenSign&apos;s Github</span>
10+
</NavLink>
11+
<NavLink to="https://www.linkedin.com/company/opensign%E2%84%A2/" target="_blank" rel="noopener noreferrer">
12+
<i aria-hidden="true" className="fa-brands fa-linkedin"></i>
13+
<span className="fa-sr-only">OpenSign&apos;s LinkedIn</span>
14+
</NavLink>
15+
<NavLink to="https://www.twitter.com/opensignlabs" target="_blank" rel="noopener noreferrer">
16+
<i aria-hidden="true" className="fa-brands fa-square-x-twitter"></i>
17+
<span className="fa-sr-only">OpenSign&apos;s Twitter</span>
18+
</NavLink>
19+
<NavLink to="https://discord.com/invite/xe9TDuyAyj" target="_blank" rel="noopener noreferrer">
20+
<i aria-hidden="true" className="fa-brands fa-discord"></i>
21+
<span className="fa-sr-only">OpenSign&apos;s Discord</span>
22+
</NavLink>
23+
</React.Fragment>
24+
)
25+
}
26+
27+
export default SocialMedia;

apps/OpenSign/src/components/sidebar/SubMenu.js

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,52 @@
11
import React, { useState } from "react";
2+
import { NavLink } from "react-router-dom";
23

3-
const Submenu = ({ icon, title, children }) => {
4-
const [isOpen, setIsOpen] = useState(false);
4+
const Submenu = ({ item, closeSidebar }) => {
5+
const [submenuOpen, setSubmenuOpen] = useState(false);
6+
const { title, icon, children } = item;
57

68
const toggleSubmenu = () => {
7-
setIsOpen(!isOpen);
9+
setSubmenuOpen(!submenuOpen);
810
};
911

1012
return (
11-
<div>
13+
<li role="none">
1214
<button
1315
onClick={toggleSubmenu}
14-
className="w-full mx-auto flex items-center text-left text-[#444] p-3 lg:p-4 hover:bg-[#eef1f5] focus:outline-none"
16+
className="w-full flex items-center text-left text-[#444] p-3 lg:p-4 hover:bg-[#eef1f5] focus:ring-2 focus:ring-blue-600"
17+
aria-expanded={submenuOpen}
18+
aria-haspopup="true"
19+
aria-controls={`submenu-${title}`}
1520
>
16-
<i className={icon + " text-[18px]"}></i>
21+
<i className={`${icon} text-[18px]`}></i>
1722
<div className="flex justify-between items-center w-full">
1823
<span className="ml-3 lg:ml-4">{title}</span>
1924
<i
20-
className={
21-
isOpen ? "fa-solid fa-angle-down" : "fa-solid fa-angle-right"
22-
}
25+
className={`${submenuOpen ? "fa-solid fa-angle-down" : "fa-solid fa-angle-right"
26+
}`}
27+
aria-hidden="true"
2328
></i>
2429
</div>
2530
</button>
26-
{isOpen && <ul>{children}</ul>}
27-
</div>
31+
{submenuOpen && (
32+
<ul id={`submenu-${title}`} role="menu" aria-label={`${title} submenu`}>
33+
{children.map((childItem) => (
34+
<li key={childItem.title} role="none">
35+
<NavLink
36+
to={`/${childItem.pageType}/${childItem.objectId}`}
37+
className="block pl-6 md:pl-8 py-2 text-sm text-gray-700 hover:bg-blue-500 hover:text-white"
38+
onClick={closeSidebar}
39+
role="menuitem"
40+
tabIndex={submenuOpen ? 0 : -1}
41+
>
42+
<i className={`${childItem.icon} text-[18px]`} aria-hidden="true"></i>
43+
<span className="ml-3 lg:ml-4">{childItem.title}</span>
44+
</NavLink>
45+
</li>
46+
))}
47+
</ul>
48+
)}
49+
</li>
2850
);
2951
};
3052

0 commit comments

Comments
 (0)