pimelon-ui 0.0.104 → 0.1.0-alpha.4
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/package.json +47 -25
- package/src/components/.DS_Store +0 -0
- package/src/components/Alert.vue +2 -2
- package/src/components/Autocomplete.vue +83 -62
- package/src/components/Avatar.stories.ts +110 -0
- package/src/components/Avatar.vue +115 -50
- package/src/components/Badge.stories.js +149 -0
- package/src/components/Badge.vue +80 -36
- package/src/components/Button.stories.js +173 -0
- package/src/components/Button.vue +169 -131
- package/src/components/Checkbox.vue +74 -0
- package/src/components/Dialog.vue +127 -84
- package/src/components/Divider.stories.ts +110 -0
- package/src/components/Divider.vue +67 -0
- package/src/components/Dropdown.stories.ts +73 -0
- package/src/components/Dropdown.vue +19 -9
- package/src/components/FormControl.vue +96 -0
- package/src/components/Input.vue +1 -1
- package/src/components/LoadingText.vue +1 -1
- package/src/components/Popover.vue +1 -1
- package/src/components/Progress.stories.js +80 -0
- package/src/components/Progress.vue +91 -0
- package/src/components/Select.vue +135 -0
- package/src/components/Spinner.stories.ts +13 -0
- package/src/components/Spinner.vue +50 -0
- package/src/components/Switch.stories.js +52 -0
- package/src/components/Switch.vue +145 -0
- package/src/components/TextEditor/.DS_Store +0 -0
- package/src/components/TextEditor/InsertImage.vue +1 -1
- package/src/components/TextEditor/InsertLink.vue +2 -2
- package/src/components/TextEditor/InsertVideo.vue +1 -1
- package/src/components/TextEditor/TextEditor.vue +20 -9
- package/src/components/TextEditor/TextEditorBubbleMenu.vue +2 -1
- package/src/components/TextEditor/icons/.DS_Store +0 -0
- package/src/components/TextInput.stories.ts +143 -0
- package/src/components/TextInput.vue +147 -0
- package/src/components/Textarea.vue +86 -0
- package/src/components/Tooltip.vue +4 -2
- package/src/components/types/TextInput.ts +14 -0
- package/src/fonts/Inter/Inter-Black.woff2 +0 -0
- package/src/fonts/Inter/Inter-BlackItalic.woff2 +0 -0
- package/src/fonts/Inter/Inter-Bold.woff2 +0 -0
- package/src/fonts/Inter/Inter-BoldItalic.woff2 +0 -0
- package/src/fonts/Inter/Inter-Display.woff2 +0 -0
- package/src/fonts/Inter/Inter-DisplayBlack.woff2 +0 -0
- package/src/fonts/Inter/Inter-DisplayBlackItalic.woff2 +0 -0
- package/src/fonts/Inter/Inter-DisplayBold.woff2 +0 -0
- package/src/fonts/Inter/Inter-DisplayBoldItalic.woff2 +0 -0
- package/src/fonts/Inter/Inter-DisplayExtraBold.woff2 +0 -0
- package/src/fonts/Inter/Inter-DisplayExtraBoldItalic.woff2 +0 -0
- package/src/fonts/Inter/Inter-DisplayExtraLight.woff2 +0 -0
- package/src/fonts/Inter/Inter-DisplayExtraLightItalic.woff2 +0 -0
- package/src/fonts/Inter/Inter-DisplayItalic.woff2 +0 -0
- package/src/fonts/Inter/Inter-DisplayLight.woff2 +0 -0
- package/src/fonts/Inter/Inter-DisplayLightItalic.woff2 +0 -0
- package/src/fonts/Inter/Inter-DisplayMedium.woff2 +0 -0
- package/src/fonts/Inter/Inter-DisplayMediumItalic.woff2 +0 -0
- package/src/fonts/Inter/Inter-DisplaySemiBold.woff2 +0 -0
- package/src/fonts/Inter/Inter-DisplaySemiBoldItalic.woff2 +0 -0
- package/src/fonts/Inter/Inter-DisplayThin.woff2 +0 -0
- package/src/fonts/Inter/Inter-DisplayThinItalic.woff2 +0 -0
- package/src/fonts/Inter/Inter-ExtraBold.woff2 +0 -0
- package/src/fonts/Inter/Inter-ExtraBoldItalic.woff2 +0 -0
- package/src/fonts/Inter/Inter-ExtraLight.woff2 +0 -0
- package/src/fonts/Inter/Inter-ExtraLightItalic.woff2 +0 -0
- package/src/fonts/Inter/Inter-Italic.var.woff2 +0 -0
- package/src/fonts/Inter/Inter-Italic.woff2 +0 -0
- package/src/fonts/Inter/Inter-Light.woff2 +0 -0
- package/src/fonts/Inter/Inter-LightItalic.woff2 +0 -0
- package/src/fonts/Inter/Inter-Medium.woff2 +0 -0
- package/src/fonts/Inter/Inter-MediumItalic.woff2 +0 -0
- package/src/fonts/Inter/Inter-Regular.woff2 +0 -0
- package/src/fonts/Inter/Inter-SemiBold.woff2 +0 -0
- package/src/fonts/Inter/Inter-SemiBoldItalic.woff2 +0 -0
- package/src/fonts/Inter/Inter-Thin.woff2 +0 -0
- package/src/fonts/Inter/Inter-ThinItalic.woff2 +0 -0
- package/src/fonts/Inter/Inter.var.woff2 +0 -0
- package/src/fonts/Inter/inter.css +277 -0
- package/src/index.js +13 -1
- package/src/resources/documentResource.js +3 -2
- package/src/resources/index.js +6 -3
- package/src/resources/listResource.js +36 -17
- package/src/resources/plugin.js +1 -16
- package/src/resources/realtime.js +15 -0
- package/src/resources/resources.js +3 -4
- package/src/style.css +16 -1
- package/src/tokens/Color.vue +194 -0
- package/src/utils/{debounce.js → debounce.ts} +8 -4
- package/src/utils/tailwind.config.js +388 -73
- package/src/utils/tailwind.config.stories.js +8 -0
- package/src/utils/useId.ts +8 -0
- package/src/vite-env.d.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pimelon-ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.1.0-alpha.4",
|
|
4
4
|
"description": "A set of components and utilities for rapid UI development",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -10,7 +10,12 @@
|
|
|
10
10
|
"bump-and-release": "git pull --rebase origin main && yarn version --patch && git push && git push --tags",
|
|
11
11
|
"docs:dev": "vitepress dev docs",
|
|
12
12
|
"docs:build": "vitepress build docs",
|
|
13
|
-
"docs:serve": "vitepress serve docs"
|
|
13
|
+
"docs:serve": "vitepress serve docs",
|
|
14
|
+
"dev": "vite",
|
|
15
|
+
"build": "vite build",
|
|
16
|
+
"preview": "vite preview",
|
|
17
|
+
"storybook": "storybook dev -p 6006",
|
|
18
|
+
"build-storybook": "storybook build"
|
|
14
19
|
},
|
|
15
20
|
"files": [
|
|
16
21
|
"src"
|
|
@@ -22,45 +27,62 @@
|
|
|
22
27
|
"author": "Alphamonak Solutions",
|
|
23
28
|
"license": "MIT",
|
|
24
29
|
"dependencies": {
|
|
25
|
-
"@headlessui/vue": "^1.
|
|
30
|
+
"@headlessui/vue": "^1.7.14",
|
|
26
31
|
"@popperjs/core": "^2.11.2",
|
|
27
32
|
"@tailwindcss/forms": "^0.5.3",
|
|
28
33
|
"@tailwindcss/typography": "^0.5.0",
|
|
29
|
-
"@tiptap/extension-color": "^2.0.
|
|
30
|
-
"@tiptap/extension-highlight": "^2.0.
|
|
31
|
-
"@tiptap/extension-image": "^2.0.
|
|
32
|
-
"@tiptap/extension-link": "^2.0.
|
|
33
|
-
"@tiptap/extension-mention": "^2.0.
|
|
34
|
-
"@tiptap/extension-placeholder": "^2.0.
|
|
35
|
-
"@tiptap/extension-table": "^2.0.
|
|
36
|
-
"@tiptap/extension-table-cell": "^2.0.
|
|
37
|
-
"@tiptap/extension-table-header": "^2.0.
|
|
38
|
-
"@tiptap/extension-table-row": "^2.0.
|
|
39
|
-
"@tiptap/extension-text-align": "^2.0.
|
|
40
|
-
"@tiptap/extension-text-style": "^2.0.
|
|
41
|
-
"@tiptap/extension-typography": "^2.0.
|
|
42
|
-
"@tiptap/pm": "^2.0.
|
|
43
|
-
"@tiptap/
|
|
44
|
-
"@tiptap/
|
|
45
|
-
"@tiptap/
|
|
46
|
-
"@tiptap/vue-3": "^2.0.0-beta.205",
|
|
47
|
-
"autoprefixer": "^10.4.2",
|
|
34
|
+
"@tiptap/extension-color": "^2.0.3",
|
|
35
|
+
"@tiptap/extension-highlight": "^2.0.3",
|
|
36
|
+
"@tiptap/extension-image": "^2.0.3",
|
|
37
|
+
"@tiptap/extension-link": "^2.0.3",
|
|
38
|
+
"@tiptap/extension-mention": "^2.0.3",
|
|
39
|
+
"@tiptap/extension-placeholder": "^2.0.3",
|
|
40
|
+
"@tiptap/extension-table": "^2.0.3",
|
|
41
|
+
"@tiptap/extension-table-cell": "^2.0.3",
|
|
42
|
+
"@tiptap/extension-table-header": "^2.0.3",
|
|
43
|
+
"@tiptap/extension-table-row": "^2.0.3",
|
|
44
|
+
"@tiptap/extension-text-align": "^2.0.3",
|
|
45
|
+
"@tiptap/extension-text-style": "^2.0.3",
|
|
46
|
+
"@tiptap/extension-typography": "^2.0.3",
|
|
47
|
+
"@tiptap/pm": "^2.0.3",
|
|
48
|
+
"@tiptap/starter-kit": "^2.0.3",
|
|
49
|
+
"@tiptap/suggestion": "^2.0.3",
|
|
50
|
+
"@tiptap/vue-3": "^2.0.3",
|
|
48
51
|
"feather-icons": "^4.28.0",
|
|
49
52
|
"idb-keyval": "^6.2.0",
|
|
50
|
-
"postcss": "^8.4.5",
|
|
51
53
|
"showdown": "^2.1.0",
|
|
52
54
|
"socket.io-client": "^4.5.1",
|
|
53
|
-
"tailwindcss": "^3.0.12",
|
|
54
55
|
"tippy.js": "^6.3.7"
|
|
55
56
|
},
|
|
57
|
+
"peerDependencies": {
|
|
58
|
+
"vue": "^3.2.45",
|
|
59
|
+
"vue-router": "^4.1.6"
|
|
60
|
+
},
|
|
56
61
|
"devDependencies": {
|
|
62
|
+
"@storybook/addon-essentials": "^7.0.0-beta.61",
|
|
63
|
+
"@storybook/addon-interactions": "^7.0.0-beta.61",
|
|
64
|
+
"@storybook/addon-links": "^7.0.0-beta.61",
|
|
65
|
+
"@storybook/blocks": "^7.0.0-alpha.8",
|
|
66
|
+
"@storybook/testing-library": "^0.0.14-next.1",
|
|
67
|
+
"@storybook/vue3": "^7.0.0-beta.61",
|
|
68
|
+
"@storybook/vue3-vite": "^7.0.0-beta.61",
|
|
69
|
+
"@vitejs/plugin-vue": "^4.0.0",
|
|
70
|
+
"autoprefixer": "^10.4.13",
|
|
57
71
|
"cross-fetch": "^3.1.5",
|
|
58
72
|
"husky": "^8.0.3",
|
|
59
73
|
"lint-staged": ">=10",
|
|
74
|
+
"postcss": "^8.4.21",
|
|
60
75
|
"prettier": "2.7.1",
|
|
61
76
|
"prettier-plugin-tailwindcss": "^0.1.13",
|
|
77
|
+
"react": "^18.2.0",
|
|
78
|
+
"react-dom": "^18.2.0",
|
|
79
|
+
"storybook": "^7.0.0-beta.61",
|
|
80
|
+
"tailwindcss": "^3.2.7",
|
|
81
|
+
"typescript": "^5.0.2",
|
|
82
|
+
"vite": "^4.1.0",
|
|
62
83
|
"vitepress": "^1.0.0-alpha.29",
|
|
63
|
-
"vue": "^3.2.45"
|
|
84
|
+
"vue": "^3.2.45",
|
|
85
|
+
"vue-router": "^4.1.6"
|
|
64
86
|
},
|
|
65
87
|
"lint-staged": {
|
|
66
88
|
"*.{js,css,md,vue}": "prettier --write"
|
|
Binary file
|
package/src/components/Alert.vue
CHANGED
|
@@ -24,10 +24,10 @@
|
|
|
24
24
|
<h3 class="text-lg font-medium text-gray-900" v-if="title">
|
|
25
25
|
{{ title }}
|
|
26
26
|
</h3>
|
|
27
|
-
<div class="mt-1 md:
|
|
27
|
+
<div class="mt-1 md:ml-2 md:mt-0">
|
|
28
28
|
<slot></slot>
|
|
29
29
|
</div>
|
|
30
|
-
<div class="mt-3 md:
|
|
30
|
+
<div class="mt-3 md:ml-auto md:mt-0">
|
|
31
31
|
<slot name="actions"></slot>
|
|
32
32
|
</div>
|
|
33
33
|
</div>
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<Combobox v-model="selectedValue" nullable v-slot="{ open: isComboboxOpen }">
|
|
3
|
-
<Popover class="w-full">
|
|
4
|
-
<template #target="{ open: openPopover }">
|
|
3
|
+
<Popover class="w-full" v-model:show="showOptions">
|
|
4
|
+
<template #target="{ open: openPopover, togglePopover }">
|
|
5
5
|
<div class="w-full">
|
|
6
|
-
<
|
|
7
|
-
class="flex w-full items-center justify-between rounded
|
|
8
|
-
:class="{ '
|
|
9
|
-
@click="() =>
|
|
6
|
+
<button
|
|
7
|
+
class="flex h-7 w-full items-center justify-between rounded bg-gray-100 py-1 pl-3 pr-2 transition-colors hover:bg-gray-200 focus:ring-2 focus:ring-gray-400"
|
|
8
|
+
:class="{ 'bg-gray-200': isComboboxOpen }"
|
|
9
|
+
@click="() => togglePopover()"
|
|
10
10
|
>
|
|
11
11
|
<span
|
|
12
|
-
class="overflow-hidden text-ellipsis text-base leading-5"
|
|
12
|
+
class="overflow-hidden text-ellipsis whitespace-nowrap text-base leading-5"
|
|
13
13
|
v-if="selectedValue"
|
|
14
14
|
>
|
|
15
15
|
{{ displayValue(selectedValue) }}
|
|
@@ -22,67 +22,77 @@
|
|
|
22
22
|
class="h-4 w-4 text-gray-500"
|
|
23
23
|
aria-hidden="true"
|
|
24
24
|
/>
|
|
25
|
-
</
|
|
25
|
+
</button>
|
|
26
26
|
</div>
|
|
27
27
|
</template>
|
|
28
|
-
<template #body>
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
>
|
|
34
|
-
<div
|
|
35
|
-
class="items-st sticky top-0 mb-1.5 flex items-stretch space-x-1.5 bg-white pt-1.5"
|
|
36
|
-
>
|
|
37
|
-
<ComboboxInput
|
|
38
|
-
class="form-input w-full placeholder-gray-500"
|
|
39
|
-
type="text"
|
|
40
|
-
@change="
|
|
41
|
-
(e) => {
|
|
42
|
-
query = e.target.value
|
|
43
|
-
}
|
|
44
|
-
"
|
|
45
|
-
:value="query"
|
|
46
|
-
autocomplete="off"
|
|
47
|
-
placeholder="Search by keyword"
|
|
48
|
-
/>
|
|
49
|
-
<Button icon="x" @click="selectedValue = null" />
|
|
50
|
-
</div>
|
|
51
|
-
<div
|
|
52
|
-
v-for="group in groups"
|
|
53
|
-
:key="group.key"
|
|
54
|
-
v-show="group.items.length > 0"
|
|
28
|
+
<template #body="{ isOpen }">
|
|
29
|
+
<div v-show="isOpen">
|
|
30
|
+
<ComboboxOptions
|
|
31
|
+
class="mt-1 max-h-[15rem] overflow-y-auto rounded-lg bg-white px-1.5 pb-1.5 shadow-2xl"
|
|
32
|
+
static
|
|
55
33
|
>
|
|
56
34
|
<div
|
|
57
|
-
|
|
58
|
-
class="px-2 py-1 text-xs font-semibold uppercase tracking-wider text-gray-500"
|
|
35
|
+
class="sticky top-0 z-10 flex items-stretch space-x-1.5 bg-white pt-1.5"
|
|
59
36
|
>
|
|
60
|
-
|
|
37
|
+
<div class="relative w-full">
|
|
38
|
+
<ComboboxInput
|
|
39
|
+
class="form-input w-full"
|
|
40
|
+
type="text"
|
|
41
|
+
@change="
|
|
42
|
+
(e) => {
|
|
43
|
+
query = e.target.value
|
|
44
|
+
}
|
|
45
|
+
"
|
|
46
|
+
:value="query"
|
|
47
|
+
autocomplete="off"
|
|
48
|
+
placeholder="Search"
|
|
49
|
+
/>
|
|
50
|
+
<button
|
|
51
|
+
class="absolute right-0 inline-flex h-7 w-7 items-center justify-center"
|
|
52
|
+
@click="selectedValue = null"
|
|
53
|
+
>
|
|
54
|
+
<FeatherIcon name="x" class="w-4" />
|
|
55
|
+
</button>
|
|
56
|
+
</div>
|
|
61
57
|
</div>
|
|
62
|
-
<
|
|
63
|
-
|
|
64
|
-
v-for="
|
|
65
|
-
:key="
|
|
66
|
-
|
|
67
|
-
v-slot="{ active, selected }"
|
|
58
|
+
<div
|
|
59
|
+
class="mt-1.5"
|
|
60
|
+
v-for="group in groups"
|
|
61
|
+
:key="group.key"
|
|
62
|
+
v-show="group.items.length > 0"
|
|
68
63
|
>
|
|
69
|
-
<
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
{ 'bg-gray-100': active },
|
|
73
|
-
]"
|
|
64
|
+
<div
|
|
65
|
+
v-if="group.group && !group.hideLabel"
|
|
66
|
+
class="px-2.5 py-1.5 text-sm font-medium text-gray-500"
|
|
74
67
|
>
|
|
75
|
-
{{
|
|
76
|
-
</
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
68
|
+
{{ group.group }}
|
|
69
|
+
</div>
|
|
70
|
+
<ComboboxOption
|
|
71
|
+
as="template"
|
|
72
|
+
v-for="option in group.items"
|
|
73
|
+
:key="option.value"
|
|
74
|
+
:value="option"
|
|
75
|
+
v-slot="{ active, selected }"
|
|
76
|
+
>
|
|
77
|
+
<li
|
|
78
|
+
:class="[
|
|
79
|
+
'flex items-center rounded px-2.5 py-1.5 text-base',
|
|
80
|
+
{ 'bg-gray-100': active },
|
|
81
|
+
]"
|
|
82
|
+
>
|
|
83
|
+
<slot name="prefix" v-bind="{ active, selected, option }" />
|
|
84
|
+
{{ option.label }}
|
|
85
|
+
</li>
|
|
86
|
+
</ComboboxOption>
|
|
87
|
+
</div>
|
|
88
|
+
<li
|
|
89
|
+
v-if="groups.length == 0"
|
|
90
|
+
class="rounded-md px-2.5 py-1.5 text-base text-gray-600"
|
|
91
|
+
>
|
|
92
|
+
No results found
|
|
93
|
+
</li>
|
|
94
|
+
</ComboboxOptions>
|
|
95
|
+
</div>
|
|
86
96
|
</template>
|
|
87
97
|
</Popover>
|
|
88
98
|
</Combobox>
|
|
@@ -102,7 +112,7 @@ import FeatherIcon from './FeatherIcon.vue'
|
|
|
102
112
|
export default {
|
|
103
113
|
name: 'Autocomplete',
|
|
104
114
|
props: ['modelValue', 'options', 'placeholder'],
|
|
105
|
-
emits: ['update:modelValue', 'change'],
|
|
115
|
+
emits: ['update:modelValue', 'update:query', 'change'],
|
|
106
116
|
components: {
|
|
107
117
|
Popover,
|
|
108
118
|
Button,
|
|
@@ -116,6 +126,7 @@ export default {
|
|
|
116
126
|
data() {
|
|
117
127
|
return {
|
|
118
128
|
query: '',
|
|
129
|
+
showOptions: false,
|
|
119
130
|
}
|
|
120
131
|
},
|
|
121
132
|
computed: {
|
|
@@ -128,6 +139,9 @@ export default {
|
|
|
128
139
|
},
|
|
129
140
|
set(val) {
|
|
130
141
|
this.query = ''
|
|
142
|
+
if (val) {
|
|
143
|
+
this.showOptions = false
|
|
144
|
+
}
|
|
131
145
|
this.$emit(this.valuePropPassed ? 'change' : 'update:modelValue', val)
|
|
132
146
|
},
|
|
133
147
|
},
|
|
@@ -150,6 +164,11 @@ export default {
|
|
|
150
164
|
.filter((group) => group.items.length > 0)
|
|
151
165
|
},
|
|
152
166
|
},
|
|
167
|
+
watch: {
|
|
168
|
+
query(q) {
|
|
169
|
+
this.$emit('update:query', q)
|
|
170
|
+
},
|
|
171
|
+
},
|
|
153
172
|
methods: {
|
|
154
173
|
filterOptions(options) {
|
|
155
174
|
if (!this.query) {
|
|
@@ -167,7 +186,9 @@ export default {
|
|
|
167
186
|
},
|
|
168
187
|
displayValue(option) {
|
|
169
188
|
if (typeof option === 'string') {
|
|
170
|
-
|
|
189
|
+
let allOptions = this.groups.flatMap((group) => group.items)
|
|
190
|
+
let selectedOption = allOptions.find((o) => o.value === option)
|
|
191
|
+
return selectedOption?.label || option
|
|
171
192
|
}
|
|
172
193
|
return option?.label
|
|
173
194
|
},
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { Avatar } from '../index'
|
|
2
|
+
|
|
3
|
+
const IconOnline = {
|
|
4
|
+
template: `<svg xmlns="http://www.w3.org/2000/svg" class="h-full w-full text-green-500" viewBox="0 0 20 20" fill="currentColor"><circle cx="10" cy="10" r="10"/></svg>`,
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const IconOffline = {
|
|
8
|
+
template: `<svg xmlns="http://www.w3.org/2000/svg" class="h-full w-full text-gray-500" viewBox="0 0 20 20" fill="currentColor"><circle cx="10" cy="10" r="10"/></svg>`,
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const IconSleep = {
|
|
12
|
+
template: `<svg class="h-full w-full" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
13
|
+
<rect width="18" height="18" rx="9" fill="white"/>
|
|
14
|
+
<path d="M16.9819 9.71993C16.9899 9.63114 16.8851 9.57883 16.8161 9.63536C15.7802 10.4848 14.4551 10.9946 13.0109 10.9946C9.69415 10.9946 7.00543 8.30585 7.00543 4.98914C7.00543 3.54495 7.51521 2.21982 8.36464 1.18388C8.42117 1.11495 8.36886 1.0101 8.28008 1.01809C4.19856 1.3855 1 4.8156 1 8.99276C1 13.415 4.58496 17 9.00724 17C13.1844 17 16.6145 13.8014 16.9819 9.71993Z" fill="#7C7C7C"/>
|
|
15
|
+
</svg>
|
|
16
|
+
`,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const IconUser = {
|
|
20
|
+
template: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
|
|
21
|
+
<path fill-rule="evenodd" d="M7.5 6a4.5 4.5 0 119 0 4.5 4.5 0 01-9 0zM3.751 20.105a8.25 8.25 0 0116.498 0 .75.75 0 01-.437.695A18.683 18.683 0 0112 22.5c-2.786 0-5.433-.608-7.812-1.7a.75.75 0 01-.437-.695z" clip-rule="evenodd" />
|
|
22
|
+
</svg>`,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default {
|
|
26
|
+
component: Avatar,
|
|
27
|
+
tags: ['autodocs'],
|
|
28
|
+
render: function (args, { argTypes }) {
|
|
29
|
+
return {
|
|
30
|
+
props: Object.keys(argTypes),
|
|
31
|
+
components: { Avatar },
|
|
32
|
+
template: `<Avatar v-bind="$props">
|
|
33
|
+
<template v-if="$props.default" #default>
|
|
34
|
+
<component :is="$props.default" />
|
|
35
|
+
</template>
|
|
36
|
+
<template v-if="$props.indicator" #indicator>
|
|
37
|
+
<component :is="$props.indicator" />
|
|
38
|
+
</template>
|
|
39
|
+
</Avatar>`,
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
argTypes: {
|
|
43
|
+
size: {
|
|
44
|
+
options: ['xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl'],
|
|
45
|
+
control: { type: 'inline-radio' },
|
|
46
|
+
},
|
|
47
|
+
shape: {
|
|
48
|
+
options: ['circle', 'square'],
|
|
49
|
+
control: { type: 'inline-radio' },
|
|
50
|
+
},
|
|
51
|
+
indicator: {
|
|
52
|
+
options: ['online', 'offline', 'sleep'],
|
|
53
|
+
mapping: {
|
|
54
|
+
online: IconOnline,
|
|
55
|
+
offline: IconOffline,
|
|
56
|
+
sleep: IconSleep,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
default: {
|
|
60
|
+
options: ['user', 'none'],
|
|
61
|
+
mapping: {
|
|
62
|
+
none: null,
|
|
63
|
+
user: IconUser,
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
args: {
|
|
68
|
+
size: '3xl',
|
|
69
|
+
shape: 'circle',
|
|
70
|
+
},
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export const Normal = {
|
|
74
|
+
args: {
|
|
75
|
+
image: 'https://randomuser.me/api/portraits/women/1.jpg',
|
|
76
|
+
},
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export const SizeSmall = {
|
|
80
|
+
args: {
|
|
81
|
+
size: 'sm',
|
|
82
|
+
image: 'https://randomuser.me/api/portraits/women/2.jpg',
|
|
83
|
+
},
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export const Label = {
|
|
87
|
+
args: {
|
|
88
|
+
label: 'A',
|
|
89
|
+
},
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export const RoundedSquare = {
|
|
93
|
+
args: {
|
|
94
|
+
shape: 'square',
|
|
95
|
+
image: 'https://randomuser.me/api/portraits/women/3.jpg',
|
|
96
|
+
},
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export const WithIndicator = {
|
|
100
|
+
args: {
|
|
101
|
+
indicator: 'online',
|
|
102
|
+
image: 'https://randomuser.me/api/portraits/women/4.jpg',
|
|
103
|
+
},
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export const IconViaDefaultSlot = {
|
|
107
|
+
args: {
|
|
108
|
+
default: 'user',
|
|
109
|
+
},
|
|
110
|
+
}
|
|
@@ -1,62 +1,127 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div
|
|
3
|
+
class="relative inline-block shrink-0"
|
|
4
|
+
:class="[sizeClasses, shapeClasses]"
|
|
5
|
+
>
|
|
3
6
|
<img
|
|
4
|
-
v-if="
|
|
5
|
-
:src="
|
|
6
|
-
class="object-cover"
|
|
7
|
-
:class="styleClasses"
|
|
8
|
-
loading="lazy"
|
|
7
|
+
v-if="image"
|
|
8
|
+
:src="image"
|
|
9
|
+
:class="[shapeClasses, 'h-full w-full object-cover']"
|
|
9
10
|
/>
|
|
10
11
|
<div
|
|
11
12
|
v-else
|
|
12
|
-
class="flex h-full w-full items-center justify-center bg-gray-
|
|
13
|
-
:class="
|
|
13
|
+
class="flex h-full w-full items-center justify-center bg-gray-100 uppercase text-gray-600"
|
|
14
|
+
:class="[labelClasses, shapeClasses]"
|
|
14
15
|
>
|
|
15
|
-
|
|
16
|
+
<div :class="iconClasses" v-if="$slots.default">
|
|
17
|
+
<slot></slot>
|
|
18
|
+
</div>
|
|
19
|
+
<template v-else>
|
|
20
|
+
{{ label && label[0] }}
|
|
21
|
+
</template>
|
|
22
|
+
</div>
|
|
23
|
+
<div
|
|
24
|
+
v-if="$slots.indicator"
|
|
25
|
+
:class="[
|
|
26
|
+
'absolute bottom-0 right-0 grid place-items-center rounded-full bg-white',
|
|
27
|
+
indicatorContainerClasses,
|
|
28
|
+
]"
|
|
29
|
+
>
|
|
30
|
+
<div :class="indicatorClasses">
|
|
31
|
+
<slot name="indicator"></slot>
|
|
32
|
+
</div>
|
|
16
33
|
</div>
|
|
17
34
|
</div>
|
|
18
35
|
</template>
|
|
19
36
|
|
|
20
|
-
<script>
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
size: {
|
|
29
|
-
default: 'md',
|
|
30
|
-
},
|
|
31
|
-
shape: {
|
|
32
|
-
default: 'circle',
|
|
33
|
-
validator(value) {
|
|
34
|
-
const valid = validShapes.includes(value)
|
|
35
|
-
if (!valid) {
|
|
36
|
-
console.warn(
|
|
37
|
-
`shape property for <Avatar /> must be one of `,
|
|
38
|
-
validShapes
|
|
39
|
-
)
|
|
40
|
-
}
|
|
41
|
-
return valid
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
computed: {
|
|
46
|
-
styleClasses() {
|
|
47
|
-
const sizeClasses = {
|
|
48
|
-
sm: 'w-5 h-5',
|
|
49
|
-
md: 'w-8 h-8',
|
|
50
|
-
lg: 'w-12 h-12',
|
|
51
|
-
}[this.size]
|
|
52
|
-
|
|
53
|
-
const shapeClass = {
|
|
54
|
-
circle: 'rounded-full',
|
|
55
|
-
square: 'rounded-lg',
|
|
56
|
-
}[this.shape]
|
|
57
|
-
|
|
58
|
-
return `${shapeClass} ${sizeClasses}`
|
|
59
|
-
},
|
|
60
|
-
},
|
|
37
|
+
<script setup lang="ts">
|
|
38
|
+
import { computed } from 'vue'
|
|
39
|
+
|
|
40
|
+
interface AvatarProps {
|
|
41
|
+
image?: string
|
|
42
|
+
label?: string
|
|
43
|
+
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl'
|
|
44
|
+
shape?: 'circle' | 'square'
|
|
61
45
|
}
|
|
46
|
+
|
|
47
|
+
const props = withDefaults(defineProps<AvatarProps>(), {
|
|
48
|
+
size: 'md',
|
|
49
|
+
shape: 'circle',
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
const shapeClasses = computed(() => {
|
|
53
|
+
return {
|
|
54
|
+
circle: 'rounded-full',
|
|
55
|
+
square: {
|
|
56
|
+
xs: 'rounded-[4px]',
|
|
57
|
+
sm: 'rounded-[5px]',
|
|
58
|
+
md: 'rounded-[5px]',
|
|
59
|
+
lg: 'rounded-[6px]',
|
|
60
|
+
xl: 'rounded-[6px]',
|
|
61
|
+
'2xl': 'rounded-[8px]',
|
|
62
|
+
'3xl': 'rounded-[10px]',
|
|
63
|
+
}[props.size],
|
|
64
|
+
}[props.shape]
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
const sizeClasses = computed(() => {
|
|
68
|
+
return {
|
|
69
|
+
xs: 'w-4 h-4',
|
|
70
|
+
sm: 'w-5 h-5',
|
|
71
|
+
md: 'w-6 h-6',
|
|
72
|
+
lg: 'w-7 h-7',
|
|
73
|
+
xl: 'w-8 h-8',
|
|
74
|
+
'2xl': 'w-10 h-10',
|
|
75
|
+
'3xl': 'w-11.5 h-11.5',
|
|
76
|
+
}[props.size]
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
const labelClasses = computed(() => {
|
|
80
|
+
let sizeClass = {
|
|
81
|
+
xs: 'text-2xs',
|
|
82
|
+
sm: 'text-sm',
|
|
83
|
+
md: 'text-base',
|
|
84
|
+
lg: 'text-base',
|
|
85
|
+
xl: 'text-lg',
|
|
86
|
+
'2xl': 'text-xl',
|
|
87
|
+
'3xl': 'text-2xl',
|
|
88
|
+
}[props.size]
|
|
89
|
+
return ['font-medium', sizeClass]
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
const indicatorContainerClasses = computed(() => {
|
|
93
|
+
return {
|
|
94
|
+
xs: '-mr-[.1rem] -mb-[.1rem] h-2 w-2',
|
|
95
|
+
sm: '-mr-[.1rem] -mb-[.1rem] h-[9px] w-[9px]',
|
|
96
|
+
md: '-mr-[.1rem] -mb-[.1rem] h-2.5 w-2.5',
|
|
97
|
+
lg: '-mr-[.1rem] -mb-[.1rem] h-3 w-3',
|
|
98
|
+
xl: '-mr-[.1rem] -mb-[.1rem] h-3 w-3',
|
|
99
|
+
'2xl': '-mr-[.1rem] -mb-[.1rem] h-3.5 w-3.5',
|
|
100
|
+
'3xl': '-mr-[.2rem] -mb-[.2rem] h-4 w-4',
|
|
101
|
+
}[props.size]
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
const indicatorClasses = computed(() => {
|
|
105
|
+
return {
|
|
106
|
+
xs: 'h-1 w-1',
|
|
107
|
+
sm: 'h-[5px] w-[5px]',
|
|
108
|
+
md: 'h-1.5 w-1.5',
|
|
109
|
+
lg: 'h-2 w-2',
|
|
110
|
+
xl: 'h-2 w-2',
|
|
111
|
+
'2xl': 'h-2.5 w-2.5',
|
|
112
|
+
'3xl': 'h-3 w-3',
|
|
113
|
+
}[props.size]
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
const iconClasses = computed(() => {
|
|
117
|
+
return {
|
|
118
|
+
xs: 'h-2.5 w-2.5',
|
|
119
|
+
sm: 'h-3 w-3',
|
|
120
|
+
md: 'h-4 w-4',
|
|
121
|
+
lg: 'h-4 w-4',
|
|
122
|
+
xl: 'h-4 w-4',
|
|
123
|
+
'2xl': 'h-5 w-5',
|
|
124
|
+
'3xl': 'h-5 w-5',
|
|
125
|
+
}[props.size]
|
|
126
|
+
})
|
|
62
127
|
</script>
|