fix: landing page ghost button (#919)

This commit is contained in:
saintnoodle
2023-07-31 13:32:34 +01:00
committed by GitHub
parent 888a4dcdf9
commit f09fb64314
20 changed files with 320 additions and 215 deletions
@@ -20,11 +20,12 @@ import { UserContext } from "context/UserContext";
import { UserSettingsContext } from "context/UserSettingsContext";
import { ColourConfig, TachiConfig } from "lib/config";
import React, { useContext, useMemo } from "react";
import { Alert } from "react-bootstrap";
import { Alert, Stack } from "react-bootstrap";
import { Link, Route, Switch } from "react-router-dom";
import { COLOUR_SET, GetGameConfig, UserDocument } from "tachi-common";
import { UGSWithRankingData, UserRecentSummary } from "types/api-returns";
import SessionCalendar from "components/sessions/SessionCalendar";
import { WindowContext } from "context/WindowContext";
import { GameStatContainer } from "./users/UserGamesPage";
import SupportBanner from "./misc/SupportBanner";
@@ -234,19 +235,28 @@ function UserGameStatsInfo({ user }: { user: UserDocument }) {
}
function DashboardNotLoggedIn() {
const {
breakpoint: { isMd },
} = useContext(WindowContext);
return (
<div style={{ fontSize: "1.3rem" }}>
<h1 className="mb-4">Welcome to {TachiConfig.name}!</h1>
<h4>
Looks like you're not logged in. If you've got an account,{" "}
<Link to="/login">Login!</Link>
</h4>
<Divider />
<h1 className="my-4">I'm New Around Here, What is this?</h1>
<span>
<b>{TachiConfig.name}</b> is a Rhythm Game Score Tracker. That means we...
</span>
<Stack gap={4} className="enable-rfs" style={{ fontSize: "16px" }}>
<div>
<h1 className="fw-bold">Welcome to {TachiConfig.name}!</h1>
<h4 className="fs-3">
Looks like you're not logged in. If you've got an account,{" "}
<Link className="link-primary text-decoration-underline" to="/login">
Login!
</Link>
</h4>
</div>
<Divider />
<div>
<h1>I'm New Around Here, What is this?</h1>
<p>
<b>{TachiConfig.name}</b> is a Rhythm Game Score Tracker. That means we...
</p>
</div>
<Divider className="mb-2" />
<FeatureContainer
tagline="Track Your Scores."
description={`${TachiConfig.name} supports a bunch of your favourite games, and integrates with many existing services to make sure no score is lost to the void. Furthermore, it's backed by an Open-Source API, so your scores are always available!`}
@@ -260,32 +270,31 @@ function DashboardNotLoggedIn() {
description={`${TachiConfig.name} implements the features rhythm gamers already talk about. Break your scores down into sessions, Showcase your best metrics on your profile, study your progress on folders - it's all there, and done for you!`}
/>
<Divider />
<div className="col-12 text-center" style={{ paddingTop: 50, paddingBottom: 50 }}>
Interested? You can register right now for <b>free</b>!
<br />
<LinkButton to="/register" className="mt-4 btn-outline-primary">
Register!
<Stack direction={isMd ? "horizontal" : "vertical"} className="mx-auto gap-4 gap-md-8">
<h1 className="fw-bold p-0 m-0 text-center">Interested?</h1>
<div className="vr d-none d-md-block" />
<hr className="m-0 mb-2 d-md-none" />
<LinkButton to="/register" size="lg" className="align-self-center">
Create an account for <b>free</b>!
</LinkButton>
</div>
</Stack>
<Divider />
<div className="col-12 text-center" style={{ paddingTop: 25 }}>
<div className="text-center">
Nosey? Here's what our users are up to.
<br />
<div style={{ fontSize: "1.0rem" }}>
<div style={{ fontSize: "1rem" }}>
<Activity url="/activity" />
</div>
</div>
</div>
</Stack>
);
}
function FeatureContainer({ tagline, description }: { tagline: string; description: string }) {
return (
<div className="row my-4 mb-16" style={{ lineHeight: "1.3", fontSize: "1.15rem" }}>
<div className="col-12 col-lg-6">
<h1 className="display-4">{tagline}</h1>
<span>{description}</span>
</div>
<div style={{ maxWidth: "790px" }}>
<h1 className="display-3 fw-light">{tagline}</h1>
<p>{description}</p>
</div>
);
}
@@ -3,7 +3,7 @@ import Divider from "components/util/Divider";
import ExternalLink from "components/util/ExternalLink";
import { TachiConfig } from "lib/config";
import React from "react";
import { Alert } from "react-bootstrap";
import Alert from "react-bootstrap/Alert";
export default function BarbatosPage() {
useSetSubheader(["Import Scores", "Barbatos"]);
@@ -23,12 +23,18 @@ export default function BarbatosPage() {
Download <code>barbatos.dll</code>.{" "}
<ul>
<li>
<ExternalLink href="https://f.wcal.xyz/2W9K7kXl">
<ExternalLink
className="text-decoration-underline"
href="https://f.wcal.xyz/2W9K7kXl"
>
VIVID WAVE
</ExternalLink>
</li>
<li>
<ExternalLink href="https://f.wcal.xyz/3VqnDgcC">
<ExternalLink
className="text-decoration-underline"
href="https://f.wcal.xyz/3VqnDgcC"
>
EXCEED GEAR
</ExternalLink>
.
@@ -37,8 +43,16 @@ export default function BarbatosPage() {
</li>
<li>
Download your config file{" "}
<ExternalLink href="/client-file-flow/CXBarbatos">here</ExternalLink>. <br />
<b>This file contains an API Key, which is meant to be kept secret!</b>
<ExternalLink
className="text-decoration-underline"
href="/client-file-flow/CXBarbatos"
>
here
</ExternalLink>
. <br />
<Alert variant="warning" className="mt-2">
This file contains an API Key, which is meant to be kept secret!
</Alert>
</li>
<li>
Place <code>barbatos.dll</code> and the above config file inside your SDVX
@@ -4,6 +4,7 @@ import ExternalLink from "components/util/ExternalLink";
import Muted from "components/util/Muted";
import { TachiConfig } from "lib/config";
import React from "react";
import Alert from "react-bootstrap/Alert";
const WIN_BAT = `
REM *** Set system-wide "_JAVA_OPTIONS" environment variable to use OpenGL pipeline (improved performance of > 30% potentially. Also use anti-aliasing for non-LR2 fonts, and finally allow Swing framework to utilize AA and GTKLookAndFeel for config window. ***
@@ -32,7 +33,10 @@ export default function BeatorajaIRPage({ game }: { game: "bms" | "pms" }) {
<ol className="instructions-list">
<li>
Download the latest version of the {name} IR{" "}
<ExternalLink href="https://github.com/TNG-dev/tachi-beatoraja-ir/releases">
<ExternalLink
className="text-decoration-underline"
href="https://github.com/TNG-dev/tachi-beatoraja-ir/releases"
>
here
</ExternalLink>
.
@@ -44,7 +48,10 @@ export default function BeatorajaIRPage({ game }: { game: "bms" | "pms" }) {
<b>NOT</b> support BMS scores achieved on beatoraja, and will not accept
scores from the client.
<br />
<ExternalLink href="https://github.com/wcko87/lr2oraja/releases">
<ExternalLink
className="text-decoration-underline"
href="https://github.com/wcko87/lr2oraja/releases"
>
LR2oraja
</ExternalLink>{" "}
is a one-file change for beatoraja that changes the settings to match
@@ -68,7 +75,7 @@ export default function BeatorajaIRPage({ game }: { game: "bms" | "pms" }) {
<li>
Select {TachiConfig.name} IR.
<br />
<span className="text-warning">
<Alert className="mt-2" variant="warning">
If the IR isn't showing up, make sure you're launching the game with the{" "}
<code>beatoraja-config.bat</code> file. Otherwise, IRs will never load.
<br />
@@ -80,6 +87,7 @@ export default function BeatorajaIRPage({ game }: { game: "bms" | "pms" }) {
<a
download="beatoraja-config.bat"
href={`data:text/plain;base64,${window.btoa(WIN_BAT)}`}
className="text-decoration-underline"
>
Windows
</a>
@@ -88,26 +96,32 @@ export default function BeatorajaIRPage({ game }: { game: "bms" | "pms" }) {
<a
download="beatoraja-config.sh"
href={`data:text/plain;base64,${window.btoa(LINUX_SH)}`}
className="text-decoration-underline"
>
Linux
</a>
</li>
</ul>
</span>
</Alert>
</li>
<li>
Get an API token for the IR by clicking{" "}
<ExternalLink href="/client-file-flow/CXBeatorajaIR">this link</ExternalLink>.
<ExternalLink
className="text-decoration-underline"
href="/client-file-flow/CXBeatorajaIR"
>
this link
</ExternalLink>
.
</li>
<li>
Place the API token in the password field. Put your username in as well! The IR
wont load if you don't have a username set.
<br />
<span className="text-warning">
<Alert className="mt-2" variant="warning">
<b>DO NOT PUT YOUR PASSWORD IN THE PASSWORD FIELD!</b>
<br />
For security reasons, you must put the API Key in that field, instead.
</span>
</Alert>
</li>
<li>
That's it! Launch the game and start playing, your scores will automatically
@@ -3,6 +3,7 @@ import Divider from "components/util/Divider";
import ExternalLink from "components/util/ExternalLink";
import { TachiConfig } from "lib/config";
import React from "react";
import Alert from "react-bootstrap/Alert";
export default function ChunitachiPage() {
useSetSubheader(["Import Scores", "Chunitachi"]);
@@ -20,19 +21,33 @@ export default function ChunitachiPage() {
<ol className="instructions-list">
<li>
Download <code>chunitachi.dll</code> from{" "}
<ExternalLink href="https://github.com/tomatosoupcan/ChunItachi/releases">
Here
<ExternalLink
className="text-decoration-underline"
href="https://github.com/tomatosoupcan/ChunItachi/releases"
>
here
</ExternalLink>
.
</li>
<li>
Download your <code>ChunItachi.ini</code> config file{" "}
<ExternalLink href="/client-file-flow/CXChunitachi">here</ExternalLink>. <br />
<b>This config file contains an API Key, which should be kept secret!</b>.
<ExternalLink
className="text-decoration-underline"
href="/client-file-flow/CXChunitachi"
>
here
</ExternalLink>
. <br />
<Alert variant="warning" className="mt-2">
This config file contains an API Key, which should be kept secret!
</Alert>
</li>
<li>
Follow the remaining install instructions on{" "}
<ExternalLink href="https://github.com/tomatosoupcan/ChunItachi/blob/main/README.md">
<ExternalLink
className="text-decoration-underline"
href="https://github.com/tomatosoupcan/ChunItachi/blob/main/README.md"
>
GitHub
</ExternalLink>
.
@@ -3,7 +3,7 @@ import Divider from "components/util/Divider";
import ExternalLink from "components/util/ExternalLink";
import { TachiConfig } from "lib/config";
import React from "react";
import { Alert } from "react-bootstrap";
import Alert from "react-bootstrap/Alert";
import { Link } from "react-router-dom";
export default function FervidexPage() {
@@ -22,12 +22,26 @@ export default function FervidexPage() {
<ol className="instructions-list">
<li>
Download <code>fervidex.dll</code> from{" "}
<ExternalLink href="https://client.fervidex.net/latest.zip">Here</ExternalLink>.
<ExternalLink
className="text-decoration-underline"
href="https://client.fervidex.net/latest.zip"
>
here
</ExternalLink>
.
</li>
<li>
Download your <code>fervidex.json</code> config file{" "}
<ExternalLink href="/client-file-flow/CXFervidex">here</ExternalLink>. <br />
<b>This config file contains an API Key, which should be kept secret!</b>.
<ExternalLink
className="text-decoration-underline"
href="/client-file-flow/CXFervidex"
>
here
</ExternalLink>
. <br />
<Alert variant="warning" className="mt-2">
This config file contains an API Key, which should be kept secret!
</Alert>
</li>
<li>
Drop both files into the same folder as your <code>bm2dx.dll</code>.
@@ -36,7 +50,10 @@ export default function FervidexPage() {
<ul className="instructions-list">
<li>
You'll also need to download{" "}
<ExternalLink href="https://client.fervidex.net/latest-chainloader.zip">
<ExternalLink
className="text-decoration-underline"
href="https://client.fervidex.net/latest-chainloader.zip"
>
this
</ExternalLink>
, and extract it to the same folder.
@@ -58,9 +75,8 @@ export default function FervidexPage() {
Looking to import existing scores? Import from your network first. If that's not
possible, enable "Sync Existing Scores" in{" "}
<Link
className="gentle-link"
className="text-decoration-underline"
to={"/u/me/integrations/services/fervidex"}
style={{ color: "black", textDecoration: "underline" }}
>
<b>your settings.</b>
</Link>
@@ -29,7 +29,10 @@ export default function ITGHookPage() {
<ol className="instructions-list">
<li>
Download the latest version of <code>Tachi.lua</code>{" "}
<ExternalLink href="https://github.com/TNG-Dev/Simply-Love-Tachi-Module">
<ExternalLink
className="text-decoration-underline"
href="https://github.com/TNG-Dev/Simply-Love-Tachi-Module"
>
here
</ExternalLink>
.
@@ -39,7 +42,13 @@ export default function ITGHookPage() {
</li>
<li>
Get your <code>Tachi.json</code> file by clicking{" "}
<ExternalLink href="/client-file-flow/CXITGHook">this link</ExternalLink>.
<ExternalLink
className="text-decoration-underline"
href="/client-file-flow/CXITGHook"
>
this link
</ExternalLink>
.
</li>
<li>
Place this file inside your user profile. It should go next to
@@ -3,6 +3,7 @@ import Divider from "components/util/Divider";
import ExternalLink from "components/util/ExternalLink";
import { TachiConfig } from "lib/config";
import React from "react";
import Alert from "react-bootstrap/Alert";
export default function KsHookPage() {
useSetSubheader(["Import Scores", "Konaste Hook"]);
@@ -20,15 +21,26 @@ export default function KsHookPage() {
<ol className="instructions-list">
<li>
Download the latest version of <code>kshook.dll</code> from{" "}
<ExternalLink href="https://djtrackers.com/kshook/latest.zip">
<ExternalLink
className="text-decoration-underline"
href="https://djtrackers.com/kshook/latest.zip"
>
here
</ExternalLink>
.
</li>
<li>
Download your config file{" "}
<ExternalLink href="/client-file-flow/CXKsHook">here</ExternalLink>. <br />
<b>This file contains an API Key, which is meant to be kept secret!</b>
<ExternalLink
className="text-decoration-underline"
href="/client-file-flow/CXKsHook"
>
here
</ExternalLink>
. <br />
<Alert variant="warning" className="mt-2">
This file contains an API Key, which is meant to be kept secret!
</Alert>
</li>
<li>Place all of these files inside your SDVX6 (EAC) folder.</li>
<li>
@@ -4,6 +4,7 @@ import ExternalLink from "components/util/ExternalLink";
import Muted from "components/util/Muted";
import { TachiConfig } from "lib/config";
import React from "react";
import Alert from "react-bootstrap/Alert";
export default function SilentHookPage() {
useSetSubheader(["Import Scores", "Silent Hook"]);
@@ -21,8 +22,11 @@ export default function SilentHookPage() {
<ol className="instructions-list">
<li>
Download <code>silent</code> from{" "}
<ExternalLink href="https://zkldi.xyz/stuff/silent-latest.zip">
Here
<ExternalLink
className="text-decoration-underline"
href="https://zkldi.xyz/stuff/silent-latest.zip"
>
here
</ExternalLink>{" "}
and place all the <code>.dll</code> files in the same folder as{" "}
<code>popn22.dll</code>.
@@ -31,8 +35,16 @@ export default function SilentHookPage() {
</li>
<li>
Download your config file to the same folder{" "}
<ExternalLink href="/client-file-flow/CXSilentHook">here</ExternalLink>. <br />
<b>This file contains an API Key, which is meant to be kept secret!</b>
<ExternalLink
className="text-decoration-underline"
href="/client-file-flow/CXSilentHook"
>
here
</ExternalLink>
. <br />
<Alert variant="warning" className="mt-2">
This file contains an API Key, which is meant to be kept secret!
</Alert>
</li>
<li>
Add <code>silent</code> to your startup script as a hook.
@@ -4,6 +4,7 @@ import Divider from "components/util/Divider";
import Muted from "components/util/Muted";
import { TachiConfig } from "lib/config";
import React from "react";
import Alert from "react-bootstrap/Alert";
import { Link } from "react-router-dom";
export default function USCDBPage() {
@@ -12,12 +13,14 @@ export default function USCDBPage() {
<>
<TISInfo name="USC Database" />
<Divider />
<Muted>
<Alert variant="info">
This method is intended for syncing up with existing scores. For new scores, you
should set up the <Link to="/import/usc-ir">USC IR</Link>, for automatic score
uploading.
</Muted>
<br />
should set up the{" "}
<Link className="text-decoration-underline" to="/import/usc-ir">
USC IR
</Link>
, for automatic score uploading.
</Alert>
<Muted>
Note: If you submit a score on a chart that {TachiConfig.name} doesn't recognise,
you'll need to wait until atleast 2 other players submit scores for that chart
@@ -38,8 +38,13 @@ export default function USCIRPage() {
<Divider />
<li>
Grab an API Token from{" "}
<ExternalLink href="/client-file-flow/CXUSCIR">here</ExternalLink>, and place it
in the API Token field.
<ExternalLink
className="text-decoration-underline"
href="/client-file-flow/CXUSCIR"
>
here
</ExternalLink>
, and place it in the API Token field.
</li>
<li>That's it! Your scores will now automatically upload to the server.</li>
</ol>
@@ -50,7 +50,10 @@ export default function WACCASiteImportPage() {
<div>
<h1 className="text-center mb-4">What Is WaccaMyPageScraper?</h1>
<div>
<ExternalLink href="https://github.com/XezolesS/WaccaMyPageScraper/">
<ExternalLink
className="text-decoration-underline"
href="https://github.com/XezolesS/WaccaMyPageScraper/"
>
WaccaMyPageScraper
</ExternalLink>{" "}
is a scraper for the official WACCA MyPage service site. Since the site is offline
@@ -9,9 +9,10 @@ import Muted from "components/util/Muted";
import SelectButton from "components/util/SelectButton";
import { UserSettingsContext } from "context/UserSettingsContext";
import { useFormik } from "formik";
import React, { useContext, useState } from "react";
import { Alert, Button, Form } from "react-bootstrap";
import React, { useContext, useRef, useState } from "react";
import { Alert, Button, Form, Stack } from "react-bootstrap";
import { UserDocument, UserSettingsDocument } from "tachi-common";
import { SetState } from "types/react";
interface Props {
reqUser: UserDocument;
@@ -269,10 +270,18 @@ function PreferencesForm({ reqUser }: { reqUser: UserDocument }) {
function ImageForm({ reqUser }: { reqUser: UserDocument }) {
const [pfp, setPfp] = useState<File | undefined>();
const pfpInput = useRef(null);
const [banner, setBanner] = useState<File | undefined>();
const bannerInput = useRef<HTMLInputElement>(null);
const handleReset = (ref: React.MutableRefObject<HTMLInputElement | null>) => {
if (ref.current) {
ref.current.value = "";
}
};
return (
<div className="d-flex flex-column">
<Stack gap={4}>
<Alert variant="danger">
Do not set inappropriate stuff as your avatar/banner. If you have to ask, the answer
is probably no.
@@ -282,11 +291,11 @@ function ImageForm({ reqUser }: { reqUser: UserDocument }) {
<input
className="form-control"
accept="image/png,image/jpeg,image/gif"
tabIndex={1}
type="file"
id="pfp"
multiple={false}
onChange={(e) => setPfp(e.target.files![0])}
ref={pfpInput}
/>
<div className="d-flex justify-content-center mt-4">
<ProfilePicture
@@ -294,18 +303,24 @@ function ImageForm({ reqUser }: { reqUser: UserDocument }) {
src={pfp ? URL.createObjectURL(pfp) : ToAPIURL(`/users/${reqUser.id}/pfp`)}
/>
</div>
<FileUploadController file={pfp} reqUser={reqUser} type="pfp" />
<FileUploadController
setFile={setPfp}
reset={() => handleReset(pfpInput)}
file={pfp}
reqUser={reqUser}
type="pfp"
/>
</Form.Group>
<Form.Group>
<Form.Label>Profile Banner</Form.Label>
<input
className="form-control"
accept="image/png,image/jpeg,image/gif"
tabIndex={2}
type="file"
id="banner"
multiple={false}
onChange={(e) => setBanner(e.target.files![0])}
ref={bannerInput}
/>
<div
className="d-flex justify-content-center mt-4 rounded"
@@ -322,15 +337,21 @@ function ImageForm({ reqUser }: { reqUser: UserDocument }) {
})`,
}}
/>
<FileUploadController file={banner} reqUser={reqUser} type="banner" />
<FileUploadController
setFile={setBanner}
reset={() => handleReset(bannerInput)}
file={banner}
reqUser={reqUser}
type="banner"
/>
</Form.Group>
</div>
</Stack>
);
}
function SocialMediaForm({ reqUser }: { reqUser: UserDocument }) {
const placeholders = {
discord: "Example#0000",
discord: "Discord Username",
twitter: "Twitter Handle",
twitch: "Twitch Username",
github: "Github Username",
@@ -429,32 +450,57 @@ function FileUploadController({
file,
type,
reqUser,
setFile,
reset,
}: {
file?: File;
type: "pfp" | "banner";
reqUser: UserDocument;
setFile: SetState<File | undefined>;
reset: () => void;
}) {
return (
<div className="d-flex mt-8">
<Button
onClick={async () => {
const res = await APIFetchV1(
`/users/me/${type}`,
{ method: "DELETE" },
true,
true
);
<div className="d-flex mt-8 justify-content-end">
{file ? (
<Button
variant="secondary"
onClick={() => {
setFile(undefined);
reset();
}}
>
Cancel
</Button>
) : (
<Button
onClick={async () => {
if (
confirm(
`Are you sure you want to clear your ${
type === "pfp" ? "profile picture?" : "profile banner?"
}`
)
) {
const res = await APIFetchV1(
`/users/me/${type}`,
{ method: "DELETE" },
true,
true
);
if (res.success) {
DelayedPageReload();
if (res.success) {
DelayedPageReload();
}
}
}}
disabled={
type === "pfp" ? !reqUser.customPfpLocation : !reqUser.customBannerLocation
}
}}
disabled={!reqUser.customPfpLocation}
className="ms-auto"
variant="secondary"
>
Unset
</Button>
variant="danger"
>
Clear {type === "pfp" ? "Profile Picture" : "Profile Banner"}
</Button>
)}
{file && (
<div className="mx-auto">
<SizeWarner bytes={file.size} cap={1024} />
@@ -480,7 +526,6 @@ function FileUploadController({
window.location.reload();
}
}}
className="ms-auto"
variant="success"
disabled={file.size > 1024 * 1000}
>
+6 -6
View File
@@ -37,7 +37,7 @@ import {
ClumpedActivitySession,
} from "types/tachi";
import { InnerQuestSectionGoal } from "components/targets/quests/Quest";
import ProfilePicture, { ProfilePictureSmall } from "components/user/ProfilePicture";
import ProfilePicture from "components/user/ProfilePicture";
import SupporterIcon from "components/util/SupporterIcon";
// Records activity for a group of users on a GPT. Also used for single users.
@@ -292,7 +292,7 @@ function ScoresActivity({
<div className="timeline-content-inner" onClick={() => setShow(!show)}>
<div className="timeline-content-title">
<span className="me-2">
<ProfilePictureSmall user={user} toGPT={`${game}/${playtype}`} />
<ProfilePicture size="sm" user={user} toGPT={`${game}/${playtype}`} />
</span>
<Icon
type={`chevron-${show ? "down" : "right"}`}
@@ -374,7 +374,7 @@ function GoalActivity({
<div className="timeline-content-inner" onClick={() => setShow(!show)}>
<div className="timeline-content-title">
<span className="me-2">
<ProfilePictureSmall user={user} toGPT={`${game}/${playtype}`} />
<ProfilePicture size="sm" user={user} toGPT={`${game}/${playtype}`} />
</span>
<Icon
type={`chevron-${show ? "down" : "right"}`}
@@ -443,7 +443,7 @@ function QuestActivity({
<div className="timeline-content-title">
<span style={{ fontSize: "1.15rem" }}>
<span className="me-2">
<ProfilePictureSmall user={user} toGPT={`${game}/${playtype}`} />
<ProfilePicture size="sm" user={user} toGPT={`${game}/${playtype}`} />
</span>
<UGPTLink reqUser={user} game={game} playtype={playtype} /> completed
the{" "}
@@ -495,7 +495,7 @@ function SessionActivity({
<div className="timeline-content-inner" onClick={() => setShow(!show)}>
<div className="timeline-content-title">
<span className="me-2">
<ProfilePictureSmall user={user} toGPT={`${game}/${playtype}`} />
<ProfilePicture size="sm" user={user} toGPT={`${game}/${playtype}`} />
</span>
<Icon
type={`chevron-${show ? "down" : "right"}`}
@@ -641,7 +641,7 @@ function ClassAchievementActivity({
<div className="timeline-content-inner">
<div className="timeline-content-title">
<span className="me-2">
<ProfilePictureSmall
<ProfilePicture size="sm"
user={user}
toGPT={`${data.game}/${data.playtype}`}
/>
+4 -1
View File
@@ -9,7 +9,10 @@ export default function TISInfo({ name }: { name: string }) {
<ol className="instructions-list">
<li>
Download the latest version of the {TachiConfig.name} Import Scripts{" "}
<ExternalLink href="https://github.com/TNG-dev/tachi-import-scripts/releases">
<ExternalLink
className="text-decoration-underline"
href="https://github.com/TNG-dev/tachi-import-scripts/releases"
>
here
</ExternalLink>
.
@@ -1,6 +1,6 @@
import { AllLUGPTStatsContext } from "context/AllLUGPTStatsContext";
import { UserSettingsContext } from "context/UserSettingsContext";
import React, { useContext } from "react";
import React, { useContext, useEffect } from "react";
import { UserDocument, UserGameStats } from "tachi-common";
import useApiQuery from "components/util/query/useApiQuery";
import Nav from "react-bootstrap/Nav";
@@ -30,13 +30,15 @@ export function HeaderMenu({
"game_stats",
]);
if (error) {
console.error(error);
}
useEffect(() => {
if (error) {
console.error(error);
}
if (data) {
setUGS(data);
}
if (data) {
setUGS(data);
}
}, [error, data]);
return (
<Nav className="p-4 d-flex flex-column flex-lg-row align-content-between gap-2 gap-lg-4 overflow-y-auto overflow-y-lg-visible scrollbar-hide h-100">
@@ -1,7 +1,7 @@
import React from "react";
import LinkButton from "components/util/LinkButton";
import { UserDocument } from "tachi-common/types/documents";
import { ProfilePictureSmall } from "components/user/ProfilePicture";
import ProfilePicture from "components/user/ProfilePicture";
import { UserNotificationButton } from "./UserNotificationButton";
import { UserProfileDropdown } from "./UserProfileDropdown";
import { SearchButton } from "./SearchButton";
@@ -28,8 +28,7 @@ export default function UserArea({
<UserNotificationButton />
<UserProfileDropdown style={dropdownMenuStyle} user={user} />
<div className="h-14 w-14 d-flex d-lg-none justify-content-center align-items-center">
{/* a temporary solution */}
<ProfilePictureSmall user={user} />
<ProfilePicture size="sm" user={user} />
</div>
</>
)}
@@ -10,6 +10,7 @@ import SignOut from "components/util/SignOut";
import QuickDropdown from "components/ui/QuickDropdown";
import { TextColour } from "types/bootstrap";
import DropdownNavLink from "components/ui/DropdownNavLink";
import ProfilePicture from "components/user/ProfilePicture";
function UserProfileDropdownToggle({ user }: { user: UserDocument }) {
const [heySplash] = useState(RFA(heySplashes));
@@ -25,13 +26,7 @@ function UserProfileDropdownToggle({ user }: { user: UserDocument }) {
</>
)}
</div>
<img
alt={user.username}
height={32}
width={32}
src={ToAPIURL("/users/me/pfp")}
className="object-fit-cover rounded"
/>
<ProfilePicture size="sm" link={false} user={user} />
</>
);
}
@@ -4,9 +4,12 @@ import SplashImage from "../misc/SplashImage";
export function SplashScreen({ broke }: { broke: string }) {
return (
<div id="splash-screen" className="splash-screen">
<div
id="splash-screen"
className="bg-body position-fixed inset-0 d-flex flex-column justify-content-center align-items-center"
>
<SplashImage />
{!broke && <CircularProgress className="splash-screen-spinner" />}
{!broke && <CircularProgress />}
{broke && <p className="mt-4">{broke}</p>}
</div>
);
+30 -84
View File
@@ -5,101 +5,47 @@ import { Link } from "react-router-dom";
export default function ProfilePicture({
user,
src,
src: imgUrl,
toGPT = "",
link = true,
size = "lg",
}: {
user: UserDocument | string;
user: UserDocument;
/**
* Specify an image src instead of infering one from the user's info
*/
src?: string;
/**
* Whether or not this profile picture should be a link (default = true)
*/
link?: boolean;
/**
* sm = 32px, lg = 128px
*/
size?: "sm" | "lg";
/**
* When clicking this this profile, should it take you to a UGPT page?
*/
toGPT?: string;
}) {
if (typeof user === "string") {
const dimensions = size === "sm" ? 32 : 128;
const props = {
src: imgUrl ? imgUrl : ToAPIURL(`/users/${user.id}/pfp`),
alt: `${user.username}'s Profile Picture`,
height: dimensions,
width: dimensions,
className: "d-inline-block object-fit-cover bg-body-tertiary shadow-sm rounded fs-0",
};
if (link) {
return (
<Link to={`/u/${user}/${toGPT}`}>
<img
src={src ? src : ToAPIURL(`/users/${user}/pfp`)}
alt={`${user}'s Profile Picture`}
className="rounded"
style={{
width: "128px",
height: "128px",
objectFit: "cover",
boxShadow: "0px 0px 10px 0px #000000",
}}
/>
<Link to={`/u/${user.username}/${toGPT}`}>
<img {...props} />
</Link>
);
}
return (
<Link to={`/u/${user.username}/${toGPT}`}>
<img
src={src ? src : ToAPIURL(`/users/${user.id}/pfp`)}
alt={`${user.username}'s Profile Picture`}
className="rounded"
style={{
width: "128px",
height: "128px",
objectFit: "cover",
boxShadow: "0px 0px 10px 0px #000000",
}}
/>
</Link>
);
}
export function ProfilePictureSmall({
user,
src,
toGPT = "",
}: {
user: UserDocument | string;
src?: string;
/**
* When clicking this this profile, should it take you to a UGPT page?
*/
toGPT?: string;
}) {
if (toGPT) {
// eslint-disable-next-line no-param-reassign
toGPT = `games/${toGPT}`;
}
if (typeof user === "string") {
return (
<Link to={`/u/${user}/${toGPT}`}>
<img
src={src ? src : ToAPIURL(`/users/${user}/pfp`)}
alt={`${user}'s Profile Picture`}
className="rounded"
style={{
width: "32px",
height: "32px",
objectFit: "cover",
boxShadow: "0px 0px 10px 0px #000000",
}}
/>
</Link>
);
}
return (
<Link to={`/u/${user.username}/${toGPT}`}>
<img
src={src ? src : ToAPIURL(`/users/${user.id}/pfp`)}
alt={`${user.username}'s Profile Picture`}
className="rounded"
style={{
width: "32px",
height: "32px",
objectFit: "cover",
boxShadow: "0px 0px 10px 0px #000000",
}}
/>
</Link>
);
return <img {...props} />;
}
@@ -637,11 +637,11 @@ $line-height-base: 1.5;
$line-height-sm: 1.25;
$line-height-lg: 2;
$h1-font-size: $font-size-base * 2;
$h2-font-size: $font-size-base * 1.75;
$h3-font-size: $font-size-base * 1.5;
$h4-font-size: $font-size-base * 1.25;
$h5-font-size: $font-size-base * 1.125;
$h1-font-size: $font-size-base * 2.5;
$h2-font-size: $font-size-base * 2;
$h3-font-size: $font-size-base * 1.75;
$h4-font-size: $font-size-base * 1.5;
$h5-font-size: $font-size-base * 1.25;
$h6-font-size: $font-size-base;
// scss-docs-end font-variables
@@ -650,7 +650,7 @@ $h6-font-size: $font-size-base;
$rfs-rem-value: 13;
$rfs-base-value: $font-size-base;
$rfs-factor: 25; // setting this <= 1 throws an error ==> bootstrap-scss/vendor/_rfs.scss:34
$rfs-breakpoint: 648px;
$rfs-breakpoint: 576px;
$rfs-class: "enable"; // this allows us to enable it with a class selector only when we want it
// scss-docs-start font-sizes
@@ -715,8 +715,8 @@ $hr-height: null !default; // Deprecated in v5.2.0
// fusv-enable
$hr-border-color: null !default; // Allows for inherited colors
$hr-border-width: var(--#{$prefix}border-width) !default;
$hr-opacity: 0.25 !default;
$hr-border-width: var(--#{$prefix}border-width);
$hr-opacity: 0.1;
$legend-margin-bottom: 0.5rem;
$legend-font-size: 1.5rem;