mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-05-05 20:56:13 -05:00
Initial
This commit is contained in:
parent
6bcdb2c657
commit
a44be81ad3
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -27,3 +27,4 @@ dump
|
|||
/playwright/.cache/
|
||||
|
||||
notepad.txt
|
||||
.vitest-attachments/
|
||||
|
|
|
|||
|
|
@ -3,6 +3,17 @@
|
|||
flex-direction: row;
|
||||
}
|
||||
|
||||
.containerWithSideNav {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mainWrapper {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.main {
|
||||
padding-block: var(--s-4) var(--s-32);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ export const Main = ({
|
|||
halfWidth,
|
||||
bigger,
|
||||
style,
|
||||
sideNav,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
|
|
@ -18,6 +19,7 @@ export const Main = ({
|
|||
halfWidth?: boolean;
|
||||
bigger?: boolean;
|
||||
style?: React.CSSProperties;
|
||||
sideNav?: React.ReactNode;
|
||||
}) => {
|
||||
const error = useRouteError();
|
||||
const isMinorSupporter = useHasRole("MINOR_SUPPORT");
|
||||
|
|
@ -26,32 +28,41 @@ export const Main = ({
|
|||
!isMinorSupporter &&
|
||||
!isRouteErrorResponse(error);
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<main
|
||||
className={
|
||||
classNameOverwrite
|
||||
? clsx(classNameOverwrite, {
|
||||
const mainElement = (
|
||||
<main
|
||||
className={
|
||||
classNameOverwrite
|
||||
? clsx(classNameOverwrite, {
|
||||
[styles.narrow]: halfWidth,
|
||||
"pt-8-forced": showLeaderboard,
|
||||
})
|
||||
: clsx(
|
||||
styles.main,
|
||||
styles.normal,
|
||||
{
|
||||
[styles.narrow]: halfWidth,
|
||||
[styles.wide]: bigger,
|
||||
"pt-8-forced": showLeaderboard,
|
||||
})
|
||||
: clsx(
|
||||
styles.main,
|
||||
styles.normal,
|
||||
{
|
||||
[styles.narrow]: halfWidth,
|
||||
[styles.wide]: bigger,
|
||||
"pt-8-forced": showLeaderboard,
|
||||
},
|
||||
className,
|
||||
)
|
||||
}
|
||||
style={style}
|
||||
>
|
||||
{children}
|
||||
</main>
|
||||
</div>
|
||||
},
|
||||
className,
|
||||
)
|
||||
}
|
||||
style={style}
|
||||
>
|
||||
{children}
|
||||
</main>
|
||||
);
|
||||
|
||||
if (sideNav) {
|
||||
return (
|
||||
<div className={styles.containerWithSideNav}>
|
||||
{sideNav}
|
||||
<div className={styles.mainWrapper}>{mainElement}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return <div className={styles.container}>{mainElement}</div>;
|
||||
};
|
||||
|
||||
export { styles as mainStyles };
|
||||
|
|
|
|||
61
app/components/SideNav.module.css
Normal file
61
app/components/SideNav.module.css
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
.sideNav {
|
||||
--side-nav-width: 200px;
|
||||
background-color: var(--color-bg-high);
|
||||
position: sticky;
|
||||
left: 0;
|
||||
top: var(--sticky-top);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--s-2);
|
||||
overflow-y: auto;
|
||||
max-height: calc(100vh - var(--layout-nav-height) - var(--s-5));
|
||||
height: fit-content;
|
||||
min-width: var(--side-nav-width);
|
||||
max-width: var(--side-nav-width);
|
||||
padding: var(--s-4) var(--s-2-5);
|
||||
border: 1.5px solid var(--color-border);
|
||||
border-radius: var(--rounded);
|
||||
margin: var(--s-2-5);
|
||||
|
||||
&::-webkit-scrollbar,
|
||||
&::-webkit-scrollbar-track {
|
||||
background-color: transparent;
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: var(--color-text-accent-transparent);
|
||||
border: 6px solid transparent;
|
||||
border-radius: 99999px;
|
||||
background-clip: content-box;
|
||||
}
|
||||
}
|
||||
|
||||
.sideNavLink {
|
||||
font-size: var(--fonts-xs);
|
||||
color: var(--color-text-high);
|
||||
text-decoration: none;
|
||||
padding: var(--s-1) var(--s-2);
|
||||
border-radius: var(--rounded-xs);
|
||||
transition:
|
||||
background-color 0.15s,
|
||||
color 0.15s;
|
||||
|
||||
&:hover {
|
||||
color: var(--color-text);
|
||||
background-color: var(--color-bg-higher);
|
||||
}
|
||||
|
||||
&[aria-current="page"] {
|
||||
color: var(--color-text);
|
||||
background-color: var(--color-bg-higher);
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
.sideNav {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
40
app/components/SideNav.tsx
Normal file
40
app/components/SideNav.tsx
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import clsx from "clsx";
|
||||
import type * as React from "react";
|
||||
import styles from "./SideNav.module.css";
|
||||
|
||||
export function SideNav({
|
||||
children,
|
||||
className,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<nav className={clsx(styles.sideNav, "scrollbar", className)}>
|
||||
{children}
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
|
||||
export function SideNavLink({
|
||||
children,
|
||||
href,
|
||||
onClick,
|
||||
isActive,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
href: string;
|
||||
onClick?: (event: React.MouseEvent<HTMLAnchorElement>) => void;
|
||||
isActive?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<a
|
||||
href={href}
|
||||
className={styles.sideNavLink}
|
||||
onClick={onClick}
|
||||
aria-current={isActive ? "page" : undefined}
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
|
@ -24,41 +24,3 @@
|
|||
.componentContent {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sideNav {
|
||||
position: fixed;
|
||||
left: var(--s-4);
|
||||
top: 60px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--s-1);
|
||||
max-height: 90dvh;
|
||||
overflow-y: auto;
|
||||
z-index: 100;
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.sideNavLink {
|
||||
font-size: var(--fonts-xs);
|
||||
color: var(--color-text-high);
|
||||
text-decoration: none;
|
||||
padding: var(--s-1) var(--s-2);
|
||||
border-radius: var(--rounded-xs);
|
||||
transition:
|
||||
background-color 0.15s,
|
||||
color 0.15s;
|
||||
|
||||
&:hover {
|
||||
color: var(--color-text);
|
||||
background-color: var(--color-bg-high);
|
||||
}
|
||||
|
||||
&[aria-current="page"] {
|
||||
color: var(--color-text);
|
||||
background-color: var(--color-bg-high);
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { parseDate } from "@internationalized/date";
|
||||
import clsx from "clsx";
|
||||
import { useEffect, useState } from "react";
|
||||
import { FormProvider, useForm } from "react-hook-form";
|
||||
import { Ability } from "~/components/Ability";
|
||||
|
|
@ -49,6 +48,7 @@ import { Pagination } from "~/components/Pagination";
|
|||
import { Placement } from "~/components/Placement";
|
||||
import { RelativeTime } from "~/components/RelativeTime";
|
||||
import { Section } from "~/components/Section";
|
||||
import { SideNav, SideNavLink } from "~/components/SideNav";
|
||||
import { StageSelect } from "~/components/StageSelect";
|
||||
import { SubmitButton } from "~/components/SubmitButton";
|
||||
import { SubNav, SubNavLink } from "~/components/SubNav";
|
||||
|
|
@ -107,19 +107,16 @@ export const SECTIONS = [
|
|||
|
||||
export default function ComponentsShowcasePage() {
|
||||
return (
|
||||
<>
|
||||
<SideNav />
|
||||
<Main className="stack lg">
|
||||
<h1>Components</h1>
|
||||
{SECTIONS.map(({ id, component: Component }) => (
|
||||
<Component key={id} id={id} />
|
||||
))}
|
||||
</Main>
|
||||
</>
|
||||
<Main className="stack lg" sideNav={<ComponentsSideNav />}>
|
||||
<h1>Components</h1>
|
||||
{SECTIONS.map(({ id, component: Component }) => (
|
||||
<Component key={id} id={id} />
|
||||
))}
|
||||
</Main>
|
||||
);
|
||||
}
|
||||
|
||||
function SideNav() {
|
||||
function ComponentsSideNav() {
|
||||
const [activeSection, setActiveSection] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -167,19 +164,18 @@ function SideNav() {
|
|||
};
|
||||
|
||||
return (
|
||||
<nav className={clsx(styles.sideNav, "scrollbar")}>
|
||||
<SideNav>
|
||||
{SECTIONS.map(({ title, id }) => (
|
||||
<a
|
||||
<SideNavLink
|
||||
key={id}
|
||||
href={`#${id}`}
|
||||
className={styles.sideNavLink}
|
||||
onClick={(e) => handleClick(e, id)}
|
||||
aria-current={activeSection === id ? "page" : undefined}
|
||||
isActive={activeSection === id}
|
||||
>
|
||||
{title}
|
||||
</a>
|
||||
</SideNavLink>
|
||||
))}
|
||||
</nav>
|
||||
</SideNav>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import {
|
|||
TierImage,
|
||||
WeaponImage,
|
||||
} from "~/components/Image";
|
||||
import { mainStyles } from "~/components/Main";
|
||||
import { Pagination } from "~/components/Pagination";
|
||||
import { SubNav, SubNavLink } from "~/components/SubNav";
|
||||
import { TopTenPlayer } from "~/features/leaderboards/components/TopTenPlayer";
|
||||
|
|
@ -62,7 +63,6 @@ import {
|
|||
} from "../loaders/u.$identifier.seasons.server";
|
||||
import type { UserPageLoaderData } from "../loaders/u.$identifier.server";
|
||||
import styles from "../user-page.module.css";
|
||||
import { mainStyles } from "~/components/Main";
|
||||
export { loader };
|
||||
|
||||
export const handle: SendouRouteHandle = {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user