From 6448a002716631e9c5468b2ff492edc119e914c8 Mon Sep 17 00:00:00 2001 From: redphx <96280+redphx@users.noreply.github.com> Date: Fri, 3 Jan 2025 19:49:40 +0700 Subject: [PATCH] Show local co-op icon in details page --- src/assets/css/button.styl | 1 - src/assets/css/misc.styl | 9 ++++ src/assets/css/root.styl | 4 ++ src/modules/patcher/patcher.ts | 30 +++++++++++++- .../patcher/patches/src/game-card-icons.ts | 2 +- src/modules/ui/product-details.ts | 41 ++++++++++++------- src/utils/bx-icon.ts | 2 + src/utils/utils.ts | 2 +- 8 files changed, 73 insertions(+), 18 deletions(-) diff --git a/src/assets/css/button.styl b/src/assets/css/button.styl index 87fbd30..0ea50a7 100755 --- a/src/assets/css/button.styl +++ b/src/assets/css/button.styl @@ -106,7 +106,6 @@ &.bx-frosted { --button-alpha: 0.2; background-color: unquote('rgba(var(--button-rgb), var(--button-alpha))'); - backdrop-filter: blur(4px) brightness(1.5); &:not([disabled]):not(:active) { &:hover, &.bx-focusable:focus { diff --git a/src/assets/css/misc.styl b/src/assets/css/misc.styl index 70babd7..9a05068 100755 --- a/src/assets/css/misc.styl +++ b/src/assets/css/misc.styl @@ -1,3 +1,12 @@ +.bx-product-details-icons { + padding: 8px; + border-radius: 4px; + + svg { + margin-right: 8px; + } +} + .bx-product-details-buttons { display: flex; gap: 10px; diff --git a/src/assets/css/root.styl b/src/assets/css/root.styl index da56668..b531acd 100755 --- a/src/assets/css/root.styl +++ b/src/assets/css/root.styl @@ -149,6 +149,10 @@ div[class^=HUDButton-module__hiddenContainer] ~ div:not([class^=HUDButton-module font-family: var(--bx-normal-font) !important; } +.bx-frosted { + backdrop-filter: blur(4px) brightness(1.5); +} + select[multiple], select[multiple]:focus { overflow: auto; border: none; diff --git a/src/modules/patcher/patcher.ts b/src/modules/patcher/patcher.ts index f7e8438..8a8c801 100755 --- a/src/modules/patcher/patcher.ts +++ b/src/modules/patcher/patcher.ts @@ -1054,6 +1054,33 @@ ${subsVar} = subs; str = PatcherUtils.insertAt(str, returnIndex, newCode); return str; }, + + /* + // 27.0.6-hotfix.1, 28444.js + gameCardPassTitle(str: string) { + // Pass gameTitle info to gameCardCustomIcons() + let index = str.indexOf('=["productId","showInputBadges","ownershipBadgeType"'); + index > -1 && (index = PatcherUtils.indexOf(str, ',gameTitle:', index, 500, true)); + if (index < 0) { + return false; + } + + const gameTitleVar = PatcherUtils.getVariableNameAfter(str, index); + if (!gameTitleVar) { + return false; + } + + index = PatcherUtils.indexOf(str, 'return', index); + index = PatcherUtils.indexOf(str, 'productId:', index); + if (index < 0) { + return false; + } + + const newCode = `gameTitle: ${gameTitleVar},`; + str = PatcherUtils.insertAt(str, index, newCode); + return str; + }, + */ }; let PATCH_ORDERS = PatcherUtils.filterPatches([ @@ -1065,6 +1092,7 @@ let PATCH_ORDERS = PatcherUtils.filterPatches([ 'exposeReactCreateComponent', 'gameCardCustomIcons', + // 'gameCardPassTitle', 'modifyPreloadedState', @@ -1185,7 +1213,7 @@ let STREAM_PAGE_PATCH_ORDERS = PatcherUtils.filterPatches([ ]); let PRODUCT_DETAIL_PAGE_PATCH_ORDERS = PatcherUtils.filterPatches([ - AppInterface && 'detectProductDetailPage', + 'detectProductDetailPage', ]); const ALL_PATCHES = [...PATCH_ORDERS, ...HOME_PAGE_PATCH_ORDERS, ...STREAM_PAGE_PATCH_ORDERS, ...PRODUCT_DETAIL_PAGE_PATCH_ORDERS]; diff --git a/src/modules/patcher/patches/src/game-card-icons.ts b/src/modules/patcher/patches/src/game-card-icons.ts index 066518b..1b6d23b 100644 --- a/src/modules/patcher/patches/src/game-card-icons.ts +++ b/src/modules/patcher/patches/src/game-card-icons.ts @@ -5,5 +5,5 @@ const supportedInputIcons = $supportedInputIcons$; const { productId } = $param$; if (window.BX_EXPOSED.localCoOpManager.isSupported(productId)) { - supportedInputIcons.push(() => window.BX_EXPOSED.createReactLocalCoOpIcon()); + supportedInputIcons.push(window.BX_EXPOSED.createReactLocalCoOpIcon); } diff --git a/src/modules/ui/product-details.ts b/src/modules/ui/product-details.ts index cf19b8c..bb564ea 100755 --- a/src/modules/ui/product-details.ts +++ b/src/modules/ui/product-details.ts @@ -1,7 +1,8 @@ import { BX_FLAGS } from "@/utils/bx-flags"; import { BxIcon } from "@/utils/bx-icon"; import { AppInterface } from "@/utils/global"; -import { ButtonStyle, CE, createButton } from "@/utils/html"; +import { ButtonStyle, CE, createButton, createSvgIcon } from "@/utils/html"; +import { LocalCoOpManager } from "@/utils/local-co-op-manager"; import { t } from "@/utils/translation"; import { parseDetailsPath } from "@/utils/utils"; @@ -28,21 +29,33 @@ export class ProductDetailsPage { private static injectTimeoutId: number | null = null; static injectButtons() { - if (!AppInterface) { - return; - } - ProductDetailsPage.injectTimeoutId && clearTimeout(ProductDetailsPage.injectTimeoutId); ProductDetailsPage.injectTimeoutId = window.setTimeout(() => { - // Find action buttons container - const $container = document.querySelector('div[class*=ActionButtons-module__container]'); - if ($container && $container.parentElement) { - $container.parentElement.appendChild(CE('div', { - class: 'bx-product-details-buttons', - }, - ['android-handheld', 'android'].includes(BX_FLAGS.DeviceInfo.deviceType) && ProductDetailsPage.$btnShortcut, - ProductDetailsPage.$btnWallpaper, - )); + // Inputs + const $inputsContainer = document.querySelector('div[class*="Header-module__gamePassAndInputsContainer"]'); + if ($inputsContainer && !$inputsContainer.dataset.bxInjected) { + $inputsContainer.dataset.bxInjected = 'true'; + + const { productId } = parseDetailsPath(window.location.pathname); + if (LocalCoOpManager.getInstance().isSupported(productId || '')) { + $inputsContainer.insertAdjacentElement('afterend', CE('div', { + class: 'bx-product-details-icons bx-frosted', + }, createSvgIcon(BxIcon.LOCAL_CO_OP), t('local-co-op'))); + } + } + + // Inject buttons for Android app + if (AppInterface) { + // Find action buttons container + const $container = document.querySelector('div[class*=ActionButtons-module__container]'); + if ($container && $container.parentElement) { + $container.parentElement.appendChild(CE('div', { + class: 'bx-product-details-buttons', + }, + ['android-handheld', 'android'].includes(BX_FLAGS.DeviceInfo.deviceType) && ProductDetailsPage.$btnShortcut, + ProductDetailsPage.$btnWallpaper, + )); + } } }, 500); } diff --git a/src/utils/bx-icon.ts b/src/utils/bx-icon.ts index b57c4c2..fc48eac 100755 --- a/src/utils/bx-icon.ts +++ b/src/utils/bx-icon.ts @@ -10,6 +10,7 @@ import iconDisplay from "@assets/svg/display.svg" with { type: "text" }; import iconEye from "@assets/svg/eye.svg" with { type: "text" }; import iconEyeSlash from "@assets/svg/eye-slash.svg" with { type: "text" }; import iconHome from "@assets/svg/home.svg" with { type: "text" }; +import iconLocalCoOp from "@assets/svg/local-co-op.svg" with { type: "text" }; import iconNativeMkb from "@assets/svg/native-mkb.svg" with { type: "text" }; import iconNew from "@assets/svg/new.svg" with { type: "text" }; import iconPencil from "@assets/svg/pencil-simple-line.svg" with { type: "text" }; @@ -52,6 +53,7 @@ export const BxIcon = { EYE: iconEye, EYE_SLASH: iconEyeSlash, HOME: iconHome, + LOCAL_CO_OP: iconLocalCoOp, NATIVE_MKB: iconNativeMkb, NEW: iconNew, MANAGE: iconPencil, diff --git a/src/utils/utils.ts b/src/utils/utils.ts index a6cc549..23e3c58 100755 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -123,7 +123,7 @@ export function productTitleToSlug(title: string): string { export function parseDetailsPath(path: string) { const matches = /\/games\/(?[^\/]+)\/(?\w+)/.exec(path); if (!matches?.groups) { - return; + return {}; } const titleSlug = matches.groups.titleSlug!.replaceAll('\%' + '7C', '-');