@ifto/mantine-kit 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +475 -2
- package/dist/component/atom/AppMain/App.module.js +7 -0
- package/dist/component/atom/AppMain/App.module.js.map +1 -0
- package/dist/component/atom/AppMain/AppMain.d.ts +7 -0
- package/dist/component/atom/AppMain/AppMain.js +14 -0
- package/dist/component/atom/AppMain/AppMain.js.map +1 -0
- package/dist/component/atom/CancelEditButton/CancelEditButton.d.ts +6 -0
- package/dist/component/atom/CancelEditButton/CancelEditButton.js +24 -0
- package/dist/component/atom/CancelEditButton/CancelEditButton.js.map +1 -0
- package/dist/component/atom/ConfirmEditButton/ConfirmEditButton.d.ts +13 -0
- package/dist/component/atom/ConfirmEditButton/ConfirmEditButton.js +30 -0
- package/dist/component/atom/ConfirmEditButton/ConfirmEditButton.js.map +1 -0
- package/dist/component/atom/DateField/DateField.d.ts +7 -0
- package/dist/component/atom/DateField/DateField.js +21 -0
- package/dist/component/atom/DateField/DateField.js.map +1 -0
- package/dist/component/atom/EditValueButton/EditValueButton.d.ts +6 -0
- package/dist/component/atom/EditValueButton/EditValueButton.js +24 -0
- package/dist/component/atom/EditValueButton/EditValueButton.js.map +1 -0
- package/dist/component/atom/ErrorAlert/ErrorAlert.d.ts +8 -0
- package/dist/component/atom/ErrorAlert/ErrorAlert.js +21 -0
- package/dist/component/atom/ErrorAlert/ErrorAlert.js.map +1 -0
- package/dist/component/atom/Surface/Surface.d.ts +20 -0
- package/dist/component/atom/Surface/Surface.js +15 -0
- package/dist/component/atom/Surface/Surface.js.map +1 -0
- package/dist/component/molecule/Breadcrumb/Breadcrumb.d.ts +12 -0
- package/dist/component/molecule/Breadcrumb/Breadcrumb.js +38 -0
- package/dist/component/molecule/Breadcrumb/Breadcrumb.js.map +1 -0
- package/dist/component/molecule/ExportMenuButton/ExportMenuButton.d.ts +25 -0
- package/dist/component/molecule/ExportMenuButton/ExportMenuButton.js +49 -0
- package/dist/component/molecule/ExportMenuButton/ExportMenuButton.js.map +1 -0
- package/dist/component/molecule/PaperCard/PaperCard.d.ts +7 -0
- package/dist/component/molecule/PaperCard/PaperCard.js +17 -0
- package/dist/component/molecule/PaperCard/PaperCard.js.map +1 -0
- package/dist/component/molecule/PrintSection/PrintSection.d.ts +14 -0
- package/dist/component/molecule/PrintSection/PrintSection.js +29 -0
- package/dist/component/molecule/PrintSection/PrintSection.js.map +1 -0
- package/dist/component/molecule/SelectField/SelectField.d.ts +32 -0
- package/dist/component/molecule/SelectField/SelectField.js +38 -0
- package/dist/component/molecule/SelectField/SelectField.js.map +1 -0
- package/dist/component/molecule/StatsCard/Stats.module.js +15 -0
- package/dist/component/molecule/StatsCard/Stats.module.js.map +1 -0
- package/dist/component/molecule/StatsCard/StatsCard.d.ts +18 -0
- package/dist/component/molecule/StatsCard/StatsCard.js +60 -0
- package/dist/component/molecule/StatsCard/StatsCard.js.map +1 -0
- package/dist/component/organism/DataForm/DataForm.d.ts +26 -0
- package/dist/component/organism/DataForm/DataForm.js +83 -0
- package/dist/component/organism/DataForm/DataForm.js.map +1 -0
- package/dist/component/organism/DataTabList/DataTabList.d.ts +24 -0
- package/dist/component/organism/DataTabList/DataTabList.js +37 -0
- package/dist/component/organism/DataTabList/DataTabList.js.map +1 -0
- package/dist/component/organism/DataTabList/DataTabList.module.js +13 -0
- package/dist/component/organism/DataTabList/DataTabList.module.js.map +1 -0
- package/dist/component/organism/EChart/EChart.d.ts +47 -0
- package/dist/component/organism/EChart/EChart.js +37 -0
- package/dist/component/organism/EChart/EChart.js.map +1 -0
- package/dist/component/organism/EChart/buildEChartOption.d.ts +40 -0
- package/dist/component/organism/EChart/buildEChartOption.js +57 -0
- package/dist/component/organism/EChart/buildEChartOption.js.map +1 -0
- package/dist/component/organism/EChart/chart/BarChart.d.ts +22 -0
- package/dist/component/organism/EChart/chart/BarChart.js +34 -0
- package/dist/component/organism/EChart/chart/BarChart.js.map +1 -0
- package/dist/component/organism/EChart/chart/CartesianChart.d.ts +48 -0
- package/dist/component/organism/EChart/chart/CartesianChart.js +63 -0
- package/dist/component/organism/EChart/chart/CartesianChart.js.map +1 -0
- package/dist/component/organism/EChart/chart/ChartHeader.d.ts +36 -0
- package/dist/component/organism/EChart/chart/ChartHeader.js +105 -0
- package/dist/component/organism/EChart/chart/ChartHeader.js.map +1 -0
- package/dist/component/organism/EChart/chart/ChartSeries.d.ts +50 -0
- package/dist/component/organism/EChart/chart/ChartSeries.js +23 -0
- package/dist/component/organism/EChart/chart/ChartSeries.js.map +1 -0
- package/dist/component/organism/EChart/chart/ChartTexts.d.ts +12 -0
- package/dist/component/organism/EChart/chart/ChartTexts.js +21 -0
- package/dist/component/organism/EChart/chart/ChartTexts.js.map +1 -0
- package/dist/component/organism/EChart/chart/ChartType.d.ts +50 -0
- package/dist/component/organism/EChart/chart/ChartType.js +1 -0
- package/dist/component/organism/EChart/chart/ChartTypeId.d.ts +2 -0
- package/dist/component/organism/EChart/chart/ChartTypeId.js +1 -0
- package/dist/component/organism/EChart/chart/ChartTypes.d.ts +15 -0
- package/dist/component/organism/EChart/chart/ChartTypes.js +24 -0
- package/dist/component/organism/EChart/chart/ChartTypes.js.map +1 -0
- package/dist/component/organism/EChart/chart/DonutChart.d.ts +32 -0
- package/dist/component/organism/EChart/chart/DonutChart.js +111 -0
- package/dist/component/organism/EChart/chart/DonutChart.js.map +1 -0
- package/dist/component/organism/EChart/chart/LineChart.d.ts +11 -0
- package/dist/component/organism/EChart/chart/LineChart.js +20 -0
- package/dist/component/organism/EChart/chart/LineChart.js.map +1 -0
- package/dist/component/organism/EChart/chart/StackedBarChart.d.ts +15 -0
- package/dist/component/organism/EChart/chart/StackedBarChart.js +30 -0
- package/dist/component/organism/EChart/chart/StackedBarChart.js.map +1 -0
- package/dist/component/organism/EChart/chart/UnitPanels.d.ts +63 -0
- package/dist/component/organism/EChart/chart/UnitPanels.js +127 -0
- package/dist/component/organism/EChart/chart/UnitPanels.js.map +1 -0
- package/dist/component/organism/EChart/echartDefaults.d.ts +32 -0
- package/dist/component/organism/EChart/echartDefaults.js +47 -0
- package/dist/component/organism/EChart/echartDefaults.js.map +1 -0
- package/dist/component/organism/EChart/useEChart.d.ts +35 -0
- package/dist/component/organism/EChart/useEChart.js +112 -0
- package/dist/component/organism/EChart/useEChart.js.map +1 -0
- package/dist/component/organism/Navbar/NavItem.d.ts +16 -0
- package/dist/component/organism/Navbar/NavItem.js +1 -0
- package/dist/component/organism/Navbar/Navbar.d.ts +20 -0
- package/dist/component/organism/Navbar/Navbar.js +64 -0
- package/dist/component/organism/Navbar/Navbar.js.map +1 -0
- package/dist/component/organism/Navbar/Navbar.module.js +19 -0
- package/dist/component/organism/Navbar/Navbar.module.js.map +1 -0
- package/dist/component/organism/PageHeader/PageHeader.d.ts +14 -0
- package/dist/component/organism/PageHeader/PageHeader.js +55 -0
- package/dist/component/organism/PageHeader/PageHeader.js.map +1 -0
- package/dist/component/organism/StatsGrid/StatsGrid.d.ts +12 -0
- package/dist/component/organism/StatsGrid/StatsGrid.js +46 -0
- package/dist/component/organism/StatsGrid/StatsGrid.js.map +1 -0
- package/dist/component/organism/StatsGrid/StatsGrid.module.js +17 -0
- package/dist/component/organism/StatsGrid/StatsGrid.module.js.map +1 -0
- package/dist/component/organism/Table/RowActions.d.ts +23 -0
- package/dist/component/organism/Table/RowActions.js +121 -0
- package/dist/component/organism/Table/RowActions.js.map +1 -0
- package/dist/component/organism/Table/Table.d.ts +51 -0
- package/dist/component/organism/Table/Table.js +110 -0
- package/dist/component/organism/Table/Table.js.map +1 -0
- package/dist/component/organism/ViewTable/ColumnComparator.d.ts +11 -0
- package/dist/component/organism/ViewTable/ColumnComparator.js +25 -0
- package/dist/component/organism/ViewTable/ColumnComparator.js.map +1 -0
- package/dist/component/organism/ViewTable/ViewTable.d.ts +53 -0
- package/dist/component/organism/ViewTable/ViewTable.js +115 -0
- package/dist/component/organism/ViewTable/ViewTable.js.map +1 -0
- package/dist/component/organism/ViewTable/useRowKey.d.ts +8 -0
- package/dist/component/organism/ViewTable/useRowKey.js +24 -0
- package/dist/component/organism/ViewTable/useRowKey.js.map +1 -0
- package/dist/component/template/CreateFormPage/CreateFormPage.d.ts +19 -0
- package/dist/component/template/CreateFormPage/CreateFormPage.js +41 -0
- package/dist/component/template/CreateFormPage/CreateFormPage.js.map +1 -0
- package/dist/component/template/EditFormPage/EditFormPage.d.ts +19 -0
- package/dist/component/template/EditFormPage/EditFormPage.js +42 -0
- package/dist/component/template/EditFormPage/EditFormPage.js.map +1 -0
- package/dist/component/template/FormPage/FormPage.d.ts +25 -0
- package/dist/component/template/FormPage/FormPage.js +130 -0
- package/dist/component/template/FormPage/FormPage.js.map +1 -0
- package/dist/component/template/FormPage/FormType.d.ts +6 -0
- package/dist/component/template/FormPage/FormType.js +12 -0
- package/dist/component/template/FormPage/FormType.js.map +1 -0
- package/dist/component/template/Layout/Layout.d.ts +21 -0
- package/dist/component/template/Layout/Layout.js +121 -0
- package/dist/component/template/Layout/Layout.js.map +1 -0
- package/dist/component/template/Layout/Layout.module.js +19 -0
- package/dist/component/template/Layout/Layout.module.js.map +1 -0
- package/dist/component/template/ListPage/ListPage.d.ts +32 -0
- package/dist/component/template/ListPage/ListPage.js +47 -0
- package/dist/component/template/ListPage/ListPage.js.map +1 -0
- package/dist/component/template/PrintPage/PrintPage.d.ts +25 -0
- package/dist/component/template/PrintPage/PrintPage.js +115 -0
- package/dist/component/template/PrintPage/PrintPage.js.map +1 -0
- package/dist/component/template/ViewPage/ViewPage.d.ts +11 -0
- package/dist/component/template/ViewPage/ViewPage.js +49 -0
- package/dist/component/template/ViewPage/ViewPage.js.map +1 -0
- package/dist/data/ListDataSource.d.ts +12 -0
- package/dist/data/ListDataSource.js +1 -0
- package/dist/data/SaveDataSource.d.ts +16 -0
- package/dist/data/SaveDataSource.js +1 -0
- package/dist/export/ExportCellText.d.ts +18 -0
- package/dist/export/ExportCellText.js +60 -0
- package/dist/export/ExportCellText.js.map +1 -0
- package/dist/export/ExportDocument.d.ts +127 -0
- package/dist/export/ExportDocument.js +59 -0
- package/dist/export/ExportDocument.js.map +1 -0
- package/dist/export/ExportDownload.d.ts +9 -0
- package/dist/export/ExportDownload.js +19 -0
- package/dist/export/ExportDownload.js.map +1 -0
- package/dist/export/ExportFileName.d.ts +11 -0
- package/dist/export/ExportFileName.js +24 -0
- package/dist/export/ExportFileName.js.map +1 -0
- package/dist/export/ExportFormat.d.ts +30 -0
- package/dist/export/ExportFormat.js +1 -0
- package/dist/export/ExportFormats.d.ts +12 -0
- package/dist/export/ExportFormats.js +16 -0
- package/dist/export/ExportFormats.js.map +1 -0
- package/dist/export/ExportTexts.d.ts +14 -0
- package/dist/export/ExportTexts.js +23 -0
- package/dist/export/ExportTexts.js.map +1 -0
- package/dist/export/csv/CsvFormat.d.ts +41 -0
- package/dist/export/csv/CsvFormat.js +91 -0
- package/dist/export/csv/CsvFormat.js.map +1 -0
- package/dist/export/xlsx/XlsxFormat.d.ts +35 -0
- package/dist/export/xlsx/XlsxFormat.js +66 -0
- package/dist/export/xlsx/XlsxFormat.js.map +1 -0
- package/dist/export/xlsx/XlsxNumberFormat.d.ts +8 -0
- package/dist/export/xlsx/XlsxNumberFormat.js +15 -0
- package/dist/export/xlsx/XlsxNumberFormat.js.map +1 -0
- package/dist/export/xlsx/XlsxSheetName.d.ts +12 -0
- package/dist/export/xlsx/XlsxSheetName.js +62 -0
- package/dist/export/xlsx/XlsxSheetName.js.map +1 -0
- package/dist/export/xlsx/XlsxSheetWriter.d.ts +67 -0
- package/dist/export/xlsx/XlsxSheetWriter.js +215 -0
- package/dist/export/xlsx/XlsxSheetWriter.js.map +1 -0
- package/dist/export/xlsx/XlsxStyle.d.ts +51 -0
- package/dist/export/xlsx/XlsxStyle.js +87 -0
- package/dist/export/xlsx/XlsxStyle.js.map +1 -0
- package/dist/hook/useIsMobile.d.ts +5 -0
- package/dist/hook/useIsMobile.js +16 -0
- package/dist/hook/useIsMobile.js.map +1 -0
- package/dist/hook/useKeyedService.d.ts +22 -0
- package/dist/hook/useKeyedService.js +38 -0
- package/dist/hook/useKeyedService.js.map +1 -0
- package/dist/hook/useLightColorSchemeOnPrint.d.ts +9 -0
- package/dist/hook/useLightColorSchemeOnPrint.js +36 -0
- package/dist/hook/useLightColorSchemeOnPrint.js.map +1 -0
- package/dist/hook/useService.d.ts +27 -0
- package/dist/hook/useService.js +23 -0
- package/dist/hook/useService.js.map +1 -0
- package/dist/http/ApiError.d.ts +13 -0
- package/dist/http/ApiError.js +22 -0
- package/dist/http/ApiError.js.map +1 -0
- package/dist/http/AxiosHttpClient.d.ts +21 -0
- package/dist/http/AxiosHttpClient.js +67 -0
- package/dist/http/AxiosHttpClient.js.map +1 -0
- package/dist/http/AxiosHttpClientConfig.d.ts +37 -0
- package/dist/http/AxiosHttpClientConfig.js +19 -0
- package/dist/http/AxiosHttpClientConfig.js.map +1 -0
- package/dist/i18n/KitLocale.d.ts +4 -0
- package/dist/i18n/KitLocale.js +7 -0
- package/dist/i18n/KitLocale.js.map +1 -0
- package/dist/i18n/KitMessages.d.ts +146 -0
- package/dist/i18n/KitMessages.js +1 -0
- package/dist/i18n/messages/enUS.d.ts +3 -0
- package/dist/i18n/messages/enUS.js +112 -0
- package/dist/i18n/messages/enUS.js.map +1 -0
- package/dist/i18n/messages/ptBR.d.ts +3 -0
- package/dist/i18n/messages/ptBR.js +97 -0
- package/dist/i18n/messages/ptBR.js.map +1 -0
- package/dist/i18n/resolveMessages.d.ts +13 -0
- package/dist/i18n/resolveMessages.js +29 -0
- package/dist/i18n/resolveMessages.js.map +1 -0
- package/dist/model/Identifiable.d.ts +7 -0
- package/dist/model/Identifiable.js +1 -0
- package/dist/provider/KitConfig.d.ts +26 -0
- package/dist/provider/KitConfig.js +1 -0
- package/dist/provider/KitContext.d.ts +9 -0
- package/dist/provider/KitContext.js +27 -0
- package/dist/provider/KitContext.js.map +1 -0
- package/dist/provider/KitProvider.d.ts +7 -0
- package/dist/provider/KitProvider.js +31 -0
- package/dist/provider/KitProvider.js.map +1 -0
- package/dist/provider/useKit.d.ts +15 -0
- package/dist/provider/useKit.js +28 -0
- package/dist/provider/useKit.js.map +1 -0
- package/dist/router/FormRouteSegments.d.ts +16 -0
- package/dist/router/FormRouteSegments.js +19 -0
- package/dist/router/FormRouteSegments.js.map +1 -0
- package/dist/router/RouterAdapter.d.ts +24 -0
- package/dist/router/RouterAdapter.js +1 -0
- package/dist/router/anchorRouter.d.ts +7 -0
- package/dist/router/anchorRouter.js +23 -0
- package/dist/router/anchorRouter.js.map +1 -0
- package/dist/styles/print.css +93 -0
- package/dist/styles.css +188 -0
- package/dist/util/ArrayUtil.d.ts +39 -0
- package/dist/util/ArrayUtil.js +48 -0
- package/dist/util/ArrayUtil.js.map +1 -0
- package/dist/util/ColorUtil.d.ts +7 -0
- package/dist/util/ColorUtil.js +16 -0
- package/dist/util/ColorUtil.js.map +1 -0
- package/dist/util/CompareUtil.d.ts +19 -0
- package/dist/util/CompareUtil.js +51 -0
- package/dist/util/CompareUtil.js.map +1 -0
- package/dist/util/DateUtil.d.ts +38 -0
- package/dist/util/DateUtil.js +55 -0
- package/dist/util/DateUtil.js.map +1 -0
- package/dist/util/DownloadUtil.d.ts +6 -0
- package/dist/util/DownloadUtil.js +25 -0
- package/dist/util/DownloadUtil.js.map +1 -0
- package/dist/util/EnumUtil.d.ts +19 -0
- package/dist/util/EnumUtil.js +32 -0
- package/dist/util/EnumUtil.js.map +1 -0
- package/dist/util/FormUtil.d.ts +8 -0
- package/dist/util/FormUtil.js +14 -0
- package/dist/util/FormUtil.js.map +1 -0
- package/dist/util/HtmlUtil.d.ts +8 -0
- package/dist/util/HtmlUtil.js +23 -0
- package/dist/util/HtmlUtil.js.map +1 -0
- package/dist/util/Notifications.d.ts +30 -0
- package/dist/util/Notifications.js +59 -0
- package/dist/util/Notifications.js.map +1 -0
- package/dist/util/NumberUtil.d.ts +19 -0
- package/dist/util/NumberUtil.js +33 -0
- package/dist/util/NumberUtil.js.map +1 -0
- package/dist/util/ObjectUtil.d.ts +22 -0
- package/dist/util/ObjectUtil.js +34 -0
- package/dist/util/ObjectUtil.js.map +1 -0
- package/dist/util/SearchParamsUtil.d.ts +23 -0
- package/dist/util/SearchParamsUtil.js +29 -0
- package/dist/util/SearchParamsUtil.js.map +1 -0
- package/dist/util/TransformData.d.ts +14 -0
- package/dist/util/TransformData.js +31 -0
- package/dist/util/TransformData.js.map +1 -0
- package/dist/util/ValidationUtil.d.ts +9 -0
- package/dist/util/ValidationUtil.js +16 -0
- package/dist/util/ValidationUtil.js.map +1 -0
- package/dist/util/parseActionsPageParams.d.ts +14 -0
- package/dist/util/parseActionsPageParams.js +29 -0
- package/dist/util/parseActionsPageParams.js.map +1 -0
- package/package.json +158 -5
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import AppMain from "../../atom/AppMain/AppMain.js";
|
|
3
|
+
import { Navbar } from "../../organism/Navbar/Navbar.js";
|
|
4
|
+
import { useKitMessages } from "../../../provider/useKit.js";
|
|
5
|
+
import Layout_module_default from "./Layout.module.js";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { useDisclosure, useMediaQuery, useMounted } from "@mantine/hooks";
|
|
8
|
+
import { ActionIcon, AppShell, Avatar, Burger, Container, Group, Menu, Tooltip, UnstyledButton, useComputedColorScheme, useMantineColorScheme, useMantineTheme } from "@mantine/core";
|
|
9
|
+
import { IconMoon, IconSun } from "@tabler/icons-react";
|
|
10
|
+
import cx from "clsx";
|
|
11
|
+
// src/component/template/Layout/Layout.tsx
|
|
12
|
+
/**
|
|
13
|
+
* Structure of the pages of the app: header with the brand, the color scheme toggle and the user menu, collapsible side
|
|
14
|
+
* menu and the content area.
|
|
15
|
+
*/
|
|
16
|
+
var Layout = ({ children, logo, navItems, navFooter, userMenu }) => {
|
|
17
|
+
const messages = useKitMessages().layout;
|
|
18
|
+
const [mobileOpened, { toggle: toggleMobile }] = useDisclosure();
|
|
19
|
+
const [desktopOpened, { toggle: toggleDesktop }] = useDisclosure(true);
|
|
20
|
+
const { setColorScheme } = useMantineColorScheme();
|
|
21
|
+
const savedColorScheme = useComputedColorScheme("light", { getInitialValueInEffect: true });
|
|
22
|
+
const nextColorScheme = (useMounted() ? savedColorScheme : "light") === "light" ? "dark" : "light";
|
|
23
|
+
const colorSchemeLabel = nextColorScheme === "dark" ? messages.enableDarkTheme : messages.enableLightTheme;
|
|
24
|
+
const theme = useMantineTheme();
|
|
25
|
+
const isMobile = !useMediaQuery(`(min-width: ${theme.breakpoints.sm})`);
|
|
26
|
+
const isOpened = isMobile ? mobileOpened : desktopOpened;
|
|
27
|
+
const toggleBurgerFn = isMobile ? toggleMobile : toggleDesktop;
|
|
28
|
+
return /* @__PURE__ */ jsxs(AppShell, {
|
|
29
|
+
header: { height: {
|
|
30
|
+
base: 60,
|
|
31
|
+
sm: 68
|
|
32
|
+
} },
|
|
33
|
+
navbar: {
|
|
34
|
+
width: { base: 300 },
|
|
35
|
+
breakpoint: "sm",
|
|
36
|
+
collapsed: {
|
|
37
|
+
mobile: !mobileOpened,
|
|
38
|
+
desktop: !desktopOpened
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
padding: 0,
|
|
42
|
+
children: [
|
|
43
|
+
/* @__PURE__ */ jsx(AppShell.Header, { children: /* @__PURE__ */ jsxs(Group, {
|
|
44
|
+
h: "100%",
|
|
45
|
+
justify: "space-between",
|
|
46
|
+
wrap: "nowrap",
|
|
47
|
+
gap: "xs",
|
|
48
|
+
px: {
|
|
49
|
+
base: "xs",
|
|
50
|
+
sm: "md"
|
|
51
|
+
},
|
|
52
|
+
children: [/* @__PURE__ */ jsxs(Group, {
|
|
53
|
+
wrap: "nowrap",
|
|
54
|
+
className: cx(Layout_module_default.shrinkable, Layout_module_default.headerGap),
|
|
55
|
+
children: [/* @__PURE__ */ jsx(Burger, {
|
|
56
|
+
opened: isOpened,
|
|
57
|
+
onClick: toggleBurgerFn,
|
|
58
|
+
size: "sm",
|
|
59
|
+
"aria-label": isOpened ? messages.collapseNavigation : messages.expandNavigation,
|
|
60
|
+
"aria-expanded": isOpened,
|
|
61
|
+
className: Layout_module_default.fixed
|
|
62
|
+
}), logo]
|
|
63
|
+
}), /* @__PURE__ */ jsxs(Group, {
|
|
64
|
+
wrap: "nowrap",
|
|
65
|
+
gap: "xs",
|
|
66
|
+
className: Layout_module_default.fixed,
|
|
67
|
+
children: [/* @__PURE__ */ jsx(Tooltip, {
|
|
68
|
+
label: colorSchemeLabel,
|
|
69
|
+
children: /* @__PURE__ */ jsxs(ActionIcon, {
|
|
70
|
+
onClick: () => setColorScheme(nextColorScheme),
|
|
71
|
+
variant: "subtle",
|
|
72
|
+
size: 40,
|
|
73
|
+
radius: "xl",
|
|
74
|
+
"aria-label": colorSchemeLabel,
|
|
75
|
+
children: [/* @__PURE__ */ jsx(IconSun, {
|
|
76
|
+
className: cx(Layout_module_default.icon, Layout_module_default.light),
|
|
77
|
+
stroke: 1.5
|
|
78
|
+
}), /* @__PURE__ */ jsx(IconMoon, {
|
|
79
|
+
className: cx(Layout_module_default.icon, Layout_module_default.dark),
|
|
80
|
+
stroke: 1.5
|
|
81
|
+
})]
|
|
82
|
+
})
|
|
83
|
+
}), userMenu && /* @__PURE__ */ jsxs(Menu, {
|
|
84
|
+
shadow: "lg",
|
|
85
|
+
width: 200,
|
|
86
|
+
children: [/* @__PURE__ */ jsx(Tooltip, {
|
|
87
|
+
label: messages.userMenu,
|
|
88
|
+
children: /* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(UnstyledButton, {
|
|
89
|
+
"aria-label": messages.userMenu,
|
|
90
|
+
style: { borderRadius: "50%" },
|
|
91
|
+
children: /* @__PURE__ */ jsx(Avatar, {
|
|
92
|
+
color: theme.primaryColor,
|
|
93
|
+
radius: "xl",
|
|
94
|
+
size: 40
|
|
95
|
+
})
|
|
96
|
+
}) })
|
|
97
|
+
}), /* @__PURE__ */ jsxs(Menu.Dropdown, { children: [/* @__PURE__ */ jsx(Menu.Label, {
|
|
98
|
+
tt: "uppercase",
|
|
99
|
+
ta: "center",
|
|
100
|
+
fw: 600,
|
|
101
|
+
children: messages.userMenuTitle
|
|
102
|
+
}), userMenu] })]
|
|
103
|
+
})]
|
|
104
|
+
})]
|
|
105
|
+
}) }),
|
|
106
|
+
/* @__PURE__ */ jsx(Navbar, {
|
|
107
|
+
items: navItems,
|
|
108
|
+
footer: navFooter,
|
|
109
|
+
linkClickHandler: () => isMobile && toggleBurgerFn()
|
|
110
|
+
}),
|
|
111
|
+
/* @__PURE__ */ jsx(AppShell.Main, { children: /* @__PURE__ */ jsx(AppMain, { children: /* @__PURE__ */ jsx(Container, {
|
|
112
|
+
p: "md",
|
|
113
|
+
fluid: true,
|
|
114
|
+
children
|
|
115
|
+
}) }) })
|
|
116
|
+
]
|
|
117
|
+
});
|
|
118
|
+
};
|
|
119
|
+
export { Layout };
|
|
120
|
+
|
|
121
|
+
//# sourceMappingURL=Layout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Layout.js","names":["classes"],"sources":["../../../../src/component/template/Layout/Layout.tsx"],"sourcesContent":["import {\n ActionIcon,\n AppShell,\n Avatar,\n Burger,\n Container,\n Group,\n Menu,\n Tooltip,\n UnstyledButton,\n useComputedColorScheme,\n useMantineColorScheme,\n useMantineTheme\n} from '@mantine/core';\nimport { useDisclosure, useMediaQuery, useMounted } from '@mantine/hooks';\nimport { IconMoon, IconSun } from '@tabler/icons-react';\nimport cx from 'clsx';\n\nimport AppMain from '../../atom/AppMain/AppMain';\nimport Navbar from '../../organism/Navbar/Navbar';\nimport { NavItem } from '../../organism/Navbar/NavItem';\nimport { useKitMessages } from '../../../provider/useKit';\nimport classes from './Layout.module.css';\n\ninterface Props {\n children: React.ReactNode;\n\n /** Brand of the app in the header (e.g. the logo with a link to the home page). */\n logo: React.ReactNode;\n\n /** Items of the side menu. */\n navItems: NavItem[];\n\n /** Content fixed at the bottom of the side menu (e.g. a link to log out). */\n navFooter?: React.ReactNode;\n\n /**\n * Items of the user menu (e.g. `Menu.Item`s for the profile and to log out), opened by the avatar in the header.\n * Without them, the avatar is not shown.\n */\n userMenu?: React.ReactNode;\n}\n\n/**\n * Structure of the pages of the app: header with the brand, the color scheme toggle and the user menu, collapsible side\n * menu and the content area.\n */\nexport const Layout = ({ children, logo, navItems, navFooter, userMenu }: Props) => {\n const messages = useKitMessages().layout;\n const [mobileOpened, { toggle: toggleMobile }] = useDisclosure();\n const [desktopOpened, { toggle: toggleDesktop }] = useDisclosure(true);\n const { setColorScheme } = useMantineColorScheme();\n const savedColorScheme = useComputedColorScheme('light', { getInitialValueInEffect: true });\n /* The server does not know the color scheme saved in the browser and always renders the light one. Using the saved\n scheme only after mounting keeps the button label equal to the server HTML (avoiding a hydration error). */\n const computedColorScheme = useMounted() ? savedColorScheme : 'light';\n const nextColorScheme = computedColorScheme === 'light' ? 'dark' : 'light';\n const colorSchemeLabel = nextColorScheme === 'dark' ? messages.enableDarkTheme : messages.enableLightTheme;\n\n const theme = useMantineTheme();\n const isDesktop = useMediaQuery(`(min-width: ${theme.breakpoints.sm})`);\n const isMobile = !isDesktop;\n const isOpened = isMobile ? mobileOpened : desktopOpened;\n const toggleBurgerFn = isMobile ? toggleMobile : toggleDesktop;\n\n return (\n <AppShell\n header={{ height: { base: 60, sm: 68 } }}\n navbar={{\n width: { base: 300 },\n breakpoint: 'sm',\n collapsed: { mobile: !mobileOpened, desktop: !desktopOpened }\n }}\n padding={0}\n >\n <AppShell.Header>\n <Group h=\"100%\" justify=\"space-between\" wrap=\"nowrap\" gap=\"xs\" px={{ base: 'xs', sm: 'md' }}>\n <Group wrap=\"nowrap\" className={cx(classes.shrinkable, classes.headerGap)}>\n <Burger\n opened={isOpened}\n onClick={toggleBurgerFn}\n size=\"sm\"\n aria-label={isOpened ? messages.collapseNavigation : messages.expandNavigation}\n aria-expanded={isOpened}\n className={classes.fixed}\n />\n\n {logo}\n </Group>\n\n <Group wrap=\"nowrap\" gap=\"xs\" className={classes.fixed}>\n <Tooltip label={colorSchemeLabel}>\n <ActionIcon\n onClick={() => setColorScheme(nextColorScheme)}\n variant=\"subtle\"\n size={40}\n radius=\"xl\"\n aria-label={colorSchemeLabel}\n >\n <IconSun className={cx(classes.icon, classes.light)} stroke={1.5} />\n <IconMoon className={cx(classes.icon, classes.dark)} stroke={1.5} />\n </ActionIcon>\n </Tooltip>\n\n {userMenu && (\n <Menu shadow=\"lg\" width={200}>\n {/* The Tooltip stays outside the Menu.Target: in Mantine 9, the Menu.Target passes the menu\n props to its direct child, and they would go to the Tooltip instead of the button. */}\n <Tooltip label={messages.userMenu}>\n <Menu.Target>\n <UnstyledButton aria-label={messages.userMenu} style={{ borderRadius: '50%' }}>\n <Avatar color={theme.primaryColor} radius=\"xl\" size={40} />\n </UnstyledButton>\n </Menu.Target>\n </Tooltip>\n <Menu.Dropdown>\n <Menu.Label tt=\"uppercase\" ta=\"center\" fw={600}>\n {messages.userMenuTitle}\n </Menu.Label>\n {userMenu}\n </Menu.Dropdown>\n </Menu>\n )}\n </Group>\n </Group>\n </AppShell.Header>\n\n <Navbar items={navItems} footer={navFooter} linkClickHandler={() => isMobile && toggleBurgerFn()} />\n\n <AppShell.Main>\n <AppMain>\n <Container p=\"md\" fluid>\n {children}\n </Container>\n </AppMain>\n </AppShell.Main>\n </AppShell>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;AA+CA,IAAa,UAAU,EAAE,UAAU,MAAM,UAAU,WAAW,eAAsB;CAChF,MAAM,WAAW,eAAe,CAAC,CAAC;CAClC,MAAM,CAAC,cAAc,EAAE,QAAQ,kBAAkB,cAAc;CAC/D,MAAM,CAAC,eAAe,EAAE,QAAQ,mBAAmB,cAAc,IAAI;CACrE,MAAM,EAAE,mBAAmB,sBAAsB;CACjD,MAAM,mBAAmB,uBAAuB,SAAS,EAAE,yBAAyB,KAAK,CAAC;CAI1F,MAAM,mBADsB,WAAW,IAAI,mBAAmB,aACd,UAAU,SAAS;CACnE,MAAM,mBAAmB,oBAAoB,SAAS,SAAS,kBAAkB,SAAS;CAE1F,MAAM,QAAQ,gBAAgB;CAE9B,MAAM,WAAW,CADC,cAAc,eAAe,MAAM,YAAY,GAAG,EAClD;CAClB,MAAM,WAAW,WAAW,eAAe;CAC3C,MAAM,iBAAiB,WAAW,eAAe;CAEjD,OACI,qBAAC,UAAD;EACI,QAAQ,EAAE,QAAQ;GAAE,MAAM;GAAI,IAAI;EAAG,EAAE;EACvC,QAAQ;GACJ,OAAO,EAAE,MAAM,IAAI;GACnB,YAAY;GACZ,WAAW;IAAE,QAAQ,CAAC;IAAc,SAAS,CAAC;GAAc;EAChE;EACA,SAAS;EAPb,UAAA;GASI,oBAAC,SAAS,QAAV,EAAA,UACI,qBAAC,OAAD;IAAO,GAAE;IAAO,SAAQ;IAAgB,MAAK;IAAS,KAAI;IAAK,IAAI;KAAE,MAAM;KAAM,IAAI;IAAK;IAA1F,UAAA,CACI,qBAAC,OAAD;KAAO,MAAK;KAAS,WAAW,GAAGA,sBAAQ,YAAYA,sBAAQ,SAAS;KAAxE,UAAA,CACI,oBAAC,QAAD;MACI,QAAQ;MACR,SAAS;MACT,MAAK;MACL,cAAY,WAAW,SAAS,qBAAqB,SAAS;MAC9D,iBAAe;MACf,WAAWA,sBAAQ;KACtB,CAAA,GAEA,IACE;IAEP,CAAA,GAAA,qBAAC,OAAD;KAAO,MAAK;KAAS,KAAI;KAAK,WAAWA,sBAAQ;KAAjD,UAAA,CACI,oBAAC,SAAD;MAAS,OAAO;MACZ,UAAA,qBAAC,YAAD;OACI,eAAe,eAAe,eAAe;OAC7C,SAAQ;OACR,MAAM;OACN,QAAO;OACP,cAAY;OALhB,UAAA,CAOI,oBAAC,SAAD;QAAS,WAAW,GAAGA,sBAAQ,MAAMA,sBAAQ,KAAK;QAAG,QAAQ;OAAM,CAAA,GACnE,oBAAC,UAAD;QAAU,WAAW,GAAGA,sBAAQ,MAAMA,sBAAQ,IAAI;QAAG,QAAQ;OAAM,CAAA,CAC3D;;KACP,CAAA,GAER,YACG,qBAAC,MAAD;MAAM,QAAO;MAAK,OAAO;MAAzB,UAAA,CAGI,oBAAC,SAAD;OAAS,OAAO,SAAS;OACrB,UAAA,oBAAC,KAAK,QAAN,EAAA,UACI,oBAAC,gBAAD;QAAgB,cAAY,SAAS;QAAU,OAAO,EAAE,cAAc,MAAM;QACxE,UAAA,oBAAC,QAAD;SAAQ,OAAO,MAAM;SAAc,QAAO;SAAK,MAAM;QAAK,CAAA;OAC9C,CAAA,EACP,CAAA;MACR,CAAA,GACT,qBAAC,KAAK,UAAN,EAAA,UAAA,CACI,oBAAC,KAAK,OAAN;OAAY,IAAG;OAAY,IAAG;OAAS,IAAI;OACtC,UAAA,SAAS;MACF,CAAA,GACX,QACU,EAAA,CAAA,CACb;KAEP,CAAA,CAAA;IACJ,CAAA,CAAA;GACM,CAAA,EAAA,CAAA;GAEjB,oBAAC,QAAD;IAAQ,OAAO;IAAU,QAAQ;IAAW,wBAAwB,YAAY,eAAe;GAAI,CAAA;GAEnG,oBAAC,SAAS,MAAV,EAAA,UACI,oBAAC,SAAD,EAAA,UACI,oBAAC,WAAD;IAAW,GAAE;IAAK,OAAA;IACb;GACM,CAAA,EACN,CAAA,EACE,CAAA;EACT;;AAElB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
// src/component/template/Layout/Layout.module.css
|
|
3
|
+
var shrinkable = "mk-Layout-module-shrinkable-JUv2C";
|
|
4
|
+
var fixed = "mk-Layout-module-fixed-Z1ueS";
|
|
5
|
+
var icon = "mk-Layout-module-icon-EDq-h";
|
|
6
|
+
var dark = "mk-Layout-module-dark-Zx9Wz";
|
|
7
|
+
var light = "mk-Layout-module-light--F7XT";
|
|
8
|
+
var headerGap = "mk-Layout-module-headerGap-VrPBg";
|
|
9
|
+
var Layout_module_default = {
|
|
10
|
+
shrinkable,
|
|
11
|
+
fixed,
|
|
12
|
+
icon,
|
|
13
|
+
dark,
|
|
14
|
+
light,
|
|
15
|
+
headerGap
|
|
16
|
+
};
|
|
17
|
+
export { dark, Layout_module_default as default, fixed, headerGap, icon, light, shrinkable };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=Layout.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Layout.module.js","names":[],"sources":["../../../../src/component/template/Layout/Layout.module.css"],"sourcesContent":[".shrinkable {\n min-width: 0;\n}\n\n.fixed {\n flex-shrink: 0;\n}\n\n.icon {\n width: 20px;\n height: 20px;\n}\n\n.dark {\n @mixin dark {\n display: none;\n }\n\n @mixin light {\n display: block;\n }\n}\n\n.light {\n @mixin light {\n display: none;\n }\n\n @mixin dark {\n display: block;\n }\n}\n\n/* Responsive spacing of the header groups: the `gap` prop of the Mantine Group accepts no values per breakpoint. */\n.headerGap {\n gap: var(--mantine-spacing-xs);\n\n @mixin larger-than $mantine-breakpoint-sm {\n gap: var(--mantine-spacing-md);\n }\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ReactElement, ReactNode } from 'react';
|
|
2
|
+
import { DataTableColumn } from 'mantine-datatable';
|
|
3
|
+
import { ListDataSource } from '../../../data/ListDataSource';
|
|
4
|
+
import { Identifiable } from '../../../model/Identifiable';
|
|
5
|
+
import { BreadcrumbItem } from '../../molecule/Breadcrumb/Breadcrumb';
|
|
6
|
+
import { ActionsSettings } from '../../organism/Table/Table';
|
|
7
|
+
interface ListPageProps<T, S> {
|
|
8
|
+
/** Title of the page (e.g. "Regions"). */
|
|
9
|
+
title: string;
|
|
10
|
+
/** Plural name of the records, used in the title of the table card. */
|
|
11
|
+
titlePlural: string;
|
|
12
|
+
breadcrumbItems: BreadcrumbItem[];
|
|
13
|
+
/** Route of the "Add" button; absent for no button. */
|
|
14
|
+
addActionRoute?: string;
|
|
15
|
+
/** Source of the records and of their deletion. */
|
|
16
|
+
service: S;
|
|
17
|
+
tableColumns: DataTableColumn<T>[];
|
|
18
|
+
/** Base path of the pages of the records (e.g. `/region`). */
|
|
19
|
+
resourceBasePath: string;
|
|
20
|
+
actionsSettings?: Partial<ActionsSettings>;
|
|
21
|
+
/** Extra content above the table (e.g. filters). */
|
|
22
|
+
children?: ReactNode;
|
|
23
|
+
customFetchMethod?: () => Promise<T[]>;
|
|
24
|
+
/** Builds the URL opened to view a record. If absent, the default view route is used. */
|
|
25
|
+
getViewUrl?: (item: T) => string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* List page of records: header with the "Add" button, optional extra content (e.g. filters) and the table of the
|
|
29
|
+
* records, with the view, edit and delete actions.
|
|
30
|
+
*/
|
|
31
|
+
declare function ListPage<M extends Identifiable, S extends ListDataSource<M>>(props: ListPageProps<M, S>): ReactElement;
|
|
32
|
+
export default ListPage;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useDocumentTitle, useKitMessages } from "../../../provider/useKit.js";
|
|
3
|
+
import PaperCard from "../../molecule/PaperCard/PaperCard.js";
|
|
4
|
+
import PageHeader from "../../organism/PageHeader/PageHeader.js";
|
|
5
|
+
import Table from "../../organism/Table/Table.js";
|
|
6
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { Group, Stack, Text } from "@mantine/core";
|
|
8
|
+
// src/component/template/ListPage/ListPage.tsx
|
|
9
|
+
/**
|
|
10
|
+
* List page of records: header with the "Add" button, optional extra content (e.g. filters) and the table of the
|
|
11
|
+
* records, with the view, edit and delete actions.
|
|
12
|
+
*/
|
|
13
|
+
function ListPage(props) {
|
|
14
|
+
const { title, titlePlural, breadcrumbItems, addActionRoute, service, tableColumns, resourceBasePath, actionsSettings, children, customFetchMethod, getViewUrl } = props;
|
|
15
|
+
const documentTitle = useDocumentTitle(title);
|
|
16
|
+
const messages = useKitMessages();
|
|
17
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("title", { children: documentTitle }), /* @__PURE__ */ jsxs(Stack, {
|
|
18
|
+
gap: "lg",
|
|
19
|
+
children: [
|
|
20
|
+
/* @__PURE__ */ jsx(PageHeader, {
|
|
21
|
+
title,
|
|
22
|
+
breadcrumbItems,
|
|
23
|
+
addActionRoute
|
|
24
|
+
}),
|
|
25
|
+
children && /* @__PURE__ */ jsx(Stack, { children }),
|
|
26
|
+
/* @__PURE__ */ jsxs(PaperCard, { children: [/* @__PURE__ */ jsx(Group, {
|
|
27
|
+
justify: "space-between",
|
|
28
|
+
mb: "md",
|
|
29
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
30
|
+
fz: "lg",
|
|
31
|
+
fw: 600,
|
|
32
|
+
children: messages.table.listTitle(titlePlural)
|
|
33
|
+
})
|
|
34
|
+
}), /* @__PURE__ */ jsx(Table, {
|
|
35
|
+
service,
|
|
36
|
+
basePath: resourceBasePath,
|
|
37
|
+
columns: tableColumns,
|
|
38
|
+
customFetchMethod,
|
|
39
|
+
actionsSettings,
|
|
40
|
+
getViewUrl
|
|
41
|
+
})] })
|
|
42
|
+
]
|
|
43
|
+
})] });
|
|
44
|
+
}
|
|
45
|
+
export { ListPage as default };
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=ListPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ListPage.js","names":["_Fragment"],"sources":["../../../../src/component/template/ListPage/ListPage.tsx"],"sourcesContent":["import { ReactElement, ReactNode } from 'react';\n\nimport { Group, Stack, Text } from '@mantine/core';\nimport { DataTableColumn } from 'mantine-datatable';\n\nimport { ListDataSource } from '../../../data/ListDataSource';\nimport { Identifiable } from '../../../model/Identifiable';\nimport { useDocumentTitle, useKitMessages } from '../../../provider/useKit';\nimport { BreadcrumbItem } from '../../molecule/Breadcrumb/Breadcrumb';\nimport PaperCard from '../../molecule/PaperCard/PaperCard';\nimport PageHeader from '../../organism/PageHeader/PageHeader';\nimport Table, { ActionsSettings } from '../../organism/Table/Table';\n\ninterface ListPageProps<T, S> {\n /** Title of the page (e.g. \"Regions\"). */\n title: string;\n\n /** Plural name of the records, used in the title of the table card. */\n titlePlural: string;\n breadcrumbItems: BreadcrumbItem[];\n\n /** Route of the \"Add\" button; absent for no button. */\n addActionRoute?: string;\n\n /** Source of the records and of their deletion. */\n service: S;\n tableColumns: DataTableColumn<T>[];\n\n /** Base path of the pages of the records (e.g. `/region`). */\n resourceBasePath: string;\n actionsSettings?: Partial<ActionsSettings>;\n\n /** Extra content above the table (e.g. filters). */\n children?: ReactNode;\n customFetchMethod?: () => Promise<T[]>;\n\n /** Builds the URL opened to view a record. If absent, the default view route is used. */\n getViewUrl?: (item: T) => string;\n}\n\n/**\n * List page of records: header with the \"Add\" button, optional extra content (e.g. filters) and the table of the\n * records, with the view, edit and delete actions.\n */\nfunction ListPage<M extends Identifiable, S extends ListDataSource<M>>(props: ListPageProps<M, S>): ReactElement {\n const {\n title,\n titlePlural,\n breadcrumbItems,\n addActionRoute,\n service,\n tableColumns,\n resourceBasePath,\n actionsSettings,\n children,\n customFetchMethod,\n getViewUrl\n } = props;\n const documentTitle = useDocumentTitle(title);\n const messages = useKitMessages();\n\n return (\n <>\n <title>{documentTitle}</title>\n <Stack gap=\"lg\">\n <PageHeader title={title} breadcrumbItems={breadcrumbItems} addActionRoute={addActionRoute} />\n {children && <Stack>{children}</Stack>}\n <PaperCard>\n <Group justify=\"space-between\" mb=\"md\">\n <Text fz=\"lg\" fw={600}>\n {messages.table.listTitle(titlePlural)}\n </Text>\n </Group>\n <Table<M, S>\n service={service}\n basePath={resourceBasePath}\n columns={tableColumns}\n customFetchMethod={customFetchMethod}\n actionsSettings={actionsSettings}\n getViewUrl={getViewUrl}\n />\n </PaperCard>\n </Stack>\n </>\n );\n}\n\nexport default ListPage;\n"],"mappings":";;;;;;;;;;;;AA4CA,SAAS,SAA8D,OAA0C;CAC7G,MAAM,EACF,OACA,aACA,iBACA,gBACA,SACA,cACA,kBACA,iBACA,UACA,mBACA,eACA;CACJ,MAAM,gBAAgB,iBAAiB,KAAK;CAC5C,MAAM,WAAW,eAAe;CAEhC,OACI,qBAAAA,UAAA,EAAA,UAAA,CACI,oBAAC,SAAD,EAAA,UAAQ,cAAqB,CAAA,GAC7B,qBAAC,OAAD;EAAO,KAAI;EAAX,UAAA;GACI,oBAAC,YAAD;IAAmB;IAAwB;IAAiC;GAAiB,CAAA;GAC5F,YAAY,oBAAC,OAAD,EAAQ,SAAgB,CAAA;GACrC,qBAAC,WAAD,EAAA,UAAA,CACI,oBAAC,OAAD;IAAO,SAAQ;IAAgB,IAAG;IAC9B,UAAA,oBAAC,MAAD;KAAM,IAAG;KAAK,IAAI;KACb,UAAA,SAAS,MAAM,UAAU,WAAW;IACnC,CAAA;GACH,CAAA,GACP,oBAAC,OAAD;IACa;IACT,UAAU;IACV,SAAS;IACU;IACF;IACL;GACf,CAAA,CACM,EAAA,CAAA;EACR;CACT,CAAA,CAAA,EAAA,CAAA;AAEV"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ReactElement, ReactNode } from 'react';
|
|
2
|
+
import type { ExportInfo } from '../../../export/ExportDocument';
|
|
3
|
+
/** Paper orientation: portrait (default) or landscape, for wide tables (e.g. a year per column). */
|
|
4
|
+
export type PrintOrientation = 'portrait' | 'landscape';
|
|
5
|
+
type Props = {
|
|
6
|
+
/** Title of the report, shown in the header. */
|
|
7
|
+
title: string;
|
|
8
|
+
/** Context info shown below the title (e.g. the period and the filters). */
|
|
9
|
+
info?: ExportInfo[];
|
|
10
|
+
orientation?: PrintOrientation;
|
|
11
|
+
/** Name of the system, shown in the footer (e.g. "Data generated by My System"). */
|
|
12
|
+
systemName: string;
|
|
13
|
+
/** Logo shown on the left of the title (e.g. an `<img>` about 48 px high); absent to show none. */
|
|
14
|
+
logo?: ReactNode;
|
|
15
|
+
/** Content of the report: sections ({@link PrintSection}), tables and charts. */
|
|
16
|
+
children: ReactNode;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Common layout of the reports: an HTML page formatted to be printed or saved as PDF with the browser itself.
|
|
20
|
+
* It has the logo, the title, the generation date, the context and, at the end, a footer with the link of the system.
|
|
21
|
+
* The bar with the "Print" button and the tips of the print dialog is shown only on screen. The pagination (paper size,
|
|
22
|
+
* repeated table header, page numbers) comes from the `styles/print.css` of the library.
|
|
23
|
+
*/
|
|
24
|
+
declare function PrintPage({ title, info, orientation, systemName, logo, children }: Props): ReactElement;
|
|
25
|
+
export default PrintPage;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useLightColorSchemeOnPrint } from "../../../hook/useLightColorSchemeOnPrint.js";
|
|
3
|
+
import { useKitMessages } from "../../../provider/useKit.js";
|
|
4
|
+
import { useEffect, useState } from "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { Alert, Anchor, Box, Button, Group, Stack, Text, Title } from "@mantine/core";
|
|
7
|
+
import { IconInfoCircle, IconPrinter } from "@tabler/icons-react";
|
|
8
|
+
// src/component/template/PrintPage/PrintPage.tsx
|
|
9
|
+
/** Size of the icons (px). */
|
|
10
|
+
var ICON_SIZE = 18;
|
|
11
|
+
/**
|
|
12
|
+
* Common layout of the reports: an HTML page formatted to be printed or saved as PDF with the browser itself.
|
|
13
|
+
* It has the logo, the title, the generation date, the context and, at the end, a footer with the link of the system.
|
|
14
|
+
* The bar with the "Print" button and the tips of the print dialog is shown only on screen. The pagination (paper size,
|
|
15
|
+
* repeated table header, page numbers) comes from the `styles/print.css` of the library.
|
|
16
|
+
*/
|
|
17
|
+
function PrintPage({ title, info = [], orientation = "portrait", systemName, logo, children }) {
|
|
18
|
+
useLightColorSchemeOnPrint();
|
|
19
|
+
const messages = useKitMessages();
|
|
20
|
+
const [generatedAt, setGeneratedAt] = useState();
|
|
21
|
+
const [siteUrl, setSiteUrl] = useState("");
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
setGeneratedAt(/* @__PURE__ */ new Date());
|
|
24
|
+
setSiteUrl(window.location.origin);
|
|
25
|
+
}, []);
|
|
26
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
27
|
+
"data-print-orientation": orientation,
|
|
28
|
+
p: {
|
|
29
|
+
base: "xs",
|
|
30
|
+
sm: "md"
|
|
31
|
+
},
|
|
32
|
+
children: [
|
|
33
|
+
/* @__PURE__ */ jsx(PrintToolbar, { messages: messages.print }),
|
|
34
|
+
/* @__PURE__ */ jsxs(Stack, {
|
|
35
|
+
component: "header",
|
|
36
|
+
gap: 4,
|
|
37
|
+
mb: "lg",
|
|
38
|
+
children: [
|
|
39
|
+
/* @__PURE__ */ jsxs(Group, {
|
|
40
|
+
gap: "sm",
|
|
41
|
+
wrap: "nowrap",
|
|
42
|
+
children: [logo, /* @__PURE__ */ jsx(Title, {
|
|
43
|
+
order: 1,
|
|
44
|
+
size: "h2",
|
|
45
|
+
c: "var(--mantine-primary-color-filled)",
|
|
46
|
+
children: title
|
|
47
|
+
})]
|
|
48
|
+
}),
|
|
49
|
+
generatedAt && /* @__PURE__ */ jsx(Text, {
|
|
50
|
+
size: "sm",
|
|
51
|
+
c: "dimmed",
|
|
52
|
+
fs: "italic",
|
|
53
|
+
children: messages.export.generatedAt(generatedAt)
|
|
54
|
+
}),
|
|
55
|
+
info.map((item) => /* @__PURE__ */ jsxs(Text, {
|
|
56
|
+
size: "sm",
|
|
57
|
+
children: [
|
|
58
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
59
|
+
span: true,
|
|
60
|
+
fw: 700,
|
|
61
|
+
c: "dimmed",
|
|
62
|
+
children: [item.label, ":"]
|
|
63
|
+
}),
|
|
64
|
+
" ",
|
|
65
|
+
item.value
|
|
66
|
+
]
|
|
67
|
+
}, item.label))
|
|
68
|
+
]
|
|
69
|
+
}),
|
|
70
|
+
children,
|
|
71
|
+
/* @__PURE__ */ jsxs(Stack, {
|
|
72
|
+
component: "footer",
|
|
73
|
+
gap: 0,
|
|
74
|
+
mt: "xl",
|
|
75
|
+
"data-print-block": true,
|
|
76
|
+
children: [/* @__PURE__ */ jsx(Text, {
|
|
77
|
+
size: "xs",
|
|
78
|
+
c: "dimmed",
|
|
79
|
+
children: messages.export.footer(systemName)
|
|
80
|
+
}), siteUrl && /* @__PURE__ */ jsx(Anchor, {
|
|
81
|
+
href: siteUrl,
|
|
82
|
+
size: "xs",
|
|
83
|
+
children: siteUrl
|
|
84
|
+
})]
|
|
85
|
+
})
|
|
86
|
+
]
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
/** Bar shown only on screen, with the print button and the tips about the options of the print dialog. */
|
|
90
|
+
function PrintToolbar({ messages }) {
|
|
91
|
+
return /* @__PURE__ */ jsxs(Group, {
|
|
92
|
+
"data-print-hidden": true,
|
|
93
|
+
justify: "space-between",
|
|
94
|
+
align: "flex-start",
|
|
95
|
+
mb: "md",
|
|
96
|
+
wrap: "wrap",
|
|
97
|
+
children: [/* @__PURE__ */ jsx(Alert, {
|
|
98
|
+
variant: "light",
|
|
99
|
+
icon: /* @__PURE__ */ jsx(IconInfoCircle, { size: ICON_SIZE }),
|
|
100
|
+
title: messages.pdfTipTitle,
|
|
101
|
+
style: {
|
|
102
|
+
flex: 1,
|
|
103
|
+
minWidth: 280
|
|
104
|
+
},
|
|
105
|
+
children: messages.pdfTip
|
|
106
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
107
|
+
leftSection: /* @__PURE__ */ jsx(IconPrinter, { size: ICON_SIZE }),
|
|
108
|
+
onClick: () => window.print(),
|
|
109
|
+
children: messages.printButton
|
|
110
|
+
})]
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
export { PrintPage as default };
|
|
114
|
+
|
|
115
|
+
//# sourceMappingURL=PrintPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PrintPage.js","names":[],"sources":["../../../../src/component/template/PrintPage/PrintPage.tsx"],"sourcesContent":["'use client';\n\nimport { ReactElement, ReactNode, useEffect, useState } from 'react';\n\nimport { Alert, Anchor, Box, Button, Group, Stack, Text, Title } from '@mantine/core';\nimport { IconInfoCircle, IconPrinter } from '@tabler/icons-react';\n\nimport type { ExportInfo } from '../../../export/ExportDocument';\nimport { useLightColorSchemeOnPrint } from '../../../hook/useLightColorSchemeOnPrint';\nimport { PrintMessages } from '../../../i18n/KitMessages';\nimport { useKitMessages } from '../../../provider/useKit';\n\n/** Size of the icons (px). */\nconst ICON_SIZE = 18;\n\n/** Paper orientation: portrait (default) or landscape, for wide tables (e.g. a year per column). */\nexport type PrintOrientation = 'portrait' | 'landscape';\n\ntype Props = {\n /** Title of the report, shown in the header. */\n title: string;\n\n /** Context info shown below the title (e.g. the period and the filters). */\n info?: ExportInfo[];\n\n orientation?: PrintOrientation;\n\n /** Name of the system, shown in the footer (e.g. \"Data generated by My System\"). */\n systemName: string;\n\n /** Logo shown on the left of the title (e.g. an `<img>` about 48 px high); absent to show none. */\n logo?: ReactNode;\n\n /** Content of the report: sections ({@link PrintSection}), tables and charts. */\n children: ReactNode;\n};\n\n/**\n * Common layout of the reports: an HTML page formatted to be printed or saved as PDF with the browser itself.\n * It has the logo, the title, the generation date, the context and, at the end, a footer with the link of the system.\n * The bar with the \"Print\" button and the tips of the print dialog is shown only on screen. The pagination (paper size,\n * repeated table header, page numbers) comes from the `styles/print.css` of the library.\n */\nfunction PrintPage({ title, info = [], orientation = 'portrait', systemName, logo, children }: Props): ReactElement {\n useLightColorSchemeOnPrint();\n const messages = useKitMessages();\n\n /* The generation date and the address of the system are read only in the browser, after mounting: on the server,\n the date would be another one and there is no `window`, so the HTML would differ from the one of the browser\n (hydration error). */\n const [generatedAt, setGeneratedAt] = useState<Date>();\n const [siteUrl, setSiteUrl] = useState('');\n useEffect(() => {\n setGeneratedAt(new Date());\n setSiteUrl(window.location.origin);\n }, []);\n\n return (\n <Box data-print-orientation={orientation} p={{ base: 'xs', sm: 'md' }}>\n <PrintToolbar messages={messages.print} />\n\n <Stack component=\"header\" gap={4} mb=\"lg\">\n <Group gap=\"sm\" wrap=\"nowrap\">\n {logo}\n <Title order={1} size=\"h2\" c=\"var(--mantine-primary-color-filled)\">\n {title}\n </Title>\n </Group>\n {generatedAt && (\n <Text size=\"sm\" c=\"dimmed\" fs=\"italic\">\n {messages.export.generatedAt(generatedAt)}\n </Text>\n )}\n {info.map(item => (\n <Text key={item.label} size=\"sm\">\n <Text span fw={700} c=\"dimmed\">\n {item.label}:\n </Text>{' '}\n {item.value}\n </Text>\n ))}\n </Stack>\n\n {children}\n\n <Stack component=\"footer\" gap={0} mt=\"xl\" data-print-block>\n <Text size=\"xs\" c=\"dimmed\">\n {messages.export.footer(systemName)}\n </Text>\n {siteUrl && (\n <Anchor href={siteUrl} size=\"xs\">\n {siteUrl}\n </Anchor>\n )}\n </Stack>\n </Box>\n );\n}\n\n/** Bar shown only on screen, with the print button and the tips about the options of the print dialog. */\nfunction PrintToolbar({ messages }: { messages: PrintMessages }): ReactElement {\n return (\n <Group data-print-hidden justify=\"space-between\" align=\"flex-start\" mb=\"md\" wrap=\"wrap\">\n <Alert\n variant=\"light\"\n icon={<IconInfoCircle size={ICON_SIZE} />}\n title={messages.pdfTipTitle}\n style={{ flex: 1, minWidth: 280 }}\n >\n {messages.pdfTip}\n </Alert>\n <Button leftSection={<IconPrinter size={ICON_SIZE} />} onClick={() => window.print()}>\n {messages.printButton}\n </Button>\n </Group>\n );\n}\n\nexport default PrintPage;\n"],"mappings":";;;;;;;;;AAaA,IAAM,YAAY;;;;;;;AA8BlB,SAAS,UAAU,EAAE,OAAO,OAAO,CAAC,GAAG,cAAc,YAAY,YAAY,MAAM,YAAiC;CAChH,2BAA2B;CAC3B,MAAM,WAAW,eAAe;CAKhC,MAAM,CAAC,aAAa,kBAAkB,SAAe;CACrD,MAAM,CAAC,SAAS,cAAc,SAAS,EAAE;CACzC,gBAAgB;EACZ,+BAAe,IAAI,KAAK,CAAC;EACzB,WAAW,OAAO,SAAS,MAAM;CACrC,GAAG,CAAC,CAAC;CAEL,OACI,qBAAC,KAAD;EAAK,0BAAwB;EAAa,GAAG;GAAE,MAAM;GAAM,IAAI;EAAK;EAApE,UAAA;GACI,oBAAC,cAAD,EAAc,UAAU,SAAS,MAAQ,CAAA;GAEzC,qBAAC,OAAD;IAAO,WAAU;IAAS,KAAK;IAAG,IAAG;IAArC,UAAA;KACI,qBAAC,OAAD;MAAO,KAAI;MAAK,MAAK;MAArB,UAAA,CACK,MACD,oBAAC,OAAD;OAAO,OAAO;OAAG,MAAK;OAAK,GAAE;OACxB,UAAA;MACE,CAAA,CACJ;;KACN,eACG,oBAAC,MAAD;MAAM,MAAK;MAAK,GAAE;MAAS,IAAG;MACzB,UAAA,SAAS,OAAO,YAAY,WAAW;KACtC,CAAA;KAET,KAAK,KAAI,SACN,qBAAC,MAAD;MAAuB,MAAK;MAA5B,UAAA;OACI,qBAAC,MAAD;QAAM,MAAA;QAAK,IAAI;QAAK,GAAE;QAAtB,UAAA,CACK,KAAK,OAAM,GACV;;OAAE;OACP,KAAK;MACJ;KALK,GAAA,KAAK,KAKV,CACT;IACE;;GAEN;GAED,qBAAC,OAAD;IAAO,WAAU;IAAS,KAAK;IAAG,IAAG;IAAK,oBAAA;IAA1C,UAAA,CACI,oBAAC,MAAD;KAAM,MAAK;KAAK,GAAE;KACb,UAAA,SAAS,OAAO,OAAO,UAAU;IAChC,CAAA,GACL,WACG,oBAAC,QAAD;KAAQ,MAAM;KAAS,MAAK;KACvB,UAAA;IACG,CAAA,CAET;;EACN;;AAEb;;AAGA,SAAS,aAAa,EAAE,YAAuD;CAC3E,OACI,qBAAC,OAAD;EAAO,qBAAA;EAAkB,SAAQ;EAAgB,OAAM;EAAa,IAAG;EAAK,MAAK;EAAjF,UAAA,CACI,oBAAC,OAAD;GACI,SAAQ;GACR,MAAM,oBAAC,gBAAD,EAAgB,MAAM,UAAY,CAAA;GACxC,OAAO,SAAS;GAChB,OAAO;IAAE,MAAM;IAAG,UAAU;GAAI;GAE/B,UAAA,SAAS;EACP,CAAA,GACP,oBAAC,QAAD;GAAQ,aAAa,oBAAC,aAAD,EAAa,MAAM,UAAY,CAAA;GAAG,eAAe,OAAO,MAAM;GAC9E,UAAA,SAAS;EACN,CAAA,CACL;;AAEf"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React, { ReactElement } from 'react';
|
|
2
|
+
import { BreadcrumbItem } from '../../molecule/Breadcrumb/Breadcrumb';
|
|
3
|
+
interface ViewPageProps {
|
|
4
|
+
/** Name of the record (e.g. "Region"). */
|
|
5
|
+
title: string;
|
|
6
|
+
breadcrumbItems: BreadcrumbItem[];
|
|
7
|
+
backRoute: string;
|
|
8
|
+
}
|
|
9
|
+
/** Page that shows a record, with the given content and the back button. */
|
|
10
|
+
declare function ViewPage(props: React.PropsWithChildren<ViewPageProps>): ReactElement;
|
|
11
|
+
export default ViewPage;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useDocumentTitle, useKitConfig } from "../../../provider/useKit.js";
|
|
3
|
+
import PaperCard from "../../molecule/PaperCard/PaperCard.js";
|
|
4
|
+
import PageHeader from "../../organism/PageHeader/PageHeader.js";
|
|
5
|
+
import "react";
|
|
6
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { Box, Button, Grid, Stack, Text } from "@mantine/core";
|
|
8
|
+
import { IconArrowBack } from "@tabler/icons-react";
|
|
9
|
+
// src/component/template/ViewPage/ViewPage.tsx
|
|
10
|
+
/** Page that shows a record, with the given content and the back button. */
|
|
11
|
+
function ViewPage(props) {
|
|
12
|
+
const { title, breadcrumbItems, backRoute, children } = props;
|
|
13
|
+
const { router, messages } = useKitConfig();
|
|
14
|
+
const { Link } = router;
|
|
15
|
+
const pageTitle = `${messages.form.action.view} ${title}`;
|
|
16
|
+
const documentTitle = useDocumentTitle(pageTitle);
|
|
17
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("title", { children: documentTitle }), /* @__PURE__ */ jsxs(Stack, {
|
|
18
|
+
gap: "lg",
|
|
19
|
+
children: [/* @__PURE__ */ jsx(PageHeader, {
|
|
20
|
+
title: pageTitle,
|
|
21
|
+
breadcrumbItems: [...breadcrumbItems, {
|
|
22
|
+
title: pageTitle,
|
|
23
|
+
href: "#"
|
|
24
|
+
}]
|
|
25
|
+
}), /* @__PURE__ */ jsx(Grid, { children: /* @__PURE__ */ jsx(Grid.Col, {
|
|
26
|
+
span: {
|
|
27
|
+
base: 12,
|
|
28
|
+
lg: 12
|
|
29
|
+
},
|
|
30
|
+
children: /* @__PURE__ */ jsx(PaperCard, { children: /* @__PURE__ */ jsxs(Stack, { children: [
|
|
31
|
+
/* @__PURE__ */ jsx(Text, {
|
|
32
|
+
size: "lg",
|
|
33
|
+
fw: 600,
|
|
34
|
+
children: pageTitle
|
|
35
|
+
}),
|
|
36
|
+
children,
|
|
37
|
+
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Button, {
|
|
38
|
+
leftSection: /* @__PURE__ */ jsx(IconArrowBack, { size: 16 }),
|
|
39
|
+
component: Link,
|
|
40
|
+
href: backRoute,
|
|
41
|
+
children: messages.common.back
|
|
42
|
+
}) })
|
|
43
|
+
] }) })
|
|
44
|
+
}) })]
|
|
45
|
+
})] });
|
|
46
|
+
}
|
|
47
|
+
export { ViewPage as default };
|
|
48
|
+
|
|
49
|
+
//# sourceMappingURL=ViewPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ViewPage.js","names":["_Fragment"],"sources":["../../../../src/component/template/ViewPage/ViewPage.tsx"],"sourcesContent":["import React, { ReactElement } from 'react';\n\nimport { Box, Button, Grid, Stack, Text } from '@mantine/core';\nimport { IconArrowBack } from '@tabler/icons-react';\n\nimport { useDocumentTitle, useKitConfig } from '../../../provider/useKit';\nimport { BreadcrumbItem } from '../../molecule/Breadcrumb/Breadcrumb';\nimport PaperCard from '../../molecule/PaperCard/PaperCard';\nimport PageHeader from '../../organism/PageHeader/PageHeader';\n\ninterface ViewPageProps {\n /** Name of the record (e.g. \"Region\"). */\n title: string;\n breadcrumbItems: BreadcrumbItem[];\n backRoute: string;\n}\n\n/** Page that shows a record, with the given content and the back button. */\nfunction ViewPage(props: React.PropsWithChildren<ViewPageProps>): ReactElement {\n const { title, breadcrumbItems, backRoute, children } = props;\n const { router, messages } = useKitConfig();\n const { Link } = router;\n const pageTitle = `${messages.form.action.view} ${title}`;\n const documentTitle = useDocumentTitle(pageTitle);\n\n return (\n <>\n <title>{documentTitle}</title>\n <Stack gap=\"lg\">\n <PageHeader title={pageTitle} breadcrumbItems={[...breadcrumbItems, { title: pageTitle, href: '#' }]} />\n <Grid>\n <Grid.Col span={{ base: 12, lg: 12 }}>\n <PaperCard>\n <Stack>\n <Text size=\"lg\" fw={600}>\n {pageTitle}\n </Text>\n\n {children}\n\n <Box>\n <Button leftSection={<IconArrowBack size={16} />} component={Link} href={backRoute}>\n {messages.common.back}\n </Button>\n </Box>\n </Stack>\n </PaperCard>\n </Grid.Col>\n </Grid>\n </Stack>\n </>\n );\n}\n\nexport default ViewPage;\n"],"mappings":";;;;;;;;;;AAkBA,SAAS,SAAS,OAA6D;CAC3E,MAAM,EAAE,OAAO,iBAAiB,WAAW,aAAa;CACxD,MAAM,EAAE,QAAQ,aAAa,aAAa;CAC1C,MAAM,EAAE,SAAS;CACjB,MAAM,YAAY,GAAG,SAAS,KAAK,OAAO,KAAK,GAAG;CAClD,MAAM,gBAAgB,iBAAiB,SAAS;CAEhD,OACI,qBAAAA,UAAA,EAAA,UAAA,CACI,oBAAC,SAAD,EAAA,UAAQ,cAAqB,CAAA,GAC7B,qBAAC,OAAD;EAAO,KAAI;EAAX,UAAA,CACI,oBAAC,YAAD;GAAY,OAAO;GAAW,iBAAiB,CAAC,GAAG,iBAAiB;IAAE,OAAO;IAAW,MAAM;GAAI,CAAC;EAAI,CAAA,GACvG,oBAAC,MAAD,EAAA,UACI,oBAAC,KAAK,KAAN;GAAU,MAAM;IAAE,MAAM;IAAI,IAAI;GAAG;GAC/B,UAAA,oBAAC,WAAD,EAAA,UACI,qBAAC,OAAD,EAAA,UAAA;IACI,oBAAC,MAAD;KAAM,MAAK;KAAK,IAAI;KACf,UAAA;IACC,CAAA;IAEL;IAED,oBAAC,KAAD,EAAA,UACI,oBAAC,QAAD;KAAQ,aAAa,oBAAC,eAAD,EAAe,MAAM,GAAK,CAAA;KAAG,WAAW;KAAM,MAAM;KACpE,UAAA,SAAS,OAAO;IACb,CAAA,EACP,CAAA;GACF,EAAA,CAAA,EACA,CAAA;EACL,CAAA,EACR,CAAA,CACH;CACT,CAAA,CAAA,EAAA,CAAA;AAEV"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Identifiable } from '../model/Identifiable';
|
|
2
|
+
/**
|
|
3
|
+
* Source of the records of a table that allows deleting them (e.g. a service that accesses a REST API). Any object
|
|
4
|
+
* with these methods works, without extending a class.
|
|
5
|
+
* @template M type of the records
|
|
6
|
+
*/
|
|
7
|
+
export interface ListDataSource<M extends Identifiable> {
|
|
8
|
+
/** Fetches all records shown in the table. */
|
|
9
|
+
findAll(): Promise<M[]>;
|
|
10
|
+
/** Deletes the record with the given id. */
|
|
11
|
+
delete(id: number | string): Promise<void>;
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Identifiable } from '../model/Identifiable';
|
|
2
|
+
/**
|
|
3
|
+
* Destination of the data of a form: creates a record (without an id) or updates an existing one (with an id). Any
|
|
4
|
+
* object with this method works, without extending a class.
|
|
5
|
+
* @template M type of the saved record, returned by the destination
|
|
6
|
+
* @template D type of the data sent by the form (e.g. a DTO, or M itself)
|
|
7
|
+
*/
|
|
8
|
+
export interface SaveDataSource<M extends Identifiable, D> {
|
|
9
|
+
/**
|
|
10
|
+
* Creates or updates a record.
|
|
11
|
+
* @param id id of the record to update; if absent, the record is created
|
|
12
|
+
* @param data data to save
|
|
13
|
+
* @return the saved record
|
|
14
|
+
*/
|
|
15
|
+
save(id: M['id'] | string | undefined, data: D): Promise<M>;
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ClassifiedCell, NumberFormat } from './ExportDocument';
|
|
2
|
+
/**
|
|
3
|
+
* Formats a number as a spreadsheet in the language of the locale shows it (e.g. a decimal comma in `pt-BR`).
|
|
4
|
+
* @param value number; a percentage is in the 0..1 scale
|
|
5
|
+
* @param format decimal places and whether the value is a percentage
|
|
6
|
+
* @param grouping whether the thousands separator is used (e.g. "1.234,56" in `pt-BR`); `false` gives "1234,56"
|
|
7
|
+
* @param locale locale of the format; defaults to `en-US`
|
|
8
|
+
* @return the formatted number, with "%" at the end if it is a percentage
|
|
9
|
+
*/
|
|
10
|
+
export declare function formatNumber(value: number, format: NumberFormat, grouping?: boolean, locale?: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Returns the text of a cell, as the user sees it.
|
|
13
|
+
* @param cell cell already classified
|
|
14
|
+
* @param grouping whether the numbers use the thousands separator
|
|
15
|
+
* @param locale locale of the number format; defaults to `en-US`
|
|
16
|
+
* @return the text of the cell; empty for an absent value
|
|
17
|
+
*/
|
|
18
|
+
export declare function cellText(cell: ClassifiedCell, grouping?: boolean, locale?: string): string;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { DEFAULT_LOCALE } from "../i18n/KitLocale.js";
|
|
3
|
+
// src/export/ExportCellText.ts
|
|
4
|
+
/** Multiplier that converts a percentage from the 0..1 scale to the 0..100 display scale. */
|
|
5
|
+
var PERCENT_SCALE = 100;
|
|
6
|
+
/**
|
|
7
|
+
* Formatters already created, by locale and format. Creating an `Intl.NumberFormat` is expensive, and the export
|
|
8
|
+
* formats every cell (e.g. to measure the column widths), but there are few combinations of locale, decimal places and
|
|
9
|
+
* thousands separator.
|
|
10
|
+
*/
|
|
11
|
+
var formatters = /* @__PURE__ */ new Map();
|
|
12
|
+
/**
|
|
13
|
+
* Returns the number formatter of a locale for the given decimal places and thousands separator.
|
|
14
|
+
* @param locale locale of the format
|
|
15
|
+
* @param decimals decimal places
|
|
16
|
+
* @param grouping whether the thousands separator is used
|
|
17
|
+
* @return the formatter, created only the first time
|
|
18
|
+
*/
|
|
19
|
+
function numberFormatter(locale, decimals, grouping) {
|
|
20
|
+
const key = `${locale}:${decimals}:${grouping}`;
|
|
21
|
+
let formatter = formatters.get(key);
|
|
22
|
+
if (!formatter) {
|
|
23
|
+
formatter = new Intl.NumberFormat(locale, {
|
|
24
|
+
minimumFractionDigits: decimals,
|
|
25
|
+
maximumFractionDigits: decimals,
|
|
26
|
+
useGrouping: grouping
|
|
27
|
+
});
|
|
28
|
+
formatters.set(key, formatter);
|
|
29
|
+
}
|
|
30
|
+
return formatter;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Formats a number as a spreadsheet in the language of the locale shows it (e.g. a decimal comma in `pt-BR`).
|
|
34
|
+
* @param value number; a percentage is in the 0..1 scale
|
|
35
|
+
* @param format decimal places and whether the value is a percentage
|
|
36
|
+
* @param grouping whether the thousands separator is used (e.g. "1.234,56" in `pt-BR`); `false` gives "1234,56"
|
|
37
|
+
* @param locale locale of the format; defaults to `en-US`
|
|
38
|
+
* @return the formatted number, with "%" at the end if it is a percentage
|
|
39
|
+
*/
|
|
40
|
+
function formatNumber(value, format, grouping = true, locale = DEFAULT_LOCALE) {
|
|
41
|
+
const formatter = numberFormatter(locale, format.decimals, grouping);
|
|
42
|
+
return format.percent ? `${formatter.format(value * PERCENT_SCALE)}%` : formatter.format(value);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Returns the text of a cell, as the user sees it.
|
|
46
|
+
* @param cell cell already classified
|
|
47
|
+
* @param grouping whether the numbers use the thousands separator
|
|
48
|
+
* @param locale locale of the number format; defaults to `en-US`
|
|
49
|
+
* @return the text of the cell; empty for an absent value
|
|
50
|
+
*/
|
|
51
|
+
function cellText(cell, grouping = true, locale = DEFAULT_LOCALE) {
|
|
52
|
+
switch (cell.kind) {
|
|
53
|
+
case "empty": return "";
|
|
54
|
+
case "number": return formatNumber(cell.value, cell.format, grouping, locale);
|
|
55
|
+
default: return cell.text;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export { cellText, formatNumber };
|
|
59
|
+
|
|
60
|
+
//# sourceMappingURL=ExportCellText.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExportCellText.js","names":[],"sources":["../../src/export/ExportCellText.ts"],"sourcesContent":["import { DEFAULT_LOCALE } from '../i18n/KitLocale';\nimport { ClassifiedCell, NumberFormat } from './ExportDocument';\n\n/** Multiplier that converts a percentage from the 0..1 scale to the 0..100 display scale. */\nconst PERCENT_SCALE = 100;\n\n/**\n * Formatters already created, by locale and format. Creating an `Intl.NumberFormat` is expensive, and the export\n * formats every cell (e.g. to measure the column widths), but there are few combinations of locale, decimal places and\n * thousands separator.\n */\nconst formatters = new Map<string, Intl.NumberFormat>();\n\n/**\n * Returns the number formatter of a locale for the given decimal places and thousands separator.\n * @param locale locale of the format\n * @param decimals decimal places\n * @param grouping whether the thousands separator is used\n * @return the formatter, created only the first time\n */\nfunction numberFormatter(locale: string, decimals: number, grouping: boolean): Intl.NumberFormat {\n const key = `${locale}:${decimals}:${grouping}`;\n let formatter = formatters.get(key);\n if (!formatter) {\n formatter = new Intl.NumberFormat(locale, {\n minimumFractionDigits: decimals,\n maximumFractionDigits: decimals,\n useGrouping: grouping\n });\n formatters.set(key, formatter);\n }\n\n return formatter;\n}\n\n/**\n * Formats a number as a spreadsheet in the language of the locale shows it (e.g. a decimal comma in `pt-BR`).\n * @param value number; a percentage is in the 0..1 scale\n * @param format decimal places and whether the value is a percentage\n * @param grouping whether the thousands separator is used (e.g. \"1.234,56\" in `pt-BR`); `false` gives \"1234,56\"\n * @param locale locale of the format; defaults to `en-US`\n * @return the formatted number, with \"%\" at the end if it is a percentage\n */\nexport function formatNumber(\n value: number,\n format: NumberFormat,\n grouping: boolean = true,\n locale: string = DEFAULT_LOCALE\n): string {\n const formatter = numberFormatter(locale, format.decimals, grouping);\n\n return format.percent ? `${formatter.format(value * PERCENT_SCALE)}%` : formatter.format(value);\n}\n\n/**\n * Returns the text of a cell, as the user sees it.\n * @param cell cell already classified\n * @param grouping whether the numbers use the thousands separator\n * @param locale locale of the number format; defaults to `en-US`\n * @return the text of the cell; empty for an absent value\n */\nexport function cellText(cell: ClassifiedCell, grouping: boolean = true, locale: string = DEFAULT_LOCALE): string {\n switch (cell.kind) {\n case 'empty':\n return '';\n case 'number':\n return formatNumber(cell.value, cell.format, grouping, locale);\n default:\n return cell.text;\n }\n}\n"],"mappings":";;;;AAIA,IAAM,gBAAgB;;;;;;AAOtB,IAAM,6BAAa,IAAI,IAA+B;;;;;;;;AAStD,SAAS,gBAAgB,QAAgB,UAAkB,UAAsC;CAC7F,MAAM,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG;CACrC,IAAI,YAAY,WAAW,IAAI,GAAG;CAClC,IAAI,CAAC,WAAW;EACZ,YAAY,IAAI,KAAK,aAAa,QAAQ;GACtC,uBAAuB;GACvB,uBAAuB;GACvB,aAAa;EACjB,CAAC;EACD,WAAW,IAAI,KAAK,SAAS;CACjC;CAEA,OAAO;AACX;;;;;;;;;AAUA,SAAgB,aACZ,OACA,QACA,WAAoB,MACpB,SAAiB,gBACX;CACN,MAAM,YAAY,gBAAgB,QAAQ,OAAO,UAAU,QAAQ;CAEnE,OAAO,OAAO,UAAU,GAAG,UAAU,OAAO,QAAQ,aAAa,EAAE,KAAK,UAAU,OAAO,KAAK;AAClG;;;;;;;;AASA,SAAgB,SAAS,MAAsB,WAAoB,MAAM,SAAiB,gBAAwB;CAC9G,QAAQ,KAAK,MAAb;EACI,KAAK,SACD,OAAO;EACX,KAAK,UACD,OAAO,aAAa,KAAK,OAAO,KAAK,QAAQ,UAAU,MAAM;EACjE,SACI,OAAO,KAAK;CACpB;AACJ"}
|