@fsegurai/codemirror-theme-tokyo-night-day
Version:
Tokyo Night Day theme for the CodeMirror editor
516 lines (510 loc) • 17.9 kB
JavaScript
import { EditorView } from '@codemirror/view';
import { HighlightStyle, syntaxHighlighting } from '@codemirror/language';
import { tags } from '@lezer/highlight';
// Helper module for styling options
const generalContent = {
fontSize: '14px',
fontFamily: 'JetBrains Mono, Consolas, monospace',
lineHeight: '1.6',
};
const generalCursor = {
borderLeftWidth: '2px',
};
const generalDiff = {
insertedTextDecoration: 'none',
deletedTextDecoration: 'line-through',
insertedLinePadding: '1px 3px',
borderRadius: '3px'};
const generalGutter = {
border: 'none',
paddingRight: '8px',
fontSize: '0.9em',
fontWeight: '500',
lineHeight: '1.78', // Adjusted to compensate for 0.9em fontSize (1.6 / 0.9 ≈ 1.78)
};
const generalPanel = {
border: 'none',
borderRadius: '4px',
padding: '2px 10px',
};
const generalLine = {
borderRadius: '2px',
};
const generalMatching = {
borderRadius: '2px',
};
const generalPlaceholder = {
borderRadius: '4px',
padding: '0 5px',
margin: '0 2px',
};
const generalScroller = {
width: '12px',
height: '12px',
borderRadius: '6px',
};
const generalSearchField = {
borderRadius: '4px',
padding: '2px 6px',
};
const generalTooltip = {
borderRadius: '4px',
borderRadiusSelected: '3px',
lineHeight: '1.3',
padding: '4px 8px',
paddingRight: '8px',
};
/**
* Function to apply merge revert styles for a theme
* @param styles Styles for the merge revert buttons
* @param styles.backgroundColor Background color of the revert area
* @param styles.borderColor Border color of the revert area
* @param styles.buttonColor Color of the revert buttons
* @param styles.buttonHoverColor Hover color of the revert buttons
*/
function applyMergeRevertStyles(styles) {
// Create a stylesheet
const styleEl = document.createElement('style');
styleEl.id = 'cm-merge-revert-styles';
// Define CSS with the theme-specific values
styleEl.textContent = `
.cm-merge-revert {
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
padding: 4px;
background-color: ${styles.backgroundColor};
border-left: 1px solid ${styles.borderColor};
border-right: 1px solid ${styles.borderColor};
width: 32px;
}
.cm-merge-revert button {
width: 100%;
height: auto;
background-color: transparent;
border: none;
color: ${styles.buttonColor};
cursor: pointer;
margin: 0 auto;
font-size: 20px;
}
.cm-merge-revert button:hover {
background-color: ${styles.buttonHoverColor};
}
`;
// Remove any existing merge styles
const existingStyle = document.getElementById('cm-merge-revert-styles');
if (existingStyle)
existingStyle.remove();
// Add the new styles
document.head.appendChild(styleEl);
}
/**
* Enhanced Tokyo Night Day theme color definitions
* ---------------------------------------------
* Colors organized by function with visual color blocks
*/
// Base colors
const base00 = '#e1e2e7', // Background
base01 = '#3760bf', // Primary foreground
base02 = '#99a7df', // Selection background
base03 = '#848cb5', // Comments, invisibles
base04 = '#8c91a8', // Dark foreground (status)
base05 = '#3760bf', // Default foreground
base06 = '#e9e9ec', // Light background
base07 = '#d5d6db', // Light background (gutter)
// Accent colors
base_red = '#f52a65', // Errors, invalid
base_orange = '#b15c00', // Numbers, constants
base_yellow = '#8c6c3e', // Classes, attributes
base_green = '#587539', // Strings, success
base_cyan = '#007197', // Functions, keywords
base_blue = '#2e7de9', // Variables, parameters
base_purple = '#7847bd', // Operators, tags
base_magenta = '#9854f1'; // Special characters
// UI specific colors
const invalid = base_red, darkBackground = base07, highlightBackground = '#5F5FAF5A', // Line highlight with improved transparency
background = base00, tooltipBackground = base06, selection = '#99a7df40', // Selection background with transparency
selectionMatch = '#99a7df60', // Selection match with transparency
cursor = base01, // Cursor color
activeBracketBg = '#0e639c20', // Active bracket background with transparency
activeBracketBorder = base_cyan, // Active bracket border
diagnosticWarning = base_orange, // Warning color
linkColor = base_cyan, // Link color
visitedLinkColor = base_purple; // Visited link color
// Diff/merge specific colors
const addedBackground = '#58753920', // Green with transparency for insertions
removedBackground = '#f52a6520', // Red with transparency for deletions
addedText = '#587539', // Tokyo Night Day green for added text
removedText = '#f52a65'; // Tokyo Night Day red for removed text
/**
* Enhanced editor theme styles for Tokyo Night Day
*/
const tokyoNightDayTheme = /*@__PURE__*/EditorView.theme({
// Base editor styles
'&': {
color: base05,
backgroundColor: background,
fontSize: generalContent.fontSize,
fontFamily: generalContent.fontFamily,
},
// Content and cursor
'.cm-content': {
caretColor: cursor,
lineHeight: generalContent.lineHeight,
},
'.cm-cursor, .cm-dropCursor': {
borderLeftColor: cursor,
borderLeftWidth: generalCursor.borderLeftWidth,
},
'.cm-fat-cursor': {
backgroundColor: `${cursor}99`,
color: background,
},
// Selection
'&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': {
backgroundColor: selection,
},
// Make sure selection appears above active line
'.cm-selectionLayer': {
zIndex: 100,
},
// Search functionality
'.cm-searchMatch': {
backgroundColor: '#0e639c40',
outline: `1px solid ${base_cyan}`,
color: base05,
borderRadius: generalSearchField.borderRadius,
},
'.cm-searchMatch.cm-searchMatch-selected': {
backgroundColor: base_cyan,
color: background,
padding: generalSearchField.padding,
'& span': {
color: background,
},
},
'.cm-search.cm-panel.cm-textfield': {
color: base05,
borderRadius: generalSearchField.borderRadius,
padding: generalSearchField.padding,
},
// Panels
'.cm-panels': {
backgroundColor: base06,
color: base05,
borderRadius: '4px',
boxShadow: '0 1px 3px rgba(0, 0, 0, 0.1)',
},
'.cm-panels.cm-panels-top': {
borderBottom: `1px solid ${base03}30`,
},
'.cm-panels.cm-panels-bottom': {
borderTop: `1px solid ${base03}30`,
},
'.cm-panel button': {
backgroundColor: tooltipBackground,
color: base05,
border: generalPanel.border,
borderRadius: generalPanel.borderRadius,
padding: generalPanel.padding,
},
'.cm-panel button:hover': {
backgroundColor: base07,
border: `1px solid ${base02}`,
},
// Line highlighting
'.cm-activeLine': {
backgroundColor: highlightBackground,
borderRadius: generalLine.borderRadius,
zIndex: 1,
},
// Gutters
'.cm-gutters': {
backgroundColor: darkBackground,
color: base03,
border: generalGutter.border,
borderRight: `1px solid ${base07}`,
paddingRight: generalGutter.paddingRight,
},
'.cm-activeLineGutter': {
// backgroundColor: '#CFD0D608)',
color: base01,
fontWeight: generalGutter.fontWeight,
},
'.cm-lineNumbers': {
fontSize: generalGutter.fontSize,
lineHeight: generalGutter.lineHeight,
},
'.cm-foldGutter': {
fontSize: generalGutter.fontSize,
lineHeight: generalGutter.lineHeight,
},
'.cm-foldGutter .cm-gutterElement': {
color: base03,
cursor: 'pointer',
},
'.cm-foldGutter .cm-gutterElement:hover': {
color: base01,
},
// Diff/Merge View Styles
// Inserted/Added Content
'.cm-insertedLine': {
textDecoration: generalDiff.insertedTextDecoration,
backgroundColor: addedBackground,
color: addedText,
padding: generalDiff.insertedLinePadding,
borderRadius: generalDiff.borderRadius,
},
'ins.cm-insertedLine, ins.cm-insertedLine:not(:has(.cm-changedText))': {
textDecoration: generalDiff.insertedTextDecoration,
backgroundColor: `${addedBackground} !important`,
color: addedText,
padding: generalDiff.insertedLinePadding,
borderRadius: generalDiff.borderRadius,
border: `1px solid ${addedText}40`,
},
'ins.cm-insertedLine .cm-changedText': {
background: 'transparent !important',
},
// Deleted/Removed Content
'.cm-deletedLine': {
textDecoration: generalDiff.deletedTextDecoration,
backgroundColor: removedBackground,
color: removedText,
padding: generalDiff.insertedLinePadding,
borderRadius: generalDiff.borderRadius,
},
'del.cm-deletedLine, del, del:not(:has(.cm-deletedText))': {
textDecoration: generalDiff.deletedTextDecoration,
backgroundColor: `${removedBackground} !important`,
color: removedText,
padding: generalDiff.insertedLinePadding,
borderRadius: generalDiff.borderRadius,
border: `1px solid ${removedText}40`,
},
'del .cm-deletedText, del .cm-changedText': {
background: 'transparent !important',
},
// Tooltips and autocomplete
'.cm-tooltip': {
backgroundColor: tooltipBackground,
border: `1px solid ${base04}40`,
borderRadius: generalTooltip.borderRadius,
padding: generalTooltip.padding,
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.15)',
},
'.cm-tooltip-autocomplete': {
'& > ul': {
backgroundColor: tooltipBackground,
border: 'none',
maxHeight: '300px',
},
'& > ul > li': {
padding: generalTooltip.padding,
lineHeight: generalTooltip.lineHeight,
},
'& > ul > li[aria-selected]': {
backgroundColor: selection,
color: base01,
borderRadius: generalTooltip.borderRadiusSelected,
},
'& > ul > li > span.cm-completionIcon': {
color: base03,
paddingRight: generalTooltip.paddingRight,
},
'& > ul > li > span.cm-completionDetail': {
color: base03,
fontStyle: 'italic',
},
},
'.cm-tooltip .cm-tooltip-arrow:before': {
borderTopColor: 'transparent',
borderBottomColor: 'transparent',
},
'.cm-tooltip .cm-tooltip-arrow:after': {
borderTopColor: tooltipBackground,
borderBottomColor: tooltipBackground,
},
// Diagnostics styling
'.cm-diagnostic': {
'&-error': {
borderLeft: `3px solid ${invalid}`,
},
'&-warning': {
borderLeft: `3px solid ${diagnosticWarning}`,
},
'&-info': {
borderLeft: `3px solid ${linkColor}`,
},
},
'.cm-lintPoint-error': {
borderBottom: `2px wavy ${invalid}`,
},
'.cm-lintPoint-warning': {
borderBottom: `2px wavy ${diagnosticWarning}`,
},
// Matching brackets
'.cm-matchingBracket': {
backgroundColor: activeBracketBg,
outline: `1px solid ${activeBracketBorder}`,
borderRadius: generalMatching.borderRadius,
},
'.cm-nonmatchingBracket': {
backgroundColor: `${base_red}20`,
outline: `1px solid ${invalid}`,
borderRadius: generalMatching.borderRadius,
},
// Selection matches
'.cm-selectionMatch': {
backgroundColor: selectionMatch,
outline: `1px solid ${base02}50`,
borderRadius: generalMatching.borderRadius,
},
// Fold placeholder
'.cm-foldPlaceholder': {
backgroundColor: tooltipBackground,
color: base03,
border: `1px dotted ${base03}70`,
borderRadius: generalPlaceholder.borderRadius,
padding: generalPlaceholder.padding,
margin: generalPlaceholder.margin,
},
// Focus outline
'&.cm-focused': {
outline: 'none',
boxShadow: `0 0 0 2px ${background}, 0 0 0 3px ${base_cyan}40`,
},
// Scrollbars
'& .cm-scroller::-webkit-scrollbar': {
width: generalScroller.width,
height: generalScroller.height,
},
'& .cm-scroller::-webkit-scrollbar-track': {
background: darkBackground,
},
'& .cm-scroller::-webkit-scrollbar-thumb': {
backgroundColor: base03,
borderRadius: generalScroller.borderRadius,
border: `3px solid ${darkBackground}`,
},
'& .cm-scroller::-webkit-scrollbar-thumb:hover': {
backgroundColor: base02,
},
// Ghost text
'.cm-ghostText': {
opacity: '0.5',
color: base03,
},
}, { dark: false });
/**
* Enhanced syntax highlighting for Tokyo Night Day theme
*/
const tokyoNightDayHighlightStyle = /*@__PURE__*/HighlightStyle.define([
// Keywords and control flow
{ tag: tags.keyword, color: base_cyan, fontWeight: 'bold' },
{ tag: tags.controlKeyword, color: base_cyan, fontWeight: 'bold' },
{ tag: tags.moduleKeyword, color: base_cyan, fontWeight: 'bold' },
// Names and variables
{ tag: [tags.name, tags.deleted, tags.character, tags.macroName], color: base_blue },
{ tag: [tags.variableName], color: base01 },
{ tag: [tags.propertyName], color: base_blue, fontStyle: 'normal' },
// Classes and types
{ tag: [tags.typeName], color: base_cyan },
{ tag: [tags.className], color: base_yellow, fontStyle: 'italic' },
{ tag: [tags.namespace], color: base_purple, fontStyle: 'italic' },
// Operators and punctuation
{ tag: [tags.operator, tags.operatorKeyword], color: base_purple },
{ tag: [tags.bracket], color: base03 },
{ tag: [tags.brace], color: base03 },
{ tag: [tags.punctuation], color: base03 },
// Functions and parameters
{ tag: [/*@__PURE__*/tags.function(tags.variableName)], color: base_cyan },
{ tag: [tags.labelName], color: base_purple, fontStyle: 'italic' },
{ tag: [/*@__PURE__*/tags.definition(/*@__PURE__*/tags.function(tags.variableName))], color: base_cyan },
{ tag: [/*@__PURE__*/tags.definition(tags.variableName)], color: base_blue },
// Constants and literals
{ tag: tags.number, color: base_orange },
{ tag: tags.changed, color: base_orange },
{ tag: tags.annotation, color: invalid, fontStyle: 'italic' },
{ tag: tags.modifier, color: base_orange, fontStyle: 'italic' },
{ tag: tags.self, color: base_orange },
{
tag: [tags.color, /*@__PURE__*/tags.constant(tags.name), /*@__PURE__*/tags.standard(tags.name)],
color: base_orange,
},
{ tag: [tags.atom, tags.bool, /*@__PURE__*/tags.special(tags.variableName)], color: base_orange },
// Strings and regex
{ tag: [tags.processingInstruction, tags.inserted], color: base_green },
{ tag: [/*@__PURE__*/tags.special(tags.string), tags.regexp], color: base_magenta },
{ tag: tags.string, color: base_green },
// Punctuation and structure
{ tag: /*@__PURE__*/tags.definition(tags.typeName), color: base_cyan, fontWeight: 'bold' },
{ tag: [/*@__PURE__*/tags.definition(tags.name), tags.separator], color: base_blue },
// Comments and documentation
{ tag: tags.meta, color: base03 },
{ tag: tags.comment, fontStyle: 'italic', color: base03 },
{ tag: tags.docComment, fontStyle: 'italic', color: base03 },
// HTML/XML elements
{ tag: [tags.tagName], color: base_purple },
{ tag: [tags.attributeName], color: base_yellow },
// Markdown and text formatting
{ tag: [tags.heading], fontWeight: 'bold', color: base_orange },
{ tag: tags.heading1, color: base_orange, fontWeight: 'bold' },
{ tag: tags.heading2, color: base_orange },
{ tag: tags.heading3, color: base_orange },
{ tag: tags.heading4, color: base_cyan },
{ tag: tags.heading5, color: base_cyan },
{ tag: tags.heading6, color: base_cyan },
{ tag: [tags.strong], fontWeight: 'bold', color: base01 },
{ tag: [tags.emphasis], fontStyle: 'italic', color: base_green },
// Links and URLs
{
tag: [tags.link],
color: visitedLinkColor,
fontWeight: '500',
textDecoration: 'underline',
textUnderlinePosition: 'under',
},
{
tag: [tags.url],
color: linkColor,
textDecoration: 'underline',
textUnderlineOffset: '2px',
},
// Special states
{
tag: [tags.invalid],
color: base01,
textDecoration: 'underline wavy',
borderBottom: `1px wavy ${invalid}`,
},
{ tag: [tags.strikethrough], color: invalid, textDecoration: 'line-through' },
// Enhanced syntax highlighting
{ tag: /*@__PURE__*/tags.constant(tags.name), color: base_orange },
{ tag: tags.deleted, color: invalid },
{ tag: tags.squareBracket, color: base03 },
{ tag: tags.angleBracket, color: base03 },
// Additional specific styles
{ tag: tags.monospace, color: base01 },
{ tag: [tags.contentSeparator], color: base_blue },
{ tag: tags.quote, color: base03 },
]);
/**
* Combined Tokyo Night Day theme extension
*/
const tokyoNightDay = [
tokyoNightDayTheme,
/*@__PURE__*/syntaxHighlighting(tokyoNightDayHighlightStyle),
];
/**
* Tokyo Night Day merge revert styles configuration
*/
const tokyoNightDayMergeStyles = {
backgroundColor: base07,
borderColor: base03,
buttonColor: base01,
buttonHoverColor: selectionMatch,
};
export { applyMergeRevertStyles, tokyoNightDay, tokyoNightDayMergeStyles };