GNU/skin/board/daemon/view.skin.php
<?php
if (!defined('_GNUBOARD_')) exit;

add_stylesheet('<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">', 0);
include_once(G5_LIB_PATH.'/thumbnail.lib.php');

// 스타일시트 연결
add_stylesheet('<link rel="stylesheet" href="'.$board_skin_url.'/style.view.css">', 0);

$view_content = get_view_thumbnail($view['content']);
$is_run = (isset($view['x2_run']) && ($view['x2_run'] == '1' || $view['x2_run'] == '실행' || strtolower($view['x2_run']) == 'run'));

// 1. [수정] 데몬 파일 소스코드 조회 (기존 x2_daemon -> wr_subject로 변경)
$daemon_name = isset($view['wr_subject']) ? $view['wr_subject'] : '';
$daemon_code = '';

if ($daemon_name) {
    $daemon_root = '/home/www/DATA/UPBIT/daemon';
    $target_path = '';

    // 루트에 바로 있는지 먼저 확인 (속도 최적화)
    if (file_exists($daemon_root . '/' . $daemon_name)) {
        $target_path = $daemon_root . '/' . $daemon_name;
    } else {
        // 없으면 하위 디렉토리 전체 스캔
        if (is_dir($daemon_root) && is_readable($daemon_root)) {
            try {
                $di = new RecursiveDirectoryIterator($daemon_root, RecursiveDirectoryIterator::SKIP_DOTS);
                $it = new RecursiveIteratorIterator($di);
                foreach ($it as $file) {
                    if ($file->isFile() && $file->getFilename() == $daemon_name) {
                        $target_path = $file->getPathname();
                        break; // 찾으면 중단
                    }
                }
            } catch (Exception $e) { }
        }
    }

    // 파일 읽기
    if ($target_path && file_exists($target_path) && is_readable($target_path)) {
        $daemon_code = file_get_contents($target_path);
    }
}

// 상태 색상 설정
$state_color = $is_run ? '#00d4ff' : '#ff2d55';
?>

<style>
    /* 전체 레이아웃 및 배경 */
    #VIEW { position: relative; min-height: 100vh; background: #020617; padding: 40px 50px; font-family: 'Pretendard', sans-serif; color: #f1f5f9; overflow-x: hidden; }
    #starCanvas { position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 1; opacity: 0.25; }
    
    .View-Wrapper { position: relative; z-index: 2; background: rgba(2, 6, 23, 0.8); border: 1px solid #1e293b; border-radius: 16px; box-shadow: 0 25px 50px rgba(0,0,0,0.6); overflow: hidden; backdrop-filter: blur(10px); }

    /* 헤더 */
    .View-Header { padding: 20px 30px; background: rgba(15, 23, 42, 0.6); border-bottom: 1px solid #1e293b; display: flex; justify-content: space-between; align-items: center; }
    .View-Header h2 { margin: 0; font-size: 1.1rem; font-weight: 900; color: #fff; display: flex; align-items: center; gap: 12px; letter-spacing: -0.5px; }
    .View-Header h2 i { color: #00d4ff; }
    .View-Header .status-badge { padding: 5px 14px; border-radius: 50px; font-size: 0.7rem; font-weight: 800; background: rgba(0, 0, 0, 0.3); color: <?php echo $state_color; ?>; border: 1px solid <?php echo $state_color; ?>; text-transform: uppercase; }

    /* [단독 디자인] Target Object 히어로 섹션 */
    .Hero-Target-Section { padding: 50px 40px; background: linear-gradient(135deg, #0f172a 0%, #020617 100%); border-bottom: 1px solid #1e293b; display: flex; align-items: center; gap: 30px; position: relative; overflow: hidden; }
    .Hero-Target-Section::before { content: ''; position: absolute; top: 0; left: 0; width: 4px; height: 100%; background: #00d4ff; box-shadow: 0 0 20px #00d4ff; }
    .Hero-Icon { width: 80px; height: 80px; background: rgba(0, 212, 255, 0.1); border: 1px solid rgba(0, 212, 255, 0.3); border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 2.5rem; color: #00d4ff; text-shadow: 0 0 15px rgba(0, 212, 255, 0.5); }
    .Hero-Content { flex: 1; }
    .Hero-Content .label { display: block; color: #64748b; font-size: 0.75rem; font-weight: 800; text-transform: uppercase; letter-spacing: 2px; margin-bottom: 8px; }
    .Hero-Content .subject-text { font-size: 2.2rem; color: #fff; font-weight: 900; margin-bottom: 8px; letter-spacing: -1px; font-family: 'JetBrains Mono', monospace; }
    .Hero-Content .kor-text { font-size: 1.2rem; color: #94a3b8; font-weight: 600; display: flex; align-items: center; gap: 10px; margin-bottom: 15px; }
    .Hero-Content .kor-text::before { content: ''; width: 20px; height: 2px; background: #1e293b; }
    
    /* 메모(wr_1) 출력 스타일 */
    .Hero-Memo { background: rgba(0, 212, 255, 0.08); border: 1px solid rgba(0, 212, 255, 0.2); padding: 12px 20px; border-radius: 8px; display: inline-flex; align-items: flex-start; gap: 12px; color: #00d4ff; font-size: 0.95rem; font-weight: 500; line-height: 1.5; max-width: 80%; }
    .Hero-Memo i { font-size: 1rem; margin-top: 3px; filter: drop-shadow(0 0 5px #00d4ff); }

    /* 대시보드 그리드 */
    .Dashboard-Grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px; background: #1e293b; border-bottom: 1px solid #1e293b; }
    .info-item { background: #080c14; padding: 20px 30px; transition: 0.3s; }
    .info-item:hover { background: #0f172a; }
    .info-item .label { display: flex; align-items: center; color: #64748b; font-size: 0.65rem; font-weight: 800; margin-bottom: 8px; text-transform: uppercase; letter-spacing: 1px; }
    .info-item .label i { color: #00d4ff; margin-right: 8px; font-size: 0.8rem; }
    .info-item .value { font-size: 0.95rem; color: #f1f5f9; font-weight: 600; }
    .info-item .value.accent { color: #00d4ff; font-family: 'JetBrains Mono', monospace; }

    /* 실시간 상태바 */
    .dynamic-result-area { background: #020617; padding: 15px 30px; border-bottom: 1px solid #1e293b; display: flex; flex-wrap: wrap; gap: 15px 40px; border-left: 4px solid #00d4ff; }
    .res-item { font-family: 'JetBrains Mono', monospace; font-size: 0.75rem; display: flex; align-items: center; }
    .res-item span { color: #475569; margin-right: 10px; font-weight: 800; }
    .res-item b { color: #94a3b8; text-transform: uppercase; }

    /* 본문 섹션 */
    .View-Body { padding: 40px; background: #000; }
    .section-title { display: flex; align-items: center; gap: 10px; margin-bottom: 20px; color: #00d4ff; font-size: 0.85rem; font-weight: 900; text-transform: uppercase; }
    .section-title::after { content: ''; flex: 1; height: 1px; background: linear-gradient(90deg, #1e293b, transparent); }
    .main-content { line-height: 1.8; color: #cbd5e1; font-size: 1.05rem; margin-bottom: 50px; }
    .info-card { background: rgba(30, 41, 59, 0.3); padding: 25px; border-radius: 12px; border: 1px solid #1e293b; margin-bottom: 30px; }
    .info-card.special { border-left: 4px solid #ff2d55; background: rgba(255, 45, 85, 0.05); }
    .info-card.additional { border-left: 4px solid #00d4ff; background: rgba(0, 212, 255, 0.05); }
    
    /* 코드 블럭 (300px 스크롤 적용) */
    .code-block { background: #050505; border: 1px solid #1e293b; padding: 25px; border-radius: 8px; font-family: 'JetBrains Mono', monospace; font-size: 0.85rem; color: #00d4ff; overflow-x: auto; overflow-y: auto; line-height: 1.6; max-height: 300px; margin-bottom: 30px; }
    .code-block::-webkit-scrollbar { width: 8px; height: 8px; }
    .code-block::-webkit-scrollbar-track { background: #020617; }
    .code-block::-webkit-scrollbar-thumb { background: #1e293b; border-radius: 4px; }
    .code-block::-webkit-scrollbar-thumb:hover { background: #00d4ff; }

    /* 태그 링크 */
    .Tag-Container { padding: 20px 40px; background: #080c14; border-top: 1px solid #1e293b; display: flex; flex-wrap: wrap; gap: 10px; }
    .x2-tag-item { display: inline-block; padding: 4px 12px; background: #1e293b; color: #94a3b8; border-radius: 4px; font-size: 0.8rem; font-weight: 700; transition: 0.2s; text-decoration: none; }
    .x2-tag-item:hover { background: #00d4ff; color: #020617; transform: translateY(-2px); }

    /* 버튼 */
    .View-Footer { padding: 30px; background: #080c14; border-top: 1px solid #1e293b; display: flex; justify-content: center; gap: 12px; }
    .btn-ui { padding: 12px 28px; border-radius: 6px; font-size: 0.85rem; font-weight: 800; cursor: pointer; transition: 0.2s; border: 1px solid #334155; background: #0f172a; color: #f1f5f9; text-decoration: none; display: inline-flex; align-items: center; gap: 8px; }
    .btn-ui:hover { border-color: #00d4ff; color: #00d4ff; background: #1e293b; }
    .btn-ui.btn-edit { background: #00d4ff; color: #020617; border: none; }
    .btn-ui.btn-edit:hover { background: #fff; color: #000; box-shadow: 0 0 20px rgba(0, 212, 255, 0.4); }

    .Post-Nav { margin-top: 30px; display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
    .nav-item { padding: 20px; background: rgba(15, 23, 42, 0.5); border: 1px solid #1e293b; border-radius: 12px; text-decoration: none; transition: 0.3s; }
    .nav-item:hover { border-color: #00d4ff; background: rgba(0, 212, 255, 0.05); }
    .nav-item .nav-label { display: block; font-size: 0.7rem; color: #64748b; font-weight: 800; margin-bottom: 5px; text-transform: uppercase; }
    .nav-item .nav-title { display: block; font-size: 0.95rem; color: #f1f5f9; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
</style>

<article id="VIEW">
    <canvas id="starCanvas"></canvas>

    <div class="View-Wrapper">
        <header class="View-Header">
            <h2><i class="fa-solid fa-terminal"></i> SYSTEM_CORE_VIEWER</h2>
            <div class="status-badge">
                <i class="fa-solid fa-circle" style="font-size: 8px; margin-right: 6px; vertical-align: middle;"></i>
                <?php echo $is_run ? 'DAEMON' : 'STOPPED'; ?>
            </div>
        </header>

        <section class="Hero-Target-Section">
            <div class="Hero-Icon">
                <i class="fa-solid fa-microchip"></i>
            </div>
            <div class="Hero-Content">
                <span class="label">Target Object / Identifier</span>
                <div class="subject-text"><?php echo get_text($view['wr_subject']); ?></div>
                <div class="kor-text"><?php echo get_text($view['wr_subject_kor']); ?></div>
                
                <?php if(isset($view['wr_1']) && trim($view['wr_1'])) { ?>
                <div class="Hero-Memo">
                    <i class="fa-solid fa-note-sticky"></i>
                    <span><?php echo nl2br(get_text($view['wr_1'])); ?></span>
                </div>
                <?php } ?>
            </div>
        </section>

        <section class="Dashboard-Grid">
            <div class="info-item">
                <span class="label"><i class="fa-solid fa-building-columns"></i> Exchange</span>
                <div class="value"><?php echo $view['ca_name'] ? $view['ca_name'] : 'N/A'; ?></div>
            </div>

            <div class="info-item">
                <span class="label"><i class="fa-solid fa-calendar-check"></i> TABLE</span>
                <div class="value accent"><?php echo isset($view['sel_event']) && $view['sel_event'] ? get_text($view['sel_event']) : '-'; ?></div>
            </div>

            <div class="info-item">
                <span class="label"><i class="fa-solid fa-gears"></i> Daemon Process</span>
                <div class="value accent"><?php echo $view['wr_subject'] ? $view['wr_subject'] : 'STANDALONE'; ?></div>
            </div>

            <div class="info-item">
                <span class="label"><i class="fa-solid fa-layer-group"></i> TYPE</span>
                <div class="value"><?php echo $view['x2_ca2']; ?></div>
            </div>

            <div class="info-item">
                <span class="label"><i class="fa-solid fa-layer-group"></i> FORM</span>
                <div class="value"><?php echo $view['x2_ca3']; ?></div>
            </div>

            <div class="info-item">
                <span class="label"><i class="fa-solid fa-shield-halved"></i> MANAGEMENT</span>
                <div class="value accent" style="color:<?php echo $state_color; ?>;"><?php echo $is_run ? 'START' : 'STOP'; ?></div>
            </div>
        </section>

        <div class="dynamic-result-area">
            <div class="res-item"><span>[STATUS]</span> <b style="color:<?php echo $state_color; ?>"><?php echo $is_run ? 'ACTIVE' : 'INACTIVE'; ?></b></div>
            <div class="res-item"><span>[ID]</span> <b>#<?php echo $view['wr_id']; ?></b></div>
            <div class="res-item"><span>[DAEMON]</span> <b><?php echo $view['wr_subject']; ?></b></div>
            <div class="res-item"><span>[TABLE]</span> <b><?php echo isset($view['sel_event']) ? $view['sel_event'] : ''; ?></b></div>
        </div>

        <section class="View-Body">
            <?php if ($view_content) { ?>
                <div class="section-title">Detailed Description</div>
                <div class="main-content">
                    <?php echo $view_content; ?>
                </div>
            <?php } ?>

            <?php if (isset($view['x2_content']) && trim($view['x2_content'])) { ?>
                <div class="section-title">Additional Information</div>
                <div class="info-card additional">
                    <div class="main-content" style="margin-bottom:0;">
                        <?php echo nl2br(stripslashes($view['x2_content'])); ?>
                    </div>
                </div>
            <?php } ?>

            <?php if (isset($view['x2_content_2']) && trim($view['x2_content_2'])) { ?>
                <div class="section-title" style="color:#ff2d55;">Special Notes & Warnings</div>
                <div class="info-card special">
                    <div class="main-content" style="margin-bottom:0; color:#fca5a5;">
                        <?php echo nl2br(stripslashes($view['x2_content_2'])); ?>
                    </div>
                </div>
            <?php } ?>

            <?php if ($daemon_code) { ?>
                <div class="section-title" style="color:#00d4ff;">Daemon Source Code (<?php echo $daemon_name; ?>)</div>
                <pre class="code-block"><?php echo htmlspecialchars($daemon_code); ?></pre>
            <?php } ?>

        </section>

        <?php if (count($view['link']) > 0 || $view['file']['count'] > 0) { ?>
        <section style="padding: 25px 40px; background: rgba(15, 23, 42, 0.4); border-top: 1px solid #1e293b;">
            <div style="display:flex; flex-wrap:wrap; gap:12px;">
                <?php
                for ($i=1; $i<=count($view['link']); $i++) {
                    if ($view['link'][$i]) {
                        echo '<a href="'.$view['link_href'][$i].'" target="_blank" class="btn-ui" style="font-size:0.75rem;"><i class="fa-solid fa-link"></i> '.cut_str($view['link'][$i], 40).'</a>';
                    }
                }
                if ($view['file']['count']) {
                    for ($i=0; $i<count($view['file']); $i++) {
                        if (isset($view['file'][$i]['source']) && !isset($view['file'][$i]['view'])) {
                            echo '<a href="'.$view['file'][$i]['href'].'" class="btn-ui" style="font-size:0.75rem;"><i class="fa-solid fa-download"></i> '.$view['file'][$i]['source'].'</a>';
                        }
                    }
                }
                ?>
            </div>
        </section>
        <?php } ?>

        <?php if ($view['x2_tag']) { ?>
        <div class="Tag-Container">
            <i class="fa-solid fa-tags" style="color:#475569; margin-right:10px; align-self:center;"></i>
            <?php
            $tags = explode(',', $view['x2_tag']); 
            foreach($tags as $tag_val) {
                $tag_val = trim($tag_val);
                if($tag_val) {
                    echo '<a href="'.G5_BBS_URL.'/board.php?bo_table='.$bo_table.'&amp;stx='.urlencode($tag_val).'&amp;sfl=wr_subject||wr_content" class="x2-tag-item">#'.$tag_val.'</a>';
                }
            }
            ?>
        </div>
        <?php } ?>

        <footer class="View-Footer">
            <a href="<?php echo $list_href; ?>" class="btn-ui"><i class="fa-solid fa-list"></i> LIST</a>
            <?php if ($update_href) { ?>
                <a href="<?php echo $update_href; ?>" class="btn-ui btn-edit"><i class="fa-solid fa-pen-to-square"></i> EDIT CONFIG</a>
            <?php } ?>
            <?php if ($delete_href) { ?>
                <a href="<?php echo $delete_href; ?>" onclick="return confirm('정말 삭제하시겠습니까?');" class="btn-ui" style="color:#ff2d55; border-color:#ff2d5522;"><i class="fa-solid fa-trash-can"></i> DELETE</a>
            <?php } ?>
        </footer>
    </div>

    <nav class="Post-Nav">
        <?php if ($prev_href) { ?>
            <a href="<?php echo $prev_href; ?>" class="nav-item">
                <span class="nav-label"><i class="fa-solid fa-arrow-left"></i> Previous Post</span>
                <span class="nav-title"><?php echo $prev_wr_subject; ?></span>
            </a>
        <?php } else { ?>
            <div class="nav-item" style="opacity:0.3; cursor:default;">
                <span class="nav-label">Previous Post</span>
                <span class="nav-title">No more posts</span>
            </div>
        <?php } ?>

        <?php if ($next_href) { ?>
            <a href="<?php echo $next_href; ?>" class="nav-item" style="text-align:right;">
                <span class="nav-label">Next Post <i class="fa-solid fa-arrow-right"></i></span>
                <span class="nav-title"><?php echo $next_wr_subject; ?></span>
            </a>
        <?php } else { ?>
            <div class="nav-item" style="opacity:0.3; cursor:default; text-align:right;">
                <span class="nav-label">Next Post</span>
                <span class="nav-title">No more posts</span>
            </div>
        <?php } ?>
    </nav>
</article>

<script>
$(function() {
    // 배경 애니메이션
    const canvas = document.getElementById('starCanvas');
    const ctx = canvas.getContext('2d');
    let stars = [];

    function init() {
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        stars = [];
        for(let i=0; i<150; i++) {
            stars.push({
                x: Math.random() * canvas.width,
                y: Math.random() * canvas.height,
                size: Math.random() * 2,
                spd: Math.random() * 0.4 + 0.1
            });
        }
    }

    function draw() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.fillStyle = "rgba(255, 255, 255, 0.4)";
        stars.forEach(s => {
            ctx.beginPath();
            ctx.arc(s.x, s.y, s.size, 0, Math.PI*2);
            ctx.fill();
            s.y += s.spd;
            if(s.y > canvas.height) s.y = 0;
        });
        requestAnimationFrame(draw);
    }

    init();
    draw();
    window.onresize = init;
});
</script>