mirror of
https://github.com/exogen/vl2-forge.git
synced 2026-01-19 19:44:46 +00:00
Add action log viewer
This commit is contained in:
parent
e38b3678cb
commit
175534b788
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
docs/_next/static/chunks/94730671-6ced0342e6a25b8f.js
Normal file
1
docs/_next/static/chunks/94730671-6ced0342e6a25b8f.js
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[522],{3051:(t,L,r)=>{r.d(L,{qGf:()=>e});var a=r(1810);function e(t){return(0,a.w_)({tag:"svg",attr:{viewBox:"0 0 24 24",fill:"currentColor"},child:[{tag:"path",attr:{d:"M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 10.5858L9.17157 7.75736L7.75736 9.17157L10.5858 12L7.75736 14.8284L9.17157 16.2426L12 13.4142L14.8284 16.2426L16.2426 14.8284L13.4142 12L16.2426 9.17157L14.8284 7.75736L12 10.5858Z"},child:[]}]})(t)}}}]);
|
||||||
File diff suppressed because one or more lines are too long
1
docs/_next/static/chunks/app/page-2dac80ee609f3188.js
Normal file
1
docs/_next/static/chunks/app/page-2dac80ee609f3188.js
Normal file
File diff suppressed because one or more lines are too long
1
docs/_next/static/chunks/f8025e75-eec57ce6fbd95417.js
Normal file
1
docs/_next/static/chunks/f8025e75-eec57ce6fbd95417.js
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[950],{2655:(l,a,t)=>{t.d(a,{m2k:()=>c});var r=t(1810);function c(l){return(0,r.w_)({tag:"svg",attr:{viewBox:"0 0 24 24",fill:"currentColor"},child:[{tag:"path",attr:{d:"M12 1.67c.955 0 1.845 .467 2.39 1.247l.105 .16l8.114 13.548a2.914 2.914 0 0 1 -2.307 4.363l-.195 .008h-16.225a2.914 2.914 0 0 1 -2.582 -4.2l.099 -.185l8.11 -13.538a2.914 2.914 0 0 1 2.491 -1.403zm.01 13.33l-.127 .007a1 1 0 0 0 0 1.986l.117 .007l.127 -.007a1 1 0 0 0 0 -1.986l-.117 -.007zm-.01 -7a1 1 0 0 0 -.993 .883l-.007 .117v4l.007 .117a1 1 0 0 0 1.986 0l.007 -.117v-4l-.007 -.117a1 1 0 0 0 -.993 -.883z"},child:[]}]})(l)}}}]);
|
||||||
|
|
@ -1 +1 @@
|
||||||
(()=>{"use strict";var e={},t={};function r(o){var n=t[o];if(void 0!==n)return n.exports;var a=t[o]={id:o,loaded:!1,exports:{}},i=!0;try{e[o].call(a.exports,a,a.exports,r),i=!1}finally{i&&delete t[o]}return a.loaded=!0,a.exports}r.m=e,(()=>{var e=[];r.O=(t,o,n,a)=>{if(o){a=a||0;for(var i=e.length;i>0&&e[i-1][2]>a;i--)e[i]=e[i-1];e[i]=[o,n,a];return}for(var l=1/0,i=0;i<e.length;i++){for(var[o,n,a]=e[i],u=!0,d=0;d<o.length;d++)(!1&a||l>=a)&&Object.keys(r.O).every(e=>r.O[e](o[d]))?o.splice(d--,1):(u=!1,a<l&&(l=a));if(u){e.splice(i--,1);var c=n();void 0!==c&&(t=c)}}return t}})(),r.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return r.d(t,{a:t}),t},(()=>{var e,t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__;r.t=function(o,n){if(1&n&&(o=this(o)),8&n||"object"==typeof o&&o&&(4&n&&o.__esModule||16&n&&"function"==typeof o.then))return o;var a=Object.create(null);r.r(a);var i={};e=e||[null,t({}),t([]),t(t)];for(var l=2&n&&o;"object"==typeof l&&!~e.indexOf(l);l=t(l))Object.getOwnPropertyNames(l).forEach(e=>i[e]=()=>o[e]);return i.default=()=>o,r.d(a,i),a}})(),r.d=(e,t)=>{for(var o in t)r.o(t,o)&&!r.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((t,o)=>(r.f[o](e,t),t),[])),r.u=e=>{},r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={},t="_N_E:";r.l=(o,n,a,i)=>{if(e[o]){e[o].push(n);return}if(void 0!==a)for(var l,u,d=document.getElementsByTagName("script"),c=0;c<d.length;c++){var s=d[c];if(s.getAttribute("src")==o||s.getAttribute("data-webpack")==t+a){l=s;break}}l||(u=!0,(l=document.createElement("script")).charset="utf-8",l.timeout=120,r.nc&&l.setAttribute("nonce",r.nc),l.setAttribute("data-webpack",t+a),l.src=r.tu(o)),e[o]=[n];var f=(t,r)=>{l.onerror=l.onload=null,clearTimeout(p);var n=e[o];if(delete e[o],l.parentNode&&l.parentNode.removeChild(l),n&&n.forEach(e=>e(r)),t)return t(r)},p=setTimeout(f.bind(null,void 0,{type:"timeout",target:l}),12e4);l.onerror=f.bind(null,l.onerror),l.onload=f.bind(null,l.onload),u&&document.head.appendChild(l)}})(),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),(()=>{var e;r.tt=()=>(void 0===e&&(e={createScriptURL:e=>e},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("nextjs#bundler",e))),e)})(),r.tu=e=>r.tt().createScriptURL(e),r.p="/vl2-forge/_next/",(()=>{var e={272:0,465:0,113:0};r.f.j=(t,o)=>{var n=r.o(e,t)?e[t]:void 0;if(0!==n){if(n)o.push(n[2]);else if(/^(113|272|465)$/.test(t))e[t]=0;else{var a=new Promise((r,o)=>n=e[t]=[r,o]);o.push(n[2]=a);var i=r.p+r.u(t),l=Error();r.l(i,o=>{if(r.o(e,t)&&(0!==(n=e[t])&&(e[t]=void 0),n)){var a=o&&("load"===o.type?"missing":o.type),i=o&&o.target&&o.target.src;l.message="Loading chunk "+t+" failed.\n("+a+": "+i+")",l.name="ChunkLoadError",l.type=a,l.request=i,n[1](l)}},"chunk-"+t,t)}}},r.O.j=t=>0===e[t];var t=(t,o)=>{var n,a,[i,l,u]=o,d=0;if(i.some(t=>0!==e[t])){for(n in l)r.o(l,n)&&(r.m[n]=l[n]);if(u)var c=u(r)}for(t&&t(o);d<i.length;d++)a=i[d],r.o(e,a)&&e[a]&&e[a][0](),e[a]=0;return r.O(c)},o=self.webpackChunk_N_E=self.webpackChunk_N_E||[];o.forEach(t.bind(null,0)),o.push=t.bind(null,o.push.bind(o))})()})();
|
(()=>{"use strict";var e={},t={};function r(o){var n=t[o];if(void 0!==n)return n.exports;var a=t[o]={id:o,loaded:!1,exports:{}},i=!0;try{e[o].call(a.exports,a,a.exports,r),i=!1}finally{i&&delete t[o]}return a.loaded=!0,a.exports}r.m=e,(()=>{var e=[];r.O=(t,o,n,a)=>{if(o){a=a||0;for(var i=e.length;i>0&&e[i-1][2]>a;i--)e[i]=e[i-1];e[i]=[o,n,a];return}for(var l=1/0,i=0;i<e.length;i++){for(var[o,n,a]=e[i],u=!0,d=0;d<o.length;d++)(!1&a||l>=a)&&Object.keys(r.O).every(e=>r.O[e](o[d]))?o.splice(d--,1):(u=!1,a<l&&(l=a));if(u){e.splice(i--,1);var c=n();void 0!==c&&(t=c)}}return t}})(),r.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return r.d(t,{a:t}),t},(()=>{var e,t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__;r.t=function(o,n){if(1&n&&(o=this(o)),8&n||"object"==typeof o&&o&&(4&n&&o.__esModule||16&n&&"function"==typeof o.then))return o;var a=Object.create(null);r.r(a);var i={};e=e||[null,t({}),t([]),t(t)];for(var l=2&n&&o;"object"==typeof l&&!~e.indexOf(l);l=t(l))Object.getOwnPropertyNames(l).forEach(e=>i[e]=()=>o[e]);return i.default=()=>o,r.d(a,i),a}})(),r.d=(e,t)=>{for(var o in t)r.o(t,o)&&!r.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((t,o)=>(r.f[o](e,t),t),[])),r.u=e=>{},r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={},t="_N_E:";r.l=(o,n,a,i)=>{if(e[o]){e[o].push(n);return}if(void 0!==a)for(var l,u,d=document.getElementsByTagName("script"),c=0;c<d.length;c++){var s=d[c];if(s.getAttribute("src")==o||s.getAttribute("data-webpack")==t+a){l=s;break}}l||(u=!0,(l=document.createElement("script")).charset="utf-8",l.timeout=120,r.nc&&l.setAttribute("nonce",r.nc),l.setAttribute("data-webpack",t+a),l.src=r.tu(o)),e[o]=[n];var f=(t,r)=>{l.onerror=l.onload=null,clearTimeout(p);var n=e[o];if(delete e[o],l.parentNode&&l.parentNode.removeChild(l),n&&n.forEach(e=>e(r)),t)return t(r)},p=setTimeout(f.bind(null,void 0,{type:"timeout",target:l}),12e4);l.onerror=f.bind(null,l.onerror),l.onload=f.bind(null,l.onload),u&&document.head.appendChild(l)}})(),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),(()=>{var e;r.tt=()=>(void 0===e&&(e={createScriptURL:e=>e},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("nextjs#bundler",e))),e)})(),r.tu=e=>r.tt().createScriptURL(e),r.p="/vl2-forge/_next/",(()=>{var e={272:0,465:0,995:0};r.f.j=(t,o)=>{var n=r.o(e,t)?e[t]:void 0;if(0!==n){if(n)o.push(n[2]);else if(/^(272|465|995)$/.test(t))e[t]=0;else{var a=new Promise((r,o)=>n=e[t]=[r,o]);o.push(n[2]=a);var i=r.p+r.u(t),l=Error();r.l(i,o=>{if(r.o(e,t)&&(0!==(n=e[t])&&(e[t]=void 0),n)){var a=o&&("load"===o.type?"missing":o.type),i=o&&o.target&&o.target.src;l.message="Loading chunk "+t+" failed.\n("+a+": "+i+")",l.name="ChunkLoadError",l.type=a,l.request=i,n[1](l)}},"chunk-"+t,t)}}},r.O.j=t=>0===e[t];var t=(t,o)=>{var n,a,[i,l,u]=o,d=0;if(i.some(t=>0!==e[t])){for(n in l)r.o(l,n)&&(r.m[n]=l[n]);if(u)var c=u(r)}for(t&&t(o);d<i.length;d++)a=i[d],r.o(e,a)&&e[a]&&e[a][0](),e[a]=0;return r.O(c)},o=self.webpackChunk_N_E=self.webpackChunk_N_E||[];o.forEach(t.bind(null,0)),o.push=t.bind(null,o.push.bind(o))})()})();
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1,7 +1,7 @@
|
||||||
7:"$Sreact.fragment"
|
7:"$Sreact.fragment"
|
||||||
8:I[9275,[],""]
|
8:I[9275,[],""]
|
||||||
9:I[1343,[],""]
|
9:I[1343,[],""]
|
||||||
a:I[7341,["665","static/chunks/f97e080b-d92374f1605c166e.js","51","static/chunks/795d4814-df14aa386162ffad.js","212","static/chunks/59650de3-3851382c06f0a1a6.js","516","static/chunks/f7333993-0b21ce6d3b378608.js","675","static/chunks/b563f954-1a29a90b42165810.js","240","static/chunks/53c13509-7351503a4af8a85a.js","699","static/chunks/8e1d74a4-900578ac2c71efa7.js","515","static/chunks/515-35a068dc133b7a18.js","931","static/chunks/app/page-198e743de2f7340f.js"],"Forge",1]
|
a:I[4538,["950","static/chunks/f8025e75-eec57ce6fbd95417.js","522","static/chunks/94730671-6ced0342e6a25b8f.js","665","static/chunks/f97e080b-d92374f1605c166e.js","51","static/chunks/795d4814-df14aa386162ffad.js","212","static/chunks/59650de3-3851382c06f0a1a6.js","516","static/chunks/f7333993-0b21ce6d3b378608.js","675","static/chunks/b563f954-1a29a90b42165810.js","240","static/chunks/53c13509-7351503a4af8a85a.js","699","static/chunks/8e1d74a4-900578ac2c71efa7.js","515","static/chunks/515-a62e2db5bca20cf3.js","931","static/chunks/app/page-2dac80ee609f3188.js"],"Forge",1]
|
||||||
b:I[3120,[],"OutletBoundary"]
|
b:I[3120,[],"OutletBoundary"]
|
||||||
d:I[3120,[],"MetadataBoundary"]
|
d:I[3120,[],"MetadataBoundary"]
|
||||||
f:I[3120,[],"ViewportBoundary"]
|
f:I[3120,[],"ViewportBoundary"]
|
||||||
|
|
@ -11,8 +11,8 @@ f:I[3120,[],"ViewportBoundary"]
|
||||||
3:HL["/vl2-forge/_next/static/media/a521fcc400cf9065-s.p.ttf","font",{"crossOrigin":"","type":"font/ttf"}]
|
3:HL["/vl2-forge/_next/static/media/a521fcc400cf9065-s.p.ttf","font",{"crossOrigin":"","type":"font/ttf"}]
|
||||||
4:HL["/vl2-forge/_next/static/media/e9ed9197b1d41e00-s.p.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
|
4:HL["/vl2-forge/_next/static/media/e9ed9197b1d41e00-s.p.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
|
||||||
5:HL["/vl2-forge/_next/static/css/bdff6c7d2b4adc3b.css","style"]
|
5:HL["/vl2-forge/_next/static/css/bdff6c7d2b4adc3b.css","style"]
|
||||||
6:HL["/vl2-forge/_next/static/css/d8287fbacbbad8f6.css","style"]
|
6:HL["/vl2-forge/_next/static/css/8f45e42583e71b0d.css","style"]
|
||||||
0:{"P":null,"b":"9Pi0et4BW69YTW10MWfB6","p":"/vl2-forge","c":["",""],"i":false,"f":[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",["$","$7","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/vl2-forge/_next/static/css/bdff6c7d2b4adc3b.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","className":"__variable_6dd175 __variable_60c549 __variable_b97ccf","children":["$","body",null,{"children":["$","$L8",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L9",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]]}],{"children":["__PAGE__",["$","$7","c",{"children":[["$","$La",null,{}],[["$","link","0",{"rel":"stylesheet","href":"/vl2-forge/_next/static/css/d8287fbacbbad8f6.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","$Lb",null,{"children":"$Lc"}]]}],{},null]},null],["$","$7","h",{"children":[null,["$","$7","Bbs2r012w6VYSLPXygGDr",{"children":[["$","$Ld",null,{"children":"$Le"}],["$","$Lf",null,{"children":"$L10"}],["$","meta",null,{"name":"next-size-adjust"}]]}]]}]]],"m":"$undefined","G":"$11","s":false,"S":true}
|
0:{"P":null,"b":"doB4mbbCjK_svkG4sfPx3","p":"/vl2-forge","c":["",""],"i":false,"f":[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",["$","$7","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/vl2-forge/_next/static/css/bdff6c7d2b4adc3b.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","className":"__variable_6dd175 __variable_60c549 __variable_b97ccf","children":["$","body",null,{"children":["$","$L8",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L9",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]]}],{"children":["__PAGE__",["$","$7","c",{"children":[["$","$La",null,{}],[["$","link","0",{"rel":"stylesheet","href":"/vl2-forge/_next/static/css/8f45e42583e71b0d.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","$Lb",null,{"children":"$Lc"}]]}],{},null]},null],["$","$7","h",{"children":[null,["$","$7","zy8WzxHRJrJcftPOY8oU_",{"children":[["$","$Ld",null,{"children":"$Le"}],["$","$Lf",null,{"children":"$L10"}],["$","meta",null,{"name":"next-size-adjust"}]]}]]}]]],"m":"$undefined","G":"$11","s":false,"S":true}
|
||||||
10:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
|
10:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
|
||||||
e:[["$","meta","0",{"charSet":"utf-8"}],["$","title","1",{"children":"VL2 Forge"}],["$","meta","2",{"name":"description","content":"Create .vl2 files for Tribes 2"}]]
|
e:[["$","meta","0",{"charSet":"utf-8"}],["$","title","1",{"children":"VL2 Forge"}],["$","meta","2",{"name":"description","content":"Create .vl2 files for Tribes 2"}]]
|
||||||
c:null
|
c:null
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
"use client";
|
"use client";
|
||||||
import { useCallback, useMemo, useState, useTransition } from "react";
|
import {
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useState,
|
||||||
|
useTransition,
|
||||||
|
} from "react";
|
||||||
import { useDropzone } from "react-dropzone";
|
import { useDropzone } from "react-dropzone";
|
||||||
import orderBy from "lodash.orderby";
|
import orderBy from "lodash.orderby";
|
||||||
import { FaGithub } from "react-icons/fa";
|
import { FaGithub } from "react-icons/fa";
|
||||||
|
|
@ -8,39 +14,67 @@ import { FileItem } from "./FileItem";
|
||||||
import { DownloadForm } from "./DownloadForm";
|
import { DownloadForm } from "./DownloadForm";
|
||||||
import { handleInputFile } from "./utils";
|
import { handleInputFile } from "./utils";
|
||||||
import styles from "./Forge.module.css";
|
import styles from "./Forge.module.css";
|
||||||
|
import { Messages } from "./Messages";
|
||||||
|
|
||||||
|
const defaultFileData = {
|
||||||
|
files: new Map(),
|
||||||
|
actionLog: [],
|
||||||
|
};
|
||||||
|
|
||||||
export function Forge() {
|
export function Forge() {
|
||||||
const [isPending, startTransition] = useTransition();
|
const [isPending, startTransition] = useTransition();
|
||||||
const [loadingCount, setLoadingCount] = useState(0);
|
const [loadingCount, setLoadingCount] = useState(0);
|
||||||
const [actionLog, setActionLog] = useState(() => []);
|
const [fileData, setFileData] = useState(defaultFileData);
|
||||||
const [files, setFiles] = useState(() => new Map());
|
|
||||||
|
const { files, actionLog } = fileData;
|
||||||
|
|
||||||
const onDrop = useCallback(async (acceptedFiles) => {
|
const onDrop = useCallback(async (acceptedFiles) => {
|
||||||
setLoadingCount((count) => count + 1);
|
setLoadingCount((count) => count + 1);
|
||||||
const actionLog = [];
|
const actionLog = [];
|
||||||
const finalMap = new Map();
|
const finalMap = new Map();
|
||||||
|
const orderedAcceptedFiles = orderBy(
|
||||||
|
Array.from(acceptedFiles),
|
||||||
|
[(file) => (file.name ?? "").toLowerCase()],
|
||||||
|
["asc"]
|
||||||
|
);
|
||||||
const allFiles: Array<Map<string, any>> = await Promise.all(
|
const allFiles: Array<Map<string, any>> = await Promise.all(
|
||||||
acceptedFiles.map((file) => handleInputFile(file))
|
orderedAcceptedFiles.map((file) => handleInputFile(file))
|
||||||
);
|
);
|
||||||
allFiles.forEach((map) => {
|
allFiles.forEach((map) => {
|
||||||
map.forEach((file, path) => {
|
map.forEach((file, path) => {
|
||||||
if (finalMap.has(path)) {
|
if (finalMap.has(path)) {
|
||||||
actionLog.push({
|
actionLog.push({
|
||||||
type: "overwrite",
|
type: "BATCH_OVERWRITE",
|
||||||
path,
|
path,
|
||||||
|
oldSource: finalMap.get(path).source,
|
||||||
|
newSource: file.source,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
finalMap.set(path, file);
|
finalMap.set(path, file);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
startTransition(() => {
|
setFileData((prevData) => {
|
||||||
setFiles((prevMap) => {
|
const { files: prevFiles, actionLog: prevActionLog } = prevData;
|
||||||
return new Map([
|
const newActionLog = [...prevActionLog, ...actionLog];
|
||||||
...Array.from(prevMap.entries()),
|
const newFiles = new Map(prevFiles);
|
||||||
...Array.from(finalMap.entries()),
|
finalMap.forEach((file, path) => {
|
||||||
]);
|
if (newFiles.has(path)) {
|
||||||
|
newActionLog.push({
|
||||||
|
type: "NEW_OVERWRITE",
|
||||||
|
path,
|
||||||
|
oldSource: newFiles.get(path).source,
|
||||||
|
newSource: file.source,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
newFiles.set(path, file);
|
||||||
});
|
});
|
||||||
setActionLog((prevLog) => [...prevLog, ...actionLog]);
|
return {
|
||||||
|
files: newFiles,
|
||||||
|
actionLog:
|
||||||
|
newActionLog.length === prevActionLog.length
|
||||||
|
? prevActionLog
|
||||||
|
: newActionLog,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
setLoadingCount((count) => count - 1);
|
setLoadingCount((count) => count - 1);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
@ -73,21 +107,27 @@ export function Forge() {
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleDelete = useCallback((path) => {
|
const handleDelete = useCallback((path) => {
|
||||||
setFiles((files) => {
|
setFileData((prevFileData) => {
|
||||||
const newFiles = new Map(files);
|
const newFiles = new Map(prevFileData.files);
|
||||||
newFiles.delete(path);
|
newFiles.delete(path);
|
||||||
return newFiles;
|
return {
|
||||||
|
files: newFiles,
|
||||||
|
actionLog: prevFileData.actionLog,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleRename = useCallback((oldPath, newPath) => {
|
const handleRename = useCallback((oldPath, newPath) => {
|
||||||
setFiles((files) => {
|
setFileData((prevFileData) => {
|
||||||
const file = files.get(oldPath);
|
const file = prevFileData.files.get(oldPath);
|
||||||
const newFile = { ...file, path: newPath };
|
const newFile = { ...file, path: newPath };
|
||||||
const newFiles = new Map(files);
|
const newFiles = new Map(prevFileData.files);
|
||||||
newFiles.delete(oldPath);
|
newFiles.delete(oldPath);
|
||||||
newFiles.set(newPath, newFile);
|
newFiles.set(newPath, newFile);
|
||||||
return newFiles;
|
return {
|
||||||
|
files: newFiles,
|
||||||
|
actionLog: prevFileData.actionLog,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
@ -144,6 +184,7 @@ export function Forge() {
|
||||||
<FaGithub aria-label="GitHub" />
|
<FaGithub aria-label="GitHub" />
|
||||||
</a>
|
</a>
|
||||||
<DownloadForm fileList={fileList} />
|
<DownloadForm fileList={fileList} />
|
||||||
|
<Messages actionLog={actionLog} />
|
||||||
</footer>
|
</footer>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
69
src/Messages.module.css
Normal file
69
src/Messages.module.css
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
.MessagesButton,
|
||||||
|
.CloseButton {
|
||||||
|
background: transparent;
|
||||||
|
border: 0;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: grid;
|
||||||
|
place-content: center;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
font-size: 32px;
|
||||||
|
color: rgba(255, 255, 255, 0.3);
|
||||||
|
transition: color 200ms;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MessagesButton.NewMessages {
|
||||||
|
color: rgba(255, 162, 43, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.MessagesButton svg {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CloseButton {
|
||||||
|
position: absolute;
|
||||||
|
top: 12px;
|
||||||
|
right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CloseButton:hover {
|
||||||
|
color: rgba(255, 255, 255, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ActionLog {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
background: rgba(0, 0, 0, 0.9);
|
||||||
|
color: rgba(255, 162, 43, 1);
|
||||||
|
padding: 32px;
|
||||||
|
overflow: auto;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ActionLog del {
|
||||||
|
font-style: normal;
|
||||||
|
text-decoration: none;
|
||||||
|
border-bottom: 2px solid red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ActionLog ins {
|
||||||
|
font-style: normal;
|
||||||
|
text-decoration: none;
|
||||||
|
border-bottom: 2px solid green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Path {
|
||||||
|
color: rgb(255, 237, 212);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.MessagesButton {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
72
src/Messages.tsx
Normal file
72
src/Messages.tsx
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { TbAlertTriangleFilled } from "react-icons/tb";
|
||||||
|
import { RiCloseCircleFill } from "react-icons/ri";
|
||||||
|
import styles from "./Messages.module.css";
|
||||||
|
|
||||||
|
export function Messages({ actionLog }) {
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const [hasNewMessages, setHasNewMessages] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isOpen) {
|
||||||
|
setHasNewMessages(false);
|
||||||
|
}
|
||||||
|
}, [isOpen]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (actionLog.length > 0) {
|
||||||
|
setHasNewMessages(true);
|
||||||
|
}
|
||||||
|
}, [actionLog]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`${styles.MessagesButton} ${
|
||||||
|
hasNewMessages ? styles.NewMessages : ""
|
||||||
|
}`}
|
||||||
|
onClick={() => {
|
||||||
|
setIsOpen((isOpen) => !isOpen);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TbAlertTriangleFilled />
|
||||||
|
</button>
|
||||||
|
<div className={styles.ActionLog} hidden={!isOpen}>
|
||||||
|
<button
|
||||||
|
className={styles.CloseButton}
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
setIsOpen(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<RiCloseCircleFill />
|
||||||
|
</button>
|
||||||
|
{actionLog.map((message, i) => {
|
||||||
|
switch (message.type) {
|
||||||
|
case "BATCH_OVERWRITE":
|
||||||
|
return (
|
||||||
|
<p key={i}>
|
||||||
|
File at <span className={styles.Path}>{message.path}</span>{" "}
|
||||||
|
from <del>{message.oldSource}</del> was replaced with the one
|
||||||
|
from <ins>{message.newSource}</ins> because of the priority in
|
||||||
|
which it was handled.
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
case "NEW_OVERWRITE":
|
||||||
|
return (
|
||||||
|
<p key={i}>
|
||||||
|
File at <span className={styles.Path}>{message.path}</span>{" "}
|
||||||
|
from <del>{message.oldSource}</del> was replaced with the one
|
||||||
|
from <ins>{message.newSource}</ins> because it is a newer
|
||||||
|
upload.
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,7 @@ export type FileType = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type FileEntry = {
|
export type FileEntry = {
|
||||||
|
source: string | null;
|
||||||
path: string;
|
path: string;
|
||||||
buffer: ArrayBuffer;
|
buffer: ArrayBuffer;
|
||||||
blobUri: string | null;
|
blobUri: string | null;
|
||||||
|
|
@ -145,6 +146,7 @@ export async function handleZipFile(file) {
|
||||||
path = detectBestPath(path);
|
path = detectBestPath(path);
|
||||||
const buffer = await fileObj.async("arraybuffer");
|
const buffer = await fileObj.async("arraybuffer");
|
||||||
const fileEntry = {
|
const fileEntry = {
|
||||||
|
source: file.name || null,
|
||||||
path,
|
path,
|
||||||
buffer,
|
buffer,
|
||||||
blobUri: null,
|
blobUri: null,
|
||||||
|
|
@ -192,6 +194,7 @@ export async function handleOtherFile(file) {
|
||||||
reader.readAsArrayBuffer(file);
|
reader.readAsArrayBuffer(file);
|
||||||
});
|
});
|
||||||
const fileEntry = {
|
const fileEntry = {
|
||||||
|
source: "direct upload",
|
||||||
path,
|
path,
|
||||||
buffer,
|
buffer,
|
||||||
blobUri: null,
|
blobUri: null,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue