mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-22 18:43:29 +00:00
Improve Docs Embed layout (#3994)
This commit is contained in:
@@ -87,7 +87,7 @@ export function AIChat() {
|
||||
>
|
||||
<EmbeddableFrame className="relative shrink-0 border-tint-subtle border-l to-tint-base">
|
||||
<EmbeddableFrameMain data-testid="ai-chat">
|
||||
<EmbeddableFrameHeader>
|
||||
<EmbeddableFrameHeader className="not-embed:px-4">
|
||||
<AIChatDynamicIcon trademark={config.trademark} />
|
||||
<EmbeddableFrameHeaderMain>
|
||||
<EmbeddableFrameTitle>
|
||||
@@ -106,7 +106,7 @@ export function AIChat() {
|
||||
/>
|
||||
</EmbeddableFrameButtons>
|
||||
</EmbeddableFrameHeader>
|
||||
<EmbeddableFrameBody>
|
||||
<EmbeddableFrameBody className="not-embed:px-4">
|
||||
<AIChatBody
|
||||
chatController={chatController}
|
||||
chat={chat}
|
||||
@@ -224,7 +224,7 @@ export function AIChatBody(props: {
|
||||
<>
|
||||
<ScrollContainer
|
||||
className="shrink grow basis-80 animate-fade-in-slow [container-type:size]"
|
||||
contentClassName="p-4 gutter-stable flex flex-col gap-4"
|
||||
contentClassName="py-4 gutter-stable flex flex-col gap-4"
|
||||
orientation="vertical"
|
||||
trailing={{ fade: false, button: true }}
|
||||
active={`#message-group-${chat.messages.filter((message) => message.role === 'user').length - 1}`}
|
||||
@@ -272,7 +272,7 @@ export function AIChatBody(props: {
|
||||
)}
|
||||
</ScrollContainer>
|
||||
|
||||
<div className="flex flex-col gap-2 px-4 pb-4">
|
||||
<div className="flex flex-col gap-2 pb-4">
|
||||
{/* Display an error banner when something went wrong. */}
|
||||
{chat.error ? <AIChatError chatController={chatController} /> : null}
|
||||
|
||||
|
||||
@@ -50,9 +50,9 @@ export async function EmbeddableDocsPage(
|
||||
<EmbeddableIframeButtons />
|
||||
</EmbeddableFrameSidebar>
|
||||
<EmbeddableFrameMain data-testid="embed-docs-page">
|
||||
<div className="relative flex not-hydrated:animate-blur-in-slow flex-col">
|
||||
<EmbeddableFrameHeader>
|
||||
<HeaderMobileMenu className="-ml-2 page-no-toc:hidden" />
|
||||
<div className="relative flex flex-col border-tint-subtle border-b theme-bold:bg-header-background">
|
||||
<EmbeddableFrameHeader className="theme-bold:text-header-link">
|
||||
<HeaderMobileMenu className="-ml-2 page-no-toc:hidden theme-bold:text-header-link hover:theme-bold:bg-header-link/3 hover:theme-bold:text-header-link lg:hidden" />
|
||||
<EmbeddableFrameHeaderMain>
|
||||
<EmbeddableFrameTitle>{context.site.title}</EmbeddableFrameTitle>
|
||||
</EmbeddableFrameHeaderMain>
|
||||
@@ -69,7 +69,7 @@ export async function EmbeddableDocsPage(
|
||||
</EmbeddableFrameHeader>
|
||||
{context.sections ? (
|
||||
<SiteSectionTabs
|
||||
className="-mt-2 border-tint-subtle border-b"
|
||||
className="not-theme-bold:-mt-2 theme-bold:bg-tint-base"
|
||||
sections={encodeClientSiteSections(context, context.sections)}
|
||||
/>
|
||||
) : null}
|
||||
@@ -77,9 +77,9 @@ export async function EmbeddableDocsPage(
|
||||
<EmbeddableFrameBody>
|
||||
<ScrollContainer
|
||||
orientation="vertical"
|
||||
className="not-hydrated:animate-blur-in-slow"
|
||||
contentClassName="p-4"
|
||||
leading={{ fade: !context.sections, button: true }}
|
||||
className="-mx-4 not-hydrated:animate-blur-in-slow"
|
||||
contentClassName="flex-row px-4"
|
||||
leading={{ fade: false, button: true }}
|
||||
trailing={{ fade: false, button: true }}
|
||||
>
|
||||
<TableOfContents context={context} withTrademark={false} />
|
||||
|
||||
@@ -11,6 +11,7 @@ export function EmbeddableDocsPageControlButtons(props: { href: string }) {
|
||||
<Button
|
||||
icon="arrow-up-right-from-square"
|
||||
data-testid="embed-docs-page-open-in-new-tab"
|
||||
className="theme-bold:text-header-link hover:bg-tint-hover hover:theme-bold:bg-header-link/3 hover:theme-bold:text-header-link"
|
||||
label={tString(language, 'open_in_new_tab')}
|
||||
href={href}
|
||||
target="_blank"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { tcls } from '@/lib/tailwind';
|
||||
import { type ClassValue, tcls } from '@/lib/tailwind';
|
||||
import React from 'react';
|
||||
import { CONTAINER_STYLE } from '../layout';
|
||||
|
||||
export type EmbeddableFrameProps = React.ComponentProps<'div'> & {
|
||||
children: React.ReactNode;
|
||||
@@ -40,11 +41,18 @@ export function EmbeddableFrameMain(props: React.ComponentProps<'div'>) {
|
||||
|
||||
export function EmbeddableFrameHeader(props: {
|
||||
children: React.ReactNode;
|
||||
className?: ClassValue;
|
||||
}) {
|
||||
const { children } = props;
|
||||
const { children, className } = props;
|
||||
|
||||
return (
|
||||
<div className="relative z-10 flex not-hydrated:animate-blur-in-slow select-none items-center gap-2 px-4 py-2.5 text-tint-strong">
|
||||
<div
|
||||
className={tcls(
|
||||
'relative z-10 flex w-full not-hydrated:animate-blur-in-slow select-none items-center gap-2 py-2.5 text-tint-strong',
|
||||
CONTAINER_STYLE,
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
@@ -60,10 +68,21 @@ export function EmbeddableFrameHeaderMain(props: {
|
||||
|
||||
export function EmbeddableFrameBody(props: {
|
||||
children: React.ReactNode;
|
||||
className?: ClassValue;
|
||||
}) {
|
||||
const { children } = props;
|
||||
const { children, className } = props;
|
||||
|
||||
return <div className="flex flex-1 flex-col overflow-hidden">{children}</div>;
|
||||
return (
|
||||
<div
|
||||
className={tcls(
|
||||
'flex w-full flex-1 flex-col overflow-hidden',
|
||||
CONTAINER_STYLE,
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function EmbeddableFrameTitle(props: {
|
||||
|
||||
@@ -29,7 +29,7 @@ export async function EmbeddableRootLayout({
|
||||
children,
|
||||
}: React.PropsWithChildren<EmbeddableRootLayoutProps>) {
|
||||
return (
|
||||
<CustomizationRootLayout context={context}>
|
||||
<CustomizationRootLayout context={context} htmlClassName="embed">
|
||||
<SiteLayoutClientContexts
|
||||
forcedTheme={
|
||||
context.customization.themes.toggeable
|
||||
|
||||
@@ -52,6 +52,7 @@ export async function TableOfContents(props: {
|
||||
'border-tint-subtle',
|
||||
|
||||
'lg:flex!',
|
||||
'embed:lg:page-no-toc:hidden!',
|
||||
'lg:animate-none!',
|
||||
'lg:sticky',
|
||||
'lg:mr-12',
|
||||
@@ -72,10 +73,13 @@ export async function TableOfContents(props: {
|
||||
'lg:site-header-sections:announcement:h-[calc(100vh-6.75rem-4.25rem)]',
|
||||
|
||||
// Client-side dynamic positioning (CSS vars applied by script)
|
||||
'lg:[html[style*="--toc-top-offset"]_&]:top-(--toc-top-offset)!',
|
||||
'lg:[html[style*="--toc-height"]_&]:h-(--toc-height)!',
|
||||
'lg:page-no-toc:[html[style*="--outline-top-offset"]_&]:top-(--outline-top-offset)!',
|
||||
'lg:page-no-toc:[html[style*="--outline-height"]_&]:top-(--outline-height)!',
|
||||
'lg:not-embed:[html[style*="--toc-top-offset"]_&]:top-(--toc-top-offset)!',
|
||||
'lg:not-embed:[html[style*="--toc-height"]_&]:h-(--toc-height)!',
|
||||
'lg:page-no-toc:not-embed:[html[style*="--outline-top-offset"]_&]:top-(--outline-top-offset)!',
|
||||
'lg:page-no-toc:not-embed:[html[style*="--outline-height"]_&]:top-(--outline-height)!',
|
||||
|
||||
'embed:top-0',
|
||||
'embed:h-full',
|
||||
|
||||
'pt-6 pb-4',
|
||||
'supports-[-webkit-touch-callout]:pb-[env(safe-area-inset-bottom)]', // Override bottom padding on iOS since we have a transparent bottom bar
|
||||
|
||||
@@ -604,12 +604,12 @@ const config: Config = {
|
||||
addVariant('site-header', 'body:has(#site-header:not(.mobile-only)) &');
|
||||
addVariant('site-header-sections', [
|
||||
'body:has(#site-header:not(.mobile-only) #sections) &',
|
||||
// 'body:has(.page-no-toc):has(#site-header:not(.mobile-only) #variants) &',
|
||||
]);
|
||||
addVariant(
|
||||
'announcement',
|
||||
'html:not(.announcement-hidden):has(#announcement-banner) &'
|
||||
);
|
||||
addVariant('embed', 'html.embed &');
|
||||
|
||||
addVariant('hydrated', 'html.hydrated:not(.route-change) &');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user