Init with default theme

This commit is contained in:
Jérémy Munsch 2023-12-18 18:23:42 +01:00
parent acc2e4cab8
commit 10697cbe67
No known key found for this signature in database
GPG key ID: 18361AF3BFEC0FEC
146 changed files with 4894 additions and 90 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
workspace.code-workspace
.vscode
auth.json

View file

@ -1,92 +1,5 @@
# Chandleur 2024
# Default Theme
## ! Ce projet ne doit pas être monté directement dans GGW
## Getting started
To make it easy for you to get started with GitLab, here's a list of recommended next steps.
Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
## Add your files
- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
```
cd existing_repo
git remote add origin https://lab.s-web.fr/ldc-web/projets/gen-game-web-themes/regalette/chandleur/chandleur-2024.git
git branch -M main
git push -uf origin main
```
## Integrate with your tools
- [ ] [Set up project integrations](https://lab.s-web.fr/ldc-web/projets/gen-game-web-themes/regalette/chandleur/chandleur-2024/-/settings/integrations)
## Collaborate with your team
- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
- [ ] [Automatically merge when pipeline succeeds](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
## Test and Deploy
Use the built-in continuous integration in GitLab.
- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
***
# Editing this README
When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template.
## Suggestions for a good README
Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
## Name
Choose a self-explaining name for your project.
## Description
Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
## Badges
On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
## Visuals
Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
## Installation
Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
## Usage
Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
## Support
Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
## Roadmap
If you have ideas for releases in the future, it is a good idea to list them in the README.
## Contributing
State if you are open to contributions and what your requirements are for accepting them.
For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
## Authors and acknowledgment
Show your appreciation to those who have contributed to the project.
## License
For open source projects, say how it is licensed.
## Project status
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
## Theme par défaut de Gen Game Web

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
assets/images/arrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

BIN
assets/images/br-1-euro.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
assets/images/br.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
assets/images/connect.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View file

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<g>
<path d="M452,0H60C26.916,0,0,26.916,0,60v392c0,33.084,26.916,60,60,60h392c33.084,0,60-26.916,60-60V60
C512,26.916,485.084,0,452,0z M472,452c0,11.028-8.972,20-20,20H338V309h61.79L410,247h-72v-43c0-16.975,13.025-30,30-30h41v-62
h-41c-50.923,0-91.978,41.25-91.978,92.174V247H216v62h60.022v163H60c-11.028,0-20-8.972-20-20V60c0-11.028,8.972-20,20-20h392
c11.028,0,20,8.972,20,20V452z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 909 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
assets/images/grattage.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

BIN
assets/images/home_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 521 KiB

View file

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<g>
<path d="M363.273,0H148.728C66.719,0,0,66.719,0,148.728v214.544C0,445.281,66.719,512,148.728,512h214.544
C445.281,512,512,445.281,512,363.273V148.728C512,66.719,445.281,0,363.273,0z M472,363.272C472,423.225,423.225,472,363.273,472
H148.728C88.775,472,40,423.225,40,363.273V148.728C40,88.775,88.775,40,148.728,40h214.544C423.225,40,472,88.775,472,148.728
V363.272z"/>
</g>
</g>
<g>
<g>
<path d="M256,118c-76.094,0-138,61.906-138,138s61.906,138,138,138s138-61.906,138-138S332.094,118,256,118z M256,354
c-54.037,0-98-43.963-98-98s43.963-98,98-98s98,43.963,98,98S310.037,354,256,354z"/>
</g>
</g>
<g>
<g>
<circle cx="396" cy="116" r="20"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
assets/images/large_br.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 KiB

BIN
assets/images/logo-br.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
assets/images/logo-kart.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

BIN
assets/images/logo-tv.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

BIN
assets/images/pastille.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
assets/images/view-br.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/mstile-150x150.png"/>
<TileColor>#2b5797</TileColor>
</tile>
</msapplication>
</browserconfig>

BIN
favicon/favicon-16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 963 B

BIN
favicon/favicon-32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
favicon/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
favicon/mstile-150x150.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

View file

@ -0,0 +1,109 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="680.000000pt" height="680.000000pt" viewBox="0 0 680.000000 680.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.14, written by Peter Selinger 2001-2017
</metadata>
<g transform="translate(0.000000,680.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M3378 6575 c-2 -1 -61 -5 -133 -9 -161 -7 -208 -12 -365 -38 -448
-73 -906 -257 -1278 -515 -247 -171 -495 -397 -647 -588 -22 -27 -43 -52 -46
-55 -4 -3 -46 -59 -94 -124 -239 -329 -418 -714 -514 -1106 -16 -69 -32 -136
-35 -150 -26 -146 -41 -260 -51 -385 -5 -67 -6 -403 -1 -450 2 -16 7 -65 10
-107 4 -43 9 -88 11 -100 2 -13 9 -54 15 -93 46 -294 145 -604 285 -890 71
-143 181 -331 248 -423 51 -69 141 -187 147 -192 3 -3 29 -34 59 -70 64 -76
250 -263 334 -335 290 -248 669 -467 1019 -590 77 -27 256 -81 298 -89 14 -3
34 -7 45 -10 59 -15 231 -46 282 -52 32 -3 61 -8 64 -10 37 -23 711 -22 749 1
3 2 33 6 68 9 34 4 119 18 189 32 1118 222 2042 1038 2407 2128 37 110 93 325
110 426 14 84 17 101 35 230 17 119 11 630 -9 770 -127 904 -598 1679 -1340
2205 -429 304 -894 479 -1485 560 -22 3 -107 8 -190 11 -82 3 -158 7 -167 8
-9 2 -18 3 -20 1z m-74 -317 c0 -54 -2 -99 -5 -102 -2 -2 -49 -6 -104 -10 -55
-3 -115 -8 -132 -11 -18 -3 -45 -7 -60 -9 -95 -13 -287 -55 -358 -76 -543
-168 -959 -431 -1315 -831 -111 -125 -200 -240 -245 -317 -5 -9 -12 -19 -15
-22 -15 -13 -123 -206 -167 -295 -152 -311 -247 -665 -269 -1000 -4 -55 -8
-102 -10 -104 -2 -2 -48 -4 -101 -5 l-98 0 1 59 c1 75 16 236 30 315 2 14 7
41 10 60 28 173 122 480 206 668 99 223 256 484 389 647 150 183 379 414 481
483 13 9 25 18 28 22 13 15 156 115 250 175 139 88 386 211 541 267 114 42
308 101 369 113 14 3 70 13 125 24 108 21 155 28 255 37 36 4 66 7 67 8 1 1
30 1 65 1 l63 0 -1 -97z m431 86 c28 -2 61 -7 75 -9 14 -3 41 -7 60 -10 427
-66 835 -225 1199 -469 58 -39 113 -76 121 -83 8 -7 31 -25 51 -40 103 -81
146 -120 279 -253 171 -171 247 -263 378 -460 259 -388 428 -848 477 -1295 4
-33 8 -71 10 -83 8 -46 8 -152 1 -159 -10 -10 -187 -10 -193 1 -3 4 -7 31 -8
60 -7 129 -14 180 -61 439 -3 15 -21 81 -39 147 -215 753 -732 1376 -1434
1730 -240 121 -542 221 -771 256 -19 2 -46 7 -60 9 -78 14 -168 22 -257 24
l-53 1 0 106 0 106 88 -6 c48 -4 110 -9 137 -12z m-180 -398 c500 -20 1018
-215 1444 -543 128 -99 364 -340 467 -478 295 -394 469 -844 511 -1320 9 -109
9 -361 0 -468 -19 -215 -92 -526 -162 -692 -60 -145 -96 -221 -147 -313 -349
-628 -937 -1084 -1622 -1258 -110 -28 -181 -43 -241 -50 -22 -3 -47 -7 -55 -9
-67 -18 -427 -26 -575 -12 -400 38 -739 150 -1094 358 -233 138 -502 372 -682
594 -269 333 -461 755 -533 1172 -14 79 -19 118 -31 243 -5 50 -5 358 0 405 2
22 7 65 10 95 3 30 7 64 9 75 2 11 7 40 11 65 18 112 24 135 62 268 149 519
449 969 878 1316 300 242 757 454 1105 511 19 3 58 10 85 15 85 16 125 20 260
26 72 4 131 8 133 9 2 2 11 1 20 -1 9 -1 76 -5 147 -8z m-2924 -2733 c0 -32 2
-67 4 -78 1 -11 6 -51 9 -90 19 -203 114 -566 191 -733 14 -29 25 -55 25 -58
0 -4 51 -107 115 -234 39 -75 185 -290 270 -395 102 -127 277 -304 385 -390
41 -33 77 -62 80 -65 3 -3 30 -23 60 -45 184 -135 418 -263 639 -350 139 -54
393 -125 501 -140 14 -2 52 -8 85 -14 60 -10 129 -18 239 -26 32 -2 62 -8 65
-14 9 -14 7 -173 -2 -188 -4 -7 -13 -10 -20 -8 -7 2 -50 6 -97 9 -74 4 -267
28 -325 40 -289 60 -494 127 -740 245 -212 102 -409 226 -600 379 -100 81
-350 332 -429 432 -37 47 -73 92 -79 100 -103 130 -272 425 -352 615 -81 193
-159 457 -190 640 -3 17 -7 39 -9 50 -2 11 -7 49 -11 85 -4 36 -9 73 -10 82
-2 9 -7 60 -10 112 l-7 96 106 0 106 0 1 -57z m5763 27 c-4 -63 -16 -203 -19
-218 -1 -9 -6 -42 -9 -72 -9 -81 -42 -246 -66 -330 -115 -414 -268 -728 -513
-1055 -141 -188 -367 -417 -532 -540 -22 -16 -42 -33 -45 -36 -13 -16 -235
-162 -323 -213 -237 -136 -574 -269 -790 -312 -10 -2 -26 -5 -35 -8 -9 -3 -30
-8 -47 -11 -31 -5 -62 -11 -105 -20 -14 -3 -41 -7 -60 -9 -19 -3 -55 -7 -80
-10 -66 -9 -127 -14 -195 -17 l-60 -3 -3 102 c-3 100 -2 102 20 103 54 2 241
22 318 34 560 86 1124 376 1526 787 173 175 294 329 407 514 54 88 177 324
177 338 0 3 9 25 20 49 81 172 177 554 196 780 6 71 12 146 13 165 1 10 26 12
104 10 102 -3 102 -3 101 -28z"/>
<path d="M5081 3581 c-12 -7 -14 -48 -15 -210 l-1 -200 40 -7 c142 -27 216 21
218 139 1 67 -18 113 -56 137 -27 16 -82 22 -111 10 -24 -9 -24 -8 -22 66 1
68 -1 74 -19 74 -11 0 -26 -4 -34 -9z m148 -198 c26 -22 36 -86 20 -125 -12
-30 -66 -54 -97 -44 -16 5 -19 18 -19 87 -1 74 0 81 20 89 34 13 53 12 76 -7z"/>
<path d="M1619 3543 c-81 -24 -119 -75 -127 -169 -13 -169 94 -249 281 -208
l27 6 0 92 0 93 -35 1 -35 1 0 -68 c0 -76 -4 -81 -59 -75 -77 9 -116 68 -106
157 6 59 26 94 61 107 34 13 101 13 126 -1 23 -12 38 1 38 34 0 34 -99 52
-171 30z"/>
<path d="M2789 3550 c-91 -16 -150 -88 -154 -189 -5 -158 106 -235 284 -196
l27 6 0 92 -1 92 -30 1 c-16 1 -32 -2 -35 -7 -3 -5 -5 -35 -5 -68 2 -65 -2
-69 -54 -65 -80 6 -110 48 -108 147 2 57 6 70 28 93 31 31 100 43 149 26 28
-10 32 -9 40 14 13 32 13 31 -7 39 -37 14 -99 21 -134 15z"/>
<path d="M4215 3542 c-1 -2 1 -20 6 -40 50 -215 62 -263 76 -299 14 -38 19
-43 47 -43 32 0 33 2 69 104 20 57 37 109 37 115 0 6 4 11 8 11 4 0 23 -46 41
-102 18 -57 38 -109 43 -115 6 -7 23 -13 38 -13 25 0 29 6 48 63 11 34 30 105
42 157 12 52 26 110 30 127 10 37 6 41 -34 39 -31 -2 -39 -15 -51 -96 -11 -73
-39 -190 -43 -185 -3 3 -22 56 -42 117 -36 109 -39 113 -68 116 l-30 3 -38
-122 c-37 -117 -39 -121 -50 -93 -6 16 -21 81 -34 145 l-23 116 -34 -1 c-19
-1 -36 -2 -38 -4z"/>
<path d="M1936 3440 c-52 -26 -71 -64 -70 -135 0 -52 5 -69 27 -98 29 -39 83
-58 144 -50 57 6 63 10 63 38 0 25 -2 26 -51 21 -27 -3 -60 0 -73 5 -25 12
-49 45 -42 58 3 5 46 8 96 7 54 -1 90 3 91 9 13 122 -83 197 -185 145z m106
-62 c19 -19 20 -22 4 -33 -17 -13 -106 -14 -106 -2 0 4 0 11 0 16 0 18 32 41
56 41 13 0 34 -10 46 -22z"/>
<path d="M2255 3453 c-67 -13 -61 1 -61 -153 l0 -140 33 0 32 0 3 118 3 117
30 3 c59 6 70 -14 73 -132 l4 -106 28 0 c15 0 30 6 32 13 10 24 1 195 -11 223
-6 16 -21 36 -33 43 -22 13 -96 21 -133 14z"/>
<path d="M3053 3450 c-24 -10 -27 -18 -18 -42 4 -11 19 -13 56 -10 55 5 79 -8
79 -42 0 -19 -5 -21 -34 -18 -80 9 -141 -40 -130 -104 11 -67 79 -90 201 -69
l32 6 -3 112 c-3 113 -13 149 -46 163 -26 10 -114 13 -137 4z m117 -200 c0
-40 0 -40 -38 -40 -40 0 -62 14 -62 40 0 26 22 40 62 40 38 0 38 0 38 -40z"/>
<path d="M3360 3451 l-35 -6 -3 -143 -3 -143 33 3 33 3 2 105 c0 58 2 111 2
118 1 7 15 12 36 12 47 0 58 -24 59 -140 l2 -95 32 -3 33 -3 -3 115 -3 116 33
6 c37 7 61 -8 67 -42 2 -10 4 -59 4 -107 l1 -88 33 3 32 3 -1 112 c-1 130 -12
156 -71 173 -30 9 -47 9 -82 -4 -34 -11 -49 -12 -65 -4 -24 13 -84 17 -136 9z"/>
<path d="M3848 3436 c-70 -46 -88 -160 -35 -229 36 -47 127 -66 195 -42 19 7
11 61 -8 57 -50 -11 -85 -10 -110 3 -17 9 -30 20 -30 24 0 5 -2 16 -5 24 -5
11 11 14 90 13 l95 -1 0 38 c0 47 -22 97 -52 116 -37 23 -103 22 -140 -3z
m104 -48 c8 -7 18 -22 20 -33 5 -19 1 -21 -51 -19 -31 1 -60 2 -64 3 -9 1 12
43 27 53 17 12 51 9 68 -4z"/>
<path d="M4822 3450 c-56 -24 -85 -74 -85 -146 0 -62 29 -116 72 -134 62 -25
179 -14 167 16 -3 9 -6 22 -6 30 0 9 -5 12 -11 8 -19 -12 -79 -13 -107 -3 -29
11 -42 26 -42 50 0 13 13 16 83 14 45 0 87 1 93 3 14 4 11 64 -5 104 -19 50
-104 81 -159 58z m94 -75 c9 -14 14 -29 10 -32 -4 -4 -31 -8 -61 -8 -60 -2
-70 11 -38 47 24 27 69 23 89 -7z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.2 KiB

19
favicon/site.webmanifest Normal file
View file

@ -0,0 +1,19 @@
{
"name": "",
"short_name": "",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}

View file

@ -0,0 +1,4 @@
.nav-link.active {
color: $primary;
font-weight: bold;
}

1
sass/base/_common.scss Normal file
View file

@ -0,0 +1 @@
// Empty.

1
sass/base/_fonts.scss Normal file
View file

@ -0,0 +1 @@
// Empty.

117
sass/base/_layout.scss Normal file
View file

@ -0,0 +1,117 @@
@use "sass:map";
body {
> header {
@include media-breakpoint-up(xl) {
.rest-in-game-banner-container {
overflow: hidden;
}
}
@include media-breakpoint-up(xxxl, map.merge($grid-breakpoints, ("xxxl": 1600px))) {
.game-logo-banner {
position: absolute;
top: 0;
}
}
.rest-in-game-banner {
transform: skew(12deg) translateX(5%);
>span {
transform: skew(-12deg);
}
}
.btn-connect {
position: relative;
padding-left: 2.3rem;
&::before {
position: absolute;
top: 50%;
left: 0.3rem;
width: 1.5rem;
height: 1.5rem;
background-image: url('@Theme/images/connect.png');
background-size: contain;
content: "";
transform: translateY(-50%);
}
}
}
> footer {
.share {
width: 1.6rem;
}
.list-inline {
.list-inline-item {
&::after {
right: 0;
display: inline-block;
width: 0.2rem;
margin-left: 0.8rem;
background-color: $color-light;
content: '\00A0';
}
&:last-child::after {
display: none;
}
}
}
svg {
fill: $color-light;
}
.downlink {
> a {
display: inline-block;
}
}
@include media-breakpoint-up(md) {
.downlink {
position: relative;
height: 6rem;
> a {
position: absolute;
top: -3rem;
left: 50%;
width: 11rem;
max-height: 8rem;
transform: translateX(-50%);
> span {
position: relative;
top: -3rem;
}
}
}
}
#page-up {
position: fixed;
right: 0;
bottom: 0;
display: none;
padding: 0;
margin-right: 1rem;
&.show {
display: block;
}
svg {
width: 3rem;
fill: $color-dark;
filter: drop-shadow(0 0 2px #{rgba($color-light, $alpha: 0.4)});
}
}
}
}

23
sass/fo.scss Normal file
View file

@ -0,0 +1,23 @@
@charset "UTF-8";
// * UTILITIES
@import "./utilities/variables";
// * VENDOR
@import "@ldc-web/cookie-notice";
@import "glightbox/dist/css/glightbox.css";
@import "./vendor/bootstrap";
// * BASE
@import "./base/bootstrap-overload";
@import "./base/fonts";
@import "./base/common";
@import "./base/layout";
// * PAGES
@import "./pages/teaser";
@import "./pages/home";
@import "./pages/static_page";
@import "./pages/products";
@import "./pages/won";
@import "./pages/participate";

316
sass/mail-theme.scss Normal file
View file

@ -0,0 +1,316 @@
@use "sass:color";
@import "utilities/variables";
// 1. Include new custom variables
@import "utilities/bootstrap-variables";
// 2. Include functions first (so you can manipulate colors, SVGs, calc, etc)
// @import "bootstrap/scss/functions";
// 3. Include remainder of required Bootstrap stylesheets
@import "bootstrap/scss/variables";
// * Laravel mail vendor
/* Base */
body,
body *:not(html, style, br, tr, code) {
position: relative;
box-sizing: border-box;
font-family:
-apple-system,
BlinkMacSystemFont,
"Segoe UI",
Roboto,
Helvetica,
Arial,
sans-serif,
"Apple Color Emoji",
"Segoe UI Emoji",
"Segoe UI Symbol";
}
body {
width: 100% !important;
height: 100%;
padding: 0;
margin: 0;
background-color: $body-bg;
color: $body-color;
line-height: 1.4;
text-size-adjust: none;
}
p,
ul,
ol,
blockquote {
line-height: 1.4;
text-align: left;
}
img {
max-width: 100%;
}
a {
color: $link-color;
}
a img {
border: 0;
}
/* Typography */
h1 {
margin-top: 0;
color: $color-primary;
color: $color-tertiary;
font-size: 18px;
font-weight: bold;
text-align: left;
}
h2 {
margin-top: 0;
color: $color-tertiary;
font-size: 16px;
font-weight: bold;
text-align: left;
}
h3 {
margin-top: 0;
color: $color-tertiary;
font-size: 14px;
font-weight: bold;
text-align: left;
}
p {
margin-top: 0;
font-size: 16px;
line-height: 1.5em;
text-align: left;
}
.sub {
font-size: 12px;
}
/* Layout */
.wrapper {
-premailer-width: 100%;
width: 100%;
padding: 0;
margin: 0;
background-color: $bg-lightened;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
}
.content {
-premailer-width: 100%;
width: 100%;
padding: 0;
margin: 0;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
}
/* Header */
.header {
padding: 25px 0;
text-align: center;
}
.header a {
color: $color-primary;
font-size: 19px;
font-weight: bold;
text-decoration: none;
}
/* Logo */
.logo {
width: 75px;
height: 75px;
max-height: 75px;
}
/* Body */
.body {
-premailer-width: 100%;
width: 100%;
padding: 0;
border-top: 1px solid #{$bg-lightened};
border-bottom: 1px solid #{$bg-lightened};
margin: 0;
background-color: $bg-lightened;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
}
.inner-body {
-premailer-width: 570px;
width: 570px;
padding: 0;
border-width: 1px;
border-color: color.scale($body-bg, $lightness: -30%);
border-radius: 2px;
margin: 0 auto;
background-color: $body-bg;
box-shadow: 0 2px 0 rgb(0 0 150 / 2.5%), 2px 4px 0 rgb(0 0 150 / 1.5%);
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
}
/* Subcopy */
.subcopy {
padding-top: 25px;
border-top: 1px solid color.scale($body-bg, $lightness: -30%);
margin-top: 25px;
}
.subcopy p {
font-size: 14px;
}
/* Footer */
.footer {
-premailer-width: 570px;
width: 570px;
padding: 0;
margin: 0 auto;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
text-align: center;
}
.footer p {
color: #b0adc5;
font-size: 12px;
text-align: center;
}
.footer a {
color: #b0adc5;
text-decoration: underline;
}
/* Tables */
.table table {
-premailer-width: 100%;
width: 100%;
margin: 30px auto;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
}
.table th {
padding-bottom: 8px;
border-bottom: 1px solid #edeff2;
margin: 0;
}
.table td {
padding: 10px 0;
margin: 0;
color: #74787e;
font-size: 15px;
line-height: 18px;
}
.content-cell {
max-width: 100vw;
padding: 32px;
}
/* Buttons */
.action {
-premailer-width: 100%;
width: 100%;
padding: 0;
margin: 30px auto;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
text-align: center;
}
.button {
display: inline-block;
overflow: hidden;
border-radius: 4px;
color: $body-bg;
text-decoration: none;
text-size-adjust: none;
}
.button-blue,
.button-primary {
border-top: 8px solid #{$color-primary};
border-right: 18px solid #{$color-primary};
border-bottom: 8px solid #{$color-primary};
border-left: 18px solid #{$color-primary};
background-color: #{$color-primary};
}
.button-green,
.button-success {
border-top: 8px solid #{$color-success};
border-right: 18px solid #{$color-success};
border-bottom: 8px solid #{$color-success};
border-left: 18px solid #{$color-success};
background-color: #{$color-success};
}
.button-red,
.button-error {
border-top: 8px solid #{$color-danger};
border-right: 18px solid #{$color-danger};
border-bottom: 8px solid #{$color-danger};
border-left: 18px solid #{$color-danger};
background-color: #{$color-danger};
}
/* Panels */
.panel {
border-left: $color-primary solid 4px;
margin: 21px 0;
}
.panel-content {
padding: 16px;
background-color: $bg-lightened;
color: $body-color;
}
.panel-content p {
color: $body-color;
}
.panel-item {
padding: 0;
}
.panel-item p:last-of-type {
padding-bottom: 0;
margin-bottom: 0;
}
/* Utilities */
.break-all {
word-break: break-all;
}

87
sass/pages/_home.scss Normal file
View file

@ -0,0 +1,87 @@
.home-page {
.picture-100-win {
left: 40%;
transform: translateX(-60%);
}
@include media-breakpoint-up(xl) {
.main-rotate {
transform: rotateZ(-5deg);
}
.anti-rotate {
transform: rotateZ(5deg);
}
}
.badge-vertical {
width: 4rem;
padding: 0.8rem;
@include media-breakpoint-up(md) {
width: 7rem;
padding: 1.3rem;
}
&::after {
display: block;
width: 0.4rem;
height: 200%;
margin: 0 auto;
background-color: $color-white;
content: ' ';
}
&:last-child::after {
display: none;
}
}
.picture-products {
max-width: 20rem;
}
#carousel-lots {
.carousel-text-pannel {
max-width: 40rem;
}
.carousel-item {
min-height: 55rem;
@include media-breakpoint-up(sm) {
min-height: 48rem;
}
@include media-breakpoint-up(md) {
min-height: 40rem;
}
}
img {
max-height: 20rem;
@include media-breakpoint-up(md) {
max-height: inherit;
}
}
.main-rotate {
transform: rotateZ(-1deg);
}
.anti-rotate {
transform: rotateZ(1deg);
}
@include media-breakpoint-up(md) {
.main-rotate {
transform: rotateZ(-5deg);
}
.anti-rotate {
transform: rotateZ(5deg);
}
}
}
}

View file

@ -0,0 +1,23 @@
.participate-page {
.br-and-arrow {
position: relative;
text-align: center;
img {
width: 9rem;
}
&::after {
position: relative;
display: inline-block;
width: 3rem;
height: 4rem;
background-image: url('@Theme/images/arrow-code.png');
background-position: center;
background-repeat: no-repeat;
background-size: contain;
content: ' ';
transform: translateY(100%);
}
}
}

15
sass/pages/_products.scss Normal file
View file

@ -0,0 +1,15 @@
.product-page {
.product-list {
.product {
width: 16rem;
@include media-breakpoint-up(sm) {
width: 13rem;
}
@include media-breakpoint-up(lg) {
width: 12rem;
}
}
}
}

View file

@ -0,0 +1,18 @@
.static-page {
h1 {
color: $color-quint;
text-align: center;
text-transform: uppercase;
}
h2,h3,h4,h5,h6 {
color: $color-quad;
text-transform: uppercase;
}
hr {
width: 30%;
border-top: 0.2rem solid #{$color-quad};
margin: 0 auto;
}
}

20
sass/pages/_teaser.scss Normal file
View file

@ -0,0 +1,20 @@
.teaser-page {
.container-big {
max-width: 1500px;
}
.picture-100-win {
left: 40%;
transform: translateX(-60%);
}
@include media-breakpoint-up(xl) {
.main-rotate {
transform: rotateZ(-5deg);
}
.anti-rotate {
transform: rotateZ(5deg);
}
}
}

27
sass/pages/_won.scss Normal file
View file

@ -0,0 +1,27 @@
@import "./../partials/spin_wheel";
.won-page {
#wheel-wrapper {
position: relative;
width: 16rem;
margin: 0 auto;
}
@include media-breakpoint-up(md) {
.prize-rotate {
transform: rotateZ(-3deg);
}
.anti-rotate {
transform: rotateZ(3deg);
}
}
.wide-banner {
position: relative;
@include media-breakpoint-up(md) {
right: -2rem;
}
}
}

