Skip to content

Instantly share code, notes, and snippets.

@pacochi
Created August 9, 2021 08:42
Show Gist options
  • Select an option

  • Save pacochi/41ed4cbdd6cbf2b5ca36e79ac6a34a58 to your computer and use it in GitHub Desktop.

Select an option

Save pacochi/41ed4cbdd6cbf2b5ca36e79ac6a34a58 to your computer and use it in GitHub Desktop.

Revisions

  1. pacochi created this gist Aug 9, 2021.
    242 changes: 242 additions & 0 deletions view.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,242 @@
    <!doctype html>
    <html lang="ja">
    <head>
    <meta charset="utf-8">
    <title>ログ見るだけのやつ</title>
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <meta name="referrer" content="no-referrer">
    <meta name="robots" content="none">
    <style type="text/css">
    body {
    background-color: #fafafa;
    display: flex;
    flex-wrap: wrap;
    }
    h1 {
    font-size: medium;
    color: #777;
    width: 100%;
    }
    nav {
    width: 10em;
    }
    ul {
    list-style-type: none;
    margin: 5px;
    padding: 5px;
    }
    li {
    margin: 0.5em;
    color: #555;
    cursor: pointer;
    }
    main {
    width: calc(100% - 20em) !important;
    }
    article {
    margin: 5px;
    border-radius: 5px;
    box-shadow: 0 2px 5px #ccc;
    background-color: white;
    }
    img {
    width: 256px;
    border-radius: 5px 5px 0 0;
    max-width: 100%;
    max-height: 100%;
    height: auto;
    cursor: zoom-in;
    transition: all 100ms 0s ease;
    }
    img.zoom {
    width: auto;
    border-radius: 5px;
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translateY(-50%) translateX(-50%);
    z-index: 2;
    cursor: zoom-out;
    }
    img.zoom~span::before {
    content: ' ';
    position: fixed;
    top:0px;
    left:0px;
    z-index: 1;
    background-color: black;
    opacity: 0.5;
    width: 100%;
    height: 100%;
    }
    video {
    max-width: 100%;
    max-height: 100%;
    }
    article {
    color: #777;
    }
    article div {
    padding: 20px;
    }
    article p {
    color: #555;
    font-size: 16px;
    line-height: 1.5;
    }
    aside {
    padding: 0 20px;
    }
    footer {
    display: block;
    text-align: right;
    padding: 5px;
    }
    time a {
    color: #333;
    }
    em {
    font-style: normal;
    }
    p.dropme {
    position: absolute;
    top: 50%;
    width: 100%;
    text-align:center;
    color: #555;
    font-size: 20px;
    }
    </style>
    </head>
    <body>
    <h1>ログ見るだけのやつ</h1>
    <nav><ul>
    </ul></nav>
    <main>
    </main>
    <script type="text/javascript">
    (() => {

    const E = (name, attr = {}, ...children) => {

    const element = Object.assign(document.createElement(name), attr);
    children.forEach(child => element.appendChild(child));
    return element;

    };
    const T = str => (str === null) ? '' : str;

    if (location.host == 'hen.acho.co') {

    document.body.appendChild(E('a', {
    href: location.href,
    download: 'view.htm'
    }, new Text('この HTML ファイルをダウンロードして archive-* フォルダに入れて開いてね。')));

    return;

    }

    const list = outbox => {

    const followers = outbox.orderedItems[0].actor + '/followers';
    const aPublic = 'https://www.w3.org/ns/activitystreams#Public';

    outbox.orderedItems.forEach(toot => {

    const published = new Date(toot.published);
    const month = published.getFullYear() + '_' + (published.getMonth() + 1);
    const privacy = (toot.type == 'Announce') ? '🔃'
    : (toot.to[0] == aPublic && toot.cc[0] == followers) ? '🌎'
    : (toot.to[0] == followers && toot.cc[0] == aPublic) ? '🔓'
    : (toot.to[0] == followers) ? '🔒' : '✉';


    if (typeof(toot.object) == 'string') toot.object = Object.assign(toot, { content: '🔃: ' + toot.object });
    else if (toot.type == 'Announce') toot.object.content = '🔃: ' + toot.object.url + '<br>' + toot.object.content;
    toot.object.date = published.toLocaleString();
    toot.object.privacy = privacy;

    if (!toots[month]) toots[month] = [];
    toots[month].push(toot.object);
    });

    (Object.entries(toots)).forEach(([month, toot]) => nav.appendChild(
    E('li', { onclick: view }, new Text(month))
    ));
    };

    const view = e => {

    const month = event.target.textContent;

    main.textContent = '';
    toots[month].forEach(toot => main.appendChild(E('article', {},
    E('div', { innerHTML: ((typeof(toot.summary) == 'string') ? toot.summary + '<br>' : '') + toot.content }),
    addAttachments(toot.attachment),
    E('footer', {},
    E('time', { datetime: toot.published },
    E('a', { href: toot.url, target: '_blank' }, new Text(T(toot.date)))
    ),
    E('em', {}, new Text(T(toot.privacy)))
    )
    )));

    };

    const addAttachments = attachments => {

    return attachments?.length ? E('aside', {}, ...attachments.map(attachment => {

    const url = '.' + attachment.url;
    switch (attachment.mediaType) {
    case 'image/png':
    case 'image/jpeg':
    return(E('img', { src: url, onclick() { this.className = this.className ? '' : 'zoom'; } }));

    case 'audio/mpeg':
    return(E('audio', { src: url, controls: 'controls' }));

    case 'video/mp4':
    return(E('video', { src: url, controls: 'controls' }));

    default:
    return(E('a', { href: url, target: '_blank' }, new Text(T(url))));
    }

    }), E('span')) : new Text('');

    };

    const toots = {};
    const nav = document.querySelector('nav').firstChild;
    const main = document.querySelector('main');

    fetch('./outbox.json').then(responce => responce.json()).then(outbox => list(outbox)).catch(e => {

    const reader = new FileReader();
    reader.addEventListener('load', e => list(JSON.parse(e.target.result)), false);

    const guard = e => { e.stopPropagation(); e.preventDefault(); };
    main.addEventListener('drop', e => {

    main.textContent = '';
    main.style.height = 'auto';
    reader.readAsText(e.dataTransfer.files[0]);
    e.stopPropagation();
    e.preventDefault();

    }, { once: true });
    main.addEventListener('dragenter', guard, false);
    main.addEventListener('dragover', guard, false);

    main.style.width = '100%';
    main.style.height = Math.trunc(window.innerHeight - main.getBoundingClientRect().top) + 'px';
    main.appendChild(E('p', { className: 'dropme' }, new Text('ここら辺に outbox.json をドラッグアンドドロップしてね')));

    });

    })();
    </script>
    </body>
    </html>