pimelon-ui 0.0.19 → 0.0.73

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 (75) hide show
  1. package/package.json +30 -8
  2. package/src/components/Alert.vue +3 -3
  3. package/src/components/Autocomplete.vue +176 -0
  4. package/src/components/Avatar.vue +3 -2
  5. package/src/components/Badge.vue +35 -20
  6. package/src/components/Button.vue +26 -11
  7. package/src/components/Card.vue +4 -4
  8. package/src/components/DatePicker.vue +247 -0
  9. package/src/components/Dialog.vue +14 -17
  10. package/src/components/Dropdown.vue +22 -17
  11. package/src/components/ErrorMessage.vue +11 -2
  12. package/src/components/FeatherIcon.vue +8 -4
  13. package/src/components/Input.vue +101 -57
  14. package/src/components/Link.vue +1 -1
  15. package/src/components/LoadingText.vue +1 -1
  16. package/src/components/Modal.vue +1 -1
  17. package/src/components/Popover.vue +124 -81
  18. package/src/components/SuccessMessage.vue +1 -1
  19. package/src/components/TextEditor/InsertImage.vue +72 -0
  20. package/src/components/TextEditor/MentionList.vue +95 -0
  21. package/src/components/TextEditor/Menu.vue +115 -9
  22. package/src/components/TextEditor/TextEditor.vue +174 -138
  23. package/src/components/TextEditor/TextEditorBubbleMenu.vue +68 -0
  24. package/src/components/TextEditor/TextEditorFixedMenu.vue +70 -0
  25. package/src/components/TextEditor/TextEditorFloatingMenu.vue +55 -0
  26. package/src/components/TextEditor/commands.js +185 -10
  27. package/src/components/TextEditor/icons/align-center.vue +14 -0
  28. package/src/components/TextEditor/icons/align-justify.vue +14 -0
  29. package/src/components/TextEditor/icons/align-left.vue +14 -0
  30. package/src/components/TextEditor/icons/align-right.vue +14 -0
  31. package/src/components/TextEditor/icons/arrow-go-back-line.vue +14 -0
  32. package/src/components/TextEditor/icons/arrow-go-forward-line.vue +14 -0
  33. package/src/components/TextEditor/icons/bold.vue +14 -0
  34. package/src/components/TextEditor/icons/code-view.vue +14 -0
  35. package/src/components/TextEditor/icons/double-quotes-r.vue +14 -0
  36. package/src/components/TextEditor/icons/font-color.vue +14 -0
  37. package/src/components/TextEditor/icons/format-clear.vue +14 -0
  38. package/src/components/TextEditor/icons/h-1.vue +14 -0
  39. package/src/components/TextEditor/icons/h-2.vue +14 -0
  40. package/src/components/TextEditor/icons/h-3.vue +14 -0
  41. package/src/components/TextEditor/icons/h-4.vue +14 -0
  42. package/src/components/TextEditor/icons/h-5.vue +14 -0
  43. package/src/components/TextEditor/icons/h-6.vue +14 -0
  44. package/src/components/TextEditor/icons/image-add-line.vue +14 -0
  45. package/src/components/TextEditor/icons/italic.vue +14 -0
  46. package/src/components/TextEditor/icons/link.vue +14 -0
  47. package/src/components/TextEditor/icons/list-ordered.vue +14 -0
  48. package/src/components/TextEditor/icons/list-unordered.vue +14 -0
  49. package/src/components/TextEditor/icons/readme.md +1 -0
  50. package/src/components/TextEditor/icons/separator.vue +14 -0
  51. package/src/components/TextEditor/icons/strikethrough.vue +14 -0
  52. package/src/components/TextEditor/icons/table-2.vue +14 -0
  53. package/src/components/TextEditor/icons/text.vue +11 -0
  54. package/src/components/TextEditor/icons/underline.vue +14 -0
  55. package/src/components/TextEditor/image-extension.js +152 -0
  56. package/src/components/TextEditor/mention.js +72 -0
  57. package/src/components/TextEditor/utils.js +11 -0
  58. package/src/components/Toast.vue +26 -20
  59. package/src/components/Tooltip.vue +35 -0
  60. package/src/directives/onOutsideClick.js +17 -11
  61. package/src/directives/visibility.js +24 -0
  62. package/src/index.js +10 -0
  63. package/src/resources/documentResource.js +192 -0
  64. package/src/resources/index.js +3 -0
  65. package/src/resources/listResource.js +306 -0
  66. package/src/resources/local.js +10 -0
  67. package/src/resources/plugin.js +111 -0
  68. package/src/resources/resources.js +192 -0
  69. package/src/style.css +2 -2
  70. package/src/utils/file-to-base64.js +9 -0
  71. package/src/utils/pageMeta.js +50 -0
  72. package/src/utils/plugin.js +4 -4
  73. package/src/utils/socketio.js +10 -8
  74. package/src/utils/vite-dev-server.js +1 -1
  75. package/src/utils/resources.js +0 -510
package/package.json CHANGED
@@ -1,11 +1,13 @@
1
1
  {
2
2
  "name": "pimelon-ui",
3
- "version": "0.0.19",
3
+ "version": "0.0.73",
4
4
  "description": "A set of components and utilities for rapid UI development",
5
5
  "main": "./src/index.js",
6
6
  "scripts": {
7
7
  "test": "npx prettier --check ./src",
8
- "prettier": "npx prettier -w ./src"
8
+ "prettier": "npx prettier -w ./src",
9
+ "prepare": "husky install",
10
+ "bump-and-release": "git pull --rebase origin main && yarn version --patch && git push && git push --tags"
9
11
  },
10
12
  "files": [
11
13
  "src"
@@ -15,19 +17,39 @@
15
17
  "url": "https://github.com/amonak/pimelon-ui.git"
16
18
  },
17
19
  "author": "Alphamonak Solutions",
20
+ "license": "MIT",
18
21
  "dependencies": {
19
22
  "@headlessui/vue": "^1.5.0",
20
23
  "@popperjs/core": "^2.11.2",
21
24
  "@tailwindcss/forms": "^0.4.0",
22
25
  "@tailwindcss/typography": "^0.5.0",
23
- "@tiptap/extension-image": "^2.0.0-beta.27",
24
- "@tiptap/extension-placeholder": "^2.0.0-beta.48",
25
- "@tiptap/starter-kit": "^2.0.0-beta.183",
26
- "@tiptap/vue-3": "^2.0.0-beta.90",
26
+ "@tiptap/extension-image": "^2.0.0-beta.30",
27
+ "@tiptap/extension-link": "^2.0.0-beta.43",
28
+ "@tiptap/extension-mention": "^2.0.0-beta.102",
29
+ "@tiptap/extension-placeholder": "^2.0.0-beta.53",
30
+ "@tiptap/extension-table": "^2.0.0-beta.54",
31
+ "@tiptap/extension-table-cell": "^2.0.0-beta.23",
32
+ "@tiptap/extension-table-header": "^2.0.0-beta.25",
33
+ "@tiptap/extension-table-row": "^2.0.0-beta.22",
34
+ "@tiptap/extension-text-align": "^2.0.0-beta.31",
35
+ "@tiptap/starter-kit": "^2.0.0-beta.191",
36
+ "@tiptap/suggestion": "^2.0.0-beta.195",
37
+ "@tiptap/vue-3": "^2.0.0-beta.96",
27
38
  "autoprefixer": "^10.4.2",
28
39
  "feather-icons": "^4.28.0",
40
+ "idb-keyval": "^6.2.0",
29
41
  "postcss": "^8.4.5",
30
- "socket.io-client": "^2.4.0",
31
- "tailwindcss": "^3.0.12"
42
+ "socket.io-client": "^4.5.1",
43
+ "tailwindcss": "^3.0.12",
44
+ "tippy.js": "^6.3.7"
45
+ },
46
+ "devDependencies": {
47
+ "husky": "^8.0.3",
48
+ "lint-staged": ">=10",
49
+ "prettier": "2.7.1",
50
+ "prettier-plugin-tailwindcss": "^0.1.13"
51
+ },
52
+ "lint-staged": {
53
+ "*.{js,css,md,vue}": "prettier --write"
32
54
  }
33
55
  }
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <div class="block w-full">
3
3
  <div
