diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..521e2ae --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,29 @@ +module.exports = { + "env": { + "browser": true, + "es2021": true + }, + "extends": [ + "eslint:recommended", + "prettier" // Make sure this is the last + ], + "overrides": [ + { + "env": { + "node": true + }, + "files": [ + ".eslintrc.{js,cjs}" + ], + "parserOptions": { + "sourceType": "script" + } + } + ], + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module" + }, + "rules": { + } +} diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..91e50e9 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6" + }, + "exclude": ["node_modules"] +} \ No newline at end of file diff --git a/lib/build.js b/lib/build.js index 2cc3b75..46c5bd9 100644 --- a/lib/build.js +++ b/lib/build.js @@ -1,375 +1,377 @@ const { exists } = require("fs-extra/lib/fs"); module.exports = async (config) => { - const - { promises: fs } = require("fs"), - fse = require("fs-extra"), - path = require("path"), - ejs = require("ejs"), - frontMatter = require("front-matter"), - glob = require("glob"), - hljs = require("highlight.js"), - md = require("markdown-it")({ - highlight: (str, lang) => { - if (lang && hljs.getLanguage(lang)) { - try { - return hljs.highlight(str, { language: lang }).value; - } catch (__) {} - } + const { promises: fs } = require("fs"), + fse = require("fs-extra"), + path = require("path"), + ejs = require("ejs"), + frontMatter = require("front-matter"), + glob = require("glob"), + hljs = require("highlight.js"), + md = require("markdown-it")({ + highlight: (str, lang) => { + if (lang && hljs.getLanguage(lang)) { + try { + return hljs.highlight(str, { language: lang }).value; + } catch (__) {} + } - return ""; // use external default escaping - }, - html: true, - linkify: true, - typographer: true, - xhtmlOut: true, - }) - .use(require("markdown-it-footnote")) - .use(require("markdown-it-emoji")), - // { readJsonIfExists } = require("./utils"), - { build, isRebuild, logFunction: log = () => {} } = config || {}, - { outputPath, journalsPerPage = 5, srcPath } = build, - { site } = config, - copyAssets = async (directory) => { - const assets = await fs.readdir(directory); + return ""; // use external default escaping + }, + html: true, + linkify: true, + typographer: true, + xhtmlOut: true, + }) + .use(require("markdown-it-footnote")) + .use(require("markdown-it-emoji")), + // { readJsonIfExists } = require("./utils"), + { build, isRebuild, logFunction: log = () => {} } = config || {}, + { outputPath, journalsPerPage = 5, srcPath } = build, + { site } = config, + copyAssets = async (directory) => { + const assets = await fs.readdir(directory); - assets.forEach(async (asset) => { - // we no longer merge scripts and styles, thanks to http/2's parallel file handling - if (asset === "_root") { - fse.copy(path.join(srcPath, "assets", asset), outputPath); - } else { - fse.copy( - path.join(srcPath, "assets", asset), - path.join(outputPath, asset) - ); - } - }); - }, - getReadTime = (text) => { - const WPM = 275, - fixedString = text.replace(/[^\w\s]+/g, ""), - count = fixedString.split(/\s+/).length; + assets.forEach(async (asset) => { + // we no longer merge scripts and styles, thanks to http/2's parallel file handling + if (asset === "_root") { + fse.copy(path.join(srcPath, "assets", asset), outputPath); + } else { + fse.copy( + path.join(srcPath, "assets", asset), + path.join(outputPath, asset) + ); + } + }); + }, + getReadTime = (text) => { + const WPM = 275, + fixedString = text.replace(/[^\w\s]+/g, ""), + count = fixedString.split(/\s+/).length; - if (count < WPM) return "less than 1 minute"; - else return `${Math.ceil(count / WPM)} minutes`; - }, - tagSorter = (a, b) => a.toLowerCase().localeCompare(b.toLowerCase()), - parseFile = (file, pagePath, siteData, isSupport) => { - const { dir, ext, name } = path.parse(file) || {}, - hasExt = name.indexOf(".") > -1, - destPath = path.join(outputPath, dir), - filePath = path.join(pagePath, file), - // read page file - data = fse.readFileSync(filePath, "utf-8"), - info = fse.statSync(filePath, "utf-8"), - // render page - { attributes, body } = frontMatter(data), - { content_type: contentType, tags: originalTags = [] } = - attributes, - // TODO: Look for tags in posts as well, link to them, and add them to tag pages - tags = - typeof originalTags === "string" - ? originalTags.split(/\W+/) - : [].concat(originalTags), - innerTags = ( - contentType === "journal" - ? body.match(/\b#(\w+)/g) || [] - : [] - ).map((val) => val.replace("#", "")), - allTags = [...tags, ...innerTags].sort(tagSorter), - updatedBody = - contentType === "journal" - ? allTags.reduce( - (acc, tag) => - acc.replace( - `#${tag}`, - ` + if (count < WPM) return "less than 1 minute"; + else return `${Math.ceil(count / WPM)} minutes`; + }, + tagSorter = (a, b) => a.toLowerCase().localeCompare(b.toLowerCase()), + parseFile = (file, pagePath, siteData, isSupport) => { + const { dir, ext, name } = path.parse(file) || {}, + hasExt = name.indexOf(".") > -1, + destPath = path.join(outputPath, dir), + filePath = path.join(pagePath, file), + // read page file + data = fse.readFileSync(filePath, "utf-8"), + info = fse.statSync(filePath, "utf-8"), + // render page + { attributes, body } = frontMatter(data), + { content_type: contentType, tags: originalTags = [] } = + attributes, + // TODO: Look for tags in posts as well, link to them, and add them to tag pages + tags = + typeof originalTags === "string" + ? originalTags.split(/\W+/) + : [].concat(originalTags), + innerTags = ( + contentType === "journal" + ? body.match(/\b#(\w+)/g) || [] + : [] + ).map((val) => val.replace("#", "")), + allTags = [...tags, ...innerTags].sort(tagSorter), + updatedBody = + contentType === "journal" + ? allTags.reduce( + (acc, tag) => + acc.replace( + `#${tag}`, + ` #${tag} ` - ), - body - ) - : body; + ), + body + ) + : body; - return { - ...config, - page: { - name, - ...attributes, - date_upd: attributes?.date_pub !== info.mtime ? info.mtime : (attributes.date_upd ?? ''), - body: updatedBody, - destPath, - filePath, - path: path.join(dir, hasExt ? name : `${name}.html`), - tags: [...tags, ...innerTags].sort(tagSorter), - ext, - }, - site: { - ...site, - pages: isSupport ? siteData : [], - }, - }; - }, - parseContent = (page, siteData) => { - const { - body, - content_type: contentType, - filePath, - // tags, - } = page || {}, - { ext } = path.parse(filePath) || {}, - { pages, tags } = siteData || {}; + return { + ...config, + page: { + name, + ...attributes, + date_upd: + attributes?.date_pub !== info.mtime + ? info.mtime + : attributes.date_upd ?? "", + body: updatedBody, + destPath, + filePath, + path: path.join(dir, hasExt ? name : `${name}.html`), + tags: [...tags, ...innerTags].sort(tagSorter), + ext, + }, + site: { + ...site, + pages: isSupport ? siteData : [], + }, + }; + }, + parseContent = (page, siteData) => { + const { + body, + content_type: contentType, + filePath, + // tags, + } = page || {}, + { ext } = path.parse(filePath) || {}, + { pages, tags } = siteData || {}; - let content = body, - readTime; + let content = body, + readTime; - if (ext === ".md") { - if (contentType === "journal" && typeof body === "string") { - readTime = getReadTime(body); - } - content = md.render(body); - } else if (ext === ".ejs") { - content = ejs.render( - body, - { page, site: { ...site, pages, tags } }, - { filename: filePath } - ); - } + if (ext === ".md") { + if (contentType === "journal" && typeof body === "string") { + readTime = getReadTime(body); + } + content = md.render(body); + } else if (ext === ".ejs") { + content = ejs.render( + body, + { page, site: { ...site, pages, tags } }, + { filename: filePath } + ); + } - return { ...page, content, readTime }; - }, - renderFile = async (page, isSupport) => { - const { - content, - destPath, - layout, - path: pagePath, - pages, - siteTags, - tags, - } = page || {}; - try { - const layoutFileName = `${srcPath}/layouts/${ - layout || "default" - }.ejs`, - layoutData = await fs.readFile(layoutFileName, "utf-8"), - completePage = isSupport - ? content - : ejs.render(layoutData, { - content, - page, - site: { - ...site, - pages, - tags: - page.content_type === "journal" - ? siteTags - : tags, - }, - filename: layoutFileName, - }); + return { ...page, content, readTime }; + }, + renderFile = async (page, isSupport) => { + const { + content, + destPath, + layout, + path: pagePath, + pages, + siteTags, + tags, + } = page || {}; + try { + const layoutFileName = `${srcPath}/layouts/${ + layout || "default" + }.ejs`, + layoutData = await fs.readFile(layoutFileName, "utf-8"), + completePage = isSupport + ? content + : ejs.render(layoutData, { + content, + page, + site: { + ...site, + pages, + tags: + page.content_type === "journal" + ? siteTags + : tags, + }, + filename: layoutFileName, + }); - if (!completePage) { - console.log("failed!", pagePath, content); - return; - } + if (!completePage) { + console.log("failed!", pagePath, content); + return; + } - // create destination directory - fse.mkdirsSync(destPath); + // create destination directory + fse.mkdirsSync(destPath); - // save the html file - fse.writeFileSync( - path.join(outputPath, pagePath), - completePage - ); - } catch (e) { - console.log("failed!", pagePath); - console.log("paths", destPath, outputPath); - console.error(e); - return; - } - }; + // save the html file + fse.writeFileSync( + path.join(outputPath, pagePath), + completePage + ); + } catch (e) { + console.log("failed!", pagePath); + console.log("paths", destPath, outputPath); + console.error(e); + return; + } + }; - log(`${isRebuild ? "Reb" : "B"}uilding...`); + log(`${isRebuild ? "Reb" : "B"}uilding...`); - // clear destination folder - fse.emptyDirSync(outputPath); + // clear destination folder + fse.emptyDirSync(outputPath); - // copy assets folder - await copyAssets(path.join(srcPath, "assets")); + // copy assets folder + await copyAssets(path.join(srcPath, "assets")); - const files = ["pages", "sitePosts"].reduce((acc, pageDir) => { - return [ - ...acc, - ...glob - .sync("**/*.@(md|ejs|html)", { - cwd: path.join(srcPath, pageDir), - }) - .map((file) => - parseFile(file, path.join(srcPath, pageDir)) - ), - ]; - }, []), - sortByPubDate = (a, b) => { - if (a.date_pub && b.date_pub) { - let a_dt = new Date(a.date_pub).getTime(), - b_dt = new Date(b.date_pub).getTime(); - if (a_dt < b_dt) { - return 1; - } - if (b_dt < a_dt) { - return -1; - } - return 0; - } - if (a.date_pub) return -1; - if (b.date_pub) return 1; - return 0; - }, - pages = files - .map(({ page }) => ({ ...page })) - .filter(({ is_draft, status }) => !is_draft && status !== "draft") - .sort(sortByPubDate), - tagCloud = pages.reduce((acc, curr) => { - const { tags } = curr; - tags.forEach((tag) => { - if (acc[tag]) acc[tag]++; - else acc[tag] = 1; - }); - return acc; - }, {}), - tags = Object.keys(tagCloud).sort(tagSorter), - yearCloud = pages - .filter(({ content_type = "" }) => content_type === "journal") - .reduce((acc, curr) => { - const { date_pub } = curr; - if (date_pub) { - const year = new Date(date_pub).getFullYear(); - if (acc[year]) acc[year]++; - else acc[year] = 1; - } - return acc; - }, {}), - years = Object.keys(yearCloud).sort().reverse(), - pagesWithContent = pages.map((page) => - parseContent(page, { pages, tags }) - ); + const files = ["pages", "sitePosts"].reduce((acc, pageDir) => { + return [ + ...acc, + ...glob + .sync("**/*.@(md|ejs|html)", { + cwd: path.join(srcPath, pageDir), + }) + .map((file) => + parseFile(file, path.join(srcPath, pageDir)) + ), + ]; + }, []), + sortByPubDate = (a, b) => { + if (a.date_pub && b.date_pub) { + let a_dt = new Date(a.date_pub).getTime(), + b_dt = new Date(b.date_pub).getTime(); + if (a_dt < b_dt) { + return 1; + } + if (b_dt < a_dt) { + return -1; + } + return 0; + } + if (a.date_pub) return -1; + if (b.date_pub) return 1; + return 0; + }, + pages = files + .map(({ page }) => ({ ...page })) + .filter(({ is_draft, status }) => !is_draft && status !== "draft") + .sort(sortByPubDate), + tagCloud = pages.reduce((acc, curr) => { + const { tags } = curr; + tags.forEach((tag) => { + if (acc[tag]) acc[tag]++; + else acc[tag] = 1; + }); + return acc; + }, {}), + tags = Object.keys(tagCloud).sort(tagSorter), + yearCloud = pages + .filter(({ content_type = "" }) => content_type === "journal") + .reduce((acc, curr) => { + const { date_pub } = curr; + if (date_pub) { + const year = new Date(date_pub).getFullYear(); + if (acc[year]) acc[year]++; + else acc[year] = 1; + } + return acc; + }, {}), + years = Object.keys(yearCloud).sort().reverse(), + pagesWithContent = pages.map((page) => + parseContent(page, { pages, tags }) + ); - // add data for the whole site to each page as it's rendered - pagesWithContent.forEach((page) => { - renderFile({ ...page, pages: pagesWithContent, siteTags: tags }); - }); + // add data for the whole site to each page as it's rendered + pagesWithContent.forEach((page) => { + renderFile({ ...page, pages: pagesWithContent, siteTags: tags }); + }); - /* Journal Stuff - Tags & Years */ + /* Journal Stuff - Tags & Years */ - // make page(s) for each tag - tags.forEach((tag) => { - // check counts - let postCount = tagCloud[tag], - pageCount = Math.ceil(postCount / journalsPerPage); - for (let i = 1; i <= pageCount; i++) { - const firstEntryIndex = journalsPerPage * (i - 1), - lastEntryIndex = journalsPerPage * i; + // make page(s) for each tag + tags.forEach((tag) => { + // check counts + let postCount = tagCloud[tag], + pageCount = Math.ceil(postCount / journalsPerPage); + for (let i = 1; i <= pageCount; i++) { + const firstEntryIndex = journalsPerPage * (i - 1), + lastEntryIndex = journalsPerPage * i; - renderFile({ - content: tag, - destPath: path.join(outputPath, "journal", "tags", tag), - entriesToList: pagesWithContent - .filter( - (p) => - p && Array.isArray(p.tags) && p.tags.includes(tag) - ) - .slice(firstEntryIndex, lastEntryIndex), - layout: "tag", - path: `journal/tags/${tag}/${ - i === 1 ? "index.html" : `page${i}.html` - }`, - site: { ...site, pages: pagesWithContent, tags }, - pageCount, - pageNum: i, - pages: pagesWithContent, - tag, - tags, - title: `Journal Entries Tagged with #${tag}`, - }); - } - }); + renderFile({ + content: tag, + destPath: path.join(outputPath, "journal", "tags", tag), + entriesToList: pagesWithContent + .filter( + (p) => + p && Array.isArray(p.tags) && p.tags.includes(tag) + ) + .slice(firstEntryIndex, lastEntryIndex), + layout: "tag", + path: `journal/tags/${tag}/${ + i === 1 ? "index.html" : `page${i}.html` + }`, + site: { ...site, pages: pagesWithContent, tags }, + pageCount, + pageNum: i, + pages: pagesWithContent, + tag, + tags, + title: `Journal Entries Tagged with #${tag}`, + }); + } + }); - // make page(s) for each year - years.forEach((year) => { - // check counts - let postCount = yearCloud[year], - pageCount = Math.ceil(postCount / journalsPerPage); - for (let i = 1; i <= pageCount; i++) { - const firstEntryIndex = journalsPerPage * (i - 1), - lastEntryIndex = journalsPerPage * i; + // make page(s) for each year + years.forEach((year) => { + // check counts + let postCount = yearCloud[year], + pageCount = Math.ceil(postCount / journalsPerPage); + for (let i = 1; i <= pageCount; i++) { + const firstEntryIndex = journalsPerPage * (i - 1), + lastEntryIndex = journalsPerPage * i; - // TODO: rethink the data passed in here - you're paging solution works (kinda), take it over the finish line! - renderFile({ - content: year, - destPath: path.join(outputPath, "journal", year), - entriesToList: pagesWithContent - .filter(({ content_type = "", date_pub = "" }) => { - if (!date_pub || content_type !== "journal") - return false; + // TODO: rethink the data passed in here - you're paging solution works (kinda), take it over the finish line! + renderFile({ + content: year, + destPath: path.join(outputPath, "journal", year), + entriesToList: pagesWithContent + .filter(({ content_type = "", date_pub = "" }) => { + if (!date_pub || content_type !== "journal") + return false; - const p_dt = new Date(date_pub).getTime(), - y1_dt = new Date( - `${year}-01-01T00:00:00-0500` - ).getTime(), - y2_dt = new Date( - `${year}-12-31T23:59:59-0500` - ).getTime(); - return p_dt >= y1_dt && p_dt <= y2_dt; - }) - .slice(firstEntryIndex, lastEntryIndex), - layout: "journal-year", - path: `journal/${year}/${ - i === 1 ? "index.html" : `page${i}.html` - }`, - site: { ...site, pages: pagesWithContent, tags }, - pageCount, - pageNum: i, - pages: pagesWithContent, - tags, - title: `Journal Entries from ${year}`, - year, - }); - } - }); + const p_dt = new Date(date_pub).getTime(), + y1_dt = new Date( + `${year}-01-01T00:00:00-0500` + ).getTime(), + y2_dt = new Date( + `${year}-12-31T23:59:59-0500` + ).getTime(); + return p_dt >= y1_dt && p_dt <= y2_dt; + }) + .slice(firstEntryIndex, lastEntryIndex), + layout: "journal-year", + path: `journal/${year}/${ + i === 1 ? "index.html" : `page${i}.html` + }`, + site: { ...site, pages: pagesWithContent, tags }, + pageCount, + pageNum: i, + pages: pagesWithContent, + tags, + title: `Journal Entries from ${year}`, + year, + }); + } + }); - /* Support pages - anything too weird / specific for markdown rendering */ + /* Support pages - anything too weird / specific for markdown rendering */ - // collect support pages - const support = ["support"].reduce((acc, pageDir) => { - return [ - ...acc, - ...glob - .sync("**/*.@(md|ejs|html)", { - cwd: path.join(srcPath, pageDir), - }) - .map((file) => - parseFile( - file, - path.join(srcPath, pageDir), - pagesWithContent, - true - ) - ), - ]; - }, []); + // collect support pages + const support = ["support"].reduce((acc, pageDir) => { + return [ + ...acc, + ...glob + .sync("**/*.@(md|ejs|html)", { + cwd: path.join(srcPath, pageDir), + }) + .map((file) => + parseFile( + file, + path.join(srcPath, pageDir), + pagesWithContent, + true + ) + ), + ]; + }, []); - // write each one out - support.forEach((fileData) => { - const { page } = fileData; - if (page?.ext === ".ejs") { - const pageAndContent = parseContent(page, { - pages: pagesWithContent, - tags, - }); - return renderFile({ ...fileData, ...pageAndContent, tags }, true); - } - return renderFile(fileData, true); - }); + // write each one out + support.forEach((fileData) => { + const { page } = fileData; + if (page?.ext === ".ejs") { + const pageAndContent = parseContent(page, { + pages: pagesWithContent, + tags, + }); + return renderFile({ ...fileData, ...pageAndContent, tags }, true); + } + return renderFile(fileData, true); + }); }; diff --git a/package.json b/package.json index 2417784..e84e6d9 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "iew-site-builder", - "version": "0.9.5", + "version": "0.9.6", "description": "", "main": "index.js", "scripts": { @@ -10,7 +10,7 @@ "watch": "node app.js watch" }, "keywords": [], - "author": "", + "author": "Eric Woodward (https://www.itsericwoodward.com)", "license": "MIT", "dependencies": { "chalk": "^4.1.2", diff --git a/src/assets/scripts/scripts.js b/src/assets/scripts/scripts.js index 74127a6..4ea4ce1 100644 --- a/src/assets/scripts/scripts.js +++ b/src/assets/scripts/scripts.js @@ -2,78 +2,79 @@ /**************************************************************************** * It's Eric Woodward's Site * - * Copyright 2014-2022 Eric Woodward + * Copyright 2014-2023 Eric Woodward * Source released under CC0 Public Domain License v1.0 + * https://www.itsericwoodward.com/licenses/cc0 * http://creativecommons.org/publicdomain/zero/1.0/ ****************************************************************************/ (function () { - "use strict"; + "use strict"; - // Checking if browser "cuts the mustard" - https://gomakethings.com/ditching-jquery/ - if (!(!!document.querySelector && !!window.addEventListener)) return; + // Checking if browser "cuts the mustard" - https://gomakethings.com/ditching-jquery/ + if (!(!!document.querySelector && !!window.addEventListener)) return; - if (window.dayjs) dayjs.extend(window.dayjs_plugin_relativeTime); + if (window.dayjs) dayjs.extend(window.dayjs_plugin_relativeTime); - // Indicate JS is loaded - document.documentElement.className = - document.documentElement.className.replace("no-js", "js"); + // Indicate JS is loaded + document.documentElement.className = + document.documentElement.className.replace("no-js", "js"); - // Enable cached fonts ASAP - if (window.Cookies && !!Cookies.get("fonts_loaded")) { - document.documentElement.className += " js-hasFontsLoaded"; - } + // Enable cached fonts ASAP + if (window.Cookies && !!Cookies.get("fonts_loaded")) { + document.documentElement.className += " js-hasFontsLoaded"; + } - docReady(function () { - setTimeout(function () { - if (!window.Cookies || !window.FontFaceObserver) return; + docReady(function () { + setTimeout(function () { + if (!window.Cookies || !window.FontFaceObserver) return; - // Handle Fonts - const fontExo2 = new FontFaceObserver("exo_2"); - fontExo2.load().then(function () { - if ( - document.documentElement.className.indexOf( - "js-hasFontsLoaded" - ) == -1 - ) { - document.documentElement.className += " js-hasFontsLoaded"; - } - Cookies.set("fonts_loaded", true); - }); + // Handle Fonts + const fontExo2 = new FontFaceObserver("exo_2"); + fontExo2.load().then(function () { + if ( + document.documentElement.className.indexOf( + "js-hasFontsLoaded" + ) == -1 + ) { + document.documentElement.className += " js-hasFontsLoaded"; + } + Cookies.set("fonts_loaded", true); + }); - // Lazy-Load Media - if (typeof loadMedia === "function") { - loadMedia(".js-lazyLoader", null, true); - } + // Lazy-Load Media + if (typeof loadMedia === "function") { + loadMedia(".js-lazyLoader", null, true); + } - // Add relative dates via dayjs - if (window.dayjs) { - const times = document.getElementsByTagName("time"); + // Add relative dates via dayjs + if (window.dayjs) { + const times = document.getElementsByTagName("time"); - [].forEach.call(times, function (the_time) { - let pub_time = the_time.getAttribute("datetime"); - if (the_time.className.indexOf("js-noRelativeTime") === -1) - the_time.innerHTML += - ' (' + - dayjs(pub_time).from(dayjs()) + - ")"; - the_time.classList.add("isDone"); - }); - } + [].forEach.call(times, function (the_time) { + let pub_time = the_time.getAttribute("datetime"); + if (the_time.className.indexOf("js-noRelativeTime") === -1) + the_time.innerHTML += + ' (' + + dayjs(pub_time).from(dayjs()) + + ")"; + the_time.classList.add("isDone"); + }); + } - if (document.documentElement.className.indexOf("is404") > -1) { - document.getElementById("searchQuery").value = - window.location.pathname - .replace(/\\.html?$/, "") - .replace(/\//g, " "); - } + if (document.documentElement.className.indexOf("is404") > -1) { + document.getElementById("searchQuery").value = + window.location.pathname + .replace(/\\.html?$/, "") + .replace(/\//g, " "); + } - document - .getElementById("searchForm") - .addEventListener("submit", function (e) { - document.getElementById("searchQuery").value += - " site:" + window.location.hostname; - }); - }, 1); - }); + document + .getElementById("searchForm") + .addEventListener("submit", function (e) { + document.getElementById("searchQuery").value += + " site:" + window.location.hostname; + }); + }, 1); + }); })(); // @license-end diff --git a/src/assets/styles/fonts.css b/src/assets/styles/fonts.css index 77b8474..97be442 100644 --- a/src/assets/styles/fonts.css +++ b/src/assets/styles/fonts.css @@ -1,4 +1,13 @@ -@font-face { +/**************************************************************************** + * It's Eric Woodward (dotcom) + * + * Copyright 2015-2023 Eric Woodward + * Source released under CC0 Public Domain License v1.0 + * https://www.itsericwoodward.com/licenses/cc0 + * http://creativecommons.org/publicdomain/zero/1. + ****************************************************************************/ + + @font-face { font-family: 'exo_2'; src: url('/fonts/exo2/Exo2-Regular-webfont.eot'); src: url('/fonts/exo2/Exo2-Regular-webfont.eot?#iefix') format('embedded-opentype'), diff --git a/src/assets/styles/imports.css b/src/assets/styles/imports.css index 46709b5..dbf507a 100644 --- a/src/assets/styles/imports.css +++ b/src/assets/styles/imports.css @@ -1,9 +1,10 @@ /**************************************************************************** * It's Eric Woodward (dotcom) * - * Copyright 2015-2018 Eric Woodward + * Copyright 2015-2023 Eric Woodward * Source released under CC0 Public Domain License v1.0 - * http://creativecommons.org/publicdomain/zero/1.0/ + * https://www.itsericwoodward.com/licenses/cc0 + * http://creativecommons.org/publicdomain/zero/1. ****************************************************************************/ /*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */ diff --git a/src/assets/styles/styles.css b/src/assets/styles/styles.css index c87b4a0..44e8e3c 100644 --- a/src/assets/styles/styles.css +++ b/src/assets/styles/styles.css @@ -1,9 +1,10 @@ /**************************************************************************** * It's Eric Woodward (dotcom) * - * Copyright 2015-2018 Eric Woodward + * Copyright 2015-2023 Eric Woodward * Source released under CC0 Public Domain License v1.0 - * http://creativecommons.org/publicdomain/zero/1.0/ + * https://www.itsericwoodward.com/licenses/cc0 + * http://creativecommons.org/publicdomain/zero/1. ****************************************************************************/ /* @@ -548,6 +549,13 @@ samp { width: 15em; } +.magnetLink { + display: block; + font-size: x-small; + margin: auto; + text-align: center; +} + .mainBio-div-img { height: auto; margin: 0; diff --git a/src/layouts/partials/footer.ejs b/src/layouts/partials/footer.ejs index 6f612d8..cb14da2 100644 --- a/src/layouts/partials/footer.ejs +++ b/src/layouts/partials/footer.ejs @@ -27,14 +27,14 @@ Except where otherwise noted, content on this site is © 2014-2023 <%=site.author.name%>, and is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License. + href="/licenses/cc-by-sa.html">Creative Commons Attribution-ShareAlike 4.0 International License.
diff --git a/src/layouts/partials/licenses/menusub.ejs b/src/layouts/partials/licenses/menusub.ejs new file mode 100644 index 0000000..79282c1 --- /dev/null +++ b/src/layouts/partials/licenses/menusub.ejs @@ -0,0 +1,25 @@ + diff --git a/src/layouts/partials/menusub.ejs b/src/layouts/partials/menusub.ejs index 52d4f88..4824f04 100644 --- a/src/layouts/partials/menusub.ejs +++ b/src/layouts/partials/menusub.ejs @@ -11,7 +11,9 @@ <%- include('thur/menusub') %> <% } %> <% } else if (page.section && page.subsection && page.section === 'web') { %> - <% if (page.subsection === 'linklists' && page.name !== 'index') { %> + <% if (page.subsection === 'licenses' && page.name !== 'index') { %> + <%- include('licenses/menusub') %> + <% } else if (page.subsection === 'linklists' && page.name !== 'index') { %> <%- include('linklists/menusub') %> <% } %> <% } else if (page.content_type === 'journal') { %> diff --git a/src/pages/about.ejs b/src/pages/about.ejs index 38b5b02..de60486 100644 --- a/src/pages/about.ejs +++ b/src/pages/about.ejs @@ -3,7 +3,6 @@ "title": "About", "description": "Information about both Eric and the site.", "date_pub": "2015-11-10T07:18:00-05:00", - "date_upd": "2021-06-21T23:58:00-04:00", "section" : "about", "content_type": "feature", "short_code": "ma", @@ -62,9 +61,9 @@@license magnet:?xt=urn:btih:90dc5c0be029de84e523b9b3922520e79e0e6f08&dn=cc0.txt CC0-1.0diff --git a/src/pages/licenses/index.md b/src/pages/licenses/index.md new file mode 100644 index 0000000..672273a --- /dev/null +++ b/src/pages/licenses/index.md @@ -0,0 +1,14 @@ +--- +title: Licenses +description: The licenses for the content that Eric produces. +date_pub: 2023-07-26T22:30:00-04:00 +section: licenses +content_type: feature +short_code: "11" +--- + +The following licenses are used on this site and [elsewhere](https://www.planarvagabond.com/) [around the web](https://git.itsericwoodward.com/explore/repos): + +- [Creative Commons Attribution-ShareAlike 4.0 International (CC-BY-SA)](./cc-by-sa.html) +- [Creative Commons CC0 1.0 Universal](cc0.html) +- [MIT](mit.html) diff --git a/src/pages/licenses/mit.md b/src/pages/licenses/mit.md new file mode 100644 index 0000000..ef067f8 --- /dev/null +++ b/src/pages/licenses/mit.md @@ -0,0 +1,19 @@ +--- +title: MIT License +description: A local copy of the MIT license. +date_pub: 2023-07-23T20:45:00-04:00 +section: web +subsection: licenses +content_type: feature +short_code: 1m1t +--- + +Copyright © 2023 [Eric Woodward](https://www.itsericwoodward.com/) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +
@license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt MITdiff --git a/src/pages/now.md b/src/pages/now.md index 52f25ff..c117f64 100644 --- a/src/pages/now.md +++ b/src/pages/now.md @@ -14,4 +14,4 @@ Between the hours of roughly 9AM and 12AM (`America/New_York` time, give or take - making another [magic deck](/magic-decks), - playing D&D (especially if it's Thursday, because that's **Togar's night!**), - messing around with some crazy side project (probably involving a game and/or a Raspberry Pi), or -- building out my Monday night astral campaign, [The Planar Vagabond's Guide to the Multiverse](http://www.planarvagabond.com/). +- building out my Monday night astral campaign, [The Planar Vagabond's Guide to the Multiverse](https://www.planarvagabond.com/). diff --git a/src/pages/web.md b/src/pages/web.md index 6f17529..185a120 100644 --- a/src/pages/web.md +++ b/src/pages/web.md @@ -14,10 +14,11 @@ The web is, IMHO, the most revolutionary invention in information sharing since ### Here - [LinkLists](/linklists) - Lists of links (natch) to various web sites, resources, and/or [blogs](/linklists/blogroll.html), typically organized around a particular subject. Like bookmarking, but not. Updated (occasionally). +- [Licenses](/licenses) - Permanent copies of the licenses that I use [here](https://git.itsericwoodward.com/explore/repos) and [there](https://www.planarvagabond.com/). ### Elsewhere -- [The Planar Vagabond's Guide to the Multiverse](http://www.planarvagabond.com/) **NEW** - The website for a free role-playing game that I'm developing as part of an ongoing campaign, which doubles as a nifty pocket guide to the wild and weird multiverse of interplanar travel. +- [The Planar Vagabond's Guide to the Multiverse](https://www.planarvagabond.com/) **NEW** - The website for a free role-playing game that I'm developing as part of an ongoing campaign, which doubles as a nifty pocket guide to the wild and weird multiverse of interplanar travel. - [Mythic Wars](https://mythicwarsgame.com/) - The site for my tabletop card-and-dice game, where the gods and goddesses themselves battle for ultimate supremacy! Features a free print-and-play demo, lots of free wallpapers, and the comprehensive rules, among other things. - [The Codex Mythica](https://codex.mythicwarsgame.com/) - An [open-source](https:/git.itsericwoodward.com/eric/codex-mythica/) web application I wrote which functions as a card database for Mythic Wars. - [My Blog](https://blog.itsericwoodward.com) - A retired instance of the [Known blogging software](https://withknown.com/) where I used to collect my various day-to-day musings. diff --git a/src/sitePosts/journal/2023/07-20-planar-vagabond.md b/src/sitePosts/journal/2023/07-20-planar-vagabond.md index 1d79168..0f1f343 100644 --- a/src/sitePosts/journal/2023/07-20-planar-vagabond.md +++ b/src/sitePosts/journal/2023/07-20-planar-vagabond.md @@ -1,9 +1,9 @@ --- title: The Planar Vagabond's Guide to the Multiverse Has Arrived! content_type: journal -date_pub: 2023-07-20T12:42:00-05:00 +date_pub: 2023-07-20T12:42:00-04:00 description: I launched a whole-new site, collecting my custom OSR homebrew (and other content) into a single interplanar space. -tags: games osr +tags: games osr PlanarVagabond --- Announcing the arrival of the most important interplanar publication since the great _Encyclopedia of the University Eternal_; a wholly remarkable tome, more popular than the _Idiot’s Guide to Running an Astral Business_, better selling than _Fifty More Things to do in Subjective Gravity_, and more controversial than Balyx Balator’s trilogy of metaphysical blockbusters: _Where the Gods Went Wrong_, _Infernus: Fairy-tale or Fiction?_, and _The Lie of Alignment_... diff --git a/src/sitePosts/journal/2023/07-23-officially-licensed.md b/src/sitePosts/journal/2023/07-23-officially-licensed.md new file mode 100644 index 0000000..c43428c --- /dev/null +++ b/src/sitePosts/journal/2023/07-23-officially-licensed.md @@ -0,0 +1,35 @@ +--- +title: I'm Officially Licensed! +content_type: journal +date_pub: 2023-07-23T22:05:00-4:00 +description: I've started hosting my own licenses on this very website. +tags: copyright licensing CC0 CC_BY_SA MIT +--- + +For the past few years, I've been releasing content under various licenses, usually linking to the "official" website for each one. But starting today, I'm looking towards the future, as I've finally added web-friendly versions of several of these licenses to [this very website](/licenses). + +Right now, there's only 3 (which makes sense, since that's all I'm using at the moment), but with all of them excitement over the [ORC license](https://downloads.paizo.com/ORC_License_FINAL.pdf) (and some other OGL alternatives), who knows what this brave, licensed future will hold? + +### Why Host Them Here? + +Two simple reasons. + +1. I like having a simple, permanent link to each license's text (ideally, with my name on said licenses). +2. If I'm going to have a simple, permanent link to each license's text, it's going to be hosted on my website. + +See? Simple. + +### Where Are They Being Used? + +- [Creative Commons CC0 1.0 Universal](/licenses/cc0.html) + - Most of the client [CSS](/styles/styles.css) and [JS](/scripts/scripts.js) files here, [MythicWarsGame.com](https://www.mythicwarsgame.com/), and [PlanarVagabond.com](https://www.planavagabond.com/) are released under this license (and shipped un-minified) to make it easier for others to read the underlying #web code. + - I've been toying with some AI image generators for making simple pictures of [magic items](https://www.planarvagabond.com/magic-items/) (as well as the odd NPC), but the Federal Copyright Office says they can't be copyrighted, so I released them under this license as well. +- [Creative Commons Attribution-ShareAlike 4.0 International](/licenses/cc-by-sa.html) + - Most of the content here and at my other sites (often stored in [Markdown](https://www.markdownguide.org/) format). + - Honestly, this is my favorite license to use, as it feels like it helps others build new things without enabling over-monetization (including the scourge that are web ads). +- [The MIT License](/licenses/mit.html) + - The server-side source for most of my [server-based projects](https://git.itsericwoodward.com/explore/repos) (and most of the forks stashed on my [Github account](https://github.com/ItsEricWoodward)) are released under this license + +I'm working on a few other fun projects right now, and I figure that having these links will be increasingly useful if and when I get them to launch. + +Until next time, here's to the future!