Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add favoriting/pinning channels #4556

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
27 changes: 22 additions & 5 deletions client/components/Channel.vue
@@ -1,6 +1,6 @@
<template>
<ChannelWrapper ref="wrapper" v-bind="$props">
<span class="name">{{ channel.name }}</span>
<span class="name">{{ name() }}</span>
<span
v-if="channel.unread"
:class="{highlight: channel.highlight && !channel.muted}"
Expand All @@ -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>
Expand Down Expand Up @@ -51,6 +65,9 @@ export default {
close() {
this.$root.closeChannel(this.channel);
},
name() {
return this.channel.displayName ? this.channel.displayName : this.channel.name;
},
},
};
</script>
4 changes: 4 additions & 0 deletions client/components/ChannelWrapper.vue
Expand Up @@ -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`);
Expand Down
4 changes: 2 additions & 2 deletions client/components/Chat.vue
Expand Up @@ -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
Expand Down
27 changes: 27 additions & 0 deletions client/components/CollapseButton.css
@@ -0,0 +1,27 @@
.collapse-network {
width: 40px;
opacity: 0.4;
padding-left: 11px;
transition: opacity 0.2s;
flex-shrink: 0;
}

.collapse-network-icon {
display: block;
width: 20px;
height: 20px;
transition: transform 0.2s;
}

.network.collapsed .collapse-network-icon {
transform: rotate(-90deg);
}

.collapse-network-icon::before {
content: "\f0d7"; /* http://fontawesome.io/icon/caret-down/ */
color: #fff;
}

.collapse-network:hover {
opacity: 1;
}
36 changes: 36 additions & 0 deletions client/components/CollapseFavoritesButton.vue
@@ -0,0 +1,36 @@
<template>
<button
v-if="favorites.length > 0"
:aria-label="getExpandLabel()"
:aria-expanded="isCollapsed"
class="collapse-network"
@click.stop="onCollapseClick"
>
<span class="collapse-network-icon" />
</button>
<span v-else class="collapse-network" />
</template>

<style scoped>
@import "./CollapseButton.css";
</style>

<script>
export default {
name: "CollapseFavoritesButton",
props: {
onCollapseClick: Function,
},
data() {
return {
favorites: this.$store.state.favoriteChannels,
isCollapsed: !this.$store.state.favoritesOpen,
};
},
methods: {
getExpandLabel() {
return this.isCollapsed ? "Expand" : "Collapse";
},
},
};
</script>
32 changes: 32 additions & 0 deletions client/components/CollapseNetworkButton.vue
@@ -0,0 +1,32 @@
<template>
<button
v-if="network.channels.length > 1"
:aria-controls="'network-' + network.uuid"
:aria-label="getExpandLabel(network)"
:aria-expanded="!network.isCollapsed"
class="collapse-network"
@click.stop="onCollapseClick"
>
<span class="collapse-network-icon" />
</button>
<span v-else class="collapse-network" />
</template>

<style scoped>
@import "./CollapseButton.css";
</style>

<script>
export default {
name: "CollapseNetworkButton",
props: {
network: Object,
onCollapseClick: Function,
},
methods: {
getExpandLabel(network) {
return network.isCollapsed ? "Expand" : "Collapse";
},
},
};
</script>
7 changes: 7 additions & 0 deletions client/components/ContextMenu.vue
Expand Up @@ -43,6 +43,7 @@ import {
generateUserContextMenu,
generateChannelContextMenu,
generateInlineChannelContextMenu,
generateFavoritesContextMenu,
} from "../js/helpers/contextMenu.js";
import eventbus from "../js/eventbus";

Expand Down Expand Up @@ -70,13 +71,15 @@ export default {
eventbus.on("contextmenu:user", this.openUserContextMenu);
eventbus.on("contextmenu:channel", this.openChannelContextMenu);
eventbus.on("contextmenu:inline-channel", this.openInlineChannelContextMenu);
eventbus.on("contextmenu:favorites", this.openFavoritesContextMenu);
},
destroyed() {
eventbus.off("escapekey", this.close);
eventbus.off("contextmenu:cancel", this.close);
eventbus.off("contextmenu:user", this.openUserContextMenu);
eventbus.off("contextmenu:channel", this.openChannelContextMenu);
eventbus.off("contextmenu:inline-channel", this.openInlineChannelContextMenu);
eventbus.off("contextmenu:favorites", this.openFavoritesContextMenu);

this.close();
},
Expand Down Expand Up @@ -119,6 +122,10 @@ export default {
);
this.open(data.event, items);
},
openFavoritesContextMenu(data) {
const items = generateFavoritesContextMenu();
this.open(data.event, items);
},
open(event, items) {
event.preventDefault();

Expand Down
79 changes: 79 additions & 0 deletions client/components/Favorites.vue
@@ -0,0 +1,79 @@
<template>
<div class="favorites">
<div class="channel-list-item" data-type="lobby" @contextmenu.prevent="openContextMenu">
<div class="lobby-wrap">
<CollapseFavoritesButton :on-collapse-click="onCollapseClick" />
<span title="Favorites" class="name">Favorites</span>
</div>
</div>
<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"
:active="
$store.state.activeChannel && channel === $store.state.activeChannel.channel
"
/>
</template>
</Draggable>
</div>
</template>

<script>
import Draggable from "vuedraggable";
import eventbus from "../js/eventbus";
import Channel from "./Channel.vue";
import CollapseFavoritesButton from "./CollapseFavoritesButton.vue";

export default {
name: "Favorites",
components: {
Channel,
CollapseFavoritesButton,
Draggable,
},
props: {
channels: Array,
onDraggableUnchoose: Function,
onDraggableChoose: Function,
longTouchDuration: Number,
},
computed: {
network() {
return {
isCollapsed: !this.$store.state.favoritesOpen,
status: {
connected: true,
secure: true,
},
};
},
},
methods: {
onCollapseClick() {
this.$store.commit("toggleFavorites");
},
openContextMenu(event) {
eventbus.emit("contextmenu:favorites", {
event: event,
channel: this.channel,
});
},
},
};
</script>
23 changes: 21 additions & 2 deletions client/components/NetworkList.vue
Expand Up @@ -69,6 +69,24 @@
@choose="onDraggableChoose"
@unchoose="onDraggableUnchoose"
>
<div
v-if="$store.state.favoriteChannels.length"
id="favorites"
aria-label="Favorite channels"
class="network"
:class="{
collapsed: !$store.state.favoritesOpen,
}"
role="region"
aria-live="polite"
>
<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"
:id="'network-' + network.uuid"
Expand Down Expand Up @@ -101,7 +119,6 @@
:channel="network.channels[0]"
@toggle-join-channel="network.isJoinChannelShown = !network.isJoinChannelShown"
/>

<Draggable
draggable=".channel-list-item"
ghost-class="ui-sortable-ghost"
Expand All @@ -118,7 +135,7 @@
>
<template v-for="(channel, index) in network.channels">
<Channel
v-if="index > 0"
v-if="index > 0 && !channel.favorite"
:key="channel.id"
:channel="channel"
:network="network"
Expand Down Expand Up @@ -200,6 +217,7 @@ import Mousetrap from "mousetrap";
import Draggable from "vuedraggable";
import {filter as fuzzyFilter} from "fuzzy";
import NetworkLobby from "./NetworkLobby.vue";
import Favorites from "./Favorites.vue";
import Channel from "./Channel.vue";
import JoinChannel from "./JoinChannel.vue";

Expand All @@ -216,6 +234,7 @@ export default {
NetworkLobby,
Channel,
Draggable,
Favorites,
},
data() {
return {
Expand Down
17 changes: 3 additions & 14 deletions client/components/NetworkLobby.vue
@@ -1,16 +1,6 @@
<template>
<ChannelWrapper v-bind="$props" :channel="channel">
<button
v-if="network.channels.length > 1"
:aria-controls="'network-' + network.uuid"
:aria-label="getExpandLabel(network)"
:aria-expanded="!network.isCollapsed"
class="collapse-network"
@click.stop="onCollapseClick"
>
<span class="collapse-network-icon" />
</button>
<span v-else class="collapse-network" />
<CollapseNetworkButton :network="network" :on-collapse-click="onCollapseClick" />
<div class="lobby-wrap">
<span :title="channel.name" class="name">{{ channel.name }}</span>
<span
Expand Down Expand Up @@ -49,11 +39,13 @@
import collapseNetwork from "../js/helpers/collapseNetwork";
import roundBadgeNumber from "../js/helpers/roundBadgeNumber";
import ChannelWrapper from "./ChannelWrapper.vue";
import CollapseNetworkButton from "./CollapseNetworkButton.vue";

export default {
name: "Channel",
components: {
ChannelWrapper,
CollapseNetworkButton,
},
props: {
network: Object,
Expand All @@ -76,9 +68,6 @@ export default {
onCollapseClick() {
collapseNetwork(this.network, !this.network.isCollapsed);
},
getExpandLabel(network) {
return network.isCollapsed ? "Expand" : "Collapse";
},
},
};
</script>