Skip to content

Instantly share code, notes, and snippets.

@bauhouse
Last active September 14, 2020 22:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bauhouse/ad2c0996c4bdb217f8b1d255ab7bdaca to your computer and use it in GitHub Desktop.
Save bauhouse/ad2c0996c4bdb217f8b1d255ab7bdaca to your computer and use it in GitHub Desktop.
Configuration file for DatoCMS for static site generation with Harp
// ============================================================
// 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