Google Antigravity Directory

The #1 directory for Google Antigravity prompts, rules, workflows & MCP servers. Optimized for Gemini 3 agentic development.

Resources

PromptsMCP ServersAntigravity RulesGEMINI.md GuideBest Practices

Company

Submit PromptAntigravityAI.directory

Popular Prompts

Next.js 14 App RouterReact TypeScriptTypeScript AdvancedFastAPI GuideDocker Best Practices

Legal

Privacy PolicyTerms of ServiceContact Us
Featured on FazierFeatured on WayfindioAntigravity AI - Featured on Startup FameFeatured on Wired BusinessFeatured on Twelve ToolsListed on Turbo0Featured on findly.toolsFeatured on Aura++That App ShowAI ToolzShinyLaunchMillion Dot HomepageSolver ToolsFeatured on FazierFeatured on WayfindioAntigravity AI - Featured on Startup FameFeatured on Wired BusinessFeatured on Twelve ToolsListed on Turbo0Featured on findly.toolsFeatured on Aura++That App ShowAI ToolzShinyLaunchMillion Dot HomepageSolver Tools

© 2026 Antigravity AI Directory. All rights reserved.

The #1 directory for Google Antigravity IDE

This website is not affiliated with, endorsed by, or associated with Google LLC. "Google" and "Gemini" are trademarks of Google LLC.

Antigravity AI Directory
PromptsMCPBest PracticesUse CasesLearn
Home
Prompts
Comments System Implementation

Comments System Implementation

Build a full-featured comments system in Google Antigravity with nested replies and reactions.

commentsreactionsnestedrealtime
by antigravity-team
⭐0Stars
.antigravity
# Comments System for Google Antigravity

Build a complete comments system with nested replies, reactions, and moderation.

## Database Schema

```sql
CREATE TABLE public.comments (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    post_id UUID REFERENCES public.posts(id) ON DELETE CASCADE,
    user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
    parent_id UUID REFERENCES public.comments(id) ON DELETE CASCADE,
    content TEXT NOT NULL,
    edited_at TIMESTAMPTZ,
    deleted BOOLEAN DEFAULT false,
    created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE public.comment_reactions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    comment_id UUID REFERENCES public.comments(id) ON DELETE CASCADE,
    user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
    reaction TEXT NOT NULL,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    UNIQUE(comment_id, user_id, reaction)
);

CREATE INDEX idx_comments_post ON public.comments(post_id, created_at);
CREATE INDEX idx_comments_parent ON public.comments(parent_id);
CREATE INDEX idx_reactions_comment ON public.comment_reactions(comment_id);

ALTER TABLE public.comments ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Comments are viewable" ON public.comments FOR SELECT USING (true);
CREATE POLICY "Users can insert comments" ON public.comments FOR INSERT WITH CHECK (auth.uid() = user_id);
CREATE POLICY "Users can update own comments" ON public.comments FOR UPDATE USING (auth.uid() = user_id);
```

## Comments Hook

```typescript
// hooks/useComments.ts
"use client";

import { useState, useEffect, useCallback } from "react";
import { createClient } from "@/lib/supabase/client";

interface Comment {
    id: string;
    post_id: string;
    user_id: string;
    parent_id: string | null;
    content: string;
    created_at: string;
    edited_at: string | null;
    deleted: boolean;
    user: { id: string; full_name: string; avatar_url: string };
    reactions: { reaction: string; count: number }[];
    replies?: Comment[];
}

export function useComments(postId: string) {
    const [comments, setComments] = useState<Comment[]>([]);
    const [loading, setLoading] = useState(true);
    const supabase = createClient();

    const fetchComments = useCallback(async () => {
        const { data } = await supabase.from("comments").select(`*, user:profiles(id, full_name, avatar_url), reactions:comment_reactions(reaction)`).eq("post_id", postId).order("created_at", { ascending: true });
        
        const nested = nestComments(data || []);
        setComments(nested);
        setLoading(false);
    }, [postId, supabase]);

    useEffect(() => {
        fetchComments();
        const channel = supabase.channel(`comments:${postId}`).on("postgres_changes", { event: "*", schema: "public", table: "comments", filter: `post_id=eq.${postId}` }, () => { fetchComments(); }).subscribe();
        return () => { channel.unsubscribe(); };
    }, [postId, fetchComments, supabase]);

    const addComment = async (content: string, parentId?: string) => {
        const { data: { user } } = await supabase.auth.getUser();
        if (!user) throw new Error("Not authenticated");
        await supabase.from("comments").insert({ post_id: postId, user_id: user.id, content, parent_id: parentId });
    };

    const editComment = async (id: string, content: string) => {
        await supabase.from("comments").update({ content, edited_at: new Date().toISOString() }).eq("id", id);
    };

    const deleteComment = async (id: string) => {
        await supabase.from("comments").update({ deleted: true, content: "[deleted]" }).eq("id", id);
    };

    return { comments, loading, addComment, editComment, deleteComment };
}

function nestComments(flat: Comment[]): Comment[] {
    const map = new Map<string, Comment>();
    const roots: Comment[] = [];
    flat.forEach((c) => map.set(c.id, { ...c, replies: [] }));
    flat.forEach((c) => {
        const comment = map.get(c.id)!;
        if (c.parent_id) map.get(c.parent_id)?.replies?.push(comment);
        else roots.push(comment);
    });
    return roots;
}
```

## Comment Component

