diff --git a/build-logic/src/main/kotlin/org.jabref.gradle.base.dependency-rules.gradle.kts b/build-logic/src/main/kotlin/org.jabref.gradle.base.dependency-rules.gradle.kts index ffb6c26b3c8..0605f581954 100644 --- a/build-logic/src/main/kotlin/org.jabref.gradle.base.dependency-rules.gradle.kts +++ b/build-logic/src/main/kotlin/org.jabref.gradle.base.dependency-rules.gradle.kts @@ -472,9 +472,7 @@ extraJavaModuleInfo { preserveExisting() exports("com.sun.javafx.scene") opens("com.sun.javafx.application", "org.testfx") - opens("com.sun.javafx.tk.quantum", "com.pixelduke.fxthemes") opens("javafx.scene", "org.controlsfx.controls") - opens("javafx.stage", "com.pixelduke.fxthemes") } module("org.controlsfx:controlsfx", "org.controlsfx.controls") { diff --git a/jabgui/src/main/java/module-info.java b/jabgui/src/main/java/module-info.java index 2b16cdc308a..1b8daa0135d 100644 --- a/jabgui/src/main/java/module-info.java +++ b/jabgui/src/main/java/module-info.java @@ -172,7 +172,6 @@ // region: other libraries (alphabetically) // requires cuid; requires com.dlsc.pdfviewfx; - requires com.pixelduke.fxthemes; // requires com.sun.jna; // requires dd.plist; requires static io.github.eadr; diff --git a/jabgui/src/main/java/org/jabref/gui/WorkspacePreferences.java b/jabgui/src/main/java/org/jabref/gui/WorkspacePreferences.java index a2dc1deccf2..adf8c3a9702 100644 --- a/jabgui/src/main/java/org/jabref/gui/WorkspacePreferences.java +++ b/jabgui/src/main/java/org/jabref/gui/WorkspacePreferences.java @@ -55,8 +55,8 @@ private WorkspacePreferences() { Language.getLanguageFor(Locale.getDefault().getLanguage()), // Default language false, // Default font size override 9, // Default font size - new Theme(Theme.BASE_CSS), // Default theme - false, // Default theme sync with OS + Theme.system(), // Default theme + true, // Default theme sync with OS true, // Default open last edited true, // Default show advanced hints true, // Default confirm delete diff --git a/jabgui/src/main/java/org/jabref/gui/preferences/JabRefGuiPreferences.java b/jabgui/src/main/java/org/jabref/gui/preferences/JabRefGuiPreferences.java index 19414826a1a..180be36d009 100644 --- a/jabgui/src/main/java/org/jabref/gui/preferences/JabRefGuiPreferences.java +++ b/jabgui/src/main/java/org/jabref/gui/preferences/JabRefGuiPreferences.java @@ -583,7 +583,7 @@ private WorkspacePreferences getWorkspacePreferencesFromBackingStore(WorkspacePr getLanguage(), getBoolean(OVERRIDE_DEFAULT_FONT_SIZE, defaults.shouldOverrideDefaultFontSize()), getInt(MAIN_FONT_SIZE, defaults.getMainFontSize()), - new Theme(get(THEME, Theme.BASE_CSS)), + new Theme(get(THEME, Theme.SYSTEM)), getBoolean(THEME_SYNC_OS, defaults.shouldThemeSyncOs()), getBoolean(OPEN_LAST_EDITED, defaults.shouldOpenLastEdited()), getBoolean(SHOW_ADVANCED_HINTS, defaults.shouldShowAdvancedHints()), diff --git a/jabgui/src/main/java/org/jabref/gui/preferences/general/GeneralTab.java b/jabgui/src/main/java/org/jabref/gui/preferences/general/GeneralTab.java index 7aca7da418f..30f133045e5 100644 --- a/jabgui/src/main/java/org/jabref/gui/preferences/general/GeneralTab.java +++ b/jabgui/src/main/java/org/jabref/gui/preferences/general/GeneralTab.java @@ -166,6 +166,7 @@ public void initialize() { validationVisualizer.initVisualization(viewModel.languageServerPortValidationStatus(), languageServerPort); validationVisualizer.initVisualization(viewModel.fontSizeValidationStatus(), fontSize); validationVisualizer.initVisualization(viewModel.customPathToThemeValidationStatus(), customThemePath); + validationVisualizer.initVisualization(viewModel.themeValidationStatus(), theme); }); remoteServer.selectedProperty().bindBidirectional(viewModel.remoteServerProperty()); diff --git a/jabgui/src/main/java/org/jabref/gui/preferences/general/GeneralTabViewModel.java b/jabgui/src/main/java/org/jabref/gui/preferences/general/GeneralTabViewModel.java index 5a1978ef8fd..fafc7c31d12 100644 --- a/jabgui/src/main/java/org/jabref/gui/preferences/general/GeneralTabViewModel.java +++ b/jabgui/src/main/java/org/jabref/gui/preferences/general/GeneralTabViewModel.java @@ -5,6 +5,7 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Optional; import javafx.beans.property.BooleanProperty; @@ -65,7 +66,14 @@ public class GeneralTabViewModel implements PreferenceTabViewModel { new ReadOnlyListWrapper<>(FXCollections.observableArrayList(ThemeTypes.values())); private final ObjectProperty selectedThemeProperty = new SimpleObjectProperty<>(); - private final BooleanProperty themeSyncOsProperty = new SimpleBooleanProperty(); + private final BooleanProperty themeSyncOsProperty = new SimpleBooleanProperty() { + @Override + protected void invalidated() { + if (themeSyncOsProperty.get()) { + selectedThemeProperty.set(null); + } + } + }; // init with empty string to avoid npe in accessing private final StringProperty customPathToThemeProperty = new SimpleStringProperty(""); @@ -103,6 +111,7 @@ public class GeneralTabViewModel implements PreferenceTabViewModel { private final Validator fontSizeValidator; private final Validator customPathToThemeValidator; + private final Validator themeValidator; private final List restartWarning = new ArrayList<>(); private final BooleanProperty remoteServerProperty = new SimpleBooleanProperty(); @@ -157,6 +166,14 @@ public GeneralTabViewModel(DialogService dialogService, Localization.lang("Visual theme"), Localization.lang("Please specify a css theme file.")))); + themeValidator = new FunctionBasedValidator<>( + selectedThemeProperty, + Objects::nonNull, + ValidationMessage.error("%s > %s %n %n %s".formatted( + Localization.lang("General"), + Localization.lang("Visual theme"), + Localization.lang("Please set a theme.")))); + remotePortValidator = new FunctionBasedValidator<>( remotePortProperty, RemoteUtil::isStringUserPort, @@ -194,17 +211,17 @@ public ValidationStatus languageServerPortValidationStatus() { public void setValues() { selectedLanguageProperty.setValue(workspacePreferences.getLanguage()); - // The light theme is in fact the absence of any theme modifying 'base.css'. Another embedded theme like - // 'dark.css', stored in the classpath, can be introduced in {@link org.jabref.gui.theme.Theme}. switch (workspacePreferences.getTheme().getType()) { - case DEFAULT -> + case LIGHT -> selectedThemeProperty.setValue(ThemeTypes.LIGHT); - case EMBEDDED -> + case DARK -> selectedThemeProperty.setValue(ThemeTypes.DARK); case CUSTOM -> { selectedThemeProperty.setValue(ThemeTypes.CUSTOM); customPathToThemeProperty.setValue(workspacePreferences.getTheme().getName()); } + case SYSTEM -> + selectedThemeProperty.setValue(null); } themeSyncOsProperty.setValue(workspacePreferences.shouldThemeSyncOs()); @@ -250,15 +267,21 @@ public void storeSettings() { workspacePreferences.setShouldOverrideDefaultFontSize(fontOverrideProperty.getValue()); workspacePreferences.setMainFontSize(Integer.parseInt(fontSizeProperty.getValue())); - switch (selectedThemeProperty.get()) { - case LIGHT -> - workspacePreferences.setTheme(Theme.light()); - case DARK -> - workspacePreferences.setTheme(Theme.dark()); - case CUSTOM -> - workspacePreferences.setTheme(Theme.custom(customPathToThemeProperty.getValue())); + boolean themeSyncOs = themeSyncOsProperty.getValue(); + workspacePreferences.setThemeSyncOs(themeSyncOs); + + if (themeSyncOs) { + workspacePreferences.setTheme(Theme.system()); + } else { + switch (selectedThemeProperty.get()) { + case LIGHT -> + workspacePreferences.setTheme(Theme.light()); + case DARK -> + workspacePreferences.setTheme(Theme.dark()); + case CUSTOM -> + workspacePreferences.setTheme(Theme.custom(customPathToThemeProperty.getValue())); + } } - workspacePreferences.setThemeSyncOs(themeSyncOsProperty.getValue()); workspacePreferences.setOpenLastEdited(openLastStartupProperty.getValue()); workspacePreferences.setShowAdvancedHints(showAdvancedHintsProperty.getValue()); @@ -337,6 +360,10 @@ public ValidationStatus customPathToThemeValidationStatus() { return customPathToThemeValidator.getValidationStatus(); } + public ValidationStatus themeValidationStatus() { + return themeValidator.getValidationStatus(); + } + @Override public boolean validateSettings() { CompositeValidator validator = new CompositeValidator(); @@ -361,6 +388,10 @@ public boolean validateSettings() { validator.addValidators(customPathToThemeValidator); } + if (!themeSyncOsProperty.get() && selectedThemeProperty.getValue() == null) { + validator.addValidators(themeValidator); + } + ValidationStatus validationStatus = validator.getValidationStatus(); if (!validationStatus.isValid()) { validationStatus.getHighestMessage().ifPresent(message -> diff --git a/jabgui/src/main/java/org/jabref/gui/theme/Theme.java b/jabgui/src/main/java/org/jabref/gui/theme/Theme.java index 99ab6f71e5f..1528ea6968c 100644 --- a/jabgui/src/main/java/org/jabref/gui/theme/Theme.java +++ b/jabgui/src/main/java/org/jabref/gui/theme/Theme.java @@ -5,61 +5,70 @@ import org.jspecify.annotations.NonNull; -/// Represents one of three types of a css based Theme for JabRef: +/// Represents one of four types of a CSS-based Theme for JabRef: /// -/// The Default type of theme is the light theme (which is in fact the absence of any theme), the dark theme is currently -/// the only embedded theme and the custom themes, that can be created by loading a proper css file. +/// - System - Tightly coupled to the shouldThemeSyncOs setting, +/// meaning we do not want to override the theme at all +/// - Light - Ignore whatever the OS is set to and make JabRef use the light theme +/// - Dark - Ignore whatever the OS is set to and make JabRef use the dark theme +/// - Custom - CSS provided by the user public class Theme { public enum Type { - DEFAULT, EMBEDDED, CUSTOM + SYSTEM, LIGHT, DARK, CUSTOM } - public static final String BASE_CSS = "Base.css"; - public static final String EMBEDDED_DARK_CSS = "Dark.css"; + public static final String SYSTEM = ""; + + private static final String BASE_CSS = "Base.css"; + + private static final String LIGHT = "light"; + private static final String DARK = "dark"; private final Type type; private final String name; private final Optional additionalStylesheet; public Theme(@NonNull String name) { - if (name.isEmpty() || BASE_CSS.equalsIgnoreCase(name)) { + if (SYSTEM.equalsIgnoreCase(name)) { this.additionalStylesheet = Optional.empty(); - this.type = Type.DEFAULT; - this.name = ""; - } else if (EMBEDDED_DARK_CSS.equalsIgnoreCase(name)) { - this.additionalStylesheet = StyleSheet.create(EMBEDDED_DARK_CSS); - if (this.additionalStylesheet.isPresent()) { - this.type = Type.EMBEDDED; - this.name = EMBEDDED_DARK_CSS; - } else { - this.type = Type.DEFAULT; - this.name = ""; - } + this.type = Type.SYSTEM; + this.name = name; + } else if (LIGHT.equalsIgnoreCase(name)) { + this.additionalStylesheet = Optional.empty(); + this.type = Type.LIGHT; + this.name = name; + } else if (DARK.equalsIgnoreCase(name)) { + this.additionalStylesheet = Optional.empty(); + this.type = Type.DARK; + this.name = name; } else { this.additionalStylesheet = StyleSheet.create(name); if (this.additionalStylesheet.isPresent()) { this.type = Type.CUSTOM; - this.name = name; } else { - this.type = Type.DEFAULT; - this.name = ""; + this.type = Type.SYSTEM; } + this.name = name; } } public static Theme light() { - return new Theme(""); + return new Theme(LIGHT); } public static Theme dark() { - return new Theme(EMBEDDED_DARK_CSS); + return new Theme(DARK); } public static Theme custom(String name) { return new Theme(name); } + public static Theme system() { + return new Theme(SYSTEM); + } + /// @return the Theme type. Guaranteed to be non-null. public Type getType() { return type; @@ -108,4 +117,8 @@ public String toString() { ", name='" + name + '\'' + '}'; } + + public static StyleSheet getBaseStyleSheet() { + return StyleSheet.create(BASE_CSS).orElseThrow(); + } } diff --git a/jabgui/src/main/java/org/jabref/gui/theme/ThemeManager.java b/jabgui/src/main/java/org/jabref/gui/theme/ThemeManager.java index db46dc9dc0d..d1345d68a63 100644 --- a/jabgui/src/main/java/org/jabref/gui/theme/ThemeManager.java +++ b/jabgui/src/main/java/org/jabref/gui/theme/ThemeManager.java @@ -29,8 +29,6 @@ import org.jabref.model.util.FileUpdateMonitor; import com.google.common.annotations.VisibleForTesting; -import com.pixelduke.window.ThemeWindowManager; -import com.pixelduke.window.ThemeWindowManagerFactory; import org.jspecify.annotations.NonNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,22 +57,17 @@ public class ThemeManager { private final WorkspacePreferences workspacePreferences; private final FileUpdateMonitor fileUpdateMonitor; - private final ThemeWindowManager themeWindowManager; private final StyleSheet baseStyleSheet; private Theme theme; - private boolean isDarkMode; private final Set webEngines = Collections.newSetFromMap(new WeakHashMap<>()); public ThemeManager(@NonNull WorkspacePreferences workspacePreferences, @NonNull FileUpdateMonitor fileUpdateMonitor) { this.workspacePreferences = workspacePreferences; this.fileUpdateMonitor = fileUpdateMonitor; - // Always returns something even if the native library is not available - see https://github.com/dukke/FXThemes/issues/15 - this.themeWindowManager = ThemeWindowManagerFactory.create(); - this.baseStyleSheet = StyleSheet.create(Theme.BASE_CSS).get(); + this.baseStyleSheet = Theme.getBaseStyleSheet(); this.theme = workspacePreferences.getTheme(); - this.isDarkMode = Theme.EMBEDDED_DARK_CSS.equals(this.theme.getName()); initializeWindowThemeUpdater(); @@ -116,8 +109,7 @@ public void installCssImmediately(Scene scene) { .map(URL::toExternalForm) .ifPresent(toAdd::add); - scene.getStylesheets().clear(); - scene.getStylesheets().addAll(toAdd); + scene.getStylesheets().setAll(toAdd); } /// Registers a runnable on JavaFX thread to install the base and additional css files as stylesheets in the given scene. @@ -173,7 +165,7 @@ private void initializeWindowThemeUpdater() { updateFontStyle(scene); } if (window instanceof Stage stage) { - stage.showingProperty().addListener(_ -> applyDarkModeToWindow(stage)); + stage.showingProperty().addListener(_ -> applyModeToWindow(stage)); } } } @@ -182,41 +174,52 @@ private void initializeWindowThemeUpdater() { // Apply styles to all windows that *already exist* applyCssAndFontToAllWindows(); - applyDarkModeToAllWindows(); + applyModeToAllWindows(); LOGGER.debug("Window theme monitoring initialized"); } - private void applyDarkModeToWindow(Stage stage) { - if (stage == null || !stage.isShowing()) { + private void applyModeToWindow(Stage stage) { + Theme.Type type = theme.getType(); + if (type == Theme.Type.CUSTOM) { return; } - try { - themeWindowManager.setDarkModeForWindowFrame(stage, isDarkMode); - LOGGER.debug("Applied {} mode to window: {}", isDarkMode ? "dark" : "light", stage); - } catch (NoClassDefFoundError | UnsatisfiedLinkError e) { - // We need to handle these exceptions because the native library may not be available on all platforms (e.g., x86). - // See https://github.com/dukke/FXThemes/issues/13 for details. - LOGGER.debug("Failed to set dark mode for window frame (likely due to native library compatibility issues on intel)", e); + + if (stage == null) { + return; + } + + Scene scene = stage.getScene(); + if (scene == null) { + return; + } + + if (Objects.equals(type, Theme.light().getType())) { + scene.getPreferences().setColorScheme(ColorScheme.LIGHT); + } else if (Objects.equals(type, Theme.dark().getType())) { + scene.getPreferences().setColorScheme(ColorScheme.DARK); + } else { + scene.getPreferences().setColorScheme(null); } } - private void applyDarkModeToAllWindows() { + private void applyModeToAllWindows() { + if (theme.getType() == Theme.Type.CUSTOM) { + return; + } + Window.getWindows().stream() .filter(Window::isShowing) .filter(window -> window instanceof Stage) .map(window -> (Stage) window) - .forEach(this::applyDarkModeToWindow); + .forEach(this::applyModeToWindow); } private void updateThemeSettings() { Theme theme = workspacePreferences.getTheme(); - if (workspacePreferences.themeSyncOsProperty().getValue()) { - if (Platform.getPreferences().getColorScheme() == ColorScheme.DARK) { - theme = Theme.dark(); - } else { - theme = Theme.light(); - } + // In this case we let JavaFX decide and don't do any changes. + if (workspacePreferences.shouldThemeSyncOs()) { + theme = Theme.system(); } if (theme.equals(this.theme)) { @@ -228,11 +231,7 @@ private void updateThemeSettings() { this.theme = theme; LOGGER.debug("Theme set to {} with base css {}", theme, baseStyleSheet); - boolean isDarkTheme = Theme.EMBEDDED_DARK_CSS.equals(theme.getName()); - if (this.isDarkMode != isDarkTheme) { - this.isDarkMode = isDarkTheme; - applyDarkModeToAllWindows(); - } + applyModeToAllWindows(); this.theme.getAdditionalStylesheet().ifPresent( styleSheet -> addStylesheetToWatchlist(styleSheet, this::additionalCssLiveUpdate)); diff --git a/jabgui/src/main/java/org/jabref/gui/welcome/quicksettings/ThemeDialog.java b/jabgui/src/main/java/org/jabref/gui/welcome/quicksettings/ThemeDialog.java index 850892e0290..16618d78088 100644 --- a/jabgui/src/main/java/org/jabref/gui/welcome/quicksettings/ThemeDialog.java +++ b/jabgui/src/main/java/org/jabref/gui/welcome/quicksettings/ThemeDialog.java @@ -3,6 +3,7 @@ import javafx.fxml.FXML; import javafx.scene.control.Alert; import javafx.scene.control.ButtonType; +import javafx.scene.control.CheckBox; import javafx.scene.control.RadioButton; import javafx.scene.control.TextField; import javafx.scene.control.ToggleGroup; @@ -21,6 +22,7 @@ import com.airhacks.afterburner.views.ViewLoader; public class ThemeDialog extends FXDialog { + @FXML private CheckBox themeSyncOs; @FXML private RadioButton lightRadio; @FXML private RadioButton darkRadio; @FXML private RadioButton customRadio; @@ -74,17 +76,27 @@ private void initialize() { if (newValue != null) { ThemeTypes selectedType = (ThemeTypes) newValue.getUserData(); viewModel.setSelectedTheme(selectedType); - updateCustomThemeVisibility(selectedType == ThemeTypes.CUSTOM); + updateThemeVisibility(); } }); + themeSyncOs.selectedProperty().addListener(_ -> { + viewModel.setThemeSyncOs(themeSyncOs.isSelected()); + updateThemeVisibility(); + }); + themeSyncOs.setSelected(viewModel.shouldThemeSyncOs()); + selectInitialTheme(); - updateCustomThemeVisibility(viewModel.getSelectedTheme() == ThemeTypes.CUSTOM); + updateThemeVisibility(); helpButton.setHelpUrl(URLs.CUSTOM_THEME_DOC); } private void selectInitialTheme() { + if (viewModel.shouldThemeSyncOs() || viewModel.getSelectedTheme() == null) { + return; + } + switch (viewModel.getSelectedTheme()) { case LIGHT -> lightRadio.setSelected(true); @@ -95,7 +107,13 @@ private void selectInitialTheme() { } } - private void updateCustomThemeVisibility(boolean visible) { + private void updateThemeVisibility() { + if (viewModel.shouldThemeSyncOs()) { + customRadio.getToggleGroup().selectToggle(null); + } + + boolean visible = viewModel.getSelectedTheme() == ThemeTypes.CUSTOM; + customThemeContainer.setVisible(visible); customThemeContainer.setManaged(visible); if (customThemeContainer.getScene() != null) { diff --git a/jabgui/src/main/java/org/jabref/gui/welcome/quicksettings/viewmodel/ThemeDialogViewModel.java b/jabgui/src/main/java/org/jabref/gui/welcome/quicksettings/viewmodel/ThemeDialogViewModel.java index 2379f644186..0b259293483 100644 --- a/jabgui/src/main/java/org/jabref/gui/welcome/quicksettings/viewmodel/ThemeDialogViewModel.java +++ b/jabgui/src/main/java/org/jabref/gui/welcome/quicksettings/viewmodel/ThemeDialogViewModel.java @@ -25,6 +25,7 @@ public class ThemeDialogViewModel extends AbstractViewModel { private final WorkspacePreferences workspacePreferences; private final GuiPreferences preferences; private final DialogService dialogService; + private boolean shouldThemeSyncOs; public ThemeDialogViewModel(GuiPreferences preferences, DialogService dialogService) { this.preferences = preferences; @@ -35,11 +36,13 @@ public ThemeDialogViewModel(GuiPreferences preferences, DialogService dialogServ } private void initializeFromCurrentTheme() { + shouldThemeSyncOs = workspacePreferences.shouldThemeSyncOs(); + Theme currentTheme = workspacePreferences.getTheme(); switch (currentTheme.getType()) { - case DEFAULT -> + case LIGHT -> selectedThemeProperty.set(ThemeTypes.LIGHT); - case EMBEDDED -> + case DARK -> selectedThemeProperty.set(ThemeTypes.DARK); case CUSTOM -> { selectedThemeProperty.set(ThemeTypes.CUSTOM); @@ -87,14 +90,28 @@ public boolean isValidConfiguration() { } public void saveSettings() { - Theme newTheme = switch (selectedThemeProperty.get()) { - case LIGHT -> - Theme.light(); - case DARK -> - Theme.dark(); - case CUSTOM -> - Theme.custom(customPathProperty.get().trim()); - }; - workspacePreferences.setTheme(newTheme); + workspacePreferences.setThemeSyncOs(shouldThemeSyncOs); + + if (shouldThemeSyncOs) { + workspacePreferences.setTheme(Theme.system()); + } else if (selectedThemeProperty.get() != null) { + Theme newTheme = switch (selectedThemeProperty.get()) { + case LIGHT -> + Theme.light(); + case DARK -> + Theme.dark(); + case CUSTOM -> + Theme.custom(customPathProperty.get().trim()); + }; + workspacePreferences.setTheme(newTheme); + } + } + + public void setThemeSyncOs(boolean selected) { + this.shouldThemeSyncOs = selected; + } + + public boolean shouldThemeSyncOs() { + return shouldThemeSyncOs; } } diff --git a/jabgui/src/main/resources/org/jabref/gui/Base.css b/jabgui/src/main/resources/org/jabref/gui/Base.css index 1442738a5b2..8d72702659d 100644 --- a/jabgui/src/main/resources/org/jabref/gui/Base.css +++ b/jabgui/src/main/resources/org/jabref/gui/Base.css @@ -1,124 +1,467 @@ -.root { - /* Note that counting for odd/even starts at 0, thus the first displayed row is even */ - -jr-row-odd-background: -fx-control-inner-background-alt; - -jr-row-even-background: -fx-control-inner-background; +/* +* This is the default JabRef theme. +* It will automatically use the OS color scheme, of not overridden inside JavaFX. +*/ + +@media (prefers-color-scheme: light) { + * { + /* Note that counting for odd/even starts at 0, thus the first displayed row is even */ + -jr-row-odd-background: -fx-control-inner-background-alt; + -jr-row-even-background: -fx-control-inner-background; + /* + On light theme, the text is hard to see when it's on top of the accent color. This is an alternative lighter accent color + for better text visibility. + */ + -jr-accent: #a3b7e6; + -jr-accent-alt: derive(-jr-accent, 15%); + + /* + The theme color and some derived colors from it are used for icons, tab-headers, marking of selected inputs and + hover colors for the main menu. It generally defines the look of JabRef. The highlighting colors below should + work nicely with this base color + */ + + /* original JabRef dark blue color */ + -jr-theme: #50618F; + + -jr-transparent-accent: rgba(163, 183, 230, 0.16); + -jr-checked: -jr-theme; + -jr-selected: -jr-accent; + + -jr-hover: #0002; + -jr-hover-text: -fx-focused-text-base-color; + + /* The base gray. Most gray-tones in the application are derived from this color. */ + -jr-base: #ebebeb; + + /* Highlights */ + -jr-blue: #0abde3; + -jr-light-blue: #48dbfb; + -jr-purple: #7559C2; + -jr-light-purple: #ff9ff3; + -jr-green: #10ac84; + -jr-light-green: #1dd1a1; + -jr-red: #ee5253; + -jr-light-red: #ff6b6b; + -jr-yellow: #feca57; + -jr-orange: #ff9f43; + + /* Background specs */ + -jr-background-alt: -fx-background; + -jr-text-area-background: derive(-jr-base, 80%); + -jr-search-background: -jr-text-area-background; + -jr-toolbar: derive(-jr-base, 46.4%); + + -jr-menu-background: derive(-jr-base, 46.4%); + -jr-menu-background-active: -jr-hover; + -jr-menu-foreground: -fx-dark-text-color; + -jr-menu-item-foreground: -fx-dark-text-color; + -jr-menu-forground-active: -fx-dark-text-color; + + -jr-head-fg: -fx-text-inner-color; + + /* All icons/text on toolbars */ + -jr-theme-text: -jr-theme; + + -jr-icon-background: transparent; + -jr-icon-background-active: #0001; + -jr-icon-background-armed: #0002; + + + /* Color for the small group view indicator for the number of hits */ + -jr-group-hits-bg: derive(-jr-sidepane-background, -50%); + -jr-group-hits-fg: ladder( + -jr-group-hits-bg, + -fx-light-text-color 45%, + -fx-dark-text-color 46%, + -fx-dark-text-color 59%, + -fx-mid-text-color 60% + ); + + /* Specific color for general tooltips */ + -jr-tooltip-bg: -jr-accent; + -jr-tooltip-fg: -jr-black; + + /* Finally, some specific jr styles that depend on -fx definitions in *this* style */ + -jr-sidepane-background: -jr-gray-1; + -jr-sidepane-header-background: -jr-gray-1; + -jr-sidepane-header-color: -jr-theme-text; + + /* Specs for the scrollbars */ + -jr-scrollbar-thumb: derive(-fx-outer-border, -30%); + -jr-scrollbar-track: derive(-fx-control-inner-background, -10%); + + -jr-separator: derive(-fx-color, -5%); + + -jr-search-text: -fx-text-base-color; + + /* For drag and drop actions */ + -jr-drag-target: -jr-purple; + -jr-drag-target-hover: derive(-jr-purple, 80%); + + -js-summary-text-color: #000000; + -js-summary-text-color-selected: #000000; + + -jr-inner-bg: derive(-fx-base, 95%); + -jr-inner-bg-alt: derive(-fx-control-inner-background, -6%); + -jr-mid-text-color: -jr-gray-3; + -jr-light-text-color: -jr-white; + -jr-outer-border: derive(-fx-color, -5%); + + -jr-match-1-odd: -jr-row-odd-background; + -jr-match-1-even: -jr-row-even-background; + -jr-match-1-text-color: -fx-mid-text-color; + + -jr-match-2-odd: derive(-jr-theme, 100%); + -jr-match-2-even: derive(-jr-match-2-odd, 10%); + -jr-match-2-text-color: -fx-mid-text-color; + + -jr-match-3-odd: derive(-jr-theme, 50%); + -jr-match-3-even: derive(-jr-match-3-odd, 10%); + -jr-match-3-text-color: derive(-jr-accent, 30%); + + -jr-match-4-odd: -jr-theme; + -jr-match-4-even: derive(-jr-match-4-odd, 10%); + -jr-match-4-text-color: -jr-accent; + } + /* - On light theme, the text is hard to see when it's on top of the accent color. This is an alternative lighter accent color - for better text visibility. + * TODO: + * Those should be removed eventually and just declared once outside of the media queries + * with the matching variables, as the rest of the CSS (below). + * Example: + * -- from: -rtfx-background-color: rgba(29, 209, 161, 0.5); + * -- to: -jr-xxx-color; (and outside this @media block) */ - -jr-accent-alt: derive(-jr-accent, 15%); + + .unchanged { + -rtfx-background-color: #0000; + } + + .text-unchanged { + + } + + .addition { + -rtfx-background-color: rgba(29, 209, 161, 0.5); + } + + .deletion { + -rtfx-background-color: rgba(255, 107, 107, 0.55); + } + + .custom-color-dialog { + + } + + .merge-field-value .action-icon { + -fx-blend-mode: multiply; + -fx-opacity: 69%; + } + + .merge-header-cell { + -fx-border-color: -jr-gray-1; + -fx-background-color: -jr-row-even-background; + } + + .merge-header { + -fx-background-color: -jr-row-even-background; + } + + .table-view .groupColumnBackground { + -fx-stroke: -jr-gray-2; + } + + .radio-button > .radio { + -fx-background-color: rgba(0, 0, 0, 0.54), -fx-control-inner-background; + } + + #groupTree .numberColumn > .hits:any-selected { + -fx-background-color: derive(-jr-green, 70%); + } + + #groupTree .numberColumn > .hits:all-selected { + -fx-background-color: -jr-green; + } + + .global-search-bar .toggle-button .glyph-icon { + -fx-icon-color: derive(-jr-search-text, 80%); + } + + .rating > .container > .button { + -fx-icon-color: derive(-fx-text-base-color, 85%); + } + + .rating > .container > .button.strong { + -fx-icon-color: -fx-text-base-color; + } + + .file-row-text { + -fx-fill: -jr-search-text; + } + + .walkthrough-spotlight { + /* -jr-blue-gray-4 with 75% Alpha */ + -fx-fill: rgba(34, 47, 62, 0.75); + } + + .walkthrough-darken { + /* -jr-blue-gray-4 with 75% Alpha */ + -fx-fill: rgba(34, 47, 62, 0.75); + } + + .walkthrough-ping { + /* -jr-accent with 75% Alpha */ + -fx-fill: rgba(163, 183, 230, 0.75); + } + + .walkthrough-tooltip .border { + /* The arrow of the PopOver. Need to override the default `.popover > .border` (https://github.com/controlsfx/controlsfx/blob/194b10bb948389bf18c463006adcec7c92ca6403/controlsfx/src/main/resources/org/controlsfx/control/popover.css#L8) */ + /* -jr-background-alt. Variable is not used because the variable cannot be properly resolved and lead to transparent fill. */ + -fx-fill: #f3f3f3 !important; + } +} + +@media (prefers-color-scheme: dark) { + * { + -jr-row-odd-background: #272b38; + -jr-row-even-background: #212330; + + -jr-accent: #255652; + -jr-accent-alt: -jr-accent; + + -jr-theme: #2c9490; + + -jr-transparent-accent: rgba(163, 183, 230, 0.16); + -jr-checked: -jr-theme; + -jr-selected: -jr-accent; + + -jr-hover: #fff1; + -jr-hover-text: -fx-focused-text-base-color; + + -jr-base: #141824; + + -jr-blue: #2c2cb7; + -jr-light-blue: #3a3ad9; + -jr-purple: #b72486; + -jr-light-purple: #d927a8; + -jr-green: #1cb631; + -jr-light-green: #28d93c; + -jr-red: #b71c1f; + -jr-light-red: #db1d2b; + -jr-yellow: #b5b021; + -jr-orange: #b77620; + + -jr-background-alt: #151924; + -jr-text-area-background: derive(-jr-base, 80%); + -jr-sidepane-background: #212330; + -jr-search-background: #2c2e3b; + + -jr-menu-background: #141824; + -jr-menu-background-active: -jr-hover; + -jr-menu-foreground: -fx-light-text-color; + -jr-menu-item-foreground: -fx-light-text-color; + -jr-menu-forground-active: derive(-fx-light-text-color, 50%); + + -jr-toolbar: -jr-menu-background; + + -jr-head-fg: -fx-text-inner-color; + + /* All icons/text on toolbars */ + -jr-theme-text: -jr-theme; + + -jr-icon-background: transparent; + -jr-icon-background-active: -jr-hover; + -jr-icon-background-armed: #fff2; + + -jr-group-hits-bg: -jr-background-alt; + -jr-group-hits-fg: -fx-light-text-color; + + /* Specific color for general tooltips */ + -jr-tooltip-bg: -jr-accent; + -jr-tooltip-fg: derive(-fx-light-text-color, 50%); + + -jr-sidepane-background: #212330; + -jr-sidepane-header-background: -jr-background-alt; + -jr-sidepane-header-color: -jr-theme-text; + + /* Specs for the scrollbars */ + -jr-scrollbar-thumb: -fx-light-text-color; + -jr-scrollbar-track: derive(-fx-control-inner-background, -90%); + + -jr-separator: #333744; + + -jr-search-text: -fx-text-base-color; + + /* For drag and drop actions */ + -jr-drag-target: -jr-accent; + -jr-drag-target-hover: -jr-accent; + + -js-summary-text-color: derive(-fx-light-text-color, 70%); + -js-summary-text-color-selected: derive(-fx-dark-text-color, 70%); + + -jr-inner-bg: #272b38; + -jr-inner-bg-alt: -fx-control-inner-background; + -jr-mid-text-color: #7d8591; + -jr-light-text-color: #e5e7ea; + -jr-outer-border: #424758; + + -jr-match-1-odd: -jr-row-odd-background; + -jr-match-1-even: -jr-row-even-background; + -jr-match-1-text-color: -fx-mid-text-color; + + -jr-match-2-odd: derive(-jr-theme, 100%); + -jr-match-2-even: derive(-jr-match-2-odd, 10%); + -jr-match-2-text-color: -fx-mid-text-color; + + -jr-match-3-odd: derive(-jr-theme, 50%); + -jr-match-3-even: derive(-jr-match-3-odd, 10%); + -jr-match-3-text-color: derive(-jr-accent, 30%); + + -jr-match-4-odd: -jr-theme; + -jr-match-4-even: derive(-jr-match-4-odd, 10%); + -jr-match-4-text-color: -jr-accent; + } /* - The theme color and some derived colors from it are used for icons, tab-headers, marking of selected inputs and - hover colors for the main menu. It generally defines the look of JabRef. The highlighting colors below should - work nicely with this base color + * TODO: + * Those should be removed eventually and just declared once outside of the media queries + * with the matching variables, as the rest of the CSS (below). + * Example: + * -- from: -rtfx-background-color: rgba(29, 209, 161, 0.5); + * -- to: -jr-xxx-color; (and outside this @media block) */ - /* original JabRef dark blue color */ - -jr-theme: #50618F; + .unchanged { - -jr-accent: #a3b7e6; - -jr-transparent-accent: rgba(163, 183, 230, 0.16); - -jr-checked: -jr-theme; + } - -jr-selected: -jr-accent; + .text-unchanged { + -fx-fill: -fx-light-text-color; + } - -jr-hover: #0002; - -jr-hover-text: -fx-focused-text-base-color; + .addition { + -fx-text-background-color: black; + -rtfx-background-color: #FDAF56; + } - /* The base gray. Most gray-tones in the application are derived from this color. */ - -jr-base: #ebebeb; + .deletion { + -fx-text-background-color: black; + -rtfx-background-color: #FFEECC; + } - -jr-white: #ffffff; - -jr-gray-0: #f2f2f2; - -jr-gray-1: #dddddd; - -jr-gray-2: #808080; - -jr-gray-3: #404040; - -jr-black: #000; + .custom-color-dialog { + -fx-background-color: -fx-control-inner-background; + } - /* Some blueish greys - currently not used */ - -jr-blue-gray-1: #c8d6e5; - -jr-blue-gray-1-darker: derive(-jr-blue-gray-1, -5%); - -jr-blue-gray-2: #8395a7; - -jr-blue-gray-2-darker: derive(-jr-blue-gray-2, -5%); - -jr-blue-gray-3: #576574; - -jr-blue-gray-3-darker: derive(-jr-blue-gray-3, -5%); - -jr-blue-gray-4: #222f3e; - -jr-blue-gray-4-darker: derive(-jr-blue-gray-4, -5%); - - /* Highlights */ - -jr-blue: #0abde3; - -jr-light-blue: #48dbfb; - -jr-purple: #7559C2; - -jr-light-purple: #ff9ff3; - -jr-green: #10ac84; - -jr-light-green: #1dd1a1; - -jr-red: #ee5253; - -jr-light-red: #ff6b6b; - -jr-yellow: #feca57; - -jr-orange: #ff9f43; - - /* Background specs */ - -jr-background-alt: -fx-background; - -jr-text-area-background: derive(-jr-base, 80%); - -jr-search-background: -jr-text-area-background; - -jr-toolbar: derive(-jr-base, 46.4%); - -jr-menu-background: derive(-jr-base, 46.4%); - -jr-menu-background-active: -jr-hover; - - -jr-menu-foreground: -fx-dark-text-color; - -jr-menu-item-foreground: -fx-dark-text-color; - -jr-menu-forground-active: -fx-dark-text-color; - - -jr-head-fg: -fx-text-inner-color; - - /* All icons/text on toolbars */ - -jr-theme-text: -jr-theme; - - -jr-icon-background: transparent; - -jr-icon-background-active: #0001; - -jr-icon-background-armed: #0002; + .table-row-cell:odd { + -fx-background-color: #272b38; + } - /* Colors for messages and errors */ - -jr-info: -jr-light-green; - -jr-warn: -jr-orange; - -jr-error: -jr-light-red; - -jr-success: -jr-green; + .table-row-cell:even { + -fx-background-color: #212330; + } + + .merge-field-value .action-icon { + -fx-blend-mode: none; + -fx-opacity: 90%; + } + + .merge-header-cell { + -fx-border-color: -fx-outer-border; + -fx-background-color: -jr-row-odd-background; + } + + .merge-header { + -fx-background-color: -jr-row-odd-background; + } + + .table-view .groupColumnBackground { + -fx-stroke: -jr-gray-3; + } + + .code-area { + -fx-background-color: -jr-background-alt; + -fx-text-fill: -fx-mid-text-color; + } + + .code-area .lineno { + -fx-background-color: -jr-background-alt; + -fx-text-fill: -fx-mid-text-color; + } - /* Color for the small group view indicator for the number of hits */ - -jr-group-hits-bg: derive(-jr-sidepane-background, -50%); - -jr-group-hits-fg: ladder( - -jr-group-hits-bg, - -fx-light-text-color 45%, - -fx-dark-text-color 46%, - -fx-dark-text-color 59%, - -fx-mid-text-color 60% - ); + .radio-button > .radio { + -fx-background-color: -fx-light-text-color, -fx-control-inner-background; + } - /* Specific color for general tooltips */ - -jr-tooltip-bg: -jr-accent; - -jr-tooltip-fg: -jr-black; + #groupTree .numberColumn > .hits:any-selected { + -fx-background-color: derive(-jr-gray-3, 25%); + } - /* Finally, some specific jr styles that depend on -fx definitions in *this* style */ - -jr-sidepane-background: -jr-gray-1; - -jr-sidepane-header-background: -jr-gray-1; - -jr-sidepane-header-color: -jr-theme-text; + #groupTree .numberColumn > .hits:all-selected { + -fx-background-color: -jr-gray-3; + } - /* Specs for the scrollbars */ - -jr-scrollbar-thumb: derive(-fx-outer-border, -30%); - -jr-scrollbar-track: derive(-fx-control-inner-background, -10%); + #preferencesContainer .tab-pane > .tab-header-area > .tab-header-background { + -fx-background-color: -jr-background; + } - -jr-separator: derive(-fx-color, -5%); + .global-search-bar .toggle-button .glyph-icon { + -fx-icon-color: derive(-jr-search-background, 50%); + } - -jr-search-text: -fx-text-base-color; + .rating > .container > .button { + -fx-icon-color: derive(-fx-light-text-color, -50%); + } - /* For drag and drop actions */ - -jr-drag-target: -jr-purple; - -jr-drag-target-hover: derive(-jr-purple, 80%); + .rating > .container > .button.strong { + -fx-icon-color: -fx-light-text-color; + } - -js-summary-text-color: #000000; - -js-summary-text-color-selected: #000000; + .file-row-text { + -fx-text-fill: -fx-light-text-color; + } + .walkthrough-spotlight { + -fx-fill: rgba(0, 0, 0, 0.65); + } + + .walkthrough-darken { + -fx-fill: rgba(0, 0, 0, 0.65); + } + + .walkthrough-ping { + /* -jr-accent with 75% Alpha */ + -fx-fill: rgba(37, 86, 82, 0.75); + } + + .walkthrough-tooltip .border { + /* -jr-background-alt. Variable is not used because the variable cannot be properly resolved and lead to transparent fill. */ + -fx-fill: #151924 !important; + } +} + +/* JabRef variables and colors */ +* { + /* Consistent size for headers of tab-pane and side-panels*/ + -jr-header-height: 3em; + + /* Colors for messages and errors */ + -jr-info: -jr-light-green; + -jr-warn: -jr-orange; + -jr-error: -jr-light-red; + -jr-success: -jr-green; + + -jr-white: #ffffff; + -jr-gray-0: #f2f2f2; + -jr-gray-1: #dddddd; + -jr-gray-2: #808080; + -jr-gray-3: #404040; + -jr-black: #000; +} + +/* JavaFX CSS overwrites with our JabRef colors. */ +.root { /* Here are redefinitions of the default properties of modena. They should in principle all be derived from the above colors. Goal should be to make as few as possible direct color-changes to elements and only do this for @@ -137,9 +480,10 @@ * -fx-text-fill value for text painted on top of backgrounds colored * with -fx-control-inner-background. */ - -fx-control-inner-background: derive(-fx-base, 95%); + + -fx-control-inner-background: -jr-inner-bg; /* Version of -fx-control-inner-background for alternative rows */ - -fx-control-inner-background-alt: derive(-fx-control-inner-background, -6%); + -fx-control-inner-background-alt: -jr-inner-bg-alt; /* One of these colors will be chosen based upon a ladder calculation * that uses the brightness of a background color. Instead of using these @@ -152,8 +496,8 @@ * -fx-selection-bar-text for text on top of -fx-selection-bar */ -fx-dark-text-color: -jr-black; - -fx-mid-text-color: -jr-gray-3; - -fx-light-text-color: -jr-white; + -fx-mid-text-color: -jr-mid-text-color; + -fx-light-text-color: -jr-light-text-color; /* We overwrite accents -> make old stick out */ -fx-accent: red; @@ -207,7 +551,7 @@ * a control. It is typically the same size as the control (i.e., insets * are 0). */ - -fx-outer-border: derive(-fx-color, -5%); + -fx-outer-border: -jr-outer-border; /* A gradient that goes from a bit lighter than -fx-color on the top to * a little darker at the bottom. Typically is the third color in the @@ -257,58 +601,14 @@ /** Focus line for keyboard focus traversal on cell based controls */ -fx-cell-focus-inner-border: derive(-fx-selection-bar, 30%); + -fx-focused-text-base-color: -fx-light-text-color; -fx-focused-mark-color: -fx-focused-text-base-color; - - /* Consistent size for headers of tab-pane and side-panels*/ - -jr-header-height: 3em; - - /* AI chat style */ - -jr-ai-message-user: derive(-jr-accent, 50%); - -jr-ai-message-user-border: -jr-theme; - -jr-ai-message-ai: derive(-jr-accent, 80%); - -jr-ai-message-ai-border: -jr-theme; - -jr-ai-message-error: -jr-error; - -jr-ai-message-error-border: derive(-jr-error, -40%); - - /* region: maintable base colors **/ - - -jr-match-1-odd: -jr-row-odd-background; - -jr-match-1-even: -jr-row-even-background; - -jr-match-1-text-color: -fx-mid-text-color; - - -jr-match-2-odd: derive(-jr-theme, 100%); - -jr-match-2-even: derive(-jr-match-2-odd, 10%); - -jr-match-2-text-color: -fx-mid-text-color; - - -jr-match-3-odd: derive(-jr-theme, 50%); - -jr-match-3-even: derive(-jr-match-3-odd, 10%); - -jr-match-3-text-color: derive(-jr-accent, 30%); - - -jr-match-4-odd: -jr-theme; - -jr-match-4-even: derive(-jr-match-4-odd, 10%); - -jr-match-4-text-color: -jr-accent; - - -jr-maintable-focused-hover-text: -jr-white; - - /* endregion */ -} - -.unchanged { - -rtfx-background-color: #0000; } .updated { -rtfx-background-color: rgba(41, 166, 236, 0.66); } -.addition { - -rtfx-background-color: rgba(29, 209, 161, 0.5); -} - -.deletion { - -rtfx-background-color: rgba(255, 107, 107, 0.55); -} - #frame { -fx-background-color: -jr-background-alt; } @@ -385,13 +685,15 @@ TextFlow > .tooltip-text-monospaced { -fx-font-family: monospace; } - -.radio-button > .radio, .check-box > .box { -fx-background-color: transparent; -fx-background-insets: 0; -fx-background-radius: 0; -fx-text-fill: -fx-text-base-color; + -fx-border-color: -fx-outer-border; /* rgba(0, 0, 0, 0.54); */ + -fx-border-width: 0.125em; + -fx-border-radius: 0.062em; + -fx-padding: 0.1em 0.1em 0.2em 0.2em; } .button, @@ -407,10 +709,8 @@ TextFlow > .tooltip-text-monospaced { } .button { - -fx-background-color: transparent; -fx-border-color: -fx-outer-border; /* rgba(0, 0, 0, 0.23); */ -fx-border-width: 0.062em; - -fx-border-radius: 0.25em; -fx-padding: 0.5em 1em 0.5em 1em; } @@ -518,13 +818,6 @@ TextFlow > .tooltip-text-monospaced { -fx-text-fill: -fx-text-background-color; } -.check-box > .box { - -fx-border-color: -fx-outer-border; /* rgba(0, 0, 0, 0.54); */ - -fx-border-width: 0.125em; - -fx-border-radius: 0.062em; - -fx-padding: 0.1em 0.1em 0.2em 0.2em; -} - .check-box:selected > .box { -fx-background-insets: 0.125em; -fx-border-color: -jr-checked; @@ -546,6 +839,7 @@ TextFlow > .tooltip-text-monospaced { -fx-padding: 0.35em; /* padding from outside edge to the inner dot */ -fx-background-color: rgba(0, 0, 0, 0.54), -fx-control-inner-background; -fx-background-insets: 0, 0.125em; + -fx-text-fill: -fx-text-base-color; } .radio-button:selected > .radio { @@ -694,8 +988,9 @@ TextFlow > .tooltip-text-monospaced { } .table-row-cell:hover, +.tree-table-row-cell:hover, .table-row-cell:hover:even, -.tree-table-row-cell:hover { +.tree-table-row-cell:hover:even { -fx-background-color: -jr-hover; -fx-fill: -jr-hover-text; -fx-text-fill: -jr-hover-text; @@ -713,8 +1008,6 @@ TextFlow > .tooltip-text-monospaced { } .merge-field-value .action-icon { - -fx-blend-mode: multiply; - -fx-opacity: 69%; -fx-icon-size: 14; -fx-icon-color: -fx-text-background-color; } @@ -725,8 +1018,6 @@ TextFlow > .tooltip-text-monospaced { .merge-header-cell { -fx-border-width: 0 0 1 0; - -fx-border-color: -jr-gray-1; - -fx-background-color: -jr-row-even-background; } .merge-header { @@ -744,10 +1035,6 @@ TextFlow > .tooltip-text-monospaced { -fx-padding: 4 0 0 5; } -.table-view .groupColumnBackground { - -fx-stroke: -jr-gray-2; -} - .scroll-pane:focused, .split-pane:focused, .list-view:focused, @@ -796,10 +1083,6 @@ TextFlow > .tooltip-text-monospaced { -fx-background-color: -jr-light-green; } -.file-row-text { - -fx-fill: -jr-search-text; -} - .file-row-text:opacity { -fx-fill: derive(-jr-search-text, 70%); } @@ -1148,10 +1431,6 @@ TextFlow > .tooltip-text-monospaced { -fx-background-color: -jr-icon-background-active; } -.global-search-bar .toggle-button .glyph-icon { - -fx-icon-color: derive(-jr-search-text, 80%); -} - .global-search-bar .toggle-button:selected .glyph-icon { -fx-icon-color: -jr-search-text; } @@ -1237,6 +1516,7 @@ We want to have a look that matches our icons in the tool-bar */ -fx-padding: 0 0 -2 0; } +.table-row-cell:dragOver-center, .table-row-cell:dragOver-center > .table-cell { -fx-background-color: -jr-drag-target-hover; } @@ -1271,42 +1551,6 @@ We want to have a look that matches our icons in the tool-bar */ -fx-background-color: -jr-sidepane-background; } -.notification-bar > .pane { - -fx-background-color: -jr-gray-3; - -fx-background-radius: 0.25em; -} - -.notification-bar > .pane > .title, -.notification-bar > .pane > .label, -.notification-bar > .pane > .button-bar > .container > .action { - -fx-text-fill: -jr-base; - -fx-padding: 1ex 1ex 1ex 1ex; -} - -.notification-bar > .pane { - -fx-effect: dropshadow(three-pass-box, rgba(0, 0, 0, 0.3), 9, 0, 0, 2); - -fx-padding: 0.375em 0.438em 0.375em 2.0em; - -fx-background-radius: 0; - -fx-border-radius: 0; -} - -.notification-bar > .pane > .button-bar > .container { - -fx-padding: 0.0em 1.5em 0.0em 0.0em; -} - -.notification-bar > .pane > .label { - -fx-graphic-text-gap: 0.5em; -} - -.notification-pane .notification-bar > .pane .close-button > .graphic { - -fx-background-color: -jr-base; -} - -.notification-bar > .pane > .label > .ikonli-font-icon { - -fx-icon-size: 1.0em; - -fx-icon-color: -jr-base; -} - .progress-bar > .bar { -fx-background-color: -jr-theme; } @@ -1521,14 +1765,6 @@ We want to have a look that matches our icons in the tool-bar */ -fx-padding: 0.5em 0.0em 0.0em 0.0em; } -.rating > .container > .button { - -fx-icon-color: derive(-fx-text-base-color, 85%); -} - -.rating > .container > .button.strong { - -fx-icon-color: -fx-text-base-color; -} - .table-column .rotated > .label { -fx-content-display: graphic-only; } @@ -1608,10 +1844,10 @@ We want to have a look that matches our icons in the tool-bar */ -fx-text-fill: -fx-focused-text-base-color; } .main-table .table-row-cell:matching-search-and-groups:focused:hover > .table-cell { - -fx-text-fill: -jr-maintable-focused-hover-text; + -fx-text-fill: -jr-white; } .main-table .table-row-cell:matching-search-and-groups:focused:hover > .table-cell > .ikonli-font-icon { - -fx-icon-color: -jr-maintable-focused-hover-text; + -fx-icon-color: -jr-white; } .main-table .table-row-cell:matching-search-and-groups:hover > .table-cell { -fx-text-fill: -jr-hover-text; @@ -1644,10 +1880,10 @@ We want to have a look that matches our icons in the tool-bar */ -fx-text-fill: -fx-focused-text-base-color; } .main-table .table-row-cell:matching-search-not-groups:focused:hover > .table-cell { - -fx-text-fill: -jr-maintable-focused-hover-text; + -fx-text-fill: -jr-white; } .main-table .table-row-cell:matching-search-not-groups:focused:hover > .table-cell > .ikonli-font-icon { - -fx-icon-color: -jr-maintable-focused-hover-text; + -fx-icon-color: -jr-white; } .main-table .table-row-cell:matching-search-not-groups:hover > .table-cell { -fx-text-fill: -jr-hover-text; @@ -1681,10 +1917,10 @@ We want to have a look that matches our icons in the tool-bar */ -fx-text-fill: -fx-focused-text-base-color; } .main-table .table-row-cell:matching-groups-not-search:focused:hover > .table-cell { - -fx-text-fill: -jr-maintable-focused-hover-text; + -fx-text-fill: -jr-white; } .main-table .table-row-cell:matching-groups-not-search:focused:hover > .table-cell > .ikonli-font-icon { - -fx-icon-color: -jr-maintable-focused-hover-text; + -fx-icon-color: -jr-white; } .main-table .table-row-cell:matching-groups-not-search:hover > .table-cell { -fx-text-fill: -jr-hover-text; @@ -1718,10 +1954,10 @@ We want to have a look that matches our icons in the tool-bar */ -fx-text-fill: -fx-focused-text-base-color; } .main-table .table-row-cell:not-matching-search-and-groups:focused:hover > .table-cell { - -fx-text-fill: -jr-maintable-focused-hover-text; + -fx-text-fill: -jr-whitet; } .main-table .table-row-cell:not-matching-search-and-groups:focused:hover > .table-cell > .ikonli-font-icon { - -fx-icon-color: -jr-maintable-focused-hover-text; + -fx-icon-color: -jr-white; } .main-table .table-row-cell:not-matching-search-and-groups:hover > .table-cell { -fx-text-fill: -jr-hover-text; @@ -2272,14 +2508,6 @@ We want to have a look that matches our icons in the tool-bar */ -fx-fill: -jr-group-hits-fg; } -#groupTree .numberColumn > .hits:any-selected { - -fx-background-color: derive(-jr-green, 70%); -} - -#groupTree .numberColumn > .hits:all-selected { - -fx-background-color: -jr-green; -} - #groupTree .expansionNodeColumn { -fx-alignment: top-right; } @@ -2831,7 +3059,6 @@ journalInfo .grid-cell-b { -fx-border-radius: 0.25em; -fx-background-radius: 0.25em; -fx-effect: dropshadow(three-pass-box, rgba(0, 0, 0, 0.1), 0.125em, 0.0, 0, 0.0625em); - -fx-border-color: -jr-wf-border-color; } .wireframe-menubar { @@ -2982,32 +3209,11 @@ journalInfo .grid-cell-b { -fx-background-color: transparent; } -.walkthrough-spotlight { - /* -jr-blue-gray-4 with 75% Alpha */ - -fx-fill: rgba(34, 47, 62, 0.75); -} - -.walkthrough-ping { - /* -jr-accent with 75% Alpha */ - -fx-fill: rgba(163, 183, 230, 0.75); -} - -.walkthrough-darken { - /* -jr-blue-gray-4 with 75% Alpha */ - -fx-fill: rgba(34, 47, 62, 0.75); -} - /* Tooltip Content */ .walkthrough-tooltip-content-container { -fx-background-color: -jr-background-alt; } -.walkthrough-tooltip .border { - /* The arrow of the PopOver. Need to override the default `.popover > .border` (https://github.com/controlsfx/controlsfx/blob/194b10bb948389bf18c463006adcec7c92ca6403/controlsfx/src/main/resources/org/controlsfx/control/popover.css#L8) */ - /* -jr-background-alt. Variable is not used because the variable cannot be properly resolved and lead to transparent fill. */ - -fx-fill: #f3f3f3 !important; -} - .walkthrough-tooltip-content-container { -fx-spacing: 1em; -fx-padding: 1em; @@ -3281,3 +3487,31 @@ journalInfo .grid-cell-b { .automatic-field-editor .button-bar .button:default { -fx-min-width: 12em; } + +.info-center-view .notification-view > .content > .text-container > .title-time-box > .title-label { + -fx-text-fill: -fx-dark-text-color; +} + +.info-center-view .notification-view > .content > .close-icon-wrapper > .ikonli-font-icon { + -fx-icon-color: -fx-dark-text-color; +} + +.info-center-view .notification-view > .content > .text-container > .title-time-box > .upper-right-pane > .time-label { + -fx-text-fill: -fx-dark-text-color; +} + +.info-center-view .notification-view > .content > .text-container > .description-label { + -fx-text-fill: -fx-dark-text-color; +} + +.info-center-view .notification-view .default-icon { + -fx-icon-color: -fx-dark-text-color; +} + +.info-center-view .notification-view > .content > .text-container > .title-time-box > .upper-right-pane > .arrow-pane .ikonli-font-icon { + -fx-icon-color: -fx-dark-text-color; +} + +.info-center-view .notification-view:expanded > .content > .text-container > .title-time-box > .upper-right-pane > .arrow-pane .ikonli-font-icon { + -fx-icon-color: -fx-dark-text-color; +} diff --git a/jabgui/src/main/resources/org/jabref/gui/Dark.css b/jabgui/src/main/resources/org/jabref/gui/Dark.css deleted file mode 100644 index 0f9f7e5d3cc..00000000000 --- a/jabgui/src/main/resources/org/jabref/gui/Dark.css +++ /dev/null @@ -1,251 +0,0 @@ -.root { - -jr-theme: #2c9490; - -jr-accent: #255652; - -jr-selected: -jr-accent; - -jr-hover: #fff1; - - -jr-row-odd-background: #272b38; - -jr-row-even-background: #212330; - -jr-accent-alt: -jr-accent; - - -jr-red: #b71c1f; - -jr-light-red: #db1d2b; - -jr-green: #1cb631; - -jr-light-green: #28d93c; - -jr-blue: #2c2cb7; - -jr-light-blue: #3a3ad9; - -jr-purple: #b72486; - -jr-light-purple: #d927a8; - -jr-yellow: #b5b021; - -jr-orange: #b77620; - - -jr-base: #141824; - - -jr-background-alt: #151924; - -jr-menu-background: #141824; - -jr-toolbar: -jr-menu-background; - -jr-sidepane-background: #212330; - -jr-search-background: #2c2e3b; - - -jr-sidepane-header-background: -jr-background-alt; - -jr-group-hits-bg: -jr-background-alt; - -jr-group-hits-fg: -fx-light-text-color; - -fx-control-inner-background: #272b38; - - -fx-control-inner-background-alt: -fx-control-inner-background; - - -fx-dark-text-color: black; - -fx-mid-text-color: #7d8591; - -fx-light-text-color: #e5e7ea; - -jr-separator: #333744; - -fx-outer-border: #424758; - - -jr-icon: -fx-light-text-color; - -jr-icon-active: derive(-fx-light-text-color, 50%); - -jr-icon-background-active: -jr-hover; - -jr-icon-background-armed: #fff2; - - -jr-menu-foreground: -fx-light-text-color; - -jr-menu-item-foreground: -fx-light-text-color; - -jr-menu-forground-active: derive(-fx-light-text-color, 50%); - - -jr-scrollbar-thumb: -fx-light-text-color; - -jr-scrollbar-track: derive(-fx-control-inner-background, -90%); - - -fx-focused-text-base-color: -fx-light-text-color; - - -jr-tooltip-fg: derive(-fx-light-text-color, 50%); - - -jr-drag-target: -jr-accent; - -jr-drag-target-hover: -jr-accent; - - -js-summary-text-color: derive(-fx-light-text-color, 70%); - -js-summary-text-color-selected: derive( -fx-dark-text-color, 70%); - - -jr-ai-message-user: derive(-jr-theme, -50%); - -jr-ai-message-ai: derive(-jr-theme, -75%); - - -jr-match-1-odd: -jr-row-odd-background; - -jr-match-1-even: -jr-row-even-background; - -jr-match-1-text-color: -fx-mid-text-color; - - -jr-match-2-odd: derive(-jr-theme, -60%); - -jr-match-2-even: derive(-jr-match-2, 4%); - -jr-match-2-text-color: -fx-mid-text-color; - - -jr-match-3-odd: derive(-jr-theme, -70%); - -jr-match-3-even: derive(-jr-match-3, 4%); - -jr-match-3-text-color: derive(-jr-accent, 30%); - - -jr-match-4-odd: derive(-jr-black, 10%); - -jr-match-4-even: -jr-background-alt; - -jr-match-4-text-color: derive(-jr-match-3-text-color, -15%); -} - -.unchanged { - -} - -.addition { - -fx-text-background-color: black; - -rtfx-background-color: #FDAF56; -} - -.deletion { - -fx-text-background-color: black; - -rtfx-background-color: #FFEECC; -} - -#previewBody { - background-color: #272b38; /* -fx-control-inner-background*/ - color: #7d8591; /* -fx-mid-text-color*/ -} - -.custom-color-dialog { - -fx-background-color: -fx-control-inner-background; -} - -.table-row-cell:odd{ - -fx-background-color:#272b38; -} - -.table-row-cell:even{ - -fx-background-color: #212330; -} - -.table-row-cell:hover, -.tree-table-row-cell:hover { - -fx-background-color: -jr-hover; -} - -/* Drag and drop colored indicator */ - -.table-row-cell:dragOver-center { - -fx-background-color: -jr-drag-target-hover; -} - -.merge-field-value .action-icon { - -fx-blend-mode: none; - -fx-opacity: 90%; -} - -.merge-header-cell { - -fx-border-width: 0 0 1 0; - -fx-border-color: -fx-outer-border; - -fx-background-color: -jr-row-odd-background; -} - -.merge-header { - -fx-background-color: -jr-row-odd-background; -} - -.table-view .groupColumnBackground { - -fx-stroke: -jr-gray-3; -} - -.code-area { - -fx-background-color: -jr-background-alt; - -fx-text-fill: -fx-mid-text-color; -} - -.code-area .lineno { - -fx-background-color: -jr-background-alt; - -fx-text-fill: -fx-mid-text-color; -} - -.text-unchanged { - -fx-fill: -fx-light-text-color; -} - -.radio-button > .radio { - -fx-background-color: -fx-light-text-color, -fx-control-inner-background; -} - -#groupTree .numberColumn > .hits:any-selected { - -fx-background-color: derive(-jr-gray-3, 25%); -} - -#groupTree .numberColumn > .hits:all-selected { - -fx-background-color: -jr-gray-3; -} - -#preferencesContainer .tab-pane > .tab-header-area > .tab-header-background { - -fx-background-color: -jr-background; -} - -.global-search-bar .toggle-button .glyph-icon { - -fx-icon-color: derive(-jr-search-background, 50%); -} - -.notification-bar > .pane { - -fx-background-color: -fx-light-text-color; -} - -.rating > .container > .button { - -fx-icon-color: derive(-fx-light-text-color, -50%); -} - -.rating > .container > .button.strong { - -fx-icon-color: -fx-light-text-color; -} - -.file-row-text { - -fx-text-fill: -fx-light-text-color; -} - -.walkthrough-spotlight { - -fx-fill: rgba(0, 0, 0, 0.65); -} - -.walkthrough-darken { - -fx-fill: rgba(0, 0, 0, 0.65); -} - -.walkthrough-ping { - /* -jr-accent with 75% Alpha */ - -fx-fill: rgba(37, 86, 82, 0.75); -} - -.walkthrough-tooltip .border { - /* -jr-background-alt. Variable is not used because the variable cannot be properly resolved and lead to transparent fill. */ - -fx-fill: #151924 !important; -} - -/* region CiteAsYouWrite */ - -/* this is the search filed used to enter the citation name */ -.search-dialog { - -fx-background-color: -jr-background-alt; -} - -/* each cells' background color and text color */ -.search-dialog .list-cell:hover, -.search-dialog .list-cell:selected { - -fx-background-color: derive(-fx-control-inner-background, 10%); - -fx-text-fill: -fx-light-text-color; -} - -/* each cells' text and label styles here */ -.search-dialog .list-cell .text, -.search-dialog .list-cell .label, -.search-dialog .search-result-label, -.search-dialog .search-result-description { - -fx-text-fill: -fx-light-text-color; - -fx-fill: -fx-light-text-color; -} - -/* This is the chip style that contains the selected citation name and cross button */ -.search-dialog .chip-style { - -fx-border-radius: 15px; - -fx-border-color: -jr-separator; - -fx-border-width: 1px; -} - -/* This is the chip style button present in the chip style. it is the cross */ -.search-dialog .chip-style .button { - -fx-border-color: transparent; - -fx-border-width: 0; - -fx-background-color: transparent; -} - -/* endregion */ diff --git a/jabgui/src/main/resources/org/jabref/gui/welcome/quicksettings/ThemeDialog.fxml b/jabgui/src/main/resources/org/jabref/gui/welcome/quicksettings/ThemeDialog.fxml index d33970f058a..29b7f6c663a 100644 --- a/jabgui/src/main/resources/org/jabref/gui/welcome/quicksettings/ThemeDialog.fxml +++ b/jabgui/src/main/resources/org/jabref/gui/welcome/quicksettings/ThemeDialog.fxml @@ -13,6 +13,7 @@ + @@ -23,9 +24,11 @@ + + - + @@ -34,13 +37,13 @@ - - @@ -50,8 +53,8 @@ -