Last active
September 14, 2020 22:23
-
-
Save bauhouse/ad2c0996c4bdb217f8b1d255ab7bdaca to your computer and use it in GitHub Desktop.
Configuration file for DatoCMS for static site generation with Harp
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
// ============================================================ | |
// dato.config.js | |
// ============================================================ | |
// Configuration file for DatoCMS | |
// For static site generation with Harp | |
// ------------------------------------------------------------ | |
// https://www.datocms.com/ | |
// https://harpjs.com/ | |
// ------------------------------------------------------------ | |
/* | |
### Packages | |
- fs | |
- dateFormat | |
### Constants and Variables | |
- Switches for file generation | |
- Initialize index pages | |
- Site | |
- Page Defaults | |
- CSS Defaults | |
- Assets CDN | |
### Data Models | |
- Organization | |
- Brand | |
- Social Media | |
- Metrics | |
- Donate | |
- Subscribe | |
- Pages | |
- Sections | |
- Events | |
- Races | |
- Images | |
### Output Data | |
- Global Variables | |
- Models | |
- Markdown Files | |
- CSS | |
### Functions | |
- setCssProperties(file, properties) | |
- createIndexFile(file, data) | |
- numberWithCommas(num) | |
- handleize(str, sep) | |
- isEmpty(obj) | |
*/ | |
// ============================================================ | |
// ------------------------------------------------------------ | |
// Packages | |
// ------------------------------------------------------------ | |
var fs = require('fs'); | |
var dateFormat = require('dateformat'); | |
// ------------------------------------------------------------ | |
// Constants and Variables | |
// ------------------------------------------------------------ | |
// Switches for file generation | |
// ------------------------------------------------------------ | |
var generate_global_variables = true; | |
var generate_page_data_files = true; | |
var generate_data_model_files = false; | |
var generate_markdown_files = false; | |
var generate_css_files = false; | |
var reset_css = false; | |
// Initialize index pages | |
// ------------------------------------------------------------ | |
// Generate index pages if generate_page_data_files = true | |
// (existing files will be ignored) | |
var create_index_pages = false; | |
var template_file_extension = 'jade'; | |
var default_index_content = '!= partial(\'../_shared/layout/page-title\')'; | |
// Site | |
// ------------------------------------------------------------ | |
const FIRM = 'Firm Inc'; | |
const AUTHOR = 'Full Name'; | |
const SITE = 'Site Name'; | |
const URI = 'https://example.com'; | |
var description = 'Site Description'; | |
var version = 1.0; | |
var year = new Date().getFullYear(); | |
// Page Defaults | |
// ------------------------------------------------------------ | |
var title = 'Hello, world'; | |
var gmap = false; | |
var header_style = 'dark'; | |
// CSS Defaults | |
// ------------------------------------------------------------ | |
var css_file = 'public/assets/css/colors.scss'; | |
var css_properties = { | |
'$primary-color': '#13c0d7', | |
'$secondary-color': '#8dc63f', | |
'$tertiary-color': '#f0bc00' | |
}; | |
// Assets CDN | |
// ------------------------------------------------------------ | |
var media_url = 'https://www.datocms-assets.com'; | |
// ------------------------------------------------------------ | |
// Data Models | |
// ------------------------------------------------------------ | |
module.exports = (dato, root, i18n) => { | |
// Organization | |
// ------------------------------------------------------------ | |
var org = { | |
name: dato.org.name, | |
legal_name: dato.org.legalName, | |
charity_name: dato.org.charityName, | |
tax_number: dato.org.taxNumber, | |
email: dato.org.email, | |
phone: dato.org.phone, | |
address: dato.org.address, | |
city: dato.org.city, | |
province: dato.org.province, | |
postal_code: dato.org.postalCode, | |
country: dato.org.country, | |
google_map_url: dato.org.googleMapUrl, | |
full_address: full_address | |
} | |
var full_address = | |
dato.org.address + ', ' + | |
dato.org.city + ', ' + | |
dato.org.province + ', ' + | |
dato.org.postalCode; | |
// Brand | |
// ------------------------------------------------------------ | |
var brand = { | |
messaging: dato.brand.messaging, | |
tagline: dato.brand.tagline, | |
logo: dato.brand.logo.value, | |
logo_dark: dato.brand.logoDark.value, | |
logo_header: dato.brand.headerLogo.value, | |
logo_header_dark: dato.brand.headerLogoDark.value | |
} | |
// Social Media | |
// ------------------------------------------------------------ | |
var social = {}; | |
dato.socials.forEach(item => { | |
var social_slug = item.title.toLowerCase(); | |
social[social_slug] = { | |
title: item.title, | |
slug: social_slug, | |
url: item.url | |
} | |
}); | |
// Metrics | |
// ------------------------------------------------------------ | |
var metrics = {}; | |
dato.metrics.forEach(metric => { | |
var metric_slug = handleize(metric.title); | |
metrics[metric_slug] = { | |
title: metric.title, | |
number: metric.number, | |
value: numberWithCommas(metric.number), | |
currency: metric.currency ? '$' : '' | |
} | |
}); | |
// Donate | |
// ------------------------------------------------------------ | |
var donate = { | |
projects_campaign_title: dato.donation.projectsCampaignTitle, | |
projects_campaign_id: dato.donation.projectsCampaignId, | |
team_donate_id: dato.donation.teamDonateId, | |
operations_campaign_id: dato.donation.operationsCampaignId, | |
}; | |
// Subscribe | |
// ------------------------------------------------------------ | |
var subscribe = { | |
title: dato.subscribe.title, | |
heading: dato.subscribe.heading, | |
description: dato.subscribe.description, | |
message_subject: dato.subscribe.messageSubject, | |
button_text: dato.subscribe.buttonText, | |
form_action: dato.subscribe.formAction | |
}; | |
// Pages | |
// ------------------------------------------------------------ | |
var pages = {}; | |
dato.pages.forEach((page, index) => { | |
var title_bg_img = null; | |
var image = null; | |
if (page.titleBgImg) { | |
title_bg_img = dato.find(page.titleBgImg.id); | |
image = {}; | |
var image_values = title_bg_img.image.value; | |
image.id = page.titleBgImg.id; | |
image.name = title_bg_img.name; | |
image.caption = title_bg_img.caption; | |
image.description = title_bg_img.description; | |
for (var i in image_values) image[i] = image_values[i]; | |
image.url = media_url + image_values.path; | |
title_bg_img = image.url; | |
} | |
var page_slug = page.slug; | |
var parent_page = null; | |
var parent_page_id = null; | |
var path = '/' + page.slug; | |
if (page.slug === 'index') { | |
path = '/'; | |
} | |
var parent_page_slug = null; | |
if (page.parentPage) { | |
parent_page = dato.find(page.parentPage.id); | |
parent_page_id = page.parentPage.id; | |
parent_page_slug = parent_page.slug; | |
var parent_page_path = parent_page_slug; | |
page_slug = parent_page_path ? parent_page.slug + '_' + page.slug : page.slug; | |
path = parent_page_path ? '/' + parent_page.slug + '/' + page.slug : '/' + page.slug; | |
} | |
// Find child pages | |
var subpages = {}; | |
dato.pages.forEach((subpage, index) => { | |
var subpage_parent_page = null; | |
var subpage_slug = null; | |
if (subpage.parentPage) { | |
subpage_parent_page = dato.find(subpage.parentPage.id); | |
subpage_slug = subpage.slug; | |
if (subpage_parent_page.slug === page.slug) { | |
var subpage_path = '/' + page.slug + '/' + subpage_slug; | |
subpages[subpage_slug] = { | |
title: subpage.title, | |
slug: subpage.slug, | |
path: subpage_path | |
} | |
} | |
} | |
}); | |
if (isEmpty(subpages)) { | |
subpages = null; | |
} | |
pages[page_slug] = { | |
title: page.title, | |
parent_page: parent_page_slug, | |
slug: page.slug, | |
path: path, | |
heading: page.heading, | |
description: page.description, | |
title_bg_img: title_bg_img, | |
main_menu: page.mainMenu, | |
footer_menu: page.footerMenu, | |
header_style: page.headerStyle ? handleize(page.headerStyle) : null, | |
subpages: subpages | |
} | |
}); | |
// Sections | |
// ------------------------------------------------------------ | |
var sections = {}; | |
dato.sections.forEach(section => { | |
var section_slug = section.slug | |
var slug = section_slug.replace(/-/g, '_') | |
// ...find image by id | |
var section_image = null; | |
var section_image_id = null; | |
var image = null; | |
if (section.image) { | |
section_image = dato.find(section.image.id); | |
image = {}; | |
var image_values = section_image.image.value; | |
image['id'] = section.image.id; | |
image['name'] = section_image.name; | |
image['caption'] = section_image.caption; | |
image['description'] = section_image.description; | |
for (var i in image_values) image[i] = image_values[i]; | |
image['url'] = media_url + image_values.path; | |
} | |
var background_image = null; | |
if (section.backgroundImage) { | |
background_image = section.backgroundImage.value; | |
background_image['url'] = media_url + background_image.path; | |
} | |
sections[slug] = { | |
title: section.title, | |
slug: section.slug, | |
heading: section.heading, | |
lead: section.lead, | |
content: section.content, | |
button_text: section.buttonText, | |
button_url: section.buttonUrl, | |
type: section.sectionType, | |
image: image, | |
background_image: background_image, | |
video_url: section.videoUrl | |
} | |
}); | |
// Events | |
// ------------------------------------------------------------ | |
// Events by Year | |
var events = {}; | |
dato.events.forEach(event => { | |
var year = event.year; | |
var event_slug = 'year_' + event.year; | |
events[event_slug] = {}; | |
}); | |
// Events by City | |
dato.events.forEach(event => { | |
var city_slug = event.city.toLowerCase(); | |
var event_slug = 'year_' + event.year; | |
var datetime = event.date; | |
var date = datetime.toISOString().substring(0,10); | |
var event_date = new Date(date); | |
events[event_slug][city_slug] = { | |
title: event.title, | |
description: event.description, | |
datetime_iso: event.datetime, | |
date_iso: date, | |
date: dateFormat(event_date, 'dddd, mmmm d, yyyy'), | |
weekday: dateFormat(event_date, 'dddd'), | |
day: dateFormat(event_date, 'd'), | |
month: dateFormat(event_date, 'mmmm'), | |
year: dateFormat(event_date, 'yyyy'), | |
city: event.city, | |
registration_url: event.registrationUrl | |
} | |
// Races by Event | |
events[event_slug][city_slug]['races'] = {}; | |
dato.races.forEach(race => { | |
if (race.event.id == event.id) { | |
var datetime = race.start; | |
var date = datetime.toISOString().substring(0,10); | |
var race_start = new Date(datetime); | |
events[event_slug][city_slug]['races']['race_' + race.slug] = { | |
title: race.title, | |
name: race.name, | |
slug: race.slug, | |
datetime_iso: datetime, | |
date_iso: date, | |
start: dateFormat(race_start, 'h:MMtt'), | |
date: dateFormat(race_start, 'dddd, mmmm d, yyyy'), | |
weekday: dateFormat(race_start, 'dddd'), | |
day: dateFormat(race_start, 'd'), | |
month: dateFormat(race_start, 'mmmm'), | |
year: dateFormat(race_start, 'yyyy'), | |
results_url: race.resultsUrl | |
} | |
} | |
}); | |
}); | |
// Images | |
// ------------------------------------------------------------ | |
var images = {}; | |
dato.images.forEach((item, index) => { | |
var image_slug = 'id_' + item.id; | |
images[image_slug] = { | |
id: item.id, | |
title: item.title, | |
name: item.name, | |
file: item.file, | |
caption: item.caption, | |
description: item.description, | |
image: item.image.value | |
} | |
images[image_slug].image.url = media_url + images[image_slug].image.path; | |
}); | |
// Globals | |
// ------------------------------------------------------------ | |
var globals = { | |
globals: { | |
firm: FIRM, | |
author: AUTHOR, | |
site: SITE, | |
uri: URI, | |
description: description, | |
version: version, | |
site_name: dato.org.name, | |
status: dato.brand.status, | |
media_url: media_url, | |
year: year, | |
title: title, | |
gmap: gmap, | |
header_style: header_style, | |
org: org, | |
brand: brand, | |
social: social, | |
metrics: metrics, | |
donate: donate, | |
subscribe: subscribe, | |
pages: pages, | |
sections: sections, | |
events: events | |
} | |
}; | |
// ------------------------------------------------------------ | |
// Output Data | |
// ------------------------------------------------------------ | |
// Global Variables | |
// ------------------------------------------------------------ | |
if (generate_global_variables) { | |
root.createDataFile('harp.json', 'json', globals); | |
} | |
// Pages | |
// ------------------------------------------------------------ | |
if (generate_page_data_files) { | |
var page = null; | |
var path = 'public/'; | |
var data_filename = '_data.json'; | |
var data_file = path + data_filename; | |
var index_filename = 'index.' + template_file_extension; | |
var index_file = path + index_filename; | |
for (key in pages) { | |
page = pages[key]; | |
if (key != 'index') { | |
path = 'public' + page.path + '/'; | |
} | |
root.createDataFile(path + data_filename, 'json', { index: page }); | |
if (create_index_pages) { | |
index_file = path + index_filename; | |
createIndexFile(index_file, default_index_content) | |
} | |
} | |
} | |
// Models | |
// ------------------------------------------------------------ | |
if (generate_data_model_files) { | |
root.createDataFile('public/_data/org.json', 'json', org); | |
root.createDataFile('public/_data/brand.json', 'json', brand); | |
root.createDataFile('public/_data/social.json', 'json', social); | |
root.createDataFile('public/_data/metrics.json', 'json', metrics); | |
root.createDataFile('public/_data/donate.json', 'json', donate); | |
root.createDataFile('public/_data/subscribe.json', 'json', subscribe); | |
root.createDataFile('public/_data/pages.json', 'json', pages); | |
root.createDataFile('public/_data/sections.json', 'json', sections); | |
root.createDataFile('public/_data/events.json', 'json', events); | |
root.createDataFile('public/_data/images.json', 'json', images); | |
} | |
// Markdown Files | |
// ------------------------------------------------------------ | |
if (generate_markdown_files) { | |
// Create a `public/_sections` directory (or empty it if already exists) | |
root.directory('public/_content/sections', dir => { | |
// For each Section | |
dato.sections.forEach((section, index) => { | |
var background_image = null; | |
if (section.backgroundImage) { | |
background_image = section.backgroundImage.value; | |
} | |
// Create a markdown file with all the metadata in the frontmatter | |
if (section.content) { | |
dir.createPost(`${section.slug}.md`, 'yaml', { | |
frontmatter: { | |
title: section.title, | |
slug: section.slug, | |
heading: section.heading, | |
lead: section.lead, | |
content: section.content, | |
button_text: section.buttonText, | |
button_url: section.buttonUrl, | |
type: section.sectionType, | |
background_image: background_image, | |
video_url: section.videoUrl | |
}, | |
content: section.content | |
}); | |
} | |
// Create a markdown file with only the content field | |
if (section.content) { | |
dir.createPost(`${section.slug}-content.md`, 'md', { | |
content: section.content | |
}); | |
} | |
// Create a markdown file with only the lead field | |
if (section.lead) { | |
dir.createPost(`${section.slug}-lead.md`, 'md', { | |
content: section.lead | |
}); | |
} | |
}); | |
}); | |
} | |
// CSS | |
// ------------------------------------------------------------ | |
// Modify SCSS properties in public/assets/css/colors.scss | |
// The file to modify | |
var file = 'public/assets/css/colors.scss'; | |
// Find properties and assign new values | |
var properties = null; | |
if (reset_css === false) { | |
properties = { | |
'$primary-color': dato.brand.primaryColor, | |
'$secondary-color': dato.brand.secondaryColor, | |
'$tertiary-color': dato.brand.tertiaryColor | |
}; | |
} | |
// Write the changes to the file (omit properties to reset to default) | |
if (generate_css_files) { | |
setCssProperties(file, properties); | |
} | |
}; | |
// ------------------------------------------------------------ | |
// Functions | |
// ------------------------------------------------------------ | |
function setCssProperties(file, properties) { | |
// The file to modify or set the default file | |
var file = file || css_file; | |
// Find properties and assign new values or provide defaults | |
var properties = properties || css_properties; | |
// Read file | |
fs.readFile(file, 'utf8', function (err,data) { | |
if (err) return console.log(err); | |
// Replace properties with regular expressions | |
var pattern = ''; | |
var value = ''; | |
var replace_str = ''; | |
// Perform replacements on result | |
var result = data; | |
for (property in properties) { | |
// Build replacement strings for each property | |
pattern = '(\\' + property + ':)(.+?);'; | |
value = properties[property]; | |
replace_str = property + ': ' + value + ';' | |
// Replace the matching properties in the file | |
result = result.replace(RegExp(pattern, 'g'), replace_str); | |
} | |
// Write file | |
fs.writeFile(file, result, 'utf8', function (err) { | |
if (err) return console.log(err); | |
}); | |
// Log change to console | |
console.log("\n* Written " + file); | |
}); | |
} | |
function createIndexFile(file, data) { | |
// console.log("* Testing file: " + file); | |
// console.log("* Testing data:" + data); | |
fs.writeFile(file, data, { flag: 'wx' }, function (err) { | |
if (err) { | |
console.log("* Ignored " + file) | |
} | |
else { | |
console.log("* Written " + file); | |
} | |
}); | |
} | |
// https://stackoverflow.com/questions/2901102/how-to-print-a-number-with-commas-as-thousands-separators-in-javascript | |
function numberWithCommas(num) { | |
var parts = num.toString().split("."); | |
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ","); | |
return parts.join("."); | |
} | |
// https://gist.github.com/tyteen4a03/3420a9e121d13b091343 | |
function handleize(str, sep) { | |
sep = sep || '_'; | |
str = str.toLowerCase(); | |
var toReplace = ['"', "'", "\\", "(", ")", "[", "]"]; | |
for (var i = 0; i < toReplace.length; ++i) { | |
str = str.replace(toReplace[i], ""); | |
} | |
str = str.replace(/\W+/g, sep); | |
if (str.charAt(str.length - 1) == sep) { | |
str = str.replace(/-+\z/, ""); | |
} | |
if (str.charAt(0) == sep) { | |
str = str.replace(/\A-+/, ""); | |
} | |
return str | |
} | |
// https://stackoverflow.com/questions/679915/how-do-i-test-for-an-empty-javascript-object | |
function isEmpty(obj) { | |
for(var prop in obj) { | |
if(obj.hasOwnProperty(prop)) | |
return false; | |
} | |
return JSON.stringify(obj) === JSON.stringify({}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment