Merge branch 'ui_details_merge'
This commit is contained in:
commit
b4a6b3779a
|
@ -25,6 +25,5 @@ node_modules
|
||||||
*~
|
*~
|
||||||
test/data/result.json
|
test/data/result.json
|
||||||
|
|
||||||
|
|
||||||
package-lock.json
|
package-lock.json
|
||||||
*.orig
|
*.orig
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
.table-fixed {
|
/* globally disable dotted outlines on anchors */
|
||||||
table-layout: fixed;
|
a:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a::-moz-focus-inner {
|
||||||
|
border: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-name-col {
|
.search-name-col {
|
||||||
|
@ -10,9 +15,46 @@
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.table-fixed {
|
||||||
|
table-layout: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add padding to first and last cell */
|
||||||
|
.table-padding th:first-child, .table-padding td:first-child {
|
||||||
|
padding-left: 1em !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-padding th:last-child, .table-padding td:last-child {
|
||||||
|
padding-right: 1em !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table thead th {
|
||||||
|
border: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table tr td {
|
||||||
|
vertical-align: middle !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Colors */
|
||||||
.navbar-purple {
|
.navbar-purple {
|
||||||
background-color: #673ab7;
|
background-color: #673ab7;
|
||||||
-webkit-box-shadow: 0 8px 6px -6px #999;
|
}
|
||||||
-moz-box-shadow: 0 8px 6px -6px #999;
|
|
||||||
box-shadow: 0 8px 6px -6px #999;
|
.table-hover-purple tbody tr:hover {
|
||||||
|
background-color: rgba(103, 58, 183, 0.2) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bootstrap fixes */
|
||||||
|
|
||||||
|
.rounded-right {
|
||||||
|
/* disable radius on left when using on right side */
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-outline, .no-outline:focus {
|
||||||
|
/* disable colored outline on btn or input */
|
||||||
|
box-shadow: none !important;
|
||||||
|
outline: none !important;
|
||||||
}
|
}
|
|
@ -13,16 +13,13 @@ export class Home extends Component<any, any> {
|
||||||
|
|
||||||
onboard() {
|
onboard() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<p class="text-justify">
|
||||||
<br />
|
|
||||||
<a href={repoUrl}>Torrents.csv</a> is a <i>collaborative</i> 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. It comes with a self-hostable webserver, a command line search, and a folder scanner to add torrents.<br /><br />
|
<a href={repoUrl}>Torrents.csv</a> is a <i>collaborative</i> 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. It comes with a self-hostable webserver, a command line search, and a folder scanner to add torrents.<br /><br />
|
||||||
<a href={repoUrl}>Torrents.csv</a> will only store torrents with at least one seeder to keep the file small, will be periodically purged of non-seeded torrents, and sorted by seeders descending.<br /><br />
|
<a href={repoUrl}>Torrents.csv</a> will only store torrents with at least one seeder to keep the file small, will be periodically purged of non-seeded torrents, and sorted by seeders descending.<br /><br />
|
||||||
To request more torrents, or add your own, go <a href={repoUrl}>here</a>.<br /><br />
|
To request more torrents, or add your own, go <a href={repoUrl}>here</a>.<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>.
|
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>.
|
||||||
|
</p>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,37 +23,33 @@ export class Navbar extends Component<any, State> {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>{this.navbar()}</div>
|
<div class="sticky-top">{this.navbar()}</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
navbar() {
|
navbar() {
|
||||||
return (
|
return (
|
||||||
<nav class="navbar navbar-dark navbar-purple">
|
<nav class="navbar navbar-dark navbar-purple p-1 shadow">
|
||||||
<a class="navbar-brand" href="#">
|
<a class="navbar-brand mx-1" href="#">
|
||||||
<i class="fas fa-fw fa-database mr-1"></i>
|
<i class="fas fa-fw fa-database mr-1"></i>
|
||||||
Torrents.csv
|
Torrents.csv
|
||||||
</a>
|
</a>
|
||||||
<ul class="navbar-nav ml-auto">
|
<div class="navbar-nav ml-auto mr-2">
|
||||||
<li class="nav-item">
|
<a class="nav-item nav-link" href={repoUrl}><i class="fab fa-fw fa-github"></i></a>
|
||||||
<a class="nav-link" href={repoUrl}><i class="fab fa-fw fa-github"></i></a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<div class="col-12 col-sm-6">
|
|
||||||
{this.searchForm()}
|
|
||||||
</div>
|
</div>
|
||||||
|
{this.searchForm()}
|
||||||
</nav>
|
</nav>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
|
||||||
// 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="col-12 col-sm-6 m-0 px-1" onSubmit={linkEvent(this, this.search)}>
|
||||||
<div class="input-group">
|
<div class="input-group w-100">
|
||||||
<input value={this.state.searchParams.q} onInput={linkEvent(this, this.searchChange)} type="text" class="form-control" placeholder="Search..." />
|
<input class="form-control border-0 no-outline" type="search" placeholder="Search..." aria-label="Search..." required
|
||||||
<button type="submit" class="btn btn-light border border-left-0 border-radius-left-0">
|
value={this.state.searchParams.q}
|
||||||
|
onInput={linkEvent(this, this.searchChange)}></input>
|
||||||
|
<button class="btn btn-light bg-white border-0 rounded-right no-outline" type="submit">
|
||||||
<i className="fas fa-fw fa-search"></i>
|
<i className="fas fa-fw fa-search"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -76,32 +76,35 @@ export class Search extends Component<any, State> {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className={this.state.results.torrents[0] ? "container-fluid" : "container"}>
|
|
||||||
<div class="row mt-2">
|
|
||||||
<div class="col-12">
|
|
||||||
{
|
{
|
||||||
this.state.searching ?
|
this.state.searching ?
|
||||||
this.spinner()
|
this.spinner() : this.state.results.torrents[0] ?
|
||||||
:
|
this.table() : this.noResults()
|
||||||
this.state.results.torrents[0] ? this.table() : this.noResults()
|
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
);
|
||||||
</div>
|
}
|
||||||
|
|
||||||
|
spinner() {
|
||||||
|
return (
|
||||||
|
<div class="text-center m-5 p-5">
|
||||||
|
<i class="fas fa-spinner fa-spin fa-5x"></i>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
noResults() {
|
noResults() {
|
||||||
return (
|
return (
|
||||||
|
<div class="text-center m-5 p-5">
|
||||||
<h1>No Results</h1>
|
<h1>No Results</h1>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
table() {
|
table() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<table class="table table-fixed table-hover table-sm table-striped">
|
<table class="table table-fixed table-hover table-sm table-striped table-hover-purple table-padding">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="search-name-col">Name</th>
|
<th class="search-name-col">Name</th>
|
||||||
|
@ -117,16 +120,25 @@ export class Search extends Component<any, State> {
|
||||||
<tr>
|
<tr>
|
||||||
<td class="search-name-cell">{torrent.name}</td>
|
<td class="search-name-cell">{torrent.name}</td>
|
||||||
<td class="text-right text-muted">{humanFileSize(torrent.size_bytes, true)}</td>
|
<td class="text-right text-muted">{humanFileSize(torrent.size_bytes, true)}</td>
|
||||||
<td class="text-right text-success"><div><i class="fas fa-fw fa-arrow-up"></i>{torrent.seeders}</div></td>
|
<td class="text-right text-success"><i class="fas fa-fw fa-arrow-up d-none d-sm-inline mr-1"></i>{torrent.seeders}</td>
|
||||||
<td class="text-right text-danger d-none d-md-table-cell"><i class="fas fa-fw fa-arrow-down"></i>{torrent.leechers}</td>
|
<td class="text-right text-danger d-none d-md-table-cell"><i class="fas fa-fw fa-arrow-down mr-1"></i>{torrent.leechers}</td>
|
||||||
<td class="text-right text-muted d-none d-md-table-cell" data-balloon={`Scraped ${moment(torrent.scraped_date * 1000).fromNow()}`} data-balloon-pos="down">
|
<td class="text-right text-muted d-none d-md-table-cell"
|
||||||
|
data-balloon={`Scraped ${moment(torrent.scraped_date * 1000).fromNow()}`}
|
||||||
|
data-balloon-pos="down">
|
||||||
{moment(torrent.created_unix * 1000).fromNow()}
|
{moment(torrent.created_unix * 1000).fromNow()}
|
||||||
</td>
|
</td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
<a data-balloon="Magnet link" data-balloon-pos="left" class="btn btn-sm" href={magnetLink(torrent.infohash, torrent.name)}>
|
<a class="btn btn-sm no-outline p-1"
|
||||||
|
href={magnetLink(torrent.infohash, torrent.name)}
|
||||||
|
data-balloon="Magnet link"
|
||||||
|
data-balloon-pos="left">
|
||||||
<i class="fas fa-fw fa-magnet"></i>
|
<i class="fas fa-fw fa-magnet"></i>
|
||||||
</a>
|
</a>
|
||||||
<a data-balloon="Report Torrent" data-balloon-pos="left" class="btn btn-sm d-none d-md-inline" href={`https://gitlab.com/dessalines/torrents.csv/issues/new?issue[assignee_id]=&issue[milestone_id]=&issue[title]=Report%20Torrent%20infohash%20${torrent.infohash}`}>
|
<a class="btn btn-sm no-outline p-1 d-none d-sm-inline"
|
||||||
|
href={`https://gitlab.com/dessalines/torrents.csv/issues/new?issue[title]=Report%20Torrent%20infohash%20${torrent.infohash}`}
|
||||||
|
target="_blank"
|
||||||
|
data-balloon="Report Torrent"
|
||||||
|
data-balloon-pos="left">
|
||||||
<i class="fas fa-fw fa-flag"></i>
|
<i class="fas fa-fw fa-flag"></i>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
@ -139,23 +151,15 @@ export class Search extends Component<any, State> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
spinner() {
|
|
||||||
return (
|
|
||||||
<div class="text-center">
|
|
||||||
<i class="fas fa-spinner fa-spin fa-5x"></i>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
paginator() {
|
paginator() {
|
||||||
return (
|
return (
|
||||||
<nav>
|
<nav>
|
||||||
<ul class="pagination">
|
<ul class="pagination justify-content-center">
|
||||||
<li className={(this.state.searchParams.page == 1) ? "page-item disabled" : "page-item"}>
|
<li className={(this.state.searchParams.page == 1) ? "page-item disabled" : "page-item"}>
|
||||||
<button class="page-link"
|
<button class="page-link"
|
||||||
onClick={linkEvent({ i: this, nextPage: false }, this.switchPage)}
|
onClick={linkEvent({ i: this, nextPage: false }, this.switchPage)}>
|
||||||
>
|
Previous
|
||||||
Previous</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="page-item">
|
<li class="page-item">
|
||||||
<button class="page-link"
|
<button class="page-link"
|
||||||
|
@ -169,10 +173,8 @@ export class Search extends Component<any, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
switchPage(a: { i: Search, nextPage: boolean }, event) {
|
switchPage(a: { i: Search, 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.props.history.push(`/search/${newSearch.q}/${newSearch.page}`);
|
a.i.props.history.push(`/search/${newSearch.q}/${newSearch.page}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -8,10 +8,8 @@
|
||||||
<link rel="shortcut icon" type="image/ico" href="/favicon.ico" />
|
<link rel="shortcut icon" type="image/ico" href="/favicon.ico" />
|
||||||
|
|
||||||
<title>Torrents.csv</title>
|
<title>Torrents.csv</title>
|
||||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO"
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
|
||||||
crossorigin="anonymous">
|
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU" crossorigin="anonymous">
|
||||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU"
|
|
||||||
crossorigin="anonymous">
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/balloon-css/0.5.0/balloon.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/balloon-css/0.5.0/balloon.min.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,8 @@ class Index extends Component<any, any> {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<HashRouter>
|
<HashRouter>
|
||||||
<div>
|
|
||||||
<Navbar />
|
<Navbar />
|
||||||
|
<div class="mt-3 p-0">
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route exact path="/" component={Home} />
|
<Route exact path="/" component={Home} />
|
||||||
<Route path={`/search/:q/:page`} component={Search} />
|
<Route path={`/search/:q/:page`} component={Search} />
|
||||||
|
|
|
@ -36,9 +36,9 @@ ajax-request@^1.2.0:
|
||||||
utils-extend "^1.0.7"
|
utils-extend "^1.0.7"
|
||||||
|
|
||||||
ajv@^6.5.5:
|
ajv@^6.5.5:
|
||||||
version "6.5.5"
|
version "6.6.1"
|
||||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.5.tgz#cf97cdade71c6399a92c6d6c4177381291b781a1"
|
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.6.1.tgz#6360f5ed0d80f232cc2b294c362d5dc2e538dd61"
|
||||||
integrity sha512-7q7gtRQDJSyuEHjuVgHoUa2VuemFiCMrfQc9Tc08XTAc4Zj/5U1buQJ0HU6i7fKjXU09SVgSmxa4sLvuvS8Iyg==
|
integrity sha512-ZoJjft5B+EJBjUyu9C9Hc0OZyPZSSlOF+plzouTrg6UlA8f+e/n8NIgBFG/9tppJtpPWfthHakK7juJdNDODww==
|
||||||
dependencies:
|
dependencies:
|
||||||
fast-deep-equal "^2.0.1"
|
fast-deep-equal "^2.0.1"
|
||||||
fast-json-stable-stringify "^2.0.0"
|
fast-json-stable-stringify "^2.0.0"
|
||||||
|
@ -1662,12 +1662,12 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3
|
||||||
js-tokens "^3.0.0 || ^4.0.0"
|
js-tokens "^3.0.0 || ^4.0.0"
|
||||||
|
|
||||||
lru-cache@^4.0.1:
|
lru-cache@^4.0.1:
|
||||||
version "4.1.4"
|
version "4.1.5"
|
||||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.4.tgz#51cc46e8e6d9530771c857e24ccc720ecdbcc031"
|
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
|
||||||
integrity sha512-EPstzZ23znHUVLKj+lcXO1KvZkrlw+ZirdwvOmnAnA/1PB4ggyXJ77LRkCqkff+ShQ+cqoxCxLQOh4cKITO5iA==
|
integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
|
||||||
dependencies:
|
dependencies:
|
||||||
pseudomap "^1.0.2"
|
pseudomap "^1.0.2"
|
||||||
yallist "^3.0.2"
|
yallist "^2.1.2"
|
||||||
|
|
||||||
map-cache@^0.2.2:
|
map-cache@^0.2.2:
|
||||||
version "0.2.2"
|
version "0.2.2"
|
||||||
|
@ -3153,6 +3153,11 @@ y18n@^3.2.1:
|
||||||
resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
|
resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
|
||||||
integrity sha1-bRX7qITAhnnA136I53WegR4H+kE=
|
integrity sha1-bRX7qITAhnnA136I53WegR4H+kE=
|
||||||
|
|
||||||
|
yallist@^2.1.2:
|
||||||
|
version "2.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
|
||||||
|
integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
|
||||||
|
|
||||||
yallist@^3.0.0, yallist@^3.0.2:
|
yallist@^3.0.0, yallist@^3.0.2:
|
||||||
version "3.0.3"
|
version "3.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"
|
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"
|
||||||
|
|
Loading…
Reference in New Issue