@@ -23,6 +23,7 @@ import { ErrorBoundary, Suspense } from "@suspensive/react";
2323import AjvDraft04 from "ajv-draft-04" ;
2424import * as React from "react" ;
2525import { useNavigate , useParams } from "react-router-dom" ;
26+ import * as R from "remeda" ;
2627
2728import { addErrorSnackbar , addSnackbar } from "../../utils/snackbar" ;
2829import { BackendAdminSignInGuard } from "../elements/admin_signin_guard" ;
@@ -61,22 +62,59 @@ const FileField: Field = (p) => (
6162 />
6263) ;
6364
65+ type ReadOnlyValueFieldStateType = {
66+ loading : boolean ;
67+ blob : Blob | null ;
68+ blobText : string | null ;
69+ objectUrl : string | null ;
70+ } ;
71+
6472const ReadOnlyValueField : React . FC < {
6573 name : string ;
6674 value : unknown ;
6775 uiSchema : UiSchema ;
68- } > = ( { name, value, uiSchema } ) => {
69- if ( uiSchema [ name ] && uiSchema [ name ] [ "ui:field" ] === "file" ) {
76+ } > = Suspense . with ( { fallback : < CircularProgress /> } , ( { name, value, uiSchema } ) => {
77+ const [ fieldState , setFieldState ] = React . useState < ReadOnlyValueFieldStateType > ( {
78+ loading : true ,
79+ blob : null ,
80+ blobText : null ,
81+ objectUrl : null ,
82+ } ) ;
83+
84+ React . useEffect ( ( ) => {
85+ ( async ( ) => {
86+ if ( ! ( R . isString ( value ) && value . startsWith ( "http" ) && uiSchema ?. [ name ] [ "ui:field" ] === "file" ) ) {
87+ setFieldState ( ( ps ) => ( { ...ps , loading : false } ) ) ;
88+ return ;
89+ }
90+
91+ const blob = await ( await fetch ( value ) ) . blob ( ) ;
92+ const blobText = await blob . text ( ) ;
93+ const objectUrl = URL . createObjectURL ( blob ) ;
94+ setFieldState ( ( ps ) => ( { ...ps , loading : false , blob, blobText, objectUrl } ) ) ;
95+ } ) ( ) ;
96+ } , [ value , name , uiSchema ] ) ;
97+
98+ if ( fieldState . loading ) return < CircularProgress /> ;
99+
100+ if ( uiSchema ?. [ name ] ?. [ "ui:field" ] === "file" && fieldState . blob ) {
70101 return (
71102 < Stack spacing = { 2 } alignItems = "flex-start" >
72- < img src = { value as string } alt = { name } style = { { maxWidth : "100%" , maxHeight : "600px" , objectFit : "contain" } } />
103+ { fieldState . blob . type . startsWith ( "image/" ) && fieldState . objectUrl && (
104+ < img src = { fieldState . objectUrl } alt = { name } style = { { maxWidth : "600px" , objectFit : "contain" } } />
105+ ) }
106+ { fieldState . blob . type . startsWith ( "application/json" ) && fieldState . blobText && (
107+ < Box sx = { { maxWidth : "600px" , overflow : "auto" } } >
108+ < Common . Components . LottieDebugPanel animationData = { JSON . parse ( fieldState . blobText ) } />
109+ </ Box >
110+ ) }
73111 < a href = { value as string } > 링크</ a >
74112 </ Stack >
75113 ) ;
76114 }
77115
78116 return value as string ;
79- } ;
117+ } ) ;
80118
81119type InnerAdminEditorStateType = {
82120 tab : number ;
0 commit comments