mgv-backoffice 1.19.0 → 1.21.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/README.md CHANGED
@@ -414,29 +414,43 @@ import { ColoredSquares, ColorsEnums } from 'mgv-backoffice'
414
414
 
415
415
  ### EarningsCard
416
416
 
417
- Earnings summary card with formatted currency display.
417
+ Earnings summary card with formatted currency display. Supports a signed P&L
418
+ mode that renders a red loss theme (and a downward trend glyph) for negative
419
+ amounts.
418
420
 
419
421
  **Props:**
420
422
 
421
423
  | Prop | Type | Default | Description |
422
424
  | ---------- | -------- |-------------------------|----------------------|
423
425
  | `title` | `String` | `'TOTAL EARNINGS'` | Card heading |
424
- | `amount` | `Number` | `0` | Monetary value |
426
+ | `amount` | `Number` | `0` | Monetary value (a stringified number is coerced) |
425
427
  | `subtitle` | `String` | `'Lifetime commission'` | Subheading text |
426
428
  | `badge` | `String` | `''` | Optional badge label |
427
429
  | `currency` | `String` | `'$'` | Currency symbol |
428
430
  | `decimals` | `Number` | `2` | Fraction digits shown for the amount |
431
+ | `accent` | `'orange' \| 'emerald' \| 'red'` | `'orange'` | Card theme. `emerald` tints it green; `red` is the loss theme. |
432
+ | `signed` | `Boolean` | `false` | Treat `amount` as a signed P&L figure: a negative value automatically switches to the `red` loss theme and flips the trend glyph to point **down**; a non-negative value keeps the chosen `accent` and the upward glyph. |
429
433
 
430
434
  **Example:**
431
435
 
