feat: Initial commit :)

This commit is contained in:
daudix-UFO
2023-08-31 03:38:44 +03:00
parent 940c84f4ee
commit f6cc7270d8
44 changed files with 2725 additions and 1 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
_site/
.sass-cache/
.jekyll-cache/
.jekyll-metadata
.gem

28
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,28 @@
image: jekyll/jekyll
cache:
paths:
- _bundle/
build:
stage: build
script:
- bundle install
- bundle exec jekyll build
- mv _site public
artifacts:
paths:
- public
except:
- main
pages:
stage: deploy
script:
- bundle exec jekyll build
- mv _site public
artifacts:
paths:
- public
only:
- main

52
.woodpecker.yml Normal file
View File

@ -0,0 +1,52 @@
# Jekyll on Woodpecker to codeberg pages
#
# This file would typically be .woodpecker.yml in the root of your repository.
#
# Takes a repository with jekyll source, generates the static site and
# pushes the result to codeberg pages
#
# Needs a codeberg access token (cbtoken) as secret in woodpecker config
# Also uses another secret (cbmail) with email address for git config
#
# CBIN must be replaced with the source repo
# CBOUT must be replaced with the target codeberg pages repo
# CBUSER must be replaced with the user/org
#
# See the _config.yml file for the important keep_files: line to preserve
# git metadata during build
#
# We also assume a domains file in the source repo that gets copied to
# .domains in the target repo so codeberg pages works for custom domains
#
steps:
build:
# Use the official jekyll build container
image: jekyll/jekyll
secrets: [ cbtoken, cbmail ]
commands:
# Avoid permission denied errors
- chmod -R a+w .
# Set up git in a working way
- git config --global --add safe.directory /woodpecker/src/codeberg.org/daudix-UFO/duckquill-source/_site
- git config --global user.email "$CBMAIL"
- git config --global user.name "CI Builder"
- git config --global init.defaultBranch pages
# clone and move the target repo
- git clone -b pages https://codeberg.org/daudix-UFO/duckquill.git
- mv blog _site
- chmod -R a+w _site
- cd _site
# Prepare for push
- git remote set-url origin https://$CBTOKEN@codeberg.org/daudix-UFO/duckquill.git
- cd ..
# Run Jekyll build stage
- bundle install
- bundle exec jekyll build
# Only needed for custom domains
# - cp domains _site/.domains
# Push to target
- cd _site
- git add --all
- git commit -m "Woodpecker CI Jekyll Build at $( env TZ=Europe/Berlin date +"%Y-%m-%d %X %Z" )"
- git push

13
404.md Normal file
View File

@ -0,0 +1,13 @@
---
layout: default
permalink: /404.html
---
![404]({{site.baseurl}}/assets/404.png){:.full.pixels}{:loading="lazy"}
# Document Not Found
The requested page could not be found. If you feel this is not normal, then you create an issue on the {{ site.hosting }}.
[Go Back](<javascript:window.history.go(-1);>){: .inline-button} [File an issue]({{site.issuesurl}})
{: .dialog-buttons}

5
Dockerfile Normal file
View File

@ -0,0 +1,5 @@
FROM jekyll/jekyll
COPY Gemfile* ./
RUN chmod -R a+w . && bundle install

10
Gemfile Normal file
View File

@ -0,0 +1,10 @@
source 'https://rubygems.org'
group :jekyll_plugins do
gem 'jekyll-sass-converter', '~> 2.2'
gem 'jekyll-sitemap'
gem 'jekyll-feed'
gem 'jekyll-toc'
end
gem "webrick"

83
Gemfile.lock Normal file
View File

@ -0,0 +1,83 @@
GEM
remote: https://rubygems.org/
specs:
addressable (2.8.5)
public_suffix (>= 2.0.2, < 6.0)
colorator (1.1.0)
concurrent-ruby (1.2.2)
em-websocket (0.5.3)
eventmachine (>= 0.12.9)
http_parser.rb (~> 0)
eventmachine (1.2.7)
ffi (1.15.5)
forwardable-extended (2.6.0)
http_parser.rb (0.8.0)
i18n (1.14.1)
concurrent-ruby (~> 1.0)
jekyll (4.3.2)
addressable (~> 2.4)
colorator (~> 1.0)
em-websocket (~> 0.5)
i18n (~> 1.0)
jekyll-sass-converter (>= 2.0, < 4.0)
jekyll-watch (~> 2.0)
kramdown (~> 2.3, >= 2.3.1)
kramdown-parser-gfm (~> 1.0)
liquid (~> 4.0)
mercenary (>= 0.3.6, < 0.5)
pathutil (~> 0.9)
rouge (>= 3.0, < 5.0)
safe_yaml (~> 1.0)
terminal-table (>= 1.8, < 4.0)
webrick (~> 1.7)
jekyll-feed (0.17.0)
jekyll (>= 3.7, < 5.0)
jekyll-sass-converter (2.2.0)
sassc (> 2.0.1, < 3.0)
jekyll-sitemap (1.4.0)
jekyll (>= 3.7, < 5.0)
jekyll-toc (0.18.0)
jekyll (>= 3.9)
nokogiri (~> 1.12)
jekyll-watch (2.2.1)
listen (~> 3.0)
kramdown (2.4.0)
rexml
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
liquid (4.0.4)
listen (3.8.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
mercenary (0.4.0)
nokogiri (1.15.4-x86_64-linux)
racc (~> 1.4)
pathutil (0.16.2)
forwardable-extended (~> 2.6)
public_suffix (5.0.3)
racc (1.7.1)
rb-fsevent (0.11.2)
rb-inotify (0.10.1)
ffi (~> 1.0)
rexml (3.2.6)
rouge (4.1.3)
safe_yaml (1.0.5)
sassc (2.4.0)
ffi (~> 1.9)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
unicode-display_width (2.4.2)
webrick (1.8.1)
PLATFORMS
x86_64-linux-musl
DEPENDENCIES
jekyll-feed
jekyll-sass-converter (~> 2.2)
jekyll-sitemap
jekyll-toc
webrick
BUNDLED WITH
2.3.25

View File

@ -1,2 +1,5 @@
# duckquill-source
- Jakub Steiner for an awesome [OS Component Website](https://jimmac.github.io/os-component-website) that are used as a base
- Cassidy James for and awesome [Mastodon-powered comments](https://cassidyjames.com/blog/fediverse-blog-comments-mastodon)
- dwb, ejm and jgs for ASCII art

62
_config.yml Normal file
View File

@ -0,0 +1,62 @@
# Site settings
title: Duckquill
baseurl: "/duckquill" # the subpath of your site, e.g. /blog/
# usually empty. necessary for building absolute URIs
# for metadata header
url: "https://daudix-ufo.codeberg.page" # the base hostname & protocol for your site
sourceurl: "https://codeberg.org/daudix-UFO/duckquill" # "edit this website" link in the footer
hosting: "Codeberg" # the hosting of your site, e.g Codeberg
description: "Duckquill blog template."
issuesurl: "https://codeberg.org/daudix-UFO/duckquill/issues" # issue tracker for website
permalink: /:title/
primary-color: "#ffa348" # used in iOS theme. further color customization in _sass/variables.scss
# Mastodon-powered commenting.
# See https://github.com/cassidyjames/cassidyjames.github.io/blob/main/_config.yaml#L31-L70
# Values can be overridden in front-matter, e.g.
# for multi-author blogs or guest posts.
comments:
# Your Mastodon API host; this should be where you have an account
host: mstdn.social
# Optional; vanity domain if configured; host will be used if omitted
domain:
# Used to determine who the original/verified poster is; role may be expanded
# in the future (e.g. for moderation)
username: Daudix
# Optional; required to fetch more than 60 replies to any given blog post.
# Application access token with read:statuses scope; NOTE: IF INCLUDED, ANYONE
# WILL BE ABLE TO READ THE ASSOCIATED ACCOUNT'S PRIVATE STATUSES. It is highly
# recommended to use a dedicated bot/API account to create an application with
# scope read:statuses.
token:
# Additional verified usernames in username@example.com format. If they are on
# the host listed above, OMIT the @example.com
verified:
# Build settings
markdown: kramdown
timezone: UTC
exclude: [Gemfile, Gemfile.lock, Dockerfile, local.sh, rename.sh, README.md]
compress_html:
blanklines: true
feed:
tags:
path: "feed/tags/"
plugins:
- jekyll-sitemap
- jekyll-feed
- jekyll-toc
defaults:
- scope:
path: "_posts"
type: "posts"
values:
layout: "default"
author: "Duckquill"
destination: "posts"

427
_includes/comments.html Normal file
View File

@ -0,0 +1,427 @@
<!--
Taken from https://github.com/cassidyjames/cassidyjames.github.io/blob/99782788a7e3ba3cc52d6803010873abd1b02b9e/_includes/comments.html
Inspired by https://codeberg.org/jwildeboer/jwildeboersource/src/commit/45f9750bb53b9f0f6f28399ce4d21785a3bb7d22/_includes/fediverse_comments.html
-->
{% if include.host %}
{% assign host = include.host %}
{% elsif page.comments.host %}
{% assign host = page.comments.host %}
{% else %}
{% assign host = site.comments.host %}
{% endif %}
{% if include.domain %}
{% assign domain = include.domain %}
{% elsif page.comments.domain %}
{% assign domain = page.comments.domain %}
{% elsif site.comments.domain %}
{% assign domain = site.comments.domain %}
{% else %}
{% assign domain = host %}
{% endif %}
{% if include.username %}
{% assign username = include.username %}
{% elsif page.comments.username %}
{% assign username = page.comments.username %}
{% else %}
{% assign username = site.comments.username %}
{% endif %}
{% if include.token %}
{% assign token = include.token %}
{% elsif page.comments.token %}
{% assign token = page.comments.token %}
{% else %}
{% assign token = site.comments.token %}
{% endif %}
{% if include.id %}
{% assign id = include.id %}
{% else %}
{% assign id = page.comments.id %}
{% endif %}
{% if site.comments.verified %}
{% assign verified = site.comments.verified | jsonify %}
{% else %}
{% assign verified = "[]" %}
{% endif %}
<section id="comments" class="article comments">
<h2>Comments</h2>
<p>Comment on this blog post by publicly replying to <a href="https://{{ host }}/@{{ username }}/{{ id }}">this Mastodon post</a> using a Mastodon or other ActivityPub/&ZeroWidthSpace;Fediverse account. Known non-private replies are displayed below.</p>
<div id="comments-wrapper">
<p><small>No known comments, yet. Reply to <a href="https://{{ host }}/@{{ username }}/{{ id }}">this Mastodon post</a> to add your own!</small></p>
<noscript><p>Loading comments relies on JavaScript. Try enabling JavaScript and reloading, or visit <a href="https://{{ host }}/@{{ username }}/{{ id }}">the original post</a> on Mastodon.</p></noscript>
</div>
<script>
// loadComments();
function loadComments() {
const HOST = "{{ host }}";
const DOMAIN = "{{ domain }}";
const USERNAME = "{{ username }}";
const TOKEN = "{{ token }}";
const VERIFIED = "{{ verified }}";
const ID = "{{ id }}";
const SUPPORTED_MEDIA = [
"image",
"gifv",
];
const STATUS_URL = `https://${ HOST }/api/v1/statuses/${ ID }`;
const REQUEST_HEADERS = new Headers();
if(TOKEN != ""){
REQUEST_HEADERS.append("Authorization", "Bearer " + TOKEN);
}
const requestOptions = {
method: "GET",
headers: REQUEST_HEADERS,
mode: "cors",
cache: "default",
};
const STATUS_REQUEST = new Request(STATUS_URL, requestOptions);
const CONTEXT_REQUEST = new Request(STATUS_URL + "/context", requestOptions);
let commentsWrapper = document.getElementById("comments-wrapper");
fetch(STATUS_REQUEST).then((response) => {
return response.json();
}).then((status) => {
fetch(CONTEXT_REQUEST).then((response) => {
return response.json();
}).then((data) => {
let descendants = data['descendants'];
if(
descendants &&
Array.isArray(descendants) &&
descendants.length > 0
) {
commentsWrapper.innerHTML = "";
descendants.unshift(status);
descendants.forEach((status) => {
if( status.account.display_name.length > 0 ) {
status.account.display_name = escapeHtml(status.account.display_name);
status.account.display_name = emojify(
status.account.display_name,
status.account.emojis
);
} else {
status.account.display_name = status.account.username;
};
let instance = "";
if( status.account.acct.includes("@") ) {
instance = status.account.acct.split("@")[1];
} else {
instance = DOMAIN;
}
status.content = emojify(status.content, status.emojis);
let avatarSource = document.createElement("source");
avatarSource.setAttribute("srcset", escapeHtml(status.account.avatar));
avatarSource.setAttribute("media", "(prefers-reduced-motion: no-preference)");
let avatarImg = document.createElement("img");
avatarImg.className = "avatar";
avatarImg.setAttribute("src", escapeHtml(status.account.avatar_static));
avatarImg.setAttribute(
"alt",
`@${ status.account.username }@${ instance } avatar`
);
avatarImg.setAttribute("loading", "lazy");
let avatarPicture = document.createElement("picture");
avatarPicture.appendChild(avatarSource);
avatarPicture.appendChild(avatarImg);
let avatar = document.createElement("a");
avatar.className = "avatar-link";
avatar.setAttribute("href", status.account.url);
avatar.setAttribute("rel", "external nofollow");
avatar.setAttribute(
"title",
`View profile at @${ status.account.username }@${ instance }`
);
avatar.appendChild(avatarPicture);
let instanceBadge = document.createElement("a");
instanceBadge.className = "instance";
instanceBadge.setAttribute("href", status.account.url);
instanceBadge.setAttribute(
"title",
`@${ status.account.username }@${ instance }`
);
instanceBadge.setAttribute("rel", "external nofollow");
instanceBadge.textContent = instance;
let display = document.createElement("span");
display.className = "display";
display.setAttribute("itemprop", "author");
display.setAttribute("itemtype", "http://schema.org/Person");
display.innerHTML = status.account.display_name;
let header = document.createElement("header");
header.className = "author";
header.appendChild(display);
header.appendChild(instanceBadge);
let permalink = document.createElement("a");
permalink.setAttribute("href", status.url);
permalink.setAttribute("itemprop", "url");
permalink.setAttribute("title", `View comment at ${ instance }`);
permalink.setAttribute("rel", "external nofollow");
permalink.textContent = new Date(status.created_at).toLocaleString('en-GB', {
dateStyle: "long",
timeStyle: "short",
});
let timestamp = document.createElement("time");
timestamp.setAttribute("datetime", status.created_at);
timestamp.appendChild(permalink);
if(status.edited_at != null) {
timestamp.classList.add("edited");
timestamp.setAttribute(
"title",
"Edited " + new Date(status.edited_at).toLocaleString('en-GB', {
dateStyle: "long",
timeStyle: "short",
})
)
};
let main = document.createElement("main");
main.setAttribute("itemprop", "text");
if(status.sensitive == true || status.spoiler_text != "") {
let summary = document.createElement("summary");
if(status.spoiler_text == "") {
status.spoiler_text == "Sensitive";
}
summary.innerHTML = status.spoiler_text;
let spoiler = document.createElement("details");
spoiler.appendChild(summary);
spoiler.innerHTML += status.content;
main.appendChild(spoiler);
} else {
main.innerHTML = status.content;
}
let interactions = document.createElement("footer");
if(status.reblogs_count > 0) {
let boosts = document.createElement("span");
boosts.className = "boosts";
boosts.setAttribute("title", "Boosts");
boosts.textContent = status.reblogs_count;
interactions.appendChild(boosts);
}
if(status.favourites_count > 0) {
let faves = document.createElement("span");
faves.className = "faves";
faves.setAttribute("title", "Favorites");
faves.textContent = status.favourites_count;
interactions.appendChild(faves);
}
let comment = document.createElement("article");
comment.id = `comment-${ status.id }`;
comment.className = "comment";
comment.setAttribute("itemprop", "comment");
comment.setAttribute("itemtype", "http://schema.org/Comment");
comment.appendChild(avatar);
comment.appendChild(header);
comment.appendChild(timestamp);
comment.appendChild(main);
let attachments = status.media_attachments;
if(
attachments &&
Array.isArray(attachments) &&
attachments.length > 0
) {
attachments.forEach((attachment) => {
if( SUPPORTED_MEDIA.includes(attachment.type) ){
let media = document.createElement("a");
media.className = "card";
media.setAttribute("href", attachment.url);
media.setAttribute("rel", "external nofollow");
let mediaElement;
switch(attachment.type){
case "image":
mediaElement = document.createElement("img");
mediaElement.setAttribute("src", attachment.preview_url);
mediaElement.setAttribute("loading", "lazy");
mediaElement.className = "media hover";
if(attachment.description != null) {
mediaElement.setAttribute("alt", attachment.description);
mediaElement.setAttribute("title", attachment.description);
}
media.appendChild(mediaElement);
break;
case "gifv":
mediaElement = document.createElement("video");
mediaElement.setAttribute("src", attachment.url);
mediaElement.setAttribute("autoplay", "");
mediaElement.setAttribute("playsinline", "");
mediaElement.setAttribute("loop", "");
mediaElement.className = "media hover";
if(attachment.description != null) {
mediaElement.setAttribute("aria-title", attachment.description);
mediaElement.setAttribute("title", attachment.description);
}
media.appendChild(mediaElement);
break;
}
comment.appendChild(media);
}
});
} else if(
status.card != null &&
status.card.image != null &&
!status.card.url.startsWith("{{ site.url }}")
) {
let cardImg = document.createElement("img");
cardImg.setAttribute("src", status.card.image);
cardImg.setAttribute("loading", "lazy");
let cardTitle = document.createElement("h5");
cardTitle.innerHTML = status.card.title;
let cardDescription = document.createElement("p");
cardDescription.innerHTML = status.card.description;
let cardCaption = document.createElement("figcaption");
cardCaption.appendChild(cardTitle);
cardCaption.appendChild(cardDescription);
let cardFigure = document.createElement("figure");
cardFigure.appendChild(cardImg);
cardFigure.appendChild(cardCaption);
let card = document.createElement("a");
card.className = "card";
card.setAttribute("href", status.card.url);
card.setAttribute("rel", "external nofollow");
card.appendChild(cardFigure);
comment.appendChild(card);
}
comment.appendChild(interactions);
if(status.account.acct == USERNAME) {
comment.classList.add("op");
avatar.classList.add("op");
avatar.setAttribute(
"title",
"Blog post author; " + avatar.getAttribute("title")
);
instanceBadge.classList.add("op");
instanceBadge.setAttribute(
"title",
"Blog post author: " + instanceBadge.getAttribute("title")
);
} else if( VERIFIED.includes(status.account.acct) ) {
comment.classList.add("verified");
avatar.classList.add("verified");
avatar.setAttribute(
"title",
avatar.getAttribute("title") + " (verified by site owner)"
);
instanceBadge.classList.add("verified");
instanceBadge.setAttribute(
"title",
instanceBadge.getAttribute("title") + " (verified by site owner)"
);
}
commentsWrapper.innerHTML += comment.outerHTML;
});
}
});
});
}
function emojify(input, emojis) {
let output = input;
emojis.forEach(emoji => {
let picture = document.createElement("picture");
let source = document.createElement("source");
source.setAttribute("srcset", escapeHtml(emoji.url));
source.setAttribute("media", "(prefers-reduced-motion: no-preference)");
let img = document.createElement("img");
img.className = "emoji";
img.setAttribute("src", escapeHtml(emoji.static_url));
img.setAttribute("alt", `:${ emoji.shortcode }:`);
img.setAttribute("title", `:${ emoji.shortcode }:`);
img.setAttribute("width", "20");
img.setAttribute("height", "20");
img.setAttribute("loading", "lazy");
picture.appendChild(source);
picture.appendChild(img);
output = output.replace(`:${ emoji.shortcode }:`, picture.outerHTML);
});
return output;
}
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/'/g, "&apos;")
.replace(/"/g, "&quot;")
;
}
</script>
<script>
const commentsSection = document.getElementById("comments");
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
loadComments();
observer.disconnect();
}
});
});
observer.observe(commentsSection);
</script>
</section>

11
_includes/footer.html Normal file
View File

