@bagelink/vue 1.4.153 → 1.4.159

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 (46) hide show
  1. package/dist/components/Alert.vue.d.ts +17 -2
  2. package/dist/components/Alert.vue.d.ts.map +1 -1
  3. package/dist/components/ListItem.vue.d.ts +2 -2
  4. package/dist/components/ListItem.vue.d.ts.map +1 -1
  5. package/dist/components/Loading.vue.d.ts +3 -2
  6. package/dist/components/Loading.vue.d.ts.map +1 -1
  7. package/dist/components/Modal.vue.d.ts.map +1 -1
  8. package/dist/components/form/inputs/ColorInput.vue.d.ts.map +1 -1
  9. package/dist/components/form/inputs/DateInput.vue.d.ts +1 -1
  10. package/dist/components/form/inputs/DateInput.vue.d.ts.map +1 -1
  11. package/dist/components/form/inputs/NumberInput.vue.d.ts.map +1 -1
  12. package/dist/components/form/inputs/RichText/index.vue.d.ts.map +1 -1
  13. package/dist/components/form/inputs/Upload/UploadInput.vue.d.ts.map +1 -1
  14. package/dist/components/layout/TabsNav.vue.d.ts.map +1 -1
  15. package/dist/components/lightbox/Lightbox.vue.d.ts.map +1 -1
  16. package/dist/index.cjs +21 -21
  17. package/dist/index.mjs +21 -21
  18. package/dist/style.css +1 -1
  19. package/dist/types/BagelForm.d.ts +1 -0
  20. package/dist/types/BagelForm.d.ts.map +1 -1
  21. package/dist/types/BtnOptions.d.ts +3 -0
  22. package/dist/types/BtnOptions.d.ts.map +1 -1
  23. package/dist/utils/sizeParsing.d.ts +3 -0
  24. package/dist/utils/sizeParsing.d.ts.map +1 -0
  25. package/package.json +1 -1
  26. package/src/components/Alert.vue +12 -9
  27. package/src/components/ListItem.vue +42 -35
  28. package/src/components/Loading.vue +73 -25
  29. package/src/components/Modal.vue +40 -24
  30. package/src/components/form/inputs/ColorInput.vue +5 -5
  31. package/src/components/form/inputs/DateInput.vue +0 -1
  32. package/src/components/form/inputs/NumberInput.vue +2 -2
  33. package/src/components/form/inputs/RichText/index.vue +147 -271
  34. package/src/components/form/inputs/Upload/UploadInput.vue +95 -212
  35. package/src/components/form/inputs/Upload/upload.css +36 -2
  36. package/src/components/layout/AppSidebar.vue +1 -1
  37. package/src/components/layout/TabsNav.vue +24 -22
  38. package/src/components/lightbox/Lightbox.vue +1 -0
  39. package/src/styles/colors.css +502 -3
  40. package/src/styles/inputs.css +12 -4
  41. package/src/styles/layout.css +779 -1
  42. package/src/styles/mobilLayout.css +779 -1
  43. package/src/styles/mobileColors.css +4167 -3739
  44. package/src/types/BagelForm.ts +1 -0
  45. package/src/types/BtnOptions.ts +4 -0
  46. package/src/utils/sizeParsing.ts +26 -0
