Skip to content

Commit

Permalink
fix require cycles and extract themecard
Browse files Browse the repository at this point in the history
  • Loading branch information
beebls committed Dec 27, 2024
1 parent 861f81a commit 321e9e1
Show file tree
Hide file tree
Showing 12 changed files with 88 additions and 171 deletions.
1 change: 1 addition & 0 deletions src/lib/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from "./motd-display";
export * from "./preset-selection-dropdown";
export * from "./theme-patch";
export * from "./modals";
export * from "./theme-card";
20 changes: 15 additions & 5 deletions src/lib/components/modals/author-view-modal/AuthorViewModal.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { ConfirmModal, Modal } from "../../../primitives";
import { Modal } from "../../../primitives";
import { PartialCSSThemeInfo, ThemeQueryResponse, UserInfo } from "@/types";
import { useEffect, useRef, useState } from "react";
import { useCSSLoaderAction } from "@/backend";
import { ThemeCardCSSVariableProvider } from "@/modules/theme-store/components";
import { SupporterIcon } from "./SupporterIcon";
import { ImSpinner5 } from "react-icons/im";
import { Focusable } from "@decky/ui";
import { ThemeCard } from "@/modules/theme-store/components/ThemeCard";
import { ThemeCard, ThemeCardCSSVariableProvider } from "../../theme-card";
// Hardcoded to prevent require cycle
import { useExpandedViewAction } from "@/modules/expanded-view/context";

export function AuthorViewModal({
closeModal,
Expand All @@ -20,6 +21,8 @@ export function AuthorViewModal({
const [loaded, setLoaded] = useState<boolean>(false);
const [themes, setThemes] = useState<PartialCSSThemeInfo[]>([]);

const openTheme = useExpandedViewAction("openTheme");

const firstThemeRef = useRef<HTMLDivElement>(null);

async function fetchThemeData() {
Expand Down Expand Up @@ -56,9 +59,16 @@ export function AuthorViewModal({
</div>
</div>
<Focusable className="flex flex-wrap justify-center gap-2">
{themes.map((e, i) => {
{themes.map((theme, i) => {
return (
<ThemeCard ref={i === 0 ? firstThemeRef : null} theme={e} onClick={closeModal} />
<ThemeCard
ref={i === 0 ? firstThemeRef : null}
theme={theme}
onClick={() => {
closeModal?.();
openTheme(theme.id);
}}
/>
);
})}
</Focusable>
Expand Down
125 changes: 52 additions & 73 deletions src/lib/components/theme-card/ThemeCard.tsx
Original file line number Diff line number Diff line change
@@ -1,89 +1,68 @@
import { PartialCSSThemeInfo } from "@/types";
import { ColumnNumbers, useThemeBrowserSharedValue, useThemeBrowserStoreValue } from "../context";
import { forwardRef } from "react";
import { shortenNumber, useThemeInstallState } from "@/lib";
import { useCSSLoaderValue } from "@/backend";
import { AiOutlineDownload } from "react-icons/ai";
import { Focusable } from "@decky/ui";
import { FaBullseye, FaDownload, FaStar } from "react-icons/fa6";
import { useExpandedViewAction } from "@/modules/expanded-view";
import { useThemeInstallState } from "../../hooks";
// Hard-coded path to prevent require cycle
import { shortenNumber } from "../../utils/shorten-number";

interface ThemeCardProps {
theme: PartialCSSThemeInfo;
size?: ColumnNumbers;
onClick?: () => void;
}

const cardWidth = {
5: 152,
4: 195,
3: 260,
};
export const ThemeCard = forwardRef<HTMLDivElement, ThemeCardProps>(({ theme, onClick }, ref) => {
const apiUrl = useCSSLoaderValue("apiUrl");
const installStatus = useThemeInstallState(theme);

export const ThemeCard = forwardRef<HTMLDivElement, ThemeCardProps>(
({ theme, size, onClick }, ref) => {
const apiUrl = useCSSLoaderValue("apiUrl");
const browserCardSize = useThemeBrowserSharedValue("browserCardSize");
const cols = size ?? browserCardSize;
const installStatus = useThemeInstallState(theme);
const imageUrl =
theme?.images[0]?.id && theme.images[0].id !== "MISSING"
? `${apiUrl}/blobs/${theme.images[0].id}`
: `https://share.deckthemes.com/cssplaceholder.png`;

const openTheme = useExpandedViewAction("openTheme");

const imageUrl =
theme?.images[0]?.id && theme.images[0].id !== "MISSING"
? `${apiUrl}/blobs/${theme.images[0].id}`
: `https://share.deckthemes.com/cssplaceholder.png`;

return (
<div className="relative">
{installStatus === "outdated" && (
<div className="cl_storeitem_notifbubble">
<AiOutlineDownload className="cl_storeitem_bubbleicon" />
</div>
)}
<Focusable
ref={ref}
className="cl_storeitem_container"
focusWithinClassName="gpfocuswithin"
onActivate={() => {
onClick?.();
openTheme(theme.id);
}}
>
<div className="cl_storeitem_imagecontainer">
<img
className="cl_storeitem_image"
src={imageUrl}
width={cardWidth[cols]}
height={(cardWidth[cols] / 16) * 10}
/>
<div className="cl_storeitem_imagedarkener" />
<div className="cl_storeitem_supinfocontainer">
<div className="cl_storeitem_iconinfoitem">
<FaDownload />
<span>
{shortenNumber(theme.download.downloadCount) ?? theme.download.downloadCount}
</span>
</div>
<div className="cl_storeitem_iconinfoitem">
<FaStar />
<span>{shortenNumber(theme.starCount) ?? theme.starCount}</span>
</div>
<div className="cl_storeitem_iconinfoitem">
<FaBullseye />
<span>{theme.target}</span>
</div>
return (
<div className="relative">
{installStatus === "outdated" && (
<div className="cl_storeitem_notifbubble">
<AiOutlineDownload className="cl_storeitem_bubbleicon" />
</div>
)}
<Focusable
ref={ref}
className="cl_storeitem_container"
focusWithinClassName="gpfocuswithin"
onActivate={onClick}
>
<div className="cl_storeitem_imagecontainer">
<img className="cl_storeitem_image" src={imageUrl} />
<div className="cl_storeitem_imagedarkener" />
<div className="cl_storeitem_supinfocontainer">
<div className="cl_storeitem_iconinfoitem">
<FaDownload />
<span>
{shortenNumber(theme.download.downloadCount) ?? theme.download.downloadCount}
</span>
</div>
<div className="cl_storeitem_iconinfoitem">
<FaStar />
<span>{shortenNumber(theme.starCount) ?? theme.starCount}</span>
</div>
<div className="cl_storeitem_iconinfoitem">
<FaBullseye />
<span>{theme.target}</span>
</div>
</div>
<div className="cl_storeitem_maininfocontainer">
<span className="cl_storeitem_title">{theme.displayName}</span>
<span className="cl_storeitem_subtitle">
{theme.version} - Last Updated {new Date(theme.updated).toLocaleDateString()}
</span>
<span className="cl_storeitem_subtitle">By {theme.specifiedAuthor}</span>
</div>
</Focusable>
</div>
);
}
);
</div>
<div className="cl_storeitem_maininfocontainer">
<span className="cl_storeitem_title">{theme.displayName}</span>
<span className="cl_storeitem_subtitle">
{theme.version} - Last Updated {new Date(theme.updated).toLocaleDateString()}
</span>
<span className="cl_storeitem_subtitle">By {theme.specifiedAuthor}</span>
</div>
</Focusable>
</div>
);
});
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { themeCardStylesGenerator } from "@/styles";
import { ColumnNumbers, useThemeBrowserSharedValue } from "../context";

export function ThemeCardCSSVariableProvider({ cardSize }: { cardSize?: ColumnNumbers }) {
const browserCardSize = useThemeBrowserSharedValue("browserCardSize");
export type ColumnNumbers = 3 | 4 | 5;

return <style>{themeCardStylesGenerator(cardSize || browserCardSize)}</style>;
export function ThemeCardCSSVariableProvider({ cardSize }: { cardSize: ColumnNumbers }) {
return <style>{themeCardStylesGenerator(cardSize)}</style>;
}
2 changes: 2 additions & 0 deletions src/lib/components/theme-card/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./ThemeCard";
export * from "./ThemeCardCSSVariableProvider";
6 changes: 5 additions & 1 deletion src/modules/theme-store/components/ThemeBrowserPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import { Focusable } from "@decky/ui";
import { useThemeBrowserStoreAction, useThemeBrowserStoreValue } from "../context";
import { BrowserSearchFields } from "./BrowserSearchFields";
import { useCSSLoaderValue } from "@/backend";
import { ThemeCard } from "./ThemeCard";
import { useEffect, useRef } from "react";
import { ImSpinner5 } from "react-icons/im";
import { LoadMoreButton } from "./LoadMoreButton";
import { useExpandedViewAction } from "@/modules/expanded-view";
import { ThemeCard } from "@/lib";

export function ThemeBrowserPage() {
const initializeStore = useThemeBrowserStoreAction("initializeStore");
Expand All @@ -14,6 +15,8 @@ export function ThemeBrowserPage() {
const indexToSnapToOnLoad = useThemeBrowserStoreValue("indexToSnapToOnLoad");
const backendVersion = useCSSLoaderValue("backendVersion");

const openTheme = useExpandedViewAction("openTheme");

const endOfPageRef = useRef<HTMLDivElement>(null);
const firstCardRef = useRef<HTMLDivElement>(null);

Expand Down Expand Up @@ -42,6 +45,7 @@ export function ThemeBrowserPage() {
.filter((theme) => theme.manifestVersion <= backendVersion)
.map((theme, index) => (
<ThemeCard
onClick={() => openTheme(theme.id)}
ref={
index === indexToSnapToOnLoad
? endOfPageRef
Expand Down
74 changes: 0 additions & 74 deletions src/modules/theme-store/components/ThemeCard.tsx

This file was deleted.

This file was deleted.

1 change: 0 additions & 1 deletion src/modules/theme-store/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export * from "./ThemeCardCSSVariableProvider";
export * from "./ThemeBrowserPage";
3 changes: 1 addition & 2 deletions src/modules/theme-store/context/ThemeBrowserSharedStore.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// This is for things that are shared across the entire Theme Browser page and all tabs.

import { createStore, useStore } from "zustand";

export type ColumnNumbers = 3 | 4 | 5;
import { ColumnNumbers } from "../../../lib/components/theme-card";

interface ThemeBrowserSharedStoreValues {
browserCardSize: ColumnNumbers;
Expand Down
10 changes: 8 additions & 2 deletions src/modules/theme-store/pages/ThemeStoreRouter.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Tabs } from "@decky/ui";
import { ThemeBrowserPage, ThemeCardCSSVariableProvider } from "../components";
import { ThemeBrowserPage } from "../components";
import {
ThemeBrowserStoreProvider,
useThemeBrowserSharedAction,
Expand All @@ -8,6 +8,7 @@ import {
import { AccountPage } from "./AccountPage";
import { useCSSLoaderValue } from "@/backend";
import { Permissions } from "@/types";
import { ThemeCardCSSVariableProvider } from "@/lib";

// TODO: Make the tab definition a constant so that it isn't re-generated every page load

Expand Down Expand Up @@ -87,8 +88,13 @@ export function ThemeStoreRouter() {

return (
<div className="cl_fullscreenroute_container">
<ThemeCardCSSVariableProvider />
<Tabs activeTab={currentTab} onShowTab={(tab) => setCurrentTab(tab)} tabs={tabs}></Tabs>
</div>
);
}

function BrowserCardSizeVariableProvider() {
const browserCardSize = useThemeBrowserSharedValue("browserCardSize");

return <ThemeCardCSSVariableProvider cardSize={browserCardSize} />;
}
2 changes: 1 addition & 1 deletion src/styles/theme-card-styles-generator.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ColumnNumbers } from "@/modules/theme-store/context";
import { ColumnNumbers } from "@/lib";

export function themeCardStylesGenerator(size: ColumnNumbers) {
return `
Expand Down

0 comments on commit 321e9e1

Please sign in to comment.