Compare commits

..

1 Commits

  1. 23
      .drone.yml
  2. 7
      .eslintrc.js
  3. 11
      .gitignore
  4. 6
      .vscode/settings.json
  5. 18
      README.md
  6. 2
      components/ArchivePage.module.css
  7. 4
      components/ArchivePage.tsx
  8. 1
      components/Bubble.module.css
  9. 4
      components/Button.module.css
  10. 4
      components/EventCard.module.css
  11. 29
      components/EventCard.tsx
  12. 4
      components/EventDescriptionCard.module.css
  13. 13
      components/EventDescriptionCard.tsx
  14. 33
      components/EventSetting.tsx
  15. 4
      components/Footer.module.css
  16. 14
      components/Footer.tsx
  17. 4
      components/Link.module.css
  18. 20
      components/MiniEventCard.module.css
  19. 32
      components/MiniEventCard.tsx
  20. 10
      components/Navbar.module.css
  21. 71
      components/Navbar.tsx
  22. 8
      components/NewsCard.module.css
  23. 11
      components/NewsCard.tsx
  24. 10
      components/OrganizedContent.module.css
  25. 4
      components/OrganizedContent/Header.module.css
  26. 2
      components/SocialLinks.module.css
  27. 10
      components/SocialLinks.tsx
  28. 6
      components/Table.module.css
  29. 12
      components/TeamMember.module.css
  30. 4
      components/TeamMember.tsx
  31. 66
      components/TeamMemberCard.module.css
  32. 71
      components/TeamMemberCard.tsx
  33. 79
      components/Theme.tsx
  34. 12
      components/WarningHeader.module.css
  35. 61
      components/WarningHeader.tsx
  36. 14
      content/about/code-of-conduct/ORDER.json
  37. 1
      content/about/code-of-conduct/additional-information.md
  38. 1
      content/about/code-of-conduct/addressing-grievances.md
  39. 1
      content/about/code-of-conduct/confidentiality.md
  40. 1
      content/about/code-of-conduct/consequences-of-inappropriate-behaviour.md
  41. 1
      content/about/code-of-conduct/contact-information.md
  42. 1
      content/about/code-of-conduct/expected-behaviour.md
  43. 1
      content/about/code-of-conduct/experiencing-unacceptable-behaviour.md
  44. 1
      content/about/code-of-conduct/license-information-and-attribution.md
  45. 1
      content/about/code-of-conduct/purpose.md
  46. 1
      content/about/code-of-conduct/revision.md
  47. 1
      content/about/code-of-conduct/scope-and-spaces.md
  48. 1
      content/about/code-of-conduct/unacceptable-behaviour.md
  49. 16
      content/about/constitution/ORDER.json
  50. 3
      content/about/constitution/amendments-and-procedures.md
  51. 1
      content/about/constitution/code-of-conduct.md
  52. 20
      content/about/constitution/committees.md
  53. 1
      content/about/constitution/dissolution.md
  54. 20
      content/about/constitution/duties-of-officers.md
  55. 19
      content/about/constitution/executive-council.md
  56. 1
      content/about/constitution/finances.md
  57. 7
      content/about/constitution/meetings.md
  58. 3
      content/about/constitution/membership.md
  59. 1
      content/about/constitution/name.md
  60. 9
      content/about/constitution/officers.md
  61. 1
      content/about/constitution/purpose.md
  62. 3
      content/about/constitution/revision.md
  63. 1
      content/about/constitution/use-of-club-resources.md
  64. 2
      content/about/our-supporters.mdx
  65. 2
      content/events/1994/fall/ACM-Style-Programming-Contest.md
  66. 2
      content/events/1994/fall/CSC-Elections.md
  67. 2
      content/events/1994/fall/Exploring-the-Internet.md
  68. 2
      content/events/1994/fall/Game-Theory.md
  69. 2
      content/events/1994/fall/Movie-Outing-Brainstorm.md
  70. 2
      content/events/1994/fall/Prograph-Picture-the-Future.md
  71. 2
      content/events/1994/fall/SIGGRAPH-Video-Night.md
  72. 2
      content/events/1994/fall/UNIX-I-Tutorial.md
  73. 2
      content/events/1994/fall/UNIX-II-Tutorial.md
  74. 2
      content/events/1999/fall/Calculational-Mathematics.md
  75. 2
      content/events/1999/fall/Ctrl-D.md
  76. 2
      content/events/1999/fall/GDB,-Purify-Tutorial.md
  77. 2
      content/events/1999/fall/Homebrew-Processors-and-Integrated-Systems-in-FPGAs.md
  78. 2
      content/events/1999/fall/Living-Laboratories-The-Future-Computing-Environments-at-Georgia-Tech.md
  79. 2
      content/events/1999/fall/Open-Q&A-session.md
  80. 2
      content/events/1999/fall/Proofs-and-Programs.md
  81. 2
      content/events/2000/fall/CSC-Elections.md
  82. 2
      content/events/2000/fall/Realising-the-Next-Generation-Internet.md
  83. 2
      content/events/2000/fall/SIGGraph-Video-Night.md
  84. 2
      content/events/2000/spring/Ctrl-D.md
  85. 2
      content/events/2000/winter/Enterprise-Java-APIs-and-Implementing-a-Web-Portal-(1).md
  86. 2
      content/events/2000/winter/Enterprise-Java-APIs-and-Implementing-a-Web-Portal.md
  87. 2
      content/events/2001/spring/ACM-Style-programming-contest.md
  88. 2
      content/events/2001/winter/ACM-Style-programming-contest.md
  89. 2
      content/events/2001/winter/Executive-elections.md
  90. 2
      content/events/2001/winter/Meeting-#2.md
  91. 2
      content/events/2001/winter/Meeting-#3.md
  92. 2
      content/events/2001/winter/Meeting-#4.md
  93. 2
      content/events/2001/winter/Meeting-#5.md
  94. 2
      content/events/2002/fall/A-GNU-Approach-to-Virtual-Memory-Management-in-a-Multiserver-Operating-System.md
  95. 2
      content/events/2002/fall/Automatic-Memory-Management-and-Garbage-Collection.md
  96. 2
      content/events/2002/fall/Business-Meeting.md
  97. 2
      content/events/2002/fall/Debian-in-the-Enterprise.md
  98. 2
      content/events/2002/fall/F02-elections.md
  99. 2
      content/events/2002/fall/GNULinux-InstallFest-with-KW-LUG-and-UW-DIG.md
  100. 2
      content/events/2002/fall/GNULinux-on-HPPA.md
  101. Some files were not shown because too many files have changed in this diff Show More

