windly-ui 1.0.0 → 1.0.2

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 (52) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +57 -33
  3. package/package.json +49 -11
  4. package/ui-library/dist/module.d.mts +3 -0
  5. package/ui-library/dist/module.json +8 -0
  6. package/ui-library/dist/module.mjs +22 -0
  7. package/ui-library/dist/types.d.mts +7 -0
  8. package/app/app.vue +0 -10
  9. package/app/assets/css/tailwind.css +0 -3
  10. package/app/components/doc/component.vue +0 -34
  11. package/app/components/doc/megaSection.vue +0 -56
  12. package/app/components/doc/section.vue +0 -56
  13. package/app/pages/_docs.vue +0 -2420
  14. package/app/pages/index.vue +0 -137
  15. package/nuxt.config.ts +0 -19
  16. package/public/doc/avatar.avif +0 -0
  17. package/public/favicon.ico +0 -0
  18. package/public/robots.txt +0 -2
  19. package/tailwind.config.ts +0 -28
  20. package/tsconfig.json +0 -18
  21. package/ui-library/components/Accordion.vue +0 -118
  22. package/ui-library/components/Avatar.vue +0 -121
  23. package/ui-library/components/Badge.vue +0 -116
  24. package/ui-library/components/Breadcrumbs.vue +0 -138
  25. package/ui-library/components/Button.vue +0 -154
  26. package/ui-library/components/Card.vue +0 -84
  27. package/ui-library/components/Checkbox.vue +0 -148
  28. package/ui-library/components/CodeBlock.vue +0 -99
  29. package/ui-library/components/ColorPicker.vue +0 -302
  30. package/ui-library/components/Date.vue +0 -240
  31. package/ui-library/components/Dialog.vue +0 -187
  32. package/ui-library/components/Divider.vue +0 -78
  33. package/ui-library/components/Drawer.vue +0 -67
  34. package/ui-library/components/Dropdown.vue +0 -248
  35. package/ui-library/components/FileUploader.vue +0 -330
  36. package/ui-library/components/Icon.vue +0 -82
  37. package/ui-library/components/Image.vue +0 -78
  38. package/ui-library/components/Input.vue +0 -531
  39. package/ui-library/components/Radio.vue +0 -356
  40. package/ui-library/components/ScrollArea.vue +0 -43
  41. package/ui-library/components/Select.vue +0 -309
  42. package/ui-library/components/Stepper.vue +0 -361
  43. package/ui-library/components/TabPanel.vue +0 -25
  44. package/ui-library/components/Table.vue +0 -152
  45. package/ui-library/components/Tabs.vue +0 -71
  46. package/ui-library/components/Textarea.vue +0 -233
  47. package/ui-library/components/Toggle.vue +0 -319
  48. package/ui-library/components/Tooltip.vue +0 -200
  49. package/ui-library/components/plugin.ts +0 -8
  50. package/ui-library/components/uiProps.ts +0 -11
  51. package/ui-library/components/useUiClasses.ts +0 -159
  52. package/ui-library/module.ts +0 -20
@@ -1,154 +0,0 @@
1
- <script setup lang="ts">
2
- defineOptions({
3
- inheritAttrs: false,
4
- })
5
-
6
- import { computed } from 'vue'
7
- import { useUiClasses } from './useUiClasses'
8
- import { uiProps } from "./uiProps";
9
-
10
- // Props
11
- const props = defineProps({
12
- label: { type: String, default: null },
13
- to: { type: [String, Object], default: null },
14
- outline: { type: Boolean, default: false },
15
- flat: { type: Boolean, default: false },
16
- unelevated: { type: Boolean, default: false },
17
- dense: { type: Boolean, default: false },
18
- stacked: { type: Boolean, default: false },
19
- gradient: { type: Boolean, default: false },
20
- color2: { type: String, default: '' },
21
- icon: { type: String, default: null },
22
- iconColor: { type: String, default: null },
23
- iconPosition: { type: String, default: 'start' },
24
- ...uiProps
25
- })
26
-
27
- // Use composable
28
- const {
29
- // props
30
- contentClass,
31
- contentStyle,
32
- textColor,
33
- disable,
34
- loading,
35
- color,
36
- rounded,
37
- size,
38
- iconSize,
39
- // class maps
40
- roundedClass,
41
- sizeClass,
42
- iconSizeClasses,
43
- // computed
44
- colorClass,
45
- computedContentClass,
46
- isColorDark,
47
- isHex,
48
- isTailwindColor,
49
- shadeTailwind,
50
- shadeHex
51
- } = useUiClasses(props)
52
-
53
- const paddingClass = {
54
- default: {
55
- sm: "py-1 px-3 min-h-8 h-auto w-auto" + (props.label ? " min-w-16" : ""),
56
- md: "py-2 px-6 min-h-10 h-auto w-auto" + (props.label ? " min-w-28":""),
57
- lg: "py-3 px-8 min-h-12 h-auto w-auto" + (props.label ? " min-w-36":""),
58
- },
59
- dense: {
60
- sm: "py-0.5 px-2 min-h-6 h-auto w-auto" + (props.label ? " min-w-16":""),
61
- md: "py-1 px-4 min-h-8 h-auto w-auto" + (props.label ? " min-w-24":""),
62
- lg: "py-1.5 px-6 min-h-10 h-auto w-auto" + (props.label ? " min-w-32":""),
63
- },
64
- };
65
-
66
- const computedClass = computed(() => {
67
- let cls = `transition-all duration-300 text-nowrap ${roundedClass[(rounded.value as keyof typeof roundedClass)]} ${sizeClass[(size.value as keyof typeof sizeClass)]}`;
68
-
69
- if (props.outline)
70
- cls += ` border bg-white border-${colorClass.value} text-${colorClass.value} hover:bg-${colorClass.value} hover:text-white`;
71
-
72
- if (props.flat)
73
- cls += ` bg-transparent text-${colorClass.value} hover:bg-${colorClass.value} hover:bg-opacity-10 shadow-none`;
74
-
75
- cls += props.dense ? ` ${paddingClass.dense[size.value as keyof typeof paddingClass.dense]}` : ` ${paddingClass.default[size.value as keyof typeof paddingClass.default]}`;
76
- cls += props.unelevated ? " no-shadow" : " shadow-md";
77
- cls += props.stacked ? " flex flex-col items-center justify-center gap-2" : " flex items-center justify-center gap-2";
78
- cls += disable.value ? " opacity-50 cursor-not-allowed" : " cursor-pointer";
79
- cls += loading.value ? " opacity-75 cursor-progress" : "";
80
- cls += props.gradient
81
- ? ` bg-gradient-to-br from-${color.value} to-${computedColor2.value} hover:bg-gradient-to-tl text-${computedTextColor.value}`
82
- : !props.flat && !props.outline
83
- ? ` bg-${color.value} hover:bg-${computedColor2.value} text-${computedTextColor.value}`
84
- : "";
85
-
86
- return cls;
87
- });
88
-
89
- const computedIconClass = computed(() => {
90
- return `material-icons ${iconSizeClasses[props.iconPosition === 'start' ? 'lg' : 'md']} ${props.iconColor ? `text-${props.iconColor}` : ''}`
91
- })
92
-
93
- // Computed props for v-bind
94
- const computedProps = computed(() => ({
95
- class: computedClass.value,
96
- disabled: disable.value || loading.value
97
- }))
98
-
99
- const computedTextColor = computed(() => {
100
- if (textColor.value) {
101
- return textColor.value;
102
- }
103
-
104
- if (props.outline || props.flat) {
105
- return color.value;
106
- }
107
-
108
- const darkBg = isColorDark(color.value);
109
- return darkBg ? "white" : "gray-900"
110
- })
111
-
112
- const computedColor2 = computed(() => {
113
- if (props.color2) return props.color2
114
-
115
- if (isTailwindColor(color.value)) {
116
- return shadeTailwind(color.value, 100)
117
- }
118
-
119
- if (isHex(color.value)) {
120
- return shadeHex(color.value, -20)
121
- }
122
-
123
- return color.value
124
- })
125
-
126
- // Click handler
127
- function onClick() {
128
- if (!loading.value && !disable.value && !props.to) {
129
- emit('click')
130
- }
131
- }
132
-
133
- // Emit function for script setup
134
- const emit = defineEmits(['click'])
135
- </script>
136
-
137
- <template>
138
- <!-- Router Link if "to" prop is provided -->
139
- <router-link v-if="to" v-bind="computedProps" :to="to">
140
- <!-- Icon (start position) -->
141
- <i v-if="icon && iconPosition === 'start'" :class="computedIconClass">{{ icon }}</i>
142
- <!-- Label -->
143
- <span v-if="label" class="label">{{ label }}</span>
144
- <!-- Icon (end position) -->
145
- <i v-if="icon && iconPosition === 'end'" :class="computedIconClass">{{ icon }}</i>
146
- </router-link>
147
-
148
- <!-- Normal button if no "to" prop -->
149
- <button v-else v-bind="computedProps" @click="onClick">
150
- <i v-if="icon && iconPosition === 'start'" :class="computedIconClass">{{ icon }}</i>
151
- <span v-if="label" class="label">{{ label }}</span>
152
- <i v-if="icon && iconPosition === 'end'" :class="computedIconClass">{{ icon }}</i>
153
- </button>
154
- </template>
@@ -1,84 +0,0 @@
1
- <script setup lang="ts">
2
- defineOptions({
3
- inheritAttrs: false,
4
- })
5
-
6
- import { computed } from 'vue'
7
-
8
- const props = defineProps({
9
- flat: { type: Boolean, default: false },
10
- square: { type: Boolean, default: false },
11
- dense: { type: Boolean, default: false },
12
- bordered: { type: Boolean, default: true },
13
-
14
- color: { type: String, default: 'white' },
15
- borderColor: { type: String, default: 'gray-200' },
16
-
17
- width: { type: String, default: '100%' },
18
- })
19
-
20
- const isHex = (val: string) => val.startsWith('#')
21
-
22
- const cardStyle = computed(() => {
23
- const style: Record<string, string> = {
24
- width: props.width,
25
- maxWidth: '80vw',
26
- }
27
-
28
- if (isHex(props.color)) {
29
- style.backgroundColor = props.color
30
- }
31
-
32
- if (props.bordered && isHex(props.borderColor)) {
33
- style.borderColor = props.borderColor
34
- }
35
-
36
- return style
37
- })
38
-
39
- const cardClass = computed(() => [
40
- 'transition-shadow duration-300',
41
- props.flat ? 'shadow-none' : 'shadow-md',
42
- props.square ? 'rounded-none' : 'rounded-md',
43
- props.bordered ? 'border' : '',
44
- !isHex(props.borderColor) && props.bordered
45
- ? `border-${props.borderColor}`
46
- : '',
47
- !isHex(props.color) ? `bg-${props.color}` : '',
48
- ])
49
-
50
- const sectionPadding = computed(() =>
51
- props.dense ? 'p-0' : 'p-4'
52
- )
53
- </script>
54
-
55
- <template>
56
- <div
57
- :class="cardClass"
58
- :style="cardStyle"
59
- v-bind="$attrs"
60
- >
61
- <!-- Header -->
62
- <div
63
- v-if="$slots.header"
64
- :class="sectionPadding"
65
- class="border-b border-gray-200"
66
- >
67
- <slot name="header" />
68
- </div>
69
-
70
- <!-- Content -->
71
- <div :class="sectionPadding">
72
- <slot />
73
- </div>
74
-
75
- <!-- Footer -->
76
- <div
77
- v-if="$slots.footer"
78
- :class="sectionPadding"
79
- class="border-t border-gray-200"
80
- >
81
- <slot name="footer" />
82
- </div>
83
- </div>
84
- </template>
@@ -1,148 +0,0 @@
1
- <script setup lang="ts">
2
- defineOptions({ inheritAttrs: false })
3
-
4
- import { computed } from 'vue'
5
- import { useUiClasses } from './useUiClasses'
6
- import { uiProps } from './uiProps'
7
-
8
- const emit = defineEmits<{
9
- (e: 'update:modelValue', value: any): void
10
- }>()
11
-
12
- const props = defineProps({
13
- modelValue: { required: true },
14
-
15
- name: { type: String, default: null },
16
- label: { type: String, default: null },
17
-
18
- trueValue: { default: true },
19
- falseValue: { default: false },
20
- intermediateValue: { default: null },
21
-
22
- checkedIcon: { type: String, default: 'check' },
23
- uncheckedIcon: { type: String, default: null },
24
- intermediateIcon: { type: String, default: 'remove' },
25
-
26
- checkedColor: { type: String, default: '' },
27
- uncheckedColor: { type: String, default: 'gray-400' },
28
-
29
- dense: { type: Boolean, default: false },
30
-
31
- ...uiProps,
32
- })
33
-
34
- const {
35
- disable,
36
- color,
37
- size,
38
- rounded,
39
- roundedClass,
40
- } = useUiClasses(props)
41
-
42
- const isChecked = computed(
43
- () => props.modelValue === props.trueValue
44
- )
45
-
46
- const isIntermediate = computed(
47
- () => props.modelValue === props.intermediateValue
48
- )
49
-
50
- const boxSizeClass = computed(() => {
51
- const map = {
52
- sm: 'w-4 h-4',
53
- md: 'w-5 h-5',
54
- lg: 'w-6 h-6',
55
- } as const
56
-
57
- return map[size.value as keyof typeof map]
58
- })
59
-
60
- const labelSizeClass = computed(() => {
61
- const map = {
62
- sm: 'text-sm',
63
- md: 'text-base',
64
- lg: 'text-xl',
65
- } as const
66
-
67
- return map[size.value as keyof typeof map]
68
- })
69
-
70
- const boxColorClass = computed(() => {
71
- if (isChecked.value) {
72
- return `bg-${props.checkedColor || color.value} border-${props.checkedColor || color.value}`
73
- }
74
-
75
- if (isIntermediate.value) {
76
- return `bg-${color.value} border-${color.value}`
77
- }
78
-
79
- return `bg-transparent border-${props.uncheckedColor}`
80
- })
81
-
82
- const containerClass = computed(() =>
83
- `
84
- inline-flex items-center gap-2
85
- ${disable.value ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}
86
- `
87
- )
88
-
89
- function toggle() {
90
- if (disable.value) return
91
-
92
- if (isChecked.value || isIntermediate.value) {
93
- emit('update:modelValue', props.falseValue)
94
- } else {
95
- emit('update:modelValue', props.trueValue)
96
- }
97
- }
98
- </script>
99
- <template>
100
- <label
101
- :class="containerClass"
102
- role="checkbox"
103
- :aria-checked="isIntermediate ? 'mixed' : isChecked"
104
- >
105
- <input
106
- type="checkbox"
107
- class="hidden"
108
- :name="name"
109
- :disabled="disable"
110
- @change="toggle"
111
- />
112
-
113
- <span
114
- :class="[
115
- 'flex items-center justify-center border transition-all duration-200 p-2',
116
- boxSizeClass,
117
- roundedClass[rounded as keyof typeof roundedClass],
118
- boxColorClass,
119
- ]"
120
- @click.prevent="toggle"
121
- >
122
- <i
123
- v-if="isChecked && checkedIcon"
124
- :class="labelSizeClass"
125
- class="material-icons text-white"
126
- >
127
- {{ checkedIcon }}
128
- </i>
129
- <i
130
- v-else-if="isIntermediate && intermediateIcon"
131
- :class="labelSizeClass"
132
- class="material-icons text-white"
133
- >
134
- {{ intermediateIcon }}
135
- </i>
136
- <i
137
- v-else-if="uncheckedIcon"
138
- :class="labelSizeClass"
139
- class="material-icons text-gray-400"
140
- >
141
- {{ uncheckedIcon }}
142
- </i>
143
- </span>
144
- <span v-if="label" class="select-none" :class="labelSizeClass">
145
- {{ label }}
146
- </span>
147
- </label>
148
- </template>
@@ -1,99 +0,0 @@
1
- <script setup lang="ts">
2
- import { ref, useSlots, computed, isVNode } from 'vue'
3
-
4
- defineProps<{
5
- title?: string
6
- }>()
7
-
8
- const activeTab = ref('example')
9
- const slots = useSlots()
10
-
11
- import type { VNode } from 'vue'
12
-
13
- function stringifyProps(props: unknown): string {
14
- if (!props || typeof props !== 'object') {
15
- return ''
16
- }
17
-
18
- return Object.entries(props as Record<string, any>)
19
- .filter(([key]) => !key.startsWith('on')) // 🔥 KEY FIX
20
- .map(([key, value]) => {
21
- if (value === true) return key
22
- if (value === false || value == null) return ''
23
- return `${key}="${String(value)}"`
24
- })
25
- .filter(Boolean)
26
- .join(' ')
27
- }
28
-
29
- function renderVNode(vnode: VNode): string {
30
- if (typeof vnode.children === 'string') {
31
- return vnode.children
32
- }
33
-
34
- if (vnode.type === Symbol.for('v-fgt')) {
35
- return (vnode.children as VNode[])
36
- .map(renderVNode)
37
- .join('')
38
- }
39
-
40
- if (typeof vnode.type === 'object') {
41
- const typeAny = vnode.type as any
42
- const name = typeAny.__name || typeAny.name || typeAny.displayName || 'Component'
43
- const props = stringifyProps(vnode.props as any)
44
- return `<${name}${props ? ' ' + props : ''} />`
45
- }
46
-
47
- if (typeof vnode.type === 'string') {
48
- const children = Array.isArray(vnode.children)
49
- ? vnode.children
50
- .map(child => (isVNode(child) ? renderVNode(child) : (typeof child === 'string' ? child : '')))
51
- .join('')
52
- : (typeof vnode.children === 'string' ? vnode.children : '')
53
- return `<${vnode.type}>${children}</${vnode.type}>`
54
- }
55
-
56
- return ''
57
- }
58
-
59
- const slotCode = computed(() => {
60
- const vnodes = slots.default?.() || []
61
- return vnodes.map(renderVNode).join('')
62
- })
63
-
64
- const buttonIcon = ref('content_copy')
65
-
66
- const copyCode = async () => {
67
- await navigator.clipboard.writeText(slotCode.value)
68
-
69
- buttonIcon.value = 'check'
70
- setTimeout(() => {
71
- buttonIcon.value = 'content_copy'
72
- }, 2000)
73
- }
74
- </script>
75
- <template>
76
- <div class="border rounded-lg bg-white overflow-hidden">
77
- <!-- Header -->
78
- <div class="flex items-center justify-between px-4 py-2 border-b bg-gray-50">
79
- <h3 v-if="title" class="font-medium text-gray-700">
80
- {{ title }}
81
- </h3>
82
-
83
- <UIButton flat :icon="buttonIcon" size="sm" class="text-gray-600" @click="copyCode" />
84
- </div>
85
-
86
- <!-- Tabs -->
87
- <UITabs v-model="activeTab">
88
- <UITabPanel name="example" label="Example">
89
- <div class="p-4">
90
- <slot />
91
- </div>
92
- </UITabPanel>
93
-
94
- <UITabPanel name="code" label="Code">
95
- <pre class="p-4 bg-gray-900 text-gray-100 text-sm overflow-x-auto"><code>{{ slotCode }}</code></pre>
96
- </UITabPanel>
97
- </UITabs>
98
- </div>
99
- </template>