Compare commits

...

1 Commits

Author SHA1 Message Date
Flatlogic Bot
956e0bb9b2 MorninMate 2026-02-23 16:01:41 +00:00
11 changed files with 316 additions and 697 deletions

View File

@ -14,7 +14,7 @@ export const colorsBgLight = {
success: 'bg-emerald-500 border-emerald-500 dark:bg-pavitra-blue dark:border-pavitra-blue text-white', 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', danger: 'bg-red-500 border-red-500 text-white',
warning: 'bg-yellow-500 border-yellow-500 text-white', warning: 'bg-yellow-500 border-yellow-500 text-white',
info: 'bg-blue-500 border-blue-500 dark:bg-pavitra-blue dark:border-pavitra-blue 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',
} }
export const colorsText = { export const colorsText = {
@ -24,7 +24,7 @@ export const colorsText = {
success: 'text-emerald-500', success: 'text-emerald-500',
danger: 'text-red-500', danger: 'text-red-500',
warning: 'text-yellow-500', warning: 'text-yellow-500',
info: 'text-blue-500', info: 'text-indigo-500',
}; };
export const colorsOutline = { export const colorsOutline = {
@ -34,7 +34,7 @@ export const colorsOutline = {
success: [colorsText.success, 'border-emerald-500'].join(' '), success: [colorsText.success, 'border-emerald-500'].join(' '),
danger: [colorsText.danger, 'border-red-500'].join(' '), danger: [colorsText.danger, 'border-red-500'].join(' '),
warning: [colorsText.warning, 'border-yellow-500'].join(' '), warning: [colorsText.warning, 'border-yellow-500'].join(' '),
info: [colorsText.info, 'border-blue-500'].join(' '), info: [colorsText.info, 'border-indigo-500'].join(' '),
}; };
export const getButtonColor = ( export const getButtonColor = (
@ -56,7 +56,7 @@ export const getButtonColor = (
success: 'ring-emerald-300 dark:ring-pavitra-blue', success: 'ring-emerald-300 dark:ring-pavitra-blue',
danger: 'ring-red-300 dark:ring-red-700', danger: 'ring-red-300 dark:ring-red-700',
warning: 'ring-yellow-300 dark:ring-yellow-700', warning: 'ring-yellow-300 dark:ring-yellow-700',
info: "ring-midnightBlueTheme-buttonColor dark:ring-pavitra-blue", info: "ring-indigo-300 dark:ring-indigo-700",
}, },
active: { active: {
white: 'bg-gray-100', white: 'bg-gray-100',
@ -66,57 +66,57 @@ export const getButtonColor = (
success: 'bg-emerald-700 dark:bg-pavitra-blue', success: 'bg-emerald-700 dark:bg-pavitra-blue',
danger: 'bg-red-700 dark:bg-red-600', danger: 'bg-red-700 dark:bg-red-600',
warning: 'bg-yellow-700 dark:bg-yellow-600', warning: 'bg-yellow-700 dark:bg-yellow-600',
info: 'bg-midnightBlueTheme-buttonColor dark:bg-pavitra-blue', info: 'bg-indigo-700 dark:bg-indigo-600',
}, },
bg: { bg: {
white: 'bg-white text-black', white: 'bg-white text-black border-gray-200',
whiteDark: 'bg-midnightBlueTheme-outsideCardColor text-primaryText dark:bg-dark-900 dark:text-white', 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', lightDark: 'bg-gray-100 text-black dark:bg-slate-800 dark:text-white border-gray-200 dark:border-white/10',
contrast: 'bg-gray-800 text-white dark:bg-white dark:text-black', contrast: 'bg-gray-800 text-white dark:bg-white dark:text-black',
success: 'bg-emerald-600 dark:bg-pavitra-blue text-white', success: 'bg-emerald-600 dark:bg-pavitra-blue text-white border-emerald-600',
danger: 'bg-midnightBlueTheme-outsideCardColor text-red-500 dark:text-white dark:bg-red-500 ', danger: 'bg-red-500 text-white dark:bg-red-600 border-red-500',
warning: 'bg-yellow-600 dark:bg-yellow-500 text-white', warning: 'bg-yellow-600 dark:bg-yellow-500 text-white border-yellow-600',
info: " bg-midnightBlueTheme-buttonColor dark:bg-pavitra-blue text-white ", info: "bg-indigo-600 text-white border-indigo-600 shadow-lg shadow-indigo-600/30",
}, },
bgHover: { bgHover: {
white: 'hover:bg-gray-100', white: 'hover:bg-gray-50 hover:border-gray-300',
whiteDark: 'hover:bg-midnightBlueTheme-outsideCardColor hover:dark:bg-dark-800', whiteDark: 'hover:bg-midnightBlueTheme-outsideCardColor/80 hover:dark:bg-dark-800',
lightDark: 'hover:bg-gray-200 hover:dark:bg-slate-700', lightDark: 'hover:bg-gray-200 hover:dark:bg-slate-700',
contrast: 'hover:bg-gray-700 hover:dark:bg-slate-100', contrast: 'hover:bg-gray-700 hover:dark:bg-slate-100',
success: success:
'hover:bg-emerald-700 hover:border-emerald-700 hover:dark:bg-pavitra-blue hover:dark:border-pavitra-blue', 'hover:bg-emerald-700 hover:border-emerald-700 hover:dark:bg-pavitra-blue/90 hover:dark:border-pavitra-blue/90',
danger: danger:
'hover:bg-red-700 hover:border-red-700 hover:dark:bg-red-600 hover:dark:border-red-600', 'hover:bg-red-600 hover:border-red-600 hover:dark:bg-red-500',
warning: warning:
'hover:bg-yellow-700 hover:border-yellow-700 hover:dark:bg-yellow-600 hover:dark:border-yellow-600', 'hover:bg-yellow-700 hover:border-yellow-700 hover:dark:bg-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", info: "hover:bg-indigo-700 hover:border-indigo-700 hover:shadow-indigo-600/40",
}, },
borders: { borders: {
white: 'border-white', 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', lightDark: 'border-gray-100 dark:border-slate-800',
contrast: 'border-gray-800 dark:border-white', contrast: 'border-gray-800 dark:border-white',
success: 'border-emerald-600 dark:border-pavitra-blue', success: 'border-emerald-600 dark:border-pavitra-blue',
danger: 'border-red-600 dark:border-red-500', danger: 'border-red-600 dark:border-red-500',
warning: 'border-yellow-600 dark:border-yellow-500', warning: 'border-yellow-600 dark:border-yellow-500',
info: "border-midnightBlueTheme-buttonColor border-blue-600 dark:border-pavitra-blue", info: "border-indigo-600 dark:border-indigo-500",
}, },
text: { text: {
contrast: 'dark:text-slate-100', contrast: 'dark:text-slate-100',
success: 'text-emerald-600 dark:text-pavitra-blue', success: 'text-emerald-600 dark:text-pavitra-blue',
danger: 'text-red-600 dark:text-red-500', danger: 'text-red-600 dark:text-red-500',
warning: 'text-yellow-600 dark:text-yellow-500', warning: 'text-yellow-600 dark:text-yellow-500',
info: ' dark:text-pavitra-blue', info: 'text-indigo-600 dark:text-indigo-400',
}, },
outlineHover: { outlineHover: {
contrast: contrast:
'hover:bg-gray-800 hover:text-gray-100 hover:dark:bg-slate-100 hover:dark:text-black', '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:text-white hover:dark:text-white hover:dark:border-pavitra-blue', success: 'hover:bg-emerald-600 hover:text-white hover:dark:bg-emerald-700',
danger: danger:
'hover:bg-red-600 hover:text-white hover:text-white hover:dark:text-white hover:dark:border-red-600', 'hover:bg-red-600 hover:text-white hover:dark:bg-red-700',
warning: warning:
'hover:bg-yellow-600 hover:text-white hover:text-white hover:dark:text-white hover:dark:border-yellow-600', 'hover:bg-yellow-600 hover:text-white hover:dark:bg-yellow-700',
info: "hover:bg-midnightBlueTheme-buttonColor text-midnightBlueTheme-buttonColor hover:bg-blue-600 hover:text-white hover:dark:text-white hover:dark:border-pavitra-blue", info: "hover:bg-indigo-600 hover:text-white hover:dark:bg-indigo-700",
}, },
} }

View File

@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
import { mdiLogout, mdiClose } from '@mdi/js' import { mdiLogout, mdiClose, mdiWeatherSunny } from '@mdi/js'
import BaseIcon from './BaseIcon' import BaseIcon from './BaseIcon'
import AsideMenuList from './AsideMenuList' import AsideMenuList from './AsideMenuList'
import { MenuAsideItem } from '../interfaces' import { MenuAsideItem } from '../interfaces'
@ -29,34 +29,41 @@ export default function AsideMenuLayer({ menu, className = '', ...props }: Props
return ( return (
<aside <aside
id='asideMenu' id='asideMenu'
className={`${className} zzz lg:py-2 lg:pl-2 w-60 fixed flex z-40 top-0 h-screen transition-position overflow-hidden`} className={`${className} lg:py-4 lg:pl-4 w-64 fixed flex z-40 top-0 h-screen transition-all duration-300 overflow-hidden`}
> >
<div <div
className={`flex-1 flex flex-col overflow-hidden dark:bg-dark-900 ${asideStyle} ${corners}`} className={`flex-1 flex flex-col overflow-hidden ${asideStyle} ${corners} border border-white/5 shadow-2xl backdrop-blur-2xl`}
> >
<div <div
className={`flex flex-row h-14 items-center justify-between ${asideBrandStyle}`} className={`flex flex-row h-20 items-center justify-between ${asideBrandStyle} px-6 border-b border-white/5`}
> >
<div className="text-center flex-1 lg:text-left lg:pl-6 xl:text-center xl:pl-0"> <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">
<b className="font-black">App Preview</b> <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">
</div> Morninmate
</span>
</Link>
<button <button
className="hidden lg:inline-block xl:hidden p-3" className="lg:hidden p-2 text-white/60 hover:text-white transition-colors"
onClick={handleAsideLgCloseClick} onClick={handleAsideLgCloseClick}
> >
<BaseIcon path={mdiClose} /> <BaseIcon path={mdiClose} />
</button> </button>
</div> </div>
<div <div
className={`flex-1 overflow-y-auto overflow-x-hidden ${ className={`flex-1 overflow-y-auto overflow-x-hidden pt-4 ${
darkMode ? 'aside-scrollbars-[slate]' : asideScrollbarsStyle darkMode ? 'aside-scrollbars-[slate]' : asideScrollbarsStyle
}`} }`}
> >
<AsideMenuList menu={menu} /> <AsideMenuList menu={menu} />
</div> </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> </div>
</aside> </aside>
) )

View File

@ -49,22 +49,22 @@ export default function BaseButton({
'items-center', 'items-center',
'whitespace-nowrap', 'whitespace-nowrap',
'focus:outline-none', 'focus:outline-none',
'transition-colors', 'transition-all',
'focus:ring', 'focus:ring',
'duration-150', 'duration-300',
'border', 'border',
disabled ? 'cursor-not-allowed' : 'cursor-pointer', disabled ? 'cursor-not-allowed' : 'cursor-pointer hover:scale-[1.02] active:scale-[0.98]',
roundedFull ? 'rounded-full' : `${corners}`, roundedFull ? 'rounded-full' : `${corners}`,
getButtonColor(color, outline, !disabled, active), getButtonColor(color, outline, !disabled, active),
className, className,
] ]
if (!label && icon) { if (!label && icon) {
componentClass.push('p-1') componentClass.push('p-1.5')
} else if (small) { } else if (small) {
componentClass.push('text-sm', roundedFull ? 'px-3 py-1' : 'p-1') componentClass.push('text-sm', roundedFull ? 'px-4 py-1.5' : 'px-2 py-1')
} else { } else {
componentClass.push('py-2', roundedFull ? 'px-6' : 'px-3') componentClass.push('py-2.5', roundedFull ? 'px-8' : 'px-5')
} }
if (disabled) { if (disabled) {
@ -76,7 +76,7 @@ export default function BaseButton({
const componentChildren = ( const componentChildren = (
<> <>
{icon && <BaseIcon path={icon} size={iconSize} className={iconClassName} />} {icon && <BaseIcon path={icon} size={iconSize} className={iconClassName} />}
{label && <span className={small && icon ? 'px-1' : 'px-2'}>{label}</span>} {label && <span className={`font-semibold ${small && icon ? 'px-1' : 'px-2'}`}>{label}</span>}
</> </>
) )

View File

@ -37,16 +37,16 @@ export default function CardBox({
const corners = useAppSelector((state) => state.style.corners); const corners = useAppSelector((state) => state.style.corners);
const cardsStyle = useAppSelector((state) => state.style.cardsStyle); const cardsStyle = useAppSelector((state) => state.style.cardsStyle);
const componentClass = [ const componentClass = [
`flex dark:border-dark-700 dark:bg-dark-900`, `flex transition-all duration-300 ease-in-out`,
className, className,
corners !== 'rounded-full'? corners : 'rounded-3xl', corners !== 'rounded-full'? corners : 'rounded-3xl',
flex, flex,
isList ? '' : `${cardsStyle}`, isList ? '' : `${cardsStyle}`,
hasTable ? '' : `border-dark-700 dark:border-dark-700`, hasTable ? '' : ``,
] ]
if (isHoverable) { if (isHoverable) {
componentClass.push('hover:shadow-lg transition-shadow duration-500') componentClass.push('hover:shadow-2xl hover:scale-[1.01] hover:border-indigo-500/20 cursor-pointer')
} }
return React.createElement( return React.createElement(

View File

@ -20,7 +20,9 @@ export default function IconRounded({
bg = false, bg = false,
className = '', className = '',
}: Props) { }: Props) {
const classAddon = bg ? colorsBgLight[color] : `${colorsText[color]} bg-gray-50 dark:bg-slate-800` 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`
return ( return (
<BaseIcon <BaseIcon
@ -28,7 +30,7 @@ export default function IconRounded({
w={w} w={w}
h={h} h={h}
size="24" size="24"
className={`rounded-full ${classAddon} ${className}`} className={`rounded-2xl transition-all duration-300 transform hover:scale-110 ${classAddon} ${className}`}
/> />
) )
} }

View File

@ -6,5 +6,5 @@ type Props = {
} }
export default function SectionMain({ children }: Props) { export default function SectionMain({ children }: Props) {
return <section className={`p-6 ${containerMaxW}`}>{children}</section> return <section className={`p-4 md:p-8 lg:p-12 ${containerMaxW}`}>{children}</section>
} }

View File

@ -86,18 +86,23 @@ export default function LayoutAuthenticated({
}, [router.events, dispatch]) }, [router.events, dispatch])
const layoutAsidePadding = 'xl:pl-60' const layoutAsidePadding = 'xl:pl-64'
return ( return (
<div className={`${darkMode ? 'dark' : ''} overflow-hidden lg:overflow-visible`}> <div className={`${darkMode ? 'dark' : ''} overflow-hidden lg:overflow-visible`}>
<div <div
className={`${layoutAsidePadding} ${ className={`${layoutAsidePadding} ${
isAsideMobileExpanded ? 'ml-60 lg:ml-0' : '' isAsideMobileExpanded ? 'ml-64 lg:ml-0' : ''
} pt-14 min-h-screen w-screen transition-position lg:w-auto ${bgColor} dark:bg-dark-800 dark:text-slate-100`} } pt-16 min-h-screen w-screen transition-all duration-300 lg:w-auto ${bgColor} dark:bg-dark-800 dark:text-slate-100 relative`}
> >
<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 <NavBar
menu={menuNavBar} menu={menuNavBar}
className={`${layoutAsidePadding} ${isAsideMobileExpanded ? 'ml-60 lg:ml-0' : ''}`} className={`${layoutAsidePadding} ${isAsideMobileExpanded ? 'ml-64 lg:ml-0' : ''}`}
> >
<NavBarItemPlain <NavBarItemPlain
display="flex lg:hidden" display="flex lg:hidden"
@ -121,7 +126,9 @@ export default function LayoutAuthenticated({
menu={menuAside} menu={menuAside}
onAsideLgClose={() => setIsAsideLgActive(false)} onAsideLgClose={() => setIsAsideLgActive(false)}
/> />
{children} <div className="relative z-10">
{children}
</div>
<FooterBar>Hand-crafted & Made with </FooterBar> <FooterBar>Hand-crafted & Made with </FooterBar>
</div> </div>
</div> </div>

View File

@ -16,13 +16,14 @@ import { WidgetCreator } from '../components/WidgetCreator/WidgetCreator';
import { SmartWidget } from '../components/SmartWidget/SmartWidget'; import { SmartWidget } from '../components/SmartWidget/SmartWidget';
import { useAppDispatch, useAppSelector } from '../stores/hooks'; import { useAppDispatch, useAppSelector } from '../stores/hooks';
const Dashboard = () => { const Dashboard = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const iconsColor = useAppSelector((state) => state.style.iconsColor); const iconsColor = useAppSelector((state) => state.style.iconsColor);
const corners = useAppSelector((state) => state.style.corners); const corners = useAppSelector((state) => state.style.corners);
const cardsStyle = useAppSelector((state) => state.style.cardsStyle); const cardsStyle = useAppSelector((state) => state.style.cardsStyle);
const loadingMessage = 'Loading...'; const loadingMessage = '...';
const [users, setUsers] = React.useState(loadingMessage); const [users, setUsers] = React.useState(loadingMessage);
@ -92,6 +93,37 @@ const Dashboard = () => {
getWidgets(widgetsRole?.role?.value || '').then(); getWidgets(widgetsRole?.role?.value || '').then();
}, [widgetsRole?.role?.value]); }, [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 ( return (
<> <>
<Head> <Head>
@ -100,12 +132,15 @@ const Dashboard = () => {
</title> </title>
</Head> </Head>
<SectionMain> <SectionMain>
<SectionTitleLineWithButton <div className="mb-10">
icon={icon.mdiChartTimelineVariant} <SectionTitleLineWithButton
title='Overview' icon={icon.mdiChartTimelineVariant}
main> title='Overview'
{''} main>
</SectionTitleLineWithButton> {''}
</SectionTitleLineWithButton>
<p className="text-indigo-200/60 -mt-6">Welcome back, {currentUser?.firstName || 'Mate'}! Here's what's happening today.</p>
</div>
{hasPermission(currentUser, 'CREATE_ROLES') && <WidgetCreator {hasPermission(currentUser, 'CREATE_ROLES') && <WidgetCreator
currentUser={currentUser} currentUser={currentUser}
@ -113,24 +148,18 @@ const Dashboard = () => {
setWidgetsRole={setWidgetsRole} setWidgetsRole={setWidgetsRole}
widgetsRole={widgetsRole} widgetsRole={widgetsRole}
/>} />}
{!!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'> <div className='grid grid-cols-1 gap-6 lg:grid-cols-4 mb-10 grid-flow-dense'>
{(isFetchingQuery || loading) && ( {(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-6`}> <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`}>
<BaseIcon <BaseIcon
className={`${iconsColor} animate-spin mr-5`} className={`${iconsColor} animate-spin mr-5`}
w='w-16' w='w-12'
h='h-16' h='h-12'
size={48} size={32}
path={icon.mdiLoading} path={icon.mdiLoading}
/>{' '} />{' '}
Loading widgets... Organizing your dashboard...
</div> </div>
)} )}
@ -146,460 +175,79 @@ const Dashboard = () => {
))} ))}
</div> </div>
{!!rolesWidgets.length && <hr className='my-6 text-midnightBlueTheme-mainBG ' />} <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') && (
<div id="dashboard" className='grid grid-cols-1 gap-6 lg:grid-cols-3 mb-6'> <StatCard
title="Users"
count={users}
{hasPermission(currentUser, 'READ_USERS') && <Link href={'/users/users-list'}> iconPath={icon.mdiAccountGroup}
<div href='/users/users-list'
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`} gradient="from-indigo-500 to-blue-600"
> />
<div className="flex justify-between align-center"> )}
<div> {hasPermission(currentUser, 'READ_PULSES') && (
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400"> <StatCard
Users title="Pulses"
</div> count={pulses}
<div className="text-3xl leading-tight font-semibold"> iconPath={icon.mdiAlarm}
{users} href='/pulses/pulses-list'
</div> gradient="from-purple-500 to-pink-600"
</div> />
<div> )}
<BaseIcon {hasPermission(currentUser, 'READ_COMPLETED_PULSES') && (
className={`${iconsColor}`} <StatCard
w="w-16" title="Completions"
h="h-16" count={completed_pulses}
size={48} iconPath={icon.mdiCalendarCheck}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment href='/completed_pulses/completed_pulses-list'
// @ts-ignore gradient="from-emerald-500 to-teal-600"
path={icon.mdiAccountGroup || icon.mdiTable} />
/> )}
</div> {hasPermission(currentUser, 'READ_POTENTIAL_SCORES') && (
</div> <StatCard
</div> title="Potential Score"
</Link>} count={potential_scores}
iconPath={icon.mdiGauge}
{hasPermission(currentUser, 'READ_ROLES') && <Link href={'/roles/roles-list'}> href='/potential_scores/potential_scores-list'
<div gradient="from-amber-500 to-orange-600"
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"> {hasPermission(currentUser, 'READ_GAMES') && (
<div> <StatCard
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400"> title="Games"
Roles count={games}
</div> iconPath={icon.mdiGamepadVariant}
<div className="text-3xl leading-tight font-semibold"> href='/games/games-list'
{roles} gradient="from-cyan-500 to-blue-500"
</div> />
</div> )}
<div> {hasPermission(currentUser, 'READ_ACTIVITIES') && (
<BaseIcon <StatCard
className={`${iconsColor}`} title="Activities"
w="w-16" count={activities}
h="h-16" iconPath={icon.mdiRun}
size={48} href='/activities/activities-list'
// eslint-disable-next-line @typescript-eslint/ban-ts-comment gradient="from-rose-500 to-red-600"
// @ts-ignore />
path={icon.mdiShieldAccountVariantOutline || icon.mdiTable} )}
/> {hasPermission(currentUser, 'READ_REWARD_BALANCES') && (
</div> <StatCard
</div> title="Rewards"
</div> count={reward_balances}
</Link>} iconPath={icon.mdiTrophy}
href='/reward_balances/reward_balances-list'
{hasPermission(currentUser, 'READ_PERMISSIONS') && <Link href={'/permissions/permissions-list'}> gradient="from-yellow-400 to-amber-600"
<div />
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`} )}
> {hasPermission(currentUser, 'READ_FAQS') && (
<div className="flex justify-between align-center"> <StatCard
<div> title="Faqs"
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400"> count={faqs}
Permissions iconPath={icon.mdiFrequentlyAskedQuestions}
</div> href='/faqs/faqs-list'
<div className="text-3xl leading-tight font-semibold"> gradient="from-slate-500 to-slate-700"
{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> </div>
</SectionMain> </SectionMain>
</> </>

View File

@ -1,161 +1,117 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import type { ReactElement } from 'react'; import type { ReactElement } from 'react';
import Head from 'next/head'; import Head from 'next/head';
import Link from 'next/link'; import Link from 'next/link';
import BaseButton from '../components/BaseButton'; import BaseButton from '../components/BaseButton';
import CardBox from '../components/CardBox';
import SectionFullScreen from '../components/SectionFullScreen'; import SectionFullScreen from '../components/SectionFullScreen';
import LayoutGuest from '../layouts/Guest'; import LayoutGuest from '../layouts/Guest';
import BaseDivider from '../components/BaseDivider';
import BaseButtons from '../components/BaseButtons';
import { getPageTitle } from '../config'; import { getPageTitle } from '../config';
import { useAppSelector } from '../stores/hooks'; import { useAppSelector } from '../stores/hooks';
import CardBoxComponentTitle from "../components/CardBoxComponentTitle"; import { mdiWeatherSunny, mdiCheckCircle, mdiRocketLaunch, mdiGamepadVariant, mdiArrowRight } from '@mdi/js';
import { getPexelsImage, getPexelsVideo } from '../helpers/pexels'; import BaseIcon from '../components/BaseIcon';
export default function Starter() { 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); const textColor = useAppSelector((state) => state.style.linkColor);
const title = 'App Preview' return (
<div className="relative overflow-hidden bg-midnightBlueTheme-mainBG min-h-screen font-sans">
// 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> <Head>
<title>{getPageTitle('Starter Page')}</title> <title>{getPageTitle('Welcome to Morninmate')}</title>
</Head> </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>
</div>
<SectionFullScreen bg='violet'> <SectionFullScreen bg='violet'>
<div <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">
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"> {/* Logo Section */}
<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> <div className="mb-12 animate-fade-in">
<p className='text-center '>For guides and documentation please check <div className="flex items-center justify-center space-x-4 mb-4">
your local README.md and the <a className={`${textColor}`} href="https://flatlogic.com/documentation">Flatlogic documentation</a></p> <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> </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>
<BaseButtons> {/* CTA Buttons */}
<BaseButton <div className="flex flex-col sm:flex-row gap-6 mb-24 w-full sm:w-auto animate-fade-in delay-200">
href='/login' <BaseButton
label='Login' href='/login'
color='info' label='Launch My Morning'
className='w-full' 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>
</BaseButtons> {/* Feature Grid */}
</CardBox> <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> </div>
</div>
</SectionFullScreen> </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>
<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> </div>
); );
} }
@ -163,4 +119,3 @@ export default function Starter() {
Starter.getLayout = function getLayout(page: ReactElement) { Starter.getLayout = function getLayout(page: ReactElement) {
return <LayoutGuest>{page}</LayoutGuest>; return <LayoutGuest>{page}</LayoutGuest>;
}; };

View File

@ -53,31 +53,31 @@ export const white: StyleObject = {
export const midnightBlueTheme: StyleObject = { export const midnightBlueTheme: StyleObject = {
aside: 'bg-midnightBlueTheme-800 text-midnightBlueTheme-text dark:text-white lg:rounded-lg', 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',
asideScrollbars: 'aside-scrollbars-blue', asideScrollbars: 'aside-scrollbars-blue',
asideBrand: 'text-blue-500 bg-white', asideBrand: 'text-indigo-500 bg-white/10 rounded-t-3xl',
asideMenuItem: asideMenuItem:
'text-midnightBlueTheme-text hover:text-white dark:text-dark-500 dark:hover:text-white dark:hover:bg-dark-800 dark:text-white', '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 dark:text-white', asideMenuItemActive: 'font-bold text-white bg-indigo-600/50 shadow-lg rounded-2xl mx-2 my-1 p-2',
activeLinkColor: 'bg-midnightBlueTheme-buttonColor rounded-lg', activeLinkColor: 'bg-indigo-600 rounded-2xl shadow-md',
asideMenuDropdown: 'bg-blue-700/50', asideMenuDropdown: 'bg-indigo-900/40 rounded-2xl mx-4',
navBarItemLabel: 'text-primaryText', navBarItemLabel: 'text-primaryText font-medium',
iconsColor: 'text-midnightBlueTheme-iconsColor dark:text-blue-500', iconsColor: 'text-indigo-400 dark:text-indigo-500',
navBarItemLabelHover: 'hover:text-stone-400', navBarItemLabelHover: 'hover:text-indigo-300',
navBarItemLabelActiveColor: 'text-midnightBlueTheme-800', navBarItemLabelActiveColor: 'text-indigo-200',
overlay: 'bg-midnightBlueTheme-mainBG', overlay: 'bg-midnightBlueTheme-mainBG/80 backdrop-blur-sm',
bgLayoutColor: 'bg-midnightBlueTheme-mainBG', bgLayoutColor: 'bg-midnightBlueTheme-mainBG',
cardsColor: 'bg-midnightBlueTheme-cardColor', cardsColor: 'bg-midnightBlueTheme-cardColor/60 backdrop-blur-xl shadow-2xl border border-white/5',
focusRingColor: focusRingColor:
'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', '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-lg', corners: 'rounded-3xl',
cardsStyle: 'bg-midnightBlueTheme-outsideCardColor border border-midnightBlueTheme-outsideCardColor shadow-xl', 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-midnightBlueTheme-buttonColor', linkColor: 'text-indigo-400',
websiteHeder: 'border-b border-white border-opacity-10 shadow-md', websiteHeder: 'border-b border-white/10 shadow-xl backdrop-blur-md bg-opacity-80',
borders: 'border-white border-opacity-10', borders: 'border-white/10',
shadow: 'shadow-md', shadow: 'shadow-2xl shadow-indigo-500/20',
websiteSectionStyle: ' bg-midnightBlueTheme-webSiteComponentBg text-white', websiteSectionStyle: 'bg-gradient-to-br from-indigo-900/20 to-purple-900/20 text-white',
textSecondary: 'text-gray-300', textSecondary: 'text-indigo-200/60',
}; };

View File

@ -86,7 +86,7 @@ module.exports = {
primaryText: '#E9EAEF', primaryText: '#E9EAEF',
}, },
fontFamily: { fontFamily: {
sans: ['Ubuntu', 'sans-serif'], sans: ['Inter', 'sans-serif'],
}, },
borderRadius: { borderRadius: {