@bagelink/vue 0.0.22 → 0.0.32

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 (82) hide show
  1. package/package.json +32 -9
  2. package/src/components/Btn.vue +221 -0
  3. package/src/components/Comments.vue +265 -0
  4. package/src/components/ContactArray.vue +127 -0
  5. package/src/components/ContactSubmissions.vue +42 -0
  6. package/src/components/DataPreview.vue +72 -0
  7. package/src/components/DropDown.vue +122 -0
  8. package/src/components/FileUploader.vue +344 -0
  9. package/src/components/FormKitTable.vue +250 -0
  10. package/src/components/FormSchema.vue +65 -0
  11. package/src/components/LangText.vue +30 -0
  12. package/src/components/ListItem.vue +16 -0
  13. package/src/components/ListView.vue +39 -0
  14. package/src/components/MaterialIcon.vue +16 -0
  15. package/src/components/Modal.vue +50 -0
  16. package/src/components/ModalForm.vue +94 -0
  17. package/src/components/NavBar.vue +343 -0
  18. package/src/components/PageTitle.vue +17 -0
  19. package/src/components/PersonPreview.vue +205 -0
  20. package/src/components/PersonPreviewFormkit.vue +205 -0
  21. package/src/components/RTXEditor.vue +147 -0
  22. package/src/components/RouterWrapper.vue +9 -0
  23. package/src/components/TabbedLayout.vue +80 -0
  24. package/src/components/TableSchema.vue +213 -0
  25. package/src/components/TopBar.vue +5 -0
  26. package/src/components/charts/BarChart.vue +290 -0
  27. package/src/components/dashboard/Lineart.vue +165 -0
  28. package/src/components/form/ItemRef.vue +38 -0
  29. package/src/components/form/MaterialIcon.vue +19 -0
  30. package/src/components/form/PlainInputField.vue +80 -0
  31. package/src/components/form/inputs/CheckInput.vue +143 -0
  32. package/src/components/form/inputs/Checkbox.vue +69 -0
  33. package/src/components/form/inputs/ColorPicker.vue +37 -0
  34. package/src/components/form/inputs/CurrencyInput.vue +133 -0
  35. package/src/components/form/inputs/DateInput.vue +49 -0
  36. package/src/components/form/inputs/DatetimeInput.vue +46 -0
  37. package/src/components/form/inputs/DurationInput.vue +51 -0
  38. package/src/components/form/inputs/DynamicLinkField.vue +140 -0
  39. package/src/components/form/inputs/EmailInput.vue +53 -0
  40. package/src/components/form/inputs/FloatInput.vue +48 -0
  41. package/src/components/form/inputs/IntInput.vue +49 -0
  42. package/src/components/form/inputs/JSONInput.vue +51 -0
  43. package/src/components/form/inputs/LinkField.vue +293 -0
  44. package/src/components/form/inputs/Password.vue +89 -0
  45. package/src/components/form/inputs/PasswordInput.vue +89 -0
  46. package/src/components/form/inputs/PlainText.vue +52 -0
  47. package/src/components/form/inputs/ReadOnlyInput.vue +24 -0
  48. package/src/components/form/inputs/RichTextEditor.vue +54 -0
  49. package/src/components/form/inputs/SelectField.vue +253 -0
  50. package/src/components/form/inputs/TableField.vue +321 -0
  51. package/src/components/form/inputs/TextArea.vue +70 -0
  52. package/src/components/form/inputs/TextInput.vue +53 -0
  53. package/src/components/form/inputs/index.ts +17 -0
  54. package/src/components/formkit/AddressArray.vue +240 -0
  55. package/src/components/formkit/BankDetailsArray.vue +265 -0
  56. package/src/components/formkit/ContactArrayFormKit.vue +151 -0
  57. package/src/components/formkit/FileUploader.vue +391 -0
  58. package/src/components/formkit/MiscFields.vue +69 -0
  59. package/src/components/formkit/Toggle.vue +160 -0
  60. package/src/components/formkit/index.ts +29 -0
  61. package/src/components/index.ts +20 -0
  62. package/src/components/whatsapp/form/MsgTemplate.vue +220 -0
  63. package/src/components/whatsapp/form/TextVariableExamples.vue +74 -0
  64. package/src/components/whatsapp/interfaces.ts +58 -0
  65. package/src/index.ts +1 -26
  66. package/src/plugins/bagel.ts +26 -0
  67. package/src/styles/modal.css +90 -0
  68. package/src/types/BagelField.ts +57 -0
  69. package/src/types/BtnOptions.ts +14 -0
  70. package/src/types/Person.ts +51 -0
  71. package/src/types/file.ts +12 -0
  72. package/src/types/index.ts +4 -0
  73. package/src/types/materialIcons.d.ts +3005 -0
  74. package/src/utils/index.ts +57 -0
  75. package/src/utils/modal.ts +95 -0
  76. package/src/utils/objects.ts +81 -0
  77. package/src/utils/strings.ts +29 -0
  78. package/dist/index.cjs +0 -23
  79. package/dist/index.d.cts +0 -12
  80. package/dist/index.d.mts +0 -12
  81. package/dist/index.d.ts +0 -12
  82. package/dist/index.mjs +0 -19
