pgo-ui 1.0.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.
Files changed (178) hide show
  1. package/README.md +195 -0
  2. package/dist/InputSearch-CHSoQ7GH.js +155 -0
  3. package/dist/favicon.ico +0 -0
  4. package/dist/index-B7ko30VS.js +5899 -0
  5. package/dist/index-BKsLeoKP.js +4781 -0
  6. package/dist/index-BeW0KHDT.js +34237 -0
  7. package/dist/index-DjwGqWIf.js +5086 -0
  8. package/dist/index-jnIKSPXM.js +4949 -0
  9. package/dist/index.es.js +58 -0
  10. package/dist/index.umd.js +111 -0
  11. package/dist/pgo-ui.css +1 -0
  12. package/package.json +99 -0
  13. package/src/App.vue +369 -0
  14. package/src/assets/fonts/Faruma.ttf +0 -0
  15. package/src/assets/logo.png +0 -0
  16. package/src/components/examples/AppBarExample.vue +100 -0
  17. package/src/components/examples/AvatarExample.vue +47 -0
  18. package/src/components/examples/BannerExample.vue +287 -0
  19. package/src/components/examples/BaseInputExample.vue +25 -0
  20. package/src/components/examples/BreadcrumbExample.vue +53 -0
  21. package/src/components/examples/CardExample.vue +77 -0
  22. package/src/components/examples/ChipExample.vue +225 -0
  23. package/src/components/examples/DatePickerExample.vue +31 -0
  24. package/src/components/examples/DropdownExample.vue +84 -0
  25. package/src/components/examples/EditorExample.vue +200 -0
  26. package/src/components/examples/ExpansionPanelExample.vue +42 -0
  27. package/src/components/examples/FileUploadExample.vue +40 -0
  28. package/src/components/examples/FormExample.vue +121 -0
  29. package/src/components/examples/HugeTest.vue +8 -0
  30. package/src/components/examples/LayoutContainerExample.vue +80 -0
  31. package/src/components/examples/ModalExample.vue +82 -0
  32. package/src/components/examples/NavDrawerExample.vue +171 -0
  33. package/src/components/examples/NumberFieldExample.vue +145 -0
  34. package/src/components/examples/RadioButtonExample.vue +161 -0
  35. package/src/components/examples/SearchExample.vue +322 -0
  36. package/src/components/examples/SelectExample.vue +121 -0
  37. package/src/components/examples/StackedTableViewExample.vue +53 -0
  38. package/src/components/examples/TabExample.vue +336 -0
  39. package/src/components/examples/TableExample.vue +228 -0
  40. package/src/components/examples/TextFieldExample.vue +181 -0
  41. package/src/components/examples/TextareaExample.vue +173 -0
  42. package/src/components/examples/ThemeToggle.vue +50 -0
  43. package/src/components/examples/TimelineExample.vue +66 -0
  44. package/src/components/examples/TipTapEditorExample.vue +20 -0
  45. package/src/components/examples/TooltipExample.vue +53 -0
  46. package/src/components/examples/VueDatePickerShowcase.vue +214 -0
  47. package/src/components/examples/_DatePickerExample.vue +33 -0
  48. package/src/components/examples/__FormExample.vue +77 -0
  49. package/src/components/index.ts +25 -0
  50. package/src/components/pgo/AppBar.vue +348 -0
  51. package/src/components/pgo/Avatar.vue +139 -0
  52. package/src/components/pgo/Banner.vue +300 -0
  53. package/src/components/pgo/Breadcrumb.vue +103 -0
  54. package/src/components/pgo/Button.vue +171 -0
  55. package/src/components/pgo/Card.vue +179 -0
  56. package/src/components/pgo/ConfirmationModel.vue +32 -0
  57. package/src/components/pgo/DataTable.vue +845 -0
  58. package/src/components/pgo/DatePicker/CalendarPanel.vue +43 -0
  59. package/src/components/pgo/DatePicker/__DatePicker.vue +122 -0
  60. package/src/components/pgo/DatePicker/types.ts +11 -0
  61. package/src/components/pgo/DatePicker/useCalendar.ts +39 -0
  62. package/src/components/pgo/DatePicker/useDatePicker.ts +31 -0
  63. package/src/components/pgo/Deprecated/ToastContainer.vue +51 -0
  64. package/src/components/pgo/Deprecated/ToastItem.vue +55 -0
  65. package/src/components/pgo/Dropdown.vue +296 -0
  66. package/src/components/pgo/DropdownItem.vue +40 -0
  67. package/src/components/pgo/Editor.vue +511 -0
  68. package/src/components/pgo/ExpansionPanel.vue +185 -0
  69. package/src/components/pgo/Footer.vue +39 -0
  70. package/src/components/pgo/HeroIcon.vue +124 -0
  71. package/src/components/pgo/LayoutContainer.vue +104 -0
  72. package/src/components/pgo/Main.vue +37 -0
  73. package/src/components/pgo/Modal.vue +261 -0
  74. package/src/components/pgo/NavDrawer.vue +127 -0
  75. package/src/components/pgo/NavDrawerItem.vue +161 -0
  76. package/src/components/pgo/NavigationDrawer.vue +850 -0
  77. package/src/components/pgo/OLDNavDrawer.vue +661 -0
  78. package/src/components/pgo/OldAppBar.vue +223 -0
  79. package/src/components/pgo/PApp.vue +102 -0
  80. package/src/components/pgo/Pagination.vue +242 -0
  81. package/src/components/pgo/Search copy.vue +310 -0
  82. package/src/components/pgo/Search.vue +411 -0
  83. package/src/components/pgo/StackedTableView.vue +167 -0
  84. package/src/components/pgo/Tab.vue +617 -0
  85. package/src/components/pgo/TestInput.vue +395 -0
  86. package/src/components/pgo/Timeline.vue +367 -0
  87. package/src/components/pgo/TimelineItem.vue +80 -0
  88. package/src/components/pgo/TipTapEditor.vue +315 -0
  89. package/src/components/pgo/Tooltip.NOTES.md +12 -0
  90. package/src/components/pgo/Tooltip.PROPS.md +21 -0
  91. package/src/components/pgo/Tooltip.vue +281 -0
  92. package/src/components/pgo/base/Base.vue +444 -0
  93. package/src/components/pgo/buttons/Chip.vue +324 -0
  94. package/src/components/pgo/buttons/ChipGroup.vue +224 -0
  95. package/src/components/pgo/buttons/Radio.vue +424 -0
  96. package/src/components/pgo/filters/FilterSection.vue +188 -0
  97. package/src/components/pgo/filters/Searchbar.vue +216 -0
  98. package/src/components/pgo/forms/DynamicForm.vue +45 -0
  99. package/src/components/pgo/forms/Form.vue +132 -0
  100. package/src/components/pgo/index.ts +89 -0
  101. package/src/components/pgo/inputs/Checkbox.vue +320 -0
  102. package/src/components/pgo/inputs/DatePicker.vue +395 -0
  103. package/src/components/pgo/inputs/FileUpload.vue +326 -0
  104. package/src/components/pgo/inputs/InputSearch.vue +194 -0
  105. package/src/components/pgo/inputs/NumberField.vue +243 -0
  106. package/src/components/pgo/inputs/Radio.vue +162 -0
  107. package/src/components/pgo/inputs/RadioGroup.vue +188 -0
  108. package/src/components/pgo/inputs/Select.vue +535 -0
  109. package/src/components/pgo/inputs/TextField.vue +194 -0
  110. package/src/components/pgo/inputs/Textarea.vue +181 -0
  111. package/src/index.js +81 -0
  112. package/src/main.js +12 -0
  113. package/src/pgo-components/__index.js +104 -0
  114. package/src/pgo-components/_index.js +31 -0
  115. package/src/pgo-components/assets/fonts/Faruma.ttf +0 -0
  116. package/src/pgo-components/assets/fonts/logo.png +0 -0
  117. package/src/pgo-components/composables/useTheme.js +10 -0
  118. package/src/pgo-components/directives/tooltip-directive.ts +393 -0
  119. package/src/pgo-components/lib/componentConfig.js +147 -0
  120. package/src/pgo-components/lib/core/composables/_useCalendar.ts +127 -0
  121. package/src/pgo-components/lib/core/composables/useDefaults.ts +15 -0
  122. package/src/pgo-components/lib/core/composables/useLanguageSelect.js +0 -0
  123. package/src/pgo-components/lib/core/composables/useRtl.ts +12 -0
  124. package/src/pgo-components/lib/core/defaults/createDefaults.ts +5 -0
  125. package/src/pgo-components/lib/core/defaults/defaults.ts +7 -0
  126. package/src/pgo-components/lib/core/rtl/rtl.ts +3 -0
  127. package/src/pgo-components/lib/core/rtl/setRtl.ts +19 -0
  128. package/src/pgo-components/lib/drawerState.ts +3 -0
  129. package/src/pgo-components/lib/i18n/defaultLables.js +71 -0
  130. package/src/pgo-components/lib/i18n/i18nPlugin.js +52 -0
  131. package/src/pgo-components/lib/i18n/useI18n.js +35 -0
  132. package/src/pgo-components/lib/index.ts +38 -0
  133. package/src/pgo-components/pages/Component.vue +7 -0
  134. package/src/pgo-components/pages/ComponentRenderer.vue +99 -0
  135. package/src/pgo-components/pages/Home.vue +125 -0
  136. package/src/pgo-components/pages/ListView.vue +372 -0
  137. package/src/pgo-components/pages/Page1.vue +296 -0
  138. package/src/pgo-components/pages/_Page1.vue +180 -0
  139. package/src/pgo-components/plugins/SnackBar.vue +251 -0
  140. package/src/pgo-components/plugins/SnackBarContainer.vue +53 -0
  141. package/src/pgo-components/plugins/SnackBarPlugin.ts +136 -0
  142. package/src/pgo-components/plugins/theme-plugin.js +114 -0
  143. package/src/pgo-components/plugins/types.ts +46 -0
  144. package/src/pgo-components/plugins/useSnackBar.js +11 -0
  145. package/src/pgo-components/plugins/useSnackBar.ts +21 -0
  146. package/src/pgo-components/plugins/validation-plugin.js +11 -0
  147. package/src/pgo-components/services/Entry.json +813 -0
  148. package/src/pgo-components/services/axios.js +54 -0
  149. package/src/pgo-components/services/data.json +90 -0
  150. package/src/pgo-components/services/person.json +260 -0
  151. package/src/pgo-components/services/toast.ts +44 -0
  152. package/src/pgo-components/styles/global.css +234 -0
  153. package/src/pgo-components/styles/reset.css +96 -0
  154. package/src/pgo-components/styles/tokens.css +18 -0
  155. package/src/pgo-components/styles/utilities/border-radius.css +57 -0
  156. package/src/pgo-components/styles/utilities/borders.css +85 -0
  157. package/src/pgo-components/styles/utilities/colors.css +38 -0
  158. package/src/pgo-components/styles/utilities/cursor.css +19 -0
  159. package/src/pgo-components/styles/utilities/display.css +78 -0
  160. package/src/pgo-components/styles/utilities/elevation.css +33 -0
  161. package/src/pgo-components/styles/utilities/flex.css +403 -0
  162. package/src/pgo-components/styles/utilities/float.css +41 -0
  163. package/src/pgo-components/styles/utilities/hover.css +9 -0
  164. package/src/pgo-components/styles/utilities/index.css +18 -0
  165. package/src/pgo-components/styles/utilities/opacity.css +27 -0
  166. package/src/pgo-components/styles/utilities/overflow.css +26 -0
  167. package/src/pgo-components/styles/utilities/palette.css +515 -0
  168. package/src/pgo-components/styles/utilities/position.css +14 -0
  169. package/src/pgo-components/styles/utilities/sizing.css +70 -0
  170. package/src/pgo-components/styles/utilities/spacing.css +578 -0
  171. package/src/pgo-components/styles/utilities/transitions.css +58 -0
  172. package/src/pgo-components/styles/utilities/typography.css +91 -0
  173. package/src/pgo-components/styles/utilities/z-index.css +11 -0
  174. package/src/pgo-components/tokens/index.js +337 -0
  175. package/src/router/index.js +88 -0
  176. package/src/shims-vue.d.ts +14 -0
  177. package/src/validations/validationRules.js +50 -0
  178. package/tailwind.config.js +73 -0
@@ -0,0 +1,39 @@
1
+ <template>
2
+ <footer ref="el" :class="['w-full', densityClass]" :style="style">
3
+ <slot />
4
+ </footer>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+ import { ref, onMounted, onBeforeUnmount, computed, inject } from "vue";
9
+
10
+ const props = defineProps({
11
+ id: {
12
+ type: String,
13
+ default: () => `footer-${Math.random().toString(36).slice(2, 9)}`,
14
+ },
15
+ dense: { type: Boolean, default: false },
16
+ });
17
+ const layout = inject<any>("layout", null);
18
+ const el = ref<HTMLElement | null>(null);
19
+ const height = ref(0);
20
+
21
+ function update() {
22
+ if (!el.value) return;
23
+ height.value = el.value.getBoundingClientRect().height;
24
+ if (layout) layout.register("footer", props.id, { height: height.value });
25
+ }
26
+
27
+ onMounted(() => {
28
+ update();
29
+ const ro = new ResizeObserver(update);
30
+ if (el.value) ro.observe(el.value);
31
+ onBeforeUnmount(() => {
32
+ ro.disconnect();
33
+ if (layout) layout.unregister("footer", props.id);
34
+ });
35
+ });
36
+
37
+ const densityClass = computed(() => (props.dense ? "h-10" : "h-14"));
38
+ const style = computed(() => ({}));
39
+ </script>
@@ -0,0 +1,124 @@
1
+ <template>
2
+ <component
3
+ :is="IconAsyncComponent"
4
+ v-bind="attrs"
5
+ :class="computedClass"
6
+ :style="computedStyle"
7
+ />
8
+ </template>
9
+
10
+ <script setup lang="ts">
11
+ import type { Component } from "vue";
12
+ import { computed, useAttrs } from "vue";
13
+ import { defineAsyncComponent } from "vue";
14
+
15
+ // Props
16
+ interface Props {
17
+ name: string;
18
+ type?: "solid" | "outline" | "mini" | "micro";
19
+ size?: number | string;
20
+ color?: string;
21
+ }
22
+
23
+ const props = withDefaults(defineProps<Props>(), {
24
+ type: "outline",
25
+ size: 24,
26
+ color: "currentColor",
27
+ });
28
+
29
+ const attrs = useAttrs();
30
+
31
+ // Convert icon names like "academic-cap" to "AcademicCapIcon"
32
+ const normalizeName = (str: string) => {
33
+ return (
34
+ str
35
+ .replace(/-([a-z])/g, (_, c) => c.toUpperCase()) // kebab → camel
36
+ .replace(/(?:^|_|\s|-)(\w)/g, (_, c) => c.toUpperCase()) // capitalize
37
+ .replace(/Icon$/, "") + "Icon"
38
+ );
39
+ };
40
+
41
+ const iconName = computed(() => normalizeName(props.name));
42
+
43
+ // Async loader
44
+ const IconAsyncComponent = computed(() =>
45
+ defineAsyncComponent({
46
+ loader: async () => {
47
+ let pack;
48
+
49
+ if (props.type === "solid") {
50
+ pack = await import("@heroicons/vue/24/solid");
51
+ } else if (props.type === "outline") {
52
+ pack = await import("@heroicons/vue/24/outline");
53
+ } else if (props.type === "mini") {
54
+ pack = await import("@heroicons/vue/20/solid");
55
+ } else if (props.type === "micro") {
56
+ pack = await import("@heroicons/vue/16/solid");
57
+ } else {
58
+ pack = await import("@heroicons/vue/24/outline");
59
+ }
60
+
61
+ const icon = (pack as any)[iconName.value];
62
+
63
+ if (!icon) {
64
+ throw new Error(
65
+ `Icon "${iconName.value}" not found in ${props.type} icons`
66
+ );
67
+ }
68
+
69
+ return icon as Component;
70
+ },
71
+
72
+ // Loading icon
73
+ loadingComponent: defineAsyncComponent(
74
+ async () => (await import("@heroicons/vue/24/outline")).ArrowPathIcon
75
+ ),
76
+
77
+ // Error fallback icon
78
+ errorComponent: defineAsyncComponent(
79
+ async () =>
80
+ (await import("@heroicons/vue/24/outline")).ExclamationTriangleIcon
81
+ ),
82
+
83
+ delay: 200,
84
+ timeout: 5000,
85
+ })
86
+ );
87
+
88
+ // Tailwind color detection
89
+ const isTailwindColorClass = (value?: string) =>
90
+ value
91
+ ? /(?:^|\s)(?:text-|fill-|stroke-|bg-|ring-|border-)/.test(value)
92
+ : false;
93
+
94
+ const tailwindColorClass = computed(() =>
95
+ isTailwindColorClass(props.color) ? String(props.color) : ""
96
+ );
97
+
98
+ const computedClass = computed(() => {
99
+ const classes = ["hero-icon"];
100
+
101
+ if (attrs.class) classes.push(String(attrs.class));
102
+ if (tailwindColorClass.value) classes.push(tailwindColorClass.value);
103
+
104
+ return classes.filter(Boolean).join(" ");
105
+ });
106
+
107
+ const computedStyle = computed(() => {
108
+ const styleObj: Record<string, any> =
109
+ typeof attrs.style === "object" ? { ...attrs.style } : {};
110
+
111
+ const sizeCss =
112
+ typeof props.size === "number" ? `${props.size}px` : props.size;
113
+
114
+ styleObj.width = sizeCss;
115
+ styleObj.height = sizeCss;
116
+
117
+ // Inline CSS color if not a Tailwind class
118
+ if (!isTailwindColorClass(props.color)) {
119
+ styleObj.color = props.color;
120
+ }
121
+
122
+ return styleObj;
123
+ });
124
+ </script>
@@ -0,0 +1,104 @@
1
+ <template>
2
+ <div class="flex h-screen overflow-hidden">
3
+ <!-- Drawer -->
4
+ <NavDrawer
5
+
6
+ :collapsed="collapsed"
7
+ :class="[
8
+ 'flex-shrink-0 bg-white shadow-lg z-30',
9
+ isMobile ? 'fixed inset-y-0 left-0 transform transition-transform duration-300 ease-in-out' : '',
10
+ drawerWidthClass,
11
+ drawerOpenClass
12
+ ]"
13
+ @close="closeDrawer"
14
+ @toggleCollapse="toggleCollapse"
15
+ />
16
+
17
+ <!-- Backdrop for mobile drawer -->
18
+
19
+ <div
20
+ v-if="isMobile && showDrawer"
21
+ class="fixed inset-0 bg-black bg-opacity-40 z-20"
22
+ @click="closeDrawer"
23
+ ></div>
24
+
25
+ <!-- Main content area -->
26
+ <div class="flex-1 flex flex-col overflow-hidden">
27
+ <!-- AppBar -->
28
+ <AppBar
29
+ title="This is APP"
30
+ :class="['flex-shrink-0']"
31
+ @toggleDrawer="toggleDrawer"
32
+ />
33
+
34
+ <!-- Content -->
35
+ <main class="flex-1 overflow-auto bg-gray-50 vts-p-4">
36
+ <slot>
37
+ sadf
38
+ </slot>
39
+ </main>
40
+
41
+ <!-- Optional Footer -->
42
+ <footer v-if="$slots.footer" class="flex-shrink-0 vts-p-4 bg-white shadow-inner">
43
+ <slot name="footer" />
44
+ </footer>
45
+ </div>
46
+ </div>
47
+ </template>
48
+
49
+ <script setup lang="ts">
50
+ import { ref, computed, onMounted, onUnmounted } from 'vue';
51
+ import AppBar from '../pgo/AppBar.vue';
52
+ import NavDrawer from '../pgo/NavDrawer.vue';
53
+
54
+ const collapsed = ref(false);
55
+ const showDrawer = ref(false);
56
+ const windowWidth = ref(window.innerWidth);
57
+
58
+ const MOBILE_BREAKPOINT = 768; // Tailwind md
59
+
60
+ // Detect mobile screen
61
+ const isMobile = computed(() => windowWidth.value < MOBILE_BREAKPOINT);
62
+
63
+ // Drawer width
64
+ const drawerWidthClass = computed(() => (collapsed.value ? 'w-16' : 'w-64'));
65
+
66
+ // Mobile drawer open/close transform
67
+ const drawerOpenClass = computed(() => {
68
+ if (!isMobile.value) return '';
69
+ return showDrawer.value ? 'translate-x-0' : '-translate-x-full';
70
+ });
71
+
72
+ // Toggle collapse
73
+ function toggleCollapse() {
74
+ collapsed.value = !collapsed.value;
75
+ }
76
+
77
+ // Toggle drawer visibility (for mobile)
78
+ function toggleDrawer() {
79
+ showDrawer.value = !showDrawer.value;
80
+ }
81
+
82
+ function closeDrawer() {
83
+ showDrawer.value = false;
84
+ }
85
+
86
+ // Update window width
87
+ function updateWidth() {
88
+ windowWidth.value = window.innerWidth;
89
+ }
90
+
91
+ onMounted(() => {
92
+ window.addEventListener('resize', updateWidth);
93
+ });
94
+ onUnmounted(() => {
95
+ window.removeEventListener('resize', updateWidth);
96
+ });
97
+ </script>
98
+
99
+ <style scoped>
100
+ /* Optional: smooth transition for main content margin on desktop when collapsing drawer */
101
+ .flex-1 {
102
+ transition: margin-left 0.3s ease-in-out;
103
+ }
104
+ </style>
@@ -0,0 +1,37 @@
1
+ <template>
2
+ <main
3
+ :class="['flex-1 w-full transition-padding duration-200', contentClass]"
4
+ ref="el"
5
+ :style="style"
6
+ >
7
+ <slot />
8
+ </main>
9
+ </template>
10
+
11
+ <script setup lang="ts">
12
+ import { ref, computed, inject, watch, onMounted } from "vue";
13
+
14
+ const layout = inject<any>("layout", null);
15
+ const el = ref<HTMLElement | null>(null);
16
+
17
+ const contentClass = computed(() => "");
18
+
19
+ const style = computed(() => {
20
+ // console.log("Layout in Main.vue horizontal:", layout?.horizontalOffset?.value);
21
+ const top = layout?.topOffset?.value || 0;
22
+ const bottom = layout?.bottomOffset?.value || 0;
23
+ const { left, right } = layout?.horizontalOffset?.value || {
24
+ left: 0,
25
+ right: 0,
26
+ };
27
+ return {
28
+ paddingTop: `${top}px`,
29
+ paddingBottom: `${bottom}px`,
30
+ paddingLeft: left ? `${left}px` : undefined,
31
+ paddingRight: right ? `${right}px` : undefined,
32
+ minHeight: `calc(100vh - ${bottom}px)`,
33
+ };
34
+ });
35
+
36
+ onMounted(() => {});
37
+ </script>
@@ -0,0 +1,261 @@
1
+ <template>
2
+ <Teleport to="body">
3
+ <Transition :name="transitionName">
4
+ <div
5
+ v-if="show"
6
+ :class="[
7
+ 'fixed inset-0 z-50 flex items-center justify-center overflow-hidden',
8
+
9
+ ]">
10
+ <!-- Overlay -->
11
+ <div class="absolute inset-0 overflow-hidden" :style="overlayThemeStyles" :class="[overlayClass, 'vts-bg-overlay']" @click="attemptClose" />
12
+
13
+ <!-- Modal -->
14
+ <Transition :name="transitionName">
15
+ <div
16
+ v-if="show"
17
+ class="relative max-h-fit flex flex-col overflow-y-auto"
18
+ :class="[fullscreen ? 'h-screen w-full rounded-none' : 'mx-4 sm:max-w-lg', modalClass, shake && 'animate-shake']"
19
+ @click.stop
20
+ >
21
+ <Card
22
+ :lang="lang"
23
+ :labels="labels"
24
+ :width="width"
25
+ :title="title"
26
+ :cardClass="cardClass"
27
+ :overflow="overflow"
28
+ :bg="bg"
29
+ :border="border"
30
+ :rounded="rounded"
31
+ :shadow="shadow"
32
+ :dir="dir"
33
+ :height="fullscreen ? 'h-screen' : height"
34
+ :margin="fullscreen ? 'm-0' : margin"
35
+
36
+ >
37
+ <template #header>
38
+ <slot name="header" />
39
+ </template>
40
+ <slot />
41
+ <template #footer>
42
+ <slot name="footer" >
43
+ <!-- <Button
44
+ label="Cancel"
45
+ color="secondary"
46
+ variant="outlined"
47
+ @click="cancelUpdate"
48
+ />
49
+ <Button
50
+ label="Confirm"
51
+ color="primary"
52
+ :loading="updateLoading"
53
+ @click="confirmUpdate"
54
+ /> -->
55
+ </slot>
56
+ </template>
57
+
58
+ </Card>
59
+ </div>
60
+ </Transition>
61
+ </div>
62
+ </Transition>
63
+ </Teleport>
64
+ </template>
65
+
66
+ <script setup lang="ts">
67
+ import { computed, ref, watch, onMounted, onBeforeUnmount } from 'vue'
68
+
69
+ const props = defineProps({
70
+ modelValue: { type: Boolean, required: true },
71
+ persistent: { type: Boolean, default: false },
72
+ fullscreen: { type: Boolean, default: false },
73
+ transition: { type: String, default: 'center' },
74
+ overlayClass: { type: String, default: '' },
75
+ modalClass: { type: String, default: '' },
76
+
77
+ //card
78
+ lang: { type: String, default: '' },
79
+ labels: { type: [String, Object], default: () => ({
80
+ en: {
81
+ title: '',
82
+ body: '',
83
+ footer: ''
84
+ },
85
+ dv: {
86
+ title: '',
87
+ body: '',
88
+ footer: ''
89
+ }
90
+ }) },
91
+ width: { type: String, default: '' },
92
+ height: { type: String, default: '' },
93
+ title: { type: [String, Object], default: '' },
94
+ cardClass: { type: String, default: '' },
95
+ overflow: { type: String, default: 'max-h-[calc(100vh-150px)] overflow-auto' },
96
+ bg: { type: String, default: 'bg-background-color' },
97
+ border: { type: String, default: 'border border-input-border' },
98
+ rounded: { type: String, default: '' },
99
+ shadow: { type: String, default: '' },
100
+ dir: { type: String, default: '' },
101
+
102
+ //body props
103
+ bodyClass: { type: String, default: '' },
104
+ margin: { type: String, default: 'mx-0 my-6' },
105
+ padding: { type: String, default: 'px-6 py-4' },
106
+ textColor: { type: String, default: 'text-input-text' },
107
+ textSize: { type: String, default: 'text-base' },
108
+
109
+ // header props
110
+ headerClass: { type: String, default: '' },
111
+ titleClass: { type: String, default: '' },
112
+ headerBg: { type: String, default: '' },
113
+ headerText: { type: String, default: 'text-input-text' },
114
+ headerTextSize: { type: String, default: 'text-lg font-semibold' },
115
+ headerBd: { type: String, default: '' },
116
+ headerMargin: { type: String, default: '' },
117
+ headerPadding: { type: String, default: 'px-6 pt-4' },
118
+
119
+ //footer props
120
+ footerClass: { type: String, default: '' },
121
+ footerBg: { type: String, default: '' },
122
+ footerText: { type: String, default: 'text-input-text' },
123
+ footerTextSize: { type: String, default: '' },
124
+ footerBd: { type: String, default: '' },
125
+ footerMargin: { type: String, default: '' },
126
+ footerPadding: { type: String, default: 'px-6 py-4' },
127
+
128
+ })
129
+
130
+ const emit = defineEmits(['update:modelValue'])
131
+
132
+ const modalThemeStyles = computed(() => ({
133
+ backgroundColor: 'var(--vts-color-surfaceElevated)',
134
+ color: 'var(--vts-color-text)',
135
+ borderRadius: 'var(--vts-radius-lg)',
136
+ boxShadow: 'var(--vts-elevation-4)'
137
+ }))
138
+
139
+ const overlayThemeStyles = computed(() => ({
140
+ // backgroundColor: 'var(--vts-color-overlay)'
141
+ }))
142
+
143
+ const footerThemeStyles = computed(() => ({
144
+ backgroundColor: 'var(--vts-color-surfaceElevated)',
145
+ borderTopColor: 'var(--vts-color-border)'
146
+ }))
147
+
148
+ const headerThemeStyles = computed(() => ({
149
+ backgroundColor: 'var(--vts-color-surfaceElevated)',
150
+ borderBottomColor: 'var(--vts-color-border)'
151
+ }))
152
+
153
+ const show = computed({
154
+ get: () => props.modelValue,
155
+ set: v => emit('update:modelValue', v)
156
+ })
157
+
158
+ const shake = ref(false)
159
+
160
+ function attemptClose() {
161
+ if (props.persistent) {
162
+ shake.value = true
163
+ setTimeout(() => (shake.value = false), 400)
164
+ return
165
+ }
166
+ show.value = false
167
+ }
168
+
169
+ function onEsc(e) {
170
+ if (e.key === 'Escape' && show.value) {
171
+ attemptClose()
172
+ }
173
+ }
174
+
175
+ onMounted(() => {
176
+ document.addEventListener('keydown', onEsc)
177
+ })
178
+
179
+ onBeforeUnmount(() => {
180
+ document.removeEventListener('keydown', onEsc)
181
+ })
182
+
183
+ const transitionName = computed(() => {
184
+ // console.log(props.transition)
185
+ return `${props.transition ?? 'center'}`
186
+ })
187
+ </script>
188
+
189
+ <style scoped>
190
+ /* Fade */
191
+ .fade-enter-active,
192
+ .fade-leave-active {
193
+ transition: opacity 0.9s ease;
194
+ }
195
+ .fade-enter-from,
196
+ .fade-leave-to {
197
+ opacity: 0;
198
+ }
199
+
200
+ /* Center */
201
+ .center-enter-active,
202
+ .center-leave-active {
203
+ transition: transform 0.35s ease, opacity 0.25s ease;
204
+ }
205
+ .center-enter-from,
206
+ .center-leave-to {
207
+ transform: scale(0.95);
208
+ opacity: 0;
209
+ }
210
+
211
+ /* Bottom */
212
+ .bottom-enter-active,
213
+ .bottom-leave-active {
214
+ transition: transform 0.4s ease;
215
+ }
216
+ .bottom-enter-from,
217
+ .bottom-leave-to {
218
+ transform: translateY(100%);
219
+ }
220
+
221
+ /* Top */
222
+ .top-enter-from,
223
+ .top-leave-to {
224
+ transform: translateY(-100%);
225
+ }
226
+
227
+ /* Left */
228
+ .left-enter-from,
229
+ .left-leave-to {
230
+ transform: translateX(-100%);
231
+ }
232
+
233
+ /* Right */
234
+ .right-enter-from,
235
+ .right-leave-to {
236
+ transform: translateX(100%);
237
+ }
238
+
239
+ /* Shake */
240
+ @keyframes shake {
241
+ 0% {
242
+ transform: translateX(0);
243
+ }
244
+ 25% {
245
+ transform: translateX(-10px);
246
+ }
247
+ 50% {
248
+ transform: translateX(10px);
249
+ }
250
+ 75% {
251
+ transform: translateX(-10px);
252
+ }
253
+ 100% {
254
+ transform: translateX(0);
255
+ }
256
+ }
257
+
258
+ .animate-shake {
259
+ animation: shake 0.3s ease forwards;
260
+ }
261
+ </style>
@@ -0,0 +1,127 @@
1
+ <template>
2
+ <aside
3
+ ref="el"
4
+ :class="[
5
+ 'fixed top-0 h-full z-30 transition-transform duration-300 bg-white dark:bg-slate-800',
6
+ positionClass,
7
+ modeClass,
8
+ permanentTransformClass,
9
+ railClass,
10
+ ]"
11
+ :style="computedStyle"
12
+ @mouseenter="onMouseEnter"
13
+ @mouseleave="onMouseLeave"
14
+ >
15
+ <div class="h-full flex flex-col overflow-hidden">
16
+ <slot />
17
+ </div>
18
+ </aside>
19
+ </template>
20
+
21
+ <script setup lang="ts">
22
+ import { ref, onMounted, onBeforeUnmount, computed, inject, watch } from "vue";
23
+ import { globalRtl } from "../../pgo-components/lib/core/rtl/rtl";
24
+
25
+ const props = defineProps({
26
+ id: {
27
+ type: String,
28
+ default: () => `drawer-${Math.random().toString(36).slice(2, 9)}`,
29
+ },
30
+ mode: { type: String, default: "permanent" }, // 'permanent' | 'temporary' | 'rail'
31
+ width: { type: Number, default: 256 },
32
+ railWidth: { type: Number, default: 72 },
33
+ modelValue: { type: Boolean, default: true }, // open state for temporary
34
+ expandOnHover: { type: Boolean, default: false },
35
+ right: { type: Boolean, default: false },
36
+ });
37
+
38
+ const emit = defineEmits(["update:modelValue"]);
39
+ const layout = inject<any>("layout", null);
40
+ const el = ref<HTMLElement | null>(null);
41
+ const expanded = ref(false);
42
+
43
+ function update() {
44
+ if (!el.value) return;
45
+ const w = props.mode === "rail" ? props.railWidth : props.width;
46
+ if (layout)
47
+ layout.register("drawer", props.id, {
48
+ width: w,
49
+ mode: props.mode,
50
+ expanded: expanded.value,
51
+ right: props.right,
52
+ });
53
+ }
54
+
55
+ onMounted(() => {
56
+ update();
57
+ const ro = new ResizeObserver(update);
58
+ if (el.value) ro.observe(el.value);
59
+ onBeforeUnmount(() => {
60
+ ro.disconnect();
61
+ if (layout) layout.unregister("drawer", props.id);
62
+ });
63
+ });
64
+
65
+ watch([() => props.mode, expanded], update);
66
+
67
+ const isOpen = computed(() => {
68
+ if (props.mode === "temporary") return props.modelValue;
69
+ if (props.mode === "permanent") return true;
70
+ if (props.mode === "rail") return true;
71
+ return true;
72
+ });
73
+
74
+ function onMouseEnter() {
75
+ if (props.mode === "rail" && props.expandOnHover) {
76
+ expanded.value = true;
77
+ update();
78
+ }
79
+ }
80
+ function onMouseLeave() {
81
+ if (props.mode === "rail" && props.expandOnHover) {
82
+ expanded.value = false;
83
+ update();
84
+ }
85
+ }
86
+
87
+ const positionClass = computed(() =>
88
+ props.right
89
+ ? globalRtl.value
90
+ ? "left-0"
91
+ : "right-0"
92
+ : globalRtl.value
93
+ ? "right-0"
94
+ : "left-0"
95
+ );
96
+ const modeClass = computed(() => {
97
+ if (props.mode === "temporary")
98
+ return isOpen.value
99
+ ? "translate-x-0"
100
+ : props.right
101
+ ? "translate-x-full"
102
+ : "-translate-x-full";
103
+ if (props.mode === "permanent") return "translate-x-0";
104
+ if (props.mode === "rail") return "translate-x-0";
105
+ return "";
106
+ });
107
+ const permanentTransformClass = computed(() =>
108
+ props.mode === "temporary" ? "pointer-events-auto" : "pointer-events-auto"
109
+ );
110
+ const railClass = computed(() => {
111
+ if (props.mode === "rail") {
112
+ const w = expanded.value ? `${props.width}px` : `${props.railWidth}px`;
113
+ return "";
114
+ }
115
+ return "";
116
+ });
117
+
118
+ const computedStyle = computed(() => {
119
+ if (props.mode === "rail") {
120
+ const w = expanded.value ? props.width : props.railWidth;
121
+ return { width: `${w}px` };
122
+ }
123
+ if (props.mode === "permanent") return { width: `${props.width}px` };
124
+ if (props.mode === "temporary") return { width: `${props.width}px` };
125
+ return {};
126
+ });
127
+ </script>