View file

@ -0,0 +1,168 @@
#wheel-wrapper {
* {
padding: 0;
margin: 0;
}
.wheel {
position: relative;
overflow: hidden;
width: 16rem;
height: 16rem;
border: 0.4rem solid #{$color-white};
border-radius: 50%;
margin: 0;
box-shadow: rgb(0 0 0 / 20%) 0 0 10px, rgb(0 0 0 / 5%) 0 3px 0;
transform: rotate(0deg);
&::before {
position: absolute;
z-index: 1000;
left: 0;
width: calc(16rem - 0.2rem * 2);
height: calc(16rem - 0.2rem * 2);
border: 0.2rem solid rgb(0 0 0 / 10%);
border-radius: 50%;
content: "";
}
.wheel-inner {
width: 100%;
height: 100%;
transition: all 6s cubic-bezier(0, 0.99, 0.44, 0.99);
}
.wheel-sec {
position: absolute;
top: -.1rem;
left: -.1rem;
width: 16rem;
height: calc(16rem / 2);
background-origin: border-box;
background-position: center;
background-repeat: no-repeat;
background-size: auto;
opacity: 1;
transform-origin: calc(16rem / 2) calc(16rem / 2);
}
.wheel-spin {
position: absolute;
z-index: 1000;
top: 50%;
left: 50%;
width: 4.2rem;
height: 4.2rem;
border-radius: 50%;
margin: -34px 0 0 -34px;
background: #{$color-white};
box-shadow: rgb(0 0 0 / 10%) 0 3px 0;
cursor: pointer;
font-family: "Exo 2", sans-serif;
user-select: none;
&::before {
position: absolute;
top: -12px;
left: 14px;
width: 0;
height: 0;
border-width: 0 20px 28px;
border-style: solid;
border-color: transparent transparent #{$color-white};
content: "";
}
&::after {
position: relative;
z-index: 100000;
display: block;
width: 4.2rem;
height: 4.2rem;
color: $color-dark;
content: "LANCER";
font-size: .7rem;
line-height: 4.2rem;
text-align: center;
text-shadow: 0 2px 0 #{$color-white}, 0 -1px 0 rgb(0 0 0 / 30%);
}
.wheel-spin-inner {
position: absolute;
z-index: 999;
top: 50%;
left: 50%;
width: 54px;
height: 54px;
border-radius: 50%;
margin: -27px 0 0 -27px;
background: $color-white;
/* Old browsers */
/* stylelint-disable-next-line declaration-property-value-no-unknown */
background: radial-gradient(center, ellipse cover, rgb(255 255 255 / 100%) 0%, rgb(234 234 234 / 100%) 100% ); /* FF3.6+ */
background: -webkit-gradient(radial, center center, 0, center center, 100%, color-stop(0%, rgb(255 255 255 / 100%)), color-stop(100%, rgb(234 234 234 / 100%)) ); /* Chrome,Safari4+ */
/* stylelint-disable-next-line declaration-property-value-no-unknown */
background: radial-gradient(center, ellipse cover, rgb(255 255 255 / 100%) 0%, rgb(234 234 234 / 100%) 100% ); /* Chrome10+,Safari5.1+ */
/* stylelint-disable-next-line declaration-property-value-no-unknown */
background: radial-gradient(center, ellipse cover, rgb(255 255 255 / 100%) 0%, rgb(234 234 234 / 100%) 100% ); /* Opera 12+ */
/* stylelint-disable-next-line declaration-property-value-no-unknown */
background: radial-gradient(center, ellipse cover, rgb(255 255 255 / 100%) 0%, rgb(234 234 234 / 100%) 100% ); /* IE10+ */
background: radial-gradient(ellipse at center, rgb(255 255 255 / 100%) 0%, rgb(234 234 234 / 100%) 100% ); /* W3C */
box-shadow: rgb(255 255 255 / 100%) 0 -2px 0 inset, rgb(255 255 255 / 100%) 0 2px 0 inset, rgb(0 0 0 / 40%) 0 0 5px;
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#eaeaea',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */
}
&:active,&.active {
&::after {
font-size: .8rem;
}
.wheel-spin-inner {
box-shadow: rgb(0 0 0 / 40%) 0 0 5px inset;
}
}
}
.wheel-shine {
position: absolute;
top: 0;
left: 0;
width: 16rem;
height: 16rem; /* FF3.6+ */
background: -webkit-gradient(radial, center center, 0, center center, 100%, color-stop(0%, rgb(255 255 255 / 100%)), color-stop(1%, rgb(255 255 255 / 99%)), color-stop(9%, rgb(255 255 255 / 91%)), color-stop(100%, rgb(255 255 255 / 0%)) ); /* Chrome,Safari4+ */ /* Chrome10+,Safari5.1+ */ /* Opera 12+ */
/* stylelint-disable-next-line declaration-property-value-no-unknown */
background: radial-gradient(center, ellipse cover, rgb(255 255 255 / 100%) 0%, rgb(255 255 255 / 99%) 1%, rgb(255 255 255 / 91%) 9%, rgb(255 255 255 / 0%) 100% ); /* IE10+ */
background: radial-gradient(ellipse at center, rgb(255 255 255 / 100%) 0%, rgb(255 255 255 / 99%) 1%, rgb(255 255 255 / 91%) 9%, rgb(255 255 255 / 0%) 100% ); /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#00ffffff',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */
opacity: 0.1;
}
}
/* ANIMATION */
@keyframes hh {
0%,
100% {
transform: rotate(0deg);
}
50% {
transform: rotate(7deg);
}
}
@keyframes hh {
0%,
100% {
transform: rotate(0deg);
}
50% {
transform: rotate(7deg);
}
}
.spin { /* Chrome, Safari, Opera */
animation: hh 0.1s;
}
}

