Skip to content

Commit d127b40

Browse files
feat: add footer (#618)
* add footer draft, reorg components * first stab at footer layout * update links, add id to contact section * fix syntax error * fix: keep hash when removing trailing slash * improve layout * line height and copyright alignment * more styling * incorporate design feedback * enable translations for footer * font size & automagic columns * fix computed prop * fix sticky footer * fix: lint errors * fix linting errors * footer links to 1rem * update top margin and padding * Update src/components/layout/Footer.vue Co-authored-by: Zé Bateira <[email protected]> * Update src/components/layout/Footer.vue Co-authored-by: Zé Bateira <[email protected]> * remove failling test Co-authored-by: Ze Bateira <[email protected]>
1 parent cbe663d commit d127b40

File tree

18 files changed

+230
-35
lines changed

18 files changed

+230
-35
lines changed

cypress/integration/footer.spec.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const pages = ['/', '/events', '/content-addressing', 'content-addressing/02']
2+
3+
// renders footer on all sample pages
4+
describe(`DISPLAYS FOOTER ON EACH PAGE TYPE`, function () {
5+
for (const page of pages) {
6+
it(`renders footer at ${page}`, function () {
7+
cy.visit(`${page}`) // loads specified page
8+
cy.get('[data-cy="footer-component"]') // loads footer component
9+
})
10+
}
11+
})
12+
13+
describe(`OPENS LINKS IN CORRECT WINDOWS`, function () {
14+
it(`opens internal link`, function () {
15+
cy.visit('/')
16+
cy.get('[data-cy="footer-link-internal"]').contains('News').click() // click internal News link
17+
cy.get('h1').contains('Newsletter') // because Cypress can't switch to new window, this proves correct page was opened in current window
18+
})
19+
})

src/App.vue

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,20 +55,27 @@ body {
5555
}
5656
5757
#app {
58-
display: flex; /* 2 */
59-
flex: 1 0 auto; /* 2 */
60-
flex-direction: column; /* 2 */
61-
6258
font-family: 'Avenir', Helvetica, Arial, sans-serif;
6359
-webkit-font-smoothing: antialiased;
6460
-moz-osx-font-smoothing: grayscale;
6561
color: #2c3e50;
62+
height: 100%;
6663
}
6764
68-
#app > div {
65+
#app > div:not(.vue-portal-target) {
6966
display: flex; /* 2 */
7067
flex: 1 0 auto; /* 2 */
7168
flex-direction: column; /* 2 */
69+
height: 100%;
70+
}
71+
72+
#app > div > div.home,
73+
#app > div > footer {
74+
flex: 0 0 auto; /* 2 */
75+
}
76+
77+
#app > div > section {
78+
flex: 1 0 auto; /* 2 */
7279
}
7380
7481
pre {

src/components/Lesson.vue

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,17 @@
111111
:run="run"
112112
:next="next" />
113113
</div>
114-
<footer class="mt4 ph3-ns bg-navy white">
114+
<div class="mt4 ph3-ns bg-aqua navy">
115115
<div v-if="isResources" class="mw7 center ph3">
116116
<p>How did you feel about this tutorial? We'd love to hear your thoughts and suggestions for improvement! Please <a :href="tutorialIssueUrl" target="_blank">share your feedback</a>.</p>
117117
</div>
118118
<div v-else class="mw7 center ph3">
119-
<p>Feeling stuck? We'd love to hear what's confusing so we can improve this lesson. Please <a :href="lessonIssueUrl" target="_blank">share your questions and feedback</a>.</p>
119+
<p><strong>Feeling stuck?</strong> We'd love to hear what's confusing so we can improve this lesson. Please <a :href="lessonIssueUrl" target="_blank">share your questions and feedback</a>.</p>
120120
</div>
121-
</footer>
121+
</div>
122+
<Footer
123+
noTopMargin
124+
/>
122125
</div>
123126
</template>
124127

@@ -142,7 +145,8 @@ import {
142145
} from '../utils/tutorials'
143146
import countly from '../utils/countly'
144147
import marked from '../utils/marked'
145-
import Header from './Header.vue'
148+
import Header from './layout/Header.vue'
149+
import Footer from './layout/Footer.vue'
146150
import Quiz from './Quiz.vue'
147151
import Resources from './Resources.vue'
148152
import Breadcrumbs from './Breadcrumbs.vue'
@@ -224,7 +228,8 @@ export default {
224228
Validator,
225229
TutorialCompletionCallout,
226230
TutorialRedirectModal,
227-
TypeIcon
231+
TypeIcon,
232+
Footer
228233
},
229234
props: {
230235
lessonId: Number,

src/components/layout/Footer.vue

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<template>
2+
<footer :class="`bg-navy white pt5-m pt5-l pt4 pb2 ${noTopMargin ? '':'footer-margin'}`"
3+
data-cy="footer-component"
4+
>
5+
<div class="flex mw7 ph3 center flex-wrap"> <!-- logo & columns -->
6+
<div class="w-33-l w-100 mb0-l mb3">
7+
<router-link to="/" class="flex items-center link">
8+
<ProtoSchoolLogo alt="ProtoSchool" class="w2 mr2 "/>
9+
<div class="ma0 fw4 white f3">
10+
<span class="montserrat fw4">Proto</span>
11+
<span class="montserrat fw2">School</span>
12+
</div>
13+
</router-link>
14+
</div>
15+
<div v-for="column in processedColumns" :key="column.title" class="w-20-l w-25-m w-33 column ">
16+
<span class="fw7">{{column.title}}</span>
17+
<ul class="list pl0">
18+
<li v-for="(link, index) in column.links" :key="index" class="pv1">
19+
<a class="link underline-hover white o-80 glow"
20+
:target="link.external ? '_blank' : ''"
21+
:data-cy="link.external ? 'footer-link-external' : 'footer-link-internal'"
22+
:href="link.url">{{link.text}}
23+
</a>
24+
</li>
25+
</ul>
26+
</div>
27+
</div>
28+
<div class="flex justify-start mt4 mw7 center ph3 f7 o-70"> <!-- fake element plus copyright -->
29+
<div class="w-33-l">
30+
</div>
31+
<p>© <a class="link underline white o-80 glow" target="_blank" href="https://protocol.ai">Protocol Labs</a> | {{translations.copyright._1}} <a class="link underline white o-80 glow" target="_blank" href="https://protocol.ai/legal/">{{translations.copyright._2}}</a>{{translations.copyright._3}} <a class="link underline white o-80 glow" target="_blank" :href="translations.copyright.licenseURL" >CC-BY 3.0</a>{{translations.copyright._4}}</p>
32+
</div>
33+
</footer>
34+
</template>
35+
36+
<script>
37+
import ProtoSchoolLogo from '../../static/images/ps_symbol_color.svg?inline'
38+
import translations from '../../static/translations'
39+
import projects from '../../static/projects.json'
40+
41+
export default {
42+
name: 'Footer',
43+
components: {
44+
ProtoSchoolLogo
45+
},
46+
props: {
47+
noTopMargin: Boolean
48+
},
49+
computed: {
50+
translations: function () {
51+
return translations.footer
52+
},
53+
processedColumns: function () {
54+
return translations.footer.columns.map(column => ({
55+
...column,
56+
links: column.links.map(link => {
57+
let text = link.text // text or undefined
58+
let url = link.url // url or underfined
59+
60+
// Fill in course and project link data automatically
61+
if (column.type === 'courses' || column.type === 'projects') {
62+
let project = projects.find(project => project.id === link)
63+
64+
text = project.name
65+
url = (column.type === 'courses') ? `/course/${link}` : project.url
66+
}
67+
68+
return { text, url, external: !url.startsWith('/') }
69+
})
70+
}))
71+
}
72+
}
73+
}
74+
</script>
75+
<style scoped>
76+
.column {
77+
margin-top: 0.7rem;
78+
}
79+
.footer-margin {
80+
margin-top: 6rem;
81+
}
82+
83+
@media (max-width: 30rem) {
84+
.footer-margin {
85+
margin-top: 3rem;
86+
}
87+
}
88+
</style>

src/components/Header.vue renamed to src/components/layout/Header.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
</template>
2424

2525
<script>
26-
import ProtoSchoolLogo from '../static/images/ps_symbol_color.svg?inline'
26+
import ProtoSchoolLogo from '../../static/images/ps_symbol_color.svg?inline'
2727
2828
import Navigation from './Navigation.vue'
2929
export default {

src/components/Navigation.vue renamed to src/components/layout/Navigation.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@
4848
</template>
4949

5050
<script>
51-
import BurgerIcon from '../static/images/burger.svg?inline'
52-
import CloseIcon from '../static/images/close.svg?inline'
51+
import BurgerIcon from '../../static/images/burger.svg?inline'
52+
import CloseIcon from '../../static/images/close.svg?inline'
5353
54-
import { getTutorialByUrl } from '../utils/tutorials'
54+
import { getTutorialByUrl } from '../../utils/tutorials'
5555
5656
export default {
5757
name: 'Navigation',

src/pages/Build.vue

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,17 +71,20 @@
7171
<router-link to="/contribute">ways to contribute</router-link>.
7272
</p>
7373
</section>
74+
<Footer/>
7475
</div>
7576
</template>
7677

7778
<script>
7879
import head from '../utils/head'
79-
import Header from '../components/Header.vue'
80+
import Header from '../components/layout/Header.vue'
81+
import Footer from '../components/layout/Footer.vue'
8082
8183
export default {
8284
name: 'Build',
8385
components: {
84-
Header
86+
Header,
87+
Footer
8588
},
8689
head () {
8790
return head()

src/pages/Contribute.vue

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949

5050
<p class="f4 fw5 lh-copy ma0 pv2 ">Feeling overwhelmed by GitHub while contributing to ProtoSchool? Send us a good old-fashioned <a href="mailto:[email protected]">email</a> and we'll do our best to help.</p>
5151

52-
<h2>Get in Touch</h2>
52+
<h2 id="contact">Get in Touch</h2>
5353
<p class="f4 fw5 lh-copy ma0 pv2 ">
5454
We use GitHub to organize ProtoSchool. The best place to get in touch
5555
with questions about event leadership and community engagement is our
@@ -73,19 +73,21 @@
7373
workshop is also required to maintain its own Code of Conduct, which you'll
7474
find linked from our <router-link to="/events">events page</router-link>.
7575
</p>
76-
7776
</section>
77+
<Footer/>
7878
</div>
7979
</template>
8080

8181
<script>
8282
import head from '../utils/head'
83-
import Header from '../components/Header.vue'
83+
import Header from '../components/layout/Header.vue'
84+
import Footer from '../components/layout/Footer.vue'
8485
8586
export default {
8687
name: 'Community',
8788
components: {
88-
Header
89+
Header,
90+
Footer
8991
},
9092
head () {
9193
return head()

src/pages/Course.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
/>
5656
</div>
5757
</section>
58+
<Footer/>
5859
</div>
5960
</template>
6061

@@ -70,7 +71,8 @@ import translations from '../static/translations'
7071
import { getAll } from '../utils/projects'
7172
import countly from '../utils/countly'
7273
73-
import Header from '../components/Header'
74+
import Header from '../components/layout/Header.vue'
75+
import Footer from '../components/layout/Footer.vue'
7476
import TutorialsGrid from '../components/TutorialsGrid'
7577
import ToggleButton from '../components/ToggleButton'
7678
import ButtonLink from '../components/buttons/ButtonLink'
@@ -83,6 +85,7 @@ export default {
8385
},
8486
components: {
8587
Header,
88+
Footer,
8689
TutorialsGrid,
8790
ToggleButton,
8891
ButtonLink,

src/pages/Events.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,20 +46,23 @@
4646
</div>
4747
</div>
4848
</section>
49+
<Footer/>
4950
</div>
5051
</template>
5152

5253
<script>
5354
import head from '../utils/head'
5455
import { pastEvents, futureEvents } from '../utils/events'
55-
import Header from '../components/Header'
56+
import Header from '../components/layout/Header.vue'
57+
import Footer from '../components/layout/Footer.vue'
5658
import EventCard from '../components/cards/EventCard'
5759
import ButtonLink from '../components/buttons/ButtonLink'
5860
5961
export default {
6062
name: 'events',
6163
components: {
6264
Header,
65+
Footer,
6366
EventCard,
6467
ButtonLink
6568
},

0 commit comments

Comments
 (0)