revamp template

This commit is contained in:
fro1991
2025-02-01 16:44:51 +07:00
parent c432df568a
commit 276a289580
1212 changed files with 112762 additions and 0 deletions

View File

@ -0,0 +1,131 @@
import { KeenIcon } from '@/components';
import {
Menu,
TMenuConfig,
MenuItem,
MenuLink,
MenuSub,
MenuTitle,
MenuArrow
} from '@/components/menu';
import { useLanguage } from '@/i18n';
const NavbarMenu = ({ items }: { items: TMenuConfig }) => {
const { isRTL } = useLanguage();
const buildMenu = (items: TMenuConfig) => {
return items.map((item, index) => {
if (item.children) {
return (
<MenuItem
key={index}
className="border-b-2 border-b-transparent menu-item-active:border-b-primary menu-item-here:border-b-primary"
toggle="dropdown"
trigger="hover"
dropdownProps={{
placement: isRTL() ? 'bottom-end' : 'bottom-start',
modifiers: [
{
name: 'offset',
options: {
offset: [0, 0] // [skid, distance]
}
}
]
}}
>
<MenuLink className="gap-1.5 pb-2 lg:pb-4 px-2">
<MenuTitle className="text-nowrap text-sm text-gray-700 menu-item-active:text-primary menu-item-active:font-medium menu-item-here:text-primary menu-item-here:font-medium menu-item-show:text-primary menu-link-hover:text-primary">
{item.title}
</MenuTitle>
<MenuArrow>
<KeenIcon
icon="down"
className="text-2xs text-gray-500 menu-item-active:text-primary menu-item-here:text-primary menu-item-show:text-primary menu-link-hover:text-primary"
/>
</MenuArrow>
</MenuLink>
<MenuSub className="menu-default" rootClassName="py-2 min-w-[200px]">
{buildMenuSub(item.children)}
</MenuSub>
</MenuItem>
);
} else {
return (
<MenuItem
key={index}
className="border-b-2 border-b-transparent menu-item-active:border-b-primary menu-item-here:border-b-primary"
>
<MenuLink path={item.path} className="gap-1.5 pb-2 lg:pb-4 px-2">
<MenuTitle className="text-nowrap font-medium text-sm text-gray-700 menu-item-active:text-primary menu-item-active:font-semibold menu-item-here:text-primary menu-item-here:font-semibold menu-item-show:text-primary menu-link-hover:text-primary">
{item.title}
</MenuTitle>
</MenuLink>
</MenuItem>
);
}
});
};
const buildMenuSub = (items: TMenuConfig) => {
return items.map((item, index) => {
if (item.children) {
return (
<MenuItem
key={index}
toggle="dropdown"
trigger="hover"
dropdownProps={{
placement: isRTL() ? 'left-start' : 'right-start',
modifiers: [
{
name: 'offset',
options: {
offset: isRTL() ? [10, 0] : [-10, 0] // [skid, distance]
}
}
]
}}
>
<MenuLink>
<MenuTitle>{item.title}</MenuTitle>
{buildMenuToggle()}
</MenuLink>
<MenuSub className="menu-default" rootClassName="py min-w-[200px]">
{buildMenuSub(item.children)}
</MenuSub>
</MenuItem>
);
} else {
return (
<MenuItem key={index}>
<MenuLink path={item.path}>
<MenuTitle>{item.title}</MenuTitle>
</MenuLink>
</MenuItem>
);
}
});
};
const buildMenuToggle = () => {
return (
<MenuArrow>
<KeenIcon icon="down" className="text-2xs [.menu-dropdown_&]:-rotate-90" />
</MenuArrow>
);
};
return (
<div className="grid">
<div className="scrollable-x-auto">
<Menu highlight={true} className="gap-3">
{buildMenu(items)}
</Menu>
</div>
</div>
);
};
export { NavbarMenu };

View File

@ -0,0 +1,59 @@
export interface IScrollspyMenuItem {
title: string;
target?: string;
active?: boolean;
children?: IScrollspyMenuItem[];
}
export interface IScrollspyMenuItems extends Array<IScrollspyMenuItem> {}
export interface IScrollspyMenuProps {
items: IScrollspyMenuItem[];
}
const ScrollspyMenu = ({ items }: IScrollspyMenuProps) => {
const buildAnchor = (item: IScrollspyMenuItem, index: number, indent: boolean = false) => {
return (
<div
key={index}
data-scrollspy-anchor={item.target}
className={`cursor-pointer flex items-center rounded-lg pl-2.5 pr-2.5 py-2.5 border border-transparent text-gray-800 scrollspy-active:bg-secondary-active scrollspy-active:text-primary scrollspy-active:font-medium dark:hover:bg-coal-300 dark:hover:border-gray-100 hover:rounded-lg dark:scrollspy-active:bg-coal-300 dark:scrollspy-active:border-gray-100 ${
indent ? 'gap-3.5' : 'gap-1.5'
} ${item.active ? 'active' : ''} text-2sm hover:text-primary`}
>
<span className="flex w-1.5 relative before:absolute start-px rtl:-start-[5px] before:top-0 before:size-1.5 before:rounded-full before:-translate-x-2/4 before:-translate-y-2/4 scrollspy-active:before:bg-primary"></span>
{item.title}
</div>
);
};
const buildSubAnchors = (items: IScrollspyMenuItems) => {
return items.map((item, index) => {
return buildAnchor(item, index, true);
});
};
const renderChildren = (items: IScrollspyMenuItems) => {
return items.map((item, index) => {
if (item.children) {
return (
<div key={index} className="flex flex-col">
<div className="ps-6 pe-2.5 py-2.5 text-2sm font-semibold text-gray-900">
{item.title}
</div>
<div className="flex flex-col">{buildSubAnchors(item.children)}</div>
</div>
);
} else {
return buildAnchor(item, index);
}
});
};
return (
<div className="flex flex-col grow relative before:absolute before:start-[11px] before:top-0 before:bottom-0 before:border-s before:border-gray-200">
{renderChildren(items)}
</div>
);
};
export { ScrollspyMenu };

View File

@ -0,0 +1,2 @@
export * from './NavbarMenu';
export * from './ScrollspyMenu';

View File

@ -0,0 +1,39 @@
import { TMenuConfig, IMenuItemConfig, MenuSub } from '@/components/menu';
import { MegaMenuSubHighlighted, MegaMenuSubDefault } from './components';
const MegaMenuSubAccount = (items: TMenuConfig) => {
const myAccountItem = items[2];
const myAccountItemGeneral = myAccountItem.children ? myAccountItem.children[0] : {};
const myAccountItemOthers = myAccountItem.children ? myAccountItem.children[1] : {};
return (
<MenuSub className="flex-col lg:flex-row gap-0 w-full lg:max-w-[1240px]">
<div className="lg:w-[250px] mt-2 lg:mt-0 lg:border-r lg:border-e-gray-200 rounded-xl lg:rounded-s-xl lg:rounded-e-none shrink-0 px-3 py-4 lg:p-7.5 bg-light-active dark:bg-coal-500 dark:lg:border-e-coal-100">
<h3 className="text-sm text-gray-800 font-semibold leading-none ps-2.5 mb-2 lg:mb-5">
{myAccountItemGeneral.title}
</h3>
<div className="menu menu-default menu-fit flex-col">
{myAccountItemGeneral.children && MegaMenuSubHighlighted(myAccountItemGeneral.children)}
</div>
</div>
<div className="pt-4 pb-2 lg:p-7.5 lg:pb-5 grow">
<div className="grid lg:grid-cols-5 gap-5">
{myAccountItemOthers.children?.map((item: IMenuItemConfig, index) => {
return (
<div key={`item-${index}`} className="flex flex-col">
<h3 className="text-sm text-gray-800 font-semibold leading-none ps-2.5 mb-2 lg:mb-5">
{item.title}
</h3>
<div className="menu menu-default menu-fit flex-col">
{item.children && MegaMenuSubDefault(item.children)}
</div>
</div>
);
})}
</div>
</div>
</MenuSub>
);
};
export { MegaMenuSubAccount };

View File

@ -0,0 +1,47 @@
import { IMenuItemConfig, TMenuConfig, MenuSub } from '@/components/menu';
import { MegaMenuFooter, MegaMenuSubDefault, MegaMenuSubHighlighted } from './components';
const MegaMenuSubAuth = (items: TMenuConfig) => {
const authItem = items[4];
const authItemGeneral = authItem.children ? authItem.children[0] : {};
const authItemOthers = authItem.children ? authItem.children[1] : {};
return (
<MenuSub className="flex-col gap-0 w-full lg:max-w-[670px]">
<div className="flex flex-col lg:flex-row">
<div className="pt-4 pb-2 lg:p-7.5 lg:pb-5 grow">
<div className="grid lg:grid-cols-2 gap-5">
{authItemGeneral.children?.map((item: IMenuItemConfig, index) => {
return (
<div key={`item-${index}`} className="flex flex-col">
<h3 className="text-sm text-gray-800 font-semibold leading-none ps-2.5 mb-2 lg:mb-5">
{item.title}
{item.badge && (
<span className="start-auto badge badge-xs badge-primary badge-outline">
{item.badge}
</span>
)}
</h3>
<div className="menu menu-default menu-fit flex-col">
{item.children && MegaMenuSubDefault(item.children)}
</div>
</div>
);
})}
</div>
</div>
<div className="lg:w-[250px] mb-4 lg:mb-0 lg:border-l lg:border-s-gray-200 rounded-xl lg:rounded-e-xl lg:rounded-s-none shrink-0 px-3 py-4 lg:p-7.5 bg-light-active dark:bg-coal-500 dark:lg:border-l-coal-100">
<h3 className="text-sm text-gray-800 font-semibold leading-none ps-2.5 mb-5">
{authItemOthers.title}
</h3>
<div className="menu menu-default menu-fit flex-col">
{authItemOthers.children && MegaMenuSubHighlighted(authItemOthers.children)}
</div>
</div>
</div>
<MegaMenuFooter />
</MenuSub>
);
};
export { MegaMenuSubAuth };

View File

@ -0,0 +1,14 @@
import { TMenuConfig, MenuSub } from '@/components/menu';
import { MegaMenuSubDropdown } from './components';
const MegaMenuSubHelp = (items: TMenuConfig) => {
const helpItem = items[5];
return (
<MenuSub className="menu-default py-2.5 lg:w-[225px]">
{helpItem.children && MegaMenuSubDropdown(helpItem.children)}
</MenuSub>
);
};
export { MegaMenuSubHelp };

View File

@ -0,0 +1,47 @@
import { TMenuConfig, IMenuItemConfig, MenuSub } from '@/components/menu';
import { MegaMenuSubDefault, MegaMenuSubHighlighted, MegaMenuFooter } from './components';
const MegaMenuSubNetwork = (items: TMenuConfig) => {
const networkItem = items[3];
const networkItemGeneral = networkItem.children ? networkItem.children[0] : {};
const networkItemOthers = networkItem.children ? networkItem.children[1] : {};
return (
<MenuSub className="flex-col gap-0 w-full lg:max-w-[670px]">
<div className="flex flex-col lg:flex-row">
<div className="flex flex-col gap-5 lg:w-[250px] mt-2 lg:mt-0 lg:border-r lg:border-r-gray-200 rounded-xl lg:rounded-none lg:rounded-tl-xl shrink-0 px-3 py-4 lg:p-7.5 bg-light-active dark:bg-coal-500 dark:lg:border-e-coal-100">
<h3 className="text-sm text-gray-800 font-semibold leading-none ps-2.5 h-3.5">
{networkItemGeneral.title}
</h3>
<div className="menu menu-default menu-fit flex-col">
{networkItemGeneral.children && MegaMenuSubHighlighted(networkItemGeneral.children)}
</div>
</div>
<div className="pt-4 pb-2 lg:p-7.5 lg:pb-5 grow">
<div className="grid lg:grid-cols-2 gap-5">
{networkItemOthers.children?.map((item: IMenuItemConfig, index) => {
return (
<div key={`item-${index}`} className="flex flex-col gap-5">
<h3 className="flex items-center gap-1.5 text-sm text-gray-800 font-semibold leading-none ps-2.5 h-3.5">
{item.title}
{item.badge && (
<span className="start-auto badge badge-xs badge-primary badge-outline">
{item.badge}
</span>
)}
</h3>
<div className="menu menu-default menu-fit flex-col">
{item.children && MegaMenuSubDefault(item.children)}
</div>
</div>
);
})}
</div>
</div>
</div>
<MegaMenuFooter />
</MenuSub>
);
};
export { MegaMenuSubNetwork };

View File

@ -0,0 +1,36 @@
import { TMenuConfig, IMenuItemConfig, MenuSub } from '@/components/menu';
import { MegaMenuSubDefault, MegaMenuFooter } from './components';
const MegaMenuSubProfiles = (items: TMenuConfig) => {
const publicProfilesItem = items[1];
return (
<MenuSub className="w-full gap-0 lg:max-w-[875px]">
<div className="pt-4 pb-2 lg:p-7.5">
<div className="grid lg:grid-cols-2 gap-5 lg:gap-10">
{publicProfilesItem.children?.map((item: IMenuItemConfig, index) => {
return (
<div key={`item-${index}`} className="menu menu-default menu-fit flex-col">
<h3 className="text-sm text-gray-800 font-semibold leading-none ps-2.5 mb-2 lg:mb-5">
{item.title}
</h3>
<div className="grid lg:grid-cols-2 lg:gap-5">
{item.children?.map((item: IMenuItemConfig, index) => {
return (
<div key={`item-${index}`} className="flex flex-col">
{item.children && MegaMenuSubDefault(item.children)}
</div>
);
})}
</div>
</div>
);
})}
</div>
</div>
<MegaMenuFooter />
</MenuSub>
);
};
export { MegaMenuSubProfiles };

View File

@ -0,0 +1,19 @@
const MegaMenuFooter = () => {
return (
<div className="flex flex-wrap items-center lg:justify-between rounded-xl lg:rounded-t-none bg-light-active dark:bg-coal-500 border border-gray-300 lg:border-0 lg:border-t lg:border-t-gray-300 dark:lg:border-t-gray-100 px-4 py-4 lg:px-7.5 lg:py-5 gap-2.5">
<div className="flex flex-col gap-1.5">
<div className="text-md font-semibold text-gray-900 leading-none">
Read to Get Started ?
</div>
<div className="text-2sm fomt-medium text-gray-600">
Take your docs to the next level of Metronic
</div>
</div>
<a href="#" className="btn btn-sm btn-dark">
Read Documentation
</a>
</div>
);
};
export { MegaMenuFooter };

View File

@ -0,0 +1,51 @@
import { KeenIcon } from '@/components';
import { TMenuConfig, MenuItem, MenuLink, MenuTitle, MenuIcon, MenuBadge } from '@/components/menu';
import clsx from 'clsx';
import { ReactNode } from 'react';
const MegaMenuSubDefault = (items: TMenuConfig) => {
const buildItems = (items: TMenuConfig): ReactNode => {
return items.map((item, index) => {
if (item.children) {
return (
<div key={index}>
<MenuItem className="pt-1">
<span className="text-gray-600 font-medium text-2sm p-2.5">{item.title}</span>
</MenuItem>
{buildItems(item.children)}
</div>
);
} else {
return (
<MenuItem key={index}>
<MenuLink path={item.path}>
{item.icon && (
<MenuIcon>
<KeenIcon icon={item.icon} />
</MenuIcon>
)}
<MenuTitle className={clsx('grow-0')}>{item.title}</MenuTitle>
{item.disabled && (
<MenuBadge>
<span className="badge badge-xs">Soon</span>
</MenuBadge>
)}
{item.badge && (
<MenuBadge>
<span className="badge badge-primary badge-outline badge-xs">{item.badge}</span>
</MenuBadge>
)}
</MenuLink>
</MenuItem>
);
}
});
};
return buildItems(items);
};
export { MegaMenuSubDefault };

View File

