<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
|
<link rel="icon" type="image/png" href="/img/ord/icon-128.png" />
|
|
<meta property="og:title" content="闭社简化版" />
|
|
<meta property="og:description" content="一个提供更简洁界面的闭社web client" />
|
|
<link href="https://cdn.bootcss.com/twitter-bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet">
|
|
<title>闭社简化版</title>
|
|
<style>
|
|
body {
|
|
background: linear-gradient(-45deg, #fff calc(50% - 1px), #d0d0d0 calc(50%), #fff calc(50% + 1px) );
|
|
background-size: 6px 5px;
|
|
font-family: 'Noto Sans SC', sans-serif;
|
|
}
|
|
|
|
body.grey {
|
|
background: #707070;
|
|
background-size: 6px 5px;
|
|
}
|
|
|
|
body,
|
|
pre {
|
|
font-family: 'Noto Sans SC', sans-serif;
|
|
}
|
|
|
|
h1,
|
|
h2,
|
|
h3,
|
|
h4,
|
|
h5,
|
|
h6 {
|
|
font-family: 'Noto Serif SC', serif;
|
|
font-weight: 300;
|
|
}
|
|
|
|
a,
|
|
a:hover,
|
|
.btn-link,
|
|
.btn-link:hover {
|
|
color: inherit;
|
|
text-decoration: underline;
|
|
display: inline-block;
|
|
}
|
|
|
|
.part1 {
|
|
min-width: 300px;
|
|
float: left;
|
|
padding-right: 10px;
|
|
position: relative;
|
|
}
|
|
|
|
.part2 {
|
|
min-width: 200px;
|
|
overflow: hidden;
|
|
padding-left: 25px;
|
|
}
|
|
|
|
.qbox {
|
|
border: 2px black solid;
|
|
background: white;
|
|
padding: 5px;
|
|
color: black;
|
|
margin: 5px 5px 20px;
|
|
}
|
|
|
|
body.grey #statuses-list .qbox {
|
|
background: #b0b0b0;
|
|
}
|
|
|
|
.new .qbox {
|
|
background: black;
|
|
color: white;
|
|
}
|
|
|
|
.new .qbox textarea {
|
|
background: black;
|
|
color: white;
|
|
}
|
|
|
|
.qbox textarea {
|
|
border: none;
|
|
border-bottom: 1px solid;
|
|
border-radius: 0;
|
|
}
|
|
|
|
body.grey #statuses-list .qbox textarea {
|
|
background: #b0b0b0;
|
|
}
|
|
|
|
.qbox .content {
|
|
margin: 15px 5px;
|
|
}
|
|
|
|
.liked, .reblogged {
|
|
font-weight: bold;
|
|
}
|
|
|
|
.super-small {
|
|
font-size: 0.5em;
|
|
}
|
|
|
|
.display_name {
|
|
margin: 0;
|
|
}
|
|
|
|
.behind {
|
|
z-index: 98;
|
|
cursor: pointer;
|
|
transform: translateY(5px) scale(0.98);
|
|
transform-origin: top;
|
|
transition-property: transform;
|
|
transition-duration: 0.5s;
|
|
}
|
|
|
|
.front {
|
|
z-index: 99;
|
|
transition-property: transform;
|
|
transition-duration: 0.5s;
|
|
}
|
|
|
|
.judge {
|
|
position: absolute;
|
|
top: 0;
|
|
right: 0;
|
|
margin: 0 0 30px 20px;
|
|
width: 90%;
|
|
}
|
|
.new {
|
|
position: relative;
|
|
margin: 30px 20px 30px 0;
|
|
}
|
|
|
|
a.hashtag {
|
|
font-weight: bold;
|
|
}
|
|
|
|
.comment-list-wrapper {
|
|
background: #3333;
|
|
padding-left: 3%;
|
|
font-size: 92%;
|
|
}
|
|
|
|
.status-media {
|
|
width: 80%;
|
|
margin: 10px 10%;
|
|
}
|
|
|
|
.emoji {
|
|
width: 22px;
|
|
vertical-align: text-bottom;
|
|
}
|
|
|
|
#statuses-list .invisible {
|
|
font-size: 0;
|
|
line-height: 0;
|
|
display: inline-block;
|
|
width: 0;
|
|
height: 0;
|
|
visibility: visible !important;
|
|
}
|
|
|
|
#statuses-list .ellipsis::after {
|
|
content: "...";
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
<div class="container" style="overflow: hidden;min-height: 100vh">
|
|
<div style='padding:15px'>
|
|
<h1> 闭社简化版 </h1>
|
|
</div>
|
|
|
|
|
|
<div class="part1">
|
|
|
|
<div class="new">
|
|
<form action="" onsubmit="return post_status(event, '')">
|
|
<div class="form-group qbox">
|
|
<textarea class="form-control" name="text" rows="5" maxlength="5000" placeholder="啥?" required="required"></textarea>
|
|
<div class="form-check mt-3 mb-3">
|
|
<input class="form-check-input" type="checkbox" value="" id="post-checkbox-an">
|
|
<label class="form-check-label" for="post-checkbox-an">
|
|
匿名
|
|
</label>
|
|
</div>
|
|
<button type="submit" class="btn btn-link btn-lg">发布</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="part2" id="part2">
|
|
<h1>本站</h1>
|
|
<button class="btn btn-link grey_theme">切换亮度</button>
|
|
<div id="statuses-list">
|
|
</div>
|
|
<span id="loading-span">加载中..</span>
|
|
</div>
|
|
|
|
</div>
|
|
</body>
|
|
|
|
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
|
|
<script src="https://cdn.bootcss.com/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
|
|
<script src="https://cdn.bootcdn.net/ajax/libs/jquery-timeago/1.6.7/jquery.timeago.min.js"></script>
|
|
<script src="https://cdn.bootcdn.net/ajax/libs/jquery-timeago/1.6.7/locales/jquery.timeago.zh-CN.js"></script>
|
|
|
|
<script>
|
|
var token;
|
|
var max_id;
|
|
var loading_statues;
|
|
var base_api_url = "https://thu.closed.social/";
|
|
|
|
jQuery.timeago.settings.allowFuture = true;
|
|
|
|
function get_token() {
|
|
(document.cookie || "").split("; ").forEach( (c) => {
|
|
let cc = c.split("=");
|
|
if (cc.shift() === "mast_token") {
|
|
token = cc.join("=");
|
|
}
|
|
});
|
|
}
|
|
|
|
function get_more_statuses() {
|
|
loading_statues = true;
|
|
$.getJSON(
|
|
`${base_api_url}api/v1/timelines/public?limit=20&local=true` + (
|
|
max_id ? `&max_id=${max_id}` : ''
|
|
),
|
|
function (data) {
|
|
data.forEach((status) => {
|
|
$('#statuses-list').append(make_status_box_html(status, true));
|
|
});
|
|
$('.timeago').timeago();
|
|
if (data.length) {
|
|
max_id = data[data.length - 1].id;
|
|
loading_statues = false;
|
|
}
|
|
}
|
|
).fail((e) => {
|
|
alert(e.responseText);
|
|
});
|
|
}
|
|
|
|
function render_poll(poll) {
|
|
if (!poll)
|
|
return '';
|
|
let show_result = poll.expired || poll.voted;
|
|
return `
|
|
<div class="status-poll-box">
|
|
${poll.options.map((option, idx) => `
|
|
<small>
|
|
${option.title}
|
|
${show_result ? ` - ${option.votes_count} / ${poll.votes_count}` : ''}
|
|
${poll.own_votes.includes(idx) ? ' ✔️ ' : ''}
|
|
</small>
|
|
<div class="progress mb-2">
|
|
<div class="progress-bar progress-bar-striped" role="progressbar"
|
|
style="width: ${show_result ? option.votes_count / poll.votes_count * 100 : 0}%"
|
|
></div>
|
|
</div>
|
|
`).join('\n')}
|
|
<small>${poll.votes_count}人参与,${poll.expired ? '已结束' : `将结束于<time class="timeago" datetime="${poll.expires_at}"></timeago>`}</small>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
function render_media(media_attachments) {
|
|
return media_attachments.map((media) => {
|
|
switch (media.type) {
|
|
case 'image':
|
|
return `<image class="status-media" src=${media.url}>`;
|
|
case 'video':
|
|
return `<video class="status-media" src=${media.url} controls></video>`;
|
|
case 'gifv':
|
|
return `<video class="status-media" src=${media.url} autoplay loop></video>`;
|
|
default:
|
|
return '';
|
|
}
|
|
}).join('\n');
|
|
}
|
|
|
|
function render_content(text, is_mask_bot, emojis) {
|
|
if (is_mask_bot) {
|
|
text = text.replace(/^<p>\[([^\]]*)\]:<br \/>/, '<p>').replace(/匿了<\/p>$/, '</p>');
|
|
}
|
|
emojis.forEach((emoji) => {
|
|
text = text.replaceAll(`:${emoji.shortcode}:`, `<img class="emoji" src="${emoji.url}">`);
|
|
});
|
|
return text;
|
|
}
|
|
|
|
function make_status_box_html(status) {
|
|
return (`
|
|
<div class="qbox" id="status-${status.id.toString()}">
|
|
<img class="avatar" width="24" src="${status.account.avatar}">
|
|
<small>
|
|
${status.account.acct === "mask_bot" ?
|
|
"匿名用户" + /^<p>(\[[^\]]*\]):/.exec(status.content)[1] : (
|
|
status.account.display_name + ' @' +status.account.acct)}
|
|
</small>
|
|
${status.reblog && (status = status.reblog) &&
|
|
`<small> 转发 @${status.account.acct}</small>` || ''}
|
|
<div class="content">
|
|
${render_content(status.content, status.account.acct === "mask_bot", status.emojis)}
|
|
</div>
|
|
${render_poll(status.poll)}
|
|
${render_media(status.media_attachments)}
|
|
<div style="text-align:right;margin: 0px 0 -5px">
|
|
<time class="timeago mr-1 super-small" datetime="${status.created_at}"
|
|
title="${status.created_at}"></time>
|
|
<small class="mr-2 font-italic super-small">${status.application && status.application.name || ''}</small>
|
|
<a href="###" class="mr-3 like-btn ${status.favourited? 'liked' : ''}"
|
|
onclick="like_status(event, '${status.id.toString()}')">
|
|
点赞<span class="num">${status.favourites_count}</span>
|
|
</a>
|
|
<a href="###" class="mr-3 reblog-btn ${status.reblogged? 'reblogged' : ''}"
|
|
onclick="reblog_status(event, '${status.id.toString()}')">
|
|
转发<span class="num">${status.reblogs_count}</span>
|
|
</a>
|
|
<a class="mr-3 reply-btn" href="###"
|
|
onclick="get_comments('${status.id.toString()}')">
|
|
回复${status.replies_count}
|
|
</a>
|
|
</div>
|
|
<div class="collapse comment-list-wrapper" data-sid="${status.id.toString()}">
|
|
<div class="comment-list">
|
|
</div>
|
|
<form action="" onsubmit="return post_status(event, '${status.id}')">
|
|
<div class="form-group qbox">
|
|
<textarea class="form-control" rows="1" maxlength="5000" required="required" >@${status.account.acct} </textarea>
|
|
<div class="form-check mt-1 mr-2 float-right">
|
|
<input class="form-check-input" type="checkbox" value="" id="reply-${status.id}-checkbox-an">
|
|
<label class="form-check-label" for="reply-${status.id}-checkbox-an">
|
|
匿名
|
|
</label>
|
|
</div>
|
|
<button type="submit" class="btn btn-sm btn-link pb-0">添加回复</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
`)
|
|
}
|
|
|
|
function get_comments(sid) {
|
|
let coll = $(`.comment-list-wrapper[data-sid="${sid}"`);
|
|
if (coll.hasClass('show')) {
|
|
coll.collapse('hide');
|
|
} else {
|
|
coll.collapse('show');
|
|
coll.find('> .comment-list').append("加载中..");
|
|
$.getJSON(
|
|
`${base_api_url}api/v1/statuses/${sid}/context`,
|
|
function (data) {
|
|
coll.find('> .comment-list').empty();
|
|
data.descendants.forEach( (rp) => {
|
|
let parent_coll = $(`.comment-list-wrapper[data-sid="${rp.in_reply_to_id}"`);
|
|
parent_coll.collapse('show');
|
|
parent_coll.find('> .comment-list').append(make_status_box_html(rp));
|
|
});
|
|
$('.timeago').timeago();
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
function like_status(e, sid) {
|
|
let target = $(e.target);
|
|
if (!target.hasClass('liked')) {
|
|
$.post(
|
|
`${base_api_url}api/v1/statuses/${sid}/favourite`,
|
|
(status) => {
|
|
target.addClass('liked');
|
|
target.find('.num').text(status.favourites_count)
|
|
}
|
|
);
|
|
} else {
|
|
$.post(
|
|
`${base_api_url}api/v1/statuses/${sid}/unfavourite`,
|
|
(status) => {
|
|
target.removeClass('liked');
|
|
target.find('.num').text(
|
|
target.find('.num').text() - 1
|
|
)
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
function reblog_status(e, sid) {
|
|
let target = $(e.target);
|
|
if (!target.hasClass('reblogged')) {
|
|
$.post(
|
|
`${base_api_url}api/v1/statuses/${sid}/reblog`,
|
|
(status) => {
|
|
target.addClass('reblogged');
|
|
target.find('.num').text(
|
|
target.find('.num').text() - (-1)
|
|
)
|
|
}
|
|
);
|
|
} else {
|
|
$.post(
|
|
`${base_api_url}api/v1/statuses/${sid}/unreblog`,
|
|
(status) => {
|
|
target.removeClass('reblogged');
|
|
target.find('.num').text(
|
|
target.find('.num').text() - 1
|
|
)
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
function post_status(e, sid) {
|
|
e.preventDefault();
|
|
let form = $(e.target);
|
|
let text = form.find('textarea').val();
|
|
if (form.find('input[type=checkbox]').is(':checked')) {
|
|
text += "\n匿了";
|
|
}
|
|
$.post(
|
|
`${base_api_url}api/v1/statuses`,
|
|
{'status': text, 'in_reply_to_id': sid || null, 'visibility': 'public'},
|
|
(status) => {
|
|
form.find('textarea').val('');
|
|
if (sid) {
|
|
form.prev().append(make_status_box_html(status));
|
|
} else {
|
|
$('#statuses-list').prepend(make_status_box_html(status));
|
|
}
|
|
},
|
|
'json'
|
|
).fail((e) => {
|
|
alert(e.responseText);
|
|
});
|
|
|
|
return false;
|
|
}
|
|
|
|
$(document).ready(function(){
|
|
get_token();
|
|
console.log(token);
|
|
if (!token) {
|
|
location.href = `${base_api_url}oauth/authorize?client_id=Wjf6ajif5kl6rIIt_TLu7SAAluGskaQiTXZoIr44jUc&response_type=code&redirect_uri=${encodeURIComponent(location.origin + "/auth")}&scope=read+write&force_login=False`
|
|
} else {
|
|
$.ajaxSetup({
|
|
headers : {
|
|
'Authorization' : 'Bearer ' + token
|
|
}
|
|
});
|
|
get_more_statuses();
|
|
$(window).scroll(() => {
|
|
if($('#loading-span').offset().top < $(window).scrollTop() + $(window).innerHeight() * 1.5 && !loading_statues) {
|
|
get_more_statuses();
|
|
}
|
|
});
|
|
}
|
|
|
|
$('.grey_theme').click((e) => {
|
|
$('body').toggleClass("grey");
|
|
});
|
|
});
|
|
</script>
|
|
|
|
</html>
|