List page reformatting

main
Marian Steinbach 4 years ago
parent c663c9a0aa
commit d6a5c86c5e
  1. 1
      package.json
  2. 4
      public/index.html
  3. 21
      src/ResultsList.css
  4. 205
      src/ResultsList.js
  5. 0
      src/ResultsList.test.js
  6. 14
      src/ResultsTable.css
  7. 210
      src/ResultsTable.js
  8. 12
      src/index.js
  9. 5
      yarn.lock

@ -13,6 +13,7 @@
"bootstrap": "4.1.3",
"case-sensitive-paths-webpack-plugin": "2.1.1",
"chalk": "1.1.3",
"chroma-js": "^1.4.0",
"css-loader": "0.28.7",
"dotenv": "4.0.0",
"dotenv-expand": "4.2.0",

@ -27,9 +27,7 @@
</nav>
</div>
<div class="container-fluid"></div>
<div id="root"></div>
</div>
<div id="root" class="container"></div>
</body>
</html>

@ -0,0 +1,21 @@
.TypeField {
font-size: 0.8em;
font-weight: 700;
}
.ResultsList {
padding: 3px 0px;
margin: 6px 0px;
}
.ScoreField {
border-radius: 3px;
background-color: #ccc;
padding: 6px 8px;
display: inline-block;
width: 3.5em;
text-align: center;
font-family: 'Arvo Gruen', 'Arvo', sans-serif;
font-size: 120%;
color: #333;
}

@ -0,0 +1,205 @@
/**
* The ResultsTable component is a table of results for all websites we checked.
*/
import React, { Component } from 'react';
import { Link } from "react-router-dom";
import './ResultsList.css';
import punycode from 'punycode';
import chroma from 'chroma-js';
class ScoreField extends Component {
render() {
var ratio = this.props.score / this.props.maxScore;
var bg = chroma.mix('#8D5335', '#75B66B', ratio);
return <span className='ScoreField' style={{backgroundColor: bg.hex()}}>{ this.props.score }</span>;
}
}
class StateField extends Component {
render() {
var label = this.props.state;
switch (this.props.state) {
case 'Nordrhein-Westfalen':
label = 'NW';
break;
case 'Rheinland-Pfalz':
label = 'RP';
break;
case 'Niedersachsen':
label = 'NS';
break;
case 'Baden-Württemberg':
label = 'BW';
break;
case 'Bayern':
label = 'BY';
break;
case 'Berlin':
label = 'BE';
break;
case 'Brandenburg':
label = 'BB';
break;
case 'Bremen':
label = 'HB';
break;
case 'Hamburg':
label = 'HB';
break;
case 'Hessen':
label = 'HE';
break;
case 'Mecklenburg-Vorpommern':
label = 'MV';
break;
case 'Saarland':
label = 'SL';
break;
case 'Sachsen':
label = 'SN';
break;
case 'Sachsen-Anhalt':
label = 'SA';
break;
case 'Schleswig-Holstein':
label = 'SH';
break;
case 'Thüringen':
label = 'SN';
break;
default:
label = this.props.state;
}
return <abbr title={this.props.state}>{label}</abbr>;
}
}
class TypeField extends Component {
render() {
var label = '';
var title = '';
if (this.props.level === 'DE:BUNDESVERBAND') {
if (this.props.type === 'YOUTH_ORGANIZATION') {
title = 'Grüne Jugend Bundesverband';
label = 'GJ BV';
} else {
title = 'Bundesverband';
label = 'BV';
}
} else if (this.props.level === 'DE:LANDESVERBAND') {
if (this.props.type === 'YOUTH_ORGANIZATION') {
title = 'Grüne Jugend Landesverband';
label = 'GJ LV';
} else {
title = 'Landesverband';
label = 'LV';
}
} else if (this.props.level === 'DE:REGIONALVERBAND') {
title = 'Regionalverband';
label = 'RV';
} else if (this.props.level === 'DE:BEZIRKSVERBAND') {
title = 'Bezirksverband';
label = 'BeV';
} else if (this.props.level === 'DE:KREISVERBAND') {
if (this.props.type === 'YOUTH_ORGANIZATION') {
title = 'Grüne Jugend Kreisverband';
label = 'GJ KV';
} else {
title = 'Kreisverband';
label = 'KV';
}
} else if (this.props.level === 'DE:ORTSVERBAND') {
title = 'Ortsverband';
label = 'OV';
}
return <abbr className='TypeField' title={title}>{label}</abbr>;
}
}
class URLField extends Component {
displayURL(url) {
var match = url.match(/:\/\/(www[0-9]?\.)?(.[^/:]+)/i);
if (match != null && match.length > 2 && typeof match[2] === 'string' && match[2].length > 0) {
return match[2];
}
return null;
}
// truncation for too long URLs
trunc(s, length) {
if (s.length > length) {
s = s.substring(0, length) + '…';
}
return s;
}
render() {
var labelURL = this.trunc(this.displayURL(punycode.toUnicode(this.props.inputURL)), 40);
return <span className='URLField'>{ labelURL }</span>;
}
}
class LocationLabel extends Component {
render() {
var label = "";
var type = <TypeField level={this.props.level} type={this.props.type} />;
if (this.props.city === null && this.props.district !== null) {
label = this.props.district;
return <span className='LocationLabel'>{type} {label}, <StateField state={this.props.state} /></span>;
} else if (this.props.city !== null && this.props.district === null) {
label = this.props.city;
return <span className='LocationLabel'>{type} {label}, <StateField state={this.props.state} /></span>;
} else if (this.props.city !== null && this.props.district !== null) {
label = `${this.props.city}, ${this.props.district}`;
return <span className='LocationLabel'>{type} {label}, <StateField state={this.props.state} /></span>;
}
label = this.props.state;
return <span className='LocationLabel'>{type} {label}</span>;
}
}
class ResultsList extends Component {
render() {
// sort results by score (descending)
this.props.results.sort((a, b) => {
return b.score - a.score;
});
var rows = [];
this.props.results.forEach((element, index) => {
var row = (
<div className='ResultsList row' key={element.input_url}>
<div className='col-12'>
<Link to={`/sites/${ encodeURIComponent(element.input_url) }`}>
<div className='row'>
<div className='col-9'>
<LocationLabel level={element.meta.level} type={element.meta.type} district={element.meta.district} city={element.meta.city} state={element.meta.state} />
</div>
<div className='col-3'>
<ScoreField score={element.score} maxScore={13} />
</div>
</div>
<URLField key={'uf'+index} inputURL={element.input_url} canonicalURLs={element.resulting_urls} />
</Link>
</div>
</div>
);
rows.push(row);
});
return rows;
}
}
export default ResultsList;

@ -1,14 +0,0 @@
.ResultsTable {
text-align: center;
font-size: 0.8rem;
}
.ResultsTable td.text {
font-size: 0.8rem;
}
.ResultsTable a.screenshot {
display: inline-block;
margin-left: 3px;
margin-right: 3px;
}

@ -1,210 +0,0 @@
/**
* The ResultsTable component is a table of results for all websites we checked.
*/
import React, { Component } from 'react';
import { Link } from "react-router-dom";
import './ResultsTable.css';
import punycode from 'punycode';
class CityField extends Component {
render() {
return <td key='city'>{ this.props.city }</td>;
}
}
class DistrictField extends Component {
render() {
return <td key='district'>{ this.props.district }</td>;
}
}
class ScoreField extends Component {
render() {
return <td key='score'>{ this.props.score }</td>;
}
}
class StateField extends Component {
render() {
var label = this.props.state;
switch (this.props.state) {
case 'Nordrhein-Westfalen':
label = 'NW';
break;
case 'Rheinland-Pfalz':
label = 'RP';
break;
case 'Niedersachsen':
label = 'NS';
break;
case 'Baden-Württemberg':
label = 'BW';
break;
case 'Bayern':
label = 'BY';
break;
case 'Berlin':
label = 'BE';
break;
case 'Brandenburg':
label = 'BB';
break;
case 'Bremen':
label = 'HB';
break;
case 'Hamburg':
label = 'HB';
break;
case 'Hessen':
label = 'HE';
break;
case 'Mecklenburg-Vorpommern':
label = 'MV';
break;
case 'Saarland':
label = 'SL';
break;
case 'Sachsen':
label = 'SN';
break;
case 'Sachsen-Anhalt':
label = 'SA';
break;
case 'Schleswig-Holstein':
label = 'SH';
break;
case 'Thüringen':
label = 'SN';
break;
default:
label = this.props.state;
}
return <td key='state'><abbr title={this.props.state}>{label}</abbr></td>;
}
}
class TypeField extends Component {
render() {
var label;
if (this.props.level === 'DE:BUNDESVERBAND') {
if (this.props.type === 'YOUTH_ORGANIZATION') {
label = <abbr title='Grüne Jugend Bundesverband'>GJ BV</abbr>;
} else {
label = <abbr title='Bundesverband'>BV</abbr>;
}
} else if (this.props.level === 'DE:LANDESVERBAND') {
if (this.props.type === 'YOUTH_ORGANIZATION') {
label = <abbr title='Grüne Jugend Landesverband'>GJ LV</abbr>;
} else {
label = <abbr title='Landesverband'>LV</abbr>;
}
} else if (this.props.level === 'DE:REGIONALVERBAND') {
label = <abbr title='Regionalverband'>RV</abbr>;
} else if (this.props.level === 'DE:BEZIRKSVERBAND') {
label = <abbr title='Bezirksverband'>BeV</abbr>;
} else if (this.props.level === 'DE:KREISVERBAND') {
if (this.props.type === 'YOUTH_ORGANIZATION') {
label = <abbr title='Grüne Jugend Kreisverband'>GJ KV</abbr>;
} else {
label = <abbr title='Kreisverband'>KV</abbr>;
}
} else if (this.props.level === 'DE:ORTSVERBAND') {
label = <abbr title='Ortsverband'>OV</abbr>;
}
return <td key='typefield'>{ label }</td>;
}
}
class URLField extends Component {
// truncation for too long URLs
trunc(s, length) {
if (s.length > length) {
s = s.substring(0, length) + '…';
}
return s;
}
render() {
var inputDisplayURL = this.trunc(punycode.toUnicode(this.props.inputURL), 45);
// There is a canonical URL...
if (typeof this.props.canonicalURLs !== 'undefined' && this.props.canonicalURLs !== null && this.props.canonicalURLs.length === 1) {
// and it is the same as the input URL
if (this.props.inputURL === this.props.canonicalURLs[0]) {
return <td key='url'> <a href={this.props.inputURL} target="_blank" rel='noopener noreferrer'> { inputDisplayURL }</a></td>;
}
// canonical URL contains input URL (as prefix)
if (this.props.canonicalURLs[0].indexOf(this.props.inputURL) === 0) {
var targetLabel = '/' + this.props.canonicalURLs[0].substr(this.props.inputURL.length);
return <td key='url'><a href={this.props.inputURL} target="_blank" rel='noopener noreferrer'> { inputDisplayURL }</a> <a href={this.props.canonicalURLs[0]} rel='noopener noreferrer'>{targetLabel}</a></td>;
}
var targetDisplayURL = this.trunc(punycode.toUnicode(this.props.canonicalURLs[0]), 45);
return (
<td key='url'>
<a href={this.props.inputURL} target="_blank" rel='noopener noreferrer'> { inputDisplayURL }</a><br />
<a href={this.props.canonicalURLs[0]} target="_blank" rel='noopener noreferrer'> { targetDisplayURL }</a>
</td>
);
}
// no canonical URL
return <td key='url'><a href={this.props.inputURL} target="_blank" rel='noopener noreferrer'> { inputDisplayURL }</a></td>;
}
}
class ResultsTable extends Component {
render() {
// sort results by score (descending)
this.props.results.sort((a, b) => {
return b.score - a.score;
});
var rows = [];
this.props.results.forEach((element, index) => {
var fields = [
<TypeField key={'tf'+index} level={element.meta.level} type={element.meta.type} />,
<StateField key={'sf'+index} state={element.meta.state} />,
<DistrictField key={'df'+index} district={element.meta.district} />,
<CityField key={'cf'+index} city={element.meta.city} />,
<URLField key={'uf'+index} inputURL={element.input_url} canonicalURLs={element.resulting_urls} />,
<ScoreField key={'scf'+index} score={element.score} />,
(
<td key={'link-'+index}>
<Link to={`/sites/${ encodeURIComponent(element.input_url) }`}>Details</Link>
</td>
),
];
rows.push(<tr key={element.input_url}>{ fields }</tr>)
});
return (
<table className='table ResultsTable'>
<thead>
<tr>
<th scope='col'>Typ</th>
<th scope='col'>Land</th>
<th scope='col'>Kreis</th>
<th scope='col'>Stadt</th>
<th scope='col'>URL</th>
<th scope='col'>Score</th>
<th scope='col'>Link</th>
</tr>
</thead>
<tbody>{ rows }</tbody>
</table>
);
}
}
export default ResultsTable;

