Skip to content
This repository has been archived by the owner on May 18, 2022. It is now read-only.

Commit

Permalink
Merge pull request #166 from KyleMaas/user-groups
Browse files Browse the repository at this point in the history
User groups
  • Loading branch information
arj03 authored Feb 4, 2021
2 parents 1142718 + 658b3f4 commit 57a54c4
Show file tree
Hide file tree
Showing 9 changed files with 470 additions and 3 deletions.
24 changes: 24 additions & 0 deletions css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,30 @@ body, html {
background-color: #6c6;
}

#channels ul.groupMembers
{
list-style: none;
margin: 0;
padding: 0;
}

#channels ul.groupMembers li > a > img
{
width: 50px;
height: 50px;
}

#channels ul.groupMembers li
{
float: left;
padding-right: 0.5rem;
}

#channels .clearingDiv
{
clear: both;
}

a.blockedAvatar
{
display: inline-block;
Expand Down
11 changes: 11 additions & 0 deletions css/profile.css
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
margin: 16px 0px 0px 0px;
}

#profile .profileButtons span.addToGroup div.v-select,
#profile .profileButtons button.clickButton {
margin-left: 1rem;
margin-top: 16px;
Expand Down Expand Up @@ -112,3 +113,13 @@
width: 100%;
height: 10rem;
}

#profile span.addToGroup {
display: inline-block;
float: right;
}

