From 7f5a75e489b25ba9f5c6634a0d72fc51bc4c4663 Mon Sep 17 00:00:00 2001 From: Alex-larget <33240357+Alex-larget@users.noreply.github.com> Date: Wed, 18 Mar 2026 21:10:11 +0800 Subject: [PATCH] go --- new-soul/soul-admin/.gitignore | 2 + new-soul/soul-admin/deploy_admin.py | 318 ++ new-soul/soul-admin/index.html | 12 + new-soul/soul-admin/package.json | 59 + new-soul/soul-admin/pnpm-lock.yaml | 4131 +++++++++++++++++ new-soul/soul-admin/postcss.config.js | 5 + new-soul/soul-admin/src/App.tsx | 58 + new-soul/soul-admin/src/api/auth.ts | 28 + new-soul/soul-admin/src/api/ckb.ts | 87 + new-soul/soul-admin/src/api/client.ts | 92 + .../soul-admin/src/components/RichEditor.css | 239 + .../soul-admin/src/components/RichEditor.tsx | 635 +++ .../components/modules/user/SetVipModal.tsx | 281 ++ .../modules/user/UserDetailModal.tsx | 1054 +++++ .../src/components/ui/Pagination.tsx | 81 + .../soul-admin/src/components/ui/badge.tsx | 31 + .../soul-admin/src/components/ui/button.tsx | 52 + .../soul-admin/src/components/ui/card.tsx | 42 + .../soul-admin/src/components/ui/dialog.tsx | 85 + .../soul-admin/src/components/ui/input.tsx | 18 + .../soul-admin/src/components/ui/label.tsx | 20 + .../soul-admin/src/components/ui/select.tsx | 79 + .../soul-admin/src/components/ui/slider.tsx | 48 + .../soul-admin/src/components/ui/switch.tsx | 26 + .../soul-admin/src/components/ui/table.tsx | 63 + .../soul-admin/src/components/ui/tabs.tsx | 49 + .../soul-admin/src/components/ui/textarea.tsx | 19 + new-soul/soul-admin/src/hooks/useDebounce.ts | 17 + new-soul/soul-admin/src/index.css | 36 + .../soul-admin/src/layouts/AdminLayout.tsx | 145 + new-soul/soul-admin/src/lib/utils.ts | 19 + new-soul/soul-admin/src/main.tsx | 13 + .../src/pages/admin-users/AdminUsersPage.tsx | 413 ++ .../src/pages/api-doc/ApiDocPage.tsx | 146 + .../src/pages/api-docs/ApiDocsPage.tsx | 442 ++ .../author-settings/AuthorSettingsPage.tsx | 362 ++ .../src/pages/chapters/ChaptersPage.tsx | 338 ++ .../src/pages/content/ChapterTree.tsx | 924 ++++ .../src/pages/content/ContentPage.tsx | 2875 ++++++++++++ .../src/pages/content/PersonAddEditModal.tsx | 650 +++ .../src/pages/dashboard/DashboardPage.tsx | 626 +++ .../pages/distribution/DistributionPage.tsx | 1301 ++++++ .../pages/find-partner/FindPartnerPage.tsx | 87 + .../find-partner/tabs/CKBConfigPanel.tsx | 381 ++ .../pages/find-partner/tabs/CKBStatsTab.tsx | 197 + .../find-partner/tabs/FindPartnerTab.tsx | 24 + .../pages/find-partner/tabs/MatchPoolTab.tsx | 359 ++ .../find-partner/tabs/MatchRecordsTab.tsx | 141 + .../find-partner/tabs/MentorBookingTab.tsx | 86 + .../src/pages/find-partner/tabs/MentorTab.tsx | 28 + .../find-partner/tabs/ResourceDockingTab.tsx | 140 + .../find-partner/tabs/TeamRecruitTab.tsx | 86 + .../src/pages/linked-mp/LinkedMpPage.tsx | 282 ++ .../soul-admin/src/pages/login/LoginPage.tsx | 123 + .../pages/match-records/MatchRecordsPage.tsx | 235 + .../soul-admin/src/pages/match/MatchPage.tsx | 576 +++ .../MentorConsultationsPage.tsx | 133 + .../src/pages/mentors/MentorsPage.tsx | 499 ++ .../src/pages/not-found/NotFoundPage.tsx | 29 + .../src/pages/orders/OrdersPage.tsx | 459 ++ .../src/pages/payment/PaymentPage.tsx | 422 ++ .../src/pages/qrcodes/QRCodesPage.tsx | 249 + .../ReferralSettingsPage.tsx | 320 ++ .../src/pages/settings/SettingsPage.tsx | 788 ++++ .../soul-admin/src/pages/site/SitePage.tsx | 406 ++ .../soul-admin/src/pages/users/UsersPage.tsx | 1265 +++++ .../src/pages/vip-roles/VipRolesPage.tsx | 125 + .../src/pages/withdrawals/WithdrawalsPage.tsx | 556 +++ new-soul/soul-admin/src/utils/toast.ts | 93 + new-soul/soul-admin/src/vite-env.d.ts | 9 + new-soul/soul-admin/tsconfig.json | 24 + new-soul/soul-admin/tsconfig.node.json | 9 + new-soul/soul-admin/tsconfig.tsbuildinfo | 1 + new-soul/soul-admin/vite.config.ts | 18 + soul-api/wechat/info.log | 2 + 75 files changed, 24073 insertions(+) create mode 100644 new-soul/soul-admin/.gitignore create mode 100644 new-soul/soul-admin/deploy_admin.py create mode 100644 new-soul/soul-admin/index.html create mode 100644 new-soul/soul-admin/package.json create mode 100644 new-soul/soul-admin/pnpm-lock.yaml create mode 100644 new-soul/soul-admin/postcss.config.js create mode 100644 new-soul/soul-admin/src/App.tsx create mode 100644 new-soul/soul-admin/src/api/auth.ts create mode 100644 new-soul/soul-admin/src/api/ckb.ts create mode 100644 new-soul/soul-admin/src/api/client.ts create mode 100644 new-soul/soul-admin/src/components/RichEditor.css create mode 100644 new-soul/soul-admin/src/components/RichEditor.tsx create mode 100644 new-soul/soul-admin/src/components/modules/user/SetVipModal.tsx create mode 100644 new-soul/soul-admin/src/components/modules/user/UserDetailModal.tsx create mode 100644 new-soul/soul-admin/src/components/ui/Pagination.tsx create mode 100644 new-soul/soul-admin/src/components/ui/badge.tsx create mode 100644 new-soul/soul-admin/src/components/ui/button.tsx create mode 100644 new-soul/soul-admin/src/components/ui/card.tsx create mode 100644 new-soul/soul-admin/src/components/ui/dialog.tsx create mode 100644 new-soul/soul-admin/src/components/ui/input.tsx create mode 100644 new-soul/soul-admin/src/components/ui/label.tsx create mode 100644 new-soul/soul-admin/src/components/ui/select.tsx create mode 100644 new-soul/soul-admin/src/components/ui/slider.tsx create mode 100644 new-soul/soul-admin/src/components/ui/switch.tsx create mode 100644 new-soul/soul-admin/src/components/ui/table.tsx create mode 100644 new-soul/soul-admin/src/components/ui/tabs.tsx create mode 100644 new-soul/soul-admin/src/components/ui/textarea.tsx create mode 100644 new-soul/soul-admin/src/hooks/useDebounce.ts create mode 100644 new-soul/soul-admin/src/index.css create mode 100644 new-soul/soul-admin/src/layouts/AdminLayout.tsx create mode 100644 new-soul/soul-admin/src/lib/utils.ts create mode 100644 new-soul/soul-admin/src/main.tsx create mode 100644 new-soul/soul-admin/src/pages/admin-users/AdminUsersPage.tsx create mode 100644 new-soul/soul-admin/src/pages/api-doc/ApiDocPage.tsx create mode 100644 new-soul/soul-admin/src/pages/api-docs/ApiDocsPage.tsx create mode 100644 new-soul/soul-admin/src/pages/author-settings/AuthorSettingsPage.tsx create mode 100644 new-soul/soul-admin/src/pages/chapters/ChaptersPage.tsx create mode 100644 new-soul/soul-admin/src/pages/content/ChapterTree.tsx create mode 100644 new-soul/soul-admin/src/pages/content/ContentPage.tsx create mode 100644 new-soul/soul-admin/src/pages/content/PersonAddEditModal.tsx create mode 100644 new-soul/soul-admin/src/pages/dashboard/DashboardPage.tsx create mode 100644 new-soul/soul-admin/src/pages/distribution/DistributionPage.tsx create mode 100644 new-soul/soul-admin/src/pages/find-partner/FindPartnerPage.tsx create mode 100644 new-soul/soul-admin/src/pages/find-partner/tabs/CKBConfigPanel.tsx create mode 100644 new-soul/soul-admin/src/pages/find-partner/tabs/CKBStatsTab.tsx create mode 100644 new-soul/soul-admin/src/pages/find-partner/tabs/FindPartnerTab.tsx create mode 100644 new-soul/soul-admin/src/pages/find-partner/tabs/MatchPoolTab.tsx create mode 100644 new-soul/soul-admin/src/pages/find-partner/tabs/MatchRecordsTab.tsx create mode 100644 new-soul/soul-admin/src/pages/find-partner/tabs/MentorBookingTab.tsx create mode 100644 new-soul/soul-admin/src/pages/find-partner/tabs/MentorTab.tsx create mode 100644 new-soul/soul-admin/src/pages/find-partner/tabs/ResourceDockingTab.tsx create mode 100644 new-soul/soul-admin/src/pages/find-partner/tabs/TeamRecruitTab.tsx create mode 100644 new-soul/soul-admin/src/pages/linked-mp/LinkedMpPage.tsx create mode 100644 new-soul/soul-admin/src/pages/login/LoginPage.tsx create mode 100644 new-soul/soul-admin/src/pages/match-records/MatchRecordsPage.tsx create mode 100644 new-soul/soul-admin/src/pages/match/MatchPage.tsx create mode 100644 new-soul/soul-admin/src/pages/mentor-consultations/MentorConsultationsPage.tsx create mode 100644 new-soul/soul-admin/src/pages/mentors/MentorsPage.tsx create mode 100644 new-soul/soul-admin/src/pages/not-found/NotFoundPage.tsx create mode 100644 new-soul/soul-admin/src/pages/orders/OrdersPage.tsx create mode 100644 new-soul/soul-admin/src/pages/payment/PaymentPage.tsx create mode 100644 new-soul/soul-admin/src/pages/qrcodes/QRCodesPage.tsx create mode 100644 new-soul/soul-admin/src/pages/referral-settings/ReferralSettingsPage.tsx create mode 100644 new-soul/soul-admin/src/pages/settings/SettingsPage.tsx create mode 100644 new-soul/soul-admin/src/pages/site/SitePage.tsx create mode 100644 new-soul/soul-admin/src/pages/users/UsersPage.tsx create mode 100644 new-soul/soul-admin/src/pages/vip-roles/VipRolesPage.tsx create mode 100644 new-soul/soul-admin/src/pages/withdrawals/WithdrawalsPage.tsx create mode 100644 new-soul/soul-admin/src/utils/toast.ts create mode 100644 new-soul/soul-admin/src/vite-env.d.ts create mode 100644 new-soul/soul-admin/tsconfig.json create mode 100644 new-soul/soul-admin/tsconfig.node.json create mode 100644 new-soul/soul-admin/tsconfig.tsbuildinfo create mode 100644 new-soul/soul-admin/vite.config.ts diff --git a/new-soul/soul-admin/.gitignore b/new-soul/soul-admin/.gitignore new file mode 100644 index 00000000..12ac6472 --- /dev/null +++ b/new-soul/soul-admin/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +.DS_Store \ No newline at end of file diff --git a/new-soul/soul-admin/deploy_admin.py b/new-soul/soul-admin/deploy_admin.py new file mode 100644 index 00000000..dc85a64f --- /dev/null +++ b/new-soul/soul-admin/deploy_admin.py @@ -0,0 +1,318 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +soul-admin 静态站点部署:打包 dist → 上传 → 解压到 dist2 → dist/dist2 互换实现无缝切换。 +不安装依赖、不重启、不调用宝塔 API。 +""" + +from __future__ import print_function + +import os +import sys +import shlex +import tempfile +import argparse +import zipfile + +try: + import paramiko +except ImportError: + print("错误: 请先安装 paramiko") + print(" pip install paramiko") + sys.exit(1) + +# ==================== 配置 ==================== + +# 站点根目录(Nginx 等指向的目录的上一级,即 dist 的父目录) +DEPLOY_BASE_PATH = "/www/wwwroot/self/soul-admin" +# 切换后 chown 的属主,宝塔一般为 www:www,空则跳过 +DEPLOY_WWW_USER = os.environ.get("DEPLOY_WWW_USER", "www:www") +DEFAULT_SSH_PORT = int(os.environ.get("DEPLOY_SSH_PORT", "22022")) + + +def get_cfg(): + base = os.environ.get("DEPLOY_BASE_PATH", DEPLOY_BASE_PATH).rstrip("/") + return { + "host": os.environ.get("DEPLOY_HOST", "43.139.27.93"), + "user": os.environ.get("DEPLOY_USER", "root"), + "password": os.environ.get("DEPLOY_PASSWORD", "Zhiqun1984"), + "ssh_key": os.environ.get("DEPLOY_SSH_KEY", ""), + "base_path": base, + "dist_path": base + "/dist", + "dist2_path": base + "/dist2", + "www_user": os.environ.get("DEPLOY_WWW_USER", DEPLOY_WWW_USER).strip(), + } + + +# ==================== 本地构建 ==================== + + +def run_build(root): + """执行本地 pnpm build""" + use_shell = sys.platform == "win32" + dist_dir = os.path.join(root, "dist") + index_html = os.path.join(dist_dir, "index.html") + + try: + r = __import__("subprocess").run( + ["pnpm", "build"], + cwd=root, + shell=use_shell, + timeout=300, + capture_output=True, + text=True, + encoding="utf-8", + errors="replace", + ) + if r.returncode != 0: + print(" [失败] 构建失败,退出码:", r.returncode) + for line in (r.stdout or "").strip().split("\n")[-10:]: + print(" " + line) + return False + except __import__("subprocess").TimeoutExpired: + print(" [失败] 构建超时") + return False + except FileNotFoundError: + print(" [失败] 未找到 pnpm,请安装: npm install -g pnpm") + return False + except Exception as e: + print(" [失败] 构建异常:", str(e)) + return False + + if not os.path.isfile(index_html): + print(" [失败] 未找到 dist/index.html") + return False + print(" [成功] 构建完成") + return True + + +# ==================== 打包 dist 为 zip ==================== + + +def pack_dist_zip(root): + """将本地 dist 目录打包为 zip(解压到 dist2 后即为站点根内容)""" + print("[2/4] 打包 dist 为 zip ...") + dist_dir = os.path.join(root, "dist") + if not os.path.isdir(dist_dir): + print(" [失败] 未找到 dist 目录") + return None + index_html = os.path.join(dist_dir, "index.html") + if not os.path.isfile(index_html): + print(" [失败] 未找到 dist/index.html,请先执行 pnpm build") + return None + + zip_path = os.path.join(tempfile.gettempdir(), "soul_admin_deploy.zip") + try: + with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf: + for dirpath, _dirs, filenames in os.walk(dist_dir): + for f in filenames: + full = os.path.join(dirpath, f) + arcname = os.path.relpath(full, dist_dir).replace("\\", "/") + zf.write(full, arcname) + print(" [成功] 打包完成: %s (%.2f MB)" % (zip_path, os.path.getsize(zip_path) / 1024 / 1024)) + return zip_path + except Exception as e: + print(" [失败] 打包异常:", str(e)) + return None + + +# ==================== SSH 上传并解压到 dist2 ==================== + + +def upload_zip_and_extract_to_dist2(cfg, zip_path): + """上传 zip 到服务器并解压到 dist2""" + print("[3/4] SSH 上传 zip 并解压到 dist2 ...") + sys.stdout.flush() + if not cfg.get("password") and not cfg.get("ssh_key"): + print(" [失败] 请设置 DEPLOY_PASSWORD 或 DEPLOY_SSH_KEY") + return False + zip_size_mb = os.path.getsize(zip_path) / (1024 * 1024) + client = paramiko.SSHClient() + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + try: + print(" 正在连接 %s@%s:%s ..." % (cfg["user"], cfg["host"], DEFAULT_SSH_PORT)) + sys.stdout.flush() + if cfg.get("ssh_key") and os.path.isfile(cfg["ssh_key"]): + client.connect( + cfg["host"], + port=DEFAULT_SSH_PORT, + username=cfg["user"], + key_filename=cfg["ssh_key"], + timeout=30, + banner_timeout=30, + ) + else: + client.connect( + cfg["host"], + port=DEFAULT_SSH_PORT, + username=cfg["user"], + password=cfg["password"], + timeout=30, + banner_timeout=30, + ) + print(" [OK] SSH 已连接,正在上传 zip(%.1f MB)..." % zip_size_mb) + sys.stdout.flush() + remote_zip = cfg["base_path"] + "/soul_admin_deploy.zip" + sftp = client.open_sftp() + chunk_mb = 5.0 + last_reported = [0] + + def _progress(transferred, total): + if total and total > 0: + now_mb = transferred / (1024 * 1024) + if now_mb - last_reported[0] >= chunk_mb or transferred >= total: + last_reported[0] = now_mb + print("\r 上传进度: %.1f / %.1f MB" % (now_mb, total / (1024 * 1024)), end="") + sys.stdout.flush() + + sftp.put(zip_path, remote_zip, callback=_progress) + if zip_size_mb >= chunk_mb: + print("") + print(" [OK] zip 已上传,正在服务器解压到 dist2 ...") + sys.stdout.flush() + sftp.close() + dist2 = cfg["dist2_path"] + cmd = "rm -rf %s && mkdir -p %s && unzip -o -q %s -d %s && rm -f %s && echo OK" % ( + dist2, + dist2, + remote_zip, + dist2, + remote_zip, + ) + stdin, stdout, stderr = client.exec_command(cmd, timeout=120) + out = stdout.read().decode("utf-8", errors="replace").strip() + err = stderr.read().decode("utf-8", errors="replace").strip() + if err: + print(" 服务器 stderr: %s" % err[:500]) + exit_status = stdout.channel.recv_exit_status() + if exit_status != 0 or "OK" not in out: + print(" [失败] 解压失败,退出码: %s" % exit_status) + if out: + print(" stdout: %s" % out[:300]) + return False + print(" [成功] 已解压到: %s" % dist2) + return True + except Exception as e: + print(" [失败] SSH 错误: %s" % str(e)) + import traceback + traceback.print_exc() + return False + finally: + client.close() + + +# ==================== 服务器目录切换:dist → dist1,dist2 → dist ==================== + + +def remote_swap_dist(cfg): + """服务器上:dist→dist1,dist2→dist,删除 dist1,实现无缝切换""" + print("[4/4] 服务器切换目录: dist→dist1, dist2→dist ...") + client = paramiko.SSHClient() + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + try: + if cfg.get("ssh_key") and os.path.isfile(cfg["ssh_key"]): + client.connect( + cfg["host"], + port=DEFAULT_SSH_PORT, + username=cfg["user"], + key_filename=cfg["ssh_key"], + timeout=15, + ) + else: + client.connect( + cfg["host"], + port=DEFAULT_SSH_PORT, + username=cfg["user"], + password=cfg["password"], + timeout=15, + ) + base = cfg["base_path"] + # 若当前没有 dist(首次部署),则 dist2 直接改名为 dist;若有 dist 则先备份再替换 + cmd = "cd %s && (test -d dist && (mv dist dist1 && mv dist2 dist && rm -rf dist1) || mv dist2 dist) && echo OK" % base + stdin, stdout, stderr = client.exec_command(cmd, timeout=60) + out = stdout.read().decode("utf-8", errors="replace").strip() + err = stderr.read().decode("utf-8", errors="replace").strip() + exit_status = stdout.channel.recv_exit_status() + if exit_status != 0 or "OK" not in out: + print(" [失败] 切换失败 (退出码: %s)" % exit_status) + if err: + print(" 服务器 stderr: %s" % err) + if out and "OK" not in out: + print(" 服务器 stdout: %s" % out) + return False + print(" [成功] 新版本已切换至: %s" % cfg["dist_path"]) + # 切换后设置 www 访问权限,否则 Nginx 无法读文件导致无法访问 + www_user = cfg.get("www_user") + if www_user: + dist_path = cfg["dist_path"] + chown_cmd = "chown -R %s %s && echo OK" % (www_user, shlex.quote(dist_path)) + stdin, stdout, stderr = client.exec_command(chown_cmd, timeout=60) + chown_out = stdout.read().decode("utf-8", errors="replace").strip() + chown_err = stderr.read().decode("utf-8", errors="replace").strip() + if stdout.channel.recv_exit_status() != 0 or "OK" not in chown_out: + print(" [警告] chown 失败,站点可能无法访问: %s" % (chown_err or chown_out)) + else: + print(" [成功] 已设置属主: %s" % www_user) + return True + except Exception as e: + print(" [失败] SSH 错误: %s" % str(e)) + return False + finally: + client.close() + + +# ==================== 主函数 ==================== + + +def main(): + parser = argparse.ArgumentParser( + description="soul-admin 静态站点部署(dist2 解压后目录切换,无缝更新)", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog="不安装依赖、不重启、不调用宝塔 API。站点路径: " + DEPLOY_BASE_PATH + "/dist", + ) + parser.add_argument("--no-build", action="store_true", help="跳过本地 pnpm build") + args = parser.parse_args() + + script_dir = os.path.dirname(os.path.abspath(__file__)) + if os.path.isfile(os.path.join(script_dir, "package.json")): + root = script_dir + else: + root = os.path.dirname(script_dir) + + cfg = get_cfg() + print("=" * 60) + print(" soul-admin 部署(dist/dist2 无缝切换)") + print("=" * 60) + print(" 服务器: %s@%s 站点目录: %s" % (cfg["user"], cfg["host"], cfg["dist_path"])) + print("=" * 60) + + if not args.no_build: + print("[1/4] 本地构建 pnpm build ...") + if not run_build(root): + return 1 + else: + if not os.path.isdir(os.path.join(root, "dist")) or not os.path.isfile( + os.path.join(root, "dist", "index.html") + ): + print("[错误] 未找到 dist/index.html,请先执行 pnpm build 或去掉 --no-build") + return 1 + print("[1/4] 跳过本地构建") + + zip_path = pack_dist_zip(root) + if not zip_path: + return 1 + if not upload_zip_and_extract_to_dist2(cfg, zip_path): + return 1 + try: + os.remove(zip_path) + except Exception: + pass + if not remote_swap_dist(cfg): + return 1 + print("") + print(" 部署完成!站点目录: %s" % cfg["dist_path"]) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/new-soul/soul-admin/index.html b/new-soul/soul-admin/index.html new file mode 100644 index 00000000..0f5aacde --- /dev/null +++ b/new-soul/soul-admin/index.html @@ -0,0 +1,12 @@ + + + + + + 管理后台 - Soul创业派对 + + +
+ + + diff --git a/new-soul/soul-admin/package.json b/new-soul/soul-admin/package.json new file mode 100644 index 00000000..fd81792a --- /dev/null +++ b/new-soul/soul-admin/package.json @@ -0,0 +1,59 @@ +{ + "name": "soul-admin", + "private": true, + "version": "0.1.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "preview": "vite preview", + "lint": "eslint . --ext ts,tsx" + }, + "dependencies": { + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-label": "2.1.8", + "@radix-ui/react-select": "2.2.6", + "@radix-ui/react-separator": "1.1.8", + "@radix-ui/react-slider": "1.3.6", + "@radix-ui/react-slot": "1.2.4", + "@radix-ui/react-switch": "1.2.6", + "@radix-ui/react-tabs": "1.1.13", + "@tiptap/extension-image": "^3.20.1", + "@tiptap/extension-link": "^3.20.1", + "@tiptap/extension-mention": "^3.20.1", + "@tiptap/extension-placeholder": "^3.20.1", + "@tiptap/extension-table": "^3.20.1", + "@tiptap/extension-table-cell": "^3.20.1", + "@tiptap/extension-table-header": "^3.20.1", + "@tiptap/extension-table-row": "^3.20.1", + "@tiptap/pm": "^3.20.1", + "@tiptap/react": "^3.20.1", + "@tiptap/starter-kit": "^3.20.1", + "class-variance-authority": "0.7.1", + "clsx": "2.1.1", + "lucide-react": "0.562.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.28.0", + "tailwind-merge": "3.4.0", + "zustand": "5.0.9" + }, + "devDependencies": { + "@eslint/js": "^9.15.0", + "@tailwindcss/postcss": "^4.1.18", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "@vitejs/plugin-react": "^4.3.4", + "autoprefixer": "^10.4.20", + "eslint": "^9.15.0", + "eslint-plugin-react-hooks": "^5.0.0", + "eslint-plugin-react-refresh": "^0.4.14", + "globals": "^15.12.0", + "picomatch": "4.0.2", + "postcss": "^8.4.49", + "tailwindcss": "^4.1.9", + "typescript": "~5.6.2", + "typescript-eslint": "^8.15.0", + "vite": "^6.0.3" + } +} diff --git a/new-soul/soul-admin/pnpm-lock.yaml b/new-soul/soul-admin/pnpm-lock.yaml new file mode 100644 index 00000000..d7afaefa --- /dev/null +++ b/new-soul/soul-admin/pnpm-lock.yaml @@ -0,0 +1,4131 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@radix-ui/react-dialog': + specifier: ^1.1.15 + version: 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-label': + specifier: 2.1.8 + version: 2.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-select': + specifier: 2.2.6 + version: 2.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-separator': + specifier: 1.1.8 + version: 1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slider': + specifier: 1.3.6 + version: 1.3.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': + specifier: 1.2.4 + version: 1.2.4(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-switch': + specifier: 1.2.6 + version: 1.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-tabs': + specifier: 1.1.13 + version: 1.1.13(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@tiptap/extension-image': + specifier: ^3.20.1 + version: 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1)) + '@tiptap/extension-link': + specifier: ^3.20.1 + version: 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + '@tiptap/extension-mention': + specifier: ^3.20.1 + version: 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)(@tiptap/suggestion@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)) + '@tiptap/extension-placeholder': + specifier: ^3.20.1 + version: 3.20.1(@tiptap/extensions@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)) + '@tiptap/extension-table': + specifier: ^3.20.1 + version: 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + '@tiptap/extension-table-cell': + specifier: ^3.20.1 + version: 3.20.1(@tiptap/extension-table@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)) + '@tiptap/extension-table-header': + specifier: ^3.20.1 + version: 3.20.1(@tiptap/extension-table@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)) + '@tiptap/extension-table-row': + specifier: ^3.20.1 + version: 3.20.1(@tiptap/extension-table@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)) + '@tiptap/pm': + specifier: ^3.20.1 + version: 3.20.1 + '@tiptap/react': + specifier: ^3.20.1 + version: 3.20.1(@floating-ui/dom@1.7.5)(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@tiptap/starter-kit': + specifier: ^3.20.1 + version: 3.20.1 + class-variance-authority: + specifier: 0.7.1 + version: 0.7.1 + clsx: + specifier: 2.1.1 + version: 2.1.1 + lucide-react: + specifier: 0.562.0 + version: 0.562.0(react@18.3.1) + react: + specifier: ^18.3.1 + version: 18.3.1 + react-dom: + specifier: ^18.3.1 + version: 18.3.1(react@18.3.1) + react-router-dom: + specifier: ^6.28.0 + version: 6.30.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + tailwind-merge: + specifier: 3.4.0 + version: 3.4.0 + zustand: + specifier: 5.0.9 + version: 5.0.9(@types/react@18.3.28)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) + devDependencies: + '@eslint/js': + specifier: ^9.15.0 + version: 9.39.2 + '@tailwindcss/postcss': + specifier: ^4.1.18 + version: 4.1.18 + '@types/react': + specifier: ^18.3.12 + version: 18.3.28 + '@types/react-dom': + specifier: ^18.3.1 + version: 18.3.7(@types/react@18.3.28) + '@vitejs/plugin-react': + specifier: ^4.3.4 + version: 4.7.0(vite@6.4.1(jiti@2.6.1)(lightningcss@1.30.2)) + autoprefixer: + specifier: ^10.4.20 + version: 10.4.24(postcss@8.5.6) + eslint: + specifier: ^9.15.0 + version: 9.39.2(jiti@2.6.1) + eslint-plugin-react-hooks: + specifier: ^5.0.0 + version: 5.2.0(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-react-refresh: + specifier: ^0.4.14 + version: 0.4.26(eslint@9.39.2(jiti@2.6.1)) + globals: + specifier: ^15.12.0 + version: 15.15.0 + picomatch: + specifier: 4.0.2 + version: 4.0.2 + postcss: + specifier: ^8.4.49 + version: 8.5.6 + tailwindcss: + specifier: ^4.1.9 + version: 4.1.18 + typescript: + specifier: ~5.6.2 + version: 5.6.3 + typescript-eslint: + specifier: ^8.15.0 + version: 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.6.3) + vite: + specifier: ^6.0.3 + version: 6.4.1(jiti@2.6.1)(lightningcss@1.30.2) + +packages: + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.0': + resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.28.6': + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.28.6': + resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.0': + resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-transform-react-jsx-self@7.27.1': + resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.27.1': + resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.21.1': + resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.3': + resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.39.2': + resolution: {integrity: sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@floating-ui/core@1.7.4': + resolution: {integrity: sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==} + + '@floating-ui/dom@1.7.5': + resolution: {integrity: sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==} + + '@floating-ui/react-dom@2.1.7': + resolution: {integrity: sha512-0tLRojf/1Go2JgEVm+3Frg9A3IW8bJgKgdO0BN5RkF//ufuz2joZM63Npau2ff3J6lUVYgDSNzNkR+aH3IVfjg==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.7': + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@radix-ui/number@1.1.1': + resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} + + '@radix-ui/primitive@1.1.3': + resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} + + '@radix-ui/react-arrow@1.1.7': + resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collection@1.1.7': + resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-compose-refs@1.1.2': + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-context@1.1.2': + resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dialog@1.1.15': + resolution: {integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-direction@1.1.1': + resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dismissable-layer@1.1.11': + resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-focus-guards@1.1.3': + resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-focus-scope@1.1.7': + resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-id@1.1.1': + resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-label@2.1.8': + resolution: {integrity: sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popper@1.2.8': + resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-portal@1.1.9': + resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-presence@1.1.5': + resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.1.3': + resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.1.4': + resolution: {integrity: sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-roving-focus@1.1.11': + resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-select@2.2.6': + resolution: {integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-separator@1.1.8': + resolution: {integrity: sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slider@1.3.6': + resolution: {integrity: sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.2.3': + resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-slot@1.2.4': + resolution: {integrity: sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-switch@1.2.6': + resolution: {integrity: sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-tabs@1.1.13': + resolution: {integrity: sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-use-callback-ref@1.1.1': + resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.2.2': + resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.2': + resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-escape-keydown@1.1.1': + resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.1': + resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-previous@1.1.1': + resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-rect@1.1.1': + resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-size@1.1.1': + resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-visually-hidden@1.2.3': + resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/rect@1.1.1': + resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + + '@remirror/core-constants@3.0.0': + resolution: {integrity: sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==} + + '@remix-run/router@1.23.2': + resolution: {integrity: sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w==} + engines: {node: '>=14.0.0'} + + '@rolldown/pluginutils@1.0.0-beta.27': + resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} + + '@rollup/rollup-android-arm-eabi@4.57.1': + resolution: {integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.57.1': + resolution: {integrity: sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.57.1': + resolution: {integrity: sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.57.1': + resolution: {integrity: sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.57.1': + resolution: {integrity: sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.57.1': + resolution: {integrity: sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.57.1': + resolution: {integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.57.1': + resolution: {integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.57.1': + resolution: {integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.57.1': + resolution: {integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.57.1': + resolution: {integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-loong64-musl@4.57.1': + resolution: {integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.57.1': + resolution: {integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-musl@4.57.1': + resolution: {integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.57.1': + resolution: {integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.57.1': + resolution: {integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.57.1': + resolution: {integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.57.1': + resolution: {integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.57.1': + resolution: {integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-openbsd-x64@4.57.1': + resolution: {integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.57.1': + resolution: {integrity: sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.57.1': + resolution: {integrity: sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.57.1': + resolution: {integrity: sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.57.1': + resolution: {integrity: sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.57.1': + resolution: {integrity: sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==} + cpu: [x64] + os: [win32] + + '@tailwindcss/node@4.1.18': + resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==} + + '@tailwindcss/oxide-android-arm64@4.1.18': + resolution: {integrity: sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.1.18': + resolution: {integrity: sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.1.18': + resolution: {integrity: sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.1.18': + resolution: {integrity: sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': + resolution: {integrity: sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': + resolution: {integrity: sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-arm64-musl@4.1.18': + resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-linux-x64-gnu@4.1.18': + resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-x64-musl@4.1.18': + resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-wasm32-wasi@4.1.18': + resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': + resolution: {integrity: sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.1.18': + resolution: {integrity: sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.1.18': + resolution: {integrity: sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==} + engines: {node: '>= 10'} + + '@tailwindcss/postcss@4.1.18': + resolution: {integrity: sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==} + + '@tiptap/core@3.20.1': + resolution: {integrity: sha512-SwkPEWIfaDEZjC8SEIi4kZjqIYUbRgLUHUuQezo5GbphUNC8kM1pi3C3EtoOPtxXrEbY6e4pWEzW54Pcrd+rVA==} + peerDependencies: + '@tiptap/pm': ^3.20.1 + + '@tiptap/extension-blockquote@3.20.1': + resolution: {integrity: sha512-WzNXk/63PQI2fav4Ta6P0GmYRyu8Gap1pV3VUqaVK829iJ6Zt1T21xayATHEHWMK27VT1GLPJkx9Ycr2jfDyQw==} + peerDependencies: + '@tiptap/core': ^3.20.1 + + '@tiptap/extension-bold@3.20.1': + resolution: {integrity: sha512-fz++Qv6Rk/Hov0IYG/r7TJ1Y4zWkuGONe0UN5g0KY32NIMg3HeOHicbi4xsNWTm9uAOl3eawWDkezEMrleObMw==} + peerDependencies: + '@tiptap/core': ^3.20.1 + + '@tiptap/extension-bubble-menu@3.20.1': + resolution: {integrity: sha512-XaPvO6aCoWdFnCBus0s88lnj17NR/OopV79i8Qhgz3WMR0vrsL5zsd45l0lZuu9pSvm5VW47SoxakkJiZC1suw==} + peerDependencies: + '@tiptap/core': ^3.20.1 + '@tiptap/pm': ^3.20.1 + + '@tiptap/extension-bullet-list@3.20.1': + resolution: {integrity: sha512-mbrlvOZo5OF3vLhp+3fk9KuL/6J/wsN0QxF6ZFRAHzQ9NkJdtdfARcBeBnkWXGN8inB6YxbTGY1/E4lmBkOpOw==} + peerDependencies: + '@tiptap/extension-list': ^3.20.1 + + '@tiptap/extension-code-block@3.20.1': + resolution: {integrity: sha512-vKejwBq+Nlj4Ybd3qOyDxIQKzYymdNH+8eXkKwGShk2nfLJIxq69DCyGvmuHgipIO1qcYPJ149UNpGN+YGcdmA==} + peerDependencies: + '@tiptap/core': ^3.20.1 + '@tiptap/pm': ^3.20.1 + + '@tiptap/extension-code@3.20.1': + resolution: {integrity: sha512-509DHINIA/Gg+eTG7TEkfsS8RUiPLH5xZNyLRT0A1oaoaJmECKfrV6aAm05IdfTyqDqz6LW5pbnX6DdUC4keug==} + peerDependencies: + '@tiptap/core': ^3.20.1 + + '@tiptap/extension-document@3.20.1': + resolution: {integrity: sha512-9vrqdGmRV7bQCSY3NLgu7UhIwgOCDp4sKqMNsoNRX0aZ021QQMTvBQDPkiRkCf7MNsnWrNNnr52PVnULEn3vFQ==} + peerDependencies: + '@tiptap/core': ^3.20.1 + + '@tiptap/extension-dropcursor@3.20.1': + resolution: {integrity: sha512-K18L9FX4znn+ViPSIbTLOGcIaXMx/gLNwAPE8wPLwswbHhQqdiY1zzdBw6drgOc1Hicvebo2dIoUlSXOZsOEcw==} + peerDependencies: + '@tiptap/extensions': ^3.20.1 + + '@tiptap/extension-floating-menu@3.20.1': + resolution: {integrity: sha512-BeDC6nfOesIMn5pFuUnkEjOxGv80sOJ8uk1mdt9/3Fkvra8cB9NIYYCVtd6PU8oQFmJ8vFqPrRkUWrG5tbqnOg==} + peerDependencies: + '@floating-ui/dom': ^1.0.0 + '@tiptap/core': ^3.20.1 + '@tiptap/pm': ^3.20.1 + + '@tiptap/extension-gapcursor@3.20.1': + resolution: {integrity: sha512-kZOtttV6Ai8VUAgEng3h4WKFbtdSNJ6ps7r0cRPY+FctWhVmgNb/JJwwyC+vSilR7nRENAhrA/Cv/RxVlvLw+g==} + peerDependencies: + '@tiptap/extensions': ^3.20.1 + + '@tiptap/extension-hard-break@3.20.1': + resolution: {integrity: sha512-9sKpmg/IIdlLXimYWUZ3PplIRcehv4Oc7V1miTqlnAthMzjMqigDkjjgte4JZV67RdnDJTQkRw8TklCAU28Emg==} + peerDependencies: + '@tiptap/core': ^3.20.1 + + '@tiptap/extension-heading@3.20.1': + resolution: {integrity: sha512-unudyfQP6FxnyWinxvPqe/51DG91J6AaJm666RnAubgYMCgym+33kBftx4j4A6qf+ddWYbD00thMNKOnVLjAEQ==} + peerDependencies: + '@tiptap/core': ^3.20.1 + + '@tiptap/extension-horizontal-rule@3.20.1': + resolution: {integrity: sha512-rjFKFXNntdl0jay8oIGFvvykHlpyQTLmrH3Ag2fj3i8yh6MVvqhtaDomYQbw5sxECd5hBkL+T4n2d2DRuVw/QQ==} + peerDependencies: + '@tiptap/core': ^3.20.1 + '@tiptap/pm': ^3.20.1 + + '@tiptap/extension-image@3.20.1': + resolution: {integrity: sha512-/GPFSLNdYSZQ0E6VBXSAk0UFtDdn98HT1Aa2tO+STELqc5jAdFB42dfFnTC6KQzTvcUOUYkE2S1Q22YC5H2XNQ==} + peerDependencies: + '@tiptap/core': ^3.20.1 + + '@tiptap/extension-italic@3.20.1': + resolution: {integrity: sha512-ZYRX13Kt8tR8JOzSXirH3pRpi8x30o7LHxZY58uXBdUvr3tFzOkh03qbN523+diidSVeHP/aMd/+IrplHRkQug==} + peerDependencies: + '@tiptap/core': ^3.20.1 + + '@tiptap/extension-link@3.20.1': + resolution: {integrity: sha512-oYTTIgsQMqpkSnJAuAc+UtIKMuI4lv9e1y4LfI1iYm6NkEUHhONppU59smhxHLzb3Ww7YpDffbp5IgDTAiJztA==} + peerDependencies: + '@tiptap/core': ^3.20.1 + '@tiptap/pm': ^3.20.1 + + '@tiptap/extension-list-item@3.20.1': + resolution: {integrity: sha512-tzgnyTW82lYJkUnadYbatwkI9dLz/OWRSWuFpQPRje/ItmFMWuQ9c9NDD8qLbXPdEYnvrgSAA+ipCD/1G0qA0Q==} + peerDependencies: + '@tiptap/extension-list': ^3.20.1 + + '@tiptap/extension-list-keymap@3.20.1': + resolution: {integrity: sha512-Dr0xsQKx0XPOgDg7xqoWwfv7FFwZ3WeF3eOjqh3rDXlNHMj1v+UW5cj1HLphrsAZHTrVTn2C+VWPJkMZrSbpvQ==} + peerDependencies: + '@tiptap/extension-list': ^3.20.1 + + '@tiptap/extension-list@3.20.1': + resolution: {integrity: sha512-euBRAn0mkV7R2VEE+AuOt3R0j9RHEMFXamPFmtvTo8IInxDClusrm6mJoDjS8gCGAXsQCRiAe1SCQBPgGbOOwg==} + peerDependencies: + '@tiptap/core': ^3.20.1 + '@tiptap/pm': ^3.20.1 + + '@tiptap/extension-mention@3.20.1': + resolution: {integrity: sha512-KOGokj7oH1QpcM8P02V+o6wHsVE0g7XEtdIy2vtq2vlFE3npNNNFkMa8F8VWX6qyC+VeVrNU6SIzS5MFY2TORA==} + peerDependencies: + '@tiptap/core': ^3.20.1 + '@tiptap/pm': ^3.20.1 + '@tiptap/suggestion': ^3.20.1 + + '@tiptap/extension-ordered-list@3.20.1': + resolution: {integrity: sha512-Y+3Ad7OwAdagqdYwCnbqf7/to5ypD4NnUNHA0TXRCs7cAHRA8AdgPoIcGFpaaSpV86oosNU3yfeJouYeroffog==} + peerDependencies: + '@tiptap/extension-list': ^3.20.1 + + '@tiptap/extension-paragraph@3.20.1': + resolution: {integrity: sha512-QFrAtXNyv7JSnomMQc1nx5AnG9mMznfbYJAbdOQYVdbLtAzTfiTuNPNbQrufy5ZGtGaHxDCoaygu2QEfzaKG+Q==} + peerDependencies: + '@tiptap/core': ^3.20.1 + + '@tiptap/extension-placeholder@3.20.1': + resolution: {integrity: sha512-k+jfbCugYGuIFBdojukgEopGazIMOgHrw46FnyN2X/6ICOIjQP2rh2ObslrsUOsJYoEevxCsNF9hZl1HvWX66g==} + peerDependencies: + '@tiptap/extensions': ^3.20.1 + + '@tiptap/extension-strike@3.20.1': + resolution: {integrity: sha512-EYgyma10lpsY+rwbVQL9u+gA7hBlKLSMFH7Zgd37FSxukOjr+HE8iKPQQ+SwbGejyDsPlLT8Z5Jnuxo5Ng90Pg==} + peerDependencies: + '@tiptap/core': ^3.20.1 + + '@tiptap/extension-table-cell@3.20.1': + resolution: {integrity: sha512-nSeboFey+MJqZuCQSbVUajQVaGiypeoUPiGd0CJdyfc0oPsBGGqp7XFJtw5HHEbDqEvSHvGNDoZDFsUTAxUyIg==} + peerDependencies: + '@tiptap/extension-table': ^3.20.1 + + '@tiptap/extension-table-header@3.20.1': + resolution: {integrity: sha512-Xsdgik3Bh5xWSkLaPR/6NDLZR5lgUDIN/yiZ7bLtfTsyGxqEvuW2Y9/j/XP3AfsZzGy2/SuA9bM9zxPcFQxwFA==} + peerDependencies: + '@tiptap/extension-table': ^3.20.1 + + '@tiptap/extension-table-row@3.20.1': + resolution: {integrity: sha512-uYE0SdY4J81wn/fg8Gum0TVSTTBekQhRGeSwDnRfBBd9JILBsLotBTt4ucM7JOUjrP9BjS+QFCT9EstAchPHfQ==} + peerDependencies: + '@tiptap/extension-table': ^3.20.1 + + '@tiptap/extension-table@3.20.1': + resolution: {integrity: sha512-y2o1De3P/FH80nst1D9pYSwtRvxF87WkNAYGurqCkZ6SjwFq1Ifeh9eY+o79R6SCwcfpvQRytCYd+Yw9o5XAtA==} + peerDependencies: + '@tiptap/core': ^3.20.1 + '@tiptap/pm': ^3.20.1 + + '@tiptap/extension-text@3.20.1': + resolution: {integrity: sha512-7PlIbYW8UenV6NPOXHmv8IcmPGlGx6HFq66RmkJAOJRPXPkTLAiX0N8rQtzUJ6jDEHqoJpaHFEHJw0xzW1yF+A==} + peerDependencies: + '@tiptap/core': ^3.20.1 + + '@tiptap/extension-underline@3.20.1': + resolution: {integrity: sha512-fmHvDKzwCgnZUwRreq8tYkb1YyEwgzZ6QQkAQ0CsCRtvRMqzerr3Duz0Als4i8voZTuGDEL3VR6nAJbLAb/wPg==} + peerDependencies: + '@tiptap/core': ^3.20.1 + + '@tiptap/extensions@3.20.1': + resolution: {integrity: sha512-JRc/v+OBH0qLTdvQ7HvHWTxGJH73QOf1MC0R8NhOX2QnAbg2mPFv1h+FjGa2gfLGuCXBdWQomjekWkUKbC4e5A==} + peerDependencies: + '@tiptap/core': ^3.20.1 + '@tiptap/pm': ^3.20.1 + + '@tiptap/pm@3.20.1': + resolution: {integrity: sha512-6kCiGLvpES4AxcEuOhb7HR7/xIeJWMjZlb6J7e8zpiIh5BoQc7NoRdctsnmFEjZvC19bIasccshHQ7H2zchWqw==} + + '@tiptap/react@3.20.1': + resolution: {integrity: sha512-UH1NpVpCaZBGB3Yr5N6aTS+rsCMDl9wHfrt/w+6+Gz4KHFZ2OILA82hELxZzhNc1Lmjz8vgCArKcsYql9gbzJA==} + peerDependencies: + '@tiptap/core': ^3.20.1 + '@tiptap/pm': ^3.20.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 + + '@tiptap/starter-kit@3.20.1': + resolution: {integrity: sha512-opqWxL/4OTEiqmVC0wsU4o3JhAf6LycJ2G/gRIZVAIFLljI9uHfpPMTFGxZ5w9IVVJaP5PJysfwW/635kKqkrw==} + + '@tiptap/suggestion@3.20.1': + resolution: {integrity: sha512-ng7olbzgZhWvPJVJygNQK5153CjquR2eJXpkLq7bRjHlahvt4TH4tGFYvGdYZcXuzbe2g9RoqT7NaPGL9CUq9w==} + peerDependencies: + '@tiptap/core': ^3.20.1 + '@tiptap/pm': ^3.20.1 + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/linkify-it@5.0.0': + resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} + + '@types/markdown-it@14.1.2': + resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} + + '@types/mdurl@2.0.0': + resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} + + '@types/prop-types@15.7.15': + resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} + + '@types/react-dom@18.3.7': + resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==} + peerDependencies: + '@types/react': ^18.0.0 + + '@types/react@18.3.28': + resolution: {integrity: sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==} + + '@types/use-sync-external-store@0.0.6': + resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} + + '@typescript-eslint/eslint-plugin@8.54.0': + resolution: {integrity: sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.54.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/parser@8.54.0': + resolution: {integrity: sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/project-service@8.54.0': + resolution: {integrity: sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/scope-manager@8.54.0': + resolution: {integrity: sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.54.0': + resolution: {integrity: sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/type-utils@8.54.0': + resolution: {integrity: sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/types@8.54.0': + resolution: {integrity: sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.54.0': + resolution: {integrity: sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/utils@8.54.0': + resolution: {integrity: sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/visitor-keys@8.54.0': + resolution: {integrity: sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@vitejs/plugin-react@4.7.0': + resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + + autoprefixer@10.4.24: + resolution: {integrity: sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + baseline-browser-mapping@2.9.19: + resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==} + hasBin: true + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + caniuse-lite@1.0.30001769: + resolution: {integrity: sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + crelt@1.0.6: + resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + + electron-to-chromium@1.5.286: + resolution: {integrity: sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==} + + enhanced-resolve@5.19.0: + resolution: {integrity: sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==} + engines: {node: '>=10.13.0'} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-plugin-react-hooks@5.2.0: + resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + + eslint-plugin-react-refresh@0.4.26: + resolution: {integrity: sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==} + peerDependencies: + eslint: '>=8.40' + + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.39.2: + resolution: {integrity: sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-equals@5.4.0: + resolution: {integrity: sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==} + engines: {node: '>=6.0.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + + fraction.js@5.3.4: + resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@15.15.0: + resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} + engines: {node: '>=18'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lightningcss-android-arm64@1.30.2: + resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.30.2: + resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.30.2: + resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.30.2: + resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.30.2: + resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.30.2: + resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.30.2: + resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.30.2: + resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.30.2: + resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.30.2: + resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.30.2: + resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.30.2: + resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} + engines: {node: '>= 12.0.0'} + + linkify-it@5.0.0: + resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + + linkifyjs@4.3.2: + resolution: {integrity: sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lucide-react@0.562.0: + resolution: {integrity: sha512-82hOAu7y0dbVuFfmO4bYF1XEwYk/mEbM5E+b1jgci/udUBEE/R7LF5Ip0CCEmXe8AybRM8L+04eP+LGZeDvkiw==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + markdown-it@14.1.1: + resolution: {integrity: sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==} + hasBin: true + + mdurl@2.0.0: + resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + orderedmap@2.1.1: + resolution: {integrity: sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prosemirror-changeset@2.4.0: + resolution: {integrity: sha512-LvqH2v7Q2SF6yxatuPP2e8vSUKS/L+xAU7dPDC4RMyHMhZoGDfBC74mYuyYF4gLqOEG758wajtyhNnsTkuhvng==} + + prosemirror-collab@1.3.1: + resolution: {integrity: sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==} + + prosemirror-commands@1.7.1: + resolution: {integrity: sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==} + + prosemirror-dropcursor@1.8.2: + resolution: {integrity: sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==} + + prosemirror-gapcursor@1.4.0: + resolution: {integrity: sha512-z00qvurSdCEWUIulij/isHaqu4uLS8r/Fi61IbjdIPJEonQgggbJsLnstW7Lgdk4zQ68/yr6B6bf7sJXowIgdQ==} + + prosemirror-history@1.5.0: + resolution: {integrity: sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==} + + prosemirror-inputrules@1.5.1: + resolution: {integrity: sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw==} + + prosemirror-keymap@1.2.3: + resolution: {integrity: sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==} + + prosemirror-markdown@1.13.4: + resolution: {integrity: sha512-D98dm4cQ3Hs6EmjK500TdAOew4Z03EV71ajEFiWra3Upr7diytJsjF4mPV2dW+eK5uNectiRj0xFxYI9NLXDbw==} + + prosemirror-menu@1.3.0: + resolution: {integrity: sha512-TImyPXCHPcDsSka2/lwJ6WjTASr4re/qWq1yoTTuLOqfXucwF6VcRa2LWCkM/EyTD1UO3CUwiH8qURJoWJRxwg==} + + prosemirror-model@1.25.4: + resolution: {integrity: sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==} + + prosemirror-schema-basic@1.2.4: + resolution: {integrity: sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ==} + + prosemirror-schema-list@1.5.1: + resolution: {integrity: sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==} + + prosemirror-state@1.4.4: + resolution: {integrity: sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==} + + prosemirror-tables@1.8.5: + resolution: {integrity: sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw==} + + prosemirror-trailing-node@3.0.0: + resolution: {integrity: sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==} + peerDependencies: + prosemirror-model: ^1.22.1 + prosemirror-state: ^1.4.2 + prosemirror-view: ^1.33.8 + + prosemirror-transform@1.11.0: + resolution: {integrity: sha512-4I7Ce4KpygXb9bkiPS3hTEk4dSHorfRw8uI0pE8IhxlK2GXsqv5tIA7JUSxtSu7u8APVOTtbUBxTmnHIxVkIJw==} + + prosemirror-view@1.41.6: + resolution: {integrity: sha512-mxpcDG4hNQa/CPtzxjdlir5bJFDlm0/x5nGBbStB2BWX+XOQ9M8ekEG+ojqB5BcVu2Rc80/jssCMZzSstJuSYg==} + + punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + react-dom@18.3.1: + resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} + peerDependencies: + react: ^18.3.1 + + react-refresh@0.17.0: + resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} + engines: {node: '>=0.10.0'} + + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.7.2: + resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-router-dom@6.30.3: + resolution: {integrity: sha512-pxPcv1AczD4vso7G4Z3TKcvlxK7g7TNt3/FNGMhfqyntocvYKj+GCatfigGDjbLozC4baguJ0ReCigoDJXb0ag==} + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + + react-router@6.30.3: + resolution: {integrity: sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw==} + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react@18.3.1: + resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + rollup@4.57.1: + resolution: {integrity: sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + rope-sequence@1.3.4: + resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==} + + scheduler@0.23.2: + resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} + hasBin: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + tailwind-merge@3.4.0: + resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} + + tailwindcss@4.1.18: + resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==} + + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + engines: {node: '>=6'} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + ts-api-utils@2.4.0: + resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + typescript-eslint@8.54.0: + resolution: {integrity: sha512-CKsJ+g53QpsNPqbzUsfKVgd3Lny4yKZ1pP4qN3jdMOg/sisIDLGyDMezycquXLE5JsEU0wp3dGNdzig0/fmSVQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + typescript@5.6.3: + resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} + engines: {node: '>=14.17'} + hasBin: true + + uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sync-external-store@1.6.0: + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + vite@6.4.1: + resolution: {integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + w3c-keyname@2.2.8: + resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zustand@5.0.9: + resolution: {integrity: sha512-ALBtUj0AfjJt3uNRQoL1tL2tMvj6Gp/6e39dnfT6uzpelGru8v1tPOGBzayOWbPJvujM8JojDk3E1LxeFisBNg==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + +snapshots: + + '@alloc/quick-lru@5.2.0': {} + + '@babel/code-frame@7.29.0': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.0': {} + + '@babel/core@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.1': + dependencies: + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.28.6': + dependencies: + '@babel/compat-data': 7.29.0 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.1 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.28.6': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.28.6': {} + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.28.6': + dependencies: + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + + '@babel/parser@7.29.0': + dependencies: + '@babel/types': 7.29.0 + + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/template@7.28.6': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + + '@babel/traverse@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@esbuild/aix-ppc64@0.25.12': + optional: true + + '@esbuild/android-arm64@0.25.12': + optional: true + + '@esbuild/android-arm@0.25.12': + optional: true + + '@esbuild/android-x64@0.25.12': + optional: true + + '@esbuild/darwin-arm64@0.25.12': + optional: true + + '@esbuild/darwin-x64@0.25.12': + optional: true + + '@esbuild/freebsd-arm64@0.25.12': + optional: true + + '@esbuild/freebsd-x64@0.25.12': + optional: true + + '@esbuild/linux-arm64@0.25.12': + optional: true + + '@esbuild/linux-arm@0.25.12': + optional: true + + '@esbuild/linux-ia32@0.25.12': + optional: true + + '@esbuild/linux-loong64@0.25.12': + optional: true + + '@esbuild/linux-mips64el@0.25.12': + optional: true + + '@esbuild/linux-ppc64@0.25.12': + optional: true + + '@esbuild/linux-riscv64@0.25.12': + optional: true + + '@esbuild/linux-s390x@0.25.12': + optional: true + + '@esbuild/linux-x64@0.25.12': + optional: true + + '@esbuild/netbsd-arm64@0.25.12': + optional: true + + '@esbuild/netbsd-x64@0.25.12': + optional: true + + '@esbuild/openbsd-arm64@0.25.12': + optional: true + + '@esbuild/openbsd-x64@0.25.12': + optional: true + + '@esbuild/openharmony-arm64@0.25.12': + optional: true + + '@esbuild/sunos-x64@0.25.12': + optional: true + + '@esbuild/win32-arm64@0.25.12': + optional: true + + '@esbuild/win32-ia32@0.25.12': + optional: true + + '@esbuild/win32-x64@0.25.12': + optional: true + + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))': + dependencies: + eslint: 9.39.2(jiti@2.6.1) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.21.1': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.3': + dependencies: + ajv: 6.12.6 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.39.2': {} + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 + + '@floating-ui/core@1.7.4': + dependencies: + '@floating-ui/utils': 0.2.10 + + '@floating-ui/dom@1.7.5': + dependencies: + '@floating-ui/core': 1.7.4 + '@floating-ui/utils': 0.2.10 + + '@floating-ui/react-dom@2.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@floating-ui/dom': 1.7.5 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + + '@floating-ui/utils@0.2.10': {} + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.7': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.4.3 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@radix-ui/number@1.1.1': {} + + '@radix-ui/primitive@1.1.3': {} + + '@radix-ui/react-arrow@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.28 + '@types/react-dom': 18.3.7(@types/react@18.3.28) + + '@radix-ui/react-collection@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.28 + '@types/react-dom': 18.3.7(@types/react@18.3.28) + + '@radix-ui/react-compose-refs@1.1.2(@types/react@18.3.28)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.28 + + '@radix-ui/react-context@1.1.2(@types/react@18.3.28)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.28 + + '@radix-ui/react-dialog@1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) + aria-hidden: 1.2.6 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.28 + '@types/react-dom': 18.3.7(@types/react@18.3.28) + + '@radix-ui/react-direction@1.1.1(@types/react@18.3.28)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.28 + + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@18.3.28)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.28 + '@types/react-dom': 18.3.7(@types/react@18.3.28) + + '@radix-ui/react-focus-guards@1.1.3(@types/react@18.3.28)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.28 + + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.28 + '@types/react-dom': 18.3.7(@types/react@18.3.28) + + '@radix-ui/react-id@1.1.1(@types/react@18.3.28)(react@18.3.1)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.28 + + '@radix-ui/react-label@2.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.28 + '@types/react-dom': 18.3.7(@types/react@18.3.28) + + '@radix-ui/react-popper@1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@floating-ui/react-dom': 2.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-use-rect': 1.1.1(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/rect': 1.1.1 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.28 + '@types/react-dom': 18.3.7(@types/react@18.3.28) + + '@radix-ui/react-portal@1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.28 + '@types/react-dom': 18.3.7(@types/react@18.3.28) + + '@radix-ui/react-presence@1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.28 + '@types/react-dom': 18.3.7(@types/react@18.3.28) + + '@radix-ui/react-primitive@2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.28 + '@types/react-dom': 18.3.7(@types/react@18.3.28) + + '@radix-ui/react-primitive@2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-slot': 1.2.4(@types/react@18.3.28)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.28 + '@types/react-dom': 18.3.7(@types/react@18.3.28) + + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.28 + '@types/react-dom': 18.3.7(@types/react@18.3.28) + + '@radix-ui/react-select@2.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + aria-hidden: 1.2.6 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.28 + '@types/react-dom': 18.3.7(@types/react@18.3.28) + + '@radix-ui/react-separator@1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.28 + '@types/react-dom': 18.3.7(@types/react@18.3.28) + + '@radix-ui/react-slider@1.3.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.28)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.28 + '@types/react-dom': 18.3.7(@types/react@18.3.28) + + '@radix-ui/react-slot@1.2.3(@types/react@18.3.28)(react@18.3.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.28 + + '@radix-ui/react-slot@1.2.4(@types/react@18.3.28)(react@18.3.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.28 + + '@radix-ui/react-switch@1.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.28)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.28 + '@types/react-dom': 18.3.7(@types/react@18.3.28) + + '@radix-ui/react-tabs@1.1.13(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.28 + '@types/react-dom': 18.3.7(@types/react@18.3.28) + + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@18.3.28)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.28 + + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@18.3.28)(react@18.3.1)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.28 + + '@radix-ui/react-use-effect-event@0.0.2(@types/react@18.3.28)(react@18.3.1)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.28 + + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@18.3.28)(react@18.3.1)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.28 + + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@18.3.28)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.28 + + '@radix-ui/react-use-previous@1.1.1(@types/react@18.3.28)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.28 + + '@radix-ui/react-use-rect@1.1.1(@types/react@18.3.28)(react@18.3.1)': + dependencies: + '@radix-ui/rect': 1.1.1 + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.28 + + '@radix-ui/react-use-size@1.1.1(@types/react@18.3.28)(react@18.3.1)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.28 + + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.28 + '@types/react-dom': 18.3.7(@types/react@18.3.28) + + '@radix-ui/rect@1.1.1': {} + + '@remirror/core-constants@3.0.0': {} + + '@remix-run/router@1.23.2': {} + + '@rolldown/pluginutils@1.0.0-beta.27': {} + + '@rollup/rollup-android-arm-eabi@4.57.1': + optional: true + + '@rollup/rollup-android-arm64@4.57.1': + optional: true + + '@rollup/rollup-darwin-arm64@4.57.1': + optional: true + + '@rollup/rollup-darwin-x64@4.57.1': + optional: true + + '@rollup/rollup-freebsd-arm64@4.57.1': + optional: true + + '@rollup/rollup-freebsd-x64@4.57.1': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.57.1': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.57.1': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.57.1': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.57.1': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.57.1': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.57.1': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.57.1': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.57.1': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.57.1': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.57.1': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.57.1': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.57.1': + optional: true + + '@rollup/rollup-linux-x64-musl@4.57.1': + optional: true + + '@rollup/rollup-openbsd-x64@4.57.1': + optional: true + + '@rollup/rollup-openharmony-arm64@4.57.1': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.57.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.57.1': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.57.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.57.1': + optional: true + + '@tailwindcss/node@4.1.18': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.19.0 + jiti: 2.6.1 + lightningcss: 1.30.2 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.1.18 + + '@tailwindcss/oxide-android-arm64@4.1.18': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.1.18': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.18': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.1.18': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.1.18': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.1.18': + optional: true + + '@tailwindcss/oxide@4.1.18': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.18 + '@tailwindcss/oxide-darwin-arm64': 4.1.18 + '@tailwindcss/oxide-darwin-x64': 4.1.18 + '@tailwindcss/oxide-freebsd-x64': 4.1.18 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.18 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.18 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.18 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.18 + '@tailwindcss/oxide-linux-x64-musl': 4.1.18 + '@tailwindcss/oxide-wasm32-wasi': 4.1.18 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.18 + + '@tailwindcss/postcss@4.1.18': + dependencies: + '@alloc/quick-lru': 5.2.0 + '@tailwindcss/node': 4.1.18 + '@tailwindcss/oxide': 4.1.18 + postcss: 8.5.6 + tailwindcss: 4.1.18 + + '@tiptap/core@3.20.1(@tiptap/pm@3.20.1)': + dependencies: + '@tiptap/pm': 3.20.1 + + '@tiptap/extension-blockquote@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + + '@tiptap/extension-bold@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + + '@tiptap/extension-bubble-menu@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)': + dependencies: + '@floating-ui/dom': 1.7.5 + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + optional: true + + '@tiptap/extension-bullet-list@3.20.1(@tiptap/extension-list@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/extension-list': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + + '@tiptap/extension-code-block@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + + '@tiptap/extension-code@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + + '@tiptap/extension-document@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + + '@tiptap/extension-dropcursor@3.20.1(@tiptap/extensions@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/extensions': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + + '@tiptap/extension-floating-menu@3.20.1(@floating-ui/dom@1.7.5)(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)': + dependencies: + '@floating-ui/dom': 1.7.5 + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + optional: true + + '@tiptap/extension-gapcursor@3.20.1(@tiptap/extensions@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/extensions': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + + '@tiptap/extension-hard-break@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + + '@tiptap/extension-heading@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + + '@tiptap/extension-horizontal-rule@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + + '@tiptap/extension-image@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + + '@tiptap/extension-italic@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + + '@tiptap/extension-link@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + linkifyjs: 4.3.2 + + '@tiptap/extension-list-item@3.20.1(@tiptap/extension-list@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/extension-list': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + + '@tiptap/extension-list-keymap@3.20.1(@tiptap/extension-list@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/extension-list': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + + '@tiptap/extension-list@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + + '@tiptap/extension-mention@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)(@tiptap/suggestion@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + '@tiptap/suggestion': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + + '@tiptap/extension-ordered-list@3.20.1(@tiptap/extension-list@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/extension-list': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + + '@tiptap/extension-paragraph@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + + '@tiptap/extension-placeholder@3.20.1(@tiptap/extensions@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/extensions': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + + '@tiptap/extension-strike@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + + '@tiptap/extension-table-cell@3.20.1(@tiptap/extension-table@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/extension-table': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + + '@tiptap/extension-table-header@3.20.1(@tiptap/extension-table@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/extension-table': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + + '@tiptap/extension-table-row@3.20.1(@tiptap/extension-table@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/extension-table': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + + '@tiptap/extension-table@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + + '@tiptap/extension-text@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + + '@tiptap/extension-underline@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + + '@tiptap/extensions@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + + '@tiptap/pm@3.20.1': + dependencies: + prosemirror-changeset: 2.4.0 + prosemirror-collab: 1.3.1 + prosemirror-commands: 1.7.1 + prosemirror-dropcursor: 1.8.2 + prosemirror-gapcursor: 1.4.0 + prosemirror-history: 1.5.0 + prosemirror-inputrules: 1.5.1 + prosemirror-keymap: 1.2.3 + prosemirror-markdown: 1.13.4 + prosemirror-menu: 1.3.0 + prosemirror-model: 1.25.4 + prosemirror-schema-basic: 1.2.4 + prosemirror-schema-list: 1.5.1 + prosemirror-state: 1.4.4 + prosemirror-tables: 1.8.5 + prosemirror-trailing-node: 3.0.0(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6) + prosemirror-transform: 1.11.0 + prosemirror-view: 1.41.6 + + '@tiptap/react@3.20.1(@floating-ui/dom@1.7.5)(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + '@types/react': 18.3.28 + '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@types/use-sync-external-store': 0.0.6 + fast-equals: 5.4.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + use-sync-external-store: 1.6.0(react@18.3.1) + optionalDependencies: + '@tiptap/extension-bubble-menu': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + '@tiptap/extension-floating-menu': 3.20.1(@floating-ui/dom@1.7.5)(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + transitivePeerDependencies: + - '@floating-ui/dom' + + '@tiptap/starter-kit@3.20.1': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/extension-blockquote': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1)) + '@tiptap/extension-bold': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1)) + '@tiptap/extension-bullet-list': 3.20.1(@tiptap/extension-list@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)) + '@tiptap/extension-code': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1)) + '@tiptap/extension-code-block': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + '@tiptap/extension-document': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1)) + '@tiptap/extension-dropcursor': 3.20.1(@tiptap/extensions@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)) + '@tiptap/extension-gapcursor': 3.20.1(@tiptap/extensions@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)) + '@tiptap/extension-hard-break': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1)) + '@tiptap/extension-heading': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1)) + '@tiptap/extension-horizontal-rule': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + '@tiptap/extension-italic': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1)) + '@tiptap/extension-link': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + '@tiptap/extension-list': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + '@tiptap/extension-list-item': 3.20.1(@tiptap/extension-list@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)) + '@tiptap/extension-list-keymap': 3.20.1(@tiptap/extension-list@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)) + '@tiptap/extension-ordered-list': 3.20.1(@tiptap/extension-list@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)) + '@tiptap/extension-paragraph': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1)) + '@tiptap/extension-strike': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1)) + '@tiptap/extension-text': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1)) + '@tiptap/extension-underline': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1)) + '@tiptap/extensions': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + + '@tiptap/suggestion@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.29.0 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.29.0 + + '@types/estree@1.0.8': {} + + '@types/json-schema@7.0.15': {} + + '@types/linkify-it@5.0.0': {} + + '@types/markdown-it@14.1.2': + dependencies: + '@types/linkify-it': 5.0.0 + '@types/mdurl': 2.0.0 + + '@types/mdurl@2.0.0': {} + + '@types/prop-types@15.7.15': {} + + '@types/react-dom@18.3.7(@types/react@18.3.28)': + dependencies: + '@types/react': 18.3.28 + + '@types/react@18.3.28': + dependencies: + '@types/prop-types': 15.7.15 + csstype: 3.2.3 + + '@types/use-sync-external-store@0.0.6': {} + + '@typescript-eslint/eslint-plugin@8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.6.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.6.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.6.3) + '@typescript-eslint/scope-manager': 8.54.0 + '@typescript-eslint/type-utils': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.6.3) + '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 8.54.0 + eslint: 9.39.2(jiti@2.6.1) + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.4.0(typescript@5.6.3) + typescript: 5.6.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.6.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.54.0 + '@typescript-eslint/types': 8.54.0 + '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 8.54.0 + debug: 4.4.3 + eslint: 9.39.2(jiti@2.6.1) + typescript: 5.6.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.54.0(typescript@5.6.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.54.0(typescript@5.6.3) + '@typescript-eslint/types': 8.54.0 + debug: 4.4.3 + typescript: 5.6.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.54.0': + dependencies: + '@typescript-eslint/types': 8.54.0 + '@typescript-eslint/visitor-keys': 8.54.0 + + '@typescript-eslint/tsconfig-utils@8.54.0(typescript@5.6.3)': + dependencies: + typescript: 5.6.3 + + '@typescript-eslint/type-utils@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.6.3)': + dependencies: + '@typescript-eslint/types': 8.54.0 + '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.6.3) + '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.6.3) + debug: 4.4.3 + eslint: 9.39.2(jiti@2.6.1) + ts-api-utils: 2.4.0(typescript@5.6.3) + typescript: 5.6.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.54.0': {} + + '@typescript-eslint/typescript-estree@8.54.0(typescript@5.6.3)': + dependencies: + '@typescript-eslint/project-service': 8.54.0(typescript@5.6.3) + '@typescript-eslint/tsconfig-utils': 8.54.0(typescript@5.6.3) + '@typescript-eslint/types': 8.54.0 + '@typescript-eslint/visitor-keys': 8.54.0 + debug: 4.4.3 + minimatch: 9.0.5 + semver: 7.7.4 + tinyglobby: 0.2.15 + ts-api-utils: 2.4.0(typescript@5.6.3) + typescript: 5.6.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.6.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.54.0 + '@typescript-eslint/types': 8.54.0 + '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.6.3) + eslint: 9.39.2(jiti@2.6.1) + typescript: 5.6.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.54.0': + dependencies: + '@typescript-eslint/types': 8.54.0 + eslint-visitor-keys: 4.2.1 + + '@vitejs/plugin-react@4.7.0(vite@6.4.1(jiti@2.6.1)(lightningcss@1.30.2))': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) + '@rolldown/pluginutils': 1.0.0-beta.27 + '@types/babel__core': 7.20.5 + react-refresh: 0.17.0 + vite: 6.4.1(jiti@2.6.1)(lightningcss@1.30.2) + transitivePeerDependencies: + - supports-color + + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + argparse@2.0.1: {} + + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + + autoprefixer@10.4.24(postcss@8.5.6): + dependencies: + browserslist: 4.28.1 + caniuse-lite: 1.0.30001769 + fraction.js: 5.3.4 + picocolors: 1.1.1 + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + balanced-match@1.0.2: {} + + baseline-browser-mapping@2.9.19: {} + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + browserslist@4.28.1: + dependencies: + baseline-browser-mapping: 2.9.19 + caniuse-lite: 1.0.30001769 + electron-to-chromium: 1.5.286 + node-releases: 2.0.27 + update-browserslist-db: 1.2.3(browserslist@4.28.1) + + callsites@3.1.0: {} + + caniuse-lite@1.0.30001769: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + + clsx@2.1.1: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + concat-map@0.0.1: {} + + convert-source-map@2.0.0: {} + + crelt@1.0.6: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.2.3: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + deep-is@0.1.4: {} + + detect-libc@2.1.2: {} + + detect-node-es@1.1.0: {} + + electron-to-chromium@1.5.286: {} + + enhanced-resolve@5.19.0: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.0 + + entities@4.5.0: {} + + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + + escalade@3.2.0: {} + + escape-string-regexp@4.0.0: {} + + eslint-plugin-react-hooks@5.2.0(eslint@9.39.2(jiti@2.6.1)): + dependencies: + eslint: 9.39.2(jiti@2.6.1) + + eslint-plugin-react-refresh@0.4.26(eslint@9.39.2(jiti@2.6.1)): + dependencies: + eslint: 9.39.2(jiti@2.6.1) + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint@9.39.2(jiti@2.6.1): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.1 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 + '@eslint/eslintrc': 3.3.3 + '@eslint/js': 9.39.2 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.6.1 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + esutils@2.0.3: {} + + fast-deep-equal@3.1.3: {} + + fast-equals@5.4.0: {} + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fdir@6.5.0(picomatch@4.0.2): + optionalDependencies: + picomatch: 4.0.2 + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flatted@3.3.3: {} + + fraction.js@5.3.4: {} + + fsevents@2.3.3: + optional: true + + gensync@1.0.0-beta.2: {} + + get-nonce@1.0.1: {} + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + globals@14.0.0: {} + + globals@15.15.0: {} + + graceful-fs@4.2.11: {} + + has-flag@4.0.0: {} + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + isexe@2.0.0: {} + + jiti@2.6.1: {} + + js-tokens@4.0.0: {} + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@2.2.3: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lightningcss-android-arm64@1.30.2: + optional: true + + lightningcss-darwin-arm64@1.30.2: + optional: true + + lightningcss-darwin-x64@1.30.2: + optional: true + + lightningcss-freebsd-x64@1.30.2: + optional: true + + lightningcss-linux-arm-gnueabihf@1.30.2: + optional: true + + lightningcss-linux-arm64-gnu@1.30.2: + optional: true + + lightningcss-linux-arm64-musl@1.30.2: + optional: true + + lightningcss-linux-x64-gnu@1.30.2: + optional: true + + lightningcss-linux-x64-musl@1.30.2: + optional: true + + lightningcss-win32-arm64-msvc@1.30.2: + optional: true + + lightningcss-win32-x64-msvc@1.30.2: + optional: true + + lightningcss@1.30.2: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.30.2 + lightningcss-darwin-arm64: 1.30.2 + lightningcss-darwin-x64: 1.30.2 + lightningcss-freebsd-x64: 1.30.2 + lightningcss-linux-arm-gnueabihf: 1.30.2 + lightningcss-linux-arm64-gnu: 1.30.2 + lightningcss-linux-arm64-musl: 1.30.2 + lightningcss-linux-x64-gnu: 1.30.2 + lightningcss-linux-x64-musl: 1.30.2 + lightningcss-win32-arm64-msvc: 1.30.2 + lightningcss-win32-x64-msvc: 1.30.2 + + linkify-it@5.0.0: + dependencies: + uc.micro: 2.1.0 + + linkifyjs@4.3.2: {} + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lucide-react@0.562.0(react@18.3.1): + dependencies: + react: 18.3.1 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + markdown-it@14.1.1: + dependencies: + argparse: 2.0.1 + entities: 4.5.0 + linkify-it: 5.0.0 + mdurl: 2.0.0 + punycode.js: 2.3.1 + uc.micro: 2.1.0 + + mdurl@2.0.0: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.12 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + natural-compare@1.4.0: {} + + node-releases@2.0.27: {} + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + orderedmap@2.1.1: {} + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + picocolors@1.1.1: {} + + picomatch@4.0.2: {} + + picomatch@4.0.3: {} + + postcss-value-parser@4.2.0: {} + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + prosemirror-changeset@2.4.0: + dependencies: + prosemirror-transform: 1.11.0 + + prosemirror-collab@1.3.1: + dependencies: + prosemirror-state: 1.4.4 + + prosemirror-commands@1.7.1: + dependencies: + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.11.0 + + prosemirror-dropcursor@1.8.2: + dependencies: + prosemirror-state: 1.4.4 + prosemirror-transform: 1.11.0 + prosemirror-view: 1.41.6 + + prosemirror-gapcursor@1.4.0: + dependencies: + prosemirror-keymap: 1.2.3 + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-view: 1.41.6 + + prosemirror-history@1.5.0: + dependencies: + prosemirror-state: 1.4.4 + prosemirror-transform: 1.11.0 + prosemirror-view: 1.41.6 + rope-sequence: 1.3.4 + + prosemirror-inputrules@1.5.1: + dependencies: + prosemirror-state: 1.4.4 + prosemirror-transform: 1.11.0 + + prosemirror-keymap@1.2.3: + dependencies: + prosemirror-state: 1.4.4 + w3c-keyname: 2.2.8 + + prosemirror-markdown@1.13.4: + dependencies: + '@types/markdown-it': 14.1.2 + markdown-it: 14.1.1 + prosemirror-model: 1.25.4 + + prosemirror-menu@1.3.0: + dependencies: + crelt: 1.0.6 + prosemirror-commands: 1.7.1 + prosemirror-history: 1.5.0 + prosemirror-state: 1.4.4 + + prosemirror-model@1.25.4: + dependencies: + orderedmap: 2.1.1 + + prosemirror-schema-basic@1.2.4: + dependencies: + prosemirror-model: 1.25.4 + + prosemirror-schema-list@1.5.1: + dependencies: + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.11.0 + + prosemirror-state@1.4.4: + dependencies: + prosemirror-model: 1.25.4 + prosemirror-transform: 1.11.0 + prosemirror-view: 1.41.6 + + prosemirror-tables@1.8.5: + dependencies: + prosemirror-keymap: 1.2.3 + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.11.0 + prosemirror-view: 1.41.6 + + prosemirror-trailing-node@3.0.0(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6): + dependencies: + '@remirror/core-constants': 3.0.0 + escape-string-regexp: 4.0.0 + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-view: 1.41.6 + + prosemirror-transform@1.11.0: + dependencies: + prosemirror-model: 1.25.4 + + prosemirror-view@1.41.6: + dependencies: + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.11.0 + + punycode.js@2.3.1: {} + + punycode@2.3.1: {} + + react-dom@18.3.1(react@18.3.1): + dependencies: + loose-envify: 1.4.0 + react: 18.3.1 + scheduler: 0.23.2 + + react-refresh@0.17.0: {} + + react-remove-scroll-bar@2.3.8(@types/react@18.3.28)(react@18.3.1): + dependencies: + react: 18.3.1 + react-style-singleton: 2.2.3(@types/react@18.3.28)(react@18.3.1) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 18.3.28 + + react-remove-scroll@2.7.2(@types/react@18.3.28)(react@18.3.1): + dependencies: + react: 18.3.1 + react-remove-scroll-bar: 2.3.8(@types/react@18.3.28)(react@18.3.1) + react-style-singleton: 2.2.3(@types/react@18.3.28)(react@18.3.1) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@18.3.28)(react@18.3.1) + use-sidecar: 1.1.3(@types/react@18.3.28)(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.28 + + react-router-dom@6.30.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + '@remix-run/router': 1.23.2 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-router: 6.30.3(react@18.3.1) + + react-router@6.30.3(react@18.3.1): + dependencies: + '@remix-run/router': 1.23.2 + react: 18.3.1 + + react-style-singleton@2.2.3(@types/react@18.3.28)(react@18.3.1): + dependencies: + get-nonce: 1.0.1 + react: 18.3.1 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 18.3.28 + + react@18.3.1: + dependencies: + loose-envify: 1.4.0 + + resolve-from@4.0.0: {} + + rollup@4.57.1: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.57.1 + '@rollup/rollup-android-arm64': 4.57.1 + '@rollup/rollup-darwin-arm64': 4.57.1 + '@rollup/rollup-darwin-x64': 4.57.1 + '@rollup/rollup-freebsd-arm64': 4.57.1 + '@rollup/rollup-freebsd-x64': 4.57.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.57.1 + '@rollup/rollup-linux-arm-musleabihf': 4.57.1 + '@rollup/rollup-linux-arm64-gnu': 4.57.1 + '@rollup/rollup-linux-arm64-musl': 4.57.1 + '@rollup/rollup-linux-loong64-gnu': 4.57.1 + '@rollup/rollup-linux-loong64-musl': 4.57.1 + '@rollup/rollup-linux-ppc64-gnu': 4.57.1 + '@rollup/rollup-linux-ppc64-musl': 4.57.1 + '@rollup/rollup-linux-riscv64-gnu': 4.57.1 + '@rollup/rollup-linux-riscv64-musl': 4.57.1 + '@rollup/rollup-linux-s390x-gnu': 4.57.1 + '@rollup/rollup-linux-x64-gnu': 4.57.1 + '@rollup/rollup-linux-x64-musl': 4.57.1 + '@rollup/rollup-openbsd-x64': 4.57.1 + '@rollup/rollup-openharmony-arm64': 4.57.1 + '@rollup/rollup-win32-arm64-msvc': 4.57.1 + '@rollup/rollup-win32-ia32-msvc': 4.57.1 + '@rollup/rollup-win32-x64-gnu': 4.57.1 + '@rollup/rollup-win32-x64-msvc': 4.57.1 + fsevents: 2.3.3 + + rope-sequence@1.3.4: {} + + scheduler@0.23.2: + dependencies: + loose-envify: 1.4.0 + + semver@6.3.1: {} + + semver@7.7.4: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + source-map-js@1.2.1: {} + + strip-json-comments@3.1.1: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + tailwind-merge@3.4.0: {} + + tailwindcss@4.1.18: {} + + tapable@2.3.0: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + ts-api-utils@2.4.0(typescript@5.6.3): + dependencies: + typescript: 5.6.3 + + tslib@2.8.1: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + typescript-eslint@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.6.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.6.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.6.3) + '@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.6.3) + '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.6.3) + '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.6.3) + eslint: 9.39.2(jiti@2.6.1) + typescript: 5.6.3 + transitivePeerDependencies: + - supports-color + + typescript@5.6.3: {} + + uc.micro@2.1.0: {} + + update-browserslist-db@1.2.3(browserslist@4.28.1): + dependencies: + browserslist: 4.28.1 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + use-callback-ref@1.3.3(@types/react@18.3.28)(react@18.3.1): + dependencies: + react: 18.3.1 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 18.3.28 + + use-sidecar@1.1.3(@types/react@18.3.28)(react@18.3.1): + dependencies: + detect-node-es: 1.1.0 + react: 18.3.1 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 18.3.28 + + use-sync-external-store@1.6.0(react@18.3.1): + dependencies: + react: 18.3.1 + + vite@6.4.1(jiti@2.6.1)(lightningcss@1.30.2): + dependencies: + esbuild: 0.25.12 + fdir: 6.5.0(picomatch@4.0.2) + picomatch: 4.0.2 + postcss: 8.5.6 + rollup: 4.57.1 + tinyglobby: 0.2.15 + optionalDependencies: + fsevents: 2.3.3 + jiti: 2.6.1 + lightningcss: 1.30.2 + + w3c-keyname@2.2.8: {} + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + yallist@3.1.1: {} + + yocto-queue@0.1.0: {} + + zustand@5.0.9(@types/react@18.3.28)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)): + optionalDependencies: + '@types/react': 18.3.28 + react: 18.3.1 + use-sync-external-store: 1.6.0(react@18.3.1) diff --git a/new-soul/soul-admin/postcss.config.js b/new-soul/soul-admin/postcss.config.js new file mode 100644 index 00000000..a7f73a2d --- /dev/null +++ b/new-soul/soul-admin/postcss.config.js @@ -0,0 +1,5 @@ +export default { + plugins: { + '@tailwindcss/postcss': {}, + }, +} diff --git a/new-soul/soul-admin/src/App.tsx b/new-soul/soul-admin/src/App.tsx new file mode 100644 index 00000000..1870aada --- /dev/null +++ b/new-soul/soul-admin/src/App.tsx @@ -0,0 +1,58 @@ +import { Routes, Route, Navigate } from 'react-router-dom' +import { AdminLayout } from './layouts/AdminLayout' +import { LoginPage } from './pages/login/LoginPage' +import { DashboardPage } from './pages/dashboard/DashboardPage' +import { OrdersPage } from './pages/orders/OrdersPage' +import { UsersPage } from './pages/users/UsersPage' +import { DistributionPage } from './pages/distribution/DistributionPage' +import { WithdrawalsPage } from './pages/withdrawals/WithdrawalsPage' +import { ContentPage } from './pages/content/ContentPage' +import { ReferralSettingsPage } from './pages/referral-settings/ReferralSettingsPage' +import { SettingsPage } from './pages/settings/SettingsPage' +import { PaymentPage } from './pages/payment/PaymentPage' +import { SitePage } from './pages/site/SitePage' +import { QRCodesPage } from './pages/qrcodes/QRCodesPage' +import { MatchPage } from './pages/match/MatchPage' +import { MatchRecordsPage } from './pages/match-records/MatchRecordsPage' +import { VipRolesPage } from './pages/vip-roles/VipRolesPage' +import { MentorsPage } from './pages/mentors/MentorsPage' +import { MentorConsultationsPage } from './pages/mentor-consultations/MentorConsultationsPage' +import { FindPartnerPage } from './pages/find-partner/FindPartnerPage' +import { ApiDocPage } from './pages/api-doc/ApiDocPage' +import { ApiDocsPage } from './pages/api-docs/ApiDocsPage' +import { NotFoundPage } from './pages/not-found/NotFoundPage' + +function App() { + return ( + + } /> + }> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + } /> + + ) +} + +export default App diff --git a/new-soul/soul-admin/src/api/auth.ts b/new-soul/soul-admin/src/api/auth.ts new file mode 100644 index 00000000..c89169bf --- /dev/null +++ b/new-soul/soul-admin/src/api/auth.ts @@ -0,0 +1,28 @@ +/** + * 管理端 JWT 本地存储(localStorage),与 soul-api JWT 鉴权配合 + */ +const ADMIN_TOKEN_KEY = 'admin_token' + +export function getAdminToken(): string | null { + try { + return localStorage.getItem(ADMIN_TOKEN_KEY) + } catch { + return null + } +} + +export function setAdminToken(token: string): void { + try { + localStorage.setItem(ADMIN_TOKEN_KEY, token) + } catch { + // ignore + } +} + +export function clearAdminToken(): void { + try { + localStorage.removeItem(ADMIN_TOKEN_KEY) + } catch { + // ignore + } +} diff --git a/new-soul/soul-admin/src/api/ckb.ts b/new-soul/soul-admin/src/api/ckb.ts new file mode 100644 index 00000000..72d4d3dc --- /dev/null +++ b/new-soul/soul-admin/src/api/ckb.ts @@ -0,0 +1,87 @@ +import { get } from './client' + +export interface CkbDevice { + id: number | string + memo: string + wechatId?: string + status?: 'online' | 'offline' | string + avatar?: string + nickname?: string + totalFriend?: number +} + +export interface CkbDevicesResponse { + success?: boolean + error?: string + devices?: CkbDevice[] + total?: number +} + +// 管理端 - 存客宝设备列表(供链接人与事选择设备) +export function getCkbDevices(params?: { page?: number; limit?: number; keyword?: string }) { + const search = new URLSearchParams() + if (params?.page) search.set('page', String(params.page)) + if (params?.limit) search.set('limit', String(params.limit)) + if (params?.keyword?.trim()) search.set('keyword', params.keyword.trim()) + const qs = search.toString() + const path = qs ? `/api/admin/ckb/devices?${qs}` : '/api/admin/ckb/devices' + return get(path) +} + +// 管理端 - 人物详情(本地 + 存客宝缓存字段),用于编辑回显 +export interface PersonDetailResponse { + success?: boolean + error?: string + person?: { + personId: string + token?: string + name: string + label?: string + ckbApiKey?: string + greeting?: string + tips?: string + remarkType?: string + remarkFormat?: string + addFriendInterval?: number + startTime?: string + endTime?: string + deviceGroups?: string + } +} + +export function getPersonDetail(personId: string) { + return get(`/api/db/person?personId=${encodeURIComponent(personId)}`) +} + +export interface CkbPlan { + id: number | string + name: string + apiKey?: string + sceneId?: number + scenario?: number + enabled?: boolean + greeting?: string + tips?: string + remarkType?: string + remarkFormat?: string + addInterval?: number + startTime?: string + endTime?: string + deviceGroups?: (number | string)[] +} + +export interface CkbPlansResponse { + success?: boolean + error?: string + plans?: CkbPlan[] + total?: number +} + +export function getCkbPlans(params?: { page?: number; limit?: number; keyword?: string }) { + const search = new URLSearchParams() + if (params?.page) search.set('page', String(params.page)) + if (params?.limit) search.set('limit', String(params.limit)) + if (params?.keyword?.trim()) search.set('keyword', params.keyword.trim()) + const qs = search.toString() + return get(qs ? `/api/admin/ckb/plans?${qs}` : '/api/admin/ckb/plans') +} diff --git a/new-soul/soul-admin/src/api/client.ts b/new-soul/soul-admin/src/api/client.ts new file mode 100644 index 00000000..d7340608 --- /dev/null +++ b/new-soul/soul-admin/src/api/client.ts @@ -0,0 +1,92 @@ +/** + * 统一 API 请求封装 + * 规则:API 路径与现网完全一致,仅通过 baseUrl 区分环境(Next 或未来 Gin) + * 鉴权:管理端使用 JWT,自动带 Authorization: Bearer (token 存 localStorage) + */ + +import { getAdminToken } from './auth' + +/** 未设置环境变量时使用的默认 API 地址(零配置部署) */ +const DEFAULT_API_BASE = 'https://soulapi.quwanzhi.com' + +/** 请求超时(毫秒),避免接口无响应时一直卡在加载中 */ +const REQUEST_TIMEOUT = 15000 + +const getBaseUrl = (): string => { + const url = import.meta.env.VITE_API_BASE_URL + if (typeof url === 'string' && url.length > 0) return url.replace(/\/$/, '') + return DEFAULT_API_BASE +} + +/** 请求完整 URL:baseUrl + path,path 必须与现网一致(如 /api/orders) */ +export function apiUrl(path: string): string { + const base = getBaseUrl() + const p = path.startsWith('/') ? path : `/${path}` + return base ? `${base}${p}` : p +} + +export type RequestInitWithBody = RequestInit & { data?: unknown } + +/** + * 发起请求。path 为与现网一致的 API 路径(如 /api/admin、/api/orders)。 + * 若有 admin_token(JWT)则自动带 Authorization: Bearer;credentials: 'include' 保留以兼容需 Cookie 的接口。 + */ +export async function request( + path: string, + options: RequestInitWithBody = {} +): Promise { + const { data, ...init } = options + const url = apiUrl(path) + const headers = new Headers(init.headers as HeadersInit) + const token = getAdminToken() + if (token) { + headers.set('Authorization', `Bearer ${token}`) + } + if (data !== undefined && data !== null && !headers.has('Content-Type')) { + headers.set('Content-Type', 'application/json') + } + const body = data !== undefined && data !== null ? JSON.stringify(data) : init.body + const controller = new AbortController() + const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT) + const res = await fetch(url, { + ...init, + headers, + body, + credentials: 'include', + signal: controller.signal, + }).finally(() => clearTimeout(timeoutId)) + const contentType = res.headers.get('Content-Type') || '' + const json: T = contentType.includes('application/json') + ? ((await res.json()) as T) + : (res as unknown as T) + if (!res.ok) { + const err = new Error((json as { error?: string })?.error || `HTTP ${res.status}`) as Error & { + status: number + data: T + } + err.status = res.status + err.data = json + throw err + } + return json +} + +/** GET */ +export function get(path: string, init?: RequestInit): Promise { + return request(path, { ...init, method: 'GET' }) +} + +/** POST */ +export function post(path: string, data?: unknown, init?: RequestInit): Promise { + return request(path, { ...init, method: 'POST', data }) +} + +/** PUT */ +export function put(path: string, data?: unknown, init?: RequestInit): Promise { + return request(path, { ...init, method: 'PUT', data }) +} + +/** DELETE */ +export function del(path: string, init?: RequestInit): Promise { + return request(path, { ...init, method: 'DELETE' }) +} diff --git a/new-soul/soul-admin/src/components/RichEditor.css b/new-soul/soul-admin/src/components/RichEditor.css new file mode 100644 index 00000000..3f981acf --- /dev/null +++ b/new-soul/soul-admin/src/components/RichEditor.css @@ -0,0 +1,239 @@ +.rich-editor-wrapper { + border: 1px solid #374151; + border-radius: 0.5rem; + background: #0a1628; + overflow: hidden; +} + +.rich-editor-toolbar { + display: flex; + align-items: center; + gap: 2px; + padding: 6px 8px; + border-bottom: 1px solid #374151; + background: #0f1d32; + flex-wrap: wrap; +} + +.toolbar-group { + display: flex; + align-items: center; + gap: 1px; +} + +.toolbar-divider { + width: 1px; + height: 20px; + background: #374151; + margin: 0 4px; +} + +.rich-editor-toolbar button { + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + border-radius: 4px; + border: none; + background: transparent; + color: #9ca3af; + cursor: pointer; + transition: all 0.15s; +} +.rich-editor-toolbar button:hover { background: #1f2937; color: #d1d5db; } +.rich-editor-toolbar button.is-active { background: rgba(56, 189, 172, 0.2); color: #38bdac; } +.rich-editor-toolbar button:disabled { opacity: 0.3; cursor: not-allowed; } + +.link-tag-select { + background: #0a1628; + border: 1px solid #374151; + color: #d1d5db; + font-size: 12px; + padding: 2px 6px; + border-radius: 4px; + cursor: pointer; + max-width: 160px; +} + +.link-input-bar { + display: flex; + align-items: center; + gap: 4px; + padding: 4px 8px; + border-bottom: 1px solid #374151; + background: #0f1d32; +} +.link-input { + flex: 1; + background: #0a1628; + border: 1px solid #374151; + color: white; + padding: 4px 8px; + border-radius: 4px; + font-size: 13px; +} +.link-confirm, .link-remove { + padding: 4px 10px; + border-radius: 4px; + border: none; + font-size: 12px; + cursor: pointer; +} +.link-confirm { background: #38bdac; color: white; } +.link-remove { background: #374151; color: #9ca3af; } + +.rich-editor-content { + min-height: 300px; + max-height: 500px; + overflow-y: auto; + padding: 12px 16px; + color: #e5e7eb; + font-size: 14px; + line-height: 1.7; +} + +.rich-editor-content:focus { outline: none; } + +.rich-editor-content h1 { font-size: 1.5em; font-weight: 700; margin: 0.8em 0 0.4em; color: white; } +.rich-editor-content h2 { font-size: 1.3em; font-weight: 600; margin: 0.7em 0 0.3em; color: white; } +.rich-editor-content h3 { font-size: 1.15em; font-weight: 600; margin: 0.6em 0 0.3em; color: white; } +.rich-editor-content p { margin: 0.4em 0; } +.rich-editor-content strong { color: white; } +.rich-editor-content code { background: #1f2937; padding: 2px 6px; border-radius: 3px; font-size: 0.9em; color: #38bdac; } +.rich-editor-content pre { background: #1f2937; padding: 12px; border-radius: 6px; overflow-x: auto; margin: 0.6em 0; } +.rich-editor-content blockquote { + border-left: 3px solid #38bdac; + padding-left: 12px; + margin: 0.6em 0; + color: #9ca3af; +} +.rich-editor-content ul, .rich-editor-content ol { padding-left: 1.5em; margin: 0.4em 0; } +.rich-editor-content li { margin: 0.2em 0; } +.rich-editor-content hr { border: none; border-top: 1px solid #374151; margin: 1em 0; } +.rich-editor-content img { max-width: 100%; border-radius: 6px; margin: 0.5em 0; } +.rich-editor-content a, .rich-link { color: #38bdac; text-decoration: underline; cursor: pointer; } + +.rich-editor-content table { + border-collapse: collapse; + width: 100%; + margin: 0.5em 0; +} +.rich-editor-content th, .rich-editor-content td { + border: 1px solid #374151; + padding: 6px 10px; + text-align: left; +} +.rich-editor-content th { background: #1f2937; font-weight: 600; } + +.rich-editor-content .ProseMirror-placeholder::before { + content: attr(data-placeholder); + color: #6b7280; + float: left; + height: 0; + pointer-events: none; +} + +.mention-tag { + background: rgba(56, 189, 172, 0.15); + color: #38bdac; + border-radius: 4px; + padding: 1px 4px; + font-weight: 500; +} + +/* #linkTag 高亮:与小程序 read.wxss .link-tag 金黄色保持一致 */ +.link-tag-node { + background: rgba(255, 215, 0, 0.12); + color: #FFD700; + border-radius: 4px; + padding: 1px 4px; + font-weight: 500; + cursor: default; + user-select: all; +} + +.mention-popup { + position: fixed; + z-index: 9999; + background: #1a2638; + border: 1px solid #374151; + border-radius: 8px; + padding: 4px; + min-width: 180px; + max-height: 240px; + overflow-y: auto; + box-shadow: 0 4px 20px rgba(0,0,0,0.4); +} +.mention-item { + display: flex; + align-items: center; + justify-content: space-between; + padding: 6px 10px; + border-radius: 4px; + cursor: pointer; + color: #d1d5db; + font-size: 13px; +} +.mention-item:hover, .mention-item.is-selected { + background: rgba(56, 189, 172, 0.15); + color: #38bdac; +} +.mention-name { font-weight: 500; } +.mention-id { font-size: 11px; color: #6b7280; } + +.bubble-menu { + display: flex; + gap: 2px; + background: #1a2638; + border: 1px solid #374151; + border-radius: 6px; + padding: 4px; + box-shadow: 0 4px 12px rgba(0,0,0,0.3); +} +.bubble-menu button { + display: flex; + align-items: center; + justify-content: center; + width: 26px; + height: 26px; + border-radius: 4px; + border: none; + background: transparent; + color: #9ca3af; + cursor: pointer; +} +.bubble-menu button:hover { background: #1f2937; color: #d1d5db; } +.bubble-menu button.is-active { color: #38bdac; } + +/* @ 按钮高亮 */ +.mention-trigger-btn { color: #38bdac !important; } +.mention-trigger-btn:hover { background: rgba(56, 189, 172, 0.2) !important; } + +/* 上传进度条 */ +.upload-progress-bar { + display: flex; + align-items: center; + gap: 8px; + padding: 4px 10px; + background: #0f1d32; + border-bottom: 1px solid #374151; +} +.upload-progress-track { + flex: 1; + height: 4px; + background: #1f2937; + border-radius: 2px; + overflow: hidden; +} +.upload-progress-fill { + height: 100%; + background: linear-gradient(90deg, #38bdac, #4ae3ce); + border-radius: 2px; + transition: width 0.3s ease; +} +.upload-progress-text { + font-size: 11px; + color: #38bdac; + white-space: nowrap; +} diff --git a/new-soul/soul-admin/src/components/RichEditor.tsx b/new-soul/soul-admin/src/components/RichEditor.tsx new file mode 100644 index 00000000..a2b233bc --- /dev/null +++ b/new-soul/soul-admin/src/components/RichEditor.tsx @@ -0,0 +1,635 @@ +import { useEditor, EditorContent, type Editor, Node as TiptapNode, mergeAttributes } from '@tiptap/react' +import StarterKit from '@tiptap/starter-kit' +import Image from '@tiptap/extension-image' +import Link from '@tiptap/extension-link' +import Mention from '@tiptap/extension-mention' +import Placeholder from '@tiptap/extension-placeholder' +import { Table, TableRow, TableCell, TableHeader } from '@tiptap/extension-table' +import { useCallback, useEffect, useRef, useState, forwardRef, useImperativeHandle } from 'react' +import { + Bold, Italic, Strikethrough, Code, List, ListOrdered, Quote, + Heading1, Heading2, Heading3, Image as ImageIcon, Link as LinkIcon, + Table as TableIcon, Undo, Redo, Minus, Video, AtSign, +} from 'lucide-react' + +export interface PersonItem { + id: string // token,文章 @ 时存此值,小程序用此兑换真实密钥 + personId?: string // 管理端编辑/删除用 + name: string + aliases?: string // comma-separated alternative names + label?: string + ckbApiKey?: string // 存客宝真实密钥,管理端可见,不对外暴露 + ckbPlanId?: number + // 存客宝创建计划用(与 Cunkebao 好友申请设置一致) + remarkType?: string + remarkFormat?: string + addFriendInterval?: number + startTime?: string + endTime?: string + deviceGroups?: string +} + +export interface LinkTagItem { + id: string + label: string + aliases?: string // comma-separated alternative labels + url: string + type: 'url' | 'miniprogram' | 'ckb' + appId?: string + pagePath?: string +} + +export interface RichEditorRef { + getHTML: () => string + getMarkdown: () => string +} + +interface RichEditorProps { + content: string + onChange: (html: string) => void + onImageUpload?: (file: File) => Promise + onVideoUpload?: (file: File) => Promise + persons?: PersonItem[] + linkTags?: LinkTagItem[] + onPersonCreate?: (name: string) => Promise + placeholder?: string + className?: string +} + +function normalizeMatchKey(value?: string): string { + return (value || '').trim().toLowerCase() +} + +function getPersonMatchKeys(person: PersonItem): string[] { + return [person.name, ...(person.aliases ? person.aliases.split(',') : [])] + .map(normalizeMatchKey) + .filter(Boolean) +} + +function getLinkTagMatchKeys(tag: LinkTagItem): string[] { + return [tag.label, ...(tag.aliases ? tag.aliases.split(',') : [])] + .map(normalizeMatchKey) + .filter(Boolean) +} + +function autoMatchMentionsAndTags(html: string, persons: PersonItem[], linkTags: LinkTagItem[]): string { + if (!html || (!persons.length && !linkTags.length) || typeof document === 'undefined') return html + + const personMap = new Map() + const linkTagMap = new Map() + + for (const person of persons) { + for (const key of getPersonMatchKeys(person)) { + if (!personMap.has(key)) personMap.set(key, person) + } + } + for (const tag of linkTags) { + for (const key of getLinkTagMatchKeys(tag)) { + if (!linkTagMap.has(key)) linkTagMap.set(key, tag) + } + } + + const container = document.createElement('div') + container.innerHTML = html + + const processTextNode = (node: Text) => { + const text = node.textContent || '' + if (!text || (!text.includes('@') && !text.includes('@') && !text.includes('#'))) return + + const parent = node.parentNode + if (!parent) return + + const fragment = document.createDocumentFragment() + const regex = /([@@][^\s@#@#]+|#[^\s@#@#]+)/g + let lastIndex = 0 + let match: RegExpExecArray | null + + while ((match = regex.exec(text)) !== null) { + const [full] = match + const index = match.index + if (index > lastIndex) { + fragment.appendChild(document.createTextNode(text.slice(lastIndex, index))) + } + + if (full.startsWith('@') || full.startsWith('@')) { + const person = personMap.get(normalizeMatchKey(full.slice(1))) + if (person) { + const span = document.createElement('span') + span.setAttribute('data-type', 'mention') + span.setAttribute('data-id', person.id) + span.setAttribute('data-label', person.name) + span.className = 'mention-tag' + span.textContent = `@${person.name}` + fragment.appendChild(span) + } else { + fragment.appendChild(document.createTextNode(full)) + } + } else { + const tag = linkTagMap.get(normalizeMatchKey(full.slice(1))) + if (tag) { + const span = document.createElement('span') + span.setAttribute('data-type', 'linkTag') + span.setAttribute('data-url', tag.url || '') + span.setAttribute('data-tag-type', tag.type || 'url') + span.setAttribute('data-tag-id', tag.id || '') + span.setAttribute('data-page-path', tag.pagePath || '') + span.setAttribute('data-app-id', tag.appId || '') + if (tag.type === 'miniprogram' && tag.appId) { + span.setAttribute('data-mp-key', tag.appId) + } + span.className = 'link-tag-node' + span.textContent = `#${tag.label}` + fragment.appendChild(span) + } else { + fragment.appendChild(document.createTextNode(full)) + } + } + + lastIndex = index + full.length + } + + if (lastIndex < text.length) { + fragment.appendChild(document.createTextNode(text.slice(lastIndex))) + } + + parent.replaceChild(fragment, node) + } + + const walk = (node: globalThis.Node) => { + if (node.nodeType === globalThis.Node.ELEMENT_NODE) { + const el = node as HTMLElement + if (el.matches('[data-type="mention"], [data-type="linkTag"], a, code, pre, script, style')) return + Array.from(el.childNodes).forEach(walk) + return + } + if (node.nodeType === globalThis.Node.TEXT_NODE) processTextNode(node as Text) + } + + Array.from(container.childNodes).forEach(walk) + return container.innerHTML +} + +function htmlToMarkdown(html: string): string { + if (!html) return '' + let md = html + md = md.replace(/]*>(.*?)<\/h1>/gi, '# $1\n\n') + md = md.replace(/]*>(.*?)<\/h2>/gi, '## $1\n\n') + md = md.replace(/]*>(.*?)<\/h3>/gi, '### $1\n\n') + md = md.replace(/]*>(.*?)<\/strong>/gi, '**$1**') + md = md.replace(/]*>(.*?)<\/b>/gi, '**$1**') + md = md.replace(/]*>(.*?)<\/em>/gi, '*$1*') + md = md.replace(/]*>(.*?)<\/i>/gi, '*$1*') + md = md.replace(/]*>(.*?)<\/s>/gi, '~~$1~~') + md = md.replace(/]*>(.*?)<\/del>/gi, '~~$1~~') + md = md.replace(/]*>(.*?)<\/code>/gi, '`$1`') + md = md.replace(/]*>(.*?)<\/blockquote>/gi, '> $1\n\n') + md = md.replace(/]*src="([^"]*)"[^>]*alt="([^"]*)"[^>]*>/gi, '![$2]($1)') + md = md.replace(/]*src="([^"]*)"[^>]*>/gi, '![]($1)') + md = md.replace(/]*href="([^"]*)"[^>]*>(.*?)<\/a>/gi, '[$2]($1)') + md = md.replace(/]*>(.*?)<\/li>/gi, '- $1\n') + md = md.replace(/<\/?[uo]l[^>]*>/gi, '\n') + md = md.replace(//gi, '\n') + md = md.replace(/]*>(.*?)<\/p>/gi, '$1\n\n') + md = md.replace(//gi, '---\n\n') + md = md.replace(/]*data-type="mention"[^>]*data-id="([^"]*)"[^>]*>@([^<]*)<\/span>/gi, '@$2') + md = md.replace(/]*data-type="linkTag"[^>]*data-url="([^"]*)"[^>]*>#([^<]*)<\/span>/gi, '#[$2]($1)') + md = md.replace(/<[^>]+>/g, '') + md = md.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, "'") + md = md.replace(/\n{3,}/g, '\n\n') + return md.trim() +} + +function markdownToHtml(md: string): string { + if (!md) return '' + if (md.startsWith('<') && md.includes('$1') + html = html.replace(/^## (.+)$/gm, '

$1

') + html = html.replace(/^# (.+)$/gm, '

$1

') + html = html.replace(/\*\*(.+?)\*\*/g, '$1') + html = html.replace(/__(.+?)__/g, '$1') + html = html.replace(/(?$1') + html = html.replace(/(?$1') + html = html.replace(/~~(.+?)~~/g, '$1') + html = html.replace(/`([^`]+)`/g, '$1') + html = html.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '$1') + html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1') + html = html.replace(/^> (.+)$/gm, '

$1

') + html = html.replace(/^---$/gm, '
') + html = html.replace(/^- (.+)$/gm, '
  • $1
  • ') + const lines = html.split('\n') + const result: string[] = [] + for (const line of lines) { + const trimmed = line.trim() + if (!trimmed) continue + if (/^<(?:h[1-6]|blockquote|hr|li|ul|ol|table|img)/.test(trimmed)) { + result.push(trimmed) + } else { + result.push(`

    ${trimmed}

    `) + } + } + return result.join('') +} + +/** + * LinkTagExtension — 自定义 TipTap 内联节点,保留所有 data-* 属性 + * 解决:insertContent(html) 会经过 TipTap schema 导致自定义属性被丢弃的问题 + */ +const LinkTagExtension = TiptapNode.create({ + name: 'linkTag', + group: 'inline', + inline: true, + selectable: true, + atom: true, + + addAttributes() { + return { + label: { default: '' }, + url: { default: '' }, + tagType: { default: 'url', parseHTML: (el: HTMLElement) => el.getAttribute('data-tag-type') || 'url' }, + tagId: { default: '', parseHTML: (el: HTMLElement) => el.getAttribute('data-tag-id') || '' }, + pagePath: { default: '', parseHTML: (el: HTMLElement) => el.getAttribute('data-page-path') || '' }, + appId: { default: '', parseHTML: (el: HTMLElement) => el.getAttribute('data-app-id') || '' }, + mpKey: { default: '', parseHTML: (el: HTMLElement) => el.getAttribute('data-mp-key') || '' }, + } + }, + + parseHTML() { + return [{ tag: 'span[data-type="linkTag"]', getAttrs: (el: HTMLElement) => ({ + label: el.textContent?.replace(/^#/, '').trim() || '', + url: el.getAttribute('data-url') || '', + tagType: el.getAttribute('data-tag-type') || 'url', + tagId: el.getAttribute('data-tag-id') || '', + pagePath: el.getAttribute('data-page-path')|| '', + appId: el.getAttribute('data-app-id') || '', + mpKey: el.getAttribute('data-mp-key') || '', + }) }] + }, + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + renderHTML({ node, HTMLAttributes }: { node: any; HTMLAttributes: Record }) { + return ['span', mergeAttributes(HTMLAttributes, { + 'data-type': 'linkTag', + 'data-url': node.attrs.url, + 'data-tag-type': node.attrs.tagType, + 'data-tag-id': node.attrs.tagId, + 'data-page-path': node.attrs.pagePath, + 'data-app-id': node.attrs.appId || '', + 'data-mp-key': node.attrs.mpKey || node.attrs.appId || '', + class: 'link-tag-node', + }), `#${node.attrs.label}`] + }, +}) + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const MentionSuggestion = ( + personsRef: React.RefObject, + onPersonCreateRef: React.RefObject<((name: string) => Promise) | undefined> +): any => ({ + items: ({ query }: { query: string }) => { + const persons = personsRef.current || [] + const q = query.toLowerCase().trim() + const filtered = persons.filter(p => { + if (p.name.toLowerCase().includes(q) || p.id.includes(q)) return true + if (p.aliases) { + return p.aliases.split(',').some(a => a.trim().toLowerCase().includes(q)) + } + return false + }).slice(0, 8) + // 当 query 有内容且无精确名称匹配时,追加「新增人物」选项 + if (q.length >= 1 && !persons.some(p => p.name.toLowerCase() === q)) { + filtered.push({ id: '__new__', name: `+ 新增「${query.trim()}」`, _newName: query.trim() } as PersonItem & { _newName: string }) + } + return filtered + }, + render: () => { + let popup: HTMLDivElement | null = null + let selectedIndex = 0 + let items: PersonItem[] = [] + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let command: ((p: { id: string; label: string }) => void) | null = null + + const selectItem = async (idx: number) => { + const item = items[idx] + if (!item || !command) return + const newItem = item as PersonItem & { _newName?: string } + if (newItem.id === '__new__' && newItem._newName && onPersonCreateRef.current) { + try { + const created = await onPersonCreateRef.current(newItem._newName) + if (created) command({ id: created.id, label: created.name }) + } catch (_) { /* 创建失败,不插入 */ } + } else { + command({ id: item.id, label: item.name }) + } + } + + const update = () => { + if (!popup) return + popup.innerHTML = items.map((item, i) => + `
    + @${item.name} + ${(item as PersonItem & { _newName?: string }).id === '__new__' ? '' : (item.label || item.id)} +
    ` + ).join('') + popup.querySelectorAll('.mention-item').forEach(el => { + el.addEventListener('click', () => { + const idx = parseInt(el.getAttribute('data-index') || '0') + selectItem(idx) + }) + }) + } + + return { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + onStart: (props: any) => { + popup = document.createElement('div') + popup.className = 'mention-popup' + document.body.appendChild(popup) + items = props.items + command = props.command + selectedIndex = 0 + update() + if (props.clientRect) { + const rect = props.clientRect() + if (rect) { + popup.style.top = `${rect.bottom + 4}px` + popup.style.left = `${rect.left}px` + } + } + }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + onUpdate: (props: any) => { + items = props.items + command = props.command + selectedIndex = 0 + update() + if (props.clientRect && popup) { + const rect = props.clientRect() + if (rect) { + popup.style.top = `${rect.bottom + 4}px` + popup.style.left = `${rect.left}px` + } + } + }, + onKeyDown: (props: { event: KeyboardEvent }) => { + if (props.event.key === 'ArrowUp') { selectedIndex = Math.max(0, selectedIndex - 1); update(); return true } + if (props.event.key === 'ArrowDown') { selectedIndex = Math.min(items.length - 1, selectedIndex + 1); update(); return true } + if (props.event.key === 'Enter') { selectItem(selectedIndex); return true } + if (props.event.key === 'Escape') { popup?.remove(); popup = null; return true } + return false + }, + onExit: () => { popup?.remove(); popup = null }, + } + }, +}) + +const RichEditor = forwardRef(({ + content, + onChange, + onImageUpload, + onVideoUpload, + persons = [], + linkTags = [], + onPersonCreate, + placeholder = '开始编辑内容...', + className, +}, ref) => { + const fileInputRef = useRef(null) + const videoInputRef = useRef(null) + const [videoUploading, setVideoUploading] = useState(false) + const [linkUrl, setLinkUrl] = useState('') + const [showLinkInput, setShowLinkInput] = useState(false) + const [imageUploading, setImageUploading] = useState(false) + const [uploadProgress, setUploadProgress] = useState(0) + const initialContent = useRef(autoMatchMentionsAndTags(markdownToHtml(content), persons, linkTags)) + + const onChangeRef = useRef(onChange) + onChangeRef.current = onChange + const personsRef = useRef(persons) + personsRef.current = persons + const linkTagsRef = useRef(linkTags) + linkTagsRef.current = linkTags + const onPersonCreateRef = useRef(onPersonCreate) + onPersonCreateRef.current = onPersonCreate + const debounceTimer = useRef>() + + const editor = useEditor({ + extensions: [ + StarterKit, + Image.configure({ inline: true, allowBase64: true }), + Link.configure({ openOnClick: false, HTMLAttributes: { class: 'rich-link' } }), + Mention.configure({ + HTMLAttributes: { class: 'mention-tag' }, + suggestion: { + ...MentionSuggestion(personsRef, onPersonCreateRef), + allowedPrefixes: null, + }, + }), + LinkTagExtension, + Placeholder.configure({ placeholder }), + Table.configure({ resizable: true }), + TableRow, TableCell, TableHeader, + ], + content: initialContent.current, + onUpdate: ({ editor: ed }: { editor: Editor }) => { + if (debounceTimer.current) clearTimeout(debounceTimer.current) + debounceTimer.current = setTimeout(() => { + const currentHtml = ed.getHTML() + const linkedHtml = autoMatchMentionsAndTags(currentHtml, personsRef.current || [], linkTagsRef.current || []) + if (linkedHtml !== currentHtml) { + ed.commands.setContent(linkedHtml, { emitUpdate: false }) + onChangeRef.current(linkedHtml) + return + } + onChangeRef.current(currentHtml) + }, 300) + }, + editorProps: { + attributes: { class: 'rich-editor-content' }, + }, + }) + + useImperativeHandle(ref, () => ({ + getHTML: () => editor?.getHTML() || '', + getMarkdown: () => htmlToMarkdown(editor?.getHTML() || ''), + })) + + useEffect(() => { + if (!editor) return + const html = autoMatchMentionsAndTags(markdownToHtml(content), personsRef.current || [], linkTagsRef.current || []) + if (html !== editor.getHTML()) { + editor.commands.setContent(html, { emitUpdate: false }) + } + }, [content, editor, persons, linkTags]) + + const handleImageUpload = useCallback(async (e: React.ChangeEvent) => { + const file = e.target.files?.[0] + if (!file || !editor) return + if (onImageUpload) { + setImageUploading(true) + setUploadProgress(10) + const progressTimer = setInterval(() => { + setUploadProgress(prev => Math.min(prev + 15, 90)) + }, 300) + try { + const url = await onImageUpload(file) + clearInterval(progressTimer) + setUploadProgress(100) + if (url) editor.chain().focus().setImage({ src: url }).run() + } finally { + clearInterval(progressTimer) + setTimeout(() => { setImageUploading(false); setUploadProgress(0) }, 500) + } + } else { + const reader = new FileReader() + reader.onload = () => { + if (typeof reader.result === 'string') editor.chain().focus().setImage({ src: reader.result }).run() + } + reader.readAsDataURL(file) + } + e.target.value = '' + }, [editor, onImageUpload]) + + const handleVideoUpload = useCallback(async (e: React.ChangeEvent) => { + const file = e.target.files?.[0] + if (!file || !editor) return + if (onVideoUpload) { + setVideoUploading(true) + setUploadProgress(5) + const progressTimer = setInterval(() => { + setUploadProgress(prev => Math.min(prev + 8, 90)) + }, 500) + try { + const url = await onVideoUpload(file) + clearInterval(progressTimer) + setUploadProgress(100) + if (url) { + editor.chain().focus().insertContent( + `

    ` + ).run() + } + } finally { + clearInterval(progressTimer) + setTimeout(() => { setVideoUploading(false); setUploadProgress(0) }, 500) + } + } + e.target.value = '' + }, [editor, onVideoUpload]) + + const triggerMention = useCallback(() => { + if (!editor) return + editor.chain().focus().insertContent('@').run() + }, [editor]) + + const insertLinkTag = useCallback((tag: LinkTagItem) => { + if (!editor) return + // 通过自定义扩展节点插入,确保 data-* 属性不被 TipTap schema 丢弃 + editor.chain().focus().insertContent({ + type: 'linkTag', + attrs: { + label: tag.label, + url: tag.url || '', + tagType: tag.type || 'url', + tagId: tag.id || '', + pagePath: tag.pagePath || '', + appId: tag.appId || '', + mpKey: tag.type === 'miniprogram' ? (tag.appId || '') : '', + }, + }).run() + }, [editor]) + + const addLink = useCallback(() => { + if (!editor || !linkUrl) return + editor.chain().focus().setLink({ href: linkUrl }).run() + setLinkUrl('') + setShowLinkInput(false) + }, [editor, linkUrl]) + + if (!editor) return null + + return ( +
    +
    +
    + + + + +
    +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + +
    + {linkTags.length > 0 && ( + <> +
    +
    + +
    + + )} +
    + {showLinkInput && ( +
    + setLinkUrl(e.target.value)} + onKeyDown={e => e.key === 'Enter' && addLink()} + className="link-input" + /> + + +
    + )} + {(imageUploading || videoUploading) && ( +
    +
    +
    +
    + {videoUploading ? '视频' : '图片'}上传中 {uploadProgress}% +
    + )} + +
    + ) +}) + +RichEditor.displayName = 'RichEditor' +export default RichEditor diff --git a/new-soul/soul-admin/src/components/modules/user/SetVipModal.tsx b/new-soul/soul-admin/src/components/modules/user/SetVipModal.tsx new file mode 100644 index 00000000..abac7808 --- /dev/null +++ b/new-soul/soul-admin/src/components/modules/user/SetVipModal.tsx @@ -0,0 +1,281 @@ +import toast from '@/utils/toast' +import { useState, useEffect } from 'react' +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogFooter, +} from '@/components/ui/dialog' +import { Button } from '@/components/ui/button' +import { Input } from '@/components/ui/input' +import { Label } from '@/components/ui/label' +import { Switch } from '@/components/ui/switch' +import { Crown, Save, X } from 'lucide-react' +import { get, put } from '@/api/client' + +interface SetVipModalProps { + open: boolean + onClose: () => void + userId: string | null + userNickname?: string + onSaved?: () => void +} + +interface VipRole { + id: number + name: string + sort: number +} + +interface VipForm { + isVip: boolean + vipExpireDate: string + vipSort: number | '' + vipRole: string + vipRoleCustom: string + vipName: string + vipProject: string + vipContact: string + vipBio: string +} + +const DEFAULT_FORM: VipForm = { + isVip: false, + vipExpireDate: '', + vipSort: '', + vipRole: '', + vipRoleCustom: '', + vipName: '', + vipProject: '', + vipContact: '', + vipBio: '', +} + +export function SetVipModal({ + open, + onClose, + userId, + userNickname = '', + onSaved, +}: SetVipModalProps) { + const [form, setForm] = useState(DEFAULT_FORM) + const [roles, setRoles] = useState([]) + const [loading, setLoading] = useState(false) + const [saving, setSaving] = useState(false) + + useEffect(() => { + if (!open) { + setForm(DEFAULT_FORM) + return + } + let cancelled = false + setLoading(true) + Promise.all([ + get<{ success?: boolean; data?: VipRole[]; roles?: VipRole[] }>('/api/db/vip-roles'), + userId ? get<{ success?: boolean; user?: Record }>(`/api/db/users?id=${encodeURIComponent(userId)}`) : Promise.resolve(null), + ]).then(([rolesRes, userRes]) => { + if (cancelled) return + const rolesList = rolesRes?.data || rolesRes?.roles || [] + setRoles(rolesList as VipRole[]) + const u = userRes?.user || null + if (u) { + const vipRole = String(u.vipRole ?? '') + const inRoles = rolesList.some((r: VipRole) => r.name === vipRole) + setForm({ + isVip: !!(u.isVip ?? false), + vipExpireDate: u.vipExpireDate ? String(u.vipExpireDate).slice(0, 10) : '', + vipSort: typeof u.vipSort === 'number' ? u.vipSort : '', + vipRole: inRoles ? vipRole : (vipRole ? '__custom__' : ''), + vipRoleCustom: inRoles ? '' : vipRole, + vipName: String(u.vipName ?? ''), + vipProject: String(u.vipProject ?? ''), + vipContact: String(u.vipContact ?? ''), + vipBio: String(u.vipBio ?? ''), + }) + } else { + setForm(DEFAULT_FORM) + } + }).catch((e) => { + if (!cancelled) console.error('Load error:', e) + }).finally(() => { + if (!cancelled) setLoading(false) + }) + return () => { cancelled = true } + }, [open, userId]) + + async function handleSave() { + if (!userId) return + if (form.isVip && !form.vipExpireDate.trim()) { + toast.error('开启 VIP 时请填写有效到期日') + return + } + if (form.isVip && form.vipExpireDate.trim()) { + const d = new Date(form.vipExpireDate) + if (isNaN(d.getTime())) { + toast.error('到期日格式无效,请使用 YYYY-MM-DD') + return + } + } + setSaving(true) + try { + const roleValue = form.vipRole === '__custom__' ? form.vipRoleCustom.trim() : form.vipRole + const payload: Record = { + id: userId, + isVip: form.isVip, + vipExpireDate: form.isVip ? form.vipExpireDate : undefined, + vipSort: form.vipSort === '' ? undefined : form.vipSort, + vipRole: roleValue || undefined, + vipName: form.vipName || undefined, + vipProject: form.vipProject || undefined, + vipContact: form.vipContact || undefined, + vipBio: form.vipBio || undefined, + } + const data = await put<{ success?: boolean; error?: string }>('/api/db/users', payload) + if (data?.success) { + toast.success('VIP 设置已保存') + onSaved?.() + onClose() + } else { + toast.error('保存失败: ' + (data as { error?: string })?.error) + } + } catch (e) { + console.error('Save VIP error:', e) + toast.error('保存失败') + } finally { + setSaving(false) + } + } + + if (!open) return null + + return ( + onClose()}> + + + + + 设置 VIP - {userNickname || userId} + + + {loading ? ( +
    加载中...
    + ) : ( +
    +
    + + setForm((f) => ({ ...f, isVip: checked }))} + /> +
    + {form.isVip && ( + <> +
    + + setForm((f) => ({ ...f, vipExpireDate: e.target.value }))} + /> +
    +
    + + { + const v = e.target.value + setForm((f) => ({ ...f, vipSort: v === '' ? '' : parseInt(v, 10) || 0 })) + }} + /> +
    + + )} +
    + + + {form.vipRole === '__custom__' && ( + setForm((f) => ({ ...f, vipRoleCustom: e.target.value }))} + /> + )} +
    +
    + + setForm((f) => ({ ...f, vipName: e.target.value }))} + /> +
    +
    + + setForm((f) => ({ ...f, vipProject: e.target.value }))} + /> +
    +
    + + setForm((f) => ({ ...f, vipContact: e.target.value }))} + /> +
    +
    + + setForm((f) => ({ ...f, vipBio: e.target.value }))} + /> +
    +
    + )} + + + + +
    +
    + ) +} diff --git a/new-soul/soul-admin/src/components/modules/user/UserDetailModal.tsx b/new-soul/soul-admin/src/components/modules/user/UserDetailModal.tsx new file mode 100644 index 00000000..c536318a --- /dev/null +++ b/new-soul/soul-admin/src/components/modules/user/UserDetailModal.tsx @@ -0,0 +1,1054 @@ +import toast from '@/utils/toast' +import { normalizeImageUrl } from '@/lib/utils' +import { useState, useEffect } from 'react' +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog' +import { Button } from '@/components/ui/button' +import { Badge } from '@/components/ui/badge' +import { Input } from '@/components/ui/input' +import { Label } from '@/components/ui/label' +import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' +import { Switch } from '@/components/ui/switch' +import { + User, + Phone, + MapPin, + RefreshCw, + Link2, + BookOpen, + ShoppingBag, + Users, + MessageCircle, + Clock, + Save, + X, + Tag, + Zap, + Search, + CheckCircle2, + Crown, + Key, + Navigation, + Smartphone, +} from 'lucide-react' +import { get, put, post } from '@/api/client' + +interface UserDetailModalProps { + open: boolean + onClose: () => void + userId: string | null + onUserUpdated?: () => void +} + +interface UserDetail { + id: string + phone?: string + nickname: string + avatar?: string + wechatId?: string + openId?: string + referralCode?: string + referredBy?: string + hasFullBook?: boolean + isAdmin?: boolean + earnings?: number + pendingEarnings?: number + referralCount?: number + createdAt?: string + updatedAt?: string + tags?: string + ckbTags?: string + ckbSyncedAt?: string + isVip?: boolean + vipExpireDate?: string | null + vipName?: string | null + vipAvatar?: string | null + vipProject?: string | null + vipContact?: string | null + vipBio?: string | null + vipRole?: string | null + // 扩展字段 + mbti?: string + region?: string + industry?: string + position?: string +} + +interface UserTrack { + id: string + action: string + actionLabel: string + target?: string + chapterTitle?: string + createdAt: string + timeAgo: string +} + +interface ShensheShouData { + rfm_score?: number + user_level?: string + tags?: string[] + last_active?: string + phone?: string +} + +export function UserDetailModal({ + open, + onClose, + userId, + onUserUpdated, +}: UserDetailModalProps) { + const [user, setUser] = useState(null) + const [tracks, setTracks] = useState([]) + const [referrals, setReferrals] = useState([]) + const [loading, setLoading] = useState(false) + const [syncing, setSyncing] = useState(false) + const [saving, setSaving] = useState(false) + const [activeTab, setActiveTab] = useState('info') + const [editPhone, setEditPhone] = useState('') + const [editNickname, setEditNickname] = useState('') + const [editTags, setEditTags] = useState([]) + const [newTag, setNewTag] = useState('') + + // 修改密码 + const [newPassword, setNewPassword] = useState('') + const [confirmPassword, setConfirmPassword] = useState('') + const [passwordSaving, setPasswordSaving] = useState(false) + + // 设成超级个体(VIP) + const [vipForm, setVipForm] = useState({ isVip: false, vipExpireDate: '', vipRole: '', vipName: '', vipProject: '', vipContact: '', vipBio: '' }) + const [vipRoles, setVipRoles] = useState<{ id: number; name: string }[]>([]) + const [vipSaving, setVipSaving] = useState(false) + + // 用户资料完善(神射手) + const [sssLoading, setSssLoading] = useState(false) + const [sssData, setSssData] = useState(null) + const [sssError, setSssError] = useState(null) + const [sssQueryPhone, setSssQueryPhone] = useState('') + const [sssQueryWechatId, setSssQueryWechatId] = useState('') + const [sssQueryOpenId, setSssQueryOpenId] = useState('') + const [batchIngestLoading, setBatchIngestLoading] = useState(false) + const [batchIngestResult, setBatchIngestResult] = useState | null>(null) + const [ckbWechatOwner, setCkbWechatOwner] = useState('') + + useEffect(() => { + if (open && userId) { + setActiveTab('info') + setSssData(null) + setSssError(null) + setBatchIngestResult(null) + setCkbWechatOwner('') + setNewPassword('') + setConfirmPassword('') + loadUserDetail() + get<{ success?: boolean; data?: { id: number; name: string }[] }>('/api/db/vip-roles').then((r) => { + if (r?.success && (r as { data?: { id: number; name: string }[] }).data) setVipRoles((r as { data: { id: number; name: string }[] }).data) + }).catch(() => {}) + } + }, [open, userId]) + + async function loadUserDetail() { + if (!userId) return + setLoading(true) + try { + const userData = await get<{ success?: boolean; user?: UserDetail }>( + `/api/db/users?id=${encodeURIComponent(userId)}`, + ) + if (userData?.success && userData.user) { + const u = userData.user + setUser(u) + setEditPhone(u.phone || '') + setEditNickname(u.nickname || '') + setSssQueryPhone(u.phone || '') + setSssQueryWechatId(u.wechatId || '') + setSssQueryOpenId(u.openId || '') + try { + setEditTags(typeof u.tags === 'string' ? (JSON.parse(u.tags || '[]') as string[]) : []) + } catch { + setEditTags([]) + } + setVipForm({ + isVip: !!(u.isVip ?? false), + vipExpireDate: u.vipExpireDate ? String(u.vipExpireDate).slice(0, 10) : '', + vipRole: String(u.vipRole ?? ''), + vipName: String(u.vipName ?? ''), + vipProject: String(u.vipProject ?? ''), + vipContact: String(u.vipContact ?? ''), + vipBio: String(u.vipBio ?? ''), + }) + } + // 行为轨迹(用户旅程) + try { + const trackData = await get<{ success?: boolean; tracks?: UserTrack[] }>( + `/api/user/track?userId=${encodeURIComponent(userId)}&limit=50`, + ) + if (trackData?.success && trackData.tracks) setTracks(trackData.tracks) + } catch { setTracks([]) } + // 关系链路 + try { + const refData = await get<{ success?: boolean; referrals?: unknown[] }>( + `/api/db/users/referrals?userId=${encodeURIComponent(userId)}`, + ) + if (refData?.success && refData.referrals) setReferrals(refData.referrals) + } catch { setReferrals([]) } + } catch (e) { + console.error('Load user detail error:', e) + } finally { + setLoading(false) + } + } + + async function handleSyncCKB() { + if (!user?.phone) { toast.info('用户未绑定手机号,无法同步'); return } + setSyncing(true) + try { + const data = await post<{ success?: boolean; error?: string }>('/api/ckb/sync', { + action: 'full_sync', + phone: user.phone, + userId: user.id, + }) + if (data?.success) { toast.success('同步成功'); loadUserDetail() } + else toast.error('同步失败: ' + (data as { error?: string })?.error) + } catch (e) { + console.error('Sync CKB error:', e) + toast.error('同步失败') + } finally { + setSyncing(false) + } + } + + async function handleSave() { + if (!user) return + setSaving(true) + try { + const payload: Record = { + id: user.id, + phone: editPhone || undefined, + nickname: editNickname || undefined, + tags: JSON.stringify(editTags), + } + const data = await put<{ success?: boolean; error?: string }>('/api/db/users', payload) + if (data?.success) { + toast.success('保存成功') + loadUserDetail() + onUserUpdated?.() + } else { + toast.error('保存失败: ' + (data as { error?: string })?.error) + } + } catch (e) { + console.error('Save user error:', e) + toast.error('保存失败') + } finally { + setSaving(false) + } + } + + const addTag = () => { + if (newTag && !editTags.includes(newTag)) { + setEditTags([...editTags, newTag]) + setNewTag('') + } + } + + const removeTag = (tag: string) => setEditTags(editTags.filter((t) => t !== tag)) + + async function handleSavePassword() { + if (!user) return + if (!newPassword) { toast.error('请输入新密码'); return } + if (newPassword !== confirmPassword) { toast.error('两次密码不一致'); return } + if (newPassword.length < 6) { toast.error('密码至少 6 位'); return } + setPasswordSaving(true) + try { + const data = await put<{ success?: boolean; error?: string }>('/api/db/users', { id: user.id, password: newPassword }) + if (data?.success) { toast.success('修改成功'); setNewPassword(''); setConfirmPassword('') } + else toast.error('修改失败: ' + (data?.error || '')) + } catch { toast.error('修改失败') } finally { setPasswordSaving(false) } + } + + async function handleSaveVip() { + if (!user) return + if (vipForm.isVip && !vipForm.vipExpireDate.trim()) { toast.error('开启 VIP 请填写有效到期日'); return } + setVipSaving(true) + try { + const payload = { + id: user.id, + isVip: vipForm.isVip, + vipExpireDate: vipForm.isVip ? vipForm.vipExpireDate : undefined, + vipRole: vipForm.vipRole || undefined, + vipName: vipForm.vipName || undefined, + vipProject: vipForm.vipProject || undefined, + vipContact: vipForm.vipContact || undefined, + vipBio: vipForm.vipBio || undefined, + } + const data = await put<{ success?: boolean; error?: string }>('/api/db/users', payload) + if (data?.success) { toast.success('VIP 设置已保存'); loadUserDetail(); onUserUpdated?.() } + else toast.error('保存失败: ' + (data?.error || '')) + } catch { toast.error('保存失败') } finally { setVipSaving(false) } + } + + // 用户资料完善查询(支持多维度) + async function handleSSSQuery() { + if (!sssQueryPhone && !sssQueryOpenId && !sssQueryWechatId) { + setSssError('请至少输入手机号、微信号或 OpenID 中的一项') + return + } + setSssLoading(true) + setSssError(null) + setSssData(null) + try { + const params = new URLSearchParams() + if (sssQueryPhone) params.set('phone', sssQueryPhone) + if (sssQueryOpenId) params.set('openId', sssQueryOpenId) + if (sssQueryWechatId) params.set('wechatId', sssQueryWechatId) + const data = await get<{ success?: boolean; data?: ShensheShouData; error?: string }>( + `/api/admin/shensheshou/query?${params}`, + ) + if (data?.success && data.data) { + setSssData(data.data) + // 自动回填到用户信息 + if (user) await handleSSSEnrich(data.data) + } + else setSssError(data?.error || '未查询到数据,该用户可能未在神射手收录') + } catch (e) { + console.error('SSS query error:', e) + setSssError('请求失败,请检查神射手接口配置') + } finally { + setSssLoading(false) + } + } + + // 查询后自动回填用户基础信息 + async function handleSSSEnrich(_sssResult?: ShensheShouData) { + if (!user) return + try { + await post('/api/admin/shensheshou/enrich', { + userId: user.id, + phone: sssQueryPhone || user.phone || '', + openId: sssQueryOpenId || user.openId || '', + wechatId: sssQueryWechatId || user.wechatId || '', + }) + loadUserDetail() + } catch (e) { + console.error('SSS enrich error:', e) + } + } + + // 神射手 - 将当前用户信息推送/同步到神射手 + async function handleSSSIngest() { + if (!user) return + setBatchIngestLoading(true) + setBatchIngestResult(null) + try { + const payload = { + users: [{ + phone: user.phone || '', + name: user.nickname || '', + openId: user.openId || '', + tags: editTags, + }] + } + const data = await post<{ success?: boolean; data?: Record; error?: string }>( + '/api/admin/shensheshou/ingest', + payload, + ) + if (data?.success && data.data) setBatchIngestResult(data.data) + else setBatchIngestResult({ error: data?.error || '推送失败' }) + } catch (e) { + console.error('SSS ingest error:', e) + setBatchIngestResult({ error: '请求失败' }) + } finally { + setBatchIngestLoading(false) + } + } + + const getActionIcon = (action: string) => { + const icons: Record> = { + view_chapter: BookOpen, + purchase: ShoppingBag, + match: Users, + login: User, + register: User, + share: Link2, + bind_phone: Phone, + bind_wechat: MessageCircle, + fill_profile: Tag, + visit_page: Navigation, + } + const Icon = icons[action] || Clock + return + } + + if (!open) return null + + return ( + onClose()}> + + + + + 用户详情 + {user?.phone && 已绑定手机} + {user?.isVip && VIP} + + + + {loading ? ( +
    + + 加载中... +
    + ) : user ? ( +
    + {/* 用户头部信息 */} +
    +
    + {user.avatar ? ( + + ) : ( + user.nickname?.charAt(0) || '?' + )} +
    +
    +
    +

    {user.nickname}

    + {user.isAdmin && 管理员} + {user.hasFullBook && 全书已购} + {user.vipRole && {user.vipRole}} +
    +

    + {user.phone ? `📱 ${user.phone}` : '未绑定手机'} + {user.wechatId && ` · 💬 ${user.wechatId}`} + {user.mbti && ` · ${user.mbti}`} +

    +
    +

    ID: {user.id.slice(0, 16)}…

    + {user.referralCode && ( +

    + 推广码: + {user.referralCode} +

    + )} +
    +
    +
    +

    ¥{(user.earnings || 0).toFixed(2)}

    +

    累计收益

    +
    +
    + + + + + 基础信息 + + + 标签体系 + + + + 用户旅程 + + + 关系链路 + + + + 用户资料完善 + + + + {/* ===== 基础信息 ===== */} + +
    +
    + + setEditPhone(e.target.value)} + /> +
    +
    + + setEditNickname(e.target.value)} + /> +
    +
    + {/* 详细信息展示 */} +
    + {user.openId && ( +
    +

    微信 OpenID

    +

    {user.openId}

    +
    + )} + {user.region && ( +
    + +
    +

    地区

    +

    {user.region}

    +
    +
    + )} + {user.industry && ( +
    +

    行业

    +

    {user.industry}

    +
    + )} + {user.position && ( +
    +

    职位

    +

    {user.position}

    +
    + )} +
    +
    +
    +

    推荐人数

    +

    {user.referralCount ?? 0}

    +
    +
    +

    待提现

    +

    + ¥{(user.pendingEarnings ?? 0).toFixed(2)} +

    +
    +
    +

    创建时间

    +

    + {user.createdAt ? new Date(user.createdAt).toLocaleDateString() : '-'} +

    +
    +
    + + {/* 快捷操作:修改密码 & 设成超级个体 */} +
    +
    +
    + + 修改密码 +
    +
    + setNewPassword(e.target.value)} + /> + setConfirmPassword(e.target.value)} + /> + +
    +
    +
    +
    + + 设成超级个体 +
    +
    +
    + + setVipForm((f) => ({ ...f, isVip: c }))} + /> +
    + {vipForm.isVip && ( +
    + + setVipForm((f) => ({ ...f, vipExpireDate: e.target.value }))} + /> +
    + )} +
    + + +
    +
    + + setVipForm((f) => ({ ...f, vipName: e.target.value }))} + /> +
    + +
    +
    +
    + + {/* VIP 信息(只读展示) */} + {user.isVip && ( +
    +
    + + VIP 信息 + {user.vipRole || 'VIP'} +
    +
    + {user.vipName &&
    展示名:{user.vipName}
    } + {user.vipProject &&
    项目:{user.vipProject}
    } + {user.vipContact &&
    联系方式:{user.vipContact}
    } + {user.vipExpireDate &&
    到期时间:{new Date(user.vipExpireDate).toLocaleDateString()}
    } +
    + {user.vipBio &&

    {user.vipBio}

    } +
    + )} + {/* 微信归属(存客宝) */} +
    +
    + + 微信归属 + 该用户归属在哪个微信号下 +
    +
    + setCkbWechatOwner(e.target.value)} + /> + +
    + {user.wechatId && ( +

    当前归属:{user.wechatId}

    + )} +
    + + {/* 存客宝同步 */} +
    +
    +
    + + 存客宝同步 +
    + +
    +
    +
    + 同步状态: + {user.ckbSyncedAt ? ( + 已同步 + ) : ( + 未同步 + )} +
    +
    + 最后同步: + + {user.ckbSyncedAt ? new Date(user.ckbSyncedAt).toLocaleString() : '-'} + +
    +
    +
    +
    + + {/* ===== 标签体系 ===== */} + +
    +
    + + 用户标签 + 基于《一场 Soul 的创业实验》维度打标 +
    + {/* 自动打标说明 */} +
    + + 命中的标签自动高亮 · 系统根据行为轨迹和填写资料自动打标 · 手动点击补充或取消 +
    + {/* 预设标签分类 */} +
    + {[ + { + category: '身份类型', + tags: ['创业者', '打工人', '自由职业', '学生', '投资人', '合伙人'], + }, + { + category: '行业背景', + tags: ['电商', '内容', '传统行业', '科技/AI', '金融', '教育', '餐饮'], + }, + { + category: '痛点标签', + tags: ['找资源', '找方向', '找合伙人', '想赚钱', '想学习', '找情感出口'], + }, + { + category: '付费意愿', + tags: ['高意向', '已付费', '观望中', '薅羊毛'], + }, + { + category: 'MBTI', + tags: ['ENTJ', 'INTJ', 'ENFP', 'INFP', 'ENTP', 'INTP', 'ESTJ', 'ISFJ'], + }, + ].map((group) => ( +
    +

    {group.category}

    +
    + {group.tags.map((tag) => ( + + ))} +
    +
    + ))} +
    +
    +

    已选标签

    +
    + {editTags.map((tag, i) => ( + + {tag} + + + ))} + {editTags.length === 0 && 暂未选择标签} +
    +
    + setNewTag(e.target.value)} + onKeyDown={(e) => e.key === 'Enter' && addTag()} + /> + +
    +
    +
    + {/* 存客宝标签 */} + {user.ckbTags && ( +
    +
    + + 存客宝标签 +
    +
    + {(typeof user.ckbTags === 'string' ? user.ckbTags.split(',') : []).map((tag, i) => ( + {tag.trim()} + ))} +
    +
    + )} +
    + + {/* ===== 用户旅程(原行为轨迹)===== */} + +
    + + 记录用户从注册到付费的完整行动路径,共 {tracks.length} 条记录 +
    +
    + {tracks.length > 0 ? ( + tracks.map((track, idx) => ( +
    +
    +
    + {getActionIcon(track.action)} +
    + {idx < tracks.length - 1 && ( +
    + )} +
    +
    +
    + {track.actionLabel} + {track.chapterTitle && ( + - {track.chapterTitle} + )} +
    +

    + + {track.timeAgo} · {new Date(track.createdAt).toLocaleString()} +

    +
    +
    + )) + ) : ( +
    + +

    暂无用户旅程记录

    +

    当用户浏览章节、购买或完善信息时会自动记录

    +
    + )} +
    + + + {/* ===== 关系链路 ===== */} + +
    +
    +
    + + 推荐的用户 +
    + 共 {referrals.length} 人 +
    +
    + {referrals.length > 0 ? ( + referrals.map((ref: unknown, i: number) => { + const r = ref as { id?: string; nickname?: string; status?: string; createdAt?: string } + return ( +
    +
    +
    + {r.nickname?.charAt(0) || '?'} +
    + {r.nickname} +
    +
    + {r.status === 'vip' && ( + 已购 + )} + + {r.createdAt ? new Date(r.createdAt).toLocaleDateString() : ''} + +
    +
    + ) + }) + ) : ( +

    暂无推荐用户

    + )} +
    +
    +
    + + {/* ===== 用户资料完善 ===== */} + +
    +
    + + 用户资料完善 + 通过多维度查询神射手数据,自动回填用户基础信息 +
    + {/* 多维度查询输入 */} +
    +
    + + setSssQueryPhone(e.target.value)} + /> +
    +
    + + setSssQueryWechatId(e.target.value)} + /> +
    +
    + + setSssQueryOpenId(e.target.value)} + /> +
    +
    + +

    查询成功后,神射手返回的标签将自动同步到该用户

    + {sssError && ( +
    + {sssError} +
    + )} + {sssData && ( +
    +
    +
    +

    神射手 RFM 分

    +

    {sssData.rfm_score ?? '-'}

    +
    +
    +

    用户等级

    +

    {sssData.user_level ?? '-'}

    +
    +
    + {sssData.tags && sssData.tags.length > 0 && ( +
    +

    神射手标签

    +
    + {sssData.tags.map((tag, i) => ( + + {tag} + + ))} +
    +
    + )} + {sssData.last_active && ( +
    + 最近活跃:{sssData.last_active} +
    + )} +
    + )} +
    + + {/* 推送到神射手 */} +
    +
    +
    +
    + + 推送用户数据到神射手 +
    +

    将本用户信息(手机号、昵称、标签等)同步至神射手,自动完善用户画像

    +
    + +
    + {!user.phone && ( +

    ⚠ 用户未绑定手机号,无法推送

    + )} + {batchIngestResult && ( +
    + {batchIngestResult.error ? ( +

    {String(batchIngestResult.error)}

    + ) : ( +
    +

    + 推送成功 +

    + {batchIngestResult.enriched !== undefined && ( +

    自动补全标签数:{String(batchIngestResult.new_tags_added ?? 0)}

    + )} +
    + )} +
    + )} +
    +
    + + +
    + + +
    +
    + ) : ( +
    用户不存在
    + )} + +
    + ) +} diff --git a/new-soul/soul-admin/src/components/ui/Pagination.tsx b/new-soul/soul-admin/src/components/ui/Pagination.tsx new file mode 100644 index 00000000..4204ed6a --- /dev/null +++ b/new-soul/soul-admin/src/components/ui/Pagination.tsx @@ -0,0 +1,81 @@ +interface PaginationProps { + page: number + totalPages: number + total: number + pageSize: number + onPageChange: (page: number) => void + onPageSizeChange?: (pageSize: number) => void + pageSizeOptions?: number[] +} + +export function Pagination({ + page, + totalPages, + total, + pageSize, + onPageChange, + onPageSizeChange, + pageSizeOptions = [10, 20, 50, 100], +}: PaginationProps) { + if (totalPages <= 1 && !onPageSizeChange) return null + + return ( +
    +
    + 共 {total} 条 + {onPageSizeChange && ( + + )} +
    + {totalPages > 1 && ( +
    + + + + {page} / {totalPages} + + + +
    + )} +
    + ) +} diff --git a/new-soul/soul-admin/src/components/ui/badge.tsx b/new-soul/soul-admin/src/components/ui/badge.tsx new file mode 100644 index 00000000..e80a5d97 --- /dev/null +++ b/new-soul/soul-admin/src/components/ui/badge.tsx @@ -0,0 +1,31 @@ +import * as React from 'react' +import { Slot } from '@radix-ui/react-slot' +import { cva, type VariantProps } from 'class-variance-authority' +import { cn } from '@/lib/utils' + +const badgeVariants = cva( + 'inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 transition-colors', + { + variants: { + variant: { + default: 'border-transparent bg-primary text-primary-foreground', + secondary: 'border-transparent bg-secondary text-secondary-foreground', + destructive: 'border-transparent bg-destructive text-white', + outline: 'text-foreground', + }, + }, + defaultVariants: { variant: 'default' }, + }, +) + +function Badge({ + className, + variant, + asChild = false, + ...props +}: React.ComponentProps<'span'> & VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot : 'span' + return +} + +export { Badge, badgeVariants } diff --git a/new-soul/soul-admin/src/components/ui/button.tsx b/new-soul/soul-admin/src/components/ui/button.tsx new file mode 100644 index 00000000..b30df2e4 --- /dev/null +++ b/new-soul/soul-admin/src/components/ui/button.tsx @@ -0,0 +1,52 @@ +import * as React from 'react' +import { Slot } from '@radix-ui/react-slot' +import { cva, type VariantProps } from 'class-variance-authority' +import { cn } from '@/lib/utils' + +const buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]", + { + variants: { + variant: { + default: 'bg-primary text-primary-foreground hover:bg-primary/90', + destructive: 'bg-destructive text-white hover:bg-destructive/90', + outline: 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground', + secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80', + ghost: 'hover:bg-accent hover:text-accent-foreground', + link: 'text-primary underline-offset-4 hover:underline', + }, + size: { + default: 'h-9 px-4 py-2 has-[>svg]:px-3', + sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5', + lg: 'h-10 rounded-md px-6 has-[>svg]:px-4', + icon: 'size-9', + 'icon-sm': 'size-8', + 'icon-lg': 'size-10', + }, + }, + defaultVariants: { + variant: 'default', + size: 'default', + }, + }, +) + +function Button({ + className, + variant, + size, + asChild = false, + ...props +}: React.ComponentProps<'button'> & + VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot : 'button' + return ( + + ) +} + +export { Button, buttonVariants } diff --git a/new-soul/soul-admin/src/components/ui/card.tsx b/new-soul/soul-admin/src/components/ui/card.tsx new file mode 100644 index 00000000..bd9d1399 --- /dev/null +++ b/new-soul/soul-admin/src/components/ui/card.tsx @@ -0,0 +1,42 @@ +import * as React from 'react' +import { cn } from '@/lib/utils' + +const Card = React.forwardRef>( + ({ className, ...props }, ref) => ( +
    + ), +) +Card.displayName = 'Card' + +const CardHeader = React.forwardRef>( + ({ className, ...props }, ref) => ( +
    + ), +) +CardHeader.displayName = 'CardHeader' + +const CardTitle = React.forwardRef>( + ({ className, ...props }, ref) => ( +

    + ), +) +CardTitle.displayName = 'CardTitle' + +const CardDescription = React.forwardRef>( + ({ className, ...props }, ref) => ( +

    + ), +) +CardDescription.displayName = 'CardDescription' + +const CardContent = React.forwardRef>( + ({ className, ...props }, ref) =>

    , +) +CardContent.displayName = 'CardContent' + +const CardFooter = React.forwardRef>( + ({ className, ...props }, ref) =>
    , +) +CardFooter.displayName = 'CardFooter' + +export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } diff --git a/new-soul/soul-admin/src/components/ui/dialog.tsx b/new-soul/soul-admin/src/components/ui/dialog.tsx new file mode 100644 index 00000000..eecb3874 --- /dev/null +++ b/new-soul/soul-admin/src/components/ui/dialog.tsx @@ -0,0 +1,85 @@ +import * as React from 'react' +import * as DialogPrimitive from '@radix-ui/react-dialog' +import { X } from 'lucide-react' +import { cn } from '@/lib/utils' + +function Dialog(props: React.ComponentProps) { + return +} + +function DialogPortal(props: React.ComponentProps) { + return +} + +const DialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogOverlay.displayName = 'DialogOverlay' + +const DialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { showCloseButton?: boolean } +>(({ className, children, showCloseButton = true, ...props }, ref) => ( + + + + {children} + {showCloseButton && ( + + + Close + + )} + + +)) +DialogContent.displayName = 'DialogContent' + +function DialogHeader({ className, ...props }: React.ComponentProps<'div'>) { + return
    +} + +function DialogFooter({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
    + ) +} + +function DialogTitle(props: React.ComponentProps) { + return +} + +function DialogDescription(props: React.ComponentProps) { + return +} + +export { + Dialog, + DialogPortal, + DialogOverlay, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +} +export const DialogClose = DialogPrimitive.Close +export const DialogTrigger = DialogPrimitive.Trigger diff --git a/new-soul/soul-admin/src/components/ui/input.tsx b/new-soul/soul-admin/src/components/ui/input.tsx new file mode 100644 index 00000000..37a6dde8 --- /dev/null +++ b/new-soul/soul-admin/src/components/ui/input.tsx @@ -0,0 +1,18 @@ +import * as React from 'react' +import { cn } from '@/lib/utils' + +function Input({ className, type, ...props }: React.ComponentProps<'input'>) { + return ( + + ) +} + +export { Input } diff --git a/new-soul/soul-admin/src/components/ui/label.tsx b/new-soul/soul-admin/src/components/ui/label.tsx new file mode 100644 index 00000000..67bcc8a4 --- /dev/null +++ b/new-soul/soul-admin/src/components/ui/label.tsx @@ -0,0 +1,20 @@ +import * as React from 'react' +import * as LabelPrimitive from '@radix-ui/react-label' +import { cn } from '@/lib/utils' + +const Label = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +Label.displayName = LabelPrimitive.Root.displayName + +export { Label } diff --git a/new-soul/soul-admin/src/components/ui/select.tsx b/new-soul/soul-admin/src/components/ui/select.tsx new file mode 100644 index 00000000..329ad74e --- /dev/null +++ b/new-soul/soul-admin/src/components/ui/select.tsx @@ -0,0 +1,79 @@ +import * as React from 'react' +import * as SelectPrimitive from '@radix-ui/react-select' +import { Check, ChevronDown, ChevronUp } from 'lucide-react' +import { cn } from '@/lib/utils' + +const Select = SelectPrimitive.Root +const SelectGroup = SelectPrimitive.Group +const SelectValue = SelectPrimitive.Value + +const SelectTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + span]:line-clamp-1', + className, + )} + {...props} + > + {children} + + + + +)) +SelectTrigger.displayName = SelectPrimitive.Trigger.displayName + +const SelectContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, position = 'popper', ...props }, ref) => ( + + + + + + {children} + + + + + +)) +SelectContent.displayName = SelectPrimitive.Content.displayName + +const SelectItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + {children} + +)) +SelectItem.displayName = SelectPrimitive.Item.displayName + +export { Select, SelectGroup, SelectValue, SelectTrigger, SelectContent, SelectItem } diff --git a/new-soul/soul-admin/src/components/ui/slider.tsx b/new-soul/soul-admin/src/components/ui/slider.tsx new file mode 100644 index 00000000..ad36e691 --- /dev/null +++ b/new-soul/soul-admin/src/components/ui/slider.tsx @@ -0,0 +1,48 @@ +import * as React from 'react' +import * as SliderPrimitive from '@radix-ui/react-slider' +import { cn } from '@/lib/utils' + +function Slider({ + className, + defaultValue, + value, + min = 0, + max = 100, + ...props +}: React.ComponentProps) { + const _values = React.useMemo( + () => + Array.isArray(value) + ? value + : Array.isArray(defaultValue) + ? defaultValue + : [min, max], + [value, defaultValue, min, max], + ) + + return ( + + + + + {Array.from({ length: _values.length }, (_, index) => ( + + ))} + + ) +} + +export { Slider } diff --git a/new-soul/soul-admin/src/components/ui/switch.tsx b/new-soul/soul-admin/src/components/ui/switch.tsx new file mode 100644 index 00000000..ec236353 --- /dev/null +++ b/new-soul/soul-admin/src/components/ui/switch.tsx @@ -0,0 +1,26 @@ +import * as React from 'react' +import * as SwitchPrimitives from '@radix-ui/react-switch' +import { cn } from '@/lib/utils' + +const Switch = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +Switch.displayName = SwitchPrimitives.Root.displayName + +export { Switch } diff --git a/new-soul/soul-admin/src/components/ui/table.tsx b/new-soul/soul-admin/src/components/ui/table.tsx new file mode 100644 index 00000000..adf8c34b --- /dev/null +++ b/new-soul/soul-admin/src/components/ui/table.tsx @@ -0,0 +1,63 @@ +import * as React from 'react' +import { cn } from '@/lib/utils' + +const Table = React.forwardRef>( + ({ className, ...props }, ref) => ( +
    + + + ), +) +Table.displayName = 'Table' + +const TableHeader = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableHeader.displayName = 'TableHeader' + +const TableBody = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableBody.displayName = 'TableBody' + +const TableRow = React.forwardRef>( + ({ className, ...props }, ref) => ( + + ), +) +TableRow.displayName = 'TableRow' + +const TableHead = React.forwardRef< + HTMLTableCellElement, + React.ThHTMLAttributes +>(({ className, ...props }, ref) => ( +
    +)) +TableHead.displayName = 'TableHead' + +const TableCell = React.forwardRef< + HTMLTableCellElement, + React.TdHTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableCell.displayName = 'TableCell' + +export { Table, TableHeader, TableBody, TableRow, TableHead, TableCell } diff --git a/new-soul/soul-admin/src/components/ui/tabs.tsx b/new-soul/soul-admin/src/components/ui/tabs.tsx new file mode 100644 index 00000000..eeed9d7e --- /dev/null +++ b/new-soul/soul-admin/src/components/ui/tabs.tsx @@ -0,0 +1,49 @@ +import * as React from 'react' +import * as TabsPrimitive from '@radix-ui/react-tabs' +import { cn } from '@/lib/utils' + +const Tabs = TabsPrimitive.Root + +const TabsList = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +TabsList.displayName = TabsPrimitive.List.displayName + +const TabsTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +TabsTrigger.displayName = TabsPrimitive.Trigger.displayName + +const TabsContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +TabsContent.displayName = TabsPrimitive.Content.displayName + +export { Tabs, TabsList, TabsTrigger, TabsContent } diff --git a/new-soul/soul-admin/src/components/ui/textarea.tsx b/new-soul/soul-admin/src/components/ui/textarea.tsx new file mode 100644 index 00000000..91036a32 --- /dev/null +++ b/new-soul/soul-admin/src/components/ui/textarea.tsx @@ -0,0 +1,19 @@ +import * as React from 'react' +import { cn } from '@/lib/utils' + +const Textarea = React.forwardRef< + HTMLTextAreaElement, + React.TextareaHTMLAttributes +>(({ className, ...props }, ref) => ( +