merge in new changes
This commit is contained in:
@@ -1,17 +1,93 @@
|
||||
---
|
||||
import Layout from './Layout.astro';
|
||||
|
||||
import directus from '../lib/directus';
|
||||
import { ClientRouter } from 'astro:transitions';
|
||||
import { readSingleton } from '@directus/sdk';
|
||||
|
||||
const global = await directus.request(readSingleton('global'));
|
||||
import directus from '@lib/directus';
|
||||
import BaseHead from '@components/BaseHead.astro';
|
||||
import Footer from '@components/Footer.astro';
|
||||
import Header from '@components/Header.astro';
|
||||
|
||||
export interface Props {
|
||||
title: string;
|
||||
import '@styles/global.css';
|
||||
|
||||
interface Props {
|
||||
title?: string;
|
||||
description?: string;
|
||||
ogImage?: any;
|
||||
lang?: string;
|
||||
structuredData?: object;
|
||||
}
|
||||
|
||||
const { title, description = 'Alex Lebens', ogImage, lang = 'en', structuredData } = Astro.props;
|
||||
|
||||
const global = await directus.request(readSingleton('site_global'));
|
||||
const normalizeTitle = !title ? global.name : `${title} | ${global.name}`;
|
||||
---
|
||||
|
||||
<Layout title={global.title} description={global.title}>
|
||||
<slot />
|
||||
</Layout>
|
||||
<html lang={lang}>
|
||||
<head>
|
||||
<title>{normalizeTitle}</title>
|
||||
<BaseHead
|
||||
title={normalizeTitle}
|
||||
description={description}
|
||||
ogImage={ogImage}
|
||||
ogTitle={title === '' ? global.name : title}
|
||||
ogDescription={description}
|
||||
structuredData={structuredData}
|
||||
/>
|
||||
<ClientRouter fallback="swap" />
|
||||
<script is:inline>
|
||||
const theme = (() => {
|
||||
if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) {
|
||||
return localStorage.getItem('theme');
|
||||
}
|
||||
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||
return 'dark';
|
||||
}
|
||||
return 'light';
|
||||
})();
|
||||
|
||||
if (theme === 'light') {
|
||||
document.documentElement.classList.remove('dark');
|
||||
} else {
|
||||
document.documentElement.classList.add('dark');
|
||||
}
|
||||
window.localStorage.setItem('theme', theme);
|
||||
</script>
|
||||
</head>
|
||||
<body class="bg-stone-200 selection:bg-yellow-400 selection:text-neutral-700 dark:bg-stone-700">
|
||||
<!-- <div class="fixed inset-0 -z-10">
|
||||
<div
|
||||
class="bg-grid-pattern absolute inset-0 [mask-image:radial-gradient(white,transparent_85%)] bg-[center_top_-1px]"
|
||||
>
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="mx-auto w-full max-w-(--breakpoint-2xl) flex-grow px-4 sm:px-6 lg:px-8">
|
||||
<Header />
|
||||
<main class="min-h-screen">
|
||||
<slot />
|
||||
</main>
|
||||
</div>
|
||||
<Footer />
|
||||
<style>
|
||||
.scrollbar-hide::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
.scrollbar-hide {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<style>
|
||||
.bg-grid-pattern {
|
||||
background-size: 24px 24px;
|
||||
background-image: radial-gradient(circle, rgba(0, 0, 0, 0.2) 1px, transparent 1px);
|
||||
transition: background-image 0.7s cubic-bezier(0.65, 0, 0.35, 1);
|
||||
}
|
||||
|
||||
:global(.dark) .bg-grid-pattern {
|
||||
background-image: radial-gradient(circle, rgba(255, 255, 255, 0.25) 1px, transparent 1px);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,165 +0,0 @@
|
||||
---
|
||||
import Layout from './Layout.astro';
|
||||
import FormattedDate from '../components/FormattedDate.astro';
|
||||
import ShareButtons from '../components/ShareButtons.astro';
|
||||
import TagList from '../components/TagList.astro';
|
||||
import './styles/markdown.css';
|
||||
|
||||
import directus from '../lib/directus';
|
||||
import { readItems } from '@directus/sdk';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const posts = await directus.request(
|
||||
readItems('posts', {
|
||||
fields: ['*'],
|
||||
})
|
||||
);
|
||||
return posts.map((post) => ({ params: { slug: post.slug }, props: post }));
|
||||
}
|
||||
|
||||
const post = Astro.props;
|
||||
|
||||
let canonicalURL;
|
||||
try {
|
||||
canonicalURL = new URL(Astro.url.pathname, Astro.site || process.env.SITE_URL);
|
||||
} catch (error) {
|
||||
console.error('Error creating canonical URL:', error);
|
||||
canonicalURL = new URL('https://www.example.com');
|
||||
}
|
||||
---
|
||||
|
||||
<Layout title={post.title} description={post.description}>
|
||||
<article class="prose prose-zinc dark:prose-invert lg:prose-lg mx-auto max-w-4xl">
|
||||
<div class="hero-text mb-12">
|
||||
<h1
|
||||
class="mb-4 text-4xl font-bold tracking-tight text-zinc-900 sm:text-5xl dark:text-zinc-100"
|
||||
>
|
||||
{post.title}
|
||||
</h1>
|
||||
|
||||
<p
|
||||
class="mb-2 line-clamp-2 text-center text-sm text-zinc-600 sm:mb-3 sm:line-clamp-3 sm:text-left sm:text-base dark:text-zinc-400"
|
||||
>
|
||||
<!-- {post.description} -->
|
||||
</p>
|
||||
|
||||
<div
|
||||
class="hero-text mb-2 flex flex-wrap items-center justify-center gap-3 text-xs text-zinc-500 sm:mb-3 sm:justify-start sm:gap-4 sm:text-sm dark:text-zinc-400"
|
||||
>
|
||||
<FormattedDate date={post.published_date} />
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="hero-text mb-2 flex flex-wrap items-center justify-center gap-3 text-xs text-zinc-500 sm:mb-3 sm:justify-start sm:gap-4 sm:text-sm dark:text-zinc-400"
|
||||
>
|
||||
<TagList tags={post.tags} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Hero image -->
|
||||
{
|
||||
post.image && (
|
||||
<div class="relative mb-8 overflow-hidden rounded-xl shadow-lg sm:mb-12">
|
||||
<div class="aspect-[16/9] w-full">
|
||||
<img
|
||||
src={`${process.env.DIRECTUS_URL ?? 'https://directus.alexlebens.dev'}/assets/${post.image}?width=500`}
|
||||
alt={post.image_alt}
|
||||
class="h-full w-full object-cover"
|
||||
loading="eager"
|
||||
/>
|
||||
</div>
|
||||
<div class="absolute inset-0 bg-gradient-to-t from-black/30 to-transparent" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
<div class="markdown-content">
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<!-- Add the like button after the content -->
|
||||
<div class="mt-12 border-t border-zinc-200 pt-8 dark:border-zinc-800">
|
||||
<div class="flex flex-col items-center justify-between gap-6 sm:flex-row">
|
||||
<ShareButtons url={canonicalURL.toString()} title={post.title} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{
|
||||
post.updated_date && (
|
||||
<div class="mt-8 text-sm text-zinc-500 italic dark:text-zinc-400">
|
||||
Last updated on <FormattedDate date={post.updated_date} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</article>
|
||||
|
||||
<slot name="after-article" />
|
||||
</Layout>
|
||||
|
||||
<script>
|
||||
document.addEventListener('astro:page-load', () => {
|
||||
// Add smooth reveal animations for content after loading
|
||||
const animateContent = () => {
|
||||
// Animate hero section
|
||||
const heroElements = document.querySelectorAll(
|
||||
'.hero-text div, .hero-text ~ div, .hero-text h1, .hero-text span, .hero-text p, .hero-text + a'
|
||||
);
|
||||
heroElements.forEach((el, index) => {
|
||||
setTimeout(
|
||||
() => {
|
||||
el.classList.add('animate-reveal');
|
||||
},
|
||||
100 + index * 150
|
||||
);
|
||||
});
|
||||
|
||||
// Animate posts with staggered delay
|
||||
const articles = document.querySelectorAll('article.group');
|
||||
articles.forEach((article, index) => {
|
||||
setTimeout(
|
||||
() => {
|
||||
article.classList.add('animate-reveal');
|
||||
},
|
||||
500 + index * 150
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
animateContent();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* Content reveal animations */
|
||||
.hero-text h1,
|
||||
.hero-text div,
|
||||
.hero-text ~ div,
|
||||
.hero-text span,
|
||||
.hero-text p,
|
||||
.hero-text + a,
|
||||
article.group {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
transition:
|
||||
opacity 0.8s ease,
|
||||
transform 0.8s ease;
|
||||
}
|
||||
|
||||
.animate-reveal {
|
||||
opacity: 1 !important;
|
||||
transform: translateY(0) !important;
|
||||
}
|
||||
|
||||
/* Hero image styling */
|
||||
article img:first-of-type {
|
||||
border-radius: 1rem;
|
||||
box-shadow:
|
||||
0 10px 25px -5px rgba(0, 0, 0, 0.1),
|
||||
0 8px 10px -6px rgba(0, 0, 0, 0.1);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
article img:first-of-type:hover {
|
||||
transform: scale(1.01);
|
||||
}
|
||||
</style>
|
||||
@@ -1,98 +0,0 @@
|
||||
---
|
||||
import { ClientRouter } from 'astro:transitions';
|
||||
|
||||
import Navigation from '../components/Navigation.astro';
|
||||
import Footer from '../components/Footer.astro';
|
||||
import Background from '../components/Background.astro';
|
||||
|
||||
import '../styles/global.css';
|
||||
|
||||
interface Props {
|
||||
title?: string | undefined;
|
||||
description?: string | undefined;
|
||||
}
|
||||
|
||||
const { title, description } = Astro.props;
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
<meta name="description" content={description} />
|
||||
<title>{title}</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<!-- Load theme early to prevent flashes between light and dark modes -->
|
||||
<script is:inline>
|
||||
const theme = (() => {
|
||||
if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) {
|
||||
return localStorage.getItem('theme');
|
||||
}
|
||||
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||
return 'dark';
|
||||
}
|
||||
return 'light';
|
||||
})();
|
||||
|
||||
if (theme === 'light') {
|
||||
document.documentElement.classList.remove('dark');
|
||||
} else {
|
||||
document.documentElement.classList.add('dark');
|
||||
}
|
||||
window.localStorage.setItem('theme', theme);
|
||||
</script>
|
||||
<ClientRouter />
|
||||
</head>
|
||||
<body
|
||||
class="flex min-h-screen flex-col bg-white text-zinc-900 dark:bg-zinc-900 dark:text-zinc-100"
|
||||
>
|
||||
<Background />
|
||||
|
||||
<div class="mx-auto w-full max-w-3xl grow px-4 sm:px-6">
|
||||
<Navigation />
|
||||
<main class="py-12">
|
||||
<slot />
|
||||
</main>
|
||||
</div>
|
||||
<Footer />
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<style>
|
||||
/* Content entrance animation */
|
||||
main {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
transition:
|
||||
opacity 0.5s ease,
|
||||
transform 0.5s ease;
|
||||
}
|
||||
|
||||
main.content-entering {
|
||||
animation: content-fade-in 0.6s ease forwards;
|
||||
}
|
||||
|
||||
@keyframes content-fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Theme transition effect */
|
||||
body.theme-transitioning * {
|
||||
transition-duration: 0.3s !important;
|
||||
}
|
||||
</style>
|
||||
@@ -1,890 +0,0 @@
|
||||
/* Article entrance animation */
|
||||
article {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
article.article-entering {
|
||||
animation: article-fade-in 0.8s ease forwards;
|
||||
}
|
||||
|
||||
@keyframes article-fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Hero image hover effect */
|
||||
article img {
|
||||
transition: transform 0.7s cubic-bezier(0.33, 1, 0.68, 1);
|
||||
}
|
||||
|
||||
/* Heading animations */
|
||||
article .heading-animated {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
transition:
|
||||
opacity 0.5s ease,
|
||||
transform 0.5s ease;
|
||||
}
|
||||
|
||||
article .heading-visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* Navigation link hover effect */
|
||||
.blog-nav-link {
|
||||
transition:
|
||||
transform 0.3s ease,
|
||||
box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.blog-nav-link.nav-link-hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 20px -10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* Ensure dark mode compatibility */
|
||||
:global(.dark) .blog-nav-link.nav-link-hover {
|
||||
box-shadow: 0 10px 20px -10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* Enhanced Markdown Content Styling */
|
||||
.markdown-content {
|
||||
font-family:
|
||||
system-ui,
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
'Segoe UI',
|
||||
Roboto,
|
||||
Oxygen,
|
||||
Ubuntu,
|
||||
Cantarell,
|
||||
'Open Sans',
|
||||
'Helvetica Neue',
|
||||
sans-serif;
|
||||
line-height: 1.7;
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
.dark .markdown-content {
|
||||
color: #e5e7eb;
|
||||
}
|
||||
|
||||
/* Headings */
|
||||
.markdown-content h1 {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 800;
|
||||
margin-top: 2.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
line-height: 1.2;
|
||||
color: #111827;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.dark .markdown-content h1 {
|
||||
color: #f9fafb;
|
||||
border-bottom-color: #374151;
|
||||
}
|
||||
|
||||
.markdown-content h2 {
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
margin-top: 2.5rem;
|
||||
margin-bottom: 1rem;
|
||||
line-height: 1.3;
|
||||
color: #111827;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.dark .markdown-content h2 {
|
||||
color: #f9fafb;
|
||||
border-bottom-color: #374151;
|
||||
}
|
||||
|
||||
.markdown-content h3 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
line-height: 1.4;
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
.dark .markdown-content h3 {
|
||||
color: #f9fafb;
|
||||
}
|
||||
|
||||
.markdown-content h4 {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
line-height: 1.5;
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
.dark .markdown-content h4 {
|
||||
color: #f9fafb;
|
||||
}
|
||||
|
||||
.markdown-content h5 {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
line-height: 1.5;
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
.dark .markdown-content h5 {
|
||||
color: #f9fafb;
|
||||
}
|
||||
|
||||
.markdown-content h6 {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
line-height: 1.5;
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
.dark .markdown-content h6 {
|
||||
color: #f9fafb;
|
||||
}
|
||||
|
||||
/* Paragraphs */
|
||||
.markdown-content p {
|
||||
margin-top: 1.25rem;
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
/* Links */
|
||||
.markdown-content a {
|
||||
color: #2563eb;
|
||||
text-decoration: none;
|
||||
border-bottom: 1px solid transparent;
|
||||
transition:
|
||||
border-color 0.2s ease,
|
||||
color 0.2s ease;
|
||||
}
|
||||
|
||||
.markdown-content a:hover {
|
||||
color: #1d4ed8;
|
||||
border-bottom-color: #1d4ed8;
|
||||
}
|
||||
|
||||
.dark .markdown-content a {
|
||||
color: #3b82f6;
|
||||
}
|
||||
|
||||
.dark .markdown-content a:hover {
|
||||
color: #60a5fa;
|
||||
border-bottom-color: #60a5fa;
|
||||
}
|
||||
|
||||
/* Bold text styling - enhanced */
|
||||
.markdown-content strong {
|
||||
font-weight: 700;
|
||||
color: #0f766e;
|
||||
background: linear-gradient(to bottom, transparent 60%, rgba(20, 184, 166, 0.2) 40%);
|
||||
padding: 0 0.2em;
|
||||
border-radius: 0.2em;
|
||||
}
|
||||
|
||||
.dark .markdown-content strong {
|
||||
color: #14b8a6;
|
||||
background: linear-gradient(to bottom, transparent 60%, rgba(20, 184, 166, 0.15) 40%);
|
||||
}
|
||||
|
||||
/* Lists */
|
||||
.markdown-content ul,
|
||||
.markdown-content ol {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
padding-left: 1.5rem;
|
||||
}
|
||||
|
||||
.markdown-content ul {
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
.markdown-content ol {
|
||||
list-style-type: decimal;
|
||||
}
|
||||
|
||||
.markdown-content li {
|
||||
margin-top: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.markdown-content li > ul,
|
||||
.markdown-content li > ol {
|
||||
margin-top: 0.25rem;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
/* Blockquotes */
|
||||
.markdown-content blockquote {
|
||||
border-left: 4px solid #3b82f6;
|
||||
padding: 1rem 1.5rem;
|
||||
margin: 1.5rem 0;
|
||||
background-color: #f3f4f6;
|
||||
border-radius: 0.375rem;
|
||||
font-style: italic;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.dark .markdown-content blockquote {
|
||||
background-color: #1f2937;
|
||||
border-left-color: #60a5fa;
|
||||
}
|
||||
|
||||
.markdown-content blockquote p {
|
||||
margin-top: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.markdown-content blockquote .quote-icon {
|
||||
position: absolute;
|
||||
top: 0.5rem;
|
||||
right: 0.5rem;
|
||||
opacity: 0.1;
|
||||
color: #3b82f6;
|
||||
}
|
||||
|
||||
.dark .markdown-content blockquote .quote-icon {
|
||||
color: #60a5fa;
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
.markdown-content pre {
|
||||
margin: 1.5rem 0;
|
||||
padding: 1rem;
|
||||
background-color: #1e293b !important;
|
||||
border-radius: 0.5rem;
|
||||
overflow-x: auto;
|
||||
position: relative;
|
||||
box-shadow:
|
||||
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
||||
0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
/* Dark mode code blocks - ensure consistency */
|
||||
.dark .markdown-content pre {
|
||||
background-color: #1e293b !important;
|
||||
}
|
||||
|
||||
.markdown-content pre code {
|
||||
font-family:
|
||||
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New',
|
||||
monospace;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.7;
|
||||
color: #e5e7eb !important;
|
||||
background-color: transparent !important;
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.dark .markdown-content pre code {
|
||||
color: #e5e7eb !important;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.markdown-content pre.with-line-numbers {
|
||||
padding-left: 3.5rem;
|
||||
}
|
||||
|
||||
.markdown-content pre code {
|
||||
font-family:
|
||||
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New',
|
||||
monospace;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.7;
|
||||
color: #e5e7eb;
|
||||
background-color: transparent;
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.markdown-content .line-numbers {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
left: 0;
|
||||
width: 2.5rem;
|
||||
text-align: right;
|
||||
padding-right: 0.75rem;
|
||||
color: #6b7280;
|
||||
user-select: none;
|
||||
font-family:
|
||||
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New',
|
||||
monospace;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.7;
|
||||
border-right: 1px solid #4b5563;
|
||||
height: calc(100% - 2rem);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.markdown-content .line-numbers span {
|
||||
display: block;
|
||||
height: 1.7em;
|
||||
}
|
||||
|
||||
.markdown-content .copy-code-button {
|
||||
position: absolute;
|
||||
top: 0.25rem;
|
||||
right: 0.25rem;
|
||||
background-color: #4b5563;
|
||||
color: #e5e7eb;
|
||||
border: none;
|
||||
border-radius: 0.25rem;
|
||||
padding: 0.15rem;
|
||||
cursor: pointer;
|
||||
opacity: 0.6;
|
||||
transition: opacity 0.2s ease;
|
||||
z-index: 10;
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.markdown-content .copy-code-button:hover {
|
||||
opacity: 1;
|
||||
background-color: #6b7280;
|
||||
}
|
||||
|
||||
.markdown-content .copy-code-button svg {
|
||||
width: 0.875rem;
|
||||
height: 0.875rem;
|
||||
}
|
||||
|
||||
/* Language label */
|
||||
.markdown-content .language-label {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 2.5rem;
|
||||
background-color: #4b5563;
|
||||
color: #e5e7eb;
|
||||
font-size: 0.65rem;
|
||||
padding: 0.125rem 0.375rem;
|
||||
border-bottom-left-radius: 0.25rem;
|
||||
border-bottom-right-radius: 0.25rem;
|
||||
text-transform: uppercase;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.05em;
|
||||
font-family:
|
||||
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New',
|
||||
monospace;
|
||||
opacity: 0.8;
|
||||
transition: opacity 0.2s ease;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.markdown-content pre:hover .language-label {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Language badge at bottom right */
|
||||
.markdown-content .language-badge {
|
||||
position: absolute;
|
||||
bottom: 0.5rem;
|
||||
right: 0.5rem;
|
||||
font-size: 0.7rem;
|
||||
padding: 0.1rem 0.3rem;
|
||||
background-color: rgba(75, 85, 99, 0.7);
|
||||
color: #e5e7eb;
|
||||
border-radius: 0.25rem;
|
||||
font-family:
|
||||
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New',
|
||||
monospace;
|
||||
opacity: 0.8;
|
||||
transition: opacity 0.2s ease;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.markdown-content pre:hover .language-badge {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Inline code */
|
||||
.markdown-content code:not(pre code) {
|
||||
font-family:
|
||||
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New',
|
||||
monospace;
|
||||
font-size: 0.875em;
|
||||
color: #ef4444;
|
||||
background-color: #f3f4f6;
|
||||
padding: 0.2em 0.4em;
|
||||
border-radius: 0.25rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.dark .markdown-content code:not(pre code) {
|
||||
color: #f87171;
|
||||
background-color: #1f2937;
|
||||
}
|
||||
|
||||
/* Tables */
|
||||
.markdown-content .table-container {
|
||||
overflow-x: auto;
|
||||
margin: 1.5rem 0;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow:
|
||||
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
||||
0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.markdown-content table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
text-align: left;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.markdown-content table th {
|
||||
background-color: #f3f4f6;
|
||||
color: #111827;
|
||||
font-weight: 600;
|
||||
padding: 0.75rem 1rem;
|
||||
border-bottom: 2px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.dark .markdown-content table th {
|
||||
background-color: #1f2937;
|
||||
color: #f9fafb;
|
||||
border-bottom-color: #374151;
|
||||
}
|
||||
|
||||
.markdown-content table td {
|
||||
padding: 0.75rem 1rem;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.dark .markdown-content table td {
|
||||
border-bottom-color: #374151;
|
||||
}
|
||||
|
||||
.markdown-content table tr.even-row {
|
||||
background-color: #f9fafb;
|
||||
}
|
||||
|
||||
.dark .markdown-content table tr.even-row {
|
||||
background-color: #111827;
|
||||
}
|
||||
|
||||
.markdown-content table tr.odd-row {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.dark .markdown-content table tr.odd-row {
|
||||
background-color: #1f2937;
|
||||
}
|
||||
|
||||
.markdown-content table tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
/* Images */
|
||||
.markdown-content img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
border-radius: 0.5rem;
|
||||
margin: 1.5rem 0;
|
||||
box-shadow:
|
||||
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
||||
0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
/* Horizontal rule */
|
||||
.markdown-content hr {
|
||||
border: 0;
|
||||
height: 1px;
|
||||
background-color: #e5e7eb;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
.dark .markdown-content hr {
|
||||
background-color: #374151;
|
||||
}
|
||||
|
||||
/* Task lists */
|
||||
.markdown-content ul li[data-task-list-item] {
|
||||
list-style-type: none;
|
||||
position: relative;
|
||||
padding-left: 1.5rem;
|
||||
}
|
||||
|
||||
.markdown-content ul li[data-task-list-item]::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0.25rem;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
border: 1px solid #9ca3af;
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.markdown-content ul li[data-task-list-item][data-checked]::before {
|
||||
background-color: #3b82f6;
|
||||
border-color: #3b82f6;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%23ffffff'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 13l4 4L19 7'%3E%3C/path%3E%3C/svg%3E");
|
||||
background-size: 0.75rem;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
/* Footnotes */
|
||||
.markdown-content .footnotes {
|
||||
margin-top: 2rem;
|
||||
padding-top: 1rem;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.dark .markdown-content .footnotes {
|
||||
border-top-color: #374151;
|
||||
}
|
||||
|
||||
.markdown-content .footnotes ol {
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
.markdown-content .footnotes li {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.markdown-content .footnote-backref {
|
||||
font-size: 0.75rem;
|
||||
vertical-align: super;
|
||||
}
|
||||
|
||||
/* Definition lists */
|
||||
.markdown-content dl {
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
|
||||
.markdown-content dt {
|
||||
font-weight: 600;
|
||||
color: #111827;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.dark .markdown-content dt {
|
||||
color: #f9fafb;
|
||||
}
|
||||
|
||||
.markdown-content dd {
|
||||
margin-left: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
/* Callouts and admonitions */
|
||||
.markdown-content .callout {
|
||||
margin: 1.5rem 0;
|
||||
padding: 1rem;
|
||||
border-radius: 0.5rem;
|
||||
border-left: 4px solid;
|
||||
background-color: #f3f4f6;
|
||||
}
|
||||
|
||||
.dark .markdown-content .callout {
|
||||
background-color: #1f2937;
|
||||
}
|
||||
|
||||
.markdown-content .callout.info {
|
||||
border-left-color: #3b82f6;
|
||||
}
|
||||
|
||||
.markdown-content .callout.warning {
|
||||
border-left-color: #f59e0b;
|
||||
background-color: rgba(245, 158, 11, 0.1);
|
||||
}
|
||||
|
||||
.dark .markdown-content .callout.warning {
|
||||
background-color: rgba(245, 158, 11, 0.05);
|
||||
}
|
||||
|
||||
.markdown-content .callout.danger {
|
||||
border-left-color: #ef4444;
|
||||
background-color: rgba(239, 68, 68, 0.1);
|
||||
}
|
||||
|
||||
.dark .markdown-content .callout.danger {
|
||||
background-color: rgba(239, 68, 68, 0.05);
|
||||
}
|
||||
|
||||
.markdown-content .callout.tip {
|
||||
border-left-color: #10b981;
|
||||
background-color: rgba(16, 185, 129, 0.1);
|
||||
}
|
||||
|
||||
.dark .markdown-content .callout.tip {
|
||||
background-color: rgba(16, 185, 129, 0.05);
|
||||
}
|
||||
|
||||
/* Code syntax highlighting - Light theme */
|
||||
.markdown-content .token.comment,
|
||||
.markdown-content .token.prolog,
|
||||
.markdown-content .token.doctype,
|
||||
.markdown-content .token.cdata {
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.markdown-content .token.punctuation {
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.markdown-content .token.namespace {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.markdown-content .token.property,
|
||||
.markdown-content .token.tag,
|
||||
.markdown-content .token.boolean,
|
||||
.markdown-content .token.number,
|
||||
.markdown-content .token.constant,
|
||||
.markdown-content .token.symbol {
|
||||
color: #ef4444;
|
||||
}
|
||||
|
||||
.markdown-content .token.selector,
|
||||
.markdown-content .token.attr-name,
|
||||
.markdown-content .token.string,
|
||||
.markdown-content .token.char,
|
||||
.markdown-content .token.builtin {
|
||||
color: #10b981;
|
||||
}
|
||||
|
||||
.markdown-content .token.operator,
|
||||
.markdown-content .token.entity,
|
||||
.markdown-content .token.url,
|
||||
.markdown-content .language-css .token.string,
|
||||
.markdown-content .style .token.string {
|
||||
color: #9333ea;
|
||||
}
|
||||
|
||||
.markdown-content .token.atrule,
|
||||
.markdown-content .token.attr-value,
|
||||
.markdown-content .token.keyword {
|
||||
color: #3b82f6;
|
||||
}
|
||||
|
||||
.markdown-content .token.function,
|
||||
.markdown-content .token.class-name {
|
||||
color: #f59e0b;
|
||||
}
|
||||
|
||||
.markdown-content .token.regex,
|
||||
.markdown-content .token.important,
|
||||
.markdown-content .token.variable {
|
||||
color: #ec4899;
|
||||
}
|
||||
|
||||
.markdown-content .token.important,
|
||||
.markdown-content .token.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.markdown-content .token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.markdown-content .token.entity {
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
/* Responsive adjustments */
|
||||
@media (max-width: 640px) {
|
||||
.markdown-content h1 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.markdown-content h2 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.markdown-content h3 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.markdown-content pre {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.markdown-content pre.with-line-numbers {
|
||||
padding-left: 3rem;
|
||||
}
|
||||
|
||||
.markdown-content .line-numbers {
|
||||
width: 2rem;
|
||||
}
|
||||
|
||||
.markdown-content blockquote {
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print styles */
|
||||
@media print {
|
||||
.markdown-content {
|
||||
font-size: 12pt;
|
||||
}
|
||||
|
||||
.markdown-content pre,
|
||||
.markdown-content code {
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
.markdown-content a {
|
||||
color: #000 !important;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.markdown-content blockquote {
|
||||
border-left: 2pt solid #000;
|
||||
padding: 0.5cm 1cm;
|
||||
background: none !important;
|
||||
}
|
||||
|
||||
.markdown-content img {
|
||||
max-width: 100% !important;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
.markdown-content h2,
|
||||
.markdown-content h3,
|
||||
.markdown-content h4 {
|
||||
page-break-after: avoid;
|
||||
}
|
||||
|
||||
.markdown-content p,
|
||||
.markdown-content h2,
|
||||
.markdown-content h3 {
|
||||
orphans: 3;
|
||||
widows: 3;
|
||||
}
|
||||
}
|
||||
|
||||
/* Additional elements */
|
||||
.markdown-content details {
|
||||
margin: 1.5rem 0;
|
||||
padding: 0.5rem 1rem;
|
||||
background-color: #f3f4f6;
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.dark .markdown-content details {
|
||||
background-color: #1f2937;
|
||||
border-color: #374151;
|
||||
}
|
||||
|
||||
.markdown-content details summary {
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
|
||||
.markdown-content details[open] summary {
|
||||
margin-bottom: 0.5rem;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.dark .markdown-content details[open] summary {
|
||||
border-bottom-color: #374151;
|
||||
}
|
||||
|
||||
/* Keyboard shortcuts */
|
||||
.markdown-content kbd {
|
||||
font-family:
|
||||
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New',
|
||||
monospace;
|
||||
font-size: 0.8em;
|
||||
padding: 0.2em 0.4em;
|
||||
margin: 0 0.1em;
|
||||
background-color: #f3f4f6;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 0.25rem;
|
||||
box-shadow: 0 1px 0 #d1d5db;
|
||||
}
|
||||
|
||||
.dark .markdown-content kbd {
|
||||
background-color: #1f2937;
|
||||
border-color: #4b5563;
|
||||
box-shadow: 0 1px 0 #4b5563;
|
||||
}
|
||||
|
||||
/* Abbreviations */
|
||||
.markdown-content abbr {
|
||||
cursor: help;
|
||||
text-decoration: underline dotted;
|
||||
}
|
||||
|
||||
/* Highlight text */
|
||||
.markdown-content mark {
|
||||
background-color: #fef3c7;
|
||||
color: #92400e;
|
||||
padding: 0.1em 0.2em;
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.dark .markdown-content mark {
|
||||
background-color: rgba(254, 243, 199, 0.2);
|
||||
color: #fbbf24;
|
||||
}
|
||||
|
||||
/* Subscript and superscript */
|
||||
.markdown-content sub,
|
||||
.markdown-content sup {
|
||||
font-size: 0.75em;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
.markdown-content sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
.markdown-content sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
/* Diagrams and charts */
|
||||
.markdown-content .mermaid {
|
||||
margin: 1.5rem 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Math equations */
|
||||
.markdown-content .math {
|
||||
overflow-x: auto;
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
|
||||
/* Embedded content */
|
||||
.markdown-content iframe {
|
||||
max-width: 100%;
|
||||
margin: 1.5rem 0;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow:
|
||||
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
||||
0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
Reference in New Issue
Block a user