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
Ryan Wang 2 years ago committed by GitHub
parent a095c07ae1
commit 274cb19fcf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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…
Cancel
Save