mono/packages/ui/docs/posts.md
2026-03-21 20:18:25 +01:00

11 KiB

Posts Module Documentation

Module path: src/modules/posts/

The posts module owns all post-related frontend functionality: creating, editing, viewing, and managing posts containing mixed media (images, videos, embeds, external links).


Directory Structure

src/modules/posts/
├── EditPost.tsx               # Create & edit page (/post/new, /post/:id/edit)
├── NewPost.tsx                # Legacy new-post page (/new)
├── PostPage.tsx               # Post detail page (/post/:id)
├── client-posts.ts            # Post API client (CRUD, feed, meta)
├── client-pictures.ts         # Picture/media API client (CRUD, comments, likes, versions)
├── components/
│   ├── PostComposer.tsx       # Post editor form (title, description, settings, image list)
│   └── PostPicker.tsx         # Dialog for selecting existing posts (append-to-post flow)
└── views/
    ├── types.ts               # Core types (PostItem, PostMediaItem, PostSettings, etc.)
    ├── adapters.ts            # Data adapters (Supabase → frontend models)
    ├── PostActions.ts          # Post action utilities
    ├── usePostActions.ts       # Post action hooks
    ├── utils.ts               # Shared utilities
    ├── db.ts                  # DB helpers
    ├── llm.tsx                # AI/LLM integration for posts
    ├── components/
    │   ├── SmartLightbox.tsx   # Full-screen media lightbox
    │   ├── DeleteDialogs.tsx   # Post/picture delete confirmation
    │   ├── ExportDropdown.tsx  # Export menu (markdown, zip, etc.)
    │   ├── TikTokDialog.tsx    # TikTok embed dialog
    │   ├── TikTokEmbed.tsx     # TikTok embed renderer
    │   └── YouTubeDialog.tsx   # YouTube embed dialog
    └── renderers/
        ├── ArticleRenderer.tsx      # Blog/article-style layout
        ├── CompactRenderer.tsx      # Default compact layout
        ├── EmbedRenderer.tsx        # oEmbed rendering (/embed/:id)
        ├── ThumbsRenderer.tsx       # Thumbnail grid layout
        └── components/
            ├── CompactActionToolbar.tsx  # Action bar (like, share, edit, etc.)
            ├── CompactFilmStrip.tsx      # Horizontal thumbnail strip
            ├── CompactMediaDetails.tsx   # Media metadata panel
            ├── CompactMediaViewer.tsx    # Main media viewport
            ├── CompactPostHeader.tsx     # Post header (author, date, categories)
            ├── Gallery.tsx              # Gallery grid component
            ├── MobileGroupItem.tsx       # Mobile-optimized post item
            ├── MobileGroupedFeed.tsx     # Mobile grouped feed view
            └── SpyGlassImage.tsx        # Zoom/spy-glass image viewer

Routes

Route Component Description
/post/new EditPost Create a new post
/post/:id PostPage View post detail
/post/:id/edit EditPost Edit an existing post
/video/:id PostPage View video post (same renderer)
/new NewPost Legacy new-post page
/wizard Wizard AI Image Wizard (separate module, not post-specific)

Route definitions: src/App.tsx


Supported Media Types

Posts can contain mixed media items. Each PostMediaItem has a type field:

Type Description Source
supabase-image Uploaded image (stored in Supabase Storage) File upload / drag-drop
mux-video Video (processed by Mux) File upload
video-intern Legacy internal video Migration
page-external External link card (with OG metadata) URL paste
youtube YouTube embed YouTube dialog
tiktok TikTok embed TikTok dialog

Display Modes (Renderers)

Posts support multiple display modes, configured via post.settings.display:

Mode Renderer Description
compact (default) CompactRenderer Side-panel layout: media viewer + filmstrip + details
article ArticleRenderer Blog-style: wide images with inline markdown text
thumbs ThumbsRenderer Grid of thumbnails
embed EmbedRenderer For /embed/:id oEmbed endpoint

The renderer is selected in PostPage.tsx based on the post's settings.


Client APIs

client-posts.ts

Post-level CRUD operations, all authenticated via Supabase session:

