From 5e6764b026a7c2d3141408e9f3ff2b8d3245ea45 Mon Sep 17 00:00:00 2001 From: james fitzsimons Date: Mon, 8 Dec 2025 22:08:30 +0000 Subject: [PATCH] Implement user auth and session management --- .gitignore | 2 + backend/app/__pycache__/auth.cpython-314.pyc | Bin 0 -> 4178 bytes backend/app/__pycache__/main.cpython-314.pyc | Bin 1244 -> 1343 bytes .../app/__pycache__/models.cpython-314.pyc | Bin 6196 -> 8608 bytes backend/app/auth.py | 71 ++ backend/app/main.py | 3 +- backend/app/models.py | 31 + .../routes/__pycache__/auth.cpython-314.pyc | Bin 0 -> 8575 bytes .../__pycache__/folders.cpython-314.pyc | Bin 7062 -> 6229 bytes .../routes/__pycache__/notes.cpython-314.pyc | Bin 4165 -> 4416 bytes backend/app/routes/auth.py | 166 ++++ backend/app/routes/folders.py | 32 +- backend/app/routes/notes.py | 18 +- backend/notes.db | Bin 110592 -> 40960 bytes backend/notes.sqbpro | 1 + backend/pyproject.toml | 3 - frontend/package-lock.json | 895 +++++++++++++++++- frontend/package.json | 5 + frontend/src/App.tsx | 44 +- frontend/src/api/encryption.tsx | 46 +- frontend/src/api/folders.tsx | 18 +- frontend/src/api/notes.tsx | 38 +- .../contextMenus/ContextMenuRenderer.tsx | 31 + .../contextMenus/FolderContextMenu.tsx | 123 +++ .../contextMenus/NoteContextMenu.tsx | 82 ++ frontend/src/components/editor/Editor.tsx | 119 --- .../src/components/sidebar/DraggableNote.tsx | 42 +- .../components/sidebar/DroppableFolder.tsx | 43 +- .../components/sidebar/RecursiveFolder.tsx | 51 +- frontend/src/components/sidebar/SideBar.tsx | 268 ++++-- frontend/src/contexts/ContextMenuContext.tsx | 114 +++ frontend/src/main.css | 80 +- frontend/src/main.tsx | 4 +- frontend/src/pages/Home.tsx | 228 ++--- frontend/src/pages/Login.tsx | 56 ++ frontend/src/pages/Markdown.tsx | 68 -- frontend/src/pages/Register.tsx | 51 + frontend/src/pages/Test.tsx | 11 + frontend/src/pages/TipTap.tsx | 198 ++++ frontend/src/pages/tiptap.css | 172 ++++ frontend/src/stores/authStore.ts | 151 +++ frontend/src/stores/notesStore.ts | 327 ++++++- frontend/src/stores/uiStore.ts | 39 +- 43 files changed, 3047 insertions(+), 584 deletions(-) create mode 100644 backend/app/__pycache__/auth.cpython-314.pyc create mode 100644 backend/app/auth.py create mode 100644 backend/app/routes/__pycache__/auth.cpython-314.pyc create mode 100644 backend/app/routes/auth.py create mode 100644 backend/notes.sqbpro delete mode 100644 backend/pyproject.toml create mode 100644 frontend/src/components/contextMenus/ContextMenuRenderer.tsx create mode 100644 frontend/src/components/contextMenus/FolderContextMenu.tsx create mode 100644 frontend/src/components/contextMenus/NoteContextMenu.tsx delete mode 100644 frontend/src/components/editor/Editor.tsx create mode 100644 frontend/src/contexts/ContextMenuContext.tsx create mode 100644 frontend/src/pages/Login.tsx delete mode 100644 frontend/src/pages/Markdown.tsx create mode 100644 frontend/src/pages/Register.tsx create mode 100644 frontend/src/pages/Test.tsx create mode 100644 frontend/src/pages/TipTap.tsx create mode 100644 frontend/src/pages/tiptap.css create mode 100644 frontend/src/stores/authStore.ts 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 0000000000000000000000000000000000000000..4e8d24ee0b8b87c03fd296308bd0c9e3941515c3 GIT binary patch literal 4178 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 cuRWx9_Z{}B?+11sr^$bzRVaR{^U$w6Ta{vGU literal 0 HcmV?d00001 diff --git a/backend/app/__pycache__/main.cpython-314.pyc b/backend/app/__pycache__/main.cpython-314.pyc index 1c5498b086091b65441ffd4b9d575c7d6ab8149f..ab30837efd83ddc34e5d6adcf249d3411c28a309 100644 GIT binary patch delta 377 zcmcb^xu1(yn~#@^0SKD8^fI4Ky*^5z= zQE+kzqa!=>EtbU6l8nvU7=;+c#egOY19342kZ53d!Xj~vMXE?-@_i;ZN07^lK#~wb z1jG^r61P~2^7BiIq=8J3^NM+aL<7SE9?=Qa7r2!#uqYRSl=^83O-^GDWh&yFyn|Vp zQEc)ZW<`6D9(2<Si&T;DWMyVIM^2znkr12!DJv2I61P~2^7BiIq<~BrATH(w z5)BLwctj^uU*J~0z@l6PQtGEEIC&Lw=wuca1xC@ysw|2&APo@n5Jqv> diff --git a/backend/app/__pycache__/models.cpython-314.pyc b/backend/app/__pycache__/models.cpython-314.pyc index b6ce6eac9d16f565af1d0de4d8144952f2ec0a91..00bb4e2660a9d90c9dd697157262b2330ca0bc27 100644 GIT binary patch literal 8608 zcmchc&u<&Y6~|}E=h*aZSOr}|XbJ*9`X{sVgGp@$Hl0c(MxF?whN^bpBPQ{>S0`(}5^ zCAFfAAT0qt&c4~5nVt9EXWk5-NW>!ypMO^m<$fDu?5}j;d_s2N!Gy$EnVn~fG|i@% z!3L@9o0g`0hHuJm_{Ft9?LJ~c+W~FTrHu=1C$uS-HX*cK(004D z?LylF?GBf=Luh-U?Q?09Lc0^%ewVgW*)_t_yFaHPr6n_*%@~@IThh`#Q$CZ^4Kw_5 z$;cH8nS9!B22SR*eAbL9T0TQceKA)u!)IST^SxqL%g56rbWh?6dAQ0z&75POj;K9=Z_e=EARZ+I_fwl)z#50ey_fTogT! zO&v{alP11NlQ_o?NDAzp4;$@Do6&KO8A(OL97Rm|HC^K~v$uU_D61`Gmh*-gE%Dq^ zhF?+N)~-MwTrT9^S=P)zu8`F(-mQJ$jra3mWriiOr@sJ z(-`e>GV($4kq3W*cup#_bL_lt;seIA(C%WdN{iAsJ1hN=zS6#(xXJ!J>rIRx8q8thbF#JR%Vo_lO++EH zgvrvDGP%6jzL?P$wX9mo==!B1&ziEH!3=j^;+awj`lXC+Xq+b6jLdTlvzApehAGb! z4YW~!)Xm_@Vm_;JGqfOnbu)BU({*^N8P=_Wo(^#GP1Bz%7^Yu0IH#%RH0SX7;6jlv zq1Cvm&gU_ZY;N9ARh>q?r)*A)FBX@y@wYNdIpf{&N$tm4zF1n)3dZ;X1}BCvPIlD_ z*>Mbde2KzBA1hrkW2%}d;0BCZRm~(h(wJLC7}I|N@vjfr`)oDbaXqyXugFK%{7jPW zCz2I;|5^aWwIGYNSLE@v5M6{>PhUmuU2CI@2#Y4(n_i1jImY^SRpkD)I9()I5_cV2 zYp07Y7VEecTzQV#?j}VKOLSg)Y~?)Nv4a%7tUYz@>6KzdKEB=u#RH6r-Dc@dGpwp) zFuXuSRq<}ic`D=8-dWD%?V5H~UC43W$ma@Lp{S}nh^Kiki9QnKtzyOzE5>}Gc!>{? zhTfkKk=R3G6v9lpCTL-~Fps{vVGGP*ZXT95c<#b7j860Evevwo&#UTfi9d!mbPB1X zJWXxV8X|<4>mT6?b6sYuy}NH_@5t5OBjp!YyZUZ+-I}d-?JrNQCVOsVZ;e)yK=Z>cFw`snwxJIIv03&I<5zedfsfH(=r zau7%Oau7#l2XO+6O<;16=T%ojAleAq0Bhqr=zYka&4`T@6*Lo5fP(O5GooECP5bzxq!3`$WmbSEFf4<9G-9TMLqQ3t^hx_q95K<|Dk2?`vg(lHW(2Q)?e0EvSn4v}~Y!X4G* zjKU+u+rNUV%~9RcfAioiquO(@e0nw2d-IKIY8=tpKjez&&xS_Jr|*%tpWJ=x2i4?6 zdGafIEhmbppLu+1pIUu#X&0KLOM}D*i4f9I5Fn|fj7}s%DUk?u@nH

Xe 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 HC35k9QKI8n 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 0000000000000000000000000000000000000000..e881b1175a7d626278d9b2eb66b0c3b8632b5757 GIT binary patch literal 8575 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 literal 7062 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 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 19604f6efb1f75c956443a79d57fe6579b5ab717..04c85ac249ba75940aaacd8d045c1b6d34f7d590 100644 GIT binary patch literal 40960 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 literal 110592 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℞MRf3PxO+DaZZ!Qf~u@_*UuhoFYT7t5iC( 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

`)C@{ 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%0DJ>-RZx%rr GhWanR3A)Vy 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 */} - {/*