refactor: adapt page header styles for responsive design (#7544)

#### What type of PR is this?

/area ui
/kind improvement
/milestone 2.21.x

#### What this PR does / why we need it:

Adapt page header styles for responsive design

before:

<img width="415" alt="image" src="https://github.com/user-attachments/assets/feee6f09-9a77-4bbf-94c2-77725c9ce76b" />

after:

<img width="416" alt="image" src="https://github.com/user-attachments/assets/60bb07a3-5d34-4cf6-b103-5d1f2206d62d" />

#### Which issue(s) this PR fixes:

Fixes https://github.com/halo-dev/halo/issues/6425

#### Special notes for your reviewer:

#### Does this PR introduce a user-facing change?

```release-note
优化移动端下文章编辑页面的样式
```
pull/7549/head
Ryan Wang 2025-06-13 14:06:42 +08:00 committed by GitHub
parent 016d4cd94b
commit d39a571e46
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
33 changed files with 392 additions and 388 deletions

View File

@ -250,31 +250,29 @@ watch(
/>
<VPageHeader :title="$t('core.attachment.title')">
<template #icon>
<IconFolder class="mr-2 self-center" />
<IconFolder />
</template>
<template #actions>
<VSpace>
<VButton
v-permission="['system:attachments:manage']"
size="sm"
@click="policyVisible = true"
>
<template #icon>
<IconDatabase2Line />
</template>
{{ $t("core.attachment.actions.storage_policies") }}
</VButton>
<VButton
v-permission="['system:attachments:manage']"
type="secondary"
@click="uploadVisible = true"
>
<template #icon>
<IconUpload />
</template>
{{ $t("core.common.buttons.upload") }}
</VButton>
</VSpace>
<VButton
v-permission="['system:attachments:manage']"
size="sm"
@click="policyVisible = true"
>
<template #icon>
<IconDatabase2Line />
</template>
{{ $t("core.attachment.actions.storage_policies") }}
</VButton>
<VButton
v-permission="['system:attachments:manage']"
type="secondary"
@click="uploadVisible = true"
>
<template #icon>
<IconUpload />
</template>
{{ $t("core.common.buttons.upload") }}
</VButton>
</template>
</VPageHeader>

View File

@ -243,7 +243,7 @@ const handleApproveInBatch = async () => {
<template>
<VPageHeader :title="$t('core.comment.title')">
<template #icon>
<IconMessage class="mr-2 self-center" />
<IconMessage />
</template>
</VPageHeader>

View File

@ -204,24 +204,22 @@ watch(
<template>
<VPageHeader :title="$t('core.deleted_page.title')">
<template #icon>
<IconDeleteBin class="mr-2 self-center text-green-600" />
<IconDeleteBin class="text-green-600" />
</template>
<template #actions>
<VSpace>
<VButton :route="{ name: 'SinglePages' }" size="sm">
{{ $t("core.common.buttons.back") }}
</VButton>
<VButton
v-permission="['system:singlepages:manage']"
:route="{ name: 'SinglePageEditor' }"
type="secondary"
>
<template #icon>
<IconAddCircle />
</template>
{{ $t("core.common.buttons.new") }}
</VButton>
</VSpace>
<VButton :route="{ name: 'SinglePages' }" size="sm">
{{ $t("core.common.buttons.back") }}
</VButton>
<VButton
v-permission="['system:singlepages:manage']"
:route="{ name: 'SinglePageEditor' }"
type="secondary"
>
<template #icon>
<IconAddCircle />
</template>
{{ $t("core.common.buttons.new") }}
</VButton>
</template>
</VPageHeader>
<div class="m-0 md:m-4">

View File

@ -27,7 +27,6 @@ import {
Toast,
VButton,
VPageHeader,
VSpace,
} from "@halo-dev/components";
import type { EditorProvider } from "@halo-dev/console-shared";
import { useLocalStorage } from "@vueuse/core";
@ -464,71 +463,69 @@ async function handleUploadImage(file: File, options?: AxiosRequestConfig) {
<VPageHeader :title="$t('core.page.title')">
<template #icon>
<IconPages class="mr-2 self-center" />
<IconPages />
</template>
<template #actions>
<VSpace>
<EditorProviderSelector
v-if="editorProviders.length > 1"
:provider="currentEditorProvider"
:allow-forced-select="!isUpdateMode"
@select="handleChangeEditorProvider"
/>
<VButton
v-if="isUpdateMode"
size="sm"
type="default"
@click="
$router.push({
name: 'SinglePageSnapshots',
query: { name: routeQueryName },
})
"
>
<template #icon>
<IconHistoryLine />
</template>
{{ $t("core.page_editor.actions.snapshots") }}
</VButton>
<VButton
size="sm"
type="default"
:loading="previewPending"
@click="handlePreview"
>
<template #icon>
<IconEye />
</template>
{{ $t("core.common.buttons.preview") }}
</VButton>
<VButton :loading="saving" size="sm" type="default" @click="handleSave">
<template #icon>
<IconSave />
</template>
{{ $t("core.common.buttons.save") }}
</VButton>
<VButton
v-if="isUpdateMode"
size="sm"
type="default"
@click="handleOpenSettingModal"
>
<template #icon>
<IconSettings />
</template>
{{ $t("core.common.buttons.setting") }}
</VButton>
<VButton
type="secondary"
:loading="publishing"
@click="handlePublishClick"
>
<template #icon>
<IconSendPlaneFill />
</template>
{{ $t("core.common.buttons.publish") }}
</VButton>
</VSpace>
<EditorProviderSelector
v-if="editorProviders.length > 1"
:provider="currentEditorProvider"
:allow-forced-select="!isUpdateMode"
@select="handleChangeEditorProvider"
/>
<VButton
v-if="isUpdateMode"
size="sm"
type="default"
@click="
$router.push({
name: 'SinglePageSnapshots',
query: { name: routeQueryName },
})
"
>
<template #icon>
<IconHistoryLine />
</template>
{{ $t("core.page_editor.actions.snapshots") }}
</VButton>
<VButton
size="sm"
type="default"
:loading="previewPending"
@click="handlePreview"
>
<template #icon>
<IconEye />
</template>
{{ $t("core.common.buttons.preview") }}
</VButton>
<VButton :loading="saving" size="sm" type="default" @click="handleSave">
<template #icon>
<IconSave />
</template>
{{ $t("core.common.buttons.save") }}
</VButton>
<VButton
v-if="isUpdateMode"
size="sm"
type="default"
@click="handleOpenSettingModal"
>
<template #icon>
<IconSettings />
</template>
{{ $t("core.common.buttons.setting") }}
</VButton>
<VButton
type="secondary"
:loading="publishing"
@click="handlePublishClick"
>
<template #icon>
<IconSendPlaneFill />
</template>
{{ $t("core.common.buttons.publish") }}
</VButton>
</template>
</VPageHeader>
<div class="editor border-t" style="height: calc(100vh - 3.5rem)">

View File

@ -281,28 +281,26 @@ watch(selectedPageNames, (newValue) => {
<VPageHeader :title="$t('core.page.title')">
<template #icon>
<IconPages class="mr-2 self-center" />
<IconPages />
</template>
<template #actions>
<VSpace>
<VButton
v-permission="['system:singlepages:view']"
:route="{ name: 'DeletedSinglePages' }"
size="sm"
>
{{ $t("core.page.actions.recycle_bin") }}
</VButton>
<VButton
v-permission="['system:singlepages:manage']"
:route="{ name: 'SinglePageEditor' }"
type="secondary"
>
<template #icon>
<IconAddCircle />
</template>
{{ $t("core.common.buttons.new") }}
</VButton>
</VSpace>
<VButton
v-permission="['system:singlepages:view']"
:route="{ name: 'DeletedSinglePages' }"
size="sm"
>
{{ $t("core.page.actions.recycle_bin") }}
</VButton>
<VButton
v-permission="['system:singlepages:manage']"
:route="{ name: 'SinglePageEditor' }"
type="secondary"
>
<template #icon>
<IconAddCircle />
</template>
{{ $t("core.common.buttons.new") }}
</VButton>
</template>
</VPageHeader>

View File

@ -8,7 +8,6 @@ import {
VCard,
VLoading,
VPageHeader,
VSpace,
} from "@halo-dev/components";
import { useQuery, useQueryClient } from "@tanstack/vue-query";
import { useRouteQuery } from "@vueuse/router";
@ -118,17 +117,15 @@ function handleCleanup() {
<template>
<VPageHeader :title="singlePage?.spec.title">
<template #icon>
<IconHistoryLine class="mr-2 self-center" />
<IconHistoryLine />
</template>
<template #actions>
<VSpace>
<VButton size="sm" @click="$router.back()">
{{ $t("core.common.buttons.back") }}
</VButton>
<VButton size="sm" type="danger" @click="handleCleanup">
{{ $t("core.page_snapshots.operations.cleanup.button") }}
</VButton>
</VSpace>
<VButton size="sm" @click="$router.back()">
{{ $t("core.common.buttons.back") }}
</VButton>
<VButton size="sm" type="danger" @click="handleCleanup">
{{ $t("core.page_snapshots.operations.cleanup.button") }}
</VButton>
</template>
</VPageHeader>

View File

@ -214,24 +214,22 @@ watch(
<template>
<VPageHeader :title="$t('core.deleted_post.title')">
<template #icon>
<IconDeleteBin class="mr-2 self-center text-green-600" />
<IconDeleteBin class="text-green-600" />
</template>
<template #actions>
<VSpace>
<VButton :route="{ name: 'Posts' }" size="sm">
{{ $t("core.common.buttons.back") }}
</VButton>
<VButton
v-permission="['system:posts:manage']"
:route="{ name: 'PostEditor' }"
type="secondary"
>
<template #icon>
<IconAddCircle />
</template>
{{ $t("core.common.buttons.new") }}
</VButton>
</VSpace>
<VButton :route="{ name: 'Posts' }" size="sm">
{{ $t("core.common.buttons.back") }}
</VButton>
<VButton
v-permission="['system:posts:manage']"
:route="{ name: 'PostEditor' }"
type="secondary"
>
<template #icon>
<IconAddCircle />
</template>
{{ $t("core.common.buttons.new") }}
</VButton>
</template>
</VPageHeader>

View File

@ -29,7 +29,6 @@ import {
Toast,
VButton,
VPageHeader,
VSpace,
} from "@halo-dev/components";
import type { EditorProvider } from "@halo-dev/console-shared";
import { useLocalStorage } from "@vueuse/core";
@ -503,68 +502,64 @@ useSlugify(
<VPageHeader :title="$t('core.post.title')">
<template #icon>
<IconBookRead class="mr-2 self-center" />
<IconBookRead />
</template>
<template #actions>
<VSpace>
<EditorProviderSelector
v-if="editorProviders.length > 1"
:provider="currentEditorProvider"
:allow-forced-select="!isUpdateMode"
@select="handleChangeEditorProvider"
/>
<VButton
v-if="isUpdateMode"
size="sm"
type="default"
@click="
$router.push({ name: 'PostSnapshots', query: { name: name } })
"
>
<template #icon>
<IconHistoryLine />
</template>
{{ $t("core.post_editor.actions.snapshots") }}
</VButton>
<VButton
size="sm"
type="default"
:loading="previewPending"
@click="handlePreview"
>
<template #icon>
<IconEye />
</template>
{{ $t("core.common.buttons.preview") }}
</VButton>
<VButton :loading="saving" size="sm" type="default" @click="handleSave">
<template #icon>
<IconSave />
</template>
{{ $t("core.common.buttons.save") }}
</VButton>
<VButton
v-if="isUpdateMode"
size="sm"
type="default"
@click="handleOpenSettingModal"
>
<template #icon>
<IconSettings />
</template>
{{ $t("core.common.buttons.setting") }}
</VButton>
<VButton
type="secondary"
:loading="publishing"
@click="handlePublishClick"
>
<template #icon>
<IconSendPlaneFill />
</template>
{{ $t("core.common.buttons.publish") }}
</VButton>
</VSpace>
<EditorProviderSelector
v-if="editorProviders.length > 1"
:provider="currentEditorProvider"
:allow-forced-select="!isUpdateMode"
@select="handleChangeEditorProvider"
/>
<VButton
v-if="isUpdateMode"
size="sm"
type="default"
@click="$router.push({ name: 'PostSnapshots', query: { name: name } })"
>
<template #icon>
<IconHistoryLine />
</template>
{{ $t("core.post_editor.actions.snapshots") }}
</VButton>
<VButton
size="sm"
type="default"
:loading="previewPending"
@click="handlePreview"
>
<template #icon>
<IconEye />
</template>
{{ $t("core.common.buttons.preview") }}
</VButton>
<VButton :loading="saving" size="sm" type="default" @click="handleSave">
<template #icon>
<IconSave />
</template>
{{ $t("core.common.buttons.save") }}
</VButton>
<VButton
v-if="isUpdateMode"
size="sm"
type="default"
@click="handleOpenSettingModal"
>
<template #icon>
<IconSettings />
</template>
{{ $t("core.common.buttons.setting") }}
</VButton>
<VButton
type="secondary"
:loading="publishing"
@click="handlePublishClick"
>
<template #icon>
<IconSendPlaneFill />
</template>
{{ $t("core.common.buttons.publish") }}
</VButton>
</template>
</VPageHeader>
<div class="editor border-t" style="height: calc(100vh - 3.5rem)">

View File

@ -384,31 +384,29 @@ watch(
/>
<VPageHeader :title="$t('core.post.title')">
<template #icon>
<IconBookRead class="mr-2 self-center" />
<IconBookRead />
</template>
<template #actions>
<VSpace>
<VButton :route="{ name: 'Categories' }" size="sm">
{{ $t("core.post.actions.categories") }}
</VButton>
<VButton :route="{ name: 'Tags' }" size="sm">
{{ $t("core.post.actions.tags") }}
</VButton>
<VButton :route="{ name: 'DeletedPosts' }" size="sm">
{{ $t("core.post.actions.recycle_bin") }}
</VButton>
<VButton :route="{ name: 'Categories' }" size="sm">
{{ $t("core.post.actions.categories") }}
</VButton>
<VButton :route="{ name: 'Tags' }" size="sm">
{{ $t("core.post.actions.tags") }}
</VButton>
<VButton :route="{ name: 'DeletedPosts' }" size="sm">
{{ $t("core.post.actions.recycle_bin") }}
</VButton>
<VButton
v-permission="['system:posts:manage']"
:route="{ name: 'PostEditor' }"
type="secondary"
>
<template #icon>
<IconAddCircle />
</template>
{{ $t("core.common.buttons.new") }}
</VButton>
</VSpace>
<VButton
v-permission="['system:posts:manage']"
:route="{ name: 'PostEditor' }"
type="secondary"
>
<template #icon>
<IconAddCircle />
</template>
{{ $t("core.common.buttons.new") }}
</VButton>
</template>
</VPageHeader>

View File

@ -10,7 +10,6 @@ import {
VCard,
VLoading,
VPageHeader,
VSpace,
} from "@halo-dev/components";
import { useQuery, useQueryClient } from "@tanstack/vue-query";
import { useRouteQuery } from "@vueuse/router";
@ -117,17 +116,15 @@ function handleCleanup() {
<template>
<VPageHeader :title="post?.spec.title">
<template #icon>
<IconHistoryLine class="mr-2 self-center" />
<IconHistoryLine />
</template>
<template #actions>
<VSpace>
<VButton size="sm" @click="$router.back()">
{{ $t("core.common.buttons.back") }}
</VButton>
<VButton size="sm" type="danger" @click="handleCleanup">
{{ $t("core.post_snapshots.operations.cleanup.button") }}
</VButton>
</VSpace>
<VButton size="sm" @click="$router.back()">
{{ $t("core.common.buttons.back") }}
</VButton>
<VButton size="sm" type="danger" @click="handleCleanup">
{{ $t("core.post_snapshots.operations.cleanup.button") }}
</VButton>
</template>
</VPageHeader>

View File

@ -64,7 +64,7 @@ async function handleUpdateInBatch() {
<CategoryEditingModal v-if="creationModal" @close="creationModal = false" />
<VPageHeader :title="$t('core.post_category.title')">
<template #icon>
<IconBookRead class="mr-2 self-center" />
<IconBookRead />
</template>
<template #actions>

View File

@ -164,7 +164,7 @@ watch(selectedTagNames, (newVal) => {
/>
<VPageHeader :title="$t('core.post_tag.title')">
<template #icon>
<IconBookRead class="mr-2 self-center" />
<IconBookRead />
</template>
<template #actions>
<VButton

View File

@ -35,7 +35,7 @@ provide<ComputedRef<DashboardWidgetDefinition[]>>(
<template>
<VPageHeader :title="$t('core.dashboard.title')">
<template #icon>
<IconDashboard class="mr-2 self-center" />
<IconDashboard />
</template>
<template #actions>
<VButton

View File

@ -13,7 +13,6 @@ import {
VButton,
VDropdown,
VDropdownItem,
VSpace,
VTabbar,
} from "@halo-dev/components";
import type {
@ -321,12 +320,12 @@ function handleCopyFromLayout(breakpoint: string) {
}
</script>
<template>
<div
class="flex items-center justify-between bg-white px-4 py-1.5 gap-5 flex-wrap sticky top-0 z-10"
>
<h2 class="flex items-center truncate text-xl font-bold text-gray-800">
<div class="page-header py-1.5">
<h2 class="page-header__title">
<IconDashboard class="mr-2 self-center" />
<span>{{ $t("core.dashboard_designer.title") }}</span>
<span class="page-header__title-text">
{{ $t("core.dashboard_designer.title") }}
</span>
</h2>
<div
class="hidden sm:block"
@ -339,7 +338,7 @@ function handleCopyFromLayout(breakpoint: string) {
@change="handleBreakpointChange"
></VTabbar>
</div>
<VSpace>
<div class="page-header__actions">
<VButton ghost @click="handleBack">
{{ $t("core.common.buttons.back") }}
</VButton>
@ -398,7 +397,7 @@ function handleCopyFromLayout(breakpoint: string) {
</template>
{{ $t("core.common.buttons.save") }}
</VButton>
</VSpace>
</div>
</div>
<div class="dashboard m-4 transition-all" :style="designContainerStyles">

View File

@ -246,7 +246,7 @@ function getMenuItemRefDisplayName(menuItem: MenuTreeItem) {
/>
<VPageHeader :title="$t('core.menu.title')">
<template #icon>
<IconListSettings class="mr-2 self-center" />
<IconListSettings />
</template>
</VPageHeader>
<div class="m-0 md:m-4">

View File

@ -195,32 +195,30 @@ onMounted(() => {
<BasicLayout>
<VPageHeader :title="selectedTheme?.spec.displayName">
<template #icon>
<IconPalette class="mr-2 self-center" />
<IconPalette />
</template>
<template #actions>
<VSpace>
<VButton
v-show="!isActivated"
v-permission="['system:themes:manage']"
size="sm"
type="primary"
@click="handleActiveTheme()"
>
{{ $t("core.common.buttons.activate") }}
</VButton>
<VButton type="default" size="sm" @click="previewModal = true">
<template #icon>
<IconEye />
</template>
{{ $t("core.common.buttons.preview") }}
</VButton>
<VButton type="secondary" @click="themesModal = true">
<template #icon>
<IconListSettings />
</template>
{{ $t("core.theme.actions.management") }}
</VButton>
</VSpace>
<VButton
v-show="!isActivated"
v-permission="['system:themes:manage']"
size="sm"
type="primary"
@click="handleActiveTheme()"
>
{{ $t("core.common.buttons.activate") }}
</VButton>
<VButton type="default" size="sm" @click="previewModal = true">
<template #icon>
<IconEye />
</template>
{{ $t("core.common.buttons.preview") }}
</VButton>
<VButton type="secondary" @click="themesModal = true">
<template #icon>
<IconListSettings />
</template>
{{ $t("core.theme.actions.management") }}
</VButton>
</template>
</VPageHeader>

View File

@ -166,7 +166,6 @@ const description = computed(() => {
<VAvatar
:src="authProvider?.spec.logo"
:alt="authProvider?.spec.displayName"
class="mr-2"
size="sm"
/>
</template>

View File

@ -71,7 +71,7 @@ async function onSortUpdate() {
<template>
<VPageHeader :title="$t('core.identity_authentication.title')">
<template #icon>
<IconLockPasswordLine class="mr-2 self-center" />
<IconLockPasswordLine />
</template>
</VPageHeader>

View File

@ -63,7 +63,7 @@ onMounted(async () => {
<template>
<VPageHeader :title="$t('core.backup.title')">
<template #icon>
<IconServerLine class="mr-2 self-center" />
<IconServerLine />
</template>
<template #actions>
<VButton type="secondary" @click="handleCreate">

View File

@ -195,7 +195,7 @@ const handleDownloadLogfile = () => {
<template>
<VPageHeader :title="$t('core.overview.title')">
<template #icon>
<IconTerminalBoxLine class="mr-2 self-center" />
<IconTerminalBoxLine />
</template>
<template #actions>
<VButton size="sm" @click="handleCopy">

View File

@ -26,7 +26,6 @@ provide<Ref<Setting | undefined>>("setting", setting);
v-if="plugin"
:src="plugin.status?.logo"
:alt="plugin.spec.displayName"
class="mr-2"
size="sm"
/>
</template>

View File

@ -48,7 +48,7 @@ watch(
<template>
<VPageHeader :title="$t('core.plugin.extension-settings.title')">
<template #icon>
<IconSettings class="mr-2 self-center" />
<IconSettings />
</template>
<template #actions>
<VButton size="sm" @click="$router.back()">

View File

@ -159,33 +159,31 @@ onMounted(() => {
<VPageHeader :title="$t('core.plugin.title')">
<template #icon>
<IconPlug class="mr-2 self-center" />
<IconPlug />
</template>
<template #actions>
<VSpace>
<HasPermission :permissions="['*']">
<VButton
size="sm"
@click="$router.push({ name: 'PluginExtensionPointSettings' })"
>
<template #icon>
<IconSettings />
</template>
{{ $t("core.plugin.actions.extension-point-settings") }}
</VButton>
</HasPermission>
<HasPermission :permissions="['*']">
<VButton
v-permission="['system:plugins:manage']"
type="secondary"
@click="pluginInstallationModalVisible = true"
size="sm"
@click="$router.push({ name: 'PluginExtensionPointSettings' })"
>
<template #icon>
<IconAddCircle />
<IconSettings />
</template>
{{ $t("core.common.buttons.install") }}
{{ $t("core.plugin.actions.extension-point-settings") }}
</VButton>
</VSpace>
</HasPermission>
<VButton
v-permission="['system:plugins:manage']"
type="secondary"
@click="pluginInstallationModalVisible = true"
>
<template #icon>
<IconAddCircle />
</template>
{{ $t("core.common.buttons.install") }}
</VButton>
</template>
</VPageHeader>

View File

@ -104,7 +104,7 @@ const handleUpdateRole = async () => {
<template>
<VPageHeader :title="$t('core.role.detail.title')">
<template #icon>
<IconShieldUser class="mr-2 self-center" />
<IconShieldUser />
</template>
</VPageHeader>
<div class="m-0 md:m-4">

View File

@ -207,7 +207,7 @@ const handleDelete = async (role: Role) => {
<VPageHeader :title="$t('core.role.title')">
<template #icon>
<IconShieldUser class="mr-2 self-center" />
<IconShieldUser />
</template>
<template #actions>
<VButton

View File

@ -80,7 +80,7 @@ provide<Ref<Setting | undefined>>("setting", setting);
<template>
<VPageHeader :title="$t('core.setting.title')">
<template #icon>
<IconSettings class="mr-2 self-center" />
<IconSettings />
</template>
</VPageHeader>

View File

@ -43,7 +43,7 @@ const routes = computed(() => {
<template>
<VPageHeader :title="$t('core.tool.title')">
<template #icon>
<IconToolsFill class="mr-2 self-center" />
<IconToolsFill />
</template>
</VPageHeader>

View File

@ -187,40 +187,38 @@ function onCreationModalClose() {
<VPageHeader :title="$t('core.user.title')">
<template #icon>
<IconUserSettings class="mr-2 self-center" />
<IconUserSettings />
</template>
<template #actions>
<VSpace>
<VButton
v-permission="['system:roles:view']"
:route="{ name: 'Roles' }"
size="sm"
type="default"
>
<VButton
v-permission="['system:roles:view']"
:route="{ name: 'Roles' }"
size="sm"
type="default"
>
<template #icon>
<IconShieldUser />
</template>
{{ $t("core.user.actions.roles") }}
</VButton>
<HasPermission :permissions="['*']">
<VButton :route="{ name: 'AuthProviders' }" size="sm" type="default">
<template #icon>
<IconShieldUser />
<IconLockPasswordLine />
</template>
{{ $t("core.user.actions.roles") }}
{{ $t("core.user.actions.identity_authentication") }}
</VButton>
<HasPermission :permissions="['*']">
<VButton :route="{ name: 'AuthProviders' }" size="sm" type="default">
<template #icon>
<IconLockPasswordLine />
</template>
{{ $t("core.user.actions.identity_authentication") }}
</VButton>
</HasPermission>
<VButton
v-permission="['system:users:manage']"
type="secondary"
@click="creationModal = true"
>
<template #icon>
<IconAddCircle />
</template>
{{ $t("core.common.buttons.new") }}
</VButton>
</VSpace>
</HasPermission>
<VButton
v-permission="['system:users:manage']"
type="secondary"
@click="creationModal = true"
>
<template #icon>
<IconAddCircle />
</template>
{{ $t("core.common.buttons.new") }}
</VButton>
</template>
</VPageHeader>

View File

@ -4,15 +4,53 @@ defineProps<{
}>();
</script>
<template>
<div class="flex items-center justify-between bg-white p-4 h-14">
<div class="min-w-0 flex-1 self-center">
<h2 class="flex items-center truncate text-xl font-bold text-gray-800">
<slot name="icon" />
<span>{{ title }}</span>
</h2>
</div>
<div class="self-center">
<div class="page-header">
<h2 class="page-header__title">
<slot name="icon" />
<span class="page-header__title-text">{{ title }}</span>
</h2>
<div class="page-header__actions">
<slot name="actions" />
</div>
</div>
</template>
<style lang="scss">
.page-header {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 3.5rem;
background-color: theme("colors.white");
padding-left: 1rem;
padding-right: 1rem;
padding-top: 0.5rem;
padding-bottom: 0.5rem;
flex-wrap: wrap;
gap: theme("spacing.2");
&__title {
display: flex;
align-items: center;
text-overflow: truncate;
font-size: 1.25rem;
font-weight: 700;
color: theme("colors.gray.800");
gap: theme("spacing.2");
}
&__title-text {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
&__actions {
display: flex;
align-items: center;
justify-content: flex-end;
gap: theme("spacing.2");
flex-wrap: wrap;
}
}
</style>

View File

@ -34,7 +34,9 @@ fetchEditorProviders();
class="group flex w-full cursor-pointer items-center gap-2 rounded p-1 hover:bg-gray-100"
>
<VAvatar v-if="provider?.logo" :src="provider.logo" size="xs"></VAvatar>
<div class="select-none text-sm text-gray-600 group-hover:text-gray-900">
<div
class="select-none text-sm text-gray-600 group-hover:text-gray-900 whitespace-nowrap"
>
{{ provider?.displayName }}
</div>
<IconExchange class="h-4 w-4 text-gray-600 group-hover:text-gray-900" />

View File

@ -22,7 +22,6 @@ import {
Toast,
VButton,
VPageHeader,
VSpace,
} from "@halo-dev/components";
import type { EditorProvider } from "@halo-dev/console-shared";
import { useMutation } from "@tanstack/vue-query";
@ -467,51 +466,49 @@ useSlugify(
<template>
<VPageHeader :title="$t('core.post.title')">
<template #icon>
<IconBookRead class="mr-2 self-center" />
<IconBookRead />
</template>
<template #actions>
<VSpace>
<EditorProviderSelector
v-if="editorProviders.length > 1"
:provider="currentEditorProvider"
:allow-forced-select="!isUpdateMode"
@select="handleChangeEditorProvider"
/>
<EditorProviderSelector
v-if="editorProviders.length > 1"
:provider="currentEditorProvider"
:allow-forced-select="!isUpdateMode"
@select="handleChangeEditorProvider"
/>
<VButton
size="sm"
type="default"
:loading="isSaving && !isPublishing"
@click="handleSaveClick"
>
<template #icon>
<IconSave />
</template>
{{ $t("core.common.buttons.save") }}
</VButton>
<VButton
v-if="isUpdateMode"
size="sm"
type="default"
@click="handleOpenPostSettingEditModal"
>
<template #icon>
<IconSettings />
</template>
{{ $t("core.common.buttons.setting") }}
</VButton>
<HasPermission :permissions="['uc:posts:publish']">
<VButton
size="sm"
type="default"
:loading="isSaving && !isPublishing"
@click="handleSaveClick"
:loading="isPublishing"
type="secondary"
@click="handlePublishClick"
>
<template #icon>
<IconSave />
<IconSendPlaneFill />
</template>
{{ $t("core.common.buttons.save") }}
{{ $t("core.common.buttons.publish") }}
</VButton>
<VButton
v-if="isUpdateMode"
size="sm"
type="default"
@click="handleOpenPostSettingEditModal"
>
<template #icon>
<IconSettings />
</template>
{{ $t("core.common.buttons.setting") }}
</VButton>
<HasPermission :permissions="['uc:posts:publish']">
<VButton
:loading="isPublishing"
type="secondary"
@click="handlePublishClick"
>
<template #icon>
<IconSendPlaneFill />
</template>
{{ $t("core.common.buttons.publish") }}
</VButton>
</HasPermission>
</VSpace>
</HasPermission>
</template>
</VPageHeader>
<div class="editor border-t" style="height: calc(100vh - 3.5rem)">

View File

@ -104,7 +104,7 @@ const {
<template>
<VPageHeader :title="$t('core.uc_post.title')">
<template #icon>
<IconBookRead class="mr-2 self-center" />
<IconBookRead />
</template>
<template #actions>
<VButton :route="{ name: 'PostEditor' }" type="secondary">

View File

@ -131,7 +131,7 @@ function handleMarkAllAsRead() {
<template>
<VPageHeader :title="$t('core.uc_notification.title')">
<template #icon>
<IconNotificationBadgeLine class="mr-2 self-center" />
<IconNotificationBadgeLine />
</template>
</VPageHeader>
<div class="m-0 md:m-4">