```typescript
// components/Comment.tsx
"use client";

import { useState } from "react";
import { formatDistanceToNow } from "date-fns";

interface CommentProps {
    comment: any;
    onReply: (parentId: string, content: string) => void;
    onEdit: (id: string, content: string) => void;
    onDelete: (id: string) => void;
    currentUserId?: string;
    depth?: number;
}

export function Comment({ comment, onReply, onEdit, onDelete, currentUserId, depth = 0 }: CommentProps) {
    const [replying, setReplying] = useState(false);
    const [editing, setEditing] = useState(false);
    const [content, setContent] = useState(comment.content);
    const [replyContent, setReplyContent] = useState("");

    const handleReply = () => {
        onReply(comment.id, replyContent);
        setReplyContent("");
        setReplying(false);
    };

    const handleEdit = () => {
        onEdit(comment.id, content);
        setEditing(false);
    };

    const isOwner = currentUserId === comment.user_id;

    return (
        <div className="comment" style={{ marginLeft: depth * 20 }}>
            <div className="comment-header">
                <img src={comment.user.avatar_url} alt="" className="avatar" />
                <span className="name">{comment.user.full_name}</span>
                <span className="time">{formatDistanceToNow(new Date(comment.created_at))} ago</span>
                {comment.edited_at && <span className="edited">(edited)</span>}
            </div>
            {editing ? (
                <div className="edit-form">
                    <textarea value={content} onChange={(e) => setContent(e.target.value)} />
                    <button onClick={handleEdit}>Save</button>
                    <button onClick={() => setEditing(false)}>Cancel</button>
                </div>
            ) : (
                <p className="comment-content">{comment.content}</p>
            )}
            <div className="comment-actions">
                <button onClick={() => setReplying(!replying)}>Reply</button>
                {isOwner && !comment.deleted && (
                    <>
                        <button onClick={() => setEditing(true)}>Edit</button>
                        <button onClick={() => onDelete(comment.id)}>Delete</button>
                    </>
                )}
            </div>
            {replying && (
                <div className="reply-form">
                    <textarea value={replyContent} onChange={(e) => setReplyContent(e.target.value)} placeholder="Write a reply..." />
                    <button onClick={handleReply}>Submit</button>
                </div>
            )}
            {comment.replies?.map((reply: any) => (
                <Comment key={reply.id} comment={reply} onReply={onReply} onEdit={onEdit} onDelete={onDelete} currentUserId={currentUserId} depth={depth + 1} />
            ))}
        </div>
    );
}
```

## Comments Section

```typescript
// components/CommentsSection.tsx
"use client";

import { useState } from "react";
import { useComments } from "@/hooks/useComments";
import { Comment } from "./Comment";
import { useAuth } from "@/components/auth/AuthProvider";

export function CommentsSection({ postId }: { postId: string }) {
    const { comments, loading, addComment, editComment, deleteComment } = useComments(postId);
    const { user } = useAuth();
    const [newComment, setNewComment] = useState("");

    const handleSubmit = async (e: React.FormEvent) => {
        e.preventDefault();
        if (!newComment.trim()) return;
        await addComment(newComment);
        setNewComment("");
    };

    if (loading) return <div>Loading comments...</div>;

    return (
        <div className="comments-section">
            <h3>Comments ({comments.length})</h3>
            {user && (
                <form onSubmit={handleSubmit}>
                    <textarea value={newComment} onChange={(e) => setNewComment(e.target.value)} placeholder="Write a comment..." />
                    <button type="submit">Post Comment</button>
                </form>
            )}
            {comments.map((comment) => (
                <Comment key={comment.id} comment={comment} onReply={(parentId, content) => addComment(content, parentId)} onEdit={editComment} onDelete={deleteComment} currentUserId={user?.id} />
            ))}
        </div>
    );
}
```

## Best Practices

1. **Nested Structure**: Support nested replies with depth limit
2. **Real-time**: Use Supabase Realtime for live updates
3. **Soft Delete**: Use soft delete to preserve thread structure
4. **Moderation**: Add reporting and admin moderation
5. **Pagination**: Paginate for posts with many comments

When to Use This Prompt

This comments prompt is ideal for developers working on:

  • comments applications requiring modern best practices and optimal performance
  • Projects that need production-ready comments code with proper error handling
  • Teams looking to standardize their comments development workflow
  • Developers wanting to learn industry-standard comments patterns and techniques

By using this prompt, you can save hours of manual coding and ensure best practices are followed from the start. It's particularly valuable for teams looking to maintain consistency across their comments implementations.

How to Use

  1. Copy the prompt - Click the copy button above to copy the entire prompt to your clipboard
  2. Paste into your AI assistant - Use with Claude, ChatGPT, Cursor, or any AI coding tool
  3. Customize as needed - Adjust the prompt based on your specific requirements
  4. Review the output - Always review generated code for security and correctness
💡 Pro Tip: For best results, provide context about your project structure and any specific constraints or preferences you have.

Best Practices

  • ✓ Always review generated code for security vulnerabilities before deploying
  • ✓ Test the comments code in a development environment first
  • ✓ Customize the prompt output to match your project's coding standards
  • ✓ Keep your AI assistant's context window in mind for complex requirements
  • ✓ Version control your prompts alongside your code for reproducibility

Frequently Asked Questions

Can I use this comments prompt commercially?

Yes! All prompts on Antigravity AI Directory are free to use for both personal and commercial projects. No attribution required, though it's always appreciated.

Which AI assistants work best with this prompt?

This prompt works excellently with Claude, ChatGPT, Cursor, GitHub Copilot, and other modern AI coding assistants. For best results, use models with large context windows.

How do I customize this prompt for my specific needs?

You can modify the prompt by adding specific requirements, constraints, or preferences. For comments projects, consider mentioning your framework version, coding style, and any specific libraries you're using.

Related Prompts

💬 Comments

Loading comments...