diff --git a/app/Controllers/PageFavorites.php b/app/Controllers/PageFavorites.php new file mode 100644 index 0000000..2b57451 --- /dev/null +++ b/app/Controllers/PageFavorites.php @@ -0,0 +1,20 @@ + 'lc_resource', + 'post__in' => explode(',', $_COOKIE['favorites']), + 'orderby' => 'title', + 'posts_per_page' => -1, + 'order' => 'asc', + 'lang' => '', + ]); + } +} diff --git a/app/Controllers/Partials/Resource.php b/app/Controllers/Partials/Resource.php index 0166054..ed3e96e 100644 --- a/app/Controllers/Partials/Resource.php +++ b/app/Controllers/Partials/Resource.php @@ -102,6 +102,18 @@ public static function getPublisher($show_link = false) return false; } + public static function getAuthors() + { + global $post; + if ($post->post_type == 'lc_resource') { + $authors = get_post_meta($post->ID, 'lc_resource_authors', true); + if ($authors) { + return $authors; + } + } + return false; + } + public static function getLanguage($format = 'slug') { global $post; @@ -128,7 +140,7 @@ public static function getFormat() return false; } - public static function getFormatSlug() + public static function getFormatIcon() { global $post; @@ -139,11 +151,12 @@ public static function getFormatSlug() switch ($format->slug) { case 'academic-paper': case 'thesis': - return 'academic-paper'; + return 'academic'; break; - case 'article': - case 'document': case 'blog-post': + return 'blog'; + break; + case 'article': case 'journal-article': case 'magazine-article': case 'newspaper-article': @@ -162,10 +175,9 @@ public static function getFormatSlug() return 'case-study'; break; case 'curriculum': - return 'educational-curriculum'; + return 'curriculum'; break; case 'film': - case 'interview': case 'video': return 'video'; break; @@ -180,11 +192,14 @@ public static function getFormatSlug() break; case 'software': case 'toolkit': - case 'template': return 'toolkit'; break; + case 'template': + return 'template'; + break; + case 'document': default: - return 'article'; + return 'document'; } } } @@ -276,4 +291,14 @@ public static function getOverflowTopics() return false; } + + public static function isFavorited() + { + global $post; + $favorites = explode(',', $_COOKIE['favorites']); + if (in_array($post->ID, $favorites)) { + return true; + } + return false; + } } diff --git a/app/ajax.php b/app/ajax.php new file mode 100644 index 0000000..2ad5ad7 --- /dev/null +++ b/app/ajax.php @@ -0,0 +1,31 @@ + admin_url('admin-ajax.php'), + 'coop_library_nonce' => wp_create_nonce('coop-library-framework-nonce') + ]); if (is_single() && comments_open() && get_option('thread_comments')) { wp_enqueue_script('comment-reply'); } - wp_enqueue_style('sage/main.css', asset_path('styles/main.css'), false, null); + wp_enqueue_style('coop-library/main.css', asset_path('styles/main.css'), false, null); }, 100); /** @@ -85,6 +89,12 @@ load_theme_textdomain('coop-library', get_template_directory() . '/lang'); }, 20); +/** + * Ajax hooks + */ +add_action('wp_ajax_update_favorites', 'App\\update_favorites'); +add_action('wp_ajax_nopriv_update_favorites', 'App\\update_favorites'); + /** * Register sidebars */ diff --git a/package-lock.json b/package-lock.json index 2664ffe..5b74323 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1509,6 +1509,37 @@ "any-observable": "^0.3.0" } }, + "@tannin/compile": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tannin/compile/-/compile-1.0.4.tgz", + "integrity": "sha512-RVfzknkrDTgtLhFSEaoGGIjpQsOzS75lzsf6v3IHP+sThoJ4qL2iQDopGo36OYeb6EzJMSKVGhsrTvqE/a1IpQ==", + "dev": true, + "requires": { + "@tannin/evaluate": "^1.1.2", + "@tannin/postfix": "^1.0.3" + } + }, + "@tannin/evaluate": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tannin/evaluate/-/evaluate-1.1.2.tgz", + "integrity": "sha512-ME/CNm9zpCqJwTZa1WUpWp51lY5IpJcsFgsNouPsgApI5D1Vr/sR/zPAQEyS8ruk45YUoFqP82VIGIhQFrhYKQ==", + "dev": true + }, + "@tannin/plural-forms": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tannin/plural-forms/-/plural-forms-1.0.4.tgz", + "integrity": "sha512-NSlGvF6q2OLXWWDLgzZRM2+L1uLBxl5wgxfmi9ZZUpZjlg+Z7Ss/QbAJpAJGxgvERuA1jhqpAuTvr/2fNbH+Ag==", + "dev": true, + "requires": { + "@tannin/compile": "^1.0.4" + } + }, + "@tannin/postfix": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tannin/postfix/-/postfix-1.0.3.tgz", + "integrity": "sha512-80uoGtphTH3vDZlJgE2xJh3qBWMAlCXq8wN8WLOxHJjms0A38vkbXOXiYMIabgnIJVc1vCcZVQa2pHt+X3AF5Q==", + "dev": true + }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", @@ -2818,6 +2849,43 @@ } } }, + "@wordpress/i18n": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-3.9.0.tgz", + "integrity": "sha512-ACpLPvdzAosAPqSLUaYQSX7fB5yAV5dFy8Y37FWLsZrv4NhUQ+rfDLdrXrCWm19LEZ5nTFfZUT0TIbYKekqIug==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.3", + "gettext-parser": "^1.3.1", + "lodash": "^4.17.15", + "memize": "^1.0.5", + "sprintf-js": "^1.1.1", + "tannin": "^1.1.0" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.8.4.tgz", + "integrity": "sha512-neAp3zt80trRVBI1x0azq6c57aNBqYZH8KhMm3TaB7wEI5Q4A2SHfBHE8w9gOhI/lrqxtEbXZgQIrHP+wvSGwQ==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.2" + } + }, + "regenerator-runtime": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", + "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==", + "dev": true + }, + "sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true + } + } + }, "@wordpress/warning": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@wordpress/warning/-/warning-1.0.0.tgz", @@ -5235,6 +5303,15 @@ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", "dev": true }, + "cookies.js": { + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/cookies.js/-/cookies.js-2.1.15.tgz", + "integrity": "sha1-bazOrqCCcZqN1a6O5BqnGrrVFqo=", + "requires": { + "es-is": "3.3.7", + "es-object-assign": "4.1.4" + } + }, "copy-concurrently": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", @@ -6190,6 +6267,15 @@ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", "dev": true }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "dev": true, + "requires": { + "iconv-lite": "~0.4.13" + } + }, "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -6360,6 +6446,25 @@ "string.prototype.trimright": "^2.1.0" } }, + "es-hasown": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/es-hasown/-/es-hasown-0.1.0.tgz", + "integrity": "sha1-ejSkgw1aqASsk0vG2p0Z3rDiCFI=" + }, + "es-is": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/es-is/-/es-is-3.3.7.tgz", + "integrity": "sha1-uS6LetZgzKXtGp9kUwkwJ4tV6yw=", + "requires": { + "es-hasown": "0.1.0", + "es-tostring": "0.1.0" + } + }, + "es-object-assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/es-object-assign/-/es-object-assign-4.1.4.tgz", + "integrity": "sha1-t72heTrMmAyfljBc8nKDtRg/C4s=" + }, "es-to-primitive": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", @@ -6371,6 +6476,11 @@ "is-symbol": "^1.0.2" } }, + "es-tostring": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/es-tostring/-/es-tostring-0.1.0.tgz", + "integrity": "sha1-pGrmIq+QwZGrE/QmuCWZ+FRZdyI=" + }, "es6-templates": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/es6-templates/-/es6-templates-0.2.3.tgz", @@ -8306,6 +8416,16 @@ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", "dev": true }, + "gettext-parser": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/gettext-parser/-/gettext-parser-1.4.0.tgz", + "integrity": "sha512-sedZYLHlHeBop/gZ1jdg59hlUEcpcZJofLq2JFwJT1zTqAU3l2wFv6IsuwFHGqbiT9DWzMUW4/em2+hspnmMMA==", + "dev": true, + "requires": { + "encoding": "^0.1.12", + "safe-buffer": "^5.1.1" + } + }, "git-raw-commits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.3.tgz", @@ -11401,6 +11521,12 @@ } } }, + "memize": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/memize/-/memize-1.0.5.tgz", + "integrity": "sha512-Dm8Jhb5kiC4+ynYsVR4QDXKt+o2dfqGuY4hE2x+XlXZkdndlT80bJxfcMv5QGp/FCy6MhG7f5ElpmKPFKOSEpg==", + "dev": true + }, "memory-fs": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", @@ -16681,6 +16807,15 @@ } } }, + "tannin": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tannin/-/tannin-1.1.1.tgz", + "integrity": "sha512-e6qNtx1XZnvC3psLnvboUekSY4phq77YDnDDhE/nqghpTVz2MbrsrN0M1dysof/WfkcSvnRVZyR8NYu5KcFtQw==", + "dev": true, + "requires": { + "@tannin/plural-forms": "^1.0.4" + } + }, "tapable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", diff --git a/package.json b/package.json index fda3d45..43b721d 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,8 @@ "node": ">= 10.0.0" }, "dependencies": { - "@platform-coop-toolkit/pinecone": "^1.0.0-alpha.10" + "@platform-coop-toolkit/pinecone": "^1.0.0-alpha.10", + "cookies.js": "^2.1.15" }, "devDependencies": { "@babel/plugin-syntax-dynamic-import": "^7.8", @@ -33,6 +34,7 @@ "@wordpress/babel-preset-default": "^4.10.0", "@wordpress/browserslist-config": "^2.6.0", "@wordpress/dependency-extraction-webpack-plugin": "^2.2.0", + "@wordpress/i18n": "^3.9.0", "babel-eslint": "^10.0.3", "browser-sync": "^2.26.7", "browser-sync-webpack-plugin": "^2.0.1", diff --git a/resources/assets/scripts/main.js b/resources/assets/scripts/main.js index 14d05f0..c6f2315 100644 --- a/resources/assets/scripts/main.js +++ b/resources/assets/scripts/main.js @@ -5,6 +5,7 @@ import 'wicg-inert'; import Router from './util/Router'; import {ready} from './util/Ready'; import common from './routes/common'; +import pageFavorites from './routes/favorites'; import home from './routes/home'; import archive from './routes/archive'; import single from './routes/single'; @@ -19,6 +20,8 @@ const routes = new Router({ archive, // Single resource single, + // Favorites page + pageFavorites, }); // Load Events diff --git a/resources/assets/scripts/routes/archive.js b/resources/assets/scripts/routes/archive.js index 8b8842e..f61258a 100644 --- a/resources/assets/scripts/routes/archive.js +++ b/resources/assets/scripts/routes/archive.js @@ -3,14 +3,6 @@ import Pinecone from '@platform-coop-toolkit/pinecone'; export default { init() { // JavaScript to be fired on the Archive page - const cards = document.querySelectorAll( '.card' ); - - if ( cards ) { - Array.prototype.forEach.call( cards, card => { - new Pinecone.Card( card ); - } ); - } - const filterContainer = document.querySelector( '.filters' ); const showFilters = document.querySelector( '#show-filters' ); const hideFilters = document.querySelector( '#hide-filters' ); diff --git a/resources/assets/scripts/routes/common.js b/resources/assets/scripts/routes/common.js index 933090a..8d8c203 100644 --- a/resources/assets/scripts/routes/common.js +++ b/resources/assets/scripts/routes/common.js @@ -3,15 +3,24 @@ import Pinecone from '@platform-coop-toolkit/pinecone'; export default { init() { // JavaScript to be fired on all pages - const toggle = document.querySelector( '.menu-toggle' ); const menu = document.querySelector( '.menu' ); - new Pinecone.Menu(toggle, menu); + const toggle = document.querySelector( '.menu-toggle' ); + new Pinecone.Menu(menu, toggle); const searchToggle = document.querySelector( '.search-toggle' ); if ( searchToggle ) { new Pinecone.SearchToggle( searchToggle, searchToggle.nextElementSibling ); } + const cards = document.querySelectorAll( '.card' ); + + if ( cards ) { + Array.prototype.forEach.call( cards, card => { + new Pinecone.Card( card, { cardLinkSelector: '.card__link' } ); // TODO: Remove the cardLinkSelector confuration. + } ); + } + + new Pinecone.Notification(); /* TODO: Resolve icon issues const icons = document.querySelectorAll( 'svg' ); diff --git a/resources/assets/scripts/routes/favorites.js b/resources/assets/scripts/routes/favorites.js new file mode 100644 index 0000000..07c2a01 --- /dev/null +++ b/resources/assets/scripts/routes/favorites.js @@ -0,0 +1,83 @@ +/* global CoopLibrary */ + +import addNotification from '../util/addNotification'; +import Pinecone from '@platform-coop-toolkit/pinecone'; +import Cookies from 'cookies.js'; +import { __ } from '@wordpress/i18n'; + +export default { + init() { + // JavaScript to be fired on the favorites page + if (!navigator.cookieEnabled) { + addNotification(__('Favorites not supported', 'coop-library'), __('Your favorites are stored in your browser\'s cookies. To add favorites, please enable cookies for this website.', 'coop-library'), 'error'); + } else { + const removeAllButton = document.getElementById('remove-all'); + const removeButtons = document.querySelectorAll('.remove-favorite'); + if (removeAllButton && removeButtons) { + new Pinecone.Dialog( removeAllButton, { + title: __('Remove favorites?', 'coop-library'), + question: __('Are you sure you want to remove all resources from your favorites?', 'coop-library'), + confirm: __('Yes, remove', 'coop-library'), + dismiss: __('No, don’t remove', 'coop-library'), + callback: function callback() { + let favorites = Cookies.get('favorites'); + fetch( CoopLibrary.ajaxurl, { + method: 'POST', + credentials: 'same-origin', + headers: new Headers( {'Content-Type': 'application/x-www-form-urlencoded'} ), + body: `action=update_favorites&coop_library_nonce=${encodeURIComponent( CoopLibrary.coop_library_nonce )}&post_id=${encodeURIComponent( favorites )}&operation=decrement`, + } ) + .then( () => { + Cookies.set('favorites', ''); + const resourceList = document.getElementById('favorites'); + removeAllButton.parentNode.removeChild(removeAllButton); + resourceList.parentNode.removeChild(resourceList); + addNotification(__('Favorites removed', 'coop-library'), __('The resources have been removed from your favorites.', 'coop-library'), 'success'); + }) + .catch( function() { + addNotification(__('Favorites not removed', 'coop-library'), __('The resources could not be removed from your favorites.', 'coop-library'), 'error'); + }); + }, + }); + } + + if (removeButtons) { + const length = removeButtons.length; + Array.prototype.forEach.call(removeButtons, btn => { + new Pinecone.Dialog( btn, { + title: __('Remove resource?', 'coop-library'), + question: __('Are you sure you want to remove this resource from your favorites?', 'coop-library'), + confirm: __('Yes, remove', 'coop-library'), + dismiss: __('No, don’t remove', 'coop-library'), + callback: function callback() { + const id = btn.dataset.id; + let favorites = Cookies.get('favorites'); + favorites = favorites ? favorites.split(',') : []; + favorites = favorites.filter(item => item !== id); + fetch( CoopLibrary.ajaxurl, { + method: 'POST', + credentials: 'same-origin', + headers: new Headers( {'Content-Type': 'application/x-www-form-urlencoded'} ), + body: `action=update_favorites&coop_library_nonce=${encodeURIComponent( CoopLibrary.coop_library_nonce )}&post_id=${encodeURIComponent( id )}&operation=decrement`, + } ) + .then( () => { + Cookies.set('favorites', favorites.toString()); + btn.parentNode.parentNode.removeChild(btn.parentNode); + if (length === 1) { + removeAllButton.parentNode.removeChild(removeAllButton); + } + addNotification(__('Favorite removed', 'coop-library'), __('The resource has been removed from your favorites.', 'coop-library'), 'success'); + }) + .catch( function() { + addNotification(__('Favorite not removed', 'coop-library'), __('The resource could not be removed from your favorites.', 'coop-library'), 'error'); + }); + }, + } ); + }); + } + } + }, + finalize() { + // JavaScript to be fired on the home page, after the init JS + }, +}; diff --git a/resources/assets/scripts/routes/home.js b/resources/assets/scripts/routes/home.js index c288886..c37d80b 100644 --- a/resources/assets/scripts/routes/home.js +++ b/resources/assets/scripts/routes/home.js @@ -1,15 +1,6 @@ -import Pinecone from '@platform-coop-toolkit/pinecone'; - export default { init() { // JavaScript to be fired on the home page - const cards = document.querySelectorAll( '.card' ); - - if ( cards ) { - Array.prototype.forEach.call( cards, card => { - new Pinecone.Card( card ); - } ); - } }, finalize() { // JavaScript to be fired on the home page, after the init JS diff --git a/resources/assets/scripts/routes/single.js b/resources/assets/scripts/routes/single.js index 754c803..bdc8318 100644 --- a/resources/assets/scripts/routes/single.js +++ b/resources/assets/scripts/routes/single.js @@ -1,8 +1,56 @@ +/* global CoopLibrary */ + +import addNotification from '../util/addNotification'; import Pinecone from '@platform-coop-toolkit/pinecone'; +import Cookies from 'cookies.js'; +import { __ } from '@wordpress/i18n'; export default { init() { // JavaScript to be fired on a single resource page + const favorite = document.getElementById('favorite'); + const id = favorite.dataset.id; + let favorites = Cookies.get('favorites'); + let operation; + favorites = favorites ? favorites.split(',') : []; + if (favorites.includes(id)) { + favorite.dataset.favorite = true; + } + + favorite.onclick = () => { + const state = 'true' === favorite.dataset.favorite || false; + if (!state) { + favorites.push(id); + operation = 'increment'; + } else { + favorites = favorites.filter(item => item !== id); + operation = 'decrement'; + } + + fetch( CoopLibrary.ajaxurl, { + method: 'POST', + credentials: 'same-origin', + headers: new Headers( {'Content-Type': 'application/x-www-form-urlencoded'} ), + body: `action=update_favorites&coop_library_nonce=${encodeURIComponent( CoopLibrary.coop_library_nonce )}&post_id=${encodeURIComponent( id )}&operation=${encodeURIComponent( operation )}`, + } ) + .then( () => { + Cookies.set('favorites', favorites.toString()); + favorite.dataset.favorite = !state; + if (operation === 'decrement') { + addNotification(__('Favorite removed', 'coop-library'), __('The resource has been removed from your favorites.', 'coop-library'), 'success'); + } else { + addNotification(__('Favorite added', 'coop-library'), __('The resource has been added to your favorites.', 'coop-library'), 'success'); + } + }) + .catch( function() { + if (operation === 'decrement') { + addNotification(__('Favorite not removed', 'coop-library'), __('The resource could not be removed from your favorites.', 'coop-library'), 'error'); + } else { + addNotification(__('Favorite not added', 'coop-library'), __('The resource could not be added to your favorites.', 'coop-library'), 'error'); + } + }); + } + const share = document.querySelector( '.share' ); if ( share ) { new Pinecone.MenuButton( share ); diff --git a/resources/assets/scripts/util/addNotification.js b/resources/assets/scripts/util/addNotification.js new file mode 100644 index 0000000..dfeb913 --- /dev/null +++ b/resources/assets/scripts/util/addNotification.js @@ -0,0 +1,41 @@ +import { __ } from '@wordpress/i18n'; + +/** + * Add a notification. + * + * @param {String} title + * @param {String} content + * @param {String} type + */ +export default (title, content, type) => { + const pageHeader = document.querySelector('.page-header'); + let icon; + switch(type) { + case 'success': + icon = ''; + break; + case 'warning': + icon = ''; + break; + case 'error': + icon = ''; + break; + case 'info': + default: + icon = ''; + } + + const alert = ` + + `; + + if (pageHeader.nextElementSibling.classList.contains('notification')) { + pageHeader.nextElementSibling.parentNode.removeChild(pageHeader.nextElementSibling); + } + pageHeader.insertAdjacentHTML('afterend', alert); +}; diff --git a/resources/assets/styles/components/_buttons.scss b/resources/assets/styles/components/_buttons.scss index e69de29..f3798f8 100644 --- a/resources/assets/styles/components/_buttons.scss +++ b/resources/assets/styles/components/_buttons.scss @@ -0,0 +1,17 @@ +.no-js #favorite { + display: none; +} + +[data-favorite="true"] { + .add, + .icon--favorite { + display: none; + } +} + +[data-favorite="false"] { + .remove, + .icon--favorite-filled { + display: none; + } +} diff --git a/resources/assets/styles/layouts/_pages.scss b/resources/assets/styles/layouts/_pages.scss index 507f938..1baf81d 100644 --- a/resources/assets/styles/layouts/_pages.scss +++ b/resources/assets/styles/layouts/_pages.scss @@ -16,3 +16,112 @@ margin-top: rem(48); } } + +// TODO: Remove after Pinecone 1.0.0-alpha.11 is merged. + +main { + position: relative; +} + +.notification { + margin-bottom: $gutter; + position: sticky; + top: $gutter; + z-index: 1; +} + +.button--borderless.button--destructive { + --color: var(--red-500); + --outline-color: var(--red-500); + --hover-color: var(--dark-mint-500); + --focus-color: var(--red-500); + --active-color: var(--white); + --active-background-color: var(--red-500); +} + +.align-right { + text-align: right; +} + +.align-right .button--borderless { + display: inline-block; + margin: rem(6) rem(-8) rem(6) rem(24); +} + +.page.page-template-page-favorites .cards .card__wrapper { + display: grid; + grid-template-columns: 100%; + grid-template-rows: 1fr 3rem; + gap: rem(20); +} + +@include breakpoint-up(sm) { + .page.page-template-page-favorites { + .cards { + display: flex; + flex-direction: row; + flex-wrap: wrap; + + @supports (display: $grid) { + display: grid; + gap: rem(30); + grid-template-columns: 100%; + } + } + + .cards .card__wrapper { + margin-bottom: rem(30); + width: 100%; + + @supports (display: $grid) { + margin-bottom: 0; + } + } + + .card:nth-child(even) { + margin-left: 0; + } + } +} + +@include breakpoint-up(md) { + .page.page-template-page-favorites { + .cards { + @supports (display: $grid) { + grid-template-columns: repeat(2, 1fr); + } + } + + .cards .card__wrapper { + width: calc(50% - #{rem(30)} / 2); + + @supports (display: $grid) { + width: 100%; + } + } + + .card:nth-child(even) { + margin-left: rem(30); + + @supports (display: $grid) { + margin-left: 0; + } + } + + .cards .card__wrapper + .card__wrapper { + margin-top: 0; + } + } +} + +@include breakpoint-up(lg) { + .page.page-template-page-favorites main { + @include grid-column-span(8, 12, 3); + } +} + +@include breakpoint-up(xl) { + .page.page-template-page-favorites main { + @include grid-column-span(8, 16, 4); + } +} diff --git a/resources/functions.php b/resources/functions.php index ceab572..c0b5ba5 100644 --- a/resources/functions.php +++ b/resources/functions.php @@ -67,7 +67,7 @@ 'File not found' ); } -}, ['helpers', 'setup', 'filters', 'admin', 'translation']); +}, ['helpers', 'setup', 'filters', 'admin', 'ajax', 'translation']); /** * Here's what's happening with these hooks: diff --git a/resources/views/index.blade.php b/resources/views/index.blade.php index 1319f2d..ffe1155 100644 --- a/resources/views/index.blade.php +++ b/resources/views/index.blade.php @@ -16,10 +16,14 @@
- {!! get_the_posts_pagination(['prev_text' => sprintf('‹ %s', __('previous resources', 'coop-library')), 'next_text' => sprintf(' %s ›', __('next resources', 'coop-library'))]) !!} + {{-- TODO: Replace this hack with a better implementation. --}} + {!! str_replace(['page-numbers current', 'page-numbers'], ['page current', 'link link--pagination'], get_the_posts_pagination([ + 'prev_text' => sprintf('‹ %s', __('previous resources', 'coop-library')), + 'next_text' => sprintf(' %s ›', __('next resources', 'coop-library')) + ])) !!} @endsection diff --git a/resources/views/page-favorites.blade.php b/resources/views/page-favorites.blade.php new file mode 100644 index 0000000..f4cd92b --- /dev/null +++ b/resources/views/page-favorites.blade.php @@ -0,0 +1,11 @@ +{{-- + Template Name: Favorites +--}} +@extends('layouts.app') + +@section('content') + @while(have_posts()) @php the_post() @endphp + @include('partials.page-header') + @include('partials.content-page-favorites') + @endwhile +@endsection diff --git a/resources/views/partials/content-front-page.blade.php b/resources/views/partials/content-front-page.blade.php index 591ae5a..f6d8143 100644 --- a/resources/views/partials/content-front-page.blade.php +++ b/resources/views/partials/content-front-page.blade.php @@ -14,7 +14,7 @@ @endforeach -
{{ __('Browse all resources', 'coop-library') }}
+

