halo/ui/console-src/modules/interface/themes/components/ThemeListModal.vue

171 lines
4.0 KiB
Vue

<script lang="ts" setup>
import { VButton, VModal, VTabbar } from "@halo-dev/components";
import {
computed,
ref,
watch,
provide,
inject,
markRaw,
nextTick,
onMounted,
type Ref,
} from "vue";
import type { Theme } from "@halo-dev/api-client";
import { useI18n } from "vue-i18n";
import { useRouteQuery } from "@vueuse/router";
import InstalledThemes from "./list-tabs/InstalledThemes.vue";
import NotInstalledThemes from "./list-tabs/NotInstalledThemes.vue";
import LocalUpload from "./list-tabs/LocalUpload.vue";
import RemoteDownload from "./list-tabs/RemoteDownload.vue";
import { usePluginModuleStore } from "@/stores/plugin";
import type { PluginModule, ThemeListTab } from "@halo-dev/console-shared";
import { usePermission } from "@/utils/permission";
const { t } = useI18n();
const { currentUserHasPermission } = usePermission();
const props = withDefaults(
defineProps<{
visible: boolean;
}>(),
{
visible: false,
}
);
const selectedTheme = inject<Ref<Theme | undefined>>("selectedTheme", ref());
watch(
() => selectedTheme.value,
(value, oldValue) => {
if (value && oldValue) {
emit("select", value);
onVisibleChange(false);
}
}
);
const emit = defineEmits<{
(event: "update:visible", visible: boolean): void;
(event: "close"): void;
(event: "select", theme: Theme | undefined): void;
}>();
const tabs = ref<ThemeListTab[]>([
{
id: "installed",
label: t("core.theme.list_modal.tabs.installed"),
component: markRaw(InstalledThemes),
priority: 10,
},
{
id: "local-upload",
label: t("core.theme.list_modal.tabs.local_upload"),
component: markRaw(LocalUpload),
priority: 20,
},
{
id: "remote-download",
label: t("core.theme.list_modal.tabs.remote_download.label"),
component: markRaw(RemoteDownload),
priority: 30,
},
{
id: "not_installed",
label: t("core.theme.list_modal.tabs.not_installed"),
component: markRaw(NotInstalledThemes),
priority: 40,
},
]);
const activeTabId = ref();
provide<Ref<string>>("activeTabId", activeTabId);
const modalTitle = computed(() => {
const tab = tabs.value.find((tab) => tab.id === activeTabId.value);
return tab?.label;
});
const onVisibleChange = (visible: boolean) => {
emit("update:visible", visible);
if (!visible) {
emit("close");
}
};
// handle remote wordpress url from route
const remoteDownloadUrl = useRouteQuery<string>("remote-download-url");
watch(
() => props.visible,
(visible) => {
if (visible && remoteDownloadUrl.value) {
nextTick(() => {
activeTabId.value = "remote-download";
});
}
}
);
const { pluginModules } = usePluginModuleStore();
onMounted(() => {
const tabsFromPlugins: ThemeListTab[] = [];
pluginModules.forEach((pluginModule: PluginModule) => {
const { extensionPoints } = pluginModule;
if (!extensionPoints?.["theme:list:tabs:create"]) {
return;
}
let items = extensionPoints["theme:list:tabs:create"]() as ThemeListTab[];
items = items.filter((item) => {
return currentUserHasPermission(item.permissions);
});
tabsFromPlugins.push(...items);
});
tabs.value = tabs.value.concat(tabsFromPlugins).sort((a, b) => {
return a.priority - b.priority;
});
activeTabId.value = tabs.value[0].id;
});
</script>
<template>
<VModal
:visible="visible"
:width="920"
height="calc(100vh - 20px)"
:title="modalTitle"
@update:visible="onVisibleChange"
>
<VTabbar
v-model:active-id="activeTabId"
:items="
tabs.map((tab) => {
return { label: tab.label, id: tab.id };
})
"
type="outline"
/>
<div class="mt-2">
<template v-for="tab in tabs" :key="tab.id">
<component
:is="tab.component"
v-bind="tab.props"
v-if="tab.id === activeTabId"
/>
</template>
</div>
<template #footer>
<VButton @click="onVisibleChange(false)">
{{ $t("core.common.buttons.close") }}
</VButton>
</template>
</VModal>
</template>