ux update
This commit is contained in:
@@ -1,3 +1,7 @@
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.bg-img {
|
||||
position: fixed;
|
||||
z-index: -1;
|
||||
@@ -45,4 +49,13 @@
|
||||
|
||||
.root-dark-mode .colored-span {
|
||||
background-color: var(--coloredspan-bgcolor-dark);
|
||||
}
|
||||
|
||||
.icon+label {
|
||||
font-size: .9em;
|
||||
vertical-align: .05em;
|
||||
cursor: inherit;
|
||||
}
|
||||
.icon+label::before {
|
||||
content: ' ';
|
||||
}
|
||||
@@ -17,7 +17,7 @@ export function build_highlight_re(txt,split) {
|
||||
return txt ? new RegExp(`(${txt.split(split).filter((x)=>!!x).map(escape_regex).join('|')})`,'g') : /^$/g;
|
||||
}
|
||||
|
||||
function ColoredSpan(props) {
|
||||
export function ColoredSpan(props) {
|
||||
return (
|
||||
<span className="colored-span" style={{
|
||||
'--coloredspan-bgcolor-light': props.colors[0],
|
||||
|
||||
@@ -266,4 +266,15 @@
|
||||
|
||||
.root-dark-mode .box-header-tag {
|
||||
background-color: #00a;
|
||||
}
|
||||
|
||||
.filter-name-bar {
|
||||
animation: slide-in-from-top .15s ease-out;
|
||||
position: sticky;
|
||||
top: 1em;
|
||||
}
|
||||
|
||||
@keyframes slide-in-from-top {
|
||||
0% {opacity: 0; transform: translateY(-50%);}
|
||||
100% {opacity: 1;}
|
||||
}
|
||||
76
src/Flows.js
76
src/Flows.js
@@ -2,7 +2,7 @@ import React, {Component, PureComponent} from 'react';
|
||||
import copy from 'copy-to-clipboard';
|
||||
import {ColorPicker} from './color_picker';
|
||||
import {split_text, NICKNAME_RE, PID_RE, URL_RE, URL_PID_RE} from './text_splitter';
|
||||
import {format_time, build_highlight_re, Time, TitleLine, HighlightedText, ClickHandler} from './Common';
|
||||
import {format_time, build_highlight_re, Time, TitleLine, HighlightedText, ClickHandler, ColoredSpan} from './Common';
|
||||
import './Flows.css';
|
||||
import LazyLoad from './react-lazyload/src';
|
||||
import {AudioWidget} from './AudioWidget';
|
||||
@@ -78,13 +78,19 @@ class Reply extends PureComponent {
|
||||
['pid',PID_RE],
|
||||
['nickname',NICKNAME_RE],
|
||||
]);
|
||||
|
||||
return (
|
||||
<div className={'flow-reply box'} style={this.props.info._display_color ? {
|
||||
'--box-bgcolor-light': this.props.info._display_color[0],
|
||||
'--box-bgcolor-dark': this.props.info._display_color[1],
|
||||
} : null}>
|
||||
<div className="box-header">
|
||||
<code className="box-id">#{this.props.info.cid}</code>
|
||||
{this.props.do_filter_name ?
|
||||
<span className="clickable box-id" onClick={()=>{this.props.do_filter_name(this.props.info.name);}}>
|
||||
<span className="icon icon-locate" /> <code>#{this.props.info.cid}</code>
|
||||
</span> :
|
||||
<code className="box-id">#{this.props.info.cid}</code>
|
||||
}
|
||||
|
||||
{this.props.info.tag!==null &&
|
||||
<span className="box-header-tag">
|
||||
@@ -191,24 +197,14 @@ class FlowSidebar extends PureComponent {
|
||||
replies: props.replies,
|
||||
loading_status: 'done',
|
||||
error_msg: null,
|
||||
dz_only: false,
|
||||
filter_name: null,
|
||||
rev: false,
|
||||
};
|
||||
this.color_picker=props.color_picker;
|
||||
this.syncState=props.sync_state||(()=>{});
|
||||
this.reply_ref=React.createRef();
|
||||
}
|
||||
|
||||
/*componentWillReceiveProps(nextProps) {
|
||||
this.setState({
|
||||
attention: nextProps.attention,
|
||||
info: nextProps.info,
|
||||
replies: nextProps.replies,
|
||||
loading_status: 'done',
|
||||
});
|
||||
this.color_picker=nextProps.color_picker;
|
||||
this.syncState=nextProps.sync_state||(()=>{});
|
||||
}*/ // refactored to use key instead
|
||||
|
||||
set_variant(cid,variant) {
|
||||
this.setState((prev)=>{
|
||||
if(cid)
|
||||
@@ -305,14 +301,20 @@ class FlowSidebar extends PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
toggle_dz_only() {
|
||||
set_filter_name(name) {
|
||||
this.setState((prevState)=>({
|
||||
dz_only: !prevState.dz_only,
|
||||
filter_name: name===prevState.filter_name ? null : name,
|
||||
}));
|
||||
}
|
||||
|
||||
toggle_rev() {
|
||||
this.setState((prevState)=>({
|
||||
rev: !prevState.rev,
|
||||
}));
|
||||
}
|
||||
|
||||
show_reply_bar(name,event) {
|
||||
if(this.reply_ref.current && !event.target.closest('a')) {
|
||||
if(this.reply_ref.current && !event.target.closest('a, .clickable')) {
|
||||
let text=this.reply_ref.current.get();
|
||||
if(/^\s*(?:Re (?:|洞主|(?:[A-Z][a-z]+ )?(?:[A-Z][a-z]+)):)?\s*$/.test(text)) {// text is nearly empty so we can replace it
|
||||
let should_text='Re '+name+': ';
|
||||
@@ -330,29 +332,39 @@ class FlowSidebar extends PureComponent {
|
||||
|
||||
let show_pid=load_single_meta(this.props.show_sidebar,this.props.token,this.props.parents.concat([this.state.info.pid]));
|
||||
|
||||
let replies_to_show=this.state.dz_only ? this.state.replies.filter((r)=>r.islz) : this.state.replies;
|
||||
let replies_to_show=this.state.filter_name ? this.state.replies.filter((r)=>r.name===this.state.filter_name) : this.state.replies.slice();
|
||||
if(this.state.rev) replies_to_show.reverse();
|
||||
|
||||
// key for lazyload elem
|
||||
let view_mode_key=(this.state.rev ? 'y-' : 'n-')+(this.state.filter_name||'null');
|
||||
|
||||
return (
|
||||
<div className="flow-item-row sidebar-flow-item">
|
||||
<div className="box box-tip">
|
||||
{!!this.props.token &&
|
||||
<span>
|
||||
<a onClick={this.report.bind(this)}>举报</a>
|
||||
/
|
||||
<a onClick={this.report.bind(this)}>
|
||||
<span className="icon icon-flag" /><label>举报</label>
|
||||
</a>
|
||||
|
||||
</span>
|
||||
}
|
||||
<a onClick={this.load_replies.bind(this)}>刷新回复</a>
|
||||
/
|
||||
<a onClick={this.toggle_dz_only.bind(this)}>{this.state.dz_only ? '查看全部' : '只看洞主'}</a>
|
||||
<a onClick={this.load_replies.bind(this)}>
|
||||
<span className="icon icon-refresh" /><label>刷新</label>
|
||||
</a>
|
||||
|
||||
<a onClick={this.toggle_rev.bind(this)}>
|
||||
<span className="icon icon-order-rev" /><label>{this.state.rev ? '还原' : '逆序'}</label>
|
||||
</a>
|
||||
{!!this.props.token &&
|
||||
<span>
|
||||
/
|
||||
|
||||
<a onClick={()=>{
|
||||
this.toggle_attention();
|
||||
}}>
|
||||
{this.state.attention ?
|
||||
<span><span className="icon icon-star-ok" /> 已关注</span> :
|
||||
<span><span className="icon icon-star" /> 未关注</span>
|
||||
<span><span className="icon icon-star-ok" /><label>已关注</label></span> :
|
||||
<span><span className="icon icon-star" /><label>未关注</label></span>
|
||||
}
|
||||
</a>
|
||||
</span>
|
||||
@@ -375,12 +387,22 @@ 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" /> 当前只看
|
||||
<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+(+this.state.dz_only)} offset={1500} height="5em" overflow={true} once={true}>
|
||||
<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);}}>
|
||||
<Reply
|
||||
info={reply} color_picker={this.color_picker} show_pid={show_pid}
|
||||
set_variant={(variant)=>{this.set_variant(reply.cid,variant);}}
|
||||
do_filter_name={this.set_filter_name.bind(this)}
|
||||
/>
|
||||
</ClickHandler>
|
||||
</LazyLoad>
|
||||
|
||||
16
src/Title.js
16
src/Title.js
@@ -151,11 +151,17 @@ class ControlBar extends PureComponent {
|
||||
<a onClick={()=>{this.props.show_sidebar(
|
||||
'设置',
|
||||
<ConfigUI />
|
||||
)}}>网页版树洞设置</a>
|
||||
/
|
||||
<a href="http://pkuhelper.pku.edu.cn/treehole_rules.html" target="_blank">树洞规范</a>
|
||||
/
|
||||
<a href="https://github.com/pkuhelper-web/webhole/issues" target="_blank">意见反馈 <span className="icon icon-github" /></a>
|
||||
)}}>
|
||||
<span className="icon icon-settings" /><label>网页版树洞设置</label>
|
||||
</a>
|
||||
|
||||
<a href="http://pkuhelper.pku.edu.cn/treehole_rules.html" target="_blank">
|
||||
<span className="icon icon-textfile" /><label>树洞规范</label>
|
||||
</a>
|
||||
|
||||
<a href="https://github.com/pkuhelper-web/webhole/issues" target="_blank">
|
||||
<span className="icon icon-github" /><label>意见反馈</label>
|
||||
</a>
|
||||
</div>
|
||||
{HELP_TEXT}
|
||||
</div>
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
}
|
||||
.reply-form button {
|
||||
flex: 0 0 3em;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.post-form-bar {
|
||||
@@ -51,6 +52,7 @@
|
||||
}
|
||||
.post-form-bar button {
|
||||
flex: 0 0 8em;
|
||||
margin-right: 0;
|
||||
}
|
||||
.post-form-img-tip {
|
||||
font-size: small;
|
||||
|
||||
@@ -197,7 +197,9 @@ export class LoginForm extends Component {
|
||||
<div>
|
||||
<p>
|
||||
<b>您已登录。</b>
|
||||
<button type="button" onClick={()=>{token.set_value(null);}}>注销</button>
|
||||
<button type="button" onClick={()=>{token.set_value(null);}}>
|
||||
<span className="icon icon-logout" /> 注销
|
||||
</button>
|
||||
<br />
|
||||
</p>
|
||||
<p>
|
||||
|
||||
@@ -27,6 +27,7 @@ input, textarea {
|
||||
border-radius: 5px;
|
||||
border: 1px solid black;
|
||||
outline: none;
|
||||
margin: 0;
|
||||
}
|
||||
input {
|
||||
padding: 0 1em;
|
||||
|
||||
Reference in New Issue
Block a user