21 Commits
Author SHA1 Message Date
orrisroot 8d98ba78f4 refactor(xoonips): move item-type directory directly under module root
Relocate item-type configurations, components, and icons from
components/item-type/ to a top-level item-type/ folder directly
under the xoonips module root.

- Generalize ItemUtil by dynamically fetching configurations.
- Move generic item-type base components to components/lib/item-type.
- Move site-wide images and icons to assets/ folder.
- Relocate item-type specific icons into each type's subdirectory.
- Implement dynamic compile-time eager loading using Vite's glob import
  with a centralized configuration file.
2026-06-11 20:45:30 +09:00
orrisroot 0c526d8670 build(tsconfig): remove deprecated baseUrl and ignoreDeprecations
Remove the deprecated baseUrl option to prevent TypeScript 7.0 errors,
and update path mappings to be relative. This allows us to remove the
ignoreDeprecations flag, resolving IDE and tooling compatibility
issues.
2026-06-11 19:17:20 +09:00
orrisroot fd4178cbc1 fix(xoonips): remove lib segment from json resource paths
Correct the fetch URLs for tree.json and simpf-links.json by removing
the lib subdirectory prefix to match their actual location.
2026-06-11 19:07:45 +09:00
orrisroot 72b1b58419 refactor(react-hooks): remove synchronous setState inside useEffect
Avoid triggering synchronous state updates inside useEffect by
refactoring to useMemo and state synchronization during render.
This resolves multiple eslint-disable-next-line instances of
react-hooks/set-state-in-effect.
2026-06-11 18:50:04 +09:00
orrisroot daff8d4e35 feat(nimgsearch): make resource and xoonips paths dynamic
Refactor NimgsearchUtil to a class accepting path and xoonipsPath in
the constructor. Pass these props down from Page and routes to
NimgsearchPage to dynamically construct brain image, brainarea config,
and help video URLs.

Also include VS Code configuration settings, tasks, and cleanup plan
files.
2026-06-11 18:39:29 +09:00
orrisroot af4545445c refactor: use absolute path props for module components
Pass absolute paths starting with '/' as the path prop to nimgdocs block
components. Adjust components and utilities to not prepend a redundant
slash when forming resource URLs or route links.
2026-06-11 18:13:30 +09:00
orrisroot c9d174b97e refactor(react): prefix react hooks, event handlers, and nodes
Prefix React hooks (useState, useEffect, useCallback, useMemo) under
src/ with React. (e.g. React.useState). Standardize event handlers
and event type definitions to use React.ChangeEventHandler,
React.MouseEventHandler, React.SubmitEventHandler, React.ChangeEvent,
and React.MouseEvent. Convert ReactNode usages to React.ReactNode.
2026-06-11 17:51:31 +09:00
orrisroot 9d7235daab refactor(xoonips): support dynamic base path and instantiate utilities
Convert IndexUtil and ItemUtil from global singletons to instances
keyed by the mounting path, enabling co-existence of multiple Xoonips
instances on different base paths.

Use ky instead of fetch for fetching JSON metadata, constructing
resource URLs dynamically relative to the instance's base path.

Pass the dynamic path prop through App, Page layout, Xoonips routes,
and all downstream item-type, search, and block components.

Add layout and page names to cspell.json to prevent spelling errors.
2026-06-11 17:22:10 +09:00
orrisroot 805d62769e refactor(nimgdocs): rename to PascalCase and relocate blocks
Move BulletinBoard, HowToUseLinks, and HowToUseVideo blocks from
src/layout/blocks into the nimgdocs module for better colocation. Rename
Nimgdocs to NimgDocs throughout (pages, routes, module registration). Add
NimgDocsIndexPage and NimgDocsUtils, remove legacy NimgdocsPage. Update
routes to use relative navigation and pass path prop to components.
2026-06-09 21:04:04 +09:00
orrisroot a395db1348 refactor: update page structures across modules
- Update credits, nimgdocs, and nimgsearch page components
 - Adjust xoonips pages for xnpnimgcenter integration
 - Refactor App and PageNotFound components
2026-06-04 17:38:45 +09:00
orrisroot 727c734b7a refactor: rename nimgcenter module to xnpnimgcenter
- Move nimgcenter module to xnpnimgcenter directory
 - Add BrainConvHowToUse and UtilitiesIndex components
 - Update module configuration and brainexplorer routes
2026-06-04 17:38:39 +09:00
orrisroot 4ff4ccbf9e chore: update config, dependencies, and formatting
- Add language setting and new dictionary words to cspell.json
 - Reformat index.html structure
 - Update package dependencies
2026-06-04 17:38:26 +09:00
orrisroot d29c9a7589 fix: resolve typescript build errors and runtime warnings
- Fix pageLinks array type from ReactElement to ReactNode in
  NimgsearchPage and XoonipsListItem
- Fix initialize() return type signature in IndexTree
- Remove unused React import in item-type index
- Add initPromise deduplication to IndexUtil and ItemUtil to
  prevent duplicate data on re-mount
- Add missing pagination images from reference project
2026-06-03 21:06:11 +09:00
orrisroot 7ea9276296 refactor(types,imports): move types to variable side and use @/ imports
Move type annotations from arrow function parameters to variable
declarations. Replace 'any' return types with explicit types.
Replace relative imports of 'common/' and 'config/' with '@/'
absolute paths in modules/ and layout/ directories.
2026-06-03 20:51:17 +09:00
orrisroot 6d8a3d5d55 refactor(credits): remove hardcoded paths and use props-based configuration
Introduce CreditsUtilsConfig for configurable URL patterns (pageUrl,
indexJsonUrl, pageJsonUrl). Add useCreditsUtils hook that accepts path and
optional config. Update ModuleProps to include path so all modules receive
their route path automatically. Update Page.tsx to pass path to credits
menu and all module components.
2026-06-03 19:54:15 +09:00
orrisroot 6281e7524d refactor(credits): reorganize credits module into components directory
Move CreditsMenu to components/blocks and extract CreditsPage and
CreditsIndex as separate components. Update imports in Page.tsx and
add new words to cspell.json.
2026-06-03 18:58:47 +09:00
orrisroot 065cc91759 refactor(src): restructure source layout into four-layer architecture
Restructure src/ directory from flat layout to four-layer architecture:

- framework: main.tsx, App.tsx, layout/ (Page, Header, Footer,
  blocks), router/ (AppRoutes with module registry auto-routing)
- config: site.ts (site settings), modules.ts (MODULES_BASE_PATH
  and MODULES array for configurable URL paths)
- common: lib/ (functions, FilterTypes), components/ (PageNotFound,
  XoopsCode, Loading, NoticeBanner, LangFlag)
- modules: six encapsulated modules (brainexplorer, credits,
  nimgcenter, nimgdocs, nimgsearch, xoonips) with internal routing

