{title}
} +{description}
+ )} +diff --git a/src/pages/trending.css b/src/pages/trending.css new file mode 100644 index 00000000..ca743f75 --- /dev/null +++ b/src/pages/trending.css @@ -0,0 +1,184 @@ +.links-bar { + position: relative; + display: flex; + padding: 16px 16px 20px calc(16px + 1em + 12px); + gap: 16px; + overflow-x: auto; + background-color: var(--bg-faded-color); + mask-image: linear-gradient( + to right, + transparent, + black 16px, + black calc(100% - 16px), + transparent + ); + text-shadow: 0 1px var(--bg-blur-color); + transition: opacity 0.3s ease-out; + + &:not(#columns &) { + @media (min-width: 40em) { + width: 95vw; + max-width: calc(320px * 3.3); + transform: translateX(calc(-50% + var(--main-width) / 2)); + } + } + + h3 { + font-size: 90%; + font-style: italic; + margin: 0; + padding: 0; + text-transform: uppercase; + color: var(--text-insignificant-color); + position: absolute; + top: calc(16px + 8px); + left: 16px; + transform-origin: top left; + transform: rotate(-90deg) translateX(-100%); + user-select: none; + background-image: linear-gradient( + to left, + var(--text-color), + var(--link-color) + ); + background-clip: text; + text-fill-color: transparent; + -webkit-text-fill-color: transparent; + } + + a { + --other-color: var(--light-color); + @media (prefers-color-scheme: dark) { + --other-color: var(--dark-color); + } + min-width: 240px; + text-decoration: none; + color: inherit; + border-radius: 16px; + overflow: hidden; + background-color: var(--other-color); + border: 4px solid transparent; + box-shadow: 0 4px 8px -2px var(--drop-shadow-color); + transition: all 0.15s ease-out; + display: flex; + background-image: linear-gradient( + to bottom, + var(--average-color) -50%, + transparent + ); + background-clip: border-box; + background-origin: border-box; + height: 320px; + + &:not(:active):is(:hover, :focus-visible) { + border-color: var(--average-color); + box-shadow: 0 4px 8px var(--drop-shadow-color), + 0 8px 16px var(--drop-shadow-color); + transform-origin: center bottom; + transform: scale(1.02); + + img { + animation: position-object 5s ease-in-out 1s 5; + } + } + + &:active { + transition: none; + transform: scale(1.015); + filter: brightness(0.8); + } + + article { + display: flex; + flex-direction: column; + justify-content: flex-end; + background-color: var(--bg-color); + background-repeat: no-repeat; + background-image: linear-gradient( + to bottom, + var(--other-color) 70%, + var(--bg-color) 100% + ); + transition: background-position-y 0.15s ease-out; + + &:is(:hover, :focus-visible) { + background-position-y: -40px; + } + + figure { + flex-grow: 1; + margin: 0 0 -16px; + padding: 0; + position: relative; + } + + img { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + object-fit: cover; + vertical-align: top; + mask-image: linear-gradient( + to bottom, + hsl(0, 0%, 0%) 0%, + hsla(0, 0%, 0%, 0.987) 14%, + hsla(0, 0%, 0%, 0.951) 26.2%, + hsla(0, 0%, 0%, 0.896) 36.8%, + hsla(0, 0%, 0%, 0.825) 45.9%, + hsla(0, 0%, 0%, 0.741) 53.7%, + hsla(0, 0%, 0%, 0.648) 60.4%, + hsla(0, 0%, 0%, 0.55) 66.2%, + hsla(0, 0%, 0%, 0.45) 71.2%, + hsla(0, 0%, 0%, 0.352) 75.6%, + hsla(0, 0%, 0%, 0.259) 79.6%, + hsla(0, 0%, 0%, 0.175) 83.4%, + hsla(0, 0%, 0%, 0.104) 87.2%, + hsla(0, 0%, 0%, 0.049) 91.1%, + hsla(0, 0%, 0%, 0.013) 95.3%, + hsla(0, 0%, 0%, 0) 100% + ); + } + } + + .article-body { + padding: 0 8px 8px; + line-height: 1.3; + flex-shrink: 0; + } + + .article-meta { + color: var(--text-insignificant-color); + font-size: 90%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + &:hover .domain { + color: var(--link-text-color); + } + + h1 { + font-weight: normal; + font-size: inherit; + margin: 0; + padding: 0; + text-wrap: balance; + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; + } + + p { + color: var(--text-insignificant-color); + margin: 0; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + font-size: 90%; + } + } +} diff --git a/src/pages/trending.jsx b/src/pages/trending.jsx index d22d08c9..a85278d5 100644 --- a/src/pages/trending.jsx +++ b/src/pages/trending.jsx @@ -1,4 +1,7 @@ +import './trending.css'; + import { MenuItem } from '@szhsin/react-menu'; +import { getBlurHashAverageColor } from 'fast-blurhash'; import { useMemo, useRef, useState } from 'preact/hooks'; import { useNavigate, useParams } from 'react-router-dom'; import { useSnapshot } from 'valtio'; @@ -6,15 +9,27 @@ import { useSnapshot } from 'valtio'; import Icon from '../components/icon'; import Link from '../components/link'; import Menu2 from '../components/menu2'; +import RelativeTime from '../components/relative-time'; import Timeline from '../components/timeline'; import { api } from '../utils/api'; import { filteredItems } from '../utils/filters'; +import pmem from '../utils/pmem'; import states from '../utils/states'; import { saveStatus } from '../utils/states'; import useTitle from '../utils/useTitle'; const LIMIT = 20; +const fetchLinks = pmem( + (masto) => { + return masto.v1.trends.links.list().next(); + }, + { + // News last much longer + maxAge: 10 * 60 * 1000, // 10 minutes + }, +); + function Trending({ columnMode, ...props }) { const snapStates = useSnapshot(states); const params = columnMode ? {} : useParams(); @@ -27,6 +42,7 @@ function Trending({ columnMode, ...props }) { const latestItem = useRef(); const [hashtags, setHashtags] = useState([]); + const [links, setLinks] = useState([]); const trendIterator = useRef(); async function fetchTrend(firstLoad) { if (firstLoad || !trendIterator.current) { @@ -38,11 +54,20 @@ function Trending({ columnMode, ...props }) { try { const iterator = masto.v1.trends.tags.list(); const { value: tags } = await iterator.next(); - console.log(tags); + console.log('tags', tags); setHashtags(tags); } catch (e) { console.error(e); } + + // Get links + try { + const { value: links } = await fetchLinks(masto); + console.log('links', links); + setLinks(links); + } catch (e) { + console.error(e); + } } const results = await trendIterator.current.next(); let { value } = results; @@ -84,26 +109,125 @@ function Trending({ columnMode, ...props }) { } const TimelineStart = useMemo(() => { - if (!hashtags.length) return null; return ( -
+ <> + {!!hashtags.length && ( + + )} + {!!links.length && ( + + )} + > ); - }, [hashtags]); + }, [hashtags, links]); return (