4
- class="items-start px-4 md:px-5 py-3.5 text-base rounded-md flex"
4
+ class="flex items-start rounded-md px-4 py-3.5 text-base md:px-5"
5
5
  :class="classes"
6
6
  >
7
7
  <svg
@@ -19,8 +19,8 @@
19
19
  fill="#318AD8"
20
20
  />
21
21
  </svg>
22
- <div class="w-full ml-2">
23
- <div class="flex flex-col md:items-baseline md:flex-row">
22
+ <div class="ml-2 w-full">
23
+ <div class="flex flex-col md:flex-row md:items-baseline">
24
24
  <h3 class="text-lg font-medium text-gray-900" v-if="title">
25
25
  {{ title }}
26
26
  </h3>
@@ -0,0 +1,176 @@
1
+ <template>
2
+ <Combobox v-model="selectedValue" nullable v-slot="{ open: isComboboxOpen }">
3
+ <Popover class="w-full">
4
+ <template #target="{ open: openPopover }">
5
+ <div class="w-full">
6
+ <ComboboxButton
7
+ class="flex w-full items-center justify-between rounded-md bg-gray-100 py-1.5 pl-3 pr-2"
8
+ :class="{ 'rounded-b-none': isComboboxOpen }"
9
+ @click="
10
+ () => {
11
+ openPopover()
12
+ }
13
+ "
14
+ >
15
+ <span
16
+ class="overflow-hidden text-ellipsis text-base"
17
+ v-if="selectedValue"
18
+ >
19
+ {{ displayValue(selectedValue) }}
20
+ </span>
21
+ <span class="text-base text-gray-500" v-else>
22
+ {{ placeholder || '' }}
23
+ </span>
24
+ <FeatherIcon
25
+ name="chevron-down"
26
+ class="h-4 w-4 text-gray-500"
27
+ aria-hidden="true"
28
+ />
29
+ </ComboboxButton>
30
+ </div>
31
+ </template>
32
+ <template #body>
33
+ <ComboboxOptions
34
+ class="max-h-[15rem] overflow-y-auto rounded-md rounded-t-none bg-white px-1.5 pb-1.5 shadow-md"
35
+ static
36
+ v-show="isComboboxOpen"
37
+ >
38
+ <div
39
+ class="items-st sticky top-0 mb-1.5 flex items-stretch space-x-1.5 bg-white pt-1.5"
40
+ >
41
+ <ComboboxInput
42
+ class="form-input w-full placeholder-gray-500"
43
+ type="text"
44
+ @change="
45
+ (e) => {
46
+ query = e.target.value
47
+ }
48
+ "
49
+ :value="query"
50
+ autocomplete="off"
51
+ placeholder="Search by keyword"
52
+ />
53
+ <Button icon="x" @click="selectedValue = null" />
54
+ </div>
55
+ <div
56
+ v-for="group in groups"
57
+ :key="group.key"
58
+ v-show="group.items.length > 0"
59
+ >
60
+ <div
61
+ v-if="group.group && !group.hideLabel"
62
+ class="px-2 py-1 text-xs font-semibold uppercase tracking-wider text-gray-500"
63
+ >
64
+ {{ group.group }}
65
+ </div>
66
+ <ComboboxOption
67
+ as="template"
68
+ v-for="option in group.items"
69
+ :key="option.value"
70
+ :value="option"
71
+ v-slot="{ active, selected }"
72
+ >
73
+ <li
74
+ :class="[
75
+ 'rounded-md px-2.5 py-1.5 text-base',
76
+ { 'bg-gray-100': active },
77
+ ]"
78
+ >
79
+ {{ option.label }}
80
+ </li>
81
+ </ComboboxOption>
82
+ </div>
83
+ <li
84
+ v-if="groups.length == 0"
85
+ class="rounded-md px-2.5 py-1.5 text-base text-gray-600"
86
+ >
87
+ No results found
88
+ </li>
89
+ </ComboboxOptions>
90
+ </template>
91
+ </Popover>
92
+ </Combobox>
93
+ </template>
94
+ <script>
95
+ import {
96
+ Combobox,
97
+ ComboboxInput,
98
+ ComboboxOptions,
99
+ ComboboxOption,
100
+ ComboboxButton,
101
+ } from '@headlessui/vue'
102
+ import Popover from './Popover.vue'
103
+
104
+ export default {
105
+ name: 'Autocomplete',
106
+ props: ['modelValue', 'options', 'placeholder'],
107
+ emits: ['update:modelValue', 'change'],
108
+ components: {
109
+ Popover,
110
+ Combobox,
111
+ ComboboxInput,
112
+ ComboboxOptions,
113
+ ComboboxOption,
114
+ ComboboxButton,
115
+ },
116
+ data() {
117
+ return {
118
+ query: '',
119
+ }
120
+ },
121
+ computed: {
122
+ valuePropPassed() {
123
+ return 'value' in this.$attrs
124
+ },
125
+ selectedValue: {
126
+ get() {
127
+ return this.valuePropPassed ? this.$attrs.value : this.modelValue
128
+ },
129
+ set(val) {
130
+ this.query = ''
131
+ this.$emit(this.valuePropPassed ? 'change' : 'update:modelValue', val)
132
+ },
133
+ },
134
+ groups() {
135
+ if (!this.options || this.options.length == 0) return []
136
+
137
+ let groups = this.options[0]?.group
138
+ ? this.options
139
+ : [{ group: '', items: this.options }]
140
+
141
+ return groups
142
+ .map((group, i) => {
143
+ return {
144
+ key: i,
145
+ group: group.group,
146
+ hideLabel: group.hideLabel || false,
147
+ items: this.filterOptions(group.items),
148
+ }
149
+ })
150
+ .filter((group) => group.items.length > 0)
151
+ },
152
+ },
153
+ methods: {
154
+ filterOptions(options) {
155
+ if (!this.query) {
156
+ return options
157
+ }
158
+ return options.filter((option) => {
159
+ let searchTexts = [option.label, option.value]
160
+ return searchTexts.some((text) =>
161
+ (text || '')
162
+ .toString()
163
+ .toLowerCase()
164
+ .includes(this.query.toLowerCase())
165
+ )
166
+ })
167
+ },
168
+ displayValue(option) {
169
+ if (typeof option === 'string') {
170
+ return option
171
+ }
172
+ return option?.label
173
+ },
174
+ },
175
+ }
176
+ </script>
@@ -1,14 +1,15 @@
1
1
  <template>
2
- <div class="overflow-hidden" :class="styleClasses">
2
+ <div class="shrink-0 overflow-hidden" :class="styleClasses">
3
3
  <img
4
4
  v-if="imageURL"
5
5
  :src="imageURL"
6
6
  class="object-cover"
7
7
  :class="styleClasses"
8
+ loading="lazy"
8
9
  />
9
10
  <div
10
11
  v-else
11
- class="flex items-center justify-center w-full h-full text-gray-600 uppercase bg-gray-200"
12
+ class="flex h-full w-full items-center justify-center bg-gray-200 uppercase text-gray-600"
12
13
  :class="{ sm: 'text-xs', md: 'text-base', lg: 'text-lg' }[size]"
13
14
  >
14
15
  {{ label && label[0] }}
@@ -1,39 +1,54 @@
1
1
  <template>
2
2
  <span
3
- class="inline-block px-3 py-1 text-xs font-medium rounded-md cursor-default"
3
+ class="inline-block cursor-default rounded-md px-3 py-1 text-xs font-medium"
4
4
  :class="classes"
5
5
  >
6
6
  <slot>{{ status }}</slot>
7
7
  </span>
8
8
  </template>
9
9
  <script>
10
+ const DEFAULT_COLOR_MAP = {
11
+ Pending: 'yellow',
12
+ Running: 'yellow',
13
+ Success: 'green',
14
+ Failure: 'red',
15
+ Active: 'green',
16
+ Broken: 'red',
17
+ Updating: 'blue',
18
+ Rejected: 'red',
19
+ Published: 'green',
20
+ Approved: 'green',
21
+ }
22
+
10
23
  export default {
11
24
  name: 'Badge',
12
- props: ['color', 'status'],
25
+ props: ['color', 'status', 'colorMap'],
13
26
  computed: {
14
27
  classes() {
15
- let color = this.color
16
- if (!color && this.status) {
17
- color = {
18
- Pending: 'yellow',
19
- Running: 'yellow',
20
- Success: 'green',
21
- Failure: 'red',
22
- Active: 'green',
23
- Broken: 'red',
24
- Updating: 'blue',
25
- Rejected: 'red',
26
- Published: 'green',
27
- Approved: 'green',
28
- }[this.status]
29
- }
30
- return {
31
- gray: 'text-gray-700 bg-gray-50',
28
+ let color = this.getBadgeColor()
29
+
30
+ let cssClasses = {
31
+ gray: 'text-gray-700 bg-gray-100',
32
32
  green: 'text-green-700 bg-green-50',
33
33
  red: 'text-red-700 bg-red-50',
34
34
  yellow: 'text-yellow-700 bg-yellow-50',
35
35
  blue: 'text-blue-700 bg-blue-50',
36
- }[color || 'gray']
36
+ }[color]
37
+
38
+ return cssClasses
39
+ },
40
+ },
41
+ methods: {
42
+ getBadgeColor() {
43
+ let color = this.color
44
+ if (color) {
45
+ return color
46
+ }
47
+
48
+ let statusColorMap = Object.assign(DEFAULT_COLOR_MAP, this.colorMap || {})
49
+ color = statusColorMap[this.status] || 'gray'
50
+
51
+ return color
37
52
  },
38
53
  },
39
54
  }
