From 321e9e157aeddac895f31032909de0389e176b0a Mon Sep 17 00:00:00 2001 From: Beebles <102569435+beebls@users.noreply.github.com> Date: Fri, 27 Dec 2024 14:37:25 -0700 Subject: [PATCH] fix require cycles and extract themecard --- src/lib/components/index.ts | 1 + .../author-view-modal/AuthorViewModal.tsx | 20 ++- src/lib/components/theme-card/ThemeCard.tsx | 125 ++++++++---------- .../ThemeCardCSSVariableProvider.tsx | 7 +- src/lib/components/theme-card/index.ts | 2 + .../components/ThemeBrowserPage.tsx | 6 +- .../theme-store/components/ThemeCard.tsx | 74 ----------- .../ThemeCardCSSVariableProvider.tsx | 8 -- src/modules/theme-store/components/index.ts | 1 - .../context/ThemeBrowserSharedStore.tsx | 3 +- .../theme-store/pages/ThemeStoreRouter.tsx | 10 +- src/styles/theme-card-styles-generator.ts | 2 +- 12 files changed, 88 insertions(+), 171 deletions(-) create mode 100644 src/lib/components/theme-card/index.ts delete mode 100644 src/modules/theme-store/components/ThemeCard.tsx delete mode 100644 src/modules/theme-store/components/ThemeCardCSSVariableProvider.tsx diff --git a/src/lib/components/index.ts b/src/lib/components/index.ts index 10bfaa9..5b8d864 100644 --- a/src/lib/components/index.ts +++ b/src/lib/components/index.ts @@ -3,3 +3,4 @@ export * from "./motd-display"; export * from "./preset-selection-dropdown"; export * from "./theme-patch"; export * from "./modals"; +export * from "./theme-card"; diff --git a/src/lib/components/modals/author-view-modal/AuthorViewModal.tsx b/src/lib/components/modals/author-view-modal/AuthorViewModal.tsx index 4cfcd49..c2540e1 100644 --- a/src/lib/components/modals/author-view-modal/AuthorViewModal.tsx +++ b/src/lib/components/modals/author-view-modal/AuthorViewModal.tsx @@ -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, @@ -20,6 +21,8 @@ export function AuthorViewModal({ const [loaded, setLoaded] = useState(false); const [themes, setThemes] = useState([]); + const openTheme = useExpandedViewAction("openTheme"); + const firstThemeRef = useRef(null); async function fetchThemeData() { @@ -56,9 +59,16 @@ export function AuthorViewModal({ - {themes.map((e, i) => { + {themes.map((theme, i) => { return ( - + { + closeModal?.(); + openTheme(theme.id); + }} + /> ); })} diff --git a/src/lib/components/theme-card/ThemeCard.tsx b/src/lib/components/theme-card/ThemeCard.tsx index e0f2854..584b047 100644 --- a/src/lib/components/theme-card/ThemeCard.tsx +++ b/src/lib/components/theme-card/ThemeCard.tsx @@ -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(({ theme, onClick }, ref) => { + const apiUrl = useCSSLoaderValue("apiUrl"); + const installStatus = useThemeInstallState(theme); -export const ThemeCard = forwardRef( - ({ 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 ( -
- {installStatus === "outdated" && ( -
- -
- )} - { - onClick?.(); - openTheme(theme.id); - }} - > -
- -
-
-
- - - {shortenNumber(theme.download.downloadCount) ?? theme.download.downloadCount} - -
-
- - {shortenNumber(theme.starCount) ?? theme.starCount} -
-
- - {theme.target} -
+ return ( +
+ {installStatus === "outdated" && ( +
+ +
+ )} + +
+ +
+
+
+ + + {shortenNumber(theme.download.downloadCount) ?? theme.download.downloadCount} + +
+
+ + {shortenNumber(theme.starCount) ?? theme.starCount} +
+
+ + {theme.target}
-
- {theme.displayName} - - {theme.version} - Last Updated {new Date(theme.updated).toLocaleDateString()} - - By {theme.specifiedAuthor} -
- -
- ); - } -); +
+
+ {theme.displayName} + + {theme.version} - Last Updated {new Date(theme.updated).toLocaleDateString()} + + By {theme.specifiedAuthor} +
+
+
+ ); +}); diff --git a/src/lib/components/theme-card/ThemeCardCSSVariableProvider.tsx b/src/lib/components/theme-card/ThemeCardCSSVariableProvider.tsx index 52f1d1f..6a32cc5 100644 --- a/src/lib/components/theme-card/ThemeCardCSSVariableProvider.tsx +++ b/src/lib/components/theme-card/ThemeCardCSSVariableProvider.tsx @@ -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 ; +export function ThemeCardCSSVariableProvider({ cardSize }: { cardSize: ColumnNumbers }) { + return ; } diff --git a/src/lib/components/theme-card/index.ts b/src/lib/components/theme-card/index.ts new file mode 100644 index 0000000..983ed59 --- /dev/null +++ b/src/lib/components/theme-card/index.ts @@ -0,0 +1,2 @@ +export * from "./ThemeCard"; +export * from "./ThemeCardCSSVariableProvider"; diff --git a/src/modules/theme-store/components/ThemeBrowserPage.tsx b/src/modules/theme-store/components/ThemeBrowserPage.tsx index 9d5e047..c187f53 100644 --- a/src/modules/theme-store/components/ThemeBrowserPage.tsx +++ b/src/modules/theme-store/components/ThemeBrowserPage.tsx @@ -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"); @@ -14,6 +15,8 @@ export function ThemeBrowserPage() { const indexToSnapToOnLoad = useThemeBrowserStoreValue("indexToSnapToOnLoad"); const backendVersion = useCSSLoaderValue("backendVersion"); + const openTheme = useExpandedViewAction("openTheme"); + const endOfPageRef = useRef(null); const firstCardRef = useRef(null); @@ -42,6 +45,7 @@ export function ThemeBrowserPage() { .filter((theme) => theme.manifestVersion <= backendVersion) .map((theme, index) => ( openTheme(theme.id)} ref={ index === indexToSnapToOnLoad ? endOfPageRef diff --git a/src/modules/theme-store/components/ThemeCard.tsx b/src/modules/theme-store/components/ThemeCard.tsx deleted file mode 100644 index e00e798..0000000 --- a/src/modules/theme-store/components/ThemeCard.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import { PartialCSSThemeInfo } from "@/types"; -import { ColumnNumbers } 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"; - -interface ThemeCardProps { - theme: PartialCSSThemeInfo; - size?: ColumnNumbers; - onClick?: () => void; -} - -export const ThemeCard = forwardRef(({ theme, onClick }, ref) => { - const apiUrl = useCSSLoaderValue("apiUrl"); - const installStatus = useThemeInstallState(theme); - - 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 ( -
- {installStatus === "outdated" && ( -
- -
- )} - { - onClick?.(); - openTheme(theme.id); - }} - > -
- -
-
-
- - - {shortenNumber(theme.download.downloadCount) ?? theme.download.downloadCount} - -
-
- - {shortenNumber(theme.starCount) ?? theme.starCount} -
-
- - {theme.target} -
-
-
-
- {theme.displayName} - - {theme.version} - Last Updated {new Date(theme.updated).toLocaleDateString()} - - By {theme.specifiedAuthor} -
- -
- ); -}); diff --git a/src/modules/theme-store/components/ThemeCardCSSVariableProvider.tsx b/src/modules/theme-store/components/ThemeCardCSSVariableProvider.tsx deleted file mode 100644 index 52f1d1f..0000000 --- a/src/modules/theme-store/components/ThemeCardCSSVariableProvider.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import { themeCardStylesGenerator } from "@/styles"; -import { ColumnNumbers, useThemeBrowserSharedValue } from "../context"; - -export function ThemeCardCSSVariableProvider({ cardSize }: { cardSize?: ColumnNumbers }) { - const browserCardSize = useThemeBrowserSharedValue("browserCardSize"); - - return ; -} diff --git a/src/modules/theme-store/components/index.ts b/src/modules/theme-store/components/index.ts index be45aeb..1ae67d4 100644 --- a/src/modules/theme-store/components/index.ts +++ b/src/modules/theme-store/components/index.ts @@ -1,2 +1 @@ -export * from "./ThemeCardCSSVariableProvider"; export * from "./ThemeBrowserPage"; diff --git a/src/modules/theme-store/context/ThemeBrowserSharedStore.tsx b/src/modules/theme-store/context/ThemeBrowserSharedStore.tsx index 6c4236c..de146b0 100644 --- a/src/modules/theme-store/context/ThemeBrowserSharedStore.tsx +++ b/src/modules/theme-store/context/ThemeBrowserSharedStore.tsx @@ -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; diff --git a/src/modules/theme-store/pages/ThemeStoreRouter.tsx b/src/modules/theme-store/pages/ThemeStoreRouter.tsx index 96fde7d..7e8971a 100644 --- a/src/modules/theme-store/pages/ThemeStoreRouter.tsx +++ b/src/modules/theme-store/pages/ThemeStoreRouter.tsx @@ -1,5 +1,5 @@ import { Tabs } from "@decky/ui"; -import { ThemeBrowserPage, ThemeCardCSSVariableProvider } from "../components"; +import { ThemeBrowserPage } from "../components"; import { ThemeBrowserStoreProvider, useThemeBrowserSharedAction, @@ -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 @@ -87,8 +88,13 @@ export function ThemeStoreRouter() { return (
- setCurrentTab(tab)} tabs={tabs}>
); } + +function BrowserCardSizeVariableProvider() { + const browserCardSize = useThemeBrowserSharedValue("browserCardSize"); + + return ; +} diff --git a/src/styles/theme-card-styles-generator.ts b/src/styles/theme-card-styles-generator.ts index d448704..f20de58 100644 --- a/src/styles/theme-card-styles-generator.ts +++ b/src/styles/theme-card-styles-generator.ts @@ -1,4 +1,4 @@ -import { ColumnNumbers } from "@/modules/theme-store/context"; +import { ColumnNumbers } from "@/lib"; export function themeCardStylesGenerator(size: ColumnNumbers) { return `