Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/myst.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,8 @@ site:
folders: true
logo: _static/myst-logo-light.svg
logo_dark: _static/myst-logo-dark.svg
navbar_icons:
- icon: github
url: https://github.com/jupyter-book/myst-theme
- icon: discord
url: https://discord.gg/QTnAx2yq
42 changes: 42 additions & 0 deletions docs/ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,48 @@ site:
- If the `.md` file it points to is empty, the footer will not be visible
- If not configured, falls back to the default "Made with MyST" footer

## Navbar Icons

Display icon links in the navigation bar for social media, GitHub, and other external resources.

### Configuration

Add icons to your site's navbar through `site.options.navbar_icons`:

```yaml
site:
options:
navbar_icons:
- icon: github
url: https://github.com/your-org/your-repo
- icon: discord
url: https://discord.gg/your-server
- icon: bluesky
url: https://bsky.app/profile/your-profile
```

Each icon requires:

- `icon`: The icon name (see supported icons below)
- `url`: The external URL to link to
- `title` (optional): Custom tooltip text

### Supported Icons

| Icon name | Description |
|-----------|-------------|
| `github` | GitHub |
| `twitter` or `x` | X (Twitter) |
| `bluesky` | Bluesky |
| `discord` | Discord |
| `mastodon` | Mastodon |
| `linkedin` | LinkedIn |
| `youtube` | YouTube |
| `slack` | Slack |
| `email` | Email |
| `rss` | RSS Feed |
| `link` or `website` | Generic external link |

## Hiding Elements

Control the visibility of various page elements. All options can be set site-wide or per-page.
Expand Down
7 changes: 7 additions & 0 deletions packages/common/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ export type PageLoader = {
dependencies?: Dependency[];
};

export type NavbarIcon = {
icon: string;
url: string;
title?: string;
};

