mirror of
https://github.com/exogen/t2-model-skinner.git
synced 2026-01-19 19:24:44 +00:00
Filters can apply to base or all layers
This commit is contained in:
parent
8cad00552c
commit
0df14f1288
File diff suppressed because one or more lines are too long
2
docs/_next/static/chunks/pages/index-63dd7a6559067c0e.js
Normal file
2
docs/_next/static/chunks/pages/index-63dd7a6559067c0e.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
docs/_next/static/chunks/webpack-0bca67f1077ef5ed.js
Normal file
2
docs/_next/static/chunks/webpack-0bca67f1077ef5ed.js
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
!function(){"use strict";var e,t,n,r,o,u,i,c={},f={};function a(e){var t=f[e];if(void 0!==t)return t.exports;var n=f[e]={exports:{}},r=!0;try{c[e].call(n.exports,n,n.exports,a),r=!1}finally{r&&delete f[e]}return n.exports}a.m=c,e=[],a.O=function(t,n,r,o){if(n){o=o||0;for(var u=e.length;u>0&&e[u-1][2]>o;u--)e[u]=e[u-1];e[u]=[n,r,o];return}for(var i=1/0,u=0;u<e.length;u++){for(var n=e[u][0],r=e[u][1],o=e[u][2],c=!0,f=0;f<n.length;f++)i>=o&&Object.keys(a.O).every(function(e){return a.O[e](n[f])})?n.splice(f--,1):(c=!1,o<i&&(i=o));if(c){e.splice(u--,1);var l=r();void 0!==l&&(t=l)}}return t},a.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(t,{a:t}),t},a.d=function(e,t){for(var n in t)a.o(t,n)&&!a.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},a.f={},a.e=function(e){return Promise.all(Object.keys(a.f).reduce(function(t,n){return a.f[n](e,t),t},[]))},a.u=function(e){return"static/chunks/"+(737===e?"fb7d5399":e)+"."+({70:"0ba1ca12d54bca2d",258:"53d25aa602c4d686",354:"3289d8281650c8de",737:"ddae1e8fed13bcfe",990:"ccb4bc1efe5cd94f"})[e]+".js"},a.miniCssF=function(e){return"static/css/ed4f6c5fadb41eb8.css"},a.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),a.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t={},n="_N_E:",a.l=function(e,r,o,u){if(t[e]){t[e].push(r);return}if(void 0!==o)for(var i,c,f=document.getElementsByTagName("script"),l=0;l<f.length;l++){var s=f[l];if(s.getAttribute("src")==e||s.getAttribute("data-webpack")==n+o){i=s;break}}i||(c=!0,(i=document.createElement("script")).charset="utf-8",i.timeout=120,a.nc&&i.setAttribute("nonce",a.nc),i.setAttribute("data-webpack",n+o),i.src=a.tu(e)),t[e]=[r];var d=function(n,r){i.onerror=i.onload=null,clearTimeout(p);var o=t[e];if(delete t[e],i.parentNode&&i.parentNode.removeChild(i),o&&o.forEach(function(e){return e(r)}),n)return n(r)},p=setTimeout(d.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=d.bind(null,i.onerror),i.onload=d.bind(null,i.onload),c&&document.head.appendChild(i)},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.tt=function(){return void 0===r&&(r={createScriptURL:function(e){return e}},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(r=trustedTypes.createPolicy("nextjs#bundler",r))),r},a.tu=function(e){return a.tt().createScriptURL(e)},a.p="/t2-model-skinner/_next/",o={272:0},a.f.j=function(e,t){var n=a.o(o,e)?o[e]:void 0;if(0!==n){if(n)t.push(n[2]);else if(272!=e){var r=new Promise(function(t,r){n=o[e]=[t,r]});t.push(n[2]=r);var u=a.p+a.u(e),i=Error();a.l(u,function(t){if(a.o(o,e)&&(0!==(n=o[e])&&(o[e]=void 0),n)){var r=t&&("load"===t.type?"missing":t.type),u=t&&t.target&&t.target.src;i.message="Loading chunk "+e+" failed.\n("+r+": "+u+")",i.name="ChunkLoadError",i.type=r,i.request=u,n[1](i)}},"chunk-"+e,e)}else o[e]=0}},a.O.j=function(e){return 0===o[e]},u=function(e,t){var n,r,u=t[0],i=t[1],c=t[2],f=0;if(u.some(function(e){return 0!==o[e]})){for(n in i)a.o(i,n)&&(a.m[n]=i[n]);if(c)var l=c(a)}for(e&&e(t);f<u.length;f++)r=u[f],a.o(o,r)&&o[r]&&o[r][0](),o[r]=0;return a.O(l)},(i=self.webpackChunk_N_E=self.webpackChunk_N_E||[]).forEach(u.bind(null,0)),i.push=u.bind(null,i.push.bind(i))}();
|
||||
//# sourceMappingURL=webpack-0bca67f1077ef5ed.js.map
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -1,2 +0,0 @@
|
|||
!function(){"use strict";var e,t,n,r,o,u,i,c={},a={};function f(e){var t=a[e];if(void 0!==t)return t.exports;var n=a[e]={exports:{}},r=!0;try{c[e].call(n.exports,n,n.exports,f),r=!1}finally{r&&delete a[e]}return n.exports}f.m=c,e=[],f.O=function(t,n,r,o){if(n){o=o||0;for(var u=e.length;u>0&&e[u-1][2]>o;u--)e[u]=e[u-1];e[u]=[n,r,o];return}for(var i=1/0,u=0;u<e.length;u++){for(var n=e[u][0],r=e[u][1],o=e[u][2],c=!0,a=0;a<n.length;a++)i>=o&&Object.keys(f.O).every(function(e){return f.O[e](n[a])})?n.splice(a--,1):(c=!1,o<i&&(i=o));if(c){e.splice(u--,1);var l=r();void 0!==l&&(t=l)}}return t},f.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(t,{a:t}),t},f.d=function(e,t){for(var n in t)f.o(t,n)&&!f.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},f.f={},f.e=function(e){return Promise.all(Object.keys(f.f).reduce(function(t,n){return f.f[n](e,t),t},[]))},f.u=function(e){return"static/chunks/"+(737===e?"fb7d5399":e)+"."+({70:"0ba1ca12d54bca2d",258:"53d25aa602c4d686",354:"3289d8281650c8de",737:"ddae1e8fed13bcfe",990:"ccb4bc1efe5cd94f"})[e]+".js"},f.miniCssF=function(e){return"static/css/7d1c0438425db85d.css"},f.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),f.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t={},n="_N_E:",f.l=function(e,r,o,u){if(t[e]){t[e].push(r);return}if(void 0!==o)for(var i,c,a=document.getElementsByTagName("script"),l=0;l<a.length;l++){var s=a[l];if(s.getAttribute("src")==e||s.getAttribute("data-webpack")==n+o){i=s;break}}i||(c=!0,(i=document.createElement("script")).charset="utf-8",i.timeout=120,f.nc&&i.setAttribute("nonce",f.nc),i.setAttribute("data-webpack",n+o),i.src=f.tu(e)),t[e]=[r];var d=function(n,r){i.onerror=i.onload=null,clearTimeout(p);var o=t[e];if(delete t[e],i.parentNode&&i.parentNode.removeChild(i),o&&o.forEach(function(e){return e(r)}),n)return n(r)},p=setTimeout(d.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=d.bind(null,i.onerror),i.onload=d.bind(null,i.onload),c&&document.head.appendChild(i)},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.tt=function(){return void 0===r&&(r={createScriptURL:function(e){return e}},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(r=trustedTypes.createPolicy("nextjs#bundler",r))),r},f.tu=function(e){return f.tt().createScriptURL(e)},f.p="/t2-model-skinner/_next/",o={272:0},f.f.j=function(e,t){var n=f.o(o,e)?o[e]:void 0;if(0!==n){if(n)t.push(n[2]);else if(272!=e){var r=new Promise(function(t,r){n=o[e]=[t,r]});t.push(n[2]=r);var u=f.p+f.u(e),i=Error();f.l(u,function(t){if(f.o(o,e)&&(0!==(n=o[e])&&(o[e]=void 0),n)){var r=t&&("load"===t.type?"missing":t.type),u=t&&t.target&&t.target.src;i.message="Loading chunk "+e+" failed.\n("+r+": "+u+")",i.name="ChunkLoadError",i.type=r,i.request=u,n[1](i)}},"chunk-"+e,e)}else o[e]=0}},f.O.j=function(e){return 0===o[e]},u=function(e,t){var n,r,u=t[0],i=t[1],c=t[2],a=0;if(u.some(function(e){return 0!==o[e]})){for(n in i)f.o(i,n)&&(f.m[n]=i[n]);if(c)var l=c(f)}for(e&&e(t);a<u.length;a++)r=u[a],f.o(o,r)&&o[r]&&o[r][0](),o[r]=0;return f.O(l)},(i=self.webpackChunk_N_E=self.webpackChunk_N_E||[]).forEach(u.bind(null,0)),i.push=u.bind(null,i.push.bind(i))}();
|
||||
//# sourceMappingURL=webpack-a09c3f76050eda6f.js.map
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
docs/_next/static/css/ed4f6c5fadb41eb8.css
Normal file
2
docs/_next/static/css/ed4f6c5fadb41eb8.css
Normal file
File diff suppressed because one or more lines are too long
1
docs/_next/static/css/ed4f6c5fadb41eb8.css.map
Normal file
1
docs/_next/static/css/ed4f6c5fadb41eb8.css.map
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -1 +1 @@
|
|||
self.__BUILD_MANIFEST={__rewrites:{beforeFiles:[],afterFiles:[],fallback:[]},"/":["static/chunks/78e521c3-312593b4f3190cc4.js","static/chunks/95b64a6e-6f3d919198a9be32.js","static/chunks/31664189-f79df42a6a9e05f8.js","static/chunks/545f34e4-f96cf9e26b6b92a5.js","static/chunks/1bfc9850-6b316c8ef06e5170.js","static/chunks/d7eeaac4-06e64d251e2cbda7.js","static/chunks/f580fadb-a8e2c6896615a304.js","static/chunks/50-cece886aa17c1d5e.js","static/chunks/pages/index-dce4039e544712d9.js"],"/_error":["static/chunks/pages/_error-479484f6c157e921.js"],sortedPages:["/","/_app","/_error"]},self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();
|
||||
self.__BUILD_MANIFEST={__rewrites:{beforeFiles:[],afterFiles:[],fallback:[]},"/":["static/chunks/78e521c3-312593b4f3190cc4.js","static/chunks/95b64a6e-6f3d919198a9be32.js","static/chunks/31664189-f79df42a6a9e05f8.js","static/chunks/545f34e4-f96cf9e26b6b92a5.js","static/chunks/1bfc9850-6b316c8ef06e5170.js","static/chunks/d7eeaac4-06e64d251e2cbda7.js","static/chunks/f580fadb-a8e2c6896615a304.js","static/chunks/50-cece886aa17c1d5e.js","static/chunks/pages/index-63dd7a6559067c0e.js"],"/_error":["static/chunks/pages/_error-479484f6c157e921.js"],sortedPages:["/","/_app","/_error"]},self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -40,11 +40,13 @@ export default function CanvasTools() {
|
|||
setSaturation,
|
||||
brightness,
|
||||
setBrightness,
|
||||
layerMode,
|
||||
setLayerMode,
|
||||
activeCanvasType,
|
||||
addImages,
|
||||
exportSkin,
|
||||
} = useTools();
|
||||
const { isDrawingMode, setDrawingMode } = useCanvas(activeCanvas);
|
||||
const { canvas, isDrawingMode, setDrawingMode } = useCanvas(activeCanvas);
|
||||
const [isMac, setIsMac] = useState(false);
|
||||
const commandKeyPrefix = isMac ? "⌘" : "Ctrl ";
|
||||
const shiftKeySymbol = "⇧";
|
||||
|
|
@ -69,10 +71,6 @@ export default function CanvasTools() {
|
|||
],
|
||||
});
|
||||
|
||||
if (isFilterToolsOpen && !selectedObjects.length) {
|
||||
setFilterToolsOpen(false);
|
||||
}
|
||||
|
||||
const isSelectionLocked = selectedObjects.length
|
||||
? selectedObjects.every((object) => lockedObjects.has(object))
|
||||
: false;
|
||||
|
|
@ -179,7 +177,6 @@ export default function CanvasTools() {
|
|||
type="button"
|
||||
ref={setReferenceElement}
|
||||
data-active={isFilterToolsOpen ? "" : undefined}
|
||||
disabled={!selectedObjects.length}
|
||||
aria-label="Filters"
|
||||
title="Filters"
|
||||
onClick={() => {
|
||||
|
|
@ -207,6 +204,60 @@ export default function CanvasTools() {
|
|||
{...attributes.popper}
|
||||
>
|
||||
<div className="Fields">
|
||||
<div className="Field ApplyTo">
|
||||
<label>Layer:</label>
|
||||
<ul>
|
||||
{selectedObjects.length ? (
|
||||
<li>
|
||||
<input
|
||||
type="radio"
|
||||
name="FilterLayer"
|
||||
value="SelectedLayer"
|
||||
id="FilterLayer-SelectedLayer"
|
||||
checked={layerMode === "SelectedLayer"}
|
||||
onChange={() => {
|
||||
setLayerMode("SelectedLayer");
|
||||
}}
|
||||
/>
|
||||
<label htmlFor="FilterLayer-SelectedLayer">
|
||||
selected ({selectedObjects.length.toLocaleString()})
|
||||
</label>
|
||||
</li>
|
||||
) : (
|
||||
<>
|
||||
<li>
|
||||
<input
|
||||
type="radio"
|
||||
name="FilterLayer"
|
||||
value="BaseLayer"
|
||||
id="FilterLayer-BaseLayer"
|
||||
checked={layerMode === "BaseLayer"}
|
||||
onChange={() => {
|
||||
setLayerMode("BaseLayer");
|
||||
}}
|
||||
/>{" "}
|
||||
<label htmlFor="FilterLayer-BaseLayer">base</label>
|
||||
</li>
|
||||
<li>
|
||||
<input
|
||||
type="radio"
|
||||
name="FilterLayer"
|
||||
value="AllLayers"
|
||||
id="FilterLayer-AllLayers"
|
||||
checked={layerMode === "AllLayers"}
|
||||
onChange={() => {
|
||||
setLayerMode("AllLayers");
|
||||
}}
|
||||
/>
|
||||
<label htmlFor="FilterLayer-AllLayers">
|
||||
all (
|
||||
{canvas?._objects.length.toLocaleString() ?? 0})
|
||||
</label>
|
||||
</li>
|
||||
</>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="Field">
|
||||
<label>
|
||||
Hue:{" "}
|
||||
|
|
|
|||
|
|
@ -90,16 +90,33 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
|
|||
const [filterChanges, setFilterChanges] = useState<
|
||||
Array<[fabric.Object, ObjectFilters]>
|
||||
>(() => []);
|
||||
const [layerMode, setLayerMode] = useState("BaseLayer");
|
||||
|
||||
if (selectedObjects.length) {
|
||||
if (layerMode !== "SelectedLayer") {
|
||||
setLayerMode("SelectedLayer");
|
||||
}
|
||||
} else {
|
||||
if (layerMode === "SelectedLayer") {
|
||||
setLayerMode("BaseLayer");
|
||||
}
|
||||
}
|
||||
|
||||
const getFilter = (name: keyof ObjectFilters) => {
|
||||
if (selectedObjects.length) {
|
||||
let applyObjects = selectedObjects;
|
||||
if (layerMode === "AllLayers") {
|
||||
applyObjects = canvas?._objects ?? [];
|
||||
} else if (layerMode === "BaseLayer") {
|
||||
applyObjects = canvas?._objects.slice(0, 1) ?? [];
|
||||
}
|
||||
if (applyObjects.length) {
|
||||
const getValue = (i: number) =>
|
||||
(filterMap.get(selectedObjects[i]) ?? {})[name] ?? 0;
|
||||
(filterMap.get(applyObjects[i]) ?? {})[name] ?? 0;
|
||||
const firstValue = getValue(0);
|
||||
if (
|
||||
selectedObjects
|
||||
applyObjects
|
||||
.slice(1)
|
||||
.every((selectedObject, i) => getValue(i + 1) === firstValue)
|
||||
.every((applyObject, i) => getValue(i + 1) === firstValue)
|
||||
) {
|
||||
return firstValue;
|
||||
}
|
||||
|
|
@ -115,22 +132,24 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
|
|||
|
||||
const setFilter = useCallback(
|
||||
(name: keyof ObjectFilters, value: number) => {
|
||||
if (!selectedObjects.length) {
|
||||
setFilterChanges([]);
|
||||
return;
|
||||
}
|
||||
const filterChanges: Array<[fabric.Object, ObjectFilters]> = [];
|
||||
const newFilterMap = new Map(filterMap);
|
||||
for (const selectedObject of selectedObjects) {
|
||||
const existingFilters = filterMap.get(selectedObject) ?? {};
|
||||
let applyObjects = selectedObjects;
|
||||
if (layerMode === "AllLayers") {
|
||||
applyObjects = canvas?._objects ?? [];
|
||||
} else if (layerMode === "BaseLayer") {
|
||||
applyObjects = canvas?._objects.slice(0, 1) ?? [];
|
||||
}
|
||||
for (const applyObject of applyObjects) {
|
||||
const existingFilters = filterMap.get(applyObject) ?? {};
|
||||
const newFilters = { ...existingFilters, [name]: value };
|
||||
newFilterMap.set(selectedObject, newFilters);
|
||||
filterChanges.push([selectedObject, newFilters]);
|
||||
newFilterMap.set(applyObject, newFilters);
|
||||
filterChanges.push([applyObject, newFilters]);
|
||||
}
|
||||
setFilterMap(newFilterMap);
|
||||
setFilterChanges(filterChanges);
|
||||
},
|
||||
[filterMap, selectedObjects]
|
||||
[canvas, layerMode, filterMap, selectedObjects]
|
||||
);
|
||||
|
||||
const setHueRotate = useCallback(
|
||||
|
|
@ -434,6 +453,8 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
|
|||
setSaturation,
|
||||
brightness,
|
||||
setBrightness,
|
||||
layerMode,
|
||||
setLayerMode,
|
||||
selectedObjects,
|
||||
lockSelection,
|
||||
unlockSelection,
|
||||
|
|
@ -464,6 +485,7 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
|
|||
hueRotate,
|
||||
saturation,
|
||||
brightness,
|
||||
layerMode,
|
||||
setHueRotate,
|
||||
setSaturation,
|
||||
setBrightness,
|
||||
|
|
|
|||
|
|
@ -385,3 +385,41 @@ select {
|
|||
transform: translate3d(0, -50%, 0);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
h6 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-weight: bold;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.Field.ApplyTo {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-self: flex-start;
|
||||
align-items: center;
|
||||
padding-top: 6px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.Field.ApplyTo input[type="radio"] {
|
||||
margin: 2px 3px;
|
||||
}
|
||||
|
||||
.Field.ApplyTo ul {
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.Field.ApplyTo li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ interface ToolsContextValue {
|
|||
setSaturation: (saturation: number) => void;
|
||||
brightness: number | null;
|
||||
setBrightness: (brightness: number) => void;
|
||||
layerMode: string;
|
||||
setLayerMode: (layerMode: string) => void;
|
||||
deleteSelection: () => void;
|
||||
undo: () => void;
|
||||
redo: () => void;
|
||||
|
|
|
|||
Loading…
Reference in a new issue