Compare commits

..

6 Commits

16 changed files with 210 additions and 81 deletions

View File

@ -23,6 +23,8 @@ export default async function posts(): Promise<Page[]> {
} }
if (page.metadata.source && page.metadata.source!.endsWith(".md")) { if (page.metadata.source && page.metadata.source!.endsWith(".md")) {
(<PostMetadata>page.metadata).readingTime = util.getReadingTime(page.text);
page.text = markdown.render(page.text); page.text = markdown.render(page.text);
} }

View File

@ -23,6 +23,8 @@ async function generateTutorials(group: string): Promise<Page[]> {
} }
if (page.metadata.source && page.metadata.source!.endsWith(".md")) { if (page.metadata.source && page.metadata.source!.endsWith(".md")) {
(<PostMetadata>page.metadata).readingTime = util.getReadingTime(page.text);
page.text = markdown.render(page.text); page.text = markdown.render(page.text);
} }

View File

@ -1,9 +1,49 @@
import MarkdownIt from "markdown-it"; import MarkdownIt from "markdown-it";
import StateCore from "markdown-it/lib/rules_core/state_core";
import MarkdownItAnchor from "markdown-it-anchor";
import slugify from "@sindresorhus/slugify";
import * as util from "./util"; import * as util from "./util";
const md = new MarkdownIt({ const md = new MarkdownIt({
highlight: util.highlight, highlight: util.highlight,
html: true html: true,
typographer: true
});
// Inserts heading anchors
// Based on https://github.com/valeriangalliat/markdown-it-anchor
md.core.ruler.push("anchor", (state) => {
const tokens = state.tokens;
tokens
.filter((token) => token.type === "heading_open")
.forEach((token) => {
const index = tokens.indexOf(token);
const title = tokens[index + 1]
.children
.filter((token) => token.type === "text" || token.type == "code_inline")
.reduce((acc, t) => acc + t.content, "");
let slug = token.attrGet("id") || slugify(title);
if (token.attrGet("id") == null) {
token.attrPush(["id", slug]);
}
const linkTokens = [
Object.assign(new state.Token("link_open", "a", 1), {
attrs: [
["class", "header-anchor"],
["href", "#" + slug],
["aria-hidden", "true"]
]
}),
Object.assign(new state.Token("html_block", "", 0), { content: token.markup }),
new state.Token("link_close", "a", -1),
Object.assign(new state.Token("text", "", 0), { content: " " })
];
state.tokens[index + 1].children.unshift(...linkTokens);
});
}); });
export function render(text: string): string { export function render(text: string): string {

View File

@ -17,6 +17,7 @@ export interface PostMetadata extends Metadata {
slug: string; slug: string;
category: string; category: string;
date: string | Date; date: string | Date;
readingTime?: number;
excerpt?: string; excerpt?: string;
uuid: string; uuid: string;
} }

View File

@ -12,6 +12,12 @@ export async function write(filePath: string, data: any) {
await fs.writeFile(dest, data); await fs.writeFile(dest, data);
} }
export function getReadingTime(text: string): number {
const avgWPM = 225;
const words = text.split(/\s+/).length;
return Math.max(1, Math.round(words / avgWPM))
}
export function highlight(source: string, language?: string): string { export function highlight(source: string, language?: string): string {
const res = language ? hljs.highlight(language, source) : hljs.highlightAuto(source); const res = language ? hljs.highlight(language, source) : hljs.highlightAuto(source);
const highlighted = res.value; const highlighted = res.value;

View File

@ -43,17 +43,62 @@ article {
margin-bottom: 75px; margin-bottom: 75px;
color: var(--content-text-color); color: var(--content-text-color);
@media (min-width: 768px) {
a::before { content: "["; }
a::after { content: "](" attr(href) ")"; word-wrap: break-word; }
a::before, a::after {
color: var(--secondary-ui-text-color);
font-family: $monospace;
font-size: 14px;
}
a { text-decoration: none; }
}
code::before, code::after {
content: "`";
font-family: $monospace;
color: var(--secondary-ui-text-color);
}
pre {
&::before, &::after {
content: "```";
display: block;
background: none;
color: var(--secondary-ui-text-color);
}
code::before, code::after {
content: "";
display: none;
}
}
strong::before, strong::after {
content: "**";
font-family: $monospace;
color: var(--secondary-ui-text-color);
}
em::before, em::after {
content: "_";
font-family: $monospace;
color: var(--secondary-ui-text-color);
}
&::after { &::after {
content: ""; content: "";
width: calc(100% - 2 * 30px); // account for .container padding, don't overflow width: calc(100% - 2 * 30px); // account for .container padding, don't overflow
height: 1px; height: 1px;
background-image: linear-gradient(to right, var(--accent-color), var(--shadow-color)); background-color: var(--accent-color);
position: absolute; position: absolute;
} }
.article-title { .article-title {
margin-top: 20px; margin-top: 20px;
margin-bottom: 0; margin-bottom: 0;
font-size: 1.8rem;
&::before {
content: "#";
font-family: $monospace;
color: var(--accent-color);
}
> a { > a {
color: var(--content-text-color); color: var(--content-text-color);
@ -63,6 +108,9 @@ article {
&:hover { &:hover {
color: var(--accent-color); color: var(--accent-color);
} }
&::before, &::after {
content: "";
}
} }
} }
@ -71,6 +119,9 @@ article {
font-size: 14px; font-size: 14px;
font-weight: lighter; font-weight: lighter;
color: var(--secondary-ui-text-color); color: var(--secondary-ui-text-color);
a { text-decoration: underline; }
a::before, a::after { content: ""; }
} }
.article-content { .article-content {
@ -79,7 +130,17 @@ article {
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6 {
font-family: $sansSerif; font-family: $sansSerif;
.header-anchor {
font-family: $monospace;
color: var(--accent-color);
&::before, &::after { content: ""; }
}
} }
h1 { font-size: 1.8rem; }
h2 { font-size: 1.6rem; }
} }
} }
@ -164,6 +225,7 @@ article {
a { a {
color: var(--accent-color); color: var(--accent-color);
text-decoration: underline;
&.fancy-link { &.fancy-link {
position: relative; position: relative;
@ -348,7 +410,7 @@ figure {
flex-wrap: wrap; flex-wrap: wrap;
padding-top: 10px; padding-top: 10px;
border-top: 3px solid var(--accent-color); // border-top: 3px solid var(--accent-color);
} }
.site-title { .site-title {

View File

@ -8,7 +8,12 @@ Modified to use colors from CSS vars, defined in theme.scss
overflow-x: auto; overflow-x: auto;
padding: 0.5em; padding: 0.5em;
color: var(--atom-mono-1); color: var(--atom-mono-1);
}
.hljs > code {
background: var(--atom-base); background: var(--atom-base);
display: block;
} }
.hljs-comment, .hljs-comment,

View File

@ -1,4 +1,5 @@
<p class="article-meta"> <p class="article-meta">
<meta itemprop="author" value="Shadowfacts">
on on
<span> <span>
<% const formatted = formatDate(metadata.date, "MMM Do, YYYY") %> <% const formatted = formatDate(metadata.date, "MMM Do, YYYY") %>
@ -11,6 +12,8 @@
in in
<span itemprop="articleSection"><a href="/tutorials/<%= metadata.series %>" rel="category"><%= metadata.seriesName %></a></span> <span itemprop="articleSection"><a href="/tutorials/<%= metadata.series %>" rel="category"><%= metadata.seriesName %></a></span>
<% } %> <% } %>
by <% if (metadata.readingTime) { %>
<span itemprop="author">Shadowfacts</span>
<%= metadata.readingTime %> min read
<% } %>
</p> </p>

View File

@ -6,9 +6,11 @@ metadata.layout = "default.html.ejs"
<div class="main"> <div class="main">
<% for (const post of posts) { %> <% for (const post of posts) { %>
<article itemscope itemtype="https://schema.org/BlogPosting"> <article itemscope itemtype="https://schema.org/BlogPosting">
<h2 class="article-title" itemprop="headline"> <h1 class="article-title" itemprop="headline">
<%- fancyLink(post.metadata.title, post.metadata.permalink, `itemprop="url mainEntityOfPage"`) %> <a href="<%= post.metadata.permalink %>" itemprop="url mainEntityOfPage">
</h2> <%= post.metadata.title %>
</a>
</h1>
<%- include("includes/article-meta.html.ejs", { metadata: post.metadata }) %> <%- include("includes/article-meta.html.ejs", { metadata: post.metadata }) %>
<div class="article-content" itemprop="description"> <div class="article-content" itemprop="description">
<%- post.metadata.excerpt %> <%- post.metadata.excerpt %>

View File

@ -4,7 +4,9 @@ metadata.layout = "default.html.ejs"
<article itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting"> <article itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<meta itemprop="mainEntityOfPage" content="https://shadowfacts.net<%= metadata.permalink %>"> <meta itemprop="mainEntityOfPage" content="https://shadowfacts.net<%= metadata.permalink %>">
<h1 class="article-title" itemprop="name headline"><%= metadata.title %></h1> <h1 class="article-title" itemprop="name headline">
<%= metadata.title %>
</h1>
<%- include("../includes/article-meta.html.ejs", { metadata }) %> <%- include("../includes/article-meta.html.ejs", { metadata }) %>
<div class="article-content" itemprop="articleBody"> <div class="article-content" itemprop="articleBody">
<%- content %> <%- content %>

View File

@ -11,7 +11,9 @@ metadata.layout = "default.html.ejs";
<% for (const tutorial of tutorials) { %> <% for (const tutorial of tutorials) { %>
<article> <article>
<h2 class="article-title"> <h2 class="article-title">
<%- fancyLink(tutorial.metadata.title, tutorial.metadata.permalink) %> <a href="<%= tutorial.metadata.permalink %>">
<%= tutorial.metadata.title %>
</a>
</h2> </h2>
<%- include("includes/article-meta.html.ejs", { metadata: tutorial.metadata }) %> <%- include("includes/article-meta.html.ejs", { metadata: tutorial.metadata }) %>
</article> </article>

View File

@ -6,7 +6,9 @@ metadata.layout = "default.html.ejs"
<% for (const series of allSeries) { %> <% for (const series of allSeries) { %>
<article> <article>
<h2 class="article-title"> <h2 class="article-title">
<%- fancyLink(series.index.metadata.title, series.index.metadata.permalink) %> <a href="<%= series.index.metadata.permalink %>">
<%= series.index.metadata.title %>
</a>
</h2> </h2>
<p class="article-meta"> <p class="article-meta">
last updated on last updated on

View File

@ -11,31 +11,31 @@ This series of tutorials teaches modding [Minecraft](https://minecraft.net) vers
**This tutorial series does not teach Java. You should already know Java before you try to mod Minecraft.** **This tutorial series does not teach Java. You should already know Java before you try to mod Minecraft.**
### Tutorials ### Tutorials
- [Setting up the Development Environment](/tutorials/forge-modding-1102/workspace-setup/) - [Setting up the Development Environment](../workspace-setup/)
- [Main Mod Class](/tutorials/forge-modding-1102/main-mod-class/) - [Main Mod Class](../main-mod-class/)
- [Proxy System](/tutorials/forge-modding-1102/proxy-system/) - [Proxy System](../proxy-system/)
- [Basic Items](/tutorials/forge-modding-1102/basic-items/) - [Basic Items](../basic-items/)
- [JSON Item Models](/tutorials/forge-modding-1102/json-item-models/) - [JSON Item Models](../json-item-models/)
- [Basic Blocks](/tutorials/forge-modding-1102/basic-blocks/) - [Basic Blocks](../basic-blocks/)
- [Basic Forge Blockstates](/tutorials/forge-modding-1102/basic-forge-blockstates/) - [Basic Forge Blockstates](../basic-forge-blockstates/)
- [Localization](/tutorials/forge-modding-1102/localization/) - [Localization](../localization/)
- [Crops](/tutorials/forge-modding-1102/crops/) - [Crops](../crops/)
- [Creative Tabs](/tutorials/forge-modding-1102/creative-tabs/) - [Creative Tabs](../creative-tabs/)
- [Advanced Creative Tabs](/tutorials/forge-modding-1102/advanced-creative-tabs/) - [Advanced Creative Tabs](../advanced-creative-tabs/)
- [Crafting/Smelting Recipes](/tutorials/forge-modding-1102/crafting-smelting-recipes/) - [Crafting/Smelting Recipes](../crafting-smelting-recipes/)
- [Ore Dictionary](/tutorials/forge-modding-1102/ore-dictionary/) - [Ore Dictionary](../ore-dictionary/)
- [JSON Block Models](/tutorials/forge-modding-1102/json-block-models/) - [JSON Block Models](../json-block-models/)
- [Food](/tutorials/forge-modding-1102/food/) - [Food](../food/)
- [Tools](/tutorials/forge-modding-1102/tools/) - [Tools](../tools/)
- [Armor](/tutorials/forge-modding-1102/armor/) - [Armor](../armor/)
- [World Generation: Ore](/tutorials/forge-modding-1102/world-generation-ore/) - [World Generation: Ore](../world-generation-ore/)
- World Generation: Tree - World Generation: Tree
- World Generation: Structure - World Generation: Structure
- mcmod.info - mcmod.info
- [Tile Entities](/tutorials/forge-modding-1102/tile-entities/) - [Tile Entities](../tile-entities/)
- [Tile Entities with Inventory](/tutorials/forge-modding-1102/tile-entities-inventory/) - [Tile Entities with Inventory](../tile-entities-inventory/)
- [Tile Entities with Inventory GUI](/tutorials/forge-modding-1102/tile-entities-inventory-gui/) - [Tile Entities with Inventory GUI](../tile-entities-inventory-gui/)
- [Dynamic Tile Entity Rendering](/tutorials/forge-modding-1102/dynamic-tile-entity-rendering/) - [Dynamic Tile Entity Rendering](../dynamic-tile-entity-rendering/)
- Advanced GUIs with Widgets - Advanced GUIs with Widgets
- Energy API - RF - Items - Energy API - RF - Items
- Energy API - RF - Blocks - Energy API - RF - Blocks

View File

@ -11,32 +11,32 @@ This series of tutorials teaches modding [Minecraft](https://minecraft.net) vers
**This tutorial series does not teach Java. You should already know Java before you try to mod Minecraft.** **This tutorial series does not teach Java. You should already know Java before you try to mod Minecraft.**
### Tutorials ### Tutorials
- [Setting up the Development Environment](/tutorials/forge-modding-1112/workspace-setup/) - [Setting up the Development Environment](../workspace-setup/)
- [Main Mod Class](/tutorials/forge-modding-1112/main-mod-class/) - [Main Mod Class](../main-mod-class/)
- [Proxy System](/tutorials/forge-modding-1112/proxy-system/) - [Proxy System](../proxy-system/)
- [Basic Items](/tutorials/forge-modding-1112/basic-items/) - [Basic Items](../basic-items/)
- [JSON Item Models](/tutorials/forge-modding-1112/json-item-models/) - [JSON Item Models](../json-item-models/)
- [Basic Blocks](/tutorials/forge-modding-1112/basic-blocks/) - [Basic Blocks](../basic-blocks/)
- [Basic Forge Blockstates](/tutorials/forge-modding-1112/basic-forge-blockstates/) - [Basic Forge Blockstates](../basic-forge-blockstates/)
- [Localization](/tutorials/forge-modding-1112/localization/) - [Localization](../localization/)
- [Crops](/tutorials/forge-modding-1112/crops/) - [Crops](../crops/)
- [Creative Tabs](/tutorials/forge-modding-1112/creative-tabs/) - [Creative Tabs](../creative-tabs/)
- [Advanced Creative Tabs](/tutorials/forge-modding-1112/advanced-creative-tabs/) - [Advanced Creative Tabs](../advanced-creative-tabs/)
- [Crafting/Smelting Recipes](/tutorials/forge-modding-1112/crafting-smelting-recipes/) - [Crafting/Smelting Recipes](../crafting-smelting-recipes/)
- [Ore Dictionary](/tutorials/forge-modding-1112/ore-dictionary/) - [Ore Dictionary](../ore-dictionary/)
- [JSON Block Models](/tutorials/forge-modding-1112/json-block-models/) - [JSON Block Models](../json-block-models/)
- [Food](/tutorials/forge-modding-1112/food/) - [Food](../food/)
- [Tools](/tutorials/forge-modding-1112/tools/) - [Tools](../tools/)
- [Armor](/tutorials/forge-modding-1112/armor/) - [Armor](../armor/)
- [World Generation: Ore](/tutorials/forge-modding-1112/world-generation-ore/) - [World Generation: Ore](../world-generation-ore/)
- _Interlude:_ [Updating to 1.11](/tutorials/forge-modding-1112/updating-to-1112/) - _Interlude:_ [Updating to 1.11](../updating-to-1112/)
- World Generation: Tree - World Generation: Tree
- World Generation: Structure - World Generation: Structure
- mcmod.info - mcmod.info
- [Tile Entities](/tutorials/forge-modding-1112/tile-entities/) - [Tile Entities](../tile-entities/)
- [Tile Entities with Inventory](/tutorials/forge-modding-1112/tile-entities-inventory/) - [Tile Entities with Inventory](../tile-entities-inventory/)
- [Tile Entities with Inventory GUI](/tutorials/forge-modding-1112/tile-entities-inventory-gui/) - [Tile Entities with Inventory GUI](../tile-entities-inventory-gui/)
- [Dynamic Tile Entity Rendering](/tutorials/forge-modding-1112/dynamic-tile-entity-rendering/) - [Dynamic Tile Entity Rendering](../dynamic-tile-entity-rendering/)
- Advanced GUIs with Widgets - Advanced GUIs with Widgets
- Energy API - RF - Items - Energy API - RF - Items
- Energy API - RF - Blocks - Energy API - RF - Blocks

View File

@ -11,32 +11,32 @@ This series of tutorials teaches modding [Minecraft](https://minecraft.net) vers
**This tutorial series does not teach Java. You should already know Java before you try to mod Minecraft.** **This tutorial series does not teach Java. You should already know Java before you try to mod Minecraft.**
### Tutorials ### Tutorials
- [Setting up the Development Environment](/tutorials/forge-modding-112/workspace-setup/) - [Setting up the Development Environment](../workspace-setup/)
- [Main Mod Class](/tutorials/forge-modding-112/main-mod-class/) - [Main Mod Class](../main-mod-class/)
- [Proxy System](/tutorials/forge-modding-112/proxy-system/) - [Proxy System](../proxy-system/)
- [Basic Items](/tutorials/forge-modding-112/basic-items/) - [Basic Items](../basic-items/)
- [JSON Item Models](/tutorials/forge-modding-112/json-item-models/) - [JSON Item Models](../json-item-models/)
- [Basic Blocks](/tutorials/forge-modding-112/basic-blocks/) - [Basic Blocks](../basic-blocks/)
- [Basic Forge Blockstates](/tutorials/forge-modding-112/basic-forge-blockstates/) - [Basic Forge Blockstates](../basic-forge-blockstates/)
- [Localization](/tutorials/forge-modding-112/localization/) - [Localization](../localization/)
- [Crops](/tutorials/forge-modding-112/crops/) - [Crops](../crops/)
- [Creative Tabs](/tutorials/forge-modding-112/creative-tabs/) - [Creative Tabs](../creative-tabs/)
- [Advanced Creative Tabs](/tutorials/forge-modding-112/advanced-creative-tabs/) - [Advanced Creative Tabs](../advanced-creative-tabs/)
- [Crafting Recipes](/tutorials/forge-modding-112/crafting-recipes/) - [Crafting Recipes](../crafting-recipes/)
- [Smelting Recipes](/tutorials/forge-modding-112/smelting-recipes/) - [Smelting Recipes](../smelting-recipes/)
- [Ore Dictionary](/tutorials/forge-modding-112/ore-dictionary/) - [Ore Dictionary](../ore-dictionary/)
- [JSON Block Models](/tutorials/forge-modding-112/json-block-models/) - [JSON Block Models](../json-block-models/)
- [Food](/tutorials/forge-modding-112/food/) - [Food](../food/)
- [Tools](/tutorials/forge-modding-112/tools/) - [Tools](../tools/)
- [Armor](/tutorials/forge-modding-112/armor/) - [Armor](../armor/)
- [World Generation: Ore](/tutorials/forge-modding-112/world-generation-ore/) - [World Generation: Ore](../world-generation-ore/)
- World Generation: Tree - World Generation: Tree
- World Generation: Structure - World Generation: Structure
- mcmod.info - mcmod.info
- [Tile Entities](/tutorials/forge-modding-112/tile-entities/) - [Tile Entities](../tile-entities/)
- [Tile Entities with Inventory](/tutorials/forge-modding-112/tile-entities-inventory/) - [Tile Entities with Inventory](../tile-entities-inventory/)
- [Tile Entities with Inventory GUI](/tutorials/forge-modding-112/tile-entities-inventory-gui/) - [Tile Entities with Inventory GUI](../tile-entities-inventory-gui/)
- [Dynamic Tile Entity Rendering](/tutorials/forge-modding-112/dynamic-tile-entity-rendering/) - [Dynamic Tile Entity Rendering](../dynamic-tile-entity-rendering/)
- Advanced GUIs with Widgets - Advanced GUIs with Widgets
- Energy API - RF - Items - Energy API - RF - Items
- Energy API - RF - Blocks - Energy API - RF - Blocks

View File

@ -1,9 +1,9 @@
{ {
"compilerOptions": { "compilerOptions": {
/* Basic Options */ /* Basic Options */
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ "target": "ES2015", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"lib": ["es6"], /* Specify library files to be included in the compilation. */ "lib": ["es6", "es7"], /* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow javascript files to be compiled. */ // "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */ // "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */