From b32573138b7607b8d9070100fb792f0241a4ba80 Mon Sep 17 00:00:00 2001 From: Hakaba Hitoyo Date: Sun, 11 Feb 2018 23:12:05 +0900 Subject: [PATCH 01/52] Add who-to-follow-panel --- src/App.js | 7 +- src/App.vue | 1 + .../who_to_follow_panel.js | 179 ++++++++++++++++++ .../who_to_follow_panel.vue | 37 ++++ src/main.js | 3 +- static/config.json | 1 + 6 files changed, 225 insertions(+), 3 deletions(-) create mode 100644 src/components/who_to_follow_panel/who_to_follow_panel.js create mode 100644 src/components/who_to_follow_panel/who_to_follow_panel.vue diff --git a/src/App.js b/src/App.js index e924896727..a052e058ea 100644 --- a/src/App.js +++ b/src/App.js @@ -2,6 +2,7 @@ import UserPanel from './components/user_panel/user_panel.vue' import NavPanel from './components/nav_panel/nav_panel.vue' import Notifications from './components/notifications/notifications.vue' import UserFinder from './components/user_finder/user_finder.vue' +import WhoToFollowPanel from './components/who_to_follow_panel/who_to_follow_panel.vue' import InstanceSpecificPanel from './components/instance_specific_panel/instance_specific_panel.vue' import ChatPanel from './components/chat_panel/chat_panel.vue' @@ -12,8 +13,9 @@ export default { NavPanel, Notifications, UserFinder, - ChatPanel, - InstanceSpecificPanel + WhoToFollowPanel, + InstanceSpecificPanel, + ChatPanel }, data: () => ({ mobileActivePanel: 'timeline' @@ -27,6 +29,7 @@ export default { style () { return { 'background-image': `url(${this.background})` } }, sitename () { return this.$store.state.config.name }, chat () { return this.$store.state.chat.channel.state === 'joined' }, + showWhoToFollowPanel () { return this.$store.state.config.showWhoToFollowPanel }, showInstanceSpecificPanel () { return this.$store.state.config.showInstanceSpecificPanel } }, methods: { diff --git a/src/App.vue b/src/App.vue index 2a910bc06b..1d8dd6c8f1 100644 --- a/src/App.vue +++ b/src/App.vue @@ -24,6 +24,7 @@ + diff --git a/src/components/who_to_follow_panel/who_to_follow_panel.js b/src/components/who_to_follow_panel/who_to_follow_panel.js new file mode 100644 index 0000000000..49653c8190 --- /dev/null +++ b/src/components/who_to_follow_panel/who_to_follow_panel.js @@ -0,0 +1,179 @@ +const WhoToFollowPanel = { + data: () => ({ + img1: '/images/avi.png', + link1: null, + name1: '', + img2: '/images/avi.png', + link2: null, + name2: '', + img3: '/images/avi.png', + link3: null, + name3: '' + }), + computed: { + user: function () { + return this.$store.state.users.currentUser.screen_name + }, + moreUrl: function () { + var host = window.location.hostname + var user = this.user + var url = 'https://vinayaka.distsn.org/?' + + encodeURIComponent(host) + '+' + encodeURIComponent(user) + return url + }, + showWhoToFollowPanel () { + return this.$store.state.config.showWhoToFollowPanel + } + }, + watch: { + user: function (user, oldUser) { + function showUsers (panel, users, aHost, aUser) { + var cn + var index = 0 + var random = Math.floor(Math.random() * 10) + for (cn = random; cn < users.length; cn = cn + 10) { + var user + user = users[cn] + var host + host = user.host + var username + if (user.username) { + username = user.username + } else { + username = user.user + } + var img + if (user.avatar) { + img = user.avatar + } else { + img = '/images/avi.png' + } + var link = 'https://' + host + '/users/' + username + var name = username + '@' + host + if ((!user.following) && + (!user.blacklisted) && + (!(host === aHost && username === aUser))) { + if (index === 0) { + panel.img1 = img + panel.link1 = link + panel.name1 = name + } else if (index === 1) { + panel.img2 = img + panel.link2 = link + panel.name2 = name + } else if (index === 2) { + panel.img3 = img + panel.link3 = link + panel.name3 = name + } + index = index + 1 + if (index > 2) { + break + } + } + } + } + function getUsers (panel) { + var user = panel.$store.state.users.currentUser.screen_name + if (user) { + panel.name1 = 'Loading...' + panel.name2 = 'Loading...' + panel.name3 = 'Loading...' + var host = window.location.hostname + var url = 'https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-simple-api.cgi?' + + encodeURIComponent(host) + '+' + encodeURIComponent(user) + window.fetch(url, {mode: 'cors'}).then(function (response) { + if (response.ok) { + return response.json() + } else { + panel.name1 = '' + panel.name2 = '' + panel.name3 = '' + } + }).then(function (users) { + showUsers(panel, users, host, user) + }) + } + } + if (this.showWhoToFollowPanel) { + getUsers(this) + } + } + }, + mounted: + function () { + function showUsers (panel, users, aHost, aUser) { + var cn + var index = 0 + var random = Math.floor(Math.random() * 10) + for (cn = random; cn < users.length; cn = cn + 10) { + var user + user = users[cn] + var host + host = user.host + var username + if (user.username) { + username = user.username + } else { + username = user.user + } + var img + if (user.avatar) { + img = user.avatar + } else { + img = '/images/avi.png' + } + var link = 'https://' + host + '/users/' + username + var name = username + '@' + host + if ((!user.following) && + (!user.blacklisted) && + (!(host === aHost && username === aUser))) { + if (index === 0) { + panel.img1 = img + panel.link1 = link + panel.name1 = name + } else if (index === 1) { + panel.img2 = img + panel.link2 = link + panel.name2 = name + } else if (index === 2) { + panel.img3 = img + panel.link3 = link + panel.name3 = name + } + index = index + 1 + if (index > 2) { + break + } + } + } + } + function getUsers (panel) { + var user = panel.user + if (user) { + panel.name1 = 'Loading...' + panel.name2 = 'Loading...' + panel.name3 = 'Loading...' + var host = window.location.hostname + var url = 'https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-simple-api.cgi?' + + encodeURIComponent(host) + '+' + encodeURIComponent(user) + window.fetch(url, {mode: 'cors'}).then(function (response) { + if (response.ok) { + return response.json() + } else { + panel.name1 = '' + panel.name2 = '' + panel.name3 = '' + } + }).then(function (users) { + showUsers(panel, users, host, user) + }) + } + } + if (this.showWhoToFollowPanel) { + getUsers(this) + } + } +} + +export default WhoToFollowPanel diff --git a/src/components/who_to_follow_panel/who_to_follow_panel.vue b/src/components/who_to_follow_panel/who_to_follow_panel.vue new file mode 100644 index 0000000000..fff966abca --- /dev/null +++ b/src/components/who_to_follow_panel/who_to_follow_panel.vue @@ -0,0 +1,37 @@ + + + + + diff --git a/src/main.js b/src/main.js index 6f8c00f04f..5c74da3af6 100644 --- a/src/main.js +++ b/src/main.js @@ -88,10 +88,11 @@ window.fetch('/api/statusnet/config.json') window.fetch('/static/config.json') .then((res) => res.json()) .then((data) => { - const {theme, background, logo, showInstanceSpecificPanel} = data + const {theme, background, logo, showWhoToFollowPanel, showInstanceSpecificPanel} = data store.dispatch('setOption', { name: 'theme', value: theme }) store.dispatch('setOption', { name: 'background', value: background }) store.dispatch('setOption', { name: 'logo', value: logo }) + store.dispatch('setOption', { name: 'showWhoToFollowPanel', value: showWhoToFollowPanel }) store.dispatch('setOption', { name: 'showInstanceSpecificPanel', value: showInstanceSpecificPanel }) if (data['chatDisabled']) { store.dispatch('disableChat') diff --git a/static/config.json b/static/config.json index 6c9c27dab2..23fdf8a8f9 100644 --- a/static/config.json +++ b/static/config.json @@ -4,5 +4,6 @@ "logo": "/static/logo.png", "defaultPath": "/main/all", "chatDisabled": false, + "showWhoToFollowPanel": false, "showInstanceSpecificPanel": false } From 96426425b8a20a1ff270e2b1f289528aa8e4dc8f Mon Sep 17 00:00:00 2001 From: Hakaba Hitoyo Date: Wed, 28 Mar 2018 15:57:11 +0900 Subject: [PATCH 02/52] refactoring --- .../who_to_follow_panel.js | 210 ++++++------------ 1 file changed, 72 insertions(+), 138 deletions(-) diff --git a/src/components/who_to_follow_panel/who_to_follow_panel.js b/src/components/who_to_follow_panel/who_to_follow_panel.js index 49653c8190..e3f06ab676 100644 --- a/src/components/who_to_follow_panel/who_to_follow_panel.js +++ b/src/components/who_to_follow_panel/who_to_follow_panel.js @@ -1,3 +1,73 @@ +function showWhoToFollow (panel, users, aHost, aUser) { + var cn + var index = 0 + var random = Math.floor(Math.random() * 10) + for (cn = random; cn < users.length; cn = cn + 10) { + var user + user = users[cn] + var host + host = user.host + var username + if (user.username) { + username = user.username + } else { + username = user.user + } + var img + if (user.avatar) { + img = user.avatar + } else { + img = '/images/avi.png' + } + var link = 'https://' + host + '/users/' + username + var name = username + '@' + host + if ((!user.following) && + (!user.blacklisted) && + (!(host === aHost && username === aUser))) { + if (index === 0) { + panel.img1 = img + panel.link1 = link + panel.name1 = name + } else if (index === 1) { + panel.img2 = img + panel.link2 = link + panel.name2 = name + } else if (index === 2) { + panel.img3 = img + panel.link3 = link + panel.name3 = name + } + index = index + 1 + if (index > 2) { + break + } + } + } +} + +function getWhoToFollow (panel) { + var user = panel.$store.state.users.currentUser.screen_name + if (user) { + panel.name1 = 'Loading...' + panel.name2 = 'Loading...' + panel.name3 = 'Loading...' + var host = window.location.hostname + var url = 'https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-simple-api.cgi?' + + encodeURIComponent(host) + '+' + encodeURIComponent(user) + window.fetch(url, {mode: 'cors'}).then(function (response) { + if (response.ok) { + return response.json() + } else { + panel.name1 = '' + panel.name2 = '' + panel.name3 = '' + } + }).then(function (users) { + showWhoToFollow(panel, users, host, user) + }) + } +} + const WhoToFollowPanel = { data: () => ({ img1: '/images/avi.png', @@ -27,151 +97,15 @@ const WhoToFollowPanel = { }, watch: { user: function (user, oldUser) { - function showUsers (panel, users, aHost, aUser) { - var cn - var index = 0 - var random = Math.floor(Math.random() * 10) - for (cn = random; cn < users.length; cn = cn + 10) { - var user - user = users[cn] - var host - host = user.host - var username - if (user.username) { - username = user.username - } else { - username = user.user - } - var img - if (user.avatar) { - img = user.avatar - } else { - img = '/images/avi.png' - } - var link = 'https://' + host + '/users/' + username - var name = username + '@' + host - if ((!user.following) && - (!user.blacklisted) && - (!(host === aHost && username === aUser))) { - if (index === 0) { - panel.img1 = img - panel.link1 = link - panel.name1 = name - } else if (index === 1) { - panel.img2 = img - panel.link2 = link - panel.name2 = name - } else if (index === 2) { - panel.img3 = img - panel.link3 = link - panel.name3 = name - } - index = index + 1 - if (index > 2) { - break - } - } - } - } - function getUsers (panel) { - var user = panel.$store.state.users.currentUser.screen_name - if (user) { - panel.name1 = 'Loading...' - panel.name2 = 'Loading...' - panel.name3 = 'Loading...' - var host = window.location.hostname - var url = 'https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-simple-api.cgi?' + - encodeURIComponent(host) + '+' + encodeURIComponent(user) - window.fetch(url, {mode: 'cors'}).then(function (response) { - if (response.ok) { - return response.json() - } else { - panel.name1 = '' - panel.name2 = '' - panel.name3 = '' - } - }).then(function (users) { - showUsers(panel, users, host, user) - }) - } - } if (this.showWhoToFollowPanel) { - getUsers(this) + getWhoToFollow(this) } } }, mounted: function () { - function showUsers (panel, users, aHost, aUser) { - var cn - var index = 0 - var random = Math.floor(Math.random() * 10) - for (cn = random; cn < users.length; cn = cn + 10) { - var user - user = users[cn] - var host - host = user.host - var username - if (user.username) { - username = user.username - } else { - username = user.user - } - var img - if (user.avatar) { - img = user.avatar - } else { - img = '/images/avi.png' - } - var link = 'https://' + host + '/users/' + username - var name = username + '@' + host - if ((!user.following) && - (!user.blacklisted) && - (!(host === aHost && username === aUser))) { - if (index === 0) { - panel.img1 = img - panel.link1 = link - panel.name1 = name - } else if (index === 1) { - panel.img2 = img - panel.link2 = link - panel.name2 = name - } else if (index === 2) { - panel.img3 = img - panel.link3 = link - panel.name3 = name - } - index = index + 1 - if (index > 2) { - break - } - } - } - } - function getUsers (panel) { - var user = panel.user - if (user) { - panel.name1 = 'Loading...' - panel.name2 = 'Loading...' - panel.name3 = 'Loading...' - var host = window.location.hostname - var url = 'https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-simple-api.cgi?' + - encodeURIComponent(host) + '+' + encodeURIComponent(user) - window.fetch(url, {mode: 'cors'}).then(function (response) { - if (response.ok) { - return response.json() - } else { - panel.name1 = '' - panel.name2 = '' - panel.name3 = '' - } - }).then(function (users) { - showUsers(panel, users, host, user) - }) - } - } if (this.showWhoToFollowPanel) { - getUsers(this) + getWhoToFollow(this) } } } From caad81800963730f9d3ef1325bf5f55dd29fde9a Mon Sep 17 00:00:00 2001 From: Hakaba Hitoyo Date: Wed, 28 Mar 2018 16:56:47 +0900 Subject: [PATCH 03/52] using internal link to users --- .../who_to_follow_panel.js | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/components/who_to_follow_panel/who_to_follow_panel.js b/src/components/who_to_follow_panel/who_to_follow_panel.js index e3f06ab676..2d376ef964 100644 --- a/src/components/who_to_follow_panel/who_to_follow_panel.js +++ b/src/components/who_to_follow_panel/who_to_follow_panel.js @@ -28,14 +28,35 @@ function showWhoToFollow (panel, users, aHost, aUser) { panel.img1 = img panel.link1 = link panel.name1 = name + this.$store.state.api.backendInteractor.externalProfile(name) + .then((externalUser) => { + if (!externalUser.error) { + this.$store.commit('addNewUsers', [externalUser]) + panel.link1 = 'https://' + host + '/users/' + externalUser.id + } + }) } else if (index === 1) { panel.img2 = img panel.link2 = link panel.name2 = name + this.$store.state.api.backendInteractor.externalProfile(name) + .then((externalUser) => { + if (!externalUser.error) { + this.$store.commit('addNewUsers', [externalUser]) + panel.link2 = 'https://' + host + '/users/' + externalUser.id + } + }) } else if (index === 2) { panel.img3 = img panel.link3 = link panel.name3 = name + this.$store.state.api.backendInteractor.externalProfile(name) + .then((externalUser) => { + if (!externalUser.error) { + this.$store.commit('addNewUsers', [externalUser]) + panel.link3 = 'https://' + host + '/users/' + externalUser.id + } + }) } index = index + 1 if (index > 2) { From 5a97cfb9599fb33b15f878869b940444234e3534 Mon Sep 17 00:00:00 2001 From: hakabahitoyo Date: Wed, 28 Mar 2018 17:45:35 +0900 Subject: [PATCH 04/52] who-to-follow-panel using internal user link --- .../who_to_follow_panel.js | 34 ++++++++----------- .../who_to_follow_panel.vue | 6 ++-- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/components/who_to_follow_panel/who_to_follow_panel.js b/src/components/who_to_follow_panel/who_to_follow_panel.js index 2d376ef964..43cd3e2d6b 100644 --- a/src/components/who_to_follow_panel/who_to_follow_panel.js +++ b/src/components/who_to_follow_panel/who_to_follow_panel.js @@ -19,44 +19,40 @@ function showWhoToFollow (panel, users, aHost, aUser) { } else { img = '/images/avi.png' } - var link = 'https://' + host + '/users/' + username var name = username + '@' + host if ((!user.following) && (!user.blacklisted) && (!(host === aHost && username === aUser))) { if (index === 0) { panel.img1 = img - panel.link1 = link panel.name1 = name - this.$store.state.api.backendInteractor.externalProfile(name) + panel.$store.state.api.backendInteractor.externalProfile(name) .then((externalUser) => { if (!externalUser.error) { - this.$store.commit('addNewUsers', [externalUser]) - panel.link1 = 'https://' + host + '/users/' + externalUser.id - } - }) + panel.$store.commit('addNewUsers', [externalUser]) + panel.link1 = '/users/' + externalUser.id + } + }) } else if (index === 1) { panel.img2 = img - panel.link2 = link panel.name2 = name - this.$store.state.api.backendInteractor.externalProfile(name) + panel.$store.state.api.backendInteractor.externalProfile(name) .then((externalUser) => { if (!externalUser.error) { - this.$store.commit('addNewUsers', [externalUser]) - panel.link2 = 'https://' + host + '/users/' + externalUser.id - } - }) + panel.$store.commit('addNewUsers', [externalUser]) + panel.link2 = '/users/' + externalUser.id + } + }) } else if (index === 2) { panel.img3 = img - panel.link3 = link panel.name3 = name - this.$store.state.api.backendInteractor.externalProfile(name) + panel.$store.state.api.backendInteractor.externalProfile(name) .then((externalUser) => { if (!externalUser.error) { - this.$store.commit('addNewUsers', [externalUser]) - panel.link3 = 'https://' + host + '/users/' + externalUser.id - } - }) + panel.$store.commit('addNewUsers', [externalUser]) + panel.link3 = '/users/' + externalUser.id + } + }) } index = index + 1 if (index > 2) { diff --git a/src/components/who_to_follow_panel/who_to_follow_panel.vue b/src/components/who_to_follow_panel/who_to_follow_panel.vue index fff966abca..56adbf416b 100644 --- a/src/components/who_to_follow_panel/who_to_follow_panel.vue +++ b/src/components/who_to_follow_panel/who_to_follow_panel.vue @@ -8,9 +8,9 @@ From ef67bd693e9ee0cb42b4ebd0b10f68e63ba04750 Mon Sep 17 00:00:00 2001 From: hakabahitoyo Date: Wed, 28 Mar 2018 18:18:36 +0900 Subject: [PATCH 05/52] using router-link in who-to-follow-panel --- .../who_to_follow_panel/who_to_follow_panel.js | 14 +++++++------- .../who_to_follow_panel/who_to_follow_panel.vue | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/components/who_to_follow_panel/who_to_follow_panel.js b/src/components/who_to_follow_panel/who_to_follow_panel.js index 43cd3e2d6b..47952d212f 100644 --- a/src/components/who_to_follow_panel/who_to_follow_panel.js +++ b/src/components/who_to_follow_panel/who_to_follow_panel.js @@ -30,7 +30,7 @@ function showWhoToFollow (panel, users, aHost, aUser) { .then((externalUser) => { if (!externalUser.error) { panel.$store.commit('addNewUsers', [externalUser]) - panel.link1 = '/users/' + externalUser.id + panel.id1 = externalUser.id } }) } else if (index === 1) { @@ -40,7 +40,7 @@ function showWhoToFollow (panel, users, aHost, aUser) { .then((externalUser) => { if (!externalUser.error) { panel.$store.commit('addNewUsers', [externalUser]) - panel.link2 = '/users/' + externalUser.id + panel.id2 = externalUser.id } }) } else if (index === 2) { @@ -50,7 +50,7 @@ function showWhoToFollow (panel, users, aHost, aUser) { .then((externalUser) => { if (!externalUser.error) { panel.$store.commit('addNewUsers', [externalUser]) - panel.link3 = '/users/' + externalUser.id + panel.id3 = externalUser.id } }) } @@ -88,14 +88,14 @@ function getWhoToFollow (panel) { const WhoToFollowPanel = { data: () => ({ img1: '/images/avi.png', - link1: null, name1: '', + id1: 0, img2: '/images/avi.png', - link2: null, name2: '', + id2: 0, img3: '/images/avi.png', - link3: null, - name3: '' + name3: '', + id3: 0 }), computed: { user: function () { diff --git a/src/components/who_to_follow_panel/who_to_follow_panel.vue b/src/components/who_to_follow_panel/who_to_follow_panel.vue index 56adbf416b..021b95576f 100644 --- a/src/components/who_to_follow_panel/who_to_follow_panel.vue +++ b/src/components/who_to_follow_panel/who_to_follow_panel.vue @@ -8,9 +8,9 @@

- {{ name1 }}
- {{ name2 }}
- {{ name3 }}
+ {{ name1 }}
+ {{ name2 }}
+ {{ name3 }}
More

From 2ade177d5a8f487014f8e790d2ed1c0f9e8ebb75 Mon Sep 17 00:00:00 2001 From: Hakaba Hitoyo Date: Sat, 5 May 2018 00:20:19 +0900 Subject: [PATCH 06/52] configurable who to follow panel --- .../who_to_follow_panel/who_to_follow_panel.js | 12 ++++++++---- src/main.js | 4 +++- static/config.json | 6 ++++++ 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/components/who_to_follow_panel/who_to_follow_panel.js b/src/components/who_to_follow_panel/who_to_follow_panel.js index 47952d212f..d62a1515a4 100644 --- a/src/components/who_to_follow_panel/who_to_follow_panel.js +++ b/src/components/who_to_follow_panel/who_to_follow_panel.js @@ -69,8 +69,10 @@ function getWhoToFollow (panel) { panel.name2 = 'Loading...' panel.name3 = 'Loading...' var host = window.location.hostname - var url = 'https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-simple-api.cgi?' + - encodeURIComponent(host) + '+' + encodeURIComponent(user) + var whoToFollowProvider = this.$store.state.config.whoToFollowProvider + var url + url = whoToFollowProvider.replace(/{{host}}/g, encodeURIComponent(host)) + url = url.replace(/{{user}}/g, encodeURIComponent(user)) window.fetch(url, {mode: 'cors'}).then(function (response) { if (response.ok) { return response.json() @@ -104,8 +106,10 @@ const WhoToFollowPanel = { moreUrl: function () { var host = window.location.hostname var user = this.user - var url = 'https://vinayaka.distsn.org/?' + - encodeURIComponent(host) + '+' + encodeURIComponent(user) + var whoToFollowLink = this.$store.state.config.whoToFollowLink + var url + url = whoToFollowLink.replace(/{{host}}/g, encodeURIComponent(host)) + url = url.replace(/{{user}}/g, encodeURIComponent(user)) return url }, showWhoToFollowPanel () { diff --git a/src/main.js b/src/main.js index a40c51f2fc..3c4a072be9 100644 --- a/src/main.js +++ b/src/main.js @@ -88,11 +88,13 @@ window.fetch('/api/statusnet/config.json') window.fetch('/static/config.json') .then((res) => res.json()) .then((data) => { - const {theme, background, logo, showWhoToFollowPanel, showInstanceSpecificPanel} = data + const {theme, background, logo, showWhoToFollowPanel, whoToFollowProvider, whoToFollowLink, showInstanceSpecificPanel} = data store.dispatch('setOption', { name: 'theme', value: theme }) store.dispatch('setOption', { name: 'background', value: background }) store.dispatch('setOption', { name: 'logo', value: logo }) store.dispatch('setOption', { name: 'showWhoToFollowPanel', value: showWhoToFollowPanel }) + store.dispatch('setOption', { name: 'whoToFollowProvider', value: whoToFollowProvider }) + store.dispatch('setOption', { name: 'whoToFollowLink', value: whoToFollowLink }) store.dispatch('setOption', { name: 'showInstanceSpecificPanel', value: showInstanceSpecificPanel }) if (data['chatDisabled']) { store.dispatch('disableChat') diff --git a/static/config.json b/static/config.json index 2c49514295..08664927c8 100644 --- a/static/config.json +++ b/static/config.json @@ -6,5 +6,11 @@ "redirectRootLogin": "/main/friends", "chatDisabled": false, "showWhoToFollowPanel": false, + "whoToFollowProvider": "https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-simple-api.cgi?{{host}}+{{user}}", + "whoToFollowProviderDummy1": "https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-osa-api.cgi?{{host}}+{{user}}", + "whoToFollowProviderDummy2": "https://followlink.osa-p.net/api/get_recommend.json?acct=@{{user}}@{{host}}", + "whoToFollowLink": "https://vinayaka.distsn.org/?{{host}}+{{user}}", + "whoToFollowLinkDummy1": "https://vinayaka.distsn.org/?{{host}}+{{user}}", + "whoToFollowLinkDummy2": "https://followlink.osa-p.net/recommend.html", "showInstanceSpecificPanel": false } From 0691af136732624e9eef143af13d85785a749d90 Mon Sep 17 00:00:00 2001 From: hakabahitoyo Date: Sat, 5 May 2018 00:43:18 +0900 Subject: [PATCH 07/52] debug --- src/components/who_to_follow_panel/who_to_follow_panel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/who_to_follow_panel/who_to_follow_panel.js b/src/components/who_to_follow_panel/who_to_follow_panel.js index d62a1515a4..e6638fca31 100644 --- a/src/components/who_to_follow_panel/who_to_follow_panel.js +++ b/src/components/who_to_follow_panel/who_to_follow_panel.js @@ -69,7 +69,7 @@ function getWhoToFollow (panel) { panel.name2 = 'Loading...' panel.name3 = 'Loading...' var host = window.location.hostname - var whoToFollowProvider = this.$store.state.config.whoToFollowProvider + var whoToFollowProvider = panel.$store.state.config.whoToFollowProvider var url url = whoToFollowProvider.replace(/{{host}}/g, encodeURIComponent(host)) url = url.replace(/{{user}}/g, encodeURIComponent(user)) From 2471b71aabdafc0e680795645cb48f89636974a8 Mon Sep 17 00:00:00 2001 From: Hakaba Hitoyo Date: Sat, 5 May 2018 00:53:40 +0900 Subject: [PATCH 08/52] osa-compatible who to follow provider --- .../who_to_follow_panel.js | 85 ++++++++----------- static/config.json | 4 +- 2 files changed, 38 insertions(+), 51 deletions(-) diff --git a/src/components/who_to_follow_panel/who_to_follow_panel.js b/src/components/who_to_follow_panel/who_to_follow_panel.js index e6638fca31..bbbb7f4c58 100644 --- a/src/components/who_to_follow_panel/who_to_follow_panel.js +++ b/src/components/who_to_follow_panel/who_to_follow_panel.js @@ -1,59 +1,48 @@ -function showWhoToFollow (panel, users, aHost, aUser) { +function showWhoToFollow (panel, reply, aHost, aUser) { + var users = reply.ids var cn var index = 0 var random = Math.floor(Math.random() * 10) for (cn = random; cn < users.length; cn = cn + 10) { var user user = users[cn] - var host - host = user.host - var username - if (user.username) { - username = user.username - } else { - username = user.user - } var img - if (user.avatar) { - img = user.avatar + if (user.icon) { + img = user.icon } else { img = '/images/avi.png' } - var name = username + '@' + host - if ((!user.following) && - (!user.blacklisted) && - (!(host === aHost && username === aUser))) { - if (index === 0) { - panel.img1 = img - panel.name1 = name - panel.$store.state.api.backendInteractor.externalProfile(name) - .then((externalUser) => { - if (!externalUser.error) { - panel.$store.commit('addNewUsers', [externalUser]) - panel.id1 = externalUser.id - } - }) - } else if (index === 1) { - panel.img2 = img - panel.name2 = name - panel.$store.state.api.backendInteractor.externalProfile(name) - .then((externalUser) => { - if (!externalUser.error) { - panel.$store.commit('addNewUsers', [externalUser]) - panel.id2 = externalUser.id - } - }) - } else if (index === 2) { - panel.img3 = img - panel.name3 = name - panel.$store.state.api.backendInteractor.externalProfile(name) - .then((externalUser) => { - if (!externalUser.error) { - panel.$store.commit('addNewUsers', [externalUser]) - panel.id3 = externalUser.id - } - }) - } + var name = user.to_id + if (index === 0) { + panel.img1 = img + panel.name1 = name + panel.$store.state.api.backendInteractor.externalProfile(name) + .then((externalUser) => { + if (!externalUser.error) { + panel.$store.commit('addNewUsers', [externalUser]) + panel.id1 = externalUser.id + } + }) + } else if (index === 1) { + panel.img2 = img + panel.name2 = name + panel.$store.state.api.backendInteractor.externalProfile(name) + .then((externalUser) => { + if (!externalUser.error) { + panel.$store.commit('addNewUsers', [externalUser]) + panel.id2 = externalUser.id + } + }) + } else if (index === 2) { + panel.img3 = img + panel.name3 = name + panel.$store.state.api.backendInteractor.externalProfile(name) + .then((externalUser) => { + if (!externalUser.error) { + panel.$store.commit('addNewUsers', [externalUser]) + panel.id3 = externalUser.id + } + }) index = index + 1 if (index > 2) { break @@ -81,8 +70,8 @@ function getWhoToFollow (panel) { panel.name2 = '' panel.name3 = '' } - }).then(function (users) { - showWhoToFollow(panel, users, host, user) + }).then(function (reply) { + showWhoToFollow(panel, reply, host, user) }) } } diff --git a/static/config.json b/static/config.json index 08664927c8..9cdb22d596 100644 --- a/static/config.json +++ b/static/config.json @@ -6,11 +6,9 @@ "redirectRootLogin": "/main/friends", "chatDisabled": false, "showWhoToFollowPanel": false, - "whoToFollowProvider": "https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-simple-api.cgi?{{host}}+{{user}}", - "whoToFollowProviderDummy1": "https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-osa-api.cgi?{{host}}+{{user}}", + "whoToFollowProvider": "https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-osa-api.cgi?{{host}}+{{user}}", "whoToFollowProviderDummy2": "https://followlink.osa-p.net/api/get_recommend.json?acct=@{{user}}@{{host}}", "whoToFollowLink": "https://vinayaka.distsn.org/?{{host}}+{{user}}", - "whoToFollowLinkDummy1": "https://vinayaka.distsn.org/?{{host}}+{{user}}", "whoToFollowLinkDummy2": "https://followlink.osa-p.net/recommend.html", "showInstanceSpecificPanel": false } From d9d6a497d9b539fe25f73944fa1b12649298be78 Mon Sep 17 00:00:00 2001 From: Hakaba Hitoyo Date: Sat, 5 May 2018 01:02:39 +0900 Subject: [PATCH 09/52] debug --- src/components/who_to_follow_panel/who_to_follow_panel.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/who_to_follow_panel/who_to_follow_panel.js b/src/components/who_to_follow_panel/who_to_follow_panel.js index bbbb7f4c58..51b9f46923 100644 --- a/src/components/who_to_follow_panel/who_to_follow_panel.js +++ b/src/components/who_to_follow_panel/who_to_follow_panel.js @@ -43,10 +43,10 @@ function showWhoToFollow (panel, reply, aHost, aUser) { panel.id3 = externalUser.id } }) - index = index + 1 - if (index > 2) { - break - } + } + index = index + 1 + if (index > 2) { + break } } } From 36b1c09831c809722c730a102af3d224597578be Mon Sep 17 00:00:00 2001 From: hakabahitoyo Date: Sun, 6 May 2018 11:33:53 +0900 Subject: [PATCH 10/52] add space --- src/components/who_to_follow_panel/who_to_follow_panel.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/who_to_follow_panel/who_to_follow_panel.vue b/src/components/who_to_follow_panel/who_to_follow_panel.vue index 021b95576f..5af6d0d5ec 100644 --- a/src/components/who_to_follow_panel/who_to_follow_panel.vue +++ b/src/components/who_to_follow_panel/who_to_follow_panel.vue @@ -8,9 +8,9 @@

- {{ name1 }}
- {{ name2 }}
- {{ name3 }}
+ {{ name1 }}
+ {{ name2 }}
+ {{ name3 }}
More

From c46795c6922bdfc3f3669d71f0c5867cb2f1577a Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sun, 15 Apr 2018 06:02:01 +0300 Subject: [PATCH 11/52] use semi-transparent faint color + fix --- src/_variables.scss | 2 +- src/components/notifications/notifications.scss | 2 +- src/services/style_setter/style_setter.js | 5 +---- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/_variables.scss b/src/_variables.scss index d90a1d48e5..3cd558686c 100644 --- a/src/_variables.scss +++ b/src/_variables.scss @@ -4,7 +4,7 @@ $darkened-background: whitesmoke; $fallback--bg: #121a24; $fallback--btn: #182230; -$fallback--faint: #999; +$fallback--faint: rgba(185, 185, 186, .5); $fallback--fg: #b9b9ba; $fallback--link: #d8a070; $fallback--icon: #666; diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss index 9cbb1226e1..008530b43c 100644 --- a/src/components/notifications/notifications.scss +++ b/src/components/notifications/notifications.scss @@ -98,7 +98,7 @@ .status { padding: 0.25em 0; color: $fallback--faint; - color: var($fallback--faint, --faint); + color: var(--faint, $fallback--faint); } padding: 0; .media-body { diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js index 9dc4a3e17d..3e96f54da9 100644 --- a/src/services/style_setter/style_setter.js +++ b/src/services/style_setter/style_setter.js @@ -72,10 +72,7 @@ const setColors = (col, commit) => { colors.lightBg = rgb2hex((col.bg.r + col.fg.r) / 2, (col.bg.g + col.fg.g) / 2, (col.bg.b + col.fg.b) / 2) // hilighted bg colors.btn = rgb2hex(col.fg.r, col.fg.g, col.fg.b) // panels & buttons colors.border = rgb2hex(col.fg.r - mod, col.fg.g - mod, col.fg.b - mod) // borders - colors.faint = rgb2hex( - col.text.r * 0.45 + col.fg.r * 0.55, - col.text.g * 0.45 + col.fg.g * 0.55, - col.text.b * 0.45 + col.fg.b * 0.55) // faint text + colors.faint = `rgba(${col.text.r}, ${col.text.g}, ${col.text.b}, .5)` colors.fg = rgb2hex(col.text.r, col.text.g, col.text.b) // text colors.lightFg = rgb2hex(col.text.r - mod, col.text.g - mod, col.text.b - mod) // strong text From 2b64432f9af868edf347214964177bd424d56664 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sun, 15 Apr 2018 06:03:57 +0300 Subject: [PATCH 12/52] semi-transparent inputbox style --- src/App.scss | 8 ++++---- src/_variables.scss | 1 + src/services/style_setter/style_setter.js | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/App.scss b/src/App.scss index a860122074..fb7ef067b6 100644 --- a/src/App.scss +++ b/src/App.scss @@ -93,8 +93,8 @@ input, textarea, .select { border-bottom: 1px solid rgba(255, 255, 255, 0.2); border-top: 1px solid rgba(0, 0, 0, 0.2); box-shadow: 0px 0px 2px black inset; - background-color: $fallback--lightBg; - background-color: var(--lightBg, $fallback--lightBg); + background-color: $fallback--input; + background-color: var(--input, $fallback--input); color: $fallback--lightFg; color: var(--lightFg, $fallback--lightFg); font-family: sans-serif; @@ -154,8 +154,8 @@ input, textarea, .select { border-top: 1px solid rgba(0, 0, 0, 0.2); box-shadow: 0px 0px 2px black inset; margin-right: .5em; - background-color: $fallback--btn; - background-color: var(--btn, $fallback--btn); + background-color: $fallback--input; + background-color: var(--input $fallback--input); vertical-align: top; text-align: center; line-height: 1.1em; diff --git a/src/_variables.scss b/src/_variables.scss index 3cd558686c..427cc36b6d 100644 --- a/src/_variables.scss +++ b/src/_variables.scss @@ -4,6 +4,7 @@ $darkened-background: whitesmoke; $fallback--bg: #121a24; $fallback--btn: #182230; +$fallback--input: #182230; $fallback--faint: rgba(185, 185, 186, .5); $fallback--fg: #b9b9ba; $fallback--link: #d8a070; diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js index 3e96f54da9..4a6c4d8f6a 100644 --- a/src/services/style_setter/style_setter.js +++ b/src/services/style_setter/style_setter.js @@ -71,6 +71,7 @@ const setColors = (col, commit) => { colors.bg = rgb2hex(col.bg.r, col.bg.g, col.bg.b) // background colors.lightBg = rgb2hex((col.bg.r + col.fg.r) / 2, (col.bg.g + col.fg.g) / 2, (col.bg.b + col.fg.b) / 2) // hilighted bg colors.btn = rgb2hex(col.fg.r, col.fg.g, col.fg.b) // panels & buttons + colors.input = `rgba(${col.fg.r}, ${col.fg.g}, ${col.fg.b}, .5)` colors.border = rgb2hex(col.fg.r - mod, col.fg.g - mod, col.fg.b - mod) // borders colors.faint = `rgba(${col.text.r}, ${col.text.g}, ${col.text.b}, .5)` colors.fg = rgb2hex(col.text.r, col.text.g, col.text.b) // text From e23986e239e66cea5bae6f26982463cb5d705774 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sun, 15 Apr 2018 06:04:17 +0300 Subject: [PATCH 13/52] unnecessary styles removed (fixes transparent color userstyle) --- src/components/nav_panel/nav_panel.vue | 2 -- src/components/status/status.vue | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/components/nav_panel/nav_panel.vue b/src/components/nav_panel/nav_panel.vue index 6f949afb63..2e1a6c7a1f 100644 --- a/src/components/nav_panel/nav_panel.vue +++ b/src/components/nav_panel/nav_panel.vue @@ -45,8 +45,6 @@ border-bottom: 1px solid; border-color: $fallback--border; border-color: var(--border, $fallback--border); - background-color: $fallback--bg; - background-color: var(--bg, $fallback--bg); padding: 0; &:first-child a { diff --git a/src/components/status/status.vue b/src/components/status/status.vue index f1163fd9b9..4b19890517 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -165,8 +165,6 @@ border-left-width: 0px; line-height: 18px; min-width: 0; - background-color: $fallback--bg; - background-color: var(--bg, $fallback--bg); border-color: $fallback--border; border-color: var(--border, $fallback--border); From 008b36dc24942058034d545402c3e404fc62d76b Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sun, 15 Apr 2018 06:04:48 +0300 Subject: [PATCH 14/52] gave text some shadow-outline to make it more readable on white backgrounds + fixed weird layout (WHY) --- .../user_card_content/user_card_content.vue | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/components/user_card_content/user_card_content.vue b/src/components/user_card_content/user_card_content.vue index ca8428cab2..a88c071232 100644 --- a/src/components/user_card_content/user_card_content.vue +++ b/src/components/user_card_content/user_card_content.vue @@ -112,17 +112,14 @@ } .profile-panel-body { - top: -0em; - padding-top: 4em; word-wrap: break-word; - background: linear-gradient(to bottom, rgba(0, 0, 0, 0), $fallback--bg 80%); - background: linear-gradient(to bottom, rgba(0, 0, 0, 0), var(--bg, $fallback--bg) 80%) + background: linear-gradient(to bottom, rgba(0, 0, 0, 0), $fallback--bg 80px); + background: linear-gradient(to bottom, rgba(0, 0, 0, 0), var(--bg, $fallback--bg) 80px) } .user-info { color: white; padding: 0 16px 16px 16px; - margin-bottom: -4em; .container { padding: 16px 10px 4px 10px; @@ -154,7 +151,11 @@ } } - text-shadow: 0px 1px 1.5px rgba(0, 0, 0, 1.0); + text-shadow: 0px 1px 1.5px rgba(0, 0, 0, 1.0), + 1px 1px 0px rgba(0, 0, 0, .2), + -1px 1px 0px rgba(0, 0, 0, .2), + 1px -1px 0px rgba(0, 0, 0, .2), + -1px -1px 0px rgba(0, 0, 0, .2); .usersettings { color: #fff; @@ -240,6 +241,12 @@ line-height:16px; padding: 1em 1.5em 0em 1em; text-align: center; + + text-shadow: 0px 1px 1.5px rgba(0, 0, 0, 1.0), + 1px 1px 0px rgba(0, 0, 0, .2), + -1px 1px 0px rgba(0, 0, 0, .2), + 1px -1px 0px rgba(0, 0, 0, .2), + -1px -1px 0px rgba(0, 0, 0, .2); } .user-count { From a6fa913f45e79734ff13fe85c7ed71cb7b2e5477 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sun, 15 Apr 2018 07:25:59 +0300 Subject: [PATCH 15/52] Input fields separate radii --- src/App.scss | 4 ++-- src/_variables.scss | 1 + src/components/style_switcher/style_switcher.js | 3 +++ src/components/style_switcher/style_switcher.vue | 6 ++++++ src/i18n/messages.js | 2 ++ src/services/style_setter/style_setter.js | 1 + 6 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/App.scss b/src/App.scss index fb7ef067b6..55b0de942d 100644 --- a/src/App.scss +++ b/src/App.scss @@ -88,8 +88,8 @@ label.select { input, textarea, .select { border: none; - border-radius: $fallback--btnRadius; - border-radius: var(--btnRadius, $fallback--btnRadius); + border-radius: $fallback--inputRadius; + border-radius: var(--inputRadius, $fallback--inputRadius); border-bottom: 1px solid rgba(255, 255, 255, 0.2); border-top: 1px solid rgba(0, 0, 0, 0.2); box-shadow: 0px 0px 2px black inset; diff --git a/src/_variables.scss b/src/_variables.scss index 427cc36b6d..b5222a6a63 100644 --- a/src/_variables.scss +++ b/src/_variables.scss @@ -22,6 +22,7 @@ $fallback--cAlertRed: rgba(211,16,20,.5); $fallback--panelRadius: 10px; $fallback--checkBoxRadius: 2px; $fallback--btnRadius: 4px; +$fallback--inputRadius: 4px; $fallback--tooltipRadius: 5px; $fallback--avatarRadius: 4px; $fallback--avatarAltRadius: 10px; diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js index 08bc71130a..6f4845c444 100644 --- a/src/components/style_switcher/style_switcher.js +++ b/src/components/style_switcher/style_switcher.js @@ -14,6 +14,7 @@ export default { greenColorLocal: '', orangeColorLocal: '', btnRadiusLocal: '', + inputRadiusLocal: '', panelRadiusLocal: '', avatarRadiusLocal: '', avatarAltRadiusLocal: '', @@ -42,6 +43,7 @@ export default { this.orangeColorLocal = rgbstr2hex(this.$store.state.config.colors.cOrange) this.btnRadiusLocal = this.$store.state.config.radii.btnRadius || 4 + this.inputRadiusLocal = this.$store.state.config.radii.inputRadius || 4 this.panelRadiusLocal = this.$store.state.config.radii.panelRadius || 10 this.avatarRadiusLocal = this.$store.state.config.radii.avatarRadius || 5 this.avatarAltRadiusLocal = this.$store.state.config.radii.avatarAltRadius || 50 @@ -85,6 +87,7 @@ export default { cGreen: greenRgb, cOrange: orangeRgb, btnRadius: this.btnRadiusLocal, + inputRadius: this.inputRadiusLocal, panelRadius: this.panelRadiusLocal, avatarRadius: this.avatarRadiusLocal, avatarAltRadius: this.avatarAltRadiusLocal, diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue index 9c39b245ac..7acba1dc4f 100644 --- a/src/components/style_switcher/style_switcher.vue +++ b/src/components/style_switcher/style_switcher.vue @@ -58,6 +58,11 @@ +
+ + + +
@@ -86,6 +91,7 @@
{{user.name}}
- -
@{{user.screen_name}}
+ + @{{user.screen_name}} + {{dailyAvg}} {{ $t('user_card.per_day') }}
@@ -74,17 +75,17 @@
-
+
{{ $t('user_card.statuses') }}
{{ $t('user_card.statuses') }}
- {{user.statuses_count}}
{{dailyAvg}} {{ $t('user_card.per_day') }}
+ {{user.statuses_count}}
-
+
{{ $t('user_card.followees') }}
{{ $t('user_card.followees') }}
{{user.friends_count}}
-
+
{{ $t('user_card.followers') }}
{{ $t('user_card.followers') }}
{{user.followers_count}} @@ -113,16 +114,16 @@ .profile-panel-body { word-wrap: break-word; - background: linear-gradient(to bottom, rgba(0, 0, 0, 0), $fallback--bg 80px); - background: linear-gradient(to bottom, rgba(0, 0, 0, 0), var(--bg, $fallback--bg) 80px) + background: linear-gradient(to bottom, rgba(0, 0, 0, 0), $fallback--bg 80%); + background: linear-gradient(to bottom, rgba(0, 0, 0, 0), var(--bg, $fallback--bg) 80%) } .user-info { color: white; - padding: 0 16px 16px 16px; + padding: 0 16px; .container { - padding: 16px 10px 4px 10px; + padding: 16px 10px 6px 10px; display: flex; max-height: 56px; overflow: hidden; @@ -151,11 +152,7 @@ } } - text-shadow: 0px 1px 1.5px rgba(0, 0, 0, 1.0), - 1px 1px 0px rgba(0, 0, 0, .2), - -1px 1px 0px rgba(0, 0, 0, .2), - 1px -1px 0px rgba(0, 0, 0, .2), - -1px -1px 0px rgba(0, 0, 0, .2); + text-shadow: $usercard-text-shadow; .usersettings { color: #fff; @@ -179,7 +176,8 @@ .user-screen-name { color: white; - font-weight: lighter; + display: inline-block; + font-weight: light; font-size: 15px; padding-right: 0.1em; } @@ -192,14 +190,12 @@ div { flex: 1; } - margin-top: 0.7em; - margin-bottom: -1.0em; .following { color: white; font-size: 14px; flex: 0 0 100%; - margin: -0.7em 0.0em 0.3em 0.0em; + margin: 0 0 .4em 0; padding-left: 16px; text-align: left; } @@ -239,18 +235,22 @@ .user-counts { display: flex; line-height:16px; - padding: 1em 1.5em 0em 1em; + padding: .5em 1.5em 0em 1.5em; text-align: center; - - text-shadow: 0px 1px 1.5px rgba(0, 0, 0, 1.0), - 1px 1px 0px rgba(0, 0, 0, .2), - -1px 1px 0px rgba(0, 0, 0, .2), - 1px -1px 0px rgba(0, 0, 0, .2), - -1px -1px 0px rgba(0, 0, 0, .2); + justify-content: space-between; + text-shadow: $usercard-text-shadow; } .user-count { flex: 1; + padding: .5em 0 .5em 0; + margin: 0 .5em; + + &.selected { + background-color: rgba(0,0,0,.35); + border-radius: $fallback--btnRadius; + border-radius: var(--btnRadius, $fallback--btnRadius); + } h5 { font-size:1em; @@ -263,7 +263,8 @@ } .dailyAvg { - font-size: 0.8em; - opacity: 0.5; + margin-left: 1em; + font-size: 0.7em; + color: #CCC; } diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue index 838a43ab69..f850290786 100644 --- a/src/components/user_profile/user_profile.vue +++ b/src/components/user_profile/user_profile.vue @@ -1,7 +1,7 @@ diff --git a/src/i18n/messages.js b/src/i18n/messages.js index a13d7f5812..897f95d25d 100644 --- a/src/i18n/messages.js +++ b/src/i18n/messages.js @@ -289,7 +289,11 @@ const en = { follow_import: 'Follow import', import_followers_from_a_csv_file: 'Import follows from a csv file', follows_imported: 'Follows imported! Processing them will take a while.', - follow_import_error: 'Error importing followers' + follow_import_error: 'Error importing followers', + delete_account: 'Delete Account', + delete_account_description: 'Permanantly delete your account and all your messages.', + delete_account_instructions: 'Type your password in the input below to confirm account deletion.', + delete_account_error: 'There was an issue deleting your account. If this persists please contact your instance administrator.' }, notifications: { notifications: 'Notifications', diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index f14bfd6d10..fd4010680f 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -30,6 +30,7 @@ const BLOCKING_URL = '/api/blocks/create.json' const UNBLOCKING_URL = '/api/blocks/destroy.json' const USER_URL = '/api/users/show.json' const FOLLOW_IMPORT_URL = '/api/pleroma/follow_import' +const DELETE_ACCOUNT_URL = '/api/pleroma/delete_account' import { each, map } from 'lodash' import 'whatwg-fetch' @@ -373,6 +374,19 @@ const followImport = ({params, credentials}) => { .then((response) => response.ok) } +const deleteAccount = ({credentials, password}) => { + const form = new FormData() + + form.append('password', password) + + return fetch(DELETE_ACCOUNT_URL, { + body: form, + method: 'POST', + headers: authHeaders(credentials) + }) + .then((response) => response.json()) +} + const fetchMutes = ({credentials}) => { const url = '/api/qvitter/mutes.json' @@ -408,7 +422,8 @@ const apiService = { updateProfile, updateBanner, externalProfile, - followImport + followImport, + deleteAccount } export default apiService diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js index 52b8286b56..c5807bed30 100644 --- a/src/services/backend_interactor_service/backend_interactor_service.js +++ b/src/services/backend_interactor_service/backend_interactor_service.js @@ -61,6 +61,8 @@ const backendInteractorService = (credentials) => { const externalProfile = (profileUrl) => apiService.externalProfile({profileUrl, credentials}) const followImport = ({params}) => apiService.followImport({params, credentials}) + const deleteAccount = ({password}) => apiService.deleteAccount({credentials, password}) + const backendInteractorServiceInstance = { fetchStatus, fetchConversation, @@ -82,7 +84,8 @@ const backendInteractorService = (credentials) => { updateBanner, updateProfile, externalProfile, - followImport + followImport, + deleteAccount } return backendInteractorServiceInstance From fae7a40aebc4266260c8cb0dcac929ac03500590 Mon Sep 17 00:00:00 2001 From: aka Date: Sun, 13 May 2018 20:47:08 -0300 Subject: [PATCH 27/52] Adds an option to export follows --- src/components/user_settings/user_settings.js | 29 +++++++++++++++++++ .../user_settings/user_settings.vue | 7 +++++ src/i18n/messages.js | 5 +++- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js index 25ee1f359a..602052ca31 100644 --- a/src/components/user_settings/user_settings.js +++ b/src/components/user_settings/user_settings.js @@ -8,6 +8,7 @@ const UserSettings = { followList: null, followImportError: false, followsImported: false, + enableFollowsExport: true, uploading: [ false, false, false, false ], previews: [ null, null, null ] } @@ -137,6 +138,34 @@ const UserSettings = { this.uploading[3] = false }) }, + /* This function takes an Array of Users + * and outputs a file with all the addresses for the user to download + */ + exportPeople(Users) { + // Get all the friends addresses + var UserAddresses = Users.map(function(user) { + // check is it's a local user + if(user && user.is_local) { + // append the instance address + user.screen_name += '@' + location.hostname; + } + return user.screen_name; + }).join('\n'); + // Make the user download the file + var fileToDownload = document.createElement('a'); + fileToDownload.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(UserAddresses)); + fileToDownload.setAttribute('download', 'friends.csv'); + fileToDownload.style.display = 'none'; + document.body.appendChild(fileToDownload); + fileToDownload.click(); + document.body.removeChild(fileToDownload); + }, + exportFollows() { + this.enableFollowsExport = false; + this.$store.state.api.backendInteractor + .fetchFriends({id: this.$store.state.users.currentUser.id}) + .then(this.exportPeople); + }, followListChange () { // eslint-disable-next-line no-undef let formData = new FormData() diff --git a/src/components/user_settings/user_settings.vue b/src/components/user_settings/user_settings.vue index ed1864cc66..184d158d5a 100644 --- a/src/components/user_settings/user_settings.vue +++ b/src/components/user_settings/user_settings.vue @@ -66,6 +66,13 @@

{{$t('settings.follow_import_error')}}

+
+

{{$t('settings.follow_export')}}

+ +
+
+

{{$t('settings.follow_export_processing')}}

+
diff --git a/src/i18n/messages.js b/src/i18n/messages.js index 168548cf0d..473fd9b185 100644 --- a/src/i18n/messages.js +++ b/src/i18n/messages.js @@ -288,7 +288,10 @@ const en = { follow_import: 'Follow import', import_followers_from_a_csv_file: 'Import follows from a csv file', follows_imported: 'Follows imported! Processing them will take a while.', - follow_import_error: 'Error importing followers' + follow_import_error: 'Error importing followers', + follow_export: 'Follow export', + follow_export_processing: 'Processing, you\'ll soon be aked to download your file', + follow_export_button: 'Export your follows to a csv file' }, notifications: { notifications: 'Notifications', From 1ff089a175eb5c77f86896b89728aa9066a4699f Mon Sep 17 00:00:00 2001 From: Exilat Date: Tue, 15 May 2018 05:14:59 +0000 Subject: [PATCH 28/52] Update messages.js --- src/i18n/messages.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/i18n/messages.js b/src/i18n/messages.js index a13d7f5812..46da4404c5 100644 --- a/src/i18n/messages.js +++ b/src/i18n/messages.js @@ -1018,7 +1018,7 @@ const oc = { timeline: { show_new: 'Ne veire mai', error_fetching: 'Error en cercant de mesas a jorn', - up_to_date: 'Actualizat', + up_to_date: 'A jorn', load_older: 'Ne veire mai', conversation: 'Conversacion', collapse: 'Tampar', @@ -1050,6 +1050,7 @@ const oc = { cRed: 'Roge (Anullar)', cOrange: 'Irange (Metre en favorit)', cGreen: 'Verd (Repartajar)', + inputRadius: 'Camps tèxte', btnRadius: 'Botons', panelRadius: 'Panèls', avatarRadius: 'Avatars', @@ -1074,7 +1075,7 @@ const oc = { notifications: { notifications: 'Notficacions', read: 'Legit !', - followed_you: 'vos a seguit', + followed_you: 'vos sèc', favorited_you: 'a aimat vòstre estatut', repeated_you: 'a repetit your vòstre estatut' }, @@ -1105,7 +1106,7 @@ const oc = { apply: 'Aplicar' }, user_profile: { - timeline_title: 'Flux a l’utilizaire' + timeline_title: 'Flux utilizaire' } } From 1487474c187cac17233f7e7942ddec2a5b8b700a Mon Sep 17 00:00:00 2001 From: Azurolu Date: Tue, 15 May 2018 11:17:32 +0000 Subject: [PATCH 29/52] Added inputRadius french translation and improved french translation as discussed with Chip. --- src/i18n/messages.js | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/i18n/messages.js b/src/i18n/messages.js index a13d7f5812..4ddf3309d0 100644 --- a/src/i18n/messages.js +++ b/src/i18n/messages.js @@ -851,32 +851,32 @@ const fr = { user_settings: 'Paramètres utilisateur', name_bio: 'Nom & Bio', name: 'Nom', - bio: 'Bioraphie', + bio: 'Biographie', avatar: 'Avatar', - current_avatar: 'Votre avatar', + current_avatar: 'Avatar actuel', set_new_avatar: 'Changer d\'avatar', - profile_banner: 'Bannière du profil', - current_profile_banner: 'Bannière du profil', + profile_banner: 'Bannière de profil', + current_profile_banner: 'Bannière de profil actuelle', set_new_profile_banner: 'Changer de bannière', profile_background: 'Image de fond', set_new_profile_background: 'Changer d\'image de fond', settings: 'Paramètres', theme: 'Thème', filtering: 'Filtre', - filtering_explanation: 'Tout les statuts contenant ces mots vont être cachés, un mot par ligne.', + filtering_explanation: 'Tout les statuts contenant ces mots seront masqués. Un mot par ligne.', attachments: 'Pièces jointes', - hide_attachments_in_tl: 'Cacher les pièces jointes dans le journal', - hide_attachments_in_convo: 'Cacher les pièces jointes dans les conversations', - nsfw_clickthrough: 'Activer le clic pour afficher les images marquées comme contenu adulte ou sensible', - autoload: 'Activer le chargement automatique une fois le bas de la page atteint', + hide_attachments_in_tl: 'Masquer les pièces jointes dans le journal', + hide_attachments_in_convo: 'Masquer les pièces jointes dans les conversations', + nsfw_clickthrough: 'Masquer les images marquées comme contenu adulte ou sensible', + autoload: 'Charger la suite automatiquement une fois le bas de la page atteint', reply_link_preview: 'Activer un aperçu d\'une réponse sur passage de la souris', presets: 'Thèmes prédéfinis', - theme_help: 'Utilisez les codes de couleur hexadécimaux (#aabbcc) pour customiser les couleurs de votre thème.', + theme_help: 'Spécifiez des codes couleur hexadécimaux (#aabbcc) pour personnaliser les couleurs du thème', background: 'Arrière plan', foreground: 'Premier plan', text: 'Texte', links: 'Liens', - streaming: 'Active le défilement automatique de nouveaux statuts lorsqu\'on est au haut de la page', + streaming: 'Charger automatiquement les nouveaux statuts lorsque vous êtes au haut de la page', follow_import: 'Importer ses abonnements', import_followers_from_a_csv_file: 'Importer ses abonnements depuis un fichier csv', follows_imported: 'Abonnements importés ! Le traitement peut prendre un moment.', @@ -887,12 +887,13 @@ const fr = { cGreen: 'Vert (Partager)', btnRadius: 'Boutons', panelRadius: 'Fenêtres', + inputRadius: 'Champs de texte', avatarRadius: 'Avatars', avatarAltRadius: 'Avatars (Notifications)', tooltipRadius: 'Info-bulles/alertes ', attachmentRadius: 'Pièces jointes', radii_help: 'Mettre en place l\'arondissement des coins de l\'interface (en pixels)', - stop_gifs: 'Passer la souris sur un GIF pour l\'animer' + stop_gifs: 'N\'animer les GIFS que lors du survol du curseur de la souris' }, notifications: { notifications: 'Notifications', @@ -910,10 +911,10 @@ const fr = { }, registration: { registration: 'Inscription', - fullname: 'Nom affiché', + fullname: 'Pseudonyme', email: 'Adresse email', bio: 'Biographie', - password_confirm: 'Confirmez le mot de passe' + password_confirm: 'Confirmation le mot de passe' }, post_status: { posting: 'Envoi en cours', @@ -921,7 +922,7 @@ const fr = { }, finder: { find_user: 'Chercher un utilisateur', - error_fetching_user: 'Une erreur est survenue lors de la recherche de l\'utilisateur' + error_fetching_user: 'Erreur lors de la recherche de l\'utilisateur' }, general: { submit: 'Envoyer', From fc2bb104442f8e3bbbe661abdee670ebb2776199 Mon Sep 17 00:00:00 2001 From: Azurolu Date: Wed, 16 May 2018 01:42:54 +0000 Subject: [PATCH 30/52] Improved french translation thanks to Chip's suggestions, added inputRadius' french translation. --- src/i18n/messages.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/i18n/messages.js b/src/i18n/messages.js index 4ddf3309d0..846d123f0a 100644 --- a/src/i18n/messages.js +++ b/src/i18n/messages.js @@ -831,8 +831,8 @@ const fr = { blocked: 'Bloqué', block: 'Bloquer', statuses: 'Statuts', - mute: 'Mettre en muet', - muted: 'Mis en muet', + mute: 'Masquer', + muted: 'Masqué', followers: 'Vous suivent', followees: 'Suivis', per_day: 'par jour', @@ -840,7 +840,7 @@ const fr = { }, timeline: { show_new: 'Afficher plus', - error_fetching: 'Erreur en cherchant des mises à jours', + error_fetching: 'Erreur en cherchant les mises à jour', up_to_date: 'À jour', load_older: 'Afficher plus', conversation: 'Conversation', @@ -869,7 +869,7 @@ const fr = { hide_attachments_in_convo: 'Masquer les pièces jointes dans les conversations', nsfw_clickthrough: 'Masquer les images marquées comme contenu adulte ou sensible', autoload: 'Charger la suite automatiquement une fois le bas de la page atteint', - reply_link_preview: 'Activer un aperçu d\'une réponse sur passage de la souris', + reply_link_preview: 'Afficher un aperçu lors du survol de liens vers une réponse', presets: 'Thèmes prédéfinis', theme_help: 'Spécifiez des codes couleur hexadécimaux (#aabbcc) pour personnaliser les couleurs du thème', background: 'Arrière plan', @@ -887,24 +887,24 @@ const fr = { cGreen: 'Vert (Partager)', btnRadius: 'Boutons', panelRadius: 'Fenêtres', - inputRadius: 'Champs de texte', + inputRadius: 'Champs de texte', avatarRadius: 'Avatars', avatarAltRadius: 'Avatars (Notifications)', tooltipRadius: 'Info-bulles/alertes ', attachmentRadius: 'Pièces jointes', - radii_help: 'Mettre en place l\'arondissement des coins de l\'interface (en pixels)', + radii_help: 'Vous pouvez ici choisir le niveau d\'arrondi des angles de l\'interface (en pixels)', stop_gifs: 'N\'animer les GIFS que lors du survol du curseur de la souris' }, notifications: { notifications: 'Notifications', read: 'Lu !', - followed_you: 'vous a suivi', + followed_you: 'a commencé à vous suivre', favorited_you: 'a aimé votre statut', repeated_you: 'a partagé votre statut' }, login: { login: 'Connexion', - username: 'Nom d\'utilisateur', + username: 'Identifiant', password: 'Mot de passe', register: 'S\'inscrire', logout: 'Déconnexion' From 954e6e076333e622134ad05cc51e07dcd1c940a7 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Wed, 16 May 2018 13:01:17 +0200 Subject: [PATCH 31/52] Make nsfw image easier to understand. --- src/assets/nsfw.png | Bin 18166 -> 17071 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/assets/nsfw.png b/src/assets/nsfw.png index bb6556b408d3b898b9fe858ab6fff56bdad86809..427490334ac6eafe0e69bea704685a5643a3c504 100644 GIT binary patch literal 17071 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

5KJrO2V;c|bq0+)wJ8skpK68-SKKCi&6* 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 S^w0k@PE}D$p<3>3*#8Bdc7`$*z!n$eOyid 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 vMwA5SrERK(!v>gTe~DWM4fX+n;Z From fed87815833bfb847be192b79782f3edca99cf5f Mon Sep 17 00:00:00 2001 From: aka Date: Wed, 16 May 2018 19:51:52 -0300 Subject: [PATCH 32/52] fix linting --- src/components/user_settings/user_settings.js | 43 ++++++++++--------- src/i18n/messages.js | 2 +- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js index 602052ca31..2c08b2f8bc 100644 --- a/src/components/user_settings/user_settings.js +++ b/src/components/user_settings/user_settings.js @@ -141,30 +141,33 @@ const UserSettings = { /* This function takes an Array of Users * and outputs a file with all the addresses for the user to download */ - exportPeople(Users) { + exportPeople (users, filename) { // Get all the friends addresses - var UserAddresses = Users.map(function(user) { - // check is it's a local user - if(user && user.is_local) { - // append the instance address - user.screen_name += '@' + location.hostname; - } - return user.screen_name; - }).join('\n'); + var UserAddresses = users.map(function (user) { + // check is it's a local user + if (user && user.is_local) { + // append the instance address + // eslint-disable-next-line no-undef + user.screen_name += '@' + location.hostname + } + return user.screen_name + }).join('\n') // Make the user download the file - var fileToDownload = document.createElement('a'); - fileToDownload.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(UserAddresses)); - fileToDownload.setAttribute('download', 'friends.csv'); - fileToDownload.style.display = 'none'; - document.body.appendChild(fileToDownload); - fileToDownload.click(); - document.body.removeChild(fileToDownload); + var fileToDownload = document.createElement('a') + fileToDownload.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(UserAddresses)) + fileToDownload.setAttribute('download', filename) + fileToDownload.style.display = 'none' + document.body.appendChild(fileToDownload) + fileToDownload.click() + document.body.removeChild(fileToDownload) }, - exportFollows() { - this.enableFollowsExport = false; + exportFollows () { + this.enableFollowsExport = false this.$store.state.api.backendInteractor - .fetchFriends({id: this.$store.state.users.currentUser.id}) - .then(this.exportPeople); + .fetchFriends({id: this.$store.state.users.currentUser.id}) + .then(function (friendList) { + this.exportPeople(friendList, 'friends.csv') + }.bind(this)) }, followListChange () { // eslint-disable-next-line no-undef diff --git a/src/i18n/messages.js b/src/i18n/messages.js index 473fd9b185..bb3f2d3952 100644 --- a/src/i18n/messages.js +++ b/src/i18n/messages.js @@ -290,7 +290,7 @@ const en = { follows_imported: 'Follows imported! Processing them will take a while.', follow_import_error: 'Error importing followers', follow_export: 'Follow export', - follow_export_processing: 'Processing, you\'ll soon be aked to download your file', + follow_export_processing: 'Processing, you\'ll soon be asked to download your file', follow_export_button: 'Export your follows to a csv file' }, notifications: { From 3c525d6a3b4a815bd600261298d08a4ac6deaa35 Mon Sep 17 00:00:00 2001 From: aka Date: Fri, 18 May 2018 07:34:36 -0300 Subject: [PATCH 33/52] use es6 notation for exportFollows --- src/components/user_settings/user_settings.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js index 2c08b2f8bc..708d19883d 100644 --- a/src/components/user_settings/user_settings.js +++ b/src/components/user_settings/user_settings.js @@ -165,9 +165,9 @@ const UserSettings = { this.enableFollowsExport = false this.$store.state.api.backendInteractor .fetchFriends({id: this.$store.state.users.currentUser.id}) - .then(function (friendList) { + .then((friendList) => { this.exportPeople(friendList, 'friends.csv') - }.bind(this)) + }) }, followListChange () { // eslint-disable-next-line no-undef From 8bd561c285aa48d750cf026d4492d4169f2fb040 Mon Sep 17 00:00:00 2001 From: chip Date: Fri, 18 May 2018 21:39:21 +0200 Subject: [PATCH 34/52] Correct typo in french translation --- src/i18n/messages.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/messages.js b/src/i18n/messages.js index f00bb6c508..43a224ce04 100644 --- a/src/i18n/messages.js +++ b/src/i18n/messages.js @@ -917,7 +917,7 @@ const fr = { fullname: 'Pseudonyme', email: 'Adresse email', bio: 'Biographie', - password_confirm: 'Confirmation le mot de passe' + password_confirm: 'Confirmation du mot de passe' }, post_status: { posting: 'Envoi en cours', From fcc1ab1d85ce5ba5944821f8a8c3cc593997f949 Mon Sep 17 00:00:00 2001 From: chip Date: Sat, 19 May 2018 20:35:14 +0200 Subject: [PATCH 35/52] Pass the "Collapse" label throught the translation function --- src/components/conversation/conversation.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index 308e5e7dce..bfcd3fe7eb 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -3,7 +3,7 @@

{{ $t('timeline.conversation') }} - Collapse + {{ $t('timeline.collapse') }}
From f06fef26b169a07d95afbf1d40764f9196ee37de Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Sun, 20 May 2018 18:28:01 +0200 Subject: [PATCH 36/52] Display visibility if available. --- src/components/status/status.js | 12 ++++++++++++ src/components/status/status.vue | 1 + static/font/config.json | 24 ++++++++++++++++++++++++ static/font/css/fontello-codes.css | 4 ++++ static/font/css/fontello-embedded.css | 16 ++++++++++------ static/font/css/fontello-ie7-codes.css | 4 ++++ static/font/css/fontello-ie7.css | 4 ++++ static/font/css/fontello.css | 18 +++++++++++------- static/font/demo.html | 20 +++++++++++++------- static/font/font/fontello.eot | Bin 12348 -> 15124 bytes static/font/font/fontello.svg | 8 ++++++++ static/font/font/fontello.ttf | Bin 12180 -> 14956 bytes static/font/font/fontello.woff | Bin 7512 -> 9176 bytes static/font/font/fontello.woff2 | Bin 6408 -> 7812 bytes 14 files changed, 91 insertions(+), 20 deletions(-) diff --git a/src/components/status/status.js b/src/components/status/status.js index 73f4a7aa7d..c93d81ffed 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -104,6 +104,18 @@ const Status = { StillImage }, methods: { + visibilityIcon(visibility) { + switch(visibility) { + case "private": + return "icon-lock" + case "unlisted": + return "icon-lock-open-alt" + case "direct": + return "icon-mail-alt" + default: + return "icon-globe" + } + }, linkClicked ({target}) { if (target.tagName === 'SPAN') { target = target.parentNode diff --git a/src/components/status/status.vue b/src/components/status/status.vue index 7902cde090..ace141cd9d 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -55,6 +55,7 @@ +