@bagelink/vue 1.15.59 → 1.15.63

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 (54) hide show
  1. package/dist/components/Avatar.vue.d.ts +5 -1
  2. package/dist/components/Avatar.vue.d.ts.map +1 -1
  3. package/dist/components/Badge.vue.d.ts +6 -1
  4. package/dist/components/Badge.vue.d.ts.map +1 -1
  5. package/dist/components/Dropdown.vue.d.ts.map +1 -1
  6. package/dist/components/ListItem.vue.d.ts +12 -0
  7. package/dist/components/ListItem.vue.d.ts.map +1 -1
  8. package/dist/components/Progress.vue.d.ts +38 -0
  9. package/dist/components/Progress.vue.d.ts.map +1 -0
  10. package/dist/components/Swiper.vue.d.ts.map +1 -1
  11. package/dist/components/index.d.ts +1 -0
  12. package/dist/components/index.d.ts.map +1 -1
  13. package/dist/components/layout/AppSidebar.vue.d.ts +1 -0
  14. package/dist/components/layout/AppSidebar.vue.d.ts.map +1 -1
  15. package/dist/components/layout/Divider.vue.d.ts +31 -0
  16. package/dist/components/layout/Divider.vue.d.ts.map +1 -0
  17. package/dist/components/layout/Layout.vue.d.ts.map +1 -1
  18. package/dist/components/layout/SidebarNavItem.vue.d.ts +20 -0
  19. package/dist/components/layout/SidebarNavItem.vue.d.ts.map +1 -0
  20. package/dist/components/layout/index.d.ts +1 -0
  21. package/dist/components/layout/index.d.ts.map +1 -1
  22. package/dist/directives/index.d.ts +2 -0
  23. package/dist/directives/index.d.ts.map +1 -1
  24. package/dist/directives/reveal.d.ts +29 -0
  25. package/dist/directives/reveal.d.ts.map +1 -0
  26. package/dist/index.cjs +37 -37
  27. package/dist/index.mjs +8104 -7796
  28. package/dist/plugins/bagel.d.ts.map +1 -1
  29. package/dist/style.css +1 -1
  30. package/dist/utils/index.d.ts +1 -1
  31. package/dist/utils/index.d.ts.map +1 -1
  32. package/package.json +1 -1
  33. package/src/components/Avatar.vue +20 -4
  34. package/src/components/Badge.vue +32 -2
  35. package/src/components/Dropdown.vue +7 -1
  36. package/src/components/ListItem.vue +151 -76
  37. package/src/components/Progress.vue +80 -0
  38. package/src/components/Swiper.vue +19 -1
  39. package/src/components/index.ts +1 -0
  40. package/src/components/layout/AppSidebar.vue +12 -15
  41. package/src/components/layout/Divider.vue +57 -0
  42. package/src/components/layout/Layout.vue +17 -4
  43. package/src/components/layout/SidebarNavItem.vue +227 -0
  44. package/src/components/layout/index.ts +1 -0
  45. package/src/directives/index.ts +2 -0
  46. package/src/directives/reveal.ts +78 -0
  47. package/src/plugins/bagel.ts +2 -1
  48. package/src/styles/appearance.css +11 -0
  49. package/src/styles/bagel.css +1 -0
  50. package/src/styles/dark.css +107 -2
  51. package/src/styles/layout.css +65 -13
  52. package/src/styles/motion.css +91 -0
  53. package/src/styles/text.css +38 -6
  54. package/src/utils/index.ts +1 -1
