Skip to content

Commit

Permalink
feat: Add dropdown toggle functionality to SingleLine component
Browse files Browse the repository at this point in the history
  • Loading branch information
Kechicode committed Jan 17, 2025
1 parent f6e5ed4 commit b380266
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 2 deletions.
99 changes: 99 additions & 0 deletions src/views/Home/Channel/DropdownDialog/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import classnames from 'classnames'
import { useState } from 'react'
import { useEffect } from 'react'

import { ReactComponent as IconUp } from '@/public/static/icons/24px/up.svg'
import { Icon } from '~/components'

import styles from './styles.module.css'

type DropdownDialogProps = {
items: {
id: string
title: string
link: string
}[]
toggleDropdown: () => void
}

const DropdownDialog = ({ items, toggleDropdown }: DropdownDialogProps) => {
const [hash, setHash] = useState('')

useEffect(() => {
// Function to update the hash state
const updateHash = () => {
setHash(window.location.hash)
}

// Set the initial hash
updateHash()

// Add an event listener to update the hash when it changes
window.addEventListener('hashchange', updateHash)

// Clean up the event listener on component unmount
return () => {
window.removeEventListener('hashchange', updateHash)
}
}, [])

const [selectedChannel, setSelectedChannel] = useState(1)

useEffect(() => {
if (hash) {
const channel = parseInt(hash.split('=')[1], 10)
setSelectedChannel(channel)
}
}, [hash])

const handleClick = (event: React.MouseEvent<HTMLDivElement>) => {
// click in container but not in content
const target = event.target as HTMLElement
if (target.closest('#channel-dropdown-dialog-content') === null) {
toggleDropdown()
}
}
return (
<div className={styles.container} onClick={handleClick}>
<div className={styles.content} id="channel-dropdown-dialog-content">
<div className={styles.contentInner}>
<div className={styles.header}>
<div className={styles.title}>選擇頻道</div>
<button className={styles.closeBtn} onClick={toggleDropdown}>
<Icon
aria-label="Close"
icon={IconUp}
size={16}
color="greyDarker"
/>
</button>
</div>
<div className={styles.body}>
<div className={styles.grid}>
{items.map((item) => (
<a
key={item.id}
href={item.link}
onClick={() => {
if (selectedChannel === parseInt(item?.id || '1', 10)) {
return
}
toggleDropdown()
}}
className={classnames(styles.gridItem, {
[styles.selectedChannel]:
selectedChannel === parseInt(item?.id || '1', 10),
})}
>
{item.title}
</a>
))}
</div>
</div>
</div>
</div>
</div>
)
}

export default DropdownDialog
52 changes: 52 additions & 0 deletions src/views/Home/Channel/DropdownDialog/styles.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
.container {
position: fixed;
top: 66px;
right: 0;
left: 0;
z-index: 1000;
height: calc(100vh - 66px);
background-color: rgb(0 0 0 / 40%);
}

.content {
padding: var(--sp8) var(--sp16) var(--sp20);
background-color: var(--color-white);

& .header {
display: flex;
align-items: center;
justify-content: space-between;

& .title {
font-size: var(--font-size-16);
font-weight: var(--font-semibold);
}
}

& .body {
margin-top: var(--sp12);

& .grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(76px, 1fr));
gap: var(--sp12);

& .gridItem {
display: flex;
align-items: center;
justify-content: center;
padding: var(--sp4) var(--sp10);
font-size: var(--font-size-14);
color: var(--color-grey-darker);
background-color: var(--color-grey-lighter);
border-radius: var(--sp8);

&.selectedChannel {
font-weight: var(--font-semibold);
color: var(--color-white);
background-color: var(--color-black);
}
}
}
}
}
9 changes: 8 additions & 1 deletion src/views/Home/Channel/SingleLine/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import classnames from 'classnames'
import { useState } from 'react'
import { useEffect } from 'react'

import { ReactComponent as IconDown } from '@/public/static/icons/24px/down.svg'
import { Icon } from '~/components'

import styles from './styles.module.css'

type SingleLineProps = {
Expand All @@ -10,9 +13,10 @@ type SingleLineProps = {
title: string
link: string
}[]
toggleDropdown: () => void
}

const SingleLine = ({ items }: SingleLineProps) => {
const SingleLine = ({ items, toggleDropdown }: SingleLineProps) => {
const [hash, setHash] = useState('')

useEffect(() => {
Expand Down Expand Up @@ -72,6 +76,9 @@ const SingleLine = ({ items }: SingleLineProps) => {
{item.title}
</a>
))}
<button className={styles.moreBtn} onClick={toggleDropdown}>
<Icon aria-label="More" icon={IconDown} size={16} />
</button>
</section>
// </div>
)
Expand Down
10 changes: 10 additions & 0 deletions src/views/Home/Channel/SingleLine/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,13 @@
}
}
}

.moreBtn {
position: sticky;
right: 0;
z-index: 1; /* ensure button stays on top */
padding: 8px 16px; /* expand button area */
color: var(--color-grey-darker);
cursor: pointer;
background: var(--color-white);
}
14 changes: 13 additions & 1 deletion src/views/Home/Feed/MainFeed/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
} from '~/gql/graphql'

import Announcements from '../../Announcements'
import DropdownDialog from '../../Channel/DropdownDialog'
import ChannelCarousel from '../../Channel/Page/Carousel'
import SingleLine from '../../Channel/SingleLine'
import Authors from '../Authors'
Expand Down Expand Up @@ -237,6 +238,12 @@ const MainFeed = ({ feedSortType: sortBy }: MainFeedProps) => {
},
]

const [showDropdown, setShowDropdown] = useState(false)

const toggleDropdown = () => {
setShowDropdown(!showDropdown)
}

const [showSingleLine, setShowSingleLine] = useState(false)

useNativeEventListener('scroll', () => {
Expand Down Expand Up @@ -376,7 +383,12 @@ const MainFeed = ({ feedSortType: sortBy }: MainFeedProps) => {
<List>
<Media lessThan="lg">
<ChannelCarousel items={items} />
{showSingleLine && <SingleLine items={items} />}
{showSingleLine && !showDropdown && (
<SingleLine items={items} toggleDropdown={toggleDropdown} />
)}
{showDropdown && (
<DropdownDialog items={items} toggleDropdown={toggleDropdown} />
)}
</Media>
{isHottestFeed && <Announcements />}
{mixFeed.map((edge, i) => {
Expand Down

0 comments on commit b380266

Please sign in to comment.