diff --git a/Dockerfile b/Dockerfile index 9c4e005130..252eb24392 100644 --- a/Dockerfile +++ b/Dockerfile @@ -71,6 +71,9 @@ RUN if [ "$PACKAGE_MANAGER" = "yarn" ] || { [ -z "$PACKAGE_MANAGER" ] && [ -f ya # --- Runtime stage --- FROM node:26.8.1-bookworm-slim AS runner +# Catalog Studio publishes to self-hosted Git repositories over HTTPS. +RUN apt-get update && apt-get install -y --no-install-recommends git ca-certificates && rm -rf /var/lib/apt/lists/* + # The CMS writes to bind-mounted host directories (/var/www/Gamedata is owned by # the host's www-data user, UID/GID 33). The node base image already ships a # www-data user with UID/GID 33, which matches that ownership — so we run as diff --git a/src/app/admin/import/furni/nitro-editor-dialog.tsx b/src/app/admin/import/furni/nitro-editor-dialog.tsx index 2fefe5c2a3..a4f0f8e973 100644 --- a/src/app/admin/import/furni/nitro-editor-dialog.tsx +++ b/src/app/admin/import/furni/nitro-editor-dialog.tsx @@ -1,4 +1,5 @@ "use client"; +import "./nitro-editor.css"; import { Box, @@ -240,6 +241,7 @@ export function NitroEditorDialog({ setMetadata(JSON.parse(JSON.stringify(originalMetadata))); setFlags({ ...originalFlags }); setJsonText(JSON.stringify(originalMetadata, null, 2)); + setJsonError(null); toast.info("Reset to original values"); }; @@ -334,7 +336,9 @@ export function NitroEditorDialog({ const hasChanges = metadata && originalMetadata && - (JSON.stringify(metadata) !== JSON.stringify(originalMetadata) || + ((activeTab === "json" + ? jsonText !== JSON.stringify(originalMetadata, null, 2) + : JSON.stringify(metadata) !== JSON.stringify(originalMetadata)) || JSON.stringify(flags) !== JSON.stringify(originalFlags)); // Furni preview URL @@ -344,13 +348,16 @@ export function NitroEditorDialog({ return ( - + {/* Header with preview */}
{/* Furni preview */}
{/* Dimensions + Interaction in 2-column layout */} -
- {/* Dimensions card */} -
-
- -

Dimensions

-
-
-
- - setDim("x", e.target.value)} - className="mt-1" - /> +
+
+ {/* Dimensions card */} +
+
+ +

Dimensions

-
- - setDim("y", e.target.value)} - className="mt-1" - /> +
+
+ + setDim("x", e.target.value)} + className="mt-1" + /> +
+
+ + setDim("y", e.target.value)} + className="mt-1" + /> +
+
+ + setDim("z", e.target.value)} + className="mt-1" + /> +
-
- - setDim("z", e.target.value)} - className="mt-1" - /> -
-
-
+
+ {/* Available rotations */} +
+
+ +

Directions

+ + {directions.length} / 8 active + +
+
+ {ALL_DIRECTIONS.map((dir) => ( + + ))} +
+

+ Choose the available rotations. Keep at least one + direction active. +

+
+
{/* Interaction card */}
@@ -506,6 +544,7 @@ export function NitroEditorDialog({
Can Stand On setFlags((f) => ({ ...f, canstandon: !!v })) @@ -515,6 +554,7 @@ export function NitroEditorDialog({
Can Sit On setFlags((f) => ({ ...f, cansiton: !!v })) @@ -524,6 +564,7 @@ export function NitroEditorDialog({
Can Lay On setFlags((f) => ({ ...f, canlayon: !!v })) @@ -581,58 +622,6 @@ export function NitroEditorDialog({
- {/* Directions - visual compass */} -
-
- -

Directions

- - {directions.length} active - -
-
-
- {/* Compass circle */} -
-
- {/* Direction buttons arranged in circle */} - {ALL_DIRECTIONS.map((dir) => { - const angle = (dir * 45 - 90) * (Math.PI / 180); - const r = 80; - const x = 96 + r * Math.cos(angle) - 18; - const y = 96 + r * Math.sin(angle) - 18; - const isActive = directions.includes(dir); - return ( - - ); - })} - {/* Center label */} -
- - {directions.length}/8 - -
-
-
-
- {/* Types */}
@@ -858,7 +847,8 @@ export function NitroEditorDialog({ >