{"id":51597124,"url":"https://github.com/ishanshrestha14/unifiy","last_synced_at":"2026-07-11T19:33:35.942Z","repository":{"id":336924913,"uuid":"1119268416","full_name":"ishanshrestha14/unifiy","owner":"ishanshrestha14","description":"A collaborative whiteboard application built on Excalidraw with integrated code editing capabilities.","archived":false,"fork":false,"pushed_at":"2026-02-12T21:59:46.000Z","size":1346,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-11T19:33:35.309Z","etag":null,"topics":["excalidraw","postgresql","react","supabase","tailwindcss","typescript"],"latest_commit_sha":null,"homepage":"https://unifiy.vercel.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ishanshrestha14.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-19T02:38:38.000Z","updated_at":"2026-02-12T21:59:50.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ishanshrestha14/unifiy","commit_stats":null,"previous_names":["pin3appl3ishan/unifiy","ishanshrestha14/unifiy"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ishanshrestha14/unifiy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ishanshrestha14%2Funifiy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ishanshrestha14%2Funifiy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ishanshrestha14%2Funifiy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ishanshrestha14%2Funifiy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ishanshrestha14","download_url":"https://codeload.github.com/ishanshrestha14/unifiy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ishanshrestha14%2Funifiy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35374165,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-11T02:00:05.354Z","response_time":104,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["excalidraw","postgresql","react","supabase","tailwindcss","typescript"],"created_at":"2026-07-11T19:33:35.756Z","updated_at":"2026-07-11T19:33:35.924Z","avatar_url":"https://github.com/ishanshrestha14.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"/public/images/uni_cover.png\" alt=\"U\u0026I Cover Page\" width=\"800\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/React-19-blue?logo=react\" alt=\"React\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/TypeScript-5.6-blue?logo=typescript\" alt=\"TypeScript\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Vite-5-purple?logo=vite\" alt=\"Vite\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Supabase-PostgreSQL-green?logo=supabase\" alt=\"Supabase\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Tailwind_CSS-3.4-blue?logo=tailwindcss\" alt=\"Tailwind CSS\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Vercel-Deployed-black?logo=vercel\" alt=\"Vercel Deployment\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/License-MIT-yellow.svg\" alt=\"MIT License\" /\u003e\n\u003c/p\u003e\n\n\u003cdiv\u003e\n \u003ch3 align=\"center\"\u003eU\u0026I - Ideate. Code. Create\u003c/h3\u003e\n\n\u003e A collaborative whiteboard application live on [unifii.vercel.app](https://unifiy.vercel.app) with integrated code editing capabilities. Sketch ideas, write code, and organize your creative workflow - all on one infinite canvas.\n\n\u003c/div\u003e\n\n\u003e **Live Demo** - [unifii.vercel.app](https://unifiy.vercel.app)\n\n## Table of Contents\n\n- [Features](#features)\n- [Tech Stack](#tech-stack)\n- [Architecture](#architecture)\n- [Getting Started](#getting-started)\n- [Project Structure](#project-structure)\n- [Environment Variables](#environment-variables)\n- [Database Schema](#database-schema)\n- [Routes](#routes)\n- [Keyboard Shortcuts](#keyboard-shortcuts)\n- [Scripts](#scripts)\n- [Contributing](#contributing)\n- [License](#license)\n\n---\n\n## Features\n\n### Canvas \u0026 Drawing\n\n- Infinite whiteboard powered by Excalidraw\n- Dark and light mode support\n- Auto-save with debounced writes\n- Scene renaming (double-click the title)\n\n### CodePad - Code on the Canvas\n\n- Embedded code editor widgets powered by CodeMirror 6\n- **Multi-language support** - JavaScript, Python, HTML, CSS, JSON, Java, Markdown\n- Draggable and resizable editor windows\n- Minimize, maximize, and close controls\n- Copy-to-clipboard for code snippets\n- Tier-based limits: Free users get up to 3 CodePads per scene\n\n### Authentication \u0026 User Management\n\n- Anonymous mode - start drawing immediately, data saved to localStorage\n- Email/password authentication via Supabase Auth\n- Automatic data migration from localStorage to your account on sign-up\n- Guided onboarding flow for new users\n\n### Workspaces \u0026 Scenes\n\n- Organize scenes into workspaces\n- Create, rename, and delete scenes from the dashboard\n- Switch between workspaces with the workspace switcher\n- Tier-based workspace limits (Free: 1 workspace, Premium: unlimited)\n\n### Sharing\n\n- Generate view-only share links with secure UUID tokens\n- Public access to shared scenes - no login required\n- Revoke share links at any time\n- Copy-to-clipboard share URLs\n\n### Landing Page\n\n- Animated marketing page with Framer Motion\n- Hero section, feature highlights, integration showcase, and bento grid layout\n- Responsive design across all breakpoints\n\n---\n\n## Tech Stack\n\n| Layer                | Technology                                        |\n| -------------------- | ------------------------------------------------- |\n| **Framework**        | React 19 + TypeScript                             |\n| **Build Tool**       | Vite 5                                            |\n| **Canvas**           | Excalidraw 0.18                                   |\n| **Code Editor**      | CodeMirror 6                                      |\n| **State Management** | Zustand 5 (with persist middleware)               |\n| **Backend / Auth**   | Supabase (PostgreSQL + Auth + Row Level Security) |\n| **Styling**          | Tailwind CSS 3.4                                  |\n| **Animations**       | Framer Motion                                     |\n| **Routing**          | React Router 7                                    |\n| **Icons**            | Lucide React                                      |\n| **Toasts**           | Sonner                                            |\n| **Deployment**       | Vercel                                            |\n\n---\n\n## Architecture\n\nU\u0026I uses a **dual-mode architecture** to support both anonymous and authenticated users:\n\n```mermaid\nflowchart TD\n    subgraph App[\"React Application\"]\n        direction TB\n\n        subgraph Anonymous[\"Anonymous User Flow\"]\n            LS[\"localSceneStore\n            (Zustand + persist)\"]\n            LOCAL[(\"localStorage\")]\n            LS \u003c--\u003e LOCAL\n        end\n\n        subgraph Authenticated[\"Authenticated User Flow\"]\n            SS[\"sceneStore\"]\n            WS[\"workspaceStore\"]\n            AS[\"authStore\"]\n        end\n\n        subgraph Canvas[\"Whiteboard Component\"]\n            EX[\"Excalidraw\n            (Canvas)\"]\n            CP[\"CodePad Overlays\n            (CodeMirror 6)\"]\n        end\n\n        Anonymous -- \"migrate on\n        sign-up\" --\u003e Authenticated\n        Canvas --\u003e Anonymous\n        Canvas --\u003e Authenticated\n    end\n\n    Authenticated \u003c-- \"REST API\n    (Auth + CRUD)\" --\u003e SB\n\n    subgraph SB[\"Supabase\"]\n        AUTH[\"Auth\n        (JWT sessions)\"]\n        DB[(\"PostgreSQL + RLS\")]\n        AUTH --- DB\n    end\n```\n\n**Anonymous users** start drawing immediately. All data persists in the browser via `localSceneStore` (Zustand with persist middleware). When a user signs up, the onboarding flow automatically migrates their local work into Supabase.\n\n**Authenticated users** get full access to workspaces, multiple scenes, sharing, and cloud persistence through `sceneStore` and `workspaceStore`, both backed by Supabase with Row Level Security.\n\n---\n\n## Getting Started\n\n### Prerequisites\n\n- [Node.js](https://nodejs.org/) v18+\n- npm\n- A [Supabase](https://supabase.com/) project (for authentication and cloud storage)\n\n### Installation\n\n```bash\n# Clone the repository\ngit clone https://github.com/Pin3appl3ishan/unifiy.git\ncd unifiy\n\n# Install dependencies\nnpm install\n\n# Create a .env file with your Supabase credentials (see Environment Variables below)\n\n# Start the development server\nnpm run dev\n```\n\nThe app will open at **http://localhost:3000**.\n\n---\n\n## Project Structure\n\n```\nsrc/\n├── components/\n│   ├── CodePad/\n│   │   └── CodePad.tsx              # CodeMirror editor widget (drag, resize, minimize)\n│   ├── Landing/\n│   │   ├── Navbar.tsx               # Navigation bar with auth links\n│   │   ├── Hero.tsx                 # Animated hero section\n│   │   ├── Integrations.tsx         # Tool/feature showcase\n│   │   ├── FeatureSection.tsx       # Alternating feature highlights\n│   │   ├── BentoGrid.tsx            # Grid layout for benefits\n│   │   ├── Footer.tsx               # Site footer\n│   │   └── index.ts                 # Barrel export\n│   ├── Onboarding/\n│   │   └── OnboardingModal.tsx      # New user welcome + data migration\n│   ├── ShareModal/\n│   │   └── ShareModal.tsx           # Share link generation and management\n│   ├── Whiteboard/\n│   │   └── Whiteboard.tsx           # Excalidraw + CodePad integration + auto-save\n│   ├── Workspace/\n│   │   └── CreateWorkspaceModal.tsx # Workspace creation form\n│   ├── WorkspaceSwitcher/\n│   │   └── WorkspaceSwitcher.tsx    # Workspace dropdown selector\n│   ├── ui/\n│   │   ├── Skeleton.tsx             # Skeleton + Skeleton.Text + Skeleton.Circle\n│   │   ├── Spinner.tsx              # Spinner + PageSpinner\n│   │   ├── DashboardSkeleton.tsx    # Dashboard loading skeleton\n│   │   └── CanvasSkeleton.tsx       # Canvas loading skeleton\n│   ├── ErrorBoundary.tsx            # React error boundary (class component)\n│   ├── ErrorFallback.tsx            # Reusable error display with retry\n│   ├── ProtectedRoute.tsx           # Auth guard for protected routes\n│   └── index.ts                     # Barrel export\n├── pages/\n│   ├── Canvas.tsx                   # Main canvas (anonymous + authenticated)\n│   ├── Dashboard.tsx                # Scene management dashboard\n│   ├── Landing.tsx                  # Marketing landing page\n│   ├── Login.tsx                    # Login page\n│   ├── Signup.tsx                   # Registration page\n│   └── SharedScene.tsx              # Public shared scene viewer\n├── stores/\n│   ├── authStore.ts                 # Authentication + user profiles + onboarding\n│   ├── localSceneStore.ts           # Anonymous user data (localStorage via persist)\n│   ├── sceneStore.ts                # Remote scene CRUD + sharing (Supabase)\n│   └── workspaceStore.ts            # Workspace management\n├── lib/\n│   ├── supabase.ts                  # Supabase client configuration\n│   ├── errors.ts                    # Custom error classes (AppError, AuthError, NetworkError, etc.)\n│   └── logger.ts                    # Structured error logging utility\n├── types/\n│   └── index.ts                     # Centralized shared interfaces and types\n├── constants/\n│   └── index.ts                     # Magic numbers, strings, toast messages, limits\n├── styles/\n│   └── index.css                    # Tailwind + custom styles\n├── App.tsx                          # Route configuration + lazy loading\n└── main.tsx                         # Entry point + ErrorBoundary + Toaster\n```\n\n---\n\n## Environment Variables\n\nCreate a `.env` file in the project root:\n\n```env\nVITE_SUPABASE_URL=https://your-project.supabase.co\nVITE_SUPABASE_ANON_KEY=your-anon-key\n```\n\nYou can find these values in your [Supabase project settings](https://app.supabase.com/) under **Settings \u003e API**.\n\n---\n\n## Database Schema\n\nThe application uses three core tables in Supabase with Row Level Security enabled:\n\n```mermaid\nerDiagram\n    profiles ||--o{ workspaces : \"owns\"\n    workspaces ||--o{ scenes : \"contains\"\n\n    profiles {\n        uuid id PK \"references auth.users.id\"\n        text tier \"free | premium\"\n        uuid current_workspace_id FK\n        boolean onboarding_complete\n    }\n\n    workspaces {\n        uuid id PK\n        uuid owner_id FK \"references profiles.id\"\n        text name\n        timestamptz created_at\n        timestamptz updated_at\n    }\n\n    scenes {\n        uuid id PK\n        uuid workspace_id FK \"references workspaces.id\"\n        text name\n        jsonb excalidraw_data \"Excalidraw canvas state\"\n        jsonb codepads \"Array of CodePad objects\"\n        uuid share_token \"nullable — for share links\"\n        text share_permission \"none | view | edit\"\n        timestamptz created_at\n        timestamptz updated_at\n    }\n```\n\n---\n\n## Routes\n\n| Route                           | Auth | Description                                               |\n| ------------------------------- | ---- | --------------------------------------------------------- |\n| `/`                             | No   | Anonymous canvas (redirects to `/workspace` if logged in) |\n| `/landing`                      | No   | Marketing landing page                                    |\n| `/login`                        | No   | Login page                                                |\n| `/signup`                       | No   | Registration page                                         |\n| `/scene/:sceneId/shared/:token` | No   | Public shared scene (view-only)                           |\n| `/workspace`                    | Yes  | Dashboard — manage scenes and workspaces                  |\n| `/scene/:id`                    | Yes  | Scene editor (authenticated)                              |\n\n---\n\n## Keyboard Shortcuts\n\n| Shortcut               | Action                          |\n| ---------------------- | ------------------------------- |\n| `Ctrl/Cmd + Shift + C` | Add a new CodePad to the canvas |\n\nAll standard Excalidraw keyboard shortcuts are also available on the canvas.\n\n---\n\n## Scripts\n\n```bash\nnpm run dev       # Start development server on port 3000\nnpm run build     # Type-check with tsc, then build for production\nnpm run preview   # Preview the production build locally\nnpm run lint      # Run TypeScript type checking (tsc --noEmit)\n```\n\n---\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/your-feature`)\n3. Commit your changes (`git commit -m 'Add your feature'`)\n4. Push to the branch (`git push origin feature/your-feature`)\n5. Open a Pull Request\n\n---\n\n## License\n\nThis project is licensed under the [MIT License](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fishanshrestha14%2Funifiy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fishanshrestha14%2Funifiy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fishanshrestha14%2Funifiy/lists"}