Skip to content

Commit 4ad56f5

Browse files
committed
feat: 파일 어드민에서 Lottie 애니메이션을 미리 조회 가능하도록 추가
1 parent eb98f21 commit 4ad56f5

File tree

1 file changed

+42
-4
lines changed

1 file changed

+42
-4
lines changed

apps/pyconkr-admin/src/components/layouts/admin_editor.tsx

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { ErrorBoundary, Suspense } from "@suspensive/react";
2323
import AjvDraft04 from "ajv-draft-04";
2424
import * as React from "react";
2525
import { useNavigate, useParams } from "react-router-dom";
26+
import * as R from "remeda";
2627

2728
import { addErrorSnackbar, addSnackbar } from "../../utils/snackbar";
2829
import { 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+
6472
const 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

81119
type InnerAdminEditorStateType = {
82120
tab: number;

0 commit comments

Comments
 (0)