fix: bug fixes (#2201)

* fix(editor): hide transclusion borders and reset spacing in read-only mode

* feat(share): add full width toggle for shared pages

* feat(share): support resizing sidebar on shared pages

* fix: auto redirect if there is only one SSO provider.
- fix tighten sso redirect
- fix share tree margin

* sync

* package overrides
This commit is contained in:
Philip Okugbe
2026-05-14 02:54:00 +01:00
committed by GitHub
parent cea9be7926
commit 299a9ca3c8
15 changed files with 696 additions and 822 deletions
@@ -166,7 +166,7 @@ export default function useAuth() {
const handleLogout = async () => {
setCurrentUser(RESET);
await logout();
window.location.replace(APP_ROUTE.AUTH.LOGIN);
window.location.replace(`${APP_ROUTE.AUTH.LOGIN}?logout=1`);
};
const handleForgotPassword = async (data: IForgotPassword) => {
@@ -35,6 +35,7 @@ export default function TransclusionReferenceView(props: NodeViewProps) {
return (
<NodeViewWrapper
className={classes.includeWrap}
data-editable={isEditable ? "true" : "false"}
data-focused={isEditable && props.selected ? "true" : "false"}
data-menu-open={openMenus > 0 ? "true" : "false"}
contentEditable={false}
@@ -62,6 +62,7 @@ export default function TransclusionView(props: NodeViewProps) {
return (
<NodeViewWrapper
className={classes.transclusionWrap}
data-editable={isEditable ? "true" : "false"}
data-menu-open={openMenus > 0 ? "true" : "false"}
data-id={transclusionId ?? undefined}
>
@@ -44,8 +44,29 @@
transition: border 0.3s;
}
.transclusionWrap:hover,
.transclusionWrap:focus-within {
.transclusionWrap[data-editable="false"],
.includeWrap[data-editable="false"] {
margin-left: 0;
margin-right: 0;
width: 100%;
padding: 0;
}
/* Cancel the wrapping .react-renderer's vertical spacing in read-only mode
so the synced block sits flush with surrounding paragraphs (whose own
margins already provide the right rhythm). */
:global(.react-renderer.node-transclusionSource):has(
.transclusionWrap[data-editable="false"]
),
:global(.react-renderer.node-transclusionReference):has(
.includeWrap[data-editable="false"]
) {
margin-top: 0;
margin-bottom: 0;
}
.transclusionWrap[data-editable="true"]:hover,
.transclusionWrap[data-editable="true"]:focus-within {
border: 2px solid
light-dark(
var(--mantine-color-orange-2),
@@ -114,9 +135,9 @@
transition: border 0.3s;
}
.includeWrap:hover,
.includeWrap[data-focused="true"],
.includeWrap[data-menu-open="true"] {
.includeWrap[data-editable="true"]:hover,
.includeWrap[data-editable="true"][data-focused="true"],
.includeWrap[data-editable="true"][data-menu-open="true"] {
border: 2px solid
light-dark(
var(--mantine-color-orange-2),
@@ -1,6 +1,11 @@
import { atom } from "jotai";
import { atomWithStorage } from "jotai/utils";
import { ISharedPageTree } from "@/features/share/types/share.types";
import { SharedPageTreeNode } from "@/features/share/utils";
export const sharedPageTreeAtom = atom<ISharedPageTree | null>(null);
export const sharedTreeDataAtom = atom<SharedPageTreeNode[] | null>(null);
export const sharedTreeDataAtom = atom<SharedPageTreeNode[] | null>(null);
export const sharedPageFullWidthAtom = atomWithStorage<boolean>(
"sharedPageFullWidth",
false,
);
@@ -1,4 +1,4 @@
import React, { useEffect, useMemo } from "react";
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import {
ActionIcon,
AppShell,
@@ -14,11 +14,16 @@ import { readOnlyEditorAtom } from "@/features/editor/atoms/editor-atoms.ts";
import { ThemeToggle } from "@/components/theme-toggle.tsx";
import { useAtomValue, useSetAtom } from "jotai";
import { useAtom } from "jotai";
import { sharedPageTreeAtom, sharedTreeDataAtom } from "@/features/share/atoms/shared-page-atom";
import {
sharedPageFullWidthAtom,
sharedPageTreeAtom,
sharedTreeDataAtom,
} from "@/features/share/atoms/shared-page-atom";
import { buildSharedPageTree } from "@/features/share/utils";
import {
desktopSidebarAtom,
mobileSidebarAtom,
sidebarWidthAtom,
} from "@/components/layouts/global/hooks/atoms/sidebar-atom.ts";
import SidebarToggle from "@/components/ui/sidebar-toggle-button.tsx";
import { useTranslation } from "react-i18next";
@@ -27,7 +32,7 @@ import {
mobileTableOfContentAsideAtom,
tableOfContentAsideAtom,
} from "@/features/share/atoms/sidebar-atom.ts";
import { IconList } from "@tabler/icons-react";
import { IconArrowsHorizontal, IconList } from "@tabler/icons-react";
import { useToggleToc } from "@/features/share/hooks/use-toggle-toc.ts";
import classes from "./share.module.css";
import {
@@ -55,6 +60,46 @@ export default function ShareShell({
const [mobileTocOpened] = useAtom(mobileTableOfContentAsideAtom);
const toggleTocMobile = useToggleToc(mobileTableOfContentAsideAtom);
const toggleToc = useToggleToc(tableOfContentAsideAtom);
const [fullWidth, setFullWidth] = useAtom(sharedPageFullWidthAtom);
const [sidebarWidth, setSidebarWidth] = useAtom(sidebarWidthAtom);
const [isResizing, setIsResizing] = useState(false);
const sidebarRef = useRef<HTMLElement | null>(null);
const startResizing = useCallback((e: React.MouseEvent) => {
e.preventDefault();
setIsResizing(true);
}, []);
const stopResizing = useCallback(() => {
setIsResizing(false);
}, []);
const resize = useCallback(
(e: MouseEvent) => {
if (!isResizing || !sidebarRef.current) return;
const newWidth =
e.clientX - sidebarRef.current.getBoundingClientRect().left;
if (newWidth < 220) {
setSidebarWidth(220);
return;
}
if (newWidth > 600) {
setSidebarWidth(600);
return;
}
setSidebarWidth(newWidth);
},
[isResizing, setSidebarWidth],
);
useEffect(() => {
window.addEventListener("mousemove", resize);
window.addEventListener("mouseup", stopResizing);
return () => {
window.removeEventListener("mousemove", resize);
window.removeEventListener("mouseup", stopResizing);
};
}, [resize, stopResizing]);
const { shareId } = useParams();
const { data } = useGetSharedPageTreeQuery(shareId);
@@ -81,7 +126,7 @@ export default function ShareShell({
header={{ height: 50 }}
{...(data?.pageTree?.length > 1 && {
navbar: {
width: 300,
width: sidebarWidth,
breakpoint: "sm",
collapsed: {
mobile: !mobileOpened,
@@ -166,6 +211,20 @@ export default function ShareShell({
<IconList size={20} stroke={2} />
</ActionIcon>
</Tooltip>
<Tooltip label={t("Full width")} withArrow>
<ActionIcon
variant={fullWidth ? "light" : "default"}
style={fullWidth ? undefined : { border: "none" }}
aria-label={t("Full width")}
aria-pressed={fullWidth}
onClick={() => setFullWidth((v) => !v)}
visibleFrom="sm"
size="sm"
>
<IconArrowsHorizontal size={20} stroke={2} />
</ActionIcon>
</Tooltip>
</>
<ThemeToggle />
@@ -174,7 +233,11 @@ export default function ShareShell({
</AppShell.Header>
{data?.pageTree?.length > 1 && (
<AppShell.Navbar p="md" className={classes.navbar}>
<AppShell.Navbar p="md" className={classes.navbar} ref={sidebarRef}>
<div
className={classes.resizeHandle}
onMouseDown={startResizing}
/>
<MemoizedSharedTree sharedPageTree={data} />
</AppShell.Navbar>
)}
@@ -10,6 +10,7 @@
.treeNode {
text-decoration: none;
user-select: none;
padding-bottom: 0;
}
.navbar,
@@ -18,3 +19,26 @@
width: 350px;
}
}
.resizeHandle {
width: 3px;
cursor: col-resize;
position: absolute;
right: 0;
top: 0;
bottom: 0;
z-index: 1;
&:hover,
&:active {
width: 5px;
background: light-dark(
var(--mantine-color-gray-4),
var(--mantine-color-dark-5)
);
}
@media (max-width: $mantine-breakpoint-sm) {
display: none;
}
}