From d30bcbabdbea232b2bf8b0e2123b28e47ec0afa0 Mon Sep 17 00:00:00 2001 From: Zeno Kapitein Date: Wed, 6 Aug 2025 16:10:55 +0200 Subject: [PATCH] Improve `Button` and `ButtonGroup` styling (#3540) --- .changeset/big-rockets-sniff.md | 5 ++ .../src/components/AIActions/AIActions.tsx | 6 +- .../AIActions/AIActionsDropdown.tsx | 3 + .../src/components/AIChat/AIChatButton.tsx | 12 ++-- .../AIChat/AIChatSuggestedQuestions.tsx | 1 - .../CodeBlock/CodeBlockRenderer.tsx | 2 +- .../DocumentView/CodeBlock/CopyCodeButton.tsx | 10 ++- .../PageFeedback/PageFeedbackForm.tsx | 66 +++++++++---------- .../components/SpaceLayout/SpaceLayout.tsx | 14 +++- .../components/ThemeToggler/ThemeToggler.tsx | 49 +++++--------- .../src/components/primitives/Button.tsx | 17 +++-- .../src/components/primitives/styles.ts | 3 +- 12 files changed, 102 insertions(+), 86 deletions(-) create mode 100644 .changeset/big-rockets-sniff.md diff --git a/.changeset/big-rockets-sniff.md b/.changeset/big-rockets-sniff.md new file mode 100644 index 000000000..3c0b5642d --- /dev/null +++ b/.changeset/big-rockets-sniff.md @@ -0,0 +1,5 @@ +--- +"gitbook": patch +--- + +Improve `Button` and `ButtonGroup` styling diff --git a/packages/gitbook/src/components/AIActions/AIActions.tsx b/packages/gitbook/src/components/AIActions/AIActions.tsx index b811ee8fd..a5908d34b 100644 --- a/packages/gitbook/src/components/AIActions/AIActions.tsx +++ b/packages/gitbook/src/components/AIActions/AIActions.tsx @@ -231,13 +231,15 @@ function AIActionWrapper(props: { } size="xsmall" variant="secondary" - label={shortLabel || label} + label={label ?? shortLabel} className="bg-tint-base text-sm" onClick={onClick} href={href} target={href ? '_blank' : undefined} disabled={disabled || loading} - /> + > + {shortLabel} + ); } diff --git a/packages/gitbook/src/components/AIActions/AIActionsDropdown.tsx b/packages/gitbook/src/components/AIActions/AIActionsDropdown.tsx index c4d7fcb23..6cc36782f 100644 --- a/packages/gitbook/src/components/AIActions/AIActionsDropdown.tsx +++ b/packages/gitbook/src/components/AIActions/AIActionsDropdown.tsx @@ -8,6 +8,7 @@ import { } from '@/components/AIActions/AIActions'; import { Button, ButtonGroup } from '@/components/primitives/Button'; import { DropdownMenu, DropdownMenuSeparator } from '@/components/primitives/DropdownMenu'; +import { tString, useLanguage } from '@/intl/client'; import type { SiteCustomizationSettings } from '@gitbook/api'; import { Icon } from '@gitbook/icons'; @@ -25,6 +26,7 @@ interface AIActionsDropdownProps { */ export function AIActionsDropdown(props: AIActionsDropdownProps) { const ref = useRef(null); + const language = useLanguage(); return ( @@ -41,6 +43,7 @@ export function AIActionsDropdown(props: AIActionsDropdownProps) { className="size-3 transition-transform group-data-[state=open]/button:rotate-180" /> } + label={tString(language, 'more')} iconOnly size="xsmall" variant="secondary" diff --git a/packages/gitbook/src/components/AIChat/AIChatButton.tsx b/packages/gitbook/src/components/AIChat/AIChatButton.tsx index 88e0d131e..78cbdcdaf 100644 --- a/packages/gitbook/src/components/AIChat/AIChatButton.tsx +++ b/packages/gitbook/src/components/AIChat/AIChatButton.tsx @@ -11,8 +11,8 @@ import { AIChatIcon } from './AIChatIcon'; /** * Button to open/close the AI chat. */ -export function AIChatButton(props: { trademark: boolean }) { - const { trademark } = props; +export function AIChatButton(props: { trademark: boolean; withLabel: boolean }) { + const { trademark, withLabel } = props; const chatController = useAIChatController(); const language = useLanguage(); @@ -20,8 +20,8 @@ export function AIChatButton(props: { trademark: boolean }) { ); } diff --git a/packages/gitbook/src/components/AIChat/AIChatSuggestedQuestions.tsx b/packages/gitbook/src/components/AIChat/AIChatSuggestedQuestions.tsx index 9f3b6318a..5f0089ebd 100644 --- a/packages/gitbook/src/components/AIChat/AIChatSuggestedQuestions.tsx +++ b/packages/gitbook/src/components/AIChat/AIChatSuggestedQuestions.tsx @@ -17,7 +17,6 @@ export default function AIChatSuggestedQuestions(props: { chatController: AIChat {DEFAULT_SUGGESTED_QUESTIONS.map((question, index) => ( + ); } diff --git a/packages/gitbook/src/components/PageFeedback/PageFeedbackForm.tsx b/packages/gitbook/src/components/PageFeedback/PageFeedbackForm.tsx index cb18f3afe..5c81bfb87 100644 --- a/packages/gitbook/src/components/PageFeedback/PageFeedbackForm.tsx +++ b/packages/gitbook/src/components/PageFeedback/PageFeedbackForm.tsx @@ -8,7 +8,7 @@ import { t, tString } from '@/intl/translate'; import { tcls } from '@/lib/tailwind'; import { useTrackEvent } from '../Insights'; -import { Button } from '../primitives'; +import { Button, ButtonGroup } from '../primitives'; const MAX_COMMENT_LENGTH = 512; @@ -61,31 +61,29 @@ export function PageFeedbackForm(props: {

{t(languages, 'was_this_helpful')}

-
-
- onSubmitRating(PageFeedbackRating.Good)} - active={rating === PageFeedbackRating.Good} - disabled={rating !== undefined} - /> - onSubmitRating(PageFeedbackRating.Ok)} - active={rating === PageFeedbackRating.Ok} - disabled={rating !== undefined} - /> - onSubmitRating(PageFeedbackRating.Bad)} - active={rating === PageFeedbackRating.Bad} - disabled={rating !== undefined} - /> -
-
+ + onSubmitRating(PageFeedbackRating.Good)} + active={rating === PageFeedbackRating.Good} + disabled={rating !== undefined} + /> + onSubmitRating(PageFeedbackRating.Ok)} + active={rating === PageFeedbackRating.Ok} + disabled={rating !== undefined} + /> + onSubmitRating(PageFeedbackRating.Bad)} + active={rating === PageFeedbackRating.Bad} + disabled={rating !== undefined} + /> +
{rating ? (
@@ -148,9 +146,9 @@ function RatingButton( }[rating] ?? null; return ( - + iconOnly + {...attr} + icon={ratingIcon} + /> ); } diff --git a/packages/gitbook/src/components/SpaceLayout/SpaceLayout.tsx b/packages/gitbook/src/components/SpaceLayout/SpaceLayout.tsx index 1ad87813d..3c864d828 100644 --- a/packages/gitbook/src/components/SpaceLayout/SpaceLayout.tsx +++ b/packages/gitbook/src/components/SpaceLayout/SpaceLayout.tsx @@ -1,5 +1,9 @@ import type { GitBookSiteContext } from '@/lib/context'; -import { CustomizationAIMode, CustomizationHeaderPreset } from '@gitbook/api'; +import { + CustomizationAIMode, + CustomizationHeaderPreset, + CustomizationSearchStyle, +} from '@gitbook/api'; import React from 'react'; import { Footer } from '@/components/Footer'; @@ -62,7 +66,13 @@ export function SpaceLayout(props: { /> {aiMode === CustomizationAIMode.Assistant ? ( - + ) : null}
); diff --git a/packages/gitbook/src/components/ThemeToggler/ThemeToggler.tsx b/packages/gitbook/src/components/ThemeToggler/ThemeToggler.tsx index 041e94a2b..c6e9a8967 100644 --- a/packages/gitbook/src/components/ThemeToggler/ThemeToggler.tsx +++ b/packages/gitbook/src/components/ThemeToggler/ThemeToggler.tsx @@ -1,11 +1,11 @@ 'use client'; -import { Icon, type IconName } from '@gitbook/icons'; +import type { IconName } from '@gitbook/icons'; import { useTheme } from 'next-themes'; import React from 'react'; import { tString, useLanguage } from '@/intl/client'; -import { tcls } from '@/lib/tailwind'; +import { Button, ButtonGroup } from '../primitives'; type ThemeMode = 'light' | 'system' | 'dark'; @@ -27,7 +27,7 @@ export function ThemeToggler() { }; return ( -
+ onSwitchMode('dark')} title={tString(language, 'switch_to_dark_theme')} /> -
+ ); } @@ -58,38 +58,21 @@ function ThemeButton(props: { }) { const { icon, onClick, title, active } = props; return ( - + variant="blank" + size="default" + className={ + active + ? 'bg-primary theme-muted:bg-primary-hover text-primary-strong ring-primary hover:bg-primary contrast-more:text-primary-strong contrast-more:ring-1 [html.sidebar-filled.theme-bold.tint_&]:bg-primary-hover' + : '' + } + icon={icon} + iconOnly + /> ); } diff --git a/packages/gitbook/src/components/primitives/Button.tsx b/packages/gitbook/src/components/primitives/Button.tsx index e7f404f6c..146cde394 100644 --- a/packages/gitbook/src/components/primitives/Button.tsx +++ b/packages/gitbook/src/components/primitives/Button.tsx @@ -135,7 +135,7 @@ export const Button = React.forwardRef< icon ) ) : null} - {iconOnly ? null : label} + {iconOnly ? null : (children ?? label)} ); @@ -171,7 +171,7 @@ export const Button = React.forwardRef< ); - return iconOnly && label ? ( + return (children || iconOnly) && label ? ( (({ children }, ref) => { +export const ButtonGroup = React.forwardRef< + HTMLDivElement, + ButtonProps & { combinedShape?: boolean } +>(({ children, className, combinedShape = true, ...rest }, ref) => { return (
*:not(:first-child)]:border-l-0 [&>*:not(:first-child,:last-child)]:rounded-none [&>*:not(:only-child):first-child]:rounded-r-none [&>*:not(:only-child):last-child]:rounded-l-none' + 'flex h-fit items-stretch justify-start', + combinedShape + ? '*:translate-y-0! *:shadow-none! [&>*:not(:first-child)]:border-l-0 [&>*:not(:first-child,:last-child)]:rounded-none [&>*:not(:only-child):first-child]:rounded-r-none [&>*:not(:only-child):last-child]:rounded-l-none' + : '', + className )} + {...rest} > {children}
diff --git a/packages/gitbook/src/components/primitives/styles.ts b/packages/gitbook/src/components/primitives/styles.ts index cd983d8c0..542f2920e 100644 --- a/packages/gitbook/src/components/primitives/styles.ts +++ b/packages/gitbook/src/components/primitives/styles.ts @@ -17,7 +17,7 @@ export const ButtonStyles = [ 'depth-subtle:shadow-xs', 'hover:depth-subtle:shadow-md', 'focus-visible:depth-subtle:shadow-md', - 'active:shadow-none', + 'active:depth-subtle:shadow-xs', 'shadow-tint/6', 'dark:shadow-tint-1', @@ -27,6 +27,7 @@ export const ButtonStyles = [ 'hover:depth-subtle:-translate-y-px', 'focus-visible:depth-subtle:-translate-y-px', + 'active:depth-subtle:translate-y-0', 'transition-all', 'grow-0',