indieHeader.vue 5.96 KB
Newer Older
1
<template>
2
3
  <header>
    <div class='profile' :style='headerStyles'>
Aral Balkan's avatar
Aral Balkan committed
4

5
      <!-- Profile image -->
6
      <img class='profile-image' v-if='profileImage' :src='profileImage' alt='Profile image'>
Aral Balkan's avatar
Aral Balkan committed
7

8
      <!-- Name and bio and, if signed out, the remote follow button -->
Aral Balkan's avatar
Aral Balkan committed
9
10
11
      <div class='profile-information'>
        <h1 class='profile-name'>{{name}}</h1>
        <p class='profile-bio'>{{bio}}</p>
12
        <button v-if='!signedIn && configured' id='follow-button' @click='followButtonPress' class='button'>Follow</button>
13
      </div>
14
15
16
    </div>

    <!-- Main navigation -->
17
    <nav class='tabs is-centered'>
18
      <ul>
Aral Balkan's avatar
Aral Balkan committed
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
        <li :class='classesForRoute("/")'>
          <nuxt-link to='/'>Me</nuxt-link>
        </li>
        <li :class='classesForRoute("/everyone")'>
          <nuxt-link to='/everyone'>Everyone</nuxt-link>
        </li>
        <li :class='classesForRoute("/search")'>
          <nuxt-link to='/search'>Search</nuxt-link>
        </li>
        <li :class='classesForRoute("/settings")' v-show='signedIn || !configured'>
          <nuxt-link to='/settings'>Settings</nuxt-link>
        </li>
        <li :class='classesForRoute("/more")' v-show='signedIn || !configured'>
          <nuxt-link to='/more'></nuxt-link>
        </li>
34
35
      </ul>
    </nav>
Aral Balkan's avatar
Aral Balkan committed
36

37
38
39
    <!-- Remote follow modal -->
    <follow-modal :isActive='followModalActive' @close='followModalActive = false' />

40
  </header>
41
42
43
</template>

<script>
Aral Balkan's avatar
Aral Balkan committed
44

45
46
import followModal from '~/components/followModal'

47
export default {
48
49
50
  components: {
    followModal
  },
Aral Balkan's avatar
Aral Balkan committed
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
  mounted () {
    // Set the route to Settings if the site is not configured.
    if (!this.configured) {
      this.$router.push('settings')
      return
    }

    //
    // Check that a path that requires person to be signed in isn’t
    // accessed. Note: this is a stopgap. We should be authenticating
    // on the server not here.
    //
    // TODO: Issue #22
    // https://source.ind.ie/indienet/site/issues/22
    //
    if (!this.signedIn) {
      const route = this.$router.history.current.path
      console.log(route)
      if (route === '/settings' || route === '/more') {
        this.$router.push('/')
      }
      return
    }
  },
  data () {
    return {
77
      followModalActive: false
Aral Balkan's avatar
Aral Balkan committed
78
79
    }
  },
80
  computed: {
Aral Balkan's avatar
Aral Balkan committed
81
82
83
84
85
86
87
88
89
90
91
92
    disablingCriteriaForRoutes () {
      return {
        '/': !this.configured,                // i.e., always enabled
        '/everyone': !this.configured,
        '/search': !this.configured,
        '/settings': false,
        '/more': !this.configured
      }
    },

    // Vuex Store

93
94
    name () { return this.$store.state.name },
    bio () { return this.$store.state.bio },
95
    profileImage () { return this.$store.state.profileImage },
96
    signedIn () { return this.$store.state.signedIn },
97
    configured () { return this.$store.state.configured },
Aral Balkan's avatar
Aral Balkan committed
98
99

    // Live header theming.
100
101
102
103
104
105
106
107
108
    headerStyles () {
      let styles = {
        backgroundColor: this.$store.state.backgroundColour
      }
      if (this.$store.state.backgroundImage) {
        styles.backgroundImage = `url('${this.$store.state.backgroundImage}')`
      }
      return styles
    }
109
  },
Aral Balkan's avatar
Aral Balkan committed
110
111
112
113
114
  watch: {
    $route: function () {
      console.log(`Header: Route changed to ${this.$route.path}.`)
    }
  },
115
  methods: {
Aral Balkan's avatar
Aral Balkan committed
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
    // Returns the correct tab class object for the passed route based on the
    // current route of the page that the header is rendering in.
    classesForRoute (route) {
      const classObject = {}

      // Is this the active tab?
      if (route === this.$route.path) classObject['is-active'] = true

      // Is this tab disabled?
      const disableTab = this.disablingCriteriaForRoutes[route]
      if (disableTab) classObject['disabled'] = true

      return classObject
    },

    // Signals that the follow button has been pressed.
132
    followButtonPress () {
133
      this.followModalActive = true
134
135
136
137
138
139
    }
  }
}
</script>

<style>
140
.profile {
141
142
  /* Note: the background colour and image are dynamically set on the
     header itself, based on the site configuration settings. */
143

Aral Balkan's avatar
Aral Balkan committed
144
145
  align-items: center;
  color: white;
146
  background-size: cover;
147
148

  /* Position relatively so contained items align to this container. */
Aral Balkan's avatar
Aral Balkan committed
149
150
151
152
  position: relative;
  padding: 1rem 1rem 0;
  text-align: center;
  width: 100%;
153
154
}

155
.profile-information {
Aral Balkan's avatar
Aral Balkan committed
156
  background-color: rgba(0,0,0,0.55);
157
158
159
  margin-top: 1rem;

  /* Offset background against padding on profile__material. */
Aral Balkan's avatar
Aral Balkan committed
160
161
162
  margin-right: -1rem;
  margin-left: -1rem;
  padding: 0.25rem 0;
163
164
}

165
.profile-name {
166
  font-size: 4rem;
167

168
  /* Numbered font weights won’t work in all browsers, will default to bold weight. */
169
  font-weight: 400;
170

Aral Balkan's avatar
Aral Balkan committed
171
  line-height: 1.2;
172
  margin: 0.5rem auto 0 auto;
173
174
175

  /* Same max-width as on main in default.vue. */
  max-width: 45rem;
176
177
  /* so text doesn’t bump against edges of viewport */
  padding: 0 0.5rem;
178
179
}

180
.profile-bio {
181
182
183
  font-size: 1.25rem;
  margin: 0.25rem auto 1rem auto;
  line-height: 1.25;
184
185
186

  /* Same max-width as on main in default.vue. */
  max-width: 45rem;
187
188
  /* so text doesn’t bump against edges of viewport */
  padding: 0 0.5rem;
189
190
}

191
.profile-image {
192
193
  background-size: cover;
  box-sizing: content-box;
194
195
  /* Make image circular with a white border. */
  border: 0.175rem solid white;
196
  border-radius: 50%;
Aral Balkan's avatar
Aral Balkan committed
197
  display: block;
198
199
  height: 10rem;
  width: 10rem;
Aral Balkan's avatar
Aral Balkan committed
200
201
  margin-right: auto;
  margin-left: auto;
202
203
204
  overflow: hidden;
}

205
#follow-button {
Aral Balkan's avatar
Aral Balkan committed
206
  position: absolute;
207
208
  top: 1rem;
  right: 1rem;
Aral Balkan's avatar
Aral Balkan committed
209
}
210

211
/* Main navigation. */
212
213

nav {
214
  margin-bottom: 1rem;
215
216
217
}

nav.tabs {
218
219
  /* Make navigation tab text bigger (ideally these should be h2s). */
  font-size: 1.5rem;
220

221
222
  /* Make navigation tabs taller. */
  line-height: 2.25;
223
224
225
226
227
228
229
230
231
}

.tabs ul {
  margin: 0;
}

.tabs li {
  margin-bottom: 0;
}
Aral Balkan's avatar
Aral Balkan committed
232
233
234
235
236
237
238

/*
  We cannot set both cursor: not-allowed and pointer-events: none on the same
  element (the cursor does not show). So, instead, we set the cursor on the
  parent li and turn off pointer events to disable the link for disabled tabs.
*/
.tabs li.disabled {
239
  cursor: not-allowed;
Aral Balkan's avatar
Aral Balkan committed
240
241
242
243
}

.tabs li.disabled > a {
  color: lightgray;
244
  pointer-events: none;
Aral Balkan's avatar
Aral Balkan committed
245
}
246
</style>