@finema/finework-layer 0.2.77 → 0.2.79
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/.husky/pre-commit +1 -1
- package/.playground/app/assets/css/main.css +6 -6
- package/.playground/app/pages/layout-admin/[id]/index.vue +145 -145
- package/.playground/app/pages/layout-admin/test/[id]/index.vue +286 -286
- package/.playground/app/pages/layout-admin.vue +283 -285
- package/.playground/app/pages/layout-user.vue +284 -284
- package/.playground/app/pages/submenu/layout-admin.vue +210 -210
- package/.vscode/settings.json +5 -1
- package/CHANGELOG.md +382 -374
- package/app/app.config.ts +144 -144
- package/app/app.vue +10 -10
- package/app/assets/css/main.css +77 -77
- package/app/components/Button/ActionIcon.vue +29 -29
- package/app/components/Button/Back.vue +22 -22
- package/app/components/Format/Currency.vue +17 -17
- package/app/components/Format/Date.vue +24 -24
- package/app/components/Format/DateTime.vue +24 -24
- package/app/components/Format/Number.vue +17 -17
- package/app/components/Format/Percent.vue +38 -38
- package/app/components/Format/TimeFromNow.vue +38 -38
- package/app/components/InfoItemList.vue +196 -196
- package/app/components/Layout/Admin/Sidebar.vue +343 -329
- package/app/components/Layout/Admin/index.vue +240 -224
- package/app/components/Layout/Apps.vue +45 -45
- package/app/components/Layout/User/index.vue +102 -102
- package/app/components/Notifications/index.vue +162 -162
- package/app/components/StatusBox.vue +56 -56
- package/app/composables/useAuth.ts +207 -207
- package/app/composables/useNotification.ts +76 -76
- package/app/composables/useRequestOptions.ts +86 -86
- package/app/constants/routes.ts +86 -86
- package/app/error.vue +218 -218
- package/app/middleware/auth.ts +45 -45
- package/app/middleware/common.ts +12 -12
- package/app/middleware/guest.ts +7 -7
- package/app/middleware/permissions.ts +29 -29
- package/bun.lock +2758 -2758
- package/eslint.config.js +206 -2
- package/index.d.ts +16 -16
- package/nuxt.config.ts +41 -41
- package/package.json +38 -38
|
@@ -1,224 +1,240 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="relative flex min-h-screen flex-1">
|
|
3
|
-
<div
|
|
4
|
-
:class="[
|
|
5
|
-
`
|
|
6
|
-
fixed inset-0 z-[102] -mt-0.5 hidden w-auto
|
|
7
|
-
lg:block
|
|
8
|
-
`,
|
|
9
|
-
{
|
|
10
|
-
'max-w-[88px]': isCollapsed,
|
|
11
|
-
'max-w-[260px]': !isCollapsed,
|
|
12
|
-
},
|
|
13
|
-
]"
|
|
14
|
-
>
|
|
15
|
-
<Sidebar
|
|
16
|
-
:label="label"
|
|
17
|
-
:is-collapsed="isCollapsed"
|
|
18
|
-
:items="sidebarItems"
|
|
19
|
-
:is-group="isSidebarGroup"
|
|
20
|
-
@toggle-collapsed="isCollapsed = !isCollapsed"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
:
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
<
|
|
104
|
-
class="
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
>
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
:
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
class="mb-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
<
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
</
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
</
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
1
|
+
<template>
|
|
2
|
+
<div class="relative flex min-h-screen flex-1">
|
|
3
|
+
<div
|
|
4
|
+
:class="[
|
|
5
|
+
`
|
|
6
|
+
fixed inset-0 z-[102] -mt-0.5 hidden w-auto
|
|
7
|
+
lg:block
|
|
8
|
+
`,
|
|
9
|
+
{
|
|
10
|
+
'max-w-[88px]': isCollapsed,
|
|
11
|
+
'max-w-[260px]': !isCollapsed,
|
|
12
|
+
},
|
|
13
|
+
]"
|
|
14
|
+
>
|
|
15
|
+
<Sidebar
|
|
16
|
+
:label="label"
|
|
17
|
+
:is-collapsed="isCollapsed"
|
|
18
|
+
:items="sidebarItems"
|
|
19
|
+
:is-group="isSidebarGroup"
|
|
20
|
+
@toggle-collapsed="isCollapsed = !isCollapsed"
|
|
21
|
+
>
|
|
22
|
+
<template #sidebar-tailing>
|
|
23
|
+
<slot name="sidebar-tailing" />
|
|
24
|
+
</template>
|
|
25
|
+
</Sidebar>
|
|
26
|
+
</div>
|
|
27
|
+
<div
|
|
28
|
+
:class="[
|
|
29
|
+
'w-full bg-gray-50',
|
|
30
|
+
{
|
|
31
|
+
'lg:pl-[88px]': isCollapsed,
|
|
32
|
+
'lg:pl-[260px]': !isCollapsed,
|
|
33
|
+
},
|
|
34
|
+
]"
|
|
35
|
+
>
|
|
36
|
+
<nav
|
|
37
|
+
class="fixed top-0 left-0 z-[101] flex min-h-[64px] w-screen items-center justify-between gap-4 border-b border-gray-300 bg-white px-5 lg:min-h-[72px] lg:justify-end"
|
|
38
|
+
>
|
|
39
|
+
<div class="flex items-center gap-4">
|
|
40
|
+
<Slideover
|
|
41
|
+
v-model:open="isShowSidebarMobile"
|
|
42
|
+
:ui="{
|
|
43
|
+
content: 'w-[80%] max-w-[260px] lg:hidden',
|
|
44
|
+
overlay: 'lg:hidden',
|
|
45
|
+
}"
|
|
46
|
+
side="left"
|
|
47
|
+
>
|
|
48
|
+
<svg
|
|
49
|
+
class="cursor-pointer lg:hidden"
|
|
50
|
+
width="19"
|
|
51
|
+
height="18"
|
|
52
|
+
viewBox="0 0 19 18"
|
|
53
|
+
fill="none"
|
|
54
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
55
|
+
transform="scale(-1, 1)"
|
|
56
|
+
@click="isShowSidebarMobile = true"
|
|
57
|
+
>
|
|
58
|
+
<path
|
|
59
|
+
d="M10 18L10 16L19 16L19 18L10 18ZM6 2L6 -2.62268e-07L19 -8.30516e-07L19 2L6 2ZM-3.49691e-07 10L-4.37114e-07 8L19 8L19 10L-3.49691e-07 10Z"
|
|
60
|
+
fill="#4B5563"
|
|
61
|
+
/>
|
|
62
|
+
</svg>
|
|
63
|
+
|
|
64
|
+
<template #content>
|
|
65
|
+
<Sidebar
|
|
66
|
+
:label="label"
|
|
67
|
+
:is-collapsed="false"
|
|
68
|
+
:is-mobile="true"
|
|
69
|
+
:items="sidebarItems"
|
|
70
|
+
:is-group="isSidebarGroup"
|
|
71
|
+
@toggle-collapsed="isShowSidebarMobile = false"
|
|
72
|
+
>
|
|
73
|
+
<template #sidebar-tailing>
|
|
74
|
+
<slot name="sidebar-tailing" />
|
|
75
|
+
</template>
|
|
76
|
+
</Sidebar>
|
|
77
|
+
</template>
|
|
78
|
+
</Slideover>
|
|
79
|
+
<NuxtLink :to="routes.home.to">
|
|
80
|
+
<img
|
|
81
|
+
src="/logo-mini.png"
|
|
82
|
+
alt="logo_mini_color"
|
|
83
|
+
class="w-[126px] min-w-[126px] lg:hidden lg:w-[172px] lg:min-w-[172px]"
|
|
84
|
+
/>
|
|
85
|
+
</NuxtLink>
|
|
86
|
+
<Apps class="lg:hidden" />
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
<div class="flex items-center justify-center gap-4">
|
|
90
|
+
<Notifications :ui="{ content: 'mt-[64px] lg:mt-[72px]' }" />
|
|
91
|
+
<DropdownMenu
|
|
92
|
+
size="xl"
|
|
93
|
+
:items="userMenuItems"
|
|
94
|
+
:content="{
|
|
95
|
+
align: 'end',
|
|
96
|
+
side: 'bottom',
|
|
97
|
+
}"
|
|
98
|
+
:ui="{
|
|
99
|
+
content: 'w-48',
|
|
100
|
+
}"
|
|
101
|
+
>
|
|
102
|
+
<div class="relative flex cursor-pointer items-center gap-2">
|
|
103
|
+
<div class="hidden flex-col justify-end text-right lg:flex">
|
|
104
|
+
<p class="font-bold">
|
|
105
|
+
{{ auth.me.value?.display_name || auth.me.value?.full_name }}
|
|
106
|
+
</p>
|
|
107
|
+
<p class="text-muted text-sm">
|
|
108
|
+
{{ auth.me.value?.email || "" }}
|
|
109
|
+
</p>
|
|
110
|
+
</div>
|
|
111
|
+
<Avatar
|
|
112
|
+
class="border-muted size-[40px] border text-2xl"
|
|
113
|
+
icon="ri:user-line"
|
|
114
|
+
:src="auth.me.value?.avatar_url || ''"
|
|
115
|
+
/>
|
|
116
|
+
<Icon
|
|
117
|
+
name="i-ph:caret-down-light"
|
|
118
|
+
class="size-5"
|
|
119
|
+
/>
|
|
120
|
+
</div>
|
|
121
|
+
</DropdownMenu>
|
|
122
|
+
</div>
|
|
123
|
+
</nav>
|
|
124
|
+
<div class="w-full bg-gray-50 pt-[64px] lg:pt-[72px]">
|
|
125
|
+
<main
|
|
126
|
+
:class="[
|
|
127
|
+
'mx-auto min-h-full flex-1 px-6 py-10 lg:px-8',
|
|
128
|
+
fullScreen ? 'w-full 2xl:max-w-[90%]' : 'max-w-7xl 2xl:max-w-[70%]',
|
|
129
|
+
]"
|
|
130
|
+
>
|
|
131
|
+
<Breadcrumb
|
|
132
|
+
v-if="
|
|
133
|
+
!app.pageMeta.isHideBreadcrumbs && breadcrumbsItems.length > 1
|
|
134
|
+
"
|
|
135
|
+
:items="breadcrumbsItems"
|
|
136
|
+
class="mb-5"
|
|
137
|
+
:ui="{
|
|
138
|
+
item: 'max-w-2/3',
|
|
139
|
+
list: 'w-full',
|
|
140
|
+
}"
|
|
141
|
+
/>
|
|
142
|
+
<div
|
|
143
|
+
v-if="app.pageMeta.title"
|
|
144
|
+
class="mb-4 flex flex-col justify-between gap-1 md:mb-6 md:gap-4 lg:flex-row lg:items-start"
|
|
145
|
+
>
|
|
146
|
+
<div class="flex flex-1 flex-col">
|
|
147
|
+
<h1
|
|
148
|
+
class="text-3xl font-bold wrap-break-word lg:max-w-2/3"
|
|
149
|
+
:title="app.pageMeta.title"
|
|
150
|
+
>
|
|
151
|
+
{{ app.pageMeta.title }}
|
|
152
|
+
<span id="page-title-extra" />
|
|
153
|
+
</h1>
|
|
154
|
+
|
|
155
|
+
<div id="page-subtitle" />
|
|
156
|
+
<p
|
|
157
|
+
v-if="app.pageMeta.sub_title"
|
|
158
|
+
class="text-[#475467]"
|
|
159
|
+
>
|
|
160
|
+
{{ app.pageMeta.sub_title }}
|
|
161
|
+
</p>
|
|
162
|
+
</div>
|
|
163
|
+
<div id="page-header" />
|
|
164
|
+
</div>
|
|
165
|
+
<slot />
|
|
166
|
+
</main>
|
|
167
|
+
</div>
|
|
168
|
+
</div>
|
|
169
|
+
</div>
|
|
170
|
+
</template>
|
|
171
|
+
|
|
172
|
+
<script lang="ts" setup>
|
|
173
|
+
import type { DropdownMenuItem, NavigationMenuItem } from '@nuxt/ui'
|
|
174
|
+
import { computed } from 'vue'
|
|
175
|
+
import Sidebar from './Sidebar.vue'
|
|
176
|
+
import Apps from '../Apps.vue'
|
|
177
|
+
|
|
178
|
+
const props = withDefaults(
|
|
179
|
+
defineProps<{
|
|
180
|
+
label: string
|
|
181
|
+
sidebarItems: NavigationMenuItem[]
|
|
182
|
+
isSidebarGroup?: boolean
|
|
183
|
+
fullScreen?: boolean
|
|
184
|
+
rootAppPath?: string
|
|
185
|
+
}>(),
|
|
186
|
+
{
|
|
187
|
+
fullScreen: true,
|
|
188
|
+
},
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
defineSlots<{
|
|
192
|
+
'sidebar-tailing': {
|
|
193
|
+
is_collapsed: boolean
|
|
194
|
+
is_mobile: boolean
|
|
195
|
+
is_group: boolean
|
|
196
|
+
}
|
|
197
|
+
}>()
|
|
198
|
+
|
|
199
|
+
const app = useApp()
|
|
200
|
+
const isShowSidebarMobile = ref(false)
|
|
201
|
+
const auth = useAuth()
|
|
202
|
+
// Cookie to store user preference for desktop
|
|
203
|
+
const isCollapsed = useCookie<boolean>('app.admin.sidebar.isCollapsed', {
|
|
204
|
+
default: () => false,
|
|
205
|
+
path: '/',
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
const userMenuItems: DropdownMenuItem[] = [
|
|
209
|
+
{
|
|
210
|
+
label: 'View profile',
|
|
211
|
+
icon: 'i-lucide-user',
|
|
212
|
+
to: routes.account.profile.to,
|
|
213
|
+
},
|
|
214
|
+
|
|
215
|
+
{
|
|
216
|
+
label: routes.logout.label,
|
|
217
|
+
icon: 'i-lucide-log-out',
|
|
218
|
+
to: routes.logout.to,
|
|
219
|
+
external: true,
|
|
220
|
+
},
|
|
221
|
+
]
|
|
222
|
+
|
|
223
|
+
const breadcrumbsItems = computed(() => {
|
|
224
|
+
const list = app.pageMeta.breadcrumbs || []
|
|
225
|
+
if (!list.length) return []
|
|
226
|
+
const extra = list.map((item: any) => ({
|
|
227
|
+
...item,
|
|
228
|
+
icon: '',
|
|
229
|
+
}))
|
|
230
|
+
|
|
231
|
+
return [
|
|
232
|
+
{
|
|
233
|
+
label: '',
|
|
234
|
+
icon: 'ph:house-line',
|
|
235
|
+
to: props.rootAppPath || '/',
|
|
236
|
+
},
|
|
237
|
+
...extra,
|
|
238
|
+
]
|
|
239
|
+
})
|
|
240
|
+
</script>
|
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<Popover
|
|
3
|
-
:content="{
|
|
4
|
-
align: 'center',
|
|
5
|
-
side: 'bottom',
|
|
6
|
-
sideOffset: 8,
|
|
7
|
-
}"
|
|
8
|
-
>
|
|
9
|
-
<Button
|
|
10
|
-
icon="mingcute:dot-grid-line"
|
|
11
|
-
variant="ghost"
|
|
12
|
-
class="text-gray-500"
|
|
13
|
-
/>
|
|
14
|
-
|
|
15
|
-
<template #content>
|
|
16
|
-
<Card class="w-[300px]">
|
|
17
|
-
<div
|
|
18
|
-
class="grid grid-cols-3 gap-6"
|
|
19
|
-
>
|
|
20
|
-
<Button
|
|
21
|
-
v-for="item in auth.menusNavbar.value"
|
|
22
|
-
:key="item.to"
|
|
23
|
-
class="flex flex-col items-center p-0 text-center"
|
|
24
|
-
variant="link"
|
|
25
|
-
:to="item.to"
|
|
26
|
-
>
|
|
27
|
-
<div class="flex h-[42px] items-center justify-center">
|
|
28
|
-
<img
|
|
29
|
-
:src="item.icon"
|
|
30
|
-
class="h-auto w-[32px]"
|
|
31
|
-
/>
|
|
32
|
-
</div>
|
|
33
|
-
<span class="text-sm font-medium text-gray-700">
|
|
34
|
-
{{ item.label }}
|
|
35
|
-
</span>
|
|
36
|
-
</Button>
|
|
37
|
-
</div>
|
|
38
|
-
</Card>
|
|
39
|
-
</template>
|
|
40
|
-
</Popover>
|
|
41
|
-
</template>
|
|
42
|
-
|
|
43
|
-
<script lang="ts" setup>
|
|
44
|
-
const auth = useAuth()
|
|
45
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<Popover
|
|
3
|
+
:content="{
|
|
4
|
+
align: 'center',
|
|
5
|
+
side: 'bottom',
|
|
6
|
+
sideOffset: 8,
|
|
7
|
+
}"
|
|
8
|
+
>
|
|
9
|
+
<Button
|
|
10
|
+
icon="mingcute:dot-grid-line"
|
|
11
|
+
variant="ghost"
|
|
12
|
+
class="text-gray-500"
|
|
13
|
+
/>
|
|
14
|
+
|
|
15
|
+
<template #content>
|
|
16
|
+
<Card class="w-[300px]">
|
|
17
|
+
<div
|
|
18
|
+
class="grid grid-cols-3 gap-6"
|
|
19
|
+
>
|
|
20
|
+
<Button
|
|
21
|
+
v-for="item in auth.menusNavbar.value"
|
|
22
|
+
:key="item.to"
|
|
23
|
+
class="flex flex-col items-center p-0 text-center"
|
|
24
|
+
variant="link"
|
|
25
|
+
:to="item.to"
|
|
26
|
+
>
|
|
27
|
+
<div class="flex h-[42px] items-center justify-center">
|
|
28
|
+
<img
|
|
29
|
+
:src="item.icon"
|
|
30
|
+
class="h-auto w-[32px]"
|
|
31
|
+
/>
|
|
32
|
+
</div>
|
|
33
|
+
<span class="text-sm font-medium text-gray-700">
|
|
34
|
+
{{ item.label }}
|
|
35
|
+
</span>
|
|
36
|
+
</Button>
|
|
37
|
+
</div>
|
|
38
|
+
</Card>
|
|
39
|
+
</template>
|
|
40
|
+
</Popover>
|
|
41
|
+
</template>
|
|
42
|
+
|
|
43
|
+
<script lang="ts" setup>
|
|
44
|
+
const auth = useAuth()
|
|
45
|
+
</script>
|