Event Description Card
|
@ -0,0 +1,55 @@
|
|||
.card {
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
max-width: 540px;
|
||||
padding: 1.5rem;
|
||||
border-radius: 4px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.poster {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
margin-right: 1.25rem;
|
||||
}
|
||||
|
||||
.details {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.name {
|
||||
color: var(--purple-2);
|
||||
font-weight: bolder;
|
||||
font-size: 1.125rem;
|
||||
line-height: 1.6875rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.desc {
|
||||
color: var(--purple-2);
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
.button {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 30px;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 768px) {
|
||||
.card {
|
||||
padding: 0;
|
||||
background-color: #e1eefa;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
import React, { ReactNode } from "react";
|
||||
// import { Button } from "./Button";
|
||||
import { EventSetting } from "./EventSetting";
|
||||
import styles from "./EventDescriptionCard.module.css";
|
||||
|
||||
interface BaseProps {
|
||||
name: string;
|
||||
date: Date;
|
||||
poster: string;
|
||||
registerLink?: string;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
type Props = BaseProps &
|
||||
(
|
||||
| { online: true; location: keyof typeof links }
|
||||
| { online: false; location: string }
|
||||
);
|
||||
|
||||
const links = {
|
||||
Twitch: "https://www.twitch.tv/uwcsclub",
|
||||
Discord: "https://discord.gg/pHfYBCg",
|
||||
Facebook: "https://www.facebook.com/uw.computerscienceclub",
|
||||
Instagram: "https://www.instagram.com/uwcsclub/",
|
||||
};
|
||||
|
||||
/**
|
||||
* @remarks
|
||||
* - Child elements will display as the event's description
|
||||
* - Assuming date prop is in EST
|
||||
* - poster is the event's image name, including file ending (.jpg/.png/etc)
|
||||
* - If event is online, location will be the platform, with capital first letter and no trailing spaces
|
||||
* - ie. location="Discord"
|
||||
* @todo
|
||||
* get Link component
|
||||
*/
|
||||
export function EventDescriptionCard(props: Props) {
|
||||
return (
|
||||
<article className={styles.card}>
|
||||
<img className={styles.poster} src={props.poster} alt={props.name} />
|
||||
|
||||
<div className={styles.details}>
|
||||
<h3 className={styles.name}>{props.name}</h3>
|
||||
|
||||
<EventSetting
|
||||
date={props.date}
|
||||
online={props.online}
|
||||
location={props.location}
|
||||
/>
|
||||
<div className={styles.desc}>{props.children}</div>
|
||||
<div className={styles.spacer}></div>
|
||||
|
||||
<footer>
|
||||
{props.registerLink && (
|
||||
<div className={styles.button}>
|
||||
<button>
|
||||
<a href={props.registerLink}>Register</a>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{props.online && (
|
||||
<a target="_blank" href={links[props.location]} rel="noreferrer">
|
||||
<img
|
||||
className={styles.logo}
|
||||
alt={props.location}
|
||||
src={"logos/" + props.location + ".png"}
|
||||
/>
|
||||
</a>
|
||||
)}
|
||||
</footer>
|
||||
</div>
|
||||
</article>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
.setting {
|
||||
color: var(--blue-1);
|
||||
font-weight: bolder;
|
||||
font-size: 0.75rem;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
import React from "react";
|
||||
import styles from "./EventSetting.module.css";
|
||||
|
||||
interface Props {
|
||||
date: Date;
|
||||
online: boolean;
|
||||
location: string;
|
||||
}
|
||||
|
||||
export function EventSetting(props: Props) {
|
||||
const date = props.date.toLocaleDateString("en-US", {
|
||||
day: "numeric",
|
||||
month: "long",
|
||||
year: "numeric",
|
||||
});
|
||||
const time = props.date.toLocaleTimeString("en-US", {
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
});
|
||||
const location = props.online ? `Online - ${props.location}` : props.location;
|
||||
|
||||
return (
|
||||
<div className={styles.setting}>
|
||||
<time dateTime={props.date.toISOString()}>{`${date} | ${time}`}</time>
|
||||
{` | ${location}`}
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -8,12 +8,6 @@
|
|||
display: inline-block;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 768px) {
|
||||
.news {
|
||||
background-color: #e1eefa;
|
||||
}
|
||||
}
|
||||
|
||||
.newsTitle {
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
|
@ -39,3 +33,32 @@
|
|||
background-color: var(--purple-2);
|
||||
margin: 0 0 13px 0;
|
||||
}
|
||||
|
||||
.eventDescriptionCardDemo {
|
||||
padding: 50px 0;
|
||||
background-color: var(--off-white);
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.eventDescriptionCardDemo > * {
|
||||
margin: 12px 50px;
|
||||
}
|
||||
|
||||
.eventDescriptionCardDemo > *:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.eventDescriptionCardDemo > *:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 768px) {
|
||||
.news,
|
||||
.eventDescriptionCardDemo {
|
||||
background-color: #e1eefa;
|
||||
}
|
||||
|
||||
.eventDescriptionCardDemo > * {
|
||||
margin: 50px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React from "react";
|
||||
import { EventDescriptionCard } from "./EventDescriptionCard";
|
||||
|
||||
import styles from "./playground.module.css";
|
||||
|
||||
|
@ -71,3 +72,42 @@ export function NewsCardDemo() {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function EventDescriptionCardDemo() {
|
||||
const { name, short, date } = afterHoursMetadata;
|
||||
|
||||
return (
|
||||
<div className={styles.eventDescriptionCardDemo}>
|
||||
<EventDescriptionCard
|
||||
name={name}
|
||||
date={date}
|
||||
online={true}
|
||||
location="Twitch"
|
||||
poster="images/playground/intro-ootb.jpg"
|
||||
registerLink="/"
|
||||
>
|
||||
<p>{short}</p>
|
||||
</EventDescriptionCard>
|
||||
<EventDescriptionCard
|
||||
name={name}
|
||||
date={date}
|
||||
online={true}
|
||||
location="Twitch"
|
||||
poster="images/playground/alt-tab.jpg"
|
||||
registerLink="/"
|
||||
>
|
||||
<p>{short}</p>
|
||||
</EventDescriptionCard>
|
||||
<EventDescriptionCard
|
||||
name={name}
|
||||
date={date}
|
||||
online={true}
|
||||
location="Twitch"
|
||||
poster="images/playground/intro-ootb.jpg"
|
||||
registerLink="/"
|
||||
>
|
||||
<p>{short}</p>
|
||||
</EventDescriptionCard>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
import {MiniEventCardDemo, NewsCardDemo} from '../components/playground'
|
||||
import {
|
||||
MiniEventCardDemo,
|
||||
NewsCardDemo,
|
||||
EventDescriptionCardDemo,
|
||||
} from "../components/playground";
|
||||
|
||||
# Playground
|
||||
|
||||
## `<MiniEventCard />`
|
||||
|
||||
The `<MiniEventCard />` component has a collapsible description, and it used on
|
||||
the events page. It uses the `<details>` tag and works without JS!
|
||||
The `<MiniEventCard />` component has a collapsible description, and it is used
|
||||
on the events page. It uses the `<details>` tag and works without JS!
|
||||
|
||||
<MiniEventCardDemo />
|
||||
|
||||
|
@ -15,4 +19,15 @@ the events page. It uses the `<details>` tag and works without JS!
|
|||
|
||||
unavailable
|
||||
|
||||
<NewsCardDemo />
|
||||
<NewsCardDemo />
|
||||
|
||||
---
|
||||
|
||||
## `<EventDescriptionCard />`
|
||||
|
||||
The `<EventDescriptionCard />` component is used on the home page, and uses the
|
||||
`<Button />` and `<EventSetting />` components.
|
||||
|
||||
<EventDescriptionCardDemo />
|
||||
|
||||
---
|
||||
|
|
After Width: | Height: | Size: 268 KiB |
After Width: | Height: | Size: 321 KiB |
Before Width: | Height: | Size: 61 KiB |
After Width: | Height: | Size: 900 B |
After Width: | Height: | Size: 615 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 575 B |