diff --git a/src/components/Styles/ThemeBrowserCardStyles.tsx b/src/components/Styles/ThemeBrowserCardStyles.tsx index 3ebc397..00d1f8c 100644 --- a/src/components/Styles/ThemeBrowserCardStyles.tsx +++ b/src/components/Styles/ThemeBrowserCardStyles.tsx @@ -2,7 +2,7 @@ import { useCssLoaderState } from "../../state"; const width = { 3: "260px", 4: "195px", 4.5: "183.33px", 5: "152px" }; const imgheightFactory = (size: number) => (Number(width[size].slice(0, -2)) / 16) * 10 + "px"; -const fontsize = { 3: "1em", 4: "0.75em", 4.5: "0.7", 5: "0.5em" }; +const fontsize = { 3: "1em", 4: "0.75em", 4.5: "0.7em", 5: "0.5em" }; const bubblesize = { 3: "40px", 4: "30px", 4.5: "25px", 5: "20px" }; export function ThemeBrowserCardStyles({ customCardSize }: { customCardSize?: number }) { @@ -32,6 +32,19 @@ export function ThemeBrowserCardStyles({ customCardSize }: { customCardSize?: nu width: var(--cssloader-themecard-bubblesize); height: var(--cssloader-themecard-bubblesize); } + .CSSLoader_ThemeCard_CustomBubble { + position: absolute; + background: linear-gradient(225deg, #2563eb 50%, transparent 51%); + z-index: 10001; + right: 0; + top: 0; + color: black; + display: flex; + justify-content: end; + font-size: var(--cssloader-themecard-fontsize); + width: var(--cssloader-themecard-bubblesize); + height: var(--cssloader-themecard-bubblesize); + } .CSSLoader_ThemeCard_BubbleIcon { padding: 0.25em; } diff --git a/src/components/ThemeManager/BrowserItemCard.tsx b/src/components/ThemeManager/BrowserItemCard.tsx index bb2790e..e9c0ff8 100644 --- a/src/components/ThemeManager/BrowserItemCard.tsx +++ b/src/components/ThemeManager/BrowserItemCard.tsx @@ -1,4 +1,4 @@ -import { FC } from "react"; +import { FC, ReactNode } from "react"; import { useCssLoaderState } from "../../state"; import { Theme } from "../../ThemeTypes"; import { Focusable, Navigation } from "decky-frontend-lib"; @@ -21,6 +21,7 @@ export const VariableSizeCard: FC<{ prevSearchOptsVarName?: string; refPassthrough?: any; onClick?: () => void; + CustomBubbleIcon?: ReactNode; }> = ({ data: e, cols: size, @@ -28,6 +29,7 @@ export const VariableSizeCard: FC<{ searchOpts, prevSearchOptsVarName, onClick, + CustomBubbleIcon, }) => { const { localThemeList, apiUrl, setGlobalState } = useCssLoaderState(); function checkIfThemeInstalled(themeObj: PartialCSSThemeInfo) { @@ -62,6 +64,9 @@ export const VariableSizeCard: FC<{ )} + {CustomBubbleIcon && ( +
{CustomBubbleIcon}
+ )} ([]); - const [privateProfiles, setPrivateProfiles] = useState([]); + const [uploadedProfiles, setUploadedProfiles] = useState< + (PartialCSSThemeInfo & { isPrivate?: boolean })[] + >([]); + const [profilesLoaded, setLoaded] = useState(false); useEffect(() => { async function getUserProfiles() { @@ -77,16 +80,22 @@ function UploadedProfilesDisplay() { // Since the short token could be invalid, we still have to re-check for if the log in actually worked. // The react value doesn't update mid function, so we re-grab it. const upToDateFullToken = python.globalState?.getGlobalState("apiFullToken"); - console.log("up to date token", upToDateFullToken); if (!upToDateFullToken) return; + + let profileArray: PartialCSSThemeInfo[] = []; const publicProfileData = await genericGET("/users/me/themes?filters=", true); if (publicProfileData && publicProfileData.total > 0) { - setPublicProfiles(publicProfileData.items); + profileArray.push(...publicProfileData.items); } const privateProfileData = await genericGET("/users/me/themes/private?filters=", true); if (privateProfileData && privateProfileData.total > 0) { - setPrivateProfiles(privateProfileData.items); + profileArray.push( + ...privateProfileData.items.map((e: PartialCSSThemeInfo) => ({ ...e, isPrivate: true })) + ); } + profileArray.sort((a, b) => (a.name > b.name ? 1 : -1)); + setUploadedProfiles(profileArray); + setLoaded(true); } if (apiShortToken) getUserProfiles(); @@ -138,34 +147,29 @@ function UploadedProfilesDisplay() { {profilesLoaded ? ( <> - - {publicProfiles.length > 0 && ( - <> - - Public Profiles: - - {publicProfiles.map((e) => ( - {}} /> - ))} - - - - )} - {apiMeData.premiumTier && - apiMeData.premiumTier !== "None" && - privateProfiles.length > 0 ? ( - <> - - Private Profiles: - - {privateProfiles.map((e) => ( - {}} /> - ))} - - - - ) : null} - + {uploadedProfiles.length > 0 && ( + <> + + {uploadedProfiles.map((e) => ( + {}} + CustomBubbleIcon={ + e.isPrivate ? null : ( + + ) + } + /> + ))} + + + )} ) : ( Loading Profiles...