From 74ef8b53f114a900824dbcbc64b0ffaca067b3c5 Mon Sep 17 00:00:00 2001 From: Per Brolin Date: Tue, 18 Jun 2024 13:00:37 +0200 Subject: [PATCH] MC-1765: WIP. Gradiant --- cypress/platform/per.html | 6 +- docs/neo-style-to-do | 1 + packages/mermaid/src/themes/theme-gradient.js | 372 ++++++++++++++++++ 3 files changed, 376 insertions(+), 3 deletions(-) create mode 100644 packages/mermaid/src/themes/theme-gradient.js diff --git a/cypress/platform/per.html b/cypress/platform/per.html index dfd4c2ae0..c9987d84f 100644 --- a/cypress/platform/per.html +++ b/cypress/platform/per.html @@ -89,7 +89,7 @@ stateDiagram-v2 -
+    
       stateDiagram-v2
       [*] --> First
       state First {
@@ -100,7 +100,7 @@ stateDiagram-v2
 
     
-
+    
       flowchart LR
         A[Start] --Some text--> B(Continue)
         B --> C{Evaluate}
@@ -117,7 +117,7 @@ stateDiagram-v2
         console.error('Mermaid error: ', err);
       };
       mermaid.initialize({
-        theme: 'forest',
+        theme: 'neo',
         handdrawnSeed: 12,
         look: 'neo',
         //layout: 'elk',
diff --git a/docs/neo-style-to-do b/docs/neo-style-to-do
index 5e8a1c917..2cf300a3e 100644
--- a/docs/neo-style-to-do
+++ b/docs/neo-style-to-do
@@ -9,3 +9,4 @@
 9. When selecting look=neo and theme for composite stated, the height differs.
 10. Drop-shadows for non-rectangular shapes are not supported: Status: Fixed
 11. Gradient
+12. Rx,Ry of rects do not apply any longer
diff --git a/packages/mermaid/src/themes/theme-gradient.js b/packages/mermaid/src/themes/theme-gradient.js
new file mode 100644
index 000000000..843f1cf45
--- /dev/null
+++ b/packages/mermaid/src/themes/theme-gradient.js
@@ -0,0 +1,372 @@
+import { darken, lighten, adjust, invert, isDark, toRgba } from 'khroma';
+import { mkBorder } from './theme-helpers.js';
+import {
+  oldAttributeBackgroundColorEven,
+  oldAttributeBackgroundColorOdd,
+} from './erDiagram-oldHardcodedValues.js';
+
+class Theme {
+  constructor() {
+    /** # Base variables */
+    /**
+     * - Background - used to know what the background color is of the diagram. This is used for
+     *   deducing colors for instance line color. Default value is #f4f4f4.
+     */
+    this.background = '#ffffff';
+
+    this.primaryColor = '#cccccc';
+    this.mainBkg = '#ffffff';
+
+    this.noteBkgColor = '#fff5ad';
+    this.noteTextColor = '#333';
+
+    this.THEME_COLOR_LIMIT = 12;
+    this.radius = 3;
+    // dark
+
+    this.fontFamily = '"trebuchet ms", verdana, arial, sans-serif';
+    this.fontSize = '10px';
+
+    // Neo-specific
+    this.nodeBorder = '#550000';
+    this.stateBorder = 'none';
+  }
+  updateColors() {
+    // The || is to make sure that if the variable has been defined by a user override that value is to be used
+
+    /* Main */
+    this.primaryTextColor = this.primaryTextColor || (this.darkMode ? '#eee' : '#333'); // invert(this.primaryColor);
+    this.secondaryColor = this.secondaryColor || adjust(this.primaryColor, { h: -120 });
+    this.tertiaryColor = this.tertiaryColor || adjust(this.primaryColor, { h: 180, l: 5 });
+
+    this.primaryBorderColor = this.primaryBorderColor || mkBorder(this.primaryColor, this.darkMode);
+    this.secondaryBorderColor =
+      this.secondaryBorderColor || mkBorder(this.secondaryColor, this.darkMode);
+    this.tertiaryBorderColor =
+      this.tertiaryBorderColor || mkBorder(this.tertiaryColor, this.darkMode);
+    this.noteBorderColor = this.noteBorderColor || mkBorder(this.noteBkgColor, this.darkMode);
+    this.noteBkgColor = this.noteBkgColor || '#fff5ad';
+    this.noteTextColor = this.noteTextColor || '#333';
+
+    this.secondaryTextColor = this.secondaryTextColor || invert(this.secondaryColor);
+    this.tertiaryTextColor = this.tertiaryTextColor || invert(this.tertiaryColor);
+    this.lineColor = this.lineColor || invert(this.background);
+    this.arrowheadColor = this.arrowheadColor || invert(this.background);
+    this.textColor = this.textColor || this.primaryTextColor;
+
+    // TODO: should this instead default to secondaryBorderColor?
+    this.border2 = this.border2 || this.tertiaryBorderColor;
+
+    /* Flowchart variables */
+    this.nodeBkg = this.nodeBkg || this.primaryColor;
+    this.mainBkg = this.mainBkg || this.primaryColor;
+    this.nodeBorder = this.nodeBorder || this.primaryBorderColor;
+    this.clusterBkg = this.clusterBkg || this.tertiaryColor;
+    this.clusterBorder = this.clusterBorder || this.tertiaryBorderColor;
+    this.defaultLinkColor = this.defaultLinkColor || this.lineColor;
+    this.titleColor = this.titleColor || this.tertiaryTextColor;
+    this.edgeLabelBackground =
+      this.edgeLabelBackground ||
+      (this.darkMode ? darken(this.secondaryColor, 30) : this.secondaryColor);
+    this.nodeTextColor = this.nodeTextColor || this.primaryTextColor;
+    /* Sequence Diagram variables */
+
+    // this.actorBorder = lighten(this.border1, 0.5);
+    this.actorBorder = this.actorBorder || this.primaryBorderColor;
+    this.actorBkg = this.actorBkg || this.mainBkg;
+    this.actorTextColor = this.actorTextColor || this.primaryTextColor;
+    this.actorLineColor = this.actorLineColor || this.actorBorder;
+    this.labelBoxBkgColor = this.labelBoxBkgColor || this.actorBkg;
+    this.signalColor = this.signalColor || this.textColor;
+    this.signalTextColor = this.signalTextColor || this.textColor;
+    this.labelBoxBorderColor = this.labelBoxBorderColor || this.actorBorder;
+    this.labelTextColor = this.labelTextColor || this.actorTextColor;
+    this.loopTextColor = this.loopTextColor || this.actorTextColor;
+    this.activationBorderColor = this.activationBorderColor || darken(this.secondaryColor, 10);
+    this.activationBkgColor = this.activationBkgColor || this.secondaryColor;
+    this.sequenceNumberColor = this.sequenceNumberColor || invert(this.lineColor);
+
+    /* Gantt chart variables */
+
+    this.sectionBkgColor = this.sectionBkgColor || this.tertiaryColor;
+    this.altSectionBkgColor = this.altSectionBkgColor || 'white';
+    this.sectionBkgColor = this.sectionBkgColor || this.secondaryColor;
+    this.sectionBkgColor2 = this.sectionBkgColor2 || this.primaryColor;
+    this.excludeBkgColor = this.excludeBkgColor || '#eeeeee';
+    this.taskBorderColor = this.taskBorderColor || this.primaryBorderColor;
+    this.taskBkgColor = this.taskBkgColor || this.primaryColor;
+    this.activeTaskBorderColor = this.activeTaskBorderColor || this.primaryColor;
+    this.activeTaskBkgColor = this.activeTaskBkgColor || lighten(this.primaryColor, 23);
+    this.gridColor = this.gridColor || 'lightgrey';
+    this.doneTaskBkgColor = this.doneTaskBkgColor || 'lightgrey';
+    this.doneTaskBorderColor = this.doneTaskBorderColor || 'grey';
+    this.critBorderColor = this.critBorderColor || '#ff8888';
+    this.critBkgColor = this.critBkgColor || 'red';
+    this.todayLineColor = this.todayLineColor || 'red';
+    this.taskTextColor = this.taskTextColor || this.textColor;
+    this.taskTextOutsideColor = this.taskTextOutsideColor || this.textColor;
+    this.taskTextLightColor = this.taskTextLightColor || this.textColor;
+    this.taskTextColor = this.taskTextColor || this.primaryTextColor;
+    this.taskTextDarkColor = this.taskTextDarkColor || this.textColor;
+    this.taskTextClickableColor = this.taskTextClickableColor || '#003163';
+
+    /* Sequence Diagram variables */
+
+    this.personBorder = this.personBorder || this.primaryBorderColor;
+    this.personBkg = this.personBkg || this.mainBkg;
+
+    /* state colors */
+    this.transitionColor = this.transitionColor || this.lineColor;
+    this.transitionLabelColor = this.transitionLabelColor || this.textColor;
+    /* The color of the text tables of the states*/
+    this.stateLabelColor = this.stateLabelColor || this.stateBkg || this.primaryTextColor;
+
+    this.stateBkg = this.stateBkg || this.mainBkg;
+    this.labelBackgroundColor = this.labelBackgroundColor || this.stateBkg;
+    this.compositeBackground = this.compositeBackground || this.background || this.tertiaryColor;
+    this.altBackground = this.altBackground || '#f0f0f0';
+    this.compositeTitleBackground = this.compositeTitleBackground || this.mainBkg;
+    this.compositeBorder = this.compositeBorder || this.nodeBorder;
+    this.innerEndBackground = this.nodeBorder;
+    this.errorBkgColor = this.errorBkgColor || this.tertiaryColor;
+    this.errorTextColor = this.errorTextColor || this.tertiaryTextColor;
+    this.transitionColor = this.transitionColor || this.lineColor;
+    this.specialStateColor = this.lineColor;
+
+    /* Color Scale */
+    /* Each color-set will have a background, a foreground and a border color */
+    this.cScale0 = this.cScale0 || this.primaryColor;
+    this.cScale1 = this.cScale1 || this.secondaryColor;
+    this.cScale2 = this.cScale2 || this.tertiaryColor;
+    this.cScale3 = this.cScale3 || adjust(this.primaryColor, { h: 30 });
+    this.cScale4 = this.cScale4 || adjust(this.primaryColor, { h: 60 });
+    this.cScale5 = this.cScale5 || adjust(this.primaryColor, { h: 90 });
+    this.cScale6 = this.cScale6 || adjust(this.primaryColor, { h: 120 });
+    this.cScale7 = this.cScale7 || adjust(this.primaryColor, { h: 150 });
+    this.cScale8 = this.cScale8 || adjust(this.primaryColor, { h: 210, l: 150 });
+    this.cScale9 = this.cScale9 || adjust(this.primaryColor, { h: 270 });
+    this.cScale10 = this.cScale10 || adjust(this.primaryColor, { h: 300 });
+    this.cScale11 = this.cScale11 || adjust(this.primaryColor, { h: 330 });
+    if (this.darkMode) {
+      for (let i = 0; i < this.THEME_COLOR_LIMIT; i++) {
+        this['cScale' + i] = darken(this['cScale' + i], 75);
+      }
+    } else {
+      for (let i = 0; i < this.THEME_COLOR_LIMIT; i++) {
+        this['cScale' + i] = darken(this['cScale' + i], 25);
+      }
+    }
+
+    // Setup the inverted color for the set
+    for (let i = 0; i < this.THEME_COLOR_LIMIT; i++) {
+      this['cScaleInv' + i] = this['cScaleInv' + i] || invert(this['cScale' + i]);
+    }
+    // Setup the peer color for the set, useful for borders
+    for (let i = 0; i < this.THEME_COLOR_LIMIT; i++) {
+      if (this.darkMode) {
+        this['cScalePeer' + i] = this['cScalePeer' + i] || lighten(this['cScale' + i], 10);
+      } else {
+        this['cScalePeer' + i] = this['cScalePeer' + i] || darken(this['cScale' + i], 10);
+      }
+    }
+
+    // Setup the label color for the set
+    this.scaleLabelColor = this.scaleLabelColor || this.labelTextColor;
+
+    for (let i = 0; i < this.THEME_COLOR_LIMIT; i++) {
+      this['cScaleLabel' + i] = this['cScaleLabel' + i] || this.scaleLabelColor;
+    }
+
+    const multiplier = this.darkMode ? -4 : -1;
+    for (let i = 0; i < 5; i++) {
+      this['surface' + i] =
+        this['surface' + i] ||
+        adjust(this.mainBkg, { h: 180, s: -15, l: multiplier * (5 + i * 3) });
+      this['surfacePeer' + i] =
+        this['surfacePeer' + i] ||
+        adjust(this.mainBkg, { h: 180, s: -15, l: multiplier * (8 + i * 3) });
+    }
+
+    /* class */
+    this.classText = this.classText || this.textColor;
+
+    /* user-journey */
+    this.fillType0 = this.fillType0 || this.primaryColor;
+    this.fillType1 = this.fillType1 || this.secondaryColor;
+    this.fillType2 = this.fillType2 || adjust(this.primaryColor, { h: 64 });
+    this.fillType3 = this.fillType3 || adjust(this.secondaryColor, { h: 64 });
+    this.fillType4 = this.fillType4 || adjust(this.primaryColor, { h: -64 });
+    this.fillType5 = this.fillType5 || adjust(this.secondaryColor, { h: -64 });
+    this.fillType6 = this.fillType6 || adjust(this.primaryColor, { h: 128 });
+    this.fillType7 = this.fillType7 || adjust(this.secondaryColor, { h: 128 });
+
+    /* pie */
+    this.pie1 = this.pie1 || this.primaryColor;
+    this.pie2 = this.pie2 || this.secondaryColor;
+    this.pie3 = this.pie3 || this.tertiaryColor;
+    this.pie4 = this.pie4 || adjust(this.primaryColor, { l: -10 });
+    this.pie5 = this.pie5 || adjust(this.secondaryColor, { l: -10 });
+    this.pie6 = this.pie6 || adjust(this.tertiaryColor, { l: -10 });
+    this.pie7 = this.pie7 || adjust(this.primaryColor, { h: +60, l: -10 });
+    this.pie8 = this.pie8 || adjust(this.primaryColor, { h: -60, l: -10 });
+    this.pie9 = this.pie9 || adjust(this.primaryColor, { h: 120, l: 0 });
+    this.pie10 = this.pie10 || adjust(this.primaryColor, { h: +60, l: -20 });
+    this.pie11 = this.pie11 || adjust(this.primaryColor, { h: -60, l: -20 });
+    this.pie12 = this.pie12 || adjust(this.primaryColor, { h: 120, l: -10 });
+    this.pieTitleTextSize = this.pieTitleTextSize || '25px';
+    this.pieTitleTextColor = this.pieTitleTextColor || this.taskTextDarkColor;
+    this.pieSectionTextSize = this.pieSectionTextSize || '17px';
+    this.pieSectionTextColor = this.pieSectionTextColor || this.textColor;
+    this.pieLegendTextSize = this.pieLegendTextSize || '17px';
+    this.pieLegendTextColor = this.pieLegendTextColor || this.taskTextDarkColor;
+    this.pieStrokeColor = this.pieStrokeColor || 'black';
+    this.pieStrokeWidth = this.pieStrokeWidth || '2px';
+    this.pieOuterStrokeWidth = this.pieOuterStrokeWidth || '2px';
+    this.pieOuterStrokeColor = this.pieOuterStrokeColor || 'black';
+    this.pieOpacity = this.pieOpacity || '0.7';
+
+    /* quadrant-graph */
+    this.quadrant1Fill = this.quadrant1Fill || this.primaryColor;
+    this.quadrant2Fill = this.quadrant2Fill || adjust(this.primaryColor, { r: 5, g: 5, b: 5 });
+    this.quadrant3Fill = this.quadrant3Fill || adjust(this.primaryColor, { r: 10, g: 10, b: 10 });
+    this.quadrant4Fill = this.quadrant4Fill || adjust(this.primaryColor, { r: 15, g: 15, b: 15 });
+    this.quadrant1TextFill = this.quadrant1TextFill || this.primaryTextColor;
+    this.quadrant2TextFill =
+      this.quadrant2TextFill || adjust(this.primaryTextColor, { r: -5, g: -5, b: -5 });
+    this.quadrant3TextFill =
+      this.quadrant3TextFill || adjust(this.primaryTextColor, { r: -10, g: -10, b: -10 });
+    this.quadrant4TextFill =
+      this.quadrant4TextFill || adjust(this.primaryTextColor, { r: -15, g: -15, b: -15 });
+    this.quadrantPointFill =
+      this.quadrantPointFill || isDark(this.quadrant1Fill)
+        ? lighten(this.quadrant1Fill)
+        : darken(this.quadrant1Fill);
+    this.quadrantPointTextFill = this.quadrantPointTextFill || this.primaryTextColor;
+    this.quadrantXAxisTextFill = this.quadrantXAxisTextFill || this.primaryTextColor;
+    this.quadrantYAxisTextFill = this.quadrantYAxisTextFill || this.primaryTextColor;
+    this.quadrantInternalBorderStrokeFill =
+      this.quadrantInternalBorderStrokeFill || this.primaryBorderColor;
+    this.quadrantExternalBorderStrokeFill =
+      this.quadrantExternalBorderStrokeFill || this.primaryBorderColor;
+    this.quadrantTitleFill = this.quadrantTitleFill || this.primaryTextColor;
+
+    /* xychart */
+    this.xyChart = {
+      backgroundColor: this.xyChart?.backgroundColor || this.background,
+      titleColor: this.xyChart?.titleColor || this.primaryTextColor,
+      xAxisTitleColor: this.xyChart?.xAxisTitleColor || this.primaryTextColor,
+      xAxisLabelColor: this.xyChart?.xAxisLabelColor || this.primaryTextColor,
+      xAxisTickColor: this.xyChart?.xAxisTickColor || this.primaryTextColor,
+      xAxisLineColor: this.xyChart?.xAxisLineColor || this.primaryTextColor,
+      yAxisTitleColor: this.xyChart?.yAxisTitleColor || this.primaryTextColor,
+      yAxisLabelColor: this.xyChart?.yAxisLabelColor || this.primaryTextColor,
+      yAxisTickColor: this.xyChart?.yAxisTickColor || this.primaryTextColor,
+      yAxisLineColor: this.xyChart?.yAxisLineColor || this.primaryTextColor,
+      plotColorPalette:
+        this.xyChart?.plotColorPalette ||
+        '#FFF4DD,#FFD8B1,#FFA07A,#ECEFF1,#D6DBDF,#C3E0A8,#FFB6A4,#FFD74D,#738FA7,#FFFFF0',
+    };
+
+    /* requirement-diagram */
+    this.requirementBackground = this.requirementBackground || this.primaryColor;
+    this.requirementBorderColor = this.requirementBorderColor || this.primaryBorderColor;
+    this.requirementBorderSize = this.requirementBorderSize || '1';
+    this.requirementTextColor = this.requirementTextColor || this.primaryTextColor;
+    this.relationColor = this.relationColor || this.lineColor;
+    this.relationLabelBackground =
+      this.relationLabelBackground ||
+      (this.darkMode ? darken(this.secondaryColor, 30) : this.secondaryColor);
+    this.relationLabelColor = this.relationLabelColor || this.actorTextColor;
+
+    /* git */
+    this.git0 = this.git0 || this.primaryColor;
+    this.git1 = this.git1 || this.secondaryColor;
+    this.git2 = this.git2 || this.tertiaryColor;
+    this.git3 = this.git3 || adjust(this.primaryColor, { h: -30 });
+    this.git4 = this.git4 || adjust(this.primaryColor, { h: -60 });
+    this.git5 = this.git5 || adjust(this.primaryColor, { h: -90 });
+    this.git6 = this.git6 || adjust(this.primaryColor, { h: +60 });
+    this.git7 = this.git7 || adjust(this.primaryColor, { h: +120 });
+    if (this.darkMode) {
+      this.git0 = lighten(this.git0, 25);
+      this.git1 = lighten(this.git1, 25);
+      this.git2 = lighten(this.git2, 25);
+      this.git3 = lighten(this.git3, 25);
+      this.git4 = lighten(this.git4, 25);
+      this.git5 = lighten(this.git5, 25);
+      this.git6 = lighten(this.git6, 25);
+      this.git7 = lighten(this.git7, 25);
+    } else {
+      this.git0 = darken(this.git0, 25);
+      this.git1 = darken(this.git1, 25);
+      this.git2 = darken(this.git2, 25);
+      this.git3 = darken(this.git3, 25);
+      this.git4 = darken(this.git4, 25);
+      this.git5 = darken(this.git5, 25);
+      this.git6 = darken(this.git6, 25);
+      this.git7 = darken(this.git7, 25);
+    }
+    this.gitInv0 = this.gitInv0 || invert(this.git0);
+    this.gitInv1 = this.gitInv1 || invert(this.git1);
+    this.gitInv2 = this.gitInv2 || invert(this.git2);
+    this.gitInv3 = this.gitInv3 || invert(this.git3);
+    this.gitInv4 = this.gitInv4 || invert(this.git4);
+    this.gitInv5 = this.gitInv5 || invert(this.git5);
+    this.gitInv6 = this.gitInv6 || invert(this.git6);
+    this.gitInv7 = this.gitInv7 || invert(this.git7);
+    this.branchLabelColor =
+      this.branchLabelColor || (this.darkMode ? 'black' : this.labelTextColor);
+    this.gitBranchLabel0 = this.gitBranchLabel0 || this.branchLabelColor;
+    this.gitBranchLabel1 = this.gitBranchLabel1 || this.branchLabelColor;
+    this.gitBranchLabel2 = this.gitBranchLabel2 || this.branchLabelColor;
+    this.gitBranchLabel3 = this.gitBranchLabel3 || this.branchLabelColor;
+    this.gitBranchLabel4 = this.gitBranchLabel4 || this.branchLabelColor;
+    this.gitBranchLabel5 = this.gitBranchLabel5 || this.branchLabelColor;
+    this.gitBranchLabel6 = this.gitBranchLabel6 || this.branchLabelColor;
+    this.gitBranchLabel7 = this.gitBranchLabel7 || this.branchLabelColor;
+
+    this.tagLabelColor = this.tagLabelColor || this.primaryTextColor;
+    this.tagLabelBackground = this.tagLabelBackground || this.primaryColor;
+    this.tagLabelBorder = this.tagBorder || this.primaryBorderColor;
+    this.tagLabelFontSize = this.tagLabelFontSize || '10px';
+    this.commitLabelColor = this.commitLabelColor || this.secondaryTextColor;
+    this.commitLabelBackground = this.commitLabelBackground || this.secondaryColor;
+    this.commitLabelFontSize = this.commitLabelFontSize || '10px';
+
+    /* -------------------------------------------------- */
+    /* EntityRelationship diagrams                        */
+
+    this.attributeBackgroundColorOdd =
+      this.attributeBackgroundColorOdd || oldAttributeBackgroundColorOdd;
+    this.attributeBackgroundColorEven =
+      this.attributeBackgroundColorEven || oldAttributeBackgroundColorEven;
+    /* -------------------------------------------------- */
+  }
+  calculate(overrides) {
+    if (typeof overrides !== 'object') {
+      // Calculate colors form base colors
+      this.updateColors();
+      return;
+    }
+
+    const keys = Object.keys(overrides);
+
+    // Copy values from overrides, this is mainly for base colors
+    keys.forEach((k) => {
+      this[k] = overrides[k];
+    });
+
+    // Calculate colors form base colors
+    this.updateColors();
+    // Copy values from overrides again in case of an override of derived value
+    keys.forEach((k) => {
+      this[k] = overrides[k];
+    });
+  }
+}
+
+export const getThemeVariables = (userOverrides) => {
+  const theme = new Theme();
+  theme.calculate(userOverrides);
+  return theme;
+};