vizhub-core / vzcode

Mob Programming Code Editor
MIT License
71 stars 14 forks source link

VizHub Color Theme Option #136

Closed curran closed 1 year ago

curran commented 1 year ago

https://github.com/vizhub-core/vizhub/blob/01cadfb78a2611df32f981b1fd8136b70447de9e/vizhub-v2/packages/neoFrontend/src/pages/VizPage/Body/Editor/themes/vizHub.js

const defaultRotation = 0.397;

curran commented 1 year ago

Related to https://github.com/uiwjs/react-codemirror/issues/557

curran commented 1 year ago

See https://raw.githubusercontent.com/vizhub-core/vizhub/01cadfb78a2611df32f981b1fd8136b70447de9e/vizhub-v2/packages/neoFrontend/src/pages/VizPage/Body/Editor/themes/vizHub.js

TODO:

import { hcl } from 'd3-color';

const sidebarDark = hcl('#3d4b65');
const sidebarLight = hcl('#5b677d');

const luminaceDifference = sidebarLight.l - sidebarDark.l;

const backgroundLuminance = sidebarDark.l - luminaceDifference * 1.1;
export const backgroundColor = hcl(
  sidebarDark.h,
  sidebarDark.c,
  backgroundLuminance
).formatHex();

const luminance = 90;

// The luminance difference between background and foreground
// measured in the OneDark Pro VSCode theme.
// const oneDarkContrast = 62;

// Use this to check luminance difference (contrast).
// console.log(luminance - backgroundLuminance);

const saturation = 70;
export const light = hcl(0, 0, luminance).formatHex();
const dark = hcl(sidebarDark.h, sidebarDark.c, 80).formatHex();

export const vizHub = (rotation) => {
  const entries = [
    'keyword',
    ['tag', 'variable', 'variable2', 'variable3', 'definition'],
    ['qualifier', 'builtin', 'header'],
    ['string', 'string2'],
    ['atom', 'number'],
    ['link', 'attribute', 'property'],
  ];

  const lightEntries = ['operator'];

  const theme = {
    container: {
      color: light,
      backgroundColor,
    },
    headerBackgroundColor: hcl(
      sidebarDark.h,
      sidebarDark.c,
      (backgroundLuminance + sidebarDark.l) / 2
    ).formatHex(),
    selectionBackground: '#000',
    lineNumbers: {
      color: 'rgba(255,255,255,0.2)',
      cursor: 'pointer',
    },
    //keyword: { color: '#c679de' },
    //atom: { color: '#98c379' },
    //property: { color: '#61afef' },
    //number: { color: '#d19a66' },
    comment: { color: dark },
    meta: { color: dark },
    //variable: { color: '#5bafef' },
    //number: { color: light },
    fatCursor: { backgroundColor: 'rgba(228, 232, 255, 0.3)' },
    default: { color: light },
    link: {
      cursor: 'pointer',
    },
  };

  theme.searching = theme.fatCursor;

  theme.colors = entries.map((entry, i) => {
    const t = ((i + 0) / entries.length + rotation) % 1;
    const color = hcl(t * 360, saturation, luminance).formatHex();
    const keys = typeof entry === 'string' ? [entry] : entry;
    keys.forEach((key) => {
      theme[key] = Object.assign({}, theme[key], { color });
    });
    return color;
  });

  theme.link.textDecoration = 'none';
  theme.header.fontWeight = 'normal';

  lightEntries.forEach((key) => {
    theme[key] = { color: light };
  });

  theme.colors.push(theme.colors[0]);
  theme.colors.push(light);

  theme.caretColor = 'white';

  theme.gutters = theme.gutter = Object.assign({}, theme.container, {
    border: 'none',
  });

  theme.matchingBracket = {
    color: theme.container.color,
    borderBottom: '1px solid rgba(255,255,255,0.4)',
  };

  return theme;
};
curran commented 1 year ago

Oh hey we could contribute it to upstream:

https://github.com/uiwjs/react-codemirror/issues/557#issuecomment-1696648456

curran commented 1 year ago

Hooray! This is the output I got to run in #

{
  container: { color: '#e2e2e2', backgroundColor: '#202e46' },
  headerBackgroundColor: '#2e3c55',
  selectionBackground: '#000',
  lineNumbers: { color: 'rgba(255,255,255,0.2)', cursor: 'pointer' },
  comment: { color: '#b9c7e6' },
  meta: { color: '#b9c7e6' },
  fatCursor: { backgroundColor: 'rgba(228, 232, 255, 0.3)' },
  default: { color: '#e2e2e2' },
  link: { cursor: 'pointer', color: '#ffdb56', textDecoration: 'none' },
  searching: { backgroundColor: 'rgba(228, 232, 255, 0.3)' },
  keyword: { color: '#77fd8c' },
  tag: { color: '#00ffff' },
  variable: { color: '#00ffff' },
  variable2: { color: '#00ffff' },
  variable3: { color: '#00ffff' },
  definition: { color: '#00ffff' },
  qualifier: { color: '#66ecff' },
  builtin: { color: '#66ecff' },
  header: { color: '#66ecff', fontWeight: 'normal' },
  string: { color: '#ffb9ff' },
  string2: { color: '#ffb9ff' },
  atom: { color: '#ffabb3' },
  number: { color: '#ffabb3' },
  attribute: { color: '#ffdb56' },
  property: { color: '#ffdb56' },
  colors: [
    '#77fd8c', '#00ffff',
    '#66ecff', '#ffb9ff',
    '#ffabb3', '#ffdb56',
    '#77fd8c', '#e2e2e2'
  ],
  operator: { color: '#e2e2e2' },
  caretColor: 'white',
  gutter: { color: '#e2e2e2', backgroundColor: '#202e46', border: 'none' },
  gutters: { color: '#e2e2e2', backgroundColor: '#202e46', border: 'none' },
  matchingBracket: { color: '#e2e2e2', borderBottom: '1px solid rgba(255,255,255,0.4)' }
}
curran commented 1 year ago

Got some help from GPT4!

import { tags as t } from '@lezer/highlight';
import { createTheme, CreateThemeOptions } from '@uiw/codemirror-themes';

const vizhubColors = {
  // ... [vizhubColors definition as provided] ...
}

export const defaultSettingsVizhubDark: CreateThemeOptions['settings'] = {
  background: vizhubColors.container.backgroundColor,
  foreground: vizhubColors.default.color,
  caret: vizhubColors.caretColor,
  selection: vizhubColors.selectionBackground,
  selectionMatch: vizhubColors.searching.backgroundColor,
  lineHighlight: vizhubColors.selectionBackground,
  gutterBackground: vizhubColors.gutter.backgroundColor,
  gutterForeground: vizhubColors.gutter.color,
  gutterActiveForeground: vizhubColors.default.color,
  fontFamily: 'Menlo, Monaco, Consolas, "Andale Mono", "Ubuntu Mono", "Courier New", monospace',
};

export function vizhubDarkInit(options?: Partial<CreateThemeOptions>) {
  const { theme = 'dark', settings = {}, styles = [] } = options || {};
  return createTheme({
    theme: theme,
    settings: {
      ...defaultSettingsVizhubDark,
      ...settings,
    },
    styles: [
      {
        tag: [
          t.keyword,
          t.operatorKeyword,
          t.modifier,
          t.color,
          t.constant(t.name),
          t.standard(t.name),
          t.standard(t.tagName),
          t.special(t.brace),
          t.atom,
          t.bool,
          t.special(t.variableName),
        ],
        color: vizhubColors.keyword.color,
      },
      {
        tag: [t.controlKeyword, t.moduleKeyword],
        color: vizhubColors.builtin.color,
      },
      {
        tag: [
          t.name,
          t.deleted,
          t.character,
          t.macroName,
          t.propertyName,
          t.variableName,
          t.labelName,
          t.definition(t.name),
        ],
        color: vizhubColors.variable.color,
      },
      { tag: t.heading, fontWeight: vizhubColors.header.fontWeight, color: vizhubColors.header.color },
      {
        tag: [t.typeName, t.className, t.tagName, t.number, t.changed, t.annotation, t.self, t.namespace],
        color: vizhubColors.tag.color,
      },
      {
        tag: [t.function(t.variableName), t.function(t.propertyName)],
        color: vizhubColors.attribute.color,
      },
      { tag: [t.number], color: vizhubColors.number.color },
      {
        tag: [t.operator, t.punctuation, t.separator, t.url, t.escape, t.regexp],
        color: vizhubColors.operator.color,
      },
      {
        tag: [t.regexp],
        color: vizhubColors.atom.color,
      },
      {
        tag: [t.special(t.string), t.processingInstruction, t.string, t.inserted],
        color: vizhubColors.string.color,
      },
      { tag: [t.angleBracket], color: vizhubColors.operator.color },
      { tag: t.strong, fontWeight: 'bold' },
      { tag: t.emphasis, fontStyle: 'italic' },
      { tag: t.strikethrough, textDecoration: 'line-through' },
      { tag: [t.meta, t.comment], color: vizhubColors.comment.color },
      { tag: t.link, color: vizhubColors.link.color, textDecoration: vizhubColors.link.textDecoration },
      { tag: t.invalid, color: '#ff0000' },
      ...styles,
    ],
  });
}

export const vizhubDark = vizhubDarkInit();