{{ __('Browse all resources', 'coop-library') }}

{{ __('My feed', 'coop-library') }}

@@ -24,7 +24,7 @@ @if($most_viewed->have_posts()) @endif diff --git a/resources/views/partials/content-lc_resource.blade.php b/resources/views/partials/content-lc_resource.blade.php index ce6a784..5ecd17c 100644 --- a/resources/views/partials/content-lc_resource.blade.php +++ b/resources/views/partials/content-lc_resource.blade.php @@ -1,28 +1,52 @@ -
  • +
    - @svg(Archive::getFormatSlug(), 'icon--' . Archive::getFormatSlug(), ['focusable' => 'false', 'aria-hidden' => 'true']) {{ __('resource format', 'coop-library') }}: {{ Archive::getFormat() }} - @if($current_language !== Archive::getLanguage()) - · - {{ $languages[Archive::getLanguage()] }} +

    {!! Archive::getShortTitle() !!}

    + @if(Archive::getAuthors()) + @endif -

    {!! Archive::getShortTitle() !!}

    - @if(Archive::getPublisher()) - - @endif - @if(Archive::getRegion()) -

    @svg('location', 'icon--location', ['focusable' => 'false', 'aria-hidden' => 'true']) {{ Archive::getRegion() }}

    - @endif + @if(Archive::getTopics()) -
    -
      - @foreach(Archive::getTopics(2) as $topic) -
    • Topic: {!! $topic['name'] !!}
    • - @endforeach -
    +
    + @foreach(Archive::getTopics(2) as $topic) +
    topic: {!! $topic['name'] !!}
    + @endforeach @if(Archive::getOverflowTopics()) -

    {{ sprintf(__('+%d more', 'coop-library'), Archive::getOverflowTopics()), }} + {{ sprintf(__('+%d more', 'coop-library'), Archive::getOverflowTopics()), }} @endif

    @endif -
  • + @if(Archive::isFavorited()) +
    + @svg('favorite-filled', 'icon--favorite-filled', ['focusable' => 'false', 'aria-hidden' => 'true']) + {{ __('Favorited', 'coop-library') }} +
    + @endif + diff --git a/resources/views/partials/content-page-favorites.blade.php b/resources/views/partials/content-page-favorites.blade.php new file mode 100644 index 0000000..0909e74 --- /dev/null +++ b/resources/views/partials/content-page-favorites.blade.php @@ -0,0 +1,13 @@ +@if($favorites->have_posts()) +
    +
    + +
    +@endif diff --git a/resources/views/partials/content-single-lc_resource.blade.php b/resources/views/partials/content-single-lc_resource.blade.php index d569ec1..1c5bd49 100644 --- a/resources/views/partials/content-single-lc_resource.blade.php +++ b/resources/views/partials/content-single-lc_resource.blade.php @@ -1,7 +1,7 @@
    @endif
    - {{-- TODO: Implement favorites. --}} +