diff --git a/.superpowers/brainstorm/hero-variants.html b/.superpowers/brainstorm/hero-variants.html new file mode 100644 index 0000000..2e70821 --- /dev/null +++ b/.superpowers/brainstorm/hero-variants.html @@ -0,0 +1,1095 @@ + + + + + + Novalon Hero Variants + + + + + +
原版: 当前生产
+ + +
+
+
+
+
智连未来,成长伙伴
+

睿新致远

+

+ 企业数字化转型服务商 +

+

+ 以智慧连接数字趋势,以伙伴身份陪您成长——您的数字化转型同行者 +

+
+ + +
+
+
+
+
+ + + + + + + + + + + +
+

值得信赖

+

用心打磨产品,以专业赢得信赖

+
+ + +
+
+
Tweaks
+
+ Hero 变体 +
+ + + + +
+
+
+ 品牌名字号 +
+ + + +
+
+
+ +
+ + + + diff --git a/CONTEXT.md b/CONTEXT.md new file mode 100644 index 0000000..7b6c66e --- /dev/null +++ b/CONTEXT.md @@ -0,0 +1,38 @@ +# Novalon Website - 领域术语表 + +## 核心实体 + +### 墨韵流光 +Novalon 网站的核心视觉系统,包含两个子机制: +- **旋转渐变边框 (ink-glow-border)**:卡片边框使用旋转的 conic-gradient,产生墨韵流动感 +- **鼠标跟随光晕 (mouse-follow)**:卡片内跟随鼠标的 radial-gradient 光晕,产生交互反馈 + +当前状态:.impeccable.md 已定义规范,但首页组件**未实现**。 + +### 水墨雅致 +Novalon 的整体设计风格定位。核心原则:以留白和排版取胜,特效点到为止。参考 Apple 中国官网。 + +### 朱砂点睛 +品牌红 #C41E3A 的使用原则——仅作点缀,不作为主色调。标题中关键词用 font-calligraphy 突出。 + +### 特效组件 (Effects) +`src/components/effects/` 目录下的 24 个视觉特效组件。当前状态:**大部分未被首页使用**,属于技术债务。 + +### Design Tokens +`.impeccable.md` 中定义的设计令牌系统,包含颜色、排版、间距、卡片系统、Section 背景交替规则。当前状态:**文档已定义,代码中 globals.css 有对应 CSS 变量,但组件层未完全落地**。 + +## 关键决策 + +| 术语 | 含义 | 决策状态 | +|------|------|---------| +| 重构范围 | 保持 5 个 section 不变,聚焦质量提升 | ✅ 已确认 | +| 特效取舍 | 逐个评估 24 个特效组件,决定保留/改造/删除 | ✅ 已确认 | +| Hero 视觉方向 | 先用原型对比再决定(排版驱动 vs 墨韵背景 vs 中间路线) | ✅ 已确认 | +| web-design-engineer 定位 | 仅用于 Hero 原型验证,不用于全站重构 | ✅ 已确认 | +| 运营状态 | 未正式上线,重构风险可控 | ✅ 已确认 | + +## 歧义已解决 + +- **"重构"≠ 推倒重来**:在现有 Next.js 架构内做系统性清理和提升,不更换技术栈 +- **"web-design-engineer"≠ 代码生成器**:它是设计验证工具,产出原型 HTML,不是最终代码 +- **"克制动效"≠ 零动效**:动效服务于信息传达(hover 反馈、scroll reveal、卡片交互),但不做装饰性粒子/水墨动画 diff --git a/docs/adr/0001-refactoring-path-hybrid-approach.md b/docs/adr/0001-refactoring-path-hybrid-approach.md new file mode 100644 index 0000000..d863985 --- /dev/null +++ b/docs/adr/0001-refactoring-path-hybrid-approach.md @@ -0,0 +1,33 @@ +# ADR 0001: 重构路径选择——混合方案而非全站 web-design-engineer 替换 + +## 状态 + +已接受 + +## 上下文 + +Novalon 网站面临技术债务问题:24 个特效组件和 50+ UI 组件大部分未被首页使用,.impeccable.md 定义的设计系统未完全落地,globals.css 有 1200+ 行但大量未引用。需要决定重构路径。 + +## 决策 + +采用**混合方案**:web-design-engineer 仅用于 Hero 区原型验证,主体重构在现有 Next.js 架构内进行。 + +## 理由 + +### 为什么不用 web-design-engineer 全站替换? + +1. **架构不兼容**:web-design-engineer 产出独立 HTML 文件,无法集成到 Next.js App Router + 静态导出架构中 +2. **丢失现有资产**:50+ UI 组件(含测试)、SEO 优化、分析追踪、可访问性适配等将全部丢失 +3. **维护性倒退**:单文件 HTML 无法支撑后续迭代(产品页、解决方案页等动态路由) + +### 为什么用混合方案? + +1. **Hero 视觉方向未定**:当前 Hero 是纯白底+文字,与设计文档差距最大,需要原型对比来决策 +2. **web-design-engineer 擅长快速视觉探索**:2-3 个 Hero 变体可在单次会话中完成 +3. **主体工作在 Next.js 内更高效**:清理死代码、激活设计系统、整合特效——这些都需要在代码库内操作 + +## 后果 + +- 正面:保留现有架构和资产,风险可控;Hero 原型可快速验证视觉方向 +- 负面:Hero 原型需要"翻译"为 Next.js 组件,存在少量双工 +- 风险:如果 Hero 原型方向与现有设计系统冲突,可能需要调整 .impeccable.md diff --git a/package-lock.json b/package-lock.json index d283ffe..479bd06 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,14 +8,10 @@ "name": "ruixin-website-react", "version": "1.0.0-phase1", "dependencies": { - "@antv/g2": "^5.4.8", "@playwright/test": "^1.58.2", - "@radix-ui/react-dialog": "^1.1.15", - "@radix-ui/react-dropdown-menu": "^2.1.16", - "@types/three": "^0.183.1", + "@radix-ui/react-slot": "^1.2.4", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "critters": "^0.0.23", "date-fns": "^4.1.0", "framer-motion": "^12.34.3", "lucide-react": "^0.563.0", @@ -23,7 +19,6 @@ "react": "19.2.3", "react-dom": "19.2.3", "tailwind-merge": "^3.4.0", - "three": "^0.183.1", "zod": "^4.3.6" }, "devDependencies": { @@ -84,241 +79,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@antv/component": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/@antv/component/-/component-2.1.11.tgz", - "integrity": "sha512-dTdz8VAd3rpjOaGEZTluz82mtzrP4XCtNlNQyrxY7VNRNcjtvpTLDn57bUL2lRu1T+iklKvgbE2llMriWkq9vQ==", - "license": "MIT", - "dependencies": { - "@antv/g": "^6.1.11", - "@antv/scale": "^0.4.16", - "@antv/util": "^3.3.10", - "svg-path-parser": "^1.1.0" - } - }, - "node_modules/@antv/component/node_modules/@antv/scale": { - "version": "0.4.16", - "resolved": "https://registry.npmjs.org/@antv/scale/-/scale-0.4.16.tgz", - "integrity": "sha512-5wg/zB5kXHxpTV5OYwJD3ja6R8yTiqIOkjOhmpEJiowkzRlbEC/BOyMvNUq5fqFIHnMCE9woO7+c3zxEQCKPjw==", - "license": "MIT", - "dependencies": { - "@antv/util": "^3.3.7", - "color-string": "^1.5.5", - "fecha": "^4.2.1" - } - }, - "node_modules/@antv/coord": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/@antv/coord/-/coord-0.4.7.tgz", - "integrity": "sha512-UTbrMLhwJUkKzqJx5KFnSRpU3BqrdLORJbwUbHK2zHSCT3q3bjcFA//ZYLVfIlwqFDXp/hzfMyRtp0c77A9ZVA==", - "license": "MIT", - "dependencies": { - "@antv/scale": "^0.4.12", - "@antv/util": "^2.0.13", - "gl-matrix": "^3.4.3" - } - }, - "node_modules/@antv/coord/node_modules/@antv/scale": { - "version": "0.4.16", - "resolved": "https://registry.npmjs.org/@antv/scale/-/scale-0.4.16.tgz", - "integrity": "sha512-5wg/zB5kXHxpTV5OYwJD3ja6R8yTiqIOkjOhmpEJiowkzRlbEC/BOyMvNUq5fqFIHnMCE9woO7+c3zxEQCKPjw==", - "license": "MIT", - "dependencies": { - "@antv/util": "^3.3.7", - "color-string": "^1.5.5", - "fecha": "^4.2.1" - } - }, - "node_modules/@antv/coord/node_modules/@antv/scale/node_modules/@antv/util": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/@antv/util/-/util-3.3.11.tgz", - "integrity": "sha512-FII08DFM4ABh2q5rPYdr0hMtKXRgeZazvXaFYCs7J7uTcWDHUhczab2qOCJLNDugoj8jFag1djb7wS9ehaRYBg==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "gl-matrix": "^3.3.0", - "tslib": "^2.3.1" - } - }, - "node_modules/@antv/coord/node_modules/@antv/util": { - "version": "2.0.17", - "resolved": "https://registry.npmjs.org/@antv/util/-/util-2.0.17.tgz", - "integrity": "sha512-o6I9hi5CIUvLGDhth0RxNSFDRwXeywmt6ExR4+RmVAzIi48ps6HUy+svxOCayvrPBN37uE6TAc2KDofRo0nK9Q==", - "license": "ISC", - "dependencies": { - "csstype": "^3.0.8", - "tslib": "^2.0.3" - } - }, - "node_modules/@antv/event-emitter": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@antv/event-emitter/-/event-emitter-0.1.3.tgz", - "integrity": "sha512-4ddpsiHN9Pd4UIlWuKVK1C4IiZIdbwQvy9i7DUSI3xNJ89FPUFt8lxDYj8GzzfdllV0NkJTRxnG+FvLk0llidg==", - "license": "MIT" - }, - "node_modules/@antv/expr": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@antv/expr/-/expr-1.0.2.tgz", - "integrity": "sha512-vrfdmPHkTuiS5voVutKl2l06w1ihBh9A8SFdQPEE+2KMVpkymzGOF1eWpfkbGZ7tiFE15GodVdhhHomD/hdIwg==", - "license": "MIT" - }, - "node_modules/@antv/g": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/@antv/g/-/g-6.3.1.tgz", - "integrity": "sha512-WYEKqy86LHB2PzTmrZXrIsIe+3Epeds2f68zceQ+BJtRoGki7Sy4IhlC8LrUMztgfT1t3d/0L745NWZwITroKA==", - "license": "MIT", - "dependencies": { - "@antv/g-lite": "2.7.0", - "@antv/util": "^3.3.5", - "@babel/runtime": "^7.25.6", - "gl-matrix": "^3.4.3", - "html2canvas": "^1.4.1" - } - }, - "node_modules/@antv/g-canvas": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@antv/g-canvas/-/g-canvas-2.2.0.tgz", - "integrity": "sha512-h7zVBBo2aO64DuGKvq9sG+yTU3sCUb9DALCVm7nz8qGPs8hhLuFOkKPEzUDNfNYZGJUGzY8UDtJ3QRGRFcvEQg==", - "license": "MIT", - "dependencies": { - "@antv/g-lite": "2.7.0", - "@antv/g-math": "3.1.0", - "@antv/util": "^3.3.5", - "@babel/runtime": "^7.25.6", - "gl-matrix": "^3.4.3", - "tslib": "^2.5.3" - } - }, - "node_modules/@antv/g-lite": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@antv/g-lite/-/g-lite-2.7.0.tgz", - "integrity": "sha512-uSzgHYa5bwR5L2Au7/5tsOhFmXKZKLPBH90+Q9bP9teVs5VT4kOAi0isPSpDI8uhdDC2/VrfTWu5K9HhWI6FWw==", - "license": "MIT", - "dependencies": { - "@antv/g-math": "3.1.0", - "@antv/util": "^3.3.5", - "@antv/vendor": "^1.0.3", - "@babel/runtime": "^7.25.6", - "eventemitter3": "^5.0.1", - "gl-matrix": "^3.4.3", - "tslib": "^2.5.3" - } - }, - "node_modules/@antv/g-math": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@antv/g-math/-/g-math-3.1.0.tgz", - "integrity": "sha512-DtN1Gj/yI0UiK18nSBsZX8RK0LszGwqfb+cBYWgE+ddyTm8dZnW4tPUhV7QXePsS6/A5hHC+JFpAAK7OEGo5ZQ==", - "license": "MIT", - "dependencies": { - "@antv/util": "^3.3.5", - "@babel/runtime": "^7.25.6", - "gl-matrix": "^3.4.3", - "tslib": "^2.5.3" - } - }, - "node_modules/@antv/g-plugin-dragndrop": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@antv/g-plugin-dragndrop/-/g-plugin-dragndrop-2.1.1.tgz", - "integrity": "sha512-+aesDUJVQDs6UJ2bOBbDlaGAPCfHmU0MbrMTlQlfpwNplWueqtgVAZ3L57oZ2ZGHRWUHiRwZGPjXMBM3O2LELw==", - "license": "MIT", - "dependencies": { - "@antv/g-lite": "2.7.0", - "@antv/util": "^3.3.5", - "@babel/runtime": "^7.25.6", - "tslib": "^2.5.3" - } - }, - "node_modules/@antv/g2": { - "version": "5.4.8", - "resolved": "https://registry.npmjs.org/@antv/g2/-/g2-5.4.8.tgz", - "integrity": "sha512-IvgIpwmT4M5/QAd3Mn2WiHIDeBqFJ4WA2gcZhRRSZuZ2KmgCqZWZwwIT0hc+kIGxwYeDoCQqf//t6FMVu3ryBg==", - "license": "MIT", - "dependencies": { - "@antv/component": "^2.1.9", - "@antv/coord": "^0.4.7", - "@antv/event-emitter": "^0.1.3", - "@antv/expr": "^1.0.2", - "@antv/g": "^6.1.24", - "@antv/g-canvas": "^2.0.43", - "@antv/g-plugin-dragndrop": "^2.0.35", - "@antv/scale": "^0.5.1", - "@antv/util": "^3.3.10", - "@antv/vendor": "^1.0.11", - "flru": "^1.0.2", - "pdfast": "^0.2.0" - } - }, - "node_modules/@antv/scale": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@antv/scale/-/scale-0.5.2.tgz", - "integrity": "sha512-rTHRAwvpHWC5PGZF/mJ2ZuTDqwwvVBDRph0Uu5PV9BXwzV7K8+9lsqGJ+XHVLxe8c6bKog5nlzvV/dcYb0d5Ow==", - "license": "MIT", - "dependencies": { - "@antv/util": "^3.3.7", - "color-string": "^1.5.5", - "fecha": "^4.2.1" - } - }, - "node_modules/@antv/util": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/@antv/util/-/util-3.3.11.tgz", - "integrity": "sha512-FII08DFM4ABh2q5rPYdr0hMtKXRgeZazvXaFYCs7J7uTcWDHUhczab2qOCJLNDugoj8jFag1djb7wS9ehaRYBg==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "gl-matrix": "^3.3.0", - "tslib": "^2.3.1" - } - }, - "node_modules/@antv/vendor": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@antv/vendor/-/vendor-1.0.11.tgz", - "integrity": "sha512-LmhPEQ+aapk3barntaiIxJ5VHno/Tyab2JnfdcPzp5xONh/8VSfed4bo/9xKo5HcUAEydko38vYLfj6lJliLiw==", - "license": "MIT AND ISC", - "dependencies": { - "@types/d3-array": "^3.2.1", - "@types/d3-color": "^3.1.3", - "@types/d3-dispatch": "^3.0.6", - "@types/d3-dsv": "^3.0.7", - "@types/d3-ease": "^3.0.2", - "@types/d3-fetch": "^3.0.7", - "@types/d3-force": "^3.0.10", - "@types/d3-format": "^3.0.4", - "@types/d3-geo": "^3.1.0", - "@types/d3-hierarchy": "^3.1.7", - "@types/d3-interpolate": "^3.0.4", - "@types/d3-path": "^3.1.0", - "@types/d3-quadtree": "^3.0.6", - "@types/d3-random": "^3.0.3", - "@types/d3-scale": "^4.0.9", - "@types/d3-scale-chromatic": "^3.1.0", - "@types/d3-shape": "^3.1.7", - "@types/d3-time": "^3.0.4", - "@types/d3-timer": "^3.0.2", - "d3-array": "^3.2.4", - "d3-color": "^3.1.0", - "d3-dispatch": "^3.0.1", - "d3-dsv": "^3.0.1", - "d3-ease": "^3.0.1", - "d3-fetch": "^3.0.1", - "d3-force": "^3.0.0", - "d3-force-3d": "^3.0.5", - "d3-format": "^3.1.0", - "d3-geo": "^3.1.1", - "d3-geo-projection": "^4.0.0", - "d3-hierarchy": "^3.1.2", - "d3-interpolate": "^3.0.1", - "d3-path": "^3.1.0", - "d3-quadtree": "^3.0.1", - "d3-random": "^3.0.1", - "d3-regression": "^1.3.10", - "d3-scale": "^4.0.2", - "d3-scale-chromatic": "^3.1.0", - "d3-shape": "^3.2.0", - "d3-time": "^3.1.0", - "d3-timer": "^3.0.1" - } - }, "node_modules/@asamuzakjp/css-color": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", @@ -2211,6 +1971,7 @@ "version": "7.29.2", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -2695,12 +2456,6 @@ "node": ">=18" } }, - "node_modules/@dimforge/rapier3d-compat": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz", - "integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==", - "license": "Apache-2.0" - }, "node_modules/@emnapi/core": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", @@ -3263,44 +3018,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@floating-ui/core": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", - "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", - "license": "MIT", - "dependencies": { - "@floating-ui/utils": "^0.2.11" - } - }, - "node_modules/@floating-ui/dom": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", - "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", - "license": "MIT", - "dependencies": { - "@floating-ui/core": "^1.7.5", - "@floating-ui/utils": "^0.2.11" - } - }, - "node_modules/@floating-ui/react-dom": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", - "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==", - "license": "MIT", - "dependencies": { - "@floating-ui/dom": "^1.7.6" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@floating-ui/utils": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", - "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", - "license": "MIT" - }, "node_modules/@formatjs/ecma402-abstract": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.6.tgz", @@ -5967,61 +5684,6 @@ "node": ">=10" } }, - "node_modules/@radix-ui/primitive": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", - "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", - "license": "MIT" - }, - "node_modules/@radix-ui/react-arrow": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", - "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.3" - }, - "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 - } - } - }, - "node_modules/@radix-ui/react-collection": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", - "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3" - }, - "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 - } - } - }, "node_modules/@radix-ui/react-compose-refs": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", @@ -6037,364 +5699,10 @@ } } }, - "node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", - "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dialog": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", - "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" - }, - "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 - } - } - }, - "node_modules/@radix-ui/react-direction": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", - "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", - "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-escape-keydown": "1.1.1" - }, - "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 - } - } - }, - "node_modules/@radix-ui/react-dropdown-menu": { - "version": "2.1.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz", - "integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-menu": "2.1.16", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, - "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 - } - } - }, - "node_modules/@radix-ui/react-focus-guards": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", - "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", - "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1" - }, - "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 - } - } - }, - "node_modules/@radix-ui/react-id": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", - "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-menu": { - "version": "2.1.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz", - "integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" - }, - "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 - } - } - }, - "node_modules/@radix-ui/react-popper": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", - "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", - "license": "MIT", - "dependencies": { - "@floating-ui/react-dom": "^2.0.0", - "@radix-ui/react-arrow": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-rect": "1.1.1", - "@radix-ui/react-use-size": "1.1.1", - "@radix-ui/rect": "1.1.1" - }, - "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 - } - } - }, - "node_modules/@radix-ui/react-portal": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", - "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "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 - } - } - }, - "node_modules/@radix-ui/react-presence": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", - "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "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 - } - } - }, - "node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "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 - } - } - }, - "node_modules/@radix-ui/react-roving-focus": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", - "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, - "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 - } - } - }, "node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz", + "integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -6409,133 +5717,6 @@ } } }, - "node_modules/@radix-ui/react-use-callback-ref": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", - "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-controllable-state": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", - "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-effect-event": "0.0.2", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-effect-event": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", - "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-escape-keydown": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", - "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-callback-ref": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", - "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-rect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", - "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", - "license": "MIT", - "dependencies": { - "@radix-ui/rect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-size": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", - "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/rect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", - "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", - "license": "MIT" - }, "node_modules/@sentry-internal/tracing": { "version": "7.120.4", "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.120.4.tgz", @@ -7178,12 +6359,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@tweenjs/tween.js": { - "version": "23.1.3", - "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", - "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==", - "license": "MIT" - }, "node_modules/@tybys/wasm-util": { "version": "0.10.1", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", @@ -7258,141 +6433,6 @@ "@types/node": "*" } }, - "node_modules/@types/d3-array": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", - "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", - "license": "MIT" - }, - "node_modules/@types/d3-color": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", - "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", - "license": "MIT" - }, - "node_modules/@types/d3-dispatch": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz", - "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==", - "license": "MIT" - }, - "node_modules/@types/d3-dsv": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", - "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", - "license": "MIT" - }, - "node_modules/@types/d3-ease": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", - "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", - "license": "MIT" - }, - "node_modules/@types/d3-fetch": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", - "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", - "license": "MIT", - "dependencies": { - "@types/d3-dsv": "*" - } - }, - "node_modules/@types/d3-force": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", - "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", - "license": "MIT" - }, - "node_modules/@types/d3-format": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", - "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", - "license": "MIT" - }, - "node_modules/@types/d3-geo": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", - "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", - "license": "MIT", - "dependencies": { - "@types/geojson": "*" - } - }, - "node_modules/@types/d3-hierarchy": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", - "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", - "license": "MIT" - }, - "node_modules/@types/d3-interpolate": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", - "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", - "license": "MIT", - "dependencies": { - "@types/d3-color": "*" - } - }, - "node_modules/@types/d3-path": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", - "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", - "license": "MIT" - }, - "node_modules/@types/d3-quadtree": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", - "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", - "license": "MIT" - }, - "node_modules/@types/d3-random": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", - "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", - "license": "MIT" - }, - "node_modules/@types/d3-scale": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", - "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", - "license": "MIT", - "dependencies": { - "@types/d3-time": "*" - } - }, - "node_modules/@types/d3-scale-chromatic": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", - "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", - "license": "MIT" - }, - "node_modules/@types/d3-shape": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", - "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", - "license": "MIT", - "dependencies": { - "@types/d3-path": "*" - } - }, - "node_modules/@types/d3-time": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", - "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", - "license": "MIT" - }, - "node_modules/@types/d3-timer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", - "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", - "license": "MIT" - }, - "node_modules/@types/geojson": { - "version": "7946.0.16", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", - "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", - "license": "MIT" - }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", @@ -7534,7 +6574,7 @@ "version": "19.2.3", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", - "devOptional": true, + "dev": true, "license": "MIT", "peerDependencies": { "@types/react": "^19.2.0" @@ -7554,12 +6594,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/stats.js": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz", - "integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==", - "license": "MIT" - }, "node_modules/@types/tedious": { "version": "4.0.14", "resolved": "https://registry.npmjs.org/@types/tedious/-/tedious-4.0.14.tgz", @@ -7570,21 +6604,6 @@ "@types/node": "*" } }, - "node_modules/@types/three": { - "version": "0.183.1", - "resolved": "https://registry.npmjs.org/@types/three/-/three-0.183.1.tgz", - "integrity": "sha512-f2Pu5Hrepfgavttdye3PsH5RWyY/AvdZQwIVhrc4uNtvF7nOWJacQKcoVJn0S4f0yYbmAE6AR+ve7xDcuYtMGw==", - "license": "MIT", - "dependencies": { - "@dimforge/rapier3d-compat": "~0.12.0", - "@tweenjs/tween.js": "~23.1.3", - "@types/stats.js": "*", - "@types/webxr": ">=0.5.17", - "@webgpu/types": "*", - "fflate": "~0.8.2", - "meshoptimizer": "~1.0.1" - } - }, "node_modules/@types/tough-cookie": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", @@ -7592,12 +6611,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/webxr": { - "version": "0.5.24", - "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.24.tgz", - "integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==", - "license": "MIT" - }, "node_modules/@types/yargs": { "version": "17.0.35", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", @@ -8357,12 +7370,6 @@ "win32" ] }, - "node_modules/@webgpu/types": { - "version": "0.1.69", - "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.69.tgz", - "integrity": "sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ==", - "license": "BSD-3-Clause" - }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -8481,6 +7488,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -8526,18 +7534,6 @@ "dev": true, "license": "Python-2.0" }, - "node_modules/aria-hidden": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", - "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", - "license": "MIT", - "dependencies": { - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/aria-query": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", @@ -9020,15 +8016,6 @@ "bare-path": "^3.0.0" } }, - "node_modules/base64-arraybuffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", - "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6.0" - } - }, "node_modules/baseline-browser-mapping": { "version": "2.10.20", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.20.tgz", @@ -9106,12 +8093,6 @@ "dev": true, "license": "MIT" }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "license": "ISC" - }, "node_modules/brace-expansion": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", @@ -9301,6 +8282,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -9597,6 +8579,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -9609,18 +8592,9 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, "license": "MIT" }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "license": "MIT", - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, "node_modules/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", @@ -9628,15 +8602,6 @@ "dev": true, "license": "MIT" }, - "node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, "node_modules/compare-func": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", @@ -9888,21 +8853,6 @@ "typescript": ">=5" } }, - "node_modules/critters": { - "version": "0.0.23", - "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.23.tgz", - "integrity": "sha512-/MCsQbuzTPA/ZTOjjyr2Na5o3lRpr8vd0MZE8tMP0OBNg/VrLxWHteVKalQ8KR+fBmUadbJLdoyEz9sT+q84qg==", - "license": "Apache-2.0", - "dependencies": { - "chalk": "^4.1.0", - "css-select": "^5.1.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.2", - "htmlparser2": "^8.0.2", - "postcss": "^8.4.23", - "postcss-media-query-parser": "^0.2.3" - } - }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -9935,43 +8885,6 @@ "dev": true, "license": "Apache-2.0" }, - "node_modules/css-line-break": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", - "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", - "license": "MIT", - "dependencies": { - "utrie": "^1.0.2" - } - }, - "node_modules/css-select": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", - "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", - "license": "BSD-2-Clause", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-what": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", - "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", - "license": "BSD-2-Clause", - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, "node_modules/css.escape": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", @@ -9997,296 +8910,9 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "devOptional": true, "license": "MIT" }, - "node_modules/d3-array": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", - "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", - "license": "ISC", - "dependencies": { - "internmap": "1 - 2" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-binarytree": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/d3-binarytree/-/d3-binarytree-1.0.2.tgz", - "integrity": "sha512-cElUNH+sHu95L04m92pG73t2MEJXKu+GeKUN1TJkFsu93E5W8E9Sc3kHEGJKgenGvj19m6upSn2EunvMgMD2Yw==", - "license": "MIT" - }, - "node_modules/d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-dispatch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", - "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-dsv": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", - "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", - "license": "ISC", - "dependencies": { - "commander": "7", - "iconv-lite": "0.6", - "rw": "1" - }, - "bin": { - "csv2json": "bin/dsv2json.js", - "csv2tsv": "bin/dsv2dsv.js", - "dsv2dsv": "bin/dsv2dsv.js", - "dsv2json": "bin/dsv2json.js", - "json2csv": "bin/json2dsv.js", - "json2dsv": "bin/json2dsv.js", - "json2tsv": "bin/json2dsv.js", - "tsv2csv": "bin/dsv2dsv.js", - "tsv2json": "bin/dsv2json.js" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-ease": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", - "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-fetch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", - "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", - "license": "ISC", - "dependencies": { - "d3-dsv": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-force": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", - "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", - "license": "ISC", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-quadtree": "1 - 3", - "d3-timer": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-force-3d": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/d3-force-3d/-/d3-force-3d-3.0.6.tgz", - "integrity": "sha512-4tsKHUPLOVkyfEffZo1v6sFHvGFwAIIjt/W8IThbp08DYAsXZck+2pSHEG5W1+gQgEvFLdZkYvmJAbRM2EzMnA==", - "license": "MIT", - "dependencies": { - "d3-binarytree": "1", - "d3-dispatch": "1 - 3", - "d3-octree": "1", - "d3-quadtree": "1 - 3", - "d3-timer": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-format": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", - "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-geo": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", - "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", - "license": "ISC", - "dependencies": { - "d3-array": "2.5.0 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-geo-projection": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/d3-geo-projection/-/d3-geo-projection-4.0.0.tgz", - "integrity": "sha512-p0bK60CEzph1iqmnxut7d/1kyTmm3UWtPlwdkM31AU+LW+BXazd5zJdoCn7VFxNCHXRngPHRnsNn5uGjLRGndg==", - "license": "ISC", - "dependencies": { - "commander": "7", - "d3-array": "1 - 3", - "d3-geo": "1.12.0 - 3" - }, - "bin": { - "geo2svg": "bin/geo2svg.js", - "geograticule": "bin/geograticule.js", - "geoproject": "bin/geoproject.js", - "geoquantize": "bin/geoquantize.js", - "geostitch": "bin/geostitch.js" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-hierarchy": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", - "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", - "license": "ISC", - "dependencies": { - "d3-color": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-octree": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/d3-octree/-/d3-octree-1.1.0.tgz", - "integrity": "sha512-F8gPlqpP+HwRPMO/8uOu5wjH110+6q4cgJvgJT6vlpy3BEaDIKlTZrgHKZSp/i1InRpVfh4puY/kvL6MxK930A==", - "license": "MIT" - }, - "node_modules/d3-path": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", - "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-quadtree": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", - "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-random": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", - "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-regression": { - "version": "1.3.10", - "resolved": "https://registry.npmjs.org/d3-regression/-/d3-regression-1.3.10.tgz", - "integrity": "sha512-PF8GWEL70cHHWpx2jUQXc68r1pyPHIA+St16muk/XRokETzlegj5LriNKg7o4LR0TySug4nHYPJNNRz/W+/Niw==", - "license": "BSD-3-Clause" - }, - "node_modules/d3-scale": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", - "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", - "license": "ISC", - "dependencies": { - "d3-array": "2.10.0 - 3", - "d3-format": "1 - 3", - "d3-interpolate": "1.2.0 - 3", - "d3-time": "2.1.1 - 3", - "d3-time-format": "2 - 4" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-scale-chromatic": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", - "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", - "license": "ISC", - "dependencies": { - "d3-color": "1 - 3", - "d3-interpolate": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-shape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", - "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", - "license": "ISC", - "dependencies": { - "d3-path": "^3.1.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", - "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", - "license": "ISC", - "dependencies": { - "d3-array": "2 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time-format": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", - "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", - "license": "ISC", - "dependencies": { - "d3-time": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-timer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", - "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, "node_modules/data-uri-to-buffer": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", @@ -10554,12 +9180,6 @@ "node": ">=8" } }, - "node_modules/detect-node-es": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", - "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", - "license": "MIT" - }, "node_modules/devtools-protocol": { "version": "0.0.1608973", "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1608973.tgz", @@ -10588,61 +9208,6 @@ "license": "MIT", "peer": true }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "license": "MIT", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "BSD-2-Clause" - }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "license": "BSD-2-Clause", - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", - "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", - "license": "BSD-2-Clause", - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, "node_modules/dot-prop": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", @@ -10760,18 +9325,6 @@ "node": ">=8.6" } }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/env-paths": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", @@ -11460,6 +10013,7 @@ "version": "5.0.4", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "dev": true, "license": "MIT" }, "node_modules/events-universal": { @@ -11677,6 +10231,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, "license": "MIT" }, "node_modules/fast-fifo": { @@ -11765,18 +10320,6 @@ } } }, - "node_modules/fecha": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", - "license": "MIT" - }, - "node_modules/fflate": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", - "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", - "license": "MIT" - }, "node_modules/figures": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", @@ -11888,15 +10431,6 @@ "dev": true, "license": "ISC" }, - "node_modules/flru": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/flru/-/flru-1.0.2.tgz", - "integrity": "sha512-kWyh8ADvHBFz6ua5xYOPnUroZTT/bwWfrCeL0Wj1dzG4/YOmOcfJ99W8dOVyyynJN35rZ9aCOtHChqQovV7yog==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/for-each": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", @@ -12115,15 +10649,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-nonce": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", - "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", @@ -12224,12 +10749,6 @@ "node": ">=18" } }, - "node_modules/gl-matrix": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.4.tgz", - "integrity": "sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==", - "license": "MIT" - }, "node_modules/glob": { "version": "10.5.0", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", @@ -12403,6 +10922,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -12516,38 +11036,6 @@ "dev": true, "license": "MIT" }, - "node_modules/html2canvas": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", - "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", - "license": "MIT", - "dependencies": { - "css-line-break": "^2.1.0", - "text-segmentation": "^1.0.3" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "MIT", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - }, "node_modules/http-errors": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", @@ -12637,6 +11125,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -12937,15 +11426,6 @@ "node": ">= 0.4" } }, - "node_modules/internmap": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", - "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, "node_modules/intl-messageformat": { "version": "10.7.18", "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.7.18.tgz", @@ -15797,12 +14277,6 @@ "dev": true, "license": "MIT" }, - "node_modules/meshoptimizer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-1.0.1.tgz", - "integrity": "sha512-Vix+QlA1YYT3FwmBBZ+49cE5y/b+pRrcXKqGpS5ouh33d3lSp2PoTpCw19E0cKDFWalembrHnIaZetf27a+W2g==", - "license": "MIT" - }, "node_modules/metaviewport-parser": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/metaviewport-parser/-/metaviewport-parser-0.3.0.tgz", @@ -16239,18 +14713,6 @@ "node": ">=8" } }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "license": "BSD-2-Clause", - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, "node_modules/nwsapi": { "version": "2.2.23", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz", @@ -16703,12 +15165,6 @@ "dev": true, "license": "MIT" }, - "node_modules/pdfast": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/pdfast/-/pdfast-0.2.0.tgz", - "integrity": "sha512-cq6TTu6qKSFUHwEahi68k/kqN2mfepjkGrG9Un70cgdRRKLKY6Rf8P8uvP2NvZktaQZNF3YE7agEkLj0vGK9bA==", - "license": "MIT" - }, "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -16906,6 +15362,7 @@ "version": "8.5.10", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", + "dev": true, "funding": [ { "type": "opencollective", @@ -16930,12 +15387,6 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/postcss-media-query-parser": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", - "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", - "license": "MIT" - }, "node_modules/postgres-array": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", @@ -17268,75 +15719,6 @@ "license": "MIT", "peer": true }, - "node_modules/react-remove-scroll": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", - "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", - "license": "MIT", - "dependencies": { - "react-remove-scroll-bar": "^2.3.7", - "react-style-singleton": "^2.2.3", - "tslib": "^2.1.0", - "use-callback-ref": "^1.3.3", - "use-sidecar": "^1.1.3" - }, - "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 - } - } - }, - "node_modules/react-remove-scroll-bar": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", - "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", - "license": "MIT", - "dependencies": { - "react-style-singleton": "^2.2.2", - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/react-style-singleton": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", - "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", - "license": "MIT", - "dependencies": { - "get-nonce": "^1.0.0", - "tslib": "^2.0.0" - }, - "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 - } - } - }, "node_modules/redent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", @@ -17702,12 +16084,6 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/rw": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", - "license": "BSD-3-Clause" - }, "node_modules/rxjs": { "version": "6.6.7", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", @@ -17808,6 +16184,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, "license": "MIT" }, "node_modules/saxes": { @@ -18137,21 +16514,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/simple-swizzle": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", - "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/simple-swizzle/node_modules/is-arrayish": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", - "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==", - "license": "MIT" - }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -18656,6 +17018,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -18677,12 +17040,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/svg-path-parser": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/svg-path-parser/-/svg-path-parser-1.1.0.tgz", - "integrity": "sha512-jGCUqcQyXpfe38R7RFfhrMyfXcBmpMNJI/B+4CE9/Unkh98UporAc461GTthv+TVDuZXsBx7/WiwJb1Oh4tt4A==", - "license": "MIT" - }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -18822,15 +17179,6 @@ "b4a": "^1.6.4" } }, - "node_modules/text-segmentation": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", - "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", - "license": "MIT", - "dependencies": { - "utrie": "^1.0.2" - } - }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -18845,12 +17193,6 @@ "dev": true, "license": "MIT" }, - "node_modules/three": { - "version": "0.183.2", - "resolved": "https://registry.npmjs.org/three/-/three-0.183.2.tgz", - "integrity": "sha512-di3BsL2FEQ1PA7Hcvn4fyJOlxRRgFYBpMTcyOgkwJIaDOdJMebEFPA+t98EvjuljDx4hNulAGwF6KIjtwI5jgQ==", - "license": "MIT" - }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -19481,49 +17823,6 @@ "punycode": "^2.1.0" } }, - "node_modules/use-callback-ref": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", - "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", - "license": "MIT", - "dependencies": { - "tslib": "^2.0.0" - }, - "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 - } - } - }, - "node_modules/use-sidecar": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", - "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", - "license": "MIT", - "dependencies": { - "detect-node-es": "^1.1.0", - "tslib": "^2.0.0" - }, - "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 - } - } - }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -19534,15 +17833,6 @@ "node": ">= 0.4.0" } }, - "node_modules/utrie": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", - "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", - "license": "MIT", - "dependencies": { - "base64-arraybuffer": "^1.0.2" - } - }, "node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", diff --git a/package.json b/package.json index 496e98f..aef1dd8 100644 --- a/package.json +++ b/package.json @@ -38,14 +38,10 @@ "prepare": "husky" }, "dependencies": { - "@antv/g2": "^5.4.8", "@playwright/test": "^1.58.2", - "@radix-ui/react-dialog": "^1.1.15", - "@radix-ui/react-dropdown-menu": "^2.1.16", - "@types/three": "^0.183.1", + "@radix-ui/react-slot": "^1.2.4", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "critters": "^0.0.23", "date-fns": "^4.1.0", "framer-motion": "^12.34.3", "lucide-react": "^0.563.0", @@ -53,7 +49,6 @@ "react": "19.2.3", "react-dom": "19.2.3", "tailwind-merge": "^3.4.0", - "three": "^0.183.1", "zod": "^4.3.6" }, "devDependencies": { diff --git a/src/app/(marketing)/about/client.tsx b/src/app/(marketing)/about/client.tsx index ed60ad0..b8c6d3b 100644 --- a/src/app/(marketing)/about/client.tsx +++ b/src/app/(marketing)/about/client.tsx @@ -1,31 +1,16 @@ 'use client'; import { motion } from 'framer-motion'; -import { useState, useEffect, useMemo } from 'react'; -import { COMPANY_INFO, STATS } from '@/lib/constants'; -import { FlipClock } from '@/components/ui/flip-clock'; +import { useMemo } from 'react'; +import { useReducedMotion } from '@/hooks/use-reduced-motion'; +import { COMPANY_INFO } from '@/lib/constants'; import { PageNav } from '@/components/layout/page-nav'; -import { Users, Target, Award, MapPin, Mail } from 'lucide-react'; -import { differenceInYears, differenceInMonths, differenceInDays, subYears, subMonths } from 'date-fns'; +import { BreadcrumbSchema } from '@/components/seo/structured-data'; +import { Users, Target, Award } from 'lucide-react'; export function AboutClient() { - const [operationTime, setOperationTime] = useState({ days: 0, months: 0, years: 0 }); - - useEffect(() => { - const foundingDate = new Date('2026-01-15'); - const calculateTime = () => { - const now = new Date(); - const years = differenceInYears(now, foundingDate); - const afterYears = subYears(now, years); - const months = differenceInMonths(afterYears, foundingDate); - const afterMonths = subMonths(afterYears, months); - const days = differenceInDays(afterMonths, foundingDate); - setOperationTime({ days, months, years }); - }; - calculateTime(); - const timer = setInterval(calculateTime, 60000); - return () => clearInterval(timer); - }, []); + const shouldReduceMotion = useReducedMotion(); + const fadeUp = shouldReduceMotion ? {} : { initial: { opacity: 0, y: 20 } }; const values = useMemo(() => [ { icon: Target, title: '务实', description: '不追逐风口,只做真正为客户创造价值的事。' }, @@ -34,193 +19,174 @@ export function AboutClient() { ], []); const milestones = useMemo(() => [ - { date: '2026年1月', title: '公司成立', description: '四川睿新致远科技有限公司在成都龙泉驿区正式成立' }, - { date: '2026年1月', title: '团队组建', description: '核心团队到位,成员来自多个大型传统IT企业,具备扎实的工程能力和规范化交付经验' }, - { date: '2026年2月', title: '业务启动', description: '推出企业数字化转型咨询与解决方案服务,开始接触首批意向客户' }, - { date: '2026年3月', title: '产品研发', description: '自主研发的ERP、CRM等产品启动研发,逐步构建产品矩阵' }, - { date: '2026年5月', title: '研发推进', description: '多款产品进入核心功能开发阶段,同步开展早期用户体验计划' }, + { date: '2026.01', title: '公司成立', description: '四川睿新致远科技有限公司在成都龙泉驿区正式成立' }, + { date: '2026.01', title: '团队组建', description: '核心团队到位,成员来自多个大型传统IT企业,具备扎实的工程能力和规范化交付经验' }, + { date: '2026.02', title: '业务启动', description: '推出企业数字化转型咨询与解决方案服务,开始接触首批意向客户' }, + { date: '2026.03', title: '产品研发', description: '自主研发的ERP、CRM等产品启动研发,逐步构建产品矩阵' }, + { date: '2026.05', title: '研发推进', description: '多款产品进入核心功能开发阶段,同步开展早期用户体验计划' }, ], []); return ( -
+
+
-

