mirror of
https://github.com/System-End/my-blog.git
synced 2026-04-19 16:18:16 +00:00
feat: everything :P
This commit is contained in:
parent
41c2871883
commit
2ceafb1ced
9 changed files with 367 additions and 11 deletions
17
src/components/FormattedDate.astro
Normal file
17
src/components/FormattedDate.astro
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
interface Props {
|
||||
date: Date;
|
||||
}
|
||||
|
||||
const { date } = Astro.props;
|
||||
---
|
||||
|
||||
<time datetime={date.toISOString()}>
|
||||
{
|
||||
date.toLocaleDateString("en-us", {
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
})
|
||||
}
|
||||
</time>
|
||||
15
src/content.config.ts
Normal file
15
src/content.config.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { defineCollection, z } from "astro:content";
|
||||
import { glob } from "astro/loaders";
|
||||
|
||||
const blog = defineCollection({
|
||||
loader: glob({ base: "./src/content/posts", pattern: "**/*.md" }),
|
||||
schema: ({ image }) =>
|
||||
z.object({
|
||||
title: z.string(),
|
||||
description: z.string(),
|
||||
pubDate: z.coerce.date(),
|
||||
heroImage: image().optional(),
|
||||
}),
|
||||
});
|
||||
|
||||
export const collections = { blog };
|
||||
8
src/content/posts/post.md
Normal file
8
src/content/posts/post.md
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
title: Buenos Dias!
|
||||
description: Hola
|
||||
pubDate: 24 Dec 2025
|
||||
---
|
||||
# First post!
|
||||
|
||||
first post - not much here
|
||||
62
src/layouts/BlogPost.astro
Normal file
62
src/layouts/BlogPost.astro
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
---
|
||||
import { Image } from "astro:assets";
|
||||
import type { CollectionEntry } from "astro:content";
|
||||
import FormattedDate from "../components/FormattedDate.astro";
|
||||
import "../styles/global.css";
|
||||
import "../styles/post.css";
|
||||
|
||||
type Props = CollectionEntry<"blog">["data"];
|
||||
const { title, description, pubDate, heroImage } = Astro.props;
|
||||
---
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>{title} // BLOG</title>
|
||||
<meta name="description" content={description} />
|
||||
</head>
|
||||
<body class="min-h-screen">
|
||||
<main class="max-w-3xl mx-auto px-4 py-12">
|
||||
<a
|
||||
href="/posts"
|
||||
class="text-sm mb-8 inline-block"
|
||||
style="color: var(--text-muted);"
|
||||
>
|
||||
← back to posts
|
||||
</a>
|
||||
|
||||
<article>
|
||||
<header
|
||||
class="mb-8 pb-6"
|
||||
style="border-bottom: 1px solid var(--border-color);"
|
||||
>
|
||||
<p
|
||||
class="text-xs mono mb-2"
|
||||
style="color: var(--purple-dim);"
|
||||
>
|
||||
<FormattedDate date={pubDate} />
|
||||
</p>
|
||||
<h1 class="text-4xl font-bold cyber-title mb-3">{title}</h1>
|
||||
<p style="color: var(--text-muted);">{description}</p>
|
||||
{
|
||||
heroImage && (
|
||||
<Image
|
||||
src={heroImage}
|
||||
format="webp"
|
||||
alt={title}
|
||||
class="mt-6"
|
||||
style="border: 1px solid var(--border-color);"
|
||||
/>
|
||||
)
|
||||
}
|
||||
</header>
|
||||
|
||||
<div class="post-content">
|
||||
<slot />
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,16 +1,29 @@
|
|||
---
|
||||
|
||||
import "../styles/global.css";
|
||||
---
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
<title>Astro</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Astro</h1>
|
||||
</body>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
<title>My Blog</title>
|
||||
</head>
|
||||
<body
|
||||
class="bg-gray-900 text-white min-h-screen flex items-center justify-center"
|
||||
>
|
||||
<main class="text-center">
|
||||
<h1 class="text-5xl font-bold mb-4">Welcome to My Blog</h1>
|
||||
<p class="text-xl text-gray-400 mb-8">
|
||||
A place for wild rambles.. maybe
|
||||
</p>
|
||||
<a
|
||||
href="/posts"
|
||||
class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-6 rounded-lg transition"
|
||||
>
|
||||
See My Posts
|
||||
</a>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
21
src/pages/posts/[...slug].astro
Normal file
21
src/pages/posts/[...slug].astro
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
import { type CollectionEntry, getCollection, render } from "astro:content";
|
||||
import BlogPost from "../../layouts/BlogPost.astro";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const posts = await getCollection("blog");
|
||||
return posts.map((post) => ({
|
||||
params: { slug: post.id },
|
||||
props: post,
|
||||
}));
|
||||
}
|
||||
|
||||
type Props = CollectionEntry<"blog">;
|
||||
const post = Astro.props;
|
||||
|
||||
const { Content } = await render(post);
|
||||
---
|
||||
|
||||
<BlogPost {...post.data}>
|
||||
<Content />
|
||||
</BlogPost>
|
||||
71
src/pages/posts/index.astro
Normal file
71
src/pages/posts/index.astro
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
---
|
||||
import { getCollection } from "astro:content";
|
||||
import FormattedDate from "../../components/FormattedDate.astro";
|
||||
import "../../styles/global.css";
|
||||
|
||||
const posts = (await getCollection("blog")).sort(
|
||||
(a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
|
||||
);
|
||||
---
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>// POSTS</title>
|
||||
</head>
|
||||
<body class="min-h-screen">
|
||||
<main class="max-w-3xl mx-auto px-4 py-12">
|
||||
<a
|
||||
href="/"
|
||||
class="text-sm mb-8 inline-block"
|
||||
style="color: var(--text-muted);"
|
||||
>
|
||||
← back to home
|
||||
</a>
|
||||
|
||||
<header class="mb-10">
|
||||
<h1 class="text-4xl font-bold cyber-title">// POSTS</h1>
|
||||
<p style="color: var(--text-muted);" class="mt-2">
|
||||
Transmissions from the void
|
||||
</p>
|
||||
</header>
|
||||
|
||||
{
|
||||
posts.length === 0 && (
|
||||
<p style="color: var(--text-muted);" class="mono">
|
||||
[ NO_DATA_FOUND ]
|
||||
</p>
|
||||
)
|
||||
}
|
||||
|
||||
<div class="space-y-4">
|
||||
{
|
||||
posts.map((post) => (
|
||||
<article class="cyber-card p-5">
|
||||
<a
|
||||
href={`/posts/${post.id}`}
|
||||
class="text-xl font-semibold block mb-2"
|
||||
>
|
||||
{post.data.title}
|
||||
</a>
|
||||
<p
|
||||
style="color: var(--text-muted);"
|
||||
class="text-sm mb-3"
|
||||
>
|
||||
{post.data.description}
|
||||
</p>
|
||||
<p
|
||||
class="text-xs mono"
|
||||
style="color: var(--purple-dim);"
|
||||
>
|
||||
<FormattedDate date={post.data.pubDate} />
|
||||
</p>
|
||||
</article>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
90
src/styles/global.css
Normal file
90
src/styles/global.css
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
@import "tailwindcss";
|
||||
|
||||
:root {
|
||||
--bg-deep: #0a0a0f;
|
||||
--bg-surface: #12121a;
|
||||
--bg-elevated: #1a1a24;
|
||||
--purple-dim: #6b21a8;
|
||||
--purple-main: #a855f7;
|
||||
--purple-bright: #c084fc;
|
||||
--cyan-accent: #22d3ee;
|
||||
--text-primary: #e2e2f0;
|
||||
--text-muted: #8888a0;
|
||||
--border-color: #2a2a3a;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--bg-deep);
|
||||
color: var(--text-primary);
|
||||
font-family: "Segoe UI", system-ui, sans-serif;
|
||||
}
|
||||
|
||||
body::before {
|
||||
content: "";
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
background: repeating-linear-gradient(
|
||||
0deg,
|
||||
transparent,
|
||||
transparent 2px,
|
||||
rgba(0, 0, 0, 0.03) 2px,
|
||||
rgba(0, 0, 0, 0.03) 4px
|
||||
);
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--purple-bright);
|
||||
text-decoration: none;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--cyan-accent);
|
||||
}
|
||||
|
||||
code,
|
||||
pre,
|
||||
.mono {
|
||||
font-family: "JetBrains Mono", "Fira Code", "Consolas", monospace;
|
||||
}
|
||||
|
||||
.cyber-card {
|
||||
background: var(--bg-surface);
|
||||
border: 1px solid var(--border-color);
|
||||
border-left: 3px solid var(--purple-main);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.cyber-card:hover {
|
||||
background: var(--bg-elevated);
|
||||
border-left-color: var(--cyan-accent);
|
||||
box-shadow: 0 0 20px rgba(168, 85, 247, 0.1);
|
||||
}
|
||||
|
||||
.cyber-btn {
|
||||
background: transparent;
|
||||
border: 1px solid var(--purple-main);
|
||||
color: var(--purple-bright);
|
||||
padding: 0.75rem 1.5rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
transition: all 0.2s ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.cyber-btn:hover {
|
||||
background: var(--purple-main);
|
||||
color: white;
|
||||
box-shadow: 0 0 15px rgba(168, 85, 247, 0.4);
|
||||
}
|
||||
|
||||
.cyber-title {
|
||||
color: var(--purple-bright);
|
||||
text-shadow: 0 0 30px rgba(168, 85, 247, 0.3);
|
||||
}
|
||||
59
src/styles/post.css
Normal file
59
src/styles/post.css
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
.post-content {
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.post-content h1,
|
||||
.post-content h2,
|
||||
.post-content h3 {
|
||||
color: var(--purple-bright);
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.post-content h1 {
|
||||
font-size: 2rem;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.post-content h2 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.post-content p {
|
||||
margin-bottom: 1rem;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.post-content a {
|
||||
color: var(--cyan-accent);
|
||||
border-bottom: 1px dashed var(--cyan-accent);
|
||||
}
|
||||
|
||||
.post-content a:hover {
|
||||
color: var(--purple-bright);
|
||||
border-bottom-color: var(--purple-bright);
|
||||
}
|
||||
|
||||
.post-content code {
|
||||
background: var(--bg-elevated);
|
||||
padding: 0.2rem 0.4rem;
|
||||
border-radius: 3px;
|
||||
font-size: 0.9em;
|
||||
color: var(--cyan-accent);
|
||||
}
|
||||
|
||||
.post-content pre {
|
||||
background: var(--bg-surface);
|
||||
border: 1px solid var(--border-color);
|
||||
padding: 1rem;
|
||||
overflow-x: auto;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.post-content img {
|
||||
max-width: 100%;
|
||||
border: 1px solid var(--border-color);
|
||||
margin: 1rem 0;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue