diff --git a/entry_types/scrolled/package/src/frontend/commenting/EditableText.js b/entry_types/scrolled/package/src/frontend/commenting/EditableText.js
index d8d07e27c4..0cb5451bce 100644
--- a/entry_types/scrolled/package/src/frontend/commenting/EditableText.js
+++ b/entry_types/scrolled/package/src/frontend/commenting/EditableText.js
@@ -9,6 +9,7 @@ import {PlainEditableText, renderElement, renderLeaf} from '../EditableText';
import {useContentElementAttributes} from '../useContentElementAttributes';
import {useAddCommentMode} from './AddCommentModeProvider';
import {useCommentDisplayFilter} from './CommentDisplayFilterProvider';
+import {useCommentingVisibility} from './CommentingVisibilityProvider';
import {useSelectedSubject} from './SelectedSubjectProvider';
import {AddCommentHint} from './AddCommentHint';
import {PopoversColumn} from './PopoversColumn';
@@ -25,8 +26,9 @@ const defaultValue = [{
export const EditableText = React.memo(function EditableText(props) {
const {inlineComments} = useContentElementAttributes();
+ const {visible} = useCommentingVisibility();
- if (inlineComments) {
+ if (inlineComments && visible) {
return ;
}
diff --git a/entry_types/scrolled/package/src/frontend/commenting/EntryDecorator.js b/entry_types/scrolled/package/src/frontend/commenting/EntryDecorator.js
index 3341a4fdd8..18dd142a24 100644
--- a/entry_types/scrolled/package/src/frontend/commenting/EntryDecorator.js
+++ b/entry_types/scrolled/package/src/frontend/commenting/EntryDecorator.js
@@ -5,6 +5,7 @@ import {createReviewSession} from 'pageflow/review';
import {ReviewStateProvider, ReviewMessageHandler} from 'pageflow-scrolled/review';
import {AddCommentModeProvider} from './AddCommentModeProvider';
import {CommentDisplayFilterProvider} from './CommentDisplayFilterProvider';
+import {CommentingVisibilityProvider} from './CommentingVisibilityProvider';
import {SelectedSubjectProvider} from './SelectedSubjectProvider';
import {FloatingToolbar} from './FloatingToolbar';
@@ -12,14 +13,16 @@ export function EntryDecorator({commentingInitialState, children}) {
return (
-
-
-
- {children}
-
-
-
-
+
+
+
+
+ {children}
+
+
+
+
+
);
}
diff --git a/entry_types/scrolled/package/src/frontend/commenting/FloatingToolbar.js b/entry_types/scrolled/package/src/frontend/commenting/FloatingToolbar.js
index 2886249e77..41c401ad77 100644
--- a/entry_types/scrolled/package/src/frontend/commenting/FloatingToolbar.js
+++ b/entry_types/scrolled/package/src/frontend/commenting/FloatingToolbar.js
@@ -1,19 +1,34 @@
-import React from 'react';
+import React, {useEffect} from 'react';
import classNames from 'classnames';
import {useLocatedCommentThreads} from 'pageflow-scrolled/review';
import {useI18n} from '../i18n';
import {useAddCommentMode} from './AddCommentModeProvider';
import {useCommentDisplayFilter} from './CommentDisplayFilterProvider';
+import {useCommentingVisibility} from './CommentingVisibilityProvider';
import {useCommentNavigation} from './SelectedSubjectProvider';
import AddCommentIcon from './images/addComment.svg';
import CancelCommentIcon from './images/cancelComment.svg';
import ChevronIcon from './images/chevron.svg';
+import HideCommentsIcon from './images/hideComments.svg';
+import ShowCommentsIcon from './images/showComments.svg';
import styles from './FloatingToolbar.module.css';
export function FloatingToolbar() {
const {t} = useI18n({locale: 'ui'});
+ const {visible} = useCommentingVisibility();
+ const {active, deactivate} = useAddCommentMode();
+
+ useEffect(() => {
+ if (!visible && active) {
+ deactivate();
+ }
+ }, [visible, active, deactivate]);
+
+ if (!visible) {
+ return ;
+ }
return (
+
);
}
+function HideCommentsButton() {
+ const {t} = useI18n({locale: 'ui'});
+ const {toggle} = useCommentingVisibility();
+ const label = t('pageflow_scrolled.review.hide_comments');
+
+ return (
+
+ );
+}
+
+function ShowCommentsButton() {
+ const {t} = useI18n({locale: 'ui'});
+ const {toggle} = useCommentingVisibility();
+ const label = t('pageflow_scrolled.review.show_comments');
+
+ return (
+
+ );
+}
+
function PositionIndicator() {
const {t} = useI18n({locale: 'ui'});
const {count, position} = useCommentNavigation();
diff --git a/entry_types/scrolled/package/src/frontend/commenting/FloatingToolbar.module.css b/entry_types/scrolled/package/src/frontend/commenting/FloatingToolbar.module.css
index adfcccc6c0..9add2f8ee8 100644
--- a/entry_types/scrolled/package/src/frontend/commenting/FloatingToolbar.module.css
+++ b/entry_types/scrolled/package/src/frontend/commenting/FloatingToolbar.module.css
@@ -1,3 +1,13 @@
+/* Collapsing/expanding is animated with a view transition (see
+ CommentingVisibilityProvider). The toolbar and the puck share
+ `comment-toolbar`, so the toolbar surface and its content morph into the
+ puck together (the content deforms and cross-fades along with the rect,
+ having no counterpart in the puck). The toggle icons (eye and bubble) share
+ `comment-toolbar-icon` and morph on their own — naming them lifts them out
+ of the surface snapshot so the icon swap stays crisp. The
+ ::view-transition old/new overrides below stretch the surface snapshots to
+ fill the animating box, so it reshapes into the puck rather than scaling
+ down with a fixed aspect ratio. */
.toolbar {
position: fixed;
bottom: space(3);
@@ -11,6 +21,67 @@
border: 1px solid var(--ui-on-primary-color-lightest);
border-radius: rounded(lg);
box-shadow: var(--ui-box-shadow-md);
+ view-transition-name: comment-toolbar;
+}
+
+.toggleIcon {
+ view-transition-name: comment-toolbar-icon;
+}
+
+:global(::view-transition-old(comment-toolbar)),
+:global(::view-transition-new(comment-toolbar)) {
+ width: 100%;
+ height: 100%;
+ object-fit: fill;
+}
+
+/* Collapsed state: a small tab docked flush to the bottom viewport edge,
+ roughly below where the hide button sits in the expanded toolbar (away from
+ the corner where custom floating buttons tend to live).
+
+ Idle opacity is driven by an animation rather than a transition so it plays
+ nicely with the collapse morph: `puckIdle` holds full opacity through its
+ delay, which spans both the view-transition snapshot capture and the reveal,
+ so the puck morphs in fully opaque (nothing flips), lingers, then fades to
+ its semi-transparent rest state. Hovering or focusing cancels the animation
+ for an instant opaque state; leaving re-runs it, so it only dims again a
+ moment after the cursor leaves. */
+.puck {
+ position: fixed;
+ bottom: 0;
+ right: space(16);
+ z-index: 1100;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: var(--ui-on-primary-color);
+ background: var(--ui-primary-color);
+ border: 1px solid var(--ui-on-primary-color-lightest);
+ border-bottom: none;
+ border-top-left-radius: rounded(md);
+ border-top-right-radius: rounded(md);
+ box-shadow: var(--ui-box-shadow-md);
+ padding: space(2);
+ cursor: pointer;
+ opacity: 0.6;
+ animation: puckIdle 0.5s ease 0.5s backwards;
+ view-transition-name: comment-toolbar;
+}
+
+.puck:hover,
+.puck:focus-visible {
+ opacity: 1;
+ animation: none;
+}
+
+@keyframes puckIdle {
+ from {
+ opacity: 1;
+ }
+
+ to {
+ opacity: 0.6;
+ }
}
.navigation {
diff --git a/entry_types/scrolled/package/src/frontend/commenting/SectionDecorator.js b/entry_types/scrolled/package/src/frontend/commenting/SectionDecorator.js
index 64da981d2b..d27561c63d 100644
--- a/entry_types/scrolled/package/src/frontend/commenting/SectionDecorator.js
+++ b/entry_types/scrolled/package/src/frontend/commenting/SectionDecorator.js
@@ -5,6 +5,7 @@ import {useCommentThreads} from 'pageflow-scrolled/review';
import {useI18n} from '../i18n';
import {useAddCommentMode} from './AddCommentModeProvider';
import {useCommentDisplayFilter} from './CommentDisplayFilterProvider';
+import {useCommentingVisibility} from './CommentingVisibilityProvider';
import {useSelectedSubject} from './SelectedSubjectProvider';
import {Popover} from './Popover';
@@ -12,6 +13,7 @@ import AddCommentIcon from './images/addComment.svg';
import styles from './SectionDecorator.module.css';
export function SectionDecorator({section, children}) {
+ const {visible} = useCommentingVisibility();
const {active} = useAddCommentMode();
const {isSelected} = useSelectedSubject('Section', section.permaId);
const {resolution} = useCommentDisplayFilter();
@@ -22,6 +24,10 @@ export function SectionDecorator({section, children}) {
});
const hasThreads = threads.length > 0;
+ if (!visible) {
+ return children;
+ }
+
return (
{children}
diff --git a/entry_types/scrolled/package/src/frontend/commenting/images/hideComments.svg b/entry_types/scrolled/package/src/frontend/commenting/images/hideComments.svg
new file mode 100644
index 0000000000..78e696996b
--- /dev/null
+++ b/entry_types/scrolled/package/src/frontend/commenting/images/hideComments.svg
@@ -0,0 +1 @@
+
diff --git a/entry_types/scrolled/package/src/frontend/commenting/images/showComments.svg b/entry_types/scrolled/package/src/frontend/commenting/images/showComments.svg
new file mode 100644
index 0000000000..69b68652f8
--- /dev/null
+++ b/entry_types/scrolled/package/src/frontend/commenting/images/showComments.svg
@@ -0,0 +1 @@
+