diff --git a/README.md b/README.md index fdc754d..1da497b 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Le code source est publié sous licence libre [GNU GPL-3.0-or-later](LICENSE) et Vous pouvez librement utiliser le service en vous inscrivant sur [https://www.musictopus.fr/](https://www.musictopus.fr/). -Une fois inscrit vous pourrez saisir vos CDs et Vinyles sur votre espace personnel le tout gratuitement, sans tracker et sans utilisation de vos données personnelles ! +Une fois inscrit vous pourrez saisir vos CDs et Vinyles sur votre espace personnel le tout gratuitement, sans tracker (en dehors de statistiques web via [Matomo](https://fr.matomo.org/)) et sans utilisation de vos données personnelles ! ## Auto hébergement @@ -195,9 +195,13 @@ MONGODB_URI # Url du serveur mongo (par défaut mongodb://musictopus-db/musictop SECRET # Hash utilisé pour pour sauvegardé les dessions (par défaut waemaeMe5ahc6ce1chaeKohKa6Io8Eik) DISCOGS_TOKEN # Token Discogs (vous devez créer un compte sur discogs afin d'en obtenir un gratuitement) FORMSPREE_ID # Id du formulaire formspree pour la page "nous-contacter" +MATOMO_URL # Url vers l'instance matomo (exemple: https://analytics.darkou.fr/) +MATOMO_ID # Id du site sur votre instance matomo (exemple: 1) +SITE_NAME # Nom du site (utilisé dans le titre des pages) ``` ## Contributeurs - Damien Broqua (développeur principal du projet) -- Brunus (Logo et fournisseur d'idées :wink: ) \ No newline at end of file +- Brunus (Logo et fournisseur d'idées :wink: ) + diff --git a/docker-compose.yml.dev b/docker-compose.yml.dev index b14864f..9391624 100644 --- a/docker-compose.yml.dev +++ b/docker-compose.yml.dev @@ -25,6 +25,9 @@ services: SECRET: ${SECRET} DISCOGS_TOKEN: ${DISCOGS_TOKEN} FORMSPREE_ID: ${FORMSPREE_ID} + MATOMO_URL: ${MATOMO_URL} + MATOMO_ID: ${MATOMO_ID} + SITE_NAME: ${SITE_NAME} networks: - musictopus musictopus-db: diff --git a/docker-compose.yml.prod b/docker-compose.yml.prod index d314748..9077877 100644 --- a/docker-compose.yml.prod +++ b/docker-compose.yml.prod @@ -25,6 +25,9 @@ services: SECRET: ${SECRET} DISCOGS_TOKEN: ${DISCOGS_TOKEN} FORMSPREE_ID: ${FORMSPREE_ID} + MATOMO_URL: ${MATOMO_URL} + MATOMO_ID: ${MATOMO_ID} + SITE_NAME: ${SITE_NAME} networks: - musictopus musictopus-db: diff --git a/package.json b/package.json index 8c53d5a..b5aea27 100644 --- a/package.json +++ b/package.json @@ -27,9 +27,6 @@ }, "license": "GPL-3.0-or-later", "devDependencies": { - "@babel/cli": "^7.17.0", - "@babel/core": "^7.17.2", - "@babel/preset-env": "^7.16.11", "eslint": "^8.9.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-config-prettier": "^8.3.0", @@ -38,11 +35,12 @@ "husky": "^7.0.4", "lint-staged": "^12.3.3", "nodemon": "^2.0.15", - "npm-run-all": "^4.1.5", - "prettier": "^2.5.1", - "rimraf": "^3.0.2" + "prettier": "^2.5.1" }, "dependencies": { + "@babel/cli": "^7.17.0", + "@babel/core": "^7.17.2", + "@babel/preset-env": "^7.16.11", "axios": "^0.26.0", "connect-ensure-login": "^0.1.1", "connect-flash": "^0.1.1", @@ -54,14 +52,17 @@ "excel4node": "^1.7.2", "express": "^4.17.2", "express-session": "^1.17.2", + "joi": "^17.6.0", "knacss": "^8.0.4", "moment": "^2.29.1", "moment-timezone": "^0.5.34", "mongoose": "^6.2.1", "mongoose-unique-validator": "^3.0.0", + "npm-run-all": "^4.1.5", "passport": "^0.5.2", "passport-http": "^0.3.0", "passport-local": "^1.0.0", + "rimraf": "^3.0.2", "sass": "^1.49.7", "vue": "^3.2.31" }, diff --git a/public/500.html b/public/500.html index 072dfd0..76eb123 100644 --- a/public/500.html +++ b/public/500.html @@ -4,7 +4,7 @@ - Site en maintenance + MusicTopus - Erreur applicative @@ -17,37 +17,10 @@ - - - -
-
-

Site inaccessible

- -

- Pas de panique on revient très vite ! -

-
- - + + Image représentant la mascotte tenant un vinyle cassé + Nous sommes désolé mais quelque chose a mal tourné de notre côté. +
+ On devrait revenir très vite ! 😅 diff --git a/public/font/icon.eot b/public/font/icon.eot index 5a5d395..a17c0f6 100644 Binary files a/public/font/icon.eot and b/public/font/icon.eot differ diff --git a/public/font/icon.svg b/public/font/icon.svg index 51f7015..d5ac2f6 100644 --- a/public/font/icon.svg +++ b/public/font/icon.svg @@ -34,6 +34,8 @@ + + diff --git a/public/font/icon.ttf b/public/font/icon.ttf index 488fa0b..4ccfa6d 100644 Binary files a/public/font/icon.ttf and b/public/font/icon.ttf differ diff --git a/public/font/icon.woff b/public/font/icon.woff index 7c3262d..3262198 100644 Binary files a/public/font/icon.woff and b/public/font/icon.woff differ diff --git a/public/font/icon.woff2 b/public/font/icon.woff2 index ac6af3a..f73baf4 100644 Binary files a/public/font/icon.woff2 and b/public/font/icon.woff2 differ diff --git a/public/img/404.svg b/public/img/404.svg index c963bb6..b4dbe78 100644 --- a/public/img/404.svg +++ b/public/img/404.svg @@ -1 +1,343 @@ - \ No newline at end of file + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/logo.svg b/public/img/logo.svg deleted file mode 100644 index 7ceed9f..0000000 --- a/public/img/logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/js/main.js b/public/js/main.js index 994b2ae..895683a 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -2,13 +2,16 @@ * Fonction permettant d'afficher un message dans un toastr * @param {String} message */ - function showToastr(message) { + function showToastr(message, success = false) { let x = document.getElementById("toastr"); if ( message ) { x.getElementsByTagName("SPAN")[0].innerHTML = message; } - x.className = `${x.className} show`; + x.className = `${x.className} show`.replace("sucess", ""); + if ( success ) { + x.className = `${x.className} success`; + } setTimeout(function(){ x.className = x.className.replace("show", ""); }, 3000); }; diff --git a/public/mstile-310x150.png b/public/mstile-310x150.png deleted file mode 100644 index ed34b0c..0000000 Binary files a/public/mstile-310x150.png and /dev/null differ diff --git a/sass/500.scss b/sass/500.scss new file mode 100644 index 0000000..910f8dd --- /dev/null +++ b/sass/500.scss @@ -0,0 +1,22 @@ +.body-500 { + padding: 0; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + + font-weight: 400; + font-size: larger; + line-height: 200%; + + text-align: center; + + img { + max-width: 60%; + margin-bottom: 32px; + + @include respond-to("small-up") { + max-width: 30%; + } + } +} \ No newline at end of file diff --git a/sass/button.scss b/sass/button.scss index 1d8c946..1fd0e5d 100644 --- a/sass/button.scss +++ b/sass/button.scss @@ -54,7 +54,7 @@ &.is-link { background-color: transparent; border-color: $nord9; - color: $nord9; + color: var(--button-link-text-color); &:hover { border-color: darken($nord9, $hoverAmount); diff --git a/sass/ma-collection.scss b/sass/collection.scss similarity index 90% rename from sass/ma-collection.scss rename to sass/collection.scss index af22f2a..6412fe1 100644 --- a/sass/ma-collection.scss +++ b/sass/collection.scss @@ -1,4 +1,9 @@ -.ma-collection { +.collection { + h1 { + i { + cursor: pointer; + } + } .filters { display: flex; justify-content: end; diff --git a/sass/colors.scss b/sass/colors.scss index 5759f90..441062c 100644 --- a/sass/colors.scss +++ b/sass/colors.scss @@ -29,7 +29,7 @@ $danger-color-hl: darken($danger-color, $hoverAmount); $warning-color-hl: darken($warning-color, $hoverAmount); $success-color-hl: darken($success-color, $hoverAmount); -$button-font-color: $nord1; +$button-font-color: #2C364A; $button-alternate-color: #01103C; $pagination-border-color: $nord3; @@ -38,6 +38,7 @@ $pagination-hover-color: rgb(115, 151, 186); :root { --default-color: #{$white}; --bg-color: #{darken($white, 5%)}; + --bg-alternate-color: #{darken($white, 8%)}; --font-color: #{$nord3}; --footer-color: #{$darken-white}; --link-color: #{$nord1}; @@ -45,18 +46,38 @@ $pagination-hover-color: rgb(115, 151, 186); --input-font-color: #{$nord3}; --input-color: #{$white}; --input-active-color: #{$nord5}; - + --navbar-color: #{darken($white, 5%)}; --box-bg-color: #F8F9FB; --box-shadow-color: #{rgba($nord4, 0.35)}; --border-color: #{$nord4}; + + --button-link-text-color: #2C364A; + + --nord0: #{$nord0}; + --nord1: #{$nord1}; + --nord2: #{$nord2}; + --nord3: #{$nord3}; + --nord4: #{$nord4}; + --nord5: #{$nord5}; + --nord6: #{$nord6}; + --nord7: #{$nord7}; + --nord8: #{$nord8}; + --nord9: #{$nord9}; + --nord10: #{$nord10}; + --nord11: #{$nord11}; + --nord12: #{$nord12}; + --nord13: #{$nord13}; + --nord14: #{$nord14}; + --nord15: #{$nord15}; } [data-theme="dark"] { --default-color: #{$nord3}; --bg-color: #{lighten($nord0, 2%)}; + --bg-alternate-color: #{lighten($nord3, 8%)}; --font-color: #{$nord6}; --footer-color: #{$nord1}; --link-color: #{$nord4}; @@ -71,4 +92,6 @@ $pagination-hover-color: rgb(115, 151, 186); --box-shadow-color: #{rgba($nord4, 0.2)}; --border-color: #{$nord1}; + + --button-link-text-color: #{$white}; } \ No newline at end of file diff --git a/sass/composants.scss b/sass/composants.scss new file mode 100644 index 0000000..b9d4e65 --- /dev/null +++ b/sass/composants.scss @@ -0,0 +1,13 @@ +.composants { + .couleur { + margin-bottom: 1rem; + text-align: center; + + border: 1px solid var(--input-active-color); + box-shadow: var(--box-shadow-color) 0px 3px 6px 0px; + + div { + height: 56px; + } + } +} \ No newline at end of file diff --git a/sass/global.scss b/sass/global.scss index 491b9ca..454cd14 100644 --- a/sass/global.scss +++ b/sass/global.scss @@ -82,4 +82,8 @@ html { @include respond-to("small-up") { display: initial; } +} + +.is-danger { + color: $nord12; } \ No newline at end of file diff --git a/sass/icons.scss b/sass/icons.scss index ca297ea..4250307 100644 --- a/sass/icons.scss +++ b/sass/icons.scss @@ -46,6 +46,7 @@ .icon-link-ext:before { content: '\f08e'; } /* '' */ .icon-sun:before { content: '\f185'; } /* '' */ .icon-moon:before { content: '\f186'; } /* '' */ +.icon-share:before { content: '\f1e0'; } /* '' */ .icon-trash:before { content: '\f1f8'; } /* '' */ .icon-blind:before { content: '\f29d'; } /* '' */ @@ -61,4 +62,4 @@ 100% { transform: rotate(359deg); } -} \ No newline at end of file +} diff --git a/sass/index.scss b/sass/index.scss index aa7557a..3a53fd2 100644 --- a/sass/index.scss +++ b/sass/index.scss @@ -41,7 +41,9 @@ @import './box'; @import './error'; +@import './500'; @import './home'; @import './ajouter-un-album'; -@import './ma-collection'; -@import './ma-collection-details'; \ No newline at end of file +@import './collection'; +@import './ma-collection-details'; +@import './composants'; \ No newline at end of file diff --git a/sass/list.scss b/sass/list.scss index 7c479ff..9dbd03a 100644 --- a/sass/list.scss +++ b/sass/list.scss @@ -3,30 +3,35 @@ .item{ padding: 0.5rem 0.75rem; - border-bottom: 1px solid var(--border-color); + border-bottom: 2px solid var(--border-color); + background-color: var(--bg-alternate-color); @include transition() {} @include respond-to("medium") { &:nth-child(2n) { background-color: var(--default-color); } + border: none; } + @include respond-to("medium-up") { - border-left: 1px solid var(--border-color); + border-left: 2px solid var(--border-color); + + &:nth-child(4n), + &:nth-child(4n-1) + { + background-color: var(--default-color); + } &:first-child, &:nth-child(2) { - border-top: 1px solid var(--border-color); + border-top: 2px solid var(--border-color); } &:nth-child(2n), &:last-child { - border-right: 1px solid var(--border-color); - margin-right: -1px; - } - - &:hover { - background-color: var(--default-color); + border-right: 2px solid var(--border-color); + margin-right: -2px; } } @@ -44,4 +49,10 @@ max-width: 90%; } } + + &.hover { + .item:hover { + background-color: var(--border-color); + } + } } \ No newline at end of file diff --git a/sass/ma-collection-details.scss b/sass/ma-collection-details.scss index 6d4ba32..952a026 100644 --- a/sass/ma-collection-details.scss +++ b/sass/ma-collection-details.scss @@ -16,6 +16,7 @@ img { max-width: 90%; + max-height: 90%; } } } diff --git a/sass/toast.scss b/sass/toast.scss index 21d1730..46777e7 100644 --- a/sass/toast.scss +++ b/sass/toast.scss @@ -13,6 +13,11 @@ color: $button-alternate-color; border-radius: 6px; + &.success { + background-color: $success-color; + color: $button-font-color; + } + &.show { visibility: visible; animation: toastrFadein 0.5s, toastrFadeout 0.5s 2.5s; diff --git a/src/app.js b/src/app.js index 0b32d82..6d1e507 100644 --- a/src/app.js +++ b/src/app.js @@ -13,9 +13,11 @@ import { isXhr } from "./helpers"; import indexRouter from "./routes"; import maCollectionRouter from "./routes/ma-collection"; +import collectionRouter from "./routes/collection"; import importAlbumRouterApiV1 from "./routes/api/v1/albums"; import importSearchRouterApiV1 from "./routes/api/v1/search"; +import importMeRouterApiV1 from "./routes/api/v1/me"; // Mongoose schema init require("./models/users"); @@ -82,8 +84,10 @@ app.use( app.use("/", indexRouter); app.use("/ma-collection", maCollectionRouter); +app.use("/collection", collectionRouter); app.use("/api/v1/albums", importAlbumRouterApiV1); app.use("/api/v1/search", importSearchRouterApiV1); +app.use("/api/v1/me", importMeRouterApiV1); // Handle 404 app.use((req, res) => { @@ -113,7 +117,10 @@ app.use((error, req, res, next) => { } else { res.status(error.errorCode || 500); res.render("index", { - page: { title: "500: Oups… le serveur a crashé !", error }, + page: { + title: error.title || "500: Oups… le serveur a crashé !", + error, + }, errorCode: error.errorCode || 500, viewname: "error", user: req.user || null, diff --git a/src/config/index.js b/src/config/index.js index 43158f5..19f16ea 100644 --- a/src/config/index.js +++ b/src/config/index.js @@ -5,4 +5,7 @@ module.exports = { secret: process.env.SECRET || "waemaeMe5ahc6ce1chaeKohKa6Io8Eik", discogsToken: process.env.DISCOGS_TOKEN, formspreeId: process.env.FORMSPREE_ID, + matomoUrl: process.env.MATOMO_URL || "", + matomoId: process.env.MATOMO_ID || "", + siteName: process.env.SITE_NAME || "MusicTopus", }; diff --git a/src/libs/error.js b/src/libs/error.js index 562265f..13470f2 100644 --- a/src/libs/error.js +++ b/src/libs/error.js @@ -4,9 +4,10 @@ class ErrorEvent extends Error { /** * @param {Number} errorCode + * @param {String} title * @param {Mixed} ...params */ - constructor(errorCode, ...params) { + constructor(errorCode, title, ...params) { super(...params); if (Error.captureStackTrace) { @@ -14,6 +15,7 @@ class ErrorEvent extends Error { } this.errorCode = parseInt(errorCode, 10); + this.title = title; this.date = new Date(); } } diff --git a/src/middleware/Albums.js b/src/middleware/Albums.js index 4796207..6caa29b 100644 --- a/src/middleware/Albums.js +++ b/src/middleware/Albums.js @@ -5,12 +5,19 @@ import xl from "excel4node"; import Pages from "./Pages"; import AlbumsModel from "../models/albums"; +import UsersModel from "../models/users"; import ErrorEvent from "../libs/error"; /** * Classe permettant la gestion des albums d'un utilisateur */ class Albums extends Pages { + /** + * Méthode permettant de remplacer certains cartactères par leur équivalents html + * @param {String} str + * + * @return {String} + */ static replaceSpecialChars(str) { if (!str) { return ""; @@ -487,7 +494,7 @@ class Albums extends Pages { static async getAllDistincts(field, user) { const distincts = await AlbumsModel.find( { - user, + User: user, }, [], { @@ -513,8 +520,11 @@ class Albums extends Pages { order = "asc", artists_sort, format, + userId: collectionUserId, } = this.req.query; + let userId = this.req.user?._id; + const where = {}; if (artists_sort) { @@ -524,8 +534,35 @@ class Albums extends Pages { where["formats.name"] = format; } + if (!this.req.user && !collectionUserId) { + throw new ErrorEvent( + 401, + "Cette collection n'est pas publique", + "Cette collection n'est pas publique" + ); + } + + if (collectionUserId) { + const userIsSharingCollection = await UsersModel.findById( + collectionUserId + ); + + if ( + !userIsSharingCollection || + !userIsSharingCollection.isPublicCollection + ) { + throw new ErrorEvent( + 401, + "Cette collection n'est pas publique", + "Cette collection n'est pas publique" + ); + } + + userId = userIsSharingCollection._id; + } + const count = await AlbumsModel.count({ - user: this.req.user._id, + User: userId, ...where, }); @@ -547,7 +584,7 @@ class Albums extends Pages { const rows = await AlbumsModel.find( { - user: this.req.user._id, + User: userId, ...where, }, [], @@ -604,6 +641,7 @@ class Albums extends Pages { this.setPageContent("artists", artists); this.setPageContent("formats", formats); + this.setPageTitle("Ma collection"); } /** @@ -618,6 +656,33 @@ class Albums extends Pages { }); this.setPageContent("item", item); + this.setPageTitle( + `Détails de l'album ${item.title} de ${item.artists_sort}` + ); + } + + /** + * Méthode permettant de créer la page "collection/:userId" + */ + async loadPublicCollection() { + const { userId } = this.req.params; + + const user = await UsersModel.findById(userId); + + if (!user || !user.isPublicCollection) { + throw new ErrorEvent( + 401, + "Cet utilisateur ne souhaite pas partager sa collection" + ); + } + + const artists = await Albums.getAllDistincts("artists_sort", userId); + const formats = await Albums.getAllDistincts("formats.name", userId); + + this.setPageContent("username", user.username); + this.setPageTitle(`Collection publique de ${user.username}`); + this.setPageContent("artists", artists); + this.setPageContent("formats", formats); } } diff --git a/src/middleware/Me.js b/src/middleware/Me.js new file mode 100644 index 0000000..ae2712c --- /dev/null +++ b/src/middleware/Me.js @@ -0,0 +1,45 @@ +import Joi from "joi"; + +import UsersModel from "../models/users"; + +/** + * Classe permettant la gestion de l'utilisateur connecté + */ +class Me { + constructor(req) { + this.req = req; + } + + /** + * Méthode permettant de modifier le profil d'un utilisateur + * @return {Object} + */ + async patchMe() { + const { body, user } = this.req; + + const schema = Joi.object({ + isPublicCollection: Joi.boolean(), + }); + + const value = await schema.validateAsync(body); + const update = await UsersModel.findByIdAndUpdate( + user._id, + { $set: value }, + { new: true } + ); + + await new Promise((resolve, reject) => { + this.req.login(update, (err) => { + if (err) { + return reject(err); + } + + return resolve(null); + }); + }); + + return update; + } +} + +export default Me; diff --git a/src/middleware/Pages.js b/src/middleware/Pages.js index e5a59af..eb3ea75 100644 --- a/src/middleware/Pages.js +++ b/src/middleware/Pages.js @@ -34,6 +34,10 @@ class Pages { } } + setPageTitle(title) { + this.pageContent.page.title = title; + } + setPageContent(field, value) { this.pageContent.page[field] = value; } diff --git a/src/models/users.js b/src/models/users.js index 0807ccb..96629c0 100644 --- a/src/models/users.js +++ b/src/models/users.js @@ -1,5 +1,7 @@ /* eslint-disable func-names */ /* eslint-disable no-invalid-this */ +/* eslint-disable no-param-reassign */ + import mongoose from "mongoose"; import uniqueValidator from "mongoose-unique-validator"; import crypto from "crypto"; @@ -23,8 +25,20 @@ const UserSchema = new mongoose.Schema( }, hash: String, salt: String, + isPublicCollection: { + type: Boolean, + default: false, + }, }, - { timestamps: true } + { + timestamps: true, + toJSON: { + transform(doc, ret) { + delete ret.hash; + delete ret.salt; + }, + }, + } ); UserSchema.plugin(uniqueValidator, { message: "est déjà utilisé" }); diff --git a/src/routes/api/v1/albums.js b/src/routes/api/v1/albums.js index 164ea40..e1caa1f 100644 --- a/src/routes/api/v1/albums.js +++ b/src/routes/api/v1/albums.js @@ -9,7 +9,7 @@ const router = express.Router(); router .route("/") - .get(ensureLoggedIn("/connexion"), async (req, res, next) => { + .get(async (req, res, next) => { try { const albums = new Albums(req); const data = await albums.getAll(); @@ -19,9 +19,11 @@ router case "csv": case "musictopus": res.header("Content-Type", "text/csv"); + res.attachment("export-musictopus.csv"); return res.status(200).send(data); case "xml": res.header("Content-type", "text/xml"); + res.attachment("export-musictopus.xml"); return res.status(200).send(data); case "xls": return data.write("musictopus.xls", res); diff --git a/src/routes/api/v1/me.js b/src/routes/api/v1/me.js new file mode 100644 index 0000000..42c46b9 --- /dev/null +++ b/src/routes/api/v1/me.js @@ -0,0 +1,24 @@ +import express from "express"; +import { ensureLoggedIn } from "connect-ensure-login"; + +import { sendResponse } from "../../../libs/format"; + +import Me from "../../../middleware/Me"; + +// eslint-disable-next-line new-cap +const router = express.Router(); + +router + .route("/") + .patch(ensureLoggedIn("/connexion"), async (req, res, next) => { + try { + const me = new Me(req); + const data = await me.patchMe(); + + return sendResponse(req, res, data); + } catch (err) { + return next(err); + } + }); + +export default router; diff --git a/src/routes/collection.js b/src/routes/collection.js new file mode 100644 index 0000000..6584992 --- /dev/null +++ b/src/routes/collection.js @@ -0,0 +1,22 @@ +import express from "express"; + +import Albums from "../middleware/Albums"; + +import render from "../libs/format"; + +// eslint-disable-next-line new-cap +const router = express.Router(); + +router.route("/:userId").get(async (req, res, next) => { + try { + const page = new Albums(req, "collection"); + + await page.loadPublicCollection(); + + render(res, page); + } catch (err) { + next(err); + } +}); + +export default router; diff --git a/src/routes/index.js b/src/routes/index.js index 95c9a45..ac43a51 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -14,6 +14,8 @@ router.route("/").get((req, res, next) => { try { const page = new Pages(req, "home"); + page.setPageTitle("Présentation du projet"); + render(res, page); } catch (err) { next(err); @@ -26,6 +28,8 @@ router try { const page = new Pages(req, "connexion"); + page.setPageTitle("Connexion"); + render(res, page); } catch (err) { next(err); @@ -61,6 +65,8 @@ router try { const page = new Pages(req, "inscription"); + page.setPageTitle("Inscription"); + render(res, page); } catch (err) { next(err); @@ -82,6 +88,8 @@ router try { const page = new Pages(req, "ajouter-un-album"); + page.setPageTitle("Ajouter un album"); + render(res, page); } catch (err) { next(err); @@ -92,6 +100,8 @@ router.route("/nous-contacter").get(async (req, res, next) => { try { const page = new Pages(req, "nous-contacter"); + page.setPageTitle("Nous contacter"); + render(res, page); } catch (err) { next(err); @@ -102,6 +112,8 @@ router.route("/composants").get(async (req, res, next) => { try { const page = new Pages(req, "composants"); + page.setPageTitle("Les composants"); + render(res, page); } catch (err) { next(err); diff --git a/src/routes/ma-collection.js b/src/routes/ma-collection.js index 51ff0ee..9c217bf 100644 --- a/src/routes/ma-collection.js +++ b/src/routes/ma-collection.js @@ -10,7 +10,7 @@ const router = express.Router(); router.route("/").get(ensureLoggedIn("/connexion"), async (req, res, next) => { try { - const page = new Albums(req, "mon-compte/ma-collection"); + const page = new Albums(req, "mon-compte/ma-collection/index"); await page.loadMyCollection(); @@ -30,6 +30,8 @@ router try { const page = new Albums(req, "mon-compte/ma-collection/exporter"); + page.setPageTitle("Exporter ma collection"); + render(res, page); } catch (err) { next(err); diff --git a/views/error.ejs b/views/error.ejs index b0e5112..8f80430 100644 --- a/views/error.ejs +++ b/views/error.ejs @@ -5,7 +5,9 @@ Erreur 404

<% } %> + <% if ( process.env.NODE_ENV !== 'production' ) { %>
<%= page.error %>
+ <% } %> \ No newline at end of file diff --git a/views/index.ejs b/views/index.ejs index ddf0b8c..a2a98b5 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -4,7 +4,7 @@ - <% if (page.title) { %><%= page.title %> <% } else { %> DarKou - MusicTopus <% } %> + <%= config.siteName %> :: <%= page.title %> @@ -19,6 +19,24 @@ + + <% if ( config.matomoUrl ) { %> + + + + <% } %> - - diff --git a/views/pages/composants.ejs b/views/pages/composants.ejs index 7c17b38..79b8ee6 100644 --- a/views/pages/composants.ejs +++ b/views/pages/composants.ejs @@ -1,8 +1,9 @@ -
+

Les composants

  • Les titres
  • +
  • Les couleurs
  • Les grilles
  • Les boutons
  • Les formulaires
  • @@ -24,11 +25,92 @@
    Titre de niveau 5
    Titre de niveau 6
    +

    Les couleurs

    +

    Polar Night

    +
    +
    +
     
    + nord0 +
    +
    +
     
    + nord1 +
    +
    +
     
    + nord2 +
    +
    +
     
    + nord3 +
    +
    +

    Snow Storm

    +
    +
    +
     
    + nord4 +
    +
    +
     
    + nord5 +
    +
    +
     
    + nord6 +
    +
    +

    Frost

    +
    +
    +
     
    + nord7 +
    +
    +
     
    + nord8 +
    +
    +
     
    + nord9 +
    +
    +
     
    + nord10 +
    +
    +

    Aurora

    +
    +
    +
     
    + nord11 +
    +
    +
     
    + nord12 +
    +
    +
     
    + nord13 +
    +
    +
     
    + nord14 +
    +
    +
     
    + nord15 +
    +
    +

    + Vous pourrez trouver plus d'informations sur le site offciel du projet nord. +

    +

    Les grilles

    Se référer à la documentation de Knacss.

    - +

    Les boutons

    .button
    @@ -39,13 +121,13 @@

    Les formulaires

    - - + +
     <div class="field">
    -    <label for="email">Adresse e-mail</label>
    -    <input type="email" name="email" id="email" placeholder="ex : damien@darkou.fr">
    +    <label for="demo-email">Adresse e-mail</label>
    +    <input type="email" name="email" id="demo-email" placeholder="ex : damien@darkou.fr">
     </div>
         
    @@ -86,30 +168,38 @@ </select> </div> -
    +
    +
    +
    - + +
    +
    +
    +
    -<div class="field">
    +<div class="field inline">
         <label for="choix1">choix 1</label>
    -    <input type="radio" id="choix1" name="choix" value="choix1" checked> 
    +    <input type="radio" id="choix1" name="choix" value="choix1" checked>
    +</div>
    +<div class="field inline">
         <label for="choix2">choix 2</label>
         <input type="radio" id="choix2" name="choix" value="choix2">
     </div>
         
    - +
     <div class="field">
         <label for="checkbox1">choix 1</label>
    -    <input type="checkbox" id="checkbox1" name="checkbox" value="checkbox1" checked> 
    +    <input type="checkbox" id="checkbox1" name="checkbox" value="checkbox1" checked>
         <label for="checkbox2">choix 2</label>
         <input type="checkbox" id="checkbox2" name="checkbox" value="checkbox2">
     </div>
    @@ -161,11 +251,11 @@
                     
                     
                 
    - +

    Pas encore inscrit ? Inscrivez-vous

    - +
    @@ -196,20 +286,41 @@

    Les notifications

    +

    Erreur

    -<button 
    +<button
         type="button"
    -    class="button is-primary" 
    +    class="button is-primary"
         onclick="showToastr('Ceci est une notification');"
     >
         Afficher une notification
     </button>
     
    +<div id="toastr">
    +    <button class="delete" onclick="hideToastr()" aria-label="Masquer la notification"></button>
    +    <span></span>
    +</div>
    +    
    +

    Succès

    + +
    + + +
    +
    +<button
    +    type="button"
    +    class="button is-primary"
    +    onclick="showToastr('Ceci est une notification', true);"
    +>
    +    Afficher une notification
    +</button>
    +
     <div id="toastr">
         <button class="delete" onclick="hideToastr()" aria-label="Masquer la notification"></button>
         <span></span>
    @@ -225,15 +336,18 @@
         .icon-link-ext
         .icon-heart
         .icon-eye
    +    .icon-left-open
    +    .icon-right-open
    +    .icon-export
    +    .icon-share
         .icon-spin
         .icon-sun
         .icon-moon
         .icon-trash
         .icon-blind
    -    .icon-left-open
    -    .icon-right-open
     
         

    Les listes

    +

    Liste normale

    @@ -256,6 +370,29 @@ </div> </div>
    +

    Liste avec effet au hover

    +
    +
    + + {{ item.title }} + +
    +
    + +
    +
    + {{ item.lorem }} +
    +
    +
    +
    +
    +<div class="grid grid-cols-1 md:grid-cols-2 list hover">
    +    <div class="item">
    +        Contenu
    +    </div>
    +</div>
    +    

    Les paginations