@bagelink/vue 0.0.25 → 0.0.35

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 +34 -9
  2. package/src/components/Btn.vue +221 -0
  3. package/src/components/Comments.vue +284 -0
  4. package/src/components/ContactArray.vue +142 -0
  5. package/src/components/ContactSubmissions.vue +45 -0
  6. package/src/components/DataPreview.vue +85 -0
  7. package/src/components/DropDown.vue +122 -0
  8. package/src/components/FileUploader.vue +353 -0
  9. package/src/components/FormKitTable.vue +299 -0
  10. package/src/components/FormSchema.vue +79 -0
  11. package/src/components/LangText.vue +32 -0
  12. package/src/components/ListItem.vue +20 -0
  13. package/src/components/ListView.vue +54 -0
  14. package/src/components/MaterialIcon.vue +19 -0
  15. package/src/components/Modal.vue +62 -0
  16. package/src/components/ModalForm.vue +109 -0
  17. package/src/components/NavBar.vue +353 -0
  18. package/src/components/PageTitle.vue +17 -0
  19. package/src/components/PersonPreview.vue +203 -0
  20. package/src/components/PersonPreviewFormkit.vue +205 -0
  21. package/src/components/RTXEditor.vue +151 -0
  22. package/src/components/RouterWrapper.vue +17 -0
  23. package/src/components/TabbedLayout.vue +83 -0
  24. package/src/components/TableSchema.vue +248 -0
  25. package/src/components/TopBar.vue +5 -0
  26. package/src/components/charts/BarChart.vue +316 -0
  27. package/src/components/dashboard/Lineart.vue +197 -0
  28. package/src/components/form/ItemRef.vue +45 -0
  29. package/src/components/form/MaterialIcon.vue +19 -0
  30. package/src/components/form/PlainInputField.vue +79 -0
  31. package/src/components/form/inputs/CheckInput.vue +143 -0
  32. package/src/components/form/inputs/Checkbox.vue +77 -0
  33. package/src/components/form/inputs/ColorPicker.vue +47 -0
  34. package/src/components/form/inputs/CurrencyInput.vue +137 -0
  35. package/src/components/form/inputs/DateInput.vue +55 -0
  36. package/src/components/form/inputs/DatetimeInput.vue +50 -0
  37. package/src/components/form/inputs/DurationInput.vue +55 -0
  38. package/src/components/form/inputs/DynamicLinkField.vue +142 -0
  39. package/src/components/form/inputs/EmailInput.vue +57 -0
  40. package/src/components/form/inputs/FloatInput.vue +52 -0
  41. package/src/components/form/inputs/IntInput.vue +53 -0
  42. package/src/components/form/inputs/JSONInput.vue +55 -0
  43. package/src/components/form/inputs/LinkField.vue +300 -0
  44. package/src/components/form/inputs/Password.vue +91 -0
  45. package/src/components/form/inputs/PasswordInput.vue +92 -0
  46. package/src/components/form/inputs/PlainText.vue +63 -0
  47. package/src/components/form/inputs/ReadOnlyInput.vue +28 -0
  48. package/src/components/form/inputs/RichTextEditor.vue +56 -0
  49. package/src/components/form/inputs/SelectField.vue +258 -0
  50. package/src/components/form/inputs/TableField.vue +319 -0
  51. package/src/components/form/inputs/TextArea.vue +79 -0
  52. package/src/components/form/inputs/TextInput.vue +63 -0
  53. package/src/components/form/inputs/index.ts +16 -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 +192 -0
  57. package/src/components/formkit/FileUploader.vue +391 -0
  58. package/src/components/formkit/MiscFields.vue +74 -0
  59. package/src/components/formkit/Toggle.vue +164 -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 +227 -0
  63. package/src/components/whatsapp/form/TextVariableExamples.vue +79 -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 +62 -0
  75. package/src/utils/modal.ts +101 -0
  76. package/src/utils/objects.ts +81 -0
  77. package/src/utils/strings.ts +36 -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,192 @@
