Merge branch 'develop' into main
This commit is contained in:
37
package-lock.json
generated
37
package-lock.json
generated
@@ -1377,6 +1377,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/uuid": {
|
||||||
|
"version": "8.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.0.tgz",
|
||||||
|
"integrity": "sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/webpack": {
|
"@types/webpack": {
|
||||||
"version": "4.41.26",
|
"version": "4.41.26",
|
||||||
"resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.26.tgz",
|
"resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.26.tgz",
|
||||||
@@ -9959,6 +9965,14 @@
|
|||||||
"tough-cookie": "~2.5.0",
|
"tough-cookie": "~2.5.0",
|
||||||
"tunnel-agent": "^0.6.0",
|
"tunnel-agent": "^0.6.0",
|
||||||
"uuid": "^3.3.2"
|
"uuid": "^3.3.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"uuid": {
|
||||||
|
"version": "3.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||||
|
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"require-directory": {
|
"require-directory": {
|
||||||
@@ -10604,6 +10618,14 @@
|
|||||||
"faye-websocket": "^0.11.3",
|
"faye-websocket": "^0.11.3",
|
||||||
"uuid": "^3.4.0",
|
"uuid": "^3.4.0",
|
||||||
"websocket-driver": "^0.7.4"
|
"websocket-driver": "^0.7.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"uuid": {
|
||||||
|
"version": "3.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||||
|
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sockjs-client": {
|
"sockjs-client": {
|
||||||
@@ -11838,10 +11860,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"uuid": {
|
"uuid": {
|
||||||
"version": "3.4.0",
|
"version": "8.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"v8-compile-cache": {
|
"v8-compile-cache": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
@@ -12666,6 +12687,14 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"ansi-colors": "^3.0.0",
|
"ansi-colors": "^3.0.0",
|
||||||
"uuid": "^3.3.2"
|
"uuid": "^3.3.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"uuid": {
|
||||||
|
"version": "3.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||||
|
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"webpack-merge": {
|
"webpack-merge": {
|
||||||
|
|||||||
@@ -10,11 +10,13 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
|
"uuid": "^8.3.2",
|
||||||
"vue": "^3.0.0",
|
"vue": "^3.0.0",
|
||||||
"vue-router": "^4.0.0-0",
|
"vue-router": "^4.0.0-0",
|
||||||
"vuex": "^4.0.0-0"
|
"vuex": "^4.0.0-0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/uuid": "^8.3.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^2.33.0",
|
"@typescript-eslint/eslint-plugin": "^2.33.0",
|
||||||
"@typescript-eslint/parser": "^2.33.0",
|
"@typescript-eslint/parser": "^2.33.0",
|
||||||
"@vue/cli-plugin-babel": "~4.5.0",
|
"@vue/cli-plugin-babel": "~4.5.0",
|
||||||
|
|||||||
@@ -4,16 +4,19 @@
|
|||||||
<div class="fs-content">
|
<div class="fs-content">
|
||||||
<router-view />
|
<router-view />
|
||||||
</div>
|
</div>
|
||||||
|
<toasts-list />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent } from "vue";
|
||||||
import Navbar from "@/components/Navbar.vue";
|
import Navbar from "@/components/Navbar.vue";
|
||||||
|
import ToastsList from "@/components/toast/ToastsList.vue";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
Navbar
|
Navbar,
|
||||||
|
ToastsList
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
30
src/api/le-systeme-solaire/index.ts
Normal file
30
src/api/le-systeme-solaire/index.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
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
|
||||||
|
};
|
||||||
36
src/api/wikipedia/index.ts
Normal file
36
src/api/wikipedia/index.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
@@ -1,3 +1,14 @@
|
|||||||
|
@keyframes toggleFavHeart {
|
||||||
|
0%, 20% {
|
||||||
|
color: #d01d35;
|
||||||
|
transform: scale(1.2);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
color: #d01d35;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes fadeInBg {
|
@keyframes fadeInBg {
|
||||||
from {
|
from {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
@@ -16,6 +27,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes fadeOut {
|
||||||
|
from {
|
||||||
|
opacity: 100%;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes fromBottom {
|
@keyframes fromBottom {
|
||||||
from {
|
from {
|
||||||
transform: translateY(20px);
|
transform: translateY(20px);
|
||||||
@@ -25,6 +45,24 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes slideFromRight {
|
||||||
|
from {
|
||||||
|
transform: translateX(100%);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideFromLeft {
|
||||||
|
from {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: translateX(100%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes paneBgAround {
|
@keyframes paneBgAround {
|
||||||
0% {
|
0% {
|
||||||
background-position: -10vw 0%;
|
background-position: -10vw 0%;
|
||||||
|
|||||||
@@ -1 +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');
|
@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');
|
||||||
@@ -66,6 +66,18 @@ a {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
&.no-style {
|
||||||
|
padding: 0;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hr {
|
hr {
|
||||||
border-color: rgba($white, .2);
|
border-color: rgba($white, .2);
|
||||||
}
|
}
|
||||||
@@ -140,13 +152,14 @@ hr {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-attachment: fixed;
|
background-attachment: fixed;
|
||||||
|
background-repeat: no-repeat;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
opacity: 33%;
|
opacity: 33%;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
&.bg-fade-in {
|
&.bg-fade-in {
|
||||||
&:after {
|
&:after {
|
||||||
width: 120vw;
|
background-size: 120vw;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
animation: fadeInBg 2s ease-out 0s 1 forwards,
|
animation: fadeInBg 2s ease-out 0s 1 forwards,
|
||||||
paneBgAround 35s ease-in-out 0s infinite forwards;
|
paneBgAround 35s ease-in-out 0s infinite forwards;
|
||||||
|
|||||||
@@ -8,6 +8,16 @@ $space-blue-600: #234e69;
|
|||||||
$space-blue-500: #457b9d;
|
$space-blue-500: #457b9d;
|
||||||
$space-blue-300: #a8dadc;
|
$space-blue-300: #a8dadc;
|
||||||
|
|
||||||
|
$blue: #306BAC;
|
||||||
|
$green: #1c8267;
|
||||||
|
$orange: #ff9844;
|
||||||
|
$red: #9f2042;
|
||||||
|
|
||||||
|
$info: $blue;
|
||||||
|
$valid: $green;
|
||||||
|
$warning: $orange;
|
||||||
|
$danger: $red;
|
||||||
|
|
||||||
$primary: $space-blue-700;
|
$primary: $space-blue-700;
|
||||||
$primary-light: $space-blue-600;
|
$primary-light: $space-blue-600;
|
||||||
|
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ export default defineComponent({
|
|||||||
link: "/"
|
link: "/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: "Célestes",
|
text: "Astres",
|
||||||
link: "/celestes"
|
link: "/astres"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: "À propos",
|
text: "À propos",
|
||||||
|
|||||||
@@ -42,6 +42,15 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</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 class="card-content">
|
||||||
<div v-if="celestial.aroundPlanet">
|
<div v-if="celestial.aroundPlanet">
|
||||||
<p>
|
<p>
|
||||||
@@ -75,12 +84,13 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<router-link
|
<button
|
||||||
:to="{ name: 'CelesteSingle', params: { slug: celestial.id } }"
|
@click="toggleFav(celestial)"
|
||||||
class="btn btn-primary"
|
class="favourite no-style"
|
||||||
|
:class="isFav ? 'active' : ''"
|
||||||
>
|
>
|
||||||
Détails
|
<span class="icon material-icons-round">favorite</span>
|
||||||
</router-link>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -88,6 +98,9 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent } from "vue";
|
||||||
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
|
||||||
|
import store from "@/store";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "celestial-card",
|
name: "celestial-card",
|
||||||
@@ -96,8 +109,38 @@ export default defineComponent({
|
|||||||
type: "unknown"
|
type: "unknown"
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
isFav() {
|
||||||
|
if (store.getters.isFav(this.celestial?.id)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
celestial: Object
|
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>
|
</script>
|
||||||
@@ -121,8 +164,18 @@ export default defineComponent({
|
|||||||
.card-icon {
|
.card-icon {
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 20px;
|
||||||
|
bottom: 20px;
|
||||||
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
user-select: none;
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 4%;
|
||||||
|
img {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> * {
|
> * {
|
||||||
@@ -135,6 +188,30 @@ export default defineComponent({
|
|||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
min-height: 30px;
|
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>
|
</style>
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
filters: {
|
filters: {
|
||||||
all: false,
|
all: true,
|
||||||
planets: false,
|
planets: false,
|
||||||
moons: false,
|
moons: false,
|
||||||
stars: false,
|
stars: false,
|
||||||
|
|||||||
98
src/components/toast/ToastCard.vue
Normal file
98
src/components/toast/ToastCard.vue
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
<template>
|
||||||
|
<div class="toast-card" :class="[toast.category, closing ? 'closing' : '']">
|
||||||
|
<div class="toast-title">
|
||||||
|
<slot name="title" />
|
||||||
|
</div>
|
||||||
|
<div class="toast-message">
|
||||||
|
<slot name="message" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { defineComponent } from "vue";
|
||||||
|
|
||||||
|
import store from "@/store";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: "ToastCard",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
closing: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
toast: Object
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// Counts down until 0 is reached
|
||||||
|
countdown(timeToLive) {
|
||||||
|
if (timeToLive > 0) {
|
||||||
|
console.log(timeToLive);
|
||||||
|
setTimeout(() => {
|
||||||
|
timeToLive = timeToLive - 1;
|
||||||
|
this.countdown(timeToLive);
|
||||||
|
}, 900);
|
||||||
|
} else {
|
||||||
|
// When timer ends
|
||||||
|
this.closing = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
this.close();
|
||||||
|
}, 1200);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
store.dispatch("toasts/purgeToast", this.toast.id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// Starts countdown to initial timer value
|
||||||
|
this.countdown(this.toast.timer);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.toast-card {
|
||||||
|
position: relative;
|
||||||
|
width: 300px;
|
||||||
|
padding: 20px 30px 26px;
|
||||||
|
border-radius: 5px;
|
||||||
|
animation: fadeIn 1s cubic-bezier(0.175, 1, 0.32, 1),
|
||||||
|
slideFromRight 1s cubic-bezier(0.175, 1, 0.32, 1);
|
||||||
|
overflow: hidden;
|
||||||
|
.toast-title {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: $fw-bold;
|
||||||
|
}
|
||||||
|
&:after {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
content: "";
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 6px;
|
||||||
|
background: rgba($fs-black, 33%);
|
||||||
|
}
|
||||||
|
&.info {
|
||||||
|
background-color: $info;
|
||||||
|
}
|
||||||
|
&.valid {
|
||||||
|
background-color: $valid;
|
||||||
|
}
|
||||||
|
&.warning {
|
||||||
|
color: $fs-black;
|
||||||
|
background-color: $warning;
|
||||||
|
}
|
||||||
|
&.danger {
|
||||||
|
background-color: $danger;
|
||||||
|
}
|
||||||
|
&.closing {
|
||||||
|
animation: fadeOut 1.2s cubic-bezier(0.175, 1, 0.32, 1),
|
||||||
|
slideFromLeft 1.2s cubic-bezier(0.175, 1, 0.32, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
45
src/components/toast/ToastsList.vue
Normal file
45
src/components/toast/ToastsList.vue
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<template>
|
||||||
|
<div class="toast-wrapper">
|
||||||
|
<div class="toast-item" v-for="toast in queue" :key="toast.id">
|
||||||
|
<toast-card :variant="toast.category" :toast="toast">
|
||||||
|
<template #title>{{ toast.title }}</template>
|
||||||
|
<template #message>
|
||||||
|
{{ toast.message }}
|
||||||
|
</template>
|
||||||
|
</toast-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { defineComponent } from "vue";
|
||||||
|
|
||||||
|
import ToastCard from "./ToastCard.vue";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: "ToastsList",
|
||||||
|
components: {
|
||||||
|
ToastCard
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
queue() {
|
||||||
|
return this.$store.state.toasts.queue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.toast-wrapper {
|
||||||
|
position: fixed;
|
||||||
|
top: 90px;
|
||||||
|
height: 100%;
|
||||||
|
right: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
.toast-item {
|
||||||
|
pointer-events: all;
|
||||||
|
margin-right: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -21,6 +21,11 @@ export const addCelestialType = (celestial: any) => {
|
|||||||
return celestial;
|
return celestial;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export const addCelestialsType = (celestials: any) => {
|
||||||
addCelestialType
|
return celestials.map((e: any) => addCelestialType(e));
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
addCelestialType,
|
||||||
|
addCelestialsType
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,12 +19,12 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
component: About
|
component: About
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/celestes",
|
path: "/astres",
|
||||||
name: "CelesteAll",
|
name: "CelesteAll",
|
||||||
component: Celestials
|
component: Celestials
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/celestes/:slug",
|
path: "/astres/:slug",
|
||||||
name: "CelesteSingle",
|
name: "CelesteSingle",
|
||||||
component: Celestial,
|
component: Celestial,
|
||||||
props: true
|
props: true
|
||||||
|
|||||||
2
src/shims-vue.d.ts
vendored
2
src/shims-vue.d.ts
vendored
@@ -4,3 +4,5 @@ declare module '*.vue' {
|
|||||||
const component: DefineComponent<{}, {}, any>
|
const component: DefineComponent<{}, {}, any>
|
||||||
export default component
|
export default component
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare module 'uuid';
|
||||||
@@ -1,8 +1,52 @@
|
|||||||
import { createStore } from "vuex";
|
import { createStore } from "vuex";
|
||||||
|
|
||||||
|
import toastStore from "./toasts";
|
||||||
|
|
||||||
export default createStore({
|
export default createStore({
|
||||||
state: {},
|
state: () => ({
|
||||||
mutations: {},
|
user: {
|
||||||
actions: {},
|
avatarUrl: "",
|
||||||
modules: {}
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
27
src/store/toasts/index.ts
Normal file
27
src/store/toasts/index.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -3,11 +3,11 @@
|
|||||||
<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">
|
||||||
L'application Full Skies explore les cieux à votre place !
|
Explorez les cieux et le système solaire avec Full Skies !
|
||||||
</p>
|
</p>
|
||||||
<p class="heading-2">
|
<p class="heading-2">
|
||||||
Embarquez pour un voyage stellaire ; destination : le système solaire et
|
Embarquez pour un voyage stellaire ; destination : le système solaire et
|
||||||
ses astres.
|
ses astres si proches.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="celestial bg-image">
|
<section class="celestial bg-image">
|
||||||
<div v-if="loaded">
|
<div v-if="celestialLoaded">
|
||||||
<header>
|
<header>
|
||||||
<h1 class="heading-1">{{ celestial.name }}</h1>
|
<h1 class="heading-1">{{ celestial.name }}</h1>
|
||||||
</header>
|
</header>
|
||||||
@@ -19,7 +19,9 @@
|
|||||||
import { defineComponent } from "vue";
|
import { defineComponent } from "vue";
|
||||||
|
|
||||||
// API
|
// API
|
||||||
import axios from "axios";
|
import { fetchCelestial } from "@/api/le-systeme-solaire";
|
||||||
|
// import { fetchWikipediaExcerpt } from "@/api/wikipedia";
|
||||||
|
|
||||||
// Global methods
|
// Global methods
|
||||||
import { addCelestialType } from "@/plugins/methods";
|
import { addCelestialType } from "@/plugins/methods";
|
||||||
import NestLoader from "@/components/NestLoader.vue";
|
import NestLoader from "@/components/NestLoader.vue";
|
||||||
@@ -32,8 +34,9 @@ export default defineComponent({
|
|||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
celestial: false,
|
celestial: {},
|
||||||
loaded: false,
|
celestialLoaded: false,
|
||||||
|
excerpt: "",
|
||||||
error: ""
|
error: ""
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -47,30 +50,18 @@ export default defineComponent({
|
|||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
// Fetches from API...
|
// Fetches from API...
|
||||||
this.fetchCelestial()
|
fetchCelestial(this.slug)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
// Adds type after fake loading (it's just to showcase the spinner tbh)
|
|
||||||
setTimeout(() => {
|
|
||||||
this.celestial = addCelestialType(res);
|
this.celestial = addCelestialType(res);
|
||||||
this.loaded = true;
|
this.celestialLoaded = true;
|
||||||
}, 1000);
|
return this.celestial;
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
this.error = "Impossible de récupérer l'astre demandé.";
|
this.error = "Impossible de récupérer l'astre demandé.";
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
// fetchWikipediaExcerpt(celestial);
|
||||||
});
|
});
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
/**
|
|
||||||
* Fetches celestial body from API
|
|
||||||
*/
|
|
||||||
fetchCelestial(): Promise<any> {
|
|
||||||
return axios
|
|
||||||
.get(`https://api.le-systeme-solaire.net/rest/bodies/${this.slug}`)
|
|
||||||
.then(res => {
|
|
||||||
return res.data;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -16,12 +16,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent, onMounted, ref } from "vue";
|
||||||
|
|
||||||
// API
|
// API
|
||||||
import axios from "axios";
|
import { fetchCelestials } from "@/api/le-systeme-solaire";
|
||||||
|
|
||||||
// Global methods
|
// Global methods
|
||||||
import { addCelestialType } from "@/plugins/methods";
|
import { addCelestialsType } from "@/plugins/methods";
|
||||||
|
|
||||||
import CelestialsList from "@/components/celestials/CelestialsList.vue";
|
import CelestialsList from "@/components/celestials/CelestialsList.vue";
|
||||||
import NestLoader from "@/components/NestLoader.vue";
|
import NestLoader from "@/components/NestLoader.vue";
|
||||||
@@ -34,38 +35,21 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
celestials: Array<any>(),
|
|
||||||
error: ""
|
error: ""
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
setup() {
|
||||||
this.fetchCelestials()
|
const celestials = ref(Array<any>());
|
||||||
.then(res => {
|
|
||||||
this.celestials = this.addType(res);
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
this.error = "Impossible de récupérer les astres.";
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
const getCelestials = async () => {
|
||||||
/**
|
celestials.value = await fetchCelestials();
|
||||||
* Fetches celestial bodies from API
|
celestials.value = addCelestialsType(celestials.value);
|
||||||
*/
|
};
|
||||||
fetchCelestials(): Promise<any> {
|
|
||||||
return axios
|
onMounted(getCelestials);
|
||||||
.get("https://api.le-systeme-solaire.net/rest/bodies/")
|
|
||||||
.then(res => {
|
return { celestials };
|
||||||
return res.data.bodies;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Assign a type from the celestial object provided
|
|
||||||
*/
|
|
||||||
addType(bodies: Array<any>): Array<any> {
|
|
||||||
return bodies.map((e: any) => addCelestialType(e));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user