MiguelPimentel.do

Meta (or how this site is made)

Table of Contents

This website is powered by ʕ•ᴥ•ʔ Bear, a privacy-first, no-nonsense, superfast blogging platform. Bear makes it very easy to start a blog of your own. Go and take a look, it's a lovely and welcoming community.

All content is written in Markdown, with pieces of HTML here and there.

It's the little things in life that make it that much better. That's why you'll find small quirky features throughout the site. For example: our links have a hover effect with color that matches the type of link (i.e. Pastel Blue for internal links, and Pastel Pink for external ones).

On the more serious side, we have implemented some tweaks to extend the functionality of the site. Let us explore some of them:

Components

Let's take a deeper look at some of the components implemented or added to the site.

Favicon

I use the following code to change the favicon for the site. Instead of being limited to an emoji, this allows us to use an image.

favicon

<link
  rel="icon"
  type="image/png"
  href="https://github.com/semanticdata/public-test/raw/main/SVG/logos/lines.svg"
/>

Scrolling Progress Bar

Mostly used on the blog posts, the scrolling progress bar component includes the following code:

<div class="progress__wrapper" style="visibility: hidden;">
  <div class="progress__bar"></div>
</div>
// SCROLLING PROGRESS BAR //
document.addEventListener("DOMContentLoaded", function () {
  const body = document.body;
  const progressBar = document.querySelector(".progress__bar");

  const updateProgress = () => {
    let scrollPos =
      (window.scrollY / (body.scrollHeight - window.innerHeight)) * 100;
    progressBar.style.width = `${scrollPos}%`;
    requestAnimationFrame(updateProgress);
  };

  // Initial call to set progress bar width
  updateProgress();

  // Update progress bar on scroll
  window.addEventListener("scroll", updateProgress);
});
<div>
  <img
    src="https://bear-images.sfo2.cdn.digitaloceanspaces.com/database-1718584442-0.jpg"
    alt="ssd drive"
    id="post-image"
    style="border:none;"
  />
  <p id="image-alt-text">
    Photo by
    <a
      href="https://unsplash.com/@fennings?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash"
      >Marc PEZIN</a
    >
    on
    <a
      href="https://unsplash.com/?utm_source=miguelpimentel.do&utm_medium=referral"
      >Unsplash</a
    >
  </p>
</div>
// BANNER IMAGE ATTRIBUTIONS //
document.addEventListener("DOMContentLoaded", function () {
  var img = document.querySelector("#post-image");
  var divText = document.querySelector("#divText");

  if (img && divText) {
    divText.textContent = img.alt || "No alt text available";
  }
});

Color Theme Toggle

<a
  ><input type="checkbox" id="theme-toggle" />
  <label for="theme-toggle">Dark mode</label></a
>
// THEME TOGGLE //
document.addEventListener("DOMContentLoaded", function () {
  const themeToggle = document.getElementById("theme-toggle");
  const themeLabel = document.getElementById("theme-label");
  const savedTheme = localStorage.getItem("theme");

  // Function to set the theme based on the saved theme
  const setTheme = (theme) => {
    document.body.setAttribute("theme", theme);
    themeToggle.checked = theme === "dark"; // Update toggle state based on theme
    themeLabel.textContent = theme === "dark" ? "Dark mode" : "Light mode"; // Update label based on theme
  };

  // Initialize theme based on saved theme
  if (savedTheme === "dark") {
    document.body.setAttribute("theme", "dark");
    setTheme("dark");
  } else {
    document.body.setAttribute("theme", "light");
    setTheme("light");
  }

  themeToggle.addEventListener("click", function (e) {
    const checked = e.target.checked;
    const theme = checked ? "dark" : "light";
    document.body.setAttribute("theme", theme);
    setTheme(theme);
    localStorage.setItem("theme", theme);
  });
});

HTML Tabs

npm install --save-dev --save-exact prettier
yarn add --dev --exact prettier
pnpm add --save-dev --save-exact prettier
bun add --dev --exact prettier

Stylesheet

Within the next element we have hidden the full stylesheet used on the site. It was last updated on 2024-06-20.

Expand
/* FONTS */
@import url('https://fonts.googleapis.com/css2?family=Inter&display=swap');
/* @import url('https://fonts.googleapis.com/css2?family=Bitter&display=swap'); */

