Improve store styling

This commit is contained in:
crschnick 2023-07-02 10:09:38 +00:00
parent 1e714e2c4a
commit 1ba5f7cf2a
9 changed files with 90 additions and 59 deletions

View file

@ -36,23 +36,25 @@ public class ListBoxViewComp<T> extends Comp<CompStructure<ScrollPane>> {
public CompStructure<ScrollPane> createBase() { public CompStructure<ScrollPane> createBase() {
Map<T, Region> cache = new HashMap<>(); Map<T, Region> cache = new HashMap<>();
VBox listView = new VBox(); VBox vbox = new VBox();
listView.setFocusTraversable(false); vbox.getStyleClass().add("content");
vbox.setFocusTraversable(false);
refresh(listView, shown, all, cache, false); refresh(vbox, shown, all, cache, false);
listView.requestLayout(); vbox.requestLayout();
shown.addListener((ListChangeListener<? super T>) (c) -> { shown.addListener((ListChangeListener<? super T>) (c) -> {
refresh(listView, c.getList(), all, cache, true); refresh(vbox, c.getList(), all, cache, true);
}); });
all.addListener((ListChangeListener<? super T>) c -> { all.addListener((ListChangeListener<? super T>) c -> {
cache.keySet().retainAll(c.getList()); cache.keySet().retainAll(c.getList());
}); });
var scroll = new ScrollPane(listView); var scroll = new ScrollPane(vbox);
scroll.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); scroll.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
scroll.setFitToWidth(true); scroll.setFitToWidth(true);
scroll.getStyleClass().add("list-box-view-comp");
return new SimpleCompStructure<>(scroll); return new SimpleCompStructure<>(scroll);
} }

View file

@ -34,12 +34,12 @@ import java.util.ArrayList;
public abstract class StoreEntryComp extends SimpleComp { public abstract class StoreEntryComp extends SimpleComp {
public static Comp<?> customSection(StoreEntryWrapper e) { public static Comp<?> customSection(StoreSection e) {
var prov = e.getEntry().getProvider(); var prov = e.getWrapper().getEntry().getProvider();
if (prov != null) { if (prov != null) {
return prov.customDisplay(e); return prov.customDisplay(e);
} else { } else {
return new StandardStoreEntryComp(e, null); return new StandardStoreEntryComp(e.getWrapper(), null);
} }
} }

View file

@ -26,8 +26,8 @@ public class StoreEntryListComp extends SimpleComp {
.map(s -> (storeEntrySection -> storeEntrySection.shouldShow(s)))); .map(s -> (storeEntrySection -> storeEntrySection.shouldShow(s))));
var content = new ListBoxViewComp<>(filtered, topLevel.getChildren(), (StoreSection e) -> { var content = new ListBoxViewComp<>(filtered, topLevel.getChildren(), (StoreSection e) -> {
var custom = StoreSection.customSection(e).hgrow(); var custom = StoreSection.customSection(e).hgrow();
return new HorizontalComp(List.of(Comp.spacer(20), custom, Comp.spacer(20))).styleClass("top"); return new HorizontalComp(List.of(Comp.spacer(10), custom, Comp.spacer(10))).styleClass("top");
}).apply(struc -> ((Region) struc.get().getContent()).setPadding(new Insets(20, 0, 20, 0))); }).apply(struc -> ((Region) struc.get().getContent()).setPadding(new Insets(10, 0, 10, 0)));
return content.styleClass("store-list-comp"); return content.styleClass("store-list-comp");
} }

View file

