From 514c99fb42bf741ccb09d34bfbad7128c29f6359 Mon Sep 17 00:00:00 2001 From: Emi Matchu Date: Mon, 29 Jan 2024 03:20:48 -0800 Subject: [PATCH] Add WIP styles tab to the pose picker It shows the styles! You can select between them, but it currently does nothing, womp womp! --- app/controllers/alt_styles_controller.rb | 6 +- .../wardrobe-2020/WardrobePage/PosePicker.js | 135 +++++++++++++++++- .../wardrobe-2020/loaders/alt-styles.js | 38 +++++ app/models/alt_style.rb | 4 + 4 files changed, 180 insertions(+), 3 deletions(-) create mode 100644 app/javascript/wardrobe-2020/loaders/alt-styles.js diff --git a/app/controllers/alt_styles_controller.rb b/app/controllers/alt_styles_controller.rb index 46f9f7fd..94bb3cd2 100644 --- a/app/controllers/alt_styles_controller.rb +++ b/app/controllers/alt_styles_controller.rb @@ -10,7 +10,11 @@ class AltStylesController < ApplicationController respond_to do |format| format.html { render } - format.json { render json: @alt_styles } + format.json { + render json: @alt_styles.as_json( + methods: [:adjective_name, :thumbnail_url], + ) + } end end end diff --git a/app/javascript/wardrobe-2020/WardrobePage/PosePicker.js b/app/javascript/wardrobe-2020/WardrobePage/PosePicker.js index 21bf4339..9b33440d 100644 --- a/app/javascript/wardrobe-2020/WardrobePage/PosePicker.js +++ b/app/javascript/wardrobe-2020/WardrobePage/PosePicker.js @@ -20,6 +20,7 @@ import { useColorModeValue, useTheme, useToast, + useToken, } from "@chakra-ui/react"; import { loadable } from "../util"; @@ -27,6 +28,7 @@ import { petAppearanceFragment } from "../components/useOutfitAppearance"; import getVisibleLayers from "../components/getVisibleLayers"; import { OutfitLayers } from "../components/OutfitPreview"; import SupportOnly from "./support/SupportOnly"; +import { useAltStylesForSpecies } from "../loaders/alt-styles"; import useSupport from "./support/useSupport"; import { useLocalStorage } from "../util"; @@ -69,7 +71,8 @@ function PosePicker({ ...props }) { const initialFocusRef = React.useRef(); - const { loading, error, poseInfos } = usePoses(speciesId, colorId, pose); + const posesQuery = usePoses(speciesId, colorId, pose); + const altStylesQuery = useAltStylesForSpecies(speciesId); const [isInSupportMode, setIsInSupportMode] = useLocalStorage( "DTIPosePickerIsInSupportMode", false, @@ -77,6 +80,11 @@ function PosePicker({ const { isSupportUser } = useSupport(); const toast = useToast(); + const loading = posesQuery.loading || altStylesQuery.loading; + const error = posesQuery.error ?? altStylesQuery.error; + const poseInfos = posesQuery.poseInfos; + const altStyles = altStylesQuery.data ?? []; + // Resize the Popover when we toggle support mode, because it probably will // affect the content size. React.useLayoutEffect(() => { @@ -201,7 +209,10 @@ function PosePicker({ - WIP: Styles go here! + + + + Expressions @@ -539,6 +550,126 @@ function PosePickerEmptyExplanation() { ); } +function StyleSelect({ altStyles }) { + const [selectedStyleId, setSelectedStyleId] = React.useState(null); + + const defaultStyle = { id: null, adjectiveName: "Default" }; + + return ( + + + {altStyles.map((altStyle) => ( + + ))} + + ); +} + +function StyleOption({ altStyle, checked, onChange }) { + const theme = useTheme(); + const selectedBorderColor = useColorModeValue( + theme.colors.green["600"], + theme.colors.green["300"], + ); + const outlineShadow = useToken("shadows", "outline"); + + return ( + + {({ css, cx }) => ( + { + // HACK: We need the timeout to beat the popover's focus stealing! + const input = e.currentTarget.querySelector("input"); + setTimeout(() => input.focus(), 0); + }} + > + onChange(altStyle.id)} + /> + + {altStyle.thumbnailUrl ? ( + + ) : ( + + )} + + {altStyle.adjectiveName} + + + )} + + ); +} + +function StyleExplanation() { + return ( + + "Alt Styles" are special NC items that override the pet's usual appearance + via the "Styling Studio". The pet's color doesn't have to match. +
+ WIP: The styles can't actually be applied yet! +
+ ); +} + function EmojiImage({ src, alt, boxSize = 16 }) { return {alt}; } diff --git a/app/javascript/wardrobe-2020/loaders/alt-styles.js b/app/javascript/wardrobe-2020/loaders/alt-styles.js new file mode 100644 index 00000000..237a103c --- /dev/null +++ b/app/javascript/wardrobe-2020/loaders/alt-styles.js @@ -0,0 +1,38 @@ +import { useQuery } from "@tanstack/react-query"; + +export function useAltStylesForSpecies(speciesId, options = {}) { + return useQuery({ + ...options, + queryKey: ["altStylesForSpecies", String(speciesId)], + queryFn: () => loadAltStylesForSpecies(speciesId), + }); +} + +async function loadAltStylesForSpecies(speciesId) { + const res = await fetch( + `/species/${encodeURIComponent(speciesId)}/alt-styles.json`, + ); + + if (!res.ok) { + throw new Error( + `loading alt styles failed: ${res.status} ${res.statusText}`, + ); + } + + return res.json().then(normalizeAltStyles); +} + +function normalizeAltStyles(altStylesData) { + return altStylesData.map(normalizeAltStyle); +} + +function normalizeAltStyle(altStyleData) { + return { + id: altStyleData.id, + speciesId: altStyleData.species_id, + colorId: altStyleData.color_id, + bodyId: altStyleData.body_id, + adjectiveName: altStyleData.adjective_name, + thumbnailUrl: altStyleData.thumbnail_url, + }; +} diff --git a/app/models/alt_style.rb b/app/models/alt_style.rb index 242799e9..135fdfcf 100644 --- a/app/models/alt_style.rb +++ b/app/models/alt_style.rb @@ -11,6 +11,10 @@ class AltStyle < ApplicationRecord species_human_name: species.human_name) end + def adjective_name + "Nostalgic #{color.human_name}" + end + def thumbnail_url # HACK: Just assume this is a Nostalgic Alt Style, and that the thumbnail # is named reliably!