About

-

+

About

+

关于我们

-

+

以智慧连接数字趋势,以伙伴身份陪您成长——您的数字化转型同行者。

-
+
-
+
-

关于 {COMPANY_INFO.shortName}

-

智连未来,成长伙伴

-

企业需要的,不是一个高高在上的专家,也不是一个做完就跑的卖家,而是一个能坐下来、一起想办法的同行者。

+

+ 关于 {COMPANY_INFO.shortName} +

-
-

智连未来

-

我们坚持对行业趋势的深度研究,不追逐昙花一现的概念。

-

每一次方案,都源于对您业务场景的洞察;

-

每一次连接,都为了让技术真正服务于您的未来。

-
- -
-

成长伙伴

-

我们不把“项目完成”当作终点。

-

您的业务增长了吗?您的团队能力提升了吗?

-

您下一次遇到难题时,还会第一个想到我们吗?

-

这些问题,比“项目是否按时完成”更让我们在意。

-
-
- - -

品牌承诺

-

我们承诺:

-
    -
  • - - 不卖您用不上的技术 -
  • -
  • - - 不说不懂业务的术语 -
  • -
  • - - 不做路过就忘的“一锤子买卖” -
  • -
-

- 我们只做一件事:成为您数字化转型路上,信得过的成长伙伴。 -

