Initial commit

This commit is contained in:
walcutt 2023-01-30 17:03:30 -05:00 committed by GitHub
commit 40cf711943
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 1830 additions and 0 deletions

1
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1 @@
github: maximevaillancourt

30
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,30 @@
---
name: Bug report
about: Something's broken with the template
title: ''
labels: bug
assignees: ''
---
<!-- If you're requesting a new feature or suggesting an idea, please use the "Discussions" tab instead of opening a new issue. Thank you! -->
**Describe the bug**
A clear and concise description of what the bug is.
**To reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- Operating system: [e.g. macOS 11.4]
- Ruby version: [e.g. Ruby 2.7.1]

View File

@ -0,0 +1,10 @@
---
name: Something else
about: Something's wrong, but it's not a bug with the template
title: ''
labels: ''
assignees: ''
---
<!-- If you're requesting a new feature or suggesting an idea, please use the "Discussions" tab instead of opening a new issue. Thank you! -->

15
.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
# Generated website directory
_site/
# Sass cache
.sass-cache/
# Jekyll cache & metadata
.jekyll-cache/
.jekyll-metadata
# Notes graph metadata
_includes/notes_graph.json
# Obsidian config
.obsidian/

11
404.html Normal file
View File

@ -0,0 +1,11 @@
---
permalink: 404.html
layout: default
title: "404"
id: "not-found"
---
<div>
<h1>Oops, that's a 404. 🙈</h1>
<p>Looks like this page doesn't exist. <a href="/">Return home</a> to get a fresh start.</p>
</div>

10
Gemfile Normal file
View File

@ -0,0 +1,10 @@
# frozen_string_literal: true
source "https://rubygems.org"
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
gem "jekyll", "~> 4.0"
gem "jekyll-last-modified-at", git: "https://github.com/maximevaillancourt/jekyll-last-modified-at", branch: "add-support-for-files-in-git-submodules"
gem "webrick", "~> 1.7"
gem "nokogiri"

86
Gemfile.lock Normal file
View File

@ -0,0 +1,86 @@
GIT
remote: https://github.com/maximevaillancourt/jekyll-last-modified-at
revision: e0c918691db625401ef5850a030da59d0124d356
branch: add-support-for-files-in-git-submodules
specs:
jekyll-last-modified-at (1.3.0)
jekyll (>= 3.7, < 5.0)
posix-spawn (~> 0.3.9)
GEM
remote: https://rubygems.org/
specs:
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
colorator (1.1.0)
concurrent-ruby (1.1.7)
em-websocket (0.5.2)
eventmachine (>= 0.12.9)
http_parser.rb (~> 0.6.0)
eventmachine (1.2.7)
ffi (1.14.2)
forwardable-extended (2.6.0)
http_parser.rb (0.6.0)
i18n (1.8.5)
concurrent-ruby (~> 1.0)
jekyll (4.2.0)
addressable (~> 2.4)
colorator (~> 1.0)
em-websocket (~> 0.5)
i18n (~> 1.0)
jekyll-sass-converter (~> 2.0)
jekyll-watch (~> 2.0)
kramdown (~> 2.3)
kramdown-parser-gfm (~> 1.0)
liquid (~> 4.0)
mercenary (~> 0.4.0)
pathutil (~> 0.9)
rouge (~> 3.0)
safe_yaml (~> 1.0)
terminal-table (~> 2.0)
jekyll-sass-converter (2.1.0)
sassc (> 2.0.1, < 3.0)
jekyll-watch (2.2.1)
listen (~> 3.0)
kramdown (2.3.1)
rexml
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
liquid (4.0.3)
listen (3.3.3)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
mercenary (0.4.0)
mini_portile2 (2.8.0)
nokogiri (1.13.10)
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
pathutil (0.16.2)
forwardable-extended (~> 2.6)
posix-spawn (0.3.15)
public_suffix (4.0.6)
racc (1.6.1)
rb-fsevent (0.10.4)
rb-inotify (0.10.1)
ffi (~> 1.0)
rexml (3.2.5)
rouge (3.26.0)
safe_yaml (1.0.5)
sassc (2.4.0)
ffi (~> 1.9)
terminal-table (2.0.0)
unicode-display_width (~> 1.1, >= 1.1.1)
unicode-display_width (1.7.0)
webrick (1.7.0)
PLATFORMS
ruby
DEPENDENCIES
jekyll (~> 4.0)
jekyll-last-modified-at!
nokogiri
webrick (~> 1.7)
BUNDLED WITH
2.2.3

9
LICENSE Normal file
View File

@ -0,0 +1,9 @@
# Released under MIT License
Copyright (c) 2020 Maxime Vaillancourt.
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.

15
README.md Normal file
View File

