@yunlefun/vue 0.1.1 → 0.1.3
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/README.md +26 -37
- package/components/YlfAccordion.vue +165 -0
- package/components/YlfAvatar.vue +70 -0
- package/components/YlfBadge.vue +142 -0
- package/components/YlfBottomMenu.vue +23 -6
- package/components/YlfBottomMenuItem.vue +41 -21
- package/components/YlfButton.vue +290 -7
- package/components/YlfCard.vue +74 -3
- package/components/YlfCheckbox.vue +84 -0
- package/components/YlfDialog.vue +174 -0
- package/components/YlfDropdownMenu.vue +98 -0
- package/components/YlfLogo.vue +83 -7
- package/components/YlfPopover.vue +64 -0
- package/components/YlfProgress.vue +65 -0
- package/components/YlfRadioGroup.vue +120 -0
- package/components/YlfSelect.vue +195 -0
- package/components/YlfSeparator.vue +68 -0
- package/components/YlfSlider.vue +89 -0
- package/components/YlfSwitch.vue +111 -0
- package/components/YlfTabs.vue +117 -0
- package/components/YlfTooltip.vue +67 -0
- package/components/accordion/demo.vue +11 -0
- package/components/accordion/index.md +19 -0
- package/components/avatar/demo.vue +9 -0
- package/components/avatar/index.md +15 -0
- package/components/badge/demo.vue +84 -0
- package/components/badge/index.md +41 -0
- package/components/bottom-menu/demo.vue +19 -10
- package/components/bottom-menu/index.md +25 -0
- package/components/button/demo.vue +101 -3
- package/components/button/index.md +41 -0
- package/components/card/demo.vue +76 -3
- package/components/card/index.md +19 -0
- package/components/checkbox/demo.vue +28 -0
- package/components/checkbox/index.md +14 -0
- package/components/common/demo.vue +7 -1
- package/components/common/index.md +10 -0
- package/components/dialog/demo.vue +33 -0
- package/components/dialog/index.md +30 -0
- package/components/dropdown-menu/demo.vue +27 -0
- package/components/dropdown-menu/index.md +27 -0
- package/components/popover/demo.vue +18 -0
- package/components/popover/index.md +21 -0
- package/components/progress/demo.vue +24 -0
- package/components/progress/index.md +17 -0
- package/components/radio/demo.vue +20 -0
- package/components/radio/index.md +23 -0
- package/components/select/demo.vue +20 -0
- package/components/select/index.md +41 -0
- package/components/separator/demo.vue +52 -0
- package/components/separator/index.md +19 -0
- package/components/slider/demo.vue +23 -0
- package/components/slider/index.md +16 -0
- package/components/switch/demo.vue +33 -0
- package/components/switch/index.md +18 -0
- package/components/tabs/demo.vue +30 -0
- package/components/tabs/index.md +18 -0
- package/components/theme.ts +5 -0
- package/components/tooltip/demo.vue +19 -0
- package/components/tooltip/index.md +21 -0
- package/dist/index.cjs +2 -1
- package/dist/index.d.cts +7 -1
- package/dist/index.d.mts +7 -1
- package/dist/index.d.ts +7 -1
- package/package.json +32 -3
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { SliderRange, SliderRoot, SliderThumb, SliderTrack } from 'reka-ui'
|
|
3
|
+
|
|
4
|
+
withDefaults(defineProps<{
|
|
5
|
+
min?: number
|
|
6
|
+
max?: number
|
|
7
|
+
step?: number
|
|
8
|
+
disabled?: boolean
|
|
9
|
+
}>(), {
|
|
10
|
+
min: 0,
|
|
11
|
+
max: 100,
|
|
12
|
+
step: 1,
|
|
13
|
+
disabled: false,
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
const model = defineModel<number[]>({ default: () => [50] })
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<SliderRoot
|
|
21
|
+
v-model="model"
|
|
22
|
+
:min="min"
|
|
23
|
+
:max="max"
|
|
24
|
+
:step="step"
|
|
25
|
+
:disabled="disabled"
|
|
26
|
+
class="ylf-slider"
|
|
27
|
+
>
|
|
28
|
+
<SliderTrack class="ylf-slider__track">
|
|
29
|
+
<SliderRange class="ylf-slider__range" />
|
|
30
|
+
</SliderTrack>
|
|
31
|
+
<SliderThumb v-for="(_, i) in model" :key="i" class="ylf-slider__thumb" />
|
|
32
|
+
</SliderRoot>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<style lang="scss">
|
|
36
|
+
.ylf-slider {
|
|
37
|
+
position: relative;
|
|
38
|
+
display: flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
width: 100%;
|
|
41
|
+
height: 20px;
|
|
42
|
+
touch-action: none;
|
|
43
|
+
user-select: none;
|
|
44
|
+
|
|
45
|
+
&[data-disabled] {
|
|
46
|
+
opacity: 0.5;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
&__track {
|
|
50
|
+
position: relative;
|
|
51
|
+
flex-grow: 1;
|
|
52
|
+
height: 6px;
|
|
53
|
+
border-radius: 999px;
|
|
54
|
+
background: var(--ylf-c-bg-mute, #e2e8f0);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
&__range {
|
|
58
|
+
position: absolute;
|
|
59
|
+
height: 100%;
|
|
60
|
+
border-radius: 999px;
|
|
61
|
+
background: var(--ylf-c-brand, #2563eb);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
&__thumb {
|
|
65
|
+
display: block;
|
|
66
|
+
width: 18px;
|
|
67
|
+
height: 18px;
|
|
68
|
+
border-radius: 50%;
|
|
69
|
+
background: #fff;
|
|
70
|
+
border: 2px solid var(--ylf-c-brand, #2563eb);
|
|
71
|
+
box-shadow: var(--ylf-shadow-sm, 0 2px 8px -2px rgba(15, 23, 42, 0.12));
|
|
72
|
+
cursor: grab;
|
|
73
|
+
transition: box-shadow 0.2s ease;
|
|
74
|
+
|
|
75
|
+
&:hover {
|
|
76
|
+
box-shadow: 0 0 0 6px var(--ylf-c-brand-soft, #eff6ff);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
&:focus-visible {
|
|
80
|
+
outline: none;
|
|
81
|
+
box-shadow: 0 0 0 4px var(--ylf-c-brand-soft, #eff6ff);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
&:active {
|
|
85
|
+
cursor: grabbing;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
</style>
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import type { YlfAccentTone } from './theme'
|
|
3
|
+
// 行为 / 可访问性由 reka-ui 提供(role=switch、键盘、焦点、data-state);
|
|
4
|
+
// 外观全部走 --ylf token,所以视觉识别仍是「晴空蓝为主、高饱和纯色点缀」。
|
|
5
|
+
import { SwitchRoot, SwitchThumb } from 'reka-ui'
|
|
6
|
+
|
|
7
|
+
withDefaults(defineProps<{
|
|
8
|
+
/** on 态轨道:brand 主色(默认)或 accent 纯色;aurora 是 accent 的旧别名 */
|
|
9
|
+
variant?: 'brand' | 'accent' | 'aurora'
|
|
10
|
+
tone?: YlfAccentTone
|
|
11
|
+
size?: 'sm' | 'md'
|
|
12
|
+
disabled?: boolean
|
|
13
|
+
}>(), {
|
|
14
|
+
variant: 'brand',
|
|
15
|
+
tone: 'blue',
|
|
16
|
+
size: 'md',
|
|
17
|
+
disabled: false,
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const checked = defineModel<boolean>({ default: false })
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<template>
|
|
24
|
+
<SwitchRoot
|
|
25
|
+
v-model="checked"
|
|
26
|
+
:disabled="disabled"
|
|
27
|
+
class="ylf-switch"
|
|
28
|
+
:data-ylf-tone="tone"
|
|
29
|
+
:class="[`ylf-switch--${variant}`, `ylf-switch--${size}`]"
|
|
30
|
+
>
|
|
31
|
+
<SwitchThumb class="ylf-switch__thumb" />
|
|
32
|
+
</SwitchRoot>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<style lang="scss">
|
|
36
|
+
.ylf-switch {
|
|
37
|
+
--_w: 52px;
|
|
38
|
+
--_h: 30px;
|
|
39
|
+
--_pad: 3px;
|
|
40
|
+
|
|
41
|
+
position: relative;
|
|
42
|
+
flex: none;
|
|
43
|
+
width: var(--_w);
|
|
44
|
+
height: var(--_h);
|
|
45
|
+
padding: 0;
|
|
46
|
+
border: none;
|
|
47
|
+
border-radius: var(--ylf-radius-pill, 999px);
|
|
48
|
+
background: var(--ylf-c-bg-mute, #e2e8f0);
|
|
49
|
+
cursor: pointer;
|
|
50
|
+
-webkit-tap-highlight-color: transparent;
|
|
51
|
+
transition:
|
|
52
|
+
background var(--ylf-duration-normal, 240ms) var(--ylf-ease-standard, ease),
|
|
53
|
+
box-shadow var(--ylf-duration-fast, 160ms) var(--ylf-ease-standard, ease);
|
|
54
|
+
|
|
55
|
+
&--sm {
|
|
56
|
+
--_w: 40px;
|
|
57
|
+
--_h: 24px;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
&:focus-visible {
|
|
61
|
+
outline: none;
|
|
62
|
+
box-shadow:
|
|
63
|
+
0 0 0 3px var(--ylf-c-brand-soft, #eff6ff),
|
|
64
|
+
0 0 0 5px var(--ylf-c-brand, #2563eb);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
&[data-disabled] {
|
|
68
|
+
opacity: 0.5;
|
|
69
|
+
cursor: not-allowed;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// on 态:晴空蓝主色
|
|
73
|
+
&[data-state='checked'] {
|
|
74
|
+
background: var(--ylf-c-brand, #2563eb);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// 选中的强调轨道,前景与填充色成组。
|
|
78
|
+
&--accent[data-state='checked'],
|
|
79
|
+
&--aurora[data-state='checked'] {
|
|
80
|
+
background: var(--ylf-accent, var(--ylf-c-brand, #2563eb));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
&__thumb {
|
|
84
|
+
display: block;
|
|
85
|
+
width: calc(var(--_h) - var(--_pad) * 2);
|
|
86
|
+
height: calc(var(--_h) - var(--_pad) * 2);
|
|
87
|
+
border-radius: 50%;
|
|
88
|
+
background: #fff;
|
|
89
|
+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
|
|
90
|
+
transform: translateX(var(--_pad));
|
|
91
|
+
transition: transform var(--ylf-duration-normal, 240ms) var(--ylf-ease-bounce, cubic-bezier(0.34, 1.56, 0.64, 1));
|
|
92
|
+
will-change: transform;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
&[data-state='checked'] &__thumb {
|
|
96
|
+
background: var(--ylf-c-text-on-accent, #fff);
|
|
97
|
+
transform: translateX(calc(var(--_w) - var(--_h) + var(--_pad)));
|
|
98
|
+
}
|
|
99
|
+
&--accent[data-state='checked'] &__thumb,
|
|
100
|
+
&--aurora[data-state='checked'] &__thumb {
|
|
101
|
+
background: var(--ylf-accent-on, var(--ylf-c-text-on-accent, #fff));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@media (prefers-reduced-motion: reduce) {
|
|
106
|
+
.ylf-switch,
|
|
107
|
+
.ylf-switch__thumb {
|
|
108
|
+
transition: none;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
</style>
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { TabsContent, TabsIndicator, TabsList, TabsRoot, TabsTrigger } from 'reka-ui'
|
|
3
|
+
|
|
4
|
+
interface TabItem {
|
|
5
|
+
label: string
|
|
6
|
+
value: string
|
|
7
|
+
disabled?: boolean
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
withDefaults(defineProps<{
|
|
11
|
+
items: TabItem[]
|
|
12
|
+
orientation?: 'horizontal' | 'vertical'
|
|
13
|
+
}>(), {
|
|
14
|
+
orientation: 'horizontal',
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const model = defineModel<string>()
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<TabsRoot
|
|
22
|
+
v-model="model"
|
|
23
|
+
:orientation="orientation"
|
|
24
|
+
class="ylf-tabs"
|
|
25
|
+
:class="`ylf-tabs--${orientation}`"
|
|
26
|
+
>
|
|
27
|
+
<TabsList class="ylf-tabs__list">
|
|
28
|
+
<TabsIndicator class="ylf-tabs__indicator" />
|
|
29
|
+
<TabsTrigger
|
|
30
|
+
v-for="t in items"
|
|
31
|
+
:key="t.value"
|
|
32
|
+
:value="t.value"
|
|
33
|
+
:disabled="t.disabled"
|
|
34
|
+
class="ylf-tabs__trigger"
|
|
35
|
+
>
|
|
36
|
+
{{ t.label }}
|
|
37
|
+
</TabsTrigger>
|
|
38
|
+
</TabsList>
|
|
39
|
+
<TabsContent
|
|
40
|
+
v-for="t in items"
|
|
41
|
+
:key="t.value"
|
|
42
|
+
:value="t.value"
|
|
43
|
+
class="ylf-tabs__content"
|
|
44
|
+
>
|
|
45
|
+
<slot :name="t.value" />
|
|
46
|
+
</TabsContent>
|
|
47
|
+
</TabsRoot>
|
|
48
|
+
</template>
|
|
49
|
+
|
|
50
|
+
<style lang="scss">
|
|
51
|
+
.ylf-tabs__list {
|
|
52
|
+
position: relative;
|
|
53
|
+
display: flex;
|
|
54
|
+
gap: 4px;
|
|
55
|
+
border-bottom: 1px solid var(--ylf-c-border, #e2e8f0);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.ylf-tabs__trigger {
|
|
59
|
+
position: relative;
|
|
60
|
+
padding: 10px 16px;
|
|
61
|
+
font-family: inherit;
|
|
62
|
+
font-size: 15px;
|
|
63
|
+
font-weight: 500;
|
|
64
|
+
color: var(--ylf-c-text-2, #475569);
|
|
65
|
+
background: transparent;
|
|
66
|
+
border: none;
|
|
67
|
+
cursor: pointer;
|
|
68
|
+
transition: color 0.2s ease;
|
|
69
|
+
|
|
70
|
+
&:hover:not([data-disabled]) {
|
|
71
|
+
color: var(--ylf-c-text, #0f172a);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
&[data-state='active'] {
|
|
75
|
+
color: var(--ylf-c-brand, #2563eb);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
&[data-disabled] {
|
|
79
|
+
opacity: 0.45;
|
|
80
|
+
cursor: not-allowed;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
&:focus-visible {
|
|
84
|
+
outline: none;
|
|
85
|
+
border-radius: var(--ylf-radius-sm, 10px);
|
|
86
|
+
box-shadow: 0 0 0 3px var(--ylf-c-brand-soft, #eff6ff);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.ylf-tabs__indicator {
|
|
91
|
+
position: absolute;
|
|
92
|
+
bottom: -1px;
|
|
93
|
+
left: 0;
|
|
94
|
+
width: var(--reka-tabs-indicator-size);
|
|
95
|
+
height: 2.5px;
|
|
96
|
+
border-radius: 999px;
|
|
97
|
+
background: var(--ylf-c-brand, #2563eb);
|
|
98
|
+
transform: translateX(var(--reka-tabs-indicator-position));
|
|
99
|
+
transition:
|
|
100
|
+
transform 0.25s var(--ylf-ease-bounce, cubic-bezier(0.34, 1.56, 0.64, 1)),
|
|
101
|
+
width 0.25s ease;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.ylf-tabs__content {
|
|
105
|
+
padding-top: 16px;
|
|
106
|
+
|
|
107
|
+
&:focus-visible {
|
|
108
|
+
outline: none;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
@media (prefers-reduced-motion: reduce) {
|
|
113
|
+
.ylf-tabs__indicator {
|
|
114
|
+
transition: none;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
</style>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
// 行为 / 定位 / a11y 由 reka-ui 提供;皮肤走 token。
|
|
3
|
+
import { TooltipArrow, TooltipContent, TooltipPortal, TooltipProvider, TooltipRoot, TooltipTrigger } from 'reka-ui'
|
|
4
|
+
|
|
5
|
+
withDefaults(defineProps<{
|
|
6
|
+
content?: string
|
|
7
|
+
side?: 'top' | 'right' | 'bottom' | 'left'
|
|
8
|
+
delay?: number
|
|
9
|
+
}>(), {
|
|
10
|
+
side: 'top',
|
|
11
|
+
delay: 300,
|
|
12
|
+
})
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<TooltipProvider :delay-duration="delay">
|
|
17
|
+
<TooltipRoot>
|
|
18
|
+
<TooltipTrigger as-child>
|
|
19
|
+
<slot />
|
|
20
|
+
</TooltipTrigger>
|
|
21
|
+
<TooltipPortal>
|
|
22
|
+
<TooltipContent :side="side" :side-offset="6" class="ylf-tooltip">
|
|
23
|
+
<slot name="content">
|
|
24
|
+
{{ content }}
|
|
25
|
+
</slot>
|
|
26
|
+
<TooltipArrow class="ylf-tooltip__arrow" :width="10" :height="5" />
|
|
27
|
+
</TooltipContent>
|
|
28
|
+
</TooltipPortal>
|
|
29
|
+
</TooltipRoot>
|
|
30
|
+
</TooltipProvider>
|
|
31
|
+
</template>
|
|
32
|
+
|
|
33
|
+
<style lang="scss">
|
|
34
|
+
.ylf-tooltip {
|
|
35
|
+
z-index: 110;
|
|
36
|
+
max-width: 240px;
|
|
37
|
+
padding: 7px 11px;
|
|
38
|
+
font-size: 13px;
|
|
39
|
+
line-height: 1.5;
|
|
40
|
+
color: var(--ylf-c-bg, #fbfcff);
|
|
41
|
+
background: var(--ylf-c-text, #0f172a);
|
|
42
|
+
border-radius: var(--ylf-radius-sm, 10px);
|
|
43
|
+
box-shadow: var(--ylf-shadow, 0 10px 28px -8px rgba(15, 23, 42, 0.16));
|
|
44
|
+
transform-origin: var(--reka-tooltip-content-transform-origin);
|
|
45
|
+
|
|
46
|
+
&[data-state='delayed-open'] {
|
|
47
|
+
animation: ylf-pop-in 0.16s ease;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
&__arrow {
|
|
51
|
+
fill: var(--ylf-c-text, #0f172a);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@keyframes ylf-pop-in {
|
|
56
|
+
from {
|
|
57
|
+
opacity: 0;
|
|
58
|
+
transform: scale(0.94);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@media (prefers-reduced-motion: reduce) {
|
|
63
|
+
.ylf-tooltip[data-state='delayed-open'] {
|
|
64
|
+
animation: none;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
</style>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const items = [
|
|
3
|
+
{ value: 'a', title: '什么是 YunLeFun Design?', content: '云乐坊设计系统,统一设计规范、品牌视觉与 UI 实现;默认晴空蓝为主,高饱和纯色点缀。' },
|
|
4
|
+
{ value: 'b', title: '为什么基于 reka-ui?', content: 'reka 管行为与可访问性,我们只管皮肤——省心,且无障碍达标。' },
|
|
5
|
+
{ value: 'c', title: '支持暗色吗?', content: '晴空白与深蓝夜空两套中性色,token 驱动,零配置随主题切换。' },
|
|
6
|
+
]
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<template>
|
|
10
|
+
<YlfAccordion :items="items" />
|
|
11
|
+
</template>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Accordion
|
|
3
|
+
title_zh: 手风琴
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
手风琴:展开/收起、键盘导航、单开/多开基于 [reka-ui](https://reka-ui.com),高度过渡与外观走 token。
|
|
7
|
+
|
|
8
|
+
## Props
|
|
9
|
+
|
|
10
|
+
| 属性 | 说明 | 类型 | 默认值 |
|
|
11
|
+
| ------------- | -------------------------------------------- | --------------------- | -------- |
|
|
12
|
+
| `v-model` | 展开项 | `string \| string[]` | — |
|
|
13
|
+
| `items` | 列表 `{ value, title, content?, disabled? }` | `AccordionItemData[]` | — |
|
|
14
|
+
| `type` | 单开 / 多开 | `single \| multiple` | `single` |
|
|
15
|
+
| `collapsible` | 单开模式允许全部收起 | `boolean` | `true` |
|
|
16
|
+
|
|
17
|
+
## Slots
|
|
18
|
+
|
|
19
|
+
每项内容可用 `value` 同名插槽覆盖 `content`。
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="flex flex-wrap items-center gap-4">
|
|
3
|
+
<YlfAvatar src="https://avatars.githubusercontent.com/u/24221472" alt="YunYouJun" size="lg" />
|
|
4
|
+
<YlfAvatar src="https://avatars.githubusercontent.com/u/24221472" alt="YunYouJun" />
|
|
5
|
+
<YlfAvatar src="https://avatars.githubusercontent.com/u/24221472" alt="YunYouJun" size="sm" />
|
|
6
|
+
<YlfAvatar fallback="云" />
|
|
7
|
+
<YlfAvatar fallback="YLF" size="lg" />
|
|
8
|
+
</div>
|
|
9
|
+
</template>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Avatar
|
|
3
|
+
title_zh: 头像
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
头像:图片加载状态管理与回退基于 [reka-ui](https://reka-ui.com),加载失败时优雅回退到首字。
|
|
7
|
+
|
|
8
|
+
## Props
|
|
9
|
+
|
|
10
|
+
| 属性 | 说明 | 类型 | 默认值 |
|
|
11
|
+
| ---------- | ---------------------- | ---------------- | ------ |
|
|
12
|
+
| `src` | 图片地址 | `string` | — |
|
|
13
|
+
| `alt` | 替代文字 | `string` | — |
|
|
14
|
+
| `fallback` | 回退文字(如姓名首字) | `string` | — |
|
|
15
|
+
| `size` | 尺寸 | `sm \| md \| lg` | `md` |
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const tones = [
|
|
3
|
+
{ value: 'blue', label: '晴空蓝' },
|
|
4
|
+
{ value: 'sun', label: '精选集' },
|
|
5
|
+
{ value: 'cyan', label: '工具' },
|
|
6
|
+
{ value: 'coral', label: '活动' },
|
|
7
|
+
{ value: 'pink', label: '创作' },
|
|
8
|
+
{ value: 'green', label: '已完成' },
|
|
9
|
+
] as const
|
|
10
|
+
const appearances = [
|
|
11
|
+
{ value: 'solid', label: '实色' },
|
|
12
|
+
{ value: 'soft', label: '柔色' },
|
|
13
|
+
{ value: 'outline', label: '描边' },
|
|
14
|
+
] as const
|
|
15
|
+
const statuses = [
|
|
16
|
+
{ value: 'success', label: '已发布' },
|
|
17
|
+
{ value: 'warning', label: '测试中' },
|
|
18
|
+
{ value: 'danger', label: '发布失败' },
|
|
19
|
+
{ value: 'info', label: '待审核' },
|
|
20
|
+
] as const
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<template>
|
|
24
|
+
<div class="ylf-badge-demo">
|
|
25
|
+
<div class="ylf-badge-demo__group">
|
|
26
|
+
<p>品牌与内容</p>
|
|
27
|
+
<div class="ylf-badge-demo__row">
|
|
28
|
+
<YlfBadge>新上线</YlfBadge>
|
|
29
|
+
<YlfBadge variant="featured">
|
|
30
|
+
精选
|
|
31
|
+
</YlfBadge>
|
|
32
|
+
<YlfBadge variant="neutral">
|
|
33
|
+
已归档
|
|
34
|
+
</YlfBadge>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
<div class="ylf-badge-demo__group">
|
|
38
|
+
<p>分类与强调</p>
|
|
39
|
+
<div v-for="appearance in appearances" :key="appearance.value" class="ylf-badge-demo__row">
|
|
40
|
+
<span class="ylf-badge-demo__label">{{ appearance.label }}</span>
|
|
41
|
+
<YlfBadge v-for="tone in tones" :key="tone.value" variant="accent" :tone="tone.value" :appearance="appearance.value">
|
|
42
|
+
{{ tone.label }}
|
|
43
|
+
</YlfBadge>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
<div class="ylf-badge-demo__group">
|
|
47
|
+
<p>状态与反馈</p>
|
|
48
|
+
<div v-for="appearance in appearances" :key="appearance.value" class="ylf-badge-demo__row">
|
|
49
|
+
<span class="ylf-badge-demo__label">{{ appearance.label }}</span>
|
|
50
|
+
<YlfBadge v-for="status in statuses" :key="status.value" :variant="status.value" :appearance="appearance.value">
|
|
51
|
+
{{ status.label }}
|
|
52
|
+
</YlfBadge>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</template>
|
|
57
|
+
|
|
58
|
+
<style scoped>
|
|
59
|
+
.ylf-badge-demo {
|
|
60
|
+
display: grid;
|
|
61
|
+
gap: var(--ylf-space-6);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.ylf-badge-demo__group > p {
|
|
65
|
+
margin: 0 0 var(--ylf-space-3);
|
|
66
|
+
color: var(--ylf-c-text-2);
|
|
67
|
+
font-size: 12px;
|
|
68
|
+
line-height: 1.5;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.ylf-badge-demo__row {
|
|
72
|
+
display: flex;
|
|
73
|
+
align-items: center;
|
|
74
|
+
flex-wrap: wrap;
|
|
75
|
+
gap: var(--ylf-space-3);
|
|
76
|
+
margin-top: var(--ylf-space-3);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.ylf-badge-demo__label {
|
|
80
|
+
width: 100%;
|
|
81
|
+
color: var(--ylf-c-text-2);
|
|
82
|
+
font-size: 12px;
|
|
83
|
+
}
|
|
84
|
+
</style>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Badge
|
|
3
|
+
title_zh: 徽标
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
默认以轻浅晴空蓝标记内容,明黄星芒点缀精选;分类和状态使用同一套高饱和实色,搭配经过对比度校验的前景文字。
|
|
7
|
+
|
|
8
|
+
## 选择徽标
|
|
9
|
+
|
|
10
|
+
- `brand`:新内容、版本等日常品牌标记。
|
|
11
|
+
- `featured`:精选、推荐等品牌标记,明黄星芒、浅黄底和中性文字。
|
|
12
|
+
- `accent`:高饱和实色,默认晴空蓝,使用 `tone` 选择明黄、青、珊瑚橙、桃粉或鲜绿。
|
|
13
|
+
- `neutral`:已归档、草稿等普通信息,无需暗示成功或错误。
|
|
14
|
+
- `success` / `warning` / `danger` / `info`:分别使用鲜绿、明黄、珊瑚橙与青色实底,配套状态图形和文字。
|
|
15
|
+
|
|
16
|
+
徽标使用系统正文字体,默认 12px、500 字重,无阴影、发光或持续动画。前景、底色和描边使用配套 token,随明暗主题调整。使用简短明确的文字描述状态,颜色辅助识别。
|
|
17
|
+
|
|
18
|
+
晴空蓝实底在浅色主题使用白字、深色主题使用深蓝字;其余纯色标签使用同色相深色文字,保证各组填充与前景的对比度。状态与强调色共享 token,详见[色彩与组件](/guide/colors#状态也来自同一套色板)。
|
|
19
|
+
|
|
20
|
+
徽标用于展示信息;需要点击筛选或执行操作时,使用按钮等交互组件。
|
|
21
|
+
|
|
22
|
+
## 强调程度
|
|
23
|
+
|
|
24
|
+
同一个色彩角色可以选择 `appearance="solid"`(实色重点)、`soft`(柔色分类)或 `outline`(描边次级)。该属性只作用于 `accent` 与状态变体,其余变体沿用自身外观。
|
|
25
|
+
|
|
26
|
+
## Props
|
|
27
|
+
|
|
28
|
+
| 属性 | 说明 | 类型 | 默认值 |
|
|
29
|
+
| ------------ | ----------------------------- | -------------------------------------------------------------------------------- | ------- |
|
|
30
|
+
| `variant` | 语义与品牌用途 | `featured \| accent \| brand \| neutral \| success \| warning \| danger \| info` | `brand` |
|
|
31
|
+
| `tone` | 强调色,仅作用于 `accent` | `blue \| sun \| cyan \| coral \| pink \| green` | `blue` |
|
|
32
|
+
| `appearance` | `accent` 与状态变体的强调程度 | `solid \| soft \| outline` | `solid` |
|
|
33
|
+
| `round` | 胶囊圆角;关闭后使用小圆角 | `boolean` | `true` |
|
|
34
|
+
|
|
35
|
+
`tone` 可选 `blue | sun | cyan | coral | pink | green`,默认 `blue`(晴空蓝),仅作用于 `accent`。`featured` 始终使用精选 token,不随 `tone` 改变。旧 `aurora` 值映射到 `featured`。
|
|
36
|
+
|
|
37
|
+
## Slots
|
|
38
|
+
|
|
39
|
+
| 名称 | 说明 |
|
|
40
|
+
| --------- | -------- |
|
|
41
|
+
| `default` | 徽标内容 |
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
import type { BottomMenuItem } from '
|
|
2
|
+
import type { BottomMenuItem } from './index'
|
|
3
3
|
import { ref } from 'vue'
|
|
4
4
|
|
|
5
5
|
const items: BottomMenuItem[] = [
|
|
@@ -15,6 +15,12 @@ const items: BottomMenuItem[] = [
|
|
|
15
15
|
title: '发现',
|
|
16
16
|
to: '/discover',
|
|
17
17
|
},
|
|
18
|
+
{
|
|
19
|
+
icon: 'i-ri-copper-coin-line',
|
|
20
|
+
activeIcon: 'i-ri-copper-coin-fill',
|
|
21
|
+
title: '云币',
|
|
22
|
+
to: '/coin',
|
|
23
|
+
},
|
|
18
24
|
{
|
|
19
25
|
icon: 'i-ri-user-line',
|
|
20
26
|
activeIcon: 'i-ri-user-fill',
|
|
@@ -37,13 +43,16 @@ function onClick(item: BottomMenuItem) {
|
|
|
37
43
|
</script>
|
|
38
44
|
|
|
39
45
|
<template>
|
|
40
|
-
<
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
<div class="mx-auto max-w-xs overflow-hidden border border-$ylf-c-border rounded-ylf-xl">
|
|
47
|
+
<div class="h-28 op-90 bg-brand-gradient" />
|
|
48
|
+
<YlfBottomMenu shadow>
|
|
49
|
+
<YlfBottomMenuItem
|
|
50
|
+
v-for="item in items"
|
|
51
|
+
:key="item.to"
|
|
52
|
+
:item="item"
|
|
53
|
+
:active="active === item.to"
|
|
54
|
+
@click="onClick"
|
|
55
|
+
/>
|
|
56
|
+
</YlfBottomMenu>
|
|
57
|
+
</div>
|
|
49
58
|
</template>
|
|
@@ -2,3 +2,28 @@
|
|
|
2
2
|
title: Bottom Menu
|
|
3
3
|
title_zh: 底部菜单
|
|
4
4
|
---
|
|
5
|
+
|
|
6
|
+
云玻璃底部导航:背景模糊通透,激活项使用晴空蓝主色。适合 H5 / 子应用的主导航。
|
|
7
|
+
|
|
8
|
+
## YlfBottomMenu Props
|
|
9
|
+
|
|
10
|
+
| 属性 | 说明 | 类型 | 默认值 |
|
|
11
|
+
| -------- | -------- | --------- | ------- |
|
|
12
|
+
| `shadow` | 浮起阴影 | `boolean` | `false` |
|
|
13
|
+
|
|
14
|
+
## YlfBottomMenuItem Props
|
|
15
|
+
|
|
16
|
+
| 属性 | 说明 | 类型 |
|
|
17
|
+
| -------- | ---------- | ---------------- |
|
|
18
|
+
| `item` | 菜单项数据 | `BottomMenuItem` |
|
|
19
|
+
| `active` | 是否激活 | `boolean` |
|
|
20
|
+
|
|
21
|
+
## BottomMenuItem
|
|
22
|
+
|
|
23
|
+
| 字段 | 说明 | 类型 |
|
|
24
|
+
| ------------ | ---------------- | -------------------------- |
|
|
25
|
+
| `title` | 标题 | `string` |
|
|
26
|
+
| `icon` | 图标 class | `string` |
|
|
27
|
+
| `activeIcon` | 激活态图标 class | `string?` |
|
|
28
|
+
| `to` | 路由目标 | `string?` |
|
|
29
|
+
| `onClick` | 点击回调 | `(...args: any[]) => void` |
|