diff --git a/src/components/Layout/TopNavBar/styles.module.css b/src/components/Layout/TopNavBar/styles.module.css
index 9f1a73c094..f6750ab847 100644
--- a/src/components/Layout/TopNavBar/styles.module.css
+++ b/src/components/Layout/TopNavBar/styles.module.css
@@ -1,6 +1,4 @@
.container {
- @mixin border-bottom-grey-light;
-
position: sticky;
top: 0;
z-index: calc(var(--z-index-global-header) + 1);
@@ -9,10 +7,12 @@
justify-content: space-between;
padding: var(--sp20) var(--sp16);
background-color: var(--color-white);
- border-bottom-color: var(--color-grey-hover);
@media (--sm-up) {
+ @mixin border-bottom-grey-light;
+
padding: var(--sp20) var(--sp32);
+ border-bottom-color: var(--color-grey-hover);
}
& .left {
diff --git a/src/components/Layout/index.tsx b/src/components/Layout/index.tsx
index 6c35416bcb..6fae6041ac 100644
--- a/src/components/Layout/index.tsx
+++ b/src/components/Layout/index.tsx
@@ -6,10 +6,10 @@ import { Head, Media, useRoute } from '~/components'
import AuthHeader from './AuthHeader'
import FixedMain from './FixedMain'
import Header from './Header'
-import NavBar from './NavBar'
+// import NavBar from './NavBar'
import Notice from './Notice'
// import SideFooter from './SideFooter'
-import SideNav from './SideNav'
+// import SideNav from './SideNav'
import Spacing from './Spacing'
import styles from './styles.module.css'
import { TopNavBar } from './TopNavBar'
@@ -21,12 +21,12 @@ export const Layout: React.FC<{ children?: React.ReactNode }> & {
AuthHeader: typeof AuthHeader
Notice: typeof Notice
} = ({ children }) => {
- const { isInPath } = useRoute()
- const isInDraftDetail = isInPath('ME_DRAFT_DETAIL')
- const isInArticleDetail = isInPath('ARTICLE_DETAIL')
- const isInArticleDetailHistory = isInPath('ARTICLE_DETAIL_HISTORY')
- const isInMomentDetail = isInPath('MOMENT_DETAIL')
- const isInMomentDetailEdit = isInPath('MOMENT_DETAIL_EDIT')
+ // const { isInPath } = useRoute()
+ // const isInDraftDetail = isInPath('ME_DRAFT_DETAIL')
+ // const isInArticleDetail = isInPath('ARTICLE_DETAIL')
+ // const isInArticleDetailHistory = isInPath('ARTICLE_DETAIL_HISTORY')
+ // const isInMomentDetail = isInPath('MOMENT_DETAIL')
+ // const isInMomentDetailEdit = isInPath('MOMENT_DETAIL_EDIT')
return (
<>
@@ -34,21 +34,21 @@ export const Layout: React.FC<{ children?: React.ReactNode }> & {
scroll(index)}
+ />
+ >
+ )
+}
+
+export default Dot
diff --git a/src/views/Home/Channel/Page/Carousel/index.tsx b/src/views/Home/Channel/Page/Carousel/index.tsx
new file mode 100644
index 0000000000..1df7611b24
--- /dev/null
+++ b/src/views/Home/Channel/Page/Carousel/index.tsx
@@ -0,0 +1,327 @@
+import classnames from 'classnames'
+import useEmblaCarousel from 'embla-carousel-react'
+import {
+ type MouseEvent,
+ // useCallback,
+ useEffect,
+ useRef,
+ useState,
+} from 'react'
+
+import { useNativeEventListener } from '~/components'
+
+// import { useCarousel } from '~/components/Hook/useCarousel'
+import Dot from './Dot'
+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`,
+ },
+ ]
+ const [dot, setDot] = useState(0)
+ const [, setSnaps] = useState
([])
+ const [carousel, carouselApi] = useEmblaCarousel({
+ loop: true,
+ skipSnaps: false,
+ })
+
+ const [columnCount, setColumnCount] = useState('4')
+
+ useNativeEventListener('resize', () => {
+ if (typeof window !== 'undefined') {
+ if (window.innerWidth < 453) {
+ setColumnCount('4')
+ }
+ if (window.innerWidth >= 453) {
+ setColumnCount('5')
+ }
+ if (window.innerWidth >= 561) {
+ setColumnCount('6')
+ }
+ if (window.innerWidth >= 669) {
+ setColumnCount('7')
+ }
+ }
+ })
+
+ const [slicedItems, setSlicedItems] = useState([])
+
+ useEffect(() => {
+ const pageCount = Math.ceil(items.length / (Number(columnCount) * 2))
+ const _slicedItems: any[] = []
+ for (let i = 0; i < pageCount; i++) {
+ _slicedItems.push(
+ items.slice(
+ i * (Number(columnCount) * 2),
+ (i + 1) * (Number(columnCount) * 2)
+ )
+ )
+ }
+ setSlicedItems(_slicedItems)
+ }, [columnCount])
+
+ // state of carusel
+ const scrolling = useRef(false)
+
+ const scroll = (index: number) => {
+ if (!carouselApi) {
+ return
+ }
+ setDot(index)
+ carouselApi.scrollTo(index)
+ stop()
+ }
+
+ const onSelect = () => {
+ if (carouselApi) {
+ setDot(carouselApi.selectedScrollSnap())
+ }
+ }
+
+ const onCaptureClick = (event: MouseEvent) => {
+ if (scrolling.current) {
+ event.preventDefault()
+ event.stopPropagation()
+ }
+ }
+
+ useEffect(() => {
+ if (!carouselApi) {
+ return
+ }
+
+ carouselApi.reInit()
+ carouselApi.scrollTo(0)
+
+ setDot(0)
+ setSnaps(carouselApi.scrollSnapList())
+
+ carouselApi.on('select', onSelect)
+ }, [carouselApi])
+
+ 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])
+
+ return (
+
+
+
+ {slicedItems?.map((its, i) => {
+ return (
+
+
+ {its?.map(
+ (
+ item: { title: string; id: string; link: string },
+ index: number
+ ) => {
+ const title = item.title || ''
+ return (
+
+ {title}
+
+ )
+ }
+ )}
+
+
+ )
+ })}
+
+
+
+
+ )
+}
+
+export default ChannelCarousel
diff --git a/src/views/Home/Channel/Page/Carousel/styles.module.css b/src/views/Home/Channel/Page/Carousel/styles.module.css
new file mode 100644
index 0000000000..6740c61bc8
--- /dev/null
+++ b/src/views/Home/Channel/Page/Carousel/styles.module.css
@@ -0,0 +1,96 @@
+.carousel {
+ position: relative;
+ width: 100%;
+ @media (--sm-up) {
+ padding: 0;
+ }
+}
+
+.footer {
+ @mixin flex-center-all;
+
+ z-index: 1;
+ margin: var(--sp16) 0 var(--sp20);
+
+ & .dots {
+ @mixin flex-center-start;
+
+ padding-left: var(--sp8);
+ }
+}
+
+.viewport {
+ width: 100%;
+ overflow: hidden;
+
+ & .container {
+ display: flex;
+ margin-left: calc(var(--sp8) * -1);
+ }
+
+ & .slide {
+ position: relative;
+ min-width: 100%;
+ }
+
+ & .content {
+ position: relative;
+ z-index: 0;
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ gap: var(--sp8) var(--sp12);
+ padding-left: var(--sp10);
+ border-radius: var(--sp16);
+
+ @media (width >= 453px) {
+ grid-template-columns: repeat(5, 1fr);
+ }
+
+ @media (width >= 561px) {
+ grid-template-columns: repeat(6, 1fr);
+ }
+
+ @media (width >= 669px) {
+ grid-template-columns: repeat(7, 1fr);
+ }
+
+ & a {
+ padding: var(--sp4) var(--sp10);
+ font-size: var(--text14);
+ line-height: 1.375rem;
+ color: var(--color-grey-darker);
+ text-align: center;
+ white-space: nowrap;
+
+ &.selectedChannel {
+ font-weight: var(--font-semibold);
+ color: var(--color-white);
+ background: var(--color-black);
+ border-radius: var(--sp8);
+ }
+ }
+
+ & p {
+ display: none;
+ }
+ }
+}
+
+.dot {
+ @mixin transition;
+
+ box-sizing: content-box;
+ box-sizing: border-box;
+ width: 12px;
+ height: 3px;
+ margin-right: var(--sp8);
+ cursor: pointer;
+ background: var(--color-grey);
+ border: 2px solid rgb(255 255 255 / 0%);
+ border-radius: var(--sp8);
+ transition-property: border-color, border-width, background-color;
+
+ &.selected {
+ border-color: var(--color-black);
+ }
+}
diff --git a/src/views/Home/Feed/MainFeed/index.tsx b/src/views/Home/Feed/MainFeed/index.tsx
index 69ba142fa7..74a9aa0056 100644
--- a/src/views/Home/Feed/MainFeed/index.tsx
+++ b/src/views/Home/Feed/MainFeed/index.tsx
@@ -21,6 +21,7 @@ import {
} from '~/gql/graphql'
import Announcements from '../../Announcements'
+import ChannelCarousel from '../../Channel/Page/Carousel'
import Authors from '../Authors'
import Billboard from '../Billboard'
import { FEED_ARTICLES_PRIVATE, FEED_ARTICLES_PUBLIC } from '../gql'
@@ -215,6 +216,9 @@ const MainFeed = ({ feedSortType: sortBy }: MainFeedProps) => {
eof
>
+
+
+
{isHottestFeed && }
{mixFeed.map((edge, i) => {
if (edge?.__typename === 'HorizontalFeed') {