mirror of
https://github.com/thelounge/thelounge.git
synced 2024-05-17 21:56:36 +02:00
Add favoriting/pinning channels
This commit is contained in:
parent
f2a8d5aacc
commit
a8935376a1
|
@ -15,13 +15,27 @@
|
||||||
>
|
>
|
||||||
<span class="parted-channel-icon" />
|
<span class="parted-channel-icon" />
|
||||||
</span>
|
</span>
|
||||||
<span class="close-tooltip tooltipped tooltipped-w" aria-label="Leave">
|
<span
|
||||||
<button class="close" aria-label="Leave" @click.stop="close" />
|
class="close-tooltip tooltipped tooltipped-w"
|
||||||
|
:aria-label="channel.favorite ? 'Unfavorite' : 'Leave'"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="close"
|
||||||
|
:aria-label="channel.favorite ? 'Unfavorite' : 'Leave'"
|
||||||
|
@click.stop="close"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<span class="close-tooltip tooltipped tooltipped-w" aria-label="Close">
|
<span
|
||||||
<button class="close" aria-label="Close" @click.stop="close" />
|
class="close-tooltip tooltipped tooltipped-w"
|
||||||
|
:aria-label="channel.favorite ? 'Unfavorite' : 'Close'"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="close"
|
||||||
|
:aria-label="channel.favorite ? 'Unfavorite' : 'Close'"
|
||||||
|
@click.stop="close"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</ChannelWrapper>
|
</ChannelWrapper>
|
||||||
|
|
|
@ -57,6 +57,10 @@ export default {
|
||||||
const extra = [];
|
const extra = [];
|
||||||
const type = this.channel.type;
|
const type = this.channel.type;
|
||||||
|
|
||||||
|
if (this.channel.favorite) {
|
||||||
|
`favorited on ${this.network.name}`;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.channel.unread > 0) {
|
if (this.channel.unread > 0) {
|
||||||
if (this.channel.unread > 1) {
|
if (this.channel.unread > 1) {
|
||||||
extra.push(`${this.channel.unread} unread messages`);
|
extra.push(`${this.channel.unread} unread messages`);
|
||||||
|
|
|
@ -13,13 +13,13 @@
|
||||||
:id="'chan-' + channel.id"
|
:id="'chan-' + channel.id"
|
||||||
class="chat-view"
|
class="chat-view"
|
||||||
:data-type="channel.type"
|
:data-type="channel.type"
|
||||||
:aria-label="channel.name"
|
:aria-label="channel.displayName ? channel.displayName : channel.name"
|
||||||
role="tabpanel"
|
role="tabpanel"
|
||||||
>
|
>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<SidebarToggle />
|
<SidebarToggle />
|
||||||
<span class="title" :aria-label="'Currently open ' + channel.type">{{
|
<span class="title" :aria-label="'Currently open ' + channel.type">{{
|
||||||
channel.name
|
channel.displayName ? channel.displayName : channel.name
|
||||||
}}</span>
|
}}</span>
|
||||||
<div v-if="channel.editTopic === true" class="topic-container">
|
<div v-if="channel.editTopic === true" class="topic-container">
|
||||||
<input
|
<input
|
||||||
|
|
|
@ -4,31 +4,39 @@
|
||||||
<div class="lobby-wrap">
|
<div class="lobby-wrap">
|
||||||
<CollapseFavoritesButton :on-collapse-click="onCollapseClick" />
|
<CollapseFavoritesButton :on-collapse-click="onCollapseClick" />
|
||||||
<span title="Favorites" class="name">Favorites</span>
|
<span title="Favorites" class="name">Favorites</span>
|
||||||
<span v-if="unreadCount > 0" class="badge">{{ unreadCount }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-for="channel in $store.state.favoriteChannels" :key="channel.id">
|
<Draggable
|
||||||
<Channel
|
draggable=".channel-list-item"
|
||||||
:channel="channel"
|
ghost-class="ui-sortable-ghost"
|
||||||
:network="network"
|
drag-class="ui-sortable-dragging"
|
||||||
:is-filtering="false"
|
:group="network.uuid"
|
||||||
:active="
|
:list="channels"
|
||||||
$store.state.activeChannel && channel === $store.state.activeChannel.channel
|
:delay="longTouchDuration"
|
||||||
"
|
:delay-on-touch-only="true"
|
||||||
/>
|
:touch-start-threshold="10"
|
||||||
</div>
|
class="channels"
|
||||||
|
@choose="onDraggableChoose"
|
||||||
|
@unchoose="onDraggableUnchoose"
|
||||||
|
>
|
||||||
|
<template v-for="channel in channels">
|
||||||
|
<Channel
|
||||||
|
:key="channel.id"
|
||||||
|
:channel="channel"
|
||||||
|
:network="network"
|
||||||
|
:is-filtering="false"
|
||||||
|
:active="
|
||||||
|
$store.state.activeChannel && channel === $store.state.activeChannel.channel
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</Draggable>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.lobby-wrap {
|
|
||||||
display: flex;
|
|
||||||
/* margin-left: 40px; */
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script>
|
<script>
|
||||||
|
import Draggable from "vuedraggable";
|
||||||
import eventbus from "../js/eventbus";
|
import eventbus from "../js/eventbus";
|
||||||
import roundBadgeNumber from "../js/helpers/roundBadgeNumber";
|
|
||||||
import Channel from "./Channel.vue";
|
import Channel from "./Channel.vue";
|
||||||
import CollapseFavoritesButton from "./CollapseFavoritesButton.vue";
|
import CollapseFavoritesButton from "./CollapseFavoritesButton.vue";
|
||||||
|
|
||||||
|
@ -37,9 +45,13 @@ export default {
|
||||||
components: {
|
components: {
|
||||||
Channel,
|
Channel,
|
||||||
CollapseFavoritesButton,
|
CollapseFavoritesButton,
|
||||||
|
Draggable,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
channels: Array,
|
channels: Array,
|
||||||
|
onDraggableUnchoose: Function,
|
||||||
|
onDraggableChoose: Function,
|
||||||
|
longTouchDuration: Number,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
network() {
|
network() {
|
||||||
|
@ -52,7 +64,6 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
onCollapseClick() {
|
onCollapseClick() {
|
||||||
this.$store.commit("toggleFavorites");
|
this.$store.commit("toggleFavorites");
|
||||||
|
@ -63,13 +74,6 @@ export default {
|
||||||
channel: this.channel,
|
channel: this.channel,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
unreadCount() {
|
|
||||||
const unread = this.channels.reduce((acc, channel) => {
|
|
||||||
return acc + channel.unread || 0;
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
return roundBadgeNumber(unread);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -80,7 +80,12 @@
|
||||||
role="region"
|
role="region"
|
||||||
aria-live="polite"
|
aria-live="polite"
|
||||||
>
|
>
|
||||||
<Favorites :channels="$store.state.favoriteChannels" />
|
<Favorites
|
||||||
|
:channels="$store.state.favoriteChannels"
|
||||||
|
:long-touch-duration="LONG_TOUCH_DURATION"
|
||||||
|
:on-draggable-unchoose="onDraggableUnchoose"
|
||||||
|
:on-draggable-choose="onDraggableChoose"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-for="network in $store.state.networks"
|
v-for="network in $store.state.networks"
|
||||||
|
@ -277,8 +282,6 @@ export default {
|
||||||
Mousetrap.bind("alt+shift+right", this.expandNetwork);
|
Mousetrap.bind("alt+shift+right", this.expandNetwork);
|
||||||
Mousetrap.bind("alt+shift+left", this.collapseNetwork);
|
Mousetrap.bind("alt+shift+left", this.collapseNetwork);
|
||||||
Mousetrap.bind("alt+j", this.toggleSearch);
|
Mousetrap.bind("alt+j", this.toggleSearch);
|
||||||
|
|
||||||
console.log(this.$store.state.favoriteChannels[0]);
|
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
Mousetrap.unbind("alt+shift+right", this.expandNetwork);
|
Mousetrap.unbind("alt+shift+right", this.expandNetwork);
|
||||||
|
|
|
@ -372,6 +372,8 @@ p {
|
||||||
.context-menu-clear-favorites::before,
|
.context-menu-clear-favorites::before,
|
||||||
.context-menu-clear-history::before { content: "\f1f8"; /* https://fontawesome.com/icons/trash?style=solid */ }
|
.context-menu-clear-history::before { content: "\f1f8"; /* https://fontawesome.com/icons/trash?style=solid */ }
|
||||||
.context-menu-mute::before { content: "\f6a9"; /* https://fontawesome.com/v5.15/icons/volume-mute?style=solid */ }
|
.context-menu-mute::before { content: "\f6a9"; /* https://fontawesome.com/v5.15/icons/volume-mute?style=solid */ }
|
||||||
|
.context-menu-favorite::before { content: "\f005"; /* http://fontawesome.io/icon/star/ */ }
|
||||||
|
|
||||||
|
|
||||||
.channel-list-item .not-secure-icon::before {
|
.channel-list-item .not-secure-icon::before {
|
||||||
content: "\f071"; /* https://fontawesome.com/icons/exclamation-triangle?style=solid */
|
content: "\f071"; /* https://fontawesome.com/icons/exclamation-triangle?style=solid */
|
||||||
|
@ -510,6 +512,7 @@ p {
|
||||||
color: #2ecc40;
|
color: #2ecc40;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#chat .msg[data-type="action"] .from::before {
|
#chat .msg[data-type="action"] .from::before {
|
||||||
content: "\f005"; /* http://fontawesome.io/icon/star/ */
|
content: "\f005"; /* http://fontawesome.io/icon/star/ */
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,9 +97,9 @@ export function generateChannelContextMenu($root, channel, network) {
|
||||||
class: "favorite",
|
class: "favorite",
|
||||||
action() {
|
action() {
|
||||||
if (channel.favorite) {
|
if (channel.favorite) {
|
||||||
socket.emit("favorites:remove", channel.id);
|
socket.emit("favorites:remove", Number(channel.id));
|
||||||
} else {
|
} else {
|
||||||
socket.emit("favorites:add", channel.id);
|
socket.emit("favorites:add", Number(channel.id));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -210,7 +210,6 @@ export function generateChannelContextMenu($root, channel, network) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add close menu item
|
|
||||||
items.push({
|
items.push({
|
||||||
label: closeMap[channel.type],
|
label: closeMap[channel.type],
|
||||||
type: "item",
|
type: "item",
|
||||||
|
|
|
@ -4,7 +4,5 @@ import socket from "../socket";
|
||||||
import store from "../store";
|
import store from "../store";
|
||||||
|
|
||||||
socket.on("favorites", function (data) {
|
socket.on("favorites", function (data) {
|
||||||
console.log("favorites", data);
|
|
||||||
|
|
||||||
store.commit("favoriteChannels", data.favoriteChannels);
|
store.commit("favoriteChannels", data.favoriteChannels);
|
||||||
});
|
});
|
||||||
|
|
|
@ -132,7 +132,6 @@ const store = new Vuex.Store({
|
||||||
state.messageSearchResults = value;
|
state.messageSearchResults = value;
|
||||||
},
|
},
|
||||||
favoriteChannels(state, payload) {
|
favoriteChannels(state, payload) {
|
||||||
console.log("payload", payload);
|
|
||||||
state.favoriteChannels.forEach((channel) => {
|
state.favoriteChannels.forEach((channel) => {
|
||||||
channel.favorite = false;
|
channel.favorite = false;
|
||||||
channel.displayName = "";
|
channel.displayName = "";
|
||||||
|
@ -159,7 +158,7 @@ const store = new Vuex.Store({
|
||||||
);
|
);
|
||||||
|
|
||||||
netChan.channel.displayName =
|
netChan.channel.displayName =
|
||||||
netChan.channel.name + `(${netChan.network.name})`;
|
netChan.channel.name + ` (${netChan.network.name})`;
|
||||||
|
|
||||||
otherNetChan.channel.displayName =
|
otherNetChan.channel.displayName =
|
||||||
otherNetChan.channel.name + ` (${otherNetChan.network.name})`;
|
otherNetChan.channel.name + ` (${otherNetChan.network.name})`;
|
||||||
|
|
|
@ -50,16 +50,16 @@ new Vue({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
} else if (channel.favorite) {
|
||||||
|
socket.emit("favorites:remove", Number(channel.id));
|
||||||
|
} else {
|
||||||
|
channel.closed = true;
|
||||||
|
|
||||||
return;
|
socket.emit("input", {
|
||||||
|
target: Number(channel.id),
|
||||||
|
text: "/close",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.closed = true;
|
|
||||||
|
|
||||||
socket.emit("input", {
|
|
||||||
target: Number(channel.id),
|
|
||||||
text: "/close",
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
render(createElement) {
|
render(createElement) {
|
||||||
|
|
|
@ -120,18 +120,7 @@ function Client(manager, name, config = {}) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
(client.config.networks || []).forEach((network) => {
|
(client.config.networks || []).forEach((network) => client.connect(network, true));
|
||||||
client.connect(network, true);
|
|
||||||
|
|
||||||
for (const chan of network.channels) {
|
|
||||||
if (chan.favorite) {
|
|
||||||
// third argument is whether to save or not;
|
|
||||||
// we don't need to here as the config is loaded from the filesystem
|
|
||||||
console.log(network.uuid, chan.id);
|
|
||||||
client.addToFavorites(network.uuid, chan.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Networks are stored directly in the client object
|
// Networks are stored directly in the client object
|
||||||
// We don't need to keep it in the config object
|
// We don't need to keep it in the config object
|
||||||
|
@ -215,6 +204,7 @@ Client.prototype.connect = function (args, isStartup = false) {
|
||||||
key: chan.key || "",
|
key: chan.key || "",
|
||||||
type: chan.type,
|
type: chan.type,
|
||||||
muted: chan.muted,
|
muted: chan.muted,
|
||||||
|
favorite: chan.favorite,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -308,6 +298,15 @@ Client.prototype.connect = function (args, isStartup = false) {
|
||||||
client.save();
|
client.save();
|
||||||
channels.forEach((channel) => channel.loadMessages(client, network));
|
channels.forEach((channel) => channel.loadMessages(client, network));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
channels.forEach((chan) => {
|
||||||
|
if (chan.favorite) {
|
||||||
|
// The third argument for addToFavorites is whether to save,
|
||||||
|
// we will only be adding in this case if the favorite is loaded from disk,
|
||||||
|
// so we can safely set it to false.
|
||||||
|
this.addToFavorites(network.uuid, chan.id, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Client.prototype.generateToken = function (callback) {
|
Client.prototype.generateToken = function (callback) {
|
||||||
|
@ -666,7 +665,7 @@ Client.prototype.part = function (network, chan) {
|
||||||
const client = this;
|
const client = this;
|
||||||
network.channels = _.without(network.channels, chan);
|
network.channels = _.without(network.channels, chan);
|
||||||
client.mentions = client.mentions.filter((msg) => !(msg.chanId === chan.id));
|
client.mentions = client.mentions.filter((msg) => !(msg.chanId === chan.id));
|
||||||
client.favoriteChannels = client.favoriteChannels.filter((fav) => fav.id !== chan.id);
|
client.favoriteChannels = client.favoriteChannels.filter((fav) => fav.channelId !== chan.id);
|
||||||
chan.destroy();
|
chan.destroy();
|
||||||
client.save();
|
client.save();
|
||||||
client.emit("part", {
|
client.emit("part", {
|
||||||
|
|
Loading…
Reference in a new issue