From dae7f704fa1099307cb43df1fa78df55816a37b2 Mon Sep 17 00:00:00 2001 From: Sebastian Graz Date: Thu, 14 Dec 2023 16:17:13 +0100 Subject: [PATCH] Style PR (#34) * codeblock styling * fix hover rounding * checkpoint layout * improve highlight algo * v1 syntax theme * fix table cell add title style * color tweaks * opaque sticky numbers * fix collection spaces * card aspect fix * adding back full-width tables * num tabs * Add v1 more table types * format --- src/app/[spaceId]/globals.css | 3 + .../DocumentView/CodeBlock/CodeBlock.tsx | 221 +++++++++++++----- .../DocumentView/CodeBlock/CopyCodeButton.tsx | 2 +- .../DocumentView/CodeBlock/theme.css | 42 ++-- src/components/DocumentView/Paragraph.tsx | 2 +- .../DocumentView/Table/RecordCard.tsx | 20 +- .../DocumentView/Table/RecordColumnValue.tsx | 52 ++++- .../DocumentView/Table/RecordRow.tsx | 4 +- .../DocumentView/Table/ViewGrid.tsx | 65 +++--- .../DocumentView/Table/table.module.css | 1 + .../Header/CollectionSpacesDropdown.tsx | 6 +- src/components/Header/Dropdown.tsx | 4 +- src/components/Header/Header.tsx | 20 +- src/components/Header/HeaderLinks.tsx | 4 +- 14 files changed, 313 insertions(+), 133 deletions(-) diff --git a/src/app/[spaceId]/globals.css b/src/app/[spaceId]/globals.css index bde7d62f1..5d4471869 100644 --- a/src/app/[spaceId]/globals.css +++ b/src/app/[spaceId]/globals.css @@ -81,6 +81,9 @@ .linear-mask-gradient { mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1) 96px, rgba(0, 0, 0, 0)); } + .linear-mask-util { + mask-image: linear-gradient(to bottom, white, white); + } .grid-area-1-1 { grid-area: 1/1; } diff --git a/src/components/DocumentView/CodeBlock/CodeBlock.tsx b/src/components/DocumentView/CodeBlock/CodeBlock.tsx index 853847d33..1d63a78e3 100644 --- a/src/components/DocumentView/CodeBlock/CodeBlock.tsx +++ b/src/components/DocumentView/CodeBlock/CodeBlock.tsx @@ -21,37 +21,108 @@ export async function CodeBlock(props: BlockProps) { const withLineNumbers = !!block.data.lineNumbers && block.nodes.length > 1; const withWrap = block.data.overflow === 'wrap'; + const title = block.data.title; + const fullWidth = block.data.fullWidth; + + const fullWidthStyle = fullWidth ? 'max-w-4xl' : 'max-w-3xl'; + const titleRounding = title ? ['rounded-md', 'rounded-ss-none'] : ['rounded-md']; return ( -
-            
+            
- {lines.map((line, index) => ( - - ))} - - -
+ {title ? ( +
+ {title} +
+ ) : null} + + +
+                
+                    {lines.map((line, index) => (
+                        
+                    ))}
+                
+            
+ ); } @@ -65,30 +136,77 @@ function CodeHighlightLine(props: { context: ContentRefContext; }) { const { block, line, isLast, withLineNumbers, context } = props; - return ( *]:mt-1', + //last child + '[&.highlighted:last-child]:rounded-b-md', + '[&.highlighted:last-child>*]:mb-1', + //is only child, dont hover effect line + '[&:only-child]:hover:ring-transparent', + //select all highlighted + '[&.highlighted]:rounded-none', + //select first in group + '[&:not(.highlighted)_+_.highlighted]:rounded-t-md', + '[&:not(.highlighted)_+_.highlighted>*]:mt-1', + //select last in group + '[&.highlighted:has(+:not(.highlighted))]:rounded-b-md', + '[&.highlighted:has(+:not(.highlighted))>*]:mb-1', + //select if highlight is singular in group + '[&:not(.highlighted)_+_.highlighted:has(+:not(.highlighted))]:rounded-md', + + line.highlighted ? ['highlighted', 'bg-dark/1', 'dark:bg-sky/1'] : null, )} > - + {withLineNumbers ? ( + + ) : null} + + {isLast ? null : !withLineNumbers && line.tokens.length === 0 && 0 ? ( {'\u200B'} @@ -133,18 +251,3 @@ function CodeHighlightToken(props: { token: HighlightToken; context: ContentRefC return {token.token.content}; } - -/** - * Compute the width ofthe gutter with the line number to align the code. - */ -function getLineNumberGutterWidth(block: DocumentBlockCode): ClassValue { - if (block.nodes.length < 10) { - return ['before:w-8', 'ml-8']; - } else if (block.nodes.length < 100) { - return ['before:w-10', 'ml-10']; - } else if (block.nodes.length < 1000) { - return ['before:w-12', 'ml-12']; - } else { - return ['before:w-14', 'ml-14']; - } -} diff --git a/src/components/DocumentView/CodeBlock/CopyCodeButton.tsx b/src/components/DocumentView/CodeBlock/CopyCodeButton.tsx index 7301bfc01..c081516ee 100644 --- a/src/components/DocumentView/CodeBlock/CopyCodeButton.tsx +++ b/src/components/DocumentView/CodeBlock/CopyCodeButton.tsx @@ -39,7 +39,7 @@ export function CopyCodeButton(props: { codeId: string; style: ClassValue }) { }; return ( - ); diff --git a/src/components/DocumentView/CodeBlock/theme.css b/src/components/DocumentView/CodeBlock/theme.css index cd27bc181..d41ace62c 100644 --- a/src/components/DocumentView/CodeBlock/theme.css +++ b/src/components/DocumentView/CodeBlock/theme.css @@ -1,27 +1,25 @@ :root { - --shiki-color-text: theme('colors.zinc.700'); - --shiki-color-background: theme('colors.white'); - --shiki-token-constant: theme('colors.emerald.700'); - --shiki-token-string: theme('colors.emerald.700'); - --shiki-token-comment: theme('colors.zinc.500'); - --shiki-token-keyword: theme('colors.cyan.700'); - --shiki-token-parameter: theme('colors.pink.700'); - --shiki-token-function: theme('colors.violet.700'); - --shiki-token-string-expression: theme('colors.emerald.700'); - --shiki-token-punctuation: theme('colors.zinc.800'); - --shiki-token-link: theme('colors.zinc.700'); + --shiki-color-text: theme('colors.dark/.88'); + --shiki-token-constant: #0a6355; + --shiki-token-string: #8b6d32; + --shiki-token-comment: theme('colors.teal.700/.64'); + --shiki-token-keyword: theme('colors.pomegranate.600'); + --shiki-token-parameter: #0a3069; + --shiki-token-function: #8250df; + --shiki-token-string-expression: #6a4906; + --shiki-token-punctuation: theme('colors.pomegranate.700/.92'); + --shiki-token-link: theme('colors.dark'); } html.dark { - --shiki-color-text: theme('colors.zinc.700'); - --shiki-color-background: theme('colors.white'); - --shiki-token-constant: theme('colors.emerald.700'); - --shiki-token-string: theme('colors.emerald.700'); - --shiki-token-comment: theme('colors.zinc.500'); - --shiki-token-keyword: theme('colors.cyan.700'); - --shiki-token-parameter: theme('colors.pink.700'); - --shiki-token-function: theme('colors.violet.700'); - --shiki-token-string-expression: theme('colors.emerald.700'); - --shiki-token-punctuation: theme('colors.zinc.800'); - --shiki-token-link: theme('colors.zinc.700'); + --shiki-color-text: theme('colors.light/.88'); + --shiki-token-constant: #d19a66; + --shiki-token-string: theme('colors.pomegranate.300'); + --shiki-token-comment: theme('colors.teal.300/.64'); + --shiki-token-keyword: theme('colors.pomegranate.400'); + --shiki-token-parameter: theme('colors.yellow.500'); + --shiki-token-function: #56b6c2; + --shiki-token-string-expression: theme('colors.pomegranate.400'); + --shiki-token-punctuation: theme('colors.periwinkle'); + --shiki-token-link: theme('colors.pomegranate.400'); } diff --git a/src/components/DocumentView/Paragraph.tsx b/src/components/DocumentView/Paragraph.tsx index df0deeb54..2147ec01e 100644 --- a/src/components/DocumentView/Paragraph.tsx +++ b/src/components/DocumentView/Paragraph.tsx @@ -9,7 +9,7 @@ export function Paragraph(props: BlockProps) { const { block, style, ...contextProps } = props; return ( -

+

); diff --git a/src/components/DocumentView/Table/RecordCard.tsx b/src/components/DocumentView/Table/RecordCard.tsx index 2d51a3e89..cf5fa595d 100644 --- a/src/components/DocumentView/Table/RecordCard.tsx +++ b/src/components/DocumentView/Table/RecordCard.tsx @@ -28,9 +28,25 @@ export async function RecordCard( const body = (
{cover ? ( - Cover + Cover ) : null} -
+
{view.columns.map((column) => { return ; })} diff --git a/src/components/DocumentView/Table/RecordColumnValue.tsx b/src/components/DocumentView/Table/RecordColumnValue.tsx index a3f236c3f..e6a103132 100644 --- a/src/components/DocumentView/Table/RecordColumnValue.tsx +++ b/src/components/DocumentView/Table/RecordColumnValue.tsx @@ -1,11 +1,14 @@ import { DocumentBlockTable, DocumentTableViewCards } from '@gitbook/api'; +import Link from 'next/link'; import { getNodeFragmentByName } from '@/lib/document'; +import { resolveContentRef } from '@/lib/references'; import { ClassValue, tcls } from '@/lib/tailwind'; -import { TableRecordKV, TableViewProps } from './Table'; +import { TableRecordKV } from './Table'; import { BlockProps } from '../Block'; import { Blocks } from '../Blocks'; +import { Checkbox } from '../Checkbox'; /** * Render the value for a column in a record. @@ -15,10 +18,9 @@ export async function RecordColumnValue( tag?: Tag; record: TableRecordKV; column: string; - columnStyle?: ClassValue; }, ) { - const { tag: Tag = 'div', block, record, column, columnStyle, context } = props; + const { tag: Tag = 'div', block, record, column, context } = props; const definition = block.data.definition[column]; const value = record[1].values[column]; @@ -28,13 +30,49 @@ export async function RecordColumnValue( } switch (definition.type) { + case 'content-ref': + const target = await resolveContentRef(value as any, context); + if (!target) { + return null; + } + return ( + + {target.text} + + ); + case 'checkbox': + return ( + + ); + case 'rating': + return ( + + {`${value}`} + + ); case 'number': - return {`${value}`}; + return ( + {`${value}`} + ); case 'text': // @ts-ignore const fragment = getNodeFragmentByName(block, value); if (!fragment) { - return {''}; + return {''}; } return ( @@ -42,9 +80,9 @@ export async function RecordColumnValue( tag={Tag} ancestorBlocks={[]} nodes={fragment.nodes} - style={[columnStyle, 'w-full', 'space-y-2', 'lg:space-y-3']} + style={['w-full', 'space-y-2', 'lg:space-y-3']} context={context} - blockStyle={['w-full']} + blockStyle={['w-full', 'max-w-[unset]']} /> ); default: diff --git a/src/components/DocumentView/Table/RecordRow.tsx b/src/components/DocumentView/Table/RecordRow.tsx index bc9afc705..4777631dc 100644 --- a/src/components/DocumentView/Table/RecordRow.tsx +++ b/src/components/DocumentView/Table/RecordRow.tsx @@ -18,14 +18,14 @@ export async function RecordRow( : ['[&>*+*]:border-l', '[&>*+*]:pl-4']; return ( - + {view.columns.map((column) => { return ( ) { const { block, view, records, style } = props; - const columnsLengthThreshold = view.columns.length >= 7; - const tableLayout = columnsLengthThreshold ? 'table-auto' : 'table-fixed'; - const tableWrapper = columnsLengthThreshold + const columnsOverThreshold = view.columns.length >= 7; + + const tableWrapper = columnsOverThreshold ? [ - 'max-w-4xl', + // has over X columns 'w-full', 'overflow-x-auto', 'overflow-y-hidden', @@ -21,22 +21,47 @@ export function ViewGrid(props: TableViewProps) { 'border', 'border-dark/2', 'dark:border-light/2', - styles.progressContainer, + block.data.fullWidth + ? [ + // has over X columns, and is full width + 'max-w-full', + ] + : [ + // NOT full width, but has over X columns + 'max-w-4xl', + ], ] - : ['max-w-3xl', 'w-full', 'overflow-x-auto', 'overflow-y-hidden', 'mx-auto']; + : [ + 'w-full', + 'overflow-x-auto', + 'overflow-y-hidden', + 'mx-auto', + // has under X columns + block.data.fullWidth + ? [ + // has under X columns, and is full width + 'max-w-full', + ] + : [ + // NOT full width, but has under X columns + 'max-w-3xl', + ], + ]; - const tableTR = columnsLengthThreshold + const tableTR = columnsOverThreshold ? ['[&>*+*]:border-l', '[&>*]:px-4'] : ['[&>*+*]:border-l', '[&>*+*]:pl-4']; - const tableTH = columnsLengthThreshold ? ['py-3'] : ['py-1', 'pt-0']; + const tableTH = columnsOverThreshold ? ['py-3'] : ['py-1', 'pt-0']; return ( -
+
{/* ProgressScroller: */}
) {
{/* Table: */} - +
{view.hideHeader ? null : ( @@ -138,11 +150,12 @@ export function ViewGrid(props: TableViewProps) { 'align-baseline', 'textwrap-balance', 'border-b', - 'border-l-light/2', + 'border-b-dark/4', 'text-left', 'text-sm', 'lg:text-base', - 'dark:border-b-light/6', + 'dark:border-l-light/2', + 'dark:border-b-light/5', )} > {block.data.definition[column].title} diff --git a/src/components/DocumentView/Table/table.module.css b/src/components/DocumentView/Table/table.module.css index bc3e1fdec..d35a2c4a2 100644 --- a/src/components/DocumentView/Table/table.module.css +++ b/src/components/DocumentView/Table/table.module.css @@ -13,6 +13,7 @@ } .progressOpacitySharp { + opacity: 0; animation-name: opacityProgressSharp; animation-duration: 1ms; animation-direction: alternate; diff --git a/src/components/Header/CollectionSpacesDropdown.tsx b/src/components/Header/CollectionSpacesDropdown.tsx index eba87ffa7..d4b7a35ae 100644 --- a/src/components/Header/CollectionSpacesDropdown.tsx +++ b/src/components/Header/CollectionSpacesDropdown.tsx @@ -17,6 +17,7 @@ export function CollectionSpacesDropdown(props: {
{space.title} diff --git a/src/components/Header/Dropdown.tsx b/src/components/Header/Dropdown.tsx index c5a7153d5..2f20b6f18 100644 --- a/src/components/Header/Dropdown.tsx +++ b/src/components/Header/Dropdown.tsx @@ -121,7 +121,9 @@ export function DropdownMenuItem(props: { 'px-3', 'py-1', 'rounded', - active ? ['bg-primary-50'] : ['hover:bg-dark/2', 'dark:hover:bg-light/2'], + active + ? ['bg-primary-100', 'dark:bg-light/2'] + : ['hover:bg-dark/2', 'dark:hover:bg-light/2'], )} > {children} diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index 51f2d6604..3f313ebe3 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -58,8 +58,8 @@ export function Header(props: { className={tcls( 'gap-8', 'grid', - 'grid-cols-[min-content_min-content]', - 'sm:grid-cols-[min-content_1fr_min-content]', + 'grid-flow-col', + 'auto-cols-[auto_auto_1fr_auto]', 'h-16', 'items-center', 'align-center', @@ -70,13 +70,15 @@ export function Header(props: { )} > - {collection ? ( - - ) : null} + + {collection ? ( + + ) : null} + {customization.header.links.map((link, index) => { return ( diff --git a/src/components/Header/HeaderLinks.tsx b/src/components/Header/HeaderLinks.tsx index de4001b86..130c11d5c 100644 --- a/src/components/Header/HeaderLinks.tsx +++ b/src/components/Header/HeaderLinks.tsx @@ -11,10 +11,12 @@ export async function HeaderLinks({ children }: HeaderLinksProps) {
*]:hidden`, //hide each child per container breakpoint