@@ -66,225 +66,108 @@ function fileName(pathKey: string) {
66
66
  </script>
67
67
 
68
68
  <template>
69
- <div class="bagel-input">
70
- <label v-if="label">{{ label }}</label>
71
- <input v-if="required && !pathKeys.length" placeholder="required" type="text" required class="pixel">
72
- <Card
73
- v-if="theme === 'basic'"
74
- outline
75
- class="flex p-05 gap-1"
76
- @dragover="(e) => handleDrag(e, true)"
77
- @drop="handleDrop"
78
- >
79
- <Btn
80
- v-if="!pathKeys.length && !fileQueue.length"
81
- class="px-1-5"
82
- icon="upload"
83
- outline
84
- :value="btnPlaceholder || 'Upload'"
85
- @click="browse()"
86
- />
87
-
88
- <template v-for="path_key in pathKeys" :key="path_key">
89
- <div class="txt-gray txt-12 flex">
90
- <div class="m-05 flex opacity-7 z-99">
91
- <Btn
92
- v-tooltip="'Delete'"
93
- color="gray"
94
- thin
95
- icon="delete"
96
- @click="removeFile(path_key)"
97
- />
98
- <Btn
99
- v-tooltip="'Replace'"
100
- color="gray"
101
- thin
102
- icon="autorenew"
103
- @click="browse()"
104
- />
105
- <Btn
106
- icon="download"
107
- flat
108
- thin
109
- :href="pathKeyToURL(path_key)"
110
- :download="fileName(path_key)"
111
- />
112
- <div class="flex gap-025 rounded pe-1 ps-05 py-025 bg-gray-80 -my-1 ">
113
- <Icon icon="draft" :size="1.5" />
114
- <p
115
- v-lightbox="{ src: pathKeyToURL(path_key), download: true }"
116
- class="ellipsis-1 word-break-all h-20 m-0 color-black txt16"
117
- >
118
- {{ fileName(path_key) }}
119
- </p>
120
- </div>
121
- </div>
122
- </div>
123
- </template>
124
-
125
- <span
126
- v-if="!pathKeys.length && !fileQueue.length"
127
- class="txt-gray txt-12"
128
- >
129
- {{ noFilePlaceholder || 'No file selected' }}
69
+ <div class="bagel-input">
70
+ <label v-if="label">{{ label }}</label>
71
+ <input v-if="required && !pathKeys.length" placeholder="required" type="text" required class="pixel">
72
+ <Card v-if="theme === 'basic'" outline class="flex p-05 gap-1" @dragover="(e) => handleDrag(e, true)" @drop="handleDrop">
73
+ <Btn v-if="!pathKeys.length && !fileQueue.length" class="px-1-5" icon="upload" outline :value="btnPlaceholder || 'Upload'" @click="browse()" />
74
+ <!-- Loading state during upload -->
75
+ <div v-if="fileQueue.length > 0" class="flex align-items-center gap-1 p-05">
76
+ <Loading size="20" />
77
+ <span class="txt-gray txt-12">
78
+ Uploading {{ fileQueue.length }} file{{ fileQueue.length > 1 ? 's' : '' }}...
130
79
  </span>
131
- </Card>
80
+ </div>
132
81
 
133
- <div
134
- v-else
135
- class="fileUploadWrap"
136
- :class="{
137
- 'fileDropZone': !pathKeys.length && !fileQueue.length,
138
- 'dragover': isDragOver,
139
- 'bgl_oval-upload': oval,
140
- }"
141
- :style="{ width, height }"
142
- @click="browse()"
143
- @dragover="(e) => handleDrag(e, true)"
144
- @drop="handleDrop"
145
- @dragleave="(e) => handleDrag(e)"
146
- >
147
- <slot name="files" :files="pathKeys" :fileQueue>
148
- <div v-if="multiple" class="bgl-multi-preview">
149
- <div
150
- v-for="path_key in pathKeys"
151
- :key="path_key"
152
- v-lightbox="{ src: pathKeyToURL(path_key), download: true }"
153
- class="multi-image-item-preview"
154
- :class="{ 'bgl_fill-image': fill }"
155
- >
156
- <Image
157
- v-if="isImage(path_key)"
158
- :pathKey="path_key"
159
- class="multi-preview"
160
- />
161
- <Icon v-else icon="description" class="multi-preview" />
162
- <p class="m-0">
82
+ <template v-for="path_key in pathKeys" :key="path_key">
83
+ <div class="txt-gray txt-12 flex">
84
+ <div class="m-05 flex opacity-8 z-99 gap-025">
85
+ <Btn v-tooltip="'Delete'" color="gray" thin icon="delete" @click="removeFile(path_key)" />
86
+ <Btn v-tooltip="'Replace'" color="gray" thin icon="autorenew" @click="browse()" />
87
+ <Btn icon="download" color="gray" thin :href="pathKeyToURL(path_key)" :download="fileName(path_key)" />
88
+ <div class="flex gap-025 rounded pe-1 ps-05 py-025 -my-1 ">
89
+ <Icon icon="draft" :size="1.5" />
90
+ <p v-lightbox="{ src: pathKeyToURL(path_key), download: true }" class="ellipsis-1 word-break-all h-20 m-0 color-black txt16">
163
91
  {{ fileName(path_key) }}