View file

@ -0,0 +1,46 @@
@use "sass:list";
@import "mixins";
@import "bootstrap/scss/functions";
@import "./bs-customs/input";
// SET SOME CLASSES WITH BOOTSTRAP BREAKPOINTS
// * Reponsive borders
@each $breakpoint in map-keys($grid-breakpoints) {
@include media-breakpoint-up($breakpoint) {
$infix: breakpoint-infix($breakpoint, $grid-breakpoints);
@include generate-bs-borders($infix, $prefix);
@each $color, $value in $theme-colors {
@include generate-bs-borders($infix, $prefix, $color);
}
}
}
// * Responsive sizings (used in laravel errors layouts)
@each $breakpoint in map-keys($grid-breakpoints) {
@include media-breakpoint-up($breakpoint) {
$infix: breakpoint-infix($breakpoint, $grid-breakpoints);
.w#{$infix}-25 {
width: 25% !important;
}
.w#{$infix}-50 {
width: 50% !important;
}
.w#{$infix}-75 {
width: 75% !important;
}
.w#{$infix}-100 {
width: 100% !important;
}
@each $prop, $unit in (width: vw, height: vh) {
@each $size in [25, 50, 75, 100] {
.#{$unit}#{$infix}-#{$size} {
#{$prop}: #{$size}#{$unit} !important;
}
}
}
}
}

