Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,11 @@ next-env.d.ts
# Firebase debug files
firebase-debug.log
firebase-debug.*.logpackage-lock.json

# Migration tool generated files
scripts/migration/discovered-references.json
scripts/migration/unique-cloudinary-urls.json
scripts/migration/asset-mapping.json
scripts/migration/migration-report.json
scripts/migration/node_modules/
scripts/migration/.env
2 changes: 1 addition & 1 deletion app/(main)/(course)/courses/rss.xml/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export async function GET() {
});
return new Response(feed.rss2(), {
headers: {
"content-type": "text/xml",
"content-type": "application/rss+xml; charset=utf-8",
"cache-control": "max-age=0, s-maxage=3600",
},
});
Expand Down
11 changes: 4 additions & 7 deletions app/(main)/(podcast)/podcasts/rss.xml/route.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
export const dynamic = "force-dynamic"; // defaults to auto

import { buildFeed } from "@/lib/rss";
import { ContentType } from "@/lib/types";
import { buildPodcastFeed } from "@/lib/rss";

export async function GET() {
const feed = await buildFeed({
type: ContentType.podcast,
});
return new Response(feed.rss2(), {
const xml = await buildPodcastFeed({});
return new Response(xml, {
headers: {
"content-type": "text/xml",
"content-type": "application/rss+xml; charset=utf-8",
"cache-control": "max-age=0, s-maxage=3600",
},
});
Expand Down
2 changes: 1 addition & 1 deletion app/(main)/(post)/blog/rss.xml/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export async function GET() {
});
return new Response(feed.rss2(), {
headers: {
"content-type": "text/xml",
"content-type": "application/rss+xml; charset=utf-8",
"cache-control": "max-age=0, s-maxage=3600",
},
});
Expand Down
4 changes: 2 additions & 2 deletions app/(main)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import * as demo from "@/sanity/lib/demo";
import { sanityFetch } from "@/sanity/lib/live";
import { settingsQuery } from "@/sanity/lib/queries";
import { cn } from "@/lib/utils";
import { resolveOpenGraphImage } from "@/sanity/lib/utils";
import { ThemeProvider } from "@/components/theme-provider";
import Link from "next/link";
import { Button } from "@/components/ui/button";
Expand Down Expand Up @@ -56,8 +57,7 @@ export async function generateMetadata(): Promise<Metadata> {
const title = settings?.title || demo.title;
const description = settings?.description || demo.description;

// const ogImage = resolveOpenGraphImage(settings?.ogImage);
const ogImage = settings?.ogImage?.secure_url;
const ogImage = resolveOpenGraphImage(settings?.ogImage);
return {
title: {
template: `%s | ${title}`,
Expand Down
13 changes: 8 additions & 5 deletions app/api/devto/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { podcastQuery, postQuery } from "@/sanity/lib/queries";
import { isValidSignature, SIGNATURE_HEADER_NAME } from "@sanity/webhook";
import toMarkdown from "@sanity/block-content-to-markdown";
import { createClient } from "next-sanity";
import { urlForImage } from "@/sanity/lib/utils";

const secret = process.env.PRIVATE_SYNDICATE_WEBOOK_SECRET;
import { apiVersion, dataset, projectId, studioUrl } from "@/sanity/lib/api";
Expand Down Expand Up @@ -81,10 +82,7 @@ const formatPodcast = async (_type: string, slug: string) => {
title: podcast.title,
published: true,
tags: ["webdev", "javascript", "beginners"],
main_image: podcast?.coverImage?.secure_url?.replace(
"upload/",
"upload/b_rgb:5e1186,c_pad,w_1000,h_420/",
),
main_image: urlForImage(podcast?.coverImage)?.width(1000).height(420).url() || "",
canonical_url: `https://codingcat.dev/${podcast._type}/${podcast.slug}`,
description: podcast?.excerpt || "",
organization_id: "1009",
Expand Down Expand Up @@ -239,7 +237,12 @@ const serializers = {
types: {
code: (props: any) =>
"```" + props?.node?.language + "\n" + props?.node?.code + "\n```",
"cloudinary.asset": (props: any) => `![](${props?.node?.secure_url})`,
image: (props: any) => {
const url = props?.node?.asset?._ref
? urlForImage(props.node)?.url()
: "";
return `![](${url})`;
},
codepen: (props: any) => `{% codepen ${props?.node?.url} %}`,
codesandbox: (props: any) =>
`{% codesandbox ${props?.node?.url?.split("https://codesandbox.io/p/sandbox/")?.at(-1)} %}`,
Expand Down
10 changes: 8 additions & 2 deletions app/api/hashnode/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { podcastQuery, postQuery } from "@/sanity/lib/queries";
import { isValidSignature, SIGNATURE_HEADER_NAME } from "@sanity/webhook";
import toMarkdown from "@sanity/block-content-to-markdown";
import { createClient } from "next-sanity";
import { urlForImage } from "@/sanity/lib/utils";
import { apiVersion, dataset, projectId, studioUrl } from "@/sanity/lib/api";

const secret = process.env.PRIVATE_SYNDICATE_WEBOOK_SECRET;
Expand Down Expand Up @@ -110,7 +111,7 @@ const formatPodcast = async (_type: string, slug: string) => {
},
],
coverImageOptions: {
coverImageURL: podcast?.coverImage?.secure_url,
coverImageURL: urlForImage(podcast?.coverImage)?.width(1600).height(840).url() || "",
},
originalArticleURL: `https://codingcat.dev/${podcast._type}/${podcast.slug}`,
contentMarkdown: `
Expand Down Expand Up @@ -344,7 +345,12 @@ const serializers = {
types: {
code: (props: any) =>
"```" + props?.node?.language + "\n" + props?.node?.code + "\n```",
"cloudinary.asset": (props: any) => `![](${props?.node?.secure_url})`,
image: (props: any) => {
const url = props?.node?.asset?._ref
? urlForImage(props.node)?.url()
: "";
return `![](${url})`;
},
codepen: (props: any) => `{% codepen ${props?.node?.url} %}`,
codesandbox: (props: any) =>
`{% codesandbox ${props?.node?.url?.split("https://codesandbox.io/p/sandbox/")?.at(-1)} %}`,
Expand Down
5 changes: 2 additions & 3 deletions app/api/youtube/rss.xml/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ export async function GET() {
updated: new Date(),
generator: "Next.js using Feed for Node.js",
feedLinks: {
json: `${process.env.NEXT_PUBLIC_BASE_URL}/api/podcast-feed`,
atom: `${process.env.NEXT_PUBLIC_BASE_URL}/api/podcast-feed?format=atom`,
rss2: `${process.env.NEXT_PUBLIC_BASE_URL || "https://codingcat.dev"}/api/youtube/rss.xml`,
},
});

Expand Down Expand Up @@ -93,7 +92,7 @@ export async function GET() {

return new Response(feed.rss2(), {
headers: {
"content-type": "text/xml",
"content-type": "application/rss+xml; charset=utf-8",
"cache-control": "max-age=0, s-maxage=3600",
},
});
Expand Down
107 changes: 44 additions & 63 deletions components/avatar.tsx
Original file line number Diff line number Diff line change
@@ -1,74 +1,55 @@
"use client";

import { CldImage } from "next-cloudinary";
import Image from "next/image";
import type { Author } from "@/sanity/types";
import Link from "next/link";
import { stegaClean } from "@sanity/client/stega";
import { urlForImage } from "@/sanity/lib/image";

interface Props {
name?: string;
href?: string;
coverImage: Exclude<Author["coverImage"], undefined> | undefined;
imgSize?: string;
width?: number;
height?: number;
name?: string;
href?: string;
coverImage: Exclude<Author["coverImage"], undefined> | undefined;
imgSize?: string;
width?: number;
height?: number;
}

export default function Avatar({
name,
href,
coverImage,
imgSize,
width,
height,
name,
href,
coverImage,
imgSize,
width,
height,
}: Props) {
const source = stegaClean(coverImage);
if (!href && source?.public_id) {
return (
<div className={`${imgSize ? imgSize : "w-12 h-12 mr-4"}`}>
<CldImage
className="w-full h-auto aspect-square rounded-md object-cover"
width={width || 48}
height={height || 48}
alt={source?.context?.custom?.alt || ""}
src={source.public_id}
config={{
url: {
secureDistribution: "media.codingcat.dev",
privateCdn: true,
},
}}
/>
</div>
);
}
if (href && source?.public_id) {
return (
<Link className="flex items-center text-xl" href={href}>
{source?.public_id && (
<div className={`${imgSize ? imgSize : "w-12 h-12 mr-4"}`}>
<CldImage
className="w-full h-auto aspect-square rounded-md object-cover"
width={width || 48}
height={height || 48}
alt={source?.context?.custom?.alt || ""}
src={source.public_id}
config={{
url: {
secureDistribution: "media.codingcat.dev",
privateCdn: true,
},
}}
/>
</div>
)}
{name && (
<div className="text-xl font-bold text-pretty hover:underline">
{name}
</div>
)}
</Link>
);
}
return <></>;
const imageUrl = coverImage?.asset?._ref
? urlForImage(coverImage)?.width(width || 48).height(height || 48).url()
: null;

if (!imageUrl) return <></>;

const imageElement = (
<div className={`${imgSize ? imgSize : "w-12 h-12 mr-4"}`}>
<Image
className="w-full h-auto aspect-square rounded-md object-cover"
width={width || 48}
height={height || 48}
alt={coverImage?.alt || ""}
src={imageUrl}
/>
</div>
);

if (!href) return imageElement;

return (
<Link className="flex items-center text-xl" href={href}>
{imageElement}
{name && (
<div className="text-xl font-bold text-pretty hover:underline">
{name}
</div>
)}
</Link>
);
}
73 changes: 28 additions & 45 deletions components/block-image.tsx
Original file line number Diff line number Diff line change
@@ -1,52 +1,35 @@
import type { CloudinaryAsset } from "@/sanity/types";
import CloudinaryImage from "@/components/cloudinary-image";
import Image from "next/image";
import { urlForImage } from "@/sanity/lib/image";

import { getCldImageUrl } from "next-cloudinary";

interface CoverImageProps {
image: CloudinaryAsset;
interface BlockImageProps {
image: any;
}

export default async function BlockImage(props: CoverImageProps) {
const { image: originalImage } = props;
export default function BlockImage(props: BlockImageProps) {
const { image } = props;

let image;
if (originalImage?.public_id) {
const imageUrl = getCldImageUrl({
src: originalImage.public_id,
width: 100,
});
const response = await fetch(imageUrl);
const arrayBuffer = await response.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
const base64 = buffer.toString("base64");
const dataUrl = `data:${response.type};base64,${base64}`;
const imageUrl = image?.asset?._ref
? urlForImage(image)?.width(1920).height(1080).url()
: null;

image = (
<CloudinaryImage
className="w-full h-auto"
width={1920}
height={1080}
sizes="100vw"
alt={originalImage?.context?.custom?.alt || ""}
src={originalImage?.public_id}
placeholder="blur"
blurDataURL={dataUrl}
config={{
url: {
secureDistribution: "media.codingcat.dev",
privateCdn: true,
},
}}
/>
);
} else {
image = <div className="bg-slate-50" style={{ paddingTop: "50%" }} />;
}
if (!imageUrl) {
return (
<div className="shadow-md transition-shadow duration-200 group-hover:shadow-lg sm:mx-0">
<div className="bg-slate-50" style={{ paddingTop: "50%" }} />
</div>
);
}

return (
<div className="shadow-md transition-shadow duration-200 group-hover:shadow-lg sm:mx-0">
{image}
</div>
);
return (
<div className="shadow-md transition-shadow duration-200 group-hover:shadow-lg sm:mx-0">
<Image
className="w-full h-auto"
width={1920}
height={1080}
sizes="100vw"
alt={image?.alt || ""}
src={imageUrl}
/>
</div>
);
}
25 changes: 0 additions & 25 deletions components/cloudinary-image.tsx

This file was deleted.

13 changes: 0 additions & 13 deletions components/cloudinary-video.tsx

This file was deleted.

Loading
Loading