@community-release/nx-ui 0.0.49 → 0.0.51

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/dist/module.d.mts CHANGED
@@ -43,6 +43,7 @@ var defaultStyle = {
43
43
  "color-bg": "#fff",
44
44
  "color-bg-text": "#fff",
45
45
  "color-text-on-bg": "var(--color-text)",
46
+ "color-overlay": "var(--color-overlay)",
46
47
  "color-border": "#e8e8e8",
47
48
  "color-border-bolder": "#e0e0e0",
48
49
  // Text
@@ -59,6 +60,7 @@ var defaultStyle = {
59
60
  "font-icons": "FontAwesome",
60
61
  "font-mono": "Consolas, SF Mono",
61
62
  // Font weight
63
+ "font-weight-bold": "700",
62
64
  "font-weight-medium": "600",
63
65
  // Padding
64
66
  "space-extra-large": "100px",
package/dist/module.d.ts CHANGED
@@ -43,6 +43,7 @@ var defaultStyle = {
43
43
  "color-bg": "#fff",
44
44
  "color-bg-text": "#fff",
45
45
  "color-text-on-bg": "var(--color-text)",
46
+ "color-overlay": "var(--color-overlay)",
46
47
  "color-border": "#e8e8e8",
47
48
  "color-border-bolder": "#e0e0e0",
48
49
  // Text
@@ -59,6 +60,7 @@ var defaultStyle = {
59
60
  "font-icons": "FontAwesome",
60
61
  "font-mono": "Consolas, SF Mono",
61
62
  // Font weight
63
+ "font-weight-bold": "700",
62
64
  "font-weight-medium": "600",
63
65
  // Padding
64
66
  "space-extra-large": "100px",
package/dist/module.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "ui",
3
3
  "configKey": "ui",
4
- "version": "0.0.49"
4
+ "version": "0.0.51"
5
5
  }
package/dist/module.mjs CHANGED
@@ -43,6 +43,7 @@ const defaultStyle = {
43
43
  "color-bg": "#fff",
44
44
  "color-bg-text": "#fff",
45
45
  "color-text-on-bg": "var(--color-text)",
46
+ "color-overlay": "var(--color-overlay)",
46
47
  "color-border": "#e8e8e8",
47
48
  "color-border-bolder": "#e0e0e0",
48
49
  // Text
@@ -59,6 +60,7 @@ const defaultStyle = {
59
60
  "font-icons": "FontAwesome",
60
61
  "font-mono": "Consolas, SF Mono",
61
62
  // Font weight
63
+ "font-weight-bold": "700",
62
64
  "font-weight-medium": "600",
63
65
  // Padding
64
66
  "space-extra-large": "100px",
@@ -119,7 +119,6 @@
119
119
  padding: 0 0 0 30px;
120
120
 
121
121
  height: @com-input-height;
122
- line-height: @com-input-height;
123
122
  font-size: @com-text-default;
124
123
  font-weight: 500;
125
124
 
@@ -0,0 +1,431 @@
1
+ <template>
2
+ <div class="component-ui-file-input" :class="classes">
3
+
4
+ <!-- Input -->
5
+ <div class="block-input">
6
+ <ui-button class="btn-add" @click="openFileDialogue" color="surface" shape="square">
7
+ <template #prepend>
8
+ <i class="icon-file ic ic-paperclip" aria-hidden="true"></i>
9
+ </template>
10
+ <template #default>
11
+ {{ dictionary['select-file'] }}
12
+ </template>
13
+ </ui-button>
14
+
15
+ <div class="status">
16
+ <span class="status-text">{{ filesList.length ? '' : dictionary['no-files'] }}</span>
17
+ <ui-button v-if="filesList.length" @click="filesList = []" class="btn-delete" variant="flat">
18
+ <template #default>
19
+ {{ dictionary['delete-all'] }} ({{ filesList.length }})
20
+ </template>
21
+ </ui-button>
22
+ </div>
23
+ </div>
24
+
25
+ <!-- Filelist -->
26
+ <div class="block-filelist" ref="refDropZone">
27
+ <ul v-if="filesList.length" class="list">
28
+ <li v-for="item of filesList" :key="item.id" class="item">
29
+ <div class="preview" :class="{'tag-image': item.image}">
30
+ <div class="file" @click="item.image ? imagePreview = item.image : ''">
31
+ <img v-if="item.image" :src="item.image" alt="" />
32
+ <span v-else>{{ item.type }}</span>
33
+ </div>
34
+ </div>
35
+ <div class="details">
36
+ <div class="details-inner-wrapper">
37
+ <span class="name">{{ item.file.name }}</span>
38
+ <em class="size">{{ item.size }} KB</em>
39
+ </div>
40
+ </div>
41
+ <span class="delete">
42
+ <ui-button @click="deleteFile(item.id)" variant="flat" shape="round-square">
43
+ {{ dictionary['delete'] }}
44
+ </ui-button>
45
+ </span>
46
+ </li>
47
+ </ul>
48
+ <div class="drag-and-drop" @click="openFileDialogue">
49
+ {{ dictionary['drag-and-drop'] }}
50
+ </div>
51
+ </div>
52
+
53
+ <ui-file-input-preview v-model="imagePreview" />
54
+ </div>
55
+ </template>
56
+
57
+ <script setup>
58
+ // Imports
59
+ import { ref, watch, computed } from 'vue';
60
+ import { useFileDialog, useDropZone } from '@vueuse/core';
61
+ import UiFileInputPreview from './preview.vue';
62
+
63
+ // Data
64
+ const emit = defineEmits(['update:modelValue']);
65
+ const props = defineProps({
66
+ modelValue: {
67
+ required: true
68
+ },
69
+ dictionary: {
70
+ type: Object,
71
+ default() {
72
+ return {
73
+ "select-file": "Attach file(s)",
74
+ "no-files": "No files selected",
75
+ "delete": "Delete",
76
+ "delete-all": "Delete all file(s) ({n})",
77
+ "drag-and-drop": "Or drag and drop file to upload."
78
+ };
79
+ }
80
+ }
81
+ });
82
+
83
+ const filesList = ref([]);
84
+
85
+ watch(filesList, e => {
86
+ emit('update:modelValue', unwrapFiles(e));
87
+ }, { deep: true });
88
+
89
+ const imagePreview = ref();
90
+
91
+ const allowedTypes = ['image/jpeg', 'image/gif', 'image/png', 'application/pdf', 'applicaion/pdf'];
92
+
93
+ // Handle button select (file input)
94
+ const { files, open: openFileDialogue, reset, onCancel, onChange: inputOnChange } = useFileDialog({
95
+ //accept: 'image/*', // Set to accept only image files
96
+ accept: allowedTypes, // Set to accept only image files
97
+ multiple: true,
98
+ });
99
+ inputOnChange(e => { filesList.value.push( ...createFileInputFiles(e) ); });
100
+
101
+ // Handle drag and drop zone
102
+ const refDropZone = ref();
103
+ const { isOverDropZone } = useDropZone(refDropZone, {
104
+ onDrop(e) {
105
+ filesList.value.push( ...createFileInputFiles(e) );
106
+ },
107
+ // specify the types of data to be received.
108
+ dataTypes: allowedTypes,
109
+ // control multi-file drop
110
+ multiple: true,
111
+ // whether to prevent default behavior for unhandled events
112
+ preventDefaultForUnhandled: false,
113
+ });
114
+
115
+ const classes = computed(() => {
116
+ const result = [];
117
+
118
+ if (isOverDropZone.value) result.push('tag-drag-over');
119
+ if (!filesList.value.length) result.push('tag-empty');
120
+
121
+ return result;
122
+ });
123
+
124
+ // Methods
125
+ function deleteFile(computedId) {
126
+ for (let i=0; i < filesList.value.length; i++) {
127
+ const item = filesList.value[i];
128
+ if (item.id === computedId) {
129
+ filesList.value.splice(i--, 1);
130
+ }
131
+ }
132
+ }
133
+
134
+ function getType(mime) {
135
+ const ar = mime.split('/');
136
+
137
+ if (ar.length) {
138
+ if (ar[0] === 'image')
139
+ return 'image';
140
+ else
141
+ return ar[1];
142
+ }
143
+
144
+ return 'file';
145
+ }
146
+
147
+ function createFileInputFiles(arFiles) {
148
+ const result = [];
149
+
150
+ for (let file of arFiles) {
151
+ const id = `${file.name}-${file.size}`;
152
+
153
+ // Skip, if file already exists in list
154
+ if (filesList.value.filter(v => v.id === id).length) continue;
155
+
156
+ const o ={
157
+ id,
158
+ file,
159
+ type: getType(file.type),
160
+ size: Math.round(file.size / 1024)
161
+ };
162
+
163
+ if (o.type == 'image')
164
+ o.image = URL.createObjectURL(file);
165
+
166
+ result.push(o);
167
+ }
168
+
169
+ return result;
170
+ }
171
+
172
+ function unwrapFiles(ar) {
173
+ return ar.length ? ar.map(v => v.file) : [];
174
+ }
175
+
176
+ // Hooks
177
+
178
+ </script>
179
+
180
+ <style lang="less">
181
+ .component-ui-file-input {
182
+ @com-color-primary-text: var(--ui-color-primary-text);
183
+ @com-color-surface: var(--ui-color-surface);
184
+ @com-color-border-bolder: var(--ui-color-border-bolder);
185
+ @com-color-border: var(--ui-color-border);
186
+ @com-color-header-text:var(--ui-color-header-text);
187
+
188
+ @com-border-radius-m: var(--ui-border-radius-default);
189
+
190
+ @com-space-default: var(--ui-space-default);
191
+ @com-space-mini: var(--ui-space-mini);
192
+ @com-space-small: var(--ui-space-small);
193
+
194
+ @com-text-large: var(--ui-text-large);
195
+ @com-text-default: var(--ui-text-default);
196
+ @com-text-small: var(--ui-text-small);
197
+
198
+ @com-font-weight-bold: var(--ui-font-weight-bold);
199
+
200
+
201
+ .block-input {
202
+ display: grid;
203
+ grid-template-columns: auto 1fr;
204
+ border-radius: @com-border-radius-m;
205
+ border: 1px solid @com-color-border;
206
+
207
+ .btn-add {
208
+ border-radius: @com-border-radius-m 0 0 @com-border-radius-m;
209
+
210
+ .ic {
211
+ font-size: @com-text-large;
212
+ }
213
+ }
214
+
215
+ .btn-delete {
216
+ border-radius: 0 @com-border-radius-m @com-border-radius-m 0;
217
+
218
+ .ic {
219
+ padding-left: @com-space-mini;
220
+ font-size: @com-text-default;
221
+ }
222
+ }
223
+
224
+
225
+ .status {
226
+ display: flex;
227
+ justify-content: end;
228
+ align-items: center;
229
+ }
230
+
231
+ .status-text {
232
+ padding-right: @com-space-default;
233
+ }
234
+ }
235
+
236
+ .block-filelist {
237
+ position: relative;
238
+ margin-top: @com-space-mini;
239
+ border-radius: @com-border-radius-m;
240
+ border: 1px dashed @com-color-border-bolder;
241
+
242
+ .item {
243
+ display: grid;
244
+ grid-template-columns: 80px 1fr 80px;
245
+
246
+ .preview {
247
+ padding: @com-space-mini;
248
+
249
+ .file {
250
+ overflow: hidden;
251
+ position: relative;
252
+ display: grid;
253
+ place-items: center;
254
+ height: 70px;
255
+
256
+ text-transform: uppercase;
257
+ font-size: @com-text-small;
258
+ font-weight: @com-font-weight-bold;
259
+ border-radius: @com-border-radius-m;
260
+ background-color: @com-color-surface;
261
+ border: 1px solid @com-color-surface;
262
+ }
263
+
264
+ img {
265
+ object-fit: contain;
266
+ }
267
+
268
+ img, span {
269
+ pointer-events: none;
270
+ }
271
+
272
+ &.tag-image {
273
+ cursor: pointer;
274
+ }
275
+ }
276
+
277
+ .details-inner-wrapper {
278
+ width: 100%;
279
+ }
280
+
281
+ .details {
282
+ display: flex;
283
+ justify-content: start;
284
+ align-items: center;
285
+ overflow: hidden;
286
+
287
+ .name {
288
+ .mix-text-overflow;
289
+
290
+ display: block;
291
+ font-weight: @com-font-weight-bold;
292
+ color: @com-color-header-text;
293
+ }
294
+
295
+ .size {
296
+ font-style: italic;
297
+ font-size: @com-text-small;
298
+ }
299
+ }
300
+
301
+ .delete {
302
+ display: flex;
303
+ justify-content: end;
304
+ align-items: center;
305
+
306
+ .component-ui-button {
307
+ font-size: @com-text-small;
308
+ height: 100%;
309
+ }
310
+ }
311
+ }
312
+ }
313
+
314
+ .drag-and-drop {
315
+ position: absolute;
316
+ inset: 0;
317
+
318
+ display: none;
319
+ place-items: center;
320
+ padding: @com-space-small;
321
+ text-align: center;
322
+ cursor: pointer;
323
+ }
324
+
325
+ // Empty
326
+ &.tag-empty {
327
+ .block-filelist {
328
+ min-height: 150px;
329
+ }
330
+
331
+ .drag-and-drop {
332
+ display: grid;
333
+ }
334
+ }
335
+
336
+ // Drag over
337
+ &.tag-drag-over {
338
+ .block-filelist {
339
+ border-color: @com-color-primary-text;
340
+ background: @com-color-surface;
341
+
342
+ .list {
343
+ opacity: 0.1;
344
+ }
345
+ }
346
+
347
+ .drag-and-drop {
348
+ display: grid;
349
+ }
350
+ }
351
+ }
352
+
353
+ @media (max-width: 640px) {
354
+ .component-ui-file-input {
355
+ @com-color-primary-text: var(--ui-color-primary-text);
356
+ @com-color-surface: var(--ui-color-surface);
357
+ @com-color-border-bolder: var(--ui-color-border-bolder);
358
+ @com-color-border: var(--ui-color-border);
359
+ @com-color-header-text:var(--ui-color-header-text);
360
+
361
+ @com-border-radius-m: var(--ui-border-radius-default);
362
+
363
+ @com-space-mini: var(--ui-space-mini);
364
+ @com-space-small: var(--ui-space-small);
365
+
366
+ @com-text-large: var(--ui-text-large);
367
+ @com-text-default: var(--ui-text-default);
368
+ @com-text-small: var(--ui-text-small);
369
+
370
+ @com-font-weight-bold: var(--ui-font-weight-bold);
371
+
372
+ .block-input {
373
+ grid-template-columns: 1fr;
374
+
375
+ .btn-add {
376
+ border-radius: @com-border-radius-m;
377
+ }
378
+
379
+ .status {
380
+ display: none;
381
+ }
382
+ }
383
+ }
384
+ }
385
+
386
+ @media (max-width: 520px) {
387
+ .component-ui-file-input {
388
+ @com-color-primary-text: var(--ui-color-primary-text);
389
+ @com-color-surface: var(--ui-color-surface);
390
+ @com-color-border-bolder: var(--ui-color-border-bolder);
391
+ @com-color-border: var(--ui-color-border);
392
+ @com-color-header-text:var(--ui-color-header-text);
393
+
394
+ @com-border-radius-m: var(--ui-border-radius-default);
395
+
396
+ @com-space-mini: var(--ui-space-mini);
397
+ @com-space-small: var(--ui-space-small);
398
+
399
+ @com-text-large: var(--ui-text-large);
400
+ @com-text-default: var(--ui-text-default);
401
+ @com-text-small: var(--ui-text-small);
402
+
403
+ @com-font-weight-bold: var(--ui-font-weight-bold);
404
+
405
+ .block-input {
406
+ .component-ui-button {
407
+ font-size: @com-text-small;
408
+ }
409
+ }
410
+
411
+ .block-filelist {
412
+ .item {
413
+ display: grid;
414
+ grid-template-columns: 70px 1fr 70px;
415
+
416
+ .preview {
417
+
418
+ }
419
+
420
+ .details {
421
+ font-size: @com-text-small;
422
+ }
423
+ }
424
+ }
425
+
426
+ .drag-and-drop {
427
+ font-size: @com-text-small;
428
+ }
429
+ }
430
+ }
431
+ </style>
@@ -0,0 +1,53 @@
1
+ <template>
2
+ <div class="component-ui-file-input-preview" @click="close" :class="classes">
3
+ <img :src="modelValue" />
4
+ </div>
5
+ </template>
6
+
7
+ <script setup>
8
+ // Imports
9
+ import { computed } from 'vue';
10
+
11
+ // Data
12
+ const emit = defineEmits(['update:modelValue']);
13
+ const props = defineProps({
14
+ modelValue: {
15
+ required: true
16
+ }
17
+ });
18
+
19
+ const classes = computed(() => {
20
+ const result = [];
21
+
22
+ if (props.modelValue) {
23
+ result.push('tag-active');
24
+ }
25
+
26
+ return result;
27
+ });
28
+
29
+ // Methods
30
+ function close() {
31
+ emit('update:modelValue', null);
32
+ }
33
+ </script>
34
+
35
+ <style lang="less">
36
+ .component-ui-file-input-preview {
37
+ // Colors
38
+ @com-color-overlay: var(--ui-color-overlay);
39
+
40
+ z-index: 5000;
41
+
42
+ display: none;
43
+ position: fixed;
44
+ inset: 0;
45
+ place-items: center;
46
+
47
+ background: @com-color-overlay;
48
+
49
+ &.tag-active {
50
+ display: grid;
51
+ }
52
+ }
53
+ </style>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@community-release/nx-ui",
3
- "version": "0.0.49",
3
+ "version": "0.0.51",
4
4
  "packageManager": "pnpm@10.14.0",
5
5
  "description": "nx-ui - Nuxt UI library",
6
6
  "repository": {
@@ -37,6 +37,8 @@
37
37
  "@vue/test-utils": "^2.4.6",
38
38
  "@vuedoc/md": "^4.0.0-beta8",
39
39
  "@vuedoc/parser": "^4.0.0-beta14",
40
+ "@vueuse/core": "^13.6.0",
41
+ "@vueuse/nuxt": "^13.6.0",
40
42
  "changelogen": "^0.5.5",
41
43
  "cross-env": "^7.0.3",
42
44
  "happy-dom": "^14.12.0",