diff --git a/CHANGELOG.MD b/CHANGELOG.MD index d22ba70e..f2d01df4 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -14,6 +14,7 @@ - Removed "Ask the Oracle" oracles from the oracle list, since they are pinned up top - Added a test mobile view for moves and oracles - Redesigned stats and tracks sections on mobile +- Redesigned moves and oracles to make each section collapsible ### Accessibility @@ -25,6 +26,7 @@ - Fixed an issue where deleting a custom move caused the app to crash - Made some performance improvements on the character view - Fixed shared tracks not showing up in the move rollers +- Prevented oracle inputs from reordering themselves --- diff --git a/src/components/features/assets/AssetCard/AssetCard.tsx b/src/components/features/assets/AssetCard/AssetCard.tsx index d4b210ee..e7c21394 100644 --- a/src/components/features/assets/AssetCard/AssetCard.tsx +++ b/src/components/features/assets/AssetCard/AssetCard.tsx @@ -179,38 +179,48 @@ export function AssetCard(props: AssetCardProps) { {asset.Requirement && ( )} - {Object.values(asset.Inputs ?? {}).map((field) => ( - { - if (handleInputChange) { - return handleInputChange(encodeDataswornId(field.$id), value); - } - return new Promise((res, reject) => - reject("HandleInputChange is undefined") - ); - }} - disabled={readOnly || !handleInputChange} - /> - ))} - {abilityInputs.map((field) => ( - { - if (handleInputChange) { - return handleInputChange(encodeDataswornId(field.$id), value); - } - return new Promise((res, reject) => - reject("handleInputChange is undefined") - ); - }} - disabled={readOnly || !handleInputChange} - /> - ))} + {Object.values(asset.Inputs ?? {}) + .sort((i1, i2) => i1.Label.localeCompare(i2.Label)) + .map((field) => ( + { + if (handleInputChange) { + return handleInputChange( + encodeDataswornId(field.$id), + value + ); + } + return new Promise((res, reject) => + reject("HandleInputChange is undefined") + ); + }} + disabled={readOnly || !handleInputChange} + /> + ))} + {abilityInputs + .sort((i1, i2) => i1.Label.localeCompare(i2.Label)) + .map((field) => ( + { + if (handleInputChange) { + return handleInputChange( + encodeDataswornId(field.$id), + value + ); + } + return new Promise((res, reject) => + reject("handleInputChange is undefined") + ); + }} + disabled={readOnly || !handleInputChange} + /> + ))} {asset.Abilities.map((ability, index) => ( 0 && ( - {conditionMeter.Conditions.map((condition) => ( + {conditionMeter.Conditions.sort((c1, c2) => + c1.localeCompare(c2) + ).map((condition) => ( void; +} + +export function CollapsibleSectionHeader(props: CollapsibleSectionHeaderProps) { + const { text, open, toggleOpen } = props; + + return ( + ({ + mt: open ? 0.5 : 0, + backgroundColor: theme.palette.background.paperInlayDarker, + color: theme.palette.grey[theme.palette.mode === "light" ? 700 : 200], + ...theme.typography.body1, + fontFamily: theme.fontFamilyTitle, + display: "flex", + justifyContent: "space-between", + alignItems: "center", + transition: theme.transitions.create(["margin"], { + duration: theme.transitions.duration.shorter, + }), + })} + > + + {text} + + ({ + transform: `rotate(${open ? "-" : ""}90deg)`, + transition: theme.transitions.create(["transform"], { + duration: theme.transitions.duration.shorter, + }), + })} + /> + + + + ); +} diff --git a/src/components/features/charactersAndCampaigns/MoveDrawer.tsx b/src/components/features/charactersAndCampaigns/MoveDrawer.tsx index 6f6d4311..c6f203dd 100644 --- a/src/components/features/charactersAndCampaigns/MoveDrawer.tsx +++ b/src/components/features/charactersAndCampaigns/MoveDrawer.tsx @@ -15,6 +15,7 @@ function MoveDrawerUnMemoized(props: MoveDrawerProps) { void; + forceOpen?: boolean; } export function MoveCategory(props: MoveCategoryProps) { - const { category, openMove } = props; + const { category, openMove, forceOpen } = props; + + const showNewView = useNewMoveOracleView(); + const [isExpanded, setIsExpanded] = useState(showNewView ? false : true); + + useEffect(() => { + setIsExpanded(showNewView ? false : true); + }, [showNewView]); + + const isExpandedOrForced = isExpanded || forceOpen; return ( <> - ({ - backgroundColor: - theme.palette.darkGrey[ - theme.palette.mode === "light" ? "light" : "dark" - ], - color: theme.palette.darkGrey.contrastText, - ...theme.typography.body1, - fontFamily: theme.fontFamilyTitle, - })} - > - {category.Title.Standard} - - {Object.values(category.Moves).map((move, index) => ( - !forceOpen && setIsExpanded((prev) => !prev)} + text={category.Title.Standard} + /> + ) : ( + ({ - "&:nth-of-type(odd)": { - backgroundColor: theme.palette.action.hover, - }, + backgroundColor: + theme.palette.darkGrey[ + theme.palette.mode === "light" ? "light" : "dark" + ], + color: theme.palette.darkGrey.contrastText, + ...theme.typography.body1, + fontFamily: theme.fontFamilyTitle, })} - disablePadding > - openMove(move)} - sx={{ - display: "flex", - justifyContent: "space-between", - alignItems: "center", - }} - > - + )} + + + {Object.values(category.Moves).map((move, index) => ( + ({ - ...theme.typography.body2, - color: theme.palette.text.primary, + "&:nth-of-type(even)": { + backgroundColor: theme.palette.background.paperInlay, + }, })} + disablePadding > - {move.Title.Standard} - - - - - - - ))} + openMove(move)} + sx={{ + display: "flex", + justifyContent: "space-between", + alignItems: "center", + }} + > + ({ + ...theme.typography.body2, + color: theme.palette.text.primary, + })} + > + {move.Title.Standard} + + + + + + + ))} + + ); } diff --git a/src/components/features/charactersAndCampaigns/MovesSection/MovesSection.tsx b/src/components/features/charactersAndCampaigns/MovesSection/MovesSection.tsx index c7d68635..bc8faaf2 100644 --- a/src/components/features/charactersAndCampaigns/MovesSection/MovesSection.tsx +++ b/src/components/features/charactersAndCampaigns/MovesSection/MovesSection.tsx @@ -5,34 +5,44 @@ import { useFilterMoves } from "./useFilterMoves"; import { useStore } from "stores/store"; export function MovesSection() { - const { setSearch, filteredMoves } = useFilterMoves(); + const { setSearch, filteredMoves, isSearchActive } = useFilterMoves(); const openDialog = useStore((store) => store.appState.openDialog); return ( <> - - ({ color: theme.palette.grey[300] })} /> - - } - aria-label={"Filter Moves"} - placeholder={"Filter Moves"} - onChange={(evt) => setSearch(evt.currentTarget.value)} - color={"primary"} - sx={(theme) => ({ - backgroundColor: theme.palette.darkGrey.main, - color: "#fff", - px: 2, - "&::hover": { + theme.palette.darkGrey.contrastText} + bgcolor={(theme) => theme.palette.darkGrey.dark} + borderBottom={(theme) => `1px solid ${theme.palette.darkGrey.dark}`} + > + + ({ color: theme.palette.grey[300] })} + /> + + } + aria-label={"Filter Moves"} + placeholder={"Filter Moves"} + onChange={(evt) => setSearch(evt.currentTarget.value)} + color={"primary"} + sx={(theme) => ({ + backgroundColor: theme.palette.darkGrey.main, + color: "#fff", + px: 2, borderBottomColor: theme.palette.darkGrey.light, - }, - })} - /> - - + })} + /> + + {filteredMoves.map((category, index) => ( { openDialog(move.$id); }} + forceOpen={isSearchActive} /> ))} diff --git a/src/components/features/charactersAndCampaigns/MovesSection/useFilterMoves.ts b/src/components/features/charactersAndCampaigns/MovesSection/useFilterMoves.ts index f8aaf99c..47c6d4d3 100644 --- a/src/components/features/charactersAndCampaigns/MovesSection/useFilterMoves.ts +++ b/src/components/features/charactersAndCampaigns/MovesSection/useFilterMoves.ts @@ -6,7 +6,7 @@ import { useCustomMoves } from "./useCustomMoves"; import { useStore } from "stores/store"; export function useFilterMoves() { - const { setSearch, debouncedSearch } = useSearch(); + const { search, setSearch, debouncedSearch } = useSearch(); const [filteredMoves, setFilteredMoves] = useState(orderedCategories); const { customMoveCategories } = useCustomMoves(); @@ -58,5 +58,5 @@ export function useFilterMoves() { setFilteredMoves(results); }, [debouncedSearch, customMoveCategories, showDelveMoves]); - return { setSearch, filteredMoves }; + return { setSearch, filteredMoves, isSearchActive: !!search }; } diff --git a/src/components/features/charactersAndCampaigns/OracleDrawer.tsx b/src/components/features/charactersAndCampaigns/OracleDrawer.tsx index 010cdc45..d6b02656 100644 --- a/src/components/features/charactersAndCampaigns/OracleDrawer.tsx +++ b/src/components/features/charactersAndCampaigns/OracleDrawer.tsx @@ -15,6 +15,7 @@ function OracleDrawerUnMemoized(props: OracleDrawerProps) { store.appState.openDialog); @@ -22,6 +26,14 @@ export function OracleCategory(props: OracleCategoryProps) { const sampleNames = category["Sample Names" as "Sample names"]; + const showNewView = useNewMoveOracleView(); + const [isExpanded, setIsExpanded] = useState(showNewView ? false : true); + useEffect(() => { + setIsExpanded(showNewView ? false : true); + }, [showNewView]); + + const isExpandedOrForced = isExpanded || forceOpen || false; + if (hiddenOracleCategoryIds[category.$id]) { return null; } @@ -29,52 +41,67 @@ export function OracleCategory(props: OracleCategoryProps) { return ( <> - {Object.keys(category.Tables ?? {}).length > 0 && ( - ({ - backgroundColor: - theme.palette.darkGrey[ - theme.palette.mode === "light" ? "light" : "dark" - ], - color: theme.palette.darkGrey.contrastText, - ...theme.typography.body1, - fontFamily: theme.fontFamilyTitle, - })} - > - {title} - - )} - {Array.isArray(sampleNames) && - sampleNames.length > 0 && - Object.keys(category.Tables ?? {}).length > 0 && ( - - rollOracleTable(category.$id + "/sample_names", true, true) - } - onOpenClick={() => openDialog(category.$id + "/sample_names")} - /> - )} - {Object.keys(category.Tables ?? {}).map((oracleId, index) => { - const oracle = category.Tables?.[oracleId]; - if (!oracle) return null; - return ( - rollOracleTable(oracle.$id, true, true)} - onOpenClick={() => { - openDialog(oracle.$id); - }} + {Object.keys(category.Tables ?? {}).length > 0 && + (showNewView ? ( + !forceOpen && setIsExpanded((prev) => !prev)} + text={title} /> - ); - })} + ) : ( + ({ + backgroundColor: + theme.palette.darkGrey[ + theme.palette.mode === "light" ? "light" : "dark" + ], + color: theme.palette.darkGrey.contrastText, + ...theme.typography.body1, + fontFamily: theme.fontFamilyTitle, + })} + > + {title} + + ))} + + + {Array.isArray(sampleNames) && + sampleNames.length > 0 && + Object.keys(category.Tables ?? {}).length > 0 && ( + + rollOracleTable(category.$id + "/sample_names", true, true) + } + onOpenClick={() => openDialog(category.$id + "/sample_names")} + /> + )} + {Object.keys(category.Tables ?? {}).map((oracleId, index) => { + const oracle = category.Tables?.[oracleId]; + if (!oracle) return null; + return ( + rollOracleTable(oracle.$id, true, true)} + onOpenClick={() => { + openDialog(oracle.$id); + }} + /> + ); + })} + + {Object.keys(category.Sets ?? {}).map((oracleSetId) => { const set = category.Sets?.[oracleSetId]; if (!set) return null; diff --git a/src/components/features/charactersAndCampaigns/OracleSection/OracleListItem.tsx b/src/components/features/charactersAndCampaigns/OracleSection/OracleListItem.tsx index 338b8e10..a20f190d 100644 --- a/src/components/features/charactersAndCampaigns/OracleSection/OracleListItem.tsx +++ b/src/components/features/charactersAndCampaigns/OracleSection/OracleListItem.tsx @@ -24,8 +24,8 @@ export function OracleListItem(props: OracleListItemProps) { id={id} disablePadding sx={(theme) => ({ - "&:nth-of-type(odd)": { - backgroundColor: theme.palette.action.hover, + "&:nth-of-type(even)": { + backgroundColor: theme.palette.background.paperInlay, }, "& #open-table": { display: isTouchDevice ? "inline-flex" : "none", diff --git a/src/components/features/charactersAndCampaigns/OracleSection/OracleSection.tsx b/src/components/features/charactersAndCampaigns/OracleSection/OracleSection.tsx index 95896a56..4954b4fc 100644 --- a/src/components/features/charactersAndCampaigns/OracleSection/OracleSection.tsx +++ b/src/components/features/charactersAndCampaigns/OracleSection/OracleSection.tsx @@ -5,7 +5,7 @@ import { useFilterOracles } from "./useFilterOracles"; import { AskTheOracleButtons } from "./AskTheOracleButtons"; export function OracleSection() { - const { search, filteredOracles, setSearch } = useFilterOracles(); + const { isSearchActive, filteredOracles, setSearch } = useFilterOracles(); return ( <> @@ -34,7 +34,6 @@ export function OracleSection() { } aria-label={"Filter Oracles"} placeholder={"Filter Oracles"} - value={search} onChange={(evt) => setSearch(evt.target.value)} color={"primary"} sx={(theme) => ({ @@ -46,7 +45,11 @@ export function OracleSection() { /> {filteredOracles.map((category, index) => ( - + ))} diff --git a/src/components/features/charactersAndCampaigns/OracleSection/useFilterOracles.ts b/src/components/features/charactersAndCampaigns/OracleSection/useFilterOracles.ts index cf2cf197..359a1d17 100644 --- a/src/components/features/charactersAndCampaigns/OracleSection/useFilterOracles.ts +++ b/src/components/features/charactersAndCampaigns/OracleSection/useFilterOracles.ts @@ -127,5 +127,5 @@ export function useFilterOracles() { showDelveOracles, ]); - return { search, setSearch, filteredOracles }; + return { isSearchActive: !!search, setSearch, filteredOracles }; } diff --git a/src/components/shared/AccessibilitySettingsDialog/AccessibilitySettingsDialog.tsx b/src/components/shared/Layout/AccessibilitySettingsDialog/AccessibilitySettingsDialog.tsx similarity index 94% rename from src/components/shared/AccessibilitySettingsDialog/AccessibilitySettingsDialog.tsx rename to src/components/shared/Layout/AccessibilitySettingsDialog/AccessibilitySettingsDialog.tsx index e64a0986..e52c2764 100644 --- a/src/components/shared/AccessibilitySettingsDialog/AccessibilitySettingsDialog.tsx +++ b/src/components/shared/Layout/AccessibilitySettingsDialog/AccessibilitySettingsDialog.tsx @@ -7,7 +7,7 @@ import { DialogContent, FormControlLabel, } from "@mui/material"; -import { DialogTitleWithCloseButton } from "../DialogTitleWithCloseButton"; +import { DialogTitleWithCloseButton } from "components/shared/DialogTitleWithCloseButton"; import { useStore } from "stores/store"; export interface AccessibilitySettingsDialogProps { diff --git a/src/components/shared/Layout/AccessibilitySettingsDialog/index.ts b/src/components/shared/Layout/AccessibilitySettingsDialog/index.ts new file mode 100644 index 00000000..6bd66360 --- /dev/null +++ b/src/components/shared/Layout/AccessibilitySettingsDialog/index.ts @@ -0,0 +1 @@ +export * from "./AccessibilitySettingsDialog"; diff --git a/src/components/shared/Layout/BetaTestsDialog.tsx b/src/components/shared/Layout/BetaTestsDialog.tsx new file mode 100644 index 00000000..538c03d7 --- /dev/null +++ b/src/components/shared/Layout/BetaTestsDialog.tsx @@ -0,0 +1,93 @@ +import { + Button, + Dialog, + DialogActions, + DialogContent, + FormControlLabel, + LinearProgress, + Stack, + Switch, +} from "@mui/material"; +import { DialogTitleWithCloseButton } from "../DialogTitleWithCloseButton"; +import { activeFeatureFlags } from "hooks/featureFlags/activeFeatureFlags"; +import { EmptyState } from "../EmptyState"; +import { useEffect, useRef, useState } from "react"; +import { useStore } from "stores/store"; + +export interface BetaTestsDialogProps { + open: boolean; + onClose: () => void; +} + +export function BetaTestsDialog(props: BetaTestsDialogProps) { + const { open, onClose } = props; + + const updateBetaTests = useStore((store) => store.appState.updateBetaTests); + + const [testStates, setTestStates] = useState>(); + const initialTestStates = useRef>(); + + useEffect(() => { + const forcedGroups: { [groupName: string]: boolean } = JSON.parse( + localStorage.getItem("forcedGroups") ?? "{}" + ); + setTestStates(forcedGroups); + initialTestStates.current = forcedGroups; + }, []); + + const handleTestChange = (testId: string, value: boolean) => { + setTestStates((prev) => ({ + ...prev, + [testId]: value, + })); + }; + + const handleSave = () => { + if (testStates !== initialTestStates.current && testStates !== undefined) { + updateBetaTests(testStates); + onClose(); + } else { + onClose(); + } + }; + + return ( + + + Beta Tests + + + {activeFeatureFlags.length === 0 ? ( + + ) : testStates === undefined ? ( + + ) : ( + + {activeFeatureFlags.map((flagConfig) => ( + + handleTestChange(flagConfig.testId, checked) + } + /> + } + label={flagConfig.label} + /> + ))} + + )} + + + + + + + ); +} diff --git a/src/components/shared/Layout/HeaderMenu.tsx b/src/components/shared/Layout/HeaderMenu.tsx index c5c18f05..c8ae164b 100644 --- a/src/components/shared/Layout/HeaderMenu.tsx +++ b/src/components/shared/Layout/HeaderMenu.tsx @@ -1,5 +1,5 @@ import { - ButtonBase, + IconButton, ListItemIcon, ListItemText, Menu, @@ -8,8 +8,6 @@ import { import { useRef, useState } from "react"; import { logout } from "lib/auth.lib"; import LogoutIcon from "@mui/icons-material/Logout"; -import { useStore } from "stores/store"; -import { UserAvatar } from "components/shared/UserAvatar"; import { useToggleTheme } from "providers/ThemeProvider"; import LightThemeIcon from "@mui/icons-material/LightMode"; import DarkThemeIcon from "@mui/icons-material/DarkMode"; @@ -23,11 +21,12 @@ import { constructCharacterPath, } from "pages/Character/routes"; import AccessibilityIcon from "@mui/icons-material/AccessibilityNew"; -import { AccessibilitySettingsDialog } from "../AccessibilitySettingsDialog/AccessibilitySettingsDialog"; +import { AccessibilitySettingsDialog } from "./AccessibilitySettingsDialog"; +import SettingsIcon from "@mui/icons-material/Settings"; +import { BetaTestsDialog } from "./BetaTestsDialog"; +import TestsIcon from "@mui/icons-material/AutoAwesome"; export function HeaderMenu() { - const userId = useStore((store) => store.auth.uid); - const [menuOpen, setMenuOpen] = useState(false); const anchorRef = useRef(null); @@ -39,18 +38,27 @@ export function HeaderMenu() { const [accessibilitySettingsOpen, setAccessibilitySettingsOpen] = useState(false); + const [betaTestsOpen, setBetaTestsOpen] = useState(false); + return ( <> - setMenuOpen(true)} > - - + ({ + transform: `rotate(${menuOpen ? "90deg" : "0deg"})`, + transition: theme.transitions.create(["transform"], { + duration: theme.transitions.duration.shorter, + }), + })} + /> + setMenuOpen(false)} @@ -67,6 +75,17 @@ export function HeaderMenu() { Accessibility Settings + { + setMenuOpen(false); + setBetaTestsOpen(true); + }} + > + + + + Beta Tests + { setMenuOpen(false); @@ -120,6 +139,10 @@ export function HeaderMenu() { open={accessibilitySettingsOpen} onClose={() => setAccessibilitySettingsOpen(false)} /> + setBetaTestsOpen(false)} + /> ); } diff --git a/src/components/shared/Layout/Layout.tsx b/src/components/shared/Layout/Layout.tsx index 00403726..bc6f9772 100644 --- a/src/components/shared/Layout/Layout.tsx +++ b/src/components/shared/Layout/Layout.tsx @@ -17,13 +17,13 @@ import { UserNameDialog } from "components/shared/UserNameDialog"; import { useStore } from "stores/store"; import { AUTH_STATE } from "stores/auth/auth.slice.type"; import { SkipToContentButton } from "./SkipToContentButton"; -import { useQueryParameterFeatureFlags } from "hooks/featureFlags/useQueryParameterFeatureFlags"; +import { useSyncFeatureFlags } from "hooks/featureFlags/useSyncFeatureFlags"; import { LinkedDialog } from "components/features/charactersAndCampaigns/LinkedDialog"; import { LiveRegion } from "../LiveRegion"; import { RollSnackbarSection } from "../RollSnackbar"; export function Layout() { - useQueryParameterFeatureFlags(); + useSyncFeatureFlags(); const { pathname } = useLocation(); const state = useStore((store) => store.auth.status); diff --git a/src/hooks/featureFlags/activeFeatureFlags.ts b/src/hooks/featureFlags/activeFeatureFlags.ts new file mode 100644 index 00000000..99ff18ba --- /dev/null +++ b/src/hooks/featureFlags/activeFeatureFlags.ts @@ -0,0 +1,6 @@ +export const activeFeatureFlags: { testId: string; label: string }[] = [ + { + testId: "new-move-oracle-view", + label: "Collapsible Move and Oracle Categories", + }, +]; diff --git a/src/hooks/featureFlags/useFeatureFlag.ts b/src/hooks/featureFlags/useFeatureFlag.ts index 8457eecf..b2f7b30a 100644 --- a/src/hooks/featureFlags/useFeatureFlag.ts +++ b/src/hooks/featureFlags/useFeatureFlag.ts @@ -1,13 +1,12 @@ import { useFeatureFlagEnabled } from "posthog-js/react"; +import { useStore } from "stores/store"; export function useFeatureFlag(flag: string): boolean { - const forcedGroups: { [groupName: string]: boolean } = JSON.parse( - localStorage.getItem("forcedGroups") ?? "{}" - ); + const activeBetaTests = useStore((store) => store.appState.betaTests); const flagValue = useFeatureFlagEnabled(flag) ?? false; - if (flag in forcedGroups) { - return forcedGroups[flag]; + if (flag in activeBetaTests) { + return activeBetaTests[flag]; } return flagValue; diff --git a/src/hooks/featureFlags/useNewMoveOracleView.ts b/src/hooks/featureFlags/useNewMoveOracleView.ts new file mode 100644 index 00000000..97f4a57b --- /dev/null +++ b/src/hooks/featureFlags/useNewMoveOracleView.ts @@ -0,0 +1,5 @@ +import { useFeatureFlag } from "./useFeatureFlag"; + +export function useNewMoveOracleView() { + return useFeatureFlag("new-move-oracle-view"); +} diff --git a/src/hooks/featureFlags/useQueryParameterFeatureFlags.ts b/src/hooks/featureFlags/useQueryParameterFeatureFlags.ts deleted file mode 100644 index 18b6d93a..00000000 --- a/src/hooks/featureFlags/useQueryParameterFeatureFlags.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { useSearchParams } from "react-router-dom"; - -export function useQueryParameterFeatureFlags() { - const [searchParams] = useSearchParams(); - - const groups = searchParams.get("featureGroups")?.split(","); - - const groupResults: { [group: string]: boolean } = JSON.parse( - localStorage.getItem("forcedGroups") ?? "{}" - ); - - groups?.forEach((group) => { - if (group.length > 1) { - const groupName = group.slice(0, group.length - 1); - const trueFalseFlag = group.slice(group.length - 1); - if (trueFalseFlag === "r") { - delete groupResults[groupName]; - } else if (trueFalseFlag === "n") { - groupResults[groupName] = false; - } else if (trueFalseFlag === "y") { - groupResults[groupName] = true; - } - } - }); - - localStorage.setItem("forcedGroups", JSON.stringify(groupResults)); -} diff --git a/src/hooks/featureFlags/useSyncFeatureFlags.ts b/src/hooks/featureFlags/useSyncFeatureFlags.ts new file mode 100644 index 00000000..b3cb1c1b --- /dev/null +++ b/src/hooks/featureFlags/useSyncFeatureFlags.ts @@ -0,0 +1,24 @@ +import { useEffect, useRef } from "react"; +import { useStore } from "stores/store"; + +export function useSyncFeatureFlags() { + const betaTests = useStore((store) => store.appState.betaTests); + const updateBetaTests = useStore((store) => store.appState.updateBetaTests); + const isInitialLoad = useRef(true); + + useEffect(() => { + const localStorageResults: { [group: string]: boolean } = JSON.parse( + localStorage.getItem("forcedGroups") ?? "{}" + ); + console.debug("UPDATING STATE TO:", localStorageResults); + updateBetaTests(localStorageResults); + }, [updateBetaTests]); + + useEffect(() => { + if (!isInitialLoad.current) { + localStorage.setItem("forcedGroups", JSON.stringify(betaTests)); + } else { + isInitialLoad.current = false; + } + }, [betaTests]); +} diff --git a/src/pages/Character/CharacterSheetPage/CharacterSheetPage.tsx b/src/pages/Character/CharacterSheetPage/CharacterSheetPage.tsx index 1aa73929..8c86033b 100644 --- a/src/pages/Character/CharacterSheetPage/CharacterSheetPage.tsx +++ b/src/pages/Character/CharacterSheetPage/CharacterSheetPage.tsx @@ -77,7 +77,7 @@ export function CharacterSheetPage() { isPaper sx={(theme) => ({ bgcolor: - theme.palette.mode === "light" + theme.palette.mode === "light" && isMobile ? "background.paperInlay" : undefined, })} diff --git a/src/pages/Character/CharacterSheetPage/components/Sidebar.tsx b/src/pages/Character/CharacterSheetPage/components/Sidebar.tsx index 080a9167..7e92fa05 100644 --- a/src/pages/Character/CharacterSheetPage/components/Sidebar.tsx +++ b/src/pages/Character/CharacterSheetPage/components/Sidebar.tsx @@ -32,7 +32,7 @@ export function Sidebar() { variant={"outlined"} sx={{ minWidth: 300, - height: "100%", + maxHeight: "100%", display: { xs: "none", md: "flex" }, flexDirection: "column", }} diff --git a/src/providers/ThemeProvider/themes/starforged-dark.tsx b/src/providers/ThemeProvider/themes/starforged-dark.tsx index 329f9f8a..b0af68ed 100644 --- a/src/providers/ThemeProvider/themes/starforged-dark.tsx +++ b/src/providers/ThemeProvider/themes/starforged-dark.tsx @@ -24,6 +24,7 @@ export const starforgedDarkTheme = createTheme({ default: starforgedGrey[950], }, grey: starforgedGrey, + divider: starforgedGrey[600], }, typography: { fontFamily: ["RubikVariable", ...baseFontFamilies].join(","), @@ -52,7 +53,6 @@ export const starforgedDarkTheme = createTheme({ MuiPaper: { styleOverrides: { root: { - border: `1px solid ${starforgedGrey[700]}`, backgroundImage: "unset!important", // Remove the annoying elevation background filter }, }, diff --git a/src/providers/ThemeProvider/themes/starforged-light.tsx b/src/providers/ThemeProvider/themes/starforged-light.tsx index ab364f16..60f18975 100644 --- a/src/providers/ThemeProvider/themes/starforged-light.tsx +++ b/src/providers/ThemeProvider/themes/starforged-light.tsx @@ -15,6 +15,7 @@ export const starforgedLightTheme = createTheme({ dark: starforgedGrey[800], contrastText: "#fff", }, + divider: starforgedGrey[300], ...sharedStatusColors, background: { paper: "#fff", diff --git a/src/stores/appState/appState.slice.default.ts b/src/stores/appState/appState.slice.default.ts index f0e56f5e..97ee4a17 100644 --- a/src/stores/appState/appState.slice.default.ts +++ b/src/stores/appState/appState.slice.default.ts @@ -6,4 +6,5 @@ export const defaultAppState: AppStateData = { previousIds: [], }, rolls: [], + betaTests: {}, }; diff --git a/src/stores/appState/appState.slice.ts b/src/stores/appState/appState.slice.ts index f6faf221..62eadec9 100644 --- a/src/stores/appState/appState.slice.ts +++ b/src/stores/appState/appState.slice.ts @@ -75,4 +75,10 @@ export const createAppStateSlice: CreateSliceType = (set) => ({ store.appState.screenReaderAnnouncement = announcement; }); }, + + updateBetaTests: (newTests) => { + set((store) => { + store.appState.betaTests = newTests; + }); + }, }); diff --git a/src/stores/appState/appState.slice.type.ts b/src/stores/appState/appState.slice.type.ts index 0c24e87e..c9e22fa3 100644 --- a/src/stores/appState/appState.slice.type.ts +++ b/src/stores/appState/appState.slice.type.ts @@ -10,6 +10,8 @@ export interface AppStateData { rolls: Roll[]; screenReaderAnnouncement?: string; + + betaTests: Record; } export interface AppStateActions { @@ -22,6 +24,8 @@ export interface AppStateActions { clearRolls: () => void; announce: (announcement: string) => void; + + updateBetaTests: (newValues: Record) => void; } export type AppStateSlice = AppStateData & AppStateActions;