forked from newthuhole/hole_thu_frontend
update topbar style
This commit is contained in:
@@ -2,7 +2,6 @@ import React, {Component} from 'react';
|
|||||||
import {Flow} from './Flows';
|
import {Flow} from './Flows';
|
||||||
import {Title} from './Title';
|
import {Title} from './Title';
|
||||||
import {Sidebar} from './Sidebar';
|
import {Sidebar} from './Sidebar';
|
||||||
import {ControlBar} from './ControlBar';
|
|
||||||
|
|
||||||
class App extends Component {
|
class App extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@@ -33,9 +32,8 @@ class App extends Component {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="bg-img" />
|
<div className="bg-img" />
|
||||||
<Title callback={this.show_sidebar.bind(this)} />
|
<Title callback={this.show_sidebar.bind(this)} set_search_text={this.set_search_text.bind(this)} />
|
||||||
<div className="left-container">
|
<div className="left-container">
|
||||||
<ControlBar set_search_text={this.set_search_text.bind(this)} />
|
|
||||||
<Flow key={this.state.flow_render_key}
|
<Flow key={this.state.flow_render_key}
|
||||||
callback={this.show_sidebar.bind(this)} search_text={this.state.search_text}
|
callback={this.show_sidebar.bind(this)} search_text={this.state.search_text}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
.centered-line {
|
.centered-line {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: #fff;
|
|
||||||
margin-top: 1em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.centered-line::before,
|
.centered-line::before,
|
||||||
.centered-line::after {
|
.centered-line::after {
|
||||||
background-color: #fff;
|
background-color: #000;
|
||||||
content: "";
|
content: "";
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
height: 1px;
|
height: 1px;
|
||||||
@@ -26,6 +24,15 @@
|
|||||||
margin-right: -50%;
|
margin-right: -50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.title-line {
|
||||||
|
color: #fff;
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
.title-line::before,
|
||||||
|
.title-line::after {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
.bg-img {
|
.bg-img {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ export function Time(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CenteredLine(props) {
|
export function TitleLine(props) {
|
||||||
return (
|
return (
|
||||||
<p className="centered-line aux-margin">
|
<p className="centered-line title-line aux-margin">
|
||||||
<span>{props.text}</span>
|
<span>{props.text}</span>
|
||||||
</p>
|
</p>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
.control-bar {
|
|
||||||
display: flex;
|
|
||||||
line-height: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.control-bar .refresh-btn {
|
|
||||||
flex: 0 0 100px;
|
|
||||||
color: black;
|
|
||||||
background-color: rgba(255,255,255,.9);
|
|
||||||
border-radius: 5px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.control-bar input {
|
|
||||||
flex: auto;
|
|
||||||
color: black;
|
|
||||||
background-color: rgba(255,255,255,.9);
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
import React, {Component} from 'react';
|
|
||||||
import './ControlBar.css';
|
|
||||||
|
|
||||||
export class ControlBar extends Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state={
|
|
||||||
search_text: '',
|
|
||||||
};
|
|
||||||
this.set_search_text=props.set_search_text;
|
|
||||||
}
|
|
||||||
|
|
||||||
on_change(event) {
|
|
||||||
this.setState({
|
|
||||||
search_text: event.target.value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
on_keypress(event) {
|
|
||||||
if(event.key==='Enter')
|
|
||||||
this.set_search_text(this.state.search_text);
|
|
||||||
}
|
|
||||||
|
|
||||||
do_refresh() {
|
|
||||||
this.setState({
|
|
||||||
search_text: '',
|
|
||||||
});
|
|
||||||
this.set_search_text(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div className="control-bar aux-margin">
|
|
||||||
<a className="refresh-btn" onClick={this.do_refresh.bind(this)}>最新树洞</a>
|
|
||||||
|
|
||||||
<input value={this.state.search_text} placeholder="搜索"
|
|
||||||
onChange={this.on_change.bind(this)} onKeyPress={this.on_keypress.bind(this)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -16,20 +16,20 @@
|
|||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.left-container .aux-margin,
|
.aux-margin,
|
||||||
.left-container .flow-item {
|
.left-container .flow-item {
|
||||||
margin-left: 50px;
|
margin-left: 50px;
|
||||||
}
|
}
|
||||||
.left-container .aux-margin {
|
.aux-margin {
|
||||||
width: calc(100% - 2 * 50px);
|
width: calc(100% - 2 * 50px);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 1200px) {
|
@media screen and (max-width: 1200px) {
|
||||||
.left-container .aux-margin,
|
.aux-margin,
|
||||||
.left-container .flow-item {
|
.left-container .flow-item {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
.left-container .aux-margin {
|
.aux-margin {
|
||||||
width: calc(100% - 2 * 10px);
|
width: calc(100% - 2 * 10px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
43
src/Flows.js
43
src/Flows.js
@@ -1,5 +1,5 @@
|
|||||||
import React, {Component} from 'react';
|
import React, {Component} from 'react';
|
||||||
import {Time, CenteredLine} from './Common.js';
|
import {Time, TitleLine} from './Common.js';
|
||||||
import './Flows.css';
|
import './Flows.css';
|
||||||
import LazyLoad from 'react-lazyload';
|
import LazyLoad from 'react-lazyload';
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ class FlowItemRow extends Component {
|
|||||||
function FlowChunk(props) {
|
function FlowChunk(props) {
|
||||||
return (
|
return (
|
||||||
<div className="flow-chunk">
|
<div className="flow-chunk">
|
||||||
<CenteredLine text={props.title} />
|
<TitleLine text={props.title} />
|
||||||
{props.list.map((info)=>(
|
{props.list.map((info)=>(
|
||||||
<LazyLoad key={info.pid} offset={500} height="15em">
|
<LazyLoad key={info.pid} offset={500} height="15em">
|
||||||
<FlowItemRow info={info} callback={props.callback} />
|
<FlowItemRow info={info} callback={props.callback} />
|
||||||
@@ -111,7 +111,11 @@ export class Flow extends Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state={
|
this.state={
|
||||||
mode: props.search_text===null ? 'list' : 'search',
|
mode: (
|
||||||
|
props.search_text===null ? 'list' :
|
||||||
|
props.search_text.charAt(0)==='#' ? 'single' :
|
||||||
|
'search'
|
||||||
|
),
|
||||||
search_param: props.search_text,
|
search_param: props.search_text,
|
||||||
loaded_pages: 0,
|
loaded_pages: 0,
|
||||||
chunks: [],
|
chunks: [],
|
||||||
@@ -154,15 +158,42 @@ export class Flow extends Component {
|
|||||||
if(json.code!==0)
|
if(json.code!==0)
|
||||||
throw new Error(json.code);
|
throw new Error(json.code);
|
||||||
const finished=json.data.length<SEARCH_PAGESIZE;
|
const finished=json.data.length<SEARCH_PAGESIZE;
|
||||||
this.setState((prev,props)=>({
|
this.setState({
|
||||||
chunks: [{
|
chunks: [{
|
||||||
title: 'Result for "'+this.state.search_param+'"',
|
title: 'Result for "'+this.state.search_param+'"',
|
||||||
data: json.data,
|
data: json.data,
|
||||||
mode: finished ? 'search_finished' : 'search',
|
mode: finished ? 'search_finished' : 'search',
|
||||||
}],
|
}],
|
||||||
loading: false,
|
loading: false,
|
||||||
}));
|
});
|
||||||
})
|
})
|
||||||
|
.catch((err)=>{
|
||||||
|
console.trace(err);
|
||||||
|
alert('load failed');
|
||||||
|
});
|
||||||
|
} else if(this.state.mode==='single') {
|
||||||
|
const pid=parseInt(this.state.search_param.substr(1),10);
|
||||||
|
fetch(
|
||||||
|
'http://www.pkuhelper.com:10301/services/pkuhole/api.php?action=getone'+
|
||||||
|
'&pid='+pid
|
||||||
|
)
|
||||||
|
.then((res)=>res.json())
|
||||||
|
.then((json)=>{
|
||||||
|
if(json.code!==0)
|
||||||
|
throw new Error(json.code);
|
||||||
|
this.setState({
|
||||||
|
chunks: [{
|
||||||
|
title: 'PID = '+pid,
|
||||||
|
data: [json.data],
|
||||||
|
mode: 'single_finished',
|
||||||
|
}],
|
||||||
|
loading: false,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err)=>{
|
||||||
|
console.trace(err);
|
||||||
|
alert('load failed');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
this.setState((prev,props)=>({
|
this.setState((prev,props)=>({
|
||||||
loaded_pages: prev.loaded_pages+1,
|
loaded_pages: prev.loaded_pages+1,
|
||||||
@@ -195,7 +226,7 @@ export class Flow extends Component {
|
|||||||
{this.state.chunks.map((chunk)=>(
|
{this.state.chunks.map((chunk)=>(
|
||||||
<FlowChunk title={chunk.title} list={chunk.data} key={chunk.title} callback={this.props.callback} />
|
<FlowChunk title={chunk.title} list={chunk.data} key={chunk.title} callback={this.props.callback} />
|
||||||
))}
|
))}
|
||||||
<CenteredLine text={this.state.loading ? 'Loading...' : '© xmcp'} />
|
<TitleLine text={this.state.loading ? 'Loading...' : '© xmcp'} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,37 @@
|
|||||||
.title {
|
.title-bar {
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: -6em;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 2em;
|
height: 9em;
|
||||||
line-height: 2em;
|
|
||||||
font-size: 1.5em;
|
|
||||||
background-color: rgba(255,255,255,.8);
|
background-color: rgba(255,255,255,.8);
|
||||||
padding: 0 50px;
|
|
||||||
box-shadow: 0 0 25px #999;
|
box-shadow: 0 0 25px #999;
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
}
|
}
|
||||||
.title-links {
|
|
||||||
float: right;
|
.title {
|
||||||
display: inline-block;
|
font-size: 2em;
|
||||||
font-size: .7em;
|
line-height: 3em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-bar {
|
||||||
|
display: flex;
|
||||||
|
margin-top: .5em;
|
||||||
|
line-height: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-bar .refresh-btn {
|
||||||
|
flex: 0 0 100px;
|
||||||
|
color: black;
|
||||||
|
background-color: rgba(255,255,255,.5);
|
||||||
|
border-radius: 5px;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
.control-bar input {
|
||||||
|
flex: auto;
|
||||||
|
color: black;
|
||||||
|
background-color: rgba(255,255,255,.5);
|
||||||
}
|
}
|
||||||
117
src/Title.js
117
src/Title.js
@@ -1,44 +1,93 @@
|
|||||||
import React, {Component} from 'react';
|
import React, {Component} from 'react';
|
||||||
import './Title.css';
|
import './Title.css';
|
||||||
|
|
||||||
export function Title(props) {
|
const HELP_TEXT=(
|
||||||
return (
|
<div className="box">
|
||||||
<div className="title">
|
<p>使用提示:</p>
|
||||||
<div className="title-links">
|
<ul>
|
||||||
<a onClick={()=>{props.callback(
|
<li>为保证使用体验,请使用 Chrome 浏览器 stable 分支最新版</li>
|
||||||
|
<li>在列表中点击帖子可以显示全部回复</li>
|
||||||
|
<li>搜索框输入 #472865 等可以查看指定 ID 的树洞</li>
|
||||||
|
</ul>
|
||||||
|
<p>使用本网站时,您需要了解并同意:</p>
|
||||||
|
<ul>
|
||||||
|
<li>所有数据来自 PKU Helper,本站不对其内容负责</li>
|
||||||
|
<li>不接受关于修改 UI 的建议</li>
|
||||||
|
<li>英梨梨是我的,你们都不要抢</li>
|
||||||
|
</ul>
|
||||||
|
<p>By @xmcp</p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
class ControlBar extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state={
|
||||||
|
search_text: '',
|
||||||
|
};
|
||||||
|
this.set_search_text=props.set_search_text;
|
||||||
|
}
|
||||||
|
|
||||||
|
on_change(event) {
|
||||||
|
this.setState({
|
||||||
|
search_text: event.target.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
on_keypress(event) {
|
||||||
|
if(event.key==='Enter')
|
||||||
|
this.set_search_text(this.state.search_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
do_refresh() {
|
||||||
|
window.scrollTo(0,0);
|
||||||
|
this.setState({
|
||||||
|
search_text: '',
|
||||||
|
});
|
||||||
|
this.set_search_text(null);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="control-bar">
|
||||||
|
<a className="refresh-btn" onClick={this.do_refresh.bind(this)}>最新树洞</a>
|
||||||
|
|
||||||
|
<input value={this.state.search_text} placeholder="搜索 或 #PID"
|
||||||
|
onChange={this.on_change.bind(this)} onKeyPress={this.on_keypress.bind(this)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<a onClick={()=>{this.props.callback(
|
||||||
'关于 P大树洞(非官方) 网页版',
|
'关于 P大树洞(非官方) 网页版',
|
||||||
<div class="box">
|
HELP_TEXT
|
||||||
<p>使用提示:</p>
|
|
||||||
<ul>
|
|
||||||
<li>为保证使用体验,请使用 Chrome 浏览器 stable 分支最新版</li>
|
|
||||||
<li>在列表中点击帖子可以显示全部回复</li>
|
|
||||||
</ul>
|
|
||||||
<p>使用本网站时,您需要了解并同意:</p>
|
|
||||||
<ul>
|
|
||||||
<li>所有数据来自 PKU Helper,本站不对其内容负责</li>
|
|
||||||
<li>不接受关于修改 UI 的建议</li>
|
|
||||||
<li>英梨梨是我的,你们都不要抢</li>
|
|
||||||
</ul>
|
|
||||||
<p>By @xmcp</p>
|
|
||||||
<br />
|
|
||||||
<p>
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
</p>
|
|
||||||
<br />
|
|
||||||
<p>
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
)}}>Help</a>
|
)}}>Help</a>
|
||||||
<a href="https://github.com/xmcp/ashole" target="_blank">GitHub</a>
|
<a href="https://github.com/xmcp/ashole" target="_blank">GitHub</a>
|
||||||
</div>
|
</div>
|
||||||
P大树洞(非官方)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Title(props) {
|
||||||
|
return (
|
||||||
|
<div className="title-bar">
|
||||||
|
<div className="aux-margin">
|
||||||
|
<p className="title centered-line">P大树洞</p>
|
||||||
|
<ControlBar callback={props.callback} set_search_text={props.set_search_text} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user