Skip to content
This repository has been archived by the owner on Jun 12, 2024. It is now read-only.

Add ProductMenu and ProductMenuDropdown component #3

Closed
colleenmcginnis opened this issue Jul 12, 2018 · 1 comment · Fixed by #14
Closed

Add ProductMenu and ProductMenuDropdown component #3

colleenmcginnis opened this issue Jul 12, 2018 · 1 comment · Fixed by #14
Assignees

Comments

@colleenmcginnis
Copy link
Contributor

This is a double component issue. 👯 The ProductMenu is essentially a stylized version of the PopoverTrigger mapbox-react component. The ProductMenuComponent is rendered and added as the content prop in the ProductMenu component.

Example in action

Here it is in the Android docs:

image

Dependencies

The ProductMenu component uses:

  • The mapbox-react-component @mapbox/react-popover-trigger.
  • A data file called src/data/product-nav-items.js. This is probably the most important thing to share between repos. The items in the dropdown should be identical in every repo. I'm not sure what the best approach is for storing this so that it can be updated when new docs sites are added.
  • The ProductMenuDropdown is rendered and passed to PopoverTrigger as the value for the content prop (not sure if that's the best approach).
    • The mapbox-react-component @mapbox/react-icon.
    • It is passed that product-nav-items.js data file from above ☝️ .

Props

ProductMenu:

  • platform, which it gets from the PageShell in the current docs)
  • product, which it also gets from the PageShell in the current docs)

ProductMenuDropdown:

  • categories that come from the product-nav-items.js data file

Things to discuss

What's the best way to factor in the product-nav-items.js data file? Should these be two components or should they be combined?

Starter code

ProductMenu (Android docs version):

import React from 'react';
import PropTypes from 'prop-types';
import PopoverTrigger from '@mapbox/react-popover-trigger';
import Icon from '@mapbox/react-icon';
import { ProductMenuDropdown } from './product-menu-dropdown';
import { ProductNavItems } from '../data/product-nav-items.js';

const popoverProps = {
  placement: 'bottom',
  themePopover: 'round shadow-darken25 h480 scroll-auto'
};

class ProductMenu extends React.PureComponent {
  static propTypes = {
    platform: PropTypes.string.isRequired,
    product: PropTypes.string.isRequired
  };

  renderMenu() {
    return <ProductMenuDropdown categories={ProductNavItems} />;
  }

  onPopoverOpen = () => {
    this.setState({ open: true });
  };

  onPopoverClose = () => {
    this.setState({ open: false });
  };

  render() {
    return (
      <PopoverTrigger
        content={this.renderMenu}
        popoverProps={popoverProps}
        onPopoverOpen={this.onPopoverOpen}
        onPopoverClose={this.onPopoverClose}
      >
        <div className="fl wmax240-ml wmax180-mm flex-parent flex-parent--space-between-main flex-parent--center-cross">
          <div className="flex-child inline-block txt-fancy txt-l cursor-pointer border-b border-b--2 border--white border--blue-on-hover txt-truncate">
            {this.props.product} SDK for {this.props.platform}
          </div>
          <Icon
            name="caret-down"
            inline={true}
            className="flex-child fr icon h30 w30"
          />
        </div>
      </PopoverTrigger>
    );
  }
}

export { ProductMenu };

ProductMenuDropdown (Android docs version):

import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import Icon from '@mapbox/react-icon';

class ProductMenuDropdown extends React.PureComponent {
  static propTypes = {
    categories: PropTypes.arrayOf(
      PropTypes.shape({
        productCategory: PropTypes.string.isRequired,
        icon: PropTypes.string.isRequired,
        products: PropTypes.arrayOf(
          PropTypes.shape({
            name: PropTypes.string,
            url: PropTypes.string,
            items: PropTypes.arrayOf(
              PropTypes.shape({
                text: PropTypes.string.isRequired,
                url: PropTypes.string.isRequired
              })
            )
          })
        ).isRequired
      })
    ).isRequired
  };

  render() {
    const categoryLength = this.props.categories.length;
    const activeDotStyle = {
      content: '',
      width: '6px',
      height: '6px',
      borderRadius: '3px',
      background: '#4264fb',
      position: 'absolute',
      margin: '10px 0 0 -12px',
      display: 'none'
    };
    const allCategories = this.props.categories.map((category, index) => {
      const allProducts = category.products.map((product, index) => {
        const liClasses = classnames('mt6 relative ', {
          'txt-bold': product.url && location.pathname.indexOf(product.url) > -1
        });
        const dotClasses = classnames({
          'inline-block': location.pathname.indexOf(product.url) > -1,
          none: location.pathname.indexOf(product.url) < 0
        });
        return (
          <li className={liClasses} key={index}>
            <div style={activeDotStyle} className={dotClasses} />
            <a href={product.url} className="color-blue-on-hover">
              {product.name}
            </a>
          </li>
        );
      });
      const categoryClasses = classnames('wmin240 py24', {
        'border-b border--gray-light': index < categoryLength - 1
      });
      return (
        <div className={categoryClasses} key={index}>
          <div className="txt-bold color-gray">
            <Icon
              name={category.icon}
              inline={true}
              className="icon mb-neg6 mr6 h20 w20 color-gray inline"
            />
            {category.productCategory}
          </div>
          <ul className="ml24">{allProducts}</ul>
        </div>
      );
    });
    return (
      <div>
        <div className="px24 pb24">{allCategories}</div>
        <div className="bg-gray-faint">
          <div className="py24 px24 txt-bold">
            <a href="/help/">Help page</a>
          </div>
        </div>
      </div>
    );
  }
}

export { ProductMenuDropdown };
@colleenmcginnis
Copy link
Contributor Author

We should also consider the feedback/solution here: https://github.com/mapbox/android-docs/pull/557.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants