Browse Source

保存关注到本地,时间线分子模式

pull/6/head
hole-thu 4 years ago
parent
commit
a93e59069a
  1. 2
      src/App.js
  2. 7
      src/Attention.js
  3. 20
      src/Flows.css
  4. 159
      src/Flows.js
  5. 11
      src/UserAction.js
  6. 4
      src/flows_api.js

2
src/App.js

@ -5,6 +5,7 @@ import { Sidebar } from './Sidebar';
import { PressureHelper } from './PressureHelper';
import { TokenCtx } from './UserAction';
import { load_config, bgimg_style } from './Config';
import { load_attentions } from './Attention.js';
import { listen_darkmode } from './infrastructure/functions';
import { LoginPopup, TitleLine } from './infrastructure/widgets';
@ -18,6 +19,7 @@ class App extends Component {
constructor(props) {
super(props);
load_config();
load_attentions();
listen_darkmode(
{ default: undefined, light: false, dark: true }[
window.config.color_scheme

7
src/Attention.js

@ -0,0 +1,7 @@
export function load_attentions() {
window.saved_attentions = JSON.parse(localStorage['saved_attentions'] || '[]');
}
export function save_attentions() {
localStorage['saved_attentions'] = JSON.stringify(window.saved_attentions);
}

20
src/Flows.css

@ -319,3 +319,23 @@
height: 50vh;
padding: 12px;
}
.export-btn {
float: right;
}
.flow-submode-choice {
display: inline-block;
color: white;
}
.flow-submode-choice a {
margin: 10px;
color: white;
}
.flow-submode-choice a.choiced {
margin: 10px;
color: white;
font-weight: bold;
}

159
src/Flows.js

@ -21,10 +21,9 @@ import {
import './Flows.css';
import LazyLoad, { forceCheck } from './react-lazyload/src';
import { TokenCtx, ReplyForm } from './UserAction';
import { API } from './flows_api';
import { cache } from './cache';
import { save_attentions } from './Attention'
/*
const IMAGE_BASE = 'https://thimg.yecdn.com/';
@ -429,7 +428,8 @@ class FlowSidebar extends PureComponent {
loading_status: 'loading',
});
const prev_info = this.state.info;
API.set_attention(this.state.info.pid, !this.state.attention, this.props.token)
const pid = prev_info.pid;
API.set_attention(pid, !this.state.attention, this.props.token)
.then((json) => {
this.setState({
loading_status: 'done',
@ -439,6 +439,17 @@ class FlowSidebar extends PureComponent {
}),
});
console.log(json);
let saved_attentions = window.saved_attentions;
if (json.attention && !saved_attentions.includes(pid)) {
saved_attentions.unshift(pid)
} else if (!json.attention && saved_attentions.includes(pid)) {
const idx = saved_attentions.indexOf(pid);
saved_attentions.splice(idx, 1)
}
window.saved_attentions = saved_attentions;
save_attentions();
this.syncState({
attention: json.attention,
info: Object.assign({}, prev_info, {
@ -1102,6 +1113,67 @@ function FlowChunk(props) {
}
export class Flow extends PureComponent {
constructor(props) {
super(props);
this.state = {
submode: this.props.mode == 'list' ? (window.config.by_c ? 1 : 0) : 0,
subflow_render_key: +new Date(),
}
}
get_submode_names(mode) {
switch(mode) {
case('list'):
return ['最新', '最近回复', '近期热门'];
case('attention'):
return ['线上', '本地']
}
return []
}
set_submode(submode) {
if (this.props.mode === 'list' && submode === 2) {
alert('将在下个版本提供');
return;
}
this.setState({
submode: submode,
subflow_render_key: +new Date(),
});
}
render() {
const { submode } = this.state;
const submode_names = this.get_submode_names(this.props.mode)
return (
<>
<div className="aux-margin flow-submode-choice">
{submode_names.map((name, idx) => (
<a
key={idx}
className={submode === idx ? 'choiced' : ''}
onClick={this.set_submode.bind(this, idx)}
>
{name}
</a>
))}
</div>
<SubFlow
key={this.state.subflow_render_key}
show_sidebar={this.props.show_sidebar}
mode={this.props.mode}
submode={this.state.submode}
search_text={this.props.search_text}
token={this.props.token}
/>
</>
)
}
}
class SubFlow extends PureComponent {
constructor(props) {
super(props);
this.state = {
@ -1112,7 +1184,6 @@ export class Flow extends PureComponent {
title: '',
data: [],
},
can_export: false,
export_text: '',
loading_status: 'done',
error_msg: null,
@ -1137,7 +1208,7 @@ export class Flow extends PureComponent {
console.log('fetching page', page);
cache();
if (this.state.mode === 'list') {
API.get_list(page, this.props.token)
API.get_list(page, this.props.token, this.props.submode)
.then((json) => {
if (page === 1 && json.data.length) {
// update latest_post_id
@ -1235,33 +1306,52 @@ export class Flow extends PureComponent {
}
}
console.log(use_search, use_regex);
API.get_attention(this.props.token)
.then((json) => {
this.setState({
chunks: {
title: `${
use_search
? use_regex
? `Result for RegEx ${regex_search.toString()} in `
: `Result for "${this.state.search_param}" in `
: ''
}Attention List`,
data: !use_search
? json.data
: !use_regex
? json.data.filter((post) => {
return this.state.search_param
if (this.props.submode === 0) {
API.get_attention(this.props.token)
.then((json) => {
this.setState({
chunks: {
title: `${
use_search
? use_regex
? `Result for RegEx ${regex_search.toString()} in `
: `Result for "${this.state.search_param}" in `
: ''
}Attention List`,
data: !use_search
? json.data
: !use_regex
? json.data.filter((post) => {
return this.state.search_param
.split(' ')
.every((keyword) => post.text.includes(keyword));
}) // Not using regex
: json.data.filter((post) => !!post.text.match(regex_search)), // Using regex
},
mode: 'attention_finished',
loading_status: 'done',
can_export: !use_search,
});
})
.catch(failed);
}) // Not using regex
: json.data.filter((post) => !!post.text.match(regex_search)), // Using regex
},
mode: 'attention_finished',
loading_status: 'done',
});
if (!use_search) {
window.saved_attentions = Array.from(
new Set([
...window.saved_attentions,
...json.data.map(post => post.pid)
])
).sort().reverse();
save_attentions();
}
})
.catch(failed);
} else if (this.props.submode === 1) {
this.setState({
title: 'Attention List: Local',
data: [],
export_text: `以下是浏览器本地保存的关注列表,将在下个版本提供直接展示\n\n#${
window.saved_attentions.join('\n#')
}`
});
}
} else {
console.log('nothing to load');
return;
@ -1274,7 +1364,7 @@ export class Flow extends PureComponent {
}));
}
}
on_scroll(event) {
if (event.target === document) {
const avail =
@ -1314,10 +1404,11 @@ export class Flow extends PureComponent {
const should_deletion_detect = localStorage['DELETION_DETECT'] === 'on';
return (
<div className="flow-container">
{this.state.can_export && (
<button type="button" onClick={this.gen_export.bind(this)}>导出</button>
{this.state.mode === 'attention_finished' && this.props.submode == 0 && (
<button className="export-btn" type="button" onClick={this.gen_export.bind(this)}>导出</button>
)}
{this.state.export_text && (
<div className="box">
<textarea

11
src/UserAction.js

@ -16,6 +16,7 @@ import {
API,
get_json,
} from './flows_api';
import { save_attentions } from './Attention'
import './UserAction.css';
@ -266,7 +267,8 @@ export class ReplyForm extends Component {
});
let data = new URLSearchParams();
data.append('pid', this.props.pid);
let pid = this.props.pid;
data.append('pid', pid);
data.append('text', this.state.text);
fetch(
API_BASE + '/docomment',
@ -285,6 +287,13 @@ export class ReplyForm extends Component {
if (json.msg) alert(json.msg);
throw new Error(JSON.stringify(json));
}
let saved_attentions = window.saved_attentions;
if (!saved_attentions.includes(pid)) {
saved_attentions.unshift(pid)
window.saved_attentions = saved_attentions;
save_attentions();
}
this.setState({
loading_status: 'done',

4
src/flows_api.js

@ -136,11 +136,11 @@ export const API = {
return handle_response(response, true);
},
get_list: async (page, token) => {
get_list: async (page, token, submode) => {
let response = await fetch(
API_BASE + '/getlist?p=' + page
+ (window.config.no_c_post ? '&no_cw' : '')
+ (window.config.by_c ? '&by_c' : ''),
+ (submode ? '&by_c' : ''),
{
headers: {'User-Token': token},
},

Loading…
Cancel
Save