@ -0,0 +1,96 @@ | |||
html, | |||
body, | |||
#__nuxt, | |||
#__layout, | |||
.page-container, | |||
main { | |||
height: 100%; | |||
} | |||
html { | |||
font-size: min(3vmin, 18px); | |||
} | |||
header { | |||
position: fixed; | |||
top: 0; | |||
width: 100vw; | |||
z-index: 403; | |||
display: grid; | |||
grid-template-columns: 1fr 1fr 1fr; | |||
padding: 1rem 1rem 0.75rem 1rem; | |||
pointer-events: none; | |||
} | |||
.white-bkg header { | |||
background-color: white; | |||
} | |||
header button { | |||
pointer-events: all; | |||
} | |||
.header__col:nth-child(2) { | |||
display: flex; | |||
justify-content: center; | |||
align-items: flex-start; | |||
} | |||
.header__col:nth-child(3) { | |||
text-align: right; | |||
} | |||
main { | |||
display: flex; | |||
flex-direction: column; | |||
} | |||
.nav { | |||
flex: 0 0 auto; | |||
background: white; | |||
display: flex; | |||
flex-direction: column; | |||
justify-content: flex-end; | |||
} | |||
:root { | |||
--m-s: 0.1s; | |||
--h-s: 0.3s; | |||
--d: calc(var(--h-s) - var(--m-s)); | |||
} | |||
.nav--hide { | |||
transition: margin-top var(--m-s) linear var(--h-s), max-height var(--h-s) linear 0s; | |||
margin-top: 0; | |||
max-height: 0; | |||
} | |||
.nav--show { | |||
margin-top: 3.5rem; | |||
max-height: 250px; | |||
transition: margin-top var(--m-s) linear 0s, max-height var(--h-s) linear var(--m-s); | |||
} | |||
.btn--nav-open { | |||
padding: 1rem; | |||
display: block; | |||
} | |||
.flyout-container { | |||
z-index: 1001; | |||
position: fixed; | |||
bottom: 0; | |||
display: flex; | |||
justify-content: center; | |||
width: 100vw; | |||
transition: all 0.3s; | |||
pointer-events: none; | |||
} | |||
.flyout-container.flyout-container--hide { | |||
transform: translateY(200px); | |||
} | |||
.flyout-container.flyout-container--show { | |||
transform: translateY(0); | |||
} |
@ -0,0 +1,163 @@ | |||
<template> | |||
<div class="chosen-wrapper"> | |||
<div class="chosen-cols"> | |||
<div class="chosen-col"> | |||
<label for="" class="chosen-text"> | |||
{{ selectedOrig.municipality }} | |||
</label> | |||
<h1 class="chosen-text"> | |||
{{ selectedOrig.iata }} | |||
</h1> | |||
<span v-if="departure" class="date-badge"> | |||
{{ departure }} {{ (departureTime ? '@' + departureTime : '') }} | |||
</span> | |||
</div> | |||
<div class="chosen-col"> | |||
<svg | |||
xmlns="http://www.w3.org/2000/svg" | |||
class="icon icon-tabler icon-tabler-arrow-right-circle" | |||
width="100" | |||
height="100" | |||
viewBox="0 0 24 24" | |||
stroke-width="1.5" | |||
stroke="#007fff" | |||
fill="none" | |||
stroke-linecap="round" | |||
stroke-linejoin="round" | |||
> | |||
<path stroke="none" d="M0 0h24v24H0z" fill="none" /> | |||
<path d="M18 15l3 -3l-3 -3" /> | |||
<circle cx="5" cy="12" r="2" /> | |||
<path d="M7 12h14" /> | |||
</svg> | |||
</div> | |||
<div class="chosen-col"> | |||
<label for="" class="chosen-text"> | |||
{{ selectedDest.municipality }} | |||
</label> | |||
<h1 class="chosen-text"> | |||
{{ selectedDest.iata }} | |||
</h1> | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
export default { | |||
props: { | |||
selectedOrig: { | |||
type: [Object], | |||
default () { | |||
return {} | |||
} | |||
}, | |||
selectedDest: { | |||
type: [Object], | |||
default () { | |||
return {} | |||
} | |||
}, | |||
departure: { | |||
type: [String], | |||
default () { | |||
return '' | |||
} | |||
}, | |||
departureTime: { | |||
type: [String], | |||
default () { | |||
return '' | |||
} | |||
} | |||
} | |||
} | |||
</script> | |||
<style> | |||
.chosen-wrapper { | |||
display: flex; | |||
flex-direction: column; | |||
align-items: center; | |||
} | |||
.chosen-cols { | |||
display: flex; | |||
justify-content: center; | |||
background-color: #003c79; | |||
border-radius: 1rem; | |||
padding: 0.5rem 2rem; | |||
margin-bottom: 2rem; | |||
position: relative; | |||
max-width: 450px; | |||
--knockout-size: 0.75rem; | |||
} | |||
.chosen-col:nth-of-type(2) { | |||
display: flex; | |||
flex-direction: column; | |||
justify-content: center; | |||
align-items: center; | |||
} | |||
.chosen-col:nth-of-type(2) svg { | |||
margin-top: -0.9rem; | |||
width: 3.5rem; | |||
height: 3.5rem; | |||
} | |||
.chosen-col:nth-of-type(2)::before { | |||
content: ""; | |||
height: var(--knockout-size); | |||
width: var(--knockout-size); | |||
background-color: white; | |||
border-radius: 0 0 999px 999px; | |||
display: block; | |||
position: absolute; | |||
top: 0; | |||
} | |||
.chosen-col:nth-of-type(2)::after { | |||
content: ""; | |||
height: var(--knockout-size); | |||
width: var(--knockout-size); | |||
background-color: white; | |||
border-radius: 999px 999px 0 0; | |||
display: block; | |||
position: absolute; | |||
bottom: 0; | |||
} | |||
.flyout .chosen-col:nth-of-type(2)::before, | |||
.flyout .chosen-col:nth-of-type(2)::after { | |||
background-color: #007fff; | |||
} | |||
label.chosen-text { | |||
color: #007fff; | |||
line-height: 0.8; | |||
font-size: 0.8rem; | |||
font-weight: 400; | |||
} | |||
.header__col:nth-child(3) label.chosen-text { | |||
text-align: right; | |||
} | |||
h1.chosen-text { | |||
font-size: 3rem; | |||
line-height: 0.8; | |||
font-weight: 500; | |||
color: #eee; | |||
} | |||
.date-badge { | |||
background: white; | |||
border-radius: 999px; | |||
padding: 0 0.5em; | |||
line-height: 1; | |||
display: inline-block; | |||
font-size: 0.8rem; | |||
} | |||
</style> |
@ -0,0 +1,30 @@ | |||
<template> | |||
<svg | |||
xmlns="http://www.w3.org/2000/svg" | |||
class="icon icon-tabler icon-tabler-x" | |||
width="60" | |||
height="60" | |||
viewBox="0 0 24 24" | |||
stroke-width="2" | |||
stroke="#bbbbbb" | |||
fill="none" | |||
stroke-linecap="round" | |||
stroke-linejoin="round" | |||
> | |||
<path stroke="none" d="M0 0h24v24H0z" fill="none" /> | |||
<line x1="18" y1="6" x2="6" y2="18" /> | |||
<line x1="6" y1="6" x2="18" y2="18" /> | |||
</svg> | |||
</template> | |||
<script> | |||
export default { | |||
} | |||
</script> | |||
<style scoped> | |||
svg { | |||
max-height: 3.2rem; | |||
} | |||
</style> |
@ -0,0 +1,29 @@ | |||
<template> | |||
<svg | |||
xmlns="http://www.w3.org/2000/svg" | |||
class="icon icon-tabler icon-tabler-chevron-down" | |||
width="60" | |||
height="60" | |||
viewBox="0 0 24 24" | |||
stroke-width="2" | |||
stroke="#bbbbbb" | |||
fill="none" | |||
stroke-linecap="round" | |||
stroke-linejoin="round" | |||
> | |||
<path stroke="none" d="M0 0h24v24H0z" fill="none" /> | |||
<polyline points="6 9 12 15 18 9" fill="none" /> | |||
</svg> | |||
</template> | |||
<script> | |||
export default { | |||
} | |||
</script> | |||
<style scoped> | |||
svg { | |||
max-height: 3.2rem; | |||
} | |||
</style> |
@ -0,0 +1,93 @@ | |||
<template> | |||
<header> | |||
<div class="header__col"> | |||
<Logo /> | |||
<div v-if="!selectedOrig.iata" class="logo-blurb"> | |||
from one of <strong>{{ airportsOrig.length }}</strong> | |||
<span style="color: white;">local</span> airports | |||
</div> | |||
<div | |||
v-if=" | |||
selectedOrig.iata && !selectedDest.iata && airports_dest.length > 1 | |||
" | |||
class="logo-blurb" | |||
> | |||
to one of <strong>{{ airportsDest.length }}</strong> | |||
{{ getCompliment }} destinations | |||
</div> | |||
</div> | |||
<div class="header__col"> | |||
<div v-show="!isPickerVisible"> | |||
<button class="btn btn--primary" @click="showPicker"> | |||
tap the map or search 🔎 | |||
</button> | |||
</div> | |||
<div v-show="isPickerVisible"> | |||
<button class="btn btn--primary" @click="showPicker"> | |||
hide search <svg | |||
xmlns="http://www.w3.org/2000/svg" | |||
class="icon icon-tabler icon-tabler-arrow-bar-to-up" | |||
width="24" | |||
height="24" | |||
viewBox="0 0 24 24" | |||
stroke-width="3" | |||
stroke="#ffffff" | |||
fill="none" | |||
stroke-linecap="round" | |||
stroke-linejoin="round" | |||
> | |||
<path stroke="none" d="M0 0h24v24H0z" fill="none" /> | |||
<line x1="12" y1="10" x2="12" y2="20" /> | |||
<line x1="12" y1="10" x2="16" y2="14" /> | |||
<line x1="12" y1="10" x2="8" y2="14" /> | |||
<line x1="4" y1="4" x2="20" y2="4" /> | |||
</svg> | |||
</button> | |||
</div> | |||
</div> | |||
<div class="header__col" /> | |||
</header> | |||
</template> | |||
<script> | |||
export default { | |||
props: { | |||
selectedOrig: { | |||
type: [Object], | |||
default () { | |||
return {} | |||
} | |||
}, | |||
selectedDest: { | |||
type: [Object], | |||
default () { | |||
return {} | |||
} | |||
}, | |||
airportsOrig: { | |||
type: [Array], | |||
default () { | |||
return [] | |||
} | |||
}, | |||
airportsDest: { | |||
type: [Array], | |||
default () { | |||
return [] | |||
} | |||
}, | |||
isPickerVisible: { | |||
type: [Boolean], | |||
default () { | |||
return null | |||
} | |||
} | |||
} | |||
} | |||
</script> | |||
<style> | |||
.asdf { | |||
color: red; | |||
} | |||
</style> |
@ -0,0 +1,592 @@ | |||
<template> | |||
<div> | |||
<button class="btn btn--primary sidebar-button" @click="showSidebar"> | |||
<svg | |||
v-if="!isSidebarVisible" | |||
xmlns="http://www.w3.org/2000/svg" | |||
class="icon icon-tabler icon-tabler-menu" | |||
width="24" | |||
height="24" | |||
viewBox="0 0 24 24" | |||
stroke-width="3" | |||
stroke="#ffffff" | |||
fill="none" | |||
stroke-linecap="round" | |||
stroke-linejoin="round" | |||
> | |||
<path stroke="none" d="M0 0h24v24H0z" fill="none" /> | |||
<line x1="4" y1="8" x2="20" y2="8" /> | |||
<line x1="4" y1="16" x2="20" y2="16" /> | |||
</svg> | |||
<svg | |||
v-if="isSidebarVisible" | |||
xmlns="http://www.w3.org/2000/svg" | |||
class="icon icon-tabler icon-tabler-arrow-bar-to-right" | |||
width="24" | |||
height="24" | |||
viewBox="0 0 24 24" | |||
stroke-width="3" | |||
stroke="#ffffff" | |||
fill="none" | |||
stroke-linecap="round" | |||
stroke-linejoin="round" | |||
> | |||
<path stroke="none" d="M0 0h24v24H0z" fill="none" /> | |||
<line x1="14" y1="12" x2="4" y2="12" /> | |||
<line x1="14" y1="12" x2="10" y2="16" /> | |||
<line x1="14" y1="12" x2="10" y2="8" /> | |||
<line x1="20" y1="4" x2="20" y2="20" /> | |||
</svg> | |||
</button> | |||
<aside | |||
:class="[ | |||
'sidebar-container', | |||
{ 'sidebar-container--hide': !isSidebarVisible }, | |||
{ 'sidebar-container--show': isSidebarVisible }, | |||
]" | |||
> | |||
<div class="sidebar"> | |||
<div class="sidebar-content"> | |||
<h1 class="h1--about"> | |||
What is FlyLocal Alaska? | |||
</h1> | |||
<div class="img-divider"> | |||
<img | |||
class="img--about" | |||
src="https://openmoji.org/data/black/svg/1F3D4.svg" | |||
alt="" | |||
srcset="" | |||
> | |||
<img | |||
class="img--about" | |||
src="https://openmoji.org/data/black/svg/1F4C5.svg" | |||
alt="" | |||
srcset="" | |||
> | |||
<img | |||
class="img--about" | |||
src="https://openmoji.org/data/black/svg/1F601.svg" | |||
alt="" | |||
srcset="" | |||
> | |||
</div> | |||
<p class="text--about"> | |||
<strong>FlyLocal-Alaska</strong> is an easy way to view the | |||
schedules for your favorite Alaskan airlines - all in one place. | |||
</p> | |||
<h1 class="h1--about"> | |||
Why FlyLocal in Alaska? | |||
</h1> | |||
<div class="img-divider"> | |||
<img | |||
class="img--about" | |||
src="https://openmoji.org/data/black/svg/1F6AB.svg" | |||
alt="" | |||
srcset="" | |||
> | |||
<img | |||
class="img--about" | |||
src="https://openmoji.org/data/black/svg/1F697.svg" | |||
alt="" | |||
srcset="" | |||
> | |||
<img | |||
class="img--about" | |||
src="https://openmoji.org/data/black/svg/1F6E3.svg" | |||
alt="" | |||
srcset="" | |||
> | |||
</div> | |||
<p class="text--about"> | |||
<strong>80% of Alaskan communities are not connected to the road | |||
system.</strong> | |||
Therefore, they rely heavily on local airlines for transportation. | |||
</p> | |||
<div class="img-divider"> | |||
<img | |||
class="img--about" | |||
src="https://openmoji.org/data/black/svg/1F6A3.svg" | |||
alt="" | |||
srcset="" | |||
> | |||
<img | |||
class="img--about" | |||
src="https://openmoji.org/data/black/svg/1F3D5.svg" | |||
alt="" | |||
srcset="" | |||
> | |||
<img | |||
class="img--about" | |||
src="https://openmoji.org/data/black/svg/1F43B.svg" | |||
alt="" | |||
srcset="" | |||
> | |||
</div> | |||
<p class="text--about"> | |||
<strong>See new places.</strong> There are ~400 public airports in | |||
Alaska, but only 20 (or 5%) with service from major US carriers. | |||
</p> | |||
<div class="img-divider"> | |||
<img | |||
class="img--about" | |||
src="https://openmoji.org/data/black/svg/1F6E9.svg" | |||
alt="" | |||
srcset="" | |||
> | |||
<img | |||
class="img--about" | |||
src="https://openmoji.org/data/black/svg/1F681.svg" | |||
alt="" | |||
srcset="" | |||
> | |||
<img | |||
class="img--about" | |||
src="https://openmoji.org/data/black/svg/1F6F8.svg" | |||
alt="" | |||
srcset="" | |||
> | |||
</div> | |||
<p class="text--about"> | |||
Enjoy a completely <strong>unique flying experience</strong>. Have | |||
you ever landed on a lake in a seaplane? Now is your chance to check | |||
it off the bucket-list. | |||
</p> | |||
<h1 class="h1--about"> | |||
Up-to-date Travel Info | |||
</h1> | |||
<ul class="about-carriers list-lrg"> | |||
<li> | |||
<a href="https://covid19.alaska.gov/travelers/"> | |||
<img | |||
class="img--carrier-logo" | |||
:src="require(`@/assets/images/orgs/alaska-travel-info.png`)" | |||
alt="Alaska Travel Info" | |||
> | |||
</a> | |||
</li> | |||
</ul> | |||
<h1 class="h1--about"> | |||
Explore Alaska on these great local airlines | |||
</h1> | |||
<ul class="about-carriers"> | |||
<li v-for="carrier in carriers" :key="carrier.id"> | |||
<a :href="carrier.fields.BookingLink" target="_blank"> | |||
<img | |||
class="img--carrier-logo" | |||
:src="require(`@/assets/images/carriers/${carrier.fields.Slug}.png`)" | |||
:alt="carrier.fields.Name" | |||
> | |||
</a> | |||
</li> | |||
</ul> | |||
<h1 class="h1--about"> | |||
Proud Member of | |||
</h1> | |||
<ul class="about-carriers list-med"> | |||
<li> | |||
<a href="https://alaskaaircarriers.org"> | |||
<img | |||
class="img--carrier-logo" | |||
:src="require(`@/assets/images/orgs/aaca.png`)" | |||
alt="Alaska Air Carriers Association" | |||
> | |||
</a> | |||
</li> | |||
<li> | |||
<a href="https://alaskatia.org"> | |||
<img | |||
class="img--carrier-logo" | |||
:src="require(`@/assets/images/orgs/alaska-tia.png`)" | |||
alt="Alaska Travel Industry Association" | |||
> | |||
</a> | |||
</li> | |||
</ul> | |||
<h1 class="h1--about"> | |||
Featured on | |||
</h1> | |||
<ul class="about-carriers list-med"> | |||
<li> | |||
<a href="https://www.1millioncups.com/anchorage/presentations/flylocal-alaska-35304"> | |||
<img | |||
class="img--carrier-logo" | |||
:src="require(`@/assets/images/orgs/1-million-cups.png`)" | |||
alt="1 Million Cups" | |||
> | |||
</a> | |||
</li> | |||
<li> | |||
<a href="https://www.travelalaska.com/offers/FlyLocal/Plane-Statewide.aspx"> | |||
<img | |||
class="img--carrier-logo" | |||
style="background: black; border-radius: 0.5rem; padding-left: 0.4rem;" | |||
:src="require(`@/assets/images/orgs/travel-alaska.png`)" | |||
alt="Travel Alaska" | |||
> | |||
</a> | |||
</li> | |||
</ul> | |||
<div class="company-footer"> | |||
⎨ FlyLocal v5.0.2 𐄙 ©2021 FlyLocal LLC ⎬ | |||
</div> | |||
</div> | |||
<ul class="contact"> | |||
<li class="contact-item"> | |||
<a href="https://twitter.com/fly_local"> | |||
<svg | |||
xmlns="http://www.w3.org/2000/svg" | |||
class="icon icon-tabler icon-tabler-brand-twitter" | |||
width="40" | |||
height="40" | |||
viewBox="0 0 24 24" | |||
stroke-width="2" | |||
stroke="#007fff" | |||
fill="none" | |||
stroke-linecap="round" | |||
stroke-linejoin="round" | |||
> | |||
<path stroke="none" d="M0 0h24v24H0z" fill="none" /> | |||
<path | |||
d="M22 4.01c-1 .49 -1.98 .689 -3 .99c-1.121 -1.265 -2.783 -1.335 -4.38 -.737s-2.643 2.06 -2.62 3.737v1c-3.245 .083 -6.135 -1.395 -8 -4c0 0 -4.182 7.433 4 11c-1.872 1.247 -3.739 2.088 -6 2c3.308 1.803 6.913 2.423 10.034 1.517c3.58 -1.04 6.522 -3.723 7.651 -7.742a13.84 13.84 0 0 0 .497 -3.753c-.002 -.249 1.51 -2.772 1.818 -4.013z" | |||
/> | |||
</svg> | |||
<span>@fly_local</span> | |||
</a> | |||
</li> | |||
<li class="contact-item"> | |||
<a href="https://facebook.com/fly_local"> | |||
<svg | |||
xmlns="http://www.w3.org/2000/svg" | |||
class="icon icon-tabler icon-tabler-brand-facebook" | |||
width="40" | |||
height="40" | |||
viewBox="0 0 24 24" | |||
stroke-width="2" | |||
stroke="#007fff" | |||
fill="none" | |||
stroke-linecap="round" | |||
stroke-linejoin="round" | |||
> | |||
<path stroke="none" d="M0 0h24v24H0z" fill="none" /> | |||
<path | |||
d="M7 10v4h3v7h4v-7h3l1 -4h-4v-2a1 1 0 0 1 1 -1h3v-4h-3a5 5 0 0 0 -5 5v2h-3" | |||
/> | |||
</svg> | |||
<span>@fly_local</span> | |||
</a> | |||
</li> | |||
<li class="contact-item"> | |||
<a href="https://instagram.com/fly_local"> | |||
<svg | |||
xmlns="http://www.w3.org/2000/svg" | |||
class="icon icon-tabler icon-tabler-brand-instagram" | |||
width="40" | |||
height="40" | |||
viewBox="0 0 24 24" | |||
stroke-width="2" | |||
stroke="#007fff" | |||
fill="none" | |||
stroke-linecap="round" | |||
stroke-linejoin="round" | |||
> | |||
<path stroke="none" d="M0 0h24v24H0z" fill="none" /> | |||
<rect x="4" y="4" width="16" height="16" rx="4" /> | |||
<circle cx="12" cy="12" r="3" /> | |||
<line x1="16.5" y1="7.5" x2="16.5" y2="7.501" /> | |||
</svg> | |||
<span>@fly_local</span> | |||
</a> | |||
</li> | |||
<li class="contact-item"> | |||
<a href="mailto:team@iflylocal.com"> | |||
<svg | |||
xmlns="http://www.w3.org/2000/svg" | |||
class="icon icon-tabler icon-tabler-user" | |||
width="40" | |||
height="40" | |||
viewBox="0 0 24 24" | |||
stroke-width="2" | |||
stroke="#007fff" | |||
fill="none" | |||
stroke-linecap="round" | |||
stroke-linejoin="round" | |||
> | |||
<path stroke="none" d="M0 0h24v24H0z" fill="none" /> | |||
<circle cx="12" cy="7" r="4" /> | |||
<path d="M6 21v-2a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4v2" /> | |||
</svg> | |||
<span>contact us</span> | |||
</a> | |||
</li> | |||
<li class="contact-item"> | |||
<a href="mailto:partners@iflylocal.com"> | |||
<svg | |||
xmlns="http://www.w3.org/2000/svg" | |||
class="icon icon-tabler icon-tabler-briefcase" | |||
width="40" | |||
height="40" | |||
viewBox="0 0 24 24" | |||
stroke-width="2" | |||
stroke="#007fff" | |||
fill="none" | |||
stroke-linecap="round" | |||
stroke-linejoin="round" | |||
> | |||
<path stroke="none" d="M0 0h24v24H0z" fill="none" /> | |||
<rect x="3" y="7" width="18" height="13" rx="2" /> | |||
<path d="M8 7v-2a2 2 0 0 1 2 -2h4a2 2 0 0 1 2 2v2" /> | |||
<line x1="12" y1="12" x2="12" y2="12.01" /> | |||
<path d="M3 13a20 20 0 0 0 18 0" /> | |||
</svg> | |||
<span>partner with us</span> | |||
</a> | |||
</li> | |||
</ul> | |||
</div> | |||
</aside> | |||
<div | |||
:class="[ | |||
'sidebar-blockui', | |||
{ 'sidebar-blockui--show': isSidebarVisible }, | |||
]" | |||
/> | |||
</div> | |||
</template> | |||
<script> | |||
export default { | |||
data: () => ({ | |||
isSidebarVisible: false, | |||
carriers: [] | |||
}), | |||
async fetch () { | |||
const filterFormula = 'AND(NOT(Status="Inactive"),FIND("Alaska",Region)>0)' | |||
const sortFormula = '&sort[0][field]=Name&sort[0][direction]=asc' | |||
let offset | |||
let data = [] | |||
while (true) { | |||
const offsetParam = offset ? `&offset=${offset}` : '' | |||
const res = await fetch(`https://api.airtable.com/v0/appiQwfVZixRgRICe/Carriers_Alaska?filterByFormula=${filterFormula}${sortFormula}${offsetParam}`, { | |||
method: 'GET', | |||
headers: { | |||
'Content-Type': 'application/x-www-form-urlencoded', | |||
Authorization: 'Bearer keyJ2ht64ZSN57AG1' | |||
} | |||
}) | |||
const json = await res.json() | |||
offset = await json.offset | |||
data = [...data, ...await json.records] | |||
// await console.log(data.length) | |||
if (await !offset) { break } // Were done let's stop this thing | |||
} | |||
this.carriers = [...data] | |||
}, | |||
methods: { | |||
showSidebar () { | |||
this.isSidebarVisible = !this.isSidebarVisible | |||
} | |||
} | |||
} | |||
</script> | |||
<style> | |||
:root { | |||
--sidebar-width: 50ch; | |||
} | |||
.sidebar-container { | |||
z-index: 1002; | |||
position: fixed; | |||
top: 0; | |||
right: 0; | |||
display: flex; | |||
justify-content: flex-start; | |||
height: 100vh; | |||
transition: all 0.3s; | |||
pointer-events: none; | |||
} | |||
.sidebar-container.sidebar-container--hide { | |||
transform: translateX(calc(var(--sidebar-width) + 6rem)); | |||
} | |||
.sidebar-container.sidebar-container--show { | |||
transform: translateX(0); | |||
} | |||
.sidebar { | |||
background: white; | |||
padding: 3rem 0 3rem 3rem; | |||
border-radius: 3rem 0 0 3rem; | |||
pointer-events: all; | |||
display: flex; | |||
flex-direction: column; | |||
align-items: flex-end; | |||
} | |||
.sidebar-content { | |||
overflow: auto; | |||
max-width: var(--sidebar-width); | |||
height: calc(100vh - 11rem); | |||
padding-right: 3rem; | |||
display: flex; | |||
flex-direction: column; | |||
align-items: center; | |||
} | |||
.img--about { | |||
height: min(3rem, 60px); | |||
display: inline-block; | |||
} | |||
div.img-divider { | |||
display: flex; | |||
justify-content: space-around; | |||
padding: 0 25%; | |||
} | |||
.img--carrier-logo { | |||
max-width: 6rem; | |||
max-height: 6rem; | |||
} | |||
.list-med .img--carrier-logo { | |||
max-width: 9rem; | |||
max-height: 9rem; | |||
} | |||
.list-lrg .img--carrier-logo { | |||
max-width: 15rem; | |||
max-height: 15rem; | |||
} | |||
h1.h1--about { | |||
font-weight: 200; | |||
text-transform: uppercase; | |||
color: #007fff; | |||
font-size: min(2.7rem, 50px); | |||
line-height: 1; | |||
text-align: center; | |||
margin-bottom: 1rem; | |||
} | |||
.text--about { | |||
margin-top: 1rem; | |||
margin-bottom: 1rem; | |||
max-width: 40ch; | |||
font-size: min(1rem, 18px); | |||
} | |||
.text--about:nth-of-type(1), | |||
.text--about:nth-of-type(4) { | |||
margin-bottom: 5rem; | |||
} | |||
.about-carriers { | |||
display: flex; | |||
flex-direction: row; | |||
flex-wrap: wrap; | |||
gap: 2rem; | |||
align-items: center; | |||
justify-content: space-around; | |||
margin-bottom: 5rem; | |||
} | |||
.about-carriers li { | |||
filter: saturate(0%); | |||
transition: 0.3s all; | |||
position: relative; | |||
} | |||
/* .about-carriers li::after { | |||
position: absolute; | |||
top: 0; | |||
right: 0; | |||
bottom: 0; | |||
left: 0; | |||
background-color: red; | |||
content: ''; | |||
} */ | |||
.about-carriers li:hover { | |||
filter: saturate(100%); | |||
transform: scale(1.05); | |||
} | |||
.sidebar-button { | |||
position: fixed; | |||
top: 1rem; | |||
right: 1rem; | |||
z-index: 1003; | |||
} | |||
.sidebar-blockui { | |||
position: fixed; | |||
top: 0; | |||
right: 0; | |||
bottom: 0; | |||
left: 0; | |||
opacity: 0; | |||
filter: blur(0.5); | |||
background-color: #007fff; | |||
transition: all 0.3s; | |||
pointer-events: none; | |||
z-index: 1001; | |||
} | |||
.sidebar-blockui.sidebar-blockui--show { | |||
opacity: 0.8; | |||
pointer-events: all; | |||
} | |||
ul.contact { | |||
display: flex; | |||
flex-direction: row; | |||
align-items: center; | |||
justify-content: center; | |||
gap: 1rem; | |||
flex-wrap: wrap; | |||
margin: 3rem 3rem 0 0; | |||
max-width: var(--sidebar-width); | |||
} | |||
li.contact-item a span { | |||
color: #007fff; | |||
transition: all 0.3s; | |||
} | |||
ul.contact li.contact-item a { | |||
display: flex; | |||
flex-direction: row; | |||
align-items: center; | |||
transition: all 0.3s; | |||
} | |||
ul.contact li.contact-item a:hover span { | |||
color: #00ca00; | |||
} | |||
ul.contact li.contact-item a svg { | |||
max-height: 2rem; | |||
max-width: 2rem; | |||
stroke-width: 1; | |||
transition: all 0.3s; | |||
} | |||
ul.contact li.contact-item a:hover svg { | |||
stroke: #00ca00; | |||
} | |||
.company-footer { | |||
font-family: monospace; | |||
font-size: 0.8rem; | |||
text-transform: uppercase; | |||
color: gray; | |||
} | |||
</style> |
@ -0,0 +1,18 @@ | |||
<template> | |||
<div style="height: 100%;"> | |||
<Nuxt /> | |||
<TheSideBar /> | |||
</div> | |||
</template> | |||
<script> | |||
export default { | |||
} | |||
</script> | |||
<style> | |||
.asdf { | |||
color: red; | |||
} | |||
</style> |
@ -0,0 +1,15 @@ | |||
export default function (req, res, next) { | |||
const redirects = [ | |||
{ | |||
from: '/', | |||
to: '/go' | |||
} | |||
] | |||
const redirect = redirects.find(r => r.from === req.url) | |||
if (redirect) { | |||
res.writeHead(301, { Location: redirect.to }) | |||
res.end() | |||
} else { | |||
next() | |||
} | |||
} |
@ -0,0 +1,226 @@ | |||
<template> | |||
<div class="white-bkg"> | |||
<header> | |||
<div class="header__col"> | |||
<button class="btn btn--primary" @click="goBack"> | |||
<svg | |||
xmlns="http://www.w3.org/2000/svg" | |||
class="icon icon-tabler icon-tabler-chevrons-left" | |||
width="24" | |||
height="24" | |||
viewBox="0 0 24 24" | |||
stroke-width="3" | |||
stroke="#ffffff" | |||
fill="none" | |||
stroke-linecap="round" | |||
stroke-linejoin="round" | |||
> | |||
<path stroke="none" d="M0 0h24v24H0z" fill="none" /> | |||
<polyline points="11 7 6 12 11 17" /> | |||
<polyline points="17 7 12 12 17 17" /> | |||
</svg> back | |||
</button> | |||
</div> | |||
<div class="header__col"> | |||
<Logo /> | |||
</div> | |||
<div class="header__col" /> | |||
</header> | |||
<main class="main-with-header"> | |||
<ChosenFlights | |||
:selected-orig="selectedOrig" | |||
:selected-dest="selectedDest" | |||
style="margin: 0 1rem;" | |||
/> | |||
<!-- <pre> | |||
{{ schedules }} | |||
</pre> --> | |||
<DatePicker | |||
:starting-date="startingDate" | |||
:selected-dows="selectedDows" | |||
/> | |||
</main> | |||
</div> | |||
</template> | |||
<script> | |||
export default { | |||
data () { | |||
return { | |||
schedules: [], | |||
startingDate: new Date(), | |||
selectedSchedule: {}, | |||
selectedDays: [], | |||
selectedOrig: {}, | |||
selectedDest: {} | |||
} | |||
}, | |||
async fetch () { | |||
// console.log(this.$route.params.o) | |||
const today = new Date().toLocaleDateString('en-CA') | |||
// function addDays (date, days) { | |||
// const result = new Date(date) | |||
// result.setDate(result.getDate() + days) | |||
// return result | |||
// } | |||
// const tomorrow = addDays(new Date(), 1).toLocaleDateString('en-CA') | |||
const scheduleFetchFilterFormula = `AND(Is_Current="Yes",Origin_IATA="${this.$route.params.o}",Destination_IATA="${this.$route.params.d}",Effective_End>"${today}")` | |||
const scheduleFetchSort = '&sort[0][field]=DepartureTimeFormatted&sort[0][direction]=asc' | |||
const response = await fetch(`https://api.airtable.com/v0/appiQwfVZixRgRICe/Schedule?filterByFormula=${scheduleFetchFilterFormula}${scheduleFetchSort}`, { | |||
method: 'GET', | |||
headers: { | |||
'Content-Type': 'application/x-www-form-urlencoded', | |||
Authorization: 'Bearer keyJ2ht64ZSN57AG1' | |||
} | |||
}) | |||
const data = await response.json() | |||
// console.log(data) | |||
this.schedules = [...data.records] | |||
}, | |||
computed: { | |||
selectedDows () { | |||
const mappedDows = this.schedules.map((schedule) => { | |||
// console.log(schedule.fields) | |||
return { | |||
Flight_Number: schedule.fields.Flight_Number, | |||
DowsList: this.daysList(schedule.fields.Frequency_Convert), | |||
Effective_Start: schedule.fields.Effective_Start, | |||
Effective_End: schedule.fields.Effective_End, | |||
DepartureTimeFormatted: schedule.fields.DepartureTimeFormatted | |||
} | |||
}) | |||
return mappedDows | |||
} | |||
}, | |||
created () { | |||
// console.log(this.$route.path) | |||
if (this.$route && this.$route.params && this.$route.params.o) { | |||
this.fetchSingleAirport(this.$route.params.o, true) | |||
} | |||
if (this.$route && this.$route.params && this.$route.params.d) { | |||
this.fetchSingleAirport(this.$route.params.d, false) | |||
} | |||
}, | |||
methods: { | |||
daysList (days) { | |||
const list = days.split(', ').map((day) => { | |||
const name = day.toLowerCase().slice(0, -1) | |||
let num | |||
switch (name) { | |||
case 'su': | |||
num = 0 | |||
break | |||
case 'mo': | |||
num = 1 | |||
break | |||
case 'tu': | |||
num = 2 | |||
break | |||
case 'we': | |||
num = 3 | |||
break | |||
case 'th': | |||
num = 4 | |||
break | |||
case 'fr': | |||
num = 5 | |||
break | |||
case 'sa': | |||
num = 6 | |||
break | |||
default: | |||
break | |||
} | |||
return { | |||
name, | |||
num | |||
} | |||
}) | |||
return list.sort(function (a, b) { | |||
return a.num - b.num | |||
}) | |||
}, | |||
goBack () { | |||
this.$router.go(-1) | |||
}, | |||
book (schedule) { | |||
if (schedule.fields.IsExpedia[0] === 'true') { | |||
this.startingDate = new Date() | |||
this.selectedSchedule = schedule.fields | |||
this.selectedDays = this.daysList(schedule.fields.Frequency_Convert) | |||
} else { | |||
window.open(schedule.fields['BookingLink (from Carriers_Alaska)'][0]) | |||
} | |||
}, | |||
clearSelectedSchedule () { | |||
console.log('clear') | |||
this.startingDate = '' | |||
this.selectedSchedule = {} | |||
}, | |||
async fetchSingleAirport (iata, isOrig) { | |||
const airportFetchFilterFormula = | |||
isOrig | |||
? `AND(Is_Origin=1,{IsCurrent-AsOrigin}="Yes",Airport_IATA="${iata}")` | |||
: `AND(Is_Destination=1,{IsCurrent-AsDest}="Yes",Airport_IATA="${iata}")` | |||
const response = await fetch(`https://api.airtable.com/v0/appiQwfVZixRgRICe/Airports_IATA?filterByFormula=${airportFetchFilterFormula}`, { | |||
method: 'GET', | |||
headers: { | |||
'Content-Type': 'application/x-www-form-urlencoded', | |||
Authorization: 'Bearer keyJ2ht64ZSN57AG1' | |||
} | |||
}) | |||
const mapData = await response.json() | |||
const thisAirport = { | |||
iata: mapData.records[0].fields.Airport_IATA, | |||
lat: mapData.records[0].fields.Latitude_Deg, | |||
long: mapData.records[0].fields.Longitude_Deg, | |||
icon: mapData.records[0].fields.Icon_Url, | |||
name: mapData.records[0].fields.Airport_Name, | |||
municipality: mapData.records[0].fields.Municipality, | |||
type: mapData.records[0].fields.Type, | |||
search: mapData.records[0].fields.Search_Field | |||
} | |||
switch (isOrig) { | |||
case true: | |||
this.selectedOrig = { ...thisAirport } | |||
break | |||
case false: | |||
this.selectedDest = { ...thisAirport } | |||
break | |||
default: | |||
break | |||
} | |||
} | |||
} | |||
} | |||
</script> | |||
<style lang="scss"> | |||
.main-with-header { | |||
margin-top: clamp(20px + 1.75rem, 4rem + 1.75rem, 50px + 1.75rem); | |||
} | |||
</style> |
@ -0,0 +1,323 @@ | |||
<template> | |||
<main> | |||
<div> | |||
<button class="btn btn--primary" style="margin-left: 2rem; margin-top: 2rem;" @click="goBack"> | |||
👈 back | |||
</button> | |||
<h1 style="text-align: center; font-size: 2.5rem;"> | |||
{{ selectedOrig.municipality }} 🛩 {{ selectedDest.municipality }} | |||
</h1> | |||
</div> | |||
<ul class="schedule-grid"> | |||
<li | |||
v-for="schedule in schedules" | |||
:key="schedule.fields.Record_ID" | |||
class="grid__row" | |||
> | |||
<pre> | |||
{{ schedule.fields.Flight_Number }} | |||
</pre> | |||
<div class="grid__field"> | |||
<label> Local Airline </label> | |||
<div class="field__content"> | |||
{{ schedule.fields.Carrier_Name }} | |||
</div> | |||
</div> | |||
<div class="grid__field"> | |||
<label> Days of the Week </label> | |||
<div class="field__content"> | |||
<div class="dow-grid"> | |||
<div | |||
v-for="day in daysList(schedule.fields.Frequency_Convert)" | |||
:key="day.name" | |||
:class="['dow-grid__day', 'day--' + day.name]" | |||
> | |||
<span> {{ day.name }} </span> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="grid__field"> | |||
<label> Departing </label> | |||
<div class="field__content"> | |||
{{ schedule.fields.Departure_TimeL }} | |||
</div> | |||
</div> | |||
<div class="grid__field"> | |||
<label> Arriving </label> | |||
<div class="field__content"> | |||
{{ schedule.fields.Arrival_TimeL }} | |||
</div> | |||
</div> | |||
<div class="grid__field"> | |||
<label> Available Until </label> | |||
<div class="field__content"> | |||
{{ schedule.fields.Effective_End }} | |||
</div> | |||
</div> | |||
<div class="grid__field"> | |||
<div class="field__content"> | |||
{{ schedule.fields.Price_USD }} | |||
</div> | |||
<button class="btn btn--primary" @click="book(schedule)"> | |||
{{ schedule.fields.IsExpedia[0] === 'true' ? 'book it!' : 'see flights' }} | |||
</button> | |||
</div> | |||
</li> | |||
</ul> | |||
</main> | |||
</template> | |||
<script> | |||
export default { | |||
data () { | |||
return { | |||
schedules: [], | |||
startingDate: '', | |||
selectedSchedule: {}, | |||
selectedDays: [], | |||
selectedOrig: {}, | |||
selectedDest: {} | |||
} | |||
}, | |||
async fetch () { | |||
// console.log(this.$route.params.o) | |||
const today = new Date().toLocaleDateString('en-CA') | |||
// function addDays (date, days) { | |||
// const result = new Date(date) | |||
// result.setDate(result.getDate() + days) | |||
// return result | |||
// } | |||
// const tomorrow = addDays(new Date(), 1).toLocaleDateString('en-CA') | |||
const scheduleFetchFilterFormula = `AND(Is_Current="Yes",Origin_IATA="${this.$route.params.o}",Destination_IATA="${this.$route.params.d}",Effective_End>"${today}",SEARCH("${new Date(this.$route.params.departure).getDay()}",Frequency)>0)` | |||
// console.log(scheduleFetchFilterFormula) | |||
const scheduleFetchSort = '&sort[0][field]=DepartureTimeFormatted&sort[0][direction]=asc' | |||
const response = await fetch(`https://api.airtable.com/v0/appiQwfVZixRgRICe/Schedule?filterByFormula=${scheduleFetchFilterFormula}${scheduleFetchSort}`, { | |||
method: 'GET', | |||
headers: { | |||
'Content-Type': 'application/x-www-form-urlencoded', | |||
Authorization: 'Bearer keyJ2ht64ZSN57AG1' | |||
} | |||
}) | |||
const data = await response.json() | |||
// console.log(data) | |||
this.schedules = [...data.records] | |||
}, | |||
computed: { | |||
}, | |||
created () { | |||
// console.log(this.$route.path) | |||
if (this.$route && this.$route.params && this.$route.params.o) { | |||
this.fetchSingleAirport(this.$route.params.o, true) | |||
} | |||
if (this.$route && this.$route.params && this.$route.params.d) { | |||
this.fetchSingleAirport(this.$route.params.d, false) | |||
} | |||
}, | |||
methods: { | |||
daysList (days) { | |||
const list = days.split(', ').map((day) => { | |||
const name = day.toLowerCase().slice(0, -1) | |||
let num | |||
switch (name) { | |||
case 'su': | |||
num = 0 | |||
break | |||
case 'mo': | |||
num = 1 | |||
break | |||
case 'tu': | |||
num = 2 | |||
break | |||
case 'we': | |||
num = 3 | |||
break | |||
case 'th': | |||
num = 4 | |||
break | |||
case 'fr': | |||
num = 5 | |||
break | |||
case 'sa': | |||
num = 6 | |||
break | |||
default: | |||
break | |||
} | |||
return { | |||
name, | |||
num | |||
} | |||
}) | |||
return list.sort(function (a, b) { | |||
return a.num - b.num | |||
}) | |||
}, | |||
goBack () { | |||
this.$router.go(-1) | |||
}, | |||
book (schedule) { | |||
if (schedule.fields.IsExpedia[0] === 'true') { | |||
this.startingDate = new Date() | |||
this.selectedSchedule = schedule.fields | |||
this.selectedDays = this.daysList(schedule.fields.Frequency_Convert) | |||
} else { | |||
window.open(schedule.fields['BookingLink (from Carriers_Alaska)'][0]) | |||
} | |||
}, | |||
clearSelectedSchedule () { | |||
console.log('clear') | |||
this.startingDate = '' | |||
this.selectedSchedule = {} | |||
}, | |||
async fetchSingleAirport (iata, isOrig) { | |||
const airportFetchFilterFormula = | |||
isOrig | |||
? `AND(Is_Origin=1,{IsCurrent-AsOrigin}="Yes",Airport_IATA="${iata}")` | |||
: `AND(Is_Destination=1,{IsCurrent-AsDest}="Yes",Airport_IATA="${iata}")` | |||
const response = await fetch(`https://api.airtable.com/v0/appiQwfVZixRgRICe/Airports_IATA?filterByFormula=${airportFetchFilterFormula}`, { | |||
method: 'GET', | |||
headers: { | |||
'Content-Type': 'application/x-www-form-urlencoded', | |||
Authorization: 'Bearer keyJ2ht64ZSN57AG1' | |||
} | |||
}) | |||
const mapData = await response.json() | |||
const thisAirport = { | |||
iata: mapData.records[0].fields.Airport_IATA, | |||
lat: mapData.records[0].fields.Latitude_Deg, | |||
long: mapData.records[0].fields.Longitude_Deg, | |||
icon: mapData.records[0].fields.Icon_Url, | |||
name: mapData.records[0].fields.Airport_Name, | |||
municipality: mapData.records[0].fields.Municipality, | |||
type: mapData.records[0].fields.Type, | |||
search: mapData.records[0].fields.Search_Field | |||
} | |||
switch (isOrig) { | |||
case true: | |||
this.selectedOrig = { ...thisAirport } | |||
break | |||
case false: | |||
this.selectedDest = { ...thisAirport } | |||
break | |||
default: | |||
break | |||
} | |||
} | |||
} | |||
} | |||
</script> | |||
<style lang="scss"> | |||
.schedule-grid { | |||
display: flex; | |||
flex-direction: column; | |||
gap: 1rem; | |||
margin: 2rem; | |||
} | |||
.grid__row { | |||
display: grid; | |||
grid-template-columns: 2fr 2fr 1fr 1fr 2fr 1fr; | |||
grid-template-rows: auto; | |||
gap: 1rem; | |||
padding: 1rem; | |||
} | |||
@media only screen and (max-width: 768px) { | |||
.grid__row { | |||
display: grid; | |||
grid-template-columns: 1fr 1fr; | |||
grid-template-rows: auto; | |||
} | |||
} | |||
.grid__row:nth-child(2n) { | |||
background: #eee; | |||
} | |||
// .grid__field { | |||
// } | |||
label { | |||
font-size: 0.75rem; | |||
font-weight: 700; | |||
color: gray; | |||
display: block; | |||
} | |||
.field__content { | |||
font-size: 1.5rem; | |||
} | |||
.dow-grid { | |||
width: 200px; | |||
display: grid; | |||
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr; | |||
gap: 0.5rem; | |||
} | |||
.dow-grid__day { | |||
font-size: 0.8rem; | |||
border: 1px solid #ccc !important; | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
border-radius: 3px !important; | |||
text-transform: capitalize; | |||
} | |||
.day--su { | |||
grid-column: 1 / span 1; | |||
} | |||
.day--mo { | |||
grid-column: 2 / span 1; | |||
} | |||
.day--tu { | |||
grid-column: 3 / span 1; | |||
} | |||
.day--we { | |||
grid-column: 4 / span 1; | |||
} | |||
.day--th { | |||
grid-column: 5 / span 1; | |||
} | |||
.day--fr { | |||
grid-column: 6 / span 1; | |||
} | |||
.day--sa { | |||
grid-column: 7 / span 1; | |||
} | |||
</style> |
@ -0,0 +1,92 @@ | |||
<template> | |||
<main class="special"> | |||
<div class="section"> | |||
<NuxtLink to="/go" class="btn btn--primary"> | |||
go to the site | |||
</NuxtLink> | |||
<br><br> | |||
<h1 style="font-size: 2rem;"> | |||
"what is this site, really?" | |||
</h1> | |||
<br> | |||
<pre style="white-space: pre-wrap;"> | |||
Last week, I was mulling over FlyLocal.io's speed issues. | |||
As an exercise, I made a list of all the things that the FlyLocal website does. | |||
- [1] get data from a server three times | |||
- [2] display data on a map, twice | |||
- [3] display data on a page, once | |||
I let it ruminate that, by design, all the heavy lifting, all the processing, is already being done by Airtable. | |||
From a technical perspective, the site is really just a *viewer* of our product, and our product is Airtable data. | |||
*** | |||
Then I thought about all the previous iterations of the site. | |||
It occurred to me that all the fancy stuff I'd done in Bubble v1 and pre-Bubble was for a business model that no longer existed. | |||
There was nothing fancy about this *new* model. No forms, no calculations. Get data, display data. | |||
And it occurred me that all the time-consuming stuff I'd done with Bubble v2 over the last year was really about me learning Bubble and figuring out how to get it to do the stuff that I already knew that websites could do: Get data, display data. | |||
And really, there was nothing all that time-consuming about getting data and displaying data, especially in 2021. | |||
*** | |||
So... I decided to take a couple days and make a website. And I'm pleasantly surprised with how quickly it all came together. | |||
Hand-coded from the ground up on a modern, popular web-dev framework, it's lean, snappy, mobile-first, it has an elegant backend, and it checks all of my boxes. | |||
It still needs some css TLC, but all the major dev is complete. | |||
</pre> | |||
<NuxtLink to="/go" class="btn btn--primary"> | |||
v5, for your consideration | |||
</NuxtLink> | |||
</div> | |||
</main> | |||
</template> | |||
<script> | |||
export default { | |||
mounted () { | |||
const body = document.querySelector('body') | |||
body.classList.add('special') | |||
} | |||
} | |||
</script> | |||
<style> | |||
main.special { | |||
color: #888 !important; | |||
display: flex; | |||
align-items: center; | |||
padding: 3rem; | |||
background: #262626; | |||
overflow-y: scroll; | |||
} | |||
.section { | |||
max-width: 60ch; | |||
border-radius: 2rem; | |||
border: 1px solid #888; | |||
background: rgba(255, 255, 255, 0.05); | |||
padding: 3rem; | |||
} | |||
.btn { | |||
border-radius: 999px; | |||
padding: 0.4em 0.8em; | |||
font-size: 1rem; | |||
white-space: nowrap; | |||
transition: 0.2s all; | |||
} | |||
.btn.btn--primary { | |||
background: #007fff; | |||
color: #fff; | |||
} | |||
</style> |
@ -1,13 +1,25 @@ | |||
<template> | |||
<main> | |||
<h1>Home page</h1> | |||
<NuxtLink to="/go"> | |||
Go! | |||
<main class="empty-page white-bkg"> | |||
<NuxtLogo /> | |||
<NuxtLink to="/go" class="btn btn--primary"> | |||
go to the site | |||
</NuxtLink> | |||
<a href="https://nuxtjs.org">External Link to another page</a> | |||
</main> | |||
</template> | |||
<script> | |||
export default {} | |||
</script> | |||
<style scoped> | |||
html { | |||
background-color: black; | |||
} | |||
.empty-page { | |||
display: flex; | |||
flex-direction: column; | |||
align-items: center; | |||
justify-content: center; | |||
} | |||
</style> |