mirror of
https://github.com/PretendoNetwork/website.git
synced 2026-08-25 10:06:03 -05:00
feat: typescript!
This commit is contained in:
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/components/*": ["./src/components/*"],
|
||||
"@/utils/*": ["./src/utils/*"],
|
||||
"@/public/*": ["./public/*"],
|
||||
"@/locales/*": ["./locales/*"],
|
||||
"@/app/*": ["./src/app/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
5
next-env.d.ts
vendored
Normal file
5
next-env.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||
@@ -1,4 +1,8 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
// @ts-check
|
||||
|
||||
/**
|
||||
* @type {import('next').NextConfig}
|
||||
**/
|
||||
|
||||
const nextConfig = {
|
||||
reactStrictMode: true,
|
||||
@@ -8,28 +12,28 @@ const nextConfig = {
|
||||
protocol: 'https',
|
||||
hostname: 'github.com',
|
||||
port: '',
|
||||
pathname: '/**'
|
||||
pathname: '/**',
|
||||
},
|
||||
{
|
||||
protocol: 'https',
|
||||
hostname: 'avatars.githubusercontent.com',
|
||||
port: '',
|
||||
pathname: '/u/**'
|
||||
pathname: '/u/**',
|
||||
},
|
||||
{
|
||||
protocol: 'https',
|
||||
hostname: 'github.githubassets.com',
|
||||
port: '',
|
||||
pathname: '/images/**'
|
||||
pathname: '/images/**',
|
||||
},
|
||||
{
|
||||
protocol: 'https',
|
||||
hostname: 'cdn.discordapp.com',
|
||||
port: '',
|
||||
pathname: '/avatars/**'
|
||||
}
|
||||
]
|
||||
}
|
||||
pathname: '/avatars/**',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
||||
59
package-lock.json
generated
59
package-lock.json
generated
@@ -32,6 +32,9 @@
|
||||
"sharp": "^0.32.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"@types/lodash.merge": "^4.6.9",
|
||||
"@types/react": "18.3.3",
|
||||
"eslint-config-next": "^13.4.19"
|
||||
}
|
||||
},
|
||||
@@ -1580,6 +1583,16 @@
|
||||
"@types/ms": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/fs-extra": {
|
||||
"version": "11.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz",
|
||||
"integrity": "sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/jsonfile": "*",
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/http-cache-semantics": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz",
|
||||
@@ -1591,6 +1604,15 @@
|
||||
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/jsonfile": {
|
||||
"version": "6.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.4.tgz",
|
||||
"integrity": "sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/keyv": {
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz",
|
||||
@@ -1599,6 +1621,21 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.5.tgz",
|
||||
"integrity": "sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/lodash.merge": {
|
||||
"version": "4.6.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash.merge/-/lodash.merge-4.6.9.tgz",
|
||||
"integrity": "sha512-23sHDPmzd59kUgWyKGiOMO2Qb9YtqRO/x4IhkgNUiPQ1+5MUVqi6bCZeq9nBJ17msjIMbEIO5u+XW4Kz6aGUhQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/lodash": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/ms": {
|
||||
"version": "0.7.34",
|
||||
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz",
|
||||
@@ -1612,11 +1649,27 @@
|
||||
"undici-types": "~5.26.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/prop-types": {
|
||||
"version": "15.7.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
|
||||
"integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/qs": {
|
||||
"version": "6.9.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz",
|
||||
"integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg=="
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "18.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz",
|
||||
"integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/responselike": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz",
|
||||
@@ -2437,6 +2490,12 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/damerau-levenshtein": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
|
||||
|
||||
@@ -34,6 +34,9 @@
|
||||
"sharp": "^0.32.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"@types/lodash.merge": "^4.6.9",
|
||||
"@types/react": "18.3.3",
|
||||
"eslint-config-next": "^13.4.19"
|
||||
},
|
||||
"browserslist": [
|
||||
|
||||
@@ -11,7 +11,7 @@ const poppins = Poppins({
|
||||
subsets: ['latin'], // this is the preloaded subset, all subsets will be available
|
||||
});
|
||||
|
||||
export default function RootLayout({ children }) {
|
||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html className={`${poppins.variable}`}>
|
||||
<body style={{ paddingTop: '48px' }}>
|
||||
@@ -19,7 +19,7 @@ export default function RootLayout({ children }) {
|
||||
{children}
|
||||
<Footer />
|
||||
<Script
|
||||
strategy="lazyOnLoad"
|
||||
strategy="lazyOnload"
|
||||
src="https://static.cloudflareinsights.com/beacon.min.js"
|
||||
data-cf-beacon='{"token": "ea6695987d664a7f90874c9c0dee9385"}'
|
||||
/>
|
||||
@@ -60,7 +60,6 @@ export const metadata = {
|
||||
card: 'summary_large_image',
|
||||
site: '@PretendoNetwork',
|
||||
creator: '@PretendoNetwork',
|
||||
url: 'https://pretendo.network/',
|
||||
images: ['https://pretendo.network/assets/images/opengraph/opengraph-image.png'],
|
||||
},
|
||||
robots: {
|
||||
@@ -11,7 +11,7 @@ import ShowcaseSection from '@/components/ShowcaseSection/ShowcaseSection';
|
||||
|
||||
import { getLocale } from '@/utils/locale';
|
||||
|
||||
import ImageFix from '@/components/ImageFix/ImageFix';
|
||||
import Image, { StaticImageData } from 'next/image';
|
||||
|
||||
import styles from './page.module.css';
|
||||
|
||||
@@ -20,14 +20,26 @@ import networkImage from '@/public/assets/images/showcase/network.png';
|
||||
import pcmouseImage from '@/public/assets/images/showcase/pcmouse.png';
|
||||
import wiiuchatImage from '@/public/assets/images/showcase/wiiuchat.png';
|
||||
|
||||
const showcaseImages = {
|
||||
interface ShowcaseImages {
|
||||
[key: string]: StaticImageData;
|
||||
}
|
||||
|
||||
const showcaseImages: ShowcaseImages = {
|
||||
juxt: juxtImage,
|
||||
network: networkImage,
|
||||
pcmouse: pcmouseImage,
|
||||
wiiuchat: wiiuchatImage,
|
||||
};
|
||||
|
||||
export default function Home(ctx) {
|
||||
interface TeamMemberObject {
|
||||
special: boolean;
|
||||
name: string;
|
||||
caption: string;
|
||||
picture: string;
|
||||
github: string;
|
||||
}
|
||||
|
||||
export default function Home() {
|
||||
const { locale } = getLocale('TODO');
|
||||
|
||||
return (
|
||||
@@ -42,7 +54,7 @@ export default function Home(ctx) {
|
||||
<Caption>Our project has many components. Here are some of them.</Caption>
|
||||
</Section>
|
||||
|
||||
{locale.showcase.map((el, i) => {
|
||||
{locale.showcase.map((el: { title: string; caption: string; image: string }, i: number) => {
|
||||
return (
|
||||
<ShowcaseSection
|
||||
title={el.title}
|
||||
@@ -55,7 +67,7 @@ export default function Home(ctx) {
|
||||
})}
|
||||
|
||||
<Section className={styles.showcaseTail} contentClassName={styles.content}>
|
||||
<ImageFix
|
||||
<Image
|
||||
src={wiiuchatImage}
|
||||
className={styles.image}
|
||||
alt=""
|
||||
@@ -89,7 +101,7 @@ export default function Home(ctx) {
|
||||
<Caption center>{locale.credits.text}</Caption>
|
||||
|
||||
<div className={styles.teamWrapper}>
|
||||
{locale.credits.people.map((el, i) => {
|
||||
{locale.credits.people.map((el: TeamMemberObject, i: number) => {
|
||||
return (
|
||||
<TeamCard name={el.name} caption={el.caption} pic={el.picture} link={el.github} key={i} />
|
||||
);
|
||||
@@ -108,7 +120,7 @@ export default function Home(ctx) {
|
||||
let ar = locale.specialThanks.people;
|
||||
ar = ar.slice(0, Math.round(ar.length / 2));
|
||||
ar = ar.concat(ar).concat(ar);
|
||||
return ar.map((el, i) => {
|
||||
return ar.map((el: TeamMemberObject, i: number) => {
|
||||
return (
|
||||
<TeamCard
|
||||
compact
|
||||
@@ -118,7 +130,7 @@ export default function Home(ctx) {
|
||||
pic={el.picture}
|
||||
link={el.github}
|
||||
key={i}
|
||||
tabIndex={(Math.round(ar.length / 4) >= i) - 1}
|
||||
tabIndex={Math.round(ar.length / 4) >= i ? 0 : 1}
|
||||
/>
|
||||
);
|
||||
});
|
||||
@@ -130,7 +142,7 @@ export default function Home(ctx) {
|
||||
let ar = locale.specialThanks.people;
|
||||
ar = ar.slice(Math.round(ar.length / 2));
|
||||
ar = ar.concat(ar).concat(ar);
|
||||
return ar.map((el, i) => {
|
||||
return ar.map((el: TeamMemberObject, i: number) => {
|
||||
return (
|
||||
<TeamCard
|
||||
compact
|
||||
@@ -140,7 +152,7 @@ export default function Home(ctx) {
|
||||
pic={el.picture}
|
||||
link={el.github}
|
||||
key={i}
|
||||
tabIndex={(Math.round(ar.length / 4) >= i) - 1}
|
||||
tabIndex={Math.round(ar.length / 4) >= i ? 0 : 1}
|
||||
/>
|
||||
);
|
||||
});
|
||||
@@ -3,6 +3,8 @@
|
||||
import { useState } from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { CSSProperties, MouseEventHandler, AnimationEventHandler } from 'react';
|
||||
|
||||
import styles from './Bandwidth.module.css';
|
||||
|
||||
/**
|
||||
@@ -20,10 +22,24 @@ import styles from './Bandwidth.module.css';
|
||||
*
|
||||
*/
|
||||
|
||||
export default function Bandwidth(ctx) {
|
||||
interface VanillaBandwidthProps {
|
||||
size?: number;
|
||||
className?: string;
|
||||
style?: CSSProperties;
|
||||
onClick?: MouseEventHandler<SVGSVGElement>;
|
||||
onAnimationEnd?: AnimationEventHandler<SVGSVGElement>;
|
||||
}
|
||||
|
||||
interface BandwidthProps extends VanillaBandwidthProps {
|
||||
lines?: Array<string>;
|
||||
alwaysShowBubble?: boolean;
|
||||
alignBubble?: 'left' | 'center' | 'right';
|
||||
}
|
||||
|
||||
export default function Bandwidth(ctx: BandwidthProps) {
|
||||
const { lines = [], size = 192, alwaysShowBubble = false, alignBubble = 'center', className, style } = ctx;
|
||||
|
||||
const [lineIndex, setLineIndex] = useState(-1 + alwaysShowBubble);
|
||||
const [lineIndex, setLineIndex] = useState(-1 + +alwaysShowBubble);
|
||||
const [jump, setJump] = useState(false || alwaysShowBubble);
|
||||
|
||||
const active = lineIndex > -1;
|
||||
@@ -49,7 +65,7 @@ export default function Bandwidth(ctx) {
|
||||
)}
|
||||
<VanillaBandwidth
|
||||
size={size}
|
||||
onClick={updateLine}
|
||||
onClick={() => updateLine()}
|
||||
className={classNames(styles.bandwidth, { [styles.jump]: jump })}
|
||||
onAnimationEnd={() => setJump(false)}
|
||||
/>
|
||||
@@ -70,12 +86,11 @@ export default function Bandwidth(ctx) {
|
||||
*
|
||||
*/
|
||||
|
||||
export const VanillaBandwidth = (ctx) => {
|
||||
export const VanillaBandwidth = (ctx: VanillaBandwidthProps) => {
|
||||
const { size = 192, className, style, onClick, onAnimationEnd } = ctx;
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
alt=""
|
||||
version="1.1"
|
||||
viewBox="0 0 813 813"
|
||||
width={size}
|
||||
@@ -85,6 +100,8 @@ export const VanillaBandwidth = (ctx) => {
|
||||
onClick={onClick}
|
||||
onAnimationEnd={onAnimationEnd}
|
||||
>
|
||||
<title>Bandwidth</title>
|
||||
<desc>A drawing of Bandwidth, a purple raccoon with a brick in one paw and a Gamepad in the other.</desc>
|
||||
<defs>
|
||||
<style>
|
||||
{
|
||||
@@ -2,6 +2,8 @@ import classNames from 'classnames';
|
||||
import CoolHover from '@/components/CoolHover/CoolHover';
|
||||
import styles from './Button.module.css';
|
||||
|
||||
import { ReactNode, MouseEventHandler, CSSProperties } from 'react';
|
||||
|
||||
import Link from 'next/link';
|
||||
|
||||
/**
|
||||
@@ -20,7 +22,19 @@ import Link from 'next/link';
|
||||
*
|
||||
*/
|
||||
|
||||
export default function Button(ctx) {
|
||||
interface ButtonProps {
|
||||
children: ReactNode | string;
|
||||
className?: string;
|
||||
primary?: boolean;
|
||||
icon?: boolean;
|
||||
compact?: boolean;
|
||||
onClick?: MouseEventHandler<HTMLButtonElement>;
|
||||
href?: string;
|
||||
target?: string;
|
||||
style?: CSSProperties;
|
||||
}
|
||||
|
||||
export default function Button(ctx: ButtonProps) {
|
||||
const { children, className, primary, icon, compact, onClick, href, target, style } = ctx;
|
||||
|
||||
const BtnEl = () => {
|
||||
@@ -50,7 +64,7 @@ export default function Button(ctx) {
|
||||
};
|
||||
|
||||
return href ? (
|
||||
<Link href={href} target={target} tabIndex="-1">
|
||||
<Link href={href} target={target} tabIndex={-1}>
|
||||
<BtnEl />
|
||||
</Link>
|
||||
) : (
|
||||
@@ -1,6 +1,8 @@
|
||||
import classNames from 'classnames';
|
||||
import styles from './ButtonWidget.module.css';
|
||||
|
||||
import { ReactNode, MouseEventHandler, CSSProperties } from 'react';
|
||||
|
||||
import Button from '@/components/Button/Button';
|
||||
|
||||
/**
|
||||
@@ -19,8 +21,19 @@ import Button from '@/components/Button/Button';
|
||||
*
|
||||
*/
|
||||
|
||||
export default function ButtonWidget(ctx) {
|
||||
const { children, className, primary, buttonText, onButtonClick, buttonHref, buttonTarget, style } = ctx;
|
||||
interface ButtonWidgetProps {
|
||||
children: ReactNode | string;
|
||||
className?: string;
|
||||
primary?: boolean;
|
||||
buttonText: string;
|
||||
onButtonClick?: MouseEventHandler<HTMLButtonElement>;
|
||||
buttonHref?: string;
|
||||
buttonTarget?: string;
|
||||
style?: CSSProperties;
|
||||
}
|
||||
|
||||
export default function ButtonWidget(ctx: ButtonWidgetProps) {
|
||||
const { children, className, primary, buttonText, onButtonClick, buttonHref, buttonTarget, style = {} } = ctx;
|
||||
return (
|
||||
<div
|
||||
className={classNames(styles.widget, className)}
|
||||
@@ -1,6 +1,7 @@
|
||||
import styles from './Caption.module.css';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { ReactNode, CSSProperties } from 'react';
|
||||
|
||||
/**
|
||||
* A reusable component for captions.
|
||||
@@ -12,7 +13,14 @@ import classNames from 'classnames';
|
||||
*
|
||||
*/
|
||||
|
||||
export default function Caption(ctx) {
|
||||
interface CaptionProps {
|
||||
children: string;
|
||||
center?: boolean;
|
||||
style?: CSSProperties;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
export default function Caption(ctx: CaptionProps) {
|
||||
const { children: caption, center, style, id } = ctx;
|
||||
|
||||
return (
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useState, ReactNode, CSSProperties } from 'react';
|
||||
import styles from './CoolHover.module.css';
|
||||
import classNames from 'classnames';
|
||||
|
||||
@@ -20,7 +20,16 @@ import classNames from 'classnames';
|
||||
*
|
||||
*/
|
||||
|
||||
export default function CoolHover(ctx) {
|
||||
interface CoolHoverProps {
|
||||
hoverColor?: string;
|
||||
bgColor?: string;
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
radius?: number;
|
||||
style?: CSSProperties;
|
||||
}
|
||||
|
||||
export default function CoolHover(ctx: CoolHoverProps) {
|
||||
const { hoverColor, bgColor, children, className, radius, style } = ctx;
|
||||
|
||||
const [pos, setPos] = useState({ x: 0, y: 0 });
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useRef, useMemo } from 'react';
|
||||
import { useEffect, useRef, useMemo, ReactNode, RefObject, Dispatch, SetStateAction } from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import styles from './Dropdown.module.css';
|
||||
@@ -42,7 +42,20 @@ import styles from './Dropdown.module.css';
|
||||
* />
|
||||
*/
|
||||
|
||||
export default function Dropdown(ctx) {
|
||||
interface DropdownContentObject {
|
||||
el: ReactNode;
|
||||
tr: RefObject<ReactNode>;
|
||||
}
|
||||
|
||||
interface DropdownProps {
|
||||
dropdownContents: Array<DropdownContentObject>;
|
||||
openState: [number, Dispatch<SetStateAction<number>>];
|
||||
clickedState: [boolean, Dispatch<SetStateAction<boolean>>];
|
||||
boundaryRef: RefObject<HTMLDivElement>;
|
||||
boundaryTolerance: number;
|
||||
}
|
||||
|
||||
export default function Dropdown(ctx: DropdownProps) {
|
||||
const [open, setOpen] = ctx.openState;
|
||||
const [clicked, setClicked] = ctx.clickedState;
|
||||
const { boundaryRef, boundaryTolerance } = ctx;
|
||||
@@ -68,36 +81,34 @@ export default function Dropdown(ctx) {
|
||||
const dropdownContentRect = dropdownContent?.current?.getBoundingClientRect();
|
||||
const dropdownRect = dropdownContent?.current?.getBoundingClientRect();
|
||||
|
||||
const pxToInt = (px) => parseInt(px.replace('px', ''));
|
||||
const clamp = (num, min, max) => Math.min(Math.max(num, min), max);
|
||||
const pxToInt = (px: string) => parseInt(px.replace('px', ''));
|
||||
const clamp = (num: number, min: number, max: number) => Math.min(Math.max(num, min), max);
|
||||
|
||||
function getRealCenter(trRef: RefObject<HTMLDivElement>) {
|
||||
const style = getComputedStyle(trRef.current);
|
||||
const rightPad = pxToInt(style.paddingRight);
|
||||
const leftPad = pxToInt(style.paddingLeft);
|
||||
|
||||
const elWidth = pxToInt(style.width);
|
||||
return (elWidth - rightPad - leftPad) / 2;
|
||||
}
|
||||
|
||||
function getTriggerOffset(trRef: RefObject<HTMLDivElement>) {
|
||||
const style = getComputedStyle(trRef.current);
|
||||
const leftPad = pxToInt(style.paddingLeft);
|
||||
return (
|
||||
trRef.current.getBoundingClientRect().left - boundaryRef.current.getBoundingClientRect().left + leftPad
|
||||
);
|
||||
}
|
||||
|
||||
function getLeftOffset(trRef: RefObject<HTMLDivElement>) {
|
||||
return getTriggerOffset(trRef) + getRealCenter(trRef);
|
||||
}
|
||||
|
||||
if (dropdownContentRect && open) {
|
||||
const sectionWidth = pxToInt(getComputedStyle(boundaryRef.current).width);
|
||||
const dropdownWidth = dropdownRect.width;
|
||||
|
||||
function getRealCenter(trRef) {
|
||||
const style = getComputedStyle(trRef.current);
|
||||
const rightPad = pxToInt(style.paddingRight);
|
||||
const leftPad = pxToInt(style.paddingLeft);
|
||||
|
||||
const elWidth = pxToInt(style.width);
|
||||
return (elWidth - rightPad - leftPad) / 2;
|
||||
}
|
||||
|
||||
function getTriggerOffset(trRef) {
|
||||
const style = getComputedStyle(trRef.current);
|
||||
const leftPad = pxToInt(style.paddingLeft);
|
||||
return (
|
||||
trRef.current.getBoundingClientRect().left -
|
||||
boundaryRef.current.getBoundingClientRect().left +
|
||||
leftPad
|
||||
);
|
||||
}
|
||||
|
||||
function getLeftOffset(trRef) {
|
||||
return getTriggerOffset(trRef) + getRealCenter(trRef);
|
||||
}
|
||||
|
||||
const arrowOffset = getLeftOffset(dropdownTriggers[open]);
|
||||
const leftOffset = getLeftOffset(dropdownTriggers[open]) - dropdownWidth / 2;
|
||||
|
||||
@@ -118,8 +129,8 @@ export default function Dropdown(ctx) {
|
||||
dropdown.current.style.height = 0;
|
||||
}
|
||||
|
||||
const closeOnClickOutside = (e) => {
|
||||
if (dropdown.current && !dropdown.current.contains(e.target)) {
|
||||
const closeOnClickOutside = (e: MouseEvent) => {
|
||||
if (dropdown.current && !dropdown.current.contains(e.target as Node)) {
|
||||
setOpen(0);
|
||||
setClicked(false);
|
||||
}
|
||||
@@ -6,7 +6,16 @@ import { CaretRight } from '@phosphor-icons/react/dist/ssr';
|
||||
|
||||
import styles from './Faq.module.css';
|
||||
|
||||
export default function Faq(ctx) {
|
||||
interface QAObject {
|
||||
question: string;
|
||||
answer: string;
|
||||
}
|
||||
|
||||
interface FaqProps {
|
||||
questionObject: Array<QAObject>;
|
||||
}
|
||||
|
||||
export default function Faq(ctx: FaqProps) {
|
||||
const { questionObject } = ctx;
|
||||
const [selectedIndex, setSelectedIndex] = useState(0);
|
||||
|
||||
@@ -22,7 +31,7 @@ export default function Faq(ctx) {
|
||||
className={classNames({ [styles.selected]: selected })}
|
||||
onClick={() => setSelectedIndex(i)}
|
||||
onKeyDown={(e) => e.key === 'Enter' && setSelectedIndex(i)}
|
||||
tabIndex="0"
|
||||
tabIndex={0}
|
||||
>
|
||||
<CaretRight size={24} weight="bold" className={styles.chevron} alt="" />
|
||||
{question.question}
|
||||
@@ -11,7 +11,7 @@ import Link from 'next/link';
|
||||
|
||||
import styles from './Footer.module.css';
|
||||
|
||||
export default function Footer(ctx) {
|
||||
export default function Footer() {
|
||||
const { locale } = getLocale('TODO');
|
||||
|
||||
const year = new Date().getFullYear(); /* Can't have an outdated year this way :3 */
|
||||
@@ -28,7 +28,7 @@ export default function Footer(ctx) {
|
||||
href={`https://wikipedia.org/wiki/${year}`}
|
||||
target="_blank"
|
||||
className={styles.link}
|
||||
tabIndex="-1"
|
||||
tabIndex={-1}
|
||||
>
|
||||
{year}
|
||||
</Link>
|
||||
@@ -1,4 +1,4 @@
|
||||
import ImageFix from '@/components/ImageFix/ImageFix';
|
||||
import Image from 'next/image';
|
||||
import n2ds from '/public/assets/images/n2ds.png';
|
||||
|
||||
import Title from '@/components/Title/Title';
|
||||
@@ -22,13 +22,7 @@ export default function Hero({ locale }) {
|
||||
</Button>
|
||||
|
||||
<div>
|
||||
<Button
|
||||
icon
|
||||
href="https://discord.gg/pretendo"
|
||||
target="_blank"
|
||||
aria-label="Discord server"
|
||||
title="Discord server"
|
||||
>
|
||||
<Button icon href="https://discord.gg/pretendo" target="_blank" aria-label="Discord server">
|
||||
<DiscordLogo size={32} weight="fill" alt="" />
|
||||
</Button>
|
||||
|
||||
@@ -41,7 +35,7 @@ export default function Hero({ locale }) {
|
||||
<GithubLogo size={32} weight="fill" alt="" />
|
||||
</Button>
|
||||
|
||||
<Button icon href="/account/upgrade" target="_blank" title="Upgrade page">
|
||||
<Button icon href="/account/upgrade" target="_blank" aria-label="Upgrade page">
|
||||
<Heart size={32} weight="fill" alt="" />
|
||||
</Button>
|
||||
</div>
|
||||
@@ -50,7 +44,7 @@ export default function Hero({ locale }) {
|
||||
<div className={styles.images}>
|
||||
<div className={styles.lightCircle}>
|
||||
<svg
|
||||
alt=""
|
||||
aria-hidden={true}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="839.371"
|
||||
height="893.406"
|
||||
@@ -155,7 +149,7 @@ export default function Hero({ locale }) {
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
<ImageFix className={styles.n2ds} src={n2ds} alt="" />
|
||||
<Image className={styles.n2ds} src={n2ds} alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,12 +0,0 @@
|
||||
import Image from 'next/image';
|
||||
|
||||
// stolen from https://github.com/prismicio/prismic-next/pull/79
|
||||
|
||||
// TODO: Remove once https://github.com/vercel/next.js/issues/52216 is resolved.
|
||||
// `next/image` seems to be affected by a default + named export bundling bug.
|
||||
let ImageFix = Image;
|
||||
if ('default' in ImageFix) {
|
||||
ImageFix = ImageFix.default;
|
||||
}
|
||||
|
||||
export default ImageFix;
|
||||
@@ -1,3 +1,5 @@
|
||||
import { CSSProperties } from 'react';
|
||||
|
||||
/**
|
||||
* The Pretendo P, with or without text.
|
||||
*
|
||||
@@ -12,14 +14,21 @@
|
||||
*
|
||||
*/
|
||||
|
||||
export default function Logo(ctx) {
|
||||
interface LogoProps {
|
||||
text?: boolean;
|
||||
size?: number;
|
||||
center?: boolean;
|
||||
className?: string;
|
||||
style?: CSSProperties;
|
||||
}
|
||||
|
||||
export default function Logo(ctx: LogoProps) {
|
||||
const { text, size = 48, center, className, style } = ctx;
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox={text ? '0 0 120 39.88' : '0 0 39.88 39.88'}
|
||||
aria-label="Pretendo"
|
||||
title="Pretendo"
|
||||
height={size}
|
||||
width={text ? size * 3 : size}
|
||||
className={className}
|
||||
@@ -1,5 +1,7 @@
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { CSSProperties, ReactNode, RefObject } from 'react';
|
||||
|
||||
import styles from './Section.module.css';
|
||||
|
||||
/**
|
||||
@@ -18,7 +20,17 @@ import styles from './Section.module.css';
|
||||
*
|
||||
*/
|
||||
|
||||
export default function Section(ctx) {
|
||||
interface SectionProps {
|
||||
id?: string;
|
||||
style?: CSSProperties;
|
||||
children?: ReactNode;
|
||||
className?: string;
|
||||
compact?: boolean;
|
||||
contentClassName?: string;
|
||||
contentRef?: RefObject<HTMLDivElement>;
|
||||
}
|
||||
|
||||
export default function Section(ctx: SectionProps) {
|
||||
const { id, style, children, className, compact, contentClassName, contentRef } = ctx;
|
||||
|
||||
return (
|
||||
@@ -1,12 +1,19 @@
|
||||
import styles from './ShowcaseSection.module.css';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import ImageFix from '@/components/ImageFix/ImageFix';
|
||||
import Image, { StaticImageData } from 'next/image';
|
||||
|
||||
import Section from '@/components/Section/Section';
|
||||
import Title from '@/components/Title/Title';
|
||||
|
||||
export default function ShowcaseSection(ctx) {
|
||||
interface ShowcaseSectionProps {
|
||||
title?: string;
|
||||
caption?: string;
|
||||
image?: StaticImageData;
|
||||
isOdd?: boolean
|
||||
}
|
||||
|
||||
export default function ShowcaseSection(ctx: ShowcaseSectionProps) {
|
||||
const { title, caption, image, isOdd } = ctx;
|
||||
return (
|
||||
<Section
|
||||
@@ -17,7 +24,7 @@ export default function ShowcaseSection(ctx) {
|
||||
<Title>{title}</Title>
|
||||
<p className={styles.caption}>{caption}</p>
|
||||
</div>
|
||||
<ImageFix src={image} alt="" className={styles.image} quality={100} sizes="(max-width: 840px) 100vw, 700px" />
|
||||
<Image src={image} alt="" className={styles.image} quality={100} sizes="(max-width: 840px) 100vw, 700px" />
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import styles from './TeamCard.module.css';
|
||||
import ImageFix from '@/components/ImageFix/ImageFix';
|
||||
import Image, { StaticImageData } from 'next/image';
|
||||
import Link from 'next/link';
|
||||
|
||||
import { Star } from '@phosphor-icons/react/dist/ssr';
|
||||
@@ -21,7 +21,18 @@ import classNames from 'classnames';
|
||||
*
|
||||
*/
|
||||
|
||||
export default function TeamCard(ctx) {
|
||||
interface TeamCardProps {
|
||||
name: string;
|
||||
caption: string;
|
||||
pic: StaticImageData | string;
|
||||
link?: string;
|
||||
compact?: boolean;
|
||||
special?: boolean;
|
||||
className?: string;
|
||||
tabIndex?: number;
|
||||
}
|
||||
|
||||
export default function TeamCard(ctx: TeamCardProps) {
|
||||
const { name, caption, pic, link, compact, special, className, tabIndex } = ctx;
|
||||
|
||||
return (
|
||||
@@ -35,7 +46,7 @@ export default function TeamCard(ctx) {
|
||||
tabIndex={tabIndex}
|
||||
>
|
||||
<div className={styles.imageWrapper}>
|
||||
<ImageFix src={pic} width={110} height={110} alt="" className={styles.image} />
|
||||
<Image src={pic} width={110} height={110} alt="" className={styles.image} />
|
||||
</div>
|
||||
<div className={styles.text}>
|
||||
<h3>{name}</h3>
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createElement } from 'react';
|
||||
import { createElement, ReactNode, CSSProperties } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import styles from './Title.module.css';
|
||||
|
||||
@@ -13,7 +13,16 @@ import styles from './Title.module.css';
|
||||
*
|
||||
*/
|
||||
|
||||
export default function Title(ctx) {
|
||||
interface TitleProps {
|
||||
children: string;
|
||||
className?: string;
|
||||
element?: string;
|
||||
style?: CSSProperties;
|
||||
id?: string;
|
||||
center?: boolean;
|
||||
}
|
||||
|
||||
export default function Title(ctx: TitleProps) {
|
||||
const { children: title = '', className, element, style, id, center } = ctx;
|
||||
|
||||
// regex to match all start/end punctuation except for parentheses and brackets. Please never make me do this again.
|
||||
@@ -1,10 +1,10 @@
|
||||
import fs from 'fs-extra';
|
||||
import merge from 'lodash.merge';
|
||||
import logger from './logger.js';
|
||||
import logger from './logger.ts';
|
||||
|
||||
import baseLocale from '@/locales/en_US.json' assert { type: 'json' };
|
||||
|
||||
function getLocale(code) {
|
||||
function getLocale(code: string) {
|
||||
const localeCode = code.replace('-', '_');
|
||||
const path = `@/locales/${localeCode}.json`;
|
||||
|
||||
@@ -26,7 +26,9 @@ function getLocale(code) {
|
||||
}
|
||||
|
||||
function getLocaleList() {
|
||||
const filenames = fs.readdirSync('@/locales').map((filename) => filename.replace('.json', '').replace('_', '-'));
|
||||
const filenames = fs
|
||||
.readdirSync('@/locales')
|
||||
.map((filename: string) => filename.replace('.json', '').replace('_', '-'));
|
||||
return filenames;
|
||||
}
|
||||
|
||||
@@ -13,31 +13,37 @@ const writeStreams = {
|
||||
|
||||
const time = () => {
|
||||
const date = new Date();
|
||||
return date.toLocaleTimeString([], { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit', fractionalSecondDigits: 3 });
|
||||
return date.toLocaleTimeString([], {
|
||||
hour12: false,
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
fractionalSecondDigits: 3,
|
||||
});
|
||||
};
|
||||
|
||||
function success(message) {
|
||||
function success(message: string) {
|
||||
const logLine = `[${time()}] [SUCCESS]: ${message}`;
|
||||
writeStreams.success.write(`${logLine}\n`);
|
||||
|
||||
console.log(chalk.green.bold(logLine));
|
||||
}
|
||||
|
||||
function error(message) {
|
||||
function error(message: string) {
|
||||
const logLine = `[${time()}] [ERROR]: ${message}`;
|
||||
writeStreams.error.write(`${logLine}\n`);
|
||||
|
||||
console.log(chalk.red.bold(logLine));
|
||||
}
|
||||
|
||||
function warn(message) {
|
||||
function warn(message: string) {
|
||||
const logLine = `[${time()}] [WARN]: ${message}`;
|
||||
writeStreams.warn.write(`${logLine}\n`);
|
||||
|
||||
console.log(chalk.yellow.bold(logLine));
|
||||
}
|
||||
|
||||
function info(message) {
|
||||
function info(message: string) {
|
||||
const logLine = `[${time()}] [INFO]: ${message}`;
|
||||
writeStreams.info.write(`${logLine}\n`);
|
||||
|
||||
32
tsconfig.json
Normal file
32
tsconfig.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/components/*": ["./src/components/*"],
|
||||
"@/utils/*": ["./src/utils/*"],
|
||||
"@/public/*": ["./public/*"],
|
||||
"@/locales/*": ["./locales/*"],
|
||||
"@/app/*": ["./src/app/*"]
|
||||
},
|
||||
"allowJs": true,
|
||||
"allowImportingTsExtensions": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": false,
|
||||
"noEmit": true,
|
||||
"incremental": true,
|
||||
"module": "esnext",
|
||||
"esModuleInterop": true,
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
]
|
||||
},
|
||||
"include": ["next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", "**/*.tsx"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Reference in New Issue
Block a user