Make small improvements to Sampler

- Support internal links
- Hide disable switch in some examples
This commit is contained in:
mkpaz 2023-05-26 21:43:42 +04:00
parent 39cf7bd992
commit cf2f46a4e0
15 changed files with 188 additions and 38 deletions

@ -0,0 +1,25 @@
/* SPDX-License-Identifier: MIT */
package atlantafx.sampler.event;
import atlantafx.sampler.page.Page;
public final class NavEvent extends Event {
private final Class<? extends Page> page;
public NavEvent(Class<? extends Page> page) {
this.page = page;
}
public Class<? extends Page> getPage() {
return page;
}
@Override
public String toString() {
return "NavEvent{"
+ "page=" + page
+ "} " + super.toString();
}
}

@ -5,6 +5,8 @@ package atlantafx.sampler.layout;
import static atlantafx.sampler.layout.MainModel.SubLayer.PAGE;
import static atlantafx.sampler.layout.MainModel.SubLayer.SOURCE_CODE;
import atlantafx.sampler.event.DefaultEventBus;
import atlantafx.sampler.event.NavEvent;
import atlantafx.sampler.page.Page;
import atlantafx.sampler.page.components.AccordionPage;
import atlantafx.sampler.page.components.AnimationsPage;
@ -94,6 +96,10 @@ public class MainModel {
.toList();
}
public MainModel() {
DefaultEventBus.getInstance().subscribe(NavEvent.class, e -> navigate(e.getPage()));
}
///////////////////////////////////////////////////////////////////////////
// Properties //
///////////////////////////////////////////////////////////////////////////

