From c3bbb4e9599b9e160bc4e77d510e2f50881196da Mon Sep 17 00:00:00 2001 From: th-kim0823 Date: Mon, 27 Apr 2026 20:15:25 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20admin=20=EC=A3=BC=EC=A0=9C=20=ED=8E=B8?= =?UTF-8?q?=EC=A7=91=20=E2=80=94=20JSON=20=EC=A7=81=EC=A0=91=20=ED=8E=B8?= =?UTF-8?q?=EC=A7=91=20+=20=EA=B2=80=EC=A6=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- app.py | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/app.py b/app.py index 6b58437..bccce16 100644 --- a/app.py +++ b/app.py @@ -710,9 +710,41 @@ def render_admin(): update_topics(new_cats) st.success("저장됨. 큰 화면 다음 갱신 시 반영.") st.rerun() - # JSON 모드는 T14에서 추가 (else branch는 placeholder) - else: - st.info("Task 14에서 JSON 직접 편집 모드 추가됨.") + else: # JSON 직접 편집 + current_json = json.dumps( + {"categories": cur_topics}, ensure_ascii=False, indent=2 + ) + edited = st.text_area( + "topics JSON", + value=current_json, + height=400, + key="topics_json_editor", + ) + jc1, jc2 = st.columns(2) + with jc1: + if st.button("JSON 검증"): + try: + parsed = json.loads(edited) + cats = parsed.get("categories", []) + if not isinstance(cats, list): + st.error("'categories'는 list 여야 합니다.") + else: + st.success(f"OK — {len(cats)}개 카테고리") + except json.JSONDecodeError as e: + st.error(f"JSON 파싱 실패: {e}") + with jc2: + if st.button("JSON 저장", type="primary"): + try: + parsed = json.loads(edited) + cats = parsed.get("categories", []) + if not isinstance(cats, list): + st.error("'categories'는 list 여야 합니다.") + else: + update_topics(cats) + st.success("저장됨.") + st.rerun() + except json.JSONDecodeError as e: + st.error(f"저장 실패 — JSON 파싱 에러: {e}") st.divider()