Skip to content

Commit d87a3b5

Browse files
authored
Merge pull request #51 from BinaryStudioAcademy/feature/top-menu
Feature/top menu
2 parents ea1c298 + 7f65ea7 commit d87a3b5

File tree

19 files changed

+212
-123
lines changed

19 files changed

+212
-123
lines changed

frontend/src/components/common/Navbar.vue

Lines changed: 86 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,42 @@
44
<a
55
role="button"
66
class="navbar-burger burger"
7+
:class="{ 'is-active': isMobileMenuActive }"
78
aria-label="menu"
89
aria-expanded="false"
9-
data-target="header-navbar"
10+
@click="toggleMobileMenu"
1011
>
1112
<span aria-hidden="true" />
1213
<span aria-hidden="true" />
1314
<span aria-hidden="true" />
1415
</a>
1516
</div>
1617

18+
<div class="navbar-menu is-hidden-desktop mobile-menu" :class="{ 'is-active': isMobileMenuActive }">
19+
<router-link class="navbar-item" :to="{ name: 'feed' }">
20+
<b-icon pack="fab" icon="twitter" />
21+
<span>Feed</span>
22+
</router-link>
23+
24+
<router-link class="navbar-item" :to="{ name: 'user-page', params: { id: user.id }}">
25+
<b-icon pack="fab" icon="twitter-square" />
26+
<span>My feed</span>
27+
</router-link>
28+
29+
<hr class="navbar-divider">
30+
31+
<router-link class="navbar-item" :to="{ name: 'profile' }">
32+
<b-icon pack="fa" icon="cog" />
33+
<span>Settings</span>
34+
</router-link>
35+
36+
37+
<a class="navbar-item" @click="onSignOut">
38+
<b-icon pack="fa" icon="sign-out-alt" />
39+
<span>Exit</span>
40+
</a>
41+
</div>
42+
1743
<div id="header-navbar" class="navbar-menu">
1844
<div class="navbar-start">
1945
<router-link class="navbar-item" to="/feed">
@@ -26,17 +52,32 @@
2652
</div>
2753

