Skip to content

Commit

Permalink
plugin: render top bar for other tabs
Browse files Browse the repository at this point in the history
  • Loading branch information
ricewind012 committed Feb 2, 2025
1 parent 3d3c199 commit 81b989a
Show file tree
Hide file tree
Showing 12 changed files with 204 additions and 75 deletions.
File renamed without changes
File renamed without changes
12 changes: 12 additions & 0 deletions frontend/events/gamelistchange.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const GAME_LIST_CHANGE_EVENT_NAME = "game-list-change";

export interface GameListChangeEvent {
appid: number;
}

export function DispatchGameListChange(appid: number) {
const ev = new CustomEvent<GameListChangeEvent>(GAME_LIST_CHANGE_EVENT_NAME, {
detail: { appid },
});
window.dispatchEvent(ev);
}
47 changes: 47 additions & 0 deletions frontend/events/tabchange.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
export const TAB_CHANGE_EVENT_NAME = "tab-change";

export enum ESuperNavTab {
Store,
Library,
Community,
Profile,
Console,
Max,
}

export interface TabChangeEvent {
tab: ESuperNavTab;
}

export function DispatchTabChange(tab: ESuperNavTab) {
const ev = new CustomEvent<TabChangeEvent>(TAB_CHANGE_EVENT_NAME, {
detail: { tab },
});
window.dispatchEvent(ev);
}

type ClientTabSetting_t =
| "store"
| "news"
| "library"
| "community"
| "friendactivity"
| "profile"
| "console";

export function GetESuperNavTabFromSetting(tab: ClientTabSetting_t) {
switch (tab) {
case "store":
case "news":
return ESuperNavTab.Store;
case "library":
return ESuperNavTab.Library;
case "community":
case "friendactivity":
return ESuperNavTab.Community;
case "profile":
return ESuperNavTab.Profile;
case "console":
return ESuperNavTab.Console;
}
}
15 changes: 0 additions & 15 deletions frontend/gamelistchange.ts

This file was deleted.

35 changes: 30 additions & 5 deletions frontend/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import * as parts from "./parts";
import { CLog } from "./logger";
import { classes, waitForElement } from "./shared";
import type { CPopupManager, SteamPopup } from "./types/normal";
import { DispatchGameListChange } from "./gamelistchange";
import { DispatchTabChange } from "./events/tabchange";
import { DispatchGameListChange } from "./events/gamelistchange";

