;
+};
+
+export const useToolbarSlot = (): HTMLElement | null => useContext(SlotContext).element;
diff --git a/webapp/src/components/space_view/page_content/page_content.module.scss b/webapp/src/components/space_view/page_content/page_content.module.scss
index a66eb930..bc583584 100644
--- a/webapp/src/components/space_view/page_content/page_content.module.scss
+++ b/webapp/src/components/space_view/page_content/page_content.module.scss
@@ -20,8 +20,7 @@
display: flex;
flex-direction: column;
gap: 8px;
- padding: 32px 0 24px;
- border-bottom: 1px solid rgba(var(--center-channel-color-rgb), 0.12);
+ padding: 32px 0 0;
&:hover .topActions,
&:focus-within .topActions {
diff --git a/webapp/src/components/space_view/page_content/page_content.tsx b/webapp/src/components/space_view/page_content/page_content.tsx
index 94d4b7dd..aaad12a0 100644
--- a/webapp/src/components/space_view/page_content/page_content.tsx
+++ b/webapp/src/components/space_view/page_content/page_content.tsx
@@ -94,6 +94,7 @@ const PageContent = ({page, draft, editing}: Props) => {
spaceId={subject.spaceId}
pageId={subject.id}
isDraft={!page}
+ editing={editing}
/>
>
) : (
diff --git a/webapp/src/components/space_view/page_header.tsx b/webapp/src/components/space_view/page_header.tsx
index d64392c6..0eccf4fa 100644
--- a/webapp/src/components/space_view/page_header.tsx
+++ b/webapp/src/components/space_view/page_header.tsx
@@ -2,9 +2,12 @@
// See LICENSE.txt for license information.
import classNames from 'classnames';
+import {useAutosaveStatus} from 'hooks/autosave_status';
import {useFullscreen} from 'hooks/fullscreen';
+import {usePagePresence} from 'hooks/page_presence';
import {useCreateRootPage} from 'hooks/pages';
import {useSidebarWidth} from 'hooks/sidebar_width';
+import {useCurrentUserId} from 'hooks/user';
import React, {useState} from 'react';
import {FormattedMessage, defineMessage, useIntl} from 'react-intl';
import {Timestamp} from 'webapp_globals';
@@ -20,6 +23,7 @@ import PencilOutlineIcon from '@mattermost/compass-icons/components/pencil-outli
import PlusIcon from '@mattermost/compass-icons/components/plus';
import {Button} from 'components/form_controls/button';
+import AutosaveIndicator from 'components/page_editor/autosave_indicator';
import PageMenu from 'components/page_menu/page_menu';
import Spacer from 'components/spacer/spacer';
@@ -86,6 +90,7 @@ type Props = {
const PageHeader = ({space, page, draft, treeOpen, editing, commentsOpen, onTogglePages, onToggleComments, onToggleEdit, onPublish}: Props) => {
const {formatMessage} = useIntl();
const createRootPage = useCreateRootPage(space.id);
+ const autosaveStatus = useAutosaveStatus();
// Read here rather than passed in: the sidebar it hides belongs to the product
// root, which shares no state with this header — see useFullscreen.
@@ -131,6 +136,9 @@ const PageHeader = ({space, page, draft, treeOpen, editing, commentsOpen, onTogg
// otherwise the space's.
const updatedAt = page?.update_at ?? draft?.update_at ?? space.update_at;
+ const currentUserId = useCurrentUserId();
+ const activeEditors = usePagePresence(space.id, subject?.id ?? '', currentUserId);
+
// Timestamp's `style` is a narrow/short/long format variant, not a DOM style object.
/* eslint-disable react/style-prop-object */
const updatedRelative = (
@@ -182,13 +190,26 @@ const PageHeader = ({space, page, draft, treeOpen, editing, commentsOpen, onTogg
-
-
-
+ {activeEditors.length > 0 && (
+
+
+
+ )}
+ {autosaveStatus ? (
+
+ ) : (
+
+
+
+ )}
{page && (