From dfdad64e93cda10ac15ae6b614e1aac1b2ca45f0 Mon Sep 17 00:00:00 2001 From: Layue13 Date: Sun, 8 Nov 2026 13:58:07 +0800 Subject: [PATCH] feat: warm cream palette, new home page with line art and join card, 987x610 window Co-Authored-By: Claude Sonnet 5.5 --- .../jackhuang/hmcl/setting/StyleSheets.java | 57 +----- .../java/org/jackhuang/hmcl/theme/Themes.java | 7 +- .../org/jackhuang/hmcl/theme/WarmPalette.java | 21 +++ .../hmcl/ui/decorator/Decorator.java | 4 +- .../hmcl/ui/decorator/MainWindowPane.java | 33 +--- .../org/jackhuang/hmcl/ui/main/HomeArt.java | 85 +++++++++ .../org/jackhuang/hmcl/ui/main/MainPage.java | 167 ++++++++---------- HMCL/src/main/resources/assets/css/blue.css | 61 ------- HMCL/src/main/resources/assets/css/root.css | 75 ++++++++ HMCL/src/main/resources/assets/css/warm.css | 64 +++++++ .../resources/assets/lang/I18N.properties | 6 + .../resources/assets/lang/I18N_lzh.properties | 6 + .../assets/lang/I18N_zh_Hans.properties | 6 + .../assets/lang/I18N_zh_Hant.properties | 6 + 14 files changed, 356 insertions(+), 242 deletions(-) create mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/theme/WarmPalette.java create mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/ui/main/HomeArt.java delete mode 100644 HMCL/src/main/resources/assets/css/blue.css create mode 100644 HMCL/src/main/resources/assets/css/warm.css diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/StyleSheets.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/StyleSheets.java index 7945ddfbce..edef092a35 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/StyleSheets.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/StyleSheets.java @@ -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) { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/theme/Themes.java b/HMCL/src/main/java/org/jackhuang/hmcl/theme/Themes.java index 9d54e6019c..84f17581e0 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/theme/Themes.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/theme/Themes.java @@ -1104,11 +1104,8 @@ public final class Themes { /// The title text fill derived from the current color scheme. private static final ObjectBinding 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. diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/theme/WarmPalette.java b/HMCL/src/main/java/org/jackhuang/hmcl/theme/WarmPalette.java new file mode 100644 index 0000000000..9bddc098f6 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/theme/WarmPalette.java @@ -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"); +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/Decorator.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/Decorator.java index 28d7ce7e87..8e21c52d9c 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/Decorator.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/Decorator.java @@ -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; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/MainWindowPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/MainWindowPane.java index ff94c48283..0152a00b84 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/MainWindowPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/MainWindowPane.java @@ -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. diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/HomeArt.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/HomeArt.java new file mode 100644 index 0000000000..40486e53a9 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/HomeArt.java @@ -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 stroke(T shape, String styleClass) { + shape.setFill(null); + shape.getStyleClass().addAll("home-art", styleClass); + return shape; + } +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/MainPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/MainPage.java index 6482721027..76dc61ed4d 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/MainPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/MainPage.java @@ -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 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() { diff --git a/HMCL/src/main/resources/assets/css/blue.css b/HMCL/src/main/resources/assets/css/blue.css deleted file mode 100644 index 27f26fa8e3..0000000000 --- a/HMCL/src/main/resources/assets/css/blue.css +++ /dev/null @@ -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; -} \ No newline at end of file diff --git a/HMCL/src/main/resources/assets/css/root.css b/HMCL/src/main/resources/assets/css/root.css index 7afc94b49c..7ddbb564ee 100644 --- a/HMCL/src/main/resources/assets/css/root.css +++ b/HMCL/src/main/resources/assets/css/root.css @@ -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; +} diff --git a/HMCL/src/main/resources/assets/css/warm.css b/HMCL/src/main/resources/assets/css/warm.css new file mode 100644 index 0000000000..68f0506a2f --- /dev/null +++ b/HMCL/src/main/resources/assets/css/warm.css @@ -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; +} diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index 1019541058..14ddbae3a7 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -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 diff --git a/HMCL/src/main/resources/assets/lang/I18N_lzh.properties b/HMCL/src/main/resources/assets/lang/I18N_lzh.properties index 754c5c2963..43b42a66dc 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_lzh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_lzh.properties @@ -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=啟戲 diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_Hans.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_Hans.properties index 739433a178..75d319289e 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_Hans.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_Hans.properties @@ -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=开始游戏 diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_Hant.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_Hant.properties index e2cb2bf8c8..2ef1b5943d 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_Hant.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_Hant.properties @@ -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=開始遊戲