120 lines
3.1 KiB
Vue
120 lines
3.1 KiB
Vue
<template>
|
|
<AppLoading v-if="!$store.ready" />
|
|
<ClientOnly v-else>
|
|
<TopMenu @changeTab="changeTab" />
|
|
<main>
|
|
<div
|
|
class="mb-2 is-flex is-justify-content-space-between is-align-items-center is-gap-1"
|
|
v-if="tab"
|
|
>
|
|
<div>
|
|
<div class="fs-17 font-semibold is-flex is-gap-1 is-align-items-center mb-1">
|
|
<div
|
|
v-if="subtab"
|
|
class="is-flex is-gap-1 is-align-items-center"
|
|
>
|
|
<span>{{ tab[$store.lang] }}</span>
|
|
<Icon
|
|
name="material-symbols:arrow-forward-ios-rounded"
|
|
:size="13"
|
|
class="has-text-grey"
|
|
/>
|
|
<span>{{ subtab[$store.lang] }}</span>
|
|
</div>
|
|
<p v-else>{{ tab[$store.lang] }}</p>
|
|
<button
|
|
@click="refresh"
|
|
class="button is-primary is-light rounded-full p-1"
|
|
>
|
|
<Icon
|
|
name="material-symbols:refresh-rounded"
|
|
:size="20"
|
|
/>
|
|
</button>
|
|
</div>
|
|
<p class="has-text-grey fs-13 font-normal">
|
|
Cập nhật:
|
|
<NuxtTime
|
|
:datetime="Date.now() - 1000 * 60 * Math.random() * 10"
|
|
locale="vi-VN"
|
|
relative
|
|
/>
|
|
</p>
|
|
</div>
|
|
<div
|
|
id="header-right-slot"
|
|
:key="componentKey"
|
|
></div>
|
|
</div>
|
|
<KeepAlive>
|
|
<component
|
|
v-if="componentKey"
|
|
:is="componentMap[vbind.component]"
|
|
:key="componentKey"
|
|
v-bind="vbind"
|
|
/>
|
|
</KeepAlive>
|
|
</main>
|
|
</ClientOnly>
|
|
</template>
|
|
<script setup>
|
|
const { $createMeta, $store, $copy, $id } = useNuxtApp();
|
|
const componentMap = {};
|
|
const componentKey = ref();
|
|
const vbind = ref({});
|
|
const tab = ref();
|
|
const subtab = ref();
|
|
const currentTab = ref();
|
|
|
|
const toPascalCase = (str) => {
|
|
if (!str || typeof str !== "string") return str;
|
|
return str
|
|
.split("/")
|
|
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
.join("");
|
|
};
|
|
|
|
function changeTab(_tab, _subtab) {
|
|
tab.value = _tab;
|
|
subtab.value = _subtab;
|
|
currentTab.value = subtab.value || tab.value;
|
|
if (currentTab.value.detail) {
|
|
vbind.value =
|
|
$store.lang === "en" ? currentTab.value.detail_en || currentTab.value.detail : currentTab.value.detail;
|
|
}
|
|
componentMap[vbind.value.component] = vbind.value.base || toPascalCase(vbind.value.component);
|
|
componentKey.value = vbind.value.component;
|
|
|
|
$store.commit("tabinfo", {
|
|
tab: tab.value,
|
|
subtab: subtab.value,
|
|
current: currentTab.value,
|
|
vbind: vbind.value,
|
|
});
|
|
|
|
const meta = {
|
|
title: currentTab.value[$store.lang],
|
|
image: undefined,
|
|
description: "Utopia",
|
|
type: "article",
|
|
keywords: "utopia",
|
|
};
|
|
useHead($createMeta(meta));
|
|
}
|
|
|
|
function refresh() {
|
|
const copy = $copy(componentKey.value) + $id();
|
|
componentKey.value = undefined;
|
|
setTimeout(() => (componentKey.value = copy));
|
|
}
|
|
</script>
|
|
<style lang="scss" scoped>
|
|
@use "bulma/sass/utilities/mixins.scss" as *;
|
|
main {
|
|
padding: 1rem 2rem 2rem;
|
|
@include mobile {
|
|
padding: 1rem;
|
|
}
|
|
}
|
|
</style>
|