;; Blog editor components (defcomp ~blog-editor-error (&key error) (div :class "max-w-[768px] mx-auto mt-[16px] rounded-[8px] border border-red-300 bg-red-50 px-[16px] py-[12px] text-[14px] text-red-700" (strong "Save failed:") " " error)) (defcomp ~blog-editor-form (&key csrf title-placeholder create-label) (form :id "post-new-form" :method "post" :class "max-w-[768px] mx-auto pb-[48px]" (input :type "hidden" :name "csrf_token" :value csrf) (input :type "hidden" :id "lexical-json-input" :name "lexical" :value "") (input :type "hidden" :id "feature-image-input" :name "feature_image" :value "") (input :type "hidden" :id "feature-image-caption-input" :name "feature_image_caption" :value "") (div :id "feature-image-container" :class "relative mt-[16px] mb-[24px] group" (div :id "feature-image-empty" (button :type "button" :id "feature-image-add-btn" :class "text-[14px] text-stone-400 hover:text-stone-600 transition-colors cursor-pointer" "+ Add feature image")) (div :id "feature-image-filled" :class "relative hidden" (img :id "feature-image-preview" :src "" :alt "" :class "w-full max-h-[448px] object-cover rounded-[8px] cursor-pointer") (button :type "button" :id "feature-image-delete-btn" :class "absolute top-[8px] right-[8px] w-[32px] h-[32px] rounded-full bg-black/50 text-white flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity hover:bg-black/70 cursor-pointer text-[14px]" :title "Remove feature image" (i :class "fa-solid fa-trash-can")) (input :type "text" :id "feature-image-caption" :value "" :placeholder "Add a caption..." :class "mt-[8px] w-full text-[14px] text-stone-500 bg-transparent border-none outline-none placeholder:text-stone-300 focus:text-stone-700")) (div :id "feature-image-uploading" :class "hidden flex items-center gap-[8px] mt-[8px] text-[14px] text-stone-400" (i :class "fa-solid fa-spinner fa-spin") " Uploading...") (input :type "file" :id "feature-image-file" :accept "image/jpeg,image/png,image/gif,image/webp,image/svg+xml" :class "hidden")) (input :type "text" :name "title" :value "" :placeholder title-placeholder :class "w-full text-[36px] font-bold bg-transparent border-none outline-none placeholder:text-stone-300 mb-[8px] leading-tight") (textarea :name "custom_excerpt" :rows "1" :placeholder "Add an excerpt..." :class "w-full text-[18px] text-stone-500 bg-transparent border-none outline-none placeholder:text-stone-300 resize-none mb-[24px] leading-relaxed") (div :id "lexical-editor" :class "relative w-full bg-transparent") (div :class "flex items-center gap-[16px] mt-[32px] pt-[16px] border-t border-stone-200" (select :name "status" :class "text-[14px] rounded-[4px] border border-stone-200 px-[8px] py-[6px] bg-white text-stone-600" (option :value "draft" :selected t "Draft") (option :value "published" "Published")) (button :type "submit" :class "px-[20px] py-[6px] bg-stone-700 text-white text-[14px] rounded-[8px] hover:bg-stone-800 transition-colors cursor-pointer" create-label)))) (defcomp ~blog-editor-styles (&key css-href) (<> (link :rel "stylesheet" :href css-href) (style "#lexical-editor { display: flow-root; }" "#lexical-editor [data-kg-card=\"html\"] * { float: none !important; }" "#lexical-editor [data-kg-card=\"html\"] table { width: 100% !important; }"))) (defcomp ~blog-editor-scripts (&key js-src init-js) (<> (script :src js-src) (script init-js)))