formatting
This commit is contained in:
12
src/App.js
12
src/App.js
@@ -100,8 +100,11 @@ class App extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
if (window.location.protocol === 'http:' &&
|
if (
|
||||||
window.location.hostname !== '127.0.0.1' && !window.location.hostname.endsWith('localhost')) {
|
window.location.protocol === 'http:' &&
|
||||||
|
window.location.hostname !== '127.0.0.1' &&
|
||||||
|
!window.location.hostname.endsWith('localhost')
|
||||||
|
) {
|
||||||
window.location.protocol = 'https:'; // 因为CDN的原因先在前端做下https跳转
|
window.location.protocol = 'https:'; // 因为CDN的原因先在前端做下https跳转
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -110,7 +113,10 @@ class App extends Component {
|
|||||||
if (arg.startsWith('?token=')) {
|
if (arg.startsWith('?token=')) {
|
||||||
let token = arg.substr(7);
|
let token = arg.substr(7);
|
||||||
if (token.endsWith(encodeURI('_任意自定义后缀'))) {
|
if (token.endsWith(encodeURI('_任意自定义后缀'))) {
|
||||||
let tmp_token_suf = localStorage['TOKEN_SUF'] || prompt('设置一个你专属的临时token后缀吧') || Math.random();
|
let tmp_token_suf =
|
||||||
|
localStorage['TOKEN_SUF'] ||
|
||||||
|
prompt('设置一个你专属的临时token后缀吧') ||
|
||||||
|
Math.random();
|
||||||
localStorage['TOKEN_SUF'] = tmp_token_suf;
|
localStorage['TOKEN_SUF'] = tmp_token_suf;
|
||||||
token = `${token.split('_')[0]}_${tmp_token_suf}`;
|
token = `${token.split('_')[0]}_${tmp_token_suf}`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
export function load_attentions() {
|
export function load_attentions() {
|
||||||
window.saved_attentions = JSON.parse(localStorage['saved_attentions'] || '[]');
|
window.saved_attentions = JSON.parse(
|
||||||
|
localStorage['saved_attentions'] || '[]',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function save_attentions() {
|
export function save_attentions() {
|
||||||
|
|||||||
@@ -12,17 +12,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.root-dark-mode .bg-img {
|
.root-dark-mode .bg-img {
|
||||||
opacity: .65;
|
opacity: 0.65;
|
||||||
}
|
}
|
||||||
|
|
||||||
.black-outline {
|
.black-outline {
|
||||||
text-shadow: /* also change .flow-item-row-with-prompt:hover::before */
|
text-shadow: /* also change .flow-item-row-with-prompt:hover::before */ -1px -1px
|
||||||
-1px -1px 0 rgba(0,0,0,.6),
|
0 rgba(0, 0, 0, 0.6),
|
||||||
0 -1px 0 rgba(0,0,0,.6),
|
0 -1px 0 rgba(0, 0, 0, 0.6), 1px -1px 0 rgba(0, 0, 0, 0.6),
|
||||||
1px -1px 0 rgba(0,0,0,.6),
|
-1px 1px 0 rgba(0, 0, 0, 0.6), 0 1px 0 rgba(0, 0, 0, 0.6),
|
||||||
-1px 1px 0 rgba(0,0,0,.6),
|
1px 1px 0 rgba(0, 0, 0, 0.6);
|
||||||
0 1px 0 rgba(0,0,0,.6),
|
|
||||||
1px 1px 0 rgba(0,0,0,.6);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-query-highlight {
|
.search-query-highlight {
|
||||||
@@ -35,7 +33,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.url-pid-link {
|
.url-pid-link {
|
||||||
opacity: .6;
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
@@ -51,15 +49,16 @@
|
|||||||
background-color: var(--coloredspan-bgcolor-dark);
|
background-color: var(--coloredspan-bgcolor-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon+label {
|
.icon + label {
|
||||||
font-size: .9em;
|
font-size: 0.9em;
|
||||||
vertical-align: .05em;
|
vertical-align: 0.05em;
|
||||||
cursor: inherit;
|
cursor: inherit;
|
||||||
padding: 0 .1rem;
|
padding: 0 0.1rem;
|
||||||
margin-left: .15rem;
|
margin-left: 0.15rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ext-img, .ext-video {
|
.ext-img,
|
||||||
|
.ext-video {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
max-height: 2000px;
|
max-height: 2000px;
|
||||||
display: block;
|
display: block;
|
||||||
|
|||||||
@@ -138,13 +138,18 @@ export class HighlightedMarkdown extends Component {
|
|||||||
['url', URL_RE],
|
['url', URL_RE],
|
||||||
['pid', PID_RE],
|
['pid', PID_RE],
|
||||||
['nickname', NICKNAME_RE],
|
['nickname', NICKNAME_RE],
|
||||||
['tag', TAG_RE]
|
['tag', TAG_RE],
|
||||||
];
|
];
|
||||||
if (props.search_param) {
|
if (props.search_param) {
|
||||||
let search_kws = props.search_param.split(' ').filter(s => !!s);
|
let search_kws = props.search_param.split(' ').filter((s) => !!s);
|
||||||
rules.push([
|
rules.push([
|
||||||
'search',
|
'search',
|
||||||
new RegExp(`(${search_kws.map((s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join("|")})`, "g")
|
new RegExp(
|
||||||
|
`(${search_kws
|
||||||
|
.map((s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
|
||||||
|
.join('|')})`,
|
||||||
|
'g',
|
||||||
|
),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
const splitted = split_text(originalText, rules);
|
const splitted = split_text(originalText, rules);
|
||||||
@@ -170,7 +175,7 @@ export class HighlightedMarkdown extends Component {
|
|||||||
<span className="icon icon-new-tab" />
|
<span className="icon icon-new-tab" />
|
||||||
</a>
|
</a>
|
||||||
{is_video(p) && (
|
{is_video(p) && (
|
||||||
<video className="ext-video" src={p} controls loop/>
|
<video className="ext-video" src={p} controls loop />
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
) : rule === 'pid' ? (
|
) : rule === 'pid' ? (
|
||||||
@@ -190,11 +195,7 @@ export class HighlightedMarkdown extends Component {
|
|||||||
) : rule === 'search' ? (
|
) : rule === 'search' ? (
|
||||||
<span className="search-query-highlight">{p}</span>
|
<span className="search-query-highlight">{p}</span>
|
||||||
) : rule === 'tag' ? (
|
) : rule === 'tag' ? (
|
||||||
<a
|
<a href={p}>{p}</a>
|
||||||
href={p}
|
|
||||||
>
|
|
||||||
{p}
|
|
||||||
</a>
|
|
||||||
) : (
|
) : (
|
||||||
p
|
p
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -26,6 +26,6 @@
|
|||||||
width: 32em;
|
width: 32em;
|
||||||
max-height: 60vh;
|
max-height: 60vh;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
margin: .5em auto 1em;
|
margin: 0.5em auto 1em;
|
||||||
box-shadow: 0 1px 5px rgba(0,0,0,.4);
|
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.4);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ import './Config.css';
|
|||||||
const BUILTIN_IMGS = {
|
const BUILTIN_IMGS = {
|
||||||
'https://cdn.jsdelivr.net/gh/thuhole/webhole@gh-pages/static/bg/gbp.jpg':
|
'https://cdn.jsdelivr.net/gh/thuhole/webhole@gh-pages/static/bg/gbp.jpg':
|
||||||
'怀旧背景(默认)',
|
'怀旧背景(默认)',
|
||||||
'https://www.tsinghua.edu.cn/image/nav-bg.jpg':
|
'https://www.tsinghua.edu.cn/image/nav-bg.jpg': '清华紫',
|
||||||
'清华紫',
|
|
||||||
'https://cdn.jsdelivr.net/gh/thuhole/webhole@gh-pages/static/bg/gbp.jpg':
|
'https://cdn.jsdelivr.net/gh/thuhole/webhole@gh-pages/static/bg/gbp.jpg':
|
||||||
'寻觅繁星',
|
'寻觅繁星',
|
||||||
'https://cdn.jsdelivr.net/gh/thuhole/webhole@gh-pages/static/bg/eriri.jpg':
|
'https://cdn.jsdelivr.net/gh/thuhole/webhole@gh-pages/static/bg/eriri.jpg':
|
||||||
@@ -33,7 +32,7 @@ const DEFAULT_CONFIG = {
|
|||||||
no_c_post: false,
|
no_c_post: false,
|
||||||
by_c: false,
|
by_c: false,
|
||||||
block_words_v2: ['#天火', '#桃花石'],
|
block_words_v2: ['#天火', '#桃花石'],
|
||||||
whitelist_cw: []
|
whitelist_cw: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
export function load_config() {
|
export function load_config() {
|
||||||
@@ -53,7 +52,9 @@ export function load_config() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (loaded_config['block_words']) {
|
if (loaded_config['block_words']) {
|
||||||
config['block_words_v2'] = loaded_config['block_words'].concat(config['block_words_v2'])
|
config['block_words_v2'] = loaded_config['block_words'].concat(
|
||||||
|
config['block_words_v2'],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('config loaded', config);
|
console.log('config loaded', config);
|
||||||
@@ -377,7 +378,9 @@ export class ConfigUI extends PureComponent {
|
|||||||
id="whitelist_cw"
|
id="whitelist_cw"
|
||||||
callback={this.save_changes_bound}
|
callback={this.save_changes_bound}
|
||||||
name="展开指定的折叠警告"
|
name="展开指定的折叠警告"
|
||||||
description={'完全匹配的树洞不会被折叠,每行一个豁免词,也可使用一个星号("*")表示豁免所有'}
|
description={
|
||||||
|
'完全匹配的树洞不会被折叠,每行一个豁免词,也可使用一个星号("*")表示豁免所有'
|
||||||
|
}
|
||||||
display={(array) => array.join('\n')}
|
display={(array) => array.join('\n')}
|
||||||
sift={(array) => array.filter((v) => v)}
|
sift={(array) => array.filter((v) => v)}
|
||||||
parse={(string) => string.split('\n')}
|
parse={(string) => string.split('\n')}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
:root {
|
:root {
|
||||||
--box-bgcolor-light: hsl(0,0%,97%);
|
--box-bgcolor-light: hsl(0, 0%, 97%);
|
||||||
--box-bgcolor-dark: hsl(0,0%,16%);
|
--box-bgcolor-dark: hsl(0, 0%, 16%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.box {
|
.box {
|
||||||
@@ -8,14 +8,14 @@
|
|||||||
color: black;
|
color: black;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
margin: 1em 0;
|
margin: 1em 0;
|
||||||
padding: .5em;
|
padding: 0.5em;
|
||||||
box-shadow: 0 2px 5px rgba(0,0,0,.4);
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.root-dark-mode .box {
|
.root-dark-mode .box {
|
||||||
background-color: var(--box-bgcolor-dark);
|
background-color: var(--box-bgcolor-dark);
|
||||||
color: var(--foreground-dark);
|
color: var(--foreground-dark);
|
||||||
box-shadow: 0 0 2px rgba(255,255,255,.25), 0 0 7px rgba(0,0,0,.15);
|
box-shadow: 0 0 2px rgba(255, 255, 255, 0.25), 0 0 7px rgba(0, 0, 0, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
.box-tip {
|
.box-tip {
|
||||||
@@ -50,7 +50,8 @@
|
|||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-flow-item .flow-item pre, .sidebar-flow-item .flow-reply pre {
|
.sidebar-flow-item .flow-item pre,
|
||||||
|
.sidebar-flow-item .flow-reply pre {
|
||||||
cursor: text;
|
cursor: text;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +69,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.flow-item-row::after {
|
.flow-item-row::after {
|
||||||
content: "";
|
content: '';
|
||||||
display: block;
|
display: block;
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
@@ -91,13 +92,10 @@
|
|||||||
left: 10px;
|
left: 10px;
|
||||||
margin-top: 1.5em;
|
margin-top: 1.5em;
|
||||||
color: white;
|
color: white;
|
||||||
text-shadow: /* copied from .black-outline */
|
text-shadow: /* copied from .black-outline */ -1px -1px 0 rgba(0, 0, 0, 0.6),
|
||||||
-1px -1px 0 rgba(0,0,0,.6),
|
0 -1px 0 rgba(0, 0, 0, 0.6), 1px -1px 0 rgba(0, 0, 0, 0.6),
|
||||||
0 -1px 0 rgba(0,0,0,.6),
|
-1px 1px 0 rgba(0, 0, 0, 0.6), 0 1px 0 rgba(0, 0, 0, 0.6),
|
||||||
1px -1px 0 rgba(0,0,0,.6),
|
1px 1px 0 rgba(0, 0, 0, 0.6);
|
||||||
-1px 1px 0 rgba(0,0,0,.6),
|
|
||||||
0 1px 0 rgba(0,0,0,.6),
|
|
||||||
1px 1px 0 rgba(0,0,0,.6);
|
|
||||||
font-family: 'Consolas', 'Courier', monospace;
|
font-family: 'Consolas', 'Courier', monospace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,17 +140,18 @@
|
|||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
.box-header, .box-footer {
|
.box-header,
|
||||||
font-size: .8em;
|
.box-footer {
|
||||||
|
font-size: 0.8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flow-item-row p.img {
|
.flow-item-row p.img {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: .5em;
|
margin-top: 0.5em;
|
||||||
}
|
}
|
||||||
.flow-item-row p.img img {
|
.flow-item-row p.img img {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
box-shadow: 0 1px 5px rgba(0,0,0,.4);
|
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.4);
|
||||||
}
|
}
|
||||||
.left-container .flow-item-row p.img img {
|
.left-container .flow-item-row p.img img {
|
||||||
max-height: 80vh;
|
max-height: 80vh;
|
||||||
@@ -164,19 +163,19 @@
|
|||||||
|
|
||||||
.box-header-badge {
|
.box-header-badge {
|
||||||
float: right;
|
float: right;
|
||||||
margin: 0 .5em;
|
margin: 0 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flow-item-dot {
|
.flow-item-dot {
|
||||||
position: relative;
|
position: relative;
|
||||||
top: calc(-.5em - 4px);
|
top: calc(-0.5em - 4px);
|
||||||
left: calc(-.5em - 4px);
|
left: calc(-0.5em - 4px);
|
||||||
width: 10px;
|
width: 10px;
|
||||||
height: 10px;
|
height: 10px;
|
||||||
margin-bottom: -10px;
|
margin-bottom: -10px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background-color: #ffcc77;
|
background-color: #ffcc77;
|
||||||
box-shadow: 1px 1px 5px rgba(0,0,0,.5);
|
box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.5);
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,7 +188,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.box-content {
|
.box-content {
|
||||||
padding: .5em 0;
|
padding: 0.5em 0;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,7 +210,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.box-id a:hover::before {
|
.box-id a:hover::before {
|
||||||
content: "复制全文";
|
content: '复制全文';
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 5em;
|
width: 5em;
|
||||||
height: 1.3em;
|
height: 1.3em;
|
||||||
@@ -222,21 +221,21 @@
|
|||||||
top: -1.5em;
|
top: -1.5em;
|
||||||
display: block;
|
display: block;
|
||||||
color: white;
|
color: white;
|
||||||
background-color: rgba(0,0,0,.6);
|
background-color: rgba(0, 0, 0, 0.6);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flow-item-row-quote {
|
.flow-item-row-quote {
|
||||||
opacity: .8;
|
opacity: 0.8;
|
||||||
filter: brightness(95%);
|
filter: brightness(95%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.root-dark-mode .flow-item-row-quote {
|
.root-dark-mode .flow-item-row-quote {
|
||||||
opacity: .7;
|
opacity: 0.7;
|
||||||
filter: unset;
|
filter: unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flow-item-quote>.box {
|
.flow-item-quote > .box {
|
||||||
margin-left: 2.5em;
|
margin-left: 2.5em;
|
||||||
max-height: 15em;
|
max-height: 15em;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
@@ -248,7 +247,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.quote-tip {
|
.quote-tip {
|
||||||
margin-top: .5em;
|
margin-top: 0.5em;
|
||||||
margin-bottom: -10em; /* so that it will not block reply bar */
|
margin-bottom: -10em; /* so that it will not block reply bar */
|
||||||
float: left;
|
float: left;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -263,8 +262,8 @@
|
|||||||
background-color: #00c;
|
background-color: #00c;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
margin-right: .25em;
|
margin-right: 0.25em;
|
||||||
padding: 0 .25em;
|
padding: 0 0.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.box-header-cw-edit {
|
.box-header-cw-edit {
|
||||||
@@ -272,17 +271,17 @@
|
|||||||
background-color: #00c;
|
background-color: #00c;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
margin:0 3px;
|
margin: 0 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.box-header-cw-edit input {
|
.box-header-cw-edit input {
|
||||||
font-size: .8em;
|
font-size: 0.8em;
|
||||||
width: 8em;
|
width: 8em;
|
||||||
padding: 0 3px;
|
padding: 0 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.box-header-cw-edit button {
|
.box-header-cw-edit button {
|
||||||
font-size: .8em;
|
font-size: 0.8em;
|
||||||
margin: 0 3px;
|
margin: 0 3px;
|
||||||
background: white;
|
background: white;
|
||||||
}
|
}
|
||||||
@@ -292,8 +291,8 @@
|
|||||||
background-color: #3338;
|
background-color: #3338;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
margin-right: .5em;
|
margin-right: 0.5em;
|
||||||
padding: .1em .5em;
|
padding: 0.1em 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.box-header-name.author-title {
|
.box-header-name.author-title {
|
||||||
@@ -306,20 +305,25 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.filter-name-bar {
|
.filter-name-bar {
|
||||||
animation: slide-in-from-top .15s ease-out;
|
animation: slide-in-from-top 0.15s ease-out;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 1em;
|
top: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes slide-in-from-top {
|
@keyframes slide-in-from-top {
|
||||||
0% {opacity: 0; transform: translateY(-50%);}
|
0% {
|
||||||
100% {opacity: 1;}
|
opacity: 0;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.reply-header-badge {
|
.reply-header-badge {
|
||||||
float: right;
|
float: right;
|
||||||
padding: 0 .5em;
|
padding: 0 0.5em;
|
||||||
opacity: .4;
|
opacity: 0.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.export-textarea {
|
.export-textarea {
|
||||||
@@ -353,19 +357,20 @@
|
|||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
.box-poll li > div, .box-poll li > button {
|
.box-poll li > div,
|
||||||
|
.box-poll li > button {
|
||||||
height: 36px !important;
|
height: 36px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.box-poll li > div > div.styles_labels__2rz-F {
|
.box-poll li > div > div.styles_labels__2rz-F {
|
||||||
top: 50% !important;
|
top: 50% !important;
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.box-poll span, .box-poll button {
|
.box-poll span,
|
||||||
|
.box-poll button {
|
||||||
font-size: 13px !important;
|
font-size: 13px !important;
|
||||||
white-space: pre-line !important;
|
white-space: pre-line !important;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.box-poll button {
|
.box-poll button {
|
||||||
|
|||||||
293
src/Flows.js
293
src/Flows.js
@@ -23,7 +23,7 @@ import LazyLoad, { forceCheck } from './react-lazyload/src';
|
|||||||
import { TokenCtx, ReplyForm } from './UserAction';
|
import { TokenCtx, ReplyForm } from './UserAction';
|
||||||
import { API, parse_replies } from './flows_api';
|
import { API, parse_replies } from './flows_api';
|
||||||
import { cache } from './cache';
|
import { cache } from './cache';
|
||||||
import { save_attentions } from './Attention'
|
import { save_attentions } from './Attention';
|
||||||
import Poll from 'react-polls';
|
import Poll from 'react-polls';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -97,8 +97,14 @@ class Reply extends PureComponent {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
info, color_picker, show_pid, do_filter_name, do_delete,
|
info,
|
||||||
do_report, do_block, search_param
|
color_picker,
|
||||||
|
show_pid,
|
||||||
|
do_filter_name,
|
||||||
|
do_delete,
|
||||||
|
do_report,
|
||||||
|
do_block,
|
||||||
|
search_param,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const author = info.name,
|
const author = info.name,
|
||||||
replyText = info.text;
|
replyText = info.text;
|
||||||
@@ -126,9 +132,7 @@ class Reply extends PureComponent {
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{(
|
{<span className="box-header-name">{info.name}</span>}
|
||||||
<span className="box-header-name">{info.name}</span>
|
|
||||||
)}
|
|
||||||
{info.author_title && (
|
{info.author_title && (
|
||||||
<span className="box-header-name author-title">{`"${info.author_title}"`}</span>
|
<span className="box-header-name author-title">{`"${info.author_title}"`}</span>
|
||||||
)}
|
)}
|
||||||
@@ -138,21 +142,21 @@ class Reply extends PureComponent {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
do_delete('cid', info.cid);
|
do_delete('cid', info.cid);
|
||||||
}}
|
}}
|
||||||
> 🗑️ </span>
|
>
|
||||||
|
{' '}
|
||||||
|
🗑️{' '}
|
||||||
|
</span>
|
||||||
)}
|
)}
|
||||||
{!!do_block && (
|
{!!do_block && (
|
||||||
<span
|
<span className="clickable" onClick={do_block}>
|
||||||
className="clickable"
|
{' '}
|
||||||
onClick={do_block}
|
🚫{' '}
|
||||||
> 🚫 </span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{!!do_report && (
|
{!!do_report && (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
<span
|
<span className="clickable" onClick={do_report}>
|
||||||
className="clickable"
|
|
||||||
onClick={do_report}
|
|
||||||
>
|
|
||||||
<span className="icon icon-flag" />
|
<span className="icon icon-flag" />
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
@@ -219,9 +223,21 @@ class FlowItem extends PureComponent {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
info, is_quote, cached, attention, can_del, do_filter_name, do_delete,
|
info,
|
||||||
do_edit_cw, timestamp, img_clickable, color_picker,
|
is_quote,
|
||||||
show_pid, do_vote, do_block, search_param
|
cached,
|
||||||
|
attention,
|
||||||
|
can_del,
|
||||||
|
do_filter_name,
|
||||||
|
do_delete,
|
||||||
|
do_edit_cw,
|
||||||
|
timestamp,
|
||||||
|
img_clickable,
|
||||||
|
color_picker,
|
||||||
|
show_pid,
|
||||||
|
do_vote,
|
||||||
|
do_block,
|
||||||
|
search_param,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { cw } = this.state;
|
const { cw } = this.state;
|
||||||
return (
|
return (
|
||||||
@@ -241,9 +257,7 @@ class FlowItem extends PureComponent {
|
|||||||
parseInt(info.pid, 10) > window.LATEST_POST_ID && (
|
parseInt(info.pid, 10) > window.LATEST_POST_ID && (
|
||||||
<div className="flow-item-dot" />
|
<div className="flow-item-dot" />
|
||||||
)}
|
)}
|
||||||
{!!attention && !cached && (
|
{!!attention && !cached && <div className="flow-item-dot" />}
|
||||||
<div className="flow-item-dot" />
|
|
||||||
)}
|
|
||||||
<div className="box-header">
|
<div className="box-header">
|
||||||
{!!do_filter_name && (
|
{!!do_filter_name && (
|
||||||
<span
|
<span
|
||||||
@@ -259,9 +273,7 @@ class FlowItem extends PureComponent {
|
|||||||
<span className="box-header-badge">
|
<span className="box-header-badge">
|
||||||
{info.likenum}
|
{info.likenum}
|
||||||
<span
|
<span
|
||||||
className={
|
className={'icon icon-' + (attention ? 'star-ok' : 'star')}
|
||||||
'icon icon-' + (attention ? 'star-ok' : 'star')
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
@@ -272,10 +284,7 @@ class FlowItem extends PureComponent {
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<code className="box-id">
|
<code className="box-id">
|
||||||
<a
|
<a href={'##' + info.pid} onClick={this.copy_link.bind(this)}>
|
||||||
href={'##' + info.pid}
|
|
||||||
onClick={this.copy_link.bind(this)}
|
|
||||||
>
|
|
||||||
#{info.pid}
|
#{info.pid}
|
||||||
</a>
|
</a>
|
||||||
</code>
|
</code>
|
||||||
@@ -283,22 +292,23 @@ class FlowItem extends PureComponent {
|
|||||||
{info.author_title && (
|
{info.author_title && (
|
||||||
<span className="box-header-name author-title">{`"${info.author_title}"`}</span>
|
<span className="box-header-name author-title">{`"${info.author_title}"`}</span>
|
||||||
)}
|
)}
|
||||||
{info.is_reported && (
|
{info.is_reported && <span className="danger-info"> R </span>}
|
||||||
<span className="danger-info"> R </span>
|
|
||||||
)}
|
|
||||||
{!!do_delete && !!info.can_del && (
|
{!!do_delete && !!info.can_del && (
|
||||||
<span
|
<span
|
||||||
className="clickable"
|
className="clickable"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
do_delete('pid', info.pid);
|
do_delete('pid', info.pid);
|
||||||
}}
|
}}
|
||||||
> 🗑️ </span>
|
>
|
||||||
|
{' '}
|
||||||
|
🗑️{' '}
|
||||||
|
</span>
|
||||||
)}
|
)}
|
||||||
{!!do_block && (
|
{!!do_block && (
|
||||||
<span
|
<span className="clickable" onClick={do_block}>
|
||||||
className="clickable"
|
{' '}
|
||||||
onClick={do_block}
|
🚫{' '}
|
||||||
> 🚫 </span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{info.dangerous_user && (
|
{info.dangerous_user && (
|
||||||
<span className="danger-info"> {info.dangerous_user} </span>
|
<span className="danger-info"> {info.dangerous_user} </span>
|
||||||
@@ -306,12 +316,10 @@ class FlowItem extends PureComponent {
|
|||||||
{info.blocked_count && (
|
{info.blocked_count && (
|
||||||
<span className="danger-info"> {info.blocked_count} </span>
|
<span className="danger-info"> {info.blocked_count} </span>
|
||||||
)}
|
)}
|
||||||
{info.cw !== null &&
|
{info.cw !== null && (!do_edit_cw || !info.can_del) && (
|
||||||
(!do_edit_cw || !info.can_del) && (
|
|
||||||
<span className="box-header-cw">{info.cw}</span>
|
<span className="box-header-cw">{info.cw}</span>
|
||||||
)}
|
)}
|
||||||
{
|
{!!do_edit_cw && !!info.can_del && (
|
||||||
!!do_edit_cw && !!info.can_del && (
|
|
||||||
<div className="box-header-cw-edit clickable">
|
<div className="box-header-cw-edit clickable">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
@@ -320,16 +328,12 @@ class FlowItem extends PureComponent {
|
|||||||
placeholder="编辑折叠警告"
|
placeholder="编辑折叠警告"
|
||||||
onChange={this.on_cw_change.bind(this)}
|
onChange={this.on_cw_change.bind(this)}
|
||||||
/>
|
/>
|
||||||
<button type="button"
|
<button type="button" onClick={(e) => do_edit_cw(cw, info.pid)}>
|
||||||
onClick={(e)=>do_edit_cw(cw, info.pid)}>
|
|
||||||
更新
|
更新
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)}
|
||||||
}
|
{info.allow_search && <span> 📢 </span>}
|
||||||
{
|
|
||||||
info.allow_search && <span> 📢 </span>
|
|
||||||
}
|
|
||||||
<Time stamp={info.timestamp} short={!img_clickable} />
|
<Time stamp={info.timestamp} short={!img_clickable} />
|
||||||
</div>
|
</div>
|
||||||
{!!info.hot_score && (
|
{!!info.hot_score && (
|
||||||
@@ -343,14 +347,14 @@ class FlowItem extends PureComponent {
|
|||||||
search_param={search_param}
|
search_param={search_param}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{ info.poll && (
|
{info.poll && (
|
||||||
<div className={!do_vote ? "box-poll disabled" : "box-poll"}>
|
<div className={!do_vote ? 'box-poll disabled' : 'box-poll'}>
|
||||||
<Poll
|
<Poll
|
||||||
key={info.poll.vote || 'x'}
|
key={info.poll.vote || 'x'}
|
||||||
question={""}
|
question={''}
|
||||||
answers={info.poll.answers}
|
answers={info.poll.answers}
|
||||||
onVote={do_vote || (() => {})}
|
onVote={do_vote || (() => {})}
|
||||||
customStyles={{'theme': 'cyan'}}
|
customStyles={{ theme: 'cyan' }}
|
||||||
noStorage={true}
|
noStorage={true}
|
||||||
vote={localStorage['VOTE_RECORD:' + info.pid] || info.poll.vote}
|
vote={localStorage['VOTE_RECORD:' + info.pid] || info.poll.vote}
|
||||||
/>
|
/>
|
||||||
@@ -358,8 +362,7 @@ class FlowItem extends PureComponent {
|
|||||||
)}
|
)}
|
||||||
{!!(attention && info.variant.latest_reply) && (
|
{!!(attention && info.variant.latest_reply) && (
|
||||||
<p className="box-footer">
|
<p className="box-footer">
|
||||||
最新回复{' '}
|
最新回复 <Time stamp={info.variant.latest_reply} short={false} />
|
||||||
<Time stamp={info.variant.latest_reply} short={false} />
|
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -432,7 +435,7 @@ class FlowSidebar extends PureComponent {
|
|||||||
info: update_count
|
info: update_count
|
||||||
? Object.assign({}, prev.info, {
|
? Object.assign({}, prev.info, {
|
||||||
reply: '' + json.data.length,
|
reply: '' + json.data.length,
|
||||||
likenum: ''+json.likenum,
|
likenum: '' + json.likenum,
|
||||||
})
|
})
|
||||||
: prev.info,
|
: prev.info,
|
||||||
attention: !!json.attention,
|
attention: !!json.attention,
|
||||||
@@ -473,16 +476,16 @@ class FlowSidebar extends PureComponent {
|
|||||||
this.setState({
|
this.setState({
|
||||||
attention: json.attention,
|
attention: json.attention,
|
||||||
info: Object.assign({}, prev_info, {
|
info: Object.assign({}, prev_info, {
|
||||||
likenum: ''+json.likenum,
|
likenum: '' + json.likenum,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
let saved_attentions = window.saved_attentions;
|
let saved_attentions = window.saved_attentions;
|
||||||
if (json.attention && !saved_attentions.includes(pid)) {
|
if (json.attention && !saved_attentions.includes(pid)) {
|
||||||
saved_attentions.unshift(pid)
|
saved_attentions.unshift(pid);
|
||||||
} else if (!json.attention && saved_attentions.includes(pid)) {
|
} else if (!json.attention && saved_attentions.includes(pid)) {
|
||||||
const idx = saved_attentions.indexOf(pid);
|
const idx = saved_attentions.indexOf(pid);
|
||||||
saved_attentions.splice(idx, 1)
|
saved_attentions.splice(idx, 1);
|
||||||
}
|
}
|
||||||
window.saved_attentions = saved_attentions;
|
window.saved_attentions = saved_attentions;
|
||||||
save_attentions();
|
save_attentions();
|
||||||
@@ -490,7 +493,7 @@ class FlowSidebar extends PureComponent {
|
|||||||
this.syncState({
|
this.syncState({
|
||||||
attention: json.attention,
|
attention: json.attention,
|
||||||
info: Object.assign({}, prev_info, {
|
info: Object.assign({}, prev_info, {
|
||||||
likenum: ''+json.likenum,
|
likenum: '' + json.likenum,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@@ -553,12 +556,12 @@ class FlowSidebar extends PureComponent {
|
|||||||
API.block(type, id, this.props.token)
|
API.block(type, id, this.props.token)
|
||||||
.then((json) => {
|
.then((json) => {
|
||||||
let data = json.data;
|
let data = json.data;
|
||||||
alert(`操作成功,其成为危险用户进度 ${data.curr}/${data.threshold}`)
|
alert(`操作成功,其成为危险用户进度 ${data.curr}/${data.threshold}`);
|
||||||
!!on_complete && on_complete();
|
!!on_complete && on_complete();
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
alert('拉黑失败\n' + e);
|
alert('拉黑失败\n' + e);
|
||||||
console.error(e)
|
console.error(e);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -590,7 +593,7 @@ class FlowSidebar extends PureComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
make_do_delete(token, on_complete=null) {
|
make_do_delete(token, on_complete = null) {
|
||||||
const do_delete = (type, id) => {
|
const do_delete = (type, id) => {
|
||||||
let note = prompt(`将删除${type}=${id}, 备注:`, '(无)');
|
let note = prompt(`将删除${type}=${id}, 备注:`, '(无)');
|
||||||
if (note !== null) {
|
if (note !== null) {
|
||||||
@@ -604,21 +607,23 @@ class FlowSidebar extends PureComponent {
|
|||||||
console.error(e);
|
console.error(e);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
return do_delete;
|
return do_delete;
|
||||||
}
|
}
|
||||||
|
|
||||||
do_edit_cw(cw, id) {
|
do_edit_cw(cw, id) {
|
||||||
API.update_cw(cw, id, this.props.token)
|
API.update_cw(cw, id, this.props.token)
|
||||||
.then((json) => {
|
.then((json) => {
|
||||||
this.setState({
|
this.setState(
|
||||||
|
{
|
||||||
info: Object.assign({}, this.state.info, { cw: cw }),
|
info: Object.assign({}, this.state.info, { cw: cw }),
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
this.syncState({
|
this.syncState({
|
||||||
info: this.state.info,
|
info: this.state.info,
|
||||||
});
|
});
|
||||||
});
|
},
|
||||||
|
);
|
||||||
alert('已更新');
|
alert('已更新');
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
@@ -671,12 +676,16 @@ class FlowSidebar extends PureComponent {
|
|||||||
do_filter_name={
|
do_filter_name={
|
||||||
replies_cnt[DZ_NAME] > 1 ? this.set_filter_name.bind(this) : null
|
replies_cnt[DZ_NAME] > 1 ? this.set_filter_name.bind(this) : null
|
||||||
}
|
}
|
||||||
do_delete={this.make_do_delete(this.props.token, ()=>{window.location.reload();})}
|
do_delete={this.make_do_delete(this.props.token, () => {
|
||||||
|
window.location.reload();
|
||||||
|
})}
|
||||||
do_edit_cw={this.do_edit_cw.bind(this)}
|
do_edit_cw={this.do_edit_cw.bind(this)}
|
||||||
do_vote={this.do_vote.bind(this)}
|
do_vote={this.do_vote.bind(this)}
|
||||||
do_block={() => {this.block(
|
do_block={() => {
|
||||||
'洞主', 'post', this.state.info.pid, () => {window.location.reload();}
|
this.block('洞主', 'post', this.state.info.pid, () => {
|
||||||
)}}
|
window.location.reload();
|
||||||
|
});
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</ClickHandler>
|
</ClickHandler>
|
||||||
);
|
);
|
||||||
@@ -766,7 +775,9 @@ class FlowSidebar extends PureComponent {
|
|||||||
条回复被删除
|
条回复被删除
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{replies_to_show.map((reply, i) => !reply.blocked && (
|
{replies_to_show.map(
|
||||||
|
(reply, i) =>
|
||||||
|
!reply.blocked && (
|
||||||
<LazyLoad
|
<LazyLoad
|
||||||
key={i}
|
key={i}
|
||||||
offset={1500}
|
offset={1500}
|
||||||
@@ -792,15 +803,29 @@ class FlowSidebar extends PureComponent {
|
|||||||
? this.set_filter_name.bind(this)
|
? this.set_filter_name.bind(this)
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
do_delete={this.make_do_delete(this.props.token, this.load_replies.bind(this))}
|
do_delete={this.make_do_delete(
|
||||||
do_block={() => {this.block(
|
this.props.token,
|
||||||
reply.name, 'comment', reply.cid, this.load_replies.bind(this)
|
this.load_replies.bind(this),
|
||||||
)}}
|
)}
|
||||||
do_report={(e) => {this.report(e, `评论区${reply.name},评论id ${reply.cid}`)}}
|
do_block={() => {
|
||||||
|
this.block(
|
||||||
|
reply.name,
|
||||||
|
'comment',
|
||||||
|
reply.cid,
|
||||||
|
this.load_replies.bind(this),
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
do_report={(e) => {
|
||||||
|
this.report(
|
||||||
|
e,
|
||||||
|
`评论区${reply.name},评论id ${reply.cid}`,
|
||||||
|
);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</ClickHandler>
|
</ClickHandler>
|
||||||
</LazyLoad>
|
</LazyLoad>
|
||||||
))}
|
),
|
||||||
|
)}
|
||||||
{this.state.rev && main_thread_elem}
|
{this.state.rev && main_thread_elem}
|
||||||
{this.props.token ? (
|
{this.props.token ? (
|
||||||
<ReplyForm
|
<ReplyForm
|
||||||
@@ -820,19 +845,27 @@ class FlowSidebar extends PureComponent {
|
|||||||
class FlowItemRow extends PureComponent {
|
class FlowItemRow extends PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.needFold = props.info.cw &&
|
this.needFold =
|
||||||
|
props.info.cw &&
|
||||||
!props.search_param &&
|
!props.search_param &&
|
||||||
(window.config.whitelist_cw.indexOf('*')==-1 && window.config.whitelist_cw.indexOf(props.info.cw)==-1) &&
|
window.config.whitelist_cw.indexOf('*') == -1 &&
|
||||||
props.mode !== 'attention' && props.mode !== 'attention_finished';
|
window.config.whitelist_cw.indexOf(props.info.cw) == -1 &&
|
||||||
|
props.mode !== 'attention' &&
|
||||||
|
props.mode !== 'attention_finished';
|
||||||
this.color_picker = new ColorPicker();
|
this.color_picker = new ColorPicker();
|
||||||
this.state = {
|
this.state = {
|
||||||
replies: props.info.comments ? parse_replies(props.info.comments, this.color_picker) : [],
|
replies: props.info.comments
|
||||||
|
? parse_replies(props.info.comments, this.color_picker)
|
||||||
|
: [],
|
||||||
reply_status: 'done',
|
reply_status: 'done',
|
||||||
reply_error: null,
|
reply_error: null,
|
||||||
info: Object.assign({}, props.info, { variant: {} }),
|
info: Object.assign({}, props.info, { variant: {} }),
|
||||||
hidden: window.config.block_words_v2.some((word) =>
|
hidden:
|
||||||
|
(window.config.block_words_v2.some((word) =>
|
||||||
props.info.text.includes(word),
|
props.info.text.includes(word),
|
||||||
) && !props.info.can_del || this.needFold,
|
) &&
|
||||||
|
!props.info.can_del) ||
|
||||||
|
this.needFold,
|
||||||
attention: props.info.attention,
|
attention: props.info.attention,
|
||||||
cached: true, // default no display anything
|
cached: true, // default no display anything
|
||||||
};
|
};
|
||||||
@@ -918,14 +951,10 @@ class FlowItemRow extends PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {show_sidebar, token, search_param, is_quote } = this.props;
|
const { show_sidebar, token, search_param, is_quote } = this.props;
|
||||||
let show_pid = load_single_meta(show_sidebar, token, [
|
let show_pid = load_single_meta(show_sidebar, token, [this.state.info.pid]);
|
||||||
this.state.info.pid,
|
|
||||||
]);
|
|
||||||
|
|
||||||
let hl_rules = [
|
let hl_rules = [['pid', PID_RE]];
|
||||||
['pid', PID_RE],
|
|
||||||
];
|
|
||||||
let parts = split_text(this.state.info.text, hl_rules);
|
let parts = split_text(this.state.info.text, hl_rules);
|
||||||
|
|
||||||
//console.log('hl:', parts,this.state.info.pid);
|
//console.log('hl:', parts,this.state.info.pid);
|
||||||
@@ -939,8 +968,7 @@ class FlowItemRow extends PureComponent {
|
|||||||
QUOTE_BLACKLIST.indexOf(content) === -1 &&
|
QUOTE_BLACKLIST.indexOf(content) === -1 &&
|
||||||
parseInt(content) < parseInt(this.state.info.pid)
|
parseInt(content) < parseInt(this.state.info.pid)
|
||||||
) {
|
) {
|
||||||
if (quote_id === null)
|
if (quote_id === null) quote_id = parseInt(content);
|
||||||
quote_id = parseInt(content);
|
|
||||||
else {
|
else {
|
||||||
quote_id = null;
|
quote_id = null;
|
||||||
break;
|
break;
|
||||||
@@ -988,7 +1016,11 @@ class FlowItemRow extends PureComponent {
|
|||||||
<p>{this.state.reply_error}</p>
|
<p>{this.state.reply_error}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{this.state.replies.slice(0, PREVIEW_REPLY_COUNT).map((reply) => !reply.blocked && (
|
{this.state.replies
|
||||||
|
.slice(0, PREVIEW_REPLY_COUNT)
|
||||||
|
.map(
|
||||||
|
(reply) =>
|
||||||
|
!reply.blocked && (
|
||||||
<Reply
|
<Reply
|
||||||
key={reply.cid}
|
key={reply.cid}
|
||||||
info={reply}
|
info={reply}
|
||||||
@@ -996,7 +1028,8 @@ class FlowItemRow extends PureComponent {
|
|||||||
show_pid={show_pid}
|
show_pid={show_pid}
|
||||||
search_param={search_param}
|
search_param={search_param}
|
||||||
/>
|
/>
|
||||||
))}
|
),
|
||||||
|
)}
|
||||||
{this.state.replies.length > PREVIEW_REPLY_COUNT && (
|
{this.state.replies.length > PREVIEW_REPLY_COUNT && (
|
||||||
<div className="box box-tip">
|
<div className="box box-tip">
|
||||||
还有 {this.state.replies.length - PREVIEW_REPLY_COUNT} 条
|
还有 {this.state.replies.length - PREVIEW_REPLY_COUNT} 条
|
||||||
@@ -1007,7 +1040,8 @@ class FlowItemRow extends PureComponent {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (this.state.hidden) {
|
if (this.state.hidden) {
|
||||||
return this.needFold && (
|
return (
|
||||||
|
this.needFold && (
|
||||||
<div
|
<div
|
||||||
className="flow-item-row flow-item-row-with-prompt"
|
className="flow-item-row flow-item-row-with-prompt"
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
@@ -1059,6 +1093,7 @@ class FlowItemRow extends PureComponent {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1163,7 +1198,9 @@ function FlowChunk(props) {
|
|||||||
{({ value: token }) => (
|
{({ value: token }) => (
|
||||||
<div className="flow-chunk">
|
<div className="flow-chunk">
|
||||||
{!!props.title && <TitleLine text={props.title} />}
|
{!!props.title && <TitleLine text={props.title} />}
|
||||||
{props.list.map((info, ind) => !info.blocked && (
|
{props.list.map(
|
||||||
|
(info, ind) =>
|
||||||
|
!info.blocked && (
|
||||||
<LazyLoad
|
<LazyLoad
|
||||||
key={info.key || info.pid}
|
key={info.key || info.pid}
|
||||||
offset={500}
|
offset={500}
|
||||||
@@ -1193,7 +1230,8 @@ function FlowChunk(props) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</LazyLoad>
|
</LazyLoad>
|
||||||
))}
|
),
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</TokenCtx.Consumer>
|
</TokenCtx.Consumer>
|
||||||
@@ -1209,19 +1247,19 @@ export class Flow extends PureComponent {
|
|||||||
}
|
}
|
||||||
this.state = {
|
this.state = {
|
||||||
submode: submode,
|
submode: submode,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
get_submode_names(mode) {
|
get_submode_names(mode) {
|
||||||
switch(mode) {
|
switch (mode) {
|
||||||
case('list'):
|
case 'list':
|
||||||
return ['最新', '最近回复', '近期热门', '随机'];
|
return ['最新', '最近回复', '近期热门', '随机'];
|
||||||
case('attention'):
|
case 'attention':
|
||||||
return ['线上关注', '本地收藏'];
|
return ['线上关注', '本地收藏'];
|
||||||
case('search'):
|
case 'search':
|
||||||
return ['Tag搜索', '全文搜索', '头衔']
|
return ['Tag搜索', '全文搜索', '头衔'];
|
||||||
}
|
}
|
||||||
return []
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
set_submode(submode) {
|
set_submode(submode) {
|
||||||
@@ -1233,7 +1271,7 @@ export class Flow extends PureComponent {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { submode } = this.state;
|
const { submode } = this.state;
|
||||||
const submode_names = this.get_submode_names(this.props.mode)
|
const submode_names = this.get_submode_names(this.props.mode);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="aux-margin flow-submode-choice">
|
<div className="aux-margin flow-submode-choice">
|
||||||
@@ -1257,11 +1295,10 @@ export class Flow extends PureComponent {
|
|||||||
token={this.props.token}
|
token={this.props.token}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class SubFlow extends PureComponent {
|
class SubFlow extends PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -1410,7 +1447,9 @@ class SubFlow extends PureComponent {
|
|||||||
.split(' ')
|
.split(' ')
|
||||||
.every((keyword) => post.text.includes(keyword));
|
.every((keyword) => post.text.includes(keyword));
|
||||||
}) // Not using regex
|
}) // Not using regex
|
||||||
: json.data.filter((post) => !!post.text.match(regex_search)), // Using regex
|
: json.data.filter(
|
||||||
|
(post) => !!post.text.match(regex_search),
|
||||||
|
), // Using regex
|
||||||
},
|
},
|
||||||
mode: 'attention_finished',
|
mode: 'attention_finished',
|
||||||
loading_status: 'done',
|
loading_status: 'done',
|
||||||
@@ -1419,18 +1458,18 @@ class SubFlow extends PureComponent {
|
|||||||
window.saved_attentions = Array.from(
|
window.saved_attentions = Array.from(
|
||||||
new Set([
|
new Set([
|
||||||
...window.saved_attentions,
|
...window.saved_attentions,
|
||||||
...json.data.map(post => post.pid)
|
...json.data.map((post) => post.pid),
|
||||||
])
|
]),
|
||||||
).sort((a, b) => (b - a));
|
).sort((a, b) => b - a);
|
||||||
save_attentions();
|
save_attentions();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(failed);
|
.catch(failed);
|
||||||
} else if (this.props.submode === 1) {
|
} else if (this.props.submode === 1) {
|
||||||
const PERPAGE = 50;
|
const PERPAGE = 50;
|
||||||
let pids = window.saved_attentions.sort(
|
let pids = window.saved_attentions
|
||||||
(a, b) => (b - a)
|
.sort((a, b) => b - a)
|
||||||
).slice((page - 1) * PERPAGE, page * PERPAGE);
|
.slice((page - 1) * PERPAGE, page * PERPAGE);
|
||||||
if (pids.length) {
|
if (pids.length) {
|
||||||
API.get_multi(pids, this.props.token)
|
API.get_multi(pids, this.props.token)
|
||||||
.then((json) => {
|
.then((json) => {
|
||||||
@@ -1458,7 +1497,7 @@ class SubFlow extends PureComponent {
|
|||||||
console.log('local attention finished');
|
console.log('local attention finished');
|
||||||
this.setState({
|
this.setState({
|
||||||
loading_status: 'done',
|
loading_status: 'done',
|
||||||
mode: 'attention_finished'
|
mode: 'attention_finished',
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1496,18 +1535,23 @@ class SubFlow extends PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
trunc_string(s, max_len) {
|
trunc_string(s, max_len) {
|
||||||
return s.substr(0, max_len) + (
|
return s.substr(0, max_len) + (s.length > max_len ? '...' : '');
|
||||||
s.length > max_len ? '...' : ''
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gen_export() {
|
gen_export() {
|
||||||
this.setState({
|
this.setState({
|
||||||
can_export: false,
|
can_export: false,
|
||||||
export_text: "以下是你关注的洞及摘要,复制保存到本地吧。\n\n" + this.state.chunks.data.map(
|
export_text:
|
||||||
p => `#${p.pid}: ${
|
'以下是你关注的洞及摘要,复制保存到本地吧。\n\n' +
|
||||||
this.trunc_string(p.text.replaceAll('\n', ' '), 50)
|
this.state.chunks.data
|
||||||
}`).join('\n\n')
|
.map(
|
||||||
|
(p) =>
|
||||||
|
`#${p.pid}: ${this.trunc_string(
|
||||||
|
p.text.replaceAll('\n', ' '),
|
||||||
|
50,
|
||||||
|
)}`,
|
||||||
|
)
|
||||||
|
.join('\n\n'),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1515,9 +1559,14 @@ class SubFlow extends PureComponent {
|
|||||||
const should_deletion_detect = localStorage['DELETION_DETECT'] === 'on';
|
const should_deletion_detect = localStorage['DELETION_DETECT'] === 'on';
|
||||||
return (
|
return (
|
||||||
<div className="flow-container">
|
<div className="flow-container">
|
||||||
|
|
||||||
{this.state.mode === 'attention_finished' && this.props.submode == 0 && (
|
{this.state.mode === 'attention_finished' && this.props.submode == 0 && (
|
||||||
<button className="export-btn" type="button" onClick={this.gen_export.bind(this)}>导出</button>
|
<button
|
||||||
|
className="export-btn"
|
||||||
|
type="button"
|
||||||
|
onClick={this.gen_export.bind(this)}
|
||||||
|
>
|
||||||
|
导出
|
||||||
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{this.state.export_text && (
|
{this.state.export_text && (
|
||||||
|
|||||||
@@ -16,4 +16,3 @@
|
|||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export class MessageViewer extends PureComponent {
|
|||||||
loading_status: 'idle',
|
loading_status: 'idle',
|
||||||
msg: [],
|
msg: [],
|
||||||
};
|
};
|
||||||
this.input_suf_ref=React.createRef();
|
this.input_suf_ref = React.createRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@@ -25,12 +25,9 @@ export class MessageViewer extends PureComponent {
|
|||||||
loading_status: 'loading',
|
loading_status: 'loading',
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
fetch(
|
fetch(API_BASE + '/systemlog', {
|
||||||
API_BASE + '/systemlog',
|
headers: { 'User-Token': this.props.token },
|
||||||
{
|
})
|
||||||
headers: {'User-Token': this.props.token},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.then(get_json)
|
.then(get_json)
|
||||||
.then((json) => {
|
.then((json) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -53,10 +50,9 @@ export class MessageViewer extends PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
do_set_token() {
|
do_set_token() {
|
||||||
if (this.state.loading_status==='loading')
|
if (this.state.loading_status === 'loading') return;
|
||||||
return;
|
|
||||||
if (!this.input_suf_ref.current.value) {
|
if (!this.input_suf_ref.current.value) {
|
||||||
alert("不建议后缀为空");
|
alert('不建议后缀为空');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let tt = this.state.tmp_token + '_' + this.input_suf_ref.current.value;
|
let tt = this.state.tmp_token + '_' + this.input_suf_ref.current.value;
|
||||||
@@ -84,20 +80,29 @@ export class MessageViewer extends PureComponent {
|
|||||||
else if (this.state.loading_status === 'done')
|
else if (this.state.loading_status === 'done')
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<br/>
|
<br />
|
||||||
<p>
|
<p>
|
||||||
最近一次重置 <Time stamp={this.state.start_time} short={false} />
|
最近一次重置 <Time stamp={this.state.start_time} short={false} />
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
随机盐 <b>{this.state.salt}</b>
|
随机盐 <b>{this.state.salt}</b>
|
||||||
</p>
|
</p>
|
||||||
<br/>
|
<br />
|
||||||
<div>
|
<div>
|
||||||
<p>15分钟临时token:</p>
|
<p>15分钟临时token:</p>
|
||||||
<div className="input-prepend">{this.state.tmp_token}_ </div>
|
<div className="input-prepend">{this.state.tmp_token}_ </div>
|
||||||
<input type="text" className="input-suf" ref={this.input_suf_ref} placeholder="自定义后缀" maxLength={10}/>
|
<input
|
||||||
<button type="button" disabled={this.state.loading_status==='loading'}
|
type="text"
|
||||||
onClick={(e)=>this.do_set_token()}>
|
className="input-suf"
|
||||||
|
ref={this.input_suf_ref}
|
||||||
|
placeholder="自定义后缀"
|
||||||
|
maxLength={10}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
disabled={this.state.loading_status === 'loading'}
|
||||||
|
onClick={(e) => this.do_set_token()}
|
||||||
|
>
|
||||||
使用
|
使用
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -105,8 +110,7 @@ export class MessageViewer extends PureComponent {
|
|||||||
<div className="box" key={msg.type + msg.timestamp}>
|
<div className="box" key={msg.type + msg.timestamp}>
|
||||||
<div className="box-header">
|
<div className="box-header">
|
||||||
<Time stamp={msg.timestamp} short={false} />
|
<Time stamp={msg.timestamp} short={false} />
|
||||||
|
|
||||||
|
|
||||||
<b>{msg.type}</b>
|
<b>{msg.type}</b>
|
||||||
|
|
||||||
<span className="box-header-name">{msg.user}</span>
|
<span className="box-header-name">{msg.user}</span>
|
||||||
@@ -117,7 +121,7 @@ export class MessageViewer extends PureComponent {
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
else return null;
|
else return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,19 +12,19 @@
|
|||||||
z-index: 20;
|
z-index: 20;
|
||||||
}
|
}
|
||||||
.sidebar-on .sidebar-shadow {
|
.sidebar-on .sidebar-shadow {
|
||||||
opacity: .3;
|
opacity: 0.3;
|
||||||
pointer-events: initial;
|
pointer-events: initial;
|
||||||
}
|
}
|
||||||
.sidebar-on .sidebar-shadow:active {
|
.sidebar-on .sidebar-shadow:active {
|
||||||
opacity: .5;
|
opacity: 0.5;
|
||||||
transition: unset;
|
transition: unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
.root-dark-mode .sidebar-on .sidebar-shadow {
|
.root-dark-mode .sidebar-on .sidebar-shadow {
|
||||||
opacity: .65;
|
opacity: 0.65;
|
||||||
}
|
}
|
||||||
.root-dark-mode .sidebar-on .sidebar-shadow:active {
|
.root-dark-mode .sidebar-on .sidebar-shadow:active {
|
||||||
opacity: .8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar {
|
.sidebar {
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
https://dev.to/peiche/100vh-behavior-on-chrome-2hm8
|
https://dev.to/peiche/100vh-behavior-on-chrome-2hm8
|
||||||
*/
|
*/
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: rgba(255,255,255,.7);
|
background-color: rgba(255, 255, 255, 0.7);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
padding-top: 3em;
|
padding-top: 3em;
|
||||||
/* padding-bottom: 1em; */ /* move to sidebar-content */
|
/* padding-bottom: 1em; */ /* move to sidebar-content */
|
||||||
@@ -47,27 +47,30 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.root-dark-mode .sidebar {
|
.root-dark-mode .sidebar {
|
||||||
background-color: hsla(0,0%,5%,.4);
|
background-color: hsla(0, 0%, 5%, 0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar, .sidebar-title {
|
.sidebar,
|
||||||
|
.sidebar-title {
|
||||||
left: 700px;
|
left: 700px;
|
||||||
will-change: opacity, transform;
|
will-change: opacity, transform;
|
||||||
z-index: 21;
|
z-index: 21;
|
||||||
width: calc(100% - 700px);
|
width: calc(100% - 700px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-on .sidebar, .sidebar-on .sidebar-title {
|
.sidebar-on .sidebar,
|
||||||
animation: sidebar-fadein .15s cubic-bezier(0.15, 0.4, 0.6, 1);
|
.sidebar-on .sidebar-title {
|
||||||
|
animation: sidebar-fadein 0.15s cubic-bezier(0.15, 0.4, 0.6, 1);
|
||||||
}
|
}
|
||||||
.sidebar-off .sidebar, .sidebar-off .sidebar-title {
|
.sidebar-off .sidebar,
|
||||||
|
.sidebar-off .sidebar-title {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
backdrop-filter: none;
|
backdrop-filter: none;
|
||||||
animation: sidebar-fadeout .2s cubic-bezier(0.15, 0.4, 0.6, 1);
|
animation: sidebar-fadeout 0.2s cubic-bezier(0.15, 0.4, 0.6, 1);
|
||||||
}
|
}
|
||||||
.sidebar-container {
|
.sidebar-container {
|
||||||
animation: sidebar-initial .25s linear; /* skip initial animation */
|
animation: sidebar-initial 0.25s linear; /* skip initial animation */
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes sidebar-fadeout {
|
@keyframes sidebar-fadeout {
|
||||||
@@ -97,8 +100,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
@keyframes sidebar-initial {
|
@keyframes sidebar-initial {
|
||||||
from {opacity: 0;}
|
from {
|
||||||
to {opacity: 0;}
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-title {
|
.sidebar-title {
|
||||||
@@ -108,15 +115,15 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
top: 0;
|
top: 0;
|
||||||
line-height: 3em;
|
line-height: 3em;
|
||||||
padding-left: .5em;
|
padding-left: 0.5em;
|
||||||
background-color: rgba(255,255,255,.6);
|
background-color: rgba(255, 255, 255, 0.6);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
backdrop-filter: blur(5px);
|
backdrop-filter: blur(5px);
|
||||||
box-shadow: 0 3px 5px rgba(0,0,0,.2);
|
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.root-dark-mode .sidebar-title {
|
.root-dark-mode .sidebar-title {
|
||||||
background-color: hsla(0,0%,18%,.6);
|
background-color: hsla(0, 0%, 18%, 0.6);
|
||||||
color: var(--foreground-dark);
|
color: var(--foreground-dark);
|
||||||
text-shadow: 0 0 3px black;
|
text-shadow: 0 0 3px black;
|
||||||
}
|
}
|
||||||
@@ -125,7 +132,6 @@
|
|||||||
pointer-events: initial;
|
pointer-events: initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* move all padding to sidebar-content - the scrolling div (overflow-y: auto) */
|
/* move all padding to sidebar-content - the scrolling div (overflow-y: auto) */
|
||||||
/* .sidebar, */
|
/* .sidebar, */
|
||||||
.sidebar-content,
|
.sidebar-content,
|
||||||
@@ -139,27 +145,31 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 1300px) {
|
@media screen and (max-width: 1300px) {
|
||||||
.sidebar, .sidebar-title {
|
.sidebar,
|
||||||
|
.sidebar-title {
|
||||||
left: calc(100% - 550px);
|
left: calc(100% - 550px);
|
||||||
width: 550px;/*
|
width: 550px; /*
|
||||||
padding-left: .5em;
|
padding-left: .5em;
|
||||||
padding-right: .5em; */
|
padding-right: .5em; */
|
||||||
}
|
}
|
||||||
.sidebar-content, .sidebar-title {
|
.sidebar-content,
|
||||||
padding-left: .5em;
|
.sidebar-title {
|
||||||
padding-right: .5em;
|
padding-left: 0.5em;
|
||||||
|
padding-right: 0.5em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@media screen and (max-width: 580px) {
|
@media screen and (max-width: 580px) {
|
||||||
.sidebar, .sidebar-title {
|
.sidebar,
|
||||||
|
.sidebar-title {
|
||||||
left: 27px;
|
left: 27px;
|
||||||
width: calc(100% - 27px);
|
width: calc(100% - 27px);
|
||||||
/* padding-left: .25em;
|
/* padding-left: .25em;
|
||||||
padding-right: .25em; */
|
padding-right: .25em; */
|
||||||
}
|
}
|
||||||
.sidebar-content, .sidebar-title {
|
.sidebar-content,
|
||||||
padding-left: .25em;
|
.sidebar-title {
|
||||||
padding-right: .25em;
|
padding-left: 0.25em;
|
||||||
|
padding-right: 0.25em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +185,7 @@
|
|||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-content-hide{
|
.sidebar-content-hide {
|
||||||
/* will make lazyload working correctly */
|
/* will make lazyload working correctly */
|
||||||
height: 0;
|
height: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|||||||
@@ -5,20 +5,20 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 7em;
|
height: 7em;
|
||||||
background-color: rgba(255,255,255,.8);
|
background-color: rgba(255, 255, 255, 0.8);
|
||||||
box-shadow: 0 0 25px rgba(0,0,0,.4);
|
box-shadow: 0 0 25px rgba(0, 0, 0, 0.4);
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
backdrop-filter: blur(5px);
|
backdrop-filter: blur(5px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.root-dark-mode .title-bar {
|
.root-dark-mode .title-bar {
|
||||||
background-color: hsla(0,0%,12%,.8);
|
background-color: hsla(0, 0%, 12%, 0.8);
|
||||||
box-shadow: 0 0 5px rgba(255,255,255,.1);
|
box-shadow: 0 0 5px rgba(255, 255, 255, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.control-bar {
|
.control-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-top: .5em;
|
margin-top: 0.5em;
|
||||||
line-height: 2em;
|
line-height: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,9 +33,9 @@
|
|||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
.control-btn-label {
|
.control-btn-label {
|
||||||
margin-left: .25rem;
|
margin-left: 0.25rem;
|
||||||
font-size: .9em;
|
font-size: 0.9em;
|
||||||
vertical-align: .05em;
|
vertical-align: 0.05em;
|
||||||
}
|
}
|
||||||
@media screen and (max-width: 900px) {
|
@media screen and (max-width: 900px) {
|
||||||
.control-btn {
|
.control-btn {
|
||||||
@@ -45,13 +45,13 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.control-search {
|
.control-search {
|
||||||
padding: 0 .5em;
|
padding: 0 0.5em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.root-dark-mode .control-btn {
|
.root-dark-mode .control-btn {
|
||||||
color: var(--foreground-dark);
|
color: var(--foreground-dark);
|
||||||
opacity: .9;
|
opacity: 0.9;
|
||||||
}
|
}
|
||||||
.root-dark-mode .control-btn:hover {
|
.root-dark-mode .control-btn:hover {
|
||||||
color: var(--foreground-dark);
|
color: var(--foreground-dark);
|
||||||
@@ -61,8 +61,8 @@
|
|||||||
.control-search {
|
.control-search {
|
||||||
flex: auto;
|
flex: auto;
|
||||||
color: black;
|
color: black;
|
||||||
background-color: rgba(255,255,255,.3) !important;
|
background-color: rgba(255, 255, 255, 0.3) !important;
|
||||||
margin: 0 .5em;
|
margin: 0 0.5em;
|
||||||
min-width: 8em;
|
min-width: 8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,11 +71,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.root-dark-mode .control-search {
|
.root-dark-mode .control-search {
|
||||||
background-color: hsla(0,0%,35%,.6) !important;
|
background-color: hsla(0, 0%, 35%, 0.6) !important;
|
||||||
color: var(--foreground-dark);
|
color: var(--foreground-dark);
|
||||||
}
|
}
|
||||||
.root-dark-mode .control-search:focus {
|
.root-dark-mode .control-search:focus {
|
||||||
background-color: hsl(0,0%,80%) !important;
|
background-color: hsl(0, 0%, 80%) !important;
|
||||||
color: black !important;
|
color: black !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,5 +84,5 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.help-desc-box p {
|
.help-desc-box p {
|
||||||
margin: .5em;
|
margin: 0.5em;
|
||||||
}
|
}
|
||||||
12
src/Title.js
12
src/Title.js
@@ -36,10 +36,11 @@ class ControlBar extends PureComponent {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("hashchange",
|
window.addEventListener(
|
||||||
|
'hashchange',
|
||||||
() => {
|
() => {
|
||||||
let text = decodeURIComponent(window.location.hash).substr(1);
|
let text = decodeURIComponent(window.location.hash).substr(1);
|
||||||
if(text && text[0]!='#') {
|
if (text && text[0] != '#') {
|
||||||
console.log('search', text);
|
console.log('search', text);
|
||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
@@ -51,7 +52,7 @@ class ControlBar extends PureComponent {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
false
|
false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,7 +137,10 @@ class ControlBar extends PureComponent {
|
|||||||
className="control-search"
|
className="control-search"
|
||||||
value={this.state.search_text}
|
value={this.state.search_text}
|
||||||
placeholder={
|
placeholder={
|
||||||
this.props.mode === 'attention' ? '在关注列表中搜索' : '关键词 / tag / #树洞号'}
|
this.props.mode === 'attention'
|
||||||
|
? '在关注列表中搜索'
|
||||||
|
: '关键词 / tag / #树洞号'
|
||||||
|
}
|
||||||
onChange={this.on_change_bound}
|
onChange={this.on_change_bound}
|
||||||
onKeyPress={this.on_keypress_bound}
|
onKeyPress={this.on_keypress_bound}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -31,12 +31,11 @@
|
|||||||
min-height: 2em;
|
min-height: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.post-form-bar {
|
.post-form-bar {
|
||||||
line-height: 2em;
|
line-height: 2em;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
margin-bottom: .5em;
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-form-bar .checkbox-bar {
|
.post-form-bar .checkbox-bar {
|
||||||
@@ -49,19 +48,19 @@
|
|||||||
margin: 0 0.5rem;
|
margin: 0 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-form-bar input[type=file] {
|
.post-form-bar input[type='file'] {
|
||||||
border: 0;
|
border: 0;
|
||||||
padding: 0 0 0 .5em;
|
padding: 0 0 0 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 580px) {
|
@media screen and (max-width: 580px) {
|
||||||
.post-form-bar input[type=file] {
|
.post-form-bar input[type='file'] {
|
||||||
width: 120px;
|
width: 120px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 320px) {
|
@media screen and (max-width: 320px) {
|
||||||
.post-form-bar input[type=file] {
|
.post-form-bar input[type='file'] {
|
||||||
width: 100px;
|
width: 100px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,8 +79,8 @@
|
|||||||
|
|
||||||
.post-form-img-tip {
|
.post-form-img-tip {
|
||||||
font-size: small;
|
font-size: small;
|
||||||
margin-top: -.5em;
|
margin-top: -0.5em;
|
||||||
margin-bottom: .5em;
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-form textarea {
|
.post-form textarea {
|
||||||
@@ -106,7 +105,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.life-info-table td {
|
.life-info-table td {
|
||||||
padding: .25em;
|
padding: 0.25em;
|
||||||
}
|
}
|
||||||
.life-info-table td:nth-child(1) {
|
.life-info-table td:nth-child(1) {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@@ -114,7 +113,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.life-info-error a {
|
.life-info-error a {
|
||||||
--var-link-color: hsl(25,100%,45%);
|
--var-link-color: hsl(25, 100%, 45%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.spoiler-input {
|
.spoiler-input {
|
||||||
|
|||||||
@@ -12,11 +12,8 @@ import { ConfigUI } from './Config';
|
|||||||
import fixOrientation from 'fix-orientation';
|
import fixOrientation from 'fix-orientation';
|
||||||
import copy from 'copy-to-clipboard';
|
import copy from 'copy-to-clipboard';
|
||||||
import { cache } from './cache';
|
import { cache } from './cache';
|
||||||
import {
|
import { API, get_json } from './flows_api';
|
||||||
API,
|
import { save_attentions } from './Attention';
|
||||||
get_json,
|
|
||||||
} from './flows_api';
|
|
||||||
import { save_attentions } from './Attention'
|
|
||||||
|
|
||||||
import './UserAction.css';
|
import './UserAction.css';
|
||||||
|
|
||||||
@@ -57,7 +54,9 @@ export function InfoSidebar(props) {
|
|||||||
<span className="icon icon-textfile" />
|
<span className="icon icon-textfile" />
|
||||||
<label>树洞规范(试行)</label>
|
<label>树洞规范(试行)</label>
|
||||||
</a>
|
</a>
|
||||||
<p><em>强烈建议开始使用前先看一遍所有设置选项</em></p>
|
<p>
|
||||||
|
<em>强烈建议开始使用前先看一遍所有设置选项</em>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="box help-desc-box">
|
<div className="box help-desc-box">
|
||||||
<p>
|
<p>
|
||||||
@@ -87,15 +86,18 @@ export function InfoSidebar(props) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="box help-desc-box">
|
<div className="box help-desc-box">
|
||||||
<p>意见反馈请加tag #意见反馈 或到github后端的issue区。</p>
|
<p>意见反馈请加tag #意见反馈 或到github后端的issue区。</p>
|
||||||
<p>新T树洞强烈期待有其他更多树洞的出现,一起分布式互联,构建清华树洞族。详情见 关于 中的描述。</p>
|
<p>
|
||||||
<p>联系我们:<a href={"mailto:"+EMAIL}>{EMAIL}</a> 。</p>
|
新T树洞强烈期待有其他更多树洞的出现,一起分布式互联,构建清华树洞族。详情见
|
||||||
|
关于 中的描述。
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
联系我们:<a href={'mailto:' + EMAIL}>{EMAIL}</a> 。
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="box help-desc-box">
|
<div className="box help-desc-box">
|
||||||
<p>
|
<p>
|
||||||
新T树洞 网页版 by @hole_thu,基于
|
新T树洞 网页版 by @hole_thu,基于
|
||||||
<a href="https://www.gnu.org/licenses/agpl-3.0.html"
|
<a href="https://www.gnu.org/licenses/agpl-3.0.html" target="_blank">
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
AGPLv3
|
AGPLv3
|
||||||
</a>
|
</a>
|
||||||
协议在{' '}
|
协议在{' '}
|
||||||
@@ -121,7 +123,8 @@ export function InfoSidebar(props) {
|
|||||||
>
|
>
|
||||||
T大树洞网页版 by @thuhole
|
T大树洞网页版 by @thuhole
|
||||||
</a>
|
</a>
|
||||||
、 <a href="https://reactjs.org/" target="_blank" rel="noopener">
|
、{' '}
|
||||||
|
<a href="https://reactjs.org/" target="_blank" rel="noopener">
|
||||||
React
|
React
|
||||||
</a>
|
</a>
|
||||||
、
|
、
|
||||||
@@ -139,8 +142,8 @@ export class LoginForm extends Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
'custom_title': window.TITLE || ''
|
custom_title: window.TITLE || '',
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
update_title(title, token) {
|
update_title(title, token) {
|
||||||
@@ -151,10 +154,11 @@ export class LoginForm extends Component {
|
|||||||
API.set_title(title, token)
|
API.set_title(title, token)
|
||||||
.then((json) => {
|
.then((json) => {
|
||||||
if (json.code === 0) {
|
if (json.code === 0) {
|
||||||
window.TITLE = title
|
window.TITLE = title;
|
||||||
alert('专属头衔设置成功');
|
alert('专属头衔设置成功');
|
||||||
}
|
}
|
||||||
}).catch(err => alert("设置头衔出错了:\n"+ err));
|
})
|
||||||
|
.catch((err) => alert('设置头衔出错了:\n' + err));
|
||||||
}
|
}
|
||||||
|
|
||||||
copy_token(token) {
|
copy_token(token) {
|
||||||
@@ -203,22 +207,27 @@ export class LoginForm extends Component {
|
|||||||
复制 User Token
|
复制 User Token
|
||||||
</a>
|
</a>
|
||||||
<br />
|
<br />
|
||||||
User Token仅用于开发bot,切勿告知他人。若怀疑被盗号请刷新Token(刷新功能即将上线)。
|
User
|
||||||
|
Token仅用于开发bot,切勿告知他人。若怀疑被盗号请刷新Token(刷新功能即将上线)。
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
专属头衔:
|
专属头衔:
|
||||||
<input
|
<input
|
||||||
value={this.state.custom_title}
|
value={this.state.custom_title}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
this.setState({ custom_title: e.target.value})
|
this.setState({ custom_title: e.target.value });
|
||||||
}}
|
}}
|
||||||
maxLength={10}
|
maxLength={10}
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
className="update-title-btn"
|
className="update-title-btn"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={(e) => {this.update_title(this.state.custom_title, token.value)}}
|
onClick={(e) => {
|
||||||
>提交</button>
|
this.update_title(this.state.custom_title, token.value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
提交
|
||||||
|
</button>
|
||||||
<br />
|
<br />
|
||||||
设置专属头衔后,可在发言时选择使用。重置后需重新设置。临时用户如需保持头衔请使用相同后缀。
|
设置专属头衔后,可在发言时选择使用。重置后需重新设置。临时用户如需保持头衔请使用相同后缀。
|
||||||
</p>
|
</p>
|
||||||
@@ -319,17 +328,14 @@ export class ReplyForm extends Component {
|
|||||||
text: text,
|
text: text,
|
||||||
use_title: use_title ? '1' : '',
|
use_title: use_title ? '1' : '',
|
||||||
});
|
});
|
||||||
fetch(
|
fetch(API_BASE + '/docomment', {
|
||||||
API_BASE + '/docomment',
|
|
||||||
{
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
'User-Token': this.props.token,
|
'User-Token': this.props.token,
|
||||||
},
|
},
|
||||||
body: data,
|
body: data,
|
||||||
},
|
})
|
||||||
)
|
|
||||||
.then(get_json)
|
.then(get_json)
|
||||||
.then((json) => {
|
.then((json) => {
|
||||||
if (json.code !== 0) {
|
if (json.code !== 0) {
|
||||||
@@ -338,7 +344,7 @@ export class ReplyForm extends Component {
|
|||||||
|
|
||||||
let saved_attentions = window.saved_attentions;
|
let saved_attentions = window.saved_attentions;
|
||||||
if (!saved_attentions.includes(pid)) {
|
if (!saved_attentions.includes(pid)) {
|
||||||
saved_attentions.unshift(pid)
|
saved_attentions.unshift(pid);
|
||||||
window.saved_attentions = saved_attentions;
|
window.saved_attentions = saved_attentions;
|
||||||
save_attentions();
|
save_attentions();
|
||||||
}
|
}
|
||||||
@@ -418,8 +424,8 @@ export class ReplyForm extends Component {
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
onChange={this.on_use_title_change_bound}
|
onChange={this.on_use_title_change_bound}
|
||||||
checked={this.state.use_title}
|
checked={this.state.use_title}
|
||||||
/>
|
/>{' '}
|
||||||
{' '}使用头衔
|
使用头衔
|
||||||
</label>
|
</label>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -490,18 +496,24 @@ export class PostForm extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
do_post() {
|
do_post() {
|
||||||
const { cw, text, allow_search, use_title, has_poll, poll_options } = this.state;
|
const {
|
||||||
|
cw,
|
||||||
|
text,
|
||||||
|
allow_search,
|
||||||
|
use_title,
|
||||||
|
has_poll,
|
||||||
|
poll_options,
|
||||||
|
} = this.state;
|
||||||
let data = new URLSearchParams({
|
let data = new URLSearchParams({
|
||||||
cw: cw,
|
cw: cw,
|
||||||
text: text,
|
text: text,
|
||||||
allow_search: allow_search ? '1' : '',
|
allow_search: allow_search ? '1' : '',
|
||||||
use_title: use_title ? '1' : '',
|
use_title: use_title ? '1' : '',
|
||||||
type: 'text'
|
type: 'text',
|
||||||
});
|
});
|
||||||
if (has_poll) {
|
if (has_poll) {
|
||||||
poll_options.forEach((opt) => {
|
poll_options.forEach((opt) => {
|
||||||
if (opt)
|
if (opt) data.append('poll_options', opt);
|
||||||
data.append('poll_options', opt);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -692,15 +704,14 @@ export class PostForm extends Component {
|
|||||||
let text = event.target.value;
|
let text = event.target.value;
|
||||||
poll_options[idx] = text;
|
poll_options[idx] = text;
|
||||||
if (!text && poll_options.length > 1) {
|
if (!text && poll_options.length > 1) {
|
||||||
poll_options.splice(idx, 1)
|
poll_options.splice(idx, 1);
|
||||||
}
|
}
|
||||||
if (poll_options[poll_options.length - 1] && poll_options.length < 8) {
|
if (poll_options[poll_options.length - 1] && poll_options.length < 8) {
|
||||||
poll_options.push('')
|
poll_options.push('');
|
||||||
}
|
}
|
||||||
this.setState({ poll_options: poll_options });
|
this.setState({ poll_options: poll_options });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { has_poll, poll_options, preview, loading_status } = this.state;
|
const { has_poll, poll_options, preview, loading_status } = this.state;
|
||||||
return (
|
return (
|
||||||
@@ -748,8 +759,8 @@ export class PostForm extends Component {
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
onChange={this.on_allow_search_change_bound}
|
onChange={this.on_allow_search_change_bound}
|
||||||
checked={this.state.allow_search}
|
checked={this.state.allow_search}
|
||||||
/>
|
/>{' '}
|
||||||
{' '}允许搜索
|
允许搜索
|
||||||
</label>
|
</label>
|
||||||
{window.TITLE && (
|
{window.TITLE && (
|
||||||
<label>
|
<label>
|
||||||
@@ -757,8 +768,8 @@ export class PostForm extends Component {
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
onChange={this.on_use_title_change_bound}
|
onChange={this.on_use_title_change_bound}
|
||||||
checked={this.state.use_title}
|
checked={this.state.use_title}
|
||||||
/>
|
/>{' '}
|
||||||
{' '}使用头衔
|
使用头衔
|
||||||
</label>
|
</label>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -815,7 +826,7 @@ export class PostForm extends Component {
|
|||||||
{has_poll && (
|
{has_poll && (
|
||||||
<div className="post-form-poll-options">
|
<div className="post-form-poll-options">
|
||||||
<h6>投票选项</h6>
|
<h6>投票选项</h6>
|
||||||
{poll_options.map( (option, idx) => (
|
{poll_options.map((option, idx) => (
|
||||||
<input
|
<input
|
||||||
key={idx}
|
key={idx}
|
||||||
type="text"
|
type="text"
|
||||||
@@ -827,7 +838,9 @@ export class PostForm extends Component {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<br /><br /><br />
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
<p>
|
<p>
|
||||||
<small>
|
<small>
|
||||||
请遵守
|
请遵守
|
||||||
@@ -839,7 +852,8 @@ export class PostForm extends Component {
|
|||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<small>
|
<small>
|
||||||
插入图片请使用图片外链,Markdown格式 , 支持动图,支持多图。推荐的图床:
|
插入图片请使用图片外链,Markdown格式 ,
|
||||||
|
支持动图,支持多图。推荐的图床:
|
||||||
<a href="https://imgchr.com/" target="_blank">
|
<a href="https://imgchr.com/" target="_blank">
|
||||||
路过图床
|
路过图床
|
||||||
</a>
|
</a>
|
||||||
@@ -848,7 +862,10 @@ export class PostForm extends Component {
|
|||||||
sm.ms
|
sm.ms
|
||||||
</a>
|
</a>
|
||||||
、
|
、
|
||||||
<a href="https://bbs.pku.edu.cn/v2/post-read.php?bid=154&threadid=3743" target="_blank">
|
<a
|
||||||
|
href="https://bbs.pku.edu.cn/v2/post-read.php?bid=154&threadid=3743"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
未名BBS
|
未名BBS
|
||||||
</a>
|
</a>
|
||||||
、
|
、
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { get_json, gen_name} from './infrastructure/functions';
|
import { get_json, gen_name } from './infrastructure/functions';
|
||||||
import { API_BASE } from './Common';
|
import { API_BASE } from './Common';
|
||||||
import { cache } from './cache';
|
import { cache } from './cache';
|
||||||
|
|
||||||
@@ -35,14 +35,11 @@ export const parse_replies = (replies, color_picker) =>
|
|||||||
export const API = {
|
export const API = {
|
||||||
load_replies: async (pid, token, color_picker, cache_version) => {
|
load_replies: async (pid, token, color_picker, cache_version) => {
|
||||||
pid = parseInt(pid);
|
pid = parseInt(pid);
|
||||||
let response = await fetch(
|
let response = await fetch(API_BASE + '/getcomment?pid=' + pid, {
|
||||||
API_BASE + '/getcomment?pid=' + pid ,
|
|
||||||
{
|
|
||||||
headers: {
|
headers: {
|
||||||
'User-Token': token,
|
'User-Token': token,
|
||||||
}
|
},
|
||||||
}
|
});
|
||||||
);
|
|
||||||
let json = await handle_response(response);
|
let json = await handle_response(response);
|
||||||
// Why delete then put ??
|
// Why delete then put ??
|
||||||
//console.log('Put cache', json, pid, cache_version);
|
//console.log('Put cache', json, pid, cache_version);
|
||||||
@@ -70,17 +67,14 @@ export const API = {
|
|||||||
let data = new URLSearchParams();
|
let data = new URLSearchParams();
|
||||||
data.append('pid', pid);
|
data.append('pid', pid);
|
||||||
data.append('switch', attention ? '1' : '0');
|
data.append('switch', attention ? '1' : '0');
|
||||||
let response = await fetch(
|
let response = await fetch(API_BASE + '/attention', {
|
||||||
API_BASE + '/attention',
|
|
||||||
{
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
'User-Token': token,
|
'User-Token': token,
|
||||||
},
|
},
|
||||||
body: data,
|
body: data,
|
||||||
},
|
});
|
||||||
);
|
|
||||||
// Delete cache to update `attention` on next reload
|
// Delete cache to update `attention` on next reload
|
||||||
cache().delete(pid);
|
cache().delete(pid);
|
||||||
return handle_response(response, false);
|
return handle_response(response, false);
|
||||||
@@ -90,55 +84,46 @@ export const API = {
|
|||||||
let data = new URLSearchParams();
|
let data = new URLSearchParams();
|
||||||
data.append('pid', pid);
|
data.append('pid', pid);
|
||||||
data.append('reason', reason);
|
data.append('reason', reason);
|
||||||
let response = await fetch(
|
let response = await fetch(API_BASE + '/report', {
|
||||||
API_BASE + '/report',
|
|
||||||
{
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
'User-Token': token,
|
'User-Token': token,
|
||||||
},
|
},
|
||||||
body: data,
|
body: data,
|
||||||
},
|
});
|
||||||
);
|
|
||||||
return handle_response(response, false);
|
return handle_response(response, false);
|
||||||
},
|
},
|
||||||
|
|
||||||
block: async (type, id, token) => {
|
block: async (type, id, token) => {
|
||||||
let data = new URLSearchParams([
|
let data = new URLSearchParams([
|
||||||
['type', type], ['id', id]
|
['type', type],
|
||||||
|
['id', id],
|
||||||
]);
|
]);
|
||||||
let response = await fetch(
|
let response = await fetch(API_BASE + '/block', {
|
||||||
API_BASE + '/block',
|
|
||||||
{
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
'User-Token': token,
|
'User-Token': token,
|
||||||
},
|
},
|
||||||
body: data,
|
body: data,
|
||||||
},
|
});
|
||||||
);
|
|
||||||
return handle_response(response, false);
|
return handle_response(response, false);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
del: async (type, id, note, token) => {
|
del: async (type, id, note, token) => {
|
||||||
let data = new URLSearchParams();
|
let data = new URLSearchParams();
|
||||||
data.append('type', type);
|
data.append('type', type);
|
||||||
data.append('id', id);
|
data.append('id', id);
|
||||||
data.append('note', note);
|
data.append('note', note);
|
||||||
let response = await fetch(
|
let response = await fetch(API_BASE + '/delete', {
|
||||||
API_BASE + '/delete',
|
|
||||||
{
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
'User-Token': token,
|
'User-Token': token,
|
||||||
},
|
},
|
||||||
body: data,
|
body: data,
|
||||||
},
|
});
|
||||||
);
|
|
||||||
return handle_response(response, false);
|
return handle_response(response, false);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -146,17 +131,14 @@ export const API = {
|
|||||||
let data = new URLSearchParams();
|
let data = new URLSearchParams();
|
||||||
data.append('cw', cw);
|
data.append('cw', cw);
|
||||||
data.append('pid', id);
|
data.append('pid', id);
|
||||||
let response = await fetch(
|
let response = await fetch(API_BASE + '/editcw', {
|
||||||
API_BASE + '/editcw',
|
|
||||||
{
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
'User-Token': token,
|
'User-Token': token,
|
||||||
},
|
},
|
||||||
body: data,
|
body: data,
|
||||||
},
|
});
|
||||||
);
|
|
||||||
return handle_response(response, false);
|
return handle_response(response, false);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -166,7 +148,7 @@ export const API = {
|
|||||||
window.config.no_c_post ? '&no_cw' : ''
|
window.config.no_c_post ? '&no_cw' : ''
|
||||||
}&order_mode=${submode}`,
|
}&order_mode=${submode}`,
|
||||||
{
|
{
|
||||||
headers: {'User-Token': token},
|
headers: { 'User-Token': token },
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return handle_response(response);
|
return handle_response(response);
|
||||||
@@ -174,58 +156,49 @@ export const API = {
|
|||||||
|
|
||||||
get_search: async (page, keyword, token, submode) => {
|
get_search: async (page, keyword, token, submode) => {
|
||||||
let response = await fetch(
|
let response = await fetch(
|
||||||
`${API_BASE}/search?search_mode=${submode}&page=${page}&keywords=${
|
`${API_BASE}/search?search_mode=${submode}&page=${page}&keywords=${encodeURIComponent(
|
||||||
encodeURIComponent(keyword)
|
keyword,
|
||||||
}&pagesize=${SEARCH_PAGESIZE}`,
|
)}&pagesize=${SEARCH_PAGESIZE}`,
|
||||||
{
|
{
|
||||||
headers: {'User-Token': token},
|
headers: { 'User-Token': token },
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
return handle_response(response);
|
return handle_response(response);
|
||||||
},
|
},
|
||||||
|
|
||||||
get_single: async (pid, token) => {
|
get_single: async (pid, token) => {
|
||||||
let response = await fetch(
|
let response = await fetch(API_BASE + '/getone?pid=' + pid, {
|
||||||
API_BASE + '/getone?pid=' + pid,
|
headers: { 'User-Token': token },
|
||||||
{
|
});
|
||||||
headers: {'User-Token': token},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return handle_response(response);
|
return handle_response(response);
|
||||||
},
|
},
|
||||||
|
|
||||||
get_attention: async (token) => {
|
get_attention: async (token) => {
|
||||||
let response = await fetch(
|
let response = await fetch(API_BASE + '/getattention', {
|
||||||
API_BASE + '/getattention',
|
headers: { 'User-Token': token },
|
||||||
{
|
});
|
||||||
headers: {'User-Token': token},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return handle_response(response);
|
return handle_response(response);
|
||||||
},
|
},
|
||||||
|
|
||||||
add_vote: async (vote, pid, token) => {
|
add_vote: async (vote, pid, token) => {
|
||||||
let data = new URLSearchParams([
|
let data = new URLSearchParams([
|
||||||
['vote', vote],
|
['vote', vote],
|
||||||
['pid', pid]
|
['pid', pid],
|
||||||
]);
|
]);
|
||||||
let response = await fetch(
|
let response = await fetch(API_BASE + '/vote', {
|
||||||
API_BASE + '/vote',
|
|
||||||
{
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
'User-Token': token,
|
'User-Token': token,
|
||||||
},
|
},
|
||||||
body: data,
|
body: data,
|
||||||
},
|
});
|
||||||
);
|
|
||||||
return handle_response(response, true);
|
return handle_response(response, true);
|
||||||
},
|
},
|
||||||
|
|
||||||
get_multi: async (pids, token) => {
|
get_multi: async (pids, token) => {
|
||||||
let response = await fetch(
|
let response = await fetch(
|
||||||
API_BASE + '/getmulti?' + pids.map(pid => `pids=${pid}`).join('&'),
|
API_BASE + '/getmulti?' + pids.map((pid) => `pids=${pid}`).join('&'),
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
'User-Token': token,
|
'User-Token': token,
|
||||||
@@ -238,18 +211,14 @@ export const API = {
|
|||||||
set_title: async (title, token) => {
|
set_title: async (title, token) => {
|
||||||
console.log('title: ', title);
|
console.log('title: ', title);
|
||||||
let data = new URLSearchParams([['title', title]]);
|
let data = new URLSearchParams([['title', title]]);
|
||||||
let response = await fetch(
|
let response = await fetch(API_BASE + '/title', {
|
||||||
API_BASE + '/title',
|
|
||||||
{
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
'User-Token': token,
|
'User-Token': token,
|
||||||
},
|
},
|
||||||
body: data,
|
body: data,
|
||||||
},
|
});
|
||||||
);
|
|
||||||
return handle_response(response, true);
|
return handle_response(response, true);
|
||||||
},
|
},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'icomoon';
|
font-family: 'icomoon';
|
||||||
src:
|
src: url('icomoon.ttf?8qh3rt') format('truetype'),
|
||||||
url('icomoon.ttf?8qh3rt') format('truetype'),
|
|
||||||
url('icomoon.woff?8qh3rt') format('woff'),
|
url('icomoon.woff?8qh3rt') format('woff'),
|
||||||
url('icomoon.svg?8qh3rt#icomoon') format('svg');
|
url('icomoon.svg?8qh3rt#icomoon') format('svg');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
@@ -19,7 +18,7 @@
|
|||||||
font-variant: normal;
|
font-variant: normal;
|
||||||
text-transform: none;
|
text-transform: none;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
vertical-align: -.0625em;
|
vertical-align: -0.0625em;
|
||||||
|
|
||||||
/* Better Font Rendering =========== */
|
/* Better Font Rendering =========== */
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
@@ -27,84 +26,84 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.icon-send:before {
|
.icon-send:before {
|
||||||
content: "\e900";
|
content: '\e900';
|
||||||
}
|
}
|
||||||
.icon-textfile:before {
|
.icon-textfile:before {
|
||||||
content: "\e926";
|
content: '\e926';
|
||||||
}
|
}
|
||||||
.icon-history:before {
|
.icon-history:before {
|
||||||
content: "\e94d";
|
content: '\e94d';
|
||||||
}
|
}
|
||||||
.icon-reply:before {
|
.icon-reply:before {
|
||||||
content: "\e96b";
|
content: '\e96b';
|
||||||
}
|
}
|
||||||
.icon-quote:before {
|
.icon-quote:before {
|
||||||
content: "\e977";
|
content: '\e977';
|
||||||
}
|
}
|
||||||
.icon-loading:before {
|
.icon-loading:before {
|
||||||
content: "\e979";
|
content: '\e979';
|
||||||
}
|
}
|
||||||
.icon-login:before {
|
.icon-login:before {
|
||||||
content: "\e98d";
|
content: '\e98d';
|
||||||
}
|
}
|
||||||
.icon-settings:before {
|
.icon-settings:before {
|
||||||
content: "\e994";
|
content: '\e994';
|
||||||
}
|
}
|
||||||
.icon-stats:before {
|
.icon-stats:before {
|
||||||
content: "\e99b";
|
content: '\e99b';
|
||||||
}
|
}
|
||||||
.icon-locate:before {
|
.icon-locate:before {
|
||||||
content: "\e9b3";
|
content: '\e9b3';
|
||||||
}
|
}
|
||||||
.icon-upload:before {
|
.icon-upload:before {
|
||||||
content: "\e9c3";
|
content: '\e9c3';
|
||||||
}
|
}
|
||||||
.icon-flag:before {
|
.icon-flag:before {
|
||||||
content: "\e9cc";
|
content: '\e9cc';
|
||||||
}
|
}
|
||||||
.icon-attention:before {
|
.icon-attention:before {
|
||||||
content: "\e9d3";
|
content: '\e9d3';
|
||||||
}
|
}
|
||||||
.icon-star:before {
|
.icon-star:before {
|
||||||
content: "\e9d7";
|
content: '\e9d7';
|
||||||
}
|
}
|
||||||
.icon-star-ok:before {
|
.icon-star-ok:before {
|
||||||
content: "\e9d9";
|
content: '\e9d9';
|
||||||
}
|
}
|
||||||
.icon-plus:before {
|
.icon-plus:before {
|
||||||
content: "\ea0a";
|
content: '\ea0a';
|
||||||
}
|
}
|
||||||
.icon-about:before {
|
.icon-about:before {
|
||||||
content: "\ea0c";
|
content: '\ea0c';
|
||||||
}
|
}
|
||||||
.icon-close:before {
|
.icon-close:before {
|
||||||
content: "\ea0d";
|
content: '\ea0d';
|
||||||
}
|
}
|
||||||
.icon-logout:before {
|
.icon-logout:before {
|
||||||
content: "\ea14";
|
content: '\ea14';
|
||||||
}
|
}
|
||||||
.icon-refresh:before {
|
.icon-refresh:before {
|
||||||
content: "\ea2e";
|
content: '\ea2e';
|
||||||
}
|
}
|
||||||
.icon-forward:before {
|
.icon-forward:before {
|
||||||
content: "\ea42";
|
content: '\ea42';
|
||||||
}
|
}
|
||||||
.icon-back:before {
|
.icon-back:before {
|
||||||
content: "\ea44";
|
content: '\ea44';
|
||||||
}
|
}
|
||||||
.icon-order-rev:before {
|
.icon-order-rev:before {
|
||||||
content: "\ea46";
|
content: '\ea46';
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
}
|
}
|
||||||
.icon-github:before {
|
.icon-github:before {
|
||||||
content: "\eab0";
|
content: '\eab0';
|
||||||
}
|
}
|
||||||
.icon-new-tab:before {
|
.icon-new-tab:before {
|
||||||
content: "\ea7e";
|
content: '\ea7e';
|
||||||
}
|
}
|
||||||
.icon-eye:before {
|
.icon-eye:before {
|
||||||
content: "\e9ce";
|
content: '\e9ce';
|
||||||
}
|
}
|
||||||
.icon-eye-blocked:before {
|
.icon-eye-blocked:before {
|
||||||
content: "\e9d1";
|
content: '\e9d1';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,10 @@ html {
|
|||||||
:root {
|
:root {
|
||||||
--var-link-color: #00c;
|
--var-link-color: #00c;
|
||||||
}
|
}
|
||||||
.root-dark-mode .left-container, .root-dark-mode .sidebar, .root-dark-mode .sidebar-title, .root-dark-mode .balance-popover {
|
.root-dark-mode .left-container,
|
||||||
|
.root-dark-mode .sidebar,
|
||||||
|
.root-dark-mode .sidebar-title,
|
||||||
|
.root-dark-mode .balance-popover {
|
||||||
--var-link-color: #9bf;
|
--var-link-color: #9bf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +34,8 @@ a:not(.no-underline):hover {
|
|||||||
margin-bottom: -1px;
|
margin-bottom: -1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
input, textarea {
|
input,
|
||||||
|
textarea {
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
border: 1px solid black;
|
border: 1px solid black;
|
||||||
outline: none;
|
outline: none;
|
||||||
@@ -46,42 +50,49 @@ audio {
|
|||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
button, .button {
|
button,
|
||||||
|
.button {
|
||||||
color: black;
|
color: black;
|
||||||
background-color: rgba(235,235,235,.5);
|
background-color: rgba(235, 235, 235, 0.5);
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border: 1px solid black;
|
border: 1px solid black;
|
||||||
line-height: 2em;
|
line-height: 2em;
|
||||||
margin: 0 .5rem;
|
margin: 0 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.root-dark-mode button, .root-dark-mode .button {
|
.root-dark-mode button,
|
||||||
background-color: hsl(0,0%,30%);
|
.root-dark-mode .button {
|
||||||
|
background-color: hsl(0, 0%, 30%);
|
||||||
color: var(--foreground-dark);
|
color: var(--foreground-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
button:hover, .button:hover {
|
button:hover,
|
||||||
background-color: rgba(255,255,255,.7);
|
.button:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.7);
|
||||||
}
|
}
|
||||||
|
|
||||||
.root-dark-mode button:hover, .root-dark-mode .button:hover {
|
.root-dark-mode button:hover,
|
||||||
background-color: hsl(0,0%,40%);
|
.root-dark-mode .button:hover {
|
||||||
|
background-color: hsl(0, 0%, 40%);
|
||||||
}
|
}
|
||||||
|
|
||||||
button:disabled, .button:disabled {
|
button:disabled,
|
||||||
background-color: rgba(128,128,128,.5);
|
.button:disabled {
|
||||||
|
background-color: rgba(128, 128, 128, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
.root-dark-mode button:disabled, .root-dark-mode .button:disabled {
|
.root-dark-mode button:disabled,
|
||||||
background-color: hsl(0,0%,20%);
|
.root-dark-mode .button:disabled {
|
||||||
color: hsl(0,0%,60%);
|
background-color: hsl(0, 0%, 20%);
|
||||||
|
color: hsl(0, 0%, 60%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.root-dark-mode input:not([type=file]), .root-dark-mode textarea {
|
.root-dark-mode input:not([type='file']),
|
||||||
background-color: hsl(0,0%,30%);
|
.root-dark-mode textarea {
|
||||||
|
background-color: hsl(0, 0%, 30%);
|
||||||
color: var(--foreground-dark);
|
color: var(--foreground-dark);
|
||||||
}
|
}
|
||||||
.root-dark-mode input:not([type=file])::placeholder {
|
.root-dark-mode input:not([type='file'])::placeholder {
|
||||||
color: var(--foreground-dark);
|
color: var(--foreground-dark);
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import './index.css';
|
import './index.css';
|
||||||
import './fonts_7/icomoon.css'
|
import './fonts_7/icomoon.css';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
//import {elevate} from './infrastructure/elevator';
|
//import {elevate} from './infrastructure/elevator';
|
||||||
import registerServiceWorker from './registerServiceWorker';
|
import registerServiceWorker from './registerServiceWorker';
|
||||||
|
|||||||
@@ -1,75 +1,72 @@
|
|||||||
export function get_json(res) {
|
export function get_json(res) {
|
||||||
if(!res.ok) {
|
if (!res.ok) {
|
||||||
return (
|
return res.text().then((t) => {
|
||||||
res.text().then((t) => {
|
|
||||||
console.log('error:', res);
|
console.log('error:', res);
|
||||||
t = t.length < 100 ? t : '';
|
t = t.length < 100 ? t : '';
|
||||||
throw Error(`${res.status} ${res.statusText} ${t}`);
|
throw Error(`${res.status} ${res.statusText} ${t}`);
|
||||||
})
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return (
|
return res.text().then((t) => {
|
||||||
res
|
|
||||||
.text()
|
|
||||||
.then((t)=>{
|
|
||||||
try {
|
try {
|
||||||
return JSON.parse(t);
|
return JSON.parse(t);
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
console.error('json parse error');
|
console.error('json parse error');
|
||||||
console.trace(e);
|
console.trace(e);
|
||||||
console.log(t);
|
console.log(t);
|
||||||
throw new SyntaxError('JSON Parse Error '+t.substr(0,50));
|
throw new SyntaxError('JSON Parse Error ' + t.substr(0, 50));
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function listen_darkmode(override) { // override: true/false/undefined
|
export function listen_darkmode(override) {
|
||||||
|
// override: true/false/undefined
|
||||||
function update_color_scheme() {
|
function update_color_scheme() {
|
||||||
if(override===undefined ? window.matchMedia('(prefers-color-scheme: dark)').matches : override)
|
if (
|
||||||
|
override === undefined
|
||||||
|
? window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||||
|
: override
|
||||||
|
)
|
||||||
document.body.classList.add('root-dark-mode');
|
document.body.classList.add('root-dark-mode');
|
||||||
else
|
else document.body.classList.remove('root-dark-mode');
|
||||||
document.body.classList.remove('root-dark-mode');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
update_color_scheme();
|
update_color_scheme();
|
||||||
window.matchMedia('(prefers-color-scheme: dark)').addListener(()=>{
|
window.matchMedia('(prefers-color-scheme: dark)').addListener(() => {
|
||||||
update_color_scheme();
|
update_color_scheme();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const NAMES = [
|
const NAMES = [
|
||||||
'Alice',
|
'Alice',
|
||||||
'Bob',
|
'Bob',
|
||||||
'Carol',
|
'Carol',
|
||||||
'Dave',
|
'Dave',
|
||||||
'Eve',
|
'Eve',
|
||||||
'Francis',
|
'Francis',
|
||||||
'Grace',
|
'Grace',
|
||||||
'Hans',
|
'Hans',
|
||||||
'Isabella',
|
'Isabella',
|
||||||
'Jason',
|
'Jason',
|
||||||
'Kate',
|
'Kate',
|
||||||
'Louis',
|
'Louis',
|
||||||
'Margaret',
|
'Margaret',
|
||||||
'Nathan',
|
'Nathan',
|
||||||
'Olivia',
|
'Olivia',
|
||||||
'Paul',
|
'Paul',
|
||||||
'Queen',
|
'Queen',
|
||||||
'Richard',
|
'Richard',
|
||||||
'Susan',
|
'Susan',
|
||||||
'Thomas',
|
'Thomas',
|
||||||
'Uma',
|
'Uma',
|
||||||
'Vivian',
|
'Vivian',
|
||||||
'Winnie',
|
'Winnie',
|
||||||
'Xander',
|
'Xander',
|
||||||
'Yasmine',
|
'Yasmine',
|
||||||
'Zach'
|
'Zach',
|
||||||
]
|
];
|
||||||
|
|
||||||
export function gen_name(name_id) {
|
export function gen_name(name_id) {
|
||||||
if (name_id == 0)
|
if (name_id == 0) return '洞主';
|
||||||
return '洞主';
|
|
||||||
|
|
||||||
let r = name_id;
|
let r = name_id;
|
||||||
let name = '';
|
let name = '';
|
||||||
@@ -81,4 +78,3 @@ export function gen_name(name_id) {
|
|||||||
|
|
||||||
return name.substr(1);
|
return name.substr(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
:root {
|
:root {
|
||||||
--foreground-dark: hsl(0,0%,93%);
|
--foreground-dark: hsl(0, 0%, 93%);
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@@ -9,7 +9,9 @@ body {
|
|||||||
text-size-adjust: 100%;
|
text-size-adjust: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
body, textarea, pre {
|
body,
|
||||||
|
textarea,
|
||||||
|
pre {
|
||||||
font-family: 'Segoe UI', '微软雅黑', 'Microsoft YaHei', sans-serif;
|
font-family: 'Segoe UI', '微软雅黑', 'Microsoft YaHei', sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,7 +21,8 @@ body, textarea, pre {
|
|||||||
-webkit-overflow-scrolling: touch;
|
-webkit-overflow-scrolling: touch;
|
||||||
}
|
}
|
||||||
|
|
||||||
p, pre {
|
p,
|
||||||
|
pre {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
.centered-line::before,
|
.centered-line::before,
|
||||||
.centered-line::after {
|
.centered-line::after {
|
||||||
background-color: #000;
|
background-color: #000;
|
||||||
content: "";
|
content: '';
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
height: 1px;
|
height: 1px;
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -17,7 +17,8 @@
|
|||||||
.root-dark-mode .centered-line {
|
.root-dark-mode .centered-line {
|
||||||
color: var(--foreground-dark);
|
color: var(--foreground-dark);
|
||||||
}
|
}
|
||||||
.root-dark-mode .centered-line::before, .root-dark-mode .centered-line::after {
|
.root-dark-mode .centered-line::before,
|
||||||
|
.root-dark-mode .centered-line::after {
|
||||||
background-color: var(--foreground-dark);
|
background-color: var(--foreground-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +45,8 @@
|
|||||||
.root-dark-mode .title-line {
|
.root-dark-mode .title-line {
|
||||||
color: var(--foreground-dark);
|
color: var(--foreground-dark);
|
||||||
}
|
}
|
||||||
.root-dark-mode .title-line::before, .root-dark-mode .title-line::after {
|
.root-dark-mode .title-line::before,
|
||||||
|
.root-dark-mode .title-line::after {
|
||||||
background-color: var(--foreground-dark);
|
background-color: var(--foreground-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,16 +54,16 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
height: 2em;
|
height: 2em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin: 0 .1em;
|
margin: 0 0.1em;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
.app-switcher-desc {
|
.app-switcher-desc {
|
||||||
margin: 0 .5em;
|
margin: 0 0.5em;
|
||||||
flex: 1 1 0;
|
flex: 1 1 0;
|
||||||
opacity: .5;
|
opacity: 0.5;
|
||||||
height: 2em;
|
height: 2em;
|
||||||
line-height: 2rem;
|
line-height: 2rem;
|
||||||
font-size: .8em;
|
font-size: 0.8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.root-dark-mode .app-switcher-desc {
|
.root-dark-mode .app-switcher-desc {
|
||||||
@@ -88,7 +90,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-switcher a:hover { /* reset underline from /hole style */
|
.app-switcher a:hover {
|
||||||
|
/* reset underline from /hole style */
|
||||||
border-bottom: unset;
|
border-bottom: unset;
|
||||||
margin-bottom: unset;
|
margin-bottom: unset;
|
||||||
}
|
}
|
||||||
@@ -108,10 +111,11 @@
|
|||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
height: 1.6em;
|
height: 1.6em;
|
||||||
line-height: 1.6em;
|
line-height: 1.6em;
|
||||||
margin: .2em .1em;
|
margin: 0.2em 0.1em;
|
||||||
padding: 0 .45em;
|
padding: 0 0.45em;
|
||||||
}
|
}
|
||||||
a.app-switcher-item, .app-switcher-item a {
|
a.app-switcher-item,
|
||||||
|
.app-switcher-item a {
|
||||||
transition: unset; /* override ant design */
|
transition: unset; /* override ant design */
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
@@ -119,11 +123,11 @@ a.app-switcher-item, .app-switcher-item a {
|
|||||||
width: 1.2rem;
|
width: 1.2rem;
|
||||||
height: 1.2rem;
|
height: 1.2rem;
|
||||||
position: relative;
|
position: relative;
|
||||||
top: .2rem;
|
top: 0.2rem;
|
||||||
vertical-align: unset; /* override ant design */
|
vertical-align: unset; /* override ant design */
|
||||||
}
|
}
|
||||||
.app-switcher-item span:not(:empty) {
|
.app-switcher-item span:not(:empty) {
|
||||||
margin-left: .2rem;
|
margin-left: 0.2rem;
|
||||||
}
|
}
|
||||||
.app-switcher-logo-hover {
|
.app-switcher-logo-hover {
|
||||||
margin-left: -1.2rem;
|
margin-left: -1.2rem;
|
||||||
@@ -137,26 +141,31 @@ a.app-switcher-item, .app-switcher-item a {
|
|||||||
color: white !important;
|
color: white !important;
|
||||||
}
|
}
|
||||||
.app-switcher-item-current {
|
.app-switcher-item-current {
|
||||||
background-color: rgba(0,0,0,.4);
|
background-color: rgba(0, 0, 0, 0.4);
|
||||||
text-shadow: 0 0 5px rgba(0,0,0,.5);
|
text-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
|
||||||
color: white !important;
|
color: white !important;
|
||||||
}
|
}
|
||||||
.app-switcher-item-current a {
|
.app-switcher-item-current a {
|
||||||
color: white !important;
|
color: white !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.root-dark-mode .app-switcher-item, .root-dark-mode .app-switcher-dropdown-title a {
|
.root-dark-mode .app-switcher-item,
|
||||||
|
.root-dark-mode .app-switcher-dropdown-title a {
|
||||||
color: var(--foreground-dark);
|
color: var(--foreground-dark);
|
||||||
}
|
}
|
||||||
.root-dark-mode .app-switcher-item:hover, .root-dark-mode .app-switcher-item-current, .root-dark-mode .app-switcher-dropdown-title:hover a {
|
.root-dark-mode .app-switcher-item:hover,
|
||||||
|
.root-dark-mode .app-switcher-item-current,
|
||||||
|
.root-dark-mode .app-switcher-dropdown-title:hover a {
|
||||||
background-color: #555;
|
background-color: #555;
|
||||||
color: var(--foreground-dark);
|
color: var(--foreground-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-switcher-item:hover .app-switcher-logo-normal, .app-switcher-item-current .app-switcher-logo-normal {
|
.app-switcher-item:hover .app-switcher-logo-normal,
|
||||||
|
.app-switcher-item-current .app-switcher-logo-normal {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
.app-switcher-item:not(.app-switcher-item-current):not(:hover) .app-switcher-logo-hover {
|
.app-switcher-item:not(.app-switcher-item-current):not(:hover)
|
||||||
|
.app-switcher-logo-hover {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,16 +187,16 @@ a.app-switcher-item, .app-switcher-item a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.app-switcher-dropdown-item {
|
.app-switcher-dropdown-item {
|
||||||
background-color: hsla(0,0%,35%,.9);
|
background-color: hsla(0, 0%, 35%, 0.9);
|
||||||
padding: .125em .25em;
|
padding: 0.125em 0.25em;
|
||||||
margin-left: -.75em;
|
margin-left: -0.75em;
|
||||||
margin-right: -.75em;
|
margin-right: -0.75em;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.app-switcher-dropdown-item:hover {
|
.app-switcher-dropdown-item:hover {
|
||||||
background-color: rgba(0,0,0,.9);
|
background-color: rgba(0, 0, 0, 0.9);
|
||||||
}
|
}
|
||||||
.app-switcher-dropdown-item:nth-child(2) {
|
.app-switcher-dropdown-item:nth-child(2) {
|
||||||
border-top-left-radius: 3px;
|
border-top-left-radius: 3px;
|
||||||
@@ -199,9 +208,9 @@ a.app-switcher-item, .app-switcher-item a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.app-switcher-dropdown-title {
|
.app-switcher-dropdown-title {
|
||||||
padding-bottom: .2em;
|
padding-bottom: 0.2em;
|
||||||
padding-left: .5em;
|
padding-left: 0.5em;
|
||||||
padding-right: .25em;
|
padding-right: 0.25em;
|
||||||
}
|
}
|
||||||
.app-switcher-dropdown-title a {
|
.app-switcher-dropdown-title a {
|
||||||
cursor: unset;
|
cursor: unset;
|
||||||
@@ -227,51 +236,52 @@ a.app-switcher-item, .app-switcher-item a {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
.thuhole-login-popup-info p {
|
.thuhole-login-popup-info p {
|
||||||
margin: .25em 1em;
|
margin: 0.25em 1em;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
.thuhole-login-popup-info ul {
|
.thuhole-login-popup-info ul {
|
||||||
margin: .75em 1em;
|
margin: 0.75em 1em;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-size: 75%;
|
font-size: 75%;
|
||||||
}
|
}
|
||||||
/* override ant design */
|
/* override ant design */
|
||||||
.thuhole-login-popup input, .thuhole-login-popup button {
|
.thuhole-login-popup input,
|
||||||
font-size: .85em;
|
.thuhole-login-popup button {
|
||||||
|
font-size: 0.85em;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
.thuhole-login-popup input:not([type="checkbox"]) {
|
.thuhole-login-popup input:not([type='checkbox']) {
|
||||||
width: 8rem;
|
width: 8rem;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
border: 1px solid black;
|
border: 1px solid black;
|
||||||
outline: none;
|
outline: none;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0 .5em;
|
padding: 0 0.5em;
|
||||||
line-height: 2em;
|
line-height: 2em;
|
||||||
}
|
}
|
||||||
.thuhole-login-popup button {
|
.thuhole-login-popup button {
|
||||||
min-width: 6rem;
|
min-width: 6rem;
|
||||||
color: black;
|
color: black;
|
||||||
background-color: rgba(235,235,235,.5);
|
background-color: rgba(235, 235, 235, 0.5);
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border: 1px solid black;
|
border: 1px solid black;
|
||||||
line-height: 2em;
|
line-height: 2em;
|
||||||
margin: 0 .5rem;
|
margin: 0 0.5rem;
|
||||||
}
|
}
|
||||||
.thuhole-login-popup button:hover {
|
.thuhole-login-popup button:hover {
|
||||||
background-color: rgba(255,255,255,.7);
|
background-color: rgba(255, 255, 255, 0.7);
|
||||||
}
|
}
|
||||||
.thuhole-login-popup button:disabled {
|
.thuhole-login-popup button:disabled {
|
||||||
background-color: rgba(128,128,128,.5);
|
background-color: rgba(128, 128, 128, 0.5);
|
||||||
}
|
}
|
||||||
.thuhole-login-type {
|
.thuhole-login-type {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 6rem;
|
width: 6rem;
|
||||||
margin: 0 .5rem;
|
margin: 0 0.5rem;
|
||||||
}
|
}
|
||||||
.thuhole-login-popup-shadow {
|
.thuhole-login-popup-shadow {
|
||||||
opacity: .5;
|
opacity: 0.5;
|
||||||
background-color: black;
|
background-color: black;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 0;
|
left: 0;
|
||||||
@@ -282,9 +292,9 @@ a.app-switcher-item, .app-switcher-item a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.thuhole-login-popup label.perm-item {
|
.thuhole-login-popup label.perm-item {
|
||||||
font-size: .8em;
|
font-size: 0.8em;
|
||||||
vertical-align: .1rem;
|
vertical-align: 0.1rem;
|
||||||
margin-left: .5rem;
|
margin-left: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.aux-margin {
|
.aux-margin {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, {Component, PureComponent} from 'react';
|
import React, { Component, PureComponent } from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
|
|
||||||
import TimeAgo from 'react-timeago';
|
import TimeAgo from 'react-timeago';
|
||||||
@@ -8,23 +8,29 @@ import buildFormatter from 'react-timeago/lib/formatters/buildFormatter';
|
|||||||
import './global.css';
|
import './global.css';
|
||||||
import './widgets.css';
|
import './widgets.css';
|
||||||
|
|
||||||
import {get_json, API_VERSION_PARAM} from './functions';
|
import { get_json, API_VERSION_PARAM } from './functions';
|
||||||
|
|
||||||
function pad2(x) {
|
function pad2(x) {
|
||||||
return x<10 ? '0'+x : ''+x;
|
return x < 10 ? '0' + x : '' + x;
|
||||||
}
|
}
|
||||||
export function format_time(time) {
|
export function format_time(time) {
|
||||||
return `${time.getMonth()+1}-${pad2(time.getDate())} ${time.getHours()}:${pad2(time.getMinutes())}:${pad2(time.getSeconds())}`;
|
return `${time.getMonth() + 1}-${pad2(
|
||||||
|
time.getDate(),
|
||||||
|
)} ${time.getHours()}:${pad2(time.getMinutes())}:${pad2(time.getSeconds())}`;
|
||||||
}
|
}
|
||||||
const chinese_format=buildFormatter(chineseStrings);
|
const chinese_format = buildFormatter(chineseStrings);
|
||||||
export function Time(props) {
|
export function Time(props) {
|
||||||
const time=new Date(props.stamp*1000);
|
const time = new Date(props.stamp * 1000);
|
||||||
return (
|
return (
|
||||||
<span className={"time-str"}>
|
<span className={'time-str'}>
|
||||||
<TimeAgo date={time} formatter={chinese_format} title={time.toLocaleString('zh-CN', {
|
<TimeAgo
|
||||||
|
date={time}
|
||||||
|
formatter={chinese_format}
|
||||||
|
title={time.toLocaleString('zh-CN', {
|
||||||
timeZone: 'Asia/Shanghai',
|
timeZone: 'Asia/Shanghai',
|
||||||
hour12: false,
|
hour12: false,
|
||||||
})} />
|
})}
|
||||||
|
/>
|
||||||
|
|
||||||
{!props.short ? format_time(time) : null}
|
{!props.short ? format_time(time) : null}
|
||||||
</span>
|
</span>
|
||||||
@@ -36,7 +42,7 @@ export function TitleLine(props) {
|
|||||||
<p className="centered-line title-line aux-margin">
|
<p className="centered-line title-line aux-margin">
|
||||||
<span className="black-outline">{props.text}</span>
|
<span className="black-outline">{props.text}</span>
|
||||||
</p>
|
</p>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GlobalTitle(props) {
|
export function GlobalTitle(props) {
|
||||||
@@ -52,13 +58,13 @@ export function GlobalTitle(props) {
|
|||||||
class LoginPopupSelf extends Component {
|
class LoginPopupSelf extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state={
|
this.state = {
|
||||||
loading_status: 'idle',
|
loading_status: 'idle',
|
||||||
}
|
|
||||||
|
|
||||||
this.input_token_ref=React.createRef();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.input_token_ref = React.createRef();
|
||||||
|
}
|
||||||
|
|
||||||
setThuhole(e, tar, ref) {
|
setThuhole(e, tar, ref) {
|
||||||
console.log(tar);
|
console.log(tar);
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -68,7 +74,6 @@ class LoginPopupSelf extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="thuhole-login-popup-shadow" />
|
<div className="thuhole-login-popup-shadow" />
|
||||||
@@ -84,9 +89,13 @@ class LoginPopupSelf extends Component {
|
|||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<input ref={this.input_token_ref} placeholder="T大树洞Token" />
|
<input ref={this.input_token_ref} placeholder="T大树洞Token" />
|
||||||
<br/>
|
<br />
|
||||||
<a href="/_login?p=thuhole" target="_blank"
|
<a
|
||||||
onClick={(e) =>{this.setThuhole(e, e.target, this.input_token_ref)}}
|
href="/_login?p=thuhole"
|
||||||
|
target="_blank"
|
||||||
|
onClick={(e) => {
|
||||||
|
this.setThuhole(e, e.target, this.input_token_ref);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<span className="icon icon-login" />
|
<span className="icon icon-login" />
|
||||||
T大树洞
|
T大树洞
|
||||||
@@ -94,40 +103,40 @@ class LoginPopupSelf extends Component {
|
|||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<small>前往Telegram群查询15分钟临时token</small>
|
<small>前往Telegram群查询15分钟临时token</small>
|
||||||
<br/>
|
<br />
|
||||||
<a href="//t.me/THUChatBot" target="_blank"
|
<a href="//t.me/THUChatBot" target="_blank">
|
||||||
>
|
|
||||||
<span className="icon icon-login" />
|
<span className="icon icon-login" />
|
||||||
清华大水群
|
清华大水群
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<button type="button" disabled
|
<button type="button" disabled>
|
||||||
>
|
|
||||||
<span className="icon icon-login" />
|
<span className="icon icon-login" />
|
||||||
未名bbs
|
未名bbs
|
||||||
</button>
|
</button>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<button type="button" disabled
|
<button type="button" disabled>
|
||||||
>
|
|
||||||
<span className="icon icon-login" />
|
<span className="icon icon-login" />
|
||||||
清华统一身份认证
|
清华统一身份认证
|
||||||
</button>
|
</button>
|
||||||
</p>
|
</p>
|
||||||
<hr />
|
<hr />
|
||||||
<p>
|
<p>
|
||||||
<button onClick={this.props.on_close}>
|
<button onClick={this.props.on_close}>取消</button>
|
||||||
取消
|
|
||||||
</button>
|
|
||||||
</p>
|
</p>
|
||||||
<hr/ >
|
<hr />
|
||||||
<div className="thuhole-login-popup-info">
|
<div className="thuhole-login-popup-info">
|
||||||
<p>提醒:
|
<p>提醒:</p>
|
||||||
</p>
|
|
||||||
<ul>
|
<ul>
|
||||||
<li> 无论采用哪种方式注册,你后台记录的用户名都是本质实名的(除临时token),因为闭社/T大树洞的管理员可以根据你的闭社id/树洞评论区代号查到邮箱。但是这不影响新T树洞的安全性。新T树洞的匿名性来自隔离用户名与发布的内容,而非试图隔离用户名与真实身份。</li>
|
<li>
|
||||||
<li> 由于T大树洞仍未提供授权接口,使用T大树洞方式登陆需要用你的token在特定洞发布一段随机内容以确定身份。这是否违反用户条例由T大树洞管理员决定,需自行承担相关风险。完成登陆后建议立即重置T大树洞token。 </li>
|
{' '}
|
||||||
|
无论采用哪种方式注册,你后台记录的用户名都是本质实名的(除临时token),因为闭社/T大树洞的管理员可以根据你的闭社id/树洞评论区代号查到邮箱。但是这不影响新T树洞的安全性。新T树洞的匿名性来自隔离用户名与发布的内容,而非试图隔离用户名与真实身份。
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{' '}
|
||||||
|
由于T大树洞仍未提供授权接口,使用T大树洞方式登陆需要用你的token在特定洞发布一段随机内容以确定身份。这是否违反用户条例由T大树洞管理员决定,需自行承担相关风险。完成登陆后建议立即重置T大树洞token。{' '}
|
||||||
|
</li>
|
||||||
<li> 目前一个人可能有两个帐号。</li>
|
<li> 目前一个人可能有两个帐号。</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -140,11 +149,11 @@ class LoginPopupSelf extends Component {
|
|||||||
export class LoginPopup extends Component {
|
export class LoginPopup extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state={
|
this.state = {
|
||||||
popup_show: false,
|
popup_show: false,
|
||||||
};
|
};
|
||||||
this.on_popup_bound=this.on_popup.bind(this);
|
this.on_popup_bound = this.on_popup.bind(this);
|
||||||
this.on_close_bound=this.on_close.bind(this);
|
this.on_close_bound = this.on_close.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
on_popup() {
|
on_popup() {
|
||||||
@@ -162,9 +171,12 @@ export class LoginPopup extends Component {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{this.props.children(this.on_popup_bound)}
|
{this.props.children(this.on_popup_bound)}
|
||||||
{this.state.popup_show &&
|
{this.state.popup_show && (
|
||||||
<LoginPopupSelf token_callback={this.props.token_callback} on_close={this.on_close_bound} />
|
<LoginPopupSelf
|
||||||
}
|
token_callback={this.props.token_callback}
|
||||||
|
on_close={this.on_close_bound}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user