Initial commit: Atomaste website
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
import MenuPlaceholder from '../Placeholder/MenuPlaceholder';
|
||||
import MenuItem from './MenuItem';
|
||||
import useMenu from "./MenuData";
|
||||
/**
|
||||
* Menu block, rendering the entire menu
|
||||
*/
|
||||
const Menu = () => {
|
||||
const {subMenu, subMenuLoaded} = useMenu();
|
||||
|
||||
if ( !subMenuLoaded ) {
|
||||
return(
|
||||
<MenuPlaceholder />
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rsssl-wizard-menu rsssl-grid-item">
|
||||
<div className="rsssl-grid-item-header">
|
||||
<h1 className="rsssl-h4">{subMenu.title}</h1>
|
||||
</div>
|
||||
<div className="rsssl-grid-item-content">
|
||||
<div className="rsssl-wizard-menu-items">
|
||||
{ subMenu.menu_items.map((menuItem, i) => <MenuItem key={"menuItem-"+i} menuItem={menuItem} isMainMenu={true} /> ) }
|
||||
</div>
|
||||
</div>
|
||||
<div className="rsssl-grid-item-footer">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Menu;
|
||||
@@ -0,0 +1,248 @@
|
||||
import {create} from 'zustand';
|
||||
import getAnchor from "../utils/getAnchor";
|
||||
|
||||
const useMenu = create(( set, get ) => ({
|
||||
menu: [],
|
||||
subMenuLoaded:false,
|
||||
previousMenuItem:false,
|
||||
nextMenuItem:false,
|
||||
selectedMainMenuItem:false,
|
||||
selectedSubMenuItem:false,
|
||||
selectedFilter: false,
|
||||
activeGroupId: false,
|
||||
hasPremiumItems:false,
|
||||
subMenu:{title:' ',menu_items:[]},
|
||||
setSelectedSubMenuItem: async (selectedSubMenuItem) => {
|
||||
let selectedMainMenuItem = getMainMenuForSubMenu(selectedSubMenuItem);
|
||||
set(state => ({ selectedSubMenuItem,selectedMainMenuItem }))
|
||||
// window.location.href=rsssl_settings.dashboard_url+'#'+selectedMainMenuItem+'/'+selectedSubMenuItem;
|
||||
window.location.hash = selectedMainMenuItem+'/'+selectedSubMenuItem;
|
||||
},
|
||||
setSelectedMainMenuItem: (selectedMainMenuItem) => {
|
||||
set(state => ({ selectedMainMenuItem }))
|
||||
// window.location.href=rsssl_settings.dashboard_url+'#'+selectedMainMenuItem;
|
||||
window.location.hash = selectedMainMenuItem;
|
||||
},
|
||||
//we need to get the main menu item directly from the anchor, otherwise we have to wait for the menu to load in page.js
|
||||
fetchSelectedMainMenuItem: () => {
|
||||
let selectedMainMenuItem = getAnchor('main') || 'dashboard';
|
||||
set((state) => ({selectedMainMenuItem: selectedMainMenuItem}));
|
||||
},
|
||||
fetchSelectedSubMenuItem: async () => {
|
||||
let selectedSubMenuItem = getAnchor('menu') || 'general';
|
||||
set((state) => ({selectedSubMenuItem: selectedSubMenuItem}));
|
||||
},
|
||||
fetchMenuData: (fields) => {
|
||||
let menu = rsssl_settings.menu;
|
||||
menu = Object.values(menu);
|
||||
const selectedMainMenuItem = getAnchor('main') || 'dashboard';
|
||||
menu = menu.filter( item => !item.default_hidden || selectedMainMenuItem===item.id);
|
||||
|
||||
if ( typeof fields !== 'undefined' ) {
|
||||
let subMenu = getSubMenu(menu, selectedMainMenuItem);
|
||||
const selectedSubMenuItem = getSelectedSubMenuItem(subMenu, fields);
|
||||
subMenu.menu_items = dropEmptyMenuItems(subMenu.menu_items, fields, selectedSubMenuItem);
|
||||
const { nextMenuItem, previousMenuItem } = getPreviousAndNextMenuItems(menu, selectedSubMenuItem, fields);
|
||||
const hasPremiumItems = subMenu.menu_items.filter((item) => {return (item.premium===true)}).length>0;
|
||||
set((state) => ({subMenuLoaded:true, menu: menu, nextMenuItem:nextMenuItem, previousMenuItem:previousMenuItem, selectedMainMenuItem: selectedMainMenuItem, selectedSubMenuItem:selectedSubMenuItem, subMenu: subMenu, hasPremiumItems: hasPremiumItems}));
|
||||
} else {
|
||||
set((state) => ({menu: menu, selectedMainMenuItem: selectedMainMenuItem}));
|
||||
|
||||
}
|
||||
},
|
||||
getDefaultSubMenuItem: async (fields) => {
|
||||
let subMenuLoaded = get().subMenuLoaded;
|
||||
if (!subMenuLoaded){
|
||||
await get().fetchMenuData(fields);
|
||||
}
|
||||
let subMenu = get().subMenu;
|
||||
let fallBackMenuItem = subMenuLoaded && subMenu.hasOwnProperty(0) ? subMenu[0].id : 'general';
|
||||
let anchor = getAnchor('menu');
|
||||
let foundAnchorInMenu = false;
|
||||
//check if this anchor actually exists in our current submenu. If not, clear it
|
||||
for (const key in this.menu.menu_items) {
|
||||
if ( subMenu.hasOwnProperty(key) && subMenu[key].id === anchor ){
|
||||
foundAnchorInMenu=true;
|
||||
}
|
||||
}
|
||||
if ( !foundAnchorInMenu ) anchor = false;
|
||||
return anchor ? anchor : fallBackMenuItem;
|
||||
}
|
||||
}));
|
||||
export default useMenu;
|
||||
|
||||
|
||||
// Parses menu items and nested items in single array
|
||||
const menuItemParser = (parsedMenuItems, menuItems, fields) => {
|
||||
menuItems.forEach((menuItem) => {
|
||||
if( menuItem.visible ) {
|
||||
parsedMenuItems.push(menuItem.id);
|
||||
if( menuItem.hasOwnProperty('menu_items') ) {
|
||||
menuItem.menu_items = dropEmptyMenuItems(menuItem.menu_items, fields );
|
||||
menuItemParser(parsedMenuItems, menuItem.menu_items, fields);
|
||||
}
|
||||
}
|
||||
});
|
||||
return parsedMenuItems;
|
||||
}
|
||||
|
||||
const getPreviousAndNextMenuItems = (menu, selectedSubMenuItem, fields) => {
|
||||
let previousMenuItem;
|
||||
let nextMenuItem;
|
||||
const parsedMenuItems = [];
|
||||
menuItemParser(parsedMenuItems, menu, fields);
|
||||
// Finds current menu item index
|
||||
const currentMenuItemIndex = parsedMenuItems.findIndex((menuItem) => menuItem === selectedSubMenuItem);
|
||||
if( currentMenuItemIndex !== -1 ) {
|
||||
previousMenuItem = parsedMenuItems[ currentMenuItemIndex === 0 ? '' : currentMenuItemIndex - 1];
|
||||
//if the previous menu item has a submenu, we should move one more back, because it will select the current sub otherwise.
|
||||
const previousMenuHasSubMenu = getMenuItemByName(previousMenuItem, menu).hasOwnProperty('menu_items');
|
||||
if (previousMenuHasSubMenu) {
|
||||
previousMenuItem = parsedMenuItems[ currentMenuItemIndex === 0 ? '' : currentMenuItemIndex - 2]
|
||||
}
|
||||
nextMenuItem = parsedMenuItems[ currentMenuItemIndex === parsedMenuItems.length - 1 ? '' : currentMenuItemIndex + 1];
|
||||
previousMenuItem = previousMenuItem ? previousMenuItem : parsedMenuItems[0];
|
||||
nextMenuItem = nextMenuItem ? nextMenuItem : parsedMenuItems[parsedMenuItems.length - 1]
|
||||
}
|
||||
return { nextMenuItem, previousMenuItem };
|
||||
}
|
||||
|
||||
const dropEmptyMenuItems = (menuItems, fields) => {
|
||||
|
||||
if (!Array.isArray(fields)) {
|
||||
return menuItems; // return the original menuItems unchanged
|
||||
}
|
||||
|
||||
const newMenuItems = menuItems;
|
||||
for (const [index, menuItem] of menuItems.entries()) {
|
||||
let menuItemFields = fields.filter((field) => {
|
||||
return (field.menu_id === menuItem.id )
|
||||
});
|
||||
|
||||
menuItemFields = menuItemFields.filter((field) => {
|
||||
return ( field.visible )
|
||||
});
|
||||
if ( menuItemFields.length === 0 && !menuItem.hasOwnProperty('menu_items') ) {
|
||||
if (typeof newMenuItems[index] === 'object' && newMenuItems[index] !== null) {
|
||||
newMenuItems[index].visible = false;
|
||||
}
|
||||
} else {
|
||||
if (typeof newMenuItems[index] === 'object' && newMenuItems[index] !== null) {
|
||||
newMenuItems[index].visible = true;
|
||||
}
|
||||
if( menuItem.hasOwnProperty('menu_items') ) {
|
||||
newMenuItems[index].menu_items = dropEmptyMenuItems(menuItem.menu_items, fields);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return newMenuItems;
|
||||
}
|
||||
|
||||
/*
|
||||
* filter sidebar menu from complete menu structure
|
||||
*/
|
||||
const getSubMenu = (menu, selectedMainMenuItem) => {
|
||||
|
||||
let subMenu = [];
|
||||
for (const key in menu) {
|
||||
if ( menu.hasOwnProperty(key) && menu[key].id === selectedMainMenuItem ){
|
||||
subMenu = menu[key];
|
||||
}
|
||||
}
|
||||
|
||||
subMenu = addVisibleToMenuItems(subMenu);
|
||||
return subMenu;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the main menu item for a submenu item
|
||||
*/
|
||||
const getMainMenuForSubMenu = (findMenuItem) => {
|
||||
let menu = rsssl_settings.menu;
|
||||
for (const mainKey in menu) {
|
||||
let mainMenuItem = menu[mainKey];
|
||||
if (mainMenuItem.id===findMenuItem) {
|
||||
return mainMenuItem.id;
|
||||
}
|
||||
if (mainMenuItem.menu_items){
|
||||
for (const subKey in mainMenuItem.menu_items) {
|
||||
let subMenuItem = mainMenuItem.menu_items[subKey];
|
||||
if (subMenuItem.id===findMenuItem) {
|
||||
return mainMenuItem.id;
|
||||
}
|
||||
if (subMenuItem.menu_items){
|
||||
for (const sub2Key in subMenuItem.menu_items) {
|
||||
let sub2MenuItem = subMenuItem.menu_items[sub2Key];
|
||||
if (sub2MenuItem.id===findMenuItem) {
|
||||
return mainMenuItem.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current selected menu item based on the hash, selecting subitems if the main one is empty.
|
||||
*/
|
||||
const getSelectedSubMenuItem = (subMenu, fields) => {
|
||||
let fallBackMenuItem = subMenu && subMenu.menu_items.hasOwnProperty(0) ? subMenu.menu_items[0].id : 'general';
|
||||
let foundAnchorInMenu;
|
||||
|
||||
//get flat array of menu items
|
||||
let parsedMenuItems = menuItemParser([], subMenu.menu_items);
|
||||
let anchor = getAnchor('menu');
|
||||
//check if this anchor actually exists in our current submenu. If not, clear it
|
||||
foundAnchorInMenu = parsedMenuItems.filter(menu_item => menu_item === anchor);
|
||||
if ( !foundAnchorInMenu ) {
|
||||
anchor = false;
|
||||
}
|
||||
let selectedMenuItem = anchor ? anchor : fallBackMenuItem;
|
||||
//check if menu item has fields. If not, try a subitem
|
||||
let fieldsInMenu = fields.filter(field => field.menu_id === selectedMenuItem);
|
||||
if ( fieldsInMenu.length===0 ) {
|
||||
//look up the current menu item
|
||||
let menuItem = getMenuItemByName(selectedMenuItem, subMenu.menu_items);
|
||||
if (menuItem && menuItem.menu_items && menuItem.menu_items.hasOwnProperty(0)) {
|
||||
selectedMenuItem = menuItem.menu_items[0].id;
|
||||
}
|
||||
}
|
||||
return selectedMenuItem;
|
||||
}
|
||||
|
||||
//Get a menu item by name from the menu array
|
||||
const getMenuItemByName = (name, menuItems) => {
|
||||
for (const key in menuItems ){
|
||||
let menuItem = menuItems[key];
|
||||
if ( menuItem.id === name ) {
|
||||
return menuItem;
|
||||
}
|
||||
if ( menuItem.menu_items ) {
|
||||
let found = getMenuItemByName(name, menuItem.menu_items);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const addVisibleToMenuItems = (menu) => {
|
||||
|
||||
let newMenuItems = Array.isArray(menu.menu_items) ? menu.menu_items : Object.values(menu.menu_items);
|
||||
|
||||
for (let [index, menuItem] of newMenuItems.entries()) {
|
||||
if (typeof menuItem === 'object' && menuItem !== null) {
|
||||
menuItem.visible = true;
|
||||
if (menuItem.hasOwnProperty('menu_items')) {
|
||||
menuItem = addVisibleToMenuItems(menuItem);
|
||||
}
|
||||
newMenuItems[index] = menuItem;
|
||||
}
|
||||
}
|
||||
menu.menu_items = newMenuItems;
|
||||
menu.visible = true;
|
||||
return menu;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import useMenu from "./MenuData";
|
||||
|
||||
const MenuItem = (props) => {
|
||||
const {selectedSubMenuItem, selectedMainMenuItem, subMenu, menu} = useMenu();
|
||||
const menuIsSelected = isSelectedMenuItem(selectedSubMenuItem, props.menuItem);
|
||||
|
||||
const ensureArray = (data) => {
|
||||
return Array.isArray(data) ? data : [data];
|
||||
}
|
||||
|
||||
let menuClass = menuIsSelected ? ' rsssl-active' : '';
|
||||
menuClass += props.menuItem.featured ? ' rsssl-featured' : '';
|
||||
menuClass += props.menuItem.new ? ' rsssl-new' : '';
|
||||
menuClass += props.menuItem.premium && !rsssl_settings.pro_plugin_active ? ' rsssl-premium' : '';
|
||||
let menuLink = props.menuItem.directLink || '#'+selectedMainMenuItem+'/'+props.menuItem.id;
|
||||
|
||||
return (
|
||||
<>
|
||||
{props.menuItem.visible && (
|
||||
<>
|
||||
{props.isMainMenu ? (
|
||||
<div className="rsssl-main-menu">
|
||||
<div className={"rsssl-menu-item" + menuClass}>
|
||||
<a href={menuLink}>
|
||||
<span>{props.menuItem.title}</span>
|
||||
{props.menuItem.featured && <span className='rsssl-menu-item-beta-pill'>{__('Beta', 'really-simple-ssl')}</span>}
|
||||
{props.menuItem.new && <span className='rsssl-menu-item-new-pill'>{__('New', 'really-simple-ssl')}</span>}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className={"rsssl-menu-item" + menuClass}>
|
||||
<a href={menuLink}>
|
||||
<span>{props.menuItem.title}</span>
|
||||
{props.menuItem.featured && <span className='rsssl-menu-item-beta-pill'>{__('Beta', 'really-simple-ssl')}</span>}
|
||||
{props.menuItem.new && <span className='rsssl-menu-item-new-pill'>{__('New', 'really-simple-ssl')}</span>}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{props.menuItem.menu_items && menuIsSelected && (
|
||||
<div className="rsssl-submenu-item">
|
||||
{ensureArray(props.menuItem.menu_items).map((subMenuItem, i) => (
|
||||
subMenuItem.visible && <MenuItem key={"submenuItem" + i} menuItem={subMenuItem} isMainMenu={false} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
export default MenuItem
|
||||
|
||||
/**
|
||||
* Utility function to check if selected menu item is the current menu item or a child of the current menu item
|
||||
* @param selectedSubMenuItem
|
||||
* @param menuItem
|
||||
* @returns {boolean}
|
||||
*/
|
||||
const isSelectedMenuItem = (selectedSubMenuItem, menuItem) => {
|
||||
if (selectedSubMenuItem === menuItem.id) {
|
||||
return true;
|
||||
}
|
||||
if (menuItem.menu_items) {
|
||||
for (const item of menuItem.menu_items) {
|
||||
if (item.id === selectedSubMenuItem) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
Reference in New Issue
Block a user