diff --git a/docusaurus.config.js b/docusaurus.config.js index 51a4449..12d5864 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -138,6 +138,10 @@ const config = { to: "contributions", label: "Contributions", }, + { + to: "talks", + label: "Talks", + }, { to: "blog", position: "right", diff --git a/src/components/talks/Talk.module.scss b/src/components/talks/Talk.module.scss new file mode 100644 index 0000000..bfcb138 --- /dev/null +++ b/src/components/talks/Talk.module.scss @@ -0,0 +1,52 @@ +@import "../../css/mixins"; + +.card { + margin-bottom: calc(var(--ifm-spacing-horizontal) * 2); + border: 1px solid var(--ifm-color-emphasis-300); + box-shadow: none; +} + +.eventDetailsContainer { + border-left: 1px solid var(--ifm-color-emphasis-300); + + @include small-size { + border-left: 0; + border-top: 1px solid var(--ifm-color-emphasis-300); + padding-top: var(--ifm-spacing-vertical); + } +} + +.list { + list-style-type: none; + padding-left: 0; +} + +.buttons { + > a { + @include small-size { + width: 100%; + margin-top: calc(var(--ifm-spacing-vertical) / 2); + } + } + + a + a { + margin-left: 0.5em; + + @include small-size { + margin-left: 0; + } + } +} + +.icon { + width: 22px; + height: 22px; + margin-right: 0.3rem; + display: inline-block; + position: relative; + top: 4px; + + [data-theme="dark"] & { + fill: var(--ifm-font-color-base); + } +} \ No newline at end of file diff --git a/src/components/talks/Talk.tsx b/src/components/talks/Talk.tsx new file mode 100644 index 0000000..aa360e4 --- /dev/null +++ b/src/components/talks/Talk.tsx @@ -0,0 +1,138 @@ +import clsx from "clsx"; +import React, { FunctionComponent } from "react"; + +import styles from "./Talk.module.scss"; +import RecordingIcon from "./assets/icon-recording.svg"; +import SlidesIcon from "./assets/icon-slides.svg"; +import RepositoryIcon from "./assets/icon-repository.svg"; +import CalendarIcon from "./assets/icon-calendar.svg"; +import MessageIcon from "./assets/icon-message.svg"; +import LocationIcon from "./assets/icon-location.svg"; + +export interface TalkMetadata { + title: string; + description: React.ReactNode; + events: EventMetadata[]; + recordingURL?: string; + slidesURL?: string; + repoURL?: string; +} + +export interface EventMetadata { + name: string; + location: string; + date: Date; +} + +const Talk: FunctionComponent = ({ + title, + description, + events = [], + recordingURL, + slidesURL, + repoURL, +}) => { + return ( +
+
+
+

{title}

+
+
+
+
{description}
+
+ +
+
+
+
+
+ {recordingURL && ( + + + + + Watch recording + + )} + {slidesURL && ( + + + + + See slides + + )} + {repoURL && ( + + + + + See repository + + )} +
+
+
+
+ ); +}; + +const EventDetails: FunctionComponent<{ data: EventMetadata[] }> = ({ + data, +}) => { + if (data.length === 0) { + return null; + } + + const [firstEvent, ...otherEvents] = data; + const { name, location, date } = firstEvent; + return ( +
+
+
    +
  • + {name} +
  • +
  • + {location} +
  • +
  • + {formatDateString(date)} +
  • +
+
+ {data.length > 1 && ( +
+

Also presented on:

+
    + {otherEvents.map(({ name, location, date }) => ( +
  • + {name} in {location} ({formatDateString(date)}) +
  • + ))} +
+
+ )} +
+ ); +}; + +function formatDateString(date: Date): string { + return `${date.getMonth() + 1}/${date.getUTCFullYear()}`; +} + +export default Talk; \ No newline at end of file diff --git a/src/components/talks/assets/icon-calendar.svg b/src/components/talks/assets/icon-calendar.svg new file mode 100644 index 0000000..0051a8e --- /dev/null +++ b/src/components/talks/assets/icon-calendar.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/components/talks/assets/icon-location.svg b/src/components/talks/assets/icon-location.svg new file mode 100644 index 0000000..6ac9213 --- /dev/null +++ b/src/components/talks/assets/icon-location.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/components/talks/assets/icon-message.svg b/src/components/talks/assets/icon-message.svg new file mode 100644 index 0000000..391669c --- /dev/null +++ b/src/components/talks/assets/icon-message.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/components/talks/assets/icon-recording.svg b/src/components/talks/assets/icon-recording.svg new file mode 100644 index 0000000..e77c0b9 --- /dev/null +++ b/src/components/talks/assets/icon-recording.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/components/talks/assets/icon-repository.svg b/src/components/talks/assets/icon-repository.svg new file mode 100644 index 0000000..2b0f237 --- /dev/null +++ b/src/components/talks/assets/icon-repository.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/components/talks/assets/icon-slides.svg b/src/components/talks/assets/icon-slides.svg new file mode 100644 index 0000000..454c66c --- /dev/null +++ b/src/components/talks/assets/icon-slides.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/pages/talks.tsx b/src/pages/talks.tsx new file mode 100644 index 0000000..5fb6478 --- /dev/null +++ b/src/pages/talks.tsx @@ -0,0 +1,61 @@ +import React from "react"; +import Layout from "@theme/Layout"; + +import Talk, { TalkMetadata } from "../components/talks/Talk"; + +const talks: TalkMetadata[] = [ + { + title: "Packit: RPM integration, all in one", + description: ( + <> + Do you want to automate how you build and test your RPM packages? + Do you maintain any package in Fedora and want to automate the + releases? Or are you just interested in CI/CD on GitHub or GitLab, + Fedora and integration of upstream projects with RPM-based Linux + distributions? In this session, we are going to deep-dive into + features of Packit that can help you do your day-to-day job. + + ), + events: [ + { + name: "DevConf.cz", + location: "Brno, Czechia", + date: new Date(2023, 6, 17), + }, + { + name: "DevConf.cz Mini", + location: "Brno, Czechia", + date: new Date(2023, 3, 31), + }, + ], + recordingURL: "https://www.youtube.com/watch?v=FxhXzgxWO18", + slidesURL: "https://static.sched.com/hosted_files/devconfcz2023/37/DevConf.cz%20June%202023%20Packit%20talk-1.pdf", + }, +]; + +const title = "Talks"; +const description = "Featured talks I presented on various events."; + +export default function Talks(): JSX.Element { + return ( + +
+

{title}

+

{description}

+ +
+ {talks.map((talkData) => ( + + ))} +
+ +
+

+ Credits to + Paweł Kosiec for implementing his own React components + for talks. +

+
+
+ ); +} \ No newline at end of file