From 7a9fce185316c2a678988f62b46b406289c557e5 Mon Sep 17 00:00:00 2001 From: Juan Cazala Date: Wed, 31 Jan 2024 10:36:13 -0300 Subject: [PATCH] feat: edit metadata (#3026) * feat: integrate file system interface * feat: integrate project * feat: layout icon * chore: lint * feat: integrate thumbnail * fix: change layout * feat: integrate deployment * feat: show metadata thubnail in project card * chore: remove console.log * chore: add thumbnail preview to files that exist * fix: upgrade @dcl/inspector to avoid retrocompat issue * chore: use @dcl/sdk instead of @dcl/inspector --- .env.example | 6 +- package-lock.json | 144 ++++++------ package.json | 3 +- src/components/Icon/Icon.types.ts | 19 +- src/components/Icon/icons.svg | 2 +- src/components/Icon/sprite.css | 212 +++++++++++------- .../InspectorPage/InspectorPage.tsx | 11 +- .../InspectorPage/TopBar/TopBar.tsx | 2 +- .../DeployModal/DeployToLand/DeployToLand.tsx | 7 +- .../DeployToWorld/DeployToWorld.container.ts | 3 +- .../DeployToWorld/DeployToWorld.tsx | 4 +- .../DeployToWorld/DeployToWorld.types.ts | 4 +- .../EditProjectModal/EditProjectModal.tsx | 12 +- src/components/ProjectCard/ProjectCard.tsx | 11 +- src/icons/layout.svg | 6 + src/modules/deployment/sagas.ts | 23 +- src/modules/inspector/sagas.ts | 70 +++++- src/modules/inspector/utils.ts | 35 +-- src/modules/media/sagas.ts | 1 - src/modules/project/utils.ts | 14 ++ src/modules/scene/types.ts | 2 + vite.config.ts | 5 +- 22 files changed, 364 insertions(+), 232 deletions(-) create mode 100644 src/icons/layout.svg diff --git a/.env.example b/.env.example index ea9070de8..d9bbbd5c4 100644 --- a/.env.example +++ b/.env.example @@ -12,8 +12,8 @@ REACT_APP_FF_BUILDER_DCL_CONTROLLER_V2= REACT_APP_FF_BUILDER_WORLDS_FOR_ENS_OWNERS= ; Local development of @dcl/inspector -REACT_APP_INSPECTOR_PORT= +VITE_INSPECTOR_PORT= ; Local development of @dcl/asset-packs -REACT_APP_BIN_INDEX_JS_DEV_PORT= -REACT_APP_BIN_INDEX_JS_DEV_PATH= +VITE_BIN_INDEX_JS_DEV_PATH= +VITE_BIN_INDEX_JS_DEV_PORT= diff --git a/package-lock.json b/package-lock.json index 5ca4510b9..a7db406e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,7 @@ "@dcl/hashing": "^3.0.4", "@dcl/mini-rpc": "^1.0.7", "@dcl/schemas": "^9.4.1", - "@dcl/sdk": "^7.3.35", + "@dcl/sdk": "^7.3.40", "@dcl/single-sign-on-client": "^0.1.0", "@dcl/ui-env": "^1.5.0", "@sentry/react": "^7.64.0", @@ -76,6 +76,7 @@ "reselect": "4.0.0", "slug": "^5.3.0", "three": "^0.107.0", + "ts-deepmerge": "^7.0.0", "typechain": "^8.1.0", "typesafe-actions": "^4.4.2", "uuid": "^3.3.2" @@ -1582,16 +1583,16 @@ } }, "node_modules/@dcl-sdk/utils": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@dcl-sdk/utils/-/utils-1.2.2.tgz", - "integrity": "sha512-4oX6yNJqivBRzixXCMkGKvBSuJnjjeUk38K9L9Vv8hbMGpxX/E6v+K2Rha1ONta+6Qyh01lnrnHow8z9Wc0QAw==" + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@dcl-sdk/utils/-/utils-1.2.4.tgz", + "integrity": "sha512-MPjLq072E2RuAD67UxeR6jmt2MFaLaEynXJUSv+08UhMfEu9FF3x5YojfGMHNCDf9Xp/d8E8DJJoJWTgSwuatg==" }, "node_modules/@dcl/asset-packs": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@dcl/asset-packs/-/asset-packs-1.9.0.tgz", - "integrity": "sha512-HWr35SamlgwbAAC79Ntd2NriVJgTfuVFH5nGPMJgUt0G3X1fAT51JhXeB9bB49aYaDV07LBGXj7AdJ3bBdoO4w==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@dcl/asset-packs/-/asset-packs-1.11.0.tgz", + "integrity": "sha512-jYZTneUJlsZcFisiGJgb3icW5qk8DH0RZ/Y9P9ca9A/In1m2qW1ja4y9tCTxoXGL4ToQKU06sTfTq7SLL5fKeQ==", "dependencies": { - "@dcl-sdk/utils": "^1.1.3", + "@dcl-sdk/utils": "^1.2.3", "@dcl/js-runtime": "7.3.35", "@dcl/sdk": "^7.3.35", "mitt": "^3.0.1" @@ -1882,9 +1883,9 @@ } }, "node_modules/@dcl/ecs": { - "version": "7.3.37", - "resolved": "https://registry.npmjs.org/@dcl/ecs/-/ecs-7.3.37.tgz", - "integrity": "sha512-f+RCyU/BqLqv2riENpw+hnh5uWhHtpmaGxFnUU1fkIW3UgL0eqODG4UtuYuBoclKKwdWMNwuTUyukpPBykiYRQ==" + "version": "7.3.40", + "resolved": "https://registry.npmjs.org/@dcl/ecs/-/ecs-7.3.40.tgz", + "integrity": "sha512-yMsvVjR/3eyGhqzaLkT6hfviu59D2hm0vQCHuYl3eYNFBFHT44L37GDggOfASaa4oNhUy5RfWIIgsA27Kz4PXQ==" }, "node_modules/@dcl/ecs-math": { "version": "2.0.2", @@ -1902,17 +1903,18 @@ "integrity": "sha512-Cg+MoIOn+BYmQV2q8zSFnNYY+GldlnUazwBnfgrq3i66ZxOaZ65h01btd8OUtSAlfWG4VTNIOHDjtKqmuwJNBg==" }, "node_modules/@dcl/inspector": { - "version": "7.3.37", - "resolved": "https://registry.npmjs.org/@dcl/inspector/-/inspector-7.3.37.tgz", - "integrity": "sha512-ntAxqbFbOAnJYAjNQ0aSq5/01M0kw2+NqExO1GEZqDQdq1UsNQS+DPHvOavOJFYpaMS+YTQJf5OSG+htrl4pMw==", + "version": "7.3.40", + "resolved": "https://registry.npmjs.org/@dcl/inspector/-/inspector-7.3.40.tgz", + "integrity": "sha512-hI4qFWZtO6EIcaVPCgzK1Z2+K7W+CWyswsdWvLhmYKKC5tSLlLTVq7pgNB5GyUHJ21laWt8Spwx/yzuaz1sThg==", "dependencies": { - "@dcl/asset-packs": "^1.8.0" + "@dcl/asset-packs": "^1.11.0", + "ts-deepmerge": "^7.0.0" } }, "node_modules/@dcl/js-runtime": { - "version": "7.3.37", - "resolved": "https://registry.npmjs.org/@dcl/js-runtime/-/js-runtime-7.3.37.tgz", - "integrity": "sha512-xlh65qgxu/2QEQp8Z1zWb6Nb1Uef9/NUVLmGfATi4IqIcYR8kZB4UlVgKXHsRlgx4bz+dbgtbr5BRbCG4TGHDQ==" + "version": "7.3.40", + "resolved": "https://registry.npmjs.org/@dcl/js-runtime/-/js-runtime-7.3.40.tgz", + "integrity": "sha512-XFcyVZVPdGbnDGL1zjj+0DIZbHmTUmzkmwWCQmXNturCf/K4jKGl06RXVLZJgi4tr6gGoYWqd8xxApI/kPqGpQ==" }, "node_modules/@dcl/linker-dapp": { "version": "0.11.0", @@ -1958,9 +1960,9 @@ } }, "node_modules/@dcl/protocol": { - "version": "1.0.0-7117237552.commit-82dc93b", - "resolved": "https://registry.npmjs.org/@dcl/protocol/-/protocol-1.0.0-7117237552.commit-82dc93b.tgz", - "integrity": "sha512-Ae8LuL/lw1hERuegVuK0OA4rkksaHP5vAl3UjVsUdbGgTgFwDyB8fxe040Rfx3PAllO5jA0nd2oslpqoyDYehA==", + "version": "1.0.0-7716486147.commit-7433b10", + "resolved": "https://registry.npmjs.org/@dcl/protocol/-/protocol-1.0.0-7716486147.commit-7433b10.tgz", + "integrity": "sha512-wlFfSR0612R0vJndjjLEwf1wrpVSORDn2rRPxwKenrMZxv+e26ITwB8qA1bxVzcM3/vfJCnZlWgcLrigjlHiGg==", "dependencies": { "@dcl/ts-proto": "1.154.0" } @@ -1982,11 +1984,11 @@ "integrity": "sha512-IPB043+NbQB3om2FlmQGmaRxTokHaSM9o3a7sEL0yJgBb60mukCpMdNXxzdIcemixfV3EhIJQ2G8HgK30XKTkA==" }, "node_modules/@dcl/react-ecs": { - "version": "7.3.37", - "resolved": "https://registry.npmjs.org/@dcl/react-ecs/-/react-ecs-7.3.37.tgz", - "integrity": "sha512-H8DYj5ofwCI+VihNppU5JGBJXoq9ayuyq7PMgUUKU/1oNZ89J/foqyqynlhgah+RzwO9aCsnVZiT2Oeh6Gsumg==", + "version": "7.3.40", + "resolved": "https://registry.npmjs.org/@dcl/react-ecs/-/react-ecs-7.3.40.tgz", + "integrity": "sha512-6HYocAua6l50RP0lkSh3XLaHv81KzXerhdJUn2cf8EcUWN1C/1kRNckhlv1FLcqxbK9gUuhqb8f2srLpVaVufQ==", "dependencies": { - "@dcl/ecs": "7.3.37", + "@dcl/ecs": "7.3.40", "react": "^18.2.0", "react-reconciler": "^0.29.0" } @@ -2002,6 +2004,29 @@ "node": ">=0.10.0" } }, + "node_modules/@dcl/react-ecs/node_modules/react-reconciler": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.29.0.tgz", + "integrity": "sha512-wa0fGj7Zht1EYMRhKWwoo1H9GApxYLBuhoAuXN0TlltESAjDssB+Apf0T/DngVqaMyPypDmabL37vw/2aRM98Q==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/@dcl/react-ecs/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, "node_modules/@dcl/rpc": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@dcl/rpc/-/rpc-1.1.2.tgz", @@ -2022,31 +2047,31 @@ } }, "node_modules/@dcl/sdk": { - "version": "7.3.37", - "resolved": "https://registry.npmjs.org/@dcl/sdk/-/sdk-7.3.37.tgz", - "integrity": "sha512-DuIfAYOrmdTAC4aPkqDywFq3GI0kbm5W9tNBP/A2nz4GXYZdouk0Ud8FYZM7W4jDP5eiR+ThSje7E4JQ3hc1Ug==", + "version": "7.3.40", + "resolved": "https://registry.npmjs.org/@dcl/sdk/-/sdk-7.3.40.tgz", + "integrity": "sha512-bGlWimg0Y4O+y+Fu4ZrbDe7okDduDPH0D3cDrwUB+rzO/FBoeagwKyt0iX3UeFd9cSO4Cu1KlHWHpF6AxX0oVw==", "dependencies": { - "@dcl/ecs": "7.3.37", + "@dcl/ecs": "7.3.40", "@dcl/ecs-math": "2.0.2", "@dcl/explorer": "1.0.159327-20240122142059.commit-58ce257", - "@dcl/js-runtime": "7.3.37", - "@dcl/react-ecs": "7.3.37", - "@dcl/sdk-commands": "7.3.37", + "@dcl/js-runtime": "7.3.40", + "@dcl/react-ecs": "7.3.40", + "@dcl/sdk-commands": "7.3.40", "text-encoding": "0.7.0" } }, "node_modules/@dcl/sdk-commands": { - "version": "7.3.37", - "resolved": "https://registry.npmjs.org/@dcl/sdk-commands/-/sdk-commands-7.3.37.tgz", - "integrity": "sha512-UMnf1wPfU7Gk4KnmLozNux2lLD0fd9J64ZOx6Vsvp/X2KEwfdnbnsu9Tv6L17HfskExyVwUxL9d52lpPJVyd6g==", + "version": "7.3.40", + "resolved": "https://registry.npmjs.org/@dcl/sdk-commands/-/sdk-commands-7.3.40.tgz", + "integrity": "sha512-ks/MVIyY4SvXXDKnYXha+qZoXhMnBz6BAtM6oURyhq7zWmRCBAlwOPcjCayzxyPjWSnGdg253MV9d+7LcRs+nw==", "dependencies": { "@dcl/crypto": "^3.4.4", - "@dcl/ecs": "7.3.37", + "@dcl/ecs": "7.3.40", "@dcl/hashing": "1.1.3", - "@dcl/inspector": "7.3.37", + "@dcl/inspector": "7.3.40", "@dcl/linker-dapp": "^0.11.0", "@dcl/mini-comms": "1.0.1-20230216163137.commit-a4c75be", - "@dcl/protocol": "1.0.0-7117237552.commit-82dc93b", + "@dcl/protocol": "1.0.0-7716486147.commit-7433b10", "@dcl/quests-client": "^1.0.3", "@dcl/quests-manager": "^0.1.4", "@dcl/rpc": "^1.1.1", @@ -18629,9 +18654,9 @@ } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", "engines": { "node": "14 || >=16.14" } @@ -20134,29 +20159,6 @@ "react-dom": "^16.8.0 || ^17 || ^18" } }, - "node_modules/react-reconciler": { - "version": "0.29.0", - "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.29.0.tgz", - "integrity": "sha512-wa0fGj7Zht1EYMRhKWwoo1H9GApxYLBuhoAuXN0TlltESAjDssB+Apf0T/DngVqaMyPypDmabL37vw/2aRM98Q==", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "peerDependencies": { - "react": "^18.2.0" - } - }, - "node_modules/react-reconciler/node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, "node_modules/react-redux": { "version": "7.2.9", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", @@ -22827,6 +22829,14 @@ "write-markdown": "dist/write-markdown.js" } }, + "node_modules/ts-deepmerge": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ts-deepmerge/-/ts-deepmerge-7.0.0.tgz", + "integrity": "sha512-WZ/iAJrKDhdINv1WG6KZIGHrZDar6VfhftG1QJFpVbOYZMYJLJOvZOo1amictRXVdBXZIgBHKswMTXzElngprA==", + "engines": { + "node": ">=14.13.1" + } + }, "node_modules/ts-essentials": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-7.0.3.tgz", @@ -23005,9 +23015,9 @@ } }, "node_modules/ts-proto": { - "version": "1.167.0", - "resolved": "https://registry.npmjs.org/ts-proto/-/ts-proto-1.167.0.tgz", - "integrity": "sha512-ATJ9bN0JpPhtWVymKpkf7zUYOLBZVOA7rWRRH/U+ML8A2xjcBgcM3H4Mme8T8Yn6S4rW6ttNjRAtLZmusAjIIA==", + "version": "1.167.2", + "resolved": "https://registry.npmjs.org/ts-proto/-/ts-proto-1.167.2.tgz", + "integrity": "sha512-7y/BLjiUZphgCe+SZBEG20DP94VK7BHpHcl5fkeN8lRCeABNIsiI54FkUQ8pe7PsHLVpFKqMO5aRLx74FX+4iA==", "dependencies": { "case-anything": "^2.1.13", "protobufjs": "^7.2.4", diff --git a/package.json b/package.json index 581e5bfeb..0e84a4f1a 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "@dcl/hashing": "^3.0.4", "@dcl/mini-rpc": "^1.0.7", "@dcl/schemas": "^9.4.1", - "@dcl/sdk": "^7.3.35", + "@dcl/sdk": "^7.3.40", "@dcl/single-sign-on-client": "^0.1.0", "@dcl/ui-env": "^1.5.0", "@sentry/react": "^7.64.0", @@ -70,6 +70,7 @@ "reselect": "4.0.0", "slug": "^5.3.0", "three": "^0.107.0", + "ts-deepmerge": "^7.0.0", "typechain": "^8.1.0", "typesafe-actions": "^4.4.2", "uuid": "^3.3.2" diff --git a/src/components/Icon/Icon.types.ts b/src/components/Icon/Icon.types.ts index 8c04e4370..c795b7b51 100644 --- a/src/components/Icon/Icon.types.ts +++ b/src/components/Icon/Icon.types.ts @@ -6,23 +6,15 @@ export type IconName = | 'alert-warning' | 'arrow-down' | 'arrow-key-down' - | 'arrow-key-down' - | 'arrow-key-left' | 'arrow-key-left' | 'arrow-key-right' - | 'arrow-key-right' - | 'arrow-key-up' | 'arrow-key-up' | 'arrow-up' | 'atlas-zoom-in' - | 'atlas-zoom-in' | 'atlas-zoom-out' - | 'atlas-zoom-out' - | 'camera' | 'camera' | 'cat' | 'center-camera' - | 'center-camera' | 'chevron-right' | 'circle' | 'cylinder' @@ -34,31 +26,24 @@ export type IconName = | 'dress' | 'duplicate' | 'edit-active' - | 'edit-active' - | 'edit' | 'edit' | 'ellipsis' | 'emote' | 'export' - | 'export' | 'facebook' | 'geometries' - | 'geometries' | 'grid-active' | 'grid' | 'heart-full' | 'heart' | 'import' - | 'import' | 'landscape' + | 'layout' | 'list-active' | 'list' | 'locate-land' - | 'locate-land' | 'minus' | 'modal-back' - | 'modal-back' - | 'modal-close' | 'modal-close' | 'move-active' | 'move' @@ -73,8 +58,6 @@ export type IconName = | 'rotate-control' | 'rotate-active' | 'rotate-left' - | 'rotate-left' - | 'rotate-right' | 'rotate-right' | 'rotate' | 'scale' diff --git a/src/components/Icon/icons.svg b/src/components/Icon/icons.svg index c1652a75b..fe9c464eb 100644 --- a/src/components/Icon/icons.svg +++ b/src/components/Icon/icons.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/components/Icon/sprite.css b/src/components/Icon/sprite.css index 519545382..ae21cd7e2 100644 --- a/src/components/Icon/sprite.css +++ b/src/components/Icon/sprite.css @@ -1,137 +1,149 @@ .Icon.add { - background: url('icons.svg') 99.40828402366864% 52.17391304347826% no-repeat; + background: url('icons.svg') 52.63157894736842% 99.37106918238993% no-repeat; width: 13px; height: 13px; } .Icon.add-active { - background: url('icons.svg') 99.40828402366864% 60.24844720496895% no-repeat; + background: url('icons.svg') 60.23391812865497% 99.37106918238993% no-repeat; width: 13px; height: 13px; } +.Icon.add-rounded { + background: url('icons.svg') 36.58536585365854% 31.57894736842105% no-repeat; + width: 20px; + height: 20px; +} + .Icon.alert { - background: url('icons.svg') 90.47619047619048% 56.831875000000004% no-repeat; + background: url('icons.svg') 0 91.13924050632912% no-repeat; width: 14px; height: 14px; } .Icon.alert-pending { - background: url('icons.svg') 50.63291139240506% 15.333333333333334% no-repeat; + background: url('icons.svg') 50% 32.432432432432435% no-repeat; width: 24px; height: 24px; } .Icon.alert-warning { - background: url('icons.svg') 0 46.666666666666664% no-repeat; + background: url('icons.svg') 0 54.054054054054056% no-repeat; width: 24px; height: 24px; } .Icon.arrow-down { - background: url('icons.svg') 40.69767441860465% 19.047619047619047% no-repeat; + background: url('icons.svg') 98.85057471264368% 13.25301204819277% no-repeat; width: 10px; height: 6px; } .Icon.arrow-key-down { - background: url('icons.svg') 90.47619047619048% 65.581875% no-repeat; + background: url('icons.svg') 8.235294117647058% 91.13924050632912% no-repeat; width: 14px; height: 14px; } .Icon.arrow-key-left { - background: url('icons.svg') 90.47619047619048% 74.331875% no-repeat; + background: url('icons.svg') 16.470588235294116% 91.13924050632912% no-repeat; width: 14px; height: 14px; } .Icon.arrow-key-right { - background: url('icons.svg') 90.47619047619048% 83.081875% no-repeat; + background: url('icons.svg') 24.705882352941178% 91.13924050632912% no-repeat; width: 14px; height: 14px; } .Icon.arrow-key-up { - background: url('icons.svg') 0 93.75% no-repeat; + background: url('icons.svg') 32.94117647058823% 91.13924050632912% no-repeat; width: 14px; height: 14px; } .Icon.arrow-up { - background: url('icons.svg') 40.69767441860465% 22.61904761904762% no-repeat; + background: url('icons.svg') 98.85057471264368% 16.867469879518072% no-repeat; width: 10px; height: 6px; } .Icon.atlas-zoom-in { - background: url('icons.svg') 98.82352941176471% 75.92592592592592% no-repeat; + background: url('icons.svg') 74.4186046511628% 98.75% no-repeat; width: 12px; height: 12px; } .Icon.atlas-zoom-out { - background: url('icons.svg') 98.82352941176471% 78.48837209302326% no-repeat; + background: url('icons.svg') 90.69767441860465% 83.48882352941176% no-repeat; width: 12px; height: 2px; } .Icon.camera { - background: url('icons.svg') 0 31.57894736842105% no-repeat; + background: url('icons.svg') 20.512820512820515% 32% no-repeat; width: 28px; height: 22px; } .Icon.cat { - background: url('icons.svg') 50.63291139240506% 30.51948051948052% no-repeat; + background: url('icons.svg') 15% 52.63157894736842% no-repeat; width: 24px; height: 20px; } .Icon.check { - background: url('icons.svg') 15.189873417721518% 46.666666666666664% no-repeat; + background: url('icons.svg') 67.5% 0 no-repeat; width: 24px; height: 24px; } .Icon.chevron-right { - background: url('icons.svg') 82.183908045977% 25% no-repeat; + background: url('icons.svg') 68.18181818181819% 65.82278481012658% no-repeat; width: 8px; height: 14px; } .Icon.circle { - background: url('icons.svg') 24.137931034482758% 90.36144578313252% no-repeat; + background: url('icons.svg') 97.72727272727273% 39.02439024390244% no-repeat; width: 8px; height: 8px; } .Icon.close { - background: url('icons.svg') 8.333333333333334% 93.75% no-repeat; + background: url('icons.svg') 41.1764705882353% 91.13924050632912% no-repeat; width: 14px; height: 14px; } .Icon.cloud-upload { - background: url('icons.svg') 51.94805194805195% 0 no-repeat; + background: url('icons.svg') 51.282051282051285% 0 no-repeat; width: 28px; height: 23px; } +.Icon.code { + background: url('icons.svg') 50% 15.646258503401361% no-repeat; + width: 24px; + height: 25px; +} + .Icon.cube { - background: url('icons.svg') 79.51807228915662% 43.67088607594937% no-repeat; + background: url('icons.svg') 28.571428571428573% 20.512820512820515% no-repeat; width: 16px; height: 16px; } .Icon.cylinder { - background: url('icons.svg') 59.25925925925926% 61.03896103896104% no-repeat; + background: url('icons.svg') 29.26829268292683% 52.63157894736842% no-repeat; width: 20px; height: 20px; } .Icon.delete { - background: url('icons.svg') 89.41176470588235% 28.887421383647794% no-repeat; + background: url('icons.svg') 90.69767441860465% 56.007006369426755% no-repeat; width: 12px; height: 15px; } @@ -143,343 +155,379 @@ } .Icon.dress { - background: url('icons.svg') 17.72151898734177% 31.16883116883117% no-repeat; + background: url('icons.svg') 67.5% 15.789473684210526% no-repeat; width: 24px; height: 20px; } .Icon.duplicate { - background: url('icons.svg') 78.57142857142857% 53.79746835443038% no-repeat; + background: url('icons.svg') 37.64705882352941% 20.512820512820515% no-repeat; width: 14px; height: 16px; } .Icon.edit { - background: url('icons.svg') 79.51807228915662% 63.924050632911396% no-repeat; + background: url('icons.svg') 0 82.05128205128206% no-repeat; width: 16px; height: 16px; } .Icon.ellipsis { - background: url('icons.svg') 80.48780487804878% 21.176470588235293% no-repeat; + background: url('icons.svg') 79.51807228915662% 73.80952380952381% no-repeat; width: 18px; height: 4px; } .Icon.emote { - background: url('icons.svg') 77.19298245614036% 25.477707006369428% no-repeat; + background: url('icons.svg') 83.23699421965318% 56.774193548387096% no-repeat; width: 11px; height: 17px; } +.Icon.ethereum { + background: url('icons.svg') 31.57894736842105% 0 no-repeat; + width: 32px; + height: 32px; +} + .Icon.export { - background: url('icons.svg') 69.04761904761905% 59.49367088607595% no-repeat; + background: url('icons.svg') 9.411764705882353% 82.05128205128206% no-repeat; width: 14px; height: 16px; } .Icon.facebook { - background: url('icons.svg') 56.470588235294116% 46.05263157894737% no-repeat; + background: url('icons.svg') 76.74418604651163% 58.666666666666664% no-repeat; width: 12px; height: 22px; } +.Icon.frames { + background: url('icons.svg') 49.411764705882355% 91.13924050632912% no-repeat; + width: 14px; + height: 14px; +} + .Icon.geometries { - background: url('icons.svg') 98.82352941176471% 68.32298136645963% no-repeat; + background: url('icons.svg') 67.44186046511628% 99.37106918238993% no-repeat; width: 12px; height: 13px; } .Icon.grid { - background: url('icons.svg') 6.976744186046512% 100% no-repeat; + background: url('icons.svg') 98.85057471264368% 20.987654320987655% no-repeat; width: 10px; height: 10px; } .Icon.grid-active { - background: url('icons.svg') 12.790697674418604% 100% no-repeat; + background: url('icons.svg') 98.85057471264368% 27.160493827160494% no-repeat; width: 10px; height: 10px; } .Icon.heart { - background: url('icons.svg') 81.48148148148148% 0 no-repeat; + background: url('icons.svg') 41.46341463414634% 51.94805194805195% no-repeat; width: 20px; height: 18px; } .Icon.heart-full { - background: url('icons.svg') 81.48148148148148% 11.538461538461538% no-repeat; + background: url('icons.svg') 53.65853658536585% 51.94805194805195% no-repeat; width: 20px; height: 18px; } +.Icon.image { + background: url('icons.svg') 57.64705882352941% 90% no-repeat; + width: 14px; + height: 12px; +} + .Icon.import { - background: url('icons.svg') 90.47619047619048% 18.97905345134087% no-repeat; + background: url('icons.svg') 91.76470588235294% 46.13344097802895% no-repeat; width: 14px; height: 15.931px; } .Icon.landscape { - background: url('icons.svg') 32.91139240506329% 31.16883116883117% no-repeat; + background: url('icons.svg') 67.5% 28.94736842105263% no-repeat; width: 24px; height: 20px; } +.Icon.layout { + background: url('icons.svg') 17.857142857142858% 82.05128205128206% no-repeat; + width: 16px; + height: 16px; +} + .Icon.list { - background: url('icons.svg') 80.95238095238095% 81.21212121212122% no-repeat; + background: url('icons.svg') 91.76470588235294% 81.5527607361963% no-repeat; width: 14px; height: 9px; } .Icon.list-active { - background: url('icons.svg') 16.666666666666668% 90.9090909090909% no-repeat; + background: url('icons.svg') 65.88235294117646% 88.34355828220859% no-repeat; width: 14px; height: 9px; } .Icon.locate-land { - background: url('icons.svg') 100% 0 no-repeat; + background: url('icons.svg') 0 100% no-repeat; width: 14px; height: 14px; } .Icon.minus { - background: url('icons.svg') 30.379746835443036% 46.666666666666664% no-repeat; + background: url('icons.svg') 67.5% 43.24324324324324% no-repeat; width: 24px; height: 24px; } .Icon.modal-back { - background: url('icons.svg') 96.55172413793103% 8.75% no-repeat; + background: url('icons.svg') 7.954545454545454% 100% no-repeat; width: 8px; height: 14px; } .Icon.modal-close { - background: url('icons.svg') 100% 17.5% no-repeat; + background: url('icons.svg') 12.941176470588236% 100% no-repeat; width: 14px; height: 14px; } .Icon.move { - background: url('icons.svg') 0 74.68354430379746% no-repeat; + background: url('icons.svg') 27.38095238095238% 82.05128205128206% no-repeat; width: 16px; height: 16px; } .Icon.move-active { - background: url('icons.svg') 9.63855421686747% 74.68354430379746% no-repeat; + background: url('icons.svg') 36.904761904761905% 82.05128205128206% no-repeat; width: 16px; height: 16px; } .Icon.parcels { - background: url('icons.svg') 98.82352941176471% 84.5679012345679% no-repeat; + background: url('icons.svg') 81.3953488372093% 98.75% no-repeat; width: 12px; height: 12px; } .Icon.pin { - background: url('icons.svg') 45.56962025316456% 46.666666666666664% no-repeat; + background: url('icons.svg') 0 70.27027027027027% no-repeat; width: 24px; height: 24px; } .Icon.pin-active { - background: url('icons.svg') 68.35443037974683% 0 no-repeat; + background: url('icons.svg') 15% 70.27027027027027% no-repeat; width: 24px; height: 24px; } .Icon.play { - background: url('icons.svg') 68.35443037974683% 16% no-repeat; + background: url('icons.svg') 30% 70.27027027027027% no-repeat; width: 24px; height: 24px; } .Icon.plus { - background: url('icons.svg') 68.35443037974683% 32% no-repeat; + background: url('icons.svg') 45% 70.27027027027027% no-repeat; width: 24px; height: 24px; } .Icon.preview { - background: url('icons.svg') 19.27710843373494% 71.95121951219512% no-repeat; + background: url('icons.svg') 19.047619047619047% 43.20987654320987% no-repeat; width: 16px; height: 10px; } .Icon.preview-active { - background: url('icons.svg') 28.91566265060241% 71.95121951219512% no-repeat; + background: url('icons.svg') 28.571428571428573% 43.20987654320987% no-repeat; width: 16px; height: 10px; } .Icon.profile { - background: url('icons.svg') 0 62.666666666666664% no-repeat; + background: url('icons.svg') 60% 70.27027027027027% no-repeat; width: 24px; height: 24px; } .Icon.reset-camera { - background: url('icons.svg') 0 84.81012658227849% no-repeat; + background: url('icons.svg') 46.42857142857143% 82.05128205128206% no-repeat; width: 16px; height: 16px; } .Icon.right-round-arrow { - background: url('icons.svg') 9.63855421686747% 84.81012658227849% no-repeat; + background: url('icons.svg') 55.95238095238095% 82.05128205128206% no-repeat; width: 16px; height: 16px; } .Icon.rotate { - background: url('icons.svg') 19.161676646706585% 84.81012658227849% no-repeat; + background: url('icons.svg') 65.08875739644971% 82.05128205128206% no-repeat; width: 15px; height: 16px; } .Icon.rotate-active { - background: url('icons.svg') 28.143712574850298% 84.81012658227849% no-repeat; + background: url('icons.svg') 73.96449704142012% 82.05128205128206% no-repeat; width: 15px; height: 16px; } .Icon.rotate-control { - background: url('icons.svg') 32% 0 no-repeat; + background: url('icons.svg') 0 34.285714285714285% no-repeat; width: 32px; height: 32px; } .Icon.rotate-left { - background: url('icons.svg') 38.55421686746988% 70.65868263473054% no-repeat; + background: url('icons.svg') 47.61904761904762% 43.63636363636363% no-repeat; width: 16px; height: 7px; } .Icon.rotate-right { - background: url('icons.svg') 48.19277108433735% 70.65868263473054% no-repeat; + background: url('icons.svg') 38.095238095238095% 42.42424242424242% no-repeat; width: 16px; height: 7px; } .Icon.scale { - background: url('icons.svg') 37.34939759036145% 84.81012658227849% no-repeat; + background: url('icons.svg') 83.33333333333333% 82.05128205128206% no-repeat; width: 16px; height: 16px; } .Icon.scale-active { - background: url('icons.svg') 46.98795180722892% 84.81012658227849% no-repeat; + background: url('icons.svg') 92.85714285714286% 0 no-repeat; width: 16px; height: 16px; } .Icon.scene-object { - background: url('icons.svg') 54.651162790697676% 84.81012658227849% no-repeat; + background: url('icons.svg') 89.65517241379311% 10.256410256410257% no-repeat; width: 10px; height: 16px; } .Icon.scene-parcel { - background: url('icons.svg') 62.65060240963855% 84.81012658227849% no-repeat; + background: url('icons.svg') 92.85714285714286% 20.512820512820515% no-repeat; width: 16px; height: 16px; } .Icon.share { - background: url('icons.svg') 98.82352941176471% 26.25% no-repeat; + background: url('icons.svg') 20.930232558139537% 100% no-repeat; width: 12px; height: 14px; } .Icon.shortcuts { - background: url('icons.svg') 72.28915662650603% 81.70731707317073% no-repeat; + background: url('icons.svg') 92.85714285714286% 29.62962962962963% no-repeat; width: 16px; height: 10px; } .Icon.sidebar { - background: url('icons.svg') 100% 35% no-repeat; + background: url('icons.svg') 28.235294117647058% 100% no-repeat; width: 14px; height: 14px; } .Icon.sidebar-active { - background: url('icons.svg') 100% 43.75% no-repeat; + background: url('icons.svg') 36.470588235294116% 100% no-repeat; width: 14px; height: 14px; } .Icon.smart { - background: url('icons.svg') 91.56626506024097% 0 no-repeat; - width: 16px; - height: 16px; + background: url('icons.svg') 88.37209302325581% 98.75% no-repeat; + width: 12px; + height: 12px; +} + +.Icon.sound { + background: url('icons.svg') 98.85057471264368% 33.333333333333336% no-repeat; + width: 10px; + height: 10px; } .Icon.table { - background: url('icons.svg') 15.189873417721518% 62.666666666666664% no-repeat; + background: url('icons.svg') 82.5% 0 no-repeat; width: 24px; height: 24px; } .Icon.table-active { - background: url('icons.svg') 30.379746835443036% 62.666666666666664% no-repeat; + background: url('icons.svg') 82.5% 16.216216216216218% no-repeat; width: 24px; height: 24px; } .Icon.textures { - background: url('icons.svg') 98.82352941176471% 91.9753086419753% no-repeat; + background: url('icons.svg') 100% 0 no-repeat; width: 12px; height: 12px; } +.Icon.time { + background: url('icons.svg') 44.705882352941174% 100% no-repeat; + width: 14px; + height: 14px; +} + .Icon.tools { - background: url('icons.svg') 68.35443037974683% 46.753246753246756% no-repeat; + background: url('icons.svg') 82.5% 31.57894736842105% no-repeat; width: 24px; height: 20px; } .Icon.triangles { - background: url('icons.svg') 0 100% no-repeat; + background: url('icons.svg') 100% 7.407407407407407% no-repeat; width: 12px; height: 10px; } .Icon.twitter { - background: url('icons.svg') 45.56962025316456% 61.03896103896104% no-repeat; + background: url('icons.svg') 82.5% 44.73684210526316% no-repeat; width: 24px; height: 20px; } .Icon.undo { - background: url('icons.svg') 91.56626506024097% 10% no-repeat; + background: url('icons.svg') 92.85714285714286% 36.70886075949367% no-repeat; width: 16px; height: 14px; } .Icon.view { - background: url('icons.svg') 30% 20% no-repeat; + background: url('icons.svg') 81.48148148148148% 69.62025316455696% no-repeat; width: 22px; height: 14px; } .Icon.wearable { - background: url('icons.svg') 80% 35.18518518518518% no-repeat; + background: url('icons.svg') 64.67065868263474% 55% no-repeat; width: 17px; height: 12px; } .Icon.zoom-in { - background: url('icons.svg') 91.01796407185628% 38.32138364779874% no-repeat; + background: url('icons.svg') 92.3076923076923% 65.56114649681528% no-repeat; width: 15px; height: 15px; } .Icon.zoom-out { - background: url('icons.svg') 91.01796407185628% 47.75534591194968% no-repeat; + background: url('icons.svg') 92.3076923076923% 75.11528662420382% no-repeat; width: 15px; height: 15px; } diff --git a/src/components/InspectorPage/InspectorPage.tsx b/src/components/InspectorPage/InspectorPage.tsx index 62f293af4..5a3891dec 100644 --- a/src/components/InspectorPage/InspectorPage.tsx +++ b/src/components/InspectorPage/InspectorPage.tsx @@ -1,4 +1,3 @@ -/* eslint-disable no-debugger */ import * as React from 'react' import { Loader } from 'decentraland-ui' import { config } from 'config' @@ -40,17 +39,17 @@ export default class InspectorPage extends React.PureComponent { let binIndexJsUrl = `${PUBLIC_URL}/bin/index.js` // use the local @dcl/inspector running on your machine - if (process.env.REACT_APP_INSPECTOR_PORT) { - htmlUrl = `http://localhost:${process.env.REACT_APP_INSPECTOR_PORT}` + if (process.env.VITE_INSPECTOR_PORT) { + htmlUrl = `http://localhost:${process.env.VITE_INSPECTOR_PORT}` binIndexJsUrl = `${htmlUrl}/bin/index.js` } let queryParams = `?dataLayerRpcParentUrl=${window.location.origin}` // use the local bin/index.js being watched and served on your machine - if (process.env.REACT_APP_BIN_INDEX_JS_DEV_PORT && process.env.REACT_APP_BIN_INDEX_JS_DEV_PATH) { - const b64 = btoa(process.env.REACT_APP_BIN_INDEX_JS_DEV_PATH) - binIndexJsUrl = `http://localhost:${process.env.REACT_APP_BIN_INDEX_JS_DEV_PORT}/content/contents/b64-${b64}` + if (process.env.VITE_BIN_INDEX_JS_DEV_PORT && process.env.VITE_BIN_INDEX_JS_DEV_PATH) { + const b64 = btoa(process.env.VITE_BIN_INDEX_JS_DEV_PATH) + binIndexJsUrl = `http://localhost:${process.env.VITE_BIN_INDEX_JS_DEV_PORT}/content/contents/b64-${b64}` } queryParams = queryParams.concat(`&binIndexJsUrl=${binIndexJsUrl}`) diff --git a/src/components/InspectorPage/TopBar/TopBar.tsx b/src/components/InspectorPage/TopBar/TopBar.tsx index 9a1599696..cf38850d7 100644 --- a/src/components/InspectorPage/TopBar/TopBar.tsx +++ b/src/components/InspectorPage/TopBar/TopBar.tsx @@ -43,7 +43,7 @@ export default function TopBar({ currentProject, isUploading, onBack, onOpenModa {currentProject && ( )} {isUploading && } diff --git a/src/components/Modals/DeployModal/DeployToLand/DeployToLand.tsx b/src/components/Modals/DeployModal/DeployToLand/DeployToLand.tsx index 056acdbac..99fcc2524 100644 --- a/src/components/Modals/DeployModal/DeployToLand/DeployToLand.tsx +++ b/src/components/Modals/DeployModal/DeployToLand/DeployToLand.tsx @@ -14,6 +14,7 @@ import LandAtlas from './LandAtlas' import { hasEnoughSpaceForScene } from './utils' import { Props, State, DeployToLandView } from './DeployToLand.types' import './DeployToLand.css' +import { getThumbnailUrl } from 'modules/project/utils' const MARKETPLACE_WEB_URL = config.get('MARKETPLACE_WEB_URL', '') export default class DeployToLand extends React.PureComponent { @@ -198,10 +199,12 @@ export default class DeployToLand extends React.PureComponent { } renderConfirmation = () => { - const { media, project, error, deployments } = this.props + const { media, project, error, scene, deployments } = this.props const { placement } = this.state const { rows, cols } = project.layout + const thumbnailUrl = getThumbnailUrl(project, scene, media) + return (
@@ -214,7 +217,7 @@ export default class DeployToLand extends React.PureComponent {

{t('deployment_modal.land.confirmation.description')}

- {project.title} + {project.title}
diff --git a/src/components/Modals/DeployModal/DeployToWorld/DeployToWorld.container.ts b/src/components/Modals/DeployModal/DeployToWorld/DeployToWorld.container.ts index 5d256361d..14f86f839 100644 --- a/src/components/Modals/DeployModal/DeployToWorld/DeployToWorld.container.ts +++ b/src/components/Modals/DeployModal/DeployToWorld/DeployToWorld.container.ts @@ -4,7 +4,7 @@ import { RootState } from 'modules/common/types' import { getCurrentProject } from 'modules/project/selectors' import { getENSByWallet, getExternalNamesForConnectedWallet } from 'modules/ens/selectors' import { deployToWorldRequest } from 'modules/deployment/actions' -import { getCurrentMetrics } from 'modules/scene/selectors' +import { getCurrentMetrics, getCurrentScene } from 'modules/scene/selectors' import { recordMediaRequest } from 'modules/media/actions' import { getDeploymentsByWorlds, getProgress as getUploadProgress, getError, isLoading } from 'modules/deployment/selectors' import { Project } from 'modules/project/types' @@ -17,6 +17,7 @@ const mapState = (state: RootState): MapStateProps => { ensList: getENSByWallet(state), externalNames: getExternalNamesForConnectedWallet(state), project: getCurrentProject(state) as Project, + scene: getCurrentScene(state), metrics: getCurrentMetrics(state), deployments: getDeploymentsByWorlds(state), deploymentProgress: getUploadProgress(state), diff --git a/src/components/Modals/DeployModal/DeployToWorld/DeployToWorld.tsx b/src/components/Modals/DeployModal/DeployToWorld/DeployToWorld.tsx index 9ad67792f..3532c312c 100644 --- a/src/components/Modals/DeployModal/DeployToWorld/DeployToWorld.tsx +++ b/src/components/Modals/DeployModal/DeployToWorld/DeployToWorld.tsx @@ -11,6 +11,7 @@ import { Deployment } from 'modules/deployment/types' import CopyToClipboard from 'components/CopyToClipboard/CopyToClipboard' import Icon from 'components/Icon' import { InfoIcon } from 'components/InfoIcon' +import { getThumbnailUrl } from 'modules/project/utils' import { DeployToWorldView, NameType, Props } from './DeployToWorld.types' import { getSizesFromDeploymentError } from './utils' import dclImage from './images/dcl.svg' @@ -26,6 +27,7 @@ const CLAIM_NAME_OPTION = 'claim_name_option' export default function DeployToWorld({ name, project, + scene, metrics, ensList, externalNames, @@ -332,7 +334,7 @@ export default function DeployToWorld({ } const renderThumbnail = () => { - const thumbnailUrl = project.thumbnail + const thumbnailUrl = getThumbnailUrl(project, scene) return (
export type MapDispatchProps = Pick export type MapDispatch = Dispatch< diff --git a/src/components/Modals/EditProjectModal/EditProjectModal.tsx b/src/components/Modals/EditProjectModal/EditProjectModal.tsx index 66e538dd6..95ee9c77d 100644 --- a/src/components/Modals/EditProjectModal/EditProjectModal.tsx +++ b/src/components/Modals/EditProjectModal/EditProjectModal.tsx @@ -65,18 +65,22 @@ export default class EditProjectModal extends React.PureComponent } render() { - const { name, deploymentStatus, onClose } = this.props + const { name, deploymentStatus, onClose, currentScene } = this.props const { title, description, rows, cols, hasError } = this.state const isSubmitDisabled = hasError || deploymentStatus !== DeploymentStatus.UNPUBLISHED return (
- {t('edit_project_modal.title')} + {currentScene.sdk6 ? {t('edit_project_modal.title')} : null}
- - + {currentScene.sdk6 ? ( + <> + + + + ) : null}
{t('edit_project_modal.custom_layout_label')} diff --git a/src/components/ProjectCard/ProjectCard.tsx b/src/components/ProjectCard/ProjectCard.tsx index b3ea07fa3..99bd99808 100644 --- a/src/components/ProjectCard/ProjectCard.tsx +++ b/src/components/ProjectCard/ProjectCard.tsx @@ -10,6 +10,7 @@ import DeploymentStatus from 'components/DeploymentStatus' import Icon from 'components/Icon' import { OptionsDropdown } from 'components/OptionsDropdown' import SDKTag from 'components/SDKTag/SDKTag' +import { getThumbnailUrl } from 'modules/project/utils' import { Props, DefaultProps, State } from './ProjectCard.types' import './ProjectCard.css' @@ -65,13 +66,13 @@ export default class ProjectCard extends React.PureComponent { let style = {} let classes = 'ProjectCard' - if (project.thumbnail) { + let thumbnailUrl = getThumbnailUrl(project, scene) + if (thumbnailUrl) { // prevent caching remote images when they are updated - let url = project.thumbnail - if (url && isRemoteURL(url)) { - url += `?updated_at=${+new Date(project.updatedAt)}` + if (thumbnailUrl && isRemoteURL(thumbnailUrl)) { + thumbnailUrl += `?updated_at=${+new Date(project.updatedAt)}` } - style = { backgroundImage: `url(${url})` } + style = { backgroundImage: `url(${thumbnailUrl})` } classes += ' has-thumbnail' } diff --git a/src/icons/layout.svg b/src/icons/layout.svg new file mode 100644 index 000000000..27983f7a8 --- /dev/null +++ b/src/icons/layout.svg @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/src/modules/deployment/sagas.ts b/src/modules/deployment/sagas.ts index 1ef6dee0c..574b95692 100644 --- a/src/modules/deployment/sagas.ts +++ b/src/modules/deployment/sagas.ts @@ -1,3 +1,4 @@ +import { merge } from 'ts-deepmerge' import { createFetchComponent } from '@well-known-components/fetch-component' import { CatalystClient, ContentClient, createContentClient } from 'dcl-catalyst-client' import { Authenticator, AuthIdentity } from '@dcl/crypto' @@ -259,7 +260,7 @@ export function* deploymentSaga(builder: BuilderAPI, catalystClient: CatalystCli { north: thumbnail, east: thumbnail, south: thumbnail, west: thumbnail }, handleProgress(ProgressStage.UPLOAD_RECORDING) ) - files['scene-thumbnail.png'] = thumbnail + files['assets/scene/thumbnail.png'] = thumbnail previewUrl = getPreviewUrl(project.id) } else { console.warn('Failed to upload scene preview') @@ -277,7 +278,7 @@ export function* deploymentSaga(builder: BuilderAPI, catalystClient: CatalystCli const smartItemComponents = ['asset-packs::Actions', 'asset-packs::Triggers'] const hasSmartItems = Array.from(componentNames).some(componentName => smartItemComponents.includes(componentName)) - const definition: SceneDefinition = { + let definition: SceneDefinition = { allowedMediaHostnames: [], owner: address || '', main: 'bin/index.js', @@ -288,7 +289,7 @@ export function* deploymentSaga(builder: BuilderAPI, catalystClient: CatalystCli display: { title: project.title, favicon: 'favicon_asset', - navmapThumbnail: 'scene-thumbnail.png' + navmapThumbnail: 'assets/scene/thumbnail.png' }, tags: hasSmartItems ? ['is_smart'] : [], scene: { @@ -309,6 +310,22 @@ export function* deploymentSaga(builder: BuilderAPI, catalystClient: CatalystCli } } + if (scene.sdk7.metadata) { + definition = merge.withOptions( + { mergeArrays: false }, + definition, + // override base definition with configuration in the scene.json + scene.sdk7.metadata as unknown as SceneDefinition, + { + // override coords with actual placement + scene: { + base: toString(base), + parcels: parcels.map(toString) + } as unknown as SceneDefinition + } + ) + } + if (world) { definition.worldConfiguration = { name: world diff --git a/src/modules/inspector/sagas.ts b/src/modules/inspector/sagas.ts index f308ff59d..b4c74777f 100644 --- a/src/modules/inspector/sagas.ts +++ b/src/modules/inspector/sagas.ts @@ -3,6 +3,7 @@ import { call, delay, put, race, select, take, takeEvery } from 'redux-saga/effe import { future, IFuture } from 'fp-future' import { hashV1 } from '@dcl/hashing' import { isErrorWithMessage } from 'decentraland-dapps/dist/lib/error' +import { merge } from 'ts-deepmerge' import { LoginFailureAction, LoginSuccessAction, LOGIN_FAILURE, LOGIN_SUCCESS } from 'modules/identity/actions' import { isLoggingIn } from 'modules/identity/selectors' import { getProjectId } from 'modules/location/utils' @@ -17,7 +18,8 @@ import { LOAD_PROJECTS_REQUEST, LOAD_PROJECTS_SUCCESS, LOAD_PROJECT_SCENE_FAILURE, - LOAD_PROJECT_SCENE_SUCCESS + LOAD_PROJECT_SCENE_SUCCESS, + editProject } from 'modules/project/actions' import { getCurrentProject, getData as getProjects, getLoading as getLoadingProjects } from 'modules/project/selectors' import { getCurrentScene } from 'modules/scene/selectors' @@ -127,7 +129,7 @@ export function* inspectorSaga(builder: BuilderAPI, store: RootStore) { // configure UI const ui = new UiClient(transport) yield call([ui, 'selectAssetsTab'], 'AssetsPack') - yield call([ui, 'toggleComponent'], 'inspector::Scene', false) + yield call([ui, 'toggleSceneInspectorTab'], 'layout', false) // wait for RPC to be idle (3 seconds) yield waitForRpcIdle(3000) @@ -198,6 +200,18 @@ export function* inspectorSaga(builder: BuilderAPI, store: RootStore) { return assets.get(path) } + if (path === 'assets/scene/thumbnail.png' || path === 'thumbnails/scene/thumbnail.png') { + const project: Project = yield select(getCurrentProject) + if (project.thumbnail.startsWith('data:')) { + const data = project.thumbnail.split(',')[1] + return Buffer.from(data, 'base64') + } else { + const response: Response = yield call(fetch, project.thumbnail, { headers: NO_CACHE_HEADERS }) + const buffer: ArrayBuffer = yield call([response, 'arrayBuffer']) + return Buffer.from(buffer) + } + } + if (path in scene.mappings) { const hash = scene.mappings[path] const response: Response = yield call(fetch, getContentsStorageUrl(hash), { headers: NO_CACHE_HEADERS }) @@ -209,16 +223,35 @@ export function* inspectorSaga(builder: BuilderAPI, store: RootStore) { switch (path) { case 'scene.json': { const project: Project = yield select(getCurrentProject) - file = JSON.stringify({ + let metadata: SceneSDK7['metadata'] = { + display: { + title: project.title, + description: project.description, + navmapThumbnail: 'assets/scene/thumbnail.png' + }, scene: { parcels: getParcels(project.layout).map($ => `${$.x},${$.y}`), base: '0,0' } - }) + } + if (scene.metadata) { + metadata = merge.withOptions({ mergeArrays: false }, metadata, scene.metadata) + } + file = JSON.stringify(metadata) break } case 'assets/scene/main.composite': { - file = JSON.stringify(scene.composite) + // keep a copy of the SceneMetadata as Scene component, this is for backwards compatibility in the builder server. + const sceneMetadataComponent = scene.composite.components.find(component => component.name === 'inspector::SceneMetadata') + const newComponents = [ + ...scene.composite.components.filter(component => component.name !== 'inspector::Scene'), + { + ...sceneMetadataComponent, + name: 'inspector::Scene' + } + ] + const newComposite = { ...scene.composite, components: newComponents } + file = JSON.stringify(newComposite) break } case 'inspector-preferences.json': { @@ -242,6 +275,8 @@ export function* inspectorSaga(builder: BuilderAPI, store: RootStore) { switch (path) { case 'scene.json': case 'assets/scene/main.composite': + case 'assets/scene/thumbnail.png': + case 'thumbnails/scene/thumbnail.png': case 'inspector-preferences.json': { return true } @@ -257,6 +292,13 @@ export function* inspectorSaga(builder: BuilderAPI, store: RootStore) { const scene: SceneSDK7 = yield getScene() const paths = [...Object.keys(scene.mappings), 'assets/scene/main.composite'] + + const project: Project = yield select(getCurrentProject) + if (project.thumbnail) { + paths.push('assets/scene/thumbnail.png') + paths.push('thumbnails/scene/thumbnail.png') + } + const files: { name: string; isDirectory: boolean }[] = [] for (const _path of paths) { @@ -281,7 +323,23 @@ export function* inspectorSaga(builder: BuilderAPI, store: RootStore) { const { path, content } = params switch (path) { case 'scene.json': { - // TODO: some changes to the scene.json might eventually end up in changes to the Project, like the name or the layout, but for now we can ignore it + const metadata = JSON.parse(new TextDecoder().decode(content)) + const project: Project = yield select(getCurrentProject) + if (project.title !== metadata.display.title || project.description !== metadata.display.description) { + yield put( + editProject(project.id, { + ...project, + title: metadata.display.title, + description: metadata.display.description + }) + ) + } + const scene: SceneSDK7 = yield getScene() + const newScene: SceneSDK7 = { + ...scene, + metadata + } + yield put(updateScene(newScene)) break } case 'assets/scene/main.composite': { diff --git a/src/modules/inspector/utils.ts b/src/modules/inspector/utils.ts index a95b83e80..0bec180cd 100644 --- a/src/modules/inspector/utils.ts +++ b/src/modules/inspector/utils.ts @@ -1,3 +1,4 @@ +import { merge } from 'ts-deepmerge' import { Composite, CompositeDefinition } from '@dcl/ecs' import { createEngineContext, dumpEngineToComposite, dumpEngineToCrdtCommands } from '@dcl/inspector' import { Layout, Project } from 'modules/project/types' @@ -76,34 +77,12 @@ export function toCrdt(scene: SceneSDK6, project?: Project) { } export function changeLayout(scene: SceneSDK7, layout: Layout) { - const sceneComponent = scene.composite.components.find(component => component.name === 'inspector::Scene')! - const newData = { - ...sceneComponent.data - } as any - - newData[0] = { - ...newData[0], - json: { - ...newData[0].json, - layout: { - ...newData[0].json.layout, - parcels: getParcels(layout) - } - } - } - - const newScene: SceneSDK7 = { - ...scene, - composite: { - ...scene.composite, - components: [ - ...scene.composite.components.filter(component => component.name !== 'inspector::Scene'), - { - ...sceneComponent, - data: newData - } - ] + const newScene: SceneSDK7 = merge({}, scene) + const parcels = getParcels(layout).map(({ x, y }) => `${x},${y}`) + newScene.metadata = merge.withOptions({ mergeArrays: false }, newScene.metadata!, { + scene: { + parcels } - } + }) return newScene } diff --git a/src/modules/media/sagas.ts b/src/modules/media/sagas.ts index 842bbfb85..e07f50c11 100644 --- a/src/modules/media/sagas.ts +++ b/src/modules/media/sagas.ts @@ -1,4 +1,3 @@ -/* eslint-disable no-debugger */ import { select, delay, put, call, takeLatest } from 'redux-saga/effects' import { MessageTransport } from '@dcl/mini-rpc' import { CameraClient } from '@dcl/inspector' diff --git a/src/modules/project/utils.ts b/src/modules/project/utils.ts index 7ab49299a..05b61adf3 100644 --- a/src/modules/project/utils.ts +++ b/src/modules/project/utils.ts @@ -2,6 +2,9 @@ import { Project, Layout, Manifest } from 'modules/project/types' import { Coordinate, Rotation } from 'modules/deployment/types' import { NO_CACHE_HEADERS } from 'lib/headers' import { getDimensions } from 'lib/layout' +import { Scene } from 'modules/scene/types' +import { getContentsStorageUrl } from 'lib/api/builder' +import { Media } from 'modules/media/types' export function getProjectDimensions(project: Project): string { const { rows, cols } = project.layout @@ -96,3 +99,14 @@ export async function getTemplate(projectId: string) { } return template } + +export function getThumbnailUrl(project: Project, scene?: Scene | null, media?: Media | null) { + let thumbnailUrl = media ? media.preview : project.thumbnail + if (scene && scene.sdk7?.metadata?.display?.navmapThumbnail) { + const hash = scene.sdk7.mappings[scene.sdk7?.metadata?.display?.navmapThumbnail] + if (hash) { + thumbnailUrl = getContentsStorageUrl(hash) + } + } + return thumbnailUrl +} diff --git a/src/modules/scene/types.ts b/src/modules/scene/types.ts index 29c0888e5..ff4606021 100644 --- a/src/modules/scene/types.ts +++ b/src/modules/scene/types.ts @@ -1,4 +1,5 @@ import { CompositeDefinition } from '@dcl/ecs' +import { Scene as SceneMetadata } from '@dcl/schemas' import { Asset, AssetParameterValues } from 'modules/asset/types' import { ModelMetrics, Vector3, Quaternion } from 'modules/models/types' @@ -78,4 +79,5 @@ export type SceneSDK7 = { id: string composite: CompositeDefinition mappings: Record + metadata?: Omit & { rating?: 'T' | 'A' } } diff --git a/vite.config.ts b/vite.config.ts index 5c524863b..33d1a64ed 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -15,7 +15,10 @@ export default defineConfig(({ mode }) => { 'process.env': { // eslint-disable-next-line @typescript-eslint/naming-convention VITE_REACT_APP_DCL_DEFAULT_ENV: envVariables.VITE_REACT_APP_DCL_DEFAULT_ENV, - VITE_BASE_URL: envVariables.VITE_BASE_URL + VITE_BASE_URL: envVariables.VITE_BASE_URL, + VITE_INSPECTOR_PORT: envVariables.VITE_INSPECTOR_PORT, + VITE_BIN_INDEX_JS_DEV_PORT: envVariables.VITE_BIN_INDEX_JS_DEV_PORT, + VITE_BIN_INDEX_JS_DEV_PATH: envVariables.VITE_BIN_INDEX_JS_DEV_PATH }, global: {} },