Initial commit
This commit is contained in:
403
package-lock.json
generated
403
package-lock.json
generated
@@ -16,11 +16,15 @@
|
||||
"@types/node": "^16.18.126",
|
||||
"@types/react": "^19.2.2",
|
||||
"@types/react-dom": "^19.2.2",
|
||||
"clsx": "^2.1.1",
|
||||
"react": "^19.2.0",
|
||||
"react-dom": "^19.2.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"typescript": "^4.9.5",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"sass": "^1.93.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@adobe/css-tools": {
|
||||
@@ -3019,6 +3023,316 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz",
|
||||
"integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"detect-libc": "^1.0.3",
|
||||
"is-glob": "^4.0.3",
|
||||
"micromatch": "^4.0.5",
|
||||
"node-addon-api": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@parcel/watcher-android-arm64": "2.5.1",
|
||||
"@parcel/watcher-darwin-arm64": "2.5.1",
|
||||
"@parcel/watcher-darwin-x64": "2.5.1",
|
||||
"@parcel/watcher-freebsd-x64": "2.5.1",
|
||||
"@parcel/watcher-linux-arm-glibc": "2.5.1",
|
||||
"@parcel/watcher-linux-arm-musl": "2.5.1",
|
||||
"@parcel/watcher-linux-arm64-glibc": "2.5.1",
|
||||
"@parcel/watcher-linux-arm64-musl": "2.5.1",
|
||||
"@parcel/watcher-linux-x64-glibc": "2.5.1",
|
||||
"@parcel/watcher-linux-x64-musl": "2.5.1",
|
||||
"@parcel/watcher-win32-arm64": "2.5.1",
|
||||
"@parcel/watcher-win32-ia32": "2.5.1",
|
||||
"@parcel/watcher-win32-x64": "2.5.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-android-arm64": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz",
|
||||
"integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-darwin-arm64": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz",
|
||||
"integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-darwin-x64": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz",
|
||||
"integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-freebsd-x64": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz",
|
||||
"integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-linux-arm-glibc": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz",
|
||||
"integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-linux-arm-musl": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz",
|
||||
"integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-linux-arm64-glibc": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz",
|
||||
"integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-linux-arm64-musl": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz",
|
||||
"integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-linux-x64-glibc": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz",
|
||||
"integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-linux-x64-musl": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz",
|
||||
"integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-win32-arm64": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz",
|
||||
"integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-win32-ia32": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz",
|
||||
"integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-win32-x64": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz",
|
||||
"integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/@pkgjs/parseargs": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||
@@ -5678,6 +5992,15 @@
|
||||
"wrap-ansi": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/clsx": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
||||
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/co": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
|
||||
@@ -6621,6 +6944,20 @@
|
||||
"npm": "1.2.8000 || >= 1.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
|
||||
"integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"bin": {
|
||||
"detect-libc": "bin/detect-libc.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-newline": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
|
||||
@@ -9211,6 +9548,13 @@
|
||||
"url": "https://opencollective.com/immer"
|
||||
}
|
||||
},
|
||||
"node_modules/immutable": {
|
||||
"version": "5.1.4",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz",
|
||||
"integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==",
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/import-fresh": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
|
||||
@@ -11614,6 +11958,14 @@
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/node-addon-api": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
|
||||
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/node-forge": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
|
||||
@@ -14522,6 +14874,27 @@
|
||||
"integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==",
|
||||
"license": "CC0-1.0"
|
||||
},
|
||||
"node_modules/sass": {
|
||||
"version": "1.93.2",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.93.2.tgz",
|
||||
"integrity": "sha512-t+YPtOQHpGW1QWsh1CHQ5cPIr9lbbGZLZnbihP/D/qZj/yuV68m8qarcV17nvkOX81BCrvzAlq2klCQFZghyTg==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chokidar": "^4.0.0",
|
||||
"immutable": "^5.0.2",
|
||||
"source-map-js": ">=0.6.2 <2.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"sass": "sass.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@parcel/watcher": "^2.4.1"
|
||||
}
|
||||
},
|
||||
"node_modules/sass-loader": {
|
||||
"version": "12.6.0",
|
||||
"resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz",
|
||||
@@ -14560,6 +14933,36 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/sass/node_modules/chokidar": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
|
||||
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"readdirp": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.16.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/sass/node_modules/readdirp": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
|
||||
"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 14.18.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/sax": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"@types/node": "^16.18.126",
|
||||
"@types/react": "^19.2.2",
|
||||
"@types/react-dom": "^19.2.2",
|
||||
"clsx": "^2.1.1",
|
||||
"react": "^19.2.0",
|
||||
"react-dom": "^19.2.0",
|
||||
"react-scripts": "5.0.1",
|
||||
@@ -40,5 +41,8 @@
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"sass": "^1.93.2"
|
||||
}
|
||||
}
|
||||
|
||||
24
src/App.tsx
24
src/App.tsx
@@ -1,26 +1,8 @@
|
||||
import React from 'react';
|
||||
import logo from './logo.svg';
|
||||
import './App.css';
|
||||
import SceneView from "./pages/SceneView";
|
||||
import "./styles/main.scss";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div className="App">
|
||||
<header className="App-header">
|
||||
<img src={logo} className="App-logo" alt="logo" />
|
||||
<p>
|
||||
Edit <code>src/App.tsx</code> and save to reload.
|
||||
</p>
|
||||
<a
|
||||
className="App-link"
|
||||
href="https://reactjs.org"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Learn React
|
||||
</a>
|
||||
</header>
|
||||
</div>
|
||||
);
|
||||
return <SceneView />;
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
||||
487
src/components/outlinePanel/OutlineList .tsx
Normal file
487
src/components/outlinePanel/OutlineList .tsx
Normal file
@@ -0,0 +1,487 @@
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
AddIcon,
|
||||
ChevronIcon,
|
||||
CollapseAllIcon,
|
||||
CubeIcon,
|
||||
EyeIcon,
|
||||
FocusIcon,
|
||||
FolderIcon,
|
||||
KebebIcon,
|
||||
LockIcon,
|
||||
} from "../../icons/ExportIcons";
|
||||
import { OutlinePanelProps } from "./OutlinePanel";
|
||||
import clsx from "clsx";
|
||||
|
||||
interface AssetGroupChild {
|
||||
groupUuid?: string;
|
||||
groupName?: string;
|
||||
isExpanded?: boolean;
|
||||
children?: AssetGroupChild[];
|
||||
modelUuid?: string;
|
||||
modelName?: string;
|
||||
isVisible?: boolean;
|
||||
isLocked?: boolean;
|
||||
}
|
||||
|
||||
interface TreeNodeProps {
|
||||
item: AssetGroupChild;
|
||||
level?: number;
|
||||
textColor?: string;
|
||||
eyeIconColor?: string;
|
||||
lockIconColor?: string;
|
||||
onDragStart: (item: AssetGroupChild) => void;
|
||||
onDrop: (item: AssetGroupChild, parent: AssetGroupChild | null, e: any) => void;
|
||||
draggingItem: AssetGroupChild | null;
|
||||
selectedObject: string | null;
|
||||
onDragOver: (item: AssetGroupChild, parent: AssetGroupChild | null, e: React.DragEvent) => void;
|
||||
setSelectedObject: React.Dispatch<React.SetStateAction<string | null>>;
|
||||
}
|
||||
|
||||
type DropAction = "above" | "child" | "below" | "none";
|
||||
|
||||
const DEFAULT_PRAMS = {
|
||||
backgroundColor: "linear-gradient(to bottom, #1e1e2f, #12121a)",
|
||||
panelSide: "left",
|
||||
textColor: "linear-gradient(to bottom, rgba(231, 231, 255, 1), #cacad6ff)",
|
||||
addIconColor: "white",
|
||||
lockIconColor: "white",
|
||||
eyeIconColor: "white",
|
||||
};
|
||||
|
||||
const TreeNode: React.FC<TreeNodeProps> = ({
|
||||
item,
|
||||
level = 0,
|
||||
textColor,
|
||||
eyeIconColor,
|
||||
lockIconColor,
|
||||
onDragStart,
|
||||
onDrop,
|
||||
draggingItem,
|
||||
setSelectedObject,
|
||||
selectedObject,
|
||||
onDragOver,
|
||||
}) => {
|
||||
const isGroupNode =
|
||||
Array.isArray(item.children) && item.children.length > 0 ? item.children : false;
|
||||
const [isExpanded, setIsExpanded] = useState(item.isExpanded || false);
|
||||
const [isVisible, setIsVisible] = useState(item.isVisible ?? true);
|
||||
const [isLocked, setIsLocked] = useState(item.isLocked ?? false);
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const [name, setName] = useState(isGroupNode ? item.groupName : item.modelName);
|
||||
|
||||
const handleDragStart = (e: React.DragEvent) => {
|
||||
e.stopPropagation();
|
||||
onDragStart(item);
|
||||
};
|
||||
|
||||
const handleDragOver = (e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
onDragOver(item, draggingItem, e);
|
||||
};
|
||||
|
||||
const handleDrop = (e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
onDrop(item, draggingItem, e);
|
||||
};
|
||||
|
||||
const isBeingDragged =
|
||||
draggingItem?.groupUuid === item.groupUuid || draggingItem?.modelUuid === item.modelUuid;
|
||||
|
||||
const handleDoubleClick = () => {
|
||||
setIsEditing(true);
|
||||
};
|
||||
|
||||
const handleBlur = () => {
|
||||
setIsEditing(false);
|
||||
};
|
||||
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === "Enter") {
|
||||
setIsEditing(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Toggle selection (used by mouse click, keyboard and touch)
|
||||
const toggleSelect = () => {
|
||||
const currentId = item.modelUuid || item.groupUuid || null;
|
||||
setSelectedObject((prev) => (prev === currentId ? null : currentId));
|
||||
};
|
||||
|
||||
const handleDivKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {
|
||||
// support Enter and Space for accessibility
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault();
|
||||
toggleSelect();
|
||||
}
|
||||
};
|
||||
|
||||
const handleTouchStart = () => {
|
||||
toggleSelect();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="tree-node">
|
||||
<div
|
||||
tabIndex={0}
|
||||
onKeyDown={handleDivKeyDown}
|
||||
onTouchStart={handleTouchStart}
|
||||
className={clsx("tree-node-content", {
|
||||
"group-node": isGroupNode,
|
||||
"asset-node": !isGroupNode,
|
||||
selected: selectedObject === item.modelUuid,
|
||||
locked: isLocked,
|
||||
hidden: !isVisible,
|
||||
dragging: isBeingDragged,
|
||||
})}
|
||||
draggable
|
||||
onDragStart={handleDragStart}
|
||||
onDragOver={handleDragOver}
|
||||
onDrop={handleDrop}
|
||||
id={item.modelUuid || item.groupUuid}
|
||||
onClick={toggleSelect}
|
||||
>
|
||||
<div className="node-wrapper" style={{ paddingLeft: `${level * 25 + 8}px` }}>
|
||||
{isGroupNode && (
|
||||
<button
|
||||
className="expand-button"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation(); // prevent triggering selection
|
||||
setIsExpanded(!isExpanded);
|
||||
}}
|
||||
>
|
||||
<ChevronIcon isOpen={isExpanded} />
|
||||
</button>
|
||||
)}
|
||||
|
||||
<div className="node-icon">
|
||||
{isGroupNode ? <FolderIcon isOpen={isExpanded} /> : <CubeIcon />}
|
||||
</div>
|
||||
|
||||
<div className="rename-input" onDoubleClick={handleDoubleClick}>
|
||||
{isEditing ? (
|
||||
<input
|
||||
autoFocus
|
||||
value={name}
|
||||
className="renaming"
|
||||
style={{ color: textColor }}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
onBlur={handleBlur}
|
||||
onKeyDown={handleKeyDown}
|
||||
/>
|
||||
) : (
|
||||
<span
|
||||
className="rename-input"
|
||||
style={{ color: textColor || DEFAULT_PRAMS.textColor }}
|
||||
>
|
||||
{name}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="node-controls">
|
||||
<button
|
||||
className="control-button"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setIsVisible(!isVisible);
|
||||
}}
|
||||
>
|
||||
<EyeIcon
|
||||
isClosed={!isVisible}
|
||||
color={eyeIconColor || DEFAULT_PRAMS.eyeIconColor}
|
||||
/>
|
||||
</button>
|
||||
{isGroupNode && item.children?.length ? (
|
||||
<button className="control-button">
|
||||
<FocusIcon />
|
||||
</button>
|
||||
) : null}
|
||||
<button
|
||||
className="control-button"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setIsLocked(!isLocked);
|
||||
}}
|
||||
>
|
||||
<LockIcon
|
||||
isLocked={isLocked}
|
||||
color={lockIconColor || DEFAULT_PRAMS.lockIconColor}
|
||||
/>
|
||||
</button>
|
||||
{isGroupNode ? (
|
||||
<button className="control-button">
|
||||
<KebebIcon />
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{isExpanded && item.children?.length ? (
|
||||
<div className="tree-children">
|
||||
{item.children.map((child) => (
|
||||
<TreeNode
|
||||
key={child.groupUuid || child.modelUuid}
|
||||
item={child}
|
||||
level={level + 1}
|
||||
onDragStart={onDragStart}
|
||||
onDrop={onDrop}
|
||||
draggingItem={draggingItem}
|
||||
selectedObject={selectedObject}
|
||||
setSelectedObject={setSelectedObject}
|
||||
onDragOver={onDragOver}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const OutlineList: React.FC<OutlinePanelProps> = ({
|
||||
backgroundColor = "linear-gradient(to bottom, #1e1e2f, #12121a)",
|
||||
panelSide = "left",
|
||||
textColor = "linear-gradient(to bottom, rgba(231, 231, 255, 1), #cacad6ff)",
|
||||
addIconColor,
|
||||
lockIconColor,
|
||||
eyeIconColor,
|
||||
}) => {
|
||||
const [selectedObject, setSelectedObject] = useState<string | null>(null); // store UUID
|
||||
|
||||
const [isOpen, setIsOpen] = useState(true);
|
||||
const [draggingItem, setDraggingItem] = useState<AssetGroupChild | null>(null);
|
||||
const [groupHierarchy, setGroupHierarchy] = useState<AssetGroupChild[]>([
|
||||
{ modelUuid: "a1", modelName: "Asset 1", isVisible: true, isLocked: false, children: [] },
|
||||
{ modelUuid: "a2", modelName: "Asset 2", isVisible: true, isLocked: false, children: [] },
|
||||
{ modelUuid: "a3", modelName: "Asset 3", isVisible: true, isLocked: false, children: [] },
|
||||
{ modelUuid: "a4", modelName: "Asset 4", isVisible: true, isLocked: false, children: [] },
|
||||
{ modelUuid: "a5", modelName: "Asset 5", isVisible: true, isLocked: false, children: [] },
|
||||
{ modelUuid: "a6", modelName: "Asset 6", isVisible: true, isLocked: false, children: [] },
|
||||
]);
|
||||
|
||||
const handleDragStart = (item: AssetGroupChild) => {
|
||||
setDraggingItem(item); // Set the dragged item when dragging starts
|
||||
};
|
||||
|
||||
const handleDrop = (
|
||||
targetItem: AssetGroupChild,
|
||||
draggedItem: AssetGroupChild | null,
|
||||
event: DragEvent | React.DragEvent
|
||||
) => {
|
||||
if (!draggedItem) return;
|
||||
|
||||
const targetId = targetItem.modelUuid;
|
||||
if (!targetId) return;
|
||||
|
||||
const hoveredDiv = document.getElementById(targetId);
|
||||
if (!hoveredDiv) return;
|
||||
|
||||
// Calculate drop position
|
||||
const rect = hoveredDiv.getBoundingClientRect();
|
||||
const parentScrollTop = hoveredDiv.parentElement?.scrollTop || 0;
|
||||
const y = (event as any).clientY - (rect.top + parentScrollTop);
|
||||
|
||||
// Determine drop action
|
||||
const action = getDropAction(y);
|
||||
if (action === "none") {
|
||||
hoveredDiv.style.borderTop = "none";
|
||||
hoveredDiv.style.borderBottom = "none";
|
||||
hoveredDiv.style.outline = "none";
|
||||
hoveredDiv.style.border = "none";
|
||||
setDraggingItem(null);
|
||||
return;
|
||||
}
|
||||
|
||||
// Update hierarchy
|
||||
const updatedHierarchy = [...groupHierarchy];
|
||||
|
||||
if (!removeItemFromHierarchy(draggedItem, updatedHierarchy)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!insertItemByAction(draggedItem, targetId, action, updatedHierarchy)) {
|
||||
updatedHierarchy.push(draggedItem);
|
||||
}
|
||||
|
||||
// Commit changes
|
||||
setGroupHierarchy(updatedHierarchy);
|
||||
setDraggingItem(null);
|
||||
hoveredDiv.style.borderTop = "none";
|
||||
hoveredDiv.style.borderBottom = "none";
|
||||
hoveredDiv.style.outline = "none";
|
||||
hoveredDiv.style.border = "none";
|
||||
};
|
||||
|
||||
const getDropAction = (y: number): DropAction => {
|
||||
if (y >= 0 && y < 7) return "above";
|
||||
if (y >= 7 && y < 19) return "child";
|
||||
if (y >= 19 && y < 32) return "below";
|
||||
return "none";
|
||||
};
|
||||
|
||||
const removeItemFromHierarchy = (
|
||||
item: AssetGroupChild,
|
||||
hierarchy: AssetGroupChild[]
|
||||
): boolean => {
|
||||
for (let i = 0; i < hierarchy.length; i++) {
|
||||
const current = hierarchy[i];
|
||||
if (current.modelUuid === item.modelUuid) {
|
||||
hierarchy.splice(i, 1);
|
||||
return true;
|
||||
}
|
||||
if (current.children?.length) {
|
||||
const removed = removeItemFromHierarchy(item, current.children);
|
||||
if (removed) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const insertItemByAction = (
|
||||
item: AssetGroupChild,
|
||||
targetId: string,
|
||||
action: DropAction,
|
||||
hierarchy: AssetGroupChild[]
|
||||
): boolean => {
|
||||
switch (action) {
|
||||
case "above":
|
||||
return insertAsSibling(item, targetId, hierarchy, 0);
|
||||
case "below":
|
||||
return insertAsSibling(item, targetId, hierarchy, 1);
|
||||
case "child":
|
||||
return addAsChild(targetId, item, hierarchy);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const insertAsSibling = (
|
||||
item: AssetGroupChild,
|
||||
targetId: string,
|
||||
hierarchy: AssetGroupChild[],
|
||||
offset: number // 0 for above, 1 for below
|
||||
): boolean => {
|
||||
for (let i = 0; i < hierarchy.length; i++) {
|
||||
if (hierarchy[i].modelUuid === targetId) {
|
||||
hierarchy.splice(i + offset, 0, item);
|
||||
return true;
|
||||
}
|
||||
if (hierarchy[i].children?.length) {
|
||||
const inserted = insertAsSibling(item, targetId, hierarchy[i].children!, offset);
|
||||
if (inserted) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const addAsChild = (
|
||||
parentId: string,
|
||||
childItem: AssetGroupChild,
|
||||
hierarchy: AssetGroupChild[]
|
||||
): boolean => {
|
||||
for (let i = 0; i < hierarchy.length; i++) {
|
||||
if (hierarchy[i].modelUuid === parentId) {
|
||||
if (!hierarchy[i].children) hierarchy[i].children = [];
|
||||
hierarchy[i].children!.push(childItem);
|
||||
return true;
|
||||
}
|
||||
if (hierarchy[i].children?.length) {
|
||||
const added = addAsChild(parentId, childItem, hierarchy[i].children!);
|
||||
if (added) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const handleDragOver = (
|
||||
targetItem: AssetGroupChild,
|
||||
draggedItem: AssetGroupChild | null,
|
||||
event: DragEvent | React.DragEvent
|
||||
) => {
|
||||
event.preventDefault();
|
||||
const targetId = targetItem?.modelUuid || targetItem?.groupUuid;
|
||||
if (!targetId) return;
|
||||
|
||||
const hoveredDiv = document.getElementById(targetId);
|
||||
if (!hoveredDiv) return;
|
||||
|
||||
// Remove previous outlines before applying new one
|
||||
hoveredDiv.style.outline = "none";
|
||||
hoveredDiv.style.borderTop = "none";
|
||||
hoveredDiv.style.borderBottom = "none";
|
||||
|
||||
const rect = hoveredDiv.getBoundingClientRect();
|
||||
const y = (event as any).clientY - rect.top;
|
||||
|
||||
// Determine where the user is hovering
|
||||
if (y >= 0 && y < 7) {
|
||||
// Top region
|
||||
console.log("Top: ");
|
||||
|
||||
hoveredDiv.style.borderTop = "2px solid purple";
|
||||
return "above";
|
||||
} else if (y >= 19 && y < 32) {
|
||||
// Bottom region
|
||||
console.log("Bottom: ");
|
||||
hoveredDiv.style.borderBottom = "2px solid purple";
|
||||
return "below";
|
||||
} else {
|
||||
// Middle region (child)
|
||||
console.log("Middle: ");
|
||||
hoveredDiv.style.outline = "2px solid #b188ff";
|
||||
return "child";
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className="outline-overlay"
|
||||
style={{
|
||||
justifyContent: panelSide === "left" ? "flex-start" : "flex-end",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="outline-card"
|
||||
style={{
|
||||
background: backgroundColor || DEFAULT_PRAMS.backgroundColor,
|
||||
}}
|
||||
>
|
||||
<div className="outline-header">
|
||||
<div className="header-title">
|
||||
<p>Outline</p>
|
||||
</div>
|
||||
<div className="outline-toolbar">
|
||||
<button className="toolbar-button">
|
||||
<AddIcon color={addIconColor || DEFAULT_PRAMS.addIconColor} />
|
||||
</button>
|
||||
<button className="toolbar-button">
|
||||
<CollapseAllIcon />
|
||||
</button>
|
||||
<button className="close-button" onClick={() => setIsOpen(!isOpen)}>
|
||||
<ChevronIcon isOpen={isOpen} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isOpen && (
|
||||
<div className="outline-content">
|
||||
{groupHierarchy.map((item) => (
|
||||
<TreeNode
|
||||
key={item.groupUuid || item.modelUuid}
|
||||
item={item}
|
||||
textColor={textColor}
|
||||
eyeIconColor={eyeIconColor}
|
||||
lockIconColor={lockIconColor}
|
||||
onDragStart={handleDragStart}
|
||||
onDrop={handleDrop}
|
||||
onDragOver={handleDragOver}
|
||||
draggingItem={draggingItem}
|
||||
selectedObject={selectedObject} // pass UUID
|
||||
setSelectedObject={setSelectedObject} // pass setter
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
17
src/components/outlinePanel/OutlinePanel.tsx
Normal file
17
src/components/outlinePanel/OutlinePanel.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import React from "react";
|
||||
import { OutlineList } from "./OutlineList ";
|
||||
|
||||
export interface OutlinePanelProps {
|
||||
textColor?: string;
|
||||
panelSide?: "left" | "right";
|
||||
backgroundColor?: string;
|
||||
addIconColor?: string;
|
||||
eyeIconColor?: string;
|
||||
lockIconColor?: string;
|
||||
}
|
||||
|
||||
const OutlinePanel: React.FC<OutlinePanelProps> = (props) => {
|
||||
return <OutlineList {...props} />;
|
||||
};
|
||||
|
||||
export default OutlinePanel;
|
||||
1742
src/icons/ExportIcons.tsx
Normal file
1742
src/icons/ExportIcons.tsx
Normal file
File diff suppressed because it is too large
Load Diff
16
src/pages/SceneView.tsx
Normal file
16
src/pages/SceneView.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import React from "react";
|
||||
import OutlinePanel from "../components/outlinePanel/OutlinePanel";
|
||||
|
||||
const SceneView = () => {
|
||||
return (
|
||||
<OutlinePanel
|
||||
// panelSide="right"
|
||||
// textColor=""
|
||||
// addIconColor=""
|
||||
// eyeIconColor=""
|
||||
// backgroundColor=""
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default SceneView;
|
||||
5
src/styles/abstracts/_functions.scss
Normal file
5
src/styles/abstracts/_functions.scss
Normal file
@@ -0,0 +1,5 @@
|
||||
// get rem from pixels
|
||||
|
||||
@function get_rem($px) {
|
||||
@return calc($px / 16 * 1rem);
|
||||
}
|
||||
33
src/styles/abstracts/_mixins.scss
Normal file
33
src/styles/abstracts/_mixins.scss
Normal file
@@ -0,0 +1,33 @@
|
||||
@mixin flex-center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@mixin flex-space-between {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
// Array of base colors
|
||||
$colors: (
|
||||
#f5550b,
|
||||
#1bac1b,
|
||||
#0099ff,
|
||||
#d4c927,
|
||||
#8400ff,
|
||||
#13e9b3,
|
||||
#df1dcf
|
||||
);
|
||||
|
||||
@mixin gradient-by-child($index) {
|
||||
// Get the color based on the index passed
|
||||
$base-color: nth($colors, $index);
|
||||
// Apply gradient using the same color with different alpha values
|
||||
background: linear-gradient(
|
||||
144.19deg,
|
||||
rgba($base-color, 0.2) 16.62%, // 20% opacity
|
||||
rgba($base-color, 0.08) 85.81% // 80% opacity
|
||||
);
|
||||
}
|
||||
171
src/styles/abstracts/_variables.scss
Normal file
171
src/styles/abstracts/_variables.scss
Normal file
@@ -0,0 +1,171 @@
|
||||
@use "functions";
|
||||
|
||||
@import url("https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=Josefin+Sans:ital,wght@0,100..700;1,100..700&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Roboto:ital,wght@0,100..900;1,100..900&display=swap");
|
||||
|
||||
// new variables
|
||||
|
||||
// text colors
|
||||
// ---------- light mode ----------
|
||||
$text-color: #2b3344;
|
||||
$text-disabled: #b7b7c6;
|
||||
$input-text-color: #595965;
|
||||
$highlight-text-color: #6f42c1;
|
||||
$text-button-color: #f3f3fd;
|
||||
|
||||
// ---------- dark mode ----------
|
||||
$text-color-dark: #f3f3fd;
|
||||
$text-disabled-dark: #6f6f7a;
|
||||
$input-text-color-dark: #b5b5c8;
|
||||
$highlight-text-color-dark: #d2baff;
|
||||
$text-button-color-dark: #f3f3fd;
|
||||
|
||||
// background colors
|
||||
// ---------- light mode ----------
|
||||
$background-color: linear-gradient(-45deg, #fcfdfd71 0%, #fcfdfd79 100%);
|
||||
$background-color-solid-gradient: linear-gradient(-45deg, #fcfdfd 0%, #fcfdfd 100%);
|
||||
$background-color-solid: #fcfdfd;
|
||||
$background-color-secondary: #fcfdfd4d;
|
||||
$background-color-accent: #6f42c1;
|
||||
$background-color-button: #6f42c1;
|
||||
$background-color-drop-down: #6f42c14d;
|
||||
$background-color-input: #ffffff4d;
|
||||
$background-color-input-focus: #f2f2f7;
|
||||
$background-color-drop-down-gradient: linear-gradient(-45deg, #75649366 0%, #40257266 100%);
|
||||
$background-color-selected: #e0dfff;
|
||||
$background-radial-gray-gradient: radial-gradient(circle, #bfe0f8 0%, #e9ebff 46%, #e2acff 100%);
|
||||
$background-model: #ffffff80;
|
||||
|
||||
// ---------- dark mode ----------
|
||||
$background-color-dark: linear-gradient(-45deg, #333333b3 0%, #2d2437b3 100%);
|
||||
$background-color-solid-gradient-dark: linear-gradient(-45deg, #333333 0%, #2d2437 100%);
|
||||
$background-color-solid-dark: #19191d;
|
||||
$background-color-secondary-dark: #19191d99;
|
||||
$background-color-accent-dark: #6f42c1;
|
||||
$background-color-button-dark: #6f42c1;
|
||||
$background-color-drop-down-dark: #50505080;
|
||||
$background-color-input-dark: #ffffff33;
|
||||
$background-color-input-focus-dark: #333333;
|
||||
$background-color-drop-down-gradient-dark: linear-gradient(-45deg, #8973b166 0%, #53427366 100%);
|
||||
$background-color-selected-dark: #403e66;
|
||||
$background-radial-gray-gradient-dark: radial-gradient(
|
||||
circle,
|
||||
#31373b 0%,
|
||||
#48494b 46%,
|
||||
#52415c 100%
|
||||
);
|
||||
$background-model-dark: #00000080;
|
||||
|
||||
// border colors
|
||||
// ---------- light mode ----------
|
||||
$border-color: #e0dfff;
|
||||
$input-border-color: #d5dddd80;
|
||||
$border-color-accent: #6f42c1;
|
||||
|
||||
// ---------- dark mode ----------
|
||||
$border-color-dark: #564b69;
|
||||
$input-border-color-dark: #d5dddd80;
|
||||
$border-color-accent-dark: #6f42c1;
|
||||
|
||||
// highlight colors
|
||||
// ---------- light mode ----------
|
||||
$highlight-accent-color: #e0dfff;
|
||||
$highlight-secondary-color: #6f42c1;
|
||||
|
||||
// ---------- dark mode ----------
|
||||
$highlight-accent-color-dark: #403e6a;
|
||||
$highlight-secondary-color-dark: #c4abf1;
|
||||
|
||||
// icon colors
|
||||
// ---------- light mode ----------
|
||||
$icon-default-color: #6f42c1;
|
||||
$icon-default-color-hover: #7f4ddb;
|
||||
$icon-default-color-active: #f2f2f7;
|
||||
|
||||
// ---------- dark mode ----------
|
||||
$icon-default-color-dark: #6f42c1;
|
||||
$icon-default-color-hover-dark: #7f4ddb;
|
||||
$icon-default-color-active-dark: #f2f2f7;
|
||||
|
||||
// colors
|
||||
$color1: #a392cd;
|
||||
$color2: #7b4cd3;
|
||||
$color3: #b186ff;
|
||||
$color4: #8752e8;
|
||||
$color5: #c7a8ff;
|
||||
|
||||
// log indication colors
|
||||
// ------------ text -------------
|
||||
$log-default-text-color: #6f42c1;
|
||||
$log-info-text-color: #1773fd;
|
||||
$log-warn-text-color: #f3a50c;
|
||||
$log-error-text-color: #fc230f;
|
||||
$log-success-text-color: #23a84f;
|
||||
// ----------- dark ---------------
|
||||
$log-default-text-color-dark: #b18ef1;
|
||||
$log-info-text-color-dark: #7eb0fa;
|
||||
$log-warn-text-color-dark: #ffaa00;
|
||||
$log-error-text-color-dark: #ff887d;
|
||||
$log-success-text-color-dark: #43ff81;
|
||||
|
||||
// ------------ background -------------
|
||||
$log-default-backgroung-color: #6e42c133;
|
||||
$log-info-background-color: #1773fd5d;
|
||||
$log-warn-background-color: #f3a50c33;
|
||||
$log-error-background-color: #fc230f33;
|
||||
$log-success-background-color: #0ef75b33;
|
||||
|
||||
// old variables
|
||||
$accent-color: #6f42c1;
|
||||
$accent-color-dark: #c4abf1;
|
||||
|
||||
$background-color-gray: #f3f3f3;
|
||||
$background-color-gray-dark: #232323;
|
||||
|
||||
$shadow-color: #3c3c431a;
|
||||
$shadow-color-dark: #8f8f8f1a;
|
||||
|
||||
$acent-gradient-dark: linear-gradient(90deg, #b392f0 0%, #a676ff 100%);
|
||||
$acent-gradient: linear-gradient(90deg, #6f42c1 0%, #925df3 100%);
|
||||
|
||||
$faint-gradient: radial-gradient(circle, #bfe0f8 0%, #e9ebff 46%, #e2acff 100%);
|
||||
$faint-gradient-dark: radial-gradient(circle, #31373b 0%, #48494b 46%, #52415c 100%);
|
||||
|
||||
$font-inter: "Inter", sans-serif;
|
||||
$font-josefin-sans: "Josefin Sans", sans-serif;
|
||||
$font-poppins: "Poppins", sans-serif;
|
||||
$font-roboto: "Roboto", sans-serif;
|
||||
|
||||
$tiny: 0.625rem;
|
||||
$small: 0.75rem;
|
||||
$regular: 0.8rem;
|
||||
$large: 1rem;
|
||||
$xlarge: 1.125rem;
|
||||
$xxlarge: 1.5rem;
|
||||
$xxxlarge: 2rem;
|
||||
|
||||
$thin-weight: 300;
|
||||
$regular-weight: 400;
|
||||
$medium-weight: 500;
|
||||
$bold-weight: 600;
|
||||
|
||||
$z-index-drei-html: 1;
|
||||
$z-index-default: 1;
|
||||
$z-index-marketplace: 2;
|
||||
$z-index-tools: 3;
|
||||
$z-index-negative: -1;
|
||||
$z-index-ui-base: 10;
|
||||
$z-index-ui-overlay: 20;
|
||||
$z-index-ui-popup: 30;
|
||||
$z-index-ui-highest: 50;
|
||||
|
||||
$box-shadow-light: 0px 2px 4px $shadow-color;
|
||||
$box-shadow-medium: 0px 4px 8px $shadow-color;
|
||||
$box-shadow-heavy: 0px 8px 16px $shadow-color;
|
||||
|
||||
$border-radius-small: 4px;
|
||||
$border-radius-medium: 6px;
|
||||
$border-radius-large: 12px;
|
||||
$border-radius-circle: 50%;
|
||||
$border-radius-xlarge: 16px;
|
||||
$border-radius-extra-large: 20px;
|
||||
$border-radius-xxx: 30px;
|
||||
580
src/styles/components/outlinePanel.scss
Normal file
580
src/styles/components/outlinePanel.scss
Normal file
@@ -0,0 +1,580 @@
|
||||
// .outline-overlay {
|
||||
// padding: 0 4px;
|
||||
// font-family: "Segoe UI", sans-serif;
|
||||
// display: flex;
|
||||
// position: absolute;
|
||||
// top: 0;
|
||||
// bottom: 0;
|
||||
// width: 100vw;
|
||||
// pointer-events: none;
|
||||
// .outline-card {
|
||||
// pointer-events: all;
|
||||
// }
|
||||
// }
|
||||
|
||||
// .outline-header {
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
// justify-content: space-between;
|
||||
// padding: 10px 16px;
|
||||
// border-bottom: 1px solid #2e2e3e;
|
||||
|
||||
// .header-title {
|
||||
// p {
|
||||
// margin: 0;
|
||||
// font-weight: 600;
|
||||
// font-size: 14px;
|
||||
// color: #ffffff;
|
||||
// }
|
||||
// }
|
||||
|
||||
// .outline-toolbar {
|
||||
// display: flex;
|
||||
// gap: 8px;
|
||||
|
||||
// .toolbar-button {
|
||||
// background: none;
|
||||
// border: none;
|
||||
// color: #aaa;
|
||||
// cursor: pointer;
|
||||
// width: 24px;
|
||||
// height: 24px;
|
||||
// border-radius: 4px;
|
||||
// transition: background 0.3s;
|
||||
|
||||
// &:hover {
|
||||
// background-color: rgba(255, 255, 255, 0.1);
|
||||
// color: #a855f7;
|
||||
// }
|
||||
|
||||
// svg {
|
||||
// width: 100%;
|
||||
// height: 100%;
|
||||
// }
|
||||
// }
|
||||
|
||||
// .close-button {
|
||||
// background: none;
|
||||
// border: none;
|
||||
// color: #aaa;
|
||||
// cursor: pointer;
|
||||
// width: 24px;
|
||||
// height: 24px;
|
||||
// border-radius: 4px;
|
||||
// transition: transform 0.3s ease;
|
||||
|
||||
// &:hover {
|
||||
// background-color: rgba(255, 255, 255, 0.1);
|
||||
// transform: rotate(-90deg);
|
||||
// color: #a855f7;
|
||||
// }
|
||||
|
||||
// svg {
|
||||
// width: 100%;
|
||||
// height: 100%;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// .outline-content {
|
||||
// max-height: 52vh;
|
||||
// overflow-y: auto;
|
||||
// padding: 8px 0;
|
||||
|
||||
// &::-webkit-scrollbar {
|
||||
// width: 6px;
|
||||
// }
|
||||
|
||||
// &::-webkit-scrollbar-thumb {
|
||||
// background: #a855f7;
|
||||
// border-radius: 10px;
|
||||
// }
|
||||
// }
|
||||
// .tree-node {
|
||||
// display: flex;
|
||||
// flex-direction: column;
|
||||
// width: 100%;
|
||||
// outline: 2px solid transparent;
|
||||
// transition: all 0.3s ease;
|
||||
|
||||
// .tree-node-content {
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
// width: 100%;
|
||||
// padding: 6px 10px;
|
||||
// border-radius: 8px;
|
||||
// background: transparent;
|
||||
// transition: background 0.2s ease, outline 0.2s ease;
|
||||
// box-sizing: border-box;
|
||||
// position: relative;
|
||||
|
||||
// &:hover {
|
||||
// background: rgba(255, 255, 255, 0.05);
|
||||
// }
|
||||
|
||||
// &.selected {
|
||||
// background: var(--background-color-accent, #6f42c1);
|
||||
// }
|
||||
|
||||
// &.multi-selected {
|
||||
// background: rgba(167, 139, 250, 0.2);
|
||||
// border-left: 3px solid var(--highlight-secondary-color, #a855f7);
|
||||
// }
|
||||
|
||||
// .expand-button {
|
||||
// background: none;
|
||||
// border: none;
|
||||
// color: #aaa;
|
||||
// cursor: pointer;
|
||||
// width: 18px;
|
||||
// height: 18px;
|
||||
// flex-shrink: 0;
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
// justify-content: center;
|
||||
|
||||
// &:hover {
|
||||
// color: #a855f7;
|
||||
// }
|
||||
// }
|
||||
|
||||
// .node-wrapper {
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
// flex: 1;
|
||||
// min-width: 0;
|
||||
// gap: 8px;
|
||||
// }
|
||||
|
||||
// .node-icon {
|
||||
// color: #a855f7;
|
||||
// flex-shrink: 0;
|
||||
// width: 16px;
|
||||
// height: 16px;
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
// justify-content: center;
|
||||
// }
|
||||
|
||||
// .rename-input {
|
||||
// flex: 1;
|
||||
// min-width: 0;
|
||||
// overflow: hidden;
|
||||
// white-space: nowrap;
|
||||
// text-overflow: ellipsis;
|
||||
// font-size: 14px;
|
||||
// color: #fff;
|
||||
|
||||
// input.renaming {
|
||||
// width: 100%;
|
||||
// border: none;
|
||||
// outline: none;
|
||||
// border-radius: 6px;
|
||||
// background: rgba(255, 255, 255, 0.1);
|
||||
// color: #fff;
|
||||
// padding: 3px 6px;
|
||||
// font-size: 14px;
|
||||
// box-sizing: border-box;
|
||||
// }
|
||||
// }
|
||||
|
||||
// .node-controls {
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
// gap: 4px;
|
||||
// flex-shrink: 0;
|
||||
|
||||
// .control-button {
|
||||
// background: none;
|
||||
// border: none;
|
||||
// color: #aaa;
|
||||
// cursor: pointer;
|
||||
// border-radius: 4px;
|
||||
// padding: 4px;
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
// justify-content: center;
|
||||
|
||||
// &:hover {
|
||||
// background: rgba(255, 255, 255, 0.1);
|
||||
// color: #a855f7;
|
||||
// }
|
||||
|
||||
// svg {
|
||||
// width: 14px;
|
||||
// height: 14px;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// .tree-children {
|
||||
// padding-left: 16px;
|
||||
// border-left: 1px dashed rgba(255, 255, 255, 0.1);
|
||||
// margin-left: 6px;
|
||||
// }
|
||||
// }
|
||||
|
||||
// // .tree-node {
|
||||
// // display: flex;
|
||||
// // flex-direction: column;
|
||||
// // outline: 2px solid transparent;
|
||||
// // transition: background 0.3s;
|
||||
|
||||
// // .tree-node-content {
|
||||
// // display: flex;
|
||||
// // align-items: center;
|
||||
// // padding: 8px 9px;
|
||||
// // gap: 6px;
|
||||
// // transition: background 0.2s ease;
|
||||
// // position: relative;
|
||||
// // &.selected {
|
||||
// // background: #6f42c1;
|
||||
// // border-radius: 45px;
|
||||
// // }
|
||||
|
||||
// // &:hover {
|
||||
// // outline: 1px solid pink;
|
||||
// // border-radius: 80px;
|
||||
// // }
|
||||
// // .node-wrapper {
|
||||
// // display: flex;
|
||||
// // gap: 40px;
|
||||
// // }
|
||||
|
||||
// // .expand-button {
|
||||
// // background: none;
|
||||
// // border: none;
|
||||
// // cursor: pointer;
|
||||
// // width: 20px;
|
||||
// // height: 20px;
|
||||
// // padding: 0;
|
||||
// // color: #aaa;
|
||||
|
||||
// // &:hover {
|
||||
// // color: #a855f7;
|
||||
// // }
|
||||
// // }
|
||||
|
||||
// // .node-icon {
|
||||
// // color: white;
|
||||
// // width: 18px;
|
||||
// // flex-shrink: 0;
|
||||
// // }
|
||||
|
||||
// // .rename-input {
|
||||
// // background: transparent;
|
||||
// // border: none;
|
||||
// // color: #fff;
|
||||
// // font-size: 14px;
|
||||
// // flex: 1;
|
||||
// // outline: none;
|
||||
// // padding: 2px 4px;
|
||||
// // &:focus {
|
||||
// // border-bottom: 1px solid #a855f7;
|
||||
// // }
|
||||
// // .renaming {
|
||||
// // outline: none;
|
||||
// // border: none;
|
||||
// // border-radius: 15px;
|
||||
// // height: 20px;
|
||||
// // }
|
||||
// // }
|
||||
|
||||
// // .node-controls {
|
||||
// // display: flex;
|
||||
// // gap: 6px;
|
||||
|
||||
// // .control-button {
|
||||
// // background: none;
|
||||
// // border: none;
|
||||
// // color: #888;
|
||||
// // cursor: pointer;
|
||||
// // // padding: 4px;
|
||||
// // border-radius: 4px;
|
||||
|
||||
// // &:hover {
|
||||
// // background-color: rgba(255, 255, 255, 0.1);
|
||||
// // color: #a855f7;
|
||||
// // }
|
||||
|
||||
// // svg {
|
||||
// // width: 16px;
|
||||
// // height: 16px;
|
||||
// // }
|
||||
// // }
|
||||
// // }
|
||||
// // }
|
||||
// // }
|
||||
|
||||
// // .tree-children {
|
||||
// // padding-left: 16px;
|
||||
// // border-left: 1px dashed rgba(255, 255, 255, 0.05);
|
||||
// // }
|
||||
|
||||
// Outline Component Styles
|
||||
// Professional tree/hierarchy view with drag-and-drop support
|
||||
|
||||
.outline-overlay {
|
||||
padding: 0 4px;
|
||||
font-family: "Segoe UI", sans-serif;
|
||||
display: flex;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
pointer-events: none;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.outline-card {
|
||||
pointer-events: all;
|
||||
width: 280px;
|
||||
max-width: 100%;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #2e2e3e;
|
||||
background: linear-gradient(to bottom, #1e1e2f, #12121a);
|
||||
box-shadow: 0 0 8px rgba(168, 85, 247, 0.2);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.outline-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 10px 16px;
|
||||
border-bottom: 1px solid #2e2e3e;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
p {
|
||||
margin: 0;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
.outline-toolbar {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
.toolbar-button {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #aaa;
|
||||
cursor: pointer;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 4px;
|
||||
transition: background 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
color: #a855f7;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.close-button {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #aaa;
|
||||
cursor: pointer;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 4px;
|
||||
transition: transform 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
transform: rotate(-90deg);
|
||||
color: #a855f7;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.outline-content {
|
||||
max-height: 52vh;
|
||||
overflow-y: auto;
|
||||
padding: 8px 0;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #a855f7;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.tree-node {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transition: background 0.3s;
|
||||
|
||||
&.dragging {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.tree-node-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
gap: 8px;
|
||||
transition: background 0.2s ease;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
border-radius: 6px;
|
||||
margin: 2px 8px;
|
||||
|
||||
&.selected {
|
||||
background: #6f42c1;
|
||||
border-radius: 50px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
outline: 2px solid #b188ff;
|
||||
border-radius: 50px;
|
||||
}
|
||||
> div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&.locked {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
transform: scale(0.98);
|
||||
background-color: transparent;
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
&.hidden {
|
||||
opacity: 0.4;
|
||||
}
|
||||
}
|
||||
|
||||
.expand-button {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
padding: 0;
|
||||
color: #aaa;
|
||||
|
||||
&:hover {
|
||||
color: #a855f7;
|
||||
}
|
||||
}
|
||||
|
||||
.node-icon {
|
||||
color: #fff;
|
||||
width: 18px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.rename-input {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
flex: 1;
|
||||
outline: none;
|
||||
padding: 2px 4px;
|
||||
|
||||
&:focus {
|
||||
border-bottom: 1px solid #a855f7;
|
||||
}
|
||||
|
||||
input {
|
||||
background: white;
|
||||
border: none;
|
||||
color: black;
|
||||
font-size: 14px;
|
||||
width: 100%;
|
||||
outline: none;
|
||||
|
||||
&:focus {
|
||||
border-bottom: 1px solid white;
|
||||
border-radius: 30px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.node-controls {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
margin-left: auto;
|
||||
|
||||
.control-button {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #888;
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
color: #a855f7;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tree-children {
|
||||
padding-left: 16px;
|
||||
border-left: 1px dashed rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
// Responsive adjustments
|
||||
@media (max-width: 768px) {
|
||||
.outline-card {
|
||||
width: 240px;
|
||||
}
|
||||
|
||||
.outline-overlay {
|
||||
padding: 0 2px;
|
||||
}
|
||||
|
||||
.rename-input {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
1
src/styles/main.scss
Normal file
1
src/styles/main.scss
Normal file
@@ -0,0 +1 @@
|
||||
@use "components/outlinePanel.scss";
|
||||
Reference in New Issue
Block a user