Compare commits
No commits in common. "ai-dev" and "master" have entirely different histories.
@ -14,7 +14,7 @@ export const colorsBgLight = {
|
||||
success: 'bg-emerald-500 border-emerald-500 dark:bg-pavitra-blue dark:border-pavitra-blue text-white',
|
||||
danger: 'bg-red-500 border-red-500 text-white',
|
||||
warning: 'bg-yellow-500 border-yellow-500 text-white',
|
||||
info: 'bg-indigo-600 border-indigo-600 dark:bg-indigo-500 dark:border-indigo-500 text-white shadow-lg shadow-indigo-500/20',
|
||||
info: 'bg-blue-500 border-blue-500 dark:bg-pavitra-blue dark:border-pavitra-blue text-white',
|
||||
}
|
||||
|
||||
export const colorsText = {
|
||||
@ -24,7 +24,7 @@ export const colorsText = {
|
||||
success: 'text-emerald-500',
|
||||
danger: 'text-red-500',
|
||||
warning: 'text-yellow-500',
|
||||
info: 'text-indigo-500',
|
||||
info: 'text-blue-500',
|
||||
};
|
||||
|
||||
export const colorsOutline = {
|
||||
@ -34,7 +34,7 @@ export const colorsOutline = {
|
||||
success: [colorsText.success, 'border-emerald-500'].join(' '),
|
||||
danger: [colorsText.danger, 'border-red-500'].join(' '),
|
||||
warning: [colorsText.warning, 'border-yellow-500'].join(' '),
|
||||
info: [colorsText.info, 'border-indigo-500'].join(' '),
|
||||
info: [colorsText.info, 'border-blue-500'].join(' '),
|
||||
};
|
||||
|
||||
export const getButtonColor = (
|
||||
@ -56,7 +56,7 @@ export const getButtonColor = (
|
||||
success: 'ring-emerald-300 dark:ring-pavitra-blue',
|
||||
danger: 'ring-red-300 dark:ring-red-700',
|
||||
warning: 'ring-yellow-300 dark:ring-yellow-700',
|
||||
info: "ring-indigo-300 dark:ring-indigo-700",
|
||||
info: "ring-midnightBlueTheme-buttonColor dark:ring-pavitra-blue",
|
||||
},
|
||||
active: {
|
||||
white: 'bg-gray-100',
|
||||
@ -66,57 +66,57 @@ export const getButtonColor = (
|
||||
success: 'bg-emerald-700 dark:bg-pavitra-blue',
|
||||
danger: 'bg-red-700 dark:bg-red-600',
|
||||
warning: 'bg-yellow-700 dark:bg-yellow-600',
|
||||
info: 'bg-indigo-700 dark:bg-indigo-600',
|
||||
info: 'bg-midnightBlueTheme-buttonColor dark:bg-pavitra-blue',
|
||||
},
|
||||
bg: {
|
||||
white: 'bg-white text-black border-gray-200',
|
||||
whiteDark: 'bg-midnightBlueTheme-outsideCardColor text-primaryText dark:bg-dark-900 dark:text-white border-white/10',
|
||||
lightDark: 'bg-gray-100 text-black dark:bg-slate-800 dark:text-white border-gray-200 dark:border-white/10',
|
||||
white: 'bg-white text-black',
|
||||
whiteDark: 'bg-midnightBlueTheme-outsideCardColor text-primaryText dark:bg-dark-900 dark:text-white',
|
||||
lightDark: 'bg-gray-100 text-black dark:bg-slate-800 dark:text-white',
|
||||
contrast: 'bg-gray-800 text-white dark:bg-white dark:text-black',
|
||||
success: 'bg-emerald-600 dark:bg-pavitra-blue text-white border-emerald-600',
|
||||
danger: 'bg-red-500 text-white dark:bg-red-600 border-red-500',
|
||||
warning: 'bg-yellow-600 dark:bg-yellow-500 text-white border-yellow-600',
|
||||
info: "bg-indigo-600 text-white border-indigo-600 shadow-lg shadow-indigo-600/30",
|
||||
success: 'bg-emerald-600 dark:bg-pavitra-blue text-white',
|
||||
danger: 'bg-midnightBlueTheme-outsideCardColor text-red-500 dark:text-white dark:bg-red-500 ',
|
||||
warning: 'bg-yellow-600 dark:bg-yellow-500 text-white',
|
||||
info: " bg-midnightBlueTheme-buttonColor dark:bg-pavitra-blue text-white ",
|
||||
},
|
||||
bgHover: {
|
||||
white: 'hover:bg-gray-50 hover:border-gray-300',
|
||||
whiteDark: 'hover:bg-midnightBlueTheme-outsideCardColor/80 hover:dark:bg-dark-800',
|
||||
white: 'hover:bg-gray-100',
|
||||
whiteDark: 'hover:bg-midnightBlueTheme-outsideCardColor hover:dark:bg-dark-800',
|
||||
lightDark: 'hover:bg-gray-200 hover:dark:bg-slate-700',
|
||||
contrast: 'hover:bg-gray-700 hover:dark:bg-slate-100',
|
||||
success:
|
||||
'hover:bg-emerald-700 hover:border-emerald-700 hover:dark:bg-pavitra-blue/90 hover:dark:border-pavitra-blue/90',
|
||||
'hover:bg-emerald-700 hover:border-emerald-700 hover:dark:bg-pavitra-blue hover:dark:border-pavitra-blue',
|
||||
danger:
|
||||
'hover:bg-red-600 hover:border-red-600 hover:dark:bg-red-500',
|
||||
'hover:bg-red-700 hover:border-red-700 hover:dark:bg-red-600 hover:dark:border-red-600',
|
||||
warning:
|
||||
'hover:bg-yellow-700 hover:border-yellow-700 hover:dark:bg-yellow-600',
|
||||
info: "hover:bg-indigo-700 hover:border-indigo-700 hover:shadow-indigo-600/40",
|
||||
'hover:bg-yellow-700 hover:border-yellow-700 hover:dark:bg-yellow-600 hover:dark:border-yellow-600',
|
||||
info: "hover:bg-midnightBlueTheme-800 hover:border-midnightBlueTheme-buttonColor hover:text-primaryText hover:dark:bg-pavitra-blue/80 hover:dark:border-pavitra-blue/80",
|
||||
},
|
||||
borders: {
|
||||
white: 'border-white',
|
||||
whiteDark: 'border-midnightBlueTheme-outsideCardColor dark:border-dark-900',
|
||||
whiteDark: 'border-midnightBlueTheme-outsideCardColor dark:border-dark-900',
|
||||
lightDark: 'border-gray-100 dark:border-slate-800',
|
||||
contrast: 'border-gray-800 dark:border-white',
|
||||
success: 'border-emerald-600 dark:border-pavitra-blue',
|
||||
danger: 'border-red-600 dark:border-red-500',
|
||||
warning: 'border-yellow-600 dark:border-yellow-500',
|
||||
info: "border-indigo-600 dark:border-indigo-500",
|
||||
info: "border-midnightBlueTheme-buttonColor border-blue-600 dark:border-pavitra-blue",
|
||||
},
|
||||
text: {
|
||||
contrast: 'dark:text-slate-100',
|
||||
success: 'text-emerald-600 dark:text-pavitra-blue',
|
||||
danger: 'text-red-600 dark:text-red-500',
|
||||
warning: 'text-yellow-600 dark:text-yellow-500',
|
||||
info: 'text-indigo-600 dark:text-indigo-400',
|
||||
info: ' dark:text-pavitra-blue',
|
||||
},
|
||||
outlineHover: {
|
||||
contrast:
|
||||
'hover:bg-gray-800 hover:text-gray-100 hover:dark:bg-slate-100 hover:dark:text-black',
|
||||
success: 'hover:bg-emerald-600 hover:text-white hover:dark:bg-emerald-700',
|
||||
success: 'hover:bg-emerald-600 hover:text-white hover:text-white hover:dark:text-white hover:dark:border-pavitra-blue',
|
||||
danger:
|
||||
'hover:bg-red-600 hover:text-white hover:dark:bg-red-700',
|
||||
'hover:bg-red-600 hover:text-white hover:text-white hover:dark:text-white hover:dark:border-red-600',
|
||||
warning:
|
||||
'hover:bg-yellow-600 hover:text-white hover:dark:bg-yellow-700',
|
||||
info: "hover:bg-indigo-600 hover:text-white hover:dark:bg-indigo-700",
|
||||
'hover:bg-yellow-600 hover:text-white hover:text-white hover:dark:text-white hover:dark:border-yellow-600',
|
||||
info: "hover:bg-midnightBlueTheme-buttonColor text-midnightBlueTheme-buttonColor hover:bg-blue-600 hover:text-white hover:dark:text-white hover:dark:border-pavitra-blue",
|
||||
},
|
||||
}
|
||||
|
||||
@ -135,4 +135,4 @@ export const getButtonColor = (
|
||||
}
|
||||
|
||||
return base.join(' ')
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { mdiLogout, mdiClose, mdiWeatherSunny } from '@mdi/js'
|
||||
import { mdiLogout, mdiClose } from '@mdi/js'
|
||||
import BaseIcon from './BaseIcon'
|
||||
import AsideMenuList from './AsideMenuList'
|
||||
import { MenuAsideItem } from '../interfaces'
|
||||
@ -29,42 +29,35 @@ export default function AsideMenuLayer({ menu, className = '', ...props }: Props
|
||||
return (
|
||||
<aside
|
||||
id='asideMenu'
|
||||
className={`${className} lg:py-4 lg:pl-4 w-64 fixed flex z-40 top-0 h-screen transition-all duration-300 overflow-hidden`}
|
||||
className={`${className} zzz lg:py-2 lg:pl-2 w-60 fixed flex z-40 top-0 h-screen transition-position overflow-hidden`}
|
||||
>
|
||||
<div
|
||||
className={`flex-1 flex flex-col overflow-hidden ${asideStyle} ${corners} border border-white/5 shadow-2xl backdrop-blur-2xl`}
|
||||
className={`flex-1 flex flex-col overflow-hidden dark:bg-dark-900 ${asideStyle} ${corners}`}
|
||||
>
|
||||
<div
|
||||
className={`flex flex-row h-20 items-center justify-between ${asideBrandStyle} px-6 border-b border-white/5`}
|
||||
className={`flex flex-row h-14 items-center justify-between ${asideBrandStyle}`}
|
||||
>
|
||||
<Link href="/" className="flex items-center space-x-3 group">
|
||||
<div className="bg-gradient-to-tr from-indigo-500 to-purple-600 p-2 rounded-xl shadow-lg group-hover:rotate-12 transition-transform duration-300">
|
||||
<BaseIcon path={mdiWeatherSunny} size={24} className="text-white" />
|
||||
</div>
|
||||
<span className="text-xl font-black tracking-tighter bg-clip-text text-transparent bg-gradient-to-r from-white to-indigo-200">
|
||||
Morninmate
|
||||
</span>
|
||||
</Link>
|
||||
<div className="text-center flex-1 lg:text-left lg:pl-6 xl:text-center xl:pl-0">
|
||||
|
||||
<b className="font-black">App Preview</b>
|
||||
|
||||
|
||||
</div>
|
||||
<button
|
||||
className="lg:hidden p-2 text-white/60 hover:text-white transition-colors"
|
||||
className="hidden lg:inline-block xl:hidden p-3"
|
||||
onClick={handleAsideLgCloseClick}
|
||||
>
|
||||
<BaseIcon path={mdiClose} />
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
className={`flex-1 overflow-y-auto overflow-x-hidden pt-4 ${
|
||||
className={`flex-1 overflow-y-auto overflow-x-hidden ${
|
||||
darkMode ? 'aside-scrollbars-[slate]' : asideScrollbarsStyle
|
||||
}`}
|
||||
>
|
||||
<AsideMenuList menu={menu} />
|
||||
</div>
|
||||
<div className="p-4 border-t border-white/5">
|
||||
<div className="bg-indigo-500/10 rounded-2xl p-4 text-xs text-indigo-200/60 text-center">
|
||||
Elevate your morning.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,22 +49,22 @@ export default function BaseButton({
|
||||
'items-center',
|
||||
'whitespace-nowrap',
|
||||
'focus:outline-none',
|
||||
'transition-all',
|
||||
'transition-colors',
|
||||
'focus:ring',
|
||||
'duration-300',
|
||||
'duration-150',
|
||||
'border',
|
||||
disabled ? 'cursor-not-allowed' : 'cursor-pointer hover:scale-[1.02] active:scale-[0.98]',
|
||||
disabled ? 'cursor-not-allowed' : 'cursor-pointer',
|
||||
roundedFull ? 'rounded-full' : `${corners}`,
|
||||
getButtonColor(color, outline, !disabled, active),
|
||||
className,
|
||||
]
|
||||
|
||||
if (!label && icon) {
|
||||
componentClass.push('p-1.5')
|
||||
componentClass.push('p-1')
|
||||
} else if (small) {
|
||||
componentClass.push('text-sm', roundedFull ? 'px-4 py-1.5' : 'px-2 py-1')
|
||||
componentClass.push('text-sm', roundedFull ? 'px-3 py-1' : 'p-1')
|
||||
} else {
|
||||
componentClass.push('py-2.5', roundedFull ? 'px-8' : 'px-5')
|
||||
componentClass.push('py-2', roundedFull ? 'px-6' : 'px-3')
|
||||
}
|
||||
|
||||
if (disabled) {
|
||||
@ -76,7 +76,7 @@ export default function BaseButton({
|
||||
const componentChildren = (
|
||||
<>
|
||||
{icon && <BaseIcon path={icon} size={iconSize} className={iconClassName} />}
|
||||
{label && <span className={`font-semibold ${small && icon ? 'px-1' : 'px-2'}`}>{label}</span>}
|
||||
{label && <span className={small && icon ? 'px-1' : 'px-2'}>{label}</span>}
|
||||
</>
|
||||
)
|
||||
|
||||
@ -93,4 +93,4 @@ export default function BaseButton({
|
||||
{ className: componentClassString, type: type ?? 'button', target, disabled, onClick },
|
||||
componentChildren
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,16 +37,16 @@ export default function CardBox({
|
||||
const corners = useAppSelector((state) => state.style.corners);
|
||||
const cardsStyle = useAppSelector((state) => state.style.cardsStyle);
|
||||
const componentClass = [
|
||||
`flex transition-all duration-300 ease-in-out`,
|
||||
`flex dark:border-dark-700 dark:bg-dark-900`,
|
||||
className,
|
||||
corners !== 'rounded-full'? corners : 'rounded-3xl',
|
||||
flex,
|
||||
isList ? '' : `${cardsStyle}`,
|
||||
hasTable ? '' : ``,
|
||||
hasTable ? '' : `border-dark-700 dark:border-dark-700`,
|
||||
]
|
||||
|
||||
if (isHoverable) {
|
||||
componentClass.push('hover:shadow-2xl hover:scale-[1.01] hover:border-indigo-500/20 cursor-pointer')
|
||||
componentClass.push('hover:shadow-lg transition-shadow duration-500')
|
||||
}
|
||||
|
||||
return React.createElement(
|
||||
@ -61,4 +61,4 @@ export default function CardBox({
|
||||
</>
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,9 +20,7 @@ export default function IconRounded({
|
||||
bg = false,
|
||||
className = '',
|
||||
}: Props) {
|
||||
const classAddon = bg
|
||||
? (color === 'info' ? 'bg-gradient-to-br from-indigo-500 to-purple-600 text-white shadow-lg shadow-indigo-500/20' : colorsBgLight[color])
|
||||
: `${colorsText[color]} bg-gray-50 dark:bg-slate-800`
|
||||
const classAddon = bg ? colorsBgLight[color] : `${colorsText[color]} bg-gray-50 dark:bg-slate-800`
|
||||
|
||||
return (
|
||||
<BaseIcon
|
||||
@ -30,7 +28,7 @@ export default function IconRounded({
|
||||
w={w}
|
||||
h={h}
|
||||
size="24"
|
||||
className={`rounded-2xl transition-all duration-300 transform hover:scale-110 ${classAddon} ${className}`}
|
||||
className={`rounded-full ${classAddon} ${className}`}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,5 +6,5 @@ type Props = {
|
||||
}
|
||||
|
||||
export default function SectionMain({ children }: Props) {
|
||||
return <section className={`p-4 md:p-8 lg:p-12 ${containerMaxW}`}>{children}</section>
|
||||
}
|
||||
return <section className={`p-6 ${containerMaxW}`}>{children}</section>
|
||||
}
|
||||
|
||||
@ -86,23 +86,18 @@ export default function LayoutAuthenticated({
|
||||
}, [router.events, dispatch])
|
||||
|
||||
|
||||
const layoutAsidePadding = 'xl:pl-64'
|
||||
const layoutAsidePadding = 'xl:pl-60'
|
||||
|
||||
return (
|
||||
<div className={`${darkMode ? 'dark' : ''} overflow-hidden lg:overflow-visible`}>
|
||||
<div
|
||||
className={`${layoutAsidePadding} ${
|
||||
isAsideMobileExpanded ? 'ml-64 lg:ml-0' : ''
|
||||
} pt-16 min-h-screen w-screen transition-all duration-300 lg:w-auto ${bgColor} dark:bg-dark-800 dark:text-slate-100 relative`}
|
||||
isAsideMobileExpanded ? 'ml-60 lg:ml-0' : ''
|
||||
} pt-14 min-h-screen w-screen transition-position lg:w-auto ${bgColor} dark:bg-dark-800 dark:text-slate-100`}
|
||||
>
|
||||
<div className="fixed inset-0 pointer-events-none overflow-hidden z-0">
|
||||
<div className="absolute -top-[10%] -left-[10%] w-[40%] h-[40%] bg-indigo-500/10 blur-[120px] rounded-full"></div>
|
||||
<div className="absolute top-[60%] -right-[5%] w-[30%] h-[30%] bg-purple-500/10 blur-[100px] rounded-full"></div>
|
||||
</div>
|
||||
|
||||
<NavBar
|
||||
menu={menuNavBar}
|
||||
className={`${layoutAsidePadding} ${isAsideMobileExpanded ? 'ml-64 lg:ml-0' : ''}`}
|
||||
className={`${layoutAsidePadding} ${isAsideMobileExpanded ? 'ml-60 lg:ml-0' : ''}`}
|
||||
>
|
||||
<NavBarItemPlain
|
||||
display="flex lg:hidden"
|
||||
@ -126,11 +121,9 @@ export default function LayoutAuthenticated({
|
||||
menu={menuAside}
|
||||
onAsideLgClose={() => setIsAsideLgActive(false)}
|
||||
/>
|
||||
<div className="relative z-10">
|
||||
{children}
|
||||
</div>
|
||||
{children}
|
||||
<FooterBar>Hand-crafted & Made with ❤️</FooterBar>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,14 +16,13 @@ import { WidgetCreator } from '../components/WidgetCreator/WidgetCreator';
|
||||
import { SmartWidget } from '../components/SmartWidget/SmartWidget';
|
||||
|
||||
import { useAppDispatch, useAppSelector } from '../stores/hooks';
|
||||
|
||||
const Dashboard = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const iconsColor = useAppSelector((state) => state.style.iconsColor);
|
||||
const corners = useAppSelector((state) => state.style.corners);
|
||||
const cardsStyle = useAppSelector((state) => state.style.cardsStyle);
|
||||
|
||||
const loadingMessage = '...';
|
||||
const loadingMessage = 'Loading...';
|
||||
|
||||
|
||||
const [users, setUsers] = React.useState(loadingMessage);
|
||||
@ -93,37 +92,6 @@ const Dashboard = () => {
|
||||
getWidgets(widgetsRole?.role?.value || '').then();
|
||||
}, [widgetsRole?.role?.value]);
|
||||
|
||||
const StatCard = ({ title, count, iconPath, href, gradient }) => (
|
||||
<Link href={href}>
|
||||
<div className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6 group transition-all duration-300 hover:scale-[1.02] hover:shadow-2xl relative overflow-hidden h-full flex flex-col justify-between`}>
|
||||
<div className={`absolute -right-4 -top-4 w-24 h-24 bg-gradient-to-br ${gradient} opacity-10 group-hover:opacity-20 rounded-full transition-all duration-500 transform group-hover:scale-150`}></div>
|
||||
<div className="flex justify-between items-start relative z-10">
|
||||
<div className="space-y-1">
|
||||
<div className="text-sm font-medium text-indigo-300 uppercase tracking-wider opacity-70">
|
||||
{title}
|
||||
</div>
|
||||
<div className="text-4xl font-bold tracking-tight">
|
||||
{count}
|
||||
</div>
|
||||
</div>
|
||||
<div className={`p-3 bg-gradient-to-br ${gradient} rounded-2xl shadow-lg transform group-hover:rotate-12 transition-transform duration-300`}>
|
||||
<BaseIcon
|
||||
className="text-white"
|
||||
w="w-8"
|
||||
h="h-8"
|
||||
size={32}
|
||||
path={iconPath}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 flex items-center text-xs font-semibold text-indigo-400 group-hover:text-indigo-300 transition-colors">
|
||||
View detailed list
|
||||
<BaseIcon path={icon.mdiChevronRight} size={16} />
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
@ -132,15 +100,12 @@ const Dashboard = () => {
|
||||
</title>
|
||||
</Head>
|
||||
<SectionMain>
|
||||
<div className="mb-10">
|
||||
<SectionTitleLineWithButton
|
||||
icon={icon.mdiChartTimelineVariant}
|
||||
title='Overview'
|
||||
main>
|
||||
{''}
|
||||
</SectionTitleLineWithButton>
|
||||
<p className="text-indigo-200/60 -mt-6">Welcome back, {currentUser?.firstName || 'Mate'}! Here's what's happening today.</p>
|
||||
</div>
|
||||
<SectionTitleLineWithButton
|
||||
icon={icon.mdiChartTimelineVariant}
|
||||
title='Overview'
|
||||
main>
|
||||
{''}
|
||||
</SectionTitleLineWithButton>
|
||||
|
||||
{hasPermission(currentUser, 'CREATE_ROLES') && <WidgetCreator
|
||||
currentUser={currentUser}
|
||||
@ -148,18 +113,24 @@ const Dashboard = () => {
|
||||
setWidgetsRole={setWidgetsRole}
|
||||
widgetsRole={widgetsRole}
|
||||
/>}
|
||||
|
||||
<div className='grid grid-cols-1 gap-6 lg:grid-cols-4 mb-10 grid-flow-dense'>
|
||||
{!!rolesWidgets.length &&
|
||||
hasPermission(currentUser, 'CREATE_ROLES') && (
|
||||
<p className=' text-gray-500 dark:text-gray-400 mb-4'>
|
||||
{`${widgetsRole?.role?.label || 'Users'}'s widgets`}
|
||||
</p>
|
||||
)}
|
||||
|
||||
<div className='grid grid-cols-1 gap-6 lg:grid-cols-4 mb-6 grid-flow-dense'>
|
||||
{(isFetchingQuery || loading) && (
|
||||
<div className={` ${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 text-lg leading-tight text-gray-500 flex items-center ${cardsStyle} dark:border-dark-700 p-8 col-span-full justify-center`}>
|
||||
<div className={` ${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 text-lg leading-tight text-gray-500 flex items-center ${cardsStyle} dark:border-dark-700 p-6`}>
|
||||
<BaseIcon
|
||||
className={`${iconsColor} animate-spin mr-5`}
|
||||
w='w-12'
|
||||
h='h-12'
|
||||
size={32}
|
||||
w='w-16'
|
||||
h='h-16'
|
||||
size={48}
|
||||
path={icon.mdiLoading}
|
||||
/>{' '}
|
||||
Organizing your dashboard...
|
||||
Loading widgets...
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -175,79 +146,460 @@ const Dashboard = () => {
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div id="dashboard" className='grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4'>
|
||||
{hasPermission(currentUser, 'READ_USERS') && (
|
||||
<StatCard
|
||||
title="Users"
|
||||
count={users}
|
||||
iconPath={icon.mdiAccountGroup}
|
||||
href='/users/users-list'
|
||||
gradient="from-indigo-500 to-blue-600"
|
||||
/>
|
||||
)}
|
||||
{hasPermission(currentUser, 'READ_PULSES') && (
|
||||
<StatCard
|
||||
title="Pulses"
|
||||
count={pulses}
|
||||
iconPath={icon.mdiAlarm}
|
||||
href='/pulses/pulses-list'
|
||||
gradient="from-purple-500 to-pink-600"
|
||||
/>
|
||||
)}
|
||||
{hasPermission(currentUser, 'READ_COMPLETED_PULSES') && (
|
||||
<StatCard
|
||||
title="Completions"
|
||||
count={completed_pulses}
|
||||
iconPath={icon.mdiCalendarCheck}
|
||||
href='/completed_pulses/completed_pulses-list'
|
||||
gradient="from-emerald-500 to-teal-600"
|
||||
/>
|
||||
)}
|
||||
{hasPermission(currentUser, 'READ_POTENTIAL_SCORES') && (
|
||||
<StatCard
|
||||
title="Potential Score"
|
||||
count={potential_scores}
|
||||
iconPath={icon.mdiGauge}
|
||||
href='/potential_scores/potential_scores-list'
|
||||
gradient="from-amber-500 to-orange-600"
|
||||
/>
|
||||
)}
|
||||
{hasPermission(currentUser, 'READ_GAMES') && (
|
||||
<StatCard
|
||||
title="Games"
|
||||
count={games}
|
||||
iconPath={icon.mdiGamepadVariant}
|
||||
href='/games/games-list'
|
||||
gradient="from-cyan-500 to-blue-500"
|
||||
/>
|
||||
)}
|
||||
{hasPermission(currentUser, 'READ_ACTIVITIES') && (
|
||||
<StatCard
|
||||
title="Activities"
|
||||
count={activities}
|
||||
iconPath={icon.mdiRun}
|
||||
href='/activities/activities-list'
|
||||
gradient="from-rose-500 to-red-600"
|
||||
/>
|
||||
)}
|
||||
{hasPermission(currentUser, 'READ_REWARD_BALANCES') && (
|
||||
<StatCard
|
||||
title="Rewards"
|
||||
count={reward_balances}
|
||||
iconPath={icon.mdiTrophy}
|
||||
href='/reward_balances/reward_balances-list'
|
||||
gradient="from-yellow-400 to-amber-600"
|
||||
/>
|
||||
)}
|
||||
{hasPermission(currentUser, 'READ_FAQS') && (
|
||||
<StatCard
|
||||
title="Faqs"
|
||||
count={faqs}
|
||||
iconPath={icon.mdiFrequentlyAskedQuestions}
|
||||
href='/faqs/faqs-list'
|
||||
gradient="from-slate-500 to-slate-700"
|
||||
/>
|
||||
)}
|
||||
{!!rolesWidgets.length && <hr className='my-6 text-midnightBlueTheme-mainBG ' />}
|
||||
|
||||
<div id="dashboard" className='grid grid-cols-1 gap-6 lg:grid-cols-3 mb-6'>
|
||||
|
||||
|
||||
{hasPermission(currentUser, 'READ_USERS') && <Link href={'/users/users-list'}>
|
||||
<div
|
||||
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Users
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">
|
||||
{users}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
path={icon.mdiAccountGroup || icon.mdiTable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>}
|
||||
|
||||
{hasPermission(currentUser, 'READ_ROLES') && <Link href={'/roles/roles-list'}>
|
||||
<div
|
||||
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Roles
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">
|
||||
{roles}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
path={icon.mdiShieldAccountVariantOutline || icon.mdiTable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>}
|
||||
|
||||
{hasPermission(currentUser, 'READ_PERMISSIONS') && <Link href={'/permissions/permissions-list'}>
|
||||
<div
|
||||
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Permissions
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">
|
||||
{permissions}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
path={icon.mdiShieldAccountOutline || icon.mdiTable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>}
|
||||
|
||||
{hasPermission(currentUser, 'READ_USER_ONBOARDING_ANSWERS') && <Link href={'/user_onboarding_answers/user_onboarding_answers-list'}>
|
||||
<div
|
||||
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
User onboarding answers
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">
|
||||
{user_onboarding_answers}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
path={'mdiHelpCircle' in icon ? icon['mdiHelpCircle' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>}
|
||||
|
||||
{hasPermission(currentUser, 'READ_ACTIVITIES') && <Link href={'/activities/activities-list'}>
|
||||
<div
|
||||
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Activities
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">
|
||||
{activities}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
path={'mdiRun' in icon ? icon['mdiRun' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>}
|
||||
|
||||
{hasPermission(currentUser, 'READ_PULSES') && <Link href={'/pulses/pulses-list'}>
|
||||
<div
|
||||
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Pulses
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">
|
||||
{pulses}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
path={'mdiAlarm' in icon ? icon['mdiAlarm' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>}
|
||||
|
||||
{hasPermission(currentUser, 'READ_COMPLETED_PULSES') && <Link href={'/completed_pulses/completed_pulses-list'}>
|
||||
<div
|
||||
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Completed pulses
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">
|
||||
{completed_pulses}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
path={'mdiCalendarCheck' in icon ? icon['mdiCalendarCheck' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>}
|
||||
|
||||
{hasPermission(currentUser, 'READ_POTENTIAL_SCORES') && <Link href={'/potential_scores/potential_scores-list'}>
|
||||
<div
|
||||
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Potential scores
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">
|
||||
{potential_scores}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
path={'mdiGauge' in icon ? icon['mdiGauge' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>}
|
||||
|
||||
{hasPermission(currentUser, 'READ_GAMES') && <Link href={'/games/games-list'}>
|
||||
<div
|
||||
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Games
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">
|
||||
{games}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
path={'mdiGamepadVariant' in icon ? icon['mdiGamepadVariant' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>}
|
||||
|
||||
{hasPermission(currentUser, 'READ_GAME_SESSIONS') && <Link href={'/game_sessions/game_sessions-list'}>
|
||||
<div
|
||||
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Game sessions
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">
|
||||
{game_sessions}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
path={'mdiTimerPlay' in icon ? icon['mdiTimerPlay' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>}
|
||||
|
||||
{hasPermission(currentUser, 'READ_REWARD_BALANCES') && <Link href={'/reward_balances/reward_balances-list'}>
|
||||
<div
|
||||
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Reward balances
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">
|
||||
{reward_balances}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
path={'mdiTrophy' in icon ? icon['mdiTrophy' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>}
|
||||
|
||||
{hasPermission(currentUser, 'READ_REWARD_TRANSACTIONS') && <Link href={'/reward_transactions/reward_transactions-list'}>
|
||||
<div
|
||||
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Reward transactions
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">
|
||||
{reward_transactions}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
path={'mdiSwapHorizontal' in icon ? icon['mdiSwapHorizontal' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>}
|
||||
|
||||
{hasPermission(currentUser, 'READ_NOTIFICATION_SCHEDULES') && <Link href={'/notification_schedules/notification_schedules-list'}>
|
||||
<div
|
||||
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Notification schedules
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">
|
||||
{notification_schedules}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
path={'mdiBell' in icon ? icon['mdiBell' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>}
|
||||
|
||||
{hasPermission(currentUser, 'READ_FAQS') && <Link href={'/faqs/faqs-list'}>
|
||||
<div
|
||||
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Faqs
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">
|
||||
{faqs}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
path={'mdiFrequentlyAskedQuestions' in icon ? icon['mdiFrequentlyAskedQuestions' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>}
|
||||
|
||||
{hasPermission(currentUser, 'READ_ANALYTICS_EVENTS') && <Link href={'/analytics_events/analytics_events-list'}>
|
||||
<div
|
||||
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Analytics events
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">
|
||||
{analytics_events}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
path={'mdiChartTimeline' in icon ? icon['mdiChartTimeline' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>}
|
||||
|
||||
{hasPermission(currentUser, 'READ_APP_SETTINGS') && <Link href={'/app_settings/app_settings-list'}>
|
||||
<div
|
||||
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
|
||||
>
|
||||
<div className="flex justify-between align-center">
|
||||
<div>
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
App settings
|
||||
</div>
|
||||
<div className="text-3xl leading-tight font-semibold">
|
||||
{app_settings}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<BaseIcon
|
||||
className={`${iconsColor}`}
|
||||
w="w-16"
|
||||
h="h-16"
|
||||
size={48}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
path={'mdiCog' in icon ? icon['mdiCog' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>}
|
||||
|
||||
|
||||
</div>
|
||||
</SectionMain>
|
||||
</>
|
||||
@ -258,4 +610,4 @@ Dashboard.getLayout = function getLayout(page: ReactElement) {
|
||||
return <LayoutAuthenticated>{page}</LayoutAuthenticated>
|
||||
}
|
||||
|
||||
export default Dashboard
|
||||
export default Dashboard
|
||||
|
||||
@ -1,121 +1,166 @@
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import type { ReactElement } from 'react';
|
||||
import Head from 'next/head';
|
||||
import Link from 'next/link';
|
||||
import BaseButton from '../components/BaseButton';
|
||||
import CardBox from '../components/CardBox';
|
||||
import SectionFullScreen from '../components/SectionFullScreen';
|
||||
import LayoutGuest from '../layouts/Guest';
|
||||
import BaseDivider from '../components/BaseDivider';
|
||||
import BaseButtons from '../components/BaseButtons';
|
||||
import { getPageTitle } from '../config';
|
||||
import { useAppSelector } from '../stores/hooks';
|
||||
import { mdiWeatherSunny, mdiCheckCircle, mdiRocketLaunch, mdiGamepadVariant, mdiArrowRight } from '@mdi/js';
|
||||
import BaseIcon from '../components/BaseIcon';
|
||||
import CardBoxComponentTitle from "../components/CardBoxComponentTitle";
|
||||
import { getPexelsImage, getPexelsVideo } from '../helpers/pexels';
|
||||
|
||||
|
||||
export default function Starter() {
|
||||
const [illustrationImage, setIllustrationImage] = useState({
|
||||
src: undefined,
|
||||
photographer: undefined,
|
||||
photographer_url: undefined,
|
||||
})
|
||||
const [illustrationVideo, setIllustrationVideo] = useState({video_files: []})
|
||||
const [contentType, setContentType] = useState('image');
|
||||
const [contentPosition, setContentPosition] = useState('left');
|
||||
const textColor = useAppSelector((state) => state.style.linkColor);
|
||||
|
||||
return (
|
||||
<div className="relative overflow-hidden bg-midnightBlueTheme-mainBG min-h-screen font-sans">
|
||||
const title = 'App Preview'
|
||||
|
||||
// Fetch Pexels image/video
|
||||
useEffect(() => {
|
||||
async function fetchData() {
|
||||
const image = await getPexelsImage();
|
||||
const video = await getPexelsVideo();
|
||||
setIllustrationImage(image);
|
||||
setIllustrationVideo(video);
|
||||
}
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
const imageBlock = (image) => (
|
||||
<div
|
||||
className='hidden md:flex flex-col justify-end relative flex-grow-0 flex-shrink-0 w-1/3'
|
||||
style={{
|
||||
backgroundImage: `${
|
||||
image
|
||||
? `url(${image?.src?.original})`
|
||||
: 'linear-gradient(rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.5))'
|
||||
}`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'left center',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
}}
|
||||
>
|
||||
<div className='flex justify-center w-full bg-blue-300/20'>
|
||||
<a
|
||||
className='text-[8px]'
|
||||
href={image?.photographer_url}
|
||||
target='_blank'
|
||||
rel='noreferrer'
|
||||
>
|
||||
Photo by {image?.photographer} on Pexels
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const videoBlock = (video) => {
|
||||
if (video?.video_files?.length > 0) {
|
||||
return (
|
||||
<div className='hidden md:flex flex-col justify-end relative flex-grow-0 flex-shrink-0 w-1/3'>
|
||||
<video
|
||||
className='absolute top-0 left-0 w-full h-full object-cover'
|
||||
autoPlay
|
||||
loop
|
||||
muted
|
||||
>
|
||||
<source src={video?.video_files[0]?.link} type='video/mp4'/>
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
<div className='flex justify-center w-full bg-blue-300/20 z-10'>
|
||||
<a
|
||||
className='text-[8px]'
|
||||
href={video?.user?.url}
|
||||
target='_blank'
|
||||
rel='noreferrer'
|
||||
>
|
||||
Video by {video.user.name} on Pexels
|
||||
</a>
|
||||
</div>
|
||||
</div>)
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
style={
|
||||
contentPosition === 'background'
|
||||
? {
|
||||
backgroundImage: `${
|
||||
illustrationImage
|
||||
? `url(${illustrationImage.src?.original})`
|
||||
: 'linear-gradient(rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.5))'
|
||||
}`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'left center',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
}
|
||||
: {}
|
||||
}
|
||||
>
|
||||
<Head>
|
||||
<title>{getPageTitle('Welcome to Morninmate')}</title>
|
||||
<title>{getPageTitle('Starter Page')}</title>
|
||||
</Head>
|
||||
|
||||
{/* Decorative Gradients */}
|
||||
<div className="fixed inset-0 pointer-events-none z-0">
|
||||
<div className="absolute top-[-20%] left-[-10%] w-[60%] h-[60%] bg-indigo-600/20 blur-[150px] rounded-full animate-pulse"></div>
|
||||
<div className="absolute bottom-[-10%] right-[-10%] w-[50%] h-[50%] bg-purple-600/15 blur-[120px] rounded-full animate-pulse"></div>
|
||||
<SectionFullScreen bg='violet'>
|
||||
<div
|
||||
className={`flex ${
|
||||
contentPosition === 'right' ? 'flex-row-reverse' : 'flex-row'
|
||||
} min-h-screen w-full`}
|
||||
>
|
||||
{contentType === 'image' && contentPosition !== 'background'
|
||||
? imageBlock(illustrationImage)
|
||||
: null}
|
||||
{contentType === 'video' && contentPosition !== 'background'
|
||||
? videoBlock(illustrationVideo)
|
||||
: null}
|
||||
<div className='flex items-center justify-center flex-col space-y-4 w-full lg:w-full'>
|
||||
<CardBox className='w-full md:w-3/5 lg:w-2/3'>
|
||||
<CardBoxComponentTitle title="Welcome to your App Preview app!"/>
|
||||
|
||||
<div className="space-y-3">
|
||||
<p className='text-center '>This is a React.js/Node.js app generated by the <a className={`${textColor}`} href="https://flatlogic.com/generator">Flatlogic Web App Generator</a></p>
|
||||
<p className='text-center '>For guides and documentation please check
|
||||
your local README.md and the <a className={`${textColor}`} href="https://flatlogic.com/documentation">Flatlogic documentation</a></p>
|
||||
</div>
|
||||
|
||||
<BaseButtons>
|
||||
<BaseButton
|
||||
href='/login'
|
||||
label='Login'
|
||||
color='info'
|
||||
className='w-full'
|
||||
/>
|
||||
|
||||
</BaseButtons>
|
||||
</CardBox>
|
||||
</div>
|
||||
</div>
|
||||
</SectionFullScreen>
|
||||
<div className='bg-black text-white flex flex-col text-center justify-center md:flex-row'>
|
||||
<p className='py-6 text-sm'>© 2026 <span>{title}</span>. All rights reserved</p>
|
||||
<Link className='py-6 ml-4 text-sm' href='/privacy-policy/'>
|
||||
Privacy Policy
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<SectionFullScreen bg='violet'>
|
||||
<div className="relative z-10 w-full max-w-6xl mx-auto px-6 py-20 lg:py-32 flex flex-col items-center text-center">
|
||||
|
||||
{/* Logo Section */}
|
||||
<div className="mb-12 animate-fade-in">
|
||||
<div className="flex items-center justify-center space-x-4 mb-4">
|
||||
<div className="bg-gradient-to-tr from-indigo-500 to-purple-600 p-5 rounded-3xl shadow-2xl shadow-indigo-500/20 transform rotate-12 hover:rotate-0 transition-transform duration-500">
|
||||
<BaseIcon path={mdiWeatherSunny} size={48} className="text-white" />
|
||||
</div>
|
||||
</div>
|
||||
<h1 className="text-6xl md:text-8xl font-black tracking-tighter text-white mb-6">
|
||||
Mornin<span className="text-transparent bg-clip-text bg-gradient-to-r from-indigo-400 to-purple-400">mate</span>
|
||||
</h1>
|
||||
<p className="text-xl md:text-2xl text-indigo-100/60 max-w-2xl mx-auto leading-relaxed">
|
||||
Gamify your morning routine, boost your potential score, and unlock fun rewards. The perfect start to your day.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* CTA Buttons */}
|
||||
<div className="flex flex-col sm:flex-row gap-6 mb-24 w-full sm:w-auto animate-fade-in delay-200">
|
||||
<BaseButton
|
||||
href='/login'
|
||||
label='Launch My Morning'
|
||||
color='info'
|
||||
roundedFull
|
||||
className='text-xl py-4 shadow-2xl shadow-indigo-600/40 hover:scale-105 transition-transform'
|
||||
/>
|
||||
<BaseButton
|
||||
href='/register'
|
||||
label='Join the Club'
|
||||
color='whiteDark'
|
||||
roundedFull
|
||||
className='text-xl py-4 border-indigo-500/20 bg-indigo-500/5 backdrop-blur-md hover:bg-indigo-500/10 transition-colors'
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Feature Grid */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 w-full animate-fade-in delay-500">
|
||||
{[
|
||||
{
|
||||
icon: mdiCheckCircle,
|
||||
title: "Pulse Routines",
|
||||
desc: "Create and track your morning activities with ease.",
|
||||
color: "text-emerald-400"
|
||||
},
|
||||
{
|
||||
icon: mdiRocketLaunch,
|
||||
title: "Potential Score",
|
||||
desc: "Watch your morning routine quality soar to 100.",
|
||||
color: "text-amber-400"
|
||||
},
|
||||
{
|
||||
icon: mdiGamepadVariant,
|
||||
title: "Unlock Games",
|
||||
desc: "Earn game sessions as rewards for your consistency.",
|
||||
color: "text-cyan-400"
|
||||
}
|
||||
].map((f, i) => (
|
||||
<div key={i} className="p-8 rounded-[2.5rem] bg-white/5 border border-white/5 backdrop-blur-xl hover:bg-white/10 transition-colors group">
|
||||
<div className={`mb-4 p-3 inline-block rounded-2xl bg-white/5 ${f.color} group-hover:scale-110 transition-transform`}>
|
||||
<BaseIcon path={f.icon} size={32} />
|
||||
</div>
|
||||
<h3 className="text-2xl font-bold text-white mb-2">{f.title}</h3>
|
||||
<p className="text-indigo-200/50 leading-relaxed">{f.desc}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</SectionFullScreen>
|
||||
|
||||
<footer className="relative z-10 py-12 border-t border-white/5 bg-black/20 backdrop-blur-md">
|
||||
<div className="max-w-6xl mx-auto px-6 flex flex-col md:flex-row justify-between items-center text-center md:text-left gap-8">
|
||||
<div className="space-y-2">
|
||||
<h4 className="text-xl font-bold text-white flex items-center justify-center md:justify-start">
|
||||
<BaseIcon path={mdiWeatherSunny} size={20} className="mr-2 text-indigo-400" />
|
||||
Morninmate
|
||||
</h4>
|
||||
<p className="text-sm text-indigo-200/40">© 2026. Made with ❤️ for your mornings.</p>
|
||||
</div>
|
||||
<div className="flex gap-8 text-sm font-medium text-indigo-200/60">
|
||||
<Link href='/privacy-policy/' className="hover:text-white transition-colors">Privacy</Link>
|
||||
<Link href='/terms/' className="hover:text-white transition-colors">Terms</Link>
|
||||
<Link href='/help/' className="hover:text-white transition-colors">Help</Link>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Starter.getLayout = function getLayout(page: ReactElement) {
|
||||
return <LayoutGuest>{page}</LayoutGuest>;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -53,31 +53,31 @@ export const white: StyleObject = {
|
||||
|
||||
|
||||
export const midnightBlueTheme: StyleObject = {
|
||||
aside: 'bg-midnightBlueTheme-800 text-midnightBlueTheme-text dark:text-white lg:rounded-3xl lg:m-4 lg:h-[calc(100vh-2rem)] shadow-2xl backdrop-blur-md bg-opacity-95 transition-all duration-300 ease-in-out',
|
||||
aside: 'bg-midnightBlueTheme-800 text-midnightBlueTheme-text dark:text-white lg:rounded-lg',
|
||||
asideScrollbars: 'aside-scrollbars-blue',
|
||||
asideBrand: 'text-indigo-500 bg-white/10 rounded-t-3xl',
|
||||
asideBrand: 'text-blue-500 bg-white',
|
||||
asideMenuItem:
|
||||
'text-midnightBlueTheme-text hover:text-white hover:bg-white/10 dark:text-dark-500 dark:hover:text-white dark:hover:bg-dark-800 transition-colors duration-200 rounded-2xl mx-2 my-1 p-2',
|
||||
asideMenuItemActive: 'font-bold text-white bg-indigo-600/50 shadow-lg rounded-2xl mx-2 my-1 p-2',
|
||||
activeLinkColor: 'bg-indigo-600 rounded-2xl shadow-md',
|
||||
asideMenuDropdown: 'bg-indigo-900/40 rounded-2xl mx-4',
|
||||
navBarItemLabel: 'text-primaryText font-medium',
|
||||
iconsColor: 'text-indigo-400 dark:text-indigo-500',
|
||||
navBarItemLabelHover: 'hover:text-indigo-300',
|
||||
navBarItemLabelActiveColor: 'text-indigo-200',
|
||||
overlay: 'bg-midnightBlueTheme-mainBG/80 backdrop-blur-sm',
|
||||
'text-midnightBlueTheme-text hover:text-white dark:text-dark-500 dark:hover:text-white dark:hover:bg-dark-800 dark:text-white',
|
||||
asideMenuItemActive: 'font-bold text-white dark:text-white',
|
||||
activeLinkColor: 'bg-midnightBlueTheme-buttonColor rounded-lg',
|
||||
asideMenuDropdown: 'bg-blue-700/50',
|
||||
navBarItemLabel: 'text-primaryText',
|
||||
iconsColor: 'text-midnightBlueTheme-iconsColor dark:text-blue-500',
|
||||
navBarItemLabelHover: 'hover:text-stone-400',
|
||||
navBarItemLabelActiveColor: 'text-midnightBlueTheme-800',
|
||||
overlay: 'bg-midnightBlueTheme-mainBG',
|
||||
bgLayoutColor: 'bg-midnightBlueTheme-mainBG',
|
||||
cardsColor: 'bg-midnightBlueTheme-cardColor/60 backdrop-blur-xl shadow-2xl border border-white/5',
|
||||
cardsColor: 'bg-midnightBlueTheme-cardColor',
|
||||
focusRingColor:
|
||||
'focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 focus:outline-none border border-white/10 dark:focus:ring-indigo-600 dark:focus:border-indigo-600',
|
||||
corners: 'rounded-3xl',
|
||||
cardsStyle: 'bg-midnightBlueTheme-outsideCardColor/40 backdrop-blur-lg border border-white/10 shadow-2xl hover:shadow-indigo-500/10 transition-all duration-300',
|
||||
linkColor: 'text-indigo-400',
|
||||
websiteHeder: 'border-b border-white/10 shadow-xl backdrop-blur-md bg-opacity-80',
|
||||
borders: 'border-white/10',
|
||||
shadow: 'shadow-2xl shadow-indigo-500/20',
|
||||
websiteSectionStyle: 'bg-gradient-to-br from-indigo-900/20 to-purple-900/20 text-white',
|
||||
textSecondary: 'text-indigo-200/60',
|
||||
'focus:ring focus:ring-midnightBlueTheme-800 focus:border-midnightBlueTheme-800 focus:outline-none border border-gray-600 dark:focus:ring-blue-600 dark:focus:border-blue-600',
|
||||
corners: 'rounded-lg',
|
||||
cardsStyle: 'bg-midnightBlueTheme-outsideCardColor border border-midnightBlueTheme-outsideCardColor shadow-xl',
|
||||
linkColor: 'text-midnightBlueTheme-buttonColor',
|
||||
websiteHeder: 'border-b border-white border-opacity-10 shadow-md',
|
||||
borders: 'border-white border-opacity-10',
|
||||
shadow: 'shadow-md',
|
||||
websiteSectionStyle: ' bg-midnightBlueTheme-webSiteComponentBg text-white',
|
||||
textSecondary: 'text-gray-300',
|
||||
};
|
||||
|
||||
|
||||
@ -132,4 +132,4 @@ export const basic: StyleObject = {
|
||||
shadow: '',
|
||||
websiteSectionStyle: '',
|
||||
textSecondary: '',
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,7 +86,7 @@ module.exports = {
|
||||
primaryText: '#E9EAEF',
|
||||
},
|
||||
fontFamily: {
|
||||
sans: ['Inter', 'sans-serif'],
|
||||
sans: ['Ubuntu', 'sans-serif'],
|
||||
|
||||
},
|
||||
borderRadius: {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user