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
- User navigates to
/post/new(via CreationWizardPopup or direct URL) EditPost.tsxrenders in create mode (noidparam)- User fills title, description, adds images via drag-drop or file picker
- Configures visibility/display in PostComposer settings accordion
- On publish:
publishImage()frompublishHandlers.tscreates the post viacreatePost(), uploads images, links them viacreatePicture() - Redirects to
/post/:id
Editing a Post
- User clicks "Edit Post" on
PostPage.tsx→ navigates to/post/:id/edit EditPost.tsxfetches post data fromfetchPostById()- Converts existing pictures to
ImageFile[]format for PostComposer - User modifies content; on save:
publishImage()callsupdatePostDetails()and updates pictures - Redirects back to
/post/:id
Viewing a Post
PostPage.tsxfetches post viafetchPostDetailsAPI()- Resolves display mode from
post.settings.display - Delegates to appropriate renderer (Compact, Article, Thumbs)
- Renderer receives all props via
PostRendererPropsinterface
Integration with ImageWizard
The ImageWizard (src/components/ImageWizard.tsx) is a separate module for AI image generation. It interacts with posts in two ways:
- Append to Post — Images generated in the wizard can be appended to an existing post via
PostPickerdialog - 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.tsstill lives inImageWizard/handlers/but is functionally post-module logic. It should be migrated tomodules/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.