diff --git a/app/components/Puzzle.tsx b/app/components/Puzzle.tsx index 344a1e21..9d944920 100644 --- a/app/components/Puzzle.tsx +++ b/app/components/Puzzle.tsx @@ -30,6 +30,7 @@ import { FaEdit, FaRegFile, FaMoon, + FaCog, } from 'react-icons/fa'; import { ClueText } from './ClueText'; import { IoMdStats } from 'react-icons/io'; @@ -91,6 +92,7 @@ import { TopBarDropDownLinkA, TopBarDropDown, TopBarDropDownLinkSimpleA, + NestedDropDown, } from './TopBar'; import { SLATE_PADDING_LARGE, @@ -148,6 +150,7 @@ import { SlateColorTheme } from './SlateColorTheme'; import { Check, Clues, Grid, More, Pause, Reveal, Timer } from './SlateIcons'; import { removeSpoilers } from '../lib/markdown/markdown'; import { SlateBegin, SlatePause, SlateSuccess } from './SlateOverlays'; +import { SolverPreferencesList } from './SolverPreferencesList'; const ModeratingOverlay = dynamic( () => import('./ModerateOverlay').then((mod) => mod.ModeratingOverlay), @@ -392,7 +395,7 @@ export const Puzzle = ({ // Pause when page goes out of focus function prodPause() { - if (process.env.NODE_ENV !== 'development') { + if (process.env.NODE_ENV !== 'development' && !props.prefs?.dontPauseOnLostFocus) { window.parent.postMessage( { type: 'pause', @@ -679,9 +682,9 @@ export const Puzzle = ({ const physicalKeyboardHandler = useCallback( (e: KeyboardEvent) => { - // Disable keyboard when paused / loading play + // Disable keyboard when loading play if (!(state.success && state.dismissedSuccess)) { - if (loadingPlayState || !state.currentTimeWindowStart) { + if (loadingPlayState) { return; } } @@ -696,7 +699,6 @@ export const Puzzle = ({ [ dispatch, loadingPlayState, - state.currentTimeWindowStart, state.success, state.dismissedSuccess, ] @@ -1030,7 +1032,8 @@ export const Puzzle = ({ ), [state.autocheck, isSlate] ); - + + const user = props.user; const moreMenu = useMemo( () => ( <> @@ -1038,7 +1041,7 @@ export const Puzzle = ({ icon={isSlate ? : } text={t`More`} > - {() => ( + {(closeDropdown) => ( <> {!state.success ? ( ) : null} + {user !== undefined ? ( + } + text={"Solver Preferences"} + > + {() => +
    + +
+ } +
+ ) : ('' + )} } @@ -1172,7 +1197,9 @@ export const Puzzle = ({ [ muted, props.isAdmin, - props.user?.uid, + props.user, + props.prefs, + user, puzzle, setMuted, state.success, diff --git a/app/components/SolverPreferencesList.tsx b/app/components/SolverPreferencesList.tsx new file mode 100644 index 00000000..bf303435 --- /dev/null +++ b/app/components/SolverPreferencesList.tsx @@ -0,0 +1,95 @@ +import { setDoc } from "firebase/firestore"; +import { AccountPrefsFlagsT, AccountPrefsT } from "../lib/prefs"; +import { logAsyncErrors } from "../lib/utils"; +import { useSnackbar } from "./Snackbar"; +import { getDocRef } from "../lib/firebaseWrapper"; + +interface PrefSettingProps { + prefs: AccountPrefsT | undefined; + userId: string; + flag: keyof AccountPrefsFlagsT; + text: string; + invert?: boolean; +} + +export const PrefSetting = (props: PrefSettingProps) => { + const { showSnackbar } = useSnackbar(); + const prefSet = props.prefs?.[props.flag] ?? false; + return ( + +); +}; + +export const SolverPreferencesList = ({prefs, userId}: {prefs?: AccountPrefsT, userId: string}) => { + if (!prefs) { + return null; // or some default content + } + return ( + <> +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • + + ); +}; \ No newline at end of file diff --git a/app/lib/prefs.ts b/app/lib/prefs.ts index 9f5fe573..3513b54b 100644 --- a/app/lib/prefs.ts +++ b/app/lib/prefs.ts @@ -14,6 +14,7 @@ const AccountPrefsFlagsV = t.partial({ dontAdvanceWordAfterCompletion: t.boolean, solveDownsOnly: t.boolean, disableCommentsByDefault: t.boolean, + dontPauseOnLostFocus: t.boolean }); export type AccountPrefsFlagsT = t.TypeOf; diff --git a/app/pages/account.tsx b/app/pages/account.tsx index 5447c5e5..6d58edf2 100644 --- a/app/pages/account.tsx +++ b/app/pages/account.tsx @@ -12,7 +12,6 @@ import { PROFILE_PIC, COVER_PIC } from '../lib/style'; import { UnsubscribeFlags, AccountPrefsT, - AccountPrefsFlagsT, } from '../lib/prefs'; import dynamic from 'next/dynamic'; @@ -36,6 +35,7 @@ import { import { signOut } from 'firebase/auth'; import { BioEditor } from '../components/BioEditor'; import { logAsyncErrors } from '../lib/utils'; +import { PrefSetting, SolverPreferencesList } from '../components/SolverPreferencesList'; export const getStaticProps = withStaticTranslation(() => { return { props: {} }; @@ -81,40 +81,6 @@ const UnsubSetting = (props: UnsubSettingProps) => { ); }; -interface PrefSettingProps { - prefs: AccountPrefsT | undefined; - userId: string; - flag: keyof AccountPrefsFlagsT; - text: string; - invert?: boolean; -} - -const PrefSetting = (props: PrefSettingProps) => { - const { showSnackbar } = useSnackbar(); - const prefSet = props.prefs?.[props.flag] ?? false; - return ( - - ); -}; - export const AccountPage = ({ user, constructorPage, prefs }: AuthProps) => { const [settingProfilePic, setSettingProfilePic] = useState(false); const [settingCoverPic, setSettingCoverPic] = useState(false); @@ -209,40 +175,10 @@ export const AccountPage = ({ user, constructorPage, prefs }: AuthProps) => { padding: '0 0', }} > -
  • - -
  • -
  • - -
  • -
  • - -
  • -
  • - -
  • +

    Browser-specific Settings

    diff --git a/app/reducers/reducer.ts b/app/reducers/reducer.ts index 72496507..fe9d574e 100644 --- a/app/reducers/reducer.ts +++ b/app/reducers/reducer.ts @@ -814,6 +814,19 @@ export function gridInterfaceReducer( } if (isKeypressAction(action)) { const key = action.key; + // Resume on Esc, but only during midgame pause + if (isPuzzleState(state) && !state.currentTimeWindowStart) { + if (state.bankedSeconds === 0) { + return state; + } + if (key.k === KeyK.Escape) { + return { + ...state, + currentTimeWindowStart: new Date().getTime() + } + } + return state; + } if (key.k === KeyK.NumLayout || key.k === KeyK.AbcLayout) { return { ...state, showExtraKeyLayout: !state.showExtraKeyLayout }; }