rung-tools/rung-cli

View on GitHub
resources/live/index.html

Summary

Maintainability
Test Coverage
<!DOCTYPE html>
<html>
    <head>
        <title>🔥 Rung CLI Hot Server</title>
        <meta charset="utf-8">
        <meta name="viewport" content="initial-scale=1, maximum-scale=1">
        <script type="text/javascript" src="./socket.io.slim.js"></script>
        <link rel="stylesheet" type="text/css" href="./live.css" />
        <link href="https://fonts.googleapis.com/css?family=Roboto:300" rel="stylesheet">
    </head>
    <body>
        <div id="rung-bar">
            <img src="./rung-logo.png" draggable="false" id="logo" />
        </div>
        <div id="rung-alerts"></div>
        <div id="rung-timeline">
            <button id="rung-timeline-prev" disabled class="rung-timeline-button">&lt;</button>
            <div id="rung-timeline-count" title="Time travel">0/0</div>
            <button id="rung-timeline-next" disabled class="rung-timeline-button">&gt;</button>
        </div>
        <div id="rung-loading">
            <div class="double-bounce-1"></div>
            <div class="double-bounce-2"></div>
        </div>
        <div id="sidebar">
            <div id="sidebar-header">
                <div id="sidebar-group-name">Rung Developers</div>
                <div id="sidebar-card-name"></div>
            </div>
            <div id="sidebar-body">
                <div class="fake-field">
                    <div class="fake-indicator"></div>
                    <div class="fake-value"></div>
                </div>
                <div class="fake-field">
                    <div class="fake-indicator"></div>
                    <div class="fake-value"></div>
                </div>
                <div class="fake-field">
                    <div class="fake-indicator"></div>
                    <div class="fake-value"></div>
                </div>
                <div class="fake-field">
                    <div class="fake-indicator"></div>
                    <div class="fake-value"></div>
                </div>
                <div id="markdown-box" class="custom-scrollbar">
                    <div id="markdown-robot"></div>
                    <div id="markdown-content">
                        <div id="sidebar-comment"></div>
                        <div id="markdown-resources"></div>
                    </div>
                </div>
            </div>
            <div id="sidebar-comment-box">
                <div id="sidebar-comment-input"></div>
                <div id="sidebar-send-button"></div>
            </div>
        </div>
        <div id="rung-error"></div>
    </body>
    <script type="text/javascript">
    const timeline = [];
    const DOM = {
        sidebarComment: document.querySelector('#sidebar-comment'),
        markdownResources: document.querySelector('#markdown-resources'),
        sidebarCardName: document.querySelector('#sidebar-card-name'),
        rungAlerts: document.querySelector('#rung-alerts'),
        loading: document.querySelector('#rung-loading'),
        error: document.querySelector('#rung-error'),
        timelinePrev: document.querySelector('#rung-timeline-prev'),
        timelineNext: document.querySelector('#rung-timeline-next'),
        timelineCount: document.querySelector('#rung-timeline-count')
    };

    function openInSidebar(alert) {
        DOM.sidebarComment.innerHTML = alert.comment;
        DOM.markdownResources.innerHTML = (alert.resources || []).map(resource =>
            `<img src="${resource}" draggable="false">`
        ).join('');
        DOM.sidebarCardName.innerText = alert.title;
    }

    function render(alerts) {
        DOM.error.style.display = 'none';
        DOM.rungAlerts.innerHTML = '';
        DOM.loading.style.opacity = 0;

        const indexes = Object.keys(alerts);
        const [first] = indexes;
        openInSidebar(alerts[first] || { title: '', comment: '' });

        indexes.forEach(index => {
            const alert = alerts[index];
            const card = document.createElement('div');
            card.className = 'card custom-scrollbar';
            card.innerHTML = alert.content;
            card.onclick = () => openInSidebar(alert);
            DOM.rungAlerts.appendChild(card);
        });
    }

    function updateTimeline() {
        const { peek } = timeline;
        DOM.timelineCount.innerText = `${peek}/${timeline.length}`;

        if (peek === 1) {
            DOM.timelinePrev.setAttribute('disabled', true);
        } else {
            DOM.timelinePrev.removeAttribute('disabled');
        }

        if (peek >= timeline.length) {
            DOM.timelineNext.setAttribute('disabled', true);
        } else {
            DOM.timelineNext.removeAttribute('disabled');
        }
    }

    const timeTravel = functor => () => {
        const { peek } = timeline;
        const nextState = functor(peek);
        timeline.peek = nextState;
        updateTimeline();
        render(timeline[nextState - 1]);
    };

    DOM.timelinePrev.onclick = timeTravel(time => time - 1);
    DOM.timelineNext.onclick = timeTravel(time => time + 1);

    const socket = io.connect(location.origin);
    socket.on('update', alerts => {
        timeline.push(alerts);
        timeline.peek = timeline.length;
        render(alerts);
        updateTimeline();
    });
    socket.on('load', () => {
        DOM.loading.style.opacity = 1;
    });
    socket.on('failure', error => {
        DOM.loading.style.opacity = 0;
        DOM.error.style.display = 'block';
        DOM.error.innerText = error;
    });
    </script>
</html>