@bagelink/vue 1.15.82 → 1.15.86
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/Alert.vue.d.ts +6 -1
- package/dist/components/Alert.vue.d.ts.map +1 -1
- package/dist/components/Avatar.vue.d.ts +3 -1
- package/dist/components/Avatar.vue.d.ts.map +1 -1
- package/dist/components/Badge.vue.d.ts +4 -0
- package/dist/components/Badge.vue.d.ts.map +1 -1
- package/dist/components/EmptyState.vue.d.ts.map +1 -1
- package/dist/components/Image.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/ArrayInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RangeInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/index.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/TextInput.vue.d.ts.map +1 -1
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/kanban/KanbanBoard.vue.d.ts +42 -0
- package/dist/components/kanban/KanbanBoard.vue.d.ts.map +1 -0
- package/dist/components/kanban/kanbanTypes.d.ts +64 -0
- package/dist/components/kanban/kanbanTypes.d.ts.map +1 -0
- package/dist/composables/useGradientVariant.d.ts.map +1 -1
- package/dist/index.cjs +165 -138
- package/dist/index.mjs +35488 -41334
- package/dist/style.css +1 -2
- package/package.json +1 -1
- package/src/components/Alert.vue +40 -9
- package/src/components/Avatar.vue +8 -5
- package/src/components/Badge.vue +30 -0
- package/src/components/Dropdown.vue +1 -1
- package/src/components/EmptyState.vue +5 -1
- package/src/components/Image.vue +18 -4
- package/src/components/form/inputs/ArrayInput.vue +2 -2
- package/src/components/form/inputs/RangeInput.vue +0 -2
- package/src/components/form/inputs/RichText/components/TableGridSelector.vue +1 -1
- package/src/components/form/inputs/RichText/editor.css +14 -8
- package/src/components/form/inputs/RichText/index.vue +1 -1
- package/src/components/form/inputs/TextInput.vue +6 -2
- package/src/components/form/inputs/Upload/upload.css +7 -1
- package/src/components/index.ts +2 -0
- package/src/components/kanban/KanbanBoard.vue +231 -0
- package/src/components/kanban/kanbanTypes.ts +72 -0
- package/src/composables/useGradientVariant.ts +20 -3
- package/src/styles/appearance.css +108 -0
- package/src/styles/base-colors.css +830 -1
- package/src/styles/buttons.css +44 -2
- package/src/styles/color-variants.css +13 -0
- package/src/styles/colors.css +1115 -1
- package/src/styles/mobileColors.css +1156 -0
- package/src/styles/motion.css +107 -19
- package/src/styles/theme.css +84 -1
- package/vite.config.ts +2 -2
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
<script setup lang="ts" generic="T extends Record<string, any> = Record<string, any>">
|
|
2
|
+
import { computed, reactive, ref } from 'vue'
|
|
3
|
+
import Badge from '../Badge.vue'
|
|
4
|
+
import Btn from '../Btn.vue'
|
|
5
|
+
import EmptyState from '../EmptyState.vue'
|
|
6
|
+
import Loading from '../Loading.vue'
|
|
7
|
+
import type { KanbanBoardProps, KanbanColumn, KanbanMoveEvent } from './kanbanTypes'
|
|
8
|
+
|
|
9
|
+
defineOptions({ name: 'BglKanbanBoard' })
|
|
10
|
+
|
|
11
|
+
const props = withDefaults(defineProps<KanbanBoardProps<T>>(), {
|
|
12
|
+
emptyText: 'Nothing here',
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
const emit = defineEmits<{
|
|
16
|
+
move: [event: KanbanMoveEvent<T>]
|
|
17
|
+
'card-click': [item: T, columnId: string]
|
|
18
|
+
}>()
|
|
19
|
+
|
|
20
|
+
const slots = defineSlots<{
|
|
21
|
+
card?: (p: { item: T; column: KanbanColumn<T> }) => any
|
|
22
|
+
'column-header'?: (p: { column: KanbanColumn<T>; count: number }) => any
|
|
23
|
+
'column-footer'?: (p: { column: KanbanColumn<T> }) => any
|
|
24
|
+
}>()
|
|
25
|
+
|
|
26
|
+
/* ── mode resolution ───────────────────────────────────────────── */
|
|
27
|
+
const serverMode = computed(() => Array.isArray(props.columns))
|
|
28
|
+
|
|
29
|
+
function read<V>(item: T, key: keyof T | ((i: T) => V) | undefined): V | undefined {
|
|
30
|
+
if (key == null) return undefined
|
|
31
|
+
return typeof key === 'function' ? key(item) : (item[key] as unknown as V)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const keyOf = (item: T): string | number => {
|
|
35
|
+
const k = props.itemKey
|
|
36
|
+
const v = k ? read<any>(item, k) : (item as any).id
|
|
37
|
+
return v ?? JSON.stringify(item)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Resolved columns with their items, for both modes. */
|
|
41
|
+
const resolvedColumns = computed<Array<KanbanColumn<T> & { items: T[] }>>(() => {
|
|
42
|
+
if (serverMode.value) {
|
|
43
|
+
return (props.columns ?? []).map(c => ({ ...c, items: c.items ?? [] }))
|
|
44
|
+
}
|
|
45
|
+
// group-by mode
|
|
46
|
+
const defs = props.columnsDef ?? []
|
|
47
|
+
const groupOf = (item: T) => String(read<string>(item, props.groupBy) ?? '')
|
|
48
|
+
const buckets = new Map<string, T[]>()
|
|
49
|
+
for (const c of defs) buckets.set(c.id, [])
|
|
50
|
+
for (const item of props.data ?? []) {
|
|
51
|
+
const g = groupOf(item)
|
|
52
|
+
if (!buckets.has(g)) {
|
|
53
|
+
// when no columnsDef provided, create columns on the fly
|
|
54
|
+
if (!defs.length) buckets.set(g, [])
|
|
55
|
+
else continue
|
|
56
|
+
}
|
|
57
|
+
buckets.get(g)!.push(item)
|
|
58
|
+
}
|
|
59
|
+
if (!defs.length) {
|
|
60
|
+
return [...buckets.entries()].map(([id, items]) => ({ id, title: id, items }))
|
|
61
|
+
}
|
|
62
|
+
return defs.map(c => ({ ...c, items: buckets.get(c.id) ?? [] }))
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
/* ── load more (one handler, per-column page tracking) ─────────── */
|
|
66
|
+
const pageByColumn = reactive<Record<string, number>>({})
|
|
67
|
+
|
|
68
|
+
function canLoadMore(col: KanbanColumn<T> & { items: T[] }) {
|
|
69
|
+
if (!props.loadMore) return false
|
|
70
|
+
if (typeof col.total === 'number') return col.items.length < col.total
|
|
71
|
+
return false
|
|
72
|
+
}
|
|
73
|
+
async function onLoadMore(col: KanbanColumn<T> & { items: T[] }) {
|
|
74
|
+
const next = (pageByColumn[col.id] ?? 1) + 1
|
|
75
|
+
pageByColumn[col.id] = next
|
|
76
|
+
await props.loadMore?.(col.id, next)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* ── drag & drop (HTML5, cross-column, controlled) ─────────────── */
|
|
80
|
+
const dragging = ref<{ item: any; from: string } | null>(null)
|
|
81
|
+
const dragOverCol = ref<string | null>(null)
|
|
82
|
+
|
|
83
|
+
function onDragStart(item: T, from: string) {
|
|
84
|
+
if (!props.draggable) return
|
|
85
|
+
dragging.value = { item, from }
|
|
86
|
+
}
|
|
87
|
+
function onDragEnd() {
|
|
88
|
+
dragging.value = null
|
|
89
|
+
dragOverCol.value = null
|
|
90
|
+
}
|
|
91
|
+
function onDrop(toCol: KanbanColumn<T> & { items: T[] }, index?: number) {
|
|
92
|
+
if (!props.draggable || !dragging.value) return
|
|
93
|
+
const { item, from } = dragging.value
|
|
94
|
+
const newIndex = index ?? toCol.items.length
|
|
95
|
+
emit('move', { item: item as T, fromColumn: from, toColumn: toCol.id, newIndex })
|
|
96
|
+
onDragEnd()
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* ── default card field resolution ─────────────────────────────── */
|
|
100
|
+
function cardTitle(item: T) { return read<string>(item, props.cardSchema?.title) }
|
|
101
|
+
function cardSubtitle(item: T) { return read<string>(item, props.cardSchema?.subtitle) }
|
|
102
|
+
function cardId(item: T) { return read<string>(item, props.cardSchema?.id) }
|
|
103
|
+
function cardBadges(item: T) {
|
|
104
|
+
const out: Array<{ label: string; color?: any }> = []
|
|
105
|
+
for (const b of props.cardSchema?.badges ?? []) {
|
|
106
|
+
const v = read<any>(item, b)
|
|
107
|
+
if (v == null || v === '') continue
|
|
108
|
+
out.push(typeof v === 'object' ? v : { label: String(v) })
|
|
109
|
+
}
|
|
110
|
+
return out
|
|
111
|
+
}
|
|
112
|
+
</script>
|
|
113
|
+
|
|
114
|
+
<template>
|
|
115
|
+
<div class="bgl-kanban">
|
|
116
|
+
<div
|
|
117
|
+
v-for="col in resolvedColumns" :key="col.id"
|
|
118
|
+
class="bgl-kanban-col"
|
|
119
|
+
:class="{ 'is-dragover': dragOverCol === col.id }"
|
|
120
|
+
@dragover.prevent="draggable && (dragOverCol = col.id)"
|
|
121
|
+
@dragleave="dragOverCol === col.id && (dragOverCol = null)"
|
|
122
|
+
@drop="onDrop(col)"
|
|
123
|
+
>
|
|
124
|
+
<!-- header -->
|
|
125
|
+
<div class="bgl-kanban-head">
|
|
126
|
+
<slot name="column-header" :column="col" :count="col.items.length">
|
|
127
|
+
<Badge v-if="col.color" dot :color="col.color" :value="col.title" flat sm />
|
|
128
|
+
<span v-else class="bgl-kanban-title">
|
|
129
|
+
<Badge v-if="col.icon" :icon="col.icon" flat sm :value="col.title" />
|
|
130
|
+
<template v-else>{{ col.title }}</template>
|
|
131
|
+
</span>
|
|
132
|
+
<Badge soft color="gray" sm :value="String(typeof col.total === 'number' ? col.total : col.items.length)" class="ms-auto" />
|
|
133
|
+
</slot>
|
|
134
|
+
</div>
|
|
135
|
+
|
|
136
|
+
<!-- cards -->
|
|
137
|
+
<div class="bgl-kanban-list">
|
|
138
|
+
<div
|
|
139
|
+
v-for="(item, i) in col.items" :key="keyOf(item)"
|
|
140
|
+
class="bgl-kanban-card-wrap"
|
|
141
|
+
:draggable="draggable || undefined"
|
|
142
|
+
@dragstart="onDragStart(item, col.id)"
|
|
143
|
+
@dragend="onDragEnd"
|
|
144
|
+
@drop.stop="onDrop(col, i)"
|
|
145
|
+
@click="emit('card-click', item, col.id)"
|
|
146
|
+
>
|
|
147
|
+
<slot name="card" :item="item" :column="col">
|
|
148
|
+
<!-- default schema card -->
|
|
149
|
+
<div class="bgl-kanban-card">
|
|
150
|
+
<div v-if="cardTitle(item)" class="bgl-kanban-card-title">{{ cardTitle(item) }}</div>
|
|
151
|
+
<div v-if="cardSubtitle(item)" class="bgl-kanban-card-sub">{{ cardSubtitle(item) }}</div>
|
|
152
|
+
<div v-if="cardBadges(item).length" class="bgl-kanban-card-badges">
|
|
153
|
+
<Badge v-for="(b, bi) in cardBadges(item)" :key="bi" sm soft :color="b.color || 'gray'" :value="b.label" />
|
|
154
|
+
</div>
|
|
155
|
+
<div v-if="cardId(item)" class="bgl-kanban-card-foot">{{ cardId(item) }}</div>
|
|
156
|
+
</div>
|
|
157
|
+
</slot>
|
|
158
|
+
</div>
|
|
159
|
+
|
|
160
|
+
<EmptyState v-if="!col.items.length && !col.loading" compact icon="inbox" :title="emptyText" class="bgl-kanban-empty" />
|
|
161
|
+
<Loading v-if="col.loading" class="bgl-kanban-loading" />
|
|
162
|
+
</div>
|
|
163
|
+
|
|
164
|
+
<!-- footer / load more -->
|
|
165
|
+
<div v-if="canLoadMore(col) || slots['column-footer']" class="bgl-kanban-foot">
|
|
166
|
+
<slot name="column-footer" :column="col">
|
|
167
|
+
<Btn
|
|
168
|
+
v-if="canLoadMore(col)" flat thin sm full-width icon="expand_more"
|
|
169
|
+
:value="`Load more`" :disabled="col.loading" @click="onLoadMore(col)"
|
|
170
|
+
/>
|
|
171
|
+
</slot>
|
|
172
|
+
</div>
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
175
|
+
</template>
|
|
176
|
+
|
|
177
|
+
<style scoped>
|
|
178
|
+
.bgl-kanban {
|
|
179
|
+
display: flex;
|
|
180
|
+
align-items: stretch;
|
|
181
|
+
gap: 1rem;
|
|
182
|
+
overflow-x: auto;
|
|
183
|
+
min-height: 0;
|
|
184
|
+
min-width: 0;
|
|
185
|
+
}
|
|
186
|
+
.bgl-kanban-col {
|
|
187
|
+
display: flex;
|
|
188
|
+
flex-direction: column;
|
|
189
|
+
gap: .6rem;
|
|
190
|
+
width: 280px;
|
|
191
|
+
min-width: 280px;
|
|
192
|
+
flex-shrink: 0;
|
|
193
|
+
border-radius: var(--bgl-radius, 12px);
|
|
194
|
+
transition: background .12s;
|
|
195
|
+
}
|
|
196
|
+
.bgl-kanban-col.is-dragover {
|
|
197
|
+
background: color-mix(in srgb, var(--bgl-primary) 8%, transparent);
|
|
198
|
+
outline: 1px dashed color-mix(in srgb, var(--bgl-primary) 40%, transparent);
|
|
199
|
+
outline-offset: 2px;
|
|
200
|
+
}
|
|
201
|
+
.bgl-kanban-head {
|
|
202
|
+
display: flex;
|
|
203
|
+
align-items: center;
|
|
204
|
+
gap: .5rem;
|
|
205
|
+
padding: 0 .25rem;
|
|
206
|
+
}
|
|
207
|
+
.bgl-kanban-title { font-size: 13px; font-weight: 600; }
|
|
208
|
+
/* flex:1 → list fills the column so empty columns stay full-height drop targets */
|
|
209
|
+
.bgl-kanban-list { display: flex; flex-direction: column; gap: .6rem; flex: 1; min-height: 8px; }
|
|
210
|
+
.bgl-kanban-card-wrap { cursor: pointer; }
|
|
211
|
+
.bgl-kanban-card-wrap[draggable='true'] { cursor: grab; }
|
|
212
|
+
.bgl-kanban-card-wrap[draggable='true']:active { cursor: grabbing; }
|
|
213
|
+
.bgl-kanban-card {
|
|
214
|
+
display: flex;
|
|
215
|
+
flex-direction: column;
|
|
216
|
+
gap: .5rem;
|
|
217
|
+
padding: .75rem .85rem;
|
|
218
|
+
background: var(--bgl-box-bg);
|
|
219
|
+
border: 1px solid var(--bgl-border-color);
|
|
220
|
+
border-radius: var(--bgl-radius, 12px);
|
|
221
|
+
transition: border-color .12s, box-shadow .12s;
|
|
222
|
+
}
|
|
223
|
+
.bgl-kanban-card:hover { border-color: color-mix(in srgb, var(--bgl-primary) 50%, var(--bgl-border-color)); }
|
|
224
|
+
.bgl-kanban-card-title { font-size: 13px; font-weight: 600; line-height: 1.3; }
|
|
225
|
+
.bgl-kanban-card-sub { font-size: 12px; opacity: .7; }
|
|
226
|
+
.bgl-kanban-card-badges { display: flex; gap: .25rem; flex-wrap: wrap; }
|
|
227
|
+
.bgl-kanban-card-foot { font-size: 11px; font-family: ui-monospace, monospace; opacity: .5; }
|
|
228
|
+
.bgl-kanban-empty { padding: .75rem 0; opacity: .5; }
|
|
229
|
+
.bgl-kanban-loading { padding: 1rem; display: flex; justify-content: center; }
|
|
230
|
+
.bgl-kanban-foot { padding-top: .1rem; }
|
|
231
|
+
</style>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { IconType, ThemeType } from '../../types'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A single board column. In **controlled / server mode** the caller supplies the
|
|
5
|
+
* full array of columns (each owning its own `items` + `total`). In **group-by
|
|
6
|
+
* mode** columns are derived from flat `data` and only `columnsDef` (id/title/…)
|
|
7
|
+
* is needed for ordering & labels.
|
|
8
|
+
*/
|
|
9
|
+
export interface KanbanColumn<T = any> {
|
|
10
|
+
id: string
|
|
11
|
+
title: string
|
|
12
|
+
items?: T[]
|
|
13
|
+
/** Total available for this column (server mode). When set, "Load more" shows while items.length < total. */
|
|
14
|
+
total?: number
|
|
15
|
+
/** This column is currently fetching (server mode) — disables the load-more button + shows a spinner. */
|
|
16
|
+
loading?: boolean
|
|
17
|
+
color?: ThemeType
|
|
18
|
+
icon?: IconType
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Lean card field map — a board card has a fixed shape, unlike a table row. */
|
|
22
|
+
export interface KanbanCardSchema<T = any> {
|
|
23
|
+
/** Field used as the card title (bold, first line). */
|
|
24
|
+
title?: keyof T | ((item: T) => string)
|
|
25
|
+
/** Optional secondary line. */
|
|
26
|
+
subtitle?: keyof T | ((item: T) => string)
|
|
27
|
+
/** Small monospace identifier shown in the footer (e.g. an id). */
|
|
28
|
+
id?: keyof T | ((item: T) => string)
|
|
29
|
+
/** Fields rendered as badges in the card body. */
|
|
30
|
+
badges?: Array<keyof T | ((item: T) => { label: string; color?: ThemeType } | string | undefined)>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface KanbanMoveEvent<T = any> {
|
|
34
|
+
item: T
|
|
35
|
+
fromColumn: string
|
|
36
|
+
toColumn: string
|
|
37
|
+
/** Insertion index within the destination column. */
|
|
38
|
+
newIndex: number
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface KanbanBoardProps<T = any> {
|
|
42
|
+
/* ── group-by mode ── */
|
|
43
|
+
/** Flat data; provide with `groupBy` to derive columns client-side. */
|
|
44
|
+
data?: T[]
|
|
45
|
+
/** Field on each item that maps to a column id. */
|
|
46
|
+
groupBy?: keyof T | ((item: T) => string)
|
|
47
|
+
/** Column order + labels (group-by mode). Items not matching any def are dropped. */
|
|
48
|
+
columnsDef?: KanbanColumn<T>[]
|
|
49
|
+
|
|
50
|
+
/* ── controlled / server mode ── */
|
|
51
|
+
/** Supplying `columns` switches the board to controlled (server) mode. */
|
|
52
|
+
columns?: KanbanColumn<T>[]
|
|
53
|
+
|
|
54
|
+
/** Stable key for each item (defaults to `item.id`). */
|
|
55
|
+
itemKey?: keyof T | ((item: T) => string | number)
|
|
56
|
+
|
|
57
|
+
/** Default card rendering. Ignored when the `#card` slot is used. */
|
|
58
|
+
cardSchema?: KanbanCardSchema<T>
|
|
59
|
+
|
|
60
|
+
/** Enable drag & drop between/within columns. The board stays controlled — handle `@move`. */
|
|
61
|
+
draggable?: boolean
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Single load-more handler for every column. The board tracks the next page
|
|
65
|
+
* per column and calls this with the column id + page. The caller fetches and
|
|
66
|
+
* appends to that column's `items` (and updates `total`).
|
|
67
|
+
*/
|
|
68
|
+
loadMore?: (columnId: string, page: number) => void | Promise<void>
|
|
69
|
+
|
|
70
|
+
/** Label for empty columns. */
|
|
71
|
+
emptyText?: string
|
|
72
|
+
}
|
|
@@ -40,6 +40,23 @@ function parseTones(value: GradientProp | undefined): string[] {
|
|
|
40
40
|
return value.trim().split(/\s+/).filter(Boolean)
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Resolve a single stop token to a CSS color value. Accepts, in order:
|
|
45
|
+
* - a `var(...)` expression → used as-is
|
|
46
|
+
* - a raw custom property `--bgl-x` → wrapped in `var(--bgl-x)`
|
|
47
|
+
* - an explicit color (#hex, rgb(), hsl(), color-mix(), named like "white")
|
|
48
|
+
* → used as-is
|
|
49
|
+
* - a theme tone like "blue" / "primary-30" → wrapped in `var(--bgl-blue)`
|
|
50
|
+
*/
|
|
51
|
+
function resolveStop(token: string): string {
|
|
52
|
+
const t = token.trim()
|
|
53
|
+
if (t.startsWith('var(') || t.startsWith('#') || /^(rgb|hsl|color-mix|linear-gradient)\(/.test(t)) {
|
|
54
|
+
return t
|
|
55
|
+
}
|
|
56
|
+
if (t.startsWith('--')) { return `var(${t})` }
|
|
57
|
+
return `var(--bgl-${t})`
|
|
58
|
+
}
|
|
59
|
+
|
|
43
60
|
interface UseGradientVariantArgs {
|
|
44
61
|
/** The `gradient` prop value. */
|
|
45
62
|
gradient: MaybeRefOrGetter<GradientProp | undefined>
|
|
@@ -86,12 +103,12 @@ export function useGradientVariant({ gradient, gradientDir, color }: UseGradient
|
|
|
86
103
|
// 0–1 stops → let the CSS auto-derive a darker second stop. Inject nothing.
|
|
87
104
|
if (s.length < 2) { return style }
|
|
88
105
|
|
|
89
|
-
style['--bgl-grad-from'] =
|
|
90
|
-
style['--bgl-grad-to'] =
|
|
106
|
+
style['--bgl-grad-from'] = resolveStop(s[0])
|
|
107
|
+
style['--bgl-grad-to'] = resolveStop(s[s.length - 1])
|
|
91
108
|
// Middle stops become the `via` slot (comma-terminated, like gradients.css).
|
|
92
109
|
const middle = s.slice(1, -1)
|
|
93
110
|
if (middle.length) {
|
|
94
|
-
style['--bgl-grad-via'] = `${middle.map(
|
|
111
|
+
style['--bgl-grad-via'] = `${middle.map(resolveStop).join(', ')}, `
|
|
95
112
|
}
|
|
96
113
|
return style
|
|
97
114
|
})
|
|
@@ -826,4 +826,112 @@
|
|
|
826
826
|
|
|
827
827
|
.bg-gradient-to-bl {
|
|
828
828
|
background-image: linear-gradient(to bottom left, var(--bgl-gradient-from, transparent), var(--bgl-gradient-to, transparent)) !important;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
/* Numeric blur scale (filter) — .blur-10 … .blur-130 */
|
|
832
|
+
.blur-10 {
|
|
833
|
+
filter: blur(10px) !important;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
.blur-20 {
|
|
837
|
+
filter: blur(20px) !important;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
.blur-30 {
|
|
841
|
+
filter: blur(30px) !important;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
.blur-40 {
|
|
845
|
+
filter: blur(40px) !important;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
.blur-50 {
|
|
849
|
+
filter: blur(50px) !important;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
.blur-60 {
|
|
853
|
+
filter: blur(60px) !important;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
.blur-70 {
|
|
857
|
+
filter: blur(70px) !important;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
.blur-80 {
|
|
861
|
+
filter: blur(80px) !important;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
.blur-90 {
|
|
865
|
+
filter: blur(90px) !important;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
.blur-100 {
|
|
869
|
+
filter: blur(100px) !important;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
.blur-110 {
|
|
873
|
+
filter: blur(110px) !important;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
.blur-120 {
|
|
877
|
+
filter: blur(120px) !important;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
.blur-130 {
|
|
881
|
+
filter: blur(130px) !important;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
/* Numeric blur scale — mobile (≤910px) */
|
|
885
|
+
@media screen and (max-width: 910px) {
|
|
886
|
+
.m_blur-10 {
|
|
887
|
+
filter: blur(10px) !important;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
.m_blur-20 {
|
|
891
|
+
filter: blur(20px) !important;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
.m_blur-30 {
|
|
895
|
+
filter: blur(30px) !important;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
.m_blur-40 {
|
|
899
|
+
filter: blur(40px) !important;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
.m_blur-50 {
|
|
903
|
+
filter: blur(50px) !important;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
.m_blur-60 {
|
|
907
|
+
filter: blur(60px) !important;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
.m_blur-70 {
|
|
911
|
+
filter: blur(70px) !important;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
.m_blur-80 {
|
|
915
|
+
filter: blur(80px) !important;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
.m_blur-90 {
|
|
919
|
+
filter: blur(90px) !important;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
.m_blur-100 {
|
|
923
|
+
filter: blur(100px) !important;
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
.m_blur-110 {
|
|
927
|
+
filter: blur(110px) !important;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
.m_blur-120 {
|
|
931
|
+
filter: blur(120px) !important;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
.m_blur-130 {
|
|
935
|
+
filter: blur(130px) !important;
|
|
936
|
+
}
|
|
829
937
|
}
|