@ -0,0 +1,11 @@
<footer class="site-footer">
<p title="Last built at {{ site.time }} ">&copy; {{ site.title }}, 2023</p>
<p><a href="{{ site.sourceurl }}">Website source</a></p>
<small>
<p>
Powered by <a href="https://jekyllrb.com">Jekyll</a> and <a href="https://codeberg.org/daudix-UFO/duckquill-source">Duckquill</a>
</p>
</small>
</footer>

25
_includes/head.html Normal file
View File

@ -0,0 +1,25 @@
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="{{ site.primary-color }}"><!-- primary color -->
<title>{% if page.title %}{{ page.title }}{% else %}{{ site.title }}{% endif %}</title>
<link rel="canonical" href="{{ page.url | replace:'index.html','' | prepend: site.baseurl | prepend: site.url }}" />
<link rel="alternate" type="application/rss+xml" title="{{ site.title }}" href="{{ "/feed.xml" | prepend: site.baseurl | prepend: site.url }}" />
<link rel="stylesheet" href="{{ "/assets/css/style.css" | prepend: site.baseurl }}" />
<link rel="icon" type="image/gif" href="{{ "/favicon.png" | prepend: site.baseurl }}" />
<link rel="apple-touch-icon" sizes="180x180" href="{{ "/apple-touch-icon.png" | prepend: site.baseurl }}" />
<!-- Open Graph -->
<meta property="og:title" content="{{ site.title }}" />
<meta property="og:url" content="{{ site.url }}" />
<meta property="og:description" content="{{ site.description }}" />
<meta property="og:image" content="{{ "/assets/card.png" | prepend: site.baseurl | prepend: site.url }}" />
<meta property="og:image:width" content="600" />
<meta property="og:image:height" content="400" />
<meta property="og:image:alt" content="A card with Duckquill written on it" />
</head>

19
_includes/navigation.html Normal file
View File

@ -0,0 +1,19 @@
<nav class="nav">
<div class="nav-container">
<a href="{{ site.baseurl }}/">
<h2 class="nav-title">{{ site.title }}</h2>
</a>
<ul>
<li><a href="{{ '/' | prepend: relative_url }}">Home</a></li>
<li><a href="{{ '/posts' | prepend: site.baseurl }}">Posts</a></li>
<li><a href="{{ '/tags' | prepend: site.baseurl }}">Tags</a></li>
<li><a href="{{ '/feed.xml' | prepend: site.baseurl }}">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
d="M1.988 1.988V3c.008.547.453.984 1 .988.004-.004.008-.004.012-.004v.028A8.977 8.977 0 0 1 11.988 13a.991.991 0 0 0 1 .984h1V13h-.004c0-.004 0-.004.004-.008C13.984 7.02 9.184 2.148 3.242 2.02A1.004 1.004 0 0 0 3 1.988v-.004zm0 4V7c.008.547.453.984 1 .988.004-.004.008-.004.012-.004V8a4.985 4.985 0 0 1 4.996 4.844 1.002 1.002 0 0 0 .988 1.145c.008-.005.012-.005.016-.005v.004h.984V13H10c0-3.793-3.047-6.898-6.82-6.992 0-.004-.004-.004-.004-.004A.892.892 0 0 0 3 5.988v-.004zm2 4a1.999 1.999 0 1 0-.002 3.998 1.999 1.999 0 0 0 .002-3.998zm0 0" />
</svg>
Feed
</a></li>
</ul>
</div>
</nav>

10
_layouts/compress.html Normal file
View File

@ -0,0 +1,10 @@
---
# Jekyll layout that compresses HTML
# v3.1.0
# http://jch.penibelst.de/
# © 20142015 Anatol Broder
# MIT License
---
{% capture _LINE_FEED %}
{% endcapture %}{% if site.compress_html.ignore.envs contains jekyll.environment or site.compress_html.ignore.envs == "all" %}{{ content }}{% else %}{% capture _content %}{{ content }}{% endcapture %}{% assign _profile = site.compress_html.profile %}{% if site.compress_html.endings == "all" %}{% assign _endings = "html head body li dt dd optgroup option colgroup caption thead tbody tfoot tr td th" | split: " " %}{% else %}{% assign _endings = site.compress_html.endings %}{% endif %}{% for _element in _endings %}{% capture _end %}</{{ _element }}>{% endcapture %}{% assign _content = _content | remove: _end %}{% endfor %}{% if _profile and _endings %}{% assign _profile_endings = _content | size | plus: 1 %}{% endif %}{% for _element in site.compress_html.startings %}{% capture _start %}<{{ _element }}>{% endcapture %}{% assign _content = _content | remove: _start %}{% endfor %}{% if _profile and site.compress_html.startings %}{% assign _profile_startings = _content | size | plus: 1 %}{% endif %}{% if site.compress_html.comments == "all" %}{% assign _comments = "<!-- -->" | split: " " %}{% else %}{% assign _comments = site.compress_html.comments %}{% endif %}{% if _comments.size == 2 %}{% capture _comment_befores %}.{{ _content }}{% endcapture %}{% assign _comment_befores = _comment_befores | split: _comments.first %}{% for _comment_before in _comment_befores %}{% if forloop.first %}{% continue %}{% endif %}{% capture _comment_outside %}{% if _carry %}{{ _comments.first }}{% endif %}{{ _comment_before }}{% endcapture %}{% capture _comment %}{% unless _carry %}{{ _comments.first }}{% endunless %}{{ _comment_outside | split: _comments.last | first }}{% if _comment_outside contains _comments.last %}{{ _comments.last }}{% assign _carry = false %}{% else %}{% assign _carry = true %}{% endif %}{% endcapture %}{% assign _content = _content | remove_first: _comment %}{% endfor %}{% if _profile %}{% assign _profile_comments = _content | size | plus: 1 %}{% endif %}{% endif %}{% assign _pre_befores = _content | split: "<pre" %}{% assign _content = "" %}{% for _pre_before in _pre_befores %}{% assign _pres = _pre_before | split: "</pre>" %}{% assign _pres_after = "" %}{% if _pres.size != 0 %}{% if site.compress_html.blanklines %}{% assign _lines = _pres.last | split: _LINE_FEED %}{% capture _pres_after %}{% for _line in _lines %}{% assign _trimmed = _line | split: " " | join: " " %}{% if _trimmed != empty or forloop.last %}{% unless forloop.first %}{{ _LINE_FEED }}{% endunless %}{{ _line }}{% endif %}{% endfor %}{% endcapture %}{% else %}{% assign _pres_after = _pres.last | split: " " | join: " " %}{% endif %}{% endif %}{% capture _content %}{{ _content }}{% if _pre_before contains "</pre>" %}<pre{{ _pres.first }}</pre>{% endif %}{% unless _pre_before contains "</pre>" and _pres.size == 1 %}{{ _pres_after }}{% endunless %}{% endcapture %}{% endfor %}{% if _profile %}{% assign _profile_collapse = _content | size | plus: 1 %}{% endif %}{% if site.compress_html.clippings == "all" %}{% assign _clippings = "html head title base link meta style body article section nav aside h1 h2 h3 h4 h5 h6 hgroup header footer address p hr blockquote ol ul li dl dt dd figure figcaption main div table caption colgroup col tbody thead tfoot tr td th" | split: " " %}{% else %}{% assign _clippings = site.compress_html.clippings %}{% endif %}{% for _element in _clippings %}{% assign _edges = " <e;<e; </e>;</e>;</e> ;</e>" | replace: "e", _element | split: ";" %}{% assign _content = _content | replace: _edges[0], _edges[1] | replace: _edges[2], _edges[3] | replace: _edges[4], _edges[5] %}{% endfor %}{% if _profile and _clippings %}{% assign _profile_clippings = _content | size | plus: 1 %}{% endif %}{{ _content }}{% if _profile %} <table id="compress_html_profile_{{ site.time | date: "%Y%m%d" }}" class="compress_html_profile"> <thead> <tr> <td>Step <td>Bytes <tbody> <tr> <td>raw <td>{{ content | size }}{% if _profile_endings %} <tr> <td>endings <td>{{ _profile_endings }}{% endif %}{% if _profile_startings %} <tr> <td>startings <td>{{ _profile_startings }}{% endif %}{% if _profile_comments %} <tr> <td>comments <td>{{ _profile_comments }}{% endif %}{% if _profile_collapse %} <tr> <td>collapse <td>{{ _profile_collapse }}{% endif %}{% if _profile_clippings %} <tr> <td>clippings <td>{{ _profile_clippings }}{% endif %} </table>{% endif %}{% endif %}

22
_layouts/default.html Normal file
View File

@ -0,0 +1,22 @@
---
layout: compress
---
<!DOCTYPE html>
<html>
{% include head.html %}
<body>
{% include navigation.html %}
<div class="container">
{{ content }}
</div>
{% include footer.html %}
</body>
</html>

68
_layouts/post.html Normal file
View File

@ -0,0 +1,68 @@
---
layout: default
---
<h1>{{ page.title }}</h1>
<small>
<time datetime="{{ page.date | date: "%Y-%m-%d" }}">{{ page.date | date_to_long_string }}</time>
{% if page.tags %}
{% if page.tags.size > 0 %}
• {{ page.tags | join: ', ' }}
{% endif %}
{% endif %}
</small>
{% if page.archive %}
<div class="highlighter-rouge statement-container archive">
<h2>⚠ Archived</h2>
{{ page.archive | markdownify }}
</div>
{% endif %}
{% if page.trigger %}
<div class="highlighter-rouge statement-container trigger">
<h2>⚠ Trigger Warning</h2>
{{ page.trigger | markdownify }}
</div>
{% endif %}
{% if page.disclaimer %}
<div class="highlighter-rouge statement-container disclaimer">
<h2>⚠ Disclaimer(s)</h2>
{{ page.disclaimer | markdownify }}
</div>
{% endif %}
{% if page.toc %}
<h2>Table of Contents</h2>
{{ content | toc }}
{% else %}
{{ content }}
{% endif %}
{%- if page.comments -%}
{%- if page.comments.id -%}
{%- include comments.html -%}
<hr>
{%- endif -%}
{%- endif -%}
{% if page.next %}
<h2>Read Next</h2>
<a href="{{ site.baseurl }}{{ page.next.url }}" class="page-link">
{{ page.next.title }}
</a>
{% endif %}
{% if page.previous %}
<h2>Read Previous</h2>
<a href="{{ site.baseurl }}{{ page.previous.url }}" class="page-link">
{{ page.previous.title }}
</a>
{% endif %}
<p class="dialog-buttons">
<a href="#top" class="inline-button">Go to top</a>
<a href="{{ site.issuesurl }}">File an issue</a>
</p>

25
_layouts/posts.html Normal file
View File

@ -0,0 +1,25 @@
---
layout: default
---
{{ content }}
<h1>{{ page.title }}</h1>
{{ page.description }}
{% for post in site.posts %}
<article>
<h2>
<a href="{{ site.baseurl }}{{ post.url }}" class="page-link">
{{ post.title }}
</a>
</h2>
<small>
<time datetime="{{ post.date | date: "%Y-%m-%d" }}">{{ post.date | date_to_long_string }}</time>
{% if post.tags %}
{% if post.tags.size > 0 %}
• {{ post.tags | join: ', ' }}
{% endif %}
{% endif %}
</small>
</article>
{% endfor %}

16
_layouts/tags.html Normal file
View File

@ -0,0 +1,16 @@
---
layout: default
---
{{ content }}
<h1>{{ page.title }}</h1>
{{ page.description }}
{% for tag in site.tags %}
<h3>{{ tag[0] }}</h3>
<ul>
{% for post in tag[1] %}
<li><a href="{{ site.baseurl }}{{ post.url }}" class="page-link">{{ post.title }}</a></li>
{% endfor %}
</ul>
{% endfor %}

View File

@ -0,0 +1,48 @@
---
layout: post
title: "The Quill of Duck"
tags: Demo Test
toc: true
comments:
id:
---
![Quill](../assets/posts/2023-08-31/quill.png){:.full.media.hover}
## The what?
This is a Duckquill post example, this post has nothing but a bunch of text and random formattings, acting like a demo.
## The Stanley!
This is the story of a man named _Stanley_.
_Stanley_ worked for a company in a big building where he was Employee `#427`.
![The Office](../assets/posts/2023-08-31/The_Office.webp){:.full.media.hover}
Employee `#427`'s job was simple: he sat at his desk in Room `427` and he pushed buttons on a keyboard.
Orders came to him through a monitor on his desk telling him what buttons to push, how long to push them, and in what order.
This is what Employee `#427` did every day of every month of every year, and although others may have considered it soul rending,
_Stanley_ relished every moment that the orders came in, as though he had been made exactly for this job.
And _Stanley_ was happy.
And then one day, something very peculiar happened.
Something that would forever change _Stanley_;
Something he would never quite forget.
He had been at his desk for nearly an hour when he had realized not one single order had arrived on the monitor for him to follow.
No one had shown up to give him instructions, call a meeting, or even say 'hi'. Never in all his years at the company had this happened, this complete isolation.
Something was very clearly wrong. Shocked, frozen solid, _Stanley_ found himself unable to move for the longest time.
But as he came to his wits and regained his senses, he got up from his desk and stepped out of his office.
All of his co-workers were gone. What could it mean? Stanley decided to go to the meeting room; perhaps he had simply missed a memo.

248
_sass/comments.scss Normal file
View File

