From 1ba5f7cf2adb5ccdfb7d6e1d94fa1b8b01fe81d9 Mon Sep 17 00:00:00 2001 From: crschnick Date: Sun, 2 Jul 2023 10:09:38 +0000 Subject: [PATCH] Improve store styling --- .../xpipe/app/comp/base/ListBoxViewComp.java | 14 ++++--- .../comp/storage/store/StoreEntryComp.java | 6 +-- .../storage/store/StoreEntryListComp.java | 4 +- .../app/comp/storage/store/StoreSection.java | 35 ++++++++++++---- ...SectionComp.java => StoreSectionComp.java} | 30 ++++++------- .../comp/storage/store/StoreSidebarComp.java | 5 +-- .../io/xpipe/app/ext/DataStoreProvider.java | 8 ++-- .../xpipe/app/resources/style/header-bars.css | 5 ++- .../app/resources/style/store-entry-comp.css | 42 ++++++++++++------- 9 files changed, 90 insertions(+), 59 deletions(-) rename app/src/main/java/io/xpipe/app/comp/storage/store/{StoreEntrySectionComp.java => StoreSectionComp.java} (79%) diff --git a/app/src/main/java/io/xpipe/app/comp/base/ListBoxViewComp.java b/app/src/main/java/io/xpipe/app/comp/base/ListBoxViewComp.java index d6a029e4e..7717da339 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/ListBoxViewComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/ListBoxViewComp.java @@ -36,23 +36,25 @@ public class ListBoxViewComp extends Comp> { public CompStructure createBase() { Map cache = new HashMap<>(); - VBox listView = new VBox(); - listView.setFocusTraversable(false); + VBox vbox = new VBox(); + vbox.getStyleClass().add("content"); + vbox.setFocusTraversable(false); - refresh(listView, shown, all, cache, false); - listView.requestLayout(); + refresh(vbox, shown, all, cache, false); + vbox.requestLayout(); shown.addListener((ListChangeListener) (c) -> { - refresh(listView, c.getList(), all, cache, true); + refresh(vbox, c.getList(), all, cache, true); }); all.addListener((ListChangeListener) c -> { cache.keySet().retainAll(c.getList()); }); - var scroll = new ScrollPane(listView); + var scroll = new ScrollPane(vbox); scroll.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); scroll.setFitToWidth(true); + scroll.getStyleClass().add("list-box-view-comp"); return new SimpleCompStructure<>(scroll); } 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 ada199845..1773ee85c 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 @@ -34,12 +34,12 @@ import java.util.ArrayList; public abstract class StoreEntryComp extends SimpleComp { - public static Comp customSection(StoreEntryWrapper e) { - var prov = e.getEntry().getProvider(); + public static Comp customSection(StoreSection e) { + var prov = e.getWrapper().getEntry().getProvider(); if (prov != null) { return prov.customDisplay(e); } else { - return new StandardStoreEntryComp(e, null); + return new StandardStoreEntryComp(e.getWrapper(), null); } } diff --git a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryListComp.java b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryListComp.java index a58954232..917d91b1d 100644 --- a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryListComp.java +++ b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryListComp.java @@ -26,8 +26,8 @@ public class StoreEntryListComp extends SimpleComp { .map(s -> (storeEntrySection -> storeEntrySection.shouldShow(s)))); var content = new ListBoxViewComp<>(filtered, topLevel.getChildren(), (StoreSection e) -> { var custom = StoreSection.customSection(e).hgrow(); - return new HorizontalComp(List.of(Comp.spacer(20), custom, Comp.spacer(20))).styleClass("top"); - }).apply(struc -> ((Region) struc.get().getContent()).setPadding(new Insets(20, 0, 20, 0))); + return new HorizontalComp(List.of(Comp.spacer(10), custom, Comp.spacer(10))).styleClass("top"); + }).apply(struc -> ((Region) struc.get().getContent()).setPadding(new Insets(10, 0, 10, 0))); return content.styleClass("store-list-comp"); } diff --git a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreSection.java b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreSection.java index 1c99f6ef6..b6ebb6a41 100644 --- a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreSection.java +++ b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreSection.java @@ -4,6 +4,9 @@ import io.xpipe.app.comp.storage.StorageFilter; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.storage.DataStorage; +import javafx.beans.binding.Bindings; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.value.ObservableBooleanValue; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import lombok.Value; @@ -19,12 +22,30 @@ public class StoreSection implements StorageFilter.Filterable { if (prov != null) { return prov.customContainer(e); } else { - return new StoreEntrySectionComp(e); + return new StoreSectionComp(e); } } StoreEntryWrapper wrapper; ObservableList children; + int depth; + ObservableBooleanValue showDetails; + + public StoreSection(StoreEntryWrapper wrapper, ObservableList children, int depth) { + this.wrapper = wrapper; + this.children = children; + this.depth = depth; + if (wrapper != null) { + this.showDetails = Bindings.createBooleanBinding( + () -> { + return wrapper.getExpanded().get() || children.size() == 0; + }, + wrapper.getExpanded(), + children); + } else { + this.showDetails = new SimpleBooleanProperty(true); + } + } private static final Comparator COMPARATOR = Comparator.comparing( o -> o.wrapper.getEntry().getState().isUsable() @@ -36,19 +57,19 @@ public class StoreSection implements StorageFilter.Filterable { public static StoreSection createTopLevel() { var topLevel = BindingsHelper.mappedContentBinding( - StoreViewState.get().getAllEntries(), storeEntryWrapper -> create(storeEntryWrapper)); + StoreViewState.get().getAllEntries(), storeEntryWrapper -> create(storeEntryWrapper, 1)); var filtered = BindingsHelper.filteredContentBinding(topLevel, section -> { return DataStorage.get() .getParent(section.getWrapper().getEntry(), true) .isEmpty(); }); var ordered = BindingsHelper.orderedContentBinding(filtered, COMPARATOR); - return new StoreSection(null, ordered); + return new StoreSection(null, ordered, 0); } - private static StoreSection create(StoreEntryWrapper e) { + private static StoreSection create(StoreEntryWrapper e, int depth) { if (!e.getEntry().getState().isUsable()) { - return new StoreSection(e, FXCollections.observableArrayList()); + return new StoreSection(e, FXCollections.observableArrayList(), depth); } var filtered = @@ -58,9 +79,9 @@ public class StoreSection implements StorageFilter.Filterable { .map(found -> found.equals(e.getEntry())) .orElse(false); }); - var children = BindingsHelper.mappedContentBinding(filtered, entry1 -> create(entry1)); + var children = BindingsHelper.mappedContentBinding(filtered, entry1 -> create(entry1, depth + 1)); var ordered = BindingsHelper.orderedContentBinding(children, COMPARATOR); - return new StoreSection(e, ordered); + return new StoreSection(e, ordered, depth); } @Override diff --git a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntrySectionComp.java b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreSectionComp.java similarity index 79% rename from app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntrySectionComp.java rename to app/src/main/java/io/xpipe/app/comp/storage/store/StoreSectionComp.java index 6cc8b4a16..ae93c01a7 100644 --- a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntrySectionComp.java +++ b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreSectionComp.java @@ -1,6 +1,5 @@ package io.xpipe.app.comp.storage.store; -import atlantafx.base.theme.Styles; import io.xpipe.app.comp.base.ListBoxViewComp; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; @@ -12,24 +11,27 @@ import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.fxcomps.util.SimpleChangeListener; import javafx.beans.binding.Bindings; import javafx.css.PseudoClass; -import javafx.scene.layout.*; -import javafx.scene.paint.Color; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; import java.util.List; -public class StoreEntrySectionComp extends Comp> { +public class StoreSectionComp extends Comp> { + 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"); private final StoreSection section; - public StoreEntrySectionComp(StoreSection section) { + public StoreSectionComp(StoreSection section) { this.section = section; } @Override public CompStructure createBase() { - var root = StandardStoreEntryComp.customSection(section.getWrapper()).apply(struc -> HBox.setHgrow(struc.get(), Priority.ALWAYS)); + var root = StandardStoreEntryComp.customSection(section).apply(struc -> HBox.setHgrow(struc.get(), Priority.ALWAYS)); var button = new IconButtonComp( Bindings.createStringBinding( () -> section.getWrapper().getExpanded().get() @@ -57,15 +59,7 @@ public class StoreEntrySectionComp extends Comp> { .map(s -> (storeEntrySection -> storeEntrySection.shouldShow(s)))); var content = new ListBoxViewComp<>(shown, all, (StoreSection e) -> { return StoreSection.customSection(e).apply(GrowAugment.create(true, false)); - }) - .apply(struc -> HBox.setHgrow(struc.get(), Priority.ALWAYS)) - .apply(struc -> struc.get().backgroundProperty().set(Background.fill(Color.color(0, 0, 0, 0.01)))); - var spacer = Comp.of(() -> { - var padding = new Region(); - padding.setMinWidth(25); - padding.setMaxWidth(25); - return padding; - }); + }).hgrow(); var expanded = Bindings.createBooleanBinding(() -> { return section.getWrapper().getExpanded().get() && section.getChildren().size() > 0; @@ -75,18 +69,20 @@ public class StoreEntrySectionComp extends Comp> { new HorizontalComp(topEntryList) .apply(struc -> struc.get().setFillHeight(true)), Comp.separator().visible(expanded), - new HorizontalComp(List.of(spacer, content)) + new HorizontalComp(List.of(content)) + .styleClass("content") .apply(struc -> struc.get().setFillHeight(true)) .hide(BindingsHelper.persist(Bindings.or( Bindings.not(section.getWrapper().getExpanded()), Bindings.size(section.getChildren()).isEqualTo(0)))))) .styleClass("store-entry-section-comp") - .styleClass(Styles.ELEVATED_1) .apply(struc -> { struc.get().setFillWidth(true); SimpleChangeListener.apply(expanded, val -> { struc.get().pseudoClassStateChanged(EXPANDED, val); }); + struc.get().pseudoClassStateChanged(EVEN, section.getDepth() % 2 == 0); + struc.get().pseudoClassStateChanged(ODD, section.getDepth() % 2 != 0); }) .createStructure(); } diff --git a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreSidebarComp.java b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreSidebarComp.java index d5dda0fd0..4b30800f6 100644 --- a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreSidebarComp.java +++ b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreSidebarComp.java @@ -1,6 +1,5 @@ package io.xpipe.app.comp.storage.store; -import atlantafx.base.theme.Styles; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.impl.VerticalComp; @@ -14,8 +13,8 @@ public class StoreSidebarComp extends SimpleComp { @Override protected Region createSimple() { var sideBar = new VerticalComp(List.of( - new StoreEntryListHeaderComp().styleClass(Styles.ELEVATED_1), - new StoreCreationBarComp().styleClass(Styles.ELEVATED_1), + new StoreEntryListHeaderComp(), + new StoreCreationBarComp(), Comp.of(() -> new Region()).styleClass("bar").styleClass("filler-bar"))); sideBar.apply(s -> VBox.setVgrow(s.get().getChildren().get(2), Priority.ALWAYS)); sideBar.styleClass("sidebar"); diff --git a/app/src/main/java/io/xpipe/app/ext/DataStoreProvider.java b/app/src/main/java/io/xpipe/app/ext/DataStoreProvider.java index cad187873..65f50359b 100644 --- a/app/src/main/java/io/xpipe/app/ext/DataStoreProvider.java +++ b/app/src/main/java/io/xpipe/app/ext/DataStoreProvider.java @@ -3,7 +3,7 @@ package io.xpipe.app.ext; import io.xpipe.app.comp.base.MarkdownComp; import io.xpipe.app.comp.base.SystemStateComp; import io.xpipe.app.comp.storage.store.StandardStoreEntryComp; -import io.xpipe.app.comp.storage.store.StoreEntrySectionComp; +import io.xpipe.app.comp.storage.store.StoreSectionComp; import io.xpipe.app.comp.storage.store.StoreEntryWrapper; import io.xpipe.app.comp.storage.store.StoreSection; import io.xpipe.app.core.AppI18n; @@ -34,12 +34,12 @@ public interface DataStoreProvider { } } - default Comp customDisplay(StoreEntryWrapper w) { - return new StandardStoreEntryComp(w, null); + default Comp customDisplay(StoreSection s) { + return new StandardStoreEntryComp(s.getWrapper(), null); } default Comp customContainer(StoreSection section) { - return new StoreEntrySectionComp(section); + return new StoreSectionComp(section); } default String failureInfo() { 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 4f43e867d..49d96da96 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 @@ -1,7 +1,8 @@ .bar { -fx-padding: 0.8em 1.0em 0.8em 1.0em; -fx-background-color: -color-bg-subtle; --fx-border-color: -color-neutral-emphasis; +-fx-border-color: -color-border-default; +-fx-effect: dropshadow(three-pass-box, -color-shadow-default, 8px, 0.5, 0, 1); } .store-header-bar { @@ -25,7 +26,7 @@ } .sidebar { --fx-spacing: 5px; +-fx-spacing: 0.75em; } .bar .button-comp { 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 37fcf1413..3542824a8 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 @@ -32,21 +32,19 @@ } .store-list-comp .top { --fx-border-width: 0 0 1em 0; --fx-background-insets: 0 0 1em 0; +-fx-border-width: 0 0 0.7em 0; +-fx-background-insets: 0 0 0.7em 0; -fx-border-color: transparent; } -.store-list-comp .top:odd .store-entry-section-comp { --fx-background-color: -color-bg-subtle; -} - -.store-list-comp .top:even .store-entry-section-comp { --fx-background-color: -color-bg-overlay; -} - -.store-list-comp .store-entry-section-comp { +.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-color: -color-bg-subtle; +-fx-background-radius: 4px; } .store-entry-comp:hover { @@ -62,21 +60,35 @@ } .store-entry-section-comp .separator { --fx-padding: 0 0.5em 0 0.5em; +-fx-padding: 0 0.75em 0 0.75em; -fx-border-insets: 0px; } +.store-entry-section-comp > .content { +-fx-padding: 5px 0 5px 25px; +} + .store-entry-section-comp .separator .line { -fx-padding: 0; -fx-border-insets: 0px; +-fx-background-color: -color-border-subtle; +-fx-pref-height: 1; } -.store-entry-section-comp * { --fx-spacing: 0.5em; +.top > .store-entry-section-comp { +-fx-effect: dropshadow(three-pass-box, -color-shadow-default, 6px, 0.5, 0, 1); +-fx-background-color: -color-bg-default; +-fx-background-radius: 4px; } .store-entry-section-comp:expanded { --fx-background-color: -color-bg-default; +-fx-border-radius: 4px; +-fx-border-width: 1px; +-fx-border-color: -color-border-default; +} + +.store-entry-section-comp .list-box-view-comp .content { +-fx-spacing: 0.2em; }