From 416f89bbf441cfc8f681711bc4280e1b50739c3d Mon Sep 17 00:00:00 2001 From: tobspr Date: Sat, 19 Jun 2021 17:16:01 +0200 Subject: [PATCH] - Puzzle DLC browser improvements / new categories - Fix errors not being thrown sometimes - Minor other stuff --- src/css/mixins.scss | 18 ++-- src/css/states/puzzle_menu.scss | 81 +++++++++-------- src/js/core/state_manager.js | 7 +- src/js/states/main_menu.js | 2 +- src/js/states/puzzle_menu.js | 150 ++++++++++++++++++-------------- translations/base-en.yaml | 13 ++- 6 files changed, 159 insertions(+), 112 deletions(-) diff --git a/src/css/mixins.scss b/src/css/mixins.scss index 43f7a259..888d84d6 100644 --- a/src/css/mixins.scss +++ b/src/css/mixins.scss @@ -15,15 +15,15 @@ $hardwareAcc: null; // ---------------------------------------- /** Increased click area for this element, helpful on mobile */ @mixin IncreasedClickArea($size) { - &::after { - content: ""; - position: absolute; - top: #{D(-$size)}; - bottom: #{D(-$size)}; - left: #{D(-$size)}; - right: #{D(-$size)}; - // background: rgba(255, 0, 0, 0.3); - } + // &::after { + // content: ""; + // position: absolute; + // top: #{D(-$size)}; + // bottom: #{D(-$size)}; + // left: #{D(-$size)}; + // right: #{D(-$size)}; + // // background: rgba(255, 0, 0, 0.3); + // } } button, .increasedClickArea { diff --git a/src/css/states/puzzle_menu.scss b/src/css/states/puzzle_menu.scss index 2c0d3773..5f28d902 100644 --- a/src/css/states/puzzle_menu.scss +++ b/src/css/states/puzzle_menu.scss @@ -19,42 +19,54 @@ overflow: hidden; > .categoryChooser { - display: grid; - grid-auto-columns: 1fr; - grid-auto-flow: column; - @include S(grid-gap, 2px); - @include S(padding-right, 10px); + > .categories { + display: grid; + grid-auto-columns: 1fr; + grid-auto-flow: column; + @include S(grid-gap, 2px); + @include S(padding-right, 10px); + @include S(margin-bottom, 5px); - > .category { - background: $accentColorBright; - border-radius: 0; - color: $accentColorDark; - transition: all 0.12s ease-in-out; - transition-property: opacity, background-color, color; + .category { + background: $accentColorBright; + border-radius: 0; + color: $accentColorDark; + transition: all 0.12s ease-in-out; + transition-property: opacity, background-color, color; - &:first-child { - @include S(border-top-left-radius, $globalBorderRadius); - @include S(border-bottom-left-radius, $globalBorderRadius); - } - &:last-child { - border-top-right-radius: $globalBorderRadius; - border-bottom-right-radius: $globalBorderRadius; - } - - &.active { - background: $colorBlueBright; - opacity: 1 !important; - color: #fff; - cursor: default; - } - - @include DarkThemeOverride { - background: $accentColorDark; - color: #bbbbc4; + &:first-child { + @include S(border-top-left-radius, $globalBorderRadius); + @include S(border-bottom-left-radius, $globalBorderRadius); + } + &:last-child { + border-top-right-radius: $globalBorderRadius; + border-bottom-right-radius: $globalBorderRadius; + } &.active { background: $colorBlueBright; + opacity: 1 !important; color: #fff; + cursor: default; + } + + @include DarkThemeOverride { + background: $accentColorDark; + color: #bbbbc4; + + &.active { + background: $colorBlueBright; + color: #fff; + } + } + + &.root { + @include S(padding-top, 10px); + @include S(padding-bottom, 10px); + @include Text; + } + &.child { + @include PlainText; } } } @@ -62,12 +74,12 @@ > .puzzles { display: grid; - grid-template-columns: repeat(auto-fit, minmax(D(180px), 1fr)); + grid-template-columns: repeat(auto-fit, minmax(D(240px), 1fr)); @include S(grid-auto-rows, 65px); @include S(grid-gap, 7px); @include S(margin-top, 10px); @include S(padding-right, 4px); - @include S(height, 360px); + @include S(height, 320px); overflow-y: scroll; pointer-events: all; position: relative; @@ -203,14 +215,11 @@ font-weight: bold; @include S(margin-right, 3px); opacity: 0.7; + text-transform: uppercase; &.stage--easy { color: $colorGreenBright; } - &.stage--normal { - color: #000; - @include DarkThemeInvert; - } &.stage--medium { color: $colorOrangeBright; } diff --git a/src/js/core/state_manager.js b/src/js/core/state_manager.js index e0c04bba..2e55f5d4 100644 --- a/src/js/core/state_manager.js +++ b/src/js/core/state_manager.js @@ -89,8 +89,13 @@ export class StateManager { const dialogParent = document.createElement("div"); dialogParent.classList.add("modalDialogParent"); document.body.appendChild(dialogParent); + try { + this.currentState.internalEnterCallback(payload); + } catch (ex) { + console.error(ex); + throw ex; + } - this.currentState.internalEnterCallback(payload); this.app.sound.playThemeMusic(this.currentState.getThemeMusic()); this.currentState.onResized(this.app.screenWidth, this.app.screenHeight); diff --git a/src/js/states/main_menu.js b/src/js/states/main_menu.js index d1174020..10abb626 100644 --- a/src/js/states/main_menu.js +++ b/src/js/states/main_menu.js @@ -95,7 +95,7 @@ export class MainMenuState extends GameState { ${ - !G_WEGAME_VERSION && G_IS_STANDALONE && puzzleDlc + (!G_WEGAME_VERSION && G_IS_STANDALONE && puzzleDlc) || G_IS_DEV ? `
${T.puzzleMenu.loadPuzzle}
+ `; return ` @@ -91,18 +59,22 @@ export class PuzzleMenuState extends TextualGameState { getMainContentHTML() { let html = ` - -
- ${categories + +
+ ${Object.keys(navigation) .map( - category => ` - - ` + rootCategory => + `` ) .join("")} +
+ +
+
+
`; @@ -154,6 +126,49 @@ export class PuzzleMenuState extends TextualGameState { .then(() => (this.loading = false)); } + /** + * Selects a root category + * @param {string} rootCategory + * @param {string=} category + */ + selectRootCategory(rootCategory, category) { + const subCategory = category || navigation[rootCategory][0]; + console.warn("Select root category", rootCategory, category, "->", subCategory); + + if (this.loading) { + return; + } + if (this.activeCategory === subCategory) { + return; + } + + const activeCategory = this.htmlElement.querySelector(".active[data-root-category]"); + if (activeCategory) { + activeCategory.classList.remove("active"); + } + + this.htmlElement.querySelector(`[data-root-category="${rootCategory}"]`).classList.add("active"); + + // Rerender buttons + + const subContainer = this.htmlElement.querySelector(".subCategories"); + while (subContainer.firstChild) { + subContainer.removeChild(subContainer.firstChild); + } + + const children = navigation[rootCategory]; + for (const category of children) { + const button = document.createElement("button"); + button.setAttribute("data-category", category); + button.classList.add("styledButton", "category", "child"); + button.innerText = T.puzzleMenu.categories[category]; + this.trackClicks(button, () => this.selectCategory(category)); + subContainer.appendChild(button); + } + + this.selectCategory(subCategory); + } + /** * * @param {import("../savegame/savegame_typedefs").PuzzleMetadata[]} puzzles @@ -167,7 +182,10 @@ export class PuzzleMenuState extends TextualGameState { for (const puzzle of puzzles) { const elem = document.createElement("div"); elem.classList.add("puzzle"); - elem.classList.toggle("completed", puzzle.completed); + + if (this.activeCategory !== "mine") { + elem.classList.toggle("completed", puzzle.completed); + } if (puzzle.title) { const title = document.createElement("div"); @@ -176,7 +194,7 @@ export class PuzzleMenuState extends TextualGameState { elem.appendChild(title); } - if (puzzle.author) { + if (puzzle.author && !["official", "mine"].includes(this.activeCategory)) { const author = document.createElement("div"); author.classList.add("author"); author.innerText = "by " + puzzle.author; @@ -187,7 +205,10 @@ export class PuzzleMenuState extends TextualGameState { stats.classList.add("stats"); elem.appendChild(stats); - if (puzzle.downloads > 0) { + if ( + puzzle.downloads > 0 && + !["official", "easy", "medium", "hard"].includes(this.activeCategory) + ) { const difficulty = document.createElement("div"); difficulty.classList.add("difficulty"); @@ -198,14 +219,15 @@ export class PuzzleMenuState extends TextualGameState { difficulty.innerText = completionPercentage + "%"; stats.appendChild(difficulty); - if (completionPercentage < 10) { + if (completionPercentage < 40) { difficulty.classList.add("stage--hard"); - } else if (completionPercentage < 30) { + difficulty.innerText = T.puzzleMenu.difficulties.hard; + } else if (completionPercentage < 80) { difficulty.classList.add("stage--medium"); - } else if (completionPercentage < 60) { - difficulty.classList.add("stage--normal"); + difficulty.innerText = T.puzzleMenu.difficulties.medium; } else { difficulty.classList.add("stage--easy"); + difficulty.innerText = T.puzzleMenu.difficulties.easy; } } @@ -249,10 +271,6 @@ export class PuzzleMenuState extends TextualGameState { * @returns {Promise} */ getPuzzlesForCategory(category) { - if (category === "levels") { - return Promise.resolve(BUILTIN_PUZZLES); - } - const result = this.app.clientApi.apiListPuzzles(category); return result.catch(err => { logger.error("Failed to get", category, ":", err); @@ -300,24 +318,28 @@ export class PuzzleMenuState extends TextualGameState { } onEnter(payload) { - this.selectCategory(lastCategory); + // Find old category + let rootCategory = "categories"; + for (const [id, children] of Object.entries(navigation)) { + if (children.includes(lastCategory)) { + rootCategory = id; + break; + } + } + + this.selectRootCategory(rootCategory, lastCategory); if (payload && payload.error) { this.dialogs.showWarning(payload.error.title, payload.error.desc); } - for (const category of categories) { - const button = this.htmlElement.querySelector(`[data-category="${category}"]`); - this.trackClicks(button, () => this.selectCategory(category)); + for (const rootCategory of Object.keys(navigation)) { + const button = this.htmlElement.querySelector(`[data-root-category="${rootCategory}"]`); + this.trackClicks(button, () => this.selectRootCategory(rootCategory)); } this.trackClicks(this.htmlElement.querySelector("button.createPuzzle"), () => this.createNewPuzzle()); this.trackClicks(this.htmlElement.querySelector("button.loadPuzzle"), () => this.loadPuzzle()); - - if (G_IS_DEV && globalConfig.debug.testPuzzleMode) { - // this.createNewPuzzle(); - this.playPuzzle(SAMPLE_PUZZLE); - } } createEmptySavegame() { diff --git a/translations/base-en.yaml b/translations/base-en.yaml index a400ca74..791be47e 100644 --- a/translations/base-en.yaml +++ b/translations/base-en.yaml @@ -140,11 +140,22 @@ puzzleMenu: levels: Levels new: New top-rated: Top Rated - mine: My Puzzles + mine: Created short: Short easy: Easy + medium: Medium hard: Hard completed: Completed + official: Official + trending: Trending today + categories: Categories + difficulties: By Difficulty + account: My Puzzles + + difficulties: + easy: Easy + medium: Medium + hard: Hard validation: title: Invalid Puzzle