From 522a1cdbaf0f478fb23a9f770b9caf732ea13803 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Tue, 29 Oct 2019 17:11:07 +0300 Subject: Hide header on scroll (mobile only) --- vnext/src/ui/Feeds.js | 137 ++++++++++++++++++++++++++----------------------- vnext/src/ui/Header.js | 134 ++++++++++++++++++++++++----------------------- 2 files changed, 140 insertions(+), 131 deletions(-) (limited to 'vnext/src/ui') diff --git a/vnext/src/ui/Feeds.js b/vnext/src/ui/Feeds.js index 8c79f779..e687f1e2 100644 --- a/vnext/src/ui/Feeds.js +++ b/vnext/src/ui/Feeds.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useRef } from 'react'; import { Link } from 'react-router-dom'; import qs from 'qs'; @@ -23,9 +23,9 @@ import { getMessages } from '../api'; * @property {import('history').History} history * @property {import('history').Location} location * @property {import('react-router').match} match - * @property {string} search + * @property {string=} search * @property {import('../api').SecureUser} visitor - * @property {import('../api').Message[]} msgs + * @property {import('../api').Message[]=} msgs */ /** @@ -101,84 +101,95 @@ export function Home(props) { } /** - * @param {{ - authRequired?: boolean, - visitor: import('../api').SecureUser, - history: import('history').History, - location: import('history').Location, - msgs: import('../api').Message[], - query: Query -}} props + * @typedef {Object} FeedState + * @property authRequired?: boolean + * @property visitor: import('../api').SecureUser + * @property history: import('history').History + * @property location: import('history').Location + * @property msgs: import('../api').Message[] + * @property query: Query + */ + +/** + * @param {FeedState} props */ function Feed(props) { - const [msgs, setMsgs] = useState([]); - const [loading, setLoading] = useState(true); - const [nextpage, setNextpage] = useState(null); - const [error, setError] = useState(false); + const [state, setState] = useState({ + history: props.history, + authRequired: props.authRequired, + query: props.query, + hash: props.visitor.hash, + filter: props.location.search.substring(1), + msgs: [], + loading: true, + nextpage: null, + error: false, + tag: '' + }); + + const stateRef = useRef(state); useEffect(() => { - let loadMessages = (hash = '', filter = '') => { - document.body.scrollTop = 0; - document.documentElement.scrollTop = 0; - setMsgs([]); - setLoading(true); - const filterParams = qs.parse(filter); - let params = Object.assign({}, filterParams || {}, props.query.search || {}); - let url = props.query.baseUrl; - if (hash) { - params.hash = hash; - } - if (!params.hash && props.authRequired) { - props.history.push('/'); - } - getMessages(url, params) - .then(response => { - const { data } = response; - const { pageParam } = props.query; - const lastMessage = data.slice(-1)[0] || {}; - const nextpage = getPageParam(pageParam, lastMessage, filterParams); - setMsgs(data); - setLoading(false); - setNextpage(nextpage); - }).catch(ex => { - setError(true); - }); + let getPageParam = (pageParam, lastMessage, filterParams) => { + const pageValue = pageParam === 'before_mid' ? lastMessage.mid : pageParam === 'page' ? (Number(filterParams.page) || 0) + 1 : moment.utc(lastMessage.updated).valueOf(); + let newFilter = { ...filterParams }; + newFilter[pageParam] = pageValue; + return `?${qs.stringify(newFilter)}`; }; - loadMessages(props.visitor.hash, props.location.search.substring(1)); - }, [props]); - - let getPageParam = (pageParam, lastMessage, filterParams) => { - const pageValue = pageParam === 'before_mid' ? lastMessage.mid : pageParam === 'page' ? (Number(filterParams.page) || 0) + 1 : moment.utc(lastMessage.updated).valueOf(); - let newFilter = { ...filterParams }; - newFilter[pageParam] = pageValue; - return `?${qs.stringify(newFilter)}`; - }; - const { tag } = qs.parse(location.search.substring(1)) || {}; - const nodes = ( - <> + document.body.scrollTop = 0; + document.documentElement.scrollTop = 0; + const filterParams = qs.parse(stateRef.current.filter); + let params = Object.assign({}, filterParams || {}, stateRef.current.query.search || {}); + let url = stateRef.current.query.baseUrl; + if (stateRef.current.hash) { + params.hash = stateRef.current.hash; + } + if (!params.hash && stateRef.current.authRequired) { + stateRef.current.history.push('/'); + } + getMessages(url, params) + .then(response => { + const { data } = response; + const { pageParam } = stateRef.current.query; + const lastMessage = data.slice(-1)[0] || {}; + const nextpage = getPageParam(pageParam, lastMessage, filterParams); + setState({ + ...stateRef.current, + msgs: data, + loading: false, + nextpage: nextpage, + tag: qs.parse(location.search.substring(1))['tag'] || '' + }); + }).catch(ex => { + setState({ + ...stateRef.current, + error: true + }); + }); + }, []); + return (state.msgs.length > 0 ? ( +
{ - tag && ( + state.tag && (

- - ← All posts with tag {tag} + + ← All posts with tag {state.tag}

) } { - msgs.map(msg => + state.msgs.map(msg => ) } { - msgs.length >= 20 && ( + state.msgs.length >= 20 && (

- Next → + Next →

) } - +
+ ) : state.error ?
error
: state.loading ?
:
No more messages
); - return msgs.length > 0 ? ( -
{nodes}
- ) : error ?
error
: loading ?
:
No more messages
; } diff --git a/vnext/src/ui/Header.js b/vnext/src/ui/Header.js index 2d042bfe..a7663dd3 100644 --- a/vnext/src/ui/Header.js +++ b/vnext/src/ui/Header.js @@ -1,73 +1,71 @@ -import React, { useEffect, useCallback, useRef } from 'react'; -import ReactDOM from 'react-dom'; -import PropTypes from 'prop-types'; +import React, { memo } from 'react'; +import { Link, withRouter } from 'react-router-dom'; -const elClassHidden = 'header--hidden'; +import Icon from './Icon'; +import { UserLink } from './UserInfo'; +import SearchBox from './SearchBox'; -const header = document.getElementById('header'); +function Header({ visitor, search, className }) { + return ( + + ); } -Header.propTypes = { - children: PropTypes.node -}; +export default memo(withRouter(Header)); -- cgit v1.2.3