Merge branch 'develop' into main
16
.babelrc
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"test": {
|
||||||
|
"presets": [
|
||||||
|
[
|
||||||
|
"@babel/preset-env",
|
||||||
|
{
|
||||||
|
"targets": {
|
||||||
|
"node": "current"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
> 1%
|
|
||||||
last 2 versions
|
|
||||||
not dead
|
|
||||||
13
.editorconfig
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
25
.eslintrc.js
@@ -1,21 +1,18 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
root: true,
|
root: true,
|
||||||
env: {
|
env: {
|
||||||
|
browser: true,
|
||||||
node: true
|
node: true
|
||||||
},
|
},
|
||||||
extends: [
|
|
||||||
"plugin:vue/vue3-essential",
|
|
||||||
"eslint:recommended",
|
|
||||||
"@vue/typescript/recommended",
|
|
||||||
"@vue/prettier",
|
|
||||||
"@vue/prettier/@typescript-eslint"
|
|
||||||
],
|
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
ecmaVersion: 2020
|
parser: 'babel-eslint'
|
||||||
},
|
},
|
||||||
rules: {
|
extends: [
|
||||||
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
|
'@nuxtjs',
|
||||||
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
|
'plugin:nuxt/recommended'
|
||||||
"@typescript-eslint/no-explicit-any": "off",
|
],
|
||||||
}
|
plugins: [
|
||||||
};
|
],
|
||||||
|
// add your custom rules here
|
||||||
|
rules: {}
|
||||||
|
}
|
||||||
|
|||||||
103
.gitignore
vendored
@@ -1,23 +1,90 @@
|
|||||||
.DS_Store
|
# Created by .ignore support plugin (hsz.mobi)
|
||||||
node_modules
|
### Node template
|
||||||
/dist
|
# Logs
|
||||||
|
/logs
|
||||||
|
*.log
|
||||||
# local env files
|
|
||||||
.env.local
|
|
||||||
.env.*.local
|
|
||||||
|
|
||||||
# Log files
|
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
pnpm-debug.log*
|
|
||||||
|
|
||||||
# Editor directories and files
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# TypeScript v1 declaration files
|
||||||
|
typings/
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
.cache
|
||||||
|
|
||||||
|
# next.js build output
|
||||||
|
.next
|
||||||
|
|
||||||
|
# nuxt.js build output
|
||||||
|
.nuxt
|
||||||
|
|
||||||
|
# Nuxt generate
|
||||||
|
dist
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless
|
||||||
|
|
||||||
|
# IDE / Editor
|
||||||
.idea
|
.idea
|
||||||
.vscode
|
|
||||||
*.suo
|
# Service worker
|
||||||
*.ntvs*
|
sw.*
|
||||||
*.njsproj
|
|
||||||
*.sln
|
# macOS
|
||||||
*.sw?
|
.DS_Store
|
||||||
|
|
||||||
|
# Vim swap files
|
||||||
|
*.swp
|
||||||
|
|||||||
35
README.md
@@ -1,16 +1,27 @@
|
|||||||
# Full Skies
|
# full-skies
|
||||||
This small-scale application is used to consume the API. Its functionnalities for now are only about exploiting the API endpoints to display data.
|
Ce projet a pour but d'exploiter [l'API Le Système Solaire](https://api.le-systeme-solaire.net/) et de proposer une interface simple pour selectionner des favoris.
|
||||||
|
|
||||||
In the future, users could be able to register and create their own list of astral bodies.
|
- [Dependencies](#dependencies)
|
||||||
|
- [How to install](#how-to-install)
|
||||||
## Dependencies
|
## Dependencies
|
||||||
- [Vue](https://vuejs.org/) - Front-end framework
|
* Vue.js
|
||||||
- [Vuex](https://vuex.vuejs.org/) - Store
|
* Nuxt
|
||||||
<!-- - [MongoDB](https://www.mongodb.com/) - Database -->
|
* Axios
|
||||||
|
* Jest
|
||||||
|
|
||||||
## Usage
|
## How to install
|
||||||
**TBI**
|
To install and run the project, you need to clone this project and run these commands in the root folder.
|
||||||
## Contributors
|
|
||||||
- [AlexisNP](https://github.com/AlexisNP)
|
|
||||||
|
|
||||||
## Credits
|
```bash
|
||||||
**TBI**
|
# Install the npm packages
|
||||||
|
$ npm install
|
||||||
|
|
||||||
|
# FOR DEVELOPPERS
|
||||||
|
# Runs an instance of the app on localhost:3000 that hot reloads
|
||||||
|
$ npm run dev
|
||||||
|
|
||||||
|
# FOR PRODUCTION
|
||||||
|
# Compiles and builds for production and starts app
|
||||||
|
$ npm run build
|
||||||
|
$ npm run start
|
||||||
|
```
|
||||||
|
|||||||
40
api/le-systeme-solaire/index.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
import { addCelestialType, addCelestialsType } from '@/plugins/methods'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the API for all celestial bodies and adds its type
|
||||||
|
* @returns Array of celestials in the API
|
||||||
|
*/
|
||||||
|
export const fetchCelestials = () => {
|
||||||
|
return axios
|
||||||
|
.get('https://api.le-systeme-solaire.net/rest/bodies/')
|
||||||
|
.then((res) => {
|
||||||
|
return addCelestialsType(res.data.bodies)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the API for all celestial bodies and adds its type
|
||||||
|
* @returns Array of celestials in the API
|
||||||
|
*/
|
||||||
|
export const fetchCelestial = (slug) => {
|
||||||
|
return axios
|
||||||
|
.get(`https://api.le-systeme-solaire.net/rest/bodies/${slug}`)
|
||||||
|
.then((res) => {
|
||||||
|
const celestial = addCelestialType(res.data)
|
||||||
|
const moons = []
|
||||||
|
if (celestial.moons) {
|
||||||
|
celestial.moons.forEach(async (moon) => {
|
||||||
|
const moonRes = await axios.get(moon.rel)
|
||||||
|
moons.push(addCelestialType(moonRes.data))
|
||||||
|
})
|
||||||
|
celestial.moons = moons
|
||||||
|
}
|
||||||
|
return celestial
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
fetchCelestials,
|
||||||
|
fetchCelestial
|
||||||
|
}
|
||||||
7
assets/README.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# ASSETS
|
||||||
|
|
||||||
|
**This directory is not required, you can delete it if you don't want to use it.**
|
||||||
|
|
||||||
|
This directory contains your un-compiled assets such as LESS, SASS, or JavaScript.
|
||||||
|
|
||||||
|
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#webpacked).
|
||||||
2
assets/scss/_fonts.scss
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
@import url(https://fonts.googleapis.com/icon?family=Material+Icons|Material+Icons+Round);
|
||||||
|
@import url(https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,400;0,700;1,400;1,700&family=Poppins:wght@400;600;700;800;900&display=swap);
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
@import 'libs/normalize';
|
@import 'libs/normalize';
|
||||||
|
|
||||||
@import 'fonts';
|
@import 'fonts';
|
||||||
@import 'variables';
|
|
||||||
@import 'animations';
|
@import 'animations';
|
||||||
|
|
||||||
* {
|
* {
|
||||||
@@ -64,6 +63,13 @@ a {
|
|||||||
color: inherit;
|
color: inherit;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
&.fs-link {
|
||||||
|
color: $primary-xxlight;
|
||||||
|
text-decoration: underline;
|
||||||
|
&:hover {
|
||||||
|
color: $primary-xlight;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
@@ -20,6 +20,9 @@ $danger: $red;
|
|||||||
|
|
||||||
$primary: $space-blue-700;
|
$primary: $space-blue-700;
|
||||||
$primary-light: $space-blue-600;
|
$primary-light: $space-blue-600;
|
||||||
|
$primary-xlight: $space-blue-500;
|
||||||
|
$primary-xxlight: $space-blue-300;
|
||||||
|
|
||||||
|
|
||||||
$heading-font-family: 'Poppins', serif;
|
$heading-font-family: 'Poppins', serif;
|
||||||
$body-font-family: 'Open Sans', sans-serif;
|
$body-font-family: 'Open Sans', sans-serif;
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
presets: ["@vue/cli-plugin-babel/preset"]
|
|
||||||
};
|
|
||||||
@@ -2,42 +2,38 @@
|
|||||||
<div class="navbar">
|
<div class="navbar">
|
||||||
<ul class="navbar-menu no-style">
|
<ul class="navbar-menu no-style">
|
||||||
<li v-for="item in items" :key="item.url" class="navbar-item">
|
<li v-for="item in items" :key="item.url" class="navbar-item">
|
||||||
<router-link :to="item.link" class="navbar-link no-style">
|
<nuxt-link :to="item.link" class="navbar-link no-style">
|
||||||
{{ item.text }}
|
{{ item.text }}
|
||||||
</router-link>
|
</nuxt-link>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script>
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent } from '@vue/composition-api'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "navbar",
|
name: 'Navbar',
|
||||||
data() {
|
data () {
|
||||||
return {
|
return {
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
text: "Home",
|
text: 'Home',
|
||||||
link: "/"
|
link: '/'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: "Astres",
|
text: 'Astres',
|
||||||
link: "/astres"
|
link: '/astres'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: "À propos",
|
text: 'Favoris',
|
||||||
link: "/a-propos"
|
link: '/favoris'
|
||||||
},
|
|
||||||
{
|
|
||||||
text: "Profil",
|
|
||||||
link: "/profil"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -92,7 +88,7 @@ export default defineComponent({
|
|||||||
transition: width 0.25s ease-in-out;
|
transition: width 0.25s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.router-link-active {
|
&.nuxt-link-exact-active {
|
||||||
&:after {
|
&:after {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="fs-loader-wrapper">
|
<div class="fs-loader-wrapper">
|
||||||
<div class="fs-loader"></div>
|
<div class="fs-loader" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script>
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent } from '@vue/composition-api'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "nest-loader"
|
name: 'NestLoader'
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
39
components/atoms/FSButton.vue
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<template>
|
||||||
|
<button
|
||||||
|
class="btn btn-primary"
|
||||||
|
:class="[
|
||||||
|
icon ? 'btn-icon' : ''
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
<span v-if="icon">
|
||||||
|
<img
|
||||||
|
:src="
|
||||||
|
white ? `/icons/${icon}.svg` : `/icons/${icon}-white.svg`
|
||||||
|
"
|
||||||
|
alt=""
|
||||||
|
class="fs-icon icon-sm"
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'FSButton',
|
||||||
|
props: {
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: () => { return '' }
|
||||||
|
},
|
||||||
|
white: {
|
||||||
|
type: Boolean,
|
||||||
|
default: () => { return false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
175
components/celestials/CelestialCard.vue
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
<template>
|
||||||
|
<div class="celestial-card">
|
||||||
|
<div class="card-wrapper">
|
||||||
|
<celestial-card-icon :type="celestial.type" />
|
||||||
|
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="heading-3">
|
||||||
|
{{ celestial.name }}
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
Type :
|
||||||
|
<span class="txt-capitalize">{{ celestial.type }}</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-info">
|
||||||
|
<nuxt-link
|
||||||
|
:to="`/astres/${celestial.id}`"
|
||||||
|
class="no-style"
|
||||||
|
>
|
||||||
|
<span class="material-icons-round">info</span>
|
||||||
|
</nuxt-link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-content">
|
||||||
|
<div v-if="celestial.aroundPlanet">
|
||||||
|
<p>
|
||||||
|
Orbite autour de
|
||||||
|
<nuxt-link
|
||||||
|
:to="`/astres/${celestial.aroundPlanet.planet}`"
|
||||||
|
class="txt-capitalize"
|
||||||
|
>
|
||||||
|
{{ celestial.aroundPlanet.planet }}
|
||||||
|
</nuxt-link>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div v-if="celestial.gravity">
|
||||||
|
<p>Facteur Gravité : {{ celestial.gravity }}</p>
|
||||||
|
</div>
|
||||||
|
<div v-if="celestial.density">
|
||||||
|
<p>Facteur Densité : {{ celestial.density }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="celestial.discoveredBy" class="card-footer">
|
||||||
|
<p>
|
||||||
|
<i>
|
||||||
|
Ce corps céleste a été découvert par
|
||||||
|
{{ celestial.discoveredBy }} le {{ celestial.discoveryDate }}
|
||||||
|
</i>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-actions">
|
||||||
|
<button
|
||||||
|
class="favourite no-style"
|
||||||
|
:class="isFav ? 'active' : ''"
|
||||||
|
@click="toggleFav()"
|
||||||
|
>
|
||||||
|
<span class="icon material-icons-round">favorite</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
import CelestialCardIcon from './CelestialCardIcon.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'CelestialCard',
|
||||||
|
components: { CelestialCardIcon },
|
||||||
|
props: {
|
||||||
|
celestial: {
|
||||||
|
type: Object,
|
||||||
|
default: () => { return {} }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
isFav () {
|
||||||
|
return this.$store.getters.isFav(this.celestial.id)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
toggleFav () {
|
||||||
|
if (!this.isFav) {
|
||||||
|
this.$store.dispatch('toasts/pushToast', {
|
||||||
|
id: uuidv4(),
|
||||||
|
title: 'Favori ajouté',
|
||||||
|
message: `${this.celestial.name} a été ajouté à la liste des favoris.`,
|
||||||
|
link: {
|
||||||
|
text: 'Consultez vos favoris.',
|
||||||
|
url: '/favoris'
|
||||||
|
},
|
||||||
|
category: 'valid',
|
||||||
|
timer: 3
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.$store.dispatch('toasts/pushToast', {
|
||||||
|
id: uuidv4(),
|
||||||
|
title: 'Favori retiré',
|
||||||
|
message: `${this.celestial.name} a été retiré de la liste des favoris.`,
|
||||||
|
link: {
|
||||||
|
text: 'Consultez vos favoris.',
|
||||||
|
url: '/favoris'
|
||||||
|
},
|
||||||
|
category: 'valid',
|
||||||
|
timer: 3
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.$store.dispatch('toggleFav', this.celestial)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.celestial-card {
|
||||||
|
height: 100%;
|
||||||
|
min-height: 100%;
|
||||||
|
padding: 20px;
|
||||||
|
color: $fs-black;
|
||||||
|
background: rgba($white, 85%);
|
||||||
|
border-radius: 5px;
|
||||||
|
|
||||||
|
.card-wrapper {
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
align-items: stretch;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
flex: 0 1 auto;
|
||||||
|
}
|
||||||
|
.card-header {
|
||||||
|
padding-right: 60px;
|
||||||
|
}
|
||||||
|
.card-content {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-info {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-actions {
|
||||||
|
color: #afafaf;
|
||||||
|
.favourite {
|
||||||
|
.icon {
|
||||||
|
color: #afafaf;
|
||||||
|
}
|
||||||
|
&.active {
|
||||||
|
.icon {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
will-change: font-size;
|
||||||
|
animation: toggleFavHeart 0.6s cubic-bezier(0.17, 0.89, 0.32, 1.49);
|
||||||
|
animation-fill-mode: forwards;
|
||||||
|
&:hover {
|
||||||
|
color: darken(#d01d35, 6%) !important
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
66
components/celestials/CelestialCardIcon.vue
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
<template>
|
||||||
|
<div class="card-icon">
|
||||||
|
<img
|
||||||
|
v-if="type === 'planète à lunes'"
|
||||||
|
src="/icons/planet-moons.svg"
|
||||||
|
class="fs-icon"
|
||||||
|
alt="planet icon"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
v-else-if="type === 'planète'"
|
||||||
|
src="/icons/planet.svg"
|
||||||
|
class="fs-icon"
|
||||||
|
alt="planet icon"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
v-else-if="type === 'lune'"
|
||||||
|
src="/icons/moon.svg"
|
||||||
|
class="fs-icon"
|
||||||
|
alt="moon icon"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
v-else-if="type === 'étoile'"
|
||||||
|
src="/icons/sun.svg"
|
||||||
|
class="fs-icon"
|
||||||
|
alt="moon icon"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
v-else
|
||||||
|
src="/icons/stars.svg"
|
||||||
|
alt="moon icon"
|
||||||
|
class="fs-icon"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'CelestialCardIcon',
|
||||||
|
|
||||||
|
props: {
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: () => { return '' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.card-icon {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
bottom: 20px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
user-select: none;
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 4%;
|
||||||
|
img {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
107
components/celestials/CelestialFilters.vue
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
<template>
|
||||||
|
<div class="celestial-filters">
|
||||||
|
<ul class="no-style">
|
||||||
|
<li>
|
||||||
|
<AtomsFSButton
|
||||||
|
:class="[filters.all ? 'active' : '']"
|
||||||
|
@click.native="emitFilter('all')"
|
||||||
|
>
|
||||||
|
Tous
|
||||||
|
</AtomsFSButton>
|
||||||
|
<AtomsFSButton
|
||||||
|
:class="[filters.planets ? 'active' : '']"
|
||||||
|
icon="planet"
|
||||||
|
inverted
|
||||||
|
@click.native="emitFilter('planets')"
|
||||||
|
>
|
||||||
|
Planètes
|
||||||
|
</AtomsFSButton>
|
||||||
|
<AtomsFSButton
|
||||||
|
:class="[filters.moons ? 'active' : '']"
|
||||||
|
icon="moon"
|
||||||
|
inverted
|
||||||
|
@click.native="emitFilter('moons')"
|
||||||
|
>
|
||||||
|
Lunes
|
||||||
|
</AtomsFSButton>
|
||||||
|
<AtomsFSButton
|
||||||
|
:class="[filters.stars ? 'active' : '']"
|
||||||
|
icon="sun"
|
||||||
|
inverted
|
||||||
|
@click.native="emitFilter('stars')"
|
||||||
|
>
|
||||||
|
Etoiles
|
||||||
|
</AtomsFSButton>
|
||||||
|
<AtomsFSButton
|
||||||
|
:class="[filters.others ? 'active' : '']"
|
||||||
|
icon="stars"
|
||||||
|
inverted
|
||||||
|
@click.native="emitFilter('others')"
|
||||||
|
>
|
||||||
|
Autres
|
||||||
|
</AtomsFSButton>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { defineComponent } from '@vue/composition-api'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'CelestialFilters',
|
||||||
|
props: {
|
||||||
|
celestials: {
|
||||||
|
type: Array,
|
||||||
|
default: () => { return [] }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
all: true,
|
||||||
|
planets: false,
|
||||||
|
moons: false,
|
||||||
|
stars: false,
|
||||||
|
others: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* Emits the type of celestial body to filter for to parent
|
||||||
|
*/
|
||||||
|
emitFilter (type) {
|
||||||
|
// Reset filter appearance
|
||||||
|
this.filters = {
|
||||||
|
all: false,
|
||||||
|
planets: false,
|
||||||
|
moons: false,
|
||||||
|
stars: false,
|
||||||
|
others: false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Triggers the correct filter
|
||||||
|
if (type === 'all') {
|
||||||
|
this.filters.all = true
|
||||||
|
} else if (type === 'planets') {
|
||||||
|
this.filters.planets = true
|
||||||
|
} else if (type === 'moons') {
|
||||||
|
this.filters.moons = true
|
||||||
|
} else if (type === 'stars') {
|
||||||
|
this.filters.stars = true
|
||||||
|
} else if (type === 'others') {
|
||||||
|
this.filters.others = true
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$emit('filter:celestials', type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.celestial-filters {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
96
components/celestials/CelestialsList.vue
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
<template>
|
||||||
|
<div class="celestial-list-wrapper">
|
||||||
|
<div v-if="celestials.length > 0">
|
||||||
|
<celestial-filters v-if="hasFilters" @filter:celestials="filterCelestials" />
|
||||||
|
|
||||||
|
<ul class="celestial-list grid no-style">
|
||||||
|
<li
|
||||||
|
v-for="(celestial, index) in sortedCelestials"
|
||||||
|
:key="index"
|
||||||
|
class="celestial-item"
|
||||||
|
>
|
||||||
|
<celestial-card :celestial="celestial" />
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else>
|
||||||
|
<nest-loader />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { defineComponent } from '@vue/composition-api'
|
||||||
|
|
||||||
|
import CelestialCard from '@/components/celestials/CelestialCard.vue'
|
||||||
|
import NestLoader from '@/components/NestLoader.vue'
|
||||||
|
import CelestialFilters from './CelestialFilters.vue'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'CelestialList',
|
||||||
|
components: {
|
||||||
|
CelestialCard,
|
||||||
|
CelestialFilters,
|
||||||
|
NestLoader
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
celestials: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
hasFilters: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Initial state
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
activeFilter: 'all'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
sortedCelestials () {
|
||||||
|
if (this.activeFilter === 'moons') {
|
||||||
|
return this.celestials.filter(e => e.type === 'lune')
|
||||||
|
} else if (this.activeFilter === 'planets') {
|
||||||
|
return this.celestials.filter(
|
||||||
|
e => e.type === 'planète' || e.type === 'planète à lunes'
|
||||||
|
)
|
||||||
|
} else if (this.activeFilter === 'stars') {
|
||||||
|
return this.celestials.filter(e => e.type === 'étoile')
|
||||||
|
} else if (this.activeFilter === 'others') {
|
||||||
|
return this.celestials.filter(e => e.type === 'autre')
|
||||||
|
} else {
|
||||||
|
return this.celestials
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* Applies the filter type to the data
|
||||||
|
*/
|
||||||
|
filterCelestials (type) {
|
||||||
|
this.activeFilter = type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.celestial-list {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: stretch;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
.celestial-item {
|
||||||
|
width: calc(33% - 20px);
|
||||||
|
margin-right: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -6,50 +6,54 @@
|
|||||||
<div class="toast-message">
|
<div class="toast-message">
|
||||||
<slot name="message" />
|
<slot name="message" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="toast-link">
|
||||||
|
<slot name="link" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent } from '@vue/composition-api'
|
||||||
|
|
||||||
import store from "@/store";
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "ToastCard",
|
name: 'ToastCard',
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
closing: false
|
|
||||||
};
|
|
||||||
},
|
|
||||||
props: {
|
props: {
|
||||||
toast: Object
|
toast: {
|
||||||
|
type: Object,
|
||||||
|
default: () => { return {} }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
closing: false,
|
||||||
|
tickingRate: 900
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
// Starts countdown to initial timer value
|
||||||
|
this.countdown(this.toast.timer)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// Counts down until 0 is reached
|
// Counts down until 0 is reached
|
||||||
countdown(timeToLive) {
|
countdown (timeToLive) {
|
||||||
if (timeToLive > 0) {
|
if (timeToLive > 0) {
|
||||||
console.log(timeToLive);
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
timeToLive = timeToLive - 1;
|
timeToLive = timeToLive - 1
|
||||||
this.countdown(timeToLive);
|
this.countdown(timeToLive)
|
||||||
}, 900);
|
}, this.tickingRate)
|
||||||
} else {
|
} else {
|
||||||
// When timer ends
|
// When timer ends
|
||||||
this.closing = true;
|
this.closing = true
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.close();
|
this.close()
|
||||||
}, 1200);
|
}, this.tickingRate)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
close() {
|
close () {
|
||||||
store.dispatch("toasts/purgeToast", this.toast.id);
|
this.$store.dispatch('toasts/purgeToast', this.toast.id)
|
||||||
}
|
}
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
// Starts countdown to initial timer value
|
|
||||||
this.countdown(this.toast.timer);
|
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -61,11 +65,23 @@ export default defineComponent({
|
|||||||
animation: fadeIn 1s cubic-bezier(0.175, 1, 0.32, 1),
|
animation: fadeIn 1s cubic-bezier(0.175, 1, 0.32, 1),
|
||||||
slideFromRight 1s cubic-bezier(0.175, 1, 0.32, 1);
|
slideFromRight 1s cubic-bezier(0.175, 1, 0.32, 1);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
.toast-title {
|
.toast-title {
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: $fw-bold;
|
font-weight: $fw-bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toast-link {
|
||||||
|
a {
|
||||||
|
color: $primary-xxlight;
|
||||||
|
text-decoration: none;
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&:after {
|
&:after {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
display: block;
|
display: block;
|
||||||
@@ -77,6 +93,7 @@ export default defineComponent({
|
|||||||
height: 6px;
|
height: 6px;
|
||||||
background: rgba($fs-black, 33%);
|
background: rgba($fs-black, 33%);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.info {
|
&.info {
|
||||||
background-color: $info;
|
background-color: $info;
|
||||||
}
|
}
|
||||||
@@ -90,6 +107,7 @@ export default defineComponent({
|
|||||||
&.danger {
|
&.danger {
|
||||||
background-color: $danger;
|
background-color: $danger;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.closing {
|
&.closing {
|
||||||
animation: fadeOut 1.2s cubic-bezier(0.175, 1, 0.32, 1),
|
animation: fadeOut 1.2s cubic-bezier(0.175, 1, 0.32, 1),
|
||||||
slideFromLeft 1.2s cubic-bezier(0.175, 1, 0.32, 1);
|
slideFromLeft 1.2s cubic-bezier(0.175, 1, 0.32, 1);
|
||||||
@@ -1,32 +1,39 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="toast-wrapper">
|
<div class="toast-wrapper">
|
||||||
<div class="toast-item" v-for="toast in queue" :key="toast.id">
|
<div v-for="toast in queue" :key="toast.id" class="toast-item">
|
||||||
<toast-card :variant="toast.category" :toast="toast">
|
<toast-card :variant="toast.category" :toast="toast">
|
||||||
<template #title>{{ toast.title }}</template>
|
<template #title>
|
||||||
|
{{ toast.title }}
|
||||||
|
</template>
|
||||||
<template #message>
|
<template #message>
|
||||||
{{ toast.message }}
|
{{ toast.message }}
|
||||||
</template>
|
</template>
|
||||||
|
<template #link>
|
||||||
|
<nuxt-link :to="toast.link.url">
|
||||||
|
{{ toast.link.text }}
|
||||||
|
</nuxt-link>
|
||||||
|
</template>
|
||||||
</toast-card>
|
</toast-card>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent } from '@vue/composition-api'
|
||||||
|
|
||||||
import ToastCard from "./ToastCard.vue";
|
import ToastCard from './ToastCard.vue'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "ToastsList",
|
name: 'ToastsList',
|
||||||
components: {
|
components: {
|
||||||
ToastCard
|
ToastCard
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
queue() {
|
queue () {
|
||||||
return this.$store.state.toasts.queue;
|
return this.$store.state.toasts.queue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
21
jest.config.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
module.exports = {
|
||||||
|
moduleNameMapper: {
|
||||||
|
'^@/(.*)$': '<rootDir>/$1',
|
||||||
|
'^~/(.*)$': '<rootDir>/$1',
|
||||||
|
'^vue$': 'vue/dist/vue.common.js'
|
||||||
|
},
|
||||||
|
moduleFileExtensions: [
|
||||||
|
'js',
|
||||||
|
'vue',
|
||||||
|
'json'
|
||||||
|
],
|
||||||
|
transform: {
|
||||||
|
'^.+\\.js$': 'babel-jest',
|
||||||
|
'.*\\.(vue)$': 'vue-jest'
|
||||||
|
},
|
||||||
|
collectCoverage: true,
|
||||||
|
collectCoverageFrom: [
|
||||||
|
'<rootDir>/components/**/*.vue',
|
||||||
|
'<rootDir>/pages/**/*.vue'
|
||||||
|
]
|
||||||
|
}
|
||||||
12
jsconfig.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"~/*": ["./*"],
|
||||||
|
"@/*": ["./*"],
|
||||||
|
"~~/*": ["./*"],
|
||||||
|
"@@/*": ["./*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"exclude": ["node_modules", ".nuxt", "dist"]
|
||||||
|
}
|
||||||
7
layouts/README.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# LAYOUTS
|
||||||
|
|
||||||
|
**This directory is not required, you can delete it if you don't want to use it.**
|
||||||
|
|
||||||
|
This directory contains your Application Layouts.
|
||||||
|
|
||||||
|
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/views#layouts).
|
||||||
@@ -2,23 +2,18 @@
|
|||||||
<div class="fs-wrapper">
|
<div class="fs-wrapper">
|
||||||
<navbar />
|
<navbar />
|
||||||
<div class="fs-content">
|
<div class="fs-content">
|
||||||
<router-view />
|
<Nuxt />
|
||||||
</div>
|
</div>
|
||||||
<toasts-list />
|
<toasts-list />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script>
|
||||||
import { defineComponent } from "vue";
|
import ToastsList from '@/components/toast/ToastsList.vue'
|
||||||
import Navbar from "@/components/Navbar.vue";
|
|
||||||
import ToastsList from "@/components/toast/ToastsList.vue";
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default {
|
||||||
components: {
|
components: { ToastsList }
|
||||||
Navbar,
|
}
|
||||||
ToastsList
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
8
middleware/README.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# MIDDLEWARE
|
||||||
|
|
||||||
|
**This directory is not required, you can delete it if you don't want to use it.**
|
||||||
|
|
||||||
|
This directory contains your application middleware.
|
||||||
|
Middleware let you define custom functions that can be run before rendering either a page or a group of pages.
|
||||||
|
|
||||||
|
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing#middleware).
|
||||||
53
nuxt.config.js
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
export default {
|
||||||
|
// Global page headers: https://go.nuxtjs.dev/config-head
|
||||||
|
head: {
|
||||||
|
title: 'Full Skies',
|
||||||
|
htmlAttrs: {
|
||||||
|
lang: 'fr'
|
||||||
|
},
|
||||||
|
meta: [
|
||||||
|
{ charset: 'utf-8' },
|
||||||
|
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
||||||
|
{ hid: 'description', name: 'description', content: 'Application éducative et informative sur les astres du système solaire.' }
|
||||||
|
],
|
||||||
|
link: [
|
||||||
|
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// Global CSS: https://go.nuxtjs.dev/config-css
|
||||||
|
css: [
|
||||||
|
'@/assets/scss/_global.scss'
|
||||||
|
],
|
||||||
|
|
||||||
|
styleResources: {
|
||||||
|
scss: [
|
||||||
|
'@/assets/scss/_variables.scss'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
|
||||||
|
plugins: [],
|
||||||
|
|
||||||
|
// Auto import components: https://go.nuxtjs.dev/config-components
|
||||||
|
components: true,
|
||||||
|
|
||||||
|
// Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
|
||||||
|
buildModules: [
|
||||||
|
// https://go.nuxtjs.dev/eslint
|
||||||
|
'@nuxtjs/eslint-module'
|
||||||
|
],
|
||||||
|
|
||||||
|
// Modules: https://go.nuxtjs.dev/config-modules
|
||||||
|
modules: [
|
||||||
|
// https://go.nuxtjs.dev/axios
|
||||||
|
'@nuxtjs/axios',
|
||||||
|
'@nuxtjs/style-resources'
|
||||||
|
],
|
||||||
|
|
||||||
|
// Axios module configuration: https://go.nuxtjs.dev/config-axios
|
||||||
|
axios: {},
|
||||||
|
|
||||||
|
// Build Configuration: https://go.nuxtjs.dev/config-build
|
||||||
|
build: {}
|
||||||
|
}
|
||||||
16551
package-lock.json
generated
55
package.json
@@ -1,39 +1,38 @@
|
|||||||
{
|
{
|
||||||
"name": "full-skies",
|
"name": "full-skies-nuxt",
|
||||||
"version": "0.1.0",
|
"version": "1.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "vue-cli-service serve",
|
"dev": "nuxt",
|
||||||
"build": "vue-cli-service build",
|
"build": "nuxt build",
|
||||||
"lint": "vue-cli-service lint"
|
"start": "nuxt start",
|
||||||
|
"generate": "nuxt generate",
|
||||||
|
"lint:js": "eslint --ext \".js,.vue\" --ignore-path .gitignore .",
|
||||||
|
"lint": "npm run lint:js",
|
||||||
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.21.1",
|
"@nuxtjs/axios": "^5.12.5",
|
||||||
"core-js": "^3.6.5",
|
"@nuxtjs/style-resources": "^1.0.0",
|
||||||
"uuid": "^8.3.2",
|
"@vue/composition-api": "^1.0.0-rc.5",
|
||||||
"vue": "^3.0.0",
|
"core-js": "^3.8.2",
|
||||||
"vue-router": "^4.0.0-0",
|
"node-sass": "^5.0.0",
|
||||||
"vuex": "^4.0.0-0"
|
"nuxt": "^2.14.12"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/uuid": "^8.3.0",
|
"@nuxtjs/eslint-config": "^5.0.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^2.33.0",
|
"@nuxtjs/eslint-module": "^3.0.2",
|
||||||
"@typescript-eslint/parser": "^2.33.0",
|
"@vue/test-utils": "^1.1.2",
|
||||||
"@vue/cli-plugin-babel": "~4.5.0",
|
"babel-core": "7.0.0-bridge.0",
|
||||||
"@vue/cli-plugin-eslint": "~4.5.0",
|
"babel-eslint": "^10.1.0",
|
||||||
"@vue/cli-plugin-router": "~4.5.0",
|
"babel-jest": "^26.6.3",
|
||||||
"@vue/cli-plugin-typescript": "~4.5.0",
|
"eslint": "^7.18.0",
|
||||||
"@vue/cli-plugin-vuex": "~4.5.0",
|
"eslint-plugin-nuxt": "^2.0.0",
|
||||||
"@vue/cli-service": "~4.5.0",
|
|
||||||
"@vue/compiler-sfc": "^3.0.0",
|
|
||||||
"@vue/eslint-config-prettier": "^6.0.0",
|
|
||||||
"@vue/eslint-config-typescript": "^5.0.2",
|
|
||||||
"eslint": "^6.7.2",
|
|
||||||
"eslint-plugin-prettier": "^3.1.3",
|
"eslint-plugin-prettier": "^3.1.3",
|
||||||
"eslint-plugin-vue": "^7.0.0-0",
|
"eslint-plugin-vue": "^7.4.1",
|
||||||
"prettier": "^1.19.1",
|
|
||||||
"sass": "^1.32.8",
|
"sass": "^1.32.8",
|
||||||
"sass-loader": "10.1.1",
|
"sass-loader": "^10.1.1",
|
||||||
"typescript": "~3.9.3"
|
"jest": "^26.6.3",
|
||||||
|
"vue-jest": "^3.0.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
6
pages/README.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# PAGES
|
||||||
|
|
||||||
|
This directory contains your Application Views and Routes.
|
||||||
|
The framework reads all the `*.vue` files inside this directory and creates the router of your application.
|
||||||
|
|
||||||
|
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing).
|
||||||
86
pages/astres/_slug.vue
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
<template>
|
||||||
|
<section class="celestial bg-image">
|
||||||
|
<main v-if="celestial">
|
||||||
|
<header>
|
||||||
|
<h1 class="heading-1">
|
||||||
|
<span>{{ celestial.name }}</span>
|
||||||
|
<span v-if="celestial.name != celestial.englishName">/ {{ celestial.englishName }}</span>
|
||||||
|
<span class="txt-capitalize">- {{ celestial.type }}</span>
|
||||||
|
</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="section-content">
|
||||||
|
<div class="celestial-body">
|
||||||
|
<div>
|
||||||
|
<h3 class="heading-3">
|
||||||
|
Informations
|
||||||
|
</h3>
|
||||||
|
<p v-if="celestial.aroundPlanet">
|
||||||
|
Orbite autour de
|
||||||
|
<nuxt-link
|
||||||
|
:to="`/astres/${celestial.aroundPlanet.planet}`"
|
||||||
|
class="txt-capitalize fs-link"
|
||||||
|
>
|
||||||
|
{{ celestial.aroundPlanet.planet }}
|
||||||
|
</nuxt-link>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p v-if="celestial.discoveredBy">
|
||||||
|
Découvert par {{ celestial.discoveredBy }} le {{ celestial.discoveryDate }}
|
||||||
|
</p>
|
||||||
|
<p>Facteur Gravité : {{ celestial.gravity }}</p>
|
||||||
|
<p>Facteur Densité : {{ celestial.density }}</p>
|
||||||
|
<p>Inclinaison : {{ celestial.inclination }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="celestial.moons" class="celestial-moons">
|
||||||
|
<h2 class="heading-2">
|
||||||
|
Astres orbitant {{ celestial.name }}
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<celestials-list :celestials="celestial.moons" :has-filters="false" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// API
|
||||||
|
import { fetchCelestial } from '@/api/le-systeme-solaire'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Celestial',
|
||||||
|
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
celestial: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted () {
|
||||||
|
// Fetches from API...
|
||||||
|
fetchCelestial(this.$route.params.slug)
|
||||||
|
.then((res) => {
|
||||||
|
this.celestial = res
|
||||||
|
return this.celestial
|
||||||
|
})
|
||||||
|
// .catch((err) => {
|
||||||
|
// console.error(err)
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.celestial {
|
||||||
|
position: relative;
|
||||||
|
min-height: 100%;
|
||||||
|
padding: 25px 5%;
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
background-image: url("/celestials_bg-min.jpg");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
56
pages/astres/index.vue
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<template>
|
||||||
|
<section class="celestials bg-image">
|
||||||
|
<main>
|
||||||
|
<header>
|
||||||
|
<h1 class="heading-1">
|
||||||
|
Le système solaire
|
||||||
|
</h1>
|
||||||
|
</header>
|
||||||
|
<div class="section-content">
|
||||||
|
<celestials-list :celestials="celestials" />
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// API
|
||||||
|
import { fetchCelestials } from '@/api/le-systeme-solaire'
|
||||||
|
|
||||||
|
import CelestialsList from '@/components/celestials/CelestialsList.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Celestials',
|
||||||
|
components: {
|
||||||
|
CelestialsList
|
||||||
|
},
|
||||||
|
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
celestials: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted () {
|
||||||
|
fetchCelestials()
|
||||||
|
.then((res) => {
|
||||||
|
this.celestials = res
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.error = 'Impossible de récupérer les astres.'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.celestials {
|
||||||
|
position: relative;
|
||||||
|
min-height: 100%;
|
||||||
|
padding: 25px 5%;
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
background-image: url("/celestials_bg-min.jpg");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
45
pages/favoris/index.vue
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<template>
|
||||||
|
<section class="favourites bg-image">
|
||||||
|
<main>
|
||||||
|
<header>
|
||||||
|
<h1 class="heading-1">
|
||||||
|
Mes favoris
|
||||||
|
</h1>
|
||||||
|
</header>
|
||||||
|
<div class="section-content">
|
||||||
|
<div v-if="favourites && favourites.length >= 1">
|
||||||
|
<celestials-list :celestials="favourites" />
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<h3 class="heading-3">
|
||||||
|
Vous n'avez aucun favori pour le moment.
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'Favourites',
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
favourites () {
|
||||||
|
return this.$store.state.user.favourites
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.favourites {
|
||||||
|
position: relative;
|
||||||
|
min-height: 100%;
|
||||||
|
padding: 25px 5%;
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
background-image: url("/home_bg-min.jpg");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="home bg-image bg-fade-in">
|
<section class="home bg-image bg-fade-in">
|
||||||
<div class="splash fade-in-children">
|
<div class="splash fade-in-children">
|
||||||
<h2 class="heading-1">Full Skies</h2>
|
<h2 class="heading-1">
|
||||||
|
Full Skies
|
||||||
|
</h2>
|
||||||
<p class="heading-2">
|
<p class="heading-2">
|
||||||
Explorez les cieux et le système solaire avec Full Skies !
|
Explorez les cieux et le système solaire avec Full Skies !
|
||||||
</p>
|
</p>
|
||||||
@@ -13,12 +15,10 @@
|
|||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script>
|
||||||
import { defineComponent } from "vue";
|
export default {
|
||||||
|
name: 'Home'
|
||||||
export default defineComponent({
|
}
|
||||||
name: "Home"
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
7
plugins/README.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# PLUGINS
|
||||||
|
|
||||||
|
**This directory is not required, you can delete it if you don't want to use it.**
|
||||||
|
|
||||||
|
This directory contains Javascript plugins that you want to run before mounting the root Vue.js application.
|
||||||
|
|
||||||
|
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/plugins).
|
||||||
31
plugins/methods/index.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
export const addCelestialType = (celestial) => {
|
||||||
|
if (celestial.isPlanet) {
|
||||||
|
if (celestial.moons) {
|
||||||
|
celestial.type = 'planète à lunes'
|
||||||
|
} else {
|
||||||
|
celestial.type = 'planète'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if element is moon
|
||||||
|
} else if (celestial.aroundPlanet != null) {
|
||||||
|
celestial.type = 'lune'
|
||||||
|
|
||||||
|
// Check if element is star
|
||||||
|
} else if (celestial.id === 'soleil') {
|
||||||
|
celestial.type = 'étoile'
|
||||||
|
|
||||||
|
// ...else, body is "other"
|
||||||
|
} else {
|
||||||
|
celestial.type = 'autre'
|
||||||
|
}
|
||||||
|
return celestial
|
||||||
|
}
|
||||||
|
|
||||||
|
export const addCelestialsType = (celestials) => {
|
||||||
|
return celestials.map(e => addCelestialType(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
addCelestialType,
|
||||||
|
addCelestialsType
|
||||||
|
}
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
||||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
|
||||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<noscript>
|
|
||||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
|
||||||
</noscript>
|
|
||||||
<div id="app"></div>
|
|
||||||
<!-- built files will be auto injected -->
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
import axios from "axios";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches the API for all celestial bodies
|
|
||||||
* @returns Array of celestials in the API
|
|
||||||
*/
|
|
||||||
export const fetchCelestials = (): Promise<any> => {
|
|
||||||
return axios
|
|
||||||
.get("https://api.le-systeme-solaire.net/rest/bodies/")
|
|
||||||
.then(res => {
|
|
||||||
return res.data.bodies;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches the API for all celestial bodies
|
|
||||||
* @returns Array of celestials in the API
|
|
||||||
*/
|
|
||||||
export const fetchCelestial = (slug: string): Promise<any> => {
|
|
||||||
return axios
|
|
||||||
.get(`https://api.le-systeme-solaire.net/rest/bodies/${slug}`)
|
|
||||||
.then(res => {
|
|
||||||
return res.data;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
fetchCelestials,
|
|
||||||
fetchCelestial
|
|
||||||
};
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
import axios from "axios";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the excerpt of the wikipedia (fr) article for the specific celestial object
|
|
||||||
* @param celestial A celestial object
|
|
||||||
*/
|
|
||||||
export const fetchWikipediaExcerpt = async (celestial: any): Promise<any> => {
|
|
||||||
let query = 'https://fr.wikipedia.org/w/api.php?action=opensearch';
|
|
||||||
|
|
||||||
switch (celestial.id) {
|
|
||||||
case "soleil":
|
|
||||||
case "lune":
|
|
||||||
query += `&search=${celestial.id}`;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "planète à lunes":
|
|
||||||
query += `&search=${celestial.id}%20planète`;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
query += `&search=${celestial.id}%20${celestial.type}`;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
query += "&limit=1&namespace=0&format=json";
|
|
||||||
|
|
||||||
console.log(query);
|
|
||||||
|
|
||||||
|
|
||||||
const req = await axios.get(query);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
fetchWikipediaExcerpt
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 6.7 KiB |
@@ -1,2 +0,0 @@
|
|||||||
@import url('https://fonts.googleapis.com/icon?family=Material+Icons|Material+Icons+Round');
|
|
||||||
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,400;0,700;1,400;1,700&family=Poppins:wght@400;600;700;800;900&display=swap');
|
|
||||||
@@ -1,217 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="celestial-card">
|
|
||||||
<div class="card-wrapper">
|
|
||||||
<div class="card-icon">
|
|
||||||
<img
|
|
||||||
v-if="celestial.type === 'planète à lunes'"
|
|
||||||
src="/icons/saturn-and-other-planets.svg"
|
|
||||||
class="fs-icon"
|
|
||||||
alt="planet icon"
|
|
||||||
/>
|
|
||||||
<img
|
|
||||||
v-else-if="celestial.type === 'planète'"
|
|
||||||
src="/icons/saturn-planet-shape.svg"
|
|
||||||
class="fs-icon"
|
|
||||||
alt="planet icon"
|
|
||||||
/>
|
|
||||||
<img
|
|
||||||
v-else-if="celestial.type === 'lune'"
|
|
||||||
src="icons/moon-and-stars-in-a-cloud.svg"
|
|
||||||
class="fs-icon"
|
|
||||||
alt="moon icon"
|
|
||||||
/>
|
|
||||||
<img
|
|
||||||
v-else-if="celestial.type === 'étoile'"
|
|
||||||
src="icons/sun-shape.svg"
|
|
||||||
class="fs-icon"
|
|
||||||
alt="moon icon"
|
|
||||||
/>
|
|
||||||
<img
|
|
||||||
v-else
|
|
||||||
src="icons/stars-group.svg"
|
|
||||||
alt="moon icon"
|
|
||||||
class="fs-icon"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card-header">
|
|
||||||
<h3 class="heading-3">{{ celestial.name }}</h3>
|
|
||||||
<p>
|
|
||||||
Type :
|
|
||||||
<span class="txt-capitalize">{{ celestial.type }}</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card-info">
|
|
||||||
<router-link
|
|
||||||
:to="{ name: 'CelesteSingle', params: { slug: celestial.id } }"
|
|
||||||
class="no-style"
|
|
||||||
>
|
|
||||||
<span class="material-icons-round">info</span>
|
|
||||||
</router-link>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card-content">
|
|
||||||
<div v-if="celestial.aroundPlanet">
|
|
||||||
<p>
|
|
||||||
Orbite autour de
|
|
||||||
<router-link
|
|
||||||
:to="{
|
|
||||||
name: 'CelesteSingle',
|
|
||||||
params: { slug: celestial.aroundPlanet.planet }
|
|
||||||
}"
|
|
||||||
class="txt-capitalize"
|
|
||||||
>
|
|
||||||
{{ celestial.aroundPlanet.planet }}
|
|
||||||
</router-link>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div v-if="celestial.gravity">
|
|
||||||
<p>Facteur Gravité : {{ celestial.gravity }}</p>
|
|
||||||
</div>
|
|
||||||
<div v-if="celestial.density">
|
|
||||||
<p>Facteur Densité : {{ celestial.density }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card-footer" v-if="celestial.discoveredBy">
|
|
||||||
<p>
|
|
||||||
<i>
|
|
||||||
Ce corps céleste a été découvert par
|
|
||||||
{{ celestial.discoveredBy }} le {{ celestial.discoveryDate }}
|
|
||||||
</i>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card-actions">
|
|
||||||
<button
|
|
||||||
@click="toggleFav(celestial)"
|
|
||||||
class="favourite no-style"
|
|
||||||
:class="isFav ? 'active' : ''"
|
|
||||||
>
|
|
||||||
<span class="icon material-icons-round">favorite</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from "vue";
|
|
||||||
import { v4 as uuidv4 } from "uuid";
|
|
||||||
|
|
||||||
import store from "@/store";
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "celestial-card",
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
type: "unknown"
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
isFav() {
|
|
||||||
if (store.getters.isFav(this.celestial?.id)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
celestial: Object
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
toggleFav: (celestial: any) => {
|
|
||||||
store.dispatch("toggleFav", celestial.id);
|
|
||||||
if (store.getters.isFav(celestial.id)) {
|
|
||||||
store.dispatch("toasts/pushToast", {
|
|
||||||
id: uuidv4(),
|
|
||||||
title: "Favori ajouté",
|
|
||||||
message: `${celestial.name} a été ajouté à la liste des favoris.`,
|
|
||||||
category: "valid",
|
|
||||||
timer: 3
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
store.dispatch("toasts/pushToast", {
|
|
||||||
id: uuidv4(),
|
|
||||||
title: "Favori retiré",
|
|
||||||
message: `${celestial.name} a été retiré de la liste des favoris.`,
|
|
||||||
category: "valid",
|
|
||||||
timer: 3
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.celestial-card {
|
|
||||||
height: 100%;
|
|
||||||
min-height: 100%;
|
|
||||||
padding: 20px;
|
|
||||||
color: $fs-black;
|
|
||||||
background: rgba($white, 85%);
|
|
||||||
border-radius: 5px;
|
|
||||||
|
|
||||||
.card-wrapper {
|
|
||||||
position: relative;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-flow: column;
|
|
||||||
align-items: stretch;
|
|
||||||
|
|
||||||
.card-icon {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
top: 20px;
|
|
||||||
bottom: 20px;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
user-select: none;
|
|
||||||
pointer-events: none;
|
|
||||||
opacity: 4%;
|
|
||||||
img {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
z-index: -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> * {
|
|
||||||
flex: 0 1 auto;
|
|
||||||
}
|
|
||||||
.card-header {
|
|
||||||
padding-right: 60px;
|
|
||||||
}
|
|
||||||
.card-content {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
min-height: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-info {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-actions {
|
|
||||||
color: #afafaf;
|
|
||||||
.favourite {
|
|
||||||
.icon {
|
|
||||||
color: #afafaf;
|
|
||||||
}
|
|
||||||
&.active {
|
|
||||||
.icon {
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
will-change: font-size;
|
|
||||||
animation: toggleFavHeart 0.6s cubic-bezier(0.17, 0.89, 0.32, 1.49);
|
|
||||||
animation-fill-mode: forwards;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="celestial-filters">
|
|
||||||
<ul class="no-style">
|
|
||||||
<li>
|
|
||||||
<button
|
|
||||||
class="btn btn-primary"
|
|
||||||
:class="[filters.all ? 'active' : '']"
|
|
||||||
@click="emitFilter('all')"
|
|
||||||
>
|
|
||||||
Tous
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="btn btn-primary btn-icon"
|
|
||||||
:class="[filters.planets ? 'active' : '']"
|
|
||||||
@click="emitFilter('planets')"
|
|
||||||
>
|
|
||||||
Planètes
|
|
||||||
<img
|
|
||||||
src="icons/saturn-planet-shape-white.svg"
|
|
||||||
alt=""
|
|
||||||
class="fs-icon icon-sm"
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="btn btn-primary btn-icon"
|
|
||||||
:class="[filters.moons ? 'active' : '']"
|
|
||||||
@click="emitFilter('moons')"
|
|
||||||
>
|
|
||||||
Lunes
|
|
||||||
<img
|
|
||||||
src="icons/moon-and-stars-in-a-cloud-white.svg"
|
|
||||||
alt=""
|
|
||||||
class="fs-icon icon-sm"
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="btn btn-primary btn-icon"
|
|
||||||
:class="[filters.stars ? 'active' : '']"
|
|
||||||
@click="emitFilter('stars')"
|
|
||||||
>
|
|
||||||
Etoiles
|
|
||||||
<img src="icons/sun-shape-white.svg" alt="" class="fs-icon icon-sm" />
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="btn btn-primary btn-icon"
|
|
||||||
:class="[filters.others ? 'active' : '']"
|
|
||||||
@click="emitFilter('others')"
|
|
||||||
>
|
|
||||||
Autres
|
|
||||||
<img
|
|
||||||
src="icons/stars-group-white.svg"
|
|
||||||
alt=""
|
|
||||||
class="fs-icon icon-sm"
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from "vue";
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "celestial-filters",
|
|
||||||
props: {
|
|
||||||
celestials: {
|
|
||||||
type: Array
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
filters: {
|
|
||||||
all: true,
|
|
||||||
planets: false,
|
|
||||||
moons: false,
|
|
||||||
stars: false,
|
|
||||||
others: false
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
/**
|
|
||||||
* Emits the type of celestial body to filter for to parent
|
|
||||||
*/
|
|
||||||
emitFilter(type: string) {
|
|
||||||
// Reset filter appearance
|
|
||||||
this.filters = {
|
|
||||||
all: false,
|
|
||||||
planets: false,
|
|
||||||
moons: false,
|
|
||||||
stars: false,
|
|
||||||
others: false
|
|
||||||
};
|
|
||||||
|
|
||||||
// Triggers the correct filter
|
|
||||||
if (type == "all") {
|
|
||||||
this.filters.all = true;
|
|
||||||
} else if (type == "planets") {
|
|
||||||
this.filters.planets = true;
|
|
||||||
} else if (type == "moons") {
|
|
||||||
this.filters.moons = true;
|
|
||||||
} else if (type == "stars") {
|
|
||||||
this.filters.stars = true;
|
|
||||||
} else if (type == "others") {
|
|
||||||
this.filters.others = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emit filter type
|
|
||||||
this.$emit("filter:celestials", type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.celestial-filters {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="celestial-list-wrapper">
|
|
||||||
<celestial-filters @filter:celestials="filterCelestials" />
|
|
||||||
<ul v-if="celestials" class="celestial-list grid no-style">
|
|
||||||
<li
|
|
||||||
v-for="(celestial, index) in sortedCelestials"
|
|
||||||
:key="index"
|
|
||||||
class="celestial-item"
|
|
||||||
>
|
|
||||||
<celestial-card :celestial="celestial" />
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from "vue";
|
|
||||||
|
|
||||||
import CelestialCard from "@/components/celestials/CelestialCard.vue";
|
|
||||||
import CelestialFilters from "./CelestialFilters.vue";
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "celestial-list",
|
|
||||||
components: {
|
|
||||||
CelestialCard,
|
|
||||||
CelestialFilters
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
celestials: {
|
|
||||||
type: Array,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Initial state
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
activeFilter: "all"
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
sortedCelestials(): Array<any> {
|
|
||||||
if (this.activeFilter == "moons") {
|
|
||||||
return this.celestials.filter((e: any) => e.type === "lune");
|
|
||||||
} else if (this.activeFilter == "planets") {
|
|
||||||
return this.celestials.filter(
|
|
||||||
(e: any) => e.type === "planète" || e.type === "planète à lunes"
|
|
||||||
);
|
|
||||||
} else if (this.activeFilter == "stars") {
|
|
||||||
return this.celestials.filter((e: any) => e.type === "étoile");
|
|
||||||
} else if (this.activeFilter == "others") {
|
|
||||||
return this.celestials.filter((e: any) => e.type === "autre");
|
|
||||||
} else {
|
|
||||||
return this.celestials;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
/**
|
|
||||||
* Applies the filter type to the data
|
|
||||||
*/
|
|
||||||
filterCelestials(type: string) {
|
|
||||||
this.activeFilter = type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.celestial-list {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: stretch;
|
|
||||||
flex-flow: row wrap;
|
|
||||||
.celestial-item {
|
|
||||||
width: calc(33% - 15px);
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
12
src/main.ts
@@ -1,12 +0,0 @@
|
|||||||
import { createApp } from "vue";
|
|
||||||
import App from "./App.vue";
|
|
||||||
import router from "./router";
|
|
||||||
import store from "./store";
|
|
||||||
|
|
||||||
import "@/assets/scss/libs/_normalize.scss";
|
|
||||||
import "@/assets/scss/_global.scss";
|
|
||||||
|
|
||||||
createApp(App)
|
|
||||||
.use(store)
|
|
||||||
.use(router)
|
|
||||||
.mount("#app");
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
export const addCelestialType = (celestial: any) => {
|
|
||||||
if (celestial.isPlanet) {
|
|
||||||
if (celestial.moons) {
|
|
||||||
celestial.type = "planète à lunes";
|
|
||||||
} else {
|
|
||||||
celestial.type = "planète";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if element is moon
|
|
||||||
} else if (celestial.aroundPlanet != null) {
|
|
||||||
celestial.type = "lune";
|
|
||||||
|
|
||||||
// Check if element is star
|
|
||||||
} else if (celestial.id === "soleil") {
|
|
||||||
celestial.type = "étoile";
|
|
||||||
|
|
||||||
// ...else, body is "other"
|
|
||||||
} else {
|
|
||||||
celestial.type = "autre";
|
|
||||||
}
|
|
||||||
return celestial;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const addCelestialsType = (celestials: any) => {
|
|
||||||
return celestials.map((e: any) => addCelestialType(e));
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
addCelestialType,
|
|
||||||
addCelestialsType
|
|
||||||
};
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
|
|
||||||
|
|
||||||
import Home from "../views/Home.vue";
|
|
||||||
import About from "../views/About.vue";
|
|
||||||
import Profile from "../views/Profile.vue";
|
|
||||||
|
|
||||||
import Celestials from "../views/celestials/Celestials.vue";
|
|
||||||
import Celestial from "../views/celestials/Celestial.vue";
|
|
||||||
|
|
||||||
const routes: Array<RouteRecordRaw> = [
|
|
||||||
{
|
|
||||||
path: "/",
|
|
||||||
name: "Home",
|
|
||||||
component: Home
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/a-propos",
|
|
||||||
name: "About",
|
|
||||||
component: About
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/astres",
|
|
||||||
name: "CelesteAll",
|
|
||||||
component: Celestials
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/astres/:slug",
|
|
||||||
name: "CelesteSingle",
|
|
||||||
component: Celestial,
|
|
||||||
props: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/profil",
|
|
||||||
name: "Profile",
|
|
||||||
component: Profile
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const router = createRouter({
|
|
||||||
history: createWebHistory(),
|
|
||||||
routes
|
|
||||||
});
|
|
||||||
|
|
||||||
export default router;
|
|
||||||
8
src/shims-vue.d.ts
vendored
@@ -1,8 +0,0 @@
|
|||||||
/* eslint-disable */
|
|
||||||
declare module '*.vue' {
|
|
||||||
import type { DefineComponent } from 'vue'
|
|
||||||
const component: DefineComponent<{}, {}, any>
|
|
||||||
export default component
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'uuid';
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
import { createStore } from "vuex";
|
|
||||||
|
|
||||||
import toastStore from "./toasts";
|
|
||||||
|
|
||||||
export default createStore({
|
|
||||||
state: () => ({
|
|
||||||
user: {
|
|
||||||
avatarUrl: "",
|
|
||||||
favourites: Array<{ id: string }>()
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
getters: {
|
|
||||||
// Returns the number of favs for the user
|
|
||||||
favCount: (state): number => {
|
|
||||||
return state.user.favourites.length;
|
|
||||||
},
|
|
||||||
// Returns true if celestial is fav
|
|
||||||
isFav: state => (celestialId: string) => {
|
|
||||||
return state.user.favourites.find(fav => fav.id === celestialId);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mutations: {
|
|
||||||
addFav: (state, celestialId: string) => {
|
|
||||||
state.user.favourites.push({ id: celestialId });
|
|
||||||
},
|
|
||||||
removeFav: (state, celestialId: string) => {
|
|
||||||
state.user.favourites = state.user.favourites.filter(
|
|
||||||
fav => fav.id != celestialId
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
toggleFav: ({ commit, getters }, celestialId: string) => {
|
|
||||||
// If the celestial is not faved
|
|
||||||
if (!getters.isFav(celestialId)) {
|
|
||||||
// ... favs it
|
|
||||||
commit("addFav", celestialId);
|
|
||||||
} else {
|
|
||||||
// ...else unfavs
|
|
||||||
commit("removeFav", celestialId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
modules: {
|
|
||||||
toasts: {
|
|
||||||
namespaced: true,
|
|
||||||
state: toastStore.state,
|
|
||||||
mutations: toastStore.mutations,
|
|
||||||
actions: toastStore.actions
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
export default {
|
|
||||||
state: {
|
|
||||||
queue: Array<{
|
|
||||||
id: string;
|
|
||||||
title: string;
|
|
||||||
message: string;
|
|
||||||
category: string;
|
|
||||||
timer: number;
|
|
||||||
}>()
|
|
||||||
},
|
|
||||||
mutations: {
|
|
||||||
pushToast: (state: any, toast: any) => {
|
|
||||||
state.queue.push(toast);
|
|
||||||
},
|
|
||||||
purgeToast: (state: any, toastId: string) => {
|
|
||||||
state.queue = state.queue.filter((toast: any) => toast.id != toastId);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
pushToast: ({ commit }: any, toast: any) => {
|
|
||||||
commit("pushToast", toast);
|
|
||||||
},
|
|
||||||
purgeToast: ({ commit }: any, toastId: string) => {
|
|
||||||
commit("purgeToast", toastId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<template>
|
|
||||||
<section class="about">
|
|
||||||
<h2>About</h2>
|
|
||||||
</section>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from "vue";
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "Home"
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@@ -1,149 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="home">
|
|
||||||
<header class="profile-header">
|
|
||||||
<h2>My Profile</h2>
|
|
||||||
<hr />
|
|
||||||
<h2>Profile for {{ user.name }}</h2>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div v-if="user.avatar">
|
|
||||||
<img :src="user.avatar" alt="" class="avatar" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="user.repos">
|
|
||||||
{{ user.name }} possède {{ user.repos.length }} repos.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="how-old">
|
|
||||||
<div v-if="user.age >= 20">
|
|
||||||
<p>Âge : {{ user.age }} (Extrêmement vieux)</p>
|
|
||||||
</div>
|
|
||||||
<div v-else-if="user.age >= 10 && user.age <= 20">
|
|
||||||
<p>Âge : {{ user.age }} (Enfant)</p>
|
|
||||||
</div>
|
|
||||||
<div v-else>
|
|
||||||
<p>Âge : {{ user.age }} (Doué pour utiliser un clavier)</p>
|
|
||||||
</div>
|
|
||||||
<div class="change-age">
|
|
||||||
<input type="number" v-model="user.age" min="1" max="999" />
|
|
||||||
<button>Devenir jeune</button>
|
|
||||||
<button>Devenir vieux</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="my-friends">
|
|
||||||
<div class="friend-list">
|
|
||||||
<h2>Friends of {{ user.name }}</h2>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th scope="col">Nom</th>
|
|
||||||
<th scope="col">UUID</th>
|
|
||||||
<th scope="col">Supprimer l'ami</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tbody>
|
|
||||||
<tr v-for="friend in user.friends" :key="friend.uuid">
|
|
||||||
<td>{{ friend.name }}</td>
|
|
||||||
<td>{{ friend.uuid }}</td>
|
|
||||||
<td>
|
|
||||||
<button @click="removeFriend(friend.uuid)">
|
|
||||||
Détruire l'ami là
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form class="friend-actions" @submit.prevent="addFriend(inputFriend)">
|
|
||||||
<input type="text" v-model="inputFriend.name" />
|
|
||||||
<button type="submit">Ajouter l'ami</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from "vue";
|
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "Profile",
|
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
user: {
|
|
||||||
name: "Alexis",
|
|
||||||
avatar: null,
|
|
||||||
age: 21,
|
|
||||||
repos: [],
|
|
||||||
friends: [
|
|
||||||
{
|
|
||||||
uuid: "91261477-04fb-4052-8ef9-6041ad7afb7e",
|
|
||||||
name: "Me"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
uuid: "c25880c8-4f04-432a-97bf-df639fff36e6",
|
|
||||||
name: "Myself"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
uuid: "1cb4cdaf-6a37-49d4-a069-b8a516203cbd",
|
|
||||||
name: "I"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
inputFriend: {
|
|
||||||
uuid: "bc59c1c9-b5a0-4047-a21e-afd1efcc4b64", // should be random but hey, this should be a token anyways so
|
|
||||||
name: ""
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
addFriend() {
|
|
||||||
if (this.inputFriend.name) {
|
|
||||||
this.user.friends.push({ ...this.inputFriend });
|
|
||||||
this.inputFriend.name = "";
|
|
||||||
} else {
|
|
||||||
// todo: error handling
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
removeFriend(uuid: string) {
|
|
||||||
this.user.friends = this.user.friends.filter(
|
|
||||||
friend => friend.uuid != uuid
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
|
||||||
axios
|
|
||||||
.get("https://api.github.com/users/alexisnp")
|
|
||||||
.then(res => {
|
|
||||||
this.user.avatar = res.data.avatar_url;
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.log(err);
|
|
||||||
});
|
|
||||||
axios
|
|
||||||
.get("https://api.github.com/users/alexisnp/repos")
|
|
||||||
.then(res => {
|
|
||||||
this.user.repos = res.data;
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.log(err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.avatar {
|
|
||||||
display: block;
|
|
||||||
border-radius: 50%;
|
|
||||||
max-width: 250px;
|
|
||||||
max-height: 250px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
<template>
|
|
||||||
<section class="celestial bg-image">
|
|
||||||
<div v-if="celestialLoaded">
|
|
||||||
<header>
|
|
||||||
<h1 class="heading-1">{{ celestial.name }}</h1>
|
|
||||||
</header>
|
|
||||||
<div class="section-content">
|
|
||||||
<div v-if="error">Une erreur est survenue : {{ error }}</div>
|
|
||||||
<div>{{ celestial }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div v-else>
|
|
||||||
<nest-loader />
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from "vue";
|
|
||||||
|
|
||||||
// API
|
|
||||||
import { fetchCelestial } from "@/api/le-systeme-solaire";
|
|
||||||
// import { fetchWikipediaExcerpt } from "@/api/wikipedia";
|
|
||||||
|
|
||||||
// Global methods
|
|
||||||
import { addCelestialType } from "@/plugins/methods";
|
|
||||||
import NestLoader from "@/components/NestLoader.vue";
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
components: {
|
|
||||||
NestLoader
|
|
||||||
},
|
|
||||||
name: "Celestial",
|
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
celestial: {},
|
|
||||||
celestialLoaded: false,
|
|
||||||
excerpt: "",
|
|
||||||
error: ""
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
props: {
|
|
||||||
slug: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
|
||||||
// Fetches from API...
|
|
||||||
fetchCelestial(this.slug)
|
|
||||||
.then(res => {
|
|
||||||
this.celestial = addCelestialType(res);
|
|
||||||
this.celestialLoaded = true;
|
|
||||||
return this.celestial;
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
this.error = "Impossible de récupérer l'astre demandé.";
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
// fetchWikipediaExcerpt(celestial);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.celestial {
|
|
||||||
position: relative;
|
|
||||||
min-height: 100%;
|
|
||||||
padding: 25px 5%;
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
background-image: url("/celestials_bg-min.jpg");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
<template>
|
|
||||||
<section class="celestials bg-image">
|
|
||||||
<header>
|
|
||||||
<h1 class="heading-1">Le système solaire</h1>
|
|
||||||
</header>
|
|
||||||
<div class="section-content">
|
|
||||||
<div v-if="error">Une erreur est survenue : {{ error }}</div>
|
|
||||||
<div v-if="celestials.length > 1">
|
|
||||||
<celestials-list :celestials="celestials" />
|
|
||||||
</div>
|
|
||||||
<div v-else>
|
|
||||||
<nest-loader />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent, onMounted, ref } from "vue";
|
|
||||||
|
|
||||||
// API
|
|
||||||
import { fetchCelestials } from "@/api/le-systeme-solaire";
|
|
||||||
|
|
||||||
// Global methods
|
|
||||||
import { addCelestialsType } from "@/plugins/methods";
|
|
||||||
|
|
||||||
import CelestialsList from "@/components/celestials/CelestialsList.vue";
|
|
||||||
import NestLoader from "@/components/NestLoader.vue";
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "Celestials",
|
|
||||||
components: {
|
|
||||||
CelestialsList,
|
|
||||||
NestLoader
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
error: ""
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
const celestials = ref(Array<any>());
|
|
||||||
|
|
||||||
const getCelestials = async () => {
|
|
||||||
celestials.value = await fetchCelestials();
|
|
||||||
celestials.value = addCelestialsType(celestials.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(getCelestials);
|
|
||||||
|
|
||||||
return { celestials };
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.celestials {
|
|
||||||
position: relative;
|
|
||||||
min-height: 100%;
|
|
||||||
padding: 25px 5%;
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
background-image: url("/celestials_bg-min.jpg");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
11
static/README.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# STATIC
|
||||||
|
|
||||||
|
**This directory is not required, you can delete it if you don't want to use it.**
|
||||||
|
|
||||||
|
This directory contains your static files.
|
||||||
|
Each file inside this directory is mapped to `/`.
|
||||||
|
Thus you'd want to delete this README.md before deploying to production.
|
||||||
|
|
||||||
|
Example: `/static/robots.txt` is mapped as `/robots.txt`.
|
||||||
|
|
||||||
|
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#static).
|
||||||
|
Before Width: | Height: | Size: 164 KiB After Width: | Height: | Size: 164 KiB |
|
Before Width: | Height: | Size: 455 KiB After Width: | Height: | Size: 455 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 322 KiB After Width: | Height: | Size: 322 KiB |
|
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 1.5 MiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 818 KiB After Width: | Height: | Size: 818 KiB |
46
store/index.js
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
export const state = () => ({
|
||||||
|
user: {
|
||||||
|
avatarUrl: '',
|
||||||
|
favourites: []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getters = {
|
||||||
|
// Returns the number of favs for the user
|
||||||
|
favCount: (state) => {
|
||||||
|
return state.user.favourites.length
|
||||||
|
},
|
||||||
|
// Returns true if celestial is fav
|
||||||
|
isFav: state => (celestialId) => {
|
||||||
|
return state.user.favourites.find(fav => fav.id === celestialId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const mutations = {
|
||||||
|
addFav: (state, celestial) => {
|
||||||
|
state.user.favourites.push(celestial)
|
||||||
|
},
|
||||||
|
removeFav: (state, celestial) => {
|
||||||
|
state.user.favourites = state.user.favourites.filter(
|
||||||
|
fav => fav.id !== celestial.id
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const actions = {
|
||||||
|
toggleFav: ({ commit, getters }, celestial) => {
|
||||||
|
// If the celestial is not faved
|
||||||
|
if (!getters.isFav(celestial.id)) {
|
||||||
|
commit('addFav', celestial)
|
||||||
|
} else {
|
||||||
|
commit('removeFav', celestial)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
state,
|
||||||
|
getters,
|
||||||
|
mutations,
|
||||||
|
actions
|
||||||
|
}
|
||||||
27
store/toasts.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
export const state = () => ({
|
||||||
|
queue: []
|
||||||
|
})
|
||||||
|
|
||||||
|
export const mutations = {
|
||||||
|
pushToast: (state, toast) => {
|
||||||
|
state.queue.push(toast)
|
||||||
|
},
|
||||||
|
purgeToast: (state, toastId) => {
|
||||||
|
state.queue = state.queue.filter(toast => toast.id !== toastId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const actions = {
|
||||||
|
pushToast: ({ commit }, toast) => {
|
||||||
|
commit('pushToast', toast)
|
||||||
|
},
|
||||||
|
purgeToast: ({ commit }, toastId) => {
|
||||||
|
commit('purgeToast', toastId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
state,
|
||||||
|
mutations,
|
||||||
|
actions
|
||||||
|
}
|
||||||
9
test/Logo.spec.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { mount } from '@vue/test-utils'
|
||||||
|
import Logo from '@/components/Logo.vue'
|
||||||
|
|
||||||
|
describe('Logo', () => {
|
||||||
|
test('is a Vue instance', () => {
|
||||||
|
const wrapper = mount(Logo)
|
||||||
|
expect(wrapper.vm).toBeTruthy()
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "esnext",
|
|
||||||
"module": "esnext",
|
|
||||||
"strict": true,
|
|
||||||
"jsx": "preserve",
|
|
||||||
"importHelpers": true,
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"allowSyntheticDefaultImports": true,
|
|
||||||
"sourceMap": true,
|
|
||||||
"baseUrl": ".",
|
|
||||||
"types": [
|
|
||||||
"webpack-env"
|
|
||||||
],
|
|
||||||
"paths": {
|
|
||||||
"@/*": [
|
|
||||||
"src/*"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"lib": [
|
|
||||||
"esnext",
|
|
||||||
"dom",
|
|
||||||
"dom.iterable",
|
|
||||||
"scripthost"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"src/**/*.ts",
|
|
||||||
"src/**/*.tsx",
|
|
||||||
"src/**/*.vue",
|
|
||||||
"tests/**/*.ts",
|
|
||||||
"tests/**/*.tsx"
|
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"node_modules"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
css: {
|
|
||||||
loaderOptions: {
|
|
||||||
scss: {
|
|
||||||
additionalData: `@import "src/assets/scss/_variables.scss";`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||