@ -0,0 +1,15 @@
# Digital garden Jekyll template + Searching
A template based off of [this template](https://github.com/maximevaillancourt/digital-garden-jekyll-template), incorporating a Jekyll search plugin from [here](https://github.com/christian-fei/Simple-Jekyll-Search).
- Based on Jekyll, a static website generator
- Supports Roam-style double bracket link syntax to other notes
- Creates backlinks to other notes automatically
- Features link previews on hover
- Includes graph visualization of the notes and their links
- Features a simple and responsive design
- Supports Markdown or HTML notes
- *NEW:* Supports searching of existing posts.
Source code is available under the [MIT license](LICENSE.md).

45
_config.yml Normal file
View File

@ -0,0 +1,45 @@
title: My digital garden
include: ['_pages']
exclude: ['_includes/notes_graph.json']
# You may need to change the base URL depending on your deploy configuration.
# Specifically, when using GitHub Pages, the baseurl should point to where GitHub
# Pages deploys your repository (which is usually the repository name).
baseurl: ''
# If you are using a host that cannot resolve URLs that do
# not end with .html (such as Neocities), set this to 'true'.
use_html_extension: false
# Set to `true` to open non-internal links in new tabs, or
# set to `false` to open non-internal links in current tab.
open_external_links_in_new_tab: true
# Set to `true` to replace tweet URLs with Twitter embeds.
# Note that doing so will negatively the reader's privacy
# as their browser will communicate with Twitter's servers.
embed_tweets: false
permalink: pretty
relative_permalinks: false
plugins:
- jekyll-last-modified-at
sass:
sass_dir: _sass
style: :compressed
collections:
notes:
output: true
permalink: /:slug
defaults:
- scope:
path: "**/*"
values:
layout: "default"
- scope:
path: "_notes/**/*.md"
values:
layout: "note"

1
_includes/footer.html Normal file
View File

@ -0,0 +1 @@
This is the footer. Include anything you'd like here, like a link to an <a class="internal-link" href="/about">About</a> page, of a <a class="internal-link" href="/search">Search</a> page.

48
_includes/head.html Normal file
View File

@ -0,0 +1,48 @@
<head>
<meta charset="UTF-8">
<link rel="canonical" href="{{ site.url }}{{ page.url }}" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="{% if page.excerpt %}{{ page.excerpt | strip_html | strip_newlines | truncate: 160 }}{% else %}{{ site.title }}{% endif %}">
<meta property="og:site_name" content="{{ site.title }}">
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=">
<link rel="stylesheet" href="{{ site.baseurl }}/styles.css">
{% if page.excerpt %}
<meta property="og:description" content="{{ page.excerpt | strip_html | strip_newlines | truncate: 160 }}"/>
{% else %}
<meta property="og:description" content="{{ site.title | strip_html | strip_newlines | truncate: 160 }}"/>
{% endif %}
{% if page.title %}
<meta property="og:title" content="{{ page.title }}">
<meta property="og:type" content="article">
{% else %}
<meta property="og:title" content="{{ site.title }}">
<meta property="og:type" content="website">
{% endif %}
{% if page.date %}
<meta property="article:published_time" content="{{ page.date | date_to_xmlschema }}">
<meta property="article:author" content="{{ site.url }}/">
{% endif %}
<meta property="og:url" content="{{ site.url }}{{ page.url }}" />
{% if page.image %}
<meta property="og:image" content="{{ site.url }}{{ page.image }}">
{% endif %}
<title>
{% if page.id == "home" %}
{{ site.title }}
{% else %}
{{ page.title }} &mdash; {{ site.title }}
{% endif %}
</title>
</head>

View File

@ -0,0 +1,140 @@
<!-- That file is not particularly elegant. This will need a refactor at some point. -->
<style>
content a.internal-link {
border-color: #8b88e6;
background-color: #efefff;
}
#tooltip-wrapper {
background: white;
padding: 1em;
border: 1px solid #ddd;
border-radius: 4px;
overflow: hidden;
position: absolute;
width: 400px;
height: 250px;
font-size: 0.8em;
box-shadow: 0 5px 10px rgba(0,0,0,0.1);
opacity: 0;
transition: opacity 100ms;
}
#tooltip-wrapper:after {
content: "";
position: absolute;
z-index: 1;
bottom: 0;
left: 0;
pointer-events: none;
background-image: linear-gradient(to bottom, rgba(255,255,255, 0), rgba(255,255,255, 1) 90%);
width: 100%;
height: 75px;
}
</style>
<div style="opacity: 0; display: none;" id='tooltip-wrapper'>
<div id='tooltip-content'>
</div>
</div>
<iframe style="display: none; height: 0; width: 0;" id='link-preview-iframe' src="">
</iframe>
<script>
var opacityTimeout;
var contentTimeout;
var transitionDurationMs = 100;
var iframe = document.getElementById('link-preview-iframe')
var tooltipWrapper = document.getElementById('tooltip-wrapper')
var tooltipContent = document.getElementById('tooltip-content')
var linkHistories = {};
function hideTooltip() {
opacityTimeout = setTimeout(function() {
tooltipWrapper.style.opacity = 0;
contentTimeout = setTimeout(function() {
tooltipContent.innerHTML = '';
tooltipWrapper.style.display = 'none';
}, transitionDurationMs + 1);
}, transitionDurationMs)
}
function showTooltip(event) {
var elem = event.target;
var elem_props = elem.getClientRects()[elem.getClientRects().length - 1];
var top = window.pageYOffset || document.documentElement.scrollTop
if (event.target.host === window.location.host) {
if (!linkHistories[event.target.href]) {
iframe.src = event.target.href
iframe.onload = function() {
tooltipContentHtml = ''
tooltipContentHtml += '<div style="font-weight: bold;">' + iframe.contentWindow.document.querySelector('h1').innerHTML + '</div>'
tooltipContentHtml += iframe.contentWindow.document.querySelector('content').innerHTML
tooltipContent.innerHTML = tooltipContentHtml
linkHistories[event.target.href] = tooltipContentHtml
tooltipWrapper.style.display = 'block';
setTimeout(function() {
tooltipWrapper.style.opacity = 1;
}, 1)
}
} else {
tooltipContent.innerHTML = linkHistories[event.target.href]
tooltipWrapper.style.display = 'block';
setTimeout(function() {
tooltipWrapper.style.opacity = 1;
}, 1)
}
tooltipWrapper.style.left = elem_props.left - (tooltipWrapper.offsetWidth / 2) + (elem_props.width / 2) + "px";
if ((window.innerHeight - elem_props.top) < (tooltipWrapper.offsetHeight)) {
tooltipWrapper.style.top = elem_props.top + top - tooltipWrapper.offsetHeight - 10 + "px";
} else if ((window.innerHeight - elem_props.top) > (tooltipWrapper.offsetHeight)) {
tooltipWrapper.style.top = elem_props.top + top + 35 + "px";
}
if ((elem_props.left + (elem_props.width / 2)) < (tooltipWrapper.offsetWidth / 2)) {
tooltipWrapper.style.left = "10px";
} else if ((document.body.clientWidth - elem_props.left - (elem_props.width / 2)) < (tooltipWrapper.offsetWidth / 2)) {
tooltipWrapper.style.left = document.body.clientWidth - tooltipWrapper.offsetWidth - 20 + "px";
}
}
}
function setupListeners(linkElement) {
linkElement.addEventListener('mouseleave', function(_event) {
hideTooltip();
});
tooltipWrapper.addEventListener('mouseleave', function(_event) {
hideTooltip();
});
linkElement.addEventListener('touchend', function(_event) {
hideTooltip();
});
tooltipWrapper.addEventListener('touchend', function(_event) {
hideTooltip();
});
linkElement.addEventListener('mouseenter', function(event) {
clearTimeout(opacityTimeout);
clearTimeout(contentTimeout);
showTooltip(event);
});
tooltipWrapper.addEventListener('mouseenter', function(event) {
clearTimeout(opacityTimeout);
clearTimeout(contentTimeout);
});
}
document.querySelectorAll('{{ include.wrapperQuerySelector }} a').forEach(setupListeners);
</script>

3
_includes/nav.html Normal file
View File

@ -0,0 +1,3 @@
<div>
<a class="internal-link" href="{{ site.baseurl }}/"><b>{{ site.title }}</b></a>
</div>

306
_includes/notes_graph.html Normal file
View File

@ -0,0 +1,306 @@
<style>
.links line {
stroke: #ccc;
opacity: 0.5;
}
.nodes circle {
cursor: pointer;
fill: #8b88e6;
transition: all 0.15s ease-out;
}
.text text {
cursor: pointer;
fill: #333;
text-shadow: -1px -1px 0 #fafafabb, 1px -1px 0 #fafafabb, -1px 1px 0 #fafafabb, 1px 1px 0 #fafafabb;
}
.nodes [active],
.text [active] {
cursor: pointer;
fill: black;
}
.inactive {
opacity: 0.1;
transition: all 0.15s ease-out;
}
#graph-wrapper {
background: #fcfcfc;
border-radius: 4px;
height: auto;
}
</style>
<div id="graph-wrapper">
<script>
window.addEventListener("load", loadGraph);
function loadGraph() {
var oScript = document.createElement("script");
oScript.src = "https://cdnjs.cloudflare.com/ajax/libs/d3/5.16.0/d3.min.js";
oScript.crossOrigin = 'anonymous';
oScript.integrity =
"sha512-FHsFVKQ/T1KWJDGSbrUhTJyS1ph3eRrxI228ND0EGaEp6v4a/vGwPWd3Dtd/+9cI7ccofZvl/wulICEurHN1pg==";
document.body.appendChild(oScript);
oScript.onload = () => {
const MINIMAL_NODE_SIZE = 8;
const MAX_NODE_SIZE = 12;
const ACTIVE_RADIUS_FACTOR = 1.5;
const STROKE = 1;
const FONT_SIZE = 16;
const TICKS = 200;
const FONT_BASELINE = 40;
const MAX_LABEL_LENGTH = 50;
const graphData = {% include notes_graph.json %}
let nodesData = graphData.nodes;
let linksData = graphData.edges;
const nodeSize = {};
const updateNodeSize = () => {
nodesData.forEach((el) => {
let weight =
3 *
Math.sqrt(
linksData.filter((l) => l.source.id === el.id || l.target.id === el.id)
.length + 1
);
if (weight < MINIMAL_NODE_SIZE) {
weight = MINIMAL_NODE_SIZE;
} else if (weight > MAX_NODE_SIZE) {
weight = MAX_NODE_SIZE;
}
nodeSize[el.id] = weight;
});
};
const onClick = (d) => {
window.location = d.path
};
const onMouseover = function (d) {
const relatedNodesSet = new Set();
linksData
.filter((n) => n.target.id == d.id || n.source.id == d.id)
.forEach((n) => {
relatedNodesSet.add(n.target.id);
relatedNodesSet.add(n.source.id);
});
node.attr("class", (node_d) => {
if (node_d.id !== d.id && !relatedNodesSet.has(node_d.id)) {
return "inactive";
}
return "";
});
link.attr("class", (link_d) => {
if (link_d.source.id !== d.id && link_d.target.id !== d.id) {
return "inactive";
}
return "";
});
link.attr("stroke-width", (link_d) => {
if (link_d.source.id === d.id || link_d.target.id === d.id) {
return STROKE * 4;
}
return STROKE;
});
text.attr("class", (text_d) => {
if (text_d.id !== d.id && !relatedNodesSet.has(text_d.id)) {
return "inactive";
}
return "";
});
};
const onMouseout = function (d) {
node.attr("class", "");
link.attr("class", "");
text.attr("class", "");
link.attr("stroke-width", STROKE);
};
const sameNodes = (previous, next) => {
if (next.length !== previous.length) {
return false;
}
const map = new Map();
for (const node of previous) {
map.set(node.id, node.label);
}
for (const node of next) {
const found = map.get(node.id);
if (!found || found !== node.title) {
return false;
}
}
return true;
};
const sameEdges = (previous, next) => {
if (next.length !== previous.length) {
return false;
}
const set = new Set();
for (const edge of previous) {
set.add(`${edge.source.id}-${edge.target.id}`);
}
for (const edge of next) {
if (!set.has(`${edge.source.id}-${edge.target.id}`)) {
return false;
}
}
return true;
};
const graphWrapper = document.getElementById('graph-wrapper')
const element = document.createElementNS("http://www.w3.org/2000/svg", "svg");
element.setAttribute("width", graphWrapper.getBoundingClientRect().width);
element.setAttribute("height", window.innerHeight * 0.8);
graphWrapper.appendChild(element);
const reportWindowSize = () => {
element.setAttribute("width", window.innerWidth);
element.setAttribute("height", window.innerHeight);
};
window.onresize = reportWindowSize;
const svg = d3.select("svg");
const width = Number(svg.attr("width"));
const height = Number(svg.attr("height"));
let zoomLevel = 1;
const simulation = d3
.forceSimulation(nodesData)
.force("forceX", d3.forceX().x(width / 2))
.force("forceY", d3.forceY().y(height / 2))
.force("charge", d3.forceManyBody())
.force(
"link",
d3
.forceLink(linksData)
.id((d) => d.id)
.distance(70)
)
.force("center", d3.forceCenter(width / 2, height / 2))
.force("collision", d3.forceCollide().radius(80))
.stop();
const g = svg.append("g");
let link = g.append("g").attr("class", "links").selectAll(".link");
let node = g.append("g").attr("class", "nodes").selectAll(".node");
let text = g.append("g").attr("class", "text").selectAll(".text");
const resize = () => {
if (d3.event) {
const scale = d3.event.transform;
zoomLevel = scale.k;
g.attr("transform", scale);
}
const zoomOrKeep = (value) => (zoomLevel >= 1 ? value / zoomLevel : value);
const font = Math.max(Math.round(zoomOrKeep(FONT_SIZE)), 1);
text.attr("font-size", (d) => font);
text.attr("y", (d) => d.y - zoomOrKeep(FONT_BASELINE) + 8);
link.attr("stroke-width", zoomOrKeep(STROKE));
node.attr("r", (d) => {
return zoomOrKeep(nodeSize[d.id]);
});
svg
.selectAll("circle")
.filter((_d, i, nodes) => d3.select(nodes[i]).attr("active"))
.attr("r", (d) => zoomOrKeep(ACTIVE_RADIUS_FACTOR * nodeSize[d.id]));
};
const ticked = () => {
node.attr("cx", (d) => d.x).attr("cy", (d) => d.y);
text
.attr("x", (d) => d.x)
.attr("y", (d) => d.y - (FONT_BASELINE - nodeSize[d.id]) / zoomLevel);
link
.attr("x1", (d) => d.source.x)
.attr("y1", (d) => d.source.y)
.attr("x2", (d) => d.target.x)
.attr("y2", (d) => d.target.y);
};
const restart = () => {
updateNodeSize();
node = node.data(nodesData, (d) => d.id);
node.exit().remove();
node = node
.enter()
.append("circle")
.attr("r", (d) => {
return nodeSize[d.id];
})
.on("click", onClick)
.on("mouseover", onMouseover)
.on("mouseout", onMouseout)
.merge(node);
link = link.data(linksData, (d) => `${d.source.id}-${d.target.id}`);
link.exit().remove();
link = link.enter().append("line").attr("stroke-width", STROKE).merge(link);
text = text.data(nodesData, (d) => d.label);
text.exit().remove();
text = text
.enter()
.append("text")
.text((d) => shorten(d.label.replace(/_*/g, ""), MAX_LABEL_LENGTH))
.attr("font-size", `${FONT_SIZE}px`)
.attr("text-anchor", "middle")
.attr("alignment-baseline", "central")
.on("click", onClick)
.on("mouseover", onMouseover)
.on("mouseout", onMouseout)
.merge(text);
node.attr("active", (d) => isCurrentPath(d.path) ? true : null);
text.attr("active", (d) => isCurrentPath(d.path) ? true : null);
simulation.nodes(nodesData);
simulation.force("link").links(linksData);
simulation.alpha(1).restart();
simulation.stop();
for (let i = 0; i < TICKS; i++) {
simulation.tick();
}
ticked();
};
const zoomHandler = d3.zoom().scaleExtent([0.2, 3]).on("zoom", resize);
zoomHandler(svg);
restart();
function isCurrentPath(notePath) {
return window.location.pathname.includes(notePath)
}
function shorten(str, maxLen, separator = ' ') {
if (str.length <= maxLen) return str;
return str.substr(0, str.lastIndexOf(separator, maxLen)) + '...';
}
}
}
</script>
</div>

