disco_app 0.8.9 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/disco_app/icons.svg +0 -0
  3. data/app/assets/javascripts/disco_app/components/{filterable_shop_list.js.jsx → custom/filterable_shop_list.js.jsx} +1 -1
  4. data/app/assets/javascripts/disco_app/components/custom/inline-radio-options.es6.jsx +59 -0
  5. data/app/assets/javascripts/disco_app/components/custom/rules-editor.es6.jsx +360 -0
  6. data/app/assets/javascripts/disco_app/components/{shop_list.js.jsx → custom/shop_list.js.jsx} +9 -11
  7. data/app/assets/javascripts/disco_app/components/custom/shop_row.js.jsx +43 -0
  8. data/app/assets/javascripts/disco_app/components/ui-kit/cards/card-section.es6.jsx +30 -0
  9. data/app/assets/javascripts/disco_app/components/ui-kit/cards/card.es6.jsx +9 -0
  10. data/app/assets/javascripts/disco_app/components/ui-kit/cards/cart-section-title.es6.jsx +7 -0
  11. data/app/assets/javascripts/disco_app/components/ui-kit/forms/base_form.es6.jsx +72 -0
  12. data/app/assets/javascripts/disco_app/components/ui-kit/forms/base_input.es6.jsx +20 -0
  13. data/app/assets/javascripts/disco_app/components/ui-kit/forms/button.es6.jsx +13 -0
  14. data/app/assets/javascripts/disco_app/components/ui-kit/forms/input-radio.es6.jsx +30 -0
  15. data/app/assets/javascripts/disco_app/components/ui-kit/forms/input-select.es6.jsx +39 -0
  16. data/app/assets/javascripts/disco_app/components/ui-kit/forms/input-text.es6.jsx +59 -0
  17. data/app/assets/javascripts/disco_app/components/ui-kit/forms/input-textarea.es6.jsx +48 -0
  18. data/app/assets/javascripts/disco_app/components/ui-kit/icons/icon-chevron.es6.jsx +33 -0
  19. data/app/assets/javascripts/disco_app/components/ui-kit/icons/next-icon.es6.jsx +18 -0
  20. data/app/assets/javascripts/disco_app/components/ui-kit/input_select.es6.jsx +21 -0
  21. data/app/assets/javascripts/disco_app/components/ui-kit/ui-layout/ui-annotated-section.es6.jsx +29 -0
  22. data/app/assets/javascripts/disco_app/components/ui-kit/ui-layout/ui-empty-state.es6.jsx +35 -0
  23. data/app/assets/javascripts/disco_app/components/ui-kit/ui-layout/ui-footer-help.es6.jsx +13 -0
  24. data/app/assets/javascripts/disco_app/components/ui-kit/ui-layout/ui-page-actions.es6.jsx +39 -0
  25. data/app/assets/javascripts/disco_app/components.js +1 -4
  26. data/app/assets/javascripts/disco_app/disco_app.js +3 -0
  27. data/app/assets/javascripts/disco_app/ui-kit.js +1 -0
  28. data/app/assets/stylesheets/disco_app/admin/_header.scss +66 -0
  29. data/app/assets/stylesheets/disco_app/admin/_layout.scss +40 -0
  30. data/app/assets/stylesheets/disco_app/admin/_nav.scss +172 -0
  31. data/app/assets/stylesheets/disco_app/admin.scss +11 -0
  32. data/app/assets/stylesheets/disco_app/disco_app.scss +12 -12
  33. data/app/assets/stylesheets/disco_app/{disco/mixins → mixins}/_flexbox.scss +6 -0
  34. data/app/assets/stylesheets/disco_app/ui-kit/_ui-empty-state.scss +94 -0
  35. data/app/assets/stylesheets/disco_app/ui-kit/_ui-footer-help.scss +25 -0
  36. data/app/assets/stylesheets/disco_app/ui-kit/_ui-icons.scss +28 -0
  37. data/app/assets/stylesheets/disco_app/ui-kit/_ui-kit.scss +5086 -0
  38. data/app/assets/stylesheets/disco_app/ui-kit/_ui-layout.scss +10 -0
  39. data/app/assets/stylesheets/disco_app/ui-kit/_ui-page-actions.scss +21 -0
  40. data/app/assets/stylesheets/disco_app/{disco/_tabs.scss → ui-kit/_ui-tabs.scss} +3 -1
  41. data/app/assets/stylesheets/disco_app/ui-kit/_ui-type.scss +13 -0
  42. data/app/controllers/disco_app/admin/concerns/plans_controller.rb +8 -5
  43. data/app/controllers/disco_app/admin/concerns/subscriptions_controller.rb +32 -0
  44. data/app/controllers/disco_app/admin/subscriptions_controller.rb +3 -0
  45. data/app/helpers/disco_app/application_helper.rb +22 -0
  46. data/app/models/disco_app/concerns/plan.rb +2 -2
  47. data/app/models/disco_app/concerns/shop.rb +0 -4
  48. data/app/models/disco_app/concerns/subscription.rb +12 -0
  49. data/app/resources/disco_app/admin/resources/concerns/shop_resource.rb +40 -3
  50. data/app/views/disco_app/admin/plans/_form.html.erb +18 -21
  51. data/app/views/disco_app/admin/plans/_plan_code_fields.html.erb +15 -0
  52. data/app/views/disco_app/admin/plans/index.html.erb +2 -0
  53. data/app/views/disco_app/admin/shops/index.html.erb +2 -1
  54. data/app/views/disco_app/admin/subscriptions/edit.html.erb +33 -0
  55. data/app/views/disco_app/shared/_icons.html.erb +3 -0
  56. data/app/views/layouts/admin/_nav_items.erb +20 -0
  57. data/app/views/layouts/admin.html.erb +53 -9
  58. data/app/views/layouts/embedded_app.html.erb +2 -0
  59. data/app/views/layouts/embedded_app_modal.html.erb +11 -0
  60. data/config/routes.rb +4 -2
  61. data/lib/disco_app/engine.rb +2 -1
  62. data/lib/disco_app/version.rb +1 -1
  63. data/lib/generators/disco_app/disco_app_generator.rb +35 -2
  64. data/lib/generators/disco_app/templates/assets/javascripts/components.js +3 -0
  65. data/lib/generators/disco_app/templates/config/database.yml.tt +20 -0
  66. data/lib/tasks/database.rake +8 -0
  67. data/test/controllers/disco_app/charges_controller_test.rb +9 -2
  68. data/test/fixtures/api/widget_store/charges/create_recurring_application_charge_request.json +1 -1
  69. data/test/fixtures/api/widget_store/charges/create_second_recurring_application_charge_request.json +1 -1
  70. data/test/fixtures/disco_app/subscriptions.yml +1 -0
  71. data/test/models/disco_app/subscription_test.rb +19 -0
  72. data/test/services/disco_app/charges_service_test.rb +9 -2
  73. data/test/test_helper.rb +3 -0
  74. metadata +80 -21
  75. data/app/assets/javascripts/disco_app/components/shop_row.js.jsx +0 -27
  76. data/app/assets/stylesheets/disco_app/bootstrap/_custom.scss +0 -54
  77. data/app/assets/stylesheets/disco_app/bootstrap/_variables.scss +0 -872
  78. data/app/assets/stylesheets/disco_app/disco/_buttons.scss +0 -31
  79. data/app/assets/stylesheets/disco_app/disco/_cards.scss +0 -52
  80. data/app/assets/stylesheets/disco_app/disco/_forms.scss +0 -23
  81. data/app/assets/stylesheets/disco_app/disco/_grid.scss +0 -58
  82. data/app/assets/stylesheets/disco_app/disco/_sections.scss +0 -61
  83. data/app/assets/stylesheets/disco_app/disco/_tables.scss +0 -57
  84. data/app/assets/stylesheets/disco_app/disco/_type.scss +0 -39
  85. data/app/views/layouts/admin/_navbar.html.erb +0 -25
  86. data/lib/generators/disco_app/adminify/adminify_generator.rb +0 -35
  87. data/lib/generators/disco_app/reactify/reactify_generator.rb +0 -45
  88. /data/app/assets/javascripts/disco_app/components/{shop_filter_tab.js.jsx → custom/shop_filter_tab.js.jsx} +0 -0
  89. /data/app/assets/javascripts/disco_app/components/{shop_filter_tabs.js.jsx → custom/shop_filter_tabs.js.jsx} +0 -0
  90. /data/app/assets/javascripts/disco_app/components/{shopify_admin_link.js.jsx → custom/shopify_admin_link.js.jsx} +0 -0
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Base class for form components that provides helper methods
3
+ * for rendering errors associated with the form
4
+ **/
5
+ class BaseForm extends React.Component {
6
+
7
+ /**
8
+ * check if the field parameter has errors associated.
9
+ * if no parameters are given, it checks if there's at least an error at all
10
+ **/
11
+ hasErrors(field) {
12
+ if ((arguments.length === 0 && this.errorKeys().length > 0) ||
13
+ (this.props.errors && this.props.errors.errors.indexOf(field) > -1)) {
14
+ return true;
15
+ }
16
+ return false;
17
+ }
18
+
19
+ /**
20
+ * returns a list of fields that contain errors
21
+ **/
22
+ errorKeys() {
23
+ return this.props.errors.errors;
24
+ }
25
+
26
+ /**
27
+ * returns the type of resource associate with this error
28
+ **/
29
+ errorType() {
30
+ return this.props.errors.type;
31
+ }
32
+
33
+ /**
34
+ * returns the error messages
35
+ **/
36
+ errorMessages() {
37
+ return this.props.errors.messages;
38
+ }
39
+
40
+ /**
41
+ * renders basic form errors
42
+ **/
43
+ renderErrors() {
44
+ if (!this.hasErrors()) {
45
+ return null;
46
+ }
47
+
48
+ var title = "There " + (this.errorMessages().length == 1 ? "is" : "are") + " " + this.errorMessages().length + " error" + (this.errorMessages().length > 1 ? "s" : "") + " for this " + this.errorType() + ":";
49
+ var errorMessages = this.errorMessages().map(function(message) {
50
+ return <li>{message}</li>;
51
+ });
52
+
53
+ return (
54
+ <div className="ui-banner ui-banner--status-error ui-banner--default-vertical-spacing ui-banner--default-horizontal-spacing">
55
+ <div className="ui-banner__ribbon">
56
+ <svg className="next-icon next-icon--24" viewBox="0 0 24 24">
57
+ <path d="M12 0C5.4 0 0 5.4 0 12s5.4 12 12 12 12-5.4 12-12S18.6 0 12 0zm0 4c1.4 0 2.7.4 3.9 1L12 8.8 8.8 12 5 15.9c-.6-1.1-1-2.5-1-3.9 0-4.4 3.6-8 8-8zm0 16c-1.4 0-2.7-.4-3.9-1l3.9-3.9 3.2-3.2L19 8.1c.6 1.1 1 2.5 1 3.9 0 4.4-3.6 8-8 8z"></path>
58
+ </svg>
59
+ </div>
60
+ <div className="ui-banner__content">
61
+ <h2 className="ui-banner__title">
62
+ {title}
63
+ </h2>
64
+ <ul>
65
+ {errorMessages}
66
+ </ul>
67
+ </div>
68
+ </div>
69
+ )
70
+ }
71
+
72
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Base class providing helper method for deciding if an input contains errors.
3
+ * Expects subclasses to have `name` and `errors` props.
4
+ **/
5
+ class BaseInput extends React.Component {
6
+
7
+ /**
8
+ * Checks if the component has associated errors or not
9
+ **/
10
+ hasError() {
11
+ if (!(this.props && this.props.name)) {
12
+ return false;
13
+ }
14
+ var fieldName = this.props.name.substring(this.props.name.lastIndexOf("[") + 1, this.props.name.lastIndexOf("]"));
15
+ return (fieldName &&
16
+ this.props.errors &&
17
+ this.props.errors.errors &&
18
+ this.props.errors.errors.indexOf(fieldName) > -1);
19
+ }
20
+ }
@@ -0,0 +1,13 @@
1
+ const Button = ({ children, disabled, onClick }) => {
2
+
3
+ const className = classNames({
4
+ 'btn': true
5
+ });
6
+
7
+ return(
8
+ <button type="button" disabled={disabled} className={className} onClick={onClick}>
9
+ {children}
10
+ </button>
11
+ )
12
+
13
+ };
@@ -0,0 +1,30 @@
1
+ const InputRadio = ({ label, name, value, checked, inline, isLast, onChange }) => {
2
+
3
+ const id = `${name}[${value}]`;
4
+
5
+ const wrapperClassName = classNames({
6
+ 'next-input-wrapper': true,
7
+ 'inline': inline,
8
+ 'sr': !isLast
9
+ });
10
+
11
+ const labelClassName = classNames({
12
+ 'next-label': true,
13
+ 'next-label--switch': true,
14
+ 'inline': inline,
15
+ 'fw-normal': inline
16
+ });
17
+
18
+ const handleChange = (e) => {
19
+ onChange(e.target.value);
20
+ };
21
+
22
+ return(
23
+ <div className={wrapperClassName}>
24
+ <label htmlFor={id} className={labelClassName}>{label}</label>
25
+ <input id={id} className="next-radio" type="radio" value={value} name={name} checked={checked} onChange={handleChange} />
26
+ <span className="next-radio--styled" />
27
+ </div>
28
+ )
29
+
30
+ };
@@ -0,0 +1,39 @@
1
+ const InputSelect = ({ id, label, labelHidden, name, options, value, onChange }) => {
2
+
3
+ const optionElements = options.map((option) => {
4
+ return <option key={option.value} value={option.value}>{option.label}</option>;
5
+ });
6
+
7
+ const labelClassName = classNames({
8
+ 'next-label': true,
9
+ 'helper--visually-hidden': labelHidden
10
+ });
11
+
12
+ const handleChange = (e) => {
13
+ onChange(e.target.value);
14
+ };
15
+
16
+ return(
17
+ <div className="next-input-wrapper">
18
+ <label className={labelClassName} htmlFor={id}>{label}</label>
19
+ <div className="next-select__wrapper next-input--has-content">
20
+ <select className="next-select rule-field" id={id} name={name} value={value} onChange={handleChange}>
21
+ {optionElements}
22
+ </select>
23
+ <NextIcon name="next-chevron-down" size={12} />
24
+ </div>
25
+ </div>
26
+ )
27
+
28
+ };
29
+
30
+ InputSelect.propTypes = {
31
+ label: React.PropTypes.string.isRequired,
32
+ name: React.PropTypes.string,
33
+ options: React.PropTypes.arrayOf(
34
+ React.PropTypes.shape({
35
+ label: React.PropTypes.string.isRequired,
36
+ value: React.PropTypes.string.isRequired
37
+ })
38
+ ).isRequired
39
+ };
@@ -0,0 +1,59 @@
1
+ class InputText extends BaseInput {
2
+
3
+ render() {
4
+ const { errors, name, value, defaultValue, disabled, helpMessage, label, labelHidden, onChange, placeholder } = this.props;
5
+
6
+ const wrapperClassName = classNames({
7
+ 'next-input-wrapper': true,
8
+ 'next-input-wrapper--is-error': this.hasError()
9
+ });
10
+
11
+ const labelClassName = classNames({
12
+ 'next-label': true,
13
+ 'helper--visually-hidden': labelHidden
14
+ });
15
+
16
+ const handleChange = (e) => {
17
+ onChange(e.target.value);
18
+ };
19
+
20
+ let helpElement = null;
21
+ if(helpMessage) {
22
+ helpElement = <p className="next-input__help-text">{helpMessage}</p>;
23
+ }
24
+
25
+ return (
26
+ <div className={wrapperClassName}>
27
+ <label className={labelClassName} htmlFor={name}>{label}</label>
28
+ <input
29
+ id={name}
30
+ className="next-input"
31
+ disabled={disabled}
32
+ value={value}
33
+ defaultValue={defaultValue}
34
+ name={name}
35
+ onChange={handleChange}
36
+ placeholder={placeholder}
37
+ type="text"
38
+ />
39
+ {helpElement}
40
+ </div>
41
+ );
42
+ }
43
+ }
44
+
45
+ InputText.propTypes = {
46
+ errors: React.PropTypes.object,
47
+ label: React.PropTypes.string.isRequired,
48
+ name: React.PropTypes.string,
49
+ onChange: React.PropTypes.func,
50
+ placeholder: React.PropTypes.string,
51
+ helpMessage: React.PropTypes.string,
52
+ error: React.PropTypes.bool,
53
+ disabled: React.PropTypes.bool
54
+ };
55
+
56
+ InputText.defaultProps = {
57
+ errors: {},
58
+ disabled: false
59
+ };
@@ -0,0 +1,48 @@
1
+ class InputTextArea extends BaseInput {
2
+
3
+ render() {
4
+ const { errors, defaultValue, label, name, onChange, placeholder, helpMessage } = this.props;
5
+
6
+ const wrapperClassName = classNames({
7
+ 'next-input-wrapper': true,
8
+ 'next-input-wrapper--is-error': this.hasError()
9
+ });
10
+
11
+ const handleChange = (e) => {
12
+ onChange(e.target.value);
13
+ };
14
+
15
+ let helpElement = null;
16
+ if(helpMessage) {
17
+ helpElement = <p className="next-input__help-text">{helpMessage}</p>;
18
+ }
19
+
20
+ return (
21
+ <div className={wrapperClassName}>
22
+ <label className="next-label" htmlFor={name}>{label}</label>
23
+ <textarea
24
+ className="next-textarea"
25
+ defaultValue={defaultValue}
26
+ name={name}
27
+ onChange={handleChange}
28
+ placeholder={placeholder}
29
+ />
30
+ {helpElement}
31
+ </div>
32
+ );
33
+ }
34
+ };
35
+
36
+ InputTextArea.propTypes = {
37
+ errors: React.PropTypes.object,
38
+ defaultValue: React.PropTypes.string,
39
+ label: React.PropTypes.string.isRequired,
40
+ name: React.PropTypes.string.isRequired,
41
+ onChange: React.PropTypes.func.isRequired,
42
+ placeholder: React.PropTypes.string,
43
+ helpMessage: React.PropTypes.string
44
+ };
45
+
46
+ InputTextArea.defaultProps = {
47
+ errors: {},
48
+ };
@@ -0,0 +1,33 @@
1
+ const IconChevron = ({ size, direction, disabled }) => {
2
+
3
+ const iconClasses = classNames({
4
+ "next-icon": true,
5
+ "next-icon--blue": disabled === false,
6
+ "next-icon--sky-darker": disabled,
7
+ "next-icon--rotate-180": direction === 'previous',
8
+ ['next-icon--' + size]: true
9
+ });
10
+
11
+ return (
12
+ <svg
13
+ aria-labelledby="next-chevron"
14
+ role="img"
15
+ className={iconClasses}
16
+ xmlns="http://www.w3.org/2000/svg"
17
+ viewBox="0 0 28 28">
18
+
19
+ <path d="M7,3.8l10.5,10.5L7,24.7l2.7,2.7L23,14.3L9.7,1C9.7,1,7,3.8,7,3.8z" />
20
+ </svg>
21
+ );
22
+ };
23
+
24
+ IconChevron.propTypes = {
25
+ direction: React.PropTypes.oneOf(['next', 'previous']).isRequired,
26
+ disabled: React.PropTypes.bool,
27
+ size: React.PropTypes.number
28
+ };
29
+
30
+ IconChevron.defaultProps = {
31
+ disabled: false,
32
+ size: 10
33
+ };
@@ -0,0 +1,18 @@
1
+ const NextIcon = ({ size, name }) => {
2
+
3
+ const className = classNames({
4
+ "next-icon": true,
5
+ ['next-icon--size-' + size]: true
6
+ });
7
+
8
+ return (
9
+ <svg className={className}>
10
+ <use xlinkHref={'#' + name} />
11
+ </svg>
12
+ );
13
+ };
14
+
15
+ NextIcon.propTypes = {
16
+ size: React.PropTypes.number,
17
+ name: React.PropTypes.string
18
+ };
@@ -0,0 +1,21 @@
1
+ const InputSelectOld = ({ label, name, options, value, onChange }) => {
2
+
3
+ const id = name;
4
+
5
+ const optionElements = options.map((option) => {
6
+ return <option key={option.value} value={option.value}>{option.label}</option>;
7
+ });
8
+
9
+ const handleChange = (e) => {
10
+ onChange(e.target.value);
11
+ };
12
+
13
+ return(
14
+ <div className="next-input-wrapper next-input-wrapper--halved">
15
+ <select id={id} name={name} value={value} onChange={handleChange}>
16
+ {optionElements}
17
+ </select>
18
+ </div>
19
+ )
20
+
21
+ };
@@ -0,0 +1,29 @@
1
+ const UIAnnotatedSection = ({ title, description, children }) => {
2
+
3
+ return (
4
+ <section className="ui-annotated-section">
5
+
6
+ <div className="ui-annotated-section__annotation">
7
+ <div className="ui-annotated-section__title">
8
+ <h2 className="next-heading next-heading--no-margin">{title}</h2>
9
+ </div>
10
+
11
+ <div className="ui-annotated-section__description">
12
+ <p>{description}</p>
13
+ </div>
14
+ </div>
15
+
16
+ <div className="ui-annotated-section__content">
17
+ {children}
18
+ </div>
19
+
20
+ </section>
21
+ );
22
+
23
+ };
24
+
25
+ UIAnnotatedSection.propTypes = {
26
+ title: React.PropTypes.string.isRequired,
27
+ description: React.PropTypes.string,
28
+ children: React.PropTypes.node
29
+ };
@@ -0,0 +1,35 @@
1
+ const UIEmptyState = ({ title, subtitle, image, href, label }) => {
2
+
3
+ let imageSubsection = null;
4
+ if(image) {
5
+ imageSubsection = (
6
+ <div className="ui-empty-state__subsection">
7
+ <div className="ui-empty-state__items ui-empty-state__items--odd-queries ui-empty-state__items--quantity-queries">
8
+ <div className="ui-empty-state__item">
9
+ <div className="ui-empty-state__subitems">
10
+ <div className="ui-empty-state__subitem">
11
+ <img src={image} alt={title} />
12
+ </div>
13
+ </div>
14
+ </div>
15
+ </div>
16
+ </div>
17
+ );
18
+ }
19
+
20
+ return(
21
+ <div className="ui-empty-state">
22
+ <div className="ui-empty-state__section">
23
+ <div className="ui-empty-state__subsection">
24
+ <h1 className="next-heading next-heading--xl">{title}</h1>
25
+ <h2 className="next-heading next-heading--subdued">{subtitle}</h2>
26
+ </div>
27
+ {imageSubsection}
28
+ <div className="ui-empty-state__subsection">
29
+ <a className="btn btn-large btn-primary" href={href}>{label}</a>
30
+ </div>
31
+ </div>
32
+ </div>
33
+ )
34
+
35
+ };
@@ -0,0 +1,13 @@
1
+ const UIFooterHelp = ({ __html }) => {
2
+
3
+ return(
4
+ <div className="ui-footer-help">
5
+ <div className="ui-footer-help__content">
6
+ <div>
7
+ <p dangerouslySetInnerHTML={{__html: __html}} />
8
+ </div>
9
+ </div>
10
+ </div>
11
+ )
12
+
13
+ };
@@ -0,0 +1,39 @@
1
+ const UIPageActions = ({ label, disabled, secondaryHref, secondaryLabel }) => {
2
+
3
+ const buttonClassName = classNames({
4
+ 'btn': true,
5
+ 'btn-primary': !disabled,
6
+ 'disabled': disabled
7
+ });
8
+
9
+ let secondaryElement = null;
10
+ if(secondaryHref) {
11
+ secondaryElement = (
12
+ <div className="ui-page-actions__secondary">
13
+ <div className="button-group">
14
+ <a className="btn" href={secondaryHref}>{secondaryLabel}</a>
15
+ </div>
16
+ </div>
17
+ );
18
+ }
19
+
20
+ return (
21
+ <div className="ui-page-actions">
22
+ {secondaryElement}
23
+ <div className="ui-page-actions__primary">
24
+ <div className="button-group button-group--right-aligned">
25
+ <button name="button" type="submit" className={buttonClassName} disabled={disabled}>
26
+ {label}
27
+ </button>
28
+ </div>
29
+ </div>
30
+ </div>
31
+ );
32
+ };
33
+
34
+ UIPageActions.propTypes = {
35
+ label: React.PropTypes.string.isRequired,
36
+ disabled: React.PropTypes.bool,
37
+ secondaryHref: React.PropTypes.string,
38
+ secondaryLabel: React.PropTypes.string
39
+ };
@@ -1,5 +1,2 @@
1
- /**
2
- * disco_app/components.js
3
- * React components common to Disco applications.
4
- */
1
+ //= require classnames
5
2
  //= require_tree ./components
@@ -3,5 +3,8 @@
3
3
  * Base Javascript for Disco applications.
4
4
  * Assumes that jQuery will be loaded in the parent application.js.
5
5
  */
6
+ //= require react
7
+ //= require react_ujs
6
8
  //= require bootstrap-sprockets
7
9
  //= require disco_app/shopify-turbolinks
10
+ //= require ./ui-kit
@@ -0,0 +1 @@
1
+ (function(){var t,e,n,s,a,i=function(t,e){return function(){return t.apply(e,arguments)}};t={STYLIZED:"next-input--stylized",SELECT_WRAPPER:"next-select__wrapper",TEXTAREA:"next-textarea",INPUT:"next-input",SELECT:"next-select",LABEL:"next-label"},n={LABEL:{FOCUSED:t.LABEL+"--is-focused"},INPUT:{FOCUSED:t.INPUT+"--is-focused"}},e=[t.INPUT,t.TEXTAREA,t.SELECT],s=function(){function s(){this.handleFocusChange=i(this.handleFocusChange,this),document.addEventListener("focus",this.handleFocusChange,!0),document.addEventListener("blur",this.handleFocusChange,!0)}return s.prototype.handleFocusChange=function(t){var s,a,i,o,r,c,l,u,d;for(u=t.target,a=0,o=e.length;o>a;a++)l=e[a],d=u.classList.contains(l);return d?(c=this.findLabelAndParent(u),i=c[0],r=c[1],s="focus"===t.type,i.classList.toggle(n.LABEL.FOCUSED,s),r.classList.toggle(n.INPUT.FOCUSED,s)):void 0},s.prototype.findLabelAndParent=function(e){var n,s;return n=document.querySelectorAll("label[for='"+e.getAttribute("id")+"']")[0],s=this._findParentNodeByClass(t.SELECT_WRAPPER,e),s||(s=this._findParentNodeByClass(t.STYLIZED,e)),[n,s]},s.prototype._findParentNodeByClass=function(t,e){var n;for(n=e.parentNode;!n.classList.contains(t);)n=n.parentNode;return n.classList.contains(t)?n:void 0},s}(),a=new s}).call(this),function(){}.call(this);
@@ -0,0 +1,66 @@
1
+ //
2
+ // header.scss
3
+ // Styles for admin header.
4
+ // --------------------------------------------------
5
+
6
+ .header-row {
7
+ display: block;
8
+ box-sizing: border-box;
9
+ position: fixed;
10
+ top: 0;
11
+ z-index: 198;
12
+ left: 230px;
13
+ right: 0;
14
+ height: 56px;
15
+ max-width: 100vw;
16
+ box-shadow: 0 1px 0 rgba(0,0,0,0.07);
17
+ background: #ffffff;
18
+ }
19
+
20
+ .header {
21
+ position: relative;
22
+ height: 56px;
23
+ padding: 0 20px;
24
+ display: -webkit-box;
25
+ display: -webkit-flex;
26
+ display: -ms-flexbox;
27
+ display: flex;
28
+ -webkit-box-orient: horizontal;
29
+ -webkit-box-direction: normal;
30
+ -webkit-flex-direction: row;
31
+ -ms-flex-direction: row;
32
+ flex-direction: row;
33
+ -webkit-box-align: center;
34
+ -webkit-align-items: center;
35
+ -ms-flex-align: center;
36
+ align-items: center;
37
+ }
38
+
39
+ .header__main {
40
+ -webkit-box-flex: 1;
41
+ -webkit-flex: 1 0 0%;
42
+ -ms-flex: 1 0 0%;
43
+ flex: 1 0 0%;
44
+ -webkit-box-ordinal-group: 2;
45
+ -webkit-order: 1;
46
+ -ms-flex-order: 1;
47
+ order: 1;
48
+ font-size: 24px;
49
+ text-align: left;
50
+ margin: 0;
51
+ padding: 10px 0;
52
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
53
+ font-weight: 300;
54
+ white-space: nowrap;
55
+ text-overflow: ellipsis;
56
+ overflow: hidden;
57
+ z-index: 2;
58
+ }
59
+
60
+ .breadcrumb {
61
+ color: #798c9c;
62
+ }
63
+
64
+ .breadcrumb a, .breadcrumb a:hover {
65
+ color: #798c9c;
66
+ }
@@ -0,0 +1,40 @@
1
+ //
2
+ // layout.scss
3
+ // Styles for admin layout.
4
+ // --------------------------------------------------
5
+
6
+ body {
7
+ line-height: 18px;
8
+ font-size: 13px;
9
+ color: #31373d;
10
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
11
+ text-rendering: optimizeLegibility;
12
+ }
13
+
14
+ html, body {
15
+ height: 100%;
16
+ margin: 0;
17
+ padding: 0;
18
+ border: 0;
19
+ background: #ebeef0;
20
+ }
21
+
22
+ #wrapper {
23
+ min-height: 100%;
24
+ background: #ebeef0;
25
+ }
26
+
27
+ #content {
28
+ padding: 56px 0 0 230px;
29
+ width: 100%;
30
+ box-sizing: border-box;
31
+ outline: 0;
32
+ display: block;
33
+ max-width: 3000px;
34
+ margin: 0 auto;
35
+ position: relative;
36
+ -webkit-transition: -webkit-transform 200ms ease;
37
+ transition: -webkit-transform 200ms ease;
38
+ transition: transform 200ms ease;
39
+ transition: transform 200ms ease, -webkit-transform 200ms ease;
40
+ }