From da88e626bbfa5670d71bf3bd7a48f74ab1187d6f Mon Sep 17 00:00:00 2001 From: Angel Fernando Quiroz Campos Date: Thu, 23 Mar 2023 19:21:59 -0500 Subject: [PATCH 1/6] UI: ShowLinks component use composition API and primeVue --- .../components/resource_links/ShowLinks.vue | 161 ++++++++++-------- 1 file changed, 88 insertions(+), 73 deletions(-) diff --git a/assets/vue/components/resource_links/ShowLinks.vue b/assets/vue/components/resource_links/ShowLinks.vue index acfd81fcc5..6a1ec88495 100644 --- a/assets/vue/components/resource_links/ShowLinks.vue +++ b/assets/vue/components/resource_links/ShowLinks.vue @@ -1,87 +1,102 @@ - From 443293642b85154bb14a01c25d030522cc6cdb6e Mon Sep 17 00:00:00 2001 From: Angel Fernando Quiroz Campos Date: Thu, 23 Mar 2023 19:23:07 -0500 Subject: [PATCH 2/6] Documents: Fix form to don't show status and user filter --- assets/vue/views/documents/Update.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assets/vue/views/documents/Update.vue b/assets/vue/views/documents/Update.vue index 562785d22c..e818d5d568 100644 --- a/assets/vue/views/documents/Update.vue +++ b/assets/vue/views/documents/Update.vue @@ -7,7 +7,8 @@ From 847a56d7c0cb9596b4187a2daa7bd31465aa80f4 Mon Sep 17 00:00:00 2001 From: Angel Fernando Quiroz Campos Date: Mon, 27 Mar 2023 02:00:05 -0500 Subject: [PATCH 3/6] UI: Use toast instead of message --- assets/css/scss/atoms/_toast.scss | 46 +++++++++++++++++++ assets/css/scss/index.scss | 1 + assets/vue/App.vue | 54 +++++++++++++++-------- assets/vue/composables/datatableCreate.js | 7 +-- assets/vue/composables/datatableList.js | 12 ++--- assets/vue/composables/datatableUpdate.js | 8 ++-- assets/vue/views/ccalendarevent/List.vue | 11 +++-- assets/vue/views/documents/List.vue | 10 +++-- assets/vue/views/page/Create.vue | 8 ++-- assets/vue/views/page/List.vue | 15 ++++--- 10 files changed, 125 insertions(+), 47 deletions(-) create mode 100644 assets/css/scss/atoms/_toast.scss diff --git a/assets/css/scss/atoms/_toast.scss b/assets/css/scss/atoms/_toast.scss new file mode 100644 index 0000000000..b4b778d5c8 --- /dev/null +++ b/assets/css/scss/atoms/_toast.scss @@ -0,0 +1,46 @@ +$color_1: #01579B; +$color_2: #1B5E20; +$color_3: #7f6003; +$color_4: #B71C1C; + +.p-toast { + @apply opacity-95; + + &-message { + @apply rounded-md mb-3.5 shadow-gray-30 shadow-md; + + &-content { + @apply py-4 px-6 gap-2.5; + + .p-toast-message-text { + @apply text-body-1; + } + .p-toast-message-icon { + } + .p-toast-summary { + @apply font-semibold; + } + .p-toast-detail { + } + } + + .p-toast-icon-close { + @apply rounded-full transition duration-200 w-4 h-6 + focus:outline-none; + } + + &.p-toast-message-info { + @apply bg-primary text-white; + } + + &.p-toast-message-success { + @apply bg-success text-white; + } + &.p-toast-message-warn { + @apply bg-warning text-gray-90; + } + &.p-toast-message-error { + @apply bg-error text-white; + } + } +} diff --git a/assets/css/scss/index.scss b/assets/css/scss/index.scss index 9c7cea474c..eaecd22a17 100755 --- a/assets/css/scss/index.scss +++ b/assets/css/scss/index.scss @@ -29,6 +29,7 @@ @import "atoms/radio"; @import "atoms/skeleton"; @import "atoms/tags"; +@import "atoms/toast"; @import "molecules/course_tool"; @import "molecules/datepicker"; diff --git a/assets/vue/App.vue b/assets/vue/App.vue index 92949f7045..80190c3b70 100644 --- a/assets/vue/App.vue +++ b/assets/vue/App.vue @@ -3,18 +3,32 @@ :is="layout" :show-breadcrumb="route.meta.showBreadcrumb" > - - -
- - + +
{ const queryParams = new URLSearchParams(window.location.search); @@ -137,10 +154,6 @@ const payload = {isAuthenticated, user}; store.dispatch('security/onRefresh', payload); -const flashMessageList = ref([]); - -provide('flashMessageList', flashMessageList); - onMounted(() => { const app = document.getElementById('app'); @@ -152,9 +165,10 @@ onMounted(() => { for (const key in flashes) { for (const flashText in flashes[key]) { - flashMessageList.value.push({ + toast.add({ severity: key, detail: flashes[key][flashText], + life: 3500, }); } } @@ -164,14 +178,16 @@ axios.interceptors.response.use( undefined, (error) => new Promise(() => { if (401 === error.response.status) { - flashMessageList.value.push({ + toast.add({ severity: 'warn', detail: error.response.data.error, + life: 3500, }); } else if (500 === error.response.status) { - flashMessageList.value.push({ + toast.add({ severity: 'warn', detail: error.response.data.detail, + life: 3500, }); } diff --git a/assets/vue/composables/datatableCreate.js b/assets/vue/composables/datatableCreate.js index 5e9194549f..7a553faabf 100644 --- a/assets/vue/composables/datatableCreate.js +++ b/assets/vue/composables/datatableCreate.js @@ -1,7 +1,7 @@ -import { inject } from 'vue'; import { useI18n } from 'vue-i18n'; import { useRoute, useRouter } from 'vue-router'; import { useStore } from 'vuex'; +import { useToast } from 'primevue/usetoast'; export function useDatatableCreate (servicePrefix) { const moduleName = servicePrefix.toLowerCase(); @@ -11,14 +11,15 @@ export function useDatatableCreate (servicePrefix) { const route = useRoute(); const { t } = useI18n(); - const flashMessageList = inject('flashMessageList'); + const toast = useToast(); function onCreated (item) { - flashMessageList.value.push({ + toast.add({ severity: 'success', detail: t('{resource} created', { 'resource': item['resourceNode'] ? item['resourceNode'].title : item.title, }), + life: 3500, }); let folderParams = route.query; diff --git a/assets/vue/composables/datatableList.js b/assets/vue/composables/datatableList.js index 9dfe1d6f9a..3a2be75ef4 100644 --- a/assets/vue/composables/datatableList.js +++ b/assets/vue/composables/datatableList.js @@ -1,10 +1,11 @@ import { useStore } from 'vuex' -import { inject, ref } from 'vue'; +import { ref } from 'vue'; import { useRoute, useRouter } from 'vue-router'; import { isEmpty } from 'lodash' import { useCidReq } from './cidReq' import { useI18n } from 'vue-i18n'; +import { useToast } from 'primevue/usetoast'; export function useDatatableList (servicePrefix) { const moduleName = servicePrefix.toLowerCase() @@ -16,7 +17,7 @@ export function useDatatableList (servicePrefix) { const { cid, sid, gid } = useCidReq() - const flashMessageList = inject('flashMessageList') + const toast = useToast(); const filters = ref({}) @@ -116,10 +117,11 @@ export function useDatatableList (servicePrefix) { onUpdateOptions(options.value); - flashMessageList.value.push({ + toast.add({ severity: 'success', - detail: t('Deleted') - }) + detail: t('Deleted'), + life: 3500, + }); } return { diff --git a/assets/vue/composables/datatableUpdate.js b/assets/vue/composables/datatableUpdate.js index 7943b79ac2..05e59c21dc 100644 --- a/assets/vue/composables/datatableUpdate.js +++ b/assets/vue/composables/datatableUpdate.js @@ -1,8 +1,9 @@ -import { computed, inject, ref, watch } from 'vue'; +import { computed, ref, watch } from 'vue'; import { useStore } from 'vuex'; import { useRoute } from 'vue-router'; import { isEmpty } from 'lodash'; import { useI18n } from 'vue-i18n'; +import { useToast } from 'primevue/usetoast'; export function useDatatableUpdate (servicePrefix) { const moduleName = servicePrefix.toLowerCase(); @@ -11,7 +12,7 @@ export function useDatatableUpdate (servicePrefix) { const route = useRoute(); const { t } = useI18n(); - const flashMessageList = inject('flashMessageList'); + const toast = useToast(); const isLoading = computed(() => store.getters[`${moduleName}/isLoading`]); @@ -74,11 +75,12 @@ export function useDatatableUpdate (servicePrefix) { } function onUpdated (item) { - flashMessageList.value.push({ + toast.add({ severity: 'success', detail: t('{resource} updated', { 'resource': item['@id'], }), + life: 3500, }); } diff --git a/assets/vue/views/ccalendarevent/List.vue b/assets/vue/views/ccalendarevent/List.vue index 99c6e6b0f4..10e78af65f 100644 --- a/assets/vue/views/ccalendarevent/List.vue +++ b/assets/vue/views/ccalendarevent/List.vue @@ -93,7 +93,7 @@ diff --git a/assets/vue/views/page/List.vue b/assets/vue/views/page/List.vue index 2be23869bf..eb25b4b665 100644 --- a/assets/vue/views/page/List.vue +++ b/assets/vue/views/page/List.vue @@ -228,8 +228,9 @@ import PrimeToolbar from 'primevue/toolbar'; import { useStore } from 'vuex'; import { useDatatableList } from '../../composables/datatableList'; -import { computed, inject, onMounted, ref } from 'vue'; +import { computed, onMounted, ref } from 'vue'; import { useI18n } from 'vue-i18n'; +import { useToast } from 'primevue/usetoast'; const store = useStore(); @@ -237,7 +238,7 @@ const { t } = useI18n(); const { filters, options, onUpdateOptions, goToAddItem, onShowItem, goToEditItem, deleteItem } = useDatatableList('Page'); -const flashMessageList = inject('flashMessageList'); +const toast = useToast(); onMounted(() => { filters.value.loadNode = 0; @@ -290,9 +291,10 @@ const saveItem = () => { if (!item.value.id) { // item.value.creator //createCategory.value(item.value); - flashMessageList.value.push({ + toast.add({ severity: 'success', - detail: t('Saved') + detail: t('Saved'), + life: 3500, }); } @@ -308,9 +310,10 @@ const deleteMultipleItems = () => { deleteMultipleDialog.value = false; selectedItems.value = []; - flashMessageList.value.push({ + toast.add({ severity: 'success', - detail: t('Pages deleted') + detail: t('Pages deleted'), + life: 3500, }); }); From 1f101f3b6d61cce77df3d2e8ac3ac1c354bc98e9 Mon Sep 17 00:00:00 2001 From: Angel Fernando Quiroz Campos Date: Thu, 30 Mar 2023 08:48:27 -0500 Subject: [PATCH 4/6] UI: Fix CSS conflict between inputtext and dropdown --- assets/css/app.scss | 4 - assets/css/scss/_catalog_course.scss | 22 ----- assets/css/scss/_catalog_session.scss | 22 ----- assets/css/scss/atoms/_dropdown.scss | 124 +++++++++++-------------- assets/css/scss/atoms/_form.scss | 45 +++++++-- assets/css/scss/atoms/_input_text.scss | 80 ++++++++-------- assets/css/scss/index.scss | 2 +- 7 files changed, 129 insertions(+), 170 deletions(-) diff --git a/assets/css/app.scss b/assets/css/app.scss index b61cfcbc60..bc59f0c65e 100644 --- a/assets/css/app.scss +++ b/assets/css/app.scss @@ -168,10 +168,6 @@ } } -.mdi { - @apply align-middle inline-flex leading-none; -} - //@import 'primevue-md-light-indigo/theme.css'; //@import '~primevue/resources/primevue.min.css'; //@import '~primeflex/primeflex.css'; diff --git a/assets/css/scss/_catalog_course.scss b/assets/css/scss/_catalog_course.scss index 992c7ccdf0..2512ee4bc8 100644 --- a/assets/css/scss/_catalog_course.scss +++ b/assets/css/scss/_catalog_course.scss @@ -16,28 +16,6 @@ position: absolute; top: 50%; } -.p-input-icon-left > .p-inputtext { - padding-left: 2.5rem; -} -.p-inputtext { - font-size: 1rem; - color: #495057; - background: #ffffff; - padding: 0.75rem 0.75rem; - border: 1px solid #ced4da; - transition: background-color 0.2s, color 0.2s, border-color 0.2s, box-shadow 0.2s; - appearance: none; - border-radius: 6px; -} -.p-inputtext:enabled:hover { - border-color: #3B82F6; -} -.p-inputtext:enabled:focus { - outline: 0 none; - outline-offset: 0; - box-shadow: 0 0 0 0.2rem #BFDBFE; - border-color: #3B82F6; -} ::v-deep(.p-datatable.p-datatable-courses) { .p-datatable-header { padding: 1rem; diff --git a/assets/css/scss/_catalog_session.scss b/assets/css/scss/_catalog_session.scss index 8e69125eb8..746a47d808 100644 --- a/assets/css/scss/_catalog_session.scss +++ b/assets/css/scss/_catalog_session.scss @@ -19,28 +19,6 @@ position: absolute; top: 50%; } -.p-input-icon-left > .p-inputtext { - padding-left: 2.5rem; -} -.p-inputtext { - font-size: 1rem; - color: #495057; - background: #ffffff; - padding: 0.75rem 0.75rem; - border: 1px solid #ced4da; - transition: background-color 0.2s, color 0.2s, border-color 0.2s, box-shadow 0.2s; - appearance: none; - border-radius: 6px; -} -.p-inputtext:enabled:hover { - border-color: #3B82F6; -} -.p-inputtext:enabled:focus { - outline: 0 none; - outline-offset: 0; - box-shadow: 0 0 0 0.2rem #BFDBFE; - border-color: #3B82F6; -} .orders-subtable { padding: 1rem; } diff --git a/assets/css/scss/atoms/_dropdown.scss b/assets/css/scss/atoms/_dropdown.scss index 0ddc20ed33..08dcca0093 100644 --- a/assets/css/scss/atoms/_dropdown.scss +++ b/assets/css/scss/atoms/_dropdown.scss @@ -1,108 +1,90 @@ -select.p-dropdown { - @apply p-4; -} - .p-dropdown { - @apply bg-white border border-solid border-support-3 p-3.5 rounded-lg transition gap-3 - hover:border-primary; - - .p-dropdown-label { - @apply outline-none; - } - - .p-dropdown-trigger { - .p-dropdown-trigger-icon { - @apply text-gray-90; - } - } + @apply border border-support-3 bg-white rounded-lg transition w-full duration-200 + hover:border-primary hover:text-gray-90 hover:outline-0 hover:outline-none; - &.p-inputwrapper-filled { - ~ label { - @apply text-primary text-caption; + &.p-dropdown-clearable { + .p-dropdown-label { + //padding-right: nth($inputPadding, 2) + $primeIconFontSize; } } - &.p-invalid { - @apply border-error text-error; + .p-dropdown-label { + @apply bg-transparent border-none + focus:outline-0 focus:outline-none; - ~ label { - @apply text-error; + &.p-placeholder { + //color: $inputPlaceholderTextColor; } } -} -.p-float-label { - .p-dropdown { - @apply w-full; - - &.p-inputwrapper-focus { - @apply border-primary; - - ~ label { - @apply top-0 text-primary text-caption; - } + .p-dropdown-trigger { + @apply bg-transparent rounded-r-lg w-12; + } - .p-placeholder { - @apply text-body-1 text-gray-90; - } - } + .p-dropdown-clear-icon { + } - &.p-inputwrapper-filled { - ~ label { - @apply top-0; - } - } + &.p-invalid.p-component { + @apply border-error text-error; } } -$color_1: #3f3f46; - .p-dropdown-panel { - @apply bg-white text-gray-50 border-none rounded-lg drop-shadow-lg; + @apply bg-white rounded-lg text-gray-90 shadow-lg; .p-dropdown-header { - @apply p-2 border-none bg-gray-15 rounded-t-lg; - - .p-dropdown-filter.p-inputtext { - @apply py-2 px-3.5 -mr-10; + //padding: $inputListHeaderPadding; + //border-bottom: $inputListHeaderBorder; + //color: $inputListHeaderTextColor; + //background: $inputOverlayHeaderBg; + //margin: $inputListHeaderMargin; + //border-top-right-radius: $borderRadius; + //border-top-left-radius: $borderRadius; + + .p-dropdown-filter { + //padding-right: nth($inputPadding, 2) + $primeIconFontSize; + //margin-right: -1 * (nth($inputPadding, 2) + $primeIconFontSize); } .p-dropdown-filter-icon { - @apply right-4 text-gray-90; + //right: nth($inputPadding, 2); + //color: $inputIconColor; } } .p-dropdown-items { - @apply p-0; + @apply py-1.5; .p-dropdown-item { - @apply outline-none m-0 px-3 py-2 border-none text-gray-50 text-body-2; - - &:not(.p-highlight) { - &:not(.p-disabled) { - &.p-focus, - &:hover { - @apply text-gray-90; - } + @apply px-4 py-2 transition text-body-2 outline-0 outline-none text-gray-90; + + &.p-highlight { + @apply bg-support-3 text-support-4; + + &.p-focus { } } - } - .p-dropdown-item.p-highlight { - @apply text-primary; + &:not(.p-highlight):not(.p-disabled) { + &.p-focus, + &:hover { + @apply bg-support-1; + } + } } .p-dropdown-item-group { - margin: 0; - padding: 0.75rem 1rem; - color: $color_1; - background: #ffffff; - font-weight: 600; + //margin: $submenuHeaderMargin; + //padding: $submenuHeaderPadding; + //color: $submenuHeaderTextColor; + //background: $submenuHeaderBg; + //font-weight: $submenuHeaderFontWeight; } + .p-dropdown-empty-message { - padding: 0.75rem 1rem; - color: $color_1; - background: transparent; + //padding: $inputListItemPadding; + //color: $inputListItemTextColor; + //background: $inputListItemBg; } } } diff --git a/assets/css/scss/atoms/_form.scss b/assets/css/scss/atoms/_form.scss index b7c95030c0..7b50904099 100644 --- a/assets/css/scss/atoms/_form.scss +++ b/assets/css/scss/atoms/_form.scss @@ -14,7 +14,7 @@ [multiple], textarea, select { - @apply text-body-1 text-gray-90 + @apply text-body-1 text-gray-90 outline-0 outline-none placeholder:text-gray-90 focus:outline-none focus:outline-offset-0 focus:ring-0 focus:ring-offset-0; } @@ -26,12 +26,6 @@ @apply hidden; } } - - form { - small { - @apply text-caption; - } - } } @layer components { @@ -63,6 +57,11 @@ } } +.field { + > small { + @apply text-caption; + } +} .p-error { @apply text-error; @@ -71,3 +70,35 @@ .p-disabled { @apply opacity-60; } + +.p-float-label { + label { + @apply left-4 text-support-3 bg-transparent transition-all duration-200; + } + + input:focus, + input.p-filled, + textarea:focus, + textarea.p-filled, + .p-inputwrapper-focus, + .p-inputwrapper-filled { + ~ label { + @apply bg-white px-1 text-primary top-0 left-2; + } + } + + .p-invalid ~ label { + @apply text-error; + } + + input:focus, + input.p-filled, + textarea:focus, + textarea.p-filled, + .p-inputwrapper-focus, + .p-inputwrapper-filled { + &.p-invalid ~ label { + @apply text-error; + } + } +} diff --git a/assets/css/scss/atoms/_input_text.scss b/assets/css/scss/atoms/_input_text.scss index b454f79c80..d92274397c 100644 --- a/assets/css/scss/atoms/_input_text.scss +++ b/assets/css/scss/atoms/_input_text.scss @@ -1,61 +1,55 @@ -input.p-inputtext { - @apply bg-white border border-solid border-support-3 p-3.5 rounded-lg transition outline-none w-full - hover:border-primary focus:border-primary; - - &:focus, - &.p-filled { - ~ { - label { - @apply text-caption text-primary; - } - } - } +.p-inputtext { + @apply border border-support-3 px-4 py-3 text-body-1 bg-white rounded-lg text-gray-90 transition w-full duration-200 + placeholder:text-support-3 + hover:border-primary hover:text-gray-90 hover:outline-0 hover:outline-none + focus:border-primary focus:text-gray-90 hover:outline-0 hover:outline-none; &.p-invalid.p-component { - @apply border-error text-error; + @apply border-error + placeholder:text-error; } &.p-inputtext-sm { - @apply px-2 py-1; + @apply px-2 py-1.5 text-body-2; } &.p-inputtext-lg { - @apply px-6 py-5; + @apply py-4; } +} - &.p-invalid { - ~ label, - &:focus ~ label { - @apply text-error; - } - } +.p-input-icon-left > i:first-of-type { + //left: nth($inputPadding, 2); + //color: $inputIconColor; } -.p-input-icon-right { - > .p-inputtext { - @apply pr-10; - } +.p-input-icon-left > .p-inputtext { + //padding-left: nth($inputPadding, 2) * 2 + $primeIconFontSize; +} - > i:last-of-type { - @apply right-3; - } +.p-input-icon-left.p-float-label > label { + //left: nth($inputPadding, 2) * 2 + $primeIconFontSize; } -.p-float-label { - input.p-inputtext { - @apply w-full; - - &:focus, - &.p-filled { - ~ { - label { - @apply top-0; - } - } - } - } +.p-input-icon-right > i:last-of-type { + //right: nth($inputPadding, 2); + //color: $inputIconColor; +} + +.p-input-icon-right > .p-inputtext { + //padding-right: nth($inputPadding, 2) * 2 + $primeIconFontSize; +} - > label { - @apply bg-white duration-200 left-2 px-1 text-support-3; +.p-inputtext-sm { + .p-inputtext { + //@include scaledFontSize($inputTextFontSize, $scaleSM); + //@include scaledPadding($inputPadding, $scaleSM); } } + +.p-inputtext-lg { + .p-inputtext { + //@include scaledFontSize($inputTextFontSize, $scaleLG); + //@include scaledPadding($inputPadding, $scaleLG); + } +} \ No newline at end of file diff --git a/assets/css/scss/index.scss b/assets/css/scss/index.scss index eaecd22a17..9d27e7dde5 100755 --- a/assets/css/scss/index.scss +++ b/assets/css/scss/index.scss @@ -13,11 +13,11 @@ @import "settings/typography"; +@import "atoms/form"; @import "atoms/avatar"; @import "atoms/buttons"; @import "atoms/checkbox"; @import "atoms/dropdown"; -@import "atoms/form"; @import "atoms/fieldset"; @import "atoms/inline_message"; @import "atoms/input_switch"; From b6763d748fc7c4f4148ec278d0af45918b311ec9 Mon Sep 17 00:00:00 2001 From: Angel Fernando Quiroz Campos Date: Thu, 30 Mar 2023 08:49:30 -0500 Subject: [PATCH 5/6] Minor: set type to inputtext in Page form --- assets/vue/components/page/Form.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/assets/vue/components/page/Form.vue b/assets/vue/components/page/Form.vue index b759b92511..ae744ff493 100644 --- a/assets/vue/components/page/Form.vue +++ b/assets/vue/components/page/Form.vue @@ -6,6 +6,7 @@ id="item_title" v-model="v$.item.title.$model" :class="{ 'p-invalid': v$.item.title.$invalid }" + type="text" />
-
-
+
+
-
+
-
+