diff --git a/static/resources_list.txt b/static/resources_list.txt index 025742834..9939f4b61 100644 --- a/static/resources_list.txt +++ b/static/resources_list.txt @@ -18,6 +18,7 @@ skin/jquery-ui/images/ui-bg_glass_95_fef1ec_1x400.png skin/jquery-ui/jquery-ui.theme.min.css skin/jquery-ui/jquery-ui.min.css skin/caret.png +skin/search-icon.svg skin/taskbar.js skin/langList.js skin/categoryList.js @@ -25,6 +26,9 @@ skin/iso6391To3.js skin/isotope.pkgd.min.js skin/index.js skin/taskbar.css +skin/home.css +skin/fonts/Poppins.ttf +skin/fonts/Roboto.ttf skin/block_external.js templates/search_result.html templates/no_search_result.html diff --git a/static/skin/fonts/Poppins.ttf b/static/skin/fonts/Poppins.ttf new file mode 100644 index 000000000..e90e87ed6 Binary files /dev/null and b/static/skin/fonts/Poppins.ttf differ diff --git a/static/skin/fonts/Roboto.ttf b/static/skin/fonts/Roboto.ttf new file mode 100644 index 000000000..3d6861b42 Binary files /dev/null and b/static/skin/fonts/Roboto.ttf differ diff --git a/static/skin/home.css b/static/skin/home.css new file mode 100644 index 000000000..5c07bf7ee --- /dev/null +++ b/static/skin/home.css @@ -0,0 +1,378 @@ +*, +*::after, +*::before { + margin: 0; + padding: 0; + box-sizing: inherit; +} + +html { + font-size: 62.5%; +} + +body { + position: relative; + box-sizing: border-box; +} + +::selection { + background-color: #00b4e4; + color: white; +} + +.kiwixNav { + background-color: #f4f6f8; + width: 100%; + padding: 20px 11vw 25px; + height: 140px; +} + +.kiwixHomeBody__results { + font-size: 1.6rem; + color: #333333; + font-family: poppins; + margin: 10px 0 -5px; + position: relative; + top: -10px; + left: 13px; +} + +.kiwixNav__filters { + display: grid; + grid-gap: 20px; + grid-template-columns: 231px 231px; + margin: 10px 0; +} + +.kiwixNav__kiwixFilter { + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + outline: 0; + box-shadow: none; + border: 0 !important; + background: white; + background-image: none; + border-radius: 1px; + width: 195px; + height: 35px; + flex: 1; + color: black; + padding: 7px 10px 10px; + cursor: pointer; + } + + .kiwixNav__kiwixFilter:-ms-expand { + display: none; + } + +.kiwixNav__select { + position: relative; + display: flex; + width: 231px; + height: 35px; + line-height: 3; + background: #909090; + overflow: hidden; + border-radius: 10px; + border: 1px solid #b5b2b2; +} + +.kiwixNav__select::after { + content: '\25BC'; + color: #fff; + background-color: #909090; + height: 100%; + position: absolute; + top: 0; + right: 0; + padding: 0 1em; + cursor: pointer; + pointer-events: none; + -webkit-transition: .25s all ease; + -o-transition: .25s all ease; + transition: .25s all ease; +} + +.kiwixNav__kiwixFilter option { + background-color: #fff; + color: #000; +} + +.kiwixSearch { + height: 35px; + width: 229px; + border-radius: 10px; + border: solid 1px #b5b2b2; + padding: 10px; + background-image: url('./search-icon.svg'); + background-repeat: no-repeat; + background-position: right center; + background-origin: content-box; + background-size: 15px; +} + +.searchButton { + margin: 0 17px; + height: 35px; + width: 100px; + border-radius: 10px; + color: white; + background-color: #909090; + border: solid 1px #b5b2b2; +} + +.searchButton:hover { + background-color: #858585; +} + +.kiwixHomeBody { + padding: 20px 15vw; + min-height: calc(100vh - 170px); + position: relative; +} + +.book__list { + position: relative; +} + +.book { + border-color: #acacac; +} + +.book__wrapper { + color: #444343; + height: 280px; + width: 250px; + margin: 15px; + background-color: #f7f7f7; + border: 1px solid #ececec; + border-radius: 3px; + display: grid; + grid-template-columns: 65px 1fr; + grid-template-rows: 70px 120px 1fr 1fr; + grid-gap: 5px; + transition: transform 0.25s; +} + +.book__wrapper:hover { + transform: scale(1.07); +} + +.book__icon { + display: flex; + align-items: center; + align-content: center; + justify-content: center; + margin: 10px 0 0 10px; +} + +.book__icon--image { + max-width: 100%; + max-height: 100%; +} + +.book__title { + display: grid; + font-family: poppins; + color: black; + padding: 12px 10px 0 2px; + width: 100%; + height: 100%; + align-items: center; + align-content: center; +} + +#bookSize { + font-size: 1.1rem; + margin: 3px 0; +} + +#bookTitle { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + font-size: 1.45rem; +} + +.book__description { + grid-column: 1 / 3; + margin: 10px 10px 5px; + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 7; + -webkit-box-orient: vertical; + font-family: roboto; + font-weight: 300; + font-size: 1.2rem; + color: #4d4d4d; + line-height: 1.25; +} + +.book__languageTag { + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 0 2px #acacac; + background-color: #ffffff; + font-weight: bold; + font-family: roboto; + color: black; + height: 25px; + width: 25px; + margin: 10px auto 0 10px; + border-radius: 5px; + font-size: 0.85rem; +} + +.book__tags { + display: flex; + text-align: end; + font-size: 1.1rem; + justify-content: flex-end; + color: #909090; + font-family: roboto; + margin-right: 10px; + margin-top: 10px; + overflow: hidden; +} + +.book__tags--wrapper { + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} + +.book__links { + display: flex; + text-align: end; + justify-content: flex-end; + grid-column: 2 / 3; + font-size: 1.1rem; + margin: 10px 4px; + color: #00b4e4; +} + +.book__links > a, .book__links > span { + text-decoration: none; + color: #00b4e4; + position: relative; + padding: 1px 6px 0; + font-family: roboto; +} + +.book__links > a:hover { + background: #00b4e4; + color: white; +} + +.fadeOut { + position: fixed; + display: none; + bottom: 0; + left: 0; + z-index: 1; + background: linear-gradient(180deg, rgba(232, 232, 232, 0) 0%, #ffffff 100%); + height: 80px; + width: 100%; +} + +.noResults { + font-size: 1.6rem; + text-align: center; +} + +.noResults > a { + color: #3498db; +} + +.loader-spinner { + position: absolute; + top: -50%; + left: 50%; + border: 5px solid #f3f3f3; + border-radius: 50%; + border-top: 5px solid #3498db; + width: 40px; + height: 40px; + margin: auto; + -webkit-animation: spin 1s linear infinite; /* Safari */ + animation: spin 1s linear infinite; + margin-top: 35px; + margin-bottom: -35px; + z-index: 2; +} + /* Safari */ +@-webkit-keyframes spin { + 0% { -webkit-transform: rotate(0deg); } + 100% { -webkit-transform: rotate(360deg); } +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +.loader { + display: none; + position: relative; + height: 70px; + width: 100%; +} + +.kiwixfooter { + display: flex; + width: 100%; + justify-content: center; + text-align: center; + font-size: 1.6rem; + height: 30px; +} + +.kiwixfooter > a { + width: auto; +} + +@media screen and (max-width: 1100px) { + + .kiwixHomeBody { + padding: 20px 10vw; + min-height: calc(100vh - 170px); + } + + .kiwixNav__filters { + grid-template-columns: repeat(4, 1fr); + } +} + +@media screen and (max-width: 590px) { + + .kiwixNav { + height: 257px; + } + + .kiwixHomeBody { + min-height: calc(100vh - 287px); + } + + .kiwixSearch { + margin-top: 11px; + } + + .searchButton { + margin: 19px 0; + width: 229px; + } + + .kiwixNav__filters { + grid-template-columns: 1fr; + } +} + +@media screen and (max-width: 340px) { + .kiwixHomeBody { + padding: 20px 5vw; + } +} \ No newline at end of file diff --git a/static/skin/index.js b/static/skin/index.js index dc1d12e88..4febd9540 100644 --- a/static/skin/index.js +++ b/static/skin/index.js @@ -8,6 +8,7 @@ const bookOrderMap = new Map(); const filterCookieName = 'filters'; const oneDayDelta = 86400000; + let loader; let footer; let fadeOutDiv; let iso; @@ -41,12 +42,23 @@ return result; } + const humanFriendlySize = (fileSize) => { + if (fileSize === 0) { + return ''; + } + const units = ['bytes', 'kB', 'MB', 'GB', 'TB']; + let quotient = Math.floor(Math.log10(fileSize) / 3); + quotient = quotient < units.length ? quotient : units.length - 1; + fileSize /= (1000 ** quotient); + return `${+fileSize.toFixed(2)} ${units[quotient]}`; + }; + function htmlEncode(str) { return str.replace(/[\u00A0-\u9999<>\&]/gim, (i) => `&#${i.charCodeAt(0)};`); } function viewPortToCount(){ - return Math.floor(window.innerHeight/100 + 1)*(window.innerWidth>1000 ? 3 : 2); + return Math.floor(window.innerHeight/300 + 1)*(window.innerWidth>1000 ? 4 : 3); } function getInnerHtml(node, query) { @@ -59,22 +71,38 @@ const description = getInnerHtml(book, 'summary'); const id = getInnerHtml(book, 'id'); const iconUrl = getInnerHtml(book, 'icon'); - const articleCount = getInnerHtml(book, 'articleCount'); - const mediaCount = getInnerHtml(book, 'mediaCount'); - - const linkTag = document.createElement('a'); - linkTag.setAttribute('class', 'book'); - linkTag.setAttribute('data-id', id); - linkTag.setAttribute('href', link); - if (sort) { - linkTag.setAttribute('data-idx', bookOrderMap.get(id)); + const language = getInnerHtml(book, 'language'); + const tags = getInnerHtml(book, 'tags'); + let tagHtml = tags.split(';').filter(tag => {return !(tag.split(':')[0].startsWith('_'))}) + .map((tag) => {return tag.charAt(0).toUpperCase() + tag.slice(1)}) + .join(' | ').replace(/_/g, ' '); + let downloadLink; + let zimSize = 0; + try { + const downloadBookLink = book.querySelector('link[type="application/x-zim"]') + zimSize = parseInt(downloadBookLink.getAttribute('length')); + downloadLink = downloadBookLink.getAttribute('href').split('.meta4')[0]; + } catch { + downloadLink = ''; } - linkTag.innerHTML = `
-
${title}
+ humanFriendlyZimSize = humanFriendlySize(zimSize); + + const divTag = document.createElement('div'); + divTag.setAttribute('class', 'book'); + divTag.setAttribute('data-id', id); + if (sort) { + divTag.setAttribute('data-idx', bookOrderMap.get(id)); + } + divTag.innerHTML = `
+
+
${title}
+ ${humanFriendlyZimSize ? `
${humanFriendlyZimSize}
`: ''} +
${description}
-
${articleCount} articles, ${mediaCount} medias
-
`; - return linkTag; +
${language.substr(0, 2).toUpperCase()}
+
${tagHtml}
+
`; + return divTag; } function toggleFooter(show=false) { @@ -87,7 +115,6 @@ } async function loadBooks() { - const loader = document.querySelector('.loader'); loader.style.display = 'block'; return await fetch(queryUrlBuilder()).then(async (resp) => { const data = new window.DOMParser().parseFromString(await resp.text(), 'application/xml'); @@ -96,12 +123,23 @@ bookOrderMap.set(getInnerHtml(book, 'id'), idx); }); incrementalLoadingParams.start += books.length; - if (parseInt(data.querySelector('totalResults').innerHTML) === bookOrderMap.size) { + const results = parseInt(data.querySelector('totalResults').innerHTML) + if (results === bookOrderMap.size) { incrementalLoadingParams.count = 0; toggleFooter(true); } else { toggleFooter(); } + const kiwixResultText = document.querySelector('.kiwixHomeBody__results') + if (results) { + let resultText = `${results} books`; + if (results === 1) { + resultText = `${results} book`; + } + kiwixResultText.innerHTML = resultText; + } else { + kiwixResultText.innerHTML = ``; + } loader.style.display = 'none'; return books; }); @@ -115,28 +153,42 @@ } function checkAndInjectEmptyMessage() { + const kiwixHomeBody = document.querySelector('.kiwixHomeBody'); if (!bookOrderMap.size) { if (!noResultInjected) { noResultInjected = true; - iso.remove(document.getElementsByClassName('book__list')[0].getElementsByTagName('a')); + iso.remove(document.getElementsByClassName('book__list')[0].getElementsByTagName('div')); iso.layout(); - const spanTag = document.createElement('span'); - spanTag.setAttribute('class', 'noResults'); - spanTag.innerHTML = `No result. Would you like to reset filter?`; - document.querySelector('body').append(spanTag); - spanTag.getElementsByTagName('a')[0].onclick = (event) => { - event.preventDefault(); - window.history.pushState({}, null, `${window.location.href.split('?')[0]}?lang=`); - setCookie(filterCookieName, 'lang='); - resetAndFilter(); - filterTypes.forEach(key => {document.getElementsByName(key)[0].value = params.get(key) || ''}); - }; + setTimeout(() => { + const divTag = document.createElement('div'); + divTag.setAttribute('class', 'noResults'); + divTag.innerHTML = `No result. Would you like to reset filter?`; + kiwixHomeBody.append(divTag); + kiwixHomeBody.setAttribute('style', 'display: flex; justify-content: center; align-items: center'); + divTag.getElementsByTagName('a')[0].onclick = (event) => { + event.preventDefault(); + window.history.pushState({}, null, `${window.location.href.split('?')[0]}?lang=`); + setCookie(filterCookieName, 'lang='); + resetAndFilter(); + document.querySelectorAll('.filter').forEach(filter => { + filter.value = params.get(filter.name) || ''; + if (filter.value) { + filter.style = 'background-color: #858585; color: #fff'; + } else { + filter.style = 'background-color: #ffffff; color: black'; + } + }) + }; + loader.setAttribute('style', 'position: absolute; top: 50%'); + }, 300); } return true; } else if (noResultInjected) { noResultInjected = false; document.getElementsByClassName('noResults')[0].remove(); + kiwixHomeBody.removeAttribute('style'); } + loader.removeAttribute('style'); return false; } @@ -185,12 +237,19 @@ window.history.pushState({}, null, `${window.location.href.split('?')[0]}?${params.toString()}`); setCookie(filterCookieName, params.toString()); } + document.querySelectorAll('.filter').forEach(filter => { + if (filter.value) { + filter.style = 'background-color: #858585; color: #fff'; + } else { + filter.style = 'background-color: #ffffff; color: black'; + } + }); await loadAndDisplayBooks(true); } window.addEventListener('popstate', async () => { await resetAndFilter(); - filterTypes.forEach(key => {document.getElementsByName(key)[0].value = params.get(key) || ''}); + document.querySelectorAll('.filter').forEach(filter => {filter.value = params.get(filter.name) || ''}); }); async function loadSubset() { @@ -223,16 +282,21 @@ return index ? parseInt(index) : Infinity; } }, - sortBy: 'weight' + sortBy: 'weight', + layoutMode: 'cellsByRow', + cellsByRow: { + columnWidth: '.book', + rowHeight: '.book' + } }); footer = document.getElementById('kiwixfooter'); fadeOutDiv = document.getElementById('fadeOut'); + loader = document.querySelector('.loader'); await loadAndDisplayBooks(); await loadAndDisplayOptions('#languageFilter', langList); await loadAndDisplayOptions('#categoryFilter', categoryList); - filterTypes.forEach((filter) => { - const filterTag = document.getElementsByName(filter)[0]; - filterTag.addEventListener('change', () => {resetAndFilter(filterTag.name, filterTag.value)}); + document.querySelectorAll('.filter').forEach(filter => { + filter.addEventListener('change', () => {resetAndFilter(filter.name, filter.value)}); }); if (filters) { window.history.pushState({}, null, `${window.location.href.split('?')[0]}?${params.toString()}`); @@ -245,6 +309,13 @@ langFilter.value = browserLang.length === 3 ? browserLang : iso6391To3[browserLang]; langFilter.dispatchEvent(new Event('change')); } + document.querySelectorAll('.filter').forEach(filter => { + if (filter.value) { + filter.style = 'background-color: #858585; color: #fff'; + } else { + filter.style = 'background-color: #ffffff; color: black'; + } + }); setCookie(filterCookieName, params.toString()); } })(); diff --git a/static/skin/isotope.pkgd.min.js b/static/skin/isotope.pkgd.min.js index 7ca671cbe..5461054f2 100644 --- a/static/skin/isotope.pkgd.min.js +++ b/static/skin/isotope.pkgd.min.js @@ -9,4 +9,70 @@ */ !function(t,e){"function"==typeof define&&define.amd?define("jquery-bridget/jquery-bridget",["jquery"],function(i){return e(t,i)}):"object"==typeof module&&module.exports?module.exports=e(t,require("jquery")):t.jQueryBridget=e(t,t.jQuery)}(window,function(t,e){"use strict";function i(i,s,a){function u(t,e,o){var n,s="$()."+i+'("'+e+'")';return t.each(function(t,u){var h=a.data(u,i);if(!h)return void r(i+" not initialized. Cannot call methods, i.e. "+s);var d=h[e];if(!d||"_"==e.charAt(0))return void r(s+" is not a valid method");var l=d.apply(h,o);n=void 0===n?l:n}),void 0!==n?n:t}function h(t,e){t.each(function(t,o){var n=a.data(o,i);n?(n.option(e),n._init()):(n=new s(o,e),a.data(o,i,n))})}a=a||e||t.jQuery,a&&(s.prototype.option||(s.prototype.option=function(t){a.isPlainObject(t)&&(this.options=a.extend(!0,this.options,t))}),a.fn[i]=function(t){if("string"==typeof t){var e=n.call(arguments,1);return u(this,t,e)}return h(this,t),this},o(a))}function o(t){!t||t&&t.bridget||(t.bridget=i)}var n=Array.prototype.slice,s=t.console,r="undefined"==typeof s?function(){}:function(t){s.error(t)};return o(e||t.jQuery),i}),function(t,e){"function"==typeof define&&define.amd?define("ev-emitter/ev-emitter",e):"object"==typeof module&&module.exports?module.exports=e():t.EvEmitter=e()}("undefined"!=typeof window?window:this,function(){function t(){}var e=t.prototype;return e.on=function(t,e){if(t&&e){var i=this._events=this._events||{},o=i[t]=i[t]||[];return o.indexOf(e)==-1&&o.push(e),this}},e.once=function(t,e){if(t&&e){this.on(t,e);var i=this._onceEvents=this._onceEvents||{},o=i[t]=i[t]||{};return o[e]=!0,this}},e.off=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){var o=i.indexOf(e);return o!=-1&&i.splice(o,1),this}},e.emitEvent=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){i=i.slice(0),e=e||[];for(var o=this._onceEvents&&this._onceEvents[t],n=0;n