Add feature image grid
This commit is contained in:
parent
818382bd13
commit
66d4a53777
2
.env.example
Normal file
2
.env.example
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
VUE_APP_UNSPLASH_BASE_URL=https://api.unsplash.com
|
||||||
|
VUE_APP_UNSPLASH_ACCESS_KEY=
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,6 +10,7 @@ geckodriver.log
|
|||||||
# local env files
|
# local env files
|
||||||
.env.local
|
.env.local
|
||||||
.env.*.local
|
.env.*.local
|
||||||
|
.env
|
||||||
|
|
||||||
# Log files
|
# Log files
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
|
36
README.md
36
README.md
@ -1,34 +1,56 @@
|
|||||||
# responsive_image_grid
|
# Responsive Image Grid
|
||||||
|
|
||||||
|
![Alt text](https://s3.crstin.com/public/responsive_image_grid_repo_preview.png)
|
||||||
|
|
||||||
|
## Origin
|
||||||
|
|
||||||
|
The initial commit has been generated by `vue create responsive_image_grid`. The next step has been adding `.prettierrc` and running `yarn lint` to convert the codebase.
|
||||||
|
|
||||||
## Project setup
|
## Project setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn
|
||||||
|
cp .env.example .env
|
||||||
```
|
```
|
||||||
yarn install
|
|
||||||
|
Then add your unsplash key after `VUE_APP_UNSPLASH_ACCESS_KEY=` to the .env file.
|
||||||
|
|
||||||
|
## Run the test suite
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn test
|
||||||
```
|
```
|
||||||
|
|
||||||
### Compiles and hot-reloads for development
|
### Compiles and hot-reloads for development
|
||||||
```
|
|
||||||
|
```bash
|
||||||
yarn serve
|
yarn serve
|
||||||
```
|
```
|
||||||
|
|
||||||
### Compiles and minifies for production
|
### Compiles and minifies for production
|
||||||
```
|
|
||||||
|
```bash
|
||||||
yarn build
|
yarn build
|
||||||
```
|
```
|
||||||
|
|
||||||
### Run your unit tests
|
### Run your unit tests
|
||||||
```
|
|
||||||
|
```bash
|
||||||
yarn test:unit
|
yarn test:unit
|
||||||
```
|
```
|
||||||
|
|
||||||
### Run your end-to-end tests
|
### Run your end-to-end tests
|
||||||
```
|
|
||||||
|
```bash
|
||||||
yarn test:e2e
|
yarn test:e2e
|
||||||
```
|
```
|
||||||
|
|
||||||
### Lints and fixes files
|
### Lints and fixes files
|
||||||
```
|
|
||||||
|
```bash
|
||||||
yarn lint
|
yarn lint
|
||||||
```
|
```
|
||||||
|
|
||||||
### Customize configuration
|
### Customize configuration
|
||||||
|
|
||||||
See [Configuration Reference](https://cli.vuejs.org/config/).
|
See [Configuration Reference](https://cli.vuejs.org/config/).
|
||||||
|
@ -7,10 +7,12 @@
|
|||||||
"build": "vue-cli-service build",
|
"build": "vue-cli-service build",
|
||||||
"test:unit": "vue-cli-service test:unit",
|
"test:unit": "vue-cli-service test:unit",
|
||||||
"test:e2e": "vue-cli-service test:e2e",
|
"test:e2e": "vue-cli-service test:e2e",
|
||||||
|
"test": "yarn test:unit && yarn test:e2e",
|
||||||
"lint": "vue-cli-service lint"
|
"lint": "vue-cli-service lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
|
"normalize.css": "^8.0.1",
|
||||||
"vue": "^2.6.11"
|
"vue": "^2.6.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Lato&display=swap" rel="stylesheet">
|
||||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
15
src/App.vue
15
src/App.vue
@ -1,28 +1,27 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<img alt="Vue logo" src="./assets/logo.png" />
|
<ImageGrid />
|
||||||
<HelloWorld msg="Welcome to Your Vue.js App" />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import HelloWorld from './components/HelloWorld.vue'
|
import ImageGrid from './components/ImageGrid.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
components: {
|
components: {
|
||||||
HelloWorld
|
ImageGrid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@import '~normalize.css/normalize.css';
|
||||||
|
|
||||||
#app {
|
#app {
|
||||||
font-family: Avenir, Helvetica, Arial, sans-serif;
|
font-family: 'Lato', Avenir, Helvetica, Arial, sans-serif;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
text-align: center;
|
padding: 50px;
|
||||||
color: #2c3e50;
|
|
||||||
margin-top: 60px;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 6.7 KiB |
@ -1,130 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="hello">
|
|
||||||
<h1>{{ msg }}</h1>
|
|
||||||
<p>
|
|
||||||
For a guide and recipes on how to configure / customize this project,<br />
|
|
||||||
check out the
|
|
||||||
<a href="https://cli.vuejs.org" target="_blank" rel="noopener"
|
|
||||||
>vue-cli documentation</a
|
|
||||||
>.
|
|
||||||
</p>
|
|
||||||
<h3>Installed CLI Plugins</h3>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener"
|
|
||||||
>babel</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener"
|
|
||||||
>eslint</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-unit-jest"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener"
|
|
||||||
>unit-jest</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-e2e-nightwatch"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener"
|
|
||||||
>e2e-nightwatch</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Essential Links</h3>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="https://forum.vuejs.org" target="_blank" rel="noopener"
|
|
||||||
>Forum</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="https://chat.vuejs.org" target="_blank" rel="noopener"
|
|
||||||
>Community Chat</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="https://twitter.com/vuejs" target="_blank" rel="noopener"
|
|
||||||
>Twitter</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Ecosystem</h3>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<a href="https://router.vuejs.org" target="_blank" rel="noopener"
|
|
||||||
>vue-router</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
href="https://github.com/vuejs/vue-devtools#vue-devtools"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener"
|
|
||||||
>vue-devtools</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener"
|
|
||||||
>vue-loader</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
href="https://github.com/vuejs/awesome-vue"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener"
|
|
||||||
>awesome-vue</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'HelloWorld',
|
|
||||||
props: {
|
|
||||||
msg: String
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
|
||||||
<style scoped lang="scss">
|
|
||||||
h3 {
|
|
||||||
margin: 40px 0 0;
|
|
||||||
}
|
|
||||||
ul {
|
|
||||||
list-style-type: none;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
li {
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0 10px;
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
color: #42b983;
|
|
||||||
}
|
|
||||||
</style>
|
|
112
src/components/ImageGrid.vue
Normal file
112
src/components/ImageGrid.vue
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
<template>
|
||||||
|
<div class="image-grid-container">
|
||||||
|
<div v-if="loading">Loading...</div>
|
||||||
|
|
||||||
|
<div v-else v-for="image in images" :key="image.id">
|
||||||
|
<a :href="image.links.html">
|
||||||
|
<figure>
|
||||||
|
<img :src="image.urls.small" :alt="image.alt_description" />
|
||||||
|
<figcaption>
|
||||||
|
<a :href="image.user.portfolio_url">{{ image.user.first_name }}</a>
|
||||||
|
</figcaption>
|
||||||
|
</figure>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="failure">
|
||||||
|
There has been an error retrieving the requested data
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: true,
|
||||||
|
failure: false,
|
||||||
|
images: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
axios
|
||||||
|
.get(
|
||||||
|
`${process.env.VUE_APP_UNSPLASH_BASE_URL}/photos/?client_id=${process.env.VUE_APP_UNSPLASH_ACCESS_KEY}`
|
||||||
|
)
|
||||||
|
.then((response) => {
|
||||||
|
this.images = response.data
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(error)
|
||||||
|
this.failure = true
|
||||||
|
})
|
||||||
|
.finally(() => (this.loading = false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
$imgBaseSize: 333px;
|
||||||
|
|
||||||
|
.image-grid-container {
|
||||||
|
text-align: center;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax($imgBaseSize, 1fr));
|
||||||
|
grid-auto-rows: minmax(150px, 1fr);
|
||||||
|
grid-gap: 2rem;
|
||||||
|
grid-auto-flow: dense;
|
||||||
|
justify-items: center;
|
||||||
|
font-size: 1.25em;
|
||||||
|
|
||||||
|
a {
|
||||||
|
display: block;
|
||||||
|
word-break: break-all;
|
||||||
|
text-decoration: none;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
figure {
|
||||||
|
position: relative;
|
||||||
|
height: $imgBaseSize;
|
||||||
|
width: $imgBaseSize;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: inherit;
|
||||||
|
width: inherit;
|
||||||
|
object-fit: cover;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.2;
|
||||||
|
transition: opacity;
|
||||||
|
transition-duration: 2000ms;
|
||||||
|
transition-timing-function: ease-out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
figcaption {
|
||||||
|
text-align: center;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
|
||||||
|
> a {
|
||||||
|
padding: 22px 0;
|
||||||
|
text-shadow: lighten(#fdfdfd, 7%);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #aaa;
|
||||||
|
transition: color;
|
||||||
|
transition-duration: 1000ms;
|
||||||
|
transition-timing-function: ease-out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
15
tests/e2e/specs/image_grid.js
Normal file
15
tests/e2e/specs/image_grid.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// For authoring Nightwatch tests, see
|
||||||
|
// https://nightwatchjs.org/guide
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
beforeEach: (browser) => browser.init(),
|
||||||
|
|
||||||
|
'Image grid is present': (browser) => {
|
||||||
|
browser
|
||||||
|
.waitForElementVisible('#app')
|
||||||
|
.assert.elementCount('.image-grid-container', 1)
|
||||||
|
.assert.elementCount('figure img', 10)
|
||||||
|
.assert.elementCount('figure figcaption', 10)
|
||||||
|
.end()
|
||||||
|
}
|
||||||
|
}
|
@ -1,36 +0,0 @@
|
|||||||
////////////////////////////////////////////////////////////////
|
|
||||||
// For authoring Nightwatch tests, see
|
|
||||||
// https://nightwatchjs.org/guide
|
|
||||||
//
|
|
||||||
// For more information on working with page objects see:
|
|
||||||
// https://nightwatchjs.org/guide/working-with-page-objects/
|
|
||||||
////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
beforeEach: (browser) => browser.init(),
|
|
||||||
|
|
||||||
'e2e tests using page objects': (browser) => {
|
|
||||||
const homepage = browser.page.homepage()
|
|
||||||
homepage.waitForElementVisible('@appContainer')
|
|
||||||
|
|
||||||
const app = homepage.section.app
|
|
||||||
app.assert.elementCount('@logo', 1)
|
|
||||||
app.expect.section('@welcome').to.be.visible
|
|
||||||
app.expect
|
|
||||||
.section('@headline')
|
|
||||||
.text.to.match(/^Welcome to Your Vue\.js (.*)App$/)
|
|
||||||
|
|
||||||
browser.end()
|
|
||||||
},
|
|
||||||
|
|
||||||
'verify if string "e2e-nightwatch" is within the cli plugin links': (
|
|
||||||
browser
|
|
||||||
) => {
|
|
||||||
const homepage = browser.page.homepage()
|
|
||||||
const welcomeSection = homepage.section.app.section.welcome
|
|
||||||
|
|
||||||
welcomeSection.expect
|
|
||||||
.element('@cliPluginLinks')
|
|
||||||
.text.to.contain('e2e-nightwatch')
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
// For authoring Nightwatch tests, see
|
|
||||||
// https://nightwatchjs.org/guide
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
'default e2e tests': (browser) => {
|
|
||||||
browser
|
|
||||||
.init()
|
|
||||||
.waitForElementVisible('#app')
|
|
||||||
.assert.elementPresent('.hello')
|
|
||||||
.assert.containsText('h1', 'Welcome to Your Vue.js App')
|
|
||||||
.assert.elementCount('img', 1)
|
|
||||||
.end()
|
|
||||||
},
|
|
||||||
|
|
||||||
'example e2e test using a custom command': (browser) => {
|
|
||||||
browser
|
|
||||||
.openHomepage()
|
|
||||||
.assert.elementPresent('.hello')
|
|
||||||
.end()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
import { shallowMount } from '@vue/test-utils'
|
|
||||||
import HelloWorld from '@/components/HelloWorld.vue'
|
|
||||||
|
|
||||||
describe('HelloWorld.vue', () => {
|
|
||||||
it('renders props.msg when passed', () => {
|
|
||||||
const msg = 'new message'
|
|
||||||
const wrapper = shallowMount(HelloWorld, {
|
|
||||||
propsData: { msg }
|
|
||||||
})
|
|
||||||
expect(wrapper.text()).toMatch(msg)
|
|
||||||
})
|
|
||||||
})
|
|
12
tests/unit/image_grid.spec.js
Normal file
12
tests/unit/image_grid.spec.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { mount } from '@vue/test-utils'
|
||||||
|
import ImageGrid from '@/components/ImageGrid.vue'
|
||||||
|
|
||||||
|
describe('ImageGrid.vue', () => {
|
||||||
|
it('toggles loading', () => {
|
||||||
|
const wrapper = mount(ImageGrid)
|
||||||
|
expect(wrapper.vm.loading).toBe(true)
|
||||||
|
expect(wrapper.text()).toContain('Loading...')
|
||||||
|
wrapper.setData({ loading: false })
|
||||||
|
expect(wrapper.vm.loading).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
@ -7392,6 +7392,11 @@ normalize-url@^3.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559"
|
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559"
|
||||||
integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==
|
integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==
|
||||||
|
|
||||||
|
normalize.css@^8.0.1:
|
||||||
|
version "8.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/normalize.css/-/normalize.css-8.0.1.tgz#9b98a208738b9cc2634caacbc42d131c97487bf3"
|
||||||
|
integrity sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==
|
||||||
|
|
||||||
npm-run-path@^2.0.0:
|
npm-run-path@^2.0.0:
|
||||||
version "2.0.2"
|
version "2.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
|
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
|
||||||
|
Loading…
Reference in New Issue
Block a user