UNPKG

@astrojs/starlight

Version:

Build beautiful, high-performance documentation websites with Astro

106 lines (88 loc) 4.51 kB
import { ExpressiveCodeTheme, type ThemeObjectOrShikiThemeName } from 'astro-expressive-code'; import nightOwlDark from './themes/night-owl-dark.jsonc?raw'; import nightOwlLight from './themes/night-owl-light.jsonc?raw'; export type BundledThemeName = 'starlight-dark' | 'starlight-light'; export type ThemeObjectOrBundledThemeName = ThemeObjectOrShikiThemeName | BundledThemeName; /** * Converts the Starlight `themes` config option into a format understood by Expressive Code, * loading any bundled themes and using the Starlight defaults if no themes were provided. */ export function preprocessThemes( themes: ThemeObjectOrBundledThemeName[] | undefined ): ThemeObjectOrShikiThemeName[] { // Try to gracefully handle cases where the user forgot to use an array in the config themes = themes && !Array.isArray(themes) ? [themes] : themes; // If no themes were provided, use our bundled default themes if (!themes || !themes.length) themes = ['starlight-dark', 'starlight-light']; return themes.map((theme) => { // If the current entry is the name of a bundled theme, load it if (theme === 'starlight-dark' || theme === 'starlight-light') { const bundledTheme = theme === 'starlight-dark' ? nightOwlDark : nightOwlLight; return customizeBundledTheme(ExpressiveCodeTheme.fromJSONString(bundledTheme)); } // Otherwise, just pass it through return theme; }); } /** * Customizes some settings of the bundled theme to make it fit better with Starlight. */ function customizeBundledTheme(theme: ExpressiveCodeTheme) { theme.colors['titleBar.border'] = theme.colors['tab.activeBackground']; theme.colors['editorGroupHeader.tabsBorder'] = theme.colors['tab.activeBackground']; // Add underline font style to link syntax highlighting tokens // to match the new GitHub theme link style theme.settings.forEach((s) => { if (s.name?.includes('Link')) s.settings.fontStyle = 'underline'; }); return theme; } /** * Modifies the given theme by applying Starlight's CSS variables to the colors of UI elements * (backgrounds, buttons, shadows etc.). This ensures that code blocks match the site's theme. */ export function applyStarlightUiThemeColors(theme: ExpressiveCodeTheme) { const isDark = theme.type === 'dark'; const neutralMinimal = isDark ? '#ffffff17' : '#0000001a'; const neutralDimmed = isDark ? '#ffffff40' : '#00000055'; // Make borders slightly transparent const borderColor = 'color-mix(in srgb, var(--sl-color-gray-5), transparent 25%)'; theme.colors['titleBar.border'] = borderColor; theme.colors['editorGroupHeader.tabsBorder'] = borderColor; // Use the same color for terminal title bar background and editor tab bar background const backgroundColor = isDark ? 'var(--sl-color-black)' : 'var(--sl-color-gray-6)'; theme.colors['titleBar.activeBackground'] = backgroundColor; theme.colors['editorGroupHeader.tabsBackground'] = backgroundColor; // Use the same color for terminal titles and tab titles theme.colors['titleBar.activeForeground'] = 'var(--sl-color-text)'; theme.colors['tab.activeForeground'] = 'var(--sl-color-text)'; // Set tab border colors const activeBorderColor = isDark ? 'var(--sl-color-accent-high)' : 'var(--sl-color-accent)'; theme.colors['tab.activeBorder'] = 'transparent'; theme.colors['tab.activeBorderTop'] = activeBorderColor; // Use neutral colors for scrollbars theme.colors['scrollbarSlider.background'] = neutralMinimal; theme.colors['scrollbarSlider.hoverBackground'] = neutralDimmed; // Set theme `bg` color property for contrast calculations theme.bg = isDark ? '#23262f' : '#f6f7f9'; theme.colors['editor.background'] = theme.bg; // Set actual background color to the appropriate Starlight CSS variable const editorBackgroundColor = isDark ? 'var(--sl-color-gray-6)' : 'var(--sl-color-gray-7)'; theme.styleOverrides.frames = { // Use the same color for editor background, terminal background and active tab background editorBackground: editorBackgroundColor, terminalBackground: editorBackgroundColor, editorActiveTabBackground: editorBackgroundColor, terminalTitlebarDotsForeground: borderColor, terminalTitlebarDotsOpacity: '0.75', inlineButtonForeground: 'var(--sl-color-text)', frameBoxShadowCssValue: 'none', }; // Use neutral, semi-transparent colors for default text markers // to avoid conflicts with the user's chosen background color theme.styleOverrides.textMarkers = { markBackground: neutralMinimal, markBorderColor: neutralDimmed, }; return theme; }