kopia lustrzana https://github.com/wagtail/wagtail
Change explorer behavior for pages w/ children, with tests
rodzic
26695a09c8
commit
81c6f3e3b1
|
@ -9,9 +9,8 @@ export const getChildPages = (id, options = {}) => {
|
|||
url += `&fields=${global.encodeURIComponent(options.fields.join(','))}`;
|
||||
}
|
||||
|
||||
if (options.filter) {
|
||||
url += `&${options.filter}`;
|
||||
}
|
||||
// Only show pages that have children for now
|
||||
url += `&has_children=1`;
|
||||
|
||||
return get(url).then(res => res.body);
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
exports[`AbsoluteDate #time 1`] = `
|
||||
<span>
|
||||
19.09.2016
|
||||
Sep. 19, 2016
|
||||
</span>
|
||||
`;
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
import React from 'react';
|
||||
|
||||
import { ADMIN_URLS, STRINGS } from 'config/wagtail';
|
||||
|
||||
const PageCount = ({ id, count, title }) => (
|
||||
<a
|
||||
href={`${ADMIN_URLS.PAGES}${id}/`}
|
||||
className="c-explorer__see-more"
|
||||
>
|
||||
{STRINGS.EXPLORE_ALL_IN}{' '}
|
||||
<span className="c-explorer__see-more__title">{title}</span>{' '}
|
||||
({count} {count !== 1 ? STRINGS.PAGES : STRINGS.PAGE})
|
||||
</a>
|
||||
);
|
||||
|
||||
PageCount.propTypes = {
|
||||
id: React.PropTypes.number.isRequired,
|
||||
count: React.PropTypes.number.isRequired,
|
||||
title: React.PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default PageCount;
|
|
@ -1,57 +1,8 @@
|
|||
import * as actions from '../actions';
|
||||
import rootReducer from './index';
|
||||
import explorer from './explorer';
|
||||
import nodes from './nodes';
|
||||
import transport from './transport';
|
||||
|
||||
describe('explorer reducers', () => {
|
||||
describe('root', () => {
|
||||
it('exists', () => {
|
||||
expect(rootReducer).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('explorer', () => {
|
||||
it('exists', () => {
|
||||
expect(explorer).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('nodes', () => {
|
||||
it('exists', () => {
|
||||
expect(nodes).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('transport', () => {
|
||||
const initialState = {
|
||||
error: null,
|
||||
showMessage: false,
|
||||
};
|
||||
|
||||
it('exists', () => {
|
||||
expect(transport).toBeDefined();
|
||||
});
|
||||
|
||||
it('returns the initial state', () => {
|
||||
expect(transport(undefined, {})).toEqual(initialState);
|
||||
});
|
||||
|
||||
it('returns error message and flag', () => {
|
||||
const action = actions.fetchFailure(new Error('Test error'));
|
||||
expect(transport(initialState, action)).toEqual({
|
||||
error: 'Test error',
|
||||
showMessage: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('clears previous error message and flag', () => {
|
||||
const action = actions.clearError();
|
||||
const errorState = {
|
||||
error: 'Test error',
|
||||
showMessage: true,
|
||||
};
|
||||
expect(transport(errorState, action)).toEqual(initialState);
|
||||
});
|
||||
describe('root', () => {
|
||||
it('exists', () => {
|
||||
expect(rootReducer).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -34,7 +34,7 @@ class Explorer extends React.Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { isVisible, nodes, path, pageTypes, type, filter, fetching, resolved } = this.props;
|
||||
const { isVisible, nodes, path, pageTypes, type, fetching, resolved } = this.props;
|
||||
const page = this.getPage();
|
||||
|
||||
const explorerProps = {
|
||||
|
@ -43,14 +43,12 @@ class Explorer extends React.Component {
|
|||
page,
|
||||
type,
|
||||
fetching,
|
||||
filter,
|
||||
nodes,
|
||||
resolved,
|
||||
ref: 'explorer',
|
||||
onPop: this.props.onPop,
|
||||
onClose: this.props.onClose,
|
||||
transport: this.props.transport,
|
||||
onFilter: this.props.onFilter,
|
||||
getChildren: this.props.getChildren,
|
||||
loadItemWithChildren: this.props.loadItemWithChildren,
|
||||
pushPage: this.props.pushPage,
|
||||
|
@ -78,7 +76,6 @@ Explorer.propTypes = {
|
|||
resolved: React.PropTypes.bool.isRequired,
|
||||
path: React.PropTypes.array,
|
||||
type: React.PropTypes.string.isRequired,
|
||||
filter: React.PropTypes.string.isRequired,
|
||||
nodes: React.PropTypes.object.isRequired,
|
||||
transport: React.PropTypes.object.isRequired,
|
||||
page: React.PropTypes.any,
|
||||
|
@ -87,7 +84,6 @@ Explorer.propTypes = {
|
|||
setDefaultPage: React.PropTypes.func.isRequired,
|
||||
onShow: React.PropTypes.func.isRequired,
|
||||
onClose: React.PropTypes.func.isRequired,
|
||||
onFilter: React.PropTypes.func.isRequired,
|
||||
getChildren: React.PropTypes.func.isRequired,
|
||||
loadItemWithChildren: React.PropTypes.func.isRequired,
|
||||
pushPage: React.PropTypes.func.isRequired,
|
||||
|
@ -105,7 +101,6 @@ const mapStateToProps = (state) => ({
|
|||
// indexes: state.entities.indexes,
|
||||
nodes: state.nodes,
|
||||
animation: state.explorer.animation,
|
||||
filter: state.explorer.filter,
|
||||
transport: state.transport
|
||||
});
|
||||
|
||||
|
@ -113,7 +108,6 @@ const mapDispatchToProps = (dispatch) => ({
|
|||
setDefaultPage: (id) => dispatch(actions.setDefaultPage(id)),
|
||||
getChildren: (id) => dispatch(actions.fetchChildren(id)),
|
||||
onShow: () => dispatch(actions.fetchRoot()),
|
||||
onFilter: (filter) => dispatch(actions.setFilter(filter)),
|
||||
loadItemWithChildren: (id) => dispatch(actions.fetchPage(id)),
|
||||
pushPage: (id) => dispatch(actions.pushPage(id)),
|
||||
onPop: () => dispatch(actions.popPage()),
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
import React from 'react';
|
||||
import CSSTransitionGroup from 'react-addons-css-transition-group';
|
||||
import { EXPLORER_ANIM_DURATION, EXPLORER_FILTERS } from '../../config/config';
|
||||
import { EXPLORER_ANIM_DURATION } from '../../config/config';
|
||||
import { STRINGS } from '../../config/wagtail';
|
||||
|
||||
import Icon from '../../components/Icon/Icon';
|
||||
import Filter from '../../components/Explorer/Filter';
|
||||
|
||||
const ExplorerHeader = ({ page, depth, filter, onPop, onFilter, transName }) => {
|
||||
const ExplorerHeader = ({ page, depth, onPop, transName }) => {
|
||||
const title = depth < 2 || !page ? STRINGS.PAGES : page.title;
|
||||
|
||||
const transitionProps = {
|
||||
|
@ -34,16 +33,6 @@ const ExplorerHeader = ({ page, depth, filter, onPop, onFilter, transName }) =>
|
|||
</CSSTransitionGroup>
|
||||
</span>
|
||||
</span>
|
||||
<span className="c-explorer__filter">
|
||||
{EXPLORER_FILTERS.map((item) => (
|
||||
<Filter
|
||||
key={item.id}
|
||||
{...item}
|
||||
activeFilter={filter}
|
||||
onFilter={onFilter}
|
||||
/>
|
||||
))}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -51,9 +40,7 @@ const ExplorerHeader = ({ page, depth, filter, onPop, onFilter, transName }) =>
|
|||
ExplorerHeader.propTypes = {
|
||||
page: React.PropTypes.object,
|
||||
depth: React.PropTypes.number,
|
||||
filter: React.PropTypes.string,
|
||||
onPop: React.PropTypes.func,
|
||||
onFilter: React.PropTypes.func,
|
||||
transName: React.PropTypes.string,
|
||||
};
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import Button from '../../components/Button/Button';
|
|||
import PublicationStatus from '../../components/PublicationStatus/PublicationStatus';
|
||||
import AbsoluteDate from '../../components/AbsoluteDate/AbsoluteDate';
|
||||
|
||||
const ExplorerItem = ({ title, typeName, data, filter, onItemClick }) => {
|
||||
const ExplorerItem = ({ title, typeName, data, onItemClick }) => {
|
||||
const { id, meta } = data;
|
||||
const status = meta ? meta.status : null;
|
||||
const time = meta ? meta.latest_revision_created_at : null;
|
||||
|
@ -16,7 +16,7 @@ const ExplorerItem = ({ title, typeName, data, filter, onItemClick }) => {
|
|||
// // TODO refactor.
|
||||
let count = 0;
|
||||
if (meta) {
|
||||
count = filter.match(/has_children/) ? meta.descendants.count - meta.children.count : meta.children.count;
|
||||
count = meta.children.count;
|
||||
}
|
||||
const hasChildren = count > 0;
|
||||
|
||||
|
@ -28,7 +28,7 @@ const ExplorerItem = ({ title, typeName, data, filter, onItemClick }) => {
|
|||
className="c-explorer__children"
|
||||
onClick={onItemClick.bind(null, id)}
|
||||
>
|
||||
<Icon name="folder-inverse" title={STRINGS.SEE_CHILDREN} />
|
||||
<Icon name="arrow-right" title={STRINGS.SEE_CHILDREN} />
|
||||
</span>
|
||||
) : null}
|
||||
|
||||
|
@ -44,13 +44,11 @@ const ExplorerItem = ({ title, typeName, data, filter, onItemClick }) => {
|
|||
ExplorerItem.propTypes = {
|
||||
title: React.PropTypes.string,
|
||||
data: React.PropTypes.object,
|
||||
filter: React.PropTypes.string,
|
||||
typeName: React.PropTypes.string,
|
||||
onItemClick: React.PropTypes.func,
|
||||
};
|
||||
|
||||
ExplorerItem.defaultProps = {
|
||||
filter: '',
|
||||
data: {},
|
||||
onItemClick: () => {},
|
||||
};
|
||||
|
|
|
@ -8,6 +8,7 @@ import { STRINGS } from '../../config/wagtail';
|
|||
import ExplorerHeader from './ExplorerHeader';
|
||||
import ExplorerItem from './ExplorerItem';
|
||||
import LoadingSpinner from './LoadingSpinner';
|
||||
import PageCount from './PageCount';
|
||||
|
||||
export default class ExplorerPanel extends React.Component {
|
||||
constructor(props) {
|
||||
|
@ -105,7 +106,7 @@ export default class ExplorerPanel extends React.Component {
|
|||
}
|
||||
|
||||
renderChildren(page) {
|
||||
const { nodes, pageTypes, filter } = this.props;
|
||||
const { nodes, pageTypes } = this.props;
|
||||
|
||||
if (!page || !page.children.items) {
|
||||
return [];
|
||||
|
@ -122,7 +123,6 @@ export default class ExplorerPanel extends React.Component {
|
|||
title: item.title,
|
||||
typeName,
|
||||
data: item,
|
||||
filter,
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -153,8 +153,6 @@ export default class ExplorerPanel extends React.Component {
|
|||
page,
|
||||
onPop,
|
||||
onClose,
|
||||
onFilter,
|
||||
filter,
|
||||
path,
|
||||
resolved
|
||||
} = this.props;
|
||||
|
@ -169,8 +167,6 @@ export default class ExplorerPanel extends React.Component {
|
|||
page,
|
||||
onPop,
|
||||
onClose,
|
||||
onFilter,
|
||||
filter
|
||||
};
|
||||
|
||||
const transitionTargetProps = {
|
||||
|
@ -202,8 +198,11 @@ export default class ExplorerPanel extends React.Component {
|
|||
{page.isFetching ? <LoadingSpinner key={1} /> : (
|
||||
<div key={0}>
|
||||
{this.getContents()}
|
||||
{(page.children.count > page.children.items.length) && (
|
||||
<PageCount id={page.id} count={page.meta.children.count} title={page.title} />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
</CSSTransitionGroup>
|
||||
|
||||
</div>
|
||||
|
@ -219,8 +218,6 @@ ExplorerPanel.propTypes = {
|
|||
onPop: React.PropTypes.func.isRequired,
|
||||
onClose: React.PropTypes.func.isRequired,
|
||||
type: React.PropTypes.string.isRequired,
|
||||
onFilter: React.PropTypes.func.isRequired,
|
||||
filter: React.PropTypes.string.isRequired,
|
||||
path: React.PropTypes.array,
|
||||
resolved: React.PropTypes.bool.isRequired,
|
||||
init: React.PropTypes.func.isRequired,
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
import React from 'react';
|
||||
|
||||
// TODO Do not use a span for a clickable element.
|
||||
const Filter = ({ label, filter = null, activeFilter, onFilter }) => (
|
||||
<span
|
||||
className={`c-filter${activeFilter === filter ? ' c-filter--active' : ''}`}
|
||||
onClick={onFilter.bind(this, filter)}
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
);
|
||||
|
||||
Filter.propTypes = {
|
||||
label: React.PropTypes.string.isRequired,
|
||||
filter: React.PropTypes.string,
|
||||
activeFilter: React.PropTypes.string,
|
||||
onFilter: React.PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default Filter;
|
|
@ -38,7 +38,6 @@ export function fetchChildren(id = 'root') {
|
|||
|
||||
return admin.getChildPages(id, {
|
||||
fields: explorer.fields,
|
||||
filter: explorer.filter,
|
||||
}).then(json => dispatch(fetchChildrenSuccess(id, json)));
|
||||
};
|
||||
}
|
||||
|
@ -84,23 +83,6 @@ export function fetchRoot() {
|
|||
export const toggleExplorer = createAction('TOGGLE_EXPLORER');
|
||||
|
||||
|
||||
export function setFilter(filter) {
|
||||
return (dispatch, getState) => {
|
||||
const { explorer } = getState();
|
||||
const id = explorer.path[explorer.path.length - 1];
|
||||
|
||||
dispatch({
|
||||
payload: {
|
||||
filter,
|
||||
id,
|
||||
},
|
||||
type: 'SET_FILTER',
|
||||
});
|
||||
|
||||
dispatch(fetchChildren(id));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: determine if page is already loaded, don't load it again, just push.
|
||||
*/
|
||||
|
|
|
@ -10,12 +10,11 @@ const defaultState = {
|
|||
// TODO Change to include less fields (just 'descendants'?) in the next version of the admin API.
|
||||
// Specificies which fields are to be fetched in the API calls.
|
||||
fields: ['title', 'latest_revision_created_at', 'status', 'descendants', 'children'],
|
||||
filter: 'has_children=1',
|
||||
// Coming from the API in order to get translated / pluralised labels.
|
||||
pageTypes: {},
|
||||
};
|
||||
|
||||
export default function explorer(state = defaultState, action) {
|
||||
export default function explorer(state = defaultState, action = {}) {
|
||||
let newNodes = state.path;
|
||||
|
||||
switch (action.type) {
|
||||
|
@ -87,11 +86,6 @@ export default function explorer(state = defaultState, action) {
|
|||
pageTypes: _.assign({}, state.pageTypes, action.payload.json.__types),
|
||||
});
|
||||
|
||||
case 'SET_FILTER':
|
||||
return _.assign({}, state, {
|
||||
filter: action.filter
|
||||
});
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
import * as actions from '../actions';
|
||||
import _ from 'lodash';
|
||||
import rootReducer from './index';
|
||||
import explorer from './explorer';
|
||||
|
||||
describe('explorer', () => {
|
||||
const initialState = {
|
||||
isVisible: false,
|
||||
isFetching: false,
|
||||
isResolved: false,
|
||||
path: [],
|
||||
currentPage: 1,
|
||||
defaultPage: 1,
|
||||
fields: ['title', 'latest_revision_created_at', 'status', 'descendants', 'children'],
|
||||
pageTypes: {},
|
||||
};
|
||||
|
||||
it('exists', () => {
|
||||
expect(explorer).toBeDefined();
|
||||
});
|
||||
it('returns the initial state if no input is provided', () => {
|
||||
expect(explorer(undefined, undefined))
|
||||
.toEqual(initialState);
|
||||
});
|
||||
it('sets the default page', () => {
|
||||
expect(explorer(initialState, {type: 'SET_DEFAULT_PAGE', payload: 100}))
|
||||
.toEqual(_.assign({}, initialState, {defaultPage: 100}))
|
||||
});
|
||||
it('resets the tree', () => {
|
||||
expect(explorer(initialState, {type: 'RESET_TREE', payload: 100}))
|
||||
.toEqual(_.assign({}, initialState, {isFetching: true, currentPage: 100}))
|
||||
});
|
||||
it('has resolved the tree', () => {
|
||||
expect(explorer(initialState, {type: 'TREE_RESOLVED'}))
|
||||
.toEqual(_.assign({}, initialState, {isResolved: true}))
|
||||
});
|
||||
it('toggles the explorer', () => {
|
||||
expect(explorer(initialState, {type: 'TOGGLE_EXPLORER', payload: 100}))
|
||||
.toEqual(
|
||||
_.assign({}, initialState, {isVisible: !initialState.isVisible, currentPage: 100})
|
||||
)
|
||||
});
|
||||
it('starts fetching', () => {
|
||||
expect(explorer(initialState, {type: 'FETCH_START'}))
|
||||
.toEqual(_.assign({}, initialState, {isFetching: true}))
|
||||
});
|
||||
it('pushes a page to the path', () => {
|
||||
expect(explorer(initialState, {type: 'PUSH_PAGE', payload: 100}))
|
||||
.toEqual(_.assign({}, initialState, {path: initialState.path.concat([100])}))
|
||||
});
|
||||
it('pops a page off the path', () => {
|
||||
expect(explorer(_.assign({}, initialState, {path: initialState.path.concat(["root", 100])}), {type: 'POP_PAGE', payload: 100}))
|
||||
.toEqual(_.assign({}, initialState, {path: initialState.path.concat(["root"])}))
|
||||
});
|
||||
});
|
|
@ -34,7 +34,7 @@ const defaultState = {
|
|||
};
|
||||
|
||||
// TODO Why isn't the default state used on init?
|
||||
export default function nodes(state = {}, action) {
|
||||
export default function nodes(state = {}, action = {}) {
|
||||
switch (action.type) {
|
||||
case 'FETCH_CHILDREN_START':
|
||||
// TODO Very hard to understand this code. To refactor.
|
||||
|
@ -67,27 +67,6 @@ export default function nodes(state = {}, action) {
|
|||
case 'RESET_TREE':
|
||||
return defaultState;
|
||||
|
||||
// eslint-disable-next-line no-case-declarations
|
||||
case 'SET_FILTER':
|
||||
// Unset all isLoaded states when the filter changes
|
||||
const updatedState = {};
|
||||
|
||||
// TODO Do not use for in.
|
||||
// TODO Very hard to understand this code. To refactor.
|
||||
// eslint-disable-next-line
|
||||
for (let key in state) {
|
||||
if (state.hasOwnProperty(key)) {
|
||||
// eslint-disable-next-line prefer-const
|
||||
let obj = state[key];
|
||||
obj.children.isLoaded = false;
|
||||
updatedState[obj.id] = _.assign({}, obj, {
|
||||
isLoaded: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return _.assign({}, updatedState);
|
||||
|
||||
case 'FETCH_START':
|
||||
return _.assign({}, state, {
|
||||
[action.payload]: _.assign({}, defaultState, state[action.payload], {
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
import * as actions from '../actions';
|
||||
import _ from 'lodash';
|
||||
import rootReducer from './index';
|
||||
import nodes from './nodes';
|
||||
|
||||
describe('nodes', () => {
|
||||
const initialState = {
|
||||
isError: false,
|
||||
isFetching: false,
|
||||
isLoaded: false,
|
||||
children: {
|
||||
items: [],
|
||||
count: 0,
|
||||
isFetching: false
|
||||
}
|
||||
};
|
||||
|
||||
const fetchingState = {
|
||||
"any": {
|
||||
isFetching: true,
|
||||
isError: false,
|
||||
isLoaded: false,
|
||||
children: {
|
||||
items: [],
|
||||
count: 0,
|
||||
isFetching: false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const fetchingChildren = {
|
||||
isError: false,
|
||||
isFetching: false,
|
||||
isLoaded: false,
|
||||
children: {
|
||||
items: [],
|
||||
count: 0,
|
||||
isFetching: false
|
||||
},
|
||||
"any": {
|
||||
isFetching: true,
|
||||
children: {
|
||||
items: [],
|
||||
count: 0,
|
||||
isFetching: true
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
it('exists', () => {
|
||||
expect(nodes).toBeDefined();
|
||||
});
|
||||
|
||||
it('returns empty state on no action and no input state', () => {
|
||||
expect(nodes(undefined, undefined)).toEqual({});
|
||||
});
|
||||
it('returns initial state on no action and initial state input', () => {
|
||||
expect(nodes(initialState, undefined)).toEqual(initialState);
|
||||
});
|
||||
it('starts fetching children', () => {
|
||||
expect(nodes(initialState, {type: 'FETCH_CHILDREN_START', payload: 'any'})).toEqual(fetchingChildren);
|
||||
});
|
||||
it('resets the tree', () => {
|
||||
expect(nodes({}, {type: 'RESET_TREE'})).toEqual(initialState);
|
||||
});
|
||||
it('starts fetching', () => {
|
||||
expect(nodes({}, {type: 'FETCH_START', payload: 'any'})).toEqual(fetchingState)
|
||||
});
|
||||
it('makes a fetch success', () => {
|
||||
expect(nodes({'any': 'any'}, {type: 'FETCH_SUCCESS'})).toEqual({'any': 'any'})
|
||||
})
|
||||
});
|
|
@ -0,0 +1,36 @@
|
|||
import * as actions from '../actions';
|
||||
import _ from 'lodash';
|
||||
import rootReducer from './index';
|
||||
import transport from './transport';
|
||||
|
||||
describe('transport', () => {
|
||||
const initialState = {
|
||||
error: null,
|
||||
showMessage: false,
|
||||
};
|
||||
|
||||
it('exists', () => {
|
||||
expect(transport).toBeDefined();
|
||||
});
|
||||
|
||||
it('returns the initial state', () => {
|
||||
expect(transport(undefined, {})).toEqual(initialState);
|
||||
});
|
||||
|
||||
it('returns error message and flag', () => {
|
||||
const action = actions.fetchFailure(new Error('Test error'));
|
||||
expect(transport(initialState, action)).toEqual({
|
||||
error: 'Test error',
|
||||
showMessage: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('clears previous error message and flag', () => {
|
||||
const action = actions.clearError();
|
||||
const errorState = {
|
||||
error: 'Test error',
|
||||
showMessage: true,
|
||||
};
|
||||
expect(transport(errorState, action)).toEqual(initialState);
|
||||
});
|
||||
});
|
|
@ -1,5 +1,5 @@
|
|||
$c-explorer-bg: #4C4E4D;
|
||||
$c-explorer-secondary: #aaa;
|
||||
$c-explorer-secondary: #cacaca;
|
||||
$c-explorer-easing: cubic-bezier(0.075, 0.820, 0.165, 1.000);
|
||||
|
||||
.c-explorer, .c-explorer * {
|
||||
|
@ -31,7 +31,7 @@ $c-explorer-easing: cubic-bezier(0.075, 0.820, 0.165, 1.000);
|
|||
padding: .5rem 1rem;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
width: 80%;
|
||||
width: 100%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
|
@ -44,34 +44,6 @@ $c-explorer-easing: cubic-bezier(0.075, 0.820, 0.165, 1.000);
|
|||
}
|
||||
}
|
||||
|
||||
.c-explorer__filter {
|
||||
float: right;
|
||||
width: 50px;
|
||||
margin-top: .5rem;
|
||||
}
|
||||
|
||||
.c-filter {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
padding: 0 .25em;
|
||||
border: solid 1px rgba(255,255,255,0.1);
|
||||
border-radius: 2px;
|
||||
line-height: 1;
|
||||
margin-left: .25rem;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background: rgba(0,0,0,0.5);
|
||||
border-color: rgba(0,0,0,0.5);
|
||||
color: $color-white;
|
||||
}
|
||||
}
|
||||
|
||||
.c-filter--active {
|
||||
color: $color-white;
|
||||
border-color: rgba(255, 255, 255, .5);
|
||||
}
|
||||
|
||||
|
||||
.c-explorer__back {
|
||||
margin-right: .25rem;
|
||||
float: left;
|
||||
|
@ -126,6 +98,7 @@ $c-explorer-easing: cubic-bezier(0.075, 0.820, 0.165, 1.000);
|
|||
|
||||
.c-explorer__item {
|
||||
display: block;
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
|
@ -134,25 +107,35 @@ $c-explorer-easing: cubic-bezier(0.075, 0.820, 0.165, 1.000);
|
|||
}
|
||||
|
||||
.c-explorer__see-more {
|
||||
cursor: pointer;
|
||||
padding: .5rem 1rem;
|
||||
padding: 1rem;
|
||||
background: rgba(0,0,0,0.2);
|
||||
color: $color-white;
|
||||
color: $c-explorer-secondary;
|
||||
display: block;
|
||||
|
||||
&:hover {
|
||||
color: $c-explorer-secondary;
|
||||
background: rgba(0,0,0,0.4);
|
||||
}
|
||||
}
|
||||
|
||||
.c-explorer__see-more__title {
|
||||
color: $color-white;
|
||||
}
|
||||
|
||||
.c-explorer__children {
|
||||
display: inline-block;
|
||||
border-radius: 50rem;
|
||||
border: solid 1px #aaa;
|
||||
color: $color-white;
|
||||
line-height: 1;
|
||||
padding: .5em .3em .5em .5em;
|
||||
padding: .7em .3em .7em .7em;
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
font-size: 2em;
|
||||
|
||||
|
||||
&:hover {
|
||||
background: rgba(0,0,0,0.5);
|
||||
|
@ -162,7 +145,7 @@ $c-explorer-easing: cubic-bezier(0.075, 0.820, 0.165, 1.000);
|
|||
|
||||
.c-status {
|
||||
background: $color-grey-1;
|
||||
color: #ddd;
|
||||
color: $c-explorer-secondary;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .03rem;
|
||||
font-size: 10px;
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
export const PAGES_ROOT_ID = 'root';
|
||||
|
||||
export const EXPLORER_ANIM_DURATION = 220;
|
||||
|
||||
// TODO Add back in when we want to support explorer that displays pages
|
||||
// without children (API call without has_children=1).
|
||||
export const EXPLORER_FILTERS = [
|
||||
{ id: 1, label: 'A', filter: null },
|
||||
{ id: 2, label: 'B', filter: 'has_children=1' }
|
||||
];
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import {
|
||||
PAGES_ROOT_ID,
|
||||
EXPLORER_ANIM_DURATION,
|
||||
EXPLORER_FILTERS,
|
||||
} from './config';
|
||||
|
||||
describe('config', () => {
|
||||
|
@ -17,9 +16,4 @@ describe('config', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('EXPLORER_FILTERS', () => {
|
||||
it('exists', () => {
|
||||
expect(EXPLORER_FILTERS).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,4 +2,4 @@ export const ADMIN_API = global.wagtailConfig.ADMIN_API;
|
|||
export const STRINGS = global.wagtailConfig.STRINGS;
|
||||
export const ADMIN_URLS = global.wagtailConfig.ADMIN_URLS;
|
||||
|
||||
export const DATE_FORMAT = 'DD.MM.YYYY';
|
||||
export const DATE_FORMAT = global.wagtailConfig.DATE_FORMATTING.DATE_FORMAT;
|
||||
|
|
|
@ -13,6 +13,10 @@ global.wagtailConfig = {
|
|||
ADMIN_URLS: {
|
||||
PAGES: '/admin/pages/',
|
||||
},
|
||||
DATE_FORMATTING: {
|
||||
DATE_FORMAT: 'MMM. D, YYYY',
|
||||
SHORT_DATE_FORMAT: 'DD/MM/YYYY',
|
||||
},
|
||||
STRINGS: {
|
||||
EXPLORER: 'Explorer',
|
||||
LOADING: 'Loading...',
|
||||
|
|
Plik diff jest za duży
Load Diff
14
package.json
14
package.json
|
@ -23,14 +23,14 @@
|
|||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.5.1",
|
||||
"babel-core": "^6.5.2",
|
||||
"babel-cli": "^6.22.2",
|
||||
"babel-core": "^6.22.1",
|
||||
"babel-jest": "^18.0.0",
|
||||
"babel-loader": "^6.2.3",
|
||||
"babel-plugin-lodash": "^3.2.9",
|
||||
"babel-polyfill": "^6.5.0",
|
||||
"babel-preset-es2015": "^6.5.0",
|
||||
"babel-preset-react": "^6.5.0",
|
||||
"babel-loader": "^6.2.10",
|
||||
"babel-plugin-lodash": "^3.2.11",
|
||||
"babel-polyfill": "^6.22.0",
|
||||
"babel-preset-es2015": "^6.22.0",
|
||||
"babel-preset-react": "^6.22.0",
|
||||
"enzyme": "^2.3.0",
|
||||
"enzyme-to-json": "^1.4.5",
|
||||
"eslint": "^2.9.0",
|
||||
|
|
|
@ -24,12 +24,22 @@
|
|||
IMAGES: '{% url "wagtailadmin_api_v1:images:listing" %}'
|
||||
};
|
||||
|
||||
// We are using Moment.js formatting syntax for now,
|
||||
// TODO: Use django settings defaults and find a way
|
||||
// to parse them in moment.js
|
||||
wagtailConfig.DATE_FORMATTING = {
|
||||
DATE_FORMAT: 'MMM. D, YYYY',
|
||||
SHORT_DATE_FORMAT: 'DD/MM/YYYY'
|
||||
};
|
||||
|
||||
wagtailConfig.STRINGS = {
|
||||
PAGE: "{% trans 'Page' %}",
|
||||
PAGES: "{% trans 'Pages' %}",
|
||||
LOADING: "{% trans 'Loading...' %}",
|
||||
NO_RESULTS: "{% trans 'No results' %}",
|
||||
SEE_CHILDREN: "{% trans 'See Children' %}",
|
||||
NO_DATE: "{% trans 'No date' %}",
|
||||
EXPLORE_ALL_IN: "{% trans 'Explore all in' %}",
|
||||
};
|
||||
|
||||
wagtailConfig.ADMIN_URLS = {
|
||||
|
|
Ładowanie…
Reference in New Issue