mirror of
https://github.com/trambarhq/relaks-wordpress-example.git
synced 2025-09-03 05:02:34 +02:00
Reworked routing so that WP permalinks arrangement is used (issue #13).
This commit is contained in:
@@ -25,13 +25,11 @@ server {
|
|||||||
proxy_cache_min_uses 1;
|
proxy_cache_min_uses 1;
|
||||||
proxy_cache_valid 200 301 302 120m;
|
proxy_cache_valid 200 301 302 120m;
|
||||||
proxy_cache_valid 404 1m;
|
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 Cache-Control "public,max-age=0";
|
||||||
add_header X-Cache-Date $upstream_http_date;
|
add_header X-Cache-Date $upstream_http_date;
|
||||||
add_header X-Cache-Status $upstream_cache_status;
|
add_header X-Cache-Status $upstream_cache_status;
|
||||||
add_header Access-Control-Allow-Origin *;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,6 +10,7 @@ const HTML_TEMPLATE = `${__dirname}/client/index.html`;
|
|||||||
|
|
||||||
async function generate(path, target) {
|
async function generate(path, target) {
|
||||||
// retrieve cached JSON through Nginx
|
// retrieve cached JSON through Nginx
|
||||||
|
console.log(`Regenerating page: ${path}`);
|
||||||
let host = `http://${NGINX_HOST}`;
|
let host = `http://${NGINX_HOST}`;
|
||||||
// create a fetch() that remembers the URLs used
|
// create a fetch() that remembers the URLs used
|
||||||
let sourceURLs = [];
|
let sourceURLs = [];
|
||||||
|
@@ -31,7 +31,7 @@ if (typeof(window) === 'object') {
|
|||||||
});
|
});
|
||||||
routeManager.addEventListener('beforechange', (evt) => {
|
routeManager.addEventListener('beforechange', (evt) => {
|
||||||
let route = new Route(routeManager, dataSource);
|
let route = new Route(routeManager, dataSource);
|
||||||
evt.postponeDefault(route.setPageType(evt.params));
|
evt.postponeDefault(route.setParameters(evt));
|
||||||
});
|
});
|
||||||
routeManager.activate();
|
routeManager.activate();
|
||||||
await routeManager.start();
|
await routeManager.start();
|
||||||
@@ -57,7 +57,6 @@ if (typeof(window) === 'object') {
|
|||||||
let mtime = await res.text();
|
let mtime = await res.text();
|
||||||
if (mtime !== mtimeLast) {
|
if (mtime !== mtimeLast) {
|
||||||
if (mtimeLast) {
|
if (mtimeLast) {
|
||||||
console.log('changed');
|
|
||||||
dataSource.invalidate();
|
dataSource.invalidate();
|
||||||
}
|
}
|
||||||
mtimeLast = mtime;
|
mtimeLast = mtime;
|
||||||
@@ -84,7 +83,7 @@ if (typeof(window) === 'object') {
|
|||||||
});
|
});
|
||||||
routeManager.addEventListener('beforechange', (evt) => {
|
routeManager.addEventListener('beforechange', (evt) => {
|
||||||
let route = new Route(routeManager, dataSource);
|
let route = new Route(routeManager, dataSource);
|
||||||
evt.postponeDefault(route.setPageType(evt.params));
|
evt.postponeDefault(route.setParameters(evt));
|
||||||
});
|
});
|
||||||
routeManager.activate();
|
routeManager.activate();
|
||||||
await routeManager.start(options.path);
|
await routeManager.start(options.path);
|
||||||
|
@@ -12,22 +12,16 @@ class ArchivePage extends AsyncComponent {
|
|||||||
|
|
||||||
async renderAsync(meanwhile) {
|
async renderAsync(meanwhile) {
|
||||||
let { wp, route } = this.props;
|
let { wp, route } = this.props;
|
||||||
let { monthSlug, categorySlug } = route.params;
|
let { date } = route.params;
|
||||||
let month = Moment(monthSlug);
|
let month = Moment(`${date.year}-${date.month}`);
|
||||||
let props = {
|
let props = {
|
||||||
route,
|
route,
|
||||||
month,
|
month,
|
||||||
};
|
};
|
||||||
|
meanwhile.show(<ArchivePageSync {...props} />);
|
||||||
let after = month.toISOString();
|
let after = month.toISOString();
|
||||||
let before = month.clone().endOf('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}`;
|
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);
|
props.posts = await wp.fetchList(url);
|
||||||
return <ArchivePageSync {...props} />;
|
return <ArchivePageSync {...props} />;
|
||||||
}
|
}
|
||||||
@@ -37,23 +31,13 @@ class ArchivePageSync extends PureComponent {
|
|||||||
static displayName = 'ArchivePageSync';
|
static displayName = 'ArchivePageSync';
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { route, categories, posts, month } = this.props;
|
let { route, posts, month } = this.props;
|
||||||
let { monthSlug, categorySlug } = route.params;
|
|
||||||
let monthLabel = month.format('MMMM YYYY');
|
let monthLabel = month.format('MMMM YYYY');
|
||||||
let monthURL = route.find([ monthSlug ]);
|
let trail = [ { label: 'Archive' }, { label: monthLabel } ];
|
||||||
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 });
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<div className="page">
|
<div className="page">
|
||||||
<Breadcrumb trail={trail} />
|
<Breadcrumb trail={trail} />
|
||||||
<PostList route={route} posts={posts} month={month} categories={categories} minimum={100} />
|
<PostList route={route} posts={posts} minimum={100} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -67,7 +51,6 @@ if (process.env.NODE_ENV !== 'production') {
|
|||||||
route: PropTypes.instanceOf(Route),
|
route: PropTypes.instanceOf(Route),
|
||||||
};
|
};
|
||||||
ArchivePageSync.propTypes = {
|
ArchivePageSync.propTypes = {
|
||||||
category: PropTypes.object,
|
|
||||||
posts: PropTypes.arrayOf(PropTypes.object),
|
posts: PropTypes.arrayOf(PropTypes.object),
|
||||||
month: PropTypes.instanceOf(Moment),
|
month: PropTypes.instanceOf(Moment),
|
||||||
route: PropTypes.instanceOf(Route),
|
route: PropTypes.instanceOf(Route),
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import { AsyncComponent } from 'relaks';
|
import { AsyncComponent } from 'relaks';
|
||||||
import { Route } from 'routing';
|
import { Route } from 'routing';
|
||||||
@@ -11,14 +12,14 @@ class CategoryPage extends AsyncComponent {
|
|||||||
|
|
||||||
async renderAsync(meanwhile) {
|
async renderAsync(meanwhile) {
|
||||||
let { wp, route } = this.props;
|
let { wp, route } = this.props;
|
||||||
let { categorySlug } = route.params;
|
let { categorySlugs } = route.params;
|
||||||
let props = {
|
let props = {
|
||||||
route,
|
route,
|
||||||
};
|
};
|
||||||
meanwhile.show(<CategoryPageSync {...props} />);
|
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} />);
|
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}`);
|
props.posts = await wp.fetchList(`/wp/v2/posts/?categories=${category.id}`);
|
||||||
return <CategoryPageSync {...props} />;
|
return <CategoryPageSync {...props} />;
|
||||||
}
|
}
|
||||||
@@ -29,13 +30,17 @@ class CategoryPageSync extends PureComponent {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { route, posts, categories } = this.props;
|
let { route, posts, categories } = this.props;
|
||||||
let { categorySlug } = route.params;
|
let trail = [ { label: 'Categories' } ];
|
||||||
let category = _.find(categories, { slug: categorySlug });
|
let category = _.last(categories);
|
||||||
let categoryLabel = _.get(category, 'name', '');
|
for (let c of categories) {
|
||||||
let trail = [
|
let label = _.get(c, 'name', '');
|
||||||
{ label: 'Categories' },
|
if (c !== category) {
|
||||||
{ label: categoryLabel },
|
let url = route.getObjectURL(c);
|
||||||
];
|
trail.push({ label, url });
|
||||||
|
} else {
|
||||||
|
trail.push({ label });
|
||||||
|
}
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div className="page">
|
<div className="page">
|
||||||
<Breadcrumb trail={trail} />
|
<Breadcrumb trail={trail} />
|
||||||
|
@@ -14,15 +14,15 @@ class PagePage extends AsyncComponent {
|
|||||||
|
|
||||||
async renderAsync(meanwhile) {
|
async renderAsync(meanwhile) {
|
||||||
let { wp, route } = this.props;
|
let { wp, route } = this.props;
|
||||||
let { pageSlug, parentPageSlugs } = route.params;
|
let { pageSlugs } = route.params;
|
||||||
let props = {
|
let props = {
|
||||||
route,
|
route,
|
||||||
};
|
};
|
||||||
props.page = await wp.fetchOne('/wp/v2/pages/', pageSlug);
|
|
||||||
meanwhile.show(<PagePageSync {...props} />);
|
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} />);
|
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} />;
|
return <PagePageSync {...props} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,25 +31,21 @@ class PagePageSync extends PureComponent {
|
|||||||
static displayName = 'PagePageSync';
|
static displayName = 'PagePageSync';
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { route, page, parentPages, childPages, transform } = this.props;
|
let { route, pages, childPages, transform } = this.props;
|
||||||
|
let page = _.last(pages);
|
||||||
let trail = [];
|
let trail = [];
|
||||||
let parents = [];
|
for (let p of pages) {
|
||||||
if (parentPages) {
|
if (p !== page) {
|
||||||
for (let parentPage of parentPages) {
|
let title = _.get(page, 'title.rendered', '');
|
||||||
parents.push(parentPage);
|
let url = route.getObjectURL(p);
|
||||||
|
|
||||||
let title = _.get(parentPage, 'title.rendered', '');
|
|
||||||
let slugs = _.map(parents, 'slug');
|
|
||||||
let url = route.find(slugs);
|
|
||||||
trail.push({ label: <HTML text={title} />, url })
|
trail.push({ label: <HTML text={title} />, url })
|
||||||
}
|
}
|
||||||
parents.push(page);
|
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="page">
|
<div className="page">
|
||||||
<Breadcrumb trail={trail} />
|
<Breadcrumb trail={trail} />
|
||||||
<PageView page={page} transform={route.transformLink} />
|
<PageView page={page} transform={route.transformLink} />
|
||||||
<PageList route={route} pages={childPages} parentPages={parents} />
|
<PageList route={route} pages={childPages} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -14,20 +14,16 @@ class PostPage extends AsyncComponent {
|
|||||||
|
|
||||||
async renderAsync(meanwhile) {
|
async renderAsync(meanwhile) {
|
||||||
let { wp, route } = this.props;
|
let { wp, route } = this.props;
|
||||||
let { monthSlug, categorySlug, postSlug } = route.params;
|
let { postSlug } = route.params;
|
||||||
let props = {
|
let props = {
|
||||||
route,
|
route,
|
||||||
};
|
};
|
||||||
if (monthSlug) {
|
|
||||||
props.month = Moment(monthSlug);
|
|
||||||
}
|
|
||||||
meanwhile.show(<PostPageSync {...props} />);
|
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);
|
props.post = await wp.fetchOne('/wp/v2/posts/', postSlug);
|
||||||
meanwhile.show(<PostPageSync {...props} />);
|
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);
|
props.author = await wp.fetchOne('/wp/v2/users/', props.post.author);
|
||||||
if (!wp.ssr) {
|
if (!wp.ssr) {
|
||||||
meanwhile.show(<PostPageSync {...props} />);
|
meanwhile.show(<PostPageSync {...props} />);
|
||||||
@@ -41,36 +37,78 @@ class PostPageSync extends PureComponent {
|
|||||||
static displayName = 'PostPageSync';
|
static displayName = 'PostPageSync';
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { route, month, category, post, author, comments } = this.props;
|
let { route, categories, post, author, comments } = this.props;
|
||||||
let { monthSlug, categorySlug } = route.params;
|
let trail = [ { label: 'Categories' } ];
|
||||||
let trail = [];
|
for (let c of categories) {
|
||||||
if (monthSlug) {
|
let label = _.get(c, 'name', '');
|
||||||
let monthLabel = month.format('MMMM YYYY');
|
let url = route.getObjectURL(c);
|
||||||
let monthURL = route.find([ monthSlug ]);
|
trail.push({ label, url });
|
||||||
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 });
|
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="page">
|
<div className="page">
|
||||||
<Breadcrumb trail={trail} />
|
<Breadcrumb trail={trail} />
|
||||||
<PostView category={category} post={post} author={author} transform={route.transformLink} />
|
<PostView post={post} author={author} transform={route.transformLink} />
|
||||||
<CommentSection comments={comments} />
|
<CommentSection comments={comments} />
|
||||||
</div>
|
</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') {
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
const PropTypes = require('prop-types');
|
const PropTypes = require('prop-types');
|
||||||
|
|
||||||
@@ -79,11 +117,10 @@ if (process.env.NODE_ENV !== 'production') {
|
|||||||
route: PropTypes.instanceOf(Route),
|
route: PropTypes.instanceOf(Route),
|
||||||
};
|
};
|
||||||
PostPageSync.propTypes = {
|
PostPageSync.propTypes = {
|
||||||
category: PropTypes.object,
|
categories: PropTypes.arrayOf(PropTypes.object),
|
||||||
post: PropTypes.object,
|
post: PropTypes.object,
|
||||||
author: PropTypes.object,
|
author: PropTypes.object,
|
||||||
comments: PropTypes.arrayOf(PropTypes.object),
|
comments: PropTypes.arrayOf(PropTypes.object),
|
||||||
month: PropTypes.instanceOf(Moment),
|
|
||||||
route: PropTypes.instanceOf(Route),
|
route: PropTypes.instanceOf(Route),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
225
src/routing.js
225
src/routing.js
@@ -16,77 +16,113 @@ class Route {
|
|||||||
return this.routeManager.change(url, options);
|
return this.routeManager.change(url, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
find(params) {
|
getRootURL() {
|
||||||
if (params instanceof Array) {
|
return this.composeURL({ path: '/' });
|
||||||
let slugs = params;
|
|
||||||
return this.routeManager.find('page', { slugs });
|
|
||||||
} else {
|
|
||||||
return this.routeManager.find('page', params);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async setPageType(params) {
|
getSearchURL(search) {
|
||||||
let slugs = params.slugs;
|
return this.composeURL({ path: '/', query: { s: search } });
|
||||||
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';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getSlugType(slug) {
|
getArchiveURL(date) {
|
||||||
let options = { minimum: '100%' };
|
let { year, month } = date;
|
||||||
let pages = await this.dataSource.fetchList('/wp/v2/pages/?parent=0', options);
|
return this.composeURL({ path: `/date/${year}/${month}/` });
|
||||||
if (_.some(pages, { slug })) {
|
}
|
||||||
return 'page';
|
|
||||||
|
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);
|
let path = url.substr(siteURL.length);
|
||||||
if (_.some(categories, { slug })) {
|
return this.composeURL({ path });
|
||||||
return 'category';
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
async preloadPage(params) {
|
||||||
@@ -126,31 +162,44 @@ class Route {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let routes = {
|
function findDate(path) {
|
||||||
'page': {
|
if (_.startsWith(path, '/date/')) {
|
||||||
path: {
|
path = path.substr(5);
|
||||||
from(path, params) {
|
}
|
||||||
params.slugs = path.split('/').filter(Boolean);
|
let m = /^\/(\d{4})\/(\d+)\/?/.exec(path);
|
||||||
return true;
|
if (m) {
|
||||||
},
|
return {
|
||||||
to(params) {
|
year: parseInt(m[1]),
|
||||||
if (params.slugs instanceof Array) {
|
month: parseInt(m[2]),
|
||||||
return `/${params.slugs.join('/')}`;
|
};
|
||||||
} else {
|
}
|
||||||
return `/`;
|
}
|
||||||
}
|
|
||||||
}
|
function findPostID(path) {
|
||||||
},
|
if (_.startsWith(path, '/archives/')) {
|
||||||
query: {
|
let id = parseInt(path.substr(10));
|
||||||
search: '${search}',
|
if (id === id) {
|
||||||
},
|
return id;
|
||||||
load: (match) => {
|
|
||||||
let type = match.params.pageType;
|
|
||||||
if (type) {
|
|
||||||
match.params.module = require(`pages/${type}-page`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
export {
|
||||||
|
@@ -30,6 +30,7 @@ A {
|
|||||||
background-color: #66023c;
|
background-color: #66023c;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
color: #cccccc;
|
color: #cccccc;
|
||||||
|
padding: 0 1em 0 1em;
|
||||||
|
|
||||||
A {
|
A {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
@@ -44,6 +45,10 @@ A {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UL {
|
||||||
|
margin-left: -1em;
|
||||||
|
}
|
||||||
|
|
||||||
.categories {
|
.categories {
|
||||||
LI {
|
LI {
|
||||||
margin-top: 0.2em;
|
margin-top: 0.2em;
|
||||||
|
@@ -8,11 +8,9 @@ class PageListView extends PureComponent {
|
|||||||
static displayName = 'PageListView';
|
static displayName = 'PageListView';
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { route, parentPages, page } = this.props;
|
let { route, page } = this.props;
|
||||||
let title = _.get(page, 'title.rendered', '');
|
let title = _.get(page, 'title.rendered', '');
|
||||||
let parentSlugs = _.map(parentPages, 'slug');
|
let url = route.getObjectURL(page);
|
||||||
let slugs = _.concat(parentSlugs, page.slug);
|
|
||||||
let url = route.find(slugs);
|
|
||||||
return (
|
return (
|
||||||
<div className="page-list-view">
|
<div className="page-list-view">
|
||||||
<a href={url}><HTML text={title} /></a>
|
<a href={url}><HTML text={title} /></a>
|
||||||
@@ -26,7 +24,6 @@ if (process.env.NODE_ENV !== 'production') {
|
|||||||
|
|
||||||
PageListView.propTypes = {
|
PageListView.propTypes = {
|
||||||
page: PropTypes.object,
|
page: PropTypes.object,
|
||||||
parentPages: PropTypes.arrayOf(PropTypes.object),
|
|
||||||
route: PropTypes.instanceOf(Route).isRequired,
|
route: PropTypes.instanceOf(Route).isRequired,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,7 @@ class PageList extends PureComponent {
|
|||||||
static displayName = 'PageList'
|
static displayName = 'PageList'
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { route, pages, parentPages } = this.props;
|
let { route, pages } = this.props;
|
||||||
if (!pages) {
|
if (!pages) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,7 @@ class PageList extends PureComponent {
|
|||||||
pages.map((page) => {
|
pages.map((page) => {
|
||||||
return (
|
return (
|
||||||
<li key={page.id}>
|
<li key={page.id}>
|
||||||
<PageListView route={route} page={page} parentPages={parentPages} />
|
<PageListView route={route} page={page} />
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
@@ -44,7 +44,6 @@ if (process.env.NODE_ENV !== 'production') {
|
|||||||
|
|
||||||
PageList.propTypes = {
|
PageList.propTypes = {
|
||||||
pages: PropTypes.arrayOf(PropTypes.object),
|
pages: PropTypes.arrayOf(PropTypes.object),
|
||||||
parentPages: PropTypes.arrayOf(PropTypes.object),
|
|
||||||
route: PropTypes.instanceOf(Route).isRequired,
|
route: PropTypes.instanceOf(Route).isRequired,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -9,18 +9,11 @@ class PostListView extends PureComponent {
|
|||||||
static displayName = 'PostListView';
|
static displayName = 'PostListView';
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { route, category, post, month } = this.props;
|
let { route, post } = this.props;
|
||||||
let title = _.get(post, 'title.rendered', '');
|
let title = _.get(post, 'title.rendered', '');
|
||||||
let excerpt = _.get(post, 'excerpt.rendered', '');
|
let excerpt = _.get(post, 'excerpt.rendered', '');
|
||||||
excerpt = cleanExcerpt(excerpt);
|
excerpt = cleanExcerpt(excerpt);
|
||||||
let slugs = [ post.slug ];
|
let url = route.getObjectURL(post);
|
||||||
if (category) {
|
|
||||||
slugs.unshift(category.slug);
|
|
||||||
}
|
|
||||||
if (month) {
|
|
||||||
slugs.unshift(month.format('YYYY-MM'));
|
|
||||||
}
|
|
||||||
let url = route.find(slugs);
|
|
||||||
return (
|
return (
|
||||||
<div className="post-list-view">
|
<div className="post-list-view">
|
||||||
<h3>
|
<h3>
|
||||||
@@ -44,9 +37,7 @@ if (process.env.NODE_ENV !== 'production') {
|
|||||||
const PropTypes = require('prop-types');
|
const PropTypes = require('prop-types');
|
||||||
|
|
||||||
PostListView.propTypes = {
|
PostListView.propTypes = {
|
||||||
category: PropTypes.object,
|
|
||||||
post: PropTypes.object,
|
post: PropTypes.object,
|
||||||
month: PropTypes.instanceOf(Moment),
|
|
||||||
route: PropTypes.instanceOf(Route).isRequired,
|
route: PropTypes.instanceOf(Route).isRequired,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -9,7 +9,7 @@ class PostList extends PureComponent {
|
|||||||
static displayName = 'PostList'
|
static displayName = 'PostList'
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { route, posts, categories, month, authors } = this.props;
|
let { route, posts } = this.props;
|
||||||
if (!posts) {
|
if (!posts) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -17,9 +17,7 @@ class PostList extends PureComponent {
|
|||||||
<div className="posts">
|
<div className="posts">
|
||||||
{
|
{
|
||||||
posts.map((post) => {
|
posts.map((post) => {
|
||||||
let author = _.find(authors, { id: post.author_id });
|
return <PostListView route={route} post={post} key={post.id} />
|
||||||
let category = _.find(categories, { id: post.categories[0] });
|
|
||||||
return <PostListView route={route} month={month} category={category} post={post} author={author} key={post.id} />
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@@ -62,8 +60,6 @@ if (process.env.NODE_ENV !== 'production') {
|
|||||||
const PropTypes = require('prop-types');
|
const PropTypes = require('prop-types');
|
||||||
|
|
||||||
PostList.propTypes = {
|
PostList.propTypes = {
|
||||||
categories: PropTypes.arrayOf(PropTypes.object),
|
|
||||||
month: PropTypes.instanceOf(Moment),
|
|
||||||
route: PropTypes.instanceOf(Route),
|
route: PropTypes.instanceOf(Route),
|
||||||
minimum: PropTypes.number,
|
minimum: PropTypes.number,
|
||||||
maximum: PropTypes.number,
|
maximum: PropTypes.number,
|
||||||
|
@@ -8,7 +8,7 @@ class PostView extends PureComponent {
|
|||||||
static displayName = 'PostView';
|
static displayName = 'PostView';
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { category, post, author, transform } = this.props;
|
let { post, author, transform } = this.props;
|
||||||
let title = _.get(post, 'title.rendered', '');
|
let title = _.get(post, 'title.rendered', '');
|
||||||
let content = _.get(post, 'content.rendered', '');
|
let content = _.get(post, 'content.rendered', '');
|
||||||
let date = _.get(post, 'date_gmt');
|
let date = _.get(post, 'date_gmt');
|
||||||
@@ -35,7 +35,6 @@ if (process.env.NODE_ENV !== 'production') {
|
|||||||
const PropTypes = require('prop-types');
|
const PropTypes = require('prop-types');
|
||||||
|
|
||||||
PostView.propTypes = {
|
PostView.propTypes = {
|
||||||
category: PropTypes.object,
|
|
||||||
post: PropTypes.object,
|
post: PropTypes.object,
|
||||||
author: PropTypes.object,
|
author: PropTypes.object,
|
||||||
transform: PropTypes.func,
|
transform: PropTypes.func,
|
||||||
|
@@ -11,21 +11,13 @@ class SideNav extends AsyncComponent {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
let { route } = this.props;
|
let { route } = this.props;
|
||||||
let { monthSlug } = route.params;
|
let { date } = route.params;
|
||||||
let selectedYear;
|
let selectedYear = _.get(date, 'year', Moment().year());
|
||||||
if (monthSlug) {
|
this.state = { selectedYear };
|
||||||
selectedYear = parseInt(monthSlug.substr(0, 4));
|
|
||||||
} else {
|
|
||||||
selectedYear = Moment().year();
|
|
||||||
}
|
|
||||||
this.state = {
|
|
||||||
selectedYear
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async renderAsync(meanwhile) {
|
async renderAsync(meanwhile) {
|
||||||
let { wp, route } = this.props;
|
let { wp, route } = this.props;
|
||||||
let { monthSlug } = route.params;
|
|
||||||
let { selectedYear } = this.state;
|
let { selectedYear } = this.state;
|
||||||
let props = {
|
let props = {
|
||||||
route,
|
route,
|
||||||
@@ -68,7 +60,10 @@ class SideNav extends AsyncComponent {
|
|||||||
let monthEntry = {
|
let monthEntry = {
|
||||||
month: m + 1,
|
month: m + 1,
|
||||||
label: start.format('MMMM'),
|
label: start.format('MMMM'),
|
||||||
slug: start.format('YYYY-MM'),
|
date: {
|
||||||
|
year: start.year(),
|
||||||
|
month: start.month() + 1,
|
||||||
|
},
|
||||||
post: undefined,
|
post: undefined,
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
@@ -96,15 +91,7 @@ class SideNav extends AsyncComponent {
|
|||||||
// load the posts of each categories
|
// load the posts of each categories
|
||||||
props.categoryPosts = [];
|
props.categoryPosts = [];
|
||||||
for (let category of props.categories) {
|
for (let category of props.categories) {
|
||||||
let url;
|
let url = `/wp/v2/posts/?categories=${category.id}`;
|
||||||
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 posts = await wp.fetchList(url);
|
let posts = await wp.fetchList(url);
|
||||||
props.categoryPosts = _.clone(props.categoryPosts);
|
props.categoryPosts = _.clone(props.categoryPosts);
|
||||||
props.categoryPosts.push(posts);
|
props.categoryPosts.push(posts);
|
||||||
@@ -125,7 +112,9 @@ class SideNavSync extends PureComponent {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="side-nav">
|
<div className="side-nav">
|
||||||
|
<h3>Categories</h3>
|
||||||
{this.renderCategories()}
|
{this.renderCategories()}
|
||||||
|
<h3>Archives</h3>
|
||||||
{this.renderArchive()}
|
{this.renderArchive()}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@@ -136,6 +125,8 @@ class SideNavSync extends PureComponent {
|
|||||||
if (!categories) {
|
if (!categories) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
// only top-level categories
|
||||||
|
categories = _.filter(categories, { parent: 0 });
|
||||||
// don't show categories with no post
|
// don't show categories with no post
|
||||||
categories = _.filter(categories, 'count');
|
categories = _.filter(categories, 'count');
|
||||||
// list category with more posts first
|
// list category with more posts first
|
||||||
@@ -153,20 +144,16 @@ class SideNavSync extends PureComponent {
|
|||||||
|
|
||||||
renderCategory(category, i) {
|
renderCategory(category, i) {
|
||||||
let { route, categoryPosts } = this.props;
|
let { route, categoryPosts } = this.props;
|
||||||
let { monthSlug, categorySlug } = route.params;
|
let { categorySlugs } = route.params;
|
||||||
let name = _.get(category, 'name', '');
|
let name = _.get(category, 'name', '');
|
||||||
let description = _.get(category, 'description', '');
|
let description = _.get(category, 'description', '');
|
||||||
let slugs = [ category.slug ];
|
let url = route.getObjectURL(category);
|
||||||
if (monthSlug) {
|
|
||||||
slugs.unshift(monthSlug);
|
|
||||||
}
|
|
||||||
let url = route.find(slugs);
|
|
||||||
let posts = (categoryPosts) ? categoryPosts[i] : undefined;
|
let posts = (categoryPosts) ? categoryPosts[i] : undefined;
|
||||||
if (_.isEmpty(posts) && !_.isUndefined(posts)) {
|
if (_.isEmpty(posts) && !_.isUndefined(posts)) {
|
||||||
url = undefined;
|
url = undefined;
|
||||||
}
|
}
|
||||||
let className;
|
let className;
|
||||||
if (categorySlug === category.slug) {
|
if (category.slug === _.last(categorySlugs)) {
|
||||||
className = 'selected';
|
className = 'selected';
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
@@ -216,13 +203,13 @@ class SideNavSync extends PureComponent {
|
|||||||
|
|
||||||
renderMonth(monthEntry, i) {
|
renderMonth(monthEntry, i) {
|
||||||
let { route } = this.props;
|
let { route } = this.props;
|
||||||
let { monthSlug } = route.params;
|
let { date } = route.params;
|
||||||
let url = route.find([ monthEntry.slug ]);
|
let url = route.getArchiveURL(monthEntry.date);
|
||||||
if (_.isEmpty(monthEntry.posts) && !_.isUndefined(monthEntry.posts)) {
|
if (_.isEmpty(monthEntry.posts) && !_.isUndefined(monthEntry.posts)) {
|
||||||
url = undefined;
|
url = undefined;
|
||||||
}
|
}
|
||||||
let className;
|
let className;
|
||||||
if (monthSlug === monthEntry.slug) {
|
if (_.isEqual(monthEntry.date, date)) {
|
||||||
className = 'selected';
|
className = 'selected';
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
|
@@ -46,7 +46,7 @@ class TopNavSync extends PureComponent {
|
|||||||
let { route, system } = this.props;
|
let { route, system } = this.props;
|
||||||
let name = _.get(system, 'name', '');
|
let name = _.get(system, 'name', '');
|
||||||
let description = _.get(system, 'description', '');
|
let description = _.get(system, 'description', '');
|
||||||
let url = route.find({});
|
let url = route.getRootURL();
|
||||||
return (
|
return (
|
||||||
<div className="title-bar">
|
<div className="title-bar">
|
||||||
<div className="title" title={description}>
|
<div className="title" title={description}>
|
||||||
@@ -76,8 +76,7 @@ class TopNavSync extends PureComponent {
|
|||||||
renderPageLinkButton(page, i) {
|
renderPageLinkButton(page, i) {
|
||||||
let { route } = this.props;
|
let { route } = this.props;
|
||||||
let title = _.get(page, 'title.rendered');
|
let title = _.get(page, 'title.rendered');
|
||||||
let slug = _.get(page, 'slug');
|
let url = route.getObjectURL(page);
|
||||||
let url = route.find([ slug ]);
|
|
||||||
return (
|
return (
|
||||||
<div className="button" key={i}>
|
<div className="button" key={i}>
|
||||||
<a href={url}>{title}</a>
|
<a href={url}>{title}</a>
|
||||||
@@ -101,7 +100,7 @@ class TopNavSync extends PureComponent {
|
|||||||
performSearch = (evt) => {
|
performSearch = (evt) => {
|
||||||
let { search } = this.state;
|
let { search } = this.state;
|
||||||
let { route } = this.props;
|
let { route } = this.props;
|
||||||
let url = route.find({ search });
|
let url = route.getSearchURL(search);
|
||||||
let options = {
|
let options = {
|
||||||
replace: (route.params.pageType === 'search')
|
replace: (route.params.pageType === 'search')
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user