diff --git a/components/cards/card.tsx b/components/cards/card.tsx index 4ffadbaf4..33a2207f8 100644 --- a/components/cards/card.tsx +++ b/components/cards/card.tsx @@ -12,7 +12,11 @@ export default function Card({ children, id, title, tooltip }: CardProps) { const tooltipId = `card-tooltip-${id}`; return ( +<<<<<<< HEAD +
>>>>>> c883f344 (`/home` tweaks (#1001)) id={id} style={{ backgroundColor: 'var(--bg-color-2)', diff --git a/components/cards/chapterSelectCard.tsx b/components/cards/chapterSelectCard.tsx index 975c8b475..54ae9eb8e 100644 --- a/components/cards/chapterSelectCard.tsx +++ b/components/cards/chapterSelectCard.tsx @@ -5,7 +5,14 @@ import getPngDataClient from '../../helpers/getPngDataClient'; import styles from './SelectCard.module.css'; interface ChapterSelectCardBaseProps { +<<<<<<< HEAD +<<<<<<< HEAD complete?: boolean; +======= +>>>>>>> c883f344 (`/home` tweaks (#1001)) +======= + complete?: boolean; +>>>>>>> dc89605e (ch4 preview (#1006)) disabled?: boolean; disabledStr?: string; href: string; @@ -16,7 +23,14 @@ interface ChapterSelectCardBaseProps { } function ChapterSelectCardBase({ +<<<<<<< HEAD +<<<<<<< HEAD + complete, +======= +>>>>>>> c883f344 (`/home` tweaks (#1001)) +======= complete, +>>>>>>> dc89605e (ch4 preview (#1006)) disabled, disabledStr, href, @@ -77,16 +91,40 @@ function ChapterSelectCardBase({ interface ChapterSelectCardProps { chapter: number; chapterUnlocked?: number; +<<<<<<< HEAD +<<<<<<< HEAD + href?: string; +} + +export default function ChapterSelectCard({ chapter, chapterUnlocked, href }: ChapterSelectCardProps) { +======= +} + +export default function ChapterSelectCard({ chapter, chapterUnlocked }: ChapterSelectCardProps) { +>>>>>>> c883f344 (`/home` tweaks (#1001)) +======= href?: string; } export default function ChapterSelectCard({ chapter, chapterUnlocked, href }: ChapterSelectCardProps) { +>>>>>>> cf73c37e (more intuitive campaign button) switch (chapter) { case 1: return ( 1} href={href ?? '/chapter1'} +<<<<<<< HEAD +======= +======= + complete={!!chapterUnlocked && chapterUnlocked > 1} +>>>>>>> dc89605e (ch4 preview (#1006)) + href={'/chapter1'} +>>>>>>> c883f344 (`/home` tweaks (#1001)) +======= +>>>>>>> cf73c37e (more intuitive campaign button) id='chapter1' levelData={'00000000\n00000000\n00000000\n00000000'} subtitle={'Grassroots'} @@ -96,10 +134,23 @@ export default function ChapterSelectCard({ chapter, chapterUnlocked, href }: Ch case 2: return ( 2} disabled={chapterUnlocked ? chapterUnlocked < 2 : false} disabledStr={'Complete Chapter 1 to unlock Chapter 2!'} href={href ?? '/chapter2'} +<<<<<<< HEAD +======= +======= + complete={!!chapterUnlocked && chapterUnlocked > 2} +>>>>>>> dc89605e (ch4 preview (#1006)) + disabled={chapterUnlocked ? chapterUnlocked < 2 : false} + disabledStr={'Complete Chapter 1 to unlock Chapter 2!'} + href={'/chapter2'} +>>>>>>> c883f344 (`/home` tweaks (#1001)) +======= +>>>>>>> cf73c37e (more intuitive campaign button) id='chapter2' levelData={'005E0C00\n0G070005\n10005010\n005100I0'} subtitle={'Into the Depths'} @@ -109,27 +160,59 @@ export default function ChapterSelectCard({ chapter, chapterUnlocked, href }: Ch case 3: return ( 3} disabled={chapterUnlocked ? chapterUnlocked < 3 : false} disabledStr={'Complete Chapter 2 to unlock Chapter 3!'} href={href ?? '/chapter3'} +<<<<<<< HEAD +======= +======= + complete={!!chapterUnlocked && chapterUnlocked > 3} +>>>>>>> dc89605e (ch4 preview (#1006)) + disabled={chapterUnlocked ? chapterUnlocked < 3 : false} + disabledStr={'Complete Chapter 2 to unlock Chapter 3!'} + href={'/chapter3'} +>>>>>>> c883f344 (`/home` tweaks (#1001)) +======= +>>>>>>> cf73c37e (more intuitive campaign button) id='chapter3' levelData={'B519F0G0\n10JH5H52\n75F02J08\n02050B10'} subtitle={'Brain Busters'} title={'Chapter 3'} /> ); +<<<<<<< HEAD +<<<<<<< HEAD + case 4: + return ( + >>>>>> dc89605e (ch4 preview (#1006)) +======= disabled={!href} href={href ?? '/play'} +>>>>>>> cf73c37e (more intuitive campaign button) id='chapter4' levelData={'65G9F0G5\nGBJ5GH5I\n50FF25DG\nJ5I5H505'} subtitle={'Coming soon...'} title={'Chapter 4'} /> ); +<<<<<<< HEAD +======= +>>>>>>> c883f344 (`/home` tweaks (#1001)) +======= +>>>>>>> dc89605e (ch4 preview (#1006)) default: return null; } diff --git a/components/formatted/formattedUser.tsx b/components/formatted/formattedUser.tsx index f7abb48ca..3b3443af8 100644 --- a/components/formatted/formattedUser.tsx +++ b/components/formatted/formattedUser.tsx @@ -65,7 +65,40 @@ export default function FormattedUser({ className, id, noLinks, noTooltip, onCli return (<>
+ {!userExtendedData ? : <> + {userExtendedData.user.name} + {!userExtendedData.user.ts ? Unregistered : <> +
+ Rank: + +
+
+ Levels Solved: + {userExtendedData.user.score} +
+
+ Registered: + +
+ } + } +
+ )} + data-tooltip-id={tooltipId} +>>>>>>> 7fe3d9c4 (solved and completed terminology (#994)) +======= + className={classNames('flex items-center gap-2 truncate w-fit max-w-full', className)} +>>>>>>> c883f344 (`/home` tweaks (#1001)) onMouseOut={() => { if (setTimer.current) { clearTimeout(setTimer.current); diff --git a/components/homepage/homeLoggedIn.tsx b/components/homepage/homeLoggedIn.tsx index 227237a7f..08fe7182a 100644 --- a/components/homepage/homeLoggedIn.tsx +++ b/components/homepage/homeLoggedIn.tsx @@ -68,9 +68,29 @@ export default function HomeLoggedIn({ }
+<<<<<<< HEAD +<<<<<<< HEAD
+======= + + Pathology Official Campaign + + } + tooltip='Click here to go to the chapter select screen, or continue with the chapter button below!' + > +
+ +>>>>>>> c883f344 (`/home` tweaks (#1001)) +======= + +
+ +>>>>>>> cf73c37e (more intuitive campaign button)
@@ -107,23 +127,59 @@ export default function HomeLoggedIn({
+<<<<<<< HEAD +<<<<<<< HEAD >>>>>> 8ac2e750 (Playhistory (#988)) +======= + title='Level of the Day' +>>>>>>> c883f344 (`/home` tweaks (#1001)) tooltip={'Every day there is a new level of the day. Difficulty increases throughout the week!'} /> +======= + title='Try this Level 🫴' + tooltip={'This is a quality level with similar difficulty to levels you\'ve played recently.'} + /> + {/* */} +>>>>>>> 8ac2e750 (Playhistory (#988)) +======= + title='Try this Level' + tooltip={'This is a quality level with similar difficulty to levels you\'ve played recently.'} + /> +>>>>>>> c883f344 (`/home` tweaks (#1001)) +<<<<<<< HEAD +<<<<<<< HEAD +======= + + + + + +>>>>>>> 8ac2e750 (Playhistory (#988)) +======= +>>>>>>> c883f344 (`/home` tweaks (#1001)) Last Played @@ -133,7 +189,21 @@ export default function HomeLoggedIn({
} tooltip='Resume your last play. Click to see your play history.' +<<<<<<< HEAD + /> +======= + + + + {/* extra check to hide the level if it is already completed (in case of corrupted playattempt data) */} + {lastLevelPlayed && lastLevelPlayed.leastMoves !== lastLevelPlayed.userMoves && } +>>>>>>> 7060c231 (homepage tweaks) +======= /> +>>>>>>> 8ac2e750 (Playhistory (#988))
diff --git a/components/homepage/recommendedLevel.tsx b/components/homepage/recommendedLevel.tsx index 131d3da01..b77a411fa 100644 --- a/components/homepage/recommendedLevel.tsx +++ b/components/homepage/recommendedLevel.tsx @@ -8,17 +8,56 @@ import LoadingCard from '../cards/loadingCard'; import SelectCard from '../cards/selectCard'; interface RecommendedLevelProps { +<<<<<<< HEAD +<<<<<<< HEAD hrefOverride?: string; +======= +>>>>>>> c883f344 (`/home` tweaks (#1001)) id: string; level?: EnrichedLevel | null; +<<<<<<< HEAD onClick?: (option: SelectOption) => void; +======= +>>>>>>> 7060c231 (homepage tweaks) +======= + hrefOverride?: string; + id: string; + level?: EnrichedLevel | null; + onClick?: (option: SelectOption) => void; +>>>>>>> 58800b84 (post level modal and tooltips (#1000)) title: JSX.Element | string; tooltip?: string; } +<<<<<<< HEAD +<<<<<<< HEAD +======= +>>>>>>> 58800b84 (post level modal and tooltips (#1000)) export default function RecommendedLevel({ hrefOverride, id, level, onClick, title, tooltip }: RecommendedLevelProps): JSX.Element { return ( +======= +export default function RecommendedLevel({ id, level, title, tooltip }: RecommendedLevelProps): JSX.Element { + return ( +<<<<<<< HEAD +
+

+ {title} +

+<<<<<<< HEAD +>>>>>>> 7060c231 (homepage tweaks) +======= + +>>>>>>> 8ac2e750 (Playhistory (#988)) +======= + +>>>>>>> c883f344 (`/home` tweaks (#1001)) {level === undefined ? : !level ? { + const atEnd = gameState.board[gameState.pos.y][gameState.pos.x].tileType === TileType.End; + + if (atEnd && gameState.moves.length <= level.leastMoves && onSolve) { + onSolve(); + } + }, [gameState, level.leastMoves, onSolve]); +>>>>>>> 7fe3d9c4 (solved and completed terminology (#994)) +======= + }, [allowFreeUndo, disableCheckpoints, disablePlayAttempts, enableSessionCheckpoint, fetchPlayAttempt, level._id, level.data, level.leastMoves, loadCheckpoint, onMove, onNext, onPrev, onSolve, pro, saveCheckpoint, trackStats]); +>>>>>>> efe86a3a (signup toast and game.tsx change) useEffect(() => { if (disableCheckpoints || !pro || !checkpoints) { diff --git a/components/level/gameWrapper.tsx b/components/level/gameWrapper.tsx index f5760a743..195a2c981 100644 --- a/components/level/gameWrapper.tsx +++ b/components/level/gameWrapper.tsx @@ -1,4 +1,7 @@ +<<<<<<< HEAD import { LevelContext } from '@root/contexts/levelContext'; +======= +>>>>>>> 58800b84 (post level modal and tooltips (#1000)) import { PageContext } from '@root/contexts/pageContext'; import React, { useContext, useEffect, useState } from 'react'; import Collection from '../../models/db/collection'; @@ -16,16 +19,53 @@ interface GameWrapperProps { user: User | null; } +<<<<<<< HEAD +<<<<<<< HEAD export default function GameWrapper({ chapter, collection, level, onNext, onPrev, user }: GameWrapperProps) { const levelContext = useContext(LevelContext); +======= +export default function GameWrapper({ chapter, collection, level, onNext, onPrev, user }: GameWrapperProps) { +>>>>>>> f1dd274f (postgamemodal improvements) + const [postGameModalOpen, setShowPostGameModalOpen] = useState(false); + const { setPreventKeyDownEvent } = useContext(PageContext); +======= +export default function GameWrapper({ collection, level, onNext, onPrev, user }: GameWrapperProps) { +<<<<<<< HEAD + const signUpToast = throttle(2500, () => { + toast.dismiss(); + toast.success( +
+
+

Good job!

+

But your progress isn't saved...

+
+ Sign up (or use a Guest Account) to save your progress and get access to more features. +
+
+ +
+ , + { + duration: 10000, + icon: '🎉', + position: 'bottom-center', + }); + }); +>>>>>>> efe86a3a (signup toast and game.tsx change) +======= const [postGameModalOpen, setShowPostGameModalOpen] = useState(false); const { setPreventKeyDownEvent } = useContext(PageContext); +>>>>>>> 58800b84 (post level modal and tooltips (#1000)) useEffect(() => { setPreventKeyDownEvent(postGameModalOpen); }, [postGameModalOpen, setPreventKeyDownEvent]); return ( +<<<<<<< HEAD +<<<<<<< HEAD +======= +>>>>>>> 58800b84 (post level modal and tooltips (#1000)) <> setTimeout(() => setShowPostGameModalOpen(true), 200)} onSolve={() => levelContext && levelContext.setSidebarIndex(1)} /> setTimeout(() => setShowPostGameModalOpen(true), 200)} + /> + >>>>>> 58800b84 (post level modal and tooltips (#1000)) +======= + chapter={chapter} +>>>>>>> f1dd274f (postgamemodal improvements) closeModal={() => setShowPostGameModalOpen(false)} collection={collection} isOpen={postGameModalOpen} @@ -48,5 +98,29 @@ export default function GameWrapper({ chapter, collection, level, onNext, onPrev reqUser={user} /> +<<<<<<< HEAD +======= + { + if (!user) { + signUpToast(); + } + + if (collection) { + addNextButtonHighlight(); + } + }} + onNext={collection ? onNext : undefined} + onPrev={collection ? onPrev : undefined} + /> +>>>>>>> 7fe3d9c4 (solved and completed terminology (#994)) +======= +>>>>>>> 58800b84 (post level modal and tooltips (#1000)) ); } diff --git a/components/level/info/formattedLevelInfo.tsx b/components/level/info/formattedLevelInfo.tsx index 246eef816..168852f28 100644 --- a/components/level/info/formattedLevelInfo.tsx +++ b/components/level/info/formattedLevelInfo.tsx @@ -2,7 +2,10 @@ import { Tab } from '@headlessui/react'; import FormattedDate from '@root/components/formatted/formattedDate'; import FormattedLevelReviews from '@root/components/formatted/formattedLevelReviews'; import Solved from '@root/components/level/info/solved'; +<<<<<<< HEAD import classNames from 'classnames'; +======= +>>>>>>> 7fe3d9c4 (solved and completed terminology (#994)) import Image from 'next/image'; import React, { useContext, useState } from 'react'; import toast from 'react-hot-toast'; @@ -22,7 +25,10 @@ import UnpublishLevelModal from '../../modal/unpublishLevelModal'; import LevelInfoCompletions from './levelInfoCompletions'; import LevelInfoPlayTime from './levelInfoPlayTime'; import LevelInfoRecords from './levelInfoRecords'; +<<<<<<< HEAD import SuggestedPanel from './suggestedPanel'; +======= +>>>>>>> 7fe3d9c4 (solved and completed terminology (#994)) interface FormattedLevelInfoProps { level: EnrichedLevel; @@ -232,7 +238,7 @@ export default function FormattedLevelInfo({ level }: FormattedLevelInfoProps) { backgroundColor: 'var(--bg-color-4)', height: 1, }} /> -
+
{({ selected }) => ( -
+
Reviews
)} @@ -254,7 +260,7 @@ export default function FormattedLevelInfo({ level }: FormattedLevelInfoProps) { } }}> {({ selected }) => ( -
+
Suggestions
)} diff --git a/components/level/info/suggestedPanel.tsx b/components/level/info/suggestedPanel.tsx index 981ef0bad..738d04387 100644 --- a/components/level/info/suggestedPanel.tsx +++ b/components/level/info/suggestedPanel.tsx @@ -1,28 +1,34 @@ import DidYouKnowTip from '@root/components/page/didYouKnowTip'; +import { LevelContext } from '@root/contexts/levelContext'; import useHomePageData, { HomepageDataType } from '@root/hooks/useHomePageData'; -import Collection from '@root/models/db/collection'; import Level, { EnrichedLevel } from '@root/models/db/level'; import User from '@root/models/db/user'; import Link from 'next/link'; -import React, { useEffect, useState } from 'react'; +import React, { useContext, useEffect, useState } from 'react'; import Card from '../../cards/card'; import ChapterSelectCard from '../../cards/chapterSelectCard'; import RecommendedLevel from '../../homepage/recommendedLevel'; interface SuggestedPanelProps { - chapter?: string; - collection?: Collection; level: Level; reqUser: User | undefined | null; } -export default function SuggestedPanel({ chapter, collection, level, reqUser }: SuggestedPanelProps) { +export default function SuggestedPanel({ level, reqUser }: SuggestedPanelProps) { + const levelContext = useContext(LevelContext); + + const collection = levelContext?.collection; + const chapter = levelContext?.chapter; let nextLevel: EnrichedLevel | undefined = undefined; let lastLevelInCollection = false; + console.log(collection); + if (collection && collection.levels) { const levelIndex = collection.levels.findIndex((l) => l._id === level._id); + console.log(levelIndex, collection.levels.length); + if (levelIndex + 1 < collection.levels.length) { nextLevel = collection.levels[levelIndex + 1] as EnrichedLevel; } else { @@ -30,6 +36,7 @@ export default function SuggestedPanel({ chapter, collection, level, reqUser }: } } + // TODO: don't use SWR here, or at least don't refetch every time you switch to the panel const { data } = useHomePageData([HomepageDataType.RecommendedLevel], nextLevel !== undefined); const recommendedLevel = data && data[HomepageDataType.RecommendedLevel]; const [queryParams, setQueryParams] = useState({}); @@ -45,15 +52,7 @@ export default function SuggestedPanel({ chapter, collection, level, reqUser }: const hrefOverride = nextLevel ? `/level/${nextLevel.slug}?${queryParams}` : undefined; return (<> -
-

- Congratulations! -

-

- You completed {level.name}! -

-
-
+
{!reqUser ?
Sign up (or use a Guest Account) to save your progress and get access to more features. @@ -65,10 +64,10 @@ export default function SuggestedPanel({ chapter, collection, level, reqUser }: {level.name} is the last level in {collection.name}.
} - {chapter && !isNaN(Number(chapter)) ? + {chapter !== undefined && lastLevelInCollection ?
- +
: diff --git a/components/modal/postGameModal.tsx b/components/modal/postGameModal.tsx index 805edabc4..5c8c73e52 100644 --- a/components/modal/postGameModal.tsx +++ b/components/modal/postGameModal.tsx @@ -5,13 +5,28 @@ import Level, { EnrichedLevel } from '@root/models/db/level'; import User from '@root/models/db/user'; import Link from 'next/link'; import React, { useEffect, useState } from 'react'; +<<<<<<< HEAD +<<<<<<< HEAD import Card from '../cards/card'; import ChapterSelectCard from '../cards/chapterSelectCard'; +======= +>>>>>>> 58800b84 (post level modal and tooltips (#1000)) +======= +import Card from '../cards/card'; +import ChapterSelectCard from '../cards/chapterSelectCard'; +>>>>>>> f1dd274f (postgamemodal improvements) import RecommendedLevel from '../homepage/recommendedLevel'; import Modal from '.'; interface PostGameModalProps { +<<<<<<< HEAD +<<<<<<< HEAD + chapter?: string; +======= +>>>>>>> 58800b84 (post level modal and tooltips (#1000)) +======= chapter?: string; +>>>>>>> f1dd274f (postgamemodal improvements) closeModal: () => void; collection?: Collection; isOpen: boolean; @@ -19,17 +34,36 @@ interface PostGameModalProps { reqUser: User | null; } +<<<<<<< HEAD +<<<<<<< HEAD export default function PostGameModal({ chapter, closeModal, collection, isOpen, level, reqUser }: PostGameModalProps) { let nextLevel: EnrichedLevel | undefined = undefined; let lastLevelInCollection = false; +======= +export default function PostGameModal({ closeModal, collection, isOpen, level, reqUser }: PostGameModalProps) { + let nextLevel: EnrichedLevel | undefined = undefined; +>>>>>>> 58800b84 (post level modal and tooltips (#1000)) +======= +export default function PostGameModal({ chapter, closeModal, collection, isOpen, level, reqUser }: PostGameModalProps) { + let nextLevel: EnrichedLevel | undefined = undefined; + let lastLevelInCollection = false; +>>>>>>> f1dd274f (postgamemodal improvements) if (collection && collection.levels) { const levelIndex = collection.levels.findIndex((l) => l._id === level._id); if (levelIndex + 1 < collection.levels.length) { nextLevel = collection.levels[levelIndex + 1] as EnrichedLevel; +<<<<<<< HEAD +<<<<<<< HEAD + } else { + lastLevelInCollection = true; +======= +>>>>>>> 58800b84 (post level modal and tooltips (#1000)) +======= } else { lastLevelInCollection = true; +>>>>>>> f1dd274f (postgamemodal improvements) } } @@ -42,7 +76,17 @@ export default function PostGameModal({ chapter, closeModal, collection, isOpen, // this is ok for now because query params are currently never expected // to change when going between two level pages useEffect(() => { +<<<<<<< HEAD +<<<<<<< HEAD + setQueryParams(new URLSearchParams(window.location.search)); +======= + const queryParameters = new URLSearchParams(window.location.search); + + setQueryParams(queryParameters); +>>>>>>> 58800b84 (post level modal and tooltips (#1000)) +======= setQueryParams(new URLSearchParams(window.location.search)); +>>>>>>> f1dd274f (postgamemodal improvements) }, []); const hrefOverride = nextLevel ? `/level/${nextLevel.slug}?${queryParams}` : undefined; @@ -63,7 +107,53 @@ export default function PostGameModal({ chapter, closeModal, collection, isOpen, } >
+<<<<<<< HEAD +<<<<<<< HEAD + {!reqUser ? +
+ Sign up (or use a Guest Account) to save your progress and get access to more features. +
+ : + <> + {lastLevelInCollection && collection && +
+ {level.name} is the last level in {collection.name}. +
+ } + {chapter && !isNaN(Number(chapter)) ? + +
+ +
+
+ : + + } + + } + +======= + {reqUser ? + <> + + + + : +======= {!reqUser ? +>>>>>>> f1dd274f (postgamemodal improvements)
Sign up (or use a Guest Account) to save your progress and get access to more features.
@@ -91,7 +181,11 @@ export default function PostGameModal({ chapter, closeModal, collection, isOpen, } } +<<<<<<< HEAD +>>>>>>> 58800b84 (post level modal and tooltips (#1000)) +======= +>>>>>>> f1dd274f (postgamemodal improvements)
); diff --git a/components/page/didYouKnowTip.tsx b/components/page/didYouKnowTip.tsx index 28818bbfc..5ac31a573 100644 --- a/components/page/didYouKnowTip.tsx +++ b/components/page/didYouKnowTip.tsx @@ -2,32 +2,69 @@ import User from '@root/models/db/user'; import Link from 'next/link'; import React, { useRef } from 'react'; +<<<<<<< HEAD +<<<<<<< HEAD interface DidYouKnowTipProps { reqUser: User | undefined | null; } export default function DidYouKnowTip({ reqUser }: DidYouKnowTipProps) { +======= +export default function DidYouKnowTip({ reqUser }: { reqUser: User }) { +>>>>>>> 58800b84 (post level modal and tooltips (#1000)) +======= +interface DidYouKnowTipProps { + reqUser: User | null; +} + +export default function DidYouKnowTip({ reqUser }: DidYouKnowTipProps) { +>>>>>>> f1dd274f (postgamemodal improvements) const tips = [ <>Every level in Pathology was created in the level editor! You can start building here., <>Use advanced search to find levels that suit your taste., <>Compete in real-time multiplayer. Race to solve puzzles against others!, +<<<<<<< HEAD +<<<<<<< HEAD + <>Join our active Discord to connect with other players and level creators., +======= + <>See your earned and potential achievements., + <>Create collections of levels, like your favorites, here., + <>Join our active Discord to connect with other players and level creators., + <>You can customize your profile picture, bio, and more on your profile., +>>>>>>> 58800b84 (post level modal and tooltips (#1000)) +======= <>Join our active Discord to connect with other players and level creators., +>>>>>>> f1dd274f (postgamemodal improvements) <>Every level in the game has a review rating. Learn how these are calculated here., <>Level difficulties are calculated automatically! Learn more about it here., <>Pathology has a long history and its own lingo / terminology (pipes, locks, etc...). You learn about them in the Pathology glossary., <>We have an iOS and Android app! Check it out: iOS and Android., <>Follow level creators by clicking their username to visit their profile., <>Go Pro for features like Checkpoints, Redo, and community time comparisons. Learn more., +<<<<<<< HEAD +<<<<<<< HEAD +======= +>>>>>>> 1e224fc7 (login link for some tips) <>You can customize your notification preferences in your notifications settings., <>See your earned and potential achievements., <>Create collections of levels, like your favorites, here., <>You can customize your profile picture, bio, and more on your profile., +<<<<<<< HEAD +======= + <>You can customize your notification preferences in your notifications settings. +>>>>>>> 58800b84 (post level modal and tooltips (#1000)) +======= +>>>>>>> 1e224fc7 (login link for some tips) ] as JSX.Element[]; const randomTip = useRef(tips[Math.floor(Math.random() * tips.length)]); return ( +<<<<<<< HEAD +
+=======
+>>>>>>> 58800b84 (post level modal and tooltips (#1000))

Did You Know?

{randomTip.current}
diff --git a/components/settings/settingsPro.tsx b/components/settings/settingsPro.tsx index 9b40be333..e8e138a02 100644 --- a/components/settings/settingsPro.tsx +++ b/components/settings/settingsPro.tsx @@ -174,7 +174,15 @@ export default function SettingsPro({ stripeCustomerPortalLink, stripePaymentLin title='Play History' /> >>>>>> 8ac2e750 (Playhistory (#988)) +======= + description='Details on levels solved per user and per creator' +>>>>>>> 7fe3d9c4 (solved and completed terminology (#994)) icon={ diff --git a/contexts/levelContext.ts b/contexts/levelContext.ts index cbc2bfb1a..bbae7468a 100644 --- a/contexts/levelContext.ts +++ b/contexts/levelContext.ts @@ -1,3 +1,4 @@ +import Collection from '@root/models/db/collection'; import { createContext } from 'react'; import { KeyedMutator } from 'swr'; import ProStatsLevelType from '../constants/proStatsLevelType'; @@ -45,6 +46,8 @@ export interface ProStatsCommunityStepData { } interface LevelContextInterface { + chapter: number | undefined; + collection: Collection | undefined; getReviews: () => void; inCampaign: boolean; // true means you are playing an unbeaten level in the campaign level: EnrichedLevel; diff --git a/helpers/generateLevelCanvas.ts b/helpers/generateLevelCanvas.ts index da9b1bed1..7fa5fa3c7 100644 --- a/helpers/generateLevelCanvas.ts +++ b/helpers/generateLevelCanvas.ts @@ -1,6 +1,6 @@ import TileType, { TileTypeDefaultVisited } from '@root/constants/tileType'; import TileTypeHelper from '@root/helpers/tileTypeHelper'; -import { Bitmap } from 'pureimage/types/bitmap'; +import { Bitmap } from 'pureimage'; /* istanbul ignore next */ export default function generateLevelCanvas(canvas: Bitmap | HTMLCanvasElement, levelData: string) { diff --git a/helpers/getPngDataServer.ts b/helpers/getPngDataServer.ts index 9d7c8eb9b..c4db2c435 100644 --- a/helpers/getPngDataServer.ts +++ b/helpers/getPngDataServer.ts @@ -1,5 +1,4 @@ import * as PImage from 'pureimage'; -import { Bitmap } from 'pureimage/types/bitmap'; import { PassThrough } from 'stream'; import Dimensions from '../constants/dimensions'; import Level from '../models/db/level'; @@ -8,7 +7,7 @@ import generateLevelCanvas from './generateLevelCanvas'; export default async function getPngDataServer(level: Level): Promise { let canvas = PImage.make(Dimensions.LevelCanvasWidth, Dimensions.LevelCanvasHeight, {}); - canvas = generateLevelCanvas(canvas, level.data) as Bitmap; + canvas = generateLevelCanvas(canvas, level.data) as PImage.Bitmap; const stream = new PassThrough(); const chunks: Uint8Array[] = []; diff --git a/package-lock.json b/package-lock.json index e460f17e1..bbd451cbd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,7 +34,7 @@ "nextjs-google-analytics": "^2.3.3", "nodemailer": "^6.9.5", "nprogress": "^0.2.0", - "pureimage": "^0.3.17", + "pureimage": "^0.4.9", "react": "^18.2.0", "react-cookie-consent": "^8.0.1", "react-data-table-component-sspenst": "^1.0.0", @@ -14903,11 +14903,11 @@ } }, "node_modules/pngjs": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", - "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz", + "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==", "engines": { - "node": ">=4.0.0" + "node": ">=14.19.0" } }, "node_modules/popper.js": { @@ -15435,16 +15435,16 @@ ] }, "node_modules/pureimage": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/pureimage/-/pureimage-0.3.17.tgz", - "integrity": "sha512-JV4hfYF1BXxDwbSR8hjhVEhVTxwmAXos8uIXQ7Bw2eWrUEpLDJnQoQ8WLlWAO4TMGJ7mp9n6gvLKJ6MSaGUkXQ==", + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/pureimage/-/pureimage-0.4.9.tgz", + "integrity": "sha512-F/mu18taDwpg3dfc+cwYAjWr1kpAic3L4tBiITkbLBjCYv0AXOWHR5jshFwTDhSlPliGmb33uATZWM1Y6H1IsQ==", "dependencies": { - "jpeg-js": "^0.4.1", + "jpeg-js": "^0.4.4", "opentype.js": "^0.4.3", - "pngjs": "^3.3.1" + "pngjs": "^7.0.0" }, "engines": { - "node": ">=0.8" + "node": ">=14.19.0" } }, "node_modules/qs": { diff --git a/package.json b/package.json index f764870c7..8329c68ca 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "nextjs-google-analytics": "^2.3.3", "nodemailer": "^6.9.5", "nprogress": "^0.2.0", - "pureimage": "^0.3.17", + "pureimage": "^0.4.9", "react": "^18.2.0", "react-cookie-consent": "^8.0.1", "react-data-table-component-sspenst": "^1.0.0", diff --git a/pages/campaigns/index.tsx b/pages/campaigns/index.tsx index ccf1d6b12..fe0c81c7c 100644 --- a/pages/campaigns/index.tsx +++ b/pages/campaigns/index.tsx @@ -1,18 +1,51 @@ +<<<<<<< HEAD +<<<<<<< HEAD import TestId from '@root/constants/testId'; +<<<<<<< HEAD +======= +======= +import TestId from '@root/constants/testId'; +>>>>>>> 22934e8a (fix test) +import { LEVEL_DEFAULT_PROJECTION } from '@root/models/schemas/levelSchema'; +>>>>>>> 3fdf9373 (/campaign perf. From ~1.1s load to about 200ms) +======= +>>>>>>> 58c811b0 (cleanup) import { PipelineStage, Types } from 'mongoose'; import { GetServerSidePropsContext, NextApiRequest } from 'next'; import Image from 'next/image'; import React, { useCallback } from 'react'; import SelectCard from '../../components/cards/selectCard'; import Page from '../../components/page/page'; +<<<<<<< HEAD +<<<<<<< HEAD +import dbConnect from '../../lib/dbConnect'; +import { getUserFromToken } from '../../lib/withAuth'; +import { EnrichedCampaign } from '../../models/db/campaign'; +======= +import { enrichCampaign, getEnrichLevelsPipelineSteps } from '../../helpers/enrich'; +import { logger } from '../../helpers/logger'; +import dbConnect from '../../lib/dbConnect'; +import { getUserFromToken } from '../../lib/withAuth'; +import Campaign, { EnrichedCampaign } from '../../models/db/campaign'; +>>>>>>> 3fdf9373 (/campaign perf. From ~1.1s load to about 200ms) +======= import dbConnect from '../../lib/dbConnect'; import { getUserFromToken } from '../../lib/withAuth'; import { EnrichedCampaign } from '../../models/db/campaign'; +>>>>>>> 58c811b0 (cleanup) import { CampaignModel, CollectionModel, LevelModel, StatModel } from '../../models/mongoose'; import SelectOption from '../../models/selectOption'; import SelectOptionStats from '../../models/selectOptionStats'; +<<<<<<< HEAD +<<<<<<< HEAD const campaignInfos: CampaignInfo[] = process.env.NODE_ENV !== 'test' ? [ +======= +const campaignInfos: CampaignInfo[] = [ +>>>>>>> 3fdf9373 (/campaign perf. From ~1.1s load to about 200ms) +======= +const campaignInfos: CampaignInfo[] = process.env.NODE_ENV !== 'test' ? [ +>>>>>>> 22934e8a (fix test) { alt: 'Psychopath', author: 'k2xl', @@ -46,7 +79,20 @@ const campaignInfos: CampaignInfo[] = process.env.NODE_ENV !== 'test' ? [ image: '/pathos.png', year: 2017, }, +<<<<<<< HEAD +<<<<<<< HEAD +<<<<<<< HEAD +] : [{ id: TestId.CAMPAIGN_OFFICIAL } as CampaignInfo]; +======= +======= +] : [ + { id: TestId.CAMPAIGN_OFFICIAL } as CampaignInfo +>>>>>>> 22934e8a (fix test) +]; +>>>>>>> 3fdf9373 (/campaign perf. From ~1.1s load to about 200ms) +======= ] : [{ id: TestId.CAMPAIGN_OFFICIAL } as CampaignInfo]; +>>>>>>> 58c811b0 (cleanup) export async function getServerSideProps(context: GetServerSidePropsContext) { await dbConnect(); @@ -54,6 +100,13 @@ export async function getServerSideProps(context: GetServerSidePropsContext) { const token = context.req?.cookies?.token; const reqUser = token ? await getUserFromToken(token, context.req as NextApiRequest) : null; +<<<<<<< HEAD +<<<<<<< HEAD +======= + // aggegate version +>>>>>>> 3fdf9373 (/campaign perf. From ~1.1s load to about 200ms) +======= +>>>>>>> 58c811b0 (cleanup) const campaignsAgg = await CampaignModel.aggregate([ { $match: { @@ -173,6 +226,13 @@ export async function getServerSideProps(context: GetServerSidePropsContext) { }, { $unset: 'collections.levels' +<<<<<<< HEAD +<<<<<<< HEAD +======= + +>>>>>>> 3fdf9373 (/campaign perf. From ~1.1s load to about 200ms) +======= +>>>>>>> 58c811b0 (cleanup) }, { $project: { @@ -183,7 +243,17 @@ export async function getServerSideProps(context: GetServerSidePropsContext) { levelCount: 1, userSolvedCount: 1 } +<<<<<<< HEAD +<<<<<<< HEAD + }, +======= + } + // now we need to sum all of the stats.complete from the collections.levels.stats + +>>>>>>> 3fdf9373 (/campaign perf. From ~1.1s load to about 200ms) +======= }, +>>>>>>> 58c811b0 (cleanup) ] as PipelineStage[]); return { diff --git a/pages/index.tsx b/pages/index.tsx index 88c80430a..418a9d3bd 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -65,14 +65,33 @@ function App() { />
+<<<<<<< HEAD +<<<<<<< HEAD +======= +>>>>>>> 8ac2e750 (Playhistory (#988)) {levelOfDay && } +======= + +>>>>>>> 7060c231 (homepage tweaks) +======= + title='Level of the Day 🗓️' +======= + title='Level of the Day' +>>>>>>> f1dd274f (postgamemodal improvements) + tooltip={'Every day there is a new level of the day. Difficulty increases throughout the week!'} + /> + } +>>>>>>> 8ac2e750 (Playhistory (#988))
diff --git a/pages/level/[username]/[slugName].tsx b/pages/level/[username]/[slugName].tsx index 4ae71ed84..0dd3ef3a4 100644 --- a/pages/level/[username]/[slugName].tsx +++ b/pages/level/[username]/[slugName].tsx @@ -66,6 +66,7 @@ export default function LevelPage({ _level, reqUser }: LevelProps) { // handle pressing "Next level" useEffect(() => { setLevel(_level); + setSidebarIndex(0); }, [_level]); const mutateLevel = useCallback(() => { @@ -218,6 +219,8 @@ export default function LevelPage({ _level, reqUser }: LevelProps) { }} /> +<<<<<<< HEAD +<<<<<<< HEAD {chapterUnlocked >= 3 && } +======= +>>>>>>> c883f344 (`/home` tweaks (#1001)) +======= + {chapterUnlocked >= 3 && } +>>>>>>> dc89605e (ch4 preview (#1006))
diff --git a/types/pureimage.d.ts b/types/pureimage.d.ts new file mode 100644 index 000000000..041e6d28c --- /dev/null +++ b/types/pureimage.d.ts @@ -0,0 +1,122 @@ +declare module 'pureimage' { + // ###### + // https://github.com/joshmarinacci/node-pureimage/blob/master/src/image.ts + + export function make(w: number, h: number, options?: unknown): Bitmap; + + export type PNGOptions = { + deflateLevel?: number, + deflateStrategy?: number, + } + + /** Encode the PNG image to output stream */ + export function encodePNGToStream( + /** An instance of {@link Bitmap} to be encoded to PNG, `bitmap.data` must be a buffer of raw PNG data */ + bitmap: Bitmap, + /** The stream to write the PNG file to */ + outstream: WriteStream, + options: PNGOptions = {} + ): Promise; + + // ###### + // https://github.com/joshmarinacci/node-pureimage/blob/master/src/bitmap.ts + + export class Bitmap { + public width: number; + public height: number; + public data: Uint8Array; + private _context: Context; + + /** + * Creates an instance of Bitmap. + * @param {number} w Width + * @param {number} h Height + * @param {any} options Currently unused + * @memberof Bitmap + */ + constructor(w: number, h: number, options?); + + /** Calculate Index */ + calculateIndex( + /** X position */ + x: number, + /** Y position */ + y: number + ); + + /** Set the RGBA(Red, Green, Blue, Alpha) values on an individual pixel level */ + setPixelRGBA( + /** X axis position */ + x: number, + /** Y axis position */ + y: number, + /** A hex representation of the RGBA value of the pixel. See {@link NAMED_COLORS} for examples */ + rgba: number + ); + + /** Set the individual red, green, blue and alpha levels of an individual pixel */ + setPixelRGBA_i( + /** X axis position */ + x: number, + /** Y axis position */ + y: number, + /** Red level */ + r: number, + /** Green level */ + g: number, + /** Blue level */ + b: number, + /** Alpha level */ + a: number + ); + + /** Get the RGBA value of an individual pixel as a hexadecimal number(See {@link NAMED_COLORS} for examples) */ + getPixelRGBA( + /** X axis position */ + x: number, + /** Y axis position */ + y: number + ); + + getDebugPixelRGBA( + /** X axis position */ + x: number, + /** Y axis position */ + y: number + ); + + /** + * Get Pixel RGBA Separate + * + * @ignore + */ + getPixelRGBA_separate( + /** X axis position */ + x: number, + /** Y axis position */ + y: number + ); + + /** + * {@link Context} factory. Creates a new {@link Context} instance object for the current bitmap object + */ + getContext(type: string); + + _copySubBitmap( + x: number, + y: number, + w: number, + h: number + ); + + _pasteSubBitmap( + src: Bitmap, + x: number, + y: number + ); + + _isValidCoords(x, y); + + validate_coords(x, y); + } +}