@ -0,0 +1,248 @@
/* Comments */
section#comments {
.comment {
display: grid;
column-gap: 1rem;
grid-template-areas:
"avatar name"
"avatar time"
"avatar post"
"...... card"
"...... interactions";
grid-template-columns: min-content;
justify-items: start;
margin: 2rem auto 2rem -1rem;
padding: 1rem;
.avatar-link {
grid-area: avatar;
height: 4rem;
position: relative;
width: 4rem;
.avatar {
margin: unset;
background-color: var(--bg2);
border-radius: var(--border-radius);
box-shadow: var(--shadow);
height: 100%;
width: 100%;
}
&.op::after {
background-color: var(--accent-color);
border-radius: 50%;
bottom: -0.25rem;
color: var(--dark4);
content: "";
display: block;
font-size: 1.25rem;
font-weight: bold;
height: 1.5rem;
line-height: 1.5rem;
position: absolute;
right: -0.25rem;
text-align: center;
width: 1.5rem;
}
}
.author {
align-items: center;
cursor: default;
display: flex;
font-weight: bold;
gap: 0.5rem;
grid-area: name;
.instance {
background-color: var(--fg05);
border-radius: 9999px;
color: var(--text);
font-size: smaller;
font-weight: normal;
padding: 0.25rem 0.75rem;
&:hover {
opacity: 0.8;
text-decoration: none;
}
&.op {
background-color: var(--accent-color);
color: var(--dark4);
&::before {
content: "";
font-weight: bold;
margin-inline-end: 0.25rem;
margin-inline-start: -0.25rem;
}
}
}
}
time {
@extend small;
font-size: smaller;
opacity: 0.9;
grid-area: time;
line-height: 1.5rem;
&.edited::after {
content: " *";
}
}
main {
grid-area: post;
justify-self: stretch;
p:first-child {
margin-top: 0.25rem;
}
p:last-child {
margin-bottom: 0;
}
}
.card {
color: inherit;
grid-area: card;
max-width: 400px;
&:hover {
text-decoration: none;
}
figure {
border-radius: var(--border-radius);
background-color: var(--bg2);
box-shadow: var(--shadow);
margin-left: 0;
margin-right: 0;
overflow: hidden;
transition: var(--transition);
img {
margin: unset;
}
&:hover {
transform: translateY(-0.5rem);
}
}
figcaption {
display: grid;
gap: 0.5rem;
margin: 0;
padding: 1rem;
text-align: left;
* {
display: inline-block;
line-height: 1.25;
margin: 0;
overflow: hidden;
padding: 0;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
// Hide the card from the shared post
&:first-of-type .card {
display: none;
}
footer {
@extend small;
display: flex;
gap: 0.4rem;
grid-area: interactions;
margin-top: 0.925rem;
.boosts {
cursor: default;
font-weight: 600;
font-variation-settings: "wght" 600; /* needed for webkit */
font-size: 90%;
padding: 0.4rem 1rem;
border-radius: var(--border-radius);
background-color: var(--orange-bg);
color: var(--orange-fg);
&::before {
color: var(--orange2);
content: "🔁";
margin-inline-end: 0.25rem;
}
}
.faves {
cursor: default;
font-weight: 600;
font-variation-settings: "wght" 600; /* needed for webkit */
font-size: 90%;
padding: 0.4rem 1rem;
border-radius: var(--border-radius);
background-color: var(--red-bg);
color: var(--red-fg);
&::before {
color: var(--red2);
content: "❤️";
margin-inline-end: 0.25rem;
}
}
}
.emoji {
margin: unset;
display: inline;
height: 1.25rem;
vertical-align: middle;
width: 1.25rem;
}
.invisible {
display: none;
}
.ellipsis::after {
content: "";
}
details {
summary {
background-image: linear-gradient(
90deg,
transparent,
transparent 0.4rem,
var(--bg2) 0.4rem,
var(--bg2) calc(100% - 0.4rem),
transparent calc(100% - 0.4rem),
transparent
),
repeating-linear-gradient(
45deg,
var(--bg1),
var(--bg1) 0.3rem,
var(--accent-color) 0.3rem,
var(--accent-color) 0.6rem
);
border-radius: var(--border-radius-small);
color: inherit;
cursor: pointer;
box-shadow: var(--shadow);
margin-top: 0.925rem;
padding: 1rem;
}
}
}
}

8
_sass/fonts.scss Normal file
View File

@ -0,0 +1,8 @@
/* Typography */
@font-face {
font-family: "InterVar";
font-weight: 100 900;
font-display: swap;
font-style: oblique italic 0deg 10deg;
src: url("../fonts/Inter.var.woff2?v=4.0") format("woff2");
}

478
_sass/main.scss Normal file
View File

@ -0,0 +1,478 @@
* {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
html,
body {
margin: 0;
padding: 0;
scroll-behavior: smooth;
scrollbar-color: var(--fg50) transparent;
}
body {
font-size: 16px;
font-family: "InterVar", sans-serif;
font-weight: 400;
line-height: 1.6;
color: var(--text);
background-color: var(--background);
/* ⇩⇩ put footer at the bottom for short pages, such as the 404 ⇩⇩ */
display: grid;
min-height: 100vh;
grid-template-rows: auto minmax(auto, 1fr) auto; /* header, stuff, footer */
}
@media only screen and (max-device-width: 480px) {
body {
font-size: 14px;
}
}
@media (prefers-color-scheme: dark) {
html {
background-color: var(--dark5);
}
}
/* Layout */
.container {
width: 80%;
margin-left: auto;
margin-right: auto;
max-width: var(--content-width);
}
@media only screen and (max-device-width: 480px) {
/*mobile*/
.container {
width: 90%;
}
}
:target {
scroll-margin-top: 25vh;
animation: glow-in-out var(--transition-long);
animation-delay: 1s;
}
@keyframes glow-in-out {
0% {
text-shadow: none;
}
50% {
text-shadow: var(--glow);
}
100% {
text-shadow: none;
}
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 3rem 0 1rem;
font-weight: 600;
line-height: 1.25;
font-variation-settings: "wght" 600; /* needed for webkit */
}
h1 {
font-size: 1.5rem;
}
@media screen and (min-width: 640px) {
h1 {
font-size: 1.6rem;
}
}
h2 {
font-size: 1.2rem;
}
a {
font-weight: 600;
text-decoration: none;
color: var(--accent-color);
cursor: pointer;
font-variation-settings: "wght" 600; /* needed for webkit */
}
a:hover {
text-decoration: underline;
}
b {
font-weight: 600;
}
small {
color: var(--fg50);
}
dl {
padding: 0;
}
dl dt {
padding: 0;
margin-top: 1rem;
font-size: 1rem;
font-weight: bold;
}
dl dd {
padding: 0;
margin-bottom: 1rem;
}
hr {
margin: 3rem auto 4rem;
width: 40%;
opacity: 40%;
}
blockquote {
padding: 0 1rem;
margin-left: 0;
color: var(--fg40);
border-left: 0.3rem solid var(--fg07);
}
blockquote > :first-child {
margin-top: 0;
}
blockquote > :last-child {
margin-bottom: 0;
}
abbr {
cursor: help;
}
kbd {
background-color: var(--fg05);
border: 1px solid var(--fg07);
border-radius: 4px;
box-shadow: inset 0 -1px 0 var(--fg09);
color: var(--text);
display: inline-block;
font-size: 11px;
line-height: 10px;
padding: 3px 5px;
vertical-align: middle;
cursor: pointer;
user-select: none;
-webkit-user-select: none;
}
kbd:active {
box-shadow: inset 0 0px 0 var(--fg09);
vertical-align: bottom;
filter: contrast(0.2);
}
/* Tables */
table {
border-collapse: collapse;
border-spacing: 0;
}
table {
display: block;
width: 100%;
overflow: auto;
word-break: normal;
word-break: keep-all;
}
table th {
font-weight: bold;
}
table th,
table td {
padding: 0.5rem 1rem;
border: 1px solid var(--fg05);
}
td,
th {
padding: 0;
}
/* Make tables vertically aligned to the top */
tbody td {
vertical-align: top;
}
/* Media */
img {
display: block;
margin: 2rem auto;
max-width: 100%;
}
img.full {
width: 100%;
}
img.pixels {
image-rendering: crisp-edges; /* older firefox browsers */
image-rendering: pixelated;
}
video {
display: block;
margin: 2rem auto;
max-width: 100%;
}
.media {
border-radius: var(--border-radius-small);
box-shadow: var(--shadow);
}
.media.hover {
transition: var(--transition-longer);
}
.media.hover:hover {
transform: scale(125%);
border-radius: unset;
box-shadow: var(--shadow-raised);
}
@media only screen and (max-device-width: 480px) {
/*mobile*/
.media.hover:hover {
transform: scale(110%);
}
}
/* Navbar */
.nav-container {
display: block;
width: 80%;
margin-left: auto;
margin-right: auto;
max-width: var(--content-width);
}
.nav {
position: sticky;
top: 0;
z-index: 1;
background-color: var(--nav-bg);
backdrop-filter: blur(24px) saturate(180%);
-webkit-backdrop-filter: blur(24px) saturate(180%);
border-bottom: 1px solid var(--fg07);
box-shadow: var(--shadow);
overflow: auto;
}
.nav-container {
margin: 0.5rem auto;
position: relative;
text-align: center;
}
.nav-title {
color: var(--fg50);
display: inline-block;
margin: 0;
}
.nav-title:hover {
text-decoration: underline;
}
.nav ul {
list-style-type: none;
margin: 1rem 0 0;
padding: 0;
text-align: center;
}
.nav li {
color: var(--fg50);
display: inline-block;
}
.nav a {
display: inline-block;
font-weight: 900;
font-size: 90%;
padding: 0.4rem 1rem;
border-radius: var(--border-radius);
background-color: transparent;
color: var(--fg50);
/* transition: var(--transition); */
}
.nav a:hover {
background-color: var(--fg05);
/* box-shadow: var(--glow); */
}
.nav svg {
fill: var(--fg50);
height: 1rem;
width: 1rem;
vertical-align: middle;
transform: translateY(-0.125rem);
}
@media (min-width: 640px) {
.nav-container {
text-align: left;
}
.nav ul {
bottom: 0;
position: absolute;
right: 0;
}
}
/* Footer */
.site-footer {
text-align: center;
padding: 3rem 0 3rem;
font-size: 1rem;
margin-top: 4rem;
}
/* Link arrows */
.page-link::after {
content: "";
}
.site-link::after {
content: "";
}
/* Buttons */
.dialog-buttons {
display: flex;
flex-direction: row;
align-items: baseline;
justify-content: space-between;
margin-top: 6rem;
}
.inline-button {
display: inline-block;
font-weight: 900;
font-size: 90%;
padding: 0.4rem 1rem;
border-radius: var(--border-radius);
background-color: var(--fg05);
color: var(--text);
}
/* ASCII */
.ascii {
line-height: normal;
margin: 3rem 0 1rem;
padding: 2px 1rem;
max-width: 80vw;
overflow-x: auto;
transition: var(--transition-long);
background: linear-gradient(to top, var(--text) 0%, transparent 100%);
background-clip: text;
-webkit-background-clip: text;
-moz-background-clip: text;
-webkit-text-fill-color: transparent;
-moz-text-fill-color: transparent;
}
.ascii:hover {
-webkit-text-fill-color: var(--text);
-moz-text-fill-color: var(--text);
text-shadow: var(--glow);
}
@media only screen and (max-device-width: 480px) {
/*mobile*/
.ascii {
max-width: 90vw;
}
}
@media only screen and (max-device-width: 640px) {
/*mobile*/
.ascii {
display: none;
}
}
@media (prefers-color-scheme: dark) {
.highlight {
filter: contrast(0.4) saturate(2);
}
}
/* Code Blocks */
.highlighter-rouge {
line-height: normal;
margin: 1rem 0 1rem;
padding: 2px 1rem;
border-radius: var(--border-radius-small);
background-color: var(--bg2);
max-width: 80vw;
overflow-x: auto;
box-shadow: var(--shadow);
}
@media only screen and (max-device-width: 480px) {
/*mobile*/
.highlighter-rouge {
max-width: 90vw;
}
}
.highlighter-rouge * {
background-color: transparent;
}
/* Inline Code */
code.highlighter-rouge {
padding: 2px 6px;
background-color: var(--fg07);
color: var(--red-fg);
box-shadow: none;
}
/* Statements */
.statement-container {
margin: 1rem 0 1rem;
line-height: normal;
}
.statement-container h2 {
margin: inherit;
}
.archive {
background-color: var(--purple-bg);
color: var(--purple-fg);
}
.disclaimer {
background-color: var(--red-bg);
color: var(--red-fg);
}
.trigger {
background-color: var(--yellow-bg);
color: var(--yellow-fg);
}

217
_sass/rouge-github.scss Normal file
View File

@ -0,0 +1,217 @@
.highlight table td {
padding: 5px;
}
.highlight table pre {
margin: 0;
}
.highlight .cm {
color: #999988;
font-style: italic;
}
.highlight .cp {
color: #999999;
font-weight: bold;
}
.highlight .c1 {
color: #999988;
font-style: italic;
}
.highlight .cs {
color: #999999;
font-weight: bold;
font-style: italic;
}
.highlight .c,
.highlight .cd {
color: #999988;
font-style: italic;
}
.highlight .err {
color: #a61717;
background-color: #e3d2d2;
}
.highlight .gd {
color: #000000;
background-color: #ffdddd;
}
.highlight .ge {
color: #000000;
font-style: italic;
}
.highlight .gr {
color: #aa0000;
}
.highlight .gh {
color: #999999;
}
.highlight .gi {
color: #000000;
background-color: #ddffdd;
}
.highlight .go {
color: #888888;
}
.highlight .gp {
color: #555555;
}
.highlight .gs {
font-weight: bold;
}
.highlight .gu {
color: #aaaaaa;
}
.highlight .gt {
color: #aa0000;
}
.highlight .kc {
color: #000000;
font-weight: bold;
}
.highlight .kd {
color: #000000;
font-weight: bold;
}
.highlight .kn {
color: #000000;
font-weight: bold;
}
.highlight .kp {
color: #000000;
font-weight: bold;
}
.highlight .kr {
color: #000000;
font-weight: bold;
}
.highlight .kt {
color: #445588;
font-weight: bold;
}
.highlight .k,
.highlight .kv {
color: #000000;
font-weight: bold;
}
.highlight .mf {
color: #009999;
}
.highlight .mh {
color: #009999;
}
.highlight .il {
color: #009999;
}
.highlight .mi {
color: #009999;
}
.highlight .mo {
color: #009999;
}
.highlight .m,
.highlight .mb,
.highlight .mx {
color: #009999;
}
.highlight .sb {
color: #d14;
}
.highlight .sc {
color: #d14;
}
.highlight .sd {
color: #d14;
}
.highlight .s2 {
color: #d14;
}
.highlight .se {
color: #d14;
}
.highlight .sh {
color: #d14;
}
.highlight .si {
color: #d14;
}
.highlight .sx {
color: #d14;
}
.highlight .sr {
color: #009926;
}
.highlight .s1 {
color: #d14;
}
.highlight .ss {
color: #990073;
}
.highlight .s {
color: #d14;
}
.highlight .na {
color: #008080;
}
.highlight .bp {
color: #999999;
}
.highlight .nb {
color: #0086b3;
}
.highlight .nc {
color: #445588;
font-weight: bold;
}
.highlight .no {
color: #008080;
}
.highlight .nd {
color: #3c5d5d;
font-weight: bold;
}
.highlight .ni {
color: #800080;
}
.highlight .ne {
color: #990000;
font-weight: bold;
}
.highlight .nf {
color: #990000;
font-weight: bold;
}
.highlight .nl {
color: #990000;
font-weight: bold;
}
.highlight .nn {
color: #555555;
}
.highlight .nt {
color: #000080;
}
.highlight .vc {
color: #008080;
}
.highlight .vg {
color: #008080;
}
.highlight .vi {
color: #008080;
}
.highlight .nv {
color: #008080;
}
.highlight .ow {
color: #000000;
font-weight: bold;
}
.highlight .o {
color: #000000;
font-weight: bold;
}
.highlight .w {
color: #bbbbbb;
}
.highlight {
background-color: transparent;
}

124
_sass/variables.scss Normal file
View File

@ -0,0 +1,124 @@
:root {
/* GNOME Color Palette */
--blue1: rgb(153, 193, 241);
--blue2: rgb(98, 160, 234);
--blue3: rgb(53, 132, 228);
--blue4: rgb(28, 113, 216);
--blue5: rgb(26, 95, 180);
--green1: rgb(143, 240, 164);
--green2: rgb(87, 227, 137);
--green3: rgb(51, 209, 122);
--green4: rgb(46, 194, 126);
--green5: rgb(38, 162, 105);
--yellow1: rgb(249, 240, 107);
--yellow2: rgb(248, 228, 92);
--yellow3: rgb(246, 211, 45);
--yellow4: rgb(245, 194, 17);
--yellow5: rgb(229, 165, 10);
--orange1: rgb(255, 190, 111);
--orange2: rgb(255, 163, 72);
--orange3: rgb(255, 120, 0);
--orange4: rgb(230, 97, 0);
--orange5: rgb(198, 70, 0);
--red1: rgb(246, 97, 81);
--red2: rgb(237, 51, 59);
--red3: rgb(224, 27, 36);
--red4: rgb(192, 28, 40);
--red5: rgb(165, 29, 45);
--purple1: rgb(220, 138, 221);
--purple2: rgb(192, 97, 203);
--purple3: rgb(145, 65, 172);
--purple4: rgb(129, 61, 156);
--purple5: rgb(97, 53, 131);
--brown1: rgb(205, 171, 143);
--brown2: rgb(181, 131, 90);
--brown3: rgb(152, 106, 68);
--brown4: rgb(134, 94, 60);
--brown5: rgb(99, 69, 44);
--light1: rgb(255, 255, 255);
--light2: rgb(246, 245, 244);
--light3: rgb(222, 221, 218);
--light4: rgb(192, 191, 188);
--light5: rgb(154, 153, 150);
--dark1: rgb(119, 118, 123);
--dark2: rgb(94, 92, 100);
--dark3: rgb(61, 56, 70);
--dark4: rgb(36, 31, 49);
--dark5: rgb(0, 0, 0);
/* General Setup */
--border: var(--light3);
--border-radius: 0.75rem;
--border-radius-small: 0.5rem;
--accent-color: var(--orange2);
--secondary-accent-color: var(--purple4);
--text: var(--dark4);
--background: var(--bg1);
--content-width: 720px;
/* Custom Color Palette */
--bg1: rgb(250, 250, 250);
--bg2: rgb(255, 255, 255);
--bg3: rgb(75, 75, 75);
--fg01: rgba(0, 0, 0, 0.01);
--fg03: rgba(0, 0, 0, 0.03);
--fg05: rgba(0, 0, 0, 0.05);
--fg07: rgba(0, 0, 0, 0.07);
--fg09: rgba(0, 0, 0, 0.09);
--fg40: rgba(0, 0, 0, 0.4);
--fg50: rgba(0, 0, 0, 0.5);
--nav-bg: rgba(255, 255, 255, 0.5);
--purple-bg: rgba(145, 65, 172, 0.1);
--purple-fg: rgb(145, 65, 172);
--red-bg: rgba(224, 27, 36, 0.1);
--red-fg: rgb(224, 27, 36);
--yellow-bg: rgba(156, 110, 3, 0.1);
--yellow-fg: rgb(156, 110, 3);
--orange-bg: rgba(255, 120, 0, 0.1);
--orange-fg: rgb(255, 120, 0);
/* Custom Variables */
--shadow: 0 0 0 1px rgba(0, 0, 0, 0.03), 0 1px 3px 1px rgba(0, 0, 0, 0.07),
0 2px 6px 2px rgba(0, 0, 0, 0.03);
--shadow-raised: 0 0 0 1px rgba(0, 0, 0, 0.03),
0 2px 6px 2px rgba(0, 0, 0, 0.09), 0 4px 12px 4px rgba(0, 0, 0, 0.06);
--glow: var(--accent-color) -6px 0 12px,
var(--secondary-accent-color) 6px 0 12px;
--transition: 200ms;
--transition-longer: 400ms;
--transition-long: 800ms;
}
@media (prefers-color-scheme: dark) {
:root {
--text: var(--light2);
--background: var(--bg3);
--fg01: rgba(255, 255, 255, 0.01);
--fg03: rgba(255, 255, 255, 0.03);
--fg05: rgba(255, 255, 255, 0.05);
--fg07: rgba(255, 255, 255, 0.07);
--fg09: rgba(255, 255, 255, 0.09);
--fg40: rgba(255, 255, 255, 0.4);
--fg50: rgba(255, 255, 255, 0.5);
--bg1: rgb(36, 36, 36);
--bg2: rgb(30, 30, 30);
--bg3: rgb(11, 11, 11);
--nav-bg: rgba(0, 0, 0, 0.5);
--purple-bg: rgba(220, 138, 221, 0.1);
--purple-fg: rgb(220, 138, 221);
--red-bg: rgba(226, 97, 81, 0.1);
--red-fg: rgb(246, 97, 81);
--yellow-bg: rgba(248, 228, 92, 0.1);
--yellow-fg: rgb(248, 228, 92);
--orange-bg: rgba(255, 190, 111, 0.1);
--orange-fg: rgb(255, 190, 111);
}
}

BIN
apple-touch-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

116
apple-touch-icon.svg Normal file
View File

@ -0,0 +1,116 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="180"
height="180"
viewBox="0 0 180 180.00001"
version="1.1"
id="svg1"
xml:space="preserve"
inkscape:version="1.3 (0e150ed6c4, 2023-07-21)"
sodipodi:docname="apple-touch-icon.svg"
inkscape:export-filename="apple-touch-icon.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="false"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="true"
inkscape:deskcolor="#1f1f1f"
inkscape:document-units="px"
showgrid="false"
inkscape:zoom="2.7222222"
inkscape:cx="90"
inkscape:cy="90"
inkscape:window-width="1280"
inkscape:window-height="731"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1"><inkscape:grid
id="grid2"
units="px"
originx="0"
originy="0"
spacingx="1"
spacingy="1.0000001"
empcolor="#0099e5"
empopacity="0.30196078"
color="#0099e5"
opacity="0.14901961"
empspacing="5"
dotted="false"
gridanglex="30"
gridanglez="30"
visible="false" /></sodipodi:namedview><defs
id="defs1"><linearGradient
id="linearGradient64"
inkscape:collect="always"><stop
style="stop-color:#deddda;stop-opacity:1;"
offset="0"
id="stop65" /><stop
style="stop-color:#c0bfbc;stop-opacity:1;"
offset="1"
id="stop64" /></linearGradient><linearGradient
id="linearGradient1"
inkscape:collect="always"><stop
style="stop-color:#ffa348;stop-opacity:1;"
offset="0"
id="stop1" /><stop
style="stop-color:#813d9c;stop-opacity:1;"
offset="1"
id="stop2" /></linearGradient><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1"
id="linearGradient3"
gradientUnits="userSpaceOnUse"
x1="26.36039"
y1="26.36039"
x2="153.6396"
y2="153.6396"
gradientTransform="matrix(0.77777778,0,0,0.77777778,20,20)" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient64"
id="linearGradient65"
x1="74"
y1="70.000006"
x2="106"
y2="70.000006"
gradientUnits="userSpaceOnUse" /></defs><g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"><circle
cx="90"
cy="90"
r="90"
id="path1"
style="fill:#ffffff" /><circle
cx="90"
cy="90"
r="70"
id="circle2"
style="fill:url(#linearGradient3);stroke-width:0.777778" /><path
id="path61"
style="color:#000000;fill:#000000;fill-opacity:0.2;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none"
d="m 115.54492,40.87109 a 16,16 0 0 0 -4.71484,0.80079 16,16 0 0 0 -0.36524,0.0977 l 0.006,0.0195 a 16,16 0 0 0 -4.92773,2.67578 16,16 0 0 0 -0.17969,0.12696 l 0.008,0.0293 a 16,16 0 0 0 -2.92578,3.20899 l -0.002,-0.01 a 16,16 0 0 0 -0.7539,1.05078 l -0.70703,1.22461 -2.58594,4.47852 -1.41406,2.44922 -2.585943,4.47851 -1.414062,2.44922 -2.585938,4.48047 -1.414062,2.44922 -2.585938,4.47852 -1.414062,2.44921 -2.585938,4.47852 -1.414062,2.44922 -2.585938,4.47851 -1.414062,2.44922 -2.585938,4.48047 -1.414062,2.44922 -1.292969,2.23828 a 16,16 0 0 0 -1.173828,2.68945 l -0.01758,-0.0645 a 16,16 0 0 0 -0.07031,0.26367 16,16 0 0 0 -0.341796,1.29102 16,16 0 0 0 -0.259766,1.37305 16,16 0 0 0 3.330078,12.42773 16,16 0 0 0 0.90625,1.05273 16,16 0 0 0 0.953125,0.95899 16,16 0 0 0 0.1875,0.1875 l -0.01758,-0.0625 a 16,16 0 0 0 0.738281,0.54492 L 63.8125,142.47461 a 2,2 0 0 0 0.732422,2.73047 2,2 0 0 0 2.732422,-0.73047 l 12.113281,-20.98047 a 16,16 0 0 0 0.839844,0.36914 l -0.06055,0.0156 a 16,16 0 0 0 0.251953,0.0664 16,16 0 0 0 1.322266,0.35157 16,16 0 0 0 1.33789,0.25195 16,16 0 0 0 12.44336,-3.32813 16,16 0 0 0 1.056642,-0.91015 16,16 0 0 0 0.94922,-0.94336 16,16 0 0 0 0.19336,-0.19141 l -0.0644,0.0176 a 16,16 0 0 0 1.74218,-2.36133 l 1.29297,-2.23828 1.41407,-2.44922 2.58593,-4.48047 1.41407,-2.44922 2.58593,-4.47851 1.41407,-2.44922 2.58593,-4.47852 1.41407,-2.44921 2.58593,-4.47852 1.41407,-2.44922 2.58593,-4.48047 1.41407,-2.44922 2.58593,-4.47851 1.41407,-2.44922 2.58593,-4.47852 0.70703,-1.22461 a 16,16 0 0 0 0.61914,-1.19921 16,16 0 0 0 0.002,-0.002 16,16 0 0 0 1.29101,-4.13281 l 0.006,-0.002 a 16,16 0 0 0 0.006,-0.0664 16,16 0 0 0 0.19531,-1.95508 16,16 0 0 0 0.01,-0.10547 l -0.006,0.002 a 16,16 0 0 0 -0.30664,-3.70313 l 0.006,-0.002 a 16,16 0 0 0 -0.0176,-0.0684 16,16 0 0 0 -0.47851,-1.78125 16,16 0 0 0 -0.0215,-0.082 l -0.006,0.002 A 16,16 0 0 0 129.11366,48.414 l 0.008,-0.002 a 16,16 0 0 0 -0.0684,-0.0957 16,16 0 0 0 -1.12695,-1.56836 16,16 0 0 0 -0.0508,-0.0723 l -0.008,0.002 a 16,16 0 0 0 -4.32227,-3.66211 16,16 0 0 0 -8,-2.14453 z" /><g
id="g59"
transform="rotate(30,76.75487,86.639766)"><path
style="opacity:1;fill:none;fill-opacity:1;stroke:url(#linearGradient65);stroke-width:32;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="M 90,40.000003 V 100.00001"
id="path9"
sodipodi:nodetypes="cc" /><path
id="path10"
style="color:#000000;fill:#9a9996;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none"
d="M 95.580078,25.005859 90,30.585938 84.457031,25.042969 a 16,16 0 0 0 -1.929687,0.898437 l 6.765625,6.765625 a 1,1 0 0 0 1.414062,0 l 6.820313,-6.820312 a 16,16 0 0 0 -1.947266,-0.88086 z M 100.58203,28.003906 90,38.585938 79.462891,28.048828 a 16,16 0 0 0 -1.414063,1.414063 l 11.244141,11.24414 a 1,1 0 0 0 1.414062,0 L 101.99609,29.417969 a 16,16 0 0 0 -1.41406,-1.414063 z m 3.53125,4.46875 L 90,46.585938 75.941406,32.527344 a 16,16 0 0 0 -0.898437,1.929687 l 14.25,14.25 a 1,1 0 0 0 1.414062,0 L 104.99414,34.419922 a 16,16 0 0 0 -0.88086,-1.947266 z M 105.9375,38.648438 90,54.585938 74.126953,38.712891 A 16,16 0 0 0 74,40 v 1.414062 l 15.292969,15.292969 a 1,1 0 0 0 1.414062,0 L 106,41.414062 V 40 a 16,16 0 0 0 -0.0625,-1.351562 z M 74,46.585938 v 2.828124 l 15.292969,15.292969 a 1,1 0 0 0 1.414062,0 L 106,49.414062 v -2.828124 l -16,16 z m 0,8 v 2.828124 l 15.292969,15.292969 a 1,1 0 0 0 1.414062,0 L 106,57.414062 v -2.828124 l -16,16 z m 0,8 v 2.828124 l 15.292969,15.292969 a 1,1 0 0 0 1.414062,0 L 106,65.414062 v -2.828124 l -16,16 z m 0,8 v 2.828124 l 15.292969,15.292969 a 1,1 0 0 0 1.414062,0 L 106,73.414062 v -2.828124 l -16,16 z m 0,8 v 2.828124 l 15.292969,15.292969 a 1,1 0 0 0 1.414062,0 L 106,81.414062 v -2.828124 l -16,16 z m 0,8 v 2.828124 l 15.292969,15.292968 a 1,1 0 0 0 1.414062,0 L 106,89.414062 V 86.585938 L 90,102.58594 Z m 0,8 v 2.828124 l 15.292969,15.292968 a 1,1 0 0 0 1.414062,0 L 106,97.414062 V 94.585938 L 90,110.58594 Z m 0.28125,8.281252 a 16,16 0 0 0 1.523438,4.35156 l 6.976562,6.97656 a 16,16 0 0 0 4.351562,1.52344 z m 31.4375,0 -12.851562,12.85156 a 16,16 0 0 0 4.351562,-1.52344 l 6.97656,-6.97656 a 16,16 0 0 0 1.52344,-4.35156 z" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#f6f5f4;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="M 90,40.000003 V 140.00001"
id="path8" /></g></g></svg>

After

Width:  |  Height:  |  Size: 7.6 KiB

BIN
assets/404.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 578 B

BIN
assets/card.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

125
assets/card.svg Normal file
View File

@ -0,0 +1,125 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
id="svg10448"
version="1.1"
viewBox="0 0 600 400.00003"
height="400.00003"
width="600"
sodipodi:docname="card.svg"
inkscape:version="1.3 (0e150ed6c4, 2023-07-21)"
inkscape:export-filename="card.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<sodipodi:namedview
id="namedview109"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="false"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="true"
inkscape:deskcolor="#1f1f1f"
showgrid="false"
inkscape:zoom="1.0833333"
inkscape:cx="300"
inkscape:cy="200.30769"
inkscape:window-width="1280"
inkscape:window-height="731"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg10448">
<inkscape:grid
id="grid1"
units="px"
originx="0"
originy="0"
spacingx="1"
spacingy="1"
empcolor="#0099e5"
empopacity="0.30196078"
color="#0099e5"
opacity="0.14901961"
empspacing="5"
dotted="false"
gridanglex="30"
gridanglez="30"
visible="false" />
</sodipodi:namedview>
<defs
id="defs10442">
<rect
x="124.22399"
y="179.45601"
width="417.94308"
height="156.17259"
id="rect1" />
<linearGradient
id="linearGradient3935">
<stop
style="stop-color:#ffa348;stop-opacity:1;"
offset="0"
id="stop3931" />
<stop
style="stop-color:#813d9c;stop-opacity:1;"
offset="1"
id="stop3933" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient3935"
id="linearGradient3937"
x1="0"
y1="0"
x2="600"
y2="400"
gradientUnits="userSpaceOnUse" />
<rect
x="124.22399"
y="179.45601"
width="417.94308"
height="156.17259"
id="rect2" />
</defs>
<metadata
id="metadata10445">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<rect
y="0"
x="0"
width="600"
id="rect965"
height="400"
style="fill:url(#linearGradient3937);fill-opacity:1" />
<text
xml:space="preserve"
id="text2"
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:64px;line-height:1.25;font-family:Cantarell;-inkscape-font-specification:'Cantarell Ultra-Bold';letter-spacing:-4.5px;white-space:pre;shape-inside:url(#rect2);display:inline;fill:#000000;fill-opacity:0.2;stroke-width:4;stroke-linecap:round;stroke-linejoin:round"
transform="translate(50.191385,-15.679866)"><tspan
x="124.22461"
y="236.92788"
id="tspan3">Duckquill</tspan></text>
<text
xml:space="preserve"
id="text1"
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:64px;line-height:1.25;font-family:Cantarell;-inkscape-font-specification:'Cantarell Ultra-Bold';letter-spacing:-4.5px;white-space:pre;shape-inside:url(#rect1);display:inline;fill:#ffffff;fill-opacity:1;stroke-width:4;stroke-linecap:round;stroke-linejoin:round"
transform="translate(46.191385,-19.679866)"><tspan
x="124.22461"
y="236.92788"
id="tspan4">Duckquill</tspan></text>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

19
assets/css/style.scss Normal file
View File

@ -0,0 +1,19 @@
---
---
/*
Duckquill
====================
based on OS Component Website which shamelessly stolen CSS from systemd
https://github.com/jimmac/os-component-website
https://github.com/systemd/systemd/tree/main/docs
*/
@import "variables";
@import "fonts";
@import "main";
@import "rouge-github";
@import "comments";

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

7
comments.md Normal file
View File

@ -0,0 +1,7 @@
---
layout: post
title: "ActivityPub/Fediverse comments demo"
toc: false
comments:
id: 110896168682002971
---

12
demo-page.md Normal file
View File

@ -0,0 +1,12 @@
---
layout: default
title: "Cake Party!"
---
# Welcome to the cake party!
![](https://i.imgur.com/ZS4LFj8.png){: width="50%"}{:loading="lazy"}
Sadly, the cake is a _lie_
[Go Crying](../demo){: .inline-button}

180
demo.md Normal file
View File

@ -0,0 +1,180 @@
---
layout: post
title: "Demo page"
toc: false
archive: "This page is, in fact, not archived, meaning it will receive content updates."
trigger: "This page contains blackjack and hookers, and bad jokes such as this one."
disclaimer: "
- All tricks in this page are performed by lab boys, don't try this at home.
- Don't expose yourself to 4000° kelvin.
- Don't take party escort submission position.
- Don't interact with asbestos and moon rocks."
---
Text can be **bold**, _italic_, or ~~strikethrough~~, it can also be _**thick**_.
[Link to another page](../demo-page){:.page-link}
There should be whitespace between paragraphs.
There should be whitespace between paragraphs. We recommend including a README, or a file with information about your project.
# Header 1
This is a normal paragraph following a header. Codeberg is a code hosting platform for version control and collaboration. It lets you and others work together on projects from anywhere.
## Header 2
> This is a blockquote following a header.
>
> When something is important enough, you do it even if the odds are not in your favor.
### Header 3
```js
// Javascript code with syntax highlighting.
var fun = function lang(l) {
dateformat.i18n = require("./lang/" + l);
return true;
};
```
```ruby
# Ruby code with syntax highlighting
GitHubPages::Dependencies.gems.each do |gem, version|
s.add_dependency(gem, "= #{version}")
end
```
#### Header 4
- This is an unordered list following a header.
- This is an unordered list following a header.
- This is an unordered list following a header.
##### Header 5
1. This is an ordered list following a header.
2. This is an ordered list following a header.
3. This is an ordered list following a header.
###### Header 6
| head1 | head two | three |
| :----------- | :---------------- | :---- |
| ok | good swedish fish | nice |
| out of stock | good and plenty | nice |
| ok | good `oreos` | hmm |
| ok | good `zoute` drop | yumm |
### There's a horizontal rule below this.
---
### Here is an unordered list:
- Item foo
- Item bar
- Item baz
- Item zip
### And an ordered list:
1. Item one
1. Item two
1. Item three
1. Item four
### And a nested list:
- level 1 item
- level 2 item
- level 2 item
- level 3 item
- level 3 item
- level 1 item
- level 2 item
- level 2 item
- level 2 item
- level 1 item
- level 2 item
- level 2 item
- level 1 item
### Small image
![Codeberg icon](https://codeberg.org/Codeberg/Design/raw/branch/main/logo/icon/png/codeberg-logo_icon_blue-64x64.png){:loading="lazy"}
### Large image
![Codeberg horizontal](https://codeberg.org/Codeberg/Design/raw/branch/main/logo/horizontal/png/codeberg-logo_horizontal_blue-850x250.png){:loading="lazy"}
### Definition lists can be used with HTML syntax.
<dl>
<dt>Name</dt>
<dd>Godzilla</dd>
<dt>Born</dt>
<dd>1952</dd>
<dt>Birthplace</dt>
<dd>Japan</dd>
<dt>Color</dt>
<dd>Green</dd>
</dl>
```
Long, single-line code blocks should not wrap. They should horizontally scroll if they are too long. This line should be long enough to demonstrate this.
```
```
The final element.
```
### Extra
Display pixel-art in full width without filtering.
```
![Pixels](https://pixeljoint.com/files/icons/full/animation_rewinded_mostfinal.gif){:.full.pixels}{:loading="lazy"}
```
![Pixels](https://pixeljoint.com/files/icons/full/animation_rewinded_mostfinal.gif){:.full.pixels}{:loading="lazy"}
[Source](https://pixeljoint.com/pixelart/15027.htm){:.site-link}
---
Keyboard shortcuts.
```
<kbd>⌘ Super</kbd> + <kbd>Space</kbd>
```
<kbd>⌘ Super</kbd> + <kbd>Space</kbd>
---
Link with arrow.
```
[Link to page](markdown-page.md){:.page-link}
[Link to site](https://example.org){:.site-link}
```
[Link to page](../markdown-page){:.page-link}
[Link to site](https://example.org){:.site-link}
---
Buttons.
```
[Go to top](#top){: .inline-button}
[File an issue]({{site.issuesurl}})
{: .dialog-buttons}
```

BIN
favicon.aseprite Normal file

Binary file not shown.

BIN
favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 B

49
index.md Normal file
View File

@ -0,0 +1,49 @@
---
layout: default
---
<pre class="ascii">
_ _ _ _ _
>(')____, >(')____, >(')____, >(')____, >(') ___,
(` =~~/ (` =~~/ (` =~~/ (` =~~/ (` =~~/
jgs~^~^`---'~^~^~^`---'~^~^~^`---'~^~^~^`---'~^~^~^`---'~^~^~
</pre>
# Duckquill
[Duckquill](https://codeberg.org/daudix-UFO/duckquill) is a modern, pretty, and clean [Jekyll](https://jekyllrb.com) template that has the purpose of greatly simplifying the process of rolling up your blog. It aims to let you write simple markdown pages and deploy them to Codeberg or GitLab Pages.
Edit a bit of metadata and tweak some of the included graphics and have a blog up in minutes!
- Proper favicon for modern browsers and Apple device icons.
- Mastodon, Facebook and other social media meta cards for easy sharing. Try [Share Preview](https://apps.gnome.org/app/com.rafaelmardojai.SharePreview) to test.
- Local copy of the amazing [Inter font](https://rsms.me/inter/). No slowdowns pulling from external hosting.
- Mobile friendly, dark variant included.
Make yourself a cup of your <abbr title="Coffee, tea, or water">favorite drink</abbr> and let's start!
## Preparation
This template needs a <abbr title="Continuous Integration Practice of automating the integration of code changes from multiple contributors into a single software project">CI</abbr> to be built and deployed, I recommend using either Codeberg or GitLab Pages. For Codeberg Pages I've written a [blog post](https://daudix-ufo.codeberg.page/blog/migration-from-github-to-codeberg/#github-pages--codeberg-pages) on step-by-step guide how to get the CI working.
There is an included `.woodpecker.yml` and `.gitlab-ci.yml` that should be easy to adjust to your situation. For additional info see [Codeberg Pages](https://docs.codeberg.org/codeberg-pages/) and [GitLab Pages](https://docs.gitlab.com/ee/user/project/pages/) docs.
## Getting started
This template includes some useful utilities to make your life easier and keep you sane (looking at you, ruby stuff).
The process of setting up the site locally consists of:
- [Install Podman](https://podman.io/docs/installation). On [Fedora Silverblue](https://fedoraproject.org/silverblue) it's already installed
- Run `local.sh build` to create a Podman container that uses official Jekyll image, download and install all needed Gems and build the site locally.
- Edit the [Jekyll](https://jekyllrb.com) config file -- `_config.yml`.
- Replace all mentions and links of `Daudix` and `Duckquill` with yours.
- Replace or edit all the graphics. Using [Inkscape](https://inkscape.org) are recommended. If you want to reduce the SVGs size, use [svgo](https://github.com/svg/svgo).
- Test the site locally. Run `local.sh serve`.
- `git commit` your changes and push to your remote repo for automatic deployment.

57
local.sh Executable file
View File

@ -0,0 +1,57 @@
#!/usr/bin/env bash
# Script for building and serving Jekyll site locally
check_command() {
if ! command -v "$1" &>/dev/null; then
echo -e "\033[1;31m$1 is not installed, install $1 to continue\033[0m"
exit 1
fi
}
check_command "podman"
set -e
case $1 in
'build')
cat << "EOF"
__ __ __ __ __
| |--.--.--.|__| |.--| |__|.-----.-----.
| _ | | || | || _ | || | _ |__ __ __
|_____|_____||__|__||_____|__||__|__|___ |__|__|__|
|_____|
EOF
echo -e "\e[1;32mBuilding Podman image\e[0m"
podman build --tag pages .
echo -e "\e[1;32mBuilding Jekyll site\e[0m"
podman run \
-it --rm --volume="$PWD:/srv/jekyll:Z" \
-w /srv/jekyll -p 4000:4000 pages \
bundle exec jekyll build
;;
'serve')
cat << "EOF"
__
.-----.-----.----.--.--.|__|.-----.-----.
|__ --| -__| _| | || || | _ |__ __ __
|_____|_____|__| \___/ |__||__|__|___ |__|__|__|
|_____|
EOF
echo -e "\e[1;32mBuilding Podman image\e[0m"
podman build --tag pages .
echo -e "\e[1;32mBuilding Jekyll site\e[0m"
podman run \
-it --rm --volume="$PWD:/srv/jekyll:Z" \
-w /srv/jekyll -p 4000:4000 pages \
bundle exec jekyll serve --incremental --livereload --host 0.0.0.0
;;
esac

18
posts.md Normal file
View File

@ -0,0 +1,18 @@
---
layout: posts
title: Posts
description: Index of all posts published to date.
---
<pre class="ascii">
__
(`/\
`=\/\ __...--~~~~~-._ _.-~~~~~--...__
`=\/\ \ / \\
`=\/ V \\
//_\___--~~~~~~-._ | _.-~~~~~~--...__\\
// ) (..----~~~~._\ | /_.~~~~----.....__\\
===( INK )==========\\|//====================
__ejm\___/________dwb`---`_____________________
</pre>

52
rename.sh Executable file
View File

@ -0,0 +1,52 @@
#!/usr/bin/env bash
# Made by ChatGPT and countless tweak requests
# Script for renaming files to be web-friendly (kebab-case without special characters)
# Function to rename files
rename_files() {
local dir="$1"
cd "$dir" || exit 1
for file in *; do
if [ -f "$file" ]; then
# Get the file extension (if any)
ext=""
if [[ $file == *.* ]]; then
ext=".${file##*.}"
new_name="${file%$ext}"
else
new_name="$file"
fi
# Normalize non-ASCII characters to their closest ASCII representation and remove consecutive dashes
new_name=$(echo "$new_name" | sed 's/[^[:alnum:]\.]/-/g; s/[[:space:]_]\+/-/g; s/-\+/-/g')
# Remove leading and trailing dashes
new_name="${new_name#-}"
new_name="${new_name%-}"
# Convert the filename to lowercase
new_name="${new_name,,}"
# Add back the file extension (if any)
new_name="$new_name$ext"
# Check if the new name is different from the old one
if [ "$file" != "$new_name" ]; then
mv -i "$file" "$new_name"
echo "Renamed: $file -> $new_name"
fi
fi
done
}
# Check if a directory argument is provided, otherwise use the current directory
if [ $# -eq 1 ]; then
target_directory="$1"
else
target_directory="."
fi
# Call the function with the specified directory
rename_files "$target_directory"

62
robots.txt Normal file
View File

@ -0,0 +1,62 @@
# Based on https://seirdy.one/robots.txt
# The next three are borrowed from https://www.videolan.org/robots.txt
# "This robot collects content from the Internet for the sole purpose of
# helping educational institutions prevent plagiarism. [...] we compare
# student papers against the content we find on the Internet to see if we
# can find similarities." (http://www.turnitin.com/robot/crawlerinfo.html)
# --> fuck off.
User-Agent: TurnitinBot
Disallow: /
# "NameProtect engages in crawling activity in search of a wide range of
# brand and other intellectual property violations that may be of interest
# to our clients." (http://www.nameprotect.com/botinfo.html)
# --> fuck off.
User-Agent: NPBot
Disallow: /
# "iThenticate® is a new service we have developed to combat the piracy
# of intellectual property and ensure the originality of written work for
# publishers, non-profit agencies, corporations, and newspapers."
# (http://www.slysearch.com/)
# --> fuck off.
User-Agent: SlySearch
Disallow: /
# BLEXBot assists internet marketers to get information on the link structure
# of sites and their interlinking on the web, to avoid any technical and
# possible legal issues and improve overall online experience.
# (http://webmeup-crawler.com/)
# --> fuck off.
User-Agent: BLEXBot
Disallow: /
# Providing Intellectual Property professionals with superior brand protection
# services by artfully merging the latest technology with expert analysis.
# (https://www.checkmarknetwork.com/spider.html/)
# "The Internet is just way to big to effectively police alone." (ACTUAL quote)
# --> fuck off.
User-agent: CheckMarkNetwork/1.0 (+https://www.checkmarknetwork.com/spider.html)
Disallow: /
# Stop trademark violations and affiliate non-compliance in paid search.
# Automatically monitor your partner and affiliates online marketing to
# protect yourself from harmful brand violations and regulatory risks.
# We regularly crawl websites on behalf of our clients to ensure content
# compliance with brand and regulatory guidelines.
# (https://www.brandverity.com/why-is-brandverity-visiting-me)
# --> fuck off.
User-agent: BrandVerity/1.0
Disallow: /
# Eat shit, OpenAI.
User-agent: ChatGPT-User
Disallow: /
User-agent: GPTBot
Disallow: /
User-agent: CCBot
Disallow: /
Sitemap: https://daudix-ufo.codeberg.page/duckquill/sitemap.xml

20
tags.md Normal file
View File

@ -0,0 +1,20 @@
---
layout: tags
title: Tags
description: Index of all tags, of all posts.
---
<pre class="ascii">
_
| ]
.-|=====-.
| | TAGS |
|________|___
||
||
|| www %%%
vwv || )_(,;;;, ,;,\_/ www
)_( || \|/ \_/ )_(\| (_)
\| \ || /\\|/ |/ \| \|// |
___\|//jgs||//_\V/_\|//_______\\|//V/\\|/__
</pre>