Skip to content

samanr/google-doc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Google Doc Clone

A real-time collaborative document editor built with React 19, TipTap, Yjs, and Liveblocks.

Features

  • Rich text editing — bold, italic, underline, strikethrough, font family, font size, text colour, highlight, headings, bullet and ordered lists, text alignment
  • Images — insert local images via file picker
  • Tables — insert and manage tables with contextual row/column controls
  • Real-time collaboration — up to 5 users per document with live cursors and named presence
  • Auto-save — document state persisted automatically via Liveblocks (debounced 1s after last edit)
  • Share via link — each document has a unique URL; share it to invite collaborators
  • Static header and footer — displays document title and date (header), doc ID and page number (footer)
  • Accessible toolbar — SVG icons with tooltips on every button, ARIA roles and labels throughout, keyboard-navigable

Tech Stack

Concern Library
UI framework React 19 + Vite 6
Rich text editor TipTap 3 (ProseMirror)
Collaboration (CRDT) Yjs
Real-time relay + persistence Liveblocks
Routing React Router 7
Styling CSS Modules
Testing Vitest + React Testing Library

Getting Started

Prerequisites

  • Node.js 18+
  • A Liveblocks account (free tier is sufficient)

Installation

git clone <repo-url>
cd google-doc
npm install

Environment variables

Create a .env.local file in the project root:

VITE_LIVEBLOCKS_PUBLIC_KEY=pk_your_key_here

Get your public key from the Liveblocks dashboard under API Keys.

Running locally

npm run dev

Open http://localhost:5173. Create a new document from the home page, or navigate directly to /doc/<any-id>.

Sharing a document

Copy the URL from your browser and send it to a collaborator. Up to 5 users can edit the same document simultaneously.

Scripts

Command Description
npm run dev Start the Vite dev server
npm run build Production build
npm run preview Preview the production build locally
npm test Run tests in watch mode
npm run coverage Run tests with V8 coverage report

Project Structure

src/
├── components/
│   ├── AlignmentGroup/       Text alignment buttons
│   ├── ColorSwatch/          Text colour and highlight pickers
│   ├── DocFooter/            Static page footer
│   ├── DocHeader/            Static page header
│   ├── EditorProvider/       Wires editor, presence, auto-save
│   ├── FontFamilySelect/     Font family dropdown
│   ├── FontSizeSelect/       Font size dropdown
│   ├── HeadingSelect/        Heading level dropdown
│   ├── ImageButton/          Image file picker
│   ├── ListButtons/          Bullet and ordered list toggles
│   ├── PageCanvas/           A4-style document canvas
│   ├── PresenceBar/          Connected users and sync status
│   ├── SaveStatus/           Auto-save indicator
│   ├── TableControls/        Insert and manage tables
│   ├── Toolbar/              Full formatting toolbar
│   ├── ToolbarButton/        Accessible toggle button primitive
│   ├── ToolbarDivider/       Visual separator
│   └── icons/                Inline SVG icon components
├── extensions/
│   └── fontSize.js           Re-exports FontSize from @tiptap/extension-text-style
├── hooks/
│   ├── useAutoSave.js        Debounced save-status from Yjs update events
│   ├── useCollabEditor.js    TipTap editor with all extensions wired up
│   ├── useDoc.js             Yjs doc + LiveblocksYjsProvider lifecycle
│   └── useIdentity.js        Persistent random display name + colour
├── lib/
│   └── liveblocks.js         Liveblocks client and room context
├── pages/
│   ├── EditorPage/           Document route (/doc/:docId)
│   ├── HomePage/             Landing page with new-doc button
│   └── RoomFullPage/         Shown when > 5 users join a room
└── test/
    └── setup.js              Vitest + jest-dom setup

Test Coverage

All source files maintain 100% coverage (statements, branches, functions, lines) enforced via Vitest's V8 provider with thresholds set in vite.config.js.

All files  | 100% Stmts | 100% Branch | 100% Funcs | 100% Lines

Notes

  • Images are session-local. Inserted images use URL.createObjectURL, which means they are not synced to other collaborators and do not survive a page refresh. A backend storage layer would be required for persistent image sharing.
  • Identity is browser-local. Each user's display name and cursor colour are generated randomly on first visit and stored in localStorage. Clearing storage resets the identity.
  • Room capacity is enforced client-side at 5 users via Liveblocks presence. This is a soft limit suitable for a prototype.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors