@brickflow/ui 0.0.40 → 0.0.43
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.json +1 -1
- package/dist/module.mjs +3 -0
- package/dist/runtime/components/Button/icons.demo.vue +9 -9
- package/dist/runtime/components/Button/index.vue +83 -57
- package/dist/runtime/components/Button/size.demo.vue +35 -66
- package/dist/runtime/components/Button/slots.demo.vue +10 -8
- package/dist/runtime/components/Button/state.demo.vue +58 -8
- package/dist/runtime/components/Button/variants.demo.vue +18 -20
- package/dist/runtime/components/Icon/basic.demo.vue +13 -10
- package/dist/runtime/components/Icon/gallery.demo.vue +142 -0
- package/dist/runtime/components/Icon/index.vue +15 -9
- package/dist/runtime/components/Link/basic.demo.vue +7 -7
- package/dist/runtime/components/Link/index.vue +81 -50
- package/dist/runtime/icon-font.d.ts +1 -0
- package/dist/runtime/pages/ui.vue +514 -347
- package/package.json +5 -5
- package/dist/runtime/components/Button/icons.demo.d.vue.ts +0 -8
- package/dist/runtime/components/Button/icons.demo.vue.d.ts +0 -8
- package/dist/runtime/components/Button/index.d.vue.ts +0 -51
- package/dist/runtime/components/Button/index.vue.d.ts +0 -51
- package/dist/runtime/components/Button/size.demo.d.vue.ts +0 -7
- package/dist/runtime/components/Button/size.demo.vue.d.ts +0 -7
- package/dist/runtime/components/Button/slots.demo.d.vue.ts +0 -7
- package/dist/runtime/components/Button/slots.demo.vue.d.ts +0 -7
- package/dist/runtime/components/Button/state.demo.d.vue.ts +0 -7
- package/dist/runtime/components/Button/state.demo.vue.d.ts +0 -7
- package/dist/runtime/components/Button/variants.demo.d.vue.ts +0 -7
- package/dist/runtime/components/Button/variants.demo.vue.d.ts +0 -7
- package/dist/runtime/components/Icon/basic.demo.d.vue.ts +0 -8
- package/dist/runtime/components/Icon/basic.demo.vue.d.ts +0 -8
- package/dist/runtime/components/Icon/index.d.vue.ts +0 -7
- package/dist/runtime/components/Icon/index.vue.d.ts +0 -7
- package/dist/runtime/components/Link/basic.demo.d.vue.ts +0 -8
- package/dist/runtime/components/Link/basic.demo.vue.d.ts +0 -8
- package/dist/runtime/components/Link/index.d.vue.ts +0 -51
- package/dist/runtime/components/Link/index.vue.d.ts +0 -51
- package/dist/runtime/pages/ui.d.vue.ts +0 -4
- package/dist/runtime/pages/ui.vue.d.ts +0 -4
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -750,6 +750,9 @@ const module$1 = defineNuxtModule({
|
|
|
750
750
|
getContents: async () => {
|
|
751
751
|
const iconNames = iconFont ? await getIconFontNames(iconFont.inputDir) : [];
|
|
752
752
|
return [
|
|
753
|
+
"import { uiConfig } from '#brickflow-ui-config'",
|
|
754
|
+
"",
|
|
755
|
+
"export const buttonConfig = uiConfig.button",
|
|
753
756
|
`export const iconNames = ${JSON.stringify(iconNames)}`,
|
|
754
757
|
`export const firstIconName = ${JSON.stringify(iconNames[0] ?? "")}`,
|
|
755
758
|
""
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
export const uiDemo = {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export const uiDemo = {
|
|
3
|
+
description: 'Set leadingIcon and trailingIcon to an icon name. Slots take precedence when both are provided.',
|
|
4
|
+
title: 'Icons',
|
|
5
|
+
}
|
|
6
6
|
</script>
|
|
7
7
|
|
|
8
|
-
<script setup>
|
|
9
|
-
import { firstIconName } from
|
|
10
|
-
|
|
8
|
+
<script lang="ts" setup>
|
|
9
|
+
import { firstIconName } from '#brickflow-ui-icons'
|
|
10
|
+
|
|
11
|
+
import Button from './index.vue'
|
|
11
12
|
</script>
|
|
12
13
|
|
|
13
14
|
<template>
|
|
@@ -17,7 +18,6 @@ import Button from "./index.vue";
|
|
|
17
18
|
<Button
|
|
18
19
|
:icon="firstIconName"
|
|
19
20
|
:trailingIcon="firstIconName"
|
|
20
|
-
variant="soft"
|
|
21
21
|
>
|
|
22
22
|
View profile
|
|
23
23
|
</Button>
|
|
@@ -1,53 +1,79 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
const UI_CONFIG = defineUiConfig
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
const UI_CONFIG = defineUiConfig<{
|
|
3
|
+
colorClasses: Record<string, Record<string, string>>
|
|
4
|
+
colorDefault: string
|
|
5
|
+
loadingIconName: string
|
|
6
|
+
sizeClasses: Record<string, string>
|
|
7
|
+
sizeDefault: string
|
|
8
|
+
sizeIconClasses: Record<string, string>
|
|
9
|
+
variantDefault: string
|
|
10
|
+
}>()
|
|
11
|
+
|
|
12
|
+
export type ButtonConfig = typeof UI_CONFIG
|
|
3
13
|
</script>
|
|
4
14
|
|
|
5
|
-
<script setup>
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
import
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
15
|
+
<script setup lang="ts">
|
|
16
|
+
import type { RouteLocationRaw } from 'vue-router'
|
|
17
|
+
|
|
18
|
+
import { computed, shallowRef } from 'vue'
|
|
19
|
+
|
|
20
|
+
import Icon from '../Icon/index.vue'
|
|
21
|
+
import BaseLink from '../Link/index.vue'
|
|
22
|
+
const props = withDefaults(
|
|
23
|
+
defineProps<{
|
|
24
|
+
block?: boolean
|
|
25
|
+
color?: ButtonColor
|
|
26
|
+
disabled?: boolean
|
|
27
|
+
icon?: string
|
|
28
|
+
loading?: boolean
|
|
29
|
+
rounded?: boolean
|
|
30
|
+
size?: ButtonSize
|
|
31
|
+
square?: boolean
|
|
32
|
+
to?: RouteLocationRaw
|
|
33
|
+
trailingIcon?: string
|
|
34
|
+
type?: 'button' | 'reset' | 'submit'
|
|
35
|
+
variant?: ButtonVariant
|
|
36
|
+
}>(),
|
|
37
|
+
{
|
|
38
|
+
color: UI_CONFIG.colorDefault,
|
|
39
|
+
icon: undefined,
|
|
40
|
+
rounded: false,
|
|
41
|
+
size: UI_CONFIG.sizeDefault,
|
|
42
|
+
to: undefined,
|
|
43
|
+
trailingIcon: undefined,
|
|
44
|
+
type: 'button',
|
|
45
|
+
variant: UI_CONFIG.variantDefault,
|
|
46
|
+
},
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
const colorClasses = UI_CONFIG.colorClasses
|
|
50
|
+
const sizeClasses = UI_CONFIG.sizeClasses
|
|
51
|
+
const sizeIconClasses = UI_CONFIG.sizeIconClasses
|
|
52
|
+
type ButtonColor = Extract<keyof typeof colorClasses, string>
|
|
53
|
+
type ButtonSize = Extract<keyof typeof sizeClasses, string>
|
|
54
|
+
type ButtonVariant = Extract<keyof (typeof colorClasses)[ButtonColor], string>
|
|
55
|
+
|
|
56
|
+
const component = computed(() => (props.to === undefined ? 'button' : BaseLink))
|
|
57
|
+
const disabled = computed(() => props.disabled || props.loading)
|
|
58
|
+
const isButton = computed(() => props.to === undefined)
|
|
59
|
+
const classes = computed(() => [
|
|
60
|
+
UI_STYLE.base,
|
|
61
|
+
sizeClasses[props.size],
|
|
62
|
+
colorClasses[props.color][props.variant],
|
|
63
|
+
props.block && UI_STYLE.state.block,
|
|
64
|
+
props.square && UI_STYLE.state.square,
|
|
65
|
+
disabled.value && UI_STYLE.state.disabled,
|
|
66
|
+
])
|
|
67
|
+
|
|
68
|
+
const isAnimating = shallowRef(false)
|
|
69
|
+
const animationTapClass = UI_STYLE.animationTap
|
|
70
|
+
function handleTap(): void {
|
|
71
|
+
isAnimating.value = false
|
|
72
|
+
|
|
73
|
+
requestAnimationFrame(() => {
|
|
74
|
+
isAnimating.value = true
|
|
75
|
+
})
|
|
76
|
+
}
|
|
51
77
|
</script>
|
|
52
78
|
|
|
53
79
|
<template>
|
|
@@ -55,16 +81,16 @@ function handleTap() {
|
|
|
55
81
|
:is="component"
|
|
56
82
|
v-bind="animationTapClass ? { onPointerupPassive: handleTap } : {}"
|
|
57
83
|
:to="props.to"
|
|
58
|
-
:type="isButton ? props.type :
|
|
59
|
-
:disabled="isButton ? disabled :
|
|
60
|
-
:aria-busy="props.loading ||
|
|
61
|
-
:aria-disabled="disabled ||
|
|
62
|
-
:tabindex="disabled && !isButton ? -1 :
|
|
84
|
+
:type="isButton ? props.type : undefined"
|
|
85
|
+
:disabled="isButton ? disabled : undefined"
|
|
86
|
+
:aria-busy="props.loading || undefined"
|
|
87
|
+
:aria-disabled="disabled || undefined"
|
|
88
|
+
:tabindex="disabled && !isButton ? -1 : undefined"
|
|
63
89
|
:class="[classes, isAnimating && animationTapClass]"
|
|
64
90
|
data-testid="ui-button"
|
|
65
91
|
:style="{
|
|
66
|
-
|
|
67
|
-
}"
|
|
92
|
+
borderRadius: props.rounded && '99999px',
|
|
93
|
+
}"
|
|
68
94
|
@contextmenu.prevent
|
|
69
95
|
>
|
|
70
96
|
<span
|
|
@@ -80,7 +106,7 @@ function handleTap() {
|
|
|
80
106
|
/>
|
|
81
107
|
<Icon
|
|
82
108
|
v-else
|
|
83
|
-
:name="props.icon"
|
|
109
|
+
:name="props.icon!"
|
|
84
110
|
:class="sizeIconClasses[props.size]"
|
|
85
111
|
aria-hidden="true"
|
|
86
112
|
/>
|
|
@@ -100,7 +126,7 @@ function handleTap() {
|
|
|
100
126
|
>
|
|
101
127
|
<slot name="trailing">
|
|
102
128
|
<Icon
|
|
103
|
-
:name="props.trailingIcon"
|
|
129
|
+
:name="props.trailingIcon!"
|
|
104
130
|
:class="sizeIconClasses[props.size]"
|
|
105
131
|
aria-hidden="true"
|
|
106
132
|
/>
|
|
@@ -1,78 +1,47 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
export const uiDemo = {
|
|
3
|
-
|
|
4
|
-
}
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export const uiDemo = {
|
|
3
|
+
title: 'Size & Rounded',
|
|
4
|
+
}
|
|
5
5
|
</script>
|
|
6
6
|
|
|
7
|
-
<script setup>
|
|
8
|
-
import { firstIconName } from
|
|
9
|
-
|
|
7
|
+
<script lang="ts" setup>
|
|
8
|
+
import { buttonConfig, firstIconName } from '#brickflow-ui-icons'
|
|
9
|
+
|
|
10
|
+
import Button from './index.vue'
|
|
10
11
|
</script>
|
|
11
12
|
|
|
12
13
|
<template>
|
|
13
14
|
<div class="flex flex-col gap-3">
|
|
14
15
|
<div class="flex flex-wrap items-center gap-3">
|
|
15
|
-
<
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
<Button
|
|
29
|
-
:icon="firstIconName"
|
|
30
|
-
size="lg"
|
|
31
|
-
>
|
|
32
|
-
Button
|
|
33
|
-
</Button>
|
|
34
|
-
<Button
|
|
35
|
-
:icon="firstIconName"
|
|
36
|
-
size="xl"
|
|
37
|
-
>
|
|
38
|
-
Button
|
|
39
|
-
</Button>
|
|
16
|
+
<div
|
|
17
|
+
v-for="(_, size) in buttonConfig.sizeClasses"
|
|
18
|
+
:key="size"
|
|
19
|
+
class="flex flex-col items-center gap-1"
|
|
20
|
+
>
|
|
21
|
+
<span class="text-xs text-zinc-500">{{ size }}</span>
|
|
22
|
+
<Button
|
|
23
|
+
:icon="firstIconName"
|
|
24
|
+
:size="size"
|
|
25
|
+
>
|
|
26
|
+
Button
|
|
27
|
+
</Button>
|
|
28
|
+
</div>
|
|
40
29
|
</div>
|
|
41
30
|
<div class="flex flex-wrap items-center gap-3">
|
|
42
|
-
<
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
>
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
Button
|
|
55
|
-
</
|
|
56
|
-
<Button
|
|
57
|
-
:icon="firstIconName"
|
|
58
|
-
rounded
|
|
59
|
-
>
|
|
60
|
-
Button
|
|
61
|
-
</Button>
|
|
62
|
-
<Button
|
|
63
|
-
:icon="firstIconName"
|
|
64
|
-
size="lg"
|
|
65
|
-
rounded
|
|
66
|
-
>
|
|
67
|
-
Button
|
|
68
|
-
</Button>
|
|
69
|
-
<Button
|
|
70
|
-
:icon="firstIconName"
|
|
71
|
-
size="xl"
|
|
72
|
-
rounded
|
|
73
|
-
>
|
|
74
|
-
Button
|
|
75
|
-
</Button>
|
|
31
|
+
<div
|
|
32
|
+
v-for="(_, size) in buttonConfig.sizeClasses"
|
|
33
|
+
:key="size"
|
|
34
|
+
class="flex flex-col items-center gap-1"
|
|
35
|
+
>
|
|
36
|
+
<span class="text-xs text-zinc-500">{{ size }}</span>
|
|
37
|
+
<Button
|
|
38
|
+
:icon="firstIconName"
|
|
39
|
+
:size="size"
|
|
40
|
+
rounded
|
|
41
|
+
>
|
|
42
|
+
Button
|
|
43
|
+
</Button>
|
|
44
|
+
</div>
|
|
76
45
|
</div>
|
|
77
46
|
</div>
|
|
78
47
|
</template>
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
export const uiDemo = {
|
|
3
|
-
|
|
4
|
-
}
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export const uiDemo = {
|
|
3
|
+
title: 'Slots',
|
|
4
|
+
}
|
|
5
5
|
</script>
|
|
6
6
|
|
|
7
|
-
<script setup>
|
|
8
|
-
import { ref } from
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
<script lang="ts" setup>
|
|
8
|
+
import { ref } from 'vue'
|
|
9
|
+
|
|
10
|
+
import Button from './index.vue'
|
|
11
|
+
|
|
12
|
+
const clicks = ref(0)
|
|
11
13
|
</script>
|
|
12
14
|
|
|
13
15
|
<template>
|
|
@@ -1,17 +1,67 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
export const uiDemo = {
|
|
3
|
-
|
|
4
|
-
}
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export const uiDemo = {
|
|
3
|
+
title: 'State',
|
|
4
|
+
}
|
|
5
5
|
</script>
|
|
6
6
|
|
|
7
|
-
<script setup>
|
|
8
|
-
import
|
|
7
|
+
<script lang="ts" setup>
|
|
8
|
+
import { buttonConfig } from '#brickflow-ui-icons'
|
|
9
|
+
|
|
10
|
+
import Button from './index.vue'
|
|
11
|
+
|
|
12
|
+
const firstColorClasses = Object.values(buttonConfig.colorClasses)[0] ?? {}
|
|
9
13
|
</script>
|
|
10
14
|
|
|
11
15
|
<template>
|
|
12
16
|
<div class="flex flex-wrap items-center gap-3">
|
|
13
|
-
<
|
|
14
|
-
|
|
17
|
+
<div class="basis-full">
|
|
18
|
+
<div class="relative flex w-fit flex-col items-start gap-3 pl-13">
|
|
19
|
+
<div class="absolute top-0 left-0 z-0 size-full object-cover pt-7 pl-13">
|
|
20
|
+
<img
|
|
21
|
+
src="https://images.unsplash.com/photo-1545346315-f4c47e3e1b55?ixid=M3w4MjcwNjd8MHwxfHNlYXJjaHwyfHxzdHJvbmclMjBtYW58ZW58MHx8fHwxNzg4MjIyNTU1fDA&ixlib=rb-4.1.0&w=1000&h=1000&fit=max&q=80"
|
|
22
|
+
class="top-0 z-0 size-full rounded-xl object-cover opacity-50"
|
|
23
|
+
/>
|
|
24
|
+
</div>
|
|
25
|
+
<div class="flex w-full items-center justify-around gap-3 text-xs text-slate-600">
|
|
26
|
+
<span
|
|
27
|
+
v-for="(_, variant) in firstColorClasses"
|
|
28
|
+
:key="variant"
|
|
29
|
+
>
|
|
30
|
+
{{ variant }}
|
|
31
|
+
</span>
|
|
32
|
+
</div>
|
|
33
|
+
<div
|
|
34
|
+
v-for="(variants, color) in buttonConfig.colorClasses"
|
|
35
|
+
:key="color"
|
|
36
|
+
class="relative flex w-full items-center gap-3 p-2"
|
|
37
|
+
>
|
|
38
|
+
<span class="absolute top-1/2 right-full mr-3 -translate-y-1/2 text-xs text-slate-600">
|
|
39
|
+
{{ color }}
|
|
40
|
+
</span>
|
|
41
|
+
<div
|
|
42
|
+
v-for="(_, variant) in variants"
|
|
43
|
+
:key="variant"
|
|
44
|
+
class="flex flex-col items-stretch gap-2"
|
|
45
|
+
>
|
|
46
|
+
<Button
|
|
47
|
+
disabled
|
|
48
|
+
:color="color"
|
|
49
|
+
:variant="variant"
|
|
50
|
+
>
|
|
51
|
+
Disabled
|
|
52
|
+
</Button>
|
|
53
|
+
<Button
|
|
54
|
+
loading
|
|
55
|
+
:color="color"
|
|
56
|
+
:variant="variant"
|
|
57
|
+
>
|
|
58
|
+
Loading
|
|
59
|
+
</Button>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
|
|
15
65
|
<Button to="/">Link</Button>
|
|
16
66
|
<Button block>Block</Button>
|
|
17
67
|
</div>
|
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
export const uiDemo = {
|
|
3
|
-
|
|
4
|
-
}
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export const uiDemo = {
|
|
3
|
+
title: 'Color & Variants',
|
|
4
|
+
}
|
|
5
5
|
</script>
|
|
6
6
|
|
|
7
|
-
<script setup>
|
|
8
|
-
import
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}));
|
|
14
|
-
const variants = colors[0]?.variants ?? [];
|
|
7
|
+
<script lang="ts" setup>
|
|
8
|
+
import { buttonConfig } from '#brickflow-ui-icons'
|
|
9
|
+
|
|
10
|
+
import Button from './index.vue'
|
|
11
|
+
|
|
12
|
+
const firstColorClasses = Object.values(buttonConfig.colorClasses)[0] ?? {}
|
|
15
13
|
</script>
|
|
16
14
|
|
|
17
15
|
<template>
|
|
@@ -22,26 +20,26 @@ const variants = colors[0]?.variants ?? [];
|
|
|
22
20
|
class="top-0 z-0 size-full rounded-xl object-cover opacity-50"
|
|
23
21
|
/>
|
|
24
22
|
</div>
|
|
25
|
-
<div class="flex w-full
|
|
23
|
+
<div class="flex w-full items-center justify-around gap-3 text-xs text-slate-600">
|
|
26
24
|
<span
|
|
27
|
-
v-for="variant in
|
|
25
|
+
v-for="(_, variant) in firstColorClasses"
|
|
28
26
|
:key="variant"
|
|
29
27
|
>
|
|
30
28
|
{{ variant }}
|
|
31
29
|
</span>
|
|
32
30
|
</div>
|
|
33
31
|
<div
|
|
34
|
-
v-for="color in
|
|
35
|
-
:key="color
|
|
36
|
-
class="relative flex w-full
|
|
32
|
+
v-for="(variants, color) in buttonConfig.colorClasses"
|
|
33
|
+
:key="color"
|
|
34
|
+
class="relative flex w-full items-center gap-3 p-2"
|
|
37
35
|
>
|
|
38
36
|
<span class="absolute top-1/2 right-full mr-3 -translate-y-1/2 text-xs text-slate-600">
|
|
39
|
-
{{ color
|
|
37
|
+
{{ color }}
|
|
40
38
|
</span>
|
|
41
39
|
<Button
|
|
42
|
-
v-for="variant in
|
|
40
|
+
v-for="(_, variant) in variants"
|
|
43
41
|
:key="variant"
|
|
44
|
-
:color="color
|
|
42
|
+
:color="color"
|
|
45
43
|
:variant="variant"
|
|
46
44
|
>
|
|
47
45
|
Button
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
export const uiDemo = {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export const uiDemo = {
|
|
3
|
+
description: 'The name matches the SVG filename without its extension.',
|
|
4
|
+
title: 'Basic usage',
|
|
5
|
+
}
|
|
6
6
|
</script>
|
|
7
7
|
|
|
8
|
-
<script setup>
|
|
9
|
-
import { ref } from
|
|
10
|
-
|
|
11
|
-
import
|
|
12
|
-
|
|
8
|
+
<script lang="ts" setup>
|
|
9
|
+
import { ref } from 'vue'
|
|
10
|
+
|
|
11
|
+
import { firstIconName } from '#brickflow-ui-icons'
|
|
12
|
+
|
|
13
|
+
import Icon from './index.vue'
|
|
14
|
+
|
|
15
|
+
const iconName = ref(firstIconName)
|
|
13
16
|
</script>
|
|
14
17
|
|
|
15
18
|
<template>
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export const uiDemo = {
|
|
3
|
+
description: 'Browse every icon available in the project, filter by name, and click to copy its name.',
|
|
4
|
+
title: 'Icon gallery',
|
|
5
|
+
}
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<script lang="ts" setup>
|
|
9
|
+
import { computed, onBeforeUnmount, ref } from 'vue'
|
|
10
|
+
|
|
11
|
+
import { iconNames } from '#brickflow-ui-icons'
|
|
12
|
+
|
|
13
|
+
import Icon from './index.vue'
|
|
14
|
+
|
|
15
|
+
const search = ref('')
|
|
16
|
+
const copiedIconName = ref('')
|
|
17
|
+
const copyError = ref('')
|
|
18
|
+
let copiedTimeout: ReturnType<typeof setTimeout> | undefined
|
|
19
|
+
|
|
20
|
+
const filteredIconNames = computed(() => {
|
|
21
|
+
const query = search.value.trim().toLocaleLowerCase()
|
|
22
|
+
|
|
23
|
+
return query ? iconNames.filter((name) => name.toLocaleLowerCase().includes(query)) : iconNames
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
const copyIconName = async (name: string): Promise<void> => {
|
|
27
|
+
copyError.value = ''
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
await navigator.clipboard.writeText(name)
|
|
31
|
+
clearTimeout(copiedTimeout)
|
|
32
|
+
copiedIconName.value = name
|
|
33
|
+
copiedTimeout = setTimeout(() => {
|
|
34
|
+
copiedIconName.value = ''
|
|
35
|
+
}, 2000)
|
|
36
|
+
} catch {
|
|
37
|
+
copyError.value = 'Could not copy the icon name. Please try again.'
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
onBeforeUnmount(() => clearTimeout(copiedTimeout))
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
<template>
|
|
45
|
+
<div class="space-y-5 text-zinc-100">
|
|
46
|
+
<div class="flex flex-wrap items-center justify-between gap-3">
|
|
47
|
+
<label class="relative block w-full max-w-md">
|
|
48
|
+
<span class="sr-only">Search icons</span>
|
|
49
|
+
<svg
|
|
50
|
+
class="pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-zinc-500"
|
|
51
|
+
aria-hidden="true"
|
|
52
|
+
fill="none"
|
|
53
|
+
stroke="currentColor"
|
|
54
|
+
stroke-linecap="round"
|
|
55
|
+
stroke-linejoin="round"
|
|
56
|
+
stroke-width="2"
|
|
57
|
+
viewBox="0 0 24 24"
|
|
58
|
+
>
|
|
59
|
+
<circle
|
|
60
|
+
cx="11"
|
|
61
|
+
cy="11"
|
|
62
|
+
r="8"
|
|
63
|
+
/>
|
|
64
|
+
<path d="m21 21-4.3-4.3" />
|
|
65
|
+
</svg>
|
|
66
|
+
<input
|
|
67
|
+
v-model="search"
|
|
68
|
+
class="w-full max-w-60 rounded-lg border border-zinc-700 bg-zinc-950 py-2 pr-3 pl-9 text-sm text-zinc-200 caret-blue-400 outline-none placeholder:text-zinc-500 focus:border-blue-400 focus:ring-2 focus:ring-blue-400/20"
|
|
69
|
+
placeholder="Search icon"
|
|
70
|
+
type="search"
|
|
71
|
+
/>
|
|
72
|
+
</label>
|
|
73
|
+
|
|
74
|
+
<p
|
|
75
|
+
class="text-sm text-zinc-400"
|
|
76
|
+
aria-live="polite"
|
|
77
|
+
>
|
|
78
|
+
{{ filteredIconNames.length }} of {{ iconNames.length }} icons
|
|
79
|
+
</p>
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
<p
|
|
83
|
+
class="sr-only"
|
|
84
|
+
role="status"
|
|
85
|
+
>
|
|
86
|
+
{{ copiedIconName ? `Copied ${copiedIconName}` : '' }}
|
|
87
|
+
</p>
|
|
88
|
+
<p
|
|
89
|
+
v-if="copyError"
|
|
90
|
+
class="text-sm text-red-400"
|
|
91
|
+
role="alert"
|
|
92
|
+
>
|
|
93
|
+
{{ copyError }}
|
|
94
|
+
</p>
|
|
95
|
+
|
|
96
|
+
<ul
|
|
97
|
+
v-if="filteredIconNames.length"
|
|
98
|
+
class="grid grid-cols-6 gap-3 lp:grid-cols-5 tb:grid-cols-4 mb:grid-cols-3 ms:grid-cols-2"
|
|
99
|
+
>
|
|
100
|
+
<li
|
|
101
|
+
v-for="name in filteredIconNames"
|
|
102
|
+
:key="name"
|
|
103
|
+
class="min-w-0"
|
|
104
|
+
>
|
|
105
|
+
<button
|
|
106
|
+
type="button"
|
|
107
|
+
:aria-label="`Copy ${name}`"
|
|
108
|
+
:class="[
|
|
109
|
+
'group flex w-full cursor-pointer flex-col items-center gap-3 rounded-xl border px-3 py-5 transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-400',
|
|
110
|
+
copiedIconName === name
|
|
111
|
+
? 'border-green-500/50 bg-green-500/10'
|
|
112
|
+
: 'border-zinc-900 bg-zinc-950/50 hover:border-zinc-700 hover:bg-zinc-900/70',
|
|
113
|
+
]"
|
|
114
|
+
:title="`Copy ${name}`"
|
|
115
|
+
@click="copyIconName(name)"
|
|
116
|
+
>
|
|
117
|
+
<Icon
|
|
118
|
+
:name="name"
|
|
119
|
+
aria-hidden="true"
|
|
120
|
+
class="text-3xl text-zinc-100"
|
|
121
|
+
/>
|
|
122
|
+
<span
|
|
123
|
+
:class="[
|
|
124
|
+
'w-full truncate text-center font-mono text-xs transition-colors',
|
|
125
|
+
copiedIconName === name ? 'text-green-400' : 'text-zinc-400 group-hover:text-zinc-100',
|
|
126
|
+
]"
|
|
127
|
+
>
|
|
128
|
+
{{ copiedIconName === name ? 'Copied' : name }}
|
|
129
|
+
</span>
|
|
130
|
+
</button>
|
|
131
|
+
</li>
|
|
132
|
+
</ul>
|
|
133
|
+
|
|
134
|
+
<div
|
|
135
|
+
v-else
|
|
136
|
+
class="rounded-xl border border-dashed border-zinc-700 px-6 py-12 text-center"
|
|
137
|
+
>
|
|
138
|
+
<p class="text-sm font-medium text-zinc-200">No icons found</p>
|
|
139
|
+
<p class="mt-1 text-sm text-zinc-500">Try another name.</p>
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
</template>
|