@finema/finework-layer 0.2.49 → 0.2.51
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/.playground/app/pages/layout-admin/test/[id]/index.vue +286 -0
- package/.playground/app/pages/layout-admin.vue +2 -2
- package/@finema finework-layer - LLM Documentation Guide.md +566 -0
- package/API_REFERENCE.md +780 -0
- package/ARCHITECTURE.md +592 -0
- package/CHANGELOG.md +8 -0
- package/COMPONENT_EXAMPLES.md +893 -0
- package/DOCUMENTATION_INDEX.md +354 -0
- package/EXAMPLES.md +597 -0
- package/QUICK_START.md +678 -0
- package/README.md +199 -33
- package/TROUBLESHOOTING.md +646 -0
- package/app/components/Button/Back.vue +1 -1
- package/app/components/Layout/Admin/Sidebar.vue +10 -3
- package/app/components/Layout/Admin/index.vue +20 -19
- package/package.json +1 -1
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<LayoutAdmin
|
|
3
|
+
label="Test Layout"
|
|
4
|
+
:sidebar-items="sidebarItems"
|
|
5
|
+
is-sidebar-group
|
|
6
|
+
root-app-path="/layout-admin"
|
|
7
|
+
>
|
|
8
|
+
<NuxtLayout>
|
|
9
|
+
<TeleportSafe to="#page-filters">
|
|
10
|
+
<div class="mb-4 flex items-center justify-between gap-1">
|
|
11
|
+
<div class="font-bold">
|
|
12
|
+
Filters
|
|
13
|
+
<Badge
|
|
14
|
+
v-if="countForm"
|
|
15
|
+
class="size-6 items-center justify-center rounded-full"
|
|
16
|
+
:label="countForm"
|
|
17
|
+
/>
|
|
18
|
+
</div>
|
|
19
|
+
<Button
|
|
20
|
+
label="Clear all"
|
|
21
|
+
variant="ghost"
|
|
22
|
+
class="text-muted p-0 text-sm"
|
|
23
|
+
@click="form.resetForm()"
|
|
24
|
+
/>
|
|
25
|
+
</div>
|
|
26
|
+
<FormFields
|
|
27
|
+
:form="form"
|
|
28
|
+
:options="formFields"
|
|
29
|
+
class="grid w-full gap-x-3"
|
|
30
|
+
/>
|
|
31
|
+
</TeleportSafe>
|
|
32
|
+
<div class="mb-4 flex gap-4">
|
|
33
|
+
<FormFields
|
|
34
|
+
:form="form"
|
|
35
|
+
:options="formSearchFields"
|
|
36
|
+
class="w-full max-w-[600px] gap-3"
|
|
37
|
+
/>
|
|
38
|
+
<Button
|
|
39
|
+
icon="material-symbols:filter-list-rounded"
|
|
40
|
+
variant="outline"
|
|
41
|
+
color="neutral"
|
|
42
|
+
class="w-fit"
|
|
43
|
+
@click="showFilter = !showFilter"
|
|
44
|
+
>
|
|
45
|
+
Filters
|
|
46
|
+
<Badge
|
|
47
|
+
v-if="countForm"
|
|
48
|
+
class="size-6 items-center justify-center rounded-full"
|
|
49
|
+
:label="countForm"
|
|
50
|
+
/>
|
|
51
|
+
</Button>
|
|
52
|
+
</div>
|
|
53
|
+
<Card> asdasdasdasdasdasd </Card>
|
|
54
|
+
<div class="bg-white p-4">
|
|
55
|
+
<Tabs
|
|
56
|
+
variant="link"
|
|
57
|
+
:items="items"
|
|
58
|
+
class="w-full"
|
|
59
|
+
/>
|
|
60
|
+
<Tabs
|
|
61
|
+
orientation="vertical"
|
|
62
|
+
:items="items"
|
|
63
|
+
class="w-full"
|
|
64
|
+
/>
|
|
65
|
+
</div>
|
|
66
|
+
</NuxtLayout>
|
|
67
|
+
</LayoutAdmin>
|
|
68
|
+
</template>
|
|
69
|
+
|
|
70
|
+
<script lang="ts" setup>
|
|
71
|
+
import type { NavigationMenuItem } from '@nuxt/ui'
|
|
72
|
+
|
|
73
|
+
const auth = useAuth()
|
|
74
|
+
const showFilter = useState('pageFilterOpen')
|
|
75
|
+
const items = ref([
|
|
76
|
+
{
|
|
77
|
+
label: 'Account',
|
|
78
|
+
icon: 'i-lucide-user',
|
|
79
|
+
content: 'This is the account content.',
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
label: 'Password',
|
|
83
|
+
icon: 'i-lucide-lock',
|
|
84
|
+
content: 'This is the password content.',
|
|
85
|
+
},
|
|
86
|
+
])
|
|
87
|
+
|
|
88
|
+
useApp().definePage({
|
|
89
|
+
title: 'Test Layout',
|
|
90
|
+
breadcrumbs: [
|
|
91
|
+
{
|
|
92
|
+
label: 'Home',
|
|
93
|
+
to: '/',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
label: 'Test Layout',
|
|
97
|
+
to: '/test-layout',
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
const form = useForm({
|
|
103
|
+
validationSchema: toTypedSchema(
|
|
104
|
+
v.object({
|
|
105
|
+
q: v.optional(v.pipe(v.string()), ''),
|
|
106
|
+
status: v.optional(v.pipe(v.string()), ''),
|
|
107
|
+
user_id: v.optional(v.pipe(v.string()), ''),
|
|
108
|
+
date_range: v.nullish(
|
|
109
|
+
v.object({
|
|
110
|
+
start: v.union([v.date(), v.string()]),
|
|
111
|
+
end: v.union([v.date(), v.string()]),
|
|
112
|
+
}),
|
|
113
|
+
),
|
|
114
|
+
}),
|
|
115
|
+
),
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
const countForm = computed(
|
|
119
|
+
() =>
|
|
120
|
+
[
|
|
121
|
+
form.values.q,
|
|
122
|
+
form.values.status,
|
|
123
|
+
form.values.user_id,
|
|
124
|
+
form.values.date_range?.start || form.values.date_range?.end,
|
|
125
|
+
].filter(Boolean).length,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
auth.me.set({
|
|
129
|
+
id: 'edab2396-2b6f-4855-b04e-a7c9ae9b70ae',
|
|
130
|
+
created_at: '2025-09-02T10:16:37.195Z',
|
|
131
|
+
updated_at: '2025-10-11T10:14:10.296Z',
|
|
132
|
+
email: 'long@finema.co',
|
|
133
|
+
full_name: 'Passakon Puttasuwan',
|
|
134
|
+
display_name: 'Long',
|
|
135
|
+
position: 'Technical Specialist',
|
|
136
|
+
team_code: 'DEV',
|
|
137
|
+
company: 'finema',
|
|
138
|
+
avatar_url:
|
|
139
|
+
'https://avatars.slack-edge.com/2023-09-25/5968557597936_c750902e3ffc4f690d80_512.jpg',
|
|
140
|
+
slack_id: 'U0147KLKKH8',
|
|
141
|
+
azure_id: 'fd7fbb55-a249-4b79-b439-2270981bd3ae',
|
|
142
|
+
is_active: true,
|
|
143
|
+
joined_date: '2025-09-02T00:00:00Z',
|
|
144
|
+
access_level: {
|
|
145
|
+
user_id: 'edab2396-2b6f-4855-b04e-a7c9ae9b70ae',
|
|
146
|
+
clockin: 'ADMIN',
|
|
147
|
+
timesheet: 'ADMIN',
|
|
148
|
+
pmo: 'SUPER',
|
|
149
|
+
setting: 'SUPER',
|
|
150
|
+
created_at: '2025-08-15T16:40:29.319Z',
|
|
151
|
+
updated_at: '2025-09-30T10:14:59.228Z',
|
|
152
|
+
},
|
|
153
|
+
team: {
|
|
154
|
+
id: 'ef2abb00-d57f-4a38-a5d1-660ee63d2e1f',
|
|
155
|
+
created_at: '2025-08-26T10:36:53.598Z',
|
|
156
|
+
updated_at: '2025-10-01T06:00:29.941Z',
|
|
157
|
+
name: 'Developer Team',
|
|
158
|
+
code: 'DEV',
|
|
159
|
+
color: 'violet',
|
|
160
|
+
description: '',
|
|
161
|
+
working_start_at: '12:02:00',
|
|
162
|
+
working_end_at: '20:00:00',
|
|
163
|
+
created_by_id: null,
|
|
164
|
+
updated_by_id: '96d3ec63-be14-41c6-9268-ea8095d2a73b',
|
|
165
|
+
deleted_by_id: null,
|
|
166
|
+
},
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
const sidebarItems: NavigationMenuItem[] = [
|
|
170
|
+
{
|
|
171
|
+
children: [
|
|
172
|
+
{
|
|
173
|
+
label: 'Submenu 1',
|
|
174
|
+
to: '/layout-admin',
|
|
175
|
+
icon: 'i-heroicons-outline:home',
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
label: 'Submenu 2',
|
|
179
|
+
to: '/layout-admin/test/1',
|
|
180
|
+
icon: 'i-heroicons-outline:home',
|
|
181
|
+
},
|
|
182
|
+
],
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
label: 'DASHBOARD',
|
|
186
|
+
children: [
|
|
187
|
+
{
|
|
188
|
+
label: 'Submenu 1',
|
|
189
|
+
to: '/submenu',
|
|
190
|
+
icon: 'i-heroicons-outline:home',
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
label: 'Submenu 2',
|
|
194
|
+
to: '/submenu/layout-admin',
|
|
195
|
+
icon: 'i-heroicons-outline:home',
|
|
196
|
+
},
|
|
197
|
+
],
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
label: 'Users',
|
|
201
|
+
children: [
|
|
202
|
+
{
|
|
203
|
+
label: 'Submenu 1',
|
|
204
|
+
to: '/submenu1',
|
|
205
|
+
icon: 'i-heroicons-outline:home',
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
label: 'Submenu 2',
|
|
209
|
+
to: '/layout-admin',
|
|
210
|
+
icon: 'i-heroicons-outline:home',
|
|
211
|
+
children: [
|
|
212
|
+
{
|
|
213
|
+
label: 'Submenu 2-1',
|
|
214
|
+
to: '/layout-admin/1',
|
|
215
|
+
icon: 'i-heroicons-outline:home',
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
label: 'Submenu 2-2',
|
|
219
|
+
to: '/layout-admin/2',
|
|
220
|
+
},
|
|
221
|
+
],
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
},
|
|
225
|
+
]
|
|
226
|
+
|
|
227
|
+
const formSearchFields = createFormFields(() => [
|
|
228
|
+
{
|
|
229
|
+
type: INPUT_TYPES.SEARCH,
|
|
230
|
+
props: {
|
|
231
|
+
name: 'q',
|
|
232
|
+
placeholder: 'ค้นหา',
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
])
|
|
236
|
+
|
|
237
|
+
const formFields = createFormFields(() => [
|
|
238
|
+
{
|
|
239
|
+
type: INPUT_TYPES.SEARCH,
|
|
240
|
+
props: {
|
|
241
|
+
name: 'q',
|
|
242
|
+
placeholder: 'ค้นหา',
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
type: INPUT_TYPES.DATE_RANGE,
|
|
247
|
+
props: {
|
|
248
|
+
label: 'Tender Date',
|
|
249
|
+
name: 'date_range',
|
|
250
|
+
placeholder: 'ระบุช่วงเวลา Tender Date',
|
|
251
|
+
clearable: true,
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
type: INPUT_TYPES.SELECT,
|
|
256
|
+
props: {
|
|
257
|
+
name: 'user_id',
|
|
258
|
+
label: 'Main Responsibility',
|
|
259
|
+
placeholder: 'Main Responsibility',
|
|
260
|
+
options: [
|
|
261
|
+
{
|
|
262
|
+
value: 'test',
|
|
263
|
+
label: 'test',
|
|
264
|
+
},
|
|
265
|
+
],
|
|
266
|
+
searchable: true,
|
|
267
|
+
clearable: true,
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
type: INPUT_TYPES.SELECT,
|
|
272
|
+
props: {
|
|
273
|
+
name: 'status',
|
|
274
|
+
label: 'status',
|
|
275
|
+
placeholder: 'All Status',
|
|
276
|
+
clearable: true,
|
|
277
|
+
options: [
|
|
278
|
+
{
|
|
279
|
+
value: 'test',
|
|
280
|
+
label: 'test',
|
|
281
|
+
},
|
|
282
|
+
],
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
])
|
|
286
|
+
</script>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
label="Test Layout"
|
|
4
4
|
:sidebar-items="sidebarItems"
|
|
5
5
|
is-sidebar-group
|
|
6
|
-
|
|
6
|
+
root-app-path="/layout-admin"
|
|
7
7
|
>
|
|
8
8
|
<NuxtLayout>
|
|
9
9
|
<TeleportSafe to="#page-filters">
|
|
@@ -176,7 +176,7 @@ const sidebarItems: NavigationMenuItem[] = [
|
|
|
176
176
|
},
|
|
177
177
|
{
|
|
178
178
|
label: 'Submenu 2',
|
|
179
|
-
to: '/layout-admin/
|
|
179
|
+
to: '/layout-admin/test/1',
|
|
180
180
|
icon: 'i-heroicons-outline:home',
|
|
181
181
|
},
|
|
182
182
|
],
|