View file

@ -0,0 +1,62 @@
@use "sass:map";
@import 'bootstrap/scss/functions';
// Override bootstrap colors
$primary: $color-primary;
$secondary: $color-secondary;
$success: $color-success;
$info: $color-info;
$warning: $color-warning;
$danger: $color-danger;
$light: $color-light;
$white: $color-white;
$dark: $color-dark;
$tertiary: $color-tertiary;
$quad: $color-quad;
$quint: $color-quint;
$theme-colors: (
primary: $primary,
secondary: $secondary,
tertiary: $tertiary,
quad: $quad,
quint: $quint,
success: $success,
info: $info,
warning: $warning,
danger: $danger,
light: $light,
"white": $white,
dark: $dark,
);
$custom-theme-colors: map.merge($theme-colors,
(
'tertiary': $tertiary,
'quad': $quad,
'quint': $quint,
));
$theme-colors: map.merge($theme-colors, $custom-theme-colors);
$theme-colors-rgb: map-loop($theme-colors, to-rgb, '$value');
// Override bootstrap vars
$font-family-base: $font-default-family-base;
$font-size-base: $font-default-size-base;
$line-height-base: $line-default-height-base;
// Add font-size variable
$heading-multiplicator: 1;
$h1-font-size: $font-size-base * $heading-multiplicator * 2.5;
$h2-font-size: $font-size-base * $heading-multiplicator * 2;
$h3-font-size: $font-size-base * $heading-multiplicator * 1.75;
$h4-font-size: $font-size-base * $heading-multiplicator * 1.5;
$h5-font-size: $font-size-base * $heading-multiplicator * 1.25;
$h6-font-size: $font-size-base * $heading-multiplicator;
// Add the new font-size in this map
$font-sizes: (
1: $h1-font-size,
2: $h2-font-size,
3: $h3-font-size,
4: $h4-font-size,
5: $h5-font-size,
6: $h6-font-size,
);

View file