13
_layouts/default.html Normal file
View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
{% include head.html %}
<body>
<nav>{% include nav.html %}</nav>
<div class="wrapper">
<main>{{ content }}</main>
<footer>{% include footer.html %}</footer>
</div>
{% include link-previews.html wrapperQuerySelector="content" %}
</body>
</html>

47
_layouts/note.html Normal file
View File

@ -0,0 +1,47 @@
---
layout: default
---
<article>
<div>
<h1>{{ page.title }}</h1>
<time datetime="{{ page.last_modified_at | date_to_xmlschema }}">{% if page.type != 'pages' %}
Last updated on {{ page.last_modified_at | date: "%B %-d, %Y" }}
{% endif %}
</time>
</div>
<div id="notes-entry-container">
<content>
{{ content }}
<p>This line appears after every note.</p>
</content>
<side style="font-size: 0.9em">
<h3 style="margin-bottom: 1em">Notes mentioning this note</h3>
{% if page.backlinks.size > 0 %}
<div style="display: grid; grid-gap: 1em; grid-template-columns: repeat(1fr);">
{% for backlink in page.backlinks %}
<div class="backlink-box">
<a class="internal-link" href="{{ site.baseurl }}{{ backlink.url }}{%- if site.use_html_extension -%}.html{%- endif -%}">{{ backlink.title }}</a><br>
<div style="font-size: 0.9em">{{ backlink.excerpt | strip_html | truncatewords: 20 }}</div>
</div>
{% endfor %}
</div>
{% else %}
<div style="font-size: 0.9em">
<p>
There are no notes linking to this note.
</p>
</div>
{% endif %}
</side>
</div>
</article>
<hr>
<p>Here are all the notes in this garden, along with their links, visualized as a graph.</p>
{% include notes_graph.html %}

7
_layouts/page.html Normal file
View File

@ -0,0 +1,7 @@
---
layout: default
---
<content>
{{ content }}
</content>

5
_notes/accents.md Normal file
View File

@ -0,0 +1,5 @@
---
title: Bon appétit!
---
Page titles with accents are supported.

21
_notes/animals/cats.md Normal file
View File

@ -0,0 +1,21 @@
---
title: A note about cats
---
This is a second note with a poem with cats.
Here's a link to a note that explains why it's important to [[move your body every day]].
> I like my pillow, my fancy bed,
>
> My cat tree and the bathroom sink.
>
> Each has its time and fills a need,
>
> but a box is best when I want to think.
You can create as many notes as you want.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur et risus at ipsum pharetra pellentesque vel in massa. Nam ornare, velit sed pulvinar gravida, justo ipsum eleifend augue, id porta velit eros vestibulum odio. Vestibulum dignissim malesuada sapien, eu volutpat lacus pellentesque et. Curabitur dui nisi, sagittis ut tempor ac, scelerisque in diam. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum vitae euismod ex. Morbi lacinia iaculis tempor.
Nunc porttitor lacus ullamcorper mauris porttitor feugiat. Vestibulum condimentum lacus vitae orci lobortis pellentesque in ac dolor. Nullam libero justo, suscipit id suscipit vel, tincidunt vitae lectus. Phasellus gravida iaculis ligula, at pharetra urna. Nunc vel tellus eleifend, aliquet magna non, condimentum est. Pellentesque vulputate posuere felis eget sodales. Cras finibus tortor porta libero bibendum, vel bibendum orci luctus. Donec ac eros vitae erat malesuada imperdiet at tempor turpis.

5
_notes/animals/tigers.md Normal file
View File

@ -0,0 +1,5 @@
---
title: Tigers
---
This is yet another note, this one about tigers.

7
_notes/consistency.md Normal file
View File

@ -0,0 +1,7 @@
---
title: Consistency is key
---
Show up. Do the work. Be consistent.
Then go take a look at the [[Your first note|first note]].

View File

@ -0,0 +1,11 @@
---
---
Move your body every day. Benefits include:
- Improved sleep quality
- Less risk of chronic disease
- Increased productivity
- Reduced anxiety
The "every day" part is important, because [[consistency]] is key to most things worth doing.

126
_notes/your-first-note.md Normal file
View File

@ -0,0 +1,126 @@
---
title: Your first seed
---
### Welcome!
This is your first note. You'll find it in the [`notes/`](https://github.com/maximevaillancourt/digital-garden-jekyll-template/tree/master/_notes) directory.
### Link syntax
To link to another note, you can use multiple syntaxes. The following four use the "double-bracket" notation ([view the Markdown source file](https://github.com/maximevaillancourt/digital-garden-jekyll-template/blob/master/_notes/your-first-note.md#link-syntax) to see the underlying syntax).
- Using the note title: [[a note about cats]]
- Using the note's filename: [[cats]]
- Using the note's title, with a label: [[A note about cats|link to the note about cats using the note title]]
- Using the note's filename, with a label: [[cats|link to the note about cats using the note's filename]]
You can organize notes in subdirectories and link them normally. For example, the links above all point to the `_notes/animals/cats.md` file. Here's another example: [[tigers]].
Non-latin languages are supported: [[안녕하세요]]; so are accents/diacritics: [[bon appétit!]]
Dashes and underscores in file names are supported, and may be omitted in the bracket link syntax. As an example, the `your-first-note.md` file can be linked to with [[your first note]] or [[your-first-note]], or even [[yOuR-FiRsT Note]].
In all cases, if the double-bracket link does not point to a valid note, the double brackets will still be shown, like this: [[there is no note that matches this link]].
Alternatively, you can use regular [Markdown syntax](https://www.markdownguide.org/getting-started/) for links, with a relative link to the other note, like this: [this is a Markdown link to the note about cats](/cats){: .internal-link}. Don't forget to use the `.internal-link` class to make sure the link is styled as an internal link (without the little arrow).
Since the Web is all about HTML, you can always use plain HTML if you want, like this: <a class="internal-link" href="/cats">This is a link to the note about cats with HTML</a>.
Of course, you can also link to external websites, like this: [this is a link to Wikipedia](https://wikipedia.org/). Again, you can use plain HTML if you prefer. Footnotes are also supported and will be treated like internal links.[^1] You can point to other notes in your footnotes.[^2]
[^1]: This is a footnote. For more information about using footnotes, check out the [Markdown Guide](https://www.markdownguide.org/extended-syntax/#footnotes).
[^2]: This is another footnote that links to the note about [[cats]]. You may also point to [[notes that do not exist]] if you wish.
### Tweet embedding
Note: This behavior is disabled by default for privacy reasons. See "Site configuration" section below to enable it.
You may include a tweet URL on its own line (like below), and it would be replaced with an official Twitter embed if the site configuration demands it.
https://twitter.com/jack/status/20
### Media embedding
You may embed media files within a note using HTML5 media tags. Here's an example for an audio file:
"Jazzy Frenchy" by Benjamin Tissot from bensound.com
<audio controls>
<source src="/assets/jazzyfrenchy.mp3" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
### Site configuration
Some behavior is configurable by tweaking the `_config.yml` file.
**`use_html_extension`**: if you use a static host that doesn't support URLs that don't end with `.html` (such as Neocities), try changing the `use_html_extension` value to `true` in the `_config.yml` file and restart the Jekyll server (or re-build the site). This adds a `.html` extension to note URLs and may resolve issues with links. If you're still having trouble, I recommend using Netlify to host your digital garden: it's free, easy to use, and fully supports this template's features out of the box.
**`open_external_links_in_new_tab`**: when set to `true`, this makes external links open in new tabs. Set to `false` to open all links in the current tab.
**`embed_tweets`**: when set to `true`, tweet URLs on their own lines will be replaced with a Twitter embed. Default value is `false`.
### Automatic bi-directional links
Notice in the "Notes mentioning this note" section that there is another note linking to this note. This is a bi-directional link, and those are automatically created when you create links to other notes.
### Link previews
If you're on a device with mouse support, try hovering your mouse on internal links to preview the notes: [[a note about cats]].
Links that have been previewed will be cached to avoid redundant requests.
### Images and other Markdown goodies
Finally, because you have the full power of Markdown in this template, you can use regular Markdown syntax for various formatting options.
Lists work as expected:
- List element A
- List element B
- List element C
1. List element
2. List element
3. List element
If you'd like to quote other people, consider using quote blocks:
> Lorem ipsum dolor sit amet
And of course, images look great:
<img src="/assets/image.jpg"/>
You can also ==highlight some content== by wrapping it with `==`.
Non-latin languages are supported too: ==你好==, ==안녕하세요==, ==こんにちは==.
### Code syntax highlighting
You can add code blocks with full syntax color highlighting by wrapping code snippet in triple backticks and specifying the type of the code (`js`, `rb`, `sh`, etc.):
```js
// Here's a bit of JavaScript:
console.log('hello!')
```
```rb
# And now some Ruby
def foo(bar)
"baz"
end
```
```sh
$ cat /dev/urandom | grep "the answer to life" # shell scripts look nice too
```
### Next steps
This digital garden template is free, open-source, and [available on GitHub here](https://github.com/maximevaillancourt/digital-garden-jekyll-template).
The easiest way to build your own digital garden based on this template is to read this [step-by-step guide explaining how to set this up from scratch](https://maximevaillancourt.com/blog/setting-up-your-own-digital-garden-with-jekyll).
Go forth, have fun, and learn new something every day! ✌️

View File

@ -0,0 +1,6 @@
---
title: 안녕하세요
---
This template supports any language. Come as you are! :)

9
_pages/about.md Normal file
View File

@ -0,0 +1,9 @@
---
layout: page
title: About
permalink: /about
---
*This is an about page.*
Feel free to tell the world about what you love! 😍

22
_pages/index.md Normal file
View File

@ -0,0 +1,22 @@
---
layout: page
title: Home
id: home
permalink: /
---
# Welcome! 🌱
<p style="padding: 3em 1em; background: #f5f7ff; border-radius: 4px;">
Take a look at <span style="font-weight: bold">[[Your first note]]</span> to get started on your exploration.
</p>
This digital garden template is free, open-source, and [available on GitHub here](https://github.com/maximevaillancourt/digital-garden-jekyll-template).
The easiest way to get started is to read this [step-by-step guide explaining how to set this up from scratch](https://maximevaillancourt.com/blog/setting-up-your-own-digital-garden-with-jekyll).
<style>
.wrapper {
max-width: 46em;
}
</style>

23
_pages/search.md Normal file
View File

@ -0,0 +1,23 @@
---
layout: page
title: Search
permalink: /search
---
<input type="text" id="search-input" placeholder="Search blog posts..">
<div id="results-container"></div>
<script src="https://unpkg.com/simple-jekyll-search@latest/dest/simple-jekyll-search.min.js"></script>
<script>
window.simpleJekyllSearch = new SimpleJekyllSearch({
searchInput: document.getElementById('search-input'),
resultsContainer: document.getElementById('results-container'),
json:'{{ site.baseurl }}/search.json',
searchResultTemplate: '<div class="search-result-box"><a class="internal-link" href="{url}?query={query}" title="{desc}">{title}</a><br><div class="search-excerpt">{excerpt}</div></div>',
// searchResultTemplate: '<li><a href="{url}?query={query}" title="{desc}">{title}</a></li>',
noResultsText: '<div class="search-result-box">No results found</div>',
limit: 10
});
</script>

View File

@ -0,0 +1,111 @@
# frozen_string_literal: true
class BidirectionalLinksGenerator < Jekyll::Generator
def generate(site)
graph_nodes = []
graph_edges = []
all_notes = site.collections['notes'].docs
all_pages = site.pages
all_docs = all_notes + all_pages
link_extension = !!site.config["use_html_extension"] ? '.html' : ''
# Convert all Wiki/Roam-style double-bracket link syntax to plain HTML
# anchor tag elements (<a>) with "internal-link" CSS class
all_docs.each do |current_note|
all_docs.each do |note_potentially_linked_to|
note_title_regexp_pattern = Regexp.escape(
File.basename(
note_potentially_linked_to.basename,
File.extname(note_potentially_linked_to.basename)
)
).gsub('\_', '[ _]').gsub('\-', '[ -]').capitalize
title_from_data = note_potentially_linked_to.data['title']
if title_from_data
title_from_data = Regexp.escape(title_from_data)
end
new_href = "#{site.baseurl}#{note_potentially_linked_to.url}#{link_extension}"
anchor_tag = "<a class='internal-link' href='#{new_href}'>\\1</a>"
# Replace double-bracketed links with label using note title
# [[A note about cats|this is a link to the note about cats]]
current_note.content.gsub!(
/\[\[#{note_title_regexp_pattern}\|(.+?)(?=\])\]\]/i,
anchor_tag
)
# Replace double-bracketed links with label using note filename
# [[cats|this is a link to the note about cats]]
current_note.content.gsub!(
/\[\[#{title_from_data}\|(.+?)(?=\])\]\]/i,
anchor_tag
)
# Replace double-bracketed links using note title
# [[a note about cats]]
current_note.content.gsub!(
/\[\[(#{title_from_data})\]\]/i,
anchor_tag
)
# Replace double-bracketed links using note filename
# [[cats]]
current_note.content.gsub!(
/\[\[(#{note_title_regexp_pattern})\]\]/i,
anchor_tag
)
end
# At this point, all remaining double-bracket-wrapped words are
# pointing to non-existing pages, so let's turn them into disabled
# links by greying them out and changing the cursor
current_note.content = current_note.content.gsub(
/\[\[([^\]]+)\]\]/i, # match on the remaining double-bracket links
<<~HTML.delete("\n") # replace with this HTML (\\1 is what was inside the brackets)
<span title='There is no note that matches this link.' class='invalid-link'>
<span class='invalid-link-brackets'>[[</span>
\\1
<span class='invalid-link-brackets'>]]</span></span>
HTML
)
end
# Identify note backlinks and add them to each note
all_notes.each do |current_note|
# Nodes: Jekyll
notes_linking_to_current_note = all_notes.filter do |e|
e.content.include?(current_note.url)
end
# Nodes: Graph
graph_nodes << {
id: note_id_from_note(current_note),
path: "#{site.baseurl}#{current_note.url}#{link_extension}",
label: current_note.data['title'],
} unless current_note.path.include?('_notes/index.html')
# Edges: Jekyll
current_note.data['backlinks'] = notes_linking_to_current_note
# Edges: Graph
notes_linking_to_current_note.each do |n|
graph_edges << {
source: note_id_from_note(n),
target: note_id_from_note(current_note),
}
end
end
File.write('_includes/notes_graph.json', JSON.dump({
edges: graph_edges,
nodes: graph_nodes,
}))
end
def note_id_from_note(note)
note.data['title'].bytes.join
end
end

22
_plugins/embed_tweets.rb Normal file
View File

@ -0,0 +1,22 @@
# frozen_string_literal: true
class TweetEmbedGenerator < Jekyll::Generator
def generate(site)
return if !site.config["embed_tweets"]
all_notes = site.collections['notes'].docs
all_pages = site.pages
all_docs = all_notes + all_pages
all_docs.each do |current_note|
current_note.content.gsub!(
/^https?:\/\/twitter\.com\/(?:#!\/)?(\w+)\/status(es)?\/(\d+)$/i,
<<~HTML
<blockquote class="twitter-tweet">
This tweet could not be embedded. <a href="#{'\0'}">View it on Twitter instead.</a>
</blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
HTML
)
end
end
end

View File

@ -0,0 +1,18 @@
# frozen_string_literal: true
EMPTY_FRONT_MATTER = <<~JEKYLL
---
---
JEKYLL
# Inject empty front matter in notes that don't have any
Jekyll::Hooks.register :site, :after_init do |site|
Dir.glob(site.collections['notes'].relative_directory + '/**/*.md').each do |filename|
raw_note_content = File.read(filename)
unless raw_note_content.start_with?('---')
raw_note_content.prepend(EMPTY_FRONT_MATTER)
File.write(filename, raw_note_content)
end
end
end

View File

@ -0,0 +1,18 @@
# frozen_string_literal: true
# Turns ==something== in Markdown to <mark>something</mark> in output HTML
Jekyll::Hooks.register [:notes], :post_convert do |doc|
replace(doc)
end
Jekyll::Hooks.register [:pages], :post_convert do |doc|
# jekyll considers anything at the root as a page,
# we only want to consider actual pages
next unless doc.path.start_with?('_pages/')
replace(doc)
end
def replace(doc)
doc.content.gsub!(/==+([^ ](.*?)?[^ .=]?)==+/, "<mark>\\1</mark>")
end

View File

@ -0,0 +1,28 @@
# If the configuration sets `open_external_links_in_new_tab` to a truthy value,
# add 'target=_blank' to anchor tags that don't have `internal-link` class
# frozen_string_literal: true
require 'nokogiri'
Jekyll::Hooks.register [:notes], :post_convert do |doc|
convert_links(doc)
end
Jekyll::Hooks.register [:pages], :post_convert do |doc|
# jekyll considers anything at the root as a page,
# we only want to consider actual pages
next unless doc.path.start_with?('_pages/')
convert_links(doc)
end
def convert_links(doc)
open_external_links_in_new_tab = !!doc.site.config["open_external_links_in_new_tab"]
if open_external_links_in_new_tab
parsed_doc = Nokogiri::HTML(doc.content)
parsed_doc.css("a:not(.internal-link):not(.footnote):not(.reversefootnote)").each do |link|
link.set_attribute('target', '_blank')
end
doc.content = parsed_doc.inner_html
end
end

76
_sass/_code.scss Normal file
View File

@ -0,0 +1,76 @@
.highlight {
background: #f8f8f8;
padding: 1px 1em;
border-radius: 3px;
font-size: 1em;
font-size: 0.9em;
overflow: auto;
margin: 1em -1em;
code{
padding: 0;
}
}
div.highlight {
display: grid;
}
.highlight .c { color: #999988; font-style: italic } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { font-weight: bold } /* Keyword */
.highlight .o { font-weight: bold } /* Operator */
.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */
.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */
.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #999999 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #aaaaaa } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { font-weight: bold } /* Keyword.Constant */
.highlight .kd { font-weight: bold } /* Keyword.Declaration */
.highlight .kp { font-weight: bold } /* Keyword.Pseudo */
.highlight .kr { font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #009999 } /* Literal.Number */
.highlight .s { color: #d14 } /* Literal.String */
.highlight .na { color: #008080 } /* Name.Attribute */
.highlight .nb { color: #0086B3 } /* Name.Builtin */
.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */
.highlight .no { color: #008080 } /* Name.Constant */
.highlight .ni { color: #800080 } /* Name.Entity */
.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */
.highlight .nn { color: #555555 } /* Name.Namespace */
.highlight .nt { color: #000080 } /* Name.Tag */
.highlight .nv { color: #008080 } /* Name.Variable */
.highlight .ow { font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mf { color: #009999 } /* Literal.Number.Float */
.highlight .mh { color: #009999 } /* Literal.Number.Hex */
.highlight .mi { color: #009999 } /* Literal.Number.Integer */
.highlight .mo { color: #009999 } /* Literal.Number.Oct */
.highlight .sb { color: #d14 } /* Literal.String.Backtick */
.highlight .sc { color: #d14 } /* Literal.String.Char */
.highlight .sd { color: #d14 } /* Literal.String.Doc */
.highlight .s2 { color: #d14 } /* Literal.String.Double */
.highlight .se { color: #d14 } /* Literal.String.Escape */
.highlight .sh { color: #d14 } /* Literal.String.Heredoc */
.highlight .si { color: #d14 } /* Literal.String.Interpol */
.highlight .sx { color: #d14 } /* Literal.String.Other */
.highlight .sr { color: #009926 } /* Literal.String.Regex */
.highlight .s1 { color: #d14 } /* Literal.String.Single */
.highlight .ss { color: #990073 } /* Literal.String.Symbol */
.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #008080 } /* Name.Variable.Class */
.highlight .vg { color: #008080 } /* Name.Variable.Global */
.highlight .vi { color: #008080 } /* Name.Variable.Instance */
.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */

338
_sass/_normalize.scss Normal file
View File

@ -0,0 +1,338 @@
/*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */
/* Document
========================================================================== */
/**
* 1. Correct the line height in all browsers.
* 2. Prevent adjustments of font size after orientation changes in iOS.
*/
html {
line-height: 1.15; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/* Sections
========================================================================== */
/**
* Remove the margin in all browsers.
*/
body {
margin: 0;
}
/**
* Correct the font size and margin on `h1` elements within `section` and
* `article` contexts in Chrome, Firefox, and Safari.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/* Grouping content
========================================================================== */
/**
* 1. Add the correct box sizing in Firefox.
* 2. Show the overflow in Edge and IE.
*/
hr {
box-sizing: content-box; /* 1 */
height: 0; /* 1 */
overflow: visible; /* 2 */
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
pre {
font-size: 1em; /* 2 */
}
/* Text-level semantics
========================================================================== */
/**
* Remove the gray background on active links in IE 10.
*/
a {
background-color: transparent;
}
/**
* 1. Remove the bottom border in Chrome 57-
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
*/
abbr[title] {
border-bottom: none; /* 1 */
text-decoration: underline; /* 2 */
text-decoration: underline dotted; /* 2 */
}
/**
* Add the correct font weight in Chrome, Edge, and Safari.
*/
b,
strong {
font-weight: bolder;
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp {
font-size: 1em; /* 2 */
}
/**
* Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` elements from affecting the line height in
* all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/* Embedded content
========================================================================== */
/**
* Remove the border on images inside links in IE 10.
*/
img {
border-style: none;
}
/* Forms
========================================================================== */
/**
* 1. Change the font styles in all browsers.
* 2. Remove the margin in Firefox and Safari.
*/
button,
input,
optgroup,
select,
textarea {
font-size: 100%; /* 1 */
line-height: 1.15; /* 1 */
margin: 0; /* 2 */
}
/**
* Show the overflow in IE.
* 1. Show the overflow in Edge.
*/
button,
input { /* 1 */
overflow: visible;
}
/**
* Remove the inheritance of text transform in Edge, Firefox, and IE.
* 1. Remove the inheritance of text transform in Firefox.
*/
button,
select { /* 1 */
text-transform: none;
}
/**
* Correct the inability to style clickable types in iOS and Safari.
*/
button,
[type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
/**
* Remove the inner border and padding in Firefox.
*/
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
/**
* Restore the focus styles unset by the previous rule.
*/
button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
outline: 1px dotted ButtonText;
}
/**
* Correct the padding in Firefox.
*/
fieldset {
padding: 0.35em 0.75em 0.625em;
}
/**
* 1. Correct the text wrapping in Edge and IE.
* 2. Correct the color inheritance from `fieldset` elements in IE.
* 3. Remove the padding so developers are not caught out when they zero out
* `fieldset` elements in all browsers.
*/
legend {
box-sizing: border-box; /* 1 */
color: inherit; /* 2 */
display: table; /* 1 */
max-width: 100%; /* 1 */
padding: 0; /* 3 */
white-space: normal; /* 1 */
}
/**
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
*/
progress {
vertical-align: baseline;
}
/**
* Remove the default vertical scrollbar in IE 10+.
*/
textarea {
overflow: auto;
}
/**
* 1. Add the correct box sizing in IE 10.
* 2. Remove the padding in IE 10.
*/
[type="checkbox"],
[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Correct the cursor style of increment and decrement buttons in Chrome.
*/
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Correct the odd appearance in Chrome and Safari.
* 2. Correct the outline style in Safari.
*/
[type="search"] {
-webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}
/**
* Remove the inner padding in Chrome and Safari on macOS.
*/
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* 1. Correct the inability to style clickable types in iOS and Safari.
* 2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button; /* 1 */
font: inherit; /* 2 */
}
/* Interactive
========================================================================== */
/*
* Add the correct display in Edge, IE 10+, and Firefox.
*/
details {
display: block;
}
/*
* Add the correct display in all browsers.
*/
summary {
display: list-item;
}
/* Misc
========================================================================== */
/**
* Add the correct display in IE 10+.
*/
template {
display: none;
}
/**
* Add the correct display in IE 10.
*/
[hidden] {
display: none;
}

162
_sass/_style.scss Normal file
View File

@ -0,0 +1,162 @@
$color-primary: hsl(0, 0%, 10%);
$color-text: hsl(0, 0%, 20%);
$color-subtext: hsl(0, 0%, 30%);
$color-border: hsl(0, 0%, 85%);
$color-box-background: mix($color-primary, white, 4%);
$border-radius: 4px;
$font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,
sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
body {
box-sizing: content-box;
font-family: $font-family;
margin: 0 auto;
line-height: 1.7;
padding: 4vh 6vw;
overflow-x: hidden;
color: $color-text;
font-size: 1rem;
max-width: 63em;
@media (min-width: 820px) {
font-size: 1.2rem;
}
}
time {
display: block;
color: $color-subtext;
margin: 0.5em 0 1em;
}
footer {
margin: 2em 0;
font-size: 0.8em;
color: mix($color-text, white, 80%);
padding-top: 1em;
}
img {
max-width: 100%;
display: block;
margin: 0 auto;
max-height: 75vh;
border-radius: $border-radius;
}
blockquote {
padding: 1.5em;
margin: 0;
font-size: 0.88em;
background: $color-box-background;
border-radius: $border-radius;
p {
margin: 0;
}
}
hr {
width: 100%;
border: 0;
height: 1px;
margin: 1.5em 0;
background: $color-border;
}
h1,
h2,
h3,
h4,
h5,
h6 {
line-height: 1.3;
margin-bottom: 0;
padding-bottom: 0;
}
a {
transition: background 300ms;
padding: 0 0.1em;
text-decoration: none;
border-bottom: 1px solid $color-border;
color: $color-primary;
&:hover {
color: black !important;
background: #fffaf1;
}
&:after {
position: relative;
top: -0.5em;
font-size: 0.7em;
content: "";
color: #aaaaaa;
}
&.internal-link:after,
&.footnote:after,
&.reversefootnote:after {
content: "";
}
}
*:focus {
background: #ffe8bc !important;
color: black !important;
}
nav {
margin: 1em 0 3em;
}
#notes-entry-container {
display: grid;
grid-gap: 2em;
grid-template-areas:
"content"
"side";
@media (min-width: 700px) {
grid-template-columns: 3fr 1fr;
grid-template-areas: "content side";
}
}
.backlink-box, .search-result-box {
background: $color-box-background;
padding: 1em;
border-radius: $border-radius;
}
.search-result-box {
margin-bottom: 1em;
}
#search-input {
width: 100%;
background: $color-box-background;
border: 0px;
border-radius: 4px;
padding: 0.5em;
}
#search-input:focus {
background: $color-primary;
}
code {
background: #f5f5f5;
padding: 0.1em 0.2em;
border-radius: 4px;
}
.invalid-link {
color: #444444;
cursor: help;
background: #fafafa;
padding: 0 0.1em;
}
.invalid-link-brackets {
color: #ccc;
cursor: help;
}

BIN
assets/image.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 641 KiB

BIN
assets/jazzyfrenchy.mp3 Normal file

Binary file not shown.

3
netlify.toml Normal file
View File

@ -0,0 +1,3 @@
[build]
command = "jekyll build --trace"
publish = "_site"

16
search.json Normal file
View File

@ -0,0 +1,16 @@
---
layout: none
---
[
{% for post in site.notes %}
{
"title" : "{{ post.title | escape }}",
"category" : "{{ post.category }}",
"tags" : "{{ post.tags | join: ', ' }}",
"url" : "{{ site.baseurl }}{{ post.url }}",
"date" : "{{ post.date }}",
"content" : "{{ post.content | strip_html | strip_newlines | smartify }}",
"excerpt" : "{{ post.content | strip_html | strip_newlines | smartify | truncatewords: 20 }}"
} {% unless forloop.last %},{% endunless %}
{% endfor %}
]

6
styles.scss Normal file
View File

@ -0,0 +1,6 @@
---
---
@import "../_sass/normalize";
@import "../_sass/code";
@import "../_sass/style";