diff --git a/.github/workflows/ci-edge.yaml b/.github/workflows/ci-edge.yaml
index 0ee98e9c..66225a03 100644
--- a/.github/workflows/ci-edge.yaml
+++ b/.github/workflows/ci-edge.yaml
@@ -29,6 +29,9 @@ jobs:
- name: 🚀 Prepare Edge
run: bun run dev:prepare
+ - name: 🎨 Run Tailwind
+ run: bun run tailwind
+
- name: 💅 Lint code
run: bun run lint
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index ccea222c..dcd408a6 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -29,6 +29,9 @@ jobs:
- name: 🚀 Prepare
run: bun run dev:prepare
+ - name: 🎨 Run Tailwind
+ run: bun run tailwind
+
- name: 💅 Lint code
run: bun run lint
diff --git a/bun.lockb b/bun.lockb
index 1db5c143..95b33314 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/packages/mockline/package.json b/packages/mockline/package.json
index 1ebf8536..04bfdea1 100644
--- a/packages/mockline/package.json
+++ b/packages/mockline/package.json
@@ -1,6 +1,6 @@
{
"name": "mockline",
- "version": "0.1.4",
+ "version": "0.1.5",
"type": "module",
"exports": {
".": {
@@ -39,6 +39,7 @@
"@tailwindcss/container-queries": "^0.1.1",
"@tailwindcss/forms": "^0.5.7",
"@tailwindcss/typography": "^0.5.14",
+ "@nuxt/schema": "^3.13.0",
"defu": "^6.1.4",
"pathe": "^1.1.2",
"radix-vue": "^1.9.4",
@@ -52,7 +53,6 @@
"devDependencies": {
"@nuxt/devtools": "^1.3.14",
"@nuxt/module-builder": "^0.8.3",
- "@nuxt/schema": "^3.12.4",
"@nuxt/test-utils": "^3.14.1",
"@types/node": "^20.16.1",
"changelogen": "^0.5.5",
diff --git a/packages/mockline/playground/app/pages/button.vue b/packages/mockline/playground/app/pages/button.vue
index 0121dfcc..13df7449 100644
--- a/packages/mockline/playground/app/pages/button.vue
+++ b/packages/mockline/playground/app/pages/button.vue
@@ -20,7 +20,11 @@ definePageMeta({
loading
@click="() => console.log('click')"
/>
-
+
({
colors: [],
transitions: false,
},
- async setup(options: ModuleOptions, nuxt): Promise {
+ async setup(options: ModuleOptions, nuxt: Nuxt): Promise {
const { resolve } = createResolver(import.meta.url)
// Transpile runtime
diff --git a/packages/mockline/src/output.css b/packages/mockline/src/output.css
index bce34762..a150018f 100644
--- a/packages/mockline/src/output.css
+++ b/packages/mockline/src/output.css
@@ -1,5 +1,5 @@
/*
-! tailwindcss v3.4.4 | MIT License | https://tailwindcss.com
+! tailwindcss v3.4.10 | MIT License | https://tailwindcss.com
*/
/*
@@ -574,10 +574,6 @@ video {
left: 0px;
}
-.right-2 {
- right: 0.5rem;
-}
-
.right-2\.5 {
right: 0.625rem;
}
@@ -586,10 +582,6 @@ video {
top: 0px;
}
-.top-2 {
- top: 0.5rem;
-}
-
.top-2\.5 {
top: 0.625rem;
}
@@ -1008,7 +1000,7 @@ video {
.backdrop-blur {
--tw-backdrop-blur: blur(8px);
-webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
- backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
+ backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
}
.transition-\[width\2c _height\] {
diff --git a/packages/mockline/src/runtime/components/elements/Button.vue b/packages/mockline/src/runtime/components/elements/Button.vue
index 94b466ee..0c9bb613 100644
--- a/packages/mockline/src/runtime/components/elements/Button.vue
+++ b/packages/mockline/src/runtime/components/elements/Button.vue
@@ -8,6 +8,7 @@ import theme from '#build/mockline/button'
@@ -59,8 +56,7 @@ const ui = computed(() => tv({ extend: button, slots: props.ui })({
:class="twMerge(ui.base({ class: props.class }))"
>
-
-
+
@@ -70,8 +66,7 @@ const ui = computed(() => tv({ extend: button, slots: props.ui })({
-
-
+
diff --git a/packages/mockline/src/runtime/composables/useComponentIcons.ts b/packages/mockline/src/runtime/composables/useComponentIcons.ts
new file mode 100644
index 00000000..0d7eed8d
--- /dev/null
+++ b/packages/mockline/src/runtime/composables/useComponentIcons.ts
@@ -0,0 +1,57 @@
+import { computed, toValue, type MaybeRefOrGetter, type ComputedRef } from 'vue'
+
+export type UseComponentIconsProps = {
+ /** Display an icon based on the `leading` and `trailing` props. */
+ icon?: string
+ /** When `true`, the icon will be displayed on the left side. */
+ leading?: boolean
+ /** Display an icon on the left side. */
+ leadingIcon?: string
+ /** When `true`, the icon will be displayed on the right side. */
+ trailing?: boolean
+ /** Display an icon on the right side. */
+ trailingIcon?: string
+ /** When `true`, the loading icon will be displayed. */
+ loading?: boolean
+ /**
+ * The icon when the `loading` prop is `true`.
+ * @defaultValue appConfig.ui.icons.loading
+ */
+ loadingIcon?: string
+}
+
+export type UseComponentIconsReturn = {
+ isLeading: ComputedRef
+ isTrailing: ComputedRef
+ leadingIconName: ComputedRef
+ trailingIconName: ComputedRef
+}
+
+export function useComponentIcons(componentProps: MaybeRefOrGetter): UseComponentIconsReturn {
+ const props = computed(() => toValue(componentProps))
+
+ const isLeading = computed(() => (props.value.icon && props.value.leading) || (props.value.icon && !props.value.trailing) || (props.value.loading && !props.value.trailing) || !!props.value.leadingIcon)
+ const isTrailing = computed(() => (props.value.icon && props.value.trailing) || (props.value.loading && props.value.trailing) || !!props.value.trailingIcon)
+
+ const leadingIconName = computed(() => {
+ if (props.value.loading) {
+ return props.value.loadingIcon || 'lucide:loader'
+ }
+
+ return props.value.leadingIcon || props.value.icon
+ })
+ const trailingIconName = computed(() => {
+ if (props.value.loading && !isLeading.value) {
+ return props.value.loadingIcon || 'lucide:loader'
+ }
+
+ return props.value.trailingIcon || props.value.icon
+ })
+
+ return {
+ isLeading,
+ isTrailing,
+ leadingIconName,
+ trailingIconName
+ }
+}
diff --git a/packages/mockline/src/tailwind.ts b/packages/mockline/src/tailwind.ts
index 13c9f8c5..55492828 100644
--- a/packages/mockline/src/tailwind.ts
+++ b/packages/mockline/src/tailwind.ts
@@ -11,7 +11,7 @@ import { colors, generateScale } from './runtime/utils/colors'
* @param nuxt - The Nuxt instance.
* @param resolve - Resolver function.
*/
-export async function installTailwind(options: ModuleOptions, nuxt: Nuxt, resolve = createResolver(import.meta.url).resolve): Promise {
+export async function installTailwind(options: ModuleOptions, nuxt: Nuxt, resolve = createResolver(process.env.url).resolve): Promise {
const runtimeDir = resolve('./runtime')
// Define the TailwindCSS configuration template
@@ -28,6 +28,7 @@ export async function installTailwind(options: ModuleOptions, nuxt: Nuxt, resolv
tailwindConfig,
join(nuxt.options.rootDir, 'tailwind.config'),
],
+ // @ts-expect-error: Nuxt does not provide a type for this option
}, nuxt.options.tailwindcss))
}