diff --git a/.env.local.example b/.env.local.example
index 379b4395..e3510219 100644
--- a/.env.local.example
+++ b/.env.local.example
@@ -1,5 +1,7 @@
NEXT_PUBLIC_API_URL=http://localhost:3000/graphql
-IMAGES_PROTOCOL=https
-IMAGES_HOSTNAME=plezanje.net
-IMAGES_PATHNAME=/storage/images
\ No newline at end of file
+NEXT_PUBLIC_IMAGES_PROTOCOL=http
+NEXT_PUBLIC_IMAGES_HOSTNAME=localhost
+NEXT_PUBLIC_IMAGES_PORT=4200
+NEXT_PUBLIC_IMAGES_PATHNAME=/assets/images
+NEXT_PUBLIC_IMAGES_BASEURL=$NEXT_PUBLIC_IMAGES_PROTOCOL://$NEXT_PUBLIC_IMAGES_HOSTNAME:$NEXT_PUBLIC_IMAGES_PORT$NEXT_PUBLIC_IMAGES_PATHNAME
\ No newline at end of file
diff --git a/next.config.js b/next.config.js
index be9e2fef..088c82a1 100644
--- a/next.config.js
+++ b/next.config.js
@@ -27,10 +27,10 @@ const nextConfig = {
images: {
remotePatterns: [
{
- protocol: process.env.IMAGES_PROTOCOL,
- hostname: process.env.IMAGES_HOSTNAME,
- port: "",
- pathname: `${process.env.IMAGES_PATHNAME}/**`,
+ protocol: process.env.NEXT_PUBLIC_IMAGES_PROTOCOL,
+ hostname: process.env.NEXT_PUBLIC_IMAGES_HOSTNAME,
+ port: process.env.NEXT_PUBLIC_IMAGES_PORT,
+ pathname: `${process.env.NEXT_PUBLIC_IMAGES_PATHNAME}/**`,
},
],
},
diff --git a/package-lock.json b/package-lock.json
index 0946ab92..406ab723 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1097,30 +1097,6 @@
"node": ">=6.9.0"
}
},
- "node_modules/@cspotcode/source-map-support": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
- "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
- "optional": true,
- "peer": true,
- "dependencies": {
- "@jridgewell/trace-mapping": "0.3.9"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": {
- "version": "0.3.9",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
- "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
- "optional": true,
- "peer": true,
- "dependencies": {
- "@jridgewell/resolve-uri": "^3.0.3",
- "@jridgewell/sourcemap-codec": "^1.4.10"
- }
- },
"node_modules/@dnd-kit/accessibility": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.0.tgz",
@@ -3506,6 +3482,90 @@
"@swc/helpers": "^0.4.14"
}
},
+ "node_modules/@isaacs/cliui": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
+ "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
+ "dependencies": {
+ "string-width": "^5.1.2",
+ "string-width-cjs": "npm:string-width@^4.2.0",
+ "strip-ansi": "^7.0.1",
+ "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
+ "wrap-ansi": "^8.1.0",
+ "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@isaacs/cliui/node_modules/ansi-regex": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
+ "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/@isaacs/cliui/node_modules/ansi-styles": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+ "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/@isaacs/cliui/node_modules/string-width": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+ "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+ "dependencies": {
+ "eastasianwidth": "^0.2.0",
+ "emoji-regex": "^9.2.2",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@isaacs/cliui/node_modules/strip-ansi": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+ "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+ "dependencies": {
+ "ansi-regex": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
+ "node_modules/@isaacs/cliui/node_modules/wrap-ansi": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+ "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+ "dependencies": {
+ "ansi-styles": "^6.1.0",
+ "string-width": "^5.0.1",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
@@ -3802,6 +3862,15 @@
"node": ">=10.12.0"
}
},
+ "node_modules/@pkgjs/parseargs": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
+ "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
+ "optional": true,
+ "engines": {
+ "node": ">=14"
+ }
+ },
"node_modules/@pkgr/utils": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.1.tgz",
@@ -5317,34 +5386,6 @@
"url": "https://github.com/sponsors/tannerlinsley"
}
},
- "node_modules/@tsconfig/node10": {
- "version": "1.0.9",
- "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
- "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
- "optional": true,
- "peer": true
- },
- "node_modules/@tsconfig/node12": {
- "version": "1.0.11",
- "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
- "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
- "optional": true,
- "peer": true
- },
- "node_modules/@tsconfig/node14": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
- "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
- "optional": true,
- "peer": true
- },
- "node_modules/@tsconfig/node16": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
- "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
- "optional": true,
- "peer": true
- },
"node_modules/@types/cookie": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz",
@@ -5628,7 +5669,7 @@
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
"integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
- "devOptional": true,
+ "dev": true,
"engines": {
"node": ">=0.4.0"
}
@@ -6072,11 +6113,14 @@
}
},
"node_modules/binary-extensions": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
- "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
"engines": {
"node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/bl": {
@@ -6111,11 +6155,11 @@
}
},
"node_modules/braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dependencies": {
- "fill-range": "^7.0.1"
+ "fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
@@ -6349,15 +6393,9 @@
"dev": true
},
"node_modules/chokidar": {
- "version": "3.5.3",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
- "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
- "funding": [
- {
- "type": "individual",
- "url": "https://paulmillr.com/funding/"
- }
- ],
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
@@ -6370,6 +6408,9 @@
"engines": {
"node": ">= 8.10.0"
},
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
"optionalDependencies": {
"fsevents": "~2.3.2"
}
@@ -6563,13 +6604,6 @@
}
}
},
- "node_modules/create-require": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
- "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
- "optional": true,
- "peer": true
- },
"node_modules/cross-env": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
@@ -6825,16 +6859,6 @@
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
},
- "node_modules/diff": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
- "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=0.3.1"
- }
- },
"node_modules/dir-glob": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@@ -6899,6 +6923,11 @@
"integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
"dev": true
},
+ "node_modules/eastasianwidth": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
+ },
"node_modules/electron-to-chromium": {
"version": "1.5.20",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.20.tgz",
@@ -7187,22 +7216,6 @@
"ms": "^2.1.1"
}
},
- "node_modules/eslint-import-resolver-node/node_modules/resolve": {
- "version": "1.22.8",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
- "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
- "dependencies": {
- "is-core-module": "^2.13.0",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- },
- "bin": {
- "resolve": "bin/resolve"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/eslint-import-resolver-typescript": {
"version": "3.5.5",
"resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.5.tgz",
@@ -7627,9 +7640,9 @@
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"node_modules/fast-glob": {
- "version": "3.2.12",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
- "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
+ "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
"dependencies": {
"@nodelib/fs.stat": "^2.0.2",
"@nodelib/fs.walk": "^1.2.3",
@@ -7749,9 +7762,9 @@
}
},
"node_modules/fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dependencies": {
"to-regex-range": "^5.0.1"
},
@@ -7821,6 +7834,32 @@
"is-callable": "^1.1.3"
}
},
+ "node_modules/foreground-child": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz",
+ "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==",
+ "dependencies": {
+ "cross-spawn": "^7.0.0",
+ "signal-exit": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/foreground-child/node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/fraction.js": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
@@ -7840,9 +7879,9 @@
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
},
"node_modules/fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"hasInstallScript": true,
"optional": true,
"os": [
@@ -8258,9 +8297,9 @@
}
},
"node_modules/hasown": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz",
- "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"dependencies": {
"function-bind": "^1.1.2"
},
@@ -8596,11 +8635,14 @@
}
},
"node_modules/is-core-module": {
- "version": "2.13.1",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
- "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
+ "version": "2.16.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.0.tgz",
+ "integrity": "sha512-urTSINYfAYgcbLb0yDQ6egFm6h3Mo1DcF9EkyXSRjjzdHbsulg01qhwWuXdOoUBuTkbQ80KDboXa0vFJ+BDH+g==",
"dependencies": {
- "hasown": "^2.0.0"
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -8657,7 +8699,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true,
"engines": {
"node": ">=8"
}
@@ -8999,6 +9040,20 @@
"set-function-name": "^2.0.1"
}
},
+ "node_modules/jackspeak": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
+ "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
+ "dependencies": {
+ "@isaacs/cliui": "^8.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ },
+ "optionalDependencies": {
+ "@pkgjs/parseargs": "^0.11.0"
+ }
+ },
"node_modules/jiti": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.17.1.tgz",
@@ -9129,11 +9184,14 @@
}
},
"node_modules/lilconfig": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
- "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
+ "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
"engines": {
- "node": ">=10"
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antonk52"
}
},
"node_modules/lines-and-columns": {
@@ -9308,13 +9366,6 @@
"yallist": "^3.0.2"
}
},
- "node_modules/make-error": {
- "version": "1.3.6",
- "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
- "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
- "optional": true,
- "peer": true
- },
"node_modules/map-cache": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
@@ -9355,11 +9406,11 @@
}
},
"node_modules/micromatch": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
- "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dependencies": {
- "braces": "^3.0.2",
+ "braces": "^3.0.3",
"picomatch": "^2.3.1"
},
"engines": {
@@ -9393,6 +9444,14 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/minipass": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
"node_modules/mitt": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
@@ -9919,6 +9978,11 @@
"node": ">=6"
}
},
+ "node_modules/package-json-from-dist": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
+ "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="
+ },
"node_modules/param-case": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",
@@ -10042,6 +10106,26 @@
"node": ">=0.10.0"
}
},
+ "node_modules/path-scurry": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+ "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
+ "dependencies": {
+ "lru-cache": "^10.2.0",
+ "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/path-scurry/node_modules/lru-cache": {
+ "version": "10.4.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="
+ },
"node_modules/path-type": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
@@ -10051,9 +10135,9 @@
}
},
"node_modules/picocolors": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
- "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew=="
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
},
"node_modules/picomatch": {
"version": "2.3.1",
@@ -10075,17 +10159,17 @@
}
},
"node_modules/pirates": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
- "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==",
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
+ "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
"engines": {
"node": ">= 6"
}
},
"node_modules/postcss": {
- "version": "8.4.38",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
- "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
+ "version": "8.4.49",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz",
+ "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==",
"funding": [
{
"type": "opencollective",
@@ -10102,8 +10186,8 @@
],
"dependencies": {
"nanoid": "^3.3.7",
- "picocolors": "^1.0.0",
- "source-map-js": "^1.2.0"
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
},
"engines": {
"node": "^10 || ^12 || >=14"
@@ -10144,20 +10228,26 @@
}
},
"node_modules/postcss-load-config": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz",
- "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==",
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz",
+ "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
"dependencies": {
- "lilconfig": "^2.0.5",
- "yaml": "^2.1.1"
+ "lilconfig": "^3.0.0",
+ "yaml": "^2.3.4"
},
"engines": {
"node": ">= 14"
},
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
- },
"peerDependencies": {
"postcss": ">=8.0.9",
"ts-node": ">=9.0.0"
@@ -10172,27 +10262,33 @@
}
},
"node_modules/postcss-nested": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz",
- "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==",
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz",
+ "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
"dependencies": {
- "postcss-selector-parser": "^6.0.11"
+ "postcss-selector-parser": "^6.1.1"
},
"engines": {
"node": ">=12.0"
},
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
- },
"peerDependencies": {
"postcss": "^8.2.14"
}
},
"node_modules/postcss-selector-parser": {
- "version": "6.0.13",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz",
- "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==",
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
+ "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
"dependencies": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
@@ -10577,11 +10673,11 @@
"dev": true
},
"node_modules/resolve": {
- "version": "1.22.2",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
- "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==",
+ "version": "1.22.9",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.9.tgz",
+ "integrity": "sha512-QxrmX1DzraFIi9PxdG5VkRfRwIgjwyud+z/iBwfRRrVmHc+P9Q7u2lSSpQ6bjr2gy5lrqIiU9vb6iAeGf2400A==",
"dependencies": {
- "is-core-module": "^2.11.0",
+ "is-core-module": "^2.16.0",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
},
@@ -10992,9 +11088,9 @@
}
},
"node_modules/source-map-js": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
- "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"engines": {
"node": ">=0.10.0"
}
@@ -11046,7 +11142,6 @@
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@@ -11056,11 +11151,29 @@
"node": ">=8"
}
},
+ "node_modules/string-width-cjs": {
+ "name": "string-width",
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-width-cjs/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+ },
"node_modules/string-width/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"node_modules/string.prototype.matchall": {
"version": "4.0.10",
@@ -11134,6 +11247,18 @@
"node": ">=8"
}
},
+ "node_modules/strip-ansi-cjs": {
+ "name": "strip-ansi",
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/strip-bom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
@@ -11187,13 +11312,13 @@
}
},
"node_modules/sucrase": {
- "version": "3.32.0",
- "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz",
- "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==",
+ "version": "3.35.0",
+ "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
+ "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.2",
"commander": "^4.0.0",
- "glob": "7.1.6",
+ "glob": "^10.3.10",
"lines-and-columns": "^1.1.6",
"mz": "^2.7.0",
"pirates": "^4.0.1",
@@ -11204,23 +11329,45 @@
"sucrase-node": "bin/sucrase-node"
},
"engines": {
- "node": ">=8"
+ "node": ">=16 || 14 >=14.17"
}
},
- "node_modules/sucrase/node_modules/glob": {
- "version": "7.1.6",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
- "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "node_modules/sucrase/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/sucrase/node_modules/glob": {
+ "version": "10.4.5",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
+ "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
+ "dependencies": {
+ "foreground-child": "^3.1.0",
+ "jackspeak": "^3.1.2",
+ "minimatch": "^9.0.4",
+ "minipass": "^7.1.2",
+ "package-json-from-dist": "^1.0.0",
+ "path-scurry": "^1.11.1"
+ },
+ "bin": {
+ "glob": "dist/esm/bin.mjs"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/sucrase/node_modules/minimatch": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
},
"engines": {
- "node": "*"
+ "node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
@@ -11278,33 +11425,32 @@
"integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="
},
"node_modules/tailwindcss": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz",
- "integrity": "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==",
+ "version": "3.4.16",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.16.tgz",
+ "integrity": "sha512-TI4Cyx7gDiZ6r44ewaJmt0o6BrMCT5aK5e0rmJ/G9Xq3w7CX/5VXl/zIPEJZFUK5VEqwByyhqNPycPlvcK4ZNw==",
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
"arg": "^5.0.2",
- "chokidar": "^3.5.3",
+ "chokidar": "^3.6.0",
"didyoumean": "^1.2.2",
"dlv": "^1.1.3",
- "fast-glob": "^3.2.12",
+ "fast-glob": "^3.3.2",
"glob-parent": "^6.0.2",
"is-glob": "^4.0.3",
- "jiti": "^1.18.2",
- "lilconfig": "^2.1.0",
- "micromatch": "^4.0.5",
+ "jiti": "^1.21.6",
+ "lilconfig": "^3.1.3",
+ "micromatch": "^4.0.8",
"normalize-path": "^3.0.0",
"object-hash": "^3.0.0",
- "picocolors": "^1.0.0",
- "postcss": "^8.4.23",
+ "picocolors": "^1.1.1",
+ "postcss": "^8.4.47",
"postcss-import": "^15.1.0",
"postcss-js": "^4.0.1",
- "postcss-load-config": "^4.0.1",
- "postcss-nested": "^6.0.1",
- "postcss-selector-parser": "^6.0.11",
- "postcss-value-parser": "^4.2.0",
- "resolve": "^1.22.2",
- "sucrase": "^3.32.0"
+ "postcss-load-config": "^4.0.2",
+ "postcss-nested": "^6.2.0",
+ "postcss-selector-parser": "^6.1.2",
+ "resolve": "^1.22.8",
+ "sucrase": "^3.35.0"
},
"bin": {
"tailwind": "lib/cli.js",
@@ -11326,9 +11472,9 @@
}
},
"node_modules/tailwindcss/node_modules/jiti": {
- "version": "1.18.2",
- "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz",
- "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==",
+ "version": "1.21.6",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz",
+ "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==",
"bin": {
"jiti": "bin/jiti.js"
}
@@ -11449,57 +11595,6 @@
"integrity": "sha512-PGcnJoTBnVGy6yYNFxWVNkdcAuAMstvutN9MgDJIV6L0oG8fB+ZNNy1T+wJzah8RPGor1mZuPQkVfXNDpy9eHA==",
"dev": true
},
- "node_modules/ts-node": {
- "version": "10.9.1",
- "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
- "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
- "optional": true,
- "peer": true,
- "dependencies": {
- "@cspotcode/source-map-support": "^0.8.0",
- "@tsconfig/node10": "^1.0.7",
- "@tsconfig/node12": "^1.0.7",
- "@tsconfig/node14": "^1.0.0",
- "@tsconfig/node16": "^1.0.2",
- "acorn": "^8.4.1",
- "acorn-walk": "^8.1.1",
- "arg": "^4.1.0",
- "create-require": "^1.1.0",
- "diff": "^4.0.1",
- "make-error": "^1.1.1",
- "v8-compile-cache-lib": "^3.0.1",
- "yn": "3.1.1"
- },
- "bin": {
- "ts-node": "dist/bin.js",
- "ts-node-cwd": "dist/bin-cwd.js",
- "ts-node-esm": "dist/bin-esm.js",
- "ts-node-script": "dist/bin-script.js",
- "ts-node-transpile-only": "dist/bin-transpile.js",
- "ts-script": "dist/bin-script-deprecated.js"
- },
- "peerDependencies": {
- "@swc/core": ">=1.2.50",
- "@swc/wasm": ">=1.2.50",
- "@types/node": "*",
- "typescript": ">=2.7"
- },
- "peerDependenciesMeta": {
- "@swc/core": {
- "optional": true
- },
- "@swc/wasm": {
- "optional": true
- }
- }
- },
- "node_modules/ts-node/node_modules/arg": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
- "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
- "optional": true,
- "peer": true
- },
"node_modules/tsconfig-paths": {
"version": "3.14.2",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz",
@@ -11808,13 +11903,6 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
- "node_modules/v8-compile-cache-lib": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
- "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
- "optional": true,
- "peer": true
- },
"node_modules/value-or-promise": {
"version": "1.0.12",
"resolved": "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.12.tgz",
@@ -12046,6 +12134,23 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
+ "node_modules/wrap-ansi-cjs": {
+ "name": "wrap-ansi",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
@@ -12131,16 +12236,6 @@
"node": ">=12"
}
},
- "node_modules/yn": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
- "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
@@ -12889,29 +12984,6 @@
"to-fast-properties": "^2.0.0"
}
},
- "@cspotcode/source-map-support": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
- "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
- "optional": true,
- "peer": true,
- "requires": {
- "@jridgewell/trace-mapping": "0.3.9"
- },
- "dependencies": {
- "@jridgewell/trace-mapping": {
- "version": "0.3.9",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
- "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
- "optional": true,
- "peer": true,
- "requires": {
- "@jridgewell/resolve-uri": "^3.0.3",
- "@jridgewell/sourcemap-codec": "^1.4.10"
- }
- }
- }
- },
"@dnd-kit/accessibility": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.0.tgz",
@@ -14697,6 +14769,59 @@
"@swc/helpers": "^0.4.14"
}
},
+ "@isaacs/cliui": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
+ "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
+ "requires": {
+ "string-width": "^5.1.2",
+ "string-width-cjs": "npm:string-width@^4.2.0",
+ "strip-ansi": "^7.0.1",
+ "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
+ "wrap-ansi": "^8.1.0",
+ "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
+ "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="
+ },
+ "ansi-styles": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+ "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="
+ },
+ "string-width": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+ "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+ "requires": {
+ "eastasianwidth": "^0.2.0",
+ "emoji-regex": "^9.2.2",
+ "strip-ansi": "^7.0.1"
+ }
+ },
+ "strip-ansi": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+ "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+ "requires": {
+ "ansi-regex": "^6.0.1"
+ }
+ },
+ "wrap-ansi": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+ "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+ "requires": {
+ "ansi-styles": "^6.1.0",
+ "string-width": "^5.0.1",
+ "strip-ansi": "^7.0.1"
+ }
+ }
+ }
+ },
"@jridgewell/gen-mapping": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
@@ -14884,6 +15009,12 @@
"webcrypto-core": "^1.7.7"
}
},
+ "@pkgjs/parseargs": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
+ "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
+ "optional": true
+ },
"@pkgr/utils": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.1.tgz",
@@ -16102,34 +16233,6 @@
"resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.5.0.tgz",
"integrity": "sha512-KnPRCkQTyqhanNC0K63GBG3wA8I+D1fQuVnAvcBF8f13akOKeQp1gSbu6f77zCxhEk727iV5oQnbHLYzHrECLg=="
},
- "@tsconfig/node10": {
- "version": "1.0.9",
- "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
- "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
- "optional": true,
- "peer": true
- },
- "@tsconfig/node12": {
- "version": "1.0.11",
- "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
- "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
- "optional": true,
- "peer": true
- },
- "@tsconfig/node14": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
- "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
- "optional": true,
- "peer": true
- },
- "@tsconfig/node16": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
- "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
- "optional": true,
- "peer": true
- },
"@types/cookie": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz",
@@ -16345,7 +16448,7 @@
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
"integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
- "devOptional": true
+ "dev": true
},
"agent-base": {
"version": "7.1.1",
@@ -16655,9 +16758,9 @@
"integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg=="
},
"binary-extensions": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
- "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA=="
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="
},
"bl": {
"version": "4.1.0",
@@ -16688,11 +16791,11 @@
}
},
"braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"requires": {
- "fill-range": "^7.0.1"
+ "fill-range": "^7.1.1"
}
},
"browserslist": {
@@ -16848,9 +16951,9 @@
"dev": true
},
"chokidar": {
- "version": "3.5.3",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
- "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
"requires": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
@@ -16995,13 +17098,6 @@
"path-type": "^4.0.0"
}
},
- "create-require": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
- "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
- "optional": true,
- "peer": true
- },
"cross-env": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
@@ -17186,13 +17282,6 @@
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
},
- "diff": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
- "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
- "optional": true,
- "peer": true
- },
"dir-glob": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@@ -17242,6 +17331,11 @@
"integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
"dev": true
},
+ "eastasianwidth": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
+ },
"electron-to-chromium": {
"version": "1.5.20",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.20.tgz",
@@ -17501,16 +17595,6 @@
"requires": {
"ms": "^2.1.1"
}
- },
- "resolve": {
- "version": "1.22.8",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
- "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
- "requires": {
- "is-core-module": "^2.13.0",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- }
}
}
},
@@ -17790,9 +17874,9 @@
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"fast-glob": {
- "version": "3.2.12",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
- "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
+ "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
"requires": {
"@nodelib/fs.stat": "^2.0.2",
"@nodelib/fs.walk": "^1.2.3",
@@ -17901,9 +17985,9 @@
}
},
"fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"requires": {
"to-regex-range": "^5.0.1"
}
@@ -17956,6 +18040,22 @@
"is-callable": "^1.1.3"
}
},
+ "foreground-child": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz",
+ "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==",
+ "requires": {
+ "cross-spawn": "^7.0.0",
+ "signal-exit": "^4.0.1"
+ },
+ "dependencies": {
+ "signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="
+ }
+ }
+ },
"fraction.js": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
@@ -17968,9 +18068,9 @@
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
},
"fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"optional": true
},
"function-bind": {
@@ -18241,9 +18341,9 @@
}
},
"hasown": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz",
- "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"requires": {
"function-bind": "^1.1.2"
}
@@ -18483,11 +18583,11 @@
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="
},
"is-core-module": {
- "version": "2.13.1",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
- "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
+ "version": "2.16.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.0.tgz",
+ "integrity": "sha512-urTSINYfAYgcbLb0yDQ6egFm6h3Mo1DcF9EkyXSRjjzdHbsulg01qhwWuXdOoUBuTkbQ80KDboXa0vFJ+BDH+g==",
"requires": {
- "hasown": "^2.0.0"
+ "hasown": "^2.0.2"
}
},
"is-date-object": {
@@ -18519,8 +18619,7 @@
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
},
"is-generator-function": {
"version": "1.0.10",
@@ -18745,6 +18844,15 @@
"set-function-name": "^2.0.1"
}
},
+ "jackspeak": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
+ "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
+ "requires": {
+ "@isaacs/cliui": "^8.0.2",
+ "@pkgjs/parseargs": "^0.11.0"
+ }
+ },
"jiti": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.17.1.tgz",
@@ -18845,9 +18953,9 @@
}
},
"lilconfig": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
- "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ=="
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
+ "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="
},
"lines-and-columns": {
"version": "1.2.4",
@@ -18982,13 +19090,6 @@
"yallist": "^3.0.2"
}
},
- "make-error": {
- "version": "1.3.6",
- "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
- "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
- "optional": true,
- "peer": true
- },
"map-cache": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
@@ -19013,11 +19114,11 @@
"requires": {}
},
"micromatch": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
- "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"requires": {
- "braces": "^3.0.2",
+ "braces": "^3.0.3",
"picomatch": "^2.3.1"
}
},
@@ -19039,6 +19140,11 @@
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="
},
+ "minipass": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="
+ },
"mitt": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
@@ -19393,6 +19499,11 @@
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"dev": true
},
+ "package-json-from-dist": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
+ "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="
+ },
"param-case": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",
@@ -19489,15 +19600,31 @@
"integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==",
"dev": true
},
+ "path-scurry": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+ "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
+ "requires": {
+ "lru-cache": "^10.2.0",
+ "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
+ },
+ "dependencies": {
+ "lru-cache": {
+ "version": "10.4.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="
+ }
+ }
+ },
"path-type": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="
},
"picocolors": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
- "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew=="
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
},
"picomatch": {
"version": "2.3.1",
@@ -19510,18 +19637,18 @@
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="
},
"pirates": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
- "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ=="
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
+ "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg=="
},
"postcss": {
- "version": "8.4.38",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
- "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
+ "version": "8.4.49",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz",
+ "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==",
"requires": {
"nanoid": "^3.3.7",
- "picocolors": "^1.0.0",
- "source-map-js": "^1.2.0"
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
}
},
"postcss-import": {
@@ -19543,26 +19670,26 @@
}
},
"postcss-load-config": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz",
- "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==",
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz",
+ "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==",
"requires": {
- "lilconfig": "^2.0.5",
- "yaml": "^2.1.1"
+ "lilconfig": "^3.0.0",
+ "yaml": "^2.3.4"
}
},
"postcss-nested": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz",
- "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==",
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz",
+ "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==",
"requires": {
- "postcss-selector-parser": "^6.0.11"
+ "postcss-selector-parser": "^6.1.1"
}
},
"postcss-selector-parser": {
- "version": "6.0.13",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz",
- "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==",
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
+ "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
"requires": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
@@ -19806,11 +19933,11 @@
"dev": true
},
"resolve": {
- "version": "1.22.2",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
- "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==",
+ "version": "1.22.9",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.9.tgz",
+ "integrity": "sha512-QxrmX1DzraFIi9PxdG5VkRfRwIgjwyud+z/iBwfRRrVmHc+P9Q7u2lSSpQ6bjr2gy5lrqIiU9vb6iAeGf2400A==",
"requires": {
- "is-core-module": "^2.11.0",
+ "is-core-module": "^2.16.0",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
}
@@ -20101,9 +20228,9 @@
}
},
"source-map-js": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
- "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg=="
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="
},
"sponge-case": {
"version": "1.0.1",
@@ -20146,7 +20273,6 @@
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@@ -20156,8 +20282,24 @@
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+ }
+ }
+ },
+ "string-width-cjs": {
+ "version": "npm:string-width@4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "dependencies": {
+ "emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
}
}
},
@@ -20215,6 +20357,14 @@
"ansi-regex": "^5.0.1"
}
},
+ "strip-ansi-cjs": {
+ "version": "npm:strip-ansi@6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "requires": {
+ "ansi-regex": "^5.0.1"
+ }
+ },
"strip-bom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
@@ -20239,30 +20389,46 @@
}
},
"sucrase": {
- "version": "3.32.0",
- "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz",
- "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==",
+ "version": "3.35.0",
+ "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
+ "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==",
"requires": {
"@jridgewell/gen-mapping": "^0.3.2",
"commander": "^4.0.0",
- "glob": "7.1.6",
+ "glob": "^10.3.10",
"lines-and-columns": "^1.1.6",
"mz": "^2.7.0",
"pirates": "^4.0.1",
"ts-interface-checker": "^0.1.9"
},
"dependencies": {
+ "brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "requires": {
+ "balanced-match": "^1.0.0"
+ }
+ },
"glob": {
- "version": "7.1.6",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
- "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "version": "10.4.5",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
+ "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
"requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
+ "foreground-child": "^3.1.0",
+ "jackspeak": "^3.1.2",
+ "minimatch": "^9.0.4",
+ "minipass": "^7.1.2",
+ "package-json-from-dist": "^1.0.0",
+ "path-scurry": "^1.11.1"
+ }
+ },
+ "minimatch": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "requires": {
+ "brace-expansion": "^2.0.1"
}
}
}
@@ -20304,33 +20470,32 @@
"integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="
},
"tailwindcss": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz",
- "integrity": "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==",
+ "version": "3.4.16",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.16.tgz",
+ "integrity": "sha512-TI4Cyx7gDiZ6r44ewaJmt0o6BrMCT5aK5e0rmJ/G9Xq3w7CX/5VXl/zIPEJZFUK5VEqwByyhqNPycPlvcK4ZNw==",
"requires": {
"@alloc/quick-lru": "^5.2.0",
"arg": "^5.0.2",
- "chokidar": "^3.5.3",
+ "chokidar": "^3.6.0",
"didyoumean": "^1.2.2",
"dlv": "^1.1.3",
- "fast-glob": "^3.2.12",
+ "fast-glob": "^3.3.2",
"glob-parent": "^6.0.2",
"is-glob": "^4.0.3",
- "jiti": "^1.18.2",
- "lilconfig": "^2.1.0",
- "micromatch": "^4.0.5",
+ "jiti": "^1.21.6",
+ "lilconfig": "^3.1.3",
+ "micromatch": "^4.0.8",
"normalize-path": "^3.0.0",
"object-hash": "^3.0.0",
- "picocolors": "^1.0.0",
- "postcss": "^8.4.23",
+ "picocolors": "^1.1.1",
+ "postcss": "^8.4.47",
"postcss-import": "^15.1.0",
"postcss-js": "^4.0.1",
- "postcss-load-config": "^4.0.1",
- "postcss-nested": "^6.0.1",
- "postcss-selector-parser": "^6.0.11",
- "postcss-value-parser": "^4.2.0",
- "resolve": "^1.22.2",
- "sucrase": "^3.32.0"
+ "postcss-load-config": "^4.0.2",
+ "postcss-nested": "^6.2.0",
+ "postcss-selector-parser": "^6.1.2",
+ "resolve": "^1.22.8",
+ "sucrase": "^3.35.0"
},
"dependencies": {
"glob-parent": {
@@ -20342,9 +20507,9 @@
}
},
"jiti": {
- "version": "1.18.2",
- "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz",
- "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg=="
+ "version": "1.21.6",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz",
+ "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w=="
}
}
},
@@ -20440,37 +20605,6 @@
"integrity": "sha512-PGcnJoTBnVGy6yYNFxWVNkdcAuAMstvutN9MgDJIV6L0oG8fB+ZNNy1T+wJzah8RPGor1mZuPQkVfXNDpy9eHA==",
"dev": true
},
- "ts-node": {
- "version": "10.9.1",
- "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
- "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
- "optional": true,
- "peer": true,
- "requires": {
- "@cspotcode/source-map-support": "^0.8.0",
- "@tsconfig/node10": "^1.0.7",
- "@tsconfig/node12": "^1.0.7",
- "@tsconfig/node14": "^1.0.0",
- "@tsconfig/node16": "^1.0.2",
- "acorn": "^8.4.1",
- "acorn-walk": "^8.1.1",
- "arg": "^4.1.0",
- "create-require": "^1.1.0",
- "diff": "^4.0.1",
- "make-error": "^1.1.1",
- "v8-compile-cache-lib": "^3.0.1",
- "yn": "3.1.1"
- },
- "dependencies": {
- "arg": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
- "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
- "optional": true,
- "peer": true
- }
- }
- },
"tsconfig-paths": {
"version": "3.14.2",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz",
@@ -20687,13 +20821,6 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
- "v8-compile-cache-lib": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
- "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
- "optional": true,
- "peer": true
- },
"value-or-promise": {
"version": "1.0.12",
"resolved": "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.12.tgz",
@@ -20865,6 +20992,16 @@
"strip-ansi": "^6.0.0"
}
},
+ "wrap-ansi-cjs": {
+ "version": "npm:wrap-ansi@7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
@@ -20921,13 +21058,6 @@
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
"dev": true
},
- "yn": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
- "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
- "optional": true,
- "peer": true
- },
"yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
diff --git a/src/app/[lang]/admin/crags/[cragSlug]/edit/components/crag-publish-status-card.tsx b/src/app/[lang]/admin/crags/[cragSlug]/edit/components/crag-publish-status-card.tsx
new file mode 100644
index 00000000..e2a486df
--- /dev/null
+++ b/src/app/[lang]/admin/crags/[cragSlug]/edit/components/crag-publish-status-card.tsx
@@ -0,0 +1,82 @@
+import { Crag } from "@/graphql/generated";
+import PublishStatusActions from "../../../components/publish-status-actions";
+import { genderizeVerb } from "@/lib/text-helpers";
+import getCurrentUser from "@/lib/auth/get-current-user";
+import { getBgStyle } from "@/lib/contributables-helpers";
+
+type TCragPublishStatusCard = {
+ crag: Crag;
+};
+
+async function CragPublishStatusCard({ crag }: TCragPublishStatusCard) {
+ const currentUser = await getCurrentUser();
+
+ return (
+
+
+
+ {currentUser?.roles.includes("admin") ? (
+ <>
+ {crag.publishStatus === "draft" && (
+ <>
+ Plezališče je v statusu{" "}
+ osnutek . Ko zaključiš z
+ urejanjem plezališča ter sektorjev in smeri v njem, ga objavi.
+ >
+ )}
+
+ {crag.publishStatus === "in_review" && (
+ <>
+ Plezališče je v statusu{" "}
+ v pregledu . Ko zaključiš
+ s pregledom potrdi ali zavrni objavo.
+ >
+ )}
+ >
+ ) : (
+ <>
+ {crag.publishStatus === "draft" && (
+ <>
+ Plezališče je v statusu{" "}
+ osnutek . Ko zaključiš z
+ urejanjem plezališča ter sektorjev in smeri v njem, ga pošlji
+ uredništvu v pregled in objavo.
+ >
+ )}
+
+ {crag.publishStatus === "in_review" && (
+ <>
+ Plezališče je v statusu{" "}
+ v pregledu . Prispevek bo
+ objavljen ko bo pregledan s strani uredništva.
+ >
+ )}
+ >
+ )}
+
+
+
+ {/* contributor */}
+
+ {currentUser && currentUser.id === crag.user?.id ? (
+ "Tvoj prispevek"
+ ) : (
+ <>
+
+ {genderizeVerb("Prispeval", "M")}:
+
+ {crag.user?.fullName}
+ >
+ )}
+
+
+
+
+
+
+ );
+}
+
+export default CragPublishStatusCard;
diff --git a/src/app/[lang]/edit/(crag)/[cragSlug]/components/edit-crag-form.tsx b/src/app/[lang]/admin/crags/[cragSlug]/edit/components/edit-crag-form.tsx
similarity index 86%
rename from src/app/[lang]/edit/(crag)/[cragSlug]/components/edit-crag-form.tsx
rename to src/app/[lang]/admin/crags/[cragSlug]/edit/components/edit-crag-form.tsx
index 946c06bf..d9897e2d 100644
--- a/src/app/[lang]/edit/(crag)/[cragSlug]/components/edit-crag-form.tsx
+++ b/src/app/[lang]/admin/crags/[cragSlug]/edit/components/edit-crag-form.tsx
@@ -1,5 +1,5 @@
import { Country, Crag } from "@/graphql/generated";
-import CragForm from "../../components/crag-form";
+import CragForm from "../../../components/crag-form";
type TEditCragForm = {
countriesWithAreas: Country[];
diff --git a/src/app/[lang]/edit/(crag)/[cragSlug]/lib/update-crag-action.ts b/src/app/[lang]/admin/crags/[cragSlug]/edit/lib/update-crag-action.ts
similarity index 100%
rename from src/app/[lang]/edit/(crag)/[cragSlug]/lib/update-crag-action.ts
rename to src/app/[lang]/admin/crags/[cragSlug]/edit/lib/update-crag-action.ts
diff --git a/src/app/[lang]/edit/(crag)/[cragSlug]/page.tsx b/src/app/[lang]/admin/crags/[cragSlug]/edit/page.tsx
similarity index 66%
rename from src/app/[lang]/edit/(crag)/[cragSlug]/page.tsx
rename to src/app/[lang]/admin/crags/[cragSlug]/edit/page.tsx
index 45624ee0..6daef59e 100644
--- a/src/app/[lang]/edit/(crag)/[cragSlug]/page.tsx
+++ b/src/app/[lang]/admin/crags/[cragSlug]/edit/page.tsx
@@ -2,7 +2,7 @@ import Breadcrumbs from "@/components/breadcrumbs";
import ContentHeader from "@/components/content-header";
import IconInfo from "@/components/ui/icons/info";
import IconRoutes from "@/components/ui/icons/routes";
-import TabMenu, { TTabMenuItem } from "@/components/ui/tab-menu";
+import TabMenu from "@/components/ui/tab-menu";
import {
EditCragPageCountriesDocument,
EditCragPageCragDocument,
@@ -10,6 +10,7 @@ import {
import urqlServer from "@/graphql/urql-server";
import { gql } from "urql";
import EditCragForm from "./components/edit-crag-form";
+import CragPublishStatusCard from "./components/crag-publish-status-card";
type TEditCragPageProps = {
params: { cragSlug: string };
@@ -30,21 +31,6 @@ async function EditCragPage({ params: { cragSlug } }: TEditCragPageProps) {
const crag = cragData.cragBySlug;
- const tabMenuItems: TTabMenuItem[] = [
- {
- label: "Osnovni podatki",
- link: `/edit/${cragSlug}`,
- isActive: true,
- icon: ,
- },
- {
- label: "Sektorji in smeri",
- link: `/edit/${cragSlug}/sectors`,
- isActive: false,
- icon: ,
- },
- ];
-
return (
<>
}
- tabMenu={ }
+ tabMenu={
+ ,
+ },
+ {
+ label: "Sektorji in smeri",
+ link: `/urejanje/plezalisca/${cragSlug}/sektorji`,
+ isActive: false,
+ icon: ,
+ },
+ ]}
+ />
+ }
/>
+ {crag.publishStatus !== "published" && (
+
+ )}
+
>
);
@@ -116,6 +124,26 @@ gql`
maxIntrinsicWidth
aspectRatio
}
+ images {
+ id
+ path
+ extension
+ maxIntrinsicWidth
+ aspectRatio
+ }
+ publishStatus
+ user {
+ id
+ fullName
+ }
+ sectors {
+ id
+ label
+ name
+ routes {
+ id
+ }
+ }
}
}
`;
diff --git a/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/delete-routes-dialog.tsx b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/delete-routes-dialog.tsx
new file mode 100644
index 00000000..c3adda1d
--- /dev/null
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/delete-routes-dialog.tsx
@@ -0,0 +1,61 @@
+import Dialog from "@/components/ui/dialog";
+import { Dispatch, SetStateAction, useState } from "react";
+import { useRouter } from "next/navigation";
+import { Route } from "@/graphql/generated";
+import deleteRoutesAction from "../lib/delete-routes-action";
+
+type TDeleteRoutesDialogProps = {
+ isOpen: boolean;
+ setIsOpen: Dispatch>;
+ routes: Route[];
+};
+
+function DeleteRoutesDialog({
+ isOpen,
+ setIsOpen,
+ routes,
+}: TDeleteRoutesDialogProps) {
+ const router = useRouter();
+
+ const [loading, setLoading] = useState(false);
+
+ const handleConfirm = async () => {
+ setLoading(true);
+ await deleteRoutesAction(routes.map((route) => route.id));
+ setIsOpen(false);
+ setLoading(false);
+ router.refresh();
+ };
+
+ return (
+
+ <>
+
+ Ali res želiš izbrisati{" "}
+ {routes.length == 1 ? (
+
+ smer {routes[0].name}
+
+ ) : (
+ vse označene smeri
+ )}
+ ?
+
+ >
+
+ );
+}
+
+export default DeleteRoutesDialog;
diff --git a/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/edit-routes-actions.tsx b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/edit-routes-actions.tsx
new file mode 100644
index 00000000..6f877d0a
--- /dev/null
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/edit-routes-actions.tsx
@@ -0,0 +1,236 @@
+import IconMoveRoutes from "@/components/ui/icons/move-routes";
+import { Crag, Route, Sector } from "@/graphql/generated";
+import { useRef, useState } from "react";
+import Checkbox from "@/components/ui/checkbox";
+import Button from "@/components/ui/button";
+import IconSwitchSector from "@/components/ui/icons/switch-sector";
+import IconDelete from "@/components/ui/icons/delete";
+import IconReturn from "@/components/ui/icons/return";
+import { useRouter } from "next/navigation";
+import SwitchSectorDialog from "./switch-sector-dialog";
+import useIsVisible from "@/hooks/useIsVisible";
+import MoveRoutesDialog from "./move-routes-dialog";
+import DeleteRoutesDialog from "./delete-routes-dialog";
+import IconMergeRoutes from "@/components/ui/icons/merge-routes";
+import MergeRoutesDialog from "./merge-routes-dialog";
+import ConvertToSectorsManyDialog from "../../../components/convert-to-sectors-many-dialog";
+import { canEdit } from "@/lib/contributables-helpers";
+import { useAuthContext } from "@/lib/auth/auth-context";
+
+type TEditRoutesActionsProps = {
+ crag: Crag;
+ sector: Sector;
+ checkedRoutes: Route[];
+ allSectors: Sector[];
+ allRoutes: Route[];
+ onCheckAll: () => void;
+};
+
+function EditRoutesActions({
+ allSectors,
+ sector,
+ crag,
+ checkedRoutes,
+ allRoutes,
+ onCheckAll,
+}: TEditRoutesActionsProps) {
+ const { currentUser } = useAuthContext();
+
+ const router = useRouter();
+
+ const [moveRoutesDialogIsOpen, setMoveRoutesDialogIsOpen] = useState(false);
+ const [switchSectorDialogIsOpen, setSwitchSectorDialogIsOpen] =
+ useState(false);
+ const [mergeRoutesDialogIsOpen, setMergeRoutesDialogIsOpen] = useState(false);
+ const [deleteRoutesDialogIsOpen, setDeleteRoutesDialogIsOpen] =
+ useState(false);
+ const [
+ convertToSectorsManyDialogIsOpen,
+ setConvertToSectorsManyDialogIsOpen,
+ ] = useState(false);
+
+ const dummyRef = useRef(null);
+ const sticky = !useIsVisible(dummyRef, true);
+
+ const noSectorsCrag =
+ allSectors.length === 1 && sector.name === "" && sector.label === "";
+
+ return (
+ <>
+ {/* A dummy div, for detecting when the 'stickiness' of the actions row starts (when this div dissapears from view) */}
+
+
+ {/* actions row */}
+
+
+ {/* check all */}
+ {allRoutes.length > 0 && (
+
route.publishStatus === "draft")
+ }
+ checked={
+ checkedRoutes.length > 0 &&
+ checkedRoutes.length ==
+ allRoutes.filter(
+ (route) =>
+ currentUser?.roles.includes("admin") ||
+ route.publishStatus === "draft"
+ ).length
+ }
+ indeterminate={
+ checkedRoutes.length <
+ allRoutes.filter(
+ (route) =>
+ currentUser?.roles.includes("admin") ||
+ route.publishStatus === "draft"
+ ).length && checkedRoutes.length > 0
+ }
+ onChange={onCheckAll}
+ label="Označi vse"
+ hideLabel="max-xs:sr-only"
+ />
+ )}
+
+ {checkedRoutes.length > 0 && (
+ <>
+ {/* divider */}
+
+
+ {/* change position of all checked routes */}
+ setMoveRoutesDialogIsOpen(true)}
+ >
+
+
+ Premakni
+
+
+ >
+ )}
+
+ {/* move checked routes into another sector */}
+ {checkedRoutes.length > 0 && allSectors.length > 1 && (
+ <>
+ {/* divider */}
+
+
+ setSwitchSectorDialogIsOpen(true)}
+ >
+
+
+
+ Premakni v drug sektor
+
+
+
+ >
+ )}
+
+ {/* merge two routes */}
+ {checkedRoutes.length == 2 && (
+ <>
+ {/* divider */}
+
+
+ setMergeRoutesDialogIsOpen(true)}
+ >
+
+
+ Združi
+
+
+ >
+ )}
+
+ {checkedRoutes.length > 0 && (
+ <>
+ {/* divider */}
+
+
+ {/* delete checked routes */}
+ setDeleteRoutesDialogIsOpen(true)}
+ >
+
+
+ Izbriši
+
+
+ >
+ )}
+
+
+ {/* back to crag sectors or make into crag with sectors */}
+
+ {noSectorsCrag ? (
+ setConvertToSectorsManyDialogIsOpen(true)}
+ />
+ ) : (
+
+ router.push(`/urejanje/plezalisca/${crag.slug}/sektorji`)
+ }
+ >
+
+
+ Nazaj na sektorje
+
+
+ )}
+
+
+
+
+ !checkedRoutes.find((checkedRoute) => checkedRoute.id == route.id)
+ )}
+ />
+
+ s.id != sector.id)}
+ />
+
+
+
+
+
+
+ >
+ );
+}
+
+export default EditRoutesActions;
diff --git a/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/edit-routes.tsx b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/edit-routes.tsx
new file mode 100644
index 00000000..dd2e7b1d
--- /dev/null
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/edit-routes.tsx
@@ -0,0 +1,163 @@
+"use client";
+
+import { Crag, Route, Sector } from "@/graphql/generated";
+import { Fragment, useEffect, useState } from "react";
+import RouteCard from "./route-card/route-card";
+import { useRouter } from "next/navigation";
+import {
+ DndContext,
+ DragEndEvent,
+ KeyboardSensor,
+ PointerSensor,
+ closestCenter,
+ useSensor,
+ useSensors,
+} from "@dnd-kit/core";
+import { restrictToParentElement } from "@dnd-kit/modifiers";
+import {
+ SortableContext,
+ arrayMove,
+ sortableKeyboardCoordinates,
+ verticalListSortingStrategy,
+} from "@dnd-kit/sortable";
+import updateRouteAction from "../lib/update-route-action";
+import EditRoutesActions from "./edit-routes-actions";
+import NewFirstRouteButton from "./new-first-route-button";
+import { useAuthContext } from "@/lib/auth/auth-context";
+
+type TEditRoutesProps = {
+ routes: Route[];
+ crag: Crag;
+ sector: Sector;
+ allSectors: Sector[];
+};
+
+function EditRoutes({ routes, crag, sector, allSectors }: TEditRoutesProps) {
+ const { currentUser } = useAuthContext();
+
+ const router = useRouter();
+ const [loading, setLoading] = useState(false);
+
+ const [sortedRoutes, setSortedRoutes] = useState(routes);
+ useEffect(() => {
+ setSortedRoutes(routes);
+ }, [routes]);
+
+ const [checkedRouteIds, setCheckedRouteIds] = useState([]);
+ const handleOnCheckedChange = (checked: boolean, routeId: string) => {
+ if (checked) {
+ setCheckedRouteIds([...checkedRouteIds, routeId]);
+ } else {
+ setCheckedRouteIds(checkedRouteIds.filter((rId) => rId !== routeId));
+ }
+ };
+
+ const handleCheckAll = () => {
+ if (
+ checkedRouteIds.length ===
+ sortedRoutes.filter(
+ (route) =>
+ currentUser?.roles.includes("admin") ||
+ route.publishStatus === "draft"
+ ).length
+ ) {
+ setCheckedRouteIds([]);
+ } else {
+ setCheckedRouteIds(
+ sortedRoutes
+ .filter(
+ (route) =>
+ currentUser?.roles.includes("admin") ||
+ route.publishStatus === "draft"
+ )
+ .map((route) => route.id)
+ );
+ }
+ };
+
+ const sensors = useSensors(
+ useSensor(PointerSensor),
+ useSensor(KeyboardSensor, {
+ coordinateGetter: sortableKeyboardCoordinates,
+ })
+ );
+
+ const handleDragEnd = async (event: DragEndEvent) => {
+ const { active, over } = event;
+ if (over && active.id !== over.id) {
+ setLoading(true);
+ const droppedRouteIndex = sortedRoutes.findIndex(
+ (route) => route.id === active.id
+ );
+ const targetRouteIndex = sortedRoutes.findIndex(
+ (route) => route.id === over.id
+ );
+ const newSortedRoutes = arrayMove(
+ sortedRoutes,
+ droppedRouteIndex,
+ targetRouteIndex
+ );
+ setSortedRoutes(newSortedRoutes);
+ const updatedRouteData = {
+ id: sortedRoutes[droppedRouteIndex].id,
+ position:
+ droppedRouteIndex > targetRouteIndex
+ ? sortedRoutes[targetRouteIndex].position
+ : sortedRoutes[targetRouteIndex].position + 1,
+ };
+ await updateRouteAction(updatedRouteData);
+ router.refresh();
+ setLoading(false);
+ }
+ };
+
+ return (
+
+
+ checkedRouteIds.includes(route.id)
+ )}
+ allRoutes={sortedRoutes}
+ onCheckAll={handleCheckAll}
+ />
+
+
+
+
+
+
+
+
+
+ {sortedRoutes.map((route) => (
+
+
+
+ ))}
+
+
+
+
+
+ );
+}
+
+export default EditRoutes;
diff --git a/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/merge-routes-dialog.tsx b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/merge-routes-dialog.tsx
new file mode 100644
index 00000000..8bde4733
--- /dev/null
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/merge-routes-dialog.tsx
@@ -0,0 +1,132 @@
+import Dialog from "@/components/ui/dialog";
+import { Dispatch, FormEvent, SetStateAction, useRef, useState } from "react";
+import { useRouter } from "next/navigation";
+import { Route } from "@/graphql/generated";
+import { Radio, RadioGroup } from "@/components/ui/radio-group";
+import { difficultyToGrade } from "@/lib/grade-helpers";
+import displayDate from "@/lib/display-date";
+import mergeRoutesAction from "../lib/merge-routes-action";
+
+type TMergeRoutesDialogProps = {
+ isOpen: boolean;
+ setIsOpen: Dispatch>;
+ routes: Route[];
+};
+
+function MergeRoutesDialog({
+ isOpen,
+ setIsOpen,
+ routes,
+}: TMergeRoutesDialogProps) {
+ const router = useRouter();
+ const formRef = useRef(null);
+ const [loading, setLoading] = useState(false);
+
+ const [mainRouteId, setMainRouteId] = useState("");
+ const [mainRouteError, setMainRouteError] = useState("");
+
+ const handleMainRouteChange = (mainRouteId: string) => {
+ setMainRouteError("");
+ setMainRouteId(mainRouteId);
+ };
+
+ const resetForm = () => {
+ // reset fields
+ setMainRouteId("");
+
+ // clear errors
+ setMainRouteError("");
+ };
+
+ const handleCancel = () => {
+ resetForm();
+ };
+
+ const handleConfirm = async () => {
+ formRef.current?.requestSubmit();
+ };
+
+ const handleOnSubmit = async (e: FormEvent) => {
+ e.preventDefault();
+ setLoading(true);
+
+ // Validate form
+ // - main route is required
+ if (!mainRouteId) {
+ setMainRouteError("'Glavna smer' je obvezen podatek.");
+ setLoading(false);
+ return;
+ }
+
+ // target route is 'main route'. that is, the route that will be 'kept'
+ // source route is the route to be deleted and from which related entities are transfered (votes, comments, images, ...)
+ const mergeRoutesData = {
+ sourceRouteId: mainRouteId != routes[0].id ? routes[0].id : routes[1].id,
+ targetRouteId: mainRouteId,
+ };
+
+ await mergeRoutesAction(mergeRoutesData);
+
+ resetForm();
+
+ // TODO: check for errors
+
+ setIsOpen(false);
+ setLoading(false);
+ router.refresh();
+ };
+
+ return (
+
+
+
+ );
+}
+
+export default MergeRoutesDialog;
diff --git a/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/move-routes-dialog.tsx b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/move-routes-dialog.tsx
new file mode 100644
index 00000000..1d570554
--- /dev/null
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/move-routes-dialog.tsx
@@ -0,0 +1,140 @@
+import Dialog from "@/components/ui/dialog";
+import { Dispatch, FormEvent, SetStateAction, useRef, useState } from "react";
+import { useRouter } from "next/navigation";
+import { Option, Select } from "@/components/ui/select";
+import { Route } from "@/graphql/generated";
+import updateRoutesAction from "../lib/update-routes-action";
+
+type TMoveRoutesDialogProps = {
+ isOpen: boolean;
+ setIsOpen: Dispatch>;
+ routes: Route[];
+ targetRoutes: Route[];
+};
+
+function MoveRoutesDialog({
+ isOpen,
+ setIsOpen,
+ routes,
+ targetRoutes,
+}: TMoveRoutesDialogProps) {
+ const router = useRouter();
+ const formRef = useRef(null);
+ const [loading, setLoading] = useState(false);
+
+ const [targetPosition, setTargetPosition] = useState("");
+ const [targetPositionError, setTargetPositionError] = useState("");
+
+ const resetForm = () => {
+ // reset fields
+ setTargetPosition("");
+
+ // clear errors
+ setTargetPositionError("");
+ };
+
+ const handleCancel = () => {
+ resetForm();
+ };
+
+ const handleConfirm = async () => {
+ formRef.current?.requestSubmit();
+ };
+
+ const handleOnSubmit = async (e: FormEvent) => {
+ e.preventDefault();
+ setLoading(true);
+
+ // Validate form
+ // - sector is required
+ if (!targetPosition) {
+ setTargetPositionError("Ciljna smer je obvezen podatek.");
+ setLoading(false);
+ return;
+ }
+
+ // sort routes by their current positions in reverse order (be is 'pushing' what is at current (target) position and below, so we need to reposition routes from the back)
+ const routesReversed = [...routes].sort(
+ (r1, r2) => r2.position - r1.position
+ );
+
+ const routesData = [];
+ for (let i = 0; i < routesReversed.length; i++) {
+ routesData.push({
+ id: routesReversed[i].id,
+ position: +targetPosition + 1,
+ });
+ }
+
+ await updateRoutesAction(routesData);
+ resetForm();
+
+ // TODO: check for errors
+
+ setIsOpen(false);
+ setLoading(false);
+ router.refresh();
+ };
+
+ const handleTargetRouteChange = (targetPosition: string) => {
+ setTargetPositionError("");
+ setTargetPosition(targetPosition);
+ };
+
+ return (
+
+
+
+ );
+}
+
+export default MoveRoutesDialog;
diff --git a/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/new-first-route-button.tsx b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/new-first-route-button.tsx
new file mode 100644
index 00000000..14ee5d6f
--- /dev/null
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/new-first-route-button.tsx
@@ -0,0 +1,39 @@
+import IconPlus from "@/components/ui/icons/plus";
+import RouteDialog from "./route-card/route-dialog";
+import { useState } from "react";
+
+type TNewFirstRouteButtonProps = {
+ sectorId: string;
+ disabled: boolean;
+};
+function NewFirstRouteButton({
+ sectorId,
+ disabled,
+}: TNewFirstRouteButtonProps) {
+ const [newRouteDialogIsOpen, setNewRouteDialogIsOpen] = useState(false);
+
+ return (
+ <>
+
+ setNewRouteDialogIsOpen(true)}
+ >
+ dodaj smer na začetek
+
+
+
+
+
+ >
+ );
+}
+
+export default NewFirstRouteButton;
diff --git a/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/route-card/delete-route-dialog.tsx b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/route-card/delete-route-dialog.tsx
new file mode 100644
index 00000000..21747377
--- /dev/null
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/route-card/delete-route-dialog.tsx
@@ -0,0 +1,52 @@
+import Dialog from "@/components/ui/dialog";
+import { Dispatch, SetStateAction, useState } from "react";
+import { useRouter } from "next/navigation";
+import deleteRouteAction from "../../lib/delete-route-action";
+import { Route } from "@/graphql/generated";
+
+type TDeleteRouteDialogProps = {
+ isOpen: boolean;
+ setIsOpen: Dispatch>;
+ route: Route;
+};
+
+function DeleteRouteDialog({
+ isOpen,
+ setIsOpen,
+ route,
+}: TDeleteRouteDialogProps) {
+ const router = useRouter();
+
+ const [loading, setLoading] = useState(false);
+
+ const handleConfirm = async () => {
+ setLoading(true);
+ await deleteRouteAction(route.id);
+ setIsOpen(false);
+ setLoading(false);
+ router.refresh();
+ };
+
+ return (
+
+ <>
+ Ali res želiš izbrisati smer{" "}
+ {route.name} ?
+ >
+
+ );
+}
+
+export default DeleteRouteDialog;
diff --git a/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/route-card/route-card.tsx b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/route-card/route-card.tsx
new file mode 100644
index 00000000..2328ded3
--- /dev/null
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/route-card/route-card.tsx
@@ -0,0 +1,193 @@
+"use client";
+
+import Button from "@/components/ui/button";
+import Checkbox from "@/components/ui/checkbox";
+import IconDelete from "@/components/ui/icons/delete";
+import IconDrag from "@/components/ui/icons/drag";
+import IconEdit from "@/components/ui/icons/edit";
+import IconPlus from "@/components/ui/icons/plus";
+import { Route } from "@/graphql/generated";
+import { difficultyToGrade } from "@/lib/grade-helpers";
+import { useState } from "react";
+import RouteDialog from "./route-dialog";
+import DeleteRouteDialog from "./delete-route-dialog";
+import { useSortable } from "@dnd-kit/sortable";
+import { CSS } from "@dnd-kit/utilities";
+import { genderizeVerb } from "@/lib/text-helpers";
+import PublishStatusActions from "../../../../../../components/publish-status-actions";
+import { canEdit, getBgStyle } from "@/lib/contributables-helpers";
+import { useAuthContext } from "@/lib/auth/auth-context";
+
+type TRouteCardProps = {
+ route: Route;
+ sectorId: string;
+ checked: boolean;
+ onCheckedChange: (checked: boolean, routeId: string) => void;
+ disabled: boolean;
+};
+
+function RouteCard({
+ route,
+ sectorId,
+ checked,
+ onCheckedChange,
+ disabled,
+}: TRouteCardProps) {
+ const { currentUser } = useAuthContext();
+
+ const grade = difficultyToGrade(
+ route.difficulty || null,
+ route.defaultGradingSystem.id
+ );
+
+ const [newRouteDialogIsOpen, setNewRouteDialogIsOpen] = useState(false);
+ const [editRouteDialogIsOpen, setEditRouteDialogIsOpen] = useState(false);
+ const [deleteRouteDialogIsOpen, setDeleteRouteDialogIsOpen] = useState(false);
+
+ const {
+ attributes,
+ listeners,
+ setNodeRef,
+ transform,
+ transition,
+ isDragging,
+ } = useSortable({ id: route.id });
+
+ const style = {
+ transform: CSS.Translate.toString(transform),
+ transition,
+ };
+
+ return (
+ <>
+ {/* route card */}
+
+ {/* first row: drag, check, name, grade, length, actions */}
+
+ {/* drag, check, name, grade, length */}
+
+ {/* drag handle */}
+
+
+
+
+
+ {/* checkbox */}
+
+ onCheckedChange(checked, route.id)}
+ disabled={disabled || !canEdit(currentUser, route)}
+ />
+
+ {/* route name */}
+
+ {route.name}
+
+
{grade?.name}
+
+ {route.length !== null && {route.length} m }
+
+
+
+ {/* actions */}
+
+ {/* edit */}
+
setEditRouteDialogIsOpen(true)}
+ >
+
+
+
+ {/* divider */}
+
+
+ {/* delete */}
+
{
+ setDeleteRouteDialogIsOpen(true);
+ }}
+ >
+
+
+
+ {/* divider */}
+
+
+ {/* add route */}
+
{
+ setNewRouteDialogIsOpen(true);
+ }}
+ >
+
+
+
+
+
+ {/* last row (if not published) */}
+ {route.publishStatus !== "published" && (
+
+
+ {currentUser && currentUser.id === route.user?.id ? (
+ "Tvoj prispevek"
+ ) : (
+ <>
+
+ {genderizeVerb("Prispeval", "M")}:
+
+ {route.user?.fullName}
+ >
+ )}
+
+
+ {/* publish status actions */}
+
+
+ )}
+
+
+
+
+
+
+
+ >
+ );
+}
+
+export default RouteCard;
diff --git a/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/route-card/route-dialog.tsx b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/route-card/route-dialog.tsx
new file mode 100644
index 00000000..4bc49fe1
--- /dev/null
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/route-card/route-dialog.tsx
@@ -0,0 +1,365 @@
+import Dialog from "@/components/ui/dialog";
+import TextField from "@/components/ui/text-field";
+import { Dispatch, FormEvent, SetStateAction, useRef, useState } from "react";
+import { useRouter } from "next/navigation";
+import { Option, Select } from "@/components/ui/select";
+import { TGradingSystemId, gradingSystems } from "@/lib/grading-systems";
+import Checkbox from "@/components/ui/checkbox";
+import TextArea from "@/components/ui/text-area";
+import createRouteAction from "../../lib/create-route-action";
+import { Route } from "@/graphql/generated";
+import updateRouteAction from "../../lib/update-route-action";
+
+type TRouteDialogBaseProps = {
+ formType: "new" | "edit";
+ isOpen: boolean;
+ setIsOpen: Dispatch>;
+};
+
+type TNewRouteDialogProps = TRouteDialogBaseProps & {
+ formType: "new";
+ position: number;
+ sectorId: string;
+
+ route?: never;
+};
+
+type TEditRouteDialogProps = TRouteDialogBaseProps & {
+ formType: "edit";
+ route: Route;
+
+ position?: never;
+ sectorId?: never;
+};
+
+type TRouteDialogProps = TNewRouteDialogProps | TEditRouteDialogProps;
+
+function RouteDialog({
+ formType,
+ isOpen,
+ setIsOpen,
+ position,
+ sectorId,
+ route,
+}: TRouteDialogProps) {
+ // Determine default/initial values for all form fields
+ let defaultValues: {
+ name: string;
+ type: string;
+ gradingSystemId: string;
+ difficulty: string;
+ isProject: boolean;
+ length: string;
+ author: string;
+ description: string;
+ };
+
+ switch (formType) {
+ case "new":
+ defaultValues = {
+ name: "",
+ type: "sport",
+ gradingSystemId: getPossibleGradingSystems("sport")[0].id,
+ difficulty: "",
+ isProject: false,
+ length: "",
+ author: "",
+ description: "",
+ };
+ break;
+ case "edit":
+ defaultValues = {
+ name: route.name,
+ type: route.routeType.id,
+ gradingSystemId: route.defaultGradingSystem.id,
+ difficulty: `${route.difficulty}` || "",
+ isProject: route.isProject,
+ length: `${route.length}` || "",
+ author: route.author || "",
+ description: route.description || "",
+ };
+ break;
+ }
+
+ const router = useRouter();
+ const formRef = useRef(null);
+ const [loading, setLoading] = useState(false);
+
+ const [name, setName] = useState(defaultValues.name);
+ const [type, setType] = useState(defaultValues.type);
+ const [gradingSystemId, setGradingSystemId] = useState(
+ defaultValues.gradingSystemId
+ );
+ const [difficulty, setDifficulty] = useState(defaultValues.difficulty);
+ const [isProject, setIsProject] = useState(defaultValues.isProject);
+ const [length, setLength] = useState("");
+ const [author, setAuthor] = useState("");
+ const [description, setDescription] = useState("");
+ const [addAnother, setAddAnother] = useState(false);
+
+ const [nameError, setNameError] = useState("");
+ const nameRef = useRef(null);
+ const [difficultyError, setDifficultyError] = useState("");
+ const difficultyRef = useRef(null);
+
+ const handleNameChange = (name: string) => {
+ setNameError("");
+ setName(name);
+ };
+
+ const handleTypeChange = (type: string) => {
+ // when type changes set grading system to first possible with the new type
+ setGradingSystemId(getPossibleGradingSystems(type)[0].id);
+ setDifficulty("");
+ setType(type);
+ };
+
+ const handleGradingSystemIdChange = (gradingSystemId: string) => {
+ setDifficulty("");
+ setGradingSystemId(gradingSystemId);
+ };
+
+ const handleDifficultyChange = (difficulty: string) => {
+ setDifficultyError("");
+ setDifficulty(difficulty);
+ };
+
+ const handleIsProjectChange = (isProject: boolean) => {
+ if (isProject) {
+ setDifficultyError("");
+ setDifficulty("");
+ }
+ setIsProject(isProject);
+ };
+
+ const possibleGradingSystems = getPossibleGradingSystems(type);
+
+ const possibleGrades = gradingSystemId
+ ? gradingSystems[gradingSystemId as TGradingSystemId].grades
+ : [];
+
+ const resetForm = () => {
+ // reset fields
+ setName(defaultValues.name);
+ setType(defaultValues.type);
+ setGradingSystemId(defaultValues.gradingSystemId);
+ setDifficulty(defaultValues.difficulty);
+ setIsProject(defaultValues.isProject);
+ setLength(defaultValues.length);
+ setAuthor(defaultValues.author);
+ setDescription(defaultValues.description);
+
+ // clear errors
+ setNameError("");
+ setDifficultyError("");
+ };
+
+ const handleCancel = () => {
+ resetForm();
+ };
+
+ const handleConfirm = async () => {
+ formRef.current?.requestSubmit();
+ };
+
+ const handleFormAction = async (e: FormEvent) => {
+ e.preventDefault();
+ setLoading(true);
+
+ // Validate form
+ const errorRefs = []; // to determine if any errors and where to scroll to
+ // - name is required
+ if (!name) {
+ setNameError("Ime smeri je obvezen podatek.");
+ errorRefs.push(nameRef);
+ }
+
+ // - difficulty is required if not a project
+ if (!isProject && !difficulty) {
+ setDifficultyError("Težavnost smeri je obvezen podatek.");
+ errorRefs.push(difficultyRef);
+ }
+
+ if (errorRefs.length > 0) {
+ setLoading(false);
+ errorRefs.shift()?.current?.scrollIntoView({ behavior: "smooth" });
+ return;
+ }
+
+ const routeData = {
+ name: name,
+ routeTypeId: type,
+ defaultGradingSystemId: gradingSystemId,
+ baseDifficulty: +difficulty || null,
+ isProject: isProject,
+ length: +length || null,
+ author: author || null,
+ // description: description || null, // TODO: be support needed
+ };
+
+ switch (formType) {
+ case "new":
+ const newRouteData = {
+ ...routeData,
+ position: position + 1,
+ sectorId: sectorId,
+ publishStatus: "draft",
+ };
+
+ await createRouteAction(newRouteData);
+ resetForm();
+ break;
+
+ case "edit":
+ const updateRouteData = {
+ ...routeData,
+ id: route.id,
+ };
+ await updateRouteAction(updateRouteData);
+ break;
+ }
+
+ // TODO: check for errors
+
+ setIsOpen(false);
+ setLoading(false);
+ router.refresh();
+ };
+
+ return (
+
+
+
+ );
+}
+
+export default RouteDialog;
+
+const getPossibleGradingSystems = (routeType: string) => {
+ return Object.values(gradingSystems).filter((gradingSystem) =>
+ gradingSystem.routeTypes.some((rt) => rt.id === routeType)
+ );
+};
diff --git a/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/switch-sector-dialog.tsx b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/switch-sector-dialog.tsx
new file mode 100644
index 00000000..b18dd53b
--- /dev/null
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/components/switch-sector-dialog.tsx
@@ -0,0 +1,130 @@
+import Dialog from "@/components/ui/dialog";
+import { Dispatch, FormEvent, SetStateAction, useRef, useState } from "react";
+import { useRouter } from "next/navigation";
+import { Option, Select } from "@/components/ui/select";
+import { Route, Sector } from "@/graphql/generated";
+import moveRoutesToSectorAction from "../lib/move-routes-to-sector-action";
+import { labelAndNameToString } from "@/lib/sector-helpers";
+
+type TSwitchSectorDialogProps = {
+ isOpen: boolean;
+ setIsOpen: Dispatch>;
+ routes: Route[];
+ targetSectors: Sector[];
+};
+
+function SwitchSectorDialog({
+ isOpen,
+ setIsOpen,
+ routes,
+ targetSectors,
+}: TSwitchSectorDialogProps) {
+ const router = useRouter();
+ const formRef = useRef(null);
+ const [loading, setLoading] = useState(false);
+
+ const [targetSector, setTargetSector] = useState("");
+ const [targetSectorError, setTargetSectorError] = useState("");
+
+ const handleTargetSectorChange = (targetSector: string) => {
+ setTargetSectorError("");
+ setTargetSector(targetSector);
+ };
+
+ const resetForm = () => {
+ // reset fields
+ setTargetSector("");
+
+ // clear errors
+ setTargetSectorError("");
+ };
+
+ const handleCancel = () => {
+ resetForm();
+ };
+
+ const handleConfirm = async () => {
+ formRef.current?.requestSubmit();
+ };
+
+ const handleOnSubmit = async (e: FormEvent) => {
+ e.preventDefault();
+ setLoading(true);
+
+ // Validate form
+ // - sector is required
+ if (!targetSector) {
+ setTargetSectorError("Ciljni sektor je obvezen podatek.");
+ setLoading(false);
+ return;
+ }
+
+ // assuming all routes passed in are sorted by position already
+ const routesData = {
+ ids: routes.map((route) => route.id),
+ sectorId: targetSector,
+ };
+
+ await moveRoutesToSectorAction(routesData);
+ resetForm();
+
+ // TODO: check for errors
+
+ setIsOpen(false);
+ setLoading(false);
+ router.refresh();
+ };
+
+ return (
+
+
+
+ Izberi sektor, v katerega želiš premakniti{" "}
+ {routes.length == 1 ? (
+
+ smer {routes[0].name}
+
+ ) : (
+ vse označene smeri
+ )}
+ .
+
+
+
+ {/* Dep.: remove sector label after it is removed from BE */}
+
+ {targetSectors.map((sector) => (
+
+ <>{labelAndNameToString(sector.label, sector.name)}>
+
+ ))}
+
+
+
+
+ );
+}
+
+export default SwitchSectorDialog;
diff --git a/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/lib/create-route-action.ts b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/lib/create-route-action.ts
new file mode 100644
index 00000000..f79fe5a7
--- /dev/null
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/lib/create-route-action.ts
@@ -0,0 +1,27 @@
+"use server";
+
+import { gql } from "urql/core";
+import urqlServer from "@/graphql/urql-server";
+import { CreateRouteDocument, CreateRouteInput } from "@/graphql/generated";
+
+async function createRouteAction(routeData: CreateRouteInput) {
+ const result = await urqlServer().mutation(CreateRouteDocument, {
+ input: routeData,
+ });
+ if (result.error) {
+ console.error(result.error);
+ throw new Error("Pri shranjevanju smeri je prišlo do napake.");
+ }
+
+ return result.data.createRoute;
+}
+
+export default createRouteAction;
+
+gql`
+ mutation CreateRoute($input: CreateRouteInput!) {
+ createRoute(input: $input) {
+ id
+ }
+ }
+`;
diff --git a/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/lib/delete-route-action.ts b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/lib/delete-route-action.ts
new file mode 100644
index 00000000..54658b03
--- /dev/null
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/lib/delete-route-action.ts
@@ -0,0 +1,25 @@
+"use server";
+
+import { gql } from "urql/core";
+import urqlServer from "@/graphql/urql-server";
+import { DeleteRouteDocument } from "@/graphql/generated";
+
+async function deleteRouteAction(routeId: string) {
+ const result = await urqlServer().mutation(DeleteRouteDocument, {
+ id: routeId,
+ });
+ if (result.error) {
+ console.error(result.error);
+ throw new Error("Pri brisanju smeri je prišlo do napake.");
+ }
+
+ return result.data.deleteRoute;
+}
+
+export default deleteRouteAction;
+
+gql`
+ mutation DeleteRoute($id: String!) {
+ deleteRoute(id: $id)
+ }
+`;
diff --git a/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/lib/delete-routes-action.ts b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/lib/delete-routes-action.ts
new file mode 100644
index 00000000..9ca77468
--- /dev/null
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/lib/delete-routes-action.ts
@@ -0,0 +1,25 @@
+"use server";
+
+import { gql } from "urql/core";
+import urqlServer from "@/graphql/urql-server";
+import { DeleteRoutesDocument } from "@/graphql/generated";
+
+async function deleteRoutesAction(routeIds: string[]) {
+ const result = await urqlServer().mutation(DeleteRoutesDocument, {
+ ids: routeIds,
+ });
+ if (result.error) {
+ console.error(result.error);
+ throw new Error("Pri brisanju smeri je prišlo do napake.");
+ }
+
+ return result.data.deleteRoutes;
+}
+
+export default deleteRoutesAction;
+
+gql`
+ mutation DeleteRoutes($ids: [String!]!) {
+ deleteRoutes(ids: $ids)
+ }
+`;
diff --git a/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/lib/merge-routes-action.ts b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/lib/merge-routes-action.ts
new file mode 100644
index 00000000..d4288500
--- /dev/null
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/lib/merge-routes-action.ts
@@ -0,0 +1,26 @@
+"use server";
+
+import { gql } from "urql/core";
+import urqlServer from "@/graphql/urql-server";
+import { MergeRoutesDocument, MergeRoutesInput } from "@/graphql/generated";
+
+async function mergeRoutesAction(mergeRoutesData: MergeRoutesInput) {
+ const result = await urqlServer().mutation(MergeRoutesDocument, {
+ input: mergeRoutesData,
+ });
+
+ if (result.error) {
+ console.error(result.error);
+ throw new Error("Pri združevanju smeri je prišlo do napake.");
+ }
+
+ return result.data.mergeRoutes;
+}
+
+export default mergeRoutesAction;
+
+gql`
+ mutation MergeRoutes($input: MergeRoutesInput!) {
+ mergeRoutes(input: $input)
+ }
+`;
diff --git a/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/lib/move-routes-to-sector-action.ts b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/lib/move-routes-to-sector-action.ts
new file mode 100644
index 00000000..251a1abe
--- /dev/null
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/lib/move-routes-to-sector-action.ts
@@ -0,0 +1,29 @@
+"use server";
+
+import { gql } from "urql/core";
+import urqlServer from "@/graphql/urql-server";
+import {
+ MoveRoutesToSectorDocument,
+ MoveRoutesToSectorInput,
+} from "@/graphql/generated";
+
+async function moveRoutesToSectorAction(routesData: MoveRoutesToSectorInput) {
+ const result = await urqlServer().mutation(MoveRoutesToSectorDocument, {
+ input: routesData,
+ });
+
+ if (result.error) {
+ console.error(result.error);
+ throw new Error("Pri premikanju smeri v drug sektor je prišlo do napake.");
+ }
+
+ return result.data.moveRoutesToSector;
+}
+
+export default moveRoutesToSectorAction;
+
+gql`
+ mutation MoveRoutesToSector($input: MoveRoutesToSectorInput!) {
+ moveRoutesToSector(input: $input)
+ }
+`;
diff --git a/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/lib/update-route-action.ts b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/lib/update-route-action.ts
new file mode 100644
index 00000000..ab5605ac
--- /dev/null
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/lib/update-route-action.ts
@@ -0,0 +1,27 @@
+"use server";
+
+import { gql } from "urql/core";
+import urqlServer from "@/graphql/urql-server";
+import { UpdateRouteDocument, UpdateRouteInput } from "@/graphql/generated";
+
+async function updateRouteAction(routeData: UpdateRouteInput) {
+ const result = await urqlServer().mutation(UpdateRouteDocument, {
+ input: routeData,
+ });
+ if (result.error) {
+ console.error(result.error);
+ throw new Error("Pri shranjevanju smeri je prišlo do napake.");
+ }
+
+ return result.data.updateRoute;
+}
+
+export default updateRouteAction;
+
+gql`
+ mutation UpdateRoute($input: UpdateRouteInput!) {
+ updateRoute(input: $input) {
+ id
+ }
+ }
+`;
diff --git a/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/lib/update-routes-action.ts b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/lib/update-routes-action.ts
new file mode 100644
index 00000000..ebe217ef
--- /dev/null
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/lib/update-routes-action.ts
@@ -0,0 +1,26 @@
+"use server";
+
+import { gql } from "urql/core";
+import urqlServer from "@/graphql/urql-server";
+import { UpdateRouteInput, UpdateRoutesDocument } from "@/graphql/generated";
+
+async function updateRoutesAction(routesData: UpdateRouteInput[]) {
+ const result = await urqlServer().mutation(UpdateRoutesDocument, {
+ input: routesData,
+ });
+ if (result.error) {
+ console.error(result.error);
+ throw new Error("Pri shranjevanju smeri je prišlo do napake.");
+ }
+ return result.data.updateRoutes;
+}
+
+export default updateRoutesAction;
+
+gql`
+ mutation UpdateRoutes($input: [UpdateRouteInput!]!) {
+ updateRoutes(input: $input) {
+ id
+ }
+ }
+`;
diff --git a/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/page.tsx b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/page.tsx
new file mode 100644
index 00000000..c127f54a
--- /dev/null
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/[sectorId]/routes/page.tsx
@@ -0,0 +1,132 @@
+import Breadcrumbs from "@/components/breadcrumbs";
+import ContentHeader from "@/components/content-header";
+import IconInfo from "@/components/ui/icons/info";
+import IconRoutes from "@/components/ui/icons/routes";
+import TabMenu from "@/components/ui/tab-menu";
+import { EditRoutesPageSectorDocument } from "@/graphql/generated";
+import urqlServer from "@/graphql/urql-server";
+import { gql } from "urql";
+import EditRoutes from "./components/edit-routes";
+import { labelAndNameToString } from "@/lib/sector-helpers";
+
+type TEditRoutesPageProps = {
+ params: { sectorId: string };
+};
+
+async function EditRoutesPage({ params: { sectorId } }: TEditRoutesPageProps) {
+ const sectorDataPromise = urqlServer().query(EditRoutesPageSectorDocument, {
+ id: sectorId,
+ });
+ const { data: sectorData } = await sectorDataPromise;
+ const sector = sectorData.sector;
+
+ const noSectorsCrag =
+ sector.crag.sectors.length === 1 &&
+ sector.name === "" &&
+ sector.label === "";
+
+ // Dep: sector label is deprecated. remove it after it is migrated into name on be.
+ return (
+ <>
+
+ }
+ tabMenu={
+ ,
+ },
+ {
+ label: "Sektorji in smeri",
+ link: `/urejanje/plezalisca/${sector.crag.slug}/sektorji`,
+ isActive: true,
+ icon: ,
+ },
+ ]}
+ />
+ }
+ />
+
+
+ >
+ );
+}
+
+export default EditRoutesPage;
+
+gql`
+ query EditRoutesPageSector($id: String!) {
+ sector(id: $id) {
+ id
+ label
+ name
+ crag {
+ id
+ slug
+ name
+ sectors {
+ id
+ label
+ name
+ }
+ }
+ routes {
+ id
+ name
+ routeType {
+ id
+ }
+ difficulty
+ defaultGradingSystem {
+ id
+ }
+ length
+ position
+ created
+ publishStatus
+ user {
+ id
+ fullName
+ }
+ sector {
+ id
+ publishStatus
+ }
+ }
+ }
+ }
+`;
diff --git a/src/app/[lang]/admin/crags/[cragSlug]/sectors/components/convert-to-sectors-many-dialog.tsx b/src/app/[lang]/admin/crags/[cragSlug]/sectors/components/convert-to-sectors-many-dialog.tsx
new file mode 100644
index 00000000..ec17cacc
--- /dev/null
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/components/convert-to-sectors-many-dialog.tsx
@@ -0,0 +1,128 @@
+import Dialog from "@/components/ui/dialog";
+import TextField from "@/components/ui/text-field";
+import { Dispatch, FormEvent, SetStateAction, useRef, useState } from "react";
+import { useRouter } from "next/navigation";
+import updateSectorAction from "../lib/update-sector-action";
+import { Crag, Sector } from "@/graphql/generated";
+import createSectorAction from "../lib/create-sector-action";
+
+type TConvertToSectorsManyDialogProps = {
+ isOpen: boolean;
+ setIsOpen: Dispatch>;
+ crag: Crag;
+};
+
+function ConvertToSectorsManyDialog({
+ isOpen,
+ setIsOpen,
+ crag,
+}: TConvertToSectorsManyDialogProps) {
+ const router = useRouter();
+ const [name, setName] = useState("");
+
+ const formRef = useRef(null);
+
+ const [nameError, setNameError] = useState("");
+ const [loading, setLoading] = useState(false);
+
+ const handleNameChange = (name: string) => {
+ setNameError("");
+ setName(name);
+ };
+
+ const handleCancel = () => {
+ // reset form state
+ setName("");
+ setNameError("");
+ };
+
+ const handleConfirm = () => {
+ formRef.current?.requestSubmit();
+ };
+
+ const handleOnSubmit = async (e: FormEvent) => {
+ e.preventDefault();
+ setLoading(true);
+
+ // validate form
+ if (!name) {
+ setNameError("Ime sektorja je obvezen podatek.");
+ setLoading(false);
+ return;
+ }
+
+ // We have two cases here:
+ // 1. Crag has no sector -> a new sector has to be created.
+ // 2. Crag has a (nameless) dummy sector -> dummy sector just needs to be renamed.
+ if (crag.sectors.length === 0) {
+ const newSectorData = {
+ name: name,
+ label: "",
+ cragId: crag.id,
+ position: 0,
+ publishStatus: "draft",
+ };
+ await createSectorAction(newSectorData);
+ } else if (
+ crag.sectors.length === 1 &&
+ crag.sectors[0].name === "" &&
+ crag.sectors[0].label === ""
+ ) {
+ const updateSectorData = {
+ id: crag.sectors[0].id,
+ name: name,
+ label: "",
+ };
+ await updateSectorAction(updateSectorData);
+ } else {
+ throw new Error("Crag already has many sectors.");
+ }
+
+ // TODO: check for errors
+
+ // reset form state and close dialog
+ setIsOpen(false);
+ setLoading(false);
+
+ router.refresh();
+ };
+
+ return (
+
+
+
+ Vse smeri v plezališču bodo premaknjene v novo ustvarjen sektor.
+
+
+
+
+
+
+
+ );
+}
+
+export default ConvertToSectorsManyDialog;
diff --git a/src/app/[lang]/admin/crags/[cragSlug]/sectors/components/convert-to-sectors-none-dialog.tsx b/src/app/[lang]/admin/crags/[cragSlug]/sectors/components/convert-to-sectors-none-dialog.tsx
new file mode 100644
index 00000000..e62da6b9
--- /dev/null
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/components/convert-to-sectors-none-dialog.tsx
@@ -0,0 +1,63 @@
+import Dialog from "@/components/ui/dialog";
+import { Dispatch, SetStateAction, useState } from "react";
+import { useRouter } from "next/navigation";
+import mergeSectorsIntoNoneAction from "../lib/merge-sectors-into-none-action";
+
+type TConvertToSectorsNoneDialogProps = {
+ isOpen: boolean;
+ setIsOpen: Dispatch>;
+ cragId: string;
+};
+
+function ConvertToSectorsNoneDialog({
+ isOpen,
+ setIsOpen,
+ cragId,
+}: TConvertToSectorsNoneDialogProps) {
+ const router = useRouter();
+ const [loading, setLoading] = useState(false);
+
+ const handleConfirm = async () => {
+ setLoading(true);
+
+ await mergeSectorsIntoNoneAction(cragId);
+
+ // TODO: check for errors
+
+ // reset form state and close dialog
+ setIsOpen(false);
+ setLoading(false);
+
+ router.refresh();
+ };
+
+ return (
+
+ <>
+
+ Vsi sektorji v plezališču bodo izbrisani in smeri premaknjene na nivo
+ plezališča.
+
+
+ Ali res želiš ukiniti sektorje?
+ >
+
+ );
+}
+
+export default ConvertToSectorsNoneDialog;
diff --git a/src/app/[lang]/edit/(crag)/[cragSlug]/sectors/components/edit-sectors/delete-sector-dialog.tsx b/src/app/[lang]/admin/crags/[cragSlug]/sectors/components/delete-sector-dialog.tsx
similarity index 74%
rename from src/app/[lang]/edit/(crag)/[cragSlug]/sectors/components/edit-sectors/delete-sector-dialog.tsx
rename to src/app/[lang]/admin/crags/[cragSlug]/sectors/components/delete-sector-dialog.tsx
index f87e65d6..4be25202 100644
--- a/src/app/[lang]/edit/(crag)/[cragSlug]/sectors/components/edit-sectors/delete-sector-dialog.tsx
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/components/delete-sector-dialog.tsx
@@ -1,8 +1,9 @@
import Dialog from "@/components/ui/dialog";
import { Sector } from "@/graphql/generated";
import { Dispatch, SetStateAction, useState } from "react";
-import deleteSectorAction from "../../lib/delete-sector-action";
+import deleteSectorAction from "../lib/delete-sector-action";
import { useRouter } from "next/navigation";
+import { labelAndNameToString } from "@/lib/sector-helpers";
type TDeleteSectorDialog = {
isOpen: boolean;
@@ -19,12 +20,6 @@ function DeleteSectorDialog({
const [loading, setLoading] = useState(false);
- // Dep.: sector.label is deprecated. remove after removed in BE
- const labelAndName =
- sector.label && sector.name
- ? `${sector.label} - ${sector.name}`
- : sector.label || sector.name || "";
-
const handleConfirm = async () => {
setLoading(true);
await deleteSectorAction(sector.id);
@@ -40,7 +35,7 @@ function DeleteSectorDialog({
setIsOpen={setIsOpen}
cancel={{ label: "Prekliči", disabled: loading }}
confirm={{
- label: "Briši",
+ label: "Izbriši",
callback: handleConfirm,
dontCloseOnConfirm: true,
loading: loading,
@@ -49,7 +44,11 @@ function DeleteSectorDialog({
>
<>
Ali res želiš izbrisati sektor{" "}
- {labelAndName} in vse smeri v njem?
+
+ {/* Dep.: sector.label is deprecated. remove after removed in BE */}
+ {labelAndNameToString(sector.label, sector.name)}
+ {" "}
+ in vse smeri v njem?
>
);
diff --git a/src/app/[lang]/edit/(crag)/[cragSlug]/sectors/components/edit-sectors/edit-sectors-many.tsx b/src/app/[lang]/admin/crags/[cragSlug]/sectors/components/edit-sectors-many.tsx
similarity index 71%
rename from src/app/[lang]/edit/(crag)/[cragSlug]/sectors/components/edit-sectors/edit-sectors-many.tsx
rename to src/app/[lang]/admin/crags/[cragSlug]/sectors/components/edit-sectors-many.tsx
index cd1d31d0..92ab03f4 100644
--- a/src/app/[lang]/edit/(crag)/[cragSlug]/sectors/components/edit-sectors/edit-sectors-many.tsx
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/components/edit-sectors-many.tsx
@@ -1,8 +1,7 @@
"use client";
import Checkbox from "@/components/ui/checkbox";
-import IconPlus from "@/components/ui/icons/plus";
-import { Sector } from "@/graphql/generated";
+import { Crag, Sector } from "@/graphql/generated";
import SectorCard from "./sector-card";
import { Fragment, useEffect, useState } from "react";
import SectorDialog from "./sector-dialog";
@@ -20,30 +19,34 @@ import {
SortableContext,
arrayMove,
sortableKeyboardCoordinates,
+ verticalListSortingStrategy,
} from "@dnd-kit/sortable";
import { restrictToParentElement } from "@dnd-kit/modifiers";
-import updateSectorAction from "../../lib/update-sector-action";
+import updateSectorAction from "../lib/update-sector-action";
import { useRouter } from "next/navigation";
+import NewFirstSectorButton from "./new-first-sector-button";
+import ConvertToSectorsNoneDialog from "./convert-to-sectors-none-dialog";
+import { canEdit } from "@/lib/contributables-helpers";
+import { useAuthContext } from "@/lib/auth/auth-context";
-type TEditCragSectorsManyProps = {
- sectors: Sector[];
- cragId: string;
+type TEditSectorsManyProps = {
+ crag: Crag;
};
-function EditSectorsMany({ sectors, cragId }: TEditCragSectorsManyProps) {
+function EditSectorsMany({ crag }: TEditSectorsManyProps) {
+ const { currentUser } = useAuthContext();
+
const router = useRouter();
const [loading, setLoading] = useState(false);
const [sectorDialogType, setSectorDialogType] = useState<"new" | "edit">();
const [sectorDialogIsOpen, setSectorDialogIsOpen] = useState(false);
const [position, setPosition] = useState(0);
- const [sector, setSector] = useState(sectors[0]);
- const [sortedSectors, setSortedSectors] = useState(sectors);
+ const [sector, setSector] = useState(crag.sectors[0]);
+ const [sortedSectors, setSortedSectors] = useState(crag.sectors);
useEffect(() => {
- setSortedSectors(sectors);
- }, [sectors]);
-
- const handleCragHasSectorsChange = () => {};
+ setSortedSectors(crag.sectors);
+ }, [crag.sectors]);
const handleAddSectorClick = (position: number) => {
setSectorDialogType("new");
@@ -64,6 +67,11 @@ function EditSectorsMany({ sectors, cragId }: TEditCragSectorsManyProps) {
setDeleteSectorDialogIsOpen(true);
};
+ const [
+ convertToSectorsNoneDialogIsOpen,
+ setConvertToSectorsNoneDialogIsOpen,
+ ] = useState(false);
+
const handleDragEnd = async (event: DragEndEvent) => {
const { active, over } = event;
@@ -108,24 +116,18 @@ function EditSectorsMany({ sectors, cragId }: TEditCragSectorsManyProps) {
return (
<>
-
-
-
-
handleAddSectorClick(0)}
- >
- dodaj sektor na začetek
-
-
+ {/* Actions row */}
+
+ setConvertToSectorsNoneDialogIsOpen(true)}
+ />
+
+
-
+
{/* Dep: sector.label is deprecated. remove after api migrates it to name */}
{sortedSectors.map((sector) => (
handleEditSectorClick(sector)}
onAddClick={() => handleAddSectorClick(sector.position + 1)}
@@ -158,7 +162,7 @@ function EditSectorsMany({ sectors, cragId }: TEditCragSectorsManyProps) {
isOpen={sectorDialogIsOpen}
setIsOpen={setSectorDialogIsOpen}
position={position}
- cragId={cragId}
+ cragId={crag.id}
/>
) : (
+
+
>
);
}
diff --git a/src/app/[lang]/admin/crags/[cragSlug]/sectors/components/edit-sectors-none.tsx b/src/app/[lang]/admin/crags/[cragSlug]/sectors/components/edit-sectors-none.tsx
new file mode 100644
index 00000000..33d32e6a
--- /dev/null
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/components/edit-sectors-none.tsx
@@ -0,0 +1,79 @@
+"use client";
+
+import Button from "@/components/ui/button";
+import Checkbox from "@/components/ui/checkbox";
+import IconRoutes from "@/components/ui/icons/routes";
+import { Crag } from "@/graphql/generated";
+import { usePathname, useRouter } from "next/navigation";
+import ConvertToSectorsManyDialog from "./convert-to-sectors-many-dialog";
+import { useState } from "react";
+import createSectorAction from "../lib/create-sector-action";
+import { canEdit } from "@/lib/contributables-helpers";
+import { useAuthContext } from "@/lib/auth/auth-context";
+
+type TEditSectorsNoneProps = {
+ crag: Crag;
+};
+
+function EditSectorsNone({ crag }: TEditSectorsNoneProps) {
+ const { currentUser } = useAuthContext();
+
+ const router = useRouter();
+ const pathname = usePathname();
+
+ const [
+ convertToSectorsManyDialogIsOpen,
+ setConvertToSectorsManyDialogIsOpen,
+ ] = useState(false);
+
+ const handleEditRoutesClick = async () => {
+ // We have two cases here:
+ // 1. Crag has no sector -> a new dummy sector has to be created. then redirect to the routes page.
+ // 2. Crag has a (nameless) dummy sector -> just redirect to the routes page.
+ if (crag.sectors.length === 0) {
+ const newDummySectorData = {
+ name: "",
+ label: "",
+ cragId: crag.id,
+ position: 0,
+ publishStatus: crag.publishStatus,
+ };
+ const newDummySector = await createSectorAction(newDummySectorData);
+
+ router.push(`${pathname}/${newDummySector.id}/smeri`);
+ } else {
+ router.push(`${pathname}/${crag.sectors[0].id}/smeri`);
+ }
+ };
+
+ return (
+ <>
+ {/* Actions row */}
+
+
+ setConvertToSectorsManyDialogIsOpen(true)}
+ />
+
+
+
+
+
+ Uredi smeri
+
+
+
+
+
+ >
+ );
+}
+
+export default EditSectorsNone;
diff --git a/src/app/[lang]/edit/(crag)/[cragSlug]/sectors/components/edit-sectors.tsx b/src/app/[lang]/admin/crags/[cragSlug]/sectors/components/edit-sectors.tsx
similarity index 64%
rename from src/app/[lang]/edit/(crag)/[cragSlug]/sectors/components/edit-sectors.tsx
rename to src/app/[lang]/admin/crags/[cragSlug]/sectors/components/edit-sectors.tsx
index c5734096..8abf25fa 100644
--- a/src/app/[lang]/edit/(crag)/[cragSlug]/sectors/components/edit-sectors.tsx
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/components/edit-sectors.tsx
@@ -1,6 +1,6 @@
import { Crag } from "@/graphql/generated";
-import EditSectorsNone from "./edit-sectors/edit-sectors-none";
-import EditSectorsMany from "./edit-sectors/edit-sectors-many";
+import EditSectorsNone from "./edit-sectors-none";
+import EditSectorsMany from "./edit-sectors-many";
type TEditCragSectorsProps = {
crag: Crag;
@@ -14,11 +14,11 @@ function EditSectors({ crag }: TEditCragSectorsProps) {
!!crag.sectors[0]?.label;
return (
-
+
{cragHasSectors ? (
-
+
) : (
-
+
)}
);
diff --git a/src/app/[lang]/admin/crags/[cragSlug]/sectors/components/new-first-sector-button.tsx b/src/app/[lang]/admin/crags/[cragSlug]/sectors/components/new-first-sector-button.tsx
new file mode 100644
index 00000000..5b5264e3
--- /dev/null
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/components/new-first-sector-button.tsx
@@ -0,0 +1,40 @@
+import IconPlus from "@/components/ui/icons/plus";
+import SectorDialog from "./sector-dialog";
+import { useState } from "react";
+
+type TNewFirstSectorButtonProps = {
+ cragId: string;
+ disabled: boolean;
+};
+
+function NewFirstSectorButton({
+ cragId,
+ disabled,
+}: TNewFirstSectorButtonProps) {
+ const [sectorDialogIsOpen, setSectorDialogIsOpen] = useState(false);
+
+ return (
+ <>
+
+ setSectorDialogIsOpen(true)}
+ >
+ dodaj sektor na začetek
+
+
+
+
+
+ >
+ );
+}
+
+export default NewFirstSectorButton;
diff --git a/src/app/[lang]/admin/crags/[cragSlug]/sectors/components/sector-card.tsx b/src/app/[lang]/admin/crags/[cragSlug]/sectors/components/sector-card.tsx
new file mode 100644
index 00000000..d3238fcb
--- /dev/null
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/components/sector-card.tsx
@@ -0,0 +1,178 @@
+import Button from "@/components/ui/button";
+import IconDelete from "@/components/ui/icons/delete";
+import IconDrag from "@/components/ui/icons/drag";
+import IconEdit from "@/components/ui/icons/edit";
+import { IconSize } from "@/components/ui/icons/icon-size";
+import IconMore from "@/components/ui/icons/more";
+import IconPlus from "@/components/ui/icons/plus";
+import IconRoutes from "@/components/ui/icons/routes";
+import { Sector } from "@/graphql/generated";
+import { genderizeVerb } from "@/lib/text-helpers";
+import { useSortable } from "@dnd-kit/sortable";
+import { CSS } from "@dnd-kit/utilities";
+import { usePathname, useRouter } from "next/navigation";
+import PublishStatusActions from "../../../components/publish-status-actions";
+import { labelAndNameToString } from "@/lib/sector-helpers";
+import { canEdit, getBgStyle } from "@/lib/contributables-helpers";
+import { useAuthContext } from "@/lib/auth/auth-context";
+
+type TSectorCardProps = {
+ sector: Sector;
+ disabled?: boolean;
+ onAddClick: () => void;
+ onEditClick: () => void;
+ onDeleteClick: () => void;
+};
+
+function SectorCard({
+ sector,
+ disabled,
+ onAddClick,
+ onEditClick,
+ onDeleteClick,
+}: TSectorCardProps) {
+ const { currentUser } = useAuthContext();
+
+ const router = useRouter();
+ const pathname = usePathname();
+
+ const moreAction = (
+
{}}>
+
+
+ );
+
+ const {
+ attributes,
+ listeners,
+ setNodeRef,
+ transform,
+ transition,
+ isDragging,
+ } = useSortable({ id: sector.id });
+
+ const style = {
+ transform: CSS.Translate.toString(transform),
+ transition,
+ };
+
+ return (
+ // {/* sector card */}
+
+ {/* drag, name, actions */}
+
+ {/* drag, name, (more) */}
+
+
+
+ {}}
+ >
+
+
+
+
+ {labelAndNameToString(sector.label, sector.name)}
+
+
+
{moreAction}
+
+
+ {/* actions */}
+
+
+ {/* edit routes */}
+
{
+ router.push(`${pathname}/${sector.id}/smeri`);
+ }}
+ >
+
+
+
+ {/* divider */}
+
+
+
{moreAction}
+
+ {/* divider */}
+
+
+ {/* edit */}
+
+
+
+
+ {/* divider */}
+
+
+ {/* delete */}
+
+
+
+
+ {/* divider */}
+
+
+ {/* add sector */}
+
+
+
+
+
+
+
+ {/* contributor, publish actions */}
+ {sector.publishStatus !== "published" && (
+
+ {/* contributor */}
+
+ {currentUser && currentUser.id === sector.user?.id ? (
+ "Tvoj prispevek"
+ ) : (
+ <>
+
+ {genderizeVerb("Prispeval", "M")}:
+
+ {sector.user?.fullName}
+ >
+ )}
+
+
+ {/* publish status actions */}
+
+
+ )}
+
+ );
+}
+
+export default SectorCard;
diff --git a/src/app/[lang]/edit/(crag)/[cragSlug]/sectors/components/edit-sectors/sector-dialog.tsx b/src/app/[lang]/admin/crags/[cragSlug]/sectors/components/sector-dialog.tsx
similarity index 92%
rename from src/app/[lang]/edit/(crag)/[cragSlug]/sectors/components/edit-sectors/sector-dialog.tsx
rename to src/app/[lang]/admin/crags/[cragSlug]/sectors/components/sector-dialog.tsx
index 8cb5dc19..32f9c5b8 100644
--- a/src/app/[lang]/edit/(crag)/[cragSlug]/sectors/components/edit-sectors/sector-dialog.tsx
+++ b/src/app/[lang]/admin/crags/[cragSlug]/sectors/components/sector-dialog.tsx
@@ -8,9 +8,9 @@ import {
useRef,
useState,
} from "react";
-import createSectorAction from "../../lib/create-sector-action";
+import createSectorAction from "../lib/create-sector-action";
import { useRouter } from "next/navigation";
-import updateSectorAction from "../../lib/update-sector-action";
+import updateSectorAction from "../lib/update-sector-action";
import { Sector } from "@/graphql/generated";
type TSectorDialogBaseProps = {
@@ -77,7 +77,8 @@ function SectorDialog({
formRef.current?.requestSubmit();
};
- const handleFormAction = async () => {
+ const handleOnSubmit = async (e: FormEvent
) => {
+ e.preventDefault();
setLoading(true);
// validate form
@@ -140,7 +141,7 @@ function SectorDialog({
dontCloseOnConfirm: true,
}}
>
-
+
,
- },
- {
- label: "Sektorji in smeri",
- link: `/edit/${cragSlug}/sectors`,
- isActive: true,
- icon: ,
- },
- ];
-
return (
<>
}
- tabMenu={ }
+ tabMenu={
+ ,
+ },
+ {
+ label: "Sektorji in smeri",
+ link: `/urejanje/plezalisca/${cragSlug}/sektorji`,
+ isActive: true,
+ icon: ,
+ },
+ ]}
+ />
+ }
/>
@@ -67,11 +73,25 @@ gql`
id
slug
name
+ publishStatus
sectors {
+ __typename
id
name
label
position
+ publishStatus
+ user {
+ id
+ fullName
+ }
+ routes {
+ id
+ }
+ crag {
+ id
+ publishStatus
+ }
}
}
}
diff --git a/src/app/[lang]/edit/(crag)/new-crag/components/new-crag-form.tsx b/src/app/[lang]/admin/crags/add/components/new-crag-form.tsx
similarity index 100%
rename from src/app/[lang]/edit/(crag)/new-crag/components/new-crag-form.tsx
rename to src/app/[lang]/admin/crags/add/components/new-crag-form.tsx
diff --git a/src/app/[lang]/edit/(crag)/new-crag/lib/create-crag-action.ts b/src/app/[lang]/admin/crags/add/lib/create-crag-action.ts
similarity index 100%
rename from src/app/[lang]/edit/(crag)/new-crag/lib/create-crag-action.ts
rename to src/app/[lang]/admin/crags/add/lib/create-crag-action.ts
diff --git a/src/app/[lang]/edit/(crag)/new-crag/page.tsx b/src/app/[lang]/admin/crags/add/page.tsx
similarity index 64%
rename from src/app/[lang]/edit/(crag)/new-crag/page.tsx
rename to src/app/[lang]/admin/crags/add/page.tsx
index e32d3e22..7d2ce44e 100644
--- a/src/app/[lang]/edit/(crag)/new-crag/page.tsx
+++ b/src/app/[lang]/admin/crags/add/page.tsx
@@ -2,7 +2,7 @@ import { NewCragPageCountriesDocument } from "@/graphql/generated";
import urqlServer from "@/graphql/urql-server";
import { gql } from "urql";
import NewCragForm from "./components/new-crag-form";
-import TabMenu, { TTabMenuItem } from "@/components/ui/tab-menu";
+import TabMenu from "@/components/ui/tab-menu";
import IconInfo from "@/components/ui/icons/info";
import IconRoutes from "@/components/ui/icons/routes";
import ContentHeader from "@/components/content-header";
@@ -17,22 +17,6 @@ async function NewCragPage() {
data: { countries },
} = await countriesDataPromise;
- const tabMenuItems: TTabMenuItem[] = [
- {
- label: "Osnovni podatki",
- link: "/edit/new-crag",
- isActive: true,
- icon: ,
- },
- {
- label: "Sektorji in smeri",
- isDisabled: true,
- link: "",
- isActive: false,
- icon: ,
- },
- ];
-
return (
<>
+ }
+ tabMenu={
+ ,
+ },
+ {
+ label: "Sektorji in smeri",
+ isDisabled: true,
+ link: "",
+ isActive: false,
+ icon: ,
+ },
]}
/>
}
- tabMenu={ }
/>
>
diff --git a/src/app/[lang]/admin/crags/components/crag-cover-image-selector.tsx b/src/app/[lang]/admin/crags/components/crag-cover-image-selector.tsx
new file mode 100644
index 00000000..b0e1cda3
--- /dev/null
+++ b/src/app/[lang]/admin/crags/components/crag-cover-image-selector.tsx
@@ -0,0 +1,140 @@
+import Dialog, { DialogSize } from "@/components/ui/dialog";
+import IconImage from "@/components/ui/icons/image";
+import { RadioCircle } from "@/components/ui/radio-group";
+import { Crag, Image } from "@/graphql/generated";
+import { Radio, RadioGroup } from "@headlessui/react";
+import NextImage from "next/image";
+import { useState } from "react";
+
+type TCragCoverImageSelectorProps = {
+ crag: Crag | null;
+ value: string | null;
+ onChange: (value: string) => void;
+ disabled: boolean;
+};
+
+function CragCoverImageSelector({
+ crag,
+ value,
+ onChange,
+ disabled,
+}: TCragCoverImageSelectorProps) {
+ const selectedImage =
+ crag?.images.find((image) => image.id === value) || null;
+
+ const [buttonImage, setButtonImage] = useState(selectedImage);
+
+ const onConfirm = () => {
+ setButtonImage(selectedImage);
+ };
+
+ return (
+ <>
+ Naslovna fotografija
+
+ {!crag || crag.images.length == 0 ? (
+
+
+
+
+
+ }
+ >
+
+ Plezališče še nima fotografij. Preden lahko izbereš naslovno
+ fotografijo moraš v galerijo dodati vsaj eno fotografijo.
+
+
+ ) : (
+
+ {buttonImage ? (
+ 1
+ ? `${60 * buttonImage.aspectRatio}px`
+ : "60px",
+ }}
+ src={`${process.env.NEXT_PUBLIC_IMAGES_BASEURL}/${buttonImage.path}.${buttonImage.extension}`}
+ alt={[crag.name, buttonImage.description]
+ .filter((part) => !!part)
+ .join(" - ")}
+ width={buttonImage.maxIntrinsicWidth}
+ height={
+ buttonImage.maxIntrinsicWidth / buttonImage.aspectRatio
+ }
+ quality={100}
+ sizes={
+ buttonImage.aspectRatio > 1
+ ? `${60 * buttonImage.aspectRatio}px`
+ : "60px"
+ }
+ />
+ ) : (
+
+
+
+ )}
+
+ }
+ >
+
+
Izberi naslovno fotografijo plezališča.
+
+
+
+ {crag?.images.map((image) => (
+
+ {({ focus, checked, disabled }) => (
+ <>
+ !!part)
+ .join(" - ")}
+ width={image.maxIntrinsicWidth}
+ height={image.maxIntrinsicWidth / image.aspectRatio}
+ quality={100}
+ sizes="(max-width: 399px) 295px, (max-width: 595px) 384px, (max-width: 751px) 192px, 140px"
+ />
+
+
+ >
+ )}
+
+ ))}
+
+
+
+
+ )}
+ >
+ );
+}
+
+export default CragCoverImageSelector;
diff --git a/src/app/[lang]/admin/crags/components/crag-form.tsx b/src/app/[lang]/admin/crags/components/crag-form.tsx
new file mode 100644
index 00000000..3612ef05
--- /dev/null
+++ b/src/app/[lang]/admin/crags/components/crag-form.tsx
@@ -0,0 +1,626 @@
+"use client";
+
+import Button from "@/components/ui/button";
+import IconAutumn from "@/components/ui/icons/autumn";
+import { IconSize } from "@/components/ui/icons/icon-size";
+import IconOverhang from "@/components/ui/icons/overhang";
+import IconRoof from "@/components/ui/icons/roof";
+import IconSlab from "@/components/ui/icons/slab";
+import IconSpring from "@/components/ui/icons/spring";
+import IconSummer from "@/components/ui/icons/summer";
+import IconVertical from "@/components/ui/icons/vertical";
+import IconWinter from "@/components/ui/icons/winter";
+import { Radio, RadioGroup } from "@/components/ui/radio-group";
+import { Select, Option } from "@/components/ui/select";
+import { Selector, SelectorOption } from "@/components/ui/selector";
+import TextArea from "@/components/ui/text-area";
+import TextField from "@/components/ui/text-field";
+import {
+ Country,
+ Crag,
+ Orientation,
+ Season,
+ WallAngle,
+} from "@/graphql/generated";
+import { FormEvent, useRef, useState } from "react";
+import { gradingSystems } from "../../../../../lib/grading-systems";
+import CoordinatesInput, {
+ formatCoordinates,
+ validateCoordinates,
+} from "@/components/ui/coordinates-input";
+import Checkbox from "@/components/ui/checkbox";
+import { useRouter } from "next/navigation";
+import createCragAction from "../add/lib/create-crag-action";
+import updateCragAction from "../[cragSlug]/edit/lib/update-crag-action";
+import CragCoverImageSelector from "./crag-cover-image-selector";
+import IconDelete from "@/components/ui/icons/delete";
+import DeleteCragDialog from "./delete-crag-dialog";
+
+type TCragFormProps = {
+ formType: "edit" | "new";
+ countriesWithAreas: Country[];
+ crag?: Crag;
+};
+
+function CragForm({ formType, countriesWithAreas, crag }: TCragFormProps) {
+ // Determine default/initial values for all form fields
+ let defaultValues;
+ if (formType == "edit" && crag) {
+ defaultValues = {
+ name: crag.name,
+ country: crag.country.id,
+ area: crag.area ? crag.area.id : "",
+ cragType: crag.type,
+ gradingSystem: crag.defaultGradingSystem
+ ? crag.defaultGradingSystem.id
+ : "",
+ cragCoordinates:
+ crag.lat && crag.lon ? formatCoordinates(crag.lat, crag.lon) : "",
+ cragDescription: crag.description || "",
+ wallAngles: crag.wallAngles || [],
+ rainproof: crag.rainproof !== null ? (crag.rainproof ? "yes" : "no") : "",
+ orientations: crag.orientations || [],
+ seasons: crag.seasons || [],
+ parkingCoordinates: "", // TODO
+ approachTime: crag.approachTime !== null ? `${crag.approachTime}` : "",
+ approachDescription: crag.access || "",
+ coverImage: crag.coverImage?.id || null,
+ isHidden: crag.isHidden || false,
+ };
+ } else {
+ // form type = 'new'
+ defaultValues = {
+ name: "",
+ country: countriesWithAreas.find((c) => c.slug == "slovenija")?.id || "",
+ area: "",
+ cragType: "sport",
+ gradingSystem: "french",
+ cragCoordinates: "",
+ cragDescription: "",
+ wallAngles: [],
+ rainproof: "",
+ orientations: [],
+ seasons: [],
+ parkingCoordinates: "",
+ approachTime: "",
+ approachDescription: "",
+ coverImage: null,
+ isHidden: false,
+ };
+ }
+
+ const [name, setName] = useState(defaultValues.name);
+ const [nameError, setNameError] = useState("");
+ const nameRef = useRef(null);
+
+ const [country, setCountry] = useState(defaultValues.country);
+ const [area, setArea] = useState(defaultValues.area);
+ const [cragType, setCragType] = useState(defaultValues.cragType);
+ const [gradingSystem, setGradingSystem] = useState(
+ defaultValues.gradingSystem
+ );
+
+ const [cragCoordinates, setCragCoordinates] = useState(
+ defaultValues.cragCoordinates
+ );
+ const [cragCoordinatesError, setCragCoordinatesError] = useState("");
+ const cragCoordinatesRef = useRef(null);
+
+ const [cragDescription, setCragDescription] = useState(
+ defaultValues.cragDescription
+ );
+ const [wallAngles, setWallAngles] = useState(
+ defaultValues.wallAngles
+ );
+ const [rainproof, setRainproof] = useState(
+ defaultValues.rainproof
+ );
+ const [orientations, setOrientations] = useState(
+ defaultValues.orientations
+ );
+ const [seasons, setSeasons] = useState(defaultValues.seasons);
+
+ const [parkingCoordinates, setParkingCoordinates] = useState(
+ defaultValues.parkingCoordinates
+ );
+ const [parkingCoordinatesError, setParkingCoordinatesError] = useState("");
+ const parkingCoordinatesRef = useRef(null);
+
+ const [approachTime, setApproachTime] = useState(defaultValues.approachTime);
+ const [approachDescription, setApproachDescription] = useState(
+ defaultValues.approachDescription
+ );
+
+ const [coverImage, setCoverImage] = useState(defaultValues.coverImage);
+ const [isHidden, setIsHidden] = useState(defaultValues.isHidden);
+
+ const formDirty =
+ defaultValues.approachDescription !== approachDescription ||
+ defaultValues.approachTime !== approachTime ||
+ defaultValues.area !== area ||
+ defaultValues.cragCoordinates !== cragCoordinates ||
+ defaultValues.cragDescription !== cragDescription ||
+ defaultValues.cragType !== cragType ||
+ defaultValues.country !== country ||
+ defaultValues.gradingSystem !== gradingSystem ||
+ defaultValues.isHidden !== isHidden ||
+ defaultValues.name !== name ||
+ defaultValues.orientations.toString() !== orientations.toString() ||
+ defaultValues.parkingCoordinates !== parkingCoordinates ||
+ defaultValues.rainproof !== rainproof ||
+ defaultValues.seasons.toString() !== seasons.toString() ||
+ defaultValues.wallAngles.toString() !== wallAngles.toString() ||
+ defaultValues.coverImage !== coverImage;
+
+ const [loading, setLoading] = useState(false);
+
+ const router = useRouter();
+
+ const handleNameChange = (name: string) => {
+ setName(name);
+ setNameError("");
+ };
+
+ const handleCountryChange = (country: string) => {
+ setCountry(country);
+ setArea("");
+ };
+
+ const areas = countriesWithAreas.find((c) => c.id === country)?.areas;
+
+ const availableGradingSystems = Object.values(gradingSystems).filter((gs) => {
+ // crag type sport
+ if (cragType == "sport") {
+ return gs.routeTypes.some((rt) =>
+ ["sport", "multipitch", "boulder"].includes(rt.id)
+ );
+ }
+ // crag type alpine
+ else {
+ return gs.routeTypes.some((rt) => rt.id == "alpine");
+ }
+ });
+
+ const handleCragTypeChange = (cragType: string) => {
+ setGradingSystem("");
+ setCragType(cragType);
+ };
+
+ const handleCragCoordinatesChange = (coordinates: string) => {
+ setCragCoordinates(coordinates);
+ setCragCoordinatesError("");
+ };
+
+ const [deleteCragDialogIsOpen, setDeleteCragDialogIsOpen] = useState(false);
+ const handleDeleteCragClick = () => {
+ setDeleteCragDialogIsOpen(true);
+ };
+
+ const handleOnSubmit = async (e: FormEvent) => {
+ e.preventDefault();
+ setLoading(true);
+
+ // Validate form
+ const errorRefs = []; // to determine if any errors and where to scroll to
+ // - name is required
+ if (!name) {
+ setNameError("Ime plezališča je obvezen podatek.");
+ errorRefs.push(nameRef);
+ }
+
+ // - value of coordinates field needs to be two numbers separated by comma, dot or space
+ let cragLat, cragLon;
+ if (cragCoordinates) {
+ const validatedCragCoordinates = validateCoordinates(cragCoordinates);
+ if (validatedCragCoordinates) {
+ [cragLat, cragLon] = validatedCragCoordinates.value;
+ } else {
+ setCragCoordinatesError(
+ "Nepravilna oblika. Koordinate vnesi v obliki: 45,56801, 13,86413"
+ );
+ errorRefs.push(cragCoordinatesRef);
+ }
+ }
+
+ let parkingLat, parkingLon; // TODO: save these where?
+ if (parkingCoordinates) {
+ const validatedParkingCoordinates =
+ validateCoordinates(parkingCoordinates);
+ if (validatedParkingCoordinates) {
+ [parkingLat, parkingLon] = validatedParkingCoordinates.value;
+ } else {
+ setParkingCoordinatesError(
+ "Nepravilna oblika. Koordinate vnesi v obliki: 45,56719, 13,86265"
+ );
+ errorRefs.push(parkingCoordinatesRef);
+ }
+ }
+
+ if (errorRefs.length > 0) {
+ setLoading(false);
+ errorRefs.shift()?.current?.scrollIntoView({ behavior: "smooth" });
+ return;
+ }
+
+ const cragData = {
+ name: name,
+ countryId: country,
+ areaId: area || null,
+ type: cragType,
+ defaultGradingSystemId: gradingSystem,
+ lat: cragLat || null,
+ lon: cragLon || null,
+ description: cragDescription || null,
+ wallAngles: wallAngles.length ? (wallAngles as WallAngle[]) : null,
+ rainproof: rainproof == "yes" ? true : rainproof == "no" ? false : null,
+ orientations: orientations.length
+ ? (orientations as Orientation[])
+ : null,
+ seasons: seasons.length ? (seasons as Season[]) : null,
+ // parkingLat, parkingLon // TODO:
+ approachTime: +approachTime || null,
+ access: approachDescription || null,
+ coverImageId: coverImage || null,
+ isHidden: isHidden,
+ };
+
+ let savedCrag;
+ switch (formType) {
+ case "new":
+ const newCragData = {
+ ...cragData,
+ publishStatus: "draft", // a new crag is initially always a draft
+ };
+
+ savedCrag = await createCragAction(newCragData);
+
+ break;
+ case "edit":
+ const updateCragData = {
+ ...cragData,
+ id: crag!.id,
+ };
+
+ savedCrag = await updateCragAction(updateCragData);
+ }
+
+ router.push(`/urejanje/plezalisca/${savedCrag.slug}/uredi`);
+ setLoading(false);
+ };
+
+ return (
+ <>
+
+
+
+ {/* Main grid for inputs layout */}
+
+ {/* Crag name */}
+
+
+
+
+ {/* Country */}
+
+
+ {countriesWithAreas.map((country) => (
+
+ {country.name}
+
+ ))}
+
+
+ {/* Area */}
+
+
+ {areas?.length
+ ? areas.map((area) => (
+
+ {area.name}
+
+ ))
+ : [1, 2].map((_) => (
+
+ {" "}
+
+ ))}
+
+
+
+ {/* Crag type */}
+
+
+
+ športno / balvani / dolge športne
+
+ alpinizem
+
+
+ {/* Default grading system */}
+
+
+ {availableGradingSystems.map((gs) => (
+
+ {gs.name}
+
+ ))}
+
+
+
+ {/* Crag coordinates */}
+
+
+
+
+ {/* Horizontal divider */}
+
+
+ {/* Crag description */}
+
+
+
+
+ {/* Wall angles */}
+
+
+
+
+
+ plošče
+
+
+
+
+
+ vertikale
+
+
+
+
+
+ previsi
+
+
+
+
+
+ strehe
+
+
+
+
+
+ {/* Rainproof */}
+
+
+ je možno
+ ni možno
+ ni znano
+
+
+
+ {/* Horizontal divider */}
+
+
+ {/* Orientations */}
+
+
+ sever
+ severovzhod
+ vzhod
+ jugovzhod
+ jug
+ jugozahod
+ zahod
+ severozahod
+
+
+
+ {/* Seasons */}
+
+
+
+
+
+ pomlad
+
+
+
+
+
+ poletje
+
+
+
+
+
+ jesen
+
+
+
+
+
+ zima
+
+
+
+
+
+ {/* Parking coordinates */}
+
+
+
+ {/* Approach time */}
+
+ min}
+ disabled={loading}
+ />
+
+
+ {/* Approach description */}
+
+
+
+
+ {/* Horizontal divider */}
+
+
+ {/* Cover image */}
+
+
+
+ {/* Visibility */}
+
+
+ {/* Horizontal divider */}
+
+
+ {/* Delete and save actions */}
+
+ {formType == "edit" ? (
+
+
+
+ Izbriši
+
+
+ ) : (
+
+ )}
+
+ Shrani
+
+
+
+
+
+
+
+ {crag && (
+
+ )}
+ >
+ );
+}
+
+export default CragForm;
diff --git a/src/app/[lang]/admin/crags/components/delete-crag-dialog.tsx b/src/app/[lang]/admin/crags/components/delete-crag-dialog.tsx
new file mode 100644
index 00000000..069dfb8e
--- /dev/null
+++ b/src/app/[lang]/admin/crags/components/delete-crag-dialog.tsx
@@ -0,0 +1,54 @@
+import Dialog from "@/components/ui/dialog";
+import { Crag } from "@/graphql/generated";
+import { Dispatch, SetStateAction, useState } from "react";
+import { useRouter } from "next/navigation";
+import deleteCragAction from "../lib/delete-crag-action";
+
+
+type TDeleteCragDialog = {
+ isOpen: boolean;
+ setIsOpen: Dispatch>;
+ crag: Crag;
+};
+
+function DeleteCragDialog({ isOpen, setIsOpen, crag }: TDeleteCragDialog) {
+ const router = useRouter();
+ const [loading, setLoading] = useState(false);
+
+ const cragHasSectors =
+ crag.sectors.length > 1 ||
+ !!crag.sectors[0]?.name ||
+ !!crag.sectors[0]?.label;
+
+ const handleConfirm = async () => {
+ setLoading(true);
+ await deleteCragAction(crag.id);
+ setIsOpen(false);
+ setLoading(false);
+ router.push(`/`);
+ };
+
+ return (
+
+ <>
+ Ali res želiš izbrisati plezališče{" "}
+ {crag.name} vključno z vsemi
+ {cragHasSectors && <> sektorji in vsemi>} smermi v njem?
+ >
+
+ );
+}
+
+export default DeleteCragDialog;
diff --git a/src/app/[lang]/admin/crags/components/publish-dialog.tsx b/src/app/[lang]/admin/crags/components/publish-dialog.tsx
new file mode 100644
index 00000000..883c4088
--- /dev/null
+++ b/src/app/[lang]/admin/crags/components/publish-dialog.tsx
@@ -0,0 +1,148 @@
+import Dialog from "@/components/ui/dialog";
+import { Dispatch, SetStateAction, useState } from "react";
+import { useRouter } from "next/navigation";
+import { Crag, Route, Sector } from "@/graphql/generated";
+import updateRouteAction from "../[cragSlug]/sectors/[sectorId]/routes/lib/update-route-action";
+import updateSectorAction from "../[cragSlug]/sectors/lib/update-sector-action";
+import updateCragAction from "../[cragSlug]/edit/lib/update-crag-action";
+import Checkbox from "@/components/ui/checkbox";
+
+type TPublishDialogProps = {
+ isOpen: boolean;
+ setIsOpen: Dispatch>;
+ contributable: Route | Sector | Crag;
+};
+
+function PublishDialog({
+ isOpen,
+ setIsOpen,
+ contributable,
+}: TPublishDialogProps) {
+ const router = useRouter();
+
+ const [cascadePublish, setCascadePublish] = useState(true);
+ const [loading, setLoading] = useState(false);
+
+ let title = "";
+ let description = "";
+ let cascadeText = null;
+ switch (contributable.__typename) {
+ case "Route":
+ title = "Objava smeri";
+ description = `Ali res želiš objaviti smer `;
+ break;
+
+ case "Sector":
+ title = "Objava sektorja";
+ description = `Ali res želiš objaviti sektor `;
+ cascadeText = contributable.routes.length
+ ? "Objavi tudi vse smeri v tem sektorju."
+ : null;
+ break;
+
+ case "Crag":
+ title = "Objava plezališča";
+ description = `Ali res želiš objaviti plezališče `;
+
+ const crag = contributable;
+ if (
+ crag.sectors.length === 1 &&
+ crag.sectors[0].name === "" &&
+ crag.sectors[0].label === ""
+ ) {
+ // crag has a dummy sector
+ if (crag.sectors[0].routes.length) {
+ cascadeText = "Objavi tudi vse smeri v tem plezališču.";
+ }
+ } else {
+ if (crag.sectors.length) {
+ cascadeText = "Objavi tudi vse sektorje v tem plezališču.";
+ }
+ if (crag.sectors.some((sector) => sector.routes.length)) {
+ cascadeText =
+ "Objavi tudi vse sektorje in vse smeri v tem plezališču.";
+ }
+ }
+
+ break;
+ }
+
+ const handleConfirm = async () => {
+ setLoading(true);
+
+ const data = {
+ id: contributable.id,
+ publishStatus: "published",
+ ...(contributable.__typename !== "Route" && {
+ cascadePublishStatus: cascadePublish,
+ }),
+ };
+
+ switch (contributable.__typename) {
+ case "Route":
+ await updateRouteAction(data);
+ break;
+ case "Sector":
+ await updateSectorAction(data);
+ break;
+ case "Crag":
+ await updateCragAction(data);
+
+ // If this is a sectorless crag, crag has a dummy sector and it's publish status also needs to be updated (despite cascadePublishStatus flag being false)
+ const crag = contributable;
+ if (
+ !cascadePublish &&
+ crag.sectors.length === 1 &&
+ crag.sectors[0].name === "" &&
+ crag.sectors[0].label === ""
+ ) {
+ const updateSectorData = {
+ id: crag.sectors[0].id,
+ publishStatus: "published",
+ };
+ await updateSectorAction(updateSectorData);
+ }
+ break;
+ }
+
+ setIsOpen(false);
+ setLoading(false);
+ router.refresh();
+ };
+
+ return (
+
+
+
+ {description}
+ {contributable.name} ?
+
+
+ {cascadeText && (
+
+
+
+ )}
+
+
+ );
+}
+
+export default PublishDialog;
diff --git a/src/app/[lang]/admin/crags/components/publish-status-actions.tsx b/src/app/[lang]/admin/crags/components/publish-status-actions.tsx
new file mode 100644
index 00000000..9316a954
--- /dev/null
+++ b/src/app/[lang]/admin/crags/components/publish-status-actions.tsx
@@ -0,0 +1,182 @@
+"use client";
+
+import Button from "@/components/ui/button";
+import IconPublish from "@/components/ui/icons/publish";
+import { Crag, Route, Sector } from "@/graphql/generated";
+import { useState } from "react";
+import IconCheck from "@/components/ui/icons/check";
+import IconClose from "@/components/ui/icons/close";
+import PublishDialog from "./publish-dialog";
+import SuggestPublishDialog from "./suggest-publish-dialog";
+import RejectDialog from "./reject-dialog";
+import { useAuthContext } from "@/lib/auth/auth-context";
+
+type TPublishStatusActionsProps = {
+ contributable: Route | Sector | Crag;
+ disabled: boolean;
+};
+
+function PublishStatusActions({
+ contributable,
+ disabled,
+}: TPublishStatusActionsProps) {
+ const { currentUser } = useAuthContext();
+
+ const [publishDialogIsOpen, setPublishDialogIsOpen] = useState(false);
+ const [suggestPublishDialogIsOpen, setSuggestPublishDialogIsOpen] =
+ useState(false);
+ const [rejectDialogIsOpen, setRejectDialogIsOpen] = useState(false);
+
+ /**
+ * Following cases are possible:
+ *
+ * user editor:
+ * status draft:
+ * possible action: publish
+ * next status: published
+ *
+ * status in_review:
+ * possible action: approve / reject
+ * next status: published / draft
+ *
+ * user regular:
+ * status draft:
+ * possible action: suggest publish
+ * next status: in_review
+ *
+ * status in_review:
+ * possible action: none (wait)
+ */
+
+ let approveRejectClass = "";
+ let parentStatus = null;
+ let hasParent = false;
+ switch (contributable.__typename) {
+ case "Route":
+ hasParent = true;
+ parentStatus = contributable.sector.publishStatus;
+ approveRejectClass = "hidden @3xl:block";
+ break;
+ case "Sector":
+ hasParent = true;
+ parentStatus = contributable.crag.publishStatus;
+ approveRejectClass = "hidden @2xl:block";
+ break;
+ case "Crag":
+ approveRejectClass = "hidden @2xl:block";
+ break;
+ }
+
+ return (
+
+ {currentUser?.roles.includes("admin") ? (
+ <>
+ {/* editor user */}
+ {contributable.publishStatus === "draft" && (
+ <>
+ {/* publish */}
+
setPublishDialogIsOpen(true)}
+ >
+
+
+ Objavi
+
+
+ >
+ )}
+
+ {contributable.publishStatus === "in_review" && (
+ <>
+ {/* approve */}
+
setPublishDialogIsOpen(true)}
+ >
+
+
+
+ Potrdi objavo
+
+
+
+
+ {/* divider */}
+
+
+ {/* reject */}
+
setRejectDialogIsOpen(true)}
+ >
+
+
+
+ Zavrni objavo
+
+
+
+
+ {/* reject publish dialog */}
+
+ >
+ )}
+
+ {/* publish / approve dialog */}
+
+ >
+ ) : (
+ <>
+ {/* regular user */}
+ {contributable.publishStatus === "draft" && (
+ <>
+ {/* suggest publish */}
+
setSuggestPublishDialogIsOpen(true)}
+ >
+
+
+
+ Predlagaj objavo
+
+
+
+ >
+ )}
+
+ {/* suggest publish dialog */}
+
+ >
+ )}
+
+ );
+}
+
+export default PublishStatusActions;
diff --git a/src/app/[lang]/admin/crags/components/reject-dialog.tsx b/src/app/[lang]/admin/crags/components/reject-dialog.tsx
new file mode 100644
index 00000000..ba61f266
--- /dev/null
+++ b/src/app/[lang]/admin/crags/components/reject-dialog.tsx
@@ -0,0 +1,170 @@
+import Dialog from "@/components/ui/dialog";
+import { Dispatch, SetStateAction, useState } from "react";
+import { useRouter } from "next/navigation";
+import { Crag, Route, Sector } from "@/graphql/generated";
+import updateRouteAction from "../[cragSlug]/sectors/[sectorId]/routes/lib/update-route-action";
+import updateSectorAction from "../[cragSlug]/sectors/lib/update-sector-action";
+import updateCragAction from "../[cragSlug]/edit/lib/update-crag-action";
+import Checkbox from "@/components/ui/checkbox";
+import TextArea from "@/components/ui/text-area";
+
+type TRejectDialogProps = {
+ isOpen: boolean;
+ setIsOpen: Dispatch>;
+ contributable: Route | Sector | Crag;
+};
+
+function RejectDialog({
+ isOpen,
+ setIsOpen,
+ contributable,
+}: TRejectDialogProps) {
+ const router = useRouter();
+
+ const [rejectionMessage, setRejectionMessage] = useState("");
+ const [rejectionMessageError, setRejectionMessageError] = useState("");
+
+ const [loading, setLoading] = useState(false);
+
+ let description = "";
+ let cascadeText = null;
+ let rejectionDescription = "";
+ switch (contributable.__typename) {
+ case "Route":
+ description = `Ali res želiš zavrniti objavo smeri `;
+ rejectionDescription =
+ "Razlog za zavrnitev objave smeri bo posredovan osebi, ki je predlagala objavo. Na podlagi tega sporočila bo lahko smer uredila tako, da bo primerna za objavo.";
+ break;
+
+ case "Sector":
+ description = `Ali res želiš zavrniti objavo sektorja `;
+ cascadeText = contributable.routes.length
+ ? "Zavrni tudi objavo vseh smeri v tem sektorju."
+ : null;
+ rejectionDescription =
+ "Razlog za zavrnitev objave sektorja bo posredovan osebi, ki je predlagala objavo. Na podlagi tega sporočila bo lahko sektor uredila tako, da bo primeren za objavo.";
+ break;
+
+ case "Crag":
+ description = `Ali res želiš zavrniti objavo plezališča `;
+
+ const crag = contributable;
+ if (
+ crag.sectors.length === 1 &&
+ crag.sectors[0].name === "" &&
+ crag.sectors[0].label === ""
+ ) {
+ // crag has a dummy sector
+ if (crag.sectors[0].routes.length) {
+ cascadeText = "Zavrni tudi objavo vseh smeri v tem plezališču.";
+ }
+ } else {
+ if (crag.sectors.length) {
+ cascadeText = "Zavrni tudi objavo vseh sektorjev v tem plezališču.";
+ }
+ if (crag.sectors.some((sector) => sector.routes.length)) {
+ cascadeText =
+ "Zavrni tudi objavo vseh sektorjev in vseh smeri v tem plezališču.";
+ }
+ }
+
+ rejectionDescription =
+ "Razlog za zavrnitev objave plezališča bo posredovan osebi, ki je predlagala objavo. Na podlagi tega sporočila bo lahko plezališče uredila tako, da bo primerno za objavo.";
+ break;
+ }
+
+ const handleRejectionMessageChange = (message: string) => {
+ setRejectionMessageError("");
+ setRejectionMessage(message);
+ };
+
+ const handleConfirm = async () => {
+ setLoading(true);
+
+ // Validate form
+ // - rejection message is required
+ if (!rejectionMessage) {
+ setRejectionMessageError("Razlog za zavrnitev je obvezen podatek.");
+ setLoading(false);
+ return;
+ }
+
+ const data = {
+ id: contributable.id,
+ publishStatus: "draft",
+ ...(contributable.__typename !== "Route" && {
+ cascadePublishStatus: true,
+ }),
+ rejectionMessage: rejectionMessage,
+ };
+
+ switch (contributable.__typename) {
+ case "Route":
+ await updateRouteAction(data);
+ break;
+ case "Sector":
+ await updateSectorAction(data);
+ break;
+ case "Crag":
+ await updateCragAction(data);
+ }
+
+ setIsOpen(false);
+ setLoading(false);
+
+ if (contributable.__typename === "Crag") {
+ // if we are rejecting a crag, redirect to home, since a rejected (now draft again) crag is not visible to the current user
+ router.push(`/`);
+ // TODO: when (if) there is an edit all crags page, redirect there.
+ } else {
+ router.refresh();
+ }
+ };
+
+ return (
+
+
+
+ {description}
+ {contributable.name} ?
+
+
+
+
+
+
+ {cascadeText && (
+
+ {}}
+ />
+
+ )}
+
+
+ );
+}
+
+export default RejectDialog;
diff --git a/src/app/[lang]/admin/crags/components/suggest-publish-dialog.tsx b/src/app/[lang]/admin/crags/components/suggest-publish-dialog.tsx
new file mode 100644
index 00000000..babf04e9
--- /dev/null
+++ b/src/app/[lang]/admin/crags/components/suggest-publish-dialog.tsx
@@ -0,0 +1,145 @@
+import Dialog, { DialogSize } from "@/components/ui/dialog";
+import { Dispatch, SetStateAction, useState } from "react";
+import { useRouter } from "next/navigation";
+import { Crag, Route, Sector } from "@/graphql/generated";
+import updateRouteAction from "../[cragSlug]/sectors/[sectorId]/routes/lib/update-route-action";
+import updateSectorAction from "../[cragSlug]/sectors/lib/update-sector-action";
+import updateCragAction from "../[cragSlug]/edit/lib/update-crag-action";
+import Checkbox from "@/components/ui/checkbox";
+
+type TSuggestPublishDialogProps = {
+ isOpen: boolean;
+ setIsOpen: Dispatch>;
+ contributable: Route | Sector | Crag;
+};
+
+function SuggestPublishDialog({
+ isOpen,
+ setIsOpen,
+ contributable,
+}: TSuggestPublishDialogProps) {
+ const router = useRouter();
+
+ const [cascadePublish, setCascadePublish] = useState(true);
+ const [loading, setLoading] = useState(false);
+
+ let description = "";
+ let cascadeText = null;
+ switch (contributable.__typename) {
+ case "Route":
+ description = `Ali res želiš uredništvu predlagati objavo smeri `;
+ break;
+
+ case "Sector":
+ description = `Ali res želiš uredništvu predlagati objavo sektorja `;
+ cascadeText = contributable.routes.length
+ ? "Predlagaj tudi objavo vseh smeri v tem sektorju."
+ : null;
+ break;
+
+ case "Crag":
+ description = `Ali res želiš uredništvu predlagati objavo plezališča `;
+
+ const crag = contributable;
+ if (
+ crag.sectors.length === 1 &&
+ crag.sectors[0].name === "" &&
+ crag.sectors[0].label === ""
+ ) {
+ // crag has a dummy sector
+ if (crag.sectors[0].routes.length) {
+ cascadeText = "Predlagaj tudi objavo vseh smeri v tem plezališču.";
+ }
+ } else {
+ if (crag.sectors.length) {
+ cascadeText =
+ "Predlagaj tudi objavo vseh sektorjev v tem plezališču.";
+ }
+ if (crag.sectors.some((sector) => sector.routes.length)) {
+ cascadeText =
+ "Predlagaj tudi objavo vseh sektorjev in vseh smeri v tem plezališču.";
+ }
+ }
+ break;
+ }
+
+ const handleConfirm = async () => {
+ setLoading(true);
+
+ const data = {
+ id: contributable.id,
+ publishStatus: "in_review",
+ ...(contributable.__typename !== "Route" && {
+ cascadePublishStatus: cascadePublish,
+ }),
+ };
+
+ switch (contributable.__typename) {
+ case "Route":
+ await updateRouteAction(data);
+ break;
+ case "Sector":
+ await updateSectorAction(data);
+ break;
+ case "Crag":
+ await updateCragAction(data);
+
+ // If this is a sectorless crag, crag has a dummy sector and it's publish status also needs to be updated (despite cascadePublishStatus flag being false)
+ const crag = contributable;
+ if (
+ !cascadePublish &&
+ crag.sectors.length === 1 &&
+ crag.sectors[0].name === "" &&
+ crag.sectors[0].label === ""
+ ) {
+ const updateSectorData = {
+ id: crag.sectors[0].id,
+ publishStatus: "in_review",
+ };
+ await updateSectorAction(updateSectorData);
+ }
+ break;
+ }
+
+ setIsOpen(false);
+ setLoading(false);
+ router.refresh();
+ };
+
+ return (
+
+
+
+ {description}
+ {contributable.name} ?
+
+
+ {cascadeText && (
+
+
+
+ )}
+
+
+ );
+}
+
+export default SuggestPublishDialog;
diff --git a/src/app/[lang]/admin/crags/lib/delete-crag-action.ts b/src/app/[lang]/admin/crags/lib/delete-crag-action.ts
new file mode 100644
index 00000000..93e72452
--- /dev/null
+++ b/src/app/[lang]/admin/crags/lib/delete-crag-action.ts
@@ -0,0 +1,30 @@
+"use server";
+
+import { gql } from "urql/core";
+import urqlServer from "@/graphql/urql-server";
+import { DeleteCragDocument } from "@/graphql/generated";
+import { revalidatePath } from "next/cache";
+
+async function deleteCragAction(cragId: string) {
+ const result = await urqlServer().mutation(DeleteCragDocument, {
+ id: cragId,
+ });
+
+ // TODO: check for known errors. one of them being: crag_has_log_entries. display error how?
+
+ if (result.error) {
+ console.error(result.error);
+ throw new Error("Pri brisanju plezališča je prišlo do napake.");
+ }
+
+ revalidatePath("crags", "page");
+ return result.data.deleteCrag;
+}
+
+export default deleteCragAction;
+
+gql`
+ mutation DeleteCrag($id: String!) {
+ deleteCrag(id: $id)
+ }
+`;
diff --git a/src/app/[lang]/crag/[cragSlug]/(crag)/gallery/page.tsx b/src/app/[lang]/crag/[cragSlug]/(crag)/gallery/page.tsx
index d3901a9d..4c12716c 100644
--- a/src/app/[lang]/crag/[cragSlug]/(crag)/gallery/page.tsx
+++ b/src/app/[lang]/crag/[cragSlug]/(crag)/gallery/page.tsx
@@ -14,7 +14,7 @@ async function CragGalleryPage({ params }: { params: TCragGalleryPageParams }) {
});
const images = data.cragBySlug.images as Image[];
- const imagesBaseUrl = `${process.env.IMAGES_PROTOCOL}://${process.env.IMAGES_HOSTNAME}${process.env.IMAGES_PATHNAME}`;
+ const imagesBaseUrl = `${process.env.NEXT_PUBLIC_IMAGES_BASEURL}`;
return (
diff --git a/src/app/[lang]/crag/[cragSlug]/(crag)/info/page.tsx b/src/app/[lang]/crag/[cragSlug]/(crag)/info/page.tsx
index f9e973e7..59971126 100644
--- a/src/app/[lang]/crag/[cragSlug]/(crag)/info/page.tsx
+++ b/src/app/[lang]/crag/[cragSlug]/(crag)/info/page.tsx
@@ -23,7 +23,9 @@ import IconMissing from "@/components/ui/icons/missing";
import Link from "@/components/ui/link";
import { IconSize } from "@/components/ui/icons/icon-size";
import IconMore from "@/components/ui/icons/more";
-import MapMarker from "@/components/map/map-marker";
+import { TLazyMapMarkerProps } from "@/components/map/lazy-map-marker";
+import DropdownMenu, { DropdownMenuItem } from "@/components/ui/dropdown-menu";
+import Button from "@/components/ui/button";
type TCragInfoPageParams = {
cragSlug: string;
@@ -69,8 +71,6 @@ async function CragInfoPage({ params }: { params: TCragInfoPageParams }) {
routeLengths.length ? Math.max(...routeLengths) : null,
];
- const imagesBaseUrl = `${process.env.IMAGES_PROTOCOL}://${process.env.IMAGES_HOSTNAME}${process.env.IMAGES_PATHNAME}`;
-
// Find out if any data depicted with icons is missing and if so, construct appropriate messages.
const iconDataMissing: string[] = [];
@@ -132,25 +132,20 @@ async function CragInfoPage({ params }: { params: TCragInfoPageParams }) {
minimumFractionDigits: 5,
});
- // Construct array of all parkings and walls markers
- const markers = Object.entries(parkings).map(
- ([id, { lat, lon, sectors }]) => (
-
}
- />
- )
+ // Construct array of all parkings and walls markers data
+ const markersData: TLazyMapMarkerProps[] = Object.entries(parkings).map(
+ ([_id, { lat, lon, sectors }]) => ({
+ type: "parking",
+ position: [lat, lon],
+ popupContent:
,
+ })
);
if (crag.lat && crag.lon) {
- markers.push(
-
{`Plezališče ${crag.name}`} }
- />
- );
+ markersData.push({
+ type: "wall",
+ position: [crag.lat, crag.lon],
+ popupContent: {`Plezališče ${crag.name}`}
,
+ });
}
return (
@@ -177,7 +172,19 @@ async function CragInfoPage({ params }: { params: TCragInfoPageParams }) {
-
+
+
+
+ }
+ >
+
+ Uredi plezališče
+
+
@@ -204,7 +211,7 @@ async function CragInfoPage({ params }: { params: TCragInfoPageParams }) {
{crag.coverImage ? (
- {markers.length > 0 && (
-
+ {markersData.length > 0 && (
+
)}
diff --git a/src/app/[lang]/edit/(crag)/[cragSlug]/sectors/components/edit-sectors/edit-sectors-none.tsx b/src/app/[lang]/edit/(crag)/[cragSlug]/sectors/components/edit-sectors/edit-sectors-none.tsx
deleted file mode 100644
index d7ba96d4..00000000
--- a/src/app/[lang]/edit/(crag)/[cragSlug]/sectors/components/edit-sectors/edit-sectors-none.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-"use client";
-
-import Button from "@/components/ui/button";
-import Checkbox from "@/components/ui/checkbox";
-import IconRoutes from "@/components/ui/icons/routes";
-
-function EditSectorsNone() {
- const handleCragHasSectorsChange = () => {};
- const handleEditRoutesButtonClick = () => {};
-
- return (
-
-
-
-
-
-
- Uredi smeri
-
-
-
- );
-}
-
-export default EditSectorsNone;
diff --git a/src/app/[lang]/edit/(crag)/[cragSlug]/sectors/components/edit-sectors/sector-card.tsx b/src/app/[lang]/edit/(crag)/[cragSlug]/sectors/components/edit-sectors/sector-card.tsx
deleted file mode 100644
index a11a0b8a..00000000
--- a/src/app/[lang]/edit/(crag)/[cragSlug]/sectors/components/edit-sectors/sector-card.tsx
+++ /dev/null
@@ -1,135 +0,0 @@
-import Button from "@/components/ui/button";
-import IconDelete from "@/components/ui/icons/delete";
-import IconDrag from "@/components/ui/icons/drag";
-import IconEdit from "@/components/ui/icons/edit";
-import { IconSize } from "@/components/ui/icons/icon-size";
-import IconMore from "@/components/ui/icons/more";
-import IconPlus from "@/components/ui/icons/plus";
-import IconRoutes from "@/components/ui/icons/routes";
-import { useSortable } from "@dnd-kit/sortable";
-import { CSS } from "@dnd-kit/utilities";
-
-type TSectorCardProps = {
- id: string;
- name: string;
- disabled?: boolean;
- onAddClick: () => void;
- onEditClick: () => void;
- onDeleteClick: () => void;
-};
-
-function SectorCard({
- id,
- name,
- disabled,
- onAddClick,
- onEditClick,
- onDeleteClick,
-}: TSectorCardProps) {
- const moreAction = (
- {}}>
-
-
- );
-
- const {
- attributes,
- listeners,
- setNodeRef,
- transform,
- transition,
- isDragging,
- } = useSortable({ id });
-
- const style = {
- transform: CSS.Transform.toString(transform),
- transition,
- };
-
- return (
-
-
- {/* drag handle, name and menu */}
-
-
-
- {}}
- >
-
-
-
-
{name}
-
-
{moreAction}
-
-
- {/* actions */}
-
-
- {/* edit routes */}
-
{}}>
-
-
-
- {/* divider */}
-
-
-
{moreAction}
-
- {/* divider */}
-
-
- {/* edit */}
-
-
-
-
- {/* divider */}
-
-
- {/* edit */}
-
-
-
-
- {/* divider */}
-
-
- {/* add sector */}
-
-
-
-
-
-
-
- );
-}
-
-export default SectorCard;
diff --git a/src/app/[lang]/edit/(crag)/components/crag-form.tsx b/src/app/[lang]/edit/(crag)/components/crag-form.tsx
deleted file mode 100644
index a03fb92c..00000000
--- a/src/app/[lang]/edit/(crag)/components/crag-form.tsx
+++ /dev/null
@@ -1,562 +0,0 @@
-"use client";
-
-import Button from "@/components/ui/button";
-import IconAutumn from "@/components/ui/icons/autumn";
-import { IconSize } from "@/components/ui/icons/icon-size";
-import IconOverhang from "@/components/ui/icons/overhang";
-import IconRoof from "@/components/ui/icons/roof";
-import IconSlab from "@/components/ui/icons/slab";
-import IconSpring from "@/components/ui/icons/spring";
-import IconSummer from "@/components/ui/icons/summer";
-import IconVertical from "@/components/ui/icons/vertical";
-import IconWinter from "@/components/ui/icons/winter";
-import { Radio, RadioGroup } from "@/components/ui/radio-group";
-import { Select, Option } from "@/components/ui/select";
-import { Selector, SelectorOption } from "@/components/ui/selector";
-import TextArea from "@/components/ui/text-area";
-import TextField from "@/components/ui/text-field";
-import {
- Country,
- Crag,
- Orientation,
- Season,
- WallAngle,
-} from "@/graphql/generated";
-import { useRef, useState } from "react";
-import { gradingSystems } from "../../../../../lib/grading-systems";
-import CoordinatesInput, {
- formatCoordinates,
- validateCoordinates,
-} from "@/components/ui/coordinates-input";
-import Checkbox from "@/components/ui/checkbox";
-import { useRouter } from "next/navigation";
-import createCragAction from "../new-crag/lib/create-crag-action";
-import updateCragAction from "../[cragSlug]/lib/update-crag-action";
-
-type TCragFormProps = {
- formType: "edit" | "new";
- countriesWithAreas: Country[];
- crag?: Crag;
-};
-
-function CragForm({ formType, countriesWithAreas, crag }: TCragFormProps) {
- // Determine default/initial values for all form fields
- let defaultValues;
- if (formType == "edit" && crag) {
- defaultValues = {
- name: crag.name,
- country: crag.country.id,
- area: crag.area ? crag.area.id : "",
- cragType: crag.type,
- gradingSystem: crag.defaultGradingSystem
- ? crag.defaultGradingSystem.id
- : "",
- cragCoordinates:
- crag.lat && crag.lon ? formatCoordinates(crag.lat, crag.lon) : "",
- cragDescription: crag.description || "",
- wallAngles: crag.wallAngles || [],
- rainproof: crag.rainproof !== null ? (crag.rainproof ? "yes" : "no") : "",
- orientations: crag.orientations || [],
- seasons: crag.seasons || [],
- parkingCoordinates: "", // TODO
- approachTime: crag.approachTime !== null ? `${crag.approachTime}` : "",
- approachDescription: crag.access || "",
- isHidden: crag.isHidden || false,
- };
- } else {
- defaultValues = {
- name: "",
- country: countriesWithAreas.find((c) => c.slug == "slovenija")?.id || "",
- area: "",
- cragType: "sport",
- gradingSystem: "french",
- cragCoordinates: "",
- cragDescription: "",
- wallAngles: [],
- rainproof: "",
- orientations: [],
- seasons: [],
- parkingCoordinates: "",
- approachTime: "",
- approachDescription: "",
- isHidden: false,
- };
- }
-
- const [name, setName] = useState(defaultValues.name);
- const [nameError, setNameError] = useState("");
- const nameRef = useRef(null);
-
- const [country, setCountry] = useState(defaultValues.country);
- const [area, setArea] = useState(defaultValues.area);
- const [cragType, setCragType] = useState(defaultValues.cragType);
- const [gradingSystem, setGradingSystem] = useState(
- defaultValues.gradingSystem
- );
-
- const [cragCoordinates, setCragCoordinates] = useState(
- defaultValues.cragCoordinates
- );
- const [cragCoordinatesError, setCragCoordinatesError] = useState("");
- const cragCoordinatesRef = useRef(null);
-
- const [cragDescription, setCragDescription] = useState(
- defaultValues.cragDescription
- );
- const [wallAngles, setWallAngles] = useState(
- defaultValues.wallAngles
- );
- const [rainproof, setRainproof] = useState(
- defaultValues.rainproof
- );
- const [orientations, setOrientations] = useState(
- defaultValues.orientations
- );
- const [seasons, setSeasons] = useState(defaultValues.seasons);
-
- const [parkingCoordinates, setParkingCoordinates] = useState(
- defaultValues.parkingCoordinates
- );
- const [parkingCoordinatesError, setParkingCoordinatesError] = useState("");
- const parkingCoordinatesRef = useRef(null);
-
- const [approachTime, setApproachTime] = useState(defaultValues.approachTime);
- const [approachDescription, setApproachDescription] = useState(
- defaultValues.approachDescription
- );
- const [isHidden, setIsHidden] = useState(defaultValues.isHidden);
-
- const [loading, setLoading] = useState(false);
-
- const router = useRouter();
-
- const handleNameChange = (name: string) => {
- setName(name);
- setNameError("");
- };
-
- const handleCountryChange = (country: string) => {
- setCountry(country);
- setArea("");
- };
-
- const areas = countriesWithAreas.find((c) => c.id === country)?.areas;
-
- const availableGradingSystems = Object.values(gradingSystems).filter((gs) => {
- // crag type sport
- if (cragType == "sport") {
- return gs.routeTypes.some((rt) =>
- ["sport", "multipitch", "boulder"].includes(rt.id)
- );
- }
- // crag type alpine
- else {
- return gs.routeTypes.some((rt) => rt.id == "alpine");
- }
- });
-
- const handleCragTypeChange = (cragType: string) => {
- setGradingSystem("");
- setCragType(cragType);
- };
-
- const handleCragCoordinatesChange = (coordinates: string) => {
- setCragCoordinates(coordinates);
- setCragCoordinatesError("");
- };
-
- const handleFormAction = async () => {
- setLoading(true);
-
- // Validate form
- const errorRefs = []; // to determine if any errors and where to scroll to
- // - name is required
- if (!name) {
- setNameError("Ime plezališča je obvezen podatek.");
- errorRefs.push(nameRef);
- }
-
- // - value of coordinates field needs to be two numbers separated by comma, dot or space
- let cragLat, cragLon;
- if (cragCoordinates) {
- const validatedCragCoordinates = validateCoordinates(cragCoordinates);
- if (validatedCragCoordinates) {
- [cragLat, cragLon] = validatedCragCoordinates.value;
- } else {
- setCragCoordinatesError(
- "Nepravilna oblika. Koordinate vnesi v obliki: 45,56801, 13,86413"
- );
- errorRefs.push(cragCoordinatesRef);
- }
- }
-
- let parkingLat, parkingLon; // TODO: save these where?
- if (parkingCoordinates) {
- const validatedParkingCoordinates =
- validateCoordinates(parkingCoordinates);
- if (validatedParkingCoordinates) {
- [parkingLat, parkingLon] = validatedParkingCoordinates.value;
- } else {
- setParkingCoordinatesError(
- "Nepravilna oblika. Koordinate vnesi v obliki: 45,56719, 13,86265"
- );
- errorRefs.push(parkingCoordinatesRef);
- }
- }
-
- if (errorRefs.length > 0) {
- setLoading(false);
- errorRefs.shift()?.current?.scrollIntoView({ behavior: "smooth" });
- return;
- }
-
- const cragData = {
- name: name,
- countryId: country,
- areaId: area || null,
- type: cragType,
- defaultGradingSystemId: gradingSystem,
- lat: cragLat || null,
- lon: cragLon || null,
- description: cragDescription || null,
- wallAngles: wallAngles.length ? (wallAngles as WallAngle[]) : null,
- rainproof: rainproof == "yes" ? true : rainproof == "no" ? false : null,
- orientations: orientations.length
- ? (orientations as Orientation[])
- : null,
- seasons: seasons.length ? (seasons as Season[]) : null,
- // parkingLat, parkingLon // TODO:
- approachTime: +approachTime || null,
- access: approachDescription || null,
- // coverImageId: null, //TODO:
- isHidden: isHidden,
- };
-
- let savedCrag;
- switch (formType) {
- case "new":
- const newCragData = {
- ...cragData,
- publishStatus: "draft", // a new crag is initially always a draft
- };
-
- savedCrag = await createCragAction(newCragData);
- break;
- case "edit":
- const updateCragData = {
- ...cragData,
- id: crag!.id,
- };
-
- savedCrag = await updateCragAction(updateCragData);
- }
-
- router.push(savedCrag.slug);
- setLoading(false);
- };
-
- return (
-
-
-
- {/* Main grid for inputs layout */}
-
- {/* Crag name */}
-
-
-
-
- {/* Country */}
-
-
- {countriesWithAreas.map((country) => (
-
- {country.name}
-
- ))}
-
-
- {/* Area */}
-
-
- {areas?.length
- ? areas.map((area) => (
-
- {area.name}
-
- ))
- : [1, 2].map((_) => (
-
- {" "}
-
- ))}
-
-
-
- {/* Crag type */}
-
-
- športno / balvani / dolge športne
- alpinizem
-
-
- {/* Default grading system */}
-
-
- {availableGradingSystems.map((gs) => (
-
- {gs.name}
-
- ))}
-
-
-
- {/* Crag coordinates */}
-
-
-
-
- {/* Horizontal divider */}
-
-
- {/* Crag description */}
-
-
-
-
- {/* Wall angles */}
-
-
-
-
-
- plošče
-
-
-
-
-
- vertikale
-
-
-
-
-
- previsi
-
-
-
-
-
- strehe
-
-
-
-
-
- {/* Rainproof */}
-
-
- je možno
- ni možno
- ni znano
-
-
-
- {/* Horizontal divider */}
-
-
- {/* Orientations */}
-
-
- sever
- severovzhod
- vzhod
- jugovzhod
- jug
- jugozahod
- zahod
- severozahod
-
-
-
- {/* Seasons */}
-
-
-
-
-
- pomlad
-
-
-
-
-
- poletje
-
-
-
-
-
- jesen
-
-
-
-
-
- zima
-
-
-
-
-
- {/* Parking coordinates */}
-
-
-
- {/* Approach time */}
-
- min}
- disabled={loading}
- />
-
-
- {/* Approach description */}
-
-
-
-
- {/* Horizontal divider */}
-
-
- {/* Cover image */}
-
-
Naslovna fotografija
-
-
- {/* Visibility */}
-
-
- {/* Horizontal divider */}
-
-
-
-
- Prekliči
-
-
- Shrani
-
-
-
-
-
-
- );
-}
-
-export default CragForm;
diff --git a/src/app/sandbox/dropdown-menu/page.tsx b/src/app/sandbox/dropdown-menu/page.tsx
new file mode 100644
index 00000000..44a0747f
--- /dev/null
+++ b/src/app/sandbox/dropdown-menu/page.tsx
@@ -0,0 +1,79 @@
+"use client";
+
+import Button from "@/components/ui/button";
+import DropdownMenu, { DropdownMenuItem } from "@/components/ui/dropdown-menu";
+import { IconSize } from "@/components/ui/icons/icon-size";
+import IconMore from "@/components/ui/icons/more";
+
+function DropdownMenuPage() {
+ return (
+
+
Dropdown menu demo
+
+
First menu on the left side of the page
+
+
+
+
+
+ }
+ >
+ {
+ console.log("Dodaj clicked in menu 1");
+ }}
+ >
+ Dodaj plezališče
+
+ Dodaj fotografijo
+ Uredi profil
+ Izbriši podatke
+
+
+
+
+
+
Second menu on the right side of the page
+
+ Open menu}
+ >
+ {
+ console.log("Dodaj clicked in menu 2");
+ }}
+ >
+ Dodaj plezališče
+
+ Dodaj fotografijo
+ Uredi profil
+ Izbriši podatke
+
+
+
+
+
+
Notes
+
+
+ Menu item can be a nextjs link or a button.
+ If a href is passed it will be a link.
+ If an onClick is passed it will be a button.
+
+ In the example above, first item is a button, second item is
+ disabled, third is a link, fourth is not wired.
+
+
+ Menu will be aligned to the bottom left of a button and will be
+ pushed from the right if not enough space in viewport.
+
+
+
+
+
+ );
+}
+
+export default DropdownMenuPage;
diff --git a/src/app/sandbox/radio-group/page.tsx b/src/app/sandbox/radio-group/page.tsx
index 10bbb9d0..1d5c7267 100644
--- a/src/app/sandbox/radio-group/page.tsx
+++ b/src/app/sandbox/radio-group/page.tsx
@@ -37,7 +37,10 @@ function RadioGroupPage() {
{/* example with error message */}
-
+
Krvavica
Pleskavica
Klobasa
@@ -48,7 +51,7 @@ function RadioGroupPage() {
Krvavica
diff --git a/src/app/sandbox/select/page.tsx b/src/app/sandbox/select/page.tsx
index a7acd20b..0cdf8b6f 100644
--- a/src/app/sandbox/select/page.tsx
+++ b/src/app/sandbox/select/page.tsx
@@ -1,11 +1,11 @@
"use client";
+
import { IconSize } from "@/components/ui/icons/icon-size";
import Button from "@/components/ui/button";
import IconColumns from "@/components/ui/icons/columns";
import IconStarFull from "@/components/ui/icons/star-full";
import { Select, Option } from "@/components/ui/select";
import { gradingSystems } from "../../../lib/grading-systems";
-
import { useState } from "react";
import IconRepeat from "@/components/ui/icons/repeat";
diff --git a/src/components/map/lazy-map.tsx b/src/components/map/lazy-map.tsx
index 8e3bb6e1..49e810d9 100644
--- a/src/components/map/lazy-map.tsx
+++ b/src/components/map/lazy-map.tsx
@@ -3,12 +3,14 @@
import { MapContainer, TileLayer } from "react-leaflet";
import L, { FitBoundsOptions } from "leaflet";
import "leaflet/dist/leaflet.css";
-import { Fragment, ReactElement, ReactNode } from "react";
+import { ReactNode } from "react";
import "./map.css";
+import MapMarker from "./map-marker";
+import { TLazyMapMarkerProps } from "./lazy-map-marker";
type TLazyMapProps = {
children?: ReactNode;
- markers?: ReactElement[];
+ markersData?: TLazyMapMarkerProps[];
className?: string;
center?: [number, number];
zoom?: number;
@@ -18,7 +20,7 @@ type TLazyMapProps = {
function LazyMap({
children,
- markers,
+ markersData,
className,
center,
zoom,
@@ -38,10 +40,9 @@ function LazyMap({
boundsOptions?: FitBoundsOptions;
zoom?: number;
} = {};
- if (autoBounds && markers) {
- boundsOrCenterAndZoom.bounds = markers.map(
- (marker) => marker.props.position
- );
+
+ if (autoBounds && markersData) {
+ boundsOrCenterAndZoom.bounds = markersData.map(({ position }) => position);
boundsOrCenterAndZoom.boundsOptions = { padding: [30, 60] };
} else {
boundsOrCenterAndZoom.center = center;
@@ -59,8 +60,13 @@ function LazyMap({
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
- {markers?.map((marker, index) => (
- {marker}
+ {markersData?.map(({ type, position, popupContent }, index) => (
+
))}
{children}
diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx
index 5e411805..a723a216 100644
--- a/src/components/ui/dialog.tsx
+++ b/src/components/ui/dialog.tsx
@@ -100,12 +100,12 @@ function Dialog({
{/* The backdrop, rendered as a fixed sibling to the panel container */}
{/* Full-screen container to center the panel */}
-
+
diff --git a/src/components/ui/dropdown-menu.tsx b/src/components/ui/dropdown-menu.tsx
new file mode 100644
index 00000000..750de93c
--- /dev/null
+++ b/src/components/ui/dropdown-menu.tsx
@@ -0,0 +1,72 @@
+import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react";
+import Link, { LinkProps } from "next/link";
+import { ReactNode } from "react";
+
+type TDropdownMenuProps = {
+ openTrigger: ReactNode;
+ children: ReactNode[] | ReactNode;
+};
+
+function DropdownMenu({ openTrigger, children }: TDropdownMenuProps) {
+ return (
+
+
+ {openTrigger}
+
+
+
+ {children}
+
+
+ );
+}
+
+type TDropdownMenuItemBaseProps = {
+ disabled?: boolean;
+ children: string;
+};
+
+type TDropdownMenuItemButtonProps = TDropdownMenuItemBaseProps & {
+ onClick?: () => void;
+ href?: never;
+};
+
+type TDropdownMenuItemLinkProps = TDropdownMenuItemBaseProps & {
+ href?: LinkProps["href"];
+ onClick?: never;
+};
+
+type TDropdownMenuItemProps =
+ | TDropdownMenuItemButtonProps
+ | TDropdownMenuItemLinkProps;
+
+function DropdownMenuItem({
+ disabled,
+ onClick,
+ href,
+ children,
+}: TDropdownMenuItemProps) {
+ const classNames =
+ "w-auto px-4 py-2 text-left outline-none active:text-neutral-600 data-[active]:bg-neutral-100 focus-visible:border-l-4 focus-visible:pl-3 focus-visible:border-blue-100 data-[disabled]:text-neutral-400 data-[disabled]:bg-white data-[disabled]:cursor-default";
+
+ return (
+
+ {href ? (
+
+ {children}
+
+ ) : (
+
+ {children}
+
+ )}
+
+ );
+}
+
+export default DropdownMenu;
+export { DropdownMenuItem };
diff --git a/src/components/ui/icons/image-no-border.tsx b/src/components/ui/icons/image.tsx
similarity index 81%
rename from src/components/ui/icons/image-no-border.tsx
rename to src/components/ui/icons/image.tsx
index 6b20285d..f012b9a9 100644
--- a/src/components/ui/icons/image-no-border.tsx
+++ b/src/components/ui/icons/image.tsx
@@ -1,4 +1,4 @@
-function ImageNoBorder() {
+function IconImage() {
return (
>;
+ onChange?: (value: string) => void;
label?: string;
description?: string;
defaultValue?: string;
disabled?: boolean;
- error?: string;
+ errorMessage?: string;
inline?: boolean;
children: ReactNode[];
};
@@ -27,7 +27,7 @@ function RadioGroup({
description,
defaultValue,
disabled,
- error,
+ errorMessage,
inline,
children,
}: TRadioGroupProps) {
@@ -49,11 +49,13 @@ function RadioGroup({
{children}
- {description && (
+ {description && !errorMessage && (
{description}
)}
- {error &&
{error}
}
+ {errorMessage && (
+
{errorMessage}
+ )}
);
}
@@ -78,38 +80,7 @@ function Radio({ value, disabled, children }: TRadioProps) {
aria-hidden="true"
className={`rounded-lg ${focus ? "ring ring-blue-100" : ""}`}
>
- {/* radio circle (outer) */}
-
- {/* radio dot (inner) */}
- {checked && (
-
- )}
-
+
@@ -121,4 +92,44 @@ function Radio({ value, disabled, children }: TRadioProps) {
);
}
-export { RadioGroup, Radio };
+type TRadioCircleProps = {
+ checked: boolean;
+ disabled: boolean;
+};
+
+function RadioCircle({ checked, disabled }: TRadioCircleProps) {
+ return (
+
+ );
+}
+
+export { RadioGroup, Radio, RadioCircle };
diff --git a/src/components/ui/select.tsx b/src/components/ui/select.tsx
index d0880eb2..029169b9 100644
--- a/src/components/ui/select.tsx
+++ b/src/components/ui/select.tsx
@@ -48,6 +48,7 @@ type SelectProps = {
label?: string;
placeholder?: string;
description?: string;
+ errorMessage?: string;
multi?: boolean;
customTrigger?: ReactElement;
disabled?: boolean;
@@ -61,6 +62,7 @@ function Select({
label,
placeholder,
description,
+ errorMessage,
multi,
customTrigger,
disabled,
@@ -116,6 +118,7 @@ function Select({
value={value}
placeholder={placeholder}
description={description}
+ errorMessage={errorMessage}
constructSelectedLabel={constructSelectedLabel}
open={open}
childrenValuesToIndexes={childrenValuesToIndexes}
@@ -143,6 +146,7 @@ function InnerListBox({
value,
placeholder,
description,
+ errorMessage,
constructSelectedLabel,
open,
childrenValuesToIndexes,
@@ -165,13 +169,20 @@ function InnerListBox({
{customTrigger}
) : (
{!!value?.length ? (
@@ -189,9 +200,12 @@ function InnerListBox({
)}
- {description && (
+ {description && !errorMessage && (
{description}
)}
+ {errorMessage && (
+ {errorMessage}
+ )}
;
+export const EditCragPageCountriesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditCragPageCountries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"countries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"areas"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]}}]} as unknown as DocumentNode;
+export const EditCragPageCragDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditCragPageCrag"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"cragSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cragBySlug"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"cragSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"country"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"area"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"defaultGradingSystem"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"lat"}},{"kind":"Field","name":{"kind":"Name","value":"lon"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"wallAngles"}},{"kind":"Field","name":{"kind":"Name","value":"rainproof"}},{"kind":"Field","name":{"kind":"Name","value":"orientations"}},{"kind":"Field","name":{"kind":"Name","value":"seasons"}},{"kind":"Field","name":{"kind":"Name","value":"approachTime"}},{"kind":"Field","name":{"kind":"Name","value":"access"}},{"kind":"Field","name":{"kind":"Name","value":"isHidden"}},{"kind":"Field","name":{"kind":"Name","value":"coverImage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"path"}},{"kind":"Field","name":{"kind":"Name","value":"extension"}},{"kind":"Field","name":{"kind":"Name","value":"maxIntrinsicWidth"}},{"kind":"Field","name":{"kind":"Name","value":"aspectRatio"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"path"}},{"kind":"Field","name":{"kind":"Name","value":"extension"}},{"kind":"Field","name":{"kind":"Name","value":"maxIntrinsicWidth"}},{"kind":"Field","name":{"kind":"Name","value":"aspectRatio"}}]}},{"kind":"Field","name":{"kind":"Name","value":"publishStatus"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"fullName"}}]}},{"kind":"Field","name":{"kind":"Name","value":"sectors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"routes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]}}]} as unknown as DocumentNode;
+export const CreateRouteDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateRoute"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateRouteInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createRoute"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode;
+export const DeleteRouteDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteRoute"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteRoute"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}]}]}}]} as unknown as DocumentNode;
+export const DeleteRoutesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteRoutes"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"ids"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteRoutes"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"ids"},"value":{"kind":"Variable","name":{"kind":"Name","value":"ids"}}}]}]}}]} as unknown as DocumentNode;
+export const MergeRoutesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"MergeRoutes"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"MergeRoutesInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"mergeRoutes"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode;
+export const MoveRoutesToSectorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"MoveRoutesToSector"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"MoveRoutesToSectorInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"moveRoutesToSector"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode;
+export const UpdateRouteDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateRoute"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateRouteInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateRoute"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode;
+export const UpdateRoutesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateRoutes"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateRouteInput"}}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateRoutes"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode;
+export const EditRoutesPageSectorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditRoutesPageSector"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sector"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"crag"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"sectors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"routes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"routeType"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"difficulty"}},{"kind":"Field","name":{"kind":"Name","value":"defaultGradingSystem"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"length"}},{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"publishStatus"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"fullName"}}]}},{"kind":"Field","name":{"kind":"Name","value":"sector"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"publishStatus"}}]}}]}}]}}]}}]} as unknown as DocumentNode;
+export const CreateSectorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateSector"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateSectorInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createSector"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode;
+export const DeleteSectorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteSector"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteSector"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}]}]}}]} as unknown as DocumentNode;
+export const MergeAllSectorsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"MergeAllSectors"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"cragId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"mergeAllSectors"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"cragId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"cragId"}}}]}]}}]} as unknown as DocumentNode;
+export const UpdateSectorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateSector"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateSectorInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateSector"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode;
+export const EditSectorsPageCragDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditSectorsPageCrag"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"cragSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cragBySlug"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"cragSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"publishStatus"}},{"kind":"Field","name":{"kind":"Name","value":"sectors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"publishStatus"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"fullName"}}]}},{"kind":"Field","name":{"kind":"Name","value":"routes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"crag"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"publishStatus"}}]}}]}}]}}]}}]} as unknown as DocumentNode;
+export const CreateCragDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateCrag"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateCragInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createCrag"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]} as unknown as DocumentNode;
+export const NewCragPageCountriesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NewCragPageCountries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"countries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"areas"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]}}]} as unknown as DocumentNode;
+export const DeleteCragDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteCrag"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteCrag"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}]}]}}]} as unknown as DocumentNode;
export const HomeLatestAscentsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"HomeLatestAscents"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"activitiesInput"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"FindActivitiesInput"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"activityRoutesInput"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"FindActivityRoutesInput"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activities"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"activitiesInput"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"fullName"}}]}},{"kind":"Field","name":{"kind":"Name","value":"routes"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"activityRoutesInput"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"route"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"difficulty"}},{"kind":"Field","name":{"kind":"Name","value":"defaultGradingSystem"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"crag"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"ascentType"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"meta"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"itemCount"}},{"kind":"Field","name":{"kind":"Name","value":"pageCount"}},{"kind":"Field","name":{"kind":"Name","value":"pageNumber"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}}]}}]}}]}}]} as unknown as DocumentNode;
export const HomeLatestDifficultyVotesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"HomeLatestDifficultyVotes"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"LatestDifficultyVotesInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"latestDifficultyVotes"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"difficulty"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"route"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"difficulty"}},{"kind":"Field","name":{"kind":"Name","value":"defaultGradingSystem"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"crag"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"fullName"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}}]}}]}}]}}]}}]} as unknown as DocumentNode;
export const CreateCommentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateComment"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateCommentInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createComment"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode;
@@ -1456,15 +1475,6 @@ export const CragSectorsDocument = {"kind":"Document","definitions":[{"kind":"Op
export const MyCragSummaryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MyCragSummary"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"FindActivityRoutesInput"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"myCragSummary"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ascentType"}},{"kind":"Field","name":{"kind":"Name","value":"route"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]}}]} as unknown as DocumentNode;
export const AllCragsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AllCrags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"crags"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"type"},"value":{"kind":"StringValue","value":"sport","block":false}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"country"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}},{"kind":"Field","name":{"kind":"Name","value":"area"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"country"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"orientations"}},{"kind":"Field","name":{"kind":"Name","value":"minDifficulty"}},{"kind":"Field","name":{"kind":"Name","value":"maxDifficulty"}},{"kind":"Field","name":{"kind":"Name","value":"seasons"}},{"kind":"Field","name":{"kind":"Name","value":"rainproof"}},{"kind":"Field","name":{"kind":"Name","value":"wallAngles"}},{"kind":"Field","name":{"kind":"Name","value":"approachTime"}},{"kind":"Field","name":{"kind":"Name","value":"nrRoutesByGrade"}},{"kind":"Field","name":{"kind":"Name","value":"hasSport"}},{"kind":"Field","name":{"kind":"Name","value":"hasBoulder"}},{"kind":"Field","name":{"kind":"Name","value":"hasMultipitch"}},{"kind":"Field","name":{"kind":"Name","value":"nrRoutes"}}]}}]}}]} as unknown as DocumentNode;
export const AllCountriesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AllCountries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"countries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"nrCrags"}},{"kind":"Field","name":{"kind":"Name","value":"areas"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"nrCrags"}}]}}]}}]}}]} as unknown as DocumentNode;
-export const EditCragPageCountriesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditCragPageCountries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"countries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"areas"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]}}]} as unknown as DocumentNode;
-export const EditCragPageCragDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditCragPageCrag"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"cragSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cragBySlug"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"cragSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"country"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"area"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"defaultGradingSystem"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"lat"}},{"kind":"Field","name":{"kind":"Name","value":"lon"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"wallAngles"}},{"kind":"Field","name":{"kind":"Name","value":"rainproof"}},{"kind":"Field","name":{"kind":"Name","value":"orientations"}},{"kind":"Field","name":{"kind":"Name","value":"seasons"}},{"kind":"Field","name":{"kind":"Name","value":"approachTime"}},{"kind":"Field","name":{"kind":"Name","value":"access"}},{"kind":"Field","name":{"kind":"Name","value":"isHidden"}},{"kind":"Field","name":{"kind":"Name","value":"coverImage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"path"}},{"kind":"Field","name":{"kind":"Name","value":"extension"}},{"kind":"Field","name":{"kind":"Name","value":"maxIntrinsicWidth"}},{"kind":"Field","name":{"kind":"Name","value":"aspectRatio"}}]}}]}}]}}]} as unknown as DocumentNode;
-export const EditSectorsPageCragDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditSectorsPageCrag"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"cragSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cragBySlug"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"cragSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"sectors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"position"}}]}}]}}]}}]} as unknown as DocumentNode;
-export const CreateSectorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateSector"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateSectorInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createSector"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode;
-export const DeleteSectorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteSector"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteSector"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}]}]}}]} as unknown as DocumentNode;
-export const UpdateSectorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateSector"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateSectorInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateSector"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode;
-export const UpdateCragDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateCrag"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateCragInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateCrag"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]} as unknown as DocumentNode;
-export const NewCragPageCountriesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NewCragPageCountries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"countries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"areas"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]}}]} as unknown as DocumentNode;
-export const CreateCragDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateCrag"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateCragInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createCrag"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]} as unknown as DocumentNode;
export const LoginDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"Login"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"email"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"password"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"login"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"email"},"value":{"kind":"Variable","name":{"kind":"Name","value":"email"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"password"},"value":{"kind":"Variable","name":{"kind":"Name","value":"password"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"token"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"fullName"}},{"kind":"Field","name":{"kind":"Name","value":"firstname"}},{"kind":"Field","name":{"kind":"Name","value":"lastname"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"roles"}}]}}]}}]}}]} as unknown as DocumentNode;
export const CragDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Crag"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"crag"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cragBySlug"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"crag"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"sectors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"routes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"difficulty"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"defaultGradingSystem"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode;
export const CragActivitiesByMonthDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"CragActivitiesByMonth"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"crag"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cragBySlug"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"crag"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"activityByMonth"}}]}}]}}]} as unknown as DocumentNode;
@@ -1473,6 +1483,11 @@ export const DryRunCreateActivityDocument = {"kind":"Document","definitions":[{"
export const AuthContextProfileDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AuthContextProfile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"firstname"}},{"kind":"Field","name":{"kind":"Name","value":"lastname"}},{"kind":"Field","name":{"kind":"Name","value":"fullName"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"roles"}}]}}]}}]} as unknown as DocumentNode;
export const namedOperations = {
Query: {
+ EditCragPageCountries: 'EditCragPageCountries',
+ EditCragPageCrag: 'EditCragPageCrag',
+ EditRoutesPageSector: 'EditRoutesPageSector',
+ EditSectorsPageCrag: 'EditSectorsPageCrag',
+ NewCragPageCountries: 'NewCragPageCountries',
HomeLatestAscents: 'HomeLatestAscents',
HomeLatestDifficultyVotes: 'HomeLatestDifficultyVotes',
CragComments: 'CragComments',
@@ -1484,28 +1499,162 @@ export const namedOperations = {
MyCragSummary: 'MyCragSummary',
AllCrags: 'AllCrags',
AllCountries: 'AllCountries',
- EditCragPageCountries: 'EditCragPageCountries',
- EditCragPageCrag: 'EditCragPageCrag',
- EditSectorsPageCrag: 'EditSectorsPageCrag',
- NewCragPageCountries: 'NewCragPageCountries',
Crag: 'Crag',
CragActivitiesByMonth: 'CragActivitiesByMonth',
DryRunCreateActivity: 'DryRunCreateActivity',
AuthContextProfile: 'AuthContextProfile'
},
Mutation: {
- CreateComment: 'CreateComment',
- DeleteComment: 'DeleteComment',
- UpdateComment: 'UpdateComment',
+ UpdateCrag: 'UpdateCrag',
+ CreateRoute: 'CreateRoute',
+ DeleteRoute: 'DeleteRoute',
+ DeleteRoutes: 'DeleteRoutes',
+ MergeRoutes: 'MergeRoutes',
+ MoveRoutesToSector: 'MoveRoutesToSector',
+ UpdateRoute: 'UpdateRoute',
+ UpdateRoutes: 'UpdateRoutes',
CreateSector: 'CreateSector',
DeleteSector: 'DeleteSector',
+ MergeAllSectors: 'MergeAllSectors',
UpdateSector: 'UpdateSector',
- UpdateCrag: 'UpdateCrag',
CreateCrag: 'CreateCrag',
+ DeleteCrag: 'DeleteCrag',
+ CreateComment: 'CreateComment',
+ DeleteComment: 'DeleteComment',
+ UpdateComment: 'UpdateComment',
Login: 'Login',
CreateActivity: 'CreateActivity'
}
}
+export type UpdateCragMutationVariables = Exact<{
+ input: UpdateCragInput;
+}>;
+
+
+export type UpdateCragMutation = { __typename?: 'Mutation', updateCrag: { __typename?: 'Crag', id: string, slug: string } };
+
+export type EditCragPageCountriesQueryVariables = Exact<{ [key: string]: never; }>;
+
+
+export type EditCragPageCountriesQuery = { __typename?: 'Query', countries: Array<{ __typename?: 'Country', id: string, name: string, slug: string, areas: Array<{ __typename?: 'Area', id: string, name: string, slug: string }> }> };
+
+export type EditCragPageCragQueryVariables = Exact<{
+ cragSlug: Scalars['String']['input'];
+}>;
+
+
+export type EditCragPageCragQuery = { __typename?: 'Query', cragBySlug: { __typename?: 'Crag', id: string, slug: string, name: string, type: string, lat?: number | null, lon?: number | null, description?: string | null, wallAngles?: Array | null, rainproof?: boolean | null, orientations?: Array | null, seasons?: Array | null, approachTime?: number | null, access?: string | null, isHidden: boolean, publishStatus: string, country: { __typename?: 'Country', id: string }, area?: { __typename?: 'Area', id: string } | null, defaultGradingSystem?: { __typename?: 'GradingSystem', id: string } | null, coverImage?: { __typename?: 'Image', id: string, path: string, extension: string, maxIntrinsicWidth: number, aspectRatio: number } | null, images: Array<{ __typename?: 'Image', id: string, path: string, extension: string, maxIntrinsicWidth: number, aspectRatio: number }>, user?: { __typename?: 'User', id: string, fullName: string } | null, sectors: Array<{ __typename?: 'Sector', id: string, label: string, name: string, routes: Array<{ __typename?: 'Route', id: string }> }> } };
+
+export type CreateRouteMutationVariables = Exact<{
+ input: CreateRouteInput;
+}>;
+
+
+export type CreateRouteMutation = { __typename?: 'Mutation', createRoute: { __typename?: 'Route', id: string } };
+
+export type DeleteRouteMutationVariables = Exact<{
+ id: Scalars['String']['input'];
+}>;
+
+
+export type DeleteRouteMutation = { __typename?: 'Mutation', deleteRoute: boolean };
+
+export type DeleteRoutesMutationVariables = Exact<{
+ ids: Array | Scalars['String']['input'];
+}>;
+
+
+export type DeleteRoutesMutation = { __typename?: 'Mutation', deleteRoutes: Array };
+
+export type MergeRoutesMutationVariables = Exact<{
+ input: MergeRoutesInput;
+}>;
+
+
+export type MergeRoutesMutation = { __typename?: 'Mutation', mergeRoutes: boolean };
+
+export type MoveRoutesToSectorMutationVariables = Exact<{
+ input: MoveRoutesToSectorInput;
+}>;
+
+
+export type MoveRoutesToSectorMutation = { __typename?: 'Mutation', moveRoutesToSector: boolean };
+
+export type UpdateRouteMutationVariables = Exact<{
+ input: UpdateRouteInput;
+}>;
+
+
+export type UpdateRouteMutation = { __typename?: 'Mutation', updateRoute: { __typename?: 'Route', id: string } };
+
+export type UpdateRoutesMutationVariables = Exact<{
+ input: Array | UpdateRouteInput;
+}>;
+
+
+export type UpdateRoutesMutation = { __typename?: 'Mutation', updateRoutes: Array<{ __typename?: 'Route', id: string }> };
+
+export type EditRoutesPageSectorQueryVariables = Exact<{
+ id: Scalars['String']['input'];
+}>;
+
+
+export type EditRoutesPageSectorQuery = { __typename?: 'Query', sector: { __typename?: 'Sector', id: string, label: string, name: string, crag: { __typename?: 'Crag', id: string, slug: string, name: string, sectors: Array<{ __typename?: 'Sector', id: string, label: string, name: string }> }, routes: Array<{ __typename?: 'Route', id: string, name: string, difficulty?: number | null, length?: number | null, position: number, created: any, publishStatus: string, routeType: { __typename?: 'RouteType', id: string }, defaultGradingSystem: { __typename?: 'GradingSystem', id: string }, user?: { __typename?: 'User', id: string, fullName: string } | null, sector: { __typename?: 'Sector', id: string, publishStatus: string } }> } };
+
+export type CreateSectorMutationVariables = Exact<{
+ input: CreateSectorInput;
+}>;
+
+
+export type CreateSectorMutation = { __typename?: 'Mutation', createSector: { __typename?: 'Sector', id: string } };
+
+export type DeleteSectorMutationVariables = Exact<{
+ id: Scalars['String']['input'];
+}>;
+
+
+export type DeleteSectorMutation = { __typename?: 'Mutation', deleteSector: boolean };
+
+export type MergeAllSectorsMutationVariables = Exact<{
+ cragId: Scalars['String']['input'];
+}>;
+
+
+export type MergeAllSectorsMutation = { __typename?: 'Mutation', mergeAllSectors: boolean };
+
+export type UpdateSectorMutationVariables = Exact<{
+ input: UpdateSectorInput;
+}>;
+
+
+export type UpdateSectorMutation = { __typename?: 'Mutation', updateSector: { __typename?: 'Sector', id: string } };
+
+export type EditSectorsPageCragQueryVariables = Exact<{
+ cragSlug: Scalars['String']['input'];
+}>;
+
+
+export type EditSectorsPageCragQuery = { __typename?: 'Query', cragBySlug: { __typename?: 'Crag', id: string, slug: string, name: string, publishStatus: string, sectors: Array<{ __typename: 'Sector', id: string, name: string, label: string, position: number, publishStatus: string, user?: { __typename?: 'User', id: string, fullName: string } | null, routes: Array<{ __typename?: 'Route', id: string }>, crag: { __typename?: 'Crag', id: string, publishStatus: string } }> } };
+
+export type CreateCragMutationVariables = Exact<{
+ input: CreateCragInput;
+}>;
+
+
+export type CreateCragMutation = { __typename?: 'Mutation', createCrag: { __typename?: 'Crag', id: string, slug: string } };
+
+export type NewCragPageCountriesQueryVariables = Exact<{ [key: string]: never; }>;
+
+
+export type NewCragPageCountriesQuery = { __typename?: 'Query', countries: Array<{ __typename?: 'Country', id: string, name: string, slug: string, areas: Array<{ __typename?: 'Area', id: string, name: string, slug: string }> }> };
+
+export type DeleteCragMutationVariables = Exact<{
+ id: Scalars['String']['input'];
+}>;
+
+
+export type DeleteCragMutation = { __typename?: 'Mutation', deleteCrag: boolean };
+
export type HomeLatestAscentsQueryVariables = Exact<{
activitiesInput?: InputMaybe;
activityRoutesInput?: InputMaybe;
@@ -1607,65 +1756,6 @@ export type AllCountriesQueryVariables = Exact<{ [key: string]: never; }>;
export type AllCountriesQuery = { __typename?: 'Query', countries: Array<{ __typename?: 'Country', name: string, slug: string, nrCrags: number, areas: Array<{ __typename?: 'Area', name: string, slug: string, nrCrags: number }> }> };
-export type EditCragPageCountriesQueryVariables = Exact<{ [key: string]: never; }>;
-
-
-export type EditCragPageCountriesQuery = { __typename?: 'Query', countries: Array<{ __typename?: 'Country', id: string, name: string, slug: string, areas: Array<{ __typename?: 'Area', id: string, name: string, slug: string }> }> };
-
-export type EditCragPageCragQueryVariables = Exact<{
- cragSlug: Scalars['String']['input'];
-}>;
-
-
-export type EditCragPageCragQuery = { __typename?: 'Query', cragBySlug: { __typename?: 'Crag', id: string, slug: string, name: string, type: string, lat?: number | null, lon?: number | null, description?: string | null, wallAngles?: Array | null, rainproof?: boolean | null, orientations?: Array | null, seasons?: Array | null, approachTime?: number | null, access?: string | null, isHidden: boolean, country: { __typename?: 'Country', id: string }, area?: { __typename?: 'Area', id: string } | null, defaultGradingSystem?: { __typename?: 'GradingSystem', id: string } | null, coverImage?: { __typename?: 'Image', id: string, path: string, extension: string, maxIntrinsicWidth: number, aspectRatio: number } | null } };
-
-export type EditSectorsPageCragQueryVariables = Exact<{
- cragSlug: Scalars['String']['input'];
-}>;
-
-
-export type EditSectorsPageCragQuery = { __typename?: 'Query', cragBySlug: { __typename?: 'Crag', id: string, slug: string, name: string, sectors: Array<{ __typename?: 'Sector', id: string, name: string, label: string, position: number }> } };
-
-export type CreateSectorMutationVariables = Exact<{
- input: CreateSectorInput;
-}>;
-
-
-export type CreateSectorMutation = { __typename?: 'Mutation', createSector: { __typename?: 'Sector', id: string } };
-
-export type DeleteSectorMutationVariables = Exact<{
- id: Scalars['String']['input'];
-}>;
-
-
-export type DeleteSectorMutation = { __typename?: 'Mutation', deleteSector: boolean };
-
-export type UpdateSectorMutationVariables = Exact<{
- input: UpdateSectorInput;
-}>;
-
-
-export type UpdateSectorMutation = { __typename?: 'Mutation', updateSector: { __typename?: 'Sector', id: string } };
-
-export type UpdateCragMutationVariables = Exact<{
- input: UpdateCragInput;
-}>;
-
-
-export type UpdateCragMutation = { __typename?: 'Mutation', updateCrag: { __typename?: 'Crag', id: string, slug: string } };
-
-export type NewCragPageCountriesQueryVariables = Exact<{ [key: string]: never; }>;
-
-
-export type NewCragPageCountriesQuery = { __typename?: 'Query', countries: Array<{ __typename?: 'Country', id: string, name: string, slug: string, areas: Array<{ __typename?: 'Area', id: string, name: string, slug: string }> }> };
-
-export type CreateCragMutationVariables = Exact<{
- input: CreateCragInput;
-}>;
-
-
-export type CreateCragMutation = { __typename?: 'Mutation', createCrag: { __typename?: 'Crag', id: string, slug: string } };
-
export type LoginMutationVariables = Exact<{
email: Scalars['String']['input'];
password: Scalars['String']['input'];
diff --git a/src/hooks/useIsVisible.tsx b/src/hooks/useIsVisible.tsx
index 2cf1ac9e..1ac76bec 100644
--- a/src/hooks/useIsVisible.tsx
+++ b/src/hooks/useIsVisible.tsx
@@ -1,7 +1,7 @@
import { RefObject, useEffect, useState } from "react";
-function useIsVisible(ref: RefObject) {
- const [isIntersecting, setIntersecting] = useState(false);
+function useIsVisible(ref: RefObject, defaultValue = false) {
+ const [isIntersecting, setIntersecting] = useState(defaultValue);
useEffect(() => {
const observer = new IntersectionObserver(([entry]) =>
diff --git a/src/lib/contributables-helpers.ts b/src/lib/contributables-helpers.ts
new file mode 100644
index 00000000..b301bf79
--- /dev/null
+++ b/src/lib/contributables-helpers.ts
@@ -0,0 +1,23 @@
+import { Crag, Route, Sector, User } from "@/graphql/generated";
+
+function canEdit(user: User | null, contributable: Route | Sector | Crag) {
+ if (user?.roles?.includes("admin")) return true; // An editor has all permissions
+ if (contributable.publishStatus === "draft") {
+ return true;
+ }
+ return false;
+}
+
+function getBgStyle(publishStatus: string) {
+ switch (publishStatus) {
+ case "draft":
+ return "bg-red-25";
+ case "in_review":
+ return "bg-amber-25";
+ case "published":
+ default:
+ return "bg-neutral-100";
+ }
+}
+
+export { canEdit, getBgStyle };
diff --git a/src/lib/sector-helpers.ts b/src/lib/sector-helpers.ts
new file mode 100644
index 00000000..b6835f5b
--- /dev/null
+++ b/src/lib/sector-helpers.ts
@@ -0,0 +1,6 @@
+// Dep.: sector.label is deprecated. remove after removed in BE
+function labelAndNameToString(label: string | null, name: string | null) {
+ return label && name ? `${label} - ${name}` : label || name || "";
+}
+
+export { labelAndNameToString };
diff --git a/src/lib/text-helpers.ts b/src/lib/text-helpers.ts
index 1a93f7ef..9a30c934 100644
--- a/src/lib/text-helpers.ts
+++ b/src/lib/text-helpers.ts
@@ -105,4 +105,10 @@ const pluralizeNoun = (
}
};
-export { pluralizeNoun };
+const genderizeVerb = (verb: string, gender: string) => {
+ if (gender == "F") return verb + "a";
+ if (gender == "M") return verb;
+ return verb + "/a";
+};
+
+export { pluralizeNoun, genderizeVerb };
diff --git a/src/rewrites.json b/src/rewrites.json
index cccc9a5a..09a719dc 100644
--- a/src/rewrites.json
+++ b/src/rewrites.json
@@ -4,7 +4,12 @@
"/{crag}/:cragSlug/{route}/:routeSlug*",
"/{crag}/:cragSlug/{comments}",
"/{crag}/:cragSlug/{gallery}",
- "/{crag}/:cragSlug*"
+ "/{crag}/:cragSlug*",
+
+ "/{admin}/{crags}/{add}",
+ "/{admin}/{crags}/:cragSlug/{edit}",
+ "/{admin}/{crags}/:cragSlug/{sectors}",
+ "/{admin}/{crags}/:cragSlug/{sectors}/:sectorId/{routes}"
],
"translations": {
"sl": {
@@ -13,7 +18,13 @@
"route": "smer",
"info": "info",
"comments": "komentarji",
- "gallery": "galerija"
+ "gallery": "galerija",
+
+ "admin": "urejanje",
+ "add": "dodaj",
+ "edit": "uredi",
+ "sectors": "sektorji",
+ "routes": "smeri"
},
"en": {
"crags": "crags",
@@ -21,7 +32,13 @@
"route": "route",
"info": "info",
"comments": "comments",
- "gallery": "gallery"
+ "gallery": "gallery",
+
+ "admin": "admin",
+ "add": "add",
+ "edit": "edit",
+ "sectors": "sectors",
+ "routes": "routes"
}
},
"defaultLanguage": "sl"
diff --git a/tailwind.config.js b/tailwind.config.js
index 46f2a4ce..84ae574a 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -2,9 +2,9 @@ const defaultTheme = require("tailwindcss/defaultTheme");
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
- "./src/pages/**/*.{js,ts,jsx,tsx}",
"./src/components/**/*.{js,ts,jsx,tsx}",
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
+ "./src/lib/**/*.{ts,tsx}",
],
theme: {
fontFamily: {
@@ -54,6 +54,9 @@ module.exports = {
100: "#F0B3AA",
500: "#d9422b",
},
+ amber: {
+ 25: "#FBF5EA",
+ },
current: "currentColor",
// ...
@@ -65,6 +68,7 @@ module.exports = {
},
width: {
13: "3.25rem", // 52px
+ 15: "3.75rem", //
30: "7.5rem", // 120px
42: "10.5rem", // 168px
},
@@ -74,9 +78,12 @@ module.exports = {
minWidth: {
0.5: "0.125rem", // 2px
8: "2rem", // 32px
+ 10: "2.5rem", // 40px
+ 12: "3rem", // 48px
14: "3.5rem", // 56px
16: "4rem", // 64px
20: "5rem", // 80px
+ 21: "5.25rem", // 84px
22: "5.5rem", // 88px
28: "7rem", // 112px
30: "7.5rem", // 120px
@@ -84,6 +91,9 @@ module.exports = {
34: "8.5rem", // 136px
36: "9rem", // 144px
},
+ maxWidth: {
+ 80: "20rem", // 320px
+ },
margin: {
18: "4.5rem", // 72px
},