@@ -44,7 +44,7 @@ export declare function normalizeDimension(value: string | number | undefined, d
44
44
  export type { NormalizedOption } from './options';
45
45
  export { getOptionIcon, getOptionLabel, getOptionValue, normalizeOption } from './options';
46
46
  export type { ComparisonOperator, FilterCondition, LogicalOperator, QueryConditions, QueryFilter } from './queryFilter';
47
- export { anyOf, parseQuery, queryFilter, range, search } from './queryFilter';
47
+ export { anyOf, buildQuery, evaluateQuery, parseQuery, queryFilter, range, search } from './queryFilter';
48
48
  export type { ShowdownConverter, ShowdownOptions } from './showdown';
49
49
  export declare function pathKeyToURL(pathKey?: string | null): string | undefined;
50
50
  export declare function getNestedValue(obj: any, path?: string, defaultValue?: any): any;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bagelink/vue",
3
3
  "type": "module",
4
- "version": "1.15.59",
4
+ "version": "1.15.63",
5
5
  "description": "Bagel core sdk packages",
6
6
  "author": {
7
7
  "name": "Bagel Studio",
@@ -1,23 +1,39 @@
1
1
  <script setup lang="ts">
2
2
  defineOptions({ name: 'BglAvatar' })
3
- import type { IconType } from '@bagelink/vue'
3
+ import type { IconType, ThemeType } from '@bagelink/vue'
4
4
  import { initials, Icon } from '@bagelink/vue'
5
+ import { computed } from 'vue'
5
6
  import Image from './Image.vue'
6
7
 
7
- withDefaults(defineProps<{
8
+ const props = withDefaults(defineProps<{
8
9
  fallback?: string
9
10
  src?: string
10
11
  name?: string
11
12
  icon?: IconType
12
13
  alt?: string
13
14
  size?: number
15
+ /** Rounded-square instead of a circle. `true` = themed radius, or pass a px radius. */
16
+ square?: boolean | number
17
+ /** Theme color → tinted background + matching icon/text color (e.g. an icon chip). */
18
+ color?: ThemeType
14
19
  }>(), { size: 50 })
20
+
21
+ const radius = computed(() => {
22
+ if (!props.square) { return '1000px' } // circle (default)
23
+ if (props.square === true) { return 'var(--bgl-btn-border-radius)' }
24
+ return `${props.square}px`
25
+ })
26
+
27
+ // When a theme color is given, tint the background and color the icon/initials.
28
+ const themed = computed(() => props.color
29
+ ? { background: `var(--bgl-${props.color}-tint, color-mix(in srgb, var(--bgl-${props.color}) 14%, transparent))`, color: `var(--bgl-${props.color})`, border: 'none' }
30
+ : {})
15
31
  </script>
16
32
 
17
33
  <template>
18
34
  <div
19
- class="round overflow-hidden txt-center p-0 avatar flex justify-content-center"
20
- :style="{ width: `${size}px`, height: `${size}px` }"
35
+ class="overflow-hidden txt-center p-0 avatar flex justify-content-center align-items-center"
36
+ :style="{ width: `${size}px`, height: `${size}px`, borderRadius: radius, ...themed }"
21
37
  >
22
38
  <Image v-if="src" :src="src" :alt="alt || name" />
23
39
  <Icon v-else-if="icon" :icon="icon" :size="size / 40" />
@@ -17,10 +17,15 @@ const props = defineProps<{
17
17
  icon?: IconType
18
18
  iconEnd?: IconType
19
19
  color?: ThemeType
20
- variant?: 'solid' | 'flat' | 'outline'
20
+ variant?: 'solid' | 'flat' | 'outline' | 'glass'
21
21
  /** Boolean variant shorthands: <Badge flat /> — same as variant="flat" */
22
22
  flat?: boolean
23
23
  outline?: boolean
24
+ /** Translucent frosted badge — readable on photos / gradients / dark heroes.
25
+ Shorthand for variant="glass". */
26
+ glass?: boolean
27
+ /** Leading status dot in the theme color (e.g. ● Live, ● Active). */
28
+ dot?: boolean
24
29
  /** @deprecated Use `outline` */
25
30
  border?: boolean
26
31
  loading?: boolean
@@ -50,6 +55,12 @@ const computedPairClass = computed(() => {
50
55
  return `pair-${theme}`
51
56
  })
52
57
 
58
+ // Dot uses the badge's theme color (strip any -light/-tint suffix for a solid dot).
59
+ const dotColor = computed(() => {
60
+ const base = (computedTheme.value || 'primary').replace(/-(light|tint|10|20|30|40|50|60|70)$/, '')
61
+ return `var(--bgl-${base})`
62
+ })
63
+
53
64
  const computedSize = computed(() => {
54
65
  if (props.size) { return props.size }
55
66
  if (props.sm) { return 'sm' }
@@ -59,6 +70,7 @@ const computedSize = computed(() => {
59
70
 
60
71
  const computedVariant = computed(() => {
61
72
  if (props.variant) { return props.variant }
73
+ if (props.glass) { return 'glass' }
62
74
  if (props.flat) { return 'flat' }
63
75
  if (props.outline || props.border) { return 'outline' }
64
76
  return 'solid'
@@ -70,6 +82,7 @@ const computedClasses = computed(() => {
70
82
  'round': props.round,
71
83
  'bgl_flatPill': computedVariant.value === 'flat',
72
84
  'bgl_pill-border': computedVariant.value === 'outline',
85
+ 'bgl_glassPill': computedVariant.value === 'glass',
73
86
  'pillLarge': computedSize.value === 'lg',
74
87
  'pillSmall': computedSize.value === 'sm',
75
88
  }
@@ -90,8 +103,9 @@ const computedClasses = computed(() => {
90
103
  >
91
104
  <div class="flex h-100 justify-content-center relative ">
92
105
  <div v-if="loading" class="loading absolute inset-0 mx-auto" />
93
- <div class="px-025 flex gap-025 justify-content-center" :class="{ 'opacity-0': loading }">
106
+ <div class="px-025 flex gap-025 justify-content-center align-items-center" :class="{ 'opacity-0': loading }">
94
107
  <Btn v-if="btn" class="bgl_pill-btn -ms-025" icon-size="0.8" round v-bind="btn" />
108
+ <span v-if="dot" class="bgl_pill-dot" :style="{ background: dotColor }" />
95
109
  <Icon v-if="icon" class="line-height-0" :icon="icon" style="font-size: var(--bgl-pill-font-size)" />
96
110
  <slot :class="{ uppercase }" />
97
111
  <template v-if="!slots.default">
@@ -119,6 +133,12 @@ const computedClasses = computed(() => {
119
133
  .pillText{
120
134
  font-size: var(--bgl-pill-font-size);
121
135
  }
136
+ .bgl_pill-dot{
137
+ width: 6px;
138
+ height: 6px;
139
+ border-radius: 50%;
140
+ flex-shrink: 0;
141
+ }
122
142
  .bgl_pill-btn{
123
143
  color: var(--bgl-pill-btn-color);
124
144
  background: var(--bgl-pill-btn-bg);
@@ -166,4 +186,14 @@ vertical-align: middle;
166
186
  border-radius: 1000px;
167
187
  }
168
188
 
189
+ /* Glass: frosted translucent badge for photos / gradients / dark heroes.
190
+ Defaults to light-on-dark; flip via --bgl-glass-bg / --bgl-glass-color. */
191
+ .bgl_glassPill {
192
+ background-color: var(--bgl-glass-bg, rgba(255, 255, 255, 0.18)) !important;
193
+ color: var(--bgl-glass-color, #fff) !important;
194
+ border: 1px solid var(--bgl-glass-border, rgba(255, 255, 255, 0.28));
195
+ backdrop-filter: blur(8px);
196
+ -webkit-backdrop-filter: blur(8px);
197
+ }
198
+
169
199
  </style>
@@ -403,7 +403,7 @@ defineExpose({ show, hide, shown })
403
403
  @focus="onPopoverMouseenter" @blur="onPopoverMouseleave" @keydown="onPopoverKeydown"
404
404
  >
405
405
  <div class="bgl-dropdown__backdrop" />
406
- <div class="bgl-dropdown__content overflow-hidden" :class="{ 'display-flex column': props.card }"
406
+ <div class="bgl-dropdown__content overflow-hidden" :class="{ 'display-flex column bgl-dropdown__content--card': props.card }"
407
407
  style="border-radius: var(--bgl-card-border-radius);">
408
408
  <slot :hide :show :shown />
409
409
  </div>
@@ -482,6 +482,12 @@ animation: bgl-dropdown-enter 0.18s ease 0.04s both;
482
482
  transform-origin: top left;
483
483
  }
484
484
 
485
+ /* Default menu breathing room so consumers don't wrap content in py-* just to
486
+ stop items touching the rounded edges. */
487
+ .bgl-dropdown__content--card .bgl_card{
488
+ padding-block: 0.375rem;
489
+ }
490
+
485
491
  </style>
486
492
  <!-- prettier-ignore-end -->
487
493
  <!-- eslint-enable -->
@@ -22,25 +22,36 @@ const props = withDefaults(
22
22
  fullWidth?: boolean
23
23
  ellipsis?: boolean
24
24
  ripple?: boolean
25
+ /** Make the whole row one hover/click target: the clickable button stretches
26
+ to the trailing edge and the #end meta floats over it (still clickable).
27
+ Great for simple rows with light trailing meta. Opt-in — the classic
28
+ layout (only the text area clickable) remains the default so rows with
29
+ wide trailing content aren't affected. Tune reserved room with the CSS
30
+ var --bgl-list-item-end-space. */
31
+ fullRow?: boolean
32
+ /** Render as an interactive row (cursor + hover) without needing a handler.
33
+ Implied when `to`, `href`, or `onClick` is set. */
34
+ clickable?: boolean
25
35
  onClick?: () => void
26
36
  }>(),
27
37
  {
28
38
  ellipsis: true,
29
- ripple: true
39
+ ripple: false,
40
+ fullRow: false,
30
41
  }
31
42
  )
32
43
 
44
+ const hasTo = computed(() => props.to !== undefined && props.to !== '')
45
+ const hasHref = computed(() => props.href !== undefined && props.href !== '')
46
+ const isClickable = computed(() => hasTo.value || hasHref.value || props.onClick !== undefined || props.clickable === true)
47
+
33
48
  const isComponent = computed(() => {
34
- if (props.to !== undefined && props.to !== '') { return 'router-link' }
35
- if (props.href !== undefined && props.href !== '') { return 'a' }
36
- if (props.onClick !== undefined) { return 'button' }
49
+ if (hasTo.value) { return 'router-link' }
50
+ if (hasHref.value) { return 'a' }
51
+ if (isClickable.value) { return 'button' }
37
52
  return 'div'
38
53
  })
39
54
 
40
- const isClickable = computed(() => {
41
- return (props.to !== undefined && props.to !== '') || (props.href !== undefined && props.href !== '') || (props.onClick !== undefined)
42
- })
43
-
44
55
  const bind = computed(() => {
45
56
  const obj: { [key: string]: any } = {}
46
57
  if (props.to !== undefined && props.to !== '') { obj.to = props.to }
@@ -48,7 +59,7 @@ const bind = computed(() => {
48
59
  if (props.target !== undefined && props.target !== undefined && ((props.to !== undefined && props.to !== '') || (props.href !== undefined && props.href !== ''))) { obj.target = props.target }
49
60
 
50
61
  obj.class = {
51
- 'notClickable': !((props.to !== undefined && props.to !== '') || (props.onClick !== undefined)),
62
+ 'notClickable': !isClickable.value,
52
63
  'no-border-list': props.flat,
53
64
  }
54
65
  if (props.disabled) { obj.disabled = true }
@@ -57,126 +68,190 @@ const bind = computed(() => {
57
68
  </script>
58
69
 
59
70
  <template>
60
- <div class="flex space-between">
61
- <!-- Content rendered before the clickable area (e.g. a drag handle). Lives
62
- outside the clickable component so interacting with it never triggers
63
- navigation/selection. -->
64
- <slot name="start" />
71
+ <div
72
+ class="flex space-between list-item-row"
73
+ :class="{ 'no-border-list': props.flat, 'list-item-flush': props.fullWidth, 'list-item-fullrow': fullRow && isClickable }"
74
+ >
75
+ <!-- Content rendered before the clickable area (e.g. a drag handle, avatar
76
+ or leading visual). Lives outside the clickable component so interacting
77
+ with it never triggers navigation/selection. -->
78
+ <div v-if="$slots.start" class="list-item-start flex align-items-center flex-shrink-0">
79
+ <slot name="start" />
80
+ </div>
65
81
  <component
66
82
  :is="isComponent" v-bind="bind" v-ripple="ripple && isClickable"
67
- class="flex flex-grow-1 gap-05 list-item" :class="{
68
- 'py-1': !props.thin,
83
+ class="flex flex-grow-1 gap-075 align-items-center list-item" :class="{
84
+ 'py-075': !props.thin,
69
85
  'py-05': props.thin,
70
86
  'px-1': !props.fullWidth,
71
87
  'px-0': props.fullWidth,
72
- }" @click="onClick"
88
+ }" @click="typeof onClick === 'function' && onClick()"
73
89
  >
74
- <Avatar v-if="src || showAvatar" style="flex-basis: 1;" :name="title" :src="src" :size="40" />
75
- <Icon v-if="icon" size="1.2" class="color-primary" :icon="icon" />
90
+ <!-- Leading visual INSIDE the clickable area. Use #media for custom art
91
+ (covers, thumbnails); `src`/`showAvatar` and `icon` are shortcuts. -->
92
+ <slot name="media">
93
+ <Avatar v-if="src || showAvatar" :name="title" :src="src" :size="thin ? 30 : 38" class="flex-shrink-0" />
94
+ <span v-if="icon" class="list-item-icon flex-shrink-0">
95
+ <Icon size="1.2" :icon="icon" />
96
+ </span>
97
+ </slot>
76
98
 
77
- <div class="txt-start">
78
- <p v-if="lead" class="txt10 m-0 p-0 txt-gray " :class="{ ellipsis }">
99
+ <div class="txt-start flex-grow-1 list-item-body">
100
+ <p v-if="lead" class="list-item-lead" :class="{ ellipsis }">
79
101
  {{ lead }}
80
102
  <slot name="lead" />
81
103
  </p>
82
- <p class="m-0 p-0 line-height-14 pb-025 item-title" :class="{ 'ellipsis-1': ellipsis }">
104
+ <p class="list-item-title" :class="{ 'ellipsis-1': ellipsis }">
83
105
  {{ title }}
84
106
  <slot />
85
107
  </p>
86
- <p
87
- v-if="subtitle" class="txt12 m-0 m-0 py-0 ps-0 pe-1-5 opacity-7 me-2"
88
- :class="{ 'ellipsis-1': ellipsis }"
89
- >
108
+ <p v-if="subtitle || $slots.subtitle" class="list-item-subtitle" :class="{ 'ellipsis-1': ellipsis }">
90
109
  {{ subtitle }}
91
110
  <slot name="subtitle" />
92
111
  </p>
93
112
  </div>
94
- <div class="flex-grow-1" />
95
113
  </component>
96
- <slot name="end">
97
- <Icon v-if="iconEnd" :icon="iconEnd" class="transition-400" />
98
- <p
99
- v-if="end" class="txt12 m-0 py-0 ps-0 pe-1-5 opacity-7 " :class="{ 'ellipsis-1': ellipsis }"
100
- v-text="end"
101
- />
102
- </slot>
114
+ <!-- Trailing meta. With fullRow, it overlaps the clickable button via a
115
+ negative margin so the button spans the whole row underneath it; the
116
+ end content itself stays on top and independently clickable. -->
117
+ <div class="list-item-end flex align-items-center gap-05 flex-shrink-0">
118
+ <slot name="end">
119
+ <span v-if="end" class="list-item-endtext" :class="{ 'ellipsis-1': ellipsis }" v-text="end" />
120
+ <Icon v-if="iconEnd" :icon="iconEnd" class="transition-400 opacity-4" />
121
+ </slot>
122
+ </div>
103
123
  </div>
104
124
  </template>
105
125
 
106
126
  <style>
107
127
 
108
- button.list-item {
109
- cursor: pointer;
110
- display: flex;
128
+ /* The row wraps the clickable area + start/end slots and owns the divider.
129
+ Center start/end slots against the (possibly taller) text block by default —
130
+ the common case for lists with a leading icon/handle and trailing meta. */
131
+ .list-item-row {
132
+ position: relative;
133
+ align-items: center;
111
134
  gap: 0.5rem;
112
- border: none;
113
- background-color: unset;
114
- width: 100%;
115
-
116
135
  }
117
136
 
118
- .list-item:disabled {
119
- opacity: 0.5;
120
- pointer-events: none;
137
+ /* Full-row click target: the clickable button stretches to the row's trailing
138
+ edge so hover/active read across the whole item. The trailing meta is lifted
139
+ out of flow and floated over the button's end — staying visible and
140
+ independently clickable. The button reserves matching room so text never sits
141
+ under the meta. Tune the reserved width with --bgl-list-item-end-space. */
142
+ .list-item-fullrow {
143
+ --bgl-list-item-end-space: 3rem;
121
144
  }
122
-
123
- .list-item {
124
- min-height: -webkit-fit-content;
125
- min-height: -moz-fit-content;
126
- min-height: fit-content;
127
- margin: 0rem 0;
128
- cursor: pointer;
129
- transition: var(--bgl-transition);
130
- color: var(--bgl-text-color);
131
- text-decoration: none;
132
- position: relative;
145
+ .list-item-fullrow .list-item-end {
146
+ position: absolute;
147
+ inset-inline-end: 0.5rem;
148
+ top: 50%;
149
+ transform: translateY(-50%);
150
+ z-index: 1;
151
+ /* non-interactive meta lets clicks fall through to the row button… */
152
+ pointer-events: none;
133
153
  }
134
-
135
- .list-item>* {
136
- margin-bottom: 0;
154
+ /* …interactive trailing controls stay clickable on top of the row button. */
155
+ .list-item-fullrow .list-item-end :where(button, a, input, select, label, [role="button"], [tabindex]) {
156
+ pointer-events: auto;
137
157
  }
138
-
139
- .list-item::after {
158
+ .list-item-fullrow .list-item:not(.px-0) { padding-inline-end: var(--bgl-list-item-end-space); }
159
+ .list-item-fullrow.list-item-flush .list-item-end { inset-inline-end: 0; }
160
+ .list-item-row::after {
140
161
  content: '';
141
162
  position: absolute;
142
- left: 0;
143
- right: 0;
163
+ inset-inline: 0;
144
164
  bottom: 0;
145
165
  border-bottom: 1px solid var(--bgl-border-color);
146
166
  }
147
-
148
- .list-item:last-child::after {
149
- content: '';
150
- position: absolute;
151
- left: 0;
152
- right: 0;
153
- bottom: 0;
167
+ .list-item-row:last-child::after,
168
+ .list-item-row.no-border-list::after {
154
169
  border-bottom: none;
155
170
  }
156
171
 
172
+ button.list-item {
173
+ border: none;
174
+ background-color: unset;
175
+ width: 100%;
176
+ font: inherit;
177
+ text-align: inherit;
178
+ }
179
+
180
+ .list-item {
181
+ min-height: fit-content;
182
+ cursor: pointer;
183
+ transition: background-color 0.15s ease;
184
+ /* Inherit color so the component adapts to ANY surface (light, dark, a
185
+ hard-coded black panel) without per-consumer overrides. On a normal
186
+ Bagelink surface `currentColor` resolves to --bgl-text-color. */
187
+ color: inherit;
188
+ text-decoration: none;
189
+ border-radius: var(--bgl-btn-border-radius);
190
+ }
191
+
192
+ .list-item:disabled {
193
+ opacity: 0.5;
194
+ pointer-events: none;
195
+ }
196
+
197
+ /* Hover/active use Bagelink's translucent gray tint, which already flips from
198
+ translucent-dark (light mode) to translucent-light (.bgl-dark-mode) — so it
199
+ reads correctly on any background. Override per-list with --bgl-list-item-hover. */
157
200
  .list-item:hover,
158
201
  .list-item.router-link-exact-active {
159
- background-color: var(--bgl-primary-tint);
202
+ background-color: var(--bgl-list-item-hover, var(--bgl-gray-tint));
203
+ }
204
+ .list-item.router-link-exact-active {
205
+ background-color: var(--bgl-list-item-active, var(--bgl-primary-tint));
160
206
  }
161
207
 
208
+ .notClickable,
162
209
  .notClickable:hover {
163
210
  background-color: unset;
164
211
  cursor: default;
165
212
  }
166
213
 
167
214
  .list-item:active {
168
- -webkit-filter: var(--bgl-hover-filter);
169
215
  filter: var(--bgl-hover-filter);
170
216
  }
171
217
 
172
- .no-border-list.list-item::after {
173
- border-bottom: none;
218
+ /* Leading icon chip */
219
+ .list-item-icon {
220
+ display: grid;
221
+ place-items: center;
222
+ width: 34px;
223
+ height: 34px;
224
+ border-radius: 9px;
225
+ background: color-mix(in srgb, var(--bgl-primary) 10%, transparent);
226
+ color: var(--bgl-primary);
174
227
  }
175
228
 
176
- @media screen and (max-width: 910px) {
177
- .list-item {
178
- padding: 0.5rem;
229
+ /* Text block: tight, clear hierarchy */
230
+ .list-item-body > p { margin: 0; padding: 0; }
231
+ .list-item-lead {
232
+ font-size: 0.6875rem;
233
+ font-weight: 600;
234
+ text-transform: uppercase;
235
+ letter-spacing: 0.04em;
236
+ opacity: 0.5;
237
+ line-height: 1.3;
238
+ }
239
+ .list-item-title {
240
+ font-size: 0.9375rem;
241
+ font-weight: 500;
242
+ line-height: 1.35;
243
+ }
244
+ .list-item-subtitle {
245
+ font-size: 0.8125rem;
246
+ opacity: 0.6;
247
+ line-height: 1.35;
248
+ margin-top: 1px;
179
249
  }
250
+ .list-item-endtext {
251
+ font-size: 0.8125rem;
252
+ opacity: 0.6;
253
+ white-space: nowrap;
180
254
  }
255
+ .list-item-end:empty { display: none; }
181
256
 
182
257
  </style>
@@ -0,0 +1,80 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * <Progress :value="68" /> // linear bar
4
+ * <Progress :value="68" color="green" label /> // with % label
5
+ * <Progress :value="90" ring :size="86" color="pink">{{ v }}%</Progress> // ring/donut
6
+ *
7
+ * Covers both the dashboard "track + fill" bar and the conic-gradient ring/donut
8
+ * that views previously hand-rolled. Animates fill on value change; the ring
9
+ * center is a free-form slot.
10
+ */
11
+ defineOptions({ name: 'BglProgress' })
12
+ import type { ThemeType } from '@bagelink/vue'
13
+ import { computed } from 'vue'
14
+
15
+ const props = withDefaults(defineProps<{
16
+ /** 0–100. */
17
+ value?: number
18
+ color?: ThemeType
19
+ /** Render as a circular ring/donut instead of a bar. */
20
+ ring?: boolean
21
+ /** Bar thickness (px) or ring diameter (px). */
22
+ size?: number
23
+ /** Ring stroke width (px). Ignored for bars. */
24
+ thickness?: number
25
+ /** Show a trailing % label (bar only, when no default slot). */
26
+ label?: boolean
27
+ }>(), { value: 0, color: 'primary', size: undefined, thickness: 9 })
28
+
29
+ const pct = computed(() => Math.max(0, Math.min(100, props.value)))
30
+ const accent = computed(() => `var(--bgl-${props.color})`)
31
+ const ringSize = computed(() => props.size ?? 86)
32
+ const barHeight = computed(() => props.size ?? 8)
33
+ </script>
34
+
35
+ <template>
36
+ <!-- RING / DONUT -->
37
+ <div
38
+ v-if="ring"
39
+ class="bgl-progress-ring grid place-items-center"
40
+ :style="{
41
+ width: `${ringSize}px`,
42
+ height: `${ringSize}px`,
43
+ '--bgl-progress-pct': `${pct}`,
44
+ background: `conic-gradient(${accent} calc(var(--bgl-progress-pct) * 1%), var(--bgl-progress-track, var(--bgl-border-color)) 0)`,
45
+ }"
46
+ >
47
+ <div
48
+ class="bgl-progress-ring-hole grid place-items-center txt-center"
49
+ :style="{ width: `calc(100% - ${thickness * 2}px)`, height: `calc(100% - ${thickness * 2}px)` }"
50
+ >
51
+ <slot />
52
+ </div>
53
+ </div>
54
+
55
+ <!-- LINEAR BAR -->
56
+ <div v-else class="flex gap-075 align-items-center">
57
+ <div class="bgl-progress-track flex-grow" :style="{ height: `${barHeight}px` }">
58
+ <div class="bgl-progress-fill" :style="{ width: `${pct}%`, background: accent }" />
59
+ </div>
60
+ <span v-if="label && !$slots.default" class="txt12 opacity-6 bgl-progress-label">{{ Math.round(pct) }}%</span>
61
+ <slot />
62
+ </div>
63
+ </template>
64
+
65
+ <style scoped>
66
+ .bgl-progress-ring { border-radius: 50%; }
67
+ .bgl-progress-ring-hole { border-radius: 50%; background: var(--bgl-box-bg); }
68
+
69
+ .bgl-progress-track {
70
+ border-radius: 100px;
71
+ background: var(--bgl-progress-track, var(--bgl-border-color));
72
+ overflow: hidden;
73
+ }
74
+ .bgl-progress-fill {
75
+ height: 100%;
76
+ border-radius: 100px;
77
+ transition: width 0.5s cubic-bezier(0.16, 1, 0.3, 1);
78
+ }
79
+ .bgl-progress-label { font-variant-numeric: tabular-nums; min-width: 2.5em; text-align: end; }
80
+ </style>
@@ -464,6 +464,24 @@ width: 100%;
464
464
  --swiper-pagination-color: white;
465
465
  }
466
466
 
467
+ /* Pagination: keep Swiper's own horizontal centering (left:50% + translateX),
468
+ just give the wrapper a sane bottom offset and consistent bullet sizing so
469
+ consumers don't need :deep() overrides to fix position. Override the bullet
470
+ look with --swiper-pagination-* vars. */
471
+ .swi-wrap .swiper-pagination-bullets {
472
+ bottom: 8px;
473
+ }
474
+ .swi-wrap .swiper-pagination-bullet {
475
+ width: var(--swiper-pagination-bullet-width, 7px);
476
+ height: var(--swiper-pagination-bullet-height, 7px);
477
+ background: var(--swiper-pagination-bullet-inactive-color, #fff);
478
+ opacity: var(--swiper-pagination-bullet-inactive-opacity, 0.6);
479
+ }
480
+ .swi-wrap .swiper-pagination-bullet-active {
481
+ opacity: 1;
482
+ background: var(--swiper-pagination-color, #fff);
483
+ }
484
+
467
485
  .swi-ctrl {
468
486
  position: absolute;
469
487
  top: 50%;
@@ -492,7 +510,7 @@ position: relative;
492
510
 
493
511
  .swi-prev,
494
512
  .swi-next {
495
- background: var(--blue);
513
+ background: var(--bgl-primary);
496
514
  height: 40px;
497
515
  width: 40px;
498
516
  border-radius: 100%;
@@ -37,6 +37,7 @@ export { default as Menu } from './Menu.vue'
37
37
  export { default as NavBar } from './NavBar.vue'
38
38
  export { default as PageTitle } from './PageTitle.vue'
39
39
  export { default as Pagination } from './Pagination.vue'
40
+ export { default as Progress } from './Progress.vue'
40
41
  export { default as Rating } from './Rating.vue'
41
42
  export { default as RouterWrapper } from './RouterWrapper.vue'
42
43
  export { default as Spreadsheet } from './Spreadsheet/Index.vue'