/* CALLOUTS or ADMONITION */
/* Callouts were removed. Find them inside the components folder of the repository. */

/* VARIABLES */
:root {
    --size-step--2: clamp(0.6944rem, 0.6856rem + 0.0444vi, 0.72rem);
    --size-step--1: clamp(0.8333rem, 0.8101rem + 0.1159vi, 0.9rem);
    --size-step-0: clamp(1rem, 0.9565rem + 0.2174vi, 1.125rem);
    --size-step-1: clamp(1.2rem, 1.1283rem + 0.3587vi, 1.4063rem);
    --size-step-2: clamp(1.44rem, 1.3295rem + 0.5527vi, 1.7578rem);
    --size-step-3: clamp(1.728rem, 1.5648rem + 0.8161vi, 2.1973rem);
    --size-step-4: clamp(2.0736rem, 1.8395rem + 1.1704vi, 2.7466rem);
    --size-step-5: clamp(2.4883rem, 2.1597rem + 1.6433vi, 3.4332rem);

    --bg-color: #f5f5f5;
    --text-color: #333;

    --color-code-background: #111222; /* #f1f1f1 */
    --visited-color: #8b6fcb;

    --garden-green: #9be895;
    --garden-pink: #C072C4;
    --garden-dark-text: #cdd6f4;
    --garden-dark-bg: #1e1e2e;
    --garden-light-bg: #f8f8f8;
    --garden-link-bg: #e9ebed;

    --color-accent: salmon;
    --color-primary: #1a8fe3;

    --font-stack: Inter, Bitter, Inter, system-ui, -apple-system, 'Segoe UI';
    --page-width: 70ch;
}

body[theme="light"] {
    --bg-color: #f5f5f5;
    --text-color: #333;
    --color-code-background: #111222;
    --link-color: var(--text-color);
}

body[theme="dark"] {
    --text-color: #f5f5f5;
    --color-code-background: #222;
    --bg-color: #1e1e2e;
    --link-color: var(--garden-green);
}

* {
    box-sizing: border-box;
}

body {
    background-color: var(--bg-color);
    color: var(--text-color);
    padding: 0.5rem 1rem;
    font-family: var(--font-stack);
    font-size: var(--size-step-0);
    line-height: 1.5;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    margin: 0;
    transition: background-color 0.3s, color 0.3s;
    word-break: break-word;
}

main {
    flex-grow: 1;
}

header,
main,
footer {
    width: 100%;
}

a {
    display: inline-block;
    color: var(--link-color);
}

a:hover {
    text-decoration: none;
    color: var(--color-primary);
}

img {
    max-width: 100%;
    border: 1px solid var(--text-color);
    border-radius: 5px;
}

h1,
h2,
h3,
h4,
h5,
h6 {
    font-weight: 100;
    line-height: 1.2;
    text-wrap: pretty;
}

h1 {
    font-size: var(--size-step-4);
    margin-block-start: 1rem;
}

h2 {
    font-size: var(--size-step-3);
}

h3 {
    font-size: var(--size-step-2);
}

h4 {
    font-size: var(--size-step-1);
}

h5 {
    font-size: var(--size-step-0);
}

h6 {
    font-size: var(--size-step--1);
}

ul,
ol {
    -webkit-padding-start: 1.5rem;
    padding-inline-start: 1.5rem;
}

li {
    padding-block-start: cal(0.75rem);
}

blockquote {
    -webkit-padding-start: 1.5rem;
    padding-inline-start: 1.5rem;
    -webkit-border-start: 0.3em solid;
    border-inline-start: 0.3em solid;
    font-style: italic;
    font-size: var(--size-step-0);
    /*margin-left: 0;*/
}

content>div>* {
    -webkit-margin-before: var(--flow-space, 1.5rem);
    margin-block-start: var(--flow-space, 1.5rem);
}

:is(h1, h2, h3, h4, h5, blockquote) {
    --flow-space: calc($spacing * 2);
}

:is(h1, h2, h3, h4, h5)+* {
    --flow-space: calc($spacing / 3);
}

:is(h1, h2, h3, h4, h5)+ :where(h2, h3, h4, h5) {
    --flow-space: calc($spacing);
}

main,
header,
footer {
    max-width: var(--page-width);
    margin-inline: auto;
}

/* HEADER, TITLE */
.title {
    text-decoration: none;
}

.title h1 {
    font-size: var(--size-step-2);
    margin-block: 0;
    color: var(--text-color);
}

.title:hover {
    text-decoration: none !important;
    outline: none;
}

/*.site-logo {
    width: var(--size-step-3);
}*/

header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    border-bottom: 1px solid var(--color-primary);
    margin-block-end: 1rem;
    word-break: normal;
}

/* NAVIGATION */
nav {
    text-align: right;
    display: inline;
    justify-content: space-between;
    width: 100%;
}

nav p {
    font-size: var(--size-step-0);
}

/* BLOG POSTS in Blog section */
ul.blog-posts {
    list-style-type: none;
    padding: unset;
}

ul.blog-posts li span {
    font-size: var(--size-step-0);
    min-width: 11ch;
    display: flex;
    margin-block-start: 1.5rem;
}

/* CODE and CODEBLOCKS */
.highlight,
.code {
    padding: 1.5rem 1px;
    color: var(--text-color);
}

pre {
    outline: 1px solid var(--text-color);
    background-color: var(--color-code-background);
}

code {
    padding-inline: 3px;
    text-wrap: pretty;
  background-color: #cecece !important;
}

pre {
    padding: 0.75rem;
    overflow: auto;
}

.highlight pre {
    margin: 0 auto;
    background: #111222;
  color: #f7f7f7;
}

/* TABLES */
table {
    width: 100%;
    margin: 1.5rem auto;
    border: 1px solid var(--text-color);
    border-collapse: collapse;
    font-size: var(--size-step-0);
}

table thead th,
table tfoot th {
    background-color: #00000025;
}

table th,
table td {
    padding: 2px 4px;
    border: 1px solid var(--text-color);
}

footer {
    padding-top: 0 !important;
}

/* FOCUS */
/* :is(a, input, textarea, summary, code) */
#theme-label,
:is(a, input, textarea, code) {
    --outline-size: max(2px, 0.08em);
    --outline-style: solid;
    --outline-color: var(--color-primary);
    --outline-offset: 3px;
}

/* :is(a, input, textarea, summary, code):focus */
#theme-label:focus,
:is(a, input, textarea, code):focus {
    outline: var(--outline-size) var(--outline-style) var(--outline-color);
    outline-offset: var(--outline-offset, var(--outline-size));
}

/* :is(a, input, textarea, summary, code):focus-visible */
#theme-label:focus-visible,
:is(a, input, textarea, code):focus-visible {
    outline: var(--outline-size) var(--outline-style) var(--outline-color);
    outline-offset: var(--outline-offset, var(--outline-size));
}

/* :is(a, input, textarea, summary, code):focus:not(:focus-visible) */
#theme-label:focus:not(:focus-visible),
:is(a, input, textarea, code):focus:not(:focus-visible) {
    outline: none;
}

/* :is(a, input, textarea, summary, code):hover */
#theme-label:hover,
:is(a, input, textarea, code):hover {
    outline: var(--outline-size) var(--outline-style) var(--outline-color);
    outline-offset: var(--outline-offset, var(--outline-size));
}

/* MEDIA QUERIES */
@media screen and (max-width: 900px) {
    .highlight pre {
        width: calc(100vw);
        position: relative;
        left: 50%;
        right: 50%;
        margin-left: -50vw;
        margin-right: -50vw;
        outline: 0;
        padding-inline: calc(calc(100vw - 65ch) / 2);
    }

    header {
        flex-direction: column;
        margin-block-start: 1rem;
    }

    nav {
        text-align: center;
    }
}

@media screen and (max-width: 700px) {
    footer p {
        text-align: center;
        float: none;
        margin-block-start: 1rem;
        margin-block-end: 0.5rem;
        /*font-size: var(--size-step-0);*/
    }

    footer span+span {
        display: block;
        text-align: center;
        float: none;
    }

    pre {
        padding-inline: 1.5rem !important;
    }
  
  .meta-page #upvote-form {
    margin-block-end: 6rem;
  }
}

.not-found {
    overflow: hidden;
}

/* PROGRESS BAR */
/*.about-page .progress__wrapper,
.home .progress__wrapper,
.meta-page .progress__wrapper,
.not-found .progress__wrapper,
.posts-page .progress__wrapper,
.projects-page .progress__wrapper,
.subscribe .progress__wrapper,
.uses-page .progress__wrapper {
  display: none;
}*/

.progress-bar .progress__wrapper {
    visibility: visible !important;
}

.progress__wrapper {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 100;
    width: 100%;
    height: 0.65rem;
    background: transparent;
}

.progress__bar {
    filter: grayscale(0.5);
    display: block;
    width: 0;
    height: inherit;
    background: linear-gradient(90deg, rgb(128, 128, 255), rgb(187, 92, 255), #cc53ff);
}

a[href^="http://"]:not([href*="miguelpimentel.do"]):hover,
a[href^="https://"]:not([href*="miguelpimentel.do"]):hover {
    color: var(--color-accent);
    outline-color: var(--color-accent);
}

p:has(+ .tabcontent),
p:has(+ .tabcontent2) {
    display: flex;
    margin: 0;
    padding: 0;
}

.tabcontent .highlight,
.tabcontent2 .highlight,
.tabcontent3 .highlight {
    padding: 0;
    margin: 0;
}

#buttons {
    display: flex;
}

/*:is(button) {
  text-decoration: none;
}*/

a > button {
  padding: 2px 3px;
}
a button:hover {
  outline: none;
  border: none;
}

:is(button):hover {
    background: var(--color-accent);
}

hr {
    border-color: var(--color-primary);
}

mark {
    padding-inline: 3px;
}

blockquote {
    border-color: var(--color-primary);
}

/* Blog post meta_image attribution */
p#image-alt-text {
    font-style: italic;
    text-align: right;
    margin-block: 0;
    font-size: var(--size-step--2);
    filter: opacity(0.9);
}

/* BANNER IMAGES */
p#image-alt-text a:hover {
    border: none;
    outline: none;
}

/* BOOKMARKLETS */
a.bookmarklet-button {
    border: solid 1px black;
    border-radius: 5px;
    padding: 0.5rem;
    margin-block: 0.5rem;
    display: inline;
    background-color: rebeccapurple;
}

.bookmarklets-page .highlight pre span {
    display: inline;
}

.bookmarklets-page time {
    display: none;
}

.bookmarklets-page .embedded.blog-posts li {
    border-bottom: 1px solid green;
    margin-block: 1rem;
}

.bookmarklets-page .embedded.blog-posts li:last-child {
    border: none;
}

.cookie-enjoyer {
    height: var(--size-step-4);
}

/* MUSIC Page was removed */
/* .music-svg {
    display: flex;
    margin-block: 1rem;
}

.music-svg:hover {
    border-radius: 5px;
    outline: none;
}

.music-svg img {
    margin-inline: auto;
    /* width: 80%;*/
display: block;
border-radius: 5px;
background-color: #00000010;
}

.music-svg img:hover {
    outline: 1px solid var(--color-accent);
}

*/

/* BADGES */
.badges {
    text-align: center;
}

.badge,
.badge-footer {
    filter: opacity(0.75);
}

.badge:hover,
.badge-footer:hover {
    border: none;
    outline: none;
    filter: opacity(1);
    transition: filter(opacity) 300ms ease;
}

.badge img,
.badge-footer img {
    border-radius: 4px;
    border: none;
}

/* HTML TABS */
.tablink,
.tablink2,
.tablink3 {
    background-color: #cecece;
    color: var(--text-color);
    float: left;
    border: none;
    outline: none;
    cursor: pointer;
    font-size: var(--size-step-0);
    padding: 0.2rem 1rem;
}

.tabcontent,
.tabcontent2,
.tabcontent3 {
    display: none;
    color: var(--text-color);
}

/* FOOTNOTES */
section.footnotes {
    border-bottom: 0.1rem solid var(--color-primary);
}

section.footnotes::before {
    content: "Footnotes: ";
    font-weight: bold;
    display: flex;
    margin-block-start: 1rem;
}

/* UPVOTE BUTTON */
#upvote-form {
  justify-content: center;
}
.meta-page #upvote-form {
  float: right;
  margin-inline-end: 4rem;
}