432
436
  ```vue
433
437
  <template>
438
+ <!-- Always-positive total: original behaviour. -->
434
439
  <EarningsCard
435
440
  title="Monthly Revenue"
436
441
  :amount="12500"
437
442
  subtitle="April 2026"
438
443
  currency="€"
439
444
  />
445
+
446
+ <!-- Signed P&L: renders red + a down arrow when the amount is negative. -->
447
+ <EarningsCard
448
+ title="TOTAL P&L"
449
+ :amount="-128.4"
450
+ subtitle="Realised + unrealised"
451
+ accent="emerald"
452
+ signed
453
+ />
440
454
  </template>
441
455
 
442
456
  <script setup lang="ts">
@@ -707,6 +721,8 @@ computePnL({ buyPrice: 100, lastPrice: 110, filledQty: 5 })
707
721
  ### BaseAppLayout
708
722
 
709
723
  Root layout: dark/light page background, skip link, `<main>`-with-inert wrapper.
724
+ The `<main>` content offset tracks the sidebar width automatically —
725
+ `lg:ml-60` when expanded, `lg:ml-16` when collapsed (via `useSidebarCollapse()`).
710
726
 
711
727
  **Props:**
712
728
 
@@ -727,8 +743,9 @@ Root layout: dark/light page background, skip link, `<main>`-with-inert wrapper.
727
743
  ### BaseSidebar
728
744
 
729
745
  Responsive sidebar with desktop fixed-positioning and mobile off-canvas
730
- behavior, focus management, optional theme toggle, and configurable nav
731
- sections.
746
+ behavior, focus management, optional theme toggle, a desktop collapse
747
+ toggle (icon-only rail), an optional notifications bell, and configurable
748
+ nav sections.
732
749
 
733
750
  **Props:**
734
751
 
@@ -739,6 +756,18 @@ sections.
739
756
  | `appName` | `String` | `''` | Optional app name in the footer. |
740
757
  | `version` | `String` | `''` | Optional version string in the footer. |
741
758
  | `showThemeToggle` | `Boolean` | `true` | Toggle the dark/light switch in the footer. |
759
+ | `collapsible` | `Boolean` | `true` | Show the desktop collapse toggle that shrinks the sidebar to an icon-only rail. |
760
+ | `showNotifications` | `Boolean` | `false` | Show the notifications bell (with unread badge) that toggles `BaseNotificationPanel`. |
761
+
762
+ > **Collapse state** is shared via `useSidebarCollapse()` (and persisted to
763
+ > localStorage) so `BaseAppLayout` can shrink the content offset from
764
+ > `lg:ml-60` to `lg:ml-16` in step with the rail. Collapsing only affects
765
+ > desktop (`lg+`); on mobile the sidebar stays a full off-canvas panel.
766
+
767
+ > **Notifications:** set `:show-notifications="true"` to render the bell,
768
+ > then drop a [`BaseNotificationPanel`](#basenotificationpanel) in your app.
769
+ > Both share state through `useNotifications()`, so the unread badge and the
770
+ > panel stay in sync.
742
771
 
743
772
  **Slots:**
744
773
 
@@ -776,6 +805,127 @@ interface NavSection {
776
805
 
777
806
  ---
778
807
 
808
+ ### BaseNotificationPanel
809
+
810
+ Left-anchored notification drawer (teleported to `<body>`, slides in from
811
+ the left, backdrop + Escape to close). Open/close state and the list live
812
+ in `useNotifications()`, so the sidebar bell and the panel stay in sync.
813
+
814
+ Enable the bell on the sidebar with `:show-notifications="true"`, drop one
815
+ `<BaseNotificationPanel />` anywhere in your app, and feed it data via the
816
+ composable.
817
+
818
+ **Props:**
819
+
820
+ | Prop | Type | Default | Description |
821
+ | ----------------- | --------- | ------------------------------ | ----------- |
822
+ | `title` | `String` | `'Notifications'` | Panel heading. |
823
+ | `emptyText` | `String` | `'You have no notifications.'` | Shown when the list is empty. |
824
+ | `showMarkAllRead` | `Boolean` | `true` | Render the "Mark all as read" action when there are unread items. |
825
+
826
+ **Emits:** `select` (the clicked notification's `id`; the row is also marked read).
827
+
828
+ ```vue
829
+ <script setup lang="ts">
830
+ import { BaseNotificationPanel, useNotifications } from 'mgv-backoffice'
831
+ const { setNotifications } = useNotifications()
832
+ setNotifications([
833
+ { id: 1, title: 'New comment', message: 'Alice replied to your post', time: '2m ago', type: 'info' },
834
+ { id: 2, title: 'Build passed', time: '1h ago', read: true, type: 'success' },
835
+ ])
836
+ </script>
837
+
838
+ <template>
839
+ <BaseSidebar :sections="navSections" :show-notifications="true" />
840
+ <BaseNotificationPanel @select="(id) => goTo(id)" />
841
+ </template>
842
+ ```
843
+
844
+ ```ts
845
+ import type { NotificationItem } from 'mgv-backoffice'
846
+
847
+ interface NotificationItem {
848
+ id: string | number
849
+ title: string
850
+ message?: string
851
+ time?: string // pre-formatted by you
852
+ read?: boolean
853
+ type?: 'info' | 'success' | 'warning' | 'error' // status dot colour
854
+ }
855
+ ```
856
+
857
+ ---
858
+
859
+ ## Authentication
860
+
861
+ ### BaseGoogleSignInButton
862
+
863
+ Google-branded "Sign in with Google" button (official multi-colour "G",
864
+ dark-mode surface swap). Purely presentational — it runs no OAuth itself;
865
+ listen on `click` and start your own Google Identity / Firebase / backend
866
+ flow there.
867
+
868
+ **Props:**
869
+
870
+ | Prop | Type | Default | Description |
871
+ | ---------- | --------- | -------------------------- | ----------- |
872
+ | `label` | `String` | `'Sign in with Google'` | Button text. |
873
+ | `loading` | `Boolean` | `false` | Disables and shows a spinner. |
874
+ | `disabled` | `Boolean` | `false` | Disables without the spinner. |
875
+ | `block` | `Boolean` | `true` | Full-width layout. |
876
+
877
+ **Emits:** `click` (only when not disabled/loading).
878
+
879
+ ### BaseLoginForm
880
+
881
+ Presentational sign-in card: email + password (with show/hide), an optional
882
+ "Remember me" checkbox, an error banner, the Google button + "or" divider,
883
+ and `logo` / `forgot` / `footer` slots. Owns its input state and emits
884
+ `submit` / `google-sign-in`; the app handles the actual request and feeds
885
+ back `loading` / `error`.
886
+
887
+ **Props:**
888
+
889
+ | Prop | Type | Default | Description |
890
+ | --------------- | --------- | ----------- | ----------- |
891
+ | `title` | `String` | `'Sign in'` | Card heading. |
892
+ | `subtitle` | `String` | `''` | Muted line under the heading. |
893
+ | `submitLabel` | `String` | `'Sign in'` | Submit button text. |
894
+ | `loading` | `Boolean` | `false` | Disables the form, spinner on submit. |
895
+ | `googleLoading` | `Boolean` | `false` | Disables the form, spinner on the Google button. |
896
+ | `error` | `String` | `''` | Error banner above the form. |
897
+ | `showGoogle` | `Boolean` | `true` | Render the Google button + divider. |
898
+ | `showRemember` | `Boolean` | `false` | Render the "Remember me" checkbox. |
899
+
900
+ **Emits:** `submit` (`LoginCredentials`), `google-sign-in`.
901
+
902
+ **Slots:** `logo`, `forgot` (next to the password label), `footer`.
903
+
904
+ ```vue
905
+ <script setup lang="ts">
906
+ import { BaseLoginForm } from 'mgv-backoffice'
907
+ import type { LoginCredentials } from 'mgv-backoffice'
908
+
909
+ async function onSubmit(creds: LoginCredentials) { /* call your API */ }
910
+ function onGoogle() { /* start Google OAuth */ }
911
+ </script>
912
+
913
+ <template>
914
+ <BaseLoginForm
915
+ subtitle="Welcome back"
916
+ :show-remember="true"
917
+ @submit="onSubmit"
918
+ @google-sign-in="onGoogle"
919
+ >
920
+ <template #logo><MyLogo /></template>
921
+ <template #forgot><a href="/forgot" class="text-sm text-emerald-600">Forgot?</a></template>
922
+ <template #footer>No account? <a href="/signup" class="text-emerald-600">Sign up</a></template>
923
+ </BaseLoginForm>
924
+ </template>
925
+ ```
926
+
927
+ ---
928
+
779
929
  ## Modals & sections
780
930
 
781
931
  ### BaseModalShell
@@ -1025,6 +1175,8 @@ import {
1025
1175
  useDebouncedRef,
1026
1176
  useToast,
1027
1177
  useMobileSidebar,
1178
+ useSidebarCollapse,
1179
+ useNotifications,
1028
1180
  } from 'mgv-backoffice'
1029
1181
  ```
