Show social accounts in header (#4068)

This commit is contained in:
Zeno Kapitein
2026-03-02 11:06:49 +01:00
committed by GitHub
parent 38a1c85fee
commit 4a6f91a19d
6 changed files with 85 additions and 26 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"gitbook": patch
---
Show social accounts in header
@@ -8,7 +8,7 @@ import { tcls } from '@/lib/tailwind';
import { ThemeToggler } from '../ThemeToggler';
import { CONTAINER_STYLE } from '../layout';
import { FooterLinksGroup } from './FooterLinksGroup';
import { SocialLink } from './SocialLink';
import { SocialAccountButton } from './SocialAccounts';
const FOOTER_COLUMNS = 4;
@@ -145,7 +145,7 @@ export function Footer(props: { context: GitBookSiteContext }) {
socialLinks.length > 0 ? (
<div className="col-span-full flex w-full grow items-center justify-center gap-2">
{socialLinks.map((account) => (
<SocialLink
<SocialAccountButton
key={`${account.platform}-${account.handle}`}
account={account}
target={customization.externalLinks.target}
@@ -4,7 +4,7 @@ import {
SiteSocialAccountPlatform,
} from '@gitbook/api';
import type { IconName } from '@gitbook/icons';
import { Button } from '../primitives';
import { Button, type ButtonProps, DropdownMenuItem } from '../primitives';
type SocialPlatformData = {
label: string;
@@ -86,8 +86,10 @@ const SOCIAL_PLATFORMS: Record<SiteSocialAccountPlatform, SocialPlatformData> =
},
};
export function SocialLink(props: { account: SiteSocialAccount; target: SiteExternalLinksTarget }) {
const { account, target } = props;
export function SocialAccountButton(
props: { account: SiteSocialAccount; target: SiteExternalLinksTarget } & ButtonProps
) {
const { account, target, ...rest } = props;
const platform = SOCIAL_PLATFORMS[account.platform];
return (
@@ -99,6 +101,23 @@ export function SocialLink(props: { account: SiteSocialAccount; target: SiteExte
variant="blank"
size="large"
target={target}
{...rest}
/>
);
}
export function SocialAccountLink(props: {
account: SiteSocialAccount;
}) {
const { account } = props;
const platform = SOCIAL_PLATFORMS[account.platform];
return (
<DropdownMenuItem
href={platform.href.replace('$handle', account.handle)}
leadingIcon={platform.icon}
>
{platform.label}
</DropdownMenuItem>
);
}
@@ -4,6 +4,7 @@ import { CONTAINER_STYLE, HEADER_HEIGHT_DESKTOP } from '@/components/layout';
import { getSpaceLanguage, t } from '@/intl/server';
import { tcls } from '@/lib/tailwind';
import type { SiteSpace } from '@gitbook/api';
import { SocialAccountButton } from '../Footer/SocialAccounts';
import { SearchContainer } from '../Search';
import { SiteSectionTabs, encodeClientSiteSections } from '../SiteSections';
import { HeaderLink } from './HeaderLink';
@@ -33,6 +34,10 @@ export function Header(props: {
visibleSections.list.some((s) => s.object === 'site-section-group'))
);
const headerSocialAccounts = customization.socialAccounts.filter(
(account) => account.display.header === true
);
return (
<header
data-gb-site-header
@@ -162,25 +167,40 @@ export function Header(props: {
</div>
{customization.header.links.length > 0 ||
headerSocialAccounts.length > 0 ||
(!withSections && variants.translations.length > 1) ? (
<HeaderLinks>
{customization.header.links.length > 0 ? (
<>
{customization.header.links.map((link) => {
{customization.header.links.map((link) => {
return (
<HeaderLink
key={link.title}
link={link}
context={context}
/>
);
})}
{headerSocialAccounts.length > 0 ? (
<div className="flex items-center gap-1">
{headerSocialAccounts.map((account) => {
return (
<HeaderLink
key={link.title}
link={link}
context={context}
<SocialAccountButton
key={`${account.platform}-${account.handle}`}
account={account}
target={customization.externalLinks.target}
className="p-2 theme-bold:text-header-link hover:site-header:theme-bold:bg-header-link/3 hover:theme-bold:text-header-link focus-visible:site-header:theme-bold:bg-header-link/3"
/>
);
})}
<HeaderLinkMore
label={t(getSpaceLanguage(context), 'more')}
links={customization.header.links}
context={context}
/>
</>
</div>
) : null}
{customization.header.links.length > 0 ||
headerSocialAccounts.length > 0 ? (
<HeaderLinkMore
label={t(getSpaceLanguage(context), 'more')}
links={customization.header.links}
socialAccounts={headerSocialAccounts}
context={context}
/>
) : null}
{!withSections && variants.translations.length > 1 ? (
<TranslationsDropdown
@@ -3,6 +3,7 @@ import {
type CustomizationContentLink,
type CustomizationHeaderItem,
SiteInsightsLinkPosition,
type SiteSocialAccount,
} from '@gitbook/api';
import { Icon } from '@gitbook/icons';
import type React from 'react';
@@ -10,8 +11,14 @@ import type React from 'react';
import { resolveContentRef } from '@/lib/references';
import { tcls } from '@/lib/tailwind';
import { SocialAccountLink } from '../Footer/SocialAccounts';
import { ToggleChevron } from '../primitives';
import { DropdownMenu, DropdownMenuItem, DropdownSubMenu } from '../primitives/DropdownMenu';
import {
DropdownMenu,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownSubMenu,
} from '../primitives/DropdownMenu';
import styles from './headerLinks.module.css';
/**
@@ -20,9 +27,10 @@ import styles from './headerLinks.module.css';
export function HeaderLinkMore(props: {
label: React.ReactNode;
links: CustomizationHeaderItem[];
socialAccounts: SiteSocialAccount[];
context: GitBookSiteContext;
}) {
const { label, links, context } = props;
const { label, links, context, socialAccounts } = props;
const renderButton = (
<button
@@ -57,6 +65,13 @@ export function HeaderLinkMore(props: {
{links.map((link, index) => (
<MoreMenuLink key={index} link={link} context={context} />
))}
{socialAccounts.length > 0 && <DropdownMenuSeparator />}
{socialAccounts.map((account) => (
<SocialAccountLink
key={`${account.platform}-${account.handle}`}
account={account}
/>
))}
</DropdownMenu>
</div>
);
@@ -18,7 +18,7 @@
}
.containerHeaderlinks > :nth-child(n + 1) ~ .linkEllipsis {
display: flex;
& div > a:nth-of-type(n + 1) {
& div > *:nth-child(n + 1) {
display: flex;
}
}
@@ -29,7 +29,7 @@
}
.containerHeaderlinks > :nth-child(n + 2) ~ .linkEllipsis {
display: flex;
& div > a:nth-of-type(n + 2) {
& div > *:nth-child(n + 2) {
display: flex;
}
}
@@ -40,7 +40,7 @@
}
.containerHeaderlinks > :nth-child(n + 3) ~ .linkEllipsis {
display: flex;
& div > a:nth-of-type(n + 3) {
& div > *:nth-child(n + 3) {
display: flex;
}
}
@@ -51,7 +51,7 @@
}
.containerHeaderlinks > :nth-child(n + 4) ~ .linkEllipsis {
display: flex;
& div > a:nth-of-type(n + 4) {
& div > *:nth-child(n + 4) {
display: flex;
}
}
@@ -62,7 +62,7 @@
}
.containerHeaderlinks > :nth-child(n + 5) ~ .linkEllipsis {
display: flex;
& div > a:nth-of-type(n + 5) {
& div > *:nth-child(n + 5) {
display: flex;
}
}
@@ -73,7 +73,7 @@
}
.containerHeaderlinks > :nth-child(n + 6) ~ .linkEllipsis {
display: flex;
& div > a:nth-of-type(n + 6) {
& div > *:nth-child(n + 6) {
display: flex;
}
}