-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
28c809f
commit 028bd3c
Showing
27 changed files
with
2,387 additions
and
7 deletions.
There are no files selected for viewing
118 changes: 118 additions & 0 deletions
118
apps/ai-hero/src/app/(content)/lists/[slug]/edit/_components/edit-list-form-metadata.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
import * as React from 'react' | ||
import { useRouter } from 'next/navigation' | ||
import type { List, ListSchema } from '@/lib/lists' | ||
import type { UseFormReturn } from 'react-hook-form' | ||
import { z } from 'zod' | ||
|
||
import { VideoResource } from '@coursebuilder/core/schemas/video-resource' | ||
import { | ||
Button, | ||
FormDescription, | ||
FormField, | ||
FormItem, | ||
FormLabel, | ||
FormMessage, | ||
Input, | ||
Textarea, | ||
} from '@coursebuilder/ui' | ||
import { useSocket } from '@coursebuilder/ui/hooks/use-socket' | ||
import { MetadataFieldState } from '@coursebuilder/ui/resources-crud/metadata-fields/metadata-field-state' | ||
import { MetadataFieldVisibility } from '@coursebuilder/ui/resources-crud/metadata-fields/metadata-field-visibility' | ||
import AdvancedTagSelector from '@coursebuilder/ui/resources-crud/tag-selector' | ||
|
||
export const ListMetadataFormFields: React.FC<{ | ||
form: UseFormReturn<z.infer<typeof ListSchema>> | ||
list: List | ||
}> = ({ form, list }) => { | ||
const router = useRouter() | ||
|
||
return ( | ||
<> | ||
<FormField | ||
control={form.control} | ||
name="id" | ||
render={({ field }) => <Input type="hidden" {...field} />} | ||
/> | ||
|
||
<FormField | ||
control={form.control} | ||
name="fields.title" | ||
render={({ field }) => ( | ||
<FormItem className="px-5"> | ||
<FormLabel className="text-lg font-bold">Title</FormLabel> | ||
<FormDescription> | ||
A title should summarize the post and explain what it is about | ||
clearly. | ||
</FormDescription> | ||
<Input {...field} /> | ||
<FormMessage /> | ||
</FormItem> | ||
)} | ||
/> | ||
<FormField | ||
control={form.control} | ||
name="fields.slug" | ||
render={({ field }) => ( | ||
<FormItem className="px-5"> | ||
<FormLabel className="text-lg font-bold">Slug</FormLabel> | ||
<FormDescription>Short with keywords is best.</FormDescription> | ||
<Input {...field} /> | ||
<FormMessage /> | ||
</FormItem> | ||
)} | ||
/> | ||
<FormField | ||
control={form.control} | ||
name="fields.description" | ||
render={({ field }) => ( | ||
<FormItem className="px-5"> | ||
<FormLabel className="text-lg font-bold"> | ||
SEO Description ({`${field.value?.length ?? '0'} / 160`}) | ||
</FormLabel> | ||
<FormDescription> | ||
A short snippet that summarizes the post in under 160 characters. | ||
Keywords should be included to support SEO. | ||
</FormDescription> | ||
<Textarea {...field} value={field.value ?? ''} /> | ||
{field.value && field.value.length > 160 && ( | ||
<FormMessage> | ||
Your description is longer than 160 characters | ||
</FormMessage> | ||
)} | ||
<FormMessage /> | ||
</FormItem> | ||
)} | ||
/> | ||
<MetadataFieldVisibility form={form} /> | ||
<MetadataFieldState form={form} /> | ||
<FormField | ||
control={form.control} | ||
name="fields.github" | ||
render={({ field }) => ( | ||
<FormItem className="px-5"> | ||
<FormLabel className="text-lg font-bold">GitHub</FormLabel> | ||
<FormDescription> | ||
Direct link to the GitHub file associated with the post. | ||
</FormDescription> | ||
<Input {...field} value={field.value ?? ''} /> | ||
<FormMessage /> | ||
</FormItem> | ||
)} | ||
/> | ||
<FormField | ||
control={form.control} | ||
name="fields.gitpod" | ||
render={({ field }) => ( | ||
<FormItem className="px-5"> | ||
<FormLabel className="text-lg font-bold">Gitpod</FormLabel> | ||
<FormDescription> | ||
Gitpod link to start a new workspace with the post. | ||
</FormDescription> | ||
<Input {...field} value={field.value ?? ''} /> | ||
<FormMessage /> | ||
</FormItem> | ||
)} | ||
/> | ||
</> | ||
) | ||
} |
104 changes: 104 additions & 0 deletions
104
apps/ai-hero/src/app/(content)/lists/[slug]/edit/_components/edit-list-form.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
'use client' | ||
|
||
import * as React from 'react' | ||
import { PostMetadataFormFields } from '@/app/(content)/posts/_components/edit-post-form-metadata' | ||
import { ImageResourceUploader } from '@/components/image-uploader/image-resource-uploader' | ||
import { env } from '@/env.mjs' | ||
import { useIsMobile } from '@/hooks/use-is-mobile' | ||
import { sendResourceChatMessage } from '@/lib/ai-chat-query' | ||
import { List, ListSchema } from '@/lib/lists' | ||
import { Post, PostSchema } from '@/lib/posts' | ||
import { autoUpdatePost, updatePost } from '@/lib/posts-query' | ||
import type { Tag } from '@/lib/tags' | ||
import { zodResolver } from '@hookform/resolvers/zod' | ||
import { ImagePlusIcon } from 'lucide-react' | ||
import { useSession } from 'next-auth/react' | ||
import { useTheme } from 'next-themes' | ||
import { useForm, type UseFormReturn } from 'react-hook-form' | ||
import { z } from 'zod' | ||
|
||
import { ContentResourceSchema } from '@coursebuilder/core/schemas' | ||
import { VideoResource } from '@coursebuilder/core/schemas/video-resource' | ||
import { EditResourcesFormDesktop } from '@coursebuilder/ui/resources-crud/edit-resources-form-desktop' | ||
|
||
import { ListMetadataFormFields } from './edit-list-form-metadata' | ||
import ListResoucesEdit from './list-resources-edit' | ||
|
||
// import { MobileEditPostForm } from './edit-post-form-mobile' | ||
|
||
const NewPostFormSchema = z.object({ | ||
title: z.string().min(2).max(90), | ||
body: z.string().nullish(), | ||
visibility: z.enum(['public', 'unlisted', 'private']), | ||
description: z.string().nullish(), | ||
github: z.string().nullish(), | ||
gitpod: z.string().nullish(), | ||
}) | ||
|
||
export type EditListFormProps = { | ||
list: List | ||
form: UseFormReturn<z.infer<typeof ListSchema>> | ||
children?: React.ReactNode | ||
availableWorkflows?: { value: string; label: string; default?: boolean }[] | ||
theme?: string | ||
} | ||
|
||
export function EditListForm({ list }: Omit<EditListFormProps, 'form'>) { | ||
const { forcedTheme: theme } = useTheme() | ||
const session = useSession() | ||
const form = useForm<z.infer<typeof ListSchema>>({ | ||
resolver: zodResolver(NewPostFormSchema), | ||
defaultValues: { | ||
id: list.id, | ||
fields: { | ||
title: list.fields?.title, | ||
body: list.fields?.body, | ||
slug: list.fields?.slug, | ||
visibility: list.fields?.visibility || 'public', | ||
state: list.fields?.state || 'draft', | ||
description: list.fields?.description ?? '', | ||
github: list.fields?.github ?? '', | ||
gitpod: list.fields?.gitpod ?? '', | ||
}, | ||
}, | ||
}) | ||
const isMobile = useIsMobile() | ||
|
||
return ( | ||
<EditResourcesFormDesktop | ||
resource={list} | ||
resourceSchema={ListSchema} | ||
getResourcePath={(slug) => `/${slug}`} | ||
updateResource={updatePost} | ||
autoUpdateResource={autoUpdatePost} | ||
form={form} | ||
bodyPanelSlot={<ListResoucesEdit list={list} />} | ||
availableWorkflows={[]} | ||
sendResourceChatMessage={sendResourceChatMessage} | ||
hostUrl={env.NEXT_PUBLIC_PARTY_KIT_URL} | ||
user={session?.data?.user} | ||
theme={theme} | ||
onResourceBodyChange={() => {}} | ||
tools={[ | ||
{ id: 'assistant' }, | ||
{ | ||
id: 'media', | ||
icon: () => ( | ||
<ImagePlusIcon strokeWidth={1.5} size={24} width={18} height={18} /> | ||
), | ||
toolComponent: ( | ||
<ImageResourceUploader | ||
key={'image-uploader'} | ||
belongsToResourceId={list.id} | ||
uploadDirectory={`posts`} | ||
/> | ||
), | ||
}, | ||
]} | ||
> | ||
<React.Suspense fallback={<div>loading</div>}> | ||
<ListMetadataFormFields form={form} list={list} /> | ||
</React.Suspense> | ||
</EditResourcesFormDesktop> | ||
) | ||
} |
40 changes: 40 additions & 0 deletions
40
apps/ai-hero/src/app/(content)/lists/[slug]/edit/_components/hit.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
'use client' | ||
|
||
import Link from 'next/link' | ||
import { useRouter } from 'next/navigation' | ||
import { addPostToList } from '@/lib/lists-query' | ||
import type { TypesenseResource } from '@/lib/typesense' | ||
|
||
import { Button } from '@coursebuilder/ui' | ||
|
||
import type { TreeAction } from './lesson-list/data/tree' | ||
import { useSelection } from './selection-context' | ||
|
||
export default function Hit({ | ||
hit, | ||
listId, | ||
updateTreeState, | ||
}: { | ||
hit: TypesenseResource | ||
listId: string | ||
updateTreeState: React.ActionDispatch<[action: TreeAction]> | ||
}) { | ||
const { toggleSelection, isSelected } = useSelection() | ||
|
||
return ( | ||
<li className={`${isSelected(hit.id) ? 'bg-muted' : ''}`}> | ||
<button | ||
type="button" | ||
className="hover:bg-muted/50 group flex w-full flex-row items-baseline justify-between gap-2 px-5 py-3 sm:py-3" | ||
onClick={() => toggleSelection(hit)} | ||
> | ||
<div className="flex items-center gap-2"> | ||
<span className="pr-5 font-medium sm:truncate">{hit.title}</span> | ||
</div> | ||
<div className="text-muted-foreground fon-normal flex flex-shrink-0 items-center gap-3 pl-7 text-xs capitalize opacity-60 sm:pl-0"> | ||
<span>{hit.type}</span> | ||
</div> | ||
</button> | ||
</li> | ||
) | ||
} |
Oops, something went wrong.