diff --git a/.meteor/packages b/.meteor/packages index e662b375696..7333e819a98 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -95,3 +95,4 @@ johanbrook:publication-collector # Custom Packages +gadicc:blaze-react-component diff --git a/.meteor/versions b/.meteor/versions index e44d08e179a..f02dbcefa7b 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -70,6 +70,7 @@ email@1.1.18 es5-shim@4.6.15 facebook@1.2.10 fastclick@1.0.13 +gadicc:blaze-react-component@1.4.0 geojson-utils@1.0.10 google@1.1.15 hot-code-push@1.0.4 diff --git a/client/modules/accounts/templates/dropdown/dropdown.js b/client/modules/accounts/templates/dropdown/dropdown.js index 10c7f5a4856..7b74a61067c 100644 --- a/client/modules/accounts/templates/dropdown/dropdown.js +++ b/client/modules/accounts/templates/dropdown/dropdown.js @@ -61,8 +61,11 @@ Template.loginDropdown.events({ }); } }); - } else if (this.route || this.name) { + } else if (this.name !== "account/profile") { event.preventDefault(); + /** TMP **/ + Reaction.showActionView(this); + } else if (this.route || this.name) { const route = this.name || this.route; Reaction.Router.go(route); } diff --git a/client/modules/core/main.js b/client/modules/core/main.js index 000cadfc9bc..49e309f8a9c 100644 --- a/client/modules/core/main.js +++ b/client/modules/core/main.js @@ -251,7 +251,7 @@ export default { setActionView(viewData) { if (viewData) { - Session.set("admin/actionView", viewData); + Session.set("admin/actionView", [viewData]); } else { const registryItem = this.getRegistryForCurrentRoute( "settings"); @@ -266,8 +266,87 @@ export default { } }, + pushActionView(viewData) { + Session.set("admin/showActionView", true); + + const actionViewStack = Session.get("admin/actionView"); + + if (viewData) { + actionViewStack.push(viewData); + Session.set("admin/actionView", actionViewStack); + } else { + const registryItem = this.getRegistryForCurrentRoute( + "settings"); + + if (registryItem) { + this.pushActionView(registryItem); + } else { + this.pushActionView({ template: "blankControls" }); + } + } + }, + + isActionViewAtRootView() { + const actionViewStack = Session.get("admin/actionView"); + + if (Array.isArray(actionViewStack) && actionViewStack.length === 1) { + return true; + } + + return false; + }, + + popActionView() { + const actionViewStack = Session.get("admin/actionView"); + actionViewStack.pop(); + + Session.set("admin/actionView", actionViewStack); + + this.setActionViewDetail({}); + }, + + setActionViewDetail(viewData) { + if (viewData) { + Session.set("admin/detailView", [viewData]); + } + }, + + pushActionViewDetail(viewData) { + Session.set("admin/showActionView", true); + + const detailViewStack = Session.get("admin/detailView"); + + if (viewData) { + detailViewStack.push(viewData); + Session.set("admin/detailView", detailViewStack); + } + }, + + popActionViewDetail() { + const detailViewStack = Session.get("admin/detailView"); + detailViewStack.pop(); + + Session.set("admin/detailView", detailViewStack); + }, + getActionView() { - return Session.get("admin/actionView") || {}; + const actionViewStack = Session.get("admin/actionView"); + + if (Array.isArray(actionViewStack) && actionViewStack.length) { + return actionViewStack.pop(); + } + + return {}; + }, + + getActionViewDetail() { + const detailViewStack = Session.get("admin/detailView"); + + if (Array.isArray(detailViewStack) && detailViewStack.length) { + return detailViewStack.pop(); + } + + return {}; }, hideActionView() { @@ -275,10 +354,14 @@ export default { }, clearActionView() { - Session.set("admin/actionView", { + Session.set("admin/actionView", [{ label: "", i18nKeyLabel: "" - }); + }]); + Session.set("admin/detailView", [{ + label: "", + i18nKeyLabel: "" + }]); }, getCurrentTag() { @@ -295,7 +378,8 @@ export default { // find registry entries for routeName const reactionApp = Packages.findOne({ "registry.name": currentRouteName, - "registry.provides": provides + "registry.provides": provides, + "enabled": true }, { enabled: 1, registry: 1, diff --git a/imports/plugins/core/dashboard/client/components/actionView.js b/imports/plugins/core/dashboard/client/components/actionView.js new file mode 100644 index 00000000000..2d2d797378b --- /dev/null +++ b/imports/plugins/core/dashboard/client/components/actionView.js @@ -0,0 +1,227 @@ +import React, { Component, PropTypes } from "react"; +import classnames from "classnames"; +import Blaze from "meteor/gadicc:blaze-react-component"; +import { + IconButton, + Translation +} from "/imports/plugins/core/ui/client/components"; +import { Admin } from "/imports/plugins/core/ui/client/providers"; +import Radium from "radium"; +import Velocity from "velocity-animate"; +import "velocity-animate/velocity.ui"; +import { VelocityTransitionGroup } from "velocity-react"; + +const getStyles = (props) => { + let viewSize = 400; + // if (props.actionView && props.actionView.priority === 1 && props.actionView.provides === "dashboard") { + if (props.actionView && props.actionView.provides === "dashboard") { + viewSize = "90vw"; + } + + return { + base: { + display: "flex", + flexDirection: "column", + height: "100vh", + position: "relative", + width: viewSize + }, + header: { + display: "flex", + alignItems: "center", + position: "relative", + height: "56px", + padding: "0 20px", + margin: 0 + }, + heading: { + display: "flex", + alignItems: "center", + flex: "1 1 auto", + position: "relative", + margin: 0, + height: "100%" + }, + body: { + display: "flex", + webkitOverflowScrolling: "touch" + }, + masterView: { + flex: "1 1 auto", + height: "100%", + overflow: "auto", + webkitOverflowScrolling: "touch" + }, + detailView: { + width: "400px", + height: "100%", + overflow: "auto", + webkitOverflowScrolling: "touch" + }, + title: { + margin: 0, + transition: "200ms all" + }, + titleWithBackButton: { + paddingLeft: 40 + }, + backButton: { + height: "100%", + position: "absolute", + top: 0, + zIndex: 1 + }, + backButtonContainers: { + display: "flex", + alignItems: "center", + height: "100%" + } + }; +}; + +class ActionView extends Component { + static propTypes = { + actionView: PropTypes.object, + actionViewIsOpen: PropTypes.bool, + buttons: PropTypes.array, + isActionViewAtRootView: PropTypes.bool + } + + renderControlComponent() { + if (this.props.actionView && typeof this.props.actionView.template === "string") { + return ( +
+ +
+ ); + } + + return null; + } + + renderDetailComponent() { + if (this.props.detailView && typeof this.props.detailView.template === "string") { + return ( +
+ +
+ ); + } + + return null; + } + + renderFooter() { + // if (this.props.footerTemplate) { + // return ( + // + // ); + // } + } + + renderBackButton() { + if (this.props.isActionViewAtRootView === false) { + return ( +
+
+ +
+
+ ); + } + } + + get styles() { + return getStyles(this.props); + } + + get backButtonEnterAnimation() { + return { + animation: { + display: "flex", + position: "absolute", + left: 20, + opaticy: 1 + }, + duration: 200 + }; + } + + get backButtonLeaveAnimaton() { + return { + animation: { + display: "flex", + position: "absolute", + left: -30, + opaticy: 0 + }, + duration: 200 + + }; + } + + render() { + const { actionView } = this.props; + const baseClassName = classnames({ + "admin-controls": true, + "show-settings": this.props.actionViewIsOpen + }); + + + return ( +
+
+ + {this.renderBackButton()} + + +
+

+ +

+
+ +
+ +
+
+
+ + {this.renderControlComponent()} + {this.renderDetailComponent()} +
+
+
+ {this.renderFooter()} +
+
+ +
+ ); + } +} + +export default Admin()(Radium(ActionView)); diff --git a/imports/plugins/core/dashboard/client/components/index.js b/imports/plugins/core/dashboard/client/components/index.js new file mode 100644 index 00000000000..35a4a4d6ebb --- /dev/null +++ b/imports/plugins/core/dashboard/client/components/index.js @@ -0,0 +1,2 @@ +export { default as ActionView } from "./actionView"; +export { default as PackageList } from "./packageList"; diff --git a/imports/plugins/core/dashboard/client/components/packageList.js b/imports/plugins/core/dashboard/client/components/packageList.js new file mode 100644 index 00000000000..01a86199f98 --- /dev/null +++ b/imports/plugins/core/dashboard/client/components/packageList.js @@ -0,0 +1,62 @@ +import React, { Component, PropTypes } from "react"; +import { Card, CardHeader, CardBody, List, ListItem } from "/imports/plugins/core/ui/client/components" +import { map } from "lodash" +class PackageList extends Component { + + // renderPackages() { + // if (Array.isArray(this.props.packages)) { + // return this.props.packages.map((packageData) => { + // return ( + // + // ); + // }); + // } + // } + + renderPackages() { + if (true) { + return map(this.props.groupedPackages, (group, name) => { + + const items = group.map((packageData) => { + return ( + + ); + }) + + + return ( + + + + {items} + + + ) + + }); + } + } + render() { + return ( + + {this.renderPackages()} + + ); + } +} + +export default PackageList; diff --git a/imports/plugins/core/dashboard/client/containers/actionViewContainer.js b/imports/plugins/core/dashboard/client/containers/actionViewContainer.js new file mode 100644 index 00000000000..14513db31a7 --- /dev/null +++ b/imports/plugins/core/dashboard/client/containers/actionViewContainer.js @@ -0,0 +1,91 @@ +import React, { Component, PropTypes } from "react"; +import { composeWithTracker } from "/lib/api/compose"; +import { Admin } from "../components" + +import { Meteor } from "meteor/meteor"; +import { Blaze } from "meteor/blaze"; +import { Template } from "meteor/templating"; +import { Reaction, i18next } from "/client/api"; +import { Packages } from "/lib/collections"; + +import { TranslationProvider, AdminContextProvider } from "/imports/plugins/core/ui/client/providers"; +import { Loading } from "/imports/plugins/core/ui/client/components"; + + +function handleActionViewBack() { + Reaction.popActionView(); +} + +function handleActionViewClose() { + Reaction.hideActionView(); +} + +function composer(props, onData) { + const shortcuts = Reaction.Apps({ provides: "shortcut", enabled: true }); + const items = []; + + if (_.isArray(shortcuts)) { + for (const shortcut of shortcuts) { + if (!shortcut.container) { + items.push({ + type: "link", + href: Reaction.Router.pathFor(shortcut.name), + className: Reaction.Router.isActiveClassName(shortcut.name), + icon: shortcut.icon, + tooltip: shortcut.label || "", + i18nKeyTooltip: shortcut.i18nKeyLabel, + tooltipPosition: "left middle" + }); + } + } + } + + items.push({ type: "seperator" }); + + items.push({ + icon: "plus", + tooltip: "Create Content", + i18nKeyTooltip: "app.createContent", + tooltipPosition: "left middle", + // onClick(event) { + // if (!instance.dropInstance) { + // instance.dropInstance = new Drop({ target: event.currentTarget, content: "", constrainToWindow: true, classes: "drop-theme-arrows", position: "right center" }); + // + // Blaze.renderWithData(Template.createContentMenu, {}, instance.dropInstance.content); + // } + // + // instance.dropInstance.open(); + // } + }); + + + + + onData(null, { + isAdminArea: true, + actionView: Reaction.getActionView(), + detailView: Reaction.getActionViewDetail(), + data: props.data, + buttons: items, + isActionViewAtRootView: Reaction.isActionViewAtRootView(), + actionViewIsOpen: Reaction.isActionViewOpen(), + + // Callbacks + handleActionViewBack, + handleActionViewClose + }); +} + +export default function ActionViewContainer(Comp) { + function CompositeComponent(props) { + return ( + + + + + + ); + } + + return composeWithTracker(composer, Loading)(CompositeComponent); +} diff --git a/imports/plugins/core/dashboard/client/containers/index.js b/imports/plugins/core/dashboard/client/containers/index.js new file mode 100644 index 00000000000..cee580eb26b --- /dev/null +++ b/imports/plugins/core/dashboard/client/containers/index.js @@ -0,0 +1,2 @@ +export { default as PackageListContainer } from "./packageListContainer"; +export { default as ActionViewContainer } from "./actionViewContainer"; diff --git a/imports/plugins/core/dashboard/client/containers/packageListContainer.js b/imports/plugins/core/dashboard/client/containers/packageListContainer.js new file mode 100644 index 00000000000..dd92f405ba7 --- /dev/null +++ b/imports/plugins/core/dashboard/client/containers/packageListContainer.js @@ -0,0 +1,68 @@ +import React from "react"; +import { groupBy } from "lodash"; +import { composeWithTracker } from "/lib/api/compose"; +import { Reaction } from "/client/api"; +import { Loading } from "/imports/plugins/core/ui/client/components"; +import { TranslationProvider } from "/imports/plugins/core/ui/client/providers"; + +/** + * handleShowPackage - Push package into action view navigation stack + * @param {SyntheticEvent} event Original event + * @param {Object} app Package data + * @return {undefined} No return value + */ +function handleShowPackage(event, app) { + Reaction.pushActionView(app); +} + +function composer(props, onData) { + const settings = Reaction.Apps({ provides: "settings", enabled: true }) || []; + + const dashboard = Reaction.Apps({ provides: "dashboard", enabled: true }).filter((d) => typeof d.template !== "undefined") || []; + + + + // const packages = apps.map((packageData) => { + // const appData = Reaction.Apps({ + // provides: "settings", + // name: packageData.packageName + // }); + // + // if ((!packageData.route || !packageData.template) && appData.length) { + // return { + // ...packageData, + // ...appData[0] + // }; + // } + // + // return packageData; + // }); + + // const groupedPackages = groupBy(packages, (app) => { + // return app.container || "misc"; + // }); + + onData(null, { + // packages, + groupedPackages: { + dashboard: dashboard, + settings: settings + }, + // groups: Object.keys(groupedPackages), + + // Callbacks + handleShowPackage + }); +} + +export default function PackageListContainer(Comp) { + function CompositeComponent(props) { + return ( + + + + ); + } + + return composeWithTracker(composer, Loading)(CompositeComponent); +} diff --git a/imports/plugins/core/dashboard/client/index.js b/imports/plugins/core/dashboard/client/index.js index b93b61b28ff..62272977648 100644 --- a/imports/plugins/core/dashboard/client/index.js +++ b/imports/plugins/core/dashboard/client/index.js @@ -6,6 +6,7 @@ import "./templates/packages/grid/grid.js"; import "./templates/packages/grid/package.html"; import "./templates/packages/grid/package.js"; import "./templates/packages/packages.html"; +import "./templates/packages/packages.js"; import "./templates/settings/settings.html"; import "./templates/settings/settings.js"; diff --git a/imports/plugins/core/dashboard/client/templates/packages/grid/package.js b/imports/plugins/core/dashboard/client/templates/packages/grid/package.js index 159454a7f7c..bdae24a8374 100644 --- a/imports/plugins/core/dashboard/client/templates/packages/grid/package.js +++ b/imports/plugins/core/dashboard/client/templates/packages/grid/package.js @@ -1,5 +1,4 @@ import { Reaction } from "/client/api"; - /* eslint no-loop-func: 0 */ /** @@ -59,7 +58,7 @@ Template.gridPackage.helpers({ controls.push({ icon: app.icon || "fa fa-cog fa-fw", onClick() { - Reaction.showActionView(app); + Reaction.pushActionView(app); } }); } @@ -68,7 +67,7 @@ Template.gridPackage.helpers({ controls.push({ icon: "angle-right", onClick() { - showPackageDashboard(data.package); + Reaction.pushActionView(data.package); } }); } @@ -76,7 +75,7 @@ Template.gridPackage.helpers({ return { controls, onContentClick() { - showPackageDashboard(data.package); + Reaction.pushActionView(data.package); } }; }, diff --git a/imports/plugins/core/dashboard/client/templates/packages/packages.html b/imports/plugins/core/dashboard/client/templates/packages/packages.html index 86b4875dea7..d4affa92562 100644 --- a/imports/plugins/core/dashboard/client/templates/packages/packages.html +++ b/imports/plugins/core/dashboard/client/templates/packages/packages.html @@ -1,5 +1,5 @@ diff --git a/imports/plugins/core/dashboard/client/templates/packages/packages.js b/imports/plugins/core/dashboard/client/templates/packages/packages.js new file mode 100644 index 00000000000..15fc8a9e184 --- /dev/null +++ b/imports/plugins/core/dashboard/client/templates/packages/packages.js @@ -0,0 +1,10 @@ +import { PackageList } from "../../components"; +import { PackageListContainer } from "../../containers"; + +Template.dashboardPackages.helpers({ + PackageListComponent() { + return { + component: PackageListContainer(PackageList) + }; + } +}); diff --git a/imports/plugins/core/dashboard/client/templates/settings/settings.html b/imports/plugins/core/dashboard/client/templates/settings/settings.html index 3d9e8020949..f94e393f60e 100644 --- a/imports/plugins/core/dashboard/client/templates/settings/settings.html +++ b/imports/plugins/core/dashboard/client/templates/settings/settings.html @@ -10,6 +10,11 @@