mirror of https://github.com/halo-dev/halo-admin
parent
558b8a3778
commit
76ed305ae5
|
@ -1,4 +1,5 @@
|
|||
<script lang="ts" setup>
|
||||
import type { PropType } from "vue";
|
||||
import { computed, ref } from "vue";
|
||||
import { IconClose } from "@/core/icons";
|
||||
|
||||
|
@ -18,6 +19,9 @@ const props = defineProps({
|
|||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
bodyClass: {
|
||||
type: Object as PropType<string[]>,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "close"]);
|
||||
|
@ -86,7 +90,7 @@ function handleClose() {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div :class="bodyClass" class="modal-body">
|
||||
<slot />
|
||||
</div>
|
||||
<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";
|
||||
// @ts-ignore
|
||||
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 {
|
||||
IconDashboard,
|
||||
|
@ -103,4 +107,6 @@ export {
|
|||
IconPhone,
|
||||
IconTablet,
|
||||
IconUserFollow,
|
||||
IconExchange,
|
||||
IconGitHub,
|
||||
};
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import {
|
||||
IconBookRead,
|
||||
IconDashboard,
|
||||
IconEye,
|
||||
IconFolder,
|
||||
IconListSettings,
|
||||
IconMessage,
|
||||
|
@ -66,7 +65,7 @@ export const menus: MenuGroupType[] = [
|
|||
items: [
|
||||
{
|
||||
name: "主题",
|
||||
path: "/themes",
|
||||
path: "/theme",
|
||||
icon: IconPalette,
|
||||
},
|
||||
{
|
||||
|
@ -74,11 +73,6 @@ export const menus: MenuGroupType[] = [
|
|||
path: "/menus",
|
||||
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 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 Visual from "../views/interface/visual/Visual.vue";
|
||||
|
||||
import PluginList from "../views/system/plugins/PluginList.vue";
|
||||
import PluginDetail from "../views/system/plugins/PluginDetail.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 GeneralSettings from "../views/system/settings/GeneralSettings.vue";
|
||||
import NotificationSettings from "../views/system/settings/NotificationSettings.vue";
|
||||
|
@ -107,13 +108,24 @@ export const routes: Array<RouteRecordRaw> = [
|
|||
],
|
||||
},
|
||||
{
|
||||
path: "/themes",
|
||||
path: "/theme",
|
||||
component: BasicLayout,
|
||||
children: [
|
||||
{
|
||||
path: "",
|
||||
name: "Themes",
|
||||
component: ThemeList,
|
||||
name: "Theme",
|
||||
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",
|
||||
component: BasicLayout,
|
||||
|
@ -175,6 +176,11 @@ export const routes: Array<RouteRecordRaw> = [
|
|||
name: "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 = [
|
||||
{
|
||||
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",
|
||||
name: "Sagiri",
|
||||
|
@ -47,30 +95,6 @@ export const themes = [
|
|||
sheetMetaField: null,
|
||||
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",
|
||||
name: "Siren",
|
||||
|
@ -459,30 +483,6 @@ export const themes = [
|
|||
sheetMetaField: null,
|
||||
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",
|
||||
name: "Zozo",
|
||||
|
|
|
@ -2,13 +2,30 @@
|
|||
import { VButton } from "@/components/base/button";
|
||||
import { VInput } from "@/components/base/input";
|
||||
import { VOption, VSelect } from "@/components/base/select";
|
||||
import { VModal } from "@/components/base/modal";
|
||||
import { VTextarea } from "@/components/base/textarea";
|
||||
import { VCard } from "@/components/base/card";
|
||||
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";
|
||||
|
||||
const activeId = ref("general");
|
||||
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(() => {
|
||||
if (deviceActiveId.value === "desktop") {
|
||||
|
@ -20,11 +37,74 @@ const iframeClasses = computed(() => {
|
|||
// phone
|
||||
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>
|
||||
<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="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="基础设置">
|
||||
<form>
|
||||
<div class="space-y-8 divide-y divide-gray-200 sm:space-y-5">
|
||||
|
@ -108,20 +188,7 @@ const iframeClasses = computed(() => {
|
|||
<div>
|
||||
<VTabbar
|
||||
v-model:active-id="deviceActiveId"
|
||||
:items="[
|
||||
{
|
||||
id: 'desktop',
|
||||
icon: IconComputer,
|
||||
},
|
||||
{
|
||||
id: 'tablet',
|
||||
icon: IconTablet,
|
||||
},
|
||||
{
|
||||
id: 'phone',
|
||||
icon: IconPhone,
|
||||
},
|
||||
]"
|
||||
:items="devices"
|
||||
type="outline"
|
||||
></VTabbar>
|
||||
</div>
|
||||
|
|
|
@ -37,9 +37,9 @@ console.log(plugin);
|
|||
</p>
|
||||
</div>
|
||||
<div class="border-t border-gray-200">
|
||||
<dl>
|
||||
<dl class="divide-y divide-gray-100">
|
||||
<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>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
|
@ -47,7 +47,7 @@ console.log(plugin);
|
|||
</dd>
|
||||
</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>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
|
@ -59,7 +59,7 @@ console.log(plugin);
|
|||
</dd>
|
||||
</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>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
|
@ -67,7 +67,7 @@ console.log(plugin);
|
|||
</dd>
|
||||
</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>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
|
@ -75,7 +75,7 @@ console.log(plugin);
|
|||
</dd>
|
||||
</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>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
|
@ -85,7 +85,7 @@ console.log(plugin);
|
|||
</dd>
|
||||
</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>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
|
@ -93,7 +93,7 @@ console.log(plugin);
|
|||
</dd>
|
||||
</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>
|
||||
<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 #actions>
|
||||
<VSpace>
|
||||
<VButton size="sm" type="default">
|
||||
<VButton :route="{ name: 'Roles' }" size="sm" type="default">
|
||||
<template #icon>
|
||||
<IconUserFollow class="h-full w-full" />
|
||||
</template>
|
||||
|
|
Loading…
Reference in New Issue