1
+ <template>
2
+ <div class="bagel-input">
3
+ <div class="mt-1">
4
+ <div
5
+ class="bglform-contact mb-2"
6
+ v-for="(contact, i) in val"
7
+ :key="i"
8
+ >
9
+ <div
10
+ class="bglform-contact-confirm"
11
+ v-if="deleteCandidate === i"
12
+ >
13
+ <p class="txt14">
14
+ {{ form.sure }}
15
+ </p>
16
+ <Btn
17
+ thin
18
+ color="red"
19
+ @click="deleteContact(contact.id)"
20
+ >
21
+ {{ form.delete }}
22
+ </Btn>
23
+ <Btn
24
+ thin
25
+ @click="deleteCandidate = -1"
26
+ >
27
+ {{ form.cancel }}
28
+ </Btn>
29
+ </div>
30
+ <Checkbox
31
+ v-model="contact.primary"
32
+ @update:model-value="($event) => primaryHandler(i, $event)"
33
+ />
34
+ <input
35
+ class="bglform-contact-label"
36
+ v-model="contact.label"
37
+ type="text"
38
+ :placeholder="form.label"
39
+ >
40
+
41
+ <input
42
+ v-model="contact.email"
43
+ :placeholder="form.email"
44
+ v-if="context?.id === 'email'"
45
+ type="email"
46
+ >
47
+ <input
48
+ v-model="contact.phone"
49
+ :placeholder="form.phone"
50
+ v-if="context?.id === 'phone'"
51
+ type="tel"
52
+ >
53
+ <!-- <MaterialIcon @click="del(i)" icon="delete" class="btn-float" /> -->
54
+ <Btn
55
+ thin
56
+ @click="deleteCandidate = i"
57
+ icon="delete"
58
+ color="gray"
59
+ :disabled="contact.primary || val.length === 1 || deleteCandidate !== -1
60
+ "
61
+ />
62
+ </div>
63
+ <Btn
64
+ class="add-btn"
65
+ color="blue"
66
+ flat
67
+ thin
68
+ @click="val.push({})"
69
+ >
70
+ {{ form.add }} {{ context?.label }}
71
+ </Btn>
72
+ </div>
73
+ </div>
74
+ </template>
75
+
76
+ <script setup lang="ts">
77
+ import { watch } from 'vue';
78
+ // import type { BagelField } from '@/types/BagelField';
79
+ import { useBagel } from 'src/plugins/bagel';
80
+ import { Btn } from '@/components';
81
+ import Checkbox from '../form/inputs/Checkbox.vue';
82
+
83
+ const bagel = useBagel();
84
+
85
+ const props = defineProps<{
86
+ context: Record<string, any>;
87
+ form: {
88
+ sure: string
89
+ delete: string
90
+ cancel: string
91
+ label: string
92
+ email: string
93
+ phone: string
94
+ add: string
95
+ }
96
+ }>();
97
+
98
+ let val = $ref<any[]>([]);
99
+ let deleteCandidate = $ref<number>(-1);
100
+
101
+ const del = (i: number) => {
102
+ val.splice(i, 1);
103
+ };
104
+
105
+ const deleteContact = async (id: string) => {
106
+ if (id) await bagel.delete(`/person/contact/${id}`);
107
+ const index = val.findIndex((v) => v.id === id);
108
+ del(index);
109
+ deleteCandidate = -1;
110
+ };
111
+
112
+ const primaryHandler = (i: number, isPrimary: boolean) => {
113
+ if (!isPrimary) return;
114
+ val.forEach((contact, index) => {
115
+ if (index !== i) contact.primary = false;
116
+ });
117
+ };
118
+
119
+ watch(
120
+ () => props.context?.value,
121
+ () => {
122
+ val = props.context?.value;
123
+ },
124
+ { immediate: true },
125
+ );
126
+
127
+ watch(
128
+ () => val,
129
+ () => {
130
+ props.context?.node.input(val);
131
+ },
132
+ );
133
+ </script>
134
+
135
+ <style scoped>
136
+ .bglform-contact {
137
+ display: flex;
138
+ align-items: center;
139
+ gap: 0.5rem;
140
+ max-width: 700px;
141
+ position: relative;
142
+ }
143
+
144
+ .bglform-contact-label {
145
+ flex-basis: 140px;
146
+ }
147
+
148
+ .bglform-contact input[type='checkbox'] {
149
+ width: 30px;
150
+ min-width: 0;
151
+ }
152
+
153
+ .light.thin.btn-txt.btn {
154
+ padding-left: calc(var(--btn-padding) / 4);
155
+ padding-right: calc(var(--btn-padding) / 4);
156
+ }
157
+
158
+ .add-btn {
159
+ display: flex;
160
+ gap: 0.5rem;
161
+ align-items: center;
162
+ margin-inline-start: 1rem;
163
+ }
164
+
165
+ .add-btn:active {
166
+ background: none !important;
167
+ }
168
+
169
+ .add-btn::before {
170
+ content: '+';
171
+ font-size: 10px;
172
+ background: var(--bgl-blue-light);
173
+ border-radius: 100%;
174
+ height: 14px;
175
+ width: 14px;
176
+ display: flex;
177
+ align-items: center;
178
+ justify-content: center;
179
+ color: var(--bgl-blue);
180
+ }
181
+
182
+ .add-btn:hover::before {
183
+ background: var(--bgl-blue);
184
+ color: var(--bgl-white);
185
+ }
186
+
187
+ @media screen and (max-width: 910px) {
188
+ .bglform-contact-label {
189
+ min-width: 0;
190
+ }
191
+ }
192
+ </style>
@@ -0,0 +1,391 @@
1
+ <template>
2
+ <div class="files-wrapper flex">
3
+ <div
4
+ ref="dropZoneEl"
5
+ class="drop-zone flex-grow"
6
+ @click="openFileDialog"
7
+ @drop.prevent.stop="onDrop"
8
+ @dragleave="draggingOver = false"
9
+ >
10
+ <Transition name="pop">
11
+ <div
12
+ ref="dropCircle"
13
+ v-if="draggingOver"
14
+ class="drop-circle"
15
+ />
16
+ </Transition>
17
+ <div
18
+ class="img-label"
19
+ v-if="allowUpload"
20
+ >
21
+ <p>
22
+ {{ dragDropLabel }} <span>{{ browseLabel }}</span>
23
+ </p>
24
+ </div>
25
+ <div class="uploading-wrap">
26
+ <div
27
+ v-for="(item, index) in files"
28
+ :class="{ uploading: item.uploading }"
29
+ :key="index"
30
+ >
31
+ <div class="load-file-bar">
32
+ <!-- Preview File if image -->
33
+ <img
34
+ width="40"
35
+ v-if="isImg(item)"
36
+ :src="item.dataUrl"
37
+ :alt="item.name"
38
+ style="margin-inline-end: 10px"
39
+ >
40
+ <p>
41
+ {{ item.name }}
42
+ </p>
43
+ <div class="flex">
44
+ <div
45
+ class="pie"
46
+ :style="`--p:${item.progress}`"
47
+ style="--b: 2px"
48
+ :class="{ complete: item.progress === 100 }"
49
+ >
50
+ <span
51
+ class="progress"
52
+ v-if="item.progress < 100"
53
+ >{{
54
+ `${item.progress.toFixed(0)}`
55
+ }}</span>
56
+ <MaterialIcon
57
+ class="success"
58
+ icon="check"
59
+ />
60
+ </div>
61
+ <Btn
62
+ thin
63
+ class="delete-btn"
64
+ @click.stop="deleteImg(item)"
65
+ icon="delete"
66
+ v-if="item.progress === 100"
67
+ />
68
+ </div>
69
+ </div>
70
+ </div>
71
+ </div>
72
+ </div>
73
+ <input
74
+ class="file-input"
75
+ type="file"
76
+ @change="handleFileInput"
77
+ ref="fileInputEl"
78
+ :multiple="context?.attrs.multiple || false"
79
+ >
80
+ </div>
81
+ </template>
82
+
83
+ <script setup lang="ts">
84
+ interface UploadFile {
85
+ dataUrl: string;
86
+ progress: number;
87
+ uploading: boolean;
88
+ file?: File;
89
+ name: string;
90
+ serverFile?: any;
91
+ uploaded: boolean;
92
+ }
93
+
94
+ import { onMounted, onUnmounted } from 'vue';
95
+ import { useBagel } from 'src/plugins/bagel';
96
+ import { MaterialIcon, Btn } from '@/components';
97
+
98
+ const bagel = useBagel();
99
+
100
+ let draggingOver = $ref(false);
101
+ const dropCircle = $ref<HTMLElement>();
102
+ const dropZoneEl = $ref<HTMLElement>();
103
+ const fileInputEl = $ref<HTMLInputElement>();
104
+
105
+ const files = $ref<UploadFile[]>([]);
106
+
107
+ const props = withDefaults(defineProps<{
108
+ context: Record<string, any>;
109
+ dragDropLabel: string;
110
+ browseLabel: string;
111
+ }>(), {
112
+ dragDropLabel: 'Drag and drop your files here',
113
+ browseLabel: 'or browse',
114
+ });
115
+
116
+ const allowUpload = $computed(() => {
117
+ const tooManyFiles = !props.context?.attrs.multiple && files.length > 0;
118
+ return !tooManyFiles;
119
+ });
120
+
121
+ const openFileDialog = () => (allowUpload ? fileInputEl?.click() : '');
122
+
123
+ function animateCircle(e: DragEvent) {
124
+ e.preventDefault();
125
+ const zoneRect = dropZoneEl?.getBoundingClientRect?.();
126
+ if (!zoneRect) return;
127
+ draggingOver = true;
128
+ const left = e.clientX - zoneRect.left;
129
+ const top = e.clientY - zoneRect.top;
130
+ dropCircle?.style?.setProperty?.('left', `${left}px`);
131
+ dropCircle?.style?.setProperty?.('top', `${top}px`);
132
+ }
133
+
134
+ function emitValue() {
135
+ // const fileValues = files.map((f) => f.serverFile?.id);
136
+ // console.log({ files });
137
+ if (!props.context?.attrs.multiple) props.context?.node.input(files[0].serverFile);
138
+ // eslint-disable-next-line no-alert
139
+ else alert('not implemented');
140
+ }
141
+
142
+ const isImg = (file: UploadFile) => file.file?.type.includes('image') ||
143
+ file.serverFile?.mimetype?.match(/image\/|jpg|png|gif|bmp|jpeg/i) ||
144
+ file.serverFile.extension?.match(/jpg|png|gif|bmp|jpeg/i);
145
+
146
+ function uploadFiles() {
147
+ files.forEach(async (file) => {
148
+ if (file.uploaded || file.uploading || !file.file) return;
149
+ file.uploading = true;
150
+ file.serverFile = await bagel.uploadFile(file.file, {
151
+ onUploadProgress: (e) => (file.progress = e.progress * 100 - 1),
152
+ });
153
+ file.progress += 1;
154
+ emitValue();
155
+ file.uploaded = true;
156
+ file.uploading = false;
157
+ });
158
+ }
159
+
160
+ const deleteImg = async (file: UploadFile) => {
161
+ await bagel.delete(`files/${file.serverFile.id}`);
162
+ const index = files.indexOf(file);
163
+ files.splice(index, 1);
164
+ emitValue();
165
+ };
166
+
167
+ function readAsDataURL(file: File): Promise<any> {
168
+ return new Promise((resolve, reject) => {
169
+ const reader = new FileReader();
170
+ reader.onload = () => resolve(reader.result);
171
+ reader.onerror = reject;
172
+ reader.readAsDataURL(file);
173
+ });
174
+ }
175
+
176
+ async function addFiles(addedFiles: FileList) {
177
+ if (!allowUpload) return;
178
+ for (let i = 0; i < addedFiles.length; i++) {
179
+ const f = addedFiles[i];
180
+ const file: UploadFile = {
181
+ // eslint-disable-next-line no-await-in-loop
182
+ dataUrl: await readAsDataURL(f),
183
+ file: f,
184
+ name: f.name,
185
+ progress: 0,
186
+ uploading: false,
187
+ uploaded: false,
188
+ };
189
+ files.push(file);
190
+ }
191
+ uploadFiles();
192
+ }
193
+
194
+ onMounted(() => {
195
+ dropZoneEl?.addEventListener('dragover', animateCircle);
196
+ if (!props.context?.attrs.multiple && props.context?.value) {
197
+ files.push({
198
+ serverFile: props.context?.value,
199
+ uploaded: true,
200
+ uploading: false,
201
+ progress: 100,
202
+ dataUrl: props.context?.value?.url,
203
+ name: props.context?.value?.name,
204
+ });
205
+ }
206
+ });
207
+ onUnmounted(() => dropZoneEl?.removeEventListener('dragover', animateCircle));
208
+
209
+ function handleFileInput(e: Event) {
210
+ const filesToAdd: FileList = (e.target as any).files;
211
+ void addFiles(filesToAdd); // TODO: Nati: should be awaited?
212
+ }
213
+
214
+ function onDrop(e: DragEvent) {
215
+ draggingOver = false;
216
+ e.preventDefault();
217
+ const filesToAdd = e.dataTransfer?.files;
218
+ if (filesToAdd) void addFiles(filesToAdd); // TODO: Nati: should be awaited?
219
+ }
220
+ </script>
221
+ <style>
222
+ .uploading-wrap {
223
+ width: 100%;
224
+ padding-right: 5px;
225
+ padding-left: 5px;
226
+ }
227
+
228
+ /*
229
+ .uploading {}
230
+ */
231
+
232
+ .img-label .icon-font {
233
+ font-size: 30px;
234
+ margin-bottom: 10px;
235
+ }
236
+
237
+ .img-label span {
238
+ text-decoration: underline;
239
+ }
240
+
241
+ .file-input {
242
+ display: none;
243
+ }
244
+
245
+ .files-wrapper {
246
+ flex-direction: column;
247
+ border-radius: 10px;
248
+ /*overflow: hidden;*/
249
+ min-height: calc(var(--input-height) * 1.5);
250
+
251
+ font-size: var(--input-font-size);
252
+ }
253
+
254
+ .drop-zone {
255
+ background-color: var(--bgl-bg);
256
+ height: 100%;
257
+ width: 100%;
258
+ flex-grow: 1;
259
+ position: relative;
260
+ overflow: hidden;
261
+ cursor: pointer;
262
+ transition: var(--bgl-transition);
263
+ outline: dashed 1px var(--border-color);
264
+ border-radius: 10px;
265
+ padding: 1px;
266
+ display: flex;
267
+ flex-direction: column;
268
+ align-items: center;
269
+ justify-content: center;
270
+ color: var(--input-color);
271
+ }
272
+
273
+ .drop-zone:hover {
274
+ color: var(--bgl-blue);
275
+ outline: dashed 1px var(--bgl-blue-tint);
276
+ }
277
+
278
+ .drop-circle {
279
+ pointer-events: none;
280
+ position: absolute;
281
+ width: 100px;
282
+ height: 100px;
283
+ border-radius: 50%;
284
+ background-color: var(--bgl-blue-tint);
285
+ display: flex;
286
+ transform: translate(-50%, -50%) scale(1);
287
+ transform-origin: left top;
288
+ }
289
+
290
+ .load-file-bar {
291
+ display: flex;
292
+ align-items: center;
293
+ justify-content: space-between;
294
+ background: var(--bgl-white);
295
+ border-radius: var(--btn-border-radius);
296
+ width: 100%;
297
+ color: var(--input-color);
298
+ height: var(--btn-height);
299
+ padding: 0.5rem;
300
+ height: 46px;
301
+ box-shadow: 0 1px 2px 0 rgb(0 0 0 / 10%);
302
+ white-space: nowrap;
303
+ }
304
+
305
+ .load-file-bar p {
306
+ width: calc(100% - 40px);
307
+ overflow: hidden;
308
+ text-overflow: ellipsis;
309
+ }
310
+
311
+ .load-file-bar span {
312
+ font-size: 10px;
313
+ }
314
+
315
+ .pie {
316
+ width: 30px;
317
+ height: 30px;
318
+ position: relative;
319
+ display: flex;
320
+ align-items: center;
321
+ justify-content: center;
322
+ }
323
+
324
+ .pie:before {
325
+ content: '';
326
+ position: absolute;
327
+ border-radius: 50%;
328
+ inset: 0;
329
+ transition: all 0.2s ease-in-out;
330
+ background: conic-gradient(var(--bgl-blue) calc(var(--p) * 1%), #0000 0);
331
+ -webkit-mask: radial-gradient(farthest-side,
332
+ #0000 calc(99% - var(--b)),
333
+ #000 calc(100% - var(--b)));
334
+ mask: radial-gradient(farthest-side,
335
+ #0000 calc(99% - var(--b)),
336
+ #000 calc(100% - var(--b)));
337
+ }
338
+
339
+ .pie .success {
340
+ transform: scale(0);
341
+ opacity: 0;
342
+ transition: all 0.3s ease-in-out;
343
+ }
344
+
345
+ .pie .progress {
346
+ position: absolute;
347
+ font-size: 10px;
348
+ }
349
+
350
+ .pie.complete .progress {
351
+ display: none;
352
+ }
353
+
354
+ .pie.complete .success {
355
+ transform: scale(1.3);
356
+ opacity: 1;
357
+ }
358
+
359
+ .pie.complete:before {
360
+ background: conic-gradient(var(--bgl-green) calc(var(--p) * 1%), #0000 0);
361
+ }
362
+
363
+ .pie.complete {
364
+ color: var(--bgl-green);
365
+ }
366
+ </style>
367
+ <style>
368
+ .pop-enter-active {
369
+ transition: scale 0.2s cubic-bezier(0.55, 0, 0.1, 1);
370
+ }
371
+
372
+ .pop-leave-active {
373
+ transition: scale 0.2s cubic-bezier(0.55, 0, 0.1, 1);
374
+ }
375
+
376
+ .pop-enter-from,
377
+ .pop-leave-to {
378
+ scale: 0;
379
+ }
380
+
381
+ .delete-btn {
382
+ margin-inline-end: -30px;
383
+ opacity: 0;
384
+ margin-inline-start: 10px;
385
+ }
386
+
387
+ .uploading-wrap:hover .delete-btn {
388
+ opacity: 1;
389
+ margin-inline-end: 0;
390
+ }
391
+ </style>
@@ -0,0 +1,74 @@
1
+ <template>
2
+ <div class="misc-wrap">
3
+ <Btn
4
+ class="add-btn"
5
+ color="gray"
6
+ flat
7
+ @click="addToField(field)"
8
+ v-for="(field, i) in fields.filter(
9
+ (field: any) => field.value?.length === 0,
10
+ )"
11
+ :key="i"
12
+ thin
13
+ >
14
+ {{ addBtnLabel }} {{ field.context?.label }}
15
+ </Btn>
16
+ </div>
17
+ </template>
18
+
19
+ <script lang="ts" setup>
20
+ import { Btn } from '@/components';
21
+
22
+ const props = defineProps<{
23
+ context: Record<string, any>;
24
+ addBtnLabel: string
25
+ }>();
26
+
27
+ const fields = $computed(() => props.context?.node?.parent?.children || []);
28
+
29
+ const addToField = (field: any) => {
30
+ field.input([{}]);
31
+ console.log(fields);
32
+ };
33
+ </script>
34
+
35
+ <style scoped>
36
+ .misc-wrap {
37
+ display: flex;
38
+ gap: 1rem;
39
+ border-top: 1px solid var(--border-color);
40
+ padding-top: 0.5rem;
41
+ margin-bottom: auto;
42
+ }
43
+
44
+ .gray.thin.btn-txt.btn.add-btn {
45
+ display: flex;
46
+ gap: 0.5rem;
47
+ align-items: center;
48
+ padding-left: 0;
49
+ padding-right: 0;
50
+ transition: var(--bgl-transition);
51
+ }
52
+
53
+ .add-btn:active {
54
+ background: none !important;
55
+ }
56
+
57
+ .add-btn::before {
58
+ content: '+';
59
+ font-size: 10px;
60
+ background: var(--bgl-gray-light);
61
+ border-radius: 100%;
62
+ height: 14px;
63
+ width: 14px;
64
+ display: flex;
65
+ align-items: center;
66
+ justify-content: center;
67
+ color: var(--bgl-gray);
68
+ }
69
+
70
+ .add-btn:hover::before {
71
+ background: var(--bgl-blue);
72
+ color: var(--bgl-white);
73
+ }
74
+ </style>