Last active
July 3, 2019 16:53
-
-
Save dinocarl/78cfc4eb14f18880d3a3385156c08ad7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { | |
compose, | |
concat, | |
cond, | |
curry, | |
flatten, | |
flip, | |
identity, | |
is, | |
isNil, | |
isEmpty, | |
join, | |
length, | |
map, | |
prop, | |
propOr, | |
reduce, | |
reject, | |
splitAt, | |
toPairs, | |
trim, | |
T, | |
uniq, | |
zip | |
} = require('ramda'); | |
const condJoin = cond([ | |
[is(Array), join('')], | |
[T, identity] | |
]); | |
const attrTmplt = ([key, val]) => `${key}="${val}"`; | |
const attrsTmplt = compose( | |
join(' '), | |
map(attrTmplt), | |
toPairs | |
); | |
const pairedTag = curry((tagname, [attrs, content]) => `${trim( | |
join( | |
' ', | |
[ | |
`<${tagname}`, | |
attrsTmplt(attrs) | |
] | |
) | |
)}>${content}</${tagname}>`); | |
const selfClosingTag = curry((tagname, [attrs]) => `<${tagname} ${attrsTmplt(attrs)} />`); | |
const identityTag = ([, content]) => content; | |
const textTmplt = pairedTag('p'); | |
const linkTmplt = pairedTag('a'); | |
const div = pairedTag('div'); | |
const span = pairedTag('span'); | |
const condLink = (condition) => (condition | |
? linkTmplt | |
: identityTag | |
); | |
const addLink = (condition, linkPath) => (condition | |
? linkTmplt( | |
[ | |
{ href: linkPath, class: 'whole-item' }, | |
span([{ class: 'hidden-text' }, 'Link']) | |
] | |
) | |
: '' | |
); | |
const templateOptions = { | |
link: linkTmplt, | |
title: pairedTag('h1'), | |
heading: pairedTag('h2'), | |
subheading: pairedTag('h3'), | |
kicker: pairedTag('h4'), | |
plainText: textTmplt, | |
image: selfClosingTag('img'), | |
none: identityTag, | |
}; | |
const itemTemplate = curry((data, linkField, linkContent, limiter) => { | |
let type = prop('renderAs', limiter); | |
let attrName = prop('attr', limiter); | |
let val = prop(attrName, data); | |
let attrs = (type === 'image') | |
? { | |
class: type, | |
src: val, | |
alt: propOr('', 'altText', limiter) | |
} | |
: { class: type }; | |
let content = (type !== 'image') | |
? val | |
: ''; | |
let wrapper = condLink((linkContent === attrName)); | |
return wrapper([ | |
{ href: propOr('', linkField, data) }, | |
propOr(textTmplt, type, templateOptions)([ | |
attrs, | |
content | |
]) | |
]); | |
}); | |
// The following 2 functions are for when an attribute | |
// layout selection has been passed that requires clever grouping. | |
// `size` will be a string, and arrContent is the content as an array | |
const cardColumn = curry((size, arrContent) => div([ | |
{ class: size }, | |
join('', arrContent) | |
])); | |
const create2Cols = curry((sizeA, sizeB, [htmlStringsA, htmlStringsB]) => concat( | |
cardColumn(sizeA, htmlStringsA), | |
cardColumn(sizeB, htmlStringsB) | |
)); | |
const groupPermutations = ({ size, rt, lt }) => [ | |
`${size}-${lt}`, | |
`${size}-${rt}`, | |
]; | |
const sizeGroupings = compose( | |
map(groupPermutations), | |
uniq | |
); | |
const colClass = concat('col-'); | |
const colClasses = compose( | |
join(' '), | |
map(colClass), | |
reject(isEmpty), | |
flatten | |
); | |
// Creates the sizing tuple needed for a 2 column layout. | |
// Expects an array of sizes that look like | |
// [{size: 'xs', grouping: '3-9'}, {size: 'sm', grouping: '5-7'}] | |
// and returns an array of col size strings like | |
// ['col-xs-3 col-sm-5', 'col-xs-9 col-sm-7'] | |
const colClassTuple = compose( | |
map(colClasses), | |
reduce(zip, ['', '']), | |
sizeGroupings | |
); | |
const miniTmplt = (data, arr, layout, layoutOpts, splitPos, linkField, linkContent) => { | |
// Convert the array of attributes into an array of HTML strings | |
let htmlStrs = map(itemTemplate(data, linkField, linkContent), arr); | |
// Use a default layout or the one specified in the data | |
let layoutData = isNil(layoutOpts) || length(layoutOpts) === 0 | |
? [{ size: 'xs', lt: '3', rt: '3' }] | |
: layoutOpts; | |
// Sometimes the data provides a basePath data point. Use it as a | |
// possible prefix to the whatever is being passed in to linkField | |
let linkPath = join('/', [ | |
propOr('', 'basePath', data), | |
propOr('', linkField, data) | |
]); | |
// A value can be passed from the data that specifies when after | |
// which array member a division should be created. Defaults to 1 | |
let splitPosition = isNil(splitPos) | |
? 1 | |
: splitPos; | |
// Function ready to concatenate either the returned formed link | |
// based on the data supplied or empty string to whatever is passed to it. | |
// used to add an extra anchor tag after the rest of the created HTML | |
// in case the whole Item is intended to serve as the link | |
let wholeItemLink = flip(concat)(addLink((linkContent === 'wholeItem'), linkPath)); | |
// We might need a tuple to be be able to create a 2 column layout | |
let cardGroups = (layout === 'card') | |
? colClassTuple(layoutData) | |
: []; | |
// Function that either provides a pass-thru or a layout Function | |
let assembleFn = length(cardGroups) === 2 | |
? create2Cols(...cardGroups) | |
: identity; | |
let condSplit = (layout === 'card') | |
? splitAt(splitPosition) | |
: identity; | |
return compose( | |
wholeItemLink, | |
condJoin, | |
assembleFn, | |
condSplit | |
)(htmlStrs); | |
}; | |
// End Prep | |
// Data | |
const data = { | |
title: "The Adventures of Tom Sawyer", | |
path: "https://www.gutenberg.org/cache/epub/74/pg74.cover.medium.jpg", | |
kicker: "Kicker", | |
author: "Mark Twain", | |
date: "1559674546767", | |
urlPath: "https://www.gutenberg.org/files/74/74-0.txt", | |
}; | |
const layoutOpts = [ | |
{ | |
size: 'xs', | |
lt: '4', | |
rt: '8' | |
}, { | |
size: 'md', | |
lt: '6', | |
rt: '6' | |
}, { | |
size: 'lg', | |
lt: '8', | |
rt: '4' | |
} | |
]; | |
const limiter = [ | |
{ | |
attr: "path", | |
renderAs: "image" | |
}, | |
{ | |
attr: "title", | |
renderAs: "heading" | |
}, | |
{ | |
attr: "kicker", | |
renderAs: "subheading" | |
}, | |
{ | |
attr: "author", | |
renderAs: "subheading" | |
}, | |
]; | |
miniTmplt( | |
data, | |
limiter, | |
'card', | |
layoutOpts, | |
1, | |
'urlPath', | |
'wholeItem' | |
); | |
// https://codepen.io/anon/pen/vqgmgw |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment