Add Nord color themes

Both light and dark variants. Needs further polishing, but still pretty usable.
This commit is contained in:
mkpaz 2022-08-21 17:00:41 +04:00
parent 996385ccd3
commit a7255949ce
8 changed files with 263 additions and 8 deletions

@ -0,0 +1,33 @@
/* SPDX-License-Identifier: MIT */
package atlantafx.base.theme;
import java.net.URI;
import java.util.Set;
public class NordDark extends AbstractTheme {
public NordDark() {}
public NordDark(URI... stylesheets) {
super(stylesheets);
}
public NordDark(Set<URI> stylesheets) {
super(stylesheets);
}
@Override
public String getName() {
return "Nord Dark";
}
@Override
public String getUserAgentStylesheet() {
return "/atlantafx/base/theme/nord-dark.css";
}
@Override
public boolean isDarkMode() {
return true;
}
}

@ -0,0 +1,33 @@
/* SPDX-License-Identifier: MIT */
package atlantafx.base.theme;
import java.net.URI;
import java.util.Set;
public class NordLight extends AbstractTheme {
public NordLight() {}
public NordLight(URI... stylesheets) {
super(stylesheets);
}
public NordLight(Set<URI> stylesheets) {
super(stylesheets);
}
@Override
public String getName() {
return "Nord Light";
}
@Override
public String getUserAgentStylesheet() {
return "/atlantafx/base/theme/nord-light.css";
}
@Override
public boolean isDarkMode() {
return false;
}
}