export type CommonTemplateOptions = {
favicon?: string;
logo?: string;
Expand All @@ -89,4 +95,5 @@ export type CommonTemplateOptions = {
hide_toc?: boolean;
hide_outline?: boolean;
outline_maxdepth?: number;
navbar_icons?: NavbarIcon[];
};
84 changes: 84 additions & 0 deletions packages/site/src/components/Navigation/NavbarIcons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* Navbar icon links for social media and external resources.
* Configured via site.options.navbar_icons in myst.yml.
*/
import type { NavbarIcon } from '@myst-theme/common';
import {
GithubIcon,
XIcon,
BlueskyIcon,
DiscordIcon,
MastodonIcon,
LinkedinIcon,
YoutubeIcon,
SlackIcon,
EmailIcon,
WebsiteIcon,
} from '@scienceicons/react/24/solid';
import { RssIcon } from '@heroicons/react/24/solid';

// Maps icon name strings to icon components
const ICON_MAP: Record<string, React.ComponentType<{ className?: string }>> = {
github: GithubIcon,
twitter: XIcon,
x: XIcon,
bluesky: BlueskyIcon,
discord: DiscordIcon,
mastodon: MastodonIcon,
linkedin: LinkedinIcon,
youtube: YoutubeIcon,
slack: SlackIcon,
email: EmailIcon,
rss: RssIcon,
link: WebsiteIcon,
website: WebsiteIcon,
};

// Default tooltip text for each icon type
const DEFAULT_TITLES: Record<string, string> = {
github: 'GitHub',
twitter: 'X (Twitter)',
x: 'X (Twitter)',
bluesky: 'Bluesky',
discord: 'Discord',
mastodon: 'Mastodon',
linkedin: 'LinkedIn',
youtube: 'YouTube',
slack: 'Slack',
email: 'Email',
rss: 'RSS Feed',
link: 'Website',
website: 'Website',
};

/** Single icon link that opens in a new tab */
export function NavbarIconLink({ icon, url, title }: NavbarIcon) {
const IconComponent = ICON_MAP[icon.toLowerCase()] ?? WebsiteIcon;
const displayTitle = title ?? DEFAULT_TITLES[icon.toLowerCase()] ?? icon;

return (
<a
href={url}
title={displayTitle}
target="_blank"
rel="noopener noreferrer"
className="myst-navbar-icon inline-flex items-center justify-center p-2 text-stone-600 dark:text-stone-300 hover:text-stone-900 dark:hover:text-white transition-colors"
>
<IconComponent className="w-5 h-5" />
<span className="sr-only">{displayTitle}</span>
</a>
);
}

/** Container for multiple navbar icon links */
export function NavbarIcons({ icons, className }: { icons?: NavbarIcon[]; className?: string }) {
if (!icons || icons.length === 0) return null;

return (
<div className={`myst-navbar-icons flex items-center ${className ?? ''}`}>
{icons.map((iconConfig, index) => (
<NavbarIconLink key={iconConfig.url || index} {...iconConfig} />
))}
</div>
);
}
15 changes: 14 additions & 1 deletion packages/site/src/components/Navigation/PrimarySidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { ExternalOrInternalLink } from './Link.js';
import type { SiteManifest, SiteNavItem } from 'myst-config';
import * as Collapsible from '@radix-ui/react-collapsible';
import { ChevronRightIcon } from '@heroicons/react/24/solid';
import { NavbarIcons } from './NavbarIcons.js';

export function SidebarNavItem({ item }: { item: SiteNavItem }) {
const baseurl = useBaseurl();
Expand Down Expand Up @@ -152,6 +153,7 @@ export const PrimarySidebar = ({
const footerRef = useRef<HTMLDivElement>(null);
const [open] = useNavOpen();
const config = useSiteManifest();
const { navbar_icons } = config?.options ?? {};

useEffect(() => {
setTimeout(() => {
Expand Down Expand Up @@ -191,6 +193,7 @@ export const PrimarySidebar = ({
)}
>
<div className="myst-primary-sidebar-nav flex-grow py-6 overflow-y-auto primary-scrollbar">
{/* Site navigation links (mobile only) */}
{nav && (
<nav
aria-label="Navigation"
Expand All @@ -199,7 +202,17 @@ export const PrimarySidebar = ({
<SidebarNav nav={nav} />
</nav>
)}
{nav && headings && <div className="my-3 border-b-2 lg:hidden" />}
{/* Social/external icon links (mobile only) */}
{navbar_icons && navbar_icons.length > 0 && (
<div className="myst-primary-sidebar-icons ml-3 xl:ml-0 mr-3 max-w-[350px] lg:hidden py-2">
<NavbarIcons icons={navbar_icons} />
</div>
)}
{/* Divider between nav/icons and table of contents */}
{(nav || (navbar_icons && navbar_icons.length > 0)) && headings && (
<div className="my-3 border-b-2 lg:hidden" />
)}
{/* Page table of contents */}
{headings && (
<nav
aria-label="Table of Contents"
Expand Down
4 changes: 3 additions & 1 deletion packages/site/src/components/Navigation/TopNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { LoadingBar } from './Loading.js';
import { HomeLink } from './HomeLink.js';
import { ActionMenu } from './ActionMenu.js';
import { ExternalOrInternalLink } from './Link.js';
import { NavbarIcons } from './NavbarIcons.js';

export const DEFAULT_NAV_HEIGHT = 60;

Expand Down Expand Up @@ -117,7 +118,7 @@ export function TopNav({ hideToc, hideSearch }: { hideToc?: boolean; hideSearch?
const [open, setOpen] = useNavOpen();
const config = useSiteManifest();
const { title, nav, actions } = config ?? {};
const { logo, logo_dark, logo_text, logo_url } = config?.options ?? {};
const { logo, logo_dark, logo_text, logo_url, navbar_icons } = config?.options ?? {};
return (
<div className="myst-top-nav bg-white/80 backdrop-blur dark:bg-stone-900/80 shadow dark:shadow-stone-700 p-3 md:px-8 sticky w-full top-0 z-30 h-[60px]">
<nav className="myst-top-nav-bar flex items-center justify-between flex-nowrap max-w-[1440px] mx-auto">
Expand Down Expand Up @@ -152,6 +153,7 @@ export function TopNav({ hideToc, hideSearch }: { hideToc?: boolean; hideSearch?
<NavItems nav={nav} />
<div className="flex-grow block"></div>
{!hideSearch && <Search />}
<NavbarIcons icons={navbar_icons} className="hidden sm:flex" />
<ThemeButton />
<div className="block sm:hidden">
<ActionMenu actions={actions} />
Expand Down
1 change: 1 addition & 0 deletions packages/site/src/components/Navigation/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export { InlineTableOfContents } from './InlineTableOfContents.js';
export { LoadingBar } from './Loading.js';
export { ActionMenu } from './ActionMenu.js';
export { HomeLink } from './HomeLink.js';
export { NavbarIcons, NavbarIconLink } from './NavbarIcons.js';
3 changes: 3 additions & 0 deletions themes/article/template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ options:
- type: file
id: style
description: Local path to a CSS file
- type: array
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we have a type array?

Similar to the nav this is a special property that this PR is introducing across all site themes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think this part needs to be changed to object or something - I haven't put any cycles in this since my original push because it's not clear to me if folks want to make a deeper change in mystmd first and it's blocking this

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think this part needs to be changed to object or something - I haven't put any cycles in this since my original push because it's not clear to me if folks want to make a deeper change in mystmd first and it's blocking this

id: navbar_icons
description: Array of icon links for the navbar (e.g., github, discord, bluesky)
build:
install: npm ci --ignore-scripts
start: npm run start
Expand Down
3 changes: 3 additions & 0 deletions themes/book/template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ options:
- type: file
id: style
description: Local path to a CSS file
- type: array
id: navbar_icons
description: Array of icon links for the navbar (e.g., github, discord, bluesky)
parts:
- id: footer
description: The site wide footer
Expand Down
Loading