This commit is contained in:
MoreStrive
2024-05-31 00:49:26 +07:00
18 changed files with 793 additions and 467 deletions
@@ -1,237 +1,69 @@
<script setup lang="ts">
</script>
<template>
<div>
useCmsPageStore
</div>
<footer class="border-t bg-white mt-6">
<div id="footer-desktop" class="px-4 mx-auto max-w-7xl 2xl:px-0 pt-4">
<div class="grid gap-4 font-semibold md:grid-cols-12 text-sm mb-2">
<div class="col-span-8">
<div class="grid grid-cols-2 md:grid-cols-3 gap-4">
</div>
</div>
<div class="col-span-4 grid gap-4 sm:border-l sm:pl-4 auto-rows-max">
<div>
<p class="mb-2 uppercase text-xl font-bold">Liên hệ</p>
<div class="flex flex-col gap-3 whitespace-nowrap">
<div class="flex items-center max-w-full gap-2">
<Icon name="fa6-solid:building" />
<span class="text-sm hover-underline" title="Trụ sở chính: T.5 93A, Thụy Khuê, TP.Hà Nội">Toà Soạn</span>
</div>
<div class="flex items-center max-w-full gap-2">
<Icon name="fa6-solid:envelope" />
<a href="mailto:ktdtonline@gmail.com" class="text-sm hover-underline">
contact@vpress.vn
</a>
</div>
<div class="flex items-center max-w-full gap-2">
<Icon name="fa6-solid:handshake" />
<span class="text-sm">Hợp tác bản quyền</span>
</div>
</div>
</div>
<div>
<p class="mb-2 text-neutral-500">Đường dây nóng</p>
<div class="flex flex-col lg:(flex-row justify-between)">
<div class="flex flex-col">
<span class="text-lg font-bold tracking-wide">0123456789</span>
<p class="text-sm text-neutral-500">( Nội)</p>
</div>
<div class="flex flex-col">
<span class="text-lg font-bold tracking-wide">0123456789</span>
<p class="text-sm text-neutral-500">(Hồ Chí Minh)</p>
</div>
</div>
</div>
</div>
</div>
<hr />
<div class="flex flex-col items-center justify-between gap-4 my-2 sm:flex-row">
<div class="flex items-center justify-center sm:order-1">
<span>Hệ thống đang chạy thử nghiệm</span>
</div>
<div class="flex items-center justify-center gap-4 sm:order-3">
<a href="https://www.facebook.com" title="Theo dõi chúng tôi trên facebook" class="grid duration-300 border rounded-full w-9 h-9 border-neutral-200 text-neutral-500 place-items-center hover:bg-blue-500 hover:text-white hover:border-blue-500">
<Icon name="fa6-brands:facebook-f" />
</a>
<a href="https://www.youtube.com" title="Theo dõi chúng tôi trên youtube" class="grid duration-300 border rounded-full w-9 h-9 border-neutral-200 text-neutral-500 place-items-center hover:bg-black hover:text-white hover:border-black">
<Icon name="ion:logo-youtube" />
</a>
<a href="https://www.tiktok.com" title="Theo dõi chúng tôi trên tiktok" class="grid border rounded-full w-9 h-9 border-neutral-200 text-neutral-500 place-items-center hover:bg-black hover:text-white hover:border-black">
<Icon name="fa6-brands:tiktok" />
</a>
</div>
<div class="flex items-center justify-center gap-4 sm:ml-auto sm:order-2">
<a href="#!" class="text-sm lg:text-base text-neutral-500">RSS</a>
</div>
</div>
<hr />
</div>
</footer>
</template>
<style lang="scss" scoped>
.col-span-8 {
grid-column: span 8 / span 8;
@media (max-width: 1150px) {
grid-column: span 7 / span 7;
}
}
.col-span-12 {
grid-column: span 12 / span 12 !important;
}
.mbootom-5 {
margin-bottom: 5px;
}
.mbootom-14 {
margin-bottom: 14px;
}
.text-neutral-500 {
color: #737373;
}
.grid-col-2 {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px;
&.grid-col-1 {
grid-template-columns: repeat(1, minmax(0, 1fr));
}
}
.flex-col {
display: flex;
flex-direction: column;
.text-span {
font-size: 1rem;
line-height: 1.75rem;
font-weight: 700;
letter-spacing: 0.025em;
flex: 1;
word-break: break-word;
}
.text-a {
font-size: 0.8rem;
line-height: 1rem;
}
}
.lg-row {
@media (min-width: 1300px) {
flex-direction: row;
justify-content: space-between;
}
}
.footer1 {
margin-top: 1.5rem;
background-color: #ffffff;
color: black;
border-top: 1px solid #bfbfbf;
&-wrap {
max-width: 90%;
margin: auto;
padding-top: 1rem;
padding-left: 0;
padding-right: 0;
.section-right {
display: grid;
margin-bottom: 0.5rem;
gap: 1rem;
font-size: 0.8rem;
line-height: 1.25rem;
font-weight: 400;
@media (min-width: 950px) {
grid-template-columns: repeat(12, minmax(0, 1fr));
}
.footer-category {
display: grid;
gap: 1rem;
height: 100%;
/* grid-template-columns: repeat(5, minmax(0, 1fr)); */
&.grid-col-3 {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
&.grid-col-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.item-nav {
padding: 10px;
.text {
font-size: 0.8rem;
line-height: 1.25rem;
color: black;
}
}
.drag-new {
display: flex;
justify-content: center;
align-items: center;
border-radius: 6px;
background: #215486;
font-size: 40px;
color: #fff;
margin: 0 11px;
max-width: 200px;
height: 30px;
}
}
&-4 {
display: grid;
grid-column: span 4 / span 4;
grid-auto-rows: max;
gap: 1rem;
&.border-top-left-0 {
border-left: 0;
border-top: 1px solid #bfbfbf;
padding-top: 1rem;
}
@media (max-width: 1150px) {
grid-column: span 5 / span 5;
}
@media (min-width: 950px) {
padding-left: 1rem;
border-left: 1px solid #bfbfbf;
}
.text {
margin-bottom: 0.5rem;
font-size: 1rem;
line-height: 1.75rem;
font-weight: 700;
text-transform: uppercase;
&-wrap {
display: flex;
flex-direction: column;
gap: 0.75rem;
white-space: nowrap;
.text-item {
display: flex;
gap: 0.5rem;
align-items: center;
max-width: 100%;
.text-child {
font-size: 0.8rem;
line-height: 1.25rem;
flex: 1;
word-break: break-word;
}
}
}
}
}
}
.section-bottom {
display: flex;
margin-top: 0.5rem;
margin-bottom: 0.5rem;
flex-direction: column;
gap: 1rem;
justify-content: space-between;
align-items: center;
@media (min-width: 640px) {
flex-direction: row;
}
.ssr {
display: flex;
gap: 1rem;
justify-content: center;
align-items: center;
a {
font-size: 0.8rem;
color: #737373;
line-height: 1.25rem;
@media (min-width: 1024px) {
font-size: 1rem;
line-height: 1.5rem;
}
}
}
&__left {
display: flex;
justify-content: center;
align-items: center;
@media (min-width: 640px) {
order: 1;
}
}
&__right {
display: flex;
gap: 1rem;
justify-content: center;
align-items: center;
.icon1 {
color: #737373;
display: grid;
place-items: center;
border-radius: 9999px;
border: 1px solid #737373;
transition-duration: 300ms;
width: 32px;
height: 32px;
}
@media (min-width: 640px) {
order: 3;
}
}
}
}
}
</style>
@@ -0,0 +1,15 @@
<script setup lang="ts">
import dayjs from 'dayjs';
const currentDateTime = ref<string>("");
onMounted(() => {
currentDateTime.value = dayjs().format("dddd, DD/MM/YYYY");
});
</script>
<template>
<div class="flex items-center text-sm whitespace-nowrap">
<Icon name="fa6-regular:clock" />
<span class="inline-block text-16px leading-normal ml-1">{{ currentDateTime }}</span>
</div>
</template>
@@ -1,237 +1,96 @@
<script setup lang="ts">
<script lang="ts" setup>
import { CurrentDateTime, LangSwitcher, TopNavigation, Mega } from "./index";
const widgetsStore = useWidgetsStore();
const layoutstore = useLayoutStore();
const { weather } = storeToRefs(widgetsStore);
const { megaMenuActive } = storeToRefs(layoutstore);
const navClass = ref("");
const handleScroll = () => {
if (window.scrollY > 0) {
navClass.value = "shadow-md";
} else {
navClass.value = "";
}
};
onMounted(async () => {
window.addEventListener("scroll", handleScroll);
await widgetsStore.fetchWeatherByLocation();
});
onUnmounted(() => {
window.removeEventListener("scroll", handleScroll);
});
</script>
<template>
<div>
useCmsPageStore
</div>
<header id="header" class="relative">
<div class="w-full mx-auto px-4 max-w-8xl py-1">
<div id="top-bar-inner" class="flex items-center justify-between md:justify-center md:divide-x">
<NuxtLink to="/" id="logo" class="pr-6">
<img src="/images/200.png" alt="logo" class="object-cover w-24" />
</NuxtLink>
<ClientOnly>
<CurrentDateTime class="md:px-4 pt-5px" />
</ClientOnly>
<div class="items-center hidden px-6 ml-auto space-x-8 lg:flex">
<div>
<ClientOnly>
<div v-if="weather" class="flex items-center space-x-1">
<p class="text-l">{{ weather.location.name }}</p>
<img :src="weather.current.condition.icon" alt="Weather Icon" class="h-8" />
<p class="text-l">{{ weather.current.temp_c }}°C</p>
</div>
<div v-else>
<p>Đang tải thông tin thời tiết...</p>
</div>
</ClientOnly>
</div>
</div>
<div class="hidden md:flex gap-4 items-center px-4">
<button class="outline-none flex py-2 bg-transparent">
<Icon name="gg:search" size="18" />
</button>
<NuxtLink :to="`/subscriptions/paper`">
<Icon name="material-symbols:book-4-outline" />
</NuxtLink>
<!-- <Auth /> -->
<button class="outline-none flex py-2 bg-transparent">
<Icon name="fa6-regular:circle-user" size="16" />
</button>
</div>
<LangSwitcher class="hidden md:block px-4 pt-5px" />
<div class="xl:hidden block pl-4">
<button
type="button"
v-show="!megaMenuActive"
@click="layoutstore.setStatus(true)"
class="py-1 duration-300 hover:text-blue-500 bg-transparent"
>
<Icon name="fa6-solid:bars" />
</button>
<button
type="button"
v-show="megaMenuActive"
@click="layoutstore.setStatus(false)"
class="py-1 duration-300 hover:text-red-500 bg-transparent"
>
<Icon name="fa6-solid:xmark" />
</button>
</div>
</div>
</div>
</header>
<TopNavigation />
<Teleport to="body">
<Mega />
</Teleport>
</template>
<style lang="scss" scoped>
.col-span-8 {
grid-column: span 8 / span 8;
@media (max-width: 1150px) {
grid-column: span 7 / span 7;
}
}
.col-span-12 {
grid-column: span 12 / span 12 !important;
}
.mbootom-5 {
margin-bottom: 5px;
}
.mbootom-14 {
margin-bottom: 14px;
}
.text-neutral-500 {
color: #737373;
}
.grid-col-2 {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px;
&.grid-col-1 {
grid-template-columns: repeat(1, minmax(0, 1fr));
}
}
.flex-col {
display: flex;
flex-direction: column;
.text-span {
font-size: 1rem;
line-height: 1.75rem;
font-weight: 700;
letter-spacing: 0.025em;
flex: 1;
word-break: break-word;
}
.text-a {
font-size: 0.8rem;
line-height: 1rem;
}
}
.lg-row {
@media (min-width: 1300px) {
flex-direction: row;
justify-content: space-between;
}
}
.footer1 {
margin-top: 1.5rem;
background-color: #ffffff;
color: black;
border-top: 1px solid #bfbfbf;
&-wrap {
max-width: 90%;
margin: auto;
padding-top: 1rem;
padding-left: 0;
padding-right: 0;
.section-right {
display: grid;
margin-bottom: 0.5rem;
gap: 1rem;
font-size: 0.8rem;
line-height: 1.25rem;
font-weight: 400;
@media (min-width: 950px) {
grid-template-columns: repeat(12, minmax(0, 1fr));
}
.footer-category {
display: grid;
gap: 1rem;
height: 100%;
/* grid-template-columns: repeat(5, minmax(0, 1fr)); */
&.grid-col-3 {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
&.grid-col-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.item-nav {
padding: 10px;
.text {
font-size: 0.8rem;
line-height: 1.25rem;
color: black;
}
}
.drag-new {
display: flex;
justify-content: center;
align-items: center;
border-radius: 6px;
background: #215486;
font-size: 40px;
color: #fff;
margin: 0 11px;
max-width: 200px;
height: 30px;
}
}
&-4 {
display: grid;
grid-column: span 4 / span 4;
grid-auto-rows: max;
gap: 1rem;
&.border-top-left-0 {
border-left: 0;
border-top: 1px solid #bfbfbf;
padding-top: 1rem;
}
@media (max-width: 1150px) {
grid-column: span 5 / span 5;
}
@media (min-width: 950px) {
padding-left: 1rem;
border-left: 1px solid #bfbfbf;
}
.text {
margin-bottom: 0.5rem;
font-size: 1rem;
line-height: 1.75rem;
font-weight: 700;
text-transform: uppercase;
&-wrap {
display: flex;
flex-direction: column;
gap: 0.75rem;
white-space: nowrap;
.text-item {
display: flex;
gap: 0.5rem;
align-items: center;
max-width: 100%;
.text-child {
font-size: 0.8rem;
line-height: 1.25rem;
flex: 1;
word-break: break-word;
}
}
}
}
}
}
.section-bottom {
display: flex;
margin-top: 0.5rem;
margin-bottom: 0.5rem;
flex-direction: column;
gap: 1rem;
justify-content: space-between;
align-items: center;
@media (min-width: 640px) {
flex-direction: row;
}
.ssr {
display: flex;
gap: 1rem;
justify-content: center;
align-items: center;
a {
font-size: 0.8rem;
color: #737373;
line-height: 1.25rem;
@media (min-width: 1024px) {
font-size: 1rem;
line-height: 1.5rem;
}
}
}
&__left {
display: flex;
justify-content: center;
align-items: center;
@media (min-width: 640px) {
order: 1;
}
}
&__right {
display: flex;
gap: 1rem;
justify-content: center;
align-items: center;
.icon1 {
color: #737373;
display: grid;
place-items: center;
border-radius: 9999px;
border: 1px solid #737373;
transition-duration: 300ms;
width: 32px;
height: 32px;
}
@media (min-width: 640px) {
order: 3;
}
}
}
}
}
</style>
<style></style>
@@ -0,0 +1,37 @@
<script setup lang="ts">
import { onClickOutside } from "@vueuse/core";
const langSwitcherEl = ref<HTMLDivElement>();
const selectingLanguages = ref<boolean>(false);
const classes = computed(() => ({
"pointer-events-auto opacity-100": selectingLanguages.value,
"pointer-events-none opacity-0": !selectingLanguages.value,
}));
onClickOutside(langSwitcherEl, () => selectingLanguages.value = false);
const languages = ['Tiếng việt']
const onSelectLanguage = () => selectingLanguages.value = false
</script>
<template>
<div ref="langSwitcherEl" id="lang-switcher" class="relative text-sm">
<button class="text-sm bg-transparent" @click="selectingLanguages = !selectingLanguages">
Tiếng việt
</button>
<div id="languages-switchable" :class="classes"
class="absolute z-50 min-w-36 right-0 top-10 bg-white rounded shadow overflow-hidden shadow-lg flex flex-col duration-300">
<div class="relative w-full px-1 py-1">
<ul>
<li v-for="(l, i) in languages" @click="onSelectLanguage" :key="i">
<button class="py-2 w-full rounded duration-300 hover:bg-blue-400 hover:text-white">
{{ l }}
</button>
</li>
</ul>
</div>
</div>
</div>
</template>
@@ -0,0 +1,61 @@
<script setup lang="ts">
import { onClickOutside } from "@vueuse/core";
import { useNavigationStoreV2 } from '~/stores/navigation';
import {storeToRefs} from "pinia";
import { vInterpolate } from '~/directives/v-interpolate';
import * as cherrio from 'cheerio'
const router = useRouter();
const route = useRoute();
const v2NavigationStore = useNavigationStoreV2()
const layoutstore = useLayoutStore();
const { megaMenuActive } = storeToRefs(layoutstore);
const {topMenu} = storeToRefs(v2NavigationStore)
const megaMenuEl = ref<HTMLElement>();
const computedClass = computed(() =>
megaMenuActive.value
? ["opacity-100", "pointer-events-auto"]
: ["opacity-0", "pointer-events-none"]
);
const $ = cherrio.load(topMenu.value)
const html = $('.parent').addClass('xl:(flex items-center justify-center)')
html.find('>li').addClass('xl:(relative group xl:mr-3) hover:bg-[#e6f4ff] py-3 px-6 rounded-md')
html.find('ul').addClass('pl-4 hidden xl:(gap-0 w-200px shadow group-hover:(block absolute top-full left-0 bg-white z-50))')
html.find('>li>a').addClass('xl:(block py-4 hover:(text-blue))')
html.find('>li>ul>li>a').addClass('xl:(block py-10px px-15px hover:(bg-blue text-white))')
</script>
<template>
<a-drawer
v-model:open="megaMenuActive"
class="custom-class"
root-class-name="root-class-name"
title="Tất cả chuyên mục"
placement="right"
:bodyStyle="{padding:0}"
>
<div
class=" h-full max-h-full flex flex-col gap-y-4 mx-auto"
>
<div id="mega-menu" v-interpolate v-html="html"></div>
</div>
</a-drawer>
</template>
<style lang="sass" scoped>
#mega-menu
max-height: 100vh
min-height: 100vh
#mega-list
max-height: 100vh
</style>
@@ -0,0 +1,23 @@
<script setup lang="ts">
import { useNavigationStoreV2 } from '~/stores/navigation';
import {storeToRefs} from "pinia";
import { vInterpolate } from '~/directives/v-interpolate';
import * as cherrio from 'cheerio'
const v2NavigationStore = useNavigationStoreV2()
const {topMenu} = storeToRefs(v2NavigationStore)
await v2NavigationStore.fetchNavigation()
const $ = cherrio.load(topMenu.value)
const html = $('.parent').addClass('xl:(flex items-center justify-center)')
html.find('>li').addClass('relative group xl:mr-3 hover:text-blue')
html.find('ul').addClass('hidden w-200px shadow group-hover:(block absolute top-full left-0 bg-white z-50)')
html.find('>li>a').addClass('block py-4')
html.find('>li>ul>li>a').addClass('block py-10px px-15px text-black hover:(bg-blue text-white)')
</script>
<template>
<nav class="main-nav text-sm z-40 sticky top-0 bg-white relative border-y border-neutral-200 hidden xl:block" v-interpolate v-html="html">
</nav>
</template>
@@ -0,0 +1,4 @@
export { default as LangSwitcher } from './LangSwitcher.vue'
export { default as CurrentDateTime } from './CurrentDateTime.vue'
export { default as TopNavigation } from './TopNavigation.vue'
export { default as Mega } from './Mega.vue'