@bagelink/vue 0.0.374 → 0.0.384
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/components/BglVideo.vue.d.ts +6 -6
- package/dist/components/BglVideo.vue.d.ts.map +1 -1
- package/dist/components/Modal.vue.d.ts +2 -0
- package/dist/components/Modal.vue.d.ts.map +1 -1
- package/dist/components/ModalForm.vue.d.ts +6 -0
- package/dist/components/ModalForm.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/FileUpload.vue.d.ts +9 -2
- package/dist/components/form/inputs/FileUpload.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText.vue.d.ts.map +1 -1
- package/dist/index.cjs +460 -90
- package/dist/index.mjs +460 -90
- package/dist/plugins/modal.d.ts +2 -0
- package/dist/plugins/modal.d.ts.map +1 -1
- package/dist/style.css +143 -134
- package/package.json +3 -1
- package/src/components/BglVideo.vue +27 -21
- package/src/components/Modal.vue +67 -46
- package/src/components/ModalForm.vue +39 -18
- package/src/components/form/inputs/FileUpload.vue +83 -91
- package/src/components/form/inputs/FileUploadURL.vue +296 -0
- package/src/components/form/inputs/RichText.vue +50 -10
- package/src/plugins/modal.ts +2 -0
- package/src/styles/modal.css +74 -74
package/src/components/Modal.vue
CHANGED
|
@@ -1,17 +1,27 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
|
-
class="bg-dark"
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
class="bg-dark"
|
|
4
|
+
:class="{ 'is-side': side, 'is-active': isVisible, 'bg-lignt': false }"
|
|
5
|
+
@click="() => (dismissable ? closeModal() : '')"
|
|
6
|
+
@keydown.esc="closeModal">
|
|
7
|
+
<Card class="modal" @click.stop :style="{ ...maxWidth }">
|
|
7
8
|
<header class="tool-bar">
|
|
8
9
|
<slot name="toolbar" />
|
|
9
|
-
<Btn
|
|
10
|
+
<Btn
|
|
11
|
+
:style="{ float: side ? 'left' : 'right' }"
|
|
12
|
+
flat
|
|
13
|
+
icon="close"
|
|
14
|
+
@click="closeModal" />
|
|
10
15
|
<Title class="modal-title" tag="h3" v-if="title" :label="title" />
|
|
11
16
|
</header>
|
|
12
17
|
<slot />
|
|
13
18
|
<footer class="modal-footer mt-3">
|
|
14
|
-
<Btn
|
|
19
|
+
<Btn
|
|
20
|
+
v-for="(action, i) in actions"
|
|
21
|
+
:key="i"
|
|
22
|
+
@click="closeModal"
|
|
23
|
+
color="gray"
|
|
24
|
+
v-bind="action" />
|
|
15
25
|
<slot name="footer" />
|
|
16
26
|
</footer>
|
|
17
27
|
</Card>
|
|
@@ -20,26 +30,36 @@
|
|
|
20
30
|
|
|
21
31
|
<script lang="ts" setup>
|
|
22
32
|
import { onMounted, onUnmounted, watch } from 'vue';
|
|
23
|
-
import {
|
|
24
|
-
type BtnOptions, Btn, useEscape, Title, Card,
|
|
25
|
-
} from '@bagelink/vue';
|
|
33
|
+
import { type BtnOptions, Btn, useEscape, Title, Card } from '@bagelink/vue';
|
|
26
34
|
import '../styles/modal.css';
|
|
27
35
|
|
|
28
36
|
const props = defineProps<{
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
side?: boolean;
|
|
38
|
+
title?: string;
|
|
39
|
+
width?: string;
|
|
40
|
+
dismissable?: boolean;
|
|
41
|
+
actions?: BtnOptions[];
|
|
42
|
+
visible?: boolean;
|
|
34
43
|
}>();
|
|
35
44
|
|
|
36
45
|
let isVisible = $ref<boolean>(false);
|
|
37
46
|
|
|
38
|
-
watch(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
47
|
+
watch(
|
|
48
|
+
() => props.visible,
|
|
49
|
+
(val) => {
|
|
50
|
+
if (val === isVisible || val === undefined) return;
|
|
51
|
+
if (val) openModal();
|
|
52
|
+
else closeModal();
|
|
53
|
+
},
|
|
54
|
+
{ immediate: true }
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const maxWidth = $computed(() => {
|
|
58
|
+
const { width } = props;
|
|
59
|
+
if (width?.match(/px|em|rem|vw|vh|%/)) return { 'max-width': width };
|
|
60
|
+
if (width?.match(/\d+/)) return { 'max-width': `${width}px` };
|
|
61
|
+
return { 'max-width': '720px' };
|
|
62
|
+
});
|
|
43
63
|
|
|
44
64
|
const emit = defineEmits(['update:visible']);
|
|
45
65
|
|
|
@@ -50,10 +70,11 @@ const closeModal = () => {
|
|
|
50
70
|
|
|
51
71
|
defineExpose({ closeModal });
|
|
52
72
|
|
|
53
|
-
const escapeKeyClose = (e: KeyboardEvent) =>
|
|
73
|
+
const escapeKeyClose = (e: KeyboardEvent) =>
|
|
74
|
+
props?.dismissable && useEscape(e, () => closeModal());
|
|
54
75
|
|
|
55
76
|
function openModal() {
|
|
56
|
-
setTimeout(() => isVisible = true, 1);
|
|
77
|
+
setTimeout(() => (isVisible = true), 1);
|
|
57
78
|
}
|
|
58
79
|
|
|
59
80
|
onMounted(() => document.addEventListener('keydown', escapeKeyClose));
|
|
@@ -65,35 +86,35 @@ onUnmounted(() => {
|
|
|
65
86
|
|
|
66
87
|
<style>
|
|
67
88
|
.modal-title {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
89
|
+
text-align: center;
|
|
90
|
+
font-weight: 600;
|
|
91
|
+
font-size: 20px;
|
|
92
|
+
margin-top: 0.5rem;
|
|
93
|
+
margin-bottom: 0 !important;
|
|
94
|
+
width: 100%;
|
|
95
|
+
-webkit-padding-end: 40px;
|
|
96
|
+
padding-inline-end: 40px;
|
|
97
|
+
line-height: 2;
|
|
98
|
+
display: -webkit-box;
|
|
99
|
+
max-width: 100%;
|
|
100
|
+
-webkit-line-clamp: 1;
|
|
101
|
+
-webkit-box-orient: vertical;
|
|
102
|
+
overflow: hidden;
|
|
103
|
+
text-overflow: ellipsis;
|
|
83
104
|
}
|
|
84
105
|
|
|
85
106
|
.modal-footer {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
107
|
+
gap: 1rem;
|
|
108
|
+
display: flex;
|
|
109
|
+
justify-content: space-between;
|
|
110
|
+
align-items: center;
|
|
90
111
|
}
|
|
91
112
|
|
|
92
|
-
.modal-footer>div {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
113
|
+
.modal-footer > div {
|
|
114
|
+
gap: 1rem;
|
|
115
|
+
display: flex;
|
|
116
|
+
justify-content: space-between;
|
|
117
|
+
align-items: center;
|
|
118
|
+
gap: 0;
|
|
98
119
|
}
|
|
99
120
|
</style>
|
|
@@ -1,13 +1,27 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<Modal
|
|
3
|
-
@onUpdate:isModalVisible="props['onUpdate:isModalVisible']"
|
|
4
|
-
:
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
@onUpdate:isModalVisible="props['onUpdate:isModalVisible']"
|
|
4
|
+
:side
|
|
5
|
+
ref="modal"
|
|
6
|
+
:width
|
|
7
|
+
:dismissable
|
|
8
|
+
:title="title">
|
|
9
|
+
<BagelForm
|
|
10
|
+
@submit="runSubmit"
|
|
11
|
+
ref="form"
|
|
12
|
+
v-model="formData"
|
|
13
|
+
:schema="computedFormSchema" />
|
|
7
14
|
<template #footer v-if="onDelete || onSubmit">
|
|
8
15
|
<div>
|
|
9
16
|
<Btn thin flat value="Cancel" @click="closeModal" />
|
|
10
|
-
<Btn
|
|
17
|
+
<Btn
|
|
18
|
+
thin
|
|
19
|
+
icon="delete"
|
|
20
|
+
v-if="onDelete"
|
|
21
|
+
flat
|
|
22
|
+
value="Delete"
|
|
23
|
+
@click="runDelete"
|
|
24
|
+
color="red" />
|
|
11
25
|
</div>
|
|
12
26
|
<Btn value="Submit" @click="runSubmit" />
|
|
13
27
|
</template>
|
|
@@ -16,28 +30,33 @@
|
|
|
16
30
|
|
|
17
31
|
<script lang="ts" setup>
|
|
18
32
|
import {
|
|
19
|
-
Modal,
|
|
33
|
+
Modal,
|
|
34
|
+
Btn,
|
|
35
|
+
BagelForm,
|
|
36
|
+
type BglFormSchemaT,
|
|
37
|
+
type BtnOptions,
|
|
38
|
+
useBagel,
|
|
20
39
|
} from '@bagelink/vue';
|
|
21
40
|
|
|
22
41
|
const bagel = useBagel();
|
|
23
42
|
|
|
24
43
|
const props = defineProps<{
|
|
25
|
-
side?: boolean;
|
|
26
|
-
title?: string;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
44
|
+
'side'?: boolean;
|
|
45
|
+
'title'?: string;
|
|
46
|
+
'width'?: string;
|
|
47
|
+
'dismissable'?: boolean;
|
|
48
|
+
'actions'?: BtnOptions[];
|
|
49
|
+
'schema': BglFormSchemaT | (() => BglFormSchemaT);
|
|
30
50
|
// eslint-disable-next-line no-unused-vars
|
|
31
|
-
onSubmit?: (
|
|
51
|
+
'onSubmit'?: (formData: any) => Promise<void>;
|
|
32
52
|
// eslint-disable-next-line no-unused-vars
|
|
33
|
-
onDelete?: (
|
|
53
|
+
'onDelete'?: (id: string) => void;
|
|
34
54
|
// eslint-disable-next-line no-unused-vars
|
|
35
|
-
'onUpdate:isModalVisible'?: (
|
|
55
|
+
'onUpdate:isModalVisible'?: (visible: boolean) => void;
|
|
36
56
|
// eslint-disable-next-line no-unused-vars
|
|
37
|
-
onError?: (
|
|
38
|
-
|
|
39
|
-
modelValue?: Record<string, any>;
|
|
57
|
+
'onError'?: (err: any) => void;
|
|
40
58
|
|
|
59
|
+
'modelValue'?: Record<string, any>;
|
|
41
60
|
}>();
|
|
42
61
|
|
|
43
62
|
const modal = $ref<InstanceType<typeof Modal>>();
|
|
@@ -47,7 +66,9 @@ const computedFormSchema = $computed(() => {
|
|
|
47
66
|
return props.schema;
|
|
48
67
|
});
|
|
49
68
|
|
|
50
|
-
const formData = defineModel<Record<string, any>>('modelValue', {
|
|
69
|
+
const formData = defineModel<Record<string, any>>('modelValue', {
|
|
70
|
+
default: {},
|
|
71
|
+
});
|
|
51
72
|
const form = $ref<InstanceType<typeof BagelForm>>();
|
|
52
73
|
const closeModal = () => modal?.closeModal();
|
|
53
74
|
|
|
@@ -9,21 +9,13 @@
|
|
|
9
9
|
@drop="drop"
|
|
10
10
|
@dragleave="dragleave"
|
|
11
11
|
class="fileUploadWrap"
|
|
12
|
-
:class="{
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class="imagePreviewWrap"
|
|
20
|
-
v-if="!multiple"
|
|
21
|
-
>
|
|
22
|
-
<img
|
|
23
|
-
class="preview"
|
|
24
|
-
:src="file.url"
|
|
25
|
-
alt=""
|
|
26
|
-
>
|
|
12
|
+
:class="{
|
|
13
|
+
fileDropZone: !storageFiles.length && !fileQueue.length,
|
|
14
|
+
dragover: isDragOver,
|
|
15
|
+
}">
|
|
16
|
+
<template v-for="file in storageFiles" :key="file.id">
|
|
17
|
+
<div class="imagePreviewWrap" v-if="!multiple">
|
|
18
|
+
<img class="preview" :src="file.url" alt="" />
|
|
27
19
|
</div>
|
|
28
20
|
<div class="previewName">
|
|
29
21
|
<img
|
|
@@ -31,8 +23,7 @@
|
|
|
31
23
|
v-if="multiple"
|
|
32
24
|
class="preview"
|
|
33
25
|
:src="file.url"
|
|
34
|
-
alt=""
|
|
35
|
-
>
|
|
26
|
+
alt="" />
|
|
36
27
|
<p class="no-margin">
|
|
37
28
|
{{ file.name }}
|
|
38
29
|
</p>
|
|
@@ -41,23 +32,12 @@
|
|
|
41
32
|
@click.stop="removeFile(file)"
|
|
42
33
|
flat
|
|
43
34
|
icon="delete"
|
|
44
|
-
color="red"
|
|
45
|
-
/>
|
|
35
|
+
color="red" />
|
|
46
36
|
</div>
|
|
47
37
|
</template>
|
|
48
|
-
<template
|
|
49
|
-
v-
|
|
50
|
-
|
|
51
|
-
>
|
|
52
|
-
<div
|
|
53
|
-
class="imagePreviewWrap"
|
|
54
|
-
v-if="!multiple"
|
|
55
|
-
>
|
|
56
|
-
<img
|
|
57
|
-
class="preview"
|
|
58
|
-
:src="fileToUrl(fileQ.file)"
|
|
59
|
-
alt=""
|
|
60
|
-
>
|
|
38
|
+
<template v-for="fileQ in fileQueue" :key="fileQ.file">
|
|
39
|
+
<div class="imagePreviewWrap" v-if="!multiple">
|
|
40
|
+
<img class="preview" :src="fileToUrl(fileQ.file)" alt="" />
|
|
61
41
|
</div>
|
|
62
42
|
<div class="previewName">
|
|
63
43
|
<img
|
|
@@ -65,8 +45,7 @@
|
|
|
65
45
|
v-if="multiple"
|
|
66
46
|
class="preview"
|
|
67
47
|
:src="fileToUrl(fileQ.file)"
|
|
68
|
-
alt=""
|
|
69
|
-
>
|
|
48
|
+
alt="" />
|
|
70
49
|
<p class="no-margin">
|
|
71
50
|
{{ fileQ.name }}
|
|
72
51
|
</p>
|
|
@@ -74,18 +53,11 @@
|
|
|
74
53
|
class="pie"
|
|
75
54
|
:style="`--p:${fileQ.progress}`"
|
|
76
55
|
style="--b: 2px"
|
|
77
|
-
:class="{ complete: fileQ.progress === 100 }"
|
|
78
|
-
|
|
79
|
-
<span
|
|
80
|
-
class="progress"
|
|
81
|
-
v-if="fileQ.progress < 100"
|
|
82
|
-
>
|
|
56
|
+
:class="{ complete: fileQ.progress === 100 }">
|
|
57
|
+
<span class="progress" v-if="fileQ.progress < 100">
|
|
83
58
|
{{ `${fileQ.progress.toFixed(0)}` }}
|
|
84
59
|
</span>
|
|
85
|
-
<MaterialIcon
|
|
86
|
-
class="success"
|
|
87
|
-
icon="check"
|
|
88
|
-
/>
|
|
60
|
+
<MaterialIcon class="success" icon="check" />
|
|
89
61
|
</div>
|
|
90
62
|
</div>
|
|
91
63
|
</template>
|
|
@@ -95,9 +67,7 @@
|
|
|
95
67
|
|
|
96
68
|
<script setup lang="ts">
|
|
97
69
|
import { watch } from 'vue';
|
|
98
|
-
import {
|
|
99
|
-
Btn, type StorageFile, useBagel, MaterialIcon,
|
|
100
|
-
} from '@bagelink/vue';
|
|
70
|
+
import { Btn, type StorageFile, useBagel, MaterialIcon } from '@bagelink/vue';
|
|
101
71
|
|
|
102
72
|
const bagel = useBagel();
|
|
103
73
|
|
|
@@ -109,28 +79,48 @@ type QueueFile = {
|
|
|
109
79
|
uploaded?: boolean;
|
|
110
80
|
};
|
|
111
81
|
|
|
82
|
+
type StrKey = keyof StorageFile;
|
|
83
|
+
|
|
84
|
+
type FSValue = string[] | string | number;
|
|
85
|
+
|
|
112
86
|
const props = defineProps<{
|
|
113
|
-
label: string
|
|
114
|
-
multiple?: boolean
|
|
115
|
-
files?: StorageFile | StorageFile[]
|
|
87
|
+
label: string;
|
|
88
|
+
multiple?: boolean;
|
|
89
|
+
files?: StorageFile | StorageFile[];
|
|
116
90
|
deleteEndpoint?: string;
|
|
91
|
+
bindkey?: StrKey;
|
|
117
92
|
}>();
|
|
118
93
|
|
|
119
|
-
const
|
|
120
|
-
const storageFiles = $ref<StorageFile[]>([]);
|
|
121
|
-
|
|
122
|
-
const compareIds = (v1?: string[] | string, v2?: string[] | string) => [v1].flat().join(',') === [v2].flat().join(',');
|
|
94
|
+
const bindKey: StrKey = props.bindkey || 'id';
|
|
123
95
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}, { immediate: true });
|
|
96
|
+
const file_bindkeys = defineModel<FSValue>('modelValue');
|
|
97
|
+
const storageFiles = $ref<StorageFile[]>([]);
|
|
127
98
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
99
|
+
const compareIds = (v1?: FSValue, v2?: FSValue) =>
|
|
100
|
+
[v1].flat().join(',') === [v2].flat().join(',');
|
|
101
|
+
|
|
102
|
+
watch(
|
|
103
|
+
() => props.files,
|
|
104
|
+
(newFiles) => {
|
|
105
|
+
if (newFiles) storageFiles.push(...[newFiles].flat());
|
|
106
|
+
},
|
|
107
|
+
{ immediate: true }
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
watch(
|
|
111
|
+
() => storageFiles,
|
|
112
|
+
(newFiles) => {
|
|
113
|
+
let idValue: FSValue;
|
|
114
|
+
if (props.multiple) idValue = newFiles.map((f) => f[bindKey]) as FSValue;
|
|
115
|
+
else {
|
|
116
|
+
idValue = (newFiles[0]?.[bindKey] as string) || '';
|
|
117
|
+
}
|
|
118
|
+
if (!compareIds(file_bindkeys?.value, idValue)) {
|
|
119
|
+
file_bindkeys.value = idValue;
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
{ deep: true }
|
|
123
|
+
);
|
|
134
124
|
|
|
135
125
|
const fileQueue = $ref<QueueFile[]>([]);
|
|
136
126
|
let isDragOver = $ref(false);
|
|
@@ -145,20 +135,20 @@ const removeFile = (file: StorageFile) => {
|
|
|
145
135
|
const index = storageFiles.indexOf(file);
|
|
146
136
|
storageFiles.splice(index, 1);
|
|
147
137
|
|
|
148
|
-
if (props.deleteEndpoint)
|
|
138
|
+
if (props.deleteEndpoint) {
|
|
139
|
+
void bagel.delete(`${props.deleteEndpoint}/${file.id}`);
|
|
140
|
+
}
|
|
149
141
|
};
|
|
150
142
|
|
|
151
143
|
const flushQueue = () => {
|
|
152
|
-
fileQueue.forEach(
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
},
|
|
161
|
-
);
|
|
144
|
+
fileQueue.forEach(async (file, i) => {
|
|
145
|
+
if (!props.multiple) storageFiles.splice(0, 1);
|
|
146
|
+
const serverFile = await bagel.uploadFile<StorageFile>(file.file, {
|
|
147
|
+
onUploadProgress: (e: any) => (file.progress = e.progress * 100 - 1),
|
|
148
|
+
});
|
|
149
|
+
storageFiles.push(serverFile);
|
|
150
|
+
fileQueue.splice(i, 1);
|
|
151
|
+
});
|
|
162
152
|
};
|
|
163
153
|
|
|
164
154
|
const browse = () => {
|
|
@@ -168,7 +158,9 @@ const browse = () => {
|
|
|
168
158
|
input.onchange = (e: Event) => {
|
|
169
159
|
const target = e?.target as HTMLInputElement;
|
|
170
160
|
if (target?.files) {
|
|
171
|
-
Array.from(target.files).forEach((file: File) =>
|
|
161
|
+
Array.from(target.files).forEach((file: File) =>
|
|
162
|
+
fileQueue.push({ name: file.name, file, progress: 0 })
|
|
163
|
+
);
|
|
172
164
|
}
|
|
173
165
|
flushQueue();
|
|
174
166
|
};
|
|
@@ -190,13 +182,9 @@ const dragover = (e: DragEvent) => {
|
|
|
190
182
|
const drop = (e: DragEvent) => {
|
|
191
183
|
preventDefault(e);
|
|
192
184
|
if (e.dataTransfer) {
|
|
193
|
-
Array
|
|
194
|
-
.
|
|
195
|
-
|
|
196
|
-
(file: File) => (
|
|
197
|
-
fileQueue.push({ name: file.name, file, progress: 0 })
|
|
198
|
-
),
|
|
199
|
-
);
|
|
185
|
+
Array.from(e.dataTransfer.files).forEach((file: File) =>
|
|
186
|
+
fileQueue.push({ name: file.name, file, progress: 0 })
|
|
187
|
+
);
|
|
200
188
|
}
|
|
201
189
|
isDragOver = false;
|
|
202
190
|
flushQueue();
|
|
@@ -222,7 +210,7 @@ const drop = (e: DragEvent) => {
|
|
|
222
210
|
display: grid;
|
|
223
211
|
grid-template-columns: 1fr 22px;
|
|
224
212
|
align-items: center;
|
|
225
|
-
|
|
213
|
+
padding-inline: 14px;
|
|
226
214
|
}
|
|
227
215
|
|
|
228
216
|
.previewName p {
|
|
@@ -258,7 +246,7 @@ img.preview {
|
|
|
258
246
|
}
|
|
259
247
|
|
|
260
248
|
.bagel-input .fileUploadWrap.fileDropZone:after {
|
|
261
|
-
content:
|
|
249
|
+
content: 'Drop files here or click to upload';
|
|
262
250
|
}
|
|
263
251
|
|
|
264
252
|
.pie {
|
|
@@ -271,18 +259,22 @@ img.preview {
|
|
|
271
259
|
}
|
|
272
260
|
|
|
273
261
|
.pie:before {
|
|
274
|
-
content:
|
|
262
|
+
content: '';
|
|
275
263
|
position: absolute;
|
|
276
264
|
border-radius: 50%;
|
|
277
265
|
inset: 0;
|
|
278
266
|
transition: all 0.2s ease-in-out;
|
|
279
267
|
background: conic-gradient(var(--bgl-primary) calc(var(--p) * 1%), #0000 0);
|
|
280
|
-
-webkit-mask: radial-gradient(
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
268
|
+
-webkit-mask: radial-gradient(
|
|
269
|
+
farthest-side,
|
|
270
|
+
#0000 calc(99% - var(--b)),
|
|
271
|
+
#000 calc(100% - var(--b))
|
|
272
|
+
);
|
|
273
|
+
mask: radial-gradient(
|
|
274
|
+
farthest-side,
|
|
275
|
+
#0000 calc(99% - var(--b)),
|
|
276
|
+
#000 calc(100% - var(--b))
|
|
277
|
+
);
|
|
286
278
|
}
|
|
287
279
|
|
|
288
280
|
.pie .success {
|