-
- - - - - {STATS.map((stat, idx) => ( -
-
{stat.value}
-
{stat.label}
+
+
+

智连未来

+

我们坚持对行业趋势的深度研究,不追逐昙花一现的概念。

+

每一次方案,都源于对您业务场景的洞察;

+

每一次连接,都为了让技术真正服务于您的未来。

+ +
+

成长伙伴

+

我们不把“项目完成”当作终点。

+

您的业务增长了吗?您的团队能力提升了吗?

+

您下一次遇到难题时,还会第一个想到我们吗?

+
+
+ +
+

我们承诺:

+
+ {[ + '不卖您用不上的技术', + '不说不懂业务的术语', + '不做路过就忘的"一锤子买卖"', + ].map((promise) => ( +
+ + {promise} +
+ ))} +
+

+ 我们只做一件事:成为您数字化转型路上,信得过的成长伙伴。 +

+
+ +
+
+
+ +
+
+
+ + 核心价值观 + +
+ {values.map((value) => ( + +
+ +
+
+

{value.title}

+

{value.description}

+
+
))} - +
+
+
+
- +
+
+ -

核心价值观

-
- {values.map((value) => ( -
-
- -
-
-

{value.title}

-

{value.description}

-
-
- ))} -
- - - -

发展历程

-
- {milestones.map((milestone) => ( -
+
+
+
+ {milestones.map((milestone, idx) => { + const isLatest = idx === milestones.length - 1; + return ( + -
- {milestone.date} +
+ {milestone.date}
-
-

{milestone.title}

-

{milestone.description}

+
+
-
- ))} +
+
{milestone.date}
+
+

{milestone.title}

+ {isLatest && ( + + 进行中 + + )} +
+

{milestone.description}

+
+ + ); + })}
- - - -

联系我们

-
-
-
- -
-
-

公司地址

-

{COMPANY_INFO.address}

-
-
-
-
- -
-
-

电子邮箱

-

{COMPANY_INFO.email}

-
-
-
-
+
diff --git a/src/app/(marketing)/about/page.test.tsx b/src/app/(marketing)/about/page.test.tsx index e6b2555..3adf12e 100644 --- a/src/app/(marketing)/about/page.test.tsx +++ b/src/app/(marketing)/about/page.test.tsx @@ -72,17 +72,6 @@ jest.mock('@/components/ui/card', () => { return { Card, CardContent }; }); -jest.mock('@/components/ui/page-header', () => { - const PageHeader = ({ title, description }: { title: string; description?: string }) => ( -
-

{title}

-

{description}

-
- ); - PageHeader.displayName = 'PageHeader'; - return { PageHeader }; -}); - jest.mock('@/components/ui/flip-clock', () => { const FlipClock = ({ years, months, days }: { years: number; months: number; days: number }) => (
diff --git a/src/app/(marketing)/contact/page.tsx b/src/app/(marketing)/contact/page.tsx index 63f3fc7..4786683 100644 --- a/src/app/(marketing)/contact/page.tsx +++ b/src/app/(marketing)/contact/page.tsx @@ -1,9 +1,10 @@ 'use client'; -import { useState, useEffect, Suspense } from 'react'; +import { useState, Suspense } from 'react'; import { useSearchParams } from 'next/navigation'; import { z } from 'zod'; import { motion } from 'framer-motion'; +import { useReducedMotion } from '@/hooks/use-reduced-motion'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Textarea } from '@/components/ui/textarea'; @@ -12,6 +13,7 @@ import { Mail, MapPin, Send, Loader2, Clock, HeadphonesIcon, CheckCircle2 } from import { COMPANY_INFO } from '@/lib/constants'; import { PageNav } from '@/components/layout/page-nav'; import { trackContactForm, trackConversion } from '@/lib/analytics'; +import { BreadcrumbSchema } from '@/components/seo/structured-data'; const contactFormSchema = z.object({ name: z.string().min(2, '姓名至少需要2个字符'), @@ -34,6 +36,8 @@ interface FormErrors { function ContactFormContent() { const searchParams = useSearchParams(); const isSuccessFromRedirect = searchParams.get('success') === 'true'; + const shouldReduceMotion = useReducedMotion(); + const fadeUp = shouldReduceMotion ? {} : { initial: { opacity: 0, y: 20 } }; const [showToast, setShowToast] = useState(isSuccessFromRedirect); const [toastMessage, setToastMessage] = useState( isSuccessFromRedirect ? '表单提交成功!我们会尽快与您联系。' : '' @@ -52,12 +56,6 @@ function ContactFormContent() { }); const [errors, setErrors] = useState({}); - useEffect(() => { - if (isSuccessFromRedirect) { - setShowToast(true); - } - }, [isSuccessFromRedirect]); - const validateField = (field: keyof ContactFormData, value: string) => { try { contactFormSchema.shape[field].parse(value); @@ -153,7 +151,8 @@ function ContactFormContent() { } return ( -
+
+ {showToast && ( -

Contact

-

+

Contact

+

联系我们

-

+

无论您有任何问题或合作意向,我们都很乐意与您交流

@@ -186,93 +185,93 @@ function ContactFormContent() {
-

联系方式

+

联系方式

-
-
- +
+
-

地址

-

{COMPANY_INFO.address}

+

地址

+

{COMPANY_INFO.address}

-
+
- -

工作时间

+ +

工作时间

- 周一至周五 - 9:00 - 18:00 + 周一至周五 + 9:00 - 18:00
-
+
- -

我们的承诺

+ +

我们的承诺

-
-

工作日 2 小时内快速响应您的咨询

+
+

工作日 2 小时内快速响应您的咨询

-
-

提供免费的业务咨询和方案评估服务

+
+

提供免费的业务咨询和方案评估服务

-
-

根据您的需求量身定制最优解决方案

+
+

根据您的需求量身定制最优解决方案

-
-

发送消息

+
+

发送消息

{isSubmitted ? (
-
+
-

消息已发送

-

感谢您的留言,我们会尽快与您联系!

+

消息已发送

+

感谢您的留言,我们会尽快与您联系!

) : (
- +
{isSubmitting ? ( @@ -371,8 +370,8 @@ function ContactFormContent() { export default function ContactPage() { return ( -
加载中...
+
+
加载中...
}> diff --git a/src/app/(marketing)/home-content-v2.tsx b/src/app/(marketing)/home-content-v2.tsx index 974a208..560e04e 100644 --- a/src/app/(marketing)/home-content-v2.tsx +++ b/src/app/(marketing)/home-content-v2.tsx @@ -26,11 +26,11 @@ const CTASection = dynamic( function HomeContentV2() { return ( -
+
- +
); diff --git a/src/app/(marketing)/loading.tsx b/src/app/(marketing)/loading.tsx new file mode 100644 index 0000000..fb9699c --- /dev/null +++ b/src/app/(marketing)/loading.tsx @@ -0,0 +1,9 @@ +export default function Loading() { + return ( +
+
+
+
+
+ ); +} diff --git a/src/app/(marketing)/news/[slug]/NewsDetailClient.tsx b/src/app/(marketing)/news/[slug]/NewsDetailClient.tsx index abecb3b..59bf728 100644 --- a/src/app/(marketing)/news/[slug]/NewsDetailClient.tsx +++ b/src/app/(marketing)/news/[slug]/NewsDetailClient.tsx @@ -6,6 +6,7 @@ import { Badge } from '@/components/ui/badge'; import { PageNav } from '@/components/layout/page-nav'; import { Calendar, ArrowLeft, Newspaper } from 'lucide-react'; import { motion } from 'framer-motion'; +import { useReducedMotion } from '@/hooks/use-reduced-motion'; import { NEWS } from '@/lib/constants'; interface NewsDetailClientProps { @@ -13,28 +14,30 @@ interface NewsDetailClientProps { } export function NewsDetailClient({ news }: NewsDetailClientProps) { + const shouldReduceMotion = useReducedMotion(); + const fadeUp = shouldReduceMotion ? {} : { initial: { opacity: 0, y: 20 } }; const relatedNews = NEWS .filter((n) => n.id !== news.id && n.category === news.category) .slice(0, 3); return ( -
+
- + {news.category} -

+

{news.title}

-
+
{news.date} @@ -47,8 +50,8 @@ export function NewsDetailClient({ news }: NewsDetailClientProps) {
) : ( -
- +
+
)} -
-

+

+

{news.excerpt}

-
+
{news.content}
{relatedNews.length > 0 && ( -
-

相关新闻

+
+

相关新闻

{relatedNews.map((related) => ( @@ -92,16 +95,16 @@ export function NewsDetailClient({ news }: NewsDetailClientProps) { className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300" /> ) : ( -
- +
+
)}
{related.category} -

+

{related.title}

-

{related.excerpt}

+

{related.excerpt}

))} @@ -117,7 +120,7 @@ export function NewsDetailClient({ news }: NewsDetailClientProps) { - diff --git a/src/app/(marketing)/news/page.tsx b/src/app/(marketing)/news/page.tsx index cd3bb00..108ab6c 100644 --- a/src/app/(marketing)/news/page.tsx +++ b/src/app/(marketing)/news/page.tsx @@ -2,6 +2,7 @@ import { useState, useMemo, ChangeEvent } from 'react'; import { motion } from 'framer-motion'; +import { useReducedMotion } from '@/hooks/use-reduced-motion'; import { NEWS, COMPANY_INFO } from '@/lib/constants'; import { Badge } from '@/components/ui/badge'; import { Input } from '@/components/ui/input'; @@ -14,6 +15,8 @@ const categories = ['全部', '公司新闻', '研发动态']; const ITEMS_PER_PAGE = 9; export default function NewsListPage() { + const shouldReduceMotion = useReducedMotion(); + const fadeUp = shouldReduceMotion ? {} : { initial: { opacity: 0, y: 20 } }; const [selectedCategory, setSelectedCategory] = useState('全部'); const [searchQuery, setSearchQuery] = useState(''); const [currentPage, setCurrentPage] = useState(1); @@ -50,21 +53,21 @@ export default function NewsListPage() { }; return ( -
+
-

News

-

+

News

+

新闻动态

-

+

了解{COMPANY_INFO.displayName}最新动态,把握行业发展脉搏

@@ -74,8 +77,8 @@ export default function NewsListPage() {
handleCategoryChange(category)} className={ selectedCategory === category - ? 'bg-[#C41E3A] hover:bg-[#A01830] text-white' + ? 'bg-[var(--color-brand-primary)] hover:bg-[var(--color-brand-primary-hover)] text-white' : '' } > @@ -98,7 +101,7 @@ export default function NewsListPage() {
- + - -

没有找到相关新闻

+ +

没有找到相关新闻

) : ( <> @@ -121,15 +124,15 @@ export default function NewsListPage() { {paginatedNews.map((newsItem, index) => ( -
+
{newsItem.image ? ( -
+
{newsItem.title}
) : ( -
- +
+
)}
{newsItem.category} -
+
{newsItem.date}
-

+

{newsItem.title}

-

+

{newsItem.excerpt}

-
+
阅读更多
@@ -184,7 +187,7 @@ export default function NewsListPage() { onClick={() => handlePageChange(page)} className={ currentPage === page - ? 'bg-[#C41E3A] hover:bg-[#A01830] text-white' + ? 'bg-[var(--color-brand-primary)] hover:bg-[var(--color-brand-primary-hover)] text-white' : '' } > diff --git a/src/app/(marketing)/products/[id]/page.tsx b/src/app/(marketing)/products/[id]/page.tsx index 40c3e52..f11ac3c 100644 --- a/src/app/(marketing)/products/[id]/page.tsx +++ b/src/app/(marketing)/products/[id]/page.tsx @@ -34,28 +34,28 @@ export default async function ProductDetailPage({ params }: { params: Promise<{ } return ( -
+
-

{product.category}

+

{product.category}

{product.status}
-

+

{product.title}

-

+

{product.description}

@@ -64,92 +64,92 @@ export default async function ProductDetailPage({ params }: { params: Promise<{
-
-

产品概述

-

+

+

产品概述

+

{product.overview}

-
-

- +
+

+ 规划功能

{product.features.map((feature, index) => (
- - {feature} + + {feature}
))}
-
-

- +
+

+ 产品优势

{product.benefits.map((benefit, index) => (
- {benefit} + {benefit}
))}
-
-

- +
+

+ 预期实施流程

{product.process.map((step, index) => (
-
+
{index + 1}
-

{step}

+

{step}

))}
-
-

技术规格

+
+

技术规格

{product.specs.map((spec, index) => (
-
- {spec} +
+ {spec}
))}
-
+
-
+
-

定价待公布

-

+

定价待公布

+

本产品正在研发中,正式定价将在产品发布时公布。如果您对产品方向感兴趣,欢迎预约早期体验,您的反馈将帮助我们打造更贴合需求的产品。

-
-
+
- -
-
+

); } diff --git a/src/app/(marketing)/services/[id]/client.tsx b/src/app/(marketing)/services/[id]/client.tsx index 3b175a2..e58caba 100644 --- a/src/app/(marketing)/services/[id]/client.tsx +++ b/src/app/(marketing)/services/[id]/client.tsx @@ -72,16 +72,16 @@ export function ServiceDetailClient({ service }: ServiceDetailClientProps) { const serviceOutcomes = outcomes[service.id] ?? []; return ( -
+
-

Services

-

+

Services

+

{service.title}

-

+

{service.description}

@@ -92,19 +92,19 @@ export function ServiceDetailClient({ service }: ServiceDetailClientProps) {
-
- +
+
-

您可能面临的挑战

+

您可能面临的挑战

{serviceChallenges.map((challenge, index) => (
-

{challenge.title}

-

{challenge.description}

+

{challenge.title}

+

{challenge.description}

))}
@@ -112,19 +112,19 @@ export function ServiceDetailClient({ service }: ServiceDetailClientProps) {
-
- +
+
-

我们如何帮助您

+

我们如何帮助您

-

+

{service.overview}

{service.features.map((feature, index) => (
- - {feature} + + {feature}
))}
@@ -132,18 +132,18 @@ export function ServiceDetailClient({ service }: ServiceDetailClientProps) {
-
- +
+
-

服务流程

+

服务流程

{service.process.map((step, index) => (
-
+
{index + 1}
-

{step}

+

{step}

))}
@@ -151,37 +151,37 @@ export function ServiceDetailClient({ service }: ServiceDetailClientProps) {
-
- +
+
-

您将获得的改变

+

您将获得的改变

{serviceOutcomes.map((outcome, index) => (
-
+
{outcome.value}
-
{outcome.label}
+
{outcome.label}
))}
-
-

+

+

{service.benefits.join(';')}

-
+
- diff --git a/src/app/(marketing)/services/page.tsx b/src/app/(marketing)/services/page.tsx index a38a096..dc97db4 100644 --- a/src/app/(marketing)/services/page.tsx +++ b/src/app/(marketing)/services/page.tsx @@ -5,25 +5,28 @@ import { StaticLink } from '@/components/ui/static-link'; import { Button } from '@/components/ui/button'; import { ArrowRight, ArrowUpRight } from 'lucide-react'; import { motion } from 'framer-motion'; +import { useReducedMotion } from '@/hooks/use-reduced-motion'; import { PageNav } from '@/components/layout/page-nav'; export default function ServicesPage() { + const shouldReduceMotion = useReducedMotion(); + const fadeUp = shouldReduceMotion ? {} : { initial: { opacity: 0, y: 20 } }; return ( -
+
-

Services

-

+

Services

+

服务

-

+

专业技术团队,为您提供全方位的数字化解决方案

@@ -36,32 +39,32 @@ export default function ServicesPage() { {SERVICES.map((service, index) => (
- + {String(index + 1).padStart(2, '0')} - +
-

+

{service.title}

-

+

{service.description}

{service.features.slice(0, 3).map((feature, idx) => ( {feature.split(':')[0]} @@ -74,17 +77,17 @@ export default function ServicesPage() {
-
+
-

+

准备开始您的数字化转型之旅?

-

+

让我们与您同行,共创美好未来

- + {module.cta} + +
); @@ -145,27 +164,14 @@ export default function SolutionsPage() { -
-
-

- 准备开始您的数字化转型之旅? -

-

- 无论您处于哪个阶段,我们都能为您提供合适的解决方案 -

-
- - -
-
-
+
); } diff --git a/src/app/(marketing)/team/client.tsx b/src/app/(marketing)/team/client.tsx index cdf7045..d74f0d8 100644 --- a/src/app/(marketing)/team/client.tsx +++ b/src/app/(marketing)/team/client.tsx @@ -1,6 +1,7 @@ 'use client'; import { motion } from 'framer-motion'; +import { useReducedMotion } from '@/hooks/use-reduced-motion'; import { StaticLink } from '@/components/ui/static-link'; import { Button } from '@/components/ui/button'; import { Shield, Building2, Users, Code, Target, ArrowRight } from 'lucide-react'; @@ -35,22 +36,24 @@ const TEAM_PILLARS = [ ]; export function TeamClient() { + const shouldReduceMotion = useReducedMotion(); + const fadeUp = shouldReduceMotion ? {} : { initial: { opacity: 0, y: 20 } }; return ( -
+
-

Team

-

+

Team

+

核心团队

-

+

核心团队从事技术咨询、企业数字化等行业 12 年+,开发团队成员来自于多个大型传统 IT 企业

@@ -61,21 +64,21 @@ export function TeamClient() {
-

关于我们的团队

+

关于我们的团队

-

- 我们的核心团队长期从事技术咨询企业数字化等行业,拥有 12 年以上的深厚积累。 +

+ 我们的核心团队长期从事技术咨询企业数字化等行业,拥有 12 年以上的深厚积累。

-

- 开发团队成员来自于多个大型传统 IT 企业,具备扎实的工程能力和规范化的交付经验。 +

+ 开发团队成员来自于多个大型传统 IT 企业,具备扎实的工程能力和规范化的交付经验。

-

+

我们相信,优秀的技术咨询不仅需要过硬的技术能力,更需要深入理解客户的业务场景和真实需求。 每一位成员都是既懂技术又懂业务的复合型人才。

@@ -83,31 +86,31 @@ export function TeamClient() { -

团队优势

+

团队优势

{TEAM_PILLARS.map((item, idx) => { const Icon = item.icon; return ( = 3 ? 'md:col-span-1 lg:col-start-1' : ''} > -
-
- +
+
+
-

{item.title}

-

{item.description}

+

{item.title}

+

{item.description}

@@ -117,14 +120,14 @@ export function TeamClient() { -

想与我们的团队交流?

-
-
-

+
+

需要帮助?

-
- +
+
-
联系我们
-
获取技术支持
+
联系我们
+
获取技术支持
-
- +
+
-
服务
-
了解我们的服务
+
服务
+
了解我们的服务
-
+
如果问题持续存在,请{' '} - + 联系我们的技术团队
diff --git a/src/app/fonts/geist-mono.woff2 b/src/app/fonts/geist-mono.woff2 new file mode 100644 index 0000000..dbdb8c2 Binary files /dev/null and b/src/app/fonts/geist-mono.woff2 differ diff --git a/src/app/fonts/geist-sans.woff2 b/src/app/fonts/geist-sans.woff2 new file mode 100644 index 0000000..b2f0121 Binary files /dev/null and b/src/app/fonts/geist-sans.woff2 differ diff --git a/src/app/globals.css b/src/app/globals.css index 34033ce..5acc100 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,71 +1,104 @@ @import "tailwindcss"; @theme inline { - --font-sans: var(--font-geist-sans); + --font-sans: var(--font-noto-sans-sc), var(--font-geist-sans), -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; --font-mono: var(--font-geist-mono); - --font-chinese: var(--font-noto-sans-sc); - --font-calligraphy: 'Ma Shan Zheng', 'ZCOOL XiaoWei', 'STKaiti', 'KaiTi', serif; + --font-chinese: var(--font-noto-sans-sc), sans-serif; + --font-calligraphy: var(--font-ma-shan-zheng), 'ZCOOL XiaoWei', 'STKaiti', 'KaiTi', serif; } :root { - /* 主色调 - 墨黑系(水墨画主色) */ --color-primary: #1C1C1C; --color-primary-hover: #0A0A0A; --color-primary-light: #3D3D3D; --color-primary-lighter: #F5F5F5; - - /* 品牌色 - 朱砂红(印章红) */ + --color-primary-rgb: 28, 28, 28; + --color-brand-primary: #C41E3A; --color-brand-primary-hover: #A01830; --color-brand-primary-light: #E04A68; --color-brand-primary-bg: #FEF2F4; - - /* 背景色系 - 宣纸白 */ + --color-bg-primary: #FFFFFF; --color-bg-secondary: #FFFBF5; --color-bg-tertiary: #F5F5F5; + --color-bg-section: #FAFAFA; --color-bg-hover: #EFEFEF; - - /* 文字色系 - 墨色层次 */ + --color-text-primary: #1C1C1C; --color-text-secondary: #3D3D3D; - --color-text-tertiary: #404040; /* 从 #4A4A4A 调整,提升对比度 */ - --color-text-muted: #595959; /* 从 #6B6B6B 调整,确保 WCAG AA 合规 */ - - /* 边框色系 */ + --color-text-tertiary: #404040; + --color-text-muted: #595959; + --color-text-subtle: #A3A3A3; + --color-text-placeholder: #5C5C5C; + --color-text-hint: #8C8C8C; + --color-border-primary: #E5E5E5; --color-border-secondary: #D4D4D4; --color-border-accent: #1C1C1C; - - /* 链接色 */ + --color-border-light: #F0F0F0; + --color-border-dark: #333333; + --color-link: #1C1C1C; --color-link-hover: #C41E3A; - - /* 状态色 */ + --color-success: #16A34A; + --color-success-hover: #15803D; --color-success-bg: #F0FDF4; --color-warning: #D97706; + --color-warning-hover: #B45309; --color-warning-bg: #FFFBEB; --color-info: #5C5C5C; --color-info-bg: #F5F5F5; --color-error: #C41E3A; --color-error-bg: #FEF2F4; - - /* 场景色 - 挑战卡片 */ + + --color-accent-blue: #2563EB; + --color-accent-purple: #7C3AED; + --color-accent-cyan: #0891B2; + + --color-brand-primary-rgb: 196, 30, 58; + --color-warning-rgb: 217, 119, 6; + --color-success-rgb: 22, 163, 74; + --color-accent-blue-rgb: 37, 99, 235; + --color-accent-purple-rgb: 124, 58, 237; + --color-accent-cyan-rgb: 8, 145, 178; + + --color-footer-bg: #1C1C1C; + --color-footer-text: #A0A0A0; + --color-footer-text-muted: #666666; + --color-footer-text-dim: #999999; + --color-footer-text-link: #E0E0E0; + --color-footer-border: #333333; + --color-challenge-isolation: #FEF2F4; --color-challenge-isolation-hover: #FDE8EC; --color-challenge-growth: #FFFBEB; --color-challenge-growth-hover: #FEF3C7; --color-challenge-compliance: #F0FDF4; --color-challenge-compliance-hover: #DCFCE7; - - /* 阴影 */ + + --color-flip-card-bg: #FAFAFA; + --color-flip-card-border: #E5E5E5; + --color-flip-card-divider: #B0B0B0; + --color-flip-card-divider-subtle: #D4D4D4; + + --color-toast-success-bg: #F0FDF4; + --color-toast-success-border: #BBF7D0; + --color-toast-error-bg: #FEF2F4; + --color-toast-error-border: #FECACA; + --color-toast-info-bg: #EFF6FF; + --color-toast-info-border: #BFDBFE; + --color-toast-close: #A3A3A3; + --color-toast-close-hover: #595959; + + --color-skeleton-bg: #E5E5E5; + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05); --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.05); --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.05); --shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.05); - - /* 尺寸变量 */ + --font-size-xs: 0.75rem; --font-size-sm: 0.875rem; --font-size-base: 1rem; @@ -76,16 +109,16 @@ --font-size-4xl: 2.25rem; --font-size-5xl: 3rem; --font-size-6xl: 3.75rem; - + --line-height-tight: 1.1; --line-height-snug: 1.25; --line-height-normal: 1.5; --line-height-relaxed: 1.625; - + --letter-spacing-tight: -0.025em; --letter-spacing-normal: 0; --letter-spacing-wide: 0.025em; - + --spacing-xs: 0.25rem; --spacing-sm: 0.5rem; --spacing-md: 1rem; @@ -95,14 +128,14 @@ --spacing-3xl: 4rem; --spacing-4xl: 6rem; --spacing-5xl: 8rem; - + --border-width-thin: 0.5px; --border-width-normal: 1px; - + --transition-fast: 150ms; --transition-normal: 200ms; --transition-slow: 300ms; - + --ease-out: cubic-bezier(0.16, 1, 0.3, 1); --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1); } @@ -112,7 +145,7 @@ @apply antialiased; border-color: var(--color-border-primary); } - + html { scroll-behavior: smooth; font-size: 16px; @@ -121,30 +154,30 @@ text-rendering: optimizeLegibility; overflow-x: hidden; } - + @media (min-width: 640px) { html { font-size: 17px; } } - + @media (min-width: 1024px) { html { font-size: 18px; } } - + body { background-color: var(--color-bg-primary); color: var(--color-text-primary); - font-family: var(--font-chinese), var(--font-sans), -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; + font-family: var(--font-sans); line-height: var(--line-height-normal); letter-spacing: var(--letter-spacing-normal); position: relative; overflow-x: hidden; width: 100%; } - + body::before { content: ''; position: fixed; @@ -152,66 +185,54 @@ left: 0; right: 0; bottom: 0; - background: - radial-gradient(ellipse at 15% 20%, rgba(28, 28, 28, 0.02) 0%, transparent 50%), - radial-gradient(ellipse at 85% 80%, rgba(196, 30, 58, 0.02) 0%, transparent 50%); + background: + radial-gradient(ellipse at 15% 20%, rgba(var(--color-primary-rgb), 0.02) 0%, transparent 50%), + radial-gradient(ellipse at 85% 80%, rgba(var(--color-brand-primary-rgb), 0.02) 0%, transparent 50%); pointer-events: none; z-index: -1; } - + h1, h2, h3, h4, h5, h6 { font-weight: 600; line-height: var(--line-height-tight); letter-spacing: var(--letter-spacing-tight); color: var(--color-text-primary); } - - h1 { - font-size: var(--font-size-5xl); - } - - h2 { - font-size: var(--font-size-4xl); - } - - h3 { - font-size: var(--font-size-2xl); - } - - h4 { - font-size: var(--font-size-xl); - } - + + h1 { font-size: var(--font-size-5xl); } + h2 { font-size: var(--font-size-4xl); } + h3 { font-size: var(--font-size-2xl); } + h4 { font-size: var(--font-size-xl); } + p { color: var(--color-text-secondary); line-height: var(--line-height-relaxed); } - + a { color: var(--color-link); text-decoration: none; transition: color var(--transition-fast) var(--ease-out); } - + a:hover { color: var(--color-link-hover); } - + button { font-family: inherit; cursor: pointer; } - + input, textarea { font-family: inherit; outline: none; } - + input:focus, textarea:focus { outline: none; } - - /* 马善政行书体 - 用于红色关键词高亮 */ + .font-calligraphy { font-family: var(--font-ma-shan-zheng), 'Ma Shan Zheng', 'ZCOOL XiaoWei', 'STKaiti', 'KaiTi', serif !important; font-weight: normal; @@ -220,7 +241,6 @@ text-rendering: optimizeLegibility; } - /* 青柳隷書 - 仅用于品牌标题"睿新致遠" */ .font-brand { font-family: var(--font-aoyagi-reisho), 'Aoyagi Reisho', 'Ma Shan Zheng', 'ZCOOL XiaoWei', 'STKaiti', 'KaiTi', serif !important; font-weight: normal; @@ -236,15 +256,6 @@ } @layer utilities { - .container-narrow { - width: 100%; - max-width: 640px; - margin-left: auto; - margin-right: auto; - padding-left: var(--spacing-lg); - padding-right: var(--spacing-lg); - } - .container-wide { width: 100%; max-width: 1200px; @@ -253,126 +264,45 @@ padding-left: var(--spacing-lg); padding-right: var(--spacing-lg); } - + @media (min-width: 768px) { .container-wide { padding-left: var(--spacing-2xl); padding-right: var(--spacing-2xl); } } - + @media (min-width: 1024px) { .container-wide { padding-left: 4rem; padding-right: 4rem; } } - + .container-full { width: 100%; padding-left: var(--spacing-lg); padding-right: var(--spacing-lg); } - + @media (min-width: 768px) { .container-full { padding-left: var(--spacing-2xl); padding-right: var(--spacing-2xl); } } - + @media (min-width: 1024px) { .container-full { padding-left: 4rem; padding-right: 4rem; } } - + .section-padding { padding-top: var(--spacing-5xl); padding-bottom: var(--spacing-5xl); } - - .section-padding-sm { - padding-top: var(--spacing-3xl); - padding-bottom: var(--spacing-3xl); - } - - .text-balance { - text-wrap: balance; - } - - .text-pretty { - text-wrap: pretty; - } - - .border-thin { - border-width: var(--border-width-thin); - } - - .transition-smooth { - transition: all var(--transition-normal) var(--ease-out); - } - - .transition-fast { - transition: all var(--transition-fast) var(--ease-out); - } - - /* 渐变背景 - Wickret 风格 */ - .bg-gradient-modern { - background: linear-gradient(135deg, var(--color-dark-bg) 0%, #1a1a2e 50%, #16213e 100%); - } - - .bg-gradient-brand { - background: linear-gradient(135deg, var(--color-gradient-start), var(--color-gradient-mid), var(--color-gradient-end)); - } - - .bg-gradient-radial { - background: radial-gradient(ellipse at center, var(--color-gradient-start) 0%, transparent 70%); - } - - /* 渐变文字 */ - .text-gradient-brand { - background: linear-gradient(135deg, var(--color-gradient-start), var(--color-gradient-mid), var(--color-gradient-end)); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; - } - - .text-gradient-cyan { - background: linear-gradient(135deg, var(--color-gradient-cyan), var(--color-gradient-mid)); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; - } - - /* 发光效果 */ - .bg-glow-red { - background: radial-gradient(circle at center, var(--color-accent-red-glow) 0%, transparent 70%); - } - - .bg-glow-purple { - background: radial-gradient(circle at center, rgba(139, 92, 246, 0.3) 0%, transparent 70%); - } - - .shadow-glow-purple { - box-shadow: 0 0 30px rgba(139, 92, 246, 0.3); - } - - .shadow-glow-red { - box-shadow: 0 0 30px rgba(196, 30, 58, 0.3); - } -} - -@keyframes fadeIn { - from { - opacity: 0; - transform: translateY(8px); - } - to { - opacity: 1; - transform: translateY(0); - } } @keyframes fadeInUp { @@ -386,37 +316,6 @@ } } -@keyframes slideIn { - from { - opacity: 0; - transform: translateX(-8px); - } - to { - opacity: 1; - transform: translateX(0); - } -} - -@keyframes scaleIn { - from { - opacity: 0; - transform: scale(0.98); - } - to { - opacity: 1; - transform: scale(1); - } -} - -@keyframes drawLine { - from { - transform: scaleX(0); - } - to { - transform: scaleX(1); - } -} - @keyframes stampIn { 0% { opacity: 0; @@ -435,220 +334,16 @@ } } -@keyframes inkSpread { - 0% { - opacity: 0; - transform: scale(0.8); - filter: blur(4px); - } - 100% { - opacity: 0.03; - transform: scale(1); - filter: blur(0); - } -} - -@keyframes inkFlow { - 0%, 100% { - background-position: 0% 0%; - } - 50% { - background-position: 100% 100%; - } -} - -@keyframes numberCount { - from { - opacity: 0; - transform: translateY(10px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -@keyframes sectionReveal { - from { - opacity: 0; - transform: translateY(40px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -@keyframes cornerFadeIn { - from { - opacity: 0; - transform: scale(0); - } - to { - opacity: 1; - transform: scale(1); - } -} - -.animate-fade-in { - animation: fadeIn 0.5s var(--ease-out) forwards; -} - .animate-fade-in-up { animation: fadeInUp 0.6s var(--ease-out) forwards; } -.animate-slide-in { - animation: slideIn 0.4s var(--ease-out) forwards; -} - -.animate-scale-in { - animation: scaleIn 0.3s var(--ease-out) forwards; -} - -.animate-draw-line { - animation: drawLine 0.4s var(--ease-out) forwards; - transform-origin: left; -} - .animate-stamp-in { animation: stampIn 0.6s var(--ease-out) forwards; } -.animate-ink-spread { - animation: inkSpread 1s var(--ease-out) forwards; -} - -.animate-section-reveal { - animation: sectionReveal 0.8s var(--ease-out) forwards; -} - -.animate-number-count { - animation: numberCount 0.5s var(--ease-out) forwards; -} - .stagger-1 { animation-delay: 0.1s; } .stagger-2 { animation-delay: 0.2s; } -.stagger-3 { animation-delay: 0.3s; } -.stagger-4 { animation-delay: 0.4s; } -.stagger-5 { animation-delay: 0.5s; } -.stagger-6 { animation-delay: 0.6s; } - -.geometric-card { - border: 1px solid rgba(196, 30, 58, 0.08); - position: relative; - background: rgba(255, 255, 255, 0.8); - backdrop-filter: blur(8px); - transition: all 0.3s var(--ease-out); -} - -.geometric-card::before, -.geometric-card::after { - content: ''; - position: absolute; - width: 12px; - height: 12px; - border: 1px solid rgba(196, 30, 58, 0.15); - opacity: 0; - transition: all 0.3s var(--ease-out); -} - -.geometric-card::before { - top: -1px; - left: -1px; - border-right: none; - border-bottom: none; - border-radius: 4px 0 0 0; -} - -.geometric-card::after { - bottom: -1px; - right: -1px; - border-left: none; - border-top: none; - border-radius: 0 0 4px 0; -} - -.geometric-card:hover { - border-color: rgba(196, 30, 58, 0.2); - transform: translateY(-4px); - box-shadow: 0 12px 40px -12px rgba(196, 30, 58, 0.15); -} - -.geometric-card:hover::before, -.geometric-card:hover::after { - opacity: 1; -} - -.geometric-card:hover::before { - animation: cornerFadeIn 0.3s var(--ease-out) forwards; -} - -.geometric-card:hover::after { - animation: cornerFadeIn 0.3s var(--ease-out) 0.1s forwards; -} - -.ink-divider { - height: 1px; - background: linear-gradient(90deg, transparent, rgba(196, 30, 58, 0.2), transparent); - position: relative; -} - -.ink-divider::before { - content: ''; - position: absolute; - left: 50%; - top: -3px; - width: 6px; - height: 6px; - background: var(--color-brand-primary); - border-radius: 50%; - transform: translateX(-50%); - opacity: 0.3; -} - -.chapter-title { - position: relative; - display: inline-block; -} - -.chapter-title::after { - content: ''; - position: absolute; - bottom: -8px; - left: 0; - width: 40px; - height: 3px; - background: var(--color-brand-primary); - border-radius: 2px; -} - -.scroll-reveal { - opacity: 0; - transform: translateY(30px); - transition: all 0.8s var(--ease-out); -} - -.scroll-reveal.revealed { - opacity: 1; - transform: translateY(0); -} - -.ink-texture { - position: relative; -} - -.ink-texture::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E"); - opacity: 0.015; - pointer-events: none; -} ::-webkit-scrollbar { width: 6px; @@ -676,7 +371,7 @@ animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; } - + html { scroll-behavior: auto; } @@ -689,469 +384,39 @@ --font-size-3xl: 1.5rem; --font-size-2xl: 1.25rem; } - + .section-padding { padding-top: var(--spacing-3xl); padding-bottom: var(--spacing-3xl); } } -@keyframes glow { - 0%, 100% { - box-shadow: 0 4px 12px rgba(196, 30, 58, 0.2); - } - 50% { - box-shadow: 0 8px 24px rgba(196, 30, 58, 0.3); - } -} - -@keyframes float { - 0%, 100% { - transform: translateY(0px); - } - 50% { - transform: translateY(-10px); - } -} - -@keyframes pulse-glow { - 0%, 100% { - opacity: 0.2; - } - 50% { - opacity: 0.4; - } -} - -@keyframes ripple { - 0% { - transform: scale(0); - opacity: 1; - } - 100% { - transform: scale(4); - opacity: 0; - } -} - -@keyframes inkDrop { - 0% { - transform: scale(0); - opacity: 0; - filter: blur(8px); - } - 50% { - opacity: 0.8; - filter: blur(2px); - } - 100% { - transform: scale(1); - opacity: 1; - filter: blur(0); - } -} - -@keyframes brushStroke { - 0% { - stroke-dashoffset: 1000; - opacity: 0; - } - 50% { - opacity: 1; - } - 100% { - stroke-dashoffset: 0; - opacity: 1; - } -} - -@keyframes sealPress { - 0% { - transform: scale(1.8) rotate(-20deg); - opacity: 0; - } - 60% { - transform: scale(0.9) rotate(2deg); - opacity: 1; - } - 80% { - transform: scale(1.05) rotate(-1deg); - } - 100% { - transform: scale(1) rotate(0deg); - opacity: 1; - } -} - -@keyframes inkBleed { - 0% { - box-shadow: 0 0 0 0 rgba(28, 28, 28, 0.1); - } - 100% { - box-shadow: 0 0 20px 10px rgba(28, 28, 28, 0); - } -} - -@keyframes shimmer { - 0% { - background-position: -200% 0; - } - 100% { - background-position: 200% 0; - } -} - -@keyframes breathe { - 0%, 100% { - transform: scale(1); - } - 50% { - transform: scale(1.02); - } -} - -@keyframes slideUp { - 0% { - transform: translateY(100%); - opacity: 0; - } - 100% { - transform: translateY(0); - opacity: 1; - } -} - -@keyframes slideDown { - 0% { - transform: translateY(-100%); - opacity: 0; - } - 100% { - transform: translateY(0); - opacity: 1; - } -} - -@keyframes expandWidth { - 0% { - width: 0; - opacity: 0; - } - 100% { - width: 100%; - opacity: 1; - } -} - -@keyframes typewriter { - from { - width: 0; - } - to { - width: 100%; - } -} - -@keyframes blink { - 0%, 50% { - opacity: 1; - } - 51%, 100% { - opacity: 0; - } -} - -.animate-glow { - animation: glow 2s ease-in-out infinite; -} - -.animate-float { - animation: float 3s ease-in-out infinite; -} - -.animate-pulse-glow { - animation: pulse-glow 2s ease-in-out infinite; -} - -.animate-ripple { - animation: ripple 0.6s ease-out forwards; -} - -.animate-ink-drop { - animation: inkDrop 0.8s cubic-bezier(0.16, 1, 0.3, 1) forwards; -} - -.animate-seal-press { - animation: sealPress 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) forwards; -} - -.animate-ink-bleed { - animation: inkBleed 1s ease-out forwards; -} - -.animate-shimmer { - background: linear-gradient( - 90deg, - rgba(196, 30, 58, 0) 0%, - rgba(196, 30, 58, 0.1) 50%, - rgba(196, 30, 58, 0) 100% - ); - background-size: 200% 100%; - animation: shimmer 2s infinite; -} - -.animate-breathe { - animation: breathe 4s ease-in-out infinite; -} - -.animate-slide-up { - animation: slideUp 0.5s cubic-bezier(0.16, 1, 0.3, 1) forwards; -} - -.animate-slide-down { - animation: slideDown 0.5s cubic-bezier(0.16, 1, 0.3, 1) forwards; -} - -.animate-expand-width { - animation: expandWidth 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards; -} - -.hover-lift { - transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.3s cubic-bezier(0.16, 1, 0.3, 1); -} - -.hover-lift:hover { - transform: translateY(-4px); - box-shadow: 0 12px 24px rgba(28, 28, 28, 0.1); -} - -.hover-scale { - transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1); -} - -.hover-scale:hover { - transform: scale(1.02); -} - -.hover-glow { - transition: box-shadow 0.3s cubic-bezier(0.16, 1, 0.3, 1); -} - -.hover-glow:hover { - box-shadow: 0 0 20px rgba(196, 30, 58, 0.3); -} - -.hover-ink { - position: relative; - overflow: hidden; -} - -.hover-ink::before { - content: ''; - position: absolute; - top: 50%; - left: 50%; - width: 0; - height: 0; - background: rgba(28, 28, 28, 0.05); - border-radius: 50%; - transform: translate(-50%, -50%); - transition: width 0.6s cubic-bezier(0.16, 1, 0.3, 1), height 0.6s cubic-bezier(0.16, 1, 0.3, 1); -} - -.hover-ink:hover::before { - width: 300%; - height: 300%; -} - -.ink-border { - position: relative; -} - -.ink-border::after { - content: ''; - position: absolute; - bottom: 0; - left: 0; - width: 0; - height: 2px; - background: linear-gradient(90deg, #1C1C1C, #C41E3A); - transition: width 0.4s cubic-bezier(0.16, 1, 0.3, 1); -} - -.ink-border:hover::after { - width: 100%; -} - -.seal-stamp { - position: relative; -} - -.seal-stamp::before { - content: ''; - position: absolute; - inset: -4px; - border: 2px solid rgba(196, 30, 58, 0.3); - border-radius: inherit; - opacity: 0; - transform: scale(1.1); - transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1); -} - -.seal-stamp:hover::before { - opacity: 1; - transform: scale(1); -} - -.primary-gradient { - background: linear-gradient(135deg, var(--color-primary) 0%, var(--color-primary-light) 100%); -} - -.primary-gradient-text { - background: linear-gradient(135deg, var(--color-primary) 0%, var(--color-primary-light) 100%); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; -} - -.brand-gradient { - background: linear-gradient(135deg, var(--color-brand-primary) 0%, var(--color-brand-primary-light) 100%); -} - -.brand-gradient-text { - background: linear-gradient(135deg, var(--color-brand-primary) 0%, var(--color-brand-primary-light) 100%); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; -} - -.card-shadow { - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04); -} - -.card-shadow-hover:hover { - box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08); -} - -.btn-primary { - background: #C41E3A; - color: #FFFFFF; - border-radius: 8px; - padding: 12px 32px; - font-weight: 600; - transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1); -} - -.btn-primary:hover { - background: #A01830; - transform: translateY(-2px); - box-shadow: 0 4px 12px rgba(196, 30, 58, 0.25); -} - -.btn-secondary { - background: #1C1C1C; - color: #FFFFFF; - border-radius: 8px; - padding: 12px 32px; - font-weight: 600; - transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1); -} - -.btn-secondary:hover { - background: #0A0A0A; - transform: translateY(-2px); - box-shadow: 0 4px 12px rgba(28, 28, 28, 0.25); -} - -.btn-outline { - background: transparent; - border: 2px solid #1C1C1C; - color: #1C1C1C; - border-radius: 8px; - padding: 12px 32px; - font-weight: 600; - transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1); -} - -.btn-outline:hover { - background: #F5F5F5; - transform: translateY(-2px); - box-shadow: 0 2px 8px rgba(28, 28, 28, 0.15); -} - -.card-health { - background: var(--color-bg-primary); - border: 1px solid var(--color-border-primary); - border-radius: 12px; - padding: 24px; - transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1); -} - -.card-health:hover { - border-color: var(--color-primary); - transform: translateY(-4px); - box-shadow: 0 8px 24px rgba(0, 0, 0, 0.06); -} - -.icon-container-primary { - background: linear-gradient(135deg, rgba(0, 94, 184, 0.1), rgba(0, 163, 224, 0.1)); - border-radius: 12px; - transition: box-shadow 0.3s ease; -} - -.icon-container-primary:hover { - box-shadow: 0 4px 12px rgba(0, 94, 184, 0.15); -} - -.icon-container-brand { - background: linear-gradient(135deg, rgba(196, 30, 58, 0.1), rgba(224, 74, 104, 0.1)); - border-radius: 12px; - transition: box-shadow 0.3s ease; -} - -.icon-container-brand:hover { - box-shadow: 0 4px 12px rgba(196, 30, 58, 0.15); -} - -/* 移动端安全区域适配 */ .safe-area-inset-bottom { padding-bottom: env(safe-area-inset-bottom, 0px); } -/* 隐藏移动端底部导航栏时的页面底部间距 */ body { padding-bottom: 0; + text-wrap: pretty; } @media (max-width: 767px) { body { padding-bottom: 64px; } - - /* 防止移动端内容溢出 */ + .container-wide, - .container-full, - .container-narrow { + .container-full { padding-left: 1rem; padding-right: 1rem; max-width: 100%; overflow-x: hidden; } - - /* 优化移动端文字大小 */ - h1 { - font-size: 2rem; - } - - h2 { - font-size: 1.75rem; - } - - h3 { - font-size: 1.375rem; - } - - /* 优化移动端按钮和链接的触摸目标 */ + + h1 { font-size: 2rem; } + h2 { font-size: 1.75rem; } + h3 { font-size: 1.375rem; } + a:not(nav[aria-label="breadcrumb"] a), button { min-height: 44px; min-width: 44px; @@ -1160,15 +425,13 @@ body { min-height: 0; min-width: 0; } - - /* 防止长文本溢出 */ + p, li, span { overflow-wrap: break-word; word-wrap: break-word; } } -/* 墨韵流光 - 旋转渐变边框 */ @property --border-angle { syntax: ''; initial-value: 0deg; @@ -1218,30 +481,54 @@ body { opacity: 0.3; } -/* 平板端优化 (768px - 1023px) */ @media (min-width: 768px) and (max-width: 1023px) { .container-wide, .container-full { padding-left: 2rem; padding-right: 2rem; } - - /* 平板端文字大小调整 */ - h1 { - font-size: 2.5rem; - } - - h2 { - font-size: 2rem; - } - - h3 { - font-size: 1.5rem; - } - - /* 平板端section间距 */ + + h1 { font-size: 2.5rem; } + h2 { font-size: 2rem; } + h3 { font-size: 1.5rem; } + .section-padding { padding-top: 4rem; padding-bottom: 4rem; } } + +.page-transition-loader { + width: 120px; + height: 3px; + background: var(--color-bg-section); + border-radius: 2px; + overflow: hidden; +} + +.page-transition-loader__bar { + width: 40%; + height: 100%; + background: var(--color-brand-primary); + border-radius: 2px; + animation: page-loader-slide 1.2s ease-in-out infinite; +} + +@keyframes page-loader-slide { + 0% { + transform: translateX(-100%); + } + 50% { + transform: translateX(200%); + } + 100% { + transform: translateX(-100%); + } +} + +@media (prefers-reduced-motion: reduce) { + .page-transition-loader__bar { + animation: none; + width: 100%; + } +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 61c1e18..77df2e8 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,6 +1,6 @@ import type { Metadata, Viewport } from "next"; -import { Geist, Geist_Mono, Noto_Sans_SC, Ma_Shan_Zheng } from "next/font/google"; import localFont from "next/font/local"; +import { Ma_Shan_Zheng, Noto_Sans_SC } from "next/font/google"; import "./globals.css"; import { Suspense } from "react"; import { ThemeProvider } from "@/contexts/theme-context"; @@ -15,24 +15,23 @@ import { ErrorBoundary } from "@/components/ui/error-boundary"; import { ScrollProgress } from "@/components/ui/scroll-progress"; import { BackToTop } from "@/components/ui/back-to-top"; -const geistSans = Geist({ +const geistSans = localFont({ + src: "./fonts/geist-sans.woff2", variable: "--font-geist-sans", - subsets: ["latin"], display: "swap", preload: false, }); -const geistMono = Geist_Mono({ +const geistMono = localFont({ + src: "./fonts/geist-mono.woff2", variable: "--font-geist-mono", - subsets: ["latin"], display: "swap", preload: false, }); -const notoSansSC = Noto_Sans_SC({ - weight: ["400", "500", "700"], - variable: "--font-noto-sans-sc", - subsets: ["latin"], +const aoyagiReisho = localFont({ + src: "./fonts/AoyagiReisho-subset.ttf", + variable: "--font-aoyagi-reisho", display: "swap", preload: true, }); @@ -40,17 +39,16 @@ const notoSansSC = Noto_Sans_SC({ const maShanZheng = Ma_Shan_Zheng({ weight: "400", variable: "--font-ma-shan-zheng", - subsets: ["latin"], display: "swap", - preload: true, + preload: false, }); -// 青柳隷書 - 仅用于品牌标题"睿新致遠"(子集版本,仅包含4个字符) -const aoyagiReisho = localFont({ - src: "./fonts/AoyagiReisho-subset.ttf", - variable: "--font-aoyagi-reisho", +const notoSansSC = Noto_Sans_SC({ + weight: ["400", "500", "700"], + variable: "--font-noto-sans-sc", display: "swap", - preload: true, + subsets: ["latin"], + preload: false, }); export const metadata: Metadata = { @@ -134,12 +132,11 @@ export default function RootLayout({ 跳转到主内容 diff --git a/src/app/not-found.tsx b/src/app/not-found.tsx index 0ab13e1..e8c2e52 100644 --- a/src/app/not-found.tsx +++ b/src/app/not-found.tsx @@ -7,21 +7,21 @@ import { COMPANY_INFO } from '@/lib/constants'; export default function NotFound() { return ( -
+
-

+

404

-
+
-

+

页面未找到

-

+

很抱歉,您访问的页面不存在或已被移动。 请检查网址是否正确,或使用以下导航继续浏览。

@@ -30,7 +30,7 @@ export default function NotFound() {
-
-

+
+

您可能在寻找

-
- +
+
-
关于我们
-
了解{COMPANY_INFO.displayName}
+
关于我们
+
了解{COMPANY_INFO.displayName}
-
- +
+
-
服务
-
我们的服务
+
服务
+
我们的服务
-
- +
+
-
产品
-
企业级产品
+
产品
+
企业级产品
-
- +
+
-
解决方案
-
行业方案
+
解决方案
+
行业方案
-
+
如果您认为这是一个错误,请{' '} - + 联系我们
diff --git a/src/app/privacy/page.tsx b/src/app/privacy/page.tsx index f98f30c..d65eb4e 100644 --- a/src/app/privacy/page.tsx +++ b/src/app/privacy/page.tsx @@ -8,8 +8,8 @@ export const metadata: Metadata = { export default function PrivacyPolicyPage() { return ( -
-
+
+

隐私政策 @@ -24,31 +24,31 @@ export default function PrivacyPolicyPage() {
-

引言

-

+

引言

+

四川睿新致远科技有限公司(以下简称“我们”、“公司”)深知个人信息对您的重要性,并会尽全力保护您的个人信息安全可靠。我们致力于维持您对我们的信任,恪守以下原则,保护您的个人信息:权责一致原则、目的明确原则、选择同意原则、最少够用原则、确保安全原则、主体参与原则、公开透明原则等。

-

+

本隐私政策适用于您通过四川睿新致远科技有限公司官方网站、移动应用、产品服务等渠道访问和使用我们的产品和服务时,我们收集和使用您的个人信息的情形。

-

一、我们如何收集和使用您的个人信息

-

+

一、我们如何收集和使用您的个人信息

+

我们会遵循正当、合法、必要的原则,仅为实现产品功能,向您提供服务之目的,收集和使用您的个人信息。

-

1.1 我们收集的个人信息

-
    +

    1.1 我们收集的个人信息

    +
    • 账户信息:当您注册账户时,我们可能收集您的姓名、电子邮箱地址、手机号码、公司名称等。
    • 联系信息:当您通过联系表单或客服与我们沟通时,我们可能收集您的姓名、电子邮箱地址、手机号码、留言内容等。
    • 使用信息:我们可能收集您使用我们产品和服务的信息,包括访问时间、浏览记录、操作日志等。
    • 设备信息:我们可能收集您使用的设备信息,包括设备型号、操作系统、浏览器类型等。
    -

    1.2 我们如何使用您的个人信息

    -
      +

      1.2 我们如何使用您的个人信息

      +
      • 提供产品和服务:向您提供我们的产品和服务,处理您的请求和订单。
      • 客户服务:与您联系,提供客户支持,回复您的咨询和反馈。
      • 改进产品和服务:分析使用情况,改进我们的产品和服务质量。
      • @@ -58,33 +58,33 @@ export default function PrivacyPolicyPage() {
-

二、我们如何共享、转让、公开披露您的个人信息

+

二、我们如何共享、转让、公开披露您的个人信息

-

2.1 共享

-

+

2.1 共享

+

我们不会向其他任何公司、组织和个人分享您的个人信息,但以下情况除外:

-
    +
    • 在获取明确同意的情况下分享:获得您的明确同意后,我们会与其他方共享您的个人信息。
    • 根据法律法规、法律程序、强制性的行政或司法要求所必须的情况进行提供。
    • 在涉及合并、收购或破产清算时,如涉及到个人信息转让,我们会要求新的持有您个人信息的公司、组织继续受本隐私政策的约束。
    -

    2.2 转让

    -

    +

    2.2 转让

    +

    我们不会将您的个人信息转让给任何公司、组织和个人,但以下情况除外:

    -
      +
      • 在获取明确同意的情况下转让。
      • 根据适用的法律法规、法律程序、强制性的行政或司法要求所必须的情况进行提供。
      • 在涉及合并、收购或破产清算时,如涉及到个人信息转让,我们会要求新的持有您个人信息的公司、组织继续受本隐私政策的约束。
      -

      2.3 公开披露

      -

      +

      2.3 公开披露

      +

      我们仅会在以下情况下,公开披露您的个人信息:

      -
        +
        • 获得您的明确同意。
        • 基于法律法规或法律程序的要求。
        • 在涉及合并、收购或破产清算时。
        • @@ -93,11 +93,11 @@ export default function PrivacyPolicyPage() {
-

三、我们如何保护您的个人信息

-

+

三、我们如何保护您的个人信息

+

我们已使用符合业界标准的安全防护措施保护您提供的个人信息,防止数据遭到未经授权访问、公开披露、使用、修改、损坏或丢失。我们会采取一切合理可行的措施,保护您的个人信息。

-
    +
    • 使用加密技术确保数据传输和存储安全。
    • 限制访问权限,仅授权人员可访问个人信息。
    • 定期进行安全审计和风险评估。
    • @@ -107,11 +107,11 @@ export default function PrivacyPolicyPage() {
-

四、您的权利

-

+

四、您的权利

+

按照中国相关的法律、法规、标准,以及其他国家、地区的通行做法,我们保障您对自己的个人信息行使以下权利:

-
    +
    • 访问您的个人信息。
    • 更正您的个人信息。
    • 删除您的个人信息。
    • @@ -119,82 +119,82 @@ export default function PrivacyPolicyPage() {
    • 注销您的账户。
    • 获取您的个人信息副本。
    -

    +

    如您需要行使上述权利,请通过本隐私政策提供的联系方式与我们联系。

-

五、未成年人保护

-

+

五、未成年人保护

+

我们非常重视对未成年人个人信息的保护。如果您是18周岁以下的未成年人,在使用我们的产品和服务前,应事先取得您家长或法定监护人的同意。如您是未成年人的监护人,当您对您所监护的未成年人的个人信息处理存在疑问时,请通过本隐私政策提供的联系方式与我们联系。

-

六、隐私政策的更新

-

+

六、隐私政策的更新

+

我们可能适时更新本隐私政策的条款,该等更新构成本隐私政策的一部分。如该等更新造成您在本隐私政策下权利的实质减少,我们将在更新生效前通过在主页上显著位置提示或向您发送电子邮件或其他方式通知您,在该种情况下,若您继续使用我们的服务,即表示同意受经修订的本隐私政策的约束。

-

七、Cookie 和网站分析工具

+

七、Cookie 和网站分析工具

-

7.1 Cookie 使用说明

-

+

7.1 Cookie 使用说明

+

我们使用 Cookie 和类似技术来提供、保护和改进我们的服务。Cookie 是存储在您设备上的小型文本文件,帮助我们识别您的设备、记住您的偏好设置。

- - +
+ - - - - + + + + - + - - - - + + + + - - - - + + + + - - - - + + + +
Cookie 类型用途持续时间是否必需Cookie 类型用途持续时间是否必需
必要 Cookie网站基本功能运行会话期间必要 Cookie网站基本功能运行会话期间
分析 Cookie了解网站使用情况,改进服务14个月分析 Cookie了解网站使用情况,改进服务14个月
营销 Cookie个性化广告(当前未使用)-营销 Cookie个性化广告(当前未使用)-
-

7.2 Google Analytics 使用说明

-

+

7.2 Google Analytics 使用说明

+

我们使用 Google Analytics 4(由 Google LLC 提供)分析网站使用情况,帮助我们了解访客如何使用网站,从而改进用户体验。

-

+

收集的数据包括:

-
    +
    • 访问的页面和停留时间
    • 设备类型、浏览器类型
    • 地理位置(国家/城市级别,IP 地址已匿名化)
    • 访问来源(直接访问、搜索引擎、外部链接)
    -

    +

    我们已采取的保护措施:

    -
      +
      • IP 地址匿名化
      • 数据保留期限设为 14 个月
      • 禁用广告个性化功能
      • @@ -202,29 +202,29 @@ export default function PrivacyPolicyPage() {
      • 不与 Google 其他服务共享数据用于广告目的
      -

      7.3 您的选择

      -
        +

        7.3 您的选择

        +
        • 您可以在首次访问时选择接受或拒绝分析 Cookie
        • 您可以点击页面右下角的“Cookie 设置”按钮随时更改偏好
        • 您可以通过浏览器设置删除或阻止 Cookie(可能影响网站功能)
        -

        7.4 数据删除请求

        -

        +

        7.4 数据删除请求

        +

        如您希望删除我们持有的您的个人数据,或撤回您的同意,请通过以下方式联系我们:

        -
          +
          • 隐私邮箱:privacy@novalon.cn
          • 联系地址:中国四川省成都市龙泉驿区幸福路12号
-

八、如何联系我们

-

+

八、如何联系我们

+

如果您对本隐私政策有任何疑问、意见或建议,或需要行使您的权利,请通过以下方式与我们联系:

-
    +
    • 公司名称:四川睿新致远科技有限公司
    • 联系邮箱:contact@novalon.cn
    • 隐私邮箱:privacy@novalon.cn
    • diff --git a/src/app/terms/page.tsx b/src/app/terms/page.tsx index 8433468..9b13436 100644 --- a/src/app/terms/page.tsx +++ b/src/app/terms/page.tsx @@ -8,8 +8,8 @@ export const metadata: Metadata = { export default function TermsOfServicePage() { return ( -
      -
      +
      +

      服务条款 @@ -24,48 +24,48 @@ export default function TermsOfServicePage() {
      -

      引言

      -

      +

      引言

      +

      欢迎使用四川睿新致远科技有限公司(以下简称“我们”、“公司”)提供的产品和服务。在使用我们的产品和服务之前,请您仔细阅读并理解本服务条款。如果您不同意本服务条款的任何内容,请停止使用我们的产品和服务。

      -

      +

      本服务条款是您与四川睿新致远科技有限公司之间就使用我们的产品和服务所订立的协议。我们有权根据需要不时修改本服务条款,修改后的条款一旦公布即代替原条款,恕不另行通知。

      -

      一、服务内容

      -

      +

      一、服务内容

      +

      我们提供的产品和服务包括但不限于:软件开发、云服务、数据分析、信息安全、企业级软件产品(如ERP、CRM、后台管理系统、BI等)等。具体服务内容以我们官方网站或产品文档为准。

      -

      +

      我们保留随时修改、暂停或终止部分或全部服务的权利,无需事先通知。对于因服务修改、暂停或终止而给您造成的任何损失,我们不承担任何责任,除非法律另有规定。

      -

      二、用户注册与账户

      +

      二、用户注册与账户

      -

      2.1 注册资格

      -

      +

      2.1 注册资格

      +

      您确认,在您完成注册程序或以其他方式实际使用本服务时,您应当是具备完全民事权利能力和完全民事行为能力的自然人、法人或其他组织。若您不具备前述主体资格,则您及您的监护人应承担因此而导致的一切后果,且我们有权注销或永久冻结您的账户。

      -

      2.2 账户安全

      -

      +

      2.2 账户安全

      +

      您有责任维护您账户的安全性和保密性。您不得向任何第三方泄露您的账户信息,也不得与他人共享您的账户。如果您发现任何未经授权使用您账户的情况,应立即通知我们。

      -

      +

      您对您账户下发生的所有活动负责。我们对因您未能维护账户安全而造成的任何损失不承担责任。

      -

      三、用户行为规范

      -

      +

      三、用户行为规范

      +

      在使用我们的产品和服务时,您同意遵守以下行为规范:

      -
        +
        • 遵守所有适用的法律法规和本服务条款。
        • 不得利用我们的产品和服务进行任何违法或不当活动。
        • 不得干扰或破坏我们的产品和服务或与我们的产品和服务相连的服务器和网络。
        • @@ -74,52 +74,52 @@ export default function TermsOfServicePage() {
        • 不得进行任何形式的商业欺诈或诈骗活动。
        • 不得恶意收集或获取其他用户的信息。
        -

        +

        如果我们认定您违反了本服务条款或任何适用法律,我们有权在不事先通知的情况下,暂停或终止您的账户,并拒绝您现在或将来使用我们的产品和服务。

      -

      四、知识产权

      -

      +

      四、知识产权

      +

      我们的产品和服务中包含的所有内容,包括但不限于软件、设计、文字、图片、音频、视频、商标、服务标识等,均受著作权法、商标法、专利法或其他适用法律的保护。

      -

      +

      除非另有明确说明,我们拥有或持有我们产品和服务中所有内容的所有知识产权。您不得以任何形式复制、修改、传播、展示、执行、创作衍生作品、转让、出售或以其他方式使用这些内容,除非获得我们的明确书面许可。

      -

      +

      您在使用我们的产品和服务时产生的任何内容,您仍保留其知识产权,但您授予我们全球性、非独占性、免版税的许可,以使用、复制、修改、传播、展示和执行这些内容,仅限于提供和改进我们的产品和服务。

      -

      五、服务费用与支付

      +

      五、服务费用与支付

      -

      5.1 费用标准

      -

      +

      5.1 费用标准

      +

      我们的产品和服务可能需要支付费用。具体费用标准以我们官方网站或产品文档公布的价格为准。我们保留随时调整价格的权利,调整后的价格适用于调整后的新订单或续费。

      -

      5.2 支付方式

      -

      +

      5.2 支付方式

      +

      我们接受多种支付方式,包括但不限于银行转账、支付宝、微信支付等。具体支付方式以我们官方网站或产品文档为准。

      -

      5.3 退款政策

      -

      +

      5.3 退款政策

      +

      除非另有明确说明,我们提供的产品和服务一经售出,不予退款。如因我们的原因导致产品或服务无法正常使用,我们将根据实际情况提供相应的补偿或解决方案。

      -

      六、免责声明

      -

      +

      六、免责声明

      +

      我们的产品和服务按“现状”和“可用”基础提供,不提供任何明示或暗示的保证,包括但不限于对适销性、适用性、非侵权性或准确性、可靠性的保证。

      -

      +

      我们不对以下情况承担责任:

      -
        +
        • 因您违反本服务条款或任何适用法律而导致的任何损失或损害。
        • 因不可抗力、网络故障、设备故障等不可控因素导致的服务中断或数据丢失。
        • 因第三方服务或内容导致的任何损失或损害。
        • @@ -128,11 +128,11 @@ export default function TermsOfServicePage() {
      -

      七、服务终止

      -

      +

      七、服务终止

      +

      您可以随时停止使用我们的产品和服务,并注销您的账户。我们也有权在不事先通知的情况下,因以下原因暂停或终止您的账户:

      -
        +
        • 您违反本服务条款或任何适用法律。
        • 我们出于安全、法律或商业考虑,认为有必要终止您的账户。
        • 您长时间未使用您的账户。
        • @@ -141,15 +141,15 @@ export default function TermsOfServicePage() {
      -

      八、争议解决

      -

      +

      八、争议解决

      +

      本服务条款的订立、执行、解释及争议解决均适用中华人民共和国法律。如就本服务条款发生任何争议,双方应首先通过友好协商解决;协商不成的,任何一方均可向公司所在地有管辖权的人民法院提起诉讼。

      -

      九、其他条款

      -
        +

        九、其他条款

        +
        • 本服务条款构成您与我们就使用我们的产品和服务所达成的完整协议,取代之前的所有口头或书面协议。
        • 如本服务条款的任何条款被认定为无效或不可执行,该条款应被限制或排除,以使其有效和可执行,其余条款继续有效。
        • 我们未行使或延迟行使本服务条款项下的任何权利或规定,不构成对该权利或规定的放弃。
        • @@ -158,20 +158,20 @@ export default function TermsOfServicePage() {
      -

      十、联系我们

      -

      +

      十、联系我们

      +

      如果您对本服务条款有任何疑问、意见或建议,请通过以下方式与我们联系:

      -
        +
        • 公司名称:四川睿新致远科技有限公司
        • 联系邮箱:contact@novalon.cn
        • 联系地址:中国四川省成都市龙泉驿区幸福路12号
      -
      -

      最后更新日期

      -

      2026年2月26日

      +
      +

      最后更新日期

      +

      2026年2月26日

      diff --git a/src/components/analytics/CookieConsent.tsx b/src/components/analytics/CookieConsent.tsx index 79c7bdd..edc7ab3 100644 --- a/src/components/analytics/CookieConsent.tsx +++ b/src/components/analytics/CookieConsent.tsx @@ -124,18 +124,18 @@ export function CookieConsent() { animate={{ y: 0, opacity: 1 }} exit={{ y: 100, opacity: 0 }} transition={{ type: 'spring', damping: 25, stiffness: 300 }} - className="fixed bottom-16 md:bottom-0 left-0 right-0 z-[9998] bg-white border-t border-gray-200 shadow-lg" + className="fixed bottom-16 md:bottom-0 left-0 right-0 z-[9998] bg-[var(--color-bg-primary)] border-t border-[var(--color-border-secondary)] shadow-lg" >
      {!showSettings ? (
      -

      +

      我们使用 Cookie 和类似技术来改善您的体验、分析网站流量。 继续使用即表示您同意我们的{' '} 隐私政策 @@ -146,21 +146,21 @@ export function CookieConsent() { @@ -169,10 +169,10 @@ export function CookieConsent() { ) : (

      -

      Cookie 偏好设置

      +

      Cookie 偏好设置

      -
      +
      - 必要 Cookie - 始终启用 + 必要 Cookie + 始终启用
      -

      +

      网站正常运行所必需,无法禁用

      -
      +
      handleTogglePreference('analytics')} - className="mt-1 h-4 w-4 rounded border-gray-300 text-[#C41E3A] focus:ring-[#C41E3A] cursor-pointer" + className="mt-1 h-4 w-4 rounded border-[var(--color-border-secondary)] text-[var(--color-brand-primary)] focus:ring-[var(--color-brand-primary)] cursor-pointer" aria-label="分析 Cookie" />
      - 分析 Cookie -

      + 分析 Cookie +

      帮助我们了解访客如何使用网站,改进用户体验

      -
      +
      handleTogglePreference('marketing')} - className="mt-1 h-4 w-4 rounded border-gray-300 text-[#C41E3A] focus:ring-[#C41E3A] cursor-pointer" + className="mt-1 h-4 w-4 rounded border-[var(--color-border-secondary)] text-[var(--color-brand-primary)] focus:ring-[var(--color-brand-primary)] cursor-pointer" aria-label="营销 Cookie" />
      - 营销 Cookie -

      + 营销 Cookie +

      用于个性化广告(当前未使用)

      @@ -238,14 +238,14 @@ export function CookieConsent() { @@ -273,7 +273,7 @@ export function CookieSettingsButton() { const event = new CustomEvent('open-cookie-settings'); window.dispatchEvent(event); }} - className="fixed bottom-4 right-4 z-[9997] px-3 py-2 text-xs font-medium text-gray-600 bg-white border border-gray-200 rounded-lg shadow-sm hover:bg-gray-50 transition-colors" + className="fixed bottom-4 right-4 z-[9997] px-3 py-2 text-xs font-medium text-[var(--color-text-muted)] bg-[var(--color-bg-primary)] border border-[var(--color-border-secondary)] rounded-lg shadow-sm hover:bg-[var(--color-primary-lighter)] transition-colors" aria-label="Cookie 设置" > Cookie 设置 diff --git a/src/components/effects/advanced-floating-effects.tsx b/src/components/effects/advanced-floating-effects.tsx deleted file mode 100644 index 0ef7317..0000000 --- a/src/components/effects/advanced-floating-effects.tsx +++ /dev/null @@ -1,450 +0,0 @@ -'use client'; - -import { motion, useScroll, useTransform } from 'framer-motion'; -import { useMemo, useState, useEffect, useRef } from 'react'; -import { Cpu, Shield, Zap, Globe, FileText, TrendingUp, BarChart3, Users } from 'lucide-react'; - -interface FloatingOrbProps { - size?: number; - color?: string; - delay?: number; - x?: number; - y?: number; - duration?: number; - icon?: any; - className?: string; -} - -function FloatingOrb({ - size = 80, - color = 'rgba(196, 30, 58, 0.08)', - delay = 0, - x = 0, - y = 0, - duration = 8, - icon: Icon, - className = '' -}: FloatingOrbProps) { - return ( - - {Icon && ( -
      - -
      - )} -
      - ); -} - -interface FloatingLineProps { - startX?: number; - startY?: number; - endX?: number; - endY?: number; - color?: string; - delay?: number; - duration?: number; - className?: string; -} - -function FloatingLine({ - startX = 0, - startY = 0, - endX = 200, - endY = 0, - color = 'rgba(28, 28, 28, 0.1)', - delay = 0, - duration = 6, - className = '' -}: FloatingLineProps) { - return ( - - - - ); -} - -interface FloatingIconProps { - icon?: any; - size?: number; - color?: string; - delay?: number; - x?: number; - y?: number; - rotation?: number; - className?: string; -} - -function FloatingIcon({ - icon: Icon, - size = 24, - color = '#1C1C1C', - delay = 0, - x = 0, - y = 0, - rotation = 0, - className = '' -}: FloatingIconProps) { - return ( - -
      - -
      -
      - ); -} - -interface ParticleRingProps { - size?: number; - color?: string; - delay?: number; - x?: number; - y?: number; - className?: string; -} - -function ParticleRing({ - size = 120, - color = 'rgba(196, 30, 58, 0.1)', - delay = 0, - x = 0, - y = 0, - className = '' -}: ParticleRingProps) { - return ( - - - {[0, 60, 120, 180, 240, 300].map((angle, i) => { - const rad = (angle * Math.PI) / 180; - const px = 60 + Math.cos(rad) * 45; - const py = 60 + Math.sin(rad) * 45; - return ( - - ); - })} - - - - ); -} - -interface GlowingDotProps { - size?: number; - color?: string; - delay?: number; - x?: number; - y?: number; - className?: string; -} - -function GlowingDot({ - size = 8, - color = '#C41E3A', - delay = 0, - x = 0, - y = 0, - className = '' -}: GlowingDotProps) { - return ( - - ); -} - -interface AdvancedFloatingEffectsProps { - variant?: 'minimal' | 'balanced' | 'rich' | 'parallax'; - className?: string; -} - -export function AdvancedFloatingEffects({ - variant = 'balanced', - className = '' -}: AdvancedFloatingEffectsProps) { - const [isMounted, setIsMounted] = useState(false); - const containerRef = useRef(null); - const { scrollY } = useScroll(); - - useEffect(() => { - setIsMounted(true); - }, []); - - const config = { - minimal: { orbs: 2, icons: 3, rings: 0, lines: 2, dots: 5 }, - balanced: { orbs: 3, icons: 5, rings: 1, lines: 4, dots: 8 }, - rich: { orbs: 5, icons: 8, rings: 2, lines: 6, dots: 12 }, - parallax: { orbs: 4, icons: 6, rings: 2, lines: 5, dots: 10 }, - }; - - const { orbs, icons, rings, lines, dots } = config[variant]; - - const iconsList = [Cpu, Shield, Zap, Globe, FileText, TrendingUp, BarChart3, Users]; - - const elements = useMemo(() => { - if (!isMounted) {return [];} - - const items = []; - const width = typeof window !== 'undefined' ? window.innerWidth : 1920; - const height = typeof window !== 'undefined' ? window.innerHeight : 1080; - - for (let i = 0; i < orbs; i++) { - items.push({ - type: 'orb', - id: `orb-${i}`, - props: { - size: 60 + Math.random() * 60, - color: i % 2 === 0 ? 'rgba(196, 30, 58, 0.08)' : 'rgba(28, 28, 28, 0.05)', - delay: i * 0.5, - x: width * 0.1 + (i * width * 0.35), - y: height * 0.15 + Math.random() * height * 0.5, - duration: 7 + Math.random() * 4, - icon: i % 3 === 0 ? iconsList[i % iconsList.length] : undefined, - }, - parallaxDepth: 0.1 + i * 0.1, - }); - } - - for (let i = 0; i < icons; i++) { - items.push({ - type: 'icon', - id: `icon-${i}`, - props: { - icon: iconsList[i % iconsList.length], - size: 20, - color: i % 2 === 0 ? '#C41E3A' : '#1C1C1C', - delay: i * 0.4, - x: width * 0.08 + (i * width * 0.12), - y: height * 0.1 + Math.random() * height * 0.65, - rotation: -15 + Math.random() * 30, - }, - parallaxDepth: 0.2 + i * 0.05, - }); - } - - for (let i = 0; i < rings; i++) { - items.push({ - type: 'ring', - id: `ring-${i}`, - props: { - size: 100 + Math.random() * 80, - color: i % 2 === 0 ? 'rgba(196, 30, 58, 0.1)' : 'rgba(28, 28, 28, 0.08)', - delay: i * 0.8, - x: width * 0.2 + (i * width * 0.4), - y: height * 0.2 + Math.random() * height * 0.4, - }, - parallaxDepth: 0.05 + i * 0.1, - }); - } - - for (let i = 0; i < lines; i++) { - items.push({ - type: 'line', - id: `line-${i}`, - props: { - startX: width * 0.05 + (i * width * 0.15), - startY: height * 0.1 + Math.random() * height * 0.7, - endX: width * 0.05 + (i * width * 0.15) + 80 + Math.random() * 120, - endY: height * 0.1 + Math.random() * height * 0.7, - color: i % 2 === 0 ? 'rgba(196, 30, 58, 0.15)' : 'rgba(28, 28, 28, 0.1)', - delay: i * 0.6, - duration: 5 + Math.random() * 3, - }, - parallaxDepth: 0.15 + i * 0.05, - }); - } - - for (let i = 0; i < dots; i++) { - items.push({ - type: 'dot', - id: `dot-${i}`, - props: { - size: 4 + Math.random() * 6, - color: i % 3 === 0 ? '#C41E3A' : i % 3 === 1 ? '#1C1C1C' : '#D4A574', - delay: i * 0.3, - x: Math.random() * width, - y: Math.random() * height, - }, - parallaxDepth: 0.25 + i * 0.02, - }); - } - - return items; - }, [orbs, icons, rings, lines, dots, isMounted, iconsList]); - - const getParallaxStyle = (depth: number) => { - if (variant !== 'parallax') {return {};} - const y = useTransform(scrollY, [0, 500], [0, -depth * 100]); - return { y }; - }; - - return ( -
      - {elements.map((el) => { - const parallaxStyle = getParallaxStyle(el.parallaxDepth); - - return ( - - {el.type === 'orb' && } - {el.type === 'icon' && } - {el.type === 'ring' && } - {el.type === 'line' && } - {el.type === 'dot' && } - - ); - })} -
      - ); -} - -export default AdvancedFloatingEffects; diff --git a/src/components/effects/data-particle-flow.tsx b/src/components/effects/data-particle-flow.tsx deleted file mode 100644 index 61f590e..0000000 --- a/src/components/effects/data-particle-flow.tsx +++ /dev/null @@ -1,195 +0,0 @@ -'use client'; - -import { motion, useReducedMotion } from 'framer-motion'; -import { useEffect, useState } from 'react'; - -interface DataParticleFlowProps { - className?: string; - particleCount?: number; - color?: string; - intensity?: 'subtle' | 'normal' | 'prominent'; - shape?: 'circle' | 'square' | 'triangle' | 'diamond' | 'star' | 'mixed'; - effect?: 'default' | 'pulse' | 'glow' | 'trail'; -} - -interface Particle { - id: number; - x: number; - y: number; - size: number; - duration: number; - delay: number; - opacity: number; - moveRange: number; - shape: 'circle' | 'square' | 'triangle' | 'diamond' | 'star'; - rotation: number; -} - -export function DataParticleFlow({ - className = '', - particleCount = 50, - color = '#C41E3A', - intensity = 'normal', - shape = 'circle', - effect = 'default', -}: DataParticleFlowProps) { - const prefersReducedMotion = useReducedMotion(); - const [particles, setParticles] = useState([]); - - useEffect(() => { - const intensityConfig = { - subtle: { sizeMin: 3, sizeMax: 8, opacityMin: 0.2, opacityMax: 0.4, moveRange: 80 }, - normal: { sizeMin: 6, sizeMax: 16, opacityMin: 0.4, opacityMax: 0.7, moveRange: 150 }, - prominent: { sizeMin: 10, sizeMax: 24, opacityMin: 0.5, opacityMax: 0.9, moveRange: 200 }, - }; - - const shapes: Particle['shape'][] = ['circle', 'square', 'triangle', 'diamond', 'star']; - const config = intensityConfig[intensity]; - - const generated: Particle[] = Array.from({ length: particleCount }, (_, i) => ({ - id: i, - x: Math.random() * 100, - y: Math.random() * 100, - size: Math.random() * (config.sizeMax - config.sizeMin) + config.sizeMin, - duration: Math.random() * 12 + 8, - delay: Math.random() * 3, - opacity: Math.random() * (config.opacityMax - config.opacityMin) + config.opacityMin, - moveRange: config.moveRange, - shape: shape === 'mixed' ? (shapes[Math.floor(Math.random() * shapes.length)] ?? 'circle') : shape as Particle['shape'], - rotation: Math.random() * 360, - })); - setParticles(generated); - }, [particleCount, intensity, shape]); - - const getShapeStyles = (particle: Particle): React.CSSProperties => { - const baseStyles: React.CSSProperties = { - width: particle.size, - height: particle.size, - left: `${particle.x}%`, - top: `${particle.y}%`, - willChange: prefersReducedMotion ? 'auto' : 'transform, opacity', - }; - - switch (particle.shape) { - case 'circle': - return { - ...baseStyles, - borderRadius: '50%', - background: `radial-gradient(circle, ${color} 0%, ${color}80 40%, transparent 70%)`, - boxShadow: effect === 'glow' ? `0 0 ${particle.size * 2}px ${color}60` : 'none', - }; - - case 'square': - return { - ...baseStyles, - borderRadius: '2px', - background: `linear-gradient(135deg, ${color} 0%, ${color}60 100%)`, - boxShadow: effect === 'glow' ? `0 0 ${particle.size}px ${color}40` : 'none', - }; - - case 'triangle': - return { - ...baseStyles, - width: 0, - height: 0, - background: 'transparent', - borderLeft: `${particle.size / 2}px solid transparent`, - borderRight: `${particle.size / 2}px solid transparent`, - borderBottom: `${particle.size}px solid ${color}`, - filter: effect === 'glow' ? `drop-shadow(0 0 ${particle.size / 2}px ${color}60)` : 'none', - }; - - case 'diamond': - return { - ...baseStyles, - transform: `rotate(45deg)`, - background: `linear-gradient(135deg, ${color} 0%, ${color}60 100%)`, - boxShadow: effect === 'glow' ? `0 0 ${particle.size}px ${color}40` : 'none', - }; - - case 'star': - return { - ...baseStyles, - clipPath: 'polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%)', - background: `radial-gradient(circle, ${color} 0%, ${color}80 100%)`, - filter: effect === 'glow' ? `drop-shadow(0 0 ${particle.size / 2}px ${color}60)` : 'none', - }; - - default: - return baseStyles; - } - }; - - const getAnimationVariants = (particle: Particle) => { - if (prefersReducedMotion) { - return { scale: 1, opacity: particle.opacity }; - } - - const baseAnimation = { - scale: [0, 2, 1.5, 2.5, 0], - opacity: [0, particle.opacity, particle.opacity * 0.8, particle.opacity, 0], - y: [0, -particle.moveRange * 0.5, -particle.moveRange, -particle.moveRange * 1.5, -particle.moveRange * 2], - x: [0, particle.moveRange * 0.3, -particle.moveRange * 0.2, particle.moveRange * 0.15, 0], - }; - - switch (effect) { - case 'pulse': - return { - ...baseAnimation, - scale: [0, 1.5, 1, 1.8, 0], - }; - - case 'glow': - return { - ...baseAnimation, - opacity: [0, particle.opacity, particle.opacity * 1.2, particle.opacity, 0], - }; - - case 'trail': - return { - ...baseAnimation, - y: [particle.moveRange * 0.5, -particle.moveRange * 0.5, -particle.moveRange * 1.5, -particle.moveRange * 2.5, -particle.moveRange * 3], - }; - - default: - return baseAnimation; - } - }; - - return ( -