1030
1182
 
@@ -1037,6 +1189,8 @@ import {
1037
1189
  | `useDebouncedRef(source, delay?)` | Debounced mirror of a ref. Timer cleared on scope dispose. |
1038
1190
  | `useToast(durationMs?)` | Per-component toast state: `{ showToast, toastMessage, toastType, showToastMessage }`. |
1039
1191
  | `useMobileSidebar()` | Singleton state shared between `BaseSidebar` and `BaseAppLayout` for the off-canvas open/closed flag. |
1192
+ | `useSidebarCollapse({ storageKey? })` | Singleton collapsed/expanded state for the desktop sidebar rail, shared between `BaseSidebar` and `BaseAppLayout` and persisted to localStorage (default key `'mgv-sidebar-collapsed'`). |
1193
+ | `useNotifications()` | Singleton notification state shared by the sidebar bell and `BaseNotificationPanel`: `{ notifications, unreadCount, open, openPanel, closePanel, togglePanel, setNotifications, add, remove, markRead, markAllRead, clear }`. |
1040
1194
 
1041
1195
  ---
1042
1196
 
@@ -0,0 +1,22 @@
1
+ interface Props {
2
+ /** Button label. Defaults to "Sign in with Google". */
3
+ label?: string;
4
+ /** Disables the button and shows a busy spinner. */
5
+ loading?: boolean;
6
+ /** Disables the button without the busy spinner. */
7
+ disabled?: boolean;
8
+ /** Full-width (block) layout. Defaults to true. */
9
+ block?: boolean;
10
+ }
11
+ declare const __VLS_export: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
12
+ click: () => any;
13
+ }, string, import('vue').PublicProps, Readonly<Props> & Readonly<{
14
+ onClick?: (() => any) | undefined;
15
+ }>, {
16
+ label: string;
17
+ disabled: boolean;
18
+ loading: boolean;
19
+ block: boolean;
20
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
21
+ declare const _default: typeof __VLS_export;
22
+ export default _default;
@@ -0,0 +1,51 @@
1
+ import { LoginCredentials } from '../types/auth';
2
+ interface Props {
3
+ /** Card heading. Defaults to "Sign in". */
4
+ title?: string;
5
+ /** Optional muted line under the heading. */
6
+ subtitle?: string;
7
+ /** Submit button label. Defaults to "Sign in". */
8
+ submitLabel?: string;
9
+ /** Disables the form and shows a spinner on the submit button. */
10
+ loading?: boolean;
11
+ /** Disables the form and shows a spinner on the Google button. */
12
+ googleLoading?: boolean;
13
+ /** Error message rendered above the form (e.g. "Invalid credentials"). */
14
+ error?: string;
15
+ /** Render the "Sign in with Google" button + divider. Defaults to true. */
16
+ showGoogle?: boolean;
17
+ /** Render the "Remember me" checkbox. Defaults to false. */
18
+ showRemember?: boolean;
19
+ }
20
+ declare var __VLS_1: {}, __VLS_10: {}, __VLS_12: {};
21
+ type __VLS_Slots = {} & {
22
+ logo?: (props: typeof __VLS_1) => any;
23
+ } & {
24
+ forgot?: (props: typeof __VLS_10) => any;
25
+ } & {
26
+ footer?: (props: typeof __VLS_12) => any;
27
+ };
28
+ declare const __VLS_base: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
29
+ submit: (credentials: LoginCredentials) => any;
30
+ "google-sign-in": () => any;
31
+ }, string, import('vue').PublicProps, Readonly<Props> & Readonly<{
32
+ onSubmit?: ((credentials: LoginCredentials) => any) | undefined;
33
+ "onGoogle-sign-in"?: (() => any) | undefined;
34
+ }>, {
35
+ title: string;
36
+ error: string;
37
+ subtitle: string;
38
+ loading: boolean;
39
+ submitLabel: string;
40
+ googleLoading: boolean;
41
+ showGoogle: boolean;
42
+ showRemember: boolean;
43
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
44
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
45
+ declare const _default: typeof __VLS_export;
46
+ export default _default;
47
+ type __VLS_WithSlots<T, S> = T & {
48
+ new (): {
49
+ $slots: S;
50
+ };
51
+ };
@@ -0,0 +1,19 @@
1
+ interface Props {
2
+ /** Panel heading. Defaults to "Notifications". */
3
+ title?: string;
4
+ /** Shown when there are no notifications. */
5
+ emptyText?: string;
6
+ /** Render the "Mark all read" action when there are unread items. */
7
+ showMarkAllRead?: boolean;
8
+ }
9
+ declare const __VLS_export: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
10
+ select: (id: string | number) => any;
11
+ }, string, import('vue').PublicProps, Readonly<Props> & Readonly<{
12
+ onSelect?: ((id: string | number) => any) | undefined;
13
+ }>, {
14
+ title: string;
15
+ emptyText: string;
16
+ showMarkAllRead: boolean;
17
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
18
+ declare const _default: typeof __VLS_export;
19
+ export default _default;
@@ -10,26 +10,32 @@ interface Props {
10
10
  version?: string;
11
11
  /** Whether to render the dark/light toggle in the footer. */
12
12
  showThemeToggle?: boolean;
13
+ /** Whether to render the desktop collapse toggle (icon-only rail). */
14
+ collapsible?: boolean;
15
+ /** Whether to render the notifications bell button. */
16
+ showNotifications?: boolean;
13
17
  }
14
18
  declare var __VLS_1: {
15
19
  size: number;
16
20
  }, __VLS_13: {
17
21
  size: number;
18
- }, __VLS_25: {}, __VLS_27: {};
22
+ }, __VLS_40: {}, __VLS_42: {};
19
23
  type __VLS_Slots = {} & {
20
24
  logo?: (props: typeof __VLS_1) => any;
21
25
  } & {
22
26
  logo?: (props: typeof __VLS_13) => any;
23
27
  } & {
24
- status?: (props: typeof __VLS_25) => any;
28
+ status?: (props: typeof __VLS_40) => any;
25
29
  } & {
26
- footer?: (props: typeof __VLS_27) => any;
30
+ footer?: (props: typeof __VLS_42) => any;
27
31
  };