@ -0,0 +1,54 @@
@mixin generate-bs-borders($infix, $prefix, $color:null) {
$color-var: var(--#{$prefix}border-color);
@if $color {
$color-var: rgba(var(--#{$prefix}#{$color}-rgb));
$color: "-#{$color}";
}
.border#{$infix}#{$color}-top {
border-top: $border-width var(--#{$prefix}border-style) #{$color-var} !important;
}
.border#{$infix}#{$color}-end {
border-right: $border-width var(--#{$prefix}border-style) #{$color-var} !important;
}
.border#{$infix}#{$color}-bottom {
border-bottom: $border-width var(--#{$prefix}border-style) #{$color-var} !important;
}
.border#{$infix}#{$color}-start {
border-left: $border-width var(--#{$prefix}border-style) #{$color-var} !important;
}
.border#{$infix}#{$color}-0 { border: 0 !important; }
.border#{$infix}#{$color}-top-0 { border-top: 0 !important; }
.border#{$infix}#{$color}-end-0 { border-right: 0 !important; }
.border#{$infix}#{$color}-bottom-0 { border-bottom: 0 !important; }
.border#{$infix}#{$color}-start-0 { border-left: 0 !important; }
@each $idx, $b-width in $border-widths {
$pidx: list.index(($border-widths), ($idx $b-width));
.border#{$infix}#{$color}-top-#{$idx} {
border-top: $b-width var(--#{$prefix}border-style) #{$color-var} !important;
}
.border#{$infix}#{$color}-end-#{$idx} {
border-right: $b-width var(--#{$prefix}border-style) #{$color-var} !important;
}
.border#{$infix}#{$color}-bottom-#{$idx} {
border-bottom: $b-width var(--#{$prefix}border-style) #{$color-var} !important;
}
.border#{$infix}#{$color}-start-#{$idx} {
border-left: $b-width var(--#{$prefix}border-style) #{$color-var} !important;
}
}
.border#{$infix}#{$color}-x {
border-right: $border-width var(--#{$prefix}border-style) #{$color-var} !important;
border-left: $border-width var(--#{$prefix}border-style) #{$color-var} !important;
}
.border#{$infix}#{$color}-y {
border-top: $border-width var(--#{$prefix}border-style) #{$color-var} !important;
border-bottom: $border-width var(--#{$prefix}border-style) #{$color-var} !important;
}
}

View file

@ -0,0 +1,41 @@
@use "sass:color";
// * COLORS
$color-white: #fff;
$color-light: #eceff3;
$color-dark: #070000;
$color-success: #00ac61;
$color-danger: #f71200;
$color-info: #508fdf;
$color-warning: #e6cd00;
$color-primary: #0f437e;
$color-secondary: #135ba7;
$color-tertiary: #db275a;
$color-quad: #00719e;
$color-quint: #fba629;
// * BACKGROUNDS COLORS
$bg-lightened: $color-light;
$bg-darkened: $color-dark;
$bg-action: $color-primary;
// * FONTS COLORS
$color-default-titles: $color-primary;
$color-default-texts: $color-dark;
// * FONTS
$font-default-family-base: "Imprima Regular", sans-serif; // - The default site font family.
$font-default-size-base: 1rem; // Assumes the browser default, typically `16px`
$line-default-height-base: 1.65;
// * Inputs
$input-bg: color.adjust($color-tertiary, $lightness: 45%);
$input-color: color.adjust($color-tertiary, $lightness: -10%);
// * Cookie Notice
$ck-primary-color: $color-primary;
$ck-secondary-color: color.adjust($color-tertiary, $lightness: -10%);
$ck-background-color: $color-light;

View file

@ -0,0 +1,32 @@
@use "sass:color";
// * Input Form floating text
.form-floating {
> label {
color: #{color.adjust($color-tertiary, $lightness: -4%)};
font-weight: bold;
}
> .form-control,
> .form-control-plaintext {
&::placeholder {
color: transparent;
}
}
> .form-control-plaintext,
> .form-control:focus,
> .form-control:not(:placeholder-shown),
> .form-select {
/* stylelint-disable-next-line no-descending-specificity */
~ label {
color: #{rgba(color.adjust($color-tertiary, $lightness: -4%), $form-floating-label-opacity)};
}
}
// Duplicated because `:-webkit-autofill` invalidates other selectors when grouped
// > .form-control:-webkit-autofill {
// ~ label {
// color: rgba(var(--#{$prefix}body-color-rgb), #{$form-floating-label-opacity});
// }
// }
}

47
sass/vendor/_bootstrap.scss vendored Normal file
View file

@ -0,0 +1,47 @@
// 1. Include new custom variables
@import "./../utilities/bootstrap-variables";
// 2. Include functions first (so you can manipulate colors, SVGs, calc, etc)
@import "bootstrap/scss/functions";
// 3. Include remainder of required Bootstrap stylesheets
@import "bootstrap/scss/variables";
@import "bootstrap/scss/variables-dark";
// 4. Include remainder of required parts
@import "bootstrap/scss/maps";
@import "bootstrap/scss/mixins";
@import "bootstrap/scss/root";
// 5. Optionally include any other parts as needed
@import "bootstrap/scss/alert";
@import "bootstrap/scss/buttons";
@import "bootstrap/scss/button-group";
@import "bootstrap/scss/containers";
@import "bootstrap/scss/dropdown";
@import "bootstrap/scss/forms";
@import "bootstrap/scss/grid";
@import "bootstrap/scss/helpers";
@import "bootstrap/scss/images";
@import "bootstrap/scss/list-group";
@import "bootstrap/scss/nav";
@import "bootstrap/scss/navbar";
@import "bootstrap/scss/pagination";
@import "bootstrap/scss/spinners";
@import "bootstrap/scss/reboot";
@import "bootstrap/scss/tables";
@import "bootstrap/scss/tooltip";
@import "bootstrap/scss/transitions";
@import "bootstrap/scss/type";
@import "bootstrap/scss/utilities";
@import "bootstrap/scss/close";
@import "bootstrap/scss/breadcrumb";
@import "bootstrap/scss/carousel";
@import "bootstrap/scss/card";
@import "bootstrap/scss/accordion";
// 6. Optionally include utilities API last to generate classes based on the Sass map in `_utilities.scss`
@import "bootstrap/scss/utilities/api";
// 7 Overload bootstrap classes
@import "./../utilities/bootstrap-custom";

72
theme.config.php Normal file
View file

@ -0,0 +1,72 @@
<?php
return [
// * GGW version
'version' => '2.0.0',
// * Theme name
'name' => 'base',
// * Picture BO validation sizes
'models' => [
'prizes' => [
'picture_max_width' => 560,
'picture_max_height' => 700,
],
'products' => [
'picture_max_width' => 550,
'picture_max_height' => 550,
],
'ranges' => [
'picture_max_width' => 476,
'picture_max_height' => 355,
],
],
// * Image resizer config
/**
* Format can specifiy to which format save the image
* JPEG PNG GIF TIF BMP ICO PSD WebP
* GD ✔️ ✔️ ✔️ - - - - ✔️ *
* Imagick ✔️ ✔️ ✔️ ✔️ ✔️ ✔️ ✔️ ✔️ *
* For WebP support GD driver must be used with PHP 5 >= 5.5.0 or PHP 7
* in order to use imagewebp(). If Imagick is used, it must be compiled
* with libwebp for WebP support.
* resize => will resize the image (boolean)
* fit => Combine cropping and resizing to format image in a smart way (boolean)
* keepRatio => will keep image ratio wile resizing (boolean)
* trim => boolean to trim the image using border color
* inCanvas => to make sure image boundarie is respected
* format => select tha wantd ouput form, yan can just convert images if you want
* example :
* 'small' => [
* 'height' => 500,
* 'width' => 250,
* 'inCanvas' => true,
* 'trim' => ['transparent', null, 10]
* ],
* 'smallWebp' => [
* 'height' => 500,
* 'width' => 250,
* 'inCanvas' => true,
* 'format' => 'webp'
* ],
* 'justconvertImage' => [
* 'format' => 'webp'
* ]
*/
'resizes' => [
'trimlot1' => [
'height' => 600,
'width' => 400,
'inCanvas' => true,
'fit' => true,
'format' => 'webp'
],
'trimlot2' => [
'height' => 400,
'width' => 400,
'fit' => true,
'inCanvas' => true,
'trim' => ['transparent', null, 10],
'format' => 'png'
]
]
];

93
ts/base/common.ts Normal file
View file

@ -0,0 +1,93 @@
// * Video frames.
document.addEventListener("DOMContentLoaded", function () {
const videoFrameList = document.querySelectorAll(
".video-frame"
) as NodeListOf<HTMLLinkElement>;
for (const videoLink of videoFrameList) {
if (!videoLink.dataset.type) {
throw new Error("Missing dataset type");
}
if (!videoLink.dataset.frame) {
throw new Error("Missing dataset frame");
}
// @ts-ignore
window.__CN_VIDEO = window.__CN_VIDEO ?? {};
const newIframe = document.createElement("iframe");
newIframe.frameBorder = "0";
newIframe.allow = "fullscreen";
newIframe.width = "1920px";
newIframe.height = "1080px";
newIframe.setAttribute("allowfullscreen", "allowfullscreen");
// @ts-ignore
const instance = new FsLightbox();
instance.props.sources = [newIframe];
setTimeout(() => {
videoLink.addEventListener("click", (e) => {
e.preventDefault();
// * This comes fslightbox lib
// @ts-ignore
instance.open();
setTimeout(function () {
// @ts-ignore
newIframe.src = window.__CN_VIDEO[videoLink.dataset.type]
? String(videoLink.href)
: String(videoLink.dataset.frame);
}, 50);
return false;
});
}, 300);
}
const scrollTop = (target: string, offset: number = 0) => {
const targetElement = document.getElementById(target);
if (!targetElement) throw new Error(`scrollTop requires ${target} to exist`);
const top = targetElement.getBoundingClientRect().top,
t = window.scrollY + top - offset;
scrollTo({
top: t,
behavior: "smooth"
});
};
const pageUp = document.getElementById("page-up");
if (pageUp) {
pageUp.addEventListener("click", () => scrollTop("content-container", 250)),
document.addEventListener("scroll", () => {
if (window.scrollY > 250) {
pageUp.classList.add("show");
return;
}
pageUp.classList.remove("show");
});
}
});
// * Input Validation.
document.addEventListener("DOMContentLoaded", function () {
document.querySelectorAll("input.is-invalid").forEach((input) => {
let timer: NodeJS.Timeout|null = null;
input.addEventListener("change", () => {
const parent = input.parentElement;
input.classList.remove("is-invalid");
if (parent && parent.classList.contains("is-invalid")) {
parent.classList.remove("is-invalid");
}
});
input.addEventListener("input", () => {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
const parent = input.parentElement;
input.classList.remove("is-invalid");
if (parent && parent.classList.contains("is-invalid")) {
parent.classList.remove("is-invalid");
}
}, 250);
});
});
});

View file

@ -0,0 +1,102 @@
<template>
<input
ref="inputDate"
:id="String(ipt_id)"
:class="String(ipt_class)"
:type="ipt_type"
:name="String(ipt_name)"
:placeholder="`${String(ipt_placeholder)} ${ipt_required ? '*' : ''}`"
v-model="ipt_value"
:autocomplete="String(ipt_autocomplete)"
:required="Boolean(ipt_required)"
@focus="startEditing"
@change="changed"
>
<label :for="String(ipt_id)">{{ `${String(ipt_placeholder)} ${ipt_required ? '*' : ''}` }}</label>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import trans from "../../../../ts/modules/trans";
export default defineComponent({
name: "InputBirthDate",
mixins: [trans],
data(): {
ipt_id: string | null;
ipt_class: string;
ipt_name: string;
ipt_placeholder: string;
ipt_autocomplete: string;
ipt_required: boolean;
ipt_value: string | undefined;
ipt_type: string;
cached_value: string | null;
} {
return {
ipt_id: null,
ipt_class: "form-control",
ipt_name: "birthdate",
ipt_placeholder: this.__("Date de naissance"),
ipt_autocomplete: "bday",
ipt_required: true,
ipt_value: undefined,
ipt_type: "text",
cached_value: null,
};
},
computed: {},
mounted() {
const json = String(this.$attrs.json ?? "{}"),
data = JSON.parse(json);
this.ipt_id = data.id ?? this.ipt_id;
this.ipt_class = data.class ?? this.ipt_class;
this.ipt_name = data.name ?? this.ipt_name;
this.ipt_placeholder = data.placeholder ?? this.ipt_placeholder;
this.ipt_autocomplete = data.autocomplete ?? this.ipt_autocomplete;
this.ipt_required = data.required ?? this.ipt_required;
this.ipt_value = data.value;
// * Transform to date type before submit
this.$nextTick(() => {
const inputDate = this.$refs.inputDate as HTMLInputElement;
// * Input already filled.
if (inputDate.value) {
this.startEditing();
} else if (this.ipt_value) {
this.ipt_value = new Date(this.ipt_value).toLocaleDateString();
}
inputDate.closest("form")?.addEventListener("submit", () => {
this.startEditing();
});
});
},
methods: {
beforeSubmit() {},
startEditing(): void {
const inputDate = this.$refs.inputDate as HTMLInputElement;
if (inputDate.value.length) {
this.cached_value = inputDate.value;
}
this.switchIptTypeToDate();
},
/**
* Change the input type to date
*/
switchIptTypeToDate(): void {
this.ipt_type = "date";
if (this.cached_value) {
const date = new Date(Date.parse(this.cached_value));
this.ipt_value = new Date(date.getTime() - (date.getTimezoneOffset() * 60000))
.toISOString()
.split("T")[0] ?? date.toISOString().substring(0,10);
}
},
changed() {
const inputDate = this.$refs.inputDate as HTMLInputElement;
this.cached_value = inputDate.value;
this.switchIptTypeToDate();
}
},
});
</script>

View file

@ -0,0 +1,136 @@
<template>
<button
@click.prevent="toggleVisibility()"
@keydown="keydown"
:class="`btn btn-tertiary rounded-0 rounded-end password-visibility-${inputId} h-100`"
:aria-pressed="visible"
>
<span
class="text-bg-tertiary reveal d-flex justify-content-center align-items-center h-100"
type="button"
:title="visible ? __('vue.PasswordVisibility.hide') : __('vue.PasswordVisibility.show')"
data-bs="tooltip"
>
<FontAwesomeIcon
v-if="visible"
icon="fas fa-eye-slash"
:aria-hidden="true"
/>
<FontAwesomeIcon
v-else
icon="fas fa-eye"
:aria-hidden="true"
/>
</span>
</button>
</template>
<script lang="ts">
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { Tooltip } from "bootstrap";
import { defineComponent } from "vue";
import trans from "./../../../../ts/modules/trans";
export default defineComponent({
name: "PasswordVisibility",
mixins: [trans],
components: { FontAwesomeIcon },
data(): {
inputId: string;
input: HTMLInputElement;
visible: boolean;
tooltipList: HTMLButtonElement[];
} {
return {
inputId: "",
input: document.createElement("input"),
visible: false,
tooltipList: [],
};
},
computed: {},
mounted() {
const json = String(this.$attrs.json ?? "{}"),
data = JSON.parse(json);
this.inputId = data.inputId;
this.input = document.getElementById(this.inputId) as HTMLInputElement;
if (!this.input) {
throw new Error(`Cannot find input id '${this.inputId}'`);
}
if (this.input.tagName !== "INPUT") {
throw new Error(`id '${this.inputId}' is not an input`);
}
if ((this.input as HTMLInputElement).type !== "password") {
throw new Error(`id '${this.inputId}' is not an input password`);
}
this.input = this.input as HTMLInputElement;
this.$nextTick(() => {
this.updateBootstrapTooltip();
});
},
methods: {
keydown(e:KeyboardEvent):void {
if (
e.key === " " ||
e.code === "Space" ||
e.keyCode === 32 ||
e.key === "Enter" ||
e.code === "Enter" ||
e.keyCode === 13
) {
this.toggleVisibility();
e.preventDefault();
}
},
/**
* Update password status (visible, hidden).
*/
toggleVisibility(): void {
if (this.input.type === "password") {
this.input.type = "text";
this.visible = true;
} else {
this.input.type = "password";
this.visible = false;
}
this.$nextTick(() => {
this.updateBootstrapTooltip();
});
},
/**
* Update Bootstrap tooltips.
*/
updateBootstrapTooltip() {
let newTooltipList = [].slice.call(
document.querySelectorAll(
".password-visibility-" + this.inputId + " [data-bs=\"tooltip\"]"
)
) as HTMLButtonElement[];
let tmp = newTooltipList.filter((x) => !this.tooltipList.includes(x));
tmp.map((tooltip) => {
return new Tooltip(tooltip);
});
this.closeBootstrapTooltip();
this.tooltipList = newTooltipList;
},
/**
* Close all Bootstrap tooltips.
*/
closeBootstrapTooltip() {
this.tooltipList.forEach((tooltip) => {
tooltip.blur();
Tooltip.getInstance(tooltip)?.hide();
});
},
},
});
</script>
<style lang="scss">
.reveal {
width: 52px;
}
</style>

8
ts/env.d.ts vendored Normal file
View file

@ -0,0 +1,8 @@
/// <reference types="vite/client" />
declare module "*.vue" {
import type { DefineComponent } from "vue";
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
const component: DefineComponent<{}, {}, any>;
export default component;
}

20
ts/fo.ts Normal file
View file

@ -0,0 +1,20 @@
// ASSETS
/// <reference types="vite/client" />
import.meta.glob(["./../assets/images/**"]);
// UTILITIES
import "./utilities/bootstrap";
import "./utilities/fontawesome";
import "./utilities/vue-fo";
// CUSTOM
import "./base/common";
// PAGES
import "./pages/home";
import "./pages/products";
import "./pages/won";
// Cookies
import CookieNotice from "@ldc-web/cookie-notice";
window.CookieNotice = CookieNotice;

12
ts/index.d.ts vendored Normal file
View file

@ -0,0 +1,12 @@
export { };
import type CookieNotice from "@ldc-web/cookie-notice";
import { AxiosStatic } from "axios";
declare global {
interface Window {
CookieNotice: typeof CookieNotice;
axios: AxiosStatic;
}
}

26
ts/modules/bsTooltips.ts Normal file
View file

@ -0,0 +1,26 @@
import type * as bootstrap from "bootstrap";
let tooltips: Array<bootstrap.Tooltip> = [];
export default {
methods: {
initTooltips() {
// Disable tooltips on reboot.
tooltips.forEach((tooltip) => {
tooltip.disable();
tooltip.hide();
});
tooltips = [].slice
.call(document.querySelectorAll("[data-bs-toggle=\"tooltip\"]"))
.map(function (tooltipTriggerEl) {
return new window.bootstrap.Tooltip(tooltipTriggerEl, {
customClass: "large-tooltip",
delay: {
show: 1250,
hide: 0,
},
});
});
},
},
};

46
ts/pages/home.ts Normal file
View file

@ -0,0 +1,46 @@
import { Carousel } from "bootstrap";
document.addEventListener("DOMContentLoaded", function () {
if (!document.querySelector("main.home-page")) {
return;
}
// * BR Carousel (With BS)
const lotsCarousel = document.getElementById("carousel-lots");
if (lotsCarousel) {
const playPauseBtn = document.getElementById("coupons-carousel-play-btn");
const carousel = Carousel.getOrCreateInstance(lotsCarousel, {
// * Start cycle on swipe (or play btn)
ride: true
});
let isRunning = false;
if (playPauseBtn) {
const updatePlayBtnStatus = () => {
// * Toggle once
if (!isRunning) {
playPauseBtn.children.item(0)?.classList.remove("d-none");
playPauseBtn.children.item(1)?.classList.add("d-none");
} else {
playPauseBtn.children.item(0)?.classList.add("d-none");
playPauseBtn.children.item(1)?.classList.remove("d-none");
}
};
playPauseBtn.addEventListener("click", () => {
if (isRunning) {
carousel.pause(true);
} else {
carousel.cycle();
}
isRunning = !isRunning;
updatePlayBtnStatus();
});
lotsCarousel.addEventListener("slide.bs.carousel", () => {
isRunning = true;
updatePlayBtnStatus();
});
}
}
});

45
ts/pages/products.ts Normal file
View file

@ -0,0 +1,45 @@
import GLightbox from "glightbox";
document.addEventListener("DOMContentLoaded", function () {
if (!document.querySelector("main.product-page")) {
return;
}
const pictureLinks = document.querySelectorAll(".glightbox") as NodeListOf<HTMLLinkElement>,
pictures = document.querySelectorAll(".glightbox img") as NodeListOf<HTMLImageElement>,
imageCount = pictures.length;
let counter: number = 0,
glightbox: GLightbox|null = null;
function incrementCounter() {
counter++;
if ( counter === imageCount ) {
glightbox = new GLightbox({
selector: ".glightbox",
});
}
}
pictures.forEach((imageElement) => {
if (imageElement.complete) {
incrementCounter();
} else {
imageElement.addEventListener( "load", incrementCounter, false );
}
});
pictureLinks.forEach((linkElement, index) => linkElement.addEventListener("keydown", (kbdEvt:KeyboardEvent) => {
if (
kbdEvt.key == " " ||
kbdEvt.code == "Space" ||
kbdEvt.keyCode == 32 ||
kbdEvt.key == "Enter" ||
kbdEvt.code == "Enter" ||
kbdEvt.keyCode == 13
) {
glightbox.openAt(index);
kbdEvt.preventDefault();
}
}));
});

103
ts/pages/won.ts Normal file
View file

@ -0,0 +1,103 @@
document.addEventListener("DOMContentLoaded", function () {
if (!document.querySelector("main.won-page")) {
return;
}
const wheelWrapper = document.getElementById("wheel-wrapper"),
spinWheelInner = wheelWrapper?.querySelector(".wheel-inner") as HTMLElement | null | undefined,
spinWheelBtnList = wheelWrapper?.querySelectorAll(".wheel-spin") as NodeListOf<HTMLElement> | undefined,
animationSection = document.getElementById("spin-animation"),
prizeSection = document.getElementById("prize-section"),
discountSection = document.getElementById("discount-section"),
winningProofSection = document.getElementById("winning-proof-section");
/** Hide animation and show win sections */
const toggleAnimationPhase = () => {
if (animationSection) {
animationSection.classList.add("d-none");
}
if (prizeSection) {
prizeSection.classList.remove("d-none");
}else if (discountSection) {
discountSection.classList.remove("d-none");
} else {
throw new Error("No section to toggle");
}
if (winningProofSection) {
winningProofSection.classList.remove("d-none");
}
};
if (!animationSection) {
throw Error("section#spin-animation missing");
}
if (wheelWrapper && spinWheelInner && spinWheelBtnList && spinWheelBtnList.length) {
let clicks: number = 0;
// * Set default degree (360*5) soit 5 tours
const degree: number = (360 * 5),
wheelPartsDeg: number = 360 / spinWheelInner.children.length,
thisWinAngle: number = (Number.parseInt(
String(wheelWrapper.dataset["winChild"])
// On s'aligne sur la tranche on on ajoute entre 10% et 90% d'une part
)) * wheelPartsDeg - 45 + (wheelPartsDeg * (Math.random() * (0.9 - 0.1) + 0.1));
let timeout: NodeJS.Timeout | null = null;
const spinTheWheel = () => {
// * Add 1 every click
/**
* Multiply the degree by number of clicks
* generate random number between 1 - 85,
* then add to the new degree
*/
const newDegree = degree * ++clicks;
const totalDegree = newDegree + thisWinAngle;
/**
* Let's make the spin btn to tilt every
* time the edge of the section hits
* the indicator
*/
spinWheelInner.style["transform"] = `rotate(${totalDegree}deg)`;
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(toggleAnimationPhase, 7000);
};
/** ! Même Algo que sur GGW legacy */
spinWheelBtnList.forEach((spinBtn) => {
spinBtn.addEventListener("click", spinTheWheel);
spinBtn.addEventListener("keydown", (kbdEvt: KeyboardEvent) => {
if (
kbdEvt.key == " " ||
kbdEvt.code == "Space" ||
kbdEvt.keyCode == 32 ||
kbdEvt.key == "Enter" ||
kbdEvt.code == "Enter" ||
kbdEvt.keyCode == 13
) {
spinBtn.classList.add("active");
spinTheWheel();
kbdEvt.preventDefault();
}
});
spinBtn.addEventListener("keyup", (kbdEvt: KeyboardEvent) => {
if (
kbdEvt.key == " " ||
kbdEvt.code == "Space" ||
kbdEvt.keyCode == 32 ||
kbdEvt.key == "Enter" ||
kbdEvt.code == "Enter" ||
kbdEvt.keyCode == 13
) {
spinBtn.classList.remove("active");
kbdEvt.preventDefault();
}
});
});
} else {
toggleAnimationPhase();
}
});

0
ts/partials/.gitkeep Normal file
View file

0
ts/types/.gitkeep Normal file
View file

21
ts/utilities/bootstrap.ts Normal file
View file

@ -0,0 +1,21 @@
import axios from "axios";
import * as bootstrap from "bootstrap";
import bsTooltips from "./../modules/bsTooltips";
/**
* We'll load the axios HTTP library which allows us to easily issue requests
* to our Laravel back-end. This library automatically handles sending the
* CSRF token as a header based on the value of the "XSRF" token cookie.
*/
axios.defaults.headers.common = {
Accept: "application/json, text/plain, */*",
"X-Requested-With": "XMLHttpRequest",
"X-CSRF-TOKEN": document
.querySelector("meta[name=\"csrf-token\"]")!
.getAttribute("content"),
};
window.axios = axios;
window.bootstrap = bootstrap;
bsTooltips.methods.initTooltips();

View file

@ -0,0 +1,94 @@
import { config, dom, library } from "@fortawesome/fontawesome-svg-core";
import {
faArrowAltCircleDown,
faArrowAltCircleUp,
faArrowDown,
faArrowLeft,
faArrowLeftLong,
faArrowRight,
faArrowRightFromBracket,
faArrowUp,
faArrowsAltH,
faArrowsAltV,
faBackspace,
faBan,
faCheck,
faChevronLeft,
faChevronRight,
faCircleCheck,
faCircleExclamation,
faCircleInfo,
faCircleNotch,
faCircleXmark,
faCopy,
faCrop,
faEraser,
faEye,
faEyeSlash,
faFolderOpen,
faGift,
faListUl,
faPause,
faPencil,
faPlay,
faPlus,
faQuestionCircle,
faRedoAlt,
faSearch,
faSearchMinus,
faSearchPlus,
faSliders,
faSyncAlt,
faTimes,
faTrash,
faUndoAlt,
faWandMagic
} from "@fortawesome/free-solid-svg-icons";
config.autoReplaceSvg = false;
library.add(faEraser);
library.add(faArrowLeftLong);
library.add(faPlus);
library.add(faTrash);
library.add(faEye);
library.add(faEyeSlash);
library.add(faFolderOpen);
library.add(faCrop);
library.add(faQuestionCircle);
library.add(faCheck);
library.add(faUndoAlt);
library.add(faRedoAlt);
library.add(faSyncAlt);
library.add(faSearchPlus);
library.add(faSearchMinus);
library.add(faArrowLeft);
library.add(faArrowRight);
library.add(faArrowUp);
library.add(faArrowDown);
library.add(faArrowsAltH);
library.add(faArrowsAltV);
library.add(faWandMagic);
library.add(faPencil);
library.add(faTimes);
library.add(faBackspace);
library.add(faSearch);
library.add(faArrowRightFromBracket);
library.add(faArrowAltCircleDown);
library.add(faArrowAltCircleUp);
library.add(faCircleCheck);
library.add(faCircleXmark);
library.add(faCopy);
library.add(faListUl);
library.add(faBan);
library.add(faCircleExclamation);
library.add(faCircleInfo);
library.add(faChevronLeft);
library.add(faChevronRight);
library.add(faCircleXmark);
library.add(faCircleNotch);
library.add(faSliders);
library.add(faPlay);
library.add(faPause);
library.add(faGift);
dom.watch();

56
ts/utilities/vue-fo.ts Normal file
View file

@ -0,0 +1,56 @@
import type { App, Component } from "vue";
import { createApp } from "vue";
document.addEventListener("DOMContentLoaded", () => {
const setupApp = (app: App<Element>) => {
app.config.globalProperties.window = window;
app.config.globalProperties.document = document;
};
// Register components
/// <reference types="vite/client" />
const vues = import.meta.glob("./../components/*.vue") as Record<
string,
() => Promise<{ default: Component }>
>;
for (const vueCptName in vues) {
const vueCptPromise = vues[vueCptName];
let htmlKey = vueCptName.split("/").pop();
if (!htmlKey) {
throw new Error(`Cannot load ${vueCptName}`);
}
htmlKey = htmlKey
.split(".")[0]
.replace(/\.?([A-Z])/g, function (x, y) {
return "-" + y.toLowerCase();
})
.replace(/^-/, "")
.replace("-component", "");
const el = document.getElementById(htmlKey),
elGroup = document.getElementsByClassName(htmlKey);
// * Init using ID
if (el) {
vueCptPromise().then((vueParsedFile) => {
const app = createApp(vueParsedFile.default, {
json: el.dataset.json ?? {},
});
setupApp(app);
app.mount(el);
});
}
// * Init Using class
for (const grpEl of elGroup) {
// * Hack to prevent loop weirdness
vueCptPromise().then((vueParsedFile) => {
setTimeout(() => {
const app = createApp(vueParsedFile.default, {
json: (grpEl as HTMLElement).dataset.json ?? {},
});
setupApp(app);
app.mount(grpEl);
}, 500);
});
}
}
});

104
views/auth/login.blade.php Normal file
View file

@ -0,0 +1,104 @@
@extends('theme::layout')
@section('title', __('Connexion'))
@section('description', __('Connexion'))
@section('no-flash', true)
@section('content')
<div class="container pb-5 pt-5">
@error('email')
<div class="row">
<div class="col">
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<strong>{{ implode(',', $errors->get('email')) }}</strong>
<button class="btn-close" data-bs-dismiss="alert" type="button" aria-label="Close"></button>
</div>
</div>
</div>
@enderror
<div class="row mb-3">
<div class="col-12 col-md-6 text-md-end g-0">
<span class="h1 fw-bold text-uppercase text-tertiary d-block mb-5">{{ __('Je m\'inscris') }}</span>
<p class="mb-5">{{ __('Pour participer et tenter votre chance, inscrivez-vous !') }}</p>
<a class="btn btn-lg btn-tertiary" href="{{ route('fo.register') }}">{{ __('Inscription') }}</a>
</div>
<div class="vr bg-tertiary d-none d-md-inline-block mx-4 px-1"></div>
<div class="col g-0">
<hr class="border-tertiary d-md-none border-3 border opacity-25">
<span class="h1 fw-bold text-uppercase text-tertiary d-block mb-5">{{ __('Je me connecte') }}</span>
<p class="mb-5">
{{ __('Si vous possédez déjà un compte Club :company, vous pouvez utiliser les mêmes identifiants.', [
'company' => $settingsGlobal->company,
]) }}
</p>
<form class="needs-validation" method="POST" action="{{ route('fo.login') }}">
@csrf
<div class="row justify-content-center mb-3">
<div class="col-xl-8">
<div class="input-group has-validation">
<div class="form-floating @error('email') is-invalid @enderror">
<input class="form-control @error('email') is-invalid @enderror" id="email" name="email"
type="email" value="{{ old('email') }}" placeholder="name@example.com" required autocomplete="email"
autofocus>
<label for="email">{{ __('Email Address') }}</label>
</div>
@error('email')
<div class="invalid-feedback" role="alert">
<strong>{{ implode(',', $errors->get('email')) }}</strong>
</div>
@enderror
</div>
</div>
</div>
<div class="row justify-content-center mb-3">
<div class="col-xl-8">
<div class="input-group has-validation">
<div class="form-floating @error('password') is-invalid @enderror">
<input class="form-control @error('password') is-invalid @enderror" id="password" name="password"
type="password" placeholder="" required autocomplete="current-password">
<label for="password">{{ __('Password') }}</label>
</div>
@error('password')
<div class="invalid-feedback" role="alert">
<strong>{{ implode(',', $errors->get('password')) }}</strong>
</div>
@enderror
</div>
</div>
</div>
<div class="row justify-content-center mb-3">
<div class="col-xl-8">
<div class="form-check text-md-end">
<input class="form-check-input float-md-none" id="remember" name="remember" type="checkbox"
{{ old('remember') ? 'checked' : '' }}>
<label class="form-check-label" for="remember">
{{ __('Remember Me') }}
</label>
</div>
</div>
</div>
<div class="row justify-content-center mb-0">
<div class="col-xl-8">
<button class="btn btn-tertiary fw-bold text-uppercase" type="submit">
{{ __('Login') }}
</button>
@if (Route::has('fo.password.request'))
<a class="btn btn-link link-tertiary fw-bold" href="{{ route('fo.password.request') }}">
{{ __('Forgot Your Password?') }}
</a>
@endif
</div>
</div>
</form>
</div>
</div>
</div>
@endsection

View file

@ -0,0 +1,38 @@
<fieldset class="mb-3">
<legend class="text-center">{{ __('Vos coordonnées') }}</legend>
{{-- ADDRESS --}}
<div class="row justify-content-center">
<div class="{{ $colClasses }}">
@include('theme::auth.partials.inputs.address', ['required' => true])
</div>
</div>
{{-- ADDRESS2 --}}
<div class="row justify-content-center">
<div class="{{ $colClasses }}">
@include('theme::auth.partials.inputs.address2')
</div>
</div>
{{-- CITY --}}
<div class="row justify-content-center">
<div class="{{ $colClasses }}">
@include('theme::auth.partials.inputs.city', ['required' => true])
</div>
</div>
{{-- POSTCODE --}}
<div class="row justify-content-center">
<div class="{{ $colClasses }}">
@include('theme::auth.partials.inputs.postal_code', ['required' => true])
</div>
</div>
{{-- COUNTRY --}}
<div class="row justify-content-center">
<div class="{{ $colClasses }}">
@include('theme::auth.partials.inputs.country', ['required' => true])
</div>
</div>
</fieldset>

View file

@ -0,0 +1,26 @@
<fieldset class="mb-3">
<legend class="text-center">{{ __('Votre profil') }}</legend>
<div class="container-fluid">
{{-- FIRST_NAME --}}
<div class="row justify-content-center">
<div class="{{ $colClasses }}">
@include('theme::auth.partials.inputs.first_name', ['required' => true])
</div>
</div>
{{-- LAST NAME --}}
<div class="row justify-content-center">
<div class="{{ $colClasses }}">
@include('theme::auth.partials.inputs.last_name', ['required' => true])
</div>
</div>
{{-- BIRTH_DATE --}}
<div class="row justify-content-center">
<div class="{{ $colClasses }}">
@include('theme::auth.partials.inputs.birth_date', ['required' => true])
</div>
</div>
</div>
</fieldset>

View file

@ -0,0 +1,28 @@
<fieldset class="mb-3">
<legend class="text-center">{{ __('Vos identifiants') }}</legend>
<div class="container-fluid">
{{-- EMAIL --}}
<div class="row justify-content-center">
<div class="col col-md-10 col-lg-8 py-2">
@include('theme::auth.partials.inputs.email', ['required' => true])
</div>
</div>
{{-- PASSWORD --}}
<div class="row justify-content-center">
<div class="col col-md-10 col-lg-8 input-group d-flex justify-content-center py-2">
@include('theme::auth.partials.inputs.password', ['required' => true])
</div>
</div>
{{-- PASSWORD CONFIRMATION --}}
<div class="row justify-content-center">
<div class="col col-md-10 col-lg-8 input-group d-flex justify-content-center py-2">
@include('theme::auth.partials.inputs.password_confirmation', ['required' => true])
</div>
</div>
@include('theme::auth.password-min-strength')
</div>
</fieldset>

View file

@ -0,0 +1,18 @@
<div class="form-floating mb-3">
<input id="address" name="address" type="text" value="{{ old('address', $crmCustomer->address ?? null) }}"
placeholder="{{ __('Votre :attribute', [
'attribute' => __('validation.attributes.line_address_1'),
]) }}"
@class([
'form-control',
'mx-auto',
'is-invalid' => $errors->has('address'),
]) autocomplete="address-line1" @readonly(!empty($readonly)) @disabled(!empty($disabled)) @required(!empty($required)) />
<label for="address">{{ Str::ucfirst(__('validation.attributes.line_address_1')) }}@if (!empty($required))
*
@endif
</label>
@foreach ($errors->get('address') as $message)
<div class="invalid-feedback">{{ $message }}</div>
@endforeach
</div>

