Merge branch 'main' into feat/organized-content

pull/79/head
William Tran 2 years ago
commit 2b8362f89c
  1. 27
      .drone.yml
  2. 28
      .eslintrc.js
  3. 13
      .vscode/settings.json
  4. 10
      check-lockfile.js
  5. 70
      components/Bubble.module.css
  6. 19
      components/Bubble.tsx
  7. 6
      components/Button.module.css
  8. 1
      components/Button.tsx
  9. 6
      components/Code.module.css
  10. 9
      components/Code.tsx
  11. 3
      components/ConnectWithUs.module.css
  12. 6
      components/ConnectWithUs.tsx
  13. 1
      components/DefaultLayout.module.css
  14. 1
      components/DefaultLayout.tsx
  15. 10
      components/EmailSignup.module.css
  16. 25
      components/EmailSignup.tsx
  17. 2
      components/EventCard.module.css
  18. 5
      components/EventCard.tsx
  19. 7
      components/EventDescriptionCard.module.css
  20. 6
      components/EventDescriptionCard.tsx
  21. 1
      components/EventSetting.tsx
  22. 9
      components/Footer.module.css
  23. 10
      components/Footer.tsx
  24. 7
      components/HorizontalLine.module.css
  25. 7
      components/HorizontalLine.tsx
  26. 8
      components/Input.module.css
  27. 1
      components/Input.tsx
  28. 4
      components/Link.module.css
  29. 4
      components/Link.tsx
  30. 29
      components/MiniEventCard.module.css
  31. 6
      components/MiniEventCard.tsx
  32. 40
      components/MiniTechTalkCard.module.css
  33. 23
      components/MiniTechTalkCard.tsx
  34. 23
      components/Navbar.module.css
  35. 16
      components/Navbar.tsx
  36. 15
      components/NewsCard.module.css
  37. 7
      components/NewsCard.tsx
  38. 52
      components/OrganizedContent.module.css
  39. 122
      components/OrganizedContent.tsx
  40. 50
      components/OrganizedContent/Header.module.css
  41. 38
      components/OrganizedContent/Header.tsx
  42. 75
      components/OrganizedContent/ReadAll.tsx
  43. 48
      components/OrganizedContent/Section.tsx
  44. 69
      components/OrganizedContent/static.ts
  45. 6
      components/Pre.module.css
  46. 9
      components/Pre.tsx
  47. 4
      components/SocialLinks.module.css
  48. 1
      components/SocialLinks.tsx
  49. 17
      components/TeamMember.module.css
  50. 12
      components/TeamMember.tsx
  51. 124
      components/TeamMemberCard.module.css
  52. 95
      components/TeamMemberCard.tsx
  53. 34
      components/TechTalkCard.module.css
  54. 26
      components/TechTalkCard.tsx
  55. 180
      components/Theme.tsx
  56. 24
      components/playground.module.css
  57. 147
      components/playground.tsx
  58. 36
      components/theme.tsx
  59. 8
      content/about/code-of-conduct/additional-information.md
  60. 9
      content/about/code-of-conduct/addressing-grievances.md
  61. 13
      content/about/code-of-conduct/confidentiality.md
  62. 13
      content/about/code-of-conduct/consequences-of-inappropriate-behaviour.md
  63. 6
      content/about/code-of-conduct/contact-information.md
  64. 10
      content/about/code-of-conduct/expected-behaviour.md
  65. 19
      content/about/code-of-conduct/experiencing-unacceptable-behaviour.md
  66. 6
      content/about/code-of-conduct/license-information-and-attribution.md
  67. 13
      content/about/code-of-conduct/purpose.md
  68. 6
      content/about/code-of-conduct/revision.md
  69. 12
      content/about/code-of-conduct/scope-and-spaces.md
  70. 16
      content/about/code-of-conduct/unacceptable-behaviour.md
  71. 10
      content/about/constitution/amendments-and-procedures.md
  72. 8
      content/about/constitution/code-of-conduct.md
  73. 27
      content/about/constitution/committees.md
  74. 6
      content/about/constitution/dissolution.md
  75. 27
      content/about/constitution/duties-of-officers.md
  76. 10
      content/about/constitution/executive-council.md
  77. 9
      content/about/constitution/finances.md
  78. 13
      content/about/constitution/meetings.md
  79. 10
      content/about/constitution/membership.md
  80. 6
      content/about/constitution/name.md
  81. 30
      content/about/constitution/officers.md
  82. 10
      content/about/constitution/purpose.md
  83. 6
      content/about/constitution/revision.md
  84. 10
      content/about/constitution/use-of-club-resources.md
  85. 16
      content/about/index.mdx
  86. 2
      content/about/our-supporters.mdx
  87. 16
      content/advice/academic-advice.mdx
  88. 98
      content/advice/coop-advice.mdx
  89. 42
      content/advice/misc-advice.mdx
  90. 14
      content/events/1994/fall/ACM-Style-Programming-Contest.md
  91. 9
      content/events/1994/fall/CSC-Elections.md
  92. 14
      content/events/1994/fall/Exploring-the-Internet.md
  93. 14
      content/events/1994/fall/Game-Theory.md
  94. 21
      content/events/1994/fall/Movie-Outing-Brainstorm.md
  95. 16
      content/events/1994/fall/Prograph-Picture-the-Future.md
  96. 9
      content/events/1994/fall/SIGGRAPH-Video-Night.md
  97. 9
      content/events/1994/fall/UNIX-I-Tutorial.md
  98. 9
      content/events/1994/fall/UNIX-II-Tutorial.md
  99. 18
      content/events/1999/fall/Calculational-Mathematics.md
  100. 9
      content/events/1999/fall/Ctrl-D.md
  101. Some files were not shown because too many files have changed in this diff Show More

@ -1,35 +1,52 @@
---
kind: pipeline
type: docker
name: node14
name: node16
steps:
- name: check-lockfile
image: node:16
commands:
- node ./check-lockfile.js
- name: install-deps
image: node:14
image: node:16
depends_on:
- check-lockfile
commands:
- npm install
- name: lint
image: node:14
image: node:16
depends_on:
- install-deps
commands:
- npm run lint
- name: build
image: node:14
image: node:16
depends_on:
- install-deps
commands:
- npm run build
- name: export
image: node:14
image: node:16
depends_on:
- build
commands:
- npm run export
- name: deploy (staging)
image: node:16
depends_on:
- export
environment:
TOKEN:
from_secret: STAGING_TOKEN
commands:
- 'curl -XPOST -H "Authorization: $TOKEN" -H "X-Branch: $DRONE_BRANCH" "https://csclub.uwaterloo.ca/~a3thakra/update-csc/"'
trigger:
event:
exclude:

@ -9,6 +9,9 @@ module.exports = {
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
"plugin:import/errors",
"plugin:import/warnings",
"plugin:import/typescript",
"plugin:react/recommended",
"plugin:prettier/recommended",
],
@ -16,12 +19,37 @@ module.exports = {
rules: {
"prettier/prettier": "error",
"import/first": "error",
"import/order": [
"error",
{
"newlines-between": "always",
"alphabetize": {
"order": "asc",
"caseInsensitive": true,
},
"pathGroups": [
{
"pattern": "@/**",
"group": "external",
"position": "after",
},
{
"pattern": "./*.css",
"group": "index",
"position": "after",
}
],
},
],
"react/prop-types": "off",
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "error",
// Turn off these rules
"@typescript-eslint/explicit-module-boundary-types": "off",
"import/no-unresolved": "off",
},
settings: {
react: {

@ -4,9 +4,7 @@
"eslint.codeActionsOnSave.mode": "all",
"[css]": {
"editor.suggest.insertMode": "replace",
"gitlens.codeLens.scopes": [
"document"
],
"gitlens.codeLens.scopes": ["document"],
"editor.formatOnSave": true
},
"[javascript]": {
@ -38,5 +36,10 @@
"files.exclude": {
"node_modules": true
},
"editor.tabSize": 2
}
"editor.tabSize": 2,
"files.eol": "\n",
"[markdown]": {
"editor.wordWrap": "on",
"editor.quickSuggestions": false
}
}

@ -0,0 +1,10 @@
const lockfile = require('./package-lock.json')
if (lockfile.lockfileVersion !== 2) {
console.error(`
Please upgrade to npm v7 and revert changes to the lockfile.
- \`npm i -g npm\` to upgrade.
`.trim())
process.exit(1)
}

@ -1,7 +1,71 @@
.bubble {
.container {
position: relative;
padding: calc(36rem / 16) 0;
overflow-x: clip;
}
.bubble {
--border-radius: calc(5000rem / 16);
display: flex;
flex-direction: row;
position: absolute;
top: 0;
height: 100%;
width: 100%;
justify-content: center;
align-items: flex-start;
}
.bubble:nth-child(odd) {
background-color: var(--blue-1-20);
.bar {
height: 100%;
width: 100%;
}
.decoration {
display: none;
width: calc(128rem / 16);
}
.margin {
display: none;
}
.content {
position: relative;
z-index: 1;
}
.container:nth-child(odd) .bar {
background-color: var(--primary-accent-light);
}
@media only screen and (min-width: calc(1350rem / 16)) {
.container:nth-child(odd) .decoration {
display: block;
position: absolute;
}
.container:nth-child(4n + 1) .bar {
border-top-right-radius: var(--border-radius);
border-bottom-right-radius: var(--border-radius);
transform: translateX(-12.5vw);
}
.container:nth-child(4n + 1) .decoration {
top: calc(-50rem / 16);
right: 8vw;
}
.container:nth-child(4n + 3) .bar {
border-top-left-radius: var(--border-radius);
border-bottom-left-radius: var(--border-radius);
transform: translateX(12.5vw);
}
.container:nth-child(4n + 3) .decoration {
top: calc(-50rem / 16);
left: 8vw;
transform: rotateY(180deg);
}
}

@ -1,11 +1,24 @@
import React from "react";
import { Image } from "@/components/Image";
import { DefaultLayout } from "./DefaultLayout";
import styles from "./Bubble.module.css";
export default function Bubble(props: { children: React.ReactNode }) {
export function Bubble(props: { children: React.ReactNode }) {
return (
<div className={styles.bubble}>
<DefaultLayout>{props.children}</DefaultLayout>
<div className={styles.container}>
<div className={styles.bubble} aria-hidden>
<div className={styles.bar} />
<Image
className={styles.decoration}
src="/images/bubble-decoration.svg"
/>
</div>
<div className={styles.content}>
<DefaultLayout>{props.children}</DefaultLayout>
</div>
</div>
);
}

@ -2,8 +2,8 @@
.link {
font-family: "Poppins", "sans-serif";
border-radius: calc(20rem / 16);
background-color: var(--blue-2);
color: white;
background-color: var(--primary-accent);
color: var(--primary-background);
border: none;
outline: none;
transition-duration: 0.3s;
@ -13,7 +13,7 @@
.button:hover,
.link:hover {
background-color: var(--teal-2);
background-color: var(--secondary-accent);
cursor: pointer;
}

@ -1,4 +1,5 @@
import React, { AnchorHTMLAttributes, ButtonHTMLAttributes } from "react";
import styles from "./Button.module.css";
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {

@ -0,0 +1,6 @@
.code {
padding: 0 calc(4rem / 16);
background: var(--code-background);
border-radius: calc(5rem / 16);
word-wrap: break-word;
}

@ -0,0 +1,9 @@
import React, { HTMLAttributes } from "react";
import styles from "./Code.module.css";
export function Code(props: HTMLAttributes<HTMLElement>) {
const classes = [styles.code, props.className ?? ""];
return <code {...props} className={classes.join(" ")} />;
}

@ -1,8 +1,7 @@
.header {
color: var(--blue-2);
color: var(--primary-accent);
font-weight: 600;
font-size: calc(36rem / 16);
margin-bottom: calc(12rem / 16);
}
.socialLinks {

@ -1,7 +1,9 @@
import React from "react";
import styles from "./ConnectWithUs.module.css";
import { SocialLinks } from "./SocialLinks";
import { Link } from "./Link";
import { SocialLinks } from "./SocialLinks";
import styles from "./ConnectWithUs.module.css";
export function ConnectWithUs() {
return (

@ -2,5 +2,4 @@
margin: 0 auto;
max-width: calc(800rem / 16);
padding: 0 calc(20rem / 16);
padding-bottom: calc(20rem / 16);
}

@ -1,4 +1,5 @@
import React from "react";
import styles from "./DefaultLayout.module.css";
export function DefaultLayout(props: { children: React.ReactNode }) {

@ -1,17 +1,13 @@
.container form {
box-sizing: border-box;
}
.header {
color: var(--blue-2);
color: var(--primary-accent);
font-weight: 600;
font-size: calc(36rem / 16);
margin-bottom: calc(12rem / 16);
}
.button {
margin-top: calc(34rem / 16);
margin-top: calc(26rem / 16);
display: block;
width: fit-content;
}
@media only screen and (max-width: calc(768rem / 16)) {

@ -1,19 +1,24 @@
import React from "react";
import styles from "./EmailSignup.module.css";
import { Button } from "./Button";
import { Input } from "./Input";
import styles from "./EmailSignup.module.css";
export function EmailSignup() {
return (
<section className={styles.container}>
<h1 className={styles.header}>Join Our Mailing List!</h1>
<form className={styles.form} action="">
<Input type="text" placeholder="Full Name*" required />
<Input type="email" placeholder="Email*" required />
<Button type="submit" className={styles.button}>
Subscribe
</Button>
</form>
<h1 className={styles.header}>Join our mailing list!</h1>
<p>
Join our mailing list to receive email notifications about important
news and upcoming events!
</p>
<Button
isLink={true}
href="https://mailman.csclub.uwaterloo.ca/postorius/lists/csc-general.csclub.uwaterloo.ca/"
className={styles.button}
>
Subscribe
</Button>
</section>
);
}

@ -41,7 +41,7 @@
}
.content > h2 {
color: var(--purple-2);
color: var(--primary-heading);
font-size: 1rem;
margin-bottom: calc(14rem / 16);
}

@ -1,10 +1,11 @@
import React, { ReactNode } from "react";
import { Button } from "./Button";
import styles from "./EventCard.module.css";
import { Button } from "./Button";
import { EventSetting } from "./EventSetting";
import { Image } from "./Image";
import styles from "./EventCard.module.css";
interface EventCardProps {
name: string;
short: string;

@ -4,7 +4,7 @@
max-width: calc(540rem / 16);
padding: calc(24rem / 16);
border-radius: calc(20rem / 16);
background-color: white;
background-color: var(--primary-background);
}
.poster {
@ -35,7 +35,7 @@
.setting {
margin: 0;
color: var(--blue-2);
color: var(--primary-accent);
font-size: calc(14rem / 16);
font-weight: 600;
}
@ -50,6 +50,7 @@
@media only screen and (max-width: calc(768rem / 16)) {
.card {
max-width: unset;
padding: 0;
background-color: transparent;
}
@ -66,7 +67,7 @@
.poster {
width: calc(95rem / 16);
height: calc(95rem / 16);
border: 1px solid var(--purple-2);
border: 1px solid var(--primary-heading);
box-sizing: border-box;
margin-right: calc(14rem / 16);
}

@ -1,10 +1,12 @@
import React from "react";
import { Button } from "./Button";
import { Image } from "./Image";
import { EventSetting } from "./EventSetting";
import styles from "./EventDescriptionCard.module.css";
import { Image } from "./Image";
import { Discord, Twitch, Instagram, Facebook } from "./SocialLinks";
import styles from "./EventDescriptionCard.module.css";
interface Props {
name: string;
short: string;

@ -1,4 +1,5 @@
import React from "react";
import styles from "./EventSetting.module.css";
interface Props {

@ -1,6 +1,6 @@
.footer {
box-sizing: border-box;
background: var(--purple-2);
background: var(--primary-heading);
height: calc(66rem / 16);
padding: calc(14rem / 16) 0;
width: 100%;
@ -18,11 +18,16 @@
}
.text {
color: var(--white);
color: var(--primary-background);
font-style: normal;
text-align: center;
}
.email {
color: unset;
text-decoration: unset;
}
@media only screen and (max-width: calc(768rem / 16)) {
.footer {
height: calc(120rem / 16);

@ -1,13 +1,19 @@
import Link from "next/link";
import React from "react";
import styles from "./Footer.module.css";
import { SocialLinks } from "./SocialLinks";
import styles from "./Footer.module.css";
export function Footer() {
return (
<footer className={styles.footer}>
<div className={styles.container}>
<div className={styles.text}>
Have questions? Email us at XX@XXX.COM
Have questions? Email us at{" "}
<Link href="mailto:exec@csclub.uwaterloo.ca">
<a className={styles.email}>exec@csclub.uwaterloo.ca</a>
</Link>
</div>
<SocialLinks color="white" size="small" />
</div>

@ -0,0 +1,7 @@
.line {
display: block;
margin: calc(1rem / 16) 0 calc(34rem / 16);
height: calc(1rem / 16);
border: none;
background-color: var(--primary-heading);
}

@ -0,0 +1,7 @@
import React from "react";
import styles from "./HorizontalLine.module.css";
export function HorizontalLine() {
return <hr className={styles.line} />;
}

@ -8,20 +8,20 @@
border: 0;
border-radius: calc(20rem / 16);
background-color: var(--grey-1-24);
background-color: var(--input-background);
font-size: calc(18rem / 16);
line-height: calc(30rem / 16);
color: var(--grey-3);
color: var(--input-text);
}
.input::placeholder {
color: var(--grey-2);
color: var(--input-placeholder-text);
font-weight: 700;
}
.input:is(:active, :hover, :focus) {
box-sizing: border-box;
border: calc(3rem / 16) solid var(--blue-1);
border: calc(3rem / 16) solid var(--primary-accent-soft);
border-radius: calc(20rem / 16);
outline: none;
padding: calc(7rem / 16) calc(28rem / 16);

@ -1,4 +1,5 @@
import React, { InputHTMLAttributes } from "react";
import styles from "./Input.module.css";
export function Input(props: InputHTMLAttributes<HTMLInputElement>) {

@ -1,10 +1,10 @@
.link {
color: var(--blue-2);
color: var(--primary-accent);
transition-duration: 0.3s;
text-decoration: none;
white-space: normal;
}
.link:hover {
color: var(--teal-2);
color: var(--secondary-accent);
}

@ -1,7 +1,7 @@
import NextLink, { LinkProps as NextLinkProps } from "next/link";
import React from "react";
import styles from "./Link.module.css";
import NextLink from "next/link";
import { LinkProps as NextLinkProps } from "next/link";
type Props = Omit<NextLinkProps, "href"> & { href: string };

@ -5,7 +5,7 @@
}
.card:nth-child(odd) {
background-color: var(--teal-2-20);
background-color: var(--secondary-accent-light);
}
.name {
@ -19,7 +19,7 @@
}
.info {
color: var(--purple-2);
color: var(--primary-heading);
margin-bottom: calc(12rem / 16);
}
@ -29,7 +29,7 @@
right: 0;
cursor: pointer;
margin: calc(20rem / 16);
color: var(--blue-2);
color: var(--primary-accent);
font-size: calc(14rem / 16);
}
@ -46,5 +46,26 @@
}
.dropDownIcon {
fill: var(--blue-2);
fill: var(--primary-accent);
}
@media only screen and (max-width: calc(768rem / 16)) {
.details {
bottom: 0;
left: 0;
top: unset;
right: unset;
}
.dropDownIcon {
display: none;
}
.card {
padding-bottom: calc(48rem / 16);
}
.nameSpacer {
display: none;
}
}

@ -1,5 +1,7 @@
import React, { ReactNode } from "react";
import { EventSetting } from "./EventSetting";
import styles from "./MiniEventCard.module.css";
interface Props {
@ -32,10 +34,8 @@ export const MiniEventCard: React.FC<Props> = ({
</div>
<p className={styles.shortDescription}>{short}</p>
</div>
<p className={styles.details}>View details {dropDownIcon}</p>
<div className={styles.details}>View details {dropDownIcon}</div>
</summary>
<div>{description}</div>
</details>
);

@ -0,0 +1,40 @@
.card {
display: flex;
flex-direction: row;
box-sizing: border-box;
padding: calc(16rem / 16);
color: var(--purple-2);
font-size: 1rem;
}
.card aside {
max-width: calc(142rem / 16);
margin-right: calc(45rem / 16);
display: flex;
justify-content: center;
align-items: center;
}
.card aside img {
max-width: calc(142rem / 16);
max-height: 100%;
object-fit: cover;
}
.content {
padding: calc(4rem / 16);
}
.content h1 {
margin: 0;
margin-top: calc(4rem / 16);
font-size: calc(18rem / 16);
}
.card section {
padding-bottom: 0;
}
.spacer {
margin-top: calc(76rem / 16);
}

@ -0,0 +1,23 @@
import React from "react";
import { Image } from "./Image";
import styles from "./MiniTechTalkCard.module.css";
interface MiniTechTalkProps {
name: string;
short: string;
poster?: string;
}
export function MiniTechTalkCard({ name, poster, short }: MiniTechTalkProps) {
return (
<article className={styles.card}>
<aside>{poster && <Image alt={name} src={poster} />}</aside>
<div className={styles.content}>
<h1>{name}</h1>
<p>{short}</p>
</div>
</article>
);
}

@ -2,8 +2,9 @@
display: flex;
justify-content: center;
align-items: center;
z-index: 10;
background-color: var(--white);
background-color: var(--primary-background);
}
.navContent {
@ -62,16 +63,16 @@
}
.navMenu a {
color: var(--purple-2);
color: var(--primary-heading);
text-decoration: none;
}
.navMenu a.currentPage {
color: var(--blue-2);
color: var(--primary-accent);
}
.navMenu > li > a:hover {
color: var(--blue-2);
color: var(--primary-accent);
font-weight: 600;
}
@ -115,8 +116,8 @@
padding: 0;
border-radius: calc(8rem / 16);
background-color: var(--white);
box-shadow: 0 calc(8rem / 16) 1rem var(--blue-1-20);
background-color: var(--primary-background);
box-shadow: 0 calc(8rem / 16) 1rem var(--primary-accent-light);
font-size: calc(14rem / 16);
}
@ -133,7 +134,7 @@
.dropdown li:hover a,
.dropdown li a:focus {
background-color: var(--blue-1-20);
background-color: var(--primary-accent-light);
}
.dropdown li:first-child a {
@ -154,13 +155,13 @@
/* On a smaller desktop screen, keep the same navbar layout but decrease the
* horizontal padding so it still fits
*/
@media screen and (max-width: calc(960rem / 16)) {
@media only screen and (max-width: calc(960rem / 16)) {
.navContent {
padding: calc(28rem / 16) calc(64rem / 16);
}
}
@media screen and (max-width: calc(768rem / 16)) {
@media only screen and (max-width: calc(768rem / 16)) {
.navContent {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
@ -223,7 +224,7 @@
left: 0;
z-index: 20;
background-color: var(--navbar-gray);
background-color: var(--navbar-page-overlay);
opacity: 0;
transition: 0.5s;
@ -243,7 +244,7 @@
padding: calc(calc(64rem / 16) - 1rem);
padding-left: calc(calc(78rem / 16) - 1rem);
background-color: var(--off-white);
background-color: var(--secondary-background);
transform: translateX(100vw);
transition: 0.5s;

@ -1,7 +1,9 @@
import React, { useReducer } from "react";
import Link from "next/link";
import { useRouter } from "next/router";
import React, { useReducer } from "react";
import { Image } from "./Image";
import styles from "./Navbar.module.css";
type Menu = {
@ -60,6 +62,10 @@ const menu: Menu = [
name: "Services",
route: "/resources/services",
},
{
name: "Machine Usage",
route: "/resources/machine-usage-agreement",
},
{
name: "Tech Talks",
route: "/resources/tech-talks",
@ -68,6 +74,14 @@ const menu: Menu = [
name: "CS Club Wiki",
route: "https://wiki.csclub.uwaterloo.ca",
},
{
name: "Advice",
route: "/resources/advice/coop",
},
{
name: "Internships",
route: "https://github.com/uwcsc/winter2022-internships",
},
],
},
];

@ -1,17 +1,23 @@
.card {
padding: calc(30rem / 16) calc(40rem / 16);
max-width: calc(524rem / 16);
background-color: var(--white);
background-color: var(--primary-background);
border-radius: calc(20rem / 16);
}
.fit.card {
max-width: unset;
padding: unset;
border-radius: unset;
}
.date {
font-size: calc(18rem / 16);
margin: 0;
}
.author {
color: var(--purple-1);
color: var(--secondary-heading);
font-style: normal;
}
@ -22,9 +28,14 @@
@media only screen and (max-width: calc(768rem / 16)) {
.card {
padding: 0;
max-width: unset;
background-color: transparent;
}
.date {
font-weight: 600;
}
.content > *:first-child {
margin-top: 1rem;
}

@ -1,19 +1,24 @@
import React, { ReactNode } from "react";
import styles from "./NewsCard.module.css";
interface NewsCardProps {
date: Date;
author: string;
children: ReactNode;
fit?: boolean;
}
export const NewsCard: React.FC<NewsCardProps> = ({
date,
author,
children,
fit = false,
}) => {
const classes = fit ? [styles.card, styles.fit] : [styles.card];
return (
<article className={styles.card}>
<article className={classes.join(" ")}>
<h1 className={styles.date}>
<time dateTime={date.toISOString()}>
{date.toLocaleDateString("en-US", {

@ -9,15 +9,23 @@
}
.content h1 {
margin: 1rem 0;
font-size: calc(24rem / 16);
font-weight: 600;
color: var(--blue-2);
color: var(--primary-accent);
}
.content h2,
.content h3 {
font-size: calc(18rem / 16);
margin-top: calc(24rem / 16);
margin-bottom: calc(16rem / 16);
}
.nav {
top: calc(20rem / 16);
position: sticky;
height: 100%;
margin: calc(8rem / 16) calc(32rem / 16) 0 0;
color: var(--purple-2);
color: var(--primary-heading);
font-weight: 500;
}
@ -26,10 +34,10 @@
overflow: hidden;
white-space: nowrap;
font-size: calc(14rem / 16);
border-bottom: calc(1rem / 16) solid var(--blue-2-25);
border-bottom: calc(1rem / 16) solid var(--primary-accent-light);
align-items: center;
height: calc(40rem / 16);
width: calc(284rem / 16);
width: calc(200rem / 16);
padding: 0 calc(14rem / 16);
cursor: pointer;
}
@ -41,8 +49,8 @@
}
.selected {
background-color: var(--blue-1-05);
color: var(--blue-2);
background-color: var(--primary-accent-dim);
color: var(--primary-accent);
font-weight: 700;
}
@ -56,7 +64,7 @@
.selected .marker {
display: inline;
background-color: var(--blue-2);
background-color: var(--primary-accent);
height: calc(24rem / 16);
width: calc(4rem / 16);
margin-right: 1rem;
@ -73,7 +81,7 @@
flex: 1;
display: flex;
cursor: pointer;
color: var(--purple-2);
color: var(--primary-heading);
font-size: calc(12rem / 16);
}
@ -88,15 +96,15 @@
}
.arrowHeading {
color: var(--blue-2);
color: var(--primary-accent);
font-size: calc(14rem / 16);
font-weight: 700;
border-bottom: calc(2rem / 16) solid var(--blue-2);
border-bottom: calc(2rem / 16) solid var(--primary-accent);
padding-bottom: calc(4rem / 16);
}
.arrow {
fill: var(--blue-2);
fill: var(--primary-accent);
margin-top: calc(27rem / 16);
}
@ -110,6 +118,12 @@
padding-left: calc(8rem / 16);
}
.link,
.link:visited {
color: inherit;
text-decoration: none;
}
.burger {
display: none;
}
@ -152,6 +166,18 @@
padding: 0 calc(16rem / 16);
}
.content h1 {
font-size: calc(18rem / 16);
}
.content h2,
.content h3,
.content h4 {
font-size: calc(18rem / 16);
margin-top: calc(24rem / 16);
margin-bottom: calc(8rem / 16);
}
.nav {
margin: 0;
}

@ -7,8 +7,9 @@ import React, {
useCallback,
} from "react";
import styles from "./OrganizedContent.module.css";
import NextLink from "next/link";
export interface LinkProps {
export interface LinkProps { //todo check if we need this
className?: string;
id: string;
children: ReactNode;
@ -20,7 +21,6 @@ type Link = ComponentType<LinkProps>;
interface Section {
id: string;
title: string;
Content: ComponentType;
}
const READ_ALL_TITLE = "Read All";
@ -28,18 +28,26 @@ export const READ_ALL_ID = "read-all";
interface Props {
sections: Section[];
currentId: string;
id: string;
children: ReactNode;
pageTitle: string;
link: Link;
}
export function OrganizedContent(props: Props) {
const sections = createSections(props.sections);
const currentIndex = sections.findIndex(({ id }) => id === props.currentId);
export function OrganizedContent({
sections,
id,
children,
pageTitle,
link: Link,
}: Props) {
const [mobileNavOpen, setMobileNavOpen] = useState(false);
const currentIndex = sections.findIndex(
({ id: sectionId }) => sectionId === id
);
if (currentIndex < 0) {
throw new Error(`Section with ID ${props.currentId} was not found`);
throw new Error(`Section with ID ${id} was not found`);
}
const section = sections[currentIndex];
@ -70,25 +78,25 @@ export function OrganizedContent(props: Props) {
<Nav
sections={sections}
currentIndex={currentIndex}
link={props.link}
pageTitle={props.pageTitle}
link={Link}
pageTitle={pageTitle}
setMobileNavOpen={setMobileNavOpen}
/>
</div>
</div>
<div className={styles.content}>
{isReadAll ? (
<section.Content />
children
) : (
<>
<div>
<section>
<h1>{section.title}</h1>
<section.Content />
</div>
{children}
</section>
<Footer
sections={sections}
currentIndex={currentIndex}
link={props.link}
link={Link}
/>
</>
)}
@ -156,7 +164,7 @@ function Nav({
setMobileNavOpen,
}: NavProps) {
return (
<div className={styles.nav}>
<nav className={styles.nav}>
<h1 className={styles.mobileNavTitle}>{pageTitle}</h1>
{sections.map((section, index) => {
const classNames = [styles.navItem];
@ -181,7 +189,7 @@ function Nav({
</Link>
);
})}
</div>
</nav>
);
}
@ -240,26 +248,68 @@ function useDebounce(func: () => void, delay = 300) {
}, [func, delay]);
}
function createSections(sections: Section[]) {
return [
{
id: READ_ALL_ID,
title: READ_ALL_TITLE,
Content() {
return (
<>
{sections.map(({ id, title, Content: SectionContent }) => (
<div key={id}>
<h1>{title}</h1>
<SectionContent />
</div>
))}
</>
);
},
},
...sections,
];
export interface SectionWithContent {
section: Section;
Content: ComponentType;
}
export function createReadAllSection(
sections: Section[],
content: false