Draftly is a privacy-first, offline-capable block editor and document organizer designed for seamless writer workflows. All your documents are stored directly in your browser — no account, no server, no internet connection required for writing. Your work remains on your device.
Behind its clean UI lies a rigorous implementation of Clean Architecture, SOLID Principles, and proven Design Patterns entirely decoupled from the React UI layer.
📥 Installable & Offline-Capable. Look for the download icon in your browser's address bar to install Draftly. After the first visit, it works with or without an internet connection. All data is stored locally in your browser.
Instead of tightly coupling business logic to React components and hooks, Draftly employs a Layered Clean Architecture where dependencies point strictly inward toward the Domain.
- Presentation Layer (React): Pure UI components and hooks (
useDraftlyEngine). Zero business logic or storage calls exist here. - Application Layer (Services & Facade): Orchestrates use cases (
DocumentService,EditorService). Exposes a singleDraftlyEngineFacade to the UI, hiding all system complexity. - Domain Layer (Entities & Business Rules): The core of the application. Pure TypeScript classes (
Block,Document,Folder) with absolutely no dependencies on React, Next.js, or LocalStorage. - Infrastructure Layer (Data & Integrations): Handles external concerns. Implements the Domain's
DocumentRepositoryinterface using aLocalStorageAdapter. Can be trivially swapped to Firebase or Supabase without altering the core app.
- Facade Pattern:
DraftlyEngineprovides a unified, simplified interface for the React UI. - Strategy Pattern: The Export pipeline uses
ExportStrategy(implemented byMarkdownExportStrategy,PdfExportStrategy, etc.), allowing new formats to be added following the Open/Closed Principle. - Command Pattern: Editor interactions (inserting, deleting, moving blocks) are encapsulated into
ICommandobjects (InsertBlockCommand), enabling robust Undo/Redo history stacks. - Factory Pattern:
BlockFactorydynamically instantiates the correct Block entity (HeadingBlock,CodeBlock, etc.) to eliminate massive switch statements. - Observer Pattern: A
GlobalEventBushandles reactivity. When theEditorServicemodifies a block, it publishes an event that the UI andAutoSaveObserverreact to asynchronously. - Repository & Adapter Pattern: The data layer is abstracted behind strict interfaces, ensuring the Domain never knows how data is saved.
We have generated comprehensive Mermaid UML diagrams documenting the system's structural and behavioral design: 👉 View the Architectural UML Diagrams in ARCHITECTURE.md
- Hierarchical Folders: Create unlimited nested subdirectories (
FolderinsideFolder). - Visual Directory Tree: Rendered recursively with vertical connection lines, indent levels, and smooth transitions.
- Cycle-Safe Drag-and-Drop: Safely move files and subfolders in/out of nested paths without creating dependency loops.
- Press & Hold to Delete: A custom touch-gesture tracker designed to let mobile users press and hold any editor block to trigger visual delete overlays.
- Haptic Feedback: Integrates with mobile device vibration motors (
navigator.vibrate) for satisfying physical confirmations.
- Contextual Menu: Triggered by pressing
/in any empty text block. - Block Conversion: Easily switch block types to Headings, Bullet Lists, Code Blocks, or Quote Blocks instantly.
- LocalStorage Persistence: All data is strictly persisted to the browser's
localStoragevia the Infrastructure Adapter. - PWA-Ready: Registers a Service Worker in production mode, enabling full offline access after the first visit.
- Export documents to clean Markdown, PDF, or DOCX with one click — all generated client-side through the Strategy pipeline.
Make sure you have Node.js (version 18+) and npm installed on your system.
git clone https://github.com/puneetnith28/draftly.git
cd draftlynpm installVerify the Domain, Application, and Infrastructure layers using the Jest suite:
npm run testnpm run devOpen http://localhost:3000 in your browser.