mirror of https://github.com/halo-dev/halo-admin
parent
558b8a3778
commit
76ed305ae5
|
@ -1,4 +1,5 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import type { PropType } from "vue";
|
||||||
import { computed, ref } from "vue";
|
import { computed, ref } from "vue";
|
||||||
import { IconClose } from "@/core/icons";
|
import { IconClose } from "@/core/icons";
|
||||||
|
|
||||||
|
@ -18,6 +19,9 @@ const props = defineProps({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
bodyClass: {
|
||||||
|
type: Object as PropType<string[]>,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(["update:visible", "close"]);
|
const emit = defineEmits(["update:visible", "close"]);
|
||||||
|
@ -86,7 +90,7 @@ function handleClose() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div :class="bodyClass" class="modal-body">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="$slots.footer" class="modal-footer">
|
<div v-if="$slots.footer" class="modal-footer">
|
||||||
|
|
|
@ -67,6 +67,10 @@ import IconPhone from "~icons/ri/smartphone-line";
|
||||||
import IconTablet from "~icons/ri/tablet-line";
|
import IconTablet from "~icons/ri/tablet-line";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import IconUserFollow from "~icons/ri/user-follow-line";
|
import IconUserFollow from "~icons/ri/user-follow-line";
|
||||||
|
// @ts-ignore
|
||||||
|
import IconExchange from "~icons/ri/exchange-line";
|
||||||
|
// @ts-ignore
|
||||||
|
import IconGitHub from "~icons/ri/github-fill";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
IconDashboard,
|
IconDashboard,
|
||||||
|
@ -103,4 +107,6 @@ export {
|
||||||
IconPhone,
|
IconPhone,
|
||||||
IconTablet,
|
IconTablet,
|
||||||
IconUserFollow,
|
IconUserFollow,
|
||||||
|
IconExchange,
|
||||||
|
IconGitHub,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import {
|
import {
|
||||||
IconBookRead,
|
IconBookRead,
|
||||||
IconDashboard,
|
IconDashboard,
|
||||||
IconEye,
|
|
||||||
IconFolder,
|
IconFolder,
|
||||||
IconListSettings,
|
IconListSettings,
|
||||||
IconMessage,
|
IconMessage,
|
||||||
|
@ -66,7 +65,7 @@ export const menus: MenuGroupType[] = [
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
name: "主题",
|
name: "主题",
|
||||||
path: "/themes",
|
path: "/theme",
|
||||||
icon: IconPalette,
|
icon: IconPalette,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -74,11 +73,6 @@ export const menus: MenuGroupType[] = [
|
||||||
path: "/menus",
|
path: "/menus",
|
||||||
icon: IconListSettings,
|
icon: IconListSettings,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "可视化",
|
|
||||||
path: "/visual",
|
|
||||||
icon: IconEye,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,13 +11,14 @@ import TagList from "../views/contents/posts/tags/TagList.vue";
|
||||||
import CommentList from "../views/contents/comments/CommentList.vue";
|
import CommentList from "../views/contents/comments/CommentList.vue";
|
||||||
import AttachmentList from "../views/contents/attachments/AttachmentList.vue";
|
import AttachmentList from "../views/contents/attachments/AttachmentList.vue";
|
||||||
|
|
||||||
import ThemeList from "../views/interface/themes/ThemeList.vue";
|
import ThemeDetail from "../views/interface/themes/ThemeDetail.vue";
|
||||||
import MenuList from "../views/interface/menus/MenuList.vue";
|
import MenuList from "../views/interface/menus/MenuList.vue";
|
||||||
import Visual from "../views/interface/visual/Visual.vue";
|
import Visual from "../views/interface/visual/Visual.vue";
|
||||||
|
|
||||||
import PluginList from "../views/system/plugins/PluginList.vue";
|
import PluginList from "../views/system/plugins/PluginList.vue";
|
||||||
import PluginDetail from "../views/system/plugins/PluginDetail.vue";
|
import PluginDetail from "../views/system/plugins/PluginDetail.vue";
|
||||||
import UserList from "../views/system/users/UserList.vue";
|
import UserList from "../views/system/users/UserList.vue";
|
||||||
|
import RoleList from "../views/system/roles/RoleList.vue";
|
||||||
import Profile from "../views/system/users/Profile.vue";
|
import Profile from "../views/system/users/Profile.vue";
|
||||||
import GeneralSettings from "../views/system/settings/GeneralSettings.vue";
|
import GeneralSettings from "../views/system/settings/GeneralSettings.vue";
|
||||||
import NotificationSettings from "../views/system/settings/NotificationSettings.vue";
|
import NotificationSettings from "../views/system/settings/NotificationSettings.vue";
|
||||||
|
@ -107,13 +108,24 @@ export const routes: Array<RouteRecordRaw> = [
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/themes",
|
path: "/theme",
|
||||||
component: BasicLayout,
|
component: BasicLayout,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: "",
|
path: "",
|
||||||
name: "Themes",
|
name: "Theme",
|
||||||
component: ThemeList,
|
component: ThemeDetail,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/theme/visual",
|
||||||
|
component: BlankLayout,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: "",
|
||||||
|
name: "ThemeVisual",
|
||||||
|
component: Visual,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -128,17 +140,6 @@ export const routes: Array<RouteRecordRaw> = [
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: "/visual",
|
|
||||||
component: BlankLayout,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: "",
|
|
||||||
name: "Visual",
|
|
||||||
component: Visual,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: "/plugins",
|
path: "/plugins",
|
||||||
component: BasicLayout,
|
component: BasicLayout,
|
||||||
|
@ -175,6 +176,11 @@ export const routes: Array<RouteRecordRaw> = [
|
||||||
name: "Profile",
|
name: "Profile",
|
||||||
component: Profile,
|
component: Profile,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "roles",
|
||||||
|
name: "Roles",
|
||||||
|
component: RoleList,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,316 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { VPageHeader } from "@/components/base/header";
|
||||||
|
import { VButton } from "@/components/base/button";
|
||||||
|
import { VSpace } from "@/components/base/space";
|
||||||
|
import { VCard } from "@/components/base/card";
|
||||||
|
import { VModal } from "@/components/base/modal";
|
||||||
|
import { VInput } from "@/components/base/input";
|
||||||
|
import { VTag } from "@/components/base/tag";
|
||||||
|
import { VTextarea } from "@/components/base/textarea";
|
||||||
|
import { VTabbar } from "@/components/base/tabs";
|
||||||
|
import {
|
||||||
|
IconArrowRight,
|
||||||
|
IconExchange,
|
||||||
|
IconEye,
|
||||||
|
IconGitHub,
|
||||||
|
IconPalette,
|
||||||
|
} from "@/core/icons";
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { themes } from "@/views/interface/themes/themes-mock";
|
||||||
|
|
||||||
|
const currentTheme = ref(themes[0]);
|
||||||
|
const changeTheme = ref(false);
|
||||||
|
const themeActiveId = ref("detail");
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
const handleChangeTheme = (theme: any) => {
|
||||||
|
currentTheme.value = theme;
|
||||||
|
changeTheme.value = false;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VModal
|
||||||
|
v-model:visible="changeTheme"
|
||||||
|
:body-class="['!p-0']"
|
||||||
|
:width="888"
|
||||||
|
title="切换主题"
|
||||||
|
>
|
||||||
|
<ul class="flex flex-col divide-y divide-gray-100" role="list">
|
||||||
|
<li
|
||||||
|
v-for="(theme, index) in themes"
|
||||||
|
:key="index"
|
||||||
|
:class="{ 'bg-gray-50': theme.activated }"
|
||||||
|
class="relative cursor-pointer py-4 transition-all hover:bg-gray-100"
|
||||||
|
@click="handleChangeTheme(theme)"
|
||||||
|
>
|
||||||
|
<div class="flex items-center">
|
||||||
|
<div
|
||||||
|
v-show="theme.activated"
|
||||||
|
class="absolute inset-y-0 left-0 w-0.5 bg-themeable-primary"
|
||||||
|
></div>
|
||||||
|
<div class="w-40 px-4">
|
||||||
|
<div
|
||||||
|
class="group aspect-w-4 aspect-h-3 block w-full overflow-hidden rounded border bg-gray-100"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
:src="theme.screenshots"
|
||||||
|
alt=""
|
||||||
|
class="pointer-events-none object-cover group-hover:opacity-75"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<VSpace align="start" direction="column" spacing="xs">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="text-lg font-medium text-gray-900">
|
||||||
|
{{ theme.name }}
|
||||||
|
</span>
|
||||||
|
<VTag v-if="theme.activated">当前启用</VTag>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span class="text-sm text-gray-400">{{ theme.version }}</span>
|
||||||
|
</div>
|
||||||
|
</VSpace>
|
||||||
|
</div>
|
||||||
|
<div class="px-4">
|
||||||
|
<VSpace spacing="lg">
|
||||||
|
<div>
|
||||||
|
<span class="text-sm text-gray-400 hover:text-blue-600">
|
||||||
|
{{ theme.author.name }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="theme.repo">
|
||||||
|
<a
|
||||||
|
:href="theme.repo"
|
||||||
|
class="text-gray-900 hover:text-blue-600"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<IconGitHub />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<IconArrowRight class="text-gray-900" />
|
||||||
|
</div>
|
||||||
|
</VSpace>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<template #footer>
|
||||||
|
<VButton @click="changeTheme = false">关闭</VButton>
|
||||||
|
</template>
|
||||||
|
</VModal>
|
||||||
|
<VPageHeader :title="currentTheme.name">
|
||||||
|
<template #icon>
|
||||||
|
<IconPalette class="mr-2 self-center" />
|
||||||
|
</template>
|
||||||
|
<template #actions>
|
||||||
|
<VSpace>
|
||||||
|
<VButton size="sm" type="default" @click="changeTheme = true">
|
||||||
|
<template #icon>
|
||||||
|
<IconExchange class="h-full w-full" />
|
||||||
|
</template>
|
||||||
|
切换主题
|
||||||
|
</VButton>
|
||||||
|
<VButton v-if="!currentTheme.activated" size="sm" type="primary">
|
||||||
|
启用
|
||||||
|
</VButton>
|
||||||
|
<VButton :route="{ name: 'ThemeVisual' }" type="secondary">
|
||||||
|
<template #icon>
|
||||||
|
<IconEye class="h-full w-full" />
|
||||||
|
</template>
|
||||||
|
可视化编辑
|
||||||
|
</VButton>
|
||||||
|
</VSpace>
|
||||||
|
</template>
|
||||||
|
</VPageHeader>
|
||||||
|
<div class="m-0 md:m-4">
|
||||||
|
<VCard :body-class="['!p-0']">
|
||||||
|
<template #header>
|
||||||
|
<VTabbar
|
||||||
|
v-model:active-id="themeActiveId"
|
||||||
|
:items="[
|
||||||
|
{ id: 'detail', label: '详情' },
|
||||||
|
{ id: 'settings', label: '基础设置' },
|
||||||
|
]"
|
||||||
|
class="w-full"
|
||||||
|
type="outline"
|
||||||
|
></VTabbar>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div v-if="themeActiveId === 'detail'">
|
||||||
|
<div class="px-4 py-4 sm:px-6">
|
||||||
|
<div class="flex flex-row gap-3">
|
||||||
|
<div v-if="currentTheme.logo">
|
||||||
|
<div
|
||||||
|
class="h-12 w-12 overflow-hidden rounded border bg-white hover:shadow-sm"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
:alt="currentTheme.name"
|
||||||
|
:src="currentTheme.logo"
|
||||||
|
class="h-full w-full"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-medium leading-6 text-gray-900">
|
||||||
|
{{ currentTheme.name }}
|
||||||
|
</h3>
|
||||||
|
<p class="mt-1 flex max-w-2xl items-center gap-2">
|
||||||
|
<span class="text-sm text-gray-500">
|
||||||
|
{{ currentTheme.version }}
|
||||||
|
</span>
|
||||||
|
<VTag>
|
||||||
|
{{ currentTheme.activated ? "当前启用" : "未启用" }}
|
||||||
|
</VTag>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="border-t border-gray-200">
|
||||||
|
<dl class="divide-y divide-gray-100">
|
||||||
|
<div
|
||||||
|
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
||||||
|
>
|
||||||
|
<dt class="text-sm font-medium text-gray-900">ID</dt>
|
||||||
|
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||||
|
{{ currentTheme.id }}
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
||||||
|
>
|
||||||
|
<dt class="text-sm font-medium text-gray-900">作者</dt>
|
||||||
|
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||||
|
{{ currentTheme.author.name }}
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
||||||
|
>
|
||||||
|
<dt class="text-sm font-medium text-gray-900">网站</dt>
|
||||||
|
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||||
|
<a :href="currentTheme.website" target="_blank">
|
||||||
|
{{ currentTheme.website }}
|
||||||
|
</a>
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
||||||
|
>
|
||||||
|
<dt class="text-sm font-medium text-gray-900">源码仓库</dt>
|
||||||
|
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||||
|
<a :href="currentTheme.repo" target="_blank">
|
||||||
|
{{ currentTheme.repo }}
|
||||||
|
</a>
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
||||||
|
>
|
||||||
|
<dt class="text-sm font-medium text-gray-900">当前版本</dt>
|
||||||
|
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||||
|
{{ currentTheme.version }}
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
||||||
|
>
|
||||||
|
<dt class="text-sm font-medium text-gray-900">Halo 版本要求</dt>
|
||||||
|
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||||
|
{{ currentTheme.require }}
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
||||||
|
>
|
||||||
|
<dt class="text-sm font-medium text-gray-900">存储位置</dt>
|
||||||
|
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||||
|
{{ currentTheme.themePath }}
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
||||||
|
>
|
||||||
|
<dt class="text-sm font-medium text-gray-900">插件依赖</dt>
|
||||||
|
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||||
|
无
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="themeActiveId === 'settings'">
|
||||||
|
<form>
|
||||||
|
<div class="space-y-6 divide-y divide-gray-100 sm:space-y-5">
|
||||||
|
<div
|
||||||
|
class="px-4 sm:grid sm:grid-cols-3 sm:items-start sm:gap-4 sm:pt-5"
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2"
|
||||||
|
>
|
||||||
|
侧边栏宽度
|
||||||
|
</label>
|
||||||
|
<div class="mt-1 sm:col-span-2 sm:mt-0">
|
||||||
|
<div class="flex max-w-lg shadow-sm">
|
||||||
|
<VInput />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="px-4 sm:grid sm:grid-cols-3 sm:items-start sm:gap-4 sm:pt-5"
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2"
|
||||||
|
>
|
||||||
|
侧边栏背景图
|
||||||
|
</label>
|
||||||
|
<div class="mt-1 sm:col-span-2 sm:mt-0">
|
||||||
|
<div class="flex max-w-lg shadow-sm">
|
||||||
|
<VInput />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="px-4 sm:grid sm:grid-cols-3 sm:items-start sm:gap-4 sm:pt-5"
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2"
|
||||||
|
>
|
||||||
|
右上角图标
|
||||||
|
</label>
|
||||||
|
<div class="mt-1 sm:col-span-2 sm:mt-0">
|
||||||
|
<div class="flex max-w-lg shadow-sm">
|
||||||
|
<VInput />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="px-4 sm:grid sm:grid-cols-3 sm:items-start sm:gap-4 sm:pt-5"
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2"
|
||||||
|
>
|
||||||
|
文章代码高亮语言
|
||||||
|
</label>
|
||||||
|
<div class="mt-1 sm:col-span-2 sm:mt-0">
|
||||||
|
<div class="flex max-w-lg shadow-sm">
|
||||||
|
<VTextarea modelValue="Halo" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pt-5">
|
||||||
|
<div class="flex justify-start p-4">
|
||||||
|
<VButton type="secondary"> 保存</VButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</VCard>
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -1,43 +0,0 @@
|
||||||
<script lang="ts" setup>
|
|
||||||
import { VPageHeader } from "@/components/base/header";
|
|
||||||
import { VButton } from "@/components/base/button";
|
|
||||||
import { VCard } from "@/components/base/card";
|
|
||||||
import { IconPalette } from "@/core/icons";
|
|
||||||
import { themes } from "@/views/interface/themes/themes-mock";
|
|
||||||
</script>
|
|
||||||
<template>
|
|
||||||
<VPageHeader title="主题">
|
|
||||||
<template #icon>
|
|
||||||
<IconPalette class="mr-2 self-center" />
|
|
||||||
</template>
|
|
||||||
<template #actions>
|
|
||||||
<VButton type="secondary">安装</VButton>
|
|
||||||
</template>
|
|
||||||
</VPageHeader>
|
|
||||||
|
|
||||||
<div class="m-4">
|
|
||||||
<ul
|
|
||||||
class="grid grid-cols-1 gap-x-2 gap-y-3 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6"
|
|
||||||
role="list"
|
|
||||||
>
|
|
||||||
<li v-for="(theme, index) in themes" :key="index" class="relative">
|
|
||||||
<VCard :body-class="['!p-0']">
|
|
||||||
<div
|
|
||||||
class="group aspect-w-10 aspect-h-7 block w-full cursor-pointer overflow-hidden bg-gray-100"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
:src="theme.screenshots"
|
|
||||||
alt=""
|
|
||||||
class="pointer-events-none object-cover group-hover:opacity-75"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<p
|
|
||||||
class="pointer-events-none block truncate px-2 py-1 text-sm font-medium text-gray-700"
|
|
||||||
>
|
|
||||||
{{ theme.name }}
|
|
||||||
</p>
|
|
||||||
</VCard>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
|
@ -1,4 +1,52 @@
|
||||||
export const themes = [
|
export const themes = [
|
||||||
|
{
|
||||||
|
id: "caicai_anatole",
|
||||||
|
name: "Anatole",
|
||||||
|
website: "https://github.com/halo-dev/halo-theme-anatole",
|
||||||
|
branch: "master",
|
||||||
|
repo: "https://github.com/halo-dev/halo-theme-anatole",
|
||||||
|
updateStrategy: "RELEASE",
|
||||||
|
description: "A other Halo theme",
|
||||||
|
logo: "https://avatars1.githubusercontent.com/u/1811819?s=460&v=4",
|
||||||
|
version: "1.2.0",
|
||||||
|
require: "1.3.0",
|
||||||
|
author: {
|
||||||
|
name: "Caicai",
|
||||||
|
website: "https://www.caicai.me",
|
||||||
|
avatar: null,
|
||||||
|
},
|
||||||
|
themePath: "/root/.halo/templates/themes/caicai_anatole",
|
||||||
|
folderName: "caicai_anatole",
|
||||||
|
hasOptions: true,
|
||||||
|
screenshots: "https://demo.halo.run/themes/caicai_anatole/screenshot.png",
|
||||||
|
postMetaField: null,
|
||||||
|
sheetMetaField: null,
|
||||||
|
activated: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "flex-block",
|
||||||
|
name: "flex-block",
|
||||||
|
website: "https://github.com/guiyunweb/halo-theme-flex-block",
|
||||||
|
branch: "master",
|
||||||
|
repo: "https://github.com/guiyunweb/halo-theme-flex-block",
|
||||||
|
updateStrategy: "RELEASE",
|
||||||
|
description: "flex-block主题修改",
|
||||||
|
logo: "https://image.guiyunweb.com/2021/84306692_p0_master1200_1608708448480_1625562784578_1625565770497.jpg",
|
||||||
|
version: "2.0",
|
||||||
|
require: null,
|
||||||
|
author: {
|
||||||
|
name: "Guiyunweb",
|
||||||
|
website: "https://guiyunweb.com",
|
||||||
|
avatar: null,
|
||||||
|
},
|
||||||
|
themePath: "/root/.halo/templates/themes/flex-block",
|
||||||
|
folderName: "flex-block",
|
||||||
|
hasOptions: true,
|
||||||
|
screenshots: "https://demo.halo.run/themes/flex-block/screenshot.png",
|
||||||
|
postMetaField: null,
|
||||||
|
sheetMetaField: null,
|
||||||
|
activated: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "cetr_sagiri",
|
id: "cetr_sagiri",
|
||||||
name: "Sagiri",
|
name: "Sagiri",
|
||||||
|
@ -47,30 +95,6 @@ export const themes = [
|
||||||
sheetMetaField: null,
|
sheetMetaField: null,
|
||||||
activated: false,
|
activated: false,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: "caicai_anatole",
|
|
||||||
name: "Anatole",
|
|
||||||
website: "https://github.com/halo-dev/halo-theme-anatole",
|
|
||||||
branch: "master",
|
|
||||||
repo: "https://github.com/halo-dev/halo-theme-anatole",
|
|
||||||
updateStrategy: "RELEASE",
|
|
||||||
description: "A other Halo theme",
|
|
||||||
logo: "https://avatars1.githubusercontent.com/u/1811819?s=460&v=4",
|
|
||||||
version: "1.2.0",
|
|
||||||
require: "1.3.0",
|
|
||||||
author: {
|
|
||||||
name: "Caicai",
|
|
||||||
website: "https://www.caicai.me",
|
|
||||||
avatar: null,
|
|
||||||
},
|
|
||||||
themePath: "/root/.halo/templates/themes/caicai_anatole",
|
|
||||||
folderName: "caicai_anatole",
|
|
||||||
hasOptions: true,
|
|
||||||
screenshots: "https://demo.halo.run/themes/caicai_anatole/screenshot.png",
|
|
||||||
postMetaField: null,
|
|
||||||
sheetMetaField: null,
|
|
||||||
activated: false,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: "louie_senpai_siren",
|
id: "louie_senpai_siren",
|
||||||
name: "Siren",
|
name: "Siren",
|
||||||
|
@ -459,30 +483,6 @@ export const themes = [
|
||||||
sheetMetaField: null,
|
sheetMetaField: null,
|
||||||
activated: false,
|
activated: false,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: "flex-block",
|
|
||||||
name: "flex-block",
|
|
||||||
website: "https://github.com/guiyunweb/halo-theme-flex-block",
|
|
||||||
branch: "master",
|
|
||||||
repo: "https://github.com/guiyunweb/halo-theme-flex-block",
|
|
||||||
updateStrategy: "RELEASE",
|
|
||||||
description: "flex-block主题修改",
|
|
||||||
logo: "https://image.guiyunweb.com/2021/84306692_p0_master1200_1608708448480_1625562784578_1625565770497.jpg",
|
|
||||||
version: "2.0",
|
|
||||||
require: null,
|
|
||||||
author: {
|
|
||||||
name: "Guiyunweb",
|
|
||||||
website: "https://guiyunweb.com",
|
|
||||||
avatar: null,
|
|
||||||
},
|
|
||||||
themePath: "/root/.halo/templates/themes/flex-block",
|
|
||||||
folderName: "flex-block",
|
|
||||||
hasOptions: true,
|
|
||||||
screenshots: "https://demo.halo.run/themes/flex-block/screenshot.png",
|
|
||||||
postMetaField: null,
|
|
||||||
sheetMetaField: null,
|
|
||||||
activated: true,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: "imzeuk_zozo",
|
id: "imzeuk_zozo",
|
||||||
name: "Zozo",
|
name: "Zozo",
|
||||||
|
|
|
@ -2,13 +2,30 @@
|
||||||
import { VButton } from "@/components/base/button";
|
import { VButton } from "@/components/base/button";
|
||||||
import { VInput } from "@/components/base/input";
|
import { VInput } from "@/components/base/input";
|
||||||
import { VOption, VSelect } from "@/components/base/select";
|
import { VOption, VSelect } from "@/components/base/select";
|
||||||
|
import { VModal } from "@/components/base/modal";
|
||||||
import { VTextarea } from "@/components/base/textarea";
|
import { VTextarea } from "@/components/base/textarea";
|
||||||
|
import { VCard } from "@/components/base/card";
|
||||||
import { VTabbar, VTabItem, VTabs } from "@/components/base/tabs";
|
import { VTabbar, VTabItem, VTabs } from "@/components/base/tabs";
|
||||||
import { computed, ref } from "vue";
|
import { computed, onMounted, ref } from "vue";
|
||||||
import { IconComputer, IconPhone, IconTablet } from "@/core/icons";
|
import { IconComputer, IconPhone, IconTablet } from "@/core/icons";
|
||||||
|
|
||||||
const activeId = ref("general");
|
const activeId = ref("general");
|
||||||
const deviceActiveId = ref("desktop");
|
const deviceActiveId = ref("desktop");
|
||||||
|
const attachmentSelectVisible = ref(false);
|
||||||
|
const devices = ref([
|
||||||
|
{
|
||||||
|
id: "desktop",
|
||||||
|
icon: IconComputer,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "tablet",
|
||||||
|
icon: IconTablet,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "phone",
|
||||||
|
icon: IconPhone,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
const iframeClasses = computed(() => {
|
const iframeClasses = computed(() => {
|
||||||
if (deviceActiveId.value === "desktop") {
|
if (deviceActiveId.value === "desktop") {
|
||||||
|
@ -20,11 +37,74 @@ const iframeClasses = computed(() => {
|
||||||
// phone
|
// phone
|
||||||
return "w-96 h-[50rem]";
|
return "w-96 h-[50rem]";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const attachments = Array.from(new Array(50), (_, index) => index).map(
|
||||||
|
(index) => {
|
||||||
|
return {
|
||||||
|
id: index,
|
||||||
|
name: `attachment-${index}`,
|
||||||
|
url: `https://picsum.photos/1000/700?random=${index}`,
|
||||||
|
size: "1.2MB",
|
||||||
|
type: "image/png",
|
||||||
|
strategy: "本地存储",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
window.addEventListener(
|
||||||
|
"message",
|
||||||
|
function receiveMessageFromIframePage(event) {
|
||||||
|
if (event.data === "select_image") {
|
||||||
|
attachmentSelectVisible.value = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
<VModal
|
||||||
|
v-model:visible="attachmentSelectVisible"
|
||||||
|
:width="1240"
|
||||||
|
title="选择附件"
|
||||||
|
>
|
||||||
|
<div class="w-full">
|
||||||
|
<ul
|
||||||
|
class="grid grid-cols-2 gap-x-2 gap-y-3 sm:grid-cols-3 md:grid-cols-2 xl:grid-cols-8 2xl:grid-cols-8"
|
||||||
|
role="list"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
v-for="(attachment, index) in attachments"
|
||||||
|
:key="index"
|
||||||
|
class="relative"
|
||||||
|
>
|
||||||
|
<VCard :body-class="['!p-0']">
|
||||||
|
<div
|
||||||
|
class="group aspect-w-10 aspect-h-7 block w-full cursor-pointer overflow-hidden bg-gray-100"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
:src="attachment.url"
|
||||||
|
alt=""
|
||||||
|
class="pointer-events-none object-cover group-hover:opacity-75"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p
|
||||||
|
class="pointer-events-none block truncate px-2 py-1 text-sm font-medium text-gray-700"
|
||||||
|
>
|
||||||
|
{{ attachment.name }}
|
||||||
|
</p>
|
||||||
|
</VCard>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<VButton type="secondary">确定</VButton>
|
||||||
|
</template>
|
||||||
|
</VModal>
|
||||||
<div class="flex h-screen">
|
<div class="flex h-screen">
|
||||||
<div class="h-full w-96 overflow-y-auto bg-white drop-shadow-sm">
|
<div class="h-full w-96 overflow-y-auto bg-white drop-shadow-sm">
|
||||||
<VTabs v-model:active-id="activeId">
|
<VTabs v-model:active-id="activeId" type="outline">
|
||||||
<VTabItem id="general" class="p-3" label="基础设置">
|
<VTabItem id="general" class="p-3" label="基础设置">
|
||||||
<form>
|
<form>
|
||||||
<div class="space-y-8 divide-y divide-gray-200 sm:space-y-5">
|
<div class="space-y-8 divide-y divide-gray-200 sm:space-y-5">
|
||||||
|
@ -108,20 +188,7 @@ const iframeClasses = computed(() => {
|
||||||
<div>
|
<div>
|
||||||
<VTabbar
|
<VTabbar
|
||||||
v-model:active-id="deviceActiveId"
|
v-model:active-id="deviceActiveId"
|
||||||
:items="[
|
:items="devices"
|
||||||
{
|
|
||||||
id: 'desktop',
|
|
||||||
icon: IconComputer,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'tablet',
|
|
||||||
icon: IconTablet,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'phone',
|
|
||||||
icon: IconPhone,
|
|
||||||
},
|
|
||||||
]"
|
|
||||||
type="outline"
|
type="outline"
|
||||||
></VTabbar>
|
></VTabbar>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -37,9 +37,9 @@ console.log(plugin);
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="border-t border-gray-200">
|
<div class="border-t border-gray-200">
|
||||||
<dl>
|
<dl class="divide-y divide-gray-100">
|
||||||
<div
|
<div
|
||||||
class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
||||||
>
|
>
|
||||||
<dt class="text-sm font-medium text-gray-900">名称</dt>
|
<dt class="text-sm font-medium text-gray-900">名称</dt>
|
||||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||||
|
@ -47,7 +47,7 @@ console.log(plugin);
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
||||||
>
|
>
|
||||||
<dt class="text-sm font-medium text-gray-900">插件类别</dt>
|
<dt class="text-sm font-medium text-gray-900">插件类别</dt>
|
||||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||||
|
@ -59,7 +59,7 @@ console.log(plugin);
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
||||||
>
|
>
|
||||||
<dt class="text-sm font-medium text-gray-900">版本</dt>
|
<dt class="text-sm font-medium text-gray-900">版本</dt>
|
||||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||||
|
@ -67,7 +67,7 @@ console.log(plugin);
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
||||||
>
|
>
|
||||||
<dt class="text-sm font-medium text-gray-900">Halo 版本要求</dt>
|
<dt class="text-sm font-medium text-gray-900">Halo 版本要求</dt>
|
||||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||||
|
@ -75,7 +75,7 @@ console.log(plugin);
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
||||||
>
|
>
|
||||||
<dt class="text-sm font-medium text-gray-900">提供方</dt>
|
<dt class="text-sm font-medium text-gray-900">提供方</dt>
|
||||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||||
|
@ -85,7 +85,7 @@ console.log(plugin);
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
||||||
>
|
>
|
||||||
<dt class="text-sm font-medium text-gray-900">协议</dt>
|
<dt class="text-sm font-medium text-gray-900">协议</dt>
|
||||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||||
|
@ -93,7 +93,7 @@ console.log(plugin);
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
||||||
>
|
>
|
||||||
<dt class="text-sm font-medium text-gray-900">模型定义</dt>
|
<dt class="text-sm font-medium text-gray-900">模型定义</dt>
|
||||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">无</dd>
|
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">无</dd>
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
<script lang="ts" setup></script>
|
||||||
|
<template>Role</template>
|
|
@ -31,7 +31,7 @@ const handleRouteToDetail = (username: string) => {
|
||||||
</template>
|
</template>
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<VSpace>
|
<VSpace>
|
||||||
<VButton size="sm" type="default">
|
<VButton :route="{ name: 'Roles' }" size="sm" type="default">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<IconUserFollow class="h-full w-full" />
|
<IconUserFollow class="h-full w-full" />
|
||||||
</template>
|
</template>
|
||||||
|
|
Loading…
Reference in New Issue