The AMP library accepts customizations via the "opts" javascript object.
AMP story pages
The opts object for rendering AMP story pages has the following structure:
const myOptsObj = {
seo,
templates: {
text: ({ story, config, seo }) => <CustomTextTemplate story={story} config={config} seo={seo} />,
video: ({ story, config, seo }) => <CustomVideoTemplate story={story} config={config} seo={seo} />
// ... other templates
},
slots: {
story: {
"top-slot": ({ story, config }) => <MyTopSlot story={story} config={config} />,
"bottom-slot": ({ story, config }) => <MyBottomSlot story={story} config={config} />
}
},
render: {
navbarRender: ({ config, theme }) => <CustomNavbar theme={theme} config={config} />,
headerCardRender: ({ story, config }) => <CustHeaderCard story={story} config={config} />,
footerRender: ({ story, config }) => <CustFooter story={story} config={config} />,
infiniteScrollRender: ({ story, config, inlineConfig }) => <CustomInfiniteScroll story={story} config={config} firstFiveStoriesConfig={inlineConfig} />,
authorCardRender:({story, config, theme}) => <CustomAuthorCard authors={story.authors} config={config} theme={theme} />,
// ... other renders
storyElementRender: {
bigfactElementRender: ({ story, config, element }) => (
<CustBigFact story={story} config={config} element={element} />
)
// ... other SE renders
}
},
// InfiniteScroll is powered by default with `amp-infinite-scroll` collection (there needs to be a collection created with slug `amp-infinite-scroll`. The stories from this collection power the infinite scroll)
// if source is `custom` - we need to provide an async function for inlineConfig & remoteConfigEndpoint
// if source is `relatedStoriesApi` - infiniteScroll is powered by relatedStoriesApi
featureConfig: {
infiniteScroll: {
source: "custom",
inlineConfig: async getCustomStoryList(){},
remoteConfigEndpoint: "amp/api/infinite-scroll",
}
},
};
seo
- this is the SEO object generated by quintype/seotemplates
- pass your custom story templates here. If not passed, the default templates will be usedslots
- config for story page slots- renders - umbrella term used for the different render props used to customize the default templates.
storyElementRender
relatedStoriesRender
headerCardRender
footerRender
infiniteScrollRender
navbarRender
authorCardRender
featureConfig
- used to provide config for amp lib features.
This section is useful if you want to use custom templates. Else, jump to slots
Passing custom templates
Go to Custom Story Templates
Slots
Slots are nothing but functions that should return a react component.
You might want to use slots to add ads, some scripts etc.
The <Head />
component may be used to put code in the head. Using it, custom scripts, css can be added. It uses react-helmet
ampRoutes(app, {
slots: {
story: {
"top-slot": ({story, config}) => <MyTopSlot story={story} config={config} />
"bottom-slot": ({story, config}) => <MyBottomSlot story={story} config={config} />
"live-blog-card-slot": ({story, config, index, card}) => <MyLiveBlogCardSlot />
"default-story-card-slot": ({story, config, index, card}) => <MyStoryCardSlot />
"default-story-element-slot": ({story, config, cardIdx, storyElementIdx, storyElement}) => <MyStoryElementSlot/>
}
}
})
Here, story
and config
is same as what's mentioned above.
Slot Name | Slot Type | props | description |
---|---|---|---|
top-slot | story | obj - {story, config} | |
bottom-slot | story | obj - {story, config} | |
live-blog-card-slot | story | obj - {story, config, index, card} | card - the card above this slot. index - the 1st card has 0th index and so on |
default-story-card-slot | story | obj - {story, config, index, card} | This slot is placed after every card on non-liveblog story templates |
default-story-element-slot | story | obj - {story, config, cardIdx, storyElementIdx, storyElement} | This slot is placed after every story element on a non-liveblog story |
related-story-card-slot | story | obj - {story, config, index, relatedStory} | This slot is placed after every related story card (also read) |
Feature Config
Feature config is an object that can be used to configure different features of amp lib.
- enableAds: used to enable/disable ads on different templates.
top
,body
andbottom
corresponds to top-ad, body-ad and bottom-ad respoectively. By default, the ads are shown if no featureConfig is given. - relatedStories (also read)
- storiesToTake: sets the number of related stories displayed. Defaults to 5
- infiniteScroll:
storySeparatorText
: String that will be displayed by the separator that separates two infinite scroll stories. If nothing is passed,SCROLL FOR NEXT
is displayed
- sidebarMenu
- Optional. To tell amplib from where to pick items for the sidebar (Hamburger) menu, pass the slug of that menu group to
opts.featureConfig.sidebarMenu.menuGroupSlug
- This can be extended to subdomains as well. For example if you have a subdomain called
world-news
, setopts.domains["world-news"].featureConfig.sidebarMenu.menuGroupSlug
. Now the sidebar menu on the subdomainworld-news
will pick items from whatever menu group you've set - go to hamburger-menu for more info
- Optional. To tell amplib from where to pick items for the sidebar (Hamburger) menu, pass the slug of that menu group to
- webengage
- isEnabled: (Boolean) Enable / disable the default webengage component.
- localization - used to provide localization of the hardcoded keywords (eg: "By", "Also Read" etc) to respective locale.
- customMetaTags (string/function) - used to add custom meta tags in the head of the amp page. Can be either a string or function. If a function is passed, it's called by passing an obj = {story, config} as params and it's return value is added in the html head
const exampleFeatureConfig = {
enableAds: {
default: {
top: true / false,
body: true / false,
bottom: true / false
},
liveBlog: {
top: true / false,
body: true / false,
bottom: true / false
}
},
liveBlog: {
dataPollInterval: "10000",
dataMaxItemsPerPage: "50"
},
relatedStories: {
storiesToTake: number
infiniteScroll: {
storySeparatorText: string
},
sidebarMenu: {
menuGroupSlug: string
},
webengage:{
isEnabled: boolean;
},
localization: {
useLocaleDateStampOnGenericStory: object | function;
translations: object | function,
},
};
Renders
If you wish to customize the default templates, you can do so using the various render prop overrides that the library provides. These too are functions that should return react components
For example,
ampRoutes(app, {
render: {
navbarRender: ({config, theme}) => <div>CUSTOM NAVBAR</div>
headerCardRender: ({story, config}) => <div>CUSTOM HEADER CARD</div>
footerRender: ({story, config}) => <div>CUSTOM FOOTER</div>
authorCardRender: ({story, config, theme}) => <div>CUSTOM AUTHOR CARD</div>,
storyElementRender: {
textElementRender: ({ story, config, element }) => (
<div>
<span>My Custom Text Element</span>
<div className="">{element.text}</div>
</div>
)
}
}
});
Here too, story
and config
is same as what's mentioned above.
Render prop name | children | props | details |
---|---|---|---|
headerCardRender | - | obj - {story, config} | |
relatedStoriesRender | - | obj - {relatedStories, config, story} | relatedStories gives stories in the related stories collection |
infiniteScrollRender | - | obj - {story, config, inlineConfig} | inlineConfig is one part of the JSON config given to to the infinite scroll component. |
storyElementRender (object containing all story element renders) | - | - | - |
↳ | bigfactElementRender | obj - {story, config, element} | element is the story element, same as what's found in the story API |
↳ | answerElementRender | obj - {story, config, element} | - same - |
↳ | questionElementRender | obj - {story, config, element} | - same - |
↳ | qAndAElementRender | obj - {story, config, element} | - same - |
↳ | summaryElementRender | obj - {story, config, element} | - same - |
↳ | textElementRender | obj - {story, config, element} | - same - |
↳ | youtubeElementRender | obj - {story, config, element} | - same - |
↳ | brightcoveElementRender | obj - {story, config, element} | - same - |
↳ | vidibleElementRender | obj - {story, config, element} | - same - |
↳ | twitterElementRender | obj - {story, config, element} | - same - |
↳ | titleElementRender | obj - {story, config, element} | - same - |
↳ | instagramElementRender | obj - {story, config, element} | - same - |
↳ | imageGalleryElementRender | obj - {story, config, element} | - same - |
↳ | imageElementRender | obj - {story, config, element} | - same - |
↳ | facebookElementRender | obj - {story, config, element} | - same - |
↳ | embedRender | obj - {story, config, element} | - same - |
↳ | dailyMotionRender | obj - {story, config, element} | - same - |
↳ | blockquoteRender | obj - {story, config, element} | - same - |
↳ | blurbRender | obj - {story, config, element} | - same - |
↳ | alsoReadRender | obj - {story, config, element} | - same - |
↳ | tableElementRender | obj - {story, config, element} | - same - |
↳ | unsupportedElementRender | obj - {story, config, element} | - same |
liveBlogCardTimeStamp | - | obj - {story, config, card} | card is the live blog card |