Optimize for Vercel, do some changes, entire site
This commit is contained in:
parent
d72cd85229
commit
f06256d97e
74 changed files with 5243 additions and 585 deletions
877
package-lock.json
generated
877
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -5,6 +5,7 @@
|
||||||
"@types/lodash": "^4.14.195",
|
"@types/lodash": "^4.14.195",
|
||||||
"@types/node": "^20.3.1",
|
"@types/node": "^20.3.1",
|
||||||
"concurrently": "^8.2.0",
|
"concurrently": "^8.2.0",
|
||||||
|
"eslint": "^8.49.0",
|
||||||
"nodemon": "^2.0.22",
|
"nodemon": "^2.0.22",
|
||||||
"tsc-alias": "^1.8.6",
|
"tsc-alias": "^1.8.6",
|
||||||
"typescript": "^5.1.3"
|
"typescript": "^5.1.3"
|
||||||
|
@ -34,6 +35,7 @@
|
||||||
"crypto-js": "^4.1.1",
|
"crypto-js": "^4.1.1",
|
||||||
"dotenv": "^16.3.0",
|
"dotenv": "^16.3.0",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
|
"formik": "^2.4.4",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"mongodb": "^5.6.0",
|
"mongodb": "^5.6.0",
|
||||||
"nanoid": "^3.3.6",
|
"nanoid": "^3.3.6",
|
||||||
|
|
|
@ -1,28 +1,31 @@
|
||||||
import globals from "@/styles/global.module.css";
|
import globals from "@/styles/global.module.css";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import styles from "./Ads.module.css";
|
import styles from "./Ads.module.css";
|
||||||
|
|
||||||
export default function Ads() {
|
export default function Ads() {
|
||||||
const [hide, setHide] = useState(false);
|
const [hide, setHide] = useState(false);
|
||||||
const [adService, setAdService] = useState(0);
|
const [adService, setAdService] = useState(0);
|
||||||
|
const int = useRef<NodeJS.Timer>();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setHide(window.localStorage.getItem("hideAds") === "true");
|
setHide(window.localStorage.getItem("hideAds") === "true");
|
||||||
setAdService(Math.random());
|
setAdService(Math.random());
|
||||||
setInterval(() => setAdService(Math.random()), 60000);
|
clearInterval(int.current);
|
||||||
|
int.current = setInterval(() => setAdService(Math.random()), 60000);
|
||||||
}, []);
|
}, []);
|
||||||
|
// Fix "partitioned storage access" on Firefox
|
||||||
return !hide ? (
|
return !hide ? (
|
||||||
<div className={globals.boxLike}>
|
<div className={globals.boxLike}>
|
||||||
{adService < 0.2 ? (
|
{adService < 0.2 ? (
|
||||||
<iframe
|
<iframe
|
||||||
src="https://mothvertising.moth.monster/embed"
|
src="https://mothvertising.moth.monster/embed"
|
||||||
className={styles.Mothvertisement}
|
className={styles.Mothvertisement}
|
||||||
key={Math.random()}
|
// key={Math.random()}
|
||||||
></iframe>
|
></iframe>
|
||||||
) : adService < 0.4 ? (
|
) : adService < 0.4 ? (
|
||||||
<iframe
|
<iframe
|
||||||
src="https://dimden.neocities.org/navlink/"
|
src="https://dimden.neocities.org/navlink/"
|
||||||
key={Math.random()}
|
// key={Math.random()}
|
||||||
className={styles.NavLink}
|
className={styles.NavLink}
|
||||||
width="180"
|
width="180"
|
||||||
height="180"
|
height="180"
|
||||||
|
@ -33,12 +36,12 @@ export default function Ads() {
|
||||||
width="300"
|
width="300"
|
||||||
height="250"
|
height="250"
|
||||||
src="https://googol.neocities.org/neolink/embed.html"
|
src="https://googol.neocities.org/neolink/embed.html"
|
||||||
key={Math.random()}
|
// key={Math.random()}
|
||||||
></iframe>
|
></iframe>
|
||||||
) : adService < 0.8 ? (
|
) : adService < 0.8 ? (
|
||||||
<iframe
|
<iframe
|
||||||
src="https://john.citrons.xyz/embed?ref=example.com"
|
src="https://john.citrons.xyz/embed?ref=example.com"
|
||||||
key={Math.random()}
|
// key={Math.random()}
|
||||||
className={styles.Johnvertisement}
|
className={styles.Johnvertisement}
|
||||||
width="732"
|
width="732"
|
||||||
height="90"
|
height="90"
|
||||||
|
@ -49,7 +52,7 @@ export default function Ads() {
|
||||||
height="60"
|
height="60"
|
||||||
className={styles.NavLink}
|
className={styles.NavLink}
|
||||||
src="https://hbaguette.neocities.org/bannerlink/embed.html"
|
src="https://hbaguette.neocities.org/bannerlink/embed.html"
|
||||||
key={Math.random()}
|
// key={Math.random()}
|
||||||
></iframe>
|
></iframe>
|
||||||
)}
|
)}
|
||||||
<div className={globals.horizontalListLeft}>
|
<div className={globals.horizontalListLeft}>
|
||||||
|
|
|
@ -23,6 +23,10 @@
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Box.ltr {
|
||||||
|
direction: ltr;
|
||||||
|
}
|
||||||
|
|
||||||
.Box .innerContent {
|
.Box .innerContent {
|
||||||
padding: 6px 4px;
|
padding: 6px 4px;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
|
|
@ -29,7 +29,11 @@ export default function Box({
|
||||||
) as React.CSSProperties;
|
) as React.CSSProperties;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={styles.Box + (!properties?.nfw ? " " + styles.fw : "")}
|
className={
|
||||||
|
styles.Box +
|
||||||
|
(!properties?.nfw ? " " + styles.fw : "") +
|
||||||
|
(properties?.ltr ? " " + styles.ltr : "")
|
||||||
|
}
|
||||||
style={style}
|
style={style}
|
||||||
>
|
>
|
||||||
<Conditional condition={properties?.title != null}>
|
<Conditional condition={properties?.title != null}>
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import { Color3 } from "@/types/assist/color";
|
import { Color3 } from "@/types/assist/color";
|
||||||
|
|
||||||
export type BoxConfig = {
|
export type BoxConfig = {
|
||||||
title?: {
|
title?: {
|
||||||
text: string;
|
text: string;
|
||||||
link?: string;
|
link?: string;
|
||||||
small?: boolean;
|
small?: boolean;
|
||||||
};
|
};
|
||||||
theme?: Color3;
|
theme?: Color3;
|
||||||
nfw?: boolean;
|
nfw?: boolean;
|
||||||
class?: string;
|
ltr?: boolean;
|
||||||
|
class?: string;
|
||||||
};
|
};
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
|
flex: 2 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Nav .right {
|
.Nav .right {
|
||||||
|
@ -37,6 +38,7 @@
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
|
flex: 0.5 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Nav .titlePath {
|
.Nav .titlePath {
|
||||||
|
|
|
@ -23,6 +23,7 @@ export default function Nav(elementProps: AnyObject) {
|
||||||
href="/"
|
href="/"
|
||||||
>
|
>
|
||||||
TrollCall
|
TrollCall
|
||||||
|
<span className={globals.small}> r4 Beta</span>
|
||||||
</Link>
|
</Link>
|
||||||
</span>
|
</span>
|
||||||
<span className={globals.title + " " + styles.shortTitle}>
|
<span className={globals.title + " " + styles.shortTitle}>
|
||||||
|
@ -30,10 +31,18 @@ export default function Nav(elementProps: AnyObject) {
|
||||||
className={globals.link}
|
className={globals.link}
|
||||||
href="/"
|
href="/"
|
||||||
>
|
>
|
||||||
TC
|
TC<span className={globals.small}> Beta</span>
|
||||||
</Link>
|
</Link>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<span className={globals.icon}>
|
||||||
|
<Link
|
||||||
|
className={globals.link}
|
||||||
|
href="https://github.com/MeowcaTheoRange/TrollCallAPIs/issues"
|
||||||
|
>
|
||||||
|
bug_report
|
||||||
|
</Link>
|
||||||
|
</span>
|
||||||
<span className={globals.icon}>
|
<span className={globals.icon}>
|
||||||
<Link
|
<Link
|
||||||
className={globals.link}
|
className={globals.link}
|
||||||
|
@ -82,7 +91,7 @@ export default function Nav(elementProps: AnyObject) {
|
||||||
</span>
|
</span>
|
||||||
<span className={globals.icon}>
|
<span className={globals.icon}>
|
||||||
<Link
|
<Link
|
||||||
href={`/logout`}
|
href={`/manage`}
|
||||||
className={globals.link}
|
className={globals.link}
|
||||||
>
|
>
|
||||||
logout
|
logout
|
||||||
|
@ -90,7 +99,24 @@ export default function Nav(elementProps: AnyObject) {
|
||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<>
|
||||||
|
<span className={globals.icon}>
|
||||||
|
<Link
|
||||||
|
href={`/add/clan`}
|
||||||
|
className={globals.link}
|
||||||
|
>
|
||||||
|
group_add
|
||||||
|
</Link>
|
||||||
|
</span>
|
||||||
|
<span className={globals.icon}>
|
||||||
|
<Link
|
||||||
|
href={`/manage`}
|
||||||
|
className={globals.link}
|
||||||
|
>
|
||||||
|
login
|
||||||
|
</Link>
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -28,9 +28,9 @@
|
||||||
.ClanCard .horizontal {
|
.ClanCard .horizontal {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: auto auto;
|
grid-template-columns: auto auto;
|
||||||
justify-content: center;
|
justify-content: start;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
padding: 8px;
|
padding: 8px 8px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,12 +58,12 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
overflow: hidden;
|
/* overflow: hidden; */
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ClanCard .horizontal .horizontalRight > * {
|
.ClanCard .horizontal .horizontalRight > * {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow: hidden;
|
/* overflow: hidden; */
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,11 +61,13 @@ export default function ClanCard({
|
||||||
{clan.displayName ?? clan.name}
|
{clan.displayName ?? clan.name}
|
||||||
</ConditionalParent>
|
</ConditionalParent>
|
||||||
</p>
|
</p>
|
||||||
<div className={globals.horizontalListLeft}>
|
<Conditional condition={clan.flairs != null}>
|
||||||
{clan.flairs.map(flair => (
|
<div className={globals.horizontalListLeft}>
|
||||||
<FlairCard flair={flair} />
|
{clan.flairs?.map(flair => (
|
||||||
))}
|
<FlairCard flair={flair} />
|
||||||
</div>
|
))}
|
||||||
|
</div>
|
||||||
|
</Conditional>
|
||||||
<hr className={globals.invisep} />
|
<hr className={globals.invisep} />
|
||||||
<p className={globals.iconText}>
|
<p className={globals.iconText}>
|
||||||
<span className={globals.iconSmall}>group</span>
|
<span className={globals.iconSmall}>group</span>
|
||||||
|
@ -93,10 +95,16 @@ export default function ClanCard({
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</Conditional>
|
</Conditional>
|
||||||
<p className={globals.iconText}>
|
<Conditional condition={clan.description.length > 0}>
|
||||||
<span className={globals.iconSmall}>description</span>
|
<p className={globals.iconText}>
|
||||||
<span className={globals.text}>{clan.description}</span>
|
<span className={globals.iconSmall}>
|
||||||
</p>
|
description
|
||||||
|
</span>
|
||||||
|
<span className={globals.text}>
|
||||||
|
{clan.description}
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</Conditional>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
|
@ -14,29 +14,22 @@ export default function ClanSkeleton() {
|
||||||
<div className={styles.horizontal}>
|
<div className={styles.horizontal}>
|
||||||
<div className={styles.horizontalLeft}></div>
|
<div className={styles.horizontalLeft}></div>
|
||||||
<div className={styles.horizontalRight}>
|
<div className={styles.horizontalRight}>
|
||||||
<p className={globals.title}>
|
<p className={globals.title}>Epic Megagames</p>
|
||||||
fjfjfjf fjf fjfjfjfjfjfj fj fj fjfjfj
|
|
||||||
</p>
|
|
||||||
<p className={globals.iconText}>
|
<p className={globals.iconText}>
|
||||||
<span className={globals.iconSmall}>group</span>
|
<span className={globals.iconSmall}>group</span>
|
||||||
<span className={globals.text}>
|
<span className={globals.text}>
|
||||||
jjffjf j f fjfjfjfjjjjff jffff
|
Tim Sweeney (88/12)
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<p className={globals.iconText}>
|
<p className={globals.iconText}>
|
||||||
<span className={globals.iconSmall}>link</span>
|
<span className={globals.iconSmall}>link</span>
|
||||||
<span className={globals.text}>
|
<span className={globals.text}>
|
||||||
https://fjfjfjfjfjfjfjfjfjfjf.fjf/fjfjfjfj
|
https://trollcall.xyz/
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<p className={globals.iconText}>
|
<p className={globals.iconText}>
|
||||||
<span className={globals.iconSmall}>description</span>
|
<span className={globals.iconSmall}>description</span>
|
||||||
<span className={globals.text}>
|
<span className={globals.text}>Tim Sweeney</span>
|
||||||
ffffffffffffffffffjjjfjf fj j jjffjf
|
|
||||||
jfjfjfjfjfjjfffjffjjjjfjfjffjfjj ffjfjf fj j fj
|
|
||||||
fjfjjfjfj jjffjjjfjfjfjfjfjjfj fj fj jf jf jf jf
|
|
||||||
fjjfjffjfjfj fjffjf fjfj
|
|
||||||
</span>
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
.FlairLink {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
.FlairCard {
|
.FlairCard {
|
||||||
background-color: var(--pri-bg);
|
background-color: var(--pri-bg);
|
||||||
color: var(--pri-fg);
|
color: var(--pri-fg);
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
/* eslint-disable @next/next/no-img-element */
|
/* eslint-disable @next/next/no-img-element */
|
||||||
import { Color3 } from "@/types/assist/color";
|
import { Color3 } from "@/types/assist/color";
|
||||||
import { ClientFlair } from "@/types/flair";
|
import { ClientFlair } from "@/types/flair";
|
||||||
|
import { ConditionalParent } from "@/utility/react/Conditional";
|
||||||
import { ThemeModeContext } from "@/utility/react/Themer";
|
import { ThemeModeContext } from "@/utility/react/Themer";
|
||||||
|
import Link from "next/link";
|
||||||
import { useContext } from "react";
|
import { useContext } from "react";
|
||||||
import styles from "./FlairCard.module.css";
|
import styles from "./FlairCard.module.css";
|
||||||
|
|
||||||
|
@ -20,12 +22,25 @@ export default function FlairCard({ flair }: { flair: ClientFlair }) {
|
||||||
}
|
}
|
||||||
) as React.CSSProperties;
|
) as React.CSSProperties;
|
||||||
return (
|
return (
|
||||||
<div
|
<ConditionalParent
|
||||||
className={styles.FlairCard}
|
condition={flair.link != null}
|
||||||
style={style}
|
parent={children => (
|
||||||
title={flair.alt}
|
<Link
|
||||||
|
className={styles.FlairLink}
|
||||||
|
href={flair.link ?? ""}
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
{flair.name}
|
<div
|
||||||
</div>
|
className={styles.FlairCard}
|
||||||
|
style={style}
|
||||||
|
title={flair.alt}
|
||||||
|
>
|
||||||
|
{flair.name}
|
||||||
|
</div>
|
||||||
|
</ConditionalParent>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,3 +31,14 @@
|
||||||
drop-shadow(1px -1px 0 currentcolor)
|
drop-shadow(1px -1px 0 currentcolor)
|
||||||
drop-shadow(-1px 1px 0 currentcolor);
|
drop-shadow(-1px 1px 0 currentcolor);
|
||||||
}
|
}
|
||||||
|
.SignCard.Skeleton .topImagePlaceholder {
|
||||||
|
font-family: "Renogare", "Poppins", "Space Grotesk", "Fira Code",
|
||||||
|
"Courier New", monospace;
|
||||||
|
font-size: 52px;
|
||||||
|
width: 52px;
|
||||||
|
color: var(--pri-bg);
|
||||||
|
filter: drop-shadow(1px 1px 0 var(--pri-fg))
|
||||||
|
drop-shadow(-1px -1px 0 var(--pri-fg))
|
||||||
|
drop-shadow(1px -1px 0 var(--pri-fg))
|
||||||
|
drop-shadow(-1px 1px 0 var(--pri-fg));
|
||||||
|
}
|
||||||
|
|
|
@ -12,18 +12,12 @@ export default function SignSkeleton() {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className={styles.gridItem}>
|
<div className={styles.gridItem}>
|
||||||
<img
|
<span className={styles.topImagePlaceholder}>λ</span>
|
||||||
src={"/assets/signs/Lime/Cancer.svg"}
|
|
||||||
className={styles.topImage}
|
|
||||||
alt=""
|
|
||||||
></img>
|
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.gridItem + " " + styles.secondary}>
|
<div className={styles.gridItem + " " + styles.secondary}>
|
||||||
<p className={globals.title}>jjjjfjfjffjfjjffj</p>
|
<p className={globals.title}>half-life</p>
|
||||||
<p className={globals.horizontalList}>
|
<p className={globals.horizontalList}>
|
||||||
<span className={globals.text}>jjjfjfj</span>
|
<span className={globals.text}>born.</span>
|
||||||
<span className={globals.text}>+</span>
|
|
||||||
<span className={globals.text}>jjjfjfj</span>
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
|
@ -82,46 +82,69 @@ export default function TrollCard({
|
||||||
<p className={globals.text}>
|
<p className={globals.text}>
|
||||||
({troll.pronunciation.join(" ")})
|
({troll.pronunciation.join(" ")})
|
||||||
</p>
|
</p>
|
||||||
<p className={globals.text}>
|
<Conditional condition={troll.username != null}>
|
||||||
Also known as <b>{troll.username}</b> online.
|
<p className={globals.text}>
|
||||||
</p>
|
Also known as <b>{troll.username}</b> online.
|
||||||
<div className={globals.horizontalListLeft}>
|
</p>
|
||||||
{troll.flairs.map(flair => (
|
</Conditional>
|
||||||
<FlairCard flair={flair} />
|
<Conditional condition={troll.flairs != null}>
|
||||||
))}
|
<div className={globals.horizontalListLeft}>
|
||||||
</div>
|
{troll.flairs?.map(flair => (
|
||||||
|
<FlairCard flair={flair} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Conditional>
|
||||||
<hr className={globals.invisep} />
|
<hr className={globals.invisep} />
|
||||||
<p className={globals.horizontalList}>
|
<Conditional
|
||||||
<Conditional condition={troll.class != null}>
|
condition={
|
||||||
<span className={globals.text}>
|
troll.class != null &&
|
||||||
{troll.class?.name} of{" "}
|
troll.gender != null &&
|
||||||
{troll.trueSign?.aspect.name}
|
troll.species != null
|
||||||
</span>
|
}
|
||||||
<span className={globals.text}>-</span>
|
>
|
||||||
</Conditional>
|
<p className={globals.horizontalList}>
|
||||||
<span className={globals.text}>{troll.gender}</span>
|
<Conditional condition={troll.class != null}>
|
||||||
<span className={globals.text}>-</span>
|
<span className={globals.text}>
|
||||||
<span className={globals.text}>
|
{troll.class?.name} of{" "}
|
||||||
{PronounGrouper(troll.pronouns)}
|
{troll.trueSign?.aspect.name}
|
||||||
</span>
|
</span>
|
||||||
</p>
|
<span className={globals.text}>-</span>
|
||||||
|
</Conditional>
|
||||||
|
<Conditional condition={troll.gender != null}>
|
||||||
|
<span className={globals.text}>
|
||||||
|
{troll.gender}
|
||||||
|
</span>
|
||||||
|
</Conditional>
|
||||||
|
<Conditional
|
||||||
|
condition={
|
||||||
|
troll.gender != null &&
|
||||||
|
troll.species != null
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span className={globals.text}>-</span>
|
||||||
|
</Conditional>
|
||||||
|
<Conditional condition={troll.species != null}>
|
||||||
|
<span className={globals.text}>
|
||||||
|
{troll.species}
|
||||||
|
</span>
|
||||||
|
</Conditional>
|
||||||
|
</p>
|
||||||
|
</Conditional>
|
||||||
<p className={globals.horizontalList}>
|
<p className={globals.horizontalList}>
|
||||||
<span className={globals.text}>
|
<span className={globals.text}>
|
||||||
{AgeConverter(troll.age, true)}
|
{AgeConverter(troll.age)} old
|
||||||
</span>
|
</span>
|
||||||
<span className={globals.text}>-</span>
|
<span className={globals.text}>-</span>
|
||||||
<span className={globals.text}>
|
<span className={globals.text}>
|
||||||
{HeightConverter(troll.height)}
|
{HeightConverter(troll.height)}
|
||||||
</span>
|
</span>
|
||||||
<Conditional condition={troll.species != null}>
|
<span className={globals.text}>-</span>
|
||||||
<span className={globals.text}>-</span>
|
<span className={globals.text}>
|
||||||
<span className={globals.text}>
|
{PronounGrouper(troll.pronouns)}
|
||||||
{troll.species}
|
</span>
|
||||||
</span>
|
|
||||||
</Conditional>
|
|
||||||
</p>{" "}
|
</p>{" "}
|
||||||
<hr className={globals.invisep} />
|
|
||||||
<Conditional condition={troll.facts != null}>
|
<Conditional condition={troll.facts != null}>
|
||||||
|
<hr className={globals.invisep} />
|
||||||
<ul>
|
<ul>
|
||||||
{troll.facts?.map((fact, index) => (
|
{troll.facts?.map((fact, index) => (
|
||||||
<li
|
<li
|
||||||
|
@ -133,8 +156,8 @@ export default function TrollCard({
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</Conditional>{" "}
|
</Conditional>{" "}
|
||||||
<hr className={globals.invisep} />
|
|
||||||
<Conditional condition={troll.trueSign != null}>
|
<Conditional condition={troll.trueSign != null}>
|
||||||
|
<hr className={globals.invisep} />
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
styles.stack +
|
styles.stack +
|
||||||
|
@ -157,7 +180,14 @@ export default function TrollCard({
|
||||||
</Conditional>
|
</Conditional>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Conditional condition={small}>
|
<Conditional
|
||||||
|
condition={
|
||||||
|
small &&
|
||||||
|
randomLove != "" &&
|
||||||
|
randomHate != "" &&
|
||||||
|
randomQuote != ""
|
||||||
|
}
|
||||||
|
>
|
||||||
<div className={styles.bottom}>
|
<div className={styles.bottom}>
|
||||||
<Conditional condition={randomLove != ""}>
|
<Conditional condition={randomLove != ""}>
|
||||||
<p className={globals.iconText}>
|
<p className={globals.iconText}>
|
||||||
|
@ -179,10 +209,12 @@ export default function TrollCard({
|
||||||
format_quote
|
format_quote
|
||||||
</span>
|
</span>
|
||||||
<span className={globals.text}>
|
<span className={globals.text}>
|
||||||
{parseQuirk(
|
{troll.quirks != null
|
||||||
randomQuote,
|
? parseQuirk(
|
||||||
troll.quirks["default"]
|
randomQuote,
|
||||||
)}
|
troll.quirks["default"]
|
||||||
|
)
|
||||||
|
: randomQuote}
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</Conditional>
|
</Conditional>
|
||||||
|
|
|
@ -19,33 +19,30 @@ export default function TrollSkeleton() {
|
||||||
></img>
|
></img>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.gridItem + " " + styles.secondary}>
|
<div className={styles.gridItem + " " + styles.secondary}>
|
||||||
<p className={globals.title}>ffjfjf fjfjjj</p>
|
<p className={globals.title}>GABBEN NEWELL</p>
|
||||||
<p className={globals.text}>(fjjjf-jjfj fjjfjf-fjffj)</p>
|
<p className={globals.text}>(gay-ben new-wul)</p>
|
||||||
<p className={globals.text}>
|
<p className={globals.text}>
|
||||||
Also known as ffjfjjfjjfjfjjjjjfjjf online.
|
Also known as gaben@valvesoftware.com online.
|
||||||
</p>
|
</p>
|
||||||
<hr className={globals.invisep} />
|
<hr className={globals.invisep} />
|
||||||
<p className={globals.horizontalList}>
|
<p className={globals.horizontalList}>
|
||||||
<span className={globals.text}>fj</span>
|
<span className={globals.text}>Lord of Sales</span>
|
||||||
<span className={globals.text}>-</span>
|
<span className={globals.text}>-</span>
|
||||||
<span className={globals.text}>ffjfj</span>
|
<span className={globals.text}>Software</span>
|
||||||
<span className={globals.text}>-</span>
|
<span className={globals.text}>-</span>
|
||||||
<span className={globals.text}>fj/fjj/fjjjf</span>
|
<span className={globals.text}>de/ck</span>
|
||||||
</p>
|
</p>
|
||||||
<p className={globals.horizontalList}>
|
<p className={globals.horizontalList}>
|
||||||
<span className={globals.text}>fj</span>
|
<span className={globals.text}>All Time</span>
|
||||||
<span className={globals.text}>-</span>
|
<span className={globals.text}>-</span>
|
||||||
<span className={globals.text}>ffjfj</span>
|
<span className={globals.text}>30%</span>
|
||||||
<span className={globals.text}>-</span>
|
<span className={globals.text}>-</span>
|
||||||
<span className={globals.text}>fj/fjj/fjjjf</span>
|
<span className={globals.text}>Steam</span>
|
||||||
</p>
|
</p>
|
||||||
<hr className={globals.invisep} />
|
<hr className={globals.invisep} />
|
||||||
<ul>
|
<ul>
|
||||||
<li className={globals.text}>fjjfjjfjffj</li>
|
<li className={globals.text}>Steam Summer Sale</li>
|
||||||
<li className={globals.text}>fjjjjfjffjjfffjfj</li>
|
<li className={globals.text}>Dota</li>
|
||||||
<li className={globals.text}>
|
|
||||||
fjjjjffjjjfjjjfjjffjfjfj
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
<br />
|
<br />
|
||||||
<div className={styles.stack + " " + styles.noFalseSign}>
|
<div className={styles.stack + " " + styles.noFalseSign}>
|
||||||
|
@ -56,20 +53,16 @@ export default function TrollSkeleton() {
|
||||||
<div className={styles.bottom}>
|
<div className={styles.bottom}>
|
||||||
<p className={globals.iconText}>
|
<p className={globals.iconText}>
|
||||||
<span className={globals.iconSmall}>thumb_up</span>
|
<span className={globals.iconSmall}>thumb_up</span>
|
||||||
<span className={globals.text}>
|
<span className={globals.text}>n < 3</span>
|
||||||
ffjj fjf jjffffjfjfj fjfjjfjfjjj
|
|
||||||
</span>
|
|
||||||
</p>
|
</p>
|
||||||
<p className={globals.iconText}>
|
<p className={globals.iconText}>
|
||||||
<span className={globals.iconSmall}>thumb_down</span>
|
<span className={globals.iconSmall}>thumb_down</span>
|
||||||
<span className={globals.text}>
|
<span className={globals.text}>n >= 3</span>
|
||||||
ffjjj fjjfjjf jf jj jjfjjjffj j fff
|
|
||||||
</span>
|
|
||||||
</p>
|
</p>
|
||||||
<p className={globals.iconText}>
|
<p className={globals.iconText}>
|
||||||
<span className={globals.iconSmall}>format_quote</span>
|
<span className={globals.iconSmall}>format_quote</span>
|
||||||
<span className={globals.text}>
|
<span className={globals.text}>
|
||||||
jjj fjjf jfjjjf f j ffff j f jjfj jf fj fjjjfj jfj
|
Hopefully, it would have been worth the wait.
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
49
src/components/form/ErrorHandler/ErrorHandler.tsx
Normal file
49
src/components/form/ErrorHandler/ErrorHandler.tsx
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
import globals from "@/styles/global.module.css";
|
||||||
|
import form_globals from "@/styles/global_form.module.css";
|
||||||
|
export default function ErrorHandler(error: any) {
|
||||||
|
console.log(error);
|
||||||
|
if (Array.isArray(error) && error.map)
|
||||||
|
return (
|
||||||
|
<span className={form_globals.verticalListCrunch}>
|
||||||
|
{error.map((errorChild, index) => (
|
||||||
|
<ErrorHandler
|
||||||
|
error={errorChild}
|
||||||
|
key={index}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
else if (typeof error === "string")
|
||||||
|
return (
|
||||||
|
<span className={`${globals.text} ${form_globals.render_error}`}>
|
||||||
|
<span className={form_globals.iconSmall}>error</span> Error:{" "}
|
||||||
|
{error.replace(
|
||||||
|
/\["?(\d+)"?\]/g,
|
||||||
|
(_: string, s1: string, __: any, ___: string) =>
|
||||||
|
" field #" + (+s1 + 1)
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
else if (Array.isArray(error.error) && error.error.map)
|
||||||
|
return (
|
||||||
|
<span className={form_globals.verticalListCrunch}>
|
||||||
|
{error.error.map((errorChild: string, index: number) => (
|
||||||
|
<ErrorHandler
|
||||||
|
error={errorChild}
|
||||||
|
key={index}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
else if (typeof error.error === "string")
|
||||||
|
return (
|
||||||
|
<span className={`${globals.text} ${form_globals.render_error}`}>
|
||||||
|
<span className={form_globals.iconSmall}>error</span> Error:{" "}
|
||||||
|
{error.error.replace(
|
||||||
|
/\["?(\d+)"?\]/g,
|
||||||
|
(_: string, s1: string, __: any, ___: string) =>
|
||||||
|
" field #" + (+s1 + 1)
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
18
src/components/form/template/.prettierrc
Normal file
18
src/components/form/template/.prettierrc
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"_comment": "A custom .prettierrc file is here because Formik gets pretty intense.",
|
||||||
|
"trailingComma": "none",
|
||||||
|
"tabWidth": 4,
|
||||||
|
"useTabs": false,
|
||||||
|
"printWidth": 160,
|
||||||
|
"semi": true,
|
||||||
|
"singleQuote": false,
|
||||||
|
"quoteProps": "preserve",
|
||||||
|
"jsxSingleQuote": false,
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"bracketSameLine": false,
|
||||||
|
"arrowParens": "avoid",
|
||||||
|
"proseWrap": "never",
|
||||||
|
"endOfLine": "lf",
|
||||||
|
"embeddedLanguageFormatting": "auto",
|
||||||
|
"singleAttributePerLine": true
|
||||||
|
}
|
730
src/components/form/template/clan.tsx
Normal file
730
src/components/form/template/clan.tsx
Normal file
|
@ -0,0 +1,730 @@
|
||||||
|
import Box from "@/components/Box/Box";
|
||||||
|
import ErrorHandler from "@/components/form/ErrorHandler/ErrorHandler";
|
||||||
|
import globals from "@/styles/global.module.css";
|
||||||
|
import form_globals from "@/styles/global_form.module.css";
|
||||||
|
import { Color3 } from "@/types/assist/color";
|
||||||
|
import { SubmitClan, SubmitClanSchema } from "@/types/client/clan";
|
||||||
|
import { ArrayHelpers, ErrorMessage, Field, FieldArray, Form, Formik } from "formik";
|
||||||
|
import { NextRouter } from "next/router";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
export default function ClanFormTemplate({
|
||||||
|
router,
|
||||||
|
onSubmitURI,
|
||||||
|
on200URI,
|
||||||
|
initialValues,
|
||||||
|
method
|
||||||
|
}: {
|
||||||
|
router: NextRouter;
|
||||||
|
initialValues?: SubmitClan;
|
||||||
|
onSubmitURI?: string;
|
||||||
|
on200URI?: string;
|
||||||
|
method?: string;
|
||||||
|
}) {
|
||||||
|
const [submitError, setSubmitError] = useState("");
|
||||||
|
return (
|
||||||
|
<Formik
|
||||||
|
initialValues={
|
||||||
|
initialValues ??
|
||||||
|
({
|
||||||
|
name: "",
|
||||||
|
description: "",
|
||||||
|
members: [
|
||||||
|
{
|
||||||
|
name: "",
|
||||||
|
pronouns: [["", "", ""]]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
} as SubmitClan)
|
||||||
|
}
|
||||||
|
validationSchema={SubmitClanSchema}
|
||||||
|
onSubmit={async (values, { setSubmitting, setErrors, setFieldError }) => {
|
||||||
|
fetch(onSubmitURI ?? "/api/clan", {
|
||||||
|
method: method ?? "POST",
|
||||||
|
body: JSON.stringify(values),
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
}).then(res => {
|
||||||
|
if (res.status === 200) router.push(on200URI ?? `/clan/${values.name}`);
|
||||||
|
else setSubmitError(res.status.toString());
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{({ values, setFieldValue, errors, initialValues, isSubmitting, resetForm, submitForm }) => (
|
||||||
|
<Form className={form_globals.FlexNormalizer}>
|
||||||
|
<Box properties={{ title: { text: "Identity" } }}>
|
||||||
|
<span className={globals.text}>About your clan. Name, members, whatever else!</span>
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
<div className={form_globals.verticalListCrunch}>
|
||||||
|
<p className={globals.titleSmall}>Name</p>
|
||||||
|
<span className={globals.text}>The name of your clan.</span>
|
||||||
|
</div>
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
<div className={globals.horizontalListLeft}>
|
||||||
|
<Field
|
||||||
|
type="text"
|
||||||
|
name="name"
|
||||||
|
placeholder="jim"
|
||||||
|
className={`
|
||||||
|
${form_globals.textLikeInput}
|
||||||
|
${form_globals.textLikeInputTight}
|
||||||
|
`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<ErrorMessage
|
||||||
|
name="name"
|
||||||
|
render={ErrorHandler}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={`
|
||||||
|
${form_globals.verticalListCrunch}
|
||||||
|
${form_globals.layoutAppearable}
|
||||||
|
${values.name != initialValues.name && values.name != null && errors.name == null ? form_globals.appear : ""}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<span className={globals.text}>By the way, your clan's link is based on the this name.</span>
|
||||||
|
<span className={globals.mono}>/clan/{values.name?.toLowerCase()}</span>
|
||||||
|
<span className={`${form_globals.render_info}`}>
|
||||||
|
<span className={form_globals.iconSmall}>info</span>{" "}
|
||||||
|
<span className={`${globals.text}`}>
|
||||||
|
Keep in mind - if you have overlapping names with another clan, you will not be able to submit this clan.
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr className={globals.invisep} />
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
<div className={form_globals.verticalListCrunch}>
|
||||||
|
<p className={globals.titleSmall}>Display name</p>
|
||||||
|
<span className={globals.text}>The display name for your clan. If left blank, the simple name will be used instead.</span>
|
||||||
|
</div>
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
<div className={globals.horizontalListLeft}>
|
||||||
|
<Field
|
||||||
|
type="text"
|
||||||
|
name="displayName"
|
||||||
|
placeholder="Clan of Jim"
|
||||||
|
className={`
|
||||||
|
${form_globals.textLikeInput}
|
||||||
|
${form_globals.textLikeInputTight}
|
||||||
|
`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<ErrorMessage
|
||||||
|
name="displayName"
|
||||||
|
render={ErrorHandler}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={`
|
||||||
|
${form_globals.verticalListCrunch}
|
||||||
|
${form_globals.layoutAppearable}
|
||||||
|
${values.displayName != initialValues.displayName && errors.displayName == null ? form_globals.appear : ""}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<span className={`${form_globals.render_info}`}>
|
||||||
|
<span className={form_globals.iconSmall}>info</span>{" "}
|
||||||
|
<span className={`${globals.text}`}>
|
||||||
|
If you have overlapping display names with another clan, nothing will happen -- though you may have issues regarding
|
||||||
|
impersonation.
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr className={globals.invisep} />
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
<div className={form_globals.verticalListCrunch}>
|
||||||
|
<p className={globals.titleSmall}>Members</p>
|
||||||
|
<span className={globals.text}>All of the members of your clan.</span>
|
||||||
|
</div>
|
||||||
|
<FieldArray
|
||||||
|
name="members"
|
||||||
|
render={(arrayHelpers: ArrayHelpers) => (
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
{values.members && values.members.length > 0 ? (
|
||||||
|
<>
|
||||||
|
<div className={form_globals.horizlist}>
|
||||||
|
<button
|
||||||
|
className={`${globals.button}`}
|
||||||
|
type="button"
|
||||||
|
onClick={() => arrayHelpers.unshift({ name: "", pronouns: [["", "", ""]] })}
|
||||||
|
>
|
||||||
|
Add member
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
{values.members.map((member, index) => (
|
||||||
|
<div
|
||||||
|
className={globals.verticalListTop}
|
||||||
|
key={index}
|
||||||
|
>
|
||||||
|
<div className={form_globals.horizlist}>
|
||||||
|
<Field
|
||||||
|
type="text"
|
||||||
|
name={`members.${index}.name`}
|
||||||
|
placeholder="Jimberly"
|
||||||
|
className={`
|
||||||
|
${form_globals.textLikeInput}
|
||||||
|
${form_globals.textLikeInputTight}
|
||||||
|
`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<ErrorMessage
|
||||||
|
name={`members.${index}.name`}
|
||||||
|
render={ErrorHandler}
|
||||||
|
/>
|
||||||
|
<div className={form_globals.horizlist}>
|
||||||
|
<FieldArray
|
||||||
|
name={`members.${index}.pronouns`}
|
||||||
|
render={(arrayPronounHelpers: ArrayHelpers) => (
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
<div className={form_globals.horizlist}>
|
||||||
|
<button
|
||||||
|
className={`${globals.button}`}
|
||||||
|
type="button"
|
||||||
|
onClick={() => arrayPronounHelpers.unshift(["", "", ""])}
|
||||||
|
>
|
||||||
|
Add pronoun set
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
{values.members[index].pronouns && values.members[index].pronouns.length > 0 ? (
|
||||||
|
values.members[index].pronouns.map((pronounSet, mbPindex) => (
|
||||||
|
<div
|
||||||
|
className={form_globals.horizlist}
|
||||||
|
key={index}
|
||||||
|
>
|
||||||
|
<div className={form_globals.horizlist}>
|
||||||
|
<Field
|
||||||
|
type="text"
|
||||||
|
name={`members.${index}.pronouns.${mbPindex}.0`}
|
||||||
|
placeholder="they"
|
||||||
|
className={`
|
||||||
|
${form_globals.textLikeInput}
|
||||||
|
${form_globals.textLikeInputSmall}
|
||||||
|
${form_globals.textLikeInputInvisible}
|
||||||
|
`}
|
||||||
|
/>
|
||||||
|
<span className={globals.text}>/</span>
|
||||||
|
<Field
|
||||||
|
type="text"
|
||||||
|
name={`members.${index}.pronouns.${mbPindex}.1`}
|
||||||
|
placeholder="them"
|
||||||
|
className={`
|
||||||
|
${form_globals.textLikeInput}
|
||||||
|
${form_globals.textLikeInputSmall}
|
||||||
|
${form_globals.textLikeInputInvisible}
|
||||||
|
`}
|
||||||
|
/>
|
||||||
|
<span className={globals.text}>/</span>
|
||||||
|
<Field
|
||||||
|
type="text"
|
||||||
|
name={`members.${index}.pronouns.${mbPindex}.2`}
|
||||||
|
placeholder="theirs"
|
||||||
|
className={`
|
||||||
|
${form_globals.textLikeInput}
|
||||||
|
${form_globals.textLikeInputSmall}
|
||||||
|
${form_globals.textLikeInputInvisible}
|
||||||
|
`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={form_globals.horizlist}>
|
||||||
|
<button
|
||||||
|
className={`${globals.buttonIcon}`}
|
||||||
|
type="button"
|
||||||
|
onClick={() => arrayPronounHelpers.remove(mbPindex)}
|
||||||
|
>
|
||||||
|
remove
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={`${globals.buttonIcon}`}
|
||||||
|
type="button"
|
||||||
|
onClick={() =>
|
||||||
|
arrayPronounHelpers.insert(mbPindex + 1, ["", "", ""])
|
||||||
|
}
|
||||||
|
>
|
||||||
|
add
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={`${globals.buttonIcon} ${
|
||||||
|
mbPindex <= 0 ? form_globals.layoutButtonDisabled : ""
|
||||||
|
}`}
|
||||||
|
disabled={mbPindex <= 0}
|
||||||
|
type="button"
|
||||||
|
onClick={() =>
|
||||||
|
arrayPronounHelpers.move(mbPindex, mbPindex - 1)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
keyboard_arrow_up
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={`${globals.buttonIcon} ${
|
||||||
|
mbPindex >= values.members[index].pronouns.length - 1
|
||||||
|
? form_globals.layoutButtonDisabled
|
||||||
|
: ""
|
||||||
|
}`}
|
||||||
|
disabled={
|
||||||
|
mbPindex >= values.members[index].pronouns.length - 1
|
||||||
|
}
|
||||||
|
type="button"
|
||||||
|
onClick={() =>
|
||||||
|
arrayPronounHelpers.move(mbPindex, mbPindex + 1)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
keyboard_arrow_down
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<ErrorMessage
|
||||||
|
name={`members.${index}.pronouns`}
|
||||||
|
render={ErrorHandler}
|
||||||
|
/>
|
||||||
|
<div className={form_globals.horizlist}>
|
||||||
|
<button
|
||||||
|
className={`${globals.buttonIcon}`}
|
||||||
|
type="button"
|
||||||
|
onClick={() => arrayHelpers.remove(index)}
|
||||||
|
>
|
||||||
|
remove
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={`${globals.buttonIcon}`}
|
||||||
|
type="button"
|
||||||
|
onClick={() => arrayHelpers.insert(index + 1, { name: "", pronouns: [["", "", ""]] })}
|
||||||
|
>
|
||||||
|
add
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={`${globals.buttonIcon} ${index <= 0 ? form_globals.layoutButtonDisabled : ""}`}
|
||||||
|
disabled={index <= 0}
|
||||||
|
type="button"
|
||||||
|
onClick={() => arrayHelpers.move(index, index - 1)}
|
||||||
|
>
|
||||||
|
keyboard_arrow_up
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={`${globals.buttonIcon} ${
|
||||||
|
index >= values.members.length - 1 ? form_globals.layoutButtonDisabled : ""
|
||||||
|
}`}
|
||||||
|
disabled={index >= values.members.length - 1}
|
||||||
|
type="button"
|
||||||
|
onClick={() => arrayHelpers.move(index, index + 1)}
|
||||||
|
>
|
||||||
|
keyboard_arrow_down
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
className={`${globals.button}`}
|
||||||
|
type="button"
|
||||||
|
onClick={() => arrayHelpers.unshift({ name: "", pronouns: [["", "", ""]] })}
|
||||||
|
>
|
||||||
|
Add members
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<ErrorMessage
|
||||||
|
name={`members`}
|
||||||
|
render={ErrorHandler}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<hr className={globals.invisep} />
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
<div className={form_globals.verticalListCrunch}>
|
||||||
|
<p className={globals.titleSmall}>description</p>
|
||||||
|
<span className={globals.text}>Describe your clan to us!</span>
|
||||||
|
<span className={globals.text}>You don't have to, but it would be cool if you did.</span>
|
||||||
|
</div>
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
<Field
|
||||||
|
as="textarea"
|
||||||
|
name="description"
|
||||||
|
placeholder="Description"
|
||||||
|
className={`
|
||||||
|
${form_globals.textLikeInput}
|
||||||
|
${form_globals.textLikeInputMultiline}
|
||||||
|
`}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
className={`${globals.text} ${values.description.length > 10000 ? form_globals.render_error : ""} ${
|
||||||
|
values.description.length >= 9900 ? form_globals.render_warning : ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{values.description.length <= 10000
|
||||||
|
? 10000 - values.description.length + " characters remaining"
|
||||||
|
: values.description.length - 10000 + " characters over limit"}
|
||||||
|
</span>
|
||||||
|
<ErrorMessage
|
||||||
|
name="description"
|
||||||
|
render={ErrorHandler}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr className={globals.invisep} />
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
<div className={form_globals.verticalListCrunch}>
|
||||||
|
<p className={globals.titleSmall}>Clan Color</p>
|
||||||
|
<span className={globals.text}>The color that represents your clan the most.</span>
|
||||||
|
</div>
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
{values.color != null && errors.color == null ? (
|
||||||
|
<>
|
||||||
|
<div className={globals.horizontalListLeft}>
|
||||||
|
<span className={globals.text}>Red</span>
|
||||||
|
<Field
|
||||||
|
type="number"
|
||||||
|
name="color.0"
|
||||||
|
placeholder="0"
|
||||||
|
min="0"
|
||||||
|
max="255"
|
||||||
|
className={`
|
||||||
|
${form_globals.textLikeInput}
|
||||||
|
${form_globals.textLikeInputSmall}
|
||||||
|
${form_globals.textLikeInputInvisible}
|
||||||
|
`}
|
||||||
|
/>
|
||||||
|
<span className={globals.text}>Green</span>
|
||||||
|
<Field
|
||||||
|
type="number"
|
||||||
|
name="color.1"
|
||||||
|
placeholder="0"
|
||||||
|
min="0"
|
||||||
|
max="255"
|
||||||
|
className={`
|
||||||
|
${form_globals.textLikeInput}
|
||||||
|
${form_globals.textLikeInputSmall}
|
||||||
|
${form_globals.textLikeInputInvisible}
|
||||||
|
`}
|
||||||
|
/>
|
||||||
|
<span className={globals.text}>Blue</span>
|
||||||
|
<Field
|
||||||
|
type="number"
|
||||||
|
name="color.2"
|
||||||
|
placeholder="0"
|
||||||
|
min="0"
|
||||||
|
max="255"
|
||||||
|
className={`
|
||||||
|
${form_globals.textLikeInput}
|
||||||
|
${form_globals.textLikeInputSmall}
|
||||||
|
${form_globals.textLikeInputInvisible}
|
||||||
|
`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span className={globals.text}>#{Color3.fromRGB(...values.color).toHex()}</span>
|
||||||
|
<Box
|
||||||
|
properties={{
|
||||||
|
title: {
|
||||||
|
text: "This is a title."
|
||||||
|
},
|
||||||
|
theme: Color3.fromRGB(...values.color)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className={globals.text}>This is average text!</span>
|
||||||
|
<button
|
||||||
|
className={globals.button}
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
setFieldValue("color", undefined);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Clear Clan Color
|
||||||
|
</button>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<button
|
||||||
|
className={globals.button}
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
setFieldValue("color", [255, 255, 255]);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Add Clan Color
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ErrorMessage
|
||||||
|
name="color"
|
||||||
|
render={ErrorHandler}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<hr className={globals.invisep} />
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
<div className={form_globals.verticalListCrunch}>
|
||||||
|
<p className={globals.titleSmall}>PFP Image</p>
|
||||||
|
<span className={globals.text}>An image.</span>
|
||||||
|
</div>
|
||||||
|
<div className={form_globals.horizlist}>
|
||||||
|
<span className={globals.icon}>image</span>
|
||||||
|
<Field
|
||||||
|
type="text"
|
||||||
|
name="pfp"
|
||||||
|
placeholder="https://example.com/"
|
||||||
|
className={`
|
||||||
|
${form_globals.textLikeInput}
|
||||||
|
${form_globals.textLikeInputTight}
|
||||||
|
`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<ErrorMessage
|
||||||
|
name="pfp"
|
||||||
|
render={ErrorHandler}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Box>
|
||||||
|
<Box properties={{ title: { text: "More" } }}>
|
||||||
|
<span className={globals.text}>Clan preferences, et cetera.</span>
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
<div className={form_globals.verticalListCrunch}>
|
||||||
|
<p className={globals.titleSmall}>Policies</p>
|
||||||
|
<span className={globals.text}>How you want others to treat your characters.</span>
|
||||||
|
</div>
|
||||||
|
<Box
|
||||||
|
properties={{
|
||||||
|
class: form_globals.vertilist
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
<p className={globals.titleSmall}>Fanart</p>
|
||||||
|
<span className={globals.text}>Allow others to draw fanart of your characters.</span>
|
||||||
|
<Field
|
||||||
|
as="select"
|
||||||
|
name="policies.fanart"
|
||||||
|
placeholder="Troll"
|
||||||
|
className={`
|
||||||
|
${form_globals.textLikeInput}
|
||||||
|
${form_globals.textLikeInputTight}
|
||||||
|
${form_globals.selectInput}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<option value="yes">Allow this</option>
|
||||||
|
<option value="ask">Require asking</option>
|
||||||
|
<option value="no">Don't do this</option>
|
||||||
|
</Field>
|
||||||
|
</div>
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
<p className={globals.titleSmall}>Fanart with other characters</p>
|
||||||
|
<span className={globals.text}>Allow others to draw fanart of your characters with other characters.</span>
|
||||||
|
<Field
|
||||||
|
as="select"
|
||||||
|
name="policies.fanartOthers"
|
||||||
|
placeholder="Troll"
|
||||||
|
className={`
|
||||||
|
${form_globals.textLikeInput}
|
||||||
|
${form_globals.textLikeInputTight}
|
||||||
|
${form_globals.selectInput}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<option value="yes">Allow this</option>
|
||||||
|
<option value="ask">Require asking</option>
|
||||||
|
<option value="no">Don't do this</option>
|
||||||
|
</Field>
|
||||||
|
</div>
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
<p className={globals.titleSmall}>Kinning</p>
|
||||||
|
<span className={globals.text}>Allow others to kin your characters.</span>
|
||||||
|
<Field
|
||||||
|
as="select"
|
||||||
|
name="policies.kinning"
|
||||||
|
placeholder="Troll"
|
||||||
|
className={`
|
||||||
|
${form_globals.textLikeInput}
|
||||||
|
${form_globals.textLikeInputTight}
|
||||||
|
${form_globals.selectInput}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<option value="yes">Allow this</option>
|
||||||
|
<option value="ask">Require asking</option>
|
||||||
|
<option value="no">Don't do this</option>
|
||||||
|
</Field>
|
||||||
|
</div>
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
<p className={globals.titleSmall}>Shipping</p>
|
||||||
|
<Field
|
||||||
|
as="select"
|
||||||
|
name="policies.shipping"
|
||||||
|
placeholder="Troll"
|
||||||
|
className={`
|
||||||
|
${form_globals.textLikeInput}
|
||||||
|
${form_globals.textLikeInputTight}
|
||||||
|
${form_globals.selectInput}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<option value="yes">Allow this</option>
|
||||||
|
<option value="ask">Require asking</option>
|
||||||
|
<option value="no">Don't do this</option>
|
||||||
|
</Field>
|
||||||
|
</div>
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
<p className={globals.titleSmall}>Fanfiction</p>
|
||||||
|
<Field
|
||||||
|
as="select"
|
||||||
|
name="policies.fanfiction"
|
||||||
|
placeholder="Troll"
|
||||||
|
className={`
|
||||||
|
${form_globals.textLikeInput}
|
||||||
|
${form_globals.textLikeInputTight}
|
||||||
|
${form_globals.selectInput}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<option value="yes">Allow this</option>
|
||||||
|
<option value="ask">Require asking</option>
|
||||||
|
<option value="no">Don't do this</option>
|
||||||
|
</Field>
|
||||||
|
</div>
|
||||||
|
<ErrorMessage
|
||||||
|
name="policies"
|
||||||
|
render={ErrorHandler}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</div>
|
||||||
|
<hr className={globals.invisep} />
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
<div className={form_globals.verticalListCrunch}>
|
||||||
|
<p className={globals.titleSmall}>BG Image</p>
|
||||||
|
<span className={globals.text}>An image that will display as a banner.</span>
|
||||||
|
<span className={globals.text}>Supporter/moderator only.</span>
|
||||||
|
</div>
|
||||||
|
<div className={form_globals.horizlist}>
|
||||||
|
<span className={globals.icon}>image</span>
|
||||||
|
<Field
|
||||||
|
type="text"
|
||||||
|
name="bgimage"
|
||||||
|
placeholder="https://example.com/"
|
||||||
|
className={`
|
||||||
|
${form_globals.textLikeInput}
|
||||||
|
${form_globals.textLikeInputTight}
|
||||||
|
`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<ErrorMessage
|
||||||
|
name="bgimage"
|
||||||
|
render={ErrorHandler}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<hr className={globals.invisep} />
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
<div className={form_globals.verticalListCrunch}>
|
||||||
|
<p className={globals.titleSmall}>CSS</p>
|
||||||
|
<span className={globals.text}>Styling that is applied when your user page is accessed.</span>
|
||||||
|
<span className={globals.text}>Supporter/moderator only.</span>
|
||||||
|
</div>
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
<Field
|
||||||
|
as="textarea"
|
||||||
|
name="css"
|
||||||
|
placeholder="CSS"
|
||||||
|
className={`
|
||||||
|
${form_globals.textLikeInput}
|
||||||
|
${form_globals.textLikeInputMultiline}
|
||||||
|
${form_globals.textLikeInputMono}
|
||||||
|
`}
|
||||||
|
/>
|
||||||
|
<ErrorMessage
|
||||||
|
name="css"
|
||||||
|
render={ErrorHandler}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr className={globals.invisep} />
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
<div className={form_globals.verticalListCrunch}>
|
||||||
|
<p className={globals.titleSmall}>Code</p>
|
||||||
|
<span className={globals.text}>
|
||||||
|
The authentication code for your clan. If this is left blank, it will be randomly generated.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
<div className={globals.horizontalListLeft}>
|
||||||
|
<Field
|
||||||
|
type="password"
|
||||||
|
name="code"
|
||||||
|
placeholder="Tim Sweeney"
|
||||||
|
className={`
|
||||||
|
${form_globals.textLikeInput}
|
||||||
|
${form_globals.textLikeInputTight}
|
||||||
|
`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<ErrorMessage
|
||||||
|
name="code"
|
||||||
|
render={ErrorHandler}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={`
|
||||||
|
${form_globals.verticalListCrunch}
|
||||||
|
${form_globals.layoutAppearable}
|
||||||
|
${values.code != initialValues.code && errors.code == null ? form_globals.appear : ""}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<span className={`${form_globals.render_info}`}>
|
||||||
|
<span className={form_globals.iconSmall}>info</span>{" "}
|
||||||
|
<span className={`${globals.text}`}>
|
||||||
|
Make sure to make this somewhat secure! You can share this code with friends, but make sure you trust them.
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Box>
|
||||||
|
<Box properties={{ title: { text: "Form Settings" } }}>
|
||||||
|
<div className={globals.horizontalListLeft}>
|
||||||
|
<button
|
||||||
|
type="reset"
|
||||||
|
className={globals.button}
|
||||||
|
disabled={isSubmitting}
|
||||||
|
// onClick={() => resetForm()}
|
||||||
|
>
|
||||||
|
Reset Form
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className={globals.button}
|
||||||
|
disabled={isSubmitting}
|
||||||
|
// onClick={submitForm}
|
||||||
|
>
|
||||||
|
Submit Form
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className={globals.horizontalListLeft}>{submitError != null && submitError.length > 0 ? ErrorHandler(submitError) : ""}</div>
|
||||||
|
<details>
|
||||||
|
<summary>Advanced stuff</summary>
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
<details>
|
||||||
|
<summary>Values (Advanced)</summary>
|
||||||
|
<p className={`${globals.mono} ${globals.blockTextKeepTabs}`}>{JSON.stringify(values, null, 2)}</p>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>Errors (Advanced)</summary>
|
||||||
|
<p className={`${globals.mono} ${globals.blockTextKeepTabs}`}>{JSON.stringify(errors, null, 2)}</p>
|
||||||
|
</details>
|
||||||
|
<p className={globals.text}>If something is wrong, make sure to send these with your report!</p>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
</Box>
|
||||||
|
</Form>
|
||||||
|
)}
|
||||||
|
</Formik>
|
||||||
|
);
|
||||||
|
}
|
1453
src/components/form/template/troll.tsx
Normal file
1453
src/components/form/template/troll.tsx
Normal file
File diff suppressed because it is too large
Load diff
90
src/components/template/credits.tsx
Normal file
90
src/components/template/credits.tsx
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
import globals from "@/styles/global.module.css";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
export default function Credits() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p className={globals.text}>
|
||||||
|
TrollCall rev. 4 created with ❤️ by MeowcaTheoRange using{" "}
|
||||||
|
<Link
|
||||||
|
href="https://nextjs.org/"
|
||||||
|
className={globals.link}
|
||||||
|
>
|
||||||
|
Next.js
|
||||||
|
</Link>{" "}
|
||||||
|
(Pages Router).
|
||||||
|
</p>
|
||||||
|
<p className={globals.text}>
|
||||||
|
<b>trollcall.xyz</b> domain owned by [person who is not me].
|
||||||
|
</p>
|
||||||
|
<p className={globals.text}>
|
||||||
|
The TrollCall name is derived from the original Hiveswap Troll
|
||||||
|
Call. The name may be used in an entity context or a project
|
||||||
|
context.
|
||||||
|
</p>
|
||||||
|
<p className={globals.text}>
|
||||||
|
The textboxes found in the [INSERT PAGE HERE] are inspired by
|
||||||
|
those from the game <b>Celeste</b>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span className={globals.blockText}>
|
||||||
|
<Link
|
||||||
|
className={globals.link}
|
||||||
|
href="https://github.com/MeowcaTheoRange/Fonts"
|
||||||
|
>
|
||||||
|
TrollCall Display
|
||||||
|
</Link>{" "}
|
||||||
|
font by MeowcaTheoRange.
|
||||||
|
</span>
|
||||||
|
<span className={globals.blockText}>
|
||||||
|
<Link
|
||||||
|
className={globals.link}
|
||||||
|
href="https://fonts.google.com/specimen/Space+Grotesk"
|
||||||
|
>
|
||||||
|
Space Grotesk
|
||||||
|
</Link>{" "}
|
||||||
|
font by Florian Karsten.
|
||||||
|
</span>
|
||||||
|
<span className={globals.blockText}>
|
||||||
|
<Link
|
||||||
|
className={globals.link}
|
||||||
|
href="https://fonts.google.com/specimen/Space+Mono"
|
||||||
|
>
|
||||||
|
Space Mono
|
||||||
|
</Link>{" "}
|
||||||
|
font by Colophon Foundry.
|
||||||
|
</span>
|
||||||
|
<span className={globals.blockText}>
|
||||||
|
<Link
|
||||||
|
className={globals.link}
|
||||||
|
href="https://fonts.google.com/specimen/Poppins"
|
||||||
|
>
|
||||||
|
Poppins
|
||||||
|
</Link>{" "}
|
||||||
|
font by Indian Type Foundry.
|
||||||
|
</span>
|
||||||
|
<span className={globals.blockText}>
|
||||||
|
<Link
|
||||||
|
className={globals.link}
|
||||||
|
href="https://fonts.google.com/specimen/Flow+Circular"
|
||||||
|
>
|
||||||
|
Flow Circular
|
||||||
|
</Link>{" "}
|
||||||
|
font by Dan Ross.
|
||||||
|
</span>
|
||||||
|
<span className={globals.blockText}>
|
||||||
|
<Link
|
||||||
|
className={globals.link}
|
||||||
|
href="https://www.creativefabrica.com/product/renogare/"
|
||||||
|
>
|
||||||
|
Renogare
|
||||||
|
</Link>{" "}
|
||||||
|
font by Deepak Dogra.
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<p className={globals.text}>
|
||||||
|
Homestuck and HIVESWAP © Homestuck Inc.
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
18
src/components/template/not-signed-in-clan.tsx
Normal file
18
src/components/template/not-signed-in-clan.tsx
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import globals from "@/styles/global.module.css";
|
||||||
|
import Box from "../Box/Box";
|
||||||
|
|
||||||
|
export default function NotSignedInClan({ clan }: { clan: string }) {
|
||||||
|
return (
|
||||||
|
<Box properties={{ title: { text: "Not Signed In" } }}>
|
||||||
|
<p className={globals.text}>
|
||||||
|
You need to part of the {clan} clan to perform this action!
|
||||||
|
</p>
|
||||||
|
<a
|
||||||
|
className={globals.link}
|
||||||
|
href="/manage"
|
||||||
|
>
|
||||||
|
Join the {clan} clan
|
||||||
|
</a>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
24
src/components/template/not-signed-in.tsx
Normal file
24
src/components/template/not-signed-in.tsx
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import globals from "@/styles/global.module.css";
|
||||||
|
import Box from "../Box/Box";
|
||||||
|
|
||||||
|
export default function NotSignedIn() {
|
||||||
|
return (
|
||||||
|
<Box properties={{ title: { text: "Not Signed In" } }}>
|
||||||
|
<p className={globals.text}>
|
||||||
|
You need to part a clan to perform this action!
|
||||||
|
</p>
|
||||||
|
<a
|
||||||
|
className={globals.link}
|
||||||
|
href="/manage"
|
||||||
|
>
|
||||||
|
Join a clan
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
className={globals.link}
|
||||||
|
href="/add/clan"
|
||||||
|
>
|
||||||
|
Create a clan
|
||||||
|
</a>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
18
src/components/template/too-signed-in.tsx
Normal file
18
src/components/template/too-signed-in.tsx
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import globals from "@/styles/global.module.css";
|
||||||
|
import Box from "../Box/Box";
|
||||||
|
|
||||||
|
export default function TooSignedIn() {
|
||||||
|
return (
|
||||||
|
<Box properties={{ title: { text: "Signed In" } }}>
|
||||||
|
<p className={globals.text}>
|
||||||
|
You can't be part a clan to perform this action!
|
||||||
|
</p>
|
||||||
|
<a
|
||||||
|
className={globals.link}
|
||||||
|
href="/manage"
|
||||||
|
>
|
||||||
|
Log out
|
||||||
|
</a>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
|
@ -26,3 +26,5 @@ if (process.env.NODE_ENV === "development") {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mainDB = client.db(process.env.MONGODB_DATABASE_NAME);
|
export const mainDB = client.db(process.env.MONGODB_DATABASE_NAME);
|
||||||
|
|
||||||
|
export const firstDB = client.db("trollcall");
|
||||||
|
|
|
@ -17,11 +17,12 @@ export async function ClanGET(
|
||||||
: await getSingleClan(query);
|
: await getSingleClan(query);
|
||||||
if (clan == null) return null;
|
if (clan == null) return null;
|
||||||
const serverClan = await ServerClanToClientClan({ ...clan });
|
const serverClan = await ServerClanToClientClan({ ...clan });
|
||||||
serverClan.flairs = cutArray(
|
if (clan.flairs != null)
|
||||||
await getManyFlairs(
|
serverClan.flairs = cutArray(
|
||||||
{ _id: { $in: clan.flairs } },
|
await getManyFlairs(
|
||||||
ServerFlairToClientFlair
|
{ _id: { $in: clan.flairs } },
|
||||||
)
|
ServerFlairToClientFlair
|
||||||
);
|
)
|
||||||
|
);
|
||||||
return serverClan as ClientClan;
|
return serverClan as ClientClan;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,12 +30,13 @@ export async function TrollGET(
|
||||||
});
|
});
|
||||||
if (troll == null) return null;
|
if (troll == null) return null;
|
||||||
const serverTroll = await ServerTrollToClientTroll(troll);
|
const serverTroll = await ServerTrollToClientTroll(troll);
|
||||||
serverTroll.flairs = cutArray(
|
if (troll.flairs != null)
|
||||||
await getManyFlairs(
|
serverTroll.flairs = cutArray(
|
||||||
{ _id: { $in: troll.flairs } },
|
await getManyFlairs(
|
||||||
ServerFlairToClientFlair
|
{ _id: { $in: troll.flairs } },
|
||||||
)
|
ServerFlairToClientFlair
|
||||||
);
|
)
|
||||||
|
);
|
||||||
// we know this is not null, as we passed in our own clan
|
// we know this is not null, as we passed in our own clan
|
||||||
serverTroll.owner = (await ClanGET(null, clan)) as ClientClan;
|
serverTroll.owner = (await ClanGET(null, clan)) as ClientClan;
|
||||||
return serverTroll as ClientTroll;
|
return serverTroll as ClientTroll;
|
||||||
|
|
|
@ -14,6 +14,13 @@ export async function ServerClanToClientClan(
|
||||||
return clientClan;
|
return clientClan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function ClientClanToSubmitClan(clientClan: ClientClan): SubmitClan {
|
||||||
|
let serverClan: SubmitClan = {
|
||||||
|
...clientClan
|
||||||
|
};
|
||||||
|
return serverClan;
|
||||||
|
}
|
||||||
|
|
||||||
export function SubmitClanToServerClan(
|
export function SubmitClanToServerClan(
|
||||||
submitClan: Partial<SubmitClan>
|
submitClan: Partial<SubmitClan>
|
||||||
): Omit<Partial<ServerClan>, "_id"> {
|
): Omit<Partial<ServerClan>, "_id"> {
|
||||||
|
|
|
@ -10,7 +10,10 @@ export async function ServerTrollToClientTroll(
|
||||||
|
|
||||||
let clientTroll: Partial<ClientTroll> = {
|
let clientTroll: Partial<ClientTroll> = {
|
||||||
...sanitizedTroll,
|
...sanitizedTroll,
|
||||||
trueSign: TrueSign[serverTroll.trueSign],
|
trueSign:
|
||||||
|
serverTroll.trueSign != null
|
||||||
|
? TrueSign[serverTroll.trueSign]
|
||||||
|
: null,
|
||||||
falseSign:
|
falseSign:
|
||||||
serverTroll.falseSign != null
|
serverTroll.falseSign != null
|
||||||
? TrueSign[serverTroll.falseSign]
|
? TrueSign[serverTroll.falseSign]
|
||||||
|
@ -24,6 +27,24 @@ export async function ServerTrollToClientTroll(
|
||||||
return clientTroll;
|
return clientTroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function ClientTrollToSubmitTroll(
|
||||||
|
clientTroll: ClientTroll
|
||||||
|
): SubmitTroll {
|
||||||
|
let submitTroll: SubmitTroll = {
|
||||||
|
...clientTroll,
|
||||||
|
quirks: clientTroll.quirks
|
||||||
|
? Object.entries(clientTroll.quirks)
|
||||||
|
: undefined,
|
||||||
|
trueSign: clientTroll.trueSign ? clientTroll.trueSign.name : undefined,
|
||||||
|
falseSign: clientTroll.falseSign
|
||||||
|
? clientTroll.falseSign.name
|
||||||
|
: undefined,
|
||||||
|
class: clientTroll.class ? clientTroll.class.name : undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
return submitTroll;
|
||||||
|
}
|
||||||
|
|
||||||
export function SubmitTrollToServerTroll(
|
export function SubmitTrollToServerTroll(
|
||||||
submitTroll: Partial<SubmitTroll>
|
submitTroll: Partial<SubmitTroll>
|
||||||
): Omit<Partial<ServerTroll>, "_id"> {
|
): Omit<Partial<ServerTroll>, "_id"> {
|
||||||
|
|
|
@ -1,48 +1,56 @@
|
||||||
import Ads from "@/components/Ads/Ads";
|
import Ads from "@/components/Ads/Ads";
|
||||||
import Box from "@/components/Box/Box";
|
import Box from "@/components/Box/Box";
|
||||||
import Nav from "@/components/Nav/Nav";
|
import Nav from "@/components/Nav/Nav";
|
||||||
|
import Credits from "@/components/template/credits";
|
||||||
import "@/styles/_app.css";
|
import "@/styles/_app.css";
|
||||||
import "@/styles/global.module.css";
|
import "@/styles/global.module.css";
|
||||||
import globals from "@/styles/global.module.css";
|
import globals from "@/styles/global.module.css";
|
||||||
import { Color3 } from "@/types/assist/color";
|
import { ThemeGet, ThemeGetOpt } from "@/types/generics";
|
||||||
import AuthContext from "@/utility/react/AuthContext";
|
import AuthContext from "@/utility/react/AuthContext";
|
||||||
import Themer, { ThemeModeContext } from "@/utility/react/Themer";
|
import Themer, { ThemeModeContext, defaultTheme } from "@/utility/react/Themer";
|
||||||
import { getCookies } from "cookies-next";
|
import { getCookies } from "cookies-next";
|
||||||
import type { AppProps } from "next/app";
|
import type { AppProps } from "next/app";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
export default function App({ Component, pageProps }: AppProps) {
|
export default function App({ Component, pageProps }: AppProps) {
|
||||||
const [theme, setTheme] = useState([
|
const router = useRouter();
|
||||||
new Color3(0.9, 0.9, 0.8),
|
const [theme, setTheme] = useState(defaultTheme as ThemeGet);
|
||||||
new Color3(0.7, 0.7, 0.6),
|
function themeSetWrapper(themeSetter: ThemeGetOpt) {
|
||||||
false
|
setTheme([
|
||||||
] as [Color3, Color3, boolean?]);
|
themeSetter[0] ?? theme[0],
|
||||||
const [width, setWidth] = useState(768);
|
themeSetter[1] ?? theme[1],
|
||||||
|
themeSetter[2] ?? theme[2],
|
||||||
|
themeSetter[3] ?? theme[3]
|
||||||
|
] as ThemeGet);
|
||||||
|
}
|
||||||
const cookies = getCookies() as {
|
const cookies = getCookies() as {
|
||||||
TROLLCALL_NAME: string;
|
TROLLCALL_NAME: string;
|
||||||
TROLLCALL_CODE: string;
|
TROLLCALL_CODE: string;
|
||||||
};
|
};
|
||||||
|
// useEffect(() => {
|
||||||
|
// setTheme(defaultTheme);
|
||||||
|
// }, [router.asPath]);
|
||||||
return (
|
return (
|
||||||
<main className={"App" + (theme[2] ? " " + "inverted" : "")}>
|
<main className={"App" + (theme[3] ? " " + "inverted" : "")}>
|
||||||
<Themer
|
<Themer
|
||||||
pri={theme[0]}
|
pri={theme[0]}
|
||||||
sec={theme[1]}
|
sec={theme[1]}
|
||||||
inverted={theme[2]}
|
inverted={theme[3]}
|
||||||
/>
|
/>
|
||||||
<AuthContext.Provider value={cookies}>
|
<AuthContext.Provider value={cookies}>
|
||||||
<Nav />
|
<Nav />
|
||||||
<ThemeModeContext.Provider value={theme[2]}>
|
<ThemeModeContext.Provider value={theme[3]}>
|
||||||
<div
|
<div
|
||||||
className={"mainContent"}
|
className={"mainContent"}
|
||||||
style={{
|
style={{
|
||||||
maxWidth: width
|
maxWidth: theme[2]
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Component
|
<Component
|
||||||
{...pageProps}
|
{...pageProps}
|
||||||
themerVars={[theme, setTheme]}
|
themerVars={[theme, themeSetWrapper]}
|
||||||
widthVars={[width, setWidth]}
|
|
||||||
/>
|
/>
|
||||||
<Box
|
<Box
|
||||||
properties={{
|
properties={{
|
||||||
|
@ -81,81 +89,7 @@ export default function App({ Component, pageProps }: AppProps) {
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
</p>
|
</p>
|
||||||
<p className={globals.text}>
|
<Credits />
|
||||||
TrollCall rev. 4 created by MeowcaTheoRange.
|
|
||||||
</p>
|
|
||||||
<p className={globals.text}>
|
|
||||||
<b>trollcall.xyz</b> domain owned by Redact.
|
|
||||||
</p>
|
|
||||||
<p className={globals.text}>
|
|
||||||
The TrollCall name is derived from the original
|
|
||||||
Hiveswap Troll Call. The name may be used in an
|
|
||||||
entity context or a project context.
|
|
||||||
</p>
|
|
||||||
<p className={globals.text}>
|
|
||||||
The textboxes found in the [INSERT PAGE HERE]
|
|
||||||
are inspired by those from the game{" "}
|
|
||||||
<b>Celeste</b>.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<span className={globals.blockText}>
|
|
||||||
<Link
|
|
||||||
className={globals.link}
|
|
||||||
href="https://github.com/MeowcaTheoRange/Fonts"
|
|
||||||
>
|
|
||||||
TrollCall Display
|
|
||||||
</Link>{" "}
|
|
||||||
font by MeowcaTheoRange.
|
|
||||||
</span>
|
|
||||||
<span className={globals.blockText}>
|
|
||||||
<Link
|
|
||||||
className={globals.link}
|
|
||||||
href="https://fonts.google.com/specimen/Space+Grotesk"
|
|
||||||
>
|
|
||||||
Space Grotesk
|
|
||||||
</Link>{" "}
|
|
||||||
font by Florian Karsten.
|
|
||||||
</span>
|
|
||||||
<span className={globals.blockText}>
|
|
||||||
<Link
|
|
||||||
className={globals.link}
|
|
||||||
href="https://fonts.google.com/specimen/Space+Mono"
|
|
||||||
>
|
|
||||||
Space Mono
|
|
||||||
</Link>{" "}
|
|
||||||
font by Colophon Foundry.
|
|
||||||
</span>
|
|
||||||
<span className={globals.blockText}>
|
|
||||||
<Link
|
|
||||||
className={globals.link}
|
|
||||||
href="https://fonts.google.com/specimen/Poppins"
|
|
||||||
>
|
|
||||||
Poppins
|
|
||||||
</Link>{" "}
|
|
||||||
font by Indian Type Foundry.
|
|
||||||
</span>
|
|
||||||
<span className={globals.blockText}>
|
|
||||||
<Link
|
|
||||||
className={globals.link}
|
|
||||||
href="https://fonts.google.com/specimen/Flow+Circular"
|
|
||||||
>
|
|
||||||
Flow Circular
|
|
||||||
</Link>{" "}
|
|
||||||
font by Dan Ross.
|
|
||||||
</span>
|
|
||||||
<span className={globals.blockText}>
|
|
||||||
<Link
|
|
||||||
className={globals.link}
|
|
||||||
href="https://www.creativefabrica.com/product/renogare/"
|
|
||||||
>
|
|
||||||
Renogare
|
|
||||||
</Link>{" "}
|
|
||||||
font by Deepak Dogra.
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<p className={globals.text}>
|
|
||||||
Homestuck and HIVESWAP © Homestuck Inc.
|
|
||||||
</p>
|
|
||||||
</Box>
|
</Box>
|
||||||
</div>
|
</div>
|
||||||
</ThemeModeContext.Provider>
|
</ThemeModeContext.Provider>
|
||||||
|
|
36
src/pages/add/clan/index.tsx
Normal file
36
src/pages/add/clan/index.tsx
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import Box from "@/components/Box/Box";
|
||||||
|
import ClanFormTemplate from "@/components/form/template/clan";
|
||||||
|
import TooSignedIn from "@/components/template/too-signed-in";
|
||||||
|
import globals from "@/styles/global.module.css";
|
||||||
|
import { ThemerGetSet } from "@/types/generics";
|
||||||
|
import AuthContext from "@/utility/react/AuthContext";
|
||||||
|
import { defaultTheme } from "@/utility/react/Themer";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import { useContext, useEffect, useState } from "react";
|
||||||
|
|
||||||
|
export default function AddClan({
|
||||||
|
themerVars: [theme, setTheme]
|
||||||
|
}: {
|
||||||
|
themerVars: ThemerGetSet;
|
||||||
|
}) {
|
||||||
|
const userCredentials = useContext(AuthContext);
|
||||||
|
const router = useRouter();
|
||||||
|
// Prevent hydration error. Nav Auth section is a client-rendered element.
|
||||||
|
const [isClient, setIsClient] = useState(false);
|
||||||
|
useEffect(() => {
|
||||||
|
setIsClient(true);
|
||||||
|
setTheme(defaultTheme);
|
||||||
|
}, []);
|
||||||
|
return isClient && userCredentials.TROLLCALL_NAME == null ? (
|
||||||
|
<>
|
||||||
|
<Box properties={{ title: { text: "Add Clan" } }}>
|
||||||
|
<span className={globals.text}>
|
||||||
|
Create a clan to contribute to the site!
|
||||||
|
</span>
|
||||||
|
</Box>
|
||||||
|
<ClanFormTemplate router={router} />
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<TooSignedIn />
|
||||||
|
);
|
||||||
|
}
|
39
src/pages/add/troll/index.tsx
Normal file
39
src/pages/add/troll/index.tsx
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
import Box from "@/components/Box/Box";
|
||||||
|
import TrollFormTemplate from "@/components/form/template/troll";
|
||||||
|
import NotSignedIn from "@/components/template/not-signed-in";
|
||||||
|
import globals from "@/styles/global.module.css";
|
||||||
|
import { ThemerGetSet } from "@/types/generics";
|
||||||
|
import AuthContext from "@/utility/react/AuthContext";
|
||||||
|
import { defaultTheme } from "@/utility/react/Themer";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import { useContext, useEffect, useState } from "react";
|
||||||
|
|
||||||
|
export default function AddTroll({
|
||||||
|
themerVars: [theme, setTheme]
|
||||||
|
}: {
|
||||||
|
themerVars: ThemerGetSet;
|
||||||
|
}) {
|
||||||
|
const userCredentials = useContext(AuthContext);
|
||||||
|
const router = useRouter();
|
||||||
|
// Prevent hydration error. Nav Auth section is a client-rendered element.
|
||||||
|
const [isClient, setIsClient] = useState(false);
|
||||||
|
useEffect(() => {
|
||||||
|
setIsClient(true);
|
||||||
|
setTheme(defaultTheme);
|
||||||
|
}, []);
|
||||||
|
return isClient && userCredentials.TROLLCALL_NAME != null ? (
|
||||||
|
<>
|
||||||
|
<Box properties={{ title: { text: "Add Troll" } }}>
|
||||||
|
<span className={globals.text}>
|
||||||
|
Add one of your own to TrollCall.
|
||||||
|
</span>
|
||||||
|
</Box>
|
||||||
|
<TrollFormTemplate
|
||||||
|
user={userCredentials}
|
||||||
|
router={router}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<NotSignedIn />
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,9 +1,6 @@
|
||||||
import { ClanGET } from "@/lib/trollcall/api/clan";
|
import { ClanGET } from "@/lib/trollcall/api/clan";
|
||||||
import { getManyPagedClans } from "@/lib/trollcall/clan";
|
import { getManyPagedClans } from "@/lib/trollcall/clan";
|
||||||
import { ServerClanToClientClan } from "@/lib/trollcall/convert/clan";
|
import { ServerClanToClientClan } from "@/lib/trollcall/convert/clan";
|
||||||
import { ServerFlairToClientFlair } from "@/lib/trollcall/convert/flair";
|
|
||||||
import { getManyFlairs } from "@/lib/trollcall/flair";
|
|
||||||
import { cutArray } from "@/lib/trollcall/utility/merge";
|
|
||||||
import { ClientClan } from "@/types/clan";
|
import { ClientClan } from "@/types/clan";
|
||||||
import { NextApiRequest, NextApiResponse } from "next";
|
import { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
|
||||||
|
@ -19,12 +16,12 @@ export default async function handler(
|
||||||
async (clan: any) => {
|
async (clan: any) => {
|
||||||
let thisClan = await ServerClanToClientClan(clan);
|
let thisClan = await ServerClanToClientClan(clan);
|
||||||
thisClan = (await ClanGET(null, clan)) as ClientClan;
|
thisClan = (await ClanGET(null, clan)) as ClientClan;
|
||||||
thisClan.flairs = cutArray(
|
// if(thisClan.flairs != null) thisClan.flairs = cutArray(
|
||||||
await getManyFlairs(
|
// await getManyFlairs(
|
||||||
{ _id: { $in: clan.flairs } },
|
// { _id: { $in: clan.flairs } },
|
||||||
ServerFlairToClientFlair
|
// ServerFlairToClientFlair
|
||||||
)
|
// )
|
||||||
);
|
// );
|
||||||
return thisClan;
|
return thisClan;
|
||||||
},
|
},
|
||||||
5,
|
5,
|
||||||
|
|
|
@ -55,10 +55,15 @@ export default async function handler(
|
||||||
if (serverClan.code == null)
|
if (serverClan.code == null)
|
||||||
serverClan.code = checkExistingClan.code || nanoid(16);
|
serverClan.code = checkExistingClan.code || nanoid(16);
|
||||||
|
|
||||||
|
const currentcode = serverClan.code;
|
||||||
|
|
||||||
// Encrypt code lole
|
// Encrypt code lole
|
||||||
serverClan.code = await hash(serverClan.code);
|
serverClan.code = await hash(serverClan.code);
|
||||||
|
|
||||||
if (!compareLevels(getLevel(checkExistingClan), "SUPPORTER")) {
|
if (
|
||||||
|
serverClan.flairs != null &&
|
||||||
|
!compareLevels(getLevel(checkExistingClan), "SUPPORTER")
|
||||||
|
) {
|
||||||
serverClan.bgimage = null;
|
serverClan.bgimage = null;
|
||||||
serverClan.css = null;
|
serverClan.css = null;
|
||||||
}
|
}
|
||||||
|
@ -73,11 +78,7 @@ export default async function handler(
|
||||||
path: "/",
|
path: "/",
|
||||||
maxAge: 31540000
|
maxAge: 31540000
|
||||||
}),
|
}),
|
||||||
serialize("TROLLCALL_CODE", newClan.code, {
|
serialize("TROLLCALL_CODE", currentcode, {
|
||||||
path: "/",
|
|
||||||
maxAge: 31540000
|
|
||||||
}),
|
|
||||||
serialize("TROLLCALL_PFP", newClan.pfp ?? "", {
|
|
||||||
path: "/",
|
path: "/",
|
||||||
maxAge: 31540000
|
maxAge: 31540000
|
||||||
})
|
})
|
||||||
|
|
|
@ -33,11 +33,18 @@ export default async function handler(
|
||||||
>;
|
>;
|
||||||
if (serverClan.code == null) serverClan.code = nanoid(16);
|
if (serverClan.code == null) serverClan.code = nanoid(16);
|
||||||
|
|
||||||
// Encrypt code lole
|
const currentcode = serverClan.code;
|
||||||
serverClan.code = hash(serverClan.code).toString();
|
|
||||||
|
|
||||||
if (!compareLevels(getLevel(serverClan), "SUPPORTER"))
|
// Encrypt code lole
|
||||||
|
serverClan.code = await hash(serverClan.code).toString();
|
||||||
|
|
||||||
|
if (
|
||||||
|
serverClan.flairs != null &&
|
||||||
|
!compareLevels(getLevel(serverClan), "SUPPORTER")
|
||||||
|
) {
|
||||||
serverClan.bgimage = null;
|
serverClan.bgimage = null;
|
||||||
|
serverClan.css = null;
|
||||||
|
}
|
||||||
const newClan = await createClan(serverClan);
|
const newClan = await createClan(serverClan);
|
||||||
if (newClan == null) return res.status(503).end();
|
if (newClan == null) return res.status(503).end();
|
||||||
// Give cookies
|
// Give cookies
|
||||||
|
@ -46,11 +53,7 @@ export default async function handler(
|
||||||
path: "/",
|
path: "/",
|
||||||
maxAge: 31540000
|
maxAge: 31540000
|
||||||
}),
|
}),
|
||||||
serialize("TROLLCALL_CODE", newClan.code, {
|
serialize("TROLLCALL_CODE", currentcode, {
|
||||||
path: "/",
|
|
||||||
maxAge: 31540000
|
|
||||||
}),
|
|
||||||
serialize("TROLLCALL_PFP", newClan.pfp ?? "", {
|
|
||||||
path: "/",
|
path: "/",
|
||||||
maxAge: 31540000
|
maxAge: 31540000
|
||||||
})
|
})
|
||||||
|
|
143
src/pages/api/convert/index.ts
Normal file
143
src/pages/api/convert/index.ts
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
// import { Filter, cursorToArray } from "@/lib/db/crud";
|
||||||
|
// import { firstDB, mainDB } from "@/lib/db/mongodb";
|
||||||
|
// import { ServerClan } from "@/types/clan";
|
||||||
|
// import { ServerTroll } from "@/types/troll";
|
||||||
|
// import { AdaptivePossessive } from "@/utility/language";
|
||||||
|
// import { hash } from "argon2";
|
||||||
|
// import { Sort } from "mongodb";
|
||||||
|
// import { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
|
||||||
|
// export function readMany(
|
||||||
|
// collection: string,
|
||||||
|
// find: Filter<Document>,
|
||||||
|
// sort: Sort
|
||||||
|
// ) {
|
||||||
|
// const selectedCollection = firstDB.collection(collection);
|
||||||
|
// return selectedCollection.find(find).sort(sort);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export async function addMany(
|
||||||
|
// collection: string,
|
||||||
|
// items: { [key: string]: any }[]
|
||||||
|
// ) {
|
||||||
|
// const selectedCollection = mainDB.collection(collection);
|
||||||
|
// return await selectedCollection.insertMany(items, { ordered: true });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export default async function handler(
|
||||||
|
// req: NextApiRequest,
|
||||||
|
// res: NextApiResponse
|
||||||
|
// ) {
|
||||||
|
// const { body, cookies, query, method } = req;
|
||||||
|
// if (method === "GET") {
|
||||||
|
// const allUsers: ServerClan[] = await cursorToArray(
|
||||||
|
// readMany("users", {}, { "name": 1 }),
|
||||||
|
// async x => {
|
||||||
|
// const sc: ServerClan = {
|
||||||
|
// _id: x._id,
|
||||||
|
// updatedDate: new Date(x.updatedDate),
|
||||||
|
// displayName: AdaptivePossessive(x.name, "Clan"),
|
||||||
|
// url: x.url,
|
||||||
|
// color: x.color,
|
||||||
|
// pfp: x.pfp,
|
||||||
|
// bgimage: null,
|
||||||
|
// css: null,
|
||||||
|
// name: x.name,
|
||||||
|
// members: [
|
||||||
|
// {
|
||||||
|
// name: x.name,
|
||||||
|
// pronouns: [["they", "them", "theirs"]]
|
||||||
|
// }
|
||||||
|
// ],
|
||||||
|
// description: x.description,
|
||||||
|
// policies: {
|
||||||
|
// fanart: "no",
|
||||||
|
// fanartOthers: "no",
|
||||||
|
// kinning: "no",
|
||||||
|
// shipping: "no",
|
||||||
|
// fanfiction: "no"
|
||||||
|
// },
|
||||||
|
// code: await hash(x.code),
|
||||||
|
// flairs: []
|
||||||
|
// };
|
||||||
|
// return sc;
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
// let allTrolls: ServerTroll[] = await cursorToArray(
|
||||||
|
// readMany("trolls", {}, { "name.0": 1 }),
|
||||||
|
// async x => {
|
||||||
|
// const st: ServerTroll = {
|
||||||
|
// _id: x._id,
|
||||||
|
// policies: x.policies,
|
||||||
|
// updatedDate: x.updatedDate,
|
||||||
|
// gender: x.gender,
|
||||||
|
// facts: x.facts,
|
||||||
|
// trueSign: x.trueSign,
|
||||||
|
// falseSign: x.falseSign,
|
||||||
|
// class: x.class,
|
||||||
|
// username: x.username,
|
||||||
|
// textColor: x.textColor,
|
||||||
|
// pageColor: null,
|
||||||
|
// quotes: [],
|
||||||
|
// species: x.species,
|
||||||
|
// name: x.name,
|
||||||
|
// pronouns: x.pronouns,
|
||||||
|
// description: x.description,
|
||||||
|
// flairs: [],
|
||||||
|
// pronunciation: x.pronunciation,
|
||||||
|
// preferences: x.preferences,
|
||||||
|
// quirks: x.quirks,
|
||||||
|
// height: x.height,
|
||||||
|
// age: Math.floor(x.age * 2.1666 * 10) / 10,
|
||||||
|
// images: [x.image],
|
||||||
|
// owner: x.owners[0]
|
||||||
|
// };
|
||||||
|
// return st;
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
// const resultClans = await addMany("clans", allUsers);
|
||||||
|
// const resultTrolls = await addMany("trolls", allTrolls);
|
||||||
|
// return res
|
||||||
|
// .status(200)
|
||||||
|
// .json({ "users": resultClans, "trolls": resultTrolls });
|
||||||
|
// } else return res.status(405).end();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /*
|
||||||
|
// type ServerTroll = Omit<{
|
||||||
|
// policies?: {
|
||||||
|
// fanart: "yes" | "ask" | "no" | null;
|
||||||
|
// fanartOthers: "yes" | "ask" | "no" | null;
|
||||||
|
// kinning: "yes" | "ask" | "no" | null;
|
||||||
|
// shipping: "yes" | "ask" | "no" | null;
|
||||||
|
// fanfiction: "yes" | "ask" | "no" | null;
|
||||||
|
// } | null | undefined;
|
||||||
|
// updatedDate?: Date | undefined;
|
||||||
|
// gender?: string | undefined;
|
||||||
|
// facts?: string[] | undefined;
|
||||||
|
// trueSign?: string | null | undefined;
|
||||||
|
// falseSign?: string | null | undefined;
|
||||||
|
// class?: string | null | undefined;
|
||||||
|
// username?: string | undefined;
|
||||||
|
// textColor?: yup.Maybe<[number, number, number] | undefined>;
|
||||||
|
// pageColor?: yup.Maybe<[number, number, number] | undefined>;
|
||||||
|
// quotes?: string[] | undefined;
|
||||||
|
// species?: yup.Maybe<string | undefined>;
|
||||||
|
// name: [string, string];
|
||||||
|
// pronouns: [string, string, string][];
|
||||||
|
// description: string;
|
||||||
|
// flairs: ObjectId[];
|
||||||
|
// pronunciation: [string, string];
|
||||||
|
// preferences: {
|
||||||
|
// love?: string[] | undefined;
|
||||||
|
// hate?: string[] | undefined;
|
||||||
|
// };
|
||||||
|
// quirks: AnyPresentValue;
|
||||||
|
// height: number;
|
||||||
|
// age: number;
|
||||||
|
// images: string[];
|
||||||
|
// owner: ObjectId;
|
||||||
|
// }, "_id"> & {
|
||||||
|
// _id: ObjectId;
|
||||||
|
// }
|
||||||
|
// */
|
46
src/pages/api/test/signin/index.ts
Normal file
46
src/pages/api/test/signin/index.ts
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
import { getSingleClan } from "@/lib/trollcall/clan";
|
||||||
|
import { compareCredentials } from "@/lib/trollcall/perms";
|
||||||
|
import { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
|
||||||
|
export default async function handler(
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse
|
||||||
|
) {
|
||||||
|
const { body, cookies, query, method } = req;
|
||||||
|
if (method === "GET") {
|
||||||
|
if (cookies.TROLLCALL_NAME == null)
|
||||||
|
return res
|
||||||
|
.status(403)
|
||||||
|
.send("Can't authenticate (name is null, are you signed out?)");
|
||||||
|
if (cookies.TROLLCALL_CODE == null)
|
||||||
|
return res
|
||||||
|
.status(403)
|
||||||
|
.send("Can't authenticate (code is null, are you signed out?)");
|
||||||
|
const checkClan = await getSingleClan({
|
||||||
|
name: cookies.TROLLCALL_NAME
|
||||||
|
});
|
||||||
|
if (checkClan == null)
|
||||||
|
return res
|
||||||
|
.status(404)
|
||||||
|
.send(
|
||||||
|
"Can't authenticate (can't find clan \"" +
|
||||||
|
cookies.TROLLCALL_NAME +
|
||||||
|
'")'
|
||||||
|
);
|
||||||
|
if (await compareCredentials(checkClan, cookies))
|
||||||
|
return res
|
||||||
|
.status(200)
|
||||||
|
.send(
|
||||||
|
"Authenticated as " + checkClan.displayName ??
|
||||||
|
checkClan.name
|
||||||
|
);
|
||||||
|
else
|
||||||
|
return res
|
||||||
|
.status(403)
|
||||||
|
.send(
|
||||||
|
"Can't authenticate (trying as " +
|
||||||
|
(checkClan.displayName ?? checkClan.name) +
|
||||||
|
", check code?)"
|
||||||
|
);
|
||||||
|
} else return res.status(405).end();
|
||||||
|
}
|
|
@ -21,12 +21,13 @@ export default async function handler(
|
||||||
thisTroll.owner = (await ClanGET({
|
thisTroll.owner = (await ClanGET({
|
||||||
_id: troll.owner
|
_id: troll.owner
|
||||||
})) as ClientClan;
|
})) as ClientClan;
|
||||||
thisTroll.flairs = cutArray(
|
if (troll.flairs != null)
|
||||||
await getManyFlairs(
|
thisTroll.flairs = cutArray(
|
||||||
{ _id: { $in: troll.flairs } },
|
await getManyFlairs(
|
||||||
ServerFlairToClientFlair
|
{ _id: { $in: troll.flairs } },
|
||||||
)
|
ServerFlairToClientFlair
|
||||||
);
|
)
|
||||||
|
);
|
||||||
|
|
||||||
return thisTroll;
|
return thisTroll;
|
||||||
},
|
},
|
||||||
|
|
|
@ -27,12 +27,13 @@ export default async function handler(
|
||||||
async (troll: any) => {
|
async (troll: any) => {
|
||||||
const thisTroll = await ServerTrollToClientTroll(troll);
|
const thisTroll = await ServerTrollToClientTroll(troll);
|
||||||
thisTroll.owner = clientClan;
|
thisTroll.owner = clientClan;
|
||||||
thisTroll.flairs = cutArray(
|
if (troll.flairs != null)
|
||||||
await getManyFlairs(
|
thisTroll.flairs = cutArray(
|
||||||
{ _id: { $in: troll.flairs } },
|
await getManyFlairs(
|
||||||
ServerFlairToClientFlair
|
{ _id: { $in: troll.flairs } },
|
||||||
)
|
ServerFlairToClientFlair
|
||||||
);
|
)
|
||||||
|
);
|
||||||
|
|
||||||
return thisTroll;
|
return thisTroll;
|
||||||
},
|
},
|
||||||
|
|
|
@ -34,6 +34,7 @@ export default async function handler(
|
||||||
stripUnknown: true
|
stripUnknown: true
|
||||||
})) as Partial<SubmitTroll>;
|
})) as Partial<SubmitTroll>;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
return res.status(400).send(err);
|
return res.status(400).send(err);
|
||||||
}
|
}
|
||||||
const checkClan = await getSingleClan({
|
const checkClan = await getSingleClan({
|
||||||
|
|
|
@ -3,13 +3,17 @@ import ClanCard from "@/components/cards/ClanCard/ClanCard";
|
||||||
import TrollCard from "@/components/cards/TrollCard/TrollCard";
|
import TrollCard from "@/components/cards/TrollCard/TrollCard";
|
||||||
import TrollSkeleton from "@/components/cards/TrollCard/TrollSkeleton";
|
import TrollSkeleton from "@/components/cards/TrollCard/TrollSkeleton";
|
||||||
import { ClanGET } from "@/lib/trollcall/api/clan";
|
import { ClanGET } from "@/lib/trollcall/api/clan";
|
||||||
|
import { cutObject } from "@/lib/trollcall/utility/merge";
|
||||||
|
import globals from "@/styles/global.module.css";
|
||||||
import { Color3 } from "@/types/assist/color";
|
import { Color3 } from "@/types/assist/color";
|
||||||
import { ClientClan } from "@/types/clan";
|
import { ClientClan } from "@/types/clan";
|
||||||
import { ThemerGetSet } from "@/types/generics";
|
import { ThemerGetSet } from "@/types/generics";
|
||||||
import { ClientTroll } from "@/types/troll";
|
import { ClientTroll } from "@/types/troll";
|
||||||
|
import AuthContext from "@/utility/react/AuthContext";
|
||||||
import Conditional from "@/utility/react/Conditional";
|
import Conditional from "@/utility/react/Conditional";
|
||||||
import { GetServerSideProps, GetStaticPropsContext } from "next";
|
import { GetServerSideProps, GetStaticPropsContext } from "next";
|
||||||
import { useEffect, useState } from "react";
|
import Link from "next/link";
|
||||||
|
import { useContext, useEffect, useState } from "react";
|
||||||
|
|
||||||
export default function Index({
|
export default function Index({
|
||||||
themerVars: [theme, setTheme],
|
themerVars: [theme, setTheme],
|
||||||
|
@ -18,26 +22,39 @@ export default function Index({
|
||||||
themerVars: ThemerGetSet;
|
themerVars: ThemerGetSet;
|
||||||
clan: ClientClan;
|
clan: ClientClan;
|
||||||
}) {
|
}) {
|
||||||
|
// Get user creds
|
||||||
|
const userCredentials = useContext(AuthContext);
|
||||||
|
const [isClient, setIsClient] = useState(false);
|
||||||
|
useEffect(() => setIsClient(true), []);
|
||||||
|
|
||||||
|
// Get user trolls
|
||||||
const [fetchedTrolls, setFetchedTrolls] = useState<ClientTroll[] | null>(
|
const [fetchedTrolls, setFetchedTrolls] = useState<ClientTroll[] | null>(
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
async function getTroll(page?: number) {
|
||||||
|
const res = await fetch(
|
||||||
|
page ? "/api/troll/.../" + page : "/api/troll/..."
|
||||||
|
);
|
||||||
|
const json = await res.json();
|
||||||
|
setFetchedTrolls(json);
|
||||||
|
}
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function getTroll() {
|
getTroll(0);
|
||||||
const res = await fetch("/api/troll/" + clan.name + "/...");
|
|
||||||
const json = await res.json();
|
|
||||||
setFetchedTrolls(json);
|
|
||||||
}
|
|
||||||
getTroll();
|
|
||||||
const color = clan.color?.map(x => x / 255) as [number, number, number];
|
const color = clan.color?.map(x => x / 255) as [number, number, number];
|
||||||
if (color != null)
|
if (color != null)
|
||||||
setTheme([new Color3(...color), new Color3(...color).darken(50)]);
|
setTheme([
|
||||||
|
new Color3(...color),
|
||||||
|
new Color3(...color).darken(50),
|
||||||
|
768
|
||||||
|
]);
|
||||||
}, []);
|
}, []);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Conditional condition={clan.bgimage != null}>
|
<Conditional condition={clan.bgimage != null}>
|
||||||
<style>{`
|
<style>{`
|
||||||
main.App {
|
main.App {
|
||||||
background-image: linear-gradient(#0008, #0008), url(${clan.bgimage});
|
background-image: var(--darken), url(${clan.bgimage}) !important;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-repeat: repeat;
|
background-repeat: repeat;
|
||||||
background-position: 50% 50%;
|
background-position: 50% 50%;
|
||||||
|
@ -49,10 +66,34 @@ ${clan.css ?? ""}
|
||||||
clan={clan}
|
clan={clan}
|
||||||
link={false}
|
link={false}
|
||||||
/>
|
/>
|
||||||
|
{isClient && userCredentials.TROLLCALL_NAME == clan.name ? (
|
||||||
|
<Box
|
||||||
|
properties={{
|
||||||
|
title: {
|
||||||
|
text: "Admin"
|
||||||
|
},
|
||||||
|
theme: theme[1]
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<p>
|
||||||
|
Well, it seems you can manage{" "}
|
||||||
|
<b>{clan.displayName ?? clan.name}</b>! Have this menu.
|
||||||
|
</p>
|
||||||
|
<Link
|
||||||
|
className={globals.linkButton}
|
||||||
|
href={`/edit/clan/${clan.name}/`}
|
||||||
|
>
|
||||||
|
Edit Clan
|
||||||
|
</Link>
|
||||||
|
</Box>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
<Box
|
<Box
|
||||||
properties={{
|
properties={{
|
||||||
title: {
|
title: {
|
||||||
text: "Clan Trolls",
|
text: "Clan Trolls",
|
||||||
|
link: "/troll/s/" + clan.name,
|
||||||
small: true
|
small: true
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
@ -87,7 +128,7 @@ export const getServerSideProps: GetServerSideProps<{
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
clan
|
clan: cutObject(clan)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
76
src/pages/clan/s/index.tsx
Normal file
76
src/pages/clan/s/index.tsx
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
import Box from "@/components/Box/Box";
|
||||||
|
import ClanCard from "@/components/cards/ClanCard/ClanCard";
|
||||||
|
import ClanSkeleton from "@/components/cards/ClanCard/ClanSkeleton";
|
||||||
|
import globals from "@/styles/global.module.css";
|
||||||
|
import "@/styles/index.module.css";
|
||||||
|
import { ClientClan } from "@/types/clan";
|
||||||
|
import { ThemerGetSet } from "@/types/generics";
|
||||||
|
import { defaultTheme } from "@/utility/react/Themer";
|
||||||
|
import { getCookies } from "cookies-next";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
getCookies();
|
||||||
|
|
||||||
|
export default function Index({
|
||||||
|
themerVars: [theme, setTheme]
|
||||||
|
}: {
|
||||||
|
themerVars: ThemerGetSet;
|
||||||
|
}) {
|
||||||
|
const [fetchedClans, setFetchedClans] = useState<ClientClan[]>([]);
|
||||||
|
const [clanPageNum, setClanPageNum] = useState(0);
|
||||||
|
const [noMore, setNoMore] = useState(false);
|
||||||
|
async function getClan(page?: number) {
|
||||||
|
const res = await fetch(
|
||||||
|
page ? "/api/clan/.../" + page : "/api/clan/..."
|
||||||
|
);
|
||||||
|
const json = await res.json();
|
||||||
|
setFetchedClans(fetchedClans.concat(json));
|
||||||
|
setNoMore(json.length < 5);
|
||||||
|
}
|
||||||
|
useEffect(() => {
|
||||||
|
getClan(clanPageNum);
|
||||||
|
setTheme(defaultTheme);
|
||||||
|
}, [clanPageNum]);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Box
|
||||||
|
properties={{
|
||||||
|
title: {
|
||||||
|
text: "Explore clans"
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className={globals.text}>
|
||||||
|
See a list of all the clans on TrollCall.
|
||||||
|
</span>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
{fetchedClans.length <= 0 ? (
|
||||||
|
<>
|
||||||
|
<ClanSkeleton />
|
||||||
|
<ClanSkeleton />
|
||||||
|
<ClanSkeleton />
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{fetchedClans.map((clan: ClientClan, idx) => (
|
||||||
|
<ClanCard
|
||||||
|
clan={clan}
|
||||||
|
key={idx + "clan"}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<button
|
||||||
|
className={globals.button}
|
||||||
|
onClick={() => {
|
||||||
|
setClanPageNum(clanPageNum + 1);
|
||||||
|
}}
|
||||||
|
disabled={noMore}
|
||||||
|
>
|
||||||
|
Load more
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
65
src/pages/edit/clan/[clan]/index.tsx
Normal file
65
src/pages/edit/clan/[clan]/index.tsx
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import Box from "@/components/Box/Box";
|
||||||
|
import ClanFormTemplate from "@/components/form/template/clan";
|
||||||
|
import NotSignedInClan from "@/components/template/not-signed-in-clan";
|
||||||
|
import { ClanGET } from "@/lib/trollcall/api/clan";
|
||||||
|
import { ClientClanToSubmitClan } from "@/lib/trollcall/convert/clan";
|
||||||
|
import { cutObject } from "@/lib/trollcall/utility/merge";
|
||||||
|
import globals from "@/styles/global.module.css";
|
||||||
|
import { ClientClan } from "@/types/clan";
|
||||||
|
import { ThemerGetSet } from "@/types/generics";
|
||||||
|
import AuthContext from "@/utility/react/AuthContext";
|
||||||
|
import { defaultTheme } from "@/utility/react/Themer";
|
||||||
|
import { GetServerSideProps, GetStaticPropsContext } from "next";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import { useContext, useEffect, useState } from "react";
|
||||||
|
|
||||||
|
export default function AddTroll({
|
||||||
|
themerVars: [theme, setTheme],
|
||||||
|
clan
|
||||||
|
}: {
|
||||||
|
themerVars: ThemerGetSet;
|
||||||
|
clan: ClientClan;
|
||||||
|
}) {
|
||||||
|
const userCredentials = useContext(AuthContext);
|
||||||
|
const router = useRouter();
|
||||||
|
// Prevent hydration error. Nav Auth section is a client-rendered element.
|
||||||
|
const [isClient, setIsClient] = useState(false);
|
||||||
|
useEffect(() => {
|
||||||
|
setIsClient(true);
|
||||||
|
setTheme(defaultTheme);
|
||||||
|
console.log(clan);
|
||||||
|
}, []);
|
||||||
|
return isClient && userCredentials.TROLLCALL_NAME == clan.name ? (
|
||||||
|
<>
|
||||||
|
<Box properties={{ title: { text: "Edit Clan" } }}>
|
||||||
|
<span className={globals.text}>Tweak your clan.</span>
|
||||||
|
</Box>
|
||||||
|
<ClanFormTemplate
|
||||||
|
router={router}
|
||||||
|
method="PUT"
|
||||||
|
onSubmitURI={`/api/clan/${clan.name}`}
|
||||||
|
initialValues={ClientClanToSubmitClan(clan)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<NotSignedInClan clan={clan.displayName ?? clan.name} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getServerSideProps: GetServerSideProps<{
|
||||||
|
clan: ClientClan;
|
||||||
|
}> = async (context: GetStaticPropsContext) => {
|
||||||
|
if (context.params?.clan == null) return { notFound: true };
|
||||||
|
const clan = await ClanGET({
|
||||||
|
name: context.params?.clan
|
||||||
|
});
|
||||||
|
if (clan == null)
|
||||||
|
return {
|
||||||
|
notFound: true
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
clan: cutObject(clan)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
77
src/pages/edit/troll/[clan]/[troll]/index.tsx
Normal file
77
src/pages/edit/troll/[clan]/[troll]/index.tsx
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
import Box from "@/components/Box/Box";
|
||||||
|
import TrollFormTemplate from "@/components/form/template/troll";
|
||||||
|
import NotSignedInClan from "@/components/template/not-signed-in-clan";
|
||||||
|
import { TrollGET } from "@/lib/trollcall/api/troll";
|
||||||
|
import { getSingleClan } from "@/lib/trollcall/clan";
|
||||||
|
import { ClientTrollToSubmitTroll } from "@/lib/trollcall/convert/troll";
|
||||||
|
import { cutObject } from "@/lib/trollcall/utility/merge";
|
||||||
|
import globals from "@/styles/global.module.css";
|
||||||
|
import { ThemerGetSet } from "@/types/generics";
|
||||||
|
import { ClientTroll } from "@/types/troll";
|
||||||
|
import AuthContext from "@/utility/react/AuthContext";
|
||||||
|
import { defaultTheme } from "@/utility/react/Themer";
|
||||||
|
import { GetServerSideProps, GetStaticPropsContext } from "next";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import { useContext, useEffect, useState } from "react";
|
||||||
|
|
||||||
|
export default function AddTroll({
|
||||||
|
themerVars: [theme, setTheme],
|
||||||
|
troll
|
||||||
|
}: {
|
||||||
|
themerVars: ThemerGetSet;
|
||||||
|
troll: ClientTroll;
|
||||||
|
}) {
|
||||||
|
const userCredentials = useContext(AuthContext);
|
||||||
|
const router = useRouter();
|
||||||
|
// Prevent hydration error. Nav Auth section is a client-rendered element.
|
||||||
|
const [isClient, setIsClient] = useState(false);
|
||||||
|
useEffect(() => {
|
||||||
|
setIsClient(true);
|
||||||
|
setTheme(defaultTheme);
|
||||||
|
console.log(troll);
|
||||||
|
}, []);
|
||||||
|
return isClient && userCredentials.TROLLCALL_NAME == troll.owner.name ? (
|
||||||
|
<>
|
||||||
|
<Box properties={{ title: { text: "Edit Troll" } }}>
|
||||||
|
<span className={globals.text}>Edit one of your trolls.</span>
|
||||||
|
</Box>
|
||||||
|
<TrollFormTemplate
|
||||||
|
user={userCredentials}
|
||||||
|
router={router}
|
||||||
|
method="PUT"
|
||||||
|
onSubmitURI={`/api/troll/${troll.owner.name}/${troll.name[0]}`}
|
||||||
|
initialValues={ClientTrollToSubmitTroll(troll)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<NotSignedInClan clan={troll.owner.displayName ?? troll.owner.name} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getServerSideProps: GetServerSideProps<{
|
||||||
|
troll: ClientTroll;
|
||||||
|
}> = async (context: GetStaticPropsContext) => {
|
||||||
|
if (context.params?.clan == null) return { notFound: true };
|
||||||
|
const serverClan = await getSingleClan({
|
||||||
|
name: context.params?.clan
|
||||||
|
});
|
||||||
|
if (serverClan == null)
|
||||||
|
return {
|
||||||
|
notFound: true
|
||||||
|
};
|
||||||
|
if (context.params?.troll == null) return { notFound: true };
|
||||||
|
const troll = await TrollGET(
|
||||||
|
{ name: context.params.troll },
|
||||||
|
null,
|
||||||
|
serverClan
|
||||||
|
);
|
||||||
|
if (troll == null)
|
||||||
|
return {
|
||||||
|
notFound: true
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
troll: cutObject(troll)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
|
@ -1,4 +1,5 @@
|
||||||
import Box from "@/components/Box/Box";
|
import Box from "@/components/Box/Box";
|
||||||
|
import Credits from "@/components/template/credits";
|
||||||
import globals from "@/styles/global.module.css";
|
import globals from "@/styles/global.module.css";
|
||||||
import "@/styles/index.module.css";
|
import "@/styles/index.module.css";
|
||||||
import { ThemerGetSet } from "@/types/generics";
|
import { ThemerGetSet } from "@/types/generics";
|
||||||
|
@ -451,80 +452,7 @@ export default function Index({
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<p className={globals.text}>
|
<Credits />
|
||||||
TrollCall rev. 4 created by MeowcaTheoRange.
|
|
||||||
</p>
|
|
||||||
<p className={globals.text}>
|
|
||||||
<b>trollcall.xyz</b> domain owned by Redact.
|
|
||||||
</p>
|
|
||||||
<p className={globals.text}>
|
|
||||||
The TrollCall name is derived from the original Hiveswap
|
|
||||||
Troll Call. The name may be used in an entity context or a
|
|
||||||
project context.
|
|
||||||
</p>
|
|
||||||
<p className={globals.text}>
|
|
||||||
The textboxes found in the [INSERT PAGE HERE] are inspired
|
|
||||||
by those from the game <b>Celeste</b>.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<span className={globals.blockText}>
|
|
||||||
<Link
|
|
||||||
className={globals.link}
|
|
||||||
href="https://github.com/MeowcaTheoRange/Fonts"
|
|
||||||
>
|
|
||||||
TrollCall Display
|
|
||||||
</Link>{" "}
|
|
||||||
font by MeowcaTheoRange.
|
|
||||||
</span>
|
|
||||||
<span className={globals.blockText}>
|
|
||||||
<Link
|
|
||||||
className={globals.link}
|
|
||||||
href="https://fonts.google.com/specimen/Space+Grotesk"
|
|
||||||
>
|
|
||||||
Space Grotesk
|
|
||||||
</Link>{" "}
|
|
||||||
font by Florian Karsten.
|
|
||||||
</span>
|
|
||||||
<span className={globals.blockText}>
|
|
||||||
<Link
|
|
||||||
className={globals.link}
|
|
||||||
href="https://fonts.google.com/specimen/Space+Mono"
|
|
||||||
>
|
|
||||||
Space Mono
|
|
||||||
</Link>{" "}
|
|
||||||
font by Colophon Foundry.
|
|
||||||
</span>
|
|
||||||
<span className={globals.blockText}>
|
|
||||||
<Link
|
|
||||||
className={globals.link}
|
|
||||||
href="https://fonts.google.com/specimen/Poppins"
|
|
||||||
>
|
|
||||||
Poppins
|
|
||||||
</Link>{" "}
|
|
||||||
font by Indian Type Foundry.
|
|
||||||
</span>
|
|
||||||
<span className={globals.blockText}>
|
|
||||||
<Link
|
|
||||||
className={globals.link}
|
|
||||||
href="https://fonts.google.com/specimen/Flow+Circular"
|
|
||||||
>
|
|
||||||
Flow Circular
|
|
||||||
</Link>{" "}
|
|
||||||
font by Dan Ross.
|
|
||||||
</span>
|
|
||||||
<span className={globals.blockText}>
|
|
||||||
<Link
|
|
||||||
className={globals.link}
|
|
||||||
href="https://www.creativefabrica.com/product/renogare/"
|
|
||||||
>
|
|
||||||
Renogare
|
|
||||||
</Link>{" "}
|
|
||||||
font by Deepak Dogra.
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<p className={globals.text}>
|
|
||||||
Homestuck and HIVESWAP © Homestuck Inc.
|
|
||||||
</p>
|
|
||||||
</Box>
|
</Box>
|
||||||
<Box properties={{ title: { text: "Contact Me" } }}>
|
<Box properties={{ title: { text: "Contact Me" } }}>
|
||||||
<p className={globals.text}>
|
<p className={globals.text}>
|
||||||
|
|
|
@ -33,7 +33,7 @@ export default function Index({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box properties={{}}>
|
<Box properties={{}}>
|
||||||
<p className={globals.iconText}>
|
<p className={`${globals.iconText} ${globals.forceLTR}`}>
|
||||||
<span className={globals.icon}>arrow_back</span>
|
<span className={globals.icon}>arrow_back</span>
|
||||||
<Link
|
<Link
|
||||||
className={globals.link}
|
className={globals.link}
|
||||||
|
@ -100,7 +100,7 @@ export const getStaticPaths: GetStaticPaths = () => {
|
||||||
name: aspect.name
|
name: aspect.name
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
fallback: true
|
fallback: false
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ export default function Index({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box properties={{}}>
|
<Box properties={{}}>
|
||||||
<p className={globals.iconText}>
|
<p className={`${globals.iconText} ${globals.forceLTR}`}>
|
||||||
<span className={globals.icon}>arrow_back</span>
|
<span className={globals.icon}>arrow_back</span>
|
||||||
<Link
|
<Link
|
||||||
className={globals.link}
|
className={globals.link}
|
||||||
|
|
|
@ -33,7 +33,7 @@ export default function Index({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box properties={{}}>
|
<Box properties={{}}>
|
||||||
<p className={globals.iconText}>
|
<p className={`${globals.iconText} ${globals.forceLTR}`}>
|
||||||
<span className={globals.icon}>arrow_back</span>
|
<span className={globals.icon}>arrow_back</span>
|
||||||
<Link
|
<Link
|
||||||
className={globals.link}
|
className={globals.link}
|
||||||
|
@ -99,7 +99,7 @@ export const getStaticPaths: GetStaticPaths = () => {
|
||||||
name: color.name
|
name: color.name
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
fallback: true
|
fallback: false
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ export default function Index({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box properties={{}}>
|
<Box properties={{}}>
|
||||||
<p className={globals.iconText}>
|
<p className={`${globals.iconText} ${globals.forceLTR}`}>
|
||||||
<span className={globals.icon}>arrow_back</span>
|
<span className={globals.icon}>arrow_back</span>
|
||||||
<Link
|
<Link
|
||||||
className={globals.link}
|
className={globals.link}
|
||||||
|
|
|
@ -15,8 +15,8 @@ export default function Index({
|
||||||
useEffect(() => setTheme(hiveswapTheme), []);
|
useEffect(() => setTheme(hiveswapTheme), []);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box properties={{}}>
|
<Box>
|
||||||
<p className={globals.iconText}>
|
<p className={`${globals.iconText} ${globals.forceLTR}`}>
|
||||||
<span className={globals.icon}>arrow_back</span>
|
<span className={globals.icon}>arrow_back</span>
|
||||||
<span className={globals.text}>hiveswap</span>
|
<span className={globals.text}>hiveswap</span>
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -34,7 +34,7 @@ export default function Index({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box properties={{}}>
|
<Box properties={{}}>
|
||||||
<p className={globals.iconText}>
|
<p className={`${globals.iconText} ${globals.forceLTR}`}>
|
||||||
<span className={globals.icon}>arrow_back</span>
|
<span className={globals.icon}>arrow_back</span>
|
||||||
<Link
|
<Link
|
||||||
className={globals.link}
|
className={globals.link}
|
||||||
|
@ -110,7 +110,7 @@ export const getStaticPaths: GetStaticPaths = () => {
|
||||||
name: sway.name
|
name: sway.name
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
fallback: true
|
fallback: false
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ export default function Index({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box properties={{}}>
|
<Box properties={{}}>
|
||||||
<p className={globals.iconText}>
|
<p className={`${globals.iconText} ${globals.forceLTR}`}>
|
||||||
<span className={globals.icon}>arrow_back</span>
|
<span className={globals.icon}>arrow_back</span>
|
||||||
<Link
|
<Link
|
||||||
className={globals.link}
|
className={globals.link}
|
||||||
|
|
|
@ -31,7 +31,7 @@ export default function Index({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box properties={{}}>
|
<Box properties={{}}>
|
||||||
<p className={globals.iconText}>
|
<p className={`${globals.iconText} ${globals.forceLTR}`}>
|
||||||
<span className={globals.icon}>arrow_back</span>
|
<span className={globals.icon}>arrow_back</span>
|
||||||
<Link
|
<Link
|
||||||
className={globals.link}
|
className={globals.link}
|
||||||
|
@ -147,7 +147,7 @@ export const getStaticPaths: GetStaticPaths = () => {
|
||||||
name: trueSign.name
|
name: trueSign.name
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
fallback: true
|
fallback: false
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ export default function Index({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box properties={{}}>
|
<Box properties={{}}>
|
||||||
<p className={globals.iconText}>
|
<p className={`${globals.iconText} ${globals.forceLTR}`}>
|
||||||
<span className={globals.icon}>arrow_back</span>
|
<span className={globals.icon}>arrow_back</span>
|
||||||
<Link
|
<Link
|
||||||
className={globals.link}
|
className={globals.link}
|
||||||
|
|
|
@ -21,23 +21,25 @@ export default function Index({
|
||||||
}: {
|
}: {
|
||||||
themerVars: ThemerGetSet;
|
themerVars: ThemerGetSet;
|
||||||
}) {
|
}) {
|
||||||
const [fetchedTrolls, setFetchedTrolls] = useState<ClientTroll[] | null>(
|
const [fetchedTrolls, setFetchedTrolls] = useState<ClientTroll[]>([]);
|
||||||
null
|
const [fetchedClans, setFetchedClans] = useState<ClientClan[]>([]);
|
||||||
);
|
async function getTroll(page?: number) {
|
||||||
const [fetchedClans, setFetchedClans] = useState<ClientClan[] | null>(null);
|
const res = await fetch(
|
||||||
|
page ? "/api/troll/.../" + page : "/api/troll/..."
|
||||||
|
);
|
||||||
|
const json = await res.json();
|
||||||
|
setFetchedTrolls(json);
|
||||||
|
}
|
||||||
|
async function getClan(page?: number) {
|
||||||
|
const res = await fetch(
|
||||||
|
page ? "/api/clan/.../" + page : "/api/clan/..."
|
||||||
|
);
|
||||||
|
const json = await res.json();
|
||||||
|
setFetchedClans(json);
|
||||||
|
}
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function getTroll() {
|
getTroll(0);
|
||||||
const res = await fetch("/api/troll/...");
|
getClan(0);
|
||||||
const json = await res.json();
|
|
||||||
setFetchedTrolls(json);
|
|
||||||
}
|
|
||||||
getTroll();
|
|
||||||
async function getClan() {
|
|
||||||
const res = await fetch("/api/clan/...");
|
|
||||||
const json = await res.json();
|
|
||||||
setFetchedClans(json);
|
|
||||||
}
|
|
||||||
getClan();
|
|
||||||
setTheme(defaultTheme);
|
setTheme(defaultTheme);
|
||||||
}, []);
|
}, []);
|
||||||
return (
|
return (
|
||||||
|
@ -73,7 +75,8 @@ export default function Index({
|
||||||
<Box
|
<Box
|
||||||
properties={{
|
properties={{
|
||||||
title: {
|
title: {
|
||||||
text: "List of characters",
|
text: "Current characters",
|
||||||
|
link: "/troll/s",
|
||||||
small: true
|
small: true
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
@ -96,7 +99,8 @@ export default function Index({
|
||||||
<Box
|
<Box
|
||||||
properties={{
|
properties={{
|
||||||
title: {
|
title: {
|
||||||
text: "List of clans",
|
text: "Current clans",
|
||||||
|
link: "/clan/s",
|
||||||
small: true
|
small: true
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|
9
src/pages/manage/index.module.css
Normal file
9
src/pages/manage/index.module.css
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
.showOnHover {
|
||||||
|
filter: blur(8px);
|
||||||
|
transition: filter 1s, user-select 1s step-end;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
.showOnHover:hover {
|
||||||
|
filter: none;
|
||||||
|
user-select: text;
|
||||||
|
}
|
145
src/pages/manage/index.tsx
Normal file
145
src/pages/manage/index.tsx
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
import Box from "@/components/Box/Box";
|
||||||
|
import globals from "@/styles/global.module.css";
|
||||||
|
import form_globals from "@/styles/global_form.module.css";
|
||||||
|
import { ThemerGetSet } from "@/types/generics";
|
||||||
|
import AuthContext from "@/utility/react/AuthContext";
|
||||||
|
import { defaultTheme } from "@/utility/react/Themer";
|
||||||
|
import { deleteCookie, getCookies, setCookie } from "cookies-next";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import { useContext, useEffect, useRef, useState } from "react";
|
||||||
|
import styles from "./index.module.css";
|
||||||
|
|
||||||
|
export default function Manage({
|
||||||
|
themerVars: [theme, setTheme]
|
||||||
|
}: {
|
||||||
|
themerVars: ThemerGetSet;
|
||||||
|
}) {
|
||||||
|
const userCredentials = useContext(AuthContext);
|
||||||
|
const nameInput = useRef<HTMLInputElement>(null);
|
||||||
|
const codeInput = useRef<HTMLInputElement>(null);
|
||||||
|
const router = useRouter();
|
||||||
|
// Prevent hydration error. Nav Auth section is a client-rendered element.
|
||||||
|
const [isClient, setIsClient] = useState(false);
|
||||||
|
useEffect(() => {
|
||||||
|
setIsClient(true);
|
||||||
|
setTheme(defaultTheme);
|
||||||
|
}, []);
|
||||||
|
const cookies = getCookies() as {
|
||||||
|
TROLLCALL_NAME: string;
|
||||||
|
TROLLCALL_CODE: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const [statusHolder, setStatusHolder] = useState("");
|
||||||
|
return isClient && userCredentials.TROLLCALL_NAME != null ? (
|
||||||
|
<>
|
||||||
|
<Box properties={{ title: { text: "Sign out?" } }}>
|
||||||
|
<p className={globals.text}>
|
||||||
|
Are you sure you want to sign out of TrollCall?
|
||||||
|
</p>
|
||||||
|
<p className={globals.text}>
|
||||||
|
Make sure to remember your credentials!
|
||||||
|
</p>
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
<span className={globals.text}>Show login</span>
|
||||||
|
</summary>
|
||||||
|
<p className={globals.text}>
|
||||||
|
NAME:{" "}
|
||||||
|
<span className={globals.mono}>
|
||||||
|
{cookies.TROLLCALL_NAME}
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<p className={globals.text}>
|
||||||
|
CODE:{" "}
|
||||||
|
<span
|
||||||
|
className={`${globals.mono} ${styles.showOnHover}`}
|
||||||
|
>
|
||||||
|
{isClient && cookies.TROLLCALL_CODE}
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</details>
|
||||||
|
<button
|
||||||
|
className={globals.button}
|
||||||
|
onClick={() => {
|
||||||
|
deleteCookie("TROLLCALL_NAME", {
|
||||||
|
path: "/"
|
||||||
|
});
|
||||||
|
deleteCookie("TROLLCALL_CODE", {
|
||||||
|
path: "/"
|
||||||
|
});
|
||||||
|
router.push("/");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Sign out
|
||||||
|
</button>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Box properties={{ title: { text: "Sign in / join a clan" } }}>
|
||||||
|
<p className={globals.text}>Join a clan on TrollCall.</p>
|
||||||
|
<p className={globals.text}>
|
||||||
|
Have you remembered your credientials? If not,{" "}
|
||||||
|
<b>submit an issue</b> or <b>join the Discord</b> for help.
|
||||||
|
</p>
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
<p className={globals.titleSmall}>Name</p>
|
||||||
|
<div className={globals.horizontalListLeft}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="name"
|
||||||
|
placeholder="jim"
|
||||||
|
ref={nameInput}
|
||||||
|
className={`
|
||||||
|
${form_globals.textLikeInput}
|
||||||
|
${form_globals.textLikeInputTight}
|
||||||
|
`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={globals.verticalListTop}>
|
||||||
|
<p className={globals.titleSmall}>Code</p>
|
||||||
|
<div className={globals.horizontalListLeft}>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
name="code"
|
||||||
|
placeholder="Tim Sweeney"
|
||||||
|
ref={codeInput}
|
||||||
|
className={`
|
||||||
|
${form_globals.textLikeInput}
|
||||||
|
${form_globals.textLikeInputTight}
|
||||||
|
`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
className={globals.button}
|
||||||
|
onClick={async () => {
|
||||||
|
setCookie(
|
||||||
|
"TROLLCALL_NAME",
|
||||||
|
nameInput.current?.value.toLowerCase() ?? "",
|
||||||
|
{
|
||||||
|
path: "/",
|
||||||
|
maxAge: 31540000
|
||||||
|
}
|
||||||
|
);
|
||||||
|
setCookie(
|
||||||
|
"TROLLCALL_CODE",
|
||||||
|
codeInput.current?.value ?? "",
|
||||||
|
{
|
||||||
|
path: "/",
|
||||||
|
maxAge: 31540000
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const status = await fetch("/api/test/signin");
|
||||||
|
if (status.status === 200) router.push("/");
|
||||||
|
else setStatusHolder(await status.text());
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Sign in
|
||||||
|
</button>
|
||||||
|
<span className={globals.text}>{statusHolder}</span>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
|
@ -85,6 +85,8 @@ export default function Index({
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [statusHolder, setStatusHolder] = useState("");
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box
|
<Box
|
||||||
|
@ -176,7 +178,8 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(0.9, 0.9, 0.8),
|
new Color3(0.9, 0.9, 0.8),
|
||||||
new Color3(0.7, 0.7, 0.6),
|
new Color3(0.7, 0.7, 0.6),
|
||||||
theme[2]
|
undefined,
|
||||||
|
undefined
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -189,7 +192,8 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(0.5, 0.5, 0.4),
|
new Color3(0.5, 0.5, 0.4),
|
||||||
new Color3(0.1, 0.1, 0),
|
new Color3(0.1, 0.1, 0),
|
||||||
theme[2]
|
undefined,
|
||||||
|
undefined
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -202,6 +206,7 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(0, 0, 0),
|
new Color3(0, 0, 0),
|
||||||
new Color3(0, 0, 0),
|
new Color3(0, 0, 0),
|
||||||
|
undefined,
|
||||||
false
|
false
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
@ -215,6 +220,7 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(1, 1, 1),
|
new Color3(1, 1, 1),
|
||||||
new Color3(1, 1, 1),
|
new Color3(1, 1, 1),
|
||||||
|
undefined,
|
||||||
true
|
true
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
@ -230,7 +236,8 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(1, 0, 0),
|
new Color3(1, 0, 0),
|
||||||
new Color3(0.5, 0, 0),
|
new Color3(0.5, 0, 0),
|
||||||
theme[2]
|
undefined,
|
||||||
|
undefined
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -242,7 +249,8 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(1, 0.5, 0),
|
new Color3(1, 0.5, 0),
|
||||||
new Color3(0.5, 0.25, 0),
|
new Color3(0.5, 0.25, 0),
|
||||||
theme[2]
|
undefined,
|
||||||
|
undefined
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -254,7 +262,8 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(1, 1, 0),
|
new Color3(1, 1, 0),
|
||||||
new Color3(0.5, 0.5, 0),
|
new Color3(0.5, 0.5, 0),
|
||||||
theme[2]
|
undefined,
|
||||||
|
undefined
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -266,7 +275,8 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(0.5, 1, 0),
|
new Color3(0.5, 1, 0),
|
||||||
new Color3(0.25, 0.5, 0),
|
new Color3(0.25, 0.5, 0),
|
||||||
theme[2]
|
undefined,
|
||||||
|
undefined
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -278,7 +288,8 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(0, 1, 0),
|
new Color3(0, 1, 0),
|
||||||
new Color3(0, 0.5, 0),
|
new Color3(0, 0.5, 0),
|
||||||
theme[2]
|
undefined,
|
||||||
|
undefined
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -290,7 +301,8 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(0, 1, 0.5),
|
new Color3(0, 1, 0.5),
|
||||||
new Color3(0, 0.5, 0.25),
|
new Color3(0, 0.5, 0.25),
|
||||||
theme[2]
|
undefined,
|
||||||
|
undefined
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -302,7 +314,8 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(0, 1, 1),
|
new Color3(0, 1, 1),
|
||||||
new Color3(0, 0.5, 0.5),
|
new Color3(0, 0.5, 0.5),
|
||||||
theme[2]
|
undefined,
|
||||||
|
undefined
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -314,7 +327,8 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(0, 0.5, 1),
|
new Color3(0, 0.5, 1),
|
||||||
new Color3(0, 0.25, 0.5),
|
new Color3(0, 0.25, 0.5),
|
||||||
theme[2]
|
undefined,
|
||||||
|
undefined
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -326,7 +340,8 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(0, 0, 1),
|
new Color3(0, 0, 1),
|
||||||
new Color3(0, 0, 0.5),
|
new Color3(0, 0, 0.5),
|
||||||
theme[2]
|
undefined,
|
||||||
|
undefined
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -338,7 +353,8 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(0.5, 0, 1),
|
new Color3(0.5, 0, 1),
|
||||||
new Color3(0.25, 0, 0.5),
|
new Color3(0.25, 0, 0.5),
|
||||||
theme[2]
|
undefined,
|
||||||
|
undefined
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -350,7 +366,8 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(1, 0, 1),
|
new Color3(1, 0, 1),
|
||||||
new Color3(0.5, 0, 0.5),
|
new Color3(0.5, 0, 0.5),
|
||||||
theme[2]
|
undefined,
|
||||||
|
undefined
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -362,7 +379,8 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(1, 0, 0.5),
|
new Color3(1, 0, 0.5),
|
||||||
new Color3(0.5, 0, 0.25),
|
new Color3(0.5, 0, 0.25),
|
||||||
theme[2]
|
undefined,
|
||||||
|
undefined
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -377,7 +395,8 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(0, 0.5, 0.6),
|
new Color3(0, 0.5, 0.6),
|
||||||
new Color3(0, 0.1, 0.2),
|
new Color3(0, 0.1, 0.2),
|
||||||
theme[2]
|
undefined,
|
||||||
|
undefined
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -390,7 +409,8 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(0.6, 0, 0),
|
new Color3(0.6, 0, 0),
|
||||||
new Color3(0.2, 0, 0),
|
new Color3(0.2, 0, 0),
|
||||||
theme[2]
|
undefined,
|
||||||
|
undefined
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -403,7 +423,8 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(0.5, 0, 0.6),
|
new Color3(0.5, 0, 0.6),
|
||||||
new Color3(0.1, 0, 0.2),
|
new Color3(0.1, 0, 0.2),
|
||||||
theme[2]
|
undefined,
|
||||||
|
undefined
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -416,7 +437,8 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(0.5, 0.5, 0.6),
|
new Color3(0.5, 0.5, 0.6),
|
||||||
new Color3(0, 0, 0.1),
|
new Color3(0, 0, 0.1),
|
||||||
theme[2]
|
undefined,
|
||||||
|
undefined
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -429,7 +451,8 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(1, 1, 0),
|
new Color3(1, 1, 0),
|
||||||
new Color3(0.5, 1, 0),
|
new Color3(0.5, 1, 0),
|
||||||
theme[2]
|
undefined,
|
||||||
|
undefined
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -442,7 +465,8 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(1, 0, 0),
|
new Color3(1, 0, 0),
|
||||||
new Color3(1, 0.75, 0),
|
new Color3(1, 0.75, 0),
|
||||||
theme[2]
|
undefined,
|
||||||
|
undefined
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -459,6 +483,7 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(0.6, 0, 1),
|
new Color3(0.6, 0, 1),
|
||||||
new Color3(0, 0.5, 0.5),
|
new Color3(0, 0.5, 0.5),
|
||||||
|
undefined,
|
||||||
false
|
false
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
@ -472,6 +497,7 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(1, 0.6, 0),
|
new Color3(1, 0.6, 0),
|
||||||
new Color3(0.5, 1, 1),
|
new Color3(0.5, 1, 1),
|
||||||
|
undefined,
|
||||||
true
|
true
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
@ -485,7 +511,8 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(0, 1, 0),
|
new Color3(0, 1, 0),
|
||||||
new Color3(1, 1, 1),
|
new Color3(1, 1, 1),
|
||||||
theme[2]
|
undefined,
|
||||||
|
undefined
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -498,7 +525,8 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(1, 0.5, 0.75),
|
new Color3(1, 0.5, 0.75),
|
||||||
new Color3(0.5, 0.25, 0.375),
|
new Color3(0.5, 0.25, 0.375),
|
||||||
theme[2]
|
undefined,
|
||||||
|
undefined
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -511,7 +539,8 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(1, 0.25, 0.5),
|
new Color3(1, 0.25, 0.5),
|
||||||
new Color3(0.5, 0.125, 0.25),
|
new Color3(0.5, 0.125, 0.25),
|
||||||
theme[2]
|
undefined,
|
||||||
|
undefined
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -524,7 +553,8 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(0.5, 0.9, 1),
|
new Color3(0.5, 0.9, 1),
|
||||||
new Color3(0.25, 0.45, 0.5),
|
new Color3(0.25, 0.45, 0.5),
|
||||||
theme[2]
|
undefined,
|
||||||
|
undefined
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -539,6 +569,7 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(0.5, 1, 0.5),
|
new Color3(0.5, 1, 0.5),
|
||||||
new Color3(1, 1, 1),
|
new Color3(1, 1, 1),
|
||||||
|
undefined,
|
||||||
true
|
true
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
@ -551,6 +582,7 @@ export default function Index({
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(0, 0.5, 0),
|
new Color3(0, 0.5, 0),
|
||||||
new Color3(0, 0, 0),
|
new Color3(0, 0, 0),
|
||||||
|
undefined,
|
||||||
false
|
false
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
@ -572,7 +604,12 @@ export default function Index({
|
||||||
<button
|
<button
|
||||||
className={globals.button}
|
className={globals.button}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setTheme([theme[0], theme[1], !theme[2]])
|
setTheme([
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
!theme[3]
|
||||||
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Invert theme palette
|
Invert theme palette
|
||||||
|
@ -647,6 +684,18 @@ export default function Index({
|
||||||
globals.buttonLink applied to button
|
globals.buttonLink applied to button
|
||||||
</button>
|
</button>
|
||||||
</Box>
|
</Box>
|
||||||
|
<Box properties={{ title: { text: "Auth test module" } }}>
|
||||||
|
<button
|
||||||
|
className={globals.button}
|
||||||
|
onClick={async () => {
|
||||||
|
const status = await fetch("/api/test/signin");
|
||||||
|
setStatusHolder(await status.text());
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Test auth
|
||||||
|
</button>
|
||||||
|
<span className={globals.text}>{statusHolder}</span>
|
||||||
|
</Box>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
15
src/pages/troll/[clan]/[troll]/gallery/index.tsx
Normal file
15
src/pages/troll/[clan]/[troll]/gallery/index.tsx
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import Box from "@/components/Box/Box";
|
||||||
|
import globals from "@/styles/global.module.css";
|
||||||
|
import { ThemerGetSet } from "@/types/generics";
|
||||||
|
|
||||||
|
export default function Index({
|
||||||
|
themerVars: [theme, setTheme]
|
||||||
|
}: {
|
||||||
|
themerVars: ThemerGetSet;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<Box properties={{ title: { text: "Work in progress" } }}>
|
||||||
|
<span className={globals.text}>Sorry :[</span>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
|
@ -3,33 +3,39 @@ import ClanCard from "@/components/cards/ClanCard/ClanCard";
|
||||||
import TrollCard from "@/components/cards/TrollCard/TrollCard";
|
import TrollCard from "@/components/cards/TrollCard/TrollCard";
|
||||||
import { TrollGET } from "@/lib/trollcall/api/troll";
|
import { TrollGET } from "@/lib/trollcall/api/troll";
|
||||||
import { getSingleClan } from "@/lib/trollcall/clan";
|
import { getSingleClan } from "@/lib/trollcall/clan";
|
||||||
|
import { cutObject } from "@/lib/trollcall/utility/merge";
|
||||||
import globals from "@/styles/global.module.css";
|
import globals from "@/styles/global.module.css";
|
||||||
import { Color3 } from "@/types/assist/color";
|
import { Color3 } from "@/types/assist/color";
|
||||||
import { ThemerGetSet, WidthGetSet } from "@/types/generics";
|
import { ThemerGetSet } from "@/types/generics";
|
||||||
import { ClientTroll } from "@/types/troll";
|
import { ClientTroll } from "@/types/troll";
|
||||||
|
import { ProperNounCase } from "@/utility/language";
|
||||||
import { parseQuirk } from "@/utility/quirk";
|
import { parseQuirk } from "@/utility/quirk";
|
||||||
|
import AuthContext from "@/utility/react/AuthContext";
|
||||||
import Conditional from "@/utility/react/Conditional";
|
import Conditional from "@/utility/react/Conditional";
|
||||||
import { GetServerSideProps, GetStaticPropsContext } from "next";
|
import { GetServerSideProps, GetStaticPropsContext } from "next";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useEffect, useState } from "react";
|
import { useContext, useEffect, useState } from "react";
|
||||||
import styles from "./index.module.css";
|
import styles from "./index.module.css";
|
||||||
|
|
||||||
export default function Index({
|
export default function Index({
|
||||||
themerVars: [theme, setTheme],
|
themerVars: [theme, setTheme],
|
||||||
widthVars: [width, setWidth],
|
|
||||||
troll
|
troll
|
||||||
}: {
|
}: {
|
||||||
themerVars: ThemerGetSet;
|
themerVars: ThemerGetSet;
|
||||||
widthVars: WidthGetSet;
|
|
||||||
troll: ClientTroll;
|
troll: ClientTroll;
|
||||||
}) {
|
}) {
|
||||||
const [fetchedTrolls, setFetchedTrolls] = useState<ClientTroll[] | null>(
|
// Get user creds
|
||||||
null
|
const userCredentials = useContext(AuthContext);
|
||||||
);
|
const [isClient, setIsClient] = useState(false);
|
||||||
|
useEffect(() => setIsClient(true), []);
|
||||||
|
|
||||||
|
// Stack troll colors
|
||||||
const trollColor = (troll.pageColor?.map(x => x / 255) ??
|
const trollColor = (troll.pageColor?.map(x => x / 255) ??
|
||||||
troll.textColor?.map(x => x / 255) ??
|
troll.textColor?.map(x => x / 255) ??
|
||||||
troll.falseSign?.color.color ??
|
troll.falseSign?.color.color ??
|
||||||
troll.trueSign?.color.color) as [number, number, number] | undefined;
|
troll.trueSign?.color.color) as [number, number, number] | undefined;
|
||||||
|
|
||||||
|
// Merge policies
|
||||||
const policies = {
|
const policies = {
|
||||||
fanart: troll.policies?.fanart ?? troll.owner.policies.fanart,
|
fanart: troll.policies?.fanart ?? troll.owner.policies.fanart,
|
||||||
fanartOthers:
|
fanartOthers:
|
||||||
|
@ -43,10 +49,10 @@ export default function Index({
|
||||||
if (trollColor != null)
|
if (trollColor != null)
|
||||||
setTheme([
|
setTheme([
|
||||||
new Color3(...trollColor),
|
new Color3(...trollColor),
|
||||||
new Color3(...trollColor).darken(50)
|
new Color3(...trollColor).darken(50),
|
||||||
|
1024
|
||||||
]);
|
]);
|
||||||
}, []);
|
}, []);
|
||||||
setWidth(1024);
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={styles.boxbox}>
|
<div className={styles.boxbox}>
|
||||||
|
@ -56,20 +62,6 @@ export default function Index({
|
||||||
link={false}
|
link={false}
|
||||||
small={false}
|
small={false}
|
||||||
/>
|
/>
|
||||||
<Box
|
|
||||||
properties={{
|
|
||||||
title: {
|
|
||||||
text: "More..."
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Link
|
|
||||||
className={globals.linkButton}
|
|
||||||
href={`/gallery/${troll.owner.name}/${troll.name[0]}/`}
|
|
||||||
>
|
|
||||||
Gallery
|
|
||||||
</Link>
|
|
||||||
</Box>
|
|
||||||
<Box
|
<Box
|
||||||
properties={{
|
properties={{
|
||||||
title: {
|
title: {
|
||||||
|
@ -211,19 +203,15 @@ export default function Index({
|
||||||
format_quote
|
format_quote
|
||||||
</span>
|
</span>
|
||||||
<span className={globals.text}>
|
<span className={globals.text}>
|
||||||
{parseQuirk(
|
{troll.quirks != null
|
||||||
quote,
|
? parseQuirk(
|
||||||
troll.quirks["default"]
|
quote,
|
||||||
)}
|
troll.quirks["default"]
|
||||||
|
)
|
||||||
|
: quote}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
<Link
|
|
||||||
className={globals.linkButton}
|
|
||||||
href={`/quirk/${troll.owner.name}/${troll.name[0]}/`}
|
|
||||||
>
|
|
||||||
Quirk Tester
|
|
||||||
</Link>
|
|
||||||
</Box>
|
</Box>
|
||||||
</Conditional>
|
</Conditional>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -233,6 +221,43 @@ export default function Index({
|
||||||
style={{ backgroundImage: `url("${troll.images[0]}")` }}
|
style={{ backgroundImage: `url("${troll.images[0]}")` }}
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
|
<Conditional condition={troll.description != ""}>
|
||||||
|
<Box
|
||||||
|
properties={{
|
||||||
|
title: {
|
||||||
|
text: "Description"
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<p className={globals.blockText}>{troll.description}</p>
|
||||||
|
</Box>
|
||||||
|
</Conditional>
|
||||||
|
<Box
|
||||||
|
properties={{
|
||||||
|
title: {
|
||||||
|
text: "More..."
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<p>
|
||||||
|
Some more stuff you can do with{" "}
|
||||||
|
<b>{ProperNounCase(troll.name[0])}</b>.
|
||||||
|
</p>
|
||||||
|
<Link
|
||||||
|
className={globals.linkButton}
|
||||||
|
href={`/troll/${troll.owner.name}/${troll.name[0]}/gallery/`}
|
||||||
|
>
|
||||||
|
Gallery
|
||||||
|
</Link>
|
||||||
|
<Conditional condition={troll.quirks != null}>
|
||||||
|
<Link
|
||||||
|
className={globals.linkButton}
|
||||||
|
href={`/troll/${troll.owner.name}/${troll.name[0]}/quirk/`}
|
||||||
|
>
|
||||||
|
Quirk Tester
|
||||||
|
</Link>
|
||||||
|
</Conditional>
|
||||||
|
</Box>
|
||||||
<Box
|
<Box
|
||||||
properties={{
|
properties={{
|
||||||
title: {
|
title: {
|
||||||
|
@ -242,15 +267,29 @@ export default function Index({
|
||||||
>
|
>
|
||||||
<ClanCard clan={troll.owner} />
|
<ClanCard clan={troll.owner} />
|
||||||
</Box>
|
</Box>
|
||||||
<Box
|
{isClient && userCredentials.TROLLCALL_NAME == troll.owner.name ? (
|
||||||
properties={{
|
<Box
|
||||||
title: {
|
properties={{
|
||||||
text: "Description"
|
title: {
|
||||||
}
|
text: "Admin"
|
||||||
}}
|
},
|
||||||
>
|
theme: theme[1]
|
||||||
<p className={globals.blockText}>{troll.description}</p>
|
}}
|
||||||
</Box>
|
>
|
||||||
|
<p>
|
||||||
|
Well, it seems you can manage{" "}
|
||||||
|
<b>{ProperNounCase(troll.name[0])}</b>! Have this menu.
|
||||||
|
</p>
|
||||||
|
<Link
|
||||||
|
className={globals.linkButton}
|
||||||
|
href={`/edit/troll/${troll.owner.name}/${troll.name[0]}/`}
|
||||||
|
>
|
||||||
|
Edit Troll
|
||||||
|
</Link>
|
||||||
|
</Box>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -274,7 +313,7 @@ export const getServerSideProps: GetServerSideProps<{
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
troll
|
troll: cutObject(troll)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
15
src/pages/troll/[clan]/[troll]/quirk/index.tsx
Normal file
15
src/pages/troll/[clan]/[troll]/quirk/index.tsx
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import Box from "@/components/Box/Box";
|
||||||
|
import globals from "@/styles/global.module.css";
|
||||||
|
import { ThemerGetSet } from "@/types/generics";
|
||||||
|
|
||||||
|
export default function Index({
|
||||||
|
themerVars: [theme, setTheme]
|
||||||
|
}: {
|
||||||
|
themerVars: ThemerGetSet;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<Box properties={{ title: { text: "Work in progress" } }}>
|
||||||
|
<span className={globals.text}>Sorry :[</span>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
110
src/pages/troll/s/[clan]/index.tsx
Normal file
110
src/pages/troll/s/[clan]/index.tsx
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
import Box from "@/components/Box/Box";
|
||||||
|
import TrollCard from "@/components/cards/TrollCard/TrollCard";
|
||||||
|
import TrollSkeleton from "@/components/cards/TrollCard/TrollSkeleton";
|
||||||
|
import { ClanGET } from "@/lib/trollcall/api/clan";
|
||||||
|
import { cutObject } from "@/lib/trollcall/utility/merge";
|
||||||
|
import globals from "@/styles/global.module.css";
|
||||||
|
import "@/styles/index.module.css";
|
||||||
|
import { Color3 } from "@/types/assist/color";
|
||||||
|
import { ClientClan } from "@/types/clan";
|
||||||
|
import { ThemerGetSet } from "@/types/generics";
|
||||||
|
import { ClientTroll } from "@/types/troll";
|
||||||
|
import { defaultTheme } from "@/utility/react/Themer";
|
||||||
|
import { getCookies } from "cookies-next";
|
||||||
|
import { GetServerSideProps, GetStaticPropsContext } from "next";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
getCookies();
|
||||||
|
|
||||||
|
export default function Index({
|
||||||
|
themerVars: [theme, setTheme],
|
||||||
|
clan
|
||||||
|
}: {
|
||||||
|
themerVars: ThemerGetSet;
|
||||||
|
clan: ClientClan;
|
||||||
|
}) {
|
||||||
|
const [fetchedTrolls, setFetchedTrolls] = useState<ClientTroll[]>([]);
|
||||||
|
const [trollPageNum, setTrollPageNum] = useState(0);
|
||||||
|
const [noMore, setNoMore] = useState(false);
|
||||||
|
async function getTroll(page?: number) {
|
||||||
|
const res = await fetch(
|
||||||
|
page
|
||||||
|
? "/api/troll/" + clan.name + "/.../" + page
|
||||||
|
: "/api/troll/" + clan.name + "/..."
|
||||||
|
);
|
||||||
|
const json = await res.json();
|
||||||
|
setFetchedTrolls(fetchedTrolls.concat(json));
|
||||||
|
setNoMore(json.length < 5);
|
||||||
|
}
|
||||||
|
useEffect(() => {
|
||||||
|
getTroll(trollPageNum);
|
||||||
|
setTheme(defaultTheme);
|
||||||
|
const color = clan.color?.map(x => x / 255) as [number, number, number];
|
||||||
|
if (color != null)
|
||||||
|
setTheme([
|
||||||
|
new Color3(...color),
|
||||||
|
new Color3(...color).darken(50),
|
||||||
|
768
|
||||||
|
]);
|
||||||
|
}, [trollPageNum]);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Box
|
||||||
|
properties={{
|
||||||
|
title: {
|
||||||
|
text:
|
||||||
|
"Characters of " + (clan.displayName ?? clan.name)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className={globals.text}>
|
||||||
|
See a list of the characters of{" "}
|
||||||
|
{clan.displayName ?? clan.name}.
|
||||||
|
</span>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
{fetchedTrolls.length <= 0 ? (
|
||||||
|
<>
|
||||||
|
<TrollSkeleton />
|
||||||
|
<TrollSkeleton />
|
||||||
|
<TrollSkeleton />
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{fetchedTrolls.map((troll: ClientTroll, idx) => (
|
||||||
|
<TrollCard
|
||||||
|
troll={troll}
|
||||||
|
key={idx + "troll"}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<button
|
||||||
|
className={globals.button}
|
||||||
|
onClick={() => {
|
||||||
|
setTrollPageNum(trollPageNum + 1);
|
||||||
|
}}
|
||||||
|
disabled={noMore}
|
||||||
|
>
|
||||||
|
Load more
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getServerSideProps: GetServerSideProps<{
|
||||||
|
clan: ClientClan;
|
||||||
|
}> = async (context: GetStaticPropsContext) => {
|
||||||
|
if (context.params?.clan == null) return { notFound: true };
|
||||||
|
const clan = await ClanGET({ name: context.params.clan });
|
||||||
|
if (clan == null)
|
||||||
|
return {
|
||||||
|
notFound: true
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
clan: cutObject(clan)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
76
src/pages/troll/s/index.tsx
Normal file
76
src/pages/troll/s/index.tsx
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
import Box from "@/components/Box/Box";
|
||||||
|
import TrollCard from "@/components/cards/TrollCard/TrollCard";
|
||||||
|
import TrollSkeleton from "@/components/cards/TrollCard/TrollSkeleton";
|
||||||
|
import globals from "@/styles/global.module.css";
|
||||||
|
import "@/styles/index.module.css";
|
||||||
|
import { ThemerGetSet } from "@/types/generics";
|
||||||
|
import { ClientTroll } from "@/types/troll";
|
||||||
|
import { defaultTheme } from "@/utility/react/Themer";
|
||||||
|
import { getCookies } from "cookies-next";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
getCookies();
|
||||||
|
|
||||||
|
export default function Index({
|
||||||
|
themerVars: [theme, setTheme]
|
||||||
|
}: {
|
||||||
|
themerVars: ThemerGetSet;
|
||||||
|
}) {
|
||||||
|
const [fetchedTrolls, setFetchedTrolls] = useState<ClientTroll[]>([]);
|
||||||
|
const [trollPageNum, setTrollPageNum] = useState(0);
|
||||||
|
const [noMore, setNoMore] = useState(false);
|
||||||
|
async function getTroll(page?: number) {
|
||||||
|
const res = await fetch(
|
||||||
|
page ? "/api/troll/.../" + page : "/api/troll/..."
|
||||||
|
);
|
||||||
|
const json = await res.json();
|
||||||
|
setFetchedTrolls(fetchedTrolls.concat(json));
|
||||||
|
setNoMore(json.length < 5);
|
||||||
|
}
|
||||||
|
useEffect(() => {
|
||||||
|
getTroll(trollPageNum);
|
||||||
|
setTheme(defaultTheme);
|
||||||
|
}, [trollPageNum]);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Box
|
||||||
|
properties={{
|
||||||
|
title: {
|
||||||
|
text: "Explore characters"
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className={globals.text}>
|
||||||
|
See a list of all the characters on TrollCall.
|
||||||
|
</span>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
{fetchedTrolls.length <= 0 ? (
|
||||||
|
<>
|
||||||
|
<TrollSkeleton />
|
||||||
|
<TrollSkeleton />
|
||||||
|
<TrollSkeleton />
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{fetchedTrolls.map((troll: ClientTroll, idx) => (
|
||||||
|
<TrollCard
|
||||||
|
troll={troll}
|
||||||
|
key={idx + "troll"}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<button
|
||||||
|
className={globals.button}
|
||||||
|
onClick={() => {
|
||||||
|
setTrollPageNum(trollPageNum + 1);
|
||||||
|
}}
|
||||||
|
disabled={noMore}
|
||||||
|
>
|
||||||
|
Load more
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
|
@ -22,10 +22,12 @@ main.App {
|
||||||
color: var(--sec-fg);
|
color: var(--sec-fg);
|
||||||
background-image: url("/assets/pattern/pattern.png");
|
background-image: url("/assets/pattern/pattern.png");
|
||||||
background-blend-mode: hard-light;
|
background-blend-mode: hard-light;
|
||||||
|
--darken: linear-gradient(#0008, #0008);
|
||||||
}
|
}
|
||||||
|
|
||||||
main.App.inverted {
|
main.App.inverted {
|
||||||
background-image: url("/assets/pattern/pattern_inv.png");
|
background-image: url("/assets/pattern/pattern_inv.png");
|
||||||
|
--darken: linear-gradient(#fff8, #fff8);
|
||||||
}
|
}
|
||||||
|
|
||||||
main.App div.mainContent {
|
main.App div.mainContent {
|
||||||
|
|
|
@ -31,12 +31,18 @@
|
||||||
transition: box-shadow 0.125s;
|
transition: box-shadow 0.125s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.linkButton:hover {
|
.linkButton:hover:not(:disabled) {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
box-shadow: 0 0 8px currentColor;
|
box-shadow: 0 0 8px currentColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.linkButton:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button,
|
||||||
|
.buttonIcon {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
box-shadow: 0 0 2px currentColor;
|
box-shadow: 0 0 2px currentColor;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
@ -52,10 +58,22 @@
|
||||||
transition: box-shadow 0.125s;
|
transition: box-shadow 0.125s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button:hover {
|
.button:hover:not(:disabled),
|
||||||
|
.buttonIcon:hover:not(:disabled) {
|
||||||
box-shadow: 0 0 8px currentColor;
|
box-shadow: 0 0 8px currentColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button:disabled,
|
||||||
|
.buttonIcon:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttonIcon {
|
||||||
|
font-family: "Material Symbols Outlined";
|
||||||
|
font-variation-settings: "FILL" 1, "opsz" 24, "GRAD" 0, "wght" 400;
|
||||||
|
}
|
||||||
|
|
||||||
.buttonLink {
|
.buttonLink {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
@ -107,6 +125,14 @@
|
||||||
white-space: pre-line;
|
white-space: pre-line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.blockTextKeepTabs {
|
||||||
|
display: block;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 20px;
|
||||||
|
font-family: "Space Grotesk";
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
.small {
|
.small {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 14px;
|
line-height: 14px;
|
||||||
|
@ -124,6 +150,7 @@
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
|
vertical-align: middle;
|
||||||
font-family: "Material Symbols Outlined";
|
font-family: "Material Symbols Outlined";
|
||||||
font-variation-settings: "FILL" 1, "opsz" 24, "GRAD" 0, "wght" 400;
|
font-variation-settings: "FILL" 1, "opsz" 24, "GRAD" 0, "wght" 400;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
@ -162,14 +189,15 @@
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 0 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.horizontalListLeft {
|
.horizontalListLeft {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
gap: 0 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
.verticalListTop {
|
.verticalListTop {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -277,3 +305,7 @@
|
||||||
width: 0;
|
width: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.forceLTR {
|
||||||
|
direction: ltr;
|
||||||
|
}
|
||||||
|
|
152
src/styles/global_form.module.css
Normal file
152
src/styles/global_form.module.css
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
/* Layout changes */
|
||||||
|
|
||||||
|
.FlexNormalizer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
align-items: stretch;
|
||||||
|
justify-content: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.verticalListCrunch {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: flex-start;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layoutAppearable {
|
||||||
|
opacity: 0;
|
||||||
|
height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-top: -8px;
|
||||||
|
transition: all 0.125s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layoutAppearable.appear {
|
||||||
|
opacity: 1;
|
||||||
|
height: initial;
|
||||||
|
overflow: visible;
|
||||||
|
margin-top: 0;
|
||||||
|
transition: all 0.125s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layoutButtonDisabled {
|
||||||
|
opacity: 0.25;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.horizlist {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertilist {
|
||||||
|
display: flex;
|
||||||
|
/* flex-wrap: wrap; */
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: flex-start;
|
||||||
|
gap: 16px !important;
|
||||||
|
/* padding: 8px !important; */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Text stuff */
|
||||||
|
|
||||||
|
.render_info {
|
||||||
|
color: #8cf;
|
||||||
|
}
|
||||||
|
|
||||||
|
.render_warning {
|
||||||
|
color: #ff8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.render_error {
|
||||||
|
color: #f88;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconSmall {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 20px;
|
||||||
|
height: 20px;
|
||||||
|
vertical-align: middle;
|
||||||
|
font-family: "Material Symbols Outlined";
|
||||||
|
font-variation-settings: "FILL" 1, "opsz" 24, "GRAD" 0, "wght" 400;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconTextForm span {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- */
|
||||||
|
|
||||||
|
.textLikeInput {
|
||||||
|
width: 25ch;
|
||||||
|
color: inherit;
|
||||||
|
box-shadow: inset 0 0 2px currentColor;
|
||||||
|
background-color: transparent;
|
||||||
|
border: 1px solid currentColor;
|
||||||
|
|
||||||
|
padding: 4px 8px;
|
||||||
|
border-radius: 2px;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 20px;
|
||||||
|
font-family: "Space Grotesk";
|
||||||
|
cursor: text;
|
||||||
|
|
||||||
|
transition: box-shadow 0.125s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textLikeInput:hover,
|
||||||
|
.textLikeInput:focus,
|
||||||
|
.textLikeInput:active {
|
||||||
|
box-shadow: inset 0 0 8px currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textLikeInputTight {
|
||||||
|
width: 20ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textLikeInputSmall {
|
||||||
|
width: 5ch;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textLikeInputInvisible {
|
||||||
|
box-shadow: none;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
height: 20px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textLikeInputInvisible:hover,
|
||||||
|
.textLikeInputInvisible:focus,
|
||||||
|
.textLikeInputInvisible:active {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textLikeInputMultiline {
|
||||||
|
padding: 8px;
|
||||||
|
height: 10em;
|
||||||
|
max-height: 30em;
|
||||||
|
resize: vertical;
|
||||||
|
width: calc(100% - 18px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.textLikeInputMono {
|
||||||
|
font-family: "Space Mono";
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectInput {
|
||||||
|
cursor: default;
|
||||||
|
}
|
|
@ -1,67 +1,5 @@
|
||||||
@import url(./fonts.css);
|
@import url(./fonts.css);
|
||||||
|
|
||||||
.title {
|
|
||||||
font-size: 24px;
|
|
||||||
line-height: 20px;
|
|
||||||
font-family: "Flow Circular";
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
|
|
||||||
.titleSmall {
|
|
||||||
font-size: 20px;
|
|
||||||
line-height: 16px;
|
|
||||||
font-family: "Flow Circular";
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text {
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 18px;
|
|
||||||
font-family: "Flow Circular";
|
|
||||||
}
|
|
||||||
|
|
||||||
.blockText {
|
|
||||||
display: block;
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 18px;
|
|
||||||
font-family: "Flow Circular";
|
|
||||||
}
|
|
||||||
|
|
||||||
.small {
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 14px;
|
|
||||||
font-family: "Flow Circular";
|
|
||||||
}
|
|
||||||
|
|
||||||
.mono {
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 20px;
|
|
||||||
font-family: "Flow Circular";
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
font-size: 24px;
|
|
||||||
line-height: 24px;
|
|
||||||
font-family: "Material Symbols Outlined";
|
|
||||||
font-variation-settings: "FILL" 1, "opsz" 24, "GRAD" 0, "wght" 400;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconSmall {
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 16px;
|
|
||||||
font-family: "Material Symbols Outlined";
|
|
||||||
font-variation-settings: "FILL" 1, "opsz" 24, "GRAD" 0, "wght" 400;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconlike {
|
|
||||||
font-size: 20px;
|
|
||||||
line-height: 20px;
|
|
||||||
font-family: "Flow Circular";
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link {
|
.link {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
|
@ -75,6 +13,29 @@
|
||||||
text-shadow: 0 0 8px currentColor;
|
text-shadow: 0 0 8px currentColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.linkButton {
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
box-shadow: 0 0 2px currentColor;
|
||||||
|
background-color: transparent;
|
||||||
|
border: 1px solid currentColor;
|
||||||
|
|
||||||
|
padding: 4px 8px;
|
||||||
|
border-radius: 2px;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 20px;
|
||||||
|
font-family: "Space Grotesk";
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
transition: box-shadow 0.125s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.linkButton:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
box-shadow: 0 0 8px currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
box-shadow: 0 0 2px currentColor;
|
box-shadow: 0 0 2px currentColor;
|
||||||
|
@ -85,7 +46,7 @@
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
font-family: "Flow Circular";
|
font-family: "Space Grotesk";
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
transition: box-shadow 0.125s;
|
transition: box-shadow 0.125s;
|
||||||
|
@ -102,7 +63,7 @@
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
font-family: "Flow Circular";
|
font-family: "Space Grotesk";
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
display: inline;
|
display: inline;
|
||||||
|
@ -118,20 +79,118 @@
|
||||||
text-shadow: 0 0 8px currentColor;
|
text-shadow: 0 0 8px currentColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 20px;
|
||||||
|
font-family: "TrollCall Display";
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.titleSmall {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 18px;
|
||||||
|
font-family: "TrollCall Display";
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 20px;
|
||||||
|
font-family: "Space Grotesk";
|
||||||
|
}
|
||||||
|
|
||||||
|
.blockText {
|
||||||
|
display: block;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 20px;
|
||||||
|
font-family: "Space Grotesk";
|
||||||
|
white-space: pre-line;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small {
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 14px;
|
||||||
|
font-family: "Space Grotesk";
|
||||||
|
}
|
||||||
|
|
||||||
|
.mono {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 20px;
|
||||||
|
font-family: "Space Mono";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
height: 24px;
|
||||||
|
font-family: "Material Symbols Outlined";
|
||||||
|
font-variation-settings: "FILL" 1, "opsz" 24, "GRAD" 0, "wght" 400;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconSmall {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 16px;
|
||||||
|
height: 16px;
|
||||||
|
font-family: "Material Symbols Outlined";
|
||||||
|
font-variation-settings: "FILL" 1, "opsz" 24, "GRAD" 0, "wght" 400;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconlike {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 24px;
|
||||||
|
height: 24px;
|
||||||
|
padding-bottom: 2px;
|
||||||
|
vertical-align: middle;
|
||||||
|
font-family: "Space Mono";
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.boxLike {
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.buttonRow,
|
.buttonRow,
|
||||||
.horizontalList {
|
.horizontalList {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
gap: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttonRow {
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.horizontalListLeft {
|
.horizontalListLeft {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
gap: 8px;
|
gap: 0 8px;
|
||||||
|
}
|
||||||
|
.verticalListTop {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: flex-start;
|
||||||
|
gap: 8px 0;
|
||||||
|
}
|
||||||
|
.flexRow {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 0 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconText {
|
.iconText {
|
||||||
|
@ -141,3 +200,85 @@
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.iconTextTop {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttonLeft {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: max-content 1fr;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttonRight {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr max-content;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
padding-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sep {
|
||||||
|
width: 100%;
|
||||||
|
background-color: currentColor;
|
||||||
|
color: currentColor;
|
||||||
|
padding: 0;
|
||||||
|
margin: 8px 0;
|
||||||
|
border: none;
|
||||||
|
height: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sepHeader {
|
||||||
|
width: 100%;
|
||||||
|
background-color: currentColor;
|
||||||
|
color: currentColor;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
border: none;
|
||||||
|
height: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invisep {
|
||||||
|
width: 100%;
|
||||||
|
background-color: transparent;
|
||||||
|
color: transparent;
|
||||||
|
padding: 0;
|
||||||
|
margin: 2px 0;
|
||||||
|
border: none;
|
||||||
|
height: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invisepHeader {
|
||||||
|
width: 100%;
|
||||||
|
background-color: transparent;
|
||||||
|
color: transparent;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
border: none;
|
||||||
|
height: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.signage {
|
||||||
|
filter: drop-shadow(1px 1px 0 currentcolor)
|
||||||
|
drop-shadow(-1px -1px 0 currentcolor)
|
||||||
|
drop-shadow(1px -1px 0 currentcolor)
|
||||||
|
drop-shadow(-1px 1px 0 currentcolor);
|
||||||
|
}
|
||||||
|
|
||||||
|
.headerPG {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
top: -128px;
|
||||||
|
height: 0;
|
||||||
|
width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
|
@ -10,7 +10,14 @@ export const SubmitClanSchema = yup
|
||||||
.min(3)
|
.min(3)
|
||||||
.max(50)
|
.max(50)
|
||||||
.lowercase(),
|
.lowercase(),
|
||||||
displayName: yup.string().notRequired().min(3).max(100),
|
displayName: yup
|
||||||
|
.string()
|
||||||
|
.notRequired()
|
||||||
|
.min(3)
|
||||||
|
.max(100)
|
||||||
|
.transform(v => {
|
||||||
|
return v.length <= 0 ? undefined : v;
|
||||||
|
}),
|
||||||
members: yup
|
members: yup
|
||||||
.array()
|
.array()
|
||||||
.of(
|
.of(
|
||||||
|
|
|
@ -11,10 +11,10 @@ export const SubmitQuirkHolderSchema = yup
|
||||||
])
|
])
|
||||||
.required()
|
.required()
|
||||||
)
|
)
|
||||||
.required()
|
.test("has-default", 'Needs "default" Quirk Mode', v => {
|
||||||
.test("has-default", 'Needs "default" Quirk Mode', v =>
|
if (v == undefined) return true;
|
||||||
v.some(([k, v]) => k === "default" || k === "Default")
|
return v.some(([k, v]) => k === "default" || k === "Default");
|
||||||
);
|
});
|
||||||
|
|
||||||
export type SubmitQuirkHolder = yup.InferType<typeof SubmitQuirkHolderSchema>;
|
export type SubmitQuirkHolder = yup.InferType<typeof SubmitQuirkHolderSchema>;
|
||||||
|
|
||||||
|
|
|
@ -12,14 +12,14 @@ export const SubmitTrollSchema = yup
|
||||||
.string()
|
.string()
|
||||||
.required()
|
.required()
|
||||||
.matches(/^[A-z]+$/, "Letters only")
|
.matches(/^[A-z]+$/, "Letters only")
|
||||||
.min(1)
|
.min(3)
|
||||||
.max(24)
|
.max(24)
|
||||||
.lowercase(),
|
.lowercase(),
|
||||||
yup
|
yup
|
||||||
.string()
|
.string()
|
||||||
.required()
|
.required()
|
||||||
.matches(/^[A-z]+$/, "Letters only")
|
.matches(/^[A-z]+$/, "Letters only")
|
||||||
.min(1)
|
.min(3)
|
||||||
.max(24)
|
.max(24)
|
||||||
.lowercase()
|
.lowercase()
|
||||||
])
|
])
|
||||||
|
@ -71,29 +71,56 @@ export const SubmitTrollSchema = yup
|
||||||
.required()
|
.required()
|
||||||
)
|
)
|
||||||
.required()
|
.required()
|
||||||
.min(1),
|
.min(1)
|
||||||
|
.max(20),
|
||||||
gender: yup
|
gender: yup
|
||||||
.string()
|
.string()
|
||||||
.required()
|
|
||||||
.matches(/^[A-z- ]+$/, "Letters only")
|
.matches(/^[A-z- ]+$/, "Letters only")
|
||||||
.min(3)
|
.max(30)
|
||||||
.max(30),
|
.transform(v => {
|
||||||
|
return v.length <= 0 ? undefined : v;
|
||||||
|
}),
|
||||||
|
|
||||||
// Personal
|
// Personal
|
||||||
preferences: yup.object({
|
preferences: yup
|
||||||
love: yup
|
.object({
|
||||||
.array()
|
love: yup
|
||||||
.of(yup.string().required().min(5).max(500))
|
.array()
|
||||||
.max(10),
|
.of(yup.string().required().min(5).max(500))
|
||||||
hate: yup
|
.min(1)
|
||||||
.array()
|
.max(10)
|
||||||
.of(yup.string().required().min(5).max(500))
|
.transform(v => {
|
||||||
.max(10)
|
return v.length <= 0 ? undefined : v;
|
||||||
}),
|
}),
|
||||||
facts: yup.array().of(yup.string().required().min(5).max(500)).max(10),
|
hate: yup
|
||||||
|
.array()
|
||||||
|
.of(yup.string().required().min(5).max(500))
|
||||||
|
.min(1)
|
||||||
|
.max(10)
|
||||||
|
.transform(v => {
|
||||||
|
return v.length <= 0 ? undefined : v;
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.transform(v => {
|
||||||
|
return v.love == null && v.hate == null ? undefined : v;
|
||||||
|
}),
|
||||||
|
facts: yup
|
||||||
|
.array()
|
||||||
|
.of(yup.string().required().min(5).max(500))
|
||||||
|
.min(1)
|
||||||
|
.max(10)
|
||||||
|
.transform(v => {
|
||||||
|
return v.length <= 0 ? null : v;
|
||||||
|
}),
|
||||||
|
|
||||||
// Hiveswap identity
|
// Hiveswap identity
|
||||||
trueSign: yup.string().required().oneOf(TrueSignKeys),
|
trueSign: yup
|
||||||
|
.string()
|
||||||
|
.nullable()
|
||||||
|
.transform(v => {
|
||||||
|
return v === "" ? null : v;
|
||||||
|
})
|
||||||
|
.oneOf(TrueSignKeys),
|
||||||
falseSign: yup
|
falseSign: yup
|
||||||
.string()
|
.string()
|
||||||
.nullable()
|
.nullable()
|
||||||
|
@ -101,10 +128,16 @@ export const SubmitTrollSchema = yup
|
||||||
return v === "" ? null : v;
|
return v === "" ? null : v;
|
||||||
})
|
})
|
||||||
.oneOf(TrueSignKeys),
|
.oneOf(TrueSignKeys),
|
||||||
class: yup.string().oneOf(ClassKeys),
|
class: yup
|
||||||
|
.string()
|
||||||
|
.nullable()
|
||||||
|
.transform(v => {
|
||||||
|
return v === "" ? null : v;
|
||||||
|
})
|
||||||
|
.oneOf(ClassKeys),
|
||||||
|
|
||||||
// Trollian
|
// Trollian
|
||||||
username: yup.string().max(100),
|
username: yup.string().max(50),
|
||||||
textColor: yup
|
textColor: yup
|
||||||
.tuple([
|
.tuple([
|
||||||
yup.number().min(0).max(255).required(),
|
yup.number().min(0).max(255).required(),
|
||||||
|
@ -119,26 +152,54 @@ export const SubmitTrollSchema = yup
|
||||||
yup.number().min(0).max(255).required()
|
yup.number().min(0).max(255).required()
|
||||||
])
|
])
|
||||||
.notRequired(), // colors the page.
|
.notRequired(), // colors the page.
|
||||||
quirks: SubmitQuirkHolderSchema.required(), // DO NOT HANDLE RIGHT NOW.
|
quirks: SubmitQuirkHolderSchema.notRequired(), // DO NOT HANDLE RIGHT NOW.
|
||||||
quotes: yup.array().of(yup.string().max(1000).required()).max(20),
|
quotes: yup
|
||||||
|
.array()
|
||||||
|
.of(yup.string().max(1000).required())
|
||||||
|
.min(1)
|
||||||
|
.max(20)
|
||||||
|
.transform(v => {
|
||||||
|
return v.length <= 0 ? undefined : v;
|
||||||
|
}),
|
||||||
|
|
||||||
// Physical stuff
|
// Physical stuff
|
||||||
species: yup
|
species: yup
|
||||||
.string()
|
.string()
|
||||||
.notRequired()
|
.notRequired()
|
||||||
.matches(/^([A-z-]+)|()$/, "Letters only")
|
.matches(/^([A-z- ]+)|()$/, "Letters only")
|
||||||
.max(50), // "Troll-*" if defined. Otherwise, just "Troll".
|
.max(50)
|
||||||
height: yup.number().required().positive(), // Inches
|
.transform(v => {
|
||||||
age: yup.number().required().positive(), // Sweeps
|
return v.length <= 0 ? undefined : v;
|
||||||
images: yup.array().of(yup.string().required().url()).required(),
|
}),
|
||||||
|
height: yup.number().required().positive().max(1024), // Inches
|
||||||
|
age: yup.number().required().positive().max(1024), // Sweeps
|
||||||
|
images: yup
|
||||||
|
.array()
|
||||||
|
.of(yup.string().required().url())
|
||||||
|
.required()
|
||||||
|
.min(1)
|
||||||
|
.max(20)
|
||||||
|
.transform(v => {
|
||||||
|
return v.length <= 0 ? undefined : v;
|
||||||
|
}),
|
||||||
// Meta stuff
|
// Meta stuff
|
||||||
policies: yup
|
policies: yup
|
||||||
.object({
|
.object({
|
||||||
fanart: PolicySchema.notRequired(),
|
fanart: PolicySchema.notRequired().transform(v => {
|
||||||
fanartOthers: PolicySchema.notRequired(),
|
return v === "" ? undefined : v;
|
||||||
kinning: PolicySchema.notRequired(),
|
}),
|
||||||
shipping: PolicySchema.notRequired(),
|
fanartOthers: PolicySchema.notRequired().transform(v => {
|
||||||
fanfiction: PolicySchema.notRequired()
|
return v === "" ? undefined : v;
|
||||||
|
}),
|
||||||
|
kinning: PolicySchema.notRequired().transform(v => {
|
||||||
|
return v === "" ? undefined : v;
|
||||||
|
}),
|
||||||
|
shipping: PolicySchema.notRequired().transform(v => {
|
||||||
|
return v === "" ? undefined : v;
|
||||||
|
}),
|
||||||
|
fanfiction: PolicySchema.notRequired().transform(v => {
|
||||||
|
return v === "" ? undefined : v;
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.notRequired()
|
.notRequired()
|
||||||
})
|
})
|
||||||
|
@ -202,15 +263,14 @@ export const PartialTrollSchema = yup
|
||||||
gender: yup
|
gender: yup
|
||||||
.string()
|
.string()
|
||||||
.matches(/^[A-z-_]+$/, "Letters only")
|
.matches(/^[A-z-_]+$/, "Letters only")
|
||||||
.min(3)
|
|
||||||
.max(30),
|
.max(30),
|
||||||
|
|
||||||
// Personal
|
// Personal
|
||||||
preferences: yup.object({
|
preferences: yup.object({
|
||||||
love: yup.array().of(yup.string().min(5).max(500)).max(10),
|
love: yup.array().of(yup.string().min(5).max(500)).min(1).max(10),
|
||||||
hate: yup.array().of(yup.string().min(5).max(500)).max(10)
|
hate: yup.array().of(yup.string().min(5).max(500)).min(1).max(10)
|
||||||
}),
|
}),
|
||||||
facts: yup.array().of(yup.string().min(5).max(500)).max(10),
|
facts: yup.array().of(yup.string().min(5).max(500)).min(1).max(10),
|
||||||
|
|
||||||
// Hiveswap identity
|
// Hiveswap identity
|
||||||
trueSign: yup.string().oneOf(TrueSignKeys),
|
trueSign: yup.string().oneOf(TrueSignKeys),
|
||||||
|
|
|
@ -6,9 +6,8 @@ export type AnyObjectAnd<T> = T & { [key: string]: any };
|
||||||
|
|
||||||
// Color
|
// Color
|
||||||
|
|
||||||
export type ThemerGetSet = [
|
export type ThemeGet = [Color3, Color3, number?, boolean?];
|
||||||
[Color3, Color3, boolean?],
|
export type ThemeGetOpt = [Color3?, Color3?, number?, boolean?];
|
||||||
(x: [Color3, Color3, boolean?]) => void
|
export type ThemeSet = (x: ThemeGetOpt) => void;
|
||||||
];
|
|
||||||
|
|
||||||
export type WidthGetSet = [number, (x: number) => void];
|
export type ThemerGetSet = [ThemeGet, ThemeSet];
|
||||||
|
|
|
@ -1,53 +1,62 @@
|
||||||
export function AdaptivePossessive(owner: string, possession: string) {
|
export function AdaptivePossessive(owner: string, possession: string) {
|
||||||
return owner + (owner.endsWith("s") ? "'" : "'s") + " " + possession;
|
return owner + (owner.endsWith("s") ? "'" : "'s") + " " + possession;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PronounGrouper(
|
export function PronounGrouper(
|
||||||
pronouns: [string, string, string][],
|
pronouns: [string, string, string][],
|
||||||
sep?: string,
|
sep?: string,
|
||||||
amount?: number
|
amount?: number
|
||||||
) {
|
) {
|
||||||
if (pronouns.length > 1)
|
if (pronouns.length > 1)
|
||||||
return pronouns.map((pronounSet) => pronounSet[0]).join("/");
|
return pronouns.map(pronounSet => pronounSet[0]).join("/");
|
||||||
else return pronouns[0].slice(0, amount ?? 2).join(sep ?? "/");
|
else return pronouns[0].slice(0, amount ?? 2).join(sep ?? "/");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function HeightConverter(inches: number) {
|
export function HeightConverter(inches: number) {
|
||||||
var feetandinches = Math.floor(inches / 12) + "'" + (inches % 12) + '"';
|
var feetandinches = Math.floor(inches / 12) + "'" + (inches % 12) + '"';
|
||||||
var meters = Math.floor((inches / 39.37) * 100) / 100 + "m";
|
var meters = Math.floor((inches / 39.37) * 100) / 100 + "m";
|
||||||
return feetandinches + " (" + meters + ")";
|
return feetandinches + " (" + meters + ")";
|
||||||
|
}
|
||||||
|
export function HeightConverterImperial(inches: number) {
|
||||||
|
return Math.floor(inches / 12) + "'" + (inches % 12) + '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function HeightConverterMetric(inches: number) {
|
||||||
|
return Math.floor((inches / 39.37) * 100) / 100 + "m";
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AgeConverter(age: number, years?: boolean) {
|
export function AgeConverter(age: number, years?: boolean) {
|
||||||
return years
|
if (years) return `${Math.round((age / 2.1667) * 10) / 10} sweeps`;
|
||||||
? `${Math.round((age / 2.1667) * 10) / 10} sweeps`
|
else if (years == null) return `${Math.round(age)} years`;
|
||||||
: `${Math.round(age * 2.1667 * 10) / 10} years`;
|
else return `${Math.round(age * 2.1667 * 10) / 10} years`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Pluralize(stringe: string) {
|
export function Pluralize(stringe: string) {
|
||||||
if (stringe.match(/(?:s|ch|sh|x|z|[^aeiou]o)$/)) return stringe + "es";
|
if (stringe.match(/(?:s|ch|sh|x|z|[^aeiou]o)$/)) return stringe + "es";
|
||||||
else if (stringe.match(/[aeiou](?:y|o)$/)) return stringe + "s";
|
else if (stringe.match(/[aeiou](?:y|o)$/)) return stringe + "s";
|
||||||
else if (stringe.match(/[^aeiou]y$/)) return stringe.slice(0, -1) + "ies";
|
else if (stringe.match(/[^aeiou]y$/)) return stringe.slice(0, -1) + "ies";
|
||||||
else if (stringe.match(/(?:f|fe)$/)) return stringe.slice(0, -1) + "ves";
|
else if (stringe.match(/(?:f|fe)$/)) return stringe.slice(0, -1) + "ves";
|
||||||
else return stringe + "s";
|
else return stringe + "s";
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ArraySample(array: any[]) {
|
export function ArraySample(array: any[]) {
|
||||||
return array[Math.floor(Math.random() * array.length)];
|
return array[Math.floor(Math.random() * array.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ProperNounCase(string: string) {
|
export function ProperNounCase(string: string) {
|
||||||
return string
|
return string
|
||||||
.split(" ")
|
.split(" ")
|
||||||
.map((x) => x.charAt(0).toUpperCase() + x.slice(1).toLowerCase())
|
.map(x => x.charAt(0).toUpperCase() + x.slice(1).toLowerCase())
|
||||||
.join(" ");
|
.join(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PesterchumNameFormatter(string: string) {
|
export function PesterchumNameFormatter(string: string) {
|
||||||
return (
|
return (
|
||||||
string +
|
string +
|
||||||
" [" +
|
" [" +
|
||||||
string.replace(/^(([a-z])[a-z]+)(([A-Z])[a-z]+)$/, "$2$4").toUpperCase() +
|
string
|
||||||
"]"
|
.replace(/^(([a-z])[a-z]+)(([A-Z])[a-z]+)$/, "$2$4")
|
||||||
);
|
.toUpperCase() +
|
||||||
|
"]"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { Color3 } from "@/types/assist/color";
|
import { Color3 } from "@/types/assist/color";
|
||||||
|
import { ThemeGet } from "@/types/generics";
|
||||||
import { createContext } from "react";
|
import { createContext } from "react";
|
||||||
|
|
||||||
export default function Themer({
|
export default function Themer({
|
||||||
|
@ -37,11 +38,14 @@ export default function Themer({
|
||||||
|
|
||||||
export const ThemeModeContext = createContext(false as boolean | undefined);
|
export const ThemeModeContext = createContext(false as boolean | undefined);
|
||||||
|
|
||||||
export const defaultTheme: [Color3, Color3] = [
|
export const defaultTheme: ThemeGet = [
|
||||||
new Color3(0.9, 0.9, 0.8),
|
new Color3(0.9, 0.9, 0.8),
|
||||||
new Color3(0.7, 0.7, 0.6)
|
new Color3(0.7, 0.7, 0.6),
|
||||||
|
768
|
||||||
];
|
];
|
||||||
export const hiveswapTheme: [Color3, Color3] = [
|
export const hiveswapTheme: ThemeGet = [
|
||||||
new Color3(0.5, 0, 1),
|
new Color3(0.5, 0, 1),
|
||||||
new Color3(0.25, 0, 0.5)
|
new Color3(0.25, 0, 0.5),
|
||||||
|
768,
|
||||||
|
undefined
|
||||||
];
|
];
|
||||||
|
|
Loading…
Reference in a new issue