164
92
  </p>
165
- <Btn
166
- thin
167
- flat
168
- icon="delete"
169
- color="red"
170
- @click="removeFile(path_key)"
171
- />
172
- </div>
173
- <div
174
- v-for="file in fileQueue"
175
- :key="file.name"
176
- class="multi-image-item-preview"
177
- :class="{ 'bgl_fill-image': fill }"
178
- >
179
- <img
180
- v-if="isImage(file.file.type)"
181
- class="multi-preview"
182
- :src="file.url"
183
- alt=""
184
- >
185
- <Icon v-else icon="description" class="multi-preview" />
186
- <p class="no-margin multi-preview-txt">
187
- {{ file.name }}
188
- </p>
189
- <div
190
- class="pie"
191
- :style="{ '--p': file.progress }"
192
- style="--b: 2px"
193
- :class="{ complete: file.progress === 100 }"
194
- >
195
- <span v-if="file.progress < 100" class="progress">
196
- {{ file.progress.toFixed(0) }}
197
- </span>
198
- <Icon class="success" icon="check_circle" />
199
93
  </div>
200
- </div>
201
- </div>
202
-
203
- <div
204
- v-else-if="pathKeys.length > 0 || fileQueue.length > 0"
205
- class="bgl-single-preview"
206
- >
207
- <div
208
- v-for="path_key in pathKeys"
209
- :key="path_key"
210
- class="single-image-item-preview"
211
- :class="{ 'bgl_fill-image': fill }"
212
- >
213
- <div class="position-start m-05 flex opacity-7 z-99 gap-025">
214
- <Btn
215
- v-tooltip="'Delete'"
216
- color="gray"
217
- thin
218
- icon="delete"
219
- @click="removeFile(path_key)"
220
- />
221
- <Btn
222
- v-tooltip="'Replace'"
223
- color="gray"
224
- thin
225
- icon="autorenew"
226
- @click="browse()"
227
- />
228
- <Btn
229
- v-tooltip="'Download'"
230
- color="gray"
231
- thin
232
- icon="download"
233
- :href="pathKeyToURL(path_key)"
234
- :download="fileName(path_key)"
235
- />
236
94
  </div>
237
- <div v-if="isImage(path_key)" class="h-100">
238
- <Image
239
- v-lightbox="{ src: pathKeyToURL(path_key), download: true }"
240
-
241
- class="single-preview"
242
- :pathKey="path_key"
243
- alt=""
244
- />
245
95
  </div>
