mirror of
https://github.com/acid-info/logos-press-engine.git
synced 2025-02-23 22:58:08 +00:00
Merge pull request #133 from acid-info/refactor-components
Refactor components
This commit is contained in:
commit
e300dc926f
@ -43,9 +43,12 @@ export const RenderArticleBlock = ({
|
||||
|
||||
return block.embed && isIframe ? (
|
||||
block.labels.includes('youtube_embed') ? (
|
||||
<ReactPlayer url={block.embed.src} />
|
||||
<IframeContainer isSimplecast={false}>
|
||||
<ReactPlayer url={block.embed.src} />
|
||||
</IframeContainer>
|
||||
) : (
|
||||
<IframeContainer
|
||||
isSimplecast={true}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: block.embed.html,
|
||||
}}
|
||||
@ -91,9 +94,9 @@ const Paragraph = styled(Typography)`
|
||||
}
|
||||
`
|
||||
|
||||
const IframeContainer = styled.div`
|
||||
const IframeContainer = styled.div<{ isSimplecast?: boolean }>`
|
||||
position: relative;
|
||||
padding-bottom: 56.25%;
|
||||
padding-bottom: ${({ isSimplecast }) => (isSimplecast ? '30%' : '60%')};
|
||||
padding-top: 30px;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
@ -107,4 +110,10 @@ const IframeContainer = styled.div`
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
& > div {
|
||||
width: 100% !important;
|
||||
height: unset !important;
|
||||
aspect-ratio: 16 / 9;
|
||||
}
|
||||
`
|
||||
|
@ -9,6 +9,7 @@ import { LPE } from '../../../types/lpe.types'
|
||||
import { ArticleImageBlockWrapper } from '../Article.ImageBlockWrapper'
|
||||
import ArticleStats from '../Article.Stats'
|
||||
import ArticleSummary from './Article.Summary'
|
||||
import { TagsAndSocial } from '@/components/TagsAndSocial'
|
||||
|
||||
export type ArticleHeaderProps = LPE.Article.Data
|
||||
|
||||
@ -53,7 +54,7 @@ const ArticleHeader = ({
|
||||
{subtitle}
|
||||
</ArticleSubtitle>
|
||||
)}
|
||||
<Tags tags={tags} className={'articleTags'} />
|
||||
<TagsAndSocial tags={tags} className={'articleTags'} />
|
||||
<AuthorsContainer>
|
||||
<Authors authors={authors} email={true} gap={12} />
|
||||
</AuthorsContainer>
|
||||
|
@ -7,6 +7,8 @@ import EpisodeStats from '../Episode.Stats'
|
||||
import EpisodePlayer from './Episode.Player'
|
||||
import Image from 'next/image'
|
||||
import Link from 'next/link'
|
||||
import { ShareButton } from '@/components/ShareButton'
|
||||
import { TagsAndSocial } from '@/components/TagsAndSocial'
|
||||
|
||||
export type EpisodeHeaderProps = LPE.Podcast.Document & {
|
||||
channel: LPE.Podcast.Channel
|
||||
@ -51,7 +53,7 @@ const EpisodeHeader = ({
|
||||
</Show>
|
||||
</CustomLink>
|
||||
)}
|
||||
{tags && <Tags tags={tags} />}
|
||||
<TagsAndSocial tags={tags} />
|
||||
{channels && <EpisodeChannels channels={channels} />}
|
||||
{description && (
|
||||
<EpisodeSubtitle
|
||||
@ -106,6 +108,7 @@ const Show = styled.div`
|
||||
|
||||
const CustomLink = styled(Link)`
|
||||
text-decoration: none;
|
||||
width: fit-content;
|
||||
`
|
||||
|
||||
export default EpisodeHeader
|
||||
|
@ -7,6 +7,7 @@ import { episodeState } from '@/components/GlobalAudioPlayer/episode.state'
|
||||
import SimplecastPlayer from './Episode.SimplecastPlayer'
|
||||
import { LPE } from '@/types/lpe.types'
|
||||
import { useRouter } from 'next/router'
|
||||
import { ResponsiveImage } from '@/components/ResponsiveImage/ResponsiveImage'
|
||||
|
||||
export type EpisodePlayerProps = {
|
||||
channel: LPE.Podcast.Channel
|
||||
@ -29,6 +30,9 @@ const EpisodePlayer = ({
|
||||
const playerContainerRef = useRef<HTMLDivElement>(null)
|
||||
const playerRef = useRef<ReactPlayer>(null)
|
||||
|
||||
const [volume, setVolume] = useState(state.value.volume)
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
const isSimplecast = channel?.name === LPE.Podcast.ChannelNames.Simplecast
|
||||
|
||||
const url =
|
||||
@ -68,12 +72,11 @@ const EpisodePlayer = ({
|
||||
}))
|
||||
}
|
||||
} else {
|
||||
if (state.value.playing) {
|
||||
state.set((prev) => ({
|
||||
...prev,
|
||||
isEnabled: true,
|
||||
}))
|
||||
}
|
||||
state.set((prev) => ({
|
||||
...prev,
|
||||
isEnabled: true,
|
||||
volume: volume,
|
||||
}))
|
||||
}
|
||||
})
|
||||
observer.observe(playerContainerRef.current as any)
|
||||
@ -81,7 +84,7 @@ const EpisodePlayer = ({
|
||||
return () => {
|
||||
observer.disconnect()
|
||||
}
|
||||
}, [keepGlobalPlay])
|
||||
}, [keepGlobalPlay, volume])
|
||||
|
||||
useEffect(() => {
|
||||
const handleLeave = () => {
|
||||
@ -110,22 +113,46 @@ const EpisodePlayer = ({
|
||||
|
||||
useEffect(() => {
|
||||
if (!state.value.isEnabled) {
|
||||
playerRef.current?.seekTo(state.value.played)
|
||||
const offset = state.value.played === 0 ? 0 : 1 / state.value.duration // 1 second in %
|
||||
playerRef.current?.seekTo(state.value.played + offset)
|
||||
}
|
||||
}, [state.value.isEnabled])
|
||||
|
||||
useEffect(() => {
|
||||
if (channel?.name === LPE.Podcast.ChannelNames.Youtube) {
|
||||
window.addEventListener('message', function (event) {
|
||||
if (event.origin == 'https://www.youtube.com') {
|
||||
const data = JSON.parse(event?.data)
|
||||
const volume = data?.info?.volume
|
||||
const listener = (event: any) => {
|
||||
if (event.origin == 'https://www.youtube.com') {
|
||||
const data = JSON.parse(event?.data)
|
||||
|
||||
if (typeof volume !== 'undefined') {
|
||||
state.set((prev) => ({ ...prev, volume: volume / 100 }))
|
||||
if (data?.info?.hasOwnProperty('muted') && !state.value.isEnabled) {
|
||||
const isMuted = data.info.muted === true
|
||||
const muteChanged = state.value.muted !== isMuted
|
||||
|
||||
const newVolume = data.info?.volume / 100 || state.value.volume
|
||||
|
||||
if (isMuted) {
|
||||
if (muteChanged && !state.value.muted) {
|
||||
// TODO : handle mute
|
||||
}
|
||||
} else if (!isMuted) {
|
||||
if (muteChanged) {
|
||||
state.set((prev) => ({
|
||||
...prev,
|
||||
muted: false,
|
||||
volume: newVolume,
|
||||
}))
|
||||
}
|
||||
setVolume(newVolume)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (channel?.name === LPE.Podcast.ChannelNames.Youtube) {
|
||||
window.addEventListener('message', listener)
|
||||
}
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('message', listener)
|
||||
}
|
||||
}, [])
|
||||
|
||||
@ -166,7 +193,12 @@ const EpisodePlayer = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
{isSimplecast && (
|
||||
{loading && coverImage && (
|
||||
<PlaceholderImage>
|
||||
<ResponsiveImage data={coverImage} />
|
||||
</PlaceholderImage>
|
||||
)}
|
||||
{!loading && isSimplecast && (
|
||||
<SimplecastPlayer
|
||||
playing={keepGlobalPlay ? false : state.value.playing}
|
||||
playedSeconds={keepGlobalPlay ? 0 : state.value.playedSeconds}
|
||||
@ -194,6 +226,7 @@ const EpisodePlayer = ({
|
||||
onPlay={handlePlay}
|
||||
onPause={handlePause}
|
||||
onDuration={handleDuration}
|
||||
onReady={() => setLoading(false)}
|
||||
config={{
|
||||
youtube: {
|
||||
playerVars: { enablejsapi: 1 },
|
||||
@ -228,4 +261,11 @@ const PlayerContainer = styled.div<{ isAudio: boolean }>`
|
||||
}
|
||||
`
|
||||
|
||||
const PlaceholderImage = styled.div`
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
aspect-ratio: 16/9;
|
||||
`
|
||||
|
||||
export default EpisodePlayer
|
||||
|
@ -96,12 +96,6 @@ const SimplecastPlayer = ({
|
||||
const Container = styled.div`
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding-top: 56%;
|
||||
background: red;
|
||||
|
||||
> * {
|
||||
position: absolute;
|
||||
}
|
||||
`
|
||||
|
||||
const ImageContainer = styled.div`
|
||||
|
@ -50,5 +50,5 @@ const Links = styled(FooterSection)`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
margin-bottom: 72px;
|
||||
margin-bottom: 36px;
|
||||
`
|
||||
|
@ -1,6 +1,6 @@
|
||||
import ReactPlayer from 'react-player'
|
||||
import styled from '@emotion/styled'
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import React, { useEffect, useRef } from 'react'
|
||||
import { CloseIcon, Typography } from '@acid-info/lsd-react'
|
||||
import Image from 'next/image'
|
||||
import { playerState } from './globalAudioPlayer.state'
|
||||
@ -61,11 +61,9 @@ export default function GlobalAudioPlayer() {
|
||||
globalPlayerRef.current?.seekTo(v)
|
||||
}
|
||||
|
||||
const handleSeekMouseUp = () =>
|
||||
// e: React.MouseEvent<HTMLInputElement, MouseEvent>,
|
||||
{
|
||||
state.set((prev) => ({ ...prev, seeking: false }))
|
||||
}
|
||||
const handleSeekMouseUp = () => {
|
||||
state.set((prev) => ({ ...prev, seeking: false }))
|
||||
}
|
||||
|
||||
const handleDuration = (duration: number) => {
|
||||
state.set((prev) => ({ ...prev, duration }))
|
||||
@ -94,7 +92,8 @@ export default function GlobalAudioPlayer() {
|
||||
|
||||
useEffect(() => {
|
||||
if (state.value.isEnabled) {
|
||||
globalPlayerRef.current?.seekTo(state.value.played)
|
||||
const offset = 1 / state.value.duration // 1 second in %
|
||||
globalPlayerRef.current?.seekTo(state.value.played + offset)
|
||||
}
|
||||
}, [state.value.isEnabled])
|
||||
|
||||
@ -171,7 +170,13 @@ export default function GlobalAudioPlayer() {
|
||||
<CloseIcon
|
||||
width={16}
|
||||
height={16}
|
||||
onClick={() => state.set((prev) => ({ ...prev, isEnabled: false }))}
|
||||
onClick={() =>
|
||||
state.set((prev) => ({
|
||||
...prev,
|
||||
isEnabled: false,
|
||||
playing: false,
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</CloseIconContainer>
|
||||
</RightMenu>
|
||||
|
20
src/components/Icons/CopyIcon/CopyIcon.tsx
Normal file
20
src/components/Icons/CopyIcon/CopyIcon.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import { LsdIcon } from '@acid-info/lsd-react'
|
||||
|
||||
export const CopyIcon = LsdIcon(
|
||||
(props) => (
|
||||
<svg
|
||||
width="14"
|
||||
height="14"
|
||||
viewBox="0 0 14 14"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M9.33268 0.583313H2.33268C1.69102 0.583313 1.16602 1.10831 1.16602 1.74998V9.91665H2.33268V1.74998H9.33268V0.583313ZM8.74935 2.91665H4.66602C4.02435 2.91665 3.50518 3.44165 3.50518 4.08331L3.49935 12.25C3.49935 12.8916 4.01852 13.4166 4.66018 13.4166H11.0827C11.7243 13.4166 12.2493 12.8916 12.2493 12.25V6.41665L8.74935 2.91665ZM4.66602 12.25V4.08331H8.16602V6.99998H11.0827V12.25H4.66602Z"
|
||||
fill="black"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
{ filled: true },
|
||||
)
|
1
src/components/Icons/CopyIcon/index.ts
Normal file
1
src/components/Icons/CopyIcon/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './CopyIcon'
|
20
src/components/Icons/ShareIcon/ShareIcon.tsx
Normal file
20
src/components/Icons/ShareIcon/ShareIcon.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import { LsdIcon } from '@acid-info/lsd-react'
|
||||
|
||||
export const ShareIcon = LsdIcon(
|
||||
(props) => (
|
||||
<svg
|
||||
width="14"
|
||||
height="14"
|
||||
viewBox="0 0 14 14"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M10.5 9.37999C10.0567 9.37999 9.66 9.55499 9.35667 9.82916L5.1975 7.40832C5.22667 7.27416 5.25 7.13999 5.25 6.99999C5.25 6.85999 5.22667 6.72582 5.1975 6.59166L9.31 4.19416C9.625 4.48582 10.0392 4.66666 10.5 4.66666C11.4683 4.66666 12.25 3.88499 12.25 2.91666C12.25 1.94832 11.4683 1.16666 10.5 1.16666C9.53167 1.16666 8.75 1.94832 8.75 2.91666C8.75 3.05666 8.77333 3.19082 8.8025 3.32499L4.69 5.72249C4.375 5.43082 3.96083 5.24999 3.5 5.24999C2.53167 5.24999 1.75 6.03166 1.75 6.99999C1.75 7.96832 2.53167 8.74999 3.5 8.74999C3.96083 8.74999 4.375 8.56916 4.69 8.27749L8.84333 10.7042C8.81417 10.8267 8.79667 10.955 8.79667 11.0833C8.79667 12.0225 9.56083 12.7867 10.5 12.7867C11.4392 12.7867 12.2033 12.0225 12.2033 11.0833C12.2033 10.1442 11.4392 9.37999 10.5 9.37999ZM10.5 2.33332C10.8208 2.33332 11.0833 2.59582 11.0833 2.91666C11.0833 3.23749 10.8208 3.49999 10.5 3.49999C10.1792 3.49999 9.91667 3.23749 9.91667 2.91666C9.91667 2.59582 10.1792 2.33332 10.5 2.33332ZM3.5 7.58332C3.17917 7.58332 2.91667 7.32082 2.91667 6.99999C2.91667 6.67916 3.17917 6.41666 3.5 6.41666C3.82083 6.41666 4.08333 6.67916 4.08333 6.99999C4.08333 7.32082 3.82083 7.58332 3.5 7.58332ZM10.5 11.6783C10.1792 11.6783 9.91667 11.4158 9.91667 11.095C9.91667 10.7742 10.1792 10.5117 10.5 10.5117C10.8208 10.5117 11.0833 10.7742 11.0833 11.095C11.0833 11.4158 10.8208 11.6783 10.5 11.6783Z"
|
||||
fill="black"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
{ filled: true },
|
||||
)
|
1
src/components/Icons/ShareIcon/index.ts
Normal file
1
src/components/Icons/ShareIcon/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './ShareIcon'
|
20
src/components/Icons/UnfilledPlayIcon/UnfilledPlayIcon.tsx
Normal file
20
src/components/Icons/UnfilledPlayIcon/UnfilledPlayIcon.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import { LsdIcon } from '@acid-info/lsd-react'
|
||||
|
||||
export const UnfilledPlayIcon = LsdIcon(
|
||||
(props) => (
|
||||
<svg
|
||||
width="14"
|
||||
height="14"
|
||||
viewBox="0 0 14 14"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M5.83329 5.03996L8.90746 6.99996L5.83329 8.95996V5.03996ZM4.66663 2.91663V11.0833L11.0833 6.99996L4.66663 2.91663Z"
|
||||
fill="black"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
{ filled: true },
|
||||
)
|
1
src/components/Icons/UnfilledPlayIcon/index.ts
Normal file
1
src/components/Icons/UnfilledPlayIcon/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './UnfilledPlayIcon'
|
@ -94,7 +94,9 @@ export default function NavBar({ defaultState }: NavBarProps) {
|
||||
<NavbarLinks links={NavLinksItems} />
|
||||
</NavLinksContainer>
|
||||
<ControlsContainer>
|
||||
<SocialMediaKit />
|
||||
<SocialMediaKitContainer>
|
||||
<SocialMediaKit />
|
||||
</SocialMediaKitContainer>
|
||||
{buttons}
|
||||
</ControlsContainer>
|
||||
{showMobileMenu && <NavbarMobileMenu />}
|
||||
@ -113,6 +115,12 @@ const PressLogoType = styled(Typography)<{ display: boolean }>`
|
||||
`}
|
||||
`
|
||||
|
||||
const SocialMediaKitContainer = styled.div`
|
||||
@media (max-width: ${({ theme }) => theme.breakpoints.sm.width}px) {
|
||||
display: none;
|
||||
}
|
||||
`
|
||||
|
||||
const Container = styled.header<{
|
||||
bordered?: boolean
|
||||
}>`
|
||||
|
@ -6,6 +6,7 @@ import { FooterOrgPanel } from '@/components/Footer/Footer.OrgPanel'
|
||||
import { useThemeState } from '@/states/themeState'
|
||||
import { ThemeSwitchWithLabel } from '@/components/ThemeSwitch/ThemeSwitch'
|
||||
import { useEffect } from 'react'
|
||||
import { SocialMediaKit } from './Navbar.SocialMediaKit'
|
||||
|
||||
interface Props {}
|
||||
|
||||
@ -24,13 +25,14 @@ export const NavbarMobileMenu = (props: Props) => {
|
||||
<NavbarMobileMenuContainer>
|
||||
<InnerContainer>
|
||||
<NavbarLinks links={NavLinksItems} />
|
||||
<FooterOrgPanel />
|
||||
<ThemeSwitchContainer>
|
||||
<SocialAndThemeSwitchContainer>
|
||||
<SocialMediaKit />
|
||||
<ThemeSwitchWithLabel
|
||||
toggle={themeState.toggleMode}
|
||||
mode={themeState.get().mode}
|
||||
/>
|
||||
</ThemeSwitchContainer>
|
||||
</SocialAndThemeSwitchContainer>
|
||||
<FooterOrgPanel />
|
||||
</InnerContainer>
|
||||
</NavbarMobileMenuContainer>
|
||||
)
|
||||
@ -70,3 +72,10 @@ const ThemeSwitchContainer = styled.div`
|
||||
margin-top: 0;
|
||||
padding-bottom: 16px;
|
||||
`
|
||||
|
||||
const SocialAndThemeSwitchContainer = styled.div`
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid rgb(var(--lsd-border-primary));
|
||||
`
|
||||
|
@ -9,6 +9,7 @@ import { LPEFooterGroup } from '@/types/ui.types'
|
||||
const socialLinks = FooterLinksItems.about.find(
|
||||
(item) => item.key === 'social',
|
||||
) as LPEFooterGroup
|
||||
|
||||
export const SocialMediaKit = () => {
|
||||
return (
|
||||
<Container>
|
||||
@ -29,14 +30,18 @@ export const SocialMediaKit = () => {
|
||||
Icon = null
|
||||
}
|
||||
return (
|
||||
<Link
|
||||
href={link.href}
|
||||
key={`sm-link-${index}`}
|
||||
title={`Join us on ${link.label}`}
|
||||
target={'_blank'}
|
||||
>
|
||||
{Icon && <Icon />}
|
||||
</Link>
|
||||
Icon && (
|
||||
<LinkContainer>
|
||||
<Link
|
||||
href={link.href}
|
||||
key={`sm-link-${index}`}
|
||||
title={`Join us on ${link.label}`}
|
||||
target={'_blank'}
|
||||
>
|
||||
<Icon />
|
||||
</Link>
|
||||
</LinkContainer>
|
||||
)
|
||||
)
|
||||
})}
|
||||
</Container>
|
||||
@ -46,8 +51,24 @@ export const SocialMediaKit = () => {
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
gap: 16px;
|
||||
|
||||
a {
|
||||
display: flex;
|
||||
}
|
||||
`
|
||||
|
||||
const LinkContainer = styled.div`
|
||||
@media (max-width: ${({ theme }) => theme.breakpoints.sm.width}px) {
|
||||
width: fit-content;
|
||||
display: flex;
|
||||
|
||||
&:not(:last-child) {
|
||||
&:after {
|
||||
content: '';
|
||||
margin-left: 16px;
|
||||
border-right: 1px solid rgb(var(--lsd-border-primary));
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
@ -3,8 +3,12 @@ import {
|
||||
ResponsiveImageProps,
|
||||
} from '@/components/ResponsiveImage/ResponsiveImage'
|
||||
import { LPE } from '@/types/lpe.types'
|
||||
import { IconButton } from '@acid-info/lsd-react'
|
||||
import Link from 'next/link'
|
||||
import { FC } from 'react'
|
||||
import { PlayIcon } from '../Icons/PlayIcon'
|
||||
import styled from '@emotion/styled'
|
||||
import { UnfilledPlayIcon } from '../Icons/UnfilledPlayIcon'
|
||||
|
||||
export type PostCardCoverProps = React.ComponentProps<typeof Link> & {
|
||||
imageProps: ResponsiveImageProps
|
||||
@ -18,8 +22,28 @@ export const PostCardCover: FC<PostCardCoverProps> = ({
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<Link {...props} className={`post-card__cover-image ${props.className}`}>
|
||||
<CustomLink
|
||||
{...props}
|
||||
className={`post-card__cover-image ${props.className}`}
|
||||
>
|
||||
<ResponsiveImage {...imageProps} data={imageData} />
|
||||
</Link>
|
||||
{playIcon && (
|
||||
<Icon size="small">
|
||||
<UnfilledPlayIcon />
|
||||
</Icon>
|
||||
)}
|
||||
</CustomLink>
|
||||
)
|
||||
}
|
||||
|
||||
const CustomLink = styled(Link)`
|
||||
position: relative;
|
||||
`
|
||||
|
||||
const Icon = styled(IconButton)`
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
right: 8px;
|
||||
background: white;
|
||||
border: none;
|
||||
`
|
||||
|
@ -4,12 +4,11 @@ import {
|
||||
PostCardShowDetailsProps,
|
||||
} from '@/components/PostCard/PostCard.ShowDetails'
|
||||
import { Tags } from '@/components/Tags'
|
||||
import { Theme, Typography } from '@acid-info/lsd-react'
|
||||
import { Theme } from '@acid-info/lsd-react'
|
||||
import { CommonProps } from '@acid-info/lsd-react/dist/utils/useCommonProps'
|
||||
import { css } from '@emotion/react'
|
||||
import styled from '@emotion/styled'
|
||||
import clsx from 'clsx'
|
||||
import Link from 'next/link'
|
||||
import React from 'react'
|
||||
import { LPE } from '../../types/lpe.types'
|
||||
import { lsdUtils } from '../../utils/lsd.utils'
|
||||
@ -73,7 +72,12 @@ export const PostCard = (_props: PostCardProps) => {
|
||||
: `/podcasts/${podcastShowDetails?.slug}/${slug}`
|
||||
|
||||
const coverImageElement = coverImage && (
|
||||
<PostCardCover href={link} imageProps={imageProps} imageData={coverImage} />
|
||||
<PostCardCover
|
||||
href={link}
|
||||
imageProps={imageProps}
|
||||
imageData={coverImage}
|
||||
playIcon={contentType === LPE.PostTypes.Podcast}
|
||||
/>
|
||||
)
|
||||
|
||||
const labelElement = (
|
||||
|
118
src/components/ShareButton/ShareButton.tsx
Normal file
118
src/components/ShareButton/ShareButton.tsx
Normal file
@ -0,0 +1,118 @@
|
||||
import { Tag, Typography } from '@acid-info/lsd-react'
|
||||
import styled from '@emotion/styled'
|
||||
import { ShareIcon } from '../Icons/ShareIcon'
|
||||
import { useRef, useState } from 'react'
|
||||
import { CopyIcon } from '../Icons/CopyIcon'
|
||||
import { XIcon } from '../Icons/XIcon'
|
||||
import Link from 'next/link'
|
||||
import { useClickAway } from 'react-use'
|
||||
|
||||
type Props = {
|
||||
url: string
|
||||
}
|
||||
|
||||
export default function ShareButton({ url }: Props) {
|
||||
const [showOptions, setShowOptions] = useState(false)
|
||||
const [copied, setCopied] = useState(false)
|
||||
const ref = useRef(null)
|
||||
|
||||
useClickAway(ref, () => {
|
||||
setShowOptions(false)
|
||||
})
|
||||
|
||||
const handleCopyClipBoard = async (text: string) => {
|
||||
await navigator.clipboard.writeText(text)
|
||||
setCopied(true)
|
||||
|
||||
// TODO : Temporary solution
|
||||
setTimeout(() => {
|
||||
setCopied(false)
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
return (
|
||||
<Container ref={ref}>
|
||||
<CustomTag
|
||||
onClick={() => setShowOptions(!showOptions)}
|
||||
icon={<ShareIcon width={14} height={14} />}
|
||||
iconDirection="left"
|
||||
showOptions={showOptions}
|
||||
>
|
||||
<Typography variant="body3">Share</Typography>
|
||||
</CustomTag>
|
||||
{showOptions && (
|
||||
<Options>
|
||||
<Label>
|
||||
<Typography variant="body3">Share Options</Typography>
|
||||
</Label>
|
||||
<ShareOption onClick={() => handleCopyClipBoard(url)}>
|
||||
<CopyIcon width={14} height={14} />
|
||||
<Typography variant="body2">
|
||||
{copied ? 'Copied' : 'Copy link'}
|
||||
</Typography>
|
||||
</ShareOption>
|
||||
<CustomLink href={`http://www.twitter.com/share?url=${url}`}>
|
||||
<ShareOption>
|
||||
<XIcon />
|
||||
<Typography variant="body2">X</Typography>
|
||||
</ShareOption>
|
||||
</CustomLink>
|
||||
</Options>
|
||||
)}
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
const HEIGHT = 24
|
||||
|
||||
const Container = styled.div`
|
||||
position: relative;
|
||||
`
|
||||
|
||||
const CustomTag = styled(Tag)<{ showOptions: boolean }>`
|
||||
width: 69px;
|
||||
height: ${HEIGHT}px;
|
||||
padding: 0 8px;
|
||||
border-bottom: ${(props) =>
|
||||
props.showOptions
|
||||
? '1px solid transparent'
|
||||
: '1px solid rgb(var(--lsd-border-primary))'};
|
||||
`
|
||||
|
||||
const Options = styled.div`
|
||||
top: ${HEIGHT - 1}px;
|
||||
left: 0;
|
||||
width: 169px;
|
||||
border: 1px solid rgb(var(--lsd-border-primary));
|
||||
position: absolute;
|
||||
background-color: rgb(var(--lsd-surface-primary));
|
||||
padding-bottom: 8px;
|
||||
z-index: 1;
|
||||
`
|
||||
|
||||
const Label = styled.div`
|
||||
padding: 12px;
|
||||
`
|
||||
|
||||
const ShareOption = styled.div`
|
||||
cursor: pointer;
|
||||
padding: 6px 12px 6px 14px;
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
align-items: center;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
`
|
||||
|
||||
const CustomLink = styled(Link)`
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
`
|
1
src/components/ShareButton/index.ts
Normal file
1
src/components/ShareButton/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { default as ShareButton } from './ShareButton'
|
34
src/components/TagsAndSocial/TagsAndSocial.tsx
Normal file
34
src/components/TagsAndSocial/TagsAndSocial.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
import styled from '@emotion/styled'
|
||||
import { ShareButton } from '../ShareButton'
|
||||
import { Tags } from '../Tags'
|
||||
|
||||
export type TagsProps = {
|
||||
tags: string[]
|
||||
className?: string
|
||||
}
|
||||
|
||||
const TagsAndSocial: React.FC<TagsProps> = ({ tags, className }) => {
|
||||
const currentUrl = typeof window !== 'undefined' ? window.location.href : ''
|
||||
|
||||
return (
|
||||
<Container>
|
||||
{tags && <Tags tags={tags} className={className} />}
|
||||
<VerticalLine />
|
||||
<ShareButton url={currentUrl} />
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
width: fit-content;
|
||||
`
|
||||
|
||||
const VerticalLine = styled.div`
|
||||
height: 12px;
|
||||
border-left: 1px solid rgb(var(--lsd-border-primary));
|
||||
`
|
||||
|
||||
export default TagsAndSocial
|
1
src/components/TagsAndSocial/index.tsx
Normal file
1
src/components/TagsAndSocial/index.tsx
Normal file
@ -0,0 +1 @@
|
||||
export { default as TagsAndSocial } from './TagsAndSocial'
|
@ -1,7 +1,4 @@
|
||||
import { LPEFooterGroup } from '@/types/ui.types'
|
||||
import { DiscordIcon } from '@/components/Icons/DiscordIcon'
|
||||
import { YoutubeIcon } from '@/components/Icons/YTIcon'
|
||||
import { XIcon } from '@/components/Icons/XIcon'
|
||||
|
||||
export const ArticleBlocksOrders = {
|
||||
title: 0,
|
||||
@ -61,12 +58,12 @@ export const FooterLinksItems: {
|
||||
title: null,
|
||||
key: 'social',
|
||||
links: [
|
||||
{ label: 'X', href: 'https://twitter.com/Logos_state', key: 'x' },
|
||||
{
|
||||
label: 'Discord',
|
||||
href: 'https://discord.gg/logos-state',
|
||||
key: 'discord',
|
||||
},
|
||||
{ label: 'X', href: 'https://twitter.com/Logos_state', key: 'x' },
|
||||
{
|
||||
label: 'Github',
|
||||
href: 'https://github.com/acid-info',
|
||||
|
Loading…
x
Reference in New Issue
Block a user