cisse-vue-ui 0.5.32 → 0.5.34
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/README.md +116 -0
- package/dist/{PageLayout.vue_vue_type_script_setup_true_lang-DTVojbLU.cjs → PageLayout.vue_vue_type_script_setup_true_lang-hhzpkC6_.cjs} +235 -3
- package/dist/PageLayout.vue_vue_type_script_setup_true_lang-hhzpkC6_.cjs.map +1 -0
- package/dist/{PageLayout.vue_vue_type_script_setup_true_lang-DcSTegL0.js → PageLayout.vue_vue_type_script_setup_true_lang-rMu1Z5uH.js} +239 -7
- package/dist/PageLayout.vue_vue_type_script_setup_true_lang-rMu1Z5uH.js.map +1 -0
- package/dist/components/index.cjs +4 -3
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +4 -3
- package/dist/components/layout/AuthLayout.stories.d.ts +10 -0
- package/dist/components/layout/AuthLayout.test.d.ts +1 -0
- package/dist/components/layout/AuthLayout.vue.d.ts +88 -0
- package/dist/components/layout/BaseLayout.stories.d.ts +2 -0
- package/dist/components/layout/index.cjs +4 -3
- package/dist/components/layout/index.cjs.map +1 -1
- package/dist/components/layout/index.d.ts +2 -0
- package/dist/components/layout/index.js +4 -3
- package/dist/index-BBUxkeI7.js +77 -0
- package/dist/index-BBUxkeI7.js.map +1 -0
- package/dist/{index-ChwvHG2L.cjs → index-BlwU8BWn.cjs} +5 -4
- package/dist/index-BlwU8BWn.cjs.map +1 -0
- package/dist/index.cjs +5 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +7 -6
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/dist/PageLayout.vue_vue_type_script_setup_true_lang-DTVojbLU.cjs.map +0 -1
- package/dist/PageLayout.vue_vue_type_script_setup_true_lang-DcSTegL0.js.map +0 -1
- package/dist/index-ChwvHG2L.cjs.map +0 -1
- package/dist/index-DaA7OpRC.js +0 -76
- package/dist/index-DaA7OpRC.js.map +0 -1
package/README.md
CHANGED
|
@@ -158,6 +158,7 @@ app.use(VueTailwindUI, { components: ['Button', 'CardComponent'] })
|
|
|
158
158
|
|
|
159
159
|
| Component | Description |
|
|
160
160
|
|-----------|-------------|
|
|
161
|
+
| `AuthLayout` | Split-panel authentication layout with branding and form sections |
|
|
161
162
|
| `BaseLayout` | App shell with sidebar, header, main content area, and route-aware menu |
|
|
162
163
|
| `PageLayout` | Page wrapper with breadcrumbs |
|
|
163
164
|
|
|
@@ -711,6 +712,92 @@ const menuItem = {
|
|
|
711
712
|
</template>
|
|
712
713
|
```
|
|
713
714
|
|
|
715
|
+
### AuthLayout
|
|
716
|
+
|
|
717
|
+
Split-panel layout for authentication pages (login, register, password reset).
|
|
718
|
+
|
|
719
|
+
```vue
|
|
720
|
+
<script setup>
|
|
721
|
+
import { ref } from 'vue'
|
|
722
|
+
import { AuthLayout, type AuthFeature } from 'cisse-vue-ui'
|
|
723
|
+
|
|
724
|
+
const email = ref('')
|
|
725
|
+
const password = ref('')
|
|
726
|
+
|
|
727
|
+
const features: AuthFeature[] = [
|
|
728
|
+
{ icon: 'lucide:shield', text: 'Secure authentication' },
|
|
729
|
+
{ icon: 'lucide:zap', text: 'Fast login' },
|
|
730
|
+
{ icon: 'lucide:users', text: 'Team collaboration' },
|
|
731
|
+
]
|
|
732
|
+
|
|
733
|
+
function handleSubmit() {
|
|
734
|
+
// Handle login
|
|
735
|
+
}
|
|
736
|
+
</script>
|
|
737
|
+
|
|
738
|
+
<template>
|
|
739
|
+
<AuthLayout
|
|
740
|
+
app-name="My App"
|
|
741
|
+
app-icon="lucide:box"
|
|
742
|
+
headline="Welcome to"
|
|
743
|
+
sub-headline="My Application"
|
|
744
|
+
description="Sign in to access your account."
|
|
745
|
+
:features="features"
|
|
746
|
+
form-title="Sign In"
|
|
747
|
+
form-subtitle="Enter your credentials"
|
|
748
|
+
home-link="/"
|
|
749
|
+
>
|
|
750
|
+
<form @submit.prevent="handleSubmit" class="space-y-4">
|
|
751
|
+
<input v-model="email" type="email" placeholder="Email" class="..." />
|
|
752
|
+
<input v-model="password" type="password" placeholder="Password" class="..." />
|
|
753
|
+
<button type="submit">Sign In</button>
|
|
754
|
+
</form>
|
|
755
|
+
|
|
756
|
+
<template #form-footer>
|
|
757
|
+
<p class="text-center mt-6">
|
|
758
|
+
Don't have an account? <a href="/register">Sign up</a>
|
|
759
|
+
</p>
|
|
760
|
+
</template>
|
|
761
|
+
</AuthLayout>
|
|
762
|
+
</template>
|
|
763
|
+
```
|
|
764
|
+
|
|
765
|
+
#### AuthLayout Props
|
|
766
|
+
|
|
767
|
+
| Prop | Type | Default | Description |
|
|
768
|
+
|------|------|---------|-------------|
|
|
769
|
+
| `appName` | `string` | `''` | Application name displayed in logo |
|
|
770
|
+
| `appIcon` | `string` | `'lucide:box'` | Iconify icon for app logo |
|
|
771
|
+
| `headline` | `string` | `''` | First line of headline |
|
|
772
|
+
| `subHeadline` | `string` | `''` | Second line with decorative underline |
|
|
773
|
+
| `description` | `string` | `''` | Description paragraph |
|
|
774
|
+
| `features` | `AuthFeature[]` | `[]` | List of features with icon and text |
|
|
775
|
+
| `gradientFrom` | `string` | `'from-primary-700'` | Tailwind gradient start class |
|
|
776
|
+
| `gradientVia` | `string` | `''` | Tailwind gradient middle class |
|
|
777
|
+
| `gradientTo` | `string` | `'to-primary-800'` | Tailwind gradient end class |
|
|
778
|
+
| `showDecorations` | `boolean` | `true` | Show floating decorative shapes |
|
|
779
|
+
| `showPattern` | `boolean` | `true` | Show dot pattern overlay |
|
|
780
|
+
| `underlineColor` | `string` | `'rgba(165, 180, 252, 0.5)'` | Sub-headline underline color |
|
|
781
|
+
| `formTitle` | `string` | `''` | Form panel title |
|
|
782
|
+
| `formSubtitle` | `string` | `''` | Form panel subtitle |
|
|
783
|
+
| `homeLink` | `string` | `'/'` | Mobile logo link URL |
|
|
784
|
+
| `brandingAnimation` | `string` | `''` | CSS class for branding animation |
|
|
785
|
+
| `formAnimation` | `string` | `''` | CSS class for form panel animation |
|
|
786
|
+
|
|
787
|
+
#### AuthLayout Slots
|
|
788
|
+
|
|
789
|
+
| Slot | Description |
|
|
790
|
+
|------|-------------|
|
|
791
|
+
| `default` | Form content (inside the white card) |
|
|
792
|
+
| `branding-panel` | Complete override of the branding panel |
|
|
793
|
+
| `branding-logo` | Custom logo in branding panel |
|
|
794
|
+
| `branding-headline` | Custom headline content |
|
|
795
|
+
| `branding-features` | Custom features list |
|
|
796
|
+
| `branding-content` | Additional content after features |
|
|
797
|
+
| `mobile-logo` | Custom mobile logo |
|
|
798
|
+
| `form-header` | Content above the form card |
|
|
799
|
+
| `form-footer` | Content below the form card |
|
|
800
|
+
|
|
714
801
|
### BaseLayout
|
|
715
802
|
|
|
716
803
|
```vue
|
|
@@ -732,6 +819,7 @@ const menuItems = [
|
|
|
732
819
|
:menu-items="menuItems"
|
|
733
820
|
:current-path="route.path"
|
|
734
821
|
:show-dark-toggle="true"
|
|
822
|
+
menu-position="top"
|
|
735
823
|
>
|
|
736
824
|
<template #logo>
|
|
737
825
|
<img src="/logo.svg" alt="Logo" class="h-8" />
|
|
@@ -742,6 +830,34 @@ const menuItems = [
|
|
|
742
830
|
</template>
|
|
743
831
|
```
|
|
744
832
|
|
|
833
|
+
#### BaseLayout Props
|
|
834
|
+
|
|
835
|
+
| Prop | Type | Default | Description |
|
|
836
|
+
|------|------|---------|-------------|
|
|
837
|
+
| `menuItems` | `MenuItemProps[]` | `[]` | Menu items for the sidebar |
|
|
838
|
+
| `appName` | `string` | `'App'` | App/brand name displayed in sidebar |
|
|
839
|
+
| `appIcon` | `string` | `'lucide:box'` | App icon (Iconify icon name) |
|
|
840
|
+
| `sidebarOpen` | `boolean` | `true` | Whether sidebar is open (v-model:sidebarOpen) |
|
|
841
|
+
| `dark` | `boolean` | `false` | Whether dark mode is enabled (v-model:dark) |
|
|
842
|
+
| `showDarkToggle` | `boolean` | `true` | Show dark mode toggle in header |
|
|
843
|
+
| `sidebarClass` | `string` | `'bg-[#172b4c]...'` | CSS classes for sidebar background |
|
|
844
|
+
| `currentPath` | `string` | - | Current route path for menu active state |
|
|
845
|
+
| `userName` | `string` | - | User display name |
|
|
846
|
+
| `userAvatar` | `string` | - | User avatar (initials or image URL) |
|
|
847
|
+
| `userMenuItems` | `UserMenuItem[]` | `[]` | User menu dropdown items |
|
|
848
|
+
| `menuPosition` | `'top' \| 'center' \| 'bottom'` | `'top'` | Menu vertical position in sidebar |
|
|
849
|
+
|
|
850
|
+
#### BaseLayout Slots
|
|
851
|
+
|
|
852
|
+
| Slot | Description |
|
|
853
|
+
|------|-------------|
|
|
854
|
+
| `default` | Main content area (or renders RouterView if available) |
|
|
855
|
+
| `logo` | Custom logo in sidebar header |
|
|
856
|
+
| `menu` | Custom menu content (receives currentPath) |
|
|
857
|
+
| `sidebar-footer` | Content at bottom of sidebar |
|
|
858
|
+
| `header-center` | Center content in header |
|
|
859
|
+
| `header-actions` | Action buttons in header (before dark toggle) |
|
|
860
|
+
|
|
745
861
|
## Dark Mode
|
|
746
862
|
|
|
747
863
|
Components support dark mode via the `.dark` class on a parent element:
|
|
@@ -2,6 +2,237 @@
|
|
|
2
2
|
const vue = require("vue");
|
|
3
3
|
const vue$1 = require("@iconify/vue");
|
|
4
4
|
const Dropdown_vue_vue_type_script_setup_true_lang = require("./Dropdown.vue_vue_type_script_setup_true_lang-BNOHbbm5.cjs");
|
|
5
|
+
const _hoisted_1$2 = { class: "flex min-h-screen" };
|
|
6
|
+
const _hoisted_2$2 = {
|
|
7
|
+
key: 0,
|
|
8
|
+
class: "absolute inset-0 overflow-hidden pointer-events-none"
|
|
9
|
+
};
|
|
10
|
+
const _hoisted_3$2 = {
|
|
11
|
+
key: 1,
|
|
12
|
+
class: "absolute inset-0 opacity-20 pointer-events-none",
|
|
13
|
+
style: { "background-image": "radial-gradient(circle, rgba(255,255,255,0.4) 1px, transparent 1px)", "background-size": "24px 24px" }
|
|
14
|
+
};
|
|
15
|
+
const _hoisted_4$2 = { class: "relative z-10 flex flex-col justify-center px-16 py-12 text-white w-full" };
|
|
16
|
+
const _hoisted_5$2 = { class: "flex items-center gap-3 mb-12" };
|
|
17
|
+
const _hoisted_6$2 = { class: "w-14 h-14 bg-white/20 backdrop-blur-sm rounded-2xl flex items-center justify-center" };
|
|
18
|
+
const _hoisted_7$2 = {
|
|
19
|
+
key: 0,
|
|
20
|
+
class: "text-3xl font-bold"
|
|
21
|
+
};
|
|
22
|
+
const _hoisted_8$2 = {
|
|
23
|
+
key: 0,
|
|
24
|
+
class: "text-4xl xl:text-5xl font-bold leading-tight mb-6"
|
|
25
|
+
};
|
|
26
|
+
const _hoisted_9$2 = {
|
|
27
|
+
key: 1,
|
|
28
|
+
class: "relative inline-block"
|
|
29
|
+
};
|
|
30
|
+
const _hoisted_10$2 = { class: "relative z-10" };
|
|
31
|
+
const _hoisted_11$1 = {
|
|
32
|
+
class: "absolute -bottom-2 left-0 w-full",
|
|
33
|
+
viewBox: "0 0 280 12",
|
|
34
|
+
fill: "none",
|
|
35
|
+
preserveAspectRatio: "none"
|
|
36
|
+
};
|
|
37
|
+
const _hoisted_12$1 = ["stroke"];
|
|
38
|
+
const _hoisted_13$1 = {
|
|
39
|
+
key: 0,
|
|
40
|
+
class: "text-lg text-white/80 max-w-md mb-10"
|
|
41
|
+
};
|
|
42
|
+
const _hoisted_14$1 = {
|
|
43
|
+
key: 0,
|
|
44
|
+
class: "space-y-4"
|
|
45
|
+
};
|
|
46
|
+
const _hoisted_15$1 = { class: "w-10 h-10 rounded-xl bg-white/10 backdrop-blur-sm flex items-center justify-center shrink-0" };
|
|
47
|
+
const _hoisted_16 = { class: "flex-1 flex items-center justify-center p-6 sm:p-12 bg-gradient-to-br from-gray-50 to-gray-100 dark:from-slate-900 dark:to-slate-800" };
|
|
48
|
+
const _hoisted_17 = { class: "lg:hidden text-center mb-8" };
|
|
49
|
+
const _hoisted_18 = { class: "w-12 h-12 bg-primary-600 rounded-xl flex items-center justify-center shadow-lg shadow-primary-200 dark:shadow-primary-900/30" };
|
|
50
|
+
const _hoisted_19 = {
|
|
51
|
+
key: 0,
|
|
52
|
+
class: "text-2xl font-bold text-gray-900 dark:text-white"
|
|
53
|
+
};
|
|
54
|
+
const _hoisted_20 = {
|
|
55
|
+
key: 0,
|
|
56
|
+
class: "text-center lg:text-left mb-8"
|
|
57
|
+
};
|
|
58
|
+
const _hoisted_21 = {
|
|
59
|
+
key: 0,
|
|
60
|
+
class: "text-2xl sm:text-3xl font-bold text-gray-900 dark:text-white mb-2"
|
|
61
|
+
};
|
|
62
|
+
const _hoisted_22 = {
|
|
63
|
+
key: 1,
|
|
64
|
+
class: "text-gray-600 dark:text-gray-400"
|
|
65
|
+
};
|
|
66
|
+
const _hoisted_23 = { class: "bg-white dark:bg-slate-800/80 rounded-3xl shadow-xl shadow-gray-200/50 dark:shadow-none p-8" };
|
|
67
|
+
const _sfc_main$2 = /* @__PURE__ */ vue.defineComponent({
|
|
68
|
+
__name: "AuthLayout",
|
|
69
|
+
props: {
|
|
70
|
+
appName: { default: "" },
|
|
71
|
+
appIcon: { default: "lucide:box" },
|
|
72
|
+
headline: { default: "" },
|
|
73
|
+
subHeadline: { default: "" },
|
|
74
|
+
description: { default: "" },
|
|
75
|
+
features: { default: () => [] },
|
|
76
|
+
gradientFrom: { default: "from-primary-700" },
|
|
77
|
+
gradientVia: { default: "" },
|
|
78
|
+
gradientTo: { default: "to-primary-800" },
|
|
79
|
+
showDecorations: { type: Boolean, default: true },
|
|
80
|
+
showPattern: { type: Boolean, default: true },
|
|
81
|
+
underlineColor: { default: "rgba(165, 180, 252, 0.5)" },
|
|
82
|
+
formTitle: { default: "" },
|
|
83
|
+
formSubtitle: { default: "" },
|
|
84
|
+
homeLink: { default: "/" },
|
|
85
|
+
brandingAnimation: { default: "" },
|
|
86
|
+
formAnimation: { default: "" }
|
|
87
|
+
},
|
|
88
|
+
setup(__props) {
|
|
89
|
+
const props = __props;
|
|
90
|
+
const slots = vue.useSlots();
|
|
91
|
+
const hasBrandingContent = vue.computed(() => {
|
|
92
|
+
return props.headline || props.subHeadline || props.description || props.features.length > 0 || slots["branding-logo"] || slots["branding-headline"] || slots["branding-content"] || props.appName;
|
|
93
|
+
});
|
|
94
|
+
const routerLinkComponent = vue.computed(() => {
|
|
95
|
+
try {
|
|
96
|
+
const RouterLink = vue.resolveComponent("RouterLink");
|
|
97
|
+
if (typeof RouterLink !== "string") {
|
|
98
|
+
return RouterLink;
|
|
99
|
+
}
|
|
100
|
+
} catch {
|
|
101
|
+
}
|
|
102
|
+
return "a";
|
|
103
|
+
});
|
|
104
|
+
const getLinkProps = (link) => {
|
|
105
|
+
if (routerLinkComponent.value === "a") {
|
|
106
|
+
return { href: link };
|
|
107
|
+
}
|
|
108
|
+
return { to: link };
|
|
109
|
+
};
|
|
110
|
+
const gradientClasses = vue.computed(() => {
|
|
111
|
+
const classes = [props.gradientFrom, props.gradientTo];
|
|
112
|
+
if (props.gradientVia) {
|
|
113
|
+
classes.splice(1, 0, props.gradientVia);
|
|
114
|
+
}
|
|
115
|
+
return classes.filter(Boolean);
|
|
116
|
+
});
|
|
117
|
+
return (_ctx, _cache) => {
|
|
118
|
+
return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$2, [
|
|
119
|
+
hasBrandingContent.value || _ctx.$slots["branding-panel"] ? (vue.openBlock(), vue.createElementBlock("div", {
|
|
120
|
+
key: 0,
|
|
121
|
+
class: vue.normalizeClass([
|
|
122
|
+
"hidden lg:flex lg:w-1/2 relative overflow-hidden bg-gradient-to-br",
|
|
123
|
+
...gradientClasses.value
|
|
124
|
+
])
|
|
125
|
+
}, [
|
|
126
|
+
vue.renderSlot(_ctx.$slots, "branding-panel", {}, () => [
|
|
127
|
+
__props.showDecorations ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_2$2, [..._cache[0] || (_cache[0] = [
|
|
128
|
+
vue.createElementVNode("div", { class: "absolute -top-20 -left-20 w-80 h-80 bg-white/5 rounded-full blur-3xl" }, null, -1),
|
|
129
|
+
vue.createElementVNode("div", { class: "absolute top-1/3 right-10 w-60 h-60 bg-white/5 rounded-full blur-3xl" }, null, -1),
|
|
130
|
+
vue.createElementVNode("div", { class: "absolute bottom-20 left-1/4 w-72 h-72 bg-white/5 rounded-full blur-3xl" }, null, -1)
|
|
131
|
+
])])) : vue.createCommentVNode("", true),
|
|
132
|
+
__props.showPattern ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_3$2)) : vue.createCommentVNode("", true),
|
|
133
|
+
__props.showDecorations ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 2 }, [
|
|
134
|
+
_cache[1] || (_cache[1] = vue.createElementVNode("div", { class: "absolute top-20 right-20 w-16 h-16 border-2 border-white/20 rounded-2xl rotate-12 pointer-events-none" }, null, -1)),
|
|
135
|
+
_cache[2] || (_cache[2] = vue.createElementVNode("div", { class: "absolute bottom-32 left-16 w-12 h-12 border-2 border-white/20 rounded-full pointer-events-none" }, null, -1)),
|
|
136
|
+
_cache[3] || (_cache[3] = vue.createElementVNode("div", { class: "absolute top-1/2 left-10 w-8 h-8 bg-white/10 rounded-lg rotate-45 pointer-events-none" }, null, -1))
|
|
137
|
+
], 64)) : vue.createCommentVNode("", true),
|
|
138
|
+
vue.createElementVNode("div", _hoisted_4$2, [
|
|
139
|
+
vue.createElementVNode("div", {
|
|
140
|
+
class: vue.normalizeClass(__props.brandingAnimation)
|
|
141
|
+
}, [
|
|
142
|
+
vue.createElementVNode("div", _hoisted_5$2, [
|
|
143
|
+
vue.renderSlot(_ctx.$slots, "branding-logo", {}, () => [
|
|
144
|
+
__props.appName || __props.appIcon ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
|
|
145
|
+
vue.createElementVNode("div", _hoisted_6$2, [
|
|
146
|
+
vue.createVNode(vue.unref(vue$1.Icon), {
|
|
147
|
+
icon: __props.appIcon,
|
|
148
|
+
class: "w-8 h-8 text-white"
|
|
149
|
+
}, null, 8, ["icon"])
|
|
150
|
+
]),
|
|
151
|
+
__props.appName ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_7$2, vue.toDisplayString(__props.appName), 1)) : vue.createCommentVNode("", true)
|
|
152
|
+
], 64)) : vue.createCommentVNode("", true)
|
|
153
|
+
])
|
|
154
|
+
]),
|
|
155
|
+
vue.renderSlot(_ctx.$slots, "branding-headline", {}, () => [
|
|
156
|
+
__props.headline || __props.subHeadline ? (vue.openBlock(), vue.createElementBlock("h1", _hoisted_8$2, [
|
|
157
|
+
__props.headline ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
|
|
158
|
+
vue.createTextVNode(vue.toDisplayString(__props.headline), 1),
|
|
159
|
+
_cache[4] || (_cache[4] = vue.createElementVNode("br", null, null, -1))
|
|
160
|
+
], 64)) : vue.createCommentVNode("", true),
|
|
161
|
+
__props.subHeadline ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_9$2, [
|
|
162
|
+
vue.createElementVNode("span", _hoisted_10$2, vue.toDisplayString(__props.subHeadline), 1),
|
|
163
|
+
(vue.openBlock(), vue.createElementBlock("svg", _hoisted_11$1, [
|
|
164
|
+
vue.createElementVNode("path", {
|
|
165
|
+
d: "M2 10C45 4 90 2 140 6C190 10 235 4 278 8",
|
|
166
|
+
stroke: __props.underlineColor,
|
|
167
|
+
"stroke-width": "4",
|
|
168
|
+
"stroke-linecap": "round"
|
|
169
|
+
}, null, 8, _hoisted_12$1)
|
|
170
|
+
]))
|
|
171
|
+
])) : vue.createCommentVNode("", true)
|
|
172
|
+
])) : vue.createCommentVNode("", true)
|
|
173
|
+
]),
|
|
174
|
+
__props.description ? (vue.openBlock(), vue.createElementBlock("p", _hoisted_13$1, vue.toDisplayString(__props.description), 1)) : vue.createCommentVNode("", true),
|
|
175
|
+
vue.renderSlot(_ctx.$slots, "branding-features", {}, () => [
|
|
176
|
+
__props.features.length > 0 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_14$1, [
|
|
177
|
+
(vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(__props.features, (feature, index) => {
|
|
178
|
+
return vue.openBlock(), vue.createElementBlock("div", {
|
|
179
|
+
key: index,
|
|
180
|
+
class: "flex items-center gap-3 text-white/90"
|
|
181
|
+
}, [
|
|
182
|
+
vue.createElementVNode("div", _hoisted_15$1, [
|
|
183
|
+
vue.createVNode(vue.unref(vue$1.Icon), {
|
|
184
|
+
icon: feature.icon,
|
|
185
|
+
class: "w-5 h-5"
|
|
186
|
+
}, null, 8, ["icon"])
|
|
187
|
+
]),
|
|
188
|
+
vue.createElementVNode("span", null, vue.toDisplayString(feature.text), 1)
|
|
189
|
+
]);
|
|
190
|
+
}), 128))
|
|
191
|
+
])) : vue.createCommentVNode("", true)
|
|
192
|
+
]),
|
|
193
|
+
vue.renderSlot(_ctx.$slots, "branding-content")
|
|
194
|
+
], 2)
|
|
195
|
+
])
|
|
196
|
+
])
|
|
197
|
+
], 2)) : vue.createCommentVNode("", true),
|
|
198
|
+
vue.createElementVNode("div", _hoisted_16, [
|
|
199
|
+
vue.createElementVNode("div", {
|
|
200
|
+
class: vue.normalizeClass(["w-full max-w-md", __props.formAnimation])
|
|
201
|
+
}, [
|
|
202
|
+
vue.createElementVNode("div", _hoisted_17, [
|
|
203
|
+
(vue.openBlock(), vue.createBlock(vue.resolveDynamicComponent(routerLinkComponent.value), vue.mergeProps(getLinkProps(__props.homeLink), { class: "inline-flex items-center gap-3" }), {
|
|
204
|
+
default: vue.withCtx(() => [
|
|
205
|
+
vue.renderSlot(_ctx.$slots, "mobile-logo", {}, () => [
|
|
206
|
+
__props.appName || __props.appIcon ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
|
|
207
|
+
vue.createElementVNode("div", _hoisted_18, [
|
|
208
|
+
vue.createVNode(vue.unref(vue$1.Icon), {
|
|
209
|
+
icon: __props.appIcon,
|
|
210
|
+
class: "w-6 h-6 text-white"
|
|
211
|
+
}, null, 8, ["icon"])
|
|
212
|
+
]),
|
|
213
|
+
__props.appName ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_19, vue.toDisplayString(__props.appName), 1)) : vue.createCommentVNode("", true)
|
|
214
|
+
], 64)) : vue.createCommentVNode("", true)
|
|
215
|
+
])
|
|
216
|
+
]),
|
|
217
|
+
_: 3
|
|
218
|
+
}, 16))
|
|
219
|
+
]),
|
|
220
|
+
vue.renderSlot(_ctx.$slots, "form-header", {}, () => [
|
|
221
|
+
__props.formTitle || __props.formSubtitle ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_20, [
|
|
222
|
+
__props.formTitle ? (vue.openBlock(), vue.createElementBlock("h2", _hoisted_21, vue.toDisplayString(__props.formTitle), 1)) : vue.createCommentVNode("", true),
|
|
223
|
+
__props.formSubtitle ? (vue.openBlock(), vue.createElementBlock("p", _hoisted_22, vue.toDisplayString(__props.formSubtitle), 1)) : vue.createCommentVNode("", true)
|
|
224
|
+
])) : vue.createCommentVNode("", true)
|
|
225
|
+
]),
|
|
226
|
+
vue.createElementVNode("div", _hoisted_23, [
|
|
227
|
+
vue.renderSlot(_ctx.$slots, "default")
|
|
228
|
+
]),
|
|
229
|
+
vue.renderSlot(_ctx.$slots, "form-footer")
|
|
230
|
+
], 2)
|
|
231
|
+
])
|
|
232
|
+
]);
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
});
|
|
5
236
|
const _hoisted_1$1 = { class: "font-inter relative flex h-dvh overflow-hidden bg-gray-100 dark:bg-slate-900" };
|
|
6
237
|
const _hoisted_2$1 = { class: "flex h-16 items-center px-3" };
|
|
7
238
|
const _hoisted_3$1 = { class: "flex flex-1 items-center justify-center gap-3" };
|
|
@@ -340,6 +571,7 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
|
|
|
340
571
|
};
|
|
341
572
|
}
|
|
342
573
|
});
|
|
343
|
-
exports._sfc_main = _sfc_main$
|
|
344
|
-
exports._sfc_main$1 = _sfc_main;
|
|
345
|
-
|
|
574
|
+
exports._sfc_main = _sfc_main$2;
|
|
575
|
+
exports._sfc_main$1 = _sfc_main$1;
|
|
576
|
+
exports._sfc_main$2 = _sfc_main;
|
|
577
|
+
//# sourceMappingURL=PageLayout.vue_vue_type_script_setup_true_lang-hhzpkC6_.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PageLayout.vue_vue_type_script_setup_true_lang-hhzpkC6_.cjs","sources":["../src/components/layout/AuthLayout.vue","../src/components/layout/BaseLayout.vue","../src/components/layout/PageLayout.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport { computed, resolveComponent, useSlots } from 'vue'\nimport { Icon } from '@iconify/vue'\n\n/**\n * Feature item for the branding panel\n */\nexport interface AuthFeature {\n /** Iconify icon name */\n icon: string\n /** Feature text */\n text: string\n}\n\nconst props = withDefaults(defineProps<{\n /** App/brand name (used in default logo slots) */\n appName?: string\n /** App icon - Iconify icon name (used in default logo slots) */\n appIcon?: string\n /** Headline text (first line) */\n headline?: string\n /** Sub-headline text (second line, with optional underline) */\n subHeadline?: string\n /** Description paragraph below headlines */\n description?: string\n /** List of features to display in branding panel */\n features?: AuthFeature[]\n /** Primary gradient from color (Tailwind class) */\n gradientFrom?: string\n /** Primary gradient via color (Tailwind class, optional) */\n gradientVia?: string\n /** Primary gradient to color (Tailwind class) */\n gradientTo?: string\n /** Show decorative floating shapes and blurs */\n showDecorations?: boolean\n /** Show dot pattern overlay on branding panel */\n showPattern?: boolean\n /** Underline accent color for sub-headline (CSS color value) */\n underlineColor?: string\n /** Form panel title */\n formTitle?: string\n /** Form panel subtitle */\n formSubtitle?: string\n /** Home link URL (used for mobile logo link) */\n homeLink?: string\n /** CSS animation class for branding content entry */\n brandingAnimation?: string\n /** CSS animation class for form panel entry */\n formAnimation?: string\n}>(), {\n appName: '',\n appIcon: 'lucide:box',\n headline: '',\n subHeadline: '',\n description: '',\n features: () => [],\n gradientFrom: 'from-primary-700',\n gradientVia: '',\n gradientTo: 'to-primary-800',\n showDecorations: true,\n showPattern: true,\n underlineColor: 'rgba(165, 180, 252, 0.5)',\n formTitle: '',\n formSubtitle: '',\n homeLink: '/',\n brandingAnimation: '',\n formAnimation: '',\n})\n\nconst slots = useSlots()\n\n// Check if branding panel has any content\nconst hasBrandingContent = computed(() => {\n return props.headline ||\n props.subHeadline ||\n props.description ||\n props.features.length > 0 ||\n slots['branding-logo'] ||\n slots['branding-headline'] ||\n slots['branding-content'] ||\n props.appName\n})\n\n// Try to resolve RouterLink (works with Vue Router)\nconst routerLinkComponent = computed(() => {\n try {\n const RouterLink = resolveComponent('RouterLink')\n if (typeof RouterLink !== 'string') {\n return RouterLink\n }\n } catch {\n // RouterLink not available\n }\n return 'a'\n})\n\nconst getLinkProps = (link: string) => {\n if (routerLinkComponent.value === 'a') {\n return { href: link }\n }\n return { to: link }\n}\n\nconst gradientClasses = computed(() => {\n const classes = [props.gradientFrom, props.gradientTo]\n if (props.gradientVia) {\n classes.splice(1, 0, props.gradientVia)\n }\n return classes.filter(Boolean)\n})\n</script>\n\n<template>\n <div class=\"flex min-h-screen\">\n <!-- Left Panel - Branding (hidden on mobile) -->\n <div\n v-if=\"hasBrandingContent || $slots['branding-panel']\"\n :class=\"[\n 'hidden lg:flex lg:w-1/2 relative overflow-hidden bg-gradient-to-br',\n ...gradientClasses,\n ]\"\n >\n <!-- Allow complete customization of branding panel -->\n <slot name=\"branding-panel\">\n <!-- Decorative floating blurs -->\n <div\n v-if=\"showDecorations\"\n class=\"absolute inset-0 overflow-hidden pointer-events-none\"\n >\n <div class=\"absolute -top-20 -left-20 w-80 h-80 bg-white/5 rounded-full blur-3xl\" />\n <div class=\"absolute top-1/3 right-10 w-60 h-60 bg-white/5 rounded-full blur-3xl\" />\n <div class=\"absolute bottom-20 left-1/4 w-72 h-72 bg-white/5 rounded-full blur-3xl\" />\n </div>\n\n <!-- Dot pattern -->\n <div\n v-if=\"showPattern\"\n class=\"absolute inset-0 opacity-20 pointer-events-none\"\n style=\"background-image: radial-gradient(circle, rgba(255,255,255,0.4) 1px, transparent 1px); background-size: 24px 24px;\"\n />\n\n <!-- Floating decorative shapes -->\n <template v-if=\"showDecorations\">\n <div class=\"absolute top-20 right-20 w-16 h-16 border-2 border-white/20 rounded-2xl rotate-12 pointer-events-none\" />\n <div class=\"absolute bottom-32 left-16 w-12 h-12 border-2 border-white/20 rounded-full pointer-events-none\" />\n <div class=\"absolute top-1/2 left-10 w-8 h-8 bg-white/10 rounded-lg rotate-45 pointer-events-none\" />\n </template>\n\n <!-- Content -->\n <div class=\"relative z-10 flex flex-col justify-center px-16 py-12 text-white w-full\">\n <div :class=\"brandingAnimation\">\n <!-- Logo -->\n <div class=\"flex items-center gap-3 mb-12\">\n <slot name=\"branding-logo\">\n <template v-if=\"appName || appIcon\">\n <div class=\"w-14 h-14 bg-white/20 backdrop-blur-sm rounded-2xl flex items-center justify-center\">\n <Icon\n :icon=\"appIcon\"\n class=\"w-8 h-8 text-white\"\n />\n </div>\n <span\n v-if=\"appName\"\n class=\"text-3xl font-bold\"\n >\n {{ appName }}\n </span>\n </template>\n </slot>\n </div>\n\n <!-- Headlines -->\n <slot name=\"branding-headline\">\n <h1\n v-if=\"headline || subHeadline\"\n class=\"text-4xl xl:text-5xl font-bold leading-tight mb-6\"\n >\n <template v-if=\"headline\">\n {{ headline }}<br>\n </template>\n <span\n v-if=\"subHeadline\"\n class=\"relative inline-block\"\n >\n <span class=\"relative z-10\">{{ subHeadline }}</span>\n <svg\n class=\"absolute -bottom-2 left-0 w-full\"\n viewBox=\"0 0 280 12\"\n fill=\"none\"\n preserveAspectRatio=\"none\"\n >\n <path\n d=\"M2 10C45 4 90 2 140 6C190 10 235 4 278 8\"\n :stroke=\"underlineColor\"\n stroke-width=\"4\"\n stroke-linecap=\"round\"\n />\n </svg>\n </span>\n </h1>\n </slot>\n\n <!-- Description -->\n <p\n v-if=\"description\"\n class=\"text-lg text-white/80 max-w-md mb-10\"\n >\n {{ description }}\n </p>\n\n <!-- Features list -->\n <slot name=\"branding-features\">\n <div\n v-if=\"features.length > 0\"\n class=\"space-y-4\"\n >\n <div\n v-for=\"(feature, index) in features\"\n :key=\"index\"\n class=\"flex items-center gap-3 text-white/90\"\n >\n <div class=\"w-10 h-10 rounded-xl bg-white/10 backdrop-blur-sm flex items-center justify-center shrink-0\">\n <Icon\n :icon=\"feature.icon\"\n class=\"w-5 h-5\"\n />\n </div>\n <span>{{ feature.text }}</span>\n </div>\n </div>\n </slot>\n\n <!-- Additional branding content -->\n <slot name=\"branding-content\" />\n </div>\n </div>\n </slot>\n </div>\n\n <!-- Right Panel - Form -->\n <div class=\"flex-1 flex items-center justify-center p-6 sm:p-12 bg-gradient-to-br from-gray-50 to-gray-100 dark:from-slate-900 dark:to-slate-800\">\n <div\n :class=\"['w-full max-w-md', formAnimation]\"\n >\n <!-- Mobile Logo -->\n <div class=\"lg:hidden text-center mb-8\">\n <component\n :is=\"routerLinkComponent\"\n v-bind=\"getLinkProps(homeLink)\"\n class=\"inline-flex items-center gap-3\"\n >\n <slot name=\"mobile-logo\">\n <template v-if=\"appName || appIcon\">\n <div class=\"w-12 h-12 bg-primary-600 rounded-xl flex items-center justify-center shadow-lg shadow-primary-200 dark:shadow-primary-900/30\">\n <Icon\n :icon=\"appIcon\"\n class=\"w-6 h-6 text-white\"\n />\n </div>\n <span\n v-if=\"appName\"\n class=\"text-2xl font-bold text-gray-900 dark:text-white\"\n >\n {{ appName }}\n </span>\n </template>\n </slot>\n </component>\n </div>\n\n <!-- Form Header (title/subtitle) -->\n <slot name=\"form-header\">\n <div\n v-if=\"formTitle || formSubtitle\"\n class=\"text-center lg:text-left mb-8\"\n >\n <h2\n v-if=\"formTitle\"\n class=\"text-2xl sm:text-3xl font-bold text-gray-900 dark:text-white mb-2\"\n >\n {{ formTitle }}\n </h2>\n <p\n v-if=\"formSubtitle\"\n class=\"text-gray-600 dark:text-gray-400\"\n >\n {{ formSubtitle }}\n </p>\n </div>\n </slot>\n\n <!-- Form Card -->\n <div class=\"bg-white dark:bg-slate-800/80 rounded-3xl shadow-xl shadow-gray-200/50 dark:shadow-none p-8\">\n <slot />\n </div>\n\n <!-- Form Footer -->\n <slot name=\"form-footer\" />\n </div>\n </div>\n </div>\n</template>\n","<script lang=\"ts\" setup>\nimport { ref, computed, resolveComponent } from 'vue'\nimport { Icon } from '@iconify/vue'\nimport MenuItem from '@/components/core/MenuItem.vue'\nimport Dropdown from '@/components/core/Dropdown.vue'\nimport type { MenuItemProps } from '@/types'\n\nexport interface UserMenuItem {\n label: string\n icon?: string\n link?: string\n action?: () => void\n}\n\nexport type MenuPosition = 'top' | 'center' | 'bottom'\n\nconst props = withDefaults(\n defineProps<{\n /** Menu items for the sidebar */\n menuItems?: MenuItemProps[]\n /** App/brand name displayed in sidebar */\n appName?: string\n /** App icon (iconify icon name) */\n appIcon?: string\n /** Whether sidebar is open (v-model:sidebarOpen) */\n sidebarOpen?: boolean\n /** Whether dark mode is enabled (v-model:dark) */\n dark?: boolean\n /** Show dark mode toggle in header */\n showDarkToggle?: boolean\n /** Primary color class for sidebar background */\n sidebarClass?: string\n /** Current route path for menu active state (pass useRoute().path) */\n currentPath?: string\n /** User display name */\n userName?: string\n /** User avatar (initials or image URL) */\n userAvatar?: string\n /** User menu items (dropdown) */\n userMenuItems?: UserMenuItem[]\n /** Menu vertical position in sidebar: 'top', 'center', or 'bottom' */\n menuPosition?: MenuPosition\n }>(),\n {\n menuItems: () => [],\n appName: 'App',\n appIcon: 'lucide:box',\n sidebarOpen: true,\n dark: false,\n showDarkToggle: true,\n sidebarClass: 'bg-[#172b4c] dark:bg-slate-950',\n currentPath: undefined,\n userName: undefined,\n userAvatar: undefined,\n userMenuItems: () => [],\n menuPosition: 'top',\n },\n)\n\nconst menuPositionClass = computed(() => {\n switch (props.menuPosition) {\n case 'center':\n return 'lg:justify-center'\n case 'bottom':\n return 'lg:justify-end'\n case 'top':\n default:\n return 'lg:justify-start'\n }\n})\n\nconst emit = defineEmits<{\n 'update:sidebarOpen': [value: boolean]\n 'update:dark': [value: boolean]\n}>()\n\nconst internalSidebarOpen = ref(props.sidebarOpen)\nconst internalDark = ref(props.dark)\n\nconst sidebarOpenModel = computed({\n get: () => props.sidebarOpen ?? internalSidebarOpen.value,\n set: (value: boolean) => {\n internalSidebarOpen.value = value\n emit('update:sidebarOpen', value)\n },\n})\n\nconst darkModel = computed({\n get: () => props.dark ?? internalDark.value,\n set: (value: boolean) => {\n internalDark.value = value\n emit('update:dark', value)\n },\n})\n\nconst toggleSidebar = () => {\n sidebarOpenModel.value = !sidebarOpenModel.value\n}\n\nconst toggleDark = () => {\n darkModel.value = !darkModel.value\n}\n\n// Try to resolve RouterView\nconst routerViewComponent = computed(() => {\n try {\n const RouterView = resolveComponent('RouterView')\n if (typeof RouterView !== 'string') {\n return RouterView\n }\n } catch {\n // RouterView not available\n }\n return null\n})\n\n// Try to resolve RouterLink\nconst routerLinkComponent = computed(() => {\n try {\n const RouterLink = resolveComponent('RouterLink')\n if (typeof RouterLink !== 'string') {\n return RouterLink\n }\n } catch {\n // RouterLink not available\n }\n return 'a'\n})\n\nconst getLinkProps = (link: string) => {\n if (routerLinkComponent.value === 'a') {\n return { href: link }\n }\n return { to: link }\n}\n\nconst handleUserMenuClick = (item: UserMenuItem) => {\n if (item.action) {\n item.action()\n }\n}\n</script>\n\n<template>\n <div class=\"font-inter relative flex h-dvh overflow-hidden bg-gray-100 dark:bg-slate-900\">\n <!-- Backdrop for mobile -->\n <div\n v-if=\"sidebarOpenModel\"\n class=\"absolute z-40 h-full w-full bg-slate-950/20 lg:hidden dark:bg-white/20\"\n @click=\"sidebarOpenModel = false\"\n />\n\n <!-- Sidebar -->\n <aside\n :class=\"[\n sidebarOpenModel ? 'lg:w-60' : 'max-lg:-translate-x-76 lg:w-16',\n sidebarClass,\n ]\"\n class=\"@container max-lg:absolute max-lg:z-50 flex h-full w-76 flex-col justify-between gap-10 transition-all duration-1000 ease-in-out\"\n >\n <!-- Sidebar Header -->\n <div class=\"flex h-16 items-center px-3\">\n <div class=\"flex flex-1 items-center justify-center gap-3\">\n <slot name=\"logo\">\n <div\n class=\"bg-primary text-primary-foreground flex size-8 items-center justify-center rounded-lg bg-white/20\"\n >\n <Icon\n class=\"size-5 text-white\"\n :icon=\"appIcon\"\n />\n </div>\n <span\n :class=\"sidebarOpenModel ? 'block' : 'hidden'\"\n class=\"font-outfit flex-1 text-lg font-semibold text-white\"\n >\n {{ appName }}\n </span>\n </slot>\n </div>\n\n <button\n class=\"rounded-lg bg-white/10 p-1 transition hover:bg-white/20 lg:hidden\"\n @click=\"toggleSidebar\"\n >\n <Icon\n class=\"size-6 text-white\"\n icon=\"lucide:menu\"\n />\n </button>\n </div>\n\n <!-- Menu Items -->\n <div\n :class=\"[sidebarOpenModel ? 'items-start' : 'items-center', menuPositionClass]\"\n class=\"flex min-h-0 flex-1 flex-col gap-8 overflow-y-auto overflow-x-hidden px-2\"\n >\n <slot\n name=\"menu\"\n :current-path=\"currentPath\"\n >\n <MenuItem\n v-for=\"(item, index) in menuItems\"\n :key=\"index\"\n :menu-item=\"item\"\n :expanded=\"sidebarOpenModel\"\n :current-path=\"currentPath\"\n />\n </slot>\n </div>\n\n <!-- Sidebar Footer -->\n <div class=\"flex flex-col gap-3 px-3 pb-3\">\n <slot name=\"sidebar-footer\" />\n </div>\n </aside>\n\n <!-- Main Content Area -->\n <div class=\"flex flex-1 flex-col min-w-0\">\n <!-- Header -->\n <header\n class=\"flex h-16 items-center justify-between border-b border-slate-200 bg-white px-4 dark:border-slate-800 dark:bg-slate-950\"\n >\n <div>\n <button\n class=\"rounded-lg bg-gray-100 p-1 transition hover:bg-gray-200 dark:bg-gray-900 dark:hover:bg-gray-800\"\n @click=\"toggleSidebar\"\n >\n <Icon\n class=\"size-6 text-gray-900 hover:text-gray-800 dark:text-gray-100\"\n icon=\"lucide:menu\"\n />\n </button>\n </div>\n\n <div class=\"flex-1\">\n <slot name=\"header-center\" />\n </div>\n\n <div class=\"flex items-center gap-3\">\n <slot name=\"header-actions\" />\n\n <button\n v-if=\"showDarkToggle\"\n class=\"flex items-center justify-center rounded-lg bg-gray-100 p-2 transition hover:bg-gray-200 dark:bg-gray-900 dark:hover:bg-gray-800\"\n @click=\"toggleDark\"\n >\n <Icon\n :icon=\"darkModel ? 'lucide:sun' : 'lucide:moon'\"\n class=\"size-5 text-gray-900 dark:text-gray-100\"\n />\n </button>\n\n <!-- User Menu -->\n <Dropdown\n v-if=\"userName || userAvatar\"\n align=\"right\"\n >\n <template #trigger>\n <button\n class=\"flex items-center gap-2 rounded-lg p-1.5 transition hover:bg-gray-100 dark:hover:bg-gray-800\"\n >\n <div\n class=\"flex size-8 items-center justify-center rounded-full bg-primary text-sm font-medium text-white\"\n >\n {{ userAvatar || '?' }}\n </div>\n <span class=\"hidden text-sm font-medium text-gray-700 dark:text-gray-300 md:block\">\n {{ userName }}\n </span>\n <Icon\n icon=\"lucide:chevron-down\"\n class=\"size-4 text-gray-500\"\n />\n </button>\n </template>\n\n <template #default=\"{ close }\">\n <div class=\"min-w-48 py-1\">\n <component\n :is=\"item.link ? routerLinkComponent : 'button'\"\n v-for=\"item in userMenuItems\"\n :key=\"item.label\"\n v-bind=\"item.link ? getLinkProps(item.link) : {}\"\n class=\"flex w-full items-center gap-2 px-4 py-2 text-left text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-800\"\n @click=\"handleUserMenuClick(item); close()\"\n >\n <Icon\n v-if=\"item.icon\"\n :icon=\"item.icon\"\n class=\"size-4\"\n />\n {{ item.label }}\n </component>\n </div>\n </template>\n </Dropdown>\n </div>\n </header>\n\n <!-- Page Content -->\n <div class=\"flex flex-1 flex-col overflow-y-auto overflow-x-hidden\">\n <main class=\"container mx-auto flex flex-1 flex-col gap-5 p-5 max-w-full\">\n <slot>\n <component\n :is=\"routerViewComponent\"\n v-if=\"routerViewComponent\"\n />\n </slot>\n </main>\n </div>\n </div>\n </div>\n</template>\n","<script lang=\"ts\" setup>\nimport { computed, resolveComponent } from 'vue'\n\nexport interface PageBreadcrumb {\n label: string\n link: string\n}\n\ndefineProps<{\n /** Page title */\n title?: string\n /** Page description */\n description?: string\n /** Breadcrumb navigation items */\n breadcrumbs?: PageBreadcrumb[]\n}>()\n\n// Try to resolve RouterLink\nconst linkComponent = computed(() => {\n try {\n const RouterLink = resolveComponent('RouterLink')\n if (typeof RouterLink !== 'string') {\n return RouterLink\n }\n } catch {\n // RouterLink not available\n }\n return 'a'\n})\n\nconst getLinkProps = (link: string) => {\n if (linkComponent.value === 'a') {\n return { href: link }\n }\n return { to: link }\n}\n</script>\n\n<template>\n <div class=\"flex flex-col gap-4\">\n <!-- Breadcrumbs -->\n <nav\n v-if=\"breadcrumbs && breadcrumbs.length > 0\"\n aria-label=\"Breadcrumb\"\n >\n <ol class=\"flex items-center\">\n <li\n v-for=\"(breadcrumb, index) in breadcrumbs\"\n :key=\"index\"\n class=\"flex items-center\"\n >\n <span\n v-if=\"index > 0\"\n class=\"mx-3 text-sm font-semibold text-gray-400 dark:text-gray-600\"\n >\n /\n </span>\n\n <slot\n name=\"breadcrumb\"\n :breadcrumb=\"breadcrumb\"\n :index=\"index\"\n :is-last=\"index === breadcrumbs.length - 1\"\n >\n <component\n :is=\"linkComponent\"\n v-bind=\"getLinkProps(breadcrumb.link)\"\n :class=\"[\n 'text-sm transition-colors',\n index < breadcrumbs.length - 1\n ? 'font-semibold text-gray-900 hover:text-primary/90 hover:underline dark:text-gray-100'\n : 'text-gray-400 dark:text-gray-600',\n ]\"\n >\n {{ breadcrumb.label }}\n </component>\n </slot>\n </li>\n </ol>\n </nav>\n\n <!-- Page Header -->\n <div class=\"flex flex-col gap-4 md:flex-row md:items-start md:justify-between\">\n <div class=\"flex flex-col gap-1 min-w-0 flex-1\">\n <h1\n v-if=\"title\"\n class=\"text-2xl font-bold text-gray-900 dark:text-gray-100 truncate\"\n >\n <slot name=\"title\">\n {{ title }}\n </slot>\n </h1>\n\n <p\n v-if=\"description\"\n class=\"text-sm text-gray-600 dark:text-gray-400\"\n >\n <slot name=\"description\">\n {{ description }}\n </slot>\n </p>\n </div>\n\n <div class=\"flex items-center gap-2 flex-wrap shrink-0\">\n <slot name=\"actions\" />\n </div>\n </div>\n\n <!-- Page Content -->\n <div class=\"flex-1\">\n <slot />\n </div>\n </div>\n</template>\n"],"names":["useSlots","computed","resolveComponent","_openBlock","_createElementBlock","_hoisted_1","$slots","_normalizeClass","_renderSlot","_hoisted_2","_createElementVNode","_hoisted_3","_Fragment","_hoisted_4","_hoisted_5","_hoisted_6","_createVNode","_unref","Icon","_hoisted_7","_toDisplayString","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_13","_hoisted_14","_renderList","_hoisted_15","_createBlock","_resolveDynamicComponent","_mergeProps","ref","MenuItem","Dropdown","_withCtx","_createTextVNode"],"mappings":"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"}
|