refactor: 清理无用资源并更新项目配置
删除大量未使用的图标、图片和组件文件 更新.gitignore、tsconfig.json和astro配置 添加新的工具函数和UI组件 修改项目元数据和依赖项
This commit is contained in:
@@ -1,94 +1,83 @@
|
||||
---
|
||||
import "../styles/global.css";
|
||||
import Header from "../components/layout/Header.astro";
|
||||
import Footer from "../components/layout/Footer.astro";
|
||||
import SpeedInsights from "@vercel/speed-insights/astro"
|
||||
const {
|
||||
pageTitle = "NeonMint by EFEELE 🚀",
|
||||
description = "Welcome to NeonMint by EFEELE, where I develop software and share knowledge.",
|
||||
ogimage = {
|
||||
url: "/images/imagedefault.webp",
|
||||
alt: "Default image of EFEELE",
|
||||
},
|
||||
} = Astro.props;
|
||||
|
||||
const siteUrl = new URL(Astro.url).origin;
|
||||
const SEO = {
|
||||
sitename: "NeonMint by EFEELE🚀",
|
||||
url: siteUrl,
|
||||
locale: "en_US",
|
||||
author: "Fernando Lopez | EFEELE",
|
||||
twitter: "@efeeledev",
|
||||
};
|
||||
interface Props {
|
||||
title?: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
|
||||
const twitterimage = `${siteUrl}${ogimage.url}`;
|
||||
const { title = "Rishikesh S - Portfolio", description = "My Portfolio" } =
|
||||
Astro.props;
|
||||
---
|
||||
|
||||
<html
|
||||
lang="en"
|
||||
class="dark:bg-[#0E0E11] bg-mint-50/5 font-montserrat scroll-smooth"
|
||||
>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>{pageTitle}</title>
|
||||
<!-- Favicon for different platforms -->
|
||||
<link rel="icon" href="/favicon-32x32.png" sizes="32x32" />
|
||||
<link rel="icon" href="/favicon-16x16.png" sizes="16x16" />
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
||||
<link rel="icon" href="/android-chrome-192x192.png" sizes="192x192" />
|
||||
<link rel="icon" href="/android-chrome-512x512.png" sizes="512x512" />
|
||||
|
||||
<!-- Web manifest -->
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
<meta name="description" content={description} />
|
||||
<meta name="author" content={SEO.author} />
|
||||
<meta name="robots" content="index, follow" />
|
||||
<link rel="canonical" href={`${Astro.site}${Astro.url.pathname}`}>
|
||||
<!-- Open Graph / Facebook -->
|
||||
<meta property="og:title" content={pageTitle} />
|
||||
<meta property="og:description" content={description} />
|
||||
<meta property="og:image" content={ogimage.url} />
|
||||
<meta property="og:image:alt" content={ogimage.alt} />
|
||||
<meta property="og:url" content={SEO.url} />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:site_name" content={SEO.sitename} />
|
||||
<meta property="og:locale" content={SEO.locale} />
|
||||
|
||||
|
||||
<!-- Twitter Cards -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content={pageTitle} />
|
||||
<meta name="twitter:description" content={description} />
|
||||
<meta name="twitter:image" content={twitterimage} />
|
||||
<meta name="twitter:image:alt" content={ogimage.alt} />
|
||||
<meta name="twitter:site" content={SEO.twitter} />
|
||||
|
||||
<meta name="theme-color" content="#0E0E11"/>
|
||||
|
||||
<!-- Sitemap -->
|
||||
<link rel="sitemap" href="/sitemap-index.xml" />
|
||||
|
||||
<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"
|
||||
/>
|
||||
</head>
|
||||
<body class="overflow-x-hidden">
|
||||
<SpeedInsights/>
|
||||
<div class="blur-circle"></div>
|
||||
<body
|
||||
class="min-h-screen bg-background font-sans antialiased selection:bg-purple-500/20 selection:text-purple-500"
|
||||
>
|
||||
<div
|
||||
style=" background:linear-gradient(45deg, rgba(96, 250, 155, 0) 10.79%, rgba(96, 250, 170, 0.03) 40.92%, rgba(96, 250, 155, 0) 90.35%)"
|
||||
class="fixed top-0 left-0 w-full h-full pointer-events-none -z-1"
|
||||
class="fixed inset-0 -z-10 h-full w-full bg-background bg-[radial-gradient(ellipse_80%_80%_at_50%_-20%,rgba(120,119,198,0.3),rgba(255,255,255,0))]"
|
||||
>
|
||||
</div>
|
||||
<Header />
|
||||
|
||||
<div class="min-h-[85vh] ">
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<Footer />
|
||||
<script>
|
||||
import "../scripts/menu.js";
|
||||
</script>
|
||||
<slot />
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<script is:inline>
|
||||
const getThemePreference = () => {
|
||||
if (typeof localStorage !== "undefined" && localStorage.getItem("theme")) {
|
||||
return localStorage.getItem("theme");
|
||||
}
|
||||
return window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||
? "dark"
|
||||
: "light";
|
||||
};
|
||||
const isDark = getThemePreference() === "dark";
|
||||
document.documentElement.classList[isDark ? "add" : "remove"]("dark");
|
||||
|
||||
if (typeof localStorage !== "undefined") {
|
||||
const observer = new MutationObserver(() => {
|
||||
const isDark = document.documentElement.classList.contains("dark");
|
||||
localStorage.setItem("theme", isDark ? "dark" : "light");
|
||||
});
|
||||
observer.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ["class"],
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
:root {
|
||||
--transition-standard: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
body {
|
||||
transition:
|
||||
background-color var(--transition-standard),
|
||||
color var(--transition-standard);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
---
|
||||
import Layout from "./Layout.astro";
|
||||
import { Icon } from "astro-icon/components";
|
||||
import Heading from "../components/ui/Heading.astro";
|
||||
import Experience from "../components/portfolio/Experience.astro";
|
||||
import NavArticle from "../components/layout/NavArticle.astro";
|
||||
import Contact from "../components/portfolio/Contact.astro";
|
||||
import Tools from "../components/portfolio/Tools.astro";
|
||||
const { frontmatter } = Astro.props;
|
||||
---
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
document.querySelectorAll("h1, h2, h3, h4, h5, h6").forEach((header) => {
|
||||
header.classList.add("scroll-m-28");
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<Layout
|
||||
pageTitle={frontmatter.title}
|
||||
description={frontmatter.description}
|
||||
ogimage={frontmatter.image}
|
||||
>
|
||||
<section
|
||||
class="w-full px-8 mt-5 max-sm:px-4 py-4 flex flex-row justify-center gap-6"
|
||||
>
|
||||
<div class="w-64 max-xl:hidden"></div>
|
||||
|
||||
<article
|
||||
class="flex flex-col gap-8 max-w-3xl max-md:w-full pb-10 pt-8 mt-8 max-sm:mt-0 px-14 max-md:px-10 max-sm:px-6 dark:bg-transparent bg-white dark:border-0 border border-neutral-100 rounded-2xl"
|
||||
>
|
||||
<div class="w-full h-auto mb-4 mx-auto" id="#">
|
||||
<div
|
||||
class="transition-all justify-center w-full gap-8 max-md:gap-3 max-lg:gap-2 flex flex-col items-center z-0 relative dark:from-mint-950 dark:to-zinc-950"
|
||||
>
|
||||
<div class="aspect-square h-60 max-md:size-32">
|
||||
<div
|
||||
class="group-hover:scale-105 relative z-10 flex w-full cursor-pointer items-center overflow-hidden rounded-full dark:p-[1.5px] p-[2px] transition-all duration-500"
|
||||
>
|
||||
<div
|
||||
class="absolute inset-0 h-full w-full rounded-fullfrom-transparent to-riptide-500 dark:from-transparent f dark:to-mint-300 animate-rotate-border bg-conic/[from_var(--border-angle)]"
|
||||
>
|
||||
</div>
|
||||
<div class="relative z-20 flex w-full rounded-full bg-mint-900">
|
||||
<div
|
||||
class="w-full aspect-square rounded-full bg-[url(/images/efeeleprofile.webp)] bg-center bg-cover"
|
||||
aria-label="Photo of Fernando Aldair López Ponce (EFEELE) for the blog"
|
||||
>
|
||||
<a
|
||||
href="/about-me"
|
||||
class="flex h-full w-full"
|
||||
aria-label="View about me page"></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="w-full flex flex-col justify-center gap-4 max-md:gap-2">
|
||||
<div class="text-center">
|
||||
<Heading textGradient="Fernando López | EFEELE" />
|
||||
</div>
|
||||
|
||||
<p
|
||||
class="text-lg max-xl:text-base text-blacktext dark:text-gray-200 mb-0 leading-8 font-semibold"
|
||||
>
|
||||
<b
|
||||
class="bg-linear-to-r from-riptide-400 to-mint-500 dark:to-mint-200 dark:from-riptide-300 text-transparent bg-clip-text"
|
||||
>Frontend Developer</b
|
||||
> with <b
|
||||
class="bg-linear-to-r from-riptide-400 to-mint-500 dark:to-mint-200 dark:from-riptide-300 text-transparent bg-clip-text"
|
||||
>8 years of experience</b
|
||||
>, passionate about development, technology, and coffee that
|
||||
sparks ideas. I love bringing digital projects to life. 🚀☕
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-4 items-center">
|
||||
<Heading text="About" textGradient="me" />
|
||||
</div>
|
||||
|
||||
<div class="markdown text-white" id="content">
|
||||
<slot />
|
||||
</div>
|
||||
</article>
|
||||
<NavArticle title={frontmatter.title} />
|
||||
</section>
|
||||
<section class="py-8 px-8 max-md:py-4 mb-4 scroll-m-16" id="experience">
|
||||
<div class="flex flex-col gap-8 pt-8 max-w-4xl mx-auto">
|
||||
<div class="flex gap-4 items-center justify-center">
|
||||
<Icon class="text-3xl text-white" name="briefcase" />
|
||||
<Heading text="Experience" textGradient="Work" level={2} />
|
||||
</div>
|
||||
|
||||
<Experience />
|
||||
</div>
|
||||
</section>
|
||||
<section class="py-8 px-8 max-md:py-4 mt-10 mb-20 scroll-m-16" id="sttack">
|
||||
<div class="flex flex-col gap-8 max-w-3xl justify-center mx-auto">
|
||||
<div class="flex gap-4 items-center justify-center">
|
||||
<Icon class="text-3xl text-white" name="dashboard" />
|
||||
<Heading text="Stack" textGradient="Technological" level={2} />
|
||||
</div>
|
||||
<Tools variant="center" />
|
||||
</div>
|
||||
</section>
|
||||
<Contact />
|
||||
</Layout>
|
||||
@@ -1,143 +0,0 @@
|
||||
---
|
||||
import Layout from "./Layout.astro";
|
||||
import { Icon } from "astro-icon/components";
|
||||
import DatePub from "../components/blog/DatePub.astro";
|
||||
import Tag from "../components/ui/Tag.astro";
|
||||
import Capsule from "../components/ui/Capsule.astro";
|
||||
import NavArticle from "../components/layout/NavArticle.astro";
|
||||
import ListPosts from "../components/blog/ListPosts.astro";
|
||||
import NavigationArticles from "../components/layout/NavigationArticles.astro";
|
||||
import Share from "../components/ui/Share.astro";
|
||||
const { frontmatter } = Astro.props;
|
||||
const currentUrl = `${Astro.site}${Astro.url.pathname}`;
|
||||
const tweetText = encodeURIComponent(
|
||||
`"${frontmatter.title}" - by ${frontmatter.author} | EFEELE`
|
||||
);
|
||||
import Heading from "../components/ui/Heading.astro";
|
||||
---
|
||||
|
||||
<script>
|
||||
const copyButtonLabel = `<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5 2V1H10V2H5ZM4.75 0C4.33579 0 4 0.335786 4 0.75V1H3.5C2.67157 1 2 1.67157 2 2.5V12.5C2 13.3284 2.67157 14 3.5 14H7V13H3.5C3.22386 13 3 12.7761 3 12.5V2.5C3 2.22386 3.22386 2 3.5 2H4V2.25C4 2.66421 4.33579 3 4.75 3H10.25C10.6642 3 11 2.66421 11 2.25V2H11.5C11.7761 2 12 2.22386 12 2.5V7H13V2.5C13 1.67157 12.3284 1 11.5 1H11V0.75C11 0.335786 10.6642 0 10.25 0H4.75ZM9 8.5C9 8.77614 8.77614 9 8.5 9C8.22386 9 8 8.77614 8 8.5C8 8.22386 8.22386 8 8.5 8C8.77614 8 9 8.22386 9 8.5ZM10.5 9C10.7761 9 11 8.77614 11 8.5C11 8.22386 10.7761 8 10.5 8C10.2239 8 10 8.22386 10 8.5C10 8.77614 10.2239 9 10.5 9ZM13 8.5C13 8.77614 12.7761 9 12.5 9C12.2239 9 12 8.77614 12 8.5C12 8.22386 12.2239 8 12.5 8C12.7761 8 13 8.22386 13 8.5ZM14.5 9C14.7761 9 15 8.77614 15 8.5C15 8.22386 14.7761 8 14.5 8C14.2239 8 14 8.22386 14 8.5C14 8.77614 14.2239 9 14.5 9ZM15 10.5C15 10.7761 14.7761 11 14.5 11C14.2239 11 14 10.7761 14 10.5C14 10.2239 14.2239 10 14.5 10C14.7761 10 15 10.2239 15 10.5ZM14.5 13C14.7761 13 15 12.7761 15 12.5C15 12.2239 14.7761 12 14.5 12C14.2239 12 14 12.2239 14 12.5C14 12.7761 14.2239 13 14.5 13ZM14.5 15C14.7761 15 15 14.7761 15 14.5C15 14.2239 14.7761 14 14.5 14C14.2239 14 14 14.2239 14 14.5C14 14.7761 14.2239 15 14.5 15ZM8.5 11C8.77614 11 9 10.7761 9 10.5C9 10.2239 8.77614 10 8.5 10C8.22386 10 8 10.2239 8 10.5C8 10.7761 8.22386 11 8.5 11ZM9 12.5C9 12.7761 8.77614 13 8.5 13C8.22386 13 8 12.7761 8 12.5C8 12.2239 8.22386 12 8.5 12C8.77614 12 9 12.2239 9 12.5ZM8.5 15C8.77614 15 9 14.7761 9 14.5C9 14.2239 8.77614 14 8.5 14C8.22386 14 8 14.2239 8 14.5C8 14.7761 8.22386 15 8.5 15ZM11 14.5C11 14.7761 10.7761 15 10.5 15C10.2239 15 10 14.7761 10 14.5C10 14.2239 10.2239 14 10.5 14C10.7761 14 11 14.2239 11 14.5ZM12.5 15C12.7761 15 13 14.7761 13 14.5C13 14.2239 12.7761 14 12.5 14C12.2239 14 12 14.2239 12 14.5C12 14.7761 12.2239 15 12.5 15Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg>`;
|
||||
let codeBlocks = Array.from(document.querySelectorAll("pre"));
|
||||
|
||||
for (let codeBlock of codeBlocks) {
|
||||
let wrapper = document.createElement("div");
|
||||
wrapper.style.position = "relative";
|
||||
wrapper.classList.add("code-block-efe", "group");
|
||||
let copyButton = document.createElement("button");
|
||||
copyButton.className = "copy-code";
|
||||
copyButton.innerHTML = copyButtonLabel;
|
||||
|
||||
codeBlock.setAttribute("tabindex", "0");
|
||||
|
||||
// wrap codeblock with relative parent element
|
||||
if (codeBlock.parentNode) {
|
||||
codeBlock.parentNode.insertBefore(wrapper, codeBlock);
|
||||
wrapper.appendChild(codeBlock);
|
||||
|
||||
// Add the copy button to the wrapper instead of the codeBlock
|
||||
// This ensures the button stays fixed relative to the code block container
|
||||
wrapper.appendChild(copyButton);
|
||||
}
|
||||
|
||||
copyButton.addEventListener("click", async () => {
|
||||
await copyCode(codeBlock, copyButton);
|
||||
});
|
||||
}
|
||||
|
||||
async function copyCode(block: HTMLElement, button: HTMLButtonElement) {
|
||||
let code = block.querySelector("code");
|
||||
if (!code) return;
|
||||
|
||||
let text = code.innerText;
|
||||
|
||||
await navigator.clipboard.writeText(text);
|
||||
|
||||
// visual feedback that task is completed
|
||||
button.innerHTML = `<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M11.4669 3.72684C11.7558 3.91574 11.8369 4.30308 11.648 4.59198L7.39799 11.092C7.29783 11.2452 7.13556 11.3467 6.95402 11.3699C6.77247 11.3931 6.58989 11.3355 6.45446 11.2124L3.70446 8.71241C3.44905 8.48022 3.43023 8.08494 3.66242 7.82953C3.89461 7.57412 4.28989 7.55529 4.5453 7.78749L6.75292 9.79441L10.6018 3.90792C10.7907 3.61902 11.178 3.53795 11.4669 3.72684Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg> Copied`;
|
||||
|
||||
setTimeout(() => {
|
||||
button.innerHTML = copyButtonLabel;
|
||||
}, 700);
|
||||
}
|
||||
</script>
|
||||
|
||||
<Layout
|
||||
pageTitle={frontmatter.title}
|
||||
description={frontmatter.description}
|
||||
ogimage={frontmatter.image}
|
||||
>
|
||||
<section
|
||||
class="relative mx-auto px-8 max-sm:px-4 flex flex-row justify-center gap-6"
|
||||
>
|
||||
<div class="w-64 max-xl:hidden"></div>
|
||||
<article
|
||||
class="flex flex-col gap-8 max-w-3xl max-md:w-full pb-10 pt-8 mt-8 px-14 max-md:px-10 max-sm:px-4 dark:bg-transparent bg-white dark:border-0 border border-neutral-100 rounded-2xl"
|
||||
>
|
||||
<header class="flex flex-col gap-4" id="start">
|
||||
<div class="flex gap-2 flex-wrap">
|
||||
{
|
||||
frontmatter.languages.map((language: string) => (
|
||||
<Capsule lang={language} />
|
||||
))
|
||||
}
|
||||
</div>
|
||||
<div class="gap-3 flex flex-wrap justify-start items-center">
|
||||
{frontmatter.tags.map((tag: string) => <Tag tag={tag}>{tag}</Tag>)}
|
||||
</div>
|
||||
<DatePub date={frontmatter.pubDate} />
|
||||
|
||||
<Heading text={frontmatter.title} />
|
||||
|
||||
<div
|
||||
class="flex items-center max-sm:flex-col gap-2 max-sm:items-start justify-between"
|
||||
>
|
||||
<div class="white flex items-center gap-4">
|
||||
<div
|
||||
aria-label="Photo of Fernando Aldair López Ponce (EFEELE) for the blog"
|
||||
class="size-10 bg-cover bg-center rounded-full drop-shadow-lg"
|
||||
style="background-image: url(/images/efeeleprofile.webp);"
|
||||
>
|
||||
</div>
|
||||
<a
|
||||
id={frontmatter.title}
|
||||
class="leading-0 text-sm font-semibold items-center gap-3 text-blacktext dark:text-riptide-50"
|
||||
href="/blog"
|
||||
>{frontmatter.author}
|
||||
</a>
|
||||
</div>
|
||||
<Share currentUrl={currentUrl} tweetText={tweetText} />
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<figure>
|
||||
{
|
||||
frontmatter.image?.url && (
|
||||
<img
|
||||
class="w-full rounded-xl"
|
||||
src={frontmatter.image.url}
|
||||
alt={frontmatter.image.alt || "Article image"}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</figure>
|
||||
|
||||
<div class="markdown" id="content">
|
||||
<slot />
|
||||
</div>
|
||||
<Share currentUrl={currentUrl} tweetText={tweetText} />
|
||||
</article>
|
||||
<NavArticle title={frontmatter.title} />
|
||||
</section>
|
||||
<div
|
||||
class="flex flex-col gap-6 max-w-4xl max-lg:py-2 py-3 max-xl:py-2 mx-auto"
|
||||
>
|
||||
<div class="px-8">
|
||||
<NavigationArticles />
|
||||
<hr class="text-mint-300/50" />
|
||||
</div>
|
||||
<div class="px-8 max-sm:px-4">
|
||||
<ListPosts currentPostUrl={Astro.url.pathname} />
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
@@ -1,67 +0,0 @@
|
||||
---
|
||||
import Layout from "./Layout.astro";
|
||||
import DatePub from "../components/blog/DatePub.astro";
|
||||
import Capsule from "../components/ui/Capsule.astro";
|
||||
import Heading from "../components/ui/Heading.astro";
|
||||
import NavArticle from "../components/layout/NavArticle.astro";
|
||||
import Contact from "../components/portfolio/Contact.astro";
|
||||
const { frontmatter } = Astro.props;
|
||||
|
||||
---
|
||||
|
||||
|
||||
<Layout
|
||||
pageTitle={frontmatter.title}
|
||||
description={frontmatter.description}
|
||||
ogimage={frontmatter.image}
|
||||
>
|
||||
<section
|
||||
class="relative mx-auto px-8 max-sm:px-4 flex flex-row justify-center gap-6"
|
||||
>
|
||||
<div class="w-64 max-xl:hidden"></div>
|
||||
<article
|
||||
class="flex flex-col gap-8 max-w-3xl max-md:w-full pb-10 pt-8 mt-8 px-14 max-md:px-10 max-sm:px-4 dark:bg-transparent bg-white dark:border-0 border border-neutral-100 rounded-2xl"
|
||||
>
|
||||
<header class="flex flex-col gap-4" id="start">
|
||||
<div class="flex gap-2 flex-wrap">
|
||||
{
|
||||
frontmatter.languages.map((language: string) => (
|
||||
<Capsule linkEnabled={false} lang={language} />
|
||||
))
|
||||
}
|
||||
</div>
|
||||
|
||||
<DatePub date={frontmatter.pubDate} />
|
||||
|
||||
<Heading text={frontmatter.title} />
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<figure>
|
||||
{
|
||||
frontmatter.image?.url && (
|
||||
<img
|
||||
class="w-full rounded-xl"
|
||||
src={frontmatter.image.url}
|
||||
alt={frontmatter.image.alt || "Article image"}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</figure>
|
||||
|
||||
<div class="markdown " id="content">
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
</article>
|
||||
<NavArticle title={frontmatter.title} />
|
||||
</section>
|
||||
<div
|
||||
class="flex flex-col gap-6 max-w-4xl max-lg:py-2 py-3 max-xl:py-2 mx-auto"
|
||||
>
|
||||
|
||||
|
||||
</div>
|
||||
<Contact />
|
||||
</Layout>
|
||||
Reference in New Issue
Block a user