Add basic modal component; Add resultDetails to search

This commit is contained in:
Robbie Antenesse 2019-09-11 17:34:11 -06:00
parent 464aad9d34
commit b1843c688c
4 changed files with 113 additions and 18 deletions

View File

@ -0,0 +1,66 @@
import html from 'choo/html';
export const modal = (modalId, controller, contentHTML, options = {}) => {
/* Options:
* controller <class>: Pass the controller class with state; Requires get/set for openModal in state.
* buttonHTML <choo/html>: Displayed in place of the default button to open the modal
* buttonText <string>: Displayed if no buttonHTML is specified
* noHeader <bool>: Set to `true` and exclude headerHTML to not include a modal header
* headerHTML <choo/html>: Displayed in place of the default header; Recommended to use `<header>` tag
* 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
* footerHTML <choo/html>: Displayed in place of the default footer; Recommended to use `<footer>` tag
*/
const isOpen = controller.openModal === modalId;
return [
(
typeof options.buttonHTML === 'undefined'
? html`<label for=${modalId} class="button">${options.buttonText}</label>`
: options.buttonHTML
),
// Modals in Picnic CSS uses pure CSS with clever usage of invisible checkboxes and labels
html`<div class="modal">
<input id=${modalId} type="checkbox" ${!isOpen ? null : 'checked'}
onchange=${() => controller.openModal = isOpen ? modalId : null }/>
<label for=${modalId} class="overlay"></label>
<article>
${typeof options.headerHTML === 'undefined'
? (
options.noHeader
? null
: html`<header>
<h3>${options.headerText}</h3>
<label for=${modalId} class="close">${'\u00d7'}</label>
</header>`
)
: options.headerHTML
}
<section class="content">
${typeof contentHTML === 'undefined'
? null
: contentHTML
}
</section>
${typeof options.footerHTML === 'undefined'
? (
options.noFooter
? null
: html`<footer>
<label for=${modalId} class="button dangerous">
Close
</label>
</footer>`
)
: options.footerHTML
}
</article>
</div>`,
];
}

View File

@ -12,6 +12,7 @@ export class SearchController extends ViewController {
series: [],
works: [],
},
openModal: null,
});
// If using controller methods in an input's onchange or onclick instance,
@ -31,6 +32,14 @@ export class SearchController extends ViewController {
return this.appState.query.hasOwnProperty('for') && this.appState.query.for.trim() !== '';
}
get openModal() {
return this.state.openModal;
}
set openModal(modalId) {
this.state.openModal = modalId;
}
search() {
if (this.hasQuery) {
this.state.done = false;

View File

@ -2,6 +2,7 @@ import html from 'choo/html';
import { I18n } from '../../i18n';
import { SearchController } from './controller'; // The controller for this view, where processing should happen.
import { resultDetails } from './resultDetails';
// This is the view function that is exported and used in the view manager.
export const searchView = (state, emit) => {
@ -30,28 +31,28 @@ export const searchView = (state, emit) => {
html`<h2>${i18n.__('search.books_header')}</h2>`,
controller.results.works.map(result => {
return html`<div class="flex search-result">
<div class="half-500">
<div class="two-third-500">
<h3 class="title">${result.name}</h3>
${result.description ? html`<h4 class="subtitle">${result.description}</h4>` : null}
</div>
<div class="third-500">
<span data-tooltip=${i18n.__('interaction.heart')}>
<button class="pseudo">
<i class="pseudo icon-heart-outline"></i>
</button>
</span>
<span data-tooltip=${i18n.__('interaction.add')}>
<button class="pseudo">
<i class="pseudo icon-plus"></i>
</button>
</span>
</div>
<div class="sixth-500">
<span class="tooltip-left" data-tooltip=${i18n.__('search.see_details_tooltip')}>
<a class="small pseudo button" href=${result.link} target="_blank">
${i18n.__('search.see_details')}
</a>
</span>
${resultDetails(
controller,
i18n,
result,
[
html`<span data-tooltip=${i18n.__('interaction.heart')}>
<button class="pseudo">
<i class="pseudo icon-heart-outline"></i>
</button>
</span>`,
html`<span data-tooltip=${i18n.__('interaction.add')}>
<button class="pseudo">
<i class="pseudo icon-plus"></i>
</button>
</span>`,
]
)}
</div>
</div>`;
}),

View File

@ -0,0 +1,19 @@
import html from 'choo/html';
import { modal } from '../partials/modal';
export const resultDetails = (searchController, i18n, result, buttonHTML) => {
const modalId = `result_${result.uri}}`;
const modalContent = html`<article>
<span class="tooltip-left" data-tooltip=${i18n.__('search.see_details_tooltip')}>
<a class="small pseudo button" href=${result.link} target="_blank">
${i18n.__('search.see_details')}
</a>
</span>
</article>`;
return modal(modalId, searchController, modalContent, {
buttonText: i18n.__('search.see_details'), // This should be replaced with buttonHTML containing the ratings and number of reviews etc.
headerText: result.name,
});
}