mirror of https://github.com/Qiskit/qiskit.org.git
Add new seminar-series page to qiskit.org (#1293)
* Create "what is this event" section for Seminar Series (#1301) * Create seminar series data table component (#1305) * Creates helpful resources section (#1310) * Fetch Seminar Series events from Airtable (#1320) * Create Seminar Series header (#1339) * Adds solution when there are no upcoming events (#1363) * Instrument seminar series page (#1400) * Add Olivia as co-host (#1401)
This commit is contained in:
parent
4d6f232fc8
commit
922a431aa5
|
@ -5,6 +5,7 @@
|
|||
@include type-style('expressive-heading-05');
|
||||
margin-bottom: $layout-03;
|
||||
color: $cool-gray-80;
|
||||
max-width: 8 * $column-size-large;
|
||||
|
||||
@include mq($from: medium, $until: large) {
|
||||
@include type-style('expressive-heading-03');
|
||||
|
|
|
@ -42,7 +42,7 @@ body {
|
|||
}
|
||||
|
||||
&_theme_light {
|
||||
background-color: $ui-background;
|
||||
background-color: $white;
|
||||
}
|
||||
|
||||
&_theme_dark {
|
||||
|
|
|
@ -6,16 +6,25 @@
|
|||
:tags="types"
|
||||
:to="to"
|
||||
cta-label="Join the event"
|
||||
:segment="segment"
|
||||
:vertical-layout="verticalLayout"
|
||||
>
|
||||
<div class="event-card__description">
|
||||
<slot v-if="this.$slots.default" />
|
||||
</div>
|
||||
<div>
|
||||
<p class="event-card__location">
|
||||
<p class="event-card__detail">
|
||||
<Map20 class="event-card__icon" />
|
||||
{{ location }}
|
||||
</p>
|
||||
<p class="event-card__date">
|
||||
<p class="event-card__detail">
|
||||
<Calendar20 class="event-card__icon" />
|
||||
<time>{{ date }}</time>
|
||||
</p>
|
||||
<p v-if="institution" class="event-card__detail">
|
||||
<Education20 class="event-card__icon" />
|
||||
{{ institution }}
|
||||
</p>
|
||||
</div>
|
||||
</AppCard>
|
||||
</template>
|
||||
|
@ -23,15 +32,19 @@
|
|||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import { Component, Prop } from 'vue-property-decorator'
|
||||
import { SegmentData } from '~/constants/appLinks'
|
||||
|
||||
@Component
|
||||
export default class EventCard extends Vue {
|
||||
@Prop({ type: Array, default: () => [] }) types!: string[]
|
||||
@Prop(String) title!: string
|
||||
@Prop(String) image!: string
|
||||
@Prop({ type: String, default: '' }) institution!: string
|
||||
@Prop(String) location!: string
|
||||
@Prop(String) date!: string
|
||||
@Prop(String) to!: string
|
||||
@Prop({ type: Object, required: false }) segment: SegmentData | undefined
|
||||
@Prop({ type: Boolean, default: false }) verticalLayout!: Boolean
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -45,14 +58,19 @@ export default class EventCard extends Vue {
|
|||
margin-bottom: $layout-01;
|
||||
}
|
||||
|
||||
&__location, &__date {
|
||||
&__description {
|
||||
margin-bottom: $spacing-06;
|
||||
}
|
||||
|
||||
&__detail {
|
||||
@include type-style('body-long-01');
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__location {
|
||||
margin-bottom: $spacing-03;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: initial;
|
||||
}
|
||||
}
|
||||
|
||||
&__icon {
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
<template>
|
||||
<section class="helpful-resources-section">
|
||||
<h2 class="copy__title" v-text="title" />
|
||||
<div class="helpful-resources-section__resources">
|
||||
<AppDescriptionCard
|
||||
v-for="resource in resources"
|
||||
:key="resource.title"
|
||||
v-bind="resource"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import { Component, Prop } from 'vue-property-decorator'
|
||||
import { DescriptionCard } from '~/components/ui/AppDescriptionCard.vue'
|
||||
|
||||
@Component
|
||||
export default class HelpfulResourcesSection extends Vue {
|
||||
@Prop(Array) resources!: DescriptionCard[]
|
||||
|
||||
title = 'Helpful Resources';
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "~/assets/scss/blocks/copy.scss";
|
||||
|
||||
.helpful-resources-section {
|
||||
&__resources {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
column-gap: 2rem;
|
||||
row-gap: 2rem;
|
||||
|
||||
@include mq($from: medium, $until: large) {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
@include mq($until: medium) {
|
||||
grid-template-columns: repeat(1, 1fr);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,37 @@
|
|||
<template>
|
||||
<section class="past-seminar-series-section">
|
||||
<h2 class="copy__title">
|
||||
Past Quantum Seminars
|
||||
</h2>
|
||||
<SeminarSeriesDataTable :events="events" events-section="past-events-section" />
|
||||
<AppCta
|
||||
class="past-seminar-series-section__cta"
|
||||
kind="ghost"
|
||||
v-bind="showMoreCta"
|
||||
/>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import { Component, Prop } from 'vue-property-decorator'
|
||||
import { SEMINAR_SERIES_FULL_ARCHIVE_CTA } from '~/constants/appLinks.ts'
|
||||
import { SeminarSeriesEvent } from '~/hooks/event-conversion-utils.ts'
|
||||
|
||||
@Component
|
||||
export default class PastSeminarSeriesSection extends Vue {
|
||||
@Prop({ type: Array, required: true }) events!: SeminarSeriesEvent[]
|
||||
|
||||
showMoreCta = SEMINAR_SERIES_FULL_ARCHIVE_CTA
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "~/assets/scss/blocks/copy.scss";
|
||||
|
||||
.past-seminar-series-section {
|
||||
&__cta {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,101 @@
|
|||
<template>
|
||||
<cv-data-table
|
||||
class="seminar-series-data-table"
|
||||
:columns="columns"
|
||||
>
|
||||
<template slot="data">
|
||||
<cv-data-table-row v-for="(row, rowIndex) in dataPerRow" :key="`${rowIndex}`">
|
||||
<cv-data-table-cell v-for="({ component, styles, data}, elementIndex) in row" :key="`${elementIndex}`">
|
||||
<AppCta v-if="isAppCtaComponent(component)" kind="ghost" v-bind="data" :style="styles" />
|
||||
<component
|
||||
:is="component"
|
||||
v-else
|
||||
:style="styles"
|
||||
>
|
||||
{{ data }}
|
||||
</component>
|
||||
</cv-data-table-cell>
|
||||
</cv-data-table-row>
|
||||
</template>
|
||||
</cv-data-table>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import { Component, Prop } from 'vue-property-decorator'
|
||||
import { GeneralLink } from '~/constants/appLinks'
|
||||
import { SeminarSeriesEvent } from '~/hooks/event-conversion-utils'
|
||||
|
||||
interface tableRowElement {
|
||||
component: string,
|
||||
styles: string,
|
||||
data: string | GeneralLink,
|
||||
}
|
||||
|
||||
@Component
|
||||
export default class SeminarSeriesDataTable extends Vue {
|
||||
@Prop({ type: Array, default: () => [] }) events!: SeminarSeriesEvent[]
|
||||
@Prop({ type: String, required: true }) eventsSection!: string
|
||||
|
||||
dataPerRow: tableRowElement[][] = this.events.map(event => ([
|
||||
{
|
||||
component: 'span',
|
||||
styles: 'min-width: 9rem; display: inline-block;',
|
||||
data: event.speaker
|
||||
},
|
||||
{
|
||||
component: 'span',
|
||||
styles: 'min-width: 9rem; display: inline-block;',
|
||||
data: event.institution
|
||||
},
|
||||
{
|
||||
component: 'span',
|
||||
styles: 'min-width: 19rem; display: inline-block;',
|
||||
data: event.title
|
||||
},
|
||||
{
|
||||
component: 'span',
|
||||
styles: 'min-width: 8rem; display: inline-block;',
|
||||
data: event.date
|
||||
},
|
||||
{
|
||||
component: 'AppCta',
|
||||
styles: 'min-width: 5rem;',
|
||||
data: {
|
||||
url: event.to,
|
||||
label: 'Join event',
|
||||
segment: {
|
||||
action: `seminar-series > ${this.eventsSection} > talk-on-youtube`
|
||||
}
|
||||
}
|
||||
}
|
||||
]))
|
||||
|
||||
columns = ['Speaker', 'Institution', 'Name of talk', 'Date of talk', 'Link to talk']
|
||||
|
||||
isAppCtaComponent (component: string) : boolean {
|
||||
return component === 'AppCta'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.seminar-series-data-table {
|
||||
overflow-x: scroll;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
.bx--data-table th {
|
||||
color: $black-100;
|
||||
background-color: $cool-gray-20;
|
||||
}
|
||||
|
||||
.bx--data-table tbody tr td, .bx--data-table tbody tr:hover td {
|
||||
color: $cool-gray-80;
|
||||
background-color: $white;
|
||||
border-top: none;
|
||||
border-bottom: 1px solid $cool-gray-20;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,127 @@
|
|||
<template>
|
||||
<header class="seminar-series-header">
|
||||
<div class="seminar-series-header__container">
|
||||
<div class="seminar-series-header__main">
|
||||
<div>
|
||||
<AppPageHeaderTitle>
|
||||
Quantum Information Science Seminar Series
|
||||
</AppPageHeaderTitle>
|
||||
<div class="seminar-series-header__description">
|
||||
<p>The Qiskit Quantum Information Science Seminar Series is dedicated to the research and academic communities as a broad and deep dive into the latest cutting edge quantum research.</p>
|
||||
<p>The seminar is live and interactive, you can discuss and ask questions as you watch, and is streamed on YouTube.</p>
|
||||
<p>Join us live every Friday at 12:00 PM ET.</p>
|
||||
</div>
|
||||
</div>
|
||||
<AppCta v-bind="cta" class="seminar-series-header__cta" />
|
||||
</div>
|
||||
<div class="seminar-series-header__aside">
|
||||
<div class="seminar-series-header__card-up-title-wrapper">
|
||||
<div class="seminar-series-header__card-up-title copy__subtitle">
|
||||
{{ cardTitle }}
|
||||
</div>
|
||||
</div>
|
||||
<EventCard v-bind="cardContent" :title="cardContent.speaker" :segment="segment" vertical-layout>
|
||||
{{ cardContent.title }}
|
||||
</EventCard>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import { Component, Prop } from 'vue-property-decorator'
|
||||
import { SEMINAR_SERIES_ALL_EPISODES_CTA } from '~/constants/appLinks.ts'
|
||||
import { SeminarSeriesEvent } from '~/hooks/event-conversion-utils.ts'
|
||||
|
||||
@Component
|
||||
export default class SeminarSeriesHeader extends Vue {
|
||||
@Prop({ type: Object, required: false }) nextEvent!: SeminarSeriesEvent|null
|
||||
@Prop({ type: Array, required: true }) pastEvents!: SeminarSeriesEvent[]
|
||||
|
||||
cta = SEMINAR_SERIES_ALL_EPISODES_CTA
|
||||
hasNextEvent = this.nextEvent
|
||||
cardTitle = this.hasNextEvent ? 'Up next:' : 'Featured seminar:'
|
||||
randomNumber = Math.random()
|
||||
randomIndex = Math.floor(this.randomNumber * this.pastEvents.length)
|
||||
cardContent = this.hasNextEvent ? this.nextEvent : this.pastEvents[this.randomIndex]
|
||||
segment = { action: 'seminar-series > header > talk-on-youtube' }
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~carbon-components/scss/globals/scss/typography';
|
||||
|
||||
.seminar-series-header {
|
||||
@include responsive-grid-bg-strip('/images/grid/grid-hero-learn.svg', auto, 28rem);
|
||||
|
||||
&__container {
|
||||
@include contained();
|
||||
display: grid;
|
||||
column-gap: $spacing-07;
|
||||
grid-template-columns: 3fr 4fr 3fr;
|
||||
grid-template-areas: 'main main aside';
|
||||
row-gap: $spacing-07;
|
||||
|
||||
@include mq($until: large) {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-areas: 'main aside';
|
||||
}
|
||||
|
||||
@include mq($until: medium) {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-areas:
|
||||
'main'
|
||||
'aside';
|
||||
}
|
||||
}
|
||||
|
||||
&__aside {
|
||||
grid-area: aside;
|
||||
}
|
||||
|
||||
&__cta {
|
||||
margin: 0 0 $layout-02;
|
||||
|
||||
@include mq($until: medium) {
|
||||
margin-top: $layout-03;
|
||||
}
|
||||
}
|
||||
|
||||
&__description {
|
||||
margin: $layout-05 0 0;
|
||||
max-width: 6 * $column-size-large;
|
||||
|
||||
> p {
|
||||
@include type-style('body-long-01');
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-bottom: $spacing-06;
|
||||
}
|
||||
}
|
||||
|
||||
@include mq($from: medium, $until: large) {
|
||||
margin-top: $layout-03;
|
||||
}
|
||||
}
|
||||
|
||||
&__main {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
grid-area: main;
|
||||
justify-content: space-between;
|
||||
margin-top: $spacing-07;
|
||||
}
|
||||
|
||||
&__card-up-title {
|
||||
border-bottom: 4px solid $purple-60;
|
||||
display: inline;
|
||||
padding-bottom: $spacing-02;
|
||||
padding-right: $spacing-03;
|
||||
|
||||
&-wrapper {
|
||||
margin-bottom: $spacing-06;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,29 @@
|
|||
<template>
|
||||
<section class="upcoming-seminar-series-section">
|
||||
<h2 class="copy__title">
|
||||
Upcoming Quantum Seminar Schedule
|
||||
</h2>
|
||||
<SeminarSeriesDataTable :events="events" events-section="upcoming-events-section" />
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import { Component, Prop } from 'vue-property-decorator'
|
||||
import { SeminarSeriesEvent } from '~/hooks/event-conversion-utils'
|
||||
|
||||
@Component
|
||||
export default class UpcomingSeminarSeriesSection extends Vue {
|
||||
@Prop({ type: Array, default: () => [] }) events!: SeminarSeriesEvent[]
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "~/assets/scss/blocks/copy.scss";
|
||||
|
||||
.upcoming-seminar-series-section {
|
||||
.copy__title {
|
||||
max-width: initial;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,52 @@
|
|||
<template>
|
||||
<section>
|
||||
<h2 class="copy__title" v-text="title" />
|
||||
<AppMosaic :mosaic-elements="mosaicElements" />
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import { Component } from 'vue-property-decorator'
|
||||
import { MosaicElement } from '~/components/ui/AppMosaic.vue'
|
||||
|
||||
@Component
|
||||
export default class WhatIsThisEventSection extends Vue {
|
||||
title = 'What is the Quantum Information Science Seminar Series?'
|
||||
|
||||
mosaicElements: MosaicElement[] = [
|
||||
{
|
||||
position: 'first',
|
||||
title: 'Learn from experts',
|
||||
description:
|
||||
'Learn from & interact directly with world-leading experts in quantum, from across the globe.',
|
||||
image: '/images/events/seminar-series/mosaic-experts.png'
|
||||
},
|
||||
{
|
||||
position: 'second',
|
||||
title: 'About the hosts',
|
||||
description:
|
||||
'Dr. Zlatko K. Minev, research staff member at IBM Quantum and recipient of MIT Tech Review’s 35 under 35 Global Innovator award, is our lead host. He is joined by Dr. Olivia Lanes, an experimental researcher and education developer at IBM, working to bridge the gap between the hardware and software communities.',
|
||||
image: '/images/events/seminar-series/mosaic-hosts.png'
|
||||
},
|
||||
{
|
||||
position: 'third',
|
||||
title: 'The latest in quantum computing',
|
||||
description:
|
||||
'This series will discuss all the most current research and new developements across the field of quantum computing.',
|
||||
image: '/images/events/seminar-series/mosaic-team.png'
|
||||
},
|
||||
{
|
||||
position: 'fourth',
|
||||
title: 'Real time questions & discussion',
|
||||
description:
|
||||
'Discuss in real time with other researchers, students, and folks in quantum, while having the ability to ask questions of the speaker in real time via the comment chat box on YouTube.',
|
||||
image: '/images/events/seminar-series/mosaic-interactivity.png'
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "~/assets/scss/blocks/copy.scss";
|
||||
</style>
|
|
@ -10,15 +10,15 @@
|
|||
<AppLink
|
||||
v-for="element in elements"
|
||||
:key="element.url"
|
||||
:class="
|
||||
iconsOnly
|
||||
? `footer-section__icon-link footer-section__icon-link_theme_${theme}`
|
||||
: `footer-section__link footer-section__link_theme_${theme}`
|
||||
"
|
||||
:class="`footer-section__link footer-section__link_theme_${theme}`"
|
||||
v-bind="element"
|
||||
kind="secondary"
|
||||
>
|
||||
<component :is="element.icon" v-if="iconsOnly" />
|
||||
<component
|
||||
:is="element.icon"
|
||||
v-if="iconsOnly"
|
||||
:class="`footer-section__icon-link footer-section__icon-link_theme_${theme}`"
|
||||
/>
|
||||
<span v-else>{{ element.label }}</span>
|
||||
</AppLink>
|
||||
</nav>
|
||||
|
|
|
@ -121,8 +121,6 @@ export default class TheMenu extends Mixins(MenuMixin) {
|
|||
@import '~carbon-components/scss/globals/scss/typography';
|
||||
|
||||
.menu {
|
||||
background-color: $white;
|
||||
|
||||
&__main-level {
|
||||
--link-color: #{$gray-80};
|
||||
}
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
<template>
|
||||
<CarefulExplanation v-bind="$attrs">
|
||||
<template #summary>
|
||||
<h2 class="copy__subtitle">
|
||||
A Carefully Worded Summary of Quantum Computing for Beginners
|
||||
</h2>
|
||||
<p class="copy__paragraph">
|
||||
Physics is an attempt to describe the behaviour of the world around us. Around the early 20th century, through delicate experiments in laboratories, physicists saw strange behaviours which could not be explained by their current understanding of physics. These discoveries led to the development of the more complete ‘quantum’ physics, which was able to describe this behaviour very successfully.
|
||||
</p>
|
||||
<AppDescriptionCard :title="title" :description="preliminaryDescription" />
|
||||
</template>
|
||||
<p class="copy__paragraph">
|
||||
Quantum physics explained behaviour previously thought impossible, and it was later discovered that this could be exploited to solve specific computational problems that were also previously thought impossible. Since this behaviour occurs only in delicate laboratory experiments, performing these new computations require delicate machines known as quantum computers. We are still learning how to build quantum computers, and it will be a while before they are large and stable enough to be useful, but progress is promising and the science is fascinating.
|
||||
|
@ -22,7 +17,10 @@ import Vue from 'vue'
|
|||
import { Component } from 'vue-property-decorator'
|
||||
|
||||
@Component
|
||||
export default class TheCarefulExplanationForBeginners extends Vue {}
|
||||
export default class TheCarefulExplanationForBeginners extends Vue {
|
||||
title = 'A Carefully Worded Summary of Quantum Computing for Beginners'
|
||||
preliminaryDescription = 'Physics is an attempt to describe the behaviour of the world around us. Around the early 20th century, through delicate experiments in laboratories, physicists saw strange behaviours which could not be explained by their current understanding of physics. These discoveries led to the development of the more complete ‘quantum’ physics, which was able to describe this behaviour very successfully.'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
<template>
|
||||
<CarefulExplanation v-bind="$attrs">
|
||||
<template #summary>
|
||||
<h2 class="copy__subtitle">
|
||||
A Carefully Worded Summary of Quantum Computing for Experts
|
||||
</h2>
|
||||
<p class="copy__paragraph">
|
||||
The ability to control and manipulate matter on an atomic scale was a dream first shared by Richard Feynman in his speech, “There’s Plenty of Room at the Bottom,” in 1959. By the 80’s, this idea really began to pick up speed, and a new subject called Quantum Computing had begun to emerge.
|
||||
</p>
|
||||
<AppDescriptionCard :title="title" :description="preliminaryDescription" />
|
||||
</template>
|
||||
<p class="copy__paragraph">
|
||||
In the 90’s, Peter Shor presented, for the first time, an algorithm that if run on a quantum processor, could provide a substantial speedup to the fundamental computational limits set by classical physics. The possibilities of a quantum computer, from being able to speed up algorithms, to their ability to more reliably simulate quantum systems themselves, was enough of an incentive for scientists and engineers across multiple disciplines to begin to dedicate their professional lives to this end goal.
|
||||
|
@ -28,5 +23,8 @@ import Vue from 'vue'
|
|||
import { Component } from 'vue-property-decorator'
|
||||
|
||||
@Component
|
||||
export default class TheCarefulExplanationForExperts extends Vue { }
|
||||
export default class TheCarefulExplanationForExperts extends Vue {
|
||||
title = 'A Carefully Worded Summary of Quantum Computing for Experts'
|
||||
preliminaryDescription = 'The ability to control and manipulate matter on an atomic scale was a dream first shared by Richard Feynman in his speech, “There’s Plenty of Room at the Bottom,” in 1959. By the 80’s, this idea really began to pick up speed, and a new subject called Quantum Computing had begun to emerge.'
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<template>
|
||||
<article class="app-card">
|
||||
<article
|
||||
class="app-card"
|
||||
:class="{'app-card_vertical': verticalLayout}"
|
||||
>
|
||||
<div
|
||||
class="app-card__image"
|
||||
:lazy-background="image"
|
||||
|
@ -23,6 +26,7 @@
|
|||
</div>
|
||||
<AppCta
|
||||
v-if="to"
|
||||
class="app-card__cta"
|
||||
v-bind="ctaLink"
|
||||
kind="ghost"
|
||||
/>
|
||||
|
@ -33,6 +37,7 @@
|
|||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import { Component, Prop } from 'vue-property-decorator'
|
||||
import { SegmentData } from '~/constants/appLinks'
|
||||
|
||||
@Component
|
||||
export default class AppCard extends Vue {
|
||||
|
@ -41,11 +46,14 @@ export default class AppCard extends Vue {
|
|||
@Prop({ type: Array, default: () => [] }) tags!: string[]
|
||||
@Prop({ type: String, default: '' }) to!: string
|
||||
@Prop({ type: String, default: '' }) ctaLabel!: string
|
||||
@Prop({ type: Object, required: false }) segment: SegmentData | undefined
|
||||
@Prop({ type: Boolean, default: false }) verticalLayout!: Boolean
|
||||
|
||||
get ctaLink () {
|
||||
return {
|
||||
url: this.to,
|
||||
label: this.ctaLabel
|
||||
label: this.ctaLabel,
|
||||
segment: this.segment
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,4 +147,35 @@ export default class AppCard extends Vue {
|
|||
margin-top: $layout-02;
|
||||
}
|
||||
}
|
||||
|
||||
.app-card_vertical {
|
||||
flex-direction: column;
|
||||
|
||||
.app-card {
|
||||
&__content {
|
||||
padding: $spacing-05;
|
||||
}
|
||||
|
||||
&__cta {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
&__description {
|
||||
margin-bottom: $spacing-03;
|
||||
margin-top: $spacing-03;
|
||||
}
|
||||
|
||||
&__image {
|
||||
min-height: 4 * $column-size-large;
|
||||
|
||||
@include mq($until: large) {
|
||||
min-height: 5 * $column-size-large;
|
||||
}
|
||||
|
||||
@include mq($from: small, $until: medium) {
|
||||
min-height: 6 * $column-size-large;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
<template>
|
||||
<article class="app-description-card">
|
||||
<div>
|
||||
<h2 class="copy__subtitle">
|
||||
{{ title }}
|
||||
</h2>
|
||||
<p class="copy__paragraph">
|
||||
{{ description }}
|
||||
</p>
|
||||
</div>
|
||||
<AppCta
|
||||
v-if="cta && cta.url"
|
||||
v-bind="cta"
|
||||
kind="ghost"
|
||||
class="app-description-card__cta"
|
||||
/>
|
||||
</article>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import { Component, Prop } from 'vue-property-decorator'
|
||||
import { GeneralLink } from '~/constants/appLinks'
|
||||
|
||||
export type DescriptionCard = {
|
||||
title: string,
|
||||
description: string,
|
||||
cta: GeneralLink
|
||||
}
|
||||
|
||||
@Component
|
||||
export default class AppDescriptionCard extends Vue {
|
||||
@Prop(String) title!: string
|
||||
@Prop(String) description!: string
|
||||
@Prop(Object) cta!: GeneralLink
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~/assets/scss/blocks/copy.scss';
|
||||
|
||||
.app-description-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
|
||||
&__cta {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -7,7 +7,10 @@
|
|||
class="app-mosaic__element"
|
||||
:class="`app-mosaic__element_${position}`"
|
||||
>
|
||||
<div class="app-mosaic__element-copy">
|
||||
<div
|
||||
class="app-mosaic__element-copy"
|
||||
:class="`app-mosaic__element-copy_${position}`"
|
||||
>
|
||||
<dt class="copy__subtitle">
|
||||
{{ title }}
|
||||
</dt>
|
||||
|
@ -32,7 +35,7 @@
|
|||
import Vue from 'vue'
|
||||
import { Component, Prop } from 'vue-property-decorator'
|
||||
|
||||
type MosaicElement = {
|
||||
export type MosaicElement = {
|
||||
position: string,
|
||||
title: string,
|
||||
description: string,
|
||||
|
@ -53,7 +56,8 @@ export default class AppMosaic extends Vue {
|
|||
&__layout {
|
||||
display: grid;
|
||||
gap: $spacing-07;
|
||||
grid-template-columns: 3fr 4fr 3fr;
|
||||
grid-template-columns: 2.5fr 4fr 3fr;
|
||||
grid-template-rows: 29.5rem 16rem;
|
||||
grid-template-areas:
|
||||
"a b c"
|
||||
"d d c"
|
||||
|
@ -61,8 +65,8 @@ export default class AppMosaic extends Vue {
|
|||
justify-items: stretch;
|
||||
|
||||
@include mq($from: medium, $until: large) {
|
||||
grid-template-columns: 2fr 3fr;
|
||||
grid-template-rows: repeat(3, minmax(10rem, auto));
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-rows: 26rem 13rem 12rem;
|
||||
grid-template-areas:
|
||||
"a b"
|
||||
"c c"
|
||||
|
@ -71,22 +75,24 @@ export default class AppMosaic extends Vue {
|
|||
}
|
||||
|
||||
@include mq($until: medium) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: repeat(4, minmax(18.75rem, auto));
|
||||
grid-template-areas:
|
||||
"a"
|
||||
"b"
|
||||
"c"
|
||||
"d"
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
&__element {
|
||||
background-color: $cool-gray-10;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@include mq($until: medium) {
|
||||
height: 18.75rem;
|
||||
}
|
||||
|
||||
&_first {
|
||||
grid-area: a;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&_second {
|
||||
|
@ -96,15 +102,13 @@ export default class AppMosaic extends Vue {
|
|||
|
||||
&_third {
|
||||
grid-area: c;
|
||||
flex-direction: column;
|
||||
|
||||
@include mq($from: medium, $until: large) {
|
||||
display: grid;
|
||||
grid-template-columns: 2fr 3fr;
|
||||
gap: $spacing-07;
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
@include mq($until: medium) {
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
}
|
||||
|
@ -131,40 +135,26 @@ export default class AppMosaic extends Vue {
|
|||
background-position: center top;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
min-height: 15rem;
|
||||
|
||||
@include mq($from: medium, $until: large) {
|
||||
min-height: 10rem;
|
||||
}
|
||||
|
||||
@include mq($until: medium) {
|
||||
min-height: 4rem;
|
||||
@include mq($until: large) {
|
||||
min-height: 12rem;
|
||||
}
|
||||
}
|
||||
|
||||
&_third {
|
||||
background-position: center bottom;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
height: 25rem;
|
||||
|
||||
@include mq($from: medium, $until: large) {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
@include mq($until: medium) {
|
||||
min-height: 4rem;
|
||||
min-height: 12rem;
|
||||
}
|
||||
}
|
||||
|
||||
&_fourth {
|
||||
background-position: right bottom;
|
||||
background-size: 12rem auto;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
@include mq($until: large) {
|
||||
background-size: 10rem auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,6 +165,10 @@ export default class AppMosaic extends Vue {
|
|||
padding: $spacing-05;
|
||||
}
|
||||
|
||||
&_fourth {
|
||||
flex: 1 0 0;
|
||||
}
|
||||
|
||||
&-description {
|
||||
@include type-style('body-long-01');
|
||||
color: $cool-gray-80;
|
||||
|
@ -187,14 +181,6 @@ export default class AppMosaic extends Vue {
|
|||
@include mq($until: medium) {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
&_fourth {
|
||||
padding-bottom: $spacing-09;
|
||||
|
||||
@include mq($until: medium) {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<template>
|
||||
<h1 class="app-page-header-title">
|
||||
<slot />
|
||||
</h1>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import { Component } from 'vue-property-decorator'
|
||||
|
||||
@Component
|
||||
export default class AppPageHeaderTitle extends Vue {}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~carbon-components/scss/globals/scss/typography';
|
||||
|
||||
.app-page-header-title {
|
||||
@include type-style('expressive-heading-05', true);
|
||||
color: $white-text-01;
|
||||
max-width: 10 * $column-size-large;
|
||||
|
||||
@include mq($from: medium, $until: large) {
|
||||
max-width: 6 * $column-size-medium;
|
||||
}
|
||||
|
||||
@include mq($until: medium) {
|
||||
max-width: 5 * $column-size-medium;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,9 +1,9 @@
|
|||
<template>
|
||||
<header class="page-header">
|
||||
<div class="page-header__container">
|
||||
<h1 class="page-header__title">
|
||||
<AppPageHeaderTitle>
|
||||
<slot />
|
||||
</h1>
|
||||
</AppPageHeaderTitle>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
@ -17,8 +17,6 @@ export default class ThePageHeader extends Vue {}
|
|||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~carbon-components/scss/globals/scss/typography';
|
||||
|
||||
.page-header {
|
||||
@include responsive-grid-bg-strip('/images/grid/grid-hero-learn.svg', auto, 28rem);
|
||||
min-height: 28rem;
|
||||
|
@ -38,19 +36,5 @@ export default class ThePageHeader extends Vue {}
|
|||
height: 28rem * 40 / 64;
|
||||
}
|
||||
}
|
||||
|
||||
&__title {
|
||||
@include type-style('expressive-heading-05', true);
|
||||
color: $white-text-01;
|
||||
max-width: 10 * $column-size-large;
|
||||
|
||||
@include mq($from: medium, $until: large) {
|
||||
max-width: 6 * $column-size-medium;
|
||||
}
|
||||
|
||||
@include mq($until: medium) {
|
||||
max-width: 5 * $column-size-medium;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -41,6 +41,24 @@ const YOUTUBE_ALL_EPISODES_CTA: GeneralLink = {
|
|||
label: 'View all episodes'
|
||||
}
|
||||
|
||||
const seminarSeriesPlaylistUrl = 'https://www.youtube.com/playlist?list=PLOFEBzvs-Vvr0uEoGFo08n4-WrM_8fft2'
|
||||
|
||||
const SEMINAR_SERIES_ALL_EPISODES_CTA: GeneralLink = {
|
||||
url: seminarSeriesPlaylistUrl,
|
||||
label: 'Go to YouTube playlist',
|
||||
segment: {
|
||||
action: 'seminar-series > header > youtube-playlist'
|
||||
}
|
||||
}
|
||||
|
||||
const SEMINAR_SERIES_FULL_ARCHIVE_CTA: GeneralLink = {
|
||||
url: seminarSeriesPlaylistUrl,
|
||||
label: 'Explore Full Seminar Archive',
|
||||
segment: {
|
||||
action: 'seminar-series > past-events-section > youtube-playlist'
|
||||
}
|
||||
}
|
||||
|
||||
const DISCOVER_TEXTBOOK_CTA: GeneralLink = {
|
||||
url: 'https://qiskit.org/textbook',
|
||||
label: 'Discover more'
|
||||
|
@ -57,11 +75,14 @@ const IBM_Q_EXPERIENCE: GeneralLink = {
|
|||
}
|
||||
|
||||
export {
|
||||
GeneralLink,
|
||||
SegmentData,
|
||||
ACCESS_IBM_Q_SYSTEMS,
|
||||
EVENT_REQUEST_LINK,
|
||||
YOUTUBE_ALL_EPISODES_CTA,
|
||||
DISCOVER_TEXTBOOK_CTA,
|
||||
REQUEST_AN_EVENT_CTA,
|
||||
SEMINAR_SERIES_ALL_EPISODES_CTA,
|
||||
SEMINAR_SERIES_FULL_ARCHIVE_CTA,
|
||||
IBM_Q_EXPERIENCE
|
||||
}
|
||||
|
|
|
@ -1,46 +1,24 @@
|
|||
[
|
||||
{
|
||||
"title": "Qiskit Community Summer Jam - Midwest ",
|
||||
"title": "Boson Sampling and Quantum Simulations in Circuit QED",
|
||||
"types": [
|
||||
"Hackathon"
|
||||
"Talks"
|
||||
],
|
||||
"image": "https://dl.airtable.com/.attachmentThumbnails/5fb60efc02b56ae0f4b336ef4f656682/382f1148",
|
||||
"location": "HackerEarth.com",
|
||||
"region": "Americas",
|
||||
"date": "June 24 - July 1, 2020",
|
||||
"to": "https://www.hackerearth.com/challenges/hackathon/qiskit-community-summer-jam-mid-west/"
|
||||
"image": "https://dl.airtable.com/.attachmentThumbnails/1e1b501e69679ad462f7634891255817/f394afe9",
|
||||
"location": "YouTube",
|
||||
"region": "Online",
|
||||
"date": "January 15, 2021",
|
||||
"to": "https://youtu.be/miK5y8BYlwQ"
|
||||
},
|
||||
{
|
||||
"title": "Qiskit Community Summer Jam - New England",
|
||||
"title": "Quantum Engineering of Superconducting Qubits | Seminar Series with Will Oliver",
|
||||
"types": [
|
||||
"Hackathon"
|
||||
"Talks"
|
||||
],
|
||||
"image": "https://dl.airtable.com/.attachmentThumbnails/5fb60efc02b56ae0f4b336ef4f656682/382f1148",
|
||||
"location": "HackerEarth.com",
|
||||
"region": "Americas",
|
||||
"date": "June 24 - July 1, 2020",
|
||||
"to": "https://qiskit-community-summer-jam-new-england.hackerearth.com/"
|
||||
},
|
||||
{
|
||||
"title": "Qiskit Community Summer Jam - California",
|
||||
"types": [
|
||||
"Hackathon"
|
||||
],
|
||||
"image": "https://dl.airtable.com/.attachmentThumbnails/5fb60efc02b56ae0f4b336ef4f656682/382f1148",
|
||||
"location": "HackerEarth.com",
|
||||
"region": "Americas",
|
||||
"date": "June 24 - July 1, 2020",
|
||||
"to": "https://www.hackerearth.com/challenges/hackathon/qiskit-community-summer-jam-california/"
|
||||
},
|
||||
{
|
||||
"title": "Qiskit Community Summer Jam - North Carolina",
|
||||
"types": [
|
||||
"Hackathon"
|
||||
],
|
||||
"image": "https://dl.airtable.com/.attachmentThumbnails/5fb60efc02b56ae0f4b336ef4f656682/382f1148",
|
||||
"location": "HackerEarth.com",
|
||||
"region": "Americas",
|
||||
"date": "June 24 - July 1, 2020",
|
||||
"to": "https://www.hackerearth.com/challenges/hackathon/qiskit-community-summer-jam-north-carolina/"
|
||||
"image": "https://dl.airtable.com/.attachmentThumbnails/f0daa554e731da5f87d13511546f3c77/6caa60ee",
|
||||
"location": "YouTube",
|
||||
"region": "Online",
|
||||
"date": "December 18, 2020",
|
||||
"to": "https://youtu.be/aGAb-GbrvMU"
|
||||
}
|
||||
]
|
|
@ -0,0 +1,11 @@
|
|||
[
|
||||
{
|
||||
"date": "January 15, 2021",
|
||||
"image": "https://dl.airtable.com/.attachmentThumbnails/1e1b501e69679ad462f7634891255817/f394afe9",
|
||||
"institution": "Yale University",
|
||||
"location": "YouTube",
|
||||
"speaker": "Steve Girvin\n\t",
|
||||
"title": "Boson Sampling and Quantum Simulations in Circuit QED",
|
||||
"to": "https://youtu.be/miK5y8BYlwQ"
|
||||
}
|
||||
]
|
|
@ -13,7 +13,7 @@ nav:
|
|||
goTo: '#code-of-conduct'
|
||||
routeName: events
|
||||
---
|
||||
|
||||
[//]: # "TODO: Remove this file once the new Seminar Series page is done."
|
||||
## What is the Quantum Information Science Seminar Series?
|
||||
The Quantum Information Science Seminar Series is a deep dive into various academic and research topics within the quantum community. This series is hosted by [Zlatko Minev, Ph.D.](https://twitter.com/zlatko_minev). **Subscribe to our YouTube channel and set a reminder to watch [Quantum Information Science Seminar Series](https://www.youtube.com/watch?v=7dfw8k2p1to&feature=youtu.be)**
|
||||
|
||||
|
|
|
@ -1,13 +1,64 @@
|
|||
[
|
||||
{
|
||||
"title": "Qiskit Global Summer School",
|
||||
"title": "What to do with a near-term quantum computer?",
|
||||
"types": [
|
||||
"Online"
|
||||
"Talks"
|
||||
],
|
||||
"image": "https://dl.airtable.com/.attachmentThumbnails/7de6fa69d8061d8f9e49e4505691338a/c067c96f",
|
||||
"location": "Online",
|
||||
"image": "https://dl.airtable.com/.attachmentThumbnails/49a702d8b04f71c43f0d4e08ac5cb1db/634f7076",
|
||||
"location": "YouTube",
|
||||
"region": "Online",
|
||||
"date": "July 20-30, 2020",
|
||||
"to": "https://qiskit.org/events/summer-school/"
|
||||
"date": "January 22, 2021",
|
||||
"to": "https://youtu.be/I6_tHLAeBsI"
|
||||
},
|
||||
{
|
||||
"title": "Compilation for Quantum Computing: Gap Analysis and Optimal Solution",
|
||||
"types": [
|
||||
"Talks"
|
||||
],
|
||||
"image": "https://dl.airtable.com/.attachmentThumbnails/b81d53d95b7a02f156dedfa6b00e5c7a/3c652699",
|
||||
"location": "YouTube",
|
||||
"region": "Online",
|
||||
"date": "January 29, 2021",
|
||||
"to": "https://youtu.be/Z9R9a3hku9Y"
|
||||
},
|
||||
{
|
||||
"title": "Qiskit Hackathon @ MIT",
|
||||
"types": [
|
||||
"Hackathon"
|
||||
],
|
||||
"image": "https://dl.airtable.com/.attachmentThumbnails/22ce9a8acb5781f8991d908fb7c247d2/b666a5e3",
|
||||
"location": "MIT",
|
||||
"region": "Americas",
|
||||
"date": "January 30-31, 2021"
|
||||
},
|
||||
{
|
||||
"title": "Qiskit Hackathon @ McMaster University",
|
||||
"types": [
|
||||
"Hackathon"
|
||||
],
|
||||
"image": "https://dl.airtable.com/.attachmentThumbnails/da755eac58a003a1ce054470b19bccf8/209a594e",
|
||||
"location": "McMaster University",
|
||||
"region": "Americas",
|
||||
"date": "February 5-7, 2021"
|
||||
},
|
||||
{
|
||||
"title": "Qiskit Hackathon @ NYU",
|
||||
"types": [
|
||||
"Hackathon"
|
||||
],
|
||||
"image": "https://dl.airtable.com/.attachmentThumbnails/61994381e16351e2a3c5f0e293390b59/9dae0f09",
|
||||
"location": "NYU",
|
||||
"region": "Americas",
|
||||
"date": "February 12-13, 2021"
|
||||
},
|
||||
{
|
||||
"title": "Qiskit Hackathon Korea",
|
||||
"types": [
|
||||
"Hackathon"
|
||||
],
|
||||
"image": "/images/events/no-picture.jpg",
|
||||
"location": "Korea",
|
||||
"region": "Asia Pacific",
|
||||
"date": "February 18-19, 2021"
|
||||
}
|
||||
]
|
|
@ -0,0 +1,20 @@
|
|||
[
|
||||
{
|
||||
"date": "January 22, 2021",
|
||||
"image": "https://dl.airtable.com/.attachmentThumbnails/49a702d8b04f71c43f0d4e08ac5cb1db/634f7076",
|
||||
"institution": "Harvard University",
|
||||
"location": "YouTube",
|
||||
"speaker": "Alán Aspuru-Guzik",
|
||||
"title": "What to do with a near-term quantum computer?",
|
||||
"to": "https://youtu.be/I6_tHLAeBsI"
|
||||
},
|
||||
{
|
||||
"date": "January 29, 2021",
|
||||
"image": "https://dl.airtable.com/.attachmentThumbnails/b81d53d95b7a02f156dedfa6b00e5c7a/3c652699",
|
||||
"institution": "UCLA",
|
||||
"location": "YouTube",
|
||||
"speaker": "Jason Cong",
|
||||
"title": "Compilation for Quantum Computing: Gap Analysis and Optimal Solution",
|
||||
"to": "https://youtu.be/Z9R9a3hku9Y"
|
||||
}
|
||||
]
|
|
@ -15,6 +15,16 @@ import {
|
|||
findImageAttachment
|
||||
} from './airtable-conversion-utils'
|
||||
|
||||
type SeminarSeriesEvent = {
|
||||
date: string,
|
||||
image: string,
|
||||
institution: string,
|
||||
location: string,
|
||||
speaker: string,
|
||||
title: string,
|
||||
to: string
|
||||
}
|
||||
|
||||
const RECORD_FIELDS = Object.freeze({
|
||||
name: 'Name',
|
||||
startDate: 'Start Date',
|
||||
|
@ -24,31 +34,61 @@ const RECORD_FIELDS = Object.freeze({
|
|||
location: 'Event Location',
|
||||
region: 'Region',
|
||||
image: 'Picture?',
|
||||
published: 'SUZIE - for website?'
|
||||
institution: 'Institution',
|
||||
showOnEventsPage: 'SUZIE - for website?',
|
||||
showOnSeminarSeriesPage: 'PAUL - Seminar Site',
|
||||
speaker: 'Speaker'
|
||||
} as const)
|
||||
|
||||
async function fetchCommunityEvents (apiKey: string, { days }: { days: any }): Promise<CommunityEvent[]> {
|
||||
const { startDate, published } = RECORD_FIELDS
|
||||
const communityEvents: CommunityEvent[] = []
|
||||
function getEventsQuery (apiKey: string, days: number, view: string, filters: string[] = []): Airtable.Query<{}> {
|
||||
const { startDate } = RECORD_FIELDS
|
||||
const base = new Airtable({ apiKey }).base('appkaaRF2QdwfusP1')
|
||||
await base('Events Main View').select({
|
||||
fields: Object.values(RECORD_FIELDS),
|
||||
filterByFormula: `AND(
|
||||
DATETIME_DIFF({${startDate}}, TODAY(), 'days') ${days > 0 ? '<=' : '>='} ${days},
|
||||
DATETIME_DIFF({${startDate}}, TODAY(), 'days') ${days > 0 ? '>=' : '<'} 0,
|
||||
{${published}}
|
||||
)`,
|
||||
sort: [{ field: startDate, direction: days > 0 ? 'asc' : 'desc' }]
|
||||
}).eachPage((records, nextPage) => {
|
||||
|
||||
const formulaFilters = [
|
||||
`DATETIME_DIFF({${startDate}}, TODAY(), 'days') ${days > 0 ? '<=' : '>='} ${days}`,
|
||||
`DATETIME_DIFF({${startDate}}, TODAY(), 'days') ${days > 0 ? '>=' : '<'} 0`,
|
||||
...filters
|
||||
]
|
||||
|
||||
const filterByFormula = `AND(${formulaFilters.join(',')})`
|
||||
|
||||
return base('Events Main View').select({
|
||||
filterByFormula,
|
||||
sort: [{ field: startDate, direction: days > 0 ? 'asc' : 'desc' }],
|
||||
view
|
||||
})
|
||||
}
|
||||
|
||||
async function fetchCommunityEvents (apiKey: string, { days }: { days: any }): Promise<CommunityEvent[]> {
|
||||
const { showOnEventsPage } = RECORD_FIELDS
|
||||
const communityEvents: CommunityEvent[] = []
|
||||
|
||||
await getEventsQuery(apiKey, days, 'Main List', [`{${showOnEventsPage}}`]).eachPage((records, nextPage) => {
|
||||
for (const record of records) {
|
||||
const communityEvent = convertToCommunityEvent(record)
|
||||
communityEvents.push(communityEvent)
|
||||
}
|
||||
nextPage()
|
||||
})
|
||||
|
||||
return Promise.resolve(communityEvents)
|
||||
}
|
||||
|
||||
async function fetchSeminarSeriesEvents (apiKey: string, { days }: { days: any }): Promise<SeminarSeriesEvent[]> {
|
||||
const { showOnSeminarSeriesPage } = RECORD_FIELDS
|
||||
const seminarSeriesEvents: SeminarSeriesEvent[] = []
|
||||
|
||||
await getEventsQuery(apiKey, days, 'Seminar Series Website', [`{${showOnSeminarSeriesPage}}`]).eachPage((records, nextPage) => {
|
||||
for (const record of records) {
|
||||
const seminarSeriesEvent = convertToSeminarSeriesEvent(record)
|
||||
seminarSeriesEvents.push(seminarSeriesEvent)
|
||||
}
|
||||
nextPage()
|
||||
})
|
||||
|
||||
return Promise.resolve(seminarSeriesEvents)
|
||||
}
|
||||
|
||||
function convertToCommunityEvent (record: any): CommunityEvent {
|
||||
return {
|
||||
title: getName(record),
|
||||
|
@ -61,10 +101,30 @@ function convertToCommunityEvent (record: any): CommunityEvent {
|
|||
}
|
||||
}
|
||||
|
||||
function convertToSeminarSeriesEvent (record: any): SeminarSeriesEvent {
|
||||
return {
|
||||
date: formatDates(...getDates(record)),
|
||||
image: getImage(record),
|
||||
institution: getInstitution(record),
|
||||
location: getLocation(record),
|
||||
speaker: getSpeaker(record),
|
||||
title: getName(record),
|
||||
to: getWebsite(record)
|
||||
}
|
||||
}
|
||||
|
||||
function getInstitution (record: any): string {
|
||||
return record.get(RECORD_FIELDS.institution)
|
||||
}
|
||||
|
||||
function getName (record: any): string {
|
||||
return record.get(RECORD_FIELDS.name)
|
||||
}
|
||||
|
||||
function getSpeaker (record: any): string {
|
||||
return record.get(RECORD_FIELDS.speaker)
|
||||
}
|
||||
|
||||
function getTypes (record: any): CommunityEventType[] {
|
||||
const value = record.get(RECORD_FIELDS.typeOfEvent) || []
|
||||
const valueList = (Array.isArray(value) ? value : [value]) as string[]
|
||||
|
@ -137,6 +197,7 @@ function getWebsite (record: any): string {
|
|||
export {
|
||||
RECORD_FIELDS,
|
||||
fetchCommunityEvents,
|
||||
fetchSeminarSeriesEvents,
|
||||
convertToCommunityEvent,
|
||||
getName,
|
||||
getTypes,
|
||||
|
@ -146,5 +207,6 @@ export {
|
|||
getWebsite,
|
||||
getDates,
|
||||
formatDates,
|
||||
filterWithWhitelist
|
||||
filterWithWhitelist,
|
||||
SeminarSeriesEvent
|
||||
}
|
||||
|
|
|
@ -1,15 +1,23 @@
|
|||
import fs from 'fs'
|
||||
import util from 'util'
|
||||
|
||||
import { fetchCommunityEvents } from './event-conversion-utils'
|
||||
import { fetchCommunityEvents, fetchSeminarSeriesEvents } from './event-conversion-utils'
|
||||
|
||||
export default async function (apiKey: any, outputFolder: string) {
|
||||
const upcomingCommunityEvents = await fetchCommunityEvents(apiKey, { days: 31 })
|
||||
const pastCommunityEvents = await fetchCommunityEvents(apiKey, { days: -31 })
|
||||
|
||||
const writeFile = util.promisify(fs.writeFile)
|
||||
const writeUpcomingEvents = writeFile(`${outputFolder}/upcoming-community-events.json`, JSON.stringify(upcomingCommunityEvents, null, 2))
|
||||
const writePastEvents = writeFile(`${outputFolder}/past-community-events.json`, JSON.stringify(pastCommunityEvents, null, 2))
|
||||
const upcomingSeminarSeriesEvents = await fetchSeminarSeriesEvents(apiKey, { days: 31 })
|
||||
const pastSeminarSeriesEvents = await fetchSeminarSeriesEvents(apiKey, { days: -62 })
|
||||
|
||||
await Promise.all([writeUpcomingEvents, writePastEvents])
|
||||
const writeFile = util.promisify(fs.writeFile)
|
||||
|
||||
const eventsAndOutputFilename = [
|
||||
{ events: upcomingCommunityEvents, outputFilename: 'upcoming-community-events.json' },
|
||||
{ events: pastCommunityEvents, outputFilename: 'past-community-events.json' },
|
||||
{ events: upcomingSeminarSeriesEvents, outputFilename: 'upcoming-seminar-series-events.json' },
|
||||
{ events: pastSeminarSeriesEvents, outputFilename: 'past-seminar-series-events.json' }
|
||||
]
|
||||
|
||||
await Promise.all(eventsAndOutputFilename.map(curr => writeFile(`${outputFolder}/${curr.outputFilename}`, JSON.stringify(curr.events, null, 2))))
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<!-- tabindex is needed to allow hiding the menu in iOS Safari -->
|
||||
<div class="default-layout content-root_theme_dark" tabindex="-1">
|
||||
<div class="default-layout content-root_theme_light" tabindex="-1">
|
||||
<header id="navigation">
|
||||
<TheMenu @change-visibility="isMenuShown = $event === 'shown'" />
|
||||
</header>
|
||||
|
|
|
@ -32,9 +32,3 @@ export default class AdvocatesPage extends QiskitPage {
|
|||
routeName: string = 'advocates'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.advocates-page {
|
||||
background-color: $white;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -184,7 +184,6 @@ export default class EventsPage extends QiskitPage {
|
|||
@import '~carbon-components/scss/globals/scss/typography';
|
||||
|
||||
.event-page {
|
||||
background-color: $white;
|
||||
color: $white-text-01;
|
||||
|
||||
&__container {
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
<template>
|
||||
<main class="event-page seminar-series-page">
|
||||
<SeminarSeriesHeader class="seminar-series-page__header" :next-event="nextEvent" :past-events="pastEvents" />
|
||||
<WhatIsThisEventSection class="seminar-series-page__section" />
|
||||
<UpcomingSeminarSeriesSection v-if="hasUpcomingEvents" :events="upcomingEvents" class="seminar-series-page__section" />
|
||||
<PastSeminarSeriesSection class="seminar-series-page__section" :events="pastEvents" />
|
||||
<HelpfulResourcesSection class="seminar-series-page__section" :resources="helpfulResources" />
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component } from 'vue-property-decorator'
|
||||
import QiskitPage from '~/components/logic/QiskitPage.vue'
|
||||
import { DescriptionCard } from '~/components/ui/AppDescriptionCard.vue'
|
||||
import pastSeminarSeriesEvents from '~/content/events/past-seminar-series-events.json'
|
||||
import upcomingSeminarSerieEvents from '~/content/events/upcoming-seminar-series-events.json'
|
||||
|
||||
@Component({
|
||||
head () {
|
||||
return {
|
||||
title: 'Qiskit Seminar Series'
|
||||
}
|
||||
}
|
||||
})
|
||||
export default class SeminarSeriesPage extends QiskitPage {
|
||||
routeName = 'seminar-series'
|
||||
// Assign the imported variable to a local one to be able to use it on the template
|
||||
upcomingEvents = upcomingSeminarSerieEvents
|
||||
pastEvents = pastSeminarSeriesEvents
|
||||
// When there are no upcoming events, the JSON file is filled with []
|
||||
hasUpcomingEvents = JSON.stringify(this.upcomingEvents) !== '[]'
|
||||
nextEvent = this.hasUpcomingEvents ? this.upcomingEvents[0] : null
|
||||
|
||||
helpfulResources: DescriptionCard[] = [
|
||||
{
|
||||
title: 'Stay informed',
|
||||
description: 'Want to keep up to date with upcoming seminars? Click here to subscribe to our calendar for all upcoming events.',
|
||||
cta: {
|
||||
url: 'https://calendar.google.com/calendar/ical/c12g9fqo0mkvp9bo26dhm3u1rs%40group.calendar.google.com/public/basic.ics',
|
||||
label: 'Get calendar updates',
|
||||
segment: {
|
||||
action: `${this.routeName} > helpful-resources > get-calendar`
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Nominate',
|
||||
description: 'If you or someone you know might be interested in speaking in a future seminar, we would love to include them. Please include your name, topic and available dates.',
|
||||
cta: {
|
||||
url: 'https://airtable.com/shrB5wy8SCaMMtKop',
|
||||
label: 'Contact us',
|
||||
segment: {
|
||||
action: `${this.routeName} > helpful-resources > contact`
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Get up to speed',
|
||||
description: 'If the content of the seminar series is too dense or technical, we have a host of content to help you get up to speed.',
|
||||
cta: {
|
||||
url: 'https://qiskit.org/learn',
|
||||
label: 'Start learning',
|
||||
segment: {
|
||||
action: `${this.routeName} > helpful-resources > qiskit-org-learn`
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Code of conduct',
|
||||
description: 'Qiskit is dedicated to providing an enjoyable and safe experience for all participants. We have a code of conduct that all events adhere to.',
|
||||
cta: {
|
||||
url: 'https://github.com/Qiskit/qiskit/blob/master/CODE_OF_CONDUCT.md',
|
||||
label: 'See code of conduct',
|
||||
segment: {
|
||||
action: `${this.routeName} > helpful-resources > code-of-conduct`
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.seminar-series-page {
|
||||
color: $white-text-01;
|
||||
|
||||
&__header {
|
||||
padding-top: $layout-06;
|
||||
|
||||
@include mq($until: medium) {
|
||||
padding-top: $layout-04;
|
||||
}
|
||||
}
|
||||
|
||||
&__section {
|
||||
@include contained();
|
||||
margin-top: $layout-05;
|
||||
margin-bottom: $layout-03;
|
||||
|
||||
@include mq($until: large) {
|
||||
margin-bottom: $layout-01;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -32,8 +32,4 @@ export default class LandingPage extends QiskitPage {
|
|||
|
||||
<style lang="scss">
|
||||
@import '~/assets/scss/blocks/copy.scss';
|
||||
|
||||
.landing-page {
|
||||
background-color: white;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -43,8 +43,6 @@ export default class LearnEntry extends QiskitPage {
|
|||
@import '~carbon-components/scss/globals/scss/typography';
|
||||
|
||||
.learn-entry {
|
||||
background-color: white;
|
||||
|
||||
&__header {
|
||||
@include responsive-grid-bg-strip('/images/grid/grid-hero-learn.svg', auto, 28rem);
|
||||
min-height: 28rem;
|
||||
|
|
|
@ -139,9 +139,3 @@ export default class LearnPage extends QiskitPage {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.learn-page {
|
||||
background-color: white;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -96,8 +96,6 @@ export default class OverviewPage extends QiskitPage {
|
|||
@import '~/assets/scss/blocks/copy.scss';
|
||||
|
||||
.overview-page {
|
||||
background-color: white;
|
||||
|
||||
&__content-container {
|
||||
@include contained();
|
||||
display: flex;
|
||||
|
|
|
@ -3,6 +3,7 @@ import CarbonComponentsVue from '@carbon/vue'
|
|||
import '~/assets/scss/carbon/components.scss'
|
||||
import { CarbonIconsVue } from '@carbon/icons-vue'
|
||||
import Calendar20 from '@carbon/icons-vue/lib/calendar/20'
|
||||
import Education20 from '@carbon/icons-vue/lib/education/20'
|
||||
import Map20 from '@carbon/icons-vue/lib/map/20'
|
||||
import ArrowRight20 from '@carbon/icons-vue/lib/arrow--right/20'
|
||||
import ArrowRight16 from '@carbon/icons-vue/lib/arrow--right/16'
|
||||
|
@ -21,6 +22,7 @@ Vue.use(CarbonComponentsVue)
|
|||
Vue.use(CarbonIconsVue, {
|
||||
components: {
|
||||
Calendar20,
|
||||
Education20,
|
||||
Map20,
|
||||
ArrowRight20,
|
||||
ArrowRight16,
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 50 KiB |
Binary file not shown.
After Width: | Height: | Size: 670 KiB |
Binary file not shown.
After Width: | Height: | Size: 46 KiB |
Binary file not shown.
After Width: | Height: | Size: 797 KiB |
Loading…
Reference in New Issue