@ -23,40 +23,25 @@ steps:
commands:
- npm run lint
- name: optimize-images
- name: build
image: node:16
depends_on:
- install-deps
commands:
- npm run build:images
- npm run build:web
- name: generate-calendar
image: node:16
depends_on:
- install-deps
commands:
- npm run build:calendar
- name: generate-api
image: node:16
depends_on:
- install-deps
commands:
- npm run build:api
- name: build
image: node:16
depends_on:
- optimize-images
commands:
- USE_LDAP=true npm run build:web
- npm run generate:calendar
- name: export
image: node:16
depends_on:
- generate-api
- generate-calendar
- build
- generate-calendar
commands:
- npm run export

@ -17,12 +17,7 @@ module.exports = {
],
plugins: ["@typescript-eslint", "react", "react-hooks", "prettier"],
rules: {
'prettier/prettier': [
'error',
{
'endOfLine': 'lf',
}
],
"prettier/prettier": "error",
"import/first": "error",
"import/order": [

11
.gitignore vendored

@ -25,13 +25,4 @@ yarn-debug.log*
yarn-error.log*
# Calendar is automatically generated
/public/events.ics
# Images should be optimized
/public/images
# APIs should be automatically generated, schema should be checked in
/public/api/*
!/public/api/schema
.idea/**
/public/events.ics

@ -40,11 +40,7 @@
"files.eol": "\n",
"[markdown]": {
"editor.wordWrap": "on",
"editor.quickSuggestions": {
"comments": "off",
"strings": "off",
"other": "off"
},
"editor.quickSuggestions": false,
"editor.tabSize": 4
}
}

@ -1,13 +1,6 @@
# README
# Development
## Documentation
- [Architecture and Folder Structure](docs/architecture.md)
- [Everything about pages](docs/pages.md)
## Development
### Dependencies
## Dependencies
Make sure that you have `node` >= 14 and `npm` >= 7. Node 14 ships with npm v6,
so if you're using node 14, you would need to upgrade npm. Alternatively you
@ -15,20 +8,19 @@ could also upgrade to node 16, which ships with npm 7.
How to upgrade npm: `npm i -g npm`
### Local
## Local
- `npm install` to install project dependencies
- `npm run build:images` to optimize images for the first time after cloning
- `npm run dev` to run the dev server (http://localhost:3000)
### Production
## Production
- `npm install` to install project dependencies
- `npm run build` to generate html/css/js
- `npm run export` to move the built files (along with assets in the public directory) to the `/out` directory
- Use your favourite web server to host the files in the `/out` directory. (A very simple one would be `python -m http.server` - not sure if it should actually be used for production :P)
## Deploy
# Deploy
- `groups` (make sure you're in the `www` group)
- `curl -o- https://git.csclub.uwaterloo.ca/www/www-new/raw/branch/main/deploy.sh | bash` (run on `caffeine`)

@ -3,7 +3,7 @@
}
.page > h1 {
border-bottom: calc(1rem / 16) solid var(--border);
border-bottom: calc(1rem / 16) solid var(--primary-heading);
padding-bottom: 1rem;
}

@ -1,6 +1,6 @@
import React from "react";
import { capitalize, Term } from "@/utils";
import { capitalize } from "@/utils";
import { Link } from "./Link";
import {
@ -16,7 +16,7 @@ export interface Props {
type: "news" | "events";
items: {
year: string;
terms: Term[];
terms: string[];
}[];
}

@ -6,6 +6,7 @@
.bubble {
--border-radius: calc(5000rem / 16);
display: flex;
flex-direction: row;
position: absolute;

@ -2,8 +2,8 @@
.link {
font-family: "Poppins", "sans-serif";
border-radius: calc(20rem / 16);
background-color: var(--button-background);
color: var(--text-light);
background-color: var(--primary-accent);
color: var(--primary-background);
border: none;
outline: none;
transition-duration: 0.3s;

@ -31,10 +31,6 @@
margin-bottom: 0;
}
.content > h1 a {
color: var(--primary-heading);
}
.content,
.content > h2 {
font-weight: 400;

@ -10,8 +10,7 @@ import styles from "./EventCard.module.css";
interface EventCardProps {
name: string;
short: string;
startDate: Date;
endDate?: Date;
date: Date;
online: boolean;
location: string;
poster?: string;
@ -19,27 +18,18 @@ interface EventCardProps {
permaLink: string;
showDescription?: boolean;
children: ReactNode;
year: number;
term: string;
slug: string;
titleLinked: boolean;
}
export function EventCard({
permaLink,
name,
startDate,
endDate,
date,
online,
location,
poster,
registerLink,
children,
showDescription = false,
year,
term,
slug,
titleLinked,
}: EventCardProps) {
return (
<article className={styles.card}>
@ -64,20 +54,9 @@ export function EventCard({
showDescription ? styles.mobileShowDescriptionContent : "",
].join(" ")}
>
<h1>
{titleLinked ? (
<Link href={`/events/${year}/${term}/${slug}`}>{name}</Link>
) : (
name
)}
</h1>
<h1>{name}</h1>
<h2>
<EventSetting
startDate={startDate}
endDate={endDate}
online={online}
location={location}
/>
<EventSetting date={date} online={online} location={location} />
</h2>
{!showDescription && (
<Link href={permaLink}>

@ -4,7 +4,7 @@
max-width: calc(540rem / 16);
padding: calc(24rem / 16);
border-radius: calc(20rem / 16);
background-color: var(--card-background);
background-color: var(--primary-background);
}
.poster {
@ -38,7 +38,7 @@
.setting {
margin: 0;
color: var(--link);
color: var(--primary-accent);
font-size: calc(14rem / 16);
font-weight: 600;
}

@ -13,8 +13,7 @@ interface Props {
short: string;
online: boolean;
location: string;
startDate: Date;
endDate?: Date;
date: Date;
poster?: string;
registerLink?: string;
permaLink: string;
@ -35,8 +34,7 @@ export function EventDescriptionCard({
poster,
name,
short,
startDate,
endDate,
date,
online,
registerLink,
permaLink,
@ -50,12 +48,7 @@ export function EventDescriptionCard({
<div className={styles.details}>
<h1 className={styles.name}>{name}</h1>
<h2 className={styles.setting}>
<EventSetting
startDate={startDate}
endDate={endDate}
online={online}
location={location}
/>
<EventSetting date={date} online={online} location={location} />
</h2>
<p className={styles.desc}>{short}</p>
<Link href={permaLink}>Learn more</Link>

@ -3,51 +3,30 @@ import React from "react";
import styles from "./EventSetting.module.css";
interface Props {
startDate: Date;
endDate?: Date;
date: Date;
online: boolean;
location: string;
}
export function EventSetting(props: Props) {
const date = props.startDate.toLocaleDateString("en-US", {
const date = props.date.toLocaleDateString("en-US", {
day: "numeric",
month: "long",
year: "numeric",
});
const time = props.startDate.toLocaleTimeString("en-US", {
const time = props.date.toLocaleTimeString("en-US", {
hour: "numeric",
minute: "numeric",
timeZoneName: "short",
});
const endDate =
props.endDate?.toLocaleDateString("en-US", {
day: "numeric",
month: "long",
year: "numeric",
}) ?? "";
const location = props.online ? `Online - ${props.location}` : props.location;
const separator = <span className={styles.separator}> | </span>;
return (
<div className={styles.container}>
{!props.endDate || date == endDate ? (
// Single day event
<>
<time dateTime={props.startDate.toISOString()}>{date}</time>
{separator}
<span>{time}</span>
</>
) : (
// Multi day event
<span>
<time dateTime={props.startDate.toISOString()}>{date}</time>
<span> - </span>
<time dateTime={props.startDate.toISOString()}>{endDate}</time>
</span>
)}
<time dateTime={props.date.toISOString()}>{date}</time>
{separator}
<span>{time}</span>
{separator}
{location}
</div>

@ -1,6 +1,6 @@
.footer {
box-sizing: border-box;
background: var(--footer-background);
background: var(--primary-heading);
padding: 1rem 0;
width: 100%;
}
@ -17,7 +17,7 @@
}
.text {
color: var(--text-light);
color: var(--primary-background);
font-style: normal;
text-align: center;
}

@ -1,15 +1,11 @@
import Link from "next/link";
import React from "react";
import { Button } from "./Button";
import { SocialLinks } from "./SocialLinks";
import { useThemeContext } from "./Theme";
import styles from "./Footer.module.css";
export function Footer() {
const themeContext = useThemeContext();
return (
<footer className={styles.footer}>
<div className={styles.container}>
@ -19,16 +15,6 @@ export function Footer() {
<a className={styles.email}>exec@csclub.uwaterloo.ca</a>
</Link>
</div>
<Button
size="small"
onClick={() =>
themeContext?.theme.name === "dark"
? themeContext?.setTheme("light")
: themeContext?.setTheme("dark")
}
>
Toggle Theme
</Button>
<SocialLinks color="white" size="small" />
</div>
</footer>

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

@ -2,11 +2,10 @@
box-sizing: border-box;
position: relative;
padding: calc(20rem / 16);
color: var(--text);
}
.darkBg {
background-color: var(--dark-card-background);
.card:nth-child(odd) {
background-color: var(--secondary-accent-light);
}
.name {
@ -15,10 +14,6 @@
margin: 0;
}
.name a {
color: var(--primary-heading);
}
.nameSpacer {
width: calc(140rem / 16);
}
@ -62,17 +57,6 @@
fill: var(--primary-accent);
}
.card h1,
.card h2,
.card h3,
.card h4 {
font-size: calc(18rem / 16);
margin-top: calc(24rem / 16);
margin-bottom: calc(8rem / 16);
color: var(--mini-event-card-text);
}
@media only screen and (max-width: calc(768rem / 16)) {
.details {
bottom: 0;

@ -1,54 +1,36 @@
import React, { ReactNode } from "react";
import { EventSetting } from "./EventSetting";
import { Link } from "./Link";
import styles from "./MiniEventCard.module.css";
interface MiniEventCardProps {
interface Props {
name: string;
description: ReactNode;
short: string;
online: boolean;
location: string;
startDate: Date;
endDate?: Date;
background: "dark-bg" | "normal-bg";
year: number;
term: string;
slug: string;
date: Date;
}
export const MiniEventCard: React.FC<MiniEventCardProps> = ({
export const MiniEventCard: React.FC<Props> = ({
name,
short,
description,
location,
startDate,
endDate,
date,
online,
background,
year,
term,
slug,
}) => {
const cardBackground =
background === "dark-bg" ? `${styles.darkBg} ${styles.card}` : styles.card;
return (
<details className={cardBackground}>
<details className={styles.card}>
<summary>
<div onClick={(event) => event.preventDefault()}>
<h2 className={styles.name}>
<Link href={`/events/${year}/${term}/${slug}`}>{name}</Link>
<div>{name}</div>
<div className={styles.nameSpacer}></div>
</h2>
<div className={styles.info}>
<EventSetting
startDate={startDate}
endDate={endDate}
location={location}
online={online}
/>
<EventSetting date={date} location={location} online={online} />
</div>
<p className={styles.shortDescription}>{short}</p>
</div>

@ -63,7 +63,7 @@
}
.navMenu a {
color: var(--primary-text);
color: var(--primary-heading);
text-decoration: none;
}
@ -219,14 +219,6 @@
cursor: pointer;
}
.icon line {
stroke: var(--icon);
}
.icon path {
fill: var(--icon);
}
.navMobileBackground {
position: fixed;
visibility: hidden;

@ -32,10 +32,6 @@ const menu: Menu = [
name: "Meet the Team",
route: "/about/team",
},
{
name: "Members",
route: "/about/members",
},
{
name: "Constitution",
route: "/about/constitution",
@ -98,7 +94,7 @@ const menu: Menu = [
},
{
name: "Internships",
route: "https://github.com/uwcsc/2023-internships",
route: "https://github.com/uwcsc/winter2022-internships",
},
],
},
@ -120,7 +116,7 @@ export function Navbar() {
className={styles.hamburger}
onClick={() => dispatch({ type: "open", route: router.pathname })}
>
<HamburgerSvg />
<Image src="/images/hamburger.svg" alt="Menu" />
</button>
<div
className={
@ -263,7 +259,7 @@ function NavItem(props: NavItemProps) {
}
onClick={() => props.onToggle(props.route)}
>
<DropdownSvg />
<Image src="/images/dropdown-icon.svg" alt="Dropdown Icon" />
</button>
<ul
className={
@ -348,64 +344,3 @@ function getMainRoute(route: string) {
}
return "/" + route.split("/")[1];
}
function HamburgerSvg() {
return (
<svg
width="30"
height="23"
viewBox="0 0 30 23"
className={styles.icon}
xmlns="http://www.w3.org/2000/svg"
>
<line
x1="28"
y1="2"
x2="2"
y2="2"
stroke="#2A2A62"
strokeWidth="4"
strokeLinecap="round"
strokeLinejoin="round"
/>
<line
x1="28"
y1="11.375"
x2="2"
y2="11.375"
stroke="#2A2A62"
strokeWidth="4"
strokeLinecap="round"
strokeLinejoin="round"
/>
<line
x1="28"
y1="20.75"
x2="2"
y2="20.75"
stroke="#2A2A62"
strokeWidth="4"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}
function DropdownSvg() {
return (
<svg
width="14"
height="9"
viewBox="0 0 14 9"
fill="none"
className={styles.icon}
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M7.75593 8.12713C7.35716 8.58759 6.64284 8.58759 6.24407 8.12713L0.638743 1.65465C0.0778675 1.00701 0.537921 0 1.39467 0L12.6053 0C13.4621 0 13.9221 1.00701 13.3613 1.65465L7.75593 8.12713Z"
fill="#2A2A62"
/>
</svg>
);
}

@ -1,26 +1,23 @@
.card {
padding: calc(30rem / 16) calc(40rem / 16);
max-width: calc(524rem / 16);
background-color: var(--card-background);
background-color: var(--primary-background);
border-radius: calc(20rem / 16);
margin-bottom: 1rem;
}
.fit.card {
max-width: unset;
padding: unset;
border-radius: unset;
background-color: var(--primary-background);
}
.date {
font-size: calc(18rem / 16);
margin: 0;
color: var(--primary-subtitle);
}
.author {
color: var(--author-text);
color: var(--secondary-heading);
font-style: normal;
}
@ -33,7 +30,6 @@
padding: 0;
max-width: unset;
background-color: transparent;
border-radius: 0;
}
.date {

@ -1,14 +1,11 @@
import React, { ReactNode } from "react";
import { Link } from "./Link";
import styles from "./NewsCard.module.css";
interface NewsCardProps {
date: Date;
author: string;
children: ReactNode;
permalink: string;
fit?: boolean;
}
@ -16,8 +13,7 @@ export const NewsCard: React.FC<NewsCardProps> = ({
date,
author,
children,
permalink,
fit = false, // resizes the article to fit the parent container if it's not a mini card
fit = false,
}) => {
const classes = fit ? [styles.card, styles.fit] : [styles.card];
@ -34,11 +30,6 @@ export const NewsCard: React.FC<NewsCardProps> = ({
</h1>
<address className={styles.author}>{author}</address>
<div className={styles.content}>{children}</div>
{!fit && (
<Link href={permalink}>
<span>Learn more</span>
</Link>
)}
</article>
);
};

@ -30,7 +30,7 @@
margin: calc(8rem / 16) calc(32rem / 16) calc(20rem / 16) 0;
height: calc(100vh - (44rem / 16));
color: var(--sidebar-text);
color: var(--primary-heading);
font-weight: 500;
}
@ -55,14 +55,10 @@
.selected {
background-color: var(--primary-accent-lightest);
color: var(--primary-heading);
color: var(--primary-accent);
font-weight: 700;
}
.selected div {
color: var(--primary-heading);
}
.readAll {
font-weight: 700;
}
@ -73,7 +69,7 @@
.selected .marker {
display: inline;
background-color: var(--marker);
background-color: var(--primary-accent);
height: calc(24rem / 16);
width: calc(4rem / 16);
margin-right: 1rem;

@ -8,12 +8,12 @@
flex-direction: row;
align-items: flex-end;
padding-bottom: 1rem;
border-bottom: calc(1rem / 16) solid var(--border);
border-bottom: calc(1rem / 16) solid var(--primary-heading);
}
.header {
line-height: 1;
color: var(--primary-title);
color: var(--primary-heading);
font-size: calc(48rem / 16);
margin: 0 0 0 calc(36rem / 16);
text-align: center;

@ -22,5 +22,5 @@
}
.white {
fill: var(--text-light);
fill: var(--primary-background);
}

@ -77,7 +77,7 @@ function InstagramSvg(color: string) {
xmlns="http://www.w3.org/2000/svg"
>
<linearGradient id="bluegreen-gradient">
<stop offset="0%" stopColor="var(--blue-gradient)" />
<stop offset="0%" stopColor="#1481E3" />
<stop offset="100%" stopColor="#4ED4B2" />
</linearGradient>
<path
@ -101,7 +101,7 @@ function DiscordSvg(color: string) {
version="1.1"
>
<linearGradient id="bluegreen-gradient">
<stop offset="0%" stopColor="var(--blue-gradient)" />
<stop offset="0%" stopColor="#1481E3" />
<stop offset="100%" stopColor="#4ED4B2" />
</linearGradient>
<g id="surface1">
@ -125,7 +125,7 @@ function TwitchSvg(color: string) {
xmlns="http://www.w3.org/2000/svg"
>
<linearGradient id="bluegreen-gradient">
<stop offset="0%" stopColor="var(--blue-gradient)" />
<stop offset="0%" stopColor="#1481E3" />
<stop offset="100%" stopColor="#4ED4B2" />
</linearGradient>
<g clipPath="url(#clip0)">
@ -170,7 +170,7 @@ function FacebookSvg(color: string) {
xmlns="http://www.w3.org/2000/svg"
>
<linearGradient id="bluegreen-gradient">
<stop offset="0%" stopColor="var(--blue-gradient)" />
<stop offset="0%" stopColor="#1481E3" />
<stop offset="100%" stopColor="#4ED4B2" />
</linearGradient>
<path
@ -194,7 +194,7 @@ function LiberaSvg(color: string) {
xmlns="http://www.w3.org/2000/svg"
>
<linearGradient id="bluegreen-gradient">
<stop offset="0%" stopColor="var(--blue-gradient)" />
<stop offset="0%" stopColor="#1481E3" />
<stop offset="100%" stopColor="#4ED4B2" />
</linearGradient>
<path

@ -7,7 +7,7 @@
}
.table thead tr {
background: var(--table-header);
background: var(--secondary-accent-light);
}
.table tbody tr {
@ -15,8 +15,8 @@
vertical-align: top;
}
.table tbody tr:nth-child(even) {
background: var(--table-section);
.table tbody tr:nth-child(odd) {
background: var(--primary-accent-lightest);
}
.table th {

@ -1,15 +1,14 @@
.container {
width: calc(126rem / 16);
max-width: calc(126rem / 16);
display: flex;
flex-direction: column;
margin: 0;
}
.img {
width: calc(118rem / 16);
height: calc(118rem / 16);
clip-path: circle();
width: 100%;
border-radius: 50%;
margin: 0 auto;
object-fit: cover;
}
@ -30,8 +29,7 @@
@media only screen and (max-width: calc(768rem / 16)) {
.img {
width: calc(126rem / 16);
height: calc(126rem / 16);
width: 100%;
}
.caption {

@ -6,13 +6,13 @@ import styles from "./TeamMember.module.css";
interface TeamMemberProps {
name: string;
role?: string;
role: string;
image: string;
}
export const TeamMember: React.FC<TeamMemberProps> = ({
name,
role = "",
role,
image,
}) => {
return (

@ -18,15 +18,11 @@
max-width: calc(126rem / 16);
max-height: calc(126rem / 16);
clip-path: circle();
clip-path: circle(50%);
}
.image {
width: calc(126rem / 16);
height: calc(126rem / 16);
clip-path: circle();
object-fit: cover;
width: 100%;
}
.name {
@ -78,50 +74,36 @@
.popupBackground {
position: fixed;
z-index: 11;
background-color: var(--navbar-page-overlay);
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: 11;
background-color: var(--navbar-page-overlay);
animation: revealBg 0.2s forwards;
}
.popupContainer {
position: fixed;
left: 0;
right: 0;
top: 50%;
z-index: 12;
display: flex;
z-index: 12;
flex-direction: column;
justify-content: flex-start;
align-items: center;
box-sizing: border-box;
padding: calc(40rem / 16);
max-height: 75vh;
overflow: auto;
background-color: var(--secondary-background);
padding: calc(20rem / 16) calc(40rem / 16);
left: 0;
top: 50%;
animation: popup 0.7s forwards;
}
.closeBtn {
position: absolute;
align-self: flex-end;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
/* reset default button styling */
background: none;
border: none;
width: min-content;
background: transparent;
border: 0px solid transparent;
padding: 0;
font-family: inherit;
line-height: inherit;
}
.popupContent {
@ -130,27 +112,29 @@
align-items: center;
}
.popupContent .name {
margin-top: calc(24rem / 16);
.popupImage {
width: 100%;
}
.popupName {
color: var(--primary-accent);
margin: calc(24rem / 16) 0 0 0;
font-size: calc(18rem / 16);
font-weight: 600;
}
.popupContent .role {
margin-bottom: calc(16rem / 16);
.popupRole {
color: var(--primary-heading);
margin: 0 0 1rem 0;
text-align: center;
font-size: calc(18rem / 16);
font-weight: 600;
}
.popupContent .description {
display: block;
.popupDescription {
font-size: calc(14rem / 16);
}
.popupContent .description > *:last-child {
margin-bottom: 0;
}
@media only screen and (max-width: calc(768rem / 16)) {
.card {
display: flex;

@ -8,26 +8,53 @@ import styles from "./TeamMemberCard.module.css";
export interface TeamMemberCardProps {
name: string;
role?: string;
role: string;
image: string;
children: React.ReactNode;
}
interface TeamMemberInfoProps extends TeamMemberCardProps {
isPopup?: boolean;
}
function TeamMemberInfo({
name,
role,
image,
children,
isPopup = false,
}: TeamMemberInfoProps) {
return (
<>
<div className={styles.picture}>
<Image
className={isPopup ? styles.popupImage : styles.image}
src={image}
alt={`Picture of ${name}`}
/>
</div>
<h1 className={isPopup ? styles.popupName : styles.name}>{name}</h1>
<h2 className={isPopup ? styles.popupRole : styles.role}>{role}</h2>
<div className={isPopup ? styles.popupDescription : styles.description}>
{children}
</div>
</>
);
}
export function TeamMemberCard({
name,
role = "",
role,
image,
children,
}: TeamMemberCardProps) {
const { width } = useWindowDimension();
const [isOpen, setIsOpen] = useState(false);
const handleClick = () => {
if (isOpen || width <= 768) {
setIsOpen(!isOpen);
}
};
return (
<>
<article className={styles.card} onClick={handleClick}>
@ -48,39 +75,11 @@ export function TeamMemberCard({
);
}
function TeamMemberInfo({
name,
role = "",
image,
children,
}: TeamMemberCardProps) {
return (
<>
<div className={styles.picture}>
<Image
className={styles.image}
src={image}
alt={`Picture of ${name}`}
/>
</div>
<h1 className={styles.name}>{name}</h1>
<h2 className={styles.role}>{role}</h2>
<div className={styles.description}>{children}</div>
</>
);
}
interface PopupProps extends TeamMemberCardProps {
interface Propup extends TeamMemberCardProps {
handleClick: () => void;
}
function ExecPopup({