The first publish page

cover-2.thumb256.gif

Resources

sequenceDiagram
    Alice ->> Bob: Hello Bob, how are you?
    Bob-->>John: How about you John?
    Bob--x Alice: I am good thanks!
    Bob-x John: I am good thanks!

    Bob-->Alice: Checking with John...
    Alice->John: Yes... John, how are you?

Warm coffee from a thermos during the fall hike.


Freedium Userscript

// ==UserScript==
// @name         Open in Freedium
// @namespace    https://thepresent.pages.dev
// @version      1.3
// @description  Adds a floating button and keyboard shortcut to open Medium articles in Freedium (works with SPA navigation)
// @match        *://*/*
// @grant        none
// ==/UserScript==

(function() {
  'use strict';

  function isMediumSite() {
    const host = location.hostname;
    if (host === "medium.com" || host.endsWith(".medium.com")) return true;

    const aliases = [
      "towardsdatascience.com",
      "betterprogramming.pub",
      "levelup.gitconnected.com",
      "javascript.plainenglish.io",
      "python.plainenglish.io",
      "infosecwriteups.com"
    ];
    if (aliases.includes(host)) return true;

    return (
      document.querySelector('meta[content="Medium"]') ||
      document.querySelector('link[rel="canonical"][href*="medium.com"]') ||
      document.querySelector('script[src*="cdn-client.medium.com"]')
    );
  }

  if (!isMediumSite()) return;

  function openFreedium() {
    const url = window.location.href;
    const freediumUrl = "https://freedium.cfd/+" + url;
    window.open(freediumUrl, "_blank");
  }

  let button;

  function addButton() {
    if (button) {
      button.remove(); // remove old button if exists
    }

    // Don't show on root
    if (location.pathname === "/" || location.pathname === "") return;

    button = document.createElement("button");
    button.innerHTML = `
      <svg xmlns="http://www.w3.org/2000/svg"
           width="18" height="18" viewBox="0 0 24 24"
           fill="none" stroke="currentColor"
           stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
        <path d="M18 13v6a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>
        <polyline points="15 3 21 3 21 9"/>
        <line x1="10" y1="14" x2="21" y2="3"/>
      </svg> Freedium
    `;
    button.style.position = "fixed";
    button.style.top = "70px";
    button.style.right = "20px";
    button.style.zIndex = "9999";
    button.style.padding = "10px 16px";
    button.style.fontSize = "14px";
    button.style.background = "#1a8917";
    button.style.color = "white";
    button.style.border = "none";
    button.style.borderRadius = "8px";
    button.style.cursor = "pointer";
    button.style.boxShadow = "0 2px 6px rgba(0,0,0,0.2)";
    button.onmouseenter = () => (button.style.background = "#166e13");
    button.onmouseleave = () => (button.style.background = "#1a8917");
    button.onclick = openFreedium;

    document.body.appendChild(button);
  }

  function addShortcut() {
    document.addEventListener("keydown", (e) => {
      if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key.toLowerCase() === "f") {
        e.preventDefault();
        openFreedium();
      }
    });
  }

  // SPA navigation detection
  function observeUrlChange() {
    let lastUrl = location.href;
    new MutationObserver(() => {
      if (location.href !== lastUrl) {
        lastUrl = location.href;
        addButton(); // re-add button on URL change
      }
    }).observe(document, {subtree: true, childList: true});
  }

  addButton();
  addShortcut();
  observeUrlChange();
})();