Skip to content

Commit

Permalink
Merge pull request #63 from Derick80/code-64-attempt-to-integrate-mdx…
Browse files Browse the repository at this point in the history
…-compilation-with-a-build-script

Code 64 attempt to integrate mdx compilation with a build script
  • Loading branch information
Derick80 authored Apr 24, 2024
2 parents 8021c50 + f2352f4 commit d4797b8
Show file tree
Hide file tree
Showing 38 changed files with 850 additions and 308 deletions.
182 changes: 178 additions & 4 deletions app/.server/content.server.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { frontmatterType } from '../routes/writing'
import { prisma } from './prisma.server'

import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'
export const getPostInformation = async (slug: string) => {
return await prisma.content.findUnique({
where: {
Expand Down Expand Up @@ -37,21 +40,192 @@ export const likeContent = async ({
}
}
})
if (hasLiked) {
return await prisma.love.delete({
console.log(hasLiked, 'hasLiked')

if (hasLiked !== null) {
const liked = await prisma.love.delete({
where: {
contentId_userId: {
userId,
contentId
}
}
})
return liked
} else {
return await prisma.love.create({
const liked = await prisma.love.create({
data: {
userId,
contentId
}
})
return liked
}
}

type PostModule = { [key: string]: unknown } // Unknown structure for now

export const getAllBlogContent = async (relativePath: string) => {
const posts = import.meta.glob(`../content/blog/*.mdx`)
if (!posts) throw new Error('No posts found')
const keys = Object.keys(posts)

const postData = await Promise.all(
keys.map(async (key) => {
const { frontmatter } = (await posts[key]()) as PostModule
if (frontmatter && typeof frontmatter === 'object') {
// Only process if frontmatter exists and is an object
return {
title: frontmatter.title,
author: frontmatter.author,
description: frontmatter.description,
datePublished: frontmatter.datePublished,
published: frontmatter.published,
categories: frontmatter.categories,

url: key,
slug: key
.replace('../content/blog/', '')
.replace('.mdx', '')
} as Omit<frontmatterType, 'code'>
} else {
// Handle the case where frontmatter is missing or not an object
console.error(
`Error processing post: ${key}. Missing or invalid frontmatter.`
)
return null // Or some placeholder value if needed
}
})
)

return postData
}

export const getPostContent = async (slug: string) => {
const filePath = path.join(__dirname, '../content/blog', `${slug}.mdx`)
const fileContents = fs.readFileSync(filePath, 'utf8')
const { data } = matter(fileContents)
return data
}

// updateDataBaseContent is my most recent function for updating the database with new content

export const updateDataBaseContent = async ({
content
}: {
content: Omit<frontmatterType, 'code'>[]
}) => {
try {
for (const post of content) {
const {
title,
author,
description,
datePublished,
published,
slug,
categories
} = post
await prisma.content.upsert({
where: {
slug
},
update: {
title,
author,
description,
datePublished,
published,
categories
},
create: {
title,
author,
description,
datePublished,
published,
slug,
categories
}
})
}
} catch (err) {
console.error(err)
} finally {
console.log('done')
}
}

export const getandUpdate = async (relativePath: string) => {
const posts = import.meta.glob(`../content/blog/*.mdx`)
if (!posts) throw new Error('No posts found')
const keys = Object.keys(posts)

const postData = await Promise.all(
keys.map(async (key) => {
const { frontmatter } = (await posts[key]()) as PostModule
if (frontmatter && typeof frontmatter === 'object') {
// Only process if frontmatter exists and is an object
return {
title: frontmatter.title,
author: frontmatter.author,
description: frontmatter.description,
datePublished: frontmatter.datePublished,
published: frontmatter.published,
categories: frontmatter.categories,
url: key,
slug: key
.replace('../content/blog/', '')
.replace('.mdx', '')
}
} else {
// Handle the case where frontmatter is missing or not an object
console.error(
`Error processing post: ${key}. Missing or invalid frontmatter.`
)
return null // Or some placeholder value if needed
}
})
)
if (!postData || postData === null) throw new Error('No posts found')

try {
for (const post of postData) {
const {
title,
author,
description,
datePublished,
published,
slug,
categories
} = post
await prisma.content.upsert({
where: {
slug
},
update: {
title,
author,
description,
datePublished,
published,
categories
},
create: {
title,
author,
description,
datePublished,
published,
slug,
categories
}
})
}
} catch (err) {
console.error(err)
} finally {
console.log('done')
}
}
2 changes: 0 additions & 2 deletions app/.server/mdx-compile.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ function markdown(markdown: string): RenderableTreeNodes {

export { markdown }



function isString(value: any): value is string {
return typeof value === 'string'
}
Expand Down
1 change: 0 additions & 1 deletion app/.server/project.server.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { prisma } from './prisma.server'
import { Prisma } from '@prisma/client'
const getAllProjects = async () => {
return await prisma.project.findMany({
include: {
Expand Down
30 changes: 30 additions & 0 deletions app/.server/update-content.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { frontmatterType } from '../routes/writing'
import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'

// I am using this in my prebuild script to get all the content from the blog folder and update the database
// I want to create a github action that will run this script and update the database with the content from the blog folder

export const getAllPostContent = () => {
const postsDirectory = path.join(process.cwd(), 'app/content/blog/')
const fileNames = fs.readdirSync(postsDirectory)

if (!fileNames.length) throw new Error('No posts found')

const posts = fileNames.map((fileName) => {
const filePath = path.join(postsDirectory, fileName)
const fileContents = fs.readFileSync(filePath, 'utf8')
// @ts-ignore
const { data } = matter<frontmatterType>(fileContents)
// add slug to data object
data.slug = fileName.replace('.mdx', '')
// return datePublished as a string AND REMOVE everything after and including the 'T'

return data
})

// console.log(posts, 'data from getAllPostContent');

return posts
}
11 changes: 9 additions & 2 deletions app/.server/user.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,15 @@ export const getUser = async (input: Prisma.UserWhereUniqueInput) => {
}

export const getUsers = async () => {
const users = await prisma.user.findFirst({
select: defaultSelect
const users = await prisma.user.findMany({
select: {
id: true,
email: true,
username: true,
avatarUrl: true,
role: true,
userImages: true
}
})

return users
Expand Down
106 changes: 106 additions & 0 deletions app/components/editable-text.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import React from 'react'
import { Input } from './ui/input'
import { Textarea } from './ui/textarea'
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger
} from './ui/tooltip'
import clsx from 'clsx'
import { Pencil1Icon } from '@radix-ui/react-icons'

type EditableTextFieldProps = {
initialValue?: string
onUpdate?: (value: string) => void
updateInitialValue?: (value: string) => void
className?: string
label?: string
}

const EditableTextField = ({
initialValue,
onUpdate,
updateInitialValue,
className,
label
}: EditableTextFieldProps) => {
const [value, setValue] = React.useState(initialValue)
const [isEditing, setIsEditing] = React.useState(false)

React.useEffect(() => {
setValue(initialValue)
}, [initialValue])

const handleInputChange = (
event: React.ChangeEvent<HTMLTextAreaElement>
) => {
setValue(event.target.value)
updateInitialValue && updateInitialValue(event.target.value)
}

const handleKeyPress = (
event: React.KeyboardEvent<HTMLTextAreaElement>
) => {
if (event.key === 'Enter') {
setIsEditing(false)
onUpdate && value && onUpdate(value)
setValue(event.currentTarget.value) // Call the onUpdate function if it exists
}
}

const handleDoubleClick = () => {
setIsEditing(true)
}

return (
<>
{isEditing ? (
<Textarea
value={value}
onChange={handleInputChange}
onKeyDown={handleKeyPress}
onBlur={() => setIsEditing(false)}
autoFocus
className={clsx(
'mt-1 h-12 w-full cursor-text transition-opacity duration-1000 ease-in-out focus:z-50 focus:border-blue-500',
'scale-100 opacity-100' // Ensure full opacity and scale when editing
)}
/>
) : (
<div className='flex w-full justify-between pl-1 pr-1'>
{label && ( // Conditionally render label if provided
<div className='mr-2 text-sm font-medium text-gray-700'>
{label}
</div>
)}
<Tooltip>
<TooltipTrigger className='w-full'>
<div
onClick={handleDoubleClick}
className={clsx(
'flex w-full cursor-text items-center justify-between',
'transition-opacity duration-300 ease-in-out',
{
'opacity-100': !isEditing,
'scale-95 opacity-0': isEditing // Apply scale and opacity transition when editing
}
)}
>
<span>{value ? value : 'Click to edit'}</span>
<Pencil1Icon className='h-4 w-4 text-gray-500' />
</div>
<TooltipContent>
<span className='text-sm text-gray-500'>
Click to edit
</span>
</TooltipContent>
</TooltipTrigger>
</Tooltip>
</div>
)}
</>
)
}

export default EditableTextField
Loading

0 comments on commit d4797b8

Please sign in to comment.