@@ -6,8 +6,10 @@ import {
66 useRemovePreparedMutation ,
77 useUpdatePreparedMutation ,
88} from "@frontend/common/hooks/useAdminAPI" ;
9+ import { isHexColor } from "@frontend/common/utils" ;
910import { Add , ArrowDownward , ArrowUpward , Delete , Edit } from "@mui/icons-material" ;
1011import {
12+ Box ,
1113 Button ,
1214 CircularProgress ,
1315 Dialog ,
@@ -27,6 +29,7 @@ import {
2729import { ErrorBoundary , Suspense } from "@suspensive/react" ;
2830import { FC , FormEvent , ReactNode , useEffect , useMemo , useState } from "react" ;
2931
32+ import { ColorInput } from "@apps/pyconkr-admin/components/elements/color_input" ;
3033import { ErrorFallback } from "@apps/pyconkr-admin/components/elements/error_fallback" ;
3134import { addErrorSnackbar , addSnackbar } from "@apps/pyconkr-admin/utils/snackbar" ;
3235
@@ -44,14 +47,14 @@ type Width = string | number;
4447 *
4548 * - `translated` renders as two table columns (한국어/영어) and two form inputs.
4649 * The _ko variant is always treated as required.
47- * - `text` / `number` render as one column and one input.
50+ * - `text` / `number` / `color` render as one column and one input.
4851 */
4952export type ColumnDef =
5053 | { name : string ; label : string ; type : "translated" ; align ?: Align ; width ?: Width }
5154 | {
5255 name : string ;
5356 label : string ;
54- type : "text" | "number" ;
57+ type : "text" | "number" | "color" ;
5558 align ?: Align ;
5659 width ?: Width ;
5760 defaultValue ?: ( existingCount : number ) => string ;
@@ -90,6 +93,8 @@ const buildPayload = (columns: ColumnDef[], values: FormValues, filter: { key: s
9093 payload [ `${ c . name } _en` ] = values [ `${ c . name } _en` ] ?? "" ;
9194 } else if ( c . type === "number" ) {
9295 payload [ c . name ] = Number ( values [ c . name ] ) || 0 ;
96+ } else if ( c . type === "color" ) {
97+ payload [ c . name ] = values [ c . name ] || null ;
9398 } else {
9499 payload [ c . name ] = values [ c . name ] ?? "" ;
95100 }
@@ -217,6 +222,19 @@ const ResourceDialog: FC<ResourceDialogProps> = ({ open, onClose, app, resource,
217222 </ Stack >
218223 ) ;
219224 }
225+ if ( c . type === "color" ) {
226+ return (
227+ < ColorInput
228+ key = { c . name }
229+ label = { c . label }
230+ value = { values [ c . name ] || null }
231+ error = { ! ! fieldErrors [ c . name ] }
232+ helperText = { fieldErrors [ c . name ] || c . helperText }
233+ autoFocus = { idx === 0 }
234+ onChange = { ( v ) => setField ( c . name , v ?? "" ) }
235+ />
236+ ) ;
237+ }
220238 return (
221239 < TextField
222240 key = { c . name }
@@ -273,6 +291,15 @@ const renderCellValue = (column: ColumnDef, row: ResourceRow, subKey?: "ko" | "e
273291 }
274292 if ( column . render ) return column . render ( row ) ;
275293 const v = row [ column . name ] ;
294+ if ( column . type === "color" ) {
295+ if ( ! isHexColor ( v ) ) return "" ;
296+ return (
297+ < Stack direction = "row" spacing = { 1 } alignItems = "center" >
298+ < Box sx = { { width : 16 , height : 16 , borderRadius : "4px" , backgroundColor : v , border : 1 , borderColor : "divider" } } />
299+ < span > { v } </ span >
300+ </ Stack >
301+ ) ;
302+ }
276303 return v === null || v === undefined ? "" : String ( v ) ;
277304} ;
278305
0 commit comments