feat: warm cream palette, new home page with line art and join card, 987x610 window
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
323d09b104
commit
dfdad64e93
14 files changed
+356
-242
No files matched your search
@@ -6,12 +6,6 @@ import javafx.beans.binding.Bindings;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.paint.Color;
|
||||
import org.glavo.monetfx.Brightness;
|
||||
import org.glavo.monetfx.ColorRole;
|
||||
import org.glavo.monetfx.ColorScheme;
|
||||
import org.jackhuang.hmcl.theme.ResolvedTheme;
|
||||
import org.jackhuang.hmcl.theme.ThemeColor;
|
||||
import org.jackhuang.hmcl.theme.Themes;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -100,55 +94,14 @@ public final class StyleSheets {
|
||||
}
|
||||
|
||||
private static String getBrightnessStyleSheet() {
|
||||
return Themes.getColorScheme().getBrightness() == Brightness.LIGHT
|
||||
? "/assets/css/brightness-light.css"
|
||||
: "/assets/css/brightness-dark.css";
|
||||
}
|
||||
|
||||
private static void addColor(StringBuilder builder, String name, Color color) {
|
||||
builder.append(" ").append(name)
|
||||
.append(": ").append(ThemeColor.getColorDisplayName(color)).append(";\n");
|
||||
}
|
||||
|
||||
private static void addColor(StringBuilder builder, String name, Color color, double opacity) {
|
||||
builder.append(" ").append(name)
|
||||
.append(": ").append(ThemeColor.getColorDisplayNameWithOpacity(color, opacity)).append(";\n");
|
||||
}
|
||||
|
||||
private static void addColor(StringBuilder builder, ColorScheme scheme, ColorRole role, double opacity) {
|
||||
builder.append(" ").append(role.getVariableName()).append("-transparent-%02d".formatted((int) (100 * opacity)))
|
||||
.append(": ").append(ThemeColor.getColorDisplayNameWithOpacity(scheme.getColor(role), opacity))
|
||||
.append(";\n");
|
||||
return "/assets/css/brightness-light.css";
|
||||
}
|
||||
|
||||
/// Returns the launcher color style sheet.
|
||||
///
|
||||
/// The launcher ships a single warm palette; user-selected themes are no longer applied.
|
||||
private static String getThemeStyleSheet() {
|
||||
final String blueCss = "/assets/css/blue.css";
|
||||
|
||||
if (ResolvedTheme.DEFAULT.equals(Themes.getTheme()))
|
||||
return blueCss;
|
||||
|
||||
ColorScheme scheme = Themes.getColorScheme();
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("* {\n");
|
||||
for (ColorRole colorRole : ColorRole.ALL) {
|
||||
addColor(builder, colorRole.getVariableName(), scheme.getColor(colorRole));
|
||||
}
|
||||
|
||||
addColor(builder, "-monet-primary-seed", scheme.getPrimaryColorSeed());
|
||||
|
||||
addColor(builder, scheme, ColorRole.PRIMARY, 0.5);
|
||||
addColor(builder, scheme, ColorRole.PRIMARY, 0.8);
|
||||
addColor(builder, scheme, ColorRole.SECONDARY_CONTAINER, 0.5);
|
||||
addColor(builder, scheme, ColorRole.SURFACE, 0.5);
|
||||
addColor(builder, scheme, ColorRole.SURFACE, 0.8);
|
||||
addColor(builder, scheme, ColorRole.ON_SURFACE_VARIANT, 0.38);
|
||||
addColor(builder, scheme, ColorRole.SURFACE_CONTAINER_LOW, 0.8);
|
||||
addColor(builder, scheme, ColorRole.SECONDARY_CONTAINER, 0.8);
|
||||
addColor(builder, scheme, ColorRole.INVERSE_SURFACE, 0.8);
|
||||
|
||||
builder.append("}\n");
|
||||
return toStyleSheetUri(builder.toString());
|
||||
return "/assets/css/warm.css";
|
||||
}
|
||||
|
||||
public static void init(Scene scene) {
|
||||
|
||||
@@ -1104,11 +1104,8 @@ public final class Themes {
|
||||
|
||||
/// The title text fill derived from the current color scheme.
|
||||
private static final ObjectBinding<Color> titleFill = Bindings.createObjectBinding(
|
||||
() -> titleBarTransparent.get()
|
||||
? getColorScheme().getOnSurface()
|
||||
: getColorScheme().getOnPrimaryContainer(),
|
||||
colorSchemeProperty(),
|
||||
titleBarTransparent
|
||||
() -> WarmPalette.INK,
|
||||
colorSchemeProperty()
|
||||
);
|
||||
|
||||
/// Returns the title text fill property derived from the current color scheme.
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
|
||||
package org.jackhuang.hmcl.theme;
|
||||
|
||||
import javafx.scene.paint.Color;
|
||||
import org.jetbrains.annotations.NotNullByDefault;
|
||||
|
||||
/// The fixed warm cream palette used by window chrome that is painted from Java.
|
||||
///
|
||||
/// Values match `/assets/css/warm.css`, which supplies the same colors to style sheets.
|
||||
@NotNullByDefault
|
||||
public final class WarmPalette {
|
||||
private WarmPalette() {
|
||||
}
|
||||
|
||||
/// The window and title-bar background.
|
||||
public static final Color WINDOW = Color.web("#F3EEE6");
|
||||
|
||||
/// The title-bar text and icon color.
|
||||
public static final Color INK = Color.web("#2A2622");
|
||||
}
|
||||
@@ -81,10 +81,10 @@ import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
|
||||
@NotNullByDefault
|
||||
public final class Decorator {
|
||||
/// The minimum width, in pixels, of the visible window content.
|
||||
private static final double MIN_CONTENT_WIDTH = 800.0;
|
||||
private static final double MIN_CONTENT_WIDTH = 987.0;
|
||||
|
||||
/// The minimum height, in pixels, including the 450-pixel background and 40-pixel title bar.
|
||||
private static final double MIN_CONTENT_HEIGHT = 450.0 + 40.0;
|
||||
private static final double MIN_CONTENT_HEIGHT = 570.0 + 40.0;
|
||||
|
||||
/// The minimum visible overlap, in pixels, used to accept a persisted window position.
|
||||
private static final double MIN_VISIBLE_WINDOW_AREA = 20.0;
|
||||
|
||||
@@ -27,6 +27,7 @@ import javafx.util.Duration;
|
||||
import org.glavo.monetfx.ColorRole;
|
||||
import org.glavo.monetfx.ColorScheme;
|
||||
import org.jackhuang.hmcl.theme.Themes;
|
||||
import org.jackhuang.hmcl.theme.WarmPalette;
|
||||
import org.jackhuang.hmcl.ui.*;
|
||||
import org.jackhuang.hmcl.ui.animation.ContainerAnimations;
|
||||
import org.jackhuang.hmcl.ui.animation.TransitionPane;
|
||||
@@ -81,7 +82,7 @@ final class MainWindowPane extends StackPane {
|
||||
() -> Themes.windowTransparentProperty().get()
|
||||
? null
|
||||
: new Background(new BackgroundFill(
|
||||
Themes.getColorScheme().getColor(ColorRole.SURFACE_CONTAINER),
|
||||
WarmPalette.WINDOW,
|
||||
CornerRadii.EMPTY,
|
||||
Insets.EMPTY)),
|
||||
Themes.windowTransparentProperty(),
|
||||
@@ -153,16 +154,7 @@ final class MainWindowPane extends StackPane {
|
||||
Region backgroundNode = new Region();
|
||||
backgroundNode.setMouseTransparent(true);
|
||||
StackPane.setAlignment(backgroundNode, Pos.BOTTOM_CENTER);
|
||||
holder.onWeakChangeAndOperate(Themes.backgroundProperty(), background -> {
|
||||
double opacity = background.opacity();
|
||||
if (opacity >= 0.001) {
|
||||
backgroundNode.setBackground(background.background());
|
||||
backgroundNode.setOpacity(opacity);
|
||||
} else {
|
||||
backgroundNode.setBackground(null);
|
||||
backgroundNode.setOpacity(0);
|
||||
}
|
||||
});
|
||||
// The launcher paints a flat cream window; wallpapers are no longer used.
|
||||
return backgroundNode;
|
||||
}
|
||||
|
||||
@@ -195,21 +187,10 @@ final class MainWindowPane extends StackPane {
|
||||
|
||||
/// Recomputes the title-bar background for the current theme and transparency preference.
|
||||
private void updateTitleBarBackground() {
|
||||
@Nullable ColorScheme colorScheme = Themes.getColorScheme();
|
||||
if (colorScheme == null) {
|
||||
titleBar.setBackground(null);
|
||||
} else if (Themes.titleBarTransparentProperty().get()) {
|
||||
Color surface = colorScheme.getSurface();
|
||||
titleBar.setBackground(new Background(new BackgroundFill(
|
||||
new Color(surface.getRed(), surface.getGreen(), surface.getBlue(), 0.5),
|
||||
CornerRadii.EMPTY,
|
||||
Insets.EMPTY)));
|
||||
} else {
|
||||
titleBar.setBackground(new Background(new BackgroundFill(
|
||||
colorScheme.getPrimaryContainer(),
|
||||
CornerRadii.EMPTY,
|
||||
Insets.EMPTY)));
|
||||
}
|
||||
titleBar.setBackground(new Background(new BackgroundFill(
|
||||
WarmPalette.WINDOW,
|
||||
CornerRadii.EMPTY,
|
||||
Insets.EMPTY)));
|
||||
}
|
||||
|
||||
/// Rebuilds the navigation bar from the current page state.
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
|
||||
package org.jackhuang.hmcl.ui.main;
|
||||
|
||||
import javafx.animation.Interpolator;
|
||||
import javafx.animation.Timeline;
|
||||
import javafx.animation.TranslateTransition;
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.shape.Line;
|
||||
import javafx.scene.shape.Polygon;
|
||||
import javafx.scene.shape.Rectangle;
|
||||
import javafx.scene.shape.Shape;
|
||||
import javafx.util.Duration;
|
||||
import org.jackhuang.hmcl.ui.animation.AnimationUtils;
|
||||
import org.jetbrains.annotations.NotNullByDefault;
|
||||
|
||||
/// Builds the line illustration on the home page: a floating block island with a tree and a blocky figure.
|
||||
///
|
||||
/// All shapes are unfilled strokes whose colors come from the `.home-art` style classes, so the drawing
|
||||
/// follows the launcher palette. The island drifts slowly up and down unless animations are disabled.
|
||||
@NotNullByDefault
|
||||
final class HomeArt {
|
||||
private HomeArt() {
|
||||
}
|
||||
|
||||
/// Creates the illustration, sized 290 by 250 pixels.
|
||||
///
|
||||
/// @return the illustration root node
|
||||
static Node create() {
|
||||
Group island = new Group(
|
||||
// Stepped underside of the island, then the grass line along its top.
|
||||
stroke(new Polygon(30, 150, 250, 150, 250, 166, 232, 166, 232, 184, 212, 184, 212, 204,
|
||||
176, 204, 176, 222, 104, 222, 104, 204, 68, 204, 68, 184, 48, 184, 48, 166, 30, 166), "home-art-line"),
|
||||
stroke(new Line(30, 158, 250, 158), "home-art-line"),
|
||||
// Tree: trunk and three stacked leaf blocks.
|
||||
stroke(rect(186, 96, 8, 54), "home-art-line"),
|
||||
stroke(rect(162, 70, 56, 26), "home-art-line"),
|
||||
stroke(rect(170, 50, 40, 20), "home-art-line"),
|
||||
stroke(rect(178, 34, 24, 16), "home-art-line"),
|
||||
// Generic blocky figure: legs, torso, arms and head.
|
||||
stroke(rect(88, 126, 10, 24), "home-art-figure"),
|
||||
stroke(rect(102, 126, 10, 24), "home-art-figure"),
|
||||
stroke(rect(88, 92, 24, 34), "home-art-figure"),
|
||||
stroke(rect(76, 92, 12, 34), "home-art-figure"),
|
||||
stroke(rect(112, 92, 12, 34), "home-art-figure"),
|
||||
stroke(rect(88, 68, 24, 24), "home-art-figure"));
|
||||
|
||||
Pane root = new Pane(
|
||||
stroke(new Line(20, 30, 54, 30), "home-art-line"),
|
||||
stroke(new Line(30, 38, 52, 38), "home-art-line"),
|
||||
stroke(new Line(200, 14, 240, 14), "home-art-line"),
|
||||
stroke(new Line(210, 22, 234, 22), "home-art-line"),
|
||||
stroke(rect(22, 62, 14, 14), "home-art-line"),
|
||||
stroke(rect(42, 100, 10, 10), "home-art-line"),
|
||||
stroke(rect(238, 108, 10, 10), "home-art-line"),
|
||||
island);
|
||||
root.setPrefSize(290, 250);
|
||||
root.setMaxSize(290, 250);
|
||||
|
||||
if (AnimationUtils.isAnimationEnabled()) {
|
||||
TranslateTransition bob = new TranslateTransition(Duration.seconds(4), island);
|
||||
bob.setFromY(0);
|
||||
bob.setToY(-5);
|
||||
bob.setAutoReverse(true);
|
||||
bob.setCycleCount(Timeline.INDEFINITE);
|
||||
bob.setInterpolator(Interpolator.EASE_BOTH);
|
||||
bob.play();
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
/// Creates an unfilled rectangle.
|
||||
private static Rectangle rect(double x, double y, double width, double height) {
|
||||
return new Rectangle(x, y, width, height);
|
||||
}
|
||||
|
||||
/// Makes a shape an unfilled outline styled by `styleClass`.
|
||||
private static <T extends Shape> T stroke(T shape, String styleClass) {
|
||||
shape.setFill(null);
|
||||
shape.getStyleClass().addAll("home-art", styleClass);
|
||||
return shape;
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,8 @@ import javafx.scene.image.ImageView;
|
||||
import javafx.scene.input.MouseButton;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.util.Duration;
|
||||
@@ -59,8 +61,6 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
||||
BindingMapping.of(GameDirectoryManager.selectedRepositoryProperty())
|
||||
.flatMap(HMCLGameRepository::snapshotProperty);
|
||||
|
||||
private final JFXButton menuButton;
|
||||
|
||||
{
|
||||
HBox titleNode = new HBox(8);
|
||||
titleNode.setPadding(new Insets(0, 0, 0, 2));
|
||||
@@ -79,111 +79,86 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
||||
|
||||
state.setValue(new State(null, titleNode, false, false, true));
|
||||
|
||||
setPadding(new Insets(20));
|
||||
setPadding(new Insets(34, 55, 34, 55));
|
||||
|
||||
|
||||
|
||||
HBox launchPane = new HBox();
|
||||
launchPane.getStyleClass().add("launch-pane");
|
||||
FXUtils.onChangeAndOperate(selectedRepositorySnapshot, ignored -> mutableInstances.setAll(GameDirectoryManager.getSelectedRepository().getDisplayInstances().toList()));
|
||||
FXUtils.onScroll(launchPane, instances, list -> {
|
||||
@Nullable HMCLGameInstance currentGame = getCurrentGame();
|
||||
@Nullable GameInstanceID currentId = currentGame != null ? currentGame.getId() : null;
|
||||
return Lang.indexWhere(list, instance -> instance.getId().equals(currentId));
|
||||
}, instance -> instance.getRepository().setSelectedInstance(instance));
|
||||
|
||||
StackPane.setAlignment(launchPane, Pos.BOTTOM_RIGHT);
|
||||
{
|
||||
JFXButton launchButton = new JFXButton();
|
||||
launchButton.getStyleClass().add("launch-button");
|
||||
launchButton.setDefaultButton(true);
|
||||
{
|
||||
VBox graphic = new VBox();
|
||||
graphic.setAlignment(Pos.CENTER);
|
||||
Label launchLabel = new Label();
|
||||
launchLabel.setStyle("-fx-font-size: 16px;");
|
||||
Label currentLabel = new Label();
|
||||
currentLabel.setStyle("-fx-font-size: 12px;");
|
||||
// Left column: greeting, headline and a short description.
|
||||
Label eyebrow = new Label(i18n("home.welcome"));
|
||||
eyebrow.getStyleClass().add("home-eyebrow");
|
||||
Label headline = new Label(i18n("home.title"));
|
||||
headline.getStyleClass().add("home-title");
|
||||
headline.setWrapText(true);
|
||||
Label subtitle = new Label(i18n("home.subtitle"));
|
||||
subtitle.getStyleClass().add("home-subtitle");
|
||||
subtitle.setWrapText(true);
|
||||
VBox hero = new VBox(8, eyebrow, headline, subtitle);
|
||||
hero.setPrefWidth(330);
|
||||
hero.setMaxWidth(330);
|
||||
headline.setPrefWidth(330);
|
||||
subtitle.setPrefWidth(330);
|
||||
hero.setMaxHeight(Region.USE_PREF_SIZE);
|
||||
StackPane.setAlignment(hero, Pos.TOP_LEFT);
|
||||
hero.setPadding(new Insets(21, 0, 0, 0));
|
||||
|
||||
FXUtils.onChangeAndOperate(currentGameProperty(), new Consumer<>() {
|
||||
private Tooltip tooltip;
|
||||
// Line illustration on the right, behind the content.
|
||||
Node art = HomeArt.create();
|
||||
StackPane.setAlignment(art, Pos.TOP_RIGHT);
|
||||
art.setMouseTransparent(true);
|
||||
((Region) art).setMaxSize(290, 250);
|
||||
|
||||
@Override
|
||||
public void accept(@Nullable HMCLGameInstance currentGame) {
|
||||
if (currentGame == null) {
|
||||
launchLabel.setText(i18n("instance.launch.empty"));
|
||||
currentLabel.setText(null);
|
||||
graphic.getChildren().setAll(launchLabel);
|
||||
FXUtils.setOnActionWithCooldown(launchButton, MainPage.this::launchNoGame);
|
||||
if (tooltip == null)
|
||||
tooltip = new Tooltip(i18n("instance.launch.empty.tooltip"));
|
||||
FXUtils.installFastTooltip(launchButton, tooltip);
|
||||
} else {
|
||||
launchLabel.setText(i18n("server.join"));
|
||||
currentLabel.setText(currentGame.getId().toString());
|
||||
graphic.getChildren().setAll(launchLabel, currentLabel);
|
||||
FXUtils.setOnActionWithCooldown(launchButton, MainPage.this::launch);
|
||||
if (tooltip != null)
|
||||
Tooltip.uninstall(launchButton, tooltip);
|
||||
}
|
||||
}
|
||||
});
|
||||
// Bottom card: what will be launched, and the join button.
|
||||
Label packLabel = factLabel(i18n("home.pack"));
|
||||
Label packValue = new Label();
|
||||
packValue.getStyleClass().add("home-fact-value");
|
||||
Label routeLabel = factLabel(i18n("home.route"));
|
||||
Label routeValue = new Label();
|
||||
routeValue.getStyleClass().add("home-fact-value");
|
||||
VBox packFact = new VBox(3, packLabel, packValue);
|
||||
VBox routeFact = new VBox(3, routeLabel, routeValue);
|
||||
HBox facts = new HBox(34, packFact, routeFact);
|
||||
facts.setAlignment(Pos.CENTER_LEFT);
|
||||
|
||||
launchButton.setGraphic(graphic);
|
||||
JFXButton joinButton = new JFXButton();
|
||||
joinButton.getStyleClass().add("join-button");
|
||||
joinButton.setDefaultButton(true);
|
||||
|
||||
Region spacer = new Region();
|
||||
HBox.setHgrow(spacer, Priority.ALWAYS);
|
||||
HBox card = new HBox(21, facts, spacer, joinButton);
|
||||
card.getStyleClass().add("home-card");
|
||||
card.setAlignment(Pos.CENTER_LEFT);
|
||||
card.setMaxHeight(Region.USE_PREF_SIZE);
|
||||
StackPane.setAlignment(card, Pos.BOTTOM_CENTER);
|
||||
|
||||
FXUtils.onChangeAndOperate(currentGameProperty(), currentGame -> {
|
||||
if (currentGame == null) {
|
||||
joinButton.setText(i18n("instance.launch.empty"));
|
||||
FXUtils.setOnActionWithCooldown(joinButton, MainPage.this::launchNoGame);
|
||||
packValue.setText(i18n("home.not_installed"));
|
||||
routeFact.setVisible(false);
|
||||
routeFact.setManaged(false);
|
||||
} else {
|
||||
joinButton.setText(i18n("server.join"));
|
||||
FXUtils.setOnActionWithCooldown(joinButton, MainPage.this::launch);
|
||||
packValue.setText(currentGame.getId().toString());
|
||||
ServerEndpoint.@Nullable Route route = ServerEndpoint.selected(currentGame.getModpackConfigurationFile());
|
||||
routeFact.setVisible(route != null);
|
||||
routeFact.setManaged(route != null);
|
||||
routeValue.setText(route != null ? route.name() : "");
|
||||
}
|
||||
});
|
||||
|
||||
menuButton = new JFXButton();
|
||||
menuButton.getStyleClass().add("menu-button");
|
||||
menuButton.setOnAction(e -> {
|
||||
if (GameListPopupMenu.hideShowing(menuButton)) {
|
||||
return;
|
||||
}
|
||||
|
||||
JFXPopup popup = GameListPopupMenu.showAndGetPopup(
|
||||
menuButton,
|
||||
JFXPopup.PopupVPosition.BOTTOM,
|
||||
JFXPopup.PopupHPosition.RIGHT,
|
||||
0,
|
||||
-menuButton.getHeight(),
|
||||
instances
|
||||
);
|
||||
|
||||
Node graphic = menuButton.getGraphic();
|
||||
if (graphic != null) {
|
||||
if (AnimationUtils.isAnimationEnabled()) {
|
||||
Duration duration = Duration.millis(200);
|
||||
RotateTransition rotateOpen = new RotateTransition(duration, graphic);
|
||||
rotateOpen.setToAngle(-180);
|
||||
FXUtils.playAnimation(graphic, "arrow-rotation", rotateOpen);
|
||||
|
||||
popup.setOnHidden(windowEvent -> {
|
||||
RotateTransition rotateClose = new RotateTransition(duration, graphic);
|
||||
rotateClose.setToAngle(0);
|
||||
FXUtils.playAnimation(graphic, "arrow-rotation", rotateClose);
|
||||
});
|
||||
} else {
|
||||
graphic.setRotate(-180);
|
||||
popup.setOnHidden(windowEvent -> graphic.setRotate(0));
|
||||
}
|
||||
}
|
||||
});
|
||||
FXUtils.installFastTooltip(menuButton, i18n("instance.switch"));
|
||||
menuButton.setGraphic(SVG.ARROW_DROP_UP.createIcon(30));
|
||||
|
||||
EventHandler<MouseEvent> secondaryClickHandle = event -> {
|
||||
if (event.getButton() == MouseButton.SECONDARY && event.getClickCount() == 1) {
|
||||
menuButton.fire();
|
||||
event.consume();
|
||||
}
|
||||
};
|
||||
launchButton.addEventHandler(MouseEvent.MOUSE_CLICKED, secondaryClickHandle);
|
||||
menuButton.addEventHandler(MouseEvent.MOUSE_CLICKED, secondaryClickHandle);
|
||||
|
||||
launchPane.getChildren().setAll(launchButton, menuButton);
|
||||
}
|
||||
|
||||
getChildren().addAll(launchPane);
|
||||
getChildren().addAll(art, hero, card);
|
||||
}
|
||||
|
||||
/// Creates the small caption above a fact value in the home card.
|
||||
private static Label factLabel(String text) {
|
||||
Label label = new Label(text);
|
||||
label.getStyleClass().add("home-fact-label");
|
||||
return label;
|
||||
}
|
||||
|
||||
private void launch() {
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
* {
|
||||
-monet-primary: #4352A5;
|
||||
-monet-on-primary: #FFFFFF;
|
||||
-monet-primary-container: #5C6BC0;
|
||||
-monet-on-primary-container: #F8F6FF;
|
||||
-monet-primary-fixed: #DEE0FF;
|
||||
-monet-primary-fixed-dim: #BAC3FF;
|
||||
-monet-on-primary-fixed: #00105B;
|
||||
-monet-on-primary-fixed-variant: #2F3F92;
|
||||
-monet-secondary: #575C7F;
|
||||
-monet-on-secondary: #FFFFFF;
|
||||
-monet-secondary-container: #D0D5FD;
|
||||
-monet-on-secondary-container: #565B7D;
|
||||
-monet-secondary-fixed: #DEE0FF;
|
||||
-monet-secondary-fixed-dim: #BFC4EC;
|
||||
-monet-on-secondary-fixed: #141938;
|
||||
-monet-on-secondary-fixed-variant: #3F4566;
|
||||
-monet-tertiary: #775200;
|
||||
-monet-on-tertiary: #FFFFFF;
|
||||
-monet-tertiary-container: #976900;
|
||||
-monet-on-tertiary-container: #FFF6EE;
|
||||
-monet-tertiary-fixed: #FFDEAC;
|
||||
-monet-tertiary-fixed-dim: #F6BD58;
|
||||
-monet-on-tertiary-fixed: #281900;
|
||||
-monet-on-tertiary-fixed-variant: #5F4100;
|
||||
-monet-error: #BA1A1A;
|
||||
-monet-on-error: #FFFFFF;
|
||||
-monet-error-container: #FFDAD6;
|
||||
-monet-on-error-container: #93000A;
|
||||
-monet-surface: #FBF8FF;
|
||||
-monet-on-surface: #1B1B21;
|
||||
-monet-surface-dim: #DBD9E1;
|
||||
-monet-surface-bright: #FBF8FF;
|
||||
-monet-surface-container-lowest: #FFFFFF;
|
||||
-monet-surface-container-low: #F5F2FA;
|
||||
-monet-surface-container: #EFEDF5;
|
||||
-monet-surface-container-high: #E9E7EF;
|
||||
-monet-surface-container-highest: #E3E1E9;
|
||||
-monet-surface-variant: #E2E1EF;
|
||||
-monet-on-surface-variant: #454651;
|
||||
-monet-background: #FBF8FF;
|
||||
-monet-on-background: #1B1B21;
|
||||
-monet-outline: #767683;
|
||||
-monet-outline-variant: #C6C5D3;
|
||||
-monet-shadow: #000000;
|
||||
-monet-scrim: #000000;
|
||||
-monet-inverse-surface: #303036;
|
||||
-monet-inverse-on-surface: #F2EFF7;
|
||||
-monet-inverse-primary: #BAC3FF;
|
||||
-monet-surface-tint: #4858AB;
|
||||
-monet-primary-seed: #5C6BC0;
|
||||
-monet-primary-transparent-50: #4352A580;
|
||||
-monet-primary-transparent-80: #4352A5CC;
|
||||
-monet-secondary-container-transparent-50: #D0D5FD80;
|
||||
-monet-surface-transparent-50: #FBF8FF80;
|
||||
-monet-surface-transparent-80: #FBF8FFCC;
|
||||
-monet-on-surface-variant-transparent-38: #45465161;
|
||||
-monet-surface-container-low-transparent-80: #F5F2FACC;
|
||||
-monet-secondary-container-transparent-80: #D0D5FDCC;
|
||||
-monet-inverse-surface-transparent-80: #303036CC;
|
||||
}
|
||||
@@ -2171,3 +2171,78 @@
|
||||
.date-picker-popup .title {
|
||||
-fx-text-fill: -monet-on-surface-variant;
|
||||
}
|
||||
|
||||
|
||||
/* ---- Home page ---- */
|
||||
.home-eyebrow {
|
||||
-fx-font-family: "Noto Sans SC";
|
||||
-fx-font-size: 12px;
|
||||
-fx-text-fill: -monet-on-surface-variant;
|
||||
}
|
||||
|
||||
.home-title {
|
||||
-fx-font-family: "Noto Sans SC";
|
||||
-fx-font-weight: bold;
|
||||
-fx-font-size: 39px;
|
||||
-fx-text-fill: -monet-on-surface;
|
||||
}
|
||||
|
||||
.home-subtitle {
|
||||
-fx-font-size: 15px;
|
||||
-fx-line-spacing: 4px;
|
||||
-fx-text-fill: -monet-on-surface-variant;
|
||||
}
|
||||
|
||||
.home-card {
|
||||
-fx-background-color: -monet-surface-bright;
|
||||
-fx-background-radius: 21px;
|
||||
-fx-border-color: -monet-outline-variant;
|
||||
-fx-border-radius: 21px;
|
||||
-fx-padding: 21px 21px 21px 34px;
|
||||
}
|
||||
|
||||
.home-fact-label {
|
||||
-fx-font-family: "Noto Sans SC";
|
||||
-fx-font-size: 12px;
|
||||
-fx-text-fill: -monet-on-surface-variant;
|
||||
}
|
||||
|
||||
.home-fact-value {
|
||||
-fx-font-family: "Noto Sans SC";
|
||||
-fx-font-size: 15px;
|
||||
-fx-text-fill: -monet-on-surface;
|
||||
}
|
||||
|
||||
.join-button {
|
||||
-fx-font-family: "Noto Sans SC";
|
||||
-fx-font-size: 16px;
|
||||
-fx-background-color: -monet-primary;
|
||||
-fx-background-radius: 13px;
|
||||
-fx-text-fill: -monet-on-primary;
|
||||
-fx-padding: 13px 34px;
|
||||
-fx-min-width: 179px;
|
||||
-fx-cursor: hand;
|
||||
}
|
||||
|
||||
.join-button:hover {
|
||||
-fx-background-color: derive(-monet-primary, 8%);
|
||||
}
|
||||
|
||||
.join-button:pressed {
|
||||
-fx-scale-x: 0.985;
|
||||
-fx-scale-y: 0.985;
|
||||
}
|
||||
|
||||
.join-button .label {
|
||||
-fx-text-fill: -monet-on-primary;
|
||||
}
|
||||
|
||||
.home-art-line {
|
||||
-fx-stroke: -monet-outline-variant;
|
||||
-fx-stroke-width: 1.5px;
|
||||
}
|
||||
|
||||
.home-art-figure {
|
||||
-fx-stroke: -monet-primary;
|
||||
-fx-stroke-width: 1.5px;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Warm cream palette with a clay accent. Every launcher color is derived from these variables.
|
||||
*/
|
||||
* {
|
||||
-monet-primary: #A9532F;
|
||||
-monet-on-primary: #FFF8F1;
|
||||
-monet-primary-container: #EFD9CC;
|
||||
-monet-on-primary-container: #4A2312;
|
||||
-monet-primary-fixed: #F6E3D8;
|
||||
-monet-primary-fixed-dim: #E8B99F;
|
||||
-monet-on-primary-fixed: #2E1307;
|
||||
-monet-on-primary-fixed-variant: #7F3C1F;
|
||||
-monet-secondary: #6E665B;
|
||||
-monet-on-secondary: #FAF7F1;
|
||||
-monet-secondary-container: #E9E1D3;
|
||||
-monet-on-secondary-container: #4A433A;
|
||||
-monet-secondary-fixed: #EDE6D9;
|
||||
-monet-secondary-fixed-dim: #CFC6B5;
|
||||
-monet-on-secondary-fixed: #231F19;
|
||||
-monet-on-secondary-fixed-variant: #51493F;
|
||||
-monet-tertiary: #5F7F54;
|
||||
-monet-on-tertiary: #FFFFFF;
|
||||
-monet-tertiary-container: #DCE5D2;
|
||||
-monet-on-tertiary-container: #1F3018;
|
||||
-monet-tertiary-fixed: #DCE5D2;
|
||||
-monet-tertiary-fixed-dim: #B5C7A8;
|
||||
-monet-on-tertiary-fixed: #121E0D;
|
||||
-monet-on-tertiary-fixed-variant: #3E5A34;
|
||||
-monet-error: #B3261E;
|
||||
-monet-on-error: #FFFFFF;
|
||||
-monet-error-container: #F9DEDC;
|
||||
-monet-on-error-container: #410E0B;
|
||||
-monet-surface: #F3EEE6;
|
||||
-monet-on-surface: #2A2622;
|
||||
-monet-surface-dim: #E2DBCF;
|
||||
-monet-surface-bright: #FAF7F1;
|
||||
-monet-surface-container-lowest: #FDFBF7;
|
||||
-monet-surface-container-low: #F8F4EC;
|
||||
-monet-surface-container: #EBE5DA;
|
||||
-monet-surface-container-high: #E4DDCF;
|
||||
-monet-surface-container-highest: #DDD5C7;
|
||||
-monet-surface-variant: #E7E0D3;
|
||||
-monet-on-surface-variant: #6E665B;
|
||||
-monet-background: #F3EEE6;
|
||||
-monet-on-background: #2A2622;
|
||||
-monet-outline: #8C8377;
|
||||
-monet-outline-variant: #DDD5C7;
|
||||
-monet-shadow: #000000;
|
||||
-monet-scrim: #000000;
|
||||
-monet-inverse-surface: #2A2622;
|
||||
-monet-inverse-on-surface: #F3EEE6;
|
||||
-monet-inverse-primary: #E8A47F;
|
||||
-monet-surface-tint: #A9532F;
|
||||
-monet-primary-seed: #A9532F;
|
||||
-monet-primary-transparent-50: #A9532F80;
|
||||
-monet-primary-transparent-80: #A9532FCC;
|
||||
-monet-secondary-container-transparent-50: #E9E1D380;
|
||||
-monet-surface-transparent-50: #F3EEE680;
|
||||
-monet-surface-transparent-80: #F3EEE6CC;
|
||||
-monet-on-surface-variant-transparent-38: #6E665B61;
|
||||
-monet-surface-container-low-transparent-80: #F8F4ECCC;
|
||||
-monet-secondary-container-transparent-80: #E9E1D3CC;
|
||||
-monet-inverse-surface-transparent-80: #2A2622CC;
|
||||
}
|
||||
@@ -791,6 +791,12 @@ instance.game.support_status.unsupported=Unsupported
|
||||
instance.game.support_status.untested=Untested
|
||||
instance.game.type=Type
|
||||
instance.launch=Launch Game
|
||||
home.welcome=Welcome back
|
||||
home.title=Join our world
|
||||
home.subtitle=One click syncs the modpack, prepares Java and connects you to the server.
|
||||
home.pack=Modpack
|
||||
home.route=Route
|
||||
home.not_installed=Not installed
|
||||
server.join=Join Server
|
||||
instance.launch_and_enter_world=Play World
|
||||
instance.launch.empty=Start Game
|
||||
|
||||
@@ -611,6 +611,12 @@ instance.game.snapshots=預版
|
||||
# instance.game.support_status.untested=
|
||||
instance.game.type=版類
|
||||
instance.launch=戲
|
||||
home.welcome=歸來
|
||||
home.title=入吾世
|
||||
home.subtitle=一點即同步、備器、入服。
|
||||
home.pack=整合包
|
||||
home.route=路
|
||||
home.not_installed=未裝
|
||||
server.join=入服
|
||||
# instance.launch_and_enter_world=
|
||||
instance.launch.empty=啟戲
|
||||
|
||||
@@ -614,6 +614,12 @@ instance.game.support_status.unsupported=不支持
|
||||
instance.game.support_status.untested=未经测试
|
||||
instance.game.type=版本类型
|
||||
instance.launch=启动游戏
|
||||
home.welcome=欢迎回来
|
||||
home.title=进入我们的世界
|
||||
home.subtitle=点一下就会同步整合包、准备好 Java,并直接连上服务器。
|
||||
home.pack=整合包
|
||||
home.route=线路
|
||||
home.not_installed=尚未安装
|
||||
server.join=进入服务器
|
||||
instance.launch_and_enter_world=进入世界
|
||||
instance.launch.empty=开始游戏
|
||||
|
||||
@@ -608,6 +608,12 @@ instance.game.support_status.unsupported=不支援
|
||||
instance.game.support_status.untested=未經測試
|
||||
instance.game.type=版本類型
|
||||
instance.launch=啟動遊戲
|
||||
home.welcome=歡迎回來
|
||||
home.title=進入我們的世界
|
||||
home.subtitle=點一下就會同步整合包、準備好 Java,並直接連上伺服器。
|
||||
home.pack=整合包
|
||||
home.route=線路
|
||||
home.not_installed=尚未安裝
|
||||
server.join=進入伺服器
|
||||
instance.launch_and_enter_world=進入世界
|
||||
instance.launch.empty=開始遊戲
|
||||
|
||||
Reference in new issue
Block a user