From a44be81ad37b6492499a9214e866eee0f7209e63 Mon Sep 17 00:00:00 2001
From: Kalle <38327916+Sendouc@users.noreply.github.com>
Date: Mon, 5 Jan 2026 19:01:50 +0200
Subject: [PATCH] Initial
---
.gitignore | 1 +
app/components/Main.module.css | 11 ++++
app/components/Main.tsx | 57 ++++++++++-------
app/components/SideNav.module.css | 61 +++++++++++++++++++
app/components/SideNav.tsx | 40 ++++++++++++
.../components-showcase.module.css | 38 ------------
.../components-showcase/routes/components.tsx | 30 ++++-----
.../routes/u.$identifier.seasons.tsx | 2 +-
8 files changed, 161 insertions(+), 79 deletions(-)
create mode 100644 app/components/SideNav.module.css
create mode 100644 app/components/SideNav.tsx
diff --git a/.gitignore b/.gitignore
index 03de3c332..26946b785 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,3 +27,4 @@ dump
/playwright/.cache/
notepad.txt
+.vitest-attachments/
diff --git a/app/components/Main.module.css b/app/components/Main.module.css
index e80d6f8b2..ffc4cef6c 100644
--- a/app/components/Main.module.css
+++ b/app/components/Main.module.css
@@ -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);
}
diff --git a/app/components/Main.tsx b/app/components/Main.tsx
index 266213e8d..cded40986 100644
--- a/app/components/Main.tsx
+++ b/app/components/Main.tsx
@@ -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 (
-
-
- {children}
-
-
+ },
+ className,
+ )
+ }
+ style={style}
+ >
+ {children}
+
);
+
+ if (sideNav) {
+ return (
+
+ {sideNav}
+
{mainElement}
+
+ );
+ }
+
+ return {mainElement}
;
};
export { styles as mainStyles };
diff --git a/app/components/SideNav.module.css b/app/components/SideNav.module.css
new file mode 100644
index 000000000..5c560d74b
--- /dev/null
+++ b/app/components/SideNav.module.css
@@ -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;
+ }
+}
diff --git a/app/components/SideNav.tsx b/app/components/SideNav.tsx
new file mode 100644
index 000000000..79c2dd20c
--- /dev/null
+++ b/app/components/SideNav.tsx
@@ -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 (
+
+ );
+}
+
+export function SideNavLink({
+ children,
+ href,
+ onClick,
+ isActive,
+}: {
+ children: React.ReactNode;
+ href: string;
+ onClick?: (event: React.MouseEvent) => void;
+ isActive?: boolean;
+}) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/app/features/components-showcase/components-showcase.module.css b/app/features/components-showcase/components-showcase.module.css
index 9dd93cdf7..8e51033ac 100644
--- a/app/features/components-showcase/components-showcase.module.css
+++ b/app/features/components-showcase/components-showcase.module.css
@@ -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;
- }
-}
diff --git a/app/features/components-showcase/routes/components.tsx b/app/features/components-showcase/routes/components.tsx
index a4063d6fe..a7bf16215 100644
--- a/app/features/components-showcase/routes/components.tsx
+++ b/app/features/components-showcase/routes/components.tsx
@@ -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 (
- <>
-
-
- Components
- {SECTIONS.map(({ id, component: Component }) => (
-
- ))}
-
- >
+ }>
+ Components
+ {SECTIONS.map(({ id, component: Component }) => (
+
+ ))}
+
);
}
-function SideNav() {
+function ComponentsSideNav() {
const [activeSection, setActiveSection] = useState(null);
useEffect(() => {
@@ -167,19 +164,18 @@ function SideNav() {
};
return (
-
+
);
}
diff --git a/app/features/user-page/routes/u.$identifier.seasons.tsx b/app/features/user-page/routes/u.$identifier.seasons.tsx
index 1308ce0b5..a3ca4bb40 100644
--- a/app/features/user-page/routes/u.$identifier.seasons.tsx
+++ b/app/features/user-page/routes/u.$identifier.seasons.tsx
@@ -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 = {