// Dependencies import { nsMerge, capitalize, cloudflareImageUrl, yyyymmdd } from 'shared/utils.mjs' // Hooks import { useState, useContext, Fragment } from 'react' import { useAccount } from 'shared/hooks/use-account.mjs' import { useBackend } from 'shared/hooks/use-backend.mjs' import { useTranslation } from 'next-i18next' // Context import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs' // Components import { Popout } from 'shared/components/popout/index.mjs' import { AuthWrapper, ns as authNs } from 'shared/components/wrappers/auth/index.mjs' import { DesignPicker } from './design-picker.mjs' import { TitleInput, SlugInput, ImageInput, CaptionInput, IntroInput, BodyInput, } from './inputs.mjs' import { Tab } from 'shared/components/account/bio.mjs' import { CodeBox } from 'shared/components/code-box.mjs' import { PageLink, WebLink } from 'shared/components/link.mjs' import { OkIcon, WarningIcon as KoIcon } from 'shared/components/icons.mjs' import { PostImage } from 'site/components/layouts/post.mjs' import { Mdx } from 'shared/components/mdx/dynamic.mjs' export const ns = nsMerge('account', 'posts', authNs) const Tip = ({ children }) =>

{children}

const Item = ({ title, children }) => (
{title}
{children}
) const dataAsMd = ({ title, user, caption, intro, designs, body }, type) => { let md = `--- title: "${title}" caption: "${caption}" date: ${yyyymmdd()} intro: "${intro}"` if (type === 'showcase') md += ` designs: [${designs.map((design) => `"${design}"`).join(', ')}] maker: ${user}` else md += ` author: ${user}` md += ` --- ${body} ` return md } export const CreatePost = ({ type = 'showcase' }) => { // Hooks const backend = useBackend() const { account } = useAccount() const { t, i18n } = useTranslation(ns) const { loading, setLoadingStatus } = useContext(LoadingStatusContext) // State const [designs, setDesigns] = useState([]) const [title, setTitle] = useState('') const [slug, setSlug] = useState(false) const [slugAvailable, setSlugAvailable] = useState(true) const [img, setImg] = useState(false) const [caption, setCaption] = useState('') const [intro, setIntro] = useState('') const [body, setBody] = useState('') const [extraImages, setExtraImages] = useState({}) const [activeTab, setActiveTab] = useState('create') const [pr, setPr] = useState(false) // Method that submits the post to the backend const submitPost = async () => { setLoadingStatus([true, `Creating ${type} post & pull request`]) const result = await backend.createPost(type, { markdown: dataAsMd( { title, user: account.username, caption, intro, designs, body, }, type ), slug, language: i18n.language, }) if (result.success) setPr(result.data) setLoadingStatus([false]) } // Shared props for tabs const tabProps = { activeTab, setActiveTab, t } const addImage = () => { const id = Object.keys(extraImages).length + 1 const newImages = { ...extraImages } newImages[id] = null setExtraImages(newImages) } const verifySlug = async (newSlug) => { setSlug(newSlug) const result = await backend.isSlugAvailable({ slug: newSlug, type }) setSlugAvailable(result.available === true ? true : false) } const setExtraImg = (key, img) => { const newImages = { ...extraImages } newImages[key] = img setExtraImages(newImages) } const childProps = { type, designs, setDesigns, title, setTitle, slug, img, setImg, caption, setCaption, intro, setIntro, body, setBody, extraImages, setExtraImages, addImage, setExtraImg, account, t, verifySlug, slugAvailable, } return ( {pr ? (

Thank you for submitting this {type} post

Here is what happened while you were waiting:

Next steps:

To summarize: You did great 💜 and we'll take it from here{' '} 🙌

) : ( <>
{activeTab === 'create' ? ( ) : ( )}
{!(title && slug && img && (type === 'blog' || designs.length > 0)) && (
You are missing the following:
    {type === 'showcase' && designs.length < 1 &&
  • Design
  • } {!title &&
  • Title
  • } {!slug &&
  • Slug
  • } {!img &&
  • Main Image
  • }
)} {!account.data?.githubUser && !account.data?.githubEmail && (
Optional: Are you on GitHub?

If you configure your GitHub username{' '} , we will credit these changes to you.

)}
)}
) } const PostPreview = ({ title, img, caption, body }) => ( <>

{title}

{body}
) const PostEditor = ({ type, designs, setDesigns, title, setTitle, slug, verifySlug, slugAvailable, img, setImg, caption, setCaption, intro, setIntro, body, setBody, extraImages, addImage, setExtraImg, t, }) => ( <>

Create a new {type} post

{t(`${type}NewInfo`)} {type === 'showcase' && ( {designs.length > 0 ? ( ) : ( )} Design: {designs.length > 0 ? ( {designs.map((d) => capitalize(d)).join(', ')} ) : ( Please select at least 1 design )} } > Pick one or more designs that are featured in this post. )} {title.length > 10 ? ( ) : ( )} Title: {title.length > 10 ? ( {title} ) : ( Please enter a post title )} } > Give your post a title. A good title is more than just a few words. {slugAvailable && slug.length > 3 ? ( ) : ( )} Slug: {slug.length > 3 ? ( {slug} ) : ( Please enter a slug (or post title) )} } > The slug is the part of the URL that uniquely identifies the post. We can generate one based on the title, but you can also customize it. {img.length > 3 ? ( ) : ( )} Main Image: {img.length > 3 ? ( {img} ) : ( Please provide a main image for the post )} } > The main image will be shown at the top of the post, and as the only image on the {type} index page. {caption.length > 3 ? ( ) : ( )} Main Image Caption: {caption.length > 3 ? ( {caption} ) : ( Please provide a caption for the main image )} } > The caption is the text that goes under the main image. Can include copyrights/credits. Markdown is allowed. {intro.length > 3 ? ( ) : ( )} Intro: {intro.length > 3 ? ( {intro} ) : ( Please provide an intro for link proviews )} } > A brief paragraph that will be shown on post previews on social media and so on. Additional Images: {Object.keys(extraImages).length} } > {img ? ( <> Here you can add any images you want to include in the post body. {Object.keys(extraImages).map((key) => { const markup = '![The image alt goes here](' + cloudflareImageUrl({ id: extraImages[key], variant: 'public' }) + ' "The image caption/title goes here")' return ( setExtraImg(key, img)} type={type} subId={key} img={extraImages[key]} slug={slug} /> {extraImages[key] && ( <>

To include this image in your post, use this markdown snippet:

)}
) })} ) : ( Please add a main image first )}
{body.length > 3 ? ( ) : ( )} Post body: {body.length > 3 ? ( {body.slice(0, 30) + '...'} ) : ( Please provide a post body )} } > The actual post body. Supports Markdown. )