diff --git a/src/app.css b/src/app.css index bad39b57..d51c0417 100644 --- a/src/app.css +++ b/src/app.css @@ -106,8 +106,10 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) { border-bottom: var(--hairline-width) solid var(--divider-color); min-height: 3em; display: grid; - grid-template-columns: 1fr 1fr 1fr; + grid-template-columns: 1fr 2fr 1fr; align-items: center; + text-overflow: ellipsis; + white-space: nowrap; } .deck > header .header-grid > .header-side:last-of-type { text-align: right; @@ -121,7 +123,6 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) { padding: 0; font-size: 1.2em; text-align: center; - white-space: nowrap; } .deck > header .header-grid h1:first-child { text-align: left; @@ -1252,7 +1253,7 @@ meter.donut:is(.danger, .explode):after { .updates-button { margin-top: 24px; } - .timeline-deck .timeline:not(.flat) > li { + .timeline:not(.flat) > li { border: 1px solid var(--divider-color); margin: 16px 0; background-color: var(--bg-color); @@ -1262,15 +1263,13 @@ meter.donut:is(.danger, .explode):after { transition: transform 0.4s var(--timing-function); --back-transition: transform 0.4s ease-out; } - .timeline-deck .timeline:not(.flat) > li:has(.status-link.is-active) { + .timeline:not(.flat) > li:has(.status-link.is-active) { transition: var(--back-transition); transform: translate3d(-2.5vw, 0, 0); } - .timeline-deck - .timeline:not(.flat) + .timeline:not(.flat) > li:not(:has(.boost-carousel)):has(+ li .status-link.is-active), - .timeline-deck - .timeline:not(.flat) + .timeline:not(.flat) > li:not(:has(.boost-carousel)):has(.status-link.is-active) + li { transition: var(--back-transition); diff --git a/src/app.jsx b/src/app.jsx index 602567bf..f43c470e 100644 --- a/src/app.jsx +++ b/src/app.jsx @@ -39,6 +39,7 @@ import Lists from './pages/lists'; import Login from './pages/login'; import Notifications from './pages/notifications'; import Public from './pages/public'; +import Search from './pages/search'; import Settings from './pages/settings'; import Status from './pages/status'; import Welcome from './pages/welcome'; @@ -215,7 +216,7 @@ function App() { } /> } /> - {/* } /> */} + } /> {/* } /> */} diff --git a/src/components/menu.jsx b/src/components/menu.jsx new file mode 100644 index 00000000..5b7508ff --- /dev/null +++ b/src/components/menu.jsx @@ -0,0 +1,55 @@ +import { FocusableItem, Menu, MenuDivider, MenuItem } from '@szhsin/react-menu'; + +import states from '../utils/states'; + +import Icon from './icon'; +import Link from './link'; + +function NavMenu(props) { + return ( + + + + } + > + + Home + + + Bookmarks + + + Favourites + + + { + states.showSettings = true; + }} + > + Settings + + + ); +} + +function MenuLink(props) { + return ( + + {({ ref, closeMenu }) => ( + + closeMenu(detail === 0 ? 'Enter' : undefined) + } + /> + )} + + ); +} + +export default NavMenu; diff --git a/src/components/timeline.jsx b/src/components/timeline.jsx index b5a5c835..b5c88c8b 100644 --- a/src/components/timeline.jsx +++ b/src/components/timeline.jsx @@ -1,9 +1,7 @@ -import { FocusableItem, Menu, MenuDivider, MenuItem } from '@szhsin/react-menu'; import { useEffect, useRef, useState } from 'preact/hooks'; import { useHotkeys } from 'react-hotkeys-hook'; import { useDebouncedCallback } from 'use-debounce'; -import states from '../utils/states'; import useInterval from '../utils/useInterval'; import usePageVisibility from '../utils/usePageVisibility'; import useScroll from '../utils/useScroll'; @@ -11,6 +9,7 @@ import useScroll from '../utils/useScroll'; import Icon from './icon'; import Link from './link'; import Loader from './loader'; +import Menu from './menu'; import Status from './status'; function Timeline({ @@ -257,31 +256,10 @@ function Timeline({
- - - } - > - - Home - - - Bookmarks - - - Favourites - - - { - states.showSettings = true; - }} - > - {' '} - Settings - - + portal={{ + target: scrollableRef.current, + }} + /> {headerStart !== null && headerStart !== undefined ? ( headerStart ) : ( @@ -409,22 +387,6 @@ function Timeline({ ); } -function MenuLink(props) { - return ( - - {({ ref, closeMenu }) => ( - - closeMenu(detail === 0 ? 'Enter' : undefined) - } - /> - )} - - ); -} - function groupBoosts(values) { let newValues = []; let boostStash = []; diff --git a/src/pages/notifications.jsx b/src/pages/notifications.jsx index 8a7c01ab..4e27f943 100644 --- a/src/pages/notifications.jsx +++ b/src/pages/notifications.jsx @@ -8,6 +8,7 @@ import Avatar from '../components/avatar'; import Icon from '../components/icon'; import Link from '../components/link'; import Loader from '../components/loader'; +import Menu from '../components/menu'; import NameText from '../components/name-text'; import RelativeTime from '../components/relative-time'; import Status from '../components/status'; @@ -145,6 +146,11 @@ function Notifications() { >
+ diff --git a/src/pages/search.css b/src/pages/search.css new file mode 100644 index 00000000..3580eb90 --- /dev/null +++ b/src/pages/search.css @@ -0,0 +1,29 @@ +#search-page header input { + width: 100%; + padding: 8px 16px; + border: 0; + border-radius: 999px; + background-color: var(--bg-faded-color); +} +#search-page header input:focus { + background-color: var(--bg-color); + outline: 2px solid var(--link-color); +} + +#search-page ul.accounts-list { + display: flex; + flex-wrap: wrap; +} +#search-page ul.accounts-list li { + flex-basis: 320px; + display: flex; + padding: 8px 16px; + gap: 8px; + align-items: center; +} + +@media (min-width: 40em) { + #search-page header input { + background-color: var(--bg-color); + } +} diff --git a/src/pages/search.jsx b/src/pages/search.jsx new file mode 100644 index 00000000..05467cf0 --- /dev/null +++ b/src/pages/search.jsx @@ -0,0 +1,104 @@ +import './search.css'; + +import { useEffect, useRef, useState } from 'preact/hooks'; +import { useSearchParams } from 'react-router-dom'; + +import Avatar from '../components/avatar'; +import Link from '../components/link'; +import Menu from '../components/menu'; +import NameText from '../components/name-text'; +import Status from '../components/status'; +import { api } from '../utils/api'; + +function Search() { + const { masto, instance, authenticated } = api(); + const [searchParams, setSearchParams] = useSearchParams(); + const searchFieldRef = useRef(); + const q = searchParams.get('q'); + const [statusResults, setStatusResults] = useState([]); + const [accountResults, setAccountResults] = useState([]); + useEffect(() => { + if (q) { + searchFieldRef.current.value = q; + + (async () => { + const results = await masto.v2.search({ + q, + limit: 20, + resolve: authenticated, + }); + console.log(results); + setStatusResults(results.statuses); + setAccountResults(results.accounts); + })(); + } + }, [q]); + + console.log({ accountResults }); + + return ( +
+
+
+
+
+ +
+
{ + e.preventDefault(); + const { q } = e.target; + if (q.value) { + setSearchParams({ q: q.value }); + } + }} + > + +
+
+
+
+
+

Accounts

+ {accountResults.length > 0 && ( +
    + {accountResults.map((account) => ( +
  • + + +
  • + ))} +
+ )} +

Posts

+ {statusResults.length > 0 && ( +
    + {statusResults.map((status) => ( +
  • + + + +
  • + ))} +
+ )} +
+
+
+ ); +} + +export default Search;