Remove old directories: config.ts, functions.ts, routes/, pages/,
custom/, components/, brainexplorer/, nimgcenter/, nimgdocs/,
nimgsearch/, xoonips/ from src root.
2026-06-03 17:50:23 +09:00
orrisroot d86e92f42d refactor(data): move json data files to data directory and load dynamically
- Moved 14 json files from src/ to data/modules/
- Replace static imports with dynamic fetch in components
- Add async init methods to IndexUtil and ItemUtil
- Add error handling to all fetch calls
- Remove dead NimgenterUtilities.tsx
2026-06-02 16:48:10 +09:00
orrisroot 26ff5d6e7d refactor: migrate remaining components to CSS modules
Replace plain class names with CSS module imports across xoonips
components (DetailBase, ListBase, TopBase, AdvancedSearchBase, etc.).
Add @/ path alias to vite.config.ts for cleaner imports.
Fix Nimgsearch tab className and wrapper element.
Fix NimgcenterDetail baseitem variable naming consistency.
Add missing CSS classes (listTable, readme, rights, formButton).
Remove unused itemTypeName styles from XoonipsTopPage.
2026-06-02 16:01:56 +09:00
orrisroot fddef22422 fix: resolve routing and navigation issues after refactor
Restore useNavigate hook in IndexTree and SearchForm components (onNavigate
prop was never passed, breaking tree clicks and search form submission).
Fix CreditsUtils.getPageUrl to include index.php in generated links.
Add XoonipsDetailWrapper to read item_id and doi from URL query params.
Fix search/advanced route to show results page instead of search form.
Fix keyword search to use getSearchKeywordByQuery for correct param parsing.
Add search/advanced path to advanced search mode detection.
Add CSS module imports to SearchForm and XoonipsSearchPage.
2026-06-02 15:56:10 +09:00
orrisroot f96130aacf refactor: reorganize codebase into layered routing, pages, and components
- Move page components from module directories to src/pages/
- Extract reusable UI components into src/components/
- Introduce src/routes/ with modular route definitions per domain
- Add @/ path alias in tsconfig for cleaner absolute imports
- Update all import paths to reflect the new directory structure
- Move bulletin.json from assets/ to src/nimgdocs/ root
- Bump react-router-dom to 7.16.0 and @biomejs/biome to 2.4.16
2026-05-29 12:57:12 +09:00
353 changed files with 4479 additions and 4849 deletions
+5 -1
View File
@@ -13,8 +13,12 @@ dist-ssr
*.local
# Editor directories and files
.vscode/*
#.vscode/*
!.vscode/extensions.json
!.vscode/launch.json
!.vscode/settings.json
!.vscode/tasks.json
.opencoe/*
.idea
.DS_Store
*.suo
+16
View File
@@ -0,0 +1,16 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "Launch Chrome against localhost",
"url": "http://localhost:5173",
"webRoot": "${workspaceFolder}",
"preLaunchTask": "npm: dev"
}
]
}
+38
View File
@@ -0,0 +1,38 @@
{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.biome": "explicit"
},
"[css]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[javascript]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[javascriptreact]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[json]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[jsonc]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[typescript]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[typescriptreact]": {
"editor.defaultFormatter": "biomejs.biome"
},
// Extensions - Biome
// - see: biome.json
// Exteions - cSpell
// - see: .cspell.json
// Extensions - ESLint
"eslint.enable": false,
// Extensions - HTML
"html.format.wrapLineLength": 0,
// Extentions - Typescript
"javascript.updateImportsOnFileMove.enabled": "always",
"typescript.updateImportsOnFileMove.enabled": "always"
}
+20
View File
@@ -0,0 +1,20 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "dev",
"isBackground": true,
"problemMatcher": {
"owner": "custom",
"pattern": { "regexp": "^$" },
"background": {
"activeOnStart": true,
"beginsPattern": ".*",
"endsPattern": "Local:"
}
},
"label": "npm: dev"
}
]
}
+1 -1
View File
@@ -1,5 +1,5 @@
{
"$schema": "https://biomejs.dev/schemas/2.4.15/schema.json",
"$schema": "https://biomejs.dev/schemas/2.4.16/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
+69
View File
@@ -0,0 +1,69 @@
{
"version": "0.2",
"language": "en,en-GB",
"ignorePaths": [],
"dictionaryDefinitions": [],
"dictionaries": [],
"words": [
"aboutus",
"additem",
"BAIC",
"baseitem",
"BESA",
"Ccolumn",
"CEED",
"centercolumn",
"Conv",
"dbrowse",
"dobr",
"docname",
"dohtml",
"doimage",
"dosmiley",
"doxcode",
"EEGLAB",
"flatmaps",
"FMRIB",
"Gazzaniga",
"howtouse",
"htmlspecialchars",
"Huettel",
"itemselect",
"Ivry",
"Jessell",
"Jezzard",
"kaikougishiryou",
"klass",
"lastupdate",
"Lcolumn",
"leftcolumn",
"LORETA",
"Magnetoencephalography",
"mainmenu",
"Mangun",
"mlang",
"mtitle",
"neuro",
"neuroimg",
"Neuroinformatics",
"NICT",
"NIMG",
"Nimgcenter",
"nimgdocs",
"NIMGPF",
"nimgsearch",
"nirs",
"noukinoukensa",
"pogodin",
"Rcolumn",
"Sinauer",
"stim",
"superconduction",
"talairach",
"Xnpnimgcenter",
"xoonips",
"Xoops"
],
"ignoreWords": [],
"import": []
}
+18 -18
View File
@@ -1,20 +1,20 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="NIMG-PF is the Neuroinformatics site of Neuroimaging under NIJC."
/>
<link rel="manifest" href="/manifest.json" />
<title>NIMG - NeuroImaging Platform</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="NIMG-PF is the Neuroinformatics site of Neuroimaging under NIJC." />
<link rel="manifest" href="/manifest.json" />
<title data-rh="true">NIMG - NeuroImaging Platform</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
+249 -253
View File
@@ -8,6 +8,7 @@
"name": "nimg",
"version": "2.0.0",
"dependencies": {
"@dr.pogodin/react-helmet": "^3.2.2",
"@orrisroot/react-html-parser": "^3.0.1",
"async-lock": "^1.4.1",
"ky": "^2.0.2",
@@ -15,37 +16,36 @@
"modern-normalize": "^3.0.1",
"moment": "^2.30.1",
"rc-tree": "^5.13.1",
"react": "^19.2.6",
"react": "^19.2.7",
"react-cookie": "^8.1.2",
"react-dom": "^19.2.6",
"react-dom": "^19.2.7",
"react-ga4": "^3.0.1",
"react-helmet-async": "^3.0.0",
"react-overlays": "^5.2.1",
"react-router-dom": "^7.15.1",
"react-router-dom": "^7.17.0",
"react-router-hash-link": "^2.4.3",
"split-string": "^6.1.0",
"xregexp": "^5.1.2",
"yet-another-react-lightbox": "^3.32.0"
},
"devDependencies": {
"@biomejs/biome": "^2.4.15",
"@biomejs/biome": "^2.4.16",
"@eslint/js": "^10.0.1",
"@types/async-lock": "^1.4.2",
"@types/lokijs": "^1.5.14",
"@types/node": "^24.12.4",
"@types/react": "^19.2.15",
"@types/node": "^24.13.1",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"@types/react-router-dom": "^5.3.3",
"@types/react-router-hash-link": "^2.4.9",
"@vitejs/plugin-react": "^6.0.2",
"eslint": "^10.4.0",
"eslint": "^10.4.1",
"eslint-plugin-react-hooks": "^7.1.1",
"eslint-plugin-react-refresh": "^0.5.2",
"globals": "^17.6.0",
"sirv": "^3.0.2",
"typescript": "~6.0.3",
"typescript-eslint": "^8.60.0",
"vite": "^8.0.14"
"typescript-eslint": "^8.61.0",
"vite": "^8.0.16"
}
},
"node_modules/@babel/code-frame": {
@@ -310,9 +310,9 @@
}
},
"node_modules/@biomejs/biome": {
"version": "2.4.15",
"resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.4.15.tgz",
"integrity": "sha512-j5VH3a/h/HXTKBM50MDMxRCzkeLv9S2XJcW2WgnZT1+xyisi+0bISrXR82gCX+8S9lvK0skEvHJRN+3Ktr2hlw==",
"version": "2.4.16",
"resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.4.16.tgz",
"integrity": "sha512-x9ajFh1zChVybCiM3TN6OD4phAqLgtPZjFrZF+aTMYCPjwBO+k529TX7PPsAqtGNLeV4UgzwQnowEgS7bGmzcA==",
"dev": true,
"license": "MIT OR Apache-2.0",
"bin": {
@@ -326,20 +326,20 @@
"url": "https://opencollective.com/biome"
},
"optionalDependencies": {
"@biomejs/cli-darwin-arm64": "2.4.15",
"@biomejs/cli-darwin-x64": "2.4.15",
"@biomejs/cli-linux-arm64": "2.4.15",
"@biomejs/cli-linux-arm64-musl": "2.4.15",
"@biomejs/cli-linux-x64": "2.4.15",
"@biomejs/cli-linux-x64-musl": "2.4.15",
"@biomejs/cli-win32-arm64": "2.4.15",
"@biomejs/cli-win32-x64": "2.4.15"
"@biomejs/cli-darwin-arm64": "2.4.16",
"@biomejs/cli-darwin-x64": "2.4.16",
"@biomejs/cli-linux-arm64": "2.4.16",
"@biomejs/cli-linux-arm64-musl": "2.4.16",
"@biomejs/cli-linux-x64": "2.4.16",
"@biomejs/cli-linux-x64-musl": "2.4.16",
"@biomejs/cli-win32-arm64": "2.4.16",
"@biomejs/cli-win32-x64": "2.4.16"
}
},
"node_modules/@biomejs/cli-darwin-arm64": {
"version": "2.4.15",
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.4.15.tgz",
"integrity": "sha512-rF3PPqLq1yoST79zaQbDjVJwsuIeci/O+9bgNmC5QpgOqz6aqYuzA4abyAGx+mgyiDXn4A049xAN8gijbuR1Qg==",
"version": "2.4.16",
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.4.16.tgz",
"integrity": "sha512-wxPvu4XOA85YJk9ixSWUmq/QBHbid85BISbOAqqBM/5xQpPk9ayjk5375tOlSC0BeCwNSbPFafQBm+vBumXq0A==",
"cpu": [
"arm64"
],
@@ -354,9 +354,9 @@
}
},
"node_modules/@biomejs/cli-darwin-x64": {
"version": "2.4.15",
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.4.15.tgz",
"integrity": "sha512-/5KHXYMfSJs1fNXiX30xFtI8JcCFV6zaVVLxOa0M2sfqBKHkpQhRTv94yxQWxeTY2lzo2OuTlNvPC+hDQt2wcQ==",
"version": "2.4.16",
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.4.16.tgz",
"integrity": "sha512-xFCqGPwYusQJp4N4NJLi1XJiZqjwFdjhT+KqtNy+Ug3qgfczqnTa6MSDvxJF6TkuDLoYJItMapz6tAf7kCekFw==",
"cpu": [
"x64"
],
@@ -371,9 +371,9 @@
}
},
"node_modules/@biomejs/cli-linux-arm64": {
"version": "2.4.15",
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.4.15.tgz",
"integrity": "sha512-owaAMZD/T4LrD0ELNCk0Km3qrRHuM0X6EAyVE1FSqGY0rbLoiDLrO4Us2tllm6cAeB2Ioa9C2C08NZPdr8+0Ug==",
"version": "2.4.16",
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.4.16.tgz",
"integrity": "sha512-2kFb4//jxfZaP6D+Rj5VkHkxgyD9EoRAVBEQb8PKRv+s4NO2zYNJKXFaJmK1CmhufJOWEfpHKaRbOja7qjmdhQ==",
"cpu": [
"arm64"
],
@@ -388,9 +388,9 @@
}
},
"node_modules/@biomejs/cli-linux-arm64-musl": {
"version": "2.4.15",
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.4.15.tgz",
"integrity": "sha512-ZPcxznxm0pogHBLZhYntyR3sR+MrZjqJIKEr7ZqVen0Rl+P/4upVmfYXjftizi9RoqZntg33fv/1fbdhbYXpEQ==",
"version": "2.4.16",
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.4.16.tgz",
"integrity": "sha512-oYxnW0ARfJkr72ezzF2OR8N/rtkgLUQeYtF8cFhVswbknHxtTcmzSsanVJP8yQKnGpGpc2ck6c5zLvHahL6Cbg==",
"cpu": [
"arm64"
],
@@ -405,9 +405,9 @@
}
},
"node_modules/@biomejs/cli-linux-x64": {
"version": "2.4.15",
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.4.15.tgz",
"integrity": "sha512-0jj7THz12GbUOLmMibktK6DZjqz2zV64KFxyBtcFTKPiiOIY0a7vns1elpO1dERvxpsZ5ik0oFfz0oGwFde1+g==",
"version": "2.4.16",
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.4.16.tgz",
"integrity": "sha512-NbcBbi/nJqn5baae6wqRXdS7Gadf2uRpehSh6vMSYpG8OhkXl/Xg8aorWrJ+9VWqAT5ml90alLvorkpMW0nBwQ==",
"cpu": [
"x64"
],
@@ -422,9 +422,9 @@
}
},
"node_modules/@biomejs/cli-linux-x64-musl": {
"version": "2.4.15",
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.15.tgz",
"integrity": "sha512-CNq/9W38SYSH023lfcQ4KKU8K0YX8T//FZUhcgtMMRABDojx5XsMV7jlweAvGSl389wJQB29Qo6Zb/a+jdvt+w==",
"version": "2.4.16",
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.16.tgz",
"integrity": "sha512-iHDS+MCM65DPqWGu+ECC3uoALyj2H7F4nVUPxIPjz/PIl94EUu+EDfGZDzFP+NY1EOPVt9NQvwFqq7HdMmowdg==",
"cpu": [
"x64"
],
@@ -439,9 +439,9 @@
}
},
"node_modules/@biomejs/cli-win32-arm64": {
"version": "2.4.15",
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.4.15.tgz",
"integrity": "sha512-ouhkYdlhp/1GghEJPdWwD/Vi3gQ1nFxuSpMolWsbq3Lsq3QUR4jl6UdhhscdCugKU5vOEuMiJhvKj66O0OCq+w==",
"version": "2.4.16",
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.4.16.tgz",
"integrity": "sha512-0rgImMsNb5v/chhkIFe3wu7PEFClS6RBAYUijGL9UsYN3PanSaoK24HSSuSJb1pYbYYVjzAyZTl3gtjJ84BM8A==",
"cpu": [
"arm64"
],
@@ -456,9 +456,9 @@
}
},
"node_modules/@biomejs/cli-win32-x64": {
"version": "2.4.15",
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.4.15.tgz",
"integrity": "sha512-zBrGq5mx5wwpnow4+2BxUvleDM+GNd4sLbPaMapsSLQLD0NGRCquqPBTgN+7XkUteHvj7M+BstuI8tmnV7+HgQ==",
"version": "2.4.16",
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.4.16.tgz",
"integrity": "sha512-Kp85jgoBHa05gix6UIRjfCDiUV3w/8VIdZ247VyyO2gEjaw12WEVhdIjlxp/AMzXxqxQwbxNTDVZ3Mwd2RG5rw==",
"cpu": [
"x64"
],
@@ -472,6 +472,19 @@
"node": ">=14.21.3"
}
},
"node_modules/@dr.pogodin/react-helmet": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/@dr.pogodin/react-helmet/-/react-helmet-3.2.2.tgz",
"integrity": "sha512-ejHvL56wsjNRfzOWvBzBXZXKCls2beMIf63Cz1yEMi5OFfsdBQHEiy0ux6665qzPXXAqHws4tnnWRiA/fpaQBg==",
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.29.2",
"react-compiler-runtime": "^1.0.0"
},
"peerDependencies": {
"react": "19"
}
},
"node_modules/@emnapi/core": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
@@ -621,9 +634,9 @@
}
},
"node_modules/@eslint/plugin-kit": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.1.tgz",
"integrity": "sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==",
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz",
"integrity": "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -782,9 +795,9 @@
}
},
"node_modules/@oxc-project/types": {
"version": "0.132.0",
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.132.0.tgz",
"integrity": "sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==",
"version": "0.133.0",
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz",
"integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==",
"dev": true,
"license": "MIT",
"funding": {
@@ -821,9 +834,9 @@
}
},
"node_modules/@rolldown/binding-android-arm64": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.2.tgz",
"integrity": "sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz",
"integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==",
"cpu": [
"arm64"
],
@@ -838,9 +851,9 @@
}
},
"node_modules/@rolldown/binding-darwin-arm64": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.2.tgz",
"integrity": "sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz",
"integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==",
"cpu": [
"arm64"
],
@@ -855,9 +868,9 @@
}
},
"node_modules/@rolldown/binding-darwin-x64": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.2.tgz",
"integrity": "sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz",
"integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==",
"cpu": [
"x64"
],
@@ -872,9 +885,9 @@
}
},
"node_modules/@rolldown/binding-freebsd-x64": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.2.tgz",
"integrity": "sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz",
"integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==",
"cpu": [
"x64"
],
@@ -889,9 +902,9 @@
}
},
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.2.tgz",
"integrity": "sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz",
"integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==",
"cpu": [
"arm"
],
@@ -906,9 +919,9 @@
}
},
"node_modules/@rolldown/binding-linux-arm64-gnu": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.2.tgz",
"integrity": "sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz",
"integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==",
"cpu": [
"arm64"
],
@@ -923,9 +936,9 @@
}
},
"node_modules/@rolldown/binding-linux-arm64-musl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.2.tgz",
"integrity": "sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz",
"integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==",
"cpu": [
"arm64"
],
@@ -940,9 +953,9 @@
}
},
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.2.tgz",
"integrity": "sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz",
"integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==",
"cpu": [
"ppc64"
],
@@ -957,9 +970,9 @@
}
},
"node_modules/@rolldown/binding-linux-s390x-gnu": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.2.tgz",
"integrity": "sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz",
"integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==",
"cpu": [
"s390x"
],
@@ -974,9 +987,9 @@
}
},
"node_modules/@rolldown/binding-linux-x64-gnu": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.2.tgz",
"integrity": "sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz",
"integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==",
"cpu": [
"x64"
],
@@ -991,9 +1004,9 @@
}
},
"node_modules/@rolldown/binding-linux-x64-musl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.2.tgz",
"integrity": "sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz",
"integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==",
"cpu": [
"x64"
],
@@ -1008,9 +1021,9 @@
}
},
"node_modules/@rolldown/binding-openharmony-arm64": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.2.tgz",
"integrity": "sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz",
"integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==",
"cpu": [
"arm64"
],
@@ -1025,9 +1038,9 @@
}
},
"node_modules/@rolldown/binding-wasm32-wasi": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.2.tgz",
"integrity": "sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz",
"integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==",
"cpu": [
"wasm32"
],
@@ -1044,9 +1057,9 @@
}
},
"node_modules/@rolldown/binding-win32-arm64-msvc": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.2.tgz",
"integrity": "sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz",
"integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==",
"cpu": [
"arm64"
],
@@ -1061,9 +1074,9 @@
}
},
"node_modules/@rolldown/binding-win32-x64-msvc": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.2.tgz",
"integrity": "sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz",
"integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==",
"cpu": [
"x64"
],
@@ -1150,19 +1163,19 @@
"license": "MIT"
},
"node_modules/@types/node": {
"version": "24.12.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz",
"integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==",
"version": "24.13.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.1.tgz",
"integrity": "sha512-RSpUJGmvsJ1ZeBehQZFhIdpsz+bIpES0nIQXko4Ybq+N+kX6XvOq3Jo+iJ82FWLdblFq85AsMikd3m35jgezYg==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.16.0"
"undici-types": "~7.18.0"
}
},
"node_modules/@types/react": {
"version": "19.2.15",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.15.tgz",
"integrity": "sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==",
"version": "19.2.17",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz",
"integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==",
"license": "MIT",
"dependencies": {
"csstype": "^3.2.2"
@@ -1220,17 +1233,17 @@
"license": "MIT"
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.60.0.tgz",
"integrity": "sha512-QYb/sa74/s7OKMbACMjrYnGspj9Hs5YI5aaffSL65UfeBUzVzBJfVo3oWSpbzPurvm7yaCCo2Lk7lVj610HqKw==",
"version": "8.61.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.61.0.tgz",
"integrity": "sha512-bFNvl9ZczlVb+wR2Akszf3gHfKVj/8WanXaGJ3UstTA7brNKg0cNdk6X1Psu5V7MZ2oQtzZKOEzIUehaoxbDGw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/regexpp": "^4.12.2",
"@typescript-eslint/scope-manager": "8.60.0",
"@typescript-eslint/type-utils": "8.60.0",
"@typescript-eslint/utils": "8.60.0",
"@typescript-eslint/visitor-keys": "8.60.0",
"@typescript-eslint/scope-manager": "8.61.0",
"@typescript-eslint/type-utils": "8.61.0",
"@typescript-eslint/utils": "8.61.0",
"@typescript-eslint/visitor-keys": "8.61.0",
"ignore": "^7.0.5",
"natural-compare": "^1.4.0",
"ts-api-utils": "^2.5.0"
@@ -1243,7 +1256,7 @@
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"@typescript-eslint/parser": "^8.60.0",
"@typescript-eslint/parser": "^8.61.0",
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.1.0"
}
@@ -1259,16 +1272,16 @@
}
},
"node_modules/@typescript-eslint/parser": {
"version": "8.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.60.0.tgz",
"integrity": "sha512-fcqpj/MyK4sxDPcbe7STNPbpQL4RLZOPWuaTmwZYuc+hJKzRf58yRxfhqGpc6PIq9ZyfSBpfHgmUHmHs0KwHwg==",
"version": "8.61.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.61.0.tgz",
"integrity": "sha512-5B7PfA2e1NQGCnDHd/0lW7W3gvp3d59Ryw54FYO8Uswxo9f6ikw3AZV+Xj/TvpImmpsiYyUqAfhC6kJID1jF6w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/scope-manager": "8.60.0",
"@typescript-eslint/types": "8.60.0",
"@typescript-eslint/typescript-estree": "8.60.0",
"@typescript-eslint/visitor-keys": "8.60.0",
"@typescript-eslint/scope-manager": "8.61.0",
"@typescript-eslint/types": "8.61.0",
"@typescript-eslint/typescript-estree": "8.61.0",
"@typescript-eslint/visitor-keys": "8.61.0",
"debug": "^4.4.3"
},
"engines": {
@@ -1284,14 +1297,14 @@
}
},
"node_modules/@typescript-eslint/project-service": {
"version": "8.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.0.tgz",
"integrity": "sha512-aZu74NNKJeUWqCjDddzdiKaS82dgYgV/vmf+Ui3ZdZejmgfXR/q+pRumgobnQ2cCJTgGTWp4ypiwsuofFubavg==",
"version": "8.61.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.61.0.tgz",
"integrity": "sha512-DV42F7MLJO6Rax7SK1yg43tcnEfGUrurSpSxKuVX+a3RCTzBlH3fuxprrOJXKCJGAaw82xXocikJ0uQaqwXgGA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/tsconfig-utils": "^8.60.0",
"@typescript-eslint/types": "^8.60.0",
"@typescript-eslint/tsconfig-utils": "^8.61.0",
"@typescript-eslint/types": "^8.61.0",
"debug": "^4.4.3"
},
"engines": {
@@ -1306,14 +1319,14 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "8.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.60.0.tgz",
"integrity": "sha512-pFzqhllJMs+jghLQWzV00ds39xLzuyqPSev5pd8f4Ir0rtKR3ZLUB4/4dhjOFighWb9larvtfJvqL+4yKDI3Xw==",
"version": "8.61.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.61.0.tgz",
"integrity": "sha512-IWdXFHFSb6mlC3HPc7QsLDm5zYEbUla6trDEHf32D3/dnuUyXd87plScSNXSbm0/RxMvObpI17sv/EDTGrGZkA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.60.0",
"@typescript-eslint/visitor-keys": "8.60.0"
"@typescript-eslint/types": "8.61.0",
"@typescript-eslint/visitor-keys": "8.61.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1324,9 +1337,9 @@
}
},
"node_modules/@typescript-eslint/tsconfig-utils": {
"version": "8.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.0.tgz",
"integrity": "sha512-BZPR3RGYlAXnly6ymAxfkVn5rCbZzQNou0rxv3GfWZ8cTQp+hhVd73khbGLAd8k1TlAPLISH337M+tAgAnaJDQ==",
"version": "8.61.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.61.0.tgz",
"integrity": "sha512-O5Amvdv9ztMpxpf+vmFULGG78IE6Qwdr3bCGvqwG4nwc9H2qXkOYJJnRbRHyMkQTjv1d03olqwwwzHLMqpFePQ==",
"dev": true,
"license": "MIT",
"engines": {
@@ -1341,15 +1354,15 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "8.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.60.0.tgz",
"integrity": "sha512-SX46wEUtitCpq7AN38HkUU/+zvUpdKf7ephtWAFgckH8O7PQIyL5gvrhQgBLuEYgLfuKWOVvWVskMbuFHAz5xg==",
"version": "8.61.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.61.0.tgz",
"integrity": "sha512-TuBiQYIkd97yBfInHCTKVYMbX4kvEmpOEuixIuzCU9p8BGT1SfyyO0d0IfDMbPIHcjn/hWnusUX5e8v5Xg+X8A==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.60.0",
"@typescript-eslint/typescript-estree": "8.60.0",
"@typescript-eslint/utils": "8.60.0",
"@typescript-eslint/types": "8.61.0",
"@typescript-eslint/typescript-estree": "8.61.0",
"@typescript-eslint/utils": "8.61.0",
"debug": "^4.4.3",
"ts-api-utils": "^2.5.0"
},
@@ -1366,9 +1379,9 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "8.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.0.tgz",
"integrity": "sha512-AsE7x2XaAK+CVbeih0Fvbn+r1qHxtpLDJ3XUuFcIinT318T90yHMJC+Zgv+jUuDjQQd06HKwxnDu6sz1IcTilA==",
"version": "8.61.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.61.0.tgz",
"integrity": "sha512-9QTQpZ5Iin4CdIodfbDQFSeiSJKidgYJYug1P9CC2xWgUTvlmixViqDZNciMjwLBZyJnG4tGmPl97rVAFb1AJg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -1380,16 +1393,16 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "8.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.0.tgz",
"integrity": "sha512-3AcZNBGMClm6CXDyo8kYvVGT/sx29sS0oBsIb9oZI2gunA4Vm2M3YHzRLPvsUBBsl+yB5FPtltq7gGH0iTlp9g==",
"version": "8.61.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.61.0.tgz",
"integrity": "sha512-42zatd5qSvvcV1JdDBCLxYRznvP4eIHpPoZXdkPFnAmanA4FuZ5dibSnCBggY8hQnqajPpoGjXFdZ7fIJKQnlA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/project-service": "8.60.0",
"@typescript-eslint/tsconfig-utils": "8.60.0",
"@typescript-eslint/types": "8.60.0",
"@typescript-eslint/visitor-keys": "8.60.0",
"@typescript-eslint/project-service": "8.61.0",
"@typescript-eslint/tsconfig-utils": "8.61.0",
"@typescript-eslint/types": "8.61.0",
"@typescript-eslint/visitor-keys": "8.61.0",
"debug": "^4.4.3",
"minimatch": "^10.2.2",
"semver": "^7.7.3",
@@ -1408,9 +1421,9 @@
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
"version": "7.8.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz",
"integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.3.tgz",
"integrity": "sha512-wnilbGyMxzbY7dNOl7jpKbLSjcfeweJWU5j4+u5qW+6/wuGD9KzIGOyZnQVSBM9E7DtWaaH3CyHkppYrKYoxwg==",
"dev": true,
"license": "ISC",
"bin": {
@@ -1421,16 +1434,16 @@
}
},
"node_modules/@typescript-eslint/utils": {
"version": "8.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.60.0.tgz",
"integrity": "sha512-HtXuPfrHTyBDkameWpl+vJb1Uevu2tznAyahM1Oc4AENidCLTPiZDWIo4GfcxNdC/RcfGcadzzkqbRG87dUrQA==",
"version": "8.61.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.61.0.tgz",
"integrity": "sha512-3bzFt7ImFMW/jVYwJamDoe/dMOdFLSC6pom6rRjdh4SZJEYupyMzem8e7vKZLclLfpHjlwSAXOUxtKxGXUiLqA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.9.1",
"@typescript-eslint/scope-manager": "8.60.0",
"@typescript-eslint/types": "8.60.0",
"@typescript-eslint/typescript-estree": "8.60.0"
"@typescript-eslint/scope-manager": "8.61.0",
"@typescript-eslint/types": "8.61.0",
"@typescript-eslint/typescript-estree": "8.61.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1445,13 +1458,13 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "8.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.0.tgz",
"integrity": "sha512-9WI52t8ZGLVGrPMBet25yAftqY/n95+zmoUUtJBBQTKDSKUu7OsPTroT2op7U9JatkoRccL0YkWDNMFfC4Sjxg==",
"version": "8.61.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.61.0.tgz",
"integrity": "sha512-QVLZu3ZPQEE+HICQyAMZ2yLQhxf0meY/wx6Hx14YcTNj13JB3qHlX3lJ02L3fLGHgERRH71kvYDwiXIguT3AjQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.60.0",
"@typescript-eslint/types": "8.61.0",
"eslint-visitor-keys": "^5.0.0"
},
"engines": {
@@ -1545,9 +1558,9 @@
}
},
"node_modules/baseline-browser-mapping": {
"version": "2.10.32",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.32.tgz",
"integrity": "sha512-wbPvpyjJPC0zdfdKXxqEL3Ea+bOMD/87X4lftiJkkaBiuG6ALQy1SLmEd7BSmVCuwCQsBrCamgBoLyfFDD1EPg==",
"version": "2.10.34",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.34.tgz",
"integrity": "sha512-IMDedajPifLnHNY0X9n8hKxRTQ6/eTHwr5bDo04WnuqxyKw6LYtQywCuuqPZwhl3aBXMvQpJov42GLCwRRdQzw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@@ -1605,9 +1618,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001793",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz",
"integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==",
"version": "1.0.30001797",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001797.tgz",
"integrity": "sha512-l8xKG+gwAIExZGl9FrF7KUwuOmk6wbEPC9Xoy/RtnWv1XG0Q4LFlagaLpUv3Kiza3W/wm27zy0yWJEieYKAP6w==",
"dev": true,
"funding": [
{
@@ -1805,9 +1818,9 @@
}
},
"node_modules/electron-to-chromium": {
"version": "1.5.362",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.362.tgz",
"integrity": "sha512-PUY2DrLvkjkUuWqq+KPL2iWshrJsZOcIojzRQ7eXFacc9dWga7MGMJAa15VbiejSZB1PAXaRLAiKgruHP8LB1w==",
"version": "1.5.369",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.369.tgz",
"integrity": "sha512-XM22K9FNaaCOvMMrBn1caIc8v0g6+pKt660ZbfQqUZvfil0hEzr8ZoiY7VcSLGM3L/x3rz5PqZrk+bKOOmVM9w==",
"dev": true,
"license": "ISC"
},
@@ -1847,9 +1860,9 @@
}
},
"node_modules/eslint": {
"version": "10.4.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-10.4.0.tgz",
"integrity": "sha512-loXy6bWOoP3EP6JA7jo6p5jMpBJmHmsNZM5SFRHLdh1MGOPurMnNBj4ZlAbaqUAaQWbCr7jHV4P7gzAyryZWkQ==",
"version": "10.4.1",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-10.4.1.tgz",
"integrity": "sha512-AyIKhnOBuOAdueD7RB3xB+YeAWScb9jHsJBgH2Hcde8InP5JYhqrRR6iTMHyTEwgENK54Cp44e4v8BwNhsuHuw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1858,7 +1871,7 @@
"@eslint/config-array": "^0.23.5",
"@eslint/config-helpers": "^0.6.0",
"@eslint/core": "^1.2.1",
"@eslint/plugin-kit": "^0.7.1",
"@eslint/plugin-kit": "^0.7.2",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
"@humanwhocodes/retry": "^0.4.2",
@@ -2757,9 +2770,9 @@
"license": "MIT"
},
"node_modules/node-releases": {
"version": "2.0.46",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.46.tgz",
"integrity": "sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==",
"version": "2.0.47",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.47.tgz",
"integrity": "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==",
"dev": true,
"license": "MIT",
"engines": {
@@ -3016,14 +3029,23 @@
}
},
"node_modules/react": {
"version": "19.2.6",
"resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz",
"integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==",
"version": "19.2.7",
"resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz",
"integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/react-compiler-runtime": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/react-compiler-runtime/-/react-compiler-runtime-1.0.0.tgz",
"integrity": "sha512-rRfjYv66HlG8896yPUDONgKzG5BxZD1nV9U6rkm+7VCuvQc903C4MjcoZR4zPw53IKSOX9wMQVpA1IAbRtzQ7w==",
"license": "MIT",
"peerDependencies": {
"react": "^17.0.0 || ^18.0.0 || ^19.0.0 || ^0.0.0-experimental"
}
},
"node_modules/react-cookie": {
"version": "8.1.2",
"resolved": "https://registry.npmjs.org/react-cookie/-/react-cookie-8.1.2.tgz",
@@ -3039,43 +3061,23 @@
}
},
"node_modules/react-dom": {
"version": "19.2.6",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz",
"integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==",
"version": "19.2.7",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz",
"integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==",
"license": "MIT",
"dependencies": {
"scheduler": "^0.27.0"
},
"peerDependencies": {
"react": "^19.2.6"
"react": "^19.2.7"
}
},
"node_modules/react-fast-compare": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
"integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==",
"license": "MIT"
},
"node_modules/react-ga4": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/react-ga4/-/react-ga4-3.0.1.tgz",
"integrity": "sha512-GyCc01bSheWXjzGDyHsXMOqk/SP5Cf/JrcJTg4hcpKx4eeSwaJKpJUc+ipF4ffLTZkmabmf3ZGBv4OKHTXNXyA==",
"license": "MIT"
},
"node_modules/react-helmet-async": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-3.0.0.tgz",
"integrity": "sha512-nA3IEZfXiclgrz4KLxAhqJqIfFDuvzQwlKwpdmzZIuC1KNSghDEIXmyU0TKtbM+NafnkICcwx8CECFrZ/sL/1w==",
"license": "Apache-2.0",
"dependencies": {
"invariant": "^2.2.4",
"react-fast-compare": "^3.2.2",
"shallowequal": "^1.1.0"
},
"peerDependencies": {
"react": "^16.6.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/react-is": {
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
@@ -3109,9 +3111,9 @@
}
},
"node_modules/react-router": {
"version": "7.15.1",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.15.1.tgz",
"integrity": "sha512-R8rl9HhgikFYoPJymnUtPXWbnDb3oget6lQnfIoupbt61aT9aOhRkDsY2XRhZRyX1Z/8a5sL74fXmFNm3NRK5A==",
"version": "7.17.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.17.0.tgz",
"integrity": "sha512-FDELK7rTMlCHO5+reyXsPlmfr7N1F91lPHsWYfMEGQm/KQ+F4JFM8jGoeQDmDvdTs93Fw9aSilH+uKRb4/jXvQ==",
"license": "MIT",
"dependencies": {
"cookie": "^1.0.1",
@@ -3131,12 +3133,12 @@
}
},
"node_modules/react-router-dom": {
"version": "7.15.1",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.15.1.tgz",
"integrity": "sha512-AzF62gjY6U9rkMq4RfP/r2EVtQ7DMfNMjyOp/flLTCrtRylLiK4wT4pSq6O8rOXZ2eXdZYJPEYe+ifomiv+Igg==",
"version": "7.17.0",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.17.0.tgz",
"integrity": "sha512-fyU2yjGups/hE6Xz0I5ZYbVL8Gx29eCjgpHaRaTaVU+OOAdfRX05KsvyRm0GO8YQwOkhpU3MurW1jyMUJn+zSw==",
"license": "MIT",
"dependencies": {
"react-router": "7.15.1"
"react-router": "7.17.0"
},
"engines": {
"node": ">=20.0.0"
@@ -3166,13 +3168,13 @@
"license": "MIT"
},
"node_modules/rolldown": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.2.tgz",
"integrity": "sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz",
"integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@oxc-project/types": "=0.132.0",
"@oxc-project/types": "=0.133.0",
"@rolldown/pluginutils": "^1.0.0"
},
"bin": {
@@ -3182,21 +3184,21 @@
"node": "^20.19.0 || >=22.12.0"
},
"optionalDependencies": {
"@rolldown/binding-android-arm64": "1.0.2",
"@rolldown/binding-darwin-arm64": "1.0.2",
"@rolldown/binding-darwin-x64": "1.0.2",
"@rolldown/binding-freebsd-x64": "1.0.2",
"@rolldown/binding-linux-arm-gnueabihf": "1.0.2",
"@rolldown/binding-linux-arm64-gnu": "1.0.2",
"@rolldown/binding-linux-arm64-musl": "1.0.2",
"@rolldown/binding-linux-ppc64-gnu": "1.0.2",
"@rolldown/binding-linux-s390x-gnu": "1.0.2",
"@rolldown/binding-linux-x64-gnu": "1.0.2",
"@rolldown/binding-linux-x64-musl": "1.0.2",
"@rolldown/binding-openharmony-arm64": "1.0.2",
"@rolldown/binding-wasm32-wasi": "1.0.2",
"@rolldown/binding-win32-arm64-msvc": "1.0.2",
"@rolldown/binding-win32-x64-msvc": "1.0.2"
"@rolldown/binding-android-arm64": "1.0.3",
"@rolldown/binding-darwin-arm64": "1.0.3",
"@rolldown/binding-darwin-x64": "1.0.3",
"@rolldown/binding-freebsd-x64": "1.0.3",
"@rolldown/binding-linux-arm-gnueabihf": "1.0.3",
"@rolldown/binding-linux-arm64-gnu": "1.0.3",
"@rolldown/binding-linux-arm64-musl": "1.0.3",
"@rolldown/binding-linux-ppc64-gnu": "1.0.3",
"@rolldown/binding-linux-s390x-gnu": "1.0.3",
"@rolldown/binding-linux-x64-gnu": "1.0.3",
"@rolldown/binding-linux-x64-musl": "1.0.3",
"@rolldown/binding-openharmony-arm64": "1.0.3",
"@rolldown/binding-wasm32-wasi": "1.0.3",
"@rolldown/binding-win32-arm64-msvc": "1.0.3",
"@rolldown/binding-win32-x64-msvc": "1.0.3"
}
},
"node_modules/scheduler": {
@@ -3221,12 +3223,6 @@
"integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==",
"license": "MIT"
},
"node_modules/shallowequal": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
"integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==",
"license": "MIT"
},
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -3285,9 +3281,9 @@
}
},
"node_modules/tinyglobby": {
"version": "0.2.16",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
"integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
"version": "0.2.17",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
"integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3360,16 +3356,16 @@
}
},
"node_modules/typescript-eslint": {
"version": "8.60.0",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.60.0.tgz",
"integrity": "sha512-9f65qWLZdAW9m1JaxBDUHcqRUfL8bkxxXL7XxEfI+F09q56PkBvIfCjLF3yInsDM/BBmwkqmCQdCZe/RYlIWEw==",
"version": "8.61.0",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.61.0.tgz",
"integrity": "sha512-8y31Rd0eGTrDKqhy6vT0HtzhN+YLjQizwX3aA3hPXP/ynSfnrBXcQY5IzsP9/DM7+klX4IUncZZjkchP0z+rUw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/eslint-plugin": "8.60.0",
"@typescript-eslint/parser": "8.60.0",
"@typescript-eslint/typescript-estree": "8.60.0",
"@typescript-eslint/utils": "8.60.0"
"@typescript-eslint/eslint-plugin": "8.61.0",
"@typescript-eslint/parser": "8.61.0",
"@typescript-eslint/typescript-estree": "8.61.0",
"@typescript-eslint/utils": "8.61.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -3399,9 +3395,9 @@
}
},
"node_modules/undici-types": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
"version": "7.18.2",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
"integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
"dev": true,
"license": "MIT"
},
@@ -3456,17 +3452,17 @@
}
},
"node_modules/vite": {
"version": "8.0.14",
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.14.tgz",
"integrity": "sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw==",
"version": "8.0.16",
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz",
"integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==",
"dev": true,
"license": "MIT",
"dependencies": {
"lightningcss": "^1.32.0",
"picomatch": "^4.0.4",
"postcss": "^8.5.15",
"rolldown": "1.0.2",
"tinyglobby": "^0.2.16"
"rolldown": "1.0.3",
"tinyglobby": "^0.2.17"
},
"bin": {
"vite": "bin/vite.js"
+10 -10
View File
@@ -12,6 +12,7 @@
"preview": "vite preview"
},
"dependencies": {
"@dr.pogodin/react-helmet": "^3.2.2",
"@orrisroot/react-html-parser": "^3.0.1",
"async-lock": "^1.4.1",
"ky": "^2.0.2",
@@ -19,36 +20,35 @@
"modern-normalize": "^3.0.1",
"moment": "^2.30.1",
"rc-tree": "^5.13.1",
"react": "^19.2.6",
"react": "^19.2.7",
"react-cookie": "^8.1.2",
"react-dom": "^19.2.6",
"react-dom": "^19.2.7",
"react-ga4": "^3.0.1",
"react-helmet-async": "^3.0.0",
"react-overlays": "^5.2.1",
"react-router-dom": "^7.15.1",
"react-router-dom": "^7.17.0",
"react-router-hash-link": "^2.4.3",
"split-string": "^6.1.0",
"xregexp": "^5.1.2",
"yet-another-react-lightbox": "^3.32.0"
},
"devDependencies": {
"@biomejs/biome": "^2.4.15",
"@biomejs/biome": "^2.4.16",
"@eslint/js": "^10.0.1",
"@types/async-lock": "^1.4.2",
"@types/lokijs": "^1.5.14",
"@types/node": "^24.12.4",
"@types/react": "^19.2.15",
"@types/node": "^24.13.1",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"@types/react-router-dom": "^5.3.3",
"@types/react-router-hash-link": "^2.4.9",
"@vitejs/plugin-react": "^6.0.2",
"eslint": "^10.4.0",
"eslint": "^10.4.1",
"eslint-plugin-react-hooks": "^7.1.1",
"eslint-plugin-react-refresh": "^0.5.2",
"globals": "^17.6.0",
"sirv": "^3.0.2",
"typescript": "~6.0.3",
"typescript-eslint": "^8.60.0",
"vite": "^8.0.14"
"typescript-eslint": "^8.61.0",
"vite": "^8.0.16"
}
}
+1 -1
View File
@@ -1,2 +1,2 @@
@import url("./common/assets/xoops.css");
@import url("./custom/assets/style.css");
@import url("./layout/assets/style.css");
+30 -4
View File
@@ -1,16 +1,42 @@
import type React from 'react';
import { HelmetProvider } from '@dr.pogodin/react-helmet';
import React from 'react';
import { CookiesProvider } from 'react-cookie';
import { HelmetProvider } from 'react-helmet-async';
import { BrowserRouter } from 'react-router-dom';
import './App.css';
import AppRoot from './common/AppRoot';
import { MODULES, MODULES_BASE_PATH } from './config/modules';
import { getIndexUtil } from './modules/xoonips/components/lib/IndexUtil';
import { getItemUtil } from './modules/xoonips/components/lib/ItemUtil';
import AppRoutes from './router/AppRoutes';
const App: React.FC = () => {
const [loading, setLoading] = React.useState(true);
React.useEffect(() => {
const promises: Promise<void>[] = [];
MODULES.forEach((module) => {
if (module.path === 'xoonips') {
const path = `/${MODULES_BASE_PATH}/${module.path}`;
promises.push(getIndexUtil(path).init());
promises.push(getItemUtil(path).init());
}
});
Promise.all(promises)
.then(() => {
setLoading(false);
})
.catch(() => {
setLoading(false);
});
}, []);
if (loading) return null;
return (
<BrowserRouter>
<CookiesProvider>
<HelmetProvider>
<AppRoot />
<AppRoutes />
</HelmetProvider>
</CookiesProvider>
</BrowserRouter>
-31
View File
@@ -1,31 +0,0 @@
import type React from 'react';
import { Helmet } from 'react-helmet-async';
import { Route, Routes } from 'react-router-dom';
import PageNotFound from '../common/lib/PageNotFound';
import type { MultiLang } from '../config';
import Functions from '../functions';
import BrainExplorerIndex from './BrainExplorerIndex';
interface Props {
lang: MultiLang;
}
const BrainExplorer: React.FC<Props> = (props: Props) => {
const { lang } = props;
return (
<>
<Helmet>
<title>Brain Explorer - {Functions.siteTitle(lang)}</title>
</Helmet>
<Routes>
<Route path="index_jm_eng.php" element={<BrainExplorerIndex lang="en" type="jm" />} />
<Route path="index_jm_jpn.php" element={<BrainExplorerIndex lang="ja" type="jm" />} />
<Route path="index_hu_eng.php" element={<BrainExplorerIndex lang="en" type="hu" />} />
<Route path="index_hu_jpn.php" element={<BrainExplorerIndex lang="ja" type="hu" />} />
<Route path="*" element={<PageNotFound lang={lang} />} />
</Routes>
</>
);
};
export default BrainExplorer;
+15 -11
View File
@@ -1,17 +1,25 @@
import type React from 'react';
import { useEffect, useState } from 'react';
import React from 'react';
import { useCookies } from 'react-cookie';
import ReactGA from 'react-ga4';
import { useLocation } from 'react-router-dom';
import Config, { type MultiLang } from '../config';
import Page from '../custom/Page';
import type { MultiLang } from '../config/site';
import Config from '../config/site';
import Page from '../layout/Page';
const AppMain: React.FC = () => {
const [cookies, setCookie] = useCookies();
const [lang, setLang] = useState<MultiLang>(['en', 'ja'].includes(cookies.ml_lang) ? cookies.ml_lang : 'en');
const location = useLocation();
useEffect(() => {
const lang = React.useMemo<MultiLang>(() => {
const params = new URLSearchParams(location.search);
const ml_lang = params.get('ml_lang');
if (ml_lang != null && ['en', 'ja'].includes(ml_lang)) {
return ml_lang as MultiLang;
}
return ['en', 'ja'].includes(cookies.ml_lang) ? cookies.ml_lang : 'en';
}, [cookies.ml_lang, location.search]);
React.useEffect(() => {
if (Config.GOOGLE_ANALYTICS_TRACKING_ID !== '') {
ReactGA.send('pageview');
}
@@ -21,13 +29,9 @@ const AppMain: React.FC = () => {
if (cookies.ml_lang !== ml_lang) {
setCookie('ml_lang', ml_lang);
}
if (lang !== ml_lang) {
// eslint-disable-next-line react-hooks/set-state-in-effect
setLang(ml_lang as MultiLang);
}
}
window.scrollTo(0, 0);
}, [cookies, setCookie, lang, location]);
}, [cookies.ml_lang, setCookie, location]);
return <Page lang={lang} />;
};
Binary file not shown.

Before

Width:  |  Height:  |  Size: 985 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 905 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 894 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 856 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 789 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 779 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 475 B

@@ -1,8 +1,8 @@
import type React from 'react';
import { Link, useLocation } from 'react-router-dom';
import type { MultiLang } from '../../config';
import mlangEnglish from '../assets/images/mlang_english.gif';
import mlangJapanese from '../assets/images/mlang_japanese.gif';
import type { MultiLang } from '../../config/site';
import mlangEnglish from './images/mlang_english.gif';
import mlangJapanese from './images/mlang_japanese.gif';
interface Props {
lang: MultiLang;
@@ -15,7 +15,7 @@ const langResources = {
ja: { image: mlangJapanese, title: 'Japanese' },
};
const LangFlag: React.FC<Props> = (props: Props) => {
const LangFlag: React.FC<Props> = (props) => {
const { lang, className, image } = props;
const location = useLocation();
const params = new URLSearchParams(location.search);
@@ -1,16 +1,16 @@
import type React from 'react';
import type { MultiLang } from '../../config';
import Functions from '../../functions';
import type { MultiLang } from '../../config/site';
import Functions from '../lib/functions';
interface Props {
lang: MultiLang;
}
const NoticeSiteHasBeenArchived: React.FC<Props> = (props: Props) => {
const NoticeBanner: React.FC<Props> = (props) => {
const { lang } = props;
const notice =
'[en]This site has been archived since FY2019 and is no longer updated.[/en][ja]このサイトは、2019年度よりアーカイブサイトとして運用されています。[/ja]';
return <p style={{ color: 'red' }}>{Functions.mlang(notice, lang)}</p>;
};
export default NoticeSiteHasBeenArchived;
export default NoticeBanner;
@@ -1,9 +1,8 @@
import type React from 'react';
import { useEffect } from 'react';
import { Helmet } from 'react-helmet-async';
import { Helmet } from '@dr.pogodin/react-helmet';
import React from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import type { MultiLang } from '../../config';
import Functions from '../../functions';
import type { MultiLang } from '../../config/site';
import Functions from '../lib/functions';
interface Props {
lang: MultiLang;
@@ -15,7 +14,7 @@ const PageNotFound: React.FC<Props> = (props) => {
const navigate = useNavigate();
const url = '/';
useEffect(() => {
React.useEffect(() => {
let timer: ReturnType<typeof setTimeout> | null = null;
if (location.pathname !== '/' && import.meta.env.PROD) {
if (timer === null) {
@@ -2,8 +2,8 @@ import type { DomElement, DomNode, Transform } from '@orrisroot/react-html-parse
import ReactHtmlParser, { convertNodeToElement } from '@orrisroot/react-html-parser';
import type React from 'react';
import { HashLink } from 'react-router-hash-link';
import type { MultiLang } from '../../config';
import Functions from '../../functions';
import type { MultiLang } from '../../config/site';
import Functions from '../lib/functions';
interface Props {
lang: MultiLang;
@@ -15,7 +15,7 @@ interface Props {
dobr?: boolean;
}
const preConvertXCode = (text: string, doxcode: boolean): string => {
const preConvertXCode: (text: string, doxcode: boolean) => string = (text, doxcode) => {
if (doxcode) {
return text.replace(/\[code\](.*)\[\/code\]/gs, (_m0, m1) => {
return '[code]' + Functions.base64Encode(m1) + '[/code]';
@@ -24,7 +24,7 @@ const preConvertXCode = (text: string, doxcode: boolean): string => {
return text;
};
const postConvertXCode = (text: string, doxcode: boolean, doimage: boolean): string => {
const postConvertXCode: (text: string, doxcode: boolean, doimage: boolean) => string = (text, doxcode, doimage) => {
if (doxcode) {
return text.replace(/\[code\](.*)\[\/code\]/gs, (_m0, m1) => {
const text = convertXCode(Functions.htmlspecialchars(Functions.base64Decode(m1)), doimage);
@@ -34,7 +34,7 @@ const postConvertXCode = (text: string, doxcode: boolean, doimage: boolean): str
return text;
};
const convertClickable = (text: string) => {
const convertClickable: (text: string) => string = (text) => {
text = text.replace(
/(^|[^\]_a-zA-Z0-9-="'/]+)((?:https?|ftp)(?::\/\/[-_.!~*'()a-zA-Z0-9;/?:@&=+$,%#]+[a-zA-Z0-9=]))/g,
(...matches) => {
@@ -49,7 +49,7 @@ const convertClickable = (text: string) => {
},
);
text = text.replace(
/(^|[^\]_a-zA-Z0-9-="'/:.]+)([a-zA-Z0-9.!#$%&*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+)/g,
/(^|[^\]_a-zA-Z0-9-="'/:.]+)([a-zA-Z0-9.!#$%&'`*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+)/g,
(...matches) => {
return matches[1] + '<a href="mailto:' + matches[2] + '">' + matches[2] + '</a>';
},
@@ -57,21 +57,21 @@ const convertClickable = (text: string) => {
return text;
};
const convertXCode: (text: string, doimage: boolean) => string = (text): string => {
const convertXCode: (text: string, doimage: boolean) => string = (text) => {
// TODO: implement
return text;
};
const convertSmiley: (text: string) => string = (text): string => {
const convertSmiley: (text: string) => string = (text) => {
// TODO: implement
return text;
};
const convertBr = (text: string): string => {
const convertBr: (text: string) => string = (text) => {
return text.replace(/(\r?\n|\r)/g, '<br />');
};
const cssConvert = (text: string): { [key: string]: string } => {
const cssConvert: (text: string) => { [key: string]: string } = (text) => {
const ret: { [key: string]: string } = {};
text.split(';').forEach((line) => {
const line_ = line.trim();
@@ -86,7 +86,7 @@ const cssConvert = (text: string): { [key: string]: string } => {
return ret;
};
const xoopsTransform: Transform = (node: DomNode, index: number | string, transform?: Transform): React.ReactNode => {
const xoopsTransform: Transform = (node, index, transform?) => {
if (node.type === 'tag') {
const node_ = node as DomElement;
if (node_.name === 'a') {
@@ -116,7 +116,7 @@ const xoopsTransform: Transform = (node: DomNode, index: number | string, transf
}
};
const XoopsCode: React.FC<Props> = (props: Props) => {
const XoopsCode: React.FC<Props> = (props) => {
const { lang } = props;
let text = props.text;
const dohtml = !!props.dohtml;

Before

Width:  |  Height:  |  Size: 175 B

After

Width:  |  Height:  |  Size: 175 B

Before

Width:  |  Height:  |  Size: 126 B

After

Width:  |  Height:  |  Size: 126 B

Before

Width:  |  Height:  |  Size: 210 B

After

Width:  |  Height:  |  Size: 210 B

Before

Width:  |  Height:  |  Size: 204 B

After

Width:  |  Height:  |  Size: 204 B

Before

Width:  |  Height:  |  Size: 174 B

After

Width:  |  Height:  |  Size: 174 B

Before

Width:  |  Height:  |  Size: 204 B

After

Width:  |  Height:  |  Size: 204 B

Before

Width:  |  Height:  |  Size: 176 B

After

Width:  |  Height:  |  Size: 176 B

Before

Width:  |  Height:  |  Size: 207 B

After

Width:  |  Height:  |  Size: 207 B

Before

Width:  |  Height:  |  Size: 170 B

After

Width:  |  Height:  |  Size: 170 B

Before

Width:  |  Height:  |  Size: 210 B

After

Width:  |  Height:  |  Size: 210 B

Before

Width:  |  Height:  |  Size: 278 B

After

Width:  |  Height:  |  Size: 278 B

Before

Width:  |  Height:  |  Size: 202 B

After

Width:  |  Height:  |  Size: 202 B

Before

Width:  |  Height:  |  Size: 678 B

After

Width:  |  Height:  |  Size: 678 B

Before

Width:  |  Height:  |  Size: 263 B

After

Width:  |  Height:  |  Size: 263 B

Before

Width:  |  Height:  |  Size: 209 B

After

Width:  |  Height:  |  Size: 209 B

Before

Width:  |  Height:  |  Size: 492 B

After

Width:  |  Height:  |  Size: 492 B

Before

Width:  |  Height:  |  Size: 205 B

After

Width:  |  Height:  |  Size: 205 B

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Before

Width:  |  Height:  |  Size: 736 B

After

Width:  |  Height:  |  Size: 736 B

Before

Width:  |  Height:  |  Size: 273 B

After

Width:  |  Height:  |  Size: 273 B

@@ -1,18 +1,18 @@
import moment from 'moment';
import XRegExp from 'xregexp';
import Config, { type MultiLang } from './config';
import Config, { type MultiLang } from '../../config/site';
const escape = (str: string): string => {
const escape: (str: string) => string = (str) => {
return encodeURIComponent(str).replace(/[!'()*]/g, (c) => {
return '%' + c.charCodeAt(0).toString(16);
});
};
const unescape = (str: string): string => {
const unescape: (str: string) => string = (str) => {
return decodeURIComponent(str);
};
const htmlspecialchars = (str: string): string => {
const htmlspecialchars: (str: string) => string = (str) => {
return str.replace(/(<|>|&|'|")/g, (match) => {
switch (match) {
case '<':
@@ -30,37 +30,37 @@ const htmlspecialchars = (str: string): string => {
});
};
const camelCase = (str: string): string => {
const camelCase: (str: string) => string = (str) => {
return str.replace(/[-_](.)/g, (...matches) => {
return matches[1].toUpperCase();
});
};
const snakeCase = (str: string): string => {
const snakeCase: (str: string) => string = (str) => {
const camel = camelCase(str);
return camel.replace(/[A-Z]/g, (...matches) => {
return '_' + matches[0].charAt(0).toLowerCase();
});
};
const pascalCase = (str: string): string => {
const pascalCase: (str: string) => string = (str) => {
const camel = camelCase(str);
return camel.charAt(0).toUpperCase() + camel.slice(1);
};
const base64Encode = (str: string): string => {
const base64Encode: (str: string) => string = (str) => {
return btoa(unescape(encodeURIComponent(str)));
};
const base64Decode = (str: string): string => {
const base64Decode: (str: string) => string = (str) => {
return decodeURIComponent(escape(atob(str)));
};
const formatDate = (timestamp: number, format: string): string => {
const formatDate: (timestamp: number, format: string) => string = (timestamp, format) => {
return moment(new Date(timestamp * 1000)).format(format);
};
const ordinal = (num: number): string => {
const ordinal: (num: number) => string = (num) => {
const hundred = num % 100;
if (hundred >= 10 && hundred <= 20) {
return 'th';
@@ -70,7 +70,7 @@ const ordinal = (num: number): string => {
return ten > 0 && ten < 4 ? suffix[ten - 1] : 'th';
};
const mlang = (str: string, lang: MultiLang): string => {
const mlang: (str: string, lang: MultiLang) => string = (str, lang) => {
const mlLangs = ['en', 'ja'];
// escape brackets inside of <input type="text" value="...">
let text = str.replace(/(<input)([^>]*)(>)/gis, (whole, m1, m2, m3) => {
@@ -116,11 +116,11 @@ const mlang = (str: string, lang: MultiLang): string => {
return text;
};
const siteTitle = (lang: MultiLang): string => {
const siteTitle: (lang: MultiLang) => string = (lang) => {
return mlang(Config.SITE_TITLE, lang);
};
const siteSlogan = (lang: MultiLang): string => {
const siteSlogan: (lang: MultiLang) => string = (lang) => {
return mlang(Config.SITE_SLOGAN, lang);
};
+29
View File
@@ -0,0 +1,29 @@
import type React from 'react';
import BrainExplorer from '../modules/brainexplorer/routes';
import Credits from '../modules/credits/routes';
import NimgDocs from '../modules/nimgdocs/routes';
import Nimgsearch from '../modules/nimgsearch/routes';
import XnpNimgCenter from '../modules/xnpnimgcenter/routes';
import Xoonips from '../modules/xoonips/routes';
import type { MultiLang } from './site';
export const MODULES_BASE_PATH = 'modules';
export interface ModuleProps {
lang: MultiLang;
path: string;
}
export interface ModuleRegistration {
path: string;
component: React.FC<ModuleProps>;
}
export const MODULES: ModuleRegistration[] = [
{ path: 'credits', component: Credits },
{ path: 'xoonips', component: Xoonips },
{ path: 'nimgdocs', component: NimgDocs },
{ path: 'nimgsearch', component: Nimgsearch },
{ path: 'xnpnimgcenter', component: XnpNimgCenter },
{ path: 'brainexplorer', component: BrainExplorer },
];
-47
View File
@@ -1,47 +0,0 @@
import type React from 'react';
import { Navigate, Route, Routes, useLocation } from 'react-router-dom';
import PageNotFound from '../common/lib/PageNotFound';
import type { MultiLang } from '../config';
import CreditsIndex from './CreditsIndex';
import CreditsPage from './CreditsPage';
interface Props {
lang: MultiLang;
}
const CreditsTop: React.FC<Props> = (props: Props) => {
const { lang } = props;
const location = useLocation();
const params = new URLSearchParams(location.search);
const paramId = params.get('id');
if (null === paramId) {
return <CreditsIndex lang={lang} />;
}
if (/^[1-9][0-9]*$/.test(paramId)) {
const id = parseInt(paramId, 10);
return <CreditsPage lang={lang} id={id} />;
}
return <PageNotFound lang={lang} />;
};
const CreditsRedirectToTop: React.FC = () => {
const location = useLocation();
const url = location.pathname + 'index.php' + location.search + location.hash;
return <Navigate to={url} />;
};
const Credits: React.FC<Props> = (props: Props) => {
const { lang } = props;
return (
<>
<Routes>
<Route path="" element={<CreditsRedirectToTop />} />
<Route path="index.php" element={<CreditsTop lang={lang} />} />
<Route path="aboutus.php" element={<CreditsPage lang={lang} id={0} />} />
<Route path="*" element={<PageNotFound lang={lang} />} />
</Routes>
</>
);
};
export default Credits;
-60
View File
@@ -1,60 +0,0 @@
import type React from 'react';
import { useEffect, useState } from 'react';
import { Helmet } from 'react-helmet-async';
import { Link } from 'react-router-dom';
import Loading from '../common/lib/Loading';
import NoticeSiteHasBeenArchived from '../common/lib/NoticeSiteHasBeenArchived';
import PageNotFound from '../common/lib/PageNotFound';
import type { MultiLang } from '../config';
import Functions from '../functions';
import CreditsUtils, { type CreditsIndexData } from './lib/CreditsUtils';
interface Props {
lang: MultiLang;
}
const CreditsIndex: React.FC<Props> = (props: Props) => {
const { lang } = props;
const [loading, setLoading] = useState<boolean>(true);
const [index, setIndex] = useState<CreditsIndexData | null>(null);
useEffect(() => {
const updatePage = async () => {
const index = await CreditsUtils.getIndex();
setLoading(false);
setIndex(index);
};
updatePage();
}, [lang]);
if (loading) {
return <Loading />;
}
if (null === index) {
return <PageNotFound lang={lang} />;
}
const mtitle = Functions.mlang(index.name, lang);
return (
<>
<Helmet>
<title>
{mtitle} - {Functions.siteTitle(lang)}
</title>
</Helmet>
<h3>{mtitle}</h3>
<NoticeSiteHasBeenArchived lang={lang} />
<ul>
{index.pages.map((page) => {
const title = Functions.mlang(page.title, lang);
const url = CreditsUtils.getPageUrl(page.id);
return (
<li key={page.id}>
<Link to={url}>{title}</Link>
</li>
);
})}
</ul>
</>
);
};
export default CreditsIndex;
-63
View File
@@ -1,63 +0,0 @@
import type React from 'react';
import { useEffect, useState } from 'react';
import { Helmet } from 'react-helmet-async';
import Loading from '../common/lib/Loading';
import NoticeSiteHasBeenArchived from '../common/lib/NoticeSiteHasBeenArchived';
import PageNotFound from '../common/lib/PageNotFound';
import XoopsCode from '../common/lib/XoopsCode';
import type { MultiLang } from '../config';
import Functions from '../functions';
import CreditsUtils, { type CreditsIndexData, type CreditsPageDetailData } from './lib/CreditsUtils';
interface Props {
lang: MultiLang;
id: number;
}
const CreditsPage: React.FC<Props> = (props: Props) => {
const { lang, id } = props;
const [loading, setLoading] = useState<boolean>(true);
const [index, setIndex] = useState<CreditsIndexData | null>(null);
const [page, setPage] = useState<CreditsPageDetailData | null>(null);
useEffect(() => {
const updatePage = async () => {
const index = await CreditsUtils.getIndex();
const page = await CreditsUtils.getPage(id);
setLoading(false);
setIndex(index);
setPage(page);
};
updatePage();
}, [id]);
if (loading) {
return <Loading />;
}
if (page === null || index === null) {
return <PageNotFound lang={lang} />;
}
const mtitle = Functions.mlang(index.name, lang);
const title = Functions.mlang(page.title, lang);
const lastupdate = page.lastupdate === 0 ? '' : Functions.formatDate(page.lastupdate, 'MMMM Do, YYYY');
return (
<>
<Helmet>
<title>
{title} - {mtitle} - {Functions.siteTitle(lang)}
</title>
</Helmet>
<h3>{title}</h3>
<NoticeSiteHasBeenArchived lang={lang} />
{'' !== lastupdate && (
<div style={{ textAlign: 'right' }}>
{Functions.mlang('[en]Last Update[/en][ja]最終更新日[/ja]', lang)} : {lastupdate}
</div>
)}
<hr />
<XoopsCode lang={lang} text={page.content} dohtml={true} />
</>
);
};
export default CreditsPage;
-48
View File
@@ -1,48 +0,0 @@
import type React from 'react';
import { useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import Loading from '../../common/lib/Loading';
import PageNotFound from '../../common/lib/PageNotFound';
import type { MultiLang } from '../../config';
import Functions from '../../functions';
import CreditsUtils, { type CreditsMenuData } from '../lib/CreditsUtils';
interface Props {
lang: MultiLang;
}
const CreditsMenu: React.FC<Props> = (props: Props) => {
const { lang } = props;
const [loading, setLoading] = useState<boolean>(true);
const [menu, setMenu] = useState<CreditsMenuData[] | null>(null);
useEffect(() => {
const updatePage = async () => {
const menu = await CreditsUtils.getMenu();
setLoading(false);
setMenu(menu);
};
updatePage();
}, [lang]);
if (loading) {
return <Loading />;
}
if (menu === null || menu.length === 0) {
return <PageNotFound lang={lang} />;
}
const links = menu.map((item, idx) => {
const title = Functions.mlang(item.title, lang);
const style = idx === 0 ? 'menuTop' : 'menuMain';
return (
<li key={idx}>
<Link className={style} to={item.link}>
{title}
</Link>
</li>
);
});
return <ul className="mainmenu">{links}</ul>;
};
export default CreditsMenu;
@@ -1,17 +1,12 @@
import type React from 'react';
import { useLocation } from 'react-router-dom';
import { HashLink } from 'react-router-hash-link';
import { type MultiLang } from '../config';
import imageBannerNiu from './assets/images/banner-niu.png';
import imageBannerRiken from './assets/images/banner-riken.png';
import imageBannerRikenCbs from './assets/images/banner-riken-cbs.png';
import imageBannerXoonips from './assets/images/banner-xoonips.png';
import imageBannerNiu from './images/banner-niu.png';
import imageBannerRiken from './images/banner-riken.png';
import imageBannerRikenCbs from './images/banner-riken-cbs.png';
import imageBannerXoonips from './images/banner-xoonips.png';
interface FooterProps {
lang: MultiLang;
}
const Footer: React.FC<FooterProps> = () => {
const Footer: React.FC = () => {
const location = useLocation();
return (
<footer id="footer">
@@ -1,8 +1,8 @@
import type React from 'react';
import { Link } from 'react-router-dom';
import LangFlag from '../common/lib/LangFlag';
import Config, { type MultiLang } from '../config';
import imageJnode from './assets/images/jnode.png';
import LangFlag from '@/common/components/LangFlag';
import Config, { type MultiLang } from '@/config/site';
import imageJnode from './images/jnode.png';
interface HeaderProps {
lang: MultiLang;
+38 -39
View File
@@ -1,32 +1,30 @@
import type React from 'react';
import { Outlet, Route, Routes } from 'react-router-dom';
import BrainExplorerIndex from '../brainexplorer/BrainExplorer';
import XoopsPathRedirect from '../common/XoopsPathRedirect';
import type { MultiLang } from '../config';
import CreditsMenu from '../credits/blocks/CreditsMenu';
import Credits from '../credits/Credits';
import NimgcenterUtilities from '../nimgcenter/NimgenterUtilities';
import Nimgdocs from '../nimgdocs/Nimgdocs';
import Nimgsearch from '../nimgsearch/Nimgsearch';
import IndexTree from '../xoonips/blocks/IndexTree';
import Ranking from '../xoonips/blocks/Rankings';
import RecentContents from '../xoonips/blocks/RecentContents';
import Search2 from '../xoonips/blocks/Search';
import Xoonips from '../xoonips/Xoonips';
import BulletinBoard from './blocks/BulletinBoard';
import HowToUseLinks from './blocks/HowToUseLinks';
import HowToUseVideo from './blocks/HowToUseVideo';
import { MODULES, MODULES_BASE_PATH } from '@/config/modules';
import type { MultiLang } from '@/config/site';
import CreditsMenu from '../modules/credits/components/blocks/CreditsMenu';
import BulletinBoard from '../modules/nimgdocs/components/blocks/BulletinBoard';
import HowToUseLinks from '../modules/nimgdocs/components/blocks/HowToUseLinks';
import HowToUseVideo from '../modules/nimgdocs/components/blocks/HowToUseVideo';
import IndexTree from '../modules/xoonips/components/blocks/IndexTree';
import Ranking from '../modules/xoonips/components/blocks/Rankings';
import RecentContents from '../modules/xoonips/components/blocks/RecentContents';
import Search2 from '../modules/xoonips/components/blocks/SearchForm';
import XoopsPathRedirect from '../router/XoopsPathRedirect';
import Information from './blocks/Information';
import Questionnaire from './blocks/Questionnaire';
import RecentStatus from './blocks/RecentStatus';
import Footer from './Footer';
import Header from './Header';
const CREDITS_PATH = `/${MODULES_BASE_PATH}/${MODULES.find((m) => m.path === 'credits')?.path}`;
const XOONIPS_PATH = `/${MODULES_BASE_PATH}/${MODULES.find((m) => m.path === 'xoonips')?.path}`;
interface Props {
lang: MultiLang;
}
const MainContent: React.FC<Props> = () => {
const MainContent: React.FC = () => {
return (
<div id="main">
<div className="mainContent">
@@ -36,19 +34,20 @@ const MainContent: React.FC<Props> = () => {
);
};
const CenterColumn: React.FC<Props> = (props: Props) => {
const CenterColumn: React.FC<Props> = (props) => {
const { lang } = props;
return (
<div id="centercolumn">
<Outlet />
<Routes>
<Route path="/*" element={<MainContent lang={lang} />}>
<Route path="modules/credits/*" element={<Credits lang={lang} />} />
<Route path="modules/xoonips/*" element={<Xoonips lang={lang} />} />
<Route path="modules/nimgdocs/*" element={<Nimgdocs lang={lang} />} />
<Route path="modules/nimgsearch/*" element={<Nimgsearch lang={lang} />} />
<Route path="modules/xnpnimgcenter/utilities/*" element={<NimgcenterUtilities lang={lang} />} />
<Route path="modules/brainexplorer/*" element={<BrainExplorerIndex lang={lang} />} />
<Route path="/*" element={<MainContent />}>
{MODULES.map((module) => (
<Route
key={module.path}
path={`${MODULES_BASE_PATH}/${module.path}/*`}
element={<module.component lang={lang} path={`/${MODULES_BASE_PATH}/${module.path}`} />}
/>
))}
<Route path="*" element={<XoopsPathRedirect lang={lang} />} />
</Route>
</Routes>
@@ -56,15 +55,15 @@ const CenterColumn: React.FC<Props> = (props: Props) => {
);
};
const CenterColumnBlock: React.FC<Props> = (props: Props) => {
const CenterColumnBlock: React.FC<Props> = (props) => {
const { lang } = props;
return (
<>
<div id="centerCcolumn">
<Information lang={lang} />
<BulletinBoard lang={lang} />
<HowToUseVideo lang={lang} />
<HowToUseLinks lang={lang} />
<BulletinBoard lang={lang} path={`/${MODULES_BASE_PATH}/nimgdocs`} />
<HowToUseVideo lang={lang} path={`/${MODULES_BASE_PATH}/nimgdocs`} />
<HowToUseLinks lang={lang} path={`/${MODULES_BASE_PATH}/nimgdocs`} />
<Questionnaire lang={lang} />
<RecentStatus lang={lang} />
</div>
@@ -73,7 +72,7 @@ const CenterColumnBlock: React.FC<Props> = (props: Props) => {
<div className="block">
<div className="blockTitle">XooNIps Ranking</div>
<div className="blockContent">
<Ranking lang={lang} />
<Ranking lang={lang} path={XOONIPS_PATH} />
</div>
</div>
</div>
@@ -81,7 +80,7 @@ const CenterColumnBlock: React.FC<Props> = (props: Props) => {
<div className="block">
<div className="blockTitle">XooNIps Update</div>
<div className="blockContent">
<RecentContents lang={lang} />
<RecentContents lang={lang} path={XOONIPS_PATH} />
</div>
</div>
</div>
@@ -90,7 +89,7 @@ const CenterColumnBlock: React.FC<Props> = (props: Props) => {
);
};
const LeftColumn: React.FC<Props> = (props: Props) => {
const LeftColumn: React.FC<Props> = (props) => {
const { lang } = props;
return (
<div id="leftcolumn">
@@ -98,32 +97,32 @@ const LeftColumn: React.FC<Props> = (props: Props) => {
<div className="block">
<div className="blockTitle">Index Tree</div>
<div className="blockContent">
<IndexTree lang={lang} />
<IndexTree lang={lang} path={XOONIPS_PATH} />
</div>
</div>
<div className="block">
<div className="blockTitle">Site Information</div>
<div className="blockContent">
<CreditsMenu lang={lang} />
<CreditsMenu lang={lang} path={CREDITS_PATH} />
</div>
</div>
</div>
);
};
const XoopsSearchBlock: React.FC<Props> = (props: Props) => {
const XoopsSearchBlock: React.FC<Props> = (props) => {
const { lang } = props;
return (
<div className="block">
<div className="blockTitle">Item Search</div>
<div className="blockContent">
<Search2 lang={lang} />
<Search2 lang={lang} path={XOONIPS_PATH} />
</div>
</div>
);
};
const Page: React.FC<Props> = (props: Props) => {
const Page: React.FC<Props> = (props) => {
const { lang } = props;
return (
<div id="page">
@@ -136,11 +135,11 @@ const Page: React.FC<Props> = (props: Props) => {
</Routes>
<Routes>
<Route path="/*" element={<LeftColumn lang={lang} />}>
<Route path="modules/xoonips/*" element={<XoopsSearchBlock lang={lang} />} />
<Route path={`${MODULES_BASE_PATH}/xoonips/*`} element={<XoopsSearchBlock lang={lang} />} />
</Route>
</Routes>
</div>
<Footer lang={lang} />
<Footer />
</div>
);
};

Before

Width:  |  Height:  |  Size: 569 B

After

Width:  |  Height:  |  Size: 569 B

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Before

Width:  |  Height:  |  Size: 633 B

After

Width:  |  Height:  |  Size: 633 B

Before

Width:  |  Height:  |  Size: 98 B

After

Width:  |  Height:  |  Size: 98 B

Before

Width:  |  Height:  |  Size: 269 B

After

Width:  |  Height:  |  Size: 269 B

Before

Width:  |  Height:  |  Size: 310 B

After

Width:  |  Height:  |  Size: 310 B

Before

Width:  |  Height:  |  Size: 187 B

After

Width:  |  Height:  |  Size: 187 B

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Before

Width:  |  Height:  |  Size: 98 B

After

Width:  |  Height:  |  Size: 98 B

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Before

Width:  |  Height:  |  Size: 167 B

After

Width:  |  Height:  |  Size: 167 B

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

@@ -395,3 +395,11 @@ tr.odd > td,
background: url(images/h2_background.png);
padding: 5px;
}
.readme,
.rights {
background-color: #ffffff;
width: 100%;
max-height: 200px;
overflow: auto;
}
@@ -1,14 +1,14 @@
import type React from 'react';
import NoticeSiteHasBeenArchived from '../../common/lib/NoticeSiteHasBeenArchived';
import XoopsCode from '../../common/lib/XoopsCode';
import type { MultiLang } from '../../config';
import Functions from '../../functions';
import NoticeBanner from '@/common/components/NoticeBanner';
import XoopsCode from '@/common/components/XoopsCode';
import Functions from '@/common/lib/functions';
import type { MultiLang } from '@/config/site';
interface Props {
lang: MultiLang;
}
const Information: React.FC<Props> = (props: Props) => {
const Information: React.FC<Props> = (props) => {
const { lang } = props;
const title = '[en]Information[/en][ja]お知らせ[/ja]';
const content = {
@@ -19,7 +19,7 @@ const Information: React.FC<Props> = (props: Props) => {
<div className="block">
<div className="blockTitle">{Functions.mlang(title, lang)}</div>
<div className="blockContent">
<NoticeSiteHasBeenArchived lang={lang} />
<NoticeBanner lang={lang} />
<XoopsCode lang={lang} text={content[lang]} dohtml={true} />
</div>
</div>
@@ -1,12 +1,12 @@
import type React from 'react';
import type { MultiLang } from '../../config';
import Functions from '../../functions';
import Functions from '@/common/lib/functions';
import type { MultiLang } from '@/config/site';
interface Props {
lang: MultiLang;
}
const Questionnaire: React.FC<Props> = (props: Props) => {
const Questionnaire: React.FC<Props> = (props) => {
const { lang } = props;
const title = '[en]Questionnaire and Contact address[/en][ja]NIMG-PFの使い方[/ja]';
return (
@@ -1,12 +1,12 @@
import type React from 'react';
import type { MultiLang } from '../../config';
import Functions from '../../functions';
import Functions from '@/common/lib/functions';
import type { MultiLang } from '@/config/site';
interface Props {
lang: MultiLang;
}
const RecentStatus: React.FC<Props> = (props: Props) => {
const RecentStatus: React.FC<Props> = (props) => {
const { lang } = props;
const title = '[en]NIMG-PF recent status[/en][ja]NIMG-PF更新情報[/ja]';
return (
Binary file not shown.

After

Width:  |  Height:  |  Size: 569 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 633 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Some files were not shown because too many files have changed in this diff Show More