3.5.0 • Published 25 days ago

@quintype/components v3.5.0

Weekly downloads
2,673
License
ISC
Repository
github
Last release
25 days ago

Quintype Components

This is a set of components that is to be used to build a Quintype Node App. This README servers as documentation of the components. Please see malibu for a reference application using this architecture.

BreakingNews

This component will automatically fetch breaking news every 30 seconds, and render the provided view.

import { renderBreakingNews } from '@quintype/framework/client/start';
const BreakingNewsView = (props) => <ul>{props.breakingNews.map((item, index) => <li key={index}><BreakingNewsItem item={item} /></li>)}</ul>
renderBreakingNews('breaking-news-container', store, BreakingNewsView);

BreakingNewsItem

This component can be used to render a BreakingNewsItem.

import {BreakingNewsItem} from '@quintype/components'

<BreakingNewsItem item={item} className="breaking-news__headline"/>

Collection

This component can be used to render a collection. You should typically pass this a collection that represents a page

import {Collection} from '@quintype/components'

// collection = Collection.getCollectionBySlug(client, 'home', {}, {depth: 1})

function TwoColLayout({collection, associatedMetadata}) {
  // for item in collection.item
  //   if item.type == story
  //     showStory
  //   else if item.type == colection
  //     <Collection />
  // speed = associatedMetadata.scroll_speed
}

function collectionTemplates(layout, index) {
  if(layout == 'twoColLayout')
    return TwoColLayout;
}

// optional
function storyTemplates(index) {
  return StoryTemplate;
}

// optional
function interstitial(index) {
  if(index % 2 == 0)
    return <AdComponent />
}

<Collection collection={collection}
            collectionTemplates={collectionTemplates}
            storyTemplates={storyTemplates}
            interstitial={interstitial} />

ClientSideOnly

This component will be loaded by client, and bypassed when doing server side rendering.

import { ClientSideOnly } from '@quintype/components';
<ClientSideOnly>
  This will be shown only on the client side
</ClientSideOnly>

DfpAds

This is a higher order component which can be used to manage ad units in a single place. A component must be created, and used with the adtype parameter

import { createDfpAdComponent } from '@quintype/components';

export const CONFIG = {
  "homepage-2": { adUnit: "HP_728x90-3", sizes: [[728, 90], [320, 50]] },
  "homepage-3": { adUnit: "HP_728x90-3", sizes: [[728, 90], [320, 50]] },
}

export const DfpAd = createDfpAdComponent({
  defaultNetworkID: "123456789",
  config: CONFIG,
  targeting: function(state) {
    const params = {};

    // if(storyIsSponsored) params['sponsor'] = storySponsor

    return params;
  }
});

<DfpAd adtype="homepage-2" />

HamburgerButton

This component can be used to trigger an action openening the Hamburger menu. The state can be accessed via state.hamburgerOpened

import { HamburgerButton } from '@quintype/components';
<HamburgerButton>
  <img src="/path/to/hamburger.png"/>
</HamburgerButton>

ImageGalleryElement

This component can be used for adding image gallery on the story page. You can pass in props like className, imageAspectRatio, defaultWidth, element and widths

import { ImageGalleryElement } from "@quintype/components";

<ImageGalleryElement element={element} key={element.id} imageAspectRatio={[4,3]} />

InfiniteScroll

This component can be used to implement InfiniteScroll. This is an internal component.

InfiniteStoryBase

This component can be used to implement InfiniteScroll on the story page. You will need to specify the function which renders the story (which will recieve props.index and props.story), and functions for triggering analytics.

import React from 'react';

import { BlankStory } from './story-templates';
import { InfiniteStoryBase } from '@quintype/components';

function StoryPageBase({index, story, otherProp}) {
  // Can switch to a different template based story-template, or only show a spoiler if index > 0
  return <BlankStory story={story} />
}

const FIELDS = "id,headline,slug,url,hero-image-s3-key,hero-image-metadata,first-published-at,last-published-at,alternative,published-at,author-name,author-id,sections,story-template,tags,cards";
function storyPageLoadItems(pageNumber) {
  return global.superagent
           .get("/api/v1/stories", {fields: FIELDS, limit:5, offset:5*pageNumber})
           .then(response => response.body.stories.map(story => ({story: story, otherProp: "value"})));
}

function StoryPage(props) {
  return <InfiniteStoryBase {...props}
                            render={StoryPageBase}
                            loadItems={storyPageLoadItems}
                            onItemFocus={(item) => console.log(`Story In View: ${item.story.headline}`)}
                            onInitialItemFocus={(item) => console.log(`Do Analytics ${item.story.headline}`)} />
}

exports.StoryPage = StoryPage;

LazyLoadImages

This component will ensure all ResponsiveImages that are in its descendent path will be loaded async. By default, the image is loaded with an empty gif, and the image becomes visible when the image scrolls 250 from the edge of the screen.

import { LazyLoadImages } from '@quintype/components';

function LazyLoadSecondImage() {
  return <div>
    <ResponsiveImage slug={props["eager-image-1"]} />
    <LazyLoadImages margin={50}>
      <div>
        <UnrelatedContent/>
        <ResponsiveImage slug={props["lazy-image"]} />
      </div>
    </LazyLoadImages>
    <ResponsiveImage slug={props["eager-image-2"]} />
  </div>
}

Link

This component generates an anchor tag. Instead of doing a browser page load, it will go to the next page via AJAX. Analytics scripts will be fired correctly (and if not, it's a bug)

import { Link } from '@quintype/components';
<Link href="/section/story-slug" otherLinkAttribute="value">Text here</Link>

LoadMoreBase

This component starts with a set of stories, and then provides a load more button. This calls out to /api/v1/stories with the properties passed via the params prop. The stories are concatenated with the stories in props.data.stories, and the contents of props.data are passed to the rendered template.

import { LoadMoreStoriesBase } from '@quintype/components';

function SectionPageWithStories({section, stories, loading, onLoadMore, noMoreStories}) {
  return <div/>;
}

export function SectionPage(props) {
  return <LoadMoreStoriesBase template={SectionPageWithStories}
                              fields={"id,headline"}
                              {...props}
                              params={{"section-id": props.data.section.id}}/>
}

LoadMoreCollectionStories

This component is very similar to the LoadMoreBase component but fetches the stroies from a collection. The api call /api/v1/collections/{collectionSlug} is made with the passed collection slug value. The component accepts the params prop and a requires a Collection Slug from which to fetch the stories and returns a set of stories only.

import { LoadMoreCollectionStories } from '@quintype/components';

function MoreCollectionStories({collection, stories, loading, onLoadMore, noMoreStories}) {
  return <div/>;
}

export function HomePage(props) {
  return <LoadMoreCollectionStories template={MoreCollectionStories}
                                    collectionSlug={props.data.collectionSlug}
                                    data={{collection: collection, stories: initialStories}}
                                    params={{}}/>
}

LoadingIndicator

This component renders it's children when the app is moving between pages. It can be used to show a spinner. It always has the class "loading-indicator", and also "loading-indicator-loading" when loading.

import { LoadingIndicator } from '@quintype/components';

<LoadingIndicator>
  <div className="spinner">Please Wait</div>
</LoadingIndicator>

Menu

This component can be used to render a menu from the menuItems in the editor. An extra class called active is applied if the menu item is the current url. By default, links will resolve via AJAX.

Items will automatically be pulled from config, please remember to expose the layout key.

Children are prepended to the list of items. Slice can be passed to extract a set of menu items.

import { Menu } from '@quintype/components';

<Menu className="menu-class" itemClassName="item-class" slice={[0, 10]}>
  <li>
    <a className="item-class" href="/"> होम </a>
  </li>
</Menu>

NavigationComponentBase

This is a base component which must be subclassed, providing a navigateTo function.

import { NavigationComponentBase }from '@quintype/components';

class SearchComponent extends NavigationComponentBase {
  render() { return <a href="#" onClick={() => this.navigateTo("/some-page-here")}>Link</a>}
}

ResponsiveHeroImage

This component takes is a wrapper over ResponsiveImages, which accepts a story and returns the hero image. By default, it picks the alt text from the headline.

import { ResponsiveHeroImage } from '@quintype/components';
<figure className="story-grid-item-image qt-image-16x9">
  <ResponsiveHeroImage story={props.story}
    aspectRatio={[16,9]}
    defaultWidth={480} widths={[250,480,640]} sizes="(max-width: 500px) 98vw, (max-width: 768px) 48vw, 23vw"
    imgParams={{auto:['format', 'compress']}}/>
</figure>

ResponsiveImage

This component takes an image, and resizes it to the correct aspect ratio using imgix or thumbor.

Also see Using Responsive Image

import { ResponsiveImage } from '@quintype/components';

<figure className="story-grid-item-image qt-image-16x9">
  <ResponsiveImage slug={props.story["hero-image-s3-key"]}
    metadata={props.story["hero-image-metadata"]}
    alt={props.story['headline']}
    aspectRatio={[16,9]}
    defaultWidth={480} widths={[250,480,640]}
    sizes="(max-width: 500px) 98vw, (max-width: 768px) 48vw, 23vw"
    imgParams={{auto:['format', 'compress']}}/>
</figure>

Responsive Source

This component is used in more advanced usages if the aspect ratio is expected to change between screens

import { ResponsiveSource } from '@quintype/components';

<figure className="story-grid-item-image">
  <picture>
    // Desktop Version
    <ResponsiveSource media="(min-width: 1024px)"
      slug={props.story["hero-image-s3-key"]}
      metadata={props.story["hero-image-metadata"]}
      aspectRatio={[4,3]}
      widths={[250,480,640]}
      sizes="(max-width: 500px) 98vw, (max-width: 768px) 48vw, 23vw"
      imgParams={{auto:['format', 'compress']}}/>

    // Mobile Version
    <ResponsiveImage
      slug={props.story["hero-image-s3-key"]}
      metadata={props.story["hero-image-metadata"]}
      alt={props.story['headline']}
      aspectRatio={[16,9]}
      defaultWidth={480} widths={[250,480,640]}
      sizes="(max-width: 500px) 98vw, (max-width: 768px) 48vw, 23vw"
      imgParams={{auto:['format', 'compress']}}/>
  </picture>
</figure>

SearchPageBase

This component is to handle search functionality and also handles load more.

A template must be passed in to render search results. Fields can be passed to get specific fields in the results. The contents of props.data are passed to the rendered template.

import { SearchPageBase } from "@quintype/components";

function SearchPageView({query, stories, onLoadMore, loading, noMoreStories}) {
  return <div />;
}

<SearchPageBase template={SearchPageView} fields={"id,headline"} {...props}/>

Search box

This component provides a form with a search text box. On submit, the user is redirected to the search page via AJAX.

A template function can also be passed in, to do custom rendering. The template prop will be called with childen having the child text box. See madrid as an example

import { SearchBox } from '@quintype/components';

<SearchBox className="foobar" placeholder="search" inputClassName="foobar-box" inputId="stg" inputRef={(x) => this.foo = x} onEscape={() => this.closeDialog()}/>

SocialShare

This component renders social share component to front end app.

import { SocialShare } from '@quintype/components';

class CustomComponent extends React.Component {

  getSocialCardsTemplate({fbUrl, twitterUrl, gplusUrl, linkedinUrl}) {
    return <ul className="social-share-icons">
        <li className="social-share-icon">
          <a href={fbUrl} target="_blank">
            <img src={fbIcon} alt="fb icon"/>
          </a>
        </li>
      </ul>
  }

  render() {
    return <div className="story-byline__social-share">
              <SocialShare url={storyShareSlug}
                title='Headline of the story'
                template={this.getSocialCardsTemplate}
                hashtags='news,india,press' />
           </div>
  }
}

StoryElement

This component renders different types of story elements

import { StoryElement } from '@quintype/components';
function StoryCard(props){
  return <div>
    {props.card['story-elements'].map((element, index) => <StoryElement element={element} key={index} story={props.story}></StoryElement>)}
  </div>
}

WithError

This function can be used to generate a wrapper component that implements componentDidCatch().

import { withError } from '@quintype/components';

function optionalErrorFn(props) {
  return <span />;
}

const MyStoryElement = withError(ClassThatMayCrash, optionalErrorFn)

Review Rating

This component takes in the value for rating and renders star for the value passed in. This comopent is generally used for story review type.

import { ReviewRating } from '@quintype/components';

<ReviewRating value="3" />

The component supports additional props which allows more customization, you can pass in props like size, color, count of stars or even change the render from star to a custom svg component. Refer to component src to know exact details of what is supported.

Recommended Components that are not included

Sliders

For a slider, we recomment react-slick. It pulls in JQuery, which will add 90kb to your bundle, but is the most malleable slider out there

Marquee for Breaking News

Our Marquee recommendation is react-malarquee. Just remember to mark all items as display: inline, and remove any floats. It supports pauseOnHover.

ReactTable for table story elements

The story table element renders a very basic table story element. It can be enhaced by using 'react-table', which supports pagination and other fancy things.

3.5.1-test.2

3 months ago

3.5.1-test.1

3 months ago

3.5.1-test.0

3 months ago

3.5.0

4 months ago

3.4.1-fix-omise.0

10 months ago

3.4.4

6 months ago

3.4.3

7 months ago

3.4.2

9 months ago

3.4.1

10 months ago

3.4.4-debug.0

7 months ago

3.4.6

5 months ago

3.4.5

5 months ago

3.4.4-test-4.0

7 months ago

3.4.0

11 months ago

3.3.3

12 months ago

3.3.2

12 months ago

3.3.4-brightcove.1

11 months ago

3.3.4-brightcove.0

11 months ago

3.3.3-brightcove.0

12 months ago

3.3.3-brightcove.2

12 months ago

3.3.3-brightcove.1

12 months ago

3.3.3-at-global.0

12 months ago

3.3.3-at-global.1

12 months ago

3.3.3-at-global.2

12 months ago

3.3.1

1 year ago

3.3.1-kumudam.0

1 year ago

3.2.0

1 year ago

3.3.0

1 year ago

3.1.3

1 year ago

3.1.2

1 year ago

3.1.1

1 year ago

3.1.0

1 year ago

3.1.4

1 year ago

3.0.3-paytrail.0

2 years ago

3.0.3-paytrail.1

2 years ago

3.0.3-paytrail.2

2 years ago

3.0.2

2 years ago

3.0.1

2 years ago

3.1.0-test-b.0

2 years ago

3.0.1-img-lazy.3

2 years ago

3.0.1-img-lazy.4

2 years ago

3.0.1-img-lazy.1

2 years ago

3.0.1-img-lazy.2

2 years ago

3.0.1-img-lazy.0

2 years ago

3.0.0

2 years ago

2.33.0

3 years ago

2.32.0

3 years ago

2.31.7

3 years ago

2.31.5

3 years ago

2.31.4

3 years ago

2.31.3

3 years ago

2.31.2

3 years ago

2.31.0

3 years ago

2.30.2

3 years ago

2.30.1

3 years ago

2.30.1-omise.0

3 years ago

2.30.1-omise.1

3 years ago

2.30.0

3 years ago

2.29.3

3 years ago

2.29.0

3 years ago

2.29.2

3 years ago

2.29.1

3 years ago

2.28.0

3 years ago

2.27.2

3 years ago

2.27.1

3 years ago

2.26.2

3 years ago

2.26.1

3 years ago

2.25.4

3 years ago

2.25.4-beta.1

3 years ago

2.25.4-beta.0

3 years ago

2.25.3

3 years ago

2.25.1

3 years ago

2.24.3-beta.2

3 years ago

2.24.3-beta.1

3 years ago

2.24.3-beta.0

3 years ago

2.24.2

3 years ago

2.23.4-beta

3 years ago

2.24.1

3 years ago

2.23.3-beta

3 years ago

2.23.2-beta

3 years ago

2.23.3

3 years ago

2.23.1-link.2

3 years ago

2.23.1

3 years ago

2.23.2

3 years ago

2.23.1-link.1

3 years ago

2.23.1-link.0

3 years ago

2.23.0

3 years ago

2.22.8-beta.6

3 years ago

2.22.8-beta.5

3 years ago

2.22.8-beta.4

3 years ago

2.22.8-beta.3

3 years ago

2.22.8-beta.2

3 years ago

2.22.8

4 years ago

2.22.9-beta.3

4 years ago

2.22.9-beta.2

4 years ago

2.22.7-beta.5

4 years ago

2.22.9-beta.1

4 years ago

2.22.9-beta.0

4 years ago

2.22.8-beta.0

4 years ago

2.22.7-beta.0

4 years ago

2.22.7-beta.2

4 years ago

2.22.7-beta.1

4 years ago

2.22.6

4 years ago

2.22.5

4 years ago

2.22.4

4 years ago

2.22.1-table.0

4 years ago

2.22.2

4 years ago

2.22.0

4 years ago

2.21.0

4 years ago

2.20.1

4 years ago

2.20.0

4 years ago

2.18.0

4 years ago

2.17.0

4 years ago

2.16.1

4 years ago

2.16.0

4 years ago

2.15.5-slot-id.0

4 years ago

2.15.5-ads-fix.4

4 years ago

2.15.5-ads-fix.3

4 years ago

2.15.5-ads-fix.2

4 years ago

2.15.5-ads-fix.0

4 years ago

2.15.5-ads-fix.1

4 years ago

2.15.4

4 years ago

2.15.3

4 years ago

2.15.2

4 years ago

2.15.1

4 years ago

2.15.0

4 years ago

2.14.4

4 years ago

2.14.3

5 years ago

2.14.2

5 years ago

2.14.1

5 years ago

2.14.0

5 years ago

2.13.0

5 years ago

2.12.1

5 years ago

2.12.0

5 years ago

2.10.0

5 years ago

2.9.1

5 years ago

2.9.0

5 years ago

2.8.3

5 years ago

2.8.2

5 years ago

2.8.1

5 years ago

2.8.0

5 years ago

2.7.0

5 years ago

2.6.0

5 years ago

2.5.0

5 years ago

2.4.0

5 years ago

2.3.1

5 years ago

2.3.0

5 years ago

2.2.0

5 years ago

2.1.2

5 years ago

2.1.1

5 years ago

2.1.0

5 years ago

2.0.1

5 years ago

1.58.1

5 years ago

1.58.0

5 years ago

1.57.4

5 years ago

1.57.3

5 years ago

1.57.2

5 years ago

1.57.1

5 years ago

1.57.0

5 years ago

1.56.0

5 years ago

1.55.2

5 years ago

1.55.1

5 years ago

1.55.0

5 years ago

1.54.1

5 years ago

1.54.0

5 years ago

1.53.6

5 years ago

1.53.5

5 years ago

1.53.4

5 years ago

1.53.3

5 years ago

1.53.2

5 years ago

1.53.1

5 years ago

1.53.0

5 years ago

1.52.3

5 years ago

1.52.2

5 years ago

1.51.1

5 years ago

1.51.0

5 years ago

1.50.1

5 years ago

1.50.0

5 years ago

1.49.0

5 years ago

1.48.0

5 years ago

1.47.0

5 years ago

1.46.0

5 years ago

1.45.1

5 years ago

1.45.0

5 years ago

1.44.0

5 years ago

1.42.4

5 years ago

1.42.1-beta.2

5 years ago

1.42.2

5 years ago

1.43.0-beta.0

5 years ago

1.42.1-beta.1

5 years ago

1.42.1-beta.0

5 years ago

1.42.1

5 years ago

1.42.0

5 years ago

1.41.0

5 years ago

1.40.0

5 years ago

1.39.0

6 years ago

1.38.0

6 years ago

1.37.1

6 years ago

1.37.0

6 years ago

1.36.0

6 years ago

1.35.0

6 years ago

1.34.1

6 years ago

1.35.0-beta.1

6 years ago

1.35.0-beta.0

6 years ago

1.34.0

6 years ago

1.33.2

6 years ago

1.33.1

6 years ago

1.34.0-beta.0

6 years ago

1.33.0

6 years ago

1.33.0-beta.8

6 years ago

1.33.0-beta.7

6 years ago

1.33.0-beta.6

6 years ago

1.33.0-beta.5

6 years ago

1.33.0-beta.4

6 years ago

1.33.0-beta.3

6 years ago

1.33.0-beta.1

6 years ago

1.33.0-beta.0

6 years ago

1.32.0

6 years ago

1.31.3-pre

6 years ago

1.31.2

6 years ago

1.31.1

6 years ago

1.31.0

6 years ago

1.30.0

6 years ago

1.29.0

6 years ago

1.28.1

6 years ago

1.28.0

6 years ago

1.27.1

6 years ago

1.27.0

6 years ago

1.26.0

6 years ago

1.25.2

6 years ago

1.25.1

6 years ago

1.25.0

6 years ago

1.24.0

6 years ago

1.23.0

6 years ago

1.22.0

6 years ago

1.21.0

6 years ago

1.20.2

6 years ago

1.20.1

6 years ago

1.20.0

6 years ago

1.19.1

6 years ago

1.19.0

6 years ago

1.18.0

6 years ago

1.17.0

6 years ago

1.16.0

6 years ago

1.15.0

6 years ago

1.14.1

6 years ago

1.14.0

6 years ago

1.13.1

6 years ago

1.13.0

6 years ago

1.11.0

6 years ago

1.10.2

6 years ago

1.10.1

6 years ago

1.10.0

6 years ago

1.9.0

6 years ago

1.8.1

6 years ago

1.8.0

6 years ago

1.7.0

6 years ago

1.6.3

6 years ago

1.6.2

6 years ago

1.6.1

6 years ago

1.6.0

6 years ago

1.5.1

6 years ago

1.5.0

6 years ago

1.4.3

6 years ago

1.4.2

6 years ago

1.4.1

6 years ago

1.4.0

6 years ago

1.3.1

6 years ago

1.3.0

6 years ago

1.2.1

6 years ago

1.2.0

6 years ago

1.1.0

6 years ago

1.0.35

6 years ago

1.0.34

6 years ago

1.0.33

6 years ago

1.0.32

6 years ago

1.0.31

6 years ago

1.0.30

6 years ago

1.0.28

6 years ago

1.0.27

6 years ago

1.0.26

6 years ago

1.0.25

6 years ago

1.0.22

6 years ago

1.0.21

6 years ago

1.0.20

6 years ago

1.0.18

6 years ago

1.0.17

6 years ago

1.0.16

6 years ago

1.0.15

6 years ago

1.0.14

6 years ago

1.0.13

6 years ago

1.0.12

6 years ago

1.0.11

6 years ago

1.0.10

6 years ago

1.0.9

6 years ago

1.0.8

6 years ago

1.0.7

6 years ago

1.0.6

6 years ago

1.0.5

6 years ago

1.0.4

6 years ago

1.0.3

6 years ago

1.0.2

6 years ago

1.0.1

6 years ago

1.0.0

6 years ago