mirror of https://github.com/halo-dev/halo-admin
feat: add preview theme support (#660)
#### What type of PR is this? /kind feature /milestone 2.0 #### What this PR does / why we need it: Ref https://github.com/halo-dev/halo/pull/2280 支持在 Console 预览主题。 #### Screenshots: <img width="1920" alt="image" src="https://user-images.githubusercontent.com/21301288/197442483-e89b8c3c-441e-4668-9840-96fe741a1f95.png"> #### Special notes for your reviewer: 测试方式:进入主题管理,打开已安装主题列表,在每一项的更多按钮即可看到预览主题的按钮。 #### Does this PR introduce a user-facing change? ```release-note 支持在 Console 预览主题。 ```pull/665/head
parent
a095c07ae1
commit
274cb19fcf
|
@ -0,0 +1,53 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { VModal, IconLink } from "@halo-dev/components";
|
||||||
|
|
||||||
|
withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
visible: boolean;
|
||||||
|
title?: string;
|
||||||
|
url?: string;
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
visible: false,
|
||||||
|
title: undefined,
|
||||||
|
url: "",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(event: "update:visible", visible: boolean): void;
|
||||||
|
(event: "close"): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const onVisibleChange = (visible: boolean) => {
|
||||||
|
emit("update:visible", visible);
|
||||||
|
if (!visible) {
|
||||||
|
emit("close");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<VModal
|
||||||
|
:body-class="['!p-0']"
|
||||||
|
:visible="visible"
|
||||||
|
fullscreen
|
||||||
|
:title="title"
|
||||||
|
@update:visible="onVisibleChange"
|
||||||
|
>
|
||||||
|
<template #actions>
|
||||||
|
<slot name="actions"></slot>
|
||||||
|
<span>
|
||||||
|
<a :href="url" target="_blank">
|
||||||
|
<IconLink />
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<div class="flex h-full items-center justify-center">
|
||||||
|
<iframe
|
||||||
|
v-if="visible"
|
||||||
|
class="h-full w-full border-none transition-all duration-300"
|
||||||
|
:src="url"
|
||||||
|
></iframe>
|
||||||
|
</div>
|
||||||
|
</VModal>
|
||||||
|
</template>
|
|
@ -2,6 +2,8 @@
|
||||||
import {
|
import {
|
||||||
IconAddCircle,
|
IconAddCircle,
|
||||||
IconGitHub,
|
IconGitHub,
|
||||||
|
IconArrowLeft,
|
||||||
|
IconArrowRight,
|
||||||
Dialog,
|
Dialog,
|
||||||
VButton,
|
VButton,
|
||||||
VEmpty,
|
VEmpty,
|
||||||
|
@ -15,6 +17,7 @@ import {
|
||||||
VTabs,
|
VTabs,
|
||||||
} from "@halo-dev/components";
|
} from "@halo-dev/components";
|
||||||
import LazyImage from "@/components/image/LazyImage.vue";
|
import LazyImage from "@/components/image/LazyImage.vue";
|
||||||
|
import UrlPreviewModal from "@/components/preview/UrlPreviewModal.vue";
|
||||||
import ThemeUploadModal from "./ThemeUploadModal.vue";
|
import ThemeUploadModal from "./ThemeUploadModal.vue";
|
||||||
import { computed, ref, watch } from "vue";
|
import { computed, ref, watch } from "vue";
|
||||||
import type { Theme } from "@halo-dev/api-client";
|
import type { Theme } from "@halo-dev/api-client";
|
||||||
|
@ -57,6 +60,8 @@ const handleFetchThemes = async () => {
|
||||||
try {
|
try {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const { data } = await apiClient.theme.listThemes({
|
const { data } = await apiClient.theme.listThemes({
|
||||||
|
page: 0,
|
||||||
|
size: 0,
|
||||||
uninstalled: activeTab.value !== "installed",
|
uninstalled: activeTab.value !== "installed",
|
||||||
});
|
});
|
||||||
themes.value = data.items;
|
themes.value = data.items;
|
||||||
|
@ -161,6 +166,50 @@ watch(
|
||||||
defineExpose({
|
defineExpose({
|
||||||
handleFetchThemes,
|
handleFetchThemes,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const preview = ref(false);
|
||||||
|
const selectedPreviewTheme = ref<Theme>();
|
||||||
|
|
||||||
|
const previewUrl = computed(() => {
|
||||||
|
if (!selectedPreviewTheme.value) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return `${import.meta.env.VITE_API_URL}/?preview-theme=${
|
||||||
|
selectedPreviewTheme.value.metadata.name
|
||||||
|
}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
const previewModalTitle = computed(() => {
|
||||||
|
if (!selectedPreviewTheme.value) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return `预览主题:${selectedPreviewTheme.value.spec.displayName}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleOpenPreview = (theme: Theme) => {
|
||||||
|
selectedPreviewTheme.value = theme;
|
||||||
|
preview.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectPreviousPreviewTheme = async () => {
|
||||||
|
const index = themes.value.findIndex(
|
||||||
|
(theme) => theme.metadata.name === selectedPreviewTheme.value?.metadata.name
|
||||||
|
);
|
||||||
|
if (index > 0) {
|
||||||
|
selectedPreviewTheme.value = themes.value[index - 1];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectNextPreviewTheme = () => {
|
||||||
|
const index = themes.value.findIndex(
|
||||||
|
(theme) => theme.metadata.name === selectedPreviewTheme.value?.metadata.name
|
||||||
|
);
|
||||||
|
if (index < themes.value.length - 1) {
|
||||||
|
selectedPreviewTheme.value = themes.value[index + 1];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<VModal
|
<VModal
|
||||||
|
@ -299,6 +348,14 @@ defineExpose({
|
||||||
v-if="currentUserHasPermission(['system:themes:manage'])"
|
v-if="currentUserHasPermission(['system:themes:manage'])"
|
||||||
#dropdownItems
|
#dropdownItems
|
||||||
>
|
>
|
||||||
|
<VButton
|
||||||
|
v-close-popper
|
||||||
|
block
|
||||||
|
type="secondary"
|
||||||
|
@click="handleOpenPreview(theme)"
|
||||||
|
>
|
||||||
|
预览
|
||||||
|
</VButton>
|
||||||
<VButton
|
<VButton
|
||||||
v-close-popper
|
v-close-popper
|
||||||
block
|
block
|
||||||
|
@ -442,4 +499,19 @@ defineExpose({
|
||||||
v-model:visible="themeInstall"
|
v-model:visible="themeInstall"
|
||||||
@close="handleFetchThemes"
|
@close="handleFetchThemes"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<UrlPreviewModal
|
||||||
|
v-model:visible="preview"
|
||||||
|
:title="previewModalTitle"
|
||||||
|
:url="previewUrl"
|
||||||
|
>
|
||||||
|
<template #actions>
|
||||||
|
<span @click="handleSelectPreviousPreviewTheme">
|
||||||
|
<IconArrowLeft />
|
||||||
|
</span>
|
||||||
|
<span @click="handleSelectNextPreviewTheme">
|
||||||
|
<IconArrowRight />
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</UrlPreviewModal>
|
||||||
</template>
|
</template>
|
||||||
|
|
Loading…
Reference in New Issue