View file

@ -0,0 +1,18 @@
<div class="form-floating mb-3">
<input id="address2" name="address2" type="text" value="{{ old('address2', $crmCustomer->address2 ?? null) }}"
placeholder="{{ __('Votre :attribute', [
'attribute' => __('validation.attributes.line_address_2'),
]) }}"
@class([
'form-control',
'mx-auto',
'is-invalid' => $errors->has('address2'),
]) autocomplete="address-line2" @readonly(!empty($readonly)) @disabled(!empty($disabled)) @required(!empty($required)) />
<label for="address2">{{ Str::ucfirst(__('validation.attributes.line_address_2')) }}@if (!empty($required))
*
@endif
</label>
@foreach ($errors->get('address2') as $message)
<div class="invalid-feedback">{{ $message }}</div>
@endforeach
</div>

View file

@ -0,0 +1,17 @@
<div class="form-floating">
@php
$dataBirthDate = [
'id' => 'register-birth_date',
'class' => 'form-control mx-auto ' . ($errors->has('birth_date') ? 'is-invalid' : ''),
'name' => 'birth_date',
'placeholder' => Str::ucfirst(__('validation.attributes.date_of_birth')) . (!empty($required) ? '*' : ''),
'autocomplete' => 'bday',
'required' => !empty($required),
'value' => old('birth_date', $crmCustomer->birth_date ?? null),
];
@endphp
<div class="input-birth-date form-floating" data-json='@json($dataBirthDate)'></div>
@foreach ($errors->get('birth_date') as $message)
<div class="invalid-feedback d-block">{{ $message }}</div>
@endforeach
</div>

