@maz-ui/mcp 4.1.2 → 4.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/dist/mcp.mjs +2 -2
- package/docs/generated-docs/maz-radio-buttons.doc.md +1 -0
- package/docs/src/components/maz-popover.md +1 -1
- package/docs/src/components/maz-select-country.md +1 -1
- package/docs/src/composables/use-display-names.md +3 -3
- package/docs/src/composables/use-form-validator.md +2 -2
- package/docs/src/composables/use-idle-timeout.md +1 -1
- package/docs/src/composables/use-swipe.md +1 -1
- package/docs/src/composables/use-timer.md +1 -1
- package/docs/src/demo/ColorPicker.vue +167 -0
- package/docs/src/demo/DemoDashboardPage.vue +2 -9
- package/docs/src/demo/ThemeEditorPage.vue +396 -0
- package/docs/src/directives/click-outside.md +1 -1
- package/docs/src/directives/lazy-img.md +1 -1
- package/docs/src/directives/tooltip.md +1 -1
- package/docs/src/directives/zoom-img.md +1 -1
- package/docs/src/guide/getting-started.md +1 -1
- package/docs/src/guide/icons.md +1 -1
- package/docs/src/guide/migration-v4.md +3 -3
- package/docs/src/guide/themes.md +4 -0
- package/docs/src/index.md +2 -2
- package/docs/src/theme-editor.md +21 -0
- package/package.json +4 -4
package/dist/mcp.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
|
7
7
|
import { resolve, dirname, join } from 'node:path';
|
|
8
8
|
import { fileURLToPath } from 'node:url';
|
|
9
9
|
|
|
10
|
-
const version = "4.1.
|
|
10
|
+
const version = "4.1.2";
|
|
11
11
|
|
|
12
12
|
const _dirname = dirname(fileURLToPath(import.meta.url));
|
|
13
13
|
class DocumentationService {
|
|
@@ -404,7 +404,7 @@ class MazUiMcpServer {
|
|
|
404
404
|
},
|
|
405
405
|
{
|
|
406
406
|
name: "list_composables",
|
|
407
|
-
description: "List all Vue
|
|
407
|
+
description: "List all Vue or Nuxt composables (useToast, useDialog, etc.)",
|
|
408
408
|
inputSchema: {
|
|
409
409
|
type: "object",
|
|
410
410
|
properties: {}
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
| **success** | Whether the input is successful. | `boolean` | No | `undefined` | - |
|
|
17
17
|
| **warning** | Whether there is a warning with the input. | `boolean` | No | `undefined` | - |
|
|
18
18
|
| **hint** | The hint text to display below the input. | `string` | No | `undefined` | - |
|
|
19
|
+
| **size** | The size of the radio buttons | `MazSize` | No | `'md'` | - |
|
|
19
20
|
|
|
20
21
|
## Events
|
|
21
22
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: MazPopover
|
|
3
|
-
description: MazPopover is a versatile Vue
|
|
3
|
+
description: MazPopover is a versatile Vue component for displaying content in overlays that bypass overflow constraints of parent elements
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# {{ $frontmatter.title }}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: MazSelectCountry
|
|
3
|
-
description: MazSelectCountry is a versatile Vue
|
|
3
|
+
description: MazSelectCountry is a versatile Vue component for selecting countries or languages with built-in internationalization support and customizable display options
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# {{ $frontmatter.title }}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: useDisplayNames
|
|
3
|
-
description: useDisplayNames is a Vue
|
|
3
|
+
description: useDisplayNames is a Vue composable specialized in displaying localized country names (regions) and language names. It supports various code formats including ISO 639-1 (language codes), ISO 3166-1 (country codes), and BCP 47 (language tags), using the Intl.DisplayNames API for internationalization.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# {{ $frontmatter.title }}
|
|
@@ -20,7 +20,7 @@ Depending on your environment (client or node server) and the browser you are us
|
|
|
20
20
|
## Key Features
|
|
21
21
|
|
|
22
22
|
- Displays localized country names (regions) and language names
|
|
23
|
-
- Supports multiple code formats: ISO 639-1 (language codes), ISO 3166-1 (country codes), and BCP 47 (language tags)
|
|
23
|
+
- Supports multiple code formats: ISO 639-1 (language codes), ISO 3166-1 (country codes), and BCP 47 (language tags)
|
|
24
24
|
- Works with any locale supported by the browser's Intl.DisplayNames API
|
|
25
25
|
- Provides functions to get individual names or bulk retrieve all available names
|
|
26
26
|
- Handles errors gracefully with fallback values
|
|
@@ -154,7 +154,7 @@ function getAllDisplayNames(options: {
|
|
|
154
154
|
|
|
155
155
|
## Notes
|
|
156
156
|
|
|
157
|
-
- The `useDisplayNames` composable is designed to be used with Vue
|
|
157
|
+
- The `useDisplayNames` composable is designed to be used with Vue.
|
|
158
158
|
- The composable functions return `ComputedRef` values, which are reactive and will update automatically when their dependencies change.
|
|
159
159
|
- Handle errors gracefully by providing fallback values when the display name cannot be fetched.
|
|
160
160
|
- The `Intl.DisplayNames` API is used internally to fetch and format the display names based on the provided locale and code.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: useFormValidator
|
|
3
|
-
description: useFormValidator and useFormField are two Vue
|
|
3
|
+
description: useFormValidator and useFormField are two Vue composables designed to simplify form validation using Valibot as the validation library. These composables offer a flexible and typed approach to handle form validation in your Vue applications.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# {{ $frontmatter.title }}
|
|
7
7
|
|
|
8
|
-
`useFormValidator` and `useFormField` are two Vue
|
|
8
|
+
`useFormValidator` and `useFormField` are two Vue composables designed to simplify form validation using [Valibot](https://valibot.dev/guides/introduction/) as the validation library. These composables offer a flexible and typed approach to handle form validation in your Vue applications.
|
|
9
9
|
|
|
10
10
|
## Introduction
|
|
11
11
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: useIdleTimeout
|
|
3
|
-
description: A Vue
|
|
3
|
+
description: A Vue composable that provides an easy way to track user inactivity on your website and execute a callback function when the user becomes idle.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# {{ $frontmatter.title }}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: useSwipe
|
|
3
|
-
description: useSwipe is a Vue
|
|
3
|
+
description: useSwipe is a Vue composable that simplifies the management of "swipe" interactions on HTML elements.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# {{ $frontmatter.title }}
|
|
@@ -19,7 +19,7 @@ The composable provides the following functionality:
|
|
|
19
19
|
|
|
20
20
|
The composable also includes cleanup logic using onBeforeUnmount to ensure that the timer is stopped when the component is unmounted.
|
|
21
21
|
|
|
22
|
-
This composable can be used in Vue
|
|
22
|
+
This composable can be used in Vue components to handle timeouts in a flexible and reactive manner.
|
|
23
23
|
|
|
24
24
|
## Usage
|
|
25
25
|
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/* eslint-disable style/max-statements-per-line */
|
|
3
|
+
|
|
4
|
+
import type { HSL } from '@maz-ui/themes'
|
|
5
|
+
import { computed, ref, watch } from 'vue'
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
modelValue: HSL
|
|
9
|
+
label?: string
|
|
10
|
+
disabled?: boolean
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
14
|
+
disabled: false,
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const emit = defineEmits<{
|
|
18
|
+
'update:modelValue': [value: HSL]
|
|
19
|
+
}>()
|
|
20
|
+
|
|
21
|
+
const colorInput = ref<HTMLInputElement>()
|
|
22
|
+
|
|
23
|
+
function hslToHex(hsl: HSL): string {
|
|
24
|
+
const match = hsl.match(/(\d+(?:\.\d+)?)\s+(\d+(?:\.\d+)?)%\s+(\d+(?:\.\d+)?)%/)
|
|
25
|
+
if (!match)
|
|
26
|
+
return '#000000'
|
|
27
|
+
|
|
28
|
+
const h = Number.parseFloat(match[1]) / 360
|
|
29
|
+
const s = Number.parseFloat(match[2]) / 100
|
|
30
|
+
const l = Number.parseFloat(match[3]) / 100
|
|
31
|
+
|
|
32
|
+
const hue2rgb = (p: number, q: number, t: number) => {
|
|
33
|
+
if (t < 0)
|
|
34
|
+
t += 1
|
|
35
|
+
if (t > 1)
|
|
36
|
+
t -= 1
|
|
37
|
+
if (t < 1 / 6)
|
|
38
|
+
return p + (q - p) * 6 * t
|
|
39
|
+
if (t < 1 / 2)
|
|
40
|
+
return q
|
|
41
|
+
if (t < 2 / 3)
|
|
42
|
+
return p + (q - p) * (2 / 3 - t) * 6
|
|
43
|
+
return p
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let r: number
|
|
47
|
+
let g: number
|
|
48
|
+
let b: number
|
|
49
|
+
|
|
50
|
+
if (s === 0) {
|
|
51
|
+
r = g = b = l
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s
|
|
55
|
+
const p = 2 * l - q
|
|
56
|
+
r = hue2rgb(p, q, h + 1 / 3)
|
|
57
|
+
g = hue2rgb(p, q, h)
|
|
58
|
+
b = hue2rgb(p, q, h - 1 / 3)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const toHex = (c: number) => {
|
|
62
|
+
const hex = Math.round(c * 255).toString(16)
|
|
63
|
+
return hex.length === 1 ? `0${hex}` : hex
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return `#${toHex(r)}${toHex(g)}${toHex(b)}`
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function hexToHsl(hex: string): HSL {
|
|
70
|
+
const r = Number.parseInt(hex.slice(1, 3), 16) / 255
|
|
71
|
+
const g = Number.parseInt(hex.slice(3, 5), 16) / 255
|
|
72
|
+
const b = Number.parseInt(hex.slice(5, 7), 16) / 255
|
|
73
|
+
|
|
74
|
+
const max = Math.max(r, g, b)
|
|
75
|
+
const min = Math.min(r, g, b)
|
|
76
|
+
let h: number
|
|
77
|
+
let s: number
|
|
78
|
+
const l = (max + min) / 2
|
|
79
|
+
|
|
80
|
+
if (max === min) {
|
|
81
|
+
h = s = 0
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
const d = max - min
|
|
85
|
+
s = l > 0.5 ? d / (2 - max - min) : d / (max + min)
|
|
86
|
+
|
|
87
|
+
switch (max) {
|
|
88
|
+
case r: h = (g - b) / d + (g < b ? 6 : 0); break
|
|
89
|
+
case g: h = (b - r) / d + 2; break
|
|
90
|
+
case b: h = (r - g) / d + 4; break
|
|
91
|
+
default: h = 0
|
|
92
|
+
}
|
|
93
|
+
h /= 6
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const hue = Math.round(h * 360)
|
|
97
|
+
const saturation = Math.round(s * 100)
|
|
98
|
+
const lightness = Math.round(l * 100)
|
|
99
|
+
|
|
100
|
+
return `${hue} ${saturation}% ${lightness}%` as HSL
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const hexValue = computed(() => hslToHex(props.modelValue))
|
|
104
|
+
|
|
105
|
+
function handleColorChange(event: Event) {
|
|
106
|
+
const target = event.target as HTMLInputElement
|
|
107
|
+
const hslValue = hexToHsl(target.value)
|
|
108
|
+
emit('update:modelValue', hslValue)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
watch(() => props.modelValue, () => {
|
|
112
|
+
if (colorInput.value) {
|
|
113
|
+
colorInput.value.value = hexValue.value
|
|
114
|
+
}
|
|
115
|
+
}, { immediate: true })
|
|
116
|
+
</script>
|
|
117
|
+
|
|
118
|
+
<template>
|
|
119
|
+
<div class="color-picker">
|
|
120
|
+
<label v-if="label" for="input-color">
|
|
121
|
+
{{ label }}
|
|
122
|
+
</label>
|
|
123
|
+
|
|
124
|
+
<input
|
|
125
|
+
id="input-color"
|
|
126
|
+
ref="colorInput"
|
|
127
|
+
type="color"
|
|
128
|
+
:value="hexValue"
|
|
129
|
+
:disabled="disabled"
|
|
130
|
+
@change="handleColorChange"
|
|
131
|
+
>
|
|
132
|
+
</div>
|
|
133
|
+
</template>
|
|
134
|
+
|
|
135
|
+
<style lang="postcss" scoped>
|
|
136
|
+
.color-picker {
|
|
137
|
+
@apply maz-inline-flex maz-flex-col maz-gap-1;
|
|
138
|
+
|
|
139
|
+
label {
|
|
140
|
+
@apply maz-text-sm maz-font-medium maz-text-foreground maz-truncate;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
input[type='color'] {
|
|
144
|
+
-webkit-appearance: none;
|
|
145
|
+
appearance: none;
|
|
146
|
+
background: none;
|
|
147
|
+
cursor: pointer;
|
|
148
|
+
|
|
149
|
+
@apply maz-h-10 maz-w-full maz-cursor-pointer maz-overflow-hidden maz-rounded maz-border maz-border-solid maz-border-divider disabled:maz-cursor-not-allowed disabled:maz-opacity-50;
|
|
150
|
+
|
|
151
|
+
&::-webkit-color-swatch-wrapper {
|
|
152
|
+
padding: 0;
|
|
153
|
+
@apply maz-rounded;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
&::-webkit-color-swatch {
|
|
157
|
+
border: none;
|
|
158
|
+
@apply maz-rounded;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
&::-moz-color-swatch {
|
|
162
|
+
border: none;
|
|
163
|
+
@apply maz-rounded;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
</style>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import dataLabels from 'chartjs-plugin-datalabels'
|
|
3
3
|
import { ref } from 'vue'
|
|
4
4
|
|
|
5
|
-
const { delay =
|
|
5
|
+
const { delay = 0 } = defineProps<{
|
|
6
6
|
delay?: number
|
|
7
7
|
}>()
|
|
8
8
|
|
|
@@ -117,7 +117,6 @@ const tableHeaders = [
|
|
|
117
117
|
color="success"
|
|
118
118
|
size="3rem"
|
|
119
119
|
:delay
|
|
120
|
-
:once="false"
|
|
121
120
|
/>
|
|
122
121
|
<div class="maz-truncate">
|
|
123
122
|
<div class="maz-text-xl maz-font-bold">
|
|
@@ -126,7 +125,6 @@ const tableHeaders = [
|
|
|
126
125
|
:count="28945"
|
|
127
126
|
prefix="$"
|
|
128
127
|
separator=","
|
|
129
|
-
:once="false"
|
|
130
128
|
/>
|
|
131
129
|
</div>
|
|
132
130
|
<div class="maz-truncate maz-text-sm maz-text-muted">
|
|
@@ -143,7 +141,6 @@ const tableHeaders = [
|
|
|
143
141
|
color="info"
|
|
144
142
|
size="3rem"
|
|
145
143
|
:delay
|
|
146
|
-
:once="false"
|
|
147
144
|
/>
|
|
148
145
|
<div class="maz-truncate">
|
|
149
146
|
<div class="maz-text-xl maz-font-bold">
|
|
@@ -151,7 +148,6 @@ const tableHeaders = [
|
|
|
151
148
|
:delay
|
|
152
149
|
:count="384"
|
|
153
150
|
separator=","
|
|
154
|
-
:once="false"
|
|
155
151
|
/>
|
|
156
152
|
</div>
|
|
157
153
|
<div class="maz-truncate maz-text-sm maz-text-muted">
|
|
@@ -168,7 +164,6 @@ const tableHeaders = [
|
|
|
168
164
|
color="warning"
|
|
169
165
|
size="3rem"
|
|
170
166
|
:delay
|
|
171
|
-
:once="false"
|
|
172
167
|
/>
|
|
173
168
|
<div class="maz-truncate">
|
|
174
169
|
<div class="maz-text-xl maz-font-bold">
|
|
@@ -176,7 +171,6 @@ const tableHeaders = [
|
|
|
176
171
|
:delay
|
|
177
172
|
:count="1482"
|
|
178
173
|
separator=","
|
|
179
|
-
:once="false"
|
|
180
174
|
/>
|
|
181
175
|
</div>
|
|
182
176
|
<div class="maz-truncate maz-text-sm maz-text-muted">
|
|
@@ -193,7 +187,6 @@ const tableHeaders = [
|
|
|
193
187
|
color="destructive"
|
|
194
188
|
size="3rem"
|
|
195
189
|
:delay
|
|
196
|
-
:once="false"
|
|
197
190
|
/>
|
|
198
191
|
<div class="maz-truncate">
|
|
199
192
|
<div class="maz-text-xl maz-font-bold">
|
|
@@ -201,7 +194,6 @@ const tableHeaders = [
|
|
|
201
194
|
:delay
|
|
202
195
|
:count="94"
|
|
203
196
|
suffix="%"
|
|
204
|
-
:once="false"
|
|
205
197
|
/>
|
|
206
198
|
</div>
|
|
207
199
|
<div class="maz-truncate maz-text-sm maz-text-muted">
|
|
@@ -223,6 +215,7 @@ const tableHeaders = [
|
|
|
223
215
|
input-size="sm"
|
|
224
216
|
pagination
|
|
225
217
|
selectable
|
|
218
|
+
scrollable
|
|
226
219
|
>
|
|
227
220
|
<template #cell-amount="{ value }">
|
|
228
221
|
<span class="maz-font-semibold">
|
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ThemePreset } from '@maz-ui/themes'
|
|
3
|
+
import { useTheme } from '@maz-ui/themes/composables/useTheme'
|
|
4
|
+
import { mazUi } from '@maz-ui/themes/presets/mazUi'
|
|
5
|
+
import { useToast } from 'maz-ui/composables'
|
|
6
|
+
import { codeToHtml } from 'shiki'
|
|
7
|
+
import { computed, nextTick, reactive, ref, watch } from 'vue'
|
|
8
|
+
import ColorPicker from './ColorPicker.vue'
|
|
9
|
+
import DemoAuthPage from './DemoAuthPage.vue'
|
|
10
|
+
import DemoDashboardPage from './DemoDashboardPage.vue'
|
|
11
|
+
import DemoProductPage from './DemoProductPage.vue'
|
|
12
|
+
|
|
13
|
+
const { updateTheme, isDark, toggleDarkMode, presetName } = useTheme()
|
|
14
|
+
const toast = useToast()
|
|
15
|
+
|
|
16
|
+
const currentTab = ref(1)
|
|
17
|
+
const editingMode = ref<'light' | 'dark'>('light')
|
|
18
|
+
const exportedCode = ref('')
|
|
19
|
+
const highlightedCode = ref('')
|
|
20
|
+
const showExportModal = ref(false)
|
|
21
|
+
const isTransitioning = ref(false)
|
|
22
|
+
|
|
23
|
+
const themeData = reactive<ThemePreset>({
|
|
24
|
+
name: mazUi.name,
|
|
25
|
+
foundation: { ...mazUi.foundation },
|
|
26
|
+
colors: {
|
|
27
|
+
light: { ...mazUi.colors.light },
|
|
28
|
+
dark: { ...mazUi.colors.dark },
|
|
29
|
+
},
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const originalTheme = {
|
|
33
|
+
name: mazUi.name,
|
|
34
|
+
foundation: { ...mazUi.foundation },
|
|
35
|
+
colors: {
|
|
36
|
+
light: { ...mazUi.colors.light },
|
|
37
|
+
dark: { ...mazUi.colors.dark },
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const colorCategories = [
|
|
42
|
+
{
|
|
43
|
+
name: 'Base Colors',
|
|
44
|
+
colors: ['background', 'foreground', 'border', 'muted', 'overlay', 'shadow'] as const,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'Colors',
|
|
48
|
+
colors: ['primary', 'primary-foreground', 'secondary', 'secondary-foreground', 'accent', 'accent-foreground', 'success', 'success-foreground', 'warning', 'warning-foreground', 'destructive', 'destructive-foreground', 'info', 'info-foreground', 'contrast', 'contrast-foreground'] as const,
|
|
49
|
+
},
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
watch([themeData, editingMode], async () => {
|
|
53
|
+
await nextTick()
|
|
54
|
+
await updateTheme(themeData)
|
|
55
|
+
}, { deep: true })
|
|
56
|
+
|
|
57
|
+
function handleThemeModeToggle() {
|
|
58
|
+
isTransitioning.value = true
|
|
59
|
+
toggleDarkMode()
|
|
60
|
+
|
|
61
|
+
setTimeout(() => {
|
|
62
|
+
isTransitioning.value = false
|
|
63
|
+
}, 500)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function resetTheme() {
|
|
67
|
+
Object.assign(themeData.foundation, originalTheme.foundation)
|
|
68
|
+
Object.assign(themeData.colors.light, originalTheme.colors.light)
|
|
69
|
+
Object.assign(themeData.colors.dark, originalTheme.colors.dark)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function copyToClipboard(text: string) {
|
|
73
|
+
navigator.clipboard.writeText(text).then(() => {
|
|
74
|
+
showExportModal.value = false
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
toast.success('Theme copied to clipboard', {
|
|
78
|
+
position: 'top',
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function exportTheme() {
|
|
83
|
+
const themeCode = `import type { ThemePreset } from '@maz-ui/themes'
|
|
84
|
+
|
|
85
|
+
export const customTheme: ThemePreset = ${JSON.stringify(themeData, null, 2)
|
|
86
|
+
// Escape single quotes within string values
|
|
87
|
+
.replace(/: "([^"]*)"/g, (match, value) => {
|
|
88
|
+
const escapedValue = value.replace(/'/g, '\\\'')
|
|
89
|
+
return `: '${escapedValue}'`
|
|
90
|
+
})
|
|
91
|
+
// Remove quotes from top-level keys and nested object keys
|
|
92
|
+
.replace(/^(\s*)"(name|foundation|colors)":/gm, '$1$2:')
|
|
93
|
+
.replace(/^(\s*)"(light|dark)":/gm, '$1$2:')}`
|
|
94
|
+
|
|
95
|
+
exportedCode.value = themeCode
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
const html = await codeToHtml(themeCode, {
|
|
99
|
+
lang: 'typescript',
|
|
100
|
+
theme: isDark.value ? 'tokyo-night' : 'github-dark',
|
|
101
|
+
})
|
|
102
|
+
highlightedCode.value = html
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
console.error('Failed to highlight code:', error)
|
|
106
|
+
highlightedCode.value = ''
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
showExportModal.value = true
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const foundationInputs = computed(() => [
|
|
113
|
+
{
|
|
114
|
+
key: 'base-font-size',
|
|
115
|
+
label: 'Base Font Size',
|
|
116
|
+
type: 'text',
|
|
117
|
+
placeholder: '14px',
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
key: 'font-family',
|
|
121
|
+
label: 'Font Family',
|
|
122
|
+
type: 'text',
|
|
123
|
+
placeholder: 'Manrope, sans-serif',
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
key: 'radius',
|
|
127
|
+
label: 'Border Radius',
|
|
128
|
+
type: 'text',
|
|
129
|
+
placeholder: '0.7rem',
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
key: 'border-width',
|
|
133
|
+
label: 'Border Width',
|
|
134
|
+
type: 'text',
|
|
135
|
+
placeholder: '0.0625rem',
|
|
136
|
+
},
|
|
137
|
+
])
|
|
138
|
+
|
|
139
|
+
const currentColors = computed(() => themeData.colors[editingMode.value])
|
|
140
|
+
|
|
141
|
+
function formatColorName(colorName: string): string {
|
|
142
|
+
return colorName
|
|
143
|
+
.split('-')
|
|
144
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
145
|
+
.join(' ')
|
|
146
|
+
}
|
|
147
|
+
</script>
|
|
148
|
+
|
|
149
|
+
<template>
|
|
150
|
+
<div class="vp-raw theme-configurator" :class="{ 'no-transitions': isTransitioning }">
|
|
151
|
+
<div class="maz-grid maz-min-h-[80vh] maz-grid-cols-1 maz-gap-4 lg:maz-grid-cols-12">
|
|
152
|
+
<!-- Editor Panel -->
|
|
153
|
+
<div class="maz-space-y-6 lg:maz-col-span-4 lg:maz-border-r lg:maz-pr-4">
|
|
154
|
+
<h2 class="maz-text-2xl maz-text-foreground">
|
|
155
|
+
Editor
|
|
156
|
+
</h2>
|
|
157
|
+
|
|
158
|
+
<div class="maz-flex maz-flex-col maz-gap-2 mob-l:maz-flex-row">
|
|
159
|
+
<MazBtn
|
|
160
|
+
size="md"
|
|
161
|
+
block
|
|
162
|
+
color="secondary"
|
|
163
|
+
@click="resetTheme"
|
|
164
|
+
>
|
|
165
|
+
Reset theme
|
|
166
|
+
</MazBtn>
|
|
167
|
+
<MazBtn
|
|
168
|
+
size="md"
|
|
169
|
+
block
|
|
170
|
+
color="primary"
|
|
171
|
+
@click="exportTheme"
|
|
172
|
+
>
|
|
173
|
+
Export theme
|
|
174
|
+
</MazBtn>
|
|
175
|
+
</div>
|
|
176
|
+
|
|
177
|
+
<MazCard block title="Base preset">
|
|
178
|
+
<MazRadioButtons
|
|
179
|
+
:model-value="presetName"
|
|
180
|
+
size="sm"
|
|
181
|
+
:options="[
|
|
182
|
+
{
|
|
183
|
+
label: 'Maz-UI',
|
|
184
|
+
value: 'maz-ui',
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
label: 'Pristine',
|
|
188
|
+
value: 'pristine',
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
label: 'Ocean',
|
|
192
|
+
value: 'ocean',
|
|
193
|
+
}, {
|
|
194
|
+
label: 'Obsidian',
|
|
195
|
+
value: 'obsidian',
|
|
196
|
+
}]"
|
|
197
|
+
@update:model-value="updateTheme($event)"
|
|
198
|
+
/>
|
|
199
|
+
</MazCard>
|
|
200
|
+
|
|
201
|
+
<!-- Foundation Settings -->
|
|
202
|
+
<MazCard title="Foundation" block>
|
|
203
|
+
<div
|
|
204
|
+
class="maz-flex maz-flex-col maz-gap-3"
|
|
205
|
+
>
|
|
206
|
+
<template
|
|
207
|
+
v-for="input in foundationInputs"
|
|
208
|
+
:key="input.key"
|
|
209
|
+
>
|
|
210
|
+
<MazInput
|
|
211
|
+
v-model="themeData.foundation[input.key as keyof typeof themeData.foundation]"
|
|
212
|
+
:label="input.label"
|
|
213
|
+
:placeholder="input.placeholder"
|
|
214
|
+
size="sm"
|
|
215
|
+
block
|
|
216
|
+
debounce
|
|
217
|
+
/>
|
|
218
|
+
</template>
|
|
219
|
+
</div>
|
|
220
|
+
</MazCard>
|
|
221
|
+
|
|
222
|
+
<!-- Colors Settings -->
|
|
223
|
+
<MazCard block>
|
|
224
|
+
<template #title>
|
|
225
|
+
<div class="maz-flex maz-w-full maz-items-center maz-justify-between">
|
|
226
|
+
<h3 class="maz-text-base">
|
|
227
|
+
Colors
|
|
228
|
+
</h3>
|
|
229
|
+
|
|
230
|
+
<div class="maz-flex maz-items-center maz-gap-2">
|
|
231
|
+
<label for="dark-mode-switch" class="maz-cursor-pointer maz-text-sm">
|
|
232
|
+
Edit dark colors
|
|
233
|
+
</label>
|
|
234
|
+
<MazSwitch
|
|
235
|
+
id="dark-mode-switch"
|
|
236
|
+
:model-value="editingMode === 'dark'"
|
|
237
|
+
@update:model-value="editingMode = $event ? 'dark' : 'light'; handleThemeModeToggle()"
|
|
238
|
+
/>
|
|
239
|
+
</div>
|
|
240
|
+
</div>
|
|
241
|
+
</template>
|
|
242
|
+
|
|
243
|
+
<div class="maz-space-y-6">
|
|
244
|
+
<div
|
|
245
|
+
v-for="category in colorCategories"
|
|
246
|
+
:key="category.name"
|
|
247
|
+
class="maz-space-y-4"
|
|
248
|
+
>
|
|
249
|
+
<h4 class="maz-border-border maz-border-b maz-pb-2 maz-text-sm maz-font-semibold maz-text-foreground">
|
|
250
|
+
{{ category.name }}
|
|
251
|
+
</h4>
|
|
252
|
+
|
|
253
|
+
<div class="maz-grid maz-grid-cols-2 maz-gap-4">
|
|
254
|
+
<ColorPicker
|
|
255
|
+
v-for="colorKey in category.colors"
|
|
256
|
+
:key="`${editingMode}-${colorKey}`"
|
|
257
|
+
v-model="currentColors[colorKey]"
|
|
258
|
+
:label="formatColorName(colorKey)"
|
|
259
|
+
class="maz-w-full"
|
|
260
|
+
/>
|
|
261
|
+
</div>
|
|
262
|
+
</div>
|
|
263
|
+
</div>
|
|
264
|
+
</MazCard>
|
|
265
|
+
</div>
|
|
266
|
+
|
|
267
|
+
<!-- Preview Panel -->
|
|
268
|
+
<div class="lg:maz-col-span-8">
|
|
269
|
+
<div class="maz-sticky maz-top-4">
|
|
270
|
+
<div class="maz-mb-4 maz-flex maz-items-center maz-justify-between">
|
|
271
|
+
<h2 class="maz-text-2xl maz-text-foreground">
|
|
272
|
+
Preview
|
|
273
|
+
</h2>
|
|
274
|
+
</div>
|
|
275
|
+
|
|
276
|
+
<MazTabs v-model="currentTab">
|
|
277
|
+
<MazTabsBar
|
|
278
|
+
:items="['Dashboard', 'Product', 'Authentication']"
|
|
279
|
+
class="maz-mb-4"
|
|
280
|
+
/>
|
|
281
|
+
|
|
282
|
+
<MazTabsContent>
|
|
283
|
+
<MazTabsContentItem :tab="1">
|
|
284
|
+
<MazCard
|
|
285
|
+
bordered
|
|
286
|
+
:padding="false"
|
|
287
|
+
overflow-hidden
|
|
288
|
+
class="maz-max-h-[70vh] maz-w-full maz-overflow-y-auto"
|
|
289
|
+
>
|
|
290
|
+
<DemoDashboardPage :delay="0" />
|
|
291
|
+
</MazCard>
|
|
292
|
+
</MazTabsContentItem>
|
|
293
|
+
|
|
294
|
+
<MazTabsContentItem :tab="2">
|
|
295
|
+
<MazCard
|
|
296
|
+
bordered
|
|
297
|
+
:padding="false"
|
|
298
|
+
overflow-hidden
|
|
299
|
+
class="maz-max-h-[70vh] maz-w-full maz-overflow-y-auto"
|
|
300
|
+
>
|
|
301
|
+
<DemoProductPage />
|
|
302
|
+
</MazCard>
|
|
303
|
+
</MazTabsContentItem>
|
|
304
|
+
|
|
305
|
+
<MazTabsContentItem :tab="3">
|
|
306
|
+
<MazCard
|
|
307
|
+
bordered
|
|
308
|
+
:padding="false"
|
|
309
|
+
overflow-hidden
|
|
310
|
+
class="maz-max-h-[70vh] maz-w-full maz-overflow-y-auto"
|
|
311
|
+
>
|
|
312
|
+
<DemoAuthPage />
|
|
313
|
+
</MazCard>
|
|
314
|
+
</MazTabsContentItem>
|
|
315
|
+
</MazTabsContent>
|
|
316
|
+
</MazTabs>
|
|
317
|
+
</div>
|
|
318
|
+
</div>
|
|
319
|
+
</div>
|
|
320
|
+
|
|
321
|
+
<!-- Export Modal -->
|
|
322
|
+
<MazDialog v-model="showExportModal" scrollable title="Export Theme">
|
|
323
|
+
<div class="maz-space-y-4">
|
|
324
|
+
<p class="maz-text-muted">
|
|
325
|
+
Copy the generated TypeScript code below to use your custom theme:
|
|
326
|
+
</p>
|
|
327
|
+
|
|
328
|
+
<div class="maz-overflow-y-auto maz-rounded-md">
|
|
329
|
+
<div
|
|
330
|
+
v-if="highlightedCode"
|
|
331
|
+
class="shiki-wrapper"
|
|
332
|
+
v-html="highlightedCode"
|
|
333
|
+
/>
|
|
334
|
+
<div
|
|
335
|
+
v-else
|
|
336
|
+
class="maz-bg-contrast maz-p-4 dark:maz-bg-surface-300"
|
|
337
|
+
>
|
|
338
|
+
<pre class="maz-whitespace-pre-wrap maz-font-mono maz-text-xs maz-text-contrast-foreground dark:maz-text-surface-foreground">{{ exportedCode }}</pre>
|
|
339
|
+
</div>
|
|
340
|
+
</div>
|
|
341
|
+
</div>
|
|
342
|
+
|
|
343
|
+
<template #footer>
|
|
344
|
+
<div class="maz-flex maz-gap-2">
|
|
345
|
+
<MazBtn color="primary" @click="copyToClipboard(exportedCode)">
|
|
346
|
+
Copy to Clipboard
|
|
347
|
+
</MazBtn>
|
|
348
|
+
</div>
|
|
349
|
+
</template>
|
|
350
|
+
</MazDialog>
|
|
351
|
+
</div>
|
|
352
|
+
</template>
|
|
353
|
+
|
|
354
|
+
<style lang="postcss" scoped>
|
|
355
|
+
@media (max-width: 1024px) {
|
|
356
|
+
.theme-configurator {
|
|
357
|
+
@apply maz-space-y-8;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.theme-configurator .maz-sticky {
|
|
361
|
+
@apply maz-static;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
</style>
|
|
365
|
+
|
|
366
|
+
<style lang="postcss">
|
|
367
|
+
/* Global styles to disable transitions during theme mode switch */
|
|
368
|
+
.no-transitions *,
|
|
369
|
+
.no-transitions *::before,
|
|
370
|
+
.no-transitions *::after {
|
|
371
|
+
transition-duration: 0ms !important;
|
|
372
|
+
transition-delay: 0ms !important;
|
|
373
|
+
animation-duration: 0ms !important;
|
|
374
|
+
animation-delay: 0ms !important;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/* Shiki code highlighting styles */
|
|
378
|
+
.shiki-wrapper {
|
|
379
|
+
@apply maz-rounded-md maz-overflow-hidden maz-bg-contrast dark:maz-bg-surface-400;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.shiki-wrapper pre {
|
|
383
|
+
@apply maz-p-4 maz-m-0 maz-text-xs maz-overflow-x-auto;
|
|
384
|
+
font-family: 'Fira Code', 'Consolas', 'Monaco', monospace !important;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
.shiki-wrapper code {
|
|
388
|
+
@apply maz-text-xs;
|
|
389
|
+
font-family: 'Fira Code', 'Consolas', 'Monaco', monospace !important;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/* Override shiki background to match theme */
|
|
393
|
+
.shiki-wrapper .shiki {
|
|
394
|
+
background-color: transparent !important;
|
|
395
|
+
}
|
|
396
|
+
</style>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: vClickOutside
|
|
3
|
-
description: vClickOutside is a Vue
|
|
3
|
+
description: vClickOutside is a Vue directive to trigger a function when the user clicks outside an element
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# {{ $frontmatter.title }}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: vLazyImg
|
|
3
|
-
description: vLazyImg is a Vue
|
|
3
|
+
description: vLazyImg is a Vue directive to lazy load images with many options. The image will be loaded on user's scroll
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# {{ $frontmatter.title }}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: vZoomImg
|
|
3
|
-
description: vZoomImg is a Vue
|
|
3
|
+
description: vZoomImg is a Vue directive to enlarge an image like a modal on click, if you have several images, you can pass them like a carousel
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# {{ $frontmatter.title }}
|
|
@@ -4,7 +4,7 @@ description: Build Vue and Nuxt applications faster with Maz-UI v4 - The modern,
|
|
|
4
4
|
head:
|
|
5
5
|
- - meta
|
|
6
6
|
- name: keywords
|
|
7
|
-
content: vue ui library, vue components, nuxt ui, maz-ui installation, vue
|
|
7
|
+
content: vue ui library, vue components, nuxt ui, maz-ui installation, components, nuxt, vue, themes, translations, icons, mcp, maz-ui
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# {{ $frontmatter.title }}
|
package/docs/src/guide/icons.md
CHANGED
|
@@ -73,7 +73,7 @@ import { MazCheck, MazHeart, MazUser } from '@maz-ui/icons'
|
|
|
73
73
|
|
|
74
74
|
- ✅ Tree-shaking - Only bundled icons are included
|
|
75
75
|
- ✅ TypeScript support with full IntelliSense
|
|
76
|
-
- ✅ Vue
|
|
76
|
+
- ✅ Vue optimized with `defineAsyncComponent`
|
|
77
77
|
- ✅ Easy to style with CSS classes
|
|
78
78
|
|
|
79
79
|
### Method 2: Auto-import with Resolver
|
|
@@ -70,7 +70,7 @@ v4.0.0 separates functionality into specialized packages for better modularity:
|
|
|
70
70
|
| **@maz-ui/utils** | JavaScript/TypeScript utilities | New |
|
|
71
71
|
| **@maz-ui/icons** | SVG icons and flags (840+ icons) | New |
|
|
72
72
|
| **@maz-ui/cli** | CLI for theme generation | Renamed |
|
|
73
|
-
| **@maz-ui/nuxt** | Nuxt
|
|
73
|
+
| **@maz-ui/nuxt** | Nuxt module | New |
|
|
74
74
|
| **@maz-ui/mcp** | MCP server for IA agent | New |
|
|
75
75
|
|
|
76
76
|
## Migration Checklist
|
|
@@ -903,8 +903,8 @@ app.use(MazUi)
|
|
|
903
903
|
- **[Official v4 Documentation](https://maz-ui.com)** - Complete documentation
|
|
904
904
|
- **[Theme Guide](/guide/themes)** - Advanced theme system
|
|
905
905
|
- **[Translation Guide](/guide/translations)** - Internationalization
|
|
906
|
-
- **[Vue Installation Guide](/guide/vue)** - Vue
|
|
907
|
-
- **[Nuxt Installation Guide](/guide/nuxt)** - Nuxt
|
|
906
|
+
- **[Vue Installation Guide](/guide/vue)** - Vue setup
|
|
907
|
+
- **[Nuxt Installation Guide](/guide/nuxt)** - Nuxt setup
|
|
908
908
|
- **[Resolvers Guide](/guide/resolvers)** - Smart auto-imports
|
|
909
909
|
- **[Complete Changelog](https://github.com/LouisMazel/maz-ui/blob/master/CHANGELOG.md)** - All changes
|
|
910
910
|
|
package/docs/src/guide/themes.md
CHANGED
|
@@ -19,6 +19,10 @@ description: Modern and performant theme system for Maz-UI with TypeScript, HSL
|
|
|
19
19
|
- **Zero FOUC** - Critical CSS injected inline to avoid flashes
|
|
20
20
|
- **Flexible Presets** - Ready-to-use and customizable configurations
|
|
21
21
|
|
|
22
|
+
## Theme Editor
|
|
23
|
+
|
|
24
|
+
Create your own theme with the [Theme Editor](./../theme-editor.md).
|
|
25
|
+
|
|
22
26
|
## Quick Usage
|
|
23
27
|
|
|
24
28
|
### 1. Plugin Configuration with `MazUi` plugin
|
package/docs/src/index.md
CHANGED
|
@@ -435,7 +435,7 @@ description: Build amazing interfaces with Maz-UI - standalone components & tool
|
|
|
435
435
|
</div>
|
|
436
436
|
<h3 class="maz-text-base maz-font-semibold">useFormValidator</h3>
|
|
437
437
|
<p class="dark:maz-text-gray-300 maz-text-muted maz-text-sm">
|
|
438
|
-
A Vue
|
|
438
|
+
A Vue composable designed to simplify form validation using Valibot as the validation library. Offers a flexible and typed approach to handle form validation.
|
|
439
439
|
</p>
|
|
440
440
|
<div class="maz-flex-1"></div>
|
|
441
441
|
<MazBtn color="background" outlined size="sm" block href="/composables/use-form-validator">Discover</MazBtn>
|
|
@@ -491,7 +491,7 @@ description: Build amazing interfaces with Maz-UI - standalone components & tool
|
|
|
491
491
|
</div>
|
|
492
492
|
<h3 class="maz-text-base maz-font-semibold">useDisplayNames</h3>
|
|
493
493
|
<p class="dark:maz-text-gray-300 maz-text-muted maz-text-sm">
|
|
494
|
-
A Vue
|
|
494
|
+
A Vue composable that provides functions to work with localized display names based on ISO codes, leveraging the Intl.DisplayNames API.
|
|
495
495
|
</p>
|
|
496
496
|
<div class="maz-flex-1"></div>
|
|
497
497
|
<MazBtn color="background" outlined size="sm" block href="/composables/use-display-names">Discover</MazBtn>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Theme Editor
|
|
3
|
+
description: Create your own theme for maz-ui and export it to use it in your project
|
|
4
|
+
layout: home
|
|
5
|
+
sidebar: false
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
<br />
|
|
9
|
+
<br />
|
|
10
|
+
|
|
11
|
+
# {{ $frontmatter.title }}
|
|
12
|
+
|
|
13
|
+
{{ $frontmatter.description }}
|
|
14
|
+
|
|
15
|
+
<br />
|
|
16
|
+
|
|
17
|
+
<ThemeEditorPage />
|
|
18
|
+
|
|
19
|
+
<script setup lang="ts">
|
|
20
|
+
import ThemeEditorPage from './demo/ThemeEditorPage.vue'
|
|
21
|
+
</script>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maz-ui/mcp",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "4.1.
|
|
4
|
+
"version": "4.1.3",
|
|
5
5
|
"description": "Maz-UI ModelContextProtocol Client",
|
|
6
6
|
"author": "Louis Mazel <me@loicmazuel.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -58,8 +58,8 @@
|
|
|
58
58
|
"test:unit:coverage": "pnpm generate:docs && vitest run --coverage"
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"@maz-ui/node": "4.1.
|
|
62
|
-
"@maz-ui/utils": "4.1.
|
|
61
|
+
"@maz-ui/node": "4.1.3",
|
|
62
|
+
"@maz-ui/utils": "4.1.3",
|
|
63
63
|
"@modelcontextprotocol/sdk": "^1.17.2"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
@@ -80,5 +80,5 @@
|
|
|
80
80
|
"lint-staged": {
|
|
81
81
|
"*.{js,ts,mjs,mts,cjs,md,yml,json}": "cross-env NODE_ENV=production eslint --fix"
|
|
82
82
|
},
|
|
83
|
-
"gitHead": "
|
|
83
|
+
"gitHead": "09f62e1bb3a3faaaa1dc48ea6434f8da80a23d76"
|
|
84
84
|
}
|