246
- <Icon
247
- v-else
248
- v-lightbox="{ src: pathKeyToURL(path_key), download: true }"
249
- :size="4"
250
- weight="2"
251
- icon="description"
252
- class="color-primary w-100"
253
- />
254
- </div>
255
- <div
256
- v-for="file in fileQueue"
257
- :key="file.name"
258
- class="single-image-item-preview"
259
- :class="{ 'bgl_fill-image': fill }"
260
- >
261
- <Loading type="bar" :progress="file.progress" class="absolute bottom-05 end start w-100px mx-auto" />
262
- <img
263
- v-if="isImage(file.file.type)"
264
- class="single-preview opacity-5"
265
- :src="file.url"
266
- alt=""
267
- >
268
- </div>
269
- </div>
270
- </slot>
271
-
272
- <slot
273
- v-if="(!pathKeys.length && !fileQueue.length) || multiple"
274
- name="placeholder"
275
- :files="pathKeys"
276
- :fileQueue
277
- :browse
278
- >
279
- <p class="p-1 flex column hover fileUploadPlaceHolder justify-content-center mb-05 ">
280
- <Icon icon="upload_2" />
281
- <span class=" pretty balance">
282
- {{ dropPlaceholder || 'Drag and Drop files here or click to upload' }}
283
- </span>
284
- </p>
285
- </slot>
286
- </div>
287
- </div>
96
+ </template>
97
+
98
+ <span v-if="!pathKeys.length && !fileQueue.length" class="txt-gray txt-12">
99
+ {{ noFilePlaceholder || 'No file selected' }}
100
+ </span>
101
+ </Card>
102
+
103
+ <div v-else class="fileUploadWrap" :class="{
104
+ 'fileDropZone': !pathKeys.length && !fileQueue.length,
105
+ 'dragover': isDragOver,
106
+ 'bgl_oval-upload': oval,
107
+ }" :style="{ width, height }" @click="browse()" @dragover="(e) => handleDrag(e, true)" @drop="handleDrop" @dragleave="(e) => handleDrag(e)">
108
+ <slot name="files" :files="pathKeys" :fileQueue>
109
+ <div v-if="multiple" class="bgl-multi-preview">
110
+ <!-- Show uploaded files only if showFileList is true (default) -->
111
+ <div v-if="showFileList !== false" v-for="path_key in pathKeys" :key="path_key" v-lightbox="{ src: pathKeyToURL(path_key), download: true }" class="multi-image-item-preview"
112
+ :class="{ 'bgl_fill-image': fill }">
113
+ <Image v-if="isImage(path_key)" :pathKey="path_key" class="multi-preview" />
114
+ <Icon v-else icon="description" class="multi-preview" />
115
+ <p class="m-0">
116
+ {{ fileName(path_key) }}
117
+ </p>
118
+ <Btn thin flat icon="delete" color="red" @click="removeFile(path_key)" />
119
+ </div>
120
+ <!-- File count indicator when showFileList is false and multiple files -->
121
+ <div v-if="showFileList === false && pathKeys.length > 0" class="flex column gap-05 pt-1">
122
+ <p class="color-primary">
123
+ {{ pathKeys.length }} file{{ pathKeys.length > 1 ? 's' : '' }} uploaded
124
+ </p>
125
+ <Btn color="primary" thin icon="autorenew" value="Replace files" @click="browse()" />
126
+ </div>
127
+ <div v-for="file in fileQueue" :key="file.name" class="multi-image-item-preview" :class="{ 'bgl_fill-image': fill }">
128
+ <img v-if="isImage(file.file.type)" class="multi-preview" :src="file.url" alt="">
129
+ <Icon v-else icon="description" class="multi-preview" />
130
+ <p class="no-margin multi-preview-txt">
131
+ {{ file.name }}
132
+ </p>
133
+ <div class="pie" :style="{ '--p': file.progress }" style="--b: 2px" :class="{ complete: file.progress === 100 }">
134
+ <span v-if="file.progress < 100" class="progress">
135
+ {{ file.progress.toFixed(0) }}
136
+ </span>
137
+ <Icon class="success" icon="check_circle" />
138
+ </div>
139
+ </div>
140
+ </div>
141
+
142
+ <div v-else-if="pathKeys.length > 0 || fileQueue.length > 0" class="bgl-single-preview">
143
+ <div v-for="path_key in pathKeys" :key="path_key" class="single-image-item-preview" :class="{ 'bgl_fill-image': fill }">
144
+ <div class="flex opacity-8 z-99 gap-025 absolute top-0 start-0" :class="{ 'mx-auto end-0 mt-1 justify-content-center': oval, 'm-05': !oval }">
145
+ <Btn v-tooltip="'Delete'" color="white" frame thin icon="delete" @click="removeFile(path_key)" />
146
+ <Btn v-tooltip="'Replace'" color="white" frame thin icon="autorenew" @click="browse()" />
147
+ <Btn v-tooltip="'Download'" color="white" frame thin icon="download" :href="pathKeyToURL(path_key)" :download="fileName(path_key)" />
148
+ </div>
149
+ <div v-if="isImage(path_key)" class="h-100">
150
+ <Image v-lightbox="{ src: pathKeyToURL(path_key), download: true }" class="single-preview" :pathKey="path_key" alt="" />
151
+ </div>
152
+ <Icon v-else v-lightbox="{ src: pathKeyToURL(path_key), download: true }" :size="4" weight="2" icon="description" class="color-primary w-100" />
153
+ </div>
154
+ <div v-for="file in fileQueue" :key="file.name" class="single-image-item-preview" :class="{ 'bgl_fill-image': fill }">
155
+ <Loading type="bar" :progress="file.progress" class="absolute bottom-05 end start w-100px mx-auto rounded overflow-hidden" />
156
+ <img v-if="isImage(file.file.type)" class="single-preview opacity-5" :src="file.url" alt="">
157
+ </div>
158
+ </div>
159
+ </slot>
160
+
161
+ <slot v-if="(!pathKeys.length && !fileQueue.length) || multiple" name="placeholder" :files="pathKeys" :fileQueue :browse>
162
+ <p class="p-1 flex column hover fileUploadPlaceHolder justify-content-center mb-05 ">
163
+ <Icon icon="upload_2" class="user-select-none" />
164
+ <span class=" pretty balance user-select-none ">
165
+ {{ dropPlaceholder || 'Drag and Drop files here or click to upload' }}
166
+ </span>
167
+ </p>
168
+ </slot>
169
+ </div>
170
+ </div>
288
171
  </template>
