Browse Source

功能适配与界面调整若干

pull/6/head
hole-thu 5 years ago
parent
commit
99f99d39f7
  1. 2
      public/index.html
  2. BIN
      public/static/favicon/180.png
  3. BIN
      public/static/favicon/192.png
  4. BIN
      public/static/favicon/512.png
  5. 37
      src/Common.js
  6. 15
      src/Flows.css
  7. 47
      src/Flows.js
  8. 5
      src/Message.js
  9. 6
      src/UserAction.css
  10. 38
      src/UserAction.js
  11. 22
      src/flows_api.js
  12. 5
      src/infrastructure/functions.js

2
public/index.html

@ -26,6 +26,6 @@
<title>新T树洞</title>
</head>
<body>
<div id="root">开启javascript,或刷新重试</div>
<div id="root">请开启javascript,或稍等片刻</div>
</body>
</html>

BIN
public/static/favicon/180.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 67 KiB

BIN
public/static/favicon/192.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 67 KiB

BIN
public/static/favicon/512.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 79 KiB

37
src/Common.js

@ -16,7 +16,7 @@ import renderMd from './Markdown';
export { format_time, Time, TitleLine };
export const API_BASE = '/_api/v1/';
export const API_BASE = '/_api/v1';
// https://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
function escape_regex(string) {
@ -164,6 +164,7 @@ export class HighlightedMarkdown extends Component {
['url', URL_RE],
['pid', PID_RE],
['nickname', NICKNAME_RE],
//TODO: tag
]);
return (
@ -217,30 +218,15 @@ export class HighlightedMarkdown extends Component {
},
];
const parser = new HtmlToReact.Parser();
if (props.author && props.text.match(/^(?:#+ |>|```|\t|\s*-|\s*\d+\.)/)) {
const renderedMarkdown = renderMd(props.text);
return (
<>
{props.author}
{parser.parseWithInstructions(
renderedMarkdown,
(node) => node.type !== 'script',
processInstructions,
) || ''}
</>
);
} else {
let rawMd = props.text;
if (props.author) rawMd = props.author + ' ' + rawMd;
const renderedMarkdown = renderMd(rawMd);
return (
parser.parseWithInstructions(
renderedMarkdown,
(node) => node.type !== 'script',
processInstructions,
) || null
);
}
let rawMd = props.text;
const renderedMarkdown = renderMd(rawMd);
return (
parser.parseWithInstructions(
renderedMarkdown,
(node) => node.type !== 'script',
processInstructions,
) || null
);
}
}
@ -314,6 +300,7 @@ export class SafeTextarea extends Component {
onChange={this.on_change_bound}
value={this.state.text}
onKeyDown={this.on_keydown_bound}
maxLength="4096"
/>
);
}

15
src/Flows.css

@ -254,7 +254,7 @@
color: white;
}
.box-header-tag {
.box-header-cw {
color: white;
background-color: #00c;
font-weight: bold;
@ -263,7 +263,16 @@
padding: 0 .25em;
}
.root-dark-mode .box-header-tag {
.box-header-name {
color: white;
background-color: #3338;
font-weight: bold;
border-radius: 5px;
margin-right: .5em;
padding: .1em .5em;
}
.root-dark-mode .box-header-cw {
background-color: #00a;
}
@ -282,4 +291,4 @@
float: right;
padding: 0 .5em;
opacity: .4;
}
}

47
src/Flows.js

@ -30,19 +30,6 @@ const CLICKABLE_TAGS = { a: true, audio: true };
const PREVIEW_REPLY_COUNT = 10;
// const QUOTE_BLACKLIST=['23333','233333','66666','666666','10086','10000','100000','99999','999999','55555','555555'];
const QUOTE_BLACKLIST = [];
const FOLD_TAGS = [
'性相关',
'政治相关',
'性话题',
'政治话题',
'折叠',
'NSFW',
'刷屏',
'真实性可疑',
'用户举报较多',
'举报较多',
'重复内容',
];
window.LATEST_POST_ID = parseInt(localStorage['_LATEST_POST_ID'], 10) || 0;
@ -104,11 +91,8 @@ class Reply extends PureComponent {
}
render() {
const replyContent = this.props.info.text;
const splitIdx = replyContent.indexOf(']');
const author = replyContent.substr(0, splitIdx + 1),
replyText = replyContent.substr(splitIdx + 2);
const author = this.props.info.name,
replyText = this.props.info.text;
return (
<div
className={'flow-reply box'}
@ -122,7 +106,6 @@ class Reply extends PureComponent {
}
>
<div className="box-header">
<code className="box-id">#{this.props.info.cid}</code>
{!!this.props.do_filter_name && (
<span
className="reply-header-badge clickable"
@ -134,10 +117,12 @@ class Reply extends PureComponent {
</span>
)}
&nbsp;
{this.props.info.tag !== null && (
<span className="box-header-tag">{this.props.info.tag}</span>
{(
<span className="box-header-name">{this.props.info.name}</span>
)}
<Time stamp={this.props.info.timestamp} short={false} />
&nbsp;
<code className="box-id">{'$' + this.props.info.cid}</code>
</div>
<div className="box-content">
<HighlightedMarkdown
@ -161,7 +146,7 @@ class FlowItem extends PureComponent {
event.preventDefault();
copy(
`${event.target.href}${
this.props.info.tag ? ' 【' + this.props.info.tag + '】' : ''
this.props.info.cw ? ' 【' + this.props.info.cw + '】' : ''
}\n` +
`${this.props.info.text}${
this.props.info.type === 'image'
@ -174,7 +159,7 @@ class FlowItem extends PureComponent {
this.props.info.likenum
}关注 ${this.props.info.reply}回复\n` +
this.props.replies
.map((r) => (r.tag ? '【' + r.tag + '】' : '') + r.text)
.map((r) => (r.cw ? '【' + r.cw + '】' : '') + r.text)
.join('\n'),
);
}
@ -237,8 +222,8 @@ class FlowItem extends PureComponent {
</a>
</code>
&nbsp;
{props.info.tag !== null && props.info.tag !== '折叠' && (
<span className="box-header-tag">{props.info.tag}</span>
{props.info.cw !== null && (
<span className="box-header-cw">{props.info.cw}</span>
)}
<Time stamp={props.info.timestamp} short={!props.img_clickable} />
</div>
@ -634,8 +619,7 @@ class FlowSidebar extends PureComponent {
class FlowItemRow extends PureComponent {
constructor(props) {
super(props);
this.needFold =
FOLD_TAGS.indexOf(props.info.tag) > -1 &&
this.needFold = props.info.cw &&
(props.search_param === '热榜' || !props.search_param) &&
window.config.fold &&
props.mode !== 'attention' && props.mode !== 'attention_finished';
@ -861,8 +845,8 @@ class FlowItemRow extends PureComponent {
)}
<code className="box-id">#{this.props.info.pid}</code>
&nbsp;
{this.props.info.tag !== null && this.props.info.tag !== '折叠' && (
<span className="box-header-tag">{this.props.info.tag}</span>
{this.props.info.cw !== null && (
<span className="box-header-cw">{this.props.info.cw}</span>
)}
<Time stamp={this.props.info.timestamp} short={true} />
<span className="box-header-badge">
@ -1038,10 +1022,11 @@ export class Flow extends PureComponent {
load_page(page) {
const failed = (err) => {
console.error(err);
console.log(err.to_string);
this.setState((prev, props) => ({
loaded_pages: prev.loaded_pages - 1,
loading_status: 'failed',
error_msg: '' + err,
error_msg: prev.loaded_pages>1 ? '找不到更多了' : '' + err,
}));
};
@ -1219,7 +1204,7 @@ export class Flow extends PureComponent {
&nbsp;Loading...
</span>
) : (
'© thuhole'
'🄯 2020 copyleft: hole_thu'
)
}
/>

5
src/Message.js

@ -22,9 +22,8 @@ export class MessageViewer extends PureComponent {
},
() => {
fetch(
'/api/v1/system_msg?user_token=' +
encodeURIComponent(this.props.token) +
API_VERSION_PARAM(),
'/_api/v1/system_msg?user_token=' +
encodeURIComponent(this.props.token)
)
.then(get_json)
.then((json) => {

6
src/UserAction.css

@ -109,3 +109,9 @@
.life-info-error a {
--var-link-color: hsl(25,100%,45%);
}
.spoiler-input {
width: 100%;
margin-bottom: 5px;
padding: 2px;
}

38
src/UserAction.js

@ -171,6 +171,8 @@ export class LoginForm extends Component {
当您发送的内容违规时我们将用系统消息提示您
</p>
<p>
<small>{token.value}</small>
<br/>
<a onClick={this.copy_token.bind(this, token.value)}>
复制 User Token
</a>
@ -263,7 +265,7 @@ export class ReplyForm extends Component {
data.append('text', this.state.text);
data.append('user_token', this.props.token);
fetch(
API_BASE + '/api.php?action=docomment' + token_param(this.props.token),
API_BASE + '/docomment' + token_param(this.props.token),
{
method: 'POST',
headers: {
@ -355,6 +357,7 @@ export class PostForm extends Component {
super(props);
this.state = {
text: '',
cw: '',
loading_status: 'done',
img_tip: null,
preview: false,
@ -362,6 +365,7 @@ export class PostForm extends Component {
this.img_ref = React.createRef();
this.area_ref = React.createRef();
this.on_change_bound = this.on_change.bind(this);
this.on_cw_change_bound = this.on_cw_change.bind(this);
this.on_img_change_bound = this.on_img_change.bind(this);
this.color_picker = new ColorPicker();
}
@ -370,6 +374,12 @@ export class PostForm extends Component {
if (this.area_ref.current) this.area_ref.current.focus();
}
on_cw_change(event) {
this.setState({
cw: event.target.value,
});
}
on_change(value) {
this.setState({
text: value,
@ -378,12 +388,13 @@ export class PostForm extends Component {
do_post(text, img) {
let data = new URLSearchParams();
data.append('cw', this.state.cw);
data.append('text', this.state.text);
data.append('type', img ? 'image' : 'text');
data.append('user_token', this.props.token);
if (img) data.append('data', img);
fetch(API_BASE + '/api.php?action=dopost' + token_param(this.props.token), {
fetch(API_BASE + '/dopost' + token_param(this.props.token), {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
@ -632,12 +643,23 @@ export class PostForm extends Component {
/>
</div>
) : (
<SafeTextarea
ref={this.area_ref}
id="new_post"
on_change={this.on_change_bound}
on_submit={this.on_submit.bind(this)}
/>
<>
<input
type="text"
placeholder="折叠警告(留空表示不折叠)"
value={this.state.cw}
id="post_cw"
className="spoiler-input"
onChange={this.on_cw_change_bound}
maxLength="32"
/>
<SafeTextarea
ref={this.area_ref}
id="new_post"
on_change={this.on_change_bound}
on_submit={this.on_submit.bind(this)}
/>
</>
)}
<p>
<small>

22
src/flows_api.js

@ -1,9 +1,9 @@
import { get_json, API_VERSION_PARAM } from './infrastructure/functions';
import { get_json} from './infrastructure/functions';
import { API_BASE } from './Common';
import { cache } from './cache';
export function token_param(token) {
return API_VERSION_PARAM() + (token ? '&user_token=' + token : '');
return token ? '?user_token=' + token : '?notoken';
}
export { get_json };
@ -34,7 +34,7 @@ export const API = {
load_replies: async (pid, token, color_picker, cache_version) => {
pid = parseInt(pid);
let response = await fetch(
API_BASE + '/api.php?action=getcomment&pid=' + pid + token_param(token),
API_BASE + '/getcomment' + token_param(token) + '&pid=' + pid ,
);
let json = await handle_response(response);
// Why delete then put ??
@ -61,7 +61,7 @@ export const API = {
data.append('pid', pid);
data.append('switch', attention ? '1' : '0');
let response = await fetch(
API_BASE + '/api.php?action=attention' + token_param(token),
API_BASE + '/attention' + token_param(token),
{
method: 'POST',
headers: {
@ -81,7 +81,7 @@ export const API = {
data.append('pid', pid);
data.append('reason', reason);
let response = await fetch(
API_BASE + '/api.php?action=report' + token_param(token),
API_BASE + '/report' + token_param(token),
{
method: 'POST',
headers: {
@ -95,7 +95,7 @@ export const API = {
get_list: async (page, token) => {
let response = await fetch(
API_BASE + '/api.php?action=getlist' + '&p=' + page + token_param(token),
API_BASE + '/getlist' + token_param(token) + '&p=' + page,
);
return handle_response(response);
},
@ -103,28 +103,28 @@ export const API = {
get_search: async (page, keyword, token) => {
let response = await fetch(
API_BASE +
'/api.php?action=search' +
'/search' +
token_param(token) +
'&pagesize=' +
SEARCH_PAGESIZE +
'&page=' +
page +
'&keywords=' +
encodeURIComponent(keyword) +
token_param(token),
encodeURIComponent(keyword)
);
return handle_response(response);
},
get_single: async (pid, token) => {
let response = await fetch(
API_BASE + '/api.php?action=getone' + '&pid=' + pid + token_param(token),
API_BASE + '/getone' + token_param(token) + '&pid=' + pid,
);
return handle_response(response);
},
get_attention: async (token) => {
let response = await fetch(
API_BASE + '/api.php?action=getattention' + token_param(token),
API_BASE + '/getattention' + token_param(token),
);
return handle_response(response);
},

5
src/infrastructure/functions.js

@ -1,5 +1,5 @@
export function get_json(res) {
if(!res.ok) throw Error(`网络错误 ${res.status} ${res.statusText}`);
if(!res.ok) throw Error(`错误 ${res.status} ${res.statusText}`);
return (
res
.text()
@ -30,6 +30,3 @@ export function listen_darkmode(override) { // override: true/false/undefined
});
}
export function API_VERSION_PARAM() {
return '&PKUHelperAPI=3.0&jsapiver='+encodeURIComponent((process.env.REACT_APP_BUILD_INFO||'null')+'-'+(Math.floor(+new Date()/7200000)*2));
}
Loading…
Cancel
Save