feat: add episode channels

This commit is contained in:
jinhojang6 2023-08-16 22:30:17 +09:00
parent af8b026b6e
commit 5a0d79462e
11 changed files with 442 additions and 281 deletions

View File

@ -0,0 +1,67 @@
import { Typography } from '@acid-info/lsd-react'
import styled from '@emotion/styled'
import { LPE } from '../../../types/lpe.types'
import { ApplePodcastsIcon } from '@/components/Icons/ApplePodcastsIcon'
import { GooglePodcastsIcon } from '@/components/Icons/GooglePodcastsIcon'
import { SpotifyIcon } from '@/components/Icons/SpotifyIcon'
import Link from 'next/link'
export type EpisodeChannelProps = {
channels: LPE.Podcast.Channel[]
}
const renderChannel = (channel: LPE.Podcast.Channel) => {
switch (channel.name) {
case LPE.Podcast.ChannelNames.Spotify:
return (
<Channel href={channel.url} target="_blank">
<SpotifyIcon width={16} height={16} />
<Typography variant="body2">Spotify</Typography>
</Channel>
)
case LPE.Podcast.ChannelNames.ApplePodcasts:
return (
<Channel href={channel.url} target="_blank">
<ApplePodcastsIcon width={16} height={16} />
<Typography variant="body2">Apple Podcasts</Typography>
</Channel>
)
case LPE.Podcast.ChannelNames.GooglePodcasts:
return (
<Channel href={channel.url} target="_blank">
<GooglePodcastsIcon width={16} height={16} />
<Typography variant="body2">Google Podcasts</Typography>
</Channel>
)
default:
return null
}
}
const EpisodeChannels = ({ channels }: EpisodeChannelProps) => {
return (
<EpisodeChannelContainer>
{channels.map((channel, idx) => renderChannel(channel))}
</EpisodeChannelContainer>
)
}
const EpisodeChannelContainer = styled.header`
display: flex;
gap: 24px;
align-items: center;
margin-top: 32px;
@media (max-width: 768px) {
padding-top: 32px;
}
`
const Channel = styled(Link)`
display: flex;
align-items: center;
gap: 8px;
text-decoration: none;
`
export default EpisodeChannels

View File

