Skip to content

Commit

Permalink
Draft popups
Browse files Browse the repository at this point in the history
  • Loading branch information
frammiie committed Nov 19, 2023
1 parent 3cf6334 commit 0a5fedb
Show file tree
Hide file tree
Showing 17 changed files with 509 additions and 172 deletions.
2 changes: 1 addition & 1 deletion src/FuyoClicker.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
background-attachment: fixed;
animation: 120s slide infinite linear;

& > * {
& > *:not(.popups) {
overflow: hidden;
width: 25rem;
display: flex;
Expand Down
26 changes: 15 additions & 11 deletions src/FuyoClicker.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { useEffect } from "react";
import { DndContext } from "@dnd-kit/core";
import { Lanes } from "@/components/lanes";
import { News } from "@/components/news";
import { Reproduction } from "@/components/reproduction";
import { Shop } from "@/components/shop";
import { State, useGameStore } from "@/stores/game";
import { Clicker } from "@/components/clicker";
import { Divider, Orientation } from "@/components/divider";
import { Species } from "@/components/species";
import { Popups } from "@/components/popups";
import { usePopupsRefs } from "@/components/popups/usePopupsRefs";

import classes from "./FuyoClicker.module.css";
import { Lanes } from "./components/lanes";
import { News } from "./components/news";
import { Reproduction } from "./components/reproduction";
import { Shop } from "./components/shop";
import { State, useGameStore } from "./stores/game";
import { Clicker } from "./components/clicker";
import { Divider, Orientation } from "./components/divider";
import { Species } from "./components/species";

/** Determines the frequency of updates of the game state. */
const TICK_MS = 1000;
Expand All @@ -20,6 +22,7 @@ const TICK_MS = 1000;
export function FuyoClicker() {
const tick = useGameStore(state => state.tick);
const state = useGameStore(state => state.state);
const refs = usePopupsRefs();

useEffect(() => {
if (state === State.PAUSED) return;
Expand All @@ -31,7 +34,7 @@ export function FuyoClicker() {

return (
<div className={classes["fuyo-clicker"]}>
<Clicker className={classes.left} />
<Clicker ref={refs.clicker} className={classes.left} />
<DndContext>
<div className={classes.middle}>
<Divider />
Expand All @@ -43,12 +46,13 @@ export function FuyoClicker() {
<Divider />
</div>
<div className={classes.right}>
<Reproduction />
<Reproduction ref={refs.repro} />
<Divider orientation={Orientation.HORIZONTAL} />
<Shop />
<Shop ref={refs.shop} />
</div>
</DndContext>
<Species />
<Popups className={classes.popups} refs={refs} />
</div>
);
}
Binary file added src/assets/images/ending.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
75 changes: 41 additions & 34 deletions src/components/clicker/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { HTMLProps, useMemo } from "react";
import { HTMLProps, forwardRef, useMemo } from "react";
import { Stage, Container } from "@pixi/react";
import { BlurFilter } from "pixi.js";
import cx from "classix";
Expand All @@ -14,38 +14,45 @@ import { Fuyonade } from "./boosts";
import { Hands } from "./hands";
import classes from "./index.module.css";

export function Clicker(props: HTMLProps<HTMLDivElement>) {
const [elementRef, size] = useElementSize();
const quality = useSettingsStore(settings => settings.quality);
export const Clicker = forwardRef<HTMLDivElement, HTMLProps<HTMLDivElement>>(
function Clicker(props, ref) {
const [elementRef, size] = useElementSize();

// [FIXME] Workound https://github.com/pixijs/pixi-react/issues/456
useMemo(() => new BlurFilter(0), []);
const quality = useSettingsStore(settings => settings.quality);

return (
<div
{...props}
className={cx(classes.clicker, props.className)}
ref={elementRef}
>
<Fuyonade />
<Header />
{size.width + size.height !== 0 && (
<Stage
width={size.width}
height={size.height}
options={{
backgroundAlpha: 0,
autoDensity: true,
}}
className={classes.stage}
>
{quality <= Quality.Medium && <Backdrop size={size} />}
<Container x={size.width / 2} y={size.height / 2}>
<Hands />
<Coin />
</Container>
</Stage>
)}
</div>
);
}
// [FIXME] Workound https://github.com/pixijs/pixi-react/issues/456
useMemo(() => new BlurFilter(0), []);

return (
<div
{...props}
ref={(element: HTMLDivElement) => {
elementRef(element);
// @ts-expect-error ref typing
ref.current = element;
}}
className={cx(classes.clicker, props.className)}
>
<Fuyonade />
<Header />
{size.width + size.height !== 0 && (
<Stage
width={size.width}
height={size.height}
options={{
backgroundAlpha: 0,
autoDensity: true,
}}
className={classes.stage}
>
{quality <= Quality.Medium && <Backdrop size={size} />}
<Container x={size.width / 2} y={size.height / 2}>
<Hands />
<Coin />
</Container>
</Stage>
)}
</div>
);
}
);
84 changes: 59 additions & 25 deletions src/components/dialog/index.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,67 @@
import { HTMLProps, forwardRef, useImperativeHandle, useRef } from "react";
import {
DialogHTMLAttributes,
MutableRefObject,
forwardRef,
useEffect,
useImperativeHandle,
useRef,
useState,
} from "react";
import cx from "classix";

import { Button } from "../button";

import classes from "./index.module.css";

export const Dialog = forwardRef<
HTMLDialogElement,
HTMLProps<HTMLDialogElement>
>(function Dialog(
{ children, ...props }: HTMLProps<HTMLDialogElement>,
outerRef
) {
const ref = useRef<HTMLDialogElement | null>(null);
useImperativeHandle(outerRef, () => ref.current!);
export interface DialogProps extends DialogHTMLAttributes<HTMLDialogElement> {
closeable?: boolean;
}

return (
<dialog
ref={ref}
{...props}
className={cx(classes.dialog, props.className)}
>
<Button
className={classes.close}
onClick={() => ref.current?.close()}
export const Dialog = forwardRef<HTMLDialogElement, DialogProps>(
function Dialog({ closeable = true, children, ...props }, outerRef) {
const ref = useRef<HTMLDialogElement | null>(null);
useImperativeHandle(outerRef, () => ref.current!);

const mutRef = ref as MutableRefObject<HTMLDialogElement>;
const [open, setOpen] = useState(false);

/**
* Control open state by using `showModal` and `close` methods due to
* preferred behavior versus manipulating the `open` attribute directly.
*/
useEffect(() => {
if (props.open && !open) {
mutRef.current.showModal();
setOpen(true);
} else if (!props.open && open) {
mutRef.current.close();
setOpen(false);
}
}, [mutRef, props.open, open]);

return (
<dialog
ref={ref}
{...props}
open={open}
className={cx(classes.dialog, props.className)}
onCancel={e => {
if (!closeable) e.preventDefault();
props.onCancel?.(e);
}}
>
</Button>
{children}
</dialog>
);
});
{closeable && (
<Button
className={classes.close}
onClick={() => {
mutRef.current.close();
}}
>
</Button>
)}
{children}
</dialog>
);
}
);
2 changes: 1 addition & 1 deletion src/components/news/settings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export function Settings() {
<h1>Settings</h1>
<Quality />
<Audio />
<Saves />
<Saves dialogRef={dialogRef} />
<Debug />
</Dialog>
</>
Expand Down
16 changes: 14 additions & 2 deletions src/components/news/settings/saves/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { Button } from "@/components/button";
import { MutableRefObject } from "react";

import classes from "../index.module.css";

import { useSaves } from "./useSaves";
import { useReset } from "./useReset";

export function Saves() {
export interface SavesProps {
dialogRef: MutableRefObject<HTMLDialogElement | null>;
}

export function Saves({ dialogRef }: SavesProps) {
const { exportSave, loadSave } = useSaves();
const { reset } = useReset();

Expand All @@ -16,7 +21,14 @@ export function Saves() {
<Button onClick={exportSave}>📤 Export Save</Button>
<Button onClick={loadSave}>📩 Load Save</Button>
</div>
<Button onClick={reset}>🛑 Reset Progress</Button>
<Button
onClick={() => {
reset();
dialogRef.current?.close();
}}
>
🛑 Reset Progress
</Button>
</section>
);
}
13 changes: 13 additions & 0 deletions src/components/popups/ending/index.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.ending {
margin-top: auto;
width: 30%;

& > h1 {
margin-bottom: 1rem;
padding: 0 0.5rem;
}

& > a > img {
width: 100%;
}
}
26 changes: 26 additions & 0 deletions src/components/popups/ending/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Dialog } from "@/components/dialog";
import { useGameStore } from "@/stores/game";
import { useState } from "react";
import image from "@/assets/images/ending.png";

import classes from "./index.module.css";

export function Ending() {
const ending = useGameStore(state => state.popups.ending);
const [open, setOpen] = useState<boolean | null>(null);

if (!ending.reached) return;

return (
<Dialog
className={classes.ending}
open={ending.reached ?? open}
onCancel={() => setOpen(false)}
>
<h1>Happy Anniversary Fuyo!</h1>
<a href={image} target="_blank" rel="noreferrer">
<img src={image} />
</a>
</Dialog>
);
}
23 changes: 23 additions & 0 deletions src/components/popups/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { HTMLProps, RefObject } from "react";

import { Tutorial } from "./tutorial";
import { Ending } from "./ending";

export interface PopupsRefs {
clicker: RefObject<HTMLDivElement>;
repro: RefObject<HTMLDivElement>;
shop: RefObject<HTMLDivElement>;
}

export interface PopupsProps extends HTMLProps<HTMLDivElement> {
refs: PopupsRefs;
}

export function Popups({ refs, ...props }: PopupsProps) {
return (
<div {...props}>
<Tutorial refs={refs} />
<Ending />
</div>
);
}
Loading

0 comments on commit 0a5fedb

Please sign in to comment.