@@ -7,23 +7,26 @@
7
7
  >
8
8
  <LoadingIndicator
9
9
  v-if="loading"
10
+ class="mr-2 -ml-1 h-3 w-3"
10
11
  :class="{
11
12
  'text-white': appearance == 'primary',
12
13
  'text-gray-600': appearance == 'secondary',
13
14
  'text-red-200': appearance == 'danger',
15
+ 'text-green-200': appearance == 'success',
16
+ 'text-yellow-200': appearance == 'warning',
14
17
  }"
15
18
  />
16
19
  <FeatherIcon
17
20
  v-else-if="iconLeft"
18
21
  :name="iconLeft"
19
- class="w-4 h-4 mr-1.5"
22
+ class="mr-1.5 h-4 w-4"
20
23
  aria-hidden="true"
21
24
  />
22
25
  <template v-if="loading && loadingText">{{ loadingText }}</template>
23
26
  <template v-else-if="icon">
24
- <FeatherIcon :name="icon" class="w-4 h-4" :aria-label="label" />
27
+ <FeatherIcon :name="icon" class="h-4 w-4" :aria-label="label" />
25
28
  </template>
26
- <span :class="icon ? 'sr-only' : ''">
29
+ <span v-else :class="icon ? 'sr-only' : ''">
27
30
  <slot>
28
31
  {{ label }}
29
32
  </slot>
@@ -31,7 +34,7 @@
31
34
  <FeatherIcon
32
35
  v-if="iconRight"
33
36
  :name="iconRight"
34
- class="w-4 h-4 ml-2"
37
+ class="ml-2 h-4 w-4"
35
38
  aria-hidden="true"
36
39
  />
37
40
  </button>
@@ -40,7 +43,15 @@
40
43
  import FeatherIcon from './FeatherIcon.vue'
41
44
  import LoadingIndicator from './LoadingIndicator.vue'