@ -3,19 +3,47 @@
package atlantafx.sampler.layout;
import atlantafx.sampler.page.Page;
import atlantafx.sampler.page.components.BreadcrumbsPage;
import atlantafx.sampler.page.components.CalendarPage;
import atlantafx.sampler.page.components.CardPage;
import atlantafx.sampler.page.components.CustomTextFieldPage;
import atlantafx.sampler.page.components.DeckPanePage;
import atlantafx.sampler.page.components.InputGroupPage;
import atlantafx.sampler.page.components.MessagePage;
import atlantafx.sampler.page.components.ModalPanePage;
import atlantafx.sampler.page.components.PopoverPage;
import atlantafx.sampler.page.components.TilePage;
import atlantafx.sampler.page.components.ToggleSwitchPage;
import atlantafx.sampler.page.general.BBCodePage;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import javafx.scene.Node;
import org.jetbrains.annotations.Nullable;
record Nav(String title,
@Nullable Node graphic,
@Nullable Class<? extends Page> pageClass,
@Nullable List<String> searchKeywords) {
@Nullable Node graphic,
@Nullable Class<? extends Page> pageClass,
@Nullable List<String> searchKeywords) {
public static final Nav ROOT = new Nav("ROOT", null, null, null);
private static final Set<Class<? extends Page>> TAGGED_PAGES = Set.of(
BBCodePage.class,
BreadcrumbsPage.class,
CalendarPage.class,
CardPage.class,
CustomTextFieldPage.class,
DeckPanePage.class,
InputGroupPage.class,
MessagePage.class,
ModalPanePage.class,
PopoverPage.class,
TilePage.class,
ToggleSwitchPage.class
);
public Nav {
Objects.requireNonNull(title, "title");
searchKeywords = Objects.requireNonNullElse(searchKeywords, Collections.emptyList());
@ -31,6 +59,10 @@ record Nav(String title,
|| (searchKeywords != null && searchKeywords.stream().anyMatch(keyword -> contains(keyword, filter)));
}
public boolean isTagged() {
return pageClass != null && TAGGED_PAGES.contains(pageClass);
}
private boolean contains(String text, String filter) {
return text.toLowerCase().contains(filter.toLowerCase());
}

@ -5,6 +5,7 @@ package atlantafx.sampler.layout;
import atlantafx.base.controls.Spacer;
import atlantafx.base.theme.Tweaks;
import atlantafx.sampler.page.Page;
import atlantafx.sampler.util.NodeUtils;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@ -12,6 +13,7 @@ import javafx.css.PseudoClass;
import javafx.geometry.Pos;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
@ -51,6 +53,7 @@ public final class NavTree extends TreeView<Nav> {
private final HBox root;
private final Label titleLabel;
private final Node arrowIcon;
private final Label tagLabel;
public NavTreeCell() {
super();
@ -62,9 +65,12 @@ public final class NavTree extends TreeView<Nav> {
arrowIcon = new FontIcon();
arrowIcon.getStyleClass().add("arrow");
tagLabel = new Label("new");
tagLabel.getStyleClass().add("tag");
root = new HBox();
root.setAlignment(Pos.CENTER_LEFT);
root.getChildren().setAll(titleLabel, new Spacer(), arrowIcon);
root.getChildren().setAll(titleLabel, new Spacer(), arrowIcon, tagLabel);
root.setCursor(Cursor.HAND);
root.getStyleClass().add("container");
root.setMaxWidth(ApplicationWindow.SIDEBAR_WIDTH - 10);
@ -99,7 +105,8 @@ public final class NavTree extends TreeView<Nav> {
titleLabel.setGraphic(nav.graphic());
pseudoClassStateChanged(GROUP, nav.isGroup());
arrowIcon.setVisible(nav.isGroup());
NodeUtils.toggleVisibility(arrowIcon, nav.isGroup());
NodeUtils.toggleVisibility(tagLabel, nav.isTagged());
}
}
}

@ -9,6 +9,7 @@ import atlantafx.base.theme.Tweaks;
import atlantafx.base.util.BBCodeParser;
import atlantafx.sampler.event.BrowseEvent;
import atlantafx.sampler.event.DefaultEventBus;
import atlantafx.sampler.event.NavEvent;
import atlantafx.sampler.event.PageEvent;
import atlantafx.sampler.layout.ApplicationWindow;
import java.net.URI;
@ -27,7 +28,6 @@ import javafx.scene.control.MenuItem;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import net.datafaker.Faker;
import org.jetbrains.annotations.Nullable;
import org.kordamp.ikonli.feather.Feather;
@ -71,15 +71,30 @@ public interface Page {
return Feather.values()[RANDOM.nextInt(Feather.values().length)];
}
@SuppressWarnings("unchecked")
default Node createFormattedText(String text, boolean handleUrl) {
var node = BBCodeParser.createFormattedText(text);
if (handleUrl) {
node.addEventFilter(ActionEvent.ACTION, e -> {
if (e.getTarget() instanceof Hyperlink link && link.getUserData() != null) {
DefaultEventBus.getInstance().publish(
new BrowseEvent(URI.create((String) link.getUserData()))
);
if (e.getTarget() instanceof Hyperlink link && link.getUserData() instanceof String url) {
if (url.startsWith("https://") || url.startsWith("http://")) {
DefaultEventBus.getInstance().publish(new BrowseEvent(URI.create(url)));
}
if (url.startsWith("local://")) {
try {
var rootPackage = "atlantafx.sampler.page.";
var c = Class.forName(rootPackage + url.substring(8));
if (Page.class.isAssignableFrom(c)) {
DefaultEventBus.getInstance().publish(new NavEvent((Class<? extends Page>) c));
} else {
throw new IllegalArgumentException();
}
} catch (Exception ignored) {
System.err.println("Invalid local URL: \"" + url + "\"");
}
}
}
e.consume();
});

@ -99,7 +99,7 @@ public final class AnimationsPage extends StackPane implements Page {
private VBox createOutline() {
var outline = new VBox();
outline.setSpacing(10);
outline.setPadding(new Insets(0, 20, 0, 20));
outline.setPadding(new Insets(20));
outline.setMinWidth(OUTLINE_WIDTH);
outline.setMaxWidth(OUTLINE_WIDTH);
Styles.appendStyle(outline, "-fx-background-color", "-color-bg-default");

@ -88,7 +88,10 @@ public final class DialogPage extends OutlinePage {
Pre-built dialog types for displaying information, warnings, and errors."""
);
return new ExampleBox(box, new Snippet(getClass(), 1), description);
var example = new ExampleBox(box, new Snippet(getClass(), 1), description);
example.setAllowDisable(false);
return example;
}
private ExampleBox exceptionDialogExample() {
@ -130,7 +133,10 @@ public final class DialogPage extends OutlinePage {
are thrown in JavaFX applications."""
);
return new ExampleBox(new HBox(button), new Snippet(getClass(), 2), description);
var example = new ExampleBox(new HBox(button), new Snippet(getClass(), 2), description);
example.setAllowDisable(false);
return example;
}
private ExampleBox confirmationDialogExample() {
@ -161,7 +167,10 @@ public final class DialogPage extends OutlinePage {
suggests the content of the dialog is seeking confirmation from the user."""
);
return new ExampleBox(new HBox(button), new Snippet(getClass(), 3), description);
var example = new ExampleBox(new HBox(button), new Snippet(getClass(), 3), description);
example.setAllowDisable(false);
return example;
}
private ExampleBox textInputDialogExample() {
@ -181,7 +190,10 @@ public final class DialogPage extends OutlinePage {
"A dialog that shows a text input control to the user."
);
return new ExampleBox(new HBox(button), new Snippet(getClass(), 4), description);
var example = new ExampleBox(new HBox(button), new Snippet(getClass(), 4), description);
example.setAllowDisable(false);
return example;
}
private ExampleBox choiceDialogExample() {
@ -202,7 +214,10 @@ public final class DialogPage extends OutlinePage {
A dialog that shows a list of choices to the user, from which they can pick one item at most."""
);
return new ExampleBox(new HBox(button), new Snippet(getClass(), 5), description);
var example = new ExampleBox(new HBox(button), new Snippet(getClass(), 5), description);
example.setAllowDisable(false);
return example;
}
private ExampleBox notificationNoHeaderDialogExample() {
@ -243,6 +258,9 @@ public final class DialogPage extends OutlinePage {
"The header text can be hidden."
);
return new ExampleBox(box, new Snippet(getClass(), 6), description);
var example = new ExampleBox(box, new Snippet(getClass(), 6), description);
example.setAllowDisable(false);
return example;
}
}

@ -176,6 +176,9 @@ public class MessagePage extends OutlinePage {
which can be used to create a fancy banner, for example."""
);
return new ExampleBox(box, new Snippet(getClass(), 4), description);
var example = new ExampleBox(box, new Snippet(getClass(), 4), description);
example.setAllowDisable(false);
return example;
}
}

@ -94,7 +94,10 @@ public final class ModalPanePage extends OutlinePage {
[code]show()[/code] method, which is a convenience method for setting the content \
of the modal pane and triggering its display state at the same time.""");
return new ExampleBox(box, new Snippet(getClass(), 1), description);
var example = new ExampleBox(box, new Snippet(getClass(), 1), description);
example.setAllowDisable(false);
return example;
}
private ExampleBox contentPositionExample() {
@ -163,7 +166,10 @@ public final class ModalPanePage extends OutlinePage {
The alignment and animated appearance of modal content can be changed \
via corresponding properties.""");
return new ExampleBox(box, new Snippet(getClass(), 1), description);
var example = new ExampleBox(box, new Snippet(getClass(), 1), description);
example.setAllowDisable(false);
return example;
}
private ExampleBox persistentExample() {
@ -192,7 +198,10 @@ public final class ModalPanePage extends OutlinePage {
or when the mouse is clicked outside the content area. [code]setPersistent()[/code] \
property prevents this behavior and instead plays a bouncing animation.""");
return new ExampleBox(box, new Snippet(getClass(), 3), description);
var example = new ExampleBox(box, new Snippet(getClass(), 3), description);
example.setAllowDisable(false);
return example;
}
private ExampleBox nestingExample() {
@ -226,7 +235,10 @@ public final class ModalPanePage extends OutlinePage {
the same behavior by stacking multiple modal panes and using the corresponding \
[code]topViewOrder[/code] property value.""");
return new ExampleBox(box, new Snippet(getClass(), 4), description);
var example = new ExampleBox(box, new Snippet(getClass(), 4), description);
example.setAllowDisable(false);
return example;
}
private ExampleBox maximizedExample() {
@ -248,7 +260,10 @@ public final class ModalPanePage extends OutlinePage {
To create a maximized dialog, simply use a content node such as [i]VBox[/i] \
that expands itself in both the horizontal and vertical directions.""");
return new ExampleBox(box, new Snippet(getClass(), 5), description);
var example = new ExampleBox(box, new Snippet(getClass(), 5), description);
example.setAllowDisable(false);
return example;
}
private ExampleBox overflowedExample() {
@ -302,7 +317,10 @@ public final class ModalPanePage extends OutlinePage {
The [i]ModalPane[/i] is already scrollable by default, but you can also use a \
[i]ScrollPane[/i] for the content node if needed.""");
return new ExampleBox(box, new Snippet(getClass(), 6), description);
var example = new ExampleBox(box, new Snippet(getClass(), 6), description);
example.setAllowDisable(false);
return example;
}
private ExampleBox dialogPaneExample() {
@ -348,7 +366,10 @@ public final class ModalPanePage extends OutlinePage {
and allows for the addition of arbitrary children."""
);
return new ExampleBox(box, new Snippet(getClass(), 8), description);
var example = new ExampleBox(box, new Snippet(getClass(), 8), description);
example.setAllowDisable(false);
return example;
}
private ExampleBox lightboxExample() {

@ -88,7 +88,10 @@ public final class PopoverPage extends OutlinePage {
[i]Popover[/i] will move around with the parent window when the user drags it."""
);
return new ExampleBox(box, new Snippet(getClass(), 1), description);
var example = new ExampleBox(box, new Snippet(getClass(), 1), description);
example.setAllowDisable(false);
return example;
}
private ExampleBox positionExample() {
@ -143,6 +146,9 @@ public final class PopoverPage extends OutlinePage {
appropriate ArrowLocation value.."""
);
return new ExampleBox(grid, new Snippet(getClass(), 2), description);
var example = new ExampleBox(grid, new Snippet(getClass(), 2), description);
example.setAllowDisable(false);
return example;
}
}

@ -367,6 +367,9 @@ public final class ProgressIndicatorPage extends OutlinePage {
change the progress bar color while the task is in progress."""
);
return new ExampleBox(content, new Snippet(getClass(), 6), description);
var example = new ExampleBox(content, new Snippet(getClass(), 6), description);
example.setAllowDisable(false);
return example;
}
}

@ -1,11 +1,11 @@
package atlantafx.sampler.page.components;
import atlantafx.base.controls.PasswordTextField;
import atlantafx.base.controls.Tile;
import atlantafx.base.controls.ToggleSwitch;
import atlantafx.base.theme.Styles;
import atlantafx.base.util.BBCodeParser;
import atlantafx.sampler.Resources;
import atlantafx.base.controls.Tile;
import atlantafx.sampler.page.ExampleBox;
import atlantafx.sampler.page.OutlinePage;
import atlantafx.sampler.page.Snippet;
@ -174,7 +174,7 @@ public class TilePage extends OutlinePage {
);
var tgl2 = new ToggleSwitch();
tile2.setAction(tgl2);
tile2.setActionHandler(() -> tgl2.setSelected(!tgl2.isSelected()));
tile2.setActionHandler(tgl2::fire);
var tile3 = new Tile("Cache Size (Mb)", null);
var spinner = new Spinner<>(10, 100, 50);
@ -187,7 +187,7 @@ public class TilePage extends OutlinePage {
);
var tgl3 = new ToggleSwitch();
tile4.setAction(tgl3);
tile4.setActionHandler(() -> tgl3.setSelected(!tgl3.isSelected()));
tile4.setActionHandler(tgl3::fire);
var box = new VBox(tile1, tile2, tile3, new Separator(), tile4);
//snippet_3:end

@ -63,7 +63,10 @@ public final class TooltipPage extends OutlinePage {
modified to show plain text to the user."""
);
return new ExampleBox(box, new Snippet(getClass(), 1), description);
var example = new ExampleBox(box, new Snippet(getClass(), 1), description);
example.setAllowDisable(false);
return example;
}
private ExampleBox positionExample() {
@ -98,7 +101,10 @@ public final class TooltipPage extends OutlinePage {
The point can be set to a corner of the popup window or a corner of its content."""
);
return new ExampleBox(box, new Snippet(getClass(), 2), description);
var example = new ExampleBox(box, new Snippet(getClass(), 2), description);
example.setAllowDisable(false);
return example;
}
private Label createLabel(String text) {

@ -49,10 +49,11 @@ public final class TypographyPage extends OutlinePage {
addPageHeader();
addFormattedText("""
Because AtlantaFX is also distributed as a single CSS file, it does not come \
with any fonts. However, it does support several utility classes demonstrated \
below that can be used to manipulate font properties. If you need a formatted \
text support have a look at [i]BBCodeParser[/i]."""
Because AtlantaFX is also distributed as a single CSS file, it does not come \
with any fonts. However, it does support several utility classes demonstrated \
below that can be used to manipulate font properties. If you need a formatted \
text support have a look at [url=local://general.BBCodePage]BBCodeParser[/url].""",
true
);
addSection("Font Size", fontSizeExample());
addSection("Font Weight", fontWeightExample());

@ -68,7 +68,7 @@
-fx-min-height: 2.1em;
-fx-pref-height: 2.1em;
-fx-max-height: 2.1em;
-fx-padding: 0 0 0 1.2em;
-fx-padding: 0 6px 0 1.2em;
-fx-border-color: -color-border-muted;
-fx-border-width: 0 0 0 1;
@ -106,5 +106,12 @@
-fx-icon-code: mdmz-remove;
}
}
.tag {
-fx-padding: 2px 4px 2px 4px;
-fx-background-radius: 4px;
-fx-font-size: 0.75em;
-fx-background-color: -color-success-subtle;
}
}
}