Compare commits
18 commits
feature/f0
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
144dfaf8c8 | ||
|
|
fbd10c6fd5 | ||
|
|
b04045ca8e | ||
|
|
b7e37108cd | ||
|
|
f7441c5560 | ||
|
|
d9c975ec2f | ||
|
|
f2ff5c1531 | ||
|
|
3333968d16 | ||
|
|
b6f6ddda50 | ||
|
|
ce47113ddb | ||
|
|
9e7d81323b | ||
|
|
5f66740be2 | ||
|
|
d7bb3edcaa | ||
|
|
8a9ca97a80 | ||
|
|
f43a216cbd | ||
|
|
6b77327af8 | ||
|
|
8db9dcd40d | ||
|
|
ec9e9a8781 |
20 changed files with 1087 additions and 254 deletions
60
app.js
60
app.js
|
|
@ -1,24 +1,25 @@
|
||||||
const DISCORD_CLIENT_ID = "your_client_id";
|
|
||||||
const DISCORD_CLIENT_SECRET = "your_client_secret";
|
|
||||||
const DISCORD_CALLBACK_URL = "http://localhost:3000/auth/discord/callback";
|
|
||||||
const SESSION_SECRET = "your_session_secret";
|
const SESSION_SECRET = "your_session_secret";
|
||||||
|
|
||||||
// ...existing code...
|
|
||||||
|
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const session = require('express-session');
|
const session = require('express-session');
|
||||||
const passport = require('passport');
|
const initDb = require('./db_init');
|
||||||
const DiscordStrategy = require('passport-discord').Strategy;
|
|
||||||
const SQLite = require('sqlite3').verbose();
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const expressLayouts = require('express-ejs-layouts');
|
||||||
|
|
||||||
const routes = require('./routes');
|
const routes = require('./routes');
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
// DB SQLite
|
// DB SQLite
|
||||||
const db = new SQLite.Database('./database.sqlite', (err) => {
|
let db;
|
||||||
if (err) console.error('Erreur SQLite:', err);
|
initDb('./database.sqlite')
|
||||||
else db.run('CREATE TABLE IF NOT EXISTS users (id TEXT PRIMARY KEY, username TEXT, discriminator TEXT, avatar TEXT)');
|
.then((database) => {
|
||||||
|
db = database;
|
||||||
|
console.log('Base de données initialisée.');
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error('Erreur lors de l\'initialisation de la base de données :', err);
|
||||||
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Sessions
|
// Sessions
|
||||||
|
|
@ -28,40 +29,19 @@ app.use(session({
|
||||||
saveUninitialized: false
|
saveUninitialized: false
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Passport config
|
|
||||||
passport.serializeUser((user, done) => done(null, user.id));
|
|
||||||
passport.deserializeUser((id, done) => {
|
|
||||||
db.get('SELECT * FROM users WHERE id = ?', [id], (err, row) => {
|
|
||||||
if (err) return done(err);
|
|
||||||
done(null, row);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
passport.use(new DiscordStrategy({
|
|
||||||
clientID: DISCORD_CLIENT_ID,
|
|
||||||
clientSecret: DISCORD_CLIENT_SECRET,
|
|
||||||
callbackURL: DISCORD_CALLBACK_URL,
|
|
||||||
scope: ['identify']
|
|
||||||
}, (accessToken, refreshToken, profile, done) => {
|
|
||||||
db.run('INSERT OR REPLACE INTO users (id, username, discriminator, avatar) VALUES (?, ?, ?, ?)',
|
|
||||||
[profile.id, profile.username, profile.discriminator, profile.avatar],
|
|
||||||
(err) => {
|
|
||||||
if (err) return done(err);
|
|
||||||
done(null, profile);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}));
|
|
||||||
|
|
||||||
app.use(passport.initialize());
|
|
||||||
app.use(passport.session());
|
|
||||||
|
|
||||||
// EJS
|
// EJS
|
||||||
app.set('view engine', 'ejs');
|
app.set('view engine', 'ejs');
|
||||||
app.set('views', path.join(__dirname, 'views'));
|
app.set('views', path.join(__dirname, 'views'));
|
||||||
|
|
||||||
|
// Express EJS Layouts
|
||||||
|
app.use(expressLayouts);
|
||||||
|
app.set('layout', 'layout'); // nom du fichier layout sans .ejs
|
||||||
|
|
||||||
|
// Static files
|
||||||
|
app.use(express.static(path.join(__dirname, 'public')));
|
||||||
|
|
||||||
// Routes
|
// Routes
|
||||||
app.use('/', routes);
|
app.use('/', routes);
|
||||||
|
|
||||||
const PORT = process.env.PORT || 3000;
|
const PORT = 3000;
|
||||||
app.listen(PORT, () => console.log('Serveur lancé sur http://localhost:' + PORT));
|
app.listen(PORT, () => console.log('Serveur lancé sur http://localhost:' + PORT));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
const sqlite3 = require('sqlite3').verbose();
|
|
||||||
const dbPath = '../database.sqlite';
|
|
||||||
const db = new sqlite3.Database(dbPath, (err) => {
|
|
||||||
if (err) {
|
|
||||||
console.error(err.message);
|
|
||||||
}
|
|
||||||
console.log('Connected to the SQLite database.');
|
|
||||||
});
|
|
||||||
|
|
||||||
import L from 'leaflet';
|
|
||||||
|
|
||||||
const key = 'YOUR_MAPTILER_API_KEY_HERE';
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
const map = L.map('search-map').setView([49.2125578, 16.62662018], 14);
|
|
||||||
L.tileLayer(`https://api.maptiler.com/maps/streets-v2/{z}/{x}/{y}.png?key=${key}`, {
|
|
||||||
tileSize: 512,
|
|
||||||
zoomOffset: -1,
|
|
||||||
minZoom: 1,
|
|
||||||
attribution: "\u003ca href=\"https://www.maptiler.com/copyright/\" target=\"_blank\"\u003e\u0026copy; MapTiler\u003c/a\u003e \u003ca href=\"https://www.openstreetmap.org/copyright\" target=\"_blank\"\u003e\u0026copy; OpenStreetMap contributors\u003c/a\u003e",
|
|
||||||
crossOrigin: true
|
|
||||||
}).addTo(map);
|
|
||||||
});
|
|
||||||
|
|
||||||
alert("connard");
|
|
||||||
BIN
database.sqlite
BIN
database.sqlite
Binary file not shown.
25
db_init.js
Normal file
25
db_init.js
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
const SQLite = require('sqlite3').verbose();
|
||||||
|
|
||||||
|
function initDb(dbPath = './database.sqlite') {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const db = new SQLite.Database(dbPath, (err) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
} else {
|
||||||
|
db.run(`CREATE TABLE IF NOT EXISTS users (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
username TEXT,
|
||||||
|
discord_id TEXT DEFAULT NULL,
|
||||||
|
google_id TEXT DEFAULT NULL,
|
||||||
|
discriminator TEXT,
|
||||||
|
avatar TEXT
|
||||||
|
)`, (err) => {
|
||||||
|
if (err) reject(err);
|
||||||
|
else resolve(db);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = initDb;
|
||||||
4
db_instance.js
Normal file
4
db_instance.js
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
// Singleton pour partager l'instance db partout
|
||||||
|
const SQLite = require('sqlite3').verbose();
|
||||||
|
const db = new SQLite.Database('./database.sqlite');
|
||||||
|
module.exports = db;
|
||||||
58
modules/auth/discord.js
Normal file
58
modules/auth/discord.js
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
const { getUserByDId } = require('./../users/getUsers');
|
||||||
|
const { postUser } = require('./../users/postUsers');
|
||||||
|
|
||||||
|
const BOT_ID = "1410258710407811082";
|
||||||
|
const BOT_SECRET = "Bn5FGfrNZCdG1XpCciOcLkzLmrz6fhib";
|
||||||
|
const REDIRECT_URI = "http://localhost:3000/auth/discord/callback";
|
||||||
|
|
||||||
|
exports.handleDiscordAuth = async (req, res) => {
|
||||||
|
const code = req.query.code;
|
||||||
|
if (!code) return res.status(400).json({ error: "Code de validation manquant" });
|
||||||
|
try {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
params.append("client_id", BOT_ID);
|
||||||
|
params.append("client_secret", BOT_SECRET);
|
||||||
|
params.append("grant_type", "authorization_code");
|
||||||
|
params.append("code", code);
|
||||||
|
params.append("redirect_uri", REDIRECT_URI);
|
||||||
|
params.append("scope", "identify email");
|
||||||
|
const tokenData = await axios.post(
|
||||||
|
"https://discord.com/api/oauth2/token",
|
||||||
|
params,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const accessToken = tokenData.data.access_token;
|
||||||
|
const userResponse = await axios.get("https://discord.com/api/users/@me", {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${accessToken}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const userData = userResponse.data;
|
||||||
|
if (!userData || !userData.id) {
|
||||||
|
console.error('Réponse Discord inattendue:', userResponse.data);
|
||||||
|
return res.status(500).json({ error: "Impossible de récupérer les infos utilisateur depuis Discord", details: userResponse.data });
|
||||||
|
}
|
||||||
|
let savedUser = await getUserByDId(userData.id);
|
||||||
|
if (!savedUser) {
|
||||||
|
const newUser = {
|
||||||
|
username: userData.username,
|
||||||
|
discord_id: userData.id,
|
||||||
|
avatar: userData.avatar
|
||||||
|
? `https://cdn.discordapp.com/avatars/${userData.id}/${userData.avatar}.png`
|
||||||
|
: null,
|
||||||
|
};
|
||||||
|
savedUser = await postUser(newUser);
|
||||||
|
}
|
||||||
|
req.session.user = savedUser;
|
||||||
|
res.redirect('/');
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err.response?.data || err.message);
|
||||||
|
res.status(500).json({ error: "Erreur lors de la connexion à Discord" });
|
||||||
|
}
|
||||||
|
};
|
||||||
54
modules/auth/google.js
Normal file
54
modules/auth/google.js
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
const { getUserByGId } = require('../users/getUsers');
|
||||||
|
const { postUser } = require('../users/postUsers');
|
||||||
|
|
||||||
|
const CLIEN_ID = "71229835507-9413gbpdamv2qbcb2ov8oda2oqgcsk8q.apps.googleusercontent.com";
|
||||||
|
const GOOGLE_SECRET = "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";
|
||||||
|
const GOOGLE_REDIRECT_URI = "http://localhost:3000/auth/google/callback";
|
||||||
|
|
||||||
|
exports.handleGoogleAuth = async (req, res) => {
|
||||||
|
const code = req.query.code;
|
||||||
|
if (!code) return res.status(400).json({ error: "Code de validation manquant" });
|
||||||
|
try {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
params.append("client_id", CLIEN_ID);
|
||||||
|
params.append("client_secret", GOOGLE_SECRET);
|
||||||
|
params.append("grant_type", "authorization_code");
|
||||||
|
params.append("code", code);
|
||||||
|
params.append("redirect_uri", GOOGLE_REDIRECT_URI);
|
||||||
|
const tokenData = await axios.post(
|
||||||
|
"https://oauth2.googleapis.com/token",
|
||||||
|
params,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const accessToken = tokenData.data.access_token;
|
||||||
|
const userResponse = await axios.get("https://www.googleapis.com/oauth2/v2/userinfo", {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${accessToken}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const userData = userResponse.data;
|
||||||
|
if (!userData || !userData.id) {
|
||||||
|
console.error("Réponse Google inattendue:", userResponse.data);
|
||||||
|
return res.status(500).json({ error: "Impossible de récupérer les infos utilisateur depuis Google", details: userResponse.data });
|
||||||
|
}
|
||||||
|
let savedUser = await getUserByGId(userData.id);
|
||||||
|
if (!savedUser) {
|
||||||
|
const newUser = {
|
||||||
|
username: userData.name || userData.email,
|
||||||
|
google_id: userData.id,
|
||||||
|
};
|
||||||
|
savedUser = await postUser(newUser);
|
||||||
|
}
|
||||||
|
req.session.user = savedUser;
|
||||||
|
res.redirect('/');
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err.response?.data || err.message);
|
||||||
|
res.status(500).json({ error: "Erreur lors de la connexion à Google" });
|
||||||
|
}
|
||||||
|
};
|
||||||
26
modules/users/getUsers.js
Normal file
26
modules/users/getUsers.js
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
|
||||||
|
const db = require('../../db_instance');
|
||||||
|
|
||||||
|
module.exports.getUserByDId = async (discordId) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const query = `SELECT * FROM users WHERE discord_id = ?`;
|
||||||
|
db.get(query, [discordId], (err, row) => {
|
||||||
|
if (err) {
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
resolve(row);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.getUserByGId = async (discordId) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const query = `SELECT * FROM users WHERE google_id = ?`;
|
||||||
|
db.get(query, [discordId], (err, row) => {
|
||||||
|
if (err) {
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
resolve(row);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
20
modules/users/postUsers.js
Normal file
20
modules/users/postUsers.js
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
const db = require('../../db_instance');
|
||||||
|
|
||||||
|
module.exports.postUser = (user) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const query = `INSERT INTO users (id, username, discord_id, discriminator, avatar) VALUES (?, ?, ?, ?, ?)`;
|
||||||
|
const params = [
|
||||||
|
user.id,
|
||||||
|
user.username,
|
||||||
|
user.discord_id,
|
||||||
|
user.discriminator,
|
||||||
|
user.avatar
|
||||||
|
];
|
||||||
|
db.run(query, params, function(err) {
|
||||||
|
if (err) {
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
resolve({ id: this.lastID, ...user });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
250
package-lock.json
generated
250
package-lock.json
generated
|
|
@ -9,13 +9,11 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dotenv": "^17.2.1",
|
"axios": "^1.11.0",
|
||||||
"ejs": "^3.1.10",
|
"ejs": "^3.1.10",
|
||||||
"express": "^5.1.0",
|
"express": "^5.1.0",
|
||||||
|
"express-ejs-layouts": "^2.5.1",
|
||||||
"express-session": "^1.18.2",
|
"express-session": "^1.18.2",
|
||||||
"leaflet": "^1.9.4",
|
|
||||||
"passport": "^0.7.0",
|
|
||||||
"passport-discord": "^0.1.4",
|
|
||||||
"sqlite3": "^5.1.7"
|
"sqlite3": "^5.1.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -160,6 +158,23 @@
|
||||||
"integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
|
"integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/asynckit": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/axios": {
|
||||||
|
"version": "1.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz",
|
||||||
|
"integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"follow-redirects": "^1.15.6",
|
||||||
|
"form-data": "^4.0.4",
|
||||||
|
"proxy-from-env": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/balanced-match": {
|
"node_modules/balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
|
|
@ -186,15 +201,6 @@
|
||||||
],
|
],
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/base64url": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/bindings": {
|
"node_modules/bindings": {
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||||
|
|
@ -365,6 +371,18 @@
|
||||||
"color-support": "bin.js"
|
"color-support": "bin.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/combined-stream": {
|
||||||
|
"version": "1.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
|
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"delayed-stream": "~1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/concat-map": {
|
"node_modules/concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
|
|
@ -459,6 +477,15 @@
|
||||||
"node": ">=4.0.0"
|
"node": ">=4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/delayed-stream": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/delegates": {
|
"node_modules/delegates": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
||||||
|
|
@ -484,18 +511,6 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/dotenv": {
|
|
||||||
"version": "17.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.1.tgz",
|
|
||||||
"integrity": "sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==",
|
|
||||||
"license": "BSD-2-Clause",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://dotenvx.com"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/dunder-proto": {
|
"node_modules/dunder-proto": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||||
|
|
@ -613,6 +628,21 @@
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/es-set-tostringtag": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"get-intrinsic": "^1.2.6",
|
||||||
|
"has-tostringtag": "^1.0.2",
|
||||||
|
"hasown": "^2.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/escape-html": {
|
"node_modules/escape-html": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||||
|
|
@ -679,6 +709,11 @@
|
||||||
"url": "https://opencollective.com/express"
|
"url": "https://opencollective.com/express"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/express-ejs-layouts": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/express-ejs-layouts/-/express-ejs-layouts-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-IXROv9n3xKga7FowT06n1Qn927JR8ZWDn5Dc9CJQoiiaaDqbhW5PDmWShzbpAa2wjWT1vJqaIM1S6vJwwX11gA=="
|
||||||
|
},
|
||||||
"node_modules/express-session": {
|
"node_modules/express-session": {
|
||||||
"version": "1.18.2",
|
"version": "1.18.2",
|
||||||
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.2.tgz",
|
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.2.tgz",
|
||||||
|
|
@ -751,6 +786,63 @@
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/follow-redirects": {
|
||||||
|
"version": "1.15.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
|
||||||
|
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"debug": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/form-data": {
|
||||||
|
"version": "4.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
|
||||||
|
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"asynckit": "^0.4.0",
|
||||||
|
"combined-stream": "^1.0.8",
|
||||||
|
"es-set-tostringtag": "^2.1.0",
|
||||||
|
"hasown": "^2.0.2",
|
||||||
|
"mime-types": "^2.1.12"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/form-data/node_modules/mime-db": {
|
||||||
|
"version": "1.52.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||||
|
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/form-data/node_modules/mime-types": {
|
||||||
|
"version": "2.1.35",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||||
|
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"mime-db": "1.52.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/forwarded": {
|
"node_modules/forwarded": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||||
|
|
@ -944,6 +1036,21 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/has-tostringtag": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"has-symbols": "^1.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/has-unicode": {
|
"node_modules/has-unicode": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
|
||||||
|
|
@ -1183,12 +1290,6 @@
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/leaflet": {
|
|
||||||
"version": "1.9.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz",
|
|
||||||
"integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==",
|
|
||||||
"license": "BSD-2-Clause"
|
|
||||||
},
|
|
||||||
"node_modules/lru-cache": {
|
"node_modules/lru-cache": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||||
|
|
@ -1534,12 +1635,6 @@
|
||||||
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
|
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/oauth": {
|
|
||||||
"version": "0.10.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/oauth/-/oauth-0.10.2.tgz",
|
|
||||||
"integrity": "sha512-JtFnB+8nxDEXgNyniwz573xxbKSOu3R8D40xQKqcjwJ2CDkYqUDI53o6IuzDJBx60Z8VKCm271+t8iFjakrl8Q==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/object-inspect": {
|
"node_modules/object-inspect": {
|
||||||
"version": "1.13.4",
|
"version": "1.13.4",
|
||||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
|
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
|
||||||
|
|
@ -1607,61 +1702,6 @@
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/passport": {
|
|
||||||
"version": "0.7.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz",
|
|
||||||
"integrity": "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"passport-strategy": "1.x.x",
|
|
||||||
"pause": "0.0.1",
|
|
||||||
"utils-merge": "^1.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "github",
|
|
||||||
"url": "https://github.com/sponsors/jaredhanson"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/passport-discord": {
|
|
||||||
"version": "0.1.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/passport-discord/-/passport-discord-0.1.4.tgz",
|
|
||||||
"integrity": "sha512-VJWPYqSOmh7SaCLw/C+k1ZqCzJnn2frrmQRx1YrcPJ3MQ+Oa31XclbbmqFICSvl8xv3Fqd6YWQ4H4p1MpIN9rA==",
|
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {
|
|
||||||
"passport-oauth2": "^1.5.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/passport-oauth2": {
|
|
||||||
"version": "1.8.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.8.0.tgz",
|
|
||||||
"integrity": "sha512-cjsQbOrXIDE4P8nNb3FQRCCmJJ/utnFKEz2NX209f7KOHPoX18gF7gBzBbLLsj2/je4KrgiwLLGjf0lm9rtTBA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"base64url": "3.x.x",
|
|
||||||
"oauth": "0.10.x",
|
|
||||||
"passport-strategy": "1.x.x",
|
|
||||||
"uid2": "0.0.x",
|
|
||||||
"utils-merge": "1.x.x"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "github",
|
|
||||||
"url": "https://github.com/sponsors/jaredhanson"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/passport-strategy": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/path-is-absolute": {
|
"node_modules/path-is-absolute": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||||
|
|
@ -1681,11 +1721,6 @@
|
||||||
"node": ">=16"
|
"node": ">=16"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pause": {
|
|
||||||
"version": "0.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
|
|
||||||
"integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg=="
|
|
||||||
},
|
|
||||||
"node_modules/picocolors": {
|
"node_modules/picocolors": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||||
|
|
@ -1752,6 +1787,12 @@
|
||||||
"node": ">= 0.10"
|
"node": ">= 0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/proxy-from-env": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/pump": {
|
"node_modules/pump": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
|
||||||
|
|
@ -2334,12 +2375,6 @@
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/uid2": {
|
|
||||||
"version": "0.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.4.tgz",
|
|
||||||
"integrity": "sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/unique-filename": {
|
"node_modules/unique-filename": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
|
||||||
|
|
@ -2375,15 +2410,6 @@
|
||||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/utils-merge": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
|
||||||
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/vary": {
|
"node_modules/vary": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,11 @@
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"type": "commonjs",
|
"type": "commonjs",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dotenv": "^17.2.1",
|
"axios": "^1.11.0",
|
||||||
"ejs": "^3.1.10",
|
"ejs": "^3.1.10",
|
||||||
"express": "^5.1.0",
|
"express": "^5.1.0",
|
||||||
|
"express-ejs-layouts": "^2.5.1",
|
||||||
"express-session": "^1.18.2",
|
"express-session": "^1.18.2",
|
||||||
"leaflet": "^1.9.4",
|
|
||||||
"passport": "^0.7.0",
|
|
||||||
"passport-discord": "^0.1.4",
|
|
||||||
"sqlite3": "^5.1.7"
|
"sqlite3": "^5.1.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
BIN
public/logo.png
Normal file
BIN
public/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 238 KiB |
111
public/resto.css
Normal file
111
public/resto.css
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
main {
|
||||||
|
text-align: left !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.restaurant-page {
|
||||||
|
width: 90%;
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.restaurant-info h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heart {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: #ececec;
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
font-size: 20px;
|
||||||
|
margin-left: 8px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rating {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin: 10px 0;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
background: #999;
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
padding: 5px 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-placeholder {
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
background: #eee;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-image {
|
||||||
|
width: 100%;
|
||||||
|
height: 200px;
|
||||||
|
background: #ccc;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
background: #f9f9f9;
|
||||||
|
padding: 15px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-item {
|
||||||
|
width: 32%;
|
||||||
|
height: 150px;
|
||||||
|
background: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reviews-title {
|
||||||
|
background: #eee;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reviews {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 20px;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review {
|
||||||
|
background: #f5f5f5;
|
||||||
|
padding: 15px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review h3 {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-rating div {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
294
public/style.css
Normal file
294
public/style.css
Normal file
|
|
@ -0,0 +1,294 @@
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
background: linear-gradient(135deg, #f8f6fc 0%, #fffbe7 100%);
|
||||||
|
color: #7a5c1e;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
background: linear-gradient(90deg, #8e68aa 60%, #cb8d37 100%);
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 10px 20px;
|
||||||
|
box-shadow: 0 2px 8px rgba(140, 104, 170, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
header h1 {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-bar {
|
||||||
|
flex-grow: 1;
|
||||||
|
margin: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-bar input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 5px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account {
|
||||||
|
background: linear-gradient(90deg, #cb8d37 60%, #8e68aa 100%);
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account:hover {
|
||||||
|
background: #a97b2c;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
main h2 {
|
||||||
|
font-size: 2rem;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sections {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 30px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section h3 {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cards {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
background: #ddd;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 15px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-info {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-info h4 {
|
||||||
|
margin: 0 0 5px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-photo {
|
||||||
|
background: #8e68aa;
|
||||||
|
width: 120px;
|
||||||
|
height: 80px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
background: #8e68aa;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px;
|
||||||
|
margin-top: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer a {
|
||||||
|
margin: 0 10px;
|
||||||
|
text-decoration: none;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header layout amélioré */
|
||||||
|
.main-header {
|
||||||
|
background: linear-gradient(90deg, #8e68aa 60%, #cb8d37 100%);
|
||||||
|
color: white;
|
||||||
|
box-shadow: 0 2px 8px rgba(140, 104, 170, 0.08);
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 10px 20px;
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 100%;
|
||||||
|
gap: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 220px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-left h1 {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
margin: 0 0 0 10px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-center {
|
||||||
|
flex: 1 1 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 260px;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-bar {
|
||||||
|
flex: 1 1 300px;
|
||||||
|
max-width: 700px;
|
||||||
|
margin: 0 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-bar input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 7px 12px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background: linear-gradient(90deg, #cb8d37 60%, #8e68aa 100%);
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account a {
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
margin-left: 8px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account a:first-child {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account:hover {
|
||||||
|
background: #a97b2c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-social {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 8px 18px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 30px;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.07);
|
||||||
|
transition: transform 0.1s, box-shadow 0.2s;
|
||||||
|
outline: none;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-social:active {
|
||||||
|
transform: scale(0.97);
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-google {
|
||||||
|
background: #fff;
|
||||||
|
color: #444;
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
}
|
||||||
|
.btn-google:hover {
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-discord {
|
||||||
|
background: #5865f2;
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
.btn-discord:hover {
|
||||||
|
background: #4752c4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-social {
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
height: 40px;
|
||||||
|
width: 40px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-right: 10px;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive */
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.header-content {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
.header-center {
|
||||||
|
justify-content: stretch;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
.header-right {
|
||||||
|
justify-content: center;
|
||||||
|
min-width: 0;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
.search-bar {
|
||||||
|
min-width: 180px;
|
||||||
|
max-width: 100%;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
.account {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
.sections {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
.social-buttons {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
43
routes.js
43
routes.js
|
|
@ -1,31 +1,46 @@
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const passport = require('passport');
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
// Page d'accueil
|
// Page d'accueil
|
||||||
router.get('/', (req, res) => {
|
router.get('/', (req, res) => {
|
||||||
res.render('index', { user: req.user });
|
res.render('index', { user: req.session.user });
|
||||||
});
|
});
|
||||||
|
|
||||||
// Page de recherche
|
// Page resto
|
||||||
router.get('/recherche', (req, res) => {
|
router.get('/resto/:id', (req, res) => {
|
||||||
res.render('search', { user: req.user });
|
res.render('resto', { user: req.session.user });
|
||||||
});
|
});
|
||||||
|
|
||||||
// Auth Discord
|
// Auth Discord
|
||||||
router.get('/auth/discord', passport.authenticate('discord'));
|
router.get('/auth/discord', (req, res) => {
|
||||||
|
const clientId = '1410258710407811082';
|
||||||
|
const redirectUri = 'http://localhost:3000/auth/discord/callback';
|
||||||
|
const scope = 'identify email';
|
||||||
|
const discordAuthUrl = `https://discord.com/api/oauth2/authorize?client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&response_type=code&scope=${scope}`;
|
||||||
|
res.redirect(discordAuthUrl);
|
||||||
|
});
|
||||||
|
|
||||||
router.get('/auth/discord/callback',
|
router.get('/auth/discord/callback', require('./modules/auth/discord').handleDiscordAuth);
|
||||||
passport.authenticate('discord', { failureRedirect: '/' }),
|
|
||||||
(req, res) => {
|
// Auth Google
|
||||||
res.redirect('/');
|
router.get('/auth/google', (req, res) => {
|
||||||
}
|
const clientId = '71229835507-9413gbpdamv2qbcb2ov8oda2oqgcsk8q.apps.googleusercontent.com';
|
||||||
);
|
const redirectUri = 'http://localhost:3000/auth/google/callback';
|
||||||
|
const scope = 'https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile';
|
||||||
|
const googleAuthUrl = `https://accounts.google.com/o/oauth2/auth?client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&response_type=code&scope=${encodeURIComponent(scope)}`;
|
||||||
|
res.redirect(googleAuthUrl);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/auth/google/callback', require('./modules/auth/google').handleGoogleAuth);
|
||||||
|
|
||||||
// Déconnexion
|
// Déconnexion
|
||||||
router.get('/logout', (req, res) => {
|
router.get('/logout', (req, res) => {
|
||||||
req.logout(() => {
|
req.session.destroy((err) => {
|
||||||
res.redirect('/');
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
return res.send("Erreur lors de la déconnexion");
|
||||||
|
}
|
||||||
|
res.redirect("/"); // Redirige vers la page d'accueil
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
BIN
static/carte.png
BIN
static/carte.png
Binary file not shown.
|
Before Width: | Height: | Size: 785 KiB |
|
|
@ -1,15 +1,78 @@
|
||||||
<!DOCTYPE html>
|
<div style="display:flex; justify-content: center; align-items: center;">
|
||||||
<html>
|
<h2 style="margin-right: 20px;">L’EPICURIEN</h2>
|
||||||
<head>
|
<img style="height: 70px; width: 70px; object-fit: contain;" alt="Logo de l'entreprise" src="logo.png" onerror="this.onerror=null;this.src='https://via.placeholder.com/70?text=Logo';" />
|
||||||
<title>Accueil</title>
|
</div>
|
||||||
</head>
|
<div class="sections">
|
||||||
<body>
|
<!-- Restaurants proches -->
|
||||||
<% if (user) { %>
|
<div class="section">
|
||||||
<h1>Bienvenue, <%= user.username %>!</h1>
|
<h3>Restaurants les plus proches</h3>
|
||||||
<a href="/logout">Déconnexion</a>
|
<div class="cards">
|
||||||
<% } else { %>
|
<a href="/resto/1" style="text-decoration:none; color:inherit;">
|
||||||
<h1>Bienvenue sur Resto-EPI</h1>
|
<div class="card">
|
||||||
<a href="/auth/discord">Connexion/Inscription via Discord</a>
|
<div class="card-info">
|
||||||
<% } %>
|
<h4>Le Canard Toulousain</h4>
|
||||||
</body>
|
<p>12 Rue du Capitole, 31000 Toulouse</p>
|
||||||
</html>
|
<p>Avis général</p>
|
||||||
|
</div>
|
||||||
|
<img alt="Photo du restaurant" src="https://source.unsplash.com/100x100/?restaurant=1" />
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a href="/resto/2" style="text-decoration:none; color:inherit;">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-info">
|
||||||
|
<h4>Chez Pépé Louis</h4>
|
||||||
|
<p>8 Avenue de la Garonne, 31000 Toulouse</p>
|
||||||
|
<p>Avis général</p>
|
||||||
|
</div>
|
||||||
|
<img alt="Photo du restaurant" src="https://source.unsplash.com/100x100/?restaurant=2" />
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a href="/resto/3" style="text-decoration:none; color:inherit;">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-info">
|
||||||
|
<h4>La Table Rose</h4>
|
||||||
|
<p>25 Rue Saint-Rome, 31000 Toulouse</p>
|
||||||
|
<p>Avis général</p>
|
||||||
|
</div>
|
||||||
|
<img alt="Photo du restaurant" src="https://source.unsplash.com/100x100/?restaurant=3" />
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Restaurants populaires -->
|
||||||
|
<div class="section">
|
||||||
|
<h3>Restaurants les plus populaires</h3>
|
||||||
|
<div class="cards">
|
||||||
|
<a href="/resto/4" style="text-decoration:none; color:inherit;">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-info">
|
||||||
|
<h4>Bistro Occitan</h4>
|
||||||
|
<p>5 Place Wilson, 31000 Toulouse</p>
|
||||||
|
<p>Avis général</p>
|
||||||
|
</div>
|
||||||
|
<img alt="Photo du restaurant" src="https://source.unsplash.com/100x100/?restaurant=4" />
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a href="/resto/5" style="text-decoration:none; color:inherit;">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-info">
|
||||||
|
<h4>L’Assiette du Sud</h4>
|
||||||
|
<p>17 Allée Jean Jaurès, 31000 Toulouse</p>
|
||||||
|
<p>Avis général</p>
|
||||||
|
</div>
|
||||||
|
<img alt="Photo du restaurant" src="https://source.unsplash.com/100x100/?restaurant=5" />
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a href="/resto/6" style="text-decoration:none; color:inherit;">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-info">
|
||||||
|
<h4>Le Petit Cassoulet</h4>
|
||||||
|
<p>3 Rue des Filatiers, 31000 Toulouse</p>
|
||||||
|
<p>Avis général</p>
|
||||||
|
</div>
|
||||||
|
<img alt="Photo du restaurant" src="https://source.unsplash.com/100x100/?restaurant=6" />
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
60
views/layout.ejs
Normal file
60
views/layout.ejs
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="fr">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<meta name="description" content="L'EPICURIEN - Découvrez et partagez les meilleurs restaurants autour de vous." />
|
||||||
|
<meta name="author" content="L'EPICURIEN Team" />
|
||||||
|
<title>L'EPICURIEN</title>
|
||||||
|
<link rel="stylesheet" href="/style.css" />
|
||||||
|
<link rel="icon" href="/logo.png" type="image/png" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<header class="main-header">
|
||||||
|
<div class="header-content">
|
||||||
|
<div class="header-left">
|
||||||
|
<a href="/" class="logo-link">
|
||||||
|
<img src="/logo.png" alt="Logo L'EPICURIEN" class="logo" />
|
||||||
|
</a>
|
||||||
|
<a href="/" class="">
|
||||||
|
<h1 style="text-decoration: none; color: white;">L'EPICURIEN</h1>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="header-center">
|
||||||
|
<div class="search-bar">
|
||||||
|
<input type="text" placeholder="Rechercher un restaurant" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="header-right">
|
||||||
|
<div class="account">
|
||||||
|
<% if (user) { %>
|
||||||
|
<a href="/logout" style="margin-left:12px;">Déconnexion</a>
|
||||||
|
<% } else { %>
|
||||||
|
<div class="social-buttons">
|
||||||
|
<a href="/auth/google" class="btn-social btn-google">
|
||||||
|
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/google/google-original.svg" alt="Google" class="icon-social"/>
|
||||||
|
</a>
|
||||||
|
<a href="/auth/discord" class="btn-social btn-discord">
|
||||||
|
<img src="https://cdn.jsdelivr.net/gh/edent/SuperTinyIcons/images/svg/discord.svg" alt="Discord" class="icon-social"/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<%- body %>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="main-footer">
|
||||||
|
<a href="#">Mentions légales</a> |
|
||||||
|
<a href="#">Politique de confidentialité</a> |
|
||||||
|
<a href="#">CGU</a>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
166
views/resto.ejs
Normal file
166
views/resto.ejs
Normal file
|
|
@ -0,0 +1,166 @@
|
||||||
|
<link rel="stylesheet" href="/resto.css" />
|
||||||
|
|
||||||
|
<div class="restaurant-page">
|
||||||
|
<!-- En-tête restaurant -->
|
||||||
|
<div class="header">
|
||||||
|
<div class="restaurant-info">
|
||||||
|
<h1>
|
||||||
|
Nom restaurant
|
||||||
|
<span class="heart">
|
||||||
|
<% if (user) { %>
|
||||||
|
❤️
|
||||||
|
<% } else { %>
|
||||||
|
🤍
|
||||||
|
<% } %>
|
||||||
|
</span>
|
||||||
|
</h1>
|
||||||
|
<p class="address">Adresse</p>
|
||||||
|
<div class="rating">
|
||||||
|
<span>⭐️⭐️⭐️⭐️⭐️</span>
|
||||||
|
<a href="#avis" class="btn">Voir tous les avis</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="chart">
|
||||||
|
<div class="chart-placeholder">
|
||||||
|
<canvas id="radarChart"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Image principale -->
|
||||||
|
<div class="main-image"></div>
|
||||||
|
|
||||||
|
<!-- Description -->
|
||||||
|
<div class="description">
|
||||||
|
<p>
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
|
||||||
|
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
|
||||||
|
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
|
||||||
|
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
|
||||||
|
occaecat cupidatat
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Galerie -->
|
||||||
|
<div class="gallery">
|
||||||
|
<div class="gallery-item"></div>
|
||||||
|
<div class="gallery-item"></div>
|
||||||
|
<div class="gallery-item"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Avis -->
|
||||||
|
<h2 class="reviews-title" id="avis">Avis</h2>
|
||||||
|
<div class="reviews">
|
||||||
|
<div class="review">
|
||||||
|
<h3>Titre avis</h3>
|
||||||
|
<p>
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
||||||
|
eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||||
|
</p>
|
||||||
|
<div class="review-rating">
|
||||||
|
<div>Qualité des plats ⭐⭐⭐⭐⭐</div>
|
||||||
|
<div>Service ⭐⭐⭐⭐⭐</div>
|
||||||
|
<div>Ambiance ⭐⭐⭐⭐⭐</div>
|
||||||
|
<div>Accessibilité ⭐⭐⭐⭐⭐</div>
|
||||||
|
<div>Tarif ⭐⭐⭐⭐⭐</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="review">
|
||||||
|
<h3>Titre avis</h3>
|
||||||
|
<p>
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
||||||
|
eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||||
|
</p>
|
||||||
|
<div class="review-rating">
|
||||||
|
<div>Qualité des plats ⭐⭐⭐⭐⭐</div>
|
||||||
|
<div>Service ⭐⭐⭐⭐⭐</div>
|
||||||
|
<div>Ambiance ⭐⭐⭐⭐⭐</div>
|
||||||
|
<div>Accessibilité ⭐⭐⭐⭐⭐</div>
|
||||||
|
<div>Tarif ⭐⭐⭐⭐⭐</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="review">
|
||||||
|
<h3>Titre avis</h3>
|
||||||
|
<p>
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
||||||
|
eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||||
|
</p>
|
||||||
|
<div class="review-rating">
|
||||||
|
<div>Qualité des plats ⭐⭐⭐⭐⭐</div>
|
||||||
|
<div>Service ⭐⭐⭐⭐⭐</div>
|
||||||
|
<div>Ambiance ⭐⭐⭐⭐⭐</div>
|
||||||
|
<div>Accessibilité ⭐⭐⭐⭐⭐</div>
|
||||||
|
<div>Tarif ⭐⭐⭐⭐⭐</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const ctx = document.getElementById('radarChart').getContext('2d');
|
||||||
|
const radarChart = new Chart(ctx, {
|
||||||
|
type: 'radar',
|
||||||
|
data: {
|
||||||
|
labels: ['Qualité des plats', 'Ambiance', 'Accessibilité', 'Service', 'Tradition'],
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: 'Moyenne des notes',
|
||||||
|
data: [4.7, 4.6, 4.4, 4.3, 4.8],
|
||||||
|
fill: true,
|
||||||
|
backgroundColor: 'rgba(255,215, 0, 0.2)',
|
||||||
|
borderColor: 'rgb(255,215, 0, 1)',
|
||||||
|
pointBackgroundColor: 'rgb(255,215, 0)',
|
||||||
|
pointBorderColor: '#fff',
|
||||||
|
pointHoverBackgroundColor: '#fff',
|
||||||
|
pointHoverBorderColor: 'rgb(255,215, 0)',
|
||||||
|
pointStyle: 'circle',
|
||||||
|
pointRadius: 5,
|
||||||
|
pointRotation: 0,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
display: false
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
callbacks: {
|
||||||
|
label: function(context) {
|
||||||
|
let label = context.dataset.label || '';
|
||||||
|
if (label) {
|
||||||
|
label += ': ';
|
||||||
|
}
|
||||||
|
label += context.formattedValue;
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
r: {
|
||||||
|
max: 5,
|
||||||
|
min: 0,
|
||||||
|
ticks: {
|
||||||
|
stepSize: 1,
|
||||||
|
display: false,
|
||||||
|
callback: function(value, index, values) {
|
||||||
|
return value.toFixed(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
elements: {
|
||||||
|
line: {
|
||||||
|
borderWidth: 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Rechercher un restaurant</title>
|
|
||||||
<link rel="stylesheet" href="styles.css">
|
|
||||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
|
||||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
|
||||||
<script src="../controllers/search.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="menu-bar">Barre menu</div>
|
|
||||||
|
|
||||||
<!-- Liste des restaurants -->
|
|
||||||
<table id="search-rst-list">
|
|
||||||
<!-- element resto -->
|
|
||||||
<td>
|
|
||||||
<tr>element</tr>
|
|
||||||
<tr>element</tr>
|
|
||||||
<tr>element</tr>
|
|
||||||
<tr>element</tr>
|
|
||||||
<tr>element</tr>
|
|
||||||
<tr>element</tr>
|
|
||||||
</td>
|
|
||||||
<!-- ... -->
|
|
||||||
</table>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Barre de filtres -->
|
|
||||||
<div id="search-filter-bar">
|
|
||||||
<div>Nom ville</div>
|
|
||||||
<div>Filtrer par</div>
|
|
||||||
<div>Champ de recherche</div>
|
|
||||||
<div>Affiner recherche</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Carte interactive -->
|
|
||||||
<div id="search-map">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="menu-footer">Barre footer</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
Loading…
Add table
Reference in a new issue