@ -0,0 +1,90 @@
import { DefaultTooltip, KeenIcon } from '@/components';
import {
TMenuConfig,
MenuItem,
MenuLink,
MenuSub,
MenuTitle,
MenuArrow,
MenuIcon,
MenuBadge,
MenuSeparator
} from '@/components/menu';
import { useResponsive } from '@/hooks';
import { useLanguage } from '@/i18n';
import clsx from 'clsx';
import { ReactNode } from 'react';
const MegaMenuSubDropdown = (items: TMenuConfig) => {
const desktopMode = useResponsive('up', 'lg');
const { isRTL } = useLanguage();
const buildItems = (items: TMenuConfig): ReactNode => {
return items.map((item, index) => {
if (item.separator) {
return <MenuSeparator key={index} />;
} else if (item.children) {
return (
<MenuItem
key={index}
toggle={desktopMode ? 'dropdown' : 'accordion'}
trigger={desktopMode ? 'hover' : 'click'}
dropdownProps={{
placement: isRTL() ? 'left-start' : 'right-start'
}}
>
<MenuLink className="grow-0">
{item.icon && (
<MenuIcon>
<KeenIcon icon={item.icon} />
</MenuIcon>
)}
<MenuTitle className={clsx('')}>{item.title}</MenuTitle>
<MenuArrow>
<KeenIcon icon="right" className="text-3xs rtl:transform rtl:rotate-180" />
</MenuArrow>
</MenuLink>
<MenuSub className="menu-default" rootClassName="max-w-[175px] lg:max-w-[220px]">
{buildItems(item.children)}
</MenuSub>
</MenuItem>
);
} else {
return (
<MenuItem key={index}>
<MenuLink path={item.path}>
{item.icon && (
<MenuIcon>
<KeenIcon icon={item.icon} />
</MenuIcon>
)}
<MenuTitle>{item.title}</MenuTitle>
{item.disabled && (
<MenuBadge>
<span className="badge badge-xs">Soon</span>
</MenuBadge>
)}
{item.badge && (
<MenuBadge>
<span className="badge badge-primary badge-outline badge-xs">{item.badge}</span>
</MenuBadge>
)}
{item.tooltip && (
<DefaultTooltip title={item.tooltip.title} placement={item.tooltip.placement}>
<KeenIcon icon="information-2" className="text-gray-500 text-md" />
</DefaultTooltip>
)}
</MenuLink>
</MenuItem>
);
}
});
};
return buildItems(items);
};
export { MegaMenuSubDropdown };

View File

@ -0,0 +1,49 @@
import { KeenIcon } from '@/components';
import { TMenuConfig, MenuItem, MenuLink, MenuTitle, MenuIcon, MenuBadge } from '@/components/menu';
import clsx from 'clsx';
import { ReactNode } from 'react';
const MegaMenuSubHighlighted = (items: TMenuConfig) => {
const buildItems = (items: TMenuConfig): ReactNode => {
return items.map((item, index) => {
return (
<MenuItem key={index}>
<MenuLink
path={item.path}
className="
menu-link border border-transparent
menu-link-hover:!bg-light menu-link-hover:border-gray-200
menu-item-active:!bg-light menu-item-active:border-gray-200
dark:menu-link-hover:!bg-coal-600 dark:menu-link-hover:border-gray-100
dark:menu-item-active:!bg-coal-600 dark:menu-item-active:border-gray-100
"
>
{item.icon && (
<MenuIcon>
<KeenIcon icon={item.icon} />
</MenuIcon>
)}
<MenuTitle className={clsx('grow-0')}>{item.title}</MenuTitle>
{item.disabled && (
<MenuBadge>
<span className="badge badge-xs">Soon</span>
</MenuBadge>
)}
{item.badge && (
<MenuBadge>
<span className="badge badge-primary badge-outline badge-xs">{item.badge}</span>
</MenuBadge>
)}
</MenuLink>
</MenuItem>
);
});
};
return buildItems(items);
};
export { MegaMenuSubHighlighted };

View File

@ -0,0 +1,4 @@
export * from './MegaMenuFooter';
export * from './MegaMenuSubDefault';
export * from './MegaMenuSubDropdown';
export * from './MegaMenuSubHighlighted';

View File

@ -0,0 +1,6 @@
export * from './components';
export * from './MegaMenuSubProfiles';
export * from './MegaMenuSubAccount';
export * from './MegaMenuSubNetwork';
export * from './MegaMenuSubAuth';
export * from './MegaMenuSubHelp';