사이트 제작기 시리즈 · 1부 — 왜 정적 홈페이지인가 / 2부 — 콘텐츠 3구역 / 3부 — 자동화 파이프라인 / 4부 (이 글, 완결) — 커스터마이징과 관리자 패널
1부에서 “Hugoplate 테마를 바닥부터 만들지 않고 가져와 필요한 부분만 고쳐 썼다”고 했습니다. 이번 완결편은 바로 그 길들이기(커스터마이징) 이야기입니다. 남이 만든 옷을 사서 내 몸에 맞게 수선한 셈인데, 그 수선 자국을 하나씩 보여드리겠습니다.
1. 목록을 3열 카드 + 사이드바로
테마 기본 목록은 단순한 한 줄 나열이었습니다. 이걸 왼쪽 3열 카드 + 오른쪽 사이드바 구성으로 바꿨습니다(layouts/blog/list.html). Hugoplate는 12칸 그리드를 쓰는데, 본문에 9칸, 사이드바에 3칸을 줬습니다.
카드 자체도 손봤습니다. 작성자·카테고리 같은 잡다한 메타 정보는 숨기고, 요약문만 200자에서 잘라 깔끔하게 보이도록 했습니다.
2. 정적 사이트의 딜레마 — “화면 크기를 모른다”
여기서 흥미로운 문제가 있습니다. 정적 사이트는 방문자의 화면 크기를 미리 알 수 없습니다. 빌드 시점에 이미 HTML이 굳어버리기 때문입니다. 그런데 우리는 데스크톱(3열)에서는 9개, 태블릿(2열)에서는 8개, 모바일(1열)에서는 6개만 딱 떨어지게 보여주고 싶었습니다.
해법은 우아합니다. 일단 9개를 다 만들어 두고, 화면 크기에 안 맞는 카드만 CSS로 숨기는 것입니다(assets/css/custom.css).
“서버가 판단할 수 없으면, 다 만들어 놓고 브라우저(CSS)에게 판단을 넘긴다.” 정적 사이트에서 자주 쓰는 발상의 전환입니다.
3. 다크 모드에서 로고가 사라지는 문제
이 사이트의 로고는 검은색 글자입니다. 그런데 다크 모드나 어두운 푸터 위에서는 검은 글자가 배경에 묻혀 안 보였습니다. 이미지를 두 벌 만드는 대신, 브라우저에서 색을 반전시키는 CSS 한 줄로 해결했습니다.
⚠️ 여기엔 함정이 있었습니다. 다크 모드에서 푸터 로고에 헤더용 반전과 푸터용 반전이 동시에 걸리면, 반전이 두 번 되어 도로 검은색이 됩니다. 그래서 푸터 로고에서는 헤더 반전 규칙에 걸리는 클래스를 빼서 이중 반전을 막았습니다.
이 밖에도 카드·인용구·태그 배지의 다크 모드 배경색을 손봤습니다. 테마 원본이 “연한 회색 글자색”을 실수로 “카드 배경색”으로도 써버려서, 다크 모드에서 글자색과 배경색이 똑같아져 안 보이던 버그가 있었거든요. 배경을 한 단계 밝은 회색(dark:bg-[#444444])으로 분리하고 글자색을 명시해 대비를 확보했습니다.
4. 코드를 안 고치고 정렬을 바꾸기
카테고리마다 원하는 정렬이 다릅니다. IT뉴스는 최신순이 좋지만, 강의 시리즈는 “1부, 2부, 3부” 순서(제목순)여야 합니다. 이걸 템플릿에 하드코딩하지 않고 설정 파일로 제어하도록 만들었습니다(config/_default/params.toml).
템플릿은 이 설정을 읽어 분기합니다.
덕분에 정렬 규칙을 바꿀 때 코드가 아니라 설정 한 줄만 고치면 됩니다. (실은 이 설정마저도 다음 항목의 관리자 패널에서 브라우저로 바꿀 수 있습니다.)
5. 코딩 없이 관리하는 Git 기반 관리자 패널
이 사이트에서 가장 야심 찬 기능입니다. jesusiswith.us/admin/ 주소로 들어가면, 개발 환경 없이 웹 브라우저만으로 카드 표시 옵션·폰트 크기·메뉴별 정렬 기준 같은 설정을 바꾸고 즉시 반영할 수 있습니다.
서버 없이 어떻게?
정적 사이트에는 백엔드 서버가 없다고 1부에서 강조했는데, 그럼 이 패널은 어떻게 설정을 저장할까요? 비밀은 GitHub REST API에 브라우저가 직접 말을 거는 것입니다.
- 인증: GitHub 개인 접근 토큰(PAT)을 쓰되, 이 토큰은 서버가 아니라 관리자 브라우저의 localStorage에만 저장됩니다.
- 배포 상태 표시: 저장 후 GitHub Actions 상태를 주기적으로 확인해 “배포 중 / 성공 / 실패”를 화면에 보여줍니다.
로컬 작업과 충돌하지 않으려면
관리자 패널은 원격 저장소를 직접 수정하기 때문에, 로컬 컴퓨터의 파일보다 원격이 앞서게 됩니다. 이 상태에서 로컬 변경을 그냥 올리면 거절(rejected)당합니다. 그래서 3부의 auto_push.sh도, 사람이 손으로 올릴 때도 항상 먼저 당겨받는 습관이 중요합니다.
원칙 하나: 메뉴 수정은 관리자 패널이든 로컬 파일이든 한쪽에서만 하세요. 양쪽에서 동시에 건드리면 병합 충돌이 납니다.
6. 제작 중 실제로 부딪힌 문제들 (트러블슈팅 하이라이트)
교육을 겸한 글인 만큼, “이런 것도 문제가 되는구나”를 남기는 게 가장 값진 부분입니다. 실제 제작 기록(docs/issue_report.md, JIWU_Mission_Troubleshooting_Report.md)에서 대표적인 것만 골랐습니다.
① path 필드 때문에 빌드가 통째로 실패
노션에서 내보낸 파일에는 path: 필드가 딸려 오는데, 최신 Hugo(v0.144+)는 이 필드를 만나면 빌드를 아예 중단합니다.
노션 동기화 때마다 다시 붙을 수 있으므로, 올리기 전
npm run build로 빌드를 미리 검증하는 습관이 안전합니다.
② 확장자는 .png인데 실제론 WebP — “unknown format”
파일 이름은 .png인데 내용은 사실 WebP인 경우, Hugo의 이미지 리사이징이 image: unknown format 오류로 멈춥니다. file 명령으로 진짜 포맷을 확인하고 확장자를 실제와 일치시켜 해결했습니다. 이후로는 아예 모든 이미지를 WebP로 통일해, 용량도 줄이고(약 26%↓) 이 오류도 원천 차단했습니다.
③ 맥에서만 정렬이 깨지던 한글 유니코드 문제
macOS는 한글을 자모 분리 방식(NFD)으로 저장하는데, 코드 속 한글 문자열은 결합형(NFC)이라 “세컨드브레인” == “세컨드브레인” 비교가 실패하는 황당한 버그가 있었습니다. 해법은 한글 문자열을 비교하는 대신 영문으로 된 폴더 경로를 비교하도록 바꾼 것입니다.
④ 로컬 미리보기에서 화면이 깨지던 문제
로컬 개발 서버를 돌리면 hugo.toml의 운영 도메인 주소를 물어와서, CSS를 엉뚱한 곳(운영 서버)에서 찾다가 화면이 깨졌습니다. 개발 환경 전용 설정 파일을 따로 두어 격리했습니다.
이러면 개발 중에는 이 값이 우선 적용되고, 실제 배포 빌드에서는 무시됩니다. Cloudflare 배포에서도 비슷하게 --baseURL $CF_PAGES_URL로 배포 주소를 동적으로 넣어 미리보기 URL에서도 디자인이 안 깨지게 했습니다.
7. 시리즈를 마치며
네 편에 걸쳐 이 사이트의 안팎을 함께 열어 봤습니다. 전체를 한 문단으로 되짚으면:
jesusiswith.us는 서버 없이 돌아가는 정적 홈페이지입니다. 글은 Markdown으로 쓰고 Hugo가 HTML로 변환하며, GitHub에 올리면 Cloudflare가 전 세계로 배포합니다(1부). 콘텐츠는 Blog·Class·Databank 세 구역에 나뉘어, 노션·수동·AI 세 경로로 채워집니다(2부). 밤사이엔 AI가 IT뉴스를 쓰고 스케줄러가 자동으로 올리며, 접속하면 그날의 QT가 팝업으로 인사합니다(3부). 그리고 가져온 테마를 반응형·다크모드·정렬·관리자 패널로 길들여, 코딩을 몰라도 운영할 수 있게 만들었습니다(4부).
코딩 경험이 없어도, 월 0원에 가까운 비용으로, AI의 도움을 받아 이만큼 만들 수 있다는 것이 이 프로젝트가 전하고 싶은 메시지입니다. 이 시리즈가 여러분만의 사이트를 시작하는 작은 계기가 되기를 바랍니다.
📚 더 깊이 들어가려면 — 같은 섹션의 “교회 홈페이지 무료 제작 매뉴얼(Chapter 1~5)” 시리즈가 처음부터 따라 만드는 실습 가이드를 제공합니다. 이 제작기가 “무엇을·왜”라면, 그 매뉴얼은 “어떻게”에 해당합니다.
