Load covers in resultDetails sorted by publish date
This commit is contained in:
parent
46d3da8010
commit
0ebafaeb9e
|
@ -35,10 +35,11 @@
|
||||||
@import '../../node_modules/picnic/src/plugins/modal/plugin';
|
@import '../../node_modules/picnic/src/plugins/modal/plugin';
|
||||||
|
|
||||||
// @import '../../node_modules/picnic/src/plugins/dropimage/plugin';
|
// @import '../../node_modules/picnic/src/plugins/dropimage/plugin';
|
||||||
// @import '../../node_modules/picnic/src/plugins/tabs/plugin';
|
@import '../../node_modules/picnic/src/plugins/tabs/plugin';
|
||||||
@import '../../node_modules/picnic/src/plugins/tooltip/plugin';
|
@import '../../node_modules/picnic/src/plugins/tooltip/plugin';
|
||||||
|
|
||||||
// Custom global styling
|
// Custom global styling
|
||||||
|
@import './picnic-customizations/tabs';
|
||||||
@import './picnic-customizations/custom';
|
@import './picnic-customizations/custom';
|
||||||
|
|
||||||
// View styling
|
// View styling
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
$tabs: five, six, seven, eight, nine, ten, eleven, twelve, thirteen, fourteen, fifteen, sixteen, seventeen, eighteen, nineteen, twenty;
|
||||||
|
|
||||||
|
.tabs {
|
||||||
|
&.one {
|
||||||
|
> .row {
|
||||||
|
width: 100%;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
> input:nth-of-type(1):checked ~ .row {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
> label img {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is probably really stupid, but whatever. I need more than the 4 built-in tabs that Picnic provides
|
||||||
|
@for $tab-index from 1 through length($tabs) {
|
||||||
|
$number: $tab-index + 4;
|
||||||
|
$tab: nth($tabs, $tab-index);
|
||||||
|
|
||||||
|
&.#{$tab} {
|
||||||
|
> .row {
|
||||||
|
width: 100% * $number;
|
||||||
|
left: -100% * ($number - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@for $item from 1 through ($number - 1) {
|
||||||
|
> input:nth-of-type(#{$item}):checked ~ .row {
|
||||||
|
margin-left: (100% * ($number - 1)) - (100% * ($item - 1));// 400%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> label img {
|
||||||
|
width: floor(100% / $number) - 2%;
|
||||||
|
margin: 4% 0 4% 4%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,8 @@ export const modal = (modalId, controller, contentHTML, options = {}) => {
|
||||||
* headerText <string>: Displayed in an `<h3>` if no header is specified
|
* headerText <string>: Displayed in an `<h3>` if no header is specified
|
||||||
* noFooter <bool>: Set to `true` and exclude footerHTML to not include a modal footer
|
* noFooter <bool>: Set to `true` and exclude footerHTML to not include a modal footer
|
||||||
* footerHTML <choo/html>: Displayed in place of the default footer; Recommended to use `<footer>` tag
|
* footerHTML <choo/html>: Displayed in place of the default footer; Recommended to use `<footer>` tag
|
||||||
|
* onShow <function>: Runs when the modal opens.
|
||||||
|
* onHide <function>: Runs when the modal closes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const isOpen = controller.openModal === modalId;
|
const isOpen = controller.openModal === modalId;
|
||||||
|
@ -23,9 +25,17 @@ export const modal = (modalId, controller, contentHTML, options = {}) => {
|
||||||
|
|
||||||
// Modals in Picnic CSS uses pure CSS with clever usage of invisible checkboxes and labels
|
// Modals in Picnic CSS uses pure CSS with clever usage of invisible checkboxes and labels
|
||||||
html`<div class="modal">
|
html`<div class="modal">
|
||||||
<input id=${modalId} type="checkbox" ${!isOpen ? null : 'checked'}
|
<input id=${modalId} type="checkbox" ${isOpen ? 'checked' : null} onchange=${event => {
|
||||||
onchange=${() => controller.openModal = isOpen ? modalId : null }/>
|
controller.openModal = !isOpen ? modalId : null; // If it's not already open, set it to the open one
|
||||||
|
if (typeof options.onShow !== 'undefined' && event.target.checked) {
|
||||||
|
options.onShow();
|
||||||
|
}
|
||||||
|
if (typeof options.onHide !== 'undefined' && !event.target.checked) {
|
||||||
|
options.onHide();
|
||||||
|
}
|
||||||
|
}}>
|
||||||
<label for=${modalId} class="overlay"></label>
|
<label for=${modalId} class="overlay"></label>
|
||||||
|
|
||||||
<article style=${typeof options.styles !== 'undefined' ? options.styles : null}>
|
<article style=${typeof options.styles !== 'undefined' ? options.styles : null}>
|
||||||
|
|
||||||
${typeof options.headerHTML === 'undefined'
|
${typeof options.headerHTML === 'undefined'
|
||||||
|
|
|
@ -56,4 +56,21 @@ export class SearchController extends ViewController {
|
||||||
}
|
}
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getCovers(inventaireURI) {
|
||||||
|
// This should only be callable after results are displayed.
|
||||||
|
const workIndex = this.results.works.findIndex(work => work.uri === inventaireURI);
|
||||||
|
if (workIndex > -1) { // This should never be false, but just in case...
|
||||||
|
if (typeof this.state.results.works[workIndex].covers === 'undefined') {
|
||||||
|
// Only fetch covers if not already fetched.
|
||||||
|
return fetch(`/api/books/covers?uri=${inventaireURI}&lang=${this.appState.language}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(responseJSON => {
|
||||||
|
this.state.results.works[workIndex].covers = responseJSON;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -35,7 +35,7 @@ export const searchView = (state, emit) => {
|
||||||
${result.description ? html`<h4 class="subtitle">${result.description}</h4>` : null}
|
${result.description ? html`<h4 class="subtitle">${result.description}</h4>` : null}
|
||||||
</div>
|
</div>
|
||||||
<div class="third-800 half-500">
|
<div class="third-800 half-500">
|
||||||
${resultDetails(controller, result)}
|
${resultDetails(controller, result, emit)}
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -3,7 +3,7 @@ import html from 'choo/html';
|
||||||
import { starRating } from '../partials/starRating';
|
import { starRating } from '../partials/starRating';
|
||||||
import { modal } from '../partials/modal';
|
import { modal } from '../partials/modal';
|
||||||
|
|
||||||
export const resultDetails = (searchController, result) => {
|
export const resultDetails = (searchController, result, emit = () => {}) => {
|
||||||
const { i18n } = searchController;
|
const { i18n } = searchController;
|
||||||
const modalId = `result_${result.uri}`;
|
const modalId = `result_${result.uri}`;
|
||||||
|
|
||||||
|
@ -17,10 +17,41 @@ export const resultDetails = (searchController, result) => {
|
||||||
</span>
|
</span>
|
||||||
</label>`;
|
</label>`;
|
||||||
|
|
||||||
|
const tabNames = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen', 'twenty'];
|
||||||
|
|
||||||
const modalContent = html`<article class="flex">
|
const modalContent = html`<article class="flex">
|
||||||
<div class="sixth-700" style="text-align:center;">
|
<div class="sixth-700" style="text-align:center;">
|
||||||
<h4>Covers</h4>
|
<h4>Covers</h4>
|
||||||
<span style="font-size:3em;"><i class="icon-loading animate-spin"></i></span>
|
${typeof result.covers === 'undefined'
|
||||||
|
? html`<span style="font-size:3em;"><i class="icon-loading animate-spin"></i></span>`
|
||||||
|
: html`<div class="tabs ${typeof tabNames[result.covers.length - 1] !== 'undefined' ? tabNames[result.covers.length - 1] : null}">
|
||||||
|
${result.covers.map((cover, index) => {
|
||||||
|
return [
|
||||||
|
html`<input id="cover_${cover.uri}" type="radio" name="${modalId}_covers" ${index === 0 ? 'checked' : null} />`,
|
||||||
|
// html`<label class="small pseudo button toggle" for="cover_${cover.uri}">•</label>`,
|
||||||
|
];
|
||||||
|
})}
|
||||||
|
<div class="row">
|
||||||
|
${result.covers.map((cover, index, allCovers) => {
|
||||||
|
return html`<div>
|
||||||
|
<img src=${cover.url} alt="${cover.uri.replace(':', ' ').toUpperCase()}, Published: ${cover.publishDate}">
|
||||||
|
${typeof allCovers[index - 1] === 'undefined'
|
||||||
|
? null
|
||||||
|
: html`<label class="button" for="cover_${allCovers[index - 1].uri}" style="margin-right:8px;">
|
||||||
|
${'<'}
|
||||||
|
</label>`
|
||||||
|
}
|
||||||
|
${typeof allCovers[index + 1] === 'undefined'
|
||||||
|
? null
|
||||||
|
: html`<label class="button" for="cover_${allCovers[index + 1].uri}">
|
||||||
|
${'>'}
|
||||||
|
</label>`
|
||||||
|
}
|
||||||
|
</div>`;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>`
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class="two-third-700">
|
<div class="two-third-700">
|
||||||
<h4>${i18n.__('interaction.average_rating')}</h4>
|
<h4>${i18n.__('interaction.average_rating')}</h4>
|
||||||
|
@ -84,5 +115,10 @@ export const resultDetails = (searchController, result) => {
|
||||||
styles: "width:90%;",
|
styles: "width:90%;",
|
||||||
buttonHTML, // This should be replaced with buttonHTML containing the ratings and number of reviews etc.
|
buttonHTML, // This should be replaced with buttonHTML containing the ratings and number of reviews etc.
|
||||||
headerText: result.name,
|
headerText: result.name,
|
||||||
|
onShow: () => {
|
||||||
|
if (typeof result.covers === 'undefined') {
|
||||||
|
searchController.getCovers(result.uri).then(() => emit('render'));
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -185,16 +185,26 @@ class BooksController {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return Object.keys(responseJSON.entities).filter(key => {
|
const covers = Object.keys(responseJSON.entities).filter(key => {
|
||||||
const entity = responseJSON.entities[key];
|
const entity = responseJSON.entities[key];
|
||||||
return entity.originalLang === this.lang && typeof entity.claims !== undefined && typeof entity.claims['invp:P2'] !== undefined;
|
return entity.originalLang === this.lang && typeof entity.claims !== undefined && typeof entity.claims['invp:P2'] !== undefined;
|
||||||
}).map(key => {
|
}).map(key => {
|
||||||
const entity = responseJSON.entities[key];
|
const entity = responseJSON.entities[key];
|
||||||
return {
|
return {
|
||||||
uri: entity.uri,
|
uri: entity.uri,
|
||||||
url: `${this.inventaire}/img/entities/${entity.claims['invp:P2'][0]}`,
|
url: typeof entity.claims['invp:P2'] !== 'undefined' ? `${this.inventaire}/img/entities/${entity.claims['invp:P2'][0]}` : null,
|
||||||
|
publishDate: typeof entity.claims['wdt:P577'] !== 'undefined' ? entity.claims['wdt:P577'][0] : null,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
covers.sort((a, b) => {
|
||||||
|
if (a.publishDate === b.publishDate) return 0;
|
||||||
|
if (!a.publishDate && !!b.publishDate) return 1;
|
||||||
|
if (!!a.publishDate && !b.publishDate) return 1;
|
||||||
|
return a.publishDate < b.publishDate ? -1 : 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
return covers;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ fastify.addHook('onRequest', (request, reply, done) => {
|
||||||
|
|
||||||
// Routes
|
// Routes
|
||||||
fastify.register(require('./routes/public'));
|
fastify.register(require('./routes/public'));
|
||||||
// fastify.register(require('./routes/home'));
|
fastify.register(require('./routes/books'));
|
||||||
// fastify.register(require('./routes/account'));
|
// fastify.register(require('./routes/account'));
|
||||||
fastify.register(require('./routes/search'));
|
fastify.register(require('./routes/search'));
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,14 @@ async function routes(fastify, options) {
|
||||||
|
|
||||||
return books.getBookData();
|
return books.getBookData();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
fastify.get('/api/books/covers', async (request, reply) => {
|
||||||
|
const bookURI = typeof request.query.uri !== 'undefined' ? request.query.uri.trim() : '';
|
||||||
|
const language = typeof request.query.lang !== 'undefined' ? request.query.lang.trim().split('-')[0] : undefined; // Get base language in cases like 'en-US'
|
||||||
|
const books = new BooksController(fastify.siteConfig.inventaireDomain, bookURI, language);
|
||||||
|
|
||||||
|
return await books.getInventaireCovers();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = routes
|
module.exports = routes
|
Loading…
Reference in New Issue