Skip to content

Commit

Permalink
Merge pull request #44 from suryanshsingh2001/blog-section
Browse files Browse the repository at this point in the history
[Feature Request] Blogs Section
  • Loading branch information
suryanshsingh2001 authored Nov 2, 2024
2 parents bb77227 + 3746472 commit 6a3d7b8
Show file tree
Hide file tree
Showing 19 changed files with 1,970 additions and 176 deletions.
134 changes: 134 additions & 0 deletions app/blogs/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import { siteConfig } from "@/config/config";
import { getPost } from "@/lib/blog";
import { formatDate, calculateReadTime } from "@/lib/utils";
import type { Metadata } from "next";
import { notFound } from "next/navigation";
import { Suspense } from "react";
import { Clock, Calendar, ArrowLeft } from "lucide-react";
import Image from "next/image";
import { Button } from "@/components/ui/button";
import Link from "next/link";
import { Avatar, AvatarImage } from "@/components/ui/avatar";



export async function generateMetadata({
params,
}: {
params: {
slug: string;
};
}): Promise<Metadata | undefined> {
const post = await getPost(params.slug);

const {
title,
publishedAt: publishedTime,
summary: description,
image,
} = post.metadata;

return {
title,
description,
openGraph: {
title,
description,
type: "article",
publishedTime,
url: `${siteConfig.url}/blog/${post.slug}`,
images: [
{
url: siteConfig.ogImage,
},
],
},
twitter: {
card: "summary_large_image",
title,
description,
images: [siteConfig.ogImage],
},
};
}

export default async function Blog({
params,
}: {
params: {
slug: string;
};
}) {
const post = await getPost(params.slug);




if (!post) {
notFound();
}

const readTime = calculateReadTime(post.source);

return (
<div className="min-h-screen py-12 px-4 sm:px-6 lg:px-8">
<article className="max-w-4xl mx-auto">
<div className="mb-8">

<Link href={"/"}>

<Button variant="ghost" className="flex items-center text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white">
<ArrowLeft className="mr-2 h-4 w-4" />
Go Back
</Button>
</Link>
</div>

<div className="relative h-96 w-full mb-8">
<Image
src={post.metadata.image}
alt={post.metadata.title}
layout="fill"
objectFit="cover"
className="rounded-lg"
/>
</div>

<header className="mb-8">
<h1 className="text-4xl font-extrabold tracking-tight text-gray-900 dark:text-white sm:text-5xl mb-4">
{post.metadata.title}
</h1>

<div className="flex items-center justify-between flex-wrap gap-4">
<div className="flex items-center space-x-4">
<Avatar>
<AvatarImage src={siteConfig.authorImage} alt={siteConfig.author} />
</Avatar>
<div>
<p className="text-sm font-medium text-gray-900 dark:text-white">{siteConfig.author}</p>
<p className="text-sm text-gray-500 dark:text-gray-400">{"Owner and Maintainer"}</p>
</div>
</div>

<div className="flex items-center space-x-4 text-sm text-gray-500 dark:text-gray-400">
<div className="flex items-center space-x-2">
<Calendar className="w-4 h-4" />
<time dateTime={post.metadata.publishedAt}>
{formatDate(post.metadata.publishedAt)}
</time>
</div>
<div className="flex items-center space-x-2">
<Clock className="w-4 h-4" />
<span>{readTime} min read</span>
</div>
</div>
</div>
</header>

<div className="prose dark:prose-invert max-w-none">
<div dangerouslySetInnerHTML={{ __html: post.source }} />
</div>
</article>
</div>
);
}
15 changes: 15 additions & 0 deletions app/blogs/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import LandingHeader from "@/components/layout/LandingHeader";



interface RootLayoutProps {
children: React.ReactNode;
}

export default function RootLayout({ children }: RootLayoutProps) {
return (
<>
{children}
</>
);
}
63 changes: 63 additions & 0 deletions app/blogs/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { getBlogPosts } from "@/lib/blog";
import { formatDate } from "@/lib/utils";
import Image from "next/image";
import Link from "next/link";
import { ArrowRight } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";

export const metadata = {
title: "Blog",
description: "My thoughts on software development, life, and more.",
};

export default async function BlogPage() {
const posts = await getBlogPosts();

return (
<section className="min-h-screen py-12 px-4 sm:px-6 lg:px-8">
<div className="max-w-2xl mx-auto">
<h1 className="text-3xl font-semibold text-gray-900 dark:text-white mb-2">
Mockly Blog
</h1>
<p className="text-xl text-gray-600 dark:text-gray-300 mb-12">
Blogs about Mockly and more.
</p>

<div className="space-y-12">
{posts
.sort(
(a, b) =>
new Date(b.metadata.publishedAt).getTime() -
new Date(a.metadata.publishedAt).getTime()
)
.map((post) => (
<article
key={post.slug}
className="border-b border-gray-200 dark:border-gray-700 pb-8 last:border-b-0"
>
<Link href={`/blogs/${post.slug}`}>
<Image
src={post.metadata.image}
alt={post.metadata.title}
width={800}
height={400}
className="rounded-lg w-full h-48 object-cover mb-4"
/>
<h2 className="text-xl font-medium text-gray-900 dark:text-white mb-2">
{post.metadata.title}
</h2>
<p className="text-base text-gray-600 dark:text-gray-300 mb-2">
{post.metadata.summary}
</p>
<time className="text-sm text-gray-500 dark:text-gray-400">
{formatDate(post.metadata.publishedAt)}
</time>
</Link>
</article>
))}
</div>
</div>
</section>
);
}
20 changes: 20 additions & 0 deletions app/editor/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,26 @@ import EditorNotAvailable from "@/components/shared/NotAvailable"
import MockupEditor from "@/components/shared/Editor.v2"
import { siteConfig } from "@/config/config"




