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 = `
+
+
+
${icon} ${title}
+
${content}
+
+ `;
+
+ 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 @@
@while (have_posts()) @php the_post() @endphp
- @include('partials.content-'.get_post_type())
+ - @include('partials.content-'.get_post_type())
@endwhile
- {!! 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 @@
@svg(str_replace('lc_', '', $slug), 'icon--' . str_replace('lc_', '', $slug), ['focusable' => 'false', 'aria-hidden' => 'true']) {{ $label }}
@endforeach
-
+ {{ __('Browse all resources', 'coop-library') }}
{{ __('My feed', 'coop-library') }}
@@ -24,7 +24,7 @@
@if($most_viewed->have_posts())
@while ($most_viewed->have_posts()) @php $most_viewed->the_post() @endphp
- @include('partials.content-'.get_post_type())
+ - @include('partials.content-'.get_post_type())
@endwhile
@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()] }}
+
+ @if(Archive::getAuthors())
+
+ @svg('author', 'icon--author', ['focusable' => 'false', 'aria-hidden' => 'true'])
+ {{ sprintf(__('By %s', 'coop-library'), Archive::getAuthors()) }}
+
@endif
-
- @if(Archive::getPublisher())
- {{ sprintf(__('By %s', 'coop-library'), 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
-
+
@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())
+
+
+
+ @while ($favorites->have_posts()) @php $favorites->the_post() @endphp
+ -
+ @include('partials.content-'.get_post_type())
+
+
+ @endwhile
+
+
+@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. --}}
+