42
45
 
43
- const ValidAppearances = ['primary', 'secondary', 'danger', 'white', 'minimal']
46
+ const ValidAppearances = [
47
+ 'primary',
48
+ 'secondary',
49
+ 'danger',
50
+ 'success',
51
+ 'warning',
52
+ 'white',
53
+ 'minimal',
54
+ ]
44
55
 
45
56
  export default {
46
57
  name: 'Button',
@@ -98,19 +109,23 @@ export default {
98
109
  buttonClasses() {
99
110
  let appearanceClasses = {
100
111
  primary:
101
- 'bg-blue-500 hover:bg-blue-600 text-white focus:ring-2 focus:ring-offset-2 focus:ring-blue-500',
112
+ 'bg-blue-500 hover:bg-blue-600 border-transparent text-white focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-blue-500',
102
113
  secondary:
103
- 'bg-gray-100 hover:bg-gray-200 text-gray-900 focus:ring-2 focus:ring-offset-2 focus:ring-gray-500',
114
+ 'bg-gray-100 hover:bg-gray-200 border-transparent text-gray-900 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-500',
104
115
  danger:
105
- 'bg-red-500 hover:bg-red-400 text-white focus:ring-2 focus:ring-offset-2 focus:ring-red-500',
116
+ 'bg-red-500 hover:bg-red-400 border-transparent text-white focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-red-500',
117
+ success:
118
+ 'bg-green-500 hover:bg-green-400 border-transparent text-white focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-green-500',
119
+ warning:
120
+ 'bg-yellow-500 hover:bg-yellow-400 border-transparent text-white focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-yellow-500',
106
121
  white:
107
- 'bg-white text-gray-900 border hover:bg-gray-50 focus:ring-2 focus:ring-offset-2 focus:ring-gray-400',
108
- minimal: `active:bg-gray-200 focus:bg-gray-200 text-gray-900 ${
122
+ 'bg-white text-gray-900 border-gray-200 hover:bg-gray-50 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-400',
123
+ minimal: `active:bg-gray-200 border-transparent focus:bg-gray-200 text-gray-900 ${
109
124
  this.active ? 'bg-gray-200' : 'bg-transparent hover:bg-gray-200'
110
125
  }`,
111
126
  }
112
127
  return [
113
- 'inline-flex items-center justify-center text-base leading-5 rounded-md transition-colors focus:outline-none',
128
+ 'inline-flex items-center justify-center text-base leading-5 rounded-md border transition-colors focus:outline-none',
114
129
  this.icon ? 'p-1.5' : 'px-3 py-1',
115
130
  this.isDisabled
116
131
  ? 'opacity-50 cursor-not-allowed pointer-events-none'
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="flex flex-col px-6 py-5 bg-white border rounded-lg shadow">
2
+ <div class="flex flex-col rounded-lg border bg-white px-6 py-5 shadow">
3
3
  <div class="flex items-baseline justify-between">
4
4
  <div class="flex items-baseline space-x-2">
5
5
  <div class="flex items-center space-x-2" v-if="$slots['actions-left']">
@@ -11,16 +11,16 @@
11
11
  <slot name="actions"></slot>
12
12
  </div>
13
13
  </div>
14
- <p class="text-base text-gray-600 mt-1.5" v-if="subtitle">
14
+ <p class="mt-1.5 text-base text-gray-600" v-if="subtitle">
15
15
  {{ subtitle }}
16
16
  </p>
17
17
  <div
18
18
  v-if="loading"
19
- class="flex flex-col items-center justify-center flex-auto mt-4 rounded-md"
19
+ class="mt-4 flex flex-auto flex-col items-center justify-center rounded-md"
20
20
  >
21
21
  <LoadingText />
22
22
  </div>
23
- <div class="flex-auto mt-4 overflow-auto" v-else-if="$slots['default']">
23
+ <div class="mt-4 flex-auto overflow-auto" v-else-if="$slots['default']">
24
24
  <slot></slot>
25
25
  </div>
26
26
  </div>