diff --git a/sampler/src/main/java/atlantafx/sampler/Launcher.java b/sampler/src/main/java/atlantafx/sampler/Launcher.java
index 25dcddc..804f051 100755
--- a/sampler/src/main/java/atlantafx/sampler/Launcher.java
+++ b/sampler/src/main/java/atlantafx/sampler/Launcher.java
@@ -1,6 +1,9 @@
/* SPDX-License-Identifier: MIT */
package atlantafx.sampler;
+import atlantafx.sampler.event.BrowseEvent;
+import atlantafx.sampler.event.DefaultEventBus;
+import atlantafx.sampler.event.Listener;
import atlantafx.sampler.layout.ApplicationWindow;
import atlantafx.sampler.theme.ThemeManager;
import fr.brouillard.oss.cssfx.CSSFX;
@@ -63,6 +66,9 @@ public class Launcher extends Application {
stage.setResizable(true);
stage.setOnCloseRequest(t -> Platform.exit());
+ // register event listeners
+ DefaultEventBus.getInstance().subscribe(BrowseEvent.class, this::onBrowseEvent);
+
Platform.runLater(() -> {
stage.show();
stage.requestFocus();
@@ -109,4 +115,9 @@ public class Launcher extends Application {
);
CSSFX.start(scene);
}
+
+ @Listener
+ private void onBrowseEvent(BrowseEvent event) {
+ getHostServices().showDocument(event.getUri().toString());
+ }
}
diff --git a/sampler/src/main/java/atlantafx/sampler/event/BrowseEvent.java b/sampler/src/main/java/atlantafx/sampler/event/BrowseEvent.java
new file mode 100644
index 0000000..f3b288a
--- /dev/null
+++ b/sampler/src/main/java/atlantafx/sampler/event/BrowseEvent.java
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: MIT */
+package atlantafx.sampler.event;
+
+import java.net.URI;
+
+public class BrowseEvent extends Event {
+
+ private final URI uri;
+
+ public BrowseEvent(URI uri) {
+ this.uri = uri;
+ }
+
+ public URI getUri() {
+ return uri;
+ }
+
+ @Override
+ public String toString() {
+ return "BrowseEvent{" +
+ "uri=" + uri +
+ '}';
+ }
+}
diff --git a/sampler/src/main/java/atlantafx/sampler/event/DefaultEventBus.java b/sampler/src/main/java/atlantafx/sampler/event/DefaultEventBus.java
new file mode 100644
index 0000000..30286ac
--- /dev/null
+++ b/sampler/src/main/java/atlantafx/sampler/event/DefaultEventBus.java
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: MIT */
+package atlantafx.sampler.event;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.function.Consumer;
+
+/**
+ * Simple event bus implementation.
+ *
+ * Subscribe and publish events. Events are published in channels distinguished by event type.
+ * Channels can be grouped using an event type hierarchy.
+ *
+ * You can use the default event bus instance {@link #getInstance}, which is a singleton
+ * or you can create one or multiple instances of {@link DefaultEventBus}.
+ */
+@SuppressWarnings({"unchecked", "rawtypes"})
+public final class DefaultEventBus implements EventBus {
+
+ public DefaultEventBus() {}
+
+ private final Map, Set> subscribers = new ConcurrentHashMap<>();
+
+ @Override
+ public void subscribe(Class extends E> eventType, Consumer subscriber) {
+ Objects.requireNonNull(eventType);
+ Objects.requireNonNull(subscriber);
+
+ Set eventSubscribers = getOrCreateSubscribers(eventType);
+ eventSubscribers.add(subscriber);
+ }
+
+ private Set getOrCreateSubscribers(Class eventType) {
+ Set eventSubscribers = subscribers.get(eventType);
+ if (eventSubscribers == null) {
+ eventSubscribers = new CopyOnWriteArraySet<>();
+ subscribers.put(eventType, eventSubscribers);
+ }
+ return eventSubscribers;
+ }
+
+ @Override
+ public void unsubscribe(Consumer subscriber) {
+ Objects.requireNonNull(subscriber);
+
+ subscribers.values().forEach(eventSubscribers -> eventSubscribers.remove(subscriber));
+ }
+
+ @Override
+ public void unsubscribe(Class extends E> eventType, Consumer subscriber) {
+ Objects.requireNonNull(eventType);
+ Objects.requireNonNull(subscriber);
+
+ subscribers.keySet().stream()
+ .filter(eventType::isAssignableFrom)
+ .map(subscribers::get)
+ .forEach(eventSubscribers -> eventSubscribers.remove(subscriber));
+ }
+
+ @Override
+ public void publish(E event) {
+ Objects.requireNonNull(event);
+
+ Class> eventType = event.getClass();
+ subscribers.keySet().stream()
+ .filter(type -> type.isAssignableFrom(eventType))
+ .flatMap(type -> subscribers.get(type).stream())
+ .forEach(subscriber -> publish(event, subscriber));
+ }
+
+ private void publish(E event, Consumer subscriber) {
+ try {
+ subscriber.accept(event);
+ } catch (Exception e) {
+ Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), e);
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ private static class InstanceHolder {
+
+ private static final DefaultEventBus INSTANCE = new DefaultEventBus();
+ }
+
+ public static DefaultEventBus getInstance() {
+ return InstanceHolder.INSTANCE;
+ }
+}
diff --git a/sampler/src/main/java/atlantafx/sampler/event/Event.java b/sampler/src/main/java/atlantafx/sampler/event/Event.java
new file mode 100644
index 0000000..0ce42cb
--- /dev/null
+++ b/sampler/src/main/java/atlantafx/sampler/event/Event.java
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: MIT */
+package atlantafx.sampler.event;
+
+import java.util.UUID;
+
+public abstract class Event {
+
+ protected final UUID id = UUID.randomUUID();
+
+ protected Event() { }
+
+ public UUID getId() {
+ return id;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) { return true; }
+ if (o == null || getClass() != o.getClass()) { return false; }
+ Event event = (Event) o;
+ return id.equals(event.id);
+ }
+
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "Event{" +
+ "id=" + id +
+ '}';
+ }
+}
diff --git a/sampler/src/main/java/atlantafx/sampler/event/EventBus.java b/sampler/src/main/java/atlantafx/sampler/event/EventBus.java
new file mode 100644
index 0000000..71f6186
--- /dev/null
+++ b/sampler/src/main/java/atlantafx/sampler/event/EventBus.java
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: MIT */
+package atlantafx.sampler.event;
+
+import java.util.function.Consumer;
+
+public interface EventBus {
+
+ /**
+ * Subscribe to an event type
+ *
+ * @param eventType the event type, can be a super class of all events to subscribe.
+ * @param subscriber the subscriber which will consume the events.
+ * @param the event type class.
+ */
+ void subscribe(Class extends T> eventType, Consumer subscriber);
+
+ /**
+ * Unsubscribe from all event types.
+ *
+ * @param subscriber the subscriber to unsubscribe.
+ */
+ void unsubscribe(Consumer subscriber);
+
+ /**
+ * Unsubscribe from an event type.
+ *
+ * @param eventType the event type, can be a super class of all events to unsubscribe.
+ * @param subscriber the subscriber to unsubscribe.
+ * @param the event type class.
+ */
+ void unsubscribe(Class extends T> eventType, Consumer subscriber);
+
+ /**
+ * Publish an event to all subscribers.
+ *
+ * The event type is the class of event
. The event is published to all consumers which subscribed to
+ * this event type or any super class.
+ *
+ * @param event the event.
+ */
+ void publish(T event);
+
+}
\ No newline at end of file
diff --git a/sampler/src/main/java/atlantafx/sampler/event/Listener.java b/sampler/src/main/java/atlantafx/sampler/event/Listener.java
new file mode 100644
index 0000000..ef5336b
--- /dev/null
+++ b/sampler/src/main/java/atlantafx/sampler/event/Listener.java
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: MIT */
+package atlantafx.sampler.event;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+@Target(ElementType.METHOD)
+public @interface Listener {}
\ No newline at end of file
diff --git a/sampler/src/main/java/atlantafx/sampler/page/general/ColorPalette.java b/sampler/src/main/java/atlantafx/sampler/page/general/ColorPalette.java
index 7579c9b..fb04864 100644
--- a/sampler/src/main/java/atlantafx/sampler/page/general/ColorPalette.java
+++ b/sampler/src/main/java/atlantafx/sampler/page/general/ColorPalette.java
@@ -12,13 +12,18 @@ import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
+import javafx.scene.text.Text;
+import javafx.scene.text.TextFlow;
import javafx.util.Duration;
+import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
+import static atlantafx.sampler.util.Controls.hyperlink;
+
class ColorPalette extends VBox {
private final List blocks = new ArrayList<>();
@@ -41,13 +46,30 @@ class ColorPalette extends VBox {
headerBox.setAlignment(Pos.CENTER_LEFT);
headerBox.getStyleClass().add("header");
+ var noteText = new VBox(6);
+ noteText.getChildren().setAll(
+ new TextFlow(
+ new Text("Color contrast between text and its background must meet "),
+ hyperlink("required WCAG standards",
+ URI.create("https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html")
+ ),
+ new Text(":")
+ ),
+ new Text(" • 4.5:1 for normal text"),
+ new Text(" • 3:1 for large text (>24px)"),
+ new Text(" • 3:1 for UI elements and graphics"),
+ new Text(" • no contrast requirement for decorative and disabled elements"),
+ new Text(),
+ new Text("Click on any color block to observe and modify color combination via built-in contrast checker.")
+ );
+
var colorGrid = colorGrid();
backgroundProperty().addListener((obs, old, val) -> bgBaseColor.set(
val != null && !val.getFills().isEmpty() ? (Color) val.getFills().get(0).getFill() : Color.WHITE
));
- getChildren().setAll(headerBox, colorGrid);
+ getChildren().setAll(headerBox, noteText, colorGrid);
setId("color-palette");
}
@@ -56,33 +78,34 @@ class ColorPalette extends VBox {
grid.getStyleClass().add("grid");
grid.add(colorBlock("-color-fg-default", "-color-bg-default", "-color-border-default"), 0, 0);
- grid.add(colorBlock("-color-fg-muted", "-color-bg-default", "-color-border-muted"), 1, 0);
- grid.add(colorBlock("-color-fg-subtle", "-color-bg-default", "-color-border-subtle"), 2, 0);
+ grid.add(colorBlock("-color-fg-default", "-color-bg-overlay", "-color-border-default"), 1, 0);
+ grid.add(colorBlock("-color-fg-muted", "-color-bg-default", "-color-border-muted"), 2, 0);
+ grid.add(colorBlock("-color-fg-subtle", "-color-bg-default", "-color-border-subtle"), 3, 0);
grid.add(colorBlock("-color-fg-emphasis", "-color-accent-emphasis", "-color-accent-emphasis"), 0, 1);
grid.add(colorBlock("-color-accent-fg", "-color-bg-default", "-color-accent-emphasis"), 1, 1);
- grid.add(colorBlock("-color-accent-fg", "-color-accent-muted", "-color-accent-muted"), 2, 1);
- grid.add(colorBlock("-color-accent-fg", "-color-accent-subtle", "-color-accent-subtle"), 3, 1);
+ grid.add(colorBlock("-color-fg-default", "-color-accent-muted", "-color-accent-emphasis"), 2, 1);
+ grid.add(colorBlock("-color-accent-fg", "-color-accent-subtle", "-color-accent-emphasis"), 3, 1);
grid.add(colorBlock("-color-fg-emphasis", "-color-neutral-emphasis-plus", "-color-neutral-emphasis-plus"), 0, 2);
grid.add(colorBlock("-color-fg-emphasis", "-color-neutral-emphasis", "-color-neutral-emphasis"), 1, 2);
- grid.add(colorBlock("-color-fg-muted", "-color-neutral-muted", "-color-neutral-muted"), 2, 2);
- grid.add(colorBlock("-color-fg-subtle", "-color-neutral-subtle", "-color-neutral-subtle"), 3, 2);
+ grid.add(colorBlock("-color-fg-default", "-color-neutral-muted", "-color-neutral-emphasis"), 2, 2);
+ grid.add(colorBlock("-color-fg-default", "-color-neutral-subtle", "-color-neutral-emphasis"), 3, 2);
grid.add(colorBlock("-color-fg-emphasis", "-color-success-emphasis", "-color-success-emphasis"), 0, 3);
grid.add(colorBlock("-color-success-fg", "-color-bg-default", "-color-success-emphasis"), 1, 3);
- grid.add(colorBlock("-color-success-fg", "-color-success-muted", "-color-success-muted"), 2, 3);
- grid.add(colorBlock("-color-success-fg", "-color-success-subtle", "-color-success-subtle"), 3, 3);
+ grid.add(colorBlock("-color-fg-default", "-color-success-muted", "-color-success-emphasis"), 2, 3);
+ grid.add(colorBlock("-color-success-fg", "-color-success-subtle", "-color-success-emphasis"), 3, 3);
grid.add(colorBlock("-color-fg-emphasis", "-color-warning-emphasis", "-color-warning-emphasis"), 0, 4);
grid.add(colorBlock("-color-warning-fg", "-color-bg-default", "-color-warning-emphasis"), 1, 4);
- grid.add(colorBlock("-color-warning-fg", "-color-warning-muted", "-color-warning-muted"), 2, 4);
- grid.add(colorBlock("-color-warning-fg", "-color-warning-subtle", "-color-warning-subtle"), 3, 4);
+ grid.add(colorBlock("-color-fg-default", "-color-warning-muted", "-color-warning-emphasis"), 2, 4);
+ grid.add(colorBlock("-color-warning-fg", "-color-warning-subtle", "-color-warning-emphasis"), 3, 4);
grid.add(colorBlock("-color-fg-emphasis", "-color-danger-emphasis", "-color-danger-emphasis"), 0, 5);
grid.add(colorBlock("-color-danger-fg", "-color-bg-default", "-color-danger-emphasis"), 1, 5);
- grid.add(colorBlock("-color-danger-fg", "-color-danger-muted", "-color-danger-muted"), 2, 5);
- grid.add(colorBlock("-color-danger-fg", "-color-danger-subtle", "-color-danger-subtle"), 3, 5);
+ grid.add(colorBlock("-color-fg-default", "-color-danger-muted", "-color-danger-emphasis"), 2, 5);
+ grid.add(colorBlock("-color-danger-fg", "-color-danger-subtle", "-color-danger-emphasis"), 3, 5);
return grid;
}
diff --git a/sampler/src/main/java/atlantafx/sampler/page/general/ColorPaletteBlock.java b/sampler/src/main/java/atlantafx/sampler/page/general/ColorPaletteBlock.java
index 028d73b..635b4d1 100644
--- a/sampler/src/main/java/atlantafx/sampler/page/general/ColorPaletteBlock.java
+++ b/sampler/src/main/java/atlantafx/sampler/page/general/ColorPaletteBlock.java
@@ -3,6 +3,8 @@ package atlantafx.sampler.page.general;
import atlantafx.base.theme.Styles;
import atlantafx.sampler.util.Containers;
+import atlantafx.sampler.util.ContrastLevel;
+import atlantafx.sampler.util.NodeUtils;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.geometry.Insets;
import javafx.scene.control.Label;
@@ -10,15 +12,17 @@ import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
-import org.kordamp.ikonli.feather.Feather;
import org.kordamp.ikonli.javafx.FontIcon;
import org.kordamp.ikonli.material2.Material2AL;
import java.util.function.Consumer;
-import static atlantafx.sampler.page.general.ContrastChecker.*;
+import static atlantafx.base.theme.Styles.TITLE_3;
+import static atlantafx.sampler.page.general.ContrastChecker.LUMINANCE_THRESHOLD;
+import static atlantafx.sampler.page.general.ContrastChecker.PASSED;
+import static atlantafx.sampler.util.ContrastLevel.getColorLuminance;
+import static atlantafx.sampler.util.ContrastLevel.getContrastRatioOpacityAware;
import static atlantafx.sampler.util.JColorUtils.flattenColor;
-import static atlantafx.sampler.util.JColorUtils.getColorLuminance;
class ColorPaletteBlock extends VBox {
@@ -27,11 +31,11 @@ class ColorPaletteBlock extends VBox {
private final String borderColorName;
private final ReadOnlyObjectProperty bgBaseColor;
- private final AnchorPane colorBox;
- private final Text fgText;
- private final FontIcon wsagIcon = new FontIcon();
- private final Label wsagLabel = new Label();
- private final FontIcon expandIcon = new FontIcon(Feather.MAXIMIZE_2);
+ private final AnchorPane colorRectangle;
+ private final Text contrastRatioText;
+ private final FontIcon contrastLevelIcon = new FontIcon();
+ private final Label contrastLevelLabel = new Label();
+ private final FontIcon editIcon = new FontIcon(Material2AL.COLORIZE);
private Consumer actionHandler;
@@ -44,69 +48,54 @@ class ColorPaletteBlock extends VBox {
this.borderColorName = validateColorName(borderColorName);
this.bgBaseColor = bgBaseColor;
- fgText = new Text();
- fgText.setStyle("-fx-fill:" + fgColorName + ";");
- fgText.getStyleClass().addAll("text", Styles.TITLE_3);
- Containers.setAnchors(fgText, new Insets(5, -1, -1, 5));
+ contrastRatioText = new Text();
+ contrastRatioText.setStyle("-fx-fill:" + fgColorName + ";");
+ contrastRatioText.getStyleClass().addAll("contrast-ratio-text", TITLE_3);
+ Containers.setAnchors(contrastRatioText, new Insets(5, -1, -1, 5));
- wsagLabel.setGraphic(wsagIcon);
- wsagLabel.getStyleClass().add("wsag-label");
- wsagLabel.setVisible(false);
- Containers.setAnchors(wsagLabel, new Insets(-1, 3, 3, -1));
+ contrastLevelLabel.setGraphic(contrastLevelIcon);
+ contrastLevelLabel.getStyleClass().add("contrast-level-label");
+ contrastLevelLabel.setVisible(false);
+ Containers.setAnchors(contrastLevelLabel, new Insets(-1, 3, 3, -1));
- expandIcon.setIconSize(24);
- expandIcon.getStyleClass().add("expand-icon");
- expandIcon.setVisible(false);
- expandIcon.setManaged(false);
- Containers.setAnchors(expandIcon, new Insets(3, 3, -1, -1));
+ editIcon.setIconSize(24);
+ editIcon.getStyleClass().add("edit-icon");
+ NodeUtils.toggleVisibility(editIcon, false);
+ Containers.setAnchors(editIcon, new Insets(3, 3, -1, -1));
- colorBox = new AnchorPane();
- colorBox.setStyle("-fx-background-color:" + bgColorName + ";" + "-fx-border-color:" + borderColorName + ";");
- colorBox.getStyleClass().add("box");
- colorBox.getChildren().setAll(fgText, wsagLabel, expandIcon);
- colorBox.setOnMouseEntered(e -> {
+ colorRectangle = new AnchorPane();
+ colorRectangle.setStyle(
+ String.format("-fx-background-color:%s;-fx-border-color:%s;", bgColorName, borderColorName)
+ );
+ colorRectangle.getStyleClass().add("rectangle");
+ colorRectangle.getChildren().setAll(contrastRatioText, contrastLevelLabel, editIcon);
+ colorRectangle.setOnMouseEntered(e -> {
var bgFill = getBgColor();
// this happens when css isn't updated yet
if (bgFill == null) { return; }
toggleHover(true);
- expandIcon.setFill(getColorLuminance(flattenColor(bgBaseColor.get(), bgFill)) < LUMINANCE_THRESHOLD ?
- Color.WHITE : Color.BLACK
+ editIcon.setFill(getColorLuminance(flattenColor(bgBaseColor.get(), bgFill)) < LUMINANCE_THRESHOLD ?
+ Color.WHITE : Color.BLACK
);
});
- colorBox.setOnMouseExited(e -> toggleHover(false));
- colorBox.setOnMouseClicked(e -> {
+ colorRectangle.setOnMouseExited(e -> toggleHover(false));
+ colorRectangle.setOnMouseClicked(e -> {
if (actionHandler != null) { actionHandler.accept(this); }
});
getChildren().addAll(
- colorBox,
- description(fgColorName),
- description(bgColorName),
- description(borderColorName)
+ colorRectangle,
+ colorNameText(fgColorName),
+ colorNameText(bgColorName),
+ colorNameText(borderColorName)
);
- getStyleClass().add("color-block");
+ getStyleClass().add("block");
}
- static String validateColorName(String colorName) {
- if (colorName == null || !colorName.startsWith("-color")) {
- throw new IllegalArgumentException("Invalid color name: '" + colorName + "'.");
- }
- return colorName;
- }
-
- private void toggleHover(boolean state) {
- expandIcon.setVisible(state);
- expandIcon.setManaged(state);
- fgText.setOpacity(state ? 0.5 : 1);
- wsagLabel.setOpacity(state ? 0.5 : 1);
- }
-
- private Text description(String text) {
- var t = new Text(text);
- t.getStyleClass().addAll("description", Styles.TEXT_SMALL);
- return t;
+ public void setOnAction(Consumer actionHandler) {
+ this.actionHandler = actionHandler;
}
public void update() {
@@ -114,28 +103,28 @@ class ColorPaletteBlock extends VBox {
var bgFill = getBgColor();
if (fgFill == null || bgFill == null) {
- fgText.setText("");
- wsagLabel.setText("");
- wsagLabel.setVisible(false);
+ contrastRatioText.setText("");
+ contrastLevelLabel.setText("");
+ contrastLevelLabel.setVisible(false);
return;
}
- double contrastRatio = 1 / getContrastRatioOpacityAware(bgFill, fgFill, bgBaseColor.get());
- colorBox.pseudoClassStateChanged(PASSED, contrastRatio >= 4.5);
+ double contrastRatio = getContrastRatioOpacityAware(bgFill, fgFill, bgBaseColor.get());
+ colorRectangle.pseudoClassStateChanged(PASSED, ContrastLevel.AA_NORMAL.satisfies(contrastRatio));
- wsagIcon.setIconCode(contrastRatio >= 4.5 ? Material2AL.CHECK : Material2AL.CLOSE);
- wsagLabel.setVisible(true);
- wsagLabel.setText(contrastRatio >= 7 ? "AAA" : "AA");
- fgText.setText(String.format("%.2f", contrastRatio));
+ contrastRatioText.setText(String.format("%.2f", contrastRatio));
+ contrastLevelIcon.setIconCode(ContrastLevel.AA_NORMAL.satisfies(contrastRatio) ? Material2AL.CHECK : Material2AL.CLOSE);
+ contrastLevelLabel.setVisible(true);
+ contrastLevelLabel.setText(ContrastLevel.AAA_NORMAL.satisfies(contrastRatio) ? "AAA" : "AA");
}
public Color getFgColor() {
- return (Color) fgText.getFill();
+ return (Color) contrastRatioText.getFill();
}
public Color getBgColor() {
- return colorBox.getBackground() != null && !colorBox.getBackground().isEmpty() ?
- (Color) colorBox.getBackground().getFills().get(0).getFill() : null;
+ return colorRectangle.getBackground() != null && !colorRectangle.getBackground().isEmpty() ?
+ (Color) colorRectangle.getBackground().getFills().get(0).getFill() : null;
}
public String getFgColorName() {
@@ -150,7 +139,22 @@ class ColorPaletteBlock extends VBox {
return borderColorName;
}
- public void setOnAction(Consumer actionHandler) {
- this.actionHandler = actionHandler;
+ private void toggleHover(boolean state) {
+ NodeUtils.toggleVisibility(editIcon, state);
+ contrastRatioText.setOpacity(state ? 0.5 : 1);
+ contrastLevelLabel.setOpacity(state ? 0.5 : 1);
+ }
+
+ private Text colorNameText(String text) {
+ var t = new Text(text);
+ t.getStyleClass().addAll("color-name", Styles.TEXT_SMALL);
+ return t;
+ }
+
+ static String validateColorName(String colorName) {
+ if (colorName == null || !colorName.startsWith("-color")) {
+ throw new IllegalArgumentException("Invalid color name: '" + colorName + "'.");
+ }
+ return colorName;
}
}
diff --git a/sampler/src/main/java/atlantafx/sampler/page/general/ColorScale.java b/sampler/src/main/java/atlantafx/sampler/page/general/ColorScale.java
index 71be1c4..1a519e0 100644
--- a/sampler/src/main/java/atlantafx/sampler/page/general/ColorScale.java
+++ b/sampler/src/main/java/atlantafx/sampler/page/general/ColorScale.java
@@ -11,12 +11,14 @@ import javafx.scene.layout.FlowPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
+import javafx.scene.text.Text;
+import javafx.scene.text.TextFlow;
import javafx.util.Duration;
import java.util.Arrays;
import java.util.List;
-public class ColorScale extends VBox {
+class ColorScale extends VBox {
private final ReadOnlyObjectWrapper bgBaseColor = new ReadOnlyObjectWrapper<>(Color.WHITE);
private final List blocks = Arrays.asList(
@@ -42,6 +44,10 @@ public class ColorScale extends VBox {
headerBox.setAlignment(Pos.CENTER_LEFT);
headerBox.getStyleClass().add("header");
+ var noteText = new TextFlow(
+ new Text("Avoid referencing scale variables directly when building UI that needs to adapt to different color themes. Instead, use the functional variables listed above.")
+ );
+
backgroundProperty().addListener((obs, old, val) -> bgBaseColor.set(
val != null && !val.getFills().isEmpty() ? (Color) val.getFills().get(0).getFill() : Color.WHITE
));
@@ -49,6 +55,7 @@ public class ColorScale extends VBox {
setId("color-scale");
getChildren().setAll(
headerBox,
+ noteText,
colorTable()
);
}
diff --git a/sampler/src/main/java/atlantafx/sampler/page/general/ColorScaleBlock.java b/sampler/src/main/java/atlantafx/sampler/page/general/ColorScaleBlock.java
index 2e82921..ec1ffa3 100644
--- a/sampler/src/main/java/atlantafx/sampler/page/general/ColorScaleBlock.java
+++ b/sampler/src/main/java/atlantafx/sampler/page/general/ColorScaleBlock.java
@@ -8,10 +8,10 @@ import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
+import static atlantafx.sampler.util.ContrastLevel.getColorLuminance;
import static atlantafx.sampler.util.JColorUtils.flattenColor;
-import static atlantafx.sampler.util.JColorUtils.getColorLuminance;
-public class ColorScaleBlock extends VBox {
+class ColorScaleBlock extends VBox {
private static final double BLOCK_WIDTH = 250;
private static final double BLOCK_HEIGHT = 50;
@@ -34,8 +34,8 @@ public class ColorScaleBlock extends VBox {
if (c instanceof Label label) {
String colorName = (String) label.getUserData();
label.setStyle(String.format("-fx-background-color:%s;-fx-text-fill:%s;",
- colorName,
- JColorUtils.toHexWithAlpha(getSafeFgColor(label))
+ colorName,
+ JColorUtils.toHexWithAlpha(getSafeFgColor(label))
));
}
});
diff --git a/sampler/src/main/java/atlantafx/sampler/page/general/ContrastChecker.java b/sampler/src/main/java/atlantafx/sampler/page/general/ContrastChecker.java
index a96e18a..39a6cf3 100644
--- a/sampler/src/main/java/atlantafx/sampler/page/general/ContrastChecker.java
+++ b/sampler/src/main/java/atlantafx/sampler/page/general/ContrastChecker.java
@@ -5,6 +5,7 @@ import atlantafx.base.controls.CustomTextField;
import atlantafx.base.controls.Spacer;
import atlantafx.base.theme.Styles;
import atlantafx.sampler.theme.ThemeManager;
+import atlantafx.sampler.util.ContrastLevel;
import atlantafx.sampler.util.JColor;
import atlantafx.sampler.util.JColorUtils;
import javafx.beans.binding.Bindings;
@@ -34,16 +35,19 @@ import org.kordamp.ikonli.material2.Material2AL;
import java.util.Objects;
import static atlantafx.sampler.page.general.ColorPaletteBlock.validateColorName;
+import static atlantafx.sampler.util.ContrastLevel.getColorLuminance;
+import static atlantafx.sampler.util.ContrastLevel.getContrastRatioOpacityAware;
import static atlantafx.sampler.util.JColorUtils.flattenColor;
-import static atlantafx.sampler.util.JColorUtils.getColorLuminance;
// Inspired by the https://colourcontrast.cc/
-public class ContrastChecker extends GridPane {
+class ContrastChecker extends GridPane {
public static final double CONTRAST_RATIO_THRESHOLD = 1.5;
public static final double LUMINANCE_THRESHOLD = 0.55;
public static final PseudoClass PASSED = PseudoClass.getPseudoClass("passed");
+ private static final String STATE_PASS = "PASS";
+ private static final String STATE_FAIL = "FAIL";
private static final int SLIDER_WIDTH = 300;
private String bgColorName;
@@ -70,7 +74,7 @@ public class ContrastChecker extends GridPane {
this.bgBaseColor = bgBaseColor;
this.contrastRatio = Bindings.createDoubleBinding(
- () -> 1 / getContrastRatioOpacityAware(bgColor.getColor(), fgColor.getColor(), bgBaseColor.get()),
+ () -> getContrastRatioOpacityAware(bgColor.getColor(), fgColor.getColor(), bgBaseColor.get()),
bgColor.colorProperty(),
fgColor.colorProperty(),
bgBaseColor
@@ -112,60 +116,42 @@ public class ContrastChecker extends GridPane {
}
private void createView() {
- var textLabel = new Label("Aa");
- textLabel.getStyleClass().add("text");
+ var largeFontLabel = new Label("Aa");
+ largeFontLabel.getStyleClass().add("large-font");
- var ratioLabel = new Label("0.0");
- ratioLabel.getStyleClass().add("ratio");
- ratioLabel.textProperty().bind(Bindings.createStringBinding(
+ var contrastRatioLabel = new Label("0.0");
+ contrastRatioLabel.getStyleClass().add("ratio");
+ contrastRatioLabel.textProperty().bind(Bindings.createStringBinding(
() -> String.format("%.2f", contrastRatio.get()), contrastRatio
));
- var fontBox = new HBox(20, textLabel, ratioLabel);
- fontBox.getStyleClass().add("font-box");
- fontBox.setAlignment(Pos.BASELINE_LEFT);
+ var contrastRatioBox = new HBox(20, largeFontLabel, contrastRatioLabel);
+ contrastRatioBox.getStyleClass().add("contrast-ratio");
+ contrastRatioBox.setAlignment(Pos.BASELINE_LEFT);
// !
- var aaNormalLabel = wsagLabel();
- var aaNormalBox = wsagBox(aaNormalLabel, "AA Normal");
+ var aaNormalLabel = contrastLevelLabel();
+ var aaNormalBox = contrastLevelBox(aaNormalLabel, "AA Normal");
- var aaLargeLabel = wsagLabel();
- var aaLargeBox = wsagBox(aaLargeLabel, "AA Large");
+ var aaLargeLabel = contrastLevelLabel();
+ var aaLargeBox = contrastLevelBox(aaLargeLabel, "AA Large");
- var aaaNormalLabel = wsagLabel();
- var aaaNormalBox = wsagBox(aaaNormalLabel, "AAA Normal");
+ var aaaNormalLabel = contrastLevelLabel();
+ var aaaNormalBox = contrastLevelBox(aaaNormalLabel, "AAA Normal");
- var aaaLargeLabel = wsagLabel();
- var aaaLargeBox = wsagBox(aaaLargeLabel, "AAA Large");
+ var aaaLargeLabel = contrastLevelLabel();
+ var aaaLargeBox = contrastLevelBox(aaaLargeLabel, "AAA Large");
- var wsagBox = new HBox(20, aaNormalBox, aaLargeBox, aaaNormalBox, aaaLargeBox);
- wsagBox.getStyleClass().add("wsag-box");
+ var contrastLevels = new HBox(20, aaNormalBox, aaLargeBox, aaaNormalBox, aaaLargeBox);
contrastRatio.addListener((obs, old, val) -> {
if (val == null) { return; }
float ratio = val.floatValue();
- if (ratio >= 7) {
- updateWsagLabel(aaNormalLabel, true);
- updateWsagLabel(aaLargeLabel, true);
- updateWsagLabel(aaaNormalLabel, true);
- updateWsagLabel(aaaLargeLabel, true);
- } else if (ratio < 7 && ratio >= 4.5) {
- updateWsagLabel(aaNormalLabel, true);
- updateWsagLabel(aaLargeLabel, true);
- updateWsagLabel(aaaNormalLabel, false);
- updateWsagLabel(aaaLargeLabel, true);
- } else if (ratio < 4.5 && ratio >= 3) {
- updateWsagLabel(aaNormalLabel, false);
- updateWsagLabel(aaLargeLabel, true);
- updateWsagLabel(aaaNormalLabel, false);
- updateWsagLabel(aaaLargeLabel, false);
- } else {
- updateWsagLabel(aaNormalLabel, false);
- updateWsagLabel(aaLargeLabel, false);
- updateWsagLabel(aaaNormalLabel, false);
- updateWsagLabel(aaaLargeLabel, false);
- }
+ updateWsagLabel(aaNormalLabel, ContrastLevel.AA_NORMAL.satisfies(ratio));
+ updateWsagLabel(aaLargeLabel, ContrastLevel.AA_LARGE.satisfies(ratio));
+ updateWsagLabel(aaaNormalLabel, ContrastLevel.AAA_NORMAL.satisfies(ratio));
+ updateWsagLabel(aaaLargeLabel, ContrastLevel.AAA_LARGE.satisfies(ratio));
});
// ~
@@ -296,7 +282,7 @@ public class ContrastChecker extends GridPane {
getStyleClass().add("contrast-checker");
// column 0
- add(new HBox(fontBox, new Spacer(), wsagBox), 0, 0, REMAINING, 1);
+ add(new HBox(contrastRatioBox, new Spacer(), contrastLevels), 0, 0, REMAINING, 1);
add(new Label("Background Color"), 0, 1);
add(bgColorNameLabel, 0, 2);
add(bgTextField, 0, 3);
@@ -335,8 +321,8 @@ public class ContrastChecker extends GridPane {
private void updateStyle() {
setStyle(String.format("-color-contrast-checker-bg:%s;-color-contrast-checker-fg:%s;",
- JColorUtils.toHexWithAlpha(bgColor.getColor()),
- JColorUtils.toHexWithAlpha(getSafeFgColor())
+ JColorUtils.toHexWithAlpha(bgColor.getColor()),
+ JColorUtils.toHexWithAlpha(getSafeFgColor())
));
}
@@ -359,25 +345,26 @@ public class ContrastChecker extends GridPane {
private void updateWsagLabel(Label label, boolean success) {
FontIcon icon = Objects.requireNonNull((FontIcon) label.getGraphic());
if (success) {
- label.setText("PASS");
+ label.setText(STATE_PASS);
icon.setIconCode(Material2AL.CHECK);
} else {
- label.setText("FAIL");
+ label.setText(STATE_FAIL);
icon.setIconCode(Material2AL.CLOSE);
}
label.pseudoClassStateChanged(PASSED, success);
}
- private Label wsagLabel() {
- var label = new Label("FAIL");
- label.getStyleClass().add("wsag-label");
+ private Label contrastLevelLabel() {
+ var label = new Label(STATE_FAIL);
+ label.getStyleClass().add("state");
label.setContentDisplay(ContentDisplay.RIGHT);
label.setGraphic(new FontIcon(Material2AL.CLOSE));
return label;
}
- private VBox wsagBox(Label label, String description) {
+ private VBox contrastLevelBox(Label label, String description) {
var box = new VBox(10, label, new Label(description));
+ box.getStyleClass().add("contrast-level");
box.setAlignment(Pos.CENTER);
return box;
}
@@ -392,12 +379,6 @@ public class ContrastChecker extends GridPane {
return slider;
}
- static double getContrastRatioOpacityAware(Color bgColor, Color fgColor, Color bgBaseColor) {
- double luminance1 = getColorLuminance(flattenColor(bgBaseColor, bgColor));
- double luminance2 = getColorLuminance(flattenColor(bgBaseColor, fgColor));
- return JColorUtils.getContrastRatio(luminance1, luminance2);
- }
-
///////////////////////////////////////////////////////////////////////////
private static class ObservableHSLAColor {
diff --git a/sampler/src/main/java/atlantafx/sampler/page/general/ThemePage.java b/sampler/src/main/java/atlantafx/sampler/page/general/ThemePage.java
index 0ed0688..804f3ef 100755
--- a/sampler/src/main/java/atlantafx/sampler/page/general/ThemePage.java
+++ b/sampler/src/main/java/atlantafx/sampler/page/general/ThemePage.java
@@ -10,12 +10,17 @@ import javafx.geometry.HPos;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
+import javafx.scene.text.Text;
+import javafx.scene.text.TextFlow;
import javafx.util.Duration;
import javafx.util.StringConverter;
+import java.net.URI;
import java.util.Objects;
import java.util.function.Consumer;
+import static atlantafx.sampler.util.Controls.hyperlink;
+
public class ThemePage extends AbstractPage {
public static final String NAME = "Theme";
@@ -23,9 +28,9 @@ public class ThemePage extends AbstractPage {
private final Consumer colorBlockActionHandler = colorBlock -> {
ContrastCheckerDialog dialog = getOrCreateContrastCheckerDialog();
dialog.getContent().setValues(colorBlock.getFgColorName(),
- colorBlock.getFgColor(),
- colorBlock.getBgColorName(),
- colorBlock.getBgColor()
+ colorBlock.getFgColor(),
+ colorBlock.getBgColorName(),
+ colorBlock.getBgColor()
);
overlay.setContent(dialog, HPos.CENTER);
overlay.toFront();
@@ -59,11 +64,21 @@ public class ThemePage extends AbstractPage {
}
private void createView() {
+ var noteText = new TextFlow(
+ new Text("AtlantaFX follows "),
+ hyperlink("Github Primer interface guidelines",
+ URI.create("https://primer.style/design/foundations/color")
+ ),
+ new Text(" and color system.")
+ );
+
userContent.getChildren().addAll(
optionsGrid(),
+ noteText,
colorPalette,
colorScale
);
+
// if you want to enable quick menu don't forget that
// theme selection choice box have to be updated accordingly
NodeUtils.toggleVisibility(quickConfigBtn, false);
diff --git a/sampler/src/main/java/atlantafx/sampler/util/ContrastLevel.java b/sampler/src/main/java/atlantafx/sampler/util/ContrastLevel.java
new file mode 100644
index 0000000..76379dd
--- /dev/null
+++ b/sampler/src/main/java/atlantafx/sampler/util/ContrastLevel.java
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: MIT */
+package atlantafx.sampler.util;
+
+import javafx.scene.paint.Color;
+
+import java.util.Arrays;
+
+import static atlantafx.sampler.util.JColorUtils.flattenColor;
+
+/**
+ * The WCAG contrast measures the difference in brightness (luminance) between two colours.
+ * It ranges from 1:1 (white on white) to 21:1 (black on white). WCAG requirements are:
+ *
+ * - 0.14285 (7.0:1) for small text in AAA-level
+ * - 0.22222 (4.5:1) for small text in AA-level, or large text in AAA-level
+ * - 0.33333 (3.0:1) for large text in AA-level
+ *
+ * WCAG defines large text as text that is 18pt and larger, or 14pt and larger if it is bold.
+ *
+ * More info.
+ */
+public enum ContrastLevel {
+
+ AA_NORMAL,
+ AA_LARGE,
+ AAA_NORMAL,
+ AAA_LARGE;
+
+ public boolean satisfies(double ratio) {
+ switch (this) {
+ case AA_NORMAL -> { return ratio >= 4.5; }
+ case AA_LARGE -> { return ratio >= 3; }
+ case AAA_NORMAL -> { return ratio >= 7; }
+ case AAA_LARGE -> { return ratio >= 4.5; }
+ }
+ return false;
+ }
+
+ public static double getContrastRatio(Color color1, Color color2) {
+ return getContrastRatio(getColorLuminance(color1), getColorLuminance(color2));
+ }
+
+ public static double getContrastRatio(double luminance1, double luminance2) {
+ return 1 / (luminance1 > luminance2 ?
+ (luminance2 + 0.05) / (luminance1 + 0.05) :
+ (luminance1 + 0.05) / (luminance2 + 0.05)
+ );
+ }
+
+ public static double getContrastRatioOpacityAware(Color bgColor, Color fgColor, Color bgBaseColor) {
+ double luminance1 = getColorLuminance(flattenColor(bgBaseColor, bgColor));
+ double luminance2 = getColorLuminance(flattenColor(bgBaseColor, fgColor));
+ return getContrastRatio(luminance1, luminance2);
+ }
+
+ /**
+ * Measures relative color luminance according to the
+ * W3C.
+ *
+ * Note that JavaFX provides {@link Color#getBrightness()} which
+ * IS NOT the same thing as luminance.
+ */
+ public static double getColorLuminance(double[] rgb) {
+ double[] tmp = Arrays.stream(rgb)
+ .map(v -> v <= 0.03928 ? (v / 12.92) : Math.pow((v + 0.055) / 1.055, 2.4))
+ .toArray();
+ return (tmp[0] * 0.2126) + (tmp[1] * 0.7152) + (tmp[2] * 0.0722);
+ }
+
+ /** @see ContrastLevel#getColorLuminance(double[]) */
+ public static double getColorLuminance(Color color) {
+ return getColorLuminance(new double[] { color.getRed(), color.getGreen(), color.getBlue() });
+ }
+}
diff --git a/sampler/src/main/java/atlantafx/sampler/util/Controls.java b/sampler/src/main/java/atlantafx/sampler/util/Controls.java
index 43d89a0..b0e4cc1 100644
--- a/sampler/src/main/java/atlantafx/sampler/util/Controls.java
+++ b/sampler/src/main/java/atlantafx/sampler/util/Controls.java
@@ -1,14 +1,15 @@
/* SPDX-License-Identifier: MIT */
package atlantafx.sampler.util;
-import javafx.scene.control.Button;
-import javafx.scene.control.MenuItem;
-import javafx.scene.control.ToggleButton;
-import javafx.scene.control.ToggleGroup;
+import atlantafx.sampler.event.BrowseEvent;
+import atlantafx.sampler.event.DefaultEventBus;
+import javafx.scene.control.*;
import javafx.scene.input.KeyCombination;
import org.kordamp.ikonli.Ikon;
import org.kordamp.ikonli.javafx.FontIcon;
+import java.net.URI;
+
import static atlantafx.base.theme.Styles.BUTTON_ICON;
public final class Controls {
@@ -40,10 +41,10 @@ public final class Controls {
}
public static ToggleButton toggleButton(String text,
- Ikon icon,
- ToggleGroup group,
- boolean selected,
- String... styleClasses) {
+ Ikon icon,
+ ToggleGroup group,
+ boolean selected,
+ String... styleClasses) {
var toggleButton = new ToggleButton(text);
if (icon != null) { toggleButton.setGraphic(new FontIcon(icon)); }
if (group != null) { toggleButton.setToggleGroup(group); }
@@ -52,4 +53,12 @@ public final class Controls {
return toggleButton;
}
+
+ public static Hyperlink hyperlink(String text, URI uri) {
+ var hyperlink = new Hyperlink(text);
+ if (uri != null) {
+ hyperlink.setOnAction(event -> DefaultEventBus.getInstance().publish(new BrowseEvent(uri)));
+ }
+ return hyperlink;
+ }
}
diff --git a/sampler/src/main/java/atlantafx/sampler/util/JColorUtils.java b/sampler/src/main/java/atlantafx/sampler/util/JColorUtils.java
index be2607e..254bd6c 100644
--- a/sampler/src/main/java/atlantafx/sampler/util/JColorUtils.java
+++ b/sampler/src/main/java/atlantafx/sampler/util/JColorUtils.java
@@ -780,48 +780,6 @@ public class JColorUtils {
// Additional Utils, mkpaz (c) //
///////////////////////////////////////////////////////////////////////////
- /**
- * The WCAG contrast measures the difference in brightness (luminance) between two colours.
- * It ranges from 1:1 (white on white) to 21:1 (black on white). WCAG requirements are:
- *
- * - 0.14285 (7.0:1) for small text in AAA-level
- * - 0.22222 (4.5:1) for small text in AA-level, or large text in AAA-level
- * - 0.33333 (3.0:1) for large text in AA-level
- *
- * WCAG defines large text as text that is 18pt and larger, or 14pt and larger if it is bold.
- *
- * More info.
- */
- public static double getContrastRatio(Color color1, Color color2) {
- return getContrastRatio(getColorLuminance(color1), getColorLuminance(color2));
- }
-
- /** @see JColorUtils#getContrastRatio(Color, Color) */
- public static double getContrastRatio(double luminance1, double luminance2) {
- return luminance1 > luminance2 ?
- (luminance2 + 0.05) / (luminance1 + 0.05) :
- (luminance1 + 0.05) / (luminance2 + 0.05);
- }
-
- /**
- * Measures relative color luminance according to the
- * W3C.
- *
- * Note that JavaFX provides {@link Color#getBrightness()} which
- * IS NOT the same thing as luminance.
- */
- public static double getColorLuminance(double[] rgb) {
- double[] tmp = Arrays.stream(rgb)
- .map(v -> v <= 0.03928 ? (v / 12.92) : Math.pow((v + 0.055) / 1.055, 2.4))
- .toArray();
- return (tmp[0] * 0.2126) + (tmp[1] * 0.7152) + (tmp[2] * 0.0722);
- }
-
- /** @see JColorUtils#getColorLuminance(double[]) */
- public static double getColorLuminance(Color color) {
- return getColorLuminance(new double[] { color.getRed(), color.getGreen(), color.getBlue() });
- }
-
/**
* Removes given color opacity, if present.
*
diff --git a/sampler/src/main/java/module-info.java b/sampler/src/main/java/module-info.java
index 4d5fd68..8021c15 100755
--- a/sampler/src/main/java/module-info.java
+++ b/sampler/src/main/java/module-info.java
@@ -20,6 +20,7 @@ module atlantafx.sampler {
exports atlantafx.sampler;
exports atlantafx.sampler.fake;
exports atlantafx.sampler.fake.domain;
+ exports atlantafx.sampler.event;
exports atlantafx.sampler.layout;
exports atlantafx.sampler.page;
exports atlantafx.sampler.page.general;
diff --git a/sampler/src/main/resources/assets/styles/scss/widgets/_color-palette.scss b/sampler/src/main/resources/assets/styles/scss/widgets/_color-palette.scss
index 11ba95c..b016623 100644
--- a/sampler/src/main/resources/assets/styles/scss/widgets/_color-palette.scss
+++ b/sampler/src/main/resources/assets/styles/scss/widgets/_color-palette.scss
@@ -13,21 +13,21 @@ $color-wsag-fg: white;
-fx-vgap: 20px;
-fx-hgap: 40px;
- >.color-block {
+ >.block {
-fx-spacing: 5px;
- >.box {
+ >.rectangle {
-fx-min-width: 12em;
-fx-min-height: 5em;
-fx-max-width: 12em;
-fx-max-height: 5em;
-fx-cursor: hand;
- &:passed>.wsag-label {
+ &:passed>.contrast-level-label {
-fx-background-color: $color-wsag-bg-passed;
}
- >.wsag-label {
+ >.contrast-level-label {
-fx-text-fill: $color-wsag-fg;
-fx-background-color: $color-wsag-bg-failed;
-fx-background-radius: 6px;
diff --git a/sampler/src/main/resources/assets/styles/scss/widgets/_contrast-checker.scss b/sampler/src/main/resources/assets/styles/scss/widgets/_contrast-checker.scss
index bb3ebc8..9abdd24 100644
--- a/sampler/src/main/resources/assets/styles/scss/widgets/_contrast-checker.scss
+++ b/sampler/src/main/resources/assets/styles/scss/widgets/_contrast-checker.scss
@@ -2,6 +2,7 @@
@use "color-palette" as palette;
.contrast-checker {
+
-fx-background-color: -color-contrast-checker-bg;
-fx-hgap: 40px;
-fx-vgap: 20px;
@@ -47,11 +48,6 @@
}
}
- .ikonli-font-icon {
- -fx-icon-color: -color-contrast-checker-fg;
- -fx-fill: -color-contrast-checker-fg;
- }
-
.slider {
>.thumb {
-fx-background-color: -color-contrast-checker-fg;
@@ -63,10 +59,15 @@
}
}
- .font-box {
+ .ikonli-font-icon {
+ -fx-icon-color: -color-contrast-checker-fg;
+ -fx-fill: -color-contrast-checker-fg;
+ }
+
+ .contrast-ratio {
-fx-padding: 0 40px 0 0;
- >.text {
+ >.large-font {
-fx-font-size: 4em;
}
@@ -75,19 +76,21 @@
}
}
- .wsag-box>*>.wsag-label {
- -fx-padding: 0.5em 1em 0.5em 1em;
- -fx-background-color: palette.$color-wsag-bg-failed;
- -fx-background-radius: 4px;
- -fx-text-fill: palette.$color-wsag-fg;
+ .contrast-level {
+ >.state {
+ -fx-padding: 0.5em 1em 0.5em 1em;
+ -fx-background-color: palette.$color-wsag-bg-failed;
+ -fx-background-radius: 4px;
+ -fx-text-fill: palette.$color-wsag-fg;
- &:passed {
- -fx-background-color: palette.$color-wsag-bg-passed;
- }
+ &:passed {
+ -fx-background-color: palette.$color-wsag-bg-passed;
+ }
- >.ikonli-font-icon {
- -fx-fill: palette.$color-wsag-fg;
- -fx-icon-color: palette.$color-wsag-fg;
+ >.ikonli-font-icon {
+ -fx-fill: palette.$color-wsag-fg;
+ -fx-icon-color: palette.$color-wsag-fg;
+ }
}
}
}