Changing space indents on UI. Changing td aligns to bootstrap text-right

This commit is contained in:
Dessalines 2018-10-11 15:20:17 -07:00
parent 43ed6e0ba4
commit a442341cd0
3 changed files with 187 additions and 187 deletions

View File

@ -1,5 +1,5 @@
[*.{js,jsx,ts,tsx,json}] [*.{js,jsx,ts,tsx,json}]
indent_style = tab indent_style = space
indent_size = 2 indent_size = 2
trim_trailing_whitespace = true trim_trailing_whitespace = true
insert_final_newline = true insert_final_newline = true

View File

@ -11,196 +11,196 @@ const container = document.getElementById('app');
class TorrentSearchComponent extends Component<any, State> { class TorrentSearchComponent extends Component<any, State> {
state: State = { state: State = {
results: { results: {
torrents: [] torrents: []
}, },
searchParams: { searchParams: {
q: "", q: "",
page: 1 page: 1
}, },
searching: false searching: false
}; };
constructor(props, context) { constructor(props, context) {
super(props, context); super(props, context);
} }
search(i: TorrentSearchComponent, event) { search(i: TorrentSearchComponent, event) {
event.preventDefault(); event.preventDefault();
if (!!i.state.searchParams.q) { if (!!i.state.searchParams.q) {
i.setState({ searching: true, results: { torrents: [] } }); i.setState({ searching: true, results: { torrents: [] } });
i.fetchData(i.state.searchParams) i.fetchData(i.state.searchParams)
.then(results => { .then(results => {
if (!!results) { if (!!results) {
i.setState({ i.setState({
results: results results: results
}); });
} }
}).catch(error => { }).catch(error => {
console.error('request failed', error); console.error('request failed', error);
}).then(() => i.setState({ searching: false })); }).then(() => i.setState({ searching: false }));
} else { } else {
i.setState({ results: { torrents: [] } }); i.setState({ results: { torrents: [] } });
} }
} }
fetchData(searchParams: SearchParams): Promise<Results> { fetchData(searchParams: SearchParams): Promise<Results> {
let q = encodeURI(searchParams.q); let q = encodeURI(searchParams.q);
return fetch(`${endpoint}/service/search?q=${q}&page=${searchParams.page}`) return fetch(`${endpoint}/service/search?q=${q}&page=${searchParams.page}`)
.then(data => data.text()) .then(data => data.text())
.then(csv => convertCsvToJson(csv)); .then(csv => convertCsvToJson(csv));
} }
render() { render() {
return ( return (
<div> <div>
{this.navbar()} {this.navbar()}
<div className={this.state.results.torrents[0]? "container-fluid" : "container"}> <div className={this.state.results.torrents[0] ? "container-fluid" : "container"}>
<div class="row mt-2"> <div class="row mt-2">
<div class="col-12"> <div class="col-12">
{ {
this.state.searching ? this.state.searching ?
this.spinner() this.spinner()
: :
this.state.results.torrents[0] ? this.table() : this.onboard() this.state.results.torrents[0] ? this.table() : this.onboard()
} }
</div> </div>
</div> </div>
</div> </div>
</div> </div>
); );
} }
table() { table() {
return ( return (
<div class="table-responsive-sm"> <div class="table-responsive-sm">
<table class="table table-hover"> <table class="table table-hover">
<thead> <thead>
<tr> <tr>
<th>Name</th> <th>Name</th>
<th align="right">Size</th> <th class="text-right">Size</th>
<th align="right">Seeds</th> <th class="text-right">Seeds</th>
<th align="right">Leeches</th> <th class="text-right">Leeches</th>
<th>Created</th> <th>Created</th>
<th>Scraped</th> <th>Scraped</th>
<th></th> <th></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{this.state.results.torrents.map(torrent => ( {this.state.results.torrents.map(torrent => (
<tr> <tr>
<td>{torrent.name}</td> <td>{torrent.name}</td>
<td align="right">{humanFileSize(torrent.size_bytes, true)}</td> <td class="text-right">{humanFileSize(torrent.size_bytes, true)}</td>
<td align="right">{torrent.seeders}</td> <td class="text-right">{torrent.seeders}</td>
<td align="right">{torrent.leechers}</td> <td class="text-right">{torrent.leechers}</td>
<td>{moment(torrent.created_unix * 1000).fromNow()}</td> <td>{moment(torrent.created_unix * 1000).fromNow()}</td>
<td>{moment(torrent.scraped_date * 1000).fromNow()}</td> <td>{moment(torrent.scraped_date * 1000).fromNow()}</td>
<td align="right"> <td class="text-right">
<a href={magnetLink(torrent.infohash)}> <a href={magnetLink(torrent.infohash)}>
<i class="fas fa-magnet"></i> <i class="fas fa-magnet"></i>
</a> </a>
</td> </td>
</tr> </tr>
))} ))}
</tbody> </tbody>
</table> </table>
{this.paginator()} {this.paginator()}
</div> </div>
); );
} }
navbar() { navbar() {
return ( return (
<nav class="navbar navbar-light bg-light"> <nav class="navbar navbar-light bg-light">
<a class="navbar-brand" href="#"> <a class="navbar-brand" href="#">
<i class="fas fa-fw fa-database mr-1"></i>Torrents.csv <i class="fas fa-fw fa-database mr-1"></i>Torrents.csv
</a> </a>
<div class="col-12 col-sm-6"> <div class="col-12 col-sm-6">
{this.searchForm()} {this.searchForm()}
</div> </div>
</nav> </nav>
); );
} }
// TODO // TODO
// https://www.codeply.com/go/xBVaM3q5X4/bootstrap-4-navbar-search-full-width // https://www.codeply.com/go/xBVaM3q5X4/bootstrap-4-navbar-search-full-width
searchForm() { searchForm() {
return ( return (
<form class="my-2 my-lg-0 d-inline w-100" onSubmit={linkEvent(this, this.search)}> <form class="my-2 my-lg-0 d-inline w-100" onSubmit={linkEvent(this, this.search)}>
<div class="input-group"> <div class="input-group">
<input value={this.state.searchParams.q} onInput={linkEvent(this, this.searchChange)} type="text" class="form-control border" placeholder="Search..." /> <input value={this.state.searchParams.q} onInput={linkEvent(this, this.searchChange)} type="text" class="form-control border" placeholder="Search..." />
<span class="input-group-append"></span> <span class="input-group-append"></span>
<button type="submit" class="btn btn-outline-secondary border border-left-0"> <button type="submit" class="btn btn-outline-secondary border border-left-0">
<i className={(this.state.searching) ? "fas fa-spinner fa-spin" : "fas fa-fw fa-search"}></i> <i className={(this.state.searching) ? "fas fa-spinner fa-spin" : "fas fa-fw fa-search"}></i>
</button> </button>
</div> </div>
</form> </form>
); );
} }
spinner() { spinner() {
return ( return (
<div class="text-center"> <div class="text-center">
<i class="fas fa-spinner fa-spin fa-5x"></i> <i class="fas fa-spinner fa-spin fa-5x"></i>
</div>
);
}
onboard() {
let site: string = "https://gitlab.com/dessalines/torrents.csv";
return (
<div>
<a href={site}>Torrents.csv</a> is a collaborative, <b>vetted</b> git repository of torrents, consisting of a single, searchable <code>torrents.csv</code> file. Its initially populated with a January 2017 backup of the pirate bay, and new torrents are periodically added from various torrents sites via a rust script.<br></br><br></br>
<a href={site}>Torrents.csv</a> will only store torrents with at least one seeder to keep the file small, and will be periodically purged of non-seeded torrents, and sorted by seeders descending.<br></br><br></br>
To request more torrents, or add your own to the file, go <a href={site}>here</a>.<br></br><br></br>
Made with <a href="https://www.rust-lang.org">Rust</a>, <a href="https://github.com/BurntSushi/ripgrep">ripgrep</a>, <a href="https://actix.rs/">Actix</a>, <a href="https://www.infernojs.org">Inferno</a>, and <a href="https://www.typescriptlang.org/">Typescript</a>.
</div> </div>
); );
} }
onboard() { paginator() {
let site: string = "https://gitlab.com/dessalines/torrents.csv"; return (
return ( <nav>
<div> <ul class="pagination">
<a href={site}>Torrents.csv</a> is a collaborative, <b>vetted</b> git repository of torrents, consisting of a single, searchable <code>torrents.csv</code> file. Its initially populated with a January 2017 backup of the pirate bay, and new torrents are periodically added from various torrents sites via a rust script.<br></br><br></br> <li className={(this.state.searchParams.page == 1) ? "page-item disabled" : "page-item"}>
<a href={site}>Torrents.csv</a> will only store torrents with at least one seeder to keep the file small, and will be periodically purged of non-seeded torrents, and sorted by seeders descending.<br></br><br></br> <button class="page-link"
To request more torrents, or add your own to the file, go <a href={site}>here</a>.<br></br><br></br> onClick={linkEvent({ i: this, nextPage: false }, this.switchPage)}
Made with <a href="https://www.rust-lang.org">Rust</a>, <a href="https://github.com/BurntSushi/ripgrep">ripgrep</a>, <a href="https://actix.rs/">Actix</a>, <a href="https://www.infernojs.org">Inferno</a>, and <a href="https://www.typescriptlang.org/">Typescript</a>. >
</div> Previous</button>
); </li>
} <li class="page-item">
<button class="page-link"
paginator() { onClick={linkEvent({ i: this, nextPage: true }, this.switchPage)}>
return ( Next
<nav>
<ul class="pagination">
<li className={(this.state.searchParams.page == 1) ? "page-item disabled" : "page-item"}>
<button class="page-link"
onClick={linkEvent({ i: this, nextPage: false }, this.switchPage)}
>
Previous</button>
</li>
<li class="page-item">
<button class="page-link"
onClick={linkEvent({ i: this, nextPage: true }, this.switchPage)}>
Next
</button> </button>
</li> </li>
</ul> </ul>
</nav> </nav>
); );
} }
searchChange(i, event) { searchChange(i, event) {
let searchParams: SearchParams = { let searchParams: SearchParams = {
q: event.target.value, q: event.target.value,
page: 1 page: 1
} }
i.setState({ searchParams: searchParams }); i.setState({ searchParams: searchParams });
} }
switchPage(a: { i: TorrentSearchComponent, nextPage: boolean }, event) { switchPage(a: { i: TorrentSearchComponent, nextPage: boolean }, event) {
let newSearch = a.i.state.searchParams; let newSearch = a.i.state.searchParams;
newSearch.page += (a.nextPage) ? 1 : -1; newSearch.page += (a.nextPage) ? 1 : -1;
a.i.setState({ a.i.setState({
searchParams: newSearch searchParams: newSearch
}); });
a.i.search(a.i, event); a.i.search(a.i, event);
} }
} }

View File

@ -1,26 +1,26 @@
export interface SearchParams { export interface SearchParams {
q: string; q: string;
page: number; page: number;
size?: number; size?: number;
} }
export interface Results { export interface Results {
torrents: Array<Torrent>; torrents: Array<Torrent>;
} }
export interface Torrent { export interface Torrent {
infohash: string; infohash: string;
name: string; name: string;
size_bytes: number; size_bytes: number;
created_unix: number; created_unix: number;
seeders: number; seeders: number;
leechers: number; leechers: number;
completed: number; completed: number;
scraped_date: number; scraped_date: number;
} }
export interface State { export interface State {
results: Results; results: Results;
searchParams: SearchParams; searchParams: SearchParams;
searching: Boolean; searching: Boolean;
} }