upgrade to different layout
Some checks failed
renovate / renovate (push) Successful in 5m22s
release-image-gitea / release (push) Failing after 7m9s
release-image-harbor / release (push) Failing after 7m9s

This commit is contained in:
2025-06-08 16:02:39 -05:00
parent e1632629a9
commit 3e89e6cb1c
75 changed files with 8314 additions and 2884 deletions

View File

@@ -0,0 +1,294 @@
---
import BlogPost from '../../layouts/BlogPost.astro';
import directus from "../../../lib/directus"
import { readItems } from "@directus/sdk";
export async function getStaticPaths() {
const posts = await directus.request(readItems("posts", {
fields: ['*'],
}));
const sortedEntries = [...posts].sort(
(a, b) => b.published_date.valueOf() - a.published_date.valueOf()
);
return sortedEntries.map((post, index) => {
return {
params: { slug: post.slug },
props: {
post,
nextPost: index > 0 ? sortedEntries[index - 1] : null,
prevPost: index < sortedEntries.length - 1 ? sortedEntries[index + 1] : null
},
};
});
}
const { post, nextPost, prevPost } = Astro.props;
---
<BlogPost slug={post.slug} title={post.title} description={post.description} content={post.content} image={post.image} image_alt={post.image_alt} published_date={post.published_date} updated_date={post.updated_date} tags={post.tags}>
<!-- Main Content - Enhanced with better typography and spacing -->
<div class="prose prose-zinc dark:prose-invert max-w-none prose-headings:scroll-mt-24 prose-headings:font-semibold prose-a:text-zinc-800 dark:prose-a:text-zinc-300 prose-a:font-medium prose-a:underline-offset-4 hover:prose-a:text-zinc-600 dark:hover:prose-a:text-zinc-100 prose-img:rounded-xl sm:prose-base prose-sm">
<div set:html={post.content} />
</div>
<!-- Next/Previous Navigation - Improved responsive design -->
<div class="mt-12 sm:mt-16 grid grid-cols-1 md:grid-cols-2 gap-4 sm:gap-6 border-t border-zinc-200 dark:border-zinc-800 pt-8 sm:pt-12">
{prevPost && (
<a
href={`/blog/${prevPost.slug}`}
class="group relative flex flex-col h-full p-4 sm:p-6 rounded-xl border border-zinc-200 dark:border-zinc-800 hover:bg-zinc-50 dark:hover:bg-zinc-800/50 transition-all duration-300 hover:-translate-y-1 overflow-hidden"
>
<div class="absolute inset-0 bg-gradient-to-r from-zinc-100 to-transparent dark:from-zinc-800 dark:to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
<span class="relative z-10 text-xs sm:text-sm font-medium text-zinc-500 dark:text-zinc-400 flex items-center gap-1 sm:gap-2 mb-1 sm:mb-2">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3 h-3 sm:w-4 sm:h-4 transition-transform duration-300 group-hover:-translate-x-1">
<path d="m15 18-6-6 6-6"></path>
</svg>
Previous Article
</span>
<h3 class="text-base sm:text-lg font-medium text-zinc-900 dark:text-white line-clamp-2 group-hover:text-zinc-700 dark:group-hover:text-zinc-300 transition-colors">
{prevPost.title}
</h3>
</a>
)}
{nextPost && (
<a
href={`/blog/${nextPost.slug}`}
class="group relative flex flex-col h-full p-4 sm:p-6 rounded-xl border border-zinc-200 dark:border-zinc-800 hover:bg-zinc-50 dark:hover:bg-zinc-800/50 transition-all duration-300 hover:-translate-y-1 md:text-right overflow-hidden"
>
<div class="absolute inset-0 bg-gradient-to-l from-zinc-100 to-transparent dark:from-zinc-800 dark:to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
<span class="relative z-10 text-xs sm:text-sm font-medium text-zinc-500 dark:text-zinc-400 flex items-center gap-1 sm:gap-2 mb-1 sm:mb-2 md:justify-end">
Next Article
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3 h-3 sm:w-4 sm:h-4 transition-transform duration-300 group-hover:translate-x-1">
<path d="m9 18 6-6-6-6"></path>
</svg>
</span>
<h3 class="text-base sm:text-lg font-medium text-zinc-900 dark:text-white line-clamp-2 group-hover:text-zinc-700 dark:group-hover:text-zinc-300 transition-colors">
{nextPost.title}
</h3>
</a>
)}
</div>
</BlogPost>
<script>
// Removing TOC-related functions
// Add copy buttons to code blocks
function initializeCodeCopyButtons() {
const codeBlocks = document.querySelectorAll('pre');
codeBlocks.forEach(block => {
// Skip if already processed by either method
if (block.classList.contains('code-block-processed') || block.classList.contains('enhanced')) {
return;
}
block.classList.add('code-block-processed');
// Create wrapper if not already wrapped
let wrapper;
if (block.parentNode.classList.contains('relative') && block.parentNode.classList.contains('group')) {
wrapper = block.parentNode;
} else {
wrapper = document.createElement('div');
wrapper.className = 'relative group';
block.parentNode.insertBefore(wrapper, block);
wrapper.appendChild(block);
}
// Add copy button if not already present
if (!wrapper.querySelector('.copy-button') && !wrapper.querySelector('.copy-code-button')) {
const copyButton = document.createElement('button');
copyButton.className = 'copy-button absolute top-2 right-2 p-1.5 rounded-md bg-zinc-700/50 hover:bg-zinc-700 text-zinc-200 opacity-0 group-hover:opacity-100 transition-opacity duration-200';
copyButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 17.25v3.375c0 .621-.504 1.125-1.125 1.125h-9.75a1.125 1.125 0 01-1.125-1.125V7.875c0-.621.504-1.125 1.125-1.125H6.75a9.06 9.06 0 011.5.124m7.5 10.376h3.375c.621 0 1.125-.504 1.125-1.125V11.25c0-4.46-3.243-8.161-7.5-8.876a9.06 9.06 0 00-1.5-.124H9.375c-.621 0-1.125.504-1.125 1.125v3.5m7.5 10.375H9.375a1.125 1.125 0 01-1.125-1.125v-9.25m12 6.625v-1.875a3.375 3.375 0 00-3.375-3.375h-1.5a1.125 1.125 0 01-1.125-1.125v-1.5a3.375 3.375 0 00-3.375-3.375H9.75" />
</svg>
`;
copyButton.addEventListener('click', () => {
const code = block.querySelector('code').innerText;
navigator.clipboard.writeText(code);
// Show copied feedback
copyButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5" />
</svg>
`;
setTimeout(() => {
copyButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 17.25v3.375c0 .621-.504 1.125-1.125 1.125h-9.75a1.125 1.125 0 01-1.125-1.125V7.875c0-.621.504-1.125 1.125-1.125H6.75a9.06 9.06 0 011.5.124m7.5 10.376h3.375c.621 0 1.125-.504 1.125-1.125V11.25c0-4.46-3.243-8.161-7.5-8.876a9.06 9.06 0 00-1.5-.124H9.375c-.621 0-1.125.504-1.125 1.125v3.5m7.5 10.375H9.375a1.125 1.125 0 01-1.125-1.125v-9.25m12 6.625v-1.875a3.375 3.375 0 00-3.375-3.375h-1.5a1.125 1.125 0 01-1.125-1.125v-1.5a3.375 3.375 0 00-3.375-3.375H9.75" />
</svg>
`;
}, 2000);
});
wrapper.appendChild(copyButton);
}
});
}
// Handle SPA transitions for blog post navigation
function setupSPATransitions() {
// Handle prev/next navigation links
document.querySelectorAll('a[href^="/blog/"]').forEach(link => {
// Skip links that are anchor links or already processed
if (link.getAttribute('href').includes('#') || link.hasAttribute('data-spa-handled')) {
return;
}
// Mark as handled to avoid duplicate listeners
link.setAttribute('data-spa-handled', 'true');
link.addEventListener('click', (e) => {
// Don't handle if modifier keys are pressed (for opening in new tab, etc.)
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
return;
}
e.preventDefault();
const targetHref = link.getAttribute('href');
// Trigger page transition animation
const pageTransition = document.getElementById('page-transition');
if (pageTransition) {
pageTransition.classList.remove('opacity-0');
pageTransition.classList.add('opacity-100');
// Navigate after transition effect
setTimeout(() => {
window.location.href = targetHref;
}, 300);
} else {
// Fallback if transition element doesn't exist
window.location.href = targetHref;
}
});
});
}
// Main initialization function
function initializeBlogPost() {
// Initialize remaining components
initializeCodeCopyButtons();
setupSPATransitions();
// Scroll to hash if present in URL
if (window.location.hash) {
setTimeout(() => {
const element = document.querySelector(window.location.hash);
if (element) {
element.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}, 100);
}
}
// Initialize on first load
document.addEventListener('DOMContentLoaded', initializeBlogPost);
// Re-initialize when content changes via Astro's view transitions
document.addEventListener('astro:page-load', initializeBlogPost);
// For compatibility with custom transition system
document.addEventListener('page-transition-complete', initializeBlogPost);
</script>
<style>
/* Removing TOC-related styles */
/* Language badge styling */
.language-badge {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
text-transform: lowercase;
letter-spacing: 0.05em;
}
/* Extra small screens */
@media (min-width: 480px) {
.xs\:inline {
display: inline;
}
.xs\:hidden {
display: none;
}
}
/* Enhanced typography for blog content - Responsive adjustments */
.prose {
@apply text-zinc-800 dark:text-zinc-200;
}
.prose h1, .prose h2, .prose h3, .prose h4 {
@apply text-zinc-900 dark:text-zinc-100 font-semibold;
}
.prose h1 {
@apply text-2xl sm:text-3xl md:text-4xl;
}
.prose h2 {
@apply text-xl sm:text-2xl mt-8 sm:mt-12 mb-3 sm:mb-4 pb-2 border-b border-zinc-200 dark:border-zinc-800;
}
.prose h3 {
@apply text-lg sm:text-xl mt-6 sm:mt-8 mb-2 sm:mb-3;
}
.prose p {
@apply leading-relaxed mb-4 sm:mb-6 text-sm sm:text-base;
}
.prose a {
@apply text-zinc-800 dark:text-zinc-300 font-medium underline decoration-zinc-400 dark:decoration-zinc-600 underline-offset-2 hover:text-zinc-600 dark:hover:text-zinc-100 hover:decoration-zinc-600 dark:hover:decoration-zinc-400 transition-colors;
}
.prose blockquote {
@apply border-l-4 border-zinc-300 dark:border-zinc-700 pl-4 italic text-zinc-700 dark:text-zinc-300 my-4 sm:my-6;
}
.prose code {
@apply bg-zinc-100 dark:bg-zinc-800 px-1.5 py-0.5 rounded text-zinc-800 dark:text-zinc-200 text-sm font-medium;
}
.prose pre {
@apply bg-[#1e293b] dark:bg-[#1e293b] text-zinc-200 p-3 sm:p-4 rounded-lg overflow-x-auto text-xs sm:text-sm my-4 sm:my-6 shadow-md !important;
}
.prose pre code {
@apply bg-transparent p-0 text-zinc-200 dark:text-zinc-200 !important;
}
.prose img {
@apply rounded-lg shadow-md my-6 sm:my-8 mx-auto max-w-full h-auto;
}
.prose ul, .prose ol {
@apply my-4 sm:my-6 pl-5 sm:pl-6;
}
.prose li {
@apply mb-1 sm:mb-2 text-sm sm:text-base;
}
.prose hr {
@apply my-8 sm:my-10 border-zinc-200 dark:border-zinc-800;
}
/* Line clamp for truncating text */
.line-clamp-2 {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
</style>