1
0
mirror of https://github.com/trambarhq/relaks-wordpress-example.git synced 2025-09-02 20:52:33 +02:00

Reworked routing so that WP permalinks arrangement is used (issue #13).

This commit is contained in:
Chung Leong
2019-01-26 19:59:33 +01:00
parent a2ed7d67d2
commit 7ee6acf316
16 changed files with 275 additions and 234 deletions

View File

@@ -25,13 +25,11 @@ server {
proxy_cache_min_uses 1;
proxy_cache_valid 200 301 302 120m;
proxy_cache_valid 404 1m;
proxy_hide_header Cache-Control;
proxy_ignore_headers Cache-Control Expires Set-Cookie;
add_header Access-Control-Allow-Origin *;
add_header Cache-Control "public,max-age=0";
add_header X-Cache-Date $upstream_http_date;
add_header X-Cache-Status $upstream_cache_status;
add_header Access-Control-Allow-Origin *;
}
}

View File

@@ -10,6 +10,7 @@ const HTML_TEMPLATE = `${__dirname}/client/index.html`;
async function generate(path, target) {
// retrieve cached JSON through Nginx
console.log(`Regenerating page: ${path}`);
let host = `http://${NGINX_HOST}`;
// create a fetch() that remembers the URLs used
let sourceURLs = [];

View File

@@ -31,7 +31,7 @@ if (typeof(window) === 'object') {
});
routeManager.addEventListener('beforechange', (evt) => {
let route = new Route(routeManager, dataSource);
evt.postponeDefault(route.setPageType(evt.params));
evt.postponeDefault(route.setParameters(evt));
});
routeManager.activate();
await routeManager.start();
@@ -57,7 +57,6 @@ if (typeof(window) === 'object') {
let mtime = await res.text();
if (mtime !== mtimeLast) {
if (mtimeLast) {
console.log('changed');
dataSource.invalidate();
}
mtimeLast = mtime;
@@ -84,7 +83,7 @@ if (typeof(window) === 'object') {
});
routeManager.addEventListener('beforechange', (evt) => {
let route = new Route(routeManager, dataSource);
evt.postponeDefault(route.setPageType(evt.params));
evt.postponeDefault(route.setParameters(evt));
});
routeManager.activate();
await routeManager.start(options.path);

View File

@@ -12,22 +12,16 @@ class ArchivePage extends AsyncComponent {
async renderAsync(meanwhile) {
let { wp, route } = this.props;
let { monthSlug, categorySlug } = route.params;
let month = Moment(monthSlug);
let { date } = route.params;
let month = Moment(`${date.year}-${date.month}`);
let props = {
route,
month,
};
meanwhile.show(<ArchivePageSync {...props} />);
let after = month.toISOString();
let before = month.clone().endOf('month').toISOString();
meanwhile.show(<ArchivePageSync {...props} />);
props.categories = await wp.fetchList('/wp/v2/categories/');
meanwhile.show(<ArchivePageSync {...props} />);
let url = `/wp/v2/posts/?after=${after}&before=${before}`;
if (categorySlug) {
let category = _.find(props.categories, { slug: categorySlug });
url = `/wp/v2/posts/?after=${after}&before=${before}&categories=${category.id}`;
}
props.posts = await wp.fetchList(url);
return <ArchivePageSync {...props} />;
}
@@ -37,23 +31,13 @@ class ArchivePageSync extends PureComponent {
static displayName = 'ArchivePageSync';
render() {
let { route, categories, posts, month } = this.props;
let { monthSlug, categorySlug } = route.params;
let { route, posts, month } = this.props;
let monthLabel = month.format('MMMM YYYY');
let monthURL = route.find([ monthSlug ]);
let trail = [ { label: 'Archive' } ];
if (categorySlug) {
let category = _.find(categories, { slug: categorySlug });
let categoryLabel = _.get(category, 'name', '');
trail.push({ label: monthLabel, url: monthURL });
trail.push({ label: categoryLabel });
} else {
trail.push({ label: monthLabel });
}
let trail = [ { label: 'Archive' }, { label: monthLabel } ];
return (
<div className="page">
<Breadcrumb trail={trail} />
<PostList route={route} posts={posts} month={month} categories={categories} minimum={100} />
<PostList route={route} posts={posts} minimum={100} />
</div>
);
}
@@ -67,7 +51,6 @@ if (process.env.NODE_ENV !== 'production') {
route: PropTypes.instanceOf(Route),
};
ArchivePageSync.propTypes = {
category: PropTypes.object,
posts: PropTypes.arrayOf(PropTypes.object),
month: PropTypes.instanceOf(Moment),
route: PropTypes.instanceOf(Route),

View File

@@ -1,3 +1,4 @@
import _ from 'lodash';
import React, { PureComponent } from 'react';
import { AsyncComponent } from 'relaks';
import { Route } from 'routing';
@@ -11,14 +12,14 @@ class CategoryPage extends AsyncComponent {
async renderAsync(meanwhile) {
let { wp, route } = this.props;
let { categorySlug } = route.params;
let { categorySlugs } = route.params;
let props = {
route,
};
meanwhile.show(<CategoryPageSync {...props} />);
props.categories = await wp.fetchList('/wp/v2/categories/');
props.categories = await wp.fetchMultiple('/wp/v2/categories/', categorySlugs);
meanwhile.show(<CategoryPageSync {...props} />);
let category = _.find(props.categories, { slug: categorySlug });
let category = _.last(props.categories);
props.posts = await wp.fetchList(`/wp/v2/posts/?categories=${category.id}`);
return <CategoryPageSync {...props} />;
}
@@ -29,13 +30,17 @@ class CategoryPageSync extends PureComponent {
render() {
let { route, posts, categories } = this.props;
let { categorySlug } = route.params;
let category = _.find(categories, { slug: categorySlug });
let categoryLabel = _.get(category, 'name', '');
let trail = [
{ label: 'Categories' },
{ label: categoryLabel },
];
let trail = [ { label: 'Categories' } ];
let category = _.last(categories);
for (let c of categories) {
let label = _.get(c, 'name', '');
if (c !== category) {
let url = route.getObjectURL(c);
trail.push({ label, url });
} else {
trail.push({ label });
}
}
return (
<div className="page">
<Breadcrumb trail={trail} />

View File

@@ -14,15 +14,15 @@ class PagePage extends AsyncComponent {
async renderAsync(meanwhile) {
let { wp, route } = this.props;
let { pageSlug, parentPageSlugs } = route.params;
let { pageSlugs } = route.params;
let props = {
route,
};
props.page = await wp.fetchOne('/wp/v2/pages/', pageSlug);
meanwhile.show(<PagePageSync {...props} />);
props.parentPages = await wp.fetchMultiple('/wp/v2/pages/', parentPageSlugs);
props.pages = await wp.fetchMultiple('/wp/v2/pages/', pageSlugs);
meanwhile.show(<PagePageSync {...props} />);
props.childPages = await wp.fetchList(`/wp/v2/pages/?parent=${props.page.id}`, { minimum: '100%' });
let page = _.last(props.pages);
props.childPages = await wp.fetchList(`/wp/v2/pages/?parent=${page.id}`, { minimum: '100%' });
return <PagePageSync {...props} />;
}
}
@@ -31,25 +31,21 @@ class PagePageSync extends PureComponent {
static displayName = 'PagePageSync';
render() {
let { route, page, parentPages, childPages, transform } = this.props;
let { route, pages, childPages, transform } = this.props;
let page = _.last(pages);
let trail = [];
let parents = [];
if (parentPages) {
for (let parentPage of parentPages) {
parents.push(parentPage);
let title = _.get(parentPage, 'title.rendered', '');
let slugs = _.map(parents, 'slug');
let url = route.find(slugs);
for (let p of pages) {
if (p !== page) {
let title = _.get(page, 'title.rendered', '');
let url = route.getObjectURL(p);
trail.push({ label: <HTML text={title} />, url })
}
parents.push(page);
}
return (
<div className="page">
<Breadcrumb trail={trail} />
<PageView page={page} transform={route.transformLink} />
<PageList route={route} pages={childPages} parentPages={parents} />
<PageList route={route} pages={childPages} />
</div>
);
}

View File

@@ -14,20 +14,16 @@ class PostPage extends AsyncComponent {
async renderAsync(meanwhile) {
let { wp, route } = this.props;
let { monthSlug, categorySlug, postSlug } = route.params;
let { postSlug } = route.params;
let props = {
route,
};
if (monthSlug) {
props.month = Moment(monthSlug);
}
meanwhile.show(<PostPageSync {...props} />);
if (categorySlug) {
props.category = await wp.fetchOne('/wp/v2/categories/', categorySlug);
meanwhile.show(<PostPageSync {...props} />);
}
props.post = await wp.fetchOne('/wp/v2/posts/', postSlug);
meanwhile.show(<PostPageSync {...props} />);
let allCategories = await wp.fetchList('/wp/v2/categories/', { minimum: '100%' });
props.categories = findMatchingCategories(allCategories, props.post.categories, route.history);
meanwhile.show(<PostPageSync {...props} />);
props.author = await wp.fetchOne('/wp/v2/users/', props.post.author);
if (!wp.ssr) {
meanwhile.show(<PostPageSync {...props} />);
@@ -41,36 +37,78 @@ class PostPageSync extends PureComponent {
static displayName = 'PostPageSync';
render() {
let { route, month, category, post, author, comments } = this.props;
let { monthSlug, categorySlug } = route.params;
let trail = [];
if (monthSlug) {
let monthLabel = month.format('MMMM YYYY');
let monthURL = route.find([ monthSlug ]);
trail.push({ label: 'Archive' });
trail.push({ label: monthLabel, url: monthURL });
}
if (categorySlug) {
let categoryLabel = _.get(category, 'name', '');
let categoryURL;
if (monthSlug) {
categoryURL = route.find([ monthSlug, categorySlug ]);
} else {
trail.push({ label: 'Categories' });
categoryURL = route.find([ categorySlug ]);
}
trail.push({ label: categoryLabel, url: categoryURL });
let { route, categories, post, author, comments } = this.props;
let trail = [ { label: 'Categories' } ];
for (let c of categories) {
let label = _.get(c, 'name', '');
let url = route.getObjectURL(c);
trail.push({ label, url });
}
return (
<div className="page">
<Breadcrumb trail={trail} />
<PostView category={category} post={post} author={author} transform={route.transformLink} />
<PostView post={post} author={author} transform={route.transformLink} />
<CommentSection comments={comments} />
</div>
);
}
}
function includeCategory(list, id, allCategories) {
let category = _.find(allCategories, { id })
if (category) {
if (!_.includes(list, category)) {
list.push(category);
}
// add parent category as well
includeCategory(list, category.parent, allCategories);
}
}
function findMatchingCategories(allCategories, ids, history) {
let applicable = [];
for (let id of ids) {
includeCategory(applicable, id, allCategories);
}
let historyIndex = (c) => {
return _.findLastIndex(history, (route) => {
if (route.params.categorySlugs) {
return _.includes(route.params.categorySlugs, c.slug);
}
});
};
let depth = (c) => {
if (c.parent) {
let parent = _.find(allCategories, { id: c.parent });
if (parent) {
return depth(parent) + 1;
}
}
return 0;
};
// order applicable categories based on how recently it was visited,
// how deep it is, and alphabetically
applicable = _.orderBy(applicable, [ historyIndex, depth, 'name' ], [ 'desc', 'desc', 'asc' ]);
let anchorCategory = _.first(applicable);
let trail = [];
if (anchorCategory) {
// add category and its ancestors
for (let c = anchorCategory; c; c = _.find(applicable, { id: c.parent })) {
trail.unshift(c);
}
// add applicable child categories
for (let c = anchorCategory; c; c = _.find(applicable, { parent: c.id })) {
if (c !== anchorCategory) {
trail.push(c);
}
}
}
return trail;
}
if (process.env.NODE_ENV !== 'production') {
const PropTypes = require('prop-types');
@@ -79,11 +117,10 @@ if (process.env.NODE_ENV !== 'production') {
route: PropTypes.instanceOf(Route),
};
PostPageSync.propTypes = {
category: PropTypes.object,
categories: PropTypes.arrayOf(PropTypes.object),
post: PropTypes.object,
author: PropTypes.object,
comments: PropTypes.arrayOf(PropTypes.object),
month: PropTypes.instanceOf(Moment),
route: PropTypes.instanceOf(Route),
};
}

View File

@@ -16,77 +16,113 @@ class Route {
return this.routeManager.change(url, options);
}
find(params) {
if (params instanceof Array) {
let slugs = params;
return this.routeManager.find('page', { slugs });
} else {
return this.routeManager.find('page', params);
}
getRootURL() {
return this.composeURL({ path: '/' });
}
async setPageType(params) {
let slugs = params.slugs;
if (slugs.length > 0) {
let slugType1 = await this.getSlugType(slugs[0]);
if (slugType1 === 'page') {
params.pageType = 'page';
params.pageSlug = _.last(slugs);
params.parentPageSlugs = _.slice(slugs, 0, -1);
} else if (slugType1 === 'category') {
if (slugs.length === 1) {
params.pageType = 'category';
params.categorySlug = slugs[0];
} else if (slugs.length === 2) {
params.pageType = 'post';
params.categorySlug = slugs[0];
params.postSlug = slugs[1];
}
} else if (slugType1 === 'archive') {
if (slugs.length === 1) {
params.pageType = 'archive';
params.monthSlug = slugs[0];
} else if (slugs.length === 2) {
let slugType2 = await this.getSlugType(slugs[1]);
if (slugType2 === 'category') {
params.pageType = 'archive';
params.monthSlug = slugs[0];
params.categorySlug = slugs[1];
} else {
params.pageType = 'post';
params.monthSlug = slugs[0];
params.postSlug = slugs[1];
}
} else if (slugs.length === 3) {
params.pageType = 'post';
params.monthSlug = slugs[0];
params.categorySlug = slugs[1];
params.postSlug = slugs[2];
}
}
}
if (!params.pageType) {
if (params.search !== undefined) {
params.pageType = 'search';
} else {
params.pageType = 'welcome';
}
}
getSearchURL(search) {
return this.composeURL({ path: '/', query: { s: search } });
}
async getSlugType(slug) {
let options = { minimum: '100%' };
let pages = await this.dataSource.fetchList('/wp/v2/pages/?parent=0', options);
if (_.some(pages, { slug })) {
return 'page';
getArchiveURL(date) {
let { year, month } = date;
return this.composeURL({ path: `/date/${year}/${month}/` });
}
getObjectURL(object) {
let { siteURL } = this.params;
let url = object.link;
if (!_.startsWith(url, siteURL)) {
throw new Error(`Object URL does not match site URL`);
}
let categories = await this.dataSource.fetchList('/wp/v2/categories/', options);
if (_.some(categories, { slug })) {
return 'category';
let path = url.substr(siteURL.length);
return this.composeURL({ path });
}
composeURL(urlParts) {
let context = _.clone(this.routeManager.context);
this.routeManager.rewrite('to', urlParts, context);
return this.routeManager.compose(urlParts);
}
async setParameters(evt) {
let params = await this.getParameters(evt.path, evt.query);
params.module = require(`pages/${params.pageType}-page`);
_.assign(evt.params, params);
}
async getParameters(path, query) {
// get the site URL and see what the page's URL would be if it
// were on WordPress itself
let siteURL = await this.getSiteURL();
let link = siteURL + path;
console.log(link);
// see if it's a search
let search = query.s;
if (search) {
return { pageType: 'search', search, siteURL };
}
if (/^\d{4}\-\d{2}$/.test(slug)) {
return 'archive';
// see if it's pointing to the root page
if (path === '/') {
return { pageType: 'welcome', siteURL };
}
// see if it's pointing to an archive
let date = findDate(path);
if (date) {
return { pageType: 'archive', date, siteURL };
}
// see if it's pointing to a post by ID
let postID = findPostID(path);
if (postID) {
let post = await this.dataSource.fetchOne('/wp/v2/posts/', postID);
if (post) {
let postSlug = post.slug;
return { pageType: 'post', postSlug, siteURL };
}
}
// see if it's pointing to a page
let allPages = await this.dataSource.fetchList('/wp/v2/pages/', { minimum: '100%' });
let pageSlugs = findMatchingSlugs(allPages, link);
if (pageSlugs) {
return { pageType: 'page', pageSlugs, siteURL };
}
// see if it's pointing to a category
let allCategories = await this.dataSource.fetchList('/wp/v2/categories/', { minimum: '100%' });
let categorySlugs = findMatchingSlugs(allCategories, link);
if (categorySlugs) {
return { pageType: 'category', categorySlugs, siteURL };
}
// see if it's pointing to a tag
let allTags = await this.dataSource.fetchList('/wp/v2/tags/', { minimum: '100%' });
let tagSlugs = findMatchingSlugs(allTags, link);
if (tagSlugs) {
let tagSlug = tagSlugs[0];
return { pageType: 'tag', tagSlug, siteURL };
}
// see if it's pointing to a post
let postSlug = _.last(_.filter(_.split(path, '/')));
let post = await this.dataSource.fetchOne('/wp/v2/posts/', postSlug);
if (post) {
return { pageType: 'post', postSlug, siteURL };
}
// go to the welcome page if we can't find a match
return { pageType: 'welcome', siteURL };
}
async getSiteURL() {
let site = await this.dataSource.fetchOne('/');
return _.trimEnd(site.url, '/');
}
async preloadPage(params) {
@@ -126,31 +162,44 @@ class Route {
}
}
let routes = {
'page': {
path: {
from(path, params) {
params.slugs = path.split('/').filter(Boolean);
return true;
},
to(params) {
if (params.slugs instanceof Array) {
return `/${params.slugs.join('/')}`;
} else {
return `/`;
}
}
},
query: {
search: '${search}',
},
load: (match) => {
let type = match.params.pageType;
if (type) {
match.params.module = require(`pages/${type}-page`);
}
function findDate(path) {
if (_.startsWith(path, '/date/')) {
path = path.substr(5);
}
let m = /^\/(\d{4})\/(\d+)\/?/.exec(path);
if (m) {
return {
year: parseInt(m[1]),
month: parseInt(m[2]),
};
}
}
function findPostID(path) {
if (_.startsWith(path, '/archives/')) {
let id = parseInt(path.substr(10));
if (id === id) {
return id;
}
},
}
}
function findMatchingSlugs(objects, link) {
let matches = [];
for (let object of objects) {
let objectLink = _.trimEnd(object.link, '/') + '/';
if (_.startsWith(objectLink, link)) {
matches.push(object);
}
}
if (matches.length > 0) {
let slugs = _.map(_.sortBy(matches, 'link.length'), 'slug');
return slugs;
}
}
let routes = {
'page': { path: '*' },
};
export {

View File

@@ -30,6 +30,7 @@ A {
background-color: #66023c;
overflow: hidden;
color: #cccccc;
padding: 0 1em 0 1em;
A {
opacity: 0.5;
@@ -44,6 +45,10 @@ A {
}
}
UL {
margin-left: -1em;
}
.categories {
LI {
margin-top: 0.2em;

View File

@@ -8,11 +8,9 @@ class PageListView extends PureComponent {
static displayName = 'PageListView';
render() {
let { route, parentPages, page } = this.props;
let { route, page } = this.props;
let title = _.get(page, 'title.rendered', '');
let parentSlugs = _.map(parentPages, 'slug');
let slugs = _.concat(parentSlugs, page.slug);
let url = route.find(slugs);
let url = route.getObjectURL(page);
return (
<div className="page-list-view">
<a href={url}><HTML text={title} /></a>
@@ -26,7 +24,6 @@ if (process.env.NODE_ENV !== 'production') {
PageListView.propTypes = {
page: PropTypes.object,
parentPages: PropTypes.arrayOf(PropTypes.object),
route: PropTypes.instanceOf(Route).isRequired,
};
}

View File

@@ -8,7 +8,7 @@ class PageList extends PureComponent {
static displayName = 'PageList'
render() {
let { route, pages, parentPages } = this.props;
let { route, pages } = this.props;
if (!pages) {
return null;
}
@@ -18,7 +18,7 @@ class PageList extends PureComponent {
pages.map((page) => {
return (
<li key={page.id}>
<PageListView route={route} page={page} parentPages={parentPages} />
<PageListView route={route} page={page} />
</li>
);
})
@@ -44,7 +44,6 @@ if (process.env.NODE_ENV !== 'production') {
PageList.propTypes = {
pages: PropTypes.arrayOf(PropTypes.object),
parentPages: PropTypes.arrayOf(PropTypes.object),
route: PropTypes.instanceOf(Route).isRequired,
};
}

View File

@@ -9,18 +9,11 @@ class PostListView extends PureComponent {
static displayName = 'PostListView';
render() {
let { route, category, post, month } = this.props;
let { route, post } = this.props;
let title = _.get(post, 'title.rendered', '');
let excerpt = _.get(post, 'excerpt.rendered', '');
excerpt = cleanExcerpt(excerpt);
let slugs = [ post.slug ];
if (category) {
slugs.unshift(category.slug);
}
if (month) {
slugs.unshift(month.format('YYYY-MM'));
}
let url = route.find(slugs);
let url = route.getObjectURL(post);
return (
<div className="post-list-view">
<h3>
@@ -44,9 +37,7 @@ if (process.env.NODE_ENV !== 'production') {
const PropTypes = require('prop-types');
PostListView.propTypes = {
category: PropTypes.object,
post: PropTypes.object,
month: PropTypes.instanceOf(Moment),
route: PropTypes.instanceOf(Route).isRequired,
};
}

View File

@@ -9,7 +9,7 @@ class PostList extends PureComponent {
static displayName = 'PostList'
render() {
let { route, posts, categories, month, authors } = this.props;
let { route, posts } = this.props;
if (!posts) {
return null;
}
@@ -17,9 +17,7 @@ class PostList extends PureComponent {
<div className="posts">
{
posts.map((post) => {
let author = _.find(authors, { id: post.author_id });
let category = _.find(categories, { id: post.categories[0] });
return <PostListView route={route} month={month} category={category} post={post} author={author} key={post.id} />
return <PostListView route={route} post={post} key={post.id} />
})
}
</div>
@@ -62,8 +60,6 @@ if (process.env.NODE_ENV !== 'production') {
const PropTypes = require('prop-types');
PostList.propTypes = {
categories: PropTypes.arrayOf(PropTypes.object),
month: PropTypes.instanceOf(Moment),
route: PropTypes.instanceOf(Route),
minimum: PropTypes.number,
maximum: PropTypes.number,

View File

@@ -8,7 +8,7 @@ class PostView extends PureComponent {
static displayName = 'PostView';
render() {
let { category, post, author, transform } = this.props;
let { post, author, transform } = this.props;
let title = _.get(post, 'title.rendered', '');
let content = _.get(post, 'content.rendered', '');
let date = _.get(post, 'date_gmt');
@@ -35,7 +35,6 @@ if (process.env.NODE_ENV !== 'production') {
const PropTypes = require('prop-types');
PostView.propTypes = {
category: PropTypes.object,
post: PropTypes.object,
author: PropTypes.object,
transform: PropTypes.func,

View File

@@ -11,21 +11,13 @@ class SideNav extends AsyncComponent {
constructor(props) {
super(props);
let { route } = this.props;
let { monthSlug } = route.params;
let selectedYear;
if (monthSlug) {
selectedYear = parseInt(monthSlug.substr(0, 4));
} else {
selectedYear = Moment().year();
}
this.state = {
selectedYear
};
let { date } = route.params;
let selectedYear = _.get(date, 'year', Moment().year());
this.state = { selectedYear };
}
async renderAsync(meanwhile) {
let { wp, route } = this.props;
let { monthSlug } = route.params;
let { selectedYear } = this.state;
let props = {
route,
@@ -68,7 +60,10 @@ class SideNav extends AsyncComponent {
let monthEntry = {
month: m + 1,
label: start.format('MMMM'),
slug: start.format('YYYY-MM'),
date: {
year: start.year(),
month: start.month() + 1,
},
post: undefined,
start,
end,
@@ -96,15 +91,7 @@ class SideNav extends AsyncComponent {
// load the posts of each categories
props.categoryPosts = [];
for (let category of props.categories) {
let url;
if (monthSlug) {
let month = Moment(monthSlug);
let after = month.toISOString();
let before = month.endOf('month').toISOString();
url = `/wp/v2/posts/?after=${after}&before=${before}&categories=${category.id}`;
} else {
url = `/wp/v2/posts/?categories=${category.id}`;
}
let url = `/wp/v2/posts/?categories=${category.id}`;
let posts = await wp.fetchList(url);
props.categoryPosts = _.clone(props.categoryPosts);
props.categoryPosts.push(posts);
@@ -125,7 +112,9 @@ class SideNavSync extends PureComponent {
render() {
return (
<div className="side-nav">
<h3>Categories</h3>
{this.renderCategories()}
<h3>Archives</h3>
{this.renderArchive()}
</div>
)
@@ -136,6 +125,8 @@ class SideNavSync extends PureComponent {
if (!categories) {
return null;
}
// only top-level categories
categories = _.filter(categories, { parent: 0 });
// don't show categories with no post
categories = _.filter(categories, 'count');
// list category with more posts first
@@ -153,20 +144,16 @@ class SideNavSync extends PureComponent {
renderCategory(category, i) {
let { route, categoryPosts } = this.props;
let { monthSlug, categorySlug } = route.params;
let { categorySlugs } = route.params;
let name = _.get(category, 'name', '');
let description = _.get(category, 'description', '');
let slugs = [ category.slug ];
if (monthSlug) {
slugs.unshift(monthSlug);
}
let url = route.find(slugs);
let url = route.getObjectURL(category);
let posts = (categoryPosts) ? categoryPosts[i] : undefined;
if (_.isEmpty(posts) && !_.isUndefined(posts)) {
url = undefined;
}
let className;
if (categorySlug === category.slug) {
if (category.slug === _.last(categorySlugs)) {
className = 'selected';
}
return (
@@ -216,13 +203,13 @@ class SideNavSync extends PureComponent {
renderMonth(monthEntry, i) {
let { route } = this.props;
let { monthSlug } = route.params;
let url = route.find([ monthEntry.slug ]);
let { date } = route.params;
let url = route.getArchiveURL(monthEntry.date);
if (_.isEmpty(monthEntry.posts) && !_.isUndefined(monthEntry.posts)) {
url = undefined;
}
let className;
if (monthSlug === monthEntry.slug) {
if (_.isEqual(monthEntry.date, date)) {
className = 'selected';
}
return (

View File

@@ -46,7 +46,7 @@ class TopNavSync extends PureComponent {
let { route, system } = this.props;
let name = _.get(system, 'name', '');
let description = _.get(system, 'description', '');
let url = route.find({});
let url = route.getRootURL();
return (
<div className="title-bar">
<div className="title" title={description}>
@@ -76,8 +76,7 @@ class TopNavSync extends PureComponent {
renderPageLinkButton(page, i) {
let { route } = this.props;
let title = _.get(page, 'title.rendered');
let slug = _.get(page, 'slug');
let url = route.find([ slug ]);
let url = route.getObjectURL(page);
return (
<div className="button" key={i}>
<a href={url}>{title}</a>
@@ -101,7 +100,7 @@ class TopNavSync extends PureComponent {
performSearch = (evt) => {
let { search } = this.state;
let { route } = this.props;
let url = route.find({ search });
let url = route.getSearchURL(search);
let options = {
replace: (route.params.pageType === 'search')
};