@ -6,12 +6,12 @@ import './index.css';
import results from './spider_result_compact.json';
import screenshots from './screenshots.json';
import StatusInfo from './StatusInfo';
import ResultsTable from './ResultsTable';
import ResultsList from './ResultsList';
import SiteDetailsPage from './SiteDetailsPage';
import registerServiceWorker from './registerServiceWorker';
const Home = () => (
<ResultsTable results={results} />
<ResultsList results={results} />
);
const SiteDetails = ({ match }) => (
@ -20,9 +20,11 @@ const SiteDetails = ({ match }) => (
const AppMainContent = () => (
<Router>
<div>
<Route exact path="/" component={Home} />
<Route path="/sites/:siteId" component={SiteDetails} />
<div className='row'>
<div className='col-12'>
<Route exact path="/" component={Home} />
<Route path="/sites/:siteId" component={SiteDetails} />
</div>
</div>
</Router>
);

@ -1587,6 +1587,11 @@ chownr@^1.0.1:
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494"
integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==
chroma-js@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/chroma-js/-/chroma-js-1.4.0.tgz#695c52e7c97617e5f687db31913503d410481ae4"
integrity sha512-5vBYGJkhSnK2SRZ0XkxwTL+TSRyP7PHIxjeg+1uce5qpNDRLLwAXcF12kIztas/BYakWPQhchzV4TKkiwKNd8Q==
ci-info@^1.5.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497"

Loading…
Cancel
Save