#profile span.addToGroup div.v-select {
display: inline-block;
width: 20em;
}
4 changes: 4 additions & 0 deletions localprefs.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ exports.getAutorefresh = function() { return (getPref('autorefresh', (typeof def

exports.setAutorefresh = function(isOn) { setPref('autorefresh', (isOn ? 'true' : 'false')) }

exports.getUserGroups = function() { return JSON.parse(getPref('userGroups', JSON.stringify(defaultPrefs.userGroups || []))) }

exports.setUserGroups = function(userGroupArray) { setPref('userGroups', JSON.stringify(userGroupArray)) }

exports.updateStateFromSettings = function() {
// Update the running state to match the stored settings.
SSB.hops = this.getHops()
Expand Down
26 changes: 26 additions & 0 deletions messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@
},
"channels": {
"title": "Channels",
"yourGroups": "Your groups",
"newGroupName": "New group name",
"addGroup": "Add group",
"confirmDeleteGroup": "Are you sure you want to delete the group \"{group}\"?",
"favoriteChannels": "Favorite channels",
"otherChannels": "Other channels",
"showChannels": "Show:",
Expand All @@ -66,6 +70,11 @@
"dbStatus": "DB status",
"ebtStatus": "EBT status"
},
"group": {
"title": "Group \"{name}\"",
"blankFieldError": "Please provide a message to publish.",
"postNewMessage": "Post general public message"
},
"messagePreview": {
"postPreview": "Post preview",
"postMessage": "Post message"
Expand Down Expand Up @@ -102,6 +111,10 @@
"saveProfile": "Save profile",
"sendMessage": "Send message",
"removeFeed": "Remove feed",
"groupDropdownPlaceholder": "Add to group",
"addToGroup": "Add to group",
"removeFromGroup": "Remove from group",
"chooseGroupFirst": "Please choose a group first",
"following": "Following",
"blocking": "Blocking",
"lastXMessagesFor": "Last {count} messages for",
Expand Down Expand Up @@ -287,6 +300,10 @@
},
"channels": {
"title": "チャンネル",
"yourGroups": "あなたのグループ",
"newGroupName": "新しいグループ名",
"addGroup": "グループを追加",
"confirmDeleteGroup": "「{group}」という名前のグループを削除してもよろしいですか?",
"favoriteChannels": "お気に入りのチャンネル",
"otherChannels": "他のチャネル",
"showChannels": "見るに:",
Expand All @@ -310,6 +327,11 @@
"dbStatus": "データベースのステータス",
"ebtStatus": "EBTのステータス"
},
"group": {
"title": "グループ「{name}」",
"blankFieldError": "公開するメッセージを入力してください。",
"postNewMessage": "一般公開メッセージを投稿する"
},
"messagePreview": {
"postPreview": "プレビュー",
"postMessage": "掲示します"
Expand Down Expand Up @@ -346,6 +368,10 @@
"saveProfile": "プロファイルを保存",
"sendMessage": "メッセージを送る",
"removeFeed": "フィードを削除する",
"groupDropdownPlaceholder": "グループに追加",
"addToGroup": "グループに追加",
"removeFromGroup": "グループから削除",
"chooseGroupFirst": "最初にグループを選択してください",
"following": "フォローする",
"blocking": "ブロックする",
"lastXMessagesFor": "最後の{count}つのメッセージ:",
Expand Down
2 changes: 2 additions & 0 deletions ui/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ require('ssb-browser-core/core').init("/.ssb-lite", optionsForCore);
const Profile = require('./profile')()
const Notifications = require('./notifications')()
const Channel = require('./channel')()
const Group = require('./group')()
const Channels = require('./channels')()
const Thread = require('./thread')()
const Private = require('./private')(componentsState)
Expand All @@ -54,6 +55,7 @@ require('ssb-browser-core/core').init("/.ssb-lite", optionsForCore);
{ name: 'public', path: '/public', component: Public },
{ name: 'channels', path: '/channels', component: Channels },
{ name: 'channel', path: '/channel/:channel', component: Channel, props: true },
{ name: 'group', path: '/group/:group', component: Group, props: true },
{ name: 'thread', path: '/thread/:rootId', component: Thread, props: true },
{ name: 'profile', path: '/profile/:feedId', component: Profile, props: true },
{ name: 'notifications', path: '/notifications', component: Notifications },
Expand Down
89 changes: 87 additions & 2 deletions ui/channels.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
module.exports = function (componentsState) {
const pull = require('pull-stream')
const localPrefs = require('../localprefs')
const userGroups = require('../usergroups')
const { and, not, isPublic, type, channel, startFrom, paginate, descending, toCallback } = SSB.dbOperators

return {
template: `
<div id="channels">
<h2>{{ $t('channels.yourGroups') }}</h2>
<div>
<div v-for="group in groups">
<h4><router-link :to="{name: 'group', params: { group: group.id }}">{{ group.name }}</router-link> <a href="javascript:void(0)" v-on:click="deleteGroup(group)" title="Delete group" style="color: #900;">X</a></h4>
<ul class="groupMembers">
<li v-for="member in group.members">
<ssb-profile-link v-bind:key="member" v-bind:feedId="member"></ssb-profile-link>
</li>
</ul>
<div class="clearingDiv"></div>
</div>
<input type="text" v-model="groupName" :placeholder="$t('channels.newGroupName')" />&nbsp;<button class="clickButton" v-on:click="addGroup">{{ $t('channels.addGroup') }}</button>
</div>
<h2>{{ $t('channels.title') }}</h2>
<div v-if="favoriteChannels.length > 0">
<h3>{{ $t('channels.favoriteChannels') }}</h3>
Expand All @@ -24,26 +38,97 @@ module.exports = function (componentsState) {
<ol>
<li v-for="(count, channel) in channels">
<router-link :to="{name: 'channel', params: { channel: channel }}">#{{ channel }}<sup>[&nbsp;{{ count }}&nbsp;]</sup></router-link>
</li>
</li>
</ol>
<p v-if="channels.length == 0">{{ $t('channels.loading') }}</p>
</div>`,

data: function() {
return {
channels: [],
favoriteChannels: [],
favoriteChannels: [],
groups: [],
groupName: '',
sortMode: "recent"
}
},

methods: {
groupMemberInfoCallback: function(err, groupId, members) {
for (g in this.groups) {
if (this.groups[g].id == groupId) {
this.groups[g].members = members
return
}
}
},

loadGroups: function() {
var self = this
userGroups.getGroups((err, groups) => {
for (g in groups) {
var found = false
var fetchMembers = true
for (l in self.groups) {
if (groups[g].id == self.groups[l].id) {
found = true
if (self.groups[l].members && self.groups[l].members.length > 0) {
// Already have member info.
groups[g].members = self.groups[l].members
fetchMembers = false
}
}
}

if (!found) {
groups[g].members = []
self.groups.push(groups[g])
}
if (fetchMembers) {
userGroups.getMembers(groups[g].id, self.groupMemberInfoCallback)
}
}

// Normally I'd like to do this with a temporary variable and storing to the data variable once at the end, but in this case we've got too many potential member callbacks - complexity would be too high.
const sortFunc = (new Intl.Collator()).compare
self.groups = self.groups.sort((a, b) => { return sortFunc(a.name, b.name) })
})
},

addGroup: function() {
var self = this
userGroups.addGroup({ name: this.groupName }, (err, groupId) => {
if (err) {
alert(err)
} else {
self.loadGroups()
self.groupName = ''
}
})
},

deleteGroup: function(group) {
var self = this
if (confirm(this.$root.$t('channels.confirmDeleteGroup', { group: group.name }))) {
userGroups.deleteGroup(group.id, (err, success) => {
if (err)
alert(err)
else {
self.groups = []
self.loadGroups()
}
})
}
},

load: function() {
document.body.classList.add('refreshing')

// Get favorite channels from preferences.
this.favoriteChannels = localPrefs.getFavoriteChannels().map(x => x.replace(/^#+/, '')).sort(Intl.Collator().compare)

this.loadGroups()

console.time("channel list")

const resultCallback = toCallback((err, answer) => {
Expand Down
Loading

0 comments on commit 57a54c4

Please sign in to comment.