289
172
 
290
173
  <style src="./upload.css" scoped></style>
@@ -106,7 +106,7 @@
106
106
  object-fit: contain;
107
107
  }
108
108
 
109
- .single-image-item-preview:hover::after {
109
+ .single-image-item-preview::after {
110
110
  content: 'zoom_in';
111
111
  font-size: 32px;
112
112
  font-family: 'Material Symbols Outlined', serif;
@@ -115,6 +115,16 @@
115
115
  color: var(--bgl-white);
116
116
  z-index: 9;
117
117
  pointer-events: none;
118
+ opacity: 0;
119
+ transition: all 0.4s ease;
120
+ }
121
+
122
+ .single-image-item-preview:hover::after {
123
+ opacity: 1;
124
+ }
125
+
126
+ .single-image-item-preview img {
127
+ transition: all 0.2s ease;
118
128
  }
119
129
 
120
130
  .single-image-item-preview:hover img {
@@ -125,7 +135,13 @@
125
135
  height: 100%;
126
136
  }
127
137
 
128
- .bgl_fill-image.single-image-item-preview .single-preview {
138
+ .bgl_fill-image.single-image-item-preview img {
139
+ height: 100%;
140
+ width: 100%;
141
+ object-fit: cover;
142
+ }
143
+
144
+ .bgl_fill-image.single-image-item-preview div:has(img) {
129
145
  border-radius: unset;
130
146
  object-fit: cover;
131
147
  box-shadow: unset;
@@ -133,6 +149,15 @@
133
149
  height: auto;
134
150
  }
135
151
 
152
+ .fileUploadWrap:not(.bgl_oval-upload) .bgl_fill-image .single-preview {
153
+ margin: 0rem !important;
154
+ height: 100% !important;
155
+ max-height: 100% !important;
156
+ max-width: 100% !important;
157
+ width: 100% !important;
158
+ object-fit: cover !important;
159
+ }
160
+
136
161
  .single-image-item-preview .pie {
137
162
  transform-origin: top;
138
163
  transform: scale(1.4);
@@ -151,6 +176,8 @@
151
176
  .bgl_oval-upload {
152
177
  border-radius: 100% !important;
153
178
  overflow: hidden;
179
+ aspect-ratio: 1 !important;
180
+ margin-inline: auto !important;
154
181
  }
155
182
 
156
183
  .bgl_oval-upload p {
@@ -177,8 +204,15 @@
177
204
  .bgl_oval-upload .single-preview {
178
205
  margin: 0;
179
206
  height: 100% !important;
207
+ max-width: unset;
208
+ max-height: unset;
180
209
  }
181
210
 
211
+ .bgl_oval-upload .bgl_fill-image .single-preview {
212
+ height: auto !important;
213
+ }
214
+
215
+
182
216
  .pie {
183
217
  width: 30px;
184
218
  height: 30px;
@@ -112,7 +112,7 @@ function logout() {
112
112
  to="/"
113
113
  class="decoration-none flex px-05"
114
114
  :class="{
115
- 'gap-025': menuState.isOpen.value,
115
+ 'gap-05': menuState.isOpen.value,
116
116
  'gap-0': !menuState.isOpen.value,
117
117
  }"
118
118
  >
@@ -35,9 +35,15 @@ function updateIndicator() {
35
35
  if (!tabsWrap.value) return
36
36
  const activeTab = tabs.value.find(tab => tab.classList.contains('active'))
37
37
  if (activeTab) {
38
- const { offsetLeft, offsetWidth } = activeTab
39
- tabsWrap.value.style.setProperty('--indicator-left', `${offsetLeft}px`)
40
- tabsWrap.value.style.setProperty('--indicator-width', `${offsetWidth}px`)
38
+ // Wait a bit more to ensure CSS is fully loaded and elements are properly sized
39
+ setTimeout(() => {
40
+ const { offsetLeft, offsetWidth } = activeTab
41
+ if (offsetLeft >= 0 && offsetWidth > 0) { // Ensure valid measurements
42
+ tabsWrap.value?.style.setProperty('--indicator-left', `${offsetLeft}px`)
43
+ tabsWrap.value?.style.setProperty('--indicator-width', `${offsetWidth}px`)
44
+ tabsWrap.value?.style.setProperty('--indicator-opacity', '1')
45
+ }
46
+ }, 10)
41
47
  }
42
48
  })
43
49
  }
@@ -69,7 +75,12 @@ watch(
69
75
 
70
76
  onMounted(() => {
71
77
  tabs.value = Array.from(tabsWrap.value?.querySelectorAll('.bgl_tab') || [])
72
- updateIndicator()
78
+
79
+ // Wait for the next frame to ensure all CSS and layout calculations are done
80
+ requestAnimationFrame(() => {
81
+ updateIndicator()
82
+ })
83
+
73
84
  window.addEventListener('resize', updateIndicator)
74
85
  })
75
86
 
@@ -86,24 +97,14 @@ onBeforeUnmount(() => {
86
97
  </script>
87
98
 
88
99
  <template>
89
- <div
90
- ref="tabsWrap" class="grid auto-flow-columns relative fit-content bgl_tabs_wrap overflow-hidden"
91
- :class="{ 'bgl_flat-tabs': flat, 'bgl_vertical-tabs': vertical }"
92
- >
93
- <slot name="tabs" v-bind="{ selectTab, isActive, tabLabel, tabs }">
94
- <button
95
- v-for="(tab, i) in props.tabs"
96
- :key="i"
97
- type="button"
98
- :class="{ active: isActive(tab) }"
99
- class="bgl_tab relative z-1"
100
- @click="selectTab(tab)"
101
- >
102
- <Icon v-if="typeof tab !== 'string' && tab.icon" :icon="tab.icon" />
103
- {{ tabLabel(tab) }}
104
- </button>
100
+ <div ref="tabsWrap" class="grid auto-flow-columns relative fit-content bgl_tabs_wrap overflow-hidden" :class="{ 'bgl_flat-tabs': flat, 'bgl_vertical-tabs': vertical }">
101
+ <slot name="tabs" v-bind="{ selectTab, isActive, tabLabel, tabs }">
102
+ <button v-for="(tab, i) in props.tabs" :key="i" type="button" :class="{ active: isActive(tab) }" class="bgl_tab relative z-1" @click="selectTab(tab)">
103
+ <Icon v-if="typeof tab !== 'string' && tab.icon" :icon="tab.icon" />
104
+ {{ tabLabel(tab) }}
105
+ </button>
105
106
  </slot>
106
- </div>
107
+ </div>
107
108
  </template>
108
109
 
109
110
  <style scoped>
@@ -127,7 +128,6 @@ onBeforeUnmount(() => {
127
128
  border-radius: var(--input-border-radius);
128
129
  transition: var(--bgl-transition);
129
130
  color: inherit
130
-
131
131
  }
132
132
 
133
133
  .bgl_tab:hover {
@@ -145,6 +145,8 @@ onBeforeUnmount(() => {
145
145
  border-radius: var(--input-border-radius);
146
146
  transition: var(--bgl-transition);
147
147
  z-index: 0;
148
+ /* Hide indicator initially until position is calculated */
149
+ opacity: var(--indicator-opacity, 0);
148
150
  }
149
151
  .bgl_flat-tabs.bgl_tabs_wrap {
150
152
  background: transparent;
@@ -210,6 +210,7 @@ defineExpose({ open, close })
210
210
  }
211
211
  .lightbox-image{
212
212
  object-fit: contain;
213
+ width: fit-content;
213
214
  }
214
215
 
215
216
  .bgl-lightbox-overlay {