Function Method Description
fetchPostById(id) GET /api/posts/:id Fetch single post with pictures
fetchPostDetailsAPI(id) GET /api/posts/:id Fetch with responsive image sizes/formats
fetchPostsList(options) GET /api/posts Paginated post list
fetchFullPost(postId) Supabase RPC Full post with all relations
createPost(data) POST /api/posts Create new post
updatePostDetails(id, updates) PATCH /api/posts/:id Update title, description, settings, meta
updatePostMeta(id, meta) PATCH /api/posts/:id Update meta only
deletePost(id) DELETE /api/posts/:id Delete post and associated pictures
mapFeedPostsToMediaItems(posts) Convert feed posts to PhotoGrid-compatible format
augmentFeedPosts(posts) Normalize API posts (add cover, author)

client-pictures.ts

Picture/media-level operations:

Function Method Description
createPicture(picture) POST /api/pictures Create picture record
updatePicture(id, updates) PATCH /api/pictures/:id Update picture metadata
deletePicture(id) DELETE /api/pictures/:id Delete single picture
deletePictures(ids) POST /api/pictures/delete-batch Batch delete
fetchPictures(options) GET /api/pictures List pictures with filters
fetchPictureById(id) GET /api/pictures/:id Single picture
fetchMediaItemsByIds(ids) GET /api/media-items Batch fetch by IDs
fetchVersions(item) GET /api/pictures/versions Version tree
toggleLike(userId, pictureId) Supabase Toggle like on picture
unlinkPictures(ids) POST /api/pictures/unlink Unlink from post
upsertPictures(pictures) POST /api/pictures/upsert Batch upsert
fetchCommentsAPI(pictureId) GET /api/pictures/:id/comments Fetch comments
addCommentAPI(pictureId, content) POST /api/pictures/:id/comments Add comment
editCommentAPI(pictureId, commentId, content) PATCH Edit comment
deleteCommentAPI(pictureId, commentId) DELETE Delete comment
toggleCommentLikeAPI(pictureId, commentId) POST Toggle comment like

Core Types

Defined in views/types.ts:

// A media item attached to a post
type PostMediaItem = MediaItem & {
    post_id: string | null;
    renderKey?: string;
};

// The post entity
interface PostItem {
    id: string;
    title: string;
    description: string | null;
    user_id: string;
    created_at: string;
    updated_at: string;
    pictures?: PostMediaItem[];
    settings?: PostSettings;
    meta?: PostMeta;
}

// Post display and visibility settings
interface PostSettings {
    display?: 'compact' | 'thumbs';
    visibility?: 'public' | 'listed' | 'private';
    link?: string;           // For link posts
    image_url?: string;
    thumbnail_url?: string;
}

// Post metadata
interface PostMeta {
    slug?: string;
    categoryIds?: string[];
    [key: string]: any;
}

Post Lifecycle

Creating a Post

  1. User navigates to /post/new (via CreationWizardPopup or direct URL)
  2. EditPost.tsx renders in create mode (no id param)
  3. User fills title, description, adds images via drag-drop or file picker
  4. Configures visibility/display in PostComposer settings accordion
  5. On publish: publishImage() from publishHandlers.ts creates the post via createPost(), uploads images, links them via createPicture()
  6. Redirects to /post/:id

Editing a Post

  1. User clicks "Edit Post" on PostPage.tsx → navigates to /post/:id/edit
  2. EditPost.tsx fetches post data from fetchPostById()
  3. Converts existing pictures to ImageFile[] format for PostComposer
  4. User modifies content; on save: publishImage() calls updatePostDetails() and updates pictures
  5. Redirects back to /post/:id

Viewing a Post

  1. PostPage.tsx fetches post via fetchPostDetailsAPI()
  2. Resolves display mode from post.settings.display
  3. Delegates to appropriate renderer (Compact, Article, Thumbs)
  4. Renderer receives all props via PostRendererProps interface

Integration with ImageWizard

The ImageWizard (src/components/ImageWizard.tsx) is a separate module for AI image generation. It interacts with posts in two ways:

  1. Append to Post — Images generated in the wizard can be appended to an existing post via PostPicker dialog
  2. Open in Wizard — Individual post images can be opened in the wizard for AI-powered editing (variations, upscaling, etc.)

The shared interface is the ImageFile type from ImageWizard/types.ts and the publishImage() function from publishHandlers.ts.

Note: publishHandlers.ts still lives in ImageWizard/handlers/ but is functionally post-module logic. It should be migrated to modules/posts/ in a future cleanup.


Post Settings & Visibility

Setting Values Effect
visibility public / listed / private Controls feed inclusion and access
display compact / article / thumbs Selects renderer
link URL string Attaches external link to post

Managed via the settings accordion in PostComposer.tsx.