Skip to content

Commit

Permalink
Merge pull request #40 from BobDotCom/react
Browse files Browse the repository at this point in the history
React Rewrite
  • Loading branch information
MaximilianAdF authored Apr 11, 2024
2 parents 763f0db + 0bc2a6d commit f89cb4d
Show file tree
Hide file tree
Showing 87 changed files with 7,903 additions and 621 deletions.
3 changes: 3 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}
42 changes: 42 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts


### JetBrains IDEs

# Shared project, keep config private
.idea/
36 changes: 36 additions & 0 deletions README-nextjs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).

## Getting Started

First, run the development server:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.

This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!

## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
72 changes: 72 additions & 0 deletions app/components/NPButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import {ReactNode} from "react";

import React, { MouseEventHandler } from 'react';
import Link from 'next/link';
import classNames from "classnames";

interface NPButtonProps {
label?: string;
type?: 'outlined' | 'filled';
color?: 'purple' | 'green';
icon?: React.ReactElement | string;
href?: string;
disabled?: boolean;
onClick?: (() => MouseEventHandler | void);
children?: string;
}

const NPButton: React.FC<NPButtonProps> = ({
type,
color,
label,
icon,
href,
disabled,
onClick,
children
}) => {

const props = {
title: label || children?.toString(),
className: classNames(
`
rounded-lg
px-4 py-2
text-xl
font-medium
transition-colors
duration-100
ease-in-out
disabled:opacity-50
`,
color === "purple" ? "bg-vivid-violet-600/25 text-vivid-violet-600 enabled:hover:bg-vivid-violet-600/50" :
color === "green" ? "bg-turquoise-400/25 text-turquoise-400 enabled:hover:bg-turquoise-400/50" : "",
),
'aria-label': label || children?.toString(),
disabled: disabled,
onClick: onClick
};

const childrenElements = (
<>
{ icon && icon }
{ children && children }
</>
);

if (!href) {
return (
<button {...props}>
{ childrenElements }
</button>
);
} else {
return (
<Link href={ href } {...props}>
{ childrenElements }
</Link>
);
}
}

export default NPButton;
239 changes: 239 additions & 0 deletions app/components/NPHackContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
import React, {FC, ReactNode, useEffect, useState} from "react";
import NPButton from "@/app/components/NPButton";
import classNames from "classnames";
import {useCountdown} from "@/app/utils/useCountdown";
import useTimeout from "@/app/utils/useTimeout";
import NPSettings from "@/app/components/NPSettings";
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import {faGear} from "@fortawesome/free-solid-svg-icons";

interface NPHackContainerButton {
label: string,
color: "purple" | "green",
callback?: () => void, // TODO: Make callback non-optional
disabled: boolean,
}

interface NPHackContainerSettings {
handleSave: () => void,
handleReset: () => void,
children: ReactNode,
}

interface NPHackContainerProps {
children: ReactNode,
title: string,
description?: string,
buttons: NPHackContainerButton[][],
countdownDuration: number,
resetCallback: () => void,
resetDelay: number,
// frameSpeed: number,
status: number,
setStatus: (status: number) => void,
statusMessage: string,
settings?: NPHackContainerSettings,

// props: {[key: string]: any},
className?: string,
}

const NPHackContainer: FC<NPHackContainerProps> = ({
children,
title,
description,
buttons,
countdownDuration,
resetCallback,
resetDelay,
// frameSpeed,
status,
setStatus,
statusMessage,
settings,
...props
}) => {
// This can be decreased if you need to call a func every frame
// For now, 1s per frame seems reasonable

const frameSpeed = 1000;

const resetTimeout = useTimeout(() => {
resetCallback();
resetCountdown();
}, resetDelay);

useEffect(() => {
if (status !== 1 && status !== 0) {
resetTimeout();
}
}, [resetTimeout, status]);

const timerReset = () => {
setStatus(2);
}

const [countdown, resetCountdown, freezeCountdown] = useCountdown(timerReset, countdownDuration, frameSpeed);

useEffect(() => {
if (status !== 1 && status !== 0) {
freezeCountdown();
}
}, [freezeCountdown, status]);

const calculateTimerBar = () => {
let width = 100
if (status === 1) {
// Only move the timer if the game is running
width -= countdown;
// We want to anticipate the next tick so the transition will start instantly
width -= Math.max(Math.min(frameSpeed/countdownDuration,1),0) * 100;
// And clamp that between 0-100
width = Math.max(Math.min(width, 100),0);
}
return width;
}


const [settingsVisible, setSettingsVisible] = useState(false);


return (
<>
{settings && <NPSettings
handleReset={settings.handleReset}
handleSave={settings.handleSave}
visible={settingsVisible}
setVisible={setSettingsVisible}
>
{settings.children}
</NPSettings>}
<div className={classNames(
`
max-h-full max-w-full
rounded-lg
overflow-hidden
`,
props.className
)}>
<div className="
max-h-full max-w-full
relative
p-3
flex flex-col justify-center
bg-[rgb(7_19_32)]
">
{/* Header */}
<div className="
mb-5
h-10
flex justify-between items-center
">
<div className="
flex items-center
gap-4
">
<embed className="w-8 sm:w-10" src="/gamePad.svg"/>
<h2 className="
text-lg
sm:text-2xl
text-spring-green-300
[text-shadow:0_0_40px_rgb(127_255_191)]
">{/*Originally, text shadow was 2.1px, but it looks much bigger on nopixel*/}
{title}
</h2>
<p className="
text-xs
sm:text-base
text-[rgb(142_142_142)]">
{description}
</p>
</div>
{settings && <div className="h-full aspect-square justify-center items-center flex p-1">
<FontAwesomeIcon
icon={faGear}
className="
size-full
text-gray-500
hover:rotate-90 hover:scale-110 hover:cursor-pointer
transition-transform
"
onClick={() => setSettingsVisible(true)}
title={"Open Settings"}
/>
</div>}
</div>
{status !== undefined && <div className={classNames(
`
gap-2.5
absolute
right-2.5
top-2.5
text-white
px-4 py-2
rounded
flex items-center justify-center
`,
status === 2 ? "bg-[rgb(56_13_23)]" :
status === 3 ? "bg-[rgb(23_95_88)]" :
status === 4 ? "bg-[rgb(118_128_37)]" : "hidden"
)}>
{/* TODO: Refactor icons, they're completely broken */}
{/*{status === 2 && <i className="fa-solid text-2xl fa-circle-xmark text-[rgb(255_84_84)]"></i>}*/}
{/*{status === 3 && <i className="fa-solid text-2xl fa-circle-check text-[rgb(84_255_164)]"></i>}*/}
{/*{status === 0 && <i className="fa-solid text-2xl fa-hourglass-start text-[rgb(118_128_37)]"></i>}*/}

{/*<i className={classNames(*/}
{/* "fa-solid text-2xl",*/}
{/* status === 2 ? "fa-circle-xmark text-[rgb(255_84_84)]" :*/}
{/* status === 3 ? "fa-circle-check text-[rgb(84_255_164)]" :*/}
{/* status === 0 ? "fa-hourglass-start text-[rgb(118_128_37)]" : "hidden" // TODO: Fix reset icon*/}
{/*)}></i>*/}
<p className="text-xs font-medium">{statusMessage}</p>
</div>}
{/* Main puzzle */}
<div className="w-full pb-2 flex-1">
{children}
</div>
{/* Buttons */}
<div className="flex flex-col w-full gap-1">
{buttons.map((buttonRow, index) => {
return (
<div className="flex gap-1 *:flex-1" key={index}>
{buttonRow.map((button, index) => {
return (
<NPButton
onClick={button.callback}
color={button.color}
key={index}
disabled={button.disabled}
>
{button.label}
</NPButton>
);
})}
</div>
);
})}
</div>
</div>
{/* Timer bar */}
{/* TODO: Check BG color, before react rewrite was rgb(36 47 59)*/}
<div className="bg-[rgb(15_27_33)] flex w-full h-2.5">
<div
className={classNames(
"bg-[orangered] w-full h-full [transition:width_linear]",
)}
style={{
transitionDuration: status !== 1 ? "0ms" : `${frameSpeed}ms`,
// transitionTimingFunction: "cubic-bezier(0.4, 1, 0.7, 0.93)",
width: `${calculateTimerBar()}%`,
}}
></div>
</div>
</div>
</>
);
}

export default NPHackContainer;
Loading

0 comments on commit f89cb4d

Please # to comment.