-
Notifications
You must be signed in to change notification settings - Fork 1
Components
The Collections component serves as the main interface for managing collections of topics with multi-platform publishing capabilities.
-
Collection Management
- Create new collections
- Edit existing collections
- Add/remove topics
- Reorder topics via drag-and-drop
- Preview collections
-
Publishing Options
- Web publishing with responsive HTML
- Dev.to integration
- Hashnode integration
- URL tracking for all platforms
-
Content Generation
- Markdown to HTML conversion
- Responsive image handling
- Dark/light theme support
- Code block formatting
-
SortableTopicItem
<SortableTopicItem id="topic-id" topic={topicData} isSelected={true} onToggle={(id) => handleToggle(id)} onRemove={(id) => handleRemove(id)} />
-
TopicSelector
<TopicSelector topic={topicData} isSelected={false} onToggle={(id) => handleToggle(id)} />
-
State Management
- Uses local state for form handling
- Uses SWR for collection data
- Maintains separate states for different publishing modals
-
DnD Implementation
- Uses dnd-kit for drag-and-drop
- Maintains order in topicIds array
- Provides smooth animations
-
Styling
- Uses shadcn/ui components
- Responsive grid layout
- Consistent dark/light theme support
The component includes utilities for generating HTML content:
const htmlContent = generateCollectionHTML(collection);
const markdown = markdownToHtml(content);Features:
- Full HTML document generation
- Responsive styling
- Image and link handling
- Code block formatting
- Theme-aware styling
-
Web Publishing
await publishCollection(collection.id, htmlContent);
-
Platform Integration
// Dev.to handleDevToPublish(collection); // Hashnode handleHashnodePublish(collection);
- MongoDB for collection storage
- AWS S3 for media storage
- Dev.to API key (optional)
- Hashnode API key (optional)
The MarkdownCMS component provides a complete content management system for creating and managing markdown-based topics.
import { MarkdownCMS } from '@/components/MarkdownCMS';
<MarkdownCMS pathname="/topics" />- EditorWithPreview
<EditorWithPreview
content={markdownContent}
onChange={handleContentChange}
theme={currentTheme}
/>- Topic Management
- Create new topics
- Edit existing topics
- Delete topics
- Sort and filter topics
- Word count tracking
-
Toolbar Actions
- Text Formatting
- Bold
- Italic
- Structure
- H1, H2, H3 headings
- Bullet lists
- Numbered lists
- Content
- Links
- Code blocks
- Image upload
- Text Formatting
-
Preview Functionality
- Live HTML preview
- Responsive image handling
- Code block formatting
- Dark/light theme support
- Editor Integration
// CodeMirror setup
<CodeMirror
value={content}
extensions={[
markdown(),
EditorView.lineWrapping
]}
theme={theme === 'dark' ? oneDark : undefined}
/>- Markdown Processing
// Convert markdown to HTML
const html = previewMarkdownToHtml(markdown);- Topic Management
// Create topic
await createTopic(name, content, description);
// Update topic
await updateTopic(id, name, content, description);
// Delete topic
await deleteTopic(id);-
Editor
- Full-width layout
- Responsive grid
- Custom toolbar design
- Theme-aware styling
-
Topic Cards
- Hover effects
- Metadata display
- Action buttons
- Description preview
- CodeMirror setup
- Theme provider
- Topics API integration
- Media storage for images
- @uiw/react-codemirror
- @codemirror/lang-markdown
- @codemirror/theme-one-dark
- lucide-react for icons
- shadcn/ui components
The Navigation component provides the main navigation bar for the application.
import Navigation from '@/components/Navigation';
<Navigation pathname={currentPathname} />-
Route Management
- Collections (
/collections) - Topics (
/) - Media (
/media) - Settings (
/settings)
- Collections (
-
Visual Feedback
- Active route highlighting (yellow)
- Hover state effects
- Consistent spacing
- Brand display
-
Layout Structure
<nav className="bg-slate-800 text-white p-4">
<div className="container mx-auto">
<!-- Brand -->
<span className="text-xl font-bold">Bebop</span>
<!-- Navigation Links -->
<div className="flex space-x-6">
<Link /> // Navigation items
</div>
</div>
</nav>-
Container
- Max width container
- Auto margins
- Flex layout
- Space between items
-
Navigation Items
- Consistent spacing (
space-x-6) - Hover effects
- Active state
- White text with yellow highlights
- Consistent spacing (
-
Brand
- Larger text size
- Bold weight
- Left alignment
- Uses Next.js Link component
- Pathname prop for active state
- Consistent yellow theme
- Mobile-ready spacing
- Dark background for contrast
The Layout component provides the main application structure and navigation.
import Layout from '@/components/Layout';
export default function YourPage() {
return (
<Layout pathname="/your-route">
<YourContent />
</Layout>
);
}-
Navigation
- Consistent top navigation bar
- Active route highlighting
- Hover effects
- Brand link to home
- Main routes:
- Collections
- Topics
- Media
- Settings
-
Structure
- Full-height minimum layout
- Centered content container
- Maximum width constraints
- Responsive padding
- Dark mode support
-
Special Cases
- Navigation hidden on landing page
- Yellow highlighting for active routes
- Hover effects for interactive elements
-
Container
.container { max-width: 7xl margin: auto padding: 2rem }
-
Navigation
- Dark slate background
- Yellow highlights for active/hover states
- Consistent spacing
- Flexible layout support
-
Themes
- Light theme: slate-50 background
- Dark theme: slate-900 background
- Proper contrast ratios maintained
- Uses Next.js Link component for client-side routing
- Pathname prop determines active route highlighting
- Maintains consistent spacing with container classes
- Implements responsive design patterns
- Supports dark mode via Tailwind classes
The DevToPublisher component enables collections to be published directly to Dev.to from within Bebop.
import { DevToPublisher } from '@/components/DevToPublisher';
<DevToPublisher
collection={collectionData}
content={htmlContent}
onSuccess={(url) => {
// Handle successful publish
}}
onClose={() => {
// Handle modal close
}}
/>- API key management and persistence
- Draft/publish toggle
- Tag management
- Series support ("Bebop CMS")
- Error handling and loading states
- Success feedback
- Modal-based interface
- Uses Dev.to REST API
- Stores credentials in localStorage
- Updates collection with Dev.to URL on success
- Maintains consistent styling with shadcn/ui components
- Handles both draft and published states
- Supports comma-separated tag input
- Dev.to API key from user settings
- API endpoint configuration in your environment
- Collection model with devToUrl field
- Consistent with Bebop's design system
- Uses shadcn/ui Card components
- Maintains dark/light mode support
- Modal overlay with proper z-indexing
The HashnodePublisher component enables collections to be published directly to Hashnode from within Bebop.
import { HashnodePublisher } from '@/components/HashnodePublisher';
<HashnodePublisher
collection={collectionData}
content={markdownContent}
onSuccess={(url) => {
// Handle successful publish
}}
onClose={() => {
// Handle modal close
}}
/>- Personal Access Token management
- Publication ID targeting
- GraphQL mutation handling
- Error handling and loading states
- Success feedback
- Modal-based interface
- Uses Hashnode GraphQL API
- Stores credentials in localStorage
- Updates collection with Hashnode URL on success
- Maintains consistent styling with shadcn/ui components
- Supports direct publication targeting
- Automatic tag assignment
- Hashnode Personal Access Token
- Valid Publication ID from Hashnode
- Collection model with hashnodeUrl field
mutation PublishPost(
$title: String!
$contentMarkdown: String!
$publicationId: ObjectId!
$tags: [PublishPostTagInput!]!
) {
publishPost(
input: {
title: $title
contentMarkdown: $contentMarkdown
publicationId: $publicationId
tags: $tags
}
) {
post {
id
url
}
}
}- Consistent with Bebop's design system
- Uses shadcn/ui Card components
- Maintains dark/light mode support
- Modal overlay with proper z-indexing
The Media component provides a complete media library interface for managing images.
import Media from '@/components/Media';
export default function MediaPage() {
return <Media pathname="/media" />;
}-
Media Management
- Image upload with validation
- Grid-based gallery view
- File information display
- URL copying
- Image deletion
- S3 integration
-
Upload Dialog
- File selection
- Size validation (5MB limit)
- Type validation (images only)
- Progress indication
- Error handling
-
Gallery Display
- Responsive grid layout
- Image thumbnails
- File metadata
- Action menus
- Empty state handling
- File Handling
// Size formatting
const size = formatFileSize(fileInBytes);
// Upload handling
const formData = new FormData();
formData.append('file', selectedFile);- API Integration
// Upload
POST /api/media
// Delete
DELETE /api/media/[id]
// Refresh
await refreshMedia();- Components Used
- Dialog for upload modal
- Card for media items
- DropdownMenu for actions
- Alert for errors
- Button for actions
- Gallery Grid
.grid {
grid-cols-1 md:grid-cols-3 lg:grid-cols-4
gap-6
}- Media Cards
- Hover shadow effects
- Aspect ratio maintenance
- Thumbnail fitting
- Dark mode support
- S3 bucket setup
- API routes for media handling
- MongoDB for media tracking
- Environment variables for S3
Bebop includes comprehensive image support throughout the application:
- Direct image uploads from the markdown editor
- AWS S3 storage backend
- Automatic URL generation
- File type and size validation
- Toolbar button for image uploads
- Markdown syntax generation
- Live preview with image rendering
- Support for alt text
Images are fully supported in all publishing formats:
- Web preview
- Published pages
- Platform exports (Hashnode, Dev.to)
- Both light and dark mode support
- Set up AWS S3:
AWS_REGION=your-region
AWS_ACCESS_KEY_ID=your-key
AWS_SECRET_ACCESS_KEY=your-secret
AWS_BUCKET_NAME=your-bucket- Configure S3 CORS:
{
"CORSRules": [
{
"AllowedHeaders": ["*"],
"AllowedMethods": ["GET", "PUT", "POST"],
"AllowedOrigins": ["http://localhost:3000", "your-domain.com"],
"ExposeHeaders": []
}
]
}- Ensure your bucket has proper public read access for uploaded files.
See the components documentation for more implementation details.