improvements

- add sidebar-stack
- add control-btn-label
- better locating dz
- enable reply_rev when 1 reply
- replace latest_post_id when page=1
This commit is contained in:
xmcp
2020-01-10 00:43:31 +08:00
parent 436ec949cb
commit 2fdca50762
10 changed files with 236 additions and 68 deletions

View File

@@ -17,8 +17,7 @@ class App extends Component {
load_config();
listen_darkmode({default: undefined, light: false, dark: true}[window.config.color_scheme]);
this.state={
sidebar_title: null,
sidebar_content: null, // determine status of sidebar
sidebar_stack: [[null,null]], // list of [status, content]
mode: 'list', // list, single, search, attention
search_text: null,
flow_render_key: +new Date(),
@@ -41,20 +40,39 @@ class App extends Component {
}
on_pressure() {
if(this.state.sidebar_title!==null)
this.setState((prevState)=>({
sidebar_title: null,
sidebar_content: prevState.sidebar_content,
}));
if(this.state.sidebar_stack.length>1)
this.show_sidebar(null,null,'clear');
else
this.set_mode('list',null);
}
show_sidebar(title,content) {
this.setState({
sidebar_title: title,
sidebar_content: content,
});
show_sidebar(title,content,mode='push') {
if(mode==='push') {
this.setState((prevState)=>({
sidebar_stack: prevState.sidebar_stack.concat([[title,content]]),
}));
} else if(mode==='pop') {
this.setState((prevState)=>{
let ns=prevState.sidebar_stack.slice();
ns.pop();
return {
sidebar_stack: ns,
};
});
} else if(mode==='replace') {
this.setState((prevState)=>{
let ns=prevState.sidebar_stack.slice();
ns.pop();
return {
sidebar_stack: ns.concat([[title,content]]),
};
});
} else if(mode==='clear') {
this.setState({
sidebar_stack: [[null,null]],
});
} else
throw new Error('bad show_sidebar mode');
}
set_mode(mode,search_text) {
@@ -102,11 +120,7 @@ class App extends Component {
<br />
</div>
)}</TokenCtx.Consumer>
<Sidebar do_close={()=>{
this.setState({
sidebar_title: null,
});
}} content={this.state.sidebar_content} title={this.state.sidebar_title} />
<Sidebar show_sidebar={this.show_sidebar_bound} stack={this.state.sidebar_stack} />
</TokenCtx.Provider>
);
}

View File

@@ -19,10 +19,12 @@ const QUOTE_BLACKLIST=['23333','233333','66666','666666','10086','10000','100000
window.LATEST_POST_ID=parseInt(localStorage['_LATEST_POST_ID'],10)||0;
const DZ_NAME='洞主';
function load_single_meta(show_sidebar,token,parents) {
return (pid)=>{
let title_elem=<FlowSidebarTitle pid={pid} parents={parents} show_sidebar={show_sidebar} token={token} />;
const color_picker=new ColorPicker();
let color_picker=new ColorPicker();
let title_elem='树洞 #'+pid;
show_sidebar(
title_elem,
<div className="box box-tip">
@@ -46,7 +48,8 @@ function load_single_meta(show_sidebar,token,parents) {
info={single.data} replies={replies.data} attention={replies.attention}
token={token} show_sidebar={show_sidebar} color_picker={color_picker}
deletion_detect={localStorage['DELETION_DETECT']==='on'} parents={parents}
/>
/>,
'replace'
)
})
.catch((e)=>{
@@ -56,7 +59,8 @@ function load_single_meta(show_sidebar,token,parents) {
<div className="box box-tip">
<p><a onClick={()=>load_single_meta(show_sidebar,token,parents)(pid)}>重新加载</a></p>
<p>{''+e}</p>
</div>
</div>,
'replace'
);
})
};
@@ -142,6 +146,11 @@ class FlowItem extends PureComponent {
<div className="flow-item-dot" />
}
<div className="box-header">
{!!this.props.do_filter_name &&
<span className="reply-header-badge clickable" onClick={()=>{this.props.do_filter_name(DZ_NAME);}}>
<span className="icon icon-locate" />
</span>
}
{!!parseInt(props.info.likenum,10) &&
<span className="box-header-badge">
{props.info.likenum}&nbsp;
@@ -334,18 +343,20 @@ class FlowSidebar extends PureComponent {
// key for lazyload elem
let view_mode_key=(this.state.rev ? 'y-' : 'n-')+(this.state.filter_name||'null');
let replies_cnt={};
let replies_cnt={[DZ_NAME]:1};
replies_to_show.forEach((r)=>{
if(replies_cnt[r.name]===undefined)
replies_cnt[r.name]=0;
replies_cnt[r.name]++;
});
let main_thread_elem=(
// hide main thread when filtered
let main_thread_elem=(this.state.filter_name && this.state.filter_name!==DZ_NAME) ? null : (
<ClickHandler callback={(e)=>{this.show_reply_bar('',e);}}>
<FlowItem info={this.state.info} attention={this.state.attention} img_clickable={true}
color_picker={this.color_picker} show_pid={show_pid} replies={this.state.replies}
set_variant={(variant)=>{this.set_variant(null,variant);}}
do_filter_name={replies_cnt[DZ_NAME]>1 ? this.set_filter_name.bind(this) : null}
/>
</ClickHandler>
);
@@ -364,7 +375,7 @@ class FlowSidebar extends PureComponent {
<a onClick={this.load_replies.bind(this)}>
<span className="icon icon-refresh" /><label>刷新</label>
</a>
{(this.state.replies.length>1 || this.state.rev) &&
{(this.state.replies.length>=1 || this.state.rev) &&
<span>
&nbsp;&nbsp;
<a onClick={this.toggle_rev.bind(this)}>
@@ -386,6 +397,15 @@ class FlowSidebar extends PureComponent {
</span>
}
</div>
{!!this.state.filter_name &&
<div className="box box-tip flow-item filter-name-bar">
<p>
<span style={{float: 'left'}}><a onClick={()=>{this.set_filter_name(null)}}>还原</a></span>
<span className="icon icon-locate" />&nbsp;当前只看&nbsp;
<ColoredSpan colors={this.color_picker.get(this.state.filter_name)}>{this.state.filter_name}</ColoredSpan>
</p>
</div>
}
{!this.state.rev &&
main_thread_elem
}
@@ -400,15 +420,6 @@ class FlowSidebar extends PureComponent {
{parseInt(this.state.info.reply)-this.state.replies.length} 条回复被删除
</div>
}
{!!this.state.filter_name &&
<div className="box box-tip flow-item filter-name-bar">
<p>
<span style={{float: 'left'}}><a onClick={()=>{this.set_filter_name(null)}}>还原</a></span>
<span className="icon icon-locate" />&nbsp;当前只看&nbsp;
<ColoredSpan colors={this.color_picker.get(this.state.filter_name)}>{this.state.filter_name}</ColoredSpan>
</p>
</div>
}
{replies_to_show.map((reply)=>(
<LazyLoad key={reply.cid+view_mode_key} offset={1500} height="5em" overflow={true} once={true}>
<ClickHandler callback={(e)=>{this.show_reply_bar(reply.name,e);}}>
@@ -433,24 +444,6 @@ class FlowSidebar extends PureComponent {
}
}
function FlowSidebarTitle(props) {
let last_pid=props.parents.length ? props.parents[props.parents.length-1] : null;
return (
<span>
树洞&nbsp;
{!!last_pid &&
<span>
<a onClick={()=>load_single_meta(props.show_sidebar,props.token,props.parents.slice(0,-1))(last_pid)}>
#{last_pid}
</a>
&nbsp;&nbsp;
</span>
}
#{props.pid}
</span>
);
}
class FlowItemRow extends PureComponent {
constructor(props) {
super(props);
@@ -499,7 +492,7 @@ class FlowItemRow extends PureComponent {
show_sidebar() {
this.props.show_sidebar(
<FlowSidebarTitle pid={this.state.info.pid} parents={[]} show_sidebar={this.props.show_sidebar} token={this.props.token} />,
'树洞 #'+this.state.info.pid,
<FlowSidebar key={+new Date()}
info={this.state.info} replies={this.state.replies} attention={this.state.attention} sync_state={this.setState.bind(this)}
token={this.props.token} show_sidebar={this.props.show_sidebar} color_picker={this.color_picker}
@@ -692,11 +685,14 @@ export class Flow extends PureComponent {
if(this.state.mode==='list') {
API.get_list(page,this.props.token)
.then((json)=>{
if(page===1)
if(page===1 && json.data.length) { // update latest_post_id
let max_id=-1;
json.data.forEach((x)=>{
if(parseInt(x.pid,10)>(parseInt(localStorage['_LATEST_POST_ID'],10)||0))
localStorage['_LATEST_POST_ID']=x.pid;
if(parseInt(x.pid,10)>max_id)
max_id=parseInt(x.pid,10);
});
localStorage['_LATEST_POST_ID']=''+max_id;
}
this.setState((prev,props)=>({
chunks: {
title: 'News Feed',

View File

@@ -5,26 +5,39 @@ export class Sidebar extends PureComponent {
constructor(props) {
super(props);
this.sidebar_ref=React.createRef();
this.do_close_bound=this.do_close.bind(this);
this.do_back_bound=this.do_back.bind(this);
}
componentDidUpdate(nextProps) {
if(this.props.content!==nextProps.content) {
if(this.props.stack!==nextProps.stack) {
//console.log('sidebar top');
if(this.sidebar_ref.current)
this.sidebar_ref.current.scrollTop=0;
}
}
do_close() {
this.props.show_sidebar(null,null,'clear');
}
do_back() {
this.props.show_sidebar(null,null,'pop');
}
render() {
let [cur_title,cur_content]=this.props.stack[this.props.stack.length-1];
return (
<div className={this.props.title!==null ? 'sidebar-on' : ''}>
<div className="sidebar-shadow" onClick={this.props.do_close} onTouchEnd={(e)=>{e.preventDefault();e.target.click();}} />
<div className={cur_title!==null ? 'sidebar-on' : ''}>
<div className="sidebar-shadow" onClick={this.do_back_bound} onTouchEnd={(e)=>{e.preventDefault();e.target.click();}} />
<div ref={this.sidebar_ref} className="sidebar">
{this.props.content}
{cur_content}
</div>
<div className="sidebar-title">
<a className="no-underline" onClick={this.props.do_close}>&nbsp;<span className="icon icon-back" />&nbsp;</a>
{this.props.title}
<a className="no-underline" onClick={this.do_close_bound}>&nbsp;<span className="icon icon-close" />&nbsp;</a>
{this.props.stack.length>2 &&
<a className="no-underline" onClick={this.do_back_bound}>&nbsp;<span className="icon icon-back" />&nbsp;</a>
}
{cur_title}
</div>
</div>
);

View File

@@ -23,7 +23,7 @@
}
.control-btn {
flex: 0 0 2em;
flex: 0 0 4.5em;
text-align: center;
color: black;
border-radius: 5px;
@@ -32,6 +32,17 @@
background-color: #555555;
color: white;
}
.control-btn-label {
margin-left: .25em;
}
@media screen and (max-width: 900px) {
.control-btn {
flex: 0 0 2em;
}
.control-btn-label {
display: none;
}
}
.root-dark-mode .control-btn {
color: var(--foreground-dark);
@@ -42,11 +53,6 @@
opacity: 1;
}
.control-btn .icon:before {
margin: .5em;
display: inline-block;
}
.control-search {
flex: auto;
color: black;

View File

@@ -132,10 +132,12 @@ class ControlBar extends PureComponent {
<div className="control-bar">
<a className="no-underline control-btn" onClick={this.do_refresh_bound}>
<span className="icon icon-refresh" />
<span className="control-btn-label">最新</span>
</a>
{!!token &&
<a className="no-underline control-btn" onClick={this.do_attention_bound}>
<span className="icon icon-attention" />
<span className="control-btn-label">关注</span>
</a>
}
<input className="control-search" value={this.state.search_text} placeholder="搜索 或 #PID"
@@ -168,6 +170,7 @@ class ControlBar extends PureComponent {
)
}}>
<span className={'icon icon-'+(token ? 'about' : 'login')} />
<span className="control-btn-label">{token ? '账户' : '登录'}</span>
</a>
{!!token &&
<a className="no-underline control-btn" onClick={()=>{
@@ -180,6 +183,7 @@ class ControlBar extends PureComponent {
)
}}>
<span className="icon icon-plus" />
<span className="control-btn-label">发表</span>
</a>
}
</div>