feat: add full page index component with pagination and actions

- Implemented FullPagePageIndex component with mock data for database clusters.
- Added pagination and bulk actions for managing database clusters.
- Created navigation context hooks for detail, edit, duplicate, and create actions.
- Introduced a new store for managing state in full-page and single-page modules.

feat: add navigation localization files

- Added English and Indonesian localization files for navigation menu items.
- Included translations for various modules including CRM, Sales, Supply Chain, and more.

feat: create system information shortcuts component

- Developed Shortcut component to display keyboard shortcuts with search functionality.
- Implemented System component to show placeholder information when system details are unavailable.
- Added localization for shortcuts and system information in English and Indonesian.

feat: implement global theme store

- Created a Zustand store for managing theme color scheme with localStorage persistence.

feat: add module page header component

- Developed ModulePageHeader component for consistent page header across modules.
- Included breadcrumb navigation, title, description, and action buttons.

feat: define default privileges for enterprise module

- Established default privileges for CRUD operations and other actions in the enterprise module.
This commit is contained in:
Firman Ramdhani
2026-07-10 22:58:55 +07:00
parent 430b231360
commit 2b8f9a9cbc
55 changed files with 2809 additions and 354 deletions
@@ -3,13 +3,24 @@ import { AppShell, Flex, Box, Text, CloseButton } from '@mantine/core';
import { CoreAppShellProvider, useCoreAppShell } from './core-app-shell-context';
import { CoreAppShellConfig, CoreAppShellSlots, CoreAppShellDimensions } from './types';
// const DEFAULT_DIMENSIONS: Required<CoreAppShellDimensions> = {
// utilityBarHeight: 32,
// headerHeight: 60,
// // sidebarWidth: 260,
// sidebarWidth: 240,
// sidebarMiniWidth: 70,
// sidebarRailWidth: 54,
// // asideWidth: 260,
// asideWidth: 240,
// };
const DEFAULT_DIMENSIONS: Required<CoreAppShellDimensions> = {
utilityBarHeight: 32,
headerHeight: 60,
sidebarWidth: 260,
sidebarMiniWidth: 80,
sidebarRailWidth: 54,
asideWidth: 260,
headerHeight: 56,
sidebarWidth: 256,
sidebarMiniWidth: 64,
sidebarRailWidth: 56,
asideWidth: 280,
};
interface CoreAppShellInnerProps {
@@ -62,7 +73,6 @@ function CoreAppShellInner({ slots = {}, children }: CoreAppShellInnerProps) {
return `calc(${dims.headerHeight}${typeof dims.headerHeight === 'number' ? 'px' : ''} + ${dims.utilityBarHeight}${typeof dims.utilityBarHeight === 'number' ? 'px' : ''})`;
}, [dims.headerHeight, dims.utilityBarHeight, showUtilityBar]);
console.log({ totalHeaderHeight, dimensions });
return (
<AppShell
layout={appShellLayout}
@@ -124,7 +134,7 @@ function CoreAppShellInner({ slots = {}, children }: CoreAppShellInnerProps) {
h="100%"
style={{
flexShrink: 0,
borderRight: '1px solid var(--mantine-color-default-border)',
borderRight: '1px solid var(--app-shell-border-color)',
}}
>
{slots.sidebarRail}
@@ -147,7 +157,7 @@ function CoreAppShellInner({ slots = {}, children }: CoreAppShellInnerProps) {
justify="space-between"
p="md"
pb="sm"
style={{ borderBottom: '1px solid var(--mantine-color-default-border)' }}
style={{ borderBottom: '1px solid var(--app-shell-border-color)' }}
>
<Text fw={700}>Menu</Text>
<CloseButton onClick={toggleMobile} size="md" aria-label="Close menu" />
@@ -1,5 +1,5 @@
import { ReactNode } from 'react';
import { Box, Container, Stack, ContainerProps } from '@mantine/core';
import { ReactNode, useEffect, useState } from 'react';
import { Box, Container, Stack, ContainerProps, Divider } from '@mantine/core';
export interface CorePageContainerProps extends ContainerProps {
headerSlot?: ReactNode;
@@ -9,34 +9,63 @@ export interface CorePageContainerProps extends ContainerProps {
export function CorePageContainer({
headerSlot,
stickyHeader = false,
stickyHeader = true,
children,
px = "md",
py = "md",
px = { base: 'md', sm: 'xl' },
py = { base: 'md', sm: 'lg' },
...others
}: CorePageContainerProps) {
const [isScrolled, setIsScrolled] = useState(false);
useEffect(() => {
if (!stickyHeader) return;
const handleScroll = () => setIsScrolled(window.scrollY > 10);
window.addEventListener('scroll', handleScroll, { passive: true });
handleScroll();
return () => window.removeEventListener('scroll', handleScroll);
}, [stickyHeader]);
return (
<Box m="calc(var(--mantine-spacing-md) * -1)">
<Stack gap={0}>
<Box
m="calc(var(--mantine-spacing-md) * -1)"
style={{
display: 'flex',
flexDirection: 'column',
minHeight: 'calc(100vh - var(--app-shell-header-offset, 0px) - var(--app-shell-footer-offset, 0px))',
}}
>
<Stack gap={0} flex={1}>
{headerSlot && (
<Box
pos={stickyHeader ? 'sticky' : 'relative'}
top={stickyHeader ? 'var(--app-shell-header-offset, 0px)' : undefined}
bg="var(--mantine-color-body)"
style={{
position: stickyHeader ? 'sticky' : 'static',
top: stickyHeader ? 'var(--app-shell-header-offset, 0px)' : undefined,
zIndex: stickyHeader ? 10 : undefined,
backgroundColor: 'var(--mantine-color-body)',
borderBottom: '1px solid var(--mantine-color-default-border)',
zIndex: stickyHeader ? 10 : 1,
boxShadow: isScrolled ? 'var(--mantine-shadow-sm)' : 'none',
transition: 'box-shadow 0.2s ease, border-color 0.2s ease',
}}
>
<Container fluid px={px} py={py}>
<Container fluid px={px} pt={{ base: 'sm', sm: 'sm' }}>
{headerSlot}
{!isScrolled && (
<Divider
mt={0}
mb={0}
styles={{
root: { borderColor: 'light-dark(var(--mantine-color-gray-2), var(--mantine-color-dark-5))' },
}}
/>
)}
</Container>
</Box>
)}
<Container fluid px={px} py={py} w="100%" {...others}>
{children}
</Container>
<Box flex={1} pos="relative">
<Container fluid px={px} py={py} w="100%" h="100%" {...others}>
{children}
</Container>
</Box>
</Stack>
</Box>
);