diff --git a/.gitignore b/.gitignore index 3c3629e..2d5f545 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ node_modules +frontend/src/assets/fontawesome/svg/* +frontend/src/assets/fontawesome/svg/0.svg diff --git a/backend/app/__pycache__/auth.cpython-314.pyc b/backend/app/__pycache__/auth.cpython-314.pyc new file mode 100644 index 0000000..4e8d24e Binary files /dev/null and b/backend/app/__pycache__/auth.cpython-314.pyc differ diff --git a/backend/app/__pycache__/main.cpython-314.pyc b/backend/app/__pycache__/main.cpython-314.pyc index 1c5498b..ab30837 100644 Binary files a/backend/app/__pycache__/main.cpython-314.pyc and b/backend/app/__pycache__/main.cpython-314.pyc differ diff --git a/backend/app/__pycache__/models.cpython-314.pyc b/backend/app/__pycache__/models.cpython-314.pyc index b6ce6ea..00bb4e2 100644 Binary files a/backend/app/__pycache__/models.cpython-314.pyc and b/backend/app/__pycache__/models.cpython-314.pyc differ diff --git a/backend/app/auth.py b/backend/app/auth.py new file mode 100644 index 0000000..fec6785 --- /dev/null +++ b/backend/app/auth.py @@ -0,0 +1,71 @@ +import secrets +from datetime import datetime, timedelta +from typing import Optional + +import bcrypt # Use bcrypt directly instead of passlib +from fastapi import Cookie, Depends, HTTPException, Request, status +from sqlmodel import Session, select + +from app.database import get_session +from app.models import Session as SessionModel +from app.models import User + + +# Password hashing with bcrypt directly +def hash_password(password: str) -> str: + password_bytes = password.encode("utf-8") + salt = bcrypt.gensalt() + hashed = bcrypt.hashpw(password_bytes, salt) + return hashed.decode("utf-8") + + +def verify_password(plain_password: str, hashed_password: str) -> bool: + password_bytes = plain_password.encode("utf-8") + hashed_bytes = hashed_password.encode("utf-8") + return bcrypt.checkpw(password_bytes, hashed_bytes) + + +# Session management +def create_session( + user_id: int, request: Request, db: Session, expires_in_days: int = 30 +) -> str: + session_id = secrets.token_urlsafe(32) + expires_at = datetime.utcnow() + timedelta(days=expires_in_days) + + db_session = SessionModel( + session_id=session_id, + user_id=user_id, + expires_at=expires_at, + ip_address=request.client.host, + user_agent=request.headers.get("user-agent"), + ) + db.add(db_session) + db.commit() + + return session_id + + +def get_session_user(session_id: Optional[str], db: Session) -> Optional[User]: + if not session_id: + return None + + session = db.exec( + select(SessionModel).where(SessionModel.session_id == session_id) + ).first() + + if not session or session.expires_at < datetime.utcnow(): + return None + + return session.user + + +# Dependency for protected routes +async def require_auth( + session_id: Optional[str] = Cookie(None), db: Session = Depends(get_session) +) -> User: + user = get_session_user(session_id, db) + if not user: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, detail="Not authenticated" + ) + return user diff --git a/backend/app/main.py b/backend/app/main.py index 0ce9249..728376a 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -2,7 +2,7 @@ from fastapi import FastAPI # type: ignore from fastapi.middleware.cors import CORSMiddleware # type:ignore from app.database import create_db_and_tables -from app.routes import folders, notes +from app.routes import auth, folders, notes app = FastAPI(title="Notes API") @@ -23,6 +23,7 @@ def on_startup(): app.include_router(notes.router, prefix="/api") app.include_router(folders.router, prefix="/api") +app.include_router(auth.router, prefix="/api") @app.get("/") diff --git a/backend/app/models.py b/backend/app/models.py index a01a0dc..afeafa9 100644 --- a/backend/app/models.py +++ b/backend/app/models.py @@ -4,11 +4,39 @@ from typing import List, Optional from sqlmodel import Field, Relationship, SQLModel # type: ignore +class User(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + username: str = Field(unique=True, index=True) + email: str = Field(unique=True, index=True) + hashed_password: str + salt: str + wrapped_master_key: str + created_at: datetime = Field(default_factory=datetime.utcnow) + + # Add relationships to existing models + notes: List["Note"] = Relationship(back_populates="user") + folders: List["Folder"] = Relationship(back_populates="user") + sessions: List["Session"] = Relationship(back_populates="user") + + +class Session(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + session_id: str = Field(unique=True, index=True) + user_id: int = Field(foreign_key="user.id") + created_at: datetime = Field(default_factory=datetime.utcnow) + expires_at: datetime + ip_address: Optional[str] = None + user_agent: Optional[str] = None + + user: User = Relationship(back_populates="sessions") + + class Folder(SQLModel, table=True): # type: ignore id: Optional[int] = Field(default=None, primary_key=True) name: str = Field(max_length=255) parent_id: Optional[int] = Field(default=None, foreign_key="folder.id") created_at: datetime = Field(default_factory=datetime.utcnow) + user_id: int = Field(foreign_key="user.id") # Relationships parent: Optional["Folder"] = Relationship( @@ -16,6 +44,7 @@ class Folder(SQLModel, table=True): # type: ignore ) children: List["Folder"] = Relationship(back_populates="parent") notes: List["Note"] = Relationship(back_populates="folder") + user: User = Relationship(back_populates="folders") class Note(SQLModel, table=True): # type: ignore @@ -25,8 +54,10 @@ class Note(SQLModel, table=True): # type: ignore folder_id: Optional[int] = Field(default=None, foreign_key="folder.id") created_at: datetime = Field(default_factory=datetime.utcnow) updated_at: datetime = Field(default_factory=datetime.utcnow) + user_id: int = Field(foreign_key="user.id") folder: Optional[Folder] = Relationship(back_populates="notes") + user: User = Relationship(back_populates="notes") # API Response models (what gets sent to frontend) diff --git a/backend/app/routes/__pycache__/auth.cpython-314.pyc b/backend/app/routes/__pycache__/auth.cpython-314.pyc new file mode 100644 index 0000000..e881b11 Binary files /dev/null and b/backend/app/routes/__pycache__/auth.cpython-314.pyc differ diff --git a/backend/app/routes/__pycache__/folders.cpython-314.pyc b/backend/app/routes/__pycache__/folders.cpython-314.pyc index ab040a2..5075343 100644 Binary files a/backend/app/routes/__pycache__/folders.cpython-314.pyc and b/backend/app/routes/__pycache__/folders.cpython-314.pyc differ diff --git a/backend/app/routes/__pycache__/notes.cpython-314.pyc b/backend/app/routes/__pycache__/notes.cpython-314.pyc index adec199..9098d40 100644 Binary files a/backend/app/routes/__pycache__/notes.cpython-314.pyc and b/backend/app/routes/__pycache__/notes.cpython-314.pyc differ diff --git a/backend/app/routes/auth.py b/backend/app/routes/auth.py new file mode 100644 index 0000000..18440eb --- /dev/null +++ b/backend/app/routes/auth.py @@ -0,0 +1,166 @@ +from datetime import datetime +from typing import Optional + +from fastapi import APIRouter, Cookie, Depends, HTTPException, Request, Response +from sqlmodel import Session, SQLModel, select + +from app.auth import create_session, hash_password, require_auth, verify_password +from app.database import get_session +from app.models import Session as SessionModel +from app.models import User + +router = APIRouter(prefix="/auth", tags=["auth"]) + + +# Request/Response models +class RegisterRequest(SQLModel): + username: str + email: str + password: str + salt: str + wrappedMasterKey: str + + +class LoginRequest(SQLModel): + username: str + password: str + + +class UserResponse(SQLModel): + id: int + username: str + email: str + salt: str # Client needs this for key derivation + wrapped_master_key: str # Client needs this to unwrap the master key + + +@router.post("/register") +def register( + data: RegisterRequest, + request: Request, + response: Response, + db: Session = Depends(get_session), +): + # Check existing user + existing = db.exec( + select(User).where( + (User.username == data.username) | (User.email == data.email) + ) + ).first() + + if existing: + raise HTTPException(status_code=400, detail="User already exists") + + # Create user + user = User( + username=data.username, + email=data.email, + hashed_password=hash_password(data.password), + salt=data.salt, + wrapped_master_key=data.wrappedMasterKey, + ) + db.add(user) + db.commit() + db.refresh(user) + + # Create session + assert user.id is not None + session_id = create_session(user.id, request, db) + + # Set cookie + response.set_cookie( + key="session_id", + value=session_id, + httponly=True, + secure=True, # HTTPS only in production + samesite="lax", + max_age=30 * 24 * 60 * 60, # 30 days + ) + + return {"user": UserResponse.model_validate(user)} + + +@router.post("/login") +def login( + data: LoginRequest, + request: Request, + response: Response, + db: Session = Depends(get_session), +): + # Find user + user = db.exec(select(User).where(User.username == data.username)).first() + + if not user or not verify_password(data.password, user.hashed_password): + raise HTTPException(status_code=401, detail="Invalid credentials") + + # Create session + assert user.id is not None + session_id = create_session(user.id, request, db) + + # Set cookie + response.set_cookie( + key="session_id", + value=session_id, + httponly=True, + secure=True, + samesite="lax", + max_age=30 * 24 * 60 * 60, + ) + + return {"user": UserResponse.model_validate(user)} + + +@router.post("/logout") +def logout( + response: Response, + session_id: Optional[str] = Cookie(None), + db: Session = Depends(get_session), +): + # Delete session from database + if session_id: + session = db.exec( + select(SessionModel).where(SessionModel.session_id == session_id) + ).first() + if session: + db.delete(session) + db.commit() + + # Clear cookie + response.delete_cookie("session_id") + return {"message": "Logged out"} + + +@router.get("/me") +def get_current_user(current_user: User = Depends(require_auth)): + return {"user": UserResponse.from_orm(current_user)} + + +@router.get("/sessions") +def list_sessions( + current_user: User = Depends(require_auth), db: Session = Depends(get_session) +): + sessions = db.exec( + select(SessionModel) + .where(SessionModel.user_id == current_user.id) + .where(SessionModel.expires_at > datetime.utcnow()) + ).all() + return {"sessions": sessions} + + +@router.delete("/sessions/{session_token}") # Renamed from session_id +def revoke_session( + session_token: str, # Renamed to avoid conflict with Cookie parameter + current_user: User = Depends(require_auth), + db: Session = Depends(get_session), +): + session = db.exec( + select(SessionModel) + .where(SessionModel.session_id == session_token) # Use renamed variable + .where(SessionModel.user_id == current_user.id) + ).first() + + if session: + db.delete(session) + db.commit() + + return {"message": "Session revoked"} diff --git a/backend/app/routes/folders.py b/backend/app/routes/folders.py index 02e1882..f77ea22 100644 --- a/backend/app/routes/folders.py +++ b/backend/app/routes/folders.py @@ -3,6 +3,7 @@ from typing import List from fastapi import APIRouter, Depends, HTTPException # type: ignore from sqlmodel import Session, select # type: ignore +from app.auth import require_auth from app.database import get_session from app.models import ( Folder, @@ -12,6 +13,7 @@ from app.models import ( FolderUpdate, Note, NoteRead, + User, ) router = APIRouter(prefix="/folders", tags=["folders"]) @@ -20,7 +22,7 @@ router = APIRouter(prefix="/folders", tags=["folders"]) def build_folder_tree_node(folder: Folder) -> FolderTreeNode: """Recursively build a folder tree node with notes and children""" return FolderTreeNode( - id=folder.id, + id=folder.id, # pyright: ignore[reportArgumentType] name=folder.name, notes=[NoteRead.model_validate(note) for note in folder.notes], children=[build_folder_tree_node(child) for child in folder.children], @@ -28,16 +30,24 @@ def build_folder_tree_node(folder: Folder) -> FolderTreeNode: @router.get("/tree", response_model=FolderTreeResponse) -def get_folder_tree(session: Session = Depends(get_session)): +def get_folder_tree( + current_user: User = Depends(require_auth), session: Session = Depends(get_session) +): """Get complete folder tree with notes""" - # Get all top-level folders (parent_id is None) + # Get all top-level folders (parent_id is None) for current user top_level_folders = session.exec( - select(Folder).where(Folder.parent_id == None) + select(Folder) + .where(Folder.parent_id == None) + .where(Folder.user_id == current_user.id) ).all() - # Get all orphaned notes (folder_id is None) - orphaned_notes = session.exec(select(Note).where(Note.folder_id == None)).all() + # Get all orphaned notes (folder_id is None) for current user + orphaned_notes = session.exec( + select(Note) + .where(Note.folder_id == None) + .where(Note.user_id == current_user.id) + ).all() # Build tree recursively tree = [build_folder_tree_node(folder) for folder in top_level_folders] @@ -56,9 +66,15 @@ def list_folders(session: Session = Depends(get_session)): @router.post("/", response_model=Folder) -def create_folder(folder: FolderCreate, session: Session = Depends(get_session)): +def create_folder( + folder: FolderCreate, + current_user: User = Depends(require_auth), + session: Session = Depends(get_session), +): """Create a new folder""" - db_folder = Folder.model_validate(folder) + folder_data = folder.model_dump() + folder_data["user_id"] = current_user.id + db_folder = Folder.model_validate(folder_data) session.add(db_folder) session.commit() session.refresh(db_folder) diff --git a/backend/app/routes/notes.py b/backend/app/routes/notes.py index 7828cfb..283168a 100644 --- a/backend/app/routes/notes.py +++ b/backend/app/routes/notes.py @@ -1,22 +1,30 @@ from datetime import datetime -from app.database import get_session -from app.models import Note, NoteCreate, NoteUpdate from fastapi import APIRouter, Depends, HTTPException from sqlmodel import Session, select +from app.auth import require_auth +from app.database import get_session +from app.models import Note, NoteCreate, NoteUpdate, User + router = APIRouter(prefix="/notes", tags=["notes"]) @router.get("/") def list_notes(session: Session = Depends(get_session)): - notes = session.exec(select(Note).order_by(Note.updated_at.desc())).all() + notes = session.exec(select(Note).order_by(Note.updated_at.desc())).all() # pyright: ignore[reportAttributeAccessIssue] return notes @router.post("/", response_model=Note) -def create_note(note: NoteCreate, session: Session = Depends(get_session)): - db_note = Note.model_validate(note) +def create_note( + note: NoteCreate, + current_user: User = Depends(require_auth), + session: Session = Depends(get_session), +): + note_data = note.model_dump() + note_data["user_id"] = current_user.id + db_note = Note.model_validate(note_data) session.add(db_note) session.commit() session.refresh(db_note) diff --git a/backend/notes.db b/backend/notes.db index 19604f6..04c85ac 100644 Binary files a/backend/notes.db and b/backend/notes.db differ diff --git a/backend/notes.sqbpro b/backend/notes.sqbpro new file mode 100644 index 0000000..fca50c8 --- /dev/null +++ b/backend/notes.sqbpro @@ -0,0 +1 @@ +
diff --git a/backend/pyproject.toml b/backend/pyproject.toml deleted file mode 100644 index 874cbff..0000000 --- a/backend/pyproject.toml +++ /dev/null @@ -1,3 +0,0 @@ -{ - "reportGeneralTypeIssues": "warning" -} diff --git a/frontend/package-lock.json b/frontend/package-lock.json index d0c83b3..01bbadb 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -14,12 +14,17 @@ "@mdxeditor/editor": "^3.49.3", "@tailwindcss/typography": "^0.5.19", "@tailwindcss/vite": "^4.1.17", + "@tiptap/extension-placeholder": "^3.12.1", + "@tiptap/react": "^3.12.1", + "@tiptap/starter-kit": "^3.12.1", "axios": "^1.13.2", + "framer-motion": "^12.23.25", "jszip": "^3.10.1", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^7.9.6", "tailwindcss": "^4.1.17", + "tiptap-markdown": "^0.9.0", "zustand": "^5.0.8" }, "devDependencies": { @@ -62,6 +67,7 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -638,6 +644,7 @@ "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.3.tgz", "integrity": "sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==", "license": "MIT", + "peer": true, "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.23.0", @@ -727,6 +734,7 @@ "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz", "integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==", "license": "MIT", + "peer": true, "dependencies": { "@marijn/find-cluster-break": "^1.0.0" } @@ -736,6 +744,7 @@ "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.38.8.tgz", "integrity": "sha512-XcE9fcnkHCbWkjeKyi0lllwXmBLtyYb5dt89dJyx23I9+LSh5vZDIuk7OLG4VM1lgrXZQcY6cxyZyk5WVPRv/A==", "license": "MIT", + "peer": true, "dependencies": { "@codemirror/state": "^6.5.0", "crelt": "^1.0.6", @@ -1219,6 +1228,7 @@ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", "license": "MIT", + "peer": true, "dependencies": { "@floating-ui/core": "^1.7.3", "@floating-ui/utils": "^0.2.10" @@ -1272,6 +1282,7 @@ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-7.1.0.tgz", "integrity": "sha512-fNxRUk1KhjSbnbuBxlWSnBLKLBNun52ZBTcs22H/xEEzM6Ap81ZFTQ4bZBxVQGQgVY0xugKGoRcCbaKjLQ3XZA==", "license": "MIT", + "peer": true, "dependencies": { "@fortawesome/fontawesome-common-types": "7.1.0" }, @@ -1636,6 +1647,7 @@ "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz", "integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==", "license": "MIT", + "peer": true, "dependencies": { "@lezer/common": "^1.3.0" } @@ -2666,6 +2678,12 @@ "react": ">=16.8" } }, + "node_modules/@remirror/core-constants": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz", + "integrity": "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==", + "license": "MIT" + }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-beta.27", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", @@ -3157,6 +3175,7 @@ "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/core": "^7.21.3", "@svgr/babel-preset": "8.1.0", @@ -3482,6 +3501,457 @@ "vite": "^5.2.0 || ^6 || ^7" } }, + "node_modules/@tiptap/core": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.12.1.tgz", + "integrity": "sha512-dn5uTnsTUjMze26iRhcus8+2auW9+/vOpk6suXg/lhBp+UzOM+EALKE3S5086ANJNgBh1PDHoBX+r1T7wEmheg==", + "license": "MIT", + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/pm": "^3.12.1" + } + }, + "node_modules/@tiptap/extension-blockquote": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-3.12.1.tgz", + "integrity": "sha512-RzuvfzpPG/bFJ2EOnui68QLLRk8E1qBLx4xdlApHjeuGFACyBWz+3Blpi2WhtYfpTslzav/mxQ//ZQu//eo6cA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.12.1" + } + }, + "node_modules/@tiptap/extension-bold": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-3.12.1.tgz", + "integrity": "sha512-ciSVsOMd/r7RoWKqRwSvzUAwUmnd1hIxdmWkjUhyKvErHNWuSgrMtK3rU+j3PadRQ+EaQ17ua9tMVj+2NdGzrg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.12.1" + } + }, + "node_modules/@tiptap/extension-bubble-menu": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.12.1.tgz", + "integrity": "sha512-RMhZbI+CmcEuGrKgMmHFXyGs/UdAQPBjW8wMEiZIqa2ZxnOwhMd79jRRTzLW7uhArzXMOe6hyytOHuEMvoj+NQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.12.1", + "@tiptap/pm": "^3.12.1" + } + }, + "node_modules/@tiptap/extension-bullet-list": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-3.12.1.tgz", + "integrity": "sha512-+ojn7q5X1VJJAhHKvmn4lis1d/1QtE87BcW0Kn0NUF8g0sGwoLgXkZWBzksbD4SD+OfqOHHnQDSnQkc3mG0Z3A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "^3.12.1" + } + }, + "node_modules/@tiptap/extension-code": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-3.12.1.tgz", + "integrity": "sha512-W6DNHcjh82PZAgOI5UUbljXpLcIwpHh/DNdRmwNKYNcq6UrKxECpLImmzZNO0QTOcoxWOXE/RYzj7JErNVcN3A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.12.1" + } + }, + "node_modules/@tiptap/extension-code-block": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-3.12.1.tgz", + "integrity": "sha512-hlLOWQmSDgPWzHujR1wPK82P83C3QcDiVKkjIkCsItwnKK8endJUtdvWDJji4ZJzFKHl8kr6eGzPJJ5/4Es0ew==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.12.1", + "@tiptap/pm": "^3.12.1" + } + }, + "node_modules/@tiptap/extension-document": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-3.12.1.tgz", + "integrity": "sha512-FHZZxzSluUdAxo8Q8iO1DOKzwDpQQhF+sIKni3T3UmE/AAhSWHWHQot5onrn6ypcrtYyuwQF4lDb/S2xbz9p8Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.12.1" + } + }, + "node_modules/@tiptap/extension-dropcursor": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-3.12.1.tgz", + "integrity": "sha512-Z6ugx7XfeAmNmK1WfPnA+Ohm2NCakTHTD1549++O/oeRhSOluRXZBAA2niHR3VACoKjZTKBrl41eBhrJsPS7XQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extensions": "^3.12.1" + } + }, + "node_modules/@tiptap/extension-floating-menu": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-3.12.1.tgz", + "integrity": "sha512-FY0QmubovOSnH8PhHH0pnmgXUQernfLMeHq2qT1B/itCDOeDULFrBQtZ5KTMAi522czuErW6s0d2EhJQlnazdw==", + "license": "MIT", + "optional": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@floating-ui/dom": "^1.0.0", + "@tiptap/core": "^3.12.1", + "@tiptap/pm": "^3.12.1" + } + }, + "node_modules/@tiptap/extension-gapcursor": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-3.12.1.tgz", + "integrity": "sha512-sXQASGES2+l8GKgZyuuqXFOkv9ncDOPuXWTSRvQZ66ZstOPttVemuGENpo+8wNwK2v9KqTOfyZBSj+xmAlnZdg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extensions": "^3.12.1" + } + }, + "node_modules/@tiptap/extension-hard-break": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-3.12.1.tgz", + "integrity": "sha512-hz3NmynK6vl05WUkXnEOlurrJ3fxrJTPTepu/sB3URHJ1GMghrfOeFBbLRrtz8BHhRg9EydCr42PMtglL1KyZw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.12.1" + } + }, + "node_modules/@tiptap/extension-heading": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-3.12.1.tgz", + "integrity": "sha512-zW2TuKdU4fYP/D4pPGGl5mVGsA8Lp3iSOGYZzZ4iFnBwdD8B24C+RS+gsYqZ+xtTZJOTJZyI2xgwljQLbS25xQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.12.1" + } + }, + "node_modules/@tiptap/extension-horizontal-rule": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.12.1.tgz", + "integrity": "sha512-SC30r1GGCuDK5AO54XLCvjMA/YQgrnYCqNB0wtoFAtamnCSTrxLDhSIFBnjrPkLEfMnjEo6EggGuWhBmekkCPA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.12.1", + "@tiptap/pm": "^3.12.1" + } + }, + "node_modules/@tiptap/extension-italic": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-3.12.1.tgz", + "integrity": "sha512-bqyoJRcAewX2/8yAjvfTIToHaHooLWduemh3qxSDkQT3dtK/m96Bn3Z7S3UMD6XoFR5x2K+oPe+nSjqbwKcGuw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.12.1" + } + }, + "node_modules/@tiptap/extension-link": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-3.12.1.tgz", + "integrity": "sha512-BmQEXokb7+5HSxkwL1n3kgJ7tgXFNdbVFZ6hD4zazrvcBJk+J0R/9QCrms8Js3uXoVqIlqBFcsuUmlz0Jq857g==", + "license": "MIT", + "dependencies": { + "linkifyjs": "^4.3.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.12.1", + "@tiptap/pm": "^3.12.1" + } + }, + "node_modules/@tiptap/extension-list": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.12.1.tgz", + "integrity": "sha512-v3WC9TR8QRVwmubuKjUplAXeTzTq2hiVKGHBbW15LTqqfsEJwt1YHUl/Sc+pSAeJfY7th5wheNfZFCsCBCW3qg==", + "license": "MIT", + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.12.1", + "@tiptap/pm": "^3.12.1" + } + }, + "node_modules/@tiptap/extension-list-item": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-3.12.1.tgz", + "integrity": "sha512-x+RdmN0NjHA2aJTPfqrAoonUdj319YliHj3ogH8MTwZllN8GY/oybaTEekVChwbS6M9dsRsaDEhyyFAnFAZUAw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "^3.12.1" + } + }, + "node_modules/@tiptap/extension-list-keymap": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-keymap/-/extension-list-keymap-3.12.1.tgz", + "integrity": "sha512-CjFVxTSQ08MQ38+w8gEhXP902Oy3jWZygciteYVrYNffYQ6LkxxtOwCp5cozyxKKGT57mHY+2Ys+8LRr8NyCYw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "^3.12.1" + } + }, + "node_modules/@tiptap/extension-ordered-list": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-3.12.1.tgz", + "integrity": "sha512-dv5xITknvb1UM5za/Vpx43+RY27trXYPUuTiSvKyKLqEWRJHhYQMrm2S7Bzwj2IpED3LM9vxocVn40YbJBWXRQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "^3.12.1" + } + }, + "node_modules/@tiptap/extension-paragraph": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-3.12.1.tgz", + "integrity": "sha512-vknowYpeCU8j025VgajzjBAsRQsUdGIHH4udekwL5D5Ss2jU5ax0w0urSHJzGaPtrujn6V359iBgFshl1cyxog==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.12.1" + } + }, + "node_modules/@tiptap/extension-placeholder": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-3.12.1.tgz", + "integrity": "sha512-JBRHMysfLE7fgK5kQoc4uVP7r4XVOUGT0x4BLysx5hIi1jvBk94ipZSZ8rHbb1F8F6BKlwecBt3VBGYQN9zKeg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extensions": "^3.12.1" + } + }, + "node_modules/@tiptap/extension-strike": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-3.12.1.tgz", + "integrity": "sha512-McG9jTR5R7Ta99Sa1Dbic0KoisBiYy7vi1pnrGp3BEMqMFWpfLsCzHg5CEgIXq4gXZ4t4YxPtIsFmsWwXD/cKw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.12.1" + } + }, + "node_modules/@tiptap/extension-text": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-3.12.1.tgz", + "integrity": "sha512-r9ToQJyWa+pHoTiEs2y7cmiVzhUOiV77ed1TE5OE5YqFruZO/lyeG2xuFX8qDADY3F2lSnUBSI2SH/FbYSQb3w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.12.1" + } + }, + "node_modules/@tiptap/extension-underline": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-3.12.1.tgz", + "integrity": "sha512-V/x3c0O1W99STnMnNuU3Pv7aI+za5muzpxwiBojV2p+yzmGFDduQZKRY5QohoxAFB/Fa46fvYS8DIrxbdsNVPg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.12.1" + } + }, + "node_modules/@tiptap/extensions": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.12.1.tgz", + "integrity": "sha512-Xtg2Ot3oebg6+ponJ3yp8VcxPtdaHaub62Eoh8DKvBexyfqp+lMDtOpJZXA9NImVG3gKn+5EAIq8kx5AtrVlJQ==", + "license": "MIT", + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.12.1", + "@tiptap/pm": "^3.12.1" + } + }, + "node_modules/@tiptap/pm": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.12.1.tgz", + "integrity": "sha512-YGv8uZrTraXzB3DPQYsyIB90Girx5QZdZOBSDj0R2bWSXc2Huqdb9PaulXqDQjEv/dp9x6w6+Q2VNIagCPUQwA==", + "license": "MIT", + "peer": true, + "dependencies": { + "prosemirror-changeset": "^2.3.0", + "prosemirror-collab": "^1.3.1", + "prosemirror-commands": "^1.6.2", + "prosemirror-dropcursor": "^1.8.1", + "prosemirror-gapcursor": "^1.3.2", + "prosemirror-history": "^1.4.1", + "prosemirror-inputrules": "^1.4.0", + "prosemirror-keymap": "^1.2.2", + "prosemirror-markdown": "^1.13.1", + "prosemirror-menu": "^1.2.4", + "prosemirror-model": "^1.24.1", + "prosemirror-schema-basic": "^1.2.3", + "prosemirror-schema-list": "^1.5.0", + "prosemirror-state": "^1.4.3", + "prosemirror-tables": "^1.6.4", + "prosemirror-trailing-node": "^3.0.0", + "prosemirror-transform": "^1.10.2", + "prosemirror-view": "^1.38.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + } + }, + "node_modules/@tiptap/react": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/react/-/react-3.12.1.tgz", + "integrity": "sha512-P6P5soxg0TqzyO5bDXLVdfO/64k4FVk6NAU9GJrRfg/94MasoId8AM7hqklIDtXEwil5dxfnlrCb3h2N/TKToA==", + "license": "MIT", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "fast-equals": "^5.3.3", + "use-sync-external-store": "^1.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "optionalDependencies": { + "@tiptap/extension-bubble-menu": "^3.12.1", + "@tiptap/extension-floating-menu": "^3.12.1" + }, + "peerDependencies": { + "@tiptap/core": "^3.12.1", + "@tiptap/pm": "^3.12.1", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "@types/react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tiptap/starter-kit": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-3.12.1.tgz", + "integrity": "sha512-DN/+1ajZaTGcg9vyaQt0dVJKRMNZT8LkncgZzfU5amU7hqUuBn1kGlm3mArx/90wG2RnLPs3KV03RBVibzBs+A==", + "license": "MIT", + "dependencies": { + "@tiptap/core": "^3.12.1", + "@tiptap/extension-blockquote": "^3.12.1", + "@tiptap/extension-bold": "^3.12.1", + "@tiptap/extension-bullet-list": "^3.12.1", + "@tiptap/extension-code": "^3.12.1", + "@tiptap/extension-code-block": "^3.12.1", + "@tiptap/extension-document": "^3.12.1", + "@tiptap/extension-dropcursor": "^3.12.1", + "@tiptap/extension-gapcursor": "^3.12.1", + "@tiptap/extension-hard-break": "^3.12.1", + "@tiptap/extension-heading": "^3.12.1", + "@tiptap/extension-horizontal-rule": "^3.12.1", + "@tiptap/extension-italic": "^3.12.1", + "@tiptap/extension-link": "^3.12.1", + "@tiptap/extension-list": "^3.12.1", + "@tiptap/extension-list-item": "^3.12.1", + "@tiptap/extension-list-keymap": "^3.12.1", + "@tiptap/extension-ordered-list": "^3.12.1", + "@tiptap/extension-paragraph": "^3.12.1", + "@tiptap/extension-strike": "^3.12.1", + "@tiptap/extension-text": "^3.12.1", + "@tiptap/extension-underline": "^3.12.1", + "@tiptap/extensions": "^3.12.1", + "@tiptap/pm": "^3.12.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -3560,6 +4030,22 @@ "@types/unist": "*" } }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "license": "MIT" + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "license": "MIT", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, "node_modules/@types/mdast": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", @@ -3569,6 +4055,12 @@ "@types/unist": "*" } }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "license": "MIT" + }, "node_modules/@types/ms": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", @@ -3579,8 +4071,8 @@ "version": "19.2.6", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.6.tgz", "integrity": "sha512-p/jUvulfgU7oKtj6Xpk8cA2Y1xKTtICGpJYeJXz2YVO2UcvjQgeRMLDGfDeqeRW2Ta+0QNFwcc8X3GH8SxZz6w==", - "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -3589,8 +4081,8 @@ "version": "19.2.3", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", - "devOptional": true, "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -3601,6 +4093,12 @@ "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", "license": "MIT" }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", + "license": "MIT" + }, "node_modules/@vitejs/plugin-react": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", @@ -3627,6 +4125,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3734,6 +4233,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", @@ -4007,7 +4507,6 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "devOptional": true, "license": "MIT" }, "node_modules/d": { @@ -4185,7 +4684,6 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -4420,6 +4918,15 @@ "type": "^2.7.2" } }, + "node_modules/fast-equals": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.3.3.tgz", + "integrity": "sha512-/boTcHZeIAQ2r/tL11voclBHDeP9WPxLt+tyAbVSyyXuUFyh0Tne7gJZTqGbxnvj79TjLdCXLOY7UIPhyG5MTw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/fault": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", @@ -4477,6 +4984,33 @@ "node": ">=0.4.x" } }, + "node_modules/framer-motion": { + "version": "12.23.25", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.25.tgz", + "integrity": "sha512-gUHGl2e4VG66jOcH0JHhuJQr6ZNwrET9g31ZG0xdXzT0CznP7fHX4P8Bcvuc4MiUB90ysNnWX2ukHRIggkl6hQ==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.23.23", + "motion-utils": "^12.23.6", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -4731,7 +5265,6 @@ "resolved": "https://registry.npmjs.org/isomorphic.js/-/isomorphic.js-0.2.5.tgz", "integrity": "sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==", "license": "MIT", - "peer": true, "funding": { "type": "GitHub Sponsors ❤", "url": "https://github.com/sponsors/dmonad" @@ -4829,7 +5362,6 @@ "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.114.tgz", "integrity": "sha512-gcxmNFzA4hv8UYi8j43uPlQ7CGcyMJ2KQb5kZASw6SnAKAf10hK12i2fjrS3Cl/ugZa5Ui6WwIu1/6MIXiHttQ==", "license": "MIT", - "peer": true, "dependencies": { "isomorphic.js": "^0.2.4" }, @@ -5111,6 +5643,21 @@ "dev": true, "license": "MIT" }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/linkifyjs": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.3.2.tgz", + "integrity": "sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==", + "license": "MIT" + }, "node_modules/longest-streak": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", @@ -5171,6 +5718,29 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/markdown-it-task-lists": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/markdown-it-task-lists/-/markdown-it-task-lists-2.1.1.tgz", + "integrity": "sha512-TxFAc76Jnhb2OUu+n3yz9RMu4CwGfaT788br6HhEDlvWfdeJcLUsxk1Hgw2yJio0OXsxv7pyIPmvECY7bMbluA==", + "license": "ISC" + }, "node_modules/markdown-table": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", @@ -5435,6 +6005,12 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "license": "MIT" + }, "node_modules/micromark": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", @@ -6153,6 +6729,21 @@ "node": ">= 0.6" } }, + "node_modules/motion-dom": { + "version": "12.23.23", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.23.tgz", + "integrity": "sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.23.6" + } + }, + "node_modules/motion-utils": { + "version": "12.23.6", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.23.6.tgz", + "integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==", + "license": "MIT" + }, "node_modules/mri": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", @@ -6219,6 +6810,12 @@ "node": ">=0.10.0" } }, + "node_modules/orderedmap": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz", + "integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==", + "license": "MIT" + }, "node_modules/outvariant": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.0.tgz", @@ -6390,17 +6987,237 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, + "node_modules/prosemirror-changeset": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.3.1.tgz", + "integrity": "sha512-j0kORIBm8ayJNl3zQvD1TTPHJX3g042et6y/KQhZhnPrruO8exkTgG8X+NRpj7kIyMMEx74Xb3DyMIBtO0IKkQ==", + "license": "MIT", + "dependencies": { + "prosemirror-transform": "^1.0.0" + } + }, + "node_modules/prosemirror-collab": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz", + "integrity": "sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0" + } + }, + "node_modules/prosemirror-commands": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.7.1.tgz", + "integrity": "sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.10.2" + } + }, + "node_modules/prosemirror-dropcursor": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.2.tgz", + "integrity": "sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0", + "prosemirror-view": "^1.1.0" + } + }, + "node_modules/prosemirror-gapcursor": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.4.0.tgz", + "integrity": "sha512-z00qvurSdCEWUIulij/isHaqu4uLS8r/Fi61IbjdIPJEonQgggbJsLnstW7Lgdk4zQ68/yr6B6bf7sJXowIgdQ==", + "license": "MIT", + "dependencies": { + "prosemirror-keymap": "^1.0.0", + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-view": "^1.0.0" + } + }, + "node_modules/prosemirror-history": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.5.0.tgz", + "integrity": "sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.2.2", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.31.0", + "rope-sequence": "^1.3.0" + } + }, + "node_modules/prosemirror-inputrules": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.5.1.tgz", + "integrity": "sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.0.0" + } + }, + "node_modules/prosemirror-keymap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.3.tgz", + "integrity": "sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "w3c-keyname": "^2.2.0" + } + }, + "node_modules/prosemirror-markdown": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.13.2.tgz", + "integrity": "sha512-FPD9rHPdA9fqzNmIIDhhnYQ6WgNoSWX9StUZ8LEKapaXU9i6XgykaHKhp6XMyXlOWetmaFgGDS/nu/w9/vUc5g==", + "license": "MIT", + "dependencies": { + "@types/markdown-it": "^14.0.0", + "markdown-it": "^14.0.0", + "prosemirror-model": "^1.25.0" + } + }, + "node_modules/prosemirror-menu": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/prosemirror-menu/-/prosemirror-menu-1.2.5.tgz", + "integrity": "sha512-qwXzynnpBIeg1D7BAtjOusR+81xCp53j7iWu/IargiRZqRjGIlQuu1f3jFi+ehrHhWMLoyOQTSRx/IWZJqOYtQ==", + "license": "MIT", + "dependencies": { + "crelt": "^1.0.0", + "prosemirror-commands": "^1.0.0", + "prosemirror-history": "^1.0.0", + "prosemirror-state": "^1.0.0" + } + }, + "node_modules/prosemirror-model": { + "version": "1.25.4", + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.4.tgz", + "integrity": "sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==", + "license": "MIT", + "peer": true, + "dependencies": { + "orderedmap": "^2.0.0" + } + }, + "node_modules/prosemirror-schema-basic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.4.tgz", + "integrity": "sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.25.0" + } + }, + "node_modules/prosemirror-schema-list": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.5.1.tgz", + "integrity": "sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.7.3" + } + }, + "node_modules/prosemirror-state": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.4.tgz", + "integrity": "sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==", + "license": "MIT", + "peer": true, + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.27.0" + } + }, + "node_modules/prosemirror-tables": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.8.3.tgz", + "integrity": "sha512-wbqCR/RlRPRe41a4LFtmhKElzBEfBTdtAYWNIGHM6X2e24NN/MTNUKyXjjphfAfdQce37Kh/5yf765mLPYDe7Q==", + "license": "MIT", + "dependencies": { + "prosemirror-keymap": "^1.2.3", + "prosemirror-model": "^1.25.4", + "prosemirror-state": "^1.4.4", + "prosemirror-transform": "^1.10.5", + "prosemirror-view": "^1.41.4" + } + }, + "node_modules/prosemirror-trailing-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-3.0.0.tgz", + "integrity": "sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==", + "license": "MIT", + "dependencies": { + "@remirror/core-constants": "3.0.0", + "escape-string-regexp": "^4.0.0" + }, + "peerDependencies": { + "prosemirror-model": "^1.22.1", + "prosemirror-state": "^1.4.2", + "prosemirror-view": "^1.33.8" + } + }, + "node_modules/prosemirror-trailing-node/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prosemirror-transform": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.10.5.tgz", + "integrity": "sha512-RPDQCxIDhIBb1o36xxwsaeAvivO8VLJcgBtzmOwQ64bMtsVFh5SSuJ6dWSxO1UsHTiTXPCgQm3PDJt7p6IOLbw==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.21.0" + } + }, + "node_modules/prosemirror-view": { + "version": "1.41.4", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.41.4.tgz", + "integrity": "sha512-WkKgnyjNncri03Gjaz3IFWvCAE94XoiEgvtr0/r2Xw7R8/IjK3sKLSiDoCHWcsXSAinVaKlGRZDvMCsF1kbzjA==", + "license": "MIT", + "peer": true, + "dependencies": { + "prosemirror-model": "^1.20.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "license": "MIT" }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -6422,6 +7239,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -6651,6 +7469,12 @@ "fsevents": "~2.3.2" } }, + "node_modules/rope-sequence": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz", + "integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==", + "license": "MIT" + }, "node_modules/sade": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", @@ -6784,7 +7608,8 @@ "version": "4.1.17", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.17.tgz", "integrity": "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/tapable": { "version": "2.3.0", @@ -6799,6 +7624,46 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/tiptap-markdown": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/tiptap-markdown/-/tiptap-markdown-0.9.0.tgz", + "integrity": "sha512-dKLQ9iiuGNgrlGVjrNauF/UBzWu4LYOx5pkD0jNkmQt/GOwfCJsBuzZTsf1jZ204ANHOm572mZ9PYvGh1S7tpQ==", + "license": "MIT", + "workspaces": [ + "example" + ], + "dependencies": { + "@types/markdown-it": "^13.0.7", + "markdown-it": "^14.1.0", + "markdown-it-task-lists": "^2.1.1", + "prosemirror-markdown": "^1.11.1" + }, + "peerDependencies": { + "@tiptap/core": "^3.0.1" + } + }, + "node_modules/tiptap-markdown/node_modules/@types/linkify-it": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz", + "integrity": "sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==", + "license": "MIT" + }, + "node_modules/tiptap-markdown/node_modules/@types/markdown-it": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-13.0.9.tgz", + "integrity": "sha512-1XPwR0+MgXLWfTn9gCsZ55AHOKW1WN+P9vr0PaQh5aerR9LLQXUbjfEAFhjmEmyoYFWAyuN2Mqkn40MZ4ukjBw==", + "license": "MIT", + "dependencies": { + "@types/linkify-it": "^3", + "@types/mdurl": "^1" + } + }, + "node_modules/tiptap-markdown/node_modules/@types/mdurl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.5.tgz", + "integrity": "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==", + "license": "MIT" + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -6811,6 +7676,12 @@ "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", "license": "ISC" }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "license": "MIT" + }, "node_modules/unidiff": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unidiff/-/unidiff-1.0.4.tgz", @@ -6962,6 +7833,15 @@ } } }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -7005,6 +7885,7 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", diff --git a/frontend/package.json b/frontend/package.json index 94cc649..837f10c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -14,12 +14,17 @@ "@mdxeditor/editor": "^3.49.3", "@tailwindcss/typography": "^0.5.19", "@tailwindcss/vite": "^4.1.17", + "@tiptap/extension-placeholder": "^3.12.1", + "@tiptap/react": "^3.12.1", + "@tiptap/starter-kit": "^3.12.1", "axios": "^1.13.2", + "framer-motion": "^12.23.25", "jszip": "^3.10.1", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^7.9.6", "tailwindcss": "^4.1.17", + "tiptap-markdown": "^0.9.0", "zustand": "^5.0.8" }, "devDependencies": { diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 7c62d37..6511fe9 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,21 +1,41 @@ // src/App.tsx +import { useEffect } from "react"; import { BrowserRouter, Routes, Route, Link } from "react-router-dom"; import Home from "./pages/Home"; // existing home page -import { MarkdownPage } from "./pages/Markdown"; import { Import } from "./pages/Import"; -const App = () => ( - - {/* Simple nav – you can replace with your own UI later */} - {/*