Modernized MoniWiki.
모니위키를 현대적인 웹 스타일로 만드는 방법을 다룹니다.
2. 현대적인 스타일의 코드 하이라이팅 프로세서(VimProcessor, PhpProcessor) #
VimProcessor, PhpProcessor의 코드 하이라이팅 개선
예시
CPP
PHP
CPP
{{{#!vim}}}
#include <iostream>
int main() {
int a = 2;
int b = 3;
std::cout << a + b << std::endl;
}
int main() {
int a = 2;
int b = 3;
std::cout << a + b << std::endl;
}
{{{#!php}}}<?php
function add($a, $b) {
return $a + $b;
}
echo add(2, 3);
?> 변경 파일 요약
| # | 파일 | 변경 유형 | 변경 내용 |
|---|---|---|---|
| 1 | css/_base.css |
수정 | .wikiSyntax 다크 테마 스타일 적용 (배경 #1e1e2e, 현대적 폰트, border-radius: 8px, box-shadow), position: relative 추가, .wikiSyntax-copy 버튼 CSS 추가 |
| 2 | css/_extra.css |
수정 | 중복 .wikiSyntax 스타일 제거, pre.wikiSyntax 색상을 다크 테마로 통일 |
| 3 | wikilib.php |
수정 | processor_php() 다크 테마용 색상 매핑 (highlight_string 출력 색상 치환), Copy 버튼 HTML 삽입 |
| 4 | plugin/processor/vim.php |
수정 | 캐시 반환/일반 반환 모두에 Copy 버튼을 .wikiSyntax 요소 안에 삽입 |
| 5 | config.php |
수정 | $javascripts 배열에 wikisyntax-copy.js 등록 |
| 6 | local/wikisyntax-copy.js |
신규 | 클립보드 복사 함수 — span.line 줄바꿈 처리 (vim), <br> / 변환 처리(php), 구형 브라우저 fallback |
수정 방법
- 다크 테마 적용 (css/_base.css)
- .wikiSyntax 배경색을 #1e1e2e (Catppuccin Mocha)로 변경
- 폰트를 JetBrains Mono, Fira Code 등 현대적 코딩 폰트로 변경
- border-radius: 8px, box-shadow 추가로 입체감 부여
- line-height: 1.6, tab-size: 4로 가독성 향상
- 중복 스타일 정리 (css/_extra.css)
- .wikiSyntax 중복 정의 제거
- pre.wikiSyntax 색상을 _base.css와 동일한 다크 테마로 통일
- PHP 프로세서 다크 테마 색상 매핑 (wikilib.php)
- highlight_string() 출력 색상을 다크 배경에 맞게 치환
- 변수/식별자: #0000BB → #89b4fa
- 키워드: #007700 → #a6e3a1
- 문자열: #DD0000 → #f38ba8
- 주석: #FF8000 → #6c7086
- 기본 텍스트: #000000 → #cdd6f4
- Copy 버튼 추가
CSS (css/_base.css)
- .wikiSyntax-copy 버튼 스타일 추가
- 코드 블록 호버 시 우상단에 페이드인 표시
- 복사 완료 시 초록색 피드백
JavaScript (local/wikisyntax-copy.js) — 신규 파일
- navigator.clipboard API 사용 + 구형 브라우저 fallback
- vim 프로세서: span.line 단위로 \n join하여 줄바꿈 보존
- php 프로세서: <br /> → \n, → 공백 변환 처리
- Copy 버튼 텍스트 자체가 클립보드에 포함되지 않도록 제외 처리
PHP 프로세서 (wikilib.php)
- processor_php() 출력에 Copy 버튼 HTML 삽입
Vim 프로세서 (plugin/processor/vim.php)
- 캐시 반환/일반 반환 모두 .wikiSyntax 요소 내부에 Copy 버튼 삽입
설정 (config.php)
- $javascripts 배열에 wikisyntax-copy.js 등록
3. CSS Cache Busting 메커니즘 적용 #
요약
브라우저 캐시로 인해 테마의 CSS와
브라우저 캐시로 인해 테마의 CSS와
/moniwiki/css/*의 CSS 스타일 수정사항이 반영되지 않는 문제를 해결하기 위해, 모든 CSS <link> 태그에 filemtime() 기반 v= 쿼리스트링을 추가합니다.캐시 버스팅 메커니즘은 여러가지가 있지만 모니위키에서 추천 방식은 filemtime() 쿼리스트링(filemtime()이 MoniWiki의 단순한 구조에 가장 적합함. 파일이 수정될 때마다 자동으로 URL이 바뀌고, 추가 빌드 도구가 필요 없음).
Cache Busting 적용 전 상태
테마 CSS URL 생성 (wiki.php:6000):
결과: /moniwiki/theme/your_theme/css/default.css (쿼리스트링 없음. 단순 CSS 삽입.)
테마 CSS URL 생성 (wiki.php:6000):
$options['css_url'] = $DBInfo->url_prefix . "/theme/$theme/css/default.css";
CSS 출력 (wiki.php:5042-5044):
결과: /moniwiki/css/default.css (쿼리스트링 없음. 단순 CSS 삽입.)
echo ' <link rel="stylesheet" type="text/css" ', $media, ' href="',
$options['css_url'] . "\" />\n";
$options['css_url'] . "\" />\n";
Cache Busting 적용 후 결과
HTML 출력 순서
HTML 출력 순서
<link rel="stylesheet" type="text/css" media="screen" href="/moniwiki/css/_base.css?v=1741234567" />
<link rel="stylesheet" type="text/css" media="screen" href="/moniwiki/css/_extra.css?v=1741234568" />
<link rel="stylesheet" type="text/css" media="screen" href="/moniwiki/css/_calendar.css?v=1741234569" />
<link rel="stylesheet" type="text/css" media="screen" href="/moniwiki/theme/your_theme/css/default.css?v=1741234570" />
<link rel="stylesheet" media="screen" type="text/css" href="/moniwiki/css/_user.css?v=1741234571" />
<link rel="stylesheet" type="text/css" media="screen" href="/moniwiki/css/_extra.css?v=1741234568" />
<link rel="stylesheet" type="text/css" media="screen" href="/moniwiki/css/_calendar.css?v=1741234569" />
<link rel="stylesheet" type="text/css" media="screen" href="/moniwiki/theme/your_theme/css/default.css?v=1741234570" />
<link rel="stylesheet" media="screen" type="text/css" href="/moniwiki/css/_user.css?v=1741234571" />
수정 방법
변경 파일 (테마 CSS)
파일: wiki.php (line 6000)
파일: wiki.php (line 6000)
Before:
if ($theme and ($DBInfo->theme_css or !$options['css_url']))
$options['css_url']=(!empty($DBInfo->themeurl) ? $DBInfo->themeurl:$DBInfo->url_prefix)."/theme/$theme/css/default.css";
After:
if ($theme and ($DBInfo->theme_css or !$options['css_url'])) {
$_css_path = "/theme/$theme/css/default.css";
$_css_prefix = !empty($DBInfo->themeurl) ? $DBInfo->themeurl : $DBInfo->url_prefix;
$_css_mtime = @filemtime('.' . $_css_path);
$options['css_url'] = $_css_prefix . $_css_path . ($_css_mtime ? '?v=' . $_css_mtime : '');
}
if ($theme and ($DBInfo->theme_css or !$options['css_url']))
$options['css_url']=(!empty($DBInfo->themeurl) ? $DBInfo->themeurl:$DBInfo->url_prefix)."/theme/$theme/css/default.css";
After:
if ($theme and ($DBInfo->theme_css or !$options['css_url'])) {
$_css_path = "/theme/$theme/css/default.css";
$_css_prefix = !empty($DBInfo->themeurl) ? $DBInfo->themeurl : $DBInfo->url_prefix;
$_css_mtime = @filemtime('.' . $_css_path);
$options['css_url'] = $_css_prefix . $_css_path . ($_css_mtime ? '?v=' . $_css_mtime : '');
}
변경 파일 (./css/*)
파일: wiki.php — CSS <link> 출력 (line ~5042)
파일: wiki.php — CSS <link> 출력 (line ~5042)
Before:
if ($options['css_url']) {
echo ' <link rel="stylesheet" type="text/css" ',$media,' href="',
$options['css_url']."\" />\n";
if (file_exists('./css/_user.css')) // FIXME
echo ' <link rel="stylesheet" media="screen" type="text/css" href="',
$DBInfo->url_prefix,"/css/_user.css\" />\n";
}
After:
if ($options['css_url']) {
// css/* sub-stylesheets (formerly @import in default.css)
foreach (array('_base.css', '_extra.css', '_calendar.css') as $_css_sub) {
if (file_exists('./css/' . $_css_sub)) {
$_sub_mtime = @filemtime('./css/' . $_css_sub);
echo ' <link rel="stylesheet" type="text/css" ', $media, ' href="',
$DBInfo->url_prefix, '/css/', $_css_sub, ($_sub_mtime ? '?v=' . $_sub_mtime : ''), "\" />\n";
}
}
echo ' <link rel="stylesheet" type="text/css" ',$media,' href="',
$options['css_url']."\" />\n";
if (file_exists('./css/_user.css')) { // FIXME
$_user_css_mtime = @filemtime('./css/_user.css');
echo ' <link rel="stylesheet" media="screen" type="text/css" href="',
$DBInfo->url_prefix,'/css/_user.css', ($_user_css_mtime ? '?v=' . $_user_css_mtime : ''), "\" />\n";
}
}
if ($options['css_url']) {
echo ' <link rel="stylesheet" type="text/css" ',$media,' href="',
$options['css_url']."\" />\n";
if (file_exists('./css/_user.css')) // FIXME
echo ' <link rel="stylesheet" media="screen" type="text/css" href="',
$DBInfo->url_prefix,"/css/_user.css\" />\n";
}
After:
if ($options['css_url']) {
// css/* sub-stylesheets (formerly @import in default.css)
foreach (array('_base.css', '_extra.css', '_calendar.css') as $_css_sub) {
if (file_exists('./css/' . $_css_sub)) {
$_sub_mtime = @filemtime('./css/' . $_css_sub);
echo ' <link rel="stylesheet" type="text/css" ', $media, ' href="',
$DBInfo->url_prefix, '/css/', $_css_sub, ($_sub_mtime ? '?v=' . $_sub_mtime : ''), "\" />\n";
}
}
echo ' <link rel="stylesheet" type="text/css" ',$media,' href="',
$options['css_url']."\" />\n";
if (file_exists('./css/_user.css')) { // FIXME
$_user_css_mtime = @filemtime('./css/_user.css');
echo ' <link rel="stylesheet" media="screen" type="text/css" href="',
$DBInfo->url_prefix,'/css/_user.css', ($_user_css_mtime ? '?v=' . $_user_css_mtime : ''), "\" />\n";
}
}
파일: css/default.css — @import 제거
Before:
@import url("_base.css");
@import url("_extra.css");
@import url("_calendar.css");
body {
After:
body {
@import url("_base.css");
@import url("_extra.css");
@import url("_calendar.css");
body {
After:
body {
Show Comments