button.upvote-button {
    border: 2px solid var(--color-primary);
    padding: 0.5rem;
    font-size: var(--size-step-0);
    display: inline-flex;
    position: absolute;
    margin-block-start: 1.5rem;
    border-radius: 50%;
    cursor: pointer;
    width: 3.5rem;
    height: 3.5rem;
    background-color: #00000015;
    background: #eee;
    color: #000 !important;
    transition: background 200ms;
}

button.upvote-button:hover {
    background-color: var(--color-accent);
}

/* THEME TOGGLE - sun and moon */
/*#theme-toggle {
  visibility: hidden;
}

#theme-toggle + label {
  content: '';
  display: inline-block;
  cursor: pointer;
  height: 2rem;
  width: 2rem;
  border-radius: 50%;
  transition: all 0.3s ease-in-out;
}

#theme-toggle:not(:checked) + label {
  background-color: gold;
}

#theme-toggle:checked + label {
  background-color: transparent;
  box-shadow: inset -0.35rem -0.35rem 1px 1px #fff;
}*/
/*
.container {
  float: right;
  margin: 1.5rem;
}

body[theme=dark] {
  .text-sun {
    color: rgba(0, 0, 0, 0.2);
  }
  .text-moon {
    color: rgba(255, 255, 255, 1);
  }
}

body[theme=light] {
  .text-sun {
    color: rgba(0, 0, 0, 1);
  }
  .text-moon {
    color: rgba(255, 255, 255, 0.2);
  }
}*/

/* THEME TOGGLE in FOOTER */
#theme-toggle {
    display: none;
}

#theme-toggle+label {
    cursor: pointer;
    text-decoration: underline;
}

/* TAGS */
p.tags a {
    background: #bcbcbc;
    background: var(--color-primary);
    border-radius: 3px 0 0 3px;
    color: #000;
    display: inline-block;
    height: 26px;
    line-height: 26px;
    padding: 0 20px 0 23px;
    position: relative;
    margin: 0 10px 10px 0;
    text-decoration: none;
    transition: all 200ms;
}

p.tags a::before {
    background: var(--bg-color);
    border-radius: 10px;
    box-shadow: inset 0 1px rgba(0, 0, 0, 0.25);
    content: '';
    height: 6px;
    left: 10px;
    position: absolute;
    width: 6px;
    top: 10px;
}

p.tags a::after {
    background: var(--bg-color);
    border-bottom: 15px solid transparent;
    border-left: 10px solid #bcbcbc;
    border-left: 10px solid var(--color-primary);
    border-top: 13px solid transparent;
    content: '';
    position: absolute;
    right: 0;
    top: 0;
    transition: all 200ms;
}

p.tags a:hover {
    background: var(--color-accent);
    color: var(--text-color);
    outline: none;
}

p.tags a:hover::after {
    border-left-color: var(--color-accent);
    background: var(--bg-color);
}

/* TAGS CONTAINER */
p.tags {
    display: inline-block;
    width: calc(100% - 3.5rem);
}

p.tags::before {
    content: "Tags: ";
    font-weight: bold;
    display: flex;
    padding-block-end: 0.5rem;
}

body[theme="dark"] {
    #theme-label {
        color: var(--garden-green);
    }
}

#theme-label:hover {
    text-decoration: none;
    color: var(--color-primary);
}

/* Powered by Bear */
footer>span+span,
footer>span+span>a {
    color: var(--text-color);
}

/* Page Specific */
.meta-page footer>span+span {
  /*float: right;*/
}
footer p,
.meta-page footer > p {
 /* text-aligned: right;*/
}

/* BOOKMARKLETS */
/*a.bookmarklet {
  text-decoration: none;
}
a.bookmarklet:hover {
  outline: none;
}*/

summary {
  cursor: pointer;
  padding-inline: 1rem;
}
details {
  border: 1px solid var(--color-primary);
  padding: 0.5rem 0;
  border-radius: 5px;
}
details[open] {
  border-color: var(--color-accent);
}
details[open] summary {
  border-bottom: 1px solid var(--color-accent);
  padding-block-end: 1rem;
}
details[open] ul {
  padding-inline: 2rem;
}

