- Changed background gradients and color schemes in `now.astro` and `projects.astro` to use primary colors. - Updated text styles and backgrounds to enhance readability and visual appeal. - Added new font imports for better typography. - Introduced custom animations and hover effects in `global.css` for enhanced user interaction. - Adjusted CSS variables for a more cohesive design across light and dark modes.
206 lines
7.9 KiB
Plaintext
206 lines
7.9 KiB
Plaintext
---
|
|
import Layout from './Layout.astro';
|
|
import type { MarkdownLayoutProps } from 'astro';
|
|
import { type Lang, type FrontmatterProps } from '@/types';
|
|
import { defaultLang } from '@/i18n/ui';
|
|
import GlassHeader from '@/components/GlassHeader';
|
|
import Footer from '@/components/Footer';
|
|
import Container from "../components/ui/Container.astro";
|
|
|
|
// Use Astro's MarkdownLayoutProps for proper type safety
|
|
export type Props = MarkdownLayoutProps<FrontmatterProps>;
|
|
|
|
// Access frontmatter data correctly for markdown layouts
|
|
const { frontmatter } = Astro.props;
|
|
const { title, description } = frontmatter;
|
|
|
|
const lang = Astro.currentLocale as Lang || defaultLang;
|
|
---
|
|
|
|
<Layout title={title} description={description}>
|
|
<!-- Enhanced background with gradient overlay -->
|
|
<div class="fixed inset-0 -z-10 h-full w-full bg-background">
|
|
<!-- Additional subtle gradient for about page -->
|
|
<div class="absolute inset-0 bg-gradient-to-br from-blue-50/30 via-transparent to-blue-50/20 dark:from-blue-950/20 dark:via-transparent dark:to-blue-950/10">
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Glass Header with navigation -->
|
|
<GlassHeader lang={lang} client:load />
|
|
|
|
<!-- Main content with proper spacing for fixed header -->
|
|
<div class="pt-16 sm:pt-20">
|
|
<Container className="py-8 md:py-12">
|
|
<div class="max-w-7xl mx-auto">
|
|
<div class="grid grid-cols-1 xl:grid-cols-4 gap-6 lg:gap-8">
|
|
<!-- Main Content -->
|
|
<main class="xl:col-span-3 order-2 xl:order-1">
|
|
<!-- About page header -->
|
|
<header class="mb-10">
|
|
<h1 class="text-3xl sm:text-4xl lg:text-5xl font-bold text-foreground mb-6 leading-tight tracking-tight">
|
|
✨ {title}
|
|
</h1>
|
|
|
|
{description && (
|
|
<p class="text-lg sm:text-xl text-muted-foreground mb-8 leading-relaxed max-w-4xl">
|
|
📝 {description}
|
|
</p>
|
|
)}
|
|
</header>
|
|
|
|
<!-- About page content with typography styles -->
|
|
<article class="prose prose-lg dark:prose-invert max-w-none prose-headings:scroll-mt-24 prose-headings:font-bold prose-headings:tracking-tight prose-h1:text-2xl sm:prose-h1:text-3xl prose-h2:text-xl sm:prose-h2:text-2xl prose-h3:text-lg sm:prose-h3:text-xl prose-h4:text-base sm:prose-h4:text-lg prose-p:text-base sm:prose-p:text-lg prose-p:leading-relaxed prose-p:mb-6 prose-a:text-primary prose-a:no-underline hover:prose-a:underline prose-strong:text-foreground prose-code:text-sm prose-code:px-2 prose-code:py-1 prose-code:rounded prose-pre:bg-muted prose-pre:border prose-pre:text-sm prose-blockquote:border-l-primary prose-blockquote:bg-muted/30 prose-blockquote:text-base prose-li:text-base sm:prose-li:text-lg prose-li:leading-relaxed">
|
|
<slot />
|
|
</article>
|
|
</main>
|
|
|
|
<!-- Sidebar with Table of Contents -->
|
|
<aside class="xl:col-span-1 order-1 xl:order-2">
|
|
<div class="xl:sticky xl:top-24 space-y-6 sm:space-y-8 xl:space-y-12 xl:max-h-[calc(100vh-6rem)] xl:overflow-y-auto">
|
|
<!-- Table of Contents -->
|
|
<div class="max-xl:hidden">
|
|
<div id="nav-content" class="sticky xl:w-72 w-full top-14">
|
|
<div class="flex flex-col gap-3 p-4">
|
|
<h3 class="dark:text-zinc-200 text-blacktext font-bold tracking-wide text-sm sm:text-base uppercase flex items-center">
|
|
<svg class="w-4 h-4 sm:w-5 sm:h-5 mr-2 text-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 10h16M4 14h16M4 18h16" />
|
|
</svg>
|
|
{lang === 'zh' ? '目录' : 'Table of Contents'}
|
|
</h3>
|
|
<div class="text-neutral-500 dark:text-neutral-300 pr-4">
|
|
<ul id="toc-list" class="leading-relaxed text-sm sm:text-base border-l dark:border-neutral-500/20 border-blacktext/20 mt-4">
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<Footer lang={lang} client:load />
|
|
</Layout>
|
|
|
|
<script>
|
|
/**
|
|
* Initialize table of contents functionality
|
|
* Extracts headings from article content and creates navigation links
|
|
*/
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
const tocList = document.getElementById("toc-list");
|
|
const content = document.querySelector("article");
|
|
|
|
if (!tocList || !content) return;
|
|
|
|
// Extract h1, h2, h3, h4 headings from article content
|
|
const headers = content.querySelectorAll("h1, h2, h3, h4");
|
|
let currentUl = tocList;
|
|
|
|
/**
|
|
* Process each heading and create corresponding TOC entry
|
|
*/
|
|
headers.forEach((header, index) => {
|
|
// Generate ID if not present
|
|
if (!header.id) {
|
|
header.id = header.textContent?.trim().toLowerCase().replace(/\s+/g, "-") + "-" + index;
|
|
}
|
|
|
|
const li = document.createElement("li");
|
|
const link = document.createElement("a");
|
|
link.href = `#${header.id}`;
|
|
link.textContent = header.textContent?.trim() || header.id;
|
|
|
|
// Apply styling based on heading level
|
|
const level = parseInt(header.tagName.charAt(1));
|
|
link.classList.add(
|
|
"block", "w-full", "text-left", "py-1.5", "px-3", "text-sm",
|
|
"transition-all", "duration-200", "border-l-2", "border-transparent",
|
|
"text-muted-foreground", "hover:text-foreground", "hover:bg-muted/30"
|
|
);
|
|
|
|
// Add indentation based on heading level
|
|
if (level === 1) {
|
|
link.classList.add("font-semibold");
|
|
} else if (level === 2) {
|
|
link.classList.add("ml-2");
|
|
} else if (level === 3) {
|
|
link.classList.add("ml-4");
|
|
} else if (level === 4) {
|
|
link.classList.add("ml-6");
|
|
}
|
|
|
|
li.appendChild(link);
|
|
tocList.appendChild(li);
|
|
|
|
/**
|
|
* Handle smooth scroll on link click
|
|
*/
|
|
link.addEventListener("click", function (e) {
|
|
e.preventDefault();
|
|
const targetElement = document.getElementById(header.id);
|
|
if (targetElement) {
|
|
targetElement.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
}
|
|
});
|
|
});
|
|
|
|
/**
|
|
* Set up intersection observer for active section tracking
|
|
*/
|
|
const observer = new IntersectionObserver(
|
|
(entries) => {
|
|
entries.forEach((entry) => {
|
|
const id = entry.target.getAttribute("id");
|
|
const link = document.querySelector(`#toc-list a[href="#${id}"]`);
|
|
|
|
if (entry.isIntersecting) {
|
|
// Remove active state from all links
|
|
document.querySelectorAll("#toc-list a").forEach((el) => {
|
|
el.classList.remove(
|
|
"bg-primary/10", "text-primary", "border-l-primary", "font-medium"
|
|
);
|
|
el.classList.add("text-muted-foreground", "border-transparent");
|
|
});
|
|
|
|
// Add active state to current link
|
|
if (link) {
|
|
link.classList.remove("text-muted-foreground", "border-transparent");
|
|
link.classList.add(
|
|
"bg-primary/10", "text-primary", "border-l-primary", "font-medium"
|
|
);
|
|
}
|
|
}
|
|
});
|
|
},
|
|
{
|
|
rootMargin: "-20% 0% -35% 0%",
|
|
threshold: 0
|
|
}
|
|
);
|
|
|
|
// Observe all headings for intersection
|
|
headers.forEach((header) => observer.observe(header));
|
|
});
|
|
</script>
|
|
|
|
<style>
|
|
/* Additional styling for smooth transitions */
|
|
#toc-list a:hover {
|
|
transform: translateX(2px);
|
|
background-color: rgba(168, 85, 247, 0.05);
|
|
}
|
|
|
|
#toc-list a:focus {
|
|
outline: 2px solid rgba(168, 85, 247, 0.3);
|
|
outline-offset: 1px;
|
|
}
|
|
|
|
#toc-list a {
|
|
transition: all 0.2s ease;
|
|
}
|
|
</style>
|