@simitgroup/simpleapp-generator 1.2.7 → 1.2.8

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.
Files changed (45) hide show
  1. package/dist/framework.js +3 -3
  2. package/dist/framework.js.map +1 -1
  3. package/package.json +1 -1
  4. package/src/framework.ts +3 -3
  5. package/templates/nuxt/app.vue.eta +7 -3
  6. package/templates/nuxt/assets/css/calendar.css._eta +21 -8
  7. package/templates/nuxt/assets/css/style.css._eta +0 -5
  8. package/templates/nuxt/assets/primevue/passthrough.ts._eta +26 -15
  9. package/templates/nuxt/components/calendar/CalendarByResource.vue.eta +29 -8
  10. package/templates/nuxt/components/event/EventDocumentViewer.vue._eta +2 -2
  11. package/templates/nuxt/components/event/EventNotification.vue._eta +23 -2
  12. package/templates/nuxt/components/header/HeaderBar.vue._eta +9 -9
  13. package/templates/nuxt/components/header/HeaderBreadcrumb.vue.eta +2 -2
  14. package/templates/nuxt/components/header/button/HeaderButtonMenuPicker.vue._eta +7 -15
  15. package/templates/nuxt/components/header/button/HeaderButtonProfile.vue.eta +23 -34
  16. package/templates/nuxt/components/list/ListView.vue.eta +10 -8
  17. package/templates/nuxt/components/renderer/RendererMoney.vue.eta +10 -2
  18. package/templates/nuxt/components/renderer/RendererViewer.vue.eta +5 -5
  19. package/templates/nuxt/components/simpleApp/SimpleAppAutocomplete.vue.eta +34 -9
  20. package/templates/nuxt/components/simpleApp/SimpleAppDocumentNo.vue.eta +7 -1
  21. package/templates/nuxt/components/simpleApp/SimpleAppFieldContainer.vue.eta +23 -16
  22. package/templates/nuxt/components/simpleApp/SimpleAppInput.vue.eta +24 -7
  23. package/templates/nuxt/components/simpleApp/SimpleAppInputTable.vue.eta +4 -3
  24. package/templates/nuxt/components/user/UserProfileListItem.vue.eta +2 -2
  25. package/templates/nuxt/composables/date.generate.ts.eta +16 -0
  26. package/templates/nuxt/composables/goTo.generate.ts.eta +1 -0
  27. package/templates/nuxt/composables/stringHelper.generate.ts.eta +0 -5
  28. package/templates/nuxt/error.vue._eta +3 -3
  29. package/templates/nuxt/layouts/default.vue._eta +19 -34
  30. package/templates/nuxt/layouts/loginlayout.vue._eta +3 -0
  31. package/templates/nuxt/layouts/mobile.vue._eta +29 -0
  32. package/templates/nuxt/nuxt.config.ts._eta +25 -15
  33. package/templates/nuxt/pages/[xorg]/user/{index.vue._eta → index.vue.eta} +10 -12
  34. package/templates/nuxt/pages/login.vue._eta +34 -0
  35. package/templates/nuxt/plugins/10.simpleapp-event.ts.eta +35 -33
  36. package/templates/nuxt/server/api/[xorg]/[...].ts.eta +7 -40
  37. package/templates/nuxt/server/api/profile/[...].ts.eta +3 -32
  38. package/templates/nuxt/simpleapp/generate/clients/SimpleAppClient.ts.eta +1 -1
  39. package/templates/nuxt/types/calendar.ts.eta +8 -1
  40. package/templates/nuxt/types/others.ts.eta +4 -1
  41. package/templates/project/lang/default._json +4 -1
  42. package/tsconfig.tsbuildinfo +1 -1
  43. package/templates/nuxt/pages/login.vue.eta +0 -30
  44. /package/templates/nuxt/pages/[xorg]/user/{[id].vue._eta → [id].vue.eta} +0 -0
  45. /package/templates/nuxt/pages/[xorg]/{user.vue._eta → user.vue.eta} +0 -0
@@ -1,10 +1,11 @@
1
1
 
2
2
  <template>
