Downloaded theme
This commit is contained in:
@@ -0,0 +1,337 @@
|
||||
{{- $lang := .Type | default "text" -}}
|
||||
{{- $filename := .Attributes.filename | default "" -}}
|
||||
{{- $label := cond (ne $filename "") $filename ($lang | upper) -}}
|
||||
{{- $id := printf "cb-%s" (printf "%d" .Ordinal | sha256 | truncate 8 "") -}}
|
||||
|
||||
{{- $collapseEnabled := site.Params.codeblock.collapse.enabled | default true -}}
|
||||
{{- $defaultState := site.Params.codeblock.collapse.defaultState | default "expanded" -}}
|
||||
{{- $collapsedHeight := site.Params.codeblock.collapse.collapsedHeight | default 200 -}}
|
||||
|
||||
{{- $highlighted := transform.HighlightCodeBlock . -}}
|
||||
|
||||
<div class="mb-codeblock" id="{{ $id }}" data-lang="{{ $lang | lower }}">
|
||||
<!-- Header with language badge and actions -->
|
||||
<div class="mb-codeblock-header">
|
||||
<div class="mb-codeblock-left">
|
||||
<span class="mb-codeblock-badge">
|
||||
{{ $lang | upper }}
|
||||
</span>
|
||||
{{- if ne $filename "" -}}
|
||||
<span class="mb-codeblock-filename">
|
||||
<i class="fas fa-file-code" style="font-size: 0.65rem;"></i>
|
||||
{{ $filename }}
|
||||
</span>
|
||||
{{- end -}}
|
||||
</div>
|
||||
|
||||
<div class="mb-codeblock-actions">
|
||||
{{- if $collapseEnabled -}}
|
||||
<button class="mb-action-btn mb-collapse-btn" data-collapsed="false" aria-label="Collapse code">
|
||||
<i class="fas fa-compress-alt"></i>
|
||||
<span>Collapse</span>
|
||||
</button>
|
||||
{{- end -}}
|
||||
<button class="mb-action-btn mb-copy-btn" aria-label="Copy code">
|
||||
<i class="fas fa-copy"></i>
|
||||
<span>Copy</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Code content -->
|
||||
<div
|
||||
class="mb-codeblock-content"
|
||||
data-state="{{ $defaultState }}"
|
||||
{{- if eq $defaultState "collapsed" }}
|
||||
style="max-height: {{ $collapsedHeight }}px; overflow: hidden;"
|
||||
{{- end }}
|
||||
>
|
||||
{{ $highlighted.Wrapped }}
|
||||
|
||||
{{- if $collapseEnabled -}}
|
||||
<div class="mb-collapse-overlay">
|
||||
<button class="mb-expand-trigger">
|
||||
<i class="fas fa-chevron-down"></i>
|
||||
<span>Click to expand</span>
|
||||
</button>
|
||||
</div>
|
||||
{{- end -}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const codeblock = document.getElementById('{{ $id }}');
|
||||
if (!codeblock) return;
|
||||
|
||||
const copyBtn = codeblock.querySelector('.mb-copy-btn');
|
||||
const collapseBtn = codeblock.querySelector('.mb-collapse-btn');
|
||||
const content = codeblock.querySelector('.mb-codeblock-content');
|
||||
const overlay = codeblock.querySelector('.mb-collapse-overlay');
|
||||
const expandTrigger = overlay?.querySelector('.mb-expand-trigger');
|
||||
|
||||
// ==================
|
||||
// COPY FUNCTIONALITY
|
||||
// ==================
|
||||
if (copyBtn) {
|
||||
copyBtn.addEventListener('click', async function() {
|
||||
let codeText = '';
|
||||
|
||||
// Handle line-numbered code (Hugo's table format)
|
||||
const codeCell = codeblock.querySelector('.lntd:last-child code');
|
||||
if (codeCell) {
|
||||
codeText = codeCell.textContent || codeCell.innerText || '';
|
||||
} else {
|
||||
// Regular code block
|
||||
const codeEl = codeblock.querySelector('pre code');
|
||||
codeText = codeEl ? (codeEl.textContent || codeEl.innerText || '') : '';
|
||||
}
|
||||
|
||||
try {
|
||||
await navigator.clipboard.writeText(codeText.trim());
|
||||
|
||||
// Success feedback
|
||||
const originalHTML = copyBtn.innerHTML;
|
||||
copyBtn.innerHTML = '<i class="fas fa-check"></i><span>Copied!</span>';
|
||||
copyBtn.classList.add('mb-btn-success');
|
||||
|
||||
setTimeout(() => {
|
||||
copyBtn.innerHTML = originalHTML;
|
||||
copyBtn.classList.remove('mb-btn-success');
|
||||
}, 2000);
|
||||
} catch (err) {
|
||||
console.error('Failed to copy code:', err);
|
||||
|
||||
// Fallback for older browsers
|
||||
const textArea = document.createElement('textarea');
|
||||
textArea.value = codeText.trim();
|
||||
textArea.style.position = 'fixed';
|
||||
textArea.style.opacity = '0';
|
||||
document.body.appendChild(textArea);
|
||||
textArea.select();
|
||||
|
||||
try {
|
||||
document.execCommand('copy');
|
||||
copyBtn.innerHTML = '<i class="fas fa-check"></i><span>Copied!</span>';
|
||||
setTimeout(() => {
|
||||
copyBtn.innerHTML = '<i class="fas fa-copy"></i><span>Copy</span>';
|
||||
}, 2000);
|
||||
} catch (fallbackErr) {
|
||||
console.error('Fallback copy failed:', fallbackErr);
|
||||
}
|
||||
|
||||
document.body.removeChild(textArea);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// =======================
|
||||
// COLLAPSE FUNCTIONALITY
|
||||
// =======================
|
||||
if (collapseBtn && content && overlay) {
|
||||
const collapsedHeight = {{ $collapsedHeight }};
|
||||
|
||||
function toggleCollapse() {
|
||||
const isCollapsed = content.dataset.state === 'collapsed';
|
||||
|
||||
if (isCollapsed) {
|
||||
// EXPAND
|
||||
content.style.maxHeight = '';
|
||||
content.style.overflow = '';
|
||||
content.dataset.state = 'expanded';
|
||||
overlay.style.display = 'none';
|
||||
collapseBtn.innerHTML = '<i class="fas fa-compress-alt"></i><span>Collapse</span>';
|
||||
collapseBtn.dataset.collapsed = 'false';
|
||||
} else {
|
||||
// COLLAPSE
|
||||
content.style.maxHeight = collapsedHeight + 'px';
|
||||
content.style.overflow = 'hidden';
|
||||
content.dataset.state = 'collapsed';
|
||||
overlay.style.display = 'flex';
|
||||
collapseBtn.innerHTML = '<i class="fas fa-expand-alt"></i><span>Expand</span>';
|
||||
collapseBtn.dataset.collapsed = 'true';
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize if default state is collapsed
|
||||
if ('{{ $defaultState }}' === 'collapsed') {
|
||||
content.dataset.state = 'collapsed';
|
||||
overlay.style.display = 'flex';
|
||||
collapseBtn.innerHTML = '<i class="fas fa-expand-alt"></i><span>Expand</span>';
|
||||
collapseBtn.dataset.collapsed = 'true';
|
||||
}
|
||||
|
||||
collapseBtn.addEventListener('click', toggleCollapse);
|
||||
|
||||
if (expandTrigger) {
|
||||
expandTrigger.addEventListener('click', toggleCollapse);
|
||||
}
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* Additional styles for improved codeblock - add to your main.css */
|
||||
|
||||
.mb-codeblock-filename {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
color: var(--color-text);
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
padding: 0.2rem 0.6rem;
|
||||
border-radius: 0.35rem;
|
||||
background: color-mix(in srgb, var(--color-bg) 40%, transparent);
|
||||
border: 1px solid color-mix(in srgb, var(--color-border) 60%, transparent);
|
||||
}
|
||||
|
||||
.mb-action-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
background: transparent;
|
||||
border: 1px solid color-mix(in srgb, var(--color-border) 70%, transparent);
|
||||
color: var(--color-text-muted);
|
||||
cursor: pointer;
|
||||
font-size: 0.7rem;
|
||||
padding: 0.35rem 0.65rem;
|
||||
border-radius: 0.4rem;
|
||||
transition: all 0.15s ease-out;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.mb-action-btn:hover {
|
||||
color: var(--color-accent);
|
||||
background: color-mix(in srgb, var(--color-accent) 12%, transparent);
|
||||
border-color: var(--color-accent);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.mb-action-btn:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.mb-action-btn i {
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
|
||||
.mb-btn-success {
|
||||
color: #22c55e !important;
|
||||
border-color: #22c55e !important;
|
||||
background: color-mix(in srgb, #22c55e 12%, transparent) !important;
|
||||
}
|
||||
|
||||
.mb-collapse-overlay {
|
||||
display: none;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
transparent 0%,
|
||||
rgba(0, 0, 0, 0.3) 40%,
|
||||
rgba(0, 0, 0, 0.85) 100%
|
||||
);
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
padding-bottom: 1rem;
|
||||
cursor: pointer;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.mb-expand-trigger {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
padding: 0.4rem 0.8rem;
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid var(--color-accent);
|
||||
background: color-mix(in srgb, var(--color-accent) 20%, transparent);
|
||||
color: var(--color-accent);
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease-out;
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
|
||||
.mb-expand-trigger:hover {
|
||||
background: color-mix(in srgb, var(--color-accent) 30%, transparent);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(168, 85, 247, 0.3);
|
||||
}
|
||||
|
||||
.mb-expand-trigger i {
|
||||
font-size: 0.7rem;
|
||||
animation: bounce 1.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes bounce {
|
||||
0%, 100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(3px);
|
||||
}
|
||||
}
|
||||
|
||||
/* Language-specific badge colors */
|
||||
.mb-codeblock[data-lang="javascript"] .mb-codeblock-badge,
|
||||
.mb-codeblock[data-lang="js"] .mb-codeblock-badge {
|
||||
background: color-mix(in srgb, #f7df1e 25%, transparent);
|
||||
color: #f7df1e;
|
||||
}
|
||||
|
||||
.mb-codeblock[data-lang="typescript"] .mb-codeblock-badge,
|
||||
.mb-codeblock[data-lang="ts"] .mb-codeblock-badge {
|
||||
background: color-mix(in srgb, #3178c6 25%, transparent);
|
||||
color: #3178c6;
|
||||
}
|
||||
|
||||
.mb-codeblock[data-lang="python"] .mb-codeblock-badge,
|
||||
.mb-codeblock[data-lang="py"] .mb-codeblock-badge {
|
||||
background: color-mix(in srgb, #3776ab 25%, transparent);
|
||||
color: #3776ab;
|
||||
}
|
||||
|
||||
.mb-codeblock[data-lang="go"] .mb-codeblock-badge {
|
||||
background: color-mix(in srgb, #00add8 25%, transparent);
|
||||
color: #00add8;
|
||||
}
|
||||
|
||||
.mb-codeblock[data-lang="rust"] .mb-codeblock-badge,
|
||||
.mb-codeblock[data-lang="rs"] .mb-codeblock-badge {
|
||||
background: color-mix(in srgb, #ce422b 25%, transparent);
|
||||
color: #ce422b;
|
||||
}
|
||||
|
||||
.mb-codeblock[data-lang="html"] .mb-codeblock-badge {
|
||||
background: color-mix(in srgb, #e34c26 25%, transparent);
|
||||
color: #e34c26;
|
||||
}
|
||||
|
||||
.mb-codeblock[data-lang="css"] .mb-codeblock-badge {
|
||||
background: color-mix(in srgb, #264de4 25%, transparent);
|
||||
color: #264de4;
|
||||
}
|
||||
|
||||
.mb-codeblock[data-lang="bash"] .mb-codeblock-badge,
|
||||
.mb-codeblock[data-lang="sh"] .mb-codeblock-badge,
|
||||
.mb-codeblock[data-lang="shell"] .mb-codeblock-badge {
|
||||
background: color-mix(in srgb, #4eaa25 25%, transparent);
|
||||
color: #4eaa25;
|
||||
}
|
||||
|
||||
.mb-codeblock[data-lang="json"] .mb-codeblock-badge {
|
||||
background: color-mix(in srgb, #000000 25%, transparent);
|
||||
color: #dddddd;
|
||||
}
|
||||
|
||||
.mb-codeblock[data-lang="yaml"] .mb-codeblock-badge,
|
||||
.mb-codeblock[data-lang="yml"] .mb-codeblock-badge {
|
||||
background: color-mix(in srgb, #cb171e 25%, transparent);
|
||||
color: #cb171e;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user