From 9dafbe81096cafadd2dca3fb3d123378460dc508 Mon Sep 17 00:00:00 2001 From: Kechicode <186776112+Kechicode@users.noreply.github.com> Date: Tue, 7 Jan 2025 17:42:28 +0800 Subject: [PATCH 1/6] feat(Channel): Add SingleLine component to MainFeed with dynamic channel links --- src/views/Home/Channel/SingleLine/index.tsx | 78 ++++++++++ .../Home/Channel/SingleLine/styles.module.css | 32 ++++ src/views/Home/Feed/MainFeed/index.tsx | 147 ++++++++++++++++++ 3 files changed, 257 insertions(+) create mode 100644 src/views/Home/Channel/SingleLine/index.tsx create mode 100644 src/views/Home/Channel/SingleLine/styles.module.css diff --git a/src/views/Home/Channel/SingleLine/index.tsx b/src/views/Home/Channel/SingleLine/index.tsx new file mode 100644 index 0000000000..d3a4fcb1a3 --- /dev/null +++ b/src/views/Home/Channel/SingleLine/index.tsx @@ -0,0 +1,78 @@ +import classnames from 'classnames' +import { useState } from 'react' +import { useEffect } from 'react' + +import styles from './styles.module.css' + +type SingleLineProps = { + items: { + id: string + title: string + link: string + }[] +} + +const SingleLine = ({ items }: SingleLineProps) => { + 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) + + // scroll to the selected channel + const selectedChannel = document.querySelector( + `.singleLine-item[data-channel-id="${channel}"]` + ) + if (selectedChannel) { + selectedChannel.scrollIntoView({ + behavior: 'smooth', + inline: 'center', + block: 'nearest', + }) + } + } + }, [hash]) + + return ( +
+ {items.map((item) => ( + + {item.title} + + ))} +
+ ) +} + +export default SingleLine diff --git a/src/views/Home/Channel/SingleLine/styles.module.css b/src/views/Home/Channel/SingleLine/styles.module.css new file mode 100644 index 0000000000..32383132e2 --- /dev/null +++ b/src/views/Home/Channel/SingleLine/styles.module.css @@ -0,0 +1,32 @@ +/* 频道行样式 */ +.singleLine { + @mixin border-bottom-grey; + + position: relative; + display: flex; + gap: var(--sp12); + align-items: center; + margin: 0 calc(var(--sp16) * -1); + overflow-x: auto; /* horizontal scroll */ + white-space: nowrap; + border-bottom-color: var(--color-grey-hover); + scrollbar-width: none; /* Firefox hide scrollbar */ + + &::-webkit-scrollbar { + display: none; + } + + & .item { + flex-shrink: 0; /* prevent shrink */ + padding: 8px 10px; + color: var(--color-grey-darker); + white-space: nowrap; + cursor: pointer; + + &.selectedChannel { + font-weight: 600; + color: var(--color-black); + border-bottom: 1px solid var(--color-black); + } + } +} diff --git a/src/views/Home/Feed/MainFeed/index.tsx b/src/views/Home/Feed/MainFeed/index.tsx index 74a9aa0056..0a61aa99b1 100644 --- a/src/views/Home/Feed/MainFeed/index.tsx +++ b/src/views/Home/Feed/MainFeed/index.tsx @@ -22,6 +22,7 @@ import { import Announcements from '../../Announcements' import ChannelCarousel from '../../Channel/Page/Carousel' +import SingleLine from '../../Channel/SingleLine' import Authors from '../Authors' import Billboard from '../Billboard' import { FEED_ARTICLES_PRIVATE, FEED_ARTICLES_PUBLIC } from '../gql' @@ -89,6 +90,151 @@ const MainFeed = ({ feedSortType: sortBy }: MainFeedProps) => { const viewer = useContext(ViewerContext) const isHottestFeed = sortBy === 'hottest' const isIcymiFeed = sortBy === 'icymi' + + const host = typeof window !== 'undefined' ? window.location.origin : '' + + const items = [ + { + id: '1', + title: 'Item 1', + link: `${host}/#channel=1`, + }, + { + id: '2', + title: 'Item 2', + link: `${host}/#channel=2`, + }, + { + id: '3', + title: 'Item 3', + link: `${host}/#channel=3`, + }, + { + id: '4', + title: 'Item 4', + link: `${host}/#channel=4`, + }, + { + id: '5', + title: 'Item 5', + link: `${host}/#channel=5`, + }, + { + id: '6', + title: 'Item 6', + link: `${host}/#channel=6`, + }, + { + id: '7', + title: 'Item 7', + link: `${host}/#channel=7`, + }, + { + id: '8', + title: 'Item 8', + link: `${host}/#channel=8`, + }, + { + id: '9', + title: 'Item 9', + link: `${host}/#channel=9`, + }, + { + id: '10', + title: 'Item 10', + link: `${host}/#channel=10`, + }, + { + id: '11', + title: 'Item 11', + link: `${host}/#channel=11`, + }, + { + id: '12', + title: 'Item 12', + link: `${host}/#channel=12`, + }, + { + id: '13', + title: 'Item 13', + link: `${host}/#channel=13`, + }, + { + id: '14', + title: 'Item 14', + link: `${host}/#channel=14`, + }, + { + id: '15', + title: 'Item 15', + link: `${host}/#channel=15`, + }, + { + id: '16', + title: 'Item 16', + link: `${host}/#channel=16`, + }, + { + id: '17', + title: 'Item 17', + link: `${host}/#channel=17`, + }, + { + id: '18', + title: 'Item 18', + link: `${host}/#channel=18`, + }, + { + id: '19', + title: 'Item 19', + link: `${host}/#channel=19`, + }, + { + id: '20', + title: 'Item 20', + link: `${host}/#channel=20`, + }, + { + id: '21', + title: 'Item 21', + link: `${host}/#channel=21`, + }, + { + id: '22', + title: 'Item 22', + link: `${host}/#channel=22`, + }, + { + id: '23', + title: 'Item 23', + link: `${host}/#channel=23`, + }, + { + id: '24', + title: 'Item 24', + link: `${host}/#channel=24`, + }, + { + id: '25', + title: 'Item 25', + link: `${host}/#channel=25`, + }, + { + id: '26', + title: 'Item 26', + link: `${host}/#channel=26`, + }, + { + id: '27', + title: 'Item 27', + link: `${host}/#channel=27`, + }, + { + id: '28', + title: 'Item 28', + link: `${host}/#channel=28`, + }, + ] /** * Data Fetching */ @@ -218,6 +364,7 @@ const MainFeed = ({ feedSortType: sortBy }: MainFeedProps) => { + {isHottestFeed && } {mixFeed.map((edge, i) => { From 8fe8233c417e0f59012084c17043dbca6ff0ccea Mon Sep 17 00:00:00 2001 From: Kechicode <186776112+Kechicode@users.noreply.github.com> Date: Tue, 7 Jan 2025 17:45:50 +0800 Subject: [PATCH 2/6] feat(Channel): refactor ChannelCarousel to Accept Dynamic Items as Props --- .../Home/Channel/Page/Carousel/index.tsx | 153 ++---------------- src/views/Home/Feed/MainFeed/index.tsx | 2 +- 2 files changed, 10 insertions(+), 145 deletions(-) diff --git a/src/views/Home/Channel/Page/Carousel/index.tsx b/src/views/Home/Channel/Page/Carousel/index.tsx index 1df7611b24..470305e85c 100644 --- a/src/views/Home/Channel/Page/Carousel/index.tsx +++ b/src/views/Home/Channel/Page/Carousel/index.tsx @@ -16,150 +16,15 @@ import styles from './styles.module.css' type ColumnCount = '4' | '5' | '6' | '7' -const ChannelCarousel = () => { - const host = typeof window !== 'undefined' ? window.location.origin : '' - const items = [ - { - id: '1', - title: 'Item 1', - link: `${host}/#channel=1`, - }, - { - id: '2', - title: 'Item 2', - link: `${host}/#channel=2`, - }, - { - id: '3', - title: 'Item 3', - link: `${host}/#channel=3`, - }, - { - id: '4', - title: 'Item 4', - link: `${host}/#channel=4`, - }, - { - id: '5', - title: 'Item 5', - link: `${host}/#channel=5`, - }, - { - id: '6', - title: 'Item 6', - link: `${host}/#channel=6`, - }, - { - id: '7', - title: 'Item 7', - link: `${host}/#channel=7`, - }, - { - id: '8', - title: 'Item 8', - link: `${host}/#channel=8`, - }, - { - id: '9', - title: 'Item 9', - link: `${host}/#channel=9`, - }, - { - id: '10', - title: 'Item 10', - link: `${host}/#channel=10`, - }, - { - id: '11', - title: 'Item 11', - link: `${host}/#channel=11`, - }, - { - id: '12', - title: 'Item 12', - link: `${host}/#channel=12`, - }, - { - id: '13', - title: 'Item 13', - link: `${host}/#channel=13`, - }, - { - id: '14', - title: 'Item 14', - link: `${host}/#channel=14`, - }, - { - id: '15', - title: 'Item 15', - link: `${host}/#channel=15`, - }, - { - id: '16', - title: 'Item 16', - link: `${host}/#channel=16`, - }, - { - id: '17', - title: 'Item 17', - link: `${host}/#channel=17`, - }, - { - id: '18', - title: 'Item 18', - link: `${host}/#channel=18`, - }, - { - id: '19', - title: 'Item 19', - link: `${host}/#channel=19`, - }, - { - id: '20', - title: 'Item 20', - link: `${host}/#channel=20`, - }, - { - id: '21', - title: 'Item 21', - link: `${host}/#channel=21`, - }, - { - id: '22', - title: 'Item 22', - link: `${host}/#channel=22`, - }, - { - id: '23', - title: 'Item 23', - link: `${host}/#channel=23`, - }, - { - id: '24', - title: 'Item 24', - link: `${host}/#channel=24`, - }, - { - id: '25', - title: 'Item 25', - link: `${host}/#channel=25`, - }, - { - id: '26', - title: 'Item 26', - link: `${host}/#channel=26`, - }, - { - id: '27', - title: 'Item 27', - link: `${host}/#channel=27`, - }, - { - id: '28', - title: 'Item 28', - link: `${host}/#channel=28`, - }, - ] +type ChannelCarouselProps = { + items: { + id: string + title: string + link: string + }[] +} + +const ChannelCarousel = ({ items }: ChannelCarouselProps) => { const [dot, setDot] = useState(0) const [, setSnaps] = useState([]) const [carousel, carouselApi] = useEmblaCarousel({ diff --git a/src/views/Home/Feed/MainFeed/index.tsx b/src/views/Home/Feed/MainFeed/index.tsx index 0a61aa99b1..66e1ccf267 100644 --- a/src/views/Home/Feed/MainFeed/index.tsx +++ b/src/views/Home/Feed/MainFeed/index.tsx @@ -363,7 +363,7 @@ const MainFeed = ({ feedSortType: sortBy }: MainFeedProps) => { > - + {isHottestFeed && } From 9c7b48b2418662a8526080adb142ea72617d0163 Mon Sep 17 00:00:00 2001 From: Kechicode <186776112+Kechicode@users.noreply.github.com> Date: Tue, 7 Jan 2025 18:08:16 +0800 Subject: [PATCH 3/6] feat(MainFeed): Add dynamic single line display in MainFeed --- src/views/Home/Channel/Page/Carousel/index.tsx | 4 +++- src/views/Home/Feed/MainFeed/index.tsx | 16 ++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/views/Home/Channel/Page/Carousel/index.tsx b/src/views/Home/Channel/Page/Carousel/index.tsx index 470305e85c..a67b5cbe17 100644 --- a/src/views/Home/Channel/Page/Carousel/index.tsx +++ b/src/views/Home/Channel/Page/Carousel/index.tsx @@ -174,7 +174,9 @@ const ChannelCarousel = ({ items }: ChannelCarouselProps) => {