declare global {
const appStore: any;
Expand All @@ -15,6 +16,7 @@ declare global {
const g_PopupManager: CPopupManager;
const LocalizationManager: any;
const MainWindowBrowserManager: any;
const settingsStore: any;
const SteamUIStore: any;
const StoreItemCache: any;
const uiStore: any;
Expand Down Expand Up @@ -53,6 +55,10 @@ function AddPopupCreatedCallback(
}

g_PopupManager.AddPopupCreatedCallback((popup) => {
if (popup.m_strName !== popupName) {
return;
}

callback(popup);

// Only apply once
Expand All @@ -65,10 +71,6 @@ function AddPopupCreatedCallback(
* Intercepts the function that's called upon a selected game change in the library.
*/
function PatchUIStore(popup: SteamPopup) {
if (popup.m_strName !== MAIN_WINDOW_NAME) {
return;
}

const store = uiStore;
const orig = store.SetGameListSelection;
const logger = new CLog("PatchUIStore");
Expand All @@ -93,6 +95,28 @@ function PatchUIStore(popup: SteamPopup) {
};
}

async function AddSuperNavEvents(popup: SteamPopup) {
const doc = popup.m_popup.document;
const container = await waitForElement(`.${classes.supernav.SuperNav}`, doc);
const sel = classes.supernav.Selected;
const observer = new MutationObserver(() => {
const children = [...container.children];
if (children.some((e) => e.classList.contains(classes.menu.MenuOpen))) {
return;
}

const tab = children.findIndex((e) => e.classList.contains(sel));
// Account for the browser navigation arrows
DispatchTabChange(tab - 2);
});

observer.observe(container, {
attributes: true,
attributeFilter: ["class"],
subtree: true,
});
}

export default async function PluginMain() {
const logger = new CLog("index");

Expand Down Expand Up @@ -154,4 +178,5 @@ export default async function PluginMain() {
}

AddPopupCreatedCallback(MAIN_WINDOW_NAME, PatchUIStore);
AddPopupCreatedCallback(MAIN_WINDOW_NAME, AddSuperNavEvents);
}
151 changes: 103 additions & 48 deletions frontend/parts/steamdesktop/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@ import {
RibbonContainer,
RibbonSection,
} from "../../components/ribbon";
import { PartComponentBase } from "../../shared";

import {
ESuperNavTab,
GetESuperNavTabFromSetting,
TAB_CHANGE_EVENT_NAME,
} from "../../events/tabchange";
import {
k_strGameListChangeEventName,
type GameListChangeEvent,
} from "../../gamelistchange";
import { PartComponentBase } from "../../shared";
GAME_LIST_CHANGE_EVENT_NAME,
} from "../../events/gamelistchange";

import { BIsChinaLauncher, Config } from "../../modules/config";
import { CKioskModeManager } from "../../modules/kioskmodemgr";
Expand Down Expand Up @@ -113,12 +119,21 @@ function GetAppLinks(appid: number) {
return vecLinks.filter(Boolean);
}

function GetDefaltTabState() {
const [eDefaultTab] = settingsStore.GetClientSetting("start_page");
return GetESuperNavTabFromSetting(eDefaultTab);
}

interface SteamDesktopState {
appid: number;
tab: ESuperNavTab;
}

export class SteamDesktop extends PartComponentBase<SteamDesktopState> {
state = { appid: -1 };
state = {
appid: -1,
tab: GetDefaltTabState(),
};

OnManageButtonClick() {
const { appid } = this.state;
Expand All @@ -139,59 +154,99 @@ export class SteamDesktop extends PartComponentBase<SteamDesktopState> {
);
}

OnGameListChangeEvent(ev: CustomEventInit<GameListChangeEvent>) {
this.setState({ ...ev.detail });
OnGoBackButtonClick() {
MainWindowBrowserManager.m_browser.GoBack();
}

componentDidMount() {
window.addEventListener(k_strGameListChangeEventName, (ev) => {
this.OnGameListChangeEvent(ev);
});
OnGoForwardButtonClick() {
MainWindowBrowserManager.m_browser.GoForward();
}

OnReloadButtonClick() {
MainWindowBrowserManager.m_browser.Reload();
}

OnWindowEvent(ev: CustomEventInit<GameListChangeEvent>) {
const { appid, tab } = this.state;
this.setState({ appid, tab, ...ev.detail });
}

// TODO: i bet this doesn't actually work
componentWillUnmount() {
window.removeEventListener(k_strGameListChangeEventName, (ev) => {
this.OnGameListChangeEvent(ev);
});
componentDidMount() {
const events = [GAME_LIST_CHANGE_EVENT_NAME, TAB_CHANGE_EVENT_NAME];
for (const event of events) {
window.addEventListener(event, (ev) => {
this.OnWindowEvent(ev);
});
}
}

render() {
const { appid } = this.state;
if (appid === -1) {
const { appid, tab } = this.state;
if (tab === ESuperNavTab.Library && appid === -1) {
return <RibbonContainer />;
}

const links = GetAppLinks(appid).map((e) => {
const { label, icon, link, url } = e;
const dest = link ? urlStore.ResolveURL(link, appid) : url;
const onClick = () => {
MainWindowBrowserManager.ShowURL(dest);
};

return <RibbonButton icon={icon} text={label} onClick={onClick} />;
});

return (
<RibbonContainer>
<RibbonSection title="Game">
<ActionButton wnd={this.props.wnd} appid={appid} />
<RibbonButton
icon="manage"
text="#GameAction_Manage"
onClick={() => this.OnManageButtonClick()}
/>
<RibbonButton
icon="details"
text="#GameAction_ViewDetails"
onClick={() => this.OnDetailsButtonClick()}
/>
<FavoriteButton wnd={this.props.wnd} appid={appid} />
</RibbonSection>
{links.length > 0 && (
<RibbonSection title="Links">{links}</RibbonSection>
)}
</RibbonContainer>
);
switch (tab) {
case ESuperNavTab.Library: {
const links = GetAppLinks(appid).map((e) => {
const { label, icon, link, url } = e;
const dest = link ? urlStore.ResolveURL(link, appid) : url;
const onClick = () => {
MainWindowBrowserManager.ShowURL(dest);
};

return <RibbonButton icon={icon} text={label} onClick={onClick} />;
});

return (
<RibbonContainer>
<RibbonSection title="Game">
<ActionButton wnd={this.props.wnd} appid={appid} />
<RibbonButton
icon="manage"
text="#GameAction_Manage"
onClick={() => this.OnManageButtonClick()}
/>
<RibbonButton
icon="details"
text="#GameAction_ViewDetails"
onClick={() => this.OnDetailsButtonClick()}
/>
<FavoriteButton wnd={this.props.wnd} appid={appid} />
</RibbonSection>
{links.length > 0 && (
<RibbonSection title="Links">{links}</RibbonSection>
)}
</RibbonContainer>
);
}

case ESuperNavTab.Console:
return <RibbonContainer />;

// Browser
default:
return (
<RibbonContainer>
<RibbonSection title="Browser">
<RibbonButton
icon="nav-back"
text="Go back"
onClick={this.OnGoBackButtonClick}
/>
<RibbonButton
icon="nav-forward"
text="Go forward"
onClick={this.OnGoForwardButtonClick}
/>
<RibbonButton
icon="update"
text="Reload"
onClick={this.OnReloadButtonClick}
/>
</RibbonSection>
</RibbonContainer>
);
}
}
}
8 changes: 7 additions & 1 deletion frontend/shared.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { findClassModule, Millennium, type ClassModule } from "@steambrew/client";
import {
findClassModule,
Millennium,
type ClassModule,
} from "@steambrew/client";
import { Component } from "react";

export interface PartComponentProps {
Expand All @@ -17,7 +21,9 @@ export const classes = {
) as ClassModule,
gamelistbar: findClassModule((e) => e.GameListHomeAndSearch) as ClassModule,
gamelistdropdown: findClassModule((e) => e.ScrollToTop) as ClassModule,
menu: findClassModule((e) => e.MenuWrapper) as ClassModule,
steamdesktop: findClassModule((e) => e.FocusBar) as ClassModule,
supernav: findClassModule((e) => e.SuperNav) as ClassModule,
titlebarcontrols: findClassModule((e) => e.BranchBar) as ClassModule,
};

Expand Down
2 changes: 1 addition & 1 deletion src/client/desktop/supernav.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
}

#Arrow {
--icon: var(--icon-nav-arrow);
--icon: var(--icon-nav-forward);

@extend %icon;

Expand Down
2 changes: 1 addition & 1 deletion src/shared/icons.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
--icon-help: icon("help");
--icon-info: icon("info");
--icon-manage: icon("manage");
--icon-nav-arrow: icon("nav-arrow");
--icon-nav-forward: icon("nav-forward");
--icon-notifications: icon("notifications");
--icon-play: icon("play");
--icon-points: icon("points");
Expand Down
4 changes: 1 addition & 3 deletions steam-theming-utils.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
/** @type {import("steam-theming-utils").Config} */
export default {
ignore: {
client: ["shared"],
},
ignore: ["client/shared"],
};
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
"jsxFragmentFactory": "window.SP_REACT.Fragment",
"moduleResolution": "node"
},
"include": ["frontend/**/*"]
"include": ["frontend/**/*"],
"exclude": ["frontend/types/generated"]
}

0 comments on commit 81b989a

Please sign in to comment.