mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-24 19:32:07 +00:00
Layout fixes
This commit is contained in:
@@ -13,11 +13,12 @@ export function AIPageSummary() {
|
||||
const visitedPagesRef = useRef(visitedPages);
|
||||
|
||||
const [summary, setSummary] = useState<{
|
||||
pageSummary?: string;
|
||||
keyFacts?: string;
|
||||
bigPicture?: string;
|
||||
}>({});
|
||||
|
||||
useEffect(() => {
|
||||
if (!summary.keyFacts) setLoading(true);
|
||||
if (!visitedPages?.length) return;
|
||||
|
||||
// Skip if the visited pages haven't changed
|
||||
@@ -47,12 +48,6 @@ export function AIPageSummary() {
|
||||
}
|
||||
})().finally(() => {
|
||||
setLoading(false);
|
||||
if (!toggle.manual) {
|
||||
setToggle({
|
||||
open: true,
|
||||
manual: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
@@ -64,13 +59,13 @@ export function AIPageSummary() {
|
||||
|
||||
return (
|
||||
toggle.open && (
|
||||
<div className="flex animate-fadeIn flex-col gap-4">
|
||||
{summary.pageSummary ? (
|
||||
<div className="flex min-w-64 animate-fadeIn flex-col gap-4">
|
||||
{summary.keyFacts ? (
|
||||
<div>
|
||||
<h5 className="mb-0.5 font-semibold text-tint-subtle text-xs uppercase">
|
||||
Key facts
|
||||
</h5>
|
||||
{summary.pageSummary}
|
||||
{summary.keyFacts}
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex w-full flex-wrap gap-2">
|
||||
|
||||
@@ -19,11 +19,39 @@ export const AdaptiveContext = React.createContext<AdaptiveContextType | null>(n
|
||||
*/
|
||||
export function AdaptiveContextProvider({ children }: { children: React.ReactNode }) {
|
||||
const [loading, setLoading] = React.useState(true);
|
||||
|
||||
// Start with a default state that works for SSR
|
||||
const [toggle, setToggle] = React.useState({
|
||||
open: true,
|
||||
open: false, // Default to open for SSR
|
||||
manual: false,
|
||||
});
|
||||
|
||||
// Update the toggle state on the client side only
|
||||
React.useEffect(() => {
|
||||
// Check for mobile only on the client
|
||||
const handleResize = () => {
|
||||
if (!toggle.manual) {
|
||||
const isMobile = window.innerWidth < 1280;
|
||||
setToggle((prev) => ({
|
||||
...prev,
|
||||
open: !isMobile,
|
||||
}));
|
||||
}
|
||||
};
|
||||
handleResize();
|
||||
|
||||
window.addEventListener('resize', handleResize);
|
||||
return () => window.removeEventListener('resize', handleResize);
|
||||
}, [toggle.manual]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (toggle.open) {
|
||||
document.body.classList.add('adaptive-pane');
|
||||
} else {
|
||||
document.body.classList.remove('adaptive-pane');
|
||||
}
|
||||
}, [toggle.open]);
|
||||
|
||||
return (
|
||||
<AdaptiveContext.Provider value={{ loading, setLoading, toggle, setToggle }}>
|
||||
{children}
|
||||
|
||||
@@ -10,8 +10,8 @@ export function AdaptivePane() {
|
||||
return (
|
||||
<div
|
||||
className={tcls(
|
||||
'flex flex-col gap-4 rounded-md straight-corners:rounded-none bg-tint-subtle ring-1 ring-tint-subtle ring-inset transition-all duration-300',
|
||||
toggle.open ? 'w-72 px-4 py-4' : 'w-56 px-4 py-3'
|
||||
'flex shrink-0 flex-col gap-4 overflow-x-hidden rounded-md straight-corners:rounded-none bg-tint-subtle ring-1 ring-tint-subtle ring-inset transition-all duration-300',
|
||||
toggle.open ? 'max-h px-4 py-4 xl:w-72' : 'px-4 py-3 xl:w-56'
|
||||
)}
|
||||
>
|
||||
<AdaptivePaneHeader />
|
||||
|
||||
@@ -21,6 +21,7 @@ export function AdaptivePaneHeader() {
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
className="text-tint-subtle text-xs"
|
||||
>
|
||||
{loading ? 'Basing on your context...' : 'Based on your context'}
|
||||
|
||||
@@ -40,7 +40,7 @@ export async function* streamPageSummary({
|
||||
},
|
||||
{
|
||||
schema: z.object({
|
||||
pageSummary: z
|
||||
keyFacts: z
|
||||
.string()
|
||||
.describe(
|
||||
'A collection of key facts from the page that together form a comprehensive summary. Keep it under 30 words.'
|
||||
@@ -201,13 +201,13 @@ export async function* streamPageSummary({
|
||||
]);
|
||||
|
||||
for await (const value of stream) {
|
||||
const pageSummary = value.pageSummary;
|
||||
const keyFacts = value.keyFacts;
|
||||
const bigPicture = value.bigPicture;
|
||||
|
||||
if (!pageSummary) continue;
|
||||
if (!keyFacts) continue;
|
||||
|
||||
yield {
|
||||
pageSummary,
|
||||
keyFacts,
|
||||
bigPicture,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -106,12 +106,16 @@ export function Header(props: { context: GitBookSiteContext; withTopHeader?: boo
|
||||
'lg:max-w-lg',
|
||||
'lg:ml-[max(calc((100%-18rem-48rem-3rem)/2),1.5rem)]', // container (100%) - sidebar (18rem) - content (48rem) - margin (3rem)
|
||||
'xl:ml-[max(calc((100%-18rem-48rem-14rem-3rem)/2),1.5rem)]', // container (100%) - sidebar (18rem) - content (48rem) - outline (14rem) - margin (3rem)
|
||||
'adaptive-pane:xl:ml-[max(calc((100%-18rem-48rem-18rem-3rem)/2),1.5rem)]',
|
||||
'page-no-toc:lg:ml-[max(calc((100%-18rem-48rem-18rem-3rem)/2),0rem)]',
|
||||
'page-full-width:lg:ml-[max(calc((100%-18rem-103rem-3rem)/2),1.5rem)]',
|
||||
'page-full-width:2xl:ml-[max(calc((100%-18rem-96rem-14rem+3rem)/2),1.5rem)]',
|
||||
'[body.adaptive-pane:has(.page-full-width)_&]:2xl:ml-[max(calc((100%-18rem-96rem-18rem+3rem)/2),1.5rem)]',
|
||||
'md:mr-auto',
|
||||
'order-last',
|
||||
'md:order-[unset]',
|
||||
'transition-[margin-left]',
|
||||
'duration-300',
|
||||
]
|
||||
: ['order-last']
|
||||
)}
|
||||
|
||||
@@ -35,10 +35,11 @@ export function PageAside(props: {
|
||||
<aside
|
||||
className={tcls(
|
||||
'group/aside',
|
||||
'hidden',
|
||||
'flex',
|
||||
// 'hidden',
|
||||
'xl:flex',
|
||||
'flex-col',
|
||||
'basis-56',
|
||||
'xl:basis-56',
|
||||
'grow-0',
|
||||
'shrink-0',
|
||||
'break-anywhere', // To prevent long words in headings from breaking the layout
|
||||
@@ -46,7 +47,14 @@ export function PageAside(props: {
|
||||
'text-tint',
|
||||
'contrast-more:text-tint-strong',
|
||||
'text-sm',
|
||||
'sticky',
|
||||
'xl:sticky',
|
||||
|
||||
'lg:px-12',
|
||||
'xl:px-0',
|
||||
'mx-auto',
|
||||
'xl:mx-0',
|
||||
'w-full',
|
||||
'max-w-3xl',
|
||||
|
||||
// Without header
|
||||
'lg:top-0',
|
||||
@@ -79,22 +87,22 @@ export function PageAside(props: {
|
||||
'page-api-block:p-2'
|
||||
)}
|
||||
>
|
||||
<div className="lg:top:0 sticky flex grow flex-col gap-6 overflow-y-auto overflow-x-visible border-none py-8 *:border-tint-subtle site-header-sections:lg:top-[6.75rem] site-header:lg:top-16 [&>*:not(:first-child)]:border-t [&>*:not(:first-child)]:pt-6">
|
||||
<div className="lg:top:0 sticky flex grow flex-col gap-6 overflow-y-auto overflow-x-visible border-none pt-8 *:border-tint-subtle site-header-sections:lg:top-[6.75rem] site-header:lg:top-16 xl:pb-8 [&>*:not(:first-child)]:border-t [&>*:not(:first-child)]:pt-6">
|
||||
{useAdaptivePane ? <AdaptivePane /> : null}
|
||||
{page.layout.outline ? (
|
||||
<>
|
||||
<div className="hidden flex-col gap-6 xl:flex">
|
||||
<PageOutline document={document} context={context} />
|
||||
<PageActions
|
||||
page={page}
|
||||
context={context}
|
||||
withPageFeedback={withPageFeedback}
|
||||
/>
|
||||
</>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
<div
|
||||
className={tcls(
|
||||
'sticky bottom-0 z-10 mt-auto flex flex-col bg-tint-base theme-gradient-tint:bg-gradient-tint theme-gradient:bg-gradient-primary theme-muted:bg-tint-subtle pb-4 page-api-block:xl:max-2xl:hidden page-api-block:xl:max-2xl:pb-0 page-api-block:xl:max-2xl:group-hover/aside:flex [html.sidebar-filled.theme-bold.tint_&]:bg-tint-subtle',
|
||||
'sticky bottom-0 z-10 mt-auto hidden flex-col bg-tint-base theme-gradient-tint:bg-gradient-tint theme-gradient:bg-gradient-primary theme-muted:bg-tint-subtle pb-4 xl:flex page-api-block:xl:max-2xl:hidden page-api-block:xl:max-2xl:pb-0 page-api-block:xl:max-2xl:group-hover/aside:flex [html.sidebar-filled.theme-bold.tint_&]:bg-tint-subtle',
|
||||
'page-api-block:xl:max-2xl:bg-transparent'
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -70,7 +70,7 @@ export async function SitePage(props: SitePageProps) {
|
||||
<PageCover as="full" page={page} cover={page.cover} context={context} />
|
||||
) : null}
|
||||
{/* We use a flex row reverse to render the aside first because the page is streamed. */}
|
||||
<div className="flex grow flex-row-reverse justify-end">
|
||||
<div className="flex grow flex-col xl:flex-row-reverse xl:justify-end">
|
||||
<PageAside
|
||||
page={page}
|
||||
document={document}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import type { SVGProps } from 'react';
|
||||
|
||||
import { tcls } from '@/lib/tailwind';
|
||||
|
||||
export const Loading = ({
|
||||
busy = true,
|
||||
...props
|
||||
@@ -13,29 +11,26 @@ export const Loading = ({
|
||||
preserveAspectRatio="xMaxYMid meet"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-busy
|
||||
aria-busy={busy}
|
||||
{...props}
|
||||
>
|
||||
<title>{busy ? 'Loading' : 'Loaded'}</title>
|
||||
<path
|
||||
className={tcls(
|
||||
busy
|
||||
? 'animate-[pathLoading_2s_ease_infinite_forwards]'
|
||||
: 'animate-[pathLoading_2s_ease_forwards]'
|
||||
)}
|
||||
d="M6 59.5V56.291C6 45.8865 11.5194 36.263 20.5 31.0091V31.0091L60.9857 7.32407C63.4452 5.88525 66.4843 5.86317 68.9643 7.26611L116 33.8734L70.4183 60.2148C67.9468 61.6431 64.9014 61.6462 62.4269 60.223L29.9772 41.5592C19.3106 35.4242 6 43.1236 6 55.4288V64.8776C6 73.4486 10.5708 81.3691 17.9918 85.6575L54.59 106.807C62.0198 111.1 71.1766 111.1 78.6064 106.807L116.364 84.9874C120.074 82.8432 122.36 78.883 122.36 74.5975V59.2647C122.36 57.7248 120.692 56.7626 119.359 57.5331L72.6023 84.5529C68.8874 86.6996 64.309 86.6996 60.5941 84.5529L26 64.5617"
|
||||
stroke="currentColor"
|
||||
pathLength="100"
|
||||
strokeOpacity={busy ? 0.24 : 1}
|
||||
className="transition-[stroke-opacity] duration-500"
|
||||
fill="none"
|
||||
strokeWidth="11"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
className="animate-[pathLoading_2s_ease_infinite_forwards] transition-opacity delay-500 duration-500"
|
||||
d="M6 59.5V56.291C6 45.8865 11.5194 36.263 20.5 31.0091V31.0091L60.9857 7.32407C63.4452 5.88525 66.4843 5.86317 68.9643 7.26611L116 33.8734L70.4183 60.2148C67.9468 61.6431 64.9014 61.6462 62.4269 60.223L29.9772 41.5592C19.3106 35.4242 6 43.1236 6 55.4288V64.8776C6 73.4486 10.5708 81.3691 17.9918 85.6575L54.59 106.807C62.0198 111.1 71.1766 111.1 78.6064 106.807L116.364 84.9874C120.074 82.8432 122.36 78.883 122.36 74.5975V59.2647C122.36 57.7248 120.692 56.7626 119.359 57.5331L72.6023 84.5529C68.8874 86.6996 64.309 86.6996 60.5941 84.5529L26 64.5617"
|
||||
stroke="currentColor"
|
||||
pathLength="100"
|
||||
strokeOpacity={busy ? 0.24 : 1}
|
||||
className="transition-opacity duration-1000"
|
||||
fill="none"
|
||||
strokeWidth="11"
|
||||
strokeLinecap="round"
|
||||
|
||||
@@ -465,6 +465,11 @@ const config: Config = {
|
||||
'body:has(.page-no-toc):has(#site-header:not(.mobile-only) #variants) &',
|
||||
]);
|
||||
|
||||
/**
|
||||
* Variant when the adaptive pane is open.
|
||||
*/
|
||||
addVariant('adaptive-pane', 'body.adaptive-pane &');
|
||||
|
||||
const customisationVariants = {
|
||||
// Sidebar styles
|
||||
sidebar: ['sidebar-default', 'sidebar-filled'],
|
||||
|
||||
Reference in New Issue
Block a user