export async function generateMetadata() {
return {
title: "Editor",
description: "Design and customize mockups for your projects.",
openGraph: {
title: "Mockly Editor",
description: "Design and customize mockups for your projects.",
type: "website",
images: [
{
url: siteConfig.ogImage,
},
],
},
}
}

export default function EditorPage() {
return siteConfig.isEditorActive ? <MockupEditor /> : <EditorNotAvailable />
}
33 changes: 33 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,37 @@ html {
}
}

h3 code {
@apply !text-lg md:!text-xl;
}

pre {
@apply !px-0 rounded-lg overflow-x-auto py-4
}

pre [data-line] {
@apply px-4
}

code {
@apply text-sm md:text-base !leading-loose;
}

pre > code {
counter-reset: line;
}

code[data-theme*=" "],
code[data-theme*=" "] span {
color: var(--shiki-light);
background-color: var(--shiki-light-bg);
}

@media (prefers-color-scheme: dark) {
code[data-theme*=" "],
code[data-theme*=" "] span {
color: var(--shiki-dark);
background-color: var(--shiki-dark-bg);
}
}

8 changes: 4 additions & 4 deletions components/layout/LandingHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ export default function LandingHeader() {

<Link
className="text-sm font-medium hover:text-primary transition-colors"
href="#pricing"
href="/blogs"
>
Pricing
Blogs
</Link>
<Link
href={siteConfig.socialLinks.github}
Expand Down Expand Up @@ -107,10 +107,10 @@ export default function LandingHeader() {

<Link
className="text-sm font-medium hover:text-primary transition-colors"
href="#pricing"
href="/blogs"
onClick={toggleSidebar}
>
Pricing
Blog
</Link>
<Link
href="https://github.com/yourusername/your-repo"
Expand Down
17 changes: 1 addition & 16 deletions components/shared/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,7 @@ import { validateInput } from "./utils";
import { TextManager, type TextStyle } from "../text-manager";
import ExportButton from "./buttons/ExportButton";

const backgroundUrls = [
"https://images.unsplash.com/photo-1557683316-973673baf926?w=1600&h=900&fit=crop",
"https://images.unsplash.com/photo-1560015534-cee980ba7e13?w=1600&h=900&fit=crop",
"https://images.unsplash.com/photo-1501696461415-6bd6660c6742?w=1600&h=900&fit=crop",
"https://images.unsplash.com/photo-1557682250-33bd709cbe85?w=1600&h=900&fit=crop",
"https://images.unsplash.com/photo-1557682224-5b8590cd9ec5?w=1600&h=900&fit=crop",
"https://images.unsplash.com/photo-1557682260-96773eb01377?w=1600&h=900&fit=crop",
"https://images.unsplash.com/photo-1557682268-e3955ed5d83f?w=1600&h=900&fit=crop",
"https://images.unsplash.com/photo-1557683311-eac922347aa1?w=1600&h=900&fit=crop",
];

const screenSizes = [
{ name: "Mobile", width: 375, height: 667 },
{ name: "Tablet", width: 768, height: 1024 },
{ name: "Desktop", width: 1440, height: 900 },
];
import { backgroundUrls, screenSizes } from "@/lib/constants";

const validationError = {
customHeight: "",
Expand Down
50 changes: 50 additions & 0 deletions components/ui/avatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"use client"

import * as React from "react"
import * as AvatarPrimitive from "@radix-ui/react-avatar"

import { cn } from "@/lib/utils"

const Avatar = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
>(({ className, ...props }, ref) => (
<AvatarPrimitive.Root
ref={ref}
className={cn(
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
className
)}
{...props}
/>
))
Avatar.displayName = AvatarPrimitive.Root.displayName

const AvatarImage = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Image>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
>(({ className, ...props }, ref) => (
<AvatarPrimitive.Image
ref={ref}
className={cn("aspect-square h-full w-full", className)}
{...props}
/>
))
AvatarImage.displayName = AvatarPrimitive.Image.displayName

const AvatarFallback = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Fallback>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
>(({ className, ...props }, ref) => (
<AvatarPrimitive.Fallback
ref={ref}
className={cn(
"flex h-full w-full items-center justify-center rounded-full bg-muted",
className
)}
{...props}
/>
))
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName

export { Avatar, AvatarImage, AvatarFallback }
4 changes: 3 additions & 1 deletion config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ export type Config = typeof siteConfig;

export const siteConfig = {
name: "Mockly",
url: "https://mockly.vercel.app",
url: "https://www.mockly.site",
author : "Suryansh Singh",
authorImage : "https://avatars.githubusercontent.com/u/80690023?s=96&v=4",
ogImage: "/icon-512.png",
description:
"Mockly streamlines the process of creating stunning mockups for your projects. No design skills? No problem. Pick your screenshots, customize backgrounds, and add text—all without leaving your browser. Fast, easy, and fully client-side.",
Expand Down
Loading

0 comments on commit 6a3d7b8

Please sign in to comment.