Preparing backend integration
This commit is contained in:
9
front/.editorconfig
Normal file
9
front/.editorconfig
Normal file
@@ -0,0 +1,9 @@
|
||||
[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue}]
|
||||
charset = utf-8
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
end_of_line = lf
|
||||
max_line_length = 100
|
||||
1
front/.gitattributes
vendored
Normal file
1
front/.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
* text=auto eol=lf
|
||||
30
front/.gitignore
vendored
Normal file
30
front/.gitignore
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
coverage
|
||||
*.local
|
||||
|
||||
/cypress/videos/
|
||||
/cypress/screenshots/
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
*.tsbuildinfo
|
||||
8
front/.vite/deps/_metadata.json
Normal file
8
front/.vite/deps/_metadata.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"hash": "5e4ba880",
|
||||
"configHash": "cda55e09",
|
||||
"lockfileHash": "e3b0c442",
|
||||
"browserHash": "94508008",
|
||||
"optimized": {},
|
||||
"chunks": {}
|
||||
}
|
||||
3
front/.vite/deps/package.json
Normal file
3
front/.vite/deps/package.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
22
front/Dockerfile
Normal file
22
front/Dockerfile
Normal file
@@ -0,0 +1,22 @@
|
||||
FROM node:lts-alpine
|
||||
|
||||
# install simple http server for serving static content
|
||||
RUN npm install -g serve
|
||||
|
||||
# make the 'app' folder the current working directory
|
||||
WORKDIR /app
|
||||
|
||||
# copy both 'package.json' and 'package-lock.json' (if available)
|
||||
COPY package*.json ./
|
||||
|
||||
# install project dependencies
|
||||
RUN npm install
|
||||
|
||||
# copy project files and folders to the current working directory (i.e. 'app' folder)
|
||||
COPY . .
|
||||
|
||||
# build app for production with minification
|
||||
RUN npm run build
|
||||
|
||||
EXPOSE 8080
|
||||
CMD ["serve", "-s", "dist", "-l", "8080"]
|
||||
4
front/README.md
Normal file
4
front/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# Hi there !
|
||||
|
||||
Inspired by when2meet, Let's meet is a free and open-source app that allows you and your friends to find a date to meet.
|
||||
From now on, there is no need to spend hours and hours trying to find a suitable day for everyone.
|
||||
4
front/deploy.sh
Normal file
4
front/deploy.sh
Normal file
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
docker build -t letsmeet .
|
||||
docker run -d -p 8080:8080 letsmeet
|
||||
1
front/env.d.ts
vendored
Normal file
1
front/env.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
28
front/eslint.config.ts
Normal file
28
front/eslint.config.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import pluginVue from 'eslint-plugin-vue'
|
||||
import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript'
|
||||
import pluginVitest from '@vitest/eslint-plugin'
|
||||
|
||||
// To allow more languages other than `ts` in `.vue` files, uncomment the following lines:
|
||||
// import { configureVueProject } from '@vue/eslint-config-typescript'
|
||||
// configureVueProject({ scriptLangs: ['ts', 'tsx'] })
|
||||
// More info at https://github.com/vuejs/eslint-config-typescript/#advanced-setup
|
||||
|
||||
export default defineConfigWithVueTs(
|
||||
{
|
||||
name: 'app/files-to-lint',
|
||||
files: ['**/*.{ts,mts,tsx,vue}'],
|
||||
},
|
||||
|
||||
{
|
||||
name: 'app/files-to-ignore',
|
||||
ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'],
|
||||
},
|
||||
|
||||
pluginVue.configs['flat/essential'],
|
||||
vueTsConfigs.recommended,
|
||||
|
||||
{
|
||||
...pluginVitest.configs.recommended,
|
||||
files: ['src/**/__tests__/*'],
|
||||
},
|
||||
)
|
||||
14
front/index.html
Normal file
14
front/index.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Afacad+Flux">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<title>Let's meet</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
9082
front/package-lock.json
generated
Normal file
9082
front/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
45
front/package.json
Normal file
45
front/package.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "letsmeet",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "run-p type-check \"build-only {@}\" --",
|
||||
"preview": "vite preview",
|
||||
"test:unit": "vitest",
|
||||
"build-only": "vite build",
|
||||
"type-check": "vue-tsc --build",
|
||||
"lint": "eslint . --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"express-requests-logger": "^4.0.2",
|
||||
"pinia": "^3.0.1",
|
||||
"vite-plugin-svgr": "^4.3.0",
|
||||
"vite-svg-loader": "^5.1.0",
|
||||
"vue": "^3.5.13",
|
||||
"vue-router": "^4.5.0",
|
||||
"vue-svg-loader": "^0.16.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tsconfig/node22": "^22.0.0",
|
||||
"@types/jsdom": "^21.1.7",
|
||||
"@types/node": "^22.13.4",
|
||||
"@vitejs/plugin-vue": "^5.2.1",
|
||||
"@vitejs/plugin-vue-jsx": "^4.1.1",
|
||||
"@vitest/eslint-plugin": "1.1.31",
|
||||
"@vue/eslint-config-typescript": "^14.4.0",
|
||||
"@vue/test-utils": "^2.4.6",
|
||||
"@vue/tsconfig": "^0.7.0",
|
||||
"eslint": "^9.20.1",
|
||||
"eslint-plugin-vue": "^9.32.0",
|
||||
"jiti": "^2.4.2",
|
||||
"jsdom": "^26.0.0",
|
||||
"npm-run-all2": "^7.0.2",
|
||||
"typescript": "~5.7.3",
|
||||
"vite": "^6.1.0",
|
||||
"vite-plugin-vue-devtools": "^7.7.2",
|
||||
"vitest": "^3.0.5",
|
||||
"vue-tsc": "^2.2.2"
|
||||
}
|
||||
}
|
||||
BIN
front/public/favicon.ico
Normal file
BIN
front/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
13
front/src/App.vue
Normal file
13
front/src/App.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import LayoutDefault from "@/layouts/LayoutDefault.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<layout-default>
|
||||
<router-view />
|
||||
</layout-default>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
3
front/src/assets/arrow-left.svg
Normal file
3
front/src/assets/arrow-left.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
|
||||
<path d="M9.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l192 192c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256 246.6 86.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-192 192z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 251 B |
3
front/src/assets/arrow-right.svg
Normal file
3
front/src/assets/arrow-right.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
|
||||
<path d="M310.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-192 192c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L242.7 256 73.4 86.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l192 192z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 254 B |
19
front/src/assets/base.css
Normal file
19
front/src/assets/base.css
Normal file
@@ -0,0 +1,19 @@
|
||||
:root
|
||||
{
|
||||
--primary-color : #1b2021;
|
||||
--secondary-color : #9BC53D;
|
||||
--header-color : #FCFCFC;
|
||||
--background-color : rgba(252, 252, 252, 0.43);
|
||||
--radius : 3px;
|
||||
--font-size : 1.3rem;
|
||||
}
|
||||
|
||||
|
||||
*
|
||||
{
|
||||
color: var(--primary-color);
|
||||
text-decoration: none;
|
||||
font-family: 'Afacad Flux', sans-serif;
|
||||
transition: 0.3s all;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
152
front/src/assets/logo.svg
Normal file
152
front/src/assets/logo.svg
Normal file
@@ -0,0 +1,152 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
width="2.33333in" height="2.1in"
|
||||
viewBox="0 0 210 189">
|
||||
<path id="Sélection"
|
||||
fill="none" stroke="black" stroke-width="1"
|
||||
d="M 0.00,0.00
|
||||
C 0.00,0.00 7.00,0.00 7.00,0.00
|
||||
7.00,0.00 7.00,53.00 7.00,53.00
|
||||
7.00,53.00 28.00,53.00 28.00,53.00
|
||||
28.00,53.00 28.00,60.00 28.00,60.00
|
||||
28.00,60.00 0.00,60.00 0.00,60.00
|
||||
0.00,60.00 0.00,0.00 0.00,0.00 Z
|
||||
M 113.00,0.00
|
||||
C 113.00,0.00 121.00,0.00 121.00,0.00
|
||||
120.96,4.95 119.67,17.07 114.61,19.43
|
||||
112.93,20.21 108.04,20.00 106.00,20.00
|
||||
110.61,12.43 112.57,9.11 113.00,0.00 Z
|
||||
M 87.00,6.00
|
||||
C 87.00,6.00 95.00,6.00 95.00,6.00
|
||||
95.00,6.00 95.00,20.00 95.00,20.00
|
||||
95.00,20.00 105.00,20.00 105.00,20.00
|
||||
105.00,20.00 105.00,26.00 105.00,26.00
|
||||
105.00,26.00 95.00,26.00 95.00,26.00
|
||||
95.00,26.00 95.00,60.00 95.00,60.00
|
||||
95.00,60.00 87.00,60.00 87.00,60.00
|
||||
87.00,60.00 87.00,26.00 87.00,26.00
|
||||
87.00,26.00 78.00,26.00 78.00,26.00
|
||||
78.00,26.00 78.00,20.00 78.00,20.00
|
||||
78.00,20.00 87.00,20.00 87.00,20.00
|
||||
87.00,20.00 87.00,6.00 87.00,6.00 Z
|
||||
M 67.00,47.00
|
||||
C 67.84,49.29 69.08,52.42 68.60,54.90
|
||||
67.45,60.75 57.63,61.10 53.00,60.99
|
||||
40.50,60.68 31.12,50.64 32.19,38.00
|
||||
33.46,22.89 50.78,13.56 63.99,21.61
|
||||
71.65,26.28 73.81,33.55 74.00,42.00
|
||||
74.00,42.00 41.00,42.00 41.00,42.00
|
||||
43.79,50.19 51.44,55.78 60.00,51.93
|
||||
62.63,50.74 64.80,48.82 67.00,47.00 Z
|
||||
M 128.00,48.00
|
||||
C 130.26,50.82 133.06,53.63 137.00,53.64
|
||||
140.71,53.65 143.50,50.35 141.92,47.39
|
||||
139.34,42.55 126.19,43.12 125.11,32.00
|
||||
124.16,22.22 131.26,18.42 140.00,19.09
|
||||
142.99,19.32 147.38,20.30 148.89,23.22
|
||||
150.14,25.66 148.71,29.52 148.00,32.00
|
||||
145.29,30.13 141.32,26.45 138.02,26.45
|
||||
134.70,26.45 131.68,29.34 134.42,32.73
|
||||
137.84,36.97 147.42,36.60 150.30,45.01
|
||||
152.83,52.42 147.55,59.78 140.00,60.81
|
||||
133.40,61.71 129.67,59.91 124.00,57.00
|
||||
124.00,57.00 126.00,48.00 126.00,48.00
|
||||
126.00,48.00 128.00,48.00 128.00,48.00 Z
|
||||
M 65.00,36.00
|
||||
C 61.69,22.75 45.46,22.92 41.00,36.00
|
||||
41.00,36.00 65.00,36.00 65.00,36.00 Z
|
||||
M 168.00,43.00
|
||||
C 168.00,43.00 173.00,43.00 173.00,43.00
|
||||
173.00,43.00 174.00,55.00 174.00,55.00
|
||||
174.00,55.00 169.00,55.00 169.00,55.00
|
||||
169.00,55.00 168.00,43.00 168.00,43.00 Z
|
||||
M 176.00,44.00
|
||||
C 176.00,44.00 181.00,44.00 181.00,44.00
|
||||
181.00,44.00 180.00,56.00 180.00,56.00
|
||||
184.34,52.55 185.53,51.86 191.00,51.00
|
||||
189.46,58.20 185.88,59.92 179.00,61.00
|
||||
179.00,61.00 180.00,56.00 180.00,56.00
|
||||
180.00,56.00 175.00,56.00 175.00,56.00
|
||||
175.00,56.00 176.00,44.00 176.00,44.00 Z
|
||||
M 157.00,52.00
|
||||
C 162.95,52.30 166.12,52.81 168.00,59.00
|
||||
162.05,58.70 158.88,58.19 157.00,52.00 Z
|
||||
M 157.00,71.00
|
||||
C 158.46,64.21 161.53,63.02 168.00,62.00
|
||||
166.54,68.79 163.47,69.98 157.00,71.00 Z
|
||||
M 194.00,95.00
|
||||
C 191.87,99.14 187.49,102.17 184.42,96.85
|
||||
184.42,96.85 177.32,73.00 177.32,73.00
|
||||
176.88,70.29 176.58,65.71 179.31,64.06
|
||||
181.50,62.75 184.80,63.93 187.00,64.70
|
||||
190.72,66.00 205.24,73.30 207.69,75.63
|
||||
211.89,79.66 209.99,84.15 205.00,86.00
|
||||
206.84,89.66 210.65,98.44 202.96,98.55
|
||||
200.44,98.59 196.38,96.14 194.00,95.00 Z
|
||||
M 169.00,67.00
|
||||
C 169.00,67.00 175.00,68.00 175.00,68.00
|
||||
174.06,74.47 173.00,77.97 166.00,79.00
|
||||
165.10,73.74 167.15,71.88 169.00,67.00 Z
|
||||
M 54.00,126.00
|
||||
C 54.00,126.00 55.00,146.00 55.00,146.00
|
||||
55.00,146.00 55.00,188.00 55.00,188.00
|
||||
55.00,188.00 47.00,188.00 47.00,188.00
|
||||
47.00,179.60 47.91,156.72 46.00,150.00
|
||||
46.00,150.00 28.00,177.00 28.00,177.00
|
||||
28.00,177.00 26.00,177.00 26.00,177.00
|
||||
26.00,177.00 7.00,150.00 7.00,150.00
|
||||
7.00,150.00 7.00,188.00 7.00,188.00
|
||||
7.00,188.00 0.00,188.00 0.00,188.00
|
||||
0.00,188.00 0.00,127.00 0.00,127.00
|
||||
0.00,127.00 28.00,163.00 28.00,163.00
|
||||
28.00,163.00 54.00,126.00 54.00,126.00 Z
|
||||
M 200.00,128.00
|
||||
C 200.00,128.00 208.00,128.00 208.00,128.00
|
||||
208.00,128.00 208.00,146.00 208.00,146.00
|
||||
208.00,146.00 207.00,168.00 207.00,168.00
|
||||
207.00,168.00 200.00,168.00 200.00,168.00
|
||||
200.00,168.00 200.00,128.00 200.00,128.00 Z
|
||||
M 168.00,148.00
|
||||
C 168.00,135.23 166.96,134.12 176.00,134.00
|
||||
176.00,134.00 176.00,148.00 176.00,148.00
|
||||
176.00,148.00 186.00,148.00 186.00,148.00
|
||||
186.00,148.00 186.00,154.00 186.00,154.00
|
||||
186.00,154.00 176.00,154.00 176.00,154.00
|
||||
176.00,154.00 176.00,188.00 176.00,188.00
|
||||
176.00,188.00 168.00,188.00 168.00,188.00
|
||||
168.00,188.00 168.00,154.00 168.00,154.00
|
||||
168.00,154.00 159.00,154.00 159.00,154.00
|
||||
159.00,154.00 159.00,148.00 159.00,148.00
|
||||
159.00,148.00 168.00,148.00 168.00,148.00 Z
|
||||
M 101.00,175.00
|
||||
C 101.84,177.29 103.08,180.42 102.60,182.90
|
||||
101.45,188.75 91.63,189.10 87.00,188.99
|
||||
75.78,188.71 67.27,181.34 66.18,170.00
|
||||
64.92,157.00 73.96,147.01 87.00,147.01
|
||||
91.17,147.01 94.32,147.35 97.96,149.61
|
||||
105.59,154.35 107.61,161.57 108.00,170.00
|
||||
108.00,170.00 75.00,170.00 75.00,170.00
|
||||
77.78,178.15 85.46,183.82 93.99,179.93
|
||||
96.58,178.74 98.75,176.71 101.00,175.00 Z
|
||||
M 149.00,175.00
|
||||
C 149.32,177.26 150.50,181.85 149.68,183.79
|
||||
146.97,190.19 131.32,189.78 126.00,187.47
|
||||
117.33,183.71 113.20,175.15 113.76,166.00
|
||||
114.80,149.05 135.00,140.81 147.91,151.53
|
||||
154.02,156.60 154.93,162.57 155.00,170.00
|
||||
155.00,170.00 122.00,170.00 122.00,170.00
|
||||
125.38,177.40 131.25,183.06 140.00,180.35
|
||||
143.04,179.41 146.29,176.79 149.00,175.00 Z
|
||||
M 99.00,164.00
|
||||
C 95.66,150.80 78.81,151.05 75.00,164.00
|
||||
75.00,164.00 99.00,164.00 99.00,164.00 Z
|
||||
M 147.00,164.00
|
||||
C 140.75,150.34 126.34,151.31 122.00,164.00
|
||||
122.00,164.00 147.00,164.00 147.00,164.00 Z
|
||||
M 202.11,178.84
|
||||
C 210.20,178.30 210.19,186.71 205.85,188.38
|
||||
200.73,190.36 194.35,183.37 202.11,178.84 Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.1 KiB |
22
front/src/assets/logo2.svg
Normal file
22
front/src/assets/logo2.svg
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 250 250">
|
||||
<defs>
|
||||
<style>
|
||||
</style>
|
||||
</defs>
|
||||
<g id="Header">
|
||||
<path class="cls-2" d="M225.05,120.76c-2.74,0-4.79-.85-6.15-2.55-1.36-1.7-2.03-3.84-2.03-6.41s.73-4.71,2.2-6.41c1.46-1.7,3.48-2.55,6.04-2.55s4.61.73,6.15,2.2c1.54,1.47,2.31,3.62,2.31,6.47s-.73,5.11-2.2,6.77c-1.46,1.66-3.57,2.49-6.31,2.49ZM225.44,98.43c-.67,0-1.21-.54-1.21-1.21v-9.01c0-6.81-1.19-14.9-3.57-24.29-2.38-9.38-3.57-15.77-3.57-19.18s.86-5.86,2.58-7.36c1.72-1.5,3.82-2.26,6.31-2.26,5.56,0,8.34,3.21,8.34,9.62,0,3.72-1.28,10.21-3.84,19.48-2.56,9.26-3.84,17.3-3.84,24.11v8.89c0,.67-.54,1.21-1.21,1.21h0Z"/>
|
||||
<g>
|
||||
<path class="cls-2" d="M80.03,35.29h6.81v34.14h17.12v.9h-23.93v-35.04Z"/>
|
||||
<path class="cls-2" d="M104.36,57.82c0-7.41,5.71-13.02,13.37-13.02,6.21,0,11.21,3.55,11.21,8.91,0,.95-.15,1.8-.4,2.6h-17.12v.1c0,7.46,4.1,12.02,9.56,12.02,4.71,0,8.26-3.3,9.21-8.01h.95c-1.1,6.06-6.51,10.41-13.32,10.41-7.66,0-13.47-5.61-13.47-13.02ZM111.46,55.42h10.61c.35-1.05.55-2.15.55-3.2,0-3.4-2-6.41-4.91-6.41-3.4,0-6.01,4.31-6.26,9.61Z"/>
|
||||
<path class="cls-2" d="M134.89,62.58v-16.37h-3.3v-.9h3.5l5.61-7.76h.9v7.76h7.36v.9h-7.36v17.97c0,3.15,1.8,4.86,4.01,4.86s4-1.75,4-4.16c0-.7-.15-1.45-.5-2.2h.9c.4.9.5,1.6.5,2.2,0,3.5-3.2,5.96-7.36,5.96-4.76,0-8.26-3.2-8.26-8.26Z"/>
|
||||
<path class="cls-2" d="M152.96,49.26v-1.05c.65.45,1.65.75,2.65.75,3.5,0,5.46-3.5,5.46-6.36,0-.2,0-.5-.05-.8-.6,1.1-2,1.95-3.7,1.95-2.5,0-4.46-1.95-4.46-4.51s1.95-4.46,4.61-4.46c3.1,0,4.86,2.65,4.86,6.56,0,4.86-2.65,8.61-6.51,8.61-1,0-2.1-.25-2.85-.7Z"/>
|
||||
<path class="cls-2" d="M163.77,63.83c0-.8.15-1.65.45-2.45h.95c-.3.8-.45,1.65-.45,2.35,0,3.35,3.75,6.01,8.36,6.01,4.16,0,6.81-2.1,6.81-4.71,0-6.31-15.42-3.81-15.42-12.77,0-4.81,4.36-7.46,9.36-7.46,5.61,0,9.46,3.2,9.46,7.46h-.95c0-3.65-3.45-6.36-7.51-6.36-3.3,0-5.46,1.85-5.46,4,0,5.81,15.42,3.2,15.42,12.67,0,5.26-4.76,8.26-10.76,8.26s-10.26-3-10.26-7.01Z"/>
|
||||
<path class="cls-2" d="M80.03,84.03h7.01l11.01,26.73,11.31-26.73h6.81v35.04h-6.81v-32.34l-13.72,32.34h-.9l-13.72-32.49v32.49h-1v-35.04Z"/>
|
||||
<path class="cls-2" d="M120.97,106.56c0-7.41,5.71-13.02,13.37-13.02,6.21,0,11.21,3.55,11.21,8.91,0,.95-.15,1.8-.4,2.6h-17.12v.1c0,7.46,4.1,12.02,9.56,12.02,4.71,0,8.26-3.3,9.21-8.01h.95c-1.1,6.06-6.51,10.41-13.32,10.41-7.66,0-13.47-5.61-13.47-13.02ZM128.08,104.15h10.61c.35-1.05.55-2.15.55-3.2,0-3.4-2-6.41-4.91-6.41-3.4,0-6.01,4.31-6.26,9.61Z"/>
|
||||
<path class="cls-2" d="M149.56,106.56c0-7.41,5.71-13.02,13.37-13.02,6.21,0,11.21,3.55,11.21,8.91,0,.95-.15,1.8-.4,2.6h-17.12v.1c0,7.46,4.1,12.02,9.56,12.02,4.71,0,8.26-3.3,9.21-8.01h.95c-1.1,6.06-6.51,10.41-13.32,10.41-7.66,0-13.47-5.61-13.47-13.02ZM156.67,104.15h10.61c.35-1.05.55-2.15.55-3.2,0-3.4-2-6.41-4.91-6.41-3.4,0-6.01,4.31-6.26,9.61Z"/>
|
||||
<path class="cls-2" d="M180.09,111.31v-16.37h-3.3v-.9h3.5l5.61-7.76h.9v7.76h7.36v.9h-7.36v17.97c0,3.15,1.8,4.86,4.01,4.86s4-1.75,4-4.16c0-.7-.15-1.45-.5-2.2h.9c.4.9.5,1.6.5,2.2,0,3.5-3.2,5.96-7.36,5.96-4.76,0-8.26-3.2-8.26-8.26Z"/>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
48
front/src/assets/main.css
Normal file
48
front/src/assets/main.css
Normal file
@@ -0,0 +1,48 @@
|
||||
@import './base.css';
|
||||
|
||||
html, body, #app, .layout {
|
||||
margin: 0;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
body
|
||||
{
|
||||
background-color: white;
|
||||
font-size: var(--font-size);
|
||||
}
|
||||
|
||||
.layout
|
||||
{
|
||||
background: var(--background-color);
|
||||
}
|
||||
|
||||
.container
|
||||
{
|
||||
display: flex;
|
||||
padding: 0 1vw 3vh 1vw;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1501px) {
|
||||
.container
|
||||
{
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1500px) {
|
||||
.container {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.colored-text
|
||||
{
|
||||
color: var(--secondary-color);
|
||||
}
|
||||
|
||||
footer
|
||||
{
|
||||
position:absolute;
|
||||
bottom:0.5vw;
|
||||
}
|
||||
86
front/src/assets/template/base.css
Normal file
86
front/src/assets/template/base.css
Normal file
@@ -0,0 +1,86 @@
|
||||
/* color palette from <https://github.com/vuejs/theme> */
|
||||
:root {
|
||||
--vt-c-white: #ffffff;
|
||||
--vt-c-white-soft: #f8f8f8;
|
||||
--vt-c-white-mute: #f2f2f2;
|
||||
|
||||
--vt-c-black: #181818;
|
||||
--vt-c-black-soft: #222222;
|
||||
--vt-c-black-mute: #282828;
|
||||
|
||||
--vt-c-indigo: #2c3e50;
|
||||
|
||||
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
|
||||
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
|
||||
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
|
||||
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
|
||||
|
||||
--vt-c-text-light-1: var(--vt-c-indigo);
|
||||
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
|
||||
--vt-c-text-dark-1: var(--vt-c-white);
|
||||
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
|
||||
}
|
||||
|
||||
/* semantic color variables for this project */
|
||||
:root {
|
||||
--color-background: var(--vt-c-white);
|
||||
--color-background-soft: var(--vt-c-white-soft);
|
||||
--color-background-mute: var(--vt-c-white-mute);
|
||||
|
||||
--color-border: var(--vt-c-divider-light-2);
|
||||
--color-border-hover: var(--vt-c-divider-light-1);
|
||||
|
||||
--color-heading: var(--vt-c-text-light-1);
|
||||
--color-text: var(--vt-c-text-light-1);
|
||||
|
||||
--section-gap: 160px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--color-background: var(--vt-c-black);
|
||||
--color-background-soft: var(--vt-c-black-soft);
|
||||
--color-background-mute: var(--vt-c-black-mute);
|
||||
|
||||
--color-border: var(--vt-c-divider-dark-2);
|
||||
--color-border-hover: var(--vt-c-divider-dark-1);
|
||||
|
||||
--color-heading: var(--vt-c-text-dark-1);
|
||||
--color-text: var(--vt-c-text-dark-2);
|
||||
}
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100vh;
|
||||
color: var(--color-text);
|
||||
background: var(--color-background);
|
||||
transition:
|
||||
color 0.5s,
|
||||
background-color 0.5s;
|
||||
line-height: 1.6;
|
||||
font-family:
|
||||
Inter,
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
'Segoe UI',
|
||||
Roboto,
|
||||
Oxygen,
|
||||
Ubuntu,
|
||||
Cantarell,
|
||||
'Fira Sans',
|
||||
'Droid Sans',
|
||||
'Helvetica Neue',
|
||||
sans-serif;
|
||||
font-size: 15px;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
35
front/src/assets/template/main.css
Normal file
35
front/src/assets/template/main.css
Normal file
@@ -0,0 +1,35 @@
|
||||
@import './base.css';
|
||||
|
||||
#app {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
a,
|
||||
.green {
|
||||
text-decoration: none;
|
||||
color: hsla(160, 100%, 37%, 1);
|
||||
transition: 0.4s;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
a:hover {
|
||||
background-color: hsla(160, 100%, 37%, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
body {
|
||||
display: flex;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
#app {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
}
|
||||
176
front/src/components/Calendar.vue
Normal file
176
front/src/components/Calendar.vue
Normal file
@@ -0,0 +1,176 @@
|
||||
<script setup lang="ts">
|
||||
import ArrowRight from "@/assets/arrow-right.svg"
|
||||
import ArrowLeft from "@/assets/arrow-left.svg";
|
||||
import {ref, onMounted, watch} from "vue";
|
||||
import { datePickerStore } from "@/stores/CalendarStore.ts";
|
||||
import { Calendar } from "@/models/Calendar.ts";
|
||||
import router from "@/router";
|
||||
|
||||
const calendar = new Calendar();
|
||||
const datePicker = datePickerStore();
|
||||
const monthYear = ref("");
|
||||
const dates = ref([] as (number | null)[]);
|
||||
const selectedDays = ref(new Map<string, Date>());
|
||||
|
||||
onMounted(() => {
|
||||
setupCalendar();
|
||||
})
|
||||
|
||||
watch(selectedDays, (newValue) => {
|
||||
let dates = Array.from(newValue.values())
|
||||
datePicker.update(dates);
|
||||
}, { deep: true });
|
||||
|
||||
function selectDay(event : Event, day : number | null){
|
||||
if(!(event.target instanceof HTMLElement) || day == null) return;
|
||||
calendar.setDay(day);
|
||||
toggleSelectedDay(event.target.id, calendar.getDate());
|
||||
highlightSelectedDay(event.target);
|
||||
}
|
||||
|
||||
function toggleSelectedDay(id : string, date : Date) : void {
|
||||
if(selectedDays.value.has(id)){
|
||||
selectedDays.value.delete(id);
|
||||
} else {
|
||||
selectedDays.value.set(id, date);
|
||||
}
|
||||
}
|
||||
|
||||
function highlightSelectedDay(element : HTMLElement){
|
||||
element.classList.toggle("item-selected");
|
||||
}
|
||||
|
||||
function setupCalendar(){
|
||||
dates.value = calendar.datesOfCurrentMonth();
|
||||
updateMonth();
|
||||
}
|
||||
|
||||
function clickPrev(){
|
||||
dates.value = calendar.datesOfPrevMonth();
|
||||
updateMonth();
|
||||
}
|
||||
|
||||
function clickNext(){
|
||||
dates.value = calendar.datesOfNextMonth();
|
||||
updateMonth();
|
||||
}
|
||||
|
||||
function updateMonth(){
|
||||
monthYear.value = calendar.getMonthYear();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="calendar-container">
|
||||
<div class="month-picker">
|
||||
<div>{{ monthYear }}</div>
|
||||
<div class="arrows">
|
||||
<div @click="clickPrev" class="prevMonth"><ArrowLeft class="arrow-left" /></div>
|
||||
<div @click="clickNext" class="nextMonth"><ArrowRight class="arrow-right" /></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="day-names">
|
||||
<div>M</div>
|
||||
<div>T</div>
|
||||
<div>W</div>
|
||||
<div>T</div>
|
||||
<div>F</div>
|
||||
<div>S</div>
|
||||
<div>S</div>
|
||||
</div>
|
||||
|
||||
<!--Elements are not recreated ? Does only the id change ? -->
|
||||
<!--Keep track of all selected ids and update view when month is update ? -->
|
||||
<div class="day-picker">
|
||||
<div v-on:click="selectDay($event, day)"
|
||||
v-for ="(day) in dates"
|
||||
:id ="day !== null ? `${day}-${monthYear}` : undefined"
|
||||
:class ="{
|
||||
'item': day !== null,
|
||||
'item-selected' : selectedDays.has(`${day}-${monthYear}`)
|
||||
}">
|
||||
{{ day }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.calendar-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
border: solid 2px;
|
||||
border-radius: var(--radius);
|
||||
padding: 0 20px 20px 20px;
|
||||
}
|
||||
|
||||
.month-picker, .day-picker, .day-names {
|
||||
justify-items: center;
|
||||
}
|
||||
|
||||
.month-picker {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom:solid 1px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.arrows {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.arrow-left, .arrow-right {
|
||||
width: 30px;
|
||||
border-radius: var(--radius);
|
||||
padding: 5px 7px 5px 7px;
|
||||
}
|
||||
|
||||
.arrow-left:hover, .arrow-right:hover {
|
||||
transform: scale(1.2);
|
||||
background-color: rgb(239,239,239);
|
||||
}
|
||||
|
||||
.day-picker, .day-names {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, 1fr);
|
||||
row-gap: 20px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.day-picker {
|
||||
grid-template-rows: repeat(6, 1fr);
|
||||
}
|
||||
|
||||
.day-names {
|
||||
padding: 20px 0 20px 0;
|
||||
}
|
||||
|
||||
.item
|
||||
{
|
||||
text-align: center;
|
||||
width: 90%;
|
||||
min-width: 30px;
|
||||
height: 100%;
|
||||
border: solid 1px;
|
||||
border-radius: 5px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.item-selected
|
||||
{
|
||||
background-color: var(--secondary-color);
|
||||
}
|
||||
|
||||
.item:hover
|
||||
{
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
</style>
|
||||
34
front/src/components/NavLink.vue
Normal file
34
front/src/components/NavLink.vue
Normal file
@@ -0,0 +1,34 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
const props = defineProps<{
|
||||
path: string;
|
||||
description: string;
|
||||
}>();
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<router-link :to=path><div class="button">{{ description }}</div></router-link>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.button {
|
||||
color: var(--primary-color);
|
||||
text-align: center;
|
||||
align-content: center;
|
||||
|
||||
border-radius: var(--radius);
|
||||
background-color: var(--secondary-color);
|
||||
word-break: break-word;
|
||||
min-height: 7vh;
|
||||
}
|
||||
|
||||
.button:hover
|
||||
{
|
||||
transform: scale(1.1);
|
||||
background-color: var(--header-color);
|
||||
filter: drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.25));
|
||||
}
|
||||
|
||||
</style>
|
||||
42
front/src/components/TextBlock.vue
Normal file
42
front/src/components/TextBlock.vue
Normal file
@@ -0,0 +1,42 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="text-block">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.text-block {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
/*justify-content: start;*/
|
||||
|
||||
word-break: break-word;
|
||||
height: fit-content;
|
||||
|
||||
border-radius: var(--radius);
|
||||
border-left: solid 4px;
|
||||
background: rgb(239, 239, 239);
|
||||
}
|
||||
|
||||
|
||||
@media screen and (max-width: 1501px) {
|
||||
.text-block {
|
||||
padding: 5px 15px 5px 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1500px) {
|
||||
.text-block {
|
||||
padding: 10px 30px 10px 30px;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
10
front/src/helpers/ArrayHelper.ts
Normal file
10
front/src/helpers/ArrayHelper.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export abstract class ArrayHelper {
|
||||
|
||||
public static contains(array : any[], element : any) : boolean {
|
||||
return array.indexOf(element) > -1;
|
||||
}
|
||||
|
||||
public static indexOf(array : any[], element : any) : number {
|
||||
return array.indexOf(element);
|
||||
}
|
||||
}
|
||||
95
front/src/layouts/LayoutDefault.vue
Normal file
95
front/src/layouts/LayoutDefault.vue
Normal file
@@ -0,0 +1,95 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import NavLink from "@/components/NavLink.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="layout">
|
||||
|
||||
<nav class="nav">
|
||||
<p>Let's<br>Meet</p>
|
||||
<div class="nav-actions-group">
|
||||
<NavLink path="/" description="Home"></NavLink>
|
||||
<NavLink path="/login" description="Log in"></NavLink>
|
||||
<NavLink path="/about" description="About"></NavLink>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="main">
|
||||
<slot/>
|
||||
</main>
|
||||
|
||||
<!--<footer class="footer">Blank footer</footer>-->
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.layout
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
nav {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
min-height: 10vh;
|
||||
border-bottom: 1px solid;
|
||||
border-radius: var(--radius);
|
||||
background-color: var(--header-color);
|
||||
filter: drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.25));
|
||||
padding: 0 3vw 0 2vw;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
nav p {
|
||||
font-size: calc(var(--font-size) * 1.1);
|
||||
margin: 4px 0 4px 0;
|
||||
}
|
||||
|
||||
.nav-actions-group {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 1vw;
|
||||
}
|
||||
|
||||
::v-deep(nav .button) {
|
||||
font-size: calc(var(--font-size) * 0.8);
|
||||
background-color: var(--header-color);
|
||||
border: solid 2px;
|
||||
height: fit-content;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 951px) {
|
||||
|
||||
::v-deep(nav .button) {
|
||||
width: 5vw;
|
||||
|
||||
min-width: 5vw;
|
||||
min-height: 4vh;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 950px) {
|
||||
|
||||
::v-deep(nav .button) {
|
||||
width: 7vw;
|
||||
|
||||
min-width: 60px;
|
||||
min-height: 3vh;
|
||||
}
|
||||
}
|
||||
|
||||
.main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
</style>
|
||||
14
front/src/main.ts
Normal file
14
front/src/main.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import './assets/main.css'
|
||||
|
||||
import {createApp } from 'vue'
|
||||
import { createPinia } from 'pinia'
|
||||
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(createPinia())
|
||||
app.use(router)
|
||||
|
||||
app.mount('#app')
|
||||
82
front/src/models/Calendar.ts
Normal file
82
front/src/models/Calendar.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
export class Calendar {
|
||||
|
||||
private readonly monthsName : string[] = [
|
||||
"January",
|
||||
"February",
|
||||
"March",
|
||||
"April",
|
||||
"May",
|
||||
"June",
|
||||
"July",
|
||||
"August",
|
||||
"September",
|
||||
"October",
|
||||
"November",
|
||||
"December"
|
||||
];
|
||||
private year : number;
|
||||
private month : number;
|
||||
private day : number;
|
||||
|
||||
public constructor() {
|
||||
let date = new Date();
|
||||
this.year = date.getFullYear();
|
||||
this.month = date.getMonth();
|
||||
this.day = date.getDay();
|
||||
}
|
||||
|
||||
public getDate(): Date {
|
||||
return new Date(this.year, this.month, this.day);
|
||||
}
|
||||
|
||||
public getMonthYear(){
|
||||
return `${this.monthsName[this.month]} ${this.year}`;
|
||||
}
|
||||
|
||||
public setDay(day : number) { this.day = day; }
|
||||
|
||||
public datesOfCurrentMonth(){
|
||||
return this.datesOf();
|
||||
}
|
||||
|
||||
public datesOfNextMonth(){
|
||||
|
||||
if(this.month+1 > 11){
|
||||
this.year += 1;
|
||||
this.month = 0;
|
||||
} else {
|
||||
this.month++;
|
||||
}
|
||||
|
||||
return this.datesOf();
|
||||
}
|
||||
|
||||
public datesOfPrevMonth(){
|
||||
if(this.month-1 < 0){
|
||||
this.year -= 1;
|
||||
this.month = 11;
|
||||
} else {
|
||||
this.month--;
|
||||
}
|
||||
return this.datesOf();
|
||||
}
|
||||
|
||||
private datesOf() {
|
||||
let dates = [];
|
||||
let daysInMonth = new Date(this.year, this.month+1, 0).getDate();
|
||||
let firstDayOfMonth = (new Date(this.year, this.month, 1).getDay() + 6) % 7; // Adjust to start from Monday
|
||||
|
||||
for (let i = 0; i < firstDayOfMonth; i++) {
|
||||
dates.push(null);
|
||||
}
|
||||
|
||||
for (let day = 1; day <= daysInMonth; day++) {
|
||||
dates.push(day);
|
||||
}
|
||||
return dates;
|
||||
}
|
||||
|
||||
public toString(){
|
||||
return `${this.day}-${this.monthsName[this.month]}-${this.year}`
|
||||
}
|
||||
}
|
||||
12
front/src/models/TimeStamp.ts
Normal file
12
front/src/models/TimeStamp.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export class TimeStamp {
|
||||
|
||||
private readonly value : number;
|
||||
|
||||
public constructor(date : Date) {
|
||||
this.value = date.getTime();
|
||||
}
|
||||
|
||||
public getValue() : number{
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
20
front/src/router/index.ts
Normal file
20
front/src/router/index.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import HomeView from '../views/HomeView.vue'
|
||||
import AboutView from '../views/AboutView.vue'
|
||||
import CreateView from "../views/CreateView.vue";
|
||||
import JoinView from "../views/JoinView.vue";
|
||||
import ErrorView from '../views/ErrorView.vue';
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
{ path: '/', name: 'home', component: HomeView},
|
||||
{ path: '/about', name: 'about', component: AboutView},
|
||||
{ path: '/create', name: 'create', component: CreateView},
|
||||
{ path: '/join', name: 'join', component: JoinView},
|
||||
{ path: '/error', name: 'error', component: ErrorView},
|
||||
{ path: '/:pathMatch(.*)*', component: ErrorView }
|
||||
]
|
||||
})
|
||||
|
||||
export default router
|
||||
22
front/src/stores/CalendarStore.ts
Normal file
22
front/src/stores/CalendarStore.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import {TimeStamp} from "@/models/TimeStamp.ts";
|
||||
|
||||
export const datePickerStore = defineStore('datePicker', {
|
||||
state: () => {
|
||||
return { dates: [] as TimeStamp[] }
|
||||
},
|
||||
getters: {
|
||||
value: (state) : TimeStamp[] => state.dates as TimeStamp[],
|
||||
},
|
||||
actions: {
|
||||
getValue(){
|
||||
return this.dates;
|
||||
},
|
||||
update(dates : Date[]) : void {
|
||||
this.dates = dates.map(date => new TimeStamp(date));
|
||||
},
|
||||
clear() : void {
|
||||
this.dates = [] as TimeStamp[];
|
||||
},
|
||||
},
|
||||
})
|
||||
28
front/src/views/AboutView.vue
Normal file
28
front/src/views/AboutView.vue
Normal file
@@ -0,0 +1,28 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import TextBlock from "@/components/TextBlock.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
<TextBlock>
|
||||
<h1>About</h1>
|
||||
<p>
|
||||
Inspired by <a href="https://when2meet.com">when2meet</a>, Let's meet is a free and open-source
|
||||
app that allows you and your friends to find a date to meet. From now on, there is no need to spend
|
||||
hours and hours trying to find a suitable day for everyone.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Developed and hosted by Naaturel<br>
|
||||
Check my links out !<br>
|
||||
<a href="https://github.com/">Github</a><br>
|
||||
<a href="https://bsky.app/profile/naaturel.be">Blue Sky</a>
|
||||
</p>
|
||||
</TextBlock>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
66
front/src/views/CreateView.vue
Normal file
66
front/src/views/CreateView.vue
Normal file
@@ -0,0 +1,66 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import Calendar from "@/components/Calendar.vue";
|
||||
import TextBlock from "@/components/TextBlock.vue";
|
||||
import NavLink from "@/components/NavLink.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
<div class="container">
|
||||
<TextBlock class="title">
|
||||
<h1>Create an <span class="colored-text">event</span></h1>
|
||||
</TextBlock>
|
||||
<div class="event-form">
|
||||
<Calendar class="calendar"/>
|
||||
<NavLink path="/create" description="Create" class="create-button"></NavLink>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.container
|
||||
{
|
||||
width: 80%;
|
||||
gap: 10vw;
|
||||
}
|
||||
|
||||
.event-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 45%;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
/* MEDIA QUERIES */
|
||||
@media screen and (min-width: 1501px) {
|
||||
|
||||
.title {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.title h1
|
||||
{
|
||||
font-size: 4rem;
|
||||
}
|
||||
|
||||
.calendar {
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1500px) {
|
||||
|
||||
.title, .event-form {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.title {
|
||||
height: fit-content;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
22
front/src/views/ErrorView.vue
Normal file
22
front/src/views/ErrorView.vue
Normal file
@@ -0,0 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import TextBlock from "@/components/TextBlock.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<TextBlock>
|
||||
<h1>Oopsie</h1>
|
||||
<p>Something went wrong</p>
|
||||
</TextBlock>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.text-block {
|
||||
border-left: solid 4px red;
|
||||
width: 35%;
|
||||
height: 35%;
|
||||
}
|
||||
|
||||
</style>
|
||||
151
front/src/views/HomeView.vue
Normal file
151
front/src/views/HomeView.vue
Normal file
@@ -0,0 +1,151 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import NavLink from "@/components/NavLink.vue";
|
||||
import TextBlock from "@/components/TextBlock.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
<div class="container">
|
||||
<TextBlock class="introduction">
|
||||
<h1>Welcome !</h1>
|
||||
<p>
|
||||
This website is currently under <span class="colored-text">development</span> and might look ugly as fuck
|
||||
bla bla bla I'm just writting things nobody will read to fill the space and see how it looks.
|
||||
</p>
|
||||
<p>
|
||||
Yes I know i could have use
|
||||
a Lorem Ipsum but it seems more natural with words everyone can understand
|
||||
</p>
|
||||
</TextBlock>
|
||||
|
||||
<div class="actions-group">
|
||||
<h1>Meet up <span class="colored-text">now</span> !</h1>
|
||||
<NavLink path="/create" description="Create" class="button"></NavLink>
|
||||
<NavLink path="/join" description="Join" class="button"></NavLink>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
.container, .actions-group {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 80%;
|
||||
gap: 10vw;
|
||||
}
|
||||
|
||||
.introduction p
|
||||
{
|
||||
width: 80%;
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
.actions-group {
|
||||
flex-direction: column;
|
||||
min-width: 250px;
|
||||
}
|
||||
|
||||
.actions-group {
|
||||
justify-content: center;
|
||||
gap: 4vh;
|
||||
height: fit-content;
|
||||
border-radius: var(--radius);
|
||||
filter: drop-shadow(0px 0px 0px rgba(0, 0, 0, 0.0));
|
||||
margin-bottom: 5vh;
|
||||
}
|
||||
|
||||
.actions-group h1
|
||||
{
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.actions-group::before,
|
||||
.actions-group::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 5%;
|
||||
height: 15%;
|
||||
border: 4px solid black;
|
||||
}
|
||||
|
||||
.actions-group::before {
|
||||
top: 0;
|
||||
left: 0;
|
||||
border-radius: var(--radius);
|
||||
border-right: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.actions-group::after {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
border-radius: var(--radius);
|
||||
border-left: none;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
/* MEDIA QUERIES */
|
||||
@media screen and (min-width: 1501px) {
|
||||
|
||||
.introduction {
|
||||
padding: 0 0 1vw 0;
|
||||
width: 50%;
|
||||
min-height: 40vh;
|
||||
}
|
||||
|
||||
.actions-group {
|
||||
width: 35%;
|
||||
min-height: 40vh;
|
||||
}
|
||||
|
||||
.introduction h1
|
||||
{
|
||||
font-size: 4rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1500px) {
|
||||
|
||||
.introduction, .actions-group {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.introduction {
|
||||
min-height: 25vh;
|
||||
}
|
||||
|
||||
.actions-group {
|
||||
min-height: 40vh;
|
||||
}
|
||||
|
||||
.introduction h1
|
||||
{
|
||||
font-size: 3rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 801px) {
|
||||
.button {
|
||||
width: 15vw;
|
||||
min-width: 15vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px) {
|
||||
.button {
|
||||
width: 50vw;
|
||||
min-width: 50vw;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
</style>
|
||||
24
front/src/views/JoinView.vue
Normal file
24
front/src/views/JoinView.vue
Normal file
@@ -0,0 +1,24 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import TextBlock from "@/components/TextBlock.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
<TextBlock>
|
||||
<h1>Join an event</h1>
|
||||
<p>
|
||||
This website is currently under <span class="colored-text">development</span> and might look ugly as fuck
|
||||
bla bla bla I'm just writing things nobody will read to fill the space and see how it looks.
|
||||
</p>
|
||||
<p>
|
||||
Yes I know i could have use
|
||||
a Lorem Ipsum but it seems more natural with words everyone can understand
|
||||
</p>
|
||||
</TextBlock>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
12
front/tsconfig.app.json
Normal file
12
front/tsconfig.app.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
||||
"exclude": ["src/**/__tests__/*"],
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
14
front/tsconfig.json
Normal file
14
front/tsconfig.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.vitest.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
19
front/tsconfig.node.json
Normal file
19
front/tsconfig.node.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "@tsconfig/node22/tsconfig.json",
|
||||
"include": [
|
||||
"vite.config.*",
|
||||
"vitest.config.*",
|
||||
"cypress.config.*",
|
||||
"nightwatch.conf.*",
|
||||
"playwright.config.*",
|
||||
"eslint.config.*"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"noEmit": true,
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"types": ["node"]
|
||||
}
|
||||
}
|
||||
11
front/tsconfig.vitest.json
Normal file
11
front/tsconfig.vitest.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "./tsconfig.app.json",
|
||||
"include": ["src/**/__tests__/*", "env.d.ts"],
|
||||
"exclude": [],
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.vitest.tsbuildinfo",
|
||||
|
||||
"lib": [],
|
||||
"types": ["node", "jsdom"]
|
||||
}
|
||||
}
|
||||
13
front/vite-plugin-middleware.ts
Normal file
13
front/vite-plugin-middleware.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Plugin } from "vite";
|
||||
|
||||
export default function requestLogger(): Plugin {
|
||||
return {
|
||||
name: "request-logger",
|
||||
configureServer(server) {
|
||||
server.middlewares.use((req, res, next) => {
|
||||
console.log("Middleware triggered:", req.url);
|
||||
next();
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
25
front/vite.config.ts
Normal file
25
front/vite.config.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { fileURLToPath, URL } from 'node:url'
|
||||
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import vueJsx from '@vitejs/plugin-vue-jsx'
|
||||
import vueDevTools from 'vite-plugin-vue-devtools'
|
||||
import svgLoader from 'vite-svg-loader';
|
||||
import requestLogger from "./vite-plugin-middleware";
|
||||
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
vueJsx(),
|
||||
vueDevTools(),
|
||||
svgLoader(),
|
||||
//requestLogger()
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||
},
|
||||
},
|
||||
})
|
||||
14
front/vitest.config.ts
Normal file
14
front/vitest.config.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { mergeConfig, defineConfig, configDefaults } from 'vitest/config'
|
||||
import viteConfig from './vite.config'
|
||||
|
||||
export default mergeConfig(
|
||||
viteConfig,
|
||||
defineConfig({
|
||||
test: {
|
||||
environment: 'jsdom',
|
||||
exclude: [...configDefaults.exclude, 'e2e/**'],
|
||||
root: fileURLToPath(new URL('./', import.meta.url)),
|
||||
},
|
||||
}),
|
||||
)
|
||||
Reference in New Issue
Block a user