3
- <span> {{ Intl.NumberFormat('en',{
3
+ <span v-if="showCurrency"> {{ Intl.NumberFormat( useI18n().defaultLocale,{
4
4
  style:'currency',
5
5
  currency: getUserProfile()?.currency,
6
6
  currencyDisplay: 'symbol',
7
7
  }).format(modelValue) }}</span>
8
+ <span v-else> {{ modelValue.toLocaleString(useI18n().defaultLocale,options) }}</span>
8
9
  </template>
9
10
  <script lang="ts" setup>
10
11
  /**
@@ -13,5 +14,12 @@
13
14
  * last change 2024-02-04
14
15
  * author: Ks Tan
15
16
  */
16
- const props = defineProps(['modelValue'])
17
+
18
+ const options = {
19
+ style: 'decimal', // Other options: 'currency', 'percent', etc.
20
+ minimumFractionDigits: 2,
21
+ maximumFractionDigits: 2,
22
+ };
23
+ const modelValue = defineModel<number>({required:true})
24
+ const props = defineProps<{showCurrency?:boolean}>()
17
25
  </script>
@@ -1,7 +1,7 @@
1
1
  <template>
2
- <a @click="openViewer" class="text-primary-700 hover:text-primary-500 cursor-pointer">
2
+ <a @click="openViewer" class="text-primary-700 dark:text-primary-400 hover:text-primary-500 cursor-pointer">
3
3
  <slot name="default">
4
- <div >{{ value[fields[0]] }}</div>
4
+ <div v-if="fields">{{ value[fields[0]] }}</div>
5
5
  </slot>
6
6
  </a>
7
7
  </template>
@@ -12,10 +12,10 @@
12
12
  * last change 2024-02-04
13
13
  * author: Ks Tan
14
14
  */
15
-
15
+ import { RendererSetting } from '~/types';
16
16
  const props = defineProps<{
17
- fields:any,
18
- setting:any,
17
+ fields?:string[],
18
+ setting:RendererSetting,
19
19
  value:any
20
20
  }>()
21
21
 
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <AutoComplete v-model="modelValue" v-if="!readonly" ref="autocompleteinput"
3
3
  forceSelection optionLabel="label"
4
- @focus="($event.target as HTMLInputElement).select()"
4
+ @focus="setFocus"
5
5
  @item-select="pickAutoComplete"
6
6
  @complete="getListFromAutocompleteApi"
7
7
  :placeholder="t('keyword')"
@@ -17,7 +17,25 @@
17
17
  @blur="onBlurAutocomplete"
18
18
  :inputId="inputId" :path="setting.instancepath"
19
19
  :readonly="readonly"
20
- />
20
+ >
21
+ <template #header>
22
+ <slot name="header">
23
+ <div class="flex flex-row font font-bold dark:text-white">
24
+ <div class="w w-1/3">{{ t(codefield) ?? t('code') }}</div>
25
+ <div class="w w-2/3" >{{ t(labelfield) ?? t('label') }}</div>
26
+ </div>
27
+ </slot>
28
+ </template>
29
+ <template #option="{index,option}">
30
+ <slot name="option" :index="index" :option="option">
31
+ <div class="flex flex-row dark:text-white">
32
+ <div class="w w-1/3" >{{ option.code }}</div>
33
+ <div class="w w-2/3" >{{ option.label }}</div>
34
+ </div>
35
+ </slot>
36
+ </template>
37
+ <!-- </slot> -->
38
+ </AutoComplete>
21
39
  <div v-else class="p-3 border rounded-lg border-gray-300 dark:border-blue-900/40 ">
22
40
  <span :readonly="readonly" class="cursor-pointer text-primary-600 dark:text-primary-400 "
23
41
  tabindex="0" @click="openViewer(true)">{{ modelValue && modelValue.label ? modelValue.label:'-' }}</span>
@@ -44,6 +62,12 @@ allowAddNew:true,showNull:true
44
62
  const path = '$'+props.setting.instancepath
45
63
  const modifiedpath = path.replaceAll('/','.')
46
64
  const queryresult = jsonpath.query(props.setting.defaultValue,modifiedpath)[0]
65
+ const remotedoc = getDocument(props.setting.fieldsetting['x-foreignkey'])
66
+ const schema:SchemaType = <SchemaType>remotedoc?.docClass.getSchema()
67
+
68
+ const labelfield = schema['x-simpleapp-config'].documentTitle as string
69
+ const codefield = schema['x-simpleapp-config'].uniqueKey as string
70
+ const docname = props.setting.fieldsetting['x-foreignkey']
47
71
 
48
72
  const emptyautocomplete = computed(():autocompletetype=> queryresult)
49
73
 
@@ -124,15 +148,16 @@ const emitChanges = () =>{
124
148
 
125
149
  }
126
150
 
151
+
152
+ const setFocus = (ev:any) => {
153
+ if(!isMobile()) ev.target.select()
154
+ }
155
+
127
156
  //pop up records
128
- const openViewer = (readonly:boolean) =>{
129
- const remotedoc = getDocument(props.setting.fieldsetting['x-foreignkey'])
157
+ const openViewer = (readonly:boolean) =>{
130
158
 
131
159
  if(remotedoc){
132
- const schema:SchemaType = remotedoc.docClass.getSchema()
133
- const labelfield = schema['x-simpleapp-config'].documentTitle as string
134
- const codefield = schema['x-simpleapp-config'].uniqueKey as string
135
- const docname = props.setting.fieldsetting['x-foreignkey']
160
+
136
161
  $event('ViewRecord',{
137
162
  _id: modelValue.value?._id as string,
138
163
  eventId: randomUUID(),
@@ -157,7 +182,7 @@ const openViewer = (readonly:boolean) =>{
157
182
  }
158
183
  modelValue.value = {...autocompleteitem.value}
159
184
  emitChanges()
160
- console.log("autocompleteitem.value",autocompleteitem.value ,modelValue.value)
185
+
161
186
 
162
187
  }
163
188
  })
@@ -3,11 +3,12 @@
3
3
 
4
4
  <div class="flex flex-row w-full">
5
5
  <InputText
6
+ @focus="setFocus"
6
7
  :readonly="readonly"
7
8
  v-model="modelValue"
8
9
  :placeholder="placeholder"
9
10
  :pt="pt"
10
- :class=" !pt ? 'flex-1 w-full rounded-lg '+ ( props.readonly?'':'dark:!bg-gray-700 rounded-tr-none rounded-br-none') : ''"
11
+ :class=" !pt ? 'flex-1 w-full rounded-lg '+ ( props.readonly?'':'rounded-tr-none rounded-br-none') : ''"
11
12
  />
12
13
  <span class="" v-if="!readonly">
13
14
  <button type="button" @click="toggle" tabindex="-1"
@@ -72,6 +73,11 @@ const loadDocFormats = async () =>{
72
73
  }
73
74
  }
74
75
 
76
+
77
+ const setFocus = (ev:any) => {
78
+ if(!isMobile()) ev.target.select()
79
+ }
80
+
75
81
  onMounted(()=>{
76
82
  loadDocFormats()
77
83
 
@@ -1,8 +1,9 @@
1
1
  <template>
2
- <div v-if="schema" class="flex flex-col">
3
- <div v-if="hidelabel"></div>
4
- <label v-else-if="error" class="simpleapp-input-label text-danger-600 overflow-hidden" :for="uuid">{{ fieldlabel }} <span v-if="props.setting.isrequired && fieldlabel" class="text-danger-600">*</span></label>
5
- <label v-else :for="uuid" class="simpleapp-input-label whitespace-nowrap text-gray-500 truncate">{{ fieldlabel }} <span v-if="props.setting.isrequired && fieldlabel" class="text-danger-600">*</span></label>
2
+ <div v-if="schema" :class="getLayoutClass()">
3
+ <label v-if="hidelabel"></label>
4
+ <label v-else :for="uuid" :class="getLabelClass()" @click="console.log(inputType)">{{ fieldlabel }} <span v-if="props.setting.isrequired && fieldlabel" class="text-danger-600">*</span></label>
5
+ <!-- <label v-else-if="error" class="simpleapp-input-label text-danger-600 overflow-hidden" :for="uuid">{{ fieldlabel }} <span v-if="props.setting.isrequired && fieldlabel" class="text-danger-600">*</span></label>
6
+ <label v-else :for="uuid" class="simpleapp-input-label whitespace-nowrap text-gray-500 truncate">{{ fieldlabel }} <span v-if="props.setting.isrequired && fieldlabel" class="text-danger-600">*</span></label> -->
6
7
 
7
8
  <!-- <div :uuid="uuid" >{{ modelValue }}</div> -->
8
9
  <!-- <div v-if="typeof modelValue =='object' && typeof modelValue['_id']!='undefined' && typeof modelValue['label']!='undefined' && readonly ==true " :uuid="uuid" class="simpleapp-value-readonly">{{ modelValue['label'] }}</div> -->
@@ -34,6 +35,7 @@ const fieldcontainerclass = ref(defaultcssclass)
34
35
  let instancepath = ref('')
35
36
  const props = defineProps<{
36
37
  label?: string,
38
+ inputType: string,
37
39
  description?: string,
38
40
  instancepath?:string,
39
41
  hidelabel?:boolean,
@@ -45,17 +47,27 @@ const props = defineProps<{
45
47
  const readonly = computed(()=>{
46
48
  return props.readonly ?? props.setting.readonly ?? false
47
49
  })
48
- // if(props.readonly !== undefined){
49
- // readonly.value=props.readonly
50
- // }else if(props.setting.readonly !==undefined){
51
- // readonly.value=props.readonly
52
- // }
53
- // console.log("props.setting.format",props.setting.format)
54
- const modelValue = defineModel()
50
+
51
+ const modelValue = defineModel<any>() //this model value support all kind of data, string, number, autocomplete and etc
55
52
  const readonlyclass="simpleapp-value-readonly"
56
53
  // console.log('props.setting',modelValue.value,props.setting)
57
54
  let schema:any
58
55
 
56
+ const getLayoutClass = () => `simpleapp-input-container flex ${ props.inputType == 'checkbox' ? " flex-row gap-4 mt-1 ml-1 " : "flex flex-col "}`
57
+
58
+ const getLabelClass = () => {
59
+ let class1= "simpleapp-input-label text-left text-gray-500 "
60
+ if(!isMobile()) class1 += "whitespace-nowrap truncate"
61
+ else if (props.inputType == 'checkbox' ) class1 += " ml-1 dark:text-grey-200"
62
+ else if (props.inputType != 'autocomplete' && modelValue.value) class1 += "-mb-4 ml-1 z-50 text-xs dark:text-grey-100"
63
+ else if (props.inputType == 'autocomplete' && modelValue.value?.label) class1 += "-mb-4 ml-1 z-50 text-xs dark:text-grey-100"
64
+ else if (props.inputType == 'number' && modelValue.value !== undefined) class1 += "-mb-4 ml-1 z-50 text-xs dark:text-grey-100"
65
+ else class1 += "-mb-4 ml-1 z-50 text-xs dark:text-grey-100 hidden"
66
+ return class1
67
+ }
68
+
69
+
70
+
59
71
  const fielddesc = computed(()=>{
60
72
  return props.description ?? ''
61
73
  })
@@ -116,8 +128,3 @@ watch(props.setting.errors,(newvalue,oldvalue)=>{
116
128
  })
117
129
 
118
130
  </script>
119
- <style scoped>
120
- .simpleapp-input-container{
121
- @apply flex flex-col
122
- }
123
- </style>
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <SimpleAppFieldContainer :hidelabel="hidelabel" v-model="modelValue"
3
- :label="label" :description="description" :pt="pt"
3
+ :label="label" :description="description" :pt="pt" :inputType="inputType"
4
4
  :setting="setting" :instancepath="instancepath" :error="error" #default="slotprops">
5
5
  <Checkbox v-if="inputType ==SimpleAppInputType.checkbox" :readonly="isReadonly" :pt="pt"
6
6
  :inputId="slotprops.uuid" :path="setting.instancepath"
@@ -93,6 +93,7 @@
93
93
  <Password
94
94
  v-else-if="inputType == SimpleAppInputType.password"
95
95
  :type="type" v-model="(modelValue as string)" :pt="pt"
96
+ @focus="setFocus"
96
97
  :readonly="isReadonly" class="flex flex-col"
97
98
  :inputId="slotprops.uuid" :path="setting.instancepath"
98
99
  :placeholder="placeholder"
@@ -117,6 +118,7 @@
117
118
  <!-- simple component -->
118
119
  <InputNumber v-else-if="inputType == SimpleAppInputType.number"
119
120
  :type="type" v-model="(modelValue as number)"
121
+ @focus="setFocus"
120
122
  :readonly="isReadonly"
121
123
  :pt="pt"
122
124
  :class="!pt ? 'w-full flex flex-col' :''"
@@ -125,7 +127,8 @@
125
127
  :placeholder="placeholder"
126
128
  />
127
129
  <Textarea v-else-if="inputType == SimpleAppInputType.textarea"
128
- v-model="(modelValue as string)"
130
+ v-model="(modelValue as string)"
131
+ :autofocus="autofocus"
129
132
  :readonly="isReadonly"
130
133
  :pt="pt"
131
134
  :type="type"
@@ -136,7 +139,9 @@
136
139
  v-bind="(componentProps as TextareaProps)"
137
140
  />
138
141
  <InputText v-else
139
- v-model="(modelValue as string)"
142
+ v-model="(modelValue as string)"
143
+ @focus="setFocus"
144
+ :autofocus="autofocus"
140
145
  :readonly="isReadonly"
141
146
  :pt="pt"
142
147
  :type="type"
@@ -186,6 +191,7 @@ const props = withDefaults( defineProps<{
186
191
  instancepath?:string,
187
192
  hidelabel?: boolean
188
193
  readonly?: boolean
194
+ autofocus?:boolean
189
195
  pt?:any,
190
196
  placeholder?:string
191
197
  componentProps?: InputNumberProps | InputSwitchProps | InputTextProps | TextareaProps | DropdownProps | CalendarProps | RatingProps
@@ -221,6 +227,9 @@ const updateDate = (value:any)=>{
221
227
 
222
228
  }
223
229
 
230
+ const setFocus = (ev:any) => {
231
+ if(!isMobile()) ev.target.select()
232
+ }
224
233
 
225
234
  const getListOptions = () =>{
226
235
 
@@ -244,6 +253,7 @@ const getListOptions = () =>{
244
253
 
245
254
  const emits = defineEmits(['change','update:modelValue','update:docNoFormat'])
246
255
 
256
+
247
257
  watch(modelValue ,(newvalue:any)=>{
248
258
 
249
259
  if([SimpleAppInputType.date,SimpleAppInputType.calendar].includes(props.inputType)){
@@ -259,7 +269,16 @@ watch(modelValue ,(newvalue:any)=>{
259
269
  emits('change',modelValue.value)
260
270
  emits('update:modelValue',modelValue.value)
261
271
  })
262
-
272
+ onMounted(()=>{
273
+ if([SimpleAppInputType.date,SimpleAppInputType.calendar].includes(props.inputType)){
274
+ if(modelValue.value){
275
+ datevalue.value = moment(modelValue.value as string ).format('YYYY-MM-DD')
276
+ }else{
277
+ datevalue.value = ''
278
+ }
279
+
280
+ }
281
+ })
263
282
 
264
283
  /************ start autocomplete only ***************/
265
284
 
@@ -272,6 +291,4 @@ watch(modelValue ,(newvalue:any)=>{
272
291
  const triggerDocNoFormatChange=(formatdata:any)=>{
273
292
  emits('update:docNoFormat',formatdata)
274
293
  }
275
- </script>
276
- <style scoped>
277
- </style>
294
+ </script>
@@ -2,9 +2,9 @@
2
2
  <DataTable v-bind="$attrs" stripedRows resizableColumns
3
3
  class="simpleapp-datatable p-datatable-sm" :value="modelValue">
4
4
  <template #empty> <div class="text-center">No record found.</div> </template>
5
- <template #header >
6
- <div>
7
- <Button v-if="!setting.readonly" icon="pi pi-plus" @click="addNew()" class="simpleapp-datatable-add btn-primary" type="button">Add</Button>
5
+ <template #header v-if="!setting.readonly && !readonly">
6
+ <div >
7
+ <Button icon="pi pi-plus" @click="addNew()" class="simpleapp-datatable-add btn-primary" type="button">Add</Button>
8
8
  </div>
9
9
  </template>
10
10
  <slot>
@@ -35,6 +35,7 @@ const props = defineProps<{
35
35
  // columns:InputTableColumn[],
36
36
  setting:any,
37
37
  getField:Function,
38
+ readonly?:boolean
38
39
  }>()
39
40
 
40
41
 
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <!-- <ul role="list" class="divide-y divide-gray-100">
3
3
  <li v-for="person in people" :key="person.email" class="flex justify-between gap-x-6 py-5"> -->
4
- <div class="flex justify-between gap-x-6 py-5 cursor-pointer">
4
+ <div class="flex justify-between gap-x-6 py-5 cursor-pointer" @click="emits('click',data)">
5
5
  <div class="flex min-w-0 gap-x-4">
6
6
  <img class="h-12 w-12 flex-none rounded-full bg-gray-50" :src="`${getAvatarLink(data.email,32)}`" alt="" />
7
7
  <div class="min-w-0 flex-auto">
@@ -38,7 +38,7 @@ import moment from 'moment'
38
38
  const props = defineProps<{
39
39
  data:any
40
40
  }>()
41
-
41
+ const emits = defineEmits(['click'])
42
42
 
43
43
 
44
44
  const datedifferent = computed(()=>{
@@ -0,0 +1,16 @@
1
+ import moment from "moment";
2
+
3
+ export const dateExists = (date:Date,listDate:Date[]) => {
4
+ const existsrecord = listDate.find(item=>{
5
+ return date.getTime()===item.getTime()
6
+ })
7
+ return existsrecord===undefined ? false :true
8
+ }
9
+ export const getMoment = (startTime:string)=> moment(startTime)
10
+ export const lastDateOfMonth = (datestr:string) => moment(datestr).endOf('month').format('YYYY-MM-DD');
11
+ export const today = () => moment().format('YYYY-MM-DD')
12
+ export const dateToString = (date:Date) => moment(date).format('YYYY-MM-DD')
13
+ export const dateToDateTimeString = (date:Date)=> moment(date).format('YYYY-MM-DD HH:mm:ss')
14
+ export const toLocalDate = (dateiso8601:string)=> new Date(String(dateiso8601)).toLocaleDateString()
15
+
16
+
@@ -30,3 +30,4 @@ export const getPathPara = (paraname:string,emptyvalue:string=''):string=>{
30
30
  }
31
31
  }
32
32
 
33
+ export const setCurrentUrl = (path:string)=>useRouter().push({path:path})
@@ -16,10 +16,5 @@ export const getAvatarLink = (email:string, size:number):string=>{
16
16
 
17
17
  }
18
18
 
19
- export const toLocalDate = (dateiso8601:string)=> new Date(String(dateiso8601)).toLocaleDateString()
20
19
  export const t = (txt:string,options?:any):string => !txt || txt.trim()=='' ? '' : useNuxtApp().$i18n.t(txt,options)
21
- export const today = () => moment().format('YYYY-MM-DD')
22
- export const dateToString = (date:Date) => moment(date).format('YYYY-MM-DD')
23
- export const getMoment = (startTime:string)=> moment(startTime)
24
- export const lastDateOfMonth = (datestr:string) => moment(datestr).endOf('month').format('YYYY-MM-DD');
25
20
  export const upperFirst = (str:string) => _.upperFirst(str)
@@ -1,10 +1,10 @@
1
1
  <template>
2
- <div class="flex items-center justify-center py-12 bg bg-gray-500">
3
- <div class="bg-white border rounded-md flex items-center justify-center mx-4 md:w-2/3">
2
+ <div class="w w-full items-center justify-center py-12 bg bg-gray-500">
3
+ <div class="bg-white dark:bg-gray-600 p-1 border rounded-md flex items-center justify-center mx-4 w-7/8 md:w-2/3">
4
4
  <div class="flex flex-col items-center py-16">
5
5
 
6
6
  <div class="flex flex-row">
7
- <div class="w w-40">
7
+ <div class="w w-full ">
8
8
  <svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-13.59 -13.59 480.17 480.17" xml:space="preserve" fill="#000000" stroke="#000000" stroke-width="0.00452986"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <g> <g> <g> <path style="fill:#010002;" d="M0,0v452.986h452.986V0H0z M403.223,24.655c8.132,0,14.668,6.558,14.668,14.625 c0,8.111-6.536,14.711-14.668,14.711c-8.089,0-14.668-6.601-14.668-14.711C388.576,31.234,395.134,24.655,403.223,24.655z M352.035,24.655c8.046,0,14.647,6.558,14.647,14.625c0,8.111-6.601,14.711-14.647,14.711c-8.132,0-14.668-6.601-14.668-14.711 C337.389,31.234,343.903,24.655,352.035,24.655z M417.955,418.624H35.053V85.701h382.903V418.624z"></path> <path style="fill:#010002;" d="M226.493,398.952c80.394,0,145.495-65.101,145.495-145.43s-65.101-145.495-145.495-145.495 c-80.373,0-145.516,65.165-145.516,145.495C80.977,333.873,146.12,398.952,226.493,398.952z M142.044,198.516l29.444-29.444 l55.005,55.027l54.984-55.027l29.379,29.444L255.894,253.5l54.984,54.941l-29.423,29.444l-54.962-54.962l-55.005,54.984 l-29.444-29.444l54.984-54.941L142.044,198.516z"></path> </g> </g> <g> </g> <g> </g> <g> </g> <g> </g> <g> </g> <g> </g> <g> </g> <g> </g> <g> </g> <g> </g> <g> </g> <g> </g> <g> </g> <g> </g> <g> </g> </g> </g></svg>
9
9
  </div>
10
10
  <div>
@@ -1,15 +1,18 @@
1
1
  <template>
2
- <div class="h-full flex flex-row" v-if="!isMobile()">
3
- <div>
4
- <HeaderButtonMenuPicker class="p-2 text-6xl cursor-pointer"></HeaderButtonMenuPicker>
5
- <div class="" v-for="item in menus">
6
- <div class="border">
7
- <NuxtLink
8
- :class="`pi ${item.iconClass} p-2 text-6xl cursor-pointer`"
9
- :to="getDocumentUrl(item.path)"
10
- ></NuxtLink>
11
- </div>
12
- </div>
2
+ <div class="h-full flex flex-row">
3
+ <div class="flex flex-col justify justify-between">
4
+ <div >
5
+ <HeaderButtonMenuPicker class="cursor-pointer p-2 text-6xl "></HeaderButtonMenuPicker>
6
+ <div class="" v-for="item in menus">
7
+ <div class="">
8
+ <NuxtLink
9
+ :class="`pi ${item.iconClass} p-2 text-6xl cursor-pointer`"
10
+ :to="getDocumentUrl(item.path)"
11
+ ></NuxtLink>
12
+ </div>
13
+ </div>
14
+ </div>
15
+ <HeaderButtonProfile class="p-6"/>
13
16
  </div>
14
17
  <div class="flex-1">
15
18
  <HeaderBar />
@@ -17,33 +20,15 @@
17
20
  <slot></slot>
18
21
  </div>
19
22
  </div>
20
- <div v-else class="mb-20">
21
- <div v-if="getCurrentXorg()" class="border flex flex-row h-20 fixed left-0 w-full justify justify-between bottom-0 z-50 bg-white dark:bg-gray-800" >
22
-
23
- <div v-for="item in menus">
24
- <NuxtLink
25
- :class="`pi ${item.iconClass} p-2 text-6xl cursor-pointer`"
26
- :to="getDocumentUrl(item.path)"
27
- ></NuxtLink>
28
- </div>
29
- <HeaderButtonMenuPicker class="p-2 text-6xl cursor-pointer"></HeaderButtonMenuPicker>
30
- </div>
31
- <div class="flex flex-col h-screen ">
32
-
33
- <HeaderBar />
34
- <UserInvitation/>
35
- <slot></slot>
36
-
37
- </div>
38
- </div>
23
+
39
24
  </template>
40
25
  <script setup lang="ts">
41
26
  const menus=[
42
27
  // {iconClass:'pi-bars',path:'managestudents/profile'},
43
- {iconClass:'pi-home',path:''},
44
- {iconClass:'pi-users',path:'managestudents/profile'},
45
- {iconClass:'pi-calendar',path:`manageclasses`},
28
+ {iconClass:'pi-home text-white',path:''},
29
+ {iconClass:'pi-users text-white',path:'managestudents/profile'},
30
+ {iconClass:'pi-calendar text-white',path:`manageclasses`},
46
31
  // {iconClass:'pi-database',path:'managedata'},
47
- {iconClass:'pi-chart-pie',path:'reports'},
32
+ {iconClass:'pi-chart-pie text-white',path:'reports'},
48
33
  ]
49
34
  </script>
@@ -0,0 +1,3 @@
1
+ <template>
2
+ <slot v-if="useRoute().path=='/login'"></slot>
3
+ </template>
@@ -0,0 +1,29 @@
1
+ <template>
2
+ <div class="h-screen flex flex-col">
3
+ <div class="flex flex-col grow">
4
+ <slot></slot>
5
+ </div>
6
+ <!-- fixed -->
7
+ <div v-if="getCurrentXorg()" class="flex h-20 border-t-2 dark:border-t-gray-700 text-4xl flex-row left-0 w-full justify justify-between bottom-0 z-50 bg-white dark:bg-gray-600 pl-2 pr-2" >
8
+ <NuxtLink v-for="item in menus"
9
+ :class="`pi ${item.iconClass} pb-6 pt-6 cursor-pointer inline-block align-middle`"
10
+ :to="getDocumentUrl(item.path)"
11
+ ></NuxtLink>
12
+ <HeaderButtonMenuPicker class=" cursor-pointer"></HeaderButtonMenuPicker>
13
+ <HeaderButtonProfile class=""/>
14
+ <UserInvitation/>
15
+ </div>
16
+ <!-- <HeaderBar class="border flex flex-row h-10 fixed left-0 w-full justify justify-between top-0 z-50 bg-white dark:bg-gray-800"/> -->
17
+
18
+ </div>
19
+ </template>
20
+ <script setup lang="ts">
21
+ const menus=[
22
+ // {iconClass:'pi-bars',path:'managestudents/profile'},
23
+ {iconClass:'pi-home text-white',path:''},
24
+ // {iconClass:'pi-users text-white',path:'managestudents/profile'},
25
+ // {iconClass:'pi-calendar text-white',path:`manageclasses`},
26
+ // {iconClass:'pi-database',path:'managedata'},
27
+ // {iconClass:'pi-chart-pie text-white',path:'reports'},
28
+ ]
29
+ </script>
@@ -6,7 +6,11 @@
6
6
  */
7
7
  import path from 'path'
8
8
  export default defineNuxtConfig({
9
- // colorMode: {} ,
9
+ colorMode: {
10
+ classSuffix: ''
11
+
12
+ },
13
+
10
14
  runtimeConfig:{
11
15
  public:{
12
16
  APP_URL: process.env.APP_URL,
@@ -26,16 +30,19 @@ export default defineNuxtConfig({
26
30
  tailwindcss: {
27
31
  // Options
28
32
  },
29
- devServer: {
30
- // host: "0.0.0.0",
31
- },
33
+ devServer: {
34
+ host: "0.0.0.0",
35
+ },
32
36
  modules: [
33
37
  // "@hebilicious/authjs-nuxt",
38
+ '@nuxtjs/color-mode',
39
+ '@nuxtjs/device',
34
40
  '@nuxtjs/i18n',
35
41
  '@sidebase/nuxt-auth',
36
42
  'nuxt-primevue',
43
+ // '@nuxtjs/pwa', //cannot turn on, will cause nuxt cant start
37
44
  // "nuxt-security", //temporary avoid nuxt-security cause cors
38
- '@vueuse/nuxt',
45
+ '@vueuse/nuxt',
39
46
  '@nuxtjs/tailwindcss',
40
47
  ['@pinia/nuxt',{
41
48
  autoImports: [
@@ -44,10 +51,13 @@ tailwindcss: {
44
51
  ['defineStore', 'definePiniaStore'], // import { defineStore as definePiniaStore } from 'pinia'
45
52
  ],
46
53
  }],
47
- '@nuxtjs/color-mode',
54
+
48
55
 
49
56
 
50
- ],
57
+ ],
58
+ device: {
59
+ refreshOnResize: true
60
+ },
51
61
  i18n: {
52
62
  lazy: true,
53
63
  langDir: "lang/",
@@ -70,13 +80,14 @@ tailwindcss: {
70
80
  iso: "cn",
71
81
  name: "Chinese",
72
82
  file: "cn.ts",
83
+
73
84
  },
74
85
  ],
75
86
  defaultLocale: "df",
76
87
  },
77
88
  primevue: {
78
89
  options: {
79
- unstyled: true,
90
+ //unstyled: true,
80
91
  ripple: true,
81
92
  inputStyle: 'filled'
82
93
  },
@@ -85,7 +96,7 @@ tailwindcss: {
85
96
  exclude: ['chart']
86
97
  },
87
98
  directives: {
88
- include: ['Ripple', 'Tooltip','BadgeDirective']
99
+ include: ['Ripple', 'Tooltip','BadgeDirective','FocusTrap']
89
100
  },
90
101
  cssLayerOrder: 'tailwind-base, primevue, tailwind-utilities',
91
102
  importPT: { as: 'SimpleAppPT', from: path.resolve(__dirname,'./assets/primevue/passthrough.ts') },
@@ -96,7 +107,7 @@ tailwindcss: {
96
107
 
97
108
  // },
98
109
  auth: {
99
- globalAppMiddleware: true
110
+ globalAppMiddleware: false
100
111
  },
101
112
  // security: {
102
113
  // corsHandler:{
@@ -127,13 +138,12 @@ tailwindcss: {
127
138
  'primeicons/primeicons.css',
128
139
  path.resolve(__dirname,'./assets/css/style.css'),
129
140
  path.resolve(__dirname,'./assets/css/calendar.css'),
130
- ],
141
+ ],
142
+ },
131
143
 
132
144
  // devtools: { enabled: true },
133
145
  // build: {
134
146
  // // transpile: ["primevue"]
135
- // },
136
-
137
-
147
+ // },
138
148
 
139
- })
149
+ )