View file

@ -0,0 +1,16 @@
<div class="form-floating">
<input id="register-city" name="city" type="text" value="{{ old('city', $crmCustomer->city ?? null) }}" @class([
'form-control',
'mx-auto',
'is-invalid' => $errors->has('city'),
])
placeholder="{{ __('validation.attributes.city') }}*" autocomplete="address-level2" @readonly(!empty($readonly)) @disabled(!empty($disabled))
@required(!empty($required)) />
<label for="register-city">{{ Str::ucfirst(__('validation.attributes.city')) }}@if (!empty($required))
*
@endif
</label>
@foreach ($errors->get('city') as $message)
<div class="invalid-feedback">{{ $message }}</div>
@endforeach
</div>

View file

@ -0,0 +1,37 @@
<div class="form-floating mb-3">
@php
// * Avoir les DROM-COM + France
$franceCountries = collect(\LDC\LDCCRM\Enums\Country::getValidCountries())->filter(fn($enum) => !in_array($enum, [LDC\LDCCRM\Enums\Country::belgium(), LDC\LDCCRM\Enums\Country::luxembourg()]));
$countries = collect(\LDC\LDCCRM\Enums\Country::getValidCountries())->filter(fn($enum) => !$franceCountries->contains($enum));
$old_country = old('country', optional($crmCustomer->country ?? null)->value ?: null);
@endphp
<select id="country" name="country" aria-label="{{ Str::ucfirst(__('validation.attributes.country')) }}" @class([
'form-select',
'mx-auto',
'is-invalid' => $errors->has('country'),
])
@readonly(!empty($readonly)) @disabled(!empty($disabled)) @required(!empty($required))>
<option @selected(!$old_country) disabled>
{{ __('Votre :attribute', [
'attribute' => __('validation.attributes.country'),
]) }}
</option>
@foreach ($franceCountries as $countryEnum)
<option value="{{ $countryEnum->value }}" @selected($old_country == $countryEnum->value)>
{{ Str::ucfirst($countryEnum->label) }}
</option>
@endforeach
@foreach ($countries as $countryEnum)
<option value="{{ $countryEnum->value }}" @selected($old_country == $countryEnum->value)>
{{ Str::ucfirst($countryEnum->label) }}
</option>
@endforeach
</select>
<label for="country">{{ Str::ucfirst(__('validation.attributes.country')) }}@if (!empty($required))
*
@endif
</label>
@foreach ($errors->get('country') as $message)
<div class="invalid-feedback">{{ $message }}</div>
@endforeach
</div>

View file

@ -0,0 +1,16 @@
<div class="form-floating">
<input id="register-email" name="email" type="email" value="{{ old('email', $crmCustomer->email ?? null) }}"
@class([
'form-control',
'mx-auto',
'is-invalid' => $errors->has('email'),
]) placeholder="{{ __('validation.attributes.email') }}*" autocomplete="email" @readonly(!empty($readonly))
@readonly(!empty($readonly)) @disabled(!empty($disabled)) @required(!empty($required)) />
<label for="register-email">{{ Str::ucfirst(__('validation.attributes.email')) }}@if (!empty($required))
*
@endif
</label>
@foreach ($errors->get('email') as $message)
<div class="invalid-feedback">{{ $message }}</div>
@endforeach
</div>

View file

@ -0,0 +1,16 @@
<div class="form-floating">
<input id="register-lastname" name="lastname" type="text" value="{{ old('lastname', $crmCustomer->lastname ?? null) }}"
@class([
'form-control',
'mx-auto',
'is-invalid' => $errors->has('lastname'),
]) placeholder="{{ __('validation.attributes.last_name') }}*" autocomplete="given-name" @readonly(!empty($readonly))
@disabled(!empty($disabled)) @required(!empty($required)) />
<label for="register-lastname">{{ Str::ucfirst(__('validation.attributes.last_name')) }}@if (!empty($required))
*
@endif
</label>
@foreach ($errors->get('lastname') as $message)
<div class="invalid-feedback">{{ $message }}</div>
@endforeach
</div>

View file

@ -0,0 +1,16 @@
<div class="form-floating">
<input id="register-firstname" name="firstname" type="text" value="{{ old('firstname', $crmCustomer->firstname ?? null) }}"
@class([
'form-control',
'mx-auto',
'is-invalid' => $errors->has('firstname'),
]) placeholder="{{ __('validation.attributes.first_name') }}*" autocomplete="family-name" @readonly(!empty($readonly))
@disabled(!empty($disabled)) @required(!empty($required)) />
<label for="register-firstname">{{ Str::ucfirst(__('validation.attributes.first_name')) }}@if (!empty($required))
*
@endif
</label>
@foreach ($errors->get('firstname') as $message)
<div class="invalid-feedback">{{ $message }}</div>
@endforeach
</div>

View file

@ -0,0 +1,21 @@
<div class="input-group has-validation">
<div class="form-floating @if ($errors->has('password')) is-invalid @endif">
<input id="register-password" name="password" type="password" @class([
'form-control',
'rounded-0',
'rounded-start',
'is-invalid' => $errors->has('password'),
])
placeholder="{{ __('validation.attributes.password') }}*" autocomplete="new-password" @readonly(!empty($readonly))
@disabled(!empty($disabled)) @required(!empty($required)) />
<label for="register-password">{{ Str::ucfirst(__('validation.attributes.password')) }}@if (!empty($required))
*
@endif
</label>
</div>
@php $dataPassword = ['inputId' => 'register-password']; @endphp
<span class="password-visibility p-0" data-json='@json($dataPassword)'></span>
@foreach ($errors->get('password') as $message)
<div class="invalid-feedback">{{ $message }}</div>
@endforeach
</div>

View file

@ -0,0 +1,21 @@
<div class="input-group has-validation">
<div class="form-floating @if ($errors->has('password_confirmation')) is-invalid @endif">
<input id="register-password-confirmation" name="password_confirmation" type="password" @class([
'form-control',
'rounded-0',
'rounded-start',
'is-invalid' => $errors->has('password_confirmation'),
])
placeholder="{{ __('validation.attributes.password_confirmation') }}*" autocomplete="new-password" @readonly(!empty($readonly))
@disabled(!empty($disabled)) @required(!empty($required)) />
<label for="register-password-confirmation">{{ Str::ucfirst(__('validation.attributes.password_confirmation')) }}@if (!empty($required))
*
@endif
</label>
</div>
@php $dataConfirmPassword = ['inputId' => 'register-password-confirmation']; @endphp
<span class="password-visibility p-0" data-json='@json($dataConfirmPassword)'></span>
@foreach ($errors->get('password_confirmation') as $message)
<div class="invalid-feedback">{{ $message }}</div>
@endforeach
</div>

View file

@ -0,0 +1,18 @@
<div class="form-floating mb-3">
<input id="phone" name="phone" type="text" value="{{ old('phone', $crmCustomer->phone ?? null) }}"
placeholder="{{ __('Votre :attribute', [
'attribute' => __('validation.attributes.phone'),
]) }}"
@class([
'form-control',
'mx-auto',
'is-invalid' => $errors->has('phone'),
]) autocomplete="tel" @readonly(!empty($readonly)) @disabled(!empty($disabled)) @required(!empty($required)) />
<label for="phone">{{ Str::ucfirst(__('validation.attributes.phone')) }}@if (!empty($required))
*
@endif
</label>
@foreach ($errors->get('phone') as $message)
<div class="invalid-feedback">{{ $message }}</div>
@endforeach
</div>

View file

@ -0,0 +1,18 @@
<div class="form-floating mb-3">
<input id="postal_code" name="postal_code" type="text" value="{{ old('postal_code', $crmCustomer->postcode ?? null) }}"
placeholder="{{ __('Votre :attribute', [
'attribute' => __('validation.attributes.postal_code'),
]) }}"
@class([
'form-control',
'mx-auto',
'is-invalid' => $errors->has('postal_code'),
]) autocomplete="postal-code" @readonly(!empty($readonly)) @disabled(!empty($disabled)) @required(!empty($required)) />
<label for="postal_code">{{ Str::ucfirst(__('validation.attributes.postal_code')) }}@if (!empty($required))
*
@endif
</label>
@foreach ($errors->get('postal_code') as $message)
<div class="invalid-feedback">{{ $message }}</div>
@endforeach
</div>

View file

@ -0,0 +1,13 @@
<div class="row justify-content-center mb-3">
<div class="col col-md-8 text-dark lh-sm px-0 py-2 text-start">
<small>
{!! nl2br(
clean(
__(
"Le mot de passe doit avoir une longueur de 8 caractères minimum,\n doit contenir une lettre majuscule et une lettre minucule,\n doit contenir un caractère spécial comme une virgule par exemple,\n doit contenir un chiffre.",
),
),
) !!}
</small>
</div>
</div>

View file

@ -0,0 +1,53 @@
@extends('theme::layout')
@section('title', __('Confirmer son adresse e-mail'))
@section('description', __('Confirmer son adresse e-mail'))
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Confirm Password') }}</div>
<div class="card-body">
{{ __('Please confirm your password before continuing.') }}
<form method="POST" action="{{ route('fo.password.confirm') }}">
@csrf
<div class="row mb-3">
<label class="col-md-4 col-form-label text-md-end" for="password">{{ __('Password') }}</label>
<div class="col-md-6">
<input class="form-control @error('password') is-invalid @enderror" id="password" name="password"
type="password" required autocomplete="current-password">
@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-0">
<div class="col-md-8 offset-md-4">
<button class="btn btn-primary" type="submit">
{{ __('Confirm Password') }}
</button>
@if (Route::has('fo.password.request'))
<a class="btn btn-link" href="{{ route('fo.password.request') }}">
{{ __('Forgot Your Password?') }}
</a>
@endif
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection

View file

@ -0,0 +1,44 @@
@extends('theme::layout')
@section('title', __('Réinitialiser son mot de passe'))
@section('description', __('Réinitialiser son mot de passe'))
@section('content')
<div class="container pb-5 pt-5">
<div class="row justify-content-center mb-3">
<div class="col-md-8">
<h1 class="fw-bold text-tertiary text-uppercase text-center">{{ __('Reset Password') }}</h1>
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-8">
<form method="POST" action="{{ route('fo.password.email') }}">
@csrf
<div class="row mb-3">
<label class="col-md-4 col-form-label text-md-end" for="email">{{ __('Email Address') }}</label>
<div class="col-md-6">
<input class="form-control @error('email') is-invalid @enderror" id="email" name="email" type="email"
value="{{ old('email') }}" required autocomplete="email" autofocus>
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-0">
<div class="col-md-6 offset-md-4">
<button class="btn btn-primary" type="submit">
{{ __('Send Password Reset Link') }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
@endsection

Some files were not shown because too many files have changed in this diff Show more