Skip to content

Commit

Permalink
add icons stored in app directory in nextjs projects
Browse files Browse the repository at this point in the history
  • Loading branch information
xavimondev committed Jul 17, 2024
1 parent 10b4f83 commit 844f8f5
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 25 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# seo-ai

## 0.3.0

### Minor Changes

- add favicon stored in app directory when working with nextjs projects

## 0.2.1

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "seo-ai",
"version": "0.2.1",
"version": "0.3.0",
"description": "Command-line tool to generate SEO metadata and HTML meta tags using AI models",
"type": "module",
"license": "MIT",
Expand Down
8 changes: 5 additions & 3 deletions src/commands/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ export const generate = new Command()

// Asking LLM to generate a list of files that are essential for the SEO.
const SUGGESTED_PATHS: string[] = []
if (files.length > 15) {
if (files.length > 20) {
const projectKeyFiles = await generateKeyProjectFiles({
files: files.join('\n'),
model
Expand Down Expand Up @@ -233,7 +233,7 @@ export const generate = new Command()
apiKey: replicateKey
})

if (isMetadata) {
if (isMetadata && icons) {
SEO_METADATA = {
...SEO_METADATA,
icons: icons as Icon
Expand Down Expand Up @@ -270,7 +270,7 @@ export const generate = new Command()
}
}

s.stop('SEO generated!')
s.stop('SEO generated')

if (!isMetadata) {
logger.break()
Expand All @@ -279,6 +279,8 @@ export const generate = new Command()
return
}

if (seoTags.length === 1 && seoTags.at(0) === 'icons') return

// It's a Next.js project, so prompt the user to enter file's path where they want to add the metadata
const filePathEntered = await text({
message: `Where would you like to add the metadata object?`,
Expand Down
61 changes: 40 additions & 21 deletions src/utils/ai.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { existsSync, mkdirSync } from 'node:fs'
import path from 'node:path'
import { Readable } from 'node:stream'
import { writeFile } from 'node:fs/promises'
import { type ReadableStream } from 'node:stream/web'
import { generateObject, generateText, type LanguageModel } from 'ai'
import { z } from 'zod'
import { DEFAULT_SEO_SCHEMA, SEO_TAGS } from '@/constants.js'
import { generateIcon } from '@/utils/replicate.js'
import { writeImage } from '@/utils/writeImage.js'

export const generateProjectDescription = async ({
model,
Expand Down Expand Up @@ -119,28 +117,31 @@ export const generateIcons = async ({
apiKey
})

const cwd = path.resolve(process.cwd())
const seoDirectory = `public/seo/icons`
const publicDirectory = `${cwd}/${seoDirectory}`
const response = await fetch(iconUrl)

if (!existsSync(publicDirectory)) {
mkdirSync(publicDirectory, {
recursive: true
if (!metadata) {
await saveIconDefaultLocation({ response })

return `<link rel="icon" href="https://example.com/seo/icons/favicon.png" />\n<link rel="apple-touch-icon" href="https://example.com/seo/icons/favicon.png" />\n`
}

const appDirectory = path.join('src/app')
if (existsSync(appDirectory)) {
await writeImage({
response,
nameFile: 'favicon.png',
pathFile: appDirectory
})

return null
}

const response = await fetch(iconUrl)
const body = Readable.fromWeb(response.body as ReadableStream<any>)
const fileIconPath = path.join(publicDirectory, 'favicon.png')
await writeFile(fileIconPath, body)

if (metadata) {
return {
icon: '/seo/icons/favicon.png',
apple: '/seo/icons/favicon.png'
}
await saveIconDefaultLocation({ response })

return {
icon: '/seo/icons/favicon.png',
apple: '/seo/icons/favicon.png'
}
return `<link rel="icon" href="https://example.com/seo/icons/icon.png" />\n<link rel="apple-touch-icon" href="https://example.com/seo/icons/icon.png" />\n`
}

export const generateKeyProjectFiles = async ({
Expand All @@ -153,7 +154,7 @@ export const generateKeyProjectFiles = async ({
const result = await generateObject({
model,
schema: z.object({ paths: z.array(z.string()) }),
prompt: `You are a codebase analysis expert. Your task is to examine the provided list of directories and files, and identify the 10 most crucial files
prompt: `You are a codebase analysis expert. Your task is to examine the provided list of directories and files, and identify the 20 most crucial files
necessary for generating SEO meta tags.
Here is the list of directories and files:
${files}
Expand All @@ -163,3 +164,21 @@ Please ensure your selection focuses on the following meta tags: ${SEO_TAGS.join

return result.object.paths
}

const saveIconDefaultLocation = async ({ response }: { response: Response }) => {
const cwd = path.resolve(process.cwd())
const seoDirectory = `public/seo/icons`
const publicDirectory = `${cwd}/${seoDirectory}`

if (!existsSync(publicDirectory)) {
mkdirSync(publicDirectory, {
recursive: true
})
}

await writeImage({
response,
nameFile: 'favicon.png',
pathFile: publicDirectory
})
}
18 changes: 18 additions & 0 deletions src/utils/writeImage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { writeFile } from 'node:fs/promises'
import path from 'node:path'
import { Readable } from 'node:stream'
import { type ReadableStream } from 'node:stream/web'

export const writeImage = async ({
response,
nameFile,
pathFile
}: {
response: Response
nameFile: string
pathFile: string
}) => {
const body = Readable.fromWeb(response.body as ReadableStream<any>)
const fileIconPath = path.join(pathFile, nameFile)
await writeFile(fileIconPath, body)
}

0 comments on commit 844f8f5

Please sign in to comment.