Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eleventy.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module.exports = function(eleventyConfig) {
eleventyConfig.addPassthroughCopy("css");
eleventyConfig.addPassthroughCopy("js");
eleventyConfig.addPassthroughCopy("CNAME");
eleventyConfig.addLayoutAlias("default", "default.njk");
return {
Expand Down
54 changes: 54 additions & 0 deletions _data/topics.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
[
{
"title": "Buffer and Streams",
"url": "/buffer-and-streams/"
},
{
"title": "Control flow",
"url": "/control-flow/"
},
{
"title": "Child Processes",
"url": "/child-processes/"
},
{
"title": "Diagnostics",
"url": "/diagnostics/"
},
{
"title": "Error Handling",
"url": "/error-handling/"
},
{
"title": "Node.js CLI",
"url": "/nodejs-cli/"
},
{
"title": "Events",
"url": "/events/"
},
{
"title": "File System",
"url": "/file-system/"
},
{
"title": "JavaScript Prerequisites",
"url": "/javascript-prerequisites/"
},
{
"title": "Module system",
"url": "/module-system/"
},
{
"title": "Process/Operating System",
"url": "/process-operating-system/"
},
{
"title": "Package.json",
"url": "/package-json/"
},
{
"title": "Unit Testing",
"url": "/unit-testing/"
}
]
22 changes: 7 additions & 15 deletions _includes/default.njk
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ title: OpenJS NodeJS Application Developer Study Guide
href="//cdn.jsdelivr.net/gh/highlightjs/cdn-release@9.16.2/build/styles/default.min.css">
<script src="//cdn.jsdelivr.net/gh/highlightjs/cdn-release@9.16.2/build/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
<script src="{{ "/js/main.js" | url }}"></script>
</head>
<body>
<header class="container">
Expand All @@ -33,26 +34,17 @@ title: OpenJS NodeJS Application Developer Study Guide
<div class="row">
<div class="sidebar column">
<nav>
<ul>
<li><a href="#" {% if page.url === '/buffer/' %} class="current" {% endif %}>Buffer and Streams</a></li>
<li><a href="#">Control flow</a></li>
<li><a href="#">Child Processes</a></li>
<li><a href="#">Diagnostics</li>
<li><a href="#">Error Handling</a></li>
<li><a href="#">Node.js CLI</a></li>
<li><a href="{{ "/events" | url }}" {% if page.url === '/events/' %} class="current" {% endif %}>Events</li>
<li><a href="#">File System</a></li>
<li><a href="#">JavaScript Prerequisites</a></li>
<li><a href="#">Module system</a></li>
<li><a href="#">Process/Operating System</a></li>
<li><a href="#">Package.json</a></li>
<li><a href="#">Unit Testing</a></li>
<ul class="topics">
{% for topic in topics %}
<li data-topic="{{topic.url}}">
<a href="{{ topic.url | url }}" {% if page.url === topic.url %} class="current" {% endif %}>{{topic.title}}</a>
</li>
{% endfor %}
</ul>
</nav>
</div>
<div class="main-content column column-75">
<h1>{{ title }}</h1>

{{ content | safe }}
</div>
</div>
Expand Down
10 changes: 10 additions & 0 deletions _includes/post.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
layout: default.njk
templateClass: tmpl-post
---

{{ content | safe }}

<h3>Ready to mark {{title}} as completed?</h3>

<button onClick="toggleCompletedTopic('{{page.url}}')" data-topic="{{page.url}}" class="completed-button">Mark as completed</button>
2 changes: 1 addition & 1 deletion control-flow/index.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
layout: default.njk
layout: post.njk
title: Control Flow
---

Expand Down
30 changes: 30 additions & 0 deletions css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ main h1 {
a {
color: #80bd01;
font-weight: bold;
transition: all 200ms ease-out;
}

a:hover {
Expand Down Expand Up @@ -60,12 +61,41 @@ a:hover {
.sidebar a {
color: #888;
font-weight: normal;
position: relative;
transition: opacity 0.5s ease-out, padding 0.5s cubic-bezier(0, 1, 0.5, 1);
}

.sidebar a.current {
color: #80bd01;
opacity: 1 !important;
}

.sidebar .completed a {
opacity: 0.5;
padding-left: 20px;
transition: opacity 0.5s ease-out;
}

.sidebar a:before {
content: "✔️";
color: #80bd01;
left: 0;
position: absolute;
transform: scale(0) translateX(-40px);
transition: transform 0.5s cubic-bezier(0.5, -0.5, 0.5, 1.5);
}

.sidebar .completed a:before {
transform: scale(1);
}

.sidebar a:hover {
color: #80bd01;
opacity: 1;
}

.completed-button.completed {
background-color: #fff;
border-color: #80bd01;
color: #333;
}
2 changes: 1 addition & 1 deletion events/index.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
layout: default.njk
layout: post.njk
title: Events
url: events
---
Expand Down
88 changes: 88 additions & 0 deletions js/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
window.addEventListener("DOMContentLoaded", event => {
if (window.localStorage) {
window.topicsCompleted = getTopicsFromLocalStorage();
updateUI();
}
});

function updateUI() {
checkForCompletedButtons();
checkSideBar();
}

function checkForCompletedButtons() {
[...getButtons()].forEach(button => {
const topic = button.dataset.topic;
if (isCompleted(topic)) {
markButtonAsCompleted(button);
} else {
markButtonAsNotCompleted(button);
}
});
}

function getButtons() {
return document.querySelectorAll(".completed-button");
}

function toggleCompletedTopic(topic) {
if (isCompleted(topic)) {
removeCompletedTopic(topic);
updateUI();
} else {
addCompletedTopic(topic);
updateUI();
}
}

function isCompleted(topic) {
return window.topicsCompleted && window.topicsCompleted.includes(topic);
}

function markButtonAsCompleted(button) {
button.classList.add("completed");
button.innerText = "Completed!";
}

function markButtonAsNotCompleted(button) {
button.classList.remove("completed");
button.innerText = "Mark as completed";
}

function getTopicsFromLocalStorage() {
return JSON.parse(window.localStorage.getItem("topicsCompleted"));
}

function addCompletedTopic(topic) {
let topics = getTopicsFromLocalStorage();
if (!topics) {
topics = [];
}
topics.push(topic);
save(topics);
}

function save(topics) {
window.topicsCompleted = topics;
window.localStorage.setItem("topicsCompleted", JSON.stringify(topics));
}

function removeCompletedTopic(topic) {
const topics = getTopicsFromLocalStorage();
save(topics.filter(t => t !== topic));
}

function getSidebarItems() {
return document.querySelectorAll(".topics li");
}

function checkSideBar() {
[...getSidebarItems()].forEach(item => {
const topic = item.dataset.topic;
if (isCompleted(topic)) {
item.classList.add("completed");
} else {
item.classList.remove("completed");
}
});
}