diff --git a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryComp.java b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryComp.java index aa739e80..78fea6c7 100644 --- a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryComp.java +++ b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryComp.java @@ -17,7 +17,9 @@ import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.fxcomps.util.SimpleChangeListener; import io.xpipe.app.prefs.AppPrefs; +import io.xpipe.app.storage.DataStoreColor; import io.xpipe.app.update.XPipeDistributionType; +import io.xpipe.app.util.DataStoreFormatter; import io.xpipe.app.util.DesktopHelper; import io.xpipe.app.util.DesktopShortcuts; import io.xpipe.app.util.ThreadHelper; @@ -43,13 +45,14 @@ import java.awt.*; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; import java.util.ArrayList; +import java.util.Arrays; public abstract class StoreEntryComp extends SimpleComp { public static StoreEntryComp create( StoreEntryWrapper entry, boolean showIcon, Comp content, boolean preferLarge) { if (!preferLarge) { - return new DenseStoreEntryComp(entry, showIcon, content); + return new DenseStoreEntryComp(entry, true, content); } else { return new StandardStoreEntryComp(entry, content); } @@ -345,12 +348,32 @@ public abstract class StoreEntryComp extends SimpleComp { MenuItem m = new MenuItem(storeCategoryWrapper.getName()); m.setOnAction(event -> { wrapper.moveTo(storeCategoryWrapper.getCategory()); + event.consume(); }); move.getItems().add(m); }); contextMenu.getItems().add(move); } + { + var color = new Menu(AppI18n.get("color"), new FontIcon("mdi2f-format-color-fill")); + var none = new MenuItem("None"); + none.setOnAction(event -> { + wrapper.getEntry().setColor(null); + event.consume(); + }); + color.getItems().add(none); + Arrays.stream(DataStoreColor.values()).forEach(dataStoreColor -> { + MenuItem m = new MenuItem(DataStoreFormatter.capitalize(dataStoreColor.getId())); + m.setOnAction(event -> { + wrapper.getEntry().setColor(dataStoreColor); + event.consume(); + }); + color.getItems().add(m); + }); + contextMenu.getItems().add(color); + } + var del = new MenuItem(AppI18n.get("remove"), new FontIcon("mdal-delete_outline")); del.disableProperty().bind(wrapper.getDeletable().not()); del.setOnAction(event -> wrapper.delete()); diff --git a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryWrapper.java b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryWrapper.java index 8355a17b..7a5a9b7d 100644 --- a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryWrapper.java +++ b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryWrapper.java @@ -7,6 +7,7 @@ import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreCategory; +import io.xpipe.app.storage.DataStoreColor; import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.util.ThreadHelper; import javafx.beans.binding.Bindings; @@ -37,6 +38,7 @@ public class StoreEntryWrapper { private final BooleanProperty expanded = new SimpleBooleanProperty(); private final Property persistentState = new SimpleObjectProperty<>(); private final MapProperty cache = new SimpleMapProperty<>(FXCollections.observableHashMap()); + private final Property color = new SimpleObjectProperty<>(); public StoreEntryWrapper(DataStoreEntry entry) { this.entry = entry; @@ -146,6 +148,7 @@ public class StoreEntryWrapper { observing.setValue(entry.isObserving()); persistentState.setValue(entry.getStorePersistentState()); cache.putAll(entry.getStoreCache()); + color.setValue(entry.getColor()); inRefresh.setValue(entry.isInRefresh()); deletable.setValue(entry.getConfiguration().isDeletable() diff --git a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreSectionComp.java b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreSectionComp.java index cd83fbbd..c2db30ce 100644 --- a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreSectionComp.java +++ b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreSectionComp.java @@ -9,16 +9,20 @@ import io.xpipe.app.fxcomps.impl.IconButtonComp; import io.xpipe.app.fxcomps.impl.VerticalComp; import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.fxcomps.util.SimpleChangeListener; +import io.xpipe.app.storage.DataStoreColor; import javafx.beans.binding.Bindings; import javafx.css.PseudoClass; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import javafx.scene.layout.VBox; +import java.util.Arrays; import java.util.List; public class StoreSectionComp extends Comp> { + private static final PseudoClass ROOT = PseudoClass.getPseudoClass("root"); + private static final PseudoClass SUB = PseudoClass.getPseudoClass("sub"); private static final PseudoClass ODD = PseudoClass.getPseudoClass("odd-depth"); private static final PseudoClass EVEN = PseudoClass.getPseudoClass("even-depth"); public static final PseudoClass EXPANDED = PseudoClass.getPseudoClass("expanded"); @@ -80,6 +84,23 @@ public class StoreSectionComp extends Comp> { }); struc.get().pseudoClassStateChanged(EVEN, section.getDepth() % 2 == 0); struc.get().pseudoClassStateChanged(ODD, section.getDepth() % 2 != 0); + }).apply(struc -> SimpleChangeListener.apply(section.getWrapper().getColor(), val -> { + if (!topLevel) { + return; + } + + struc.get().getStyleClass().removeIf(s -> Arrays.stream(DataStoreColor.values()) + .anyMatch(dataStoreColor -> dataStoreColor.getId().equals(s))); + struc.get().getStyleClass().remove("none"); + if (val != null) { + struc.get().getStyleClass().add(val.getId()); + } else { + struc.get().getStyleClass().add("none"); + } + })) + .apply(struc -> { + struc.get().pseudoClassStateChanged(ROOT, topLevel); + struc.get().pseudoClassStateChanged(SUB, !topLevel); }) .createStructure(); } diff --git a/app/src/main/java/io/xpipe/app/core/AppTheme.java b/app/src/main/java/io/xpipe/app/core/AppTheme.java index cf56267b..70554b79 100644 --- a/app/src/main/java/io/xpipe/app/core/AppTheme.java +++ b/app/src/main/java/io/xpipe/app/core/AppTheme.java @@ -21,6 +21,7 @@ import javafx.scene.layout.Pane; import javafx.stage.Window; import javafx.util.Duration; import lombok.AllArgsConstructor; +import lombok.Getter; import lombok.SneakyThrows; import java.nio.file.Files; @@ -40,6 +41,9 @@ public class AppTheme { return; } + Theme.ALL.forEach(theme -> stage.getScene().getRoot().getStyleClass().remove(theme.getCssId())); + stage.getScene().getRoot().getStyleClass().add(t.getCssId()); + stage.getScene().getRoot().pseudoClassStateChanged(LIGHT, !t.isDark()); stage.getScene().getRoot().pseudoClassStateChanged(DARK, t.isDark()); SimpleChangeListener.apply(AppPrefs.get().performanceMode(),val -> { @@ -130,8 +134,8 @@ public class AppTheme { private final String name; - public DerivedTheme(String id, String name, atlantafx.base.theme.Theme theme) { - super(id, theme); + public DerivedTheme(String id, String cssId, String name, atlantafx.base.theme.Theme theme) { + super(id, cssId, theme); this.name = name; } @@ -165,16 +169,16 @@ public class AppTheme { @AllArgsConstructor public static class Theme implements PrefsChoiceValue { - public static final Theme PRIMER_LIGHT = new Theme("light", new PrimerLight()); - public static final Theme PRIMER_DARK = new Theme("dark", new PrimerDark()); - public static final Theme NORD_LIGHT = new Theme("nordLight", new NordLight()); - public static final Theme NORD_DARK = new Theme("nordDark", new NordDark()); - public static final Theme CUPERTINO_LIGHT = new Theme("cupertinoLight", new CupertinoLight()); - public static final Theme CUPERTINO_DARK = new Theme("cupertinoDark", new CupertinoDark()); - public static final Theme DRACULA = new Theme("dracula", new Dracula()); + public static final Theme PRIMER_LIGHT = new Theme("light", "primer", new PrimerLight()); + public static final Theme PRIMER_DARK = new Theme("dark", "primer", new PrimerDark()); + public static final Theme NORD_LIGHT = new Theme("nordLight", "nord", new NordLight()); + public static final Theme NORD_DARK = new Theme("nordDark", "nord", new NordDark()); + public static final Theme CUPERTINO_LIGHT = new Theme("cupertinoLight", "cupertino", new CupertinoLight()); + public static final Theme CUPERTINO_DARK = new Theme("cupertinoDark", "cupertino", new CupertinoDark()); + public static final Theme DRACULA = new Theme("dracula", "dracula", new Dracula()); // Adjust this to create your own theme - public static final Theme CUSTOM = new DerivedTheme("custom", "Custom", new PrimerDark()); + public static final Theme CUSTOM = new DerivedTheme("custom", "primer", "Custom", new PrimerDark()); // Also include your custom theme here public static final List ALL = List.of(PRIMER_LIGHT, PRIMER_DARK, NORD_LIGHT, NORD_DARK, CUPERTINO_LIGHT, CUPERTINO_DARK, DRACULA); @@ -196,6 +200,8 @@ public class AppTheme { } protected final String id; + @Getter + protected final String cssId; protected final atlantafx.base.theme.Theme theme; public boolean isDark() { diff --git a/app/src/main/java/io/xpipe/app/storage/DataStoreColor.java b/app/src/main/java/io/xpipe/app/storage/DataStoreColor.java new file mode 100644 index 00000000..833f4acb --- /dev/null +++ b/app/src/main/java/io/xpipe/app/storage/DataStoreColor.java @@ -0,0 +1,27 @@ +package io.xpipe.app.storage; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Getter; + +@Getter +public enum DataStoreColor { + @JsonProperty("red") + RED("red", "\uD83D\uDFE5"), + + @JsonProperty("green") + GREEN("green", "\uD83D\uDFE9"), + + @JsonProperty("yellow") + YELLOW("yellow", "\uD83D\uDFE8"), + + @JsonProperty("blue") + BLUE("blue", "\uD83D\uDFE6"); + + private final String id; + private final String emoji; + + DataStoreColor(String id, String emoji) { + this.id = id; + this.emoji = emoji; + } +} diff --git a/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java b/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java index 959186e6..8e8be60e 100644 --- a/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java +++ b/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java @@ -62,6 +62,10 @@ public class DataStoreEntry extends StorageElement { @NonFinal JsonNode storePersistentStateNode; + + @NonFinal + DataStoreColor color; + private DataStoreEntry( Path directory, UUID uuid, @@ -74,7 +78,8 @@ public class DataStoreEntry extends StorageElement { Validity validity, Configuration configuration, JsonNode storePersistentState, - boolean expanded) { + boolean expanded, DataStoreColor color + ) { super(directory, uuid, name, lastUsed, lastModified, dirty); this.categoryUuid = categoryUuid; this.store = DataStorageParser.storeFromNode(storeNode); @@ -82,6 +87,7 @@ public class DataStoreEntry extends StorageElement { this.validity = validity; this.configuration = configuration; this.expanded = expanded; + this.color = color; this.provider = store != null ? DataStoreProviders.byStoreClass(store.getClass()).orElse(null) : null; @@ -103,7 +109,8 @@ public class DataStoreEntry extends StorageElement { store.isComplete() ? Validity.COMPLETE : Validity.INCOMPLETE, Configuration.defaultConfiguration(), null, - false); + false, null + ); entry.refresh(); return entry; } @@ -119,7 +126,8 @@ public class DataStoreEntry extends StorageElement { JsonNode storeNode, Configuration configuration, JsonNode storePersistentState, - boolean expanded) { + boolean expanded, + DataStoreColor color) { return new DataStoreEntry( directory, uuid, @@ -132,7 +140,8 @@ public class DataStoreEntry extends StorageElement { Validity.INCOMPLETE, configuration, storePersistentState, - expanded); + expanded, color + ); } public static DataStoreEntry fromDirectory(Path dir) throws Exception { @@ -178,6 +187,15 @@ public class DataStoreEntry extends StorageElement { var expanded = Optional.ofNullable(stateJson.get("expanded")) .map(jsonNode -> jsonNode.booleanValue()) .orElse(true); + var color = Optional.ofNullable(stateJson.get("color")) + .map(node -> { + try { + return mapper.treeToValue(node, DataStoreColor.class); + } catch (JsonProcessingException e) { + return null; + } + }) + .orElse(null); // Store loading is prone to errors. JsonNode storeNode = null; @@ -196,7 +214,8 @@ public class DataStoreEntry extends StorageElement { storeNode, configuration, persistentState, - expanded); + expanded, + color); } public void setInRefresh(boolean newRefresh) { @@ -274,6 +293,15 @@ public class DataStoreEntry extends StorageElement { } } + public void setColor(DataStoreColor newColor) { + var changed = !Objects.equals(color, newColor); + this.color = newColor; + if (changed) { + dirty = true; + notifyUpdate(); + } + } + public boolean isDisabled() { return validity == Validity.LOAD_FAILED; } @@ -431,6 +459,7 @@ public class DataStoreEntry extends StorageElement { obj.put("categoryUuid", categoryUuid.toString()); stateObj.put("lastUsed", lastUsed.toString()); stateObj.put("lastModified", lastModified.toString()); + stateObj.set("color", mapper.valueToTree(color)); stateObj.set("persistentState", storePersistentStateNode); obj.set("configuration", mapper.valueToTree(configuration)); stateObj.put("expanded", expanded); diff --git a/app/src/main/resources/io/xpipe/app/resources/lang/translations_en.properties b/app/src/main/resources/io/xpipe/app/resources/lang/translations_en.properties index 58704584..5c6ec0b9 100644 --- a/app/src/main/resources/io/xpipe/app/resources/lang/translations_en.properties +++ b/app/src/main/resources/io/xpipe/app/resources/lang/translations_en.properties @@ -5,6 +5,7 @@ lf=LF (Linux) none=None common=Common key=Key +color=Color passwordManager=Password manager prompt=Prompt customCommand=Custom command diff --git a/app/src/main/resources/io/xpipe/app/resources/style/header-bars.css b/app/src/main/resources/io/xpipe/app/resources/style/header-bars.css index 932227d4..6c874874 100644 --- a/app/src/main/resources/io/xpipe/app/resources/style/header-bars.css +++ b/app/src/main/resources/io/xpipe/app/resources/style/header-bars.css @@ -13,6 +13,16 @@ -fx-spacing: 0.8em; } +.root.nord .store-header-bar { + -fx-background-radius: 0; + -fx-border-radius: 0; +} + +.root.nord .bar { + -fx-background-radius: 0; + -fx-border-radius: 0; +} + .bar .filter-bar .text-field { -fx-padding: 0.35em; -fx-text-fill: -color-fg-default; @@ -49,6 +59,11 @@ -fx-spacing: 0.2em; } +.root.nord .store-creation-bar, .root.nord .store-sort-bar, .root.nord .store-category-bar { + -fx-background-radius: 0; + -fx-border-radius: 0; +} + .store-category-bar { -fx-padding: 0.8em 0.5em 0.8em 0.5em; -fx-background-color: -color-bg-subtle; diff --git a/app/src/main/resources/io/xpipe/app/resources/style/store-entry-comp.css b/app/src/main/resources/io/xpipe/app/resources/style/store-entry-comp.css index dce8897b..fa9fb36d 100644 --- a/app/src/main/resources/io/xpipe/app/resources/style/store-entry-comp.css +++ b/app/src/main/resources/io/xpipe/app/resources/style/store-entry-comp.css @@ -1,3 +1,12 @@ +.store-list-comp .top { + -fx-border-width: 0 0 0.5em 0; + -fx-background-insets: 0 0 0.5em 0; + -fx-border-color: transparent; + -fx-background-color: transparent; +} + +/* Grid */ + .store-entry-grid .date, .store-entry-grid .summary { -fx-text-fill: -color-fg-muted; } @@ -21,7 +30,11 @@ .store-entry-grid .icon { -fx-background-color: -color-bg-overlay; --fx-background-radius: 5px; + -fx-background-radius: 5px; +} + +.root.nord .store-entry-grid .icon { + -fx-background-radius: 3; } .root:pretty .store-entry-grid .icon { @@ -41,34 +54,16 @@ -fx-padding: 1px 6px 1px 6px; } -.store-list-comp .top { --fx-border-width: 0 0 0.7em 0; --fx-background-insets: 0 0 0.7em 0; --fx-border-color: transparent; --fx-background-color: transparent; -} - -.store-entry-section-comp:expanded:odd-depth { --fx-background-color: -color-bg-default; --fx-background-radius: 4px; -} - -.store-entry-section-comp:expanded:even-depth { --fx-background-radius: 4px; -} - -.root:light .store-entry-section-comp:expanded:even-depth { --fx-background-color: derive(-color-bg-default, -3%); -} - -.root:dark .store-entry-section-comp:expanded:even-depth { --fx-background-color: derive(-color-bg-default, 5%); --fx-border-color: -color-border-subtle; -} +/* Entry */ .store-entry-comp { -fx-border-color: transparent; -fx-background-color: transparent; + -fx-background-radius: 4px; +} + +.root.nord .store-entry-comp { + -fx-background-radius: 0; } .store-entry-comp:hover { @@ -99,6 +94,8 @@ -fx-padding: 6px; } +/* Section */ + .store-entry-section-comp .separator { -fx-padding: 0 0.75em 0 0.75em; -fx-border-insets: 0px; @@ -115,24 +112,146 @@ -fx-pref-height: 1; } -.top > .store-entry-section-comp { --fx-background-color: -color-bg-default; --fx-background-radius: 4px; -} - .root:pretty .top > .store-entry-section-comp { --fx-effect: dropshadow(three-pass-box, -color-shadow-default, 3px, 0.5, 0, 1); +-fx-effect: dropshadow(three-pass-box, -color-shadow-default, 2px, 0.5, 0, 1); } -.store-entry-section-comp:expanded { --fx-border-radius: 4px; --fx-border-width: 1px; --fx-border-color: -color-border-default; +.store-entry-section-comp { + -fx-border-radius: 4px; + -fx-background-radius: 4px; +} + +.root.nord .store-entry-section-comp { + -fx-border-radius: 0; + -fx-background-radius: 0; } .store-entry-section-comp .list-box-view-comp .content { -fx-spacing: 0.2em; } +.store-entry-section-comp.none { + -fx-background-color: -color-bg-default; + -fx-border-color: -color-border-default; +} + +/* Colors */ + +.root:light .top > .store-entry-section-comp.blue { + -fx-background-color: linear-gradient(from 100% 0% to 0% 100% , rgb(130, 130, 250, 0.2) 40%, rgb(57, 57, 200, 0.2) 50%, rgb(137, 137, 250, 0.2) 100%); + -fx-border-color: rgba(80, 100, 150, 0.3); +} + +.root:light .top > .store-entry-section-comp.blue > .separator .line { + -fx-border-color: rgba(80, 100, 150, 0.4); +} + +.root:dark .top > .store-entry-section-comp.blue { + -fx-background-color: linear-gradient(from 100% 0% to 0% 100% , rgb(30, 30, 80, 0.8) 40%, rgb(27, 27, 65, 0.8) 50%, rgb(37, 37, 100, 0.8) 100%); + -fx-border-color: rgba(80, 100, 150, 0.7); +} + +.root:dark .top > .store-entry-section-comp.blue > .separator .line { + -fx-border-color: rgba(80, 100, 150, 0.7); +} + +.root:light .top > .store-entry-section-comp.red { + -fx-background-color: linear-gradient(from 100% 0% to 0% 100% , rgb(220, 100, 100, 0.15) 40%, rgb(205, 50, 50, 0.15) 50%, rgb(200, 90, 90, 0.15) 100%); + -fx-border-color: rgba(150, 100, 80, 0.4); +} + +.root:light .top > .store-entry-section-comp.red > .separator .line { + -fx-border-color: rgba(150, 100, 80, 0.4); +} + +.root:dark .top > .store-entry-section-comp.red { + -fx-background-color: linear-gradient(from 100% 0% to 0% 100% , rgb(80, 30, 30, 0.4) 40%, rgb(65, 27, 27, 0.4) 50%, rgb(100, 37, 37, 0.4) 100%); + -fx-border-color: rgba(150, 100, 80, 0.4); +} + +.root:dark .top > .store-entry-section-comp.red > .separator .line { + -fx-border-color: rgba(150, 100, 80, 0.4); +} + +.root:light .top > .store-entry-section-comp.yellow { + -fx-background-color: linear-gradient(from 100% 0% to 0% 100% , rgb(180, 180, 30, 0.2) 40%, rgb(135, 135, 27, 0.2) 50%, rgb(200, 200, 37, 0.2) 100%); + -fx-border-color: rgba(170, 170, 80, 0.3); +} + +.root:light .top > .store-entry-section-comp.yellow > .separator .line { + -fx-border-color: rgba(170, 170, 80, 0.5); +} + +.root:dark .top > .store-entry-section-comp.yellow { + -fx-background-color: linear-gradient(from 100% 0% to 0% 100% , rgb(80, 80, 30, 0.4) 40%, rgb(65, 65, 27, 0.4) 50%, rgb(100, 100, 37, 0.4) 100%); + -fx-border-color: rgba(150, 150, 80, 0.4); +} + +.root:dark .top > .store-entry-section-comp.yellow > .separator .line { + -fx-border-color: rgba(170, 170, 80, 0.3); +} + +.root:light .top > .store-entry-section-comp.green { + -fx-background-color: linear-gradient(from 100% 0% to 0% 100% , rgb(30, 180, 30, 0.1) 40%, rgb(20, 120, 20, 0.15) 50%, rgb(37, 200, 37, 0.1) 100%); + -fx-border-color: rgba(100, 150, 80, 0.2); +} + +.root:light .top > .store-entry-section-comp.green > .separator .line { + -fx-border-color: rgba(100, 150, 80, 0.4); +} + +.root:dark .top > .store-entry-section-comp.green { + -fx-background-color: linear-gradient(from 100% 0% to 0% 100% , rgb(30, 80, 30, 0.3) 40%, rgb(20, 60, 20, 0.3) 50%, rgb(37, 100, 37, 0.3) 100%); + -fx-border-color: rgba(100, 190, 80, 0.3); +} + +.root:dark .top > .store-entry-section-comp.green > .separator .line { + -fx-border-color: rgba(100, 190, 80, 0.2); +} + +/* Light sub backgrounds */ + +.root:light .store-entry-section-comp:sub:expanded { + -fx-border-color: #9999; +} + +.root:light .store-entry-section-comp.none .store-entry-section-comp:expanded:even-depth { + -fx-background-color: derive(-color-bg-default, -3%); +} + +.root:light .store-entry-section-comp.none .store-entry-section-comp:expanded:odd-depth { + -fx-background-color: -color-bg-default; +} + +.root:light .store-entry-section-comp:sub:expanded:even-depth { + -fx-background-color: #ddd5; +} + +.root:light .store-entry-section-comp:sub:expanded:odd-depth { + -fx-background-color: #aaa3; +} + +/* Dark sub backgrounds */ + +.root:dark .store-entry-section-comp:sub:expanded { + -fx-border-color: #4449; +} + +.root:dark .store-entry-section-comp.none .store-entry-section-comp:expanded:even-depth { + -fx-background-color: derive(-color-bg-default, 5%); +} + +.root:dark .store-entry-section-comp.none .store-entry-section-comp:expanded:odd-depth { + -fx-background-color: -color-bg-default; +} + +.root:dark .store-entry-section-comp:sub:expanded:even-depth { + -fx-background-color: #1114; +} + +.root:dark .store-entry-section-comp:sub:expanded:odd-depth { + -fx-background-color: #2224; +} +