@ -7,6 +7,7 @@ import { default as Stats } from '@/components/Article/Article.Stats'
import { LogosCircleIcon } from '@/components/Icons/LogosCircleIcon' import { LogosCircleIcon } from '@/components/Icons/LogosCircleIcon'
import { useHookstate } from '@hookstate/core' import { useHookstate } from '@hookstate/core'
import { playerState } from '@/components/GlobalAudioPlayer/globalAudioPlayer.state' import { playerState } from '@/components/GlobalAudioPlayer/globalAudioPlayer.state'
import EpisodeChannels from './Episode.Channels'
export type EpisodeHeaderProps = LPE.Podcast.Document & { export type EpisodeHeaderProps = LPE.Podcast.Document & {
url: string url: string
@ -18,6 +19,7 @@ const EpisodeHeader = ({
description, description,
publishedAt, publishedAt,
tags, tags,
channels,
url, url,
readingTime, readingTime,
}: EpisodeHeaderProps) => { }: EpisodeHeaderProps) => {
@ -55,6 +57,7 @@ const EpisodeHeader = ({
Network State Podcast Network State Podcast
</PodcastName> </PodcastName>
{tags && <Tags tags={tags} />} {tags && <Tags tags={tags} />}
{channels && <EpisodeChannels channels={channels} />}
{description && ( {description && (
<EpisodeSubtitle <EpisodeSubtitle
variant="h6" variant="h6"

View File

@ -11,9 +11,7 @@ import { getAudioSourceFromEpisode } from '@/utils/data.utils'
import Image from 'next/image' import Image from 'next/image'
import { playerState } from './globalAudioPlayer.state' import { playerState } from './globalAudioPlayer.state'
import { useHookstate } from '@hookstate/core' import { useHookstate } from '@hookstate/core'
import { episodeState } from './episode.state'
// Hasing it out episodes: https://api.simplecast.com/podcasts/b54c0885-7c72-415d-b032-7d294b78d785/episodes?preview=true
const TEMP_EPISODE_ID = '30d4e2f5-4434-419c-8fc1-a76e4b367e20'
type EpisodeProps = { type EpisodeProps = {
title: string title: string
@ -24,8 +22,8 @@ type EpisodeProps = {
export default function GlobalAudioPlayer() { export default function GlobalAudioPlayer() {
const state = useHookstate(playerState) const state = useHookstate(playerState)
const epState = useHookstate(episodeState)
const episodeId = ''
const ref = useRef<ReactPlayer>(null) const ref = useRef<ReactPlayer>(null)
const [episode, setEpisode] = useState<EpisodeProps>({ const [episode, setEpisode] = useState<EpisodeProps>({
title: '', title: '',
@ -36,7 +34,7 @@ export default function GlobalAudioPlayer() {
useMemo(() => { useMemo(() => {
const getAudioSource = async () => { const getAudioSource = async () => {
const response = await getAudioSourceFromEpisode(TEMP_EPISODE_ID) const response = await getAudioSourceFromEpisode(epState.value.episodeId)
setEpisode({ setEpisode({
title: response.title, title: response.title,
@ -47,7 +45,7 @@ export default function GlobalAudioPlayer() {
} }
getAudioSource() getAudioSource()
}, [episodeId]) }, [epState])
const [showVolume, setShowVolume] = useState(false) const [showVolume, setShowVolume] = useState(false)

View File

@ -0,0 +1,17 @@
import { hookstate } from '@hookstate/core'
// Hasing it out episodes: https://api.simplecast.com/podcasts/b54c0885-7c72-415d-b032-7d294b78d785/episodes?preview=true
const TEMP_EPISODE_ID = '30d4e2f5-4434-419c-8fc1-a76e4b367e20'
export type EpisodeState = {
episodeId: string
}
export const defaultEpisodeState: EpisodeState = {
episodeId: TEMP_EPISODE_ID,
}
export const episodeState =
typeof window === 'undefined'
? hookstate(defaultEpisodeState)
: hookstate<EpisodeState>(defaultEpisodeState)

View File

@ -0,0 +1,27 @@
import { LsdIcon } from '@acid-info/lsd-react'
export const ApplePodcastsIcon = LsdIcon(
(props) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
fill="none"
viewBox="0 0 16 16"
{...props}
>
<g clipPath="url(#clip0_541_16016)">
<path
fill="#000"
d="M3.56 0A3.552 3.552 0 000 3.56v8.88A3.552 3.552 0 003.56 16h8.88A3.552 3.552 0 0016 12.44V3.56A3.552 3.552 0 0012.44 0H3.56zm4.35 1.712a5.48 5.48 0 014.037 1.725c.816.848 1.275 1.746 1.51 2.928.08.393.08 1.466.004 1.909a5.67 5.67 0 01-2.16 3.53c-.405.307-1.397.841-1.557.841-.059 0-.064-.06-.037-.306.048-.395.096-.477.32-.571.357-.15.965-.583 1.338-.957a5.096 5.096 0 001.339-2.357c.139-.55.123-1.77-.032-2.336-.485-1.797-1.952-3.195-3.75-3.568-.522-.107-1.471-.107-2 0-1.818.373-3.322 1.84-3.78 3.685-.123.502-.123 1.723 0 2.224.303 1.222 1.093 2.342 2.127 3.008.203.134.448.272.55.315.224.096.272.176.314.57.027.24.02.31-.037.31-.037 0-.31-.117-.597-.256l-.027-.02c-1.648-.81-2.704-2.183-3.088-4.008-.096-.47-.112-1.595-.02-2.027.24-1.16.699-2.066 1.461-2.869 1.099-1.158 2.512-1.77 4.086-1.77H7.91zM8 3.585c.272.003.535.027.737.071 1.856.413 3.173 2.272 2.917 4.116a3.76 3.76 0 01-.81 1.92c-.225.287-.769.767-.865.767-.015 0-.032-.182-.032-.402v-.404l.278-.33c1.045-1.252.97-3.002-.171-4.15-.443-.446-.955-.709-1.616-.83-.427-.079-.517-.079-.965-.006-.68.112-1.207.375-1.675.838-1.147 1.136-1.221 2.894-.176 4.148l.275.33v.406c0 .224-.018.405-.04.405-.02 0-.176-.107-.341-.24l-.023-.007c-.554-.443-1.045-1.228-1.248-1.998-.122-.466-.122-1.35.006-1.814.336-1.252 1.258-2.223 2.538-2.679.274-.097.756-.147 1.21-.14zM7.912 5.58c.206 0 .413.04.562.118.332.18.58.48.694.84.309 1.052-.806 1.973-1.814 1.502h-.01c-.474-.22-.73-.637-.736-1.18 0-.488.272-.914.742-1.163a1.26 1.26 0 01.562-.117zM7.905 8.73c.659-.003 1.138.232 1.314.646.132.31.082 1.288-.146 2.868-.154 1.104-.24 1.383-.453 1.571-.293.26-.71.332-1.104.192h-.002c-.477-.171-.58-.403-.776-1.763-.227-1.58-.277-2.558-.145-2.868.174-.41.649-.644 1.313-.646z"
></path>
</g>
<defs>
<clipPath id="clip0_541_16016">
<path fill="#fff" d="M0 0H16V16H0z"></path>
</clipPath>
</defs>
</svg>
),
{ filled: true },
)

View File

@ -0,0 +1 @@
export * from './ApplePodcastsIcon'

View File

@ -0,0 +1,27 @@
import { LsdIcon } from '@acid-info/lsd-react'
export const GooglePodcastsIcon = LsdIcon(
(props) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
fill="none"
viewBox="0 0 16 16"
{...props}
>
<g clipPath="url(#clip0_541_16028)">
<path
fill="#000"
d="M1.001 6.452c-.553 0-1 .447-1 1v1.087a1 1 0 002 0V7.452c0-.553-.446-1-1-1zm13.996 0c-.553 0-1 .447-1 1v1.087a1 1 0 002 0V7.452c0-.553-.446-1-1-1zM4.453 9.725c-.554 0-1 .446-1 1v1.086a1 1 0 102 0v-1.08c0-.553-.447-1-1-1v-.006zm0-6.545c-.554 0-1 .447-1 1v3.571a1 1 0 102 0V4.172c0-.553-.447-1-1-1v.008zm7.092 0c-.554 0-1 .447-1 1v1.093a1 1 0 002 0V4.18c0-.553-.447-1-1-1zM7.999 0c-.553 0-1 .447-1 1v1.087a1 1 0 002 0V1c0-.553-.446-1-1-1zm0 12.903c-.553 0-1 .447-1 1v1.094a1 1 0 002 .006V13.91c0-.547-.446-1-1-1v-.007zm3.546-5.638c-.553 0-1 .454-1 1v3.552a1 1 0 102 0V8.265c0-.554-.446-1-1-1zM8 4.085c-.553 0-1 .454-1 1v5.819a1 1 0 102 0V5.092c0-.553-.446-1-1-1v-.007z"
></path>
</g>
<defs>
<clipPath id="clip0_541_16028">
<path fill="#fff" d="M0 0H16V16H0z"></path>
</clipPath>
</defs>
</svg>
),
{ filled: true },
)

View File

@ -0,0 +1 @@
export * from './GooglePodcastsIcon'

View File

@ -0,0 +1,27 @@
import { LsdIcon } from '@acid-info/lsd-react'
export const SpotifyIcon = LsdIcon(
(props) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
fill="none"
viewBox="0 0 16 16"
{...props}
>
<g clipPath="url(#clip0_541_16022)">
<path
fill="#000"
d="M8 0a8 8 0 100 16A8 8 0 008 0zm3.669 11.538a.498.498 0 01-.686.166c-1.879-1.148-4.243-1.408-7.028-.771a.499.499 0 01-.222-.973c3.048-.696 5.662-.396 7.77.892.235.145.31.451.166.686zm.979-2.178a.624.624 0 01-.858.206C9.64 8.244 6.362 7.86 3.818 8.633a.625.625 0 01-.362-1.193c2.905-.882 6.517-.455 8.987 1.063.293.18.385.564.205.857zm.084-2.268C10.154 5.56 5.9 5.419 3.438 6.167a.748.748 0 11-.434-1.432c2.825-.858 7.523-.692 10.492 1.07a.747.747 0 11-.764 1.287z"
></path>
</g>
<defs>
<clipPath id="clip0_541_16022">
<path fill="#fff" d="M0 0H16V16H0z"></path>
</clipPath>
</defs>
</svg>
),
{ filled: true },
)

View File

@ -0,0 +1 @@
export * from './SpotifyIcon'

View File

@ -19,9 +19,7 @@
"type": "text", "type": "text",
"html": "<p class=\"c1\"><span class=\"c0\">Episode hosts - Annie McEwen and Molly Webster</span></p>", "html": "<p class=\"c1\"><span class=\"c0\">Episode hosts - Annie McEwen and Molly Webster</span></p>",
"text": "Episode hosts - Annie McEwen and Molly Webster", "text": "Episode hosts - Annie McEwen and Molly Webster",
"classNames": [ "classNames": ["c1"],
"c1"
],
"footnotes": [], "footnotes": [],
"order": 9, "order": 9,
"tagName": "p", "tagName": "p",
@ -32,9 +30,7 @@
"type": "text", "type": "text",
"html": "<p class=\"c1\"><span class=\"c0\">Produced by - Annie McEwen and Becca Bressler </span></p>", "html": "<p class=\"c1\"><span class=\"c0\">Produced by - Annie McEwen and Becca Bressler </span></p>",
"text": "Produced by - Annie McEwen and Becca Bressler ", "text": "Produced by - Annie McEwen and Becca Bressler ",
"classNames": [ "classNames": ["c1"],
"c1"
],
"footnotes": [], "footnotes": [],
"order": 10, "order": 10,
"tagName": "p", "tagName": "p",
@ -45,9 +41,7 @@
"type": "text", "type": "text",
"html": "<p class=\"c1\"><span class=\"c0\">With help from - Matt Kielty</span></p>", "html": "<p class=\"c1\"><span class=\"c0\">With help from - Matt Kielty</span></p>",
"text": "With help from - Matt Kielty", "text": "With help from - Matt Kielty",
"classNames": [ "classNames": ["c1"],
"c1"
],
"footnotes": [], "footnotes": [],
"order": 11, "order": 11,
"tagName": "p", "tagName": "p",
@ -58,9 +52,7 @@
"type": "text", "type": "text",
"html": "<p class=\"c1\"><span class=\"c0\">Original music and sound design contributed by - Jeremy Bloom, Annie McEwen, Matt Kielty</span></p>", "html": "<p class=\"c1\"><span class=\"c0\">Original music and sound design contributed by - Jeremy Bloom, Annie McEwen, Matt Kielty</span></p>",
"text": "Original music and sound design contributed by - Jeremy Bloom, Annie McEwen, Matt Kielty", "text": "Original music and sound design contributed by - Jeremy Bloom, Annie McEwen, Matt Kielty",
"classNames": [ "classNames": ["c1"],
"c1"
],
"footnotes": [], "footnotes": [],
"order": 12, "order": 12,
"tagName": "p", "tagName": "p",
@ -71,9 +63,7 @@
"type": "text", "type": "text",
"html": "<p class=\"c1\"><span class=\"c0\">Mixing by - Jeremy Bloom</span></p>", "html": "<p class=\"c1\"><span class=\"c0\">Mixing by - Jeremy Bloom</span></p>",
"text": "Mixing by - Jeremy Bloom", "text": "Mixing by - Jeremy Bloom",
"classNames": [ "classNames": ["c1"],
"c1"
],
"footnotes": [], "footnotes": [],
"order": 13, "order": 13,
"tagName": "p", "tagName": "p",
@ -84,9 +74,7 @@
"type": "text", "type": "text",
"html": "<p class=\"c1\"><span class=\"c0\">With dialogue mixing by - Arianne Wack </span></p>", "html": "<p class=\"c1\"><span class=\"c0\">With dialogue mixing by - Arianne Wack </span></p>",
"text": "With dialogue mixing by - Arianne Wack ", "text": "With dialogue mixing by - Arianne Wack ",
"classNames": [ "classNames": ["c1"],
"c1"
],
"footnotes": [], "footnotes": [],
"order": 14, "order": 14,
"tagName": "p", "tagName": "p",
@ -97,9 +85,7 @@
"type": "text", "type": "text",
"html": "<p class=\"c1\"><span class=\"c0\">Fact-checking by - Diane Kelly</span></p>", "html": "<p class=\"c1\"><span class=\"c0\">Fact-checking by - Diane Kelly</span></p>",
"text": "Fact-checking by - Diane Kelly", "text": "Fact-checking by - Diane Kelly",
"classNames": [ "classNames": ["c1"],
"c1"
],
"footnotes": [], "footnotes": [],
"order": 15, "order": 15,
"tagName": "p", "tagName": "p",
@ -110,9 +96,7 @@
"type": "text", "type": "text",
"html": "<p class=\"c1\"><span class=\"c0\">And edited by - Alex Neason</span></p>", "html": "<p class=\"c1\"><span class=\"c0\">And edited by - Alex Neason</span></p>",
"text": "And edited by - Alex Neason", "text": "And edited by - Alex Neason",
"classNames": [ "classNames": ["c1"],
"c1"
],
"footnotes": [], "footnotes": [],
"order": 16, "order": 16,
"tagName": "p", "tagName": "p",
@ -235,8 +219,16 @@
"url": "https://www.youtube.com/watch?v=vmx_oOb2On0" "url": "https://www.youtube.com/watch?v=vmx_oOb2On0"
}, },
{ {
"name": "youtube", "name": "apple_podcasts",
"url": "https://www.youtube.com/watch?v=vmx_oOb2On0" "url": "https://podcasts.apple.com/us/podcast/franck-royer-decentralized-messaging/id1376906132?i=1000618673846"
},
{
"name": "spotify",
"url": "https://open.spotify.com/show/3WkYBYaZ4W1Z8gzBlOvr7y"
},
{
"name": "google_podcasts",
"url": "https://podcasts.google.com/feed/aHR0cHM6Ly9mZWVkcy5zaW1wbGVjYXN0LmNvbS9xd0d2bGoyag/episode/OGQ5ZmE0NzgtMGUxNy00YWIzLTk1NzgtYTNiYTEyMjMwY2Jm?sa=X&ved=0CAUQkfYCahcKEwiwz7SVoeGAAxUAAAAAHQAAAAAQNQ"
} }
], ],
"coverImage": { "coverImage": {