28
32
  declare const __VLS_base: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<Props> & Readonly<{}>, {
29
33
  homeRouteName: string;
30
34
  appName: string;
31
35
  version: string;
32
36
  showThemeToggle: boolean;
37
+ collapsible: boolean;
38
+ showNotifications: boolean;
33
39
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
34
40
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
35
41
  declare const _default: typeof __VLS_export;
@@ -1,12 +1,13 @@
1
1
  /**
2
2
  * Accent colour of the card. Defaults to `orange` so existing consumers are
3
- * unaffected; `emerald` lets a host app tint the card to a green-themed brand.
4
- * Each accent carries the full literal Tailwind class strings (rather than a
5
- * single interpolated hue) so the classes are statically detectable and the
6
- * two themes can differ in more than hue e.g. orange renders the amount in
7
- * neutral grey while emerald renders it in the accent itself.
3
+ * unaffected; `emerald` lets a host app tint the card to a green-themed brand,
4
+ * and `red` renders a loss/negative theme (also selected automatically by
5
+ * `signed`, see below). Each accent carries the full literal Tailwind class
6
+ * strings (rather than a single interpolated hue) so the classes are statically
7
+ * detectable and the themes can differ in more than hue — e.g. orange renders
8
+ * the amount in neutral grey while emerald/red render it in the accent itself.
8
9
  */
9
- type Accent = 'orange' | 'emerald';
10
+ type Accent = 'orange' | 'emerald' | 'red';
10
11
  interface Props {
11
12
  title?: string;
12
13
  amount?: number;
@@ -15,6 +16,15 @@ interface Props {
15
16
  currency?: string;
16
17
  decimals?: number;
17
18
  accent?: Accent;
19
+ /**
20
+ * Treat the card as a signed P&L figure. When `true` and the amount is
21
+ * negative, the card renders the loss theme automatically: the `red` accent
22
+ * (border / amount / subtitle / icon-box recoloured) AND the trend glyph
23
+ * flipped to point DOWN. A non-negative amount keeps the chosen `accent` and
24
+ * the upward glyph. Defaults to `false` so existing consumers — which use the
25
+ * card for always-positive totals like lifetime earnings — are unaffected.
26
+ */
27
+ signed?: boolean;
18
28
  }
19
29
  declare const __VLS_export: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<Props> & Readonly<{}>, {
20
30
  title: string;
@@ -24,6 +34,7 @@ declare const __VLS_export: import('vue').DefineComponent<Props, {}, {}, {}, {},
24
34
  currency: string;
25
35
  decimals: number;
26
36
  accent: Accent;
37
+ signed: boolean;
27
38
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
28
39
  declare const _default: typeof __VLS_export;
29
40
  export default _default;
@@ -0,0 +1,29 @@
1
+ import { NotificationItem } from '../types/notification';
2
+ export declare function useNotifications(): {
3
+ notifications: import('vue').Ref<{
4
+ id: string | number;
5
+ title: string;
6
+ message?: string | undefined;
7
+ time?: string | undefined;
8
+ read?: boolean | undefined;
9
+ type?: "info" | "success" | "warning" | "error" | undefined;
10
+ }[], NotificationItem[] | {
11
+ id: string | number;
12
+ title: string;
13
+ message?: string | undefined;
14
+ time?: string | undefined;
15
+ read?: boolean | undefined;
16
+ type?: "info" | "success" | "warning" | "error" | undefined;
17
+ }[]>;
18
+ unreadCount: import('vue').ComputedRef<number>;
19
+ open: import('vue').Ref<boolean, boolean>;
20
+ openPanel: () => void;
21
+ closePanel: () => void;
22
+ togglePanel: () => void;
23
+ setNotifications: (items: NotificationItem[]) => void;
24
+ add: (item: NotificationItem) => void;
25
+ remove: (id: NotificationItem["id"]) => void;
26
+ markRead: (id: NotificationItem["id"]) => void;
27
+ markAllRead: () => void;
28
+ clear: () => void;
29
+ };
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Shared collapsed/expanded state for the desktop sidebar.
3
+ *
4
+ * Module-scoped singleton (mirrors useMobileSidebar) so `BaseSidebar` and
5
+ * the page layout (`BaseAppLayout`, which offsets `<main>` by the sidebar
6
+ * width) stay in sync. When collapsed, the sidebar shrinks to an icon-only
7
+ * rail on desktop.
8
+ *
9
+ * The preference is persisted to localStorage. The first consumer can pass
10
+ * an options object to override the key; subsequent callers reuse the same
11
+ * singleton and the option is only consulted on the first call.
12
+ */
13
+ export interface UseSidebarCollapseOptions {
14
+ /** localStorage key used to persist the preference. */
15
+ storageKey?: string;
16
+ }
17
+ export declare function useSidebarCollapse(options?: UseSidebarCollapseOptions): {
18
+ collapsed: import('vue').Ref<boolean, boolean>;
19
+ collapse: () => void;
20
+ expand: () => void;
21
+ toggle: () => void;
22
+ };
package/dist/index.d.ts CHANGED
@@ -25,6 +25,9 @@ export { default as BasePageHeader } from './components/BasePageHeader.vue';
25
25
  export { default as BaseToolbarButton } from './components/BaseToolbarButton.vue';
26
26
  export { default as BaseActionButton } from './components/BaseActionButton.vue';
27
27
  export { default as BaseCopyButton } from './components/BaseCopyButton.vue';
28
+ export { default as BaseGoogleSignInButton } from './components/BaseGoogleSignInButton.vue';
29
+ export { default as BaseLoginForm } from './components/BaseLoginForm.vue';
30
+ export { default as BaseNotificationPanel } from './components/BaseNotificationPanel.vue';
28
31
  export { useTheme, initTheme } from './composables/useTheme';
29
32
  export type { UseThemeOptions } from './composables/useTheme';
30
33
  export { useThemeClasses } from './composables/useThemeClasses';
@@ -33,6 +36,9 @@ export { useEscapeKey } from './composables/useEscapeKey';
33
36
  export { useDebouncedRef } from './composables/useDebounce';
34
37
  export { useToast } from './composables/useToast';
35
38
  export { useMobileSidebar } from './composables/useMobileSidebar';
39
+ export { useSidebarCollapse } from './composables/useSidebarCollapse';
40
+ export type { UseSidebarCollapseOptions } from './composables/useSidebarCollapse';
41
+ export { useNotifications } from './composables/useNotifications';
36
42
  export { AlertEnum } from './enums/AlertEnum';
37
43
  export { BaseBadgeEnum } from './enums/BaseBadgeEnum';
38
44
  export { BaseButtonEnum } from './enums/BaseButtonEnum';
@@ -46,6 +52,8 @@ export { PositioningEnum } from './enums/PositioningEnum';
46
52
  export type { BreadCrumb } from './components/BaseBreadcrumb.vue';
47
53
  export type { NavItem, NavSection } from './types/sidebar';
48
54
  export type { EntityPickerItem } from './types/entityPicker';
55
+ export type { LoginCredentials } from './types/auth';
56
+ export type { NotificationItem } from './types/notification';
49
57
  export { getBaseColor, getBaseColorOf } from './utils/util';
50
58
  export { methodBadgeSolid, methodBadgeBright, statusBadgeSolid, statusBadgeTinted, } from './utils/httpColors';
51
59
  export { sanitizeHtml, isSafeHref } from './utils/sanitizeHtml';
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Credentials emitted by `BaseLoginForm` on submit.
3
+ *
4
+ * `remember` is only present when the form is rendered with the
5
+ * "remember me" checkbox enabled.
6
+ */
7
+ export interface LoginCredentials {
8
+ email: string;
9
+ password: string;
10
+ remember?: boolean;
11
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * A single entry rendered in `BaseNotificationPanel` and counted by the
3
+ * sidebar's unread badge.
4
+ *
5
+ * • `id` — stable key, used for list rendering and mark/remove ops.
6
+ * • `title` — bold headline line.
7
+ * • `message` — optional secondary line.
8
+ * • `time` — optional pre-formatted timestamp (e.g. "2h ago"). The
9
+ * library does not format dates for you.
10
+ * • `read` — unread entries are highlighted and count toward the badge.
11
+ * • `type` — drives the small status dot colour.
12
+ */
13
+ export interface NotificationItem {
14
+ id: string | number;
15
+ title: string;
16
+ message?: string;
17
+ time?: string;
18
+ read?: boolean;
19
+ type?: 'info' | 'success' | 'warning' | 'error';
20
+ }