mirror of
https://github.com/anotherhadi/blog.git
synced 2026-04-03 04:02:09 +02:00
init
This commit is contained in:
52
src/pages/403.astro
Normal file
52
src/pages/403.astro
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
import { House, FolderOpen } from "@lucide/astro";
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="403 - Forbidden | Another Hadi"
|
||||
description="You don't have permission to access this page."
|
||||
>
|
||||
<div class="min-h-screen flex items-center justify-center px-4 py-20">
|
||||
<div class="text-center max-w-2xl mx-auto">
|
||||
<!-- Large 403 Number -->
|
||||
<h1 class="text-9xl font-bold text-primary mb-4 animate-pulse">403</h1>
|
||||
|
||||
<!-- Error Title -->
|
||||
<h2 class="text-4xl font-bold mb-4">🥀 Forbidden</h2>
|
||||
|
||||
<!-- Error Description -->
|
||||
<p class="text-xl mb-8 text-base-content/70">
|
||||
Oops! You don't have permission to access this page. Let's get you back
|
||||
on track.
|
||||
</p>
|
||||
|
||||
<!-- Divider -->
|
||||
<div class="divider"></div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="flex gap-4 justify-center flex-wrap mt-8">
|
||||
<a href="/" class="btn btn-primary gap-2">
|
||||
<House class="size-5" />
|
||||
Go Home
|
||||
</a>
|
||||
<a href="/#projects" class="btn btn-outline gap-2">
|
||||
<FolderOpen class="size-5" />
|
||||
View Projects
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Helpful Links -->
|
||||
<div class="flex justify-center gap-2 mt-12">
|
||||
<p class="text-sm text-base-content/60 mb-4">
|
||||
You might be looking for:
|
||||
</p>
|
||||
<div class="flex gap-3 justify-center flex-wrap text-sm">
|
||||
<a href="/blog" class="link link-hover">Blog</a>
|
||||
<span class="text-base-content/30">•</span>
|
||||
<a href="/#about" class="link link-hover">About</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
52
src/pages/404.astro
Normal file
52
src/pages/404.astro
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
import { House, FolderOpen } from "@lucide/astro";
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="404 - Page Not Found | Another Hadi"
|
||||
description="The page you're looking for doesn't exist."
|
||||
>
|
||||
<div class="min-h-screen flex items-center justify-center px-4 py-20">
|
||||
<div class="text-center max-w-2xl mx-auto">
|
||||
<!-- Large 404 Number -->
|
||||
<h1 class="text-9xl font-bold text-primary mb-4 animate-pulse">404</h1>
|
||||
|
||||
<!-- Error Title -->
|
||||
<h2 class="text-4xl font-bold mb-4">🥀 Page Not Found</h2>
|
||||
|
||||
<!-- Error Description -->
|
||||
<p class="text-xl mb-8 text-base-content/70">
|
||||
Oops! The page you're looking for doesn't exist or has been moved. Let's
|
||||
get you back on track.
|
||||
</p>
|
||||
|
||||
<!-- Divider -->
|
||||
<div class="divider"></div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="flex gap-4 justify-center flex-wrap mt-8">
|
||||
<a href="/" class="btn btn-primary gap-2">
|
||||
<House class="size-5" />
|
||||
Go Home
|
||||
</a>
|
||||
<a href="/#projects" class="btn btn-outline gap-2">
|
||||
<FolderOpen class="size-5" />
|
||||
View Projects
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Helpful Links -->
|
||||
<div class="flex justify-center gap-2 mt-12">
|
||||
<p class="text-sm text-base-content/60 mb-4">
|
||||
You might be looking for:
|
||||
</p>
|
||||
<div class="flex gap-3 justify-center flex-wrap text-sm">
|
||||
<a href="/blog" class="link link-hover">Blog</a>
|
||||
<span class="text-base-content/30">•</span>
|
||||
<a href="/#about" class="link link-hover">About</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
75
src/pages/500.astro
Normal file
75
src/pages/500.astro
Normal file
@@ -0,0 +1,75 @@
|
||||
---
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
import { House, ArrowLeft } from "@lucide/astro";
|
||||
|
||||
interface Props {
|
||||
error?: unknown;
|
||||
}
|
||||
|
||||
const { error } = Astro.props;
|
||||
|
||||
// Sanitize error for display - NEVER expose sensitive server details in production
|
||||
const displayMessage =
|
||||
"An unexpected error occurred while processing your request.";
|
||||
|
||||
// Log full error server-side for debugging (only visible in server logs)
|
||||
if (error instanceof Error) {
|
||||
console.error("500 Server Error:", {
|
||||
message: error.message,
|
||||
stack: error.stack,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="500 - Server Error | Another Hadi"
|
||||
description="An error occurred while processing your request."
|
||||
>
|
||||
<div class="min-h-screen flex items-center justify-center px-4 py-20">
|
||||
<div class="text-center max-w-2xl mx-auto">
|
||||
<!-- Large 500 Number -->
|
||||
<h1 class="text-9xl font-bold text-error mb-4 animate-pulse">500</h1>
|
||||
|
||||
<!-- Error Title -->
|
||||
<h2 class="text-4xl font-bold mb-4">Server Error</h2>
|
||||
|
||||
<!-- Error Description -->
|
||||
<p class="text-xl mb-8 text-base-content/70">
|
||||
{displayMessage}
|
||||
<br />
|
||||
Please try again later or contact me if the problem persists.
|
||||
</p>
|
||||
|
||||
<!-- Divider -->
|
||||
<div class="divider"></div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="flex gap-4 justify-center flex-wrap mt-8">
|
||||
<a href="/" class="btn btn-primary gap-2">
|
||||
<House class="size-5" />
|
||||
Go Home
|
||||
</a>
|
||||
<button onclick="history.back()" class="btn btn-outline gap-2">
|
||||
<ArrowLeft class="size-5" />
|
||||
Go Back
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Helpful Links -->
|
||||
<div class="mt-8">
|
||||
<p class="text-sm text-base-content/60 mb-4">Need help?</p>
|
||||
<div class="flex gap-3 justify-center flex-wrap text-sm">
|
||||
<a href="/#contact" class="link link-hover">Contact</a>
|
||||
<span class="text-base-content/30">•</span>
|
||||
<a
|
||||
href="https://github.com/anotherhadi/blog/issues"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="link link-hover">Report Issue</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
75
src/pages/503.astro
Normal file
75
src/pages/503.astro
Normal file
@@ -0,0 +1,75 @@
|
||||
---
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
import { House, ArrowLeft } from "@lucide/astro";
|
||||
|
||||
interface Props {
|
||||
error?: unknown;
|
||||
}
|
||||
|
||||
const { error } = Astro.props;
|
||||
|
||||
// Sanitize error for display - NEVER expose sensitive server details in production
|
||||
const displayMessage =
|
||||
"An unexpected error occurred while processing your request.";
|
||||
|
||||
// Log full error server-side for debugging (only visible in server logs)
|
||||
if (error instanceof Error) {
|
||||
console.error("503 Service Unavaiable:", {
|
||||
message: error.message,
|
||||
stack: error.stack,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="503 - Service Unavaiable | Another Hadi"
|
||||
description="An error occurred while processing your request."
|
||||
>
|
||||
<div class="min-h-screen flex items-center justify-center px-4 py-20">
|
||||
<div class="text-center max-w-2xl mx-auto">
|
||||
<!-- Large 503 Number -->
|
||||
<h1 class="text-9xl font-bold text-error mb-4 animate-pulse">503</h1>
|
||||
|
||||
<!-- Error Title -->
|
||||
<h2 class="text-4xl font-bold mb-4">Service Unavailable</h2>
|
||||
|
||||
<!-- Error Description -->
|
||||
<p class="text-xl mb-8 text-base-content/70">
|
||||
{displayMessage}
|
||||
<br />
|
||||
Please try again later or contact me if the problem persists.
|
||||
</p>
|
||||
|
||||
<!-- Divider -->
|
||||
<div class="divider"></div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="flex gap-4 justify-center flex-wrap mt-8">
|
||||
<a href="/" class="btn btn-primary gap-2">
|
||||
<House class="size-5" />
|
||||
Go Home
|
||||
</a>
|
||||
<button onclick="history.back()" class="btn btn-outline gap-2">
|
||||
<ArrowLeft class="size-5" />
|
||||
Go Back
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Helpful Links -->
|
||||
<div class="mt-8">
|
||||
<p class="text-sm text-base-content/60 mb-4">Need help?</p>
|
||||
<div class="flex gap-3 justify-center flex-wrap text-sm">
|
||||
<a href="/#contact" class="link link-hover">Contact</a>
|
||||
<span class="text-base-content/30">•</span>
|
||||
<a
|
||||
href="https://github.com/anotherhadi/blog/issues"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="link link-hover">Report Issue</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
27
src/pages/blog/[...slug].astro
Normal file
27
src/pages/blog/[...slug].astro
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
import { getCollection, render } from "astro:content";
|
||||
import BlogLayout from "../../layouts/BlogLayout.astro";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const blogEntries = await getCollection("blog");
|
||||
|
||||
return blogEntries.map((entry) => ({
|
||||
params: { slug: entry.id },
|
||||
props: { entry },
|
||||
}));
|
||||
}
|
||||
|
||||
const { entry } = Astro.props;
|
||||
const { Content } = await render(entry);
|
||||
---
|
||||
|
||||
<BlogLayout
|
||||
title={entry.data.title}
|
||||
description={entry.data.description}
|
||||
publishDate={entry.data.publishDate}
|
||||
updatedDate={entry.data.updatedDate}
|
||||
image={entry.data.image}
|
||||
tags={entry.data.tags}
|
||||
>
|
||||
<Content />
|
||||
</BlogLayout>
|
||||
64
src/pages/blog/index.astro
Normal file
64
src/pages/blog/index.astro
Normal file
@@ -0,0 +1,64 @@
|
||||
---
|
||||
import Layout from "../../layouts/Layout.astro";
|
||||
import { getCollection } from "astro:content";
|
||||
import { Image } from "astro:assets";
|
||||
import TagBadge from "../../components/TagBadge.astro";
|
||||
import { ChevronLeft } from "@lucide/astro";
|
||||
import BlogCard from "../../components/BlogCard.astro";
|
||||
|
||||
const blogPosts = await getCollection("blog");
|
||||
|
||||
// Sort by publish date, most recent first
|
||||
const sortedPosts = blogPosts.sort(
|
||||
(a, b) => b.data.publishDate.getTime() - a.data.publishDate.getTime(),
|
||||
);
|
||||
|
||||
function formatDate(date: Date) {
|
||||
return date.toLocaleDateString("en-US", {
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
});
|
||||
}
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="Blog - Another Hadi"
|
||||
description="Read my latest blog posts and articles about cybersecurity, OSINT and technology."
|
||||
>
|
||||
<main class="max-w-6xl mx-auto px-4 py-20">
|
||||
<!-- Header -->
|
||||
<div class="text-center mb-16">
|
||||
<h1 class="text-5xl font-bold mb-4">Blog</h1>
|
||||
<p class="text-xl text-base-content/70">
|
||||
Thoughts, insights, and tutorials on cybersecurity, OSINT, and
|
||||
technology.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Back to Home -->
|
||||
<div class="mb-8">
|
||||
<a href="/" class="btn btn-ghost btn-sm">
|
||||
<ChevronLeft size={18} />
|
||||
Back to Home
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Blog Posts Grid -->
|
||||
{
|
||||
sortedPosts.length === 0 ? (
|
||||
<div class="text-center py-20">
|
||||
<p class="text-2xl text-base-content/60">
|
||||
No blog posts yet. Check back soon!
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
{sortedPosts.map((post) => (
|
||||
<BlogCard post={post} />
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</main>
|
||||
</Layout>
|
||||
27
src/pages/index.astro
Normal file
27
src/pages/index.astro
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
import Hero from "../components/Hero.astro";
|
||||
import Projects from "../components/Projects.astro";
|
||||
import Blog from "../components/Blog.astro";
|
||||
import Contact from "../components/Contact.astro";
|
||||
import { siteConfig } from "../config";
|
||||
import avatar from "../../public/avatar.jpg";
|
||||
---
|
||||
|
||||
<Layout title={`Another Hadi`} description={siteConfig.description}>
|
||||
<main>
|
||||
<Hero
|
||||
name={siteConfig.name}
|
||||
title={siteConfig.title}
|
||||
description={siteConfig.description}
|
||||
avatar={avatar}
|
||||
location={siteConfig.location}
|
||||
socialLinks={siteConfig.socialLinks}
|
||||
gpgKey={siteConfig.gpgKey}
|
||||
/>
|
||||
|
||||
<Blog />
|
||||
<Projects />
|
||||
<Contact />
|
||||
</main>
|
||||
</Layout>
|
||||
28
src/pages/projects/[...slug].astro
Normal file
28
src/pages/projects/[...slug].astro
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
import { getCollection, render } from "astro:content";
|
||||
import ProjectLayout from "../../layouts/ProjectLayout.astro";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const projectEntries = await getCollection("projects");
|
||||
|
||||
return projectEntries.map((entry) => ({
|
||||
params: { slug: entry.id },
|
||||
props: { entry },
|
||||
}));
|
||||
}
|
||||
|
||||
const { entry } = Astro.props;
|
||||
const { Content } = await render(entry);
|
||||
---
|
||||
|
||||
<ProjectLayout
|
||||
title={entry.data.title}
|
||||
description={entry.data.description}
|
||||
image={entry.data.image}
|
||||
tags={entry.data.tags}
|
||||
demoLink={entry.data.demoLink}
|
||||
url={entry.data.url}
|
||||
sourceLink={entry.data.sourceLink}
|
||||
>
|
||||
<Content />
|
||||
</ProjectLayout>
|
||||
62
src/pages/projects/index.astro
Normal file
62
src/pages/projects/index.astro
Normal file
@@ -0,0 +1,62 @@
|
||||
---
|
||||
import Layout from "../../layouts/Layout.astro";
|
||||
import { getCollection } from "astro:content";
|
||||
import ProjectCard from "../../components/ProjectCard.astro";
|
||||
import { ChevronLeft } from "@lucide/astro";
|
||||
import { ArrowRight } from "lucide-astro";
|
||||
|
||||
const projects = await getCollection("projects");
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="Projects - Another Hadi"
|
||||
description="Explore my latest projects and work"
|
||||
>
|
||||
<main class="max-w-6xl mx-auto px-4 py-20">
|
||||
<!-- Header -->
|
||||
<div class="text-center mb-16">
|
||||
<h1 class="text-5xl font-bold mb-4">Projects</h1>
|
||||
<p class="text-xl text-base-content/70">
|
||||
I enjoy the challenge of reimagining existing programs & scripts in my
|
||||
own unique way. By creating these projects from scratch, I can ensure
|
||||
complete control over every aspect of their design and functionality.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Back to Home -->
|
||||
<div class="mb-8">
|
||||
<a href="/" class="btn btn-ghost btn-sm">
|
||||
<ChevronLeft size={18} />
|
||||
Back to Home
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Projects Grid -->
|
||||
{
|
||||
projects.length === 0 ? (
|
||||
<div class="text-center py-20">
|
||||
<p class="text-2xl text-base-content/60">
|
||||
No projects yet. Check back soon!
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
{projects.map((project) => (
|
||||
<ProjectCard project={project} />
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
<div class="text-center mt-12">
|
||||
<a
|
||||
href="https://github.com/anotherhadi"
|
||||
target="_blank"
|
||||
class="btn btn-ghost gap-2"
|
||||
>
|
||||
View All Projects
|
||||
<ArrowRight class="size-4" />
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
Reference in New Issue
Block a user