Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DocumentationPage component (for Resources / Quickstart page) and make header/sidebar fixed on scroll #662

Merged
merged 2 commits into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
902 changes: 895 additions & 7 deletions frontend2/package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions frontend2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"react-dom": "^18.2.0",
"react-hook-form": "^7.45.1",
"react-router-dom": "^6.13.0",
"react-markdown": "^8.0.7",
Copy link
Member

@acrantel acrantel Aug 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in the future, we may consider switching to marked or remarkable, because they are about 1/3 the size of react-markdown.
we'll just need to figure out how to replace <a>s that link to urls within play.batlecode.org with <Link> when using those libraries

"web-vitals": "^2.1.4"
},
"scripts": {
Expand Down
6 changes: 4 additions & 2 deletions frontend2/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import NotFound from "./views/NotFound";
import Rankings from "./views/Rankings";
import { CurrentUserProvider } from "./components/CurrentUserProvider";
import PrivateRoute from "./components/PrivateRoute";
import Resources from "./views/Resources";

const App: React.FC = () => {
const [episodeId, setEpisodeId] = useState(DEFAULT_EPISODE);
Expand Down Expand Up @@ -57,15 +58,16 @@ const router = createBrowserRouter([
element: <EpisodeLayout />,
children: [
// Pages that should always be visible
// TODO: /:episodeId/resources, /:episodeId/tournaments, /:episodeId/queue
// TODO: /:episodeId/tournaments, /:episodeId/queue
{ path: "/:episodeId/resources", element: <Resources /> },
{ path: "/:episodeId/quickstart", element: <QuickStart /> },
{ path: "/:episodeId/home", element: <Home /> },
{
path: "/:episodeId/",
loader: ({ params }) => {
return redirect(`/${params.episodeId as string}/home`);
},
},
{ path: "/:episodeId/quickstart", element: <QuickStart /> },
{ path: "/:episodeId/*", element: <NotFound /> },
{ path: "/:episodeId/rankings", element: <Rankings /> },
],
Expand Down
47 changes: 47 additions & 0 deletions frontend2/src/components/DocumentationPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from "react";
import ReactMarkdown from "react-markdown";
import { Link } from "react-router-dom";

const isInternalLink = (to: string): boolean => {
const url = new URL(to, window.location.origin);
return url.hostname === window.location.hostname;
};

interface DocumentationPageProps {
text: string;
}

const DocumentationPage: React.FC<DocumentationPageProps> = ({ text }) => {
return (
<div className="h-full w-full overflow-auto bg-white p-6">
<ReactMarkdown
components={{
a: ({ href, ...props }) => {
const target = href ?? "";
if (isInternalLink(target)) {
return (
<Link
className="text-cyan-600 hover:underline"
to={target}
{...props}
/>
);
} else {
return (
<a
className="text-cyan-600 hover:underline"
href={target}
{...props}
/>
);
}
},
}}
>
{text}
</ReactMarkdown>
</div>
);
};

export default DocumentationPage;
6 changes: 3 additions & 3 deletions frontend2/src/components/EpisodeLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ const EpisodeLayout: React.FC = () => {
episodeContext.setEpisodeId(episodeId);
}
return (
<div className="h-screen">
<div className="h-screen overflow-auto">
<Header />
<div className="flex h-full flex-row">
<Sidebar />
<Sidebar />
<div className="fixed right-0 h-full pt-16 sm:left-52">
<Outlet />
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion frontend2/src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const Header: React.FC = () => {
const { episodeId } = useContext(EpisodeContext);

return (
<nav className="bg-gray-700">
<nav className="fixed top-0 h-16 w-full bg-gray-700">
<div className="w-full px-2 sm:px-6 lg:px-8">
<div className="relative flex h-16 items-center justify-between">
{/* mobile menu */}
Expand Down
4 changes: 2 additions & 2 deletions frontend2/src/components/sidebar/SidebarSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ const SidebarSection: React.FC<SidebarSectionProps> = ({ children, title }) => {
return (
<div className="px-4">
{title !== undefined && (
<h2 className="mx-auto mb-2 font-light uppercase text-gray-500">
<div className="mx-auto mb-2 font-light uppercase text-gray-500">
{title}
</h2>
</div>
)}
<div className="flex flex-col gap-1">{children}</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion frontend2/src/components/sidebar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ const Sidebar: React.FC<SidebarProps> = ({ collapsed }) => {
const { episodeId } = useContext(EpisodeContext);

return collapsed ? null : (
<nav className="hidden h-full flex-col gap-8 bg-gray-50 py-4 shadow-sm shadow-gray-200 sm:flex">
<nav className="fixed top-16 z-10 hidden h-full w-52 flex-col gap-8 bg-gray-50 py-4 drop-shadow-[2px_0_2px_rgba(0,0,0,0.25)] sm:flex">
<SidebarSection title="">
{generateSidebarItems(0, 2, episodeId)}
</SidebarSection>
Expand Down
68 changes: 68 additions & 0 deletions frontend2/src/content/bc23.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
export const BC23_QUICKSTART = `# Quick Start

This is the Battlecode 2023 contest website, which will be your main hub for all Battlecode-related things for the duration of the contest. For a general overview of what Battlecode is, visit [our landing page](https://battlecode.org/).

## Create an account and team

To participate in Battlecode, you need an account and a team. Each team can consist of 1 to 4 people.

[Create an account](/register) on this website, and then go to the [team section](/bc23/team) to either create or join a team.

## Installation

### Step 1: Install Java

You'll need a Java Development Kit (JDK) version 8. Unfortunately, higher versions will not work. [Download it here](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html). You may need to create an Oracle account.

- Alternatively, you can install a JDK yourself using your favorite package manager. Make sure it's an Oracle JDK — we don't support anything else — and is compatible with Java 8.

If you're unsure how to install the JDK, you can find instructions for all operating systems [here](https://docs.oracle.com/javase/8/docs/technotes/guides/install/install_overview.html) (pay attention to \`PATH\` and \`CLASSPATH\`).

### Step 2: Download Battlecode

Next, you should download the [Battlecode 2023 scaffold](https://github.com/battlecode/battlecode23-scaffold). To get up and running quickly, you can click "Clone or download" and then "Download ZIP," and move on to the next step.

TODO: the rest of the page

`;

export const BC23_RESOURCES = `# Markdown syntax guide

# This is a Heading h1
## This is a Heading h2
###### This is a Heading h6

*This text will be italic*
_This will also be italic_

**This text will be bold**
__This will also be bold__

_You **can** combine them_

### Unordered List

* Item 1
* Item 2
* Item 2a
* Item 2b

### Ordered List

1. Item 1
1. Item 2
1. Item 3
1. Item 3a
1. Item 3b

![This is an alt text for an image.](/image/sample.png "This is a sample image.")

[This links to example.com](https://example.com).

\`\`\`
let message = 'Hello world';
alert(message);
\`\`\`

this is \`an inline code block\`
`;
35 changes: 34 additions & 1 deletion frontend2/src/index.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,37 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Josefin+Sans:wght@100;300;400;500;700&display=swap');
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Josefin+Sans:wght@100;300;400;500;700&display=swap");

@layer base {
h1 {
@apply pb-4 text-3xl font-medium text-gray-900;
}
h2 {
@apply pb-4 pt-6 text-2xl font-medium text-gray-900;
}
h3 {
@apply pb-4 text-xl font-medium text-gray-900;
}
h4 {
@apply pb-4 text-lg font-medium text-gray-700;
}
p {
@apply pb-4 text-gray-900;
}
code {
@apply rounded bg-gray-100 px-1 py-0.5 text-sm text-cyan-900;
}
pre code {
@apply p-0;
}
pre {
@apply rounded bg-gray-100 px-4 py-3;
}
ul {
@apply ml-6 list-outside list-disc pb-4;
}
ol {
@apply ml-6 list-outside list-decimal pb-4;
}
}
8 changes: 4 additions & 4 deletions frontend2/src/views/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,13 @@ const Login: React.FC = () => {
onSubmit={handleSubmit(onSubmit)}
className="flex w-11/12 flex-col gap-5 rounded-lg bg-gray-100 p-6 shadow-md sm:w-[350px]"
>
<h3 className="text-center text-xl font-light text-gray-700">
<div className="text-center text-xl font-light text-gray-700">
Log in to Battlecode
</h3>
</div>
{
// TODO: replace this with our custom notification component
loginError !== undefined && (
<p className="text-center text-sm text-red-600">{loginError}</p>
<div className="text-center text-sm text-red-600">{loginError}</div>
)
}
<Input
Expand Down Expand Up @@ -91,7 +91,7 @@ const Login: React.FC = () => {
</div>
</form>
<div className="w-11/12 flex-1">
<div className="text-light mt-4 w-full rounded-lg bg-white p-6 text-center text-sm shadow-md sm:w-[350px]">
<div className="text-light mx-auto mt-4 w-full rounded-lg bg-white p-6 text-center text-sm shadow-md sm:w-[350px]">
Need an account?{" "}
<Link className="text-cyan-600" to="/register">
Register for one!
Expand Down
4 changes: 3 additions & 1 deletion frontend2/src/views/QuickStart.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import React from "react";
import DocumentationPage from "../components/DocumentationPage";
import { BC23_QUICKSTART } from "../content/bc23";

const QuickStart: React.FC = () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this view going to always bring up bc23's Quickstart? Or are we planning to use EpisodeContext on this page (e.g. bc22,bc23) that indexes and retrieves <episodeId>_QUICKSTART for the Quickstart component?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup, this will be a later change where we'll get the episode id and display that episode's quickstart

return <p>quickstart page</p>;
return <DocumentationPage text={BC23_QUICKSTART} />;
};

export default QuickStart;
2 changes: 1 addition & 1 deletion frontend2/src/views/Rankings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const Rankings: React.FC = () => {
}, [searchQuery, page]);

return (
<div className="mb-20 ml-10 flex w-full flex-col">
<div className="flex h-full w-full flex-col overflow-auto p-6">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we have to use padding instead of margins here, otherwise it will overflow the page width because of the combined w-full and ml-10

<h1 className="mb-5 text-3xl font-bold leading-7 text-gray-900">
Rankings
</h1>
Expand Down
6 changes: 3 additions & 3 deletions frontend2/src/views/Register.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ const Register: React.FC = () => {
};
return (
<div className="flex h-screen flex-col items-center justify-center bg-gradient-to-tr from-cyan-200 to-cyan-700 p-2">
<h2 className="flex flex-1 items-end text-center font-display text-5xl tracking-wide text-white sm:text-6xl">
<div className="flex flex-1 items-end text-center font-display text-5xl tracking-wide text-white sm:text-6xl">
BATTLECODE
</h2>
</div>
{/* https://github.com/orgs/react-hook-form/discussions/8622 */}
<form
/* eslint-disable-next-line @typescript-eslint/no-misused-promises */
Expand All @@ -75,7 +75,7 @@ const Register: React.FC = () => {
{
// TODO: replace this with our custom notification component
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this on our roadmap?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup!

formError !== undefined && (
<p className="text-center text-sm text-red-600">{formError}</p>
<div className="text-center text-sm text-red-600">{formError}</div>
)
}
<Input
Expand Down
9 changes: 9 additions & 0 deletions frontend2/src/views/Resources.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react";
import { BC23_RESOURCES } from "../content/bc23";
import DocumentationPage from "../components/DocumentationPage";

const Resources = (): JSX.Element => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto the comment above about this page eventually rendering the appropriate year's resources based on the URL's episodeId? If that was already the plan then disregard.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, we'll render the proper year later. that change will likely come in the same pr as the change that adds the actual 2023 / 2024 episode specific text

return <DocumentationPage text={BC23_RESOURCES} />;
};

export default Resources;