mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-22 10:33:22 +00:00
Support image frame (#3695)
This commit is contained in:
@@ -304,7 +304,7 @@
|
||||
"react-dom": "^19.0.0",
|
||||
},
|
||||
"catalog": {
|
||||
"@gitbook/api": "0.143.1",
|
||||
"@gitbook/api": "0.143.2",
|
||||
"bidc": "^0.0.2",
|
||||
},
|
||||
"packages": {
|
||||
@@ -676,7 +676,7 @@
|
||||
|
||||
"@fortawesome/fontawesome-svg-core": ["@fortawesome/fontawesome-svg-core@6.6.0", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "6.6.0" } }, "sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg=="],
|
||||
|
||||
"@gitbook/api": ["@gitbook/api@0.143.1", "", { "dependencies": { "event-iterator": "^2.0.0", "eventsource-parser": "^3.0.0" } }, "sha512-5k7PnMe9W8EhmSejqayCbAIIJDGB4C2m+o6+dD+asmlv+6jE/LqoxuAvbP8o+kG83tMnbsr5I5d73B/9cAYbag=="],
|
||||
"@gitbook/api": ["@gitbook/api@0.143.2", "", { "dependencies": { "event-iterator": "^2.0.0", "eventsource-parser": "^3.0.0" } }, "sha512-ZIQwIgX+artl0o20ftnzeJyM9icwQ6pFeM55AG/lEdeFbMuUGxTfSnZ90+8Aou8l/3ELR3/tOkU2SAvyKc+ATw=="],
|
||||
|
||||
"@gitbook/browser-types": ["@gitbook/browser-types@workspace:packages/browser-types"],
|
||||
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@
|
||||
"workspaces": {
|
||||
"packages": ["packages/*"],
|
||||
"catalog": {
|
||||
"@gitbook/api": "0.143.1",
|
||||
"@gitbook/api": "0.143.2",
|
||||
"bidc": "^0.0.2"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -24,6 +24,7 @@ export function Caption(
|
||||
wrapperStyle?: ClassValue;
|
||||
block: DocumentBlockImage | DocumentBlockDrawing | DocumentBlockEmbed | DocumentBlockFile;
|
||||
withBorder?: boolean;
|
||||
withFrame?: boolean;
|
||||
} & DocumentContextProps
|
||||
) {
|
||||
const {
|
||||
@@ -33,6 +34,7 @@ export function Caption(
|
||||
context,
|
||||
fit = false,
|
||||
withBorder = false,
|
||||
withFrame = false,
|
||||
wrapperStyle = [
|
||||
'relative',
|
||||
'overflow-hidden',
|
||||
@@ -44,6 +46,7 @@ export function Caption(
|
||||
withBorder
|
||||
? 'rounded-corners:rounded-sm circular-corners:rounded-2xl after:border-tint-subtle after:border after:rounded circular-corners:after:rounded-2xl rounded-corners:after:rounded-sm dark:after:mix-blend-plus-lighter after:pointer-events-none'
|
||||
: null,
|
||||
withFrame && 'p-2',
|
||||
],
|
||||
style,
|
||||
} = props;
|
||||
@@ -62,7 +65,14 @@ export function Caption(
|
||||
return (
|
||||
<picture className={tcls('relative', style)}>
|
||||
<div className={tcls(wrapperStyle, 'mx-auto')}>{children}</div>
|
||||
<figcaption className={tcls('text-sm', 'text-center', 'mt-2', 'text-tint')}>
|
||||
<figcaption
|
||||
className={tcls(
|
||||
'text-xs',
|
||||
'text-center',
|
||||
'text-tint',
|
||||
withFrame ? 'mt-0.5 mb-2.5' : 'mt-2'
|
||||
)}
|
||||
>
|
||||
<Inlines
|
||||
nodes={captionParagraph.nodes}
|
||||
document={document}
|
||||
|
||||
@@ -11,8 +11,8 @@ import type { DocumentContext } from './DocumentView';
|
||||
export function Images(props: BlockProps<DocumentBlockImages>) {
|
||||
const { document, block, style, context, isEstimatedOffscreen } = props;
|
||||
|
||||
const isMultipleImages = block.nodes.length > 1;
|
||||
const { align = 'center' } = block.data;
|
||||
const hasMultipleImages = block.nodes.length > 1;
|
||||
const { align = 'center', withFrame } = block.data;
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -24,7 +24,15 @@ export function Images(props: BlockProps<DocumentBlockImages>) {
|
||||
align === 'center' && 'justify-center',
|
||||
align === 'right' && 'justify-end',
|
||||
align === 'left' && 'justify-start',
|
||||
isMultipleImages && ['grid', 'grid-flow-col']
|
||||
hasMultipleImages && ['grid', 'grid-flow-col'],
|
||||
withFrame && [
|
||||
'rounded-2xl',
|
||||
'border',
|
||||
'border-[rgb(234,235,238)]',
|
||||
'dark:border-[rgb(45,50,58)]',
|
||||
'relative',
|
||||
'overflow-hidden',
|
||||
]
|
||||
)}
|
||||
>
|
||||
{block.nodes.map((node: any, _i: number) => (
|
||||
@@ -36,6 +44,7 @@ export function Images(props: BlockProps<DocumentBlockImages>) {
|
||||
siblings={block.nodes.length}
|
||||
context={context}
|
||||
isEstimatedOffscreen={isEstimatedOffscreen}
|
||||
withFrame={withFrame}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
@@ -62,8 +71,9 @@ async function ImageBlock(props: {
|
||||
context: DocumentContext;
|
||||
siblings: number;
|
||||
isEstimatedOffscreen: boolean;
|
||||
withFrame?: boolean;
|
||||
}) {
|
||||
const { block, context, isEstimatedOffscreen } = props;
|
||||
const { block, context, isEstimatedOffscreen, withFrame } = props;
|
||||
|
||||
const [src, darkSrc] = await Promise.all([
|
||||
context.contentContext ? resolveContentRef(block.data.ref, context.contentContext) : null,
|
||||
@@ -77,33 +87,66 @@ async function ImageBlock(props: {
|
||||
}
|
||||
|
||||
return (
|
||||
<Caption {...props} fit>
|
||||
<Image
|
||||
alt={block.data.alt ?? ''}
|
||||
sizes={imageBlockSizes}
|
||||
resize={context.contentContext?.imageResizer}
|
||||
sources={{
|
||||
light: {
|
||||
src: src.href,
|
||||
size: src.file?.dimensions,
|
||||
},
|
||||
dark: darkSrc
|
||||
? {
|
||||
src: darkSrc.href,
|
||||
size: darkSrc.file?.dimensions,
|
||||
}
|
||||
: null,
|
||||
}}
|
||||
priority={isEstimatedOffscreen ? 'lazy' : 'high'}
|
||||
preload
|
||||
zoom
|
||||
inlineStyle={{
|
||||
maxWidth: '100%',
|
||||
width: getImageDimension(block.data.width, undefined),
|
||||
height: getImageDimension(block.data.height, 'auto'),
|
||||
}}
|
||||
/>
|
||||
</Caption>
|
||||
<div className={tcls('relative', 'overflow-hidden')}>
|
||||
{/* Frame grid */}
|
||||
{withFrame && (
|
||||
<div
|
||||
className={tcls(
|
||||
'absolute',
|
||||
'-top-0.5',
|
||||
'-left-0.5',
|
||||
'right-px',
|
||||
'bottom-px',
|
||||
'opacity-40',
|
||||
'dark:opacity-[0.1]',
|
||||
'bg-[length:24px_24px,24px_24px]',
|
||||
'bg-[linear-gradient(to_right,_rgb(234,235,238)_1px,_transparent_1px),linear-gradient(to_bottom,_rgb(234,235,238)_1px,_transparent_1px)]',
|
||||
'dark:bg-[linear-gradient(to_right,_rgb(122,128,139)_1px,_transparent_1px),linear-gradient(to_bottom,_rgb(122,128,139)_1px,_transparent_1px)]',
|
||||
'bg-repeat'
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Shadow overlay */}
|
||||
{withFrame && (
|
||||
<div
|
||||
className={tcls(
|
||||
'pointer-events-none absolute inset-0 rounded-2xl',
|
||||
'shadow-[inset_0_0_10px_10px_rgba(255,255,255,0.9)]',
|
||||
'dark:shadow-[inset_0_0_10px_10px_rgb(29,29,29)]'
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Caption {...props} fit>
|
||||
<Image
|
||||
alt={block.data.alt ?? ''}
|
||||
sizes={imageBlockSizes}
|
||||
resize={context.contentContext?.imageResizer}
|
||||
sources={{
|
||||
light: {
|
||||
src: src.href,
|
||||
size: src.file?.dimensions,
|
||||
},
|
||||
dark: darkSrc
|
||||
? {
|
||||
src: darkSrc.href,
|
||||
size: darkSrc.file?.dimensions,
|
||||
}
|
||||
: null,
|
||||
}}
|
||||
priority={isEstimatedOffscreen ? 'lazy' : 'high'}
|
||||
preload
|
||||
zoom
|
||||
inlineStyle={{
|
||||
maxWidth: '100%',
|
||||
width: getImageDimension(block.data.width, undefined),
|
||||
height: getImageDimension(block.data.height, 'auto'),
|
||||
}}
|
||||
style={withFrame ? 'rounded-xl' : undefined}
|
||||
/>
|
||||
</Caption>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user