mirror of
https://github.com/thelounge/thelounge.git
synced 2024-06-08 08:42:17 +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>
|
||||
<span class="close-tooltip tooltipped tooltipped-w" aria-label="Leave">
|
||||
<button class="close" aria-label="Leave" @click.stop="close" />
|
||||
<span
|
||||
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>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="close-tooltip tooltipped tooltipped-w" aria-label="Close">
|
||||
<button class="close" aria-label="Close" @click.stop="close" />
|
||||
<span
|
||||
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>
|
||||
</template>
|
||||
</ChannelWrapper>
|
||||
|
|
|
@ -57,6 +57,10 @@ export default {
|
|||
const extra = [];
|
||||
const type = this.channel.type;
|
||||
|
||||
if (this.channel.favorite) {
|
||||
`favorited on ${this.network.name}`;
|
||||
}
|
||||
|
||||
if (this.channel.unread > 0) {
|
||||
if (this.channel.unread > 1) {
|
||||
extra.push(`${this.channel.unread} unread messages`);
|
||||
|
|
|
@ -13,13 +13,13 @@
|
|||
:id="'chan-' + channel.id"
|
||||
class="chat-view"
|
||||
:data-type="channel.type"
|
||||
:aria-label="channel.name"
|
||||
:aria-label="channel.displayName ? channel.displayName : channel.name"
|
||||
role="tabpanel"
|
||||
>
|
||||
<div class="header">
|
||||
<SidebarToggle />
|
||||
<span class="title" :aria-label="'Currently open ' + channel.type">{{
|
||||
channel.name
|
||||
channel.displayName ? channel.displayName : channel.name
|
||||
}}</span>
|
||||
<div v-if="channel.editTopic === true" class="topic-container">
|
||||
<input
|
||||
|
|
|
@ -4,11 +4,24 @@
|
|||
<div class="lobby-wrap">
|
||||
<CollapseFavoritesButton :on-collapse-click="onCollapseClick" />
|
||||
<span title="Favorites" class="name">Favorites</span>
|
||||
<span v-if="unreadCount > 0" class="badge">{{ unreadCount }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-for="channel in $store.state.favoriteChannels" :key="channel.id">
|
||||
<Draggable
|
||||
draggable=".channel-list-item"
|
||||
ghost-class="ui-sortable-ghost"
|
||||
drag-class="ui-sortable-dragging"
|
||||
:group="network.uuid"
|
||||
:list="channels"
|
||||
:delay="longTouchDuration"
|
||||
:delay-on-touch-only="true"
|
||||
:touch-start-threshold="10"
|
||||
class="channels"
|
||||
@choose="onDraggableChoose"
|
||||
@unchoose="onDraggableUnchoose"
|
||||
>
|
||||
<template v-for="channel in channels">
|
||||
<Channel
|
||||
:key="channel.id"
|
||||
:channel="channel"
|
||||
:network="network"
|
||||
:is-filtering="false"
|
||||
|
@ -16,19 +29,14 @@
|
|||
$store.state.activeChannel && channel === $store.state.activeChannel.channel
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</Draggable>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.lobby-wrap {
|
||||
display: flex;
|
||||
/* margin-left: 40px; */
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
import Draggable from "vuedraggable";
|
||||
import eventbus from "../js/eventbus";
|
||||
import roundBadgeNumber from "../js/helpers/roundBadgeNumber";
|
||||
import Channel from "./Channel.vue";
|
||||
import CollapseFavoritesButton from "./CollapseFavoritesButton.vue";
|
||||
|
||||
|
@ -37,9 +45,13 @@ export default {
|
|||
components: {
|
||||
Channel,
|
||||
CollapseFavoritesButton,
|
||||
Draggable,
|
||||
},
|
||||
props: {
|
||||
channels: Array,
|
||||
onDraggableUnchoose: Function,
|
||||
onDraggableChoose: Function,
|
||||
longTouchDuration: Number,
|
||||
},
|
||||
computed: {
|
||||
network() {
|
||||
|
@ -52,7 +64,6 @@ export default {
|
|||
};
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
onCollapseClick() {
|
||||
this.$store.commit("toggleFavorites");
|
||||
|
@ -63,13 +74,6 @@ export default {
|
|||
channel: this.channel,
|
||||
});
|
||||
},
|
||||
unreadCount() {
|
||||
const unread = this.channels.reduce((acc, channel) => {
|
||||
return acc + channel.unread || 0;
|
||||
}, 0);
|
||||
|
||||
return roundBadgeNumber(unread);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -80,7 +80,12 @@
|
|||
role="region"
|
||||
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
|
||||
v-for="network in $store.state.networks"
|
||||
|
@ -277,8 +282,6 @@ export default {
|
|||
Mousetrap.bind("alt+shift+right", this.expandNetwork);
|
||||
Mousetrap.bind("alt+shift+left", this.collapseNetwork);
|
||||
Mousetrap.bind("alt+j", this.toggleSearch);
|
||||
|
||||
console.log(this.$store.state.favoriteChannels[0]);
|
||||
},
|
||||
beforeDestroy() {
|
||||
Mousetrap.unbind("alt+shift+right", this.expandNetwork);
|
||||
|
|
|
@ -372,6 +372,8 @@ p {
|
|||
.context-menu-clear-favorites::before,
|
||||
.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-favorite::before { content: "\f005"; /* http://fontawesome.io/icon/star/ */ }
|
||||
|
||||
|
||||
.channel-list-item .not-secure-icon::before {
|
||||
content: "\f071"; /* https://fontawesome.com/icons/exclamation-triangle?style=solid */
|
||||
|
@ -510,6 +512,7 @@ p {
|
|||
color: #2ecc40;
|
||||
}
|
||||
|
||||
|
||||
#chat .msg[data-type="action"] .from::before {
|
||||
content: "\f005"; /* http://fontawesome.io/icon/star/ */
|
||||
}
|
||||
|
|
|
@ -97,9 +97,9 @@ export function generateChannelContextMenu($root, channel, network) {
|
|||
class: "favorite",
|
||||
action() {
|
||||
if (channel.favorite) {
|
||||
socket.emit("favorites:remove", channel.id);
|
||||
socket.emit("favorites:remove", Number(channel.id));
|
||||
} 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({
|
||||
label: closeMap[channel.type],
|
||||
type: "item",
|
||||
|
|
|
@ -4,7 +4,5 @@ import socket from "../socket";
|
|||
import store from "../store";
|
||||
|
||||
socket.on("favorites", function (data) {
|
||||
console.log("favorites", data);
|
||||
|
||||
store.commit("favoriteChannels", data.favoriteChannels);
|
||||
});
|
||||
|
|
|
@ -132,7 +132,6 @@ const store = new Vuex.Store({
|
|||
state.messageSearchResults = value;
|
||||
},
|
||||
favoriteChannels(state, payload) {
|
||||
console.log("payload", payload);
|
||||
state.favoriteChannels.forEach((channel) => {
|
||||
channel.favorite = false;
|
||||
channel.displayName = "";
|
||||
|
|
|
@ -50,16 +50,16 @@ new Vue({
|
|||
});
|
||||
}
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
} else if (channel.favorite) {
|
||||
socket.emit("favorites:remove", Number(channel.id));
|
||||
} else {
|
||||
channel.closed = true;
|
||||
|
||||
socket.emit("input", {
|
||||
target: Number(channel.id),
|
||||
text: "/close",
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
render(createElement) {
|
||||
|
|
|
@ -120,18 +120,7 @@ function Client(manager, name, config = {}) {
|
|||
}
|
||||
});
|
||||
|
||||
(client.config.networks || []).forEach((network) => {
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
(client.config.networks || []).forEach((network) => client.connect(network, true));
|
||||
|
||||
// Networks are stored directly in the client 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 || "",
|
||||
type: chan.type,
|
||||
muted: chan.muted,
|
||||
favorite: chan.favorite,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
@ -308,6 +298,15 @@ Client.prototype.connect = function (args, isStartup = false) {
|
|||
client.save();
|
||||
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) {
|
||||
|
@ -666,7 +665,7 @@ Client.prototype.part = function (network, chan) {
|
|||
const client = this;
|
||||
network.channels = _.without(network.channels, chan);
|
||||
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();
|
||||
client.save();
|
||||
client.emit("part", {
|
||||
|
|
Loading…
Reference in a new issue