mirror of
https://github.com/setube/ogame-vue-ts.git
synced 2026-05-12 07:55:11 +08:00
Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20fb2bb6a4 | ||
|
|
752cade67c | ||
|
|
a689ce21b7 | ||
|
|
37045b432b | ||
|
|
a0ab4beaf4 | ||
|
|
53d5216e88 | ||
|
|
2ed15c4782 | ||
|
|
0da82802b8 | ||
|
|
d2465b5d4b | ||
|
|
e8590d54c7 | ||
|
|
2e3ac1231f | ||
|
|
99e4dbbb0d | ||
|
|
07ece4412f | ||
|
|
bde0532dbd | ||
|
|
d69b842c80 | ||
|
|
57fdc1b637 | ||
|
|
d700216cfc | ||
|
|
6813456d12 | ||
|
|
97db1324b6 | ||
|
|
ebd7eb1405 | ||
|
|
310372b8e2 | ||
|
|
d5a6dd49a1 | ||
|
|
f30676df07 | ||
|
|
690e6cbbf5 | ||
|
|
bd24ca02ae | ||
|
|
d9a8accad7 | ||
|
|
b166babf12 | ||
|
|
4aa4d9d350 | ||
|
|
60fd4135ec | ||
|
|
0bb9244214 | ||
|
|
cfcde0b024 | ||
|
|
053bd24855 | ||
|
|
7d1f36046d | ||
|
|
22ae07de90 | ||
|
|
a76909a2c7 | ||
|
|
8144f305e2 | ||
|
|
04721e2450 | ||
|
|
85ab19fb4a | ||
|
|
03f76b6497 | ||
|
|
9a571da4b1 | ||
|
|
797cc815f6 | ||
|
|
30aceb2a76 | ||
|
|
4340450d78 | ||
|
|
2bac87cd39 | ||
|
|
1aac97dfee | ||
|
|
84b090d51d | ||
|
|
a592713623 | ||
|
|
ec6b9cee07 | ||
|
|
b6fcad0a65 | ||
|
|
5273520305 | ||
|
|
751cb1e341 | ||
|
|
add90c5603 | ||
|
|
3410eeda19 | ||
|
|
c690323803 | ||
|
|
59dd7bfd05 | ||
|
|
3fa716e515 | ||
|
|
9aa240e335 | ||
|
|
88fa8aa2ee | ||
|
|
2601f1b776 | ||
|
|
763dfdde04 |
31
.github/ISSUE_TEMPLATE/BUG反馈.md
vendored
31
.github/ISSUE_TEMPLATE/BUG反馈.md
vendored
@@ -1,31 +0,0 @@
|
||||
---
|
||||
name: BUG反馈
|
||||
about: 报告项目中发现的缺陷或问题
|
||||
title: '[BUG] 简要描述问题'
|
||||
labels: 'bug'
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
**问题描述**
|
||||
清晰准确地描述遇到的问题
|
||||
|
||||
**重现步骤**
|
||||
|
||||
1. 第一步操作
|
||||
2. 第二步操作
|
||||
3. 出现问题的操作
|
||||
|
||||
**期望行为**
|
||||
描述您认为正确的行为应该是怎样的
|
||||
|
||||
**实际行为**
|
||||
描述实际发生的错误行为
|
||||
|
||||
**环境信息**
|
||||
|
||||
- 操作系统:
|
||||
- 浏览器(如适用):
|
||||
- 项目版本:
|
||||
|
||||
**截图或日志(可选)**
|
||||
如果有错误截图或日志,请提供
|
||||
19
.github/ISSUE_TEMPLATE/功能请求.md
vendored
19
.github/ISSUE_TEMPLATE/功能请求.md
vendored
@@ -1,19 +0,0 @@
|
||||
---
|
||||
name: 功能请求
|
||||
about: 请求添加新功能或改进现有功能
|
||||
title: '[功能] 简要描述功能'
|
||||
labels: 'enhancement'
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
**功能描述**
|
||||
清晰描述您希望添加的功能
|
||||
|
||||
**功能背景**
|
||||
说明为什么需要这个功能,它能解决什么问题
|
||||
|
||||
**建议实现方案(可选)**
|
||||
如果有具体的实现想法,可以在这里描述
|
||||
|
||||
**附加信息**
|
||||
任何其他有助于理解这个功能的信息
|
||||
19
.github/ISSUE_TEMPLATE/反馈建议.md
vendored
19
.github/ISSUE_TEMPLATE/反馈建议.md
vendored
@@ -1,19 +0,0 @@
|
||||
---
|
||||
name: 反馈建议
|
||||
about: 为这个项目提出功能建议或改进意见
|
||||
title: '[建议] 简要描述您的建议'
|
||||
labels: 'enhancement'
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
**您的建议是什么?**
|
||||
请清晰描述您希望添加的功能或改进点
|
||||
|
||||
**为什么需要这个功能/改进?**
|
||||
说明这个建议会解决什么问题或带来什么价值
|
||||
|
||||
**您期望的实现方式(可选)**
|
||||
如果有具体的实现想法,可以在这里描述
|
||||
|
||||
**附加信息(可选)**
|
||||
任何其他有助于理解这个建议的信息
|
||||
19
.github/ISSUE_TEMPLATE/文档改进.md
vendored
19
.github/ISSUE_TEMPLATE/文档改进.md
vendored
@@ -1,19 +0,0 @@
|
||||
---
|
||||
name: 文档改进
|
||||
about: 报告文档问题或建议改进
|
||||
title: '[文档] 简要描述问题'
|
||||
labels: 'documentation'
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
**文档位置**
|
||||
指出需要改进的文档路径或 URL
|
||||
|
||||
**当前问题**
|
||||
描述当前文档存在的问题或不清晰的地方
|
||||
|
||||
**改进建议**
|
||||
提出具体的改进建议
|
||||
|
||||
**附加信息(可选)**
|
||||
任何其他有助于改进文档的信息
|
||||
45
.github/workflows/github-pages.yml
vendored
Normal file
45
.github/workflows/github-pages.yml
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
name: 构建 Github Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ] # 如果你的主分支叫 master,请改为 master
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: 安装 Nodejs
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 20 # 建议使用 LTS 版本
|
||||
|
||||
- name: 安装 pnpm 并构建前端
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
run_install: true
|
||||
|
||||
- name: 构建前端项目
|
||||
run: pnpm run build
|
||||
|
||||
# 关键步骤:告诉 GitHub Actions 跳过 Jekyll 检查
|
||||
- name: 配置 Github Pages
|
||||
uses: actions/configure-pages@v5
|
||||
|
||||
- name: 上传构建版
|
||||
uses: actions/upload-pages-artifact@v4
|
||||
with:
|
||||
path: './docs'
|
||||
|
||||
- name: 部署到 GitHub Pages
|
||||
uses: actions/deploy-pages@v4
|
||||
3
.github/workflows/ogame-vue-ts.yml
vendored
3
.github/workflows/ogame-vue-ts.yml
vendored
@@ -56,4 +56,5 @@ jobs:
|
||||
${{ vars.DOCKERHUB_USERNAME != '' && format('docker.io/{0}/ogame-vue-ts:latest', vars.DOCKERHUB_USERNAME) || '' }}
|
||||
${{ vars.DOCKERHUB_USERNAME != '' && format('docker.io/{0}/ogame-vue-ts:{1}', vars.DOCKERHUB_USERNAME, github.sha) || '' }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
cache-to: type=gha,mode=max
|
||||
outputs: type=image,name=target,annotation-index.org.opencontainers.image.description=OGame Vue Ts
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -11,6 +11,8 @@ CLAUDE.md
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
dist-electron
|
||||
docs
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
@@ -24,3 +26,5 @@ dist-ssr
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
/docs
|
||||
/docs/assets
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
FROM node:latest AS builder
|
||||
FROM node:lts-alpine AS builder
|
||||
|
||||
RUN mkdir -p /workspace
|
||||
WORKDIR /workspace
|
||||
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
|
||||
RUN apk update && apk add git
|
||||
RUN npm config set registry https://registry.npmmirror.com
|
||||
RUN git clone https://github.com/setube/ogame-vue-ts.git
|
||||
RUN mv ./ogame-vue-ts/* . ; rm -rf ./ogame-vue-ts/
|
||||
|
||||
RUN npm install -g pnpm ; pnpm install;
|
||||
RUN pnpm build
|
||||
RUN pnpm run build
|
||||
|
||||
# --- 第二阶段:Nginx ---
|
||||
FROM nginx:alpine
|
||||
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
@@ -213,13 +213,6 @@ The application supports full theme customization through Tailwind CSS variables
|
||||
|
||||
Contributions are welcome! Please feel free to submit issues or pull requests.
|
||||
|
||||
### Issue Templates
|
||||
We provide the following issue templates in both Chinese and English:
|
||||
- Bug Report
|
||||
- Feature Request
|
||||
- Documentation Improvement
|
||||
- eedback & Suggestion
|
||||
|
||||
## License
|
||||
|
||||
This work is licensed under the [Creative Commons Attribution-NonCommercial 4.0 International License](https://creativecommons.org/licenses/by-nc/4.0/).
|
||||
|
||||
@@ -213,13 +213,6 @@ ogame-vue-ts/
|
||||
|
||||
欢迎贡献!请随时提交 issue 或 pull request。
|
||||
|
||||
### Issue 模板
|
||||
我们提供以下中英文 issue 模板:
|
||||
- BUG反馈 / Bug Report
|
||||
- 功能请求 / Feature Request
|
||||
- 文档改进 / Documentation Improvement
|
||||
- 反馈建议 / Feedback & Suggestion
|
||||
|
||||
## 许可证
|
||||
|
||||
本作品采用 [知识共享署名-非商业性使用 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc/4.0/) 进行许可。
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import { BrowserWindow, app } from "electron";
|
||||
import path, { dirname } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
app.whenReady().then(() => {
|
||||
let i = dirname(fileURLToPath(import.meta.url)), a = new BrowserWindow({
|
||||
title: "OGame",
|
||||
icon: path.join(i, "../public/favicon.ico"),
|
||||
width: 1200,
|
||||
height: 800
|
||||
});
|
||||
a.setMenu(null), process.env.VITE_DEV_SERVER_URL ? a.loadURL(process.env.VITE_DEV_SERVER_URL) : a.loadFile("docs/index.html");
|
||||
});
|
||||
@@ -1 +0,0 @@
|
||||
ogame-vue-ts.wenzi.games
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,7 +0,0 @@
|
||||
import{$t as e,At as t,Ct as n,Dn as r,En as i,Gn as a,Gt as o,Jt as s,Ln as c,Ot as ee,Qt as l,Vt as te,Xn as u,Xt as d,Yn as ne,Yt as f,Zt as p,_ as m,b as h,en as g,g as re,gn as _,jt as ie,kt as ae,m as oe,mn as v,p as se,qn as y,tn as ce,v as le,y as b}from"./game-logic-Bi1l7y4K.js";import"./vendor-pinia-DqhKuBjp.js";import"./vendor-crypto-CQM8pryk.js";import"./game-i18n-Dr0JspcV.js";import"./vendor-others-DTUzJ7S-.js";import"./vendor-reka-ui-BEHIKScj.js";import"./vendor-utils-BlvnUqQX.js";import"./vendor-vueuse-CJcfYqoW.js";import{B as ue,M as x}from"./vendor-icons-z9V6Jdbh.js";import{t as S}from"./CardDescription-BSLS07AU.js";import{d as C,v as de}from"./game-config-CG6z6nnH.js";import{D as fe,H as pe,K as w,N as T,W as E,_ as D,a as O,b as me,c as he,f as k,h as ge,i as A,l as j,o as M,p as N,q as P,r as F,s as I,u as L,v as _e,y as ve}from"./index-BT5w6et-.js";import{t as ye}from"./useGameConfig-b98LOtBY.js";import{t as be}from"./CardUnlockOverlay-DYfgGY6J.js";var xe={key:0,class:`container mx-auto p-4 sm:p-6`},Se={class:`text-2xl sm:text-3xl font-bold mb-4 sm:mb-6`},Ce={class:`mb-4 sm:mb-6 p-3 sm:p-4 bg-muted/50 rounded-lg border`},we={class:`flex items-center justify-between`},Te={class:`text-sm sm:text-base font-medium flex items-center gap-2`},Ee={class:`text-sm sm:text-base font-bold`},De={class:`mt-2`},Oe={class:`w-full bg-background rounded-full h-2.5 sm:h-3 overflow-hidden`},ke={class:`grid grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4`},Ae={class:`mb-2`},je={class:`flex flex-col sm:flex-row sm:justify-between sm:items-start gap-2`},Me={class:`space-y-3`},R={class:`text-xs sm:text-sm space-y-1.5 sm:space-y-2`},Ne={class:`text-muted-foreground mb-1 sm:mb-2`},Pe={class:`space-y-1 sm:space-y-1.5`},Fe={class:`text-xs`},Ie={class:`text-xs sm:text-sm space-y-0.5 sm:space-y-1`},Le={class:`flex items-center gap-1.5 text-muted-foreground`},Re={class:`flex items-center gap-1.5 text-muted-foreground`},ze={key:1,class:`text-xs text-muted-foreground`},Be={class:`flex gap-2 flex-wrap`},Ve={key:0},z=ce({__name:`BuildingsView`,setup(ce){let z=P(),He=fe(),{t:B}=w(),{BUILDINGS:V,TECHNOLOGIES:Ue}=ye(),H=s(()=>z.currentPlanet),U=c(!1),W=c(``),G=c(``),K=c(!1),q=c(``),J=c(null),We=[{key:`metal`},{key:`crystal`},{key:`deuterium`},{key:`darkMatter`}],Ge=s(()=>H.value?Object.values(C).filter(e=>{let t=V.value[e];return H.value.isMoon?t.moonOnly===!0:t.moonOnly!==!0}):[]),Ke=e=>{if(!z.currentPlanet||!m(z.currentPlanet,e,z.player.technologies,z.player.officers).valid)return!1;let t=oe(z.currentPlanet,e,z.player.officers);return z.currentPlanet.buildQueue.push(t),!0},Y=e=>ie(e),qe=e=>{if(!Z(e)){W.value=B(`common.requirementsNotMet`),G.value=Ye(e),U.value=!0;return}Ke(e)||(W.value=B(`buildingsView.upgradeFailed`),G.value=B(`buildingsView.upgradeFailedMessage`),U.value=!0)},X=e=>H.value?.buildings[e]||0,Z=e=>{if(!H.value)return!1;let t=V.value[e],n=b(t,X(e)+1);return!n||Object.keys(n).length===0?!0:le(H.value,z.player.technologies,n)},Je=e=>{if(!H.value)return B(`buildingsView.upgrade`);let t=V.value[e],n=X(e);return t.maxLevel!==void 0&&n>=t.maxLevel?B(`buildingsView.maxLevelReached`):H.value.buildQueue.length>0||Z(e)?B(`buildingsView.upgrade`):B(`buildingsView.requirementsNotMet`)},Ye=e=>{let t=V.value[e],n=b(t,X(e)+1);if(!n||!H.value)return``;let r=[];for(let[e,t]of Object.entries(n))if(Object.values(C).includes(e)){let n=e,i=H.value.buildings[n]||0,a=V.value[n]?.name||n,o=i>=t?`✓`:`✗`;r.push(`${o} ${a}: Lv ${t} (${B(`common.current`)}: Lv ${i})`)}else if(Object.values(de).includes(e)){let n=e,i=z.player.technologies[n]||0,a=Ue.value[n]?.name||n,o=i>=t?`✓`:`✗`;r.push(`${o} ${a}: Lv ${t} (${B(`common.current`)}: Lv ${i})`)}return r.join(`
|
||||
`)},Xe=e=>{if(!H.value)return!1;let t=V.value[e],r=X(e);if(t.maxLevel!==void 0&&r>=t.maxLevel)return!1;let i=n(z.player.officers,Date.now()),a=h(H.value,i.additionalBuildQueue);if(H.value.buildQueue.filter(e=>e.type===`building`||e.type===`demolish`).length>=a||!m(H.value,e,z.player.technologies,z.player.officers).valid)return!1;let o=Q(e,r+1);return H.value.resources.metal>=o.metal&&H.value.resources.crystal>=o.crystal&&H.value.resources.deuterium>=o.deuterium&&H.value.resources.darkMatter>=o.darkMatter},Q=(e,t)=>ee(e,t),Ze=(e,t)=>{if(!H.value)return 0;let r=n(z.player.officers,Date.now()),i=H.value.buildings[C.RoboticsFactory]||0,a=H.value.buildings[C.NaniteFactory]||0;return ae(e,t,r.buildingSpeedBonus,i,a)},Qe=e=>{if(!z.currentPlanet||!re(z.currentPlanet,e,z.player.officers).valid)return!1;let t=se(z.currentPlanet,e,z.player.officers);return z.currentPlanet.buildQueue.push(t),!0},$e=e=>{let t=V.value[e].name,n=$(e);q.value=`${B(`buildingsView.confirmDemolishMessage`)}: ${t}
|
||||
|
||||
${B(`buildingsView.demolishRefund`)}:
|
||||
${B(`resources.metal`)}: ${k(n.metal)}
|
||||
${B(`resources.crystal`)}: ${k(n.crystal)}
|
||||
${B(`resources.deuterium`)}: ${k(n.deuterium)}${n.darkMatter>0?`\n${B(`resources.darkMatter`)}: ${k(n.darkMatter)}`:``}`,J.value=e,K.value=!0},et=()=>{J.value&&(Qe(J.value)||(W.value=B(`buildingsView.demolishFailed`),G.value=B(`buildingsView.demolishFailedMessage`),U.value=!0)),K.value=!1,J.value=null},tt=e=>{if(!H.value||X(e)<=0)return!1;let t=n(z.player.officers,Date.now()),r=h(H.value,t.additionalBuildQueue);return!(H.value.buildQueue.filter(e=>e.type===`building`||e.type===`demolish`).length>=r)},$=e=>t(e,X(e));return(t,n)=>H.value?(v(),l(`div`,xe,[f(`h1`,Se,u(a(B)(`buildingsView.title`)),1),f(`div`,Ce,[f(`div`,we,[f(`div`,Te,[g(a(x),{size:16}),e(` `+u(a(B)(`buildingsView.spaceUsage`))+`: `,1)]),f(`div`,Ee,[f(`span`,{class:y(Y(H.value)>H.value.maxSpace?`text-destructive`:`text-primary`)},u(a(k)(Y(H.value))),3),n[2]||=f(`span`,{class:`text-muted-foreground mx-1`},`/`,-1),f(`span`,null,u(a(k)(H.value.maxSpace)),1)])]),f(`div`,De,[f(`div`,Oe,[f(`div`,{class:y([`h-full transition-all duration-300`,Y(H.value)>H.value.maxSpace?`bg-destructive`:`bg-primary`]),style:ne({width:`${Math.min(Y(H.value)/H.value.maxSpace*100,100)}%`})},null,6)])])]),f(`div`,ke,[(v(!0),l(o,null,_(Ge.value,t=>(v(),d(a(me),{key:t,class:`relative`},{default:i(()=>[g(be,{requirements:a(V)[t].requirements,currentLevel:X(t)},null,8,[`requirements`,`currentLevel`]),g(a(_e),null,{default:i(()=>[f(`div`,Ae,[f(`div`,je,[g(a(D),{class:`text-sm sm:text-base lg:text-lg cursor-pointer hover:text-primary transition-colors underline decoration-dotted underline-offset-4 order-2 sm:order-1`,onClick:e=>a(He).openBuilding(t,X(t))},{default:i(()=>[e(u(a(V)[t].name),1)]),_:2},1032,[`onClick`]),g(a(pe),{variant:`secondary`,class:`text-xs whitespace-nowrap self-start order-1 sm:order-2`},{default:i(()=>[e(` Lv `+u(X(t)),1)]),_:2},1024)])]),g(a(S),{class:`text-xs sm:text-sm`},{default:i(()=>[e(u(a(V)[t].description),1)]),_:2},1024)]),_:2},1024),g(a(ve),null,{default:i(()=>[f(`div`,Me,[f(`div`,R,[f(`p`,Ne,u(a(B)(`buildingsView.upgradeCost`))+`:`,1),f(`div`,Pe,[(v(),l(o,null,_(We,e=>r(f(`div`,{key:e.key,class:`flex items-center gap-1.5 sm:gap-2`},[g(T,{type:e.key,size:`sm`},null,8,[`type`]),f(`span`,Fe,u(a(B)(`resources.${e.key}`))+`:`,1),f(`span`,{class:y([`font-medium text-xs sm:text-sm`,a(ge)(H.value.resources[e.key],Q(t,X(t)+1)[e.key])])},u(a(k)(Q(t,X(t)+1)[e.key])),3)]),[[te,e.key!==`darkMatter`||Q(t,X(t)+1).darkMatter>0]])),64))])]),f(`div`,Ie,[f(`div`,Le,[g(a(ue),{size:14,class:`flex-shrink-0`}),f(`span`,null,u(a(N)(Ze(t,X(t)+1))),1)]),f(`div`,Re,[g(a(x),{size:14,class:`flex-shrink-0`}),f(`span`,null,u(a(V)[t].spaceUsage),1)])]),g(a(E),{onClick:e=>qe(t),disabled:!Xe(t),class:`w-full`},{default:i(()=>[e(u(Je(t)),1)]),_:2},1032,[`onClick`,`disabled`]),X(t)>0?(v(),d(a(E),{key:0,onClick:e=>$e(t),disabled:!tt(t),variant:`destructive`,class:`w-full`},{default:i(()=>[e(u(a(B)(`buildingsView.demolish`)),1)]),_:1},8,[`onClick`,`disabled`])):p(``,!0),X(t)>0?(v(),l(`div`,ze,[f(`p`,null,u(a(B)(`buildingsView.demolishRefund`))+`:`,1),f(`div`,Be,[f(`span`,null,u(a(k)($(t).metal))+` `+u(a(B)(`resources.metal`)),1),f(`span`,null,u(a(k)($(t).crystal))+` `+u(a(B)(`resources.crystal`)),1),f(`span`,null,u(a(k)($(t).deuterium))+` `+u(a(B)(`resources.deuterium`)),1),$(t).darkMatter>0?(v(),l(`span`,Ve,u(a(k)($(t).darkMatter))+` `+u(a(B)(`resources.darkMatter`)),1)):p(``,!0)])])):p(``,!0)])]),_:2},1024)]),_:2},1024))),128))]),g(a(L),{open:U.value,"onUpdate:open":n[0]||=e=>U.value=e},{default:i(()=>[g(a(I),null,{default:i(()=>[g(a(A),null,{default:i(()=>[g(a(F),null,{default:i(()=>[e(u(W.value),1)]),_:1}),g(a(M),{class:`whitespace-pre-line`},{default:i(()=>[e(u(G.value),1)]),_:1})]),_:1}),g(a(O),null,{default:i(()=>[g(a(j),null,{default:i(()=>[e(u(a(B)(`common.confirm`)),1)]),_:1})]),_:1})]),_:1})]),_:1},8,[`open`]),g(a(L),{open:K.value,"onUpdate:open":n[1]||=e=>K.value=e},{default:i(()=>[g(a(I),null,{default:i(()=>[g(a(A),null,{default:i(()=>[g(a(F),null,{default:i(()=>[e(u(a(B)(`buildingsView.confirmDemolish`)),1)]),_:1}),g(a(M),{class:`whitespace-pre-line`},{default:i(()=>[e(u(q.value),1)]),_:1})]),_:1}),g(a(O),null,{default:i(()=>[g(a(he),null,{default:i(()=>[e(u(a(B)(`common.cancel`)),1)]),_:1}),g(a(j),{onClick:et},{default:i(()=>[e(u(a(B)(`common.confirm`)),1)]),_:1})]),_:1})]),_:1})]),_:1},8,[`open`])])):p(``,!0)}});export{z as default};
|
||||
@@ -1 +0,0 @@
|
||||
import{Gn as e,Qt as t,_n as n,mn as r,qn as i,tn as a}from"./game-logic-Bi1l7y4K.js";import{G as o}from"./index-BT5w6et-.js";var s=a({__name:`CardDescription`,props:{class:{}},setup(a){let s=a;return(a,c)=>(r(),t(`p`,{"data-slot":`card-description`,class:i(e(o)(`text-muted-foreground text-sm`,s.class))},[n(a.$slots,`default`)],2))}});export{s as t};
|
||||
@@ -1,2 +0,0 @@
|
||||
import{$t as e,En as t,Gn as n,Jt as r,Ln as i,Qt as a,Xn as o,Yt as s,Zt as c,en as l,mn as u,tn as d,v as f}from"./game-logic-Bi1l7y4K.js";import{D as p}from"./vendor-icons-z9V6Jdbh.js";import{d as m,v as h}from"./game-config-CG6z6nnH.js";import{K as g,W as _,a as v,i as y,l as b,o as x,q as S,r as C,s as w,u as T}from"./index-BT5w6et-.js";import{t as E}from"./useGameConfig-b98LOtBY.js";var D={key:0,class:`absolute inset-0 z-10 bg-background/70 backdrop-blur-[2px] rounded-lg flex items-center justify-center`},O={class:`text-center p-4 space-y-2`},k={class:`flex justify-center`},A={class:`rounded-full bg-muted p-2`},j={class:`text-xs font-medium text-muted-foreground`},M=d({__name:`CardUnlockOverlay`,props:{requirements:{},currentLevel:{}},setup(d){let M=d,N=S(),{t:P}=g(),{BUILDINGS:F,TECHNOLOGIES:I}=E(),L=i(!1),R=i(``),z=i(``),B=r(()=>M.currentLevel!==void 0&&M.currentLevel>0||!M.requirements||!N.currentPlanet?!0:f(N.currentPlanet,N.player.technologies,M.requirements)),V=()=>{if(!M.requirements||!N.currentPlanet)return``;let e=[];for(let[t,n]of Object.entries(M.requirements))if(Object.values(m).includes(t)){let r=t,i=N.currentPlanet.buildings[r]||0,a=F.value[r]?.name||r,o=i>=n?`✓`:`✗`;e.push(`${o} ${a}: Lv ${n} (${P(`common.current`)}: Lv ${i})`)}else if(Object.values(h).includes(t)){let r=t,i=N.player.technologies[r]||0,a=I.value[r]?.name||r,o=i>=n?`✓`:`✗`;e.push(`${o} ${a}: Lv ${n} (${P(`common.current`)}: Lv ${i})`)}return e.join(`
|
||||
`)},H=()=>{R.value=P(`common.requirementsNotMet`),z.value=V(),L.value=!0};return(r,i)=>B.value?c(``,!0):(u(),a(`div`,D,[s(`div`,O,[s(`div`,k,[s(`div`,A,[l(n(p),{size:20,class:`text-muted-foreground`})])]),s(`p`,j,o(n(P)(`common.locked`)),1),l(n(_),{variant:`outline`,size:`sm`,onClick:H,class:`text-xs`},{default:t(()=>[e(o(n(P)(`common.viewRequirements`)),1)]),_:1})]),l(n(T),{open:L.value,"onUpdate:open":i[0]||=e=>L.value=e},{default:t(()=>[l(n(w),null,{default:t(()=>[l(n(y),null,{default:t(()=>[l(n(C),null,{default:t(()=>[e(o(R.value),1)]),_:1}),l(n(x),{class:`whitespace-pre-line`},{default:t(()=>[e(o(z.value),1)]),_:1})]),_:1}),l(n(v),null,{default:t(()=>[l(n(b),null,{default:t(()=>[e(o(n(P)(`common.confirm`)),1)]),_:1})]),_:1})]),_:1})]),_:1},8,[`open`])]))}});export{M as t};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,2 +0,0 @@
|
||||
import{$t as e,Dn as t,En as n,Gn as r,Gt as i,It as a,Jt as o,Ln as s,Qt as c,S as l,Vt as ee,Xn as u,Xt as te,Yt as d,Zt as ne,d as re,en as f,gn as p,mn as m,qn as ie,tn as ae,u as oe,v as h,y as g}from"./game-logic-Bi1l7y4K.js";import"./vendor-pinia-DqhKuBjp.js";import"./vendor-vue-router-1sDnnIWZ.js";import"./vendor-crypto-CQM8pryk.js";import"./game-i18n-Dr0JspcV.js";import"./vendor-others-DTUzJ7S-.js";import"./vendor-reka-ui-BEHIKScj.js";import"./vendor-utils-BlvnUqQX.js";import"./vendor-vueuse-CJcfYqoW.js";import"./vendor-icons-z9V6Jdbh.js";import{t as se}from"./CardDescription-BSLS07AU.js";import{d as _,v}from"./game-config-CG6z6nnH.js";import{D as ce,H as le,K as ue,N as de,W as y,_ as b,a as x,b as S,f as C,h as w,i as T,l as E,o as D,q as O,r as k,s as A,u as j,v as M,y as N}from"./index-BT5w6et-.js";import{t as P}from"./useGameConfig-b98LOtBY.js";import{t as F}from"./CardUnlockOverlay-DYfgGY6J.js";import{t as I}from"./UnlockRequirement-CoWPiUl8.js";var L={key:0,class:`container mx-auto p-4 sm:p-6`},R={class:`text-2xl sm:text-3xl font-bold mb-4 sm:mb-6`},fe={class:`grid grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4`},z={class:`mb-2`},B={class:`flex flex-col sm:flex-row sm:justify-between sm:items-start gap-2`},V={class:`space-y-2.5 sm:space-y-3`},pe={class:`text-xs sm:text-sm space-y-1.5 sm:space-y-2`},me={class:`text-muted-foreground mb-1 sm:mb-2`},he={class:`space-y-1 sm:space-y-1.5`},ge={class:`text-xs`},H=ae({__name:`ResearchView`,setup(ae){let H=O(),_e=ce(),{t:U}=ue(),{TECHNOLOGIES:W,BUILDINGS:ve}=P(),G=o(()=>H.currentPlanet),K=o(()=>H.player),q=s(!1),J=s(``),Y=s(``),ye=[{key:`metal`},{key:`crystal`},{key:`deuterium`},{key:`darkMatter`}],X=e=>{if(!H.currentPlanet||!re(H.currentPlanet,e,H.player.technologies,H.player.researchQueue).valid)return!1;let t=H.player.technologies[e]||0,{queueItem:n}=oe(H.currentPlanet,e,t,H.player.officers,H.player.technologies);return H.player.researchQueue.push(n),!0},Z=e=>{if(!G.value)return!1;let t=W.value[e],n=g(t,Q(e)+1);return!n||Object.keys(n).length===0?!0:h(G.value,H.player.technologies,n)},be=e=>{if(!G.value)return U(`researchView.research`);let t=W.value[e],n=Q(e);if(t.maxLevel!==void 0&&n>=t.maxLevel)return U(`researchView.maxLevelReached`);let r=l(H.player.technologies);return K.value.researchQueue.length>=r||Z(e)?U(`researchView.research`):U(`buildingsView.requirementsNotMet`)},xe=e=>{let t=W.value[e],n=g(t,Q(e)+1);if(!n||!G.value)return``;let r=[];for(let[e,t]of Object.entries(n))if(Object.values(_).includes(e)){let n=e,i=G.value.buildings[n]||0,a=ve.value[n]?.name||n,o=i>=t?`✓`:`✗`;r.push(`${o} ${a}: Lv ${t} (${U(`common.current`)}: Lv ${i})`)}else if(Object.values(v).includes(e)){let n=e,i=H.player.technologies[n]||0,a=W.value[n]?.name||n,o=i>=t?`✓`:`✗`;r.push(`${o} ${a}: Lv ${t} (${U(`common.current`)}: Lv ${i})`)}return r.join(`
|
||||
`)},Se=e=>{if(!Z(e)){J.value=U(`common.requirementsNotMet`),Y.value=xe(e),q.value=!0;return}X(e)||(J.value=U(`researchView.researchFailed`),Y.value=U(`researchView.researchFailedMessage`),q.value=!0)},Q=e=>K.value.technologies[e]||0,Ce=e=>{if(!G.value)return!1;let t=W.value[e],n=Q(e);if(t.maxLevel!==void 0&&n>=t.maxLevel)return!1;let r=l(H.player.technologies);if(K.value.researchQueue.length>=r)return!1;let i=$(e,n+1);return h(G.value,H.player.technologies,t.requirements)&&G.value.resources.metal>=i.metal&&G.value.resources.crystal>=i.crystal&&G.value.resources.deuterium>=i.deuterium&&G.value.resources.darkMatter>=i.darkMatter},$=(e,t)=>a(e,t);return(a,o)=>G.value?(m(),c(`div`,L,[f(I,{"required-building":r(_).ResearchLab,"required-level":1},null,8,[`required-building`]),d(`h1`,R,u(r(U)(`researchView.title`)),1),d(`div`,fe,[(m(!0),c(i,null,p(Object.values(r(v)),a=>(m(),te(r(S),{key:a,class:`relative`},{default:n(()=>[f(F,{requirements:r(W)[a].requirements,currentLevel:Q(a)},null,8,[`requirements`,`currentLevel`]),f(r(M),null,{default:n(()=>[d(`div`,z,[d(`div`,B,[f(r(b),{class:`text-sm sm:text-base lg:text-lg cursor-pointer hover:text-primary transition-colors underline decoration-dotted underline-offset-4 order-2 sm:order-1`,onClick:e=>r(_e).openTechnology(a,Q(a))},{default:n(()=>[e(u(r(W)[a].name),1)]),_:2},1032,[`onClick`]),f(r(le),{variant:`secondary`,class:`text-xs whitespace-nowrap self-start order-1 sm:order-2`},{default:n(()=>[e(` Lv `+u(Q(a)),1)]),_:2},1024)])]),f(r(se),{class:`text-xs sm:text-sm`},{default:n(()=>[e(u(r(W)[a].description),1)]),_:2},1024)]),_:2},1024),f(r(N),null,{default:n(()=>[d(`div`,V,[d(`div`,pe,[d(`p`,me,u(r(U)(`researchView.researchCost`))+`:`,1),d(`div`,he,[(m(),c(i,null,p(ye,e=>t(d(`div`,{key:e.key,class:`flex items-center gap-1.5 sm:gap-2`},[f(de,{type:e.key,size:`sm`},null,8,[`type`]),d(`span`,ge,u(r(U)(`resources.${e.key}`))+`:`,1),d(`span`,{class:ie([`font-medium text-xs sm:text-sm`,r(w)(G.value.resources[e.key],$(a,Q(a)+1)[e.key])])},u(r(C)($(a,Q(a)+1)[e.key])),3)]),[[ee,e.key!==`darkMatter`||$(a,Q(a)+1).darkMatter>0]])),64))])]),f(r(y),{onClick:e=>Se(a),disabled:!Ce(a),class:`w-full`},{default:n(()=>[e(u(be(a)),1)]),_:2},1032,[`onClick`,`disabled`])])]),_:2},1024)]),_:2},1024))),128))]),f(r(j),{open:q.value,"onUpdate:open":o[0]||=e=>q.value=e},{default:n(()=>[f(r(A),null,{default:n(()=>[f(r(T),null,{default:n(()=>[f(r(k),null,{default:n(()=>[e(u(J.value),1)]),_:1}),f(r(D),{class:`whitespace-pre-line`},{default:n(()=>[e(u(Y.value),1)]),_:1})]),_:1}),f(r(x),null,{default:n(()=>[f(r(E),null,{default:n(()=>[e(u(r(U)(`common.confirm`)),1)]),_:1})]),_:1})]),_:1})]),_:1},8,[`open`])])):ne(``,!0)}});export{H as default};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
import{En as e,Gn as t,Jn as n,Xt as r,_n as i,ln as a,mn as o,rn as s,tn as c}from"./game-logic-Bi1l7y4K.js";import{c as l}from"./vendor-others-DTUzJ7S-.js";import{$ as u,c as d,et as f,l as p,s as m,u as h}from"./vendor-reka-ui-BEHIKScj.js";import{G as g}from"./index-BT5w6et-.js";var _=c({__name:`Tabs`,props:{defaultValue:{},orientation:{},dir:{},activationMode:{},modelValue:{},unmountOnHide:{type:Boolean},asChild:{type:Boolean},as:{},class:{}},emits:[`update:modelValue`],setup(c,{emit:d}){let f=c,p=d,m=u(l(f,`class`),p);return(c,l)=>(o(),r(t(h),a({"data-slot":`tabs`},t(m),{class:t(g)(`flex flex-col gap-2`,f.class)}),{default:e(e=>[i(c.$slots,`default`,n(s(e)))]),_:3},16,[`class`]))}}),v=c({__name:`TabsContent`,props:{value:{},forceMount:{type:Boolean},asChild:{type:Boolean},as:{},class:{}},setup(n){let s=n,c=l(s,`class`);return(n,l)=>(o(),r(t(p),a({"data-slot":`tabs-content`,class:t(g)(`flex-1 outline-none`,s.class)},t(c)),{default:e(()=>[i(n.$slots,`default`)]),_:3},16,[`class`]))}}),y=c({__name:`TabsList`,props:{loop:{type:Boolean},asChild:{type:Boolean},as:{},class:{},tabCount:{}},setup(n){let s=n,c=l(s,`class`,`tabCount`);return(l,u)=>(o(),r(t(d),a({"data-slot":`tabs-list`},t(c),{class:t(g)(`bg-muted text-muted-foreground inline-flex w-fit items-center justify-center rounded-lg p-[3px]`,n.tabCount&&n.tabCount>3?n.tabCount>6?`h-[85px] sm:h-9`:`h-[65px] sm:h-9`:`h-9`,s.class)}),{default:e(()=>[i(l.$slots,`default`)]),_:3},16,[`class`]))}}),b=c({__name:`TabsTrigger`,props:{value:{},disabled:{type:Boolean},asChild:{type:Boolean},as:{},class:{}},setup(n){let s=n,c=f(l(s,`class`));return(n,l)=>(o(),r(t(m),a({"data-slot":`tabs-trigger`,class:t(g)(`inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-all`,`text-muted-foreground hover:text-foreground`,`data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-md data-[state=active]:border-border`,`dark:data-[state=active]:bg-background dark:data-[state=active]:text-foreground dark:data-[state=active]:border-border dark:data-[state=active]:shadow-lg`,`focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring focus-visible:ring-[3px] focus-visible:outline-1`,`disabled:pointer-events-none disabled:opacity-50`,`[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4`,s.class)},t(c)),{default:e(()=>[i(n.$slots,`default`)]),_:3},16,[`class`]))}});export{_ as i,y as n,v as r,b as t};
|
||||
@@ -1 +0,0 @@
|
||||
import{En as e,Gn as t,Jn as n,Xt as r,_n as i,mn as a,rn as o,tn as s}from"./game-logic-Bi1l7y4K.js";import{a as c}from"./vendor-reka-ui-BEHIKScj.js";var l=s({__name:`TooltipProvider`,props:{delayDuration:{default:0},skipDelayDuration:{},disableHoverableContent:{type:Boolean},disableClosingTrigger:{type:Boolean},disabled:{type:Boolean},ignoreNonKeyboardFocus:{type:Boolean}},setup(s){let l=s;return(s,u)=>(a(),r(t(c),n(o(l)),{default:e(()=>[i(s.$slots,`default`)]),_:3},16))}});export{l as t};
|
||||
@@ -1 +0,0 @@
|
||||
import{$t as e,En as t,Gn as n,Jt as r,Qt as i,Xn as a,Yt as o,Zt as s,en as c,mn as l,tn as u}from"./game-logic-Bi1l7y4K.js";import{o as d}from"./vendor-vue-router-1sDnnIWZ.js";import{D as f,J as p}from"./vendor-icons-z9V6Jdbh.js";import{t as m}from"./CardDescription-BSLS07AU.js";import{H as h,K as g,W as _,_ as v,b as y,q as b,v as x,y as S}from"./index-BT5w6et-.js";import{t as C}from"./useGameConfig-b98LOtBY.js";var w={key:0,class:`fixed inset-0 z-50 bg-background/80 backdrop-blur-sm flex items-center justify-center p-4`},T={class:`flex justify-center mb-4`},E={class:`rounded-full bg-muted p-4`},D={class:`p-4 bg-muted rounded-lg space-y-2`},O={class:`text-sm font-medium text-center`},k={class:`flex items-center justify-center gap-2`},A={class:`text-base sm:text-lg font-bold`},j={key:0,class:`text-xs text-center text-muted-foreground`},M={class:`flex gap-2`},N=u({__name:`UnlockRequirement`,props:{requiredBuilding:{},requiredLevel:{}},setup(u){let N=u,P=d(),F=b(),{t:I}=g(),{BUILDINGS:L}=C(),R=r(()=>L.value[N.requiredBuilding]?.name||N.requiredBuilding),z=r(()=>F.currentPlanet&&F.currentPlanet.buildings[N.requiredBuilding]||0),B=r(()=>z.value>=N.requiredLevel),V=()=>{P.push(`/buildings`)};return(r,d)=>B.value?s(``,!0):(l(),i(`div`,w,[c(n(y),{class:`max-w-md w-full`},{default:t(()=>[c(n(x),{class:`text-center`},{default:t(()=>[o(`div`,T,[o(`div`,E,[c(n(f),{size:48,class:`text-muted-foreground`})])]),c(n(v),{class:`text-xl sm:text-2xl`},{default:t(()=>[e(a(n(I)(`common.featureLocked`)),1)]),_:1}),c(n(m),{class:`text-sm sm:text-base`},{default:t(()=>[e(a(n(I)(`common.unlockRequired`)),1)]),_:1})]),_:1}),c(n(S),{class:`space-y-4`},{default:t(()=>[o(`div`,D,[o(`p`,O,a(n(I)(`common.requiredBuilding`))+`:`,1),o(`div`,k,[o(`span`,A,a(R.value),1),c(n(h),{variant:`default`},{default:t(()=>[e(`Lv `+a(u.requiredLevel),1)]),_:1})]),z.value===void 0?s(``,!0):(l(),i(`p`,j,a(n(I)(`common.currentLevel`))+`: Lv `+a(z.value),1))]),o(`div`,M,[c(n(_),{onClick:V,class:`flex-1`},{default:t(()=>[c(n(p),{size:16,class:`mr-2`}),e(` `+a(n(I)(`common.goToBuildings`)),1)]),_:1})])]),_:1})]),_:1})]))}});export{N as t};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 12 KiB |
@@ -1 +0,0 @@
|
||||
var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),s=e=>{let n={};for(var r in e)t(n,r,{get:e[r],enumerable:!0});return n},c=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},l=(n,r,a)=>(a=n==null?{}:e(i(n)),c(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n)),u=(e=>typeof require<`u`?require:typeof Proxy<`u`?new Proxy(e,{get:(e,t)=>(typeof require<`u`?require:e)[t]}):e)(function(e){if(typeof require<`u`)return require.apply(this,arguments);throw Error('Calling `require` for "'+e+"\" in an environment that doesn't expose the `require` function.")});export{l as i,s as n,u as r,o as t};
|
||||
@@ -1 +0,0 @@
|
||||
import{Jt as e}from"./game-logic-Bi1l7y4K.js";import{_ as t,d as n,f as r,h as i,l as a,n as o,r as s,s as c,u as l,v as u}from"./game-config-CG6z6nnH.js";import{K as d}from"./index-BT5w6et-.js";const f=()=>{let{t:f}=d(),p={[n.MetalMine]:`metalMine`,[n.CrystalMine]:`crystalMine`,[n.DeuteriumSynthesizer]:`deuteriumSynthesizer`,[n.SolarPlant]:`solarPlant`,[n.FusionReactor]:`fusionReactor`,[n.RoboticsFactory]:`roboticsFactory`,[n.NaniteFactory]:`naniteFactory`,[n.Shipyard]:`shipyard`,[n.ResearchLab]:`researchLab`,[n.MetalStorage]:`metalStorage`,[n.CrystalStorage]:`crystalStorage`,[n.DeuteriumTank]:`deuteriumTank`,[n.DarkMatterCollector]:`darkMatterCollector`,[n.DarkMatterTank]:`darkMatterTank`,[n.MissileSilo]:`missileSilo`,[n.Terraformer]:`terraformer`,[n.LunarBase]:`lunarBase`,[n.SensorPhalanx]:`sensorPhalanx`,[n.JumpGate]:`jumpGate`,[n.PlanetDestroyerFactory]:`planetDestroyerFactory`},m={[t.LightFighter]:`lightFighter`,[t.HeavyFighter]:`heavyFighter`,[t.Cruiser]:`cruiser`,[t.Battleship]:`battleship`,[t.Battlecruiser]:`battlecruiser`,[t.Bomber]:`bomber`,[t.Destroyer]:`destroyer`,[t.SmallCargo]:`smallCargo`,[t.LargeCargo]:`largeCargo`,[t.ColonyShip]:`colonyShip`,[t.Recycler]:`recycler`,[t.EspionageProbe]:`espionageProbe`,[t.SolarSatellite]:`solarSatellite`,[t.DarkMatterHarvester]:`darkMatterHarvester`,[t.Deathstar]:`deathstar`},h={[r.RocketLauncher]:`rocketLauncher`,[r.LightLaser]:`lightLaser`,[r.HeavyLaser]:`heavyLaser`,[r.GaussCannon]:`gaussCannon`,[r.IonCannon]:`ionCannon`,[r.PlasmaTurret]:`plasmaTurret`,[r.SmallShieldDome]:`smallShieldDome`,[r.LargeShieldDome]:`largeShieldDome`,[r.AntiBallisticMissile]:`antiBallisticMissile`,[r.InterplanetaryMissile]:`interplanetaryMissile`,[r.PlanetaryShield]:`planetaryShield`},g={[u.EnergyTechnology]:`energyTechnology`,[u.LaserTechnology]:`laserTechnology`,[u.IonTechnology]:`ionTechnology`,[u.HyperspaceTechnology]:`hyperspaceTechnology`,[u.PlasmaTechnology]:`plasmaTechnology`,[u.ComputerTechnology]:`computerTechnology`,[u.EspionageTechnology]:`espionageTechnology`,[u.WeaponsTechnology]:`weaponsTechnology`,[u.ShieldingTechnology]:`shieldingTechnology`,[u.ArmourTechnology]:`armourTechnology`,[u.Astrophysics]:`astrophysics`,[u.GravitonTechnology]:`gravitonTechnology`,[u.CombustionDrive]:`combustionDrive`,[u.ImpulseDrive]:`impulseDrive`,[u.HyperspaceDrive]:`hyperspaceDrive`,[u.DarkMatterTechnology]:`darkMatterTechnology`,[u.TerraformingTechnology]:`terraformingTechnology`,[u.PlanetDestructionTech]:`planetDestructionTech`},_={[i.Commander]:`commander`,[i.Admiral]:`admiral`,[i.Engineer]:`engineer`,[i.Geologist]:`geologist`,[i.Technocrat]:`technocrat`,[i.DarkMatterSpecialist]:`darkMatterSpecialist`};return{BUILDINGS:e(()=>{let e={};for(let[t,n]of Object.entries(o)){let r=t,i=p[r];e[r]={...n,name:f(`buildings.${i}`),description:f(`buildingDescriptions.${i}`)}}return e}),SHIPS:e(()=>{let e={};for(let[t,n]of Object.entries(a)){let r=t,i=m[r];e[r]={...n,name:f(`ships.${i}`),description:f(`shipDescriptions.${i}`)}}return e}),DEFENSES:e(()=>{let e={};for(let[t,n]of Object.entries(s)){let r=t,i=h[r];e[r]={...n,name:f(`defenses.${i}`),description:f(`defenseDescriptions.${i}`)}}return e}),TECHNOLOGIES:e(()=>{let e={};for(let[t,n]of Object.entries(l)){let r=t,i=g[r];e[r]={...n,name:f(`technologies.${i}`),description:f(`technologyDescriptions.${i}`)}}return e}),OFFICERS:e(()=>{let e={};for(let[t,n]of Object.entries(c)){let r=t,i=_[r];e[r]={...n,name:f(`officers.${i}`),description:f(`officerDescriptions.${i}`)}}return e})}};export{f as t};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
import{Bn as e,Cn as t,Gn as n,Jt as r,Ln as i,Wn as a,an as o,fn as s,nn as c,un as l,wn as u}from"./game-logic-Bi1l7y4K.js";import{a as d,i as f,l as p,o as m,r as h,s as g,u as _}from"./vendor-others-DTUzJ7S-.js";var v=f?window:void 0,y=f?window.document:void 0;f&&window.navigator,f&&window.location;function b(e){let t=a(e);return t?.$el??t}function x(...e){let t=(e,t,n,r)=>(e.addEventListener(t,n,r),()=>e.removeEventListener(t,n,r)),i=r(()=>{let t=p(a(e[0])).filter(e=>e!=null);return t.every(e=>typeof e!=`string`)?t:void 0});return _(()=>[i.value?.map(e=>b(e))??[v].filter(e=>e!=null),p(a(i.value?e[1]:e[0])),p(n(i.value?e[2]:e[1])),a(i.value?e[3]:e[2])],([e,n,r,i],a,o)=>{if(!e?.length||!n?.length||!r?.length)return;let s=m(i)?{...i}:i,c=e.flatMap(e=>n.flatMap(n=>r.map(r=>t(e,n,r,s))));o(()=>{c.forEach(e=>e())})},{flush:`post`})}function S(){let t=e(!1),n=c();return n&&s(()=>{t.value=!0},n),t}function C(e){let t=S();return r(()=>(t.value,!!e()))}var w=Symbol(`vueuse-ssr-width`);function T(){let e=o()?h(w,null):null;return typeof e==`number`?e:void 0}function E(t,n={}){let{window:i=v,ssrWidth:o=T()}=n,s=C(()=>i&&`matchMedia`in i&&typeof i.matchMedia==`function`),c=e(typeof o==`number`),l=e(),d=e(!1);return u(()=>{if(c.value){c.value=!s.value,d.value=a(t).split(`,`).some(e=>{let t=e.includes(`not all`),n=e.match(/\(\s*min-width:\s*(-?\d+(?:\.\d*)?[a-z]+\s*)\)/),r=e.match(/\(\s*max-width:\s*(-?\d+(?:\.\d*)?[a-z]+\s*)\)/),i=!!(n||r);return n&&i&&(i=o>=g(n[1])),r&&i&&(i=o<=g(r[1])),t?!i:i});return}s.value&&(l.value=i.matchMedia(a(t)),d.value=l.value.matches)}),x(l,`change`,e=>{d.value=e.matches},{passive:!0}),r(()=>d.value)}function D(e){return JSON.parse(JSON.stringify(e))}function O(e,n,a,o={}){var s,u;let{clone:f=!1,passive:p=!1,eventName:m,deep:h=!1,defaultValue:g,shouldEmit:_}=o,v=c(),y=a||v?.emit||(v==null||(s=v.$emit)==null?void 0:s.bind(v))||(v==null||(u=v.proxy)==null||(u=u.$emit)==null?void 0:u.bind(v?.proxy)),b=m;n||=`modelValue`,b||=`update:${n.toString()}`;let x=e=>f?typeof f==`function`?f(e):D(e):e,S=()=>d(e[n])?x(e[n]):g,C=e=>{_?_(e)&&y(b,e):y(b,e)};if(p){let r=i(S()),a=!1;return t(()=>e[n],e=>{a||(a=!0,r.value=x(e),l(()=>a=!1))}),t(r,t=>{!a&&(t!==e[n]||h)&&C(t)},{deep:h}),r}else return r({get(){return S()},set(e){C(e)}})}export{O as i,x as n,E as r,y as t};
|
||||
BIN
docs/favicon.ico
BIN
docs/favicon.ico
Binary file not shown.
|
Before Width: | Height: | Size: 227 KiB |
@@ -1,34 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-cmn-Hans">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover" />
|
||||
<link rel="icon" type="image/svg+xml" href="./logo.svg" />
|
||||
<title>OGame-Vue-Ts</title>
|
||||
<script type="module" crossorigin src="./assets/index-BT5w6et-.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="./assets/game-config-CG6z6nnH.js">
|
||||
<link rel="modulepreload" crossorigin href="./assets/rolldown-runtime-CIDIeb-o.js">
|
||||
<link rel="modulepreload" crossorigin href="./assets/game-logic-Bi1l7y4K.js">
|
||||
<link rel="modulepreload" crossorigin href="./assets/vendor-others-DTUzJ7S-.js">
|
||||
<link rel="modulepreload" crossorigin href="./assets/vendor-reka-ui-BEHIKScj.js">
|
||||
<link rel="modulepreload" crossorigin href="./assets/vendor-vueuse-CJcfYqoW.js">
|
||||
<link rel="modulepreload" crossorigin href="./assets/vendor-crypto-CQM8pryk.js">
|
||||
<link rel="modulepreload" crossorigin href="./assets/vendor-utils-BlvnUqQX.js">
|
||||
<link rel="modulepreload" crossorigin href="./assets/vendor-icons-z9V6Jdbh.js">
|
||||
<link rel="modulepreload" crossorigin href="./assets/vendor-pinia-DqhKuBjp.js">
|
||||
<link rel="modulepreload" crossorigin href="./assets/vendor-vue-router-1sDnnIWZ.js">
|
||||
<link rel="modulepreload" crossorigin href="./assets/game-i18n-Dr0JspcV.js">
|
||||
<link rel="stylesheet" crossorigin href="./assets/vendor-others-BMPyaZWq.css">
|
||||
<link rel="stylesheet" crossorigin href="./assets/index-D0T1QtIu.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
<!-- 统计勿删 -->
|
||||
<script charset="UTF-8" id="LA_COLLECT" src="https://sdk.51.la/js-sdk-pro.min.js"></script>
|
||||
<script>LA.init({ id: "L298GYqn6JhAO0VU", ck: "L298GYqn6JhAO0VU", autoTrack: true, hashMode: true })</script>
|
||||
</body>
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 12 KiB |
2
package-lock.json
generated
2
package-lock.json
generated
@@ -8187,4 +8187,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
13
package.json
13
package.json
@@ -8,8 +8,8 @@
|
||||
"email": "1962257451@qq.com"
|
||||
},
|
||||
"private": true,
|
||||
"version": "1.2.0",
|
||||
"buildDate": "2025/12/15 08:22:52",
|
||||
"version": "1.4.0",
|
||||
"buildDate": "2025/12/19 12:29:46",
|
||||
"main": "dist-electron/main.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
@@ -23,17 +23,16 @@
|
||||
"@tailwindcss/vite": "^4.1.17",
|
||||
"@tanstack/vue-table": "^8.21.3",
|
||||
"@vueuse/core": "^14.1.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"crypto-js": "^4.2.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"finalhandler": "^2.1.1",
|
||||
"lucide-vue-next": "^0.556.0",
|
||||
"marked": "^17.0.1",
|
||||
"motion-v": "^1.7.4",
|
||||
"pinia": "^3.0.4",
|
||||
"pinia-plugin-persistedstate": "^4.7.1",
|
||||
"reka-ui": "^2.6.1",
|
||||
"serve-static": "^2.2.0",
|
||||
"tailwind-merge": "^3.4.0",
|
||||
"tailwindcss": "^4.1.17",
|
||||
"vue": "^3.5.24",
|
||||
"vue-router": "4",
|
||||
@@ -45,15 +44,19 @@
|
||||
"@types/node": "^24.10.2",
|
||||
"@vitejs/plugin-vue": "^6.0.1",
|
||||
"@vue/tsconfig": "^0.8.1",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"electron": "^39.2.7",
|
||||
"electron-builder": "^26.0.12",
|
||||
"electron-vite": "^5.0.0",
|
||||
"tailwind-merge": "^3.4.0",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"typescript": "~5.9.3",
|
||||
"vite": "npm:rolldown-vite@7.2.5",
|
||||
"vite-plugin-electron": "^0.29.0",
|
||||
"vite-plugin-electron-renderer": "^0.14.6",
|
||||
"vite-plugin-pwa": "^1.2.0",
|
||||
"vue-tsc": "^3.1.4"
|
||||
},
|
||||
"pnpm": {
|
||||
|
||||
2962
pnpm-lock.yaml
generated
2962
pnpm-lock.yaml
generated
@@ -20,12 +20,6 @@ importers:
|
||||
'@vueuse/core':
|
||||
specifier: ^14.1.0
|
||||
version: 14.1.0(vue@3.5.25(typescript@5.9.3))
|
||||
class-variance-authority:
|
||||
specifier: ^0.7.1
|
||||
version: 0.7.1
|
||||
clsx:
|
||||
specifier: ^2.1.1
|
||||
version: 2.1.1
|
||||
crypto-js:
|
||||
specifier: ^4.2.0
|
||||
version: 4.2.0
|
||||
@@ -38,6 +32,12 @@ importers:
|
||||
lucide-vue-next:
|
||||
specifier: ^0.556.0
|
||||
version: 0.556.0(vue@3.5.25(typescript@5.9.3))
|
||||
marked:
|
||||
specifier: ^17.0.1
|
||||
version: 17.0.1
|
||||
motion-v:
|
||||
specifier: ^1.7.4
|
||||
version: 1.7.4(@vueuse/core@14.1.0(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))
|
||||
pinia:
|
||||
specifier: ^3.0.4
|
||||
version: 3.0.4(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))
|
||||
@@ -50,9 +50,6 @@ importers:
|
||||
serve-static:
|
||||
specifier: ^2.2.0
|
||||
version: 2.2.0
|
||||
tailwind-merge:
|
||||
specifier: ^3.4.0
|
||||
version: 3.4.0
|
||||
tailwindcss:
|
||||
specifier: ^4.1.17
|
||||
version: 4.1.17
|
||||
@@ -81,6 +78,12 @@ importers:
|
||||
'@vue/tsconfig':
|
||||
specifier: ^0.8.1
|
||||
version: 0.8.1(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))
|
||||
class-variance-authority:
|
||||
specifier: ^0.7.1
|
||||
version: 0.7.1
|
||||
clsx:
|
||||
specifier: ^2.1.1
|
||||
version: 2.1.1
|
||||
cross-env:
|
||||
specifier: ^7.0.3
|
||||
version: 7.0.3
|
||||
@@ -93,6 +96,9 @@ importers:
|
||||
electron-vite:
|
||||
specifier: ^5.0.0
|
||||
version: 5.0.0(rolldown-vite@7.2.5(@types/node@24.10.2)(esbuild@0.25.12)(jiti@2.6.1)(terser@5.44.1))
|
||||
tailwind-merge:
|
||||
specifier: ^3.4.0
|
||||
version: 3.4.0
|
||||
tw-animate-css:
|
||||
specifier: ^1.4.0
|
||||
version: 1.4.0
|
||||
@@ -108,6 +114,9 @@ importers:
|
||||
vite-plugin-electron-renderer:
|
||||
specifier: ^0.14.6
|
||||
version: 0.14.6
|
||||
vite-plugin-pwa:
|
||||
specifier: ^1.2.0
|
||||
version: 1.2.0(@vite-pwa/assets-generator@1.0.2)(rolldown-vite@7.2.5(@types/node@24.10.2)(esbuild@0.25.12)(jiti@2.6.1)(terser@5.44.1))(workbox-build@7.4.0)(workbox-window@7.4.0)
|
||||
vue-tsc:
|
||||
specifier: ^3.1.4
|
||||
version: 3.1.8(typescript@5.9.3)
|
||||
@@ -117,6 +126,12 @@ packages:
|
||||
7zip-bin@5.2.0:
|
||||
resolution: {integrity: sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==}
|
||||
|
||||
'@apideck/better-ajv-errors@0.3.6':
|
||||
resolution: {integrity: sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==}
|
||||
engines: {node: '>=10'}
|
||||
peerDependencies:
|
||||
ajv: '>=8'
|
||||
|
||||
'@babel/code-frame@7.27.1':
|
||||
resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
@@ -133,14 +148,39 @@ packages:
|
||||
resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-annotate-as-pure@7.27.3':
|
||||
resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-compilation-targets@7.27.2':
|
||||
resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-create-class-features-plugin@7.28.5':
|
||||
resolution: {integrity: sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0
|
||||
|
||||
'@babel/helper-create-regexp-features-plugin@7.28.5':
|
||||
resolution: {integrity: sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0
|
||||
|
||||
'@babel/helper-define-polyfill-provider@0.6.5':
|
||||
resolution: {integrity: sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
|
||||
|
||||
'@babel/helper-globals@7.28.0':
|
||||
resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-member-expression-to-functions@7.28.5':
|
||||
resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-module-imports@7.27.1':
|
||||
resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
@@ -151,10 +191,30 @@ packages:
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0
|
||||
|
||||
'@babel/helper-optimise-call-expression@7.27.1':
|
||||
resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-plugin-utils@7.27.1':
|
||||
resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-remap-async-to-generator@7.27.1':
|
||||
resolution: {integrity: sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0
|
||||
|
||||
'@babel/helper-replace-supers@7.27.1':
|
||||
resolution: {integrity: sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0
|
||||
|
||||
'@babel/helper-skip-transparent-expression-wrappers@7.27.1':
|
||||
resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-string-parser@7.27.1':
|
||||
resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
@@ -167,6 +227,10 @@ packages:
|
||||
resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-wrap-function@7.28.3':
|
||||
resolution: {integrity: sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helpers@7.28.4':
|
||||
resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
@@ -176,12 +240,381 @@ packages:
|
||||
engines: {node: '>=6.0.0'}
|
||||
hasBin: true
|
||||
|
||||
'@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5':
|
||||
resolution: {integrity: sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0
|
||||
|
||||
'@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1':
|
||||
resolution: {integrity: sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0
|
||||
|
||||
'@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1':
|
||||
resolution: {integrity: sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0
|
||||
|
||||
'@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1':
|
||||
resolution: {integrity: sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.13.0
|
||||
|
||||
'@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3':
|
||||
resolution: {integrity: sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0
|
||||
|
||||
'@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2':
|
||||
resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-syntax-import-assertions@7.27.1':
|
||||
resolution: {integrity: sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-syntax-import-attributes@7.27.1':
|
||||
resolution: {integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-syntax-unicode-sets-regex@7.18.6':
|
||||
resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0
|
||||
|
||||
'@babel/plugin-transform-arrow-functions@7.27.1':
|
||||
resolution: {integrity: sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-async-generator-functions@7.28.0':
|
||||
resolution: {integrity: sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-async-to-generator@7.27.1':
|
||||
resolution: {integrity: sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-block-scoped-functions@7.27.1':
|
||||
resolution: {integrity: sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-block-scoping@7.28.5':
|
||||
resolution: {integrity: sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-class-properties@7.27.1':
|
||||
resolution: {integrity: sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-class-static-block@7.28.3':
|
||||
resolution: {integrity: sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.12.0
|
||||
|
||||
'@babel/plugin-transform-classes@7.28.4':
|
||||
resolution: {integrity: sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-computed-properties@7.27.1':
|
||||
resolution: {integrity: sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-destructuring@7.28.5':
|
||||
resolution: {integrity: sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-dotall-regex@7.27.1':
|
||||
resolution: {integrity: sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-duplicate-keys@7.27.1':
|
||||
resolution: {integrity: sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1':
|
||||
resolution: {integrity: sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0
|
||||
|
||||
'@babel/plugin-transform-dynamic-import@7.27.1':
|
||||
resolution: {integrity: sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-explicit-resource-management@7.28.0':
|
||||
resolution: {integrity: sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-exponentiation-operator@7.28.5':
|
||||
resolution: {integrity: sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-export-namespace-from@7.27.1':
|
||||
resolution: {integrity: sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-for-of@7.27.1':
|
||||
resolution: {integrity: sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-function-name@7.27.1':
|
||||
resolution: {integrity: sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-json-strings@7.27.1':
|
||||
resolution: {integrity: sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-literals@7.27.1':
|
||||
resolution: {integrity: sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-logical-assignment-operators@7.28.5':
|
||||
resolution: {integrity: sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-member-expression-literals@7.27.1':
|
||||
resolution: {integrity: sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-modules-amd@7.27.1':
|
||||
resolution: {integrity: sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-modules-commonjs@7.27.1':
|
||||
resolution: {integrity: sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-modules-systemjs@7.28.5':
|
||||
resolution: {integrity: sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-modules-umd@7.27.1':
|
||||
resolution: {integrity: sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-named-capturing-groups-regex@7.27.1':
|
||||
resolution: {integrity: sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0
|
||||
|
||||
'@babel/plugin-transform-new-target@7.27.1':
|
||||
resolution: {integrity: sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-nullish-coalescing-operator@7.27.1':
|
||||
resolution: {integrity: sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-numeric-separator@7.27.1':
|
||||
resolution: {integrity: sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-object-rest-spread@7.28.4':
|
||||
resolution: {integrity: sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-object-super@7.27.1':
|
||||
resolution: {integrity: sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-optional-catch-binding@7.27.1':
|
||||
resolution: {integrity: sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-optional-chaining@7.28.5':
|
||||
resolution: {integrity: sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-parameters@7.27.7':
|
||||
resolution: {integrity: sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-private-methods@7.27.1':
|
||||
resolution: {integrity: sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-private-property-in-object@7.27.1':
|
||||
resolution: {integrity: sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-property-literals@7.27.1':
|
||||
resolution: {integrity: sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-regenerator@7.28.4':
|
||||
resolution: {integrity: sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-regexp-modifiers@7.27.1':
|
||||
resolution: {integrity: sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0
|
||||
|
||||
'@babel/plugin-transform-reserved-words@7.27.1':
|
||||
resolution: {integrity: sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-shorthand-properties@7.27.1':
|
||||
resolution: {integrity: sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-spread@7.27.1':
|
||||
resolution: {integrity: sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-sticky-regex@7.27.1':
|
||||
resolution: {integrity: sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-template-literals@7.27.1':
|
||||
resolution: {integrity: sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-typeof-symbol@7.27.1':
|
||||
resolution: {integrity: sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-unicode-escapes@7.27.1':
|
||||
resolution: {integrity: sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-unicode-property-regex@7.27.1':
|
||||
resolution: {integrity: sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-unicode-regex@7.27.1':
|
||||
resolution: {integrity: sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-unicode-sets-regex@7.27.1':
|
||||
resolution: {integrity: sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0
|
||||
|
||||
'@babel/preset-env@7.28.5':
|
||||
resolution: {integrity: sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/preset-modules@0.1.6-no-external-plugins':
|
||||
resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0
|
||||
|
||||
'@babel/runtime@7.28.4':
|
||||
resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/template@7.27.2':
|
||||
resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
@@ -194,6 +627,9 @@ packages:
|
||||
resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@canvas/image-data@1.1.0':
|
||||
resolution: {integrity: sha512-QdObRRjRbcXGmM1tmJ+MrHcaz1MftF2+W7YI+MsphnsCrmtyfS0d5qJbk0MeSbUeyM/jCb0hmnkXPsy026L7dA==}
|
||||
|
||||
'@develar/schema-utils@2.6.5':
|
||||
resolution: {integrity: sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==}
|
||||
engines: {node: '>= 8.9.0'}
|
||||
@@ -425,6 +861,123 @@ packages:
|
||||
'@gar/promisify@1.1.3':
|
||||
resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==}
|
||||
|
||||
'@img/sharp-darwin-arm64@0.33.5':
|
||||
resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@img/sharp-darwin-x64@0.33.5':
|
||||
resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@img/sharp-libvips-darwin-arm64@1.0.4':
|
||||
resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@img/sharp-libvips-darwin-x64@1.0.4':
|
||||
resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@img/sharp-libvips-linux-arm64@1.0.4':
|
||||
resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-arm@1.0.5':
|
||||
resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-s390x@1.0.4':
|
||||
resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-x64@1.0.4':
|
||||
resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-arm64@1.0.4':
|
||||
resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-x64@1.0.4':
|
||||
resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-linux-arm64@0.33.5':
|
||||
resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-arm@0.33.5':
|
||||
resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-s390x@0.33.5':
|
||||
resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-x64@0.33.5':
|
||||
resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linuxmusl-arm64@0.33.5':
|
||||
resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-linuxmusl-x64@0.33.5':
|
||||
resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-wasm32@0.33.5':
|
||||
resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [wasm32]
|
||||
|
||||
'@img/sharp-win32-ia32@0.33.5':
|
||||
resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@img/sharp-win32-x64@0.33.5':
|
||||
resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@internationalized/date@3.10.0':
|
||||
resolution: {integrity: sha512-oxDR/NTEJ1k+UFVQElaNIk65E/Z83HK1z1WI3lQyhTtnNg4R5oVXaPzK3jcpKG8UHKDVuDQHzn+wsxSz8RP3aw==}
|
||||
|
||||
@@ -493,6 +1046,9 @@ packages:
|
||||
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
'@quansync/fs@1.0.0':
|
||||
resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==}
|
||||
|
||||
'@rolldown/binding-android-arm64@1.0.0-beta.50':
|
||||
resolution: {integrity: sha512-XlEkrOIHLyGT3avOgzfTFSjG+f+dZMw+/qd+Y3HLN86wlndrB/gSimrJCk4gOhr1XtRtEKfszpadI3Md4Z4/Ag==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -583,10 +1139,62 @@ packages:
|
||||
'@rolldown/pluginutils@1.0.0-beta.50':
|
||||
resolution: {integrity: sha512-5e76wQiQVeL1ICOZVUg4LSOVYg9jyhGCin+icYozhsUzM+fHE7kddi1bdiE0jwVqTfkjba3jUFbEkoC9WkdvyA==}
|
||||
|
||||
'@rollup/plugin-babel@5.3.1':
|
||||
resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0
|
||||
'@types/babel__core': ^7.1.9
|
||||
rollup: ^1.20.0||^2.0.0
|
||||
peerDependenciesMeta:
|
||||
'@types/babel__core':
|
||||
optional: true
|
||||
|
||||
'@rollup/plugin-node-resolve@15.3.1':
|
||||
resolution: {integrity: sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
rollup: ^2.78.0||^3.0.0||^4.0.0
|
||||
peerDependenciesMeta:
|
||||
rollup:
|
||||
optional: true
|
||||
|
||||
'@rollup/plugin-replace@2.4.2':
|
||||
resolution: {integrity: sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==}
|
||||
peerDependencies:
|
||||
rollup: ^1.20.0 || ^2.0.0
|
||||
|
||||
'@rollup/plugin-terser@0.4.4':
|
||||
resolution: {integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
rollup: ^2.0.0||^3.0.0||^4.0.0
|
||||
peerDependenciesMeta:
|
||||
rollup:
|
||||
optional: true
|
||||
|
||||
'@rollup/pluginutils@3.1.0':
|
||||
resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==}
|
||||
engines: {node: '>= 8.0.0'}
|
||||
peerDependencies:
|
||||
rollup: ^1.20.0||^2.0.0
|
||||
|
||||
'@rollup/pluginutils@5.3.0':
|
||||
resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
|
||||
peerDependenciesMeta:
|
||||
rollup:
|
||||
optional: true
|
||||
|
||||
'@sindresorhus/is@4.6.0':
|
||||
resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
'@surma/rollup-plugin-off-main-thread@2.2.3':
|
||||
resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==}
|
||||
|
||||
'@swc/helpers@0.5.17':
|
||||
resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==}
|
||||
|
||||
@@ -722,6 +1330,12 @@ packages:
|
||||
'@types/debug@4.1.12':
|
||||
resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
|
||||
|
||||
'@types/estree@0.0.39':
|
||||
resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==}
|
||||
|
||||
'@types/estree@1.0.8':
|
||||
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
||||
|
||||
'@types/file-saver@2.0.7':
|
||||
resolution: {integrity: sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==}
|
||||
|
||||
@@ -746,9 +1360,15 @@ packages:
|
||||
'@types/plist@3.0.5':
|
||||
resolution: {integrity: sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==}
|
||||
|
||||
'@types/resolve@1.20.2':
|
||||
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
|
||||
|
||||
'@types/responselike@1.0.3':
|
||||
resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==}
|
||||
|
||||
'@types/trusted-types@2.0.7':
|
||||
resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
|
||||
|
||||
'@types/verror@1.10.11':
|
||||
resolution: {integrity: sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==}
|
||||
|
||||
@@ -758,6 +1378,11 @@ packages:
|
||||
'@types/yauzl@2.10.3':
|
||||
resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==}
|
||||
|
||||
'@vite-pwa/assets-generator@1.0.2':
|
||||
resolution: {integrity: sha512-MCbrb508JZHqe7bUibmZj/lyojdhLRnfkmyXnkrCM2zVrjTgL89U8UEfInpKTvPeTnxsw2hmyZxnhsdNR6yhwg==}
|
||||
engines: {node: '>=16.14.0'}
|
||||
hasBin: true
|
||||
|
||||
'@vitejs/plugin-vue@6.0.2':
|
||||
resolution: {integrity: sha512-iHmwV3QcVGGvSC1BG5bZ4z6iwa1SOpAPWmnjOErd4Ske+lZua5K9TtAVdx0gMBClJ28DViCbSmZitjWZsWO3LA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -892,6 +1517,9 @@ packages:
|
||||
ajv@6.12.6:
|
||||
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
|
||||
|
||||
ajv@8.17.1:
|
||||
resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
|
||||
|
||||
alien-signals@3.1.1:
|
||||
resolution: {integrity: sha512-ogkIWbVrLwKtHY6oOAXaYkAxP+cTH7V5FZ5+Tm4NZFd8VDZ6uNMDrfzqctTZ42eTMCSR3ne3otpcxmqSnFfPYA==}
|
||||
|
||||
@@ -928,6 +1556,14 @@ packages:
|
||||
resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
array-buffer-byte-length@1.0.2:
|
||||
resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
arraybuffer.prototype.slice@1.0.4:
|
||||
resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
assert-plus@1.0.0:
|
||||
resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==}
|
||||
engines: {node: '>=0.8'}
|
||||
@@ -940,6 +1576,10 @@ packages:
|
||||
resolution: {integrity: sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==}
|
||||
engines: {node: '>=0.12.0'}
|
||||
|
||||
async-function@1.0.0:
|
||||
resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
async@3.2.6:
|
||||
resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
|
||||
|
||||
@@ -950,6 +1590,25 @@ packages:
|
||||
resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==}
|
||||
engines: {node: '>= 4.0.0'}
|
||||
|
||||
available-typed-arrays@1.0.7:
|
||||
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
babel-plugin-polyfill-corejs2@0.4.14:
|
||||
resolution: {integrity: sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
|
||||
|
||||
babel-plugin-polyfill-corejs3@0.13.0:
|
||||
resolution: {integrity: sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
|
||||
|
||||
babel-plugin-polyfill-regenerator@0.6.5:
|
||||
resolution: {integrity: sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
|
||||
|
||||
balanced-match@1.0.2:
|
||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||
|
||||
@@ -1017,6 +1676,14 @@ packages:
|
||||
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
call-bind@1.0.8:
|
||||
resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
call-bound@1.0.4:
|
||||
resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
caniuse-lite@1.0.30001760:
|
||||
resolution: {integrity: sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==}
|
||||
|
||||
@@ -1076,6 +1743,16 @@ packages:
|
||||
color-name@1.1.4:
|
||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||
|
||||
color-string@1.9.1:
|
||||
resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
|
||||
|
||||
color@4.2.3:
|
||||
resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
|
||||
engines: {node: '>=12.5.0'}
|
||||
|
||||
colorette@2.0.20:
|
||||
resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
|
||||
|
||||
combined-stream@1.0.8:
|
||||
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
@@ -1091,6 +1768,10 @@ packages:
|
||||
resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==}
|
||||
engines: {node: ^12.20.0 || >=14}
|
||||
|
||||
common-tags@1.8.2:
|
||||
resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==}
|
||||
engines: {node: '>=4.0.0'}
|
||||
|
||||
compare-version@0.1.2:
|
||||
resolution: {integrity: sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -1101,6 +1782,10 @@ packages:
|
||||
config-file-ts@0.2.8-rc1:
|
||||
resolution: {integrity: sha512-GtNECbVI82bT4RiDIzBSVuTKoSHufnU7Ce7/42bkWZJZFLjmDF2WBpVsvRkhKCfKBnTBb3qZrBwPpFBU/Myvhg==}
|
||||
|
||||
consola@3.4.2:
|
||||
resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==}
|
||||
engines: {node: ^14.18.0 || >=16.10.0}
|
||||
|
||||
convert-source-map@2.0.0:
|
||||
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
|
||||
|
||||
@@ -1108,6 +1793,9 @@ packages:
|
||||
resolution: {integrity: sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
core-js-compat@3.47.0:
|
||||
resolution: {integrity: sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==}
|
||||
|
||||
core-util-is@1.0.2:
|
||||
resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==}
|
||||
|
||||
@@ -1129,9 +1817,25 @@ packages:
|
||||
crypto-js@4.2.0:
|
||||
resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==}
|
||||
|
||||
crypto-random-string@2.0.0:
|
||||
resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
csstype@3.2.3:
|
||||
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
|
||||
|
||||
data-view-buffer@1.0.2:
|
||||
resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
data-view-byte-length@1.0.2:
|
||||
resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
data-view-byte-offset@1.0.1:
|
||||
resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
debug@4.4.3:
|
||||
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
|
||||
engines: {node: '>=6.0'}
|
||||
@@ -1141,10 +1845,22 @@ packages:
|
||||
supports-color:
|
||||
optional: true
|
||||
|
||||
decode-bmp@0.2.1:
|
||||
resolution: {integrity: sha512-NiOaGe+GN0KJqi2STf24hfMkFitDUaIoUU3eKvP/wAbLe8o6FuW5n/x7MHPR0HKvBokp6MQY/j7w8lewEeVCIA==}
|
||||
engines: {node: '>=8.6.0'}
|
||||
|
||||
decode-ico@0.4.1:
|
||||
resolution: {integrity: sha512-69NZfbKIzux1vBOd31al3XnMnH+2mqDhEgLdpygErm4d60N+UwA5Sq5WFjmEDQzumgB9fElojGwWG0vybVfFmA==}
|
||||
engines: {node: '>=8.6'}
|
||||
|
||||
decompress-response@6.0.0:
|
||||
resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
deepmerge@4.3.1:
|
||||
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
defaults@1.0.4:
|
||||
resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==}
|
||||
|
||||
@@ -1278,6 +1994,10 @@ packages:
|
||||
err-code@2.0.3:
|
||||
resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==}
|
||||
|
||||
es-abstract@1.24.1:
|
||||
resolution: {integrity: sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
es-define-property@1.0.1:
|
||||
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -1294,6 +2014,10 @@ packages:
|
||||
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
es-to-primitive@1.3.0:
|
||||
resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
es6-error@4.1.1:
|
||||
resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==}
|
||||
|
||||
@@ -1313,9 +2037,16 @@ packages:
|
||||
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
estree-walker@1.0.1:
|
||||
resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==}
|
||||
|
||||
estree-walker@2.0.2:
|
||||
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
|
||||
|
||||
esutils@2.0.3:
|
||||
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
etag@1.8.1:
|
||||
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
@@ -1338,6 +2069,9 @@ packages:
|
||||
fast-json-stable-stringify@2.1.0:
|
||||
resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
|
||||
|
||||
fast-uri@3.1.0:
|
||||
resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==}
|
||||
|
||||
fd-slicer@1.1.0:
|
||||
resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==}
|
||||
|
||||
@@ -1360,6 +2094,10 @@ packages:
|
||||
resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==}
|
||||
engines: {node: '>= 18.0.0'}
|
||||
|
||||
for-each@0.3.5:
|
||||
resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
foreground-child@3.3.1:
|
||||
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
|
||||
engines: {node: '>=14'}
|
||||
@@ -1368,6 +2106,20 @@ packages:
|
||||
resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
framer-motion@12.23.12:
|
||||
resolution: {integrity: sha512-6e78rdVtnBvlEVgu6eFEAgG9v3wLnYEboM8I5O5EXvfKC8gxGQB8wXJdhkMy10iVcn05jl6CNw7/HTsTCfwcWg==}
|
||||
peerDependencies:
|
||||
'@emotion/is-prop-valid': '*'
|
||||
react: ^18.0.0 || ^19.0.0
|
||||
react-dom: ^18.0.0 || ^19.0.0
|
||||
peerDependenciesMeta:
|
||||
'@emotion/is-prop-valid':
|
||||
optional: true
|
||||
react:
|
||||
optional: true
|
||||
react-dom:
|
||||
optional: true
|
||||
|
||||
fresh@2.0.0:
|
||||
resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==}
|
||||
engines: {node: '>= 0.8'}
|
||||
@@ -1407,6 +2159,17 @@ packages:
|
||||
function-bind@1.1.2:
|
||||
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
|
||||
|
||||
function.prototype.name@1.1.8:
|
||||
resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
functions-have-names@1.2.3:
|
||||
resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
|
||||
|
||||
generator-function@2.0.1:
|
||||
resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
gensync@1.0.0-beta.2:
|
||||
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
@@ -1419,6 +2182,9 @@ packages:
|
||||
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
get-own-enumerable-property-symbols@3.0.2:
|
||||
resolution: {integrity: sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==}
|
||||
|
||||
get-proto@1.0.1:
|
||||
resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -1427,10 +2193,19 @@ packages:
|
||||
resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
get-symbol-description@1.1.0:
|
||||
resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
glob@10.5.0:
|
||||
resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==}
|
||||
hasBin: true
|
||||
|
||||
glob@11.1.0:
|
||||
resolution: {integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==}
|
||||
engines: {node: 20 || >=22}
|
||||
hasBin: true
|
||||
|
||||
glob@7.2.3:
|
||||
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
|
||||
deprecated: Glob versions prior to v9 are no longer supported
|
||||
@@ -1459,6 +2234,10 @@ packages:
|
||||
graceful-fs@4.2.11:
|
||||
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
|
||||
|
||||
has-bigints@1.1.0:
|
||||
resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
has-flag@4.0.0:
|
||||
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -1466,6 +2245,10 @@ packages:
|
||||
has-property-descriptors@1.0.2:
|
||||
resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
|
||||
|
||||
has-proto@1.2.0:
|
||||
resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
has-symbols@1.1.0:
|
||||
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -1478,6 +2261,9 @@ packages:
|
||||
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
hey-listen@1.0.8:
|
||||
resolution: {integrity: sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==}
|
||||
|
||||
hookable@5.5.3:
|
||||
resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==}
|
||||
|
||||
@@ -1515,6 +2301,9 @@ packages:
|
||||
humanize-ms@1.2.1:
|
||||
resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
|
||||
|
||||
ico-endec@0.1.6:
|
||||
resolution: {integrity: sha512-ZdLU38ZoED3g1j3iEyzcQj+wAkY2xfWNkymszfJPoxucIUhK7NayQ+/C4Kv0nDFMIsbtbEHldv3V8PU494/ueQ==}
|
||||
|
||||
iconv-corefoundation@1.1.7:
|
||||
resolution: {integrity: sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==}
|
||||
engines: {node: ^8.11.2 || >=10}
|
||||
@@ -1524,6 +2313,9 @@ packages:
|
||||
resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
idb@7.1.1:
|
||||
resolution: {integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==}
|
||||
|
||||
ieee754@1.2.1:
|
||||
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
|
||||
|
||||
@@ -1545,18 +2337,65 @@ packages:
|
||||
inherits@2.0.4:
|
||||
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
||||
|
||||
internal-slot@1.1.0:
|
||||
resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
ip-address@10.1.0:
|
||||
resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==}
|
||||
engines: {node: '>= 12'}
|
||||
|
||||
is-array-buffer@3.0.5:
|
||||
resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-arrayish@0.3.4:
|
||||
resolution: {integrity: sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==}
|
||||
|
||||
is-async-function@2.1.1:
|
||||
resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-bigint@1.1.0:
|
||||
resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-boolean-object@1.2.2:
|
||||
resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-callable@1.2.7:
|
||||
resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-ci@3.0.1:
|
||||
resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==}
|
||||
hasBin: true
|
||||
|
||||
is-core-module@2.16.1:
|
||||
resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-data-view@1.0.2:
|
||||
resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-date-object@1.1.0:
|
||||
resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-finalizationregistry@1.1.1:
|
||||
resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-fullwidth-code-point@3.0.0:
|
||||
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
is-generator-function@1.1.2:
|
||||
resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-interactive@1.0.0:
|
||||
resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -1564,14 +2403,80 @@ packages:
|
||||
is-lambda@1.0.1:
|
||||
resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==}
|
||||
|
||||
is-map@2.0.3:
|
||||
resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-module@1.0.0:
|
||||
resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
|
||||
|
||||
is-negative-zero@2.0.3:
|
||||
resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-number-object@1.1.1:
|
||||
resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-obj@1.0.1:
|
||||
resolution: {integrity: sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
is-regex@1.2.1:
|
||||
resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-regexp@1.0.0:
|
||||
resolution: {integrity: sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
is-set@2.0.3:
|
||||
resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-shared-array-buffer@1.0.4:
|
||||
resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-stream@2.0.1:
|
||||
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
is-string@1.1.1:
|
||||
resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-symbol@1.1.1:
|
||||
resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-typed-array@1.1.15:
|
||||
resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-unicode-supported@0.1.0:
|
||||
resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
is-weakmap@2.0.2:
|
||||
resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-weakref@1.1.1:
|
||||
resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-weakset@2.0.4:
|
||||
resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-what@5.5.0:
|
||||
resolution: {integrity: sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
isarray@2.0.5:
|
||||
resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
|
||||
|
||||
isbinaryfile@4.0.10:
|
||||
resolution: {integrity: sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==}
|
||||
engines: {node: '>= 8.0.0'}
|
||||
@@ -1586,6 +2491,10 @@ packages:
|
||||
jackspeak@3.4.3:
|
||||
resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
|
||||
|
||||
jackspeak@4.1.1:
|
||||
resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
jake@10.9.4:
|
||||
resolution: {integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -1613,6 +2522,12 @@ packages:
|
||||
json-schema-traverse@0.4.1:
|
||||
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
|
||||
|
||||
json-schema-traverse@1.0.0:
|
||||
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
|
||||
|
||||
json-schema@0.4.0:
|
||||
resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==}
|
||||
|
||||
json-stringify-safe@5.0.1:
|
||||
resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==}
|
||||
|
||||
@@ -1627,12 +2542,20 @@ packages:
|
||||
jsonfile@6.2.0:
|
||||
resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==}
|
||||
|
||||
jsonpointer@5.0.1:
|
||||
resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
keyv@4.5.4:
|
||||
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
||||
|
||||
lazy-val@1.0.5:
|
||||
resolution: {integrity: sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==}
|
||||
|
||||
leven@3.1.0:
|
||||
resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
lightningcss-android-arm64@1.30.2:
|
||||
resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
@@ -1707,6 +2630,12 @@ packages:
|
||||
resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
|
||||
lodash.debounce@4.0.8:
|
||||
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
|
||||
|
||||
lodash.sortby@4.7.0:
|
||||
resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==}
|
||||
|
||||
lodash@4.17.21:
|
||||
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
|
||||
|
||||
@@ -1721,6 +2650,10 @@ packages:
|
||||
lru-cache@10.4.3:
|
||||
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
|
||||
|
||||
lru-cache@11.2.4:
|
||||
resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
lru-cache@5.1.1:
|
||||
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
|
||||
|
||||
@@ -1737,6 +2670,9 @@ packages:
|
||||
peerDependencies:
|
||||
vue: '>=3.0.1'
|
||||
|
||||
magic-string@0.25.9:
|
||||
resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
|
||||
|
||||
magic-string@0.30.21:
|
||||
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
|
||||
|
||||
@@ -1744,6 +2680,11 @@ packages:
|
||||
resolution: {integrity: sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==}
|
||||
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
|
||||
|
||||
marked@17.0.1:
|
||||
resolution: {integrity: sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg==}
|
||||
engines: {node: '>= 20'}
|
||||
hasBin: true
|
||||
|
||||
matcher@3.0.0:
|
||||
resolution: {integrity: sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -1851,6 +2792,18 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
motion-dom@12.23.12:
|
||||
resolution: {integrity: sha512-RcR4fvMCTESQBD/uKQe49D5RUeDOokkGRmz4ceaJKDBgHYtZtntC/s2vLvY38gqGaytinij/yi3hMcWVcEF5Kw==}
|
||||
|
||||
motion-utils@12.23.6:
|
||||
resolution: {integrity: sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==}
|
||||
|
||||
motion-v@1.7.4:
|
||||
resolution: {integrity: sha512-YNDUAsany04wfI7YtHxQK3kxzNvh+OdFUk9GpA3+hMt7j6P+5WrVAAgr8kmPPoVza9EsJiAVhqoN3YYFN0Twrw==}
|
||||
peerDependencies:
|
||||
'@vueuse/core': '>=10.0.0'
|
||||
vue: '>=3.0.0'
|
||||
|
||||
ms@2.1.3:
|
||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||
|
||||
@@ -1888,10 +2841,18 @@ packages:
|
||||
resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
object-inspect@1.13.4:
|
||||
resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
object-keys@1.1.1:
|
||||
resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
object.assign@4.1.7:
|
||||
resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
ohash@2.0.11:
|
||||
resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==}
|
||||
|
||||
@@ -1910,6 +2871,10 @@ packages:
|
||||
resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
own-keys@1.0.1:
|
||||
resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
p-cancelable@2.1.1:
|
||||
resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -1940,10 +2905,17 @@ packages:
|
||||
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
path-parse@1.0.7:
|
||||
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
|
||||
|
||||
path-scurry@1.11.1:
|
||||
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
|
||||
engines: {node: '>=16 || 14 >=14.18'}
|
||||
|
||||
path-scurry@2.0.1:
|
||||
resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
pe-library@0.4.1:
|
||||
resolution: {integrity: sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==}
|
||||
engines: {node: '>=12', npm: '>=6'}
|
||||
@@ -1957,6 +2929,10 @@ packages:
|
||||
picocolors@1.1.1:
|
||||
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
||||
|
||||
picomatch@2.3.1:
|
||||
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
|
||||
engines: {node: '>=8.6'}
|
||||
|
||||
picomatch@4.0.3:
|
||||
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -1988,6 +2964,10 @@ packages:
|
||||
resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==}
|
||||
engines: {node: '>=10.4.0'}
|
||||
|
||||
possible-typed-array-names@1.1.0:
|
||||
resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
postcss@8.5.6:
|
||||
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
@@ -1997,6 +2977,14 @@ packages:
|
||||
engines: {node: '>=14.0.0'}
|
||||
hasBin: true
|
||||
|
||||
pretty-bytes@5.6.0:
|
||||
resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
pretty-bytes@6.1.1:
|
||||
resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==}
|
||||
engines: {node: ^14.13.1 || >=16.0.0}
|
||||
|
||||
proc-log@2.0.1:
|
||||
resolution: {integrity: sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==}
|
||||
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
|
||||
@@ -2024,10 +3012,16 @@ packages:
|
||||
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
quansync@1.0.0:
|
||||
resolution: {integrity: sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==}
|
||||
|
||||
quick-lru@5.1.1:
|
||||
resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
randombytes@2.1.0:
|
||||
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
|
||||
|
||||
range-parser@1.2.1:
|
||||
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
@@ -2040,6 +3034,32 @@ packages:
|
||||
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
reflect.getprototypeof@1.0.10:
|
||||
resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
regenerate-unicode-properties@10.2.2:
|
||||
resolution: {integrity: sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
regenerate@1.4.2:
|
||||
resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==}
|
||||
|
||||
regexp.prototype.flags@1.5.4:
|
||||
resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
regexpu-core@6.4.0:
|
||||
resolution: {integrity: sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
regjsgen@0.8.0:
|
||||
resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==}
|
||||
|
||||
regjsparser@0.13.0:
|
||||
resolution: {integrity: sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==}
|
||||
hasBin: true
|
||||
|
||||
reka-ui@2.6.1:
|
||||
resolution: {integrity: sha512-XK7cJDQoNuGXfCNzBBo/81Yg/OgjPwvbabnlzXG2VsdSgNsT6iIkuPBPr+C0Shs+3bb0x0lbPvgQAhMSCKm5Ww==}
|
||||
peerDependencies:
|
||||
@@ -2049,6 +3069,10 @@ packages:
|
||||
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
require-from-string@2.0.2:
|
||||
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
resedit@1.7.2:
|
||||
resolution: {integrity: sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA==}
|
||||
engines: {node: '>=12', npm: '>=6'}
|
||||
@@ -2056,6 +3080,11 @@ packages:
|
||||
resolve-alpn@1.2.1:
|
||||
resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==}
|
||||
|
||||
resolve@1.22.11:
|
||||
resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
hasBin: true
|
||||
|
||||
responselike@2.0.1:
|
||||
resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==}
|
||||
|
||||
@@ -2129,9 +3158,26 @@ packages:
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
hasBin: true
|
||||
|
||||
rollup@2.79.2:
|
||||
resolution: {integrity: sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
hasBin: true
|
||||
|
||||
safe-array-concat@1.1.3:
|
||||
resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==}
|
||||
engines: {node: '>=0.4'}
|
||||
|
||||
safe-buffer@5.2.1:
|
||||
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
||||
|
||||
safe-push-apply@1.0.0:
|
||||
resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
safe-regex-test@1.1.0:
|
||||
resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
safer-buffer@2.1.2:
|
||||
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
|
||||
|
||||
@@ -2165,13 +3211,35 @@ packages:
|
||||
resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
serialize-javascript@6.0.2:
|
||||
resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==}
|
||||
|
||||
serve-static@2.2.0:
|
||||
resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
set-function-length@1.2.2:
|
||||
resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
set-function-name@2.0.2:
|
||||
resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
set-proto@1.0.0:
|
||||
resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
setprototypeof@1.2.0:
|
||||
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
|
||||
|
||||
sharp-ico@0.1.5:
|
||||
resolution: {integrity: sha512-a3jODQl82NPp1d5OYb0wY+oFaPk7AvyxipIowCHk7pBsZCWgbe0yAkU2OOXdoH0ENyANhyOQbs9xkAiRHcF02Q==}
|
||||
|
||||
sharp@0.33.5:
|
||||
resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
|
||||
shebang-command@2.0.0:
|
||||
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -2180,6 +3248,22 @@ packages:
|
||||
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
side-channel-list@1.0.0:
|
||||
resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
side-channel-map@1.0.1:
|
||||
resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
side-channel-weakmap@1.0.2:
|
||||
resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
side-channel@1.1.0:
|
||||
resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
signal-exit@3.0.7:
|
||||
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
|
||||
|
||||
@@ -2187,6 +3271,9 @@ packages:
|
||||
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
simple-swizzle@0.2.4:
|
||||
resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==}
|
||||
|
||||
simple-update-notifier@2.0.0:
|
||||
resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -2199,6 +3286,9 @@ packages:
|
||||
resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==}
|
||||
engines: {node: '>= 6.0.0', npm: '>= 3.0.0'}
|
||||
|
||||
smob@1.5.0:
|
||||
resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==}
|
||||
|
||||
socks-proxy-agent@7.0.0:
|
||||
resolution: {integrity: sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==}
|
||||
engines: {node: '>= 10'}
|
||||
@@ -2218,6 +3308,15 @@ packages:
|
||||
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
source-map@0.8.0-beta.0:
|
||||
resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==}
|
||||
engines: {node: '>= 8'}
|
||||
deprecated: The work that was done in this beta branch won't be included in future versions
|
||||
|
||||
sourcemap-codec@1.4.8:
|
||||
resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
|
||||
deprecated: Please use @jridgewell/sourcemap-codec instead
|
||||
|
||||
speakingurl@14.0.1:
|
||||
resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -2237,6 +3336,10 @@ packages:
|
||||
resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
stop-iteration-iterator@1.1.0:
|
||||
resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
string-width@4.2.3:
|
||||
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -2245,9 +3348,29 @@ packages:
|
||||
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
string.prototype.matchall@4.0.12:
|
||||
resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
string.prototype.trim@1.2.10:
|
||||
resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
string.prototype.trimend@1.0.9:
|
||||
resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
string.prototype.trimstart@1.0.8:
|
||||
resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
string_decoder@1.3.0:
|
||||
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
|
||||
|
||||
stringify-object@3.3.0:
|
||||
resolution: {integrity: sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
strip-ansi@6.0.1:
|
||||
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -2256,6 +3379,10 @@ packages:
|
||||
resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
strip-comments@2.0.1:
|
||||
resolution: {integrity: sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
sumchecker@3.0.1:
|
||||
resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==}
|
||||
engines: {node: '>= 8.0'}
|
||||
@@ -2268,6 +3395,10 @@ packages:
|
||||
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
supports-preserve-symlinks-flag@1.0.0:
|
||||
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
tailwind-merge@3.4.0:
|
||||
resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==}
|
||||
|
||||
@@ -2282,6 +3413,10 @@ packages:
|
||||
resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
temp-dir@2.0.0:
|
||||
resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
temp-file@3.4.0:
|
||||
resolution: {integrity: sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==}
|
||||
|
||||
@@ -2289,6 +3424,10 @@ packages:
|
||||
resolution: {integrity: sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
|
||||
tempy@0.6.0:
|
||||
resolution: {integrity: sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
terser@5.44.1:
|
||||
resolution: {integrity: sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -2308,10 +3447,16 @@ packages:
|
||||
resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==}
|
||||
engines: {node: '>=14.14'}
|
||||
|
||||
to-data-view@1.1.0:
|
||||
resolution: {integrity: sha512-1eAdufMg6mwgmlojAx3QeMnzB/BTVp7Tbndi3U7ftcT2zCZadjxkkmLmd97zmaxWi+sgGcgWrokmpEoy0Dn0vQ==}
|
||||
|
||||
toidentifier@1.0.1:
|
||||
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
|
||||
engines: {node: '>=0.6'}
|
||||
|
||||
tr46@1.0.1:
|
||||
resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==}
|
||||
|
||||
truncate-utf8-bytes@1.0.2:
|
||||
resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==}
|
||||
|
||||
@@ -2325,17 +3470,63 @@ packages:
|
||||
resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
type-fest@0.16.0:
|
||||
resolution: {integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
typed-array-buffer@1.0.3:
|
||||
resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
typed-array-byte-length@1.0.3:
|
||||
resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
typed-array-byte-offset@1.0.4:
|
||||
resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
typed-array-length@1.0.7:
|
||||
resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
typescript@5.9.3:
|
||||
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
|
||||
engines: {node: '>=14.17'}
|
||||
hasBin: true
|
||||
|
||||
unbox-primitive@1.1.0:
|
||||
resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
unconfig-core@7.4.2:
|
||||
resolution: {integrity: sha512-VgPCvLWugINbXvMQDf8Jh0mlbvNjNC6eSUziHsBCMpxR05OPrNrvDnyatdMjRgcHaaNsCqz+wjNXxNw1kRLHUg==}
|
||||
|
||||
unconfig@7.4.2:
|
||||
resolution: {integrity: sha512-nrMlWRQ1xdTjSnSUqvYqJzbTBFugoqHobQj58B2bc8qxHKBBHMNNsWQFP3Cd3/JZK907voM2geYPWqD4VK3MPQ==}
|
||||
|
||||
undici-types@6.21.0:
|
||||
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
||||
|
||||
undici-types@7.16.0:
|
||||
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
|
||||
|
||||
unicode-canonical-property-names-ecmascript@2.0.1:
|
||||
resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
unicode-match-property-ecmascript@2.0.0:
|
||||
resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
unicode-match-property-value-ecmascript@2.2.1:
|
||||
resolution: {integrity: sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
unicode-property-aliases-ecmascript@2.2.0:
|
||||
resolution: {integrity: sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
unique-filename@2.0.1:
|
||||
resolution: {integrity: sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==}
|
||||
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
|
||||
@@ -2344,6 +3535,10 @@ packages:
|
||||
resolution: {integrity: sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==}
|
||||
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
|
||||
|
||||
unique-string@2.0.0:
|
||||
resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
universalify@0.1.2:
|
||||
resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
|
||||
engines: {node: '>= 4.0.0'}
|
||||
@@ -2352,6 +3547,10 @@ packages:
|
||||
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
|
||||
upath@1.2.0:
|
||||
resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
update-browserslist-db@1.2.2:
|
||||
resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==}
|
||||
hasBin: true
|
||||
@@ -2382,6 +3581,18 @@ packages:
|
||||
vite-plugin-electron-renderer:
|
||||
optional: true
|
||||
|
||||
vite-plugin-pwa@1.2.0:
|
||||
resolution: {integrity: sha512-a2xld+SJshT9Lgcv8Ji4+srFJL4k/1bVbd1x06JIkvecpQkwkvCncD1+gSzcdm3s+owWLpMJerG3aN5jupJEVw==}
|
||||
engines: {node: '>=16.0.0'}
|
||||
peerDependencies:
|
||||
'@vite-pwa/assets-generator': ^1.0.0
|
||||
vite: ^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
|
||||
workbox-build: ^7.4.0
|
||||
workbox-window: ^7.4.0
|
||||
peerDependenciesMeta:
|
||||
'@vite-pwa/assets-generator':
|
||||
optional: true
|
||||
|
||||
vscode-uri@3.1.0:
|
||||
resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==}
|
||||
|
||||
@@ -2432,11 +3643,82 @@ packages:
|
||||
wcwidth@1.0.1:
|
||||
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
|
||||
|
||||
webidl-conversions@4.0.2:
|
||||
resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==}
|
||||
|
||||
whatwg-url@7.1.0:
|
||||
resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==}
|
||||
|
||||
which-boxed-primitive@1.1.1:
|
||||
resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
which-builtin-type@1.2.1:
|
||||
resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
which-collection@1.0.2:
|
||||
resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
which-typed-array@1.1.19:
|
||||
resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
which@2.0.2:
|
||||
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
||||
engines: {node: '>= 8'}
|
||||
hasBin: true
|
||||
|
||||
workbox-background-sync@7.4.0:
|
||||
resolution: {integrity: sha512-8CB9OxKAgKZKyNMwfGZ1XESx89GryWTfI+V5yEj8sHjFH8MFelUwYXEyldEK6M6oKMmn807GoJFUEA1sC4XS9w==}
|
||||
|
||||
workbox-broadcast-update@7.4.0:
|
||||
resolution: {integrity: sha512-+eZQwoktlvo62cI0b+QBr40v5XjighxPq3Fzo9AWMiAosmpG5gxRHgTbGGhaJv/q/MFVxwFNGh/UwHZ/8K88lA==}
|
||||
|
||||
workbox-build@7.4.0:
|
||||
resolution: {integrity: sha512-Ntk1pWb0caOFIvwz/hfgrov/OJ45wPEhI5PbTywQcYjyZiVhT3UrwwUPl6TRYbTm4moaFYithYnl1lvZ8UjxcA==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
|
||||
workbox-cacheable-response@7.4.0:
|
||||
resolution: {integrity: sha512-0Fb8795zg/x23ISFkAc7lbWes6vbw34DGFIMw31cwuHPgDEC/5EYm6m/ZkylLX0EnEbbOyOCLjKgFS/Z5g0HeQ==}
|
||||
|
||||
workbox-core@7.4.0:
|
||||
resolution: {integrity: sha512-6BMfd8tYEnN4baG4emG9U0hdXM4gGuDU3ectXuVHnj71vwxTFI7WOpQJC4siTOlVtGqCUtj0ZQNsrvi6kZZTAQ==}
|
||||
|
||||
workbox-expiration@7.4.0:
|
||||
resolution: {integrity: sha512-V50p4BxYhtA80eOvulu8xVfPBgZbkxJ1Jr8UUn0rvqjGhLDqKNtfrDfjJKnLz2U8fO2xGQJTx/SKXNTzHOjnHw==}
|
||||
|
||||
workbox-google-analytics@7.4.0:
|
||||
resolution: {integrity: sha512-MVPXQslRF6YHkzGoFw1A4GIB8GrKym/A5+jYDUSL+AeJw4ytQGrozYdiZqUW1TPQHW8isBCBtyFJergUXyNoWQ==}
|
||||
|
||||
workbox-navigation-preload@7.4.0:
|
||||
resolution: {integrity: sha512-etzftSgdQfjMcfPgbfaZCfM2QuR1P+4o8uCA2s4rf3chtKTq/Om7g/qvEOcZkG6v7JZOSOxVYQiOu6PbAZgU6w==}
|
||||
|
||||
workbox-precaching@7.4.0:
|
||||
resolution: {integrity: sha512-VQs37T6jDqf1rTxUJZXRl3yjZMf5JX/vDPhmx2CPgDDKXATzEoqyRqhYnRoxl6Kr0rqaQlp32i9rtG5zTzIlNg==}
|
||||
|
||||
workbox-range-requests@7.4.0:
|
||||
resolution: {integrity: sha512-3Vq854ZNuP6Y0KZOQWLaLC9FfM7ZaE+iuQl4VhADXybwzr4z/sMmnLgTeUZLq5PaDlcJBxYXQ3U91V7dwAIfvw==}
|
||||
|
||||
workbox-recipes@7.4.0:
|
||||
resolution: {integrity: sha512-kOkWvsAn4H8GvAkwfJTbwINdv4voFoiE9hbezgB1sb/0NLyTG4rE7l6LvS8lLk5QIRIto+DjXLuAuG3Vmt3cxQ==}
|
||||
|
||||
workbox-routing@7.4.0:
|
||||
resolution: {integrity: sha512-C/ooj5uBWYAhAqwmU8HYQJdOjjDKBp9MzTQ+otpMmd+q0eF59K+NuXUek34wbL0RFrIXe/KKT+tUWcZcBqxbHQ==}
|
||||
|
||||
workbox-strategies@7.4.0:
|
||||
resolution: {integrity: sha512-T4hVqIi5A4mHi92+5EppMX3cLaVywDp8nsyUgJhOZxcfSV/eQofcOA6/EMo5rnTNmNTpw0rUgjAI6LaVullPpg==}
|
||||
|
||||
workbox-streams@7.4.0:
|
||||
resolution: {integrity: sha512-QHPBQrey7hQbnTs5GrEVoWz7RhHJXnPT+12qqWM378orDMo5VMJLCkCM1cnCk+8Eq92lccx/VgRZ7WAzZWbSLg==}
|
||||
|
||||
workbox-sw@7.4.0:
|
||||
resolution: {integrity: sha512-ltU+Kr3qWR6BtbdlMnCjobZKzeV1hN+S6UvDywBrwM19TTyqA03X66dzw1tEIdJvQ4lYKkBFox6IAEhoSEZ8Xw==}
|
||||
|
||||
workbox-window@7.4.0:
|
||||
resolution: {integrity: sha512-/bIYdBLAVsNR3v7gYGaV4pQW3M3kEPx5E8vDxGvxo6khTrGtSSCS7QiFKv9ogzBgZiy0OXLP9zO28U/1nF1mfw==}
|
||||
|
||||
wrap-ansi@7.0.0:
|
||||
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -2481,6 +3763,13 @@ snapshots:
|
||||
|
||||
7zip-bin@5.2.0: {}
|
||||
|
||||
'@apideck/better-ajv-errors@0.3.6(ajv@8.17.1)':
|
||||
dependencies:
|
||||
ajv: 8.17.1
|
||||
json-schema: 0.4.0
|
||||
jsonpointer: 5.0.1
|
||||
leven: 3.1.0
|
||||
|
||||
'@babel/code-frame@7.27.1':
|
||||
dependencies:
|
||||
'@babel/helper-validator-identifier': 7.28.5
|
||||
@@ -2517,6 +3806,10 @@ snapshots:
|
||||
'@jridgewell/trace-mapping': 0.3.31
|
||||
jsesc: 3.1.0
|
||||
|
||||
'@babel/helper-annotate-as-pure@7.27.3':
|
||||
dependencies:
|
||||
'@babel/types': 7.28.5
|
||||
|
||||
'@babel/helper-compilation-targets@7.27.2':
|
||||
dependencies:
|
||||
'@babel/compat-data': 7.28.5
|
||||
@@ -2525,8 +3818,46 @@ snapshots:
|
||||
lru-cache: 5.1.1
|
||||
semver: 6.3.1
|
||||
|
||||
'@babel/helper-create-class-features-plugin@7.28.5(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-annotate-as-pure': 7.27.3
|
||||
'@babel/helper-member-expression-to-functions': 7.28.5
|
||||
'@babel/helper-optimise-call-expression': 7.27.1
|
||||
'@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/helper-skip-transparent-expression-wrappers': 7.27.1
|
||||
'@babel/traverse': 7.28.5
|
||||
semver: 6.3.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-annotate-as-pure': 7.27.3
|
||||
regexpu-core: 6.4.0
|
||||
semver: 6.3.1
|
||||
|
||||
'@babel/helper-define-polyfill-provider@0.6.5(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-compilation-targets': 7.27.2
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
debug: 4.4.3
|
||||
lodash.debounce: 4.0.8
|
||||
resolve: 1.22.11
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/helper-globals@7.28.0': {}
|
||||
|
||||
'@babel/helper-member-expression-to-functions@7.28.5':
|
||||
dependencies:
|
||||
'@babel/traverse': 7.28.5
|
||||
'@babel/types': 7.28.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/helper-module-imports@7.27.1':
|
||||
dependencies:
|
||||
'@babel/traverse': 7.28.5
|
||||
@@ -2543,14 +3874,51 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/helper-optimise-call-expression@7.27.1':
|
||||
dependencies:
|
||||
'@babel/types': 7.28.5
|
||||
|
||||
'@babel/helper-plugin-utils@7.27.1': {}
|
||||
|
||||
'@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-annotate-as-pure': 7.27.3
|
||||
'@babel/helper-wrap-function': 7.28.3
|
||||
'@babel/traverse': 7.28.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/helper-replace-supers@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-member-expression-to-functions': 7.28.5
|
||||
'@babel/helper-optimise-call-expression': 7.27.1
|
||||
'@babel/traverse': 7.28.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/helper-skip-transparent-expression-wrappers@7.27.1':
|
||||
dependencies:
|
||||
'@babel/traverse': 7.28.5
|
||||
'@babel/types': 7.28.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/helper-string-parser@7.27.1': {}
|
||||
|
||||
'@babel/helper-validator-identifier@7.28.5': {}
|
||||
|
||||
'@babel/helper-validator-option@7.27.1': {}
|
||||
|
||||
'@babel/helper-wrap-function@7.28.3':
|
||||
dependencies:
|
||||
'@babel/template': 7.27.2
|
||||
'@babel/traverse': 7.28.5
|
||||
'@babel/types': 7.28.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/helpers@7.28.4':
|
||||
dependencies:
|
||||
'@babel/template': 7.27.2
|
||||
@@ -2560,11 +3928,479 @@ snapshots:
|
||||
dependencies:
|
||||
'@babel/types': 7.28.5
|
||||
|
||||
'@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
'@babel/traverse': 7.28.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
'@babel/helper-skip-transparent-expression-wrappers': 7.27.1
|
||||
'@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.28.5)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
'@babel/traverse': 7.28.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
|
||||
'@babel/plugin-syntax-import-assertions@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5)
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-async-generator-functions@7.28.0(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
'@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/traverse': 7.28.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/plugin-transform-async-to-generator@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-module-imports': 7.27.1
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
'@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.5)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-block-scoping@7.28.5(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-class-properties@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5)
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/plugin-transform-class-static-block@7.28.3(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5)
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/plugin-transform-classes@7.28.4(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-annotate-as-pure': 7.27.3
|
||||
'@babel/helper-compilation-targets': 7.27.2
|
||||
'@babel/helper-globals': 7.28.0
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
'@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/traverse': 7.28.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/plugin-transform-computed-properties@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
'@babel/template': 7.27.2
|
||||
|
||||
'@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
'@babel/traverse': 7.28.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/plugin-transform-dotall-regex@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5)
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5)
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-explicit-resource-management@7.28.0(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
'@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/plugin-transform-exponentiation-operator@7.28.5(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-for-of@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
'@babel/helper-skip-transparent-expression-wrappers': 7.27.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/plugin-transform-function-name@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-compilation-targets': 7.27.2
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
'@babel/traverse': 7.28.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/plugin-transform-json-strings@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-literals@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-logical-assignment-operators@7.28.5(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5)
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5)
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/plugin-transform-modules-systemjs@7.28.5(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5)
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
'@babel/helper-validator-identifier': 7.28.5
|
||||
'@babel/traverse': 7.28.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5)
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/plugin-transform-named-capturing-groups-regex@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5)
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-new-target@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-nullish-coalescing-operator@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-numeric-separator@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-object-rest-spread@7.28.4(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-compilation-targets': 7.27.2
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
'@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.5)
|
||||
'@babel/traverse': 7.28.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/plugin-transform-object-super@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
'@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/plugin-transform-optional-catch-binding@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-optional-chaining@7.28.5(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
'@babel/helper-skip-transparent-expression-wrappers': 7.27.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/plugin-transform-parameters@7.27.7(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-private-methods@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5)
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/plugin-transform-private-property-in-object@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-annotate-as-pure': 7.27.3
|
||||
'@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5)
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-regenerator@7.28.4(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-regexp-modifiers@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5)
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-spread@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
'@babel/helper-skip-transparent-expression-wrappers': 7.27.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-unicode-property-regex@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5)
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5)
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/plugin-transform-unicode-sets-regex@7.27.1(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5)
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
|
||||
'@babel/preset-env@7.28.5(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/compat-data': 7.28.5
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-compilation-targets': 7.27.2
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
'@babel/helper-validator-option': 7.27.1
|
||||
'@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.28.5(@babel/core@7.28.5)
|
||||
'@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.28.3(@babel/core@7.28.5)
|
||||
'@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.5)
|
||||
'@babel/plugin-syntax-import-assertions': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-async-generator-functions': 7.28.0(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-async-to-generator': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-block-scoping': 7.28.5(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-class-static-block': 7.28.3(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-classes': 7.28.4(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-computed-properties': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-dotall-regex': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-explicit-resource-management': 7.28.0(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-exponentiation-operator': 7.28.5(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-json-strings': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-literals': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-logical-assignment-operators': 7.28.5(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-modules-systemjs': 7.28.5(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-nullish-coalescing-operator': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-numeric-separator': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-object-rest-spread': 7.28.4(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-optional-catch-binding': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-private-methods': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-private-property-in-object': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-regenerator': 7.28.4(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-regexp-modifiers': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-spread': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-unicode-property-regex': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-unicode-sets-regex': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.28.5)
|
||||
babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.5)
|
||||
babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.5)
|
||||
babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.5)
|
||||
core-js-compat: 3.47.0
|
||||
semver: 6.3.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.28.5)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-plugin-utils': 7.27.1
|
||||
'@babel/types': 7.28.5
|
||||
esutils: 2.0.3
|
||||
|
||||
'@babel/runtime@7.28.4': {}
|
||||
|
||||
'@babel/template@7.27.2':
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.27.1
|
||||
@@ -2588,6 +4424,9 @@ snapshots:
|
||||
'@babel/helper-string-parser': 7.27.1
|
||||
'@babel/helper-validator-identifier': 7.28.5
|
||||
|
||||
'@canvas/image-data@1.1.0':
|
||||
optional: true
|
||||
|
||||
'@develar/schema-utils@2.6.5':
|
||||
dependencies:
|
||||
ajv: 6.12.6
|
||||
@@ -2819,6 +4658,81 @@ snapshots:
|
||||
|
||||
'@gar/promisify@1.1.3': {}
|
||||
|
||||
'@img/sharp-darwin-arm64@0.33.5':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-darwin-arm64': 1.0.4
|
||||
optional: true
|
||||
|
||||
'@img/sharp-darwin-x64@0.33.5':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-darwin-x64': 1.0.4
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-darwin-arm64@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-darwin-x64@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linux-arm64@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linux-arm@1.0.5':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linux-s390x@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linux-x64@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-arm64@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-x64@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linux-arm64@0.33.5':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linux-arm64': 1.0.4
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linux-arm@0.33.5':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linux-arm': 1.0.5
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linux-s390x@0.33.5':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linux-s390x': 1.0.4
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linux-x64@0.33.5':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linux-x64': 1.0.4
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linuxmusl-arm64@0.33.5':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linuxmusl-arm64': 1.0.4
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linuxmusl-x64@0.33.5':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linuxmusl-x64': 1.0.4
|
||||
optional: true
|
||||
|
||||
'@img/sharp-wasm32@0.33.5':
|
||||
dependencies:
|
||||
'@emnapi/runtime': 1.7.1
|
||||
optional: true
|
||||
|
||||
'@img/sharp-win32-ia32@0.33.5':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-win32-x64@0.33.5':
|
||||
optional: true
|
||||
|
||||
'@internationalized/date@3.10.0':
|
||||
dependencies:
|
||||
'@swc/helpers': 0.5.17
|
||||
@@ -2858,7 +4772,6 @@ snapshots:
|
||||
dependencies:
|
||||
'@jridgewell/gen-mapping': 0.3.13
|
||||
'@jridgewell/trace-mapping': 0.3.31
|
||||
optional: true
|
||||
|
||||
'@jridgewell/sourcemap-codec@1.5.5': {}
|
||||
|
||||
@@ -2904,6 +4817,11 @@ snapshots:
|
||||
'@pkgjs/parseargs@0.11.0':
|
||||
optional: true
|
||||
|
||||
'@quansync/fs@1.0.0':
|
||||
dependencies:
|
||||
quansync: 1.0.0
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-android-arm64@1.0.0-beta.50':
|
||||
optional: true
|
||||
|
||||
@@ -2950,8 +4868,63 @@ snapshots:
|
||||
|
||||
'@rolldown/pluginutils@1.0.0-beta.50': {}
|
||||
|
||||
'@rollup/plugin-babel@5.3.1(@babel/core@7.28.5)(rollup@2.79.2)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-module-imports': 7.27.1
|
||||
'@rollup/pluginutils': 3.1.0(rollup@2.79.2)
|
||||
rollup: 2.79.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@rollup/plugin-node-resolve@15.3.1(rollup@2.79.2)':
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 5.3.0(rollup@2.79.2)
|
||||
'@types/resolve': 1.20.2
|
||||
deepmerge: 4.3.1
|
||||
is-module: 1.0.0
|
||||
resolve: 1.22.11
|
||||
optionalDependencies:
|
||||
rollup: 2.79.2
|
||||
|
||||
'@rollup/plugin-replace@2.4.2(rollup@2.79.2)':
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 3.1.0(rollup@2.79.2)
|
||||
magic-string: 0.25.9
|
||||
rollup: 2.79.2
|
||||
|
||||
'@rollup/plugin-terser@0.4.4(rollup@2.79.2)':
|
||||
dependencies:
|
||||
serialize-javascript: 6.0.2
|
||||
smob: 1.5.0
|
||||
terser: 5.44.1
|
||||
optionalDependencies:
|
||||
rollup: 2.79.2
|
||||
|
||||
'@rollup/pluginutils@3.1.0(rollup@2.79.2)':
|
||||
dependencies:
|
||||
'@types/estree': 0.0.39
|
||||
estree-walker: 1.0.1
|
||||
picomatch: 2.3.1
|
||||
rollup: 2.79.2
|
||||
|
||||
'@rollup/pluginutils@5.3.0(rollup@2.79.2)':
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
estree-walker: 2.0.2
|
||||
picomatch: 4.0.3
|
||||
optionalDependencies:
|
||||
rollup: 2.79.2
|
||||
|
||||
'@sindresorhus/is@4.6.0': {}
|
||||
|
||||
'@surma/rollup-plugin-off-main-thread@2.2.3':
|
||||
dependencies:
|
||||
ejs: 3.1.10
|
||||
json5: 2.2.3
|
||||
magic-string: 0.25.9
|
||||
string.prototype.matchall: 4.0.12
|
||||
|
||||
'@swc/helpers@0.5.17':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
@@ -3062,6 +5035,10 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/ms': 2.1.0
|
||||
|
||||
'@types/estree@0.0.39': {}
|
||||
|
||||
'@types/estree@1.0.8': {}
|
||||
|
||||
'@types/file-saver@2.0.7': {}
|
||||
|
||||
'@types/fs-extra@9.0.13':
|
||||
@@ -3090,10 +5067,14 @@ snapshots:
|
||||
xmlbuilder: 15.1.1
|
||||
optional: true
|
||||
|
||||
'@types/resolve@1.20.2': {}
|
||||
|
||||
'@types/responselike@1.0.3':
|
||||
dependencies:
|
||||
'@types/node': 24.10.2
|
||||
|
||||
'@types/trusted-types@2.0.7': {}
|
||||
|
||||
'@types/verror@1.10.11':
|
||||
optional: true
|
||||
|
||||
@@ -3104,6 +5085,16 @@ snapshots:
|
||||
'@types/node': 24.10.2
|
||||
optional: true
|
||||
|
||||
'@vite-pwa/assets-generator@1.0.2':
|
||||
dependencies:
|
||||
cac: 6.7.14
|
||||
colorette: 2.0.20
|
||||
consola: 3.4.2
|
||||
sharp: 0.33.5
|
||||
sharp-ico: 0.1.5
|
||||
unconfig: 7.4.2
|
||||
optional: true
|
||||
|
||||
'@vitejs/plugin-vue@6.0.2(rolldown-vite@7.2.5(@types/node@24.10.2)(esbuild@0.25.12)(jiti@2.6.1)(terser@5.44.1))(vue@3.5.25(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@rolldown/pluginutils': 1.0.0-beta.50
|
||||
@@ -3247,8 +5238,7 @@ snapshots:
|
||||
|
||||
abbrev@1.1.1: {}
|
||||
|
||||
acorn@8.15.0:
|
||||
optional: true
|
||||
acorn@8.15.0: {}
|
||||
|
||||
agent-base@6.0.2:
|
||||
dependencies:
|
||||
@@ -3278,6 +5268,13 @@ snapshots:
|
||||
json-schema-traverse: 0.4.1
|
||||
uri-js: 4.4.1
|
||||
|
||||
ajv@8.17.1:
|
||||
dependencies:
|
||||
fast-deep-equal: 3.1.3
|
||||
fast-uri: 3.1.0
|
||||
json-schema-traverse: 1.0.0
|
||||
require-from-string: 2.0.2
|
||||
|
||||
alien-signals@3.1.1: {}
|
||||
|
||||
ansi-regex@5.0.1: {}
|
||||
@@ -3339,6 +5336,21 @@ snapshots:
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
array-buffer-byte-length@1.0.2:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
is-array-buffer: 3.0.5
|
||||
|
||||
arraybuffer.prototype.slice@1.0.4:
|
||||
dependencies:
|
||||
array-buffer-byte-length: 1.0.2
|
||||
call-bind: 1.0.8
|
||||
define-properties: 1.2.1
|
||||
es-abstract: 1.24.1
|
||||
es-errors: 1.3.0
|
||||
get-intrinsic: 1.3.0
|
||||
is-array-buffer: 3.0.5
|
||||
|
||||
assert-plus@1.0.0:
|
||||
optional: true
|
||||
|
||||
@@ -3347,12 +5359,42 @@ snapshots:
|
||||
|
||||
async-exit-hook@2.0.1: {}
|
||||
|
||||
async-function@1.0.0: {}
|
||||
|
||||
async@3.2.6: {}
|
||||
|
||||
asynckit@0.4.0: {}
|
||||
|
||||
at-least-node@1.0.0: {}
|
||||
|
||||
available-typed-arrays@1.0.7:
|
||||
dependencies:
|
||||
possible-typed-array-names: 1.1.0
|
||||
|
||||
babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.5):
|
||||
dependencies:
|
||||
'@babel/compat-data': 7.28.5
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5)
|
||||
semver: 6.3.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
babel-plugin-polyfill-corejs3@0.13.0(@babel/core@7.28.5):
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5)
|
||||
core-js-compat: 3.47.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
babel-plugin-polyfill-regenerator@0.6.5(@babel/core@7.28.5):
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
balanced-match@1.0.2: {}
|
||||
|
||||
base64-js@1.5.1: {}
|
||||
@@ -3467,6 +5509,18 @@ snapshots:
|
||||
es-errors: 1.3.0
|
||||
function-bind: 1.1.2
|
||||
|
||||
call-bind@1.0.8:
|
||||
dependencies:
|
||||
call-bind-apply-helpers: 1.0.2
|
||||
es-define-property: 1.0.1
|
||||
get-intrinsic: 1.3.0
|
||||
set-function-length: 1.2.2
|
||||
|
||||
call-bound@1.0.4:
|
||||
dependencies:
|
||||
call-bind-apply-helpers: 1.0.2
|
||||
get-intrinsic: 1.3.0
|
||||
|
||||
caniuse-lite@1.0.30001760: {}
|
||||
|
||||
chalk@4.1.2:
|
||||
@@ -3518,18 +5572,34 @@ snapshots:
|
||||
|
||||
color-name@1.1.4: {}
|
||||
|
||||
color-string@1.9.1:
|
||||
dependencies:
|
||||
color-name: 1.1.4
|
||||
simple-swizzle: 0.2.4
|
||||
optional: true
|
||||
|
||||
color@4.2.3:
|
||||
dependencies:
|
||||
color-convert: 2.0.1
|
||||
color-string: 1.9.1
|
||||
optional: true
|
||||
|
||||
colorette@2.0.20:
|
||||
optional: true
|
||||
|
||||
combined-stream@1.0.8:
|
||||
dependencies:
|
||||
delayed-stream: 1.0.0
|
||||
|
||||
commander@2.20.3:
|
||||
optional: true
|
||||
commander@2.20.3: {}
|
||||
|
||||
commander@5.1.0: {}
|
||||
|
||||
commander@9.5.0:
|
||||
optional: true
|
||||
|
||||
common-tags@1.8.2: {}
|
||||
|
||||
compare-version@0.1.2: {}
|
||||
|
||||
concat-map@0.0.1: {}
|
||||
@@ -3539,12 +5609,19 @@ snapshots:
|
||||
glob: 10.5.0
|
||||
typescript: 5.9.3
|
||||
|
||||
consola@3.4.2:
|
||||
optional: true
|
||||
|
||||
convert-source-map@2.0.0: {}
|
||||
|
||||
copy-anything@4.0.5:
|
||||
dependencies:
|
||||
is-what: 5.5.0
|
||||
|
||||
core-js-compat@3.47.0:
|
||||
dependencies:
|
||||
browserslist: 4.28.1
|
||||
|
||||
core-util-is@1.0.2:
|
||||
optional: true
|
||||
|
||||
@@ -3568,16 +5645,51 @@ snapshots:
|
||||
|
||||
crypto-js@4.2.0: {}
|
||||
|
||||
crypto-random-string@2.0.0: {}
|
||||
|
||||
csstype@3.2.3: {}
|
||||
|
||||
data-view-buffer@1.0.2:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
es-errors: 1.3.0
|
||||
is-data-view: 1.0.2
|
||||
|
||||
data-view-byte-length@1.0.2:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
es-errors: 1.3.0
|
||||
is-data-view: 1.0.2
|
||||
|
||||
data-view-byte-offset@1.0.1:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
es-errors: 1.3.0
|
||||
is-data-view: 1.0.2
|
||||
|
||||
debug@4.4.3:
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
|
||||
decode-bmp@0.2.1:
|
||||
dependencies:
|
||||
'@canvas/image-data': 1.1.0
|
||||
to-data-view: 1.1.0
|
||||
optional: true
|
||||
|
||||
decode-ico@0.4.1:
|
||||
dependencies:
|
||||
'@canvas/image-data': 1.1.0
|
||||
decode-bmp: 0.2.1
|
||||
to-data-view: 1.1.0
|
||||
optional: true
|
||||
|
||||
decompress-response@6.0.0:
|
||||
dependencies:
|
||||
mimic-response: 3.1.0
|
||||
|
||||
deepmerge@4.3.1: {}
|
||||
|
||||
defaults@1.0.4:
|
||||
dependencies:
|
||||
clone: 1.0.4
|
||||
@@ -3589,14 +5701,12 @@ snapshots:
|
||||
es-define-property: 1.0.1
|
||||
es-errors: 1.3.0
|
||||
gopd: 1.2.0
|
||||
optional: true
|
||||
|
||||
define-properties@1.2.1:
|
||||
dependencies:
|
||||
define-data-property: 1.1.4
|
||||
has-property-descriptors: 1.0.2
|
||||
object-keys: 1.1.1
|
||||
optional: true
|
||||
|
||||
defu@6.1.4: {}
|
||||
|
||||
@@ -3761,6 +5871,63 @@ snapshots:
|
||||
|
||||
err-code@2.0.3: {}
|
||||
|
||||
es-abstract@1.24.1:
|
||||
dependencies:
|
||||
array-buffer-byte-length: 1.0.2
|
||||
arraybuffer.prototype.slice: 1.0.4
|
||||
available-typed-arrays: 1.0.7
|
||||
call-bind: 1.0.8
|
||||
call-bound: 1.0.4
|
||||
data-view-buffer: 1.0.2
|
||||
data-view-byte-length: 1.0.2
|
||||
data-view-byte-offset: 1.0.1
|
||||
es-define-property: 1.0.1
|
||||
es-errors: 1.3.0
|
||||
es-object-atoms: 1.1.1
|
||||
es-set-tostringtag: 2.1.0
|
||||
es-to-primitive: 1.3.0
|
||||
function.prototype.name: 1.1.8
|
||||
get-intrinsic: 1.3.0
|
||||
get-proto: 1.0.1
|
||||
get-symbol-description: 1.1.0
|
||||
globalthis: 1.0.4
|
||||
gopd: 1.2.0
|
||||
has-property-descriptors: 1.0.2
|
||||
has-proto: 1.2.0
|
||||
has-symbols: 1.1.0
|
||||
hasown: 2.0.2
|
||||
internal-slot: 1.1.0
|
||||
is-array-buffer: 3.0.5
|
||||
is-callable: 1.2.7
|
||||
is-data-view: 1.0.2
|
||||
is-negative-zero: 2.0.3
|
||||
is-regex: 1.2.1
|
||||
is-set: 2.0.3
|
||||
is-shared-array-buffer: 1.0.4
|
||||
is-string: 1.1.1
|
||||
is-typed-array: 1.1.15
|
||||
is-weakref: 1.1.1
|
||||
math-intrinsics: 1.1.0
|
||||
object-inspect: 1.13.4
|
||||
object-keys: 1.1.1
|
||||
object.assign: 4.1.7
|
||||
own-keys: 1.0.1
|
||||
regexp.prototype.flags: 1.5.4
|
||||
safe-array-concat: 1.1.3
|
||||
safe-push-apply: 1.0.0
|
||||
safe-regex-test: 1.1.0
|
||||
set-proto: 1.0.0
|
||||
stop-iteration-iterator: 1.1.0
|
||||
string.prototype.trim: 1.2.10
|
||||
string.prototype.trimend: 1.0.9
|
||||
string.prototype.trimstart: 1.0.8
|
||||
typed-array-buffer: 1.0.3
|
||||
typed-array-byte-length: 1.0.3
|
||||
typed-array-byte-offset: 1.0.4
|
||||
typed-array-length: 1.0.7
|
||||
unbox-primitive: 1.1.0
|
||||
which-typed-array: 1.1.19
|
||||
|
||||
es-define-property@1.0.1: {}
|
||||
|
||||
es-errors@1.3.0: {}
|
||||
@@ -3776,6 +5943,12 @@ snapshots:
|
||||
has-tostringtag: 1.0.2
|
||||
hasown: 2.0.2
|
||||
|
||||
es-to-primitive@1.3.0:
|
||||
dependencies:
|
||||
is-callable: 1.2.7
|
||||
is-date-object: 1.1.0
|
||||
is-symbol: 1.1.1
|
||||
|
||||
es6-error@4.1.1:
|
||||
optional: true
|
||||
|
||||
@@ -3815,8 +5988,12 @@ snapshots:
|
||||
escape-string-regexp@4.0.0:
|
||||
optional: true
|
||||
|
||||
estree-walker@1.0.1: {}
|
||||
|
||||
estree-walker@2.0.2: {}
|
||||
|
||||
esutils@2.0.3: {}
|
||||
|
||||
etag@1.8.1: {}
|
||||
|
||||
exponential-backoff@3.1.3: {}
|
||||
@@ -3838,6 +6015,8 @@ snapshots:
|
||||
|
||||
fast-json-stable-stringify@2.1.0: {}
|
||||
|
||||
fast-uri@3.1.0: {}
|
||||
|
||||
fd-slicer@1.1.0:
|
||||
dependencies:
|
||||
pend: 1.2.0
|
||||
@@ -3863,6 +6042,10 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
for-each@0.3.5:
|
||||
dependencies:
|
||||
is-callable: 1.2.7
|
||||
|
||||
foreground-child@3.3.1:
|
||||
dependencies:
|
||||
cross-spawn: 7.0.6
|
||||
@@ -3876,6 +6059,12 @@ snapshots:
|
||||
hasown: 2.0.2
|
||||
mime-types: 2.1.35
|
||||
|
||||
framer-motion@12.23.12:
|
||||
dependencies:
|
||||
motion-dom: 12.23.12
|
||||
motion-utils: 12.23.6
|
||||
tslib: 2.8.1
|
||||
|
||||
fresh@2.0.0: {}
|
||||
|
||||
fs-extra@10.1.0:
|
||||
@@ -3920,6 +6109,19 @@ snapshots:
|
||||
|
||||
function-bind@1.1.2: {}
|
||||
|
||||
function.prototype.name@1.1.8:
|
||||
dependencies:
|
||||
call-bind: 1.0.8
|
||||
call-bound: 1.0.4
|
||||
define-properties: 1.2.1
|
||||
functions-have-names: 1.2.3
|
||||
hasown: 2.0.2
|
||||
is-callable: 1.2.7
|
||||
|
||||
functions-have-names@1.2.3: {}
|
||||
|
||||
generator-function@2.0.1: {}
|
||||
|
||||
gensync@1.0.0-beta.2: {}
|
||||
|
||||
get-caller-file@2.0.5: {}
|
||||
@@ -3937,6 +6139,8 @@ snapshots:
|
||||
hasown: 2.0.2
|
||||
math-intrinsics: 1.1.0
|
||||
|
||||
get-own-enumerable-property-symbols@3.0.2: {}
|
||||
|
||||
get-proto@1.0.1:
|
||||
dependencies:
|
||||
dunder-proto: 1.0.1
|
||||
@@ -3946,6 +6150,12 @@ snapshots:
|
||||
dependencies:
|
||||
pump: 3.0.3
|
||||
|
||||
get-symbol-description@1.1.0:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
es-errors: 1.3.0
|
||||
get-intrinsic: 1.3.0
|
||||
|
||||
glob@10.5.0:
|
||||
dependencies:
|
||||
foreground-child: 3.3.1
|
||||
@@ -3955,6 +6165,15 @@ snapshots:
|
||||
package-json-from-dist: 1.0.1
|
||||
path-scurry: 1.11.1
|
||||
|
||||
glob@11.1.0:
|
||||
dependencies:
|
||||
foreground-child: 3.3.1
|
||||
jackspeak: 4.1.1
|
||||
minimatch: 10.1.1
|
||||
minipass: 7.1.2
|
||||
package-json-from-dist: 1.0.1
|
||||
path-scurry: 2.0.1
|
||||
|
||||
glob@7.2.3:
|
||||
dependencies:
|
||||
fs.realpath: 1.0.0
|
||||
@@ -3986,7 +6205,6 @@ snapshots:
|
||||
dependencies:
|
||||
define-properties: 1.2.1
|
||||
gopd: 1.2.0
|
||||
optional: true
|
||||
|
||||
gopd@1.2.0: {}
|
||||
|
||||
@@ -4006,12 +6224,17 @@ snapshots:
|
||||
|
||||
graceful-fs@4.2.11: {}
|
||||
|
||||
has-bigints@1.1.0: {}
|
||||
|
||||
has-flag@4.0.0: {}
|
||||
|
||||
has-property-descriptors@1.0.2:
|
||||
dependencies:
|
||||
es-define-property: 1.0.1
|
||||
optional: true
|
||||
|
||||
has-proto@1.2.0:
|
||||
dependencies:
|
||||
dunder-proto: 1.0.1
|
||||
|
||||
has-symbols@1.1.0: {}
|
||||
|
||||
@@ -4023,6 +6246,8 @@ snapshots:
|
||||
dependencies:
|
||||
function-bind: 1.1.2
|
||||
|
||||
hey-listen@1.0.8: {}
|
||||
|
||||
hookable@5.5.3: {}
|
||||
|
||||
hosted-git-info@4.1.0:
|
||||
@@ -4077,6 +6302,9 @@ snapshots:
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
|
||||
ico-endec@0.1.6:
|
||||
optional: true
|
||||
|
||||
iconv-corefoundation@1.1.7:
|
||||
dependencies:
|
||||
cli-truncate: 2.1.0
|
||||
@@ -4087,6 +6315,8 @@ snapshots:
|
||||
dependencies:
|
||||
safer-buffer: 2.1.2
|
||||
|
||||
idb@7.1.1: {}
|
||||
|
||||
ieee754@1.2.1: {}
|
||||
|
||||
imurmurhash@0.1.4: {}
|
||||
@@ -4102,22 +6332,141 @@ snapshots:
|
||||
|
||||
inherits@2.0.4: {}
|
||||
|
||||
internal-slot@1.1.0:
|
||||
dependencies:
|
||||
es-errors: 1.3.0
|
||||
hasown: 2.0.2
|
||||
side-channel: 1.1.0
|
||||
|
||||
ip-address@10.1.0: {}
|
||||
|
||||
is-array-buffer@3.0.5:
|
||||
dependencies:
|
||||
call-bind: 1.0.8
|
||||
call-bound: 1.0.4
|
||||
get-intrinsic: 1.3.0
|
||||
|
||||
is-arrayish@0.3.4:
|
||||
optional: true
|
||||
|
||||
is-async-function@2.1.1:
|
||||
dependencies:
|
||||
async-function: 1.0.0
|
||||
call-bound: 1.0.4
|
||||
get-proto: 1.0.1
|
||||
has-tostringtag: 1.0.2
|
||||
safe-regex-test: 1.1.0
|
||||
|
||||
is-bigint@1.1.0:
|
||||
dependencies:
|
||||
has-bigints: 1.1.0
|
||||
|
||||
is-boolean-object@1.2.2:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
has-tostringtag: 1.0.2
|
||||
|
||||
is-callable@1.2.7: {}
|
||||
|
||||
is-ci@3.0.1:
|
||||
dependencies:
|
||||
ci-info: 3.9.0
|
||||
|
||||
is-core-module@2.16.1:
|
||||
dependencies:
|
||||
hasown: 2.0.2
|
||||
|
||||
is-data-view@1.0.2:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
get-intrinsic: 1.3.0
|
||||
is-typed-array: 1.1.15
|
||||
|
||||
is-date-object@1.1.0:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
has-tostringtag: 1.0.2
|
||||
|
||||
is-finalizationregistry@1.1.1:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
|
||||
is-fullwidth-code-point@3.0.0: {}
|
||||
|
||||
is-generator-function@1.1.2:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
generator-function: 2.0.1
|
||||
get-proto: 1.0.1
|
||||
has-tostringtag: 1.0.2
|
||||
safe-regex-test: 1.1.0
|
||||
|
||||
is-interactive@1.0.0: {}
|
||||
|
||||
is-lambda@1.0.1: {}
|
||||
|
||||
is-map@2.0.3: {}
|
||||
|
||||
is-module@1.0.0: {}
|
||||
|
||||
is-negative-zero@2.0.3: {}
|
||||
|
||||
is-number-object@1.1.1:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
has-tostringtag: 1.0.2
|
||||
|
||||
is-obj@1.0.1: {}
|
||||
|
||||
is-regex@1.2.1:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
gopd: 1.2.0
|
||||
has-tostringtag: 1.0.2
|
||||
hasown: 2.0.2
|
||||
|
||||
is-regexp@1.0.0: {}
|
||||
|
||||
is-set@2.0.3: {}
|
||||
|
||||
is-shared-array-buffer@1.0.4:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
|
||||
is-stream@2.0.1: {}
|
||||
|
||||
is-string@1.1.1:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
has-tostringtag: 1.0.2
|
||||
|
||||
is-symbol@1.1.1:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
has-symbols: 1.1.0
|
||||
safe-regex-test: 1.1.0
|
||||
|
||||
is-typed-array@1.1.15:
|
||||
dependencies:
|
||||
which-typed-array: 1.1.19
|
||||
|
||||
is-unicode-supported@0.1.0: {}
|
||||
|
||||
is-weakmap@2.0.2: {}
|
||||
|
||||
is-weakref@1.1.1:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
|
||||
is-weakset@2.0.4:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
get-intrinsic: 1.3.0
|
||||
|
||||
is-what@5.5.0: {}
|
||||
|
||||
isarray@2.0.5: {}
|
||||
|
||||
isbinaryfile@4.0.10: {}
|
||||
|
||||
isbinaryfile@5.0.7: {}
|
||||
@@ -4130,6 +6479,10 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@pkgjs/parseargs': 0.11.0
|
||||
|
||||
jackspeak@4.1.1:
|
||||
dependencies:
|
||||
'@isaacs/cliui': 8.0.2
|
||||
|
||||
jake@10.9.4:
|
||||
dependencies:
|
||||
async: 3.2.6
|
||||
@@ -4150,6 +6503,10 @@ snapshots:
|
||||
|
||||
json-schema-traverse@0.4.1: {}
|
||||
|
||||
json-schema-traverse@1.0.0: {}
|
||||
|
||||
json-schema@0.4.0: {}
|
||||
|
||||
json-stringify-safe@5.0.1:
|
||||
optional: true
|
||||
|
||||
@@ -4165,12 +6522,16 @@ snapshots:
|
||||
optionalDependencies:
|
||||
graceful-fs: 4.2.11
|
||||
|
||||
jsonpointer@5.0.1: {}
|
||||
|
||||
keyv@4.5.4:
|
||||
dependencies:
|
||||
json-buffer: 3.0.1
|
||||
|
||||
lazy-val@1.0.5: {}
|
||||
|
||||
leven@3.1.0: {}
|
||||
|
||||
lightningcss-android-arm64@1.30.2:
|
||||
optional: true
|
||||
|
||||
@@ -4220,6 +6581,10 @@ snapshots:
|
||||
lightningcss-win32-arm64-msvc: 1.30.2
|
||||
lightningcss-win32-x64-msvc: 1.30.2
|
||||
|
||||
lodash.debounce@4.0.8: {}
|
||||
|
||||
lodash.sortby@4.7.0: {}
|
||||
|
||||
lodash@4.17.21: {}
|
||||
|
||||
log-symbols@4.1.0:
|
||||
@@ -4231,6 +6596,8 @@ snapshots:
|
||||
|
||||
lru-cache@10.4.3: {}
|
||||
|
||||
lru-cache@11.2.4: {}
|
||||
|
||||
lru-cache@5.1.1:
|
||||
dependencies:
|
||||
yallist: 3.1.1
|
||||
@@ -4245,6 +6612,10 @@ snapshots:
|
||||
dependencies:
|
||||
vue: 3.5.25(typescript@5.9.3)
|
||||
|
||||
magic-string@0.25.9:
|
||||
dependencies:
|
||||
sourcemap-codec: 1.4.8
|
||||
|
||||
magic-string@0.30.21:
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.5.5
|
||||
@@ -4271,6 +6642,8 @@ snapshots:
|
||||
- bluebird
|
||||
- supports-color
|
||||
|
||||
marked@17.0.1: {}
|
||||
|
||||
matcher@3.0.0:
|
||||
dependencies:
|
||||
escape-string-regexp: 4.0.0
|
||||
@@ -4361,6 +6734,24 @@ snapshots:
|
||||
|
||||
mkdirp@1.0.4: {}
|
||||
|
||||
motion-dom@12.23.12:
|
||||
dependencies:
|
||||
motion-utils: 12.23.6
|
||||
|
||||
motion-utils@12.23.6: {}
|
||||
|
||||
motion-v@1.7.4(@vueuse/core@14.1.0(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3)):
|
||||
dependencies:
|
||||
'@vueuse/core': 14.1.0(vue@3.5.25(typescript@5.9.3))
|
||||
framer-motion: 12.23.12
|
||||
hey-listen: 1.0.8
|
||||
motion-dom: 12.23.12
|
||||
vue: 3.5.25(typescript@5.9.3)
|
||||
transitivePeerDependencies:
|
||||
- '@emotion/is-prop-valid'
|
||||
- react
|
||||
- react-dom
|
||||
|
||||
ms@2.1.3: {}
|
||||
|
||||
muggle-string@0.4.1: {}
|
||||
@@ -4388,8 +6779,18 @@ snapshots:
|
||||
|
||||
normalize-url@6.1.0: {}
|
||||
|
||||
object-keys@1.1.1:
|
||||
optional: true
|
||||
object-inspect@1.13.4: {}
|
||||
|
||||
object-keys@1.1.1: {}
|
||||
|
||||
object.assign@4.1.7:
|
||||
dependencies:
|
||||
call-bind: 1.0.8
|
||||
call-bound: 1.0.4
|
||||
define-properties: 1.2.1
|
||||
es-object-atoms: 1.1.1
|
||||
has-symbols: 1.1.0
|
||||
object-keys: 1.1.1
|
||||
|
||||
ohash@2.0.11: {}
|
||||
|
||||
@@ -4417,6 +6818,12 @@ snapshots:
|
||||
strip-ansi: 6.0.1
|
||||
wcwidth: 1.0.1
|
||||
|
||||
own-keys@1.0.1:
|
||||
dependencies:
|
||||
get-intrinsic: 1.3.0
|
||||
object-keys: 1.1.1
|
||||
safe-push-apply: 1.0.0
|
||||
|
||||
p-cancelable@2.1.1: {}
|
||||
|
||||
p-limit@3.1.0:
|
||||
@@ -4437,11 +6844,18 @@ snapshots:
|
||||
|
||||
path-key@3.1.1: {}
|
||||
|
||||
path-parse@1.0.7: {}
|
||||
|
||||
path-scurry@1.11.1:
|
||||
dependencies:
|
||||
lru-cache: 10.4.3
|
||||
minipass: 7.1.2
|
||||
|
||||
path-scurry@2.0.1:
|
||||
dependencies:
|
||||
lru-cache: 11.2.4
|
||||
minipass: 7.1.2
|
||||
|
||||
pe-library@0.4.1: {}
|
||||
|
||||
pend@1.2.0: {}
|
||||
@@ -4450,6 +6864,8 @@ snapshots:
|
||||
|
||||
picocolors@1.1.1: {}
|
||||
|
||||
picomatch@2.3.1: {}
|
||||
|
||||
picomatch@4.0.3: {}
|
||||
|
||||
pinia-plugin-persistedstate@4.7.1(pinia@3.0.4(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))):
|
||||
@@ -4471,6 +6887,8 @@ snapshots:
|
||||
base64-js: 1.5.1
|
||||
xmlbuilder: 15.1.1
|
||||
|
||||
possible-typed-array-names@1.1.0: {}
|
||||
|
||||
postcss@8.5.6:
|
||||
dependencies:
|
||||
nanoid: 3.3.11
|
||||
@@ -4482,6 +6900,10 @@ snapshots:
|
||||
commander: 9.5.0
|
||||
optional: true
|
||||
|
||||
pretty-bytes@5.6.0: {}
|
||||
|
||||
pretty-bytes@6.1.1: {}
|
||||
|
||||
proc-log@2.0.1: {}
|
||||
|
||||
progress@2.0.3: {}
|
||||
@@ -4500,8 +6922,15 @@ snapshots:
|
||||
|
||||
punycode@2.3.1: {}
|
||||
|
||||
quansync@1.0.0:
|
||||
optional: true
|
||||
|
||||
quick-lru@5.1.1: {}
|
||||
|
||||
randombytes@2.1.0:
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
|
||||
range-parser@1.2.1: {}
|
||||
|
||||
read-binary-file-arch@1.0.6:
|
||||
@@ -4516,6 +6945,47 @@ snapshots:
|
||||
string_decoder: 1.3.0
|
||||
util-deprecate: 1.0.2
|
||||
|
||||
reflect.getprototypeof@1.0.10:
|
||||
dependencies:
|
||||
call-bind: 1.0.8
|
||||
define-properties: 1.2.1
|
||||
es-abstract: 1.24.1
|
||||
es-errors: 1.3.0
|
||||
es-object-atoms: 1.1.1
|
||||
get-intrinsic: 1.3.0
|
||||
get-proto: 1.0.1
|
||||
which-builtin-type: 1.2.1
|
||||
|
||||
regenerate-unicode-properties@10.2.2:
|
||||
dependencies:
|
||||
regenerate: 1.4.2
|
||||
|
||||
regenerate@1.4.2: {}
|
||||
|
||||
regexp.prototype.flags@1.5.4:
|
||||
dependencies:
|
||||
call-bind: 1.0.8
|
||||
define-properties: 1.2.1
|
||||
es-errors: 1.3.0
|
||||
get-proto: 1.0.1
|
||||
gopd: 1.2.0
|
||||
set-function-name: 2.0.2
|
||||
|
||||
regexpu-core@6.4.0:
|
||||
dependencies:
|
||||
regenerate: 1.4.2
|
||||
regenerate-unicode-properties: 10.2.2
|
||||
regjsgen: 0.8.0
|
||||
regjsparser: 0.13.0
|
||||
unicode-match-property-ecmascript: 2.0.0
|
||||
unicode-match-property-value-ecmascript: 2.2.1
|
||||
|
||||
regjsgen@0.8.0: {}
|
||||
|
||||
regjsparser@0.13.0:
|
||||
dependencies:
|
||||
jsesc: 3.1.0
|
||||
|
||||
reka-ui@2.6.1(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)):
|
||||
dependencies:
|
||||
'@floating-ui/dom': 1.7.4
|
||||
@@ -4535,12 +7005,20 @@ snapshots:
|
||||
|
||||
require-directory@2.1.1: {}
|
||||
|
||||
require-from-string@2.0.2: {}
|
||||
|
||||
resedit@1.7.2:
|
||||
dependencies:
|
||||
pe-library: 0.4.1
|
||||
|
||||
resolve-alpn@1.2.1: {}
|
||||
|
||||
resolve@1.22.11:
|
||||
dependencies:
|
||||
is-core-module: 2.16.1
|
||||
path-parse: 1.0.7
|
||||
supports-preserve-symlinks-flag: 1.0.0
|
||||
|
||||
responselike@2.0.1:
|
||||
dependencies:
|
||||
lowercase-keys: 2.0.0
|
||||
@@ -4608,8 +7086,31 @@ snapshots:
|
||||
'@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.50
|
||||
'@rolldown/binding-win32-x64-msvc': 1.0.0-beta.50
|
||||
|
||||
rollup@2.79.2:
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
|
||||
safe-array-concat@1.1.3:
|
||||
dependencies:
|
||||
call-bind: 1.0.8
|
||||
call-bound: 1.0.4
|
||||
get-intrinsic: 1.3.0
|
||||
has-symbols: 1.1.0
|
||||
isarray: 2.0.5
|
||||
|
||||
safe-buffer@5.2.1: {}
|
||||
|
||||
safe-push-apply@1.0.0:
|
||||
dependencies:
|
||||
es-errors: 1.3.0
|
||||
isarray: 2.0.5
|
||||
|
||||
safe-regex-test@1.1.0:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
es-errors: 1.3.0
|
||||
is-regex: 1.2.1
|
||||
|
||||
safer-buffer@2.1.2: {}
|
||||
|
||||
sanitize-filename@1.6.3:
|
||||
@@ -4648,6 +7149,10 @@ snapshots:
|
||||
type-fest: 0.13.1
|
||||
optional: true
|
||||
|
||||
serialize-javascript@6.0.2:
|
||||
dependencies:
|
||||
randombytes: 2.1.0
|
||||
|
||||
serve-static@2.2.0:
|
||||
dependencies:
|
||||
encodeurl: 2.0.0
|
||||
@@ -4657,18 +7162,107 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
set-function-length@1.2.2:
|
||||
dependencies:
|
||||
define-data-property: 1.1.4
|
||||
es-errors: 1.3.0
|
||||
function-bind: 1.1.2
|
||||
get-intrinsic: 1.3.0
|
||||
gopd: 1.2.0
|
||||
has-property-descriptors: 1.0.2
|
||||
|
||||
set-function-name@2.0.2:
|
||||
dependencies:
|
||||
define-data-property: 1.1.4
|
||||
es-errors: 1.3.0
|
||||
functions-have-names: 1.2.3
|
||||
has-property-descriptors: 1.0.2
|
||||
|
||||
set-proto@1.0.0:
|
||||
dependencies:
|
||||
dunder-proto: 1.0.1
|
||||
es-errors: 1.3.0
|
||||
es-object-atoms: 1.1.1
|
||||
|
||||
setprototypeof@1.2.0: {}
|
||||
|
||||
sharp-ico@0.1.5:
|
||||
dependencies:
|
||||
decode-ico: 0.4.1
|
||||
ico-endec: 0.1.6
|
||||
sharp: 0.33.5
|
||||
optional: true
|
||||
|
||||
sharp@0.33.5:
|
||||
dependencies:
|
||||
color: 4.2.3
|
||||
detect-libc: 2.1.2
|
||||
semver: 7.7.3
|
||||
optionalDependencies:
|
||||
'@img/sharp-darwin-arm64': 0.33.5
|
||||
'@img/sharp-darwin-x64': 0.33.5
|
||||
'@img/sharp-libvips-darwin-arm64': 1.0.4
|
||||
'@img/sharp-libvips-darwin-x64': 1.0.4
|
||||
'@img/sharp-libvips-linux-arm': 1.0.5
|
||||
'@img/sharp-libvips-linux-arm64': 1.0.4
|
||||
'@img/sharp-libvips-linux-s390x': 1.0.4
|
||||
'@img/sharp-libvips-linux-x64': 1.0.4
|
||||
'@img/sharp-libvips-linuxmusl-arm64': 1.0.4
|
||||
'@img/sharp-libvips-linuxmusl-x64': 1.0.4
|
||||
'@img/sharp-linux-arm': 0.33.5
|
||||
'@img/sharp-linux-arm64': 0.33.5
|
||||
'@img/sharp-linux-s390x': 0.33.5
|
||||
'@img/sharp-linux-x64': 0.33.5
|
||||
'@img/sharp-linuxmusl-arm64': 0.33.5
|
||||
'@img/sharp-linuxmusl-x64': 0.33.5
|
||||
'@img/sharp-wasm32': 0.33.5
|
||||
'@img/sharp-win32-ia32': 0.33.5
|
||||
'@img/sharp-win32-x64': 0.33.5
|
||||
optional: true
|
||||
|
||||
shebang-command@2.0.0:
|
||||
dependencies:
|
||||
shebang-regex: 3.0.0
|
||||
|
||||
shebang-regex@3.0.0: {}
|
||||
|
||||
side-channel-list@1.0.0:
|
||||
dependencies:
|
||||
es-errors: 1.3.0
|
||||
object-inspect: 1.13.4
|
||||
|
||||
side-channel-map@1.0.1:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
es-errors: 1.3.0
|
||||
get-intrinsic: 1.3.0
|
||||
object-inspect: 1.13.4
|
||||
|
||||
side-channel-weakmap@1.0.2:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
es-errors: 1.3.0
|
||||
get-intrinsic: 1.3.0
|
||||
object-inspect: 1.13.4
|
||||
side-channel-map: 1.0.1
|
||||
|
||||
side-channel@1.1.0:
|
||||
dependencies:
|
||||
es-errors: 1.3.0
|
||||
object-inspect: 1.13.4
|
||||
side-channel-list: 1.0.0
|
||||
side-channel-map: 1.0.1
|
||||
side-channel-weakmap: 1.0.2
|
||||
|
||||
signal-exit@3.0.7: {}
|
||||
|
||||
signal-exit@4.1.0: {}
|
||||
|
||||
simple-swizzle@0.2.4:
|
||||
dependencies:
|
||||
is-arrayish: 0.3.4
|
||||
optional: true
|
||||
|
||||
simple-update-notifier@2.0.0:
|
||||
dependencies:
|
||||
semver: 7.7.3
|
||||
@@ -4682,6 +7276,8 @@ snapshots:
|
||||
|
||||
smart-buffer@4.2.0: {}
|
||||
|
||||
smob@1.5.0: {}
|
||||
|
||||
socks-proxy-agent@7.0.0:
|
||||
dependencies:
|
||||
agent-base: 6.0.2
|
||||
@@ -4704,6 +7300,12 @@ snapshots:
|
||||
|
||||
source-map@0.6.1: {}
|
||||
|
||||
source-map@0.8.0-beta.0:
|
||||
dependencies:
|
||||
whatwg-url: 7.1.0
|
||||
|
||||
sourcemap-codec@1.4.8: {}
|
||||
|
||||
speakingurl@14.0.1: {}
|
||||
|
||||
sprintf-js@1.1.3:
|
||||
@@ -4717,6 +7319,11 @@ snapshots:
|
||||
|
||||
statuses@2.0.2: {}
|
||||
|
||||
stop-iteration-iterator@1.1.0:
|
||||
dependencies:
|
||||
es-errors: 1.3.0
|
||||
internal-slot: 1.1.0
|
||||
|
||||
string-width@4.2.3:
|
||||
dependencies:
|
||||
emoji-regex: 8.0.0
|
||||
@@ -4729,10 +7336,55 @@ snapshots:
|
||||
emoji-regex: 9.2.2
|
||||
strip-ansi: 7.1.2
|
||||
|
||||
string.prototype.matchall@4.0.12:
|
||||
dependencies:
|
||||
call-bind: 1.0.8
|
||||
call-bound: 1.0.4
|
||||
define-properties: 1.2.1
|
||||
es-abstract: 1.24.1
|
||||
es-errors: 1.3.0
|
||||
es-object-atoms: 1.1.1
|
||||
get-intrinsic: 1.3.0
|
||||
gopd: 1.2.0
|
||||
has-symbols: 1.1.0
|
||||
internal-slot: 1.1.0
|
||||
regexp.prototype.flags: 1.5.4
|
||||
set-function-name: 2.0.2
|
||||
side-channel: 1.1.0
|
||||
|
||||
string.prototype.trim@1.2.10:
|
||||
dependencies:
|
||||
call-bind: 1.0.8
|
||||
call-bound: 1.0.4
|
||||
define-data-property: 1.1.4
|
||||
define-properties: 1.2.1
|
||||
es-abstract: 1.24.1
|
||||
es-object-atoms: 1.1.1
|
||||
has-property-descriptors: 1.0.2
|
||||
|
||||
string.prototype.trimend@1.0.9:
|
||||
dependencies:
|
||||
call-bind: 1.0.8
|
||||
call-bound: 1.0.4
|
||||
define-properties: 1.2.1
|
||||
es-object-atoms: 1.1.1
|
||||
|
||||
string.prototype.trimstart@1.0.8:
|
||||
dependencies:
|
||||
call-bind: 1.0.8
|
||||
define-properties: 1.2.1
|
||||
es-object-atoms: 1.1.1
|
||||
|
||||
string_decoder@1.3.0:
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
|
||||
stringify-object@3.3.0:
|
||||
dependencies:
|
||||
get-own-enumerable-property-symbols: 3.0.2
|
||||
is-obj: 1.0.1
|
||||
is-regexp: 1.0.0
|
||||
|
||||
strip-ansi@6.0.1:
|
||||
dependencies:
|
||||
ansi-regex: 5.0.1
|
||||
@@ -4741,6 +7393,8 @@ snapshots:
|
||||
dependencies:
|
||||
ansi-regex: 6.2.2
|
||||
|
||||
strip-comments@2.0.1: {}
|
||||
|
||||
sumchecker@3.0.1:
|
||||
dependencies:
|
||||
debug: 4.4.3
|
||||
@@ -4755,6 +7409,8 @@ snapshots:
|
||||
dependencies:
|
||||
has-flag: 4.0.0
|
||||
|
||||
supports-preserve-symlinks-flag@1.0.0: {}
|
||||
|
||||
tailwind-merge@3.4.0: {}
|
||||
|
||||
tailwindcss@4.1.17: {}
|
||||
@@ -4770,6 +7426,8 @@ snapshots:
|
||||
mkdirp: 1.0.4
|
||||
yallist: 4.0.0
|
||||
|
||||
temp-dir@2.0.0: {}
|
||||
|
||||
temp-file@3.4.0:
|
||||
dependencies:
|
||||
async-exit-hook: 2.0.1
|
||||
@@ -4780,13 +7438,19 @@ snapshots:
|
||||
mkdirp: 0.5.6
|
||||
rimraf: 2.6.3
|
||||
|
||||
tempy@0.6.0:
|
||||
dependencies:
|
||||
is-stream: 2.0.1
|
||||
temp-dir: 2.0.0
|
||||
type-fest: 0.16.0
|
||||
unique-string: 2.0.0
|
||||
|
||||
terser@5.44.1:
|
||||
dependencies:
|
||||
'@jridgewell/source-map': 0.3.11
|
||||
acorn: 8.15.0
|
||||
commander: 2.20.3
|
||||
source-map-support: 0.5.21
|
||||
optional: true
|
||||
|
||||
tiny-async-pool@1.3.0:
|
||||
dependencies:
|
||||
@@ -4803,8 +7467,15 @@ snapshots:
|
||||
|
||||
tmp@0.2.5: {}
|
||||
|
||||
to-data-view@1.1.0:
|
||||
optional: true
|
||||
|
||||
toidentifier@1.0.1: {}
|
||||
|
||||
tr46@1.0.1:
|
||||
dependencies:
|
||||
punycode: 2.3.1
|
||||
|
||||
truncate-utf8-bytes@1.0.2:
|
||||
dependencies:
|
||||
utf8-byte-length: 1.0.5
|
||||
@@ -4816,12 +7487,80 @@ snapshots:
|
||||
type-fest@0.13.1:
|
||||
optional: true
|
||||
|
||||
type-fest@0.16.0: {}
|
||||
|
||||
typed-array-buffer@1.0.3:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
es-errors: 1.3.0
|
||||
is-typed-array: 1.1.15
|
||||
|
||||
typed-array-byte-length@1.0.3:
|
||||
dependencies:
|
||||
call-bind: 1.0.8
|
||||
for-each: 0.3.5
|
||||
gopd: 1.2.0
|
||||
has-proto: 1.2.0
|
||||
is-typed-array: 1.1.15
|
||||
|
||||
typed-array-byte-offset@1.0.4:
|
||||
dependencies:
|
||||
available-typed-arrays: 1.0.7
|
||||
call-bind: 1.0.8
|
||||
for-each: 0.3.5
|
||||
gopd: 1.2.0
|
||||
has-proto: 1.2.0
|
||||
is-typed-array: 1.1.15
|
||||
reflect.getprototypeof: 1.0.10
|
||||
|
||||
typed-array-length@1.0.7:
|
||||
dependencies:
|
||||
call-bind: 1.0.8
|
||||
for-each: 0.3.5
|
||||
gopd: 1.2.0
|
||||
is-typed-array: 1.1.15
|
||||
possible-typed-array-names: 1.1.0
|
||||
reflect.getprototypeof: 1.0.10
|
||||
|
||||
typescript@5.9.3: {}
|
||||
|
||||
unbox-primitive@1.1.0:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
has-bigints: 1.1.0
|
||||
has-symbols: 1.1.0
|
||||
which-boxed-primitive: 1.1.1
|
||||
|
||||
unconfig-core@7.4.2:
|
||||
dependencies:
|
||||
'@quansync/fs': 1.0.0
|
||||
quansync: 1.0.0
|
||||
optional: true
|
||||
|
||||
unconfig@7.4.2:
|
||||
dependencies:
|
||||
'@quansync/fs': 1.0.0
|
||||
defu: 6.1.4
|
||||
jiti: 2.6.1
|
||||
quansync: 1.0.0
|
||||
unconfig-core: 7.4.2
|
||||
optional: true
|
||||
|
||||
undici-types@6.21.0: {}
|
||||
|
||||
undici-types@7.16.0: {}
|
||||
|
||||
unicode-canonical-property-names-ecmascript@2.0.1: {}
|
||||
|
||||
unicode-match-property-ecmascript@2.0.0:
|
||||
dependencies:
|
||||
unicode-canonical-property-names-ecmascript: 2.0.1
|
||||
unicode-property-aliases-ecmascript: 2.2.0
|
||||
|
||||
unicode-match-property-value-ecmascript@2.2.1: {}
|
||||
|
||||
unicode-property-aliases-ecmascript@2.2.0: {}
|
||||
|
||||
unique-filename@2.0.1:
|
||||
dependencies:
|
||||
unique-slug: 3.0.0
|
||||
@@ -4830,10 +7569,16 @@ snapshots:
|
||||
dependencies:
|
||||
imurmurhash: 0.1.4
|
||||
|
||||
unique-string@2.0.0:
|
||||
dependencies:
|
||||
crypto-random-string: 2.0.0
|
||||
|
||||
universalify@0.1.2: {}
|
||||
|
||||
universalify@2.0.1: {}
|
||||
|
||||
upath@1.2.0: {}
|
||||
|
||||
update-browserslist-db@1.2.2(browserslist@4.28.1):
|
||||
dependencies:
|
||||
browserslist: 4.28.1
|
||||
@@ -4861,6 +7606,19 @@ snapshots:
|
||||
optionalDependencies:
|
||||
vite-plugin-electron-renderer: 0.14.6
|
||||
|
||||
vite-plugin-pwa@1.2.0(@vite-pwa/assets-generator@1.0.2)(rolldown-vite@7.2.5(@types/node@24.10.2)(esbuild@0.25.12)(jiti@2.6.1)(terser@5.44.1))(workbox-build@7.4.0)(workbox-window@7.4.0):
|
||||
dependencies:
|
||||
debug: 4.4.3
|
||||
pretty-bytes: 6.1.1
|
||||
tinyglobby: 0.2.15
|
||||
vite: rolldown-vite@7.2.5(@types/node@24.10.2)(esbuild@0.25.12)(jiti@2.6.1)(terser@5.44.1)
|
||||
workbox-build: 7.4.0
|
||||
workbox-window: 7.4.0
|
||||
optionalDependencies:
|
||||
'@vite-pwa/assets-generator': 1.0.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
vscode-uri@3.1.0: {}
|
||||
|
||||
vue-demi@0.14.10(vue@3.5.25(typescript@5.9.3)):
|
||||
@@ -4894,10 +7652,172 @@ snapshots:
|
||||
dependencies:
|
||||
defaults: 1.0.4
|
||||
|
||||
webidl-conversions@4.0.2: {}
|
||||
|
||||
whatwg-url@7.1.0:
|
||||
dependencies:
|
||||
lodash.sortby: 4.7.0
|
||||
tr46: 1.0.1
|
||||
webidl-conversions: 4.0.2
|
||||
|
||||
which-boxed-primitive@1.1.1:
|
||||
dependencies:
|
||||
is-bigint: 1.1.0
|
||||
is-boolean-object: 1.2.2
|
||||
is-number-object: 1.1.1
|
||||
is-string: 1.1.1
|
||||
is-symbol: 1.1.1
|
||||
|
||||
which-builtin-type@1.2.1:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
function.prototype.name: 1.1.8
|
||||
has-tostringtag: 1.0.2
|
||||
is-async-function: 2.1.1
|
||||
is-date-object: 1.1.0
|
||||
is-finalizationregistry: 1.1.1
|
||||
is-generator-function: 1.1.2
|
||||
is-regex: 1.2.1
|
||||
is-weakref: 1.1.1
|
||||
isarray: 2.0.5
|
||||
which-boxed-primitive: 1.1.1
|
||||
which-collection: 1.0.2
|
||||
which-typed-array: 1.1.19
|
||||
|
||||
which-collection@1.0.2:
|
||||
dependencies:
|
||||
is-map: 2.0.3
|
||||
is-set: 2.0.3
|
||||
is-weakmap: 2.0.2
|
||||
is-weakset: 2.0.4
|
||||
|
||||
which-typed-array@1.1.19:
|
||||
dependencies:
|
||||
available-typed-arrays: 1.0.7
|
||||
call-bind: 1.0.8
|
||||
call-bound: 1.0.4
|
||||
for-each: 0.3.5
|
||||
get-proto: 1.0.1
|
||||
gopd: 1.2.0
|
||||
has-tostringtag: 1.0.2
|
||||
|
||||
which@2.0.2:
|
||||
dependencies:
|
||||
isexe: 2.0.0
|
||||
|
||||
workbox-background-sync@7.4.0:
|
||||
dependencies:
|
||||
idb: 7.1.1
|
||||
workbox-core: 7.4.0
|
||||
|
||||
workbox-broadcast-update@7.4.0:
|
||||
dependencies:
|
||||
workbox-core: 7.4.0
|
||||
|
||||
workbox-build@7.4.0:
|
||||
dependencies:
|
||||
'@apideck/better-ajv-errors': 0.3.6(ajv@8.17.1)
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/preset-env': 7.28.5(@babel/core@7.28.5)
|
||||
'@babel/runtime': 7.28.4
|
||||
'@rollup/plugin-babel': 5.3.1(@babel/core@7.28.5)(rollup@2.79.2)
|
||||
'@rollup/plugin-node-resolve': 15.3.1(rollup@2.79.2)
|
||||
'@rollup/plugin-replace': 2.4.2(rollup@2.79.2)
|
||||
'@rollup/plugin-terser': 0.4.4(rollup@2.79.2)
|
||||
'@surma/rollup-plugin-off-main-thread': 2.2.3
|
||||
ajv: 8.17.1
|
||||
common-tags: 1.8.2
|
||||
fast-json-stable-stringify: 2.1.0
|
||||
fs-extra: 9.1.0
|
||||
glob: 11.1.0
|
||||
lodash: 4.17.21
|
||||
pretty-bytes: 5.6.0
|
||||
rollup: 2.79.2
|
||||
source-map: 0.8.0-beta.0
|
||||
stringify-object: 3.3.0
|
||||
strip-comments: 2.0.1
|
||||
tempy: 0.6.0
|
||||
upath: 1.2.0
|
||||
workbox-background-sync: 7.4.0
|
||||
workbox-broadcast-update: 7.4.0
|
||||
workbox-cacheable-response: 7.4.0
|
||||
workbox-core: 7.4.0
|
||||
workbox-expiration: 7.4.0
|
||||
workbox-google-analytics: 7.4.0
|
||||
workbox-navigation-preload: 7.4.0
|
||||
workbox-precaching: 7.4.0
|
||||
workbox-range-requests: 7.4.0
|
||||
workbox-recipes: 7.4.0
|
||||
workbox-routing: 7.4.0
|
||||
workbox-strategies: 7.4.0
|
||||
workbox-streams: 7.4.0
|
||||
workbox-sw: 7.4.0
|
||||
workbox-window: 7.4.0
|
||||
transitivePeerDependencies:
|
||||
- '@types/babel__core'
|
||||
- supports-color
|
||||
|
||||
workbox-cacheable-response@7.4.0:
|
||||
dependencies:
|
||||
workbox-core: 7.4.0
|
||||
|
||||
workbox-core@7.4.0: {}
|
||||
|
||||
workbox-expiration@7.4.0:
|
||||
dependencies:
|
||||
idb: 7.1.1
|
||||
workbox-core: 7.4.0
|
||||
|
||||
workbox-google-analytics@7.4.0:
|
||||
dependencies:
|
||||
workbox-background-sync: 7.4.0
|
||||
workbox-core: 7.4.0
|
||||
workbox-routing: 7.4.0
|
||||
workbox-strategies: 7.4.0
|
||||
|
||||
workbox-navigation-preload@7.4.0:
|
||||
dependencies:
|
||||
workbox-core: 7.4.0
|
||||
|
||||
workbox-precaching@7.4.0:
|
||||
dependencies:
|
||||
workbox-core: 7.4.0
|
||||
workbox-routing: 7.4.0
|
||||
workbox-strategies: 7.4.0
|
||||
|
||||
workbox-range-requests@7.4.0:
|
||||
dependencies:
|
||||
workbox-core: 7.4.0
|
||||
|
||||
workbox-recipes@7.4.0:
|
||||
dependencies:
|
||||
workbox-cacheable-response: 7.4.0
|
||||
workbox-core: 7.4.0
|
||||
workbox-expiration: 7.4.0
|
||||
workbox-precaching: 7.4.0
|
||||
workbox-routing: 7.4.0
|
||||
workbox-strategies: 7.4.0
|
||||
|
||||
workbox-routing@7.4.0:
|
||||
dependencies:
|
||||
workbox-core: 7.4.0
|
||||
|
||||
workbox-strategies@7.4.0:
|
||||
dependencies:
|
||||
workbox-core: 7.4.0
|
||||
|
||||
workbox-streams@7.4.0:
|
||||
dependencies:
|
||||
workbox-core: 7.4.0
|
||||
workbox-routing: 7.4.0
|
||||
|
||||
workbox-sw@7.4.0: {}
|
||||
|
||||
workbox-window@7.4.0:
|
||||
dependencies:
|
||||
'@types/trusted-types': 2.0.7
|
||||
workbox-core: 7.4.0
|
||||
|
||||
wrap-ansi@7.0.0:
|
||||
dependencies:
|
||||
ansi-styles: 4.3.0
|
||||
|
||||
1840
src/App.vue
1840
src/App.vue
@@ -1,7 +1,13 @@
|
||||
<template>
|
||||
<SidebarProvider :open="sidebarOpen" @update:open="sidebarOpen = $event">
|
||||
<!-- 首页:无侧边栏/头部 -->
|
||||
<template v-if="isHomePage">
|
||||
<RouterView />
|
||||
</template>
|
||||
|
||||
<!-- 其他页面:完整布局(含侧边栏) -->
|
||||
<SidebarProvider v-else :open="sidebarOpen" @update:open="handleSidebarOpenChange">
|
||||
<Sidebar collapsible="icon">
|
||||
<!-- Logo -->
|
||||
<!-- 标志 -->
|
||||
<SidebarHeader class="border-b">
|
||||
<div class="flex items-center justify-center p-4 group-data-[collapsible=icon]:p-2">
|
||||
<img src="@/assets/logo.svg" class="w-10 group-data-[collapsible=icon]:w-8" />
|
||||
@@ -13,15 +19,77 @@
|
||||
<!-- 星球信息 -->
|
||||
<SidebarGroup v-if="planet" class="border-b group-data-[collapsible=icon]:hidden">
|
||||
<div class="px-4 py-3 space-y-2 text-sm">
|
||||
<div>
|
||||
<p class="font-semibold mb-1">
|
||||
{{ planet.name }}
|
||||
<Badge v-if="planet.isMoon" variant="secondary" class="ml-1 text-xs">{{ t('planet.moon') }}</Badge>
|
||||
</p>
|
||||
<p class="text-muted-foreground text-xs">
|
||||
[{{ planet.position.galaxy }}:{{ planet.position.system }}:{{ planet.position.position }}]
|
||||
</p>
|
||||
</div>
|
||||
<!-- 星球切换器 -->
|
||||
<Popover>
|
||||
<PopoverTrigger as-child>
|
||||
<Button
|
||||
data-tutorial="planet-selector"
|
||||
variant="outline"
|
||||
class="w-full justify-between h-auto px-3 py-2.5 border-2 hover:bg-accent hover:border-primary transition-colors"
|
||||
>
|
||||
<div class="flex items-start gap-2.5 flex-1 min-w-0">
|
||||
<Globe class="h-5 w-5 flex-shrink-0 mt-0.5 text-primary" />
|
||||
<div class="flex-1 min-w-0 text-left">
|
||||
<div class="text-[10px] text-muted-foreground uppercase tracking-wider mb-0.5">
|
||||
{{ t('planet.currentPlanet') }}
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5 mb-0.5">
|
||||
<span class="truncate font-semibold text-sm">{{ planet.name }}</span>
|
||||
<Badge v-if="planet.isMoon" variant="secondary" class="text-[10px] px-1 py-0 h-4">
|
||||
{{ t('planet.moon') }}
|
||||
</Badge>
|
||||
</div>
|
||||
<div class="text-[11px] text-muted-foreground">
|
||||
[{{ planet.position.galaxy }}:{{ planet.position.system }}:{{ planet.position.position }}]
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ChevronsUpDown class="h-4 w-4 flex-shrink-0 text-muted-foreground ml-2" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-72 p-0" side="bottom" align="start">
|
||||
<div class="p-2">
|
||||
<div class="px-2 py-1.5 mb-1 text-xs font-semibold text-muted-foreground">
|
||||
{{ t('planet.switchPlanet') }}
|
||||
</div>
|
||||
<div class="space-y-0.5 max-h-80 overflow-y-auto">
|
||||
<div v-for="p in gameStore.player.planets" :key="p.id" class="flex items-center gap-1">
|
||||
<Button
|
||||
@click="switchToPlanet(p.id)"
|
||||
:variant="p.id === planet.id ? 'secondary' : 'ghost'"
|
||||
class="flex-1 justify-start h-auto py-2 px-2"
|
||||
size="sm"
|
||||
>
|
||||
<div class="flex items-start gap-2 w-full min-w-0">
|
||||
<Globe class="h-4 w-4 flex-shrink-0 mt-0.5" :class="p.id === planet.id ? 'text-primary' : ''" />
|
||||
<div class="flex-1 min-w-0 text-left">
|
||||
<div class="flex items-center gap-1.5 mb-0.5">
|
||||
<span class="truncate font-medium text-sm">{{ p.name }}</span>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
class="h-2 w-2 p-0 flex-shrink-0"
|
||||
@click.stop="openRenameDialog(p.id, p.name)"
|
||||
:title="t('planet.renamePlanet')"
|
||||
>
|
||||
<Pencil class="h-2 w-2" />
|
||||
</Button>
|
||||
<Badge v-if="p.isMoon" variant="outline" class="text-[10px] px-1 py-0 h-4">
|
||||
{{ t('planet.moon') }}
|
||||
</Badge>
|
||||
</div>
|
||||
<div class="text-[11px] text-muted-foreground">
|
||||
[{{ p.position.galaxy }}:{{ p.position.system }}:{{ p.position.position }}]
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
||||
<!-- 玩家积分显示 -->
|
||||
<div class="bg-muted/50 rounded-lg p-2">
|
||||
<div class="flex items-center justify-between">
|
||||
@@ -42,18 +110,35 @@
|
||||
</SidebarGroup>
|
||||
|
||||
<!-- 导航菜单 -->
|
||||
<SidebarGroup>
|
||||
<SidebarGroup data-tutorial="navigation">
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem v-for="item in navItems" :key="item.path">
|
||||
<SidebarMenuButton as-child :is-active="$route.path === item.path" :tooltip="item.name.value">
|
||||
<RouterLink :to="item.path">
|
||||
<component :is="item.icon" />
|
||||
<span>{{ item.name.value }}</span>
|
||||
<!-- 未读消息数量 -->
|
||||
<SidebarMenuBadge v-if="item.path === '/messages' && unreadMessagesCount > 0">
|
||||
{{ unreadMessagesCount }}
|
||||
</SidebarMenuBadge>
|
||||
</RouterLink>
|
||||
<SidebarMenuButton
|
||||
:data-nav-path="item.path"
|
||||
:is-active="$route.path === item.path"
|
||||
:tooltip="item.name.value"
|
||||
@click="handleNavClick(item.path, $event)"
|
||||
>
|
||||
<component :is="item.icon" />
|
||||
<span>{{ item.name.value }}</span>
|
||||
<!-- 未读消息数量 -->
|
||||
<SidebarMenuBadge
|
||||
v-if="item.path === '/messages' && unreadMessagesCount > 0"
|
||||
class="bg-destructive text-destructive-foreground"
|
||||
>
|
||||
{{ unreadMessagesCount }}
|
||||
</SidebarMenuBadge>
|
||||
<!-- 正在执行的舰队任务数量 -->
|
||||
<SidebarMenuBadge v-if="item.path === '/fleet' && activeFleetMissionsCount > 0" class="bg-primary text-primary-foreground">
|
||||
{{ activeFleetMissionsCount }}
|
||||
</SidebarMenuBadge>
|
||||
<!-- 未读外交报告数量 -->
|
||||
<SidebarMenuBadge
|
||||
v-if="item.path === '/diplomacy' && unreadDiplomaticReportsCount > 0"
|
||||
class="bg-destructive text-destructive-foreground"
|
||||
>
|
||||
{{ unreadDiplomaticReportsCount }}
|
||||
</SidebarMenuBadge>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
@@ -72,7 +157,11 @@
|
||||
<span>{{ localeNames[gameStore.locale] }}</span>
|
||||
</SidebarMenuButton>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-48 p-2" side="right" align="end">
|
||||
<PopoverContent
|
||||
class="w-48 p-2"
|
||||
:side="sidebarOpen || innerWidth < 768 ? 'top' : 'right'"
|
||||
:align="sidebarOpen || innerWidth < 768 ? 'center' : 'end'"
|
||||
>
|
||||
<div class="space-y-1">
|
||||
<Button
|
||||
v-for="locale in locales"
|
||||
@@ -111,132 +200,194 @@
|
||||
|
||||
<!-- 主内容区 -->
|
||||
<SidebarInset>
|
||||
<div class="flex flex-col h-full overflow-hidden">
|
||||
<!-- 顶部资源栏 -->
|
||||
<header v-if="planet" class="bg-card border-b px-4 sm:px-6 py-6.5 shadow-md">
|
||||
<div class="flex items-center justify-between gap-3 sm:gap-6">
|
||||
<!-- 汉堡菜单(移动端)- 左侧占位 -->
|
||||
<div class="lg:flex-1">
|
||||
<SidebarTrigger class="lg:hidden" />
|
||||
</div>
|
||||
<div class="flex flex-col h-full pt-[60px]">
|
||||
<!-- 顶部资源栏 - 固定定位 -->
|
||||
<header
|
||||
v-if="planet"
|
||||
class="fixed top-0 right-0 left-0 z-40 bg-card border-b px-4 sm:px-6 py-3 shadow-md"
|
||||
:class="sidebarOpen ? 'lg:left-[var(--sidebar-width)]' : 'lg:left-[var(--sidebar-width-icon)]'"
|
||||
>
|
||||
<div class="flex flex-col gap-3">
|
||||
<!-- 第一行:菜单、资源预览、状态 -->
|
||||
<div class="grid items-center gap-3 sm:gap-6" style="grid-template-columns: auto 1fr auto">
|
||||
<!-- 左侧:汉堡菜单(移动端)/ 占位(PC端) -->
|
||||
<div>
|
||||
<SidebarTrigger class="lg:hidden" data-tutorial="mobile-menu" />
|
||||
</div>
|
||||
|
||||
<!-- 资源显示 - PC端居中 -->
|
||||
<div class="flex items-center gap-3 sm:gap-6 flex-1 lg:flex-none overflow-x-auto lg:justify-center">
|
||||
<div v-for="resourceType in resourceTypes" :key="resourceType.key" class="flex items-center gap-1.5 sm:gap-2 flex-shrink-0">
|
||||
<ResourceIcon :type="resourceType.key" size="md" />
|
||||
<div class="min-w-0">
|
||||
<!-- 所有资源统一显示:当前值/容量 -->
|
||||
<p
|
||||
class="text-xs sm:text-sm font-medium truncate"
|
||||
:class="getResourceColor(planet.resources[resourceType.key], capacity?.[resourceType.key] || Infinity)"
|
||||
<!-- 资源显示 - PC端居中,移动端可折叠 -->
|
||||
<!-- 关键:min-w-0 + overflow-hidden,避免横向滚动内容溢出覆盖左侧菜单按钮 -->
|
||||
<div class="min-w-0 overflow-hidden">
|
||||
<div
|
||||
class="resource-bar flex items-center gap-3 sm:gap-6 justify-start sm:justify-center"
|
||||
:class="resourceBarExpanded ? 'hidden' : 'overflow-x-auto'"
|
||||
>
|
||||
<div
|
||||
v-for="resourceType in resourceTypes"
|
||||
:key="resourceType.key"
|
||||
class="flex items-center gap-1.5 sm:gap-2 flex-shrink-0"
|
||||
>
|
||||
{{ formatNumber(planet.resources[resourceType.key]) }} / {{ formatNumber(capacity?.[resourceType.key] || 0) }}
|
||||
</p>
|
||||
<p class="text-[10px] sm:text-xs text-muted-foreground truncate">
|
||||
+{{ formatNumber(Math.round((production?.[resourceType.key] || 0) / 60)) }}/{{ t('resources.perMinute') }}
|
||||
</p>
|
||||
<ResourceIcon :type="resourceType.key" size="md" />
|
||||
<div class="min-w-0">
|
||||
<!-- 电力显示净产量和效率 -->
|
||||
<template v-if="resourceType.key === 'energy'">
|
||||
<p
|
||||
class="text-xs sm:text-sm font-medium truncate"
|
||||
:class="netEnergy >= 0 ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400'"
|
||||
>
|
||||
{{ netEnergy >= 0 ? '+' : '' }}{{ formatNumber(netEnergy) }}
|
||||
</p>
|
||||
<p class="text-[10px] sm:text-xs text-muted-foreground truncate">
|
||||
{{ formatNumber(production?.energy || 0) }} / {{ formatNumber(energyConsumption) }}
|
||||
</p>
|
||||
</template>
|
||||
<!-- 其他资源统一显示:当前值/容量 -->
|
||||
<template v-else>
|
||||
<p
|
||||
class="text-xs sm:text-sm font-medium truncate"
|
||||
:class="getResourceColor(planet.resources[resourceType.key], capacity?.[resourceType.key] || Infinity)"
|
||||
>
|
||||
{{ formatNumber(planet.resources[resourceType.key]) }} /
|
||||
{{ formatNumber(capacity?.[resourceType.key] || 0) }}
|
||||
</p>
|
||||
<p class="text-[10px] sm:text-xs text-muted-foreground truncate">
|
||||
+{{ formatNumber(Math.round((production?.[resourceType.key] || 0) / 60)) }}/{{ t('resources.perMinute') }}
|
||||
</p>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧状态 - 右侧占位 -->
|
||||
<div class="flex items-center gap-2 sm:gap-4 flex-shrink-0 lg:flex-1 lg:justify-end">
|
||||
<!-- 建造队列状态 -->
|
||||
<div v-if="planet.buildQueue.length > 0" class="flex items-center gap-1.5 sm:gap-2 text-xs sm:text-sm">
|
||||
<div class="h-2 w-2 rounded-full bg-green-500 animate-pulse" />
|
||||
<span class="text-muted-foreground hidden sm:inline">{{ t('queue.building') }}</span>
|
||||
</div>
|
||||
<div v-if="gameStore.player.researchQueue.length > 0" class="flex items-center gap-1.5 sm:gap-2 text-xs sm:text-sm">
|
||||
<div class="h-2 w-2 rounded-full bg-blue-500 animate-pulse" />
|
||||
<span class="text-muted-foreground hidden sm:inline">{{ t('queue.researching') }}</span>
|
||||
<!-- 右侧:展开按钮(仅移动端) -->
|
||||
<div class="flex items-center gap-2 sm:gap-3 flex-shrink-0 justify-end">
|
||||
<!-- 移动端展开按钮 -->
|
||||
<Button @click="resourceBarExpanded = !resourceBarExpanded" variant="ghost" size="sm" class="lg:hidden h-8 w-8 p-0">
|
||||
<ChevronDown v-if="!resourceBarExpanded" class="h-4 w-4" />
|
||||
<ChevronUp v-else class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- 建造队列 -->
|
||||
<div
|
||||
v-if="planet && (planet.buildQueue.length > 0 || gameStore.player.researchQueue.length > 0)"
|
||||
class="bg-card border-b px-4 sm:px-6 py-4.5"
|
||||
<!-- 展开的资源详情(仅移动端且展开时显示) - absolute定位覆盖在内容上,带过渡动画 -->
|
||||
<Transition
|
||||
enter-active-class="transition-all duration-300 ease-out"
|
||||
enter-from-class="opacity-0 -translate-y-2"
|
||||
enter-to-class="opacity-100 translate-y-0"
|
||||
leave-active-class="transition-all duration-200 ease-in"
|
||||
leave-from-class="opacity-100 translate-y-0"
|
||||
leave-to-class="opacity-0 -translate-y-2"
|
||||
>
|
||||
<div class="space-y-3">
|
||||
<!-- 建造队列 -->
|
||||
<div v-for="item in planet.buildQueue" :key="item.id" class="space-y-1.5">
|
||||
<div class="flex items-center justify-between text-xs sm:text-sm gap-2">
|
||||
<div class="flex items-center gap-1.5 sm:gap-2 min-w-0 flex-1">
|
||||
<div class="h-2 w-2 rounded-full bg-green-500 animate-pulse flex-shrink-0" />
|
||||
<span class="font-medium truncate">{{ getItemName(item) }}</span>
|
||||
<span class="text-muted-foreground hidden sm:inline flex-shrink-0 text-[10px] sm:text-xs">
|
||||
<template v-if="item.type === 'ship' || item.type === 'defense'">
|
||||
→ {{ t('queue.quantity') }} {{ item.quantity }}
|
||||
</template>
|
||||
<template v-else>→ {{ t('queue.level') }} {{ item.targetLevel }}</template>
|
||||
</span>
|
||||
<div
|
||||
v-if="planet && resourceBarExpanded"
|
||||
class="fixed top-[60px] right-0 left-0 z-30 bg-card border-b px-4 py-3 shadow-md lg:hidden"
|
||||
:class="sidebarOpen ? 'lg:left-[var(--sidebar-width)]' : 'lg:left-[var(--sidebar-width-icon)]'"
|
||||
>
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<div v-for="resourceType in resourceTypes" :key="resourceType.key" class="bg-muted/50 rounded-lg p-2.5">
|
||||
<div class="flex items-center justify-center gap-2 mb-1.5">
|
||||
<ResourceIcon :type="resourceType.key" size="md" />
|
||||
<span class="text-xs font-medium text-muted-foreground">{{ t(`resources.${resourceType.key}`) }}</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 sm:gap-3 flex-shrink-0">
|
||||
<span class="text-muted-foreground text-[10px] sm:text-xs whitespace-nowrap">
|
||||
{{ formatTime(getRemainingTime(item)) }}
|
||||
</span>
|
||||
<Button
|
||||
@click="handleCancelBuild(item.id)"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
class="h-5 sm:h-6 px-1.5 sm:px-2 text-[10px] sm:text-xs"
|
||||
>
|
||||
{{ t('queue.cancel') }}
|
||||
</Button>
|
||||
<div class="space-y-0.5 text-center">
|
||||
<!-- 电力显示净产量和效率 -->
|
||||
<template v-if="resourceType.key === 'energy'">
|
||||
<p
|
||||
class="text-sm font-semibold"
|
||||
:class="netEnergy >= 0 ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400'"
|
||||
>
|
||||
{{ netEnergy >= 0 ? '+' : '' }}{{ formatNumber(netEnergy) }}
|
||||
</p>
|
||||
<p class="text-[10px] text-muted-foreground">
|
||||
{{ t('resources.production') }}: {{ formatNumber(production?.energy || 0) }} / {{ formatNumber(energyConsumption) }}
|
||||
</p>
|
||||
</template>
|
||||
<!-- 其他资源统一显示:当前值/容量 -->
|
||||
<template v-else>
|
||||
<p
|
||||
class="text-sm font-semibold"
|
||||
:class="getResourceColor(planet.resources[resourceType.key], capacity?.[resourceType.key] || Infinity)"
|
||||
>
|
||||
{{ formatNumber(planet.resources[resourceType.key]) }}
|
||||
</p>
|
||||
<p class="text-[10px] text-muted-foreground">
|
||||
{{ t('resources.capacity') }}: {{ formatNumber(capacity?.[resourceType.key] || 0) }}
|
||||
</p>
|
||||
<p class="text-[10px] text-muted-foreground">
|
||||
{{ t('resources.production') }}: +{{ formatNumber(Math.round((production?.[resourceType.key] || 0) / 60)) }}/{{
|
||||
t('resources.perMinute')
|
||||
}}
|
||||
</p>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<Progress :model-value="getQueueProgress(item)" class="h-1.5" />
|
||||
</div>
|
||||
<!-- 研究队列 -->
|
||||
<div v-for="item in gameStore.player.researchQueue" :key="item.id" class="space-y-1.5">
|
||||
<div class="flex items-center justify-between text-xs sm:text-sm gap-2">
|
||||
<div class="flex items-center gap-1.5 sm:gap-2 min-w-0 flex-1">
|
||||
<div class="h-2 w-2 rounded-full bg-blue-500 animate-pulse flex-shrink-0" />
|
||||
<span class="font-medium truncate">{{ getItemName(item) }}</span>
|
||||
<span class="text-muted-foreground hidden sm:inline flex-shrink-0 text-[10px] sm:text-xs">
|
||||
→ {{ t('queue.level') }} {{ item.targetLevel }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 sm:gap-3 flex-shrink-0">
|
||||
<span class="text-muted-foreground text-[10px] sm:text-xs whitespace-nowrap">
|
||||
{{ formatTime(getRemainingTime(item)) }}
|
||||
</span>
|
||||
<Button
|
||||
@click="handleCancelResearch(item.id)"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
class="h-5 sm:h-6 px-1.5 sm:px-2 text-[10px] sm:text-xs"
|
||||
>
|
||||
{{ t('queue.cancel') }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<Progress :model-value="getQueueProgress(item)" class="h-1.5" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
|
||||
<!-- 即将到来的敌对舰队警告 -->
|
||||
<IncomingFleetAlerts @open-panel="openEnemyAlertPanel" />
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<main class="flex-1 overflow-y-auto">
|
||||
<div class="animate-fade-in">
|
||||
<RouterView />
|
||||
</div>
|
||||
<main class="flex-1">
|
||||
<Transition name="page" mode="out-in">
|
||||
<div :key="$route.fullPath" class="h-full">
|
||||
<!-- 背景动画开启时 -->
|
||||
<template v-if="gameStore.player.backgroundEnabled">
|
||||
<StarsBackground v-if="isDark" :factor="0.05" :speed="50" star-color="#fff" class="h-full">
|
||||
<div class="relative z-10 h-full">
|
||||
<RouterView />
|
||||
</div>
|
||||
</StarsBackground>
|
||||
|
||||
<div v-else class="relative h-full w-full overflow-hidden">
|
||||
<div class="relative z-10 h-full">
|
||||
<RouterView />
|
||||
</div>
|
||||
|
||||
<ParticlesBg class="absolute inset-0 z-0" :quantity="100" :ease="100" color="#000" :staticity="10" refresh />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 背景动画关闭时 -->
|
||||
<div v-else class="h-full">
|
||||
<RouterView />
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</main>
|
||||
</div>
|
||||
</SidebarInset>
|
||||
|
||||
<!-- 右下角固定通知按钮 -->
|
||||
<div class="fixed bottom-4 right-4 z-50 flex flex-col gap-2">
|
||||
<!-- 返回顶部 -->
|
||||
<BackToTop />
|
||||
|
||||
<!-- 队列通知 -->
|
||||
<QueueNotifications />
|
||||
|
||||
<!-- 外交通知 -->
|
||||
<DiplomaticNotifications />
|
||||
|
||||
<!-- 敌方警报 -->
|
||||
<EnemyAlertNotifications ref="enemyAlertNotificationsRef" />
|
||||
</div>
|
||||
|
||||
<!-- 确认对话框 -->
|
||||
<AlertDialog :open="confirmDialogOpen" @update:open="confirmDialogOpen = $event">
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>{{ confirmDialogTitle }}</AlertDialogTitle>
|
||||
<AlertDialogDescription>{{ confirmDialogMessage }}</AlertDialogDescription>
|
||||
<AlertDialogDescription class="whitespace-pre-line">
|
||||
{{ confirmDialogMessage }}
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>{{ t('common.cancel') }}</AlertDialogCancel>
|
||||
<AlertDialogAction @click="handleConfirmAction">{{ t('common.confirm') }}</AlertDialogAction>
|
||||
<AlertDialogAction @click="handleConfirmDialogConfirm">{{ t('common.confirm') }}</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
@@ -244,22 +395,57 @@
|
||||
<!-- 详情弹窗 -->
|
||||
<DetailDialog />
|
||||
|
||||
<!-- 更新弹窗 -->
|
||||
<UpdateDialog v-model:open="showUpdateDialog" :version-info="updateInfo" />
|
||||
|
||||
<!-- 弱引导提示系统 -->
|
||||
<HintToast />
|
||||
|
||||
<!-- Toast 通知 -->
|
||||
<Sonner position="top-center" />
|
||||
|
||||
<!-- 重命名星球对话框 -->
|
||||
<Dialog v-model:open="renameDialogOpen">
|
||||
<DialogContent class="sm:max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ t('planet.renamePlanetTitle') }}</DialogTitle>
|
||||
<DialogDescription class="sr-only">{{ t('planet.renamePlanetTitle') }}</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div class="py-4">
|
||||
<Input v-model="newPlanetName" :placeholder="t('planet.planetNamePlaceholder')" @keyup.enter="confirmRenamePlanet" />
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" @click="renameDialogOpen = false">
|
||||
{{ t('common.cancel') }}
|
||||
</Button>
|
||||
<Button @click="confirmRenamePlanet" :disabled="!newPlanetName.trim()">
|
||||
{{ t('planet.rename') }}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</SidebarProvider>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, onUnmounted, computed, ref } from 'vue'
|
||||
import { RouterView, RouterLink } from 'vue-router'
|
||||
import { onMounted, onUnmounted, computed, ref, watch } from 'vue'
|
||||
import { RouterView, useRouter } from 'vue-router'
|
||||
import { useGameStore } from '@/stores/gameStore'
|
||||
import { useUniverseStore } from '@/stores/universeStore'
|
||||
import { useNPCStore } from '@/stores/npcStore'
|
||||
import { useTheme } from '@/composables/useTheme'
|
||||
import { useI18n } from '@/composables/useI18n'
|
||||
import { useGameConfig } from '@/composables/useGameConfig'
|
||||
import { localeNames, detectBrowserLocale, type Locale } from '@/locales'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Progress } from '@/components/ui/progress'
|
||||
import { Popover, PopoverTrigger, PopoverContent } from '@/components/ui/popover'
|
||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import IncomingFleetAlerts from '@/components/IncomingFleetAlerts.vue'
|
||||
import DiplomaticNotifications from '@/components/DiplomaticNotifications.vue'
|
||||
import EnemyAlertNotifications from '@/components/EnemyAlertNotifications.vue'
|
||||
import QueueNotifications from '@/components/QueueNotifications.vue'
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
@@ -275,8 +461,6 @@
|
||||
SidebarTrigger
|
||||
} from '@/components/ui/sidebar'
|
||||
import ResourceIcon from '@/components/ResourceIcon.vue'
|
||||
import DetailDialog from '@/components/DetailDialog.vue'
|
||||
import Sonner from '@/components/ui/sonner/Sonner.vue'
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
@@ -287,7 +471,17 @@
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle
|
||||
} from '@/components/ui/alert-dialog'
|
||||
import { formatNumber, formatTime, getResourceColor } from '@/utils/format'
|
||||
import DetailDialog from '@/components/DetailDialog.vue'
|
||||
import UpdateDialog from '@/components/UpdateDialog.vue'
|
||||
import HintToast from '@/components/HintToast.vue'
|
||||
import BackToTop from '@/components/BackToTop.vue'
|
||||
import Sonner from '@/components/ui/sonner/Sonner.vue'
|
||||
import { MissionType, BuildingType, TechnologyType, DiplomaticEventType } from '@/types/game'
|
||||
import type { FleetMission, NPC, MissileAttack } from '@/types/game'
|
||||
import { DIPLOMATIC_CONFIG } from '@/config/gameConfig'
|
||||
import type { VersionInfo } from '@/utils/versionCheck'
|
||||
import { formatNumber, getResourceColor } from '@/utils/format'
|
||||
import { scaleNumber, scaleResources } from '@/utils/speed'
|
||||
import {
|
||||
Moon,
|
||||
Sun,
|
||||
@@ -304,122 +498,87 @@
|
||||
Languages,
|
||||
Settings,
|
||||
Wrench,
|
||||
ChevronsLeft
|
||||
ChevronsLeft,
|
||||
ChevronsUpDown,
|
||||
ChevronDown,
|
||||
ChevronUp,
|
||||
Handshake,
|
||||
Pencil
|
||||
} from 'lucide-vue-next'
|
||||
import * as gameLogic from '@/logic/gameLogic'
|
||||
import * as planetLogic from '@/logic/planetLogic'
|
||||
import * as officerLogic from '@/logic/officerLogic'
|
||||
import * as buildingValidation from '@/logic/buildingValidation'
|
||||
import * as resourceLogic from '@/logic/resourceLogic'
|
||||
import { useGameLifecycle } from '@/composables/useGameLifecycle'
|
||||
import { useMissionHandler } from '@/composables/useMissionHandler'
|
||||
import { useNPCHandler } from '@/composables/useNPCHandler'
|
||||
import { useQueueHandler } from '@/composables/useQueueHandler'
|
||||
import { useGameUpdate } from '@/composables/useGameUpdate'
|
||||
import { migrateGameData } from '@/utils/migration'
|
||||
import * as researchValidation from '@/logic/researchValidation'
|
||||
import * as fleetLogic from '@/logic/fleetLogic'
|
||||
import * as shipLogic from '@/logic/shipLogic'
|
||||
import * as npcGrowthLogic from '@/logic/npcGrowthLogic'
|
||||
import * as npcBehaviorLogic from '@/logic/npcBehaviorLogic'
|
||||
import * as diplomaticLogic from '@/logic/diplomaticLogic'
|
||||
import * as publicLogic from '@/logic/publicLogic'
|
||||
import pkg from '../package.json'
|
||||
import { toast } from 'vue-sonner'
|
||||
import { migrateGameData } from '@/utils/migration'
|
||||
import { checkLatestVersion } from '@/utils/versionCheck'
|
||||
import { StarsBackground } from '@/components/ui/bg-stars'
|
||||
import { ParticlesBg } from '@/components/ui/particles-bg'
|
||||
|
||||
// 执行数据迁移(在 store 初始化之前)
|
||||
migrateGameData()
|
||||
|
||||
const router = useRouter()
|
||||
const gameStore = useGameStore()
|
||||
const universeStore = useUniverseStore()
|
||||
const npcStore = useNPCStore()
|
||||
const { isDark } = useTheme()
|
||||
const { t } = useI18n()
|
||||
const { BUILDINGS, TECHNOLOGIES } = useGameConfig()
|
||||
const enemyAlertNotificationsRef = ref<InstanceType<typeof EnemyAlertNotifications> | null>(null)
|
||||
// ConfirmDialog 状态
|
||||
const confirmDialogOpen = ref(false)
|
||||
const confirmDialogTitle = ref('')
|
||||
const confirmDialogMessage = ref('')
|
||||
const innerWidth = computed(() => window.innerWidth)
|
||||
const confirmDialogAction = ref<(() => void) | null>(null)
|
||||
// 更新弹窗状态
|
||||
const showUpdateDialog = ref(false)
|
||||
const updateInfo = ref<VersionInfo | null>(null)
|
||||
// 所有可用的语言选项
|
||||
const locales: Locale[] = ['zh-CN', 'zh-TW', 'en', 'de', 'ru', 'ko', 'ja']
|
||||
|
||||
// 侧边栏状态(不持久化,根据屏幕尺寸初始化)
|
||||
// PC端(≥1024px)默认打开,移动端默认关闭
|
||||
const sidebarOpen = ref(window.innerWidth >= 1024)
|
||||
|
||||
// 初始化 composables
|
||||
const { initGame } = useGameLifecycle()
|
||||
|
||||
const { processMissionArrival, processMissionReturn } = useMissionHandler(t)
|
||||
|
||||
const { processNPCMissionArrival, processNPCMissionReturn, updateNPCGrowth, updateNPCBehavior } = useNPCHandler()
|
||||
|
||||
const { handleCancelBuild, handleCancelResearch, getItemName, getRemainingTime, getQueueProgress } = useQueueHandler(
|
||||
t,
|
||||
confirmDialogOpen,
|
||||
confirmDialogTitle,
|
||||
confirmDialogMessage,
|
||||
confirmDialogAction
|
||||
)
|
||||
|
||||
const { updateGame } = useGameUpdate(
|
||||
processMissionArrival,
|
||||
processMissionReturn,
|
||||
processNPCMissionArrival,
|
||||
processNPCMissionReturn,
|
||||
updateNPCGrowth,
|
||||
updateNPCBehavior
|
||||
)
|
||||
// 移动端资源栏展开状态
|
||||
const resourceBarExpanded = ref(false)
|
||||
const npcUpdateCounter = ref(0) // 累计秒数
|
||||
const NPC_UPDATE_INTERVAL = 5 // 每1秒更新一次NPC,确保发育速度与玩家相当
|
||||
// NPC行为系统更新函数(侦查和攻击决策)
|
||||
const npcBehaviorCounter = ref(0)
|
||||
const NPC_BEHAVIOR_INTERVAL = 5 // 每5秒检查一次NPC行为
|
||||
|
||||
// 游戏循环定时器
|
||||
let gameLoop: ReturnType<typeof setInterval> | null = null
|
||||
const gameLoop = ref<ReturnType<typeof setInterval> | null>(null)
|
||||
const pointsUpdateInterval = ref<ReturnType<typeof setInterval> | null>(null)
|
||||
const konamiCleanup = ref<(() => void) | null>(null)
|
||||
const versionCheckInterval = ref<ReturnType<typeof setInterval> | null>(null) // 重命名星球相关状态
|
||||
const renameDialogOpen = ref(false)
|
||||
const renamingPlanetId = ref<string | null>(null)
|
||||
const newPlanetName = ref('')
|
||||
// 功能解锁要求配置
|
||||
const featureRequirements: Record<string, { building: BuildingType; level: number }> = {
|
||||
'/research': { building: BuildingType.ResearchLab, level: 1 },
|
||||
'/shipyard': { building: BuildingType.Shipyard, level: 1 },
|
||||
'/defense': { building: BuildingType.Shipyard, level: 1 },
|
||||
'/fleet': { building: BuildingType.Shipyard, level: 1 }
|
||||
}
|
||||
|
||||
// 清理定时器
|
||||
onUnmounted(() => {
|
||||
if (gameLoop) clearInterval(gameLoop)
|
||||
})
|
||||
|
||||
// 初始化游戏
|
||||
onMounted(async () => {
|
||||
// 如果是首次访问(没有星球数据),使用浏览器语言自动检测
|
||||
const isFirstVisit = gameStore.player.planets.length === 0
|
||||
if (isFirstVisit) {
|
||||
gameStore.locale = detectBrowserLocale()
|
||||
}
|
||||
await initGame(t('common.playerName'), t('planet.homePlanet'), t('planet.planetPrefix'))
|
||||
// 启动游戏循环
|
||||
gameLoop = setInterval(() => {
|
||||
updateGame()
|
||||
}, 1000) // 每1秒更新一次
|
||||
})
|
||||
// 判断是否为首页
|
||||
const isHomePage = computed(() => router.currentRoute.value.path === '/')
|
||||
|
||||
// 定义 planet computed(需要在 watch 之前定义)
|
||||
const planet = computed(() => gameStore.currentPlanet)
|
||||
|
||||
const navItems = [
|
||||
{ name: computed(() => t('nav.overview')), path: '/', icon: Home },
|
||||
{ name: computed(() => t('nav.buildings')), path: '/buildings', icon: Building2 },
|
||||
{ name: computed(() => t('nav.research')), path: '/research', icon: FlaskConical },
|
||||
{ name: computed(() => t('nav.shipyard')), path: '/shipyard', icon: Ship },
|
||||
{ name: computed(() => t('nav.defense')), path: '/defense', icon: Shield },
|
||||
{ name: computed(() => t('nav.fleet')), path: '/fleet', icon: Rocket },
|
||||
{ name: computed(() => t('nav.officers')), path: '/officers', icon: Users },
|
||||
{ name: computed(() => t('nav.simulator')), path: '/battle-simulator', icon: Swords },
|
||||
{ name: computed(() => t('nav.galaxy')), path: '/galaxy', icon: Globe },
|
||||
{ name: computed(() => t('nav.messages')), path: '/messages', icon: Mail },
|
||||
{ name: computed(() => t('nav.settings')), path: '/settings', icon: Settings },
|
||||
// GM菜单仅在开发模式下显示
|
||||
...(import.meta.env.DEV ? [{ name: computed(() => t('nav.gm')), path: '/gm', icon: Wrench }] : [])
|
||||
]
|
||||
|
||||
// 使用直接计算,不再缓存
|
||||
const production = computed(() => {
|
||||
if (!planet.value) return null
|
||||
const now = Date.now()
|
||||
const bonuses = officerLogic.calculateActiveBonuses(gameStore.player.officers, now)
|
||||
return resourceLogic.calculateResourceProduction(planet.value, {
|
||||
resourceProductionBonus: bonuses.resourceProductionBonus,
|
||||
darkMatterProductionBonus: bonuses.darkMatterProductionBonus,
|
||||
energyProductionBonus: bonuses.energyProductionBonus
|
||||
})
|
||||
})
|
||||
|
||||
const capacity = computed(() => {
|
||||
if (!planet.value) return null
|
||||
const now = Date.now()
|
||||
const bonuses = officerLogic.calculateActiveBonuses(gameStore.player.officers, now)
|
||||
return resourceLogic.calculateResourceCapacity(planet.value, bonuses.storageCapacityBonus)
|
||||
})
|
||||
|
||||
// 未读消息数量
|
||||
const unreadMessagesCount = computed(() => {
|
||||
const unreadBattles = gameStore.player.battleReports.filter(r => !r.read).length
|
||||
const unreadSpies = gameStore.player.spyReports.filter(r => !r.read).length
|
||||
return unreadBattles + unreadSpies
|
||||
})
|
||||
|
||||
// 资源类型配置
|
||||
const resourceTypes = [
|
||||
{ key: 'metal' as const },
|
||||
@@ -429,13 +588,1124 @@
|
||||
{ key: 'darkMatter' as const }
|
||||
]
|
||||
|
||||
const navItems = computed(() => [
|
||||
{ name: computed(() => t('nav.overview')), path: '/overview', icon: Home },
|
||||
{ name: computed(() => t('nav.buildings')), path: '/buildings', icon: Building2 },
|
||||
{ name: computed(() => t('nav.research')), path: '/research', icon: FlaskConical },
|
||||
{ name: computed(() => t('nav.shipyard')), path: '/shipyard', icon: Ship },
|
||||
{ name: computed(() => t('nav.defense')), path: '/defense', icon: Shield },
|
||||
{ name: computed(() => t('nav.fleet')), path: '/fleet', icon: Rocket },
|
||||
{ name: computed(() => t('nav.officers')), path: '/officers', icon: Users },
|
||||
{ name: computed(() => t('nav.simulator')), path: '/battle-simulator', icon: Swords },
|
||||
{ name: computed(() => t('nav.galaxy')), path: '/galaxy', icon: Globe },
|
||||
{ name: computed(() => t('nav.diplomacy')), path: '/diplomacy', icon: Handshake },
|
||||
{ name: computed(() => t('nav.messages')), path: '/messages', icon: Mail },
|
||||
{ name: computed(() => t('nav.settings')), path: '/settings', icon: Settings },
|
||||
// GM菜单在启用GM模式时显示
|
||||
...(gameStore.player.isGMEnabled ? [{ name: computed(() => t('nav.gm')), path: '/gm', icon: Wrench }] : [])
|
||||
])
|
||||
|
||||
// 使用直接计算,不再缓存
|
||||
const production = computed(() => {
|
||||
if (!planet.value) return null
|
||||
const now = Date.now()
|
||||
const bonuses = officerLogic.calculateActiveBonuses(gameStore.player.officers, now)
|
||||
const base = resourceLogic.calculateResourceProduction(planet.value, {
|
||||
resourceProductionBonus: bonuses.resourceProductionBonus,
|
||||
darkMatterProductionBonus: bonuses.darkMatterProductionBonus,
|
||||
energyProductionBonus: bonuses.energyProductionBonus
|
||||
})
|
||||
return scaleResources(base, gameStore.gameSpeed)
|
||||
})
|
||||
|
||||
const capacity = computed(() => {
|
||||
if (!planet.value) return null
|
||||
const now = Date.now()
|
||||
const bonuses = officerLogic.calculateActiveBonuses(gameStore.player.officers, now)
|
||||
return resourceLogic.calculateResourceCapacity(planet.value, bonuses.storageCapacityBonus)
|
||||
})
|
||||
|
||||
// 电力消耗
|
||||
const energyConsumption = computed(() => {
|
||||
if (!planet.value) return 0
|
||||
return scaleNumber(resourceLogic.calculateEnergyConsumption(planet.value), gameStore.gameSpeed)
|
||||
})
|
||||
|
||||
// 净电力(产量 - 消耗)
|
||||
const netEnergy = computed(() => {
|
||||
if (!planet.value || !production.value) return 0
|
||||
return production.value.energy - energyConsumption.value
|
||||
})
|
||||
|
||||
// 未读消息数量
|
||||
const unreadMessagesCount = computed(() => {
|
||||
const unreadBattles = gameStore.player.battleReports.filter(r => !r.read).length
|
||||
const unreadSpies = gameStore.player.spyReports.filter(r => !r.read).length
|
||||
const unreadSpied = gameStore.player.spiedNotifications?.filter(n => !n.read).length || 0
|
||||
const unreadMissions = gameStore.player.missionReports?.filter(r => !r.read).length || 0
|
||||
const unreadNPCActivity = gameStore.player.npcActivityNotifications?.filter(n => !n.read).length || 0
|
||||
const unreadGifts = gameStore.player.giftNotifications?.filter(n => !n.read).length || 0
|
||||
const unreadGiftRejected = gameStore.player.giftRejectedNotifications?.filter(n => !n.read).length || 0
|
||||
return unreadBattles + unreadSpies + unreadSpied + unreadMissions + unreadNPCActivity + unreadGifts + unreadGiftRejected
|
||||
})
|
||||
|
||||
// 正在执行的舰队任务数量(包括飞行中的导弹)
|
||||
const activeFleetMissionsCount = computed(() => {
|
||||
const fleetMissions = gameStore.player.fleetMissions.filter(m => m.status === 'outbound' || m.status === 'returning').length
|
||||
const flyingMissiles = gameStore.player.missileAttacks?.filter(m => m.status === 'flying').length || 0
|
||||
return fleetMissions + flyingMissiles
|
||||
})
|
||||
|
||||
// 未读外交报告数量
|
||||
const unreadDiplomaticReportsCount = computed(() => {
|
||||
return (gameStore.player.diplomaticReports || []).filter(r => !r.read).length
|
||||
})
|
||||
|
||||
// 月球相关
|
||||
const moon = computed(() => {
|
||||
if (!planet.value || planet.value.isMoon) return null
|
||||
return gameStore.getMoonForPlanet(planet.value.id)
|
||||
})
|
||||
|
||||
const hasMoon = computed(() => !!moon.value)
|
||||
|
||||
const handleNotification = (type: string, itemType: string, level?: number) => {
|
||||
const settings = gameStore.notificationSettings
|
||||
if (!settings) return
|
||||
|
||||
// 检查主开关
|
||||
if (!settings.browser && !settings.inApp) return
|
||||
|
||||
// 检查具体类型开关
|
||||
let typeKey: 'construction' | 'research'
|
||||
let title = ''
|
||||
let body = ''
|
||||
|
||||
if (type === 'building') {
|
||||
typeKey = 'construction'
|
||||
const buildingType = itemType as BuildingType
|
||||
const name = BUILDINGS.value[buildingType]?.name || itemType
|
||||
title = t('notifications.constructionComplete')
|
||||
body = `${name} Lv ${level}`
|
||||
} else if (type === 'technology') {
|
||||
typeKey = 'research'
|
||||
const technologyType = itemType as TechnologyType
|
||||
const name = TECHNOLOGIES.value[technologyType]?.name || itemType
|
||||
title = t('notifications.researchComplete')
|
||||
body = `${name} Lv ${level}`
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
if (!settings.types[typeKey]) return
|
||||
|
||||
// browser
|
||||
if (settings.browser && 'Notification' in window && Notification.permission === 'granted') {
|
||||
const shouldSuppress = settings.suppressInFocus && document.hasFocus()
|
||||
if (!shouldSuppress) {
|
||||
new Notification(title, { body, icon: '/favicon.ico' })
|
||||
}
|
||||
}
|
||||
|
||||
// toast
|
||||
if (settings.inApp) {
|
||||
toast.success(title, { description: body })
|
||||
}
|
||||
}
|
||||
|
||||
const handleConfirmDialogConfirm = () => {
|
||||
if (confirmDialogAction.value) {
|
||||
confirmDialogAction.value()
|
||||
}
|
||||
confirmDialogOpen.value = false
|
||||
}
|
||||
|
||||
const initGame = async () => {
|
||||
const shouldInit = gameLogic.shouldInitializeGame(gameStore.player.planets)
|
||||
if (!shouldInit) {
|
||||
const now = Date.now()
|
||||
|
||||
// 计算离线收益(直接同步计算,应用游戏速度)
|
||||
const bonuses = officerLogic.calculateActiveBonuses(gameStore.player.officers, now)
|
||||
gameStore.player.planets.forEach(planet => {
|
||||
resourceLogic.updatePlanetResources(planet, now, bonuses, gameStore.gameSpeed)
|
||||
})
|
||||
|
||||
// 只在没有NPC星球时才生成(首次加载已有玩家数据时)
|
||||
if (Object.keys(universeStore.planets).length === 0) {
|
||||
generateNPCPlanets()
|
||||
}
|
||||
|
||||
// 初始化或更新玩家积分
|
||||
gameStore.player.points = publicLogic.calculatePlayerPoints(gameStore.player)
|
||||
|
||||
return
|
||||
}
|
||||
gameStore.player = gameLogic.initializePlayer(gameStore.player.id, t('common.playerName'))
|
||||
const initialPlanet = planetLogic.createInitialPlanet(gameStore.player.id, t('planet.homePlanet'))
|
||||
gameStore.player.planets = [initialPlanet]
|
||||
gameStore.currentPlanetId = initialPlanet.id
|
||||
// 新玩家初始化时生成NPC星球
|
||||
generateNPCPlanets()
|
||||
// 初始化玩家积分
|
||||
gameStore.player.points = publicLogic.calculatePlayerPoints(gameStore.player)
|
||||
}
|
||||
|
||||
const generateNPCPlanets = () => {
|
||||
const npcCount = 200
|
||||
for (let i = 0; i < npcCount; i++) {
|
||||
const position = gameLogic.generateRandomPosition()
|
||||
const key = gameLogic.generatePositionKey(position.galaxy, position.system, position.position)
|
||||
if (universeStore.planets[key]) continue
|
||||
const npcPlanet = planetLogic.createNPCPlanet(i, position, t('planet.planetPrefix'))
|
||||
universeStore.planets[key] = npcPlanet
|
||||
}
|
||||
}
|
||||
|
||||
const updateGame = async () => {
|
||||
const now = Date.now()
|
||||
if (gameStore.isPaused) return
|
||||
gameStore.gameTime = now
|
||||
// 检查军官过期
|
||||
gameLogic.checkOfficersExpiration(gameStore.player.officers, now)
|
||||
// 处理游戏更新(建造队列、研究队列等)
|
||||
const result = gameLogic.processGameUpdate(gameStore.player, now, gameStore.gameSpeed, handleNotification)
|
||||
gameStore.player.researchQueue = result.updatedResearchQueue
|
||||
// 处理舰队任务
|
||||
gameStore.player.fleetMissions.forEach(mission => {
|
||||
if (mission.status === 'outbound' && now >= mission.arrivalTime) {
|
||||
processMissionArrival(mission)
|
||||
} else if (mission.status === 'returning' && mission.returnTime && now >= mission.returnTime) {
|
||||
processMissionReturn(mission)
|
||||
}
|
||||
})
|
||||
|
||||
// 处理导弹攻击任务(使用反向循环以便安全删除)
|
||||
for (let i = gameStore.player.missileAttacks.length - 1; i >= 0; i--) {
|
||||
const missileAttack = gameStore.player.missileAttacks[i]
|
||||
if (missileAttack && missileAttack.status === 'flying' && now >= missileAttack.arrivalTime) {
|
||||
await processMissileAttackArrival(missileAttack)
|
||||
// 导弹攻击是单程的,到达后直接从数组中移除
|
||||
gameStore.player.missileAttacks.splice(i, 1)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理NPC舰队任务
|
||||
npcStore.npcs.forEach(npc => {
|
||||
if (npc.fleetMissions) {
|
||||
npc.fleetMissions.forEach(mission => {
|
||||
if (mission.status === 'outbound' && now >= mission.arrivalTime) {
|
||||
processNPCMissionArrival(npc, mission)
|
||||
} else if (mission.status === 'returning' && mission.returnTime && now >= mission.returnTime) {
|
||||
processNPCMissionReturn(npc, mission)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// NPC成长系统更新
|
||||
updateNPCGrowth(1)
|
||||
|
||||
// NPC行为系统更新(侦查和攻击决策)
|
||||
updateNPCBehavior(1)
|
||||
|
||||
// 检查并处理被消灭的NPC(所有星球都被摧毁的NPC)
|
||||
const eliminatedNpcIds = diplomaticLogic.checkAndHandleEliminatedNPCs(npcStore.npcs, gameStore.player, gameStore.locale)
|
||||
if (eliminatedNpcIds.length > 0) {
|
||||
// 从universeStore中移除被消灭NPC的星球数据
|
||||
eliminatedNpcIds.forEach(npcId => {
|
||||
const npc = npcStore.npcs.find(n => n.id === npcId)
|
||||
if (npc && npc.planets) {
|
||||
// 遍历NPC的所有星球,从universeStore中删除
|
||||
npc.planets.forEach(planet => {
|
||||
const planetKey = gameLogic.generatePositionKey(planet.position.galaxy, planet.position.system, planet.position.position)
|
||||
if (universeStore.planets[planetKey]) {
|
||||
delete universeStore.planets[planetKey]
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// 从NPC列表中移除被消灭的NPC
|
||||
npcStore.npcs = npcStore.npcs.filter(npc => !eliminatedNpcIds.includes(npc.id))
|
||||
}
|
||||
}
|
||||
|
||||
const processMissionArrival = async (mission: FleetMission) => {
|
||||
// 从宇宙星球地图中查找目标星球
|
||||
const targetKey = gameLogic.generatePositionKey(
|
||||
mission.targetPosition.galaxy,
|
||||
mission.targetPosition.system,
|
||||
mission.targetPosition.position
|
||||
)
|
||||
// 先从玩家星球中查找,再从宇宙地图中查找
|
||||
const targetPlanet =
|
||||
gameStore.player.planets.find(
|
||||
p =>
|
||||
p.position.galaxy === mission.targetPosition.galaxy &&
|
||||
p.position.system === mission.targetPosition.system &&
|
||||
p.position.position === mission.targetPosition.position
|
||||
) || universeStore.planets[targetKey]
|
||||
|
||||
// 获取起始星球名称(用于报告)
|
||||
const originPlanet = gameStore.player.planets.find(p => p.id === mission.originPlanetId)
|
||||
const originPlanetName = originPlanet?.name || t('fleetView.unknownPlanet')
|
||||
|
||||
if (mission.missionType === MissionType.Transport) {
|
||||
// 在处理任务之前保存货物信息(因为processTransportArrival会清空cargo)
|
||||
const transportedResources = { ...mission.cargo }
|
||||
const result = fleetLogic.processTransportArrival(mission, targetPlanet, gameStore.player, npcStore.npcs)
|
||||
// 生成运输任务报告
|
||||
if (!gameStore.player.missionReports) {
|
||||
gameStore.player.missionReports = []
|
||||
}
|
||||
gameStore.player.missionReports.push({
|
||||
id: `mission-report-${mission.id}`,
|
||||
timestamp: Date.now(),
|
||||
missionType: MissionType.Transport,
|
||||
originPlanetId: mission.originPlanetId,
|
||||
originPlanetName,
|
||||
targetPosition: mission.targetPosition,
|
||||
targetPlanetId: targetPlanet?.id,
|
||||
targetPlanetName:
|
||||
targetPlanet?.name || `[${mission.targetPosition.galaxy}:${mission.targetPosition.system}:${mission.targetPosition.position}]`,
|
||||
success: result.success,
|
||||
message: result.success ? t('missionReports.transportSuccess') : t('missionReports.transportFailed'),
|
||||
details: {
|
||||
transportedResources
|
||||
},
|
||||
read: false
|
||||
})
|
||||
} else if (mission.missionType === MissionType.Attack) {
|
||||
const attackResult = await fleetLogic.processAttackArrival(mission, targetPlanet, gameStore.player, null, gameStore.player.planets)
|
||||
if (attackResult) {
|
||||
gameStore.player.battleReports.push(attackResult.battleResult)
|
||||
|
||||
// 检查是否攻击了NPC星球,更新外交关系
|
||||
if (targetPlanet) {
|
||||
const targetNpc = npcStore.npcs.find(npc => npc.planets.some(p => p.id === targetPlanet.id))
|
||||
if (targetNpc) {
|
||||
diplomaticLogic.handleAttackReputation(gameStore.player, targetNpc, attackResult.battleResult, npcStore.npcs, gameStore.locale)
|
||||
}
|
||||
}
|
||||
|
||||
if (attackResult.moon) {
|
||||
gameStore.player.planets.push(attackResult.moon)
|
||||
}
|
||||
if (attackResult.debrisField) {
|
||||
// 将残骸场添加到游戏状态
|
||||
universeStore.debrisFields[attackResult.debrisField.id] = attackResult.debrisField
|
||||
}
|
||||
}
|
||||
} else if (mission.missionType === MissionType.Colonize) {
|
||||
const newPlanet = fleetLogic.processColonizeArrival(mission, targetPlanet, gameStore.player, t('planet.colonyPrefix'))
|
||||
// 生成殖民任务报告
|
||||
if (!gameStore.player.missionReports) {
|
||||
gameStore.player.missionReports = []
|
||||
}
|
||||
gameStore.player.missionReports.push({
|
||||
id: `mission-report-${mission.id}`,
|
||||
timestamp: Date.now(),
|
||||
missionType: MissionType.Colonize,
|
||||
originPlanetId: mission.originPlanetId,
|
||||
originPlanetName,
|
||||
targetPosition: mission.targetPosition,
|
||||
targetPlanetId: newPlanet?.id,
|
||||
targetPlanetName: newPlanet?.name,
|
||||
success: !!newPlanet,
|
||||
message: newPlanet ? t('missionReports.colonizeSuccess') : t('missionReports.colonizeFailed'),
|
||||
details: newPlanet
|
||||
? {
|
||||
newPlanetId: newPlanet.id,
|
||||
newPlanetName: newPlanet.name
|
||||
}
|
||||
: undefined,
|
||||
read: false
|
||||
})
|
||||
if (newPlanet) {
|
||||
gameStore.player.planets.push(newPlanet)
|
||||
}
|
||||
} else if (mission.missionType === MissionType.Spy) {
|
||||
const spyReport = fleetLogic.processSpyArrival(mission, targetPlanet, gameStore.player, null, npcStore.npcs)
|
||||
if (spyReport) gameStore.player.spyReports.push(spyReport)
|
||||
} else if (mission.missionType === MissionType.Deploy) {
|
||||
const deployed = fleetLogic.processDeployArrival(mission, targetPlanet, gameStore.player.id, gameStore.player.technologies)
|
||||
// 生成部署任务报告
|
||||
if (!gameStore.player.missionReports) {
|
||||
gameStore.player.missionReports = []
|
||||
}
|
||||
gameStore.player.missionReports.push({
|
||||
id: `mission-report-${mission.id}`,
|
||||
timestamp: Date.now(),
|
||||
missionType: MissionType.Deploy,
|
||||
originPlanetId: mission.originPlanetId,
|
||||
originPlanetName,
|
||||
targetPosition: mission.targetPosition,
|
||||
targetPlanetId: targetPlanet?.id,
|
||||
targetPlanetName:
|
||||
targetPlanet?.name || `[${mission.targetPosition.galaxy}:${mission.targetPosition.system}:${mission.targetPosition.position}]`,
|
||||
success: deployed.success,
|
||||
message: deployed.success ? t('missionReports.deploySuccess') : t('missionReports.deployFailed'),
|
||||
details: {
|
||||
deployedFleet: mission.fleet
|
||||
},
|
||||
read: false
|
||||
})
|
||||
if (deployed.success && !deployed.overflow) {
|
||||
const missionIndex = gameStore.player.fleetMissions.indexOf(mission)
|
||||
if (missionIndex > -1) gameStore.player.fleetMissions.splice(missionIndex, 1)
|
||||
return
|
||||
}
|
||||
} else if (mission.missionType === MissionType.Recycle) {
|
||||
// 处理回收任务
|
||||
const debrisId = `debris_${mission.targetPosition.galaxy}_${mission.targetPosition.system}_${mission.targetPosition.position}`
|
||||
const debrisField = universeStore.debrisFields[debrisId]
|
||||
const recycleResult = fleetLogic.processRecycleArrival(mission, debrisField)
|
||||
|
||||
// 生成回收任务报告
|
||||
if (!gameStore.player.missionReports) {
|
||||
gameStore.player.missionReports = []
|
||||
}
|
||||
gameStore.player.missionReports.push({
|
||||
id: `mission-report-${mission.id}`,
|
||||
timestamp: Date.now(),
|
||||
missionType: MissionType.Recycle,
|
||||
originPlanetId: mission.originPlanetId,
|
||||
originPlanetName,
|
||||
targetPosition: mission.targetPosition,
|
||||
success: !!recycleResult,
|
||||
message: recycleResult ? t('missionReports.recycleSuccess') : t('missionReports.recycleFailed'),
|
||||
details: recycleResult
|
||||
? {
|
||||
recycledResources: recycleResult.collectedResources,
|
||||
remainingDebris: recycleResult.remainingDebris || undefined
|
||||
}
|
||||
: undefined,
|
||||
read: false
|
||||
})
|
||||
|
||||
if (recycleResult && debrisField) {
|
||||
if (recycleResult.remainingDebris && (recycleResult.remainingDebris.metal > 0 || recycleResult.remainingDebris.crystal > 0)) {
|
||||
// 更新残骸场
|
||||
universeStore.debrisFields[debrisId] = {
|
||||
id: debrisField.id,
|
||||
position: debrisField.position,
|
||||
resources: recycleResult.remainingDebris,
|
||||
createdAt: debrisField.createdAt,
|
||||
expiresAt: debrisField.expiresAt
|
||||
}
|
||||
} else {
|
||||
// 残骸场已被完全收集,删除
|
||||
delete universeStore.debrisFields[debrisId]
|
||||
}
|
||||
}
|
||||
} else if (mission.missionType === MissionType.Destroy) {
|
||||
// 处理行星毁灭任务
|
||||
const destroyResult = fleetLogic.processDestroyArrival(mission, targetPlanet, gameStore.player)
|
||||
|
||||
// 生成毁灭任务报告
|
||||
if (!gameStore.player.missionReports) {
|
||||
gameStore.player.missionReports = []
|
||||
}
|
||||
gameStore.player.missionReports.push({
|
||||
id: `mission-report-${mission.id}`,
|
||||
timestamp: Date.now(),
|
||||
missionType: MissionType.Destroy,
|
||||
originPlanetId: mission.originPlanetId,
|
||||
originPlanetName,
|
||||
targetPosition: mission.targetPosition,
|
||||
targetPlanetId: targetPlanet?.id,
|
||||
targetPlanetName: targetPlanet?.name,
|
||||
success: destroyResult?.success || false,
|
||||
message: destroyResult?.success ? t('missionReports.destroySuccess') : t('missionReports.destroyFailed'),
|
||||
details: destroyResult?.success
|
||||
? {
|
||||
destroyedPlanetName:
|
||||
targetPlanet?.name ||
|
||||
`[${mission.targetPosition.galaxy}:${mission.targetPosition.system}:${mission.targetPosition.position}]`
|
||||
}
|
||||
: undefined,
|
||||
read: false
|
||||
})
|
||||
|
||||
if (destroyResult && destroyResult.success && destroyResult.planetId) {
|
||||
// 星球被摧毁
|
||||
|
||||
// 处理外交关系(如果目标是NPC星球)
|
||||
if (targetPlanet && targetPlanet.ownerId) {
|
||||
const planetOwner = npcStore.npcs.find(npc => npc.id === targetPlanet.ownerId)
|
||||
if (planetOwner) {
|
||||
diplomaticLogic.handlePlanetDestructionReputation(gameStore.player, targetPlanet, planetOwner, npcStore.npcs, gameStore.locale)
|
||||
}
|
||||
}
|
||||
|
||||
// 从玩家星球列表中移除(如果是玩家的星球)
|
||||
const planetIndex = gameStore.player.planets.findIndex(p => p.id === destroyResult.planetId)
|
||||
if (planetIndex > -1) {
|
||||
gameStore.player.planets.splice(planetIndex, 1)
|
||||
} else {
|
||||
// 不是玩家星球,从宇宙地图中移除
|
||||
delete universeStore.planets[targetKey]
|
||||
}
|
||||
}
|
||||
} else if (mission.missionType === MissionType.Expedition) {
|
||||
// 处理远征任务
|
||||
const expeditionResult = fleetLogic.processExpeditionArrival(mission)
|
||||
|
||||
// 生成远征任务报告
|
||||
if (!gameStore.player.missionReports) {
|
||||
gameStore.player.missionReports = []
|
||||
}
|
||||
|
||||
// 根据事件类型生成不同的报告消息
|
||||
let reportMessage = ''
|
||||
let reportDetails: Record<string, unknown> = {}
|
||||
|
||||
switch (expeditionResult.eventType) {
|
||||
case 'resources':
|
||||
reportMessage = t('missionReports.expeditionResources')
|
||||
reportDetails = { foundResources: expeditionResult.resources }
|
||||
break
|
||||
case 'darkMatter':
|
||||
reportMessage = t('missionReports.expeditionDarkMatter')
|
||||
reportDetails = { foundResources: expeditionResult.resources }
|
||||
break
|
||||
case 'fleet':
|
||||
reportMessage = t('missionReports.expeditionFleet')
|
||||
reportDetails = { foundFleet: expeditionResult.fleet }
|
||||
break
|
||||
case 'pirates':
|
||||
reportMessage = expeditionResult.fleetLost
|
||||
? t('missionReports.expeditionPiratesAttack')
|
||||
: t('missionReports.expeditionPiratesEscaped')
|
||||
reportDetails = expeditionResult.fleetLost ? { fleetLost: expeditionResult.fleetLost } : {}
|
||||
break
|
||||
case 'aliens':
|
||||
reportMessage = expeditionResult.fleetLost
|
||||
? t('missionReports.expeditionAliensAttack')
|
||||
: t('missionReports.expeditionAliensEscaped')
|
||||
reportDetails = expeditionResult.fleetLost ? { fleetLost: expeditionResult.fleetLost } : {}
|
||||
break
|
||||
default:
|
||||
reportMessage = t('missionReports.expeditionNothing')
|
||||
}
|
||||
|
||||
gameStore.player.missionReports.push({
|
||||
id: `mission-report-${mission.id}`,
|
||||
timestamp: Date.now(),
|
||||
missionType: MissionType.Expedition,
|
||||
originPlanetId: mission.originPlanetId,
|
||||
originPlanetName,
|
||||
targetPosition: mission.targetPosition,
|
||||
success: expeditionResult.eventType !== 'nothing',
|
||||
message: reportMessage,
|
||||
details: reportDetails,
|
||||
read: false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const processMissionReturn = (mission: FleetMission) => {
|
||||
const originPlanet = gameStore.player.planets.find(p => p.id === mission.originPlanetId)
|
||||
if (!originPlanet) return
|
||||
shipLogic.addFleet(originPlanet.fleet, mission.fleet)
|
||||
resourceLogic.addResources(originPlanet.resources, mission.cargo)
|
||||
const missionIndex = gameStore.player.fleetMissions.indexOf(mission)
|
||||
if (missionIndex > -1) gameStore.player.fleetMissions.splice(missionIndex, 1)
|
||||
}
|
||||
|
||||
// NPC任务处理
|
||||
const processNPCMissionArrival = (npc: NPC, mission: FleetMission) => {
|
||||
if (mission.missionType === MissionType.Recycle) {
|
||||
// NPC回收任务到达
|
||||
const debrisId = mission.debrisFieldId
|
||||
if (!debrisId) {
|
||||
console.warn('[NPC Mission] Recycle mission missing debrisFieldId')
|
||||
mission.status = 'returning'
|
||||
mission.returnTime = Date.now() + (mission.arrivalTime - mission.departureTime)
|
||||
return
|
||||
}
|
||||
|
||||
const debrisField = universeStore.debrisFields[debrisId]
|
||||
const recycleResult = fleetLogic.processRecycleArrival(mission, debrisField)
|
||||
|
||||
if (recycleResult && debrisField) {
|
||||
if (recycleResult.remainingDebris && (recycleResult.remainingDebris.metal > 0 || recycleResult.remainingDebris.crystal > 0)) {
|
||||
// 更新残骸场
|
||||
universeStore.debrisFields[debrisId] = {
|
||||
id: debrisField.id,
|
||||
position: debrisField.position,
|
||||
resources: recycleResult.remainingDebris,
|
||||
createdAt: debrisField.createdAt
|
||||
}
|
||||
} else {
|
||||
// 残骸已被完全回收,从宇宙中删除
|
||||
delete universeStore.debrisFields[debrisId]
|
||||
}
|
||||
}
|
||||
|
||||
// 移除即将到来的警告(回收任务已到达)
|
||||
removeIncomingFleetAlertById(mission.id)
|
||||
|
||||
// 设置返回时间
|
||||
mission.returnTime = Date.now() + (mission.arrivalTime - mission.departureTime)
|
||||
return
|
||||
}
|
||||
|
||||
// 找到目标星球
|
||||
const targetKey = gameLogic.generatePositionKey(
|
||||
mission.targetPosition.galaxy,
|
||||
mission.targetPosition.system,
|
||||
mission.targetPosition.position
|
||||
)
|
||||
const targetPlanet =
|
||||
gameStore.player.planets.find(
|
||||
p =>
|
||||
p.position.galaxy === mission.targetPosition.galaxy &&
|
||||
p.position.system === mission.targetPosition.system &&
|
||||
p.position.position === mission.targetPosition.position
|
||||
) || universeStore.planets[targetKey]
|
||||
|
||||
if (!targetPlanet) {
|
||||
console.warn('[NPC Mission] Target planet not found')
|
||||
return
|
||||
}
|
||||
|
||||
if (mission.missionType === MissionType.Spy) {
|
||||
// NPC侦查到达
|
||||
const { spiedNotification, spyReport } = npcBehaviorLogic.processNPCSpyArrival(npc, mission, targetPlanet, gameStore.player)
|
||||
|
||||
// 保存侦查报告到NPC(用于后续攻击决策)
|
||||
if (!npc.playerSpyReports) {
|
||||
npc.playerSpyReports = {}
|
||||
}
|
||||
npc.playerSpyReports[targetPlanet.id] = spyReport
|
||||
|
||||
// 添加被侦查通知给玩家
|
||||
if (!gameStore.player.spiedNotifications) {
|
||||
gameStore.player.spiedNotifications = []
|
||||
}
|
||||
gameStore.player.spiedNotifications.push(spiedNotification)
|
||||
|
||||
// 移除即将到来的警告(侦查已到达)
|
||||
removeIncomingFleetAlertById(mission.id)
|
||||
} else if (mission.missionType === MissionType.Attack) {
|
||||
// NPC攻击到达 - 使用专门的NPC攻击处理逻辑
|
||||
fleetLogic.processNPCAttackArrival(npc, mission, targetPlanet, gameStore.player, gameStore.player.planets).then(attackResult => {
|
||||
if (attackResult) {
|
||||
// 添加战斗报告给玩家
|
||||
gameStore.player.battleReports.push(attackResult.battleResult)
|
||||
|
||||
// 如果生成月球,添加到玩家星球列表
|
||||
if (attackResult.moon) {
|
||||
gameStore.player.planets.push(attackResult.moon)
|
||||
}
|
||||
|
||||
// 如果生成残骸场,添加到宇宙残骸场列表
|
||||
if (attackResult.debrisField) {
|
||||
const existingDebris = universeStore.debrisFields[attackResult.debrisField.id]
|
||||
if (existingDebris) {
|
||||
// 累加残骸资源
|
||||
universeStore.debrisFields[attackResult.debrisField.id] = {
|
||||
...existingDebris,
|
||||
resources: {
|
||||
metal: existingDebris.resources.metal + attackResult.debrisField.resources.metal,
|
||||
crystal: existingDebris.resources.crystal + attackResult.debrisField.resources.crystal
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 新残骸场
|
||||
universeStore.debrisFields[attackResult.debrisField.id] = attackResult.debrisField
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 移除即将到来的警告(攻击已到达)
|
||||
removeIncomingFleetAlertById(mission.id)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const processNPCMissionReturn = (npc: NPC, mission: FleetMission) => {
|
||||
// 找到NPC的起始星球
|
||||
const originPlanet = npc.planets.find(p => p.id === mission.originPlanetId)
|
||||
if (!originPlanet) return
|
||||
|
||||
// 返还舰队
|
||||
shipLogic.addFleet(originPlanet.fleet, mission.fleet)
|
||||
|
||||
// 如果携带掠夺资源,给NPC添加资源
|
||||
if (mission.cargo) {
|
||||
originPlanet.resources.metal += mission.cargo.metal
|
||||
originPlanet.resources.crystal += mission.cargo.crystal
|
||||
originPlanet.resources.deuterium += mission.cargo.deuterium
|
||||
}
|
||||
|
||||
// 从NPC任务列表中移除
|
||||
if (npc.fleetMissions) {
|
||||
const missionIndex = npc.fleetMissions.indexOf(mission)
|
||||
if (missionIndex > -1) {
|
||||
npc.fleetMissions.splice(missionIndex, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理导弹攻击到达
|
||||
const processMissileAttackArrival = async (missileAttack: MissileAttack) => {
|
||||
// 动态导入导弹逻辑
|
||||
const missileLogic = await import('@/logic/missileLogic')
|
||||
|
||||
// 找到目标星球
|
||||
const targetKey = gameLogic.generatePositionKey(
|
||||
missileAttack.targetPosition.galaxy,
|
||||
missileAttack.targetPosition.system,
|
||||
missileAttack.targetPosition.position
|
||||
)
|
||||
const targetPlanet =
|
||||
gameStore.player.planets.find(
|
||||
p =>
|
||||
p.position.galaxy === missileAttack.targetPosition.galaxy &&
|
||||
p.position.system === missileAttack.targetPosition.system &&
|
||||
p.position.position === missileAttack.targetPosition.position
|
||||
) || universeStore.planets[targetKey]
|
||||
|
||||
// 如果目标星球不存在,导弹失败
|
||||
if (!targetPlanet) {
|
||||
missileAttack.status = 'arrived'
|
||||
// 生成失败报告
|
||||
if (!gameStore.player.missionReports) {
|
||||
gameStore.player.missionReports = []
|
||||
}
|
||||
gameStore.player.missionReports.push({
|
||||
id: `missile-report-${missileAttack.id}`,
|
||||
timestamp: Date.now(),
|
||||
missionType: MissionType.MissileAttack,
|
||||
originPlanetId: missileAttack.originPlanetId,
|
||||
originPlanetName: gameStore.player.planets.find(p => p.id === missileAttack.originPlanetId)?.name || t('fleetView.unknownPlanet'),
|
||||
targetPosition: missileAttack.targetPosition,
|
||||
targetPlanetId: undefined,
|
||||
targetPlanetName: `[${missileAttack.targetPosition.galaxy}:${missileAttack.targetPosition.system}:${missileAttack.targetPosition.position}]`,
|
||||
success: false,
|
||||
message: t('missionReports.missileAttackFailed'),
|
||||
details: {
|
||||
missileCount: missileAttack.missileCount,
|
||||
missileHits: 0,
|
||||
missileIntercepted: 0,
|
||||
defenseLosses: {}
|
||||
},
|
||||
read: false
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 计算导弹攻击结果
|
||||
const impactResult = missileLogic.calculateMissileImpact(missileAttack.missileCount, targetPlanet)
|
||||
|
||||
// 应用损失到目标星球
|
||||
missileLogic.applyMissileAttackResult(targetPlanet, impactResult.defenseLosses)
|
||||
|
||||
// 如果目标是NPC的星球,扣除外交好感度
|
||||
if (targetPlanet.ownerId && targetPlanet.ownerId !== gameStore.player.id) {
|
||||
const targetNpc = npcStore.npcs.find(npc => npc.id === targetPlanet.ownerId)
|
||||
if (targetNpc) {
|
||||
// 导弹攻击扣除好感度
|
||||
const { REPUTATION_CHANGES } = DIPLOMATIC_CONFIG
|
||||
const reputationLoss = REPUTATION_CHANGES.ATTACK / 2 // 导弹攻击的好感度惩罚是普通攻击的一半
|
||||
|
||||
// 更新NPC对玩家的关系(统一使用 npc.relations 作为唯一数据源)
|
||||
if (!targetNpc.relations) {
|
||||
targetNpc.relations = {}
|
||||
}
|
||||
const npcRelation = diplomaticLogic.getOrCreateRelation(targetNpc.relations, targetNpc.id, gameStore.player.id)
|
||||
targetNpc.relations[gameStore.player.id] = diplomaticLogic.updateReputation(
|
||||
npcRelation,
|
||||
reputationLoss,
|
||||
DiplomaticEventType.Attack,
|
||||
t('diplomacy.reports.wasAttackedByMissile')
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 标记导弹攻击为已到达
|
||||
missileAttack.status = 'arrived'
|
||||
|
||||
// 生成导弹攻击报告
|
||||
if (!gameStore.player.missionReports) {
|
||||
gameStore.player.missionReports = []
|
||||
}
|
||||
const reportMessage =
|
||||
impactResult.missileHits > 0
|
||||
? `${t('missionReports.missileAttackSuccess')}: ${impactResult.missileHits} ${t('missionReports.hits')}`
|
||||
: t('missionReports.missileAttackIntercepted')
|
||||
|
||||
gameStore.player.missionReports.push({
|
||||
id: `missile-report-${missileAttack.id}`,
|
||||
timestamp: Date.now(),
|
||||
missionType: MissionType.MissileAttack,
|
||||
originPlanetId: missileAttack.originPlanetId,
|
||||
originPlanetName: gameStore.player.planets.find(p => p.id === missileAttack.originPlanetId)?.name || t('fleetView.unknownPlanet'),
|
||||
targetPosition: missileAttack.targetPosition,
|
||||
targetPlanetId: targetPlanet.id,
|
||||
targetPlanetName: targetPlanet.name,
|
||||
success: true,
|
||||
message: reportMessage,
|
||||
details: {
|
||||
missileCount: missileAttack.missileCount,
|
||||
missileHits: impactResult.missileHits,
|
||||
missileIntercepted: impactResult.missileIntercepted,
|
||||
defenseLosses: impactResult.defenseLosses
|
||||
},
|
||||
read: false
|
||||
})
|
||||
}
|
||||
|
||||
// 打开敌方警报面板
|
||||
const openEnemyAlertPanel = () => {
|
||||
enemyAlertNotificationsRef.value?.open()
|
||||
}
|
||||
|
||||
const removeIncomingFleetAlertById = (missionId: string) => {
|
||||
if (!gameStore.player.incomingFleetAlerts) return
|
||||
const index = gameStore.player.incomingFleetAlerts.findIndex(a => a.id === missionId)
|
||||
if (index > -1) {
|
||||
gameStore.player.incomingFleetAlerts.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
const updateNPCGrowth = (deltaSeconds: number) => {
|
||||
// 累积时间
|
||||
npcUpdateCounter.value += deltaSeconds
|
||||
|
||||
// 只在达到更新间隔时才执行
|
||||
if (npcUpdateCounter.value < NPC_UPDATE_INTERVAL) {
|
||||
return
|
||||
}
|
||||
|
||||
// 获取所有星球
|
||||
const allPlanets = Object.values(universeStore.planets)
|
||||
|
||||
// 如果NPC store为空,从星球数据中初始化NPC
|
||||
if (npcStore.npcs.length === 0) {
|
||||
const npcMap = new Map<string, any>()
|
||||
|
||||
allPlanets.forEach(planet => {
|
||||
// 跳过玩家的星球
|
||||
if (planet.ownerId === gameStore.player.id || !planet.ownerId) return
|
||||
|
||||
// 这是NPC的星球
|
||||
if (!npcMap.has(planet.ownerId)) {
|
||||
// 为每个NPC设置随机的初始冷却时间,避免所有NPC同时行动
|
||||
const now = Date.now()
|
||||
const randomSpyOffset = Math.random() * 240 * 1000 // 0-4分钟的随机延迟
|
||||
const randomAttackOffset = Math.random() * 480 * 1000 // 0-8分钟的随机延迟
|
||||
|
||||
// 初始化NPC与玩家的中立关系
|
||||
const initialRelations: Record<string, any> = {}
|
||||
initialRelations[gameStore.player.id] = {
|
||||
fromId: planet.ownerId,
|
||||
toId: gameStore.player.id,
|
||||
reputation: 0,
|
||||
status: 'neutral' as const,
|
||||
lastUpdated: now,
|
||||
history: []
|
||||
}
|
||||
|
||||
npcMap.set(planet.ownerId, {
|
||||
id: planet.ownerId,
|
||||
name: `NPC-${planet.ownerId.substring(0, 8)}`,
|
||||
planets: [],
|
||||
technologies: {}, // 初始化空科技树
|
||||
difficulty: 'medium' as const, // 默认中等难度
|
||||
relations: initialRelations, // 外交关系(默认与玩家中立)
|
||||
allies: [], // 盟友列表
|
||||
enemies: [], // 敌人列表
|
||||
lastSpyTime: now - randomSpyOffset, // 设置随机的上次侦查时间
|
||||
lastAttackTime: now - randomAttackOffset, // 设置随机的上次攻击时间
|
||||
fleetMissions: [], // 舰队任务
|
||||
playerSpyReports: {} // 对玩家的侦查报告
|
||||
})
|
||||
}
|
||||
|
||||
npcMap.get(planet.ownerId)!.planets.push(planet)
|
||||
})
|
||||
|
||||
// 保存到store
|
||||
npcStore.npcs = Array.from(npcMap.values())
|
||||
|
||||
// 如果有NPC,基于玩家实力初始化NPC
|
||||
if (npcStore.npcs.length > 0) {
|
||||
const gameState: npcGrowthLogic.NPCGrowthGameState = {
|
||||
planets: allPlanets,
|
||||
player: gameStore.player,
|
||||
npcs: npcStore.npcs
|
||||
}
|
||||
|
||||
const playerPower = npcGrowthLogic.calculatePlayerAveragePower(gameState)
|
||||
|
||||
npcStore.npcs.forEach(npc => {
|
||||
npcGrowthLogic.initializeNPCStartingPower(npc, playerPower)
|
||||
})
|
||||
|
||||
// 初始化NPC之间的外交关系(盟友/敌人)
|
||||
npcGrowthLogic.initializeNPCDiplomacy(npcStore.npcs)
|
||||
}
|
||||
}
|
||||
|
||||
// 确保所有NPC都有间谍探测器(修复旧版本保存的数据)
|
||||
if (npcStore.npcs.length > 0) {
|
||||
npcGrowthLogic.ensureNPCSpyProbes(npcStore.npcs)
|
||||
}
|
||||
|
||||
// 确保所有NPC都与玩家建立了关系(修复旧版本保存的数据)
|
||||
if (npcStore.npcs.length > 0) {
|
||||
const now = Date.now()
|
||||
npcStore.npcs.forEach(npc => {
|
||||
if (!npc.relations) {
|
||||
npc.relations = {}
|
||||
}
|
||||
// 如果NPC没有与玩家的关系,建立中立关系
|
||||
if (!npc.relations[gameStore.player.id]) {
|
||||
npc.relations[gameStore.player.id] = {
|
||||
fromId: npc.id,
|
||||
toId: gameStore.player.id,
|
||||
reputation: 0,
|
||||
status: 'neutral' as const,
|
||||
lastUpdated: now,
|
||||
history: []
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 如果没有NPC,直接返回
|
||||
if (npcStore.npcs.length === 0) {
|
||||
npcUpdateCounter.value = 0
|
||||
return
|
||||
}
|
||||
|
||||
// 构建游戏状态
|
||||
const gameState: npcGrowthLogic.NPCGrowthGameState = {
|
||||
planets: allPlanets,
|
||||
player: gameStore.player,
|
||||
npcs: npcStore.npcs
|
||||
}
|
||||
|
||||
// 使用累积的时间更新每个NPC(应用游戏速度倍率)
|
||||
npcStore.npcs.forEach(npc => {
|
||||
npcGrowthLogic.updateNPCGrowth(npc, gameState, npcUpdateCounter.value, gameStore.gameSpeed)
|
||||
})
|
||||
|
||||
// 重置计数器
|
||||
npcUpdateCounter.value = 0
|
||||
}
|
||||
|
||||
const updateNPCBehavior = (deltaSeconds: number) => {
|
||||
// 累积时间
|
||||
npcBehaviorCounter.value += deltaSeconds
|
||||
|
||||
// 只在达到更新间隔时才执行
|
||||
if (npcBehaviorCounter.value < NPC_BEHAVIOR_INTERVAL) {
|
||||
return
|
||||
}
|
||||
|
||||
// 如果没有NPC,直接返回
|
||||
if (npcStore.npcs.length === 0) {
|
||||
npcBehaviorCounter.value = 0
|
||||
return
|
||||
}
|
||||
|
||||
const now = Date.now()
|
||||
// 合并玩家星球和NPC星球到allPlanets(NPC需要能够侦查和攻击玩家星球)
|
||||
const allPlanets = [...gameStore.player.planets, ...Object.values(universeStore.planets)]
|
||||
|
||||
// 计算当前所有正在进行的侦查和攻击任务数量
|
||||
let activeSpyMissions = 0
|
||||
let activeAttackMissions = 0
|
||||
npcStore.npcs.forEach(npc => {
|
||||
if (npc.fleetMissions) {
|
||||
npc.fleetMissions.forEach(mission => {
|
||||
if (mission.status === 'outbound') {
|
||||
if (mission.missionType === 'spy') {
|
||||
activeSpyMissions++
|
||||
} else if (mission.missionType === 'attack') {
|
||||
activeAttackMissions++
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// 获取并发限制配置
|
||||
const config = npcBehaviorLogic.calculateDynamicBehavior(gameStore.player.points)
|
||||
|
||||
// 更新每个NPC的行为(随机顺序,避免总是优先处理同一批NPC)
|
||||
const shuffledNpcs = [...npcStore.npcs].sort(() => Math.random() - 0.5)
|
||||
shuffledNpcs.forEach(npc => {
|
||||
// 在更新前检查当前并发数,如果已达上限则跳过该NPC
|
||||
npcBehaviorLogic.updateNPCBehaviorWithLimit(npc, gameStore.player, allPlanets, universeStore.debrisFields, now, {
|
||||
activeSpyMissions,
|
||||
activeAttackMissions,
|
||||
config
|
||||
})
|
||||
|
||||
// 重新计算当前并发数(因为可能新增了任务)
|
||||
activeSpyMissions = 0
|
||||
activeAttackMissions = 0
|
||||
npcStore.npcs.forEach(n => {
|
||||
if (n.fleetMissions) {
|
||||
n.fleetMissions.forEach(mission => {
|
||||
if (mission.status === 'outbound') {
|
||||
if (mission.missionType === 'spy') activeSpyMissions++
|
||||
else if (mission.missionType === 'attack') activeAttackMissions++
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
npcBehaviorCounter.value = 0
|
||||
}
|
||||
|
||||
// 启动游戏循环
|
||||
const startGameLoop = () => {
|
||||
if (gameStore.isPaused) return
|
||||
// 清理旧的定时器
|
||||
if (gameLoop.value) {
|
||||
clearInterval(gameLoop.value)
|
||||
}
|
||||
// 游戏循环固定为1秒,避免高倍速时的卡顿
|
||||
// gameSpeed 只作用于资源产出和时间消耗的倍率
|
||||
const interval = 1000
|
||||
// 启动新的游戏循环
|
||||
gameLoop.value = setInterval(() => {
|
||||
updateGame()
|
||||
}, interval)
|
||||
}
|
||||
|
||||
// 停止游戏循环
|
||||
const stopGameLoop = () => {
|
||||
if (gameLoop.value) {
|
||||
clearInterval(gameLoop.value)
|
||||
gameLoop.value = null
|
||||
}
|
||||
}
|
||||
|
||||
// 启动积分更新定时器(每10秒更新一次)
|
||||
const startPointsUpdate = () => {
|
||||
if (pointsUpdateInterval.value) {
|
||||
clearInterval(pointsUpdateInterval.value)
|
||||
}
|
||||
pointsUpdateInterval.value = setInterval(() => {
|
||||
if (!gameStore.isPaused) {
|
||||
gameStore.player.points = publicLogic.calculatePlayerPoints(gameStore.player)
|
||||
}
|
||||
}, 10000) // 10秒更新一次
|
||||
}
|
||||
|
||||
// 处理取消建造事件
|
||||
const handleCancelBuildEvent = (event: CustomEvent) => {
|
||||
handleCancelBuild(event.detail)
|
||||
}
|
||||
|
||||
// 处理取消研究事件
|
||||
const handleCancelResearchEvent = (event: CustomEvent) => {
|
||||
handleCancelResearch(event.detail)
|
||||
}
|
||||
|
||||
// 科乐美秘籍:上上下下左左右右BA
|
||||
const setupKonamiCode = () => {
|
||||
const konamiCode = ['ArrowUp', 'ArrowUp', 'ArrowDown', 'ArrowDown', 'ArrowLeft', 'ArrowLeft', 'ArrowRight', 'ArrowRight', 'b', 'a']
|
||||
let konamiIndex = 0
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
// 如果已经激活GM模式,直接返回
|
||||
if (gameStore.player.isGMEnabled) return
|
||||
|
||||
const key = event.key.toLowerCase()
|
||||
// 检查是否匹配当前秘籍序列
|
||||
if (key === konamiCode[konamiIndex] || event.key === konamiCode[konamiIndex]) {
|
||||
konamiIndex++
|
||||
// 如果完成整个秘籍序列
|
||||
if (konamiIndex === konamiCode.length) {
|
||||
gameStore.player.isGMEnabled = true
|
||||
// 显示成功消息
|
||||
toast.success(t('common.gmModeActivated'))
|
||||
konamiIndex = 0
|
||||
}
|
||||
} else {
|
||||
// 如果按错了键,重置序列
|
||||
konamiIndex = 0
|
||||
}
|
||||
}
|
||||
window.addEventListener('keydown', handleKeyDown)
|
||||
// 返回清理函数
|
||||
return () => {
|
||||
window.removeEventListener('keydown', handleKeyDown)
|
||||
}
|
||||
}
|
||||
|
||||
// 打开重命名对话框
|
||||
const openRenameDialog = (planetId: string, currentName: string) => {
|
||||
renamingPlanetId.value = planetId
|
||||
newPlanetName.value = currentName
|
||||
renameDialogOpen.value = true
|
||||
}
|
||||
|
||||
// 确认重命名
|
||||
const confirmRenamePlanet = () => {
|
||||
if (!renamingPlanetId.value || !newPlanetName.value.trim()) return
|
||||
|
||||
const targetPlanet = gameStore.player.planets.find(p => p.id === renamingPlanetId.value)
|
||||
if (targetPlanet) {
|
||||
targetPlanet.name = newPlanetName.value.trim()
|
||||
}
|
||||
|
||||
renameDialogOpen.value = false
|
||||
renamingPlanetId.value = null
|
||||
newPlanetName.value = ''
|
||||
}
|
||||
|
||||
// 检查功能是否解锁
|
||||
const checkFeatureUnlocked = (path: string): { unlocked: boolean; requirement?: { building: BuildingType; level: number } } => {
|
||||
const requirement = featureRequirements[path]
|
||||
if (!requirement) {
|
||||
return { unlocked: true }
|
||||
}
|
||||
|
||||
const currentLevel = planet.value?.buildings[requirement.building] || 0
|
||||
return {
|
||||
unlocked: currentLevel >= requirement.level,
|
||||
requirement
|
||||
}
|
||||
}
|
||||
|
||||
// 处理导航点击
|
||||
const handleNavClick = (path: string, event: Event) => {
|
||||
const { unlocked, requirement } = checkFeatureUnlocked(path)
|
||||
|
||||
if (!unlocked && requirement) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
|
||||
const buildingName = BUILDINGS.value[requirement.building]?.name || requirement.building
|
||||
const currentLevel = planet.value?.buildings[requirement.building] || 0
|
||||
|
||||
toast.warning(t('common.featureLocked'), {
|
||||
description: `${t('common.requiredBuilding')}: ${buildingName} Lv ${requirement.level} (${t(
|
||||
'common.currentLevel'
|
||||
)}: Lv ${currentLevel})`,
|
||||
action: {
|
||||
label: t('common.goToBuildings'),
|
||||
onClick: () => router.push('/buildings')
|
||||
},
|
||||
duration: 3000
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 功能已解锁,正常导航
|
||||
router.push(path)
|
||||
}
|
||||
|
||||
// 切换到月球
|
||||
const switchToMoon = () => {
|
||||
if (moon.value) {
|
||||
@@ -450,18 +1720,142 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 切换到指定星球
|
||||
const switchToPlanet = (planetId: string) => {
|
||||
gameStore.currentPlanetId = planetId
|
||||
}
|
||||
|
||||
// 切换侧边栏
|
||||
const toggleSidebar = () => {
|
||||
sidebarOpen.value = !sidebarOpen.value
|
||||
}
|
||||
|
||||
// 处理确认对话框的确认操作
|
||||
const handleConfirmAction = () => {
|
||||
if (confirmDialogAction.value) {
|
||||
confirmDialogAction.value()
|
||||
}
|
||||
confirmDialogOpen.value = false
|
||||
// 处理侧边栏打开/关闭状态变化
|
||||
const handleSidebarOpenChange = (open: boolean) => {
|
||||
sidebarOpen.value = open
|
||||
}
|
||||
|
||||
// 取消建造
|
||||
const handleCancelBuild = (queueId: string) => {
|
||||
confirmDialogTitle.value = t('queue.cancelBuild')
|
||||
confirmDialogMessage.value = t('queue.confirmCancel')
|
||||
confirmDialogAction.value = () => {
|
||||
if (!gameStore.currentPlanet) return false
|
||||
const { item, index } = buildingValidation.findQueueItem(gameStore.currentPlanet.buildQueue, queueId)
|
||||
if (!item) return false
|
||||
if (item.type === 'building') {
|
||||
const refund = buildingValidation.cancelBuildingUpgrade(gameStore.currentPlanet, item)
|
||||
resourceLogic.addResources(gameStore.currentPlanet.resources, refund)
|
||||
}
|
||||
gameStore.currentPlanet.buildQueue.splice(index, 1)
|
||||
return true
|
||||
}
|
||||
confirmDialogOpen.value = true
|
||||
}
|
||||
|
||||
// 取消研究
|
||||
const handleCancelResearch = (queueId: string) => {
|
||||
confirmDialogTitle.value = t('queue.cancelResearch')
|
||||
confirmDialogMessage.value = t('queue.confirmCancel')
|
||||
confirmDialogAction.value = () => {
|
||||
if (!gameStore.currentPlanet) return false
|
||||
const { item, index } = buildingValidation.findQueueItem(gameStore.player.researchQueue, queueId)
|
||||
if (!item) return false
|
||||
if (item.type === 'technology') {
|
||||
const refund = researchValidation.cancelTechnologyResearch(item)
|
||||
resourceLogic.addResources(gameStore.currentPlanet.resources, refund)
|
||||
}
|
||||
gameStore.player.researchQueue.splice(index, 1)
|
||||
return true
|
||||
}
|
||||
confirmDialogOpen.value = true
|
||||
}
|
||||
|
||||
// 监听暂停状态变化
|
||||
watch(
|
||||
() => gameStore.isPaused,
|
||||
isPaused => {
|
||||
if (isPaused) {
|
||||
stopGameLoop()
|
||||
} else {
|
||||
startGameLoop()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// 初始化游戏
|
||||
onMounted(async () => {
|
||||
try {
|
||||
// 如果是首次访问(没有星球数据),使用浏览器语言自动检测
|
||||
const isFirstVisit = gameStore.player.planets.length === 0
|
||||
if (isFirstVisit) {
|
||||
gameStore.locale = detectBrowserLocale()
|
||||
}
|
||||
await initGame()
|
||||
// 启动游戏循环
|
||||
startGameLoop()
|
||||
// 启动积分更新定时器
|
||||
startPointsUpdate()
|
||||
// 启动科乐美秘籍监听
|
||||
konamiCleanup.value = setupKonamiCode()
|
||||
|
||||
// 添加队列取消事件监听
|
||||
window.addEventListener('cancel-build', handleCancelBuildEvent as EventListener)
|
||||
window.addEventListener('cancel-research', handleCancelResearchEvent as EventListener)
|
||||
|
||||
// 首次检查版本(被动检测)
|
||||
const versionInfo = await checkLatestVersion(gameStore.player.lastVersionCheckTime || 0, (time: number) => {
|
||||
gameStore.player.lastVersionCheckTime = time
|
||||
})
|
||||
if (versionInfo) {
|
||||
updateInfo.value = versionInfo
|
||||
toast.info(t('settings.newVersionAvailable', { version: versionInfo.version }), {
|
||||
duration: Infinity,
|
||||
dismissible: true,
|
||||
action: {
|
||||
label: t('settings.viewUpdate'),
|
||||
onClick: () => {
|
||||
showUpdateDialog.value = true
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
// 启动版本检查定时器(每5分钟被动检查一次)
|
||||
versionCheckInterval.value = setInterval(async () => {
|
||||
const versionInfo = await checkLatestVersion(gameStore.player.lastVersionCheckTime || 0, (time: number) => {
|
||||
gameStore.player.lastVersionCheckTime = time
|
||||
})
|
||||
if (versionInfo) {
|
||||
updateInfo.value = versionInfo
|
||||
toast.info(t('settings.newVersionAvailable', { version: versionInfo.version }), {
|
||||
duration: Infinity,
|
||||
dismissible: true,
|
||||
action: {
|
||||
label: t('settings.viewUpdate'),
|
||||
onClick: () => {
|
||||
showUpdateDialog.value = true
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}, 5 * 60 * 1000)
|
||||
} catch (error) {
|
||||
console.error('Error during game initialization:', error)
|
||||
// 即使初始化失败,也尝试启动基本的游戏循环
|
||||
startGameLoop()
|
||||
}
|
||||
})
|
||||
|
||||
// 清理定时器
|
||||
onUnmounted(() => {
|
||||
if (gameLoop.value) clearInterval(gameLoop.value)
|
||||
if (pointsUpdateInterval.value) clearInterval(pointsUpdateInterval.value)
|
||||
if (konamiCleanup.value) konamiCleanup.value()
|
||||
if (versionCheckInterval.value) clearInterval(versionCheckInterval.value)
|
||||
// 移除队列取消事件监听
|
||||
window.removeEventListener('cancel-build', handleCancelBuildEvent as EventListener)
|
||||
window.removeEventListener('cancel-research', handleCancelResearchEvent as EventListener)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
95
src/assets/main.css
Normal file
95
src/assets/main.css
Normal file
@@ -0,0 +1,95 @@
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
:root {
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.141 0.005 285.823);
|
||||
--popover: oklch(1 0 0);
|
||||
--popover-foreground: oklch(0.141 0.005 285.823);
|
||||
--primary: oklch(0.21 0.006 285.885);
|
||||
--primary-foreground: oklch(0.985 0 0);
|
||||
--secondary: oklch(0.967 0.001 286.375);
|
||||
--secondary-foreground: oklch(0.21 0.006 285.885);
|
||||
--muted: oklch(0.967 0.001 286.375);
|
||||
--muted-foreground: oklch(0.552 0.016 285.938);
|
||||
--accent: oklch(0.967 0.001 286.375);
|
||||
--accent-foreground: oklch(0.21 0.006 285.885);
|
||||
--destructive: oklch(0.577 0.245 27.325);
|
||||
--destructive-foreground: oklch(0.577 0.245 27.325);
|
||||
--border: oklch(0.92 0.004 286.32);
|
||||
--input: oklch(0.92 0.004 286.32);
|
||||
--ring: oklch(0.705 0.015 286.067);
|
||||
--radius: 0.625rem;
|
||||
--background: oklch(1 0 0);
|
||||
--foreground: oklch(0.141 0.005 285.823);
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: oklch(0.141 0.005 285.823);
|
||||
--foreground: oklch(0.985 0 0);
|
||||
--card: oklch(0.141 0.005 285.823);
|
||||
--card-foreground: oklch(0.985 0 0);
|
||||
--popover: oklch(0.141 0.005 285.823);
|
||||
--popover-foreground: oklch(0.985 0 0);
|
||||
--primary: oklch(0.985 0 0);
|
||||
--primary-foreground: oklch(0.21 0.006 285.885);
|
||||
--secondary: oklch(0.274 0.006 286.033);
|
||||
--secondary-foreground: oklch(0.985 0 0);
|
||||
--muted: oklch(0.274 0.006 286.033);
|
||||
--muted-foreground: oklch(0.705 0.015 286.067);
|
||||
--accent: oklch(0.274 0.006 286.033);
|
||||
--accent-foreground: oklch(0.985 0 0);
|
||||
--destructive: oklch(0.396 0.141 25.723);
|
||||
--destructive-foreground: oklch(0.637 0.237 25.331);
|
||||
--border: oklch(0.274 0.006 286.033);
|
||||
--input: oklch(0.274 0.006 286.033);
|
||||
--ring: oklch(0.442 0.017 285.786);
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--color-card: var(--card);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-destructive-foreground: var(--destructive-foreground);
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border outline-ring/50;
|
||||
}
|
||||
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
|
||||
html {
|
||||
color-scheme: light dark;
|
||||
}
|
||||
|
||||
html.dark {
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
html.light {
|
||||
color-scheme: light;
|
||||
}
|
||||
48
src/components/BackToTop.vue
Normal file
48
src/components/BackToTop.vue
Normal file
@@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<Transition
|
||||
enter-active-class="transition-all duration-300 ease-out"
|
||||
enter-from-class="translate-y-4 opacity-0"
|
||||
enter-to-class="translate-y-0 opacity-100"
|
||||
leave-active-class="transition-all duration-200 ease-in"
|
||||
leave-from-class="translate-y-0 opacity-100"
|
||||
leave-to-class="translate-y-4 opacity-0"
|
||||
>
|
||||
<Button v-if="isVisible" variant="outline" size="icon" @click="scrollToTop">
|
||||
<ChevronUp class="h-4 w-4" />
|
||||
</Button>
|
||||
</Transition>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { ChevronUp } from 'lucide-vue-next'
|
||||
|
||||
// 显示阈值(滚动超过这个距离才显示按钮)
|
||||
const SCROLL_THRESHOLD = 300
|
||||
|
||||
const isVisible = ref(false)
|
||||
|
||||
// 监听滚动事件
|
||||
const handleScroll = () => {
|
||||
isVisible.value = window.scrollY > SCROLL_THRESHOLD
|
||||
}
|
||||
|
||||
// 丝滑返回顶部
|
||||
const scrollToTop = () => {
|
||||
window.scrollTo({
|
||||
top: 0,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('scroll', handleScroll, { passive: true })
|
||||
// 初始检查
|
||||
handleScroll()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('scroll', handleScroll)
|
||||
})
|
||||
</script>
|
||||
@@ -40,15 +40,9 @@
|
||||
</div>
|
||||
|
||||
<!-- 胜利者 -->
|
||||
<div class="text-center p-4 rounded-lg" :class="getWinnerStyle(report.winner)">
|
||||
<div class="text-center p-4 rounded-lg" :class="getPlayerResultStyle()">
|
||||
<p class="text-lg font-bold">
|
||||
{{
|
||||
report.winner === 'attacker'
|
||||
? t('messagesView.victory')
|
||||
: report.winner === 'defender'
|
||||
? t('messagesView.defeat')
|
||||
: t('messagesView.draw')
|
||||
}}
|
||||
{{ report.winner === 'draw' ? t('messagesView.draw') : isPlayerVictory ? t('messagesView.victory') : t('messagesView.defeat') }}
|
||||
</p>
|
||||
<p v-if="report.rounds" class="text-sm mt-1">{{ t('simulatorView.afterRounds').replace('{rounds}', String(report.rounds)) }}</p>
|
||||
</div>
|
||||
@@ -92,86 +86,88 @@
|
||||
</div>
|
||||
|
||||
<!-- 剩余单位 -->
|
||||
<div v-if="report.attackerRemaining || report.defenderRemaining" class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div v-if="hasAnyRemaining" class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<!-- 攻击方剩余 -->
|
||||
<div v-if="report.attackerRemaining && Object.keys(report.attackerRemaining).length > 0" class="space-y-2">
|
||||
<div class="space-y-2">
|
||||
<p class="text-sm font-medium text-blue-600 dark:text-blue-400">{{ t('messagesView.attackerRemaining') }}</p>
|
||||
<div class="p-3 bg-muted rounded-lg space-y-1 text-xs">
|
||||
<div v-for="(count, shipType) in report.attackerRemaining" :key="shipType">
|
||||
<span class="text-muted-foreground">{{ SHIPS[shipType].name }}:</span>
|
||||
<span class="ml-2 font-medium">{{ count }}</span>
|
||||
</div>
|
||||
<template v-if="report.attackerRemaining && Object.keys(report.attackerRemaining).length > 0">
|
||||
<div v-for="(count, shipType) in report.attackerRemaining" :key="shipType">
|
||||
<span class="text-muted-foreground">{{ SHIPS[shipType].name }}:</span>
|
||||
<span class="ml-2 font-medium">{{ count }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<p v-else class="text-muted-foreground">{{ t('messagesView.allDestroyed') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 防守方剩余 -->
|
||||
<div
|
||||
v-if="
|
||||
report.defenderRemaining &&
|
||||
(Object.keys(report.defenderRemaining.fleet || {}).length > 0 ||
|
||||
Object.keys(report.defenderRemaining.defense || {}).length > 0)
|
||||
"
|
||||
class="space-y-2"
|
||||
>
|
||||
<div class="space-y-2">
|
||||
<p class="text-sm font-medium text-blue-600 dark:text-blue-400">{{ t('messagesView.defenderRemaining') }}</p>
|
||||
<div class="p-3 bg-muted rounded-lg space-y-1 text-xs">
|
||||
<div v-for="(count, shipType) in report.defenderRemaining.fleet" :key="shipType">
|
||||
<span class="text-muted-foreground">{{ SHIPS[shipType].name }}:</span>
|
||||
<span class="ml-2 font-medium">{{ count }}</span>
|
||||
</div>
|
||||
<div v-for="(count, defenseType) in report.defenderRemaining.defense" :key="defenseType">
|
||||
<span class="text-muted-foreground">{{ DEFENSES[defenseType].name }}:</span>
|
||||
<span class="ml-2 font-medium">{{ count }}</span>
|
||||
</div>
|
||||
<template
|
||||
v-if="
|
||||
report.defenderRemaining &&
|
||||
(Object.keys(report.defenderRemaining.fleet || {}).length > 0 ||
|
||||
Object.keys(report.defenderRemaining.defense || {}).length > 0)
|
||||
"
|
||||
>
|
||||
<div v-for="(count, shipType) in report.defenderRemaining.fleet" :key="shipType">
|
||||
<span class="text-muted-foreground">{{ SHIPS[shipType].name }}:</span>
|
||||
<span class="ml-2 font-medium">{{ count }}</span>
|
||||
</div>
|
||||
<div v-for="(count, defenseType) in report.defenderRemaining.defense" :key="defenseType">
|
||||
<span class="text-muted-foreground">{{ DEFENSES[defenseType].name }}:</span>
|
||||
<span class="ml-2 font-medium">{{ count }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<p v-else class="text-muted-foreground">{{ t('messagesView.allDestroyed') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 战利品和残骸 -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<!-- 掠夺资源 -->
|
||||
<div
|
||||
v-if="report.plunder && (report.plunder.metal > 0 || report.plunder.crystal > 0 || report.plunder.deuterium > 0)"
|
||||
class="p-3 bg-green-50 dark:bg-green-950 rounded-lg"
|
||||
>
|
||||
<p class="text-sm font-medium mb-2 text-green-600 dark:text-green-400">{{ t('messagesView.plunder') }}</p>
|
||||
<div class="flex flex-wrap gap-3 text-xs">
|
||||
<span v-if="report.plunder.metal > 0" class="flex items-center gap-1">
|
||||
<ResourceIcon type="metal" size="sm" />
|
||||
{{ formatNumber(report.plunder.metal) }}
|
||||
</span>
|
||||
<span v-if="report.plunder.crystal > 0" class="flex items-center gap-1">
|
||||
<ResourceIcon type="crystal" size="sm" />
|
||||
{{ formatNumber(report.plunder.crystal) }}
|
||||
</span>
|
||||
<span v-if="report.plunder.deuterium > 0" class="flex items-center gap-1">
|
||||
<ResourceIcon type="deuterium" size="sm" />
|
||||
{{ formatNumber(report.plunder.deuterium) }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- 掠夺资源 -->
|
||||
<div
|
||||
v-if="report.plunder && (report.plunder.metal > 0 || report.plunder.crystal > 0 || report.plunder.deuterium > 0)"
|
||||
class="p-3 bg-green-50 dark:bg-green-950 rounded-lg"
|
||||
>
|
||||
<p class="text-sm font-medium mb-2 text-green-600 dark:text-green-400">{{ t('messagesView.plunder') }}</p>
|
||||
<div class="flex flex-wrap gap-3 text-xs justify-center">
|
||||
<span v-if="report.plunder.metal > 0" class="flex items-center gap-1">
|
||||
<ResourceIcon type="metal" size="sm" />
|
||||
{{ formatNumber(report.plunder.metal) }}
|
||||
</span>
|
||||
<span v-if="report.plunder.crystal > 0" class="flex items-center gap-1">
|
||||
<ResourceIcon type="crystal" size="sm" />
|
||||
{{ formatNumber(report.plunder.crystal) }}
|
||||
</span>
|
||||
<span v-if="report.plunder.deuterium > 0" class="flex items-center gap-1">
|
||||
<ResourceIcon type="deuterium" size="sm" />
|
||||
{{ formatNumber(report.plunder.deuterium) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 残骸场 -->
|
||||
<div
|
||||
v-if="report.debrisField && (report.debrisField.metal > 0 || report.debrisField.crystal > 0)"
|
||||
class="p-3 bg-muted rounded-lg"
|
||||
>
|
||||
<p class="text-sm font-medium mb-2">{{ t('messagesView.debrisField') }}</p>
|
||||
<div class="flex flex-wrap gap-3 text-xs">
|
||||
<span v-if="report.debrisField.metal > 0" class="flex items-center gap-1">
|
||||
<ResourceIcon type="metal" size="sm" />
|
||||
{{ formatNumber(report.debrisField.metal) }}
|
||||
</span>
|
||||
<span v-if="report.debrisField.crystal > 0" class="flex items-center gap-1">
|
||||
<ResourceIcon type="crystal" size="sm" />
|
||||
{{ formatNumber(report.debrisField.crystal) }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- 月球生成概率 -->
|
||||
<p v-if="report.moonChance && report.moonChance > 0" class="text-xs text-muted-foreground mt-2">
|
||||
{{ t('messagesView.moonChance') }}: {{ (report.moonChance * 100).toFixed(1) }}%
|
||||
</p>
|
||||
<!-- 残骸场 -->
|
||||
<div
|
||||
v-if="report.debrisField && (report.debrisField.metal > 0 || report.debrisField.crystal > 0)"
|
||||
class="text-center p-4 bg-muted rounded-lg"
|
||||
>
|
||||
<p class="text-sm font-medium mb-2">{{ t('messagesView.debrisField') }}</p>
|
||||
<div class="flex flex-wrap gap-3 text-xs justify-center">
|
||||
<span v-if="report.debrisField.metal > 0" class="flex items-center gap-1">
|
||||
<ResourceIcon type="metal" size="sm" />
|
||||
{{ formatNumber(report.debrisField.metal) }}
|
||||
</span>
|
||||
<span v-if="report.debrisField.crystal > 0" class="flex items-center gap-1">
|
||||
<ResourceIcon type="crystal" size="sm" />
|
||||
{{ formatNumber(report.debrisField.crystal) }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- 月球生成概率 -->
|
||||
<p v-if="report.moonChance && report.moonChance > 0" class="text-xs text-muted-foreground mt-2">
|
||||
{{ t('messagesView.moonChance') }}: {{ (report.moonChance * 100).toFixed(1) }}%
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 回合详情 -->
|
||||
@@ -301,7 +297,11 @@
|
||||
// 获取攻击方星球信息
|
||||
const attackerPlanet = computed(() => {
|
||||
if (!props.report) return null
|
||||
return gameStore.player.planets.find(p => p.id === props.report!.attackerPlanetId)
|
||||
// 先从玩家星球中查找
|
||||
const playerPlanet = gameStore.player.planets.find(p => p.id === props.report!.attackerPlanetId)
|
||||
if (playerPlanet) return playerPlanet
|
||||
// 再从宇宙星球地图中查找(包括 NPC 星球)
|
||||
return Object.values(universeStore.planets).find(p => p.id === props.report!.attackerPlanetId)
|
||||
})
|
||||
|
||||
// 获取防守方星球信息
|
||||
@@ -310,10 +310,35 @@
|
||||
// 先从玩家星球中查找
|
||||
const playerPlanet = gameStore.player.planets.find(p => p.id === props.report!.defenderPlanetId)
|
||||
if (playerPlanet) return playerPlanet
|
||||
// 再从宇宙星球地图中查找
|
||||
// 再从宇宙星球地图中查找(包括 NPC 星球)
|
||||
return Object.values(universeStore.planets).find(p => p.id === props.report!.defenderPlanetId)
|
||||
})
|
||||
|
||||
// 判断玩家是攻击方还是防守方
|
||||
const isPlayerAttacker = computed(() => {
|
||||
if (!props.report) return false
|
||||
return gameStore.player.planets.some(p => p.id === props.report!.attackerPlanetId)
|
||||
})
|
||||
|
||||
// 判断玩家是否胜利
|
||||
const isPlayerVictory = computed(() => {
|
||||
if (!props.report) return false
|
||||
if (props.report.winner === 'draw') return false
|
||||
// 玩家是攻击方且攻击方胜利,或者玩家是防守方且防守方胜利
|
||||
return (isPlayerAttacker.value && props.report.winner === 'attacker') || (!isPlayerAttacker.value && props.report.winner === 'defender')
|
||||
})
|
||||
|
||||
// 判断是否有任何剩余单位需要显示
|
||||
const hasAnyRemaining = computed(() => {
|
||||
if (!props.report) return false
|
||||
const hasAttackerRemaining = props.report.attackerRemaining && Object.keys(props.report.attackerRemaining).length > 0
|
||||
const hasDefenderRemaining =
|
||||
props.report.defenderRemaining &&
|
||||
(Object.keys(props.report.defenderRemaining.fleet || {}).length > 0 ||
|
||||
Object.keys(props.report.defenderRemaining.defense || {}).length > 0)
|
||||
return hasAttackerRemaining || hasDefenderRemaining
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.open,
|
||||
newValue => {
|
||||
@@ -328,10 +353,11 @@
|
||||
emit('update:open', newValue)
|
||||
})
|
||||
|
||||
// 获取胜利者样式
|
||||
const getWinnerStyle = (winner: string) => {
|
||||
if (winner === 'attacker') return 'bg-green-50 dark:bg-green-950 text-green-700 dark:text-green-300'
|
||||
if (winner === 'defender') return 'bg-red-50 dark:bg-red-950 text-red-700 dark:text-red-300'
|
||||
return 'bg-gray-50 dark:bg-gray-950 text-gray-700 dark:text-gray-300'
|
||||
// 获取玩家战斗结果样式
|
||||
const getPlayerResultStyle = () => {
|
||||
if (!props.report) return 'bg-gray-50 dark:bg-gray-950 text-gray-700 dark:text-gray-300'
|
||||
if (props.report.winner === 'draw') return 'bg-gray-50 dark:bg-gray-950 text-gray-700 dark:text-gray-300'
|
||||
if (isPlayerVictory.value) return 'bg-green-50 dark:bg-green-950 text-green-700 dark:text-green-300'
|
||||
return 'bg-red-50 dark:bg-red-950 text-red-700 dark:text-red-300'
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -17,8 +17,14 @@
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>{{ requirementsDialogTitle }}</AlertDialogTitle>
|
||||
<AlertDialogDescription class="whitespace-pre-line">
|
||||
{{ requirementsDialogMessage }}
|
||||
<AlertDialogDescription>
|
||||
<div class="space-y-2">
|
||||
<div v-for="(req, index) in requirementsDialogItems" :key="index" class="flex items-center gap-2 text-sm">
|
||||
<Check v-if="req.met" :size="16" class="text-green-500 flex-shrink-0" />
|
||||
<X v-else :size="16" class="text-red-500 flex-shrink-0" />
|
||||
<span>{{ req.name }}: Lv {{ req.requiredLevel }} ({{ t('common.current') }}: Lv {{ req.currentLevel }})</span>
|
||||
</div>
|
||||
</div>
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
@@ -35,7 +41,7 @@
|
||||
import { useI18n } from '@/composables/useI18n'
|
||||
import { useGameConfig } from '@/composables/useGameConfig'
|
||||
import { BuildingType, TechnologyType } from '@/types/game'
|
||||
import { Lock } from 'lucide-vue-next'
|
||||
import { Lock, Check, X } from 'lucide-vue-next'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import {
|
||||
AlertDialog,
|
||||
@@ -61,7 +67,7 @@
|
||||
// AlertDialog 状态
|
||||
const requirementsDialogOpen = ref(false)
|
||||
const requirementsDialogTitle = ref('')
|
||||
const requirementsDialogMessage = ref('')
|
||||
const requirementsDialogItems = ref<Array<{ name: string; requiredLevel: number; currentLevel: number; met: boolean }>>([])
|
||||
|
||||
const isUnlocked = computed(() => {
|
||||
// 如果已经建造过(level > 0),则认为已解锁,不显示遮罩
|
||||
@@ -70,34 +76,32 @@
|
||||
return publicLogic.checkRequirements(gameStore.currentPlanet, gameStore.player.technologies, props.requirements)
|
||||
})
|
||||
|
||||
const getRequirementsList = (): string => {
|
||||
if (!props.requirements || !gameStore.currentPlanet) return ''
|
||||
const getRequirementsList = (): Array<{ name: string; requiredLevel: number; currentLevel: number; met: boolean }> => {
|
||||
if (!props.requirements || !gameStore.currentPlanet) return []
|
||||
|
||||
const lines: string[] = []
|
||||
const items: Array<{ name: string; requiredLevel: number; currentLevel: number; met: boolean }> = []
|
||||
for (const [key, requiredLevel] of Object.entries(props.requirements)) {
|
||||
// 检查是否为建筑类型
|
||||
if (Object.values(BuildingType).includes(key as BuildingType)) {
|
||||
const buildingType = key as BuildingType
|
||||
const currentLevel = gameStore.currentPlanet.buildings[buildingType] || 0
|
||||
const name = BUILDINGS.value[buildingType]?.name || buildingType
|
||||
const status = currentLevel >= requiredLevel ? '✓' : '✗'
|
||||
lines.push(`${status} ${name}: Lv ${requiredLevel} (${t('common.current')}: Lv ${currentLevel})`)
|
||||
items.push({ name, requiredLevel, currentLevel, met: currentLevel >= requiredLevel })
|
||||
}
|
||||
// 检查是否为科技类型
|
||||
else if (Object.values(TechnologyType).includes(key as TechnologyType)) {
|
||||
const techType = key as TechnologyType
|
||||
const currentLevel = gameStore.player.technologies[techType] || 0
|
||||
const name = TECHNOLOGIES.value[techType]?.name || techType
|
||||
const status = currentLevel >= requiredLevel ? '✓' : '✗'
|
||||
lines.push(`${status} ${name}: Lv ${requiredLevel} (${t('common.current')}: Lv ${currentLevel})`)
|
||||
items.push({ name, requiredLevel, currentLevel, met: currentLevel >= requiredLevel })
|
||||
}
|
||||
}
|
||||
return lines.join('\n')
|
||||
return items
|
||||
}
|
||||
|
||||
const showRequirements = () => {
|
||||
requirementsDialogTitle.value = t('common.requirementsNotMet')
|
||||
requirementsDialogMessage.value = getRequirementsList()
|
||||
requirementsDialogItems.value = getRequirementsList()
|
||||
requirementsDialogOpen.value = true
|
||||
}
|
||||
</script>
|
||||
|
||||
338
src/components/DiplomaticNotifications.vue
Normal file
338
src/components/DiplomaticNotifications.vue
Normal file
@@ -0,0 +1,338 @@
|
||||
<template>
|
||||
<Popover v-model:open="isOpen">
|
||||
<PopoverTrigger as-child>
|
||||
<Button variant="outline" size="icon" class="relative">
|
||||
<ScrollText class="h-4 w-4" />
|
||||
<Badge
|
||||
v-if="unreadCount > 0"
|
||||
variant="destructive"
|
||||
class="absolute -top-1 -right-1 h-5 w-5 p-0 flex items-center justify-center text-xs"
|
||||
>
|
||||
{{ unreadCount }}
|
||||
</Badge>
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-96 p-0" align="end">
|
||||
<div class="flex items-center justify-between p-4 border-b">
|
||||
<h3 class="font-semibold">{{ t('diplomacy.notifications') }}</h3>
|
||||
<Button v-if="unreadCount > 0" variant="ghost" size="sm" @click="markAllAsRead">
|
||||
{{ t('diplomacy.markAllRead') }}
|
||||
</Button>
|
||||
</div>
|
||||
<ScrollArea class="h-96">
|
||||
<Empty v-if="reports.length === 0" class="border-0">
|
||||
<EmptyContent>
|
||||
<ScrollText class="h-10 w-10 text-muted-foreground" />
|
||||
<EmptyDescription>{{ t('diplomacy.noReports') }}</EmptyDescription>
|
||||
</EmptyContent>
|
||||
</Empty>
|
||||
<div v-else class="divide-y">
|
||||
<div
|
||||
v-for="report in reports"
|
||||
:key="report.id"
|
||||
class="p-3 hover:bg-muted/50 cursor-pointer transition-colors"
|
||||
:class="{ 'bg-primary/5': !report.read }"
|
||||
@click="handleReportClick(report)"
|
||||
>
|
||||
<div class="flex items-center gap-3">
|
||||
<!-- 左侧:事件图标 -->
|
||||
<div class="flex-shrink-0">
|
||||
<component :is="getEventIcon(report.eventType)" class="h-5 w-5" :class="getEventIconColor(report.eventType)" />
|
||||
</div>
|
||||
<!-- 中间:主要信息 -->
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-medium text-sm truncate">{{ report.npcName }}</span>
|
||||
<Badge :variant="getStatusBadgeVariant(report.newStatus)" class="text-xs flex-shrink-0">
|
||||
{{ getStatusText(report.newStatus) }}
|
||||
</Badge>
|
||||
</div>
|
||||
<p class="text-xs text-muted-foreground mt-0.5">
|
||||
{{ getEventTypeText(report.eventType) }}
|
||||
</p>
|
||||
</div>
|
||||
<!-- 右侧:好感度变化和时间 -->
|
||||
<div class="flex-shrink-0 text-right">
|
||||
<span
|
||||
class="text-sm font-bold block"
|
||||
:class="report.reputationChange >= 0 ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400'"
|
||||
>
|
||||
{{ report.reputationChange >= 0 ? '+' : '' }}{{ report.reputationChange }}
|
||||
</span>
|
||||
<span class="text-[10px] text-muted-foreground">
|
||||
{{ formatRelativeTime((Date.now() - report.timestamp) / 1000, t) }}{{ t('diplomacy.ago') }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- 未读标记 -->
|
||||
<span v-if="!report.read" class="h-2 w-2 rounded-full bg-destructive flex-shrink-0" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ScrollArea>
|
||||
<div v-if="reports.length > 0" class="p-2 border-t">
|
||||
<Button variant="ghost" size="sm" class="w-full" @click="goToDiplomacy">
|
||||
{{ t('diplomacy.viewAll') }}
|
||||
</Button>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
||||
<!-- 外交报告详情对话框 -->
|
||||
<Dialog :open="detailDialogOpen" @update:open="detailDialogOpen = $event">
|
||||
<DialogContent class="max-w-2xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle class="flex items-center gap-2">
|
||||
<component
|
||||
v-if="selectedReport"
|
||||
:is="getEventIcon(selectedReport.eventType)"
|
||||
class="h-5 w-5"
|
||||
:class="getEventIconColor(selectedReport.eventType)"
|
||||
/>
|
||||
{{ t('diplomacy.reportDetails') }}
|
||||
</DialogTitle>
|
||||
<DialogDescription class="sr-only">
|
||||
{{ t('diplomacy.reportDetails') }}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div v-if="selectedReport" class="space-y-4">
|
||||
<!-- NPC信息 -->
|
||||
<div class="flex items-center gap-3 p-4 bg-muted/50 rounded-lg">
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center gap-2 mb-1">
|
||||
<h3 class="font-semibold text-lg">{{ selectedReport.npcName }}</h3>
|
||||
<Badge :variant="getStatusBadgeVariant(selectedReport.newStatus)">
|
||||
{{ getStatusText(selectedReport.newStatus) }}
|
||||
</Badge>
|
||||
</div>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
{{ formatRelativeTime((Date.now() - selectedReport.timestamp) / 1000, t) }}{{ t('diplomacy.ago') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 事件描述 -->
|
||||
<div class="space-y-2">
|
||||
<h4 class="font-semibold text-sm">{{ t('diplomacy.eventDescription') }}</h4>
|
||||
<p class="text-sm p-3 bg-muted/30 rounded-md">
|
||||
{{
|
||||
selectedReport.messageKey && selectedReport.messageParams
|
||||
? t(selectedReport.messageKey, selectedReport.messageParams)
|
||||
: selectedReport.message
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 关系变化 -->
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<!-- 好感度变化 -->
|
||||
<div class="space-y-2">
|
||||
<h4 class="font-semibold text-sm">{{ t('diplomacy.reputationChange') }}</h4>
|
||||
<div class="p-3 bg-muted/30 rounded-md">
|
||||
<div class="flex items-center justify-between text-sm mb-2">
|
||||
<span class="text-muted-foreground">{{ t('diplomacy.before') }}</span>
|
||||
<span class="font-semibold" :class="getReputationColor(selectedReport.newReputation - selectedReport.reputationChange)">
|
||||
{{ selectedReport.newReputation - selectedReport.reputationChange > 0 ? '+' : ''
|
||||
}}{{ selectedReport.newReputation - selectedReport.reputationChange }}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center justify-center text-lg font-bold my-1"
|
||||
:class="selectedReport.reputationChange >= 0 ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400'"
|
||||
>
|
||||
{{ selectedReport.reputationChange >= 0 ? '+' : '' }}{{ selectedReport.reputationChange }}
|
||||
</div>
|
||||
<div class="flex items-center justify-between text-sm mt-2">
|
||||
<span class="text-muted-foreground">{{ t('diplomacy.after') }}</span>
|
||||
<span class="font-semibold" :class="getReputationColor(selectedReport.newReputation)">
|
||||
{{ selectedReport.newReputation > 0 ? '+' : '' }}{{ selectedReport.newReputation }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 关系状态变化 -->
|
||||
<div class="space-y-2">
|
||||
<h4 class="font-semibold text-sm">{{ t('diplomacy.statusChange') }}</h4>
|
||||
<div class="p-3 bg-muted/30 rounded-md">
|
||||
<div class="flex items-center justify-between text-sm mb-2">
|
||||
<span class="text-muted-foreground">{{ t('diplomacy.before') }}</span>
|
||||
<Badge :variant="getStatusBadgeVariant(selectedReport.oldStatus)" class="text-xs">
|
||||
{{ getStatusText(selectedReport.oldStatus) }}
|
||||
</Badge>
|
||||
</div>
|
||||
<div class="flex items-center justify-center my-3">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6 text-muted-foreground"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 14l-7 7m0 0l-7-7m7 7V3" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex items-center justify-between text-sm mt-2">
|
||||
<span class="text-muted-foreground">{{ t('diplomacy.after') }}</span>
|
||||
<Badge :variant="getStatusBadgeVariant(selectedReport.newStatus)" class="text-xs">
|
||||
{{ getStatusText(selectedReport.newStatus) }}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DialogFooter>
|
||||
<Button variant="outline" @click="detailDialogOpen = false">{{ t('common.close') }}</Button>
|
||||
<Button @click="goToDiplomacyFromDialog">{{ t('diplomacy.viewDiplomacy') }}</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useGameStore } from '@/stores/gameStore'
|
||||
import { useI18n } from '@/composables/useI18n'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from '@/components/ui/dialog'
|
||||
import { ScrollArea } from '@/components/ui/scroll-area'
|
||||
import { ScrollText, Gift, Sword, Eye, Trash2, Skull } from 'lucide-vue-next'
|
||||
import { Empty, EmptyContent, EmptyDescription } from '@/components/ui/empty'
|
||||
import { RelationStatus, DiplomaticEventType } from '@/types/game'
|
||||
import type { DiplomaticReport } from '@/types/game'
|
||||
import { formatRelativeTime } from '@/utils/format'
|
||||
|
||||
const router = useRouter()
|
||||
const gameStore = useGameStore()
|
||||
const { t } = useI18n()
|
||||
const isOpen = ref(false)
|
||||
const detailDialogOpen = ref(false)
|
||||
const selectedReport = ref<DiplomaticReport | null>(null)
|
||||
|
||||
const reports = computed(() => {
|
||||
return (gameStore.player.diplomaticReports || []).slice().reverse().slice(0, 20) // 最近20条
|
||||
})
|
||||
|
||||
const unreadCount = computed(() => {
|
||||
return (gameStore.player.diplomaticReports || []).filter(r => !r.read).length
|
||||
})
|
||||
|
||||
const getEventIcon = (eventType: DiplomaticReport['eventType']) => {
|
||||
switch (eventType) {
|
||||
case DiplomaticEventType.GiftResources:
|
||||
return Gift
|
||||
case DiplomaticEventType.Attack:
|
||||
case DiplomaticEventType.AllyAttacked:
|
||||
return Sword
|
||||
case DiplomaticEventType.Spy:
|
||||
return Eye
|
||||
case DiplomaticEventType.StealDebris:
|
||||
return Trash2
|
||||
case DiplomaticEventType.DestroyPlanet:
|
||||
return Skull
|
||||
default:
|
||||
return ScrollText
|
||||
}
|
||||
}
|
||||
|
||||
const getEventIconColor = (eventType: DiplomaticReport['eventType']) => {
|
||||
switch (eventType) {
|
||||
case DiplomaticEventType.GiftResources:
|
||||
return 'text-green-500'
|
||||
case DiplomaticEventType.Attack:
|
||||
case DiplomaticEventType.DestroyPlanet:
|
||||
return 'text-red-500'
|
||||
case DiplomaticEventType.AllyAttacked:
|
||||
return 'text-orange-500'
|
||||
case DiplomaticEventType.Spy:
|
||||
return 'text-purple-500'
|
||||
case DiplomaticEventType.StealDebris:
|
||||
return 'text-yellow-500'
|
||||
default:
|
||||
return 'text-muted-foreground'
|
||||
}
|
||||
}
|
||||
|
||||
const getEventTypeText = (eventType: DiplomaticReport['eventType']) => {
|
||||
switch (eventType) {
|
||||
case DiplomaticEventType.GiftResources:
|
||||
return t('diplomacy.eventType.gift')
|
||||
case DiplomaticEventType.Attack:
|
||||
return t('diplomacy.eventType.attack')
|
||||
case DiplomaticEventType.AllyAttacked:
|
||||
return t('diplomacy.eventType.allyAttacked')
|
||||
case DiplomaticEventType.Spy:
|
||||
return t('diplomacy.eventType.spy')
|
||||
case DiplomaticEventType.StealDebris:
|
||||
return t('diplomacy.eventType.stealDebris')
|
||||
case DiplomaticEventType.DestroyPlanet:
|
||||
return t('diplomacy.eventType.destroyPlanet')
|
||||
default:
|
||||
return t('diplomacy.eventType.unknown')
|
||||
}
|
||||
}
|
||||
|
||||
const getStatusBadgeVariant = (status: RelationStatus) => {
|
||||
switch (status) {
|
||||
case RelationStatus.Hostile:
|
||||
return 'destructive'
|
||||
case RelationStatus.Friendly:
|
||||
return 'default'
|
||||
case RelationStatus.Neutral:
|
||||
default:
|
||||
return 'secondary'
|
||||
}
|
||||
}
|
||||
|
||||
const getStatusText = (status: RelationStatus) => {
|
||||
switch (status) {
|
||||
case RelationStatus.Hostile:
|
||||
return t('diplomacy.status.hostile')
|
||||
case RelationStatus.Friendly:
|
||||
return t('diplomacy.status.friendly')
|
||||
case RelationStatus.Neutral:
|
||||
default:
|
||||
return t('diplomacy.status.neutral')
|
||||
}
|
||||
}
|
||||
|
||||
const getReputationColor = (reputation: number | null) => {
|
||||
if (reputation === null) return 'text-muted-foreground'
|
||||
if (reputation >= 20) return 'text-green-600 dark:text-green-400'
|
||||
if (reputation <= -20) return 'text-red-600 dark:text-red-400'
|
||||
return 'text-muted-foreground'
|
||||
}
|
||||
|
||||
const handleReportClick = (report: DiplomaticReport) => {
|
||||
// 标记为已读
|
||||
report.read = true
|
||||
// 设置选中的报告
|
||||
selectedReport.value = report
|
||||
// 关闭通知面板
|
||||
isOpen.value = true
|
||||
// 打开对话框
|
||||
detailDialogOpen.value = true
|
||||
}
|
||||
|
||||
const markAllAsRead = () => {
|
||||
gameStore.player.diplomaticReports?.forEach(report => {
|
||||
report.read = true
|
||||
})
|
||||
}
|
||||
|
||||
const goToDiplomacy = () => {
|
||||
isOpen.value = false
|
||||
router.push('/diplomacy')
|
||||
}
|
||||
|
||||
const goToDiplomacyFromDialog = () => {
|
||||
const npcId = selectedReport.value?.npcId
|
||||
detailDialogOpen.value = false
|
||||
router.push(npcId ? `/diplomacy?npcId=${npcId}` : '/diplomacy')
|
||||
}
|
||||
</script>
|
||||
304
src/components/EnemyAlertNotifications.vue
Normal file
304
src/components/EnemyAlertNotifications.vue
Normal file
@@ -0,0 +1,304 @@
|
||||
<template>
|
||||
<Popover v-model:open="isOpen">
|
||||
<PopoverTrigger as-child>
|
||||
<Button variant="outline" size="icon" class="relative">
|
||||
<Siren class="h-4 w-4" />
|
||||
<Badge
|
||||
v-if="activeAlerts.length > 0"
|
||||
variant="destructive"
|
||||
class="absolute -top-1 -right-1 h-5 w-5 p-0 flex items-center justify-center text-xs animate-pulse"
|
||||
>
|
||||
{{ activeAlerts.length }}
|
||||
</Badge>
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-96 p-0" align="end">
|
||||
<div class="flex items-center justify-between p-4 border-b">
|
||||
<h3 class="font-semibold">{{ t('enemyAlert.title') }}</h3>
|
||||
<Button v-if="activeAlerts.length > 0" variant="ghost" size="sm" @click="markAllAsRead">
|
||||
{{ t('enemyAlert.markAllRead') }}
|
||||
</Button>
|
||||
</div>
|
||||
<ScrollArea class="h-96">
|
||||
<Empty v-if="activeAlerts.length === 0" class="border-0">
|
||||
<EmptyContent>
|
||||
<Shield class="h-10 w-10 text-muted-foreground" />
|
||||
<EmptyDescription>{{ t('enemyAlert.noAlerts') }}</EmptyDescription>
|
||||
</EmptyContent>
|
||||
</Empty>
|
||||
<div v-else class="divide-y">
|
||||
<div
|
||||
v-for="alert in activeAlerts"
|
||||
:key="alert.id"
|
||||
class="p-3 hover:bg-muted/50 cursor-pointer transition-colors"
|
||||
:class="{ 'bg-destructive/10': !alert.read }"
|
||||
@click="handleAlertClick(alert)"
|
||||
>
|
||||
<div class="flex items-center gap-3">
|
||||
<!-- 左侧:任务图标 -->
|
||||
<div class="flex-shrink-0">
|
||||
<component :is="getMissionIcon(alert.missionType)" class="h-5 w-5" :class="getMissionIconColor(alert.missionType)" />
|
||||
</div>
|
||||
<!-- 中间:主要信息 -->
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-medium text-sm truncate">{{ alert.npcName }}</span>
|
||||
<Badge :variant="getMissionBadgeVariant(alert.missionType)" class="text-xs flex-shrink-0">
|
||||
{{ getMissionTypeText(alert.missionType) }}
|
||||
</Badge>
|
||||
</div>
|
||||
<p class="text-xs text-muted-foreground mt-0.5">
|
||||
{{ alert.targetPlanetName }} · {{ t('enemyAlert.fleetSize') }}: {{ alert.fleetSize }}
|
||||
</p>
|
||||
</div>
|
||||
<!-- 右侧:倒计时 -->
|
||||
<div class="flex-shrink-0 text-right">
|
||||
<span class="text-sm font-bold block" :class="getRemainingTimeColor(alert)">
|
||||
{{ formatRemainingTime(alert) }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- 未读标记 -->
|
||||
<span v-if="!alert.read" class="h-2 w-2 rounded-full bg-destructive flex-shrink-0 animate-pulse" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ScrollArea>
|
||||
<div v-if="activeAlerts.length > 0" class="p-2 border-t">
|
||||
<Button variant="ghost" size="sm" class="w-full" @click="goToFleet">
|
||||
{{ t('enemyAlert.viewFleet') }}
|
||||
</Button>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
||||
<!-- 警报详情对话框 -->
|
||||
<Dialog :open="detailDialogOpen" @update:open="detailDialogOpen = $event">
|
||||
<DialogContent class="max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle class="flex items-center gap-2">
|
||||
<component
|
||||
v-if="selectedAlert"
|
||||
:is="getMissionIcon(selectedAlert.missionType)"
|
||||
class="h-5 w-5"
|
||||
:class="getMissionIconColor(selectedAlert.missionType)"
|
||||
/>
|
||||
{{ t('enemyAlert.alertDetails') }}
|
||||
</DialogTitle>
|
||||
<DialogDescription class="sr-only">
|
||||
{{ t('enemyAlert.alertDetails') }}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div v-if="selectedAlert" class="space-y-4">
|
||||
<!-- 敌方信息 -->
|
||||
<div class="flex items-center gap-3 p-4 bg-destructive/10 rounded-lg">
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center gap-2 mb-1">
|
||||
<h3 class="font-semibold text-lg">{{ selectedAlert.npcName }}</h3>
|
||||
<Badge :variant="getMissionBadgeVariant(selectedAlert.missionType)">
|
||||
{{ getMissionTypeText(selectedAlert.missionType) }}
|
||||
</Badge>
|
||||
</div>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
{{ t('enemyAlert.fleetSize') }}: {{ selectedAlert.fleetSize }} {{ t('enemyAlert.ships') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 目标信息 -->
|
||||
<div class="space-y-2">
|
||||
<h4 class="font-semibold text-sm">{{ t('enemyAlert.targetInfo') }}</h4>
|
||||
<div class="p-3 bg-muted/30 rounded-md flex items-center gap-2">
|
||||
<Globe class="h-4 w-4 text-blue-500" />
|
||||
<span class="font-medium">{{ selectedAlert.targetPlanetName }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 到达时间 -->
|
||||
<div class="space-y-2">
|
||||
<h4 class="font-semibold text-sm">{{ t('enemyAlert.arrivalTime') }}</h4>
|
||||
<div class="p-3 bg-muted/30 rounded-md">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-muted-foreground">{{ t('enemyAlert.countdown') }}</span>
|
||||
<span class="font-bold text-lg" :class="getRemainingTimeColor(selectedAlert)">
|
||||
{{ formatRemainingTime(selectedAlert) }}
|
||||
</span>
|
||||
</div>
|
||||
<p class="text-xs text-muted-foreground mt-1">
|
||||
{{ formatDate(selectedAlert.arrivalTime) }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 警告提示 -->
|
||||
<div class="p-3 bg-destructive/10 rounded-md border border-destructive/20">
|
||||
<p class="text-sm text-destructive dark:text-red-400">
|
||||
{{ getMissionWarningText(selectedAlert.missionType) }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DialogFooter>
|
||||
<Button variant="outline" @click="detailDialogOpen = false">{{ t('common.close') }}</Button>
|
||||
<Button @click="goToMessagesFromDialog">{{ t('enemyAlert.viewMessages') }}</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useGameStore } from '@/stores/gameStore'
|
||||
import { useI18n } from '@/composables/useI18n'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from '@/components/ui/dialog'
|
||||
import { ScrollArea } from '@/components/ui/scroll-area'
|
||||
import { Empty, EmptyContent, EmptyDescription } from '@/components/ui/empty'
|
||||
import { Siren, Eye, Sword, Shield, Globe } from 'lucide-vue-next'
|
||||
import { MissionType } from '@/types/game'
|
||||
import type { IncomingFleetAlert } from '@/types/game'
|
||||
import { formatDate, formatTime } from '@/utils/format'
|
||||
|
||||
const router = useRouter()
|
||||
const gameStore = useGameStore()
|
||||
const { t } = useI18n()
|
||||
const isOpen = ref(false)
|
||||
const detailDialogOpen = ref(false)
|
||||
const selectedAlert = ref<IncomingFleetAlert | null>(null)
|
||||
const currentTime = ref(Date.now())
|
||||
let timeInterval: ReturnType<typeof setInterval> | null = null
|
||||
|
||||
// 启动计时器,用于实时更新倒计时
|
||||
onMounted(() => {
|
||||
timeInterval = setInterval(() => {
|
||||
currentTime.value = Date.now()
|
||||
}, 1000)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (timeInterval) {
|
||||
clearInterval(timeInterval)
|
||||
timeInterval = null
|
||||
}
|
||||
})
|
||||
|
||||
// 获取活跃的警报(未到达的)
|
||||
const activeAlerts = computed(() => {
|
||||
const now = currentTime.value
|
||||
return (gameStore.player.incomingFleetAlerts || [])
|
||||
.filter(alert => alert.arrivalTime > now)
|
||||
.sort((a, b) => a.arrivalTime - b.arrivalTime) // 按到达时间排序
|
||||
})
|
||||
|
||||
// 获取任务类型图标
|
||||
const getMissionIcon = (missionType: MissionType) => {
|
||||
switch (missionType) {
|
||||
case MissionType.Spy:
|
||||
return Eye
|
||||
case MissionType.Attack:
|
||||
return Sword
|
||||
default:
|
||||
return Siren
|
||||
}
|
||||
}
|
||||
|
||||
// 获取任务类型图标颜色
|
||||
const getMissionIconColor = (missionType: MissionType) => {
|
||||
switch (missionType) {
|
||||
case MissionType.Spy:
|
||||
return 'text-purple-500'
|
||||
case MissionType.Attack:
|
||||
return 'text-red-500'
|
||||
default:
|
||||
return 'text-yellow-500'
|
||||
}
|
||||
}
|
||||
|
||||
// 获取任务类型Badge样式
|
||||
const getMissionBadgeVariant = (missionType: MissionType): 'destructive' | 'secondary' => {
|
||||
return missionType === MissionType.Attack ? 'destructive' : 'secondary'
|
||||
}
|
||||
|
||||
// 获取任务类型文本
|
||||
const getMissionTypeText = (missionType: MissionType) => {
|
||||
switch (missionType) {
|
||||
case MissionType.Spy:
|
||||
return t('enemyAlert.missionType.spy')
|
||||
case MissionType.Attack:
|
||||
return t('enemyAlert.missionType.attack')
|
||||
default:
|
||||
return t('enemyAlert.missionType.unknown')
|
||||
}
|
||||
}
|
||||
|
||||
// 获取任务警告文本
|
||||
const getMissionWarningText = (missionType: MissionType) => {
|
||||
switch (missionType) {
|
||||
case MissionType.Spy:
|
||||
return t('enemyAlert.warning.spy')
|
||||
case MissionType.Attack:
|
||||
return t('enemyAlert.warning.attack')
|
||||
default:
|
||||
return t('enemyAlert.warning.unknown')
|
||||
}
|
||||
}
|
||||
|
||||
// 格式化剩余时间
|
||||
const formatRemainingTime = (alert: IncomingFleetAlert) => {
|
||||
const remaining = Math.max(0, Math.floor((alert.arrivalTime - currentTime.value) / 1000))
|
||||
if (remaining <= 0) {
|
||||
return t('enemyAlert.arrived')
|
||||
}
|
||||
return formatTime(remaining)
|
||||
}
|
||||
|
||||
// 获取剩余时间颜色
|
||||
const getRemainingTimeColor = (alert: IncomingFleetAlert) => {
|
||||
const remaining = alert.arrivalTime - currentTime.value
|
||||
if (remaining <= 0) return 'text-red-600 dark:text-red-400 font-bold' // 已到达
|
||||
if (remaining < 60000) return 'text-red-600 dark:text-red-400' // < 1分钟
|
||||
if (remaining < 300000) return 'text-orange-600 dark:text-orange-400' // < 5分钟
|
||||
return 'text-muted-foreground'
|
||||
}
|
||||
|
||||
// 处理警报点击
|
||||
const handleAlertClick = (alert: IncomingFleetAlert) => {
|
||||
alert.read = true
|
||||
selectedAlert.value = alert
|
||||
isOpen.value = true
|
||||
// 打开对话框
|
||||
detailDialogOpen.value = true
|
||||
}
|
||||
|
||||
// 标记所有为已读
|
||||
const markAllAsRead = () => {
|
||||
gameStore.player.incomingFleetAlerts?.forEach(alert => {
|
||||
alert.read = true
|
||||
})
|
||||
}
|
||||
|
||||
// 跳转到舰队页面
|
||||
const goToFleet = () => {
|
||||
isOpen.value = false
|
||||
router.push('/fleet')
|
||||
}
|
||||
|
||||
// 从对话框跳转到消息页面
|
||||
const goToMessagesFromDialog = () => {
|
||||
detailDialogOpen.value = false
|
||||
router.push('/messages')
|
||||
}
|
||||
|
||||
// 打开弹窗(供外部调用)
|
||||
const open = () => {
|
||||
isOpen.value = true
|
||||
}
|
||||
|
||||
// 暴露方法给父组件
|
||||
defineExpose({
|
||||
open
|
||||
})
|
||||
</script>
|
||||
86
src/components/HintToast.vue
Normal file
86
src/components/HintToast.vue
Normal file
@@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<Transition
|
||||
enter-active-class="transition-all duration-300 ease-out"
|
||||
enter-from-class="-translate-y-4 opacity-0"
|
||||
enter-to-class="translate-y-0 opacity-100"
|
||||
leave-active-class="transition-all duration-200 ease-in"
|
||||
leave-from-class="translate-y-0 opacity-100"
|
||||
leave-to-class="-translate-y-4 opacity-0"
|
||||
>
|
||||
<div
|
||||
v-if="isHintVisible && currentHint"
|
||||
class="fixed top-2 right-2 max-w-[280px] sm:top-4 sm:right-4 sm:max-w-xs z-50 pointer-events-auto"
|
||||
>
|
||||
<div class="bg-card border rounded-lg shadow-lg p-3" role="alert" aria-live="polite">
|
||||
<!-- 标题栏 -->
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<component :is="getIcon(currentHint.icon)" class="h-4 w-4 text-primary flex-shrink-0" />
|
||||
<h4 class="font-medium text-sm">{{ t(currentHint.titleKey) }}</h4>
|
||||
</div>
|
||||
|
||||
<!-- 内容 -->
|
||||
<p class="text-sm text-muted-foreground mb-3 line-clamp-3">{{ t(currentHint.messageKey) }}</p>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="flex items-center justify-end">
|
||||
<Button size="sm" class="text-xs h-7" @click="handleDismiss">
|
||||
{{ t('hints.dontShowAgain') }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useHints } from '@/composables/useHints'
|
||||
import { useI18n } from '@/composables/useI18n'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import {
|
||||
Home,
|
||||
Building,
|
||||
FlaskConical,
|
||||
Rocket,
|
||||
Plane,
|
||||
Globe,
|
||||
Handshake,
|
||||
Mail,
|
||||
Shield,
|
||||
Lightbulb,
|
||||
Users,
|
||||
Swords,
|
||||
Settings,
|
||||
Wand2
|
||||
} from 'lucide-vue-next'
|
||||
import type { Component } from 'vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
const { currentHint, isHintVisible, dismissHint } = useHints()
|
||||
|
||||
// 图标名称到组件的映射
|
||||
const iconMap: Record<string, Component> = {
|
||||
home: Home,
|
||||
building: Building,
|
||||
flask: FlaskConical,
|
||||
rocket: Rocket,
|
||||
plane: Plane,
|
||||
globe: Globe,
|
||||
handshake: Handshake,
|
||||
mail: Mail,
|
||||
shield: Shield,
|
||||
users: Users,
|
||||
swords: Swords,
|
||||
settings: Settings,
|
||||
wand: Wand2
|
||||
}
|
||||
|
||||
const getIcon = (iconName?: string) => {
|
||||
if (!iconName) return Lightbulb
|
||||
return iconMap[iconName] || Lightbulb
|
||||
}
|
||||
|
||||
// 不再显示 - 永久关闭
|
||||
const handleDismiss = () => {
|
||||
dismissHint(true)
|
||||
}
|
||||
</script>
|
||||
@@ -1,67 +1,40 @@
|
||||
<template>
|
||||
<div v-if="alerts.length > 0" class="bg-destructive/10 border-b border-destructive/20">
|
||||
<div class="px-4 sm:px-6 py-2 space-y-2">
|
||||
<div
|
||||
v-for="alert in alerts"
|
||||
:key="alert.id"
|
||||
class="flex items-center justify-between gap-3 bg-destructive/5 rounded-lg px-3 py-2 border border-destructive/20"
|
||||
>
|
||||
<!-- 警告图标和信息 -->
|
||||
<div class="flex items-center gap-2 flex-1 min-w-0">
|
||||
<AlertTriangle class="h-5 w-5 text-destructive flex-shrink-0 animate-pulse" />
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-sm font-semibold text-destructive truncate">
|
||||
<template v-if="alert.missionType === 'spy'">
|
||||
{{ t('alerts.npcSpyIncoming') }}
|
||||
</template>
|
||||
<template v-else-if="alert.missionType === 'attack'">
|
||||
{{ t('alerts.npcAttackIncoming') }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ t('alerts.npcFleetIncoming') }}
|
||||
</template>
|
||||
</p>
|
||||
<p class="text-xs text-muted-foreground truncate">
|
||||
{{ alert.npcName }} → {{ alert.targetPlanetName }}
|
||||
<template v-if="alert.missionType === 'attack'">({{ alert.fleetSize }} {{ t('alerts.ships') }})</template>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 倒计时 -->
|
||||
<div class="flex items-center gap-2 flex-shrink-0">
|
||||
<div class="text-right">
|
||||
<p class="text-xs font-mono text-destructive">
|
||||
{{ formatTimeRemaining(alert.arrivalTime) }}
|
||||
</p>
|
||||
<p class="text-[10px] text-muted-foreground">
|
||||
{{ formatTime(alert.arrivalTime) }}
|
||||
</p>
|
||||
</div>
|
||||
<Button @click="markAsRead(alert)" variant="ghost" size="sm" class="h-6 w-6 p-0">
|
||||
<X class="h-3 w-3" />
|
||||
</Button>
|
||||
<div v-if="activeAlerts.length > 0" class="bg-destructive/10 border-b border-destructive/20">
|
||||
<div class="px-4 sm:px-6 py-2 flex items-center justify-between gap-3">
|
||||
<!-- 警告图标和汇总信息 -->
|
||||
<div class="flex items-center gap-2 flex-1 min-w-0">
|
||||
<AlertTriangle class="h-5 w-5 text-destructive flex-shrink-0 animate-pulse" />
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-sm font-semibold text-destructive">
|
||||
{{ getAlertSummary() }}
|
||||
</p>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
{{ t('enemyAlert.countdown') }}: {{ formatTimeRemaining(nearestAlert?.arrivalTime || 0) }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 查看按钮 -->
|
||||
<Button @click="openAlertPanel" variant="outline" size="sm" class="flex-shrink-0">
|
||||
{{ t('common.view') }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
import type { IncomingFleetAlert } from '@/types/game'
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { useGameStore } from '@/stores/gameStore'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { AlertTriangle, X } from 'lucide-vue-next'
|
||||
import { AlertTriangle } from 'lucide-vue-next'
|
||||
import { useI18n } from '@/composables/useI18n'
|
||||
|
||||
const props = defineProps<{
|
||||
alerts: IncomingFleetAlert[]
|
||||
}>()
|
||||
import { MissionType } from '@/types/game'
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'markAsRead', alert: IncomingFleetAlert): void
|
||||
(e: 'openPanel'): void
|
||||
}>()
|
||||
|
||||
const gameStore = useGameStore()
|
||||
const { t } = useI18n()
|
||||
|
||||
// 强制更新倒计时
|
||||
@@ -78,6 +51,46 @@
|
||||
if (updateInterval) clearInterval(updateInterval)
|
||||
})
|
||||
|
||||
// 获取活跃的警报(未到达的)
|
||||
const activeAlerts = computed(() => {
|
||||
return (gameStore.player.incomingFleetAlerts || [])
|
||||
.filter(alert => alert.arrivalTime > now.value)
|
||||
.sort((a, b) => a.arrivalTime - b.arrivalTime)
|
||||
})
|
||||
|
||||
// 最近的警报
|
||||
const nearestAlert = computed(() => activeAlerts.value[0] || null)
|
||||
|
||||
// 统计各类型警报数量
|
||||
const alertCounts = computed(() => {
|
||||
const counts = { spy: 0, attack: 0, other: 0 }
|
||||
activeAlerts.value.forEach(alert => {
|
||||
if (alert.missionType === MissionType.Spy) {
|
||||
counts.spy++
|
||||
} else if (alert.missionType === MissionType.Attack) {
|
||||
counts.attack++
|
||||
} else {
|
||||
counts.other++
|
||||
}
|
||||
})
|
||||
return counts
|
||||
})
|
||||
|
||||
// 生成警报汇总文本
|
||||
const getAlertSummary = (): string => {
|
||||
const parts: string[] = []
|
||||
if (alertCounts.value.attack > 0) {
|
||||
parts.push(`${alertCounts.value.attack} ${t('enemyAlert.missionType.attack')}`)
|
||||
}
|
||||
if (alertCounts.value.spy > 0) {
|
||||
parts.push(`${alertCounts.value.spy} ${t('enemyAlert.missionType.spy')}`)
|
||||
}
|
||||
if (alertCounts.value.other > 0) {
|
||||
parts.push(`${alertCounts.value.other} ${t('enemyAlert.missionType.unknown')}`)
|
||||
}
|
||||
return t('alerts.incomingFleets', { count: activeAlerts.value.length }) + ': ' + parts.join(', ')
|
||||
}
|
||||
|
||||
const formatTimeRemaining = (arrivalTime: number): string => {
|
||||
const remaining = Math.max(0, arrivalTime - now.value)
|
||||
const seconds = Math.floor((remaining / 1000) % 60)
|
||||
@@ -90,12 +103,7 @@
|
||||
return `${minutes}:${String(seconds).padStart(2, '0')}`
|
||||
}
|
||||
|
||||
const formatTime = (timestamp: number): string => {
|
||||
const date = new Date(timestamp)
|
||||
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
|
||||
}
|
||||
|
||||
const markAsRead = (alert: IncomingFleetAlert) => {
|
||||
emit('markAsRead', alert)
|
||||
const openAlertPanel = () => {
|
||||
emit('openPanel')
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -15,23 +15,37 @@
|
||||
<TableHead v-if="type === 'building' && showProductionColumn" class="text-center">{{ t('buildings.production') }}</TableHead>
|
||||
<TableHead v-if="type === 'building' && showConsumptionColumn" class="text-center">{{ t('buildings.consumption') }}</TableHead>
|
||||
<TableHead v-if="type === 'building' && showCapacityColumn" class="text-center">{{ t('buildings.storageCapacity') }}</TableHead>
|
||||
<TableHead v-if="type === 'building' && showFleetStorageColumn" class="text-center">{{ t('buildings.fleetStorage') }}</TableHead>
|
||||
<TableHead v-if="type === 'building' && showBuildQueueColumn" class="text-center">{{ t('buildings.buildQueueBonus') }}</TableHead>
|
||||
<TableHead v-if="type === 'building' && showFleetStorageColumn" class="text-center">
|
||||
{{ t('buildings.fleetStorage') }}
|
||||
</TableHead>
|
||||
<TableHead v-if="type === 'building' && showBuildQueueColumn" class="text-center">
|
||||
{{ t('buildings.buildQueueBonus') }}
|
||||
</TableHead>
|
||||
<TableHead v-if="type === 'building' && showSpaceColumn" class="text-center">{{ t('buildings.spaceBonus') }}</TableHead>
|
||||
<TableHead v-if="type === 'building' && showMissileColumn" class="text-center">{{ t('buildings.missileCapacity') }}</TableHead>
|
||||
<TableHead v-if="type === 'building' && showBuildSpeedColumn" class="text-center">{{ t('buildings.buildSpeedBonus') }}</TableHead>
|
||||
<TableHead v-if="type === 'building' && showResearchSpeedColumn" class="text-center">{{ t('buildings.researchSpeedBonus') }}</TableHead>
|
||||
<TableHead v-if="type === 'building' && showBuildSpeedColumn" class="text-center">
|
||||
{{ t('buildings.buildSpeedBonus') }}
|
||||
</TableHead>
|
||||
<TableHead v-if="type === 'building' && showResearchSpeedColumn" class="text-center">
|
||||
{{ t('buildings.researchSpeedBonus') }}
|
||||
</TableHead>
|
||||
<!-- 科技相关列 -->
|
||||
<TableHead v-if="type === 'technology' && showAttackBonusColumn" class="text-center">{{ t('research.attackBonus') }}</TableHead>
|
||||
<TableHead v-if="type === 'technology' && showShieldBonusColumn" class="text-center">{{ t('research.shieldBonus') }}</TableHead>
|
||||
<TableHead v-if="type === 'technology' && showArmorBonusColumn" class="text-center">{{ t('research.armorBonus') }}</TableHead>
|
||||
<TableHead v-if="type === 'technology' && showSpyLevelColumn" class="text-center">{{ t('research.spyLevel') }}</TableHead>
|
||||
<TableHead v-if="type === 'technology' && showFleetStorageColumn" class="text-center">{{ t('buildings.fleetStorage') }}</TableHead>
|
||||
<TableHead v-if="type === 'technology' && showResearchQueueColumn" class="text-center">{{ t('research.researchQueueBonus') }}</TableHead>
|
||||
<TableHead v-if="type === 'technology' && showFleetStorageColumn" class="text-center">
|
||||
{{ t('buildings.fleetStorage') }}
|
||||
</TableHead>
|
||||
<TableHead v-if="type === 'technology' && showResearchQueueColumn" class="text-center">
|
||||
{{ t('research.researchQueueBonus') }}
|
||||
</TableHead>
|
||||
<TableHead v-if="type === 'technology' && showColonySlotsColumn" class="text-center">{{ t('research.colonySlots') }}</TableHead>
|
||||
<TableHead v-if="type === 'technology' && showSpaceColumn" class="text-center">{{ t('buildings.spaceBonus') }}</TableHead>
|
||||
<TableHead v-if="type === 'technology' && showSpeedBonusColumn" class="text-center">{{ t('research.speedBonus') }}</TableHead>
|
||||
<TableHead v-if="type === 'technology' && showResearchSpeedColumn" class="text-center">{{ t('buildings.researchSpeedBonus') }}</TableHead>
|
||||
<TableHead v-if="type === 'technology' && showResearchSpeedColumn" class="text-center">
|
||||
{{ t('buildings.researchSpeedBonus') }}
|
||||
</TableHead>
|
||||
<TableHead class="text-center">{{ t('player.points') }}</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
@@ -78,7 +92,8 @@
|
||||
</TableCell>
|
||||
<TableCell v-if="type === 'building' && showFleetStorageColumn" class="text-center text-sm">
|
||||
<span v-if="getLevelData(level).fleetStorage > 0" class="text-blue-600 dark:text-blue-400">
|
||||
+<NumberWithTooltip :value="getLevelData(level).fleetStorage" />
|
||||
+
|
||||
<NumberWithTooltip :value="getLevelData(level).fleetStorage" />
|
||||
</span>
|
||||
<span v-else>-</span>
|
||||
</TableCell>
|
||||
@@ -87,7 +102,8 @@
|
||||
</TableCell>
|
||||
<TableCell v-if="type === 'building' && showSpaceColumn" class="text-center text-sm">
|
||||
<span v-if="getLevelData(level).spaceBonus > 0" class="text-green-600 dark:text-green-400">
|
||||
+<NumberWithTooltip :value="getLevelData(level).spaceBonus" />
|
||||
+
|
||||
<NumberWithTooltip :value="getLevelData(level).spaceBonus" />
|
||||
</span>
|
||||
<span v-else>-</span>
|
||||
</TableCell>
|
||||
@@ -95,8 +111,12 @@
|
||||
<span class="text-orange-600 dark:text-orange-400">+10</span>
|
||||
</TableCell>
|
||||
<TableCell v-if="type === 'building' && showBuildSpeedColumn" class="text-center text-sm">
|
||||
<span v-if="itemType === 'roboticsFactory'" class="text-cyan-600 dark:text-cyan-400">+{{ getLevelData(level).buildSpeedBonus * 100 }}%</span>
|
||||
<span v-else-if="itemType === 'naniteFactory'" class="text-cyan-600 dark:text-cyan-400">+{{ getLevelData(level).buildSpeedBonus * 100 }}%</span>
|
||||
<span v-if="itemType === 'roboticsFactory'" class="text-cyan-600 dark:text-cyan-400">
|
||||
+{{ getLevelData(level).buildSpeedBonus * 100 }}%
|
||||
</span>
|
||||
<span v-else-if="itemType === 'naniteFactory'" class="text-cyan-600 dark:text-cyan-400">
|
||||
+{{ getLevelData(level).buildSpeedBonus * 100 }}%
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell v-if="type === 'building' && showResearchSpeedColumn" class="text-center text-sm">
|
||||
<span class="text-indigo-600 dark:text-indigo-400">+{{ (getLevelData(level).researchSpeedBonus - 1) * 100 }}%</span>
|
||||
@@ -115,7 +135,10 @@
|
||||
<span class="text-purple-600 dark:text-purple-400">+{{ level }}</span>
|
||||
</TableCell>
|
||||
<TableCell v-if="type === 'technology' && showFleetStorageColumn" class="text-center text-sm">
|
||||
<span class="text-blue-600 dark:text-blue-400">+<NumberWithTooltip :value="level * 500" /></span>
|
||||
<span class="text-blue-600 dark:text-blue-400">
|
||||
+
|
||||
<NumberWithTooltip :value="level * 500" />
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell v-if="type === 'technology' && showResearchQueueColumn" class="text-center text-sm">
|
||||
<span class="text-purple-600 dark:text-purple-400">+1</span>
|
||||
@@ -124,7 +147,7 @@
|
||||
<span class="text-green-600 dark:text-green-400">+1</span>
|
||||
</TableCell>
|
||||
<TableCell v-if="type === 'technology' && showSpaceColumn" class="text-center text-sm">
|
||||
<span class="text-green-600 dark:text-green-400">+5 {{ t('research.forAllPlanets') }}</span>
|
||||
<span class="text-green-600 dark:text-green-400">+30 {{ t('research.forAllPlanets') }}</span>
|
||||
</TableCell>
|
||||
<TableCell v-if="type === 'technology' && showSpeedBonusColumn" class="text-center text-sm">
|
||||
<span class="text-yellow-600 dark:text-yellow-400">+{{ level * 10 }}%</span>
|
||||
@@ -152,15 +175,21 @@
|
||||
<CardContent class="space-y-2">
|
||||
<div class="flex items-center justify-between text-sm">
|
||||
<span class="text-muted-foreground">{{ t('resources.metal') }}:</span>
|
||||
<span class="font-medium"><NumberWithTooltip :value="totalStats.metal" /></span>
|
||||
<span class="font-medium">
|
||||
<NumberWithTooltip :value="totalStats.metal" />
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between text-sm">
|
||||
<span class="text-muted-foreground">{{ t('resources.crystal') }}:</span>
|
||||
<span class="font-medium"><NumberWithTooltip :value="totalStats.crystal" /></span>
|
||||
<span class="font-medium">
|
||||
<NumberWithTooltip :value="totalStats.crystal" />
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between text-sm">
|
||||
<span class="text-muted-foreground">{{ t('resources.deuterium') }}:</span>
|
||||
<span class="font-medium"><NumberWithTooltip :value="totalStats.deuterium" /></span>
|
||||
<span class="font-medium">
|
||||
<NumberWithTooltip :value="totalStats.deuterium" />
|
||||
</span>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -275,13 +304,22 @@
|
||||
<CardTitle class="text-sm">{{ t(`${typeKey}.buildCost`) }}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent class="space-y-2">
|
||||
<div v-for="resourceType in costResourceTypes" :key="resourceType.key" v-show="unitCost[resourceType.key] > 0" class="flex items-center justify-between text-sm">
|
||||
<div
|
||||
v-for="resourceType in costResourceTypes"
|
||||
:key="resourceType.key"
|
||||
v-show="unitCost[resourceType.key] > 0"
|
||||
class="flex items-center justify-between text-sm"
|
||||
>
|
||||
<span class="text-muted-foreground">{{ t(`resources.${resourceType.key}`) }}:</span>
|
||||
<span class="font-medium"><NumberWithTooltip :value="unitCost[resourceType.key]" /></span>
|
||||
<span class="font-medium">
|
||||
<NumberWithTooltip :value="unitCost[resourceType.key]" />
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between text-sm pt-2 border-t">
|
||||
<span class="text-muted-foreground">{{ t('player.points') }}:</span>
|
||||
<span class="font-bold text-primary"><NumberWithTooltip :value="pointsPerUnit" /></span>
|
||||
<span class="font-bold text-primary">
|
||||
<NumberWithTooltip :value="pointsPerUnit" />
|
||||
</span>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -311,9 +349,23 @@
|
||||
<div class="space-y-2">
|
||||
<p class="text-sm text-muted-foreground">{{ t(`${typeKey}.totalCost`) }}:</p>
|
||||
<div class="space-y-1 text-sm">
|
||||
<div v-for="resourceType in costResourceTypes" :key="resourceType.key" class="flex justify-between">
|
||||
<span>{{ t(`resources.${resourceType.key}`) }}:</span>
|
||||
<span class="font-medium"><NumberWithTooltip :value="batchCost[resourceType.key]" /></span>
|
||||
<div class="flex justify-between">
|
||||
<span>{{ t('resources.metal') }}:</span>
|
||||
<span class="font-medium">
|
||||
<NumberWithTooltip :value="batchCost.metal" />
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span>{{ t('resources.crystal') }}:</span>
|
||||
<span class="font-medium">
|
||||
<NumberWithTooltip :value="batchCost.crystal" />
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span>{{ t('resources.deuterium') }}:</span>
|
||||
<span class="font-medium">
|
||||
<NumberWithTooltip :value="batchCost.deuterium" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -434,7 +486,7 @@
|
||||
const showFleetStorageColumn = computed(() => {
|
||||
if (props.type === 'building') {
|
||||
const buildingType = props.itemType as BuildingType
|
||||
return buildingType === 'shipyard'
|
||||
return buildingType === 'shipyard' || buildingType === 'hangar'
|
||||
} else if (props.type === 'technology') {
|
||||
const techType = props.itemType as TechnologyType
|
||||
return techType === 'computerTechnology'
|
||||
@@ -626,43 +678,87 @@
|
||||
const storageBonus = 1 + (activeBonuses.value.storageCapacityBonus || 0) / 100
|
||||
const baseCapacity = 10000
|
||||
|
||||
if (buildingType === 'metalMine') {
|
||||
production = Math.floor(1500 * level * Math.pow(1.5, level) * resourceBonus)
|
||||
consumption = Math.floor(10 * level * Math.pow(1.1, level))
|
||||
} else if (buildingType === 'crystalMine') {
|
||||
production = Math.floor(1000 * level * Math.pow(1.5, level) * resourceBonus)
|
||||
consumption = Math.floor(10 * level * Math.pow(1.1, level))
|
||||
} else if (buildingType === 'deuteriumSynthesizer') {
|
||||
production = Math.floor(500 * level * Math.pow(1.5, level) * resourceBonus)
|
||||
consumption = Math.floor(10 * level * Math.pow(1.1, level))
|
||||
} else if (buildingType === 'solarPlant') {
|
||||
production = Math.floor(50 * level * Math.pow(1.1, level) * energyBonus)
|
||||
} else if (buildingType === 'metalStorage') {
|
||||
capacity = Math.floor(baseCapacity * Math.pow(2, level) * storageBonus)
|
||||
} else if (buildingType === 'crystalStorage') {
|
||||
capacity = Math.floor(baseCapacity * Math.pow(2, level) * storageBonus)
|
||||
} else if (buildingType === 'deuteriumTank') {
|
||||
capacity = Math.floor(baseCapacity * Math.pow(2, level) * storageBonus)
|
||||
} else if (buildingType === 'darkMatterCollector') {
|
||||
capacity = 1000 + level * 100
|
||||
production = Math.floor(25 * level * Math.pow(1.5, level))
|
||||
} else if (buildingType === 'darkMatterTank') {
|
||||
const darkMatterBaseCapacity = 1000
|
||||
capacity = Math.floor(darkMatterBaseCapacity * Math.pow(2, level) * storageBonus)
|
||||
} else if (buildingType === 'fusionReactor') {
|
||||
production = Math.floor(150 * level * Math.pow(1.15, level))
|
||||
} else if (buildingType === 'shipyard') {
|
||||
fleetStorage = 1000 * level
|
||||
} else if (buildingType === 'terraformer') {
|
||||
spaceBonus = 5
|
||||
} else if (buildingType === 'lunarBase') {
|
||||
spaceBonus = 5
|
||||
} else if (buildingType === 'roboticsFactory') {
|
||||
buildSpeedBonus = level
|
||||
} else if (buildingType === 'naniteFactory') {
|
||||
buildSpeedBonus = level * 2
|
||||
} else if (buildingType === 'researchLab') {
|
||||
researchSpeedBonus = level
|
||||
// Building calculation configuration
|
||||
const buildingCalculations: Record<
|
||||
string,
|
||||
(level: number) => Partial<{
|
||||
production: number
|
||||
consumption: number
|
||||
capacity: number
|
||||
fleetStorage: number
|
||||
spaceBonus: number
|
||||
buildSpeedBonus: number
|
||||
researchSpeedBonus: number
|
||||
}>
|
||||
> = {
|
||||
metalMine: lvl => ({
|
||||
production: Math.floor(1500 * lvl * Math.pow(1.5, lvl) * resourceBonus),
|
||||
consumption: Math.floor(10 * lvl * Math.pow(1.1, lvl))
|
||||
}),
|
||||
crystalMine: lvl => ({
|
||||
production: Math.floor(1000 * lvl * Math.pow(1.5, lvl) * resourceBonus),
|
||||
consumption: Math.floor(10 * lvl * Math.pow(1.1, lvl))
|
||||
}),
|
||||
deuteriumSynthesizer: lvl => ({
|
||||
production: Math.floor(500 * lvl * Math.pow(1.5, lvl) * resourceBonus),
|
||||
consumption: Math.floor(10 * lvl * Math.pow(1.1, lvl))
|
||||
}),
|
||||
solarPlant: lvl => ({
|
||||
production: Math.floor(50 * lvl * Math.pow(1.1, lvl) * energyBonus)
|
||||
}),
|
||||
metalStorage: lvl => ({
|
||||
capacity: Math.floor(baseCapacity * Math.pow(2, lvl) * storageBonus)
|
||||
}),
|
||||
crystalStorage: lvl => ({
|
||||
capacity: Math.floor(baseCapacity * Math.pow(2, lvl) * storageBonus)
|
||||
}),
|
||||
deuteriumTank: lvl => ({
|
||||
capacity: Math.floor(baseCapacity * Math.pow(2, lvl) * storageBonus)
|
||||
}),
|
||||
darkMatterCollector: lvl => ({
|
||||
capacity: 1000 + lvl * 100,
|
||||
production: Math.floor(25 * lvl * Math.pow(1.5, lvl))
|
||||
}),
|
||||
darkMatterTank: lvl => ({
|
||||
capacity: Math.floor(1000 * Math.pow(2, lvl) * storageBonus)
|
||||
}),
|
||||
fusionReactor: lvl => ({
|
||||
production: Math.floor(150 * lvl * Math.pow(1.15, lvl))
|
||||
}),
|
||||
shipyard: lvl => ({
|
||||
fleetStorage: 1000 * lvl
|
||||
}),
|
||||
hangar: lvl => ({
|
||||
fleetStorage: 500 * lvl
|
||||
}),
|
||||
terraformer: () => ({
|
||||
spaceBonus: 30
|
||||
}),
|
||||
lunarBase: () => ({
|
||||
spaceBonus: 30
|
||||
}),
|
||||
roboticsFactory: lvl => ({
|
||||
buildSpeedBonus: lvl
|
||||
}),
|
||||
naniteFactory: lvl => ({
|
||||
buildSpeedBonus: lvl * 2
|
||||
}),
|
||||
researchLab: lvl => ({
|
||||
researchSpeedBonus: lvl
|
||||
})
|
||||
}
|
||||
|
||||
// Apply calculations if configuration exists
|
||||
const calc = buildingCalculations[buildingType]
|
||||
if (calc) {
|
||||
const result = calc(level)
|
||||
production = result.production ?? production
|
||||
consumption = result.consumption ?? consumption
|
||||
capacity = result.capacity ?? capacity
|
||||
fleetStorage = result.fleetStorage ?? fleetStorage
|
||||
spaceBonus = result.spaceBonus ?? spaceBonus
|
||||
buildSpeedBonus = result.buildSpeedBonus ?? buildSpeedBonus
|
||||
researchSpeedBonus = result.researchSpeedBonus ?? researchSpeedBonus
|
||||
}
|
||||
|
||||
const points = pointsLogic.calculateBuildingPoints(buildingType, level - 1, level)
|
||||
@@ -685,7 +781,18 @@
|
||||
}
|
||||
|
||||
const points = pointsLogic.calculateTechnologyPoints(techType, level - 1, level)
|
||||
return { cost, time, production: 0, consumption: 0, points, capacity: 0, fleetStorage: 0, spaceBonus: 0, buildSpeedBonus: 0, researchSpeedBonus }
|
||||
return {
|
||||
cost,
|
||||
time,
|
||||
production: 0,
|
||||
consumption: 0,
|
||||
points,
|
||||
capacity: 0,
|
||||
fleetStorage: 0,
|
||||
spaceBonus: 0,
|
||||
buildSpeedBonus: 0,
|
||||
researchSpeedBonus
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,104 +1,146 @@
|
||||
<template>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div class="flex items-start justify-between">
|
||||
<div class="flex-1">
|
||||
<CardTitle class="flex items-center gap-2">
|
||||
{{ npc.name }}
|
||||
<Badge :variant="statusBadgeVariant">
|
||||
{{ statusText }}
|
||||
</Badge>
|
||||
</CardTitle>
|
||||
<CardDescription class="mt-1">
|
||||
{{ npc.planets.length }} {{ t('diplomacy.planets') }}
|
||||
<span v-if="npc.allies && npc.allies.length > 0" class="ml-2">· {{ npc.allies.length }} {{ t('diplomacy.allies') }}</span>
|
||||
</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent class="space-y-4">
|
||||
<!-- 好感度进度条 -->
|
||||
<div class="space-y-2">
|
||||
<div class="flex items-center justify-between text-sm">
|
||||
<span class="text-muted-foreground">{{ t('diplomacy.reputation') }}</span>
|
||||
<span class="font-semibold" :class="reputationColor">{{ reputation > 0 ? '+' : '' }}{{ reputation }}</span>
|
||||
</div>
|
||||
<div class="relative">
|
||||
<!-- 背景进度条 -->
|
||||
<div class="h-2 bg-muted rounded-full overflow-hidden">
|
||||
<!-- 负值部分(左侧,红色) -->
|
||||
<div
|
||||
v-if="reputation < 0"
|
||||
class="h-full bg-red-500 dark:bg-red-600 absolute right-1/2"
|
||||
:style="{ width: `${Math.abs(reputation) / 2}%` }"
|
||||
/>
|
||||
<!-- 正值部分(右侧,绿色) -->
|
||||
<div
|
||||
v-if="reputation > 0"
|
||||
class="h-full bg-green-500 dark:bg-green-600 absolute left-1/2"
|
||||
:style="{ width: `${reputation / 2}%` }"
|
||||
/>
|
||||
<div class="rounded-lg transition-shadow duration-300">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div class="flex items-start justify-between">
|
||||
<div class="flex-1">
|
||||
<CardTitle class="flex items-center gap-2">
|
||||
{{ npc.name }}
|
||||
<span v-if="npc.note" class="text-muted-foreground font-normal">({{ npc.note }})</span>
|
||||
<Badge :variant="statusBadgeVariant">
|
||||
{{ statusText }}
|
||||
</Badge>
|
||||
</CardTitle>
|
||||
<CardDescription class="mt-1">
|
||||
{{ npc.planets.length }} {{ t('diplomacy.planets') }}
|
||||
<span v-if="npc.allies && npc.allies.length > 0" class="ml-2">· {{ npc.allies.length }} {{ t('diplomacy.allies') }}</span>
|
||||
</CardDescription>
|
||||
</div>
|
||||
<!-- 中心线 -->
|
||||
<div class="absolute left-1/2 top-0 bottom-0 w-px bg-border" />
|
||||
<!-- 编辑备注按钮 -->
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
class="h-8 w-8 p-0"
|
||||
@click="openNoteDialog"
|
||||
:title="npc.note ? t('diplomacy.actions.editNote') : t('diplomacy.actions.addNote')"
|
||||
>
|
||||
<Pencil class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<div class="flex justify-between text-xs text-muted-foreground">
|
||||
<span>-100</span>
|
||||
<span>0</span>
|
||||
<span>+100</span>
|
||||
</CardHeader>
|
||||
<CardContent class="space-y-4">
|
||||
<!-- 好感度进度条 -->
|
||||
<div class="space-y-2">
|
||||
<div class="flex items-center justify-between text-sm">
|
||||
<span class="text-muted-foreground">{{ t('diplomacy.reputation') }}</span>
|
||||
<span class="font-semibold" :class="reputationColor">{{ reputation > 0 ? '+' : '' }}{{ reputation }}</span>
|
||||
</div>
|
||||
<div class="relative">
|
||||
<!-- 背景进度条 -->
|
||||
<div class="h-2 bg-muted rounded-full overflow-hidden">
|
||||
<!-- 负值部分(左侧,红色) -->
|
||||
<div
|
||||
v-if="reputation < 0"
|
||||
class="h-full bg-red-500 dark:bg-red-600 absolute right-1/2"
|
||||
:style="{ width: `${Math.abs(reputation) / 2}%` }"
|
||||
/>
|
||||
<!-- 正值部分(右侧,绿色) -->
|
||||
<div
|
||||
v-if="reputation > 0"
|
||||
class="h-full bg-green-500 dark:bg-green-600 absolute left-1/2"
|
||||
:style="{ width: `${reputation / 2}%` }"
|
||||
/>
|
||||
</div>
|
||||
<!-- 中心线 -->
|
||||
<div class="absolute left-1/2 top-0 bottom-0 w-px bg-border" />
|
||||
</div>
|
||||
<div class="flex justify-between text-xs text-muted-foreground">
|
||||
<span>-100</span>
|
||||
<span>0</span>
|
||||
<span>+100</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 盟友信息 -->
|
||||
<div v-if="npc.allies && npc.allies.length > 0" class="pt-2 border-t">
|
||||
<p class="text-sm text-muted-foreground mb-2">{{ t('diplomacy.alliedWith') }}:</p>
|
||||
<div class="flex flex-wrap gap-1">
|
||||
<Badge v-for="allyId in npc.allies.slice(0, 3)" :key="allyId" variant="outline" class="text-xs">
|
||||
{{ getAllyName(allyId) }}
|
||||
</Badge>
|
||||
<Badge v-if="npc.allies.length > 3" variant="outline" class="text-xs">
|
||||
+{{ npc.allies.length - 3 }} {{ t('diplomacy.more') }}
|
||||
</Badge>
|
||||
<!-- 盟友信息 -->
|
||||
<div v-if="npc.allies && npc.allies.length > 0" class="pt-2 border-t">
|
||||
<p class="text-sm text-muted-foreground mb-2">{{ t('diplomacy.alliedWith') }}:</p>
|
||||
<div class="flex flex-wrap gap-1">
|
||||
<Badge
|
||||
v-for="allyId in npc.allies.slice(0, 3)"
|
||||
:key="allyId"
|
||||
variant="outline"
|
||||
class="text-xs cursor-pointer hover:bg-accent transition-colors"
|
||||
:class="getAllyBorderClass(allyId)"
|
||||
@click="scrollToAlly(allyId)"
|
||||
>
|
||||
{{ getAllyName(allyId) }}
|
||||
</Badge>
|
||||
<Badge v-if="npc.allies.length > 3" variant="outline" class="text-xs">
|
||||
+{{ npc.allies.length - 3 }} {{ t('diplomacy.more') }}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="flex gap-2 pt-2">
|
||||
<Button size="sm" variant="outline" class="flex-1" @click="handleGiftResources">
|
||||
<Gift class="h-4 w-4 mr-2" />
|
||||
{{ t('diplomacy.actions.gift') }}
|
||||
</Button>
|
||||
<Button size="sm" variant="outline" class="flex-1" @click="handleViewPlanets">
|
||||
<Globe class="h-4 w-4 mr-2" />
|
||||
{{ t('diplomacy.actions.viewPlanets') }}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<!-- 最近活动 -->
|
||||
<div v-if="recentEvent" class="pt-2 border-t">
|
||||
<p class="text-xs text-muted-foreground mb-1">{{ t('diplomacy.lastEvent') }}:</p>
|
||||
<div class="flex items-center gap-2 text-xs">
|
||||
<component :is="getEventIcon(recentEvent.reason)" class="h-3 w-3" />
|
||||
<span>{{ getEventText(recentEvent.reason) }}</span>
|
||||
<span class="text-muted-foreground">{{ formatTime(Date.now() - recentEvent.timestamp) }} {{ t('diplomacy.ago') }}</span>
|
||||
<!-- 操作按钮 -->
|
||||
<div class="flex gap-2 pt-2">
|
||||
<Button size="sm" variant="outline" class="flex-1" @click="handleGiftResources">
|
||||
<Gift class="h-4 w-4 mr-2" />
|
||||
{{ t('diplomacy.actions.gift') }}
|
||||
</Button>
|
||||
<Button size="sm" variant="outline" class="flex-1" @click="handleViewPlanets">
|
||||
<Globe class="h-4 w-4 mr-2" />
|
||||
{{ t('diplomacy.actions.viewPlanets') }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<!-- 最近活动 -->
|
||||
<div v-if="recentEvent" class="pt-2 border-t">
|
||||
<p class="text-xs text-muted-foreground mb-1">{{ t('diplomacy.lastEvent') }}:</p>
|
||||
<div class="flex items-center gap-2 text-xs">
|
||||
<component :is="getEventIcon(recentEvent.reason)" class="h-3 w-3" />
|
||||
<span>{{ getEventText(recentEvent.reason) }}</span>
|
||||
<span class="text-muted-foreground">
|
||||
{{ formatRelativeTime((Date.now() - recentEvent.timestamp) / 1000, t) }}{{ t('diplomacy.ago') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<!-- 备注编辑对话框 -->
|
||||
<Dialog v-model:open="noteDialogOpen">
|
||||
<DialogContent class="sm:max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ npc.note ? t('diplomacy.actions.editNote') : t('diplomacy.actions.addNote') }}</DialogTitle>
|
||||
<DialogDescription class="sr-only">{{ t('diplomacy.note') }}</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div class="py-4">
|
||||
<Input v-model="noteInput" :placeholder="t('diplomacy.notePlaceholder')" @keyup.enter="saveNote" />
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" @click="noteDialogOpen = false">{{ t('common.cancel') }}</Button>
|
||||
<Button @click="saveNote">{{ t('common.save') }}</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useNPCStore } from '@/stores/npcStore'
|
||||
import { useGameStore } from '@/stores/gameStore'
|
||||
import { useI18n } from '@/composables/useI18n'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Gift, Globe, Sword, Eye, Trash2 } from 'lucide-vue-next'
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from '@/components/ui/dialog'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Gift, Globe, Sword, Eye, Trash2, Pencil } from 'lucide-vue-next'
|
||||
import { RelationStatus, DiplomaticEventType } from '@/types/game'
|
||||
import type { DiplomaticRelation, NPC } from '@/types/game'
|
||||
import { formatTime } from '@/utils/format'
|
||||
import { formatRelativeTime } from '@/utils/format'
|
||||
|
||||
const props = defineProps<{
|
||||
npc: NPC
|
||||
@@ -107,8 +149,28 @@
|
||||
|
||||
const router = useRouter()
|
||||
const npcStore = useNPCStore()
|
||||
const gameStore = useGameStore()
|
||||
const { t } = useI18n()
|
||||
|
||||
// 备注对话框状态
|
||||
const noteDialogOpen = ref(false)
|
||||
const noteInput = ref('')
|
||||
|
||||
// 打开备注对话框
|
||||
const openNoteDialog = () => {
|
||||
noteInput.value = props.npc.note || ''
|
||||
noteDialogOpen.value = true
|
||||
}
|
||||
|
||||
// 保存备注
|
||||
const saveNote = () => {
|
||||
const npc = npcStore.npcs.find(n => n.id === props.npc.id)
|
||||
if (npc) {
|
||||
npc.note = noteInput.value.trim() || undefined
|
||||
}
|
||||
noteDialogOpen.value = false
|
||||
}
|
||||
|
||||
// 好感度值
|
||||
const reputation = computed(() => props.relation?.reputation || 0)
|
||||
|
||||
@@ -155,7 +217,26 @@
|
||||
// 获取盟友名称
|
||||
const getAllyName = (allyId: string) => {
|
||||
const ally = npcStore.npcs.find(n => n.id === allyId)
|
||||
return ally?.name || allyId.substring(0, 8)
|
||||
if (!ally) return allyId.substring(0, 8)
|
||||
return ally.note ? `${ally.name}(${ally.note})` : ally.name
|
||||
}
|
||||
|
||||
// 获取盟友与玩家的外交关系状态对应的边框样式
|
||||
const getAllyBorderClass = (allyId: string) => {
|
||||
const ally = npcStore.npcs.find(n => n.id === allyId)
|
||||
if (!ally) return ''
|
||||
|
||||
const allyRelation = ally.relations?.[gameStore.player.id]
|
||||
if (!allyRelation) return '' // 无关系,使用默认边框
|
||||
|
||||
switch (allyRelation.status) {
|
||||
case RelationStatus.Friendly:
|
||||
return 'border-green-500 dark:border-green-400'
|
||||
case RelationStatus.Hostile:
|
||||
return 'border-red-500 dark:border-red-400'
|
||||
default:
|
||||
return '' // 中立,使用默认边框
|
||||
}
|
||||
}
|
||||
|
||||
// 获取事件图标
|
||||
@@ -229,4 +310,12 @@
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动到盟友卡片
|
||||
const scrollToAlly = (allyId: string) => {
|
||||
// 触发父组件的滚动事件
|
||||
// 通过emit通知父组件滚动到指定的NPC卡片
|
||||
const event = new CustomEvent('scrollToNpc', { detail: { npcId: allyId }, bubbles: true })
|
||||
document.dispatchEvent(event)
|
||||
}
|
||||
</script>
|
||||
|
||||
323
src/components/NpcRelationRow.vue
Normal file
323
src/components/NpcRelationRow.vue
Normal file
@@ -0,0 +1,323 @@
|
||||
<template>
|
||||
<div class="rounded-lg transition-shadow duration-300">
|
||||
<div class="p-3 rounded-lg border hover:bg-accent/50 transition-colors cursor-pointer" @click="toggleExpand">
|
||||
<!-- 桌面端:单行布局 -->
|
||||
<div class="hidden sm:flex items-center gap-3">
|
||||
<!-- 状态指示器 -->
|
||||
<div
|
||||
class="w-2 h-2 rounded-full flex-shrink-0"
|
||||
:class="{
|
||||
'bg-green-500': status === RelationStatus.Friendly,
|
||||
'bg-red-500': status === RelationStatus.Hostile,
|
||||
'bg-gray-400': status === RelationStatus.Neutral
|
||||
}"
|
||||
/>
|
||||
|
||||
<!-- 名称和备注 -->
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-medium truncate">{{ npc.name }}</span>
|
||||
<span v-if="npc.note" class="text-muted-foreground text-sm truncate">({{ npc.note }})</span>
|
||||
</div>
|
||||
<div class="text-xs text-muted-foreground">
|
||||
{{ npc.planets.length }} {{ t('diplomacy.planets') }}
|
||||
<span v-if="npc.allies && npc.allies.length > 0">· {{ npc.allies.length }} {{ t('diplomacy.allies') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 好感度 -->
|
||||
<div class="flex items-center gap-2 flex-shrink-0">
|
||||
<div class="w-16 h-1.5 bg-muted rounded-full overflow-hidden relative">
|
||||
<div v-if="reputation < 0" class="h-full bg-red-500 absolute right-1/2" :style="{ width: `${Math.abs(reputation) / 2}%` }" />
|
||||
<div v-if="reputation > 0" class="h-full bg-green-500 absolute left-1/2" :style="{ width: `${reputation / 2}%` }" />
|
||||
<div class="absolute left-1/2 top-0 bottom-0 w-px bg-border" />
|
||||
</div>
|
||||
<span class="text-sm font-medium w-10 text-right" :class="reputationColor">{{ reputation > 0 ? '+' : '' }}{{ reputation }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="flex items-center gap-1 flex-shrink-0">
|
||||
<Button variant="ghost" size="icon" class="h-8 w-8" @click.stop="handleGiftResources" :title="t('diplomacy.actions.gift')">
|
||||
<Gift class="h-4 w-4" />
|
||||
</Button>
|
||||
<Button variant="ghost" size="icon" class="h-8 w-8" @click.stop="handleViewPlanets" :title="t('diplomacy.actions.viewPlanets')">
|
||||
<Globe class="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class="h-8 w-8"
|
||||
@click.stop="openNoteDialog"
|
||||
:title="npc.note ? t('diplomacy.actions.editNote') : t('diplomacy.actions.addNote')"
|
||||
>
|
||||
<Pencil class="h-4 w-4" />
|
||||
</Button>
|
||||
<ChevronDown class="h-4 w-4 text-muted-foreground transition-transform" :class="{ 'rotate-180': isExpanded }" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 移动端:两行布局 -->
|
||||
<div class="sm:hidden space-y-2">
|
||||
<!-- 第一行:状态、名称、展开箭头 -->
|
||||
<div class="flex items-center gap-2">
|
||||
<div
|
||||
class="w-2 h-2 rounded-full flex-shrink-0"
|
||||
:class="{
|
||||
'bg-green-500': status === RelationStatus.Friendly,
|
||||
'bg-red-500': status === RelationStatus.Hostile,
|
||||
'bg-gray-400': status === RelationStatus.Neutral
|
||||
}"
|
||||
/>
|
||||
<div class="flex-1 min-w-0">
|
||||
<span class="font-medium truncate">{{ npc.name }}</span>
|
||||
<span v-if="npc.note" class="text-muted-foreground text-sm ml-1">({{ npc.note }})</span>
|
||||
</div>
|
||||
<ChevronDown class="h-4 w-4 text-muted-foreground transition-transform flex-shrink-0" :class="{ 'rotate-180': isExpanded }" />
|
||||
</div>
|
||||
|
||||
<!-- 第二行:星球数、好感度、操作按钮 -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="text-xs text-muted-foreground">
|
||||
{{ npc.planets.length }} {{ t('diplomacy.planets') }}
|
||||
<span v-if="npc.allies && npc.allies.length > 0">· {{ npc.allies.length }} {{ t('diplomacy.allies') }}</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1">
|
||||
<!-- 好感度数值 -->
|
||||
<span class="text-xs font-medium mr-1" :class="reputationColor">{{ reputation > 0 ? '+' : '' }}{{ reputation }}</span>
|
||||
<!-- 操作按钮 -->
|
||||
<Button variant="ghost" size="icon" class="h-7 w-7" @click.stop="handleGiftResources" :title="t('diplomacy.actions.gift')">
|
||||
<Gift class="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
<Button variant="ghost" size="icon" class="h-7 w-7" @click.stop="handleViewPlanets" :title="t('diplomacy.actions.viewPlanets')">
|
||||
<Globe class="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class="h-7 w-7"
|
||||
@click.stop="openNoteDialog"
|
||||
:title="npc.note ? t('diplomacy.actions.editNote') : t('diplomacy.actions.addNote')"
|
||||
>
|
||||
<Pencil class="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 展开详情 -->
|
||||
<div v-if="isExpanded" class="ml-5 pl-3 border-l-2 border-muted py-2 space-y-2">
|
||||
<!-- 盟友信息 -->
|
||||
<div v-if="npc.allies && npc.allies.length > 0" class="flex items-center gap-2 flex-wrap">
|
||||
<span class="text-xs text-muted-foreground">{{ t('diplomacy.alliedWith') }}:</span>
|
||||
<Badge
|
||||
v-for="allyId in npc.allies.slice(0, 5)"
|
||||
:key="allyId"
|
||||
variant="outline"
|
||||
class="text-xs cursor-pointer hover:bg-accent transition-colors"
|
||||
:class="getAllyBorderClass(allyId)"
|
||||
@click="scrollToAlly(allyId)"
|
||||
>
|
||||
{{ getAllyName(allyId) }}
|
||||
</Badge>
|
||||
<Badge v-if="npc.allies.length > 5" variant="outline" class="text-xs">+{{ npc.allies.length - 5 }} {{ t('diplomacy.more') }}</Badge>
|
||||
</div>
|
||||
|
||||
<!-- 最近活动 -->
|
||||
<div v-if="recentEvent" class="flex items-center gap-2 text-xs">
|
||||
<span class="text-muted-foreground">{{ t('diplomacy.lastEvent') }}:</span>
|
||||
<component :is="getEventIcon(recentEvent.reason)" class="h-3 w-3" />
|
||||
<span>{{ getEventText(recentEvent.reason) }}</span>
|
||||
<span class="text-muted-foreground">
|
||||
{{ formatRelativeTime((Date.now() - recentEvent.timestamp) / 1000, t) }}{{ t('diplomacy.ago') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 备注编辑对话框 -->
|
||||
<Dialog v-model:open="noteDialogOpen">
|
||||
<DialogContent class="sm:max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ npc.note ? t('diplomacy.actions.editNote') : t('diplomacy.actions.addNote') }}</DialogTitle>
|
||||
<DialogDescription class="sr-only">{{ t('diplomacy.note') }}</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div class="py-4">
|
||||
<Input v-model="noteInput" :placeholder="t('diplomacy.notePlaceholder')" @keyup.enter="saveNote" />
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" @click="noteDialogOpen = false">{{ t('common.cancel') }}</Button>
|
||||
<Button @click="saveNote">{{ t('common.save') }}</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useNPCStore } from '@/stores/npcStore'
|
||||
import { useGameStore } from '@/stores/gameStore'
|
||||
import { useI18n } from '@/composables/useI18n'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Gift, Globe, Pencil, ChevronDown, Sword, Eye, Trash2 } from 'lucide-vue-next'
|
||||
import { RelationStatus, DiplomaticEventType } from '@/types/game'
|
||||
import type { DiplomaticRelation, NPC } from '@/types/game'
|
||||
import { formatRelativeTime } from '@/utils/format'
|
||||
|
||||
const props = defineProps<{
|
||||
npc: NPC
|
||||
relation?: DiplomaticRelation
|
||||
}>()
|
||||
|
||||
const router = useRouter()
|
||||
const npcStore = useNPCStore()
|
||||
const gameStore = useGameStore()
|
||||
const { t } = useI18n()
|
||||
|
||||
// 展开状态
|
||||
const isExpanded = ref(false)
|
||||
const toggleExpand = () => {
|
||||
isExpanded.value = !isExpanded.value
|
||||
}
|
||||
|
||||
// 备注对话框状态
|
||||
const noteDialogOpen = ref(false)
|
||||
const noteInput = ref('')
|
||||
|
||||
const openNoteDialog = () => {
|
||||
noteInput.value = props.npc.note || ''
|
||||
noteDialogOpen.value = true
|
||||
}
|
||||
|
||||
const saveNote = () => {
|
||||
const npc = npcStore.npcs.find(n => n.id === props.npc.id)
|
||||
if (npc) {
|
||||
npc.note = noteInput.value.trim() || undefined
|
||||
}
|
||||
noteDialogOpen.value = false
|
||||
}
|
||||
|
||||
// 好感度值
|
||||
const reputation = computed(() => props.relation?.reputation || 0)
|
||||
|
||||
// 关系状态
|
||||
const status = computed(() => props.relation?.status || RelationStatus.Neutral)
|
||||
|
||||
// 好感度颜色
|
||||
const reputationColor = computed(() => {
|
||||
if (reputation.value >= 20) return 'text-green-600 dark:text-green-400'
|
||||
if (reputation.value <= -20) return 'text-red-600 dark:text-red-400'
|
||||
return 'text-muted-foreground'
|
||||
})
|
||||
|
||||
// 最近的外交事件
|
||||
const recentEvent = computed(() => {
|
||||
if (!props.relation?.history || props.relation.history.length === 0) return null
|
||||
return props.relation.history[props.relation.history.length - 1]
|
||||
})
|
||||
|
||||
// 获取盟友名称
|
||||
const getAllyName = (allyId: string) => {
|
||||
const ally = npcStore.npcs.find(n => n.id === allyId)
|
||||
if (!ally) return allyId.substring(0, 8)
|
||||
return ally.note ? `${ally.name}(${ally.note})` : ally.name
|
||||
}
|
||||
|
||||
// 获取盟友边框样式
|
||||
const getAllyBorderClass = (allyId: string) => {
|
||||
const ally = npcStore.npcs.find(n => n.id === allyId)
|
||||
if (!ally) return ''
|
||||
|
||||
const allyRelation = ally.relations?.[gameStore.player.id]
|
||||
if (!allyRelation) return ''
|
||||
|
||||
switch (allyRelation.status) {
|
||||
case RelationStatus.Friendly:
|
||||
return 'border-green-500 dark:border-green-400'
|
||||
case RelationStatus.Hostile:
|
||||
return 'border-red-500 dark:border-red-400'
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
// 获取事件图标
|
||||
const getEventIcon = (eventType: string) => {
|
||||
switch (eventType) {
|
||||
case DiplomaticEventType.GiftResources:
|
||||
return Gift
|
||||
case DiplomaticEventType.Attack:
|
||||
case DiplomaticEventType.AllyAttacked:
|
||||
return Sword
|
||||
case DiplomaticEventType.Spy:
|
||||
return Eye
|
||||
case DiplomaticEventType.StealDebris:
|
||||
return Trash2
|
||||
default:
|
||||
return Gift
|
||||
}
|
||||
}
|
||||
|
||||
// 获取事件文本
|
||||
const getEventText = (eventType: string) => {
|
||||
switch (eventType) {
|
||||
case DiplomaticEventType.GiftResources:
|
||||
return t('diplomacy.events.gift')
|
||||
case DiplomaticEventType.Attack:
|
||||
return t('diplomacy.events.attack')
|
||||
case DiplomaticEventType.AllyAttacked:
|
||||
return t('diplomacy.events.allyAttacked')
|
||||
case DiplomaticEventType.Spy:
|
||||
return t('diplomacy.events.spy')
|
||||
case DiplomaticEventType.StealDebris:
|
||||
return t('diplomacy.events.stealDebris')
|
||||
default:
|
||||
return eventType
|
||||
}
|
||||
}
|
||||
|
||||
// 赠送资源
|
||||
const handleGiftResources = () => {
|
||||
if (props.npc.planets.length > 0) {
|
||||
const targetPlanet = props.npc.planets[0]
|
||||
if (!targetPlanet) return
|
||||
|
||||
router.push({
|
||||
path: '/fleet',
|
||||
query: {
|
||||
galaxy: targetPlanet.position.galaxy,
|
||||
system: targetPlanet.position.system,
|
||||
position: targetPlanet.position.position,
|
||||
gift: '1'
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 查看星球
|
||||
const handleViewPlanets = () => {
|
||||
if (props.npc.planets.length > 0) {
|
||||
const targetPlanet = props.npc.planets[0]
|
||||
if (!targetPlanet) return
|
||||
|
||||
router.push({
|
||||
path: '/galaxy',
|
||||
query: {
|
||||
galaxy: targetPlanet.position.galaxy,
|
||||
system: targetPlanet.position.system,
|
||||
highlightNpc: props.npc.id
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动到盟友卡片
|
||||
const scrollToAlly = (allyId: string) => {
|
||||
const event = new CustomEvent('scrollToNpc', { detail: { npcId: allyId }, bubbles: true })
|
||||
document.dispatchEvent(event)
|
||||
}
|
||||
</script>
|
||||
90
src/components/PrivacyDialog.vue
Normal file
90
src/components/PrivacyDialog.vue
Normal file
@@ -0,0 +1,90 @@
|
||||
<template>
|
||||
<Dialog v-model:open="open">
|
||||
<DialogContent class="max-w-2xl max-h-[80vh] overflow-hidden flex flex-col">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ t('privacy.title') }}</DialogTitle>
|
||||
<DialogDescription class="sr-only">{{ t('privacy.title') }}</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div class="flex-1 overflow-y-auto pr-2 space-y-4 text-sm">
|
||||
<!-- 简介 -->
|
||||
<section>
|
||||
<h3 class="font-semibold mb-1">{{ t('privacy.sections.introduction.title') }}</h3>
|
||||
<p class="text-muted-foreground">{{ t('privacy.sections.introduction.content') }}</p>
|
||||
</section>
|
||||
|
||||
<!-- 数据收集 -->
|
||||
<section>
|
||||
<h3 class="font-semibold mb-1">{{ t('privacy.sections.dataCollection.title') }}</h3>
|
||||
<p class="text-muted-foreground mb-1">{{ t('privacy.sections.dataCollection.content') }}</p>
|
||||
<ul class="list-disc list-inside text-muted-foreground ml-2 space-y-0.5">
|
||||
<li>{{ t('privacy.sections.dataCollection.items.gameProgress') }}</li>
|
||||
<li>{{ t('privacy.sections.dataCollection.items.settings') }}</li>
|
||||
<li>{{ t('privacy.sections.dataCollection.items.language') }}</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<!-- 数据存储 -->
|
||||
<section>
|
||||
<h3 class="font-semibold mb-1">{{ t('privacy.sections.dataStorage.title') }}</h3>
|
||||
<p class="text-muted-foreground">{{ t('privacy.sections.dataStorage.content') }}</p>
|
||||
</section>
|
||||
|
||||
<!-- 无服务器通信 -->
|
||||
<section>
|
||||
<h3 class="font-semibold mb-1">{{ t('privacy.sections.noServer.title') }}</h3>
|
||||
<p class="text-muted-foreground">{{ t('privacy.sections.noServer.content') }}</p>
|
||||
</section>
|
||||
|
||||
<!-- 第三方服务 -->
|
||||
<section>
|
||||
<h3 class="font-semibold mb-1">{{ t('privacy.sections.thirdParty.title') }}</h3>
|
||||
<p class="text-muted-foreground">{{ t('privacy.sections.thirdParty.content') }}</p>
|
||||
</section>
|
||||
|
||||
<!-- 数据控制 -->
|
||||
<section>
|
||||
<h3 class="font-semibold mb-1">{{ t('privacy.sections.dataControl.title') }}</h3>
|
||||
<p class="text-muted-foreground mb-1">{{ t('privacy.sections.dataControl.content') }}</p>
|
||||
<ul class="list-disc list-inside text-muted-foreground ml-2 space-y-0.5">
|
||||
<li>{{ t('privacy.sections.dataControl.items.export') }}</li>
|
||||
<li>{{ t('privacy.sections.dataControl.items.import') }}</li>
|
||||
<li>{{ t('privacy.sections.dataControl.items.delete') }}</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<!-- 联系我们 -->
|
||||
<section>
|
||||
<h3 class="font-semibold mb-1">{{ t('privacy.sections.contact.title') }}</h3>
|
||||
<p class="text-muted-foreground">
|
||||
{{ t('privacy.sections.contact.content') }}
|
||||
<a
|
||||
:href="`https://github.com/${pkg.author.name}/${pkg.name}/issues`"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="text-primary hover:underline"
|
||||
>
|
||||
GitHub Issues
|
||||
</a>
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
<DialogFooter class="mt-4">
|
||||
<Button variant="outline" @click="open = false">
|
||||
{{ t('common.close') }}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from '@/composables/useI18n'
|
||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import pkg from '../../package.json'
|
||||
|
||||
// 双向绑定 open 状态
|
||||
const open = defineModel<boolean>('open', { default: false })
|
||||
|
||||
const { t } = useI18n()
|
||||
</script>
|
||||
200
src/components/QueueNotifications.vue
Normal file
200
src/components/QueueNotifications.vue
Normal file
@@ -0,0 +1,200 @@
|
||||
<template>
|
||||
<Popover v-model:open="isOpen">
|
||||
<PopoverTrigger as-child>
|
||||
<Button data-tutorial="queue-button" variant="outline" size="icon" class="relative">
|
||||
<ListOrdered class="h-4 w-4" />
|
||||
<Badge
|
||||
v-if="totalQueueCount > 0"
|
||||
variant="default"
|
||||
class="absolute -top-1 -right-1 h-5 w-5 p-0 flex items-center justify-center text-xs"
|
||||
>
|
||||
{{ totalQueueCount }}
|
||||
</Badge>
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-96 p-0" align="end">
|
||||
<div class="flex items-center justify-between p-4 border-b">
|
||||
<h3 class="font-semibold">{{ t('queue.title') }} ({{ totalQueueCount }})</h3>
|
||||
</div>
|
||||
|
||||
<Tabs v-model="activeTab" class="w-full">
|
||||
<TabsList class="w-full grid grid-cols-5 h-9 rounded-none border-b bg-transparent">
|
||||
<TabsTrigger v-for="tab in tabConfig" :key="tab.value" :value="tab.value" class="text-xs px-1 data-[state=active]:bg-muted">
|
||||
{{ t(`queue.tabs.${tab.value}`) }}
|
||||
<Badge v-if="tab.items.length > 0" variant="secondary" class="ml-1 h-4 px-1 text-[10px]">
|
||||
{{ tab.items.length }}
|
||||
</Badge>
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<ScrollArea class="h-[420px]">
|
||||
<TabsContent v-for="tab in tabConfig" :key="tab.value" :value="tab.value" class="mt-0">
|
||||
<Empty v-if="tab.items.length === 0" class="border-0">
|
||||
<EmptyContent>
|
||||
<Inbox class="h-10 w-10 text-muted-foreground" />
|
||||
<EmptyDescription>{{ t('queue.empty') }}</EmptyDescription>
|
||||
</EmptyContent>
|
||||
</Empty>
|
||||
<div v-else class="divide-y p-4 space-y-3">
|
||||
<div v-for="item in tab.items" :key="item.id" class="space-y-1.5">
|
||||
<div class="flex items-center justify-between text-xs sm:text-sm gap-2">
|
||||
<div class="flex items-center gap-1.5 sm:gap-2 min-w-0 flex-1">
|
||||
<div class="h-2 w-2 rounded-full animate-pulse flex-shrink-0" :class="getStatusDotClass(item)" />
|
||||
<span class="font-medium truncate">{{ getItemName(item) }}</span>
|
||||
<span class="text-muted-foreground text-[10px] sm:text-xs">
|
||||
{{
|
||||
item.type === 'ship' || item.type === 'defense'
|
||||
? `→ ${t('queue.quantity')} ${item.quantity}`
|
||||
: item.type === 'demolish'
|
||||
? `→ ${t('queue.demolishing')}`
|
||||
: `→ ${t('queue.level')} ${item.targetLevel}`
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 sm:gap-3 flex-shrink-0">
|
||||
<span class="text-muted-foreground text-[10px] sm:text-xs whitespace-nowrap">
|
||||
{{ formatTime(getRemainingTime(item)) }}
|
||||
</span>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
class="h-5 sm:h-6 px-1.5 sm:px-2 text-[10px] sm:text-xs"
|
||||
@click.stop="handleCancel(item)"
|
||||
>
|
||||
{{ t('queue.cancel') }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<Progress :model-value="getQueueProgress(item)" class="h-1.5" />
|
||||
</div>
|
||||
</div>
|
||||
</TabsContent>
|
||||
</ScrollArea>
|
||||
</Tabs>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, onUnmounted, watch } from 'vue'
|
||||
import { ListOrdered, Inbox } from 'lucide-vue-next'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
|
||||
import { ScrollArea } from '@/components/ui/scroll-area'
|
||||
import { Progress } from '@/components/ui/progress'
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||
import { Empty, EmptyContent, EmptyDescription } from '@/components/ui/empty'
|
||||
import { useGameStore } from '@/stores/gameStore'
|
||||
import { useGameConfig } from '@/composables/useGameConfig'
|
||||
import { useI18n } from '@/composables/useI18n'
|
||||
import { formatTime } from '@/utils/format'
|
||||
import type { BuildQueueItem, BuildingType, ShipType, DefenseType, TechnologyType } from '@/types/game'
|
||||
|
||||
const { t } = useI18n()
|
||||
const gameStore = useGameStore()
|
||||
const { BUILDINGS, SHIPS, DEFENSES, TECHNOLOGIES } = useGameConfig()
|
||||
|
||||
const isOpen = ref(false)
|
||||
const activeTab = ref('all')
|
||||
|
||||
// 响应式时间戳,用于驱动时间和进度的动态更新
|
||||
const currentTime = ref(Date.now())
|
||||
let timerInterval: ReturnType<typeof setInterval> | null = null
|
||||
|
||||
// 当弹窗打开时启动计时器,关闭时停止
|
||||
watch(isOpen, open => {
|
||||
if (open) {
|
||||
// 启动每秒更新的计时器
|
||||
timerInterval = setInterval(() => {
|
||||
currentTime.value = Date.now()
|
||||
}, 1000)
|
||||
} else {
|
||||
// 停止计时器
|
||||
if (timerInterval) {
|
||||
clearInterval(timerInterval)
|
||||
timerInterval = null
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 组件卸载时清理计时器
|
||||
onUnmounted(() => {
|
||||
if (timerInterval) {
|
||||
clearInterval(timerInterval)
|
||||
timerInterval = null
|
||||
}
|
||||
})
|
||||
|
||||
// 获取当前星球的建造队列
|
||||
const buildQueue = computed(() => {
|
||||
return gameStore.currentPlanet?.buildQueue || []
|
||||
})
|
||||
|
||||
// 获取研究队列
|
||||
const researchQueue = computed(() => {
|
||||
return gameStore.player.researchQueue || []
|
||||
})
|
||||
|
||||
// 总队列数量
|
||||
const totalQueueCount = computed(() => {
|
||||
return buildQueue.value.length + researchQueue.value.length
|
||||
})
|
||||
|
||||
// 标签页配置(用于循环渲染)
|
||||
const tabConfig = computed(() => [
|
||||
{ value: 'all', items: [...buildQueue.value, ...researchQueue.value] },
|
||||
{ value: 'buildings', items: buildQueue.value.filter(item => item.type === 'building' || item.type === 'demolish') },
|
||||
{ value: 'research', items: researchQueue.value },
|
||||
{ value: 'ships', items: buildQueue.value.filter(item => item.type === 'ship') },
|
||||
{ value: 'defense', items: buildQueue.value.filter(item => item.type === 'defense') }
|
||||
])
|
||||
|
||||
// 获取队列项名称
|
||||
const getItemName = (item: BuildQueueItem): string => {
|
||||
if (item.type === 'building' || item.type === 'demolish') {
|
||||
return BUILDINGS.value[item.itemType as BuildingType].name
|
||||
} else if (item.type === 'ship') {
|
||||
return SHIPS.value[item.itemType as ShipType].name
|
||||
} else if (item.type === 'defense') {
|
||||
return DEFENSES.value[item.itemType as DefenseType].name
|
||||
} else if (item.type === 'technology') {
|
||||
return TECHNOLOGIES.value[item.itemType as TechnologyType].name
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
// 获取剩余时间(使用响应式 currentTime 确保动态更新)
|
||||
const getRemainingTime = (item: BuildQueueItem): number => {
|
||||
return Math.max(0, Math.floor((item.endTime - currentTime.value) / 1000))
|
||||
}
|
||||
|
||||
// 获取队列进度(使用响应式 currentTime 确保动态更新)
|
||||
const getQueueProgress = (item: BuildQueueItem): number => {
|
||||
const elapsed = currentTime.value - item.startTime
|
||||
const total = item.endTime - item.startTime
|
||||
return Math.min(100, (elapsed / total) * 100)
|
||||
}
|
||||
|
||||
// 统一的取消处理
|
||||
const handleCancel = (item: BuildQueueItem) => {
|
||||
let eventName: string
|
||||
if (item.type === 'building' || item.type === 'ship' || item.type === 'defense' || item.type === 'demolish') {
|
||||
eventName = 'cancel-build'
|
||||
} else if (item.type === 'technology') {
|
||||
eventName = 'cancel-research'
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
const event = new CustomEvent(eventName, { detail: item.id })
|
||||
window.dispatchEvent(event)
|
||||
}
|
||||
|
||||
// 获取状态指示点颜色
|
||||
const getStatusDotClass = (item: BuildQueueItem): string => {
|
||||
if (item.type === 'demolish') return 'bg-destructive'
|
||||
if (item.type === 'technology') return 'bg-blue-500'
|
||||
return 'bg-green-500'
|
||||
}
|
||||
</script>
|
||||
120
src/components/UpdateDialog.vue
Normal file
120
src/components/UpdateDialog.vue
Normal file
@@ -0,0 +1,120 @@
|
||||
<template>
|
||||
<Dialog :open="open" @update:open="$emit('update:open', $event)">
|
||||
<DialogScrollContent class="max-w-2xl max-h-[80vh] flex flex-col">
|
||||
<DialogHeader class="flex-shrink-0">
|
||||
<DialogTitle>{{ t('settings.newVersionAvailable', { version: versionInfo?.version || '' }) }}</DialogTitle>
|
||||
<DialogDescription>{{ t('settings.updateAvailable') }}</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div class="flex-1 overflow-y-auto min-h-0 mt-4 pr-2">
|
||||
<div class="prose prose-sm dark:prose-invert max-w-none" v-html="renderedMarkdown" />
|
||||
</div>
|
||||
|
||||
<DialogFooter class="flex gap-2 flex-shrink-0 mt-4">
|
||||
<Button variant="outline" @click="$emit('update:open', false)">
|
||||
{{ t('common.cancel') }}
|
||||
</Button>
|
||||
<Button @click="handleDownload">
|
||||
<Download class="mr-2 h-4 w-4" />
|
||||
{{ t('settings.download') }}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogScrollContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { marked } from 'marked'
|
||||
import { useI18n } from '@/composables/useI18n'
|
||||
import { Dialog, DialogScrollContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Download } from 'lucide-vue-next'
|
||||
import type { VersionInfo } from '@/utils/versionCheck'
|
||||
|
||||
const props = defineProps<{
|
||||
open: boolean
|
||||
versionInfo: VersionInfo | null
|
||||
}>()
|
||||
|
||||
defineEmits<{
|
||||
'update:open': [value: boolean]
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const renderedMarkdown = computed(() => {
|
||||
if (!props.versionInfo?.releaseNotes) return ''
|
||||
return marked(props.versionInfo.releaseNotes)
|
||||
})
|
||||
|
||||
const handleDownload = () => {
|
||||
if (props.versionInfo?.downloadUrl) {
|
||||
window.open(props.versionInfo.downloadUrl, '_blank')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.prose) {
|
||||
color: hsl(var(--foreground));
|
||||
}
|
||||
|
||||
:deep(.prose h1) {
|
||||
font-size: 1.5em;
|
||||
font-weight: 700;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
:deep(.prose h2) {
|
||||
font-size: 1.25em;
|
||||
font-weight: 600;
|
||||
margin-top: 0.8em;
|
||||
margin-bottom: 0.4em;
|
||||
}
|
||||
|
||||
:deep(.prose h3) {
|
||||
font-size: 1.1em;
|
||||
font-weight: 600;
|
||||
margin-top: 0.6em;
|
||||
margin-bottom: 0.3em;
|
||||
}
|
||||
|
||||
:deep(.prose p) {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
:deep(.prose ul) {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
padding-left: 1.5em;
|
||||
}
|
||||
|
||||
:deep(.prose li) {
|
||||
margin-top: 0.25em;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
|
||||
:deep(.prose code) {
|
||||
background: hsl(var(--muted));
|
||||
padding: 0.2em 0.4em;
|
||||
border-radius: 0.25rem;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
:deep(.prose pre) {
|
||||
background: hsl(var(--muted));
|
||||
padding: 1em;
|
||||
border-radius: 0.5rem;
|
||||
overflow-x: auto;
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
:deep(.prose a) {
|
||||
color: hsl(var(--primary));
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
159
src/components/ui/bg-stars/StarsBackground.vue
Normal file
159
src/components/ui/bg-stars/StarsBackground.vue
Normal file
@@ -0,0 +1,159 @@
|
||||
<template>
|
||||
<div
|
||||
:class="cn('relative size-full overflow-hidden bg-[radial-gradient(ellipse_at_bottom,_#262626_0%,_#000_100%)]', props.class)"
|
||||
@mousemove="handleMouseMove"
|
||||
>
|
||||
<motion.div :style="{ x: springX, y: springY }">
|
||||
<!-- Star Layer 1 -->
|
||||
<motion.div class="absolute top-0 left-0 w-full h-[2000px]" :animate="{ y: [0, -2000] }" :transition="starLayer1Transition">
|
||||
<div
|
||||
class="absolute bg-transparent rounded-full"
|
||||
:style="{
|
||||
width: '1px',
|
||||
height: '1px',
|
||||
boxShadow: boxShadow1
|
||||
}"
|
||||
/>
|
||||
<div
|
||||
class="absolute bg-transparent rounded-full top-[2000px]"
|
||||
:style="{
|
||||
width: '1px',
|
||||
height: '1px',
|
||||
boxShadow: boxShadow1
|
||||
}"
|
||||
/>
|
||||
</motion.div>
|
||||
|
||||
<!-- Star Layer 2 -->
|
||||
<motion.div class="absolute top-0 left-0 w-full h-[2000px]" :animate="{ y: [0, -2000] }" :transition="starLayer2Transition">
|
||||
<div
|
||||
class="absolute bg-transparent rounded-full"
|
||||
:style="{
|
||||
width: '2px',
|
||||
height: '2px',
|
||||
boxShadow: boxShadow2
|
||||
}"
|
||||
/>
|
||||
<div
|
||||
class="absolute bg-transparent rounded-full top-[2000px]"
|
||||
:style="{
|
||||
width: '2px',
|
||||
height: '2px',
|
||||
boxShadow: boxShadow2
|
||||
}"
|
||||
/>
|
||||
</motion.div>
|
||||
|
||||
<!-- Star Layer 3 -->
|
||||
<motion.div class="absolute top-0 left-0 w-full h-[2000px]" :animate="{ y: [0, -2000] }" :transition="starLayer3Transition">
|
||||
<div
|
||||
class="absolute bg-transparent rounded-full"
|
||||
:style="{
|
||||
width: '3px',
|
||||
height: '3px',
|
||||
boxShadow: boxShadow3
|
||||
}"
|
||||
/>
|
||||
<div
|
||||
class="absolute bg-transparent rounded-full top-[2000px]"
|
||||
:style="{
|
||||
width: '3px',
|
||||
height: '3px',
|
||||
boxShadow: boxShadow3
|
||||
}"
|
||||
/>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
<!-- Slot for child content -->
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { SpringOptions, Transition } from 'motion-v'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { motion, useMotionValue, useSpring } from 'motion-v'
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
|
||||
interface StarsBackgroundProps {
|
||||
factor?: number
|
||||
speed?: number
|
||||
transition?: SpringOptions
|
||||
starColor?: string
|
||||
class?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<StarsBackgroundProps>(), {
|
||||
factor: 0.05,
|
||||
speed: 50,
|
||||
transition: () => ({ stiffness: 50, damping: 20 }),
|
||||
starColor: '#fff'
|
||||
})
|
||||
|
||||
// For slot content
|
||||
defineSlots()
|
||||
|
||||
function generateStars(count: number, starColor: string) {
|
||||
const shadows: string[] = []
|
||||
for (let i = 0; i < count; i++) {
|
||||
const x = Math.floor(Math.random() * 4000) - 2000
|
||||
const y = Math.floor(Math.random() * 4000) - 2000
|
||||
shadows.push(`${x}px ${y}px ${starColor}`)
|
||||
}
|
||||
return shadows.join(', ')
|
||||
}
|
||||
|
||||
const offsetX = useMotionValue(1)
|
||||
const offsetY = useMotionValue(1)
|
||||
|
||||
const springX = useSpring(offsetX, props.transition)
|
||||
const springY = useSpring(offsetY, props.transition)
|
||||
|
||||
function handleMouseMove(e: MouseEvent) {
|
||||
const centerX = window.innerWidth / 2
|
||||
const centerY = window.innerHeight / 2
|
||||
const newOffsetX = -(e.clientX - centerX) * props.factor
|
||||
const newOffsetY = -(e.clientY - centerY) * props.factor
|
||||
offsetX.set(newOffsetX)
|
||||
offsetY.set(newOffsetY)
|
||||
}
|
||||
|
||||
const boxShadow1 = ref('')
|
||||
const boxShadow2 = ref('')
|
||||
const boxShadow3 = ref('')
|
||||
|
||||
onMounted(() => {
|
||||
boxShadow1.value = generateStars(1000, props.starColor)
|
||||
boxShadow2.value = generateStars(400, props.starColor)
|
||||
boxShadow3.value = generateStars(200, props.starColor)
|
||||
})
|
||||
|
||||
// Watch for starColor changes
|
||||
watch(
|
||||
() => props.starColor,
|
||||
newColor => {
|
||||
boxShadow1.value = generateStars(1000, newColor)
|
||||
boxShadow2.value = generateStars(400, newColor)
|
||||
boxShadow3.value = generateStars(200, newColor)
|
||||
}
|
||||
)
|
||||
|
||||
const starLayer1Transition = computed<Transition>(() => ({
|
||||
repeat: Infinity,
|
||||
duration: props.speed,
|
||||
ease: 'linear' as const
|
||||
}))
|
||||
|
||||
const starLayer2Transition = computed<Transition>(() => ({
|
||||
repeat: Infinity,
|
||||
duration: props.speed * 2,
|
||||
ease: 'linear' as const
|
||||
}))
|
||||
|
||||
const starLayer3Transition = computed<Transition>(() => ({
|
||||
repeat: Infinity,
|
||||
duration: props.speed * 3,
|
||||
ease: 'linear' as const
|
||||
}))
|
||||
</script>
|
||||
1
src/components/ui/bg-stars/index.ts
Normal file
1
src/components/ui/bg-stars/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default as StarsBackground } from './StarsBackground.vue'
|
||||
@@ -6,7 +6,7 @@
|
||||
v-bind="{ ...$attrs, ...forwarded }"
|
||||
:class="
|
||||
cn(
|
||||
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg',
|
||||
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-[60] grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-2xl',
|
||||
props.class
|
||||
)
|
||||
"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
v-bind="delegatedProps"
|
||||
:class="
|
||||
cn(
|
||||
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80',
|
||||
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-[60] bg-black/80',
|
||||
props.class
|
||||
)
|
||||
"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
v-bind="{ ...$attrs, ...forwarded }"
|
||||
:class="
|
||||
cn(
|
||||
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 w-[calc(100vw-3rem)] translate-x-[-50%] translate-y-[-50%] rounded-lg border shadow-lg duration-200 sm:w-auto flex flex-col p-0',
|
||||
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-[60] w-[calc(100vw-3rem)] translate-x-[-50%] translate-y-[-50%] rounded-lg border shadow-lg duration-200 sm:w-auto sm:min-w-[764px] flex flex-col p-0',
|
||||
containerClass
|
||||
)
|
||||
"
|
||||
@@ -17,7 +17,7 @@
|
||||
</div>
|
||||
|
||||
<!-- 可滚动的内容区域 -->
|
||||
<div class="overflow-y-auto px-4 py-3 sm:px-6 sm:py-4">
|
||||
<div class="overflow-y-auto px-4 py-3 sm:px-6 sm:py-4 max-h-[60vh]">
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
|
||||
22
src/components/ui/empty/Empty.vue
Normal file
22
src/components/ui/empty/Empty.vue
Normal file
@@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<div
|
||||
data-slot="empty"
|
||||
:class="
|
||||
cn(
|
||||
'flex min-w-0 flex-1 flex-col items-center justify-center gap-6 text-balance rounded-lg border-dashed p-6 text-center md:p-12',
|
||||
props.class
|
||||
)
|
||||
"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes['class']
|
||||
}>()
|
||||
</script>
|
||||
14
src/components/ui/empty/EmptyContent.vue
Normal file
14
src/components/ui/empty/EmptyContent.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<template>
|
||||
<div data-slot="empty-content" :class="cn('flex w-full min-w-0 max-w-sm flex-col items-center gap-4 text-balance text-sm', props.class)">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes['class']
|
||||
}>()
|
||||
</script>
|
||||
19
src/components/ui/empty/EmptyDescription.vue
Normal file
19
src/components/ui/empty/EmptyDescription.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<p
|
||||
data-slot="empty-description"
|
||||
:class="
|
||||
cn('text-muted-foreground [&>a:hover]:text-primary text-sm/relaxed [&>a]:underline [&>a]:underline-offset-4', $attrs.class ?? '')
|
||||
"
|
||||
>
|
||||
<slot />
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
defineProps<{
|
||||
class?: HTMLAttributes['class']
|
||||
}>()
|
||||
</script>
|
||||
14
src/components/ui/empty/EmptyHeader.vue
Normal file
14
src/components/ui/empty/EmptyHeader.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<template>
|
||||
<div data-slot="empty-header" :class="cn('flex max-w-sm flex-col items-center gap-2 text-center', props.class)">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes['class']
|
||||
}>()
|
||||
</script>
|
||||
17
src/components/ui/empty/EmptyMedia.vue
Normal file
17
src/components/ui/empty/EmptyMedia.vue
Normal file
@@ -0,0 +1,17 @@
|
||||
<template>
|
||||
<div data-slot="empty-icon" :data-variant="variant" :class="cn(emptyMediaVariants({ variant }), props.class)">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import type { EmptyMediaVariants } from '.'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { emptyMediaVariants } from '.'
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes['class']
|
||||
variant?: EmptyMediaVariants['variant']
|
||||
}>()
|
||||
</script>
|
||||
14
src/components/ui/empty/EmptyTitle.vue
Normal file
14
src/components/ui/empty/EmptyTitle.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<template>
|
||||
<div data-slot="empty-title" :class="cn('text-lg font-medium tracking-tight', props.class)">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes['class']
|
||||
}>()
|
||||
</script>
|
||||
23
src/components/ui/empty/index.ts
Normal file
23
src/components/ui/empty/index.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import type { VariantProps } from 'class-variance-authority'
|
||||
import { cva } from 'class-variance-authority'
|
||||
|
||||
export { default as Empty } from './Empty.vue'
|
||||
export { default as EmptyContent } from './EmptyContent.vue'
|
||||
export { default as EmptyDescription } from './EmptyDescription.vue'
|
||||
export { default as EmptyHeader } from './EmptyHeader.vue'
|
||||
export { default as EmptyMedia } from './EmptyMedia.vue'
|
||||
export { default as EmptyTitle } from './EmptyTitle.vue'
|
||||
|
||||
export const emptyMediaVariants = cva('mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0', {
|
||||
variants: {
|
||||
variant: {
|
||||
default: 'bg-transparent',
|
||||
icon: "bg-muted text-foreground flex size-10 shrink-0 items-center justify-center rounded-lg [&_svg:not([class*='size-'])]:size-6"
|
||||
}
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default'
|
||||
}
|
||||
})
|
||||
|
||||
export type EmptyMediaVariants = VariantProps<typeof emptyMediaVariants>
|
||||
91
src/components/ui/pagination/FixedPagination.vue
Normal file
91
src/components/ui/pagination/FixedPagination.vue
Normal file
@@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<div v-if="totalPages > 1" class="fixed bottom-4 left-1/2 -translate-x-1/2 z-40">
|
||||
<div class="flex items-center gap-2">
|
||||
<!-- 上一页按钮 - 圆形胶囊 -->
|
||||
<button
|
||||
v-if="currentPage > 1"
|
||||
@click="emit('update:page', currentPage - 1)"
|
||||
class="h-10 w-10 rounded-full bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60 border shadow-lg flex items-center justify-center hover:bg-accent transition-colors"
|
||||
>
|
||||
<ChevronLeft class="h-5 w-5" />
|
||||
</button>
|
||||
|
||||
<!-- 页码 - 椭圆形胶囊 -->
|
||||
<div
|
||||
class="bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60 border rounded-full py-2 px-3 shadow-lg flex items-center gap-1"
|
||||
>
|
||||
<button
|
||||
v-for="pageNum in pageNumbers"
|
||||
:key="pageNum"
|
||||
@click="emit('update:page', pageNum)"
|
||||
class="h-8 min-w-8 px-2 rounded-full text-sm font-medium transition-colors"
|
||||
:class="pageNum === currentPage ? 'bg-primary text-primary-foreground' : 'hover:bg-accent'"
|
||||
>
|
||||
{{ pageNum }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 下一页按钮 - 圆形胶囊 -->
|
||||
<button
|
||||
v-if="currentPage < totalPages"
|
||||
@click="emit('update:page', currentPage + 1)"
|
||||
class="h-10 w-10 rounded-full bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60 border shadow-lg flex items-center justify-center hover:bg-accent transition-colors"
|
||||
>
|
||||
<ChevronRight class="h-5 w-5" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { ChevronLeft, ChevronRight } from 'lucide-vue-next'
|
||||
|
||||
interface Props {
|
||||
page: number
|
||||
totalPages: number
|
||||
maxVisible?: number
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
maxVisible: 3
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:page': [page: number]
|
||||
}>()
|
||||
|
||||
const currentPage = computed(() => props.page)
|
||||
|
||||
// 生成页码列表 - 最多显示指定数量页码,不含省略号
|
||||
const pageNumbers = computed(() => {
|
||||
const pages: number[] = []
|
||||
const { totalPages, maxVisible } = props
|
||||
const current = currentPage.value
|
||||
|
||||
if (totalPages <= maxVisible) {
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
pages.push(i)
|
||||
}
|
||||
} else {
|
||||
let start = current - Math.floor(maxVisible / 2)
|
||||
let end = current + Math.floor(maxVisible / 2)
|
||||
|
||||
// 边界调整
|
||||
if (start < 1) {
|
||||
start = 1
|
||||
end = maxVisible
|
||||
}
|
||||
if (end > totalPages) {
|
||||
end = totalPages
|
||||
start = totalPages - maxVisible + 1
|
||||
}
|
||||
|
||||
for (let i = start; i <= end; i++) {
|
||||
pages.push(i)
|
||||
}
|
||||
}
|
||||
|
||||
return pages
|
||||
})
|
||||
</script>
|
||||
@@ -6,3 +6,4 @@ export { default as PaginationItem } from './PaginationItem.vue'
|
||||
export { default as PaginationLast } from './PaginationLast.vue'
|
||||
export { default as PaginationNext } from './PaginationNext.vue'
|
||||
export { default as PaginationPrevious } from './PaginationPrevious.vue'
|
||||
export { default as FixedPagination } from './FixedPagination.vue'
|
||||
|
||||
238
src/components/ui/particles-bg/ParticlesBg.vue
Normal file
238
src/components/ui/particles-bg/ParticlesBg.vue
Normal file
@@ -0,0 +1,238 @@
|
||||
<template>
|
||||
<div ref="canvasContainerRef" :class="$props.class" aria-hidden="true">
|
||||
<canvas ref="canvasRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useMouse, useDevicePixelRatio } from '@vueuse/core'
|
||||
import { ref, onMounted, onBeforeUnmount, watch, computed, reactive } from 'vue'
|
||||
|
||||
type Circle = {
|
||||
x: number
|
||||
y: number
|
||||
translateX: number
|
||||
translateY: number
|
||||
size: number
|
||||
alpha: number
|
||||
targetAlpha: number
|
||||
dx: number
|
||||
dy: number
|
||||
magnetism: number
|
||||
}
|
||||
|
||||
type Props = {
|
||||
color?: string
|
||||
quantity?: number
|
||||
staticity?: number
|
||||
ease?: number
|
||||
class?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
color: '#FFF',
|
||||
quantity: 100,
|
||||
staticity: 50,
|
||||
ease: 50,
|
||||
class: ''
|
||||
})
|
||||
|
||||
const canvasRef = ref<HTMLCanvasElement | null>(null)
|
||||
const canvasContainerRef = ref<HTMLDivElement | null>(null)
|
||||
const context = ref<CanvasRenderingContext2D | null>(null)
|
||||
const circles = ref<Circle[]>([])
|
||||
const mouse = reactive<{ x: number; y: number }>({ x: 0, y: 0 })
|
||||
const canvasSize = reactive<{ w: number; h: number }>({ w: 0, h: 0 })
|
||||
const { x: mouseX, y: mouseY } = useMouse()
|
||||
const { pixelRatio } = useDevicePixelRatio()
|
||||
|
||||
const color = computed(() => {
|
||||
// Remove the leading '#' if it's present
|
||||
let hex = props.color.replace(/^#/, '')
|
||||
|
||||
// If the hex code is 3 characters, expand it to 6 characters
|
||||
if (hex.length === 3) {
|
||||
hex = hex
|
||||
.split('')
|
||||
.map(char => char + char)
|
||||
.join('')
|
||||
}
|
||||
|
||||
// Parse the r, g, b values from the hex string
|
||||
const bigint = parseInt(hex, 16)
|
||||
const r = (bigint >> 16) & 255 // Extract the red component
|
||||
const g = (bigint >> 8) & 255 // Extract the green component
|
||||
const b = bigint & 255 // Extract the blue component
|
||||
|
||||
// Return the RGB values as a string separated by spaces
|
||||
return `${r} ${g} ${b}`
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
if (canvasRef.value) {
|
||||
context.value = canvasRef.value.getContext('2d')
|
||||
}
|
||||
|
||||
initCanvas()
|
||||
animate()
|
||||
window.addEventListener('resize', initCanvas)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('resize', initCanvas)
|
||||
})
|
||||
|
||||
watch([mouseX, mouseY], () => {
|
||||
onMouseMove()
|
||||
})
|
||||
|
||||
function initCanvas() {
|
||||
resizeCanvas()
|
||||
drawParticles()
|
||||
}
|
||||
|
||||
function onMouseMove() {
|
||||
if (canvasRef.value) {
|
||||
const rect = canvasRef.value.getBoundingClientRect()
|
||||
const { w, h } = canvasSize
|
||||
const x = mouseX.value - rect.left - w / 2
|
||||
const y = mouseY.value - rect.top - h / 2
|
||||
|
||||
const inside = x < w / 2 && x > -w / 2 && y < h / 2 && y > -h / 2
|
||||
if (inside) {
|
||||
mouse.x = x
|
||||
mouse.y = y
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resizeCanvas() {
|
||||
if (canvasContainerRef.value && canvasRef.value && context.value) {
|
||||
circles.value.length = 0
|
||||
canvasSize.w = canvasContainerRef.value.offsetWidth
|
||||
canvasSize.h = canvasContainerRef.value.offsetHeight
|
||||
canvasRef.value.width = canvasSize.w * pixelRatio.value
|
||||
canvasRef.value.height = canvasSize.h * pixelRatio.value
|
||||
canvasRef.value.style.width = canvasSize.w + 'px'
|
||||
canvasRef.value.style.height = canvasSize.h + 'px'
|
||||
context.value.scale(pixelRatio.value, pixelRatio.value)
|
||||
}
|
||||
}
|
||||
|
||||
function circleParams(): Circle {
|
||||
const x = Math.floor(Math.random() * canvasSize.w)
|
||||
const y = Math.floor(Math.random() * canvasSize.h)
|
||||
const translateX = 0
|
||||
const translateY = 0
|
||||
const size = Math.floor(Math.random() * 2) + 1
|
||||
const alpha = 0
|
||||
const targetAlpha = parseFloat((Math.random() * 0.6 + 0.1).toFixed(1))
|
||||
const dx = (Math.random() - 0.5) * 0.2
|
||||
const dy = (Math.random() - 0.5) * 0.2
|
||||
const magnetism = 0.1 + Math.random() * 4
|
||||
return {
|
||||
x,
|
||||
y,
|
||||
translateX,
|
||||
translateY,
|
||||
size,
|
||||
alpha,
|
||||
targetAlpha,
|
||||
dx,
|
||||
dy,
|
||||
magnetism
|
||||
}
|
||||
}
|
||||
|
||||
function drawCircle(circle: Circle, update = false) {
|
||||
if (context.value) {
|
||||
const { x, y, translateX, translateY, size, alpha } = circle
|
||||
context.value.translate(translateX, translateY)
|
||||
context.value.beginPath()
|
||||
context.value.arc(x, y, size, 0, 2 * Math.PI)
|
||||
context.value.fillStyle = `rgba(${color.value.split(' ').join(', ')}, ${alpha})`
|
||||
context.value.fill()
|
||||
context.value.setTransform(pixelRatio.value, 0, 0, pixelRatio.value, 0, 0)
|
||||
|
||||
if (!update) {
|
||||
circles.value.push(circle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clearContext() {
|
||||
if (context.value) {
|
||||
context.value.clearRect(0, 0, canvasSize.w, canvasSize.h)
|
||||
}
|
||||
}
|
||||
|
||||
function drawParticles() {
|
||||
clearContext()
|
||||
const particleCount = props.quantity
|
||||
for (let i = 0; i < particleCount; i++) {
|
||||
const circle = circleParams()
|
||||
drawCircle(circle)
|
||||
}
|
||||
}
|
||||
|
||||
function remapValue(value: number, start1: number, end1: number, start2: number, end2: number): number {
|
||||
const remapped = ((value - start1) * (end2 - start2)) / (end1 - start1) + start2
|
||||
return remapped > 0 ? remapped : 0
|
||||
}
|
||||
|
||||
function animate() {
|
||||
clearContext()
|
||||
circles.value.forEach((circle, i) => {
|
||||
// Handle the alpha value
|
||||
const edge = [
|
||||
circle.x + circle.translateX - circle.size, // distance from left edge
|
||||
canvasSize.w - circle.x - circle.translateX - circle.size, // distance from right edge
|
||||
circle.y + circle.translateY - circle.size, // distance from top edge
|
||||
canvasSize.h - circle.y - circle.translateY - circle.size // distance from bottom edge
|
||||
]
|
||||
|
||||
const closestEdge = edge.reduce((a, b) => Math.min(a, b))
|
||||
const remapClosestEdge = parseFloat(remapValue(closestEdge, 0, 20, 0, 1).toFixed(2))
|
||||
|
||||
if (remapClosestEdge > 1) {
|
||||
circle.alpha += 0.02
|
||||
if (circle.alpha > circle.targetAlpha) circle.alpha = circle.targetAlpha
|
||||
} else {
|
||||
circle.alpha = circle.targetAlpha * remapClosestEdge
|
||||
}
|
||||
|
||||
circle.x += circle.dx
|
||||
circle.y += circle.dy
|
||||
circle.translateX += (mouse.x / (props.staticity / circle.magnetism) - circle.translateX) / props.ease
|
||||
circle.translateY += (mouse.y / (props.staticity / circle.magnetism) - circle.translateY) / props.ease
|
||||
|
||||
// circle gets out of the canvas
|
||||
if (
|
||||
circle.x < -circle.size ||
|
||||
circle.x > canvasSize.w + circle.size ||
|
||||
circle.y < -circle.size ||
|
||||
circle.y > canvasSize.h + circle.size
|
||||
) {
|
||||
// remove the circle from the array
|
||||
circles.value.splice(i, 1)
|
||||
// create a new circle
|
||||
const newCircle = circleParams()
|
||||
drawCircle(newCircle)
|
||||
// update the circle position
|
||||
} else {
|
||||
drawCircle(
|
||||
{
|
||||
...circle,
|
||||
x: circle.x,
|
||||
y: circle.y,
|
||||
translateX: circle.translateX,
|
||||
translateY: circle.translateY,
|
||||
alpha: circle.alpha
|
||||
},
|
||||
true
|
||||
)
|
||||
}
|
||||
})
|
||||
window.requestAnimationFrame(animate)
|
||||
}
|
||||
</script>
|
||||
1
src/components/ui/particles-bg/index.ts
Normal file
1
src/components/ui/particles-bg/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default as ParticlesBg } from './ParticlesBg.vue'
|
||||
25
src/components/ui/scroll-area/ScrollArea.vue
Normal file
25
src/components/ui/scroll-area/ScrollArea.vue
Normal file
@@ -0,0 +1,25 @@
|
||||
<template>
|
||||
<ScrollAreaRoot data-slot="scroll-area" v-bind="delegatedProps" :class="cn('relative', props.class)">
|
||||
<ScrollAreaViewport
|
||||
data-slot="scroll-area-viewport"
|
||||
class="focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1"
|
||||
>
|
||||
<slot />
|
||||
</ScrollAreaViewport>
|
||||
<ScrollBar />
|
||||
<ScrollAreaCorner />
|
||||
</ScrollAreaRoot>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { ScrollAreaRootProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { ScrollAreaCorner, ScrollAreaRoot, ScrollAreaViewport } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
import ScrollBar from './ScrollBar.vue'
|
||||
|
||||
const props = defineProps<ScrollAreaRootProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
</script>
|
||||
30
src/components/ui/scroll-area/ScrollBar.vue
Normal file
30
src/components/ui/scroll-area/ScrollBar.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<ScrollAreaScrollbar
|
||||
data-slot="scroll-area-scrollbar"
|
||||
v-bind="delegatedProps"
|
||||
:class="
|
||||
cn(
|
||||
'flex touch-none p-px transition-colors select-none',
|
||||
orientation === 'vertical' && 'h-full w-2.5 border-l border-l-transparent',
|
||||
orientation === 'horizontal' && 'h-2.5 flex-col border-t border-t-transparent',
|
||||
props.class
|
||||
)
|
||||
"
|
||||
>
|
||||
<ScrollAreaThumb data-slot="scroll-area-thumb" class="bg-border relative flex-1 rounded-full" />
|
||||
</ScrollAreaScrollbar>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { ScrollAreaScrollbarProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { ScrollAreaScrollbar, ScrollAreaThumb } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = withDefaults(defineProps<ScrollAreaScrollbarProps & { class?: HTMLAttributes['class'] }>(), {
|
||||
orientation: 'vertical'
|
||||
})
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
</script>
|
||||
2
src/components/ui/scroll-area/index.ts
Normal file
2
src/components/ui/scroll-area/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export { default as ScrollArea } from './ScrollArea.vue'
|
||||
export { default as ScrollBar } from './ScrollBar.vue'
|
||||
@@ -1,20 +1,3 @@
|
||||
<script setup lang="ts">
|
||||
import type { SeparatorProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { Separator } from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = withDefaults(defineProps<
|
||||
SeparatorProps & { class?: HTMLAttributes["class"] }
|
||||
>(), {
|
||||
orientation: "horizontal",
|
||||
decorative: true,
|
||||
})
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Separator
|
||||
data-slot="separator"
|
||||
@@ -22,8 +5,23 @@ const delegatedProps = reactiveOmit(props, "class")
|
||||
:class="
|
||||
cn(
|
||||
'bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px',
|
||||
props.class,
|
||||
props.class
|
||||
)
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { SeparatorProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { Separator } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = withDefaults(defineProps<SeparatorProps & { class?: HTMLAttributes['class'] }>(), {
|
||||
orientation: 'horizontal',
|
||||
decorative: true
|
||||
})
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
</script>
|
||||
|
||||
@@ -1 +1 @@
|
||||
export { default as Separator } from "./Separator.vue"
|
||||
export { default as Separator } from './Separator.vue'
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import type { DialogRootEmits, DialogRootProps } from "reka-ui"
|
||||
import { DialogRoot, useForwardPropsEmits } from "reka-ui"
|
||||
|
||||
const props = defineProps<DialogRootProps>()
|
||||
const emits = defineEmits<DialogRootEmits>()
|
||||
|
||||
const forwarded = useForwardPropsEmits(props, emits)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DialogRoot
|
||||
v-slot="slotProps"
|
||||
data-slot="sheet"
|
||||
v-bind="forwarded"
|
||||
>
|
||||
<DialogRoot v-slot="slotProps" data-slot="sheet" v-bind="forwarded">
|
||||
<slot v-bind="slotProps" />
|
||||
</DialogRoot>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { DialogRootEmits, DialogRootProps } from 'reka-ui'
|
||||
import { DialogRoot, useForwardPropsEmits } from 'reka-ui'
|
||||
|
||||
const props = defineProps<DialogRootProps>()
|
||||
const emits = defineEmits<DialogRootEmits>()
|
||||
|
||||
const forwarded = useForwardPropsEmits(props, emits)
|
||||
</script>
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import type { DialogCloseProps } from "reka-ui"
|
||||
import { DialogClose } from "reka-ui"
|
||||
|
||||
const props = defineProps<DialogCloseProps>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DialogClose
|
||||
data-slot="sheet-close"
|
||||
v-bind="props"
|
||||
>
|
||||
<DialogClose data-slot="sheet-close" v-bind="props">
|
||||
<slot />
|
||||
</DialogClose>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { DialogCloseProps } from 'reka-ui'
|
||||
import { DialogClose } from 'reka-ui'
|
||||
|
||||
const props = defineProps<DialogCloseProps>()
|
||||
</script>
|
||||
|
||||
@@ -1,52 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import type { DialogContentEmits, DialogContentProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { X } from "lucide-vue-next"
|
||||
import {
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogPortal,
|
||||
useForwardPropsEmits,
|
||||
} from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
import SheetOverlay from "./SheetOverlay.vue"
|
||||
|
||||
interface SheetContentProps extends DialogContentProps {
|
||||
class?: HTMLAttributes["class"]
|
||||
side?: "top" | "right" | "bottom" | "left"
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
})
|
||||
|
||||
const props = withDefaults(defineProps<SheetContentProps>(), {
|
||||
side: "right",
|
||||
})
|
||||
const emits = defineEmits<DialogContentEmits>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class", "side")
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DialogPortal>
|
||||
<SheetOverlay />
|
||||
<DialogContent
|
||||
data-slot="sheet-content"
|
||||
:class="cn(
|
||||
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500',
|
||||
side === 'right'
|
||||
&& 'data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm',
|
||||
side === 'left'
|
||||
&& 'data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm',
|
||||
side === 'top'
|
||||
&& 'data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b',
|
||||
side === 'bottom'
|
||||
&& 'data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t',
|
||||
props.class)"
|
||||
:class="
|
||||
cn(
|
||||
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500',
|
||||
side === 'right' &&
|
||||
'data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm',
|
||||
side === 'left' &&
|
||||
'data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm',
|
||||
side === 'top' && 'data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b',
|
||||
side === 'bottom' &&
|
||||
'data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t',
|
||||
props.class
|
||||
)
|
||||
"
|
||||
v-bind="{ ...$attrs, ...forwarded }"
|
||||
>
|
||||
<slot />
|
||||
@@ -60,3 +29,31 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
</DialogContent>
|
||||
</DialogPortal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { DialogContentEmits, DialogContentProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { X } from 'lucide-vue-next'
|
||||
import { DialogClose, DialogContent, DialogPortal, useForwardPropsEmits } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
import SheetOverlay from './SheetOverlay.vue'
|
||||
|
||||
interface SheetContentProps extends DialogContentProps {
|
||||
class?: HTMLAttributes['class']
|
||||
side?: 'top' | 'right' | 'bottom' | 'left'
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false
|
||||
})
|
||||
|
||||
const props = withDefaults(defineProps<SheetContentProps>(), {
|
||||
side: 'right'
|
||||
})
|
||||
const emits = defineEmits<DialogContentEmits>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class', 'side')
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
</script>
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
import type { DialogDescriptionProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { DialogDescription } from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<DialogDescriptionProps & { class?: HTMLAttributes["class"] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DialogDescription
|
||||
data-slot="sheet-description"
|
||||
:class="cn('text-muted-foreground text-sm', props.class)"
|
||||
v-bind="delegatedProps"
|
||||
>
|
||||
<DialogDescription data-slot="sheet-description" :class="cn('text-muted-foreground text-sm', props.class)" v-bind="delegatedProps">
|
||||
<slot />
|
||||
</DialogDescription>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { DialogDescriptionProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { DialogDescription } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<DialogDescriptionProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
</script>
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{ class?: HTMLAttributes["class"] }>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
data-slot="sheet-footer"
|
||||
:class="cn('mt-auto flex flex-col gap-2 p-4', props.class)
|
||||
"
|
||||
>
|
||||
<div data-slot="sheet-footer" :class="cn('mt-auto flex flex-col gap-2 p-4', props.class)">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<{ class?: HTMLAttributes['class'] }>()
|
||||
</script>
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{ class?: HTMLAttributes["class"] }>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
data-slot="sheet-header"
|
||||
:class="cn('flex flex-col gap-1.5 p-4', props.class)"
|
||||
>
|
||||
<div data-slot="sheet-header" :class="cn('flex flex-col gap-1.5 p-4', props.class)">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<{ class?: HTMLAttributes['class'] }>()
|
||||
</script>
|
||||
|
||||
@@ -1,21 +1,26 @@
|
||||
<script setup lang="ts">
|
||||
import type { DialogOverlayProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { DialogOverlay } from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<DialogOverlayProps & { class?: HTMLAttributes["class"] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DialogOverlay
|
||||
data-slot="sheet-overlay"
|
||||
:class="cn('data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80', props.class)"
|
||||
:class="
|
||||
cn(
|
||||
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80',
|
||||
props.class
|
||||
)
|
||||
"
|
||||
v-bind="delegatedProps"
|
||||
>
|
||||
<slot />
|
||||
</DialogOverlay>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { DialogOverlayProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { DialogOverlay } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<DialogOverlayProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
</script>
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
import type { DialogTitleProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { DialogTitle } from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<DialogTitleProps & { class?: HTMLAttributes["class"] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DialogTitle
|
||||
data-slot="sheet-title"
|
||||
:class="cn('text-foreground font-semibold', props.class)"
|
||||
v-bind="delegatedProps"
|
||||
>
|
||||
<DialogTitle data-slot="sheet-title" :class="cn('text-foreground font-semibold', props.class)" v-bind="delegatedProps">
|
||||
<slot />
|
||||
</DialogTitle>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { DialogTitleProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { DialogTitle } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<DialogTitleProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
</script>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user