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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
robots.txt
node_modules/
yarn-error.log
yarn.lock
78 changes: 78 additions & 0 deletions assets/css/screen.css
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,84 @@ hr {
}
}

.anchor-link {
position: relative;
opacity: 0;
padding: 8px;
margin-left: 4px;
color: var(--ghost-accent-color);
border: none;
background: none;
cursor: pointer;
transition: opacity 0.3s ease;
min-width: 44px;
min-height: 44px;
display: inline-flex;
align-items: center;
justify-content: center;
}

/* Tooltip styles */
.anchor-link::before {
content: attr(data-tooltip);
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
padding: 6px 10px;
background: var(--color-darker-gray);
color: white;
font-size: 14px;
white-space: nowrap;
border-radius: 4px;
opacity: 0;
visibility: hidden;
transition: opacity 0.2s ease, visibility 0.2s ease;
}

/* Show tooltip on hover */
.anchor-link:hover::before {
opacity: 1;
visibility: visible;
}

/* When copied, change tooltip text */
.anchor-link.copied::before {
content: attr(data-tooltip-copied);
}

@media (hover: hover) {
.anchor-link {
opacity: 0;
}

h1:hover .anchor-link,
h2:hover .anchor-link,
h3:hover .anchor-link,
h4:hover .anchor-link,
h5:hover .anchor-link,
h6:hover .anchor-link,
.anchor-link:focus {
opacity: 1;
}
}

@media (hover: none) {
.anchor-link {
opacity: 0.8;
}
}

.anchor-link.copied {
animation: pulse 0.4s ease;
}

@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.2); }
100% { transform: scale(1); }
}

/* Custom CTA
/* ---------------------------------------------------------- */

Expand Down
50 changes: 50 additions & 0 deletions assets/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,53 @@ function initParallax() {
(function () {
pagination(true, initParallax);
})();

(function (window, document) {
const TOOLTIP_TEXTS = {
default: 'Copy link to this section',
copied: 'Link copied!'
};

var addAnchors = () => {
var headings = document.querySelectorAll('.gh-content h1, .gh-content h2, .gh-content h3, .gh-content h4, .gh-content h5, .gh-content h6')
headings.forEach((heading) => {
heading.insertAdjacentHTML('beforeend', `
<button class="anchor-link"
aria-label="${TOOLTIP_TEXTS.default}"
data-tooltip="${TOOLTIP_TEXTS.default}"
data-tooltip-copied="${TOOLTIP_TEXTS.copied}">
<svg width="1em" height="0.85em" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"></path></svg>
</button>
`)

const anchor = heading.querySelector('.anchor-link');
anchor.addEventListener('click', async (e) => {
e.preventDefault();
const url = new URL(window.location.href);
url.hash = heading.id;

try {
await navigator.clipboard.writeText(url.toString());
showCopiedFeedback(anchor);
} catch (err) {
console.error('Failed to copy:', err);
anchor.setAttribute('aria-label', 'Failed to copy link');
}
});
});
}

function showCopiedFeedback(element) {
element.classList.add('copied');
element.setAttribute('aria-label', TOOLTIP_TEXTS.copied);
element.setAttribute('data-tooltip', TOOLTIP_TEXTS.copied);

setTimeout(() => {
element.classList.remove('copied');
element.setAttribute('aria-label', TOOLTIP_TEXTS.default);
element.setAttribute('data-tooltip', TOOLTIP_TEXTS.default);
}, 2000);
}

document.addEventListener('DOMContentLoaded', addAnchors)
})(window, document);