diff --git a/app/css/master.css b/app/css/master.css index d357ab90..c91623f9 100644 --- a/app/css/master.css +++ b/app/css/master.css @@ -21,7 +21,8 @@ html { .action-menu-item:hover { filter: brightness(80%) !important; } -.btn, .btn-flat { +.btn, +.btn-flat { font-size: 1.1rem; margin: 0.4rem; text-transform: none; @@ -340,16 +341,16 @@ blockquote:before, flex-wrap: wrap; flex-direction: column; } -input[type="color"] { +input[type='color'] { -webkit-appearance: none; border: none; width: 32px; height: 32px; } -input[type="color"]::-webkit-color-swatch-wrapper { +input[type='color']::-webkit-color-swatch-wrapper { padding: 0; } -input[type="color"]::-webkit-color-swatch { +input[type='color']::-webkit-color-swatch { border: none; } #menu { @@ -631,6 +632,24 @@ button { } .via-dropdown { text-overflow: ellipsis; - white-space: nowrap; - overflow-x: hidden; -} \ No newline at end of file + white-space: nowrap; + overflow-x: hidden; +} +#re-online { + background-color: rgb(38, 92, 153); + position: fixed; + width: 100vw; + height: 2rem; + padding: 0.25rem; + color: white; + z-index: 1000; +} +#offline { + background-color: rgb(153, 38, 38); + position: fixed; + width: 100vw; + height: 2rem; + padding: 0.25rem; + color: white; + z-index: 999; +} diff --git a/app/css/post.css b/app/css/post.css index 9d46498d..ef434339 100644 --- a/app/css/post.css +++ b/app/css/post.css @@ -64,9 +64,10 @@ textarea { } #emoji { } -#suggest { +#suggest, #draft { max-height: 23rem; overflow-y: scroll; + overflow-x: hidden; } #emoji-list { width: 100%; diff --git a/app/js/common/keyshortcut.js b/app/js/common/keyshortcut.js index 07722f61..6bfee7fe 100644 --- a/app/js/common/keyshortcut.js +++ b/app/js/common/keyshortcut.js @@ -227,7 +227,8 @@ $(function($) { var acct_id = $('#timeline_' + selectedColumn).attr('data-acct') var ats_cm = $('.selectedToot .rep-btn').attr('data-men') var mode = $('.selectedToot .rep-btn').attr('data-visen') - re(id, ats_cm, acct_id, mode) + var cwTxt = $('#cw-text').val() + re(id, ats_cm, acct_id, mode, cwTxt) return false } } diff --git a/app/js/platform/end.js b/app/js/platform/end.js index 4e9eb1a8..32b828a6 100644 --- a/app/js/platform/end.js +++ b/app/js/platform/end.js @@ -219,10 +219,12 @@ if(pwa) { const connection = function (event) { console.log(navigator.onLine, 'network state') if(!navigator.onLine) { - $('#toot-post-btn').addClass('disabled') - } else { - $('#toot-post-btn').removeClass('disabled') + $('#re-online').addClass('hide') + $('#offline').removeClass('hide') + } else if(!$('#offline').hasClass('hide')) { + $('#offline').addClass('hide') + $('#re-online').removeClass('hide') } } window.onoffline = connection -window.ononline = connection \ No newline at end of file +window.ononline = connection diff --git a/app/js/post/emoji.js b/app/js/post/emoji.js index 40a54863..a87f4c39 100644 --- a/app/js/post/emoji.js +++ b/app/js/post/emoji.js @@ -23,6 +23,7 @@ function emojiToggle(reaction) { } $('#post-box').css('width', width + 'px') $('#suggest').html('') + $('#draft').html('') if (!localStorage.getItem('emojis_' + acct_id)) { var html = `` $('#emoji-list').html(html) @@ -31,10 +32,12 @@ function emojiToggle(reaction) { } } else { $('#poll').addClass('hide') + $('#draft').addClass('hide') $('#right-side').hide() $('#right-side').css('width', '300px') $('#emoji').addClass('hide') $('#suggest').html('') + $('#draft').html('') $('#left-side').css('width', '100%') var width = localStorage.getItem('postbox-width') if (width) { diff --git a/app/js/post/post.js b/app/js/post/post.js index f35c8a43..3a3e3aaf 100644 --- a/app/js/post/post.js +++ b/app/js/post/post.js @@ -9,7 +9,16 @@ function sec() { } post(null, mode) } -function post(mode, postvis) { +function post(mode, postvis, dry) { + if(!navigator.onLine && !dry) { + draftToggle(true) + addToDraft() + M.toast({ + html: lang.lang_post_offline, + displayLength: 3000 + }) + return false + } if ($('#toot-post-btn').prop('disabled')) { return false } @@ -122,7 +131,7 @@ function post(mode, postvis) { console.log('This toot will be posted at:' + scheduled) schedule() toot.scheduled_at = scheduled - if($('#sch-box').hasClass('expire')) { + if ($('#sch-box').hasClass('expire')) { toot.scheduled_at = null toot.expires_at = scheduled } @@ -131,7 +140,7 @@ function post(mode, postvis) { } if (!$('#poll').hasClass('hide')) { var options = [] - $('.mastodon-choice').map(function() { + $('.mastodon-choice').map(function () { var choice = $(this).val() if (choice != '') { options.push(choice) @@ -159,6 +168,13 @@ function post(mode, postvis) { } } console.table(toot) + if (dry) { + $('#ideKey').val('') + $('.toot-btn-group').prop('disabled', false) + todc() + toot['TheDeskAcctId'] = acct_id + return toot + } var httpreq = new XMLHttpRequest() httpreq.open('POST', start, true) httpreq.setRequestHeader('Content-Type', 'application/json') @@ -166,11 +182,11 @@ function post(mode, postvis) { httpreq.setRequestHeader('Idempotency-Key', ideKey) httpreq.responseType = 'json' httpreq.send(JSON.stringify(toot)) - httpreq.onreadystatechange = function() { + httpreq.onreadystatechange = function () { if (httpreq.readyState === 4) { var json = httpreq.response if (this.status !== 200) { - if(media && this.status == 422) { + if (media && this.status == 422) { $('#ideKey').val('') $('.toot-btn-group').prop('disabled', false) alertProcessUnfinished() @@ -201,7 +217,7 @@ function post(mode, postvis) { } function expPostMode() { $('#sch-box').toggleClass('expire') - if($('#sch-box').hasClass('expire')) { + if ($('#sch-box').hasClass('expire')) { Swal.fire({ type: 'info', title: 'Expiring toot On' @@ -270,7 +286,7 @@ function misskeyPost() { httpreq.setRequestHeader('Content-Type', 'application/json') httpreq.responseType = 'json' httpreq.send(JSON.stringify(toot)) - httpreq.onreadystatechange = function() { + httpreq.onreadystatechange = function () { if (httpreq.readyState === 4) { if (str.indexOf(localStorage.getItem('stable')) == -1) { localStorage.removeItem('stable') @@ -339,7 +355,7 @@ function clear() { $('#mins_poll').val(6) $('#poll').addClass('hide') $('#pollsta').text(lang.lang_no) - $('.mastodon-choice').map(function() { + $('.mastodon-choice').map(function () { $(this).val('') }) localStorage.removeItem('image') diff --git a/app/js/post/secure.js b/app/js/post/secure.js index 9440344b..9e7351d9 100644 --- a/app/js/post/secure.js +++ b/app/js/post/secure.js @@ -79,8 +79,8 @@ function loadVis() { loadVis() //コンテントワーニング -function cw() { - if ($('#cw').hasClass('cw-avail')) { +function cw(force) { + if ($('#cw').hasClass('cw-avail') || !force) { $('#cw-text').val() $('#cw-text').hide() $('#cw').removeClass('yellow-text') @@ -100,8 +100,8 @@ function cw_show(e) { $(e).parent().parent().find('.cw_hide').toggleClass('cw') $(e).parent().find('.cw_long').toggleClass('hide') } -$(function() { - $('#cw-text').on('change', function(event) { +$(function () { + $('#cw-text').on('change', function (event) { var acct_id = $('#post-acct-sel').val() var domain = localStorage.getItem('domain_' + acct_id) var cwlen = $('#cw-text').val().length @@ -126,3 +126,79 @@ function schedule() { $('#sch-box').addClass('sch-avail') } } + +//下書き機能 +function draftToggle(force) { + if ($('#draft').hasClass('hide') || force) { + $('#draft').removeClass('hide') + $('#right-side').show() + $('#right-side').css('width', '300px') + $('#left-side').css('width', 'calc(100% - 300px)') + var width = localStorage.getItem('postbox-width') + if (width) { + width = width.replace('px', '') * 1 + 300 + } else { + width = 600 + } + $('#post-box').css('width', width + 'px') + $('#suggest').html('') + $('#draft').html('') + draftDraw() + } else { + $('#poll').addClass('hide') + $('#draft').addClass('hide') + $('#right-side').hide() + $('#right-side').css('width', '300px') + $('#emoji').addClass('hide') + $('#suggest').html('') + $('#draft').html('') + $('#left-side').css('width', '100%') + var width = localStorage.getItem('postbox-width') + if (width) { + width = width.replace('px', '') * 1 + } else { + width = 300 + } + $('#post-box').css('width', width + 'px') + } +} +function draftDraw() { + var draft = localStorage.getItem('draft') + var html = `` + if (draft) { + var draftObj = JSON.parse(draft) + for (let i = 0; i < draftObj.length; i++) { + var toot = draftObj[i] + html = html + `
+ reply + cancel + ${escapeHTML(toot.status).replace(/\n/, '').substr(0, 10)} +
` + } + } + $('#draft').html(html) +} +function addToDraft() { + var json = post(null, null, true) + var draft = localStorage.getItem('draft') + var draftObj = [] + if (draft) draftObj = JSON.parse(draft) + draftObj.push(json) + draft = JSON.stringify(draftObj) + localStorage.setItem('draft', draft) + draftDraw() +} +function useThisDraft(i) { + var draft = localStorage.getItem('draft') + var draftObj = JSON.parse(draft) + draftToPost(draftObj[i], draftObj[i]['TheDeskAcctId'], 0) + draftToggle() +} +function deleteThisDraft(i) { + var draft = localStorage.getItem('draft') + var draftObj = JSON.parse(draft) + draftObj.splice(i, 1) + draft = JSON.stringify(draftObj) + localStorage.setItem('draft', draft) + draftDraw() +} \ No newline at end of file diff --git a/app/js/post/status.js b/app/js/post/status.js index 763f12d4..0e96b64b 100644 --- a/app/js/post/status.js +++ b/app/js/post/status.js @@ -15,7 +15,7 @@ function fav(id, acct_id, remote) { httpreq.setRequestHeader('Authorization', 'Bearer ' + at) httpreq.responseType = 'json' httpreq.send() - httpreq.onreadystatechange = function() { + httpreq.onreadystatechange = function () { if (httpreq.readyState === 4) { var json = httpreq.response if (this.status !== 200) { @@ -75,7 +75,7 @@ function rt(id, acct_id, remote, vis) { } else { httpreq.send() } - httpreq.onreadystatechange = function() { + httpreq.onreadystatechange = function () { if (httpreq.readyState === 4) { var json = httpreq.response if (this.status !== 200) { @@ -131,7 +131,7 @@ function bkm(id, acct_id, tlid) { httpreq.setRequestHeader('Authorization', 'Bearer ' + at) httpreq.responseType = 'json' httpreq.send() - httpreq.onreadystatechange = function() { + httpreq.onreadystatechange = function () { if (httpreq.readyState === 4) { var json = httpreq.response if (this.status !== 200) { @@ -160,7 +160,7 @@ function bkm(id, acct_id, tlid) { //フォロー async function follow(acct_id, resolve) { - if($('#his-data').hasClass('locked')) { + if ($('#his-data').hasClass('locked')) { locked = true } else { locked = false @@ -178,7 +178,7 @@ async function follow(acct_id, resolve) { var flag = 'follow' var flagm = 'create' } - + var id = $('#his-data').attr('user-id') if (resolve == 'selector') { var fullacct = $('#his-acct').attr('fullname') @@ -200,7 +200,7 @@ async function follow(acct_id, resolve) { httpreq.setRequestHeader('Authorization', 'Bearer ' + at) httpreq.responseType = 'json' httpreq.send(JSON.stringify(ent)) - httpreq.onreadystatechange = function() { + httpreq.onreadystatechange = function () { if (httpreq.readyState === 4) { var json = httpreq.response if (this.status !== 200) { @@ -212,7 +212,7 @@ async function follow(acct_id, resolve) { $('#his-follow-btn-text').text(lang.lang_status_follow) } else { $('#his-data').addClass('following') - if(locked) { + if (locked) { $('#his-follow-btn-text').text(lang.lang_status_requesting) } else { $('#his-follow-btn-text').text(lang.lang_status_unfollow) @@ -278,7 +278,7 @@ function block(acct_id) { httpreq.setRequestHeader('Authorization', 'Bearer ' + at) httpreq.responseType = 'json' httpreq.send() - httpreq.onreadystatechange = function() { + httpreq.onreadystatechange = function () { if (httpreq.readyState === 4) { if (this.status !== 200) { setLog(start, this.status, this.response) @@ -338,7 +338,7 @@ function muteDo(acct_id) { httpreq.setRequestHeader('Authorization', 'Bearer ' + at) httpreq.responseType = 'json' httpreq.send(rq) - httpreq.onreadystatechange = function() { + httpreq.onreadystatechange = function () { if (httpreq.readyState === 4) { if (this.status !== 200) { setLog(start, this.status, this.response) @@ -378,7 +378,7 @@ function del(id, acct_id) { httpreq.responseType = 'json' httpreq.send() } - httpreq.onreadystatechange = function() { + httpreq.onreadystatechange = function () { if (httpreq.readyState === 4) { if (this.status !== 200) { setLog(start, this.status, this.response) @@ -420,69 +420,73 @@ function redraft(id, acct_id) { httpreq.responseType = 'json' httpreq.send() } - httpreq.onreadystatechange = function() { + httpreq.onreadystatechange = function () { if (httpreq.readyState === 4) { if (this.status !== 200) { setLog(start, this.status, this.response) } var json = httpreq.response - $('#post-acct-sel').prop('disabled', true) - $('#post-acct-sel').val(acct_id) - $('select').formSelect() - mdCheck() - var medias = $('[toot-id=' + id + ']').attr('data-medias') - var mediack = json.media_attachments[0] - //メディアがあれば - var media_ids = [] - if (mediack) { - for (var i = 0; i <= 4; i++) { - if (json.media_attachments[i]) { - media_ids.push(json.media_attachments[i].id) - $('#preview').append( - '' - ) - } else { - break - } - } - } - var vismode = $('[toot-id=' + id + '] .vis-data').attr('data-vis') - vis(vismode) - var medias = media_ids.join(','); - $('#media').val(medias) - localStorage.setItem('nohide', true) - show() - if (json.text) { - var html = json.text - } else { - var html = $('[toot-id=' + id + '] .toot').html() - html = html.replace(/^

(.+)<\/p>$/, '$1') - html = html.replace(//, '\n') - html = html.replace(/

/, '\n') - html = html.replace(/<\/p>/, '\n') - html = html.replace(//g, '$1') - html = $.strip_tags(html) - } - $('#textarea').val(html) - if (json.spoiler_text) { - cw() - $('#cw-text').val(json.spoiler_text) - } - if (json.sensitive) { - $('#nsfw').addClass('yellow-text') - $('#nsfw').html('visibility') - $('#nsfw').addClass('nsfw-avail') - } - if (json.in_reply_to_id) { - $('#reply').val(json.in_reply_to_id) - } + draftToPost(json, acct_id, id) } } } }) } +function draftToPost(json, acct_id, id) { + $('#post-acct-sel').prop('disabled', true) + $('#post-acct-sel').val(acct_id) + $('select').formSelect() + mdCheck() + var medias = $('[toot-id=' + id + ']').attr('data-medias') + mediack = null + if(json.media_attachments) mediack = json.media_attachments[0] + //メディアがあれば + var media_ids = [] + if (mediack) { + for (var i = 0; i <= 4; i++) { + if (json.media_attachments[i]) { + media_ids.push(json.media_attachments[i].id) + $('#preview').append( + '' + ) + } else { + break + } + } + } + var vismode = json.visibility + vis(vismode) + var medias = media_ids.join(',') + $('#media').val(medias) + localStorage.setItem('nohide', true) + show() + if (json.text) { + var html = json.text + } else { + var html = json.status + html = html.replace(/^

(.+)<\/p>$/, '$1') + html = html.replace(//, '\n') + html = html.replace(/

/, '\n') + html = html.replace(/<\/p>/, '\n') + html = html.replace(//g, '$1') + html = $.strip_tags(html) + } + $('#textarea').val(html) + if (json.spoiler_text) { + cw(true) + $('#cw-text').val(json.spoiler_text) + } + if (json.sensitive) { + $('#nsfw').addClass('yellow-text') + $('#nsfw').html('visibility') + $('#nsfw').addClass('nsfw-avail') + } + if (json.in_reply_to_id) { + $('#reply').val(json.in_reply_to_id) + } +} //ピン留め function pin(id, acct_id) { if ($(`.cvo[unique-id=${id}]`).hasClass('pined')) { @@ -499,7 +503,7 @@ function pin(id, acct_id) { httpreq.setRequestHeader('Authorization', 'Bearer ' + at) httpreq.responseType = 'json' httpreq.send() - httpreq.onreadystatechange = function() { + httpreq.onreadystatechange = function () { if (httpreq.readyState === 4) { var json = httpreq.response if (this.status !== 200) { @@ -530,7 +534,7 @@ function request(id, flag, acct_id) { httpreq.setRequestHeader('Authorization', 'Bearer ' + at) httpreq.responseType = 'json' httpreq.send() - httpreq.onreadystatechange = function() { + httpreq.onreadystatechange = function () { if (httpreq.readyState === 4) { var json = httpreq.response if (this.status !== 200) { @@ -556,7 +560,7 @@ function domainblock(add, flag, acct_id) { httpreq.setRequestHeader('Authorization', 'Bearer ' + at) httpreq.responseType = 'json' httpreq.send() - httpreq.onreadystatechange = function() { + httpreq.onreadystatechange = function () { if (httpreq.readyState === 4) { var json = httpreq.response if (this.status !== 200) { @@ -583,7 +587,7 @@ function empUser() { M.toast({ html: id + lang.lang_status_emphas, displayLength: 4000 }) } else { var can - Object.keys(obj).forEach(function(key) { + Object.keys(obj).forEach(function (key) { var usT = obj[key] if (usT != id && !can) { can = false @@ -615,7 +619,7 @@ function pinUser() { httpreq.setRequestHeader('Authorization', 'Bearer ' + at) httpreq.responseType = 'json' httpreq.send() - httpreq.onreadystatechange = function() { + httpreq.onreadystatechange = function () { if (httpreq.readyState === 4) { var json = httpreq.response if (this.status !== 200) { @@ -651,20 +655,20 @@ function staEx(mode) { Authorization: 'Bearer ' + at } }) - .then(function(response) { + .then(function (response) { if (!response.ok) { - response.text().then(function(text) { + response.text().then(function (text) { setLog(response.url, response.status, text) }) } return response.json() }) - .catch(function(error) { + .catch(function (error) { todo(error) setLog(start, 'JSON', error) console.error(error) }) - .then(function(json) { + .then(function (json) { if (json.statuses) { if (json.statuses[0]) { var id = json.statuses[0].id diff --git a/app/js/post/suggest.js b/app/js/post/suggest.js index 42838b52..26626531 100644 --- a/app/js/post/suggest.js +++ b/app/js/post/suggest.js @@ -18,7 +18,7 @@ input.addEventListener( var new_val = input.value if (new_val == '') { $('#suggest').html('') - if ($('#poll').hasClass('hide') && $('#emoji').hasClass('hide')) { + if ($('#poll').hasClass('hide') && $('#emoji').hasClass('hide') && $('#draft').hasClass('hide')) { $('#right-side').hide() $('#right-side').css('width', '300px') $('#left-side').css('width', '100%') @@ -41,7 +41,7 @@ input.addEventListener( var q = acct[1] } else { $('#suggest').html('') - if ($('#poll').hasClass('hide') && $('#emoji').hasClass('hide')) { + if ($('#poll').hasClass('hide') && $('#emoji').hasClass('hide') && $('#draft').hasClass('hide')) { $('#right-side').hide() $('#right-side').css('width', '300px') $('#left-side').css('width', '100%') @@ -138,6 +138,7 @@ input.addEventListener( $('#post-box').css('width', width + 'px') $('#poll').addClass('hide') $('#emoji').addClass('hide') + $('#draft').addClass('hide') } } else if (json.accounts[0] && acct[1]) { var accts = '' @@ -165,8 +166,9 @@ input.addEventListener( $('#suggest').html(accts) $('#poll').addClass('hide') $('#emoji').addClass('hide') + $('#draft').addClass('hide') } else { - if ($('#poll').hasClass('hide') && $('#emoji').hasClass('hide')) { + if ($('#poll').hasClass('hide') && $('#emoji').hasClass('hide') && $('#draft').hasClass('hide')) { $('#right-side').hide() $('#right-side').css('width', '300px') $('#left-side').css('width', '100%') @@ -226,7 +228,7 @@ function tagInsert(code, del) { } sentence = before + word + after textarea.value = sentence - if ($('#poll').hasClass('hide') && $('#emoji').hasClass('hide')) { + if ($('#poll').hasClass('hide') && $('#emoji').hasClass('hide') && $('#draft').hasClass('hide')) { $('#right-side').hide() $('#right-side').css('width', '300px') $('#left-side').css('width', '50%') diff --git a/app/js/post/use-txtbox.js b/app/js/post/use-txtbox.js index 9e272df2..e7a347c2 100644 --- a/app/js/post/use-txtbox.js +++ b/app/js/post/use-txtbox.js @@ -1,5 +1,5 @@ /*リプライ*/ -function re(id, ats_cm, acct_id, mode) { +function re(id, ats_cm, acct_id, mode, cwTxt) { clear() var ats = ats_cm.split(',') localStorage.setItem('nohide', true) @@ -25,13 +25,18 @@ function re(id, ats_cm, acct_id, mode) { } $('#acct-sel-prof').attr('src', profimg) vis(mode) + if(localStorage.getItem('cw-continue') == 'yes') { + cw(true) + $('#cw-text').val(cwTxt) + } } function reEx(id) { $('#tootmodal').modal('close') var at = $('#tootmodal').attr('data-user') var acct_id = $('#status-acct-sel').val() var mode = $('#tootmodal .vis-data').attr('data-vis') - re(id, at, acct_id, mode) + var cwTxt = $('#cw-text').val() + re(id, at, acct_id, mode, cwTxt) } //引用 function qt(id, acct_id, at, url) { diff --git a/app/js/tl/parse.js b/app/js/tl/parse.js index 6afcca0d..98befa14 100644 --- a/app/js/tl/parse.js +++ b/app/js/tl/parse.js @@ -1085,7 +1085,7 @@ function parse(obj, mix, acct_id, tlid, popup, mutefilter, type) {

- diff --git a/app/js/tl/poll.js b/app/js/tl/poll.js index 212fe844..2dd887c8 100644 --- a/app/js/tl/poll.js +++ b/app/js/tl/poll.js @@ -25,6 +25,7 @@ function pollToggle() { } $('#post-box').css('width', width + 'px') $('#emoji').addClass('hide') + $('#draft').addClass('hide') $('#poll').addClass('hide') $('#pollsta').text(lang.lang_no) } diff --git a/app/package.json b/app/package.json index 1ba54928..458c554e 100644 --- a/app/package.json +++ b/app/package.json @@ -1,6 +1,6 @@ { "name": "thedesk", - "version": "21.2.4", + "version": "21.3.0", "codename": "Mayu", "description": "TheDesk is a Mastodon client for PC.", "repository": "https://github.com/cutls/TheDesk", @@ -68,7 +68,7 @@ "lodash": "^4.17.20", "materialize-css": "git://github.com/cutls/materialize#v1-dev", "sumchecker": "^3.0.1", - "sweetalert2": "^10.3.5", + "sweetalert2": "^10.10.0", "system-font-families": "^0.4.1", "vue": "^2.6.12" }, @@ -77,10 +77,10 @@ }, "devDependencies": { "chokidar": "^3.4.2", - "electron": "^10.1.2", + "electron": "^10.1.5", "electron-builder": "^22.8.1", "electron-rebuild": "^2.3.2", - "eslint": "^7.9.0", + "eslint": "^7.13.0", "readline-sync": "1.4.10" }, "build": { diff --git a/app/view/make/index.sample.html b/app/view/make/index.sample.html index 20b535ab..fd4d0bbf 100644 --- a/app/view/make/index.sample.html +++ b/app/view/make/index.sample.html @@ -43,6 +43,12 @@ chat
+
+ @@nowOffline@@ +
+
+ @@reOnline@@ +
@@ -278,6 +284,9 @@
  • @@poll@@
  • +
  • + @@draft@@ +
  • @@ -297,6 +306,7 @@
    +
    @@emojiWarn@@ @@ -765,7 +775,7 @@ HP
    GitHub

    -