@ -4,6 +4,9 @@ import io.xpipe.app.comp.storage.StorageFilter;
import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.fxcomps.util.BindingsHelper;
import io.xpipe.app.storage.DataStorage; 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.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import lombok.Value; import lombok.Value;
@ -19,12 +22,30 @@ public class StoreSection implements StorageFilter.Filterable {
if (prov != null) { if (prov != null) {
return prov.customContainer(e); return prov.customContainer(e);
} else { } else {
return new StoreEntrySectionComp(e); return new StoreSectionComp(e);
} }
} }
StoreEntryWrapper wrapper; StoreEntryWrapper wrapper;
ObservableList<StoreSection> children; ObservableList<StoreSection> children;
int depth;
ObservableBooleanValue showDetails;
public StoreSection(StoreEntryWrapper wrapper, ObservableList<StoreSection> 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<StoreSection> COMPARATOR = Comparator.<StoreSection, Instant>comparing( private static final Comparator<StoreSection> COMPARATOR = Comparator.<StoreSection, Instant>comparing(
o -> o.wrapper.getEntry().getState().isUsable() o -> o.wrapper.getEntry().getState().isUsable()
@ -36,19 +57,19 @@ public class StoreSection implements StorageFilter.Filterable {
public static StoreSection createTopLevel() { public static StoreSection createTopLevel() {
var topLevel = BindingsHelper.mappedContentBinding( var topLevel = BindingsHelper.mappedContentBinding(
StoreViewState.get().getAllEntries(), storeEntryWrapper -> create(storeEntryWrapper)); StoreViewState.get().getAllEntries(), storeEntryWrapper -> create(storeEntryWrapper, 1));
var filtered = BindingsHelper.filteredContentBinding(topLevel, section -> { var filtered = BindingsHelper.filteredContentBinding(topLevel, section -> {
return DataStorage.get() return DataStorage.get()
.getParent(section.getWrapper().getEntry(), true) .getParent(section.getWrapper().getEntry(), true)
.isEmpty(); .isEmpty();
}); });
var ordered = BindingsHelper.orderedContentBinding(filtered, COMPARATOR); 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()) { if (!e.getEntry().getState().isUsable()) {
return new StoreSection(e, FXCollections.observableArrayList()); return new StoreSection(e, FXCollections.observableArrayList(), depth);
} }
var filtered = var filtered =
@ -58,9 +79,9 @@ public class StoreSection implements StorageFilter.Filterable {
.map(found -> found.equals(e.getEntry())) .map(found -> found.equals(e.getEntry()))
.orElse(false); .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); var ordered = BindingsHelper.orderedContentBinding(children, COMPARATOR);
return new StoreSection(e, ordered); return new StoreSection(e, ordered, depth);
} }
@Override @Override

View file

@ -1,6 +1,5 @@
package io.xpipe.app.comp.storage.store; package io.xpipe.app.comp.storage.store;
import atlantafx.base.theme.Styles;
import io.xpipe.app.comp.base.ListBoxViewComp; import io.xpipe.app.comp.base.ListBoxViewComp;
import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.CompStructure; 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 io.xpipe.app.fxcomps.util.SimpleChangeListener;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.css.PseudoClass; import javafx.css.PseudoClass;
import javafx.scene.layout.*; import javafx.scene.layout.HBox;
import javafx.scene.paint.Color; import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import java.util.List; import java.util.List;
public class StoreEntrySectionComp extends Comp<CompStructure<VBox>> { public class StoreSectionComp extends Comp<CompStructure<VBox>> {
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"); public static final PseudoClass EXPANDED = PseudoClass.getPseudoClass("expanded");
private final StoreSection section; private final StoreSection section;
public StoreEntrySectionComp(StoreSection section) { public StoreSectionComp(StoreSection section) {
this.section = section; this.section = section;
} }
@Override @Override
public CompStructure<VBox> createBase() { public CompStructure<VBox> 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( var button = new IconButtonComp(
Bindings.createStringBinding( Bindings.createStringBinding(
() -> section.getWrapper().getExpanded().get() () -> section.getWrapper().getExpanded().get()
@ -57,15 +59,7 @@ public class StoreEntrySectionComp extends Comp<CompStructure<VBox>> {
.map(s -> (storeEntrySection -> storeEntrySection.shouldShow(s)))); .map(s -> (storeEntrySection -> storeEntrySection.shouldShow(s))));
var content = new ListBoxViewComp<>(shown, all, (StoreSection e) -> { var content = new ListBoxViewComp<>(shown, all, (StoreSection e) -> {
return StoreSection.customSection(e).apply(GrowAugment.create(true, false)); return StoreSection.customSection(e).apply(GrowAugment.create(true, false));
}) }).hgrow();
.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;
});
var expanded = Bindings.createBooleanBinding(() -> { var expanded = Bindings.createBooleanBinding(() -> {
return section.getWrapper().getExpanded().get() && section.getChildren().size() > 0; return section.getWrapper().getExpanded().get() && section.getChildren().size() > 0;
@ -75,18 +69,20 @@ public class StoreEntrySectionComp extends Comp<CompStructure<VBox>> {
new HorizontalComp(topEntryList) new HorizontalComp(topEntryList)
.apply(struc -> struc.get().setFillHeight(true)), .apply(struc -> struc.get().setFillHeight(true)),
Comp.separator().visible(expanded), Comp.separator().visible(expanded),
new HorizontalComp(List.of(spacer, content)) new HorizontalComp(List.of(content))
.styleClass("content")
.apply(struc -> struc.get().setFillHeight(true)) .apply(struc -> struc.get().setFillHeight(true))
.hide(BindingsHelper.persist(Bindings.or( .hide(BindingsHelper.persist(Bindings.or(
Bindings.not(section.getWrapper().getExpanded()), Bindings.not(section.getWrapper().getExpanded()),
Bindings.size(section.getChildren()).isEqualTo(0)))))) Bindings.size(section.getChildren()).isEqualTo(0))))))
.styleClass("store-entry-section-comp") .styleClass("store-entry-section-comp")
.styleClass(Styles.ELEVATED_1)
.apply(struc -> { .apply(struc -> {
struc.get().setFillWidth(true); struc.get().setFillWidth(true);
SimpleChangeListener.apply(expanded, val -> { SimpleChangeListener.apply(expanded, val -> {
struc.get().pseudoClassStateChanged(EXPANDED, val); struc.get().pseudoClassStateChanged(EXPANDED, val);
}); });
struc.get().pseudoClassStateChanged(EVEN, section.getDepth() % 2 == 0);
struc.get().pseudoClassStateChanged(ODD, section.getDepth() % 2 != 0);
}) })
.createStructure(); .createStructure();
} }

View file

@ -1,6 +1,5 @@
package io.xpipe.app.comp.storage.store; package io.xpipe.app.comp.storage.store;
import atlantafx.base.theme.Styles;
import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.fxcomps.impl.VerticalComp; import io.xpipe.app.fxcomps.impl.VerticalComp;
@ -14,8 +13,8 @@ public class StoreSidebarComp extends SimpleComp {
@Override @Override
protected Region createSimple() { protected Region createSimple() {
var sideBar = new VerticalComp(List.of( var sideBar = new VerticalComp(List.of(
new StoreEntryListHeaderComp().styleClass(Styles.ELEVATED_1), new StoreEntryListHeaderComp(),
new StoreCreationBarComp().styleClass(Styles.ELEVATED_1), new StoreCreationBarComp(),
Comp.of(() -> new Region()).styleClass("bar").styleClass("filler-bar"))); Comp.of(() -> new Region()).styleClass("bar").styleClass("filler-bar")));
sideBar.apply(s -> VBox.setVgrow(s.get().getChildren().get(2), Priority.ALWAYS)); sideBar.apply(s -> VBox.setVgrow(s.get().getChildren().get(2), Priority.ALWAYS));
sideBar.styleClass("sidebar"); sideBar.styleClass("sidebar");

View file

@ -3,7 +3,7 @@ package io.xpipe.app.ext;
import io.xpipe.app.comp.base.MarkdownComp; import io.xpipe.app.comp.base.MarkdownComp;
import io.xpipe.app.comp.base.SystemStateComp; import io.xpipe.app.comp.base.SystemStateComp;
import io.xpipe.app.comp.storage.store.StandardStoreEntryComp; 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.StoreEntryWrapper;
import io.xpipe.app.comp.storage.store.StoreSection; import io.xpipe.app.comp.storage.store.StoreSection;
import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppI18n;
@ -34,12 +34,12 @@ public interface DataStoreProvider {
} }
} }
default Comp<?> customDisplay(StoreEntryWrapper w) { default Comp<?> customDisplay(StoreSection s) {
return new StandardStoreEntryComp(w, null); return new StandardStoreEntryComp(s.getWrapper(), null);
} }
default Comp<?> customContainer(StoreSection section) { default Comp<?> customContainer(StoreSection section) {
return new StoreEntrySectionComp(section); return new StoreSectionComp(section);
} }
default String failureInfo() { default String failureInfo() {

View file

@ -1,7 +1,8 @@
.bar { .bar {
-fx-padding: 0.8em 1.0em 0.8em 1.0em; -fx-padding: 0.8em 1.0em 0.8em 1.0em;
-fx-background-color: -color-bg-subtle; -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 { .store-header-bar {
@ -25,7 +26,7 @@
} }
.sidebar { .sidebar {
-fx-spacing: 5px; -fx-spacing: 0.75em;
} }
.bar .button-comp { .bar .button-comp {

View file

@ -32,21 +32,19 @@
} }
.store-list-comp .top { .store-list-comp .top {
-fx-border-width: 0 0 1em 0; -fx-border-width: 0 0 0.7em 0;
-fx-background-insets: 0 0 1em 0; -fx-background-insets: 0 0 0.7em 0;
-fx-border-color: transparent; -fx-border-color: transparent;
} }
.store-list-comp .top:odd .store-entry-section-comp { .store-entry-section-comp:expanded:odd-depth {
-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 {
-fx-background-color: -color-bg-default; -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 { .store-entry-comp:hover {
@ -62,21 +60,35 @@
} }
.store-entry-section-comp .separator { .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; -fx-border-insets: 0px;
} }
.store-entry-section-comp > .content {
-fx-padding: 5px 0 5px 25px;
}
.store-entry-section-comp .separator .line { .store-entry-section-comp .separator .line {
-fx-padding: 0; -fx-padding: 0;
-fx-border-insets: 0px; -fx-border-insets: 0px;
-fx-background-color: -color-border-subtle;
-fx-pref-height: 1;
} }
.store-entry-section-comp * { .top > .store-entry-section-comp {
-fx-spacing: 0.5em; -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 { .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;
} }