mirror of https://github.com/halo-dev/halo-admin
feat: add enable and upgrade support for theme list (#774)
#### What type of PR is this? /kind improvement #### What this PR does / why we need it: 1. 在主题管理列表添加启用和升级的支持。 2. 优化主题页面右上角的按钮布局 3. 优化主题管理的代码结构。 #### Which issue(s) this PR fixes: Fixes https://github.com/halo-dev/halo/issues/2948 #### Screenshots: <img width="1515" alt="image" src="https://user-images.githubusercontent.com/21301288/207893631-6db10293-d0ee-4af4-9c43-f137055df28e.png"> <img width="1665" alt="image" src="https://user-images.githubusercontent.com/21301288/207894016-dd1a5d27-9fff-4211-8869-381208932eaf.png"> #### Special notes for your reviewer: 测试方式: 1. 进入主题管理,点击右上角的主题管理。 4. 测试单个主题的启用和升级是否符合预期。 #### Does this PR introduce a user-facing change? ```release-note Console 端的主题管理列表添加启用和升级的支持。 ```pull/773/head^2
parent
75f2cb0540
commit
6ac0816380
|
@ -2,15 +2,12 @@
|
||||||
import {
|
import {
|
||||||
IconAddCircle,
|
IconAddCircle,
|
||||||
IconGitHub,
|
IconGitHub,
|
||||||
Dialog,
|
|
||||||
VButton,
|
VButton,
|
||||||
VEmpty,
|
VEmpty,
|
||||||
VModal,
|
VModal,
|
||||||
VSpace,
|
VSpace,
|
||||||
VTag,
|
|
||||||
VEntity,
|
VEntity,
|
||||||
VEntityField,
|
VEntityField,
|
||||||
VStatusDot,
|
|
||||||
VTabItem,
|
VTabItem,
|
||||||
VTabs,
|
VTabs,
|
||||||
VLoading,
|
VLoading,
|
||||||
|
@ -18,15 +15,11 @@ import {
|
||||||
import LazyImage from "@/components/image/LazyImage.vue";
|
import LazyImage from "@/components/image/LazyImage.vue";
|
||||||
import ThemePreviewModal from "./preview/ThemePreviewModal.vue";
|
import ThemePreviewModal from "./preview/ThemePreviewModal.vue";
|
||||||
import ThemeUploadModal from "./ThemeUploadModal.vue";
|
import ThemeUploadModal from "./ThemeUploadModal.vue";
|
||||||
|
import ThemeListItem from "./components/ThemeListItem.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";
|
||||||
import { apiClient } from "@/utils/api-client";
|
import { apiClient } from "@/utils/api-client";
|
||||||
import { usePermission } from "@/utils/permission";
|
|
||||||
import { onBeforeRouteLeave } from "vue-router";
|
import { onBeforeRouteLeave } from "vue-router";
|
||||||
import { useThemeStore } from "@/stores/theme";
|
|
||||||
import { storeToRefs } from "pinia";
|
|
||||||
|
|
||||||
const { currentUserHasPermission } = usePermission();
|
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
@ -49,7 +42,7 @@ const emit = defineEmits<{
|
||||||
const activeTab = ref("installed");
|
const activeTab = ref("installed");
|
||||||
const themes = ref<Theme[]>([] as Theme[]);
|
const themes = ref<Theme[]>([] as Theme[]);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const themeInstall = ref(false);
|
const themeUploadVisible = ref(false);
|
||||||
const creating = ref(false);
|
const creating = ref(false);
|
||||||
const refreshInterval = ref();
|
const refreshInterval = ref();
|
||||||
|
|
||||||
|
@ -57,8 +50,6 @@ const modalTitle = computed(() => {
|
||||||
return activeTab.value === "installed" ? "已安装的主题" : "未安装的主题";
|
return activeTab.value === "installed" ? "已安装的主题" : "未安装的主题";
|
||||||
});
|
});
|
||||||
|
|
||||||
const { activatedTheme } = storeToRefs(useThemeStore());
|
|
||||||
|
|
||||||
const handleFetchThemes = async (options?: { mute?: boolean }) => {
|
const handleFetchThemes = async (options?: { mute?: boolean }) => {
|
||||||
try {
|
try {
|
||||||
clearInterval(refreshInterval.value);
|
clearInterval(refreshInterval.value);
|
||||||
|
@ -104,57 +95,6 @@ watch(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleUninstall = async (theme: Theme, deleteExtensions?: boolean) => {
|
|
||||||
Dialog.warning({
|
|
||||||
title: `${
|
|
||||||
deleteExtensions
|
|
||||||
? "确定要删除该主题以及对应的配置吗?"
|
|
||||||
: "确定要删除该主题吗?"
|
|
||||||
}`,
|
|
||||||
description: "该操作不可恢复。",
|
|
||||||
onConfirm: async () => {
|
|
||||||
try {
|
|
||||||
await apiClient.extension.theme.deletethemeHaloRunV1alpha1Theme({
|
|
||||||
name: theme.metadata.name,
|
|
||||||
});
|
|
||||||
|
|
||||||
// delete theme setting and configMap
|
|
||||||
if (!deleteExtensions) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { settingName, configMapName } = theme.spec;
|
|
||||||
|
|
||||||
if (settingName) {
|
|
||||||
await apiClient.extension.setting.deletev1alpha1Setting(
|
|
||||||
{
|
|
||||||
name: settingName,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
mute: true,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (configMapName) {
|
|
||||||
await apiClient.extension.configMap.deletev1alpha1ConfigMap(
|
|
||||||
{
|
|
||||||
name: configMapName,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
mute: true,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Failed to uninstall theme", e);
|
|
||||||
} finally {
|
|
||||||
await handleFetchThemes();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCreateTheme = async (theme: Theme) => {
|
const handleCreateTheme = async (theme: Theme) => {
|
||||||
try {
|
try {
|
||||||
creating.value = true;
|
creating.value = true;
|
||||||
|
@ -204,6 +144,7 @@ defineExpose({
|
||||||
handleFetchThemes,
|
handleFetchThemes,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// preview
|
||||||
const previewVisible = ref(false);
|
const previewVisible = ref(false);
|
||||||
const selectedPreviewTheme = ref<Theme>();
|
const selectedPreviewTheme = ref<Theme>();
|
||||||
|
|
||||||
|
@ -211,6 +152,19 @@ const handleOpenPreview = (theme: Theme) => {
|
||||||
selectedPreviewTheme.value = theme;
|
selectedPreviewTheme.value = theme;
|
||||||
previewVisible.value = true;
|
previewVisible.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// upgrade
|
||||||
|
const themeToUpgrade = ref<Theme>();
|
||||||
|
|
||||||
|
const handleOpenUpgradeModal = (theme: Theme) => {
|
||||||
|
themeToUpgrade.value = theme;
|
||||||
|
themeUploadVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOpenInstallModal = () => {
|
||||||
|
themeToUpgrade.value = undefined;
|
||||||
|
themeUploadVisible.value = true;
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<VModal
|
<VModal
|
||||||
|
@ -241,7 +195,7 @@ const handleOpenPreview = (theme: Theme) => {
|
||||||
<VButton
|
<VButton
|
||||||
v-permission="['system:themes:manage']"
|
v-permission="['system:themes:manage']"
|
||||||
type="primary"
|
type="primary"
|
||||||
@click="themeInstall = true"
|
@click="handleOpenInstallModal()"
|
||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<IconAddCircle class="h-full w-full" />
|
<IconAddCircle class="h-full w-full" />
|
||||||
|
@ -262,129 +216,15 @@ const handleOpenPreview = (theme: Theme) => {
|
||||||
:key="index"
|
:key="index"
|
||||||
@click="handleSelectTheme(theme)"
|
@click="handleSelectTheme(theme)"
|
||||||
>
|
>
|
||||||
<VEntity
|
<ThemeListItem
|
||||||
|
:theme="theme"
|
||||||
:is-selected="
|
:is-selected="
|
||||||
theme.metadata.name === selectedTheme?.metadata?.name
|
theme.metadata.name === selectedTheme?.metadata?.name
|
||||||
"
|
"
|
||||||
>
|
@reload="handleFetchThemes({ mute: true })"
|
||||||
<template #start>
|
@preview="handleOpenPreview(theme)"
|
||||||
<VEntityField>
|
@upgrade="handleOpenUpgradeModal(theme)"
|
||||||
<template #description>
|
/>
|
||||||
<div class="w-32">
|
|
||||||
<div
|
|
||||||
class="group aspect-w-4 aspect-h-3 block w-full overflow-hidden rounded border bg-gray-100"
|
|
||||||
>
|
|
||||||
<LazyImage
|
|
||||||
:key="theme.metadata.name"
|
|
||||||
:src="theme.spec.logo"
|
|
||||||
:alt="theme.spec.displayName"
|
|
||||||
classes="pointer-events-none object-cover group-hover:opacity-75"
|
|
||||||
>
|
|
||||||
<template #loading>
|
|
||||||
<div
|
|
||||||
class="flex h-full items-center justify-center object-cover"
|
|
||||||
>
|
|
||||||
<span class="text-xs text-gray-400"
|
|
||||||
>加载中...</span
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template #error>
|
|
||||||
<div
|
|
||||||
class="flex h-full items-center justify-center object-cover"
|
|
||||||
>
|
|
||||||
<span class="text-xs text-red-400"
|
|
||||||
>加载异常</span
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</LazyImage>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</VEntityField>
|
|
||||||
<VEntityField
|
|
||||||
:title="theme.spec.displayName"
|
|
||||||
:description="theme.spec.version"
|
|
||||||
>
|
|
||||||
<template #extra>
|
|
||||||
<VTag
|
|
||||||
v-if="
|
|
||||||
theme.metadata.name === activatedTheme?.metadata?.name
|
|
||||||
"
|
|
||||||
>
|
|
||||||
当前启用
|
|
||||||
</VTag>
|
|
||||||
</template>
|
|
||||||
</VEntityField>
|
|
||||||
</template>
|
|
||||||
<template #end>
|
|
||||||
<VEntityField v-if="theme.metadata.deletionTimestamp">
|
|
||||||
<template #description>
|
|
||||||
<VStatusDot
|
|
||||||
v-tooltip="`删除中`"
|
|
||||||
state="warning"
|
|
||||||
animate
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</VEntityField>
|
|
||||||
<VEntityField>
|
|
||||||
<template #description>
|
|
||||||
<a
|
|
||||||
class="text-sm text-gray-400 hover:text-blue-600"
|
|
||||||
:href="theme.spec.author.website"
|
|
||||||
target="_blank"
|
|
||||||
@click.stop
|
|
||||||
>
|
|
||||||
{{ theme.spec.author.name }}
|
|
||||||
</a>
|
|
||||||
</template>
|
|
||||||
</VEntityField>
|
|
||||||
<VEntityField>
|
|
||||||
<template #description>
|
|
||||||
<a
|
|
||||||
:href="theme.spec.repo"
|
|
||||||
class="text-gray-900 hover:text-blue-600"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
<IconGitHub />
|
|
||||||
</a>
|
|
||||||
</template>
|
|
||||||
</VEntityField>
|
|
||||||
</template>
|
|
||||||
<template
|
|
||||||
v-if="currentUserHasPermission(['system:themes:manage'])"
|
|
||||||
#dropdownItems
|
|
||||||
>
|
|
||||||
<VButton
|
|
||||||
v-close-popper
|
|
||||||
block
|
|
||||||
type="secondary"
|
|
||||||
@click="handleOpenPreview(theme)"
|
|
||||||
>
|
|
||||||
预览
|
|
||||||
</VButton>
|
|
||||||
<VButton
|
|
||||||
v-close-popper
|
|
||||||
block
|
|
||||||
type="danger"
|
|
||||||
@click="handleUninstall(theme)"
|
|
||||||
>
|
|
||||||
卸载
|
|
||||||
</VButton>
|
|
||||||
<VButton
|
|
||||||
v-close-popper
|
|
||||||
:disabled="
|
|
||||||
theme.metadata.name === activatedTheme?.metadata?.name
|
|
||||||
"
|
|
||||||
block
|
|
||||||
type="danger"
|
|
||||||
@click="handleUninstall(theme, true)"
|
|
||||||
>
|
|
||||||
卸载并删除配置
|
|
||||||
</VButton>
|
|
||||||
</template>
|
|
||||||
</VEntity>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</Transition>
|
</Transition>
|
||||||
|
@ -499,7 +339,7 @@ const handleOpenPreview = (theme: Theme) => {
|
||||||
<VButton
|
<VButton
|
||||||
v-permission="['system:themes:manage']"
|
v-permission="['system:themes:manage']"
|
||||||
type="secondary"
|
type="secondary"
|
||||||
@click="themeInstall = true"
|
@click="handleOpenInstallModal()"
|
||||||
>
|
>
|
||||||
安装主题
|
安装主题
|
||||||
</VButton>
|
</VButton>
|
||||||
|
@ -510,7 +350,8 @@ const handleOpenPreview = (theme: Theme) => {
|
||||||
|
|
||||||
<ThemeUploadModal
|
<ThemeUploadModal
|
||||||
v-if="visible"
|
v-if="visible"
|
||||||
v-model:visible="themeInstall"
|
v-model:visible="themeUploadVisible"
|
||||||
|
:upgrade-theme="themeToUpgrade"
|
||||||
@close="handleFetchThemes"
|
@close="handleFetchThemes"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,206 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import {
|
||||||
|
IconGitHub,
|
||||||
|
VButton,
|
||||||
|
VSpace,
|
||||||
|
VTag,
|
||||||
|
VEntity,
|
||||||
|
VEntityField,
|
||||||
|
VStatusDot,
|
||||||
|
Dialog,
|
||||||
|
} from "@halo-dev/components";
|
||||||
|
import LazyImage from "@/components/image/LazyImage.vue";
|
||||||
|
import type { Theme } from "@halo-dev/api-client";
|
||||||
|
import { apiClient } from "@/utils/api-client";
|
||||||
|
import { toRefs } from "vue";
|
||||||
|
import { useThemeLifeCycle } from "../../composables/use-theme";
|
||||||
|
import { usePermission } from "@/utils/permission";
|
||||||
|
|
||||||
|
const { currentUserHasPermission } = usePermission();
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
theme: Theme;
|
||||||
|
isSelected?: boolean;
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
isSelected: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(event: "reload"): void;
|
||||||
|
(event: "upgrade"): void;
|
||||||
|
(event: "preview"): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const { theme } = toRefs(props);
|
||||||
|
|
||||||
|
const { isActivated, handleActiveTheme } = useThemeLifeCycle(theme);
|
||||||
|
|
||||||
|
const handleUninstall = async (theme: Theme, deleteExtensions?: boolean) => {
|
||||||
|
Dialog.warning({
|
||||||
|
title: `${
|
||||||
|
deleteExtensions
|
||||||
|
? "确定要删除该主题以及对应的配置吗?"
|
||||||
|
: "确定要删除该主题吗?"
|
||||||
|
}`,
|
||||||
|
description: "该操作不可恢复。",
|
||||||
|
onConfirm: async () => {
|
||||||
|
try {
|
||||||
|
await apiClient.extension.theme.deletethemeHaloRunV1alpha1Theme({
|
||||||
|
name: theme.metadata.name,
|
||||||
|
});
|
||||||
|
|
||||||
|
// delete theme setting and configMap
|
||||||
|
if (!deleteExtensions) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { settingName, configMapName } = theme.spec;
|
||||||
|
|
||||||
|
if (settingName) {
|
||||||
|
await apiClient.extension.setting.deletev1alpha1Setting(
|
||||||
|
{
|
||||||
|
name: settingName,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mute: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configMapName) {
|
||||||
|
await apiClient.extension.configMap.deletev1alpha1ConfigMap(
|
||||||
|
{
|
||||||
|
name: configMapName,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mute: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to uninstall theme", e);
|
||||||
|
} finally {
|
||||||
|
emit("reload");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VEntity :is-selected="isSelected">
|
||||||
|
<template #start>
|
||||||
|
<VEntityField>
|
||||||
|
<template #description>
|
||||||
|
<div class="w-32">
|
||||||
|
<div
|
||||||
|
class="group aspect-w-4 aspect-h-3 block w-full overflow-hidden rounded border bg-gray-100"
|
||||||
|
>
|
||||||
|
<LazyImage
|
||||||
|
:key="theme.metadata.name"
|
||||||
|
:src="theme.spec.logo"
|
||||||
|
:alt="theme.spec.displayName"
|
||||||
|
classes="pointer-events-none object-cover group-hover:opacity-75"
|
||||||
|
>
|
||||||
|
<template #loading>
|
||||||
|
<div
|
||||||
|
class="flex h-full items-center justify-center object-cover"
|
||||||
|
>
|
||||||
|
<span class="text-xs text-gray-400">加载中...</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #error>
|
||||||
|
<div
|
||||||
|
class="flex h-full items-center justify-center object-cover"
|
||||||
|
>
|
||||||
|
<span class="text-xs text-red-400">加载异常</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</LazyImage>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</VEntityField>
|
||||||
|
<VEntityField
|
||||||
|
:title="theme.spec.displayName"
|
||||||
|
:description="theme.spec.version"
|
||||||
|
>
|
||||||
|
<template #extra>
|
||||||
|
<VTag v-if="isActivated"> 当前启用 </VTag>
|
||||||
|
</template>
|
||||||
|
</VEntityField>
|
||||||
|
</template>
|
||||||
|
<template #end>
|
||||||
|
<VEntityField v-if="theme.metadata.deletionTimestamp">
|
||||||
|
<template #description>
|
||||||
|
<VStatusDot v-tooltip="`删除中`" state="warning" animate />
|
||||||
|
</template>
|
||||||
|
</VEntityField>
|
||||||
|
<VEntityField>
|
||||||
|
<template #description>
|
||||||
|
<a
|
||||||
|
class="text-sm text-gray-400 hover:text-blue-600"
|
||||||
|
:href="theme.spec.author.website"
|
||||||
|
target="_blank"
|
||||||
|
@click.stop
|
||||||
|
>
|
||||||
|
{{ theme.spec.author.name }}
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
</VEntityField>
|
||||||
|
<VEntityField>
|
||||||
|
<template #description>
|
||||||
|
<a
|
||||||
|
:href="theme.spec.repo"
|
||||||
|
class="text-gray-900 hover:text-blue-600"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<IconGitHub />
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
</VEntityField>
|
||||||
|
</template>
|
||||||
|
<template
|
||||||
|
v-if="currentUserHasPermission(['system:themes:manage'])"
|
||||||
|
#dropdownItems
|
||||||
|
>
|
||||||
|
<VButton v-close-popper block type="secondary" @click="handleActiveTheme">
|
||||||
|
启用
|
||||||
|
</VButton>
|
||||||
|
<VButton v-close-popper block type="default" @click="emit('upgrade')">
|
||||||
|
升级
|
||||||
|
</VButton>
|
||||||
|
<VButton v-close-popper block type="default" @click="emit('preview')">
|
||||||
|
预览
|
||||||
|
</VButton>
|
||||||
|
<FloatingDropdown class="w-full" placement="right" :triggers="['click']">
|
||||||
|
<VButton block type="danger"> 卸载 </VButton>
|
||||||
|
<template #popper>
|
||||||
|
<div class="w-52 p-2">
|
||||||
|
<VSpace class="w-full" direction="column">
|
||||||
|
<VButton
|
||||||
|
v-close-popper.all
|
||||||
|
block
|
||||||
|
type="danger"
|
||||||
|
@click="handleUninstall(theme)"
|
||||||
|
>
|
||||||
|
卸载
|
||||||
|
</VButton>
|
||||||
|
<VButton
|
||||||
|
v-close-popper.all
|
||||||
|
block
|
||||||
|
type="danger"
|
||||||
|
@click="handleUninstall(theme, true)"
|
||||||
|
>
|
||||||
|
卸载并删除配置
|
||||||
|
</VButton>
|
||||||
|
</VSpace>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</FloatingDropdown>
|
||||||
|
</template>
|
||||||
|
</VEntity>
|
||||||
|
</template>
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import ThemeListItem from "./ThemeListItem.vue";
|
import ThemePreviewListItem from "./ThemePreviewListItem.vue";
|
||||||
import { useSettingForm } from "@/composables/use-setting-form";
|
import { useSettingForm } from "@/composables/use-setting-form";
|
||||||
import { useThemeStore } from "@/stores/theme";
|
import { useThemeStore } from "@/stores/theme";
|
||||||
import { apiClient } from "@/utils/api-client";
|
import { apiClient } from "@/utils/api-client";
|
||||||
|
@ -339,7 +339,7 @@ const iframeClasses = computed(() => {
|
||||||
:key="index"
|
:key="index"
|
||||||
@click="handleSelect(item)"
|
@click="handleSelect(item)"
|
||||||
>
|
>
|
||||||
<ThemeListItem
|
<ThemePreviewListItem
|
||||||
:theme="item"
|
:theme="item"
|
||||||
:is-selected="
|
:is-selected="
|
||||||
selectedTheme?.metadata.name === item.metadata.name
|
selectedTheme?.metadata.name === item.metadata.name
|
||||||
|
|
|
@ -169,12 +169,6 @@ onMounted(() => {
|
||||||
</template>
|
</template>
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<VSpace>
|
<VSpace>
|
||||||
<VButton size="sm" type="default" @click="themesModal = true">
|
|
||||||
<template #icon>
|
|
||||||
<IconExchange class="h-full w-full" />
|
|
||||||
</template>
|
|
||||||
切换主题
|
|
||||||
</VButton>
|
|
||||||
<VButton
|
<VButton
|
||||||
v-if="!isActivated"
|
v-if="!isActivated"
|
||||||
v-permission="['system:themes:manage']"
|
v-permission="['system:themes:manage']"
|
||||||
|
@ -190,6 +184,12 @@ onMounted(() => {
|
||||||
</template>
|
</template>
|
||||||
预览
|
预览
|
||||||
</VButton>
|
</VButton>
|
||||||
|
<VButton size="sm" type="default" @click="themesModal = true">
|
||||||
|
<template #icon>
|
||||||
|
<IconExchange class="h-full w-full" />
|
||||||
|
</template>
|
||||||
|
主题管理
|
||||||
|
</VButton>
|
||||||
</VSpace>
|
</VSpace>
|
||||||
</template>
|
</template>
|
||||||
</VPageHeader>
|
</VPageHeader>
|
||||||
|
|
Loading…
Reference in New Issue