/* NEw BLOCKQUOTES */
blockquote {
  /* font-size: 1.4em; */
  /* width: 80%; */
  margin: 1rem auto; /* 50px */
  /* font-family:Open Sans; */
  font-style:italic;
  color: #555555;
  /* padding:1.2em 30px 1.2em 75px; */
  padding: 1.2rem 1rem 1.2rem 3rem;
  border-left: 8px solid #78C0A8;
  border-right: 1px solid #78C0A8;
  line-height:1.6;
  position: relative;
  background:#EDEDED;
}

blockquote::before {
  /* font-family:Arial; */
  content: "\201C";
  color: #78C0A8;
  font-size: 4rem;
  position: absolute;
  left: 10px;
  top: -10px;
}

blockquote::after {
  content: '';
}

blockquote span {
  display: block;
  color: #333333;
  font-style: normal;
  font-weight: bold;
  margin-top: 1rem;
}

/*                 */
/* Responsive Menu */
/*                 */

:root {
  --color: #1f2227;
}

nav.responsive {
/*   padding: 30px; */
/*   text-align: center; */
  display: none;
}

nav.responsive ul {
/*   float: right; */
}

nav.responsive ul li {
  display: inline-block;
/*   float: left; */
}

nav.responsive ul li:not(:first-child) {
  margin-inline-start: 1rem;
}

nav.responsive ul li a {
  display: inline-block;
  outline: none;
  font-size: 16px;
  text-decoration: none;
  letter-spacing: 0.04em;
  color: var(--color);
}

nav.responsive ul li a:hover {
  color: gray;
  text-decoration: none;
}

@media screen and (max-width: 560px) {
  .nav-container {
    position: fixed;
    top: 0;
    left: 0;
    height: 100%;
    width: 100%;
    z-index: -1;
    opacity: 0;
    transition: all 0.2s ease;
    background: var(--color);
  }

  .nav-container ul {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 100%;
  }

  .nav-container ul li {
    display: block;
    float: none;
    width: 100%;
    text-align: right;
    margin-bottom: 10px;
  }

  .nav-container ul li:nth-child(1) a {
    transition-delay: 0.2s;
  }

  .nav-container ul li:nth-child(2) a {
    transition-delay: 0.3s;
  }

  .nav-container ul li:nth-child(3) a {
    transition-delay: 0.4s;
  }

  .nav-container ul li:nth-child(4) a {
    transition-delay: 0.5s;
  }

  .nav-container ul li:not(:first-child) {
/*     margin-left: 0; */
  }

  nav.responsive {
    display: inherit;
  }
  
  nav.responsive ul li:not(:first-child) {
  margin-inline-start: 0;
}
  
  .nav-container ul li a {
    padding: 10px 25px;
    opacity: 0;
    color: var(--color);
    color: black;
    font-size: 24px;
    font-weight: 600;
    transform: translateY(-20px);
    transition: all 0.2s ease;
  }

  .nav-open {
    position: fixed;
    right: 10px;
    top: 10px;
    display: block;
    width: 48px;
    height: 48px;
    cursor: pointer;
    z-index: 9999;
    border-radius: 50%;
  }

  .nav-open i {
    display: block;
    width: 20px;
    height: 2px;
    border-radius: 2px;
    margin-left: 14px;
    background: var(--color);
    color: white;
  }

  .nav-open i:nth-child(1) {
    margin-top: 16px;
  }

  .nav-open i:nth-child(2) {
    margin-top: 4px;
    opacity: 1;
  }

  .nav-open i:nth-child(3) {
    margin-top: 4px;
  }
}

#nav:checked + .nav-open {
  transform: rotate(45deg);
}

#nav:checked + .nav-open i {
  background: white;
  transition: transform 0.2s ease;
}

#nav:checked + .nav-open i:nth-child(1) {
  transform: translateY(6px) rotate(180deg);
}

#nav:checked + .nav-open i:nth-child(2) {
  opacity: 0;
}

#nav:checked + .nav-open i:nth-child(3) {
  transform: translateY(-6px) rotate(90deg);
}

#nav:checked ~ .nav-container {
  z-index: 9990;
  opacity: 1;
}

#nav:checked ~ .nav-container ul li a {
  opacity: 1;
  transform: translateY(0);
  color: white;
}

.hidden {
  display: none;
}


#meta