@@ -0,0 +1,250 @@
1
+ <template>
2
+ <div class="table-list-wrap h-100">
3
+ <Transition name="fade">
4
+ <div class="table-list">
5
+ <table class="infinite-wrapper">
6
+ <thead class="row first-row">
7
+ <th class="col" v-for="field in columns" :key="field.id" @click="sort(field.id)">
8
+ <div class="flex">
9
+ {{ field.label || field.id }}
10
+ <div class="list-arrows" :class="{ sorted: sortField === field.id }">
11
+ <MaterialIcon :class="{ desc: sortDirection === 'DESC' }" icon="keyboard_arrow_up" />
12
+ </div>
13
+ </div>
14
+ </th>
15
+ </thead>
16
+ <tbody ref="infinite" class="rows infinite" :class="{ loading }">
17
+ <tr
18
+ @click="selectElement(row)" class="row row-item position-relative" v-for="row in data"
19
+ :key="row.id"
20
+ >
21
+ <td class="col" v-for="field in columns" :key="`${field.id}-${row.id}`">
22
+ <slot v-if="slots[field.id]" :name="field.id" :row="row" :field="field"/>
23
+ <div v-else>
24
+ <div v-if="field.inputType === 'DateInput'">
25
+ {{ new Date(row[field.id]).toLocaleDateString() }}
26
+ </div>
27
+ <div v-else-if="field.inputType === 'CheckInput'">
28
+ <MaterialIcon icon="check" class="pill green" v-if="row[field.id]" />
29
+ <MaterialIcon icon="close" class="pill" v-else />
30
+ </div>
31
+ <div v-else-if="field.inputType === 'ItemRef' && row[field.id]">
32
+ <Btn
33
+ v-if="field.refCollection" color="gray" class="thin" @click="
34
+ $router.push(
35
+ `/${field.refCollection}/${row[field.id].id}`,
36
+ )"
37
+ >
38
+ {{
39
+ field.refFields
40
+ ?.map((k) => row[field.id][k])
41
+ .join(' ') || row[field.id].id
42
+ }}
43
+ <MaterialIcon icon="arrow_forward" />
44
+ </Btn>
45
+ <Btn
46
+ icon="receipt" is="a" thin v-else-if="field.link"
47
+ :href="row[field.id][field.link]" target="_blank"
48
+ >
49
+ {{
50
+ field.refFields
51
+ ?.map((k) => row[field.id][k])
52
+ .join(' ') || row[field.id].id
53
+ }}
54
+ </Btn>
55
+ <div
56
+ class="pill" v-else
57
+ :class="field.refFields?.map((k) => row[field.id][k]).join(' ') || row[field.id].id"
58
+ >
59
+ {{
60
+ field.refFields
61
+ ?.map((k) => row[field.id][k])
62
+ .join(' ') || row[field.id].id
63
+ }}
64
+ </div>
65
+ </div>
66
+ <div class="max-col-width" v-else>
67
+ {{ row[field.id] }}
68
+ </div>
69
+ </div>
70
+ </td>
71
+ </tr>
72
+ </tbody>
73
+ </table>
74
+ </div>
75
+ </Transition>
76
+ </div>
77
+ </template>
78
+
79
+ <script setup lang="ts">
80
+ import { computed, ref, useSlots } from 'vue';
81
+ import { BagelField } from '@/types';
82
+ import { Btn, MaterialIcon } from '@/components';
83
+
84
+ const slots = useSlots();
85
+ const loading = ref(true);
86
+
87
+ const props = defineProps<{
88
+ data: any[];
89
+ schema?: BagelField[];
90
+ }>();
91
+
92
+ const emit = defineEmits(['selectElement']);
93
+
94
+ const selectElement = (data: Record<string, any>) => {
95
+ emit('selectElement', data);
96
+ };
97
+
98
+ // const sortList = () => {};
99
+ const sortDirection = ref('');
100
+ const sortField = ref('');
101
+
102
+ const sort = (fieldname: string) => {
103
+ if (sortField.value === fieldname) {
104
+ if (sortDirection.value === 'ASC') sortDirection.value = 'DESC';
105
+ else sortField.value = '';
106
+ } else {
107
+ sortField.value = fieldname;
108
+ sortDirection.value = 'ASC';
109
+ }
110
+ };
111
+
112
+ const columns = computed<BagelField[]>(
113
+ (): BagelField[] => props.schema
114
+ || Object.keys(props.data[0]).map((k: string) => ({
115
+ id: k,
116
+ inputType: 'PlainText',
117
+ })),
118
+ );
119
+ </script>
120
+
121
+ <style scoped>
122
+ .Paid {
123
+ background-color: var(--bgl-green);
124
+ color: white;
125
+ }
126
+
127
+ .Error {
128
+ background-color: var(--bgl-red-tint);
129
+ color: var(--bgl-red)
130
+ }
131
+
132
+ .list-arrows {
133
+ opacity: 0;
134
+ }
135
+
136
+ .list-arrows .icon-font {
137
+ transition: all ease-in-out 0.2s;
138
+ }
139
+
140
+ .list-arrows.sorted {
141
+ opacity: 1;
142
+ }
143
+
144
+ .list-arrows.sorted .desc {
145
+ transform: rotate(180deg);
146
+ }
147
+
148
+ table {
149
+ border-collapse: separate;
150
+ border-spacing: 0 15px;
151
+ border-collapse: collapse;
152
+ }
153
+
154
+ th {
155
+ font-weight: 400;
156
+ }
157
+
158
+ .row {
159
+ border-bottom: 1px solid var(--border-color);
160
+ cursor: pointer;
161
+ }
162
+
163
+ .row.first-row {
164
+ font-size: 0.8rem;
165
+ color: var(--bgl-black-tint);
166
+ position: sticky;
167
+ top: 0;
168
+ z-index: 2;
169
+ background: var(--bgl-white);
170
+ height: 50px;
171
+ vertical-align: bottom;
172
+ }
173
+
174
+ .row.first-row::after {
175
+ content: '';
176
+ border-bottom: 1px solid var(--border-color);
177
+ position: absolute;
178
+ left: 0;
179
+ right: 0;
180
+ bottom: -1px;
181
+ }
182
+
183
+ .first-row .col {
184
+ cursor: pointer;
185
+ background: var(--bgl-white);
186
+ }
187
+
188
+ .col {
189
+ white-space: nowrap;
190
+ padding: 14px;
191
+ transition: var(--bgl-transition);
192
+ line-height: 1;
193
+ padding-left: 1rem;
194
+ padding-right: 1rem;
195
+ align-items: center;
196
+ }
197
+
198
+ .col>div {
199
+ display: flex;
200
+ gap: 0.5rem;
201
+ }
202
+
203
+ .max-col-width {
204
+ max-width: 30vw;
205
+ overflow: hidden;
206
+ text-overflow: ellipsis;
207
+ }
208
+
209
+ .col.check .icon-font {
210
+ border-radius: 100%;
211
+ background: var(--bgl-blue-20);
212
+ color: var(--bgl-blue);
213
+ width: 20px;
214
+ height: 20px;
215
+ display: flex;
216
+ align-items: center;
217
+ justify-content: center;
218
+ margin-top: -2px;
219
+ }
220
+
221
+ .rows {
222
+ font-size: 0.8125em;
223
+ }
224
+
225
+ .table-list {
226
+ height: 100%;
227
+ position: relative;
228
+ padding-left: 0 !important;
229
+ padding-right: 0 !important;
230
+ overflow: auto;
231
+ }
232
+
233
+ .BagelTable .table-list {
234
+ overflow: unset;
235
+ }
236
+
237
+ .row-item {
238
+ height: 50px;
239
+ transition: all 200ms ease;
240
+ }
241
+
242
+ .row-item:hover {
243
+ background: var(--bgl-gray-light);
244
+ }
245
+
246
+ .infinite-wrapper {
247
+ overflow-y: auto;
248
+ width: 100%;
249
+ }
250
+ </style>
@@ -0,0 +1,65 @@
1
+ <template>
2
+ <div>
3
+ <FormKit
4
+ type="form" :modelValue="modelValue" @update:modelValue="handleEmit" @submit="runSubmit"
5
+ :submitLabel="$t('save')"
6
+ >
7
+ <FormKitSchema :schema="schema" :data="data" />
8
+ </FormKit>
9
+ <Btn
10
+ class="del-top" v-if="modelValue?.id && onDelete" @click="runDelete" value="Delete" flat icon="delete"
11
+ color="red" thin
12
+ />
13
+ </div>
14
+ </template>
15
+
16
+ <script lang="ts" setup>
17
+ import { reactive } from 'vue';
18
+ import { type FormKitSchemaDefinition } from '@formkit/core';
19
+
20
+ import { Btn } from '@/components';
21
+ import { useModal } from '@/utils';
22
+
23
+ const { showModal } = useModal();
24
+ const emits = defineEmits(['update:modelValue', 'submit']);
25
+ const handleEmit = (val: any) => emits('update:modelValue', val);
26
+ const runSubmit = (val: any) => emits('submit', val);
27
+
28
+ const props = withDefaults(defineProps<{
29
+ modelValue?: any;
30
+ schema: FormKitSchemaDefinition;
31
+ onDelete?: any |((id: string) => void);
32
+ $t: (key: string) => string;
33
+ }>(),{
34
+ $t: (key: string) => key,
35
+ });
36
+
37
+ const data = reactive({
38
+ ...props.modelValue,
39
+ t: (val: string) => props.$t(val),
40
+ });
41
+
42
+ const runDelete = () => {
43
+ showModal(
44
+ {
45
+ class: 'small-modal',
46
+ title: props.$t('Are you sure?'),
47
+ actions: [
48
+ {
49
+ value: 'Confirm',
50
+ color: 'red',
51
+ onClick: () => props.onDelete?.(data.id),
52
+ },
53
+ { value: 'Cancel', color: 'gray' },
54
+ ],
55
+ },
56
+ { default: props.$t('form.deleteMessage') },
57
+ );
58
+ };
59
+ </script>
60
+
61
+ <style>
62
+ .del-top {
63
+ transform: translateY(-2.6rem);
64
+ }
65
+ </style>
@@ -0,0 +1,30 @@
1
+ <template>
2
+ <span ref="el" />
3
+ {{ input }}
4
+ <!-- v-html="$t(input)" -->
5
+ </template>
6
+ <script setup lang="ts">
7
+ defineProps<{
8
+ input: any;
9
+ }>();
10
+ </script>
11
+ <style>
12
+ .translate {
13
+ cursor: pointer;
14
+ position: relative;
15
+ }
16
+
17
+ .translate:hover {
18
+ /* color: var(--bgl-blue); */
19
+ }
20
+
21
+ .translate-globe {
22
+ position: absolute;
23
+ top: -5px;
24
+ right: -5px;
25
+ width: 10px;
26
+ height: 10px;
27
+ background-size: contain;
28
+ /* background-image: url('@/assets/globe.svg'); */
29
+ }
30
+ </style>
@@ -0,0 +1,16 @@
1
+ <template>
2
+ <component :is="to ? 'RouterLink' : 'div'" :to="to" class="list-item ellipsis">
3
+ <p class="txt16 no-margin">
4
+ <slot />
5
+ </p>
6
+ <p class="txt14 no-margin txtgray">
7
+ <slot name="subtitle" />
8
+ </p>
9
+ </component>
10
+ </template>
11
+
12
+ <script lang="ts" setup>
13
+ defineProps<{
14
+ to?: string;
15
+ }>();
16
+ </script>
@@ -0,0 +1,39 @@
1
+ <template>
2
+ <div class="card list-view grid thin">
3
+ <div class="list-header flex gap-3 align-items-top">
4
+ <div v-if="enableSearch" class="bagel-input search-wrap">
5
+ <input :placeholder="searchPlaceholder" v-model="searchTerm" @input="search()">
6
+ <MaterialIcon class="txtgray" icon="search" />
7
+ </div>
8
+ <Btn color="blue" v-if="enableAdd" icon="add" @click="emit('add')" />
9
+ </div>
10
+ <div class="list-content grid auto-flow-rows align-items-start">
11
+ <slot />
12
+ </div>
13
+ </div>
14
+ </template>
15
+
16
+ <script lang="ts" setup>
17
+ import { MaterialIcon, Btn } from '@/components';
18
+ import { debounce } from '@/utils';
19
+
20
+ defineProps<{
21
+ enableAdd: boolean;
22
+ enableSearch: boolean;
23
+ open: boolean;
24
+ searchPlaceholder: string;
25
+ }
26
+ >()
27
+ const emit = defineEmits(['search', 'add', 'debounce']);
28
+ const searchTerm = $ref('');
29
+ const search = () => {
30
+ emit('search', searchTerm);
31
+ debounce(() => emit('debounce', searchTerm));
32
+ };
33
+ </script>
34
+
35
+ <style>
36
+ .search-wrap {
37
+ flex-grow: 1;
38
+ }
39
+ </style>
@@ -0,0 +1,16 @@
1
+ <template>
2
+ <div class="icon-font" :style="{ fontSize: `${size}rem` }">
3
+ {{ icon }}
4
+ </div>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+ import type { MaterialIcons } from '@/types/materialIcons';
9
+
10
+ defineProps<{
11
+ icon: MaterialIcons;
12
+ size?: number;
13
+ }>();
14
+ </script>
15
+
16
+ <style scoped></style>
@@ -0,0 +1,50 @@
1
+ <template>
2
+ <div class="bg-dark" :class="{ 'is-side': side, 'is-active': isActive }"
3
+ @click="() => (dismissable ? closeModal() : '')" @keydown.esc="closeModal">
4
+ <div class="card modal" @click.stop>
5
+ <header class="tool-bar">
6
+ <slot name="toolbar" />
7
+ </header>
8
+ <h3 class="modal-title">
9
+ {{ title }}
10
+ </h3>
11
+ <slot />
12
+ <footer class="modal-footer mt-3">
13
+ <Btn v-for="(action, i) in actions" :key="i" @click="closeModal" color="gray" v-bind="action" />
14
+ <slot name="footer" />
15
+ </footer>
16
+ </div>
17
+ </div>
18
+ </template>
19
+
20
+ <script lang="ts" setup>
21
+ import { onMounted } from 'vue';
22
+ import { Btn } from '@/components';
23
+ import { BtnOptions } from '@/types/BtnOptions';
24
+ import '../styles/modal.css';
25
+
26
+ defineProps<{
27
+ side?: boolean;
28
+ title?: string;
29
+ dismissable?: boolean;
30
+ actions?: BtnOptions[];
31
+ }>();
32
+
33
+ let isActive = $ref<boolean>(false);
34
+
35
+ onMounted(() => {
36
+ setTimeout(() => {
37
+ isActive = true;
38
+ }, 1);
39
+ });
40
+
41
+ const emit = defineEmits(['update:isModalVisible']);
42
+
43
+ const closeModal = () => {
44
+ isActive = false;
45
+ setTimeout(() => {
46
+ emit('update:isModalVisible', false);
47
+ }, 200);
48
+ };
49
+ </script>
50
+
@@ -0,0 +1,94 @@
1
+ <template>
2
+ <div
3
+ class="bg-dark" :class="{ 'is-side': side, 'is-active': isActive }"
4
+ @click="() => (dismissable ? closeModal() : '')" @keydown.esc="closeModal"
5
+ >
6
+ <div class="card modal" @click.stop>
7
+ <header class="tool-bar">
8
+ <slot name="toolbar" />
9
+ <Btn :style="{ float: side ? 'left' : 'right' }" flat icon="close" @click="closeModal" />
10
+ <h3 class="modal-title">
11
+ {{ title }}
12
+ </h3>
13
+ </header>
14
+ <FormSchema
15
+ :onDelete="onDelete?runDelete:null" :modelValue="modelValue" @update:modelValue="handleEmit"
16
+ @submit="runSubmit" :schema="computedFormSchema"
17
+ />
18
+ </div>
19
+ </div>
20
+ </template>
21
+
22
+ <script lang="ts" setup>
23
+ import { type FormKitSchemaDefinition } from '@formkit/core';
24
+ import { onMounted } from 'vue';
25
+ import { Btn, FormSchema } from '@/components';
26
+ import '../styles/modal.css';
27
+ import { BtnOptions } from '@/types/BtnOptions';
28
+
29
+ // import { BagelField } from '@/types';
30
+
31
+ const props = defineProps<{
32
+ side?: boolean;
33
+ title?: string;
34
+ dismissable?: boolean;
35
+ actions?: BtnOptions[];
36
+ schema:FormKitSchemaDefinition |(() => FormKitSchemaDefinition);
37
+ modelValue?: Record<string, any>;
38
+ onSubmit?: ((formData: any) => void);
39
+ onDelete?: ((id: string) => void);
40
+ }>();
41
+
42
+ const computedFormSchema = $computed(() => {
43
+ if (typeof props.schema === 'function') {
44
+ return props.schema();
45
+ }
46
+ return props.schema;
47
+ });
48
+
49
+ let isActive = $ref<boolean>(false);
50
+
51
+ onMounted(() => {
52
+ setTimeout(() => {
53
+ isActive = true;
54
+ }, 1);
55
+ });
56
+
57
+ const emit = defineEmits(['update:isModalVisible', 'update:modelValue']);
58
+ const handleEmit = (value: any) => {
59
+ emit('update:modelValue', value);
60
+ };
61
+
62
+ const closeModal = () => {
63
+ isActive = false;
64
+ setTimeout(() => {
65
+ emit('update:isModalVisible', false);
66
+ }, 200);
67
+ };
68
+
69
+ const runSubmit = async (formData: any) => {
70
+ try {
71
+ await props.onSubmit?.(formData);
72
+ closeModal();
73
+ } catch (err) {
74
+ console.error(err);
75
+ }
76
+ };
77
+
78
+ const runDelete = () => {
79
+ props.onDelete?.(props.modelValue?.id);
80
+ closeModal();
81
+ };
82
+ </script>
83
+
84
+ <style scoped>
85
+ .modal-title {
86
+ margin-top: 0.5rem;
87
+ }
88
+
89
+ @media screen and (max-width: 910px) {
90
+ .modal-title {
91
+ margin-top: 1rem;
92
+ }
93
+ }
94
+ </style>