Skip to content

Instantly share code, notes, and snippets.

@dinocarl
Last active August 29, 2019 21:44
Show Gist options
  • Save dinocarl/c2a9406773a2b9327de9c2e418bc8f81 to your computer and use it in GitHub Desktop.
Save dinocarl/c2a9406773a2b9327de9c2e418bc8f81 to your computer and use it in GitHub Desktop.
const {
compose,
concat,
curry,
flatten,
flip,
identity,
isNil,
isEmpty,
join,
length,
map,
prop,
propOr,
reduce,
reject,
splitAt,
toPairs,
uniq,
zip
} = R // ramda
const el = curry(React.createElement)
const identityTag = curry((props, ...children) => children)
const div = el(`div`)
const h1 = el(`h1`)
const h2 = el(`h2`)
const p = el(`p`)
const span = el(`span`)
const a = el(`a`)
const ul = el(`ul`)
const li = el(`li`)
const textTmplt = el(`p`)
const linkTmplt = el(`a`)
const listedItems = map(li({}))
const addLink = (condition, linkPath) => (condition
? linkTmplt(
{ href: linkPath, className: 'whole-item' },
span({ className: 'hidden-text' }, 'Link')
)
: ''
)
const condLink = (condition) => (condition
? linkTmplt
: identityTag
)
const templateOptions = {
link: linkTmplt,
title: el('h1'),
heading: el('h2'),
subheading: el('h3'),
kicker: el('h4'),
plainText: textTmplt,
image: el('img'),
}
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')
? {
className: type,
src: val,
alt: propOr('', 'altText', limiter)
}
: { className: type }
let content = (type !== 'image')
? val
: null
let wrapper = condLink((linkContent === attrName))
return wrapper(
{ href: propOr('', linkField, data) },
propOr(textTmplt, type, templateOptions)(
attrs,
content
)
)
})
const cardColumn = (size) => div({ className: size })
const create2Cols = curry((sizeA, sizeB, [childrenA, childrenB]) => [
cardColumn(sizeA)(childrenA),
cardColumn(sizeB)(childrenB)
])
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 dataBasedHtml = 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 = compose(
join('/'),
reject(isEmpty)
)([
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,
assembleFn,
condSplit
)(dataBasedHtml);
};
// data
const listData = [
`a`, `b`, `c`
]
const data = {
title: "The Adventures of Tom Sawyer",
path: "https://www.gutenberg.org/cache/epub/74/pg74.cover.medium.jpg",
kicker: "This is the Kicker",
author: "Mark Twain",
date: "1559674546767",
urlPath: "https://www.gutenberg.org/files/74/74-0.txt",
}
const limiter = [
{
attr: "path",
renderAs: "image"
},
{
attr: "title",
renderAs: "heading"
},
{
attr: "kicker",
renderAs: "subheading"
},
{
attr: "author",
renderAs: "subheading"
},
]
const layoutOpts = [
{
size: 'xs',
lt: '4',
rt: '8'
}, {
size: 'md',
lt: '6',
rt: '6'
}, {
size: 'lg',
lt: '8',
rt: '4'
}
]
const App = () => div(
{ className: `container` },
h1(
{},
span(
{ style: { color: `red` } },
`React without JSX`
),
` - `,
a(
{
id: `some-id`,
href: `/path/to/resource`
},
`link text`
),
' ',
span(
{},
'last span'
)
),
div(
{ className: 'row' },
...miniTmplt(
data,
limiter,
'card',
layoutOpts,
1,
'urlPath',
'wholeItem'
)
),
ul(
{},
listedItems(listData)
)
)
ReactDOM.render(
App(),
document.getElementById(`app`)
);
// https://jsfiddle.net/48bkn7Lo/
// https://jsfiddle.net/9g7yq345/
// https://jsfiddle.net/ytx5uj9c/1/
// https://jsfiddle.net/p5Lj6e3d/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment