@alfakit/vue 0.1.0 → 0.1.2
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/CHANGELOG.md +17 -0
- package/dist/components/actions/ActionButton.js.map +1 -1
- package/dist/components/actions/ActionButton.vue.d.ts.map +1 -1
- package/dist/components/actions/ActionButton.vue_vue_type_script_setup_true_lang.js +160 -159
- package/dist/components/actions/ActionButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/actions/ActionModal.js.map +1 -1
- package/dist/components/actions/ActionModal.vue.d.ts.map +1 -1
- package/dist/components/actions/ActionModal.vue_vue_type_script_setup_true_lang.js +214 -214
- package/dist/components/actions/ActionModal.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/cms/CmsLinkButton.vue.d.ts +1 -1
- package/dist/components/fields/ColorPickerField.js.map +1 -1
- package/dist/components/fields/ColorPickerField.vue.d.ts.map +1 -1
- package/dist/components/fields/ColorPickerField.vue_vue_type_script_setup_true_lang.js +1 -0
- package/dist/components/fields/ColorPickerField.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/fields/ComboboxSelect.js.map +1 -1
- package/dist/components/fields/ComboboxSelect.vue.d.ts.map +1 -1
- package/dist/components/fields/ComboboxSelect.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/fields/ComboboxSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/fields/FileUploadField.js.map +1 -1
- package/dist/components/fields/FileUploadField.vue.d.ts.map +1 -1
- package/dist/components/fields/FileUploadField.vue_vue_type_script_setup_true_lang.js +183 -183
- package/dist/components/fields/FileUploadField.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/fields/OneTimeCodeInputField.js.map +1 -1
- package/dist/components/fields/OneTimeCodeInputField.vue_vue_type_script_setup_true_lang.js +1 -2
- package/dist/components/fields/OneTimeCodeInputField.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/fields/SelectField.js.map +1 -1
- package/dist/components/fields/SelectField.vue.d.ts.map +1 -1
- package/dist/components/fields/SelectField.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/components/fields/SelectField.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/fields/TableColumnHeaders.js.map +1 -1
- package/dist/components/fields/TableColumnHeaders.vue.d.ts.map +1 -1
- package/dist/components/fields/TableColumnHeaders.vue_vue_type_script_setup_true_lang.js +6 -3
- package/dist/components/fields/TableColumnHeaders.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/file-manager/FileManagerView.js.map +1 -1
- package/dist/components/file-manager/FileManagerView.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/file-manager/FileManagerView.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/form/FormBlock.js.map +1 -1
- package/dist/components/form/FormBlock.vue.d.ts.map +1 -1
- package/dist/components/form/FormBlock.vue_vue_type_script_setup_true_lang.js +81 -77
- package/dist/components/form/FormBlock.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/form/form-context.js +25 -25
- package/dist/components/form/form-context.js.map +1 -1
- package/dist/components/layout/FusedGroupComponent.js.map +1 -1
- package/dist/components/layout/FusedGroupComponent.vue.d.ts.map +1 -1
- package/dist/components/layout/FusedGroupComponent.vue_vue_type_script_setup_true_lang.js +1 -0
- package/dist/components/layout/FusedGroupComponent.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/layout/TabsComponent.js.map +1 -1
- package/dist/components/layout/TabsComponent.vue.d.ts.map +1 -1
- package/dist/components/layout/TabsComponent.vue_vue_type_script_setup_true_lang.js +76 -55
- package/dist/components/layout/TabsComponent.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/notifications/NotificationsMenu.js.map +1 -1
- package/dist/components/notifications/NotificationsMenu.vue.d.ts.map +1 -1
- package/dist/components/notifications/NotificationsMenu.vue_vue_type_script_setup_true_lang.js +44 -42
- package/dist/components/notifications/NotificationsMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/panel/GlobalSearch.js.map +1 -1
- package/dist/components/panel/GlobalSearch.vue.d.ts.map +1 -1
- package/dist/components/panel/GlobalSearch.vue_vue_type_script_setup_true_lang.js +1 -0
- package/dist/components/panel/GlobalSearch.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/panel/ShortcutKeys.js.map +1 -1
- package/dist/components/panel/ShortcutKeys.vue.d.ts.map +1 -1
- package/dist/components/panel/ShortcutKeys.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/components/panel/ShortcutKeys.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/panel/TenantMenu.js.map +1 -1
- package/dist/components/panel/TenantMenu.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/components/panel/TenantMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/table/GroupHeaderRow.js.map +1 -1
- package/dist/components/table/GroupHeaderRow.vue.d.ts.map +1 -1
- package/dist/components/table/GroupHeaderRow.vue_vue_type_script_setup_true_lang.js +55 -34
- package/dist/components/table/GroupHeaderRow.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/table/SelectCell.js.map +1 -1
- package/dist/components/table/SelectCell.vue.d.ts.map +1 -1
- package/dist/components/table/SelectCell.vue_vue_type_script_setup_true_lang.js +24 -19
- package/dist/components/table/SelectCell.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/table/TextInputCell.js.map +1 -1
- package/dist/components/table/TextInputCell.vue.d.ts.map +1 -1
- package/dist/components/table/TextInputCell.vue_vue_type_script_setup_true_lang.js +38 -33
- package/dist/components/table/TextInputCell.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components.css +347 -0
- package/dist/eject-manifest.json +2 -2
- package/dist/lib/Icon.js.map +1 -1
- package/dist/lib/Icon.vue.d.ts.map +1 -1
- package/dist/lib/Icon.vue_vue_type_script_setup_true_lang.js +18 -19
- package/dist/lib/Icon.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/lib/hydration.d.ts +9 -0
- package/dist/lib/hydration.d.ts.map +1 -0
- package/dist/lib/hydration.js +17 -0
- package/dist/lib/hydration.js.map +1 -0
- package/dist/lib/icons.d.ts +3 -5
- package/dist/lib/icons.d.ts.map +1 -1
- package/dist/lib/icons.js +19 -22
- package/dist/lib/icons.js.map +1 -1
- package/dist/lib/lazy.d.ts +1 -1
- package/dist/lib/lazy.d.ts.map +1 -1
- package/dist/lib/lazy.js +12 -11
- package/dist/lib/lazy.js.map +1 -1
- package/dist/standalone/AlfakitToaster.js.map +1 -1
- package/dist/standalone/AlfakitToaster.vue.d.ts.map +1 -1
- package/dist/standalone/AlfakitToaster.vue_vue_type_script_setup_true_lang.js +23 -15
- package/dist/standalone/AlfakitToaster.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/standalone.css +47 -0
- package/dist/starter-kit/widgets/SearchTrigger.js.map +1 -1
- package/dist/starter-kit/widgets/SearchTrigger.vue.d.ts.map +1 -1
- package/dist/starter-kit/widgets/SearchTrigger.vue_vue_type_script_setup_true_lang.js +1 -0
- package/dist/starter-kit/widgets/SearchTrigger.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/starter-kit/widgets/TenantChooser.js.map +1 -1
- package/dist/starter-kit/widgets/TenantChooser.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/starter-kit/widgets/TenantChooser.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/themes.css +2 -334
- package/package.json +3 -3
- package/src/components/actions/ActionButton.vue +14 -6
- package/src/components/actions/ActionModal.vue +3 -1
- package/src/components/fields/ColorPickerField.vue +1 -0
- package/src/components/fields/ComboboxSelect.vue +1 -1
- package/src/components/fields/FileUploadField.vue +14 -11
- package/src/components/fields/OneTimeCodeInputField.vue +1 -1
- package/src/components/fields/SelectField.vue +4 -2
- package/src/components/fields/TableColumnHeaders.vue +6 -1
- package/src/components/file-manager/FileManagerView.vue +1 -1
- package/src/components/form/FormBlock.vue +24 -0
- package/src/components/form/form-context.ts +2 -2
- package/src/components/layout/FusedGroupComponent.vue +1 -0
- package/src/components/layout/TabsComponent.vue +61 -5
- package/src/components/notifications/NotificationsMenu.vue +11 -0
- package/src/components/panel/GlobalSearch.vue +1 -0
- package/src/components/panel/ShortcutKeys.vue +1 -0
- package/src/components/panel/TenantMenu.vue +2 -2
- package/src/components/table/GroupHeaderRow.vue +27 -0
- package/src/components/table/SelectCell.vue +5 -2
- package/src/components/table/TextInputCell.vue +11 -5
- package/src/lib/Icon.vue +6 -5
- package/src/lib/hydration.ts +35 -0
- package/src/lib/icons.ts +6 -11
- package/src/lib/lazy.ts +5 -6
- package/src/standalone/AlfakitToaster.vue +12 -2
- package/src/starter-kit/widgets/SearchTrigger.vue +1 -0
- package/src/starter-kit/widgets/TenantChooser.vue +1 -1
|
@@ -1,77 +1,98 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import t from "../../lib/
|
|
3
|
-
import n from "
|
|
4
|
-
import r from "
|
|
5
|
-
import i from "../
|
|
6
|
-
import a from "../
|
|
7
|
-
import o from "../ui/
|
|
8
|
-
import s from "
|
|
9
|
-
import c from "
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import
|
|
1
|
+
import { useT as e } from "../../context.js";
|
|
2
|
+
import { cn as t } from "../../lib/utils.js";
|
|
3
|
+
import { useStoreSelector as n } from "../../composables/use-store.js";
|
|
4
|
+
import r from "../../lib/Icon.js";
|
|
5
|
+
import { useOptionalFormStore as i } from "../form/form-context.js";
|
|
6
|
+
import a from "../schema/SchemaRenderer.js";
|
|
7
|
+
import o from "../ui/Tabs.js";
|
|
8
|
+
import s from "../ui/TabsContent.js";
|
|
9
|
+
import c from "../ui/TabsList.js";
|
|
10
|
+
import l from "../ui/TabsTrigger.js";
|
|
11
|
+
import u from "./DeferredSchema.js";
|
|
12
|
+
import d from "./TabBadge.js";
|
|
13
|
+
import { componentHasErrors as f, readPersisted as p, schemaGapClass as m, tabFromQuery as h, tabQueryValue as g, tabToReveal as _, writePersisted as v } from "@alfakit/core";
|
|
14
|
+
import { usePage as y } from "@inertiajs/vue3";
|
|
15
|
+
import { Fragment as b, computed as x, createBlock as S, createCommentVNode as C, createElementBlock as w, createElementVNode as T, createTextVNode as E, createVNode as D, defineComponent as O, mergeProps as k, normalizeClass as A, onMounted as j, openBlock as M, ref as N, renderList as P, toDisplayString as F, unref as I, watch as L, withCtx as R } from "vue";
|
|
13
16
|
//#region src/components/layout/TabsComponent.vue?vue&type=script&setup=true&lang.ts
|
|
14
|
-
var
|
|
17
|
+
var z = { class: "sr-only" }, B = "text-destructive data-[state=active]:text-destructive dark:text-destructive dark:data-[state=active]:text-destructive", V = /*@__PURE__*/ O({
|
|
15
18
|
__name: "TabsComponent",
|
|
16
19
|
props: { component: {} },
|
|
17
|
-
setup(
|
|
18
|
-
let
|
|
19
|
-
|
|
20
|
-
let e =
|
|
21
|
-
if (!e ||
|
|
22
|
-
let t =
|
|
23
|
-
t &&
|
|
20
|
+
setup(O) {
|
|
21
|
+
let V = O, H = x(() => V.component.schema ?? []), U = y(), W = V.component.queryStringKey ? h(H.value, new URL(U.url, "http://localhost").searchParams.get(V.component.queryStringKey)) : null, G = N(W ?? H.value[Math.max(0, V.component.activeTab - 1)]?.key ?? H.value[0]?.key ?? "");
|
|
22
|
+
j(() => {
|
|
23
|
+
let e = V.component.persistTab;
|
|
24
|
+
if (!e || W) return;
|
|
25
|
+
let t = p(e.key, e.storage);
|
|
26
|
+
t && H.value.some((e) => e.key === t) && (G.value = t);
|
|
24
27
|
});
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
let K = e(), q = i(), J = n(q?.store ?? {
|
|
29
|
+
get: () => ({ errors: {} }),
|
|
30
|
+
subscribe: () => () => {}
|
|
31
|
+
}, (e) => e.errors), Y = x(() => new Set(H.value.filter((e) => f(e, J.value)).map((e) => e.key)));
|
|
32
|
+
L(J, (e, t) => {
|
|
33
|
+
let n = _(H.value, G.value, t ?? {}, e);
|
|
34
|
+
n !== null && (G.value = n);
|
|
35
|
+
}, { immediate: !0 });
|
|
36
|
+
function X(e) {
|
|
37
|
+
G.value = e;
|
|
38
|
+
let t = V.component.persistTab;
|
|
39
|
+
t && v(t.key, e, t.storage);
|
|
29
40
|
}
|
|
30
|
-
return
|
|
31
|
-
if (!
|
|
32
|
-
let t = new URL(window.location.href);
|
|
33
|
-
|
|
34
|
-
}, { immediate: !0 }), (
|
|
35
|
-
"data-surface":
|
|
36
|
-
"model-value":
|
|
37
|
-
orientation:
|
|
38
|
-
class:
|
|
39
|
-
},
|
|
40
|
-
default:
|
|
41
|
-
"data-scrollable":
|
|
42
|
-
class:
|
|
41
|
+
return L(G, (e) => {
|
|
42
|
+
if (!V.component.queryStringKey || typeof window > "u") return;
|
|
43
|
+
let t = H.value.find((t) => t.key === e), n = new URL(window.location.href);
|
|
44
|
+
n.searchParams.set(V.component.queryStringKey, t ? g(t) : e), window.history.replaceState(window.history.state, "", n);
|
|
45
|
+
}, { immediate: !0 }), (e, n) => (M(), S(o, k({
|
|
46
|
+
"data-surface": V.component.contained ? "tabs" : void 0,
|
|
47
|
+
"model-value": G.value,
|
|
48
|
+
orientation: V.component.vertical ? "vertical" : "horizontal",
|
|
49
|
+
class: I(t)(V.component.contained && "bg-card rounded-xl border shadow-xs", V.component.vertical && "flex-row")
|
|
50
|
+
}, V.component.extraAttributes, { "onUpdate:modelValue": n[0] ||= (e) => X(String(e)) }), {
|
|
51
|
+
default: R(() => [D(c, {
|
|
52
|
+
"data-scrollable": V.component.scrollable === !1 ? "false" : void 0,
|
|
53
|
+
class: A(I(t)(V.component.contained && "m-2", V.component.vertical ? "self-start" : V.component.scrollable === !1 ? "h-auto max-w-full flex-wrap justify-start" : "relative max-w-full overflow-x-auto"))
|
|
43
54
|
}, {
|
|
44
|
-
default:
|
|
55
|
+
default: R(() => [(M(!0), w(b, null, P(H.value, (e) => (M(), S(l, {
|
|
45
56
|
key: e.key,
|
|
46
|
-
value: e.key
|
|
57
|
+
value: e.key,
|
|
58
|
+
"data-invalid": Y.value.has(e.key) || void 0,
|
|
59
|
+
class: A(Y.value.has(e.key) ? B : void 0)
|
|
47
60
|
}, {
|
|
48
|
-
default:
|
|
49
|
-
e.icon && e.iconPosition !== "after" ? (
|
|
61
|
+
default: R(() => [
|
|
62
|
+
e.icon && e.iconPosition !== "after" ? (M(), S(I(r), {
|
|
50
63
|
key: 0,
|
|
51
64
|
name: e.icon
|
|
52
|
-
}, null, 8, ["name"])) :
|
|
53
|
-
|
|
54
|
-
e.icon && e.iconPosition === "after" ? (
|
|
65
|
+
}, null, 8, ["name"])) : C("", !0),
|
|
66
|
+
E(" " + F(e.label) + " ", 1),
|
|
67
|
+
e.icon && e.iconPosition === "after" ? (M(), S(I(r), {
|
|
55
68
|
key: 1,
|
|
56
69
|
name: e.icon
|
|
57
|
-
}, null, 8, ["name"])) :
|
|
58
|
-
|
|
70
|
+
}, null, 8, ["name"])) : C("", !0),
|
|
71
|
+
D(d, { tab: e }, null, 8, ["tab"]),
|
|
72
|
+
Y.value.has(e.key) ? (M(), w(b, { key: 2 }, [n[1] ||= T("span", {
|
|
73
|
+
"aria-hidden": "true",
|
|
74
|
+
class: "bg-destructive size-1.5 shrink-0 rounded-full"
|
|
75
|
+
}, null, -1), T("span", z, "(" + F(I(K)("translatable.has_errors")) + ")", 1)], 64)) : C("", !0)
|
|
59
76
|
]),
|
|
60
77
|
_: 2
|
|
61
|
-
}, 1032, [
|
|
78
|
+
}, 1032, [
|
|
79
|
+
"value",
|
|
80
|
+
"data-invalid",
|
|
81
|
+
"class"
|
|
82
|
+
]))), 128))]),
|
|
62
83
|
_: 1
|
|
63
|
-
}, 8, ["data-scrollable", "class"]), (
|
|
64
|
-
key:
|
|
65
|
-
value:
|
|
84
|
+
}, 8, ["data-scrollable", "class"]), (M(!0), w(b, null, P(H.value, (e) => (M(), S(s, {
|
|
85
|
+
key: e.key,
|
|
86
|
+
value: e.key,
|
|
66
87
|
"force-mount": "",
|
|
67
|
-
class:
|
|
88
|
+
class: A(I(t)("data-[state=inactive]:hidden", V.component.contained ? "p-6 pt-4" : "pt-4"))
|
|
68
89
|
}, {
|
|
69
|
-
default:
|
|
70
|
-
default:
|
|
90
|
+
default: R(() => [D(u, { component: e }, {
|
|
91
|
+
default: R(({ component: e }) => [D(a, {
|
|
71
92
|
components: e.schema ?? [],
|
|
72
93
|
columns: e.columns,
|
|
73
94
|
attributes: e.extraAttributes,
|
|
74
|
-
class:
|
|
95
|
+
class: A(I(m)(e) || void 0)
|
|
75
96
|
}, null, 8, [
|
|
76
97
|
"components",
|
|
77
98
|
"columns",
|
|
@@ -92,6 +113,6 @@ var j = /*@__PURE__*/ b({
|
|
|
92
113
|
}
|
|
93
114
|
});
|
|
94
115
|
//#endregion
|
|
95
|
-
export {
|
|
116
|
+
export { V as default };
|
|
96
117
|
|
|
97
118
|
//# sourceMappingURL=TabsComponent.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TabsComponent.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","Tabs","_mergeProps","_unref","_withCtx","_createVNode","TabsList","_normalizeClass","_createElementBlock","_Fragment","_renderList","TabsTrigger","Icon","_createCommentVNode","_createTextVNode","_toDisplayString","TabBadge","TabsContent","DeferredSchema","SchemaRenderer","Icon_default","SchemaRenderer_default","Tabs_default","TabsContent_default","TabsList_default","TabsTrigger_default","DeferredSchema_default","TabBadge_default","TabsComponent_vue_vue_type_script_setup_true_lang_default","props","__props","tabs","computed","page","usePage","fromQuery","active","ref","tab","persist","stored","readPersisted","changeTab","value","writePersisted","watch","url","openBlock","createBlock","mergeProps","unref","cn","_cache","$event","withCtx","createVNode","normalizeClass","createElementBlock","Fragment","renderList","createCommentVNode","createTextVNode","toDisplayString","loaded","schemaGapClass"],"sources":["../../../src/components/layout/TabsComponent.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { TabsSchema } from '@alfakit/core'\nimport { readPersisted, schemaGapClass, writePersisted } from '@alfakit/core'\nimport { usePage } from '@inertiajs/vue3'\nimport { computed, onMounted, ref, watch } from 'vue'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport SchemaRenderer from '../schema/SchemaRenderer.vue'\nimport Tabs from '../ui/Tabs.vue'\nimport TabsContent from '../ui/TabsContent.vue'\nimport TabsList from '../ui/TabsList.vue'\nimport TabsTrigger from '../ui/TabsTrigger.vue'\nimport DeferredSchema from './DeferredSchema.vue'\nimport TabBadge from './TabBadge.vue'\n\nconst props = defineProps<{ component: TabsSchema }>()\nconst tabs = computed(() => props.component.schema ?? [])\n// The page URL (not `window.location`) so the server renders the same tab as the browser.\nconst page = usePage()\nconst fromQuery = props.component.queryStringKey\n ? new URL(page.url, 'http://localhost').searchParams.get(props.component.queryStringKey)\n : null\nconst active = ref<string>(\n tabs.value.find((tab) => tab.key === fromQuery)?.key ??\n tabs.value[Math.max(0, props.component.activeTab - 1)]?.key ??\n tabs.value[0]?.key ??\n '',\n)\n\n// `persistTab()`: restored after mounting (the server can't read browser storage); a tab\n// named in the query string wins.\nonMounted(() => {\n const persist = props.component.persistTab\n\n if (!persist || fromQuery) return\n\n const stored = readPersisted(persist.key, persist.storage)\n\n if (stored && tabs.value.some((tab) => tab.key === stored)) active.value = stored\n})\n\nfunction changeTab(value: string) {\n active.value = value\n\n const persist = props.component.persistTab\n\n if (persist) writePersisted(persist.key, value, persist.storage)\n}\n\nwatch(\n active,\n (value) => {\n if (!props.component.queryStringKey || typeof window === 'undefined') return\n\n const url = new URL(window.location.href)\n url.searchParams.set(props.component.queryStringKey, value)\n window.history.replaceState(window.history.state, '', url)\n },\n { immediate: true },\n)\n</script>\n\n<template>\n <Tabs\n :data-surface=\"props.component.contained ? 'tabs' : undefined\"\n :model-value=\"active\"\n :orientation=\"props.component.vertical ? 'vertical' : 'horizontal'\"\n :class=\"\n cn(\n props.component.contained && 'bg-card rounded-xl border shadow-xs',\n props.component.vertical && 'flex-row',\n )\n \"\n v-bind=\"props.component.extraAttributes\"\n @update:model-value=\"changeTab(String($event))\"\n >\n <TabsList\n :data-scrollable=\"props.component.scrollable === false ? 'false' : undefined\"\n :class=\"\n cn(\n props.component.contained && 'm-2',\n props.component.vertical\n ? 'self-start'\n : props.component.scrollable === false\n ? 'h-auto max-w-full flex-wrap justify-start'\n : 'relative max-w-full overflow-x-auto',\n )\n \"\n >\n <TabsTrigger v-for=\"tab in tabs\" :key=\"tab.key\" :value=\"tab.key\">\n <Icon v-if=\"tab.icon && tab.iconPosition !== 'after'\" :name=\"tab.icon\" />\n {{ tab.label }}\n <Icon v-if=\"tab.icon && tab.iconPosition === 'after'\" :name=\"tab.icon\" />\n <TabBadge :tab=\"tab\" />\n </TabsTrigger>\n </TabsList>\n <TabsContent\n v-for=\"tab in tabs\"\n :key=\"tab.key\"\n :value=\"tab.key\"\n force-mount\n :class=\"cn('data-[state=inactive]:hidden', props.component.contained ? 'p-6 pt-4' : 'pt-4')\"\n >\n <DeferredSchema v-slot=\"{ component: loaded }\" :component=\"tab\">\n <SchemaRenderer\n :components=\"loaded.schema ?? []\"\n :columns=\"loaded.columns\"\n :attributes=\"loaded.extraAttributes\"\n :class=\"schemaGapClass(loaded) || undefined\"\n />\n </DeferredSchema>\n </TabsContent>\n </Tabs>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TabsComponent.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","Tabs","_mergeProps","_unref","_withCtx","_createVNode","TabsList","_normalizeClass","_createElementBlock","_Fragment","_renderList","TabsTrigger","Icon","_createCommentVNode","_createTextVNode","_toDisplayString","TabBadge","_createElementVNode","TabsContent","DeferredSchema","SchemaRenderer","Icon_default","SchemaRenderer_default","Tabs_default","TabsContent_default","TabsList_default","TabsTrigger_default","DeferredSchema_default","TabBadge_default","_hoisted_1","TAB_INVALID_CLASSES","TabsComponent_vue_vue_type_script_setup_true_lang_default","props","__props","tabs","computed","page","usePage","fromQuery","tabFromQuery","active","ref","persist","stored","readPersisted","tab","t","useT","store","useOptionalFormStore","errors","useStoreSelector","state","invalidTabs","componentHasErrors","reveal","tabToReveal","previous","next","changeTab","value","writePersisted","watch","item","url","tabQueryValue","openBlock","createBlock","mergeProps","unref","cn","_cache","$event","withCtx","createVNode","normalizeClass","createElementBlock","Fragment","renderList","createCommentVNode","createTextVNode","toDisplayString","createElementVNode","loaded","schemaGapClass"],"sources":["../../../src/components/layout/TabsComponent.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { TabsSchema } from '@alfakit/core'\nimport {\n componentHasErrors,\n readPersisted,\n schemaGapClass,\n tabFromQuery,\n tabQueryValue,\n tabToReveal,\n writePersisted,\n} from '@alfakit/core'\nimport { usePage } from '@inertiajs/vue3'\nimport { computed, onMounted, ref, watch } from 'vue'\nimport { useStoreSelector } from '../../composables/use-store'\nimport { useT } from '../../context'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { useOptionalFormStore } from '../form/form-context'\nimport SchemaRenderer from '../schema/SchemaRenderer.vue'\nimport Tabs from '../ui/Tabs.vue'\nimport TabsContent from '../ui/TabsContent.vue'\nimport TabsList from '../ui/TabsList.vue'\nimport TabsTrigger from '../ui/TabsTrigger.vue'\nimport DeferredSchema from './DeferredSchema.vue'\nimport TabBadge from './TabBadge.vue'\n\nconst props = defineProps<{ component: TabsSchema }>()\nconst tabs = computed(() => props.component.schema ?? [])\n// The page URL (not `window.location`) so the server renders the same tab as the browser.\nconst page = usePage()\n// The tab's readable value (`?tab=billing-address`), or its key in links from older versions.\nconst fromQuery = props.component.queryStringKey\n ? tabFromQuery(\n tabs.value,\n new URL(page.url, 'http://localhost').searchParams.get(props.component.queryStringKey),\n )\n : null\nconst active = ref<string>(\n fromQuery ??\n tabs.value[Math.max(0, props.component.activeTab - 1)]?.key ??\n tabs.value[0]?.key ??\n '',\n)\n\n// `persistTab()`: restored after mounting (the server can't read browser storage); a tab\n// named in the query string wins.\nonMounted(() => {\n const persist = props.component.persistTab\n\n if (!persist || fromQuery) return\n\n const stored = readPersisted(persist.key, persist.storage)\n\n if (stored && tabs.value.some((tab) => tab.key === stored)) active.value = stored\n})\n\n// Tabs holding a field with a validation error are marked, and when a submit brings new\n// errors while the open tab has none, the first tab with an error opens.\nconst TAB_INVALID_CLASSES =\n 'text-destructive data-[state=active]:text-destructive dark:text-destructive dark:data-[state=active]:text-destructive'\nconst t = useT()\nconst store = useOptionalFormStore()\nconst errors = useStoreSelector(\n store?.store ?? {\n get: () => ({ errors: {} as Record<string, string[]> }),\n subscribe: () => () => {},\n },\n (state) => state.errors,\n)\nconst invalidTabs = computed(\n () =>\n new Set(\n tabs.value.filter((tab) => componentHasErrors(tab, errors.value)).map((tab) => tab.key),\n ),\n)\n\nwatch(\n errors,\n (next, previous) => {\n const reveal = tabToReveal(tabs.value, active.value, previous ?? {}, next)\n\n if (reveal !== null) active.value = reveal\n },\n { immediate: true },\n)\n\nfunction changeTab(value: string) {\n active.value = value\n\n const persist = props.component.persistTab\n\n if (persist) writePersisted(persist.key, value, persist.storage)\n}\n\nwatch(\n active,\n (value) => {\n if (!props.component.queryStringKey || typeof window === 'undefined') return\n\n const tab = tabs.value.find((item) => item.key === value)\n const url = new URL(window.location.href)\n url.searchParams.set(props.component.queryStringKey, tab ? tabQueryValue(tab) : value)\n window.history.replaceState(window.history.state, '', url)\n },\n { immediate: true },\n)\n</script>\n\n<template>\n <Tabs\n :data-surface=\"props.component.contained ? 'tabs' : undefined\"\n :model-value=\"active\"\n :orientation=\"props.component.vertical ? 'vertical' : 'horizontal'\"\n :class=\"\n cn(\n props.component.contained && 'bg-card rounded-xl border shadow-xs',\n props.component.vertical && 'flex-row',\n )\n \"\n v-bind=\"props.component.extraAttributes\"\n @update:model-value=\"changeTab(String($event))\"\n >\n <TabsList\n :data-scrollable=\"props.component.scrollable === false ? 'false' : undefined\"\n :class=\"\n cn(\n props.component.contained && 'm-2',\n props.component.vertical\n ? 'self-start'\n : props.component.scrollable === false\n ? 'h-auto max-w-full flex-wrap justify-start'\n : 'relative max-w-full overflow-x-auto',\n )\n \"\n >\n <TabsTrigger\n v-for=\"tab in tabs\"\n :key=\"tab.key\"\n :value=\"tab.key\"\n :data-invalid=\"invalidTabs.has(tab.key) || undefined\"\n :class=\"invalidTabs.has(tab.key) ? TAB_INVALID_CLASSES : undefined\"\n >\n <Icon v-if=\"tab.icon && tab.iconPosition !== 'after'\" :name=\"tab.icon\" />\n {{ tab.label }}\n <Icon v-if=\"tab.icon && tab.iconPosition === 'after'\" :name=\"tab.icon\" />\n <TabBadge :tab=\"tab\" />\n <template v-if=\"invalidTabs.has(tab.key)\">\n <span aria-hidden=\"true\" class=\"bg-destructive size-1.5 shrink-0 rounded-full\"></span>\n <span class=\"sr-only\">({{ t('translatable.has_errors') }})</span>\n </template>\n </TabsTrigger>\n </TabsList>\n <TabsContent\n v-for=\"tab in tabs\"\n :key=\"tab.key\"\n :value=\"tab.key\"\n force-mount\n :class=\"cn('data-[state=inactive]:hidden', props.component.contained ? 'p-6 pt-4' : 'pt-4')\"\n >\n <DeferredSchema v-slot=\"{ component: loaded }\" :component=\"tab\">\n <SchemaRenderer\n :components=\"loaded.schema ?? []\"\n :columns=\"loaded.columns\"\n :attributes=\"loaded.extraAttributes\"\n :class=\"schemaGapClass(loaded) || undefined\"\n />\n </DeferredSchema>\n </TabsContent>\n </Tabs>\n</template>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NotificationsMenu.js","names":["_sfc_main","NotificationsMenu_vue_vue_type_script_setup_true_lang_default","NotificationsMenu_default"],"sources":["../../../src/components/notifications/NotificationsMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n NotificationCenter,\n notificationTintStyles,\n onDatabaseNotificationsSent,\n onOpenDatabaseNotifications,\n} from '@alfakit/core'\nimport { BellIcon, CheckCheckIcon, Trash2Icon } from '@lucide/vue'\nimport { computed, onMounted, onScopeDispose, ref, watch } from 'vue'\nimport { useStore } from '../../composables/use-store'\nimport { useDirection, useFormatter, usePanel, useT } from '../../context'\nimport { cssColor, textColorClasses } from '../../lib/colors'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport Button from '../ui/Button.vue'\nimport Popover from '../ui/Popover.vue'\nimport PopoverContent from '../ui/PopoverContent.vue'\nimport PopoverTrigger from '../ui/PopoverTrigger.vue'\nimport ScrollArea from '../ui/ScrollArea.vue'\nimport Spinner from '../ui/Spinner.vue'\nimport NotificationActionButton from './NotificationActionButton.vue'\n\n/**\n * Bell menu for database notifications. It also opens when something calls\n * `openDatabaseNotifications()` (or an action with `->openDatabaseNotifications()`).\n * `variant=\"sidebar\"`: a full-width row with a label, for layouts that put it in the sidebar.\n */\nconst props = withDefaults(defineProps<{ variant?: 'topbar' | 'sidebar' }>(), {\n variant: 'topbar',\n})\nconst t = useT()\nconst direction = useDirection()\nconst panel = usePanel()\nconst config = computed(() => panel.value.databaseNotifications)\nconst endpoints = panel.value.endpoints\n\nconst center =\n endpoints.notifications && endpoints.notificationsReadAll && endpoints.notificationsDestroyAll\n ? new NotificationCenter(\n {\n notifications: endpoints.notifications,\n notificationsReadAll: endpoints.notificationsReadAll,\n notificationsDestroyAll: endpoints.notificationsDestroyAll,\n },\n config.value?.unreadCount ?? 0,\n )\n : null\n\nconst open = ref(false)\nconst state = useStore(\n center?.store ?? {\n get: () => ({ notifications: [], unreadCount: 0, loading: false, hasMore: false, page: 0 }),\n subscribe: () => () => {},\n },\n)\n\n// Polling starts in the browser only: a server render must not leave timers behind.\nonMounted(() => {\n watch(\n () => config.value?.pollingInterval,\n (interval) => center?.startPolling(interval),\n { immediate: true },\n )\n})\n\nwatch(open, (isOpen) => {\n if (isOpen) void center?.load()\n})\n\n// Realtime notifications announce stored ones, so the unread count updates right away.\nlet stopListening: (() => void) | null = null\nonMounted(() => {\n stopListening = center ? onDatabaseNotificationsSent(() => void center.load()) : null\n})\nonScopeDispose(() => stopListening?.())\n\n// `openDatabaseNotifications()`: opened from code or an action.\nlet stopOpenListener: (() => void) | null = null\nonMounted(() => {\n stopOpenListener = onOpenDatabaseNotifications(() => (open.value = true))\n})\nonScopeDispose(() => stopOpenListener?.())\n\nonScopeDispose(() => center?.stopPolling())\nconst format = useFormatter()\n</script>\n\n<template>\n <Popover v-if=\"config && center\" :open=\"open\" @update:open=\"open = $event\">\n <PopoverTrigger as-child>\n <Button\n v-if=\"props.variant === 'sidebar'\"\n type=\"button\"\n variant=\"ghost\"\n class=\"relative w-full justify-start gap-2 group-data-[collapsible=icon]:size-8 group-data-[collapsible=icon]:justify-center group-data-[collapsible=icon]:p-0\"\n data-slot=\"notifications-trigger\"\n data-variant=\"sidebar\"\n >\n <!-- In a collapsed (icon) sidebar only the bell and its badge stay visible. -->\n <Icon\n name=\"alfakit::panels.topbar.open-database-notifications-button\"\n :fallback=\"BellIcon\"\n />\n <span class=\"flex-1 text-start group-data-[collapsible=icon]:sr-only\">{{\n t('notifications', {}, 'Notifications')\n }}</span>\n <span\n v-if=\"state.unreadCount > 0\"\n class=\"bg-primary text-primary-foreground flex h-5 min-w-5 items-center justify-center rounded-full px-1 text-xs font-medium group-data-[collapsible=icon]:absolute group-data-[collapsible=icon]:-end-1 group-data-[collapsible=icon]:-top-1 group-data-[collapsible=icon]:h-4 group-data-[collapsible=icon]:min-w-4 group-data-[collapsible=icon]:text-[10px]\"\n >{{ state.unreadCount > 99 ? '99+' : state.unreadCount }}\n <span class=\"sr-only\">{{ t('unread_notifications', {}, 'unread') }}</span></span\n >\n </Button>\n <Button\n v-else\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n class=\"relative\"\n data-slot=\"notifications-trigger\"\n :aria-label=\"t('notifications', {}, 'Notifications')\"\n >\n <Icon\n name=\"alfakit::panels.topbar.open-database-notifications-button\"\n :fallback=\"BellIcon\"\n />\n <span\n v-if=\"state.unreadCount > 0\"\n class=\"bg-primary text-primary-foreground absolute -end-0.5 -top-0.5 flex h-4 min-w-4 items-center justify-center rounded-full px-1 text-[10px] font-medium\"\n >{{ state.unreadCount > 99 ? '99+' : state.unreadCount }}</span\n >\n </Button>\n </PopoverTrigger>\n <PopoverContent\n :align=\"props.variant === 'sidebar' ? 'start' : 'end'\"\n :side=\"props.variant === 'sidebar' ? (direction === 'rtl' ? 'left' : 'right') : 'bottom'\"\n class=\"w-80 p-0 sm:w-96\"\n >\n <div class=\"flex items-center justify-between border-b px-3 py-2\">\n <span class=\"text-sm font-semibold\">{{ t('notifications', {}, 'Notifications') }}</span>\n <div class=\"flex items-center gap-1\">\n <Button\n v-if=\"state.unreadCount > 0\"\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n :title=\"t('mark_all_read', {}, 'Mark all as read')\"\n @click=\"void center.markAllAsRead()\"\n ><CheckCheckIcon\n /></Button>\n <Button\n v-if=\"state.notifications.length > 0\"\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n :title=\"t('clear_notifications', {}, 'Clear notifications')\"\n @click=\"void center.clear()\"\n ><Trash2Icon\n /></Button>\n </div>\n </div>\n <ScrollArea class=\"max-h-96\">\n <div\n v-if=\"state.loading && state.notifications.length === 0\"\n class=\"flex justify-center py-8\"\n >\n <Spinner />\n </div>\n <p\n v-else-if=\"state.notifications.length === 0\"\n class=\"text-muted-foreground px-3 py-8 text-center text-sm\"\n >\n {{ t('no_notifications', {}, 'You have no notifications.') }}\n </p>\n <ul v-else class=\"divide-y\">\n <li\n v-for=\"notification in state.notifications\"\n :key=\"notification.id\"\n :class=\"cn('flex gap-3 px-3 py-3', !notification.readAt && 'bg-primary/5')\"\n :style=\"\n notification.color\n ? notificationTintStyles(cssColor(notification.color)).item\n : undefined\n \"\n >\n <Icon\n v-if=\"notification.icon\"\n :name=\"notification.icon\"\n :class=\"\n cn(\n 'mt-0.5 size-5 shrink-0',\n notification.iconColor && textColorClasses[notification.iconColor],\n )\n \"\n />\n <div class=\"flex min-w-0 flex-1 flex-col gap-1\">\n <div class=\"flex items-start justify-between gap-2\">\n <p class=\"text-sm font-medium\">{{ notification.title }}</p>\n <button\n v-if=\"!notification.readAt\"\n type=\"button\"\n class=\"focus-visible:ring-ring/50 -me-2 -mt-0.5 flex size-6 shrink-0 items-center justify-center rounded-full outline-none focus-visible:ring-[3px]\"\n :aria-label=\"t('mark_as_read', {}, 'Mark as read')\"\n @click=\"void center.markAsRead(notification.id)\"\n >\n <span class=\"bg-primary size-2 rounded-full\" aria-hidden=\"true\" />\n </button>\n </div>\n <p\n v-if=\"notification.body\"\n class=\"text-muted-foreground text-sm\"\n v-html=\"notification.body\"\n />\n <time v-if=\"notification.date\" class=\"text-muted-foreground text-xs\">{{\n format.relative(notification.date)\n }}</time>\n <div v-if=\"notification.actions\" class=\"flex flex-wrap gap-1\">\n <NotificationActionButton\n v-for=\"action in notification.actions\"\n :key=\"action.name\"\n :action=\"action\"\n :on-mark-as-read=\"() => void center!.markAsRead(notification.id)\"\n :on-mark-as-unread=\"() => void center!.markAsUnread(notification.id)\"\n />\n </div>\n </div>\n </li>\n </ul>\n <div\n v-if=\"state.hasMore && state.notifications.length > 0\"\n class=\"flex justify-center border-t p-2\"\n >\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n :disabled=\"state.loading\"\n @click=\"void center!.loadMore()\"\n >\n <Spinner v-if=\"state.loading\" />\n {{ t('load_more', {}, 'Load more') }}\n </Button>\n </div>\n </ScrollArea>\n </PopoverContent>\n </Popover>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"NotificationsMenu.js","names":["_sfc_main","NotificationsMenu_vue_vue_type_script_setup_true_lang_default","NotificationsMenu_default"],"sources":["../../../src/components/notifications/NotificationsMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n NotificationCenter,\n notificationTintStyles,\n onDatabaseNotificationsSent,\n onOpenDatabaseNotifications,\n} from '@alfakit/core'\nimport { BellIcon, CheckCheckIcon, Trash2Icon } from '@lucide/vue'\nimport { computed, onMounted, onScopeDispose, ref, watch } from 'vue'\nimport { useStore } from '../../composables/use-store'\nimport { useDirection, useFormatter, usePanel, useT } from '../../context'\nimport { cssColor, textColorClasses } from '../../lib/colors'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport Button from '../ui/Button.vue'\nimport Popover from '../ui/Popover.vue'\nimport PopoverContent from '../ui/PopoverContent.vue'\nimport PopoverTrigger from '../ui/PopoverTrigger.vue'\nimport ScrollArea from '../ui/ScrollArea.vue'\nimport Spinner from '../ui/Spinner.vue'\nimport NotificationActionButton from './NotificationActionButton.vue'\n\n/**\n * Bell menu for database notifications. It also opens when something calls\n * `openDatabaseNotifications()` (or an action with `->openDatabaseNotifications()`).\n * `variant=\"sidebar\"`: a full-width row with a label, for layouts that put it in the sidebar.\n */\nconst props = withDefaults(defineProps<{ variant?: 'topbar' | 'sidebar' }>(), {\n variant: 'topbar',\n})\nconst t = useT()\nconst direction = useDirection()\nconst panel = usePanel()\nconst config = computed(() => panel.value.databaseNotifications)\nconst endpoints = panel.value.endpoints\n\nconst center =\n endpoints.notifications && endpoints.notificationsReadAll && endpoints.notificationsDestroyAll\n ? new NotificationCenter(\n {\n notifications: endpoints.notifications,\n notificationsReadAll: endpoints.notificationsReadAll,\n notificationsDestroyAll: endpoints.notificationsDestroyAll,\n },\n config.value?.unreadCount ?? 0,\n )\n : null\n\nconst open = ref(false)\nconst state = useStore(\n center?.store ?? {\n get: () => ({ notifications: [], unreadCount: 0, loading: false, hasMore: false, page: 0 }),\n subscribe: () => () => {},\n },\n)\n\n// Polling starts in the browser only: a server render must not leave timers behind.\nonMounted(() => {\n watch(\n () => config.value?.pollingInterval,\n (interval) => center?.startPolling(interval),\n { immediate: true },\n )\n})\n\nwatch(open, (isOpen) => {\n if (isOpen) void center?.load()\n})\n\n// Every visit brings the server's unread count (another user after impersonating, or\n// notifications read in another tab): follow it instead of waiting for the next poll.\nwatch(\n () => config.value?.unreadCount,\n (count) => {\n if (center && typeof count === 'number' && count !== center.store.get().unreadCount) {\n center.store.update({ unreadCount: count })\n }\n },\n)\n\n// Realtime notifications announce stored ones, so the unread count updates right away.\nlet stopListening: (() => void) | null = null\nonMounted(() => {\n stopListening = center ? onDatabaseNotificationsSent(() => void center.load()) : null\n})\nonScopeDispose(() => stopListening?.())\n\n// `openDatabaseNotifications()`: opened from code or an action.\nlet stopOpenListener: (() => void) | null = null\nonMounted(() => {\n stopOpenListener = onOpenDatabaseNotifications(() => (open.value = true))\n})\nonScopeDispose(() => stopOpenListener?.())\n\nonScopeDispose(() => center?.stopPolling())\nconst format = useFormatter()\n</script>\n\n<template>\n <Popover v-if=\"config && center\" :open=\"open\" @update:open=\"open = $event\">\n <PopoverTrigger as-child>\n <Button\n v-if=\"props.variant === 'sidebar'\"\n type=\"button\"\n variant=\"ghost\"\n class=\"relative w-full justify-start gap-2 group-data-[collapsible=icon]:size-8 group-data-[collapsible=icon]:justify-center group-data-[collapsible=icon]:p-0\"\n data-slot=\"notifications-trigger\"\n data-variant=\"sidebar\"\n >\n <!-- In a collapsed (icon) sidebar only the bell and its badge stay visible. -->\n <Icon\n name=\"alfakit::panels.topbar.open-database-notifications-button\"\n :fallback=\"BellIcon\"\n />\n <span class=\"flex-1 text-start group-data-[collapsible=icon]:sr-only\">{{\n t('notifications', {}, 'Notifications')\n }}</span>\n <span\n v-if=\"state.unreadCount > 0\"\n class=\"bg-primary text-primary-foreground flex h-5 min-w-5 items-center justify-center rounded-full px-1 text-xs font-medium group-data-[collapsible=icon]:absolute group-data-[collapsible=icon]:-end-1 group-data-[collapsible=icon]:-top-1 group-data-[collapsible=icon]:h-4 group-data-[collapsible=icon]:min-w-4 group-data-[collapsible=icon]:text-[10px]\"\n >{{ state.unreadCount > 99 ? '99+' : state.unreadCount }}\n <span class=\"sr-only\">{{ t('unread_notifications', {}, 'unread') }}</span></span\n >\n </Button>\n <Button\n v-else\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n class=\"relative\"\n data-slot=\"notifications-trigger\"\n :aria-label=\"t('notifications', {}, 'Notifications')\"\n >\n <Icon\n name=\"alfakit::panels.topbar.open-database-notifications-button\"\n :fallback=\"BellIcon\"\n />\n <span\n v-if=\"state.unreadCount > 0\"\n class=\"bg-primary text-primary-foreground absolute -end-0.5 -top-0.5 flex h-4 min-w-4 items-center justify-center rounded-full px-1 text-[10px] font-medium\"\n >{{ state.unreadCount > 99 ? '99+' : state.unreadCount }}</span\n >\n </Button>\n </PopoverTrigger>\n <PopoverContent\n :align=\"props.variant === 'sidebar' ? 'start' : 'end'\"\n :side=\"props.variant === 'sidebar' ? (direction === 'rtl' ? 'left' : 'right') : 'bottom'\"\n class=\"w-80 p-0 sm:w-96\"\n >\n <div class=\"flex items-center justify-between border-b px-3 py-2\">\n <span class=\"text-sm font-semibold\">{{ t('notifications', {}, 'Notifications') }}</span>\n <div class=\"flex items-center gap-1\">\n <Button\n v-if=\"state.unreadCount > 0\"\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n :title=\"t('mark_all_read', {}, 'Mark all as read')\"\n @click=\"void center.markAllAsRead()\"\n ><CheckCheckIcon\n /></Button>\n <Button\n v-if=\"state.notifications.length > 0\"\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n :title=\"t('clear_notifications', {}, 'Clear notifications')\"\n @click=\"void center.clear()\"\n ><Trash2Icon\n /></Button>\n </div>\n </div>\n <ScrollArea class=\"max-h-96\">\n <div\n v-if=\"state.loading && state.notifications.length === 0\"\n class=\"flex justify-center py-8\"\n >\n <Spinner />\n </div>\n <p\n v-else-if=\"state.notifications.length === 0\"\n class=\"text-muted-foreground px-3 py-8 text-center text-sm\"\n >\n {{ t('no_notifications', {}, 'You have no notifications.') }}\n </p>\n <ul v-else class=\"divide-y\">\n <li\n v-for=\"notification in state.notifications\"\n :key=\"notification.id\"\n :class=\"cn('flex gap-3 px-3 py-3', !notification.readAt && 'bg-primary/5')\"\n :style=\"\n notification.color\n ? notificationTintStyles(cssColor(notification.color)).item\n : undefined\n \"\n >\n <Icon\n v-if=\"notification.icon\"\n :name=\"notification.icon\"\n :class=\"\n cn(\n 'mt-0.5 size-5 shrink-0',\n notification.iconColor && textColorClasses[notification.iconColor],\n )\n \"\n />\n <div class=\"flex min-w-0 flex-1 flex-col gap-1\">\n <div class=\"flex items-start justify-between gap-2\">\n <p class=\"text-sm font-medium\">{{ notification.title }}</p>\n <button\n v-if=\"!notification.readAt\"\n type=\"button\"\n class=\"focus-visible:ring-ring/50 -me-2 -mt-0.5 flex size-6 shrink-0 items-center justify-center rounded-full outline-none focus-visible:ring-[3px]\"\n :aria-label=\"t('mark_as_read', {}, 'Mark as read')\"\n @click=\"void center.markAsRead(notification.id)\"\n >\n <span class=\"bg-primary size-2 rounded-full\" aria-hidden=\"true\" />\n </button>\n </div>\n <p\n v-if=\"notification.body\"\n class=\"text-muted-foreground text-sm\"\n v-html=\"notification.body\"\n />\n <time v-if=\"notification.date\" class=\"text-muted-foreground text-xs\">{{\n format.relative(notification.date)\n }}</time>\n <div v-if=\"notification.actions\" class=\"flex flex-wrap gap-1\">\n <NotificationActionButton\n v-for=\"action in notification.actions\"\n :key=\"action.name\"\n :action=\"action\"\n :on-mark-as-read=\"() => void center!.markAsRead(notification.id)\"\n :on-mark-as-unread=\"() => void center!.markAsUnread(notification.id)\"\n />\n </div>\n </div>\n </li>\n </ul>\n <div\n v-if=\"state.hasMore && state.notifications.length > 0\"\n class=\"flex justify-center border-t p-2\"\n >\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n :disabled=\"state.loading\"\n @click=\"void center!.loadMore()\"\n >\n <Spinner v-if=\"state.loading\" />\n {{ t('load_more', {}, 'Load more') }}\n </Button>\n </div>\n </ScrollArea>\n </PopoverContent>\n </Popover>\n</template>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NotificationsMenu.vue.d.ts","sourceRoot":"","sources":["../../../src/components/notifications/NotificationsMenu.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"NotificationsMenu.vue.d.ts","sourceRoot":"","sources":["../../../src/components/notifications/NotificationsMenu.vue"],"names":[],"mappings":"AAyRA;;;;GAIG;AACH,KAAK,WAAW,GAAG;IAAE,OAAO,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAA;CAAE,CAAC;;aAAvB,QAAQ,GAAG,SAAS;;AAomBnD,wBAOG"}
|
package/dist/components/notifications/NotificationsMenu.vue_vue_type_script_setup_true_lang.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useDirection as e, useFormatter as t, usePanel as ee, useT as te } from "../../context.js";
|
|
2
2
|
import { cn as n } from "../../lib/utils.js";
|
|
3
|
-
import { useStore as
|
|
4
|
-
import { cssColor as
|
|
3
|
+
import { useStore as ne } from "../../composables/use-store.js";
|
|
4
|
+
import { cssColor as r, textColorClasses as i } from "../../lib/colors.js";
|
|
5
5
|
import a from "../../lib/Icon.js";
|
|
6
6
|
import o from "../ui/Button2.js";
|
|
7
7
|
import s from "../ui/Spinner.js";
|
|
@@ -10,8 +10,8 @@ import c from "../ui/Popover.js";
|
|
|
10
10
|
import l from "../ui/PopoverContent.js";
|
|
11
11
|
import u from "../ui/PopoverTrigger.js";
|
|
12
12
|
import d from "../ui/ScrollArea.js";
|
|
13
|
-
import { NotificationCenter as
|
|
14
|
-
import { Fragment as
|
|
13
|
+
import { NotificationCenter as f, notificationTintStyles as ie, onDatabaseNotificationsSent as ae, onOpenDatabaseNotifications as oe } from "@alfakit/core";
|
|
14
|
+
import { Fragment as p, computed as se, createBlock as m, createCommentVNode as h, createElementBlock as g, createElementVNode as _, createTextVNode as v, createVNode as y, defineComponent as b, normalizeClass as x, normalizeStyle as ce, onMounted as S, onScopeDispose as C, openBlock as w, ref as le, renderList as T, toDisplayString as E, unref as D, watch as O, withCtx as k } from "vue";
|
|
15
15
|
import { BellIcon as A, CheckCheckIcon as j, Trash2Icon as M } from "@lucide/vue";
|
|
16
16
|
//#region src/components/notifications/NotificationsMenu.vue?vue&type=script&setup=true&lang.ts
|
|
17
17
|
var N = { class: "flex-1 text-start group-data-[collapsible=icon]:sr-only" }, P = {
|
|
@@ -38,15 +38,15 @@ var N = { class: "flex-1 text-start group-data-[collapsible=icon]:sr-only" }, P
|
|
|
38
38
|
}, ge = {
|
|
39
39
|
key: 3,
|
|
40
40
|
class: "flex justify-center border-t p-2"
|
|
41
|
-
}, W = /*@__PURE__*/
|
|
41
|
+
}, W = /*@__PURE__*/ b({
|
|
42
42
|
__name: "NotificationsMenu",
|
|
43
43
|
props: { variant: { default: "topbar" } },
|
|
44
|
-
setup(
|
|
45
|
-
let W =
|
|
44
|
+
setup(b) {
|
|
45
|
+
let W = b, G = te(), _e = e(), K = ee(), q = se(() => K.value.databaseNotifications), J = K.value.endpoints, Y = J.notifications && J.notificationsReadAll && J.notificationsDestroyAll ? new f({
|
|
46
46
|
notifications: J.notifications,
|
|
47
47
|
notificationsReadAll: J.notificationsReadAll,
|
|
48
48
|
notificationsDestroyAll: J.notificationsDestroyAll
|
|
49
|
-
}, q.value?.unreadCount ?? 0) : null, X = le(!1), Z =
|
|
49
|
+
}, q.value?.unreadCount ?? 0) : null, X = le(!1), Z = ne(Y?.store ?? {
|
|
50
50
|
get: () => ({
|
|
51
51
|
notifications: [],
|
|
52
52
|
unreadCount: 0,
|
|
@@ -60,23 +60,25 @@ var N = { class: "flex-1 text-start group-data-[collapsible=icon]:sr-only" }, P
|
|
|
60
60
|
O(() => q.value?.pollingInterval, (e) => Y?.startPolling(e), { immediate: !0 });
|
|
61
61
|
}), O(X, (e) => {
|
|
62
62
|
e && Y?.load();
|
|
63
|
+
}), O(() => q.value?.unreadCount, (e) => {
|
|
64
|
+
Y && typeof e == "number" && e !== Y.store.get().unreadCount && Y.store.update({ unreadCount: e });
|
|
63
65
|
});
|
|
64
66
|
let Q = null;
|
|
65
67
|
S(() => {
|
|
66
|
-
Q = Y ?
|
|
68
|
+
Q = Y ? ae(() => void Y.load()) : null;
|
|
67
69
|
}), C(() => Q?.());
|
|
68
70
|
let $ = null;
|
|
69
71
|
S(() => {
|
|
70
|
-
$ =
|
|
72
|
+
$ = oe(() => X.value = !0);
|
|
71
73
|
}), C(() => $?.()), C(() => Y?.stopPolling());
|
|
72
74
|
let ve = t();
|
|
73
|
-
return (e, t) => q.value && D(Y) ? (w(),
|
|
75
|
+
return (e, t) => q.value && D(Y) ? (w(), m(c, {
|
|
74
76
|
key: 0,
|
|
75
77
|
open: X.value,
|
|
76
78
|
"onUpdate:open": t[3] ||= (e) => X.value = e
|
|
77
79
|
}, {
|
|
78
|
-
default: k(() => [
|
|
79
|
-
default: k(() => [W.variant === "sidebar" ? (w(),
|
|
80
|
+
default: k(() => [y(u, { "as-child": "" }, {
|
|
81
|
+
default: k(() => [W.variant === "sidebar" ? (w(), m(o, {
|
|
80
82
|
key: 0,
|
|
81
83
|
type: "button",
|
|
82
84
|
variant: "ghost",
|
|
@@ -85,15 +87,15 @@ var N = { class: "flex-1 text-start group-data-[collapsible=icon]:sr-only" }, P
|
|
|
85
87
|
"data-variant": "sidebar"
|
|
86
88
|
}, {
|
|
87
89
|
default: k(() => [
|
|
88
|
-
|
|
90
|
+
y(D(a), {
|
|
89
91
|
name: "alfakit::panels.topbar.open-database-notifications-button",
|
|
90
92
|
fallback: D(A)
|
|
91
93
|
}, null, 8, ["fallback"]),
|
|
92
|
-
|
|
93
|
-
D(Z).unreadCount > 0 ? (w(),
|
|
94
|
+
_("span", N, E(D(G)("notifications", {}, "Notifications")), 1),
|
|
95
|
+
D(Z).unreadCount > 0 ? (w(), g("span", P, [v(E(D(Z).unreadCount > 99 ? "99+" : D(Z).unreadCount) + " ", 1), _("span", F, E(D(G)("unread_notifications", {}, "unread")), 1)])) : h("", !0)
|
|
94
96
|
]),
|
|
95
97
|
_: 1
|
|
96
|
-
})) : (w(),
|
|
98
|
+
})) : (w(), m(o, {
|
|
97
99
|
key: 1,
|
|
98
100
|
type: "button",
|
|
99
101
|
variant: "ghost",
|
|
@@ -102,19 +104,19 @@ var N = { class: "flex-1 text-start group-data-[collapsible=icon]:sr-only" }, P
|
|
|
102
104
|
"data-slot": "notifications-trigger",
|
|
103
105
|
"aria-label": D(G)("notifications", {}, "Notifications")
|
|
104
106
|
}, {
|
|
105
|
-
default: k(() => [
|
|
107
|
+
default: k(() => [y(D(a), {
|
|
106
108
|
name: "alfakit::panels.topbar.open-database-notifications-button",
|
|
107
109
|
fallback: D(A)
|
|
108
|
-
}, null, 8, ["fallback"]), D(Z).unreadCount > 0 ? (w(),
|
|
110
|
+
}, null, 8, ["fallback"]), D(Z).unreadCount > 0 ? (w(), g("span", I, E(D(Z).unreadCount > 99 ? "99+" : D(Z).unreadCount), 1)) : h("", !0)]),
|
|
109
111
|
_: 1
|
|
110
112
|
}, 8, ["aria-label"]))]),
|
|
111
113
|
_: 1
|
|
112
|
-
}),
|
|
114
|
+
}), y(l, {
|
|
113
115
|
align: W.variant === "sidebar" ? "start" : "end",
|
|
114
116
|
side: W.variant === "sidebar" ? D(_e) === "rtl" ? "left" : "right" : "bottom",
|
|
115
117
|
class: "w-80 p-0 sm:w-96"
|
|
116
118
|
}, {
|
|
117
|
-
default: k(() => [
|
|
119
|
+
default: k(() => [_("div", L, [_("span", R, E(D(G)("notifications", {}, "Notifications")), 1), _("div", z, [D(Z).unreadCount > 0 ? (w(), m(o, {
|
|
118
120
|
key: 0,
|
|
119
121
|
type: "button",
|
|
120
122
|
variant: "ghost",
|
|
@@ -122,9 +124,9 @@ var N = { class: "flex-1 text-start group-data-[collapsible=icon]:sr-only" }, P
|
|
|
122
124
|
title: D(G)("mark_all_read", {}, "Mark all as read"),
|
|
123
125
|
onClick: t[0] ||= (e) => void D(Y).markAllAsRead()
|
|
124
126
|
}, {
|
|
125
|
-
default: k(() => [
|
|
127
|
+
default: k(() => [y(D(j))]),
|
|
126
128
|
_: 1
|
|
127
|
-
}, 8, ["title"])) :
|
|
129
|
+
}, 8, ["title"])) : h("", !0), D(Z).notifications.length > 0 ? (w(), m(o, {
|
|
128
130
|
key: 1,
|
|
129
131
|
type: "button",
|
|
130
132
|
variant: "ghost",
|
|
@@ -132,35 +134,35 @@ var N = { class: "flex-1 text-start group-data-[collapsible=icon]:sr-only" }, P
|
|
|
132
134
|
title: D(G)("clear_notifications", {}, "Clear notifications"),
|
|
133
135
|
onClick: t[1] ||= (e) => void D(Y).clear()
|
|
134
136
|
}, {
|
|
135
|
-
default: k(() => [
|
|
137
|
+
default: k(() => [y(D(M))]),
|
|
136
138
|
_: 1
|
|
137
|
-
}, 8, ["title"])) :
|
|
138
|
-
default: k(() => [D(Z).loading && D(Z).notifications.length === 0 ? (w(),
|
|
139
|
+
}, 8, ["title"])) : h("", !0)])]), y(d, { class: "max-h-96" }, {
|
|
140
|
+
default: k(() => [D(Z).loading && D(Z).notifications.length === 0 ? (w(), g("div", B, [y(s)])) : D(Z).notifications.length === 0 ? (w(), g("p", ue, E(D(G)("no_notifications", {}, "You have no notifications.")), 1)) : (w(), g("ul", V, [(w(!0), g(p, null, T(D(Z).notifications, (e) => (w(), g("li", {
|
|
139
141
|
key: e.id,
|
|
140
|
-
class:
|
|
141
|
-
style:
|
|
142
|
-
}, [e.icon ? (w(),
|
|
142
|
+
class: x(D(n)("flex gap-3 px-3 py-3", !e.readAt && "bg-primary/5")),
|
|
143
|
+
style: ce(e.color ? D(ie)(D(r)(e.color)).item : void 0)
|
|
144
|
+
}, [e.icon ? (w(), m(D(a), {
|
|
143
145
|
key: 0,
|
|
144
146
|
name: e.icon,
|
|
145
|
-
class:
|
|
146
|
-
}, null, 8, ["name", "class"])) :
|
|
147
|
-
|
|
147
|
+
class: x(D(n)("mt-0.5 size-5 shrink-0", e.iconColor && D(i)[e.iconColor]))
|
|
148
|
+
}, null, 8, ["name", "class"])) : h("", !0), _("div", H, [
|
|
149
|
+
_("div", U, [_("p", de, E(e.title), 1), e.readAt ? h("", !0) : (w(), g("button", {
|
|
148
150
|
key: 0,
|
|
149
151
|
type: "button",
|
|
150
152
|
class: "focus-visible:ring-ring/50 -me-2 -mt-0.5 flex size-6 shrink-0 items-center justify-center rounded-full outline-none focus-visible:ring-[3px]",
|
|
151
153
|
"aria-label": D(G)("mark_as_read", {}, "Mark as read"),
|
|
152
154
|
onClick: (t) => void D(Y).markAsRead(e.id)
|
|
153
|
-
}, [...t[4] ||= [
|
|
155
|
+
}, [...t[4] ||= [_("span", {
|
|
154
156
|
class: "bg-primary size-2 rounded-full",
|
|
155
157
|
"aria-hidden": "true"
|
|
156
158
|
}, null, -1)]], 8, fe))]),
|
|
157
|
-
e.body ? (w(),
|
|
159
|
+
e.body ? (w(), g("p", {
|
|
158
160
|
key: 0,
|
|
159
161
|
class: "text-muted-foreground text-sm",
|
|
160
162
|
innerHTML: e.body
|
|
161
|
-
}, null, 8, pe)) :
|
|
162
|
-
e.date ? (w(),
|
|
163
|
-
e.actions ? (w(),
|
|
163
|
+
}, null, 8, pe)) : h("", !0),
|
|
164
|
+
e.date ? (w(), g("time", me, E(D(ve).relative(e.date)), 1)) : h("", !0),
|
|
165
|
+
e.actions ? (w(), g("div", he, [(w(!0), g(p, null, T(e.actions, (t) => (w(), m(re, {
|
|
164
166
|
key: t.name,
|
|
165
167
|
action: t,
|
|
166
168
|
"on-mark-as-read": () => void D(Y).markAsRead(e.id),
|
|
@@ -169,23 +171,23 @@ var N = { class: "flex-1 text-start group-data-[collapsible=icon]:sr-only" }, P
|
|
|
169
171
|
"action",
|
|
170
172
|
"on-mark-as-read",
|
|
171
173
|
"on-mark-as-unread"
|
|
172
|
-
]))), 128))])) :
|
|
173
|
-
])], 6))), 128))])), D(Z).hasMore && D(Z).notifications.length > 0 ? (w(),
|
|
174
|
+
]))), 128))])) : h("", !0)
|
|
175
|
+
])], 6))), 128))])), D(Z).hasMore && D(Z).notifications.length > 0 ? (w(), g("div", ge, [y(o, {
|
|
174
176
|
type: "button",
|
|
175
177
|
variant: "ghost",
|
|
176
178
|
size: "sm",
|
|
177
179
|
disabled: D(Z).loading,
|
|
178
180
|
onClick: t[2] ||= (e) => void D(Y).loadMore()
|
|
179
181
|
}, {
|
|
180
|
-
default: k(() => [D(Z).loading ? (w(),
|
|
182
|
+
default: k(() => [D(Z).loading ? (w(), m(s, { key: 0 })) : h("", !0), v(" " + E(D(G)("load_more", {}, "Load more")), 1)]),
|
|
181
183
|
_: 1
|
|
182
|
-
}, 8, ["disabled"])])) :
|
|
184
|
+
}, 8, ["disabled"])])) : h("", !0)]),
|
|
183
185
|
_: 1
|
|
184
186
|
})]),
|
|
185
187
|
_: 1
|
|
186
188
|
}, 8, ["align", "side"])]),
|
|
187
189
|
_: 1
|
|
188
|
-
}, 8, ["open"])) :
|
|
190
|
+
}, 8, ["open"])) : h("", !0);
|
|
189
191
|
}
|
|
190
192
|
});
|
|
191
193
|
//#endregion
|
package/dist/components/notifications/NotificationsMenu.vue_vue_type_script_setup_true_lang.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NotificationsMenu.vue_vue_type_script_setup_true_lang.js","names":["_unref","_openBlock","_createBlock","Popover","_withCtx","_createVNode","PopoverTrigger","Button","Icon","_createElementVNode","_toDisplayString","_createElementBlock","_createTextVNode","_createCommentVNode","PopoverContent","ScrollArea","Spinner","_Fragment","_renderList","_normalizeClass","_normalizeStyle","NotificationActionButton","Icon_default","Button_default","Spinner_default","NotificationActionButton_default","Popover_default","PopoverContent_default","PopoverTrigger_default","ScrollArea_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_18","NotificationsMenu_vue_vue_type_script_setup_true_lang_default","props","__props","t","useT","direction","useDirection","panel","usePanel","config","computed","endpoints","center","NotificationCenter","open","ref","state","useStore","onMounted","interval","watch","isOpen","stopListening","onDatabaseNotificationsSent","onScopeDispose","stopOpenListener","onOpenDatabaseNotifications","format","useFormatter","unref","openBlock","createBlock","_cache","$event","withCtx","createVNode","BellIcon","createElementVNode","toDisplayString","createElementBlock","createTextVNode","createCommentVNode","CheckCheckIcon","Trash2Icon","Fragment","renderList","notification","normalizeClass","cn","normalizeStyle","notificationTintStyles","cssColor","textColorClasses","action"],"sources":["../../../src/components/notifications/NotificationsMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n NotificationCenter,\n notificationTintStyles,\n onDatabaseNotificationsSent,\n onOpenDatabaseNotifications,\n} from '@alfakit/core'\nimport { BellIcon, CheckCheckIcon, Trash2Icon } from '@lucide/vue'\nimport { computed, onMounted, onScopeDispose, ref, watch } from 'vue'\nimport { useStore } from '../../composables/use-store'\nimport { useDirection, useFormatter, usePanel, useT } from '../../context'\nimport { cssColor, textColorClasses } from '../../lib/colors'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport Button from '../ui/Button.vue'\nimport Popover from '../ui/Popover.vue'\nimport PopoverContent from '../ui/PopoverContent.vue'\nimport PopoverTrigger from '../ui/PopoverTrigger.vue'\nimport ScrollArea from '../ui/ScrollArea.vue'\nimport Spinner from '../ui/Spinner.vue'\nimport NotificationActionButton from './NotificationActionButton.vue'\n\n/**\n * Bell menu for database notifications. It also opens when something calls\n * `openDatabaseNotifications()` (or an action with `->openDatabaseNotifications()`).\n * `variant=\"sidebar\"`: a full-width row with a label, for layouts that put it in the sidebar.\n */\nconst props = withDefaults(defineProps<{ variant?: 'topbar' | 'sidebar' }>(), {\n variant: 'topbar',\n})\nconst t = useT()\nconst direction = useDirection()\nconst panel = usePanel()\nconst config = computed(() => panel.value.databaseNotifications)\nconst endpoints = panel.value.endpoints\n\nconst center =\n endpoints.notifications && endpoints.notificationsReadAll && endpoints.notificationsDestroyAll\n ? new NotificationCenter(\n {\n notifications: endpoints.notifications,\n notificationsReadAll: endpoints.notificationsReadAll,\n notificationsDestroyAll: endpoints.notificationsDestroyAll,\n },\n config.value?.unreadCount ?? 0,\n )\n : null\n\nconst open = ref(false)\nconst state = useStore(\n center?.store ?? {\n get: () => ({ notifications: [], unreadCount: 0, loading: false, hasMore: false, page: 0 }),\n subscribe: () => () => {},\n },\n)\n\n// Polling starts in the browser only: a server render must not leave timers behind.\nonMounted(() => {\n watch(\n () => config.value?.pollingInterval,\n (interval) => center?.startPolling(interval),\n { immediate: true },\n )\n})\n\nwatch(open, (isOpen) => {\n if (isOpen) void center?.load()\n})\n\n// Realtime notifications announce stored ones, so the unread count updates right away.\nlet stopListening: (() => void) | null = null\nonMounted(() => {\n stopListening = center ? onDatabaseNotificationsSent(() => void center.load()) : null\n})\nonScopeDispose(() => stopListening?.())\n\n// `openDatabaseNotifications()`: opened from code or an action.\nlet stopOpenListener: (() => void) | null = null\nonMounted(() => {\n stopOpenListener = onOpenDatabaseNotifications(() => (open.value = true))\n})\nonScopeDispose(() => stopOpenListener?.())\n\nonScopeDispose(() => center?.stopPolling())\nconst format = useFormatter()\n</script>\n\n<template>\n <Popover v-if=\"config && center\" :open=\"open\" @update:open=\"open = $event\">\n <PopoverTrigger as-child>\n <Button\n v-if=\"props.variant === 'sidebar'\"\n type=\"button\"\n variant=\"ghost\"\n class=\"relative w-full justify-start gap-2 group-data-[collapsible=icon]:size-8 group-data-[collapsible=icon]:justify-center group-data-[collapsible=icon]:p-0\"\n data-slot=\"notifications-trigger\"\n data-variant=\"sidebar\"\n >\n <!-- In a collapsed (icon) sidebar only the bell and its badge stay visible. -->\n <Icon\n name=\"alfakit::panels.topbar.open-database-notifications-button\"\n :fallback=\"BellIcon\"\n />\n <span class=\"flex-1 text-start group-data-[collapsible=icon]:sr-only\">{{\n t('notifications', {}, 'Notifications')\n }}</span>\n <span\n v-if=\"state.unreadCount > 0\"\n class=\"bg-primary text-primary-foreground flex h-5 min-w-5 items-center justify-center rounded-full px-1 text-xs font-medium group-data-[collapsible=icon]:absolute group-data-[collapsible=icon]:-end-1 group-data-[collapsible=icon]:-top-1 group-data-[collapsible=icon]:h-4 group-data-[collapsible=icon]:min-w-4 group-data-[collapsible=icon]:text-[10px]\"\n >{{ state.unreadCount > 99 ? '99+' : state.unreadCount }}\n <span class=\"sr-only\">{{ t('unread_notifications', {}, 'unread') }}</span></span\n >\n </Button>\n <Button\n v-else\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n class=\"relative\"\n data-slot=\"notifications-trigger\"\n :aria-label=\"t('notifications', {}, 'Notifications')\"\n >\n <Icon\n name=\"alfakit::panels.topbar.open-database-notifications-button\"\n :fallback=\"BellIcon\"\n />\n <span\n v-if=\"state.unreadCount > 0\"\n class=\"bg-primary text-primary-foreground absolute -end-0.5 -top-0.5 flex h-4 min-w-4 items-center justify-center rounded-full px-1 text-[10px] font-medium\"\n >{{ state.unreadCount > 99 ? '99+' : state.unreadCount }}</span\n >\n </Button>\n </PopoverTrigger>\n <PopoverContent\n :align=\"props.variant === 'sidebar' ? 'start' : 'end'\"\n :side=\"props.variant === 'sidebar' ? (direction === 'rtl' ? 'left' : 'right') : 'bottom'\"\n class=\"w-80 p-0 sm:w-96\"\n >\n <div class=\"flex items-center justify-between border-b px-3 py-2\">\n <span class=\"text-sm font-semibold\">{{ t('notifications', {}, 'Notifications') }}</span>\n <div class=\"flex items-center gap-1\">\n <Button\n v-if=\"state.unreadCount > 0\"\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n :title=\"t('mark_all_read', {}, 'Mark all as read')\"\n @click=\"void center.markAllAsRead()\"\n ><CheckCheckIcon\n /></Button>\n <Button\n v-if=\"state.notifications.length > 0\"\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n :title=\"t('clear_notifications', {}, 'Clear notifications')\"\n @click=\"void center.clear()\"\n ><Trash2Icon\n /></Button>\n </div>\n </div>\n <ScrollArea class=\"max-h-96\">\n <div\n v-if=\"state.loading && state.notifications.length === 0\"\n class=\"flex justify-center py-8\"\n >\n <Spinner />\n </div>\n <p\n v-else-if=\"state.notifications.length === 0\"\n class=\"text-muted-foreground px-3 py-8 text-center text-sm\"\n >\n {{ t('no_notifications', {}, 'You have no notifications.') }}\n </p>\n <ul v-else class=\"divide-y\">\n <li\n v-for=\"notification in state.notifications\"\n :key=\"notification.id\"\n :class=\"cn('flex gap-3 px-3 py-3', !notification.readAt && 'bg-primary/5')\"\n :style=\"\n notification.color\n ? notificationTintStyles(cssColor(notification.color)).item\n : undefined\n \"\n >\n <Icon\n v-if=\"notification.icon\"\n :name=\"notification.icon\"\n :class=\"\n cn(\n 'mt-0.5 size-5 shrink-0',\n notification.iconColor && textColorClasses[notification.iconColor],\n )\n \"\n />\n <div class=\"flex min-w-0 flex-1 flex-col gap-1\">\n <div class=\"flex items-start justify-between gap-2\">\n <p class=\"text-sm font-medium\">{{ notification.title }}</p>\n <button\n v-if=\"!notification.readAt\"\n type=\"button\"\n class=\"focus-visible:ring-ring/50 -me-2 -mt-0.5 flex size-6 shrink-0 items-center justify-center rounded-full outline-none focus-visible:ring-[3px]\"\n :aria-label=\"t('mark_as_read', {}, 'Mark as read')\"\n @click=\"void center.markAsRead(notification.id)\"\n >\n <span class=\"bg-primary size-2 rounded-full\" aria-hidden=\"true\" />\n </button>\n </div>\n <p\n v-if=\"notification.body\"\n class=\"text-muted-foreground text-sm\"\n v-html=\"notification.body\"\n />\n <time v-if=\"notification.date\" class=\"text-muted-foreground text-xs\">{{\n format.relative(notification.date)\n }}</time>\n <div v-if=\"notification.actions\" class=\"flex flex-wrap gap-1\">\n <NotificationActionButton\n v-for=\"action in notification.actions\"\n :key=\"action.name\"\n :action=\"action\"\n :on-mark-as-read=\"() => void center!.markAsRead(notification.id)\"\n :on-mark-as-unread=\"() => void center!.markAsUnread(notification.id)\"\n />\n </div>\n </div>\n </li>\n </ul>\n <div\n v-if=\"state.hasMore && state.notifications.length > 0\"\n class=\"flex justify-center border-t p-2\"\n >\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n :disabled=\"state.loading\"\n @click=\"void center!.loadMore()\"\n >\n <Spinner v-if=\"state.loading\" />\n {{ t('load_more', {}, 'Load more') }}\n </Button>\n </div>\n </ScrollArea>\n </PopoverContent>\n </Popover>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"NotificationsMenu.vue_vue_type_script_setup_true_lang.js","names":["_unref","_openBlock","_createBlock","Popover","_withCtx","_createVNode","PopoverTrigger","Button","Icon","_createElementVNode","_toDisplayString","_createElementBlock","_createTextVNode","_createCommentVNode","PopoverContent","ScrollArea","Spinner","_Fragment","_renderList","_normalizeClass","_normalizeStyle","NotificationActionButton","Icon_default","Button_default","Spinner_default","NotificationActionButton_default","Popover_default","PopoverContent_default","PopoverTrigger_default","ScrollArea_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_18","NotificationsMenu_vue_vue_type_script_setup_true_lang_default","props","__props","t","useT","direction","useDirection","panel","usePanel","config","computed","endpoints","center","NotificationCenter","open","ref","state","useStore","onMounted","interval","watch","isOpen","count","stopListening","onDatabaseNotificationsSent","onScopeDispose","stopOpenListener","onOpenDatabaseNotifications","format","useFormatter","unref","openBlock","createBlock","_cache","$event","withCtx","createVNode","BellIcon","createElementVNode","toDisplayString","createElementBlock","createTextVNode","createCommentVNode","CheckCheckIcon","Trash2Icon","Fragment","renderList","notification","normalizeClass","cn","normalizeStyle","notificationTintStyles","cssColor","textColorClasses","action"],"sources":["../../../src/components/notifications/NotificationsMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n NotificationCenter,\n notificationTintStyles,\n onDatabaseNotificationsSent,\n onOpenDatabaseNotifications,\n} from '@alfakit/core'\nimport { BellIcon, CheckCheckIcon, Trash2Icon } from '@lucide/vue'\nimport { computed, onMounted, onScopeDispose, ref, watch } from 'vue'\nimport { useStore } from '../../composables/use-store'\nimport { useDirection, useFormatter, usePanel, useT } from '../../context'\nimport { cssColor, textColorClasses } from '../../lib/colors'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport Button from '../ui/Button.vue'\nimport Popover from '../ui/Popover.vue'\nimport PopoverContent from '../ui/PopoverContent.vue'\nimport PopoverTrigger from '../ui/PopoverTrigger.vue'\nimport ScrollArea from '../ui/ScrollArea.vue'\nimport Spinner from '../ui/Spinner.vue'\nimport NotificationActionButton from './NotificationActionButton.vue'\n\n/**\n * Bell menu for database notifications. It also opens when something calls\n * `openDatabaseNotifications()` (or an action with `->openDatabaseNotifications()`).\n * `variant=\"sidebar\"`: a full-width row with a label, for layouts that put it in the sidebar.\n */\nconst props = withDefaults(defineProps<{ variant?: 'topbar' | 'sidebar' }>(), {\n variant: 'topbar',\n})\nconst t = useT()\nconst direction = useDirection()\nconst panel = usePanel()\nconst config = computed(() => panel.value.databaseNotifications)\nconst endpoints = panel.value.endpoints\n\nconst center =\n endpoints.notifications && endpoints.notificationsReadAll && endpoints.notificationsDestroyAll\n ? new NotificationCenter(\n {\n notifications: endpoints.notifications,\n notificationsReadAll: endpoints.notificationsReadAll,\n notificationsDestroyAll: endpoints.notificationsDestroyAll,\n },\n config.value?.unreadCount ?? 0,\n )\n : null\n\nconst open = ref(false)\nconst state = useStore(\n center?.store ?? {\n get: () => ({ notifications: [], unreadCount: 0, loading: false, hasMore: false, page: 0 }),\n subscribe: () => () => {},\n },\n)\n\n// Polling starts in the browser only: a server render must not leave timers behind.\nonMounted(() => {\n watch(\n () => config.value?.pollingInterval,\n (interval) => center?.startPolling(interval),\n { immediate: true },\n )\n})\n\nwatch(open, (isOpen) => {\n if (isOpen) void center?.load()\n})\n\n// Every visit brings the server's unread count (another user after impersonating, or\n// notifications read in another tab): follow it instead of waiting for the next poll.\nwatch(\n () => config.value?.unreadCount,\n (count) => {\n if (center && typeof count === 'number' && count !== center.store.get().unreadCount) {\n center.store.update({ unreadCount: count })\n }\n },\n)\n\n// Realtime notifications announce stored ones, so the unread count updates right away.\nlet stopListening: (() => void) | null = null\nonMounted(() => {\n stopListening = center ? onDatabaseNotificationsSent(() => void center.load()) : null\n})\nonScopeDispose(() => stopListening?.())\n\n// `openDatabaseNotifications()`: opened from code or an action.\nlet stopOpenListener: (() => void) | null = null\nonMounted(() => {\n stopOpenListener = onOpenDatabaseNotifications(() => (open.value = true))\n})\nonScopeDispose(() => stopOpenListener?.())\n\nonScopeDispose(() => center?.stopPolling())\nconst format = useFormatter()\n</script>\n\n<template>\n <Popover v-if=\"config && center\" :open=\"open\" @update:open=\"open = $event\">\n <PopoverTrigger as-child>\n <Button\n v-if=\"props.variant === 'sidebar'\"\n type=\"button\"\n variant=\"ghost\"\n class=\"relative w-full justify-start gap-2 group-data-[collapsible=icon]:size-8 group-data-[collapsible=icon]:justify-center group-data-[collapsible=icon]:p-0\"\n data-slot=\"notifications-trigger\"\n data-variant=\"sidebar\"\n >\n <!-- In a collapsed (icon) sidebar only the bell and its badge stay visible. -->\n <Icon\n name=\"alfakit::panels.topbar.open-database-notifications-button\"\n :fallback=\"BellIcon\"\n />\n <span class=\"flex-1 text-start group-data-[collapsible=icon]:sr-only\">{{\n t('notifications', {}, 'Notifications')\n }}</span>\n <span\n v-if=\"state.unreadCount > 0\"\n class=\"bg-primary text-primary-foreground flex h-5 min-w-5 items-center justify-center rounded-full px-1 text-xs font-medium group-data-[collapsible=icon]:absolute group-data-[collapsible=icon]:-end-1 group-data-[collapsible=icon]:-top-1 group-data-[collapsible=icon]:h-4 group-data-[collapsible=icon]:min-w-4 group-data-[collapsible=icon]:text-[10px]\"\n >{{ state.unreadCount > 99 ? '99+' : state.unreadCount }}\n <span class=\"sr-only\">{{ t('unread_notifications', {}, 'unread') }}</span></span\n >\n </Button>\n <Button\n v-else\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n class=\"relative\"\n data-slot=\"notifications-trigger\"\n :aria-label=\"t('notifications', {}, 'Notifications')\"\n >\n <Icon\n name=\"alfakit::panels.topbar.open-database-notifications-button\"\n :fallback=\"BellIcon\"\n />\n <span\n v-if=\"state.unreadCount > 0\"\n class=\"bg-primary text-primary-foreground absolute -end-0.5 -top-0.5 flex h-4 min-w-4 items-center justify-center rounded-full px-1 text-[10px] font-medium\"\n >{{ state.unreadCount > 99 ? '99+' : state.unreadCount }}</span\n >\n </Button>\n </PopoverTrigger>\n <PopoverContent\n :align=\"props.variant === 'sidebar' ? 'start' : 'end'\"\n :side=\"props.variant === 'sidebar' ? (direction === 'rtl' ? 'left' : 'right') : 'bottom'\"\n class=\"w-80 p-0 sm:w-96\"\n >\n <div class=\"flex items-center justify-between border-b px-3 py-2\">\n <span class=\"text-sm font-semibold\">{{ t('notifications', {}, 'Notifications') }}</span>\n <div class=\"flex items-center gap-1\">\n <Button\n v-if=\"state.unreadCount > 0\"\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n :title=\"t('mark_all_read', {}, 'Mark all as read')\"\n @click=\"void center.markAllAsRead()\"\n ><CheckCheckIcon\n /></Button>\n <Button\n v-if=\"state.notifications.length > 0\"\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n :title=\"t('clear_notifications', {}, 'Clear notifications')\"\n @click=\"void center.clear()\"\n ><Trash2Icon\n /></Button>\n </div>\n </div>\n <ScrollArea class=\"max-h-96\">\n <div\n v-if=\"state.loading && state.notifications.length === 0\"\n class=\"flex justify-center py-8\"\n >\n <Spinner />\n </div>\n <p\n v-else-if=\"state.notifications.length === 0\"\n class=\"text-muted-foreground px-3 py-8 text-center text-sm\"\n >\n {{ t('no_notifications', {}, 'You have no notifications.') }}\n </p>\n <ul v-else class=\"divide-y\">\n <li\n v-for=\"notification in state.notifications\"\n :key=\"notification.id\"\n :class=\"cn('flex gap-3 px-3 py-3', !notification.readAt && 'bg-primary/5')\"\n :style=\"\n notification.color\n ? notificationTintStyles(cssColor(notification.color)).item\n : undefined\n \"\n >\n <Icon\n v-if=\"notification.icon\"\n :name=\"notification.icon\"\n :class=\"\n cn(\n 'mt-0.5 size-5 shrink-0',\n notification.iconColor && textColorClasses[notification.iconColor],\n )\n \"\n />\n <div class=\"flex min-w-0 flex-1 flex-col gap-1\">\n <div class=\"flex items-start justify-between gap-2\">\n <p class=\"text-sm font-medium\">{{ notification.title }}</p>\n <button\n v-if=\"!notification.readAt\"\n type=\"button\"\n class=\"focus-visible:ring-ring/50 -me-2 -mt-0.5 flex size-6 shrink-0 items-center justify-center rounded-full outline-none focus-visible:ring-[3px]\"\n :aria-label=\"t('mark_as_read', {}, 'Mark as read')\"\n @click=\"void center.markAsRead(notification.id)\"\n >\n <span class=\"bg-primary size-2 rounded-full\" aria-hidden=\"true\" />\n </button>\n </div>\n <p\n v-if=\"notification.body\"\n class=\"text-muted-foreground text-sm\"\n v-html=\"notification.body\"\n />\n <time v-if=\"notification.date\" class=\"text-muted-foreground text-xs\">{{\n format.relative(notification.date)\n }}</time>\n <div v-if=\"notification.actions\" class=\"flex flex-wrap gap-1\">\n <NotificationActionButton\n v-for=\"action in notification.actions\"\n :key=\"action.name\"\n :action=\"action\"\n :on-mark-as-read=\"() => void center!.markAsRead(notification.id)\"\n :on-mark-as-unread=\"() => void center!.markAsUnread(notification.id)\"\n />\n </div>\n </div>\n </li>\n </ul>\n <div\n v-if=\"state.hasMore && state.notifications.length > 0\"\n class=\"flex justify-center border-t p-2\"\n >\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n :disabled=\"state.loading\"\n @click=\"void center!.loadMore()\"\n >\n <Spinner v-if=\"state.loading\" />\n {{ t('load_more', {}, 'Load more') }}\n </Button>\n </div>\n </ScrollArea>\n </PopoverContent>\n </Popover>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2BA,IAAMiD,IAAQC,GAGRC,IAAIC,GAAK,GACTC,KAAYC,EAAa,GACzBC,IAAQC,GAAS,GACjBC,IAASC,SAAeH,EAAM,MAAM,qBAAqB,GACzDI,IAAYJ,EAAM,MAAM,WAExBK,IACJD,EAAU,iBAAiBA,EAAU,wBAAwBA,EAAU,0BACnE,IAAIE,EACF;GACE,eAAeF,EAAU;GACzB,sBAAsBA,EAAU;GAChC,yBAAyBA,EAAU;EACrC,GACAF,EAAO,OAAO,eAAe,CAC/B,IACA,MAEAK,IAAOC,GAAI,EAAK,GAChBC,IAAQC,GACZL,GAAQ,SAAS;GACf,YAAY;IAAE,eAAe,CAAC;IAAG,aAAa;IAAG,SAAS;IAAO,SAAS;IAAO,MAAM;GAAE;GACzF,uBAAuB,CAAC;EAC1B,CACF;EAiBA,AAdAM,QAAgB;GACd,QACQT,EAAO,OAAO,kBACnB,MAAaG,GAAQ,aAAaO,CAAQ,GAC3C,EAAE,WAAW,GAAK,CACpB;EACF,CAAC,GAEDC,EAAMN,IAAO,MAAW;GACtB,AAAIO,KAAQT,GAAa,KAAK;EAChC,CAAC,GAIDQ,QACQX,EAAO,OAAO,cACnB,MAAU;GACT,AAAIG,KAAU,OAAOU,KAAU,YAAYA,MAAUV,EAAO,MAAM,IAAI,CAAC,CAAC,eACtEA,EAAO,MAAM,OAAO,EAAE,aAAaU,EAAM,CAAC;EAE9C,CACF;EAGA,IAAIC,IAAqC;EAIzC,AAHAL,QAAgB;GACd,IAAgBN,IAASY,SAAkC,KAAKZ,EAAO,KAAK,CAAC,IAAI;EACnF,CAAC,GACDa,QAAqBF,IAAgB,CAAC;EAGtC,IAAIG,IAAwC;EAM5C,AALAR,QAAgB;GACd,IAAmBS,SAAmC,EAAK,QAAQ,EAAK;EAC1E,CAAC,GACDF,QAAqBC,IAAmB,CAAC,GAEzCD,QAAqBb,GAAQ,YAAY,CAAC;EAC1C,IAAMgB,KAASC,EAAa;mBAIXpB,EAAA,SAAUzD,EAAA4D,CAAA,KAAzB3D,EAAA,GAAAC,EA6JUC,GAAA;;GA7JwB,MAAM2D,EAAA;GAAO,iBAAW,AAAAmB,EAAA,QAAA,MAAE,EAAA,QAAOC;;GACjE,SAAA9E,QA2CiB,CA3CjBC,EA2CiBC,GAAA,EA3CD,YAAA,GAAQ,GAAA;IACtB,SAAAF,QAsBS,CArBD6C,EAAM,YAAO,aADrBhD,EAAA,GAAAC,EAsBSK,GAAA;;KApBP,MAAK;KACL,SAAQ;KACR,OAAM;KACN,aAAU;KACV,gBAAa;;KAGb,SAAAH,QAGE;MAHFC,EAGEL,EAAAQ,CAAA,GAAA;OAFA,MAAK;OACJ,UAAUR,EAAAqF,CAAA;;MAEb5E,EAES,QAFTqB,GAESpB,EADPV,EAAAmD,CAAA,CAAC,CAAA,iBAAA,CAAA,GAAA,eAAA,CAAA,GAAA,CAAA;MAGKnD,EAAAgE,CAAA,CAAK,CAAC,cAAW,KADzB/D,EAAA,GAAAU,EAKC,QALDoB,GAKC,CAFKnB,EAAAF,EAAAV,EAAAgE,CAAA,CAAK,CAAC,cAAW,KAAA,QAAgBhE,EAAAgE,CAAA,CAAK,CAAC,WAAW,IAAG,KACzD,CAAA,GAAAvD,EAA0E,QAA1EuB,GAA0EtB,EAAjDV,EAAAmD,CAAA,CAAC,CAAA,wBAAA,CAAA,GAAA,QAAA,CAAA,GAAA,CAAA,CAAA,CAAA,KAAAuC,EAAA,IAAA,EAAA;;;IAG9BzF,CAAAA,MAAAA,EAAA,GAAAC,EAkBSK,GAAA;;KAhBP,MAAK;KACL,SAAQ;KACR,MAAK;KACL,OAAM;KACN,aAAU;KACT,cAAYP,EAAAmD,CAAA,CAAC,CAAA,iBAAA,CAAA,GAAA,eAAA;;KAEd,SAAA/C,QAGE,CAHFC,EAGEL,EAAAQ,CAAA,GAAA;MAFA,MAAK;MACJ,UAAUR,EAAAqF,CAAA;KAGLrF,GAAAA,MAAAA,GAAAA,CAAAA,UAAAA,CAAAA,GAAAA,EAAAgE,CAAA,CAAK,CAAC,cAAW,KADzB/D,EAAA,GAAAU,EAIC,QAJDsB,GAICvB,EADKV,EAAAgE,CAAA,CAAK,CAAC,cAAW,KAAA,QAAgBhE,EAAAgE,CAAA,CAAK,CAAC,WAAW,GAAA,CAAA,KAAA0B,EAAA,IAAA,EAAA,CAAA,CAAA;;;;GAI5DrF,CAAAA,GAAAA,EA+GiBS,GAAA;IA9Gd,OAAOmC,EAAM,YAAO,YAAA,UAAA;IACpB,MAAMA,EAAM,YAAO,YAAkBjD,EAAAqD,EAAA,MAAS,QAAA,SAAA,UAAA;IAC/C,OAAM;;IAEN,SAAAjD,QAsBM,CAtBNK,EAsBM,OAtBNyB,GAsBM,CArBJzB,EAAwF,QAAxF0B,GAAwFzB,EAAjDV,EAAAmD,CAAA,CAAC,CAAA,iBAAA,CAAA,GAAA,eAAA,CAAA,GAAA,CAAA,GACxC1C,EAmBM,OAnBN2B,GAmBM,CAjBIpC,EAAAgE,CAAA,CAAK,CAAC,cAAW,KADzB/D,EAAA,GAAAC,EAQWK,GAAA;;KANT,MAAK;KACL,SAAQ;KACR,MAAK;KACJ,OAAOP,EAAAmD,CAAA,CAAC,CAAA,iBAAA,CAAA,GAAA,kBAAA;KACR,SAAK,AAAA8B,EAAA,QAAA,MAAA,KAAOjF,EAAA4D,CAAA,CAAM,CAAC,cAAa;;KAChC,SAAAxD,QACD,CADCC,EACDL,EAAA2F,CAAA,CAAA,CAAA,CAAA;;IAEM3F,GAAAA,GAAAA,CAAAA,OAAAA,CAAAA,KAAAA,EAAAA,IAAAA,EAAAA,GAAAA,EAAAgE,CAAA,CAAK,CAAC,cAAc,SAAM,KADlC/D,EAAA,GAAAC,EAQWK,GAAA;;KANT,MAAK;KACL,SAAQ;KACR,MAAK;KACJ,OAAOP,EAAAmD,CAAA,CAAC,CAAA,uBAAA,CAAA,GAAA,qBAAA;KACR,SAAK,AAAA8B,EAAA,QAAA,MAAA,KAAOjF,EAAA4D,CAAA,CAAM,CAAC,MAAK;;KACxB,SAAAxD,QACD,CADCC,EACDL,EAAA4F,CAAA,CAAA,CAAA,CAAA;;IAGNvF,GAAAA,GAAAA,CAAAA,OAAAA,CAAAA,KAAAA,EAAAA,IAAAA,EAAAA,CAAAA,CAAAA,CAAAA,CAAAA,GAAAA,EAkFaU,GAAA,EAlFD,OAAM,WAAU,GAAA;KAC1B,SAAAX,QAKM,CAJEJ,EAAAgE,CAAA,CAAK,CAAC,WAAWhE,EAAAgE,CAAA,CAAK,CAAC,cAAc,WAAM,KADnD/D,EAAA,GAAAU,EAKM,OALN0B,GAKM,CADJhC,EAAWW,CAAA,CAAA,CAAA,KAGAhB,EAAAgE,CAAA,CAAK,CAAC,cAAc,WAAM,KADvC/D,EAAA,GAAAU,EAKI,KALJ2B,IAKI5B,EADCV,EAAAmD,CAAA,CAAC,CAAA,oBAAA,CAAA,GAAA,4BAAA,CAAA,GAAA,CAAA,MAENlD,EAAA,GAAAU,EAqDK,MArDL4B,GAqDK,EApDHtC,EAAA,EAAA,GAAAU,EAmDKM,GAAA,MAAAC,EAlDoBlB,EAAAgE,CAAA,CAAK,CAAC,gBAAtB,OADT/D,EAAA,GAAAU,EAmDK,MAAA;MAjDF,KAAKoF,EAAa;MAClB,OAAK5E,EAAEnB,EAAAiG,CAAA,CAAE,CAAA,wBAAA,CAA0BF,EAAa,UAAM,cAAA,CAAA;MACtD,OAAK3E,GAAiB2E,EAAa,QAAwB/F,EAAAmG,EAAA,CAAsB,CAACnG,EAAAoG,CAAA,CAAQ,CAACL,EAAa,KAAK,CAAA,CAAA,CAAG,OAAuB,KAAA,CAAA;KAOhI,GAAA,CAAAA,EAAa,QADrB9F,EAAA,GAAAC,EASEF,EAAAQ,CAAA,GAAA;;MAPC,MAAMuF,EAAa;MACnB,OAAK5E,EAAmBnB,EAAAiG,CAAA,CAAE,CAAA,0BAAgEF,EAAa,aAAa/F,EAAAqG,CAAA,CAAgB,CAACN,EAAa,UAAA,CAAA;KAOrJtF,GAAAA,MAAAA,GAAAA,CAAAA,QAAAA,OAAAA,CAAAA,KAAAA,EAAAA,IAAAA,EAAAA,GAAAA,EA8BM,OA9BN+B,GA8BM;MA7BJ/B,EAWM,OAXNgC,GAWM,CAVJhC,EAA2D,KAA3DiC,IAA2DhC,EAAzBqF,EAAa,KAAK,GAAA,CAAA,GAE3CA,EAAa,sBADtB9F,EAAA,GAAAU,EAQS,UAAA;;OANP,MAAK;OACL,OAAM;OACL,cAAYX,EAAAmD,CAAA,CAAC,CAAA,gBAAA,CAAA,GAAA,cAAA;OACb,UAAK,MAAA,KAAOnD,EAAA4D,CAAA,CAAM,CAAC,WAAWmC,EAAa,EAAE;MAE9CtF,GAAAA,CAAAA,GAAAA,AAAAA,EAAAA,OAAAA,CAAAA,EAAkE,QAAA;OAA5D,OAAM;OAAiC,eAAY;;MAIrDsF,EAAa,QADrB9F,EAAA,GAAAU,EAIE,KAAA;;OAFA,OAAM;OACN,WAAQoF,EAAa;;MAEXA,EAAa,QAAzB9F,EAAA,GAAAU,EAES,QAFTkC,IAESnC,EADPV,EAAA4E,EAAA,CAAM,CAAC,SAASmB,EAAa,IAAI,CAAA,GAAA,CAAA,KAAAL,EAAA,IAAA,EAAA;MAExBK,EAAa,WAAxB9F,EAAA,GAAAU,EAQM,OARNmC,IAQM,EAPJ7C,EAAA,EAAA,GAAAU,EAMEM,GAAA,MAAAC,EALiB6E,EAAa,UAAvB,OADT9F,EAAA,GAAAC,EAMEmB,IAAA;OAJC,KAAKiF,EAAO;OACJ;OACR,yBAAe,KAAatG,EAAA4D,CAAA,CAAM,CAAE,WAAWmC,EAAa,EAAE;OAC9D,2BAAiB,KAAa/F,EAAA4D,CAAA,CAAM,CAAE,aAAamC,EAAa,EAAE;;;;;;aAOrE/F,GAAAA,GAAAA,EAAAA,CAAAA,IAAAA,EAAAgE,CAAA,CAAK,CAAC,WAAWhE,EAAAgE,CAAA,CAAK,CAAC,cAAc,SAAM,KADnD/D,EAAA,GAAAU,EAcM,OAdNoC,IAcM,CAVJ1C,EASSE,GAAA;MARP,MAAK;MACL,SAAQ;MACR,MAAK;MACJ,UAAUP,EAAAgE,CAAA,CAAK,CAAC;MAChB,SAAK,AAAAiB,EAAA,QAAA,MAAA,KAAOjF,EAAA4D,CAAA,CAAM,CAAE,SAAQ;;MAE7B,SAAAxD,QAAgC,CAAjBJ,EAAAgE,CAAA,CAAK,CAAC,WAArB/D,EAAA,GAAAC,EAAgCc,GAAA,EAAA,KAAA,EAAA,CAAA,KAAA0E,EAAA,IAAA,EAAA,GAAA9E,EAAA,MAChCF,EAAGV,EAAAmD,CAAA,CAAC,CAAA,aAAA,CAAA,GAAA,WAAA,CAAA,GAAA,CAAA,CAAA,CAAA"}
|