✨ External attachments
This commit is contained in:
		| @@ -9,14 +9,15 @@ import ( | |||||||
| type Attachment struct { | type Attachment struct { | ||||||
| 	BaseModel | 	BaseModel | ||||||
|  |  | ||||||
| 	FileID   string  `json:"file_id"` | 	FileID      string  `json:"file_id"` | ||||||
| 	Filesize int64   `json:"filesize"` | 	Filesize    int64   `json:"filesize"` | ||||||
| 	Filename string  `json:"filename"` | 	Filename    string  `json:"filename"` | ||||||
| 	Mimetype string  `json:"mimetype"` | 	Mimetype    string  `json:"mimetype"` | ||||||
| 	Post     *Post   `json:"post"` | 	ExternalUrl string  `json:"external_url"` | ||||||
| 	Author   Account `json:"author"` | 	Post        *Post   `json:"post"` | ||||||
| 	PostID   *uint   `json:"post_id"` | 	Author      Account `json:"author"` | ||||||
| 	AuthorID uint    `json:"author_id"` | 	PostID      *uint   `json:"post_id"` | ||||||
|  | 	AuthorID    uint    `json:"author_id"` | ||||||
| } | } | ||||||
|  |  | ||||||
| func (v Attachment) GetStoragePath() string { | func (v Attachment) GetStoragePath() string { | ||||||
|   | |||||||
| @@ -14,7 +14,7 @@ export default function PostAttachments(props: { attachments: any[] }) { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   function getUrl(item: any): string { |   function getUrl(item: any): string { | ||||||
|     return `/api/attachments/o/${item.file_id}`; |     return item.external_url ?? `/api/attachments/o/${item.file_id}`; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   createEffect(() => { |   createEffect(() => { | ||||||
| @@ -36,8 +36,8 @@ export default function PostAttachments(props: { attachments: any[] }) { | |||||||
|               <i class="fa-solid fa-circle-question text-3xl"></i> |               <i class="fa-solid fa-circle-question text-3xl"></i> | ||||||
|               <p class="mt-3">{item().filename}</p> |               <p class="mt-3">{item().filename}</p> | ||||||
|  |  | ||||||
|               <div class="flex gap-3 w-full"> |               <div class="flex gap-2 w-full"> | ||||||
|                 <p class="text-sm">{item().filesize} Bytes</p> |                 <p class="text-sm">{item().filesize <= 0 ? "Unknown" : item().filesize} Bytes</p> | ||||||
|                 <p class="text-sm">{item().mimetype}</p> |                 <p class="text-sm">{item().mimetype}</p> | ||||||
|               </div> |               </div> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| import { createEffect, createSignal, For, Show } from "solid-js"; | import { createEffect, createSignal, For, Match, Show, Switch } from "solid-js"; | ||||||
| import { getAtk, useUserinfo } from "../stores/userinfo.tsx"; | import { getAtk, useUserinfo } from "../stores/userinfo.tsx"; | ||||||
|  |  | ||||||
| import styles from "./PostPublish.module.css"; | import styles from "./PostPublish.module.css"; | ||||||
| @@ -22,6 +22,8 @@ export default function PostPublish(props: { | |||||||
|   const [categories, setCategories] = createSignal<{ alias: string, name: string }[]>([]); |   const [categories, setCategories] = createSignal<{ alias: string, name: string }[]>([]); | ||||||
|   const [tags, setTags] = createSignal<{ alias: string, name: string }[]>([]); |   const [tags, setTags] = createSignal<{ alias: string, name: string }[]>([]); | ||||||
|  |  | ||||||
|  |   const [attachmentMode, setAttachmentMode] = createSignal(0); | ||||||
|  |  | ||||||
|   createEffect(() => { |   createEffect(() => { | ||||||
|     setAttachments(props.editing?.attachments ?? []); |     setAttachments(props.editing?.attachments ?? []); | ||||||
|     setCategories(props.editing?.categories ?? []); |     setCategories(props.editing?.categories ?? []); | ||||||
| @@ -101,7 +103,7 @@ export default function PostPublish(props: { | |||||||
|     setSubmitting(false); |     setSubmitting(false); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   async function uploadAttachments(evt: SubmitEvent) { |   async function uploadAttachment(evt: SubmitEvent) { | ||||||
|     evt.preventDefault(); |     evt.preventDefault(); | ||||||
|  |  | ||||||
|     const form = evt.target as HTMLFormElement; |     const form = evt.target as HTMLFormElement; | ||||||
| @@ -125,6 +127,19 @@ export default function PostPublish(props: { | |||||||
|     setUploading(false); |     setUploading(false); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   function addAttachment(evt: SubmitEvent) { | ||||||
|  |     evt.preventDefault(); | ||||||
|  |  | ||||||
|  |     const form = evt.target as HTMLFormElement; | ||||||
|  |     const data = Object.fromEntries(new FormData(form)); | ||||||
|  |  | ||||||
|  |     setAttachments(attachments().concat([{ | ||||||
|  |       ...data, | ||||||
|  |       author_id: userinfo?.profiles?.id, | ||||||
|  |     }])); | ||||||
|  |     form.reset(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   function addCategory(evt: SubmitEvent) { |   function addCategory(evt: SubmitEvent) { | ||||||
|     evt.preventDefault(); |     evt.preventDefault(); | ||||||
|  |  | ||||||
| @@ -138,7 +153,7 @@ export default function PostPublish(props: { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   function removeCategory(target: any) { |   function removeCategory(target: any) { | ||||||
|     setCategories(categories().filter(item => item.alias !== target.alias)) |     setCategories(categories().filter(item => item.alias !== target.alias)); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   function addTag(evt: SubmitEvent) { |   function addTag(evt: SubmitEvent) { | ||||||
| @@ -154,7 +169,7 @@ export default function PostPublish(props: { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   function removeTag(target: any) { |   function removeTag(target: any) { | ||||||
|     setTags(tags().filter(item => item.alias !== target.alias)) |     setTags(tags().filter(item => item.alias !== target.alias)); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   function resetForm() { |   function resetForm() { | ||||||
| @@ -270,23 +285,60 @@ export default function PostPublish(props: { | |||||||
|       <dialog id="attachments" class="modal"> |       <dialog id="attachments" class="modal"> | ||||||
|         <div class="modal-box"> |         <div class="modal-box"> | ||||||
|           <h3 class="font-bold text-lg mx-1">Attachments</h3> |           <h3 class="font-bold text-lg mx-1">Attachments</h3> | ||||||
|           <form class="w-full mt-3" onSubmit={uploadAttachments}> |  | ||||||
|             <label class="form-control"> |           <div role="tablist" class="tabs tabs-boxed mt-3"> | ||||||
|               <div class="label"> |             <input type="radio" name="attachment" role="tab" class="tab" aria-label="File picker" | ||||||
|                 <span class="label-text">Pick a file</span> |                    checked={attachmentMode() === 0} onClick={() => setAttachmentMode(0)} /> | ||||||
|               </div> |             <input type="radio" name="attachment" role="tab" class="tab" aria-label="External link" | ||||||
|               <div class="join"> |                    checked={attachmentMode() === 1} onClick={() => setAttachmentMode(1)} /> | ||||||
|                 <input required type="file" name="attachment" |           </div> | ||||||
|                        class="join-item file-input file-input-bordered w-full" /> |  | ||||||
|                 <button type="submit" class="join-item btn btn-primary" disabled={uploading()}> |           <Switch> | ||||||
|                   <i class="fa-solid fa-upload"></i> |             <Match when={attachmentMode() === 0}> | ||||||
|                 </button> |               <form class="w-full mt-2" onSubmit={uploadAttachment}> | ||||||
|               </div> |                 <label class="form-control"> | ||||||
|               <div class="label"> |                   <div class="label"> | ||||||
|                 <span class="label-text-alt">Click upload to add this file into list</span> |                     <span class="label-text">Pick a file</span> | ||||||
|               </div> |                   </div> | ||||||
|             </label> |                   <div class="join"> | ||||||
|           </form> |                     <input required type="file" name="attachment" | ||||||
|  |                            class="join-item file-input file-input-bordered w-full" /> | ||||||
|  |                     <button type="submit" class="join-item btn btn-primary" disabled={uploading()}> | ||||||
|  |                       <i class="fa-solid fa-upload"></i> | ||||||
|  |                     </button> | ||||||
|  |                   </div> | ||||||
|  |                   <div class="label"> | ||||||
|  |                     <span class="label-text-alt">Click upload to add this file into list</span> | ||||||
|  |                   </div> | ||||||
|  |                 </label> | ||||||
|  |               </form> | ||||||
|  |             </Match> | ||||||
|  |             <Match when={attachmentMode() === 1}> | ||||||
|  |               <form class="w-full mt-2" onSubmit={addAttachment}> | ||||||
|  |                 <label class="form-control"> | ||||||
|  |                   <div class="label"> | ||||||
|  |                     <span class="label-text">Attach an external file</span> | ||||||
|  |                   </div> | ||||||
|  |                   <div class="join"> | ||||||
|  |                     <input required type="text" name="mimetype" class="join-item input input-bordered w-full" | ||||||
|  |                            placeholder="Mimetype" /> | ||||||
|  |                     <input required type="text" name="filename" class="join-item input input-bordered w-full" | ||||||
|  |                            placeholder="Name" /> | ||||||
|  |                   </div> | ||||||
|  |                   <div class="join"> | ||||||
|  |                     <input required type="text" name="external_url" class="join-item input input-bordered w-full" | ||||||
|  |                            placeholder="External URL" /> | ||||||
|  |                     <button type="submit" class="join-item btn btn-primary"> | ||||||
|  |                       <i class="fa-solid fa-plus"></i> | ||||||
|  |                     </button> | ||||||
|  |                   </div> | ||||||
|  |                   <div class="label"> | ||||||
|  |                     <span class="label-text-alt">Click add button to add it into list</span> | ||||||
|  |                   </div> | ||||||
|  |                 </label> | ||||||
|  |               </form> | ||||||
|  |             </Match> | ||||||
|  |           </Switch> | ||||||
|  |  | ||||||
|           <Show when={attachments().length > 0}> |           <Show when={attachments().length > 0}> | ||||||
|             <h3 class="font-bold mt-3 mx-1">Attachment list</h3> |             <h3 class="font-bold mt-3 mx-1">Attachment list</h3> | ||||||
|   | |||||||
| @@ -11,7 +11,8 @@ interface MenuItem { | |||||||
|  |  | ||||||
| export default function Navbar() { | export default function Navbar() { | ||||||
|   const nav: MenuItem[] = [ |   const nav: MenuItem[] = [ | ||||||
|     { label: "Feed", href: "/" } |     { label: "Feed", href: "/" }, | ||||||
|  |     { label: "Realms", href: "/realms" } | ||||||
|   ]; |   ]; | ||||||
|  |  | ||||||
|   const wellKnown = useWellKnown(); |   const wellKnown = useWellKnown(); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user