2854
<div class="navbar-end">
29-
<div class="navbar-item profile">
30-
<figure class="image is-32x32 is-square">
31-
<img
32-
v-if="user.avatar"
33-
class="profile-image is-rounded"
34-
:src="user.avatar"
35-
>
36-
<DefaultAvatar v-else class="image is-32x32" :user="user" />
37-
</figure>
38-
<span class="profile-name">{{ user.name }}</span>
39-
<span class="icon is-medium"><font-awesome-icon icon="angle-down" /></span>
55+
<div class="navbar-item has-dropdown is-hoverable profile">
56+
<a class="navbar-link">
57+
<figure class="image is-32x32 is-square">
58+
<img
59+
v-if="user.avatar"
60+
class="profile-image is-rounded"
61+
:src="user.avatar"
62+
>
63+
<DefaultAvatar v-else class="image is-32x32" :user="user" />
64+
</figure>
65+
<span class="profile-name">{{ user.name }}</span>
66+
</a>
67+
68+
<div class="navbar-dropdown is-right">
69+
<router-link class="navbar-item" :to="{ name: 'profile' }">
70+
<b-icon pack="fa" icon="cog" />
71+
<span>Settings</span>
72+
</router-link>
73+
74+
<hr class="navbar-divider">
75+
76+
<a class="navbar-item" @click="onSignOut">
77+
<b-icon pack="fa" icon="sign-out-alt" />
78+
<span>Exit</span>
79+
</a>
80+
</div>
4081
</div>
4182
</div>
4283
</div>
@@ -54,6 +95,10 @@ export default {
5495
DefaultAvatar,
5596
},
5697
98+
data: () => ({
99+
isMobileMenuActive: false
100+
}),
101+
57102
computed: {
58103
...mapGetters('auth', {
59104
user: 'getAuthenticatedUser'
@@ -67,8 +112,19 @@ export default {
67112
68113
methods: {
69114
...mapActions('auth', [
70-
'fetchAuthenticatedUser'
71-
])
115+
'fetchAuthenticatedUser',
116+
'signOut'
117+
]),
118+
119+
async onSignOut() {
120+
await this.signOut();
121+
122+
this.$router.push({ name: 'auth.signIn' });
123+
},
124+
125+
toggleMobileMenu() {
126+
this.isMobileMenuActive = !this.isMobileMenuActive;
127+
}
72128
}
73129
};
74130
</script>
@@ -77,7 +133,7 @@ export default {
77133
@import '../../styles/common';
78134
79135
.navbar {
80-
margin-bottom: 20px;
136+
margin-bottom: 30px;
81137
box-shadow: 5px 5px 5px 0 #00000020;
82138
}
83139
@@ -94,4 +150,19 @@ export default {
94150
padding-top: 0;
95151
}
96152
}
153+
154+
.mobile-menu {
155+
.navbar-item {
156+
display: flex;
157+
align-items: center;
158+
159+
.icon {
160+
margin-right: 10px;
161+
}
162+
163+
span:last-child {
164+
line-height: 1.588;
165+
}
166+
}
167+
}
97168
</style>

frontend/src/components/view/feed/TweetPreview.vue renamed to frontend/src/components/common/TweetPreview.vue

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
</template>
4646

4747
<script>
48-
import DefaultAvatar from '../../common/DefaultAvatar.vue';
48+
import DefaultAvatar from './DefaultAvatar.vue';
4949
5050
export default {
5151
name: 'TweetPreview',
@@ -64,13 +64,18 @@ export default {
6464
</script>
6565

6666
<style lang="scss" scoped>
67-
@import '../../../styles/common';
67+
@import '../../styles/common';
6868
6969
.tweet {
7070
cursor: pointer;
7171
padding: 15px;
7272
border-radius: 5px;
7373
box-shadow: 5px 5px 5px 0 #00000020;
74+
transition: 0.2s ease-out all;
75+
76+
&:hover {
77+
box-shadow: 1px 1px 0 0 #00000020;
78+
}
7479
7580
&-image {
7681
margin: 12px 0 0 0;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<template>
2+
<div class="tweets-container">
3+
<template v-for="tweet in tweets">
4+
<TweetPreview
5+
:key="tweet.id"
6+
:tweet="tweet"
7+
@click="onTweetClick"
8+
/>
9+
</template>
10+
</div>
11+
</template>
12+
13+
<script>
14+
import TweetPreview from './TweetPreview.vue';
15+
16+
export default {
17+
name: 'TweetPreviewList',
18+
19+
props: {
20+
tweets: {
21+
type: Array,
22+
required: true
23+
}
24+
},
25+
26+
components: {
27+
TweetPreview,
28+
},
29+
30+
methods: {
31+
onTweetClick(tweet) {
32+
this.$router.push({ name: 'tweet-page', params: { id: tweet.id } });
33+
},
34+
},
35+
};
36+
</script>
37+
38+
<style scoped lang="scss">
39+
.tweets-container {
40+
padding-bottom: 20px;
41+
}
42+
</style>
Lines changed: 14 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template>
2-
<div class="tweets-container">
2+
<div class="feed-container">
33
<div class="navigation">
44
<b-button
55
class="btn-add-tweet"
@@ -14,13 +14,7 @@
1414
</b-button>
1515
</div>
1616

17-
<template v-for="tweet in tweets">
18-
<TweetPreview
19-
:key="tweet.id"
20-
:tweet="tweet"
21-
@click="onTweetClick"
22-
/>
23-
</template>
17+
<TweetPreviewList :tweets="tweets" />
2418

2519
<b-modal :active.sync="isNewTweetModalActive" has-modal-card>
2620
<NewTweetForm />
@@ -30,14 +24,14 @@
3024

3125
<script>
3226
import { mapGetters, mapActions } from 'vuex';
33-
import TweetPreview from './TweetPreview.vue';
27+
import TweetPreviewList from '../../common/TweetPreviewList.vue';
3428
import NewTweetForm from './NewTweetForm.vue';
3529
3630
export default {
3731
name: 'FeedContainer',
3832
3933
components: {
40-
TweetPreview,
34+
TweetPreviewList,
4135
NewTweetForm,
4236
},
4337
@@ -67,41 +61,25 @@ export default {
6761
showAddTweetModal() {
6862
this.isNewTweetModalActive = true;
6963
},
70-
71-
onTweetClick(tweet) {
72-
this.$router.push({ name: 'tweet-page', params: { id: tweet.id } });
73-
},
7464
},
7565
};
7666
</script>
7767

7868
<style scoped lang="scss">
7969
@import '~bulma/sass/utilities/initial-variables';
8070
81-
.tweets-container {
82-
padding-bottom: 20px;
83-
84-
.tweet {
85-
transition: 0.2s ease-out all;
86-
87-
&:hover {
88-
box-shadow: 1px 1px 0 0 #00000020;
89-
}
90-
}
91-
92-
.navigation {
93-
padding: 10px 0;
94-
margin-bottom: 20px;
95-
}
71+
.navigation {
72+
padding: 10px 0;
73+
margin-bottom: 20px;
74+
}
9675
97-
.modal-card {
98-
border-radius: 6px;
99-
}
76+
.modal-card {
77+
border-radius: 6px;
78+
}
10079
101-
.btn-add-tweet {
102-
@media screen and (max-width: $tablet) {
103-
font-size: 1rem;
104-
}
80+
.btn-add-tweet {
81+
@media screen and (max-width: $tablet) {
82+
font-size: 1rem;
10583
}
10684
}
10785
</style>

frontend/src/components/view/tweet/Tweet.vue

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ import Comment from './Comment.vue';
7171
import NewCommentForm from './NewCommentForm.vue';
7272
import EditTweetForm from './EditTweetForm.vue';
7373
import DefaultAvatar from '../../common/DefaultAvatar.vue';
74+
import showStatusToast from '../../mixin/showStatusToast';
7475
7576
export default {
7677
name: 'Tweet',
@@ -82,6 +83,8 @@ export default {
8283
DefaultAvatar,
8384
},
8485
86+
mixins: [showStatusToast],
87+
8588
props: {
8689
tweet: {
8790
type: Object,
@@ -131,16 +134,16 @@ export default {
131134
message: 'Are you sure you want to <b>delete</b> your tweet? This action cannot be undone.',
132135
confirmText: 'Delete Tweet',
133136
type: 'is-danger',
137+
134138
onConfirm: async () => {
135139
try {
136140
await this.deleteTweet(this.tweet.id);
137-
this.$toast.open('Tweet deleted!');
141+
142+
this.showSuccessMessage('Tweet deleted!');
143+
138144
this.$router.push({ name: 'feed' });
139145
} catch {
140-
this.$toast.open({
141-
message: 'Unable to delete tweet!',
142-
type: 'is-danger',
143-
});
146+
this.showErrorMessage('Unable to delete tweet!');
144147
}
145148
}
146149
});

frontend/src/components/view/tweet/TweetContainer.vue

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
<template>
2-
<div class="container">
3-
<Tweet v-if="tweet" :tweet="tweet" />
4-
</div>
2+
<Tweet v-if="tweet" :tweet="tweet" />
53
</template>
64

75
<script>
@@ -38,7 +36,4 @@ export default {
3836
</script>
3937

4038
<style scoped lang="scss">
41-
.container {
42-
max-width: 960px;
43-
}
4439
</style>

0 commit comments

Comments
 (0)