58 Commits

Author SHA1 Message Date
nguyen van thai b4aa3e45d1 thainv-dev: Fix emagazine 2024-07-18 17:11:42 +07:00
nguyen van thai a63155a782 thainv-dev: Fix 2024-07-17 14:27:21 +07:00
nguyen van thai 45f21ba187 Fix Footer 2024-07-17 11:00:01 +07:00
nguyen van thai 795cd47e41 thainv-dev: Fix 2024-07-17 10:35:35 +07:00
nguyen van thai 5f9525371d Poll 2024-07-16 22:54:15 +07:00
nguyen van thai 6f571d9549 fix 2024-07-16 13:06:34 +07:00
nguyen van thai 174a596db9 Fix 2024-07-16 11:37:38 +07:00
Duong Truong Phong 5f72a107ce phongdt:add id component 2024-07-16 11:19:46 +07:00
nguyen van thai 5a041acd54 Fix 2024-07-16 09:58:54 +07:00
nguyen van thai 9cc998e0bf Fix 2024-07-16 09:23:44 +07:00
MoreStrive 7565a37d60 feat: create by site 2024-07-15 21:02:22 +07:00
MoreStrive 043f97743c Merge branch 'main' of http://work.gct.com.vn/minhnt/NSG_PORTAL_V2 2024-07-12 19:14:35 +07:00
MoreStrive dffbe39fa6 minhnt-dev: fix page template 2024-07-12 19:13:34 +07:00
nguyen van thai 7151e7d311 . 2024-07-11 08:38:56 +07:00
nguyen van thai 7da82c9101 . 2024-07-10 17:39:38 +07:00
nguyen van thai 212e6d357c . 2024-07-09 16:17:48 +07:00
nguyen van thai 7cb6199610 fix 2024-07-09 15:27:08 +07:00
nguyen van thai 0dba7790b1 Fix 2024-07-09 15:15:22 +07:00
nguyen van thai 776a3cf2c7 fix 2024-07-09 09:41:47 +07:00
nguyen van thai 2e49529934 Fix Responsive 2024-07-09 09:23:17 +07:00
nguyen van thai 28ce3d42a0 Fix Responsive 2024-07-09 08:33:33 +07:00
nguyen van thai 08ad924483 Responsive 2024-07-08 17:38:54 +07:00
MoreStrive 76b2fa4771 minhnt-dev: scroll smooth 2024-07-08 17:03:33 +07:00
MoreStrive 81bfa351e8 Merge branch 'main' of http://work.gct.com.vn/minhnt/NSG_PORTAL_V2 2024-07-06 18:29:42 +07:00
MoreStrive a3e20c9445 feat: select tag 2024-07-06 18:29:38 +07:00
nguyen van thai 6806201085 thainv-dev: Fix 2024-07-06 18:19:38 +07:00
MoreStrive 4ec2e425df Merge branch 'main' of http://work.gct.com.vn/minhnt/NSG_PORTAL_V2 2024-07-06 16:34:43 +07:00
MoreStrive 31175ade27 minhnt-dev: fix lodash 2024-07-06 16:34:25 +07:00
nguyen van thai ccd92c86ee thainv-dev: Nhúng 2024-07-06 16:28:45 +07:00
phongdt a47229f44e Merge pull request 'phongdt:fix paging' (#9) from phongdt into main
Reviewed-on: http://work.gct.com.vn/minhnt/NSG_PORTAL_V2/pulls/9
2024-07-05 15:32:49 +07:00
Duong Truong Phong 0ad19bbcfd phongdt:fix paging 2024-07-05 15:30:58 +07:00
phongdt 11ea05de83 Merge pull request 'phongdt' (#8) from phongdt into main
Reviewed-on: http://work.gct.com.vn/minhnt/NSG_PORTAL_V2/pulls/8
2024-07-05 15:13:26 +07:00
Duong Truong Phong e738cca263 Merge branch 'phongdt' of http://work.gct.com.vn/minhnt/NSG_PORTAL_V2 into phongdt 2024-07-05 15:13:00 +07:00
Duong Truong Phong b93f0218a5 phongdt:paging 2024-07-05 15:12:49 +07:00
Duong Truong Phong 3fe4da0ecb phongdt: paging component 2024-07-05 15:12:49 +07:00
Duong Truong Phong a9d6bea337 phongdt:paging 2024-07-05 15:12:16 +07:00
nguyen van thai df31b7bdef . 2024-07-05 15:03:50 +07:00
MoreStrive a1c6e2872f feat: full size 2024-07-05 15:01:01 +07:00
Duong Truong Phong 46b808cf9c phongdt: paging component 2024-07-05 14:51:25 +07:00
MoreStrive 367374863e Merge branch 'main' of http://work.gct.com.vn/minhnt/NSG_PORTAL_V2 2024-07-05 14:29:53 +07:00
MoreStrive 66b5a8ce6a feat: widget 2024-07-05 14:29:49 +07:00
nguyen van thai adecec9041 Layout Page Component 2024-07-05 14:17:41 +07:00
MoreStrive 984ec50a39 Merge branch 'main' of http://work.gct.com.vn/minhnt/NSG_PORTAL_V2 2024-07-05 13:05:28 +07:00
MoreStrive a756c91bd0 feat: widget 2024-07-05 13:05:21 +07:00
nguyen van thai cf64f11e72 thainv-dev 2024-07-05 11:57:41 +07:00
nguyen van thai 780474bcb3 Merge branch 'main' of http://work.gct.com.vn/minhnt/NSG_PORTAL_V2 2024-07-05 11:41:49 +07:00
nguyen van thai be1393b7da thainv-dev: Layout Page Section 2024-07-05 11:41:38 +07:00
MoreStrive a5f9ff7bac fix: null component 2024-07-05 11:02:04 +07:00
nguyen van thai 5889e9af0e thainv-dev 2024-07-05 10:39:07 +07:00
MoreStrive 17036b77af feat: layout none bugs 2024-07-05 10:29:08 +07:00
MoreStrive ac218aeac5 fea: navigation 2024-07-05 10:03:28 +07:00
MoreStrive 815ce88d95 Merge branch 'main' of http://work.gct.com.vn/minhnt/NSG_PORTAL_V2 2024-07-05 09:48:47 +07:00
MoreStrive 76d4628100 feat: fix type 2024-07-05 09:48:34 +07:00
nguyen van thai 7bf902041e thainv-dev 2024-07-05 09:45:00 +07:00
nguyen van thai 554ceab3c6 thainv-dev: Fix 2024-07-03 15:33:51 +07:00
MoreStrive ee5c6f40f1 deploy 2024-07-02 16:03:24 +07:00
MoreStrive 4bf217c207 Merge branch 'main' of http://work.gct.com.vn/minhnt/NSG_PORTAL_V2 2024-07-01 16:06:28 +07:00
MoreStrive 0adb6fca36 minhnt-dev: Video Card 2024-07-01 16:05:16 +07:00
129 changed files with 4188 additions and 1813 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

+141 -91
View File
@@ -20,101 +20,106 @@ $color-line: #EDEDED;
body { body {
font-size: 14px; font-size: 14px;
font-family: $font-raleway; font-family: $font-raleway;
scroll-behavior: smooth;
} }
%headings { // %headings {
color: $color-text; // color: $color-text;
font-family: $font-gelasio; // font-family: $font-gelasio;
line-height: 130%; // line-height: 130%;
font-weight: 700; // font-weight: 700;
} // }
%label { // %label {
color: $color-text; // color: $color-text;
font-family: $font-raleway; // font-family: $font-raleway;
line-height: 130%; // line-height: 130%;
font-weight: 700; // font-weight: 700;
} // }
%paragraph { // %paragraph {
color: $color-paragraph; // color: $color-paragraph;
font-family: $font-raleway; // font-family: $font-raleway;
line-height: 180%; // line-height: 180%;
font-weight: 500; // font-weight: 500;
} // }
h1, h2, h3, h4, h5, h6 { // h1, h2, h3, h4, h5, h6 {
font-family: $font-gelasio; // font-family: $font-gelasio;
} // }
h1 a { // h1 a {
@extend %headings; // @extend %headings;
font-size: 64px; // font-size: 64px;
} // }
h2 a{ // h2 a{
@extend %headings; // @extend %headings;
font-size: 44px; // font-size: 44px;
} // }
h3 a{ // h3 a{
@extend %headings; // @extend %headings;
font-size: 24px; // font-size: 24px;
} // }
h4 a{ // h4 a{
@extend %headings; // @extend %headings;
font-size: 20px; // font-size: 20px;
} // }
h5 a{ // h5 a{
@extend %headings; // @extend %headings;
font-size: 18px; // font-size: 18px;
} // }
h6 a{ // h6 a{
@extend %headings; // @extend %headings;
font-size: 16px; // font-size: 16px;
} // }
h6.h6-plus a { // h6.h6-plus a {
@extend %headings; // @extend %headings;
font-size: 14px; // font-size: 14px;
font-weight: 500; // font-weight: 500;
} // }
label { // label {
&.label-l1 { // &.label-l1 {
@extend %label; // @extend %label;
font-size: 18px; // font-size: 18px;
} // }
&.label-l2 { // &.label-l2 {
@extend %label; // @extend %label;
font-size: 16px; // font-size: 16px;
} // }
&.label-l3 { // &.label-l3 {
@extend %label; // @extend %label;
font-size: 14px; // font-size: 14px;
} // }
} // }
p { // p {
&.paragraph-p1 { // &.paragraph-p1 {
font-size: 18px; // font-size: 18px;
} // }
&.paragraph-p2 { // &.paragraph-p2 {
font-size: 16px; // font-size: 16px;
} // }
&.paragraph-p2 { // &.paragraph-p2 {
font-size: 14px; // font-size: 14px;
} // }
// }
a {
@apply hover:text-primary font-gelasio font-700 leading-130%;
} }
figure { figure {
@@ -125,27 +130,27 @@ img {
object-fit: cover!important; object-fit: cover!important;
} }
.content { // .content {
& p { // & p {
@apply mb-2 font-arial leading-160%; // @apply mb-2 font-arial leading-160%;
} // }
& #title { // & #title {
@apply font-merriweather font-bold leading-150%; // @apply font-merriweather font-bold leading-150%;
} // }
& #intro, & #sub { // & #intro, & #sub {
@apply font-arial font-medium leading-160%; // @apply font-arial font-medium leading-160%;
} // }
& audio { // & audio {
@apply w-full; // @apply w-full;
} // }
& document, & a, & custom-figure, & author { // & document, & a, & custom-figure, & author {
@apply cursor-pointer text-primary-600; // @apply cursor-pointer text-primary;
} // }
} // }
div[layout="TYPE:Detail-LAYOUT:image"] { div[layout="TYPE:Detail-LAYOUT:image"] {
& p,& figure.align-center-image, & #sub, & #title, & #intro, & #breadcrumb, & #navigation__bottom { & p,& figure.align-center-image, & #sub, & #title, & #intro, & #breadcrumb, & #navigation__bottom {
@@ -167,4 +172,49 @@ div[layout="ARTICLE_PAGE"] {
.container { .container {
max-width: 1385px; max-width: 1385px;
}
.layout_container {
& > .section_layout {
@apply mt-12 first:mt-0;
}
}
@media (max-width: 640px) {
.collection-container {
grid-template-columns: repeat(1, minmax(0, 1fr)) !important;
& > article.basic-article {
flex-direction: row!important;
& > .basic-article_thumbnail {
width: 50%!important;
}
}
}
}
.emagazine, .infographic, .image {
p {
@apply w-full max-w-660px mx-auto text-18px font-raleway leading-180%;
}
figure {
@apply w-full;
}
img {
@apply mx-auto;
}
}
.emagazine {
h1,h2,h3,h4,h5,h6,span,em {
@apply w-full max-w-660px mx-auto;
}
}
.detail-default {
p {
@apply text-18px font-raleway leading-180% my-10px;
}
} }
+1 -1
View File
@@ -6,7 +6,7 @@ const props = defineProps<{ events: any[] }>()
<div v-if="events?.length" class="mt-6"> <div v-if="events?.length" class="mt-6">
<h3 class="text-xl font-semibold after:content-[':']">Sự kiện</h3> <h3 class="text-xl font-semibold after:content-[':']">Sự kiện</h3>
<ul class="flex flex-col gap-2 list-disc ml-4 my-2 pl-3 flex-wrap"> <ul class="flex flex-col gap-2 list-disc ml-4 my-2 pl-3 flex-wrap">
<li v-for="(event, index) in events" :key="index" class="font-semibold text-primary-100"> <li v-for="(event, index) in events" :key="index" class="font-semibold text-primary">
<nuxt-link :to="{ name: 'event-eventSlug', params: { eventSlug: event.code } }">{{ event.title }}</nuxt-link> <nuxt-link :to="{ name: 'event-eventSlug', params: { eventSlug: event.code } }">{{ event.title }}</nuxt-link>
</li> </li>
</ul> </ul>
+74 -24
View File
@@ -15,13 +15,14 @@ const store = reactive({
}); });
const { currentPoll } = storeToRefs(store.poll); const { currentPoll } = storeToRefs(store.poll);
const { currentPollOptions } = storeToRefs(store.pollOptions); const { currentPollOptions } = storeToRefs(store.pollOptions);
const { currentPollResponses } = storeToRefs(store.pollResponse); // const { currentPollResponses } = storeToRefs(store.pollResponse);
const poll = reactive<Poll | any>({}); const poll = reactive<Poll | any>({});
const options = ref<PollOption[] | any[]>([]); const options = ref<PollOption[] | any[]>([]);
async function loadData() { async function loadData() {
await store.poll.fetchById(String(props.dataId)); await store.poll.fetchById(String(props.dataId));
await store.pollOptions.fetchByPollId(String(props.dataId)); await store.pollOptions.fetchByPollId(String(props.dataId));
await store.pollResponse.fetchByPollId(String(props.dataId)); // await store.pollResponse.fetchByPollId(String(props.dataId));
assignData(); assignData();
} }
@@ -30,13 +31,14 @@ function assignData() {
options.value = currentPollOptions.value; options.value = currentPollOptions.value;
} }
onBeforeMount(async () => { await loadData();
await loadData(); // onBeforeMount(async () => {
}); // });
const selectedOption = ref<any>(-1); // const selectedOption = ref<any>(-1);
const showResult = ref(false); // const showResult = ref(false);
const alreadyVoted = ref(false); const alreadyVoted = ref(false);
const showResult = ref(false)
const canShowResult = computed(() => { const canShowResult = computed(() => {
switch (poll.settings?.resultPublication) { switch (poll.settings?.resultPublication) {
case 0: case 0:
@@ -49,29 +51,77 @@ const canShowResult = computed(() => {
return alreadyVoted.value && (!poll.endTime || new Date() > new Date(poll.endTime)); return alreadyVoted.value && (!poll.endTime || new Date() > new Date(poll.endTime));
} }
}); });
// const toggleResults = () => {
// if (canShowResult.value) showResult.value = !showResult.value;
// };
const singleSelect = ref<number>(-1)
const multipleSelect = ref<number []>([])
const totalResponses = ref(0); const totalResponses = ref(0);
async function submitVote() { async function submitVote() {
if (selectedOption.value >= 0 && !alreadyVoted.value) { // if (selectedOption.value >= 0 && !alreadyVoted.value) {
const result = await store.pollResponse.create({ optionId: selectedOption.value }); // const result = await store.pollResponse.create({ optionId: selectedOption.value });
if (result?.id) { // if (result?.id) {
totalResponses.value = options.value?.reduce((sum, option) => sum + Number(option.responseCount ?? 0), 1); // totalResponses.value = options.value?.reduce((sum, option) => sum + Number(option.responseCount ?? 0), 1);
options?.value?.forEach((option: PollOption | any) => { // options?.value?.forEach((option: PollOption | any) => {
if (option.id === selectedOption.value) { // if (option.id === selectedOption.value) {
option.responseCount = (option.responseCount ?? 0) + 1; // option.responseCount = (option.responseCount ?? 0) + 1;
// }
// option.percentage = Number(((option.responseCount / totalResponses.value) * 100).toFixed(1));
// });
// alreadyVoted.value = true;
// }
// }
switch (poll.type) {
case 1:
if(singleSelect.value >= 0) {
const result = await store.pollResponse.create({ optionId: singleSelect.value })
if(result?.id) {
totalResponses.value = options.value?.reduce((sum, option) => sum + Number(option.responseCount ?? 0), 1);
options?.value?.forEach((option: PollOption | any) => {
if (option.id === singleSelect.value) {
option.responseCount = (option.responseCount ?? 0) + 1;
}
option.percentage = Number(((option.responseCount / totalResponses.value) * 100).toFixed(1));
alreadyVoted.value = true
});
} }
option.percentage = Number(((option.responseCount / totalResponses.value) * 100).toFixed(1)); }
});
alreadyVoted.value = true;
}
} }
} }
const toggleResults = () => {
if (canShowResult.value) showResult.value = !showResult.value;
};
</script> </script>
<template> <template>
<span class="inline-block px-4 py-2 shadow-xl rounded-lg bg-[#f5f5f5]">
<div class="inline-block px-4 py-2 mb-5">
<h3 class="text-#000 font-raleway font-italic text-16px font-500 leading-140% mb-2">{{ poll?.title }}</h3>
<ul class="flex flex-col gap-3">
<template v-if="poll.type === 1">
<li v-for="(option, index) in options" :key="index">
<input :id="`option-${index}`" :disabled="singleSelect >= 0 && alreadyVoted ? true : false" type="radio" class="peer opacity-0" :value="option.id" v-model="singleSelect">
<label :for="`option-${index}`" class="font-raleway text-16px relative text-#000 font-400 leading-140% pl-16px before:content-[''] before:inline-block before:w-14px before:h-14px before:rounded-50% before:border-1 before:absolute before:left--3 before:top-10px before:border-1px before:border-#000 before:translate-y--50% after:absolute after:left--10px after:top-10px after:translate-y--50% after:border-#000 after:content-[''] after:inline-block after:w-10px after:h-10px after:rounded-full peer-checked:after:bg-primary peer-checked:before:border-primary ">{{ option?.title }}</label>
</li>
</template>
</ul>
<div class="flex items-center justify-center mt-3">
<button @click="submitVote()" v-if="!alreadyVoted" :disabled="alreadyVoted && singleSelect >= 0 ? true : false" class="px-5 py-10px rounded-6px bg-primary text-#fff font-raleway text-14px font-400">Gửi kết quả</button>
<button @click="showResult = true" v-if="alreadyVoted" class="px-5 py-10px rounded-6px bg-primary text-#fff font-raleway text-14px font-400">Xem kết quả</button>
</div>
<div class="mt-5" v-if="showResult && canShowResult">
<h3 class="text-#000 font-raleway font-italic text-16px font-500 leading-140% mb-2">{{ poll?.title }}</h3>
<ul>
<li v-for="(answer, index) in options" :key="index" class="flex gap-4 items-center text-#000 font-raleway text-12px leading-140%">
{{ answer.percentage}}%
<div :style="{ width: `${answer.percentage}%` }" :class="answer.id === singleSelect ? 'bg-primary' : 'bg-#AEAEAE'" class="h-1.5 rounded-full"></div>
</li>
</ul>
</div>
</div>
<!-- <span class="inline-block px-4 py-2 shadow-xl rounded-lg bg-[#f5f5f5]">
<span class="block"> <span class="block">
<span class="underline decoration-gray-500 font-bold"> <span class="underline decoration-gray-500 font-bold">
{{ poll?.title }} {{ poll?.title }}
@@ -100,5 +150,5 @@ const toggleResults = () => {
</span> </span>
<b>Tổng số lượt binh chọn: {{ totalResponses }}</b> <b>Tổng số lượt binh chọn: {{ totalResponses }}</b>
</span> </span>
</span> </span> -->
</template> </template>
+17 -7
View File
@@ -246,23 +246,33 @@ async function submitSend() {}
</script> </script>
<template> <template>
<div class="inline-block px-4 py-2 shadow-xl rounded-lg bg-[#f5f5f5] !text-black-500"> <div class="inline-block px-4 py-2 !text-black-500">
<h5 class="underline decoration-gray-500 font-bold mb-2">Câu đố: {{ data?.title }}</h5> <h5 class="underline decoration-gray-500 font-bold mb-2">Câu đố: {{ data?.title }}</h5>
<ul class="px-3"> <ul class="px-3 flex flex-col gap-3">
<li v-for="(question, questionIndex) in data.questionGeneral" :key="questionIndex" class="mb-2"> <li v-for="(question, questionIndex) in data.questionGeneral" :key="questionIndex" class="mb-2">
<h5 class="mb-1 font-700 text-black-500">{{ `${questionIndex + 1}. ${question.title}` }}</h5> <h5 class="text-#000 font-raleway font-italic text-16px font-500 leading-140% mb-2">{{ `${questionIndex + 1}. ${question.title}` }}</h5>
<ul> <ul>
<template v-if="question.type === 1">
<li v-for="(answer, answerIndex) in question.answers" :key="answerIndex" class="flex items-center gap-1 py-1"> <li v-for="(answer, answerIndex) in question.answers" :key="answerIndex" class="flex items-center gap-1 py-1">
<input :id="`answer-${questionIndex}-${answerIndex}`" :type="question.type === 1 ? 'radio' : 'checkbox'" :value="answerIndex" v-model="selectQuizAnswer[questionIndex]" /> <input :id="`answer-${questionIndex}-${answerIndex}`" type="radio" :value="answerIndex" class="peer opacity-0" v-model="selectQuizAnswer[questionIndex]" />
<label :for="`answer-${questionIndex}-${answerIndex}`" class="font-semibold">{{ answer.title }}</label> <label :for="`answer-${questionIndex}-${answerIndex}`" class="font-raleway text-16px relative text-#000 font-400 leading-140% pl-16px before:content-[''] before:inline-block before:w-14px before:h-14px before:rounded-50% before:border-1 before:absolute before:left--3 before:top-10px before:border-1px before:border-#000 before:translate-y--50% after:absolute after:left--10px after:top-10px after:translate-y--50% after:border-#000 after:content-[''] after:inline-block after:w-10px after:h-10px after:rounded-full peer-checked:after:bg-primary peer-checked:before:border-primary ">{{ answer.title }}</label>
</li> </li>
</template>
<template v-else>
<li v-for="(answer, answerIndex) in question.answers" :key="answerIndex" class="flex items-center gap-1 py-1">
<input :id="`answer-${questionIndex}-${answerIndex}`" type="checkbox" :value="answerIndex" class="peer opacity-0" v-model="selectQuizAnswer[questionIndex]" />
<label :for="`answer-${questionIndex}-${answerIndex}`" class="font-raleway text-16px relative text-#000 font-400 leading-140% pl-16px before:content-[''] before:inline-block before:w-14px before:h-14px before:rounded-2px before:border-1 before:absolute before:left--3 before:top-10px before:border-1px before:border-#000 before:translate-y--50% after:absolute after:left--10px after:top-6px after:translate-y--50% after:border-#000 after:content-['✔'] after:text-12px after:text-transparent after:inline-block after:w-14px after:h-14px peer-checked:after:text-white peer-checked:before:border-primary peer-checked:before:bg-primary ">{{ answer.title }}</label>
</li>
</template>
</ul> </ul>
</li> </li>
</ul> </ul>
<button @click="submitSend" class="bg-primary-500 text-white py-1 px-3 rounded-4px cursor-pointer hover:bg-primary-600 float-right">Gửi câu trả lời</button> <div class="flex justify-center">
<button @click="submitSend" class="mx-auto px-5 py-10px rounded-6px bg-primary text-#fff font-raleway text-14px font-400">Gửi câu trả lời</button>
</div>
</div> </div>
<!-- <div> <!-- <div>
<h5 class="text-black text-18px font-700">{{ data?.title }}</h5> <h5 class="text-black text-18px font-700">{{ data?.title }}</h5>
@@ -274,7 +284,7 @@ async function submitSend() {}
<li <li
v-for="(index, item) in data.questionGeneral.length" v-for="(index, item) in data.questionGeneral.length"
:key="index" :key="index"
:class="step >= index - 1 ? 'bg-primary-500 text-white transition-all delay-300' : 'bg-white text-primary-500'" :class="step >= index - 1 ? 'bg-primary-500 text-white transition-all delay-300' : 'bg-white text-primary'"
class="relative z-3 w-7 h-7 rounded-full flex items-center justify-center border-2 border-solid border-primary-500" class="relative z-3 w-7 h-7 rounded-full flex items-center justify-center border-2 border-solid border-primary-500"
> >
<template template v-if="step > index - 1"><Icon name="material-symbols:check-rounded" class="text-22px" /></template> <template template v-if="step > index - 1"><Icon name="material-symbols:check-rounded" class="text-22px" /></template>
+23 -6
View File
@@ -270,24 +270,41 @@ async function submitSend() {
<template> <template>
<div class="inline-block px-4 py-2 shadow-xl rounded-lg bg-[#f5f5f5] !text-black-500"> <div class="inline-block px-4 py-2 !text-black-500">
<h5 class="underline decoration-gray-500 font-bold mb-2">Khảo sát: {{ dataSurvey?.title }}</h5> <h5 class="underline decoration-gray-500 font-bold mb-2">Khảo sát: {{ dataSurvey?.title }}</h5>
<ul class="px-3"> <ul class="px-3">
<li v-for="(question, questionIndex) in dataSurvey.questionGeneral" :key="questionIndex" class="mb-2"> <li v-for="(question, questionIndex) in dataSurvey.questionGeneral" :key="questionIndex" class="mb-2">
<h5 class="mb-1 font-700 text-black-500">{{ `${questionIndex + 1}. ${question.title}` }}</h5> <h5 class="text-#000 font-raleway font-italic text-16px font-500 leading-140% mb-2">{{ `${questionIndex + 1}. ${question.title}` }}</h5>
<ul> <!-- <ul>
<li v-for="(answer, answerIndex) in question.answers" :key="answerIndex" class="flex items-center gap-1 py-1"> <li v-for="(answer, answerIndex) in question.answers" :key="answerIndex" class="flex items-center gap-1 py-1">
<input :id="`answer-survey-${questionIndex}-${answerIndex}`" :type="question.type === 1 ? 'radio' : 'checkbox'" :value="answerIndex" v-model="selectSurveyAnswer[questionIndex]"> <input :id="`answer-survey-${questionIndex}-${answerIndex}`" :type="question.type === 1 ? 'radio' : 'checkbox'" :value="answerIndex" v-model="selectSurveyAnswer[questionIndex]">
<label :for="`answer-survey-${questionIndex}-${answerIndex}`" class="font-semibold">{{ answer.title }}</label> <label :for="`answer-survey-${questionIndex}-${answerIndex}`" class="font-semibold">{{ answer.title }}</label>
</li> </li>
</ul> </ul> -->
<ul>
<template v-if="question.type === 1">
<li v-for="(answer, answerIndex) in question.answers" :key="answerIndex" class="flex items-center gap-1 py-1">
<input :id="`answer-survey-${questionIndex}-${answerIndex}`" type="radio" :value="answerIndex" class="peer opacity-0" v-model="selectSurveyAnswer[questionIndex]" />
<label :for="`answer-survey-${questionIndex}-${answerIndex}`" class="font-raleway text-16px relative text-#000 font-400 leading-140% pl-16px before:content-[''] before:inline-block before:w-14px before:h-14px before:rounded-50% before:border-1 before:absolute before:left--3 before:top-10px before:border-1px before:border-#000 before:translate-y--50% after:absolute after:left--10px after:top-10px after:translate-y--50% after:border-#000 after:content-[''] after:inline-block after:w-10px after:h-10px after:rounded-full peer-checked:after:bg-primary peer-checked:before:border-primary ">{{ answer.title }}</label>
</li>
</template>
<template v-else>
<li v-for="(answer, answerIndex) in question.answers" :key="answerIndex" class="flex items-center gap-1 py-1">
<input :id="`answer-survey-${questionIndex}-${answerIndex}`" type="checkbox" :value="answerIndex" class="peer opacity-0" v-model="selectSurveyAnswer[questionIndex]" />
<label :for="`answer-survey-${questionIndex}-${answerIndex}`" class="font-raleway text-16px relative text-#000 font-400 leading-140% pl-16px before:content-[''] before:inline-block before:w-14px before:h-14px before:rounded-2px before:border-1 before:absolute before:left--3 before:top-10px before:border-1px before:border-#000 before:translate-y--50% after:absolute after:left--10px after:top-6px after:translate-y--50% after:border-#000 after:content-['✔'] after:text-12px after:text-transparent after:inline-block after:w-14px after:h-14px peer-checked:after:text-white peer-checked:before:border-primary peer-checked:before:bg-primary ">{{ answer.title }}</label>
</li>
</template>
</ul>
</li> </li>
</ul> </ul>
<button @click="submitSend" class="bg-primary-500 text-white py-1 px-3 rounded-4px cursor-pointer hover:bg-primary-600 float-right">Gửi câu trả lời</button> <div class="flex justify-center">
<button @click="submitSend" class="mx-auto px-5 py-10px rounded-6px bg-primary text-#fff font-raleway text-14px font-400">Gửi câu trả lời</button>
</div>
<!-- <button @click="submitSend" class="bg-primary-500 text-white py-1 px-3 rounded-4px cursor-pointer hover:bg-primary-600 float-right">Gửi câu trả lời</button> -->
</div> </div>
</template> </template>
@@ -4,9 +4,10 @@ import DynamicComponent from "~/components/dynamic-page/page-component/templates
import { useDynamicPageStore } from '~/stores/dynamic-page'; import { useDynamicPageStore } from '~/stores/dynamic-page';
const { currentPage } = storeToRefs(useDynamicPageStore()); const { currentPage } = storeToRefs(useDynamicPageStore());
const props = defineProps<{ const props = defineProps<{
type?: string; // [TOP_NAVIGATION, BOTTOM_NAVIGATION] type?: any; // [TOP_NAVIGATION, BOTTOM_NAVIGATION]
}>(); }>();
const contentParse = computed(() => (currentPage.value.content ? JSON.parse(currentPage.value.content) : {}));
const defineTypeRecusive = { const defineTypeRecusive = {
TOP_NAVIGATION: enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.NAVIGATION]['TOP']}`]['NAVIGATION_TOP_DEFAULT'], TOP_NAVIGATION: enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.NAVIGATION]['TOP']}`]['NAVIGATION_TOP_DEFAULT'],
BOTTOM_NAVIGATION: enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.NAVIGATION]['BOTTOM']}`]['NAVIGATION_BOTTOM_DEFAULT'], BOTTOM_NAVIGATION: enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.NAVIGATION]['BOTTOM']}`]['NAVIGATION_BOTTOM_DEFAULT'],
@@ -16,14 +17,22 @@ const findDataPosition = computed<any>(() => {
let result = {}; let result = {};
switch (props.type) { switch (props.type) {
case defineTypeRecusive.TOP_NAVIGATION: case defineTypeRecusive.TOP_NAVIGATION:
result = currentPage.value.components && currentPage.value.components.find((component: any) => { if (contentParse.value.navigationTop) {
return component.taxonomy === enumPageComponentKey.NAVIGATION && component.settings?.layout === defineTypeRecusive.TOP_NAVIGATION result =
}); currentPage.value.components &&
currentPage.value.components.find((component: any) => {
return component.id === contentParse.value.navigationTop;
});
}
break; break;
case defineTypeRecusive.BOTTOM_NAVIGATION: case defineTypeRecusive.BOTTOM_NAVIGATION:
result = currentPage.value.components && currentPage.value.components.find((component: any) => { if (contentParse.value.navigationBottom) {
return component.taxonomy === enumPageComponentKey.NAVIGATION && component.settings?.layout === defineTypeRecusive.BOTTOM_NAVIGATION result =
}); currentPage.value.components &&
currentPage.value.components.find((component: any) => {
return component.id === contentParse.value.navigationBottom;
});
}
break; break;
default: default:
result = {}; result = {};
@@ -1,15 +1,13 @@
<script setup lang="ts"></script> <script setup lang="ts"></script>
<template> <template>
<div class="pt-5"> <div class="pt-5">
<div class="content p-3"> <div class="content p-3 border-y-1px border-solid border-#000">
<span class="text-12px text-[#AFADB5] text-end block">Quảng full</span> <img class="mx-auto max-h-[300px] object-cover" src="/assets/images/tienphong/ads_full.png" alt="">
<img class="block w-full h-full" src="/assets/images/tienphong/main-ads-2.jpg" alt="">
</div> </div>
</div> </div>
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
.content { .content {
font-size: 18px; font-size: 18px;
background-color: #eeeeee;
} }
</style> </style>
@@ -13,7 +13,6 @@ const definedDynamicComponent: Record<string, any> = {
}; };
const getCurrentComponent = computed(() => _props.settings.layout); const getCurrentComponent = computed(() => _props.settings.layout);
const GET_PROPS = computed(() => { const GET_PROPS = computed(() => {
return () => { return () => {
let props: any = {}; let props: any = {};
@@ -32,6 +31,7 @@ const GET_PROPS = computed(() => {
<template> <template>
<component <component
v-if="definedDynamicComponent[getCurrentComponent]"
:is="definedDynamicComponent[getCurrentComponent]" :is="definedDynamicComponent[getCurrentComponent]"
v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings, content: _props.content }" v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings, content: _props.content }"
/> />
@@ -11,7 +11,7 @@ const definedDynamicComponent: Record<string, any> = {
[enumPageComponentTemplate[enumPageComponentKey.ADVERTISING]["ADVERTISING"]]: Advertisings, [enumPageComponentTemplate[enumPageComponentKey.ADVERTISING]["ADVERTISING"]]: Advertisings,
}; };
const getCurrentComponent = computed(() => `${_props.settings.layout}`); const getCurrentComponent = computed(() => `${_props.settings.template}`);
const GET_PROPS = computed(() => { const GET_PROPS = computed(() => {
return () => { return () => {
let props: any = {}; let props: any = {};
@@ -26,8 +26,13 @@ const GET_PROPS = computed(() => {
} }
}; };
}); });
// console.log(getCurrentComponent.value, 'quảng caosd ád')
</script> </script>
<template> <template>
<component :is="definedDynamicComponent[getCurrentComponent]" v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings }" /> <component
v-if="definedDynamicComponent[getCurrentComponent]"
:is="definedDynamicComponent[getCurrentComponent]"
v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings }"
/>
</template> </template>
@@ -1,15 +1,15 @@
<script setup lang="ts"> <script setup lang="ts">
const type = ref(""); const type = ref("");
import { enumPageComponentTemplates } from "@/definitions/enum"; import { enumPageComponentTemplates } from "@/definitions/enum";
import { DEFAULT_QUERY_DROP } from "@/utils/parseSQL"; import { DEFAULT_QUERY_DROP, getInputValue } from "@/utils/parseSQL";
import { getInputValue } from "@/utils/parseSQL";
const props = defineProps<{ const props = defineProps<{
dataResult?: any; dataResult?: any;
dataType?: any; dataType?: any;
dataQuery?: any; dataQuery?: any;
layout?: string; layout?: string;
label?: string; label?: any;
component?: any;
}>(); }>();
const LAYOUT_PARSE = computed(() => { const LAYOUT_PARSE = computed(() => {
@@ -50,12 +50,15 @@ const parseData = computed(() => {
return result; return result;
}); });
</script> </script>
<template> <template>
<article class="card-audio" :class="LAYOUT_PARSE['article_Class']" :style="LAYOUT_PARSE['article']"> <article :id="`cpn_${props.component.id}`" class="card-audio" :class="LAYOUT_PARSE['article_Class']" :style="LAYOUT_PARSE['article']">
<img :src="parseData?.thumbnail ? parseData?.thumbnail : 'https://indiaeducationdiary.in/wp-content/uploads/2021/02/SD-default-image.png'" :alt="parseData?.title?.replace(/<[^>]+>/g, '')" /> <nuxt-link :to="`/bai-viet/${parseData?.slug}`" class="article-thumbnail">
<img :src="parseData?.thumbnail ? parseData?.thumbnail : 'https://indiaeducationdiary.in/wp-content/uploads/2021/02/SD-default-image.png'" :alt="parseData?.title?.replace(/<[^>]+>/g, '')" />
</nuxt-link>
<div class="card-audio__content"> <div class="card-audio__content">
<span> <span class="flex justify-center">
<template v-if="type === 'Image'"> <template v-if="['Image', 'Infographics', 'Emagazine'].includes(type)">
<svg width="28" height="22" viewBox="0 0 28 22" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="28" height="22" viewBox="0 0 28 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path <path
d="M25.25 0.5H7.25C5.98438 0.5 5 1.53125 5 2.75V14.75C5 16.0156 5.98438 17 7.25 17H25.25C26.4688 17 27.5 16.0156 27.5 14.75V2.75C27.5 1.53125 26.4688 0.5 25.25 0.5ZM10.9531 3.5C11.75 3.5 12.4531 4.20312 12.4531 5C12.4531 5.84375 11.7969 6.5 10.9531 6.5C10.1094 6.5 9.45312 5.84375 9.45312 5C9.45312 4.20312 10.1562 3.5 10.9531 3.5ZM23.6562 13.625C23.5156 13.8594 23.2344 14 23 14H9.5C9.17188 14 8.9375 13.8594 8.79688 13.625C8.70312 13.3438 8.70312 13.0625 8.89062 12.8281L12.1719 8.32812C12.3125 8.14062 12.5 8 12.7812 8C13.0156 8 13.2031 8.14062 13.3438 8.32812L14.4219 9.78125L17.375 5.375C17.4688 5.14062 17.7031 5 17.9844 5C18.2188 5 18.4531 5.14062 18.5938 5.375L23.6094 12.875C23.75 13.0625 23.75 13.3906 23.6562 13.625ZM21.875 19.25H6.125C4.25 19.25 2.75 17.75 2.75 15.875V4.625C2.75 4.01562 2.23438 3.5 1.625 3.5C0.96875 3.5 0.5 4.01562 0.5 4.625V15.875C0.5 19.0156 2.98438 21.5 6.125 21.5H21.875C22.4844 21.5 23 21.0312 23 20.375C23 19.7656 22.4844 19.25 21.875 19.25Z" d="M25.25 0.5H7.25C5.98438 0.5 5 1.53125 5 2.75V14.75C5 16.0156 5.98438 17 7.25 17H25.25C26.4688 17 27.5 16.0156 27.5 14.75V2.75C27.5 1.53125 26.4688 0.5 25.25 0.5ZM10.9531 3.5C11.75 3.5 12.4531 4.20312 12.4531 5C12.4531 5.84375 11.7969 6.5 10.9531 6.5C10.1094 6.5 9.45312 5.84375 9.45312 5C9.45312 4.20312 10.1562 3.5 10.9531 3.5ZM23.6562 13.625C23.5156 13.8594 23.2344 14 23 14H9.5C9.17188 14 8.9375 13.8594 8.79688 13.625C8.70312 13.3438 8.70312 13.0625 8.89062 12.8281L12.1719 8.32812C12.3125 8.14062 12.5 8 12.7812 8C13.0156 8 13.2031 8.14062 13.3438 8.32812L14.4219 9.78125L17.375 5.375C17.4688 5.14062 17.7031 5 17.9844 5C18.2188 5 18.4531 5.14062 18.5938 5.375L23.6094 12.875C23.75 13.0625 23.75 13.3906 23.6562 13.625ZM21.875 19.25H6.125C4.25 19.25 2.75 17.75 2.75 15.875V4.625C2.75 4.01562 2.23438 3.5 1.625 3.5C0.96875 3.5 0.5 4.01562 0.5 4.625V15.875C0.5 19.0156 2.98438 21.5 6.125 21.5H21.875C22.4844 21.5 23 21.0312 23 20.375C23 19.7656 22.4844 19.25 21.875 19.25Z"
@@ -63,22 +66,26 @@ const parseData = computed(() => {
/> />
</svg> </svg>
</template> </template>
</span> <template v-if="['Postcard', 'Video'].includes(type)">
<svg width="28" height="18" viewBox="0 0 28 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18.5 2.25V15.75C18.5 17.0156 17.4688 18 16.25 18H2.75C1.48438 18 0.5 17.0156 0.5 15.75V2.25C0.5 1.03125 1.48438 0 2.75 0H16.25C17.4688 0 18.5 1.03125 18.5 2.25ZM27.5 3V15.0469C27.5 16.2188 26.0938 16.9219 25.1094 16.2656L20 12.7031V5.34375L25.1094 1.78125C26.0938 1.125 27.5 1.82812 27.5 3Z" fill="white"/>
</svg>
<div class="card-audio__type-category"> </template>
</span>
<div class="card-audio__type-category" >
<div class="card-audio__type" v-if="type">{{ type }}</div> <div class="card-audio__type" v-if="type">{{ type }}</div>
<nuxt-link v-if="parseData" class="card-audio__category" :style="LAYOUT_PARSE['category-article']" :class="LAYOUT_PARSE['category-article_Class']">{{ <nuxt-link v-if="parseData?.category" to="#" class="card-audio__category" :style="LAYOUT_PARSE['category-article']" :class="LAYOUT_PARSE['category-article_Class']">{{
parseData?.category?.title parseData?.category?.title
}}</nuxt-link> }}</nuxt-link>
<span v-else class="empty-block" style="height: 8px; width: 30px"></span>
</div> </div>
<nuxt-link>
<h2 v-html="parseData.title" v-if="parseData" :class="LAYOUT_PARSE['title_Class']" :style="LAYOUT_PARSE['h3.title']"></h2> <h2 :class="LAYOUT_PARSE['title_Class']" :style="LAYOUT_PARSE['h3.title']">
<span v-else class="empty-block" style="height: 8px"></span> <nuxt-link :to="`/bai-viet/${parseData?.code}`"><span v-html="parseData?.title"></span> </nuxt-link>
</nuxt-link> </h2>
</div> </div>
</article> </article>
<div v-html="LAYOUT_PARSE.styleClasses" style="display:none;"></div> <div v-if="LAYOUT_PARSE.styleClasses" v-html="LAYOUT_PARSE.styleClasses" style="display:none;"></div>
</template> </template>
<style lang="scss"> <style lang="scss">
@@ -88,12 +95,18 @@ const parseData = computed(() => {
padding-bottom: calc((16 / 9) * 100%); padding-bottom: calc((16 / 9) * 100%);
overflow: hidden; overflow: hidden;
img { .article-thumbnail {
position: absolute; position: absolute;
height: 100%; height: 100%;
width: 100%; width: 100%;
object-fit: cover;
z-index: 1; z-index: 1;
& img {
width: 100%;
height: 100%;
object-fit: cover;
}
} }
.card-audio__content { .card-audio__content {
@@ -9,7 +9,8 @@ const props = defineProps<{
dataType?: any; dataType?: any;
dataQuery?: any; dataQuery?: any;
layout?: string; layout?: string;
label?: string; label?: any;
component?: any;
}>(); }>();
const LAYOUT_PARSE = computed(() => { const LAYOUT_PARSE = computed(() => {
@@ -27,42 +28,48 @@ const parseData = computed(() => {
<template> <template>
<article <article
v-if="parseData" v-if="parseData"
:id="`cpn_${props.component.id}`"
class="basic-article border-custom" class="basic-article border-custom"
:class="LAYOUT_PARSE['article_Class']" :class="LAYOUT_PARSE['article_Class']"
:style="LAYOUT_PARSE['article']" :style="LAYOUT_PARSE['article']"
> >
<div class="basic-article_thumbnail" :class="LAYOUT_PARSE['thumbnail_Class']" :style="LAYOUT_PARSE['div.basic-article_thumbnail']"> <div class="basic-article_thumbnail article-thumbnail" :class="LAYOUT_PARSE['thumbnail_Class']" :style="LAYOUT_PARSE['div.basic-article_thumbnail']">
<template v-if="parseData"> <template v-if="parseData">
<img class="object-fit-cover" :src="parseData.thumbnail ? parseData.thumbnail : '/images/default-thumbnail.jpg'" :alt="parseData.title?.replace(/<[^>]+>/g, '')" /> <nuxt-link :to="`${parseData.code}`">
<img class="object-fit-cover" :src="parseData.thumbnail ? parseData.thumbnail : '/images/default-thumbnail.jpg'" :alt="parseData.title?.replace(/<[^>]+>/g, '')" />
</nuxt-link>
</template> </template>
<span v-else class="empty-block" style="width: 100%; height: 100%; min-height: 50px"></span> <span v-else class="empty-block" style="width: 100%; height: 100%; min-height: 50px"></span>
</div> </div>
<div class="basic-article_content" :class="[!parseData && 'no-data']"> <div class="basic-article_content" :class="[!parseData && 'no-data']">
<template v-if="parseData?.topics && parseData?.topics.length > 0"> <template v-if="parseData?.topics && parseData?.topics.length > 0">
<nuxt-link class="article-card-default__topic" :to="`/${parseData?.topics[0].code}`" :style="LAYOUT_PARSE['topic']"> <nuxt-link class="article-card-default__topic" :to="`/${parseData?.topics[0].code}`" :style="LAYOUT_PARSE['topic']">
<h5>{{ parseData?.topics[0].title }}</h5> <h5><nuxt-link :to="`/topic/${parseData?.topics[0].code}`">
{{ parseData?.topics[0].title }}</nuxt-link></h5>
</nuxt-link> </nuxt-link>
</template> </template>
<h3 class="line-clamp" :class="LAYOUT_PARSE['title_Class']" :style="LAYOUT_PARSE['h3.title']"> <h3 class="line-clamp" :class="LAYOUT_PARSE['title_Class']" :style="LAYOUT_PARSE['h3.title']">
<template v-if="parseData"> <template v-if="parseData">
{{ parseData.title?.replace(/<[^>]+>/g, "") }} <nuxt-link :to="`/bai-viet/${parseData.code}`">
{{ parseData.title?.replace(/<[^>]+>/g, "") }}
</nuxt-link>
</template> </template>
<span v-else class="empty-block" style="height: 8px"></span> <span v-else class="empty-block" style="height: 8px"></span>
</h3> </h3>
<div class="article-card-default__bottom" v-if="LAYOUT_PARSE.layout === 'row'"> <div class="article-card-default__bottom" v-if="LAYOUT_PARSE.layout === 'row'">
<span :style="LAYOUT_PARSE['time']" style="margin-right: 5px" :class="LAYOUT_PARSE['time_Class']">{{ <span :style="LAYOUT_PARSE['time']" style="margin-right: 5px" :class="[LAYOUT_PARSE['time_Class'], 'article-time']">{{
formatDate(String(parseData?.createdOn), "DD/MM/YYYY | HH:mm") formatDate(String(parseData?.createdOn), "DD/MM/YYYY | HH:mm")
}}</span> }}</span>
<nuxt-link :style="LAYOUT_PARSE['category-article']" :class="LAYOUT_PARSE['category-article_Class']">{{ parseData?.category?.title }}</nuxt-link> <nuxt-link :style="LAYOUT_PARSE['category-article']" :class="LAYOUT_PARSE['category-article_Class']">{{ parseData?.category?.title }}</nuxt-link>
</div> </div>
<p class="mb-0 line-clamp" :class="LAYOUT_PARSE['paragraph_Class']" :style="LAYOUT_PARSE['p.paragraph']"> <p class="mb-0 line-clamp-5 article-intro" :class="LAYOUT_PARSE['paragraph_Class']" :style="LAYOUT_PARSE['p.paragraph']">
<template v-if="parseData"> <template v-if="parseData">
{{ parseData.intro?.replace(/<[^>]+>/g, "") }} {{ parseData.intro?.replace(/<[^>]+>/g, "") }}
</template> </template>
<span v-else class="empty-block" style="height: 5px"></span> <span v-else class="empty-block" style="height: 5px"></span>
</p> </p>
<div class="article-card-default__bottom" v-if="LAYOUT_PARSE?.layout !== 'row'" :style="LAYOUT_PARSE['metadata']"> <div class="article-card-default__bottom" v-if="LAYOUT_PARSE?.layout !== 'row'" :style="LAYOUT_PARSE['metadata']">
<span :style="LAYOUT_PARSE['time']" style="margin-right: 5px" :class="LAYOUT_PARSE['time_Class']">{{ <span :style="LAYOUT_PARSE['time']" style="margin-right: 5px" :class="[LAYOUT_PARSE['time_Class'], 'article-time']">{{
formatDate(String(parseData?.createdOn), "DD/MM/YYYY | HH:mm") formatDate(String(parseData?.createdOn), "DD/MM/YYYY | HH:mm")
}}</span> }}</span>
<nuxt-link :style="LAYOUT_PARSE['category-article']" :class="LAYOUT_PARSE['category-article_Class']">{{ parseData?.category?.title }}</nuxt-link> <nuxt-link :style="LAYOUT_PARSE['category-article']" :class="LAYOUT_PARSE['category-article_Class']">{{ parseData?.category?.title }}</nuxt-link>
@@ -234,5 +241,16 @@ p {
height: 100px; height: 100px;
display: block; display: block;
} }
@media (max-width: 640px) {
padding-left: 0px!important;
padding-right: 0px!important;
border: 0px solid transparent!important;
flex-direction: column !important;
& .basic-article_thumbnail {
width: 100% !important;
}
}
} }
</style> </style>
@@ -0,0 +1,114 @@
<script lang="ts" setup>
import { enumPageComponentTemplates } from "@/definitions/enum";
import { DEFAULT_QUERY_DROP } from "@/utils/parseSQL";
import { getInputValue } from "@/utils/parseSQL";
import { formatDate } from "@/utils/filters";
const props = defineProps<{
dataResult?: any;
dataType?: any;
dataQuery?: any;
layout?: string;
label?: string;
component?: any;
}>();
const LAYOUT_PARSE = computed(() => {
const designObject = props.label ? getInputValue(props.label, "OBJECT") : {};
return Object.assign({}, designObject);
});
const emit = defineEmits(["selectComponent", "dropData"]);
const selectComponent = () => {
emit("selectComponent");
};
const parseData = computed(() => {
if (!props.dataResult) return;
const result = getInputValue(props.dataResult, "OBJECT");
return result;
});
const drop = (e: any) => {
if (e.dataTransfer.getData(`${enumPageComponentTemplates.ARTICLE}`)) {
const data = e.dataTransfer.getData(`${enumPageComponentTemplates.ARTICLE}`);
const { dataType, dataResult } = JSON.parse(data);
const dataQuery = DEFAULT_QUERY_DROP(dataType, dataResult.id);
emit("dropData", {
dataType,
dataResult,
dataQuery: dataQuery,
});
}
};
</script>
<template>
<article :id="`cpn_${props.component.id}`" class="basic-article border-custom" :class="LAYOUT_PARSE['article_Class']" :style="LAYOUT_PARSE['article']">
<div class="article_miss">
<template v-if="parseData">
<nuxt-link :to="`/bai-viet/${parseData.slug}`">
<div class="article_miss_thumb custom-thumb" :style="{ backgroundImage: `url('${parseData.thumbnail ? parseData.thumbnail : '/images/default-thumbnail.jpg'}')` }"></div>
</nuxt-link>
<div class="article_miss_content" :style="LAYOUT_PARSE['content']">
<nuxt-link :to="`/bai-viet/${parseData.slug}`">
<h3 class="line-clamp text-white" :class="LAYOUT_PARSE['title_Class']" :style="LAYOUT_PARSE['h3.title']">
{{ parseData.title?.replace(/<[^>]+>/g, "") }}
</h3>
</nuxt-link>
</div>
</template>
<div v-else class="empty-box"></div>
</div>
<div v-html="LAYOUT_PARSE.styleClasses" v-if="LAYOUT_PARSE.styles" style="display: none"></div>
</article>
</template>
<style lang="scss" scoped>
.article_miss {
height: 100%;
position: relative;
.article_miss_thumb {
background-size: cover;
background-repeat: no-repeat;
background-position: center;
position: relative;
border-radius: 12px;
cursor: pointer;
height: 100%;
}
.article_miss_content {
position: absolute;
z-index: 2;
bottom: -30px;
background-color: rgba(255, 93, 2, 0.7);
backdrop-filter: blur(2px);
width: 80%;
left: 10%;
padding: 16px 10px;
border-radius: 8px;
h3 {
font-size: 16px;
font-weight: 700;
line-height: 130%;
text-align: center;
// margin-bottom: 12px;
margin-bottom: 0;
}
}
.empty-box {
background-color: #409eff;
min-height: 60px;
height: 100%;
i {
font-size: 60px;
}
}
}
</style>
@@ -7,7 +7,8 @@ const props = defineProps<{
dataType?: any; dataType?: any;
dataQuery?: any; dataQuery?: any;
layout?: string; layout?: string;
label?: string; label?: any;
component?: any;
}>(); }>();
const LAYOUT_PARSE = computed(() => { const LAYOUT_PARSE = computed(() => {
@@ -24,11 +25,9 @@ const parseData = computed(() => {
<template> <template>
<article <article
:id="`cpn_${props.component.id}`"
class="basic-article border-custom" class="basic-article border-custom"
:class="LAYOUT_PARSE['article_Class']" :class="LAYOUT_PARSE['article_Class']"
@click="selectComponent"
@dragover.prevent
@drop.stop.prevent="drop"
:style="LAYOUT_PARSE['article']" :style="LAYOUT_PARSE['article']"
> >
<!-- <div class="basic-article_thumbnail" :class="LAYOUT_PARSE['thumbnail_Class']" :style="LAYOUT_PARSE['div.basic-article_thumbnail']"> <!-- <div class="basic-article_thumbnail" :class="LAYOUT_PARSE['thumbnail_Class']" :style="LAYOUT_PARSE['div.basic-article_thumbnail']">
@@ -77,7 +76,7 @@ const parseData = computed(() => {
class="article_video_thumb" class="article_video_thumb"
:style="{ backgroundImage: `url('${parseData.thumbnail ? parseData.thumbnail : '/images/default-thumbnail.jpg'}')` }" :style="{ backgroundImage: `url('${parseData.thumbnail ? parseData.thumbnail : '/images/default-thumbnail.jpg'}')` }"
> >
<i class="ri-play-circle-line"></i> <Icon name="ri:play-circle-line" />
</div> </div>
<div class="article_video_content"> <div class="article_video_content">
<div> <div>
@@ -88,20 +87,9 @@ const parseData = computed(() => {
</div> </div>
</div> </div>
</template> </template>
<div v-else>
<div class="empty-box">
<div class="d-flex justify-content-center align-items-center flex-column empty-block" style="background-color: #409eff;">
<i class="ri-play-circle-line text-white"></i>
</div>
<div class="empty-block">
<div style="height: 8px"></div>
<div style="height: 8px"></div>
</div>
</div>
</div>
</div> </div>
<div v-html="LAYOUT_PARSE.styleClasses"></div> <div v-if="LAYOUT_PARSE.styleClasses" v-html="LAYOUT_PARSE.styleClasses"></div>
</article> </article>
</template> </template>
@@ -110,6 +98,7 @@ const parseData = computed(() => {
.article_video_container { .article_video_container {
display: flex; display: flex;
align-items: center; align-items: center;
.article_video_thumb { .article_video_thumb {
background-size: cover; background-size: cover;
background-repeat: no-repeat; background-repeat: no-repeat;
@@ -119,8 +108,10 @@ const parseData = computed(() => {
width: 250px; width: 250px;
height: 140px; height: 140px;
border-radius: 2px; border-radius: 2px;
margin: 10px;
text-align: center; text-align: center;
display: flex;
justify-content: center;
align-items: center;
&::after { &::after {
content: ''; content: '';
position: absolute; position: absolute;
@@ -131,17 +122,18 @@ const parseData = computed(() => {
top: 0px; top: 0px;
left: 0px; left: 0px;
} }
i { svg {
font-size: 40px; font-size: 40px;
color: white; color: white;
position: relative; position: relative;
z-index: 2; z-index: 2;
} }
} }
.article_video_content { .article_video_content {
position: relative; position: relative;
z-index: 2; z-index: 2;
margin: 10px 0px; padding: 10px;
> div { > div {
background: #ffffff; background: #ffffff;
} }
@@ -1,6 +1,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { enumPageComponentTemplates } from "@/definitions/enum"; import { enumPageComponentTemplates } from "@/definitions/enum";
import { DEFAULT_QUERY_DROP, getInputValue } from "@/utils/parseSQL"; import { DEFAULT_QUERY_DROP, getInputValue } from "@/utils/parseSQL";
import { getResource } from "@/utils/resourceHandler";
const props = defineProps<{ const props = defineProps<{
dataResult?: any; dataResult?: any;
@@ -8,6 +9,7 @@ const props = defineProps<{
dataQuery?: any; dataQuery?: any;
layout?: string; layout?: string;
label?: string; label?: string;
component?: any;
}>(); }>();
const LAYOUT_PARSE = computed(() => { const LAYOUT_PARSE = computed(() => {
@@ -15,143 +17,122 @@ const LAYOUT_PARSE = computed(() => {
return Object.assign({}, designObject); return Object.assign({}, designObject);
}); });
const emit = defineEmits(["selectComponent", "dropData"]);
const selectComponent = () => {
emit("selectComponent");
};
const parseData = computed(() => { const parseData = computed(() => {
if (!props.dataResult) return; if (!props.dataResult) return;
const result = getInputValue(props.dataResult, "OBJECT"); const result = getInputValue(props.dataResult, "OBJECT");
return result; return result;
}); });
const drop = (e: any) => {
if (e.dataTransfer.getData(`${enumPageComponentTemplates.ARTICLE}`)) {
const data = e.dataTransfer.getData(`${enumPageComponentTemplates.ARTICLE}`);
const { dataType, dataResult } = JSON.parse(data);
const dataQuery = DEFAULT_QUERY_DROP(dataType, dataResult.id);
emit("dropData", {
dataType,
dataResult,
dataQuery: dataQuery,
});
}
};
</script> </script>
<template> <template>
<article <article :id="`cpn_${props.component?.id}`" class="basic-article border-custom" :class="LAYOUT_PARSE['article_Class']" @click="selectComponent" @dragover.prevent @drop.stop.prevent="drop" :style="LAYOUT_PARSE['article']">
class="basic-article border-custom"
:class="LAYOUT_PARSE['article_Class']"
@click="selectComponent"
@dragover.prevent
@drop.stop.prevent="drop"
:style="LAYOUT_PARSE['article']"
>
<!-- <div class="basic-article_thumbnail" :class="LAYOUT_PARSE['thumbnail_Class']" :style="LAYOUT_PARSE['div.basic-article_thumbnail']">
<template v-if="parseData">
<img class="object-fit-cover" :src="parseData.thumbnail ? parseData.thumbnail : '/images/default-thumbnail.jpg'" :alt="parseData.title?.replace(/<[^>]+>/g, '')" />
</template>
<span v-else class="empty-block" style="width: 100%; height: 100%; min-height: 50px"></span>
</div>
<div class="basic-article_content" :class="[!parseData && 'no-data']">
<template v-if="parseData?.topics && parseData?.topics.length > 0">
<nuxt-link class="article-card-default__topic" :to="`/${parseData?.topics[0].code}`" :style="LAYOUT_PARSE['topic']">
<h5>{{ parseData?.topics[0].title }}</h5>
</nuxt-link>
</template>
<h3 class="line-clamp" :class="LAYOUT_PARSE['title_Class']" :style="LAYOUT_PARSE['h3.title']">
<template v-if="parseData">
{{ parseData.title?.replace(/<[^>]+>/g, "") }}
</template>
<span v-else class="empty-block" style="height: 8px"></span>
</h3>
<div class="article-card-default__bottom" v-if="LAYOUT_PARSE.layout === 'row'">
<span :style="LAYOUT_PARSE['time']" style="margin-right: 5px" :class="LAYOUT_PARSE['time_Class']">{{
formatDate(String(parseData?.createdOn), "DD/MM/YYYY | HH:mm")
}}</span>
<nuxt-link :style="LAYOUT_PARSE['category-article']" :class="LAYOUT_PARSE['category-article_Class']">{{ parseData?.category?.title }}</nuxt-link>
</div>
<p class="mb-0 line-clamp" :class="LAYOUT_PARSE['paragraph_Class']" :style="LAYOUT_PARSE['p.paragraph']">
<template v-if="parseData">
{{ parseData.intro?.replace(/<[^>]+>/g, "") }}
</template>
<span v-else class="empty-block" style="height: 5px"></span>
</p>
<div class="article-card-default__bottom" v-if="LAYOUT_PARSE?.layout !== 'row'" :style="LAYOUT_PARSE['metadata']">
<span :style="LAYOUT_PARSE['time']" style="margin-right: 5px" :class="LAYOUT_PARSE['time_Class']">{{
formatDate(String(parseData?.createdOn), "DD/MM/YYYY | HH:mm")
}}</span>
<nuxt-link :style="LAYOUT_PARSE['category-article']" :class="LAYOUT_PARSE['category-article_Class']">{{ parseData?.category?.title }}</nuxt-link>
</div>
</div>
-->
<div class="article_video"> <div class="article_video">
<template v-if="parseData"> <template v-if="parseData">
<div <div class="article_video_thumb article-thumbnail" :style="{ backgroundImage: `url('${parseData.thumbnail ? parseData.thumbnail : '/images/default-thumbnail.jpg'}')` }">
class="article_video_thumb" <div></div>
:style="{ backgroundImage: `url('${parseData.thumbnail ? parseData.thumbnail : '/images/default-thumbnail.jpg'}')` }" <div class="article_video_content">
> <span>
<div></div> <svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
<div class="article_video_content"> <path
<span><i class="ri-play-circle-line"></i></span> d="M23.5 18.5C24.375 17.875 25.625 17.875 26.5 18.5L44.5 29.5C45.375 30 46 31 46 32C46 33.125 45.375 34.125 44.5 34.625L26.5 45.625C25.625 46.125 24.375 46.25 23.5 45.625C22.5 45.125 22 44.125 22 43V21C22 20 22.5 19 23.5 18.5ZM64 32C64 49.75 49.625 64 32 64C14.25 64 0 49.75 0 32C0 14.375 14.25 0 32 0C49.625 0 64 14.375 64 32ZM32 6C17.625 6 6 17.75 6 32C6 46.375 17.625 58 32 58C46.25 58 58 46.375 58 32C58 17.75 46.25 6 32 6Z"
<h3 class="line-clamp text-white" :class="LAYOUT_PARSE['title_Class']" :style="LAYOUT_PARSE['h3.title']"> fill="#ED1C24"
{{ parseData.title?.replace(/<[^>]+>/g, "") }} />
</h3> </svg>
<p class="mb-0 line-clamp text-white" :class="LAYOUT_PARSE['paragraph_Class']" :style="LAYOUT_PARSE['p.paragraph']"> </span>
{{ parseData.intro?.replace(/<[^>]+>/g, "") }} <h3 class="line-clamp article-title" :class="LAYOUT_PARSE['title_Class']" :style="LAYOUT_PARSE['h3.title']">
</p> {{ parseData.title?.replace(/<[^>]+>/g, "") }}
</div> </h3>
</div> <p class="mb-0 line-clamp article-intro" :class="LAYOUT_PARSE['paragraph_Class']" :style="LAYOUT_PARSE['p.paragraph']">
</template> {{ parseData.intro?.replace(/<[^>]+>/g, "") }}
<div v-else class="empty-box"> </p>
<div class="d-flex justify-content-center align-items-center flex-column"> </div>
<i class="ri-play-circle-line text-white"></i>
</div>
</div> </div>
</template>
<div v-else class="empty-box">
<div class="d-flex justify-content-center align-items-center flex-column">
<i class="ri-play-circle-line"></i>
</div>
</div>
</div> </div>
<div v-html="LAYOUT_PARSE.styleClasses"></div> <div v-html="LAYOUT_PARSE.styleClasses" v-if="LAYOUT_PARSE.styles"></div>
</article> </article>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
.article_video { .article_video {
.article_video_thumb { .article_video_thumb {
background-size: cover; background-size: cover;
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center; background-position: center;
position: relative; position: relative;
z-index: 0; z-index: 0;
padding: 120px 85px 60px 85px; padding: 120px 85px 60px 85px;
border-radius: 2px; border-radius: 2px;
margin: 10px; margin: 10px;
cursor: pointer; cursor: pointer;
&::after { &::after {
content: ''; content: "";
position: absolute; position: absolute;
width: 100%; width: 100%;
height: 100%; height: 100%;
background-color: rgba(0, 0, 0, 0.4); background-color: rgba(0, 0, 0, 0.4);
z-index: 1; z-index: 1;
top: 0px; top: 0px;
left: 0px; left: 0px;
}
.article_video_content {
position: relative;
z-index: 2;
h3 {
font-size: 44px;
font-weight: 700;
line-height: 57.2px;
text-align: left;
margin-bottom: 12px;
}
p {
font-size: 14px;
font-weight: 400;
}
i {
font-size: 80px;
color: #ed1c24;
}
}
}
.empty-box {
background-color: #409eff;
margin: 10px;
min-height: 60px;
i {
font-size: 60px;
}
}
} }
.article_video_content {
position: relative;
z-index: 2;
h3 {
font-size: 44px;
font-weight: 700;
line-height: 57.2px;
text-align: left;
margin-bottom: 12px;
color: white;
}
p {
font-size: 14px;
font-weight: 400;
color: white;
}
i {
font-size: 80px;
color: #ed1c24;
}
}
}
.empty-box {
background-color: #409eff;
margin: 10px;
min-height: 60px;
i {
font-size: 60px;
}
}
}
</style> </style>
@@ -1,4 +1,5 @@
export { default as Article_Card_Default } from './Card.vue' export { default as Article_Card_Default } from './Card.vue'
export { default as Article_Card_Audio } from './Audio.vue' export { default as Article_Card_Audio } from './Audio.vue'
export { default as Article_Card_Video } from './Video.vue' export { default as Article_Card_Video } from './Video.vue'
export { default as Article_Card_Video_Hightlight } from './VideoBackground.vue' export { default as Article_Card_Video_Hightlight } from './VideoBackground.vue'
export { default as Article_Card_Miss_Hightlight } from './MissBackground.vue'
@@ -1,6 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import { enumPageComponentTemplate, enumPageComponentKey, enumPageComponentLayouts } from "@/definitions/enum"; import { enumPageComponentTemplate, enumPageComponentKey, enumPageComponentLayouts } from "@/definitions/enum";
import { Article_Card_Default, Article_Card_Audio, Article_Card_Video, Article_Card_Video_Hightlight } from "./index"; import { Article_Card_Default, Article_Card_Audio, Article_Card_Video, Article_Card_Video_Hightlight,Article_Card_Miss_Hightlight } from "./index";
const _props = defineProps<{ const _props = defineProps<{
settings: any; settings: any;
@@ -13,6 +13,7 @@ const definedDynamicComponent: Record<string, any> = {
[enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]["ARTICLE_CARD"]]["CARD_AUDIO"]]: Article_Card_Audio, [enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]["ARTICLE_CARD"]]["CARD_AUDIO"]]: Article_Card_Audio,
[enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]["ARTICLE_CARD"]]["CARD_VIDEO"]]: Article_Card_Video, [enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]["ARTICLE_CARD"]]["CARD_VIDEO"]]: Article_Card_Video,
[enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]["ARTICLE_CARD"]]["CARD_VIDEO_HIGHLIGHT"]]: Article_Card_Video_Hightlight, [enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]["ARTICLE_CARD"]]["CARD_VIDEO_HIGHLIGHT"]]: Article_Card_Video_Hightlight,
[enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]["ARTICLE_CARD"]]["CARD_MISS_HIGHLIGHT"]]: Article_Card_Miss_Hightlight,
}; };
const getCurrentComponent = computed(() => { const getCurrentComponent = computed(() => {
@@ -36,5 +37,9 @@ const GET_PROPS = computed(() => {
</script> </script>
<template> <template>
<component :is="definedDynamicComponent[getCurrentComponent]" v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings }" /> <component
v-if="definedDynamicComponent[getCurrentComponent]"
:is="definedDynamicComponent[getCurrentComponent]"
v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings }"
/>
</template> </template>
@@ -0,0 +1,95 @@
<script setup lang="ts">
const emit = defineEmits(["dropData", "selectComponent"]);
const _props = defineProps<{
dataResult?: any;
dataType?: any;
dataQuery?: any;
layout?: string;
label?: string;
}>();
const { currentArticle } = storeToRefs(useArticleStore())
console.log(currentArticle.value, 'currentArticle')
</script>
<template>
<div class="overflow-hidden emagazine">
<h2 class="font-gelasio text-center text-44px font-bold leading-130%" v-if="currentArticle?.title" v-html="currentArticle?.title"></h2>
<div class="article-detail" v-html="currentArticle.detail"></div>
</div>
</template>
<style scoped lang="scss">
.breadcrumb {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
&__list {
margin: 0;
padding: 0px;
display: flex;
overflow-x: auto;
gap: 1.5rem;
align-items: center;
font-size: 0.875rem;
line-height: 1.25rem;
&__item {
display: inline-block;
position: relative;
&__title {
margin: 0;
font-size: 18px;
color: #000;
font-weight: 500;
text-transform: uppercase;
line-height: 180%;
}
// &:first-child {
// color: blue;
// }
&:not(:first-child):before {
content: "\\";
position: absolute;
left: -18px;
}
}
}
.article-card-default__topic {
position: relative;
// background-color: #151411;
display: inline-block;
h5 {
font-size: 12px;
display: flex;
align-items: center;
justify-content: center;
text-transform: uppercase;
// color: #fff;
padding: 0 12px;
height: 100%;
margin: 0;
border: 1px solid #000;
line-height: 180%;
font-weight: 300;
}
&::after {
position: absolute;
content: "";
display: block;
width: 12px;
height: 100%;
background-color: #ed1c24;
left: -12px;
top: 0;
}
}
}
.content {
width: auto;
}
</style>
@@ -1,8 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { enumPageComponentTemplates } from "@/definitions/enum"; import { enumPageComponentTemplates } from "@/definitions/enum";
import { DEFAULT_QUERY_DROP } from "@/utils/parseSQL"; import { DEFAULT_QUERY_DROP, getInputValue } from "@/utils/parseSQL";
import { isEmpty } from "@/utils/lodash"; const emit = defineEmits(["dropData", "selectComponent"]);
import { getInputValue } from "@/utils/parseSQL";
const _props = defineProps<{ const _props = defineProps<{
dataResult?: any; dataResult?: any;
@@ -18,6 +17,9 @@ const LAYOUT_PARSE = computed(() => {
const designObject = _props.label ? getInputValue(_props.label, "OBJECT") : {}; const designObject = _props.label ? getInputValue(_props.label, "OBJECT") : {};
return Object.assign({}, designObject); return Object.assign({}, designObject);
}); });
const selectComponent = () => {
emit("selectComponent");
};
const parseData = computed(() => { const parseData = computed(() => {
if (!_props.dataResult) return; if (!_props.dataResult) return;
@@ -25,20 +27,29 @@ const parseData = computed(() => {
return result; return result;
}); });
const articleStore = useArticleStore(); const drop = (e: any) => {
const currentArticle = computed(() => articleStore.currentArticleGeneral); if (e.dataTransfer.getData(`${enumPageComponentTemplates.ARTICLE}`)) {
const data = e.dataTransfer.getData(`${enumPageComponentTemplates.ARTICLE}`);
const { dataType, dataResult } = JSON.parse(data);
const dataQuery = DEFAULT_QUERY_DROP(dataType, dataResult.id);
emit("dropData", {
dataType,
dataResult,
dataQuery: dataQuery,
});
}
};
</script> </script>
<template> <template>
<div class="overflow-hidden"> <div @click="selectComponent" class="overflow-hidden" @dragover.prevent @drop.stop.prevent="drop">
<div class="breadcrumb" v-if="!LAYOUT_PARSE['HideBreadcrumb']"> <div class="breadcrumb" v-if="!LAYOUT_PARSE['HideBreadcrumb']">
<ul class="breadcrumb__list"> <ul class="breadcrumb__list">
<li <li
class="breadcrumb__list__item" class="breadcrumb__list__item"
v-for="(item, index) in _props.dataResult && _props.dataResult?.length > 0 ? _props.dataResult : Array(SETTING_OPTIONS.BREADCRUMB_MAX_ELEMENT).fill(null)" v-for="(item, index) in _props.dataResult && _props.dataResult?.length > 0 ? _props.dataResult : Array(SETTING_OPTIONS.BREADCRUMB_MAX_ELEMENT).fill(null)"
:key="index" :key="index"
:class="isEmpty(item) && 'empty'"
> >
<p v-if="!isEmpty(item)" class="breadcrumb__list__item__title"> <p class="breadcrumb__list__item__title">
{{ item?.title }} {{ item?.title }}
</p> </p>
</li> </li>
@@ -1,55 +1,76 @@
<script setup lang="ts"> <script setup lang="ts">
import { isEmpty } from "@/utils/lodash"; const emit = defineEmits(["dropData", "selectComponent"]);
const { categoryTree } = storeToRefs(useCategoryStore());
const { currentArticle } = storeToRefs(useArticleStore());
if (categoryTree.value) {
await useCategoryStore().fetchBySiteId();
}
const _props = defineProps<{ const _props = defineProps<{
dataResult?: any[]; dataResult?: any[];
}>(); }>();
const SETTING_OPTIONS = { const SETTING_OPTIONS = {
BREADCRUMB_MAX_ELEMENT: 3, BREADCRUMB_MAX_ELEMENT: 3,
}; };
const currentCategoryTree = findElementPathById(categoryTree.value, currentArticle.value.categoryId);
function findElementPathById(categories: any[], targetId: number, path: any[] = []) {
for (const category of categories) {
const currentPath = [...path, { title: category.title, code: category.code }];
if (category.id === targetId) {
return currentPath;
}
if (category.children) {
const result: any = findElementPathById(category.children, targetId, currentPath);
if (result) {
return result;
}
}
}
return null;
}
console.log(currentArticle.value, "currentArticle");
</script> </script>
<template> <template>
<div class="overflow-hidden"> <div class="overflow-hidden w-full max-w-1385px mx-auto px-30px image">
<div class="breadcrumb"> <div class="">
<ul class="breadcrumb__list"> <div class="category flex justify-between flex-wrap items-center mb-10px">
<li <ul class="flex gap-32px">
class="breadcrumb__list__item" <li v-for="(category, index) in currentCategoryTree" :key="index" class="first:text-#000 text-#929292 last:after:content-[''] relative after:absolute after:content-['/'] after:text-20px after:right--20px">
v-for="(item, index) in _props.dataResult && _props.dataResult?.length > 0 ? _props.dataResult : Array(SETTING_OPTIONS.BREADCRUMB_MAX_ELEMENT).fill(null)" <nuxt-link class="font-raleway text-18px font-500 leading-180% uppercase" :to="`/${category.code}`">{{ category.title }}</nuxt-link>
:key="index" </li>
:class="isEmpty(item) && 'empty'" </ul>
>
<p v-if="!isEmpty(item)" class="breadcrumb__list__item__title">
{{ item?.title }}
</p>
</li>
</ul>
<p class="breakcrumb__time">Ngày tạo image</p> <div v-if="currentArticle.topics" class="pl-20px relative bg-primary inline-block">
</div> <nuxt-link class="h-30px block py-4px px-16px border-1 border-#000 bg-white text-12px leading-180% font-raleway font-400" :to="`/topic/${currentArticle.topics[0].code}`">{{ currentArticle.topics[0].title }}</nuxt-link>
</div>
<div class="content">Nội dung bài viết sẽ đây</div>
<div class="btn-wrap w-100 max-w">
<div class="center-y">
<p title="Quay trở lại" class="button--back">
<Icon name="fa6-solid:arrow-left" />
</p>
<button class="button--bookmark">
<Icon name="fa6-regular:bookmark" />
</button>
</div> </div>
<h2 class="font-gelasio text-44px font-bold leading-130%" v-if="currentArticle.title" v-html="currentArticle.title"></h2>
<!-- <div class="grid grid-cols-12 gap-20px">
<div class="col-span-3"></div>
</div> -->
<div class="center-y"> <div class="author flex gap-12px my-20px" v-if="currentArticle.authors">
<button title="Copy link" class="button--back copy-link"> <ul class="flex">
<Icon name="mdi:link-variant" /> <li :style="{ 'z-index': index + 1 }" class="relative ml--12px first:ml-0" v-for="(author, index) in currentArticle.authors" :key="index">
</button> <nuxt-link :to="`/tac-gia/${author.code}`">
<img :src="author.thumbnail || `http://picsum.photos/1024/600?random=1`" alt="" class="w-64px p-1px border-1px border-white h-64px object-cover rounded-full" />
</nuxt-link>
</li>
</ul>
<div>
<div class="mt-10px">
<nuxt-link class="font-raleway text-#000" v-for="(author, index) in currentArticle.authors" :key="index" :to="`/tac-gia/${author.code}`">{{ author.title + (index < currentArticle.authors.length - 1 ? ", " : "") }}</nuxt-link>
</div>
<div class="text-12px">Xuất bản vào {{ formatDate(currentArticle.publishedOn, "DD/MM/YYYY | hh:mm") }}</div>
</div>
</div> </div>
<div v-html="currentArticle.detail"></div>
</div> </div>
</div> </div>
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
$max-width: 680px; $max-width: 1276px;
.breadcrumb { .breadcrumb {
display: flex; display: flex;
@@ -0,0 +1,101 @@
<script setup lang="ts">
const emit = defineEmits(["dropData", "selectComponent"]);
const _props = defineProps<{
dataResult?: any;
dataType?: any;
dataQuery?: any;
layout?: string;
label?: string;
}>();
const { currentArticle } = storeToRefs(useArticleStore())
console.log(currentArticle.value, 'currentArticle')
</script>
<template>
<div class="overflow-hidden infographic">
<!-- bổ sung sau -->
<!-- <img :src="currentArticle.thumbnail" alt="" class="w-full object-cover">
<div class="px-44px pb-30px my-30px max-w-660px mx-auto border-b-1px border-#000">
</div> -->
<h2 class="font-gelasio text-center text-44px font-bold leading-130%" v-if="currentArticle?.title" v-html="currentArticle?.title"></h2>
<div v-html="currentArticle.detail"></div>
</div>
</template>
<style scoped lang="scss">
.breadcrumb {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
&__list {
margin: 0;
padding: 0px;
display: flex;
overflow-x: auto;
gap: 1.5rem;
align-items: center;
font-size: 0.875rem;
line-height: 1.25rem;
&__item {
display: inline-block;
position: relative;
&__title {
margin: 0;
font-size: 18px;
color: #000;
font-weight: 500;
text-transform: uppercase;
line-height: 180%;
}
// &:first-child {
// color: blue;
// }
&:not(:first-child):before {
content: "\\";
position: absolute;
left: -18px;
}
}
}
.article-card-default__topic {
position: relative;
// background-color: #151411;
display: inline-block;
h5 {
font-size: 12px;
display: flex;
align-items: center;
justify-content: center;
text-transform: uppercase;
// color: #fff;
padding: 0 12px;
height: 100%;
margin: 0;
border: 1px solid #000;
line-height: 180%;
font-weight: 300;
}
&::after {
position: absolute;
content: "";
display: block;
width: 12px;
height: 100%;
background-color: #ed1c24;
left: -12px;
top: 0;
}
}
}
.center-y {
width: auto;
}
</style>
@@ -1,93 +1,254 @@
<script setup lang="ts"> <script setup lang="ts">
import { useArticleStore } from "~/stores/articles";
import Poll from "~/components/article/immerse/Poll.vue";
import Quiz from "~/components/article/immerse/Quiz.vue";
import Survey from "~/components/article/immerse/Survey.vue";
import Document from "~/components/article/immerse/Document.vue";
import Attachment from "@/components/article/immerse/Attachment.vue";
import Tag from "@/components/article/immerse/Tag.vue";
const { currentArticle } = storeToRefs(useArticleStore());
import { useDynamicPageStore } from "~/stores/dynamic-page";
import { useCategoryStore } from "~/stores/category";
const store = reactive({
dynamicPage: useDynamicPageStore(),
article: useArticleStore(),
category: useCategoryStore(),
});
const { categoryTree } = storeToRefs(store.category);
await store.category.fetchBySiteId();
const currentCategoryTree = (store.category.currentCategoryTree = findElementPathById(categoryTree.value, currentArticle.value.categoryId));
function findElementPathById(categories: any[], targetId: number, path: any[] = []) {
for (const category of categories) {
const currentPath = [...path, { title: category.title, code: category.code }];
if (category.id === targetId) {
return currentPath;
}
if (category.children) {
const result: any = findElementPathById(category.children, targetId, currentPath);
if (result) {
return result;
}
}
}
return null;
}
onMounted(async () => {
clickElement("figure", "custom-figure", "data-code");
clickElement("author", "author", "data-code");
let detailEmagazine = document.querySelector('div[layout="ARTICLE_DETAIL_EMAGAZINE"]');
let breadcrumb = document.querySelector('div[layout="BREADCRUM_DEFAULT"]');
if (detailEmagazine && breadcrumb) {
breadcrumb.classList.add("lg:max-w-640px", "mx-auto");
}
});
function clickElement(type: string, selector: string, attribute: string) {
const elements = document.querySelectorAll(selector);
elements.forEach((element) => {
element.addEventListener("click", (event) => {
event.preventDefault();
const url = `${window.location.protocol}//${window.location.host}/${type}/${element.getAttribute(attribute)}`;
const a = document.createElement("a");
a.href = url;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
});
});
}
const isBookmark = ref(false);
const onClickBookmark = () => {
isBookmark.value = !isBookmark.value;
};
async function copyLink() {
try {
const url = window.location.href;
await navigator.clipboard.writeText(url);
alert("copy link thành công");
} catch (error) {
alert(error);
}
}
const getSrc = (htmlString: string) => {
const srcRegex = /src="([^"]+)"/;
return htmlString?.match(srcRegex);
};
const isMoreControl = ref(false);
const isPlayed = ref(true);
const isVolume = ref(true);
const speedList = ref<{ [key: number]: string }>({
1: "0.5x",
2: "0.75x",
3: "1.0x",
4: "1.25x",
5: "1.50x",
});
const speedIndexDefault = ref(3);
const speedDefault = ref(speedList.value[speedIndexDefault.value]);
const volume = ref(1.0);
const audioPlayer = ref<HTMLAudioElement | null>(null);
const currentTime = ref(0);
const duration = ref(0);
function setUpVolums() {
isVolume.value = !isVolume.value;
if (audioPlayer.value) {
if (isVolume.value) {
audioPlayer.value.volume = 1;
} else {
audioPlayer.value.volume = 0;
}
}
}
const updateVolume = (num?: number) => {
if (audioPlayer.value) {
if(num) {
volume.value += num
}
// console.log('1231321')
audioPlayer.value.volume = volume.value;
}
};
function chanageSpeed() {
if (speedIndexDefault.value < 5) {
speedIndexDefault.value += 1;
if (audioPlayer.value) {
audioPlayer.value.playbackRate += 0.25;
}
speedDefault.value = speedList.value[speedIndexDefault.value];
} else {
if (audioPlayer.value) {
audioPlayer.value.playbackRate = 0.5;
}
speedIndexDefault.value = 1;
speedDefault.value = speedList.value[1];
}
}
function togglePlayer() {
isPlayed.value = !isPlayed.value;
if (audioPlayer.value) {
if (isPlayed.value) {
audioPlayer.value.pause();
} else {
audioPlayer.value.play();
}
}
}
function replayAndForward(time: number) {
if (audioPlayer.value) {
if (audioPlayer.value.currentTime == audioPlayer.value.duration) {
isPlayed.value = true;
} else {
audioPlayer.value.currentTime = audioPlayer.value.currentTime + time;
}
}
}
const seekToTime = () => {
if (audioPlayer.value) {
audioPlayer.value.currentTime = currentTime.value;
}
};
const updateCurrentTime = () => {
if (audioPlayer.value) {
currentTime.value = audioPlayer.value.currentTime;
}
};
const updateDuration = () => {
if (audioPlayer.value) {
duration.value = audioPlayer.value.duration;
}
};
const currrentTimeComputed = computed(() => {
return utils.formattedTime(currentTime.value);
});
const durationComputed = computed(() => {
return utils.formattedTime(duration.value);
});
</script> </script>
<template> <template>
<div <div class="lg:p-40px md:p-30px p-5 border-1px border-solid border-black/10 rounded-8px">
class="podcast__wrapper overflow-hidden" <div class="flex md:flex-row flex-col md:gap-6 gap-2 justify-between mb-10px">
> <p class="text-#9f9f9f text-14px mb-2 md:hidden block text-center">
<div {{ utils.dateFormat(currentArticle?.publishedOn, "dddd, DD/MM/YYYY - HH:mm") }}
class="podcast"
>
<p
class="podcast__content__time"
>
Ngày tạo podcast
</p> </p>
<figure><img src="http://picsum.photos/1024/600?random=1'" alt="Ảnh podcast" title="Ảnh podcast" /></figure> <figure class="!w-auto"><img class="w-150px h-150px rounded-8px shadow-md cursor-pointer" :src="currentArticle?.thumbnail" alt="Ảnh podcast" title="Ảnh podcast" /></figure>
<div <div class="flex-1 text-#222 m-0 md:text-left text-center">
class="podcast__content" <p class="text-#9f9f9f text-14px mb-2 md:block hidden">
> {{ utils.dateFormat(currentArticle?.publishedOn, "dddd, DD/MM/YYYY - HH:mm") }}
<p
class="podcast__content__time"
>
Ngày tạo podcast
</p>
<h1 class="podcast__content__title">Tiêu đề podcast</h1>
<p
class="podcast__content__text"
>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p> </p>
<h1 class="text-24px md:mb-4 mb-2 font-bold" v-html="currentArticle?.title"></h1>
<p class="hidden md:line-clamp-3" v-html="currentArticle?.intro"></p>
</div> </div>
<ul <ul class="items-start gap-2 m-0 p-0 md:flex hidden">
class="buttons" <li class="w-9 h-9 bg-white border-1 border-solid border-[rgb(229, 231, 235)] cursor-pointer shadow-md rounded-50px relative hover:bg-primary-100 hover:text-primary-600">
> <Icon class="text-18px absolute top-50% left-50% translate-x--50% translate-y--50%" name="mdi:bookmark-outline" />
<li><Icon name="mdi:bookmark-outline" /></li> </li>
<li><Icon name="material-symbols:mode-comment-outline" /></li> <li class="w-9 h-9 bg-white border-1 border-solid border-[rgb(229, 231, 235)] cursor-pointer shadow-md rounded-50px relative hover:bg-primary-100 hover:text-primary-600">
<Icon class="text-18px absolute top-50% left-50% translate-x--50% translate-y--50%" name="material-symbols:mode-comment-outline" />
</li>
</ul> </ul>
</div> </div>
<audio :src="getSrc(currentArticle?.detail)?.[1]" preload="auto" ref="audioPlayer" @timeupdate="updateCurrentTime" @loadedmetadata="updateDuration" />
<div class="playlist"> <div class="p-2">
<div class="playlist__time"> <input class="w-full accent-primary-600 cursor-pointer" type="range" v-model="currentTime" @input="seekToTime" :max="duration" />
<span>5:00</span> <div class="flex justify-between">
<span>10:00</span> <span>{{ currrentTimeComputed }}</span>
<span>{{ durationComputed }}</span>
</div> </div>
<div class="playlist__buttons"> <div class="flex justify-between items-center">
<div class="playlist__buttons__left"> <div class="md:w-150px text-left">
<div <div class="text-28px text-primary-600 md:hidden block">
class="button__prev"
>
<Icon name="material-symbols:skip-previous" /> <Icon name="material-symbols:skip-previous" />
</div> </div>
<div <div class="md:inline-flex hidden items-center gap-2 ml--10px h9 text-primary-600 rounded-8px text-28px cursor-pointer hover:bg-primary-100">
class="sound" <Icon @click="updateVolume(-0.1)" name="material-symbols:volume-mute"></Icon>
> <input v-if="isVolume" class="accent-primary-600 h-1 w-12 lg:w-20 cursor-pointer" type="range" v-model="volume" @input="updateVolume()" min="0.1" max="1" step="0.1" />
<Icon name="material-symbols:volume-mute"></Icon> <Icon @click="updateVolume(0.1)" name="material-symbols:volume-up"></Icon>
<div></div>
<Icon name="material-symbols:volume-up"></Icon>
</div> </div>
</div> </div>
<div class="play"> <div class="flex items-center justify-center gap-4 flex-1 text-28px text-primary-600">
<Icon name="fluent:skip-back-10-48-filled" /> <Icon @click="replayAndForward(-10)" name="fluent:skip-back-10-48-filled" />
<Icon name="material-symbols:play-arrow" class="button" /> <button @click="togglePlayer" class="bg-transparent">
<Icon name="fluent:skip-forward-10-48-filled" /> <Icon v-if="isPlayed" name="material-symbols:play-arrow-rounded" class="text-64px" />
<Icon v-if="!isPlayed" name="material-symbols:pause" class="text-64px" />
</button>
<Icon @click="replayAndForward(10)" name="fluent:skip-forward-10-48-filled" />
</div> </div>
<div class="playlist__buttons__right"> <div class="md:w-150px text-right">
<div <div class="text-28px text-primary-600 md:hidden block">
class="button__next"
>
<Icon name="material-symbols:skip-next" /> <Icon name="material-symbols:skip-next" />
</div> </div>
<div <div class="text-14px text-primary-600 md:block hidden cursor-pointer" @click="chanageSpeed">
class="speed" <span class="font-300">Tốc độ phát: </span>
> <strong class="font-bold text-20px ml-1">{{ speedDefault }}</strong>
<span>Tốc độ phát: </span>
<strong>1x</strong>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<p <p class="md:hidden block" v-html="currentArticle?.intro"></p>
class="podcast__content__text"
>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
</div> </div>
</template> </template>
<style lang="scss"> <style lang="scss">
@@ -1,42 +1,93 @@
<script setup lang="ts"> <script setup lang="ts">
import Comment from "@/components/dynamic-page/page-component/templates/others/comments/Default.vue"; const { categoryTree } = storeToRefs(useCategoryStore());
const { currentArticle } = storeToRefs(useArticleStore());
if (categoryTree.value) {
await useCategoryStore().fetchBySiteId();
}
const currentCategoryTree = findElementPathById(categoryTree.value, currentArticle.value.categoryId);
function findElementPathById(categories: any[], targetId: number, path: any[] = []) {
for (const category of categories) {
const currentPath = [...path, { title: category.title, code: category.code }];
if (category.id === targetId) {
return currentPath;
}
if (category.children) {
const result: any = findElementPathById(category.children, targetId, currentPath);
if (result) {
return result;
}
}
}
return null;
}
</script> </script>
<template> <template>
<div class="container overflow-hidden"> <div class="video-container">
<div class="video row"> <ul class="flex gap-32px lg:ml-80px md:ml-40px sm:ml-20px">
<div <li v-for="(category, index) in currentCategoryTree" :key="index" class="first:text-#000 text-#929292 last:after:content-[''] relative after:absolute after:content-['/'] after:text-20px after:right--20px">
class="video__left" <nuxt-link class="font-raleway text-18px font-500 leading-180% uppercase" :to="`/${category.code}`">{{ category.title }}</nuxt-link>
> </li>
<video controls="controls" width="100%" height="100%" data-file-id="149" data-resource="https://acp-api.vpress.vn/Resources/Video/983d2f57-7743-472f-b22d-fc73085af6d5.mp4" data-title="Download.mp4"> </ul>
<source src="" type="video/mp4" /> <h2 class="font-gelasio text-center text-44px font-bold leading-130%" v-if="currentArticle?.title" v-html="currentArticle?.title"></h2>
</video> <div class="video-content" v-html="currentArticle.detail"></div>
</div>
<div
class="video__right bg-body-tertiary"
>
<h1
class=""
>
Tiêu đề video
</h1>
<p class="line-clamp-3 fs-5 fw-light">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
<h5 class="text-end fs-4 opacity-75">Tác giả</h5>
<p><b class="text-primary fw-semibold">Danh mục</b> <span class="ms-2 opacity-25 fw-semibold">Ngày đăng video</span></p>
<Comment />
</div>
</div>
</div> </div>
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
.line-clamp-3 { .video-container {
overflow: hidden; width: 100%;
display: -webkit-box; max-width: 1080px;
-webkit-box-orient: vertical; margin: auto;
-webkit-line-clamp: 3;
.category-list {
display: flex;
gap: 32px;
margin-bottom: 26px;
list-style: none;
padding: 0;
margin: 0 0 0 80px;
.category-item {
color: #929292;
position: relative;
font-size: 18px;
& > span {
font-size: 18px;
font-weight: 500;
line-height: 180%;
text-transform: uppercase;
}
&::after {
position: absolute;
content: "/";
font-size: 20px;
right: -20px;
}
&:first-child {
color: #000;
}
&:last-child {
&::after {
content: "";
}
}
}
}
.video-content {
width: 100%;
// max-width: 1080px;
margin: 26px 0 26px 0px;
// background-color: #eee;
// height: 500px;
font-size: 20px;
display: flex;
align-items: center;
justify-content: center;
}
} }
</style> </style>
@@ -3,4 +3,6 @@
export { default as Article_Detail_General } from './General.vue' export { default as Article_Detail_General } from './General.vue'
export { default as Article_Detail_Podcast } from './Podcast.vue' export { default as Article_Detail_Podcast } from './Podcast.vue'
export { default as Article_Detail_Video } from './Video.vue' export { default as Article_Detail_Video } from './Video.vue'
export { default as Article_Detail_Image } from './Image.vue' export { default as Article_Detail_Image } from './Image.vue'
export { default as Article_Detail_Emagazine } from './Emagazine.vue'
export { default as Article_Detail_Infographic } from './Infographic.vue'
@@ -2,7 +2,7 @@
import { enumPageComponentTemplate, enumPageComponentKey, enumPageComponentLayouts } from "@/definitions/enum"; import { enumPageComponentTemplate, enumPageComponentKey, enumPageComponentLayouts } from "@/definitions/enum";
// import { Article_Card, Article_Detail_Video, Article_Detail_Podcast, Article_Detail_General, Article_Detail_Image } from "./index"; // import { Article_Card, Article_Detail_Video, Article_Detail_Podcast, Article_Detail_General, Article_Detail_Image } from "./index";
import { Article_Detail_General, Article_Detail_Podcast, Article_Detail_Video, Article_Detail_Image } from "./index"; import { Article_Detail_General, Article_Detail_Podcast, Article_Detail_Video, Article_Detail_Image, Article_Detail_Emagazine, Article_Detail_Infographic } from "./index";
const _props = defineProps<{ const _props = defineProps<{
settings: any; settings: any;
component?: any; component?: any;
@@ -13,6 +13,8 @@ const definedDynamicComponent: Record<string, any> = {
[enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]["ARTICLE_DETAIL"]]["DETAIL_PODCAST"]]: Article_Detail_Podcast, [enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]["ARTICLE_DETAIL"]]["DETAIL_PODCAST"]]: Article_Detail_Podcast,
[enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]["ARTICLE_DETAIL"]]["DETAIL_VIDEO"]]: Article_Detail_Video, [enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]["ARTICLE_DETAIL"]]["DETAIL_VIDEO"]]: Article_Detail_Video,
[enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]["ARTICLE_DETAIL"]]["DETAIL_IMAGE"]]: Article_Detail_Image, [enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]["ARTICLE_DETAIL"]]["DETAIL_IMAGE"]]: Article_Detail_Image,
[enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]["ARTICLE_DETAIL"]]["DETAIL_EMAGAZINE"]]: Article_Detail_Emagazine,
[enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]["ARTICLE_DETAIL"]]["DETAIL_INFOGRAPHIC"]]: Article_Detail_Infographic,
}; };
const getCurrentComponent = computed(() => `${_props.settings.layout}`); const getCurrentComponent = computed(() => `${_props.settings.layout}`);
@@ -33,5 +35,9 @@ const GET_PROPS = computed(() => {
</script> </script>
<template> <template>
<component :is="definedDynamicComponent[getCurrentComponent]" v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings }" /> <component
v-if="definedDynamicComponent[getCurrentComponent]"
:is="definedDynamicComponent[getCurrentComponent]"
v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings }"
/>
</template> </template>
@@ -32,5 +32,9 @@ const GET_PROPS = computed(() => {
</script> </script>
<template> <template>
<component :is="definedDynamicComponent[getCurrentComponent]" v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings }" /> <component
v-if="definedDynamicComponent[getCurrentComponent]"
:is="definedDynamicComponent[getCurrentComponent]"
v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings }"
/>
</template> </template>
@@ -3,11 +3,28 @@ import { isEmpty } from "@/utils/lodash";
import { COLLECTION_QUERY_DROP, getValueStringWithKeyAndColon, getInputValue } from "@/utils/parseSQL"; import { COLLECTION_QUERY_DROP, getValueStringWithKeyAndColon, getInputValue } from "@/utils/parseSQL";
const _props = defineProps<{ const _props = defineProps<{
dataResult?: any[]; dataResult?: any;
dataQuery?: string; dataQuery?: string;
label?: string; label?: any;
component?: any;
}>(); }>();
const SETTING_OPTIONS = {
MAX_ELEMENT: 3,
};
const _dataResult = computed(() => {
const designObject = _props.label ? getInputValue(_props.label, "OBJECT") : {};
let _components = Array(Number(designObject.MAX) || SETTING_OPTIONS.MAX_ELEMENT).fill(null);
const result = getInputValue(_props.dataResult, "ARRAY");
result &&
result.length > 0 &&
_components.map((_: any, index: any) => {
_components[index] = result[index] || null;
});
return Object.assign({}, _components);
});
const designObject = computed(() => { const designObject = computed(() => {
return _props.label ? getInputValue(_props.label, "OBJECT") : {}; return _props.label ? getInputValue(_props.label, "OBJECT") : {};
}); });
@@ -21,12 +38,12 @@ const mapActivesToItems = (index: number) => {
</script> </script>
<template> <template>
<div class="categories-container border-custom" :class="designObject['categories_Class']" :style="designObject['div.categories-container']"> <div :id="`cpn_${_props.component.id}`" class="categories-container border-custom" :class="designObject['categories_Class']" :style="designObject['div.categories-container']">
<div v-for="(component, index) in _dataResult" :key="index" :class="['border-custom', isEmpty(component) ? 'empty' : 'category', designObject['category_Class']]" :style="mapActivesToItems(index)['category']"> <div v-for="(component, index) in _dataResult" :key="index" :class="['border-custom', isEmpty(component) ? 'empty' : 'category', designObject['category_Class']]" :style="mapActivesToItems(index)['category']">
<template v-if="!isEmpty(component)"> <template v-if="!isEmpty(component)">
<div> <div>
<h3 :style="mapActivesToItems(index)['h3.categories']"> <h3 :style="mapActivesToItems(index)['h3.categories']">
{{ component.title }} <nuxt-link :to="`/${component.code}`">{{ component.title }}</nuxt-link>
</h3> </h3>
</div> </div>
<div v-html="designObject.styleClasses"></div> <div v-html="designObject.styleClasses"></div>
@@ -3,9 +3,10 @@ import { isEmpty } from "@/utils/lodash";
import { COLLECTION_QUERY_DROP, getValueStringWithKeyAndColon, getInputValue } from "@/utils/parseSQL"; import { COLLECTION_QUERY_DROP, getValueStringWithKeyAndColon, getInputValue } from "@/utils/parseSQL";
const _props = defineProps<{ const _props = defineProps<{
dataResult?: any[]; dataResult?: any;
dataQuery?: string; dataQuery?: string;
label?: string; label?: any;
component?: any;
}>(); }>();
const SETTING_OPTIONS = { const SETTING_OPTIONS = {
@@ -37,7 +38,7 @@ const mapActivesToItems = (index: number) => {
</script> </script>
<template> <template>
<div class="categories-container border-custom" :class="designObject['categories_Class']" :style="designObject['div.categories-container']"> <div :id="`cpn_${_props.component.id}`" class="categories-container border-custom flex-wrap" :class="designObject['categories_Class']" :style="designObject['div.categories-container']">
<div v-for="(component, index) in _dataResult" :key="index" :class="['border-custom', isEmpty(component) ? 'empty' : 'category', designObject['category_Class']]" :style="mapActivesToItems(index)['category']"> <div v-for="(component, index) in _dataResult" :key="index" :class="['border-custom', isEmpty(component) ? 'empty' : 'category', designObject['category_Class']]" :style="mapActivesToItems(index)['category']">
<template v-if="!isEmpty(component)"> <template v-if="!isEmpty(component)">
<div class="category-content"> <div class="category-content">
@@ -45,13 +46,11 @@ const mapActivesToItems = (index: number) => {
<path d="M5.984 2.456V4.184H4.336V5.992H2.4V4.184H0.752V2.456H2.4V0.648H4.336V2.456H5.984Z" fill="black" /> <path d="M5.984 2.456V4.184H4.336V5.992H2.4V4.184H0.752V2.456H2.4V0.648H4.336V2.456H5.984Z" fill="black" />
</svg> </svg>
<h3 <h3 :style="mapActivesToItems(index)['h3.categories']" class="whitespace-nowrap">
:style="mapActivesToItems(index)['h3.categories']" <nuxt-link :to="`/${component.code}`">{{ component.title }}</nuxt-link>
>
{{ component.title }}
</h3> </h3>
</div> </div>
<div v-html="designObject.styleClasses"></div> <div v-if="designObject.styleClasses" v-html="designObject.styleClasses"></div>
</template> </template>
</div> </div>
</div> </div>
@@ -31,5 +31,9 @@ const GET_PROPS = computed(() => {
</script> </script>
<template> <template>
<component :is="definedDynamicComponent[getCurrentComponent]" v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings, content: _props.content }" /> <component
v-if="definedDynamicComponent[getCurrentComponent]"
:is="definedDynamicComponent[getCurrentComponent]"
v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings, content: _props.content }"
/>
</template> </template>
@@ -31,6 +31,7 @@ const GET_PROPS = computed(() => {
<template> <template>
<component <component
v-if="definedDynamicComponent[getCurrentComponent]"
:is="definedDynamicComponent[getCurrentComponent]" :is="definedDynamicComponent[getCurrentComponent]"
v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings }" v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings }"
/> />
@@ -5,11 +5,12 @@ import { isEmpty } from "@/utils/lodash";
import { enumPageComponentTemplates } from "@/definitions/enum"; import { enumPageComponentTemplates } from "@/definitions/enum";
const _props = defineProps<{ const _props = defineProps<{
dataResult?: any[]; dataResult?: any;
dataQuery?: string; dataQuery?: string;
layout?: string; layout?: string;
label?: string; label?: any;
content?: any; content?: any;
component?: any;
}>(); }>();
const SETTING_OPTIONS = { const SETTING_OPTIONS = {
@@ -46,7 +47,7 @@ const mapActivesToItems = (index: number) => {
</script> </script>
<template> <template>
<div class="collection-container border-custom" :class="[LAYOUT_PARSE['div.collection-container_Class'], LAYOUT_PARSE['collection_Class']]" :style="LAYOUT_PARSE['div.collection-container']"> <div :id="`cpn_${_props.component.id}`" class="collection-container border-custom" :class="[LAYOUT_PARSE['div.collection-container_Class'], LAYOUT_PARSE['collection_Class']]" :style="LAYOUT_PARSE['div.collection-container']">
<DynamicComponent <DynamicComponent
v-for="(component, index) in _dataResult" v-for="(component, index) in _dataResult"
:key="index" :key="index"
@@ -5,11 +5,12 @@ import { isEmpty } from "@/utils/lodash";
import { enumPageComponentTemplates } from "@/definitions/enum"; import { enumPageComponentTemplates } from "@/definitions/enum";
const _props = defineProps<{ const _props = defineProps<{
dataResult?: any[]; dataResult?: any;
dataQuery?: string; dataQuery?: string;
layout?: string; layout?: string;
label?: string; label?: any;
content?: any; content?: any;
component?: any;
}>(); }>();
const SETTING_OPTIONS = { const SETTING_OPTIONS = {
@@ -46,7 +47,7 @@ const mapActivesToItems = (index: number) => {
</script> </script>
<template> <template>
<div class="collection-container border-custom overflow-hidden" :class="[LAYOUT_PARSE['div.collection-container_Class'], LAYOUT_PARSE['collection_Class']]" :style="LAYOUT_PARSE['div.collection-container']"> <div :id="`cpn_${_props.component.id}`" class="collection-container border-custom overflow-hidden" :class="[LAYOUT_PARSE['div.collection-container_Class'], LAYOUT_PARSE['collection_Class']]" :style="LAYOUT_PARSE['div.collection-container']">
<DynamicComponent <DynamicComponent
v-for="(component, index) in _dataResult" v-for="(component, index) in _dataResult"
:key="index" :key="index"
@@ -0,0 +1,247 @@
<script setup lang="ts">
import DynamicComponent from "~/components/dynamic-page/page-component/templates/index.vue";
import { COLLECTION_QUERY_DROP, getValueStringWithKeyAndColon, getInputValue } from "@/utils/parseSQL";
import { isEmpty } from "@/utils/lodash";
import { enumPageComponentTemplates } from "@/definitions/enum";
const emit = defineEmits(["dropComponent", "dropData", "selectComponent"]);
// const store = reactive({
// page: useCmsPageStore(),
// section: usePageSectionStore(),
// });
// const { currentScreenMode } = storeToRefs(useCmsPageStore());
const _props = defineProps<{
dataResult?: any[];
dataQuery?: string;
layout?: string;
label?: string;
content?: any;
component?: any;
}>();
const SETTING_OPTIONS = {
MAX_ELEMENT: 9,
TEMPLATE: "TYPE:Card",
LAYOUT: "TYPE:Card_VideoHightLight",
};
const COMPONENT = {
taxonomy: enumPageComponentTemplates.ARTICLE,
};
const LAYOUT_PARSE = computed(() => {
return _props.label ? getInputValue(_props.label, "OBJECT") : {};
});
const _dataResult = computed(() => {
let _components = Array(Number(LAYOUT_PARSE.value.MAX) || SETTING_OPTIONS.MAX_ELEMENT).fill(null);
const result = getInputValue(_props.dataResult, "ARRAY");
result &&
result.length > 0 &&
_components.map((_: any, index: any) => {
_components[index] = result[index] || null;
});
return _components;
});
async function dropData(data: any) {
if (data) {
const { dataResult, dataType } = data;
const checkDataResult = getInputValue(_props.dataResult, "ARRAY");
const result = _props.dataResult ? [...checkDataResult, { ...dataResult }] : [{ ...dataResult }];
const getDataQuery = _props.dataQuery ? COLLECTION_QUERY_DROP(dataType, getValueStringWithKeyAndColon(_props.dataQuery) + "," + dataResult.id) : COLLECTION_QUERY_DROP(dataType, dataResult.id);
emit("dropData", {
dataResult: result,
dataType,
dataQuery: getDataQuery,
});
}
}
const selectComponent = () => {
emit("selectComponent");
};
const mapActivesToItems = (index: number) => {
if (LAYOUT_PARSE.value && LAYOUT_PARSE.value.listCss) {
return LAYOUT_PARSE.value.listCss[index] || {};
}
return {};
};
</script>
<template>
<div
:id="`cpn_${_props.component?.id}`"
class="collection-video-container border-custom"
:class="[LAYOUT_PARSE['div.collection-container_Class'], LAYOUT_PARSE['collection_Class']]"
@click="selectComponent"
:style="LAYOUT_PARSE['div.collection-container']"
>
<div v-for="(component, index) in _dataResult" :key="index">
<div class="wrap">
<!-- {{ index }} -->
<DynamicComponent
:settings="{
template: SETTING_OPTIONS.TEMPLATE,
layout: SETTING_OPTIONS.LAYOUT,
label: mapActivesToItems(Number(index)),
dataResult: !isEmpty(component) ? { ...component } : null,
}"
:component="COMPONENT"
@drop-data="dropData"
/>
</div>
</div>
</div>
<div v-html="LAYOUT_PARSE.styleClasses" style="display: none" v-if="LAYOUT_PARSE.styles"></div>
</template>
<style lang="scss">
.collection-video-container {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
grid-template-rows: repeat(3, minmax(0, 1fr));
gap: 20px;
& > div {
background-color: #eee;
position: relative;
width: 100%;
padding-top: calc((9 / 16) * 100%);
& > .wrap {
position: absolute;
top: 0;
width: 100%;
height: 100%;
& > .basic-article {
height: 100%;
& > .article_video {
height: 100%;
& > .article_video_thumb {
height: 100%;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
justify-content: flex-end;
overflow: hidden;
& > .article_video_content {
padding: 0 24px 8px 24px;
display: flex;
flex-direction: column;
align-items: center;
& > span {
margin-bottom: 10px;
}
& > .article-title {
text-align: center;
font-size: 18px;
font-weight: 700;
line-height: 130%;
margin: 0;
}
& > .article-intro {
display: none;
}
}
}
& > .empty-box {
width: 100%;
height: 100%;
box-sizing: border-box;
margin: 0px;
& > div {
width: 100%;
height: 100%;
}
}
}
}
}
&:nth-child(1) {
grid-column: span 2 / span 2;
grid-row: span 2 / span 2;
order: 6;
background-color: aqua;
& > .wrap {
& > .basic-article {
& > .article_video {
& > .article_video_thumb {
& > .article_video_content {
padding: 0 120px 24px 120px;
}
}
}
}
}
}
&:nth-child(2) {
order: 2;
background-color: red;
}
&:nth-child(3) {
order: 3;
background-color: green;
}
&:nth-child(4) {
order: 4;
background-color: orange;
}
&:nth-child(5) {
order: 5;
background-color: orangered;
}
&:nth-child(6) {
order: 6;
background-color: brown;
}
&:nth-child(7) {
order: 7;
background-color: blueviolet;
}
&:nth-child(8) {
order: 8;
background-color: darkred;
}
&:nth-child(9) {
order: 9;
background-color: darkcyan;
}
}
// &.column-phone {
// grid-template-columns: repeat(1, minmax(0, 1fr)) !important;
// }
// &.column {
// grid-template-columns: repeat(1, minmax(0, 1fr));
// }
// &.row {
// grid-template-rows: auto;
// grid-auto-flow: column;
// }
// &.border-pri {
// gap: 5px;
// }
// &.border-custom {
// border-color: #e5e5e5 !important;
// }
// .empty {
// min-height: 100px;
// border-radius: 6px;
// background: #409eff;
// }
// &.noData {
// border-radius: 6px;
// }
}
</style>
@@ -1,2 +1,3 @@
export { default as Default_Collection } from './Default.vue' export { default as Default_Collection } from './Default.vue'
export { default as Audio_Collection } from './Audio.vue' export { default as Audio_Collection } from './Audio.vue'
export { default as Video_Collection } from './Video.vue'
@@ -1,6 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import { enumPageComponentTemplate, enumPageComponentKey, enumPageComponentLayouts } from "@/definitions/enum"; import { enumPageComponentTemplate, enumPageComponentKey, enumPageComponentLayouts } from "@/definitions/enum";
import { Default_Collection, Audio_Collection } from "./index"; import { Default_Collection, Audio_Collection, Video_Collection } from "./index";
const _props = defineProps<{ const _props = defineProps<{
settings: any; settings: any;
@@ -10,6 +10,7 @@ const _props = defineProps<{
const definedDynamicComponent: Record<string, any> = { const definedDynamicComponent: Record<string, any> = {
[enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.COLLECTION]["ARTICLE"]}`]["ARTICLE_COLLECTION_DEFAULT"]]: Default_Collection, [enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.COLLECTION]["ARTICLE"]}`]["ARTICLE_COLLECTION_DEFAULT"]]: Default_Collection,
[enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.COLLECTION]["ARTICLE"]}`]["ARTICLE_COLLECTION_AUDIO"]]: Audio_Collection, [enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.COLLECTION]["ARTICLE"]}`]["ARTICLE_COLLECTION_AUDIO"]]: Audio_Collection,
[enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.COLLECTION]["ARTICLE"]}`]["ARTICLE_COLLECTION_VIDEO"]]: Video_Collection,
}; };
const getCurrentComponent = computed(() => _props.settings.layout); const getCurrentComponent = computed(() => _props.settings.layout);
@@ -30,5 +31,9 @@ const GET_PROPS = computed(() => {
</script> </script>
<template> <template>
<component :is="definedDynamicComponent[getCurrentComponent]" v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings, content: _props.content }" /> <component
v-if="definedDynamicComponent[getCurrentComponent]"
:is="definedDynamicComponent[getCurrentComponent]"
v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings, content: _props.content }"
/>
</template> </template>
@@ -0,0 +1 @@
export { default as Misses_Default } from './misses/Default.vue'
@@ -0,0 +1,37 @@
<script lang="ts" setup>
import { enumPageComponentTemplate, enumPageComponentKey, enumPageComponentLayouts } from "@/definitions/enum";
import { Misses_Default } from "./index";
const _props = defineProps<{
settings: any;
component?: any;
content?: any;
}>();
const definedDynamicComponent: Record<string, any> = {
[enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.COLLECTION]["CATEGORY"]}`]["MISSES_COLLECTION_DEFAULT"]]: Misses_Default,
};
const getCurrentComponent = computed(() => _props.settings.layout);
const GET_PROPS = computed(() => {
return () => {
let props: any = {};
if (_props.settings) {
for (const [key, value] of Object.entries(_props.settings)) {
props = {
...props,
[key]: value,
};
}
return props;
}
};
});
</script>
<template>
<component
v-if="definedDynamicComponent[getCurrentComponent]"
:is="definedDynamicComponent[getCurrentComponent]"
v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings, content: _props.content }"
/>
</template>
@@ -0,0 +1,195 @@
<script setup lang="ts">
import DynamicComponent from "~/components/dynamic-page/page-component/templates/index.vue";
import { COLLECTION_QUERY_DROP, getValueStringWithKeyAndColon, getInputValue } from "@/utils/parseSQL";
import { isEmpty } from "@/utils/lodash";
import { enumPageComponentTemplates } from "@/definitions/enum";
const emit = defineEmits(["dropComponent", "dropData", "selectComponent"]);
const _props = defineProps<{
dataResult?: any;
dataQuery?: string;
layout?: string;
label?: string;
content?: any;
component?: any;
}>();
const SETTING_OPTIONS = {
MAX_ELEMENT: 6,
TEMPLATE: "TYPE:Card",
LAYOUT: "TYPE:Card_MissHightLight",
};
const COMPONENT = {
taxonomy: enumPageComponentTemplates.ARTICLE,
};
const LAYOUT_PARSE = computed(() => {
// console.log(_props.label);
return _props.label ? getInputValue(_props.label, "OBJECT") : {};
});
const _dataResult = computed(() => {
let _components = Array(Number(LAYOUT_PARSE.value.MAX) || SETTING_OPTIONS.MAX_ELEMENT).fill(null);
const result = getInputValue(_props.dataResult, "ARRAY");
result &&
result.length > 0 &&
_components.map((_: any, index: any) => {
_components[index] = result[index] || null;
});
return _components;
});
async function dropData(data: any) {
if (data) {
const { dataResult, dataType } = data;
const checkDataResult = getInputValue(_props.dataResult, "ARRAY");
const result = _props.dataResult ? [...checkDataResult, { ...dataResult }] : [{ ...dataResult }];
const getDataQuery = _props.dataQuery ? COLLECTION_QUERY_DROP(dataType, getValueStringWithKeyAndColon(_props.dataQuery) + "," + dataResult.id) : COLLECTION_QUERY_DROP(dataType, dataResult.id);
emit("dropData", {
dataResult: result,
dataType,
dataQuery: getDataQuery,
});
}
}
const selectComponent = () => {
emit("selectComponent");
};
const mapActivesToItems = (index: number) => {
if (LAYOUT_PARSE.value && LAYOUT_PARSE.value.listCss) {
return LAYOUT_PARSE.value.listCss[index] || {};
}
return {};
};
</script>
<template>
<section :id="`cpn_${_props.component.id}`" class="gallery" :class="[LAYOUT_PARSE['div.collection-container_Class'], LAYOUT_PARSE['collection_Class']]" @click="selectComponent" :style="LAYOUT_PARSE['div.collection-container']">
<div class="wrap" v-for="(component, index) in _dataResult" :key="index">
<DynamicComponent
class="box"
:settings="{
template: SETTING_OPTIONS.TEMPLATE,
layout: SETTING_OPTIONS.LAYOUT,
label: { ...mapActivesToItems(Number(index)) },
dataResult: !isEmpty(component) ? { ...component } : null,
}"
:component="COMPONENT"
@drop-data="dropData"
/>
</div>
</section>
<!-- <conllection
class="collection-container border-custom overflow-hidden"
:class="[LAYOUT_PARSE['div.collection-container_Class'], LAYOUT_PARSE['collection_Class']]"
@click="selectComponent"
:style="LAYOUT_PARSE['div.collection-container']"
>
<DynamicComponent
v-for="(component, index) in _dataResult"
:key="index"
:class="[index === 0 || index === 1 ? 'row-span-3' : index === 2 || index === 3 ? 'row-span-2' : 'row-span-1']"
:settings="{
template: SETTING_OPTIONS.TEMPLATE,
layout: SETTING_OPTIONS.LAYOUT,
label: { ...mapActivesToItems(Number(index)) },
dataResult: !isEmpty(component) ? { ...component } : null,
}"
:component="COMPONENT"
@drop-data="dropData"
/>
</conllection> -->
<div v-if="LAYOUT_PARSE.styleClasses" v-html="LAYOUT_PARSE.styleClasses" style="display: none"></div>
</template>
<style lang="scss" scoped>
.gallery {
column-count: 4;
-webkit-column-count: 4;
-moz-column-count: 4;
gap: 16px;
@media (min-width: 640px) and (max-width: 1024px) {
column-count: 2;
-webkit-column-count: 2;
-moz-column-count: 2;
}
@media (max-width: 640px) {
column-count: 1;
-webkit-column-count: 1;
-moz-column-count: 1;
}
.wrap {
position: relative;
width: 100%;
&:nth-child(1),
&:nth-child(2) {
padding-top: 615px;
}
&:nth-child(3),
&:nth-child(5) {
padding-top: 358px;
}
&:nth-child(4),
&:nth-child(6) {
margin-top: 16px;
padding-top: 241px;
}
& > .box {
position: absolute;
top: 0;
width: 100%;
height: 100%;
padding-bottom: 30px;
// margin: 10px 0;
}
}
.row-span-3 {
// grid-row: span 3 / span 3;
// height: 585px;
// margin: 10px 0;
// &:nth-child(1) {
// background-color: red;
// }
// &:nth-child(2) {
// background-color: yellow;
// }
}
.row-span-2 {
// margin: 10px 0;
// grid-row: span 2 / span 2;
// height: 328px;
// background-color: aqua;
// .basic-article {
// }
}
.row-span-1 {
// grid-row: span 1 / span 1;
// height: 211px;
// background-color: green;
// .basic-article {
// }
}
}
.image img {
height: auto;
width: 100%;
}
.collection-container {
// display: grid;
// grid-template-columns: repeat(4, 1fr);
// grid-template-rows: repeat(3, 1fr);
gap: 20px;
column-count: 4;
}
</style>
@@ -1 +1,2 @@
export { default as Article_Collection } from './articles/index.vue' export { default as Article_Collection } from './articles/index.vue'
export { default as Category_Collection } from './categories/index.vue'
@@ -1,6 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import { enumPageComponentTemplate, enumPageComponentKey, enumPageComponentLayouts } from "@/definitions/enum"; import { enumPageComponentTemplate, enumPageComponentKey, enumPageComponentLayouts } from "@/definitions/enum";
import { Article_Collection } from "./index"; import { Article_Collection, Category_Collection } from "./index";
const _props = defineProps<{ const _props = defineProps<{
settings: any; settings: any;
@@ -9,6 +9,7 @@ const _props = defineProps<{
}>(); }>();
const definedDynamicComponent: Record<string, any> = { const definedDynamicComponent: Record<string, any> = {
[enumPageComponentTemplate[enumPageComponentKey.COLLECTION]["ARTICLE"]]: Article_Collection, [enumPageComponentTemplate[enumPageComponentKey.COLLECTION]["ARTICLE"]]: Article_Collection,
[enumPageComponentTemplate[enumPageComponentKey.COLLECTION]["CATEGORY"]]: Category_Collection,
}; };
const getCurrentComponent = computed(() => _props.settings.template); const getCurrentComponent = computed(() => _props.settings.template);
@@ -30,5 +31,9 @@ const GET_PROPS = computed(() => {
</script> </script>
<template> <template>
<component :is="definedDynamicComponent[getCurrentComponent]" v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings, content: _props.content }" /> <component
v-if="definedDynamicComponent[getCurrentComponent]"
:is="definedDynamicComponent[getCurrentComponent]"
v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings, content: _props.content }"
/>
</template> </template>
@@ -36,5 +36,9 @@ const GET_PROPS = computed(() => {
</script> </script>
<template> <template>
<component :is="definedDynamicComponent[getCurrentComponent]" v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings, content: _props.content }" /> <component
v-if="definedDynamicComponent[getCurrentComponent]"
:is="definedDynamicComponent[getCurrentComponent]"
v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings, content: _props.content }"
/>
</template> </template>
@@ -1,12 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { isEmpty } from "@/utils/lodash"; import { isEmpty } from "@/utils/lodash";
import { nanoid } from "nanoid" import { nanoid } from "nanoid";
import DynamicComponent from "~/components/dynamic-page/page-component/templates/index.vue"; import DynamicComponent from "~/components/dynamic-page/page-component/templates/index.vue";
import RecusiveNavItem from "@/components/dynamic-page/page-component/templates/navigations/components/RecusiveNavItem.vue"; import RecusiveNavItem from "@/components/dynamic-page/page-component/templates/navigations/components/RecusiveNavItem.vue";
import { buildTree } from "@/utils/recusive"; import { buildTree } from "@/utils/recusive";
const _props = defineProps<{ const _props = defineProps<{
content?: any[]; content?: any;
component?: any; component?: any;
}>(); }>();
</script> </script>
@@ -15,16 +15,17 @@ const _props = defineProps<{
<div class="px-4 mt-4"> <div class="px-4 mt-4">
<div class="nav-container"> <div class="nav-container">
<template v-if="_props.content"> <template v-if="_props.content">
<div v-for="item, index in buildTree(_props.content)" :key="index" class="nav-items-box"> <div v-for="(item, index) in buildTree(_props.content)" :key="index" class="nav-items-box">
<div class="submenu-container"> <div class="submenu-container">
<h4 class="" >{{ item.title }}</h4> <nuxt-link :to="`/${item.slug}`"
><h4 class="font-raleway">{{ item.title }}</h4></nuxt-link
>
<div class="ml-2"> <div class="ml-2">
<h5 <nuxt-link v-for="(_item, _index) in item.childs ? item.childs : []" :key="_index" :to="`/${_item.slug}`"
v-for="_item, _index in item.childs ? item.childs : []" ><h5 class="font-raleway">
:key="_index" {{ _item.title }}
</h5></nuxt-link
> >
{{ _item.title }}
</h5>
</div> </div>
</div> </div>
</div> </div>
@@ -32,6 +32,7 @@ const GET_PROPS = computed(() => {
<template> <template>
<component <component
v-if="definedDynamicComponent[getCurrentComponent]"
:is="definedDynamicComponent[getCurrentComponent]" :is="definedDynamicComponent[getCurrentComponent]"
v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings, content: _props.content }" v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings, content: _props.content }"
/> />
@@ -19,7 +19,9 @@ const setGlobalState = (id: any) => {
<div v-for="(record) in props.records" :key="record.id" class="navigation-branch cursor-pointer"> <div v-for="(record) in props.records" :key="record.id" class="navigation-branch cursor-pointer">
<template v-if="record && record.childs && record.childs.length > 0 && record.typeChild === enumPageComponentStaticChild.DEFAULT"> <template v-if="record && record.childs && record.childs.length > 0 && record.typeChild === enumPageComponentStaticChild.DEFAULT">
<div class="navigation-submenu"> <div class="navigation-submenu">
<div class="navigation_title ">{{ record?.title }}</div> <div class="navigation_title">
<nuxt-link :to="`/${record?.slug}`" class="!font-arial !font-400">{{ record?.title }}</nuxt-link>
</div>
<div class="navigation-item submenu-container dropdown-container"> <div class="navigation-item submenu-container dropdown-container">
<RecusiveNavItem :records="record.childs" /> <RecusiveNavItem :records="record.childs" />
</div> </div>
@@ -28,7 +30,9 @@ const setGlobalState = (id: any) => {
<template v-else-if="record.typeChild === enumPageComponentStaticChild.LAYOUT"> <template v-else-if="record.typeChild === enumPageComponentStaticChild.LAYOUT">
<div class="navigation-submenu"> <div class="navigation-submenu">
<div class="position-relative ps-3"> <div class="position-relative ps-3">
<div class="navigation_title ">{{ record?.title }}</div> <div class="navigation_title ">
<nuxt-link :to="`/${record?.slug}`" class="!font-arial !font-400">{{ record?.title }}</nuxt-link>
</div>
</div> </div>
<div class="full-layout dropdown-container"> <div class="full-layout dropdown-container">
<template v-if="record.data"> <template v-if="record.data">
@@ -40,7 +44,9 @@ const setGlobalState = (id: any) => {
</div> </div>
</template> </template>
<template v-else> <template v-else>
<div class="navigation_title navigation-item" >{{ record?.title }}</div> <div class="navigation_title navigation-item" >
<nuxt-link :to="`/${record?.slug}`" class="!font-arial !font-400">{{ record?.title }}</nuxt-link>
</div>
</template> </template>
</div> </div>
</div> </div>
@@ -4,7 +4,7 @@ import DynamicComponent from "~/components/dynamic-page/page-component/templates
import { getInputValue } from "@/utils/parseSQL"; import { getInputValue } from "@/utils/parseSQL";
const _props = defineProps<{ const _props = defineProps<{
dataResult?: any[]; dataResult?: any;
dataQuery?: string; dataQuery?: string;
component?: any; component?: any;
}>(); }>();
@@ -32,6 +32,7 @@ const GET_PROPS = computed(() => {
<template> <template>
<component <component
v-if="definedDynamicComponent[getCurrentComponent]"
:is="definedDynamicComponent[getCurrentComponent]" :is="definedDynamicComponent[getCurrentComponent]"
v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings, content: _props.content }" v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings, content: _props.content }"
/> />
@@ -33,7 +33,8 @@ const GET_PROPS = computed(() => {
</script> </script>
<template> <template>
<component <component
v-if="definedDynamicComponent[getCurrentComponent]"
:is="definedDynamicComponent[getCurrentComponent]" :is="definedDynamicComponent[getCurrentComponent]"
v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings, content: _props.content }" v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings, content: _props.content }"
/> />
@@ -3,7 +3,7 @@ import { buildTree } from "@/utils/recusive";
import RecusiveNavItem from "@/components/dynamic-page/page-component/templates/navigations/components/RecusiveNavItem.vue"; import RecusiveNavItem from "@/components/dynamic-page/page-component/templates/navigations/components/RecusiveNavItem.vue";
const _props = defineProps<{ const _props = defineProps<{
content?: any[]; content?: any;
component?: any; component?: any;
}>(); }>();
@@ -32,6 +32,7 @@ const GET_PROPS = computed(() => {
<template> <template>
<component <component
v-if="definedDynamicComponent[getCurrentComponent]"
:is="definedDynamicComponent[getCurrentComponent]" :is="definedDynamicComponent[getCurrentComponent]"
v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings, content: _props.content }" v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings, content: _props.content }"
/> />
@@ -1,4 +1,4 @@
// export { default as Weather_Day } from './weathers/WeatherDay.vue' // export { default as Weather_Day } from './weathers/WeatherDay.vue'
// export { default as Comment_Default } from './comments/Default.vue' // export { default as Comment_Default } from './comments/Default.vue'
export { default as Other_Weather } from './weathers/index.vue' export { default as Other_Weather } from './weathers/index.vue'
export { default as Other_Secutities } from './securities/index.vue' export { default as Other_Stock } from './stocks/index.vue'
@@ -1,6 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import { enumPageComponentTemplate, enumPageComponentKey, enumPageComponentLayouts } from "@/definitions/enum"; import { enumPageComponentTemplate, enumPageComponentKey, enumPageComponentLayouts } from "@/definitions/enum";
import { Other_Weather, Other_Secutities } from "./index"; import { Other_Weather, Other_Stock } from "./index";
const _props = defineProps<{ const _props = defineProps<{
settings: any; settings: any;
@@ -9,7 +9,7 @@ const _props = defineProps<{
}>(); }>();
const definedDynamicComponent: Record<string, any> = { const definedDynamicComponent: Record<string, any> = {
[enumPageComponentTemplate[enumPageComponentKey.OTHER]["WEATHER"]]: Other_Weather, [enumPageComponentTemplate[enumPageComponentKey.OTHER]["WEATHER"]]: Other_Weather,
[enumPageComponentTemplate[enumPageComponentKey.OTHER]["SECURITIES"]]: Other_Secutities, [enumPageComponentTemplate[enumPageComponentKey.OTHER]['STOCK']]: Other_Stock,
// [enumPageComponentTemplate[enumPageComponentKey.ARTICLE]["ARTICLE_DETAIL"]]: Article_Detail, // [enumPageComponentTemplate[enumPageComponentKey.ARTICLE]["ARTICLE_DETAIL"]]: Article_Detail,
}; };
const getCurrentComponent = computed(() => _props.settings.template); const getCurrentComponent = computed(() => _props.settings.template);
@@ -30,5 +30,9 @@ const GET_PROPS = computed(() => {
</script> </script>
<template> <template>
<component :is="definedDynamicComponent[getCurrentComponent]" v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings }" /> <component
v-if="definedDynamicComponent[getCurrentComponent]"
:is="definedDynamicComponent[getCurrentComponent]"
v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings }"
/>
</template> </template>
@@ -1,15 +0,0 @@
<script setup lang="ts"></script>
<template>
<div>chứng khoán</div>
</template>
<style lang="scss" scoped>
div {
width: 100%;
height: 200px;
background-color: #ededed;
font-size: 24px;
display: flex;
align-items: center;
justify-content: center;
}
</style>
@@ -1 +0,0 @@
export { default as Securities_Default } from './Securities.vue'
@@ -0,0 +1,32 @@
<script setup lang="ts">
import { nanoid } from 'nanoid';
import JSWidget from '@/components/widget/JSwidget.vue';
const widgetOptions = {
"locale": "vi",
"width": "334px",
"height": "250px",
"price_line_color": "#71BDDF",
"grid_color": "#999999",
"label_color": "#999999",
}
</script>
<template>
<JSWidget
:CONTAINER_ID="nanoid(10)"
:SCRIPT_ID="nanoid(10)"
SCRIPT_SRC="https://www.fireant.vn/Scripts/web/widgets.js"
:options="widgetOptions"
:inside="false"
widgetKey="FireAnt"
/>
</template>
<style lang="scss" scoped>
div {
width: 100%;
font-size: 24px;
display: flex;
align-items: center;
justify-content: center;
}
</style>
@@ -0,0 +1,56 @@
<script setup lang="ts">
import { nanoid } from 'nanoid';
import JSWidget from '@/components/widget/JSwidget.vue';
const widgetOptions = {
"symbols": [
{
"proName": "FOREXCOM:SPXUSD",
"title": "S&P 500 Index"
},
{
"proName": "FOREXCOM:NSXUSD",
"title": "US 100 Cash CFD"
},
{
"proName": "FX_IDC:EURUSD",
"title": "EUR to USD"
},
{
"proName": "BITSTAMP:BTCUSD",
"title": "Bitcoin"
},
{
"proName": "BITSTAMP:ETHUSD",
"title": "Ethereum"
}
],
"isTransparent": false,
"showSymbolLogo": true,
"colorTheme": "dark",
"locale": "en"
}
</script>
<template>
<div>
<JSWidget
:CONTAINER_ID="nanoid(10)"
:SCRIPT_ID="nanoid(10)"
SCRIPT_SRC="https://s3.tradingview.com/external-embedding/embed-widget-tickers.js"
:options="widgetOptions"
:inside="true"
widgetKey="TradingView"
/>
</div>
</template>
<style lang="scss" scoped>
div {
width: 100%;
font-size: 24px;
display: flex;
align-items: center;
justify-content: center;
}
</style>
@@ -0,0 +1,2 @@
export { default as Stock_Default } from './334x641.vue'
export { default as Stock_FullSize } from './Full.vue'
@@ -1,15 +1,15 @@
<script lang="ts" setup> <script lang="ts" setup>
import { enumPageComponentTemplate, enumPageComponentKey, enumPageComponentLayouts } from "@/definitions/enum"; import { enumPageComponentTemplate, enumPageComponentKey, enumPageComponentLayouts } from "@/definitions/enum";
import { Stock_Default, Stock_FullSize } from "./index";
// import { Article_Card, Article_Detail_Video, Article_Detail_Podcast, Article_Detail_General, Article_Detail_Image } from "./index";
import { Securities_Default } from "./index";
const _props = defineProps<{ const _props = defineProps<{
settings: any; settings: any;
component?: any; component?: any;
content?: any; content?: any;
}>(); }>();
const definedDynamicComponent: Record<string, any> = { const definedDynamicComponent: Record<string, any> = {
[enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.OTHER]["SECURITIES"]]["SECURITIES_DEFAULT"]]: Securities_Default, [enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.OTHER]['STOCK']]['STOCK_DEFAULT']]: Stock_Default,
[enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.OTHER]["STOCK"]]["STOCK_FULLSIZE"]]: Stock_FullSize,
}; };
const getCurrentComponent = computed(() => `${_props.settings.layout}`); const getCurrentComponent = computed(() => `${_props.settings.layout}`);
@@ -30,5 +30,9 @@ const GET_PROPS = computed(() => {
</script> </script>
<template> <template>
<component :is="definedDynamicComponent[getCurrentComponent]" v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings }" /> <component
</template> v-if="definedDynamicComponent[getCurrentComponent]"
:is="definedDynamicComponent[getCurrentComponent]"
v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings }"
/>
</template>
@@ -32,6 +32,7 @@ const GET_PROPS = computed(() => {
<template> <template>
<component <component
v-if="definedDynamicComponent[getCurrentComponent]"
:is="definedDynamicComponent[getCurrentComponent]" :is="definedDynamicComponent[getCurrentComponent]"
v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings, content: _props.content }" v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings, content: _props.content }"
/> />
@@ -1,14 +1,13 @@
<script setup lang="ts"> <script setup lang="ts">
import { isEmpty } from "@/utils/lodash";
import DynamicComponent from "~/components/dynamic-page/page-component/templates/index.vue"; import DynamicComponent from "~/components/dynamic-page/page-component/templates/index.vue";
import { COLLECTION_PAGING_QUERY_DROP, getInputValue } from "@/utils/parseSQL"; import { getInputValue } from "@/utils/parseSQL";
import { enumPageComponentTemplates } from "@/definitions/enum";
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
import { useScroll } from '@vueuse/core';
const store = reactive({ const store = reactive({
component: usePageComponentStore(), component: useDynamicPageStore(),
}); });
const _props = defineProps<{ const _props = defineProps<{
dataResult?: any[]; dataResult?: any[];
dataQuery?: string; dataQuery?: string;
@@ -18,8 +17,12 @@ const _props = defineProps<{
const SETTING_OPTIONS = { const SETTING_OPTIONS = {
MAX_ELEMENT: 5, MAX_ELEMENT: 5,
TEMPLATE: "Article", TEMPLATE: "TYPE:Card",
LAYOUT: "TYPE:Card", LAYOUT: "TYPE:Card_Default",
};
const COMPONENT = {
taxonomy: enumPageComponentTemplates.ARTICLE,
}; };
const page = ref(1); const page = ref(1);
@@ -60,14 +63,11 @@ const handleRouteChange = async (query: any) => {
const param = query[`cpn_${_props.component?.id}`]; const param = query[`cpn_${_props.component?.id}`];
if (param) { if (param) {
const [_, value] = param.split(":") || []; const [_, value] = param.split(":") || [];
page.value = value; page.value = Number(value);
await loadPage(value); await loadPage(value);
} }
}; };
onBeforeMount(() => {
if (route.query[`cpn_${_props.component?.id}`]) handleRouteChange(route.query);
});
const loadPage = async (page: number) => { const loadPage = async (page: number) => {
let newDataQuery = ""; let newDataQuery = "";
@@ -79,14 +79,17 @@ const loadPage = async (page: number) => {
} else { } else {
newDataQuery = _props.component?.settings?.dataQuery + ` Page[${page}]`; newDataQuery = _props.component?.settings?.dataQuery + ` Page[${page}]`;
} }
const res = await store.component.getOverviewPageComponentById(Number(_props.component?.id), newDataQuery); const {item} = await store.component.getOverviewPageComponentById(Number(_props.component?.id), newDataQuery);
const data = getInputValue(res?.settings?.dataResult, "OBJECT"); const data = getInputValue(item?.settings?.dataResult, "OBJECT");
if (Object.keys(data).length > 0) { if (Object.keys(data).length > 0) {
totals.value = data.Total; totals.value = data.Total;
listArticlePaging.value = data?.Data || []; listArticlePaging.value = data?.Data || [];
} }
}; };
if (route.query[`cpn_${_props.component?.id}`]) handleRouteChange(route.query);
const handleNextPrev = (type: "+" | "-") => { const handleNextPrev = (type: "+" | "-") => {
if (listArticleByCategory.value?.length > 0) { if (listArticleByCategory.value?.length > 0) {
if (type === "+") { if (type === "+") {
@@ -104,54 +107,36 @@ const mapActivesToItems = (index: number) => {
} }
return {}; return {};
}; };
</script> </script>
<template> <template>
<section> <section :id="`cpn_[${_props.component.id}]`" v-if="listArticleByCategory?.length > 0">
<div class="section-container" :class="[listArticleByCategory && listArticleByCategory?.length > 0 ? '' : 'noData']"> <div class="section-container">
<div class="section-layout" :style="designObject['div.section']"> <div class="section-layout" :style="designObject['div.section']">
<template v-if="listArticleByCategory?.length > 0"> <template v-for="(component, index) in listArticlePaging?.length > 0 ? listArticlePaging : listArticleByCategory" :key="index">
<template v-for="(component, index) in listArticlePaging?.length > 0 ? listArticlePaging : listArticleByCategory"> <DynamicComponent
<DynamicComponent :settings="{
:key="index" template: SETTING_OPTIONS.TEMPLATE,
v-if="!isEmpty(component)" layout: SETTING_OPTIONS.LAYOUT,
:settings="{ dataResult: { ...component },
template: SETTING_OPTIONS.TEMPLATE, label: mapActivesToItems(Number(index)),
layout: SETTING_OPTIONS.LAYOUT, }"
dataResult: { ...component }, :component="COMPONENT"
label: mapActivesToItems(Number(index)), />
}"
/>
</template>
</template>
<template v-else>
<div class="empty"><h6 class="px-2 text-center">Nội dung danh sách bài viết của danh mục sẽ đây</h6></div>
</template> </template>
<div class="button-page flex"> <div class="button-page flex">
<a class="btn-page prev-page" @click.stop="() => handleNextPrev('-')" v-if="page > 1"> <a :href="`#cpn_[${_props.component.id}]`" class="btn-page prev-page" @click.stop="() => handleNextPrev('-')" v-if="page > 1">
<i class="el-icon"> <Icon name="ooui:previous-ltr"></Icon>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
<path
fill="currentColor"
d="M609.408 149.376 277.76 489.6a32 32 0 0 0 0 44.672l331.648 340.352a29.12 29.12 0 0 0 41.728 0 30.592 30.592 0 0 0 0-42.752L339.264 511.936l311.872-319.872a30.592 30.592 0 0 0 0-42.688 29.12 29.12 0 0 0-41.728 0z"
></path>
</svg>
</i>
</a> </a>
<a v-if="listArticleByCategory?.length > 0" :class="['btn-page', page === index + 1 && 'active']" @click.stop="() => select(index + 1)" v-for="(_, index) in Math.ceil(totals / limit)">{{ index + 1 }}</a> <a :href="`#cpn_[${_props.component.id}]`" :class="['btn-page', page === index + 1 && 'active']" @click.stop="() => select(index + 1)" v-for="(_, index) in Math.ceil(totals / limit)" :key="index">{{ index + 1 }}</a>
<a class="btn-page next-page" @click.stop="() => handleNextPrev('+')" v-if="page < Math.ceil(totals / limit)"> <a :href="`#cpn_[${_props.component.id}]`" class="btn-page next-page" @click.stop="() => handleNextPrev('+')" v-if="page < Math.ceil(totals / limit)">
<i class="el-icon"> <Icon name="ooui:previous-rtl"></Icon>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
<path
fill="currentColor"
d="M340.864 149.312a30.592 30.592 0 0 0 0 42.752L652.736 512 340.864 831.872a30.592 30.592 0 0 0 0 42.752 29.12 29.12 0 0 0 41.728 0L714.24 534.336a32 32 0 0 0 0-44.672L382.592 149.376a29.12 29.12 0 0 0-41.728 0z"
></path>
</svg>
</i>
</a> </a>
</div> </div>
</div> </div>
</div> </div>
<div v-html="designObject.styleClasses" style="display: none" v-if="designObject.styles"></div>
</section> </section>
</template> </template>
@@ -161,35 +146,9 @@ const mapActivesToItems = (index: number) => {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
/* gap: 10px; */ /* gap: 10px; */
overflow-x: scroll;
&.border-custom { &.border-custom {
border-color: #e5e5e5 !important; border-color: #e5e5e5 !important;
} }
&.borderLeft {
border-left: 1px solid;
}
&.borderRight {
border-right: 1px solid;
}
&.borderTop {
border-top: 1px solid;
}
&.borderBottom {
border-bottom: 1px solid;
}
}
.empty {
width: 100%;
height: 100%;
min-height: 50px;
background-color: #409eff;
display: flex;
white-space: normal;
justify-content: center;
align-items: center;
h6 {
color: #fff;
}
} }
.basic-article { .basic-article {
&.article { &.article {
@@ -198,9 +157,6 @@ const mapActivesToItems = (index: number) => {
pointer-events: none; pointer-events: none;
} }
} }
&.noData {
border-radius: 6px;
}
.flex { .flex {
display: flex; display: flex;
@@ -218,17 +174,21 @@ const mapActivesToItems = (index: number) => {
.btn-page { .btn-page {
width: 40px; width: 40px;
height: 40px; height: 40px;
padding: 9px 16px;
text-align: center; text-align: center;
line-height: 36px; line-height: 36px;
border: 1px solid #409eff; border-radius: 4px;
border-radius: 3px;
margin-left: 10px; margin-left: 10px;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
gap: 8px;
flex-shrink: 0;
background: #f2f2f2;
cursor: pointer; cursor: pointer;
color: #222222;
&.active { &.active {
background: #409eff; background: #ed1c24;
color: white; color: white;
} }
} }
@@ -31,6 +31,7 @@ const GET_PROPS = computed(() => {
<template> <template>
<component <component
v-if="definedDynamicComponent[getCurrentComponent]"
:is="definedDynamicComponent[getCurrentComponent]" :is="definedDynamicComponent[getCurrentComponent]"
v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings }" v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings }"
/> />
@@ -31,6 +31,7 @@ const GET_PROPS = computed(() => {
<template> <template>
<component <component
v-if="definedDynamicComponent[getCurrentComponent]"
:is="definedDynamicComponent[getCurrentComponent]" :is="definedDynamicComponent[getCurrentComponent]"
v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings }" v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings }"
/> />
@@ -0,0 +1,595 @@
<script setup lang="ts">
import Poll from "~/components/article/immerse/Poll.vue";
import Quiz from "~/components/article/immerse/Quiz.vue";
import Survey from "~/components/article/immerse/Survey.vue";
import Document from "~/components/article/immerse/Document.vue";
import Attachment from "@/components/article/immerse/Attachment.vue";
import Tag from "@/components/article/immerse/Tag.vue";
// import articlerelation from "@/components/article/immerse/ArticleRelation.vue";
import RecusiveSection from "@/components/dynamic-page/page-section/RecusiveSection.vue";
import { getInputValue } from "@/utils/parseSQL";
import { enumPageSectionLayouts, enumPageSectionTemplate, enumPageSectionKey } from "~/definitions/enum";
import type { PageSection } from "@/server/models/dynamic-page/index";
import { formatDate } from '@/utils/filters'
const emit = defineEmits(["dropComponent", "dropData", "selectComponent"]);
const { categoryTree } = storeToRefs(useCategoryStore());
const { currentArticle } = storeToRefs(useArticleStore())
if(categoryTree.value) {
await useCategoryStore().fetchBySiteId()
}
const props = defineProps<{
layout?: string;
content?: any;
settings: any;
section: PageSection;
}>();
const defineTypeRecusive = {
COMPONENT: "component",
SECTION: "section",
};
const SETTING_OPTIONS = computed(() => {
let _setting_options = {};
switch (props.layout) {
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.ARTICLE]["DETAIL"]]["DEFAULT"]:
_setting_options = {
MAX_ELEMENT: 2,
};
break;
default:
_setting_options = {
MAX_ELEMENT: 1,
};
break;
}
return _setting_options;
});
const designObject = computed(() => {
// không truyn lable là ch lên s li
return props?.settings?.label ? getInputValue(props.settings.label, "OBJECT") : {};
});
const CLASS_FOR_SECTION = computed(() => {
let _classForSection = {};
switch (props.layout) {
case enumPageSectionLayouts[`${enumPageSectionTemplate[enumPageSectionKey.ARTICLE]["DETAIL"]}`]["DEFAULT"]:
_classForSection = {
section_layout: "section_layout two_col_layout tow_row_layout",
section_layout_value: enumPageSectionLayouts[`${enumPageSectionTemplate[enumPageSectionKey.ARTICLE]["DETAIL"]}`]["DEFAULT"],
};
break;
default:
_classForSection = {
section_layout: "section_layout basic_column",
};
break;
}
return _classForSection;
});
const LAYOUT_PARSE = computed(() => {
return props.settings?.label ? getInputValue(props.settings.label, "OBJECT") : {};
});
const mapActivesToItems = (index: number) => {
if (LAYOUT_PARSE.value && LAYOUT_PARSE.value.listCss) {
return LAYOUT_PARSE.value.listCss[index] || {};
}
return {};
};
const currentCategoryTree = ref<any []>([]);
if(currentArticle.value?.categoryId) {
console.log('urrentArticle.value?.categoryId', categoryTree.value)
currentCategoryTree.value = findElementPathById(categoryTree.value, currentArticle.value.categoryId)
}
function findElementPathById(categories: any[], targetId: number, path: any[] = []) {
for (const category of categories) {
const currentPath = [...path, { title: category.title, code: category.code }];
if (category.id === targetId) {
return currentPath;
}
if (category.children) {
const result: any = findElementPathById(category.children, targetId, currentPath);
if (result) {
return result;
}
}
}
return null;
}
</script>
<template>
<div class="section_layout border-custom four_col_layout" :style="LAYOUT_PARSE['div.section_layout']">
<div class="left">
<div>
<!-- <div class="audio">
<div class="play">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M24 12C24 18.6562 18.6094 24 12 24C5.34375 24 0 18.6562 0 12C0 5.39062 5.34375 0 12 0C18.6094 0 24 5.39062 24 12ZM8.25 7.875V16.125C8.25 16.5469 8.4375 16.9219 8.8125 17.1094C9.14062 17.3438 9.60938 17.2969 9.9375 17.1094L16.6875 12.9844C17.0156 12.7969 17.25 12.4219 17.25 12C17.25 11.625 17.0156 11.25 16.6875 11.0625L9.9375 6.9375C9.60938 6.70312 9.14062 6.70312 8.8125 6.9375C8.4375 7.125 8.25 7.5 8.25 7.875Z"
fill="#8E8E8E"
/>
</svg>
</div>
<div class="time">
<span>20:42</span>
</div>
<div class="timeline">
<input type="range" name="" id="" />
</div>
</div> -->
<div class="buttons">
<div class="actions">
<span class="copy">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M12 3V0H8.5C7.65625 0 7 0.6875 7 1.5V10.5C7 11.3438 7.65625 12 8.5 12H14.5C15.3125 12 16 11.3438 16 10.5V4H13C12.4375 4 12 3.5625 12 3ZM13 0V3H16L13 0ZM6 11V4H1.5C0.65625 4 0 4.6875 0 5.5V14.5C0 15.3438 0.65625 16 1.5 16H7.5C8.3125 16 9 15.3438 9 14.5V13H8C6.875 13 6 12.125 6 11Z"
fill="currentColor"
/>
</svg>
</span>
<span class="facebook">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M15.75 8C15.75 3.71875 12.2812 0.25 8 0.25C3.71875 0.25 0.25 3.71875 0.25 8C0.25 11.875 3.0625 15.0938 6.78125 15.6562V10.25H4.8125V8H6.78125V6.3125C6.78125 4.375 7.9375 3.28125 9.6875 3.28125C10.5625 3.28125 11.4375 3.4375 11.4375 3.4375V5.34375H10.4688C9.5 5.34375 9.1875 5.9375 9.1875 6.5625V8H11.3438L11 10.25H9.1875V15.6562C12.9062 15.0938 15.75 11.875 15.75 8Z"
fill="currentColor"
/>
</svg>
</span>
<span class="envelope">
<svg width="16" height="12" viewBox="0 0 16 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M8 9C7.46875 9 6.9375 8.84375 6.5 8.5L0 3.4375V10.5C0 11.3438 0.65625 12 1.5 12H14.5C15.3125 12 16 11.3438 16 10.5V3.4375L9.46875 8.5C9.03125 8.84375 8.5 9 8 9ZM0.5 2.5625L7.125 7.71875C7.625 8.09375 8.34375 8.09375 8.84375 7.71875L15.4688 2.5625C15.7812 2.3125 16 1.90625 16 1.5C16 0.6875 15.3125 0 14.5 0H1.5C0.65625 0 0 0.6875 0 1.5C0 1.90625 0.1875 2.3125 0.5 2.5625Z"
fill="currentColor"
/>
</svg>
</span>
<span class="print">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M14 6H2C0.875 6 0 6.90625 0 8V11C0 11.5625 0.4375 12 1 12H2V15C2 15.5625 2.4375 16 3 16H13C13.5312 16 14 15.5625 14 15V12H15C15.5312 12 16 11.5625 16 11V8C16 6.90625 15.0938 6 14 6ZM12 14H4V11H12V14ZM13.5 9.25C13.0625 9.25 12.75 8.9375 12.75 8.5C12.75 8.09375 13.0625 7.75 13.5 7.75C13.9062 7.75 14.25 8.09375 14.25 8.5C14.25 8.9375 13.9062 9.25 13.5 9.25ZM4 2H11.1562L12 2.84375V5H14V2.4375C14 2.15625 13.875 1.90625 13.6875 1.71875L12.2812 0.3125C12.0938 0.125 11.8438 0 11.5625 0H3C2.4375 0 2 0.46875 2 1V5H4V2Z"
fill="currentColor"
/>
</svg>
</span>
</div>
<div class="fontSize">
<span>
<svg width="13" height="15" viewBox="0 0 13 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M1.05469 12C0.971354 12 0.90625 11.9609 0.859375 11.8828C0.8125 11.7995 0.789062 11.7057 0.789062 11.6016C0.789062 11.4818 0.809896 11.4062 0.851562 11.375C0.888021 11.3438 0.960938 11.3229 1.07031 11.3125C1.20052 11.2969 1.34115 11.2891 1.49219 11.2891C1.64844 11.2839 1.79427 11.2448 1.92969 11.1719C2.07031 11.0938 2.18229 10.9401 2.26562 10.7109L5.84375 0.742188H7.09375L10.5703 10.7109C10.6536 10.9401 10.763 11.0938 10.8984 11.1719C11.0339 11.2448 11.1771 11.2839 11.3281 11.2891C11.4844 11.2891 11.625 11.2969 11.75 11.3125C11.8594 11.3229 11.9323 11.3438 11.9688 11.375C12.0104 11.4062 12.0312 11.4818 12.0312 11.6016C12.0312 11.6589 12.0078 11.7396 11.9609 11.8438C11.9193 11.9479 11.8542 12 11.7656 12H7.85156C7.76302 12 7.69531 11.9479 7.64844 11.8438C7.60677 11.7396 7.58594 11.6589 7.58594 11.6016C7.58594 11.4297 7.67188 11.3333 7.84375 11.3125C8.16146 11.2969 8.41927 11.2839 8.61719 11.2734C8.8151 11.263 8.91406 11.1979 8.91406 11.0781C8.91406 11.0417 8.90625 11.0052 8.89062 10.9688L7.94531 8.14062H4.19531L3.24219 10.9688C3.23177 10.9948 3.22656 11.026 3.22656 11.0625C3.22656 11.1927 3.33594 11.263 3.55469 11.2734C3.77865 11.2786 4.04948 11.2917 4.36719 11.3125C4.53906 11.3333 4.625 11.4297 4.625 11.6016C4.625 11.6589 4.60156 11.7396 4.55469 11.8438C4.51302 11.9479 4.44792 12 4.35938 12H1.05469ZM6.14844 2.72656L4.4375 7.46875H7.72656L6.14844 2.72656Z"
fill="currentColor"
/>
<path d="M1 13.8984H11.7344V14.7266H1V13.8984Z" fill="black" />
</svg>
</span>
<span>
<svg width="18" height="17" viewBox="0 0 18 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M1.08203 17C0.957031 17 0.859375 16.9414 0.789062 16.8242C0.71875 16.6992 0.683594 16.5586 0.683594 16.4023C0.683594 16.2227 0.714844 16.1094 0.777344 16.0625C0.832031 16.0156 0.941406 15.9844 1.10547 15.9688C1.30078 15.9453 1.51172 15.9336 1.73828 15.9336C1.97266 15.9258 2.19141 15.8672 2.39453 15.7578C2.60547 15.6406 2.77344 15.4102 2.89844 15.0664L8.26562 0.113281H10.1406L15.3555 15.0664C15.4805 15.4102 15.6445 15.6406 15.8477 15.7578C16.0508 15.8672 16.2656 15.9258 16.4922 15.9336C16.7266 15.9336 16.9375 15.9453 17.125 15.9688C17.2891 15.9844 17.3984 16.0156 17.4531 16.0625C17.5156 16.1094 17.5469 16.2227 17.5469 16.4023C17.5469 16.4883 17.5117 16.6094 17.4414 16.7656C17.3789 16.9219 17.2812 17 17.1484 17H11.2773C11.1445 17 11.043 16.9219 10.9727 16.7656C10.9102 16.6094 10.8789 16.4883 10.8789 16.4023C10.8789 16.1445 11.0078 16 11.2656 15.9688C11.7422 15.9453 12.1289 15.9258 12.4258 15.9102C12.7227 15.8945 12.8711 15.7969 12.8711 15.6172C12.8711 15.5625 12.8594 15.5078 12.8359 15.4531L11.418 11.2109H5.79297L4.36328 15.4531C4.34766 15.4922 4.33984 15.5391 4.33984 15.5938C4.33984 15.7891 4.50391 15.8945 4.83203 15.9102C5.16797 15.918 5.57422 15.9375 6.05078 15.9688C6.30859 16 6.4375 16.1445 6.4375 16.4023C6.4375 16.4883 6.40234 16.6094 6.33203 16.7656C6.26953 16.9219 6.17188 17 6.03906 17H1.08203ZM8.72266 3.08984L6.15625 10.2031H11.0898L8.72266 3.08984Z"
fill="currentColor"
/>
</svg>
</span>
<span>
<svg width="24" height="23" viewBox="0 0 24 23" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M1.10938 23C0.942708 23 0.8125 22.9219 0.71875 22.7656C0.625 22.599 0.578125 22.4115 0.578125 22.2031C0.578125 21.9635 0.619792 21.8125 0.703125 21.75C0.776042 21.6875 0.921875 21.6458 1.14062 21.625C1.40104 21.5938 1.68229 21.5781 1.98438 21.5781C2.29688 21.5677 2.58854 21.4896 2.85938 21.3438C3.14062 21.1875 3.36458 20.8802 3.53125 20.4219L10.6875 0.484375H13.1875L20.1406 20.4219C20.3073 20.8802 20.526 21.1875 20.7969 21.3438C21.0677 21.4896 21.3542 21.5677 21.6562 21.5781C21.9688 21.5781 22.25 21.5938 22.5 21.625C22.7188 21.6458 22.8646 21.6875 22.9375 21.75C23.0208 21.8125 23.0625 21.9635 23.0625 22.2031C23.0625 22.3177 23.0156 22.4792 22.9219 22.6875C22.8385 22.8958 22.7083 23 22.5312 23H14.7031C14.526 23 14.3906 22.8958 14.2969 22.6875C14.2135 22.4792 14.1719 22.3177 14.1719 22.2031C14.1719 21.8594 14.3438 21.6667 14.6875 21.625C15.3229 21.5938 15.8385 21.5677 16.2344 21.5469C16.6302 21.526 16.8281 21.3958 16.8281 21.1562C16.8281 21.0833 16.8125 21.0104 16.7812 20.9375L14.8906 15.2812H7.39062L5.48438 20.9375C5.46354 20.9896 5.45312 21.0521 5.45312 21.125C5.45312 21.3854 5.67188 21.526 6.10938 21.5469C6.55729 21.5573 7.09896 21.5833 7.73438 21.625C8.07812 21.6667 8.25 21.8594 8.25 22.2031C8.25 22.3177 8.20312 22.4792 8.10938 22.6875C8.02604 22.8958 7.89583 23 7.71875 23H1.10938ZM11.2969 4.45312L7.875 13.9375H14.4531L11.2969 4.45312Z"
fill="currentColor"
/>
</svg>
</span>
</div>
</div>
<div class="tags" v-if="currentArticle && currentArticle?.tags">
<span>
<svg width="18" height="19" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M1.875 0.75H7.69531C8.35938 0.75 8.98438 1.02344 9.45312 1.49219L16.3281 8.36719C17.3047 9.34375 17.3047 10.9453 16.3281 11.9219L11.1328 17.1172C10.1562 18.0938 8.55469 18.0938 7.57812 17.1172L0.703125 10.2422C0.234375 9.77344 0 9.14844 0 8.48438V2.625C0 1.60938 0.820312 0.75 1.875 0.75ZM4.375 6.375C5.03906 6.375 5.625 5.82812 5.625 5.125C5.625 4.46094 5.03906 3.875 4.375 3.875C3.67188 3.875 3.125 4.46094 3.125 5.125C3.125 5.82812 3.67188 6.375 4.375 6.375Z"
fill="#ED1C24"
/>
</svg>
</span>
<ul >
<li v-for="(tag, index) in currentArticle?.tags">
<nuxt-link class="font-raleway font-500" :to="`/tag/${tag.code}`">{{ tag.title }}</nuxt-link>
</li>
</ul>
</div>
</div>
<div class="section_child" :class="['border-custom']" :style="mapActivesToItems(0)['div.section_child']" @dragover.prevent @drop.stop.prevent="dropPlacementInSection($event, 0, props.content ? props?.content[0].data : '')">
<template v-if="props.content">
<RecusiveSection :type="props?.content[0].type" :id="props?.content[0].data" :section="props.section" />
</template>
<template v-else>
<RecusiveSection :type="''" :id="''" :section="props.section" />
</template>
</div>
</div>
<div class="content detail-default">
<div class="content__top">
<div class="flex justify-between flex-wrap items-center mb-10px">
<ul class="flex gap-32px" v-if="currentCategoryTree?.length">
<li v-for="( category, index ) in currentCategoryTree" :key="index" class="first:text-#000 text-#929292 last:after:content-[''] relative after:absolute after:content-['/'] after:text-20px after:right--20px" >
<nuxt-link class=" font-raleway text-18px font-500 leading-180% uppercase" :to="`/${category.code}`">{{ category.title }}</nuxt-link>
</li>
</ul>
<div v-if="currentArticle?.topics" class="pl-20px relative bg-primary inline-block">
<nuxt-link class="h-30px block py-4px px-16px border-1 border-#000 bg-white text-12px leading-180% font-raleway font-400" :to="`/topic/${currentArticle?.topics[0].slug}`">{{ currentArticle?.topics[0].title }}</nuxt-link>
</div>
</div>
<h2 class="font-gelasio text-44px font-bold leading-130%" v-if="currentArticle?.title" v-html="currentArticle?.title"></h2>
<div class="author flex gap-12px my-20px" v-if="currentArticle?.authors">
<ul class="flex">
<li :style="{'z-index': index + 1}" class="relative ml--12px first:ml-0" v-for="(author, index) in currentArticle?.authors" :key="index">
<nuxt-link :to="`/tac-gia/${author.code}`">
<img :src="author?.thumbnail || `http://picsum.photos/1024/600?random=1`" alt="" class="w-64px p-1px border-1px border-white h-64px object-cover rounded-full">
</nuxt-link>
</li>
</ul>
<div>
<div class="mt-10px">
<nuxt-link class="font-raleway text-#000" v-for="(author, index) in currentArticle?.authors" :key="index" :to="`/tac-gia/${author.code}`">{{ author.title + (index < currentArticle.authors.length - 1 ? ', ' : '') }}</nuxt-link>
</div>
<div class="text-12px">
Xuất bản vào {{ formatDate(currentArticle?.publishedOn, 'DD/MM/YYYY | hh:mm') }}
</div>
</div>
</div>
<figure v-if="currentArticle?.thumbnail">
<img :src="currentArticle?.thumbnail" class="w-full " alt="">
</figure>
</div>
<div class="content__bottom" >
<div class="content__bottom__left">
<div class="content__bottom__left__control">
<div class="content__bottom__left__control__sticky [&_span:hover]:text-primary">
<span class="flex justify-center ">
<svg width="20" height="21" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M20 10.5C20 16.0469 15.5078 20.5 10 20.5C4.45312 20.5 0 16.0469 0 10.5C0 4.99219 4.45312 0.5 10 0.5C15.5078 0.5 20 4.99219 20 10.5ZM6.875 7.0625V13.9375C6.875 14.2891 7.03125 14.6016 7.34375 14.7578C7.61719 14.9531 8.00781 14.9141 8.28125 14.7578L13.9062 11.3203C14.1797 11.1641 14.375 10.8516 14.375 10.5C14.375 10.1875 14.1797 9.875 13.9062 9.71875L8.28125 6.28125C8.00781 6.08594 7.61719 6.08594 7.34375 6.28125C7.03125 6.4375 6.875 6.75 6.875 7.0625Z"
fill="currentColor"
/>
</svg>
</span>
<span class="flex justify-center">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M12 3V0H8.5C7.65625 0 7 0.6875 7 1.5V10.5C7 11.3438 7.65625 12 8.5 12H14.5C15.3125 12 16 11.3438 16 10.5V4H13C12.4375 4 12 3.5625 12 3ZM13 0V3H16L13 0ZM6 11V4H1.5C0.65625 4 0 4.6875 0 5.5V14.5C0 15.3438 0.65625 16 1.5 16H7.5C8.3125 16 9 15.3438 9 14.5V13H8C6.875 13 6 12.125 6 11Z"
fill="currentColor"
/>
</svg>
</span>
<span class="flex justify-center">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M15.75 8C15.75 3.71875 12.2812 0.25 8 0.25C3.71875 0.25 0.25 3.71875 0.25 8C0.25 11.875 3.0625 15.0938 6.78125 15.6562V10.25H4.8125V8H6.78125V6.3125C6.78125 4.375 7.9375 3.28125 9.6875 3.28125C10.5625 3.28125 11.4375 3.4375 11.4375 3.4375V5.34375H10.4688C9.5 5.34375 9.1875 5.9375 9.1875 6.5625V8H11.3438L11 10.25H9.1875V15.6562C12.9062 15.0938 15.75 11.875 15.75 8Z"
fill="currentColor"
/>
</svg>
</span>
<span class="flex justify-center">
<svg width="16" height="12" viewBox="0 0 16 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M8 9C7.46875 9 6.9375 8.84375 6.5 8.5L0 3.4375V10.5C0 11.3438 0.65625 12 1.5 12H14.5C15.3125 12 16 11.3438 16 10.5V3.4375L9.46875 8.5C9.03125 8.84375 8.5 9 8 9ZM0.5 2.5625L7.125 7.71875C7.625 8.09375 8.34375 8.09375 8.84375 7.71875L15.4688 2.5625C15.7812 2.3125 16 1.90625 16 1.5C16 0.6875 15.3125 0 14.5 0H1.5C0.65625 0 0 0.6875 0 1.5C0 1.90625 0.1875 2.3125 0.5 2.5625Z"
fill="currentColor"
/>
</svg>
</span>
<span class="flex justify-center">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M14 6H2C0.875 6 0 6.90625 0 8V11C0 11.5625 0.4375 12 1 12H2V15C2 15.5625 2.4375 16 3 16H13C13.5312 16 14 15.5625 14 15V12H15C15.5312 12 16 11.5625 16 11V8C16 6.90625 15.0938 6 14 6ZM12 14H4V11H12V14ZM13.5 9.25C13.0625 9.25 12.75 8.9375 12.75 8.5C12.75 8.09375 13.0625 7.75 13.5 7.75C13.9062 7.75 14.25 8.09375 14.25 8.5C14.25 8.9375 13.9062 9.25 13.5 9.25ZM4 2H11.1562L12 2.84375V5H14V2.4375C14 2.15625 13.875 1.90625 13.6875 1.71875L12.2812 0.3125C12.0938 0.125 11.8438 0 11.5625 0H3C2.4375 0 2 0.46875 2 1V5H4V2Z"
fill="currentColor"
/>
</svg>
</span>
</div>
</div>
<div>
<p class="my-10px" v-if="currentArticle?.intro" v-html="currentArticle.intro">
</p>
<!-- <div v-html="currentArticle.detail" class="[&_p_>_span]:!font-raleway [&_p]:mb-10px"></div> -->
<component :is="{ template: currentArticle?.detail, components: { Poll, Quiz, Survey, Document, Attachment, Tag } }" />
</div>
</div>
<div class="content__bottom__right">
<div class="section_child" :class="['border-custom']" :style="mapActivesToItems(1)['div.section_child']">
<template v-if="props.content">
<RecusiveSection :type="props?.content[1].type" :id="props?.content[1].data" :section="props.section" />
</template>
<template v-else>
<RecusiveSection :type="''" :id="''" :section="props.section" />
</template>
</div>
</div>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
$control-width: 80px;
.border-pri {
&.section_layout {
gap: 5px;
}
}
.section_layout {
display: flex;
.left {
width: 305px;
.tags {
display: flex;
align-items: center;
gap: 20px;
padding: 24px 0 20px 0;
border-top: 1px solid #ededed;
border-bottom: 1px solid #ededed;
& > ul {
padding: 0;
margin: 0;
display: flex;
gap: 12px;
flex-wrap: wrap;
& > li {
list-style: none;
& > a {
display: block;
font-size: 12px;
line-height: 180%;
padding: 0 10px;
background-color: #f5efef;
border-radius: 6px;
}
}
}
}
.buttons {
margin: 20px 0;
display: flex;
justify-content: space-between;
align-items: center;
.actions,
.fontSize {
display: flex;
align-items: flex-end;
gap: 1.5rem;
}
}
.audio {
display: flex;
width: 100%;
height: 28px;
padding: 2px 12px 2px 2px;
border-radius: 999px;
background-color: #eee;
align-items: center;
.play {
margin-right: 16px;
}
.time {
line-height: 180%;
font-size: 12px;
color: #000;
margin-right: 6px;
}
.timeline {
flex: 1;
display: flex;
align-items: center;
}
}
input[type="range"] {
width: 100%;
height: 4px;
color: #4a4a4a;
--thumb-height: 1.125em;
--track-height: 0.125em;
--track-color: rgba(0, 0, 0, 0.2);
--brightness-hover: 180%;
--brightness-down: 80%;
--clip-edges: 0.125em;
}
/* === range commons === */
input[type="range"] {
position: relative;
background: #fff0;
overflow: hidden;
}
input[type="range"]:active {
cursor: grabbing;
}
input[type="range"]:disabled {
filter: grayscale(1);
opacity: 0.3;
cursor: not-allowed;
}
/* === WebKit specific styles === */
input[type="range"],
input[type="range"]::-webkit-slider-runnable-track,
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
transition: all ease 100ms;
height: var(--thumb-height);
}
input[type="range"]::-webkit-slider-runnable-track,
input[type="range"]::-webkit-slider-thumb {
position: relative;
}
input[type="range"]::-webkit-slider-thumb {
--thumb-radius: calc((var(--thumb-height) * 0.5) - 1px);
--clip-top: calc((var(--thumb-height) - var(--track-height)) * 0.5 - 0.5px);
--clip-bottom: calc(var(--thumb-height) - var(--clip-top));
--clip-further: calc(100% + 1px);
--box-fill: calc(-100vmax - var(--thumb-width, var(--thumb-height))) 0 0 100vmax currentColor;
width: var(--thumb-width, var(--thumb-height));
background: linear-gradient(#e50e0e 0 0) scroll no-repeat left center / 50% calc(var(--track-height) + 1px);
background-color: #e50e0e;
box-shadow: var(--box-fill);
border-radius: var(--thumb-width, var(--thumb-height));
filter: brightness(100%);
clip-path: polygon(100% -1px, var(--clip-edges) -1px, 0 var(--clip-top), -100vmax var(--clip-top), -100vmax var(--clip-bottom), 0 var(--clip-bottom), var(--clip-edges) 100%, var(--clip-further) var(--clip-further));
}
input[type="range"]:hover::-webkit-slider-thumb {
filter: brightness(var(--brightness-hover));
cursor: grab;
}
input[type="range"]:active::-webkit-slider-thumb {
filter: brightness(var(--brightness-down));
cursor: grabbing;
}
input[type="range"]::-webkit-slider-runnable-track {
background: linear-gradient(var(--track-color) 0 0) scroll no-repeat center / 100% calc(var(--track-height) + 1px);
}
input[type="range"]:disabled::-webkit-slider-thumb {
cursor: not-allowed;
}
/* === Firefox specific styles === */
// input[type="range"],
// input[type="range"]::-moz-range-track,
// input[type="range"]::-moz-range-thumb {
// appearance: none;
// transition: all ease 100ms;
// height: var(--thumb-height);
// }
// input[type="range"]::-moz-range-track,
// input[type="range"]::-moz-range-thumb,
// input[type="range"]::-moz-range-progress {
// background: #fff0;
// }
// input[type="range"]::-moz-range-thumb {
// background: currentColor;
// border: 0;
// width: var(--thumb-width, var(--thumb-height));
// border-radius: var(--thumb-width, var(--thumb-height));
// cursor: grab;
// }
// input[type="range"]:active::-moz-range-thumb {
// cursor: grabbing;
// }
// input[type="range"]::-moz-range-track {
// width: 100%;
// background: var(--track-color);
// }
// input[type="range"]::-moz-range-progress {
// appearance: none;
// background: currentColor;
// transition-delay: 30ms;
// }
// input[type="range"]::-moz-range-track,
// input[type="range"]::-moz-range-progress {
// height: calc(var(--track-height) + 1px);
// border-radius: var(--track-height);
// }
// input[type="range"]::-moz-range-thumb,
// input[type="range"]::-moz-range-progress {
// filter: brightness(100%);
// }
// input[type="range"]:hover::-moz-range-thumb,
// input[type="range"]:hover::-moz-range-progress {
// filter: brightness(var(--brightness-hover));
// }
// input[type="range"]:active::-moz-range-thumb,
// input[type="range"]:active::-moz-range-progress {
// filter: brightness(var(--brightness-down));
// }
// input[type="range"]:disabled::-moz-range-thumb {
// cursor: not-allowed;
// }
}
.content {
margin-left: $control-width;
flex: 1;
display: flex;
flex-direction: column;
&__top {
width: 100%;
}
&__bottom {
width: 100%;
min-height: 300px;
display: flex;
justify-content: space-between;
&__left {
flex: 1;
max-width: 660px;
display: block;
height: 100%;
position: relative;
&__control {
width: $control-width;
position: absolute;
height: 100%;
left: -$control-width;
&__sticky {
position: sticky;
top: 10px;
display: flex;
flex-direction: column;
gap: 16px;
& > span {
text-align: center;
}
}
}
}
&__right {
width: 300px;
}
}
}
}
</style>
@@ -0,0 +1,135 @@
<script setup lang="ts">
import RecusiveSection from "@/components/dynamic-page/page-section/RecusiveSection.vue";
import { getInputValue } from "@/utils/parseSQL";
import { enumPageSectionLayouts, enumPageSectionTemplate, enumPageSectionKey } from "~/definitions/enum";
import type { PageSection } from "@/server/models/dynamic-page/index";
const emit = defineEmits(["dropComponent", "dropData", "selectComponent"]);
const props = defineProps<{
layout?: string;
content?: any;
settings: any;
section: PageSection;
}>();
const defineTypeRecusive = {
COMPONENT: "component",
SECTION: "section",
};
const SETTING_OPTIONS = computed(() => {
let _setting_options = {
MAX_ELEMENT: 1,
};
return _setting_options;
});
const designObject = computed(() => {
// không truyn lable là ch lên s li
return props?.settings?.label ? getInputValue(props.settings.label, "OBJECT") : {};
});
const CLASS_FOR_SECTION = computed(() => {
let _classForSection = {
section_layout: "section_layout basic_column",
};
return _classForSection;
});
const handleActiveItem = (key: string, keyActive: string, index: number, defaultValue: any) => {
const designObject = props?.section?.settings?.label ? getInputValue(props.section.settings.label, "OBJECT") : {};
const updatedDesignObject = { ...designObject };
if (Array.isArray(designObject[keyActive])) {
const isActive = designObject[keyActive].includes(Number(index) + 1);
return {
...updatedDesignObject,
[key]: isActive ? designObject[key] : defaultValue,
};
}
delete updatedDesignObject[key];
return updatedDesignObject;
};
const LAYOUT_PARSE = computed(() => {
return props.settings?.label ? getInputValue(props.settings.label, "OBJECT") : {};
});
const mapActivesToItems = (index: number) => {
if (LAYOUT_PARSE.value && LAYOUT_PARSE.value.listCss) {
return LAYOUT_PARSE.value.listCss[index] || {};
}
return {};
};
</script>
<template>
<div
class="section_layout border-custom"
:class="[CLASS_FOR_SECTION.section_layout]"
:style="LAYOUT_PARSE['div.section_layout']"
>
<div
class="section_child"
v-for="(position, index) in props.content || Array(SETTING_OPTIONS.MAX_ELEMENT).fill({})"
:key="index"
:class="['border-custom', CLASS_FOR_SECTION[index]]"
:style="mapActivesToItems(index)['div.section_child']"
>
<RecusiveSection :type="position.type" :id="position.data" :section="props.section" />
</div>
</div>
</template>
<style lang="scss" scoped>
.border-pri {
&.section_layout {
gap: 5px;
}
}
.section_layout {
display: grid;
&.smartphone_layout {
grid-template-columns: repeat(1, minmax(0, 1fr)) !important;
}
&.basic_column {
grid-template-columns: repeat(1, minmax(0, 1fr));
}
&.two_col_layout {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
&.three_col_layout {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
&.four_col_layout {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
&.five_col_layout {
grid-template-columns: repeat(5, minmax(0, 1fr));
}
&.six_col_layout {
grid-template-columns: repeat(6, minmax(0, 1fr));
}
.col-span-2 {
grid-column: span 2 / span 2;
}
.col-span-3 {
grid-column: span 3 / span 3;
}
.col-span-4 {
grid-column: span 4 / span 4;
}
.col-span-5 {
grid-column: span 5 / span 5;
}
.border-custom {
border-color: #e5e5e5 !important;
}
}
</style>
@@ -1 +1,5 @@
export { default as NONE_DEFAULT_LAYOUT } from './none/Default.vue' export { default as NONE_DEFAULT_LAYOUT } from './none/Default.vue'
export { default as MISS_DEFAULT_LAYOUT } from './category/misses/Default.vue'
export { default as ARTICLE_DETAIL_DEFAULT } from './articles/details/Default.vue'
@@ -1,7 +1,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { PageSection } from "@/server/models/dynamic-page/index"; import type { PageSection } from "@/server/models/dynamic-page/index";
import { enumPageSectionLayouts, enumPageSectionTemplate, enumPageSectionKey } from "@/definitions/enum"; import { enumPageSectionLayouts, enumPageSectionTemplate, enumPageSectionKey } from "@/definitions/enum";
import { NONE_DEFAULT_LAYOUT } from "./index"; import { NONE_DEFAULT_LAYOUT, MISS_DEFAULT_LAYOUT, ARTICLE_DETAIL_DEFAULT } from "./index";
const _props = defineProps<{ const _props = defineProps<{
settings?: any; settings?: any;
@@ -11,26 +11,37 @@ const _props = defineProps<{
}>(); }>();
const definedDynamicSection: Record<string, any> = { const definedDynamicSection: Record<string, any> = {
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_TWO']]: NONE_DEFAULT_LAYOUT, /* NONE */
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_LEFT_TWO']]: NONE_DEFAULT_LAYOUT, [enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_TWO"]]: NONE_DEFAULT_LAYOUT,
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_ONE_TWO_THREE"]]: NONE_DEFAULT_LAYOUT, [enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_ONE_TWO_THREE"]]: NONE_DEFAULT_LAYOUT,
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_FIVE_THREE_TWO_TWO"]]: NONE_DEFAULT_LAYOUT,
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_FIVE_TWO_TWO_THREE"]]: NONE_DEFAULT_LAYOUT,
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_TWO_FIVE_THREE_TWO"]]: NONE_DEFAULT_LAYOUT,
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_ONE_FIVE"]]: NONE_DEFAULT_LAYOUT, [enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_ONE_FIVE"]]: NONE_DEFAULT_LAYOUT,
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_RIGHT_TWO']]: NONE_DEFAULT_LAYOUT, [enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_ONE_FOUR"]]: NONE_DEFAULT_LAYOUT,
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_THREE']]: NONE_DEFAULT_LAYOUT, [enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_LEFT_TWO"]]: NONE_DEFAULT_LAYOUT,
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_FOUR']]: NONE_DEFAULT_LAYOUT, [enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_RIGHT_TWO"]]: NONE_DEFAULT_LAYOUT,
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_CENTER_TWO']]: NONE_DEFAULT_LAYOUT, [enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_THREE"]]: NONE_DEFAULT_LAYOUT,
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_CENTER_THREE']]: NONE_DEFAULT_LAYOUT, [enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_FOUR"]]: NONE_DEFAULT_LAYOUT,
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_CENTER_FOUR']]: NONE_DEFAULT_LAYOUT, [enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_CENTER_TWO"]]: NONE_DEFAULT_LAYOUT,
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_ONE']]: NONE_DEFAULT_LAYOUT, [enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_CENTER_THREE"]]: NONE_DEFAULT_LAYOUT,
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_TWO']]: NONE_DEFAULT_LAYOUT, [enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_CENTER_FOUR"]]: NONE_DEFAULT_LAYOUT,
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_THREE']]: NONE_DEFAULT_LAYOUT, [enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["HORIZONTAL_ONE"]]: NONE_DEFAULT_LAYOUT,
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_FOUR']]: NONE_DEFAULT_LAYOUT, [enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["HORIZONTAL_TWO"]]: NONE_DEFAULT_LAYOUT,
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_FIVE']]: NONE_DEFAULT_LAYOUT, [enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["HORIZONTAL_THREE"]]: NONE_DEFAULT_LAYOUT,
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_SIX']]: NONE_DEFAULT_LAYOUT, [enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["HORIZONTAL_FOUR"]]: NONE_DEFAULT_LAYOUT,
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_SEVEN']]: NONE_DEFAULT_LAYOUT, [enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["HORIZONTAL_FIVE"]]: NONE_DEFAULT_LAYOUT,
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_EIGHT']]: NONE_DEFAULT_LAYOUT, [enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["HORIZONTAL_SIX"]]: NONE_DEFAULT_LAYOUT,
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_NINE']]: NONE_DEFAULT_LAYOUT, [enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["HORIZONTAL_SEVEN"]]: NONE_DEFAULT_LAYOUT,
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_TEN']]: NONE_DEFAULT_LAYOUT, [enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["HORIZONTAL_EIGHT"]]: NONE_DEFAULT_LAYOUT,
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["HORIZONTAL_NINE"]]: NONE_DEFAULT_LAYOUT,
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["HORIZONTAL_TEN"]]: NONE_DEFAULT_LAYOUT,
/* SECTION */
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.CATEGORY]["MISSES"]]["DEFAULT"]]: MISS_DEFAULT_LAYOUT,
/** ARTICLE */
[enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.ARTICLE]["DETAIL"]]["DEFAULT"]]: ARTICLE_DETAIL_DEFAULT,
}; };
const getCurrentSection = computed(() => { const getCurrentSection = computed(() => {
@@ -53,7 +64,9 @@ const GET_PROPS = computed(() => {
</script> </script>
<template> <template>
<component <component
v-if="definedDynamicSection[getCurrentSection]"
:is="definedDynamicSection[getCurrentSection]" :is="definedDynamicSection[getCurrentSection]"
v-bind="{ v-bind="{
...GET_PROPS(), ...GET_PROPS(),
@@ -4,6 +4,8 @@ import { getInputValue } from "@/utils/parseSQL";
import { enumPageSectionLayouts, enumPageSectionTemplate, enumPageSectionKey } from "~/definitions/enum"; import { enumPageSectionLayouts, enumPageSectionTemplate, enumPageSectionKey } from "~/definitions/enum";
import type { PageSection } from "@/server/models/dynamic-page/index"; import type { PageSection } from "@/server/models/dynamic-page/index";
const emit = defineEmits(["dropComponent", "dropData", "selectComponent"]);
const props = defineProps<{ const props = defineProps<{
layout?: string; layout?: string;
content?: any; content?: any;
@@ -16,16 +18,20 @@ const defineTypeRecusive = {
SECTION: "section", SECTION: "section",
}; };
const designObject = computed(() => {
// không truyn lable là ch lên s li
return props?.settings?.label ? getInputValue(props.settings.label, "OBJECT") : {};
});
const SETTING_OPTIONS = computed(() => { const SETTING_OPTIONS = computed(() => {
let _setting_options = {}; let _setting_options = {};
switch (props.layout) { switch (props.layout) {
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_TWO"]:
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_TWO']:
_setting_options = { _setting_options = {
MAX_ELEMENT: 2, MAX_ELEMENT: 2,
}; };
break; break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_ONE_TWO_THREE"]: case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_ONE_TWO_THREE"]:
_setting_options = { _setting_options = {
MAX_ELEMENT: 3, MAX_ELEMENT: 3,
}; };
@@ -35,87 +41,107 @@ const SETTING_OPTIONS = computed(() => {
MAX_ELEMENT: 2, MAX_ELEMENT: 2,
}; };
break; break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_LEFT_TWO']: case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_FIVE_THREE_TWO_TWO"]:
_setting_options = {
MAX_ELEMENT: 2,
};
break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_RIGHT_TWO']:
_setting_options = {
MAX_ELEMENT: 2,
};
break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_THREE']:
_setting_options = {
MAX_ELEMENT: 3,
};
break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_FOUR']:
_setting_options = { _setting_options = {
MAX_ELEMENT: 4, MAX_ELEMENT: 4,
}; };
break; break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_CENTER_TWO']: case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_FIVE_TWO_TWO_THREE"]:
_setting_options = {
MAX_ELEMENT: 4,
};
break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_TWO_FIVE_THREE_TWO"]:
_setting_options = {
MAX_ELEMENT: 4,
};
break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_ONE_FOUR"]:
_setting_options = {
MAX_ELEMENT: 2,
};
break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_LEFT_TWO"]:
_setting_options = {
MAX_ELEMENT: 2,
};
break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_RIGHT_TWO"]:
_setting_options = {
MAX_ELEMENT: 2,
};
break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_THREE"]:
_setting_options = { _setting_options = {
MAX_ELEMENT: 3, MAX_ELEMENT: 3,
}; };
break; break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_CENTER_THREE']: case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_FOUR"]:
_setting_options = {
MAX_ELEMENT: 4,
};
break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_CENTER_TWO"]:
_setting_options = { _setting_options = {
MAX_ELEMENT: 3, MAX_ELEMENT: 3,
}; };
break; break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_CENTER_FOUR']: case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_CENTER_THREE"]:
_setting_options = { _setting_options = {
MAX_ELEMENT: 3, MAX_ELEMENT: 3,
}; };
break; break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_ONE']: case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_CENTER_FOUR"]:
_setting_options = {
MAX_ELEMENT: 3,
};
break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["HORIZONTAL_ONE"]:
_setting_options = { _setting_options = {
MAX_ELEMENT: 1, MAX_ELEMENT: 1,
}; };
break; break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_TWO']: case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["HORIZONTAL_TWO"]:
_setting_options = { _setting_options = {
MAX_ELEMENT: 2, MAX_ELEMENT: 2,
}; };
break; break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_THREE']: case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["HORIZONTAL_THREE"]:
_setting_options = { _setting_options = {
MAX_ELEMENT: 3, MAX_ELEMENT: 3,
}; };
break; break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_FOUR']: case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["HORIZONTAL_FOUR"]:
_setting_options = { _setting_options = {
MAX_ELEMENT: 4, MAX_ELEMENT: 4,
}; };
break; break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_FIVE']: case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["HORIZONTAL_FIVE"]:
_setting_options = { _setting_options = {
MAX_ELEMENT: 5, MAX_ELEMENT: 5,
}; };
break; break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_SIX']: case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["HORIZONTAL_SIX"]:
_setting_options = { _setting_options = {
MAX_ELEMENT: 6, MAX_ELEMENT: 6,
}; };
break; break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_SEVEN']: case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["HORIZONTAL_SEVEN"]:
_setting_options = { _setting_options = {
MAX_ELEMENT: 7, MAX_ELEMENT: 7,
}; };
break; break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_EIGHT']: case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["HORIZONTAL_EIGHT"]:
_setting_options = { _setting_options = {
MAX_ELEMENT: 8, MAX_ELEMENT: 8,
}; };
break; break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_NINE']: case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["HORIZONTAL_NINE"]:
_setting_options = { _setting_options = {
MAX_ELEMENT: 9, MAX_ELEMENT: 9,
}; };
break; break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_TEN']: case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["HORIZONTAL_TEN"]:
_setting_options = { _setting_options = {
MAX_ELEMENT: 10, MAX_ELEMENT: 10,
}; };
@@ -129,69 +155,109 @@ const SETTING_OPTIONS = computed(() => {
return _setting_options; return _setting_options;
}); });
const designObject = computed(() => {
return props?.settings?.label ? getInputValue(props.settings.label, "OBJECT") : {};
});
const CLASS_FOR_SECTION = computed(() => { const CLASS_FOR_SECTION = computed(() => {
let _classForSection = {}; let _classForSection = {};
switch (props.layout) { switch (props.layout) {
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_TWO']: case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_TWO"]:
_classForSection = { _classForSection = {
section_layout: "section_layout two_col_layout", section_layout: "section_layout two_col_layout",
}; };
break; break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_ONE_FIVE"]:
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_LEFT_TWO"]:
_classForSection = { _classForSection = {
section_layout: "section_layout six_col_layout", section_layout: "section_layout twelve_col_layout",
1: "col-span-5", 0: "md:col-span-8 col-span-12",
1: "md:col-span-4 col-span-12",
}; };
break; break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_ONE_TWO_THREE"]: case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_RIGHT_TWO"]:
_classForSection = { _classForSection = {
section_layout: "section_layout six_col_layout", section_layout: "section_layout grid-cols-12",
1: "col-span-2", 0: "md:col-span-4 col-span-12",
2: "col-span-3", 1: "md:col-span-8 col-span-12",
}; };
break; break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_LEFT_TWO']: case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_ONE_FIVE"]:
_classForSection = { _classForSection = {
section_layout: "section_layout three_col_layout", section_layout: "section_layout grid-cols-12",
0: "col-span-2", 0: "lg:col-span-2 lg:block hidden",
1: "lg:col-span-10 col-span-12",
}; };
break; break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_RIGHT_TWO']: case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_FIVE_THREE_TWO_TWO"]:
_classForSection = { _classForSection = {
section_layout: "section_layout three_col_layout", section_layout: "section_layout twelve_col_layout",
1: "col-span-2", 0: "col-span-5",
1: "col-span-3",
2: "col-span-2",
3: "col-span-2",
}; };
break; break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_THREE']: case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_FIVE_TWO_TWO_THREE"]:
_classForSection = { _classForSection = {
section_layout: "section_layout three_col_layout", section_layout: "section_layout grid-cols-12",
0: "md:col-span-5 col-span-12",
1: "md:col-span-2 sm:col-span-6 col-span-12",
2: "md:col-span-2 sm:col-span-6 col-span-12",
3: "md:col-span-3 col-span-12",
}; };
break; break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_FOUR']: case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_TWO_FIVE_THREE_TWO"]:
_classForSection = {
section_layout: "section_layout grid-cols-12",
0: "col-span-2 md:block hidden",
1: "md:col-span-5 sm:col-span-7 col-span-12",
2: "md:col-span-3 sm:col-span-5 col-span-12",
3: "col-span-2 md:block hidden",
};
break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_ONE_FOUR"]:
_classForSection = {
section_layout: "section_layout five_col_layout",
1: "col-span-4",
};
break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_THREE"]:
_classForSection = {
section_layout: "section_layout grid-cols-12",
0: "sm:col-span-4 col-span-12",
1: "sm:col-span-4 col-span-12",
2: "sm:col-span-4 col-span-12"
};
break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_FOUR"]:
_classForSection = { _classForSection = {
section_layout: "section_layout four_col_layout", section_layout: "section_layout four_col_layout",
}; };
break; break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_CENTER_TWO']: case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_CENTER_TWO"]:
_classForSection = { _classForSection = {
section_layout: "section_layout four_col_layout", section_layout: "section_layout four_col_layout",
1: "col-span-2", 1: "col-span-2",
}; };
break; break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_CENTER_THREE']: case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_CENTER_THREE"]:
_classForSection = { _classForSection = {
section_layout: "section_layout five_col_layout", section_layout: "section_layout five_col_layout",
1: "col-span-3", 1: "col-span-3",
}; };
break; break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_CENTER_FOUR']: case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_CENTER_FOUR"]:
_classForSection = { _classForSection = {
section_layout: "section_layout six_col_layout", section_layout: "section_layout grid-cols-12",
1: "col-span-4", 0: "lg:col-span-2 md:col-span-6 col-span-12 lg:order-1 md:order-2 order-2",
1: "lg:col-span-8 md:col-span-12 col-span-12 lg:order-2 md:order-1 order-1",
2: "lg:col-span-2 md:col-span-6 col-span-12 lg:order-3 md:order-3 order-3",
};
break;
case enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]["NONE"]]["VERTICAL_ONE_TWO_THREE"]:
_classForSection = {
section_layout: "section_layout grid-cols-12",
0: "col-span-2 lg:block hidden",
1: "lg:col-span-4 md:col-span-5 col-span-12",
2: "lg:col-span-6 md:col-span-7 col-span-12",
}; };
break; break;
default: default:
@@ -203,6 +269,22 @@ const CLASS_FOR_SECTION = computed(() => {
return _classForSection; return _classForSection;
}); });
const handleActiveItem = (key: string, keyActive: string, index: number, defaultValue: any) => {
const designObject = props?.section?.settings?.label ? getInputValue(props.section.settings.label, "OBJECT") : {};
const updatedDesignObject = { ...designObject };
if (Array.isArray(designObject[keyActive])) {
const isActive = designObject[keyActive].includes(Number(index) + 1);
return {
...updatedDesignObject,
[key]: isActive ? designObject[key] : defaultValue,
};
}
delete updatedDesignObject[key];
return updatedDesignObject;
};
const LAYOUT_PARSE = computed(() => { const LAYOUT_PARSE = computed(() => {
return props.settings?.label ? getInputValue(props.settings.label, "OBJECT") : {}; return props.settings?.label ? getInputValue(props.settings.label, "OBJECT") : {};
}); });
@@ -210,7 +292,7 @@ const LAYOUT_PARSE = computed(() => {
const mapActivesToItems = (index: number) => { const mapActivesToItems = (index: number) => {
if (LAYOUT_PARSE.value && LAYOUT_PARSE.value.listCss) { if (LAYOUT_PARSE.value && LAYOUT_PARSE.value.listCss) {
return LAYOUT_PARSE.value.listCss[index] || {}; return LAYOUT_PARSE.value.listCss[index] || {};
} }
return {}; return {};
}; };
</script> </script>
@@ -219,15 +301,14 @@ const mapActivesToItems = (index: number) => {
<div class="section_layout border-custom" :class="[CLASS_FOR_SECTION.section_layout]" :style="LAYOUT_PARSE['div.section_layout']"> <div class="section_layout border-custom" :class="[CLASS_FOR_SECTION.section_layout]" :style="LAYOUT_PARSE['div.section_layout']">
<div <div
class="section_child" class="section_child"
v-for="(position, index) in props.content || Array(SETTING_OPTIONS.MAX_ELEMENT).fill({})" v-for="(position, index) in props.content || Array(SETTING_OPTIONS?.MAX_ELEMENT).fill({})"
:key="index" :key="index"
:class="['border-custom', CLASS_FOR_SECTION[index]]" :class="['border-custom', CLASS_FOR_SECTION[index]]"
:style="mapActivesToItems(index)['div.section_child']" :style="mapActivesToItems(index)['div.section_child']"
@dragover.prevent
@drop.stop.prevent="dropPlacementInSection($event, index, position.data)"
> >
<RecusiveSection :type="position.type" :id="position.data" :section="props.section" /> <RecusiveSection :type="position.type" :id="position.data" :section="props.section" />
</div> </div>
<div v-if="LAYOUT_PARSE['div.background']?.includes('display:block;')" class="attributeBackground" :style="LAYOUT_PARSE['div.background']"></div>
</div> </div>
</template> </template>
@@ -239,6 +320,29 @@ const mapActivesToItems = (index: number) => {
} }
.section_layout { .section_layout {
display: grid; display: grid;
position: relative;
.attributeBackground {
position: absolute;
height: 100%;
z-index: 0;
display: none;
left: -50vw;
width: 150vw;
}
.section_child {
z-index: 1;
}
.attributeBackground {
position: absolute;
height: 100%;
z-index: 0;
display: none;
left: -50vw;
width: 150vw;
}
&.smartphone_layout { &.smartphone_layout {
grid-template-columns: repeat(1, minmax(0, 1fr)) !important; grid-template-columns: repeat(1, minmax(0, 1fr)) !important;
} }
@@ -262,15 +366,57 @@ const mapActivesToItems = (index: number) => {
&.six_col_layout { &.six_col_layout {
grid-template-columns: repeat(6, minmax(0, 1fr)); grid-template-columns: repeat(6, minmax(0, 1fr));
} }
.col-span-2 { &.seven_col_layout {
grid-column: span 2 / span 2; grid-template-columns: repeat(7, minmax(0, 1fr));
} }
.col-span-3 { &.eight_col_layout {
grid-column: span 3 / span 3; grid-template-columns: repeat(8, minmax(0, 1fr));
} }
.col-span-4 { &.nine_col_layout {
grid-column: span 4 / span 4; grid-template-columns: repeat(9, minmax(0, 1fr));
} }
&.ten_col_layout {
grid-template-columns: repeat(10, minmax(0, 1fr));
}
&.eleven_col_layout {
grid-template-columns: repeat(11, minmax(0, 1fr));
}
&.twelve_col_layout {
grid-template-columns: repeat(12, minmax(0, 1fr));
}
// .col-span-2 {
// grid-column: span 2 / span 2;
// }
// .col-span-3 {
// grid-column: span 3 / span 3;
// }
// .col-span-4 {
// grid-column: span 4 / span 4;
// }
// .col-span-5 {
// grid-column: span 5 / span 5;
// }
// .col-span-6 {
// grid-column: span 6 / span 6;
// }
// .col-span-7 {
// grid-column: span 7 / span 7;
// }
// .col-span-8 {
// grid-column: span 8 / span 8;
// }
// .col-span-9 {
// grid-column: span 9 / span 9;
// }
// .col-span-10 {
// grid-column: span 10 / span 10;
// }
// .col-span-11 {
// grid-column: span 11 / span 11;
// }
// .col-span-12 {
// grid-column: span 12 / span 12;
// }
.border-custom { .border-custom {
border-color: #e5e5e5 !important; border-color: #e5e5e5 !important;
} }
@@ -0,0 +1,25 @@
<script setup lang="ts">
import DynamicLayout from '@/components/dynamic-page/page-section/layouts/index.vue';
import type { PageSection } from "@/server/models/dynamic-page/index";
const emit = defineEmits(["dropComponent", "dropData", "selectComponent"]);
const props = defineProps<{
label?: any;
layout?: string;
settings?: any;
content?: any;
section: PageSection;
}>();
</script>
<template>
<DynamicLayout :layout="props.layout" :content="props.content" :settings="props.settings" :section="props.section" />
</template>
<style lang="scss" scoped>
.border-custom {
border-color: #e5e5e5 !important;
}
</style>
@@ -1 +1,2 @@
export { default as Article_Section_Default } from './Default.vue' export { default as Article_Section_Default } from './Default.vue'
export { default as Article_Detail } from './Detail.vue'
@@ -1,5 +1,5 @@
<script lang="ts" setup> <script lang="ts" setup>
import { Article_Section_Default } from "./index"; import { Article_Section_Default, Article_Detail } from "./index";
import type { PageSection } from "@/server/models/dynamic-page/index"; import type { PageSection } from "@/server/models/dynamic-page/index";
import { enumPageSectionKey, enumPageSectionTemplate } from "@/definitions/enum"; import { enumPageSectionKey, enumPageSectionTemplate } from "@/definitions/enum";
@@ -10,7 +10,8 @@ const _props = defineProps<{
}>(); }>();
const definedDynamicSection: Record<string, any> = { const definedDynamicSection: Record<string, any> = {
[enumPageSectionTemplate[enumPageSectionKey.ARTICLE]['DEFAULT']]: Article_Section_Default, [`${enumPageSectionTemplate[enumPageSectionKey.ARTICLE]["DEFAULT"]}`]: Article_Section_Default,
[`${enumPageSectionTemplate[enumPageSectionKey.ARTICLE]["DETAIL"]}`]: Article_Detail,
}; };
const getCurrentSection = computed(() => _props.settings.template); const getCurrentSection = computed(() => _props.settings.template);
@@ -32,7 +33,11 @@ const GET_PROPS = computed(() => {
</script> </script>
<template> <template>
<component :is="definedDynamicSection[getCurrentSection]" v-bind="{ ...GET_PROPS(), section: _props.section, content: _props.content, settings: _props.settings }"> <component
v-if="definedDynamicSection[getCurrentSection]"
:is="definedDynamicSection[getCurrentSection]"
v-bind="{ ...GET_PROPS(), section: _props.section, content: _props.content, settings: _props.settings }"
>
<slot /> <slot />
</component> </component>
</template> </template>
@@ -0,0 +1 @@
export { default as Misses_Section } from './misses/index.vue'
@@ -0,0 +1,43 @@
<script lang="ts" setup>
import type { PageSection } from "@/server/models/dynamic-page/index";
import { enumPageSectionKey, enumPageSectionTemplate } from "@/definitions/enum";
import { Misses_Section } from "./index";
const _props = defineProps<{
settings?: any;
content?: any;
section: PageSection;
}>();
const definedDynamicSection: Record<string, any> = {
[enumPageSectionTemplate[enumPageSectionKey.CATEGORY]['MISSES']]: Misses_Section,
};
const getCurrentSection = computed(() => _props.settings.template);
const GET_PROPS = computed(() => {
return () => {
let props: any = {};
if (_props.settings) {
for (const [key, value] of Object.entries(_props.settings)) {
props = {
...props,
[key]: value,
};
}
}
return props;
};
});
</script>
<template>
<component
v-if="definedDynamicSection[getCurrentSection]"
:is="definedDynamicSection[getCurrentSection]"
v-bind="{ ...GET_PROPS(), section: _props.section, content: _props.content, settings: _props.settings }"
>
<slot />
</component>
</template>
@@ -0,0 +1,43 @@
<script setup lang="ts">
import DynamicLayout from '@/components/dynamic-page/page-section/layouts/index.vue';
import type { PageSection } from "@/server/models/dynamic-page/index";
const emit = defineEmits(["dropComponent", "dropData", "selectComponent"]);
const props = defineProps<{
label?: any;
layout?: string;
settings?: any;
content?: any;
section: PageSection;
}>();
</script>
<template>
<section>
<div>
<div>
<div>
<img class="w-full " src="~/assets/images/tienphong/MissCategory.png" alt="">
</div>
<div class="mt-3">
<template v-if="props.layout">
<DynamicLayout
:layout="props.layout"
:content="props.content"
:settings="props.settings"
:section="props.section"
/>
</template>
</div>
</div>
</div>
</section>
</template>
<style lang="scss" scoped>
.border-custom {
border-color: #e5e5e5 !important;
}
</style>
@@ -0,0 +1 @@
export { default as Default } from './Default.vue'
@@ -0,0 +1,43 @@
<script lang="ts" setup>
import type { PageSection } from "@/server/models/dynamic-page/index";
import { enumPageSectionKey, enumPageSectionTemplate } from "@/definitions/enum";
import { Default } from "./index";
const _props = defineProps<{
settings?: any;
content?: any;
section: PageSection;
}>();
const definedDynamicSection: Record<string, any> = {
[enumPageSectionTemplate[enumPageSectionKey.CATEGORY]['MISSES']]: Default,
};
const getCurrentSection = computed(() => _props.settings.template);
const GET_PROPS = computed(() => {
return () => {
let props: any = {};
if (_props.settings) {
for (const [key, value] of Object.entries(_props.settings)) {
props = {
...props,
[key]: value,
};
}
}
return props;
};
});
</script>
<template>
<component
v-if="definedDynamicSection[getCurrentSection]"
:is="definedDynamicSection[getCurrentSection]"
v-bind="{ ...GET_PROPS(), section: _props.section, content: _props.content, settings: _props.settings }"
>
<slot />
</component>
</template>
@@ -1 +1,3 @@
export { default as None_Section } from './none/index.vue' export { default as None_Section } from './none/index.vue'
export { default as Category_Section } from './category/index.vue'
export { default as Article_Section } from './articles/index.vue'
@@ -1,7 +1,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { PageSection } from "@/server/models/dynamic-page/index"; import type { PageSection } from "@/server/models/dynamic-page/index";
import { enumPageSectionKey } from "@/definitions/enum"; import { enumPageSectionKey } from "@/definitions/enum";
import { None_Section } from "./index"; import { None_Section,Category_Section, Article_Section } from "./index";
const _props = defineProps<{ const _props = defineProps<{
settings?: any; settings?: any;
@@ -11,6 +11,8 @@ const _props = defineProps<{
const definedDynamicSection: Record<string, any> = { const definedDynamicSection: Record<string, any> = {
[enumPageSectionKey.NONE]: None_Section, [enumPageSectionKey.NONE]: None_Section,
[enumPageSectionKey.CATEGORY]: Category_Section,
[enumPageSectionKey.ARTICLE]: Article_Section,
}; };
const getCurrentSection = computed(() => { const getCurrentSection = computed(() => {
@@ -34,7 +36,7 @@ const GET_PROPS = computed(() => {
</script> </script>
<template> <template>
<component :is="definedDynamicSection[getCurrentSection]" v-bind="{ ...GET_PROPS(), section: _props.section, content: _props.content, settings: _props.settings }"> <component v-if="definedDynamicSection[getCurrentSection]" :is="definedDynamicSection[getCurrentSection]" v-bind="{ ...GET_PROPS(), section: _props.section, content: _props.content, settings: _props.settings }">
<slot /> <slot />
</component> </component>
</template> </template>
@@ -32,7 +32,11 @@ const GET_PROPS = computed(() => {
</script> </script>
<template> <template>
<component :is="definedDynamicSection[getCurrentSection]" v-bind="{ ...GET_PROPS(), section: _props.section, content: _props.content, settings: _props.settings }"> <component
v-if="definedDynamicSection[getCurrentSection]"
:is="definedDynamicSection[getCurrentSection]"
v-bind="{ ...GET_PROPS(), section: _props.section, content: _props.content, settings: _props.settings }"
>
<slot /> <slot />
</component> </component>
</template> </template>
@@ -1,76 +0,0 @@
<script setup lang="ts">
import { getInputValue } from "@/utils/parseSQL";
const props = defineProps<{
layout?: any,
label?:any
}>()
const CLASS_FOR_LAYOUT = computed(() => {
let _classForLayout = {};
switch (props.layout) {
case 'Full_Page':
_classForLayout = {
page_container: 'page_container full-size-page',
layout_container: 'layout_container full-size-layout',
};
break;
case 'Center_Page':
_classForLayout = {
page_container: 'page_container full-size-page',
layout_container: 'layout_container center-layout',
};
break;
case 'Background_Page':
_classForLayout = {
page_container: 'page_container full-size-page background-container',
layout_container: 'layout_container center-layout',
};
break;
default:
_classForLayout = {
page_container: 'page_container',
layout_container: 'layout_container',
};
break;
}
return _classForLayout;
})
const LAYOUT_PARSE = computed(() => {
return props?.label ? getInputValue(props.label, "OBJECT") : {};
});
</script>
<template>
<div :class="[CLASS_FOR_LAYOUT.page_container]" :style="LAYOUT_PARSE['div.page_container']">
<div :class="[CLASS_FOR_LAYOUT.layout_container]" class="grid-container">
<slot />
</div>
</div>
</template>
<style lang="scss" scoped>
.page_container {
&.full-size-page {
width: 100%;
}
.full-size-layout {
padding-left: 20px;
padding-right: 20px;
}
}
.layout_container {
padding-top: 20px;
&.center-layout {
max-width: 1385px;
margin: auto;
}
}
.grid-container {
display: grid;
grid-template-columns: repeat(1, minmax(0, 1fr));
}
</style>
@@ -0,0 +1,76 @@
<script setup lang="ts">
import { getInputValue } from "@/utils/parseSQL";
import { enumPageLayouts, enumPageTemplate, enumPageKey } from "@/definitions/enum";
const props = defineProps<{
layout?: any,
label?:any
}>()
const CLASS_FOR_LAYOUT = computed(() => {
let _classForLayout = {};
switch (props.layout) {
case enumPageLayouts[enumPageTemplate[enumPageKey.HOME]['DEFAULT']]['DEFAULT']:
_classForLayout = {
page_container: "page_container full-size-page",
layout_container: "layout_container center-layout",
};
break;
case enumPageLayouts[enumPageTemplate[enumPageKey.HOME]['DEFAULT']]['FULL']:
_classForLayout = {
page_container: "page_container full-size-page",
layout_container: "layout_container full-size-layout",
};
break;
case enumPageLayouts[enumPageTemplate[enumPageKey.HOME]['DEFAULT']]['BACKGROUND_PAGE']:
_classForLayout = {
page_container: "page_container full-size-page background-container",
layout_container: "layout_container center-layout",
};
break;
default:
_classForLayout = {
page_container: "page_container",
layout_container: "layout_container",
};
break;
}
return _classForLayout;
});
</script>
<template>
<div :class="[CLASS_FOR_LAYOUT.page_container]">
<div :class="[CLASS_FOR_LAYOUT.layout_container]" class="grid-container">
<slot />
</div>
</div>
</template>
<style lang="scss" scoped>
.page_container {
// padding: 20px 0;
&.full-size-page {
width: 100%;
}
// .full-size-layout {
// padding-left: 20px;
// padding-right: 20px;
// }
}
.layout_container {
padding-top: 20px;
&.center-layout {
max-width: 1440px;
padding: 0 27.5px;
margin: auto;
}
}
.grid-container {
display: grid;
grid-template-columns: repeat(1, minmax(0, 1fr));
}
</style>
@@ -1,4 +1,4 @@
export { default as BASE_LAYOUT } from './Default.vue' export { default as Home_Default } from './homes/Default.vue'
// Article // Article
export { default as ARTICLE_LONG_LAYOUT } from './articles/Long.vue' export { default as ARTICLE_LONG_LAYOUT } from './articles/Long.vue'
+30 -35
View File
@@ -1,50 +1,45 @@
<script lang="ts" setup> <script lang="ts" setup>
import { layouts } from "@/definitions/enum"; import { enumPageKey, enumPageTemplate, enumPageLayouts } from "@/definitions/enum";
import { Home_Default, ARTICLE_LONG_LAYOUT, ARTICLE_NONE_LAYOUT, ARTICLE_NORMAL_LAYOUT, ARTICLE_PAGE_LAYOUT, ARTICLE_SHORT_LAYOUT } from "./index";
import {
BASE_LAYOUT,
ARTICLE_SHORT_LAYOUT,
ARTICLE_PAGE_LAYOUT,
ARTICLE_NORMAL_LAYOUT,
ARTICLE_NONE_LAYOUT,
ARTICLE_LONG_LAYOUT,
} from './index';
const _props = defineProps<{ const _props = defineProps<{
settings?: any, settings?: any;
}>() }>();
const definedDynamicPageLayout: Record<string, any> = { const definedDynamicPageLayout: Record<string, any> = {
'Default': BASE_LAYOUT, [enumPageLayouts[enumPageTemplate[enumPageKey.HOME]["DEFAULT"]]["DEFAULT"]]: Home_Default,
[layouts.FULL_PAGE]: BASE_LAYOUT, [enumPageLayouts[enumPageTemplate[enumPageKey.HOME]["DEFAULT"]]["FULL"]]: Home_Default,
[layouts.CENTER_PAGE]: BASE_LAYOUT, [enumPageLayouts[enumPageTemplate[enumPageKey.HOME]["DEFAULT"]]["BACKGROUND_PAGE"]]: Home_Default,
[layouts.BACKGROUND_PAGE]: BASE_LAYOUT,
'ARTICLE_SHORT': ARTICLE_SHORT_LAYOUT, [enumPageLayouts[enumPageTemplate[enumPageKey.ARTICLE]["DETAIL"]]["ARTICLE_SHORT"]]: ARTICLE_SHORT_LAYOUT,
'ARTICLE_PAGE': ARTICLE_PAGE_LAYOUT, [enumPageLayouts[enumPageTemplate[enumPageKey.ARTICLE]["DETAIL"]]["ARTICLE_PAGE"]]: ARTICLE_PAGE_LAYOUT,
'ARTICLE_NORMAL': ARTICLE_NORMAL_LAYOUT, [enumPageLayouts[enumPageTemplate[enumPageKey.ARTICLE]["DETAIL"]]["ARTICLE_NORMAL"]]: ARTICLE_NORMAL_LAYOUT,
'ARTICLE_NONE': ARTICLE_NONE_LAYOUT, [enumPageLayouts[enumPageTemplate[enumPageKey.ARTICLE]["DETAIL"]]["ARTICLE_NONE"]]: ARTICLE_NONE_LAYOUT,
'ARTICLE_LONG': ARTICLE_LONG_LAYOUT, [enumPageLayouts[enumPageTemplate[enumPageKey.ARTICLE]["DETAIL"]]["ARTICLE_LONG"]]: ARTICLE_LONG_LAYOUT,
} };
const getCurrentLayout = computed(() => _props.settings.layout); const getCurrentLayout = computed(() => _props.settings?.layout);
const GET_PROPS = computed(() => { const GET_PROPS = computed(() => {
return () => { return () => {
let props: any = {}; let props: any = {};
for (const [key, value] of Object.entries(_props.settings)) { for (const [key, value] of Object.entries(_props.settings)) {
props = { props = {
...props, ...props,
[key]: value [key]: value,
} };
} }
return props; return props;
}; };
}) });
</script> </script>
<template> <template>
<component :is="definedDynamicPageLayout[getCurrentLayout]" v-bind="GET_PROPS()"> <component
v-if="definedDynamicPageLayout[getCurrentLayout]"
:is="definedDynamicPageLayout[getCurrentLayout]"
v-bind="GET_PROPS()"
>
<slot /> <slot />
</component> </component>
</template> </template>
@@ -9,7 +9,7 @@ const props = defineProps<{
</script> </script>
<template> <template>
<div class="h-100 overflow-y-auto"> <div class="h-full overflow-y-auto">
<HeaderHomeTemplate /> <HeaderHomeTemplate />
<DynamicLayout :settings="props.settings"> <DynamicLayout :settings="props.settings">
<slot /> <slot />
@@ -0,0 +1 @@
export { default as DetailDefault } from './DetailDefault.vue';
@@ -0,0 +1,37 @@
<script lang="ts" setup>
import { DetailDefault } from './index';
import { enumPageKey, enumPageTemplate } from "@/definitions/enum";
const _props = defineProps<{
settings: any
}>()
const definedDynamicPage: Record<string, any> = {
[enumPageTemplate[enumPageKey.ARTICLE]['DETAIL']]: DetailDefault,
}
const getCurrentTemplate = computed(() => {
return _props.settings?.template || '';
});
const GET_PROPS = computed(() => {
return () => {
let props : any = {};
if (_props.settings) {
for (const [key, value] of Object.entries(_props.settings)) {
props = {
...props,
[key]: value
}
}
}
return props;
};
})
</script>
<template>
<component v-if="definedDynamicPage[getCurrentTemplate]" :is="definedDynamicPage[getCurrentTemplate]" v-bind="{...(GET_PROPS()), settings: _props.settings}">
<slot />
</component>
</template>
@@ -4,57 +4,56 @@ import { enumPageComponentLayouts, enumPageComponentTemplate, enumPageComponentK
</script> </script>
<template> <template>
<footer id="footer" class="main-footer"> <footer id="footer" class="main-footer mt-20">
<div class="main-footer-container"> <div class="main-footer-container">
<div class="footer-centertab"> <div class="footer-centertab">
<div> <div class="footer-navigation-container md:block hidden">
<div class="footer-navigation-container">
<div> <div>
<AssignComponent :type="enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.NAVIGATION]['BOTTOM']}`]['NAVIGATION_BOTTOM_DEFAULT']" /> <AssignComponent :type="enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.NAVIGATION]['BOTTOM']}`]['NAVIGATION_BOTTOM_DEFAULT']" />
</div> </div>
</div> </div>
<div class="footer-contact-container"> <div class="footer-contact-container md:grid-cols-2 grid-cols-1">
<div> <div class="md:order-1 order-2">
<h3>BÁO GIẤY</h3> <h3 class="md:text-left text-center">BÁO GIẤY</h3>
<div class="footer-contact"> <div class="footer-contact">
<div> <div class="md:justify-start justify-center">
<div> <div>
<span><Icon name="material-symbols:call-outline" /></span> <span><Icon name="material-symbols:call-outline" /></span>
<span>024.39434341</span> <span>0123456789</span>
</div> </div>
<div> <div>
<span><Icon name="material-symbols:mail-outline" /></span> <span><Icon name="material-symbols:mail-outline" /></span>
<span>toasoan@baotienphong.vn</span> <span>toasoan@vpress.vn</span>
</div> </div>
</div> </div>
<div class="footer-contact-buynow"> <div class="footer-contact-buynow md:justify-start justify-center">
<img src="~/assets/images/tienphong/muabaogiay-footer.png" alt="" /> <img src="~/assets/images/tienphong/muabaogiay-footer.png" alt="" />
</div> </div>
</div> </div>
</div> </div>
<div> <div class="md:order-2 order-1">
<h3>THEO DÕI TRÊN MẠNG HỘI</h3> <h3 class="md:text-left text-center md:!border-#3d3d3d !border-transparent">THEO DÕI TRÊN MẠNG HỘI</h3>
<div class="footer-socials"> <div class="footer-socials">
<div> <div class="md:grid lg:grid-cols-2 md:grid-cols-1 flex md:gap-50px gap-32px md:justify-start justify-center">
<div> <div class="xl:gap-22px gap-6px">
<span><Icon name="ic:baseline-facebook" /></span> <span><Icon name="ic:baseline-facebook" /></span>
<span>facebook.com/baotienphong</span> <span class="md:inline hidden whitespace-normal">facebook.com/vpress</span>
</div> </div>
<div> <div class="xl:gap-22px gap-6px">
<span><Icon name="uil:youtube" /></span> <span><Icon name="uil:youtube" /></span>
<span>youtube.com/baotienphong</span> <span class="md:inline hidden whitespace-normal">youtube.com/vpress</span>
</div> </div>
<div> <div class="xl:gap-22px gap-6px">
<span><Icon name="ic:baseline-tiktok" /></span> <span><Icon name="ic:baseline-tiktok" /></span>
<span>tiktok.com/baotienphong</span> <span class="md:inline hidden whitespace-normal">tiktok.com/vpress</span>
</div> </div>
<div> <div class="xl:gap-22px gap-6px">
<span><Icon name="arcticons:zalo" /></span> <span><Icon name="arcticons:zalo" /></span>
<span>zalo.vn/baotienphong</span> <span class="md:inline hidden whitespace-normal">zalo.vn/vpress</span>
</div> </div>
</div> </div>
</div> </div>
@@ -62,19 +61,19 @@ import { enumPageComponentLayouts, enumPageComponentTemplate, enumPageComponentK
</div> </div>
<div class="footer-ads"> <div class="footer-ads">
<h3>LIÊN HỆ QUẢNG CÁO</h3> <h3 class="md:text-left text-center">LIÊN HỆ QUẢNG CÁO</h3>
<div class="footer-ads-container"> <div class="footer-ads-container flex-wrap lg:gap-60px gap-20px md:flex-row flex-col">
<div class="align-items-center"> <div class="align-items-center">
<span><Icon name="material-symbols:call-outline" /></span> <span><Icon name="material-symbols:call-outline" /></span>
<span class="flex flex-column"> <span class="flex flex-column">
<span>024.39434340</span> <span>0123456789 - </span>
<span>0909559988</span> <span>0123456789</span>
</span> </span>
</div> </div>
<div> <div>
<span><Icon name="material-symbols:mail-outline" /></span> <span><Icon name="material-symbols:mail-outline" /></span>
<span>kinhdoanh@baotienphong.vn</span> <span>kinhdoanh@vpress.vn</span>
</div> </div>
<div class="button-ads-price"> <div class="button-ads-price">
<span><Icon name="ic:outline-format-list-bulleted" /></span> <span><Icon name="ic:outline-format-list-bulleted" /></span>
@@ -82,41 +81,36 @@ import { enumPageComponentLayouts, enumPageComponentTemplate, enumPageComponentK
</div> </div>
</div> </div>
</div> </div>
</div>
</div> </div>
</div> </div>
<div class="footer-bottomtab"> <div class="footer-bottomtab">
<div> <div class="flex justify-between items-end">
<div> <div class="flex-1 flex md:justify-start justify-center">
<div class="flex justify-between items-end">
<div class="w-1/2">
<div> <div>
<img src="~/assets/images/tienphong/logo-footer.png" alt="" /> <img class="w-200px" src="~/assets/images/tienphong/logo.png" alt="" />
</div> </div>
</div> </div>
<div class="footer-bottomtab-relations w-1/2"> <div class="footer-bottomtab-relations">
<img src="~/assets/images/tienphong/sinhvien-logo.png" alt="" /> <!-- <img src="~/assets/images/tienphong/sinhvien-logo.png" alt="" />
<img src="~/assets/images/tienphong/hht-online-logo.png" alt="" /> <img src="~/assets/images/tienphong/hht-online-logo.png" alt="" />
<img src="~/assets/images/tienphong/tamviet-logo.png" alt="" /> <img src="~/assets/images/tienphong/tamviet-logo.png" alt="" /> -->
</div> </div>
</div> </div>
<div class="flex justify-between items-end footer-bottomtab-description"> <div class="flex justify-between md:flex-row flex-col gap-20px footer-bottomtab-description md:text-left text-center">
<div class="w-1/2 space-y-10px"> <div class="flex-1 space-y-10px">
<p>© Bản quyền thuộc báo điện tử <span class="fw-bold">Tiền Phong</span></p> <p>© Bản quyền thuộc báo điện tử <span class="fw-bold">....</span></p>
<p><span class="fw-bold">Tổng Biên tập</span>: XUÂN SƠN</p> <p><span class="fw-bold">Tổng Biên tập</span>: ...</p>
<p>Tòa soạn: 15 Hồ Xuân Hương, Nội - Điện thoại: 024.39431250</p> <p>Tòa soạn: Nội - Điện thoại: 0123456789</p>
<p>Email: <span class="fw-bold">online.baotienphong@gmail.com</span> - Hotline: <span class="fw-bold">0865.015.015 - 0977.456.112</span></p> <p>Email: <span class="fw-bold">online.vpress@gmail.com</span> - Hotline: <span class="fw-bold">0123456789</span></p>
</div> </div>
<div class="w-1/2 space-y-10px"> <div class="flex-1 space-y-10px">
<p>Giấy phép số <span class="fw-bold">76/GP-BTTTT</span>, cấp ngày 26/02/2020.</p> <p>Giấy phép số <span class="fw-bold">...</span>, cấp ngày ....</p>
<p> quan chủ quản: <span class="fw-bold">Trung ương Đoàn TNCS Hồ Chí Minh</span></p> <p> quan chủ quản: <span class="fw-bold">....</span></p>
<p>Cấm sao chép dưới mọi hình thức nếu không sự chấp thuận bằng văn bản</p> <p>Cấm sao chép dưới mọi hình thức nếu không sự chấp thuận bằng văn bản</p>
<p>Powered by Hemera Media</p> <p>Powered by VPress</p>
</div> </div>
</div> </div>
</div>
</div>
</div> </div>
</footer> </footer>
</template> </template>
@@ -125,16 +119,17 @@ import { enumPageComponentLayouts, enumPageComponentTemplate, enumPageComponentK
.main-footer { .main-footer {
.main-footer-container { .main-footer-container {
background: #2b2b2b; background: #2b2b2b;
padding: 54px 15px 20px 15px; padding: 54px 0 32px 0;
} }
.footer-centertab { .footer-centertab {
margin: 0 auto; margin: 0 auto;
max-width: 1385px; max-width: 1440px;
padding: 0 27.5px;
> div { > div {
max-width: 1145px; // max-width: 1145px;
margin-left: auto; // margin-left: auto;
padding: 0 33px; // padding: 0 33px;
} }
.footer-navigation-container { .footer-navigation-container {
@@ -147,7 +142,7 @@ import { enumPageComponentLayouts, enumPageComponentTemplate, enumPageComponentK
.footer-contact-container { .footer-contact-container {
display: grid; display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr)); // grid-template-columns: repeat(2, minmax(0, 1fr));
margin-top: 22px; margin-top: 22px;
gap: 60px; gap: 60px;
border-bottom: 1px solid #ed1c24; border-bottom: 1px solid #ed1c24;
@@ -189,13 +184,13 @@ import { enumPageComponentLayouts, enumPageComponentTemplate, enumPageComponentK
.footer-socials { .footer-socials {
margin-top: 20px; margin-top: 20px;
> div { > div {
display: grid; // display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr)); // grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 55px; // gap: 55px;
> div { > div {
display: flex; display: flex;
align-items: flex-end; align-items: flex-end;
gap: 22px; // gap: 22px;
} }
span { span {
color: #ffffff; color: #ffffff;
@@ -213,7 +208,7 @@ import { enumPageComponentLayouts, enumPageComponentTemplate, enumPageComponentK
> div { > div {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 60px; // gap: 60px;
> div { > div {
display: flex; display: flex;
align-items: flex-end; align-items: flex-end;
@@ -262,18 +257,19 @@ import { enumPageComponentLayouts, enumPageComponentTemplate, enumPageComponentK
.footer-bottomtab { .footer-bottomtab {
width: 100%; width: 100%;
padding: 5px 15px; // padding: 5px 15px;
> div { > div {
margin: 0 auto; margin: 0 auto;
max-width: 1385px; max-width: 1440px;
padding: 0 27.5px;
> div { > div {
max-width: 1145px; // max-width: 1145px;
margin-left: auto; // margin-left: auto;
padding: 0 33px; // padding: 0 33px;
} }
} }
padding: 0 33px; // padding: 0 33px;
padding-bottom: 80px; padding-bottom: 80px;
padding-top: 24px; padding-top: 24px;
.footer-bottomtab-relations { .footer-bottomtab-relations {
@@ -8,23 +8,23 @@ const currentDateTime = ref<string>("");
onMounted(() => { onMounted(() => {
currentDateTime.value = dayjs().format("dddd, DD/MM/YYYY, HH:mm"); currentDateTime.value = dayjs().format("dddd, DD/MM/YYYY, HH:mm");
}); });
const showMenuMobile = ref(false)
</script> </script>
<template> <template>
<header id="header" class="main-header"> <header id="header" class="main-header">
<div class="main-header-topbar "> <div class="main-header-topbar lg:block hidden">
<div class="flex items-center !py-3px"> <div class="flex items-center !py-3px">
<time class="text-capitalize text-white text-12px" :datetime="currentDateTime">{{ currentDateTime }} GMT+7</time> <time class="text-capitalize text-white text-12px" :datetime="currentDateTime">{{ currentDateTime }} GMT+7</time>
<div class="main-header-topbar-listag"> <div class="main-header-topbar-listag"></div>
</div>
<div class="main-header-topbar-infor flex items-center"> <div class="main-header-topbar-infor flex items-center">
<div> <div>
<div class="text-white text-12px"> <div class="text-white text-12px">
<span>HOTLINE: </span> <span>HOTLINE: </span>
<a href="tel:0865015015"> 0865.015.015</a> <a href="tel:0865015015"> 0123456789</a>
<span> - </span> <span> - </span>
<a href="tel:0977456112">0977.456.112</a> <a href="tel:0977456112">0123456789</a>
</div> </div>
</div> </div>
<div class="flex items-center"> <div class="flex items-center">
@@ -34,16 +34,16 @@ onMounted(() => {
</div> </div>
</div> </div>
</div> </div>
<div class="main-header-centerbar"> <div class="main-header-centerbar lg:block hidden">
<div class="flex items-center"> <div class="flex items-center">
<div class="main-header-logo"> <div class="main-header-logo">
<img src="~/assets/images/tienphong/logo.png" alt="logo"> <nuxt-link to="/"><img class="w-200px" src="~/assets/images/tienphong/logo.png" alt="logo" /></nuxt-link>
</div> </div>
<div class="main-header-control"> <div class="main-header-control">
<div class="main-header-relations"> <div class="main-header-relations">
<img src="~/assets/images/tienphong/sinhvien-logo.png" alt=""> <!-- <img src="~/assets/images/tienphong/sinhvien-logo.png" alt="">
<img src="~/assets/images/tienphong/hht-online-logo.png" alt=""> <img src="~/assets/images/tienphong/hht-online-logo.png" alt="">
<img src="~/assets/images/tienphong/tamviet-logo.png" alt=""> <img src="~/assets/images/tienphong/tamviet-logo.png" alt=""> -->
</div> </div>
<div class="main-header-navbar"> <div class="main-header-navbar">
<AssignComponent :type="enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.NAVIGATION]['TOP']}`]['NAVIGATION_TOP_DEFAULT']" /> <AssignComponent :type="enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.NAVIGATION]['TOP']}`]['NAVIGATION_TOP_DEFAULT']" />
@@ -51,16 +51,16 @@ onMounted(() => {
</div> </div>
</div> </div>
</div> </div>
<div class="main-ads"> <div class="main-ads lg:block hidden">
<div class="main-ads-container"> <div class="main-ads-container py-20px border-y-1px border-#000">
<div class="main-ads-content"> <div class="main-ads-content">
<img src="~/assets/images/tienphong/main-ads.png" alt=""> <img src="~/assets/images/tienphong/main-ads.png" alt="" />
</div> </div>
</div> </div>
</div> </div>
<div class="main-header-control"> <div class="main-header-control lg:block hidden">
<div class="header-control-container !py-2"> <div class="header-control-container">
<div> <div class="border-b-1px border-#000 py-2">
<div class="header-control_tag"> <div class="header-control_tag">
<label>Xu hướng</label> <label>Xu hướng</label>
</div> </div>
@@ -72,22 +72,67 @@ onMounted(() => {
<Icon name="material-symbols-light:search" /> <Icon name="material-symbols-light:search" />
</div> </div>
<div> <div>
<img src="http://picsum.photos/1024/600?random=1" width="40" height="40" class="rounded-circle" alt=""> <img src="http://picsum.photos/1024/600?random=1" width="40" height="40" class="rounded-circle" alt="" />
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="main-header-mobile px-3 lg:hidden block">
<div class="flex items-center justify-between py-4 border-b-1px border-solid border-#000">
<div class="main-header-mobile-logo">
<nuxt-link to="/"><img class="w-128px" src="~/assets/images/tienphong/logo.png" alt="logo" /></nuxt-link>
</div>
<div class="main-header-mobile-control flex gap-20px">
<button class="bg-transparent" @click="showMenuMobile = true">
<svg width="21" height="17" viewBox="0 0 21 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M0 0.75C0 0.375 0.328125 0 0.75 0H20.25C20.625 0 21 0.375 21 0.75C21 1.17188 20.625 1.5 20.25 1.5H0.75C0.328125 1.5 0 1.17188 0 0.75ZM0 8.25C0 7.875 0.328125 7.5 0.75 7.5H20.25C20.625 7.5 21 7.875 21 8.25C21 8.67188 20.625 9 20.25 9H0.75C0.328125 9 0 8.67188 0 8.25ZM20.25 16.5H0.75C0.328125 16.5 0 16.1719 0 15.75C0 15.375 0.328125 15 0.75 15H20.25C20.625 15 21 15.375 21 15.75C21 16.1719 20.625 16.5 20.25 16.5Z"
fill="black"
/>
</svg>
</button>
<button class="bg-transparent">
<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M23.7656 22.7344L17.1094 16.125C18.6094 14.3906 19.4531 12.1875 19.4531 9.75C19.4531 4.40625 15.0469 0 9.70312 0C4.3125 0 0 4.40625 0 9.75C0 15.1406 4.35938 19.5 9.70312 19.5C12.0938 19.5 14.2969 18.6562 16.0312 17.1562L22.6406 23.8125C22.8281 23.9531 23.0156 24 23.25 24C23.4375 24 23.625 23.9531 23.7656 23.8125C24.0469 23.5312 24.0469 23.0156 23.7656 22.7344ZM9.75 18C5.15625 18 1.5 14.2969 1.5 9.75C1.5 5.20312 5.15625 1.5 9.75 1.5C14.2969 1.5 18 5.20312 18 9.75C18 14.3438 14.2969 18 9.75 18Z" fill="black"/>
</svg>
</button>
</div>
</div>
</div>
<!-- navigation header -->
<div class="main-header-mobile-navigation fixed inset-0 bg-white z-999" v-if="showMenuMobile">
<div class="main-header-mobile px-3">
<div class="flex items-center justify-between py-4">
<div class="main-header-mobile-logo" @click="showMenuMobile = false">
<nuxt-link to="/"><img class="w-128px" src="~/assets/images/tienphong/logo.png" alt="logo" /></nuxt-link>
</div>
<div class="main-header-mobile-control flex gap-20px">
<button class="bg-transparent" @click="showMenuMobile = false">
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="m12 13.4l-4.9 4.9q-.275.275-.7.275t-.7-.275t-.275-.7t.275-.7l4.9-4.9l-4.9-4.9q-.275-.275-.275-.7t.275-.7t.7-.275t.7.275l4.9 4.9l4.9-4.9q.275-.275.7-.275t.7.275t.275.7t-.275.7L13.4 12l4.9 4.9q.275.275.275.7t-.275.7t-.7.275t-.7-.275z"/></svg>
</button>
</div>
</div>
</div>
<div class="p-3">
<AssignComponent :type="enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.NAVIGATION]['TOP']}`]['NAVIGATION_TOP_DEFAULT']" />
</div>
</div>
</header> </header>
</template> </template>
<style lang="scss" scoped> <style lang="scss">
.main-header { .main-header {
.main-header-topbar { .main-header-topbar {
background: #ED1C24; background: #ed1c24;
>div { > div {
max-width: 1385px; max-width: 1385px;
padding: 5px 15px; padding: 5px 20px;
margin: 0 auto; margin: 0 auto;
justify-content: space-between; justify-content: space-between;
} }
@@ -110,9 +155,9 @@ onMounted(() => {
.main-header-centerbar { .main-header-centerbar {
padding: 20px 0px; padding: 20px 0px;
> div { > div {
max-width: 1385px; max-width: 1440px;
margin: 0 auto; margin: 0 auto;
padding: 0px 15px; padding: 0px 27.5px;
} }
.main-header-control { .main-header-control {
flex: 1; flex: 1;
@@ -128,15 +173,17 @@ onMounted(() => {
} }
} }
.main-ads { .main-ads {
max-width: 1385px; max-width: 1440px;
margin: 0px auto; margin: 0px auto;
padding: 20px 0px; padding: 0px 27.5px;
border-top: 1px solid #000000; // border-top: 1px solid #000000;
border-bottom: 1px solid #000000; // border-bottom: 1px solid #000000;
.main-ads-content { .main-ads-content {
width: 970px; width: 100%;
height: 250px; max-width: 970px;
// height: 250px;
text-align: center; text-align: center;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -147,10 +194,10 @@ onMounted(() => {
} }
.main-header-control { .main-header-control {
.header-control-container { .header-control-container {
max-width: 1385px; max-width: 1440px;
margin: 0px auto 10px auto; margin: 0px auto 10px auto;
padding: 10px 0px; padding: 0 27.5px;
border-bottom: 1px solid #000000; // border-bottom: 1px solid #000000;
> div { > div {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -164,27 +211,27 @@ onMounted(() => {
position: relative; position: relative;
height: 30px; height: 30px;
label { label {
font-size: 12px; font-size: 12px;
text-transform: uppercase; text-transform: uppercase;
padding: 0 16px 0 12px; padding: 0 16px 0 12px;
display: flex; display: flex;
align-items: center; align-items: center;
height: 100%; height: 100%;
margin: 0; margin: 0;
border: 1px solid #000; border: 1px solid #000;
line-height: 1.8; line-height: 1.8;
font-weight: 300; font-weight: 300;
}
&::after {
position: absolute;
content: "";
display: block;
width: 12px;
height: 100%;
background-color: #ed1c24;
left: -12px;
top: 0;
} }
&::after {
position: absolute;
content: "";
display: block;
width: 12px;
height: 100%;
background-color: #ed1c24;
left: -12px;
top: 0;
}
} }
&_article { &_article {
flex: 1; flex: 1;
@@ -211,5 +258,45 @@ onMounted(() => {
} }
} }
} }
.main-header-mobile-navigation {
& > div > nav > div {
justify-content: flex-start;
}
& .navigation-container {
flex-direction: column;
gap: 0px;
width: 100%;
align-items: start;
& > .navigation-branch {
width: 100%;
border-top: 1px solid #dee2e6;
&:first-child {
border: transparent;
}
& > .navigation-item {
width: 100%;
height: 100%;
& > a {
font-family: "Gelasio", serif !important;
text-transform: uppercase;
font-weight: 800!important;
display: block;
font-size: 16px;
padding: 8px 0;
width: 100%;
height: 100%;
}
}
}
}
}
} }
</style> </style>
@@ -2,22 +2,19 @@
import DynamicLayout from "~/components/dynamic-page/page/layouts/index.vue"; import DynamicLayout from "~/components/dynamic-page/page/layouts/index.vue";
import HeaderHomeTemplate from "~/components/dynamic-page/page/templates/components/headers/HeaderHomeTemplate.vue"; import HeaderHomeTemplate from "~/components/dynamic-page/page/templates/components/headers/HeaderHomeTemplate.vue";
import FooterHomeTemplate from "~/components/dynamic-page/page/templates/components/footers/FooterHomeTemplate.vue"; import FooterHomeTemplate from "~/components/dynamic-page/page/templates/components/footers/FooterHomeTemplate.vue";
const props = defineProps<{
settings?: any;
}>();
const props = defineProps<{
settings?: any
}>()
</script> </script>
<template> <template>
<div> <div class="h-full overflow-y-auto">
<HeaderHomeTemplate> <HeaderHomeTemplate />
<DynamicLayout :settings="props.settings"> <DynamicLayout :settings="props.settings">
<slot /> <slot />
</DynamicLayout> </DynamicLayout>
</HeaderHomeTemplate> <FooterHomeTemplate />
<DynamicLayout :settings="props.settings"> </div>
<slot />
</DynamicLayout>
<FooterHomeTemplate />
</div>
</template> </template>
@@ -0,0 +1 @@
export { default as Home } from './Home.vue';
@@ -0,0 +1,37 @@
<script lang="ts" setup>
import { Home } from './index';
import { enumPageKey, enumPageTemplate } from "@/definitions/enum";
const _props = defineProps<{
settings: any
}>()
const definedDynamicPage: Record<string, any> = {
[enumPageTemplate[enumPageKey.HOME]['DEFAULT']]: Home,
}
const getCurrentTemplate = computed(() => {
return _props.settings?.template || '';
});
const GET_PROPS = computed(() => {
return () => {
let props : any = {};
if (_props.settings) {
for (const [key, value] of Object.entries(_props.settings)) {
props = {
...props,
[key]: value
}
}
}
return props;
};
})
</script>
<template>
<component v-if="definedDynamicPage[getCurrentTemplate]" :is="definedDynamicPage[getCurrentTemplate]" v-bind="{...(GET_PROPS()), settings: _props.settings}">
<slot />
</component>
</template>
@@ -1 +1,2 @@
export { default as HomeBasic } from './homes/Basic.vue' export { default as Home } from './homes/index.vue'
export { default as Article } from './articles/index.vue'
@@ -1,38 +1,45 @@
<script lang="ts" setup> <script lang="ts" setup>
import { HomeBasic } from './index'; import { Home, Article } from "./index";
import type { Page } from "@/models/cms";
import { enumPageKey } from "@/definitions/enum";
const _props = defineProps<{ const _props = defineProps<{
settings: any settings: any;
}>() page: Page;
}>();
const definedDynamicPage: Record<string, any> = { const definedDynamicPage: Record<string, any> = {
'Home' : HomeBasic, [enumPageKey.HOME]: Home,
'Article': HomeBasic [enumPageKey.ARTICLE]: Article,
} };
const getCurrentTemplate = computed(() => { const getCurrentTemplate = computed(() => {
return _props.settings && _props.settings.template || ''; return _props.page?.taxonomy || "";
}); });
const GET_PROPS = computed(() => { const GET_PROPS = computed(() => {
return () => { return () => {
let props : any = {}; let props: any = {};
if (_props.settings) { if (_props.settings) {
for (const [key, value] of _props.settings ? Object.entries(_props.settings) : []) { for (const [key, value] of Object.entries(_props.settings)) {
props = { props = {
...props, ...props,
[key]: value [key]: value,
} };
} }
} }
return props; return props;
}; };
}) });
</script> </script>
<template> <template>
<component :is="definedDynamicPage[getCurrentTemplate] || null" v-bind="{...(GET_PROPS()), settings: _props.settings}"> <component
class="overflow-x-hidden"
v-if="definedDynamicPage[getCurrentTemplate]"
:is="definedDynamicPage[getCurrentTemplate]"
v-bind="{...(GET_PROPS()), settings: _props.settings}"
>
<slot /> <slot />
</component> </component>
</template> </template>
+80
View File
@@ -0,0 +1,80 @@
<script setup lang="ts">
const props = defineProps<{
SCRIPT_ID?: any,
SCRIPT_SRC?: any,
CONTAINER_ID?: any,
options?: any,
inside?: boolean,
widgetKey?: any
}>()
const widgets : any = {};
const instance = getCurrentInstance();
const canUseDOM = () => {
return typeof window !== 'undefined' && window.document && window.document.createElement;
};
const getScriptElement = () => {
return document.getElementById(props.SCRIPT_ID);
}
const updateOnloadListener = (onload : any) => {
const script : any = getScriptElement();
const oldOnload = script.onload;
return script.onload = () => {
oldOnload();
onload();
};
}
const scriptExists = () => {
return getScriptElement() !== null;
}
const appendScript = (onload : any) => {
if (!canUseDOM()) {
onload();
return;
}
if (scriptExists()) {
if (typeof window[props.widgetKey] === 'undefined') {
updateOnloadListener(onload);
return;
}
onload();
return;
}
const script = document.createElement('script');
script.id = props.SCRIPT_ID;
script.type = 'text/javascript';
script.async = true;
script.src = props.SCRIPT_SRC;
script.onload = onload;
if (props.inside) document.getElementById(props.CONTAINER_ID) && document.getElementById(props.CONTAINER_ID).appendChild(script);
else {
document.getElementsByTagName('body')[0].appendChild(script);
}
}
const initWidget = (key: any) => {
if (typeof widgets[key].key === 'undefined') {
return;
}
widgets[key].script()
}
onMounted(async () => {
await Object.assign(widgets, {
FireAnt: {
script: () => new window.FireAnt.MarketsWidget({ container_id: props.CONTAINER_ID, ...props.options }),
key: window.FireAnt
},
TradingView: {
script: () => new window.TradingView.widget({ container_id: props.CONTAINER_ID, ...props.options }),
key: window.TradingView
}
})
appendScript(initWidget(props.widgetKey));
})
</script>
<template>
<div :key="props.CONTAINER_ID" :id="props.CONTAINER_ID"></div>
</template>
+33
View File
@@ -0,0 +1,33 @@
// <div class="tradingview-widget-container">
// <script type="text/javascript" src="https://s3.tradingview.com/external-embedding/embed-widget-ticker-tape.js" async>
// {
// "symbols": [
// {
// "proName": "FOREXCOM:SPXUSD",
// "title": "S&P 500 Index"
// },
// {
// "proName": "FOREXCOM:NSXUSD",
// "title": "US 100 Cash CFD"
// },
// {
// "proName": "FX_IDC:EURUSD",
// "title": "EUR to USD"
// },
// {
// "proName": "BITSTAMP:BTCUSD",
// "title": "Bitcoin"
// },
// {
// "proName": "BITSTAMP:ETHUSD",
// "title": "Ethereum"
// }
// ],
// "showSymbolLogo": true,
// "isTransparent": false,
// "displayMode": "adaptive",
// "colorTheme": "dark",
// "locale": "en"
// }
// </script>
// </div>
+5 -2
View File
@@ -35,11 +35,13 @@ export {
pageTypes, pageTypes,
pageComponentTypes, pageComponentTypes,
pageSectionTypes, pageSectionTypes,
pageTaxonomy,
pageDataQuery, pageDataQuery,
pageDataType, pageDataType,
pageLayouts,
/* PAGE SETTINGS */
pageTaxonomy,
pageTemplates, pageTemplates,
pageLayouts,
/* SECTION SETTINGS */ /* SECTION SETTINGS */
pageSectionTaxonomy, pageSectionTaxonomy,
@@ -50,6 +52,7 @@ export {
pageComponentTaxonomy, pageComponentTaxonomy,
pageComponentTemplates, pageComponentTemplates,
pageComponentLayouts, pageComponentLayouts,
} from "./page.type"; } from "./page.type";
export { placementType } from "./placement.type"; export { placementType } from "./placement.type";
export { pollType, pollParticipantType, pollOptionType, pollResultPublication } from "./poll.type"; export { pollType, pollParticipantType, pollOptionType, pollResultPublication } from "./poll.type";
-232
View File
@@ -1,232 +0,0 @@
import { enumPageComponentLayouts, enumPageSectionLayouts, templates, enumPageComponentKey, enumPageComponentTemplate, enumPageSectionKey, enumPageSectionTemplate } from "@/definitions/enum";
export const pageTypes = [
{ title: "None", value: 0 }, // Không xác định
{ title: "Home", value: 1 }, // Trang chủ
{ title: "Section", value: 2 }, // Chuyên trang
{ title: "Category", value: 3 }, // Trang danh mục
{ title: "Topic", value: 4 }, // Trang chủ đề
{ title: "Event", value: 5 }, // Trang sự kiện
{ title: "Collection", value: 6 }, // Trang sưu tập
{ title: "Article", value: 7 }, // Trang bài viết
{ title: "Tag", value: 8 }, // Trang từ khóa
{ title: "Author", value: 9 }, // Trang tác giả
{ title: "Search", value: 10 }, // Trang tìm kiếm
{ title: "Contact", value: 11 }, // Trang liên hệ
{ title: "About", value: 12 }, // Trang giới thiệu
{ title: "Service", value: 13 }, // Trang dịch vụ
{ title: "Policy", value: 14 }, // Trang chính sách
{ title: "Terms", value: 15 }, // Trang điều khoản
{ title: "Privacy", value: 16 }, // Trang bảo mật
{ title: "Error", value: 97 }, // Trang lỗi
{ title: "Maintenance", value: 98 }, // Trang bảo trì
{ title: "Custom", value: 99 }, // Trang tùy chỉnh
];
// LayoutType: None=0 | Normal=1 | Short=2 | Long=3 | Page=4
export const pageLayouts = (key: string) => {
if (key === templates.ARTICLE) {
return [
{ title: "None", key: 0, value: "ARTICLE_NONE" },
{ title: "Normal", key: 1, value: "ARTICLE_NORMAL" },
{ title: "Short", key: 2, value: "ARTICLE_SHORT" },
{ title: "Long", key: 3, value: "ARTICLE_LONG" },
{ title: "Page", key: 4, value: "ARTICLE_PAGE" },
];
} else {
return [
{ title: "None", value: 0 },
{ title: "Cơ bản", value: "Default" },
{ title: "Full Page", value: "Full_Page" }, // full with 100%
{ title: "Center Page", value: "Center_Page" }, // ở giữa
{ title: "Backgroud Page", value: "Backgroud_Page" }, // Phân trang
];
}
};
export const pageTemplates = [
{ title: "None", value: "None" }, // Không xác định
{ title: "Home", value: "Home" }, // Trang chủ
{ title: "Section", value: "Section" }, // Chuyên trang
{ title: "Category", value: "Category" }, // Trang danh mục
{ title: "Topic", value: "Topic" }, // Trang chủ đề
{ title: "Event", value: "Event" }, // Trang sự kiện
{ title: "Collection", value: "Collection" }, // Trang sưu tập
{ title: "Article", value: "Article" }, // Trang bài viết
{ title: "Tag", value: "Tag" }, // Trang từ khóa
{ title: "Author", value: "Author" }, // Trang tác giả
{ title: "Search", value: "Search" }, // Trang tìm kiếm
{ title: "Contact", value: "Contact" }, // Trang liên hệ
{ title: "About", value: "About" }, // Trang giới thiệu
{ title: "Service", value: "Service" }, // Trang dịch vụ
{ title: "Policy", value: "Policy" }, // Trang chính sách
{ title: "Terms", value: "Terms" }, // Trang điều khoản
{ title: "Privacy", value: "Privacy" }, // Trang bảo mật
{ title: "Error", value: "Error" }, // Trang lỗi
{ title: "Maintenance", value: "Maintenance" }, // Trang bảo trì
{ title: "Custom", value: "Custom" }, // Trang tùy chỉnh
];
export const pageComponentTypes = [
{ title: "None", value: 0 }, // Không xác định
{ title: "Individual", value: 1 }, // Đơn lẻ
{ title: "Collection", value: 2 }, // Sưu tập
{ title: "Pagination", value: 3 }, // Phân trang
];
export const pageSectionTypes = [
{ title: "None", value: 0 }, // Không xác định
{ title: "Block", value: 1 }, // Khối
];
export const pageDataType = [
{ title: "Section", value: "Section" },
{ title: "Category", value: "Category" },
{ title: "Topic", value: "Topic" },
{ title: "Event", value: "Event" },
{ title: "Collection", value: "Collection" },
{ title: "Article", value: "Article" },
{ title: "Tag", value: "Tag" },
{ title: "Author", value: "Author" },
{ title: "Poll", value: "Poll" },
{ title: "Quiz", value: "Quiz" },
{ title: "Survey", value: "Survey" },
{ title: "Advertising", value: "Advertising" },
{ title: "Other", value: "Other" },
];
export const pageDataQuery = [
{ title: "IDS", value: "IDS" },
{ title: "NEW", value: "NEW" },
{ title: "VIEW", value: "VIEW" },
{ title: "SQL", value: "SQL" },
{ title: "REQUEST", value: "REQUEST" },
];
export const pageTaxonomy = [
{ title: "Home", value: "Home" }, // Trang khác
{ title: "Section", value: "Section" }, // Chuyên trang
{ title: "Category", value: "Category" }, // Trang danh mục
{ title: "Topic", value: "Topic" }, // Trang chủ đề
{ title: "Event", value: "Event" }, // Trang sự kiện
{ title: "Collection", value: "Collection" }, // Trang sưu tập
{ title: "Article", value: "Article" }, // Trang bài viết
{ title: "Tag", value: "Tag" }, // Trang từ khóa
{ title: "Author", value: "Author" }, // Trang tác giả
{ title: "Poll", value: "Poll" }, // Trang poll
{ title: "Quiz", value: "Quiz" }, // Trang quiz
{ title: "Survey", value: "Survey" }, // Trang survey
{ title: "Advertising", value: "Advertising" }, // Trang quảng cáo
{ title: "Other", value: "Other" }, // Trang khác
{ title: "Navigation", value: "Navigation" }, // Navigation
];
/* SECTION SETTINGS */
export const pageSectionTaxonomy = [
{ title: "None", value: "None" }, // Phân vùng của Chuyên trang
{ title: "Section", value: "Section" }, // Phân vùng của Chuyên trang
{ title: "Category", value: "Category" }, // Phân vùng của Trang danh mục
{ title: "Topic", value: "Topic" }, // Phân vùng của Trang chủ đề
{ title: "Event", value: "Event" }, // Phân vùng của Trang sự kiện
{ title: "Collection", value: "Collection" }, // Phân vùng của Trang sưu tập
{ title: "Article", value: "Article" }, // Phân vùng của Trang bài viết
{ title: "Tag", value: "Tag" }, // Phân vùng của Trang từ khóa
{ title: "Author", value: "Author" }, // Phân vùng của Trang tác giả
{ title: "Poll", value: "Poll" }, // Phân vùng của Trang poll
{ title: "Quiz", value: "Quiz" }, // Phân vùng của Trang quiz
{ title: "Survey", value: "Survey" }, // Phân vùng của Trang survey
{ title: "Advertising", value: "Advertising" }, // Phân vùng của Trang quảng cáo
{ title: "Other", value: "Other" }, // Phân vùng của Trang khác
{ title: "Navigation", value: "Navigation" }, // Phân vùng của Navigation
];
export const pageSectionTempaltes = {
[enumPageSectionKey.NONE]: [
{ title: "Thẻ trống", value: enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE'] },
],
};
export const pageSectionLayouts = {
[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]: [
{ title: "2 Cột", value: enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_TWO'] },
{ title: "2 Cột, bên trái rộng", value: enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_LEFT_TWO'] },
{ title: "2 Cột, bên phải rộng", value: enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_RIGHT_TWO'] },
{ title: "3 Cột", value: enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_THREE'] },
{ title: "4 Cột", value: enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_FOUR'] },
{ title: "4 Cột, giữa 2 cột", value: enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_CENTER_TWO'] },
{ title: "5 Cột, giữa 3 cột", value: enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_CENTER_THREE'] },
{ title: "6 Cột, giữa 4 cột", value: enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['VERTICAL_CENTER_FOUR'] },
{ title: "1 Hàng", value: enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_ONE'] },
{ title: "2 Hàng", value: enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_TWO'] },
{ title: "3 Hàng", value: enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_THREE'] },
{ title: "4 Hàng", value: enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_FOUR'] },
{ title: "5 Hàng", value: enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_FIVE'] },
{ title: "6 Hàng", value: enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_SIX'] },
{ title: "7 Hàng", value: enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_SEVEN'] },
{ title: "8 Hàng", value: enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_EIGHT'] },
{ title: "9 Hàng", value: enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_NINE'] },
{ title: "10 Hàng", value: enumPageSectionLayouts[enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']]['HORIZONTAL_TEN'] }
],
};
/* COMPONENT SETTINGS */
export const pageComponentTaxonomy = [
{ title: "Section", value: "Section" }, // Component loại Chuyên trang
{ title: "Category", value: "Category" }, // Component loại danh mục
{ title: "Topic", value: "Topic" }, // Component loại chủ đề
{ title: "Event", value: "Event" }, // Component loại sự kiện
{ title: "Collection", value: "Collection" }, // Component loại sưu tập
{ title: "Article", value: "Article" }, // Component loại bài viết
{ title: "Tag", value: "Tag" }, // Component loại từ khóa
{ title: "Author", value: "Author" }, // Component loại tác giả
{ title: "Poll", value: "Poll" }, // Component loại poll
{ title: "Quiz", value: "Quiz" }, // Component loại quiz
{ title: "Survey", value: "Survey" }, // Trang survey
{ title: "Advertising", value: "Advertising" }, // Component loại quảng cáo
{ title: "Other", value: "Other" }, // Component loại khác
{ title: "Navigation", value: "Navigation" }, // Component loại Navigation
];
export const pageComponentTemplates = {
[`${enumPageComponentKey.ARTICLE}`]: [
{ title: "Thẻ bài viết", value: enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_CARD'] },
{ title: "Chi tiết bài viết", value: enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_DETAIL'] },
],
[`${enumPageComponentKey.OTHER}`]: [
{ title: "Thời tiết", value: enumPageComponentTemplate[enumPageComponentKey.OTHER]['WEATHER'] },
{ title: "Chứng khoán", value: enumPageComponentTemplate[enumPageComponentKey.OTHER]['SECURITIES'] },
],
[`${enumPageComponentKey.ADVERTISING}`]: [
{ title: "Quảng cáo", value: enumPageComponentTemplate[enumPageComponentKey.ADVERTISING]['ADVERTISING'] },
],
};
export const pageComponentLayouts = {
[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_CARD']]: [
{ title: "Thẻ bài viết cơ bản", value: enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_CARD']]['CARD_DEFAULT'] },
{ title: "Thẻ bài viết audio ", value: enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_CARD']]['CARD_AUDIO'] }
// { title: "Thẻ bài viết hình ảnh ", value: enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_CARD']]['CARD_AUDIO'] },
// { title: "Thẻ bài viết có lồng chữ trong ảnh", value: '2' },
// { title: "Thẻ bài viết Video", value: '3' },
// { title: "Thẻ bài viết Audio", value: '4' },
],
[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_DETAIL']]: [
{ title: "Chi tiết bài viết", value: enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_DETAIL']]['DETAIL_GENERAL'] },
{ title: "Chi tiết podcast", value: enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_DETAIL']]['DETAIL_PODCAST'] },
{ title: "Chi tiết video", value: enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_DETAIL']]['DETAIL_VIDEO'] },
{ title: "Chi tiết image", value: enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_DETAIL']]['DETAIL_IMAGE'] },
// { title: "Chi tiết bài viết cơ bản", value: '1' },
// { title: "Chi tiết bài viết Video", value: '2' },
// { title: "Chi tiết bài viết Podcast ", value: '3' },
// { title: "Chi tiết bài viết Image ", value: '4' },
],
[enumPageComponentTemplate[enumPageComponentKey.OTHER]['WEATHER']]: [
{ title: "Thời tiết", value: enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.OTHER]['WEATHER']]['WEATHER_DEFAULT'] }
],
[enumPageComponentTemplate[enumPageComponentKey.OTHER]['SECURITIES']]: [
{ title: "Chứng khoán", value: enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.OTHER]['SECURITIES']]['SECURITIES_DEFAULT'] }
],
[enumPageComponentTemplate[enumPageComponentKey.ADVERTISING]['ADVERTISING']]: [
{ title: "Quảng cáo", value: enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ADVERTISING]['ADVERTISING']]['ADVERTISING_DEFAULT'] }
],
};
+52 -51
View File
@@ -1,4 +1,4 @@
import { enumPageComponentLayouts, enumPageSectionLayouts, templates, enumPageComponentKey, enumPageComponentTemplate, enumPageSectionKey, enumPageSectionTemplate } from "@/definitions/enum"; import { enumPageKey, enumPageTemplate, enumPageLayouts, enumPageComponentLayouts, enumPageSectionLayouts, enumPageComponentKey, enumPageComponentTemplate, enumPageSectionKey, enumPageSectionTemplate } from "@/definitions/enum";
export const pageTypes = [ export const pageTypes = [
{ title: "None", value: 0 }, // Không xác định { title: "None", value: 0 }, // Không xác định
@@ -24,49 +24,6 @@ export const pageTypes = [
]; ];
// LayoutType: None=0 | Normal=1 | Short=2 | Long=3 | Page=4 // LayoutType: None=0 | Normal=1 | Short=2 | Long=3 | Page=4
export const pageLayouts = (key: string) => {
if (key === templates.ARTICLE) {
return [
{ title: "None", key: 0, value: "ARTICLE_NONE" },
{ title: "Normal", key: 1, value: "ARTICLE_NORMAL" },
{ title: "Short", key: 2, value: "ARTICLE_SHORT" },
{ title: "Long", key: 3, value: "ARTICLE_LONG" },
{ title: "Page", key: 4, value: "ARTICLE_PAGE" },
];
} else {
return [
{ title: "None", value: 0 },
{ title: "Cơ bản", value: "Default" },
{ title: "Full Page", value: "Full_Page" }, // full with 100%
{ title: "Center Page", value: "Center_Page" }, // ở giữa
{ title: "Backgroud Page", value: "Backgroud_Page" }, // Phân trang
];
}
};
export const pageTemplates = [
{ title: "None", value: "None" }, // Không xác định
{ title: "Home", value: "Home" }, // Trang chủ
{ title: "Section", value: "Section" }, // Chuyên trang
{ title: "Category", value: "Category" }, // Trang danh mục
{ title: "Topic", value: "Topic" }, // Trang chủ đề
{ title: "Event", value: "Event" }, // Trang sự kiện
{ title: "Collection", value: "Collection" }, // Trang sưu tập
{ title: "Article", value: "Article" }, // Trang bài viết
{ title: "Tag", value: "Tag" }, // Trang từ khóa
{ title: "Author", value: "Author" }, // Trang tác giả
{ title: "Search", value: "Search" }, // Trang tìm kiếm
{ title: "Contact", value: "Contact" }, // Trang liên hệ
{ title: "About", value: "About" }, // Trang giới thiệu
{ title: "Service", value: "Service" }, // Trang dịch vụ
{ title: "Policy", value: "Policy" }, // Trang chính sách
{ title: "Terms", value: "Terms" }, // Trang điều khoản
{ title: "Privacy", value: "Privacy" }, // Trang bảo mật
{ title: "Error", value: "Error" }, // Trang lỗi
{ title: "Maintenance", value: "Maintenance" }, // Trang bảo trì
{ title: "Custom", value: "Custom" }, // Trang tùy chỉnh
];
export const pageComponentTypes = [ export const pageComponentTypes = [
{ title: "None", value: 0 }, // Không xác định { title: "None", value: 0 }, // Không xác định
{ title: "Individual", value: 1 }, // Đơn lẻ { title: "Individual", value: 1 }, // Đơn lẻ
@@ -103,6 +60,7 @@ export const pageDataQuery = [
{ title: "REQUEST", value: "REQUEST" }, { title: "REQUEST", value: "REQUEST" },
]; ];
/* PAGE SETTINGS */
export const pageTaxonomy = [ export const pageTaxonomy = [
{ title: "Home", value: "Home" }, // Trang khác { title: "Home", value: "Home" }, // Trang khác
{ title: "Section", value: "Section" }, // Chuyên trang { title: "Section", value: "Section" }, // Chuyên trang
@@ -121,6 +79,31 @@ export const pageTaxonomy = [
{ title: "Navigation", value: "Navigation" }, // Navigation { title: "Navigation", value: "Navigation" }, // Navigation
]; ];
export const pageTemplates = {
[enumPageKey.HOME]: [
{ title: "Trang chủ - Báo Tiền Phong", value: enumPageTemplate[enumPageKey.HOME]['DEFAULT'] },
{ title: "Trang chủ - Báo Kinh tế đô thị", value: enumPageTemplate[enumPageKey.HOME]['DEFAULT'] },
],
[enumPageKey.ARTICLE]: [
{ title: "Chi tiết bài viết", value: enumPageTemplate[enumPageKey.ARTICLE]['DETAIL'] },
],
};
export const pageLayouts = {
[enumPageTemplate[enumPageKey.HOME]['DEFAULT']]: [
{ title: "Giới hạn chiều rộng", value: enumPageLayouts[enumPageTemplate[enumPageKey.HOME]['DEFAULT']]['DEFAULT'] },
{ title: "Không giới hạn chiều rộng", value: enumPageLayouts[enumPageTemplate[enumPageKey.HOME]['DEFAULT']]['FULL'] },
{ title: "Giới hạn chiều rộng có Quảng cáo", value: enumPageLayouts[enumPageTemplate[enumPageKey.HOME]['DEFAULT']]['BACKGROUND_PAGE'] },
],
[enumPageTemplate[enumPageKey.ARTICLE]['DETAIL']]: [
{ title: "Không có", value: enumPageLayouts[enumPageTemplate[enumPageKey.ARTICLE]['DETAIL']]['ARTICLE_NONE'] },
{ title: "Bài viết thường", value: enumPageLayouts[enumPageTemplate[enumPageKey.ARTICLE]['DETAIL']]['ARTICLE_NORMAL'] },
{ title: "Bài viết ngắn", value: enumPageLayouts[enumPageTemplate[enumPageKey.ARTICLE]['DETAIL']]['ARTICLE_SHORT'] },
{ title: "Bài viết dài", value: enumPageLayouts[enumPageTemplate[enumPageKey.ARTICLE]['DETAIL']]['ARTICLE_LONG'] },
{ title: "Bài viết toàn trang", value: enumPageLayouts[enumPageTemplate[enumPageKey.ARTICLE]['DETAIL']]['ARTICLE_PAGE'] },
],
};
/* SECTION SETTINGS */ /* SECTION SETTINGS */
export const pageSectionTaxonomy = [ export const pageSectionTaxonomy = [
{ title: "None", value: "None" }, // Phân vùng của Chuyên trang { title: "None", value: "None" }, // Phân vùng của Chuyên trang
@@ -146,9 +129,10 @@ export const pageSectionTempaltes = {
], ],
[enumPageSectionKey.ARTICLE]: [ [enumPageSectionKey.ARTICLE]: [
{ title: "Phân vùng bài viết cơ bản", value: enumPageSectionTemplate[enumPageSectionKey.ARTICLE]['DEFAULT'] }, { title: "Phân vùng bài viết cơ bản", value: enumPageSectionTemplate[enumPageSectionKey.ARTICLE]['DEFAULT'] },
{ title: "Thẻ bài viết chi tiết", value: enumPageSectionTemplate[enumPageSectionKey.ARTICLE]['DETAIL'] },
], ],
[enumPageSectionKey.SECTION]: [ [enumPageSectionKey.CATEGORY]: [
{ title: "Phân vùng Hoa hậu", value: enumPageSectionTemplate[enumPageSectionKey.SECTION]['MISSES'] }, { title: "Phân vùng Hoa hậu", value: enumPageSectionTemplate[enumPageSectionKey.CATEGORY]['MISSES'] },
], ],
}; };
@@ -158,6 +142,10 @@ export const pageSectionLayouts = {
{ title: "Trái 1 Cột, giữa 2 Cột, phải 3 Cột", value: enumPageSectionLayouts[`${enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']}`]['VERTICAL_ONE_TWO_THREE'] }, { title: "Trái 1 Cột, giữa 2 Cột, phải 3 Cột", value: enumPageSectionLayouts[`${enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']}`]['VERTICAL_ONE_TWO_THREE'] },
{ title: "2 Cột, bên trái rộng", value: enumPageSectionLayouts[`${enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']}`]['VERTICAL_LEFT_TWO'] }, { title: "2 Cột, bên trái rộng", value: enumPageSectionLayouts[`${enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']}`]['VERTICAL_LEFT_TWO'] },
{ title: "6 Cột, phải 5 cột", value: enumPageSectionLayouts[`${enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']}`]['VERTICAL_ONE_FIVE'] }, { title: "6 Cột, phải 5 cột", value: enumPageSectionLayouts[`${enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']}`]['VERTICAL_ONE_FIVE'] },
{ title: "5-3-2-2", value: enumPageSectionLayouts[`${enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']}`]['VERTICAL_FIVE_THREE_TWO_TWO'] },
{ title: "5-2-2-3", value: enumPageSectionLayouts[`${enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']}`]['VERTICAL_FIVE_TWO_TWO_THREE'] },
{ title: "2-5-3-2", value: enumPageSectionLayouts[`${enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']}`]['VERTICAL_TWO_FIVE_THREE_TWO'] },
{ title: "5 Cột, phải 4 cột", value: enumPageSectionLayouts[`${enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']}`]['VERTICAL_ONE_FOUR'] },
{ title: "2 Cột, bên phải rộng", value: enumPageSectionLayouts[`${enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']}`]['VERTICAL_RIGHT_TWO'] }, { title: "2 Cột, bên phải rộng", value: enumPageSectionLayouts[`${enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']}`]['VERTICAL_RIGHT_TWO'] },
{ title: "3 Cột", value: enumPageSectionLayouts[`${enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']}`]['VERTICAL_THREE'] }, { title: "3 Cột", value: enumPageSectionLayouts[`${enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']}`]['VERTICAL_THREE'] },
{ title: "4 Cột", value: enumPageSectionLayouts[`${enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']}`]['VERTICAL_FOUR'] }, { title: "4 Cột", value: enumPageSectionLayouts[`${enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']}`]['VERTICAL_FOUR'] },
@@ -175,8 +163,12 @@ export const pageSectionLayouts = {
{ title: "9 Hàng", value: enumPageSectionLayouts[`${enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']}`]['HORIZONTAL_NINE'] }, { title: "9 Hàng", value: enumPageSectionLayouts[`${enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']}`]['HORIZONTAL_NINE'] },
{ title: "10 Hàng", value: enumPageSectionLayouts[`${enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']}`]['HORIZONTAL_TEN'] } { title: "10 Hàng", value: enumPageSectionLayouts[`${enumPageSectionTemplate[enumPageSectionKey.NONE]['NONE']}`]['HORIZONTAL_TEN'] }
], ],
[`${enumPageSectionTemplate[enumPageSectionKey.SECTION]['MISSES']}`]: [ [`${enumPageSectionTemplate[enumPageSectionKey.CATEGORY]['MISSES']}`]: [
{ title: "Cơ bản", value: enumPageSectionLayouts[`${enumPageSectionTemplate[enumPageSectionKey.SECTION]['MISSES']}`]['DEFAULT'] }, { title: "Cơ bản", value: enumPageSectionLayouts[`${enumPageSectionTemplate[enumPageSectionKey.CATEGORY]['MISSES']}`]['DEFAULT'] },
],
[`${enumPageSectionTemplate[enumPageSectionKey.ARTICLE]['DETAIL']}`]: [
{ title: "Cơ bản", value: enumPageSectionLayouts[`${enumPageSectionTemplate[enumPageSectionKey.ARTICLE]['DETAIL']}`]['DEFAULT'] },
], ],
}; };
@@ -210,6 +202,7 @@ export const pageComponentTemplates = {
], ],
[`${enumPageComponentKey.COLLECTION}`]: [ [`${enumPageComponentKey.COLLECTION}`]: [
{ title: "Bộ sưu tập bài viết", value: enumPageComponentTemplate[enumPageComponentKey.COLLECTION]['ARTICLE'] }, { title: "Bộ sưu tập bài viết", value: enumPageComponentTemplate[enumPageComponentKey.COLLECTION]['ARTICLE'] },
{ title: "Bộ sưu tập danh mục", value: enumPageComponentTemplate[enumPageComponentKey.COLLECTION]['CATEGORY'] },
], ],
[`${enumPageComponentKey.SECTION}`]: [ [`${enumPageComponentKey.SECTION}`]: [
{ title: "Bộ phân trang bài viết", value: enumPageComponentTemplate[enumPageComponentKey.SECTION]['ARTICLE'] }, { title: "Bộ phân trang bài viết", value: enumPageComponentTemplate[enumPageComponentKey.SECTION]['ARTICLE'] },
@@ -222,7 +215,7 @@ export const pageComponentTemplates = {
], ],
[`${enumPageComponentKey.OTHER}`]: [ [`${enumPageComponentKey.OTHER}`]: [
{ title: "Thời tiết", value: enumPageComponentTemplate[enumPageComponentKey.OTHER]['WEATHER'] }, { title: "Thời tiết", value: enumPageComponentTemplate[enumPageComponentKey.OTHER]['WEATHER'] },
{ title: "Chứng khoán", value: enumPageComponentTemplate[enumPageComponentKey.OTHER]['SECURITIES'] }, { title: "Chứng khoán", value: enumPageComponentTemplate[enumPageComponentKey.OTHER]['STOCK'] },
], ],
}; };
@@ -232,12 +225,15 @@ export const pageComponentLayouts = {
{ title: "Thẻ bài viết Audio", value: enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_CARD']}`]['CARD_AUDIO'] }, { title: "Thẻ bài viết Audio", value: enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_CARD']}`]['CARD_AUDIO'] },
{ title: "Thẻ bài viết Video", value: enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_CARD']}`]['CARD_VIDEO'] }, { title: "Thẻ bài viết Video", value: enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_CARD']}`]['CARD_VIDEO'] },
{ title: "Thẻ bài viết Video Hightlight", value: enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_CARD']}`]['CARD_VIDEO_HIGHLIGHT'] }, { title: "Thẻ bài viết Video Hightlight", value: enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_CARD']}`]['CARD_VIDEO_HIGHLIGHT'] },
{ title: "Thẻ bài viết Hoa hậu Hightlight", value: enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_CARD']}`]['CARD_MISS_HIGHLIGHT'] },
], ],
[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_DETAIL']]: [ [enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_DETAIL']]: [
{ title: "Chi tiết bài viết", value: enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_DETAIL']]['DETAIL_GENERAL'] }, { title: "Chi tiết bài viết", value: enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_DETAIL']]['DETAIL_GENERAL'] },
{ title: "Chi tiết bài Podcast", value: enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_DETAIL']]['DETAIL_PODCAST'] }, { title: "Chi tiết bài Podcast", value: enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_DETAIL']]['DETAIL_PODCAST'] },
{ title: "Chi tiết bài Video", value: enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_DETAIL']]['DETAIL_VIDEO'] }, { title: "Chi tiết bài Video", value: enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_DETAIL']]['DETAIL_VIDEO'] },
{ title: "Chi tiết bài Image", value: enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_DETAIL']]['DETAIL_IMAGE'] }, { title: "Chi tiết bài Image", value: enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_DETAIL']]['DETAIL_IMAGE'] },
{ title: "Chi tiết bài eMagazine", value: enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_DETAIL']]['DETAIL_EMAGAZINE'] },
{ title: "Chi tiết bài Inforgraphic", value: enumPageComponentLayouts[enumPageComponentTemplate[enumPageComponentKey.ARTICLE]['ARTICLE_DETAIL']]['DETAIL_INFOGRAPHIC'] },
], ],
/* NAVIGATION */ /* NAVIGATION */
[`${enumPageComponentTemplate[enumPageComponentKey.NAVIGATION]['TOP']}`]: [ [`${enumPageComponentTemplate[enumPageComponentKey.NAVIGATION]['TOP']}`]: [
@@ -254,6 +250,10 @@ export const pageComponentLayouts = {
[`${enumPageComponentTemplate[enumPageComponentKey.COLLECTION]['ARTICLE']}`]: [ [`${enumPageComponentTemplate[enumPageComponentKey.COLLECTION]['ARTICLE']}`]: [
{ title: "Thẻ bài viết cơ bản", value: enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.COLLECTION]['ARTICLE']}`]['ARTICLE_COLLECTION_DEFAULT'] }, { title: "Thẻ bài viết cơ bản", value: enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.COLLECTION]['ARTICLE']}`]['ARTICLE_COLLECTION_DEFAULT'] },
{ title: "Thẻ bài viết Audio", value: enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.COLLECTION]['ARTICLE']}`]['ARTICLE_COLLECTION_AUDIO'] }, { title: "Thẻ bài viết Audio", value: enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.COLLECTION]['ARTICLE']}`]['ARTICLE_COLLECTION_AUDIO'] },
{ title: "Thẻ bài viết Video", value: enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.COLLECTION]['ARTICLE']}`]['ARTICLE_COLLECTION_VIDEO'] },
],
[`${enumPageComponentTemplate[enumPageComponentKey.COLLECTION]['CATEGORY']}`]: [
{ title: "Hoa hậu - Cơ bản", value: enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.COLLECTION]['CATEGORY']}`]['MISSES_COLLECTION_DEFAULT'] },
], ],
/* SECTION */ /* SECTION */
@@ -277,7 +277,8 @@ export const pageComponentLayouts = {
[`${enumPageComponentTemplate[enumPageComponentKey.OTHER]['WEATHER']}`]: [ [`${enumPageComponentTemplate[enumPageComponentKey.OTHER]['WEATHER']}`]: [
{ title: "Thời tiết", value: enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.OTHER]['WEATHER']}`]['WEATHER_DEFAULT'] } { title: "Thời tiết", value: enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.OTHER]['WEATHER']}`]['WEATHER_DEFAULT'] }
], ],
[`${enumPageComponentTemplate[enumPageComponentKey.OTHER]['SECURITIES']}`]: [ [`${enumPageComponentTemplate[enumPageComponentKey.OTHER]['STOCK']}`]: [
{ title: "Chứng khoán", value: enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.OTHER]['SECURITIES']}`]['SECURITIES_DEFAULT'] } { title: "Chứng khoán", value: enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.OTHER]['STOCK']}`]['STOCK_DEFAULT'] },
{ title: "Chứng khoán Full Size", value: enumPageComponentLayouts[`${enumPageComponentTemplate[enumPageComponentKey.OTHER]['STOCK']}`]['STOCK_FULLSIZE'] }
], ],
}; };
+3 -2
View File
@@ -1,9 +1,10 @@
export { PublishTypes as publishTypes, sharingTypes } from "./publishTypes.enum"; export { PublishTypes as publishTypes, sharingTypes } from "./publishTypes.enum";
export { categoryTypes } from "./categoryTypes.enum"; export { categoryTypes } from "./categoryTypes.enum";
export { export {
templates, layouts, dataTypes, dataQuery, sectionTypes, sectionTaxonomy, enumPageType, enumPageSectionLayouts, enumPageComponentLayouts, enumPageComponentTemplates, enumPageComponentStaticChild, dataTypes, dataQuery, sectionTypes, sectionTaxonomy, enumPageType, enumPageSectionLayouts, enumPageComponentLayouts, enumPageComponentTemplates, enumPageComponentStaticChild,
dataTypeSort, dataTypeKeyInSort, dataTypeKeyInWith, dataSelectQuery, dataTypeTTL, dataMethodRequest, dataDesignLayout, dataBorderDesign, dataHideDesign, dataFontWeightDesign, dataPaddingDesign, dataTypeSort, dataTypeKeyInSort, dataTypeKeyInWith, dataSelectQuery, dataTypeTTL, dataMethodRequest, dataDesignLayout, dataBorderDesign, dataHideDesign, dataFontWeightDesign, dataPaddingDesign,
enumPageComponentKey, enumPageComponentTemplate, dataStaticType, enumPageSectionKey, enumPageSectionTemplate, enumPageComponentDefaultSetting enumPageComponentKey, enumPageComponentTemplate, dataStaticType, enumPageSectionKey, enumPageSectionTemplate, enumPageComponentDefaultSetting, enumPageComponentDefaultStyle,
enumPageKey, enumPageTemplate, enumPageLayouts
} from "./page.enum"; } from "./page.enum";
export { enumStatus } from "./status.enum"; export { enumStatus } from "./status.enum";
export { actionCommands } from "./actionCommands.enum"; export { actionCommands } from "./actionCommands.enum";

Some files were not shown because too many files have changed in this diff Show More