@ -3,7 +3,6 @@ package atlantafx.sampler.page;
import atlantafx.base.controls.Spacer; import atlantafx.base.controls.Spacer;
import atlantafx.base.theme.Styles; import atlantafx.base.theme.Styles;
import atlantafx.sampler.theme.HighlightJSTheme;
import atlantafx.sampler.theme.ThemeManager; import atlantafx.sampler.theme.ThemeManager;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.event.EventHandler; import javafx.event.EventHandler;
@ -135,10 +134,9 @@ public abstract class AbstractPage extends BorderPane implements Page {
Objects.requireNonNull(stream, "Missing source file '" + sourceFileName + "';"); Objects.requireNonNull(stream, "Missing source file '" + sourceFileName + "';");
// set syntax highlight theme according to JavaFX theme // set syntax highlight theme according to JavaFX theme
var highlightJSTheme = ThemeManager.getInstance().getTheme().isDarkMode() ? ThemeManager tm = ThemeManager.getInstance();
HighlightJSTheme.githubDark() : System.out.println(tm.getMatchingHighlightJSTheme(tm.getTheme()).getBackground());
HighlightJSTheme.githubLight(); codeViewer.setContent(stream, tm.getMatchingHighlightJSTheme(tm.getTheme()));
codeViewer.setContent(stream, highlightJSTheme);
graphic.setIconCode(ICON_SAMPLE); graphic.setIconCode(ICON_SAMPLE);
codeViewerWrapper.toFront(); codeViewerWrapper.toFront();

@ -30,4 +30,18 @@ public class HighlightJSTheme {
var bg = "#0d1117"; var bg = "#0d1117";
return new HighlightJSTheme(css, bg); return new HighlightJSTheme(css, bg);
} }
public static HighlightJSTheme nordLight() {
// there's no Nord light theme,
// below is "stackoverflow-light" theme with changed background
var css = "*/.hljs{color:#2f3337;background:#ECEFF4}.hljs-subst{color:#2f3337}.hljs-comment{color:#656e77}.hljs-attr,.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-section,.hljs-selector-tag{color:#015692}.hljs-attribute{color:#803378}.hljs-name,.hljs-number,.hljs-quote,.hljs-selector-id,.hljs-template-tag,.hljs-type{color:#b75501}.hljs-selector-class{color:#015692}.hljs-link,.hljs-regexp,.hljs-selector-attr,.hljs-string,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#54790d}.hljs-meta,.hljs-selector-pseudo{color:#015692}.hljs-built_in,.hljs-literal,.hljs-title{color:#b75501}.hljs-bullet,.hljs-code{color:#535a60}.hljs-meta .hljs-string{color:#54790d}.hljs-deletion{color:#c02d2e}.hljs-addition{color:#2f6f44}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}";
var bg = "ECEFF4";
return new HighlightJSTheme(css, bg);
}
public static HighlightJSTheme nordDark() {
var css = "pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#2e3440}.hljs,.hljs-subst{color:#d8dee9}.hljs-selector-tag{color:#81a1c1}.hljs-selector-id{color:#8fbcbb;font-weight:700}.hljs-selector-attr,.hljs-selector-class{color:#8fbcbb}.hljs-property,.hljs-selector-pseudo{color:#88c0d0}.hljs-addition{background-color:rgba(163,190,140,.5)}.hljs-deletion{background-color:rgba(191,97,106,.5)}.hljs-built_in,.hljs-class,.hljs-type{color:#8fbcbb}.hljs-function,.hljs-function>.hljs-title,.hljs-title.hljs-function{color:#88c0d0}.hljs-keyword,.hljs-literal,.hljs-symbol{color:#81a1c1}.hljs-number{color:#b48ead}.hljs-regexp{color:#ebcb8b}.hljs-string{color:#a3be8c}.hljs-title{color:#8fbcbb}.hljs-params{color:#d8dee9}.hljs-bullet{color:#81a1c1}.hljs-code{color:#8fbcbb}.hljs-emphasis{font-style:italic}.hljs-formula{color:#8fbcbb}.hljs-strong{font-weight:700}.hljs-link:hover{text-decoration:underline}.hljs-comment,.hljs-quote{color:#4c566a}.hljs-doctag{color:#8fbcbb}.hljs-meta,.hljs-meta .hljs-keyword{color:#5e81ac}.hljs-meta .hljs-string{color:#a3be8c}.hljs-attr{color:#8fbcbb}.hljs-attribute{color:#d8dee9}.hljs-name{color:#81a1c1}.hljs-section{color:#88c0d0}.hljs-tag{color:#81a1c1}.hljs-template-variable,.hljs-variable{color:#d8dee9}.hljs-template-tag{color:#5e81ac}.language-abnf .hljs-attribute{color:#88c0d0}.language-abnf .hljs-symbol{color:#ebcb8b}.language-apache .hljs-attribute{color:#88c0d0}.language-apache .hljs-section{color:#81a1c1}.language-arduino .hljs-built_in{color:#88c0d0}.language-aspectj .hljs-meta{color:#d08770}.language-aspectj>.hljs-title{color:#88c0d0}.language-bnf .hljs-attribute{color:#8fbcbb}.language-clojure .hljs-name{color:#88c0d0}.language-clojure .hljs-symbol{color:#ebcb8b}.language-coq .hljs-built_in{color:#88c0d0}.language-cpp .hljs-meta .hljs-string{color:#8fbcbb}.language-css .hljs-built_in{color:#88c0d0}.language-css .hljs-keyword{color:#d08770}.language-diff .hljs-meta,.language-ebnf .hljs-attribute{color:#8fbcbb}.language-glsl .hljs-built_in{color:#88c0d0}.language-groovy .hljs-meta:not(:first-child),.language-haxe .hljs-meta,.language-java .hljs-meta{color:#d08770}.language-ldif .hljs-attribute{color:#8fbcbb}.language-lisp .hljs-name,.language-lua .hljs-built_in,.language-moonscript .hljs-built_in,.language-nginx .hljs-attribute{color:#88c0d0}.language-nginx .hljs-section{color:#5e81ac}.language-pf .hljs-built_in,.language-processing .hljs-built_in{color:#88c0d0}.language-scss .hljs-keyword,.language-stylus .hljs-keyword{color:#81a1c1}.language-swift .hljs-meta{color:#d08770}.language-vim .hljs-built_in{color:#88c0d0;font-style:italic}.language-yaml .hljs-meta{color:#d08770}";
var bg = "#2E3440";
return new HighlightJSTheme(css, bg);
}
} }

@ -1,11 +1,11 @@
/* SPDX-License-Identifier: MIT */ /* SPDX-License-Identifier: MIT */
package atlantafx.sampler.theme; package atlantafx.sampler.theme;
import atlantafx.sampler.Resources;
import atlantafx.base.theme.PrimerDark; import atlantafx.base.theme.PrimerDark;
import atlantafx.base.theme.PrimerLight; import atlantafx.base.theme.PrimerLight;
import atlantafx.base.theme.Theme; import atlantafx.base.theme.Theme;
import atlantafx.sampler.Launcher; import atlantafx.sampler.Launcher;
import atlantafx.sampler.Resources;
import javafx.application.Application; import javafx.application.Application;
import javafx.scene.Scene; import javafx.scene.Scene;
@ -62,6 +62,14 @@ public final class ThemeManager {
Resources.getResource("theme-test/primer-dark.css"), Resources.getResource("theme-test/primer-dark.css"),
appStylesheets appStylesheets
), true)); ), true));
themes.add(new ExternalTheme("Nord Light", DUMMY_STYLESHEET, merge(
Resources.getResource("theme-test/nord-light.css"),
appStylesheets
), false));
themes.add(new ExternalTheme("Nord Dark", DUMMY_STYLESHEET, merge(
Resources.getResource("theme-test/nord-dark.css"),
appStylesheets
), true));
} else { } else {
themes.add(new PrimerLight(appStylesheets)); themes.add(new PrimerLight(appStylesheets));
themes.add(new PrimerDark(appStylesheets)); themes.add(new PrimerDark(appStylesheets));
@ -86,6 +94,13 @@ public final class ThemeManager {
currentFontSize = fontSize; currentFontSize = fontSize;
} }
public HighlightJSTheme getMatchingHighlightJSTheme(Theme theme) {
Objects.requireNonNull(theme);
if ("Nord Light".equals(theme.getName())) { return HighlightJSTheme.nordLight(); }
if ("Nord Dark".equals(theme.getName())) { return HighlightJSTheme.nordDark(); }
return theme.isDarkMode() ? HighlightJSTheme.githubDark() : HighlightJSTheme.githubLight();
}
@SafeVarargs @SafeVarargs
private <T> Set<T> merge(T first, T... arr) { private <T> Set<T> merge(T first, T... arr) {
var set = new LinkedHashSet<T>(); var set = new LinkedHashSet<T>();

@ -26,6 +26,8 @@
<args> <args>
<arg>${scss.inputDir}/primer-light.scss:${css.outputDir}/primer-light.css</arg> <arg>${scss.inputDir}/primer-light.scss:${css.outputDir}/primer-light.css</arg>
<arg>${scss.inputDir}/primer-dark.scss:${css.outputDir}/primer-dark.css</arg> <arg>${scss.inputDir}/primer-dark.scss:${css.outputDir}/primer-dark.css</arg>
<arg>${scss.inputDir}/nord-light.scss:${css.outputDir}/nord-light.css</arg>
<arg>${scss.inputDir}/nord-dark.scss:${css.outputDir}/nord-dark.css</arg>
<arg>--no-source-map</arg> <arg>--no-source-map</arg>
</args> </args>
</configuration> </configuration>

86
styles/src/nord-dark.scss Executable file

@ -0,0 +1,86 @@
// SPDX-License-Identifier: MIT
// Nord color palette
// informational, not commented to display color preview
$nord0: #2E3440;
$nord1: #3B4252;
$nord1: #434C5E;
$nord3: #4C566A;
$nord4: #D8DEE9;
$nord5: #E5E9F0;
$nord6: #ECEFF4;
$nord7: #8FBCBB;
$nord8: #88C0D0;
$nord9: #81A1C1;
$nord10: #5E81AC;
$nord11: #BF616A;
$nord12: #D08770;
$nord13: #EBCB8B;
$nord14: #A3BE8C;
$nord16: #B48EAD;
@forward "settings/palette" with (
$fg-default: #ECEFF4,
$fg-muted: #DFE4ED,
$fg-subtle: #CFD7E3,
$fg-onEmphasis: #ECEFF4,
$canvas-default: #2E3440,
$canvas-overlay: #2E3440,
$canvas-inset: #3B4252,
$canvas-subtle: #3B4252,
$border-default: #4C566A,
$border-muted: #40495A,
$border-subtle: #3B4353,
$neutral-emphasisPlus: #6e7681,
$neutral-emphasis: #6e7681,
$neutral-muted: rgba(110, 118, 129, 0.4),
$neutral-subtle: rgba(110, 118, 129, 0.1),
$accent-fg: #81A1C1,
$accent-emphasis: #5E81AC,
$accent-muted: rgba(81, 109, 157, 0.3),
$accent-subtle: rgba(81, 109, 157, 0.1),
$success-fg: #A3BE8C,
$success-emphasis: #5A7C4F,
$success-muted: rgba(163, 190, 140, 0.4),
$success-subtle: rgba(163, 190, 140, 0.15),
$warning-fg: #D08770,
$warning-emphasis: #AA5338,
$warning-muted: rgba(170, 83, 56, 0.4),
$warning-subtle: rgba(170, 83, 56, 0.15),
$danger-fg: #CA7C83,
$danger-emphasis: #BF616A,
$danger-muted: rgba(178, 72, 82, 0.4),
$danger-subtle: rgba(178, 72, 82, 0.15)
);
@forward "settings/config" with (
$darkMode: true,
$color-delta-hover: 15%,
$color-delta-active: 20%
);
@use "general";
@forward "components/slider" as slider-* with (
$thumb-color: -color-fg-subtle,
$thumb-color-border: -color-fg-subtle
);
@forward "components/titled-pane" as titled-pane-* with (
$elevation-color: -color-bg-inset
);
@forward "components/tooltip" as tooltip-* with (
$color-bg: -color-bg-inset,
$color-fg: -color-fg-default
);
@use "components";

74
styles/src/nord-light.scss Executable file

@ -0,0 +1,74 @@
// SPDX-License-Identifier: MIT
// Nord is officially only supports dark theme:
// https://github.com/arcticicestudio/nord/issues/46
// Nord color palette
// informational, not commented to display color preview
$nord0: #2E3440;
$nord1: #3B4252;
$nord1: #434C5E;
$nord3: #4C566A;
$nord4: #D8DEE9;
$nord5: #E5E9F0;
$nord6: #ECEFF4;
$nord7: #8FBCBB;
$nord8: #88C0D0;
$nord9: #81A1C1;
$nord10: #5E81AC;
$nord11: #BF616A;
$nord12: #D08770;
$nord13: #EBCB8B;
$nord14: #A3BE8C;
$nord16: #B48EAD;
@forward "settings/palette" with (
$fg-default: #2E3440,
$fg-muted: #4C566A,
$fg-subtle: #5A657C,
$fg-onEmphasis: #ECEFF4,
$canvas-default: #ECEFF4,
$canvas-overlay: #ECEFF4,
$canvas-inset: #D8DEE9,
$canvas-subtle: #E5E9F0,
$border-default: rgba(181, 188, 201, 1),
$border-muted: rgba(181, 188, 201, 0.75),
$border-subtle: rgba(181, 188, 201, 0.6),
$neutral-emphasisPlus: #24292f,
$neutral-emphasis: #6e7781,
$neutral-muted: rgba(175, 184, 193, 0.2),
$neutral-subtle: rgba(234, 238, 242, 0.5),
$accent-fg: #5E81AC,
$accent-emphasis: #5E81AC,
$accent-muted: rgba(81, 109, 157, 0.3),
$accent-subtle: rgba(81, 109, 157, 0.1),
$success-fg: #67864c,
$success-emphasis: #67864c,
$success-muted: rgba(103, 134, 76, 0.4),
$success-subtle: rgba(103, 134, 76, 0.15),
$warning-fg: #C26446,
$warning-emphasis: #C26446,
$warning-muted: rgba(170, 83, 56, 0.4),
$warning-subtle: rgba(170, 83, 56, 0.15),
$danger-fg: #BF616A,
$danger-emphasis: #BF616A,
$danger-muted: rgba(178, 72, 82, 0.4),
$danger-subtle: rgba(178, 72, 82, 0.15)
);
@forward "settings/config" with (
$color-delta-hover: 5%,
$color-delta-active: 10%
);
@use "general";
@use "components";