feat: Commit initial avec application Quarkus JSF et page d'accueil
- Ajout de la configuration JSF/Quarkus - Ajout des contrôleurs et composants JSF - Ajout de la page d'accueil avec animations - Configuration Docker et environnement de build
This commit is contained in:
5
.dockerignore
Normal file
5
.dockerignore
Normal file
@@ -0,0 +1,5 @@
|
||||
*
|
||||
!target/*-runner
|
||||
!target/*-runner.jar
|
||||
!target/lib/*
|
||||
!target/quarkus-app/*
|
||||
107
.gitignore
vendored
Normal file
107
.gitignore
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
# Maven
|
||||
target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
release.properties
|
||||
.flattened-pom.xml
|
||||
|
||||
# Eclipse
|
||||
.project
|
||||
.classpath
|
||||
.settings/
|
||||
bin/
|
||||
|
||||
# IntelliJ
|
||||
.idea/
|
||||
*.ipr
|
||||
*.iml
|
||||
*.iws
|
||||
|
||||
# NetBeans
|
||||
nb-configuration.xml
|
||||
nbproject/
|
||||
nbactions.xml
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode/
|
||||
.factorypath
|
||||
|
||||
# OSX
|
||||
.DS_Store
|
||||
|
||||
# Windows
|
||||
Thumbs.db
|
||||
Desktop.ini
|
||||
|
||||
# Vim
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# patch
|
||||
*.orig
|
||||
*.rej
|
||||
|
||||
# Local environment
|
||||
.env
|
||||
.env.local
|
||||
.env.*
|
||||
|
||||
# Quarkus
|
||||
.quarkus/
|
||||
/.quarkus/cli/plugins/
|
||||
quarkus.log
|
||||
hs_err_pid*
|
||||
|
||||
# Application Specific
|
||||
.certs/
|
||||
.certificates/
|
||||
*.jks
|
||||
*.p12
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
log/
|
||||
logs/
|
||||
|
||||
# Temporary files
|
||||
*~
|
||||
*.bak
|
||||
*.tmp
|
||||
temp/
|
||||
|
||||
# Node (in case you add frontend tools later)
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
yarn-debug.log
|
||||
yarn-error.log
|
||||
|
||||
# Build output
|
||||
dist/
|
||||
build/
|
||||
out/
|
||||
|
||||
# Application specific properties
|
||||
src/main/resources/application-*.properties
|
||||
!src/main/resources/application.properties
|
||||
|
||||
# Compiled files
|
||||
*.class
|
||||
*.jar
|
||||
*.war
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
# Test coverage
|
||||
/coverage/
|
||||
.nyc_output/
|
||||
|
||||
# Maven Wrapper
|
||||
.mvn/
|
||||
mvnw
|
||||
mvnw.cmd
|
||||
|
||||
# Docker
|
||||
.dockerignore
|
||||
58
README.md
Normal file
58
README.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# lionsdev-client-impl-quarkus
|
||||
|
||||
This project uses Quarkus, the Supersonic Subatomic Java Framework.
|
||||
|
||||
If you want to learn more about Quarkus, please visit its website: <https://quarkus.io/>.
|
||||
|
||||
## Running the application in dev mode
|
||||
|
||||
You can run your application in dev mode that enables live coding using:
|
||||
|
||||
```shell script
|
||||
./mvnw quarkus:dev
|
||||
```
|
||||
|
||||
> **_NOTE:_** Quarkus now ships with a Dev UI, which is available in dev mode only at <http://localhost:8080/q/dev/>.
|
||||
|
||||
## Packaging and running the application
|
||||
|
||||
The application can be packaged using:
|
||||
|
||||
```shell script
|
||||
./mvnw package
|
||||
```
|
||||
|
||||
It produces the `quarkus-run.jar` file in the `target/quarkus-app/` directory.
|
||||
Be aware that it’s not an _über-jar_ as the dependencies are copied into the `target/quarkus-app/lib/` directory.
|
||||
|
||||
The application is now runnable using `java -jar target/quarkus-app/quarkus-run.jar`.
|
||||
|
||||
If you want to build an _über-jar_, execute the following command:
|
||||
|
||||
```shell script
|
||||
./mvnw package -Dquarkus.package.jar.type=uber-jar
|
||||
```
|
||||
|
||||
The application, packaged as an _über-jar_, is now runnable using `java -jar target/*-runner.jar`.
|
||||
|
||||
## Creating a native executable
|
||||
|
||||
You can create a native executable using:
|
||||
|
||||
```shell script
|
||||
./mvnw package -Dnative
|
||||
```
|
||||
|
||||
Or, if you don't have GraalVM installed, you can run the native executable build in a container using:
|
||||
|
||||
```shell script
|
||||
./mvnw package -Dnative -Dquarkus.native.container-build=true
|
||||
```
|
||||
|
||||
You can then execute your native executable with: `./target/lionsdev-client-impl-quarkus-1.0.0-SNAPSHOT-runner`
|
||||
|
||||
If you want to learn more about building native executables, please consult <https://quarkus.io/guides/maven-tooling>.
|
||||
|
||||
## Related Guides
|
||||
|
||||
- PrimeFaces ([guide](https://quarkiverse.github.io/quarkiverse-docs/quarkus-primefaces/dev/)): PrimeFaces - lets you utilize PrimeFaces and PF Extensions to make JavaServer Faces (JSF) development so much easier!
|
||||
111
pom.xml
Normal file
111
pom.xml
Normal file
@@ -0,0 +1,111 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>dev.lions</groupId>
|
||||
<artifactId>lionsdev-client-impl-quarkus</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<compiler-plugin.version>3.13.0</compiler-plugin.version>
|
||||
<maven.compiler.release>17</maven.compiler.release>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
|
||||
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
|
||||
<quarkus.platform.version>3.6.4</quarkus.platform.version>
|
||||
<skipITs>true</skipITs>
|
||||
<surefire-plugin.version>3.5.0</surefire-plugin.version>
|
||||
<myfaces.version>4.0.1</myfaces.version>
|
||||
<primefaces.version>13.0.4</primefaces.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${quarkus.platform.group-id}</groupId>
|
||||
<artifactId>${quarkus.platform.artifact-id}</artifactId>
|
||||
<version>${quarkus.platform.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<!-- Quarkus Core -->
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-undertow</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-arc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- MyFaces -->
|
||||
<dependency>
|
||||
<groupId>org.apache.myfaces.core</groupId>
|
||||
<artifactId>myfaces-api</artifactId>
|
||||
<version>${myfaces.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.myfaces.core</groupId>
|
||||
<artifactId>myfaces-impl</artifactId>
|
||||
<version>${myfaces.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- PrimeFaces -->
|
||||
<dependency>
|
||||
<groupId>io.quarkiverse.primefaces</groupId>
|
||||
<artifactId>quarkus-primefaces</artifactId>
|
||||
<version>3.14.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Test -->
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-junit5</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>${quarkus.platform.group-id}</groupId>
|
||||
<artifactId>quarkus-maven-plugin</artifactId>
|
||||
<version>${quarkus.platform.version}</version>
|
||||
<extensions>true</extensions>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>build</goal>
|
||||
<goal>generate-code</goal>
|
||||
<goal>generate-code-tests</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<parameters>true</parameters>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>${surefire-plugin.version}</version>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
|
||||
<maven.home>${maven.home}</maven.home>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
97
src/main/docker/Dockerfile.jvm
Normal file
97
src/main/docker/Dockerfile.jvm
Normal file
@@ -0,0 +1,97 @@
|
||||
####
|
||||
# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
|
||||
#
|
||||
# Before building the container image run:
|
||||
#
|
||||
# ./mvnw package
|
||||
#
|
||||
# Then, build the image with:
|
||||
#
|
||||
# docker build -f src/main/docker/Dockerfile.jvm -t quarkus/lionsdev-client-impl-quarkus-jvm .
|
||||
#
|
||||
# Then run the container using:
|
||||
#
|
||||
# docker run -i --rm -p 8080:8080 quarkus/lionsdev-client-impl-quarkus-jvm
|
||||
#
|
||||
# If you want to include the debug port into your docker image
|
||||
# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005.
|
||||
# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005
|
||||
# when running the container
|
||||
#
|
||||
# Then run the container using :
|
||||
#
|
||||
# docker run -i --rm -p 8080:8080 quarkus/lionsdev-client-impl-quarkus-jvm
|
||||
#
|
||||
# This image uses the `run-java.sh` script to run the application.
|
||||
# This scripts computes the command line to execute your Java application, and
|
||||
# includes memory/GC tuning.
|
||||
# You can configure the behavior using the following environment properties:
|
||||
# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class")
|
||||
# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options
|
||||
# in JAVA_OPTS (example: "-Dsome.property=foo")
|
||||
# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is
|
||||
# used to calculate a default maximal heap memory based on a containers restriction.
|
||||
# If used in a container without any memory constraints for the container then this
|
||||
# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio
|
||||
# of the container available memory as set here. The default is `50` which means 50%
|
||||
# of the available memory is used as an upper boundary. You can skip this mechanism by
|
||||
# setting this value to `0` in which case no `-Xmx` option is added.
|
||||
# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This
|
||||
# is used to calculate a default initial heap memory based on the maximum heap memory.
|
||||
# If used in a container without any memory constraints for the container then this
|
||||
# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio
|
||||
# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx`
|
||||
# is used as the initial heap size. You can skip this mechanism by setting this value
|
||||
# to `0` in which case no `-Xms` option is added (example: "25")
|
||||
# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS.
|
||||
# This is used to calculate the maximum value of the initial heap memory. If used in
|
||||
# a container without any memory constraints for the container then this option has
|
||||
# no effect. If there is a memory constraint then `-Xms` is limited to the value set
|
||||
# here. The default is 4096MB which means the calculated value of `-Xms` never will
|
||||
# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096")
|
||||
# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output
|
||||
# when things are happening. This option, if set to true, will set
|
||||
# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true").
|
||||
# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example:
|
||||
# true").
|
||||
# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787").
|
||||
# - CONTAINER_CORE_LIMIT: A calculated core limit as described in
|
||||
# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2")
|
||||
# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024").
|
||||
# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion.
|
||||
# (example: "20")
|
||||
# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking.
|
||||
# (example: "40")
|
||||
# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection.
|
||||
# (example: "4")
|
||||
# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus
|
||||
# previous GC times. (example: "90")
|
||||
# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20")
|
||||
# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100")
|
||||
# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should
|
||||
# contain the necessary JRE command-line options to specify the required GC, which
|
||||
# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC).
|
||||
# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080")
|
||||
# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080")
|
||||
# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be
|
||||
# accessed directly. (example: "foo.example.com,bar.example.com")
|
||||
#
|
||||
###
|
||||
FROM registry.access.redhat.com/ubi8/openjdk-17:1.20
|
||||
|
||||
ENV LANGUAGE='en_US:en'
|
||||
|
||||
|
||||
# We make four distinct layers so if there are application changes the library layers can be re-used
|
||||
COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/
|
||||
COPY --chown=185 target/quarkus-app/*.jar /deployments/
|
||||
COPY --chown=185 target/quarkus-app/app/ /deployments/app/
|
||||
COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/
|
||||
|
||||
EXPOSE 8080
|
||||
USER 185
|
||||
ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
|
||||
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
|
||||
|
||||
ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]
|
||||
|
||||
93
src/main/docker/Dockerfile.legacy-jar
Normal file
93
src/main/docker/Dockerfile.legacy-jar
Normal file
@@ -0,0 +1,93 @@
|
||||
####
|
||||
# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
|
||||
#
|
||||
# Before building the container image run:
|
||||
#
|
||||
# ./mvnw package -Dquarkus.package.jar.type=legacy-jar
|
||||
#
|
||||
# Then, build the image with:
|
||||
#
|
||||
# docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/lionsdev-client-impl-quarkus-legacy-jar .
|
||||
#
|
||||
# Then run the container using:
|
||||
#
|
||||
# docker run -i --rm -p 8080:8080 quarkus/lionsdev-client-impl-quarkus-legacy-jar
|
||||
#
|
||||
# If you want to include the debug port into your docker image
|
||||
# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005.
|
||||
# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005
|
||||
# when running the container
|
||||
#
|
||||
# Then run the container using :
|
||||
#
|
||||
# docker run -i --rm -p 8080:8080 quarkus/lionsdev-client-impl-quarkus-legacy-jar
|
||||
#
|
||||
# This image uses the `run-java.sh` script to run the application.
|
||||
# This scripts computes the command line to execute your Java application, and
|
||||
# includes memory/GC tuning.
|
||||
# You can configure the behavior using the following environment properties:
|
||||
# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class")
|
||||
# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options
|
||||
# in JAVA_OPTS (example: "-Dsome.property=foo")
|
||||
# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is
|
||||
# used to calculate a default maximal heap memory based on a containers restriction.
|
||||
# If used in a container without any memory constraints for the container then this
|
||||
# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio
|
||||
# of the container available memory as set here. The default is `50` which means 50%
|
||||
# of the available memory is used as an upper boundary. You can skip this mechanism by
|
||||
# setting this value to `0` in which case no `-Xmx` option is added.
|
||||
# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This
|
||||
# is used to calculate a default initial heap memory based on the maximum heap memory.
|
||||
# If used in a container without any memory constraints for the container then this
|
||||
# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio
|
||||
# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx`
|
||||
# is used as the initial heap size. You can skip this mechanism by setting this value
|
||||
# to `0` in which case no `-Xms` option is added (example: "25")
|
||||
# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS.
|
||||
# This is used to calculate the maximum value of the initial heap memory. If used in
|
||||
# a container without any memory constraints for the container then this option has
|
||||
# no effect. If there is a memory constraint then `-Xms` is limited to the value set
|
||||
# here. The default is 4096MB which means the calculated value of `-Xms` never will
|
||||
# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096")
|
||||
# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output
|
||||
# when things are happening. This option, if set to true, will set
|
||||
# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true").
|
||||
# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example:
|
||||
# true").
|
||||
# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787").
|
||||
# - CONTAINER_CORE_LIMIT: A calculated core limit as described in
|
||||
# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2")
|
||||
# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024").
|
||||
# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion.
|
||||
# (example: "20")
|
||||
# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking.
|
||||
# (example: "40")
|
||||
# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection.
|
||||
# (example: "4")
|
||||
# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus
|
||||
# previous GC times. (example: "90")
|
||||
# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20")
|
||||
# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100")
|
||||
# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should
|
||||
# contain the necessary JRE command-line options to specify the required GC, which
|
||||
# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC).
|
||||
# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080")
|
||||
# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080")
|
||||
# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be
|
||||
# accessed directly. (example: "foo.example.com,bar.example.com")
|
||||
#
|
||||
###
|
||||
FROM registry.access.redhat.com/ubi8/openjdk-17:1.20
|
||||
|
||||
ENV LANGUAGE='en_US:en'
|
||||
|
||||
|
||||
COPY target/lib/* /deployments/lib/
|
||||
COPY target/*-runner.jar /deployments/quarkus-run.jar
|
||||
|
||||
EXPOSE 8080
|
||||
USER 185
|
||||
ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
|
||||
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
|
||||
|
||||
ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]
|
||||
27
src/main/docker/Dockerfile.native
Normal file
27
src/main/docker/Dockerfile.native
Normal file
@@ -0,0 +1,27 @@
|
||||
####
|
||||
# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode.
|
||||
#
|
||||
# Before building the container image run:
|
||||
#
|
||||
# ./mvnw package -Dnative
|
||||
#
|
||||
# Then, build the image with:
|
||||
#
|
||||
# docker build -f src/main/docker/Dockerfile.native -t quarkus/lionsdev-client-impl-quarkus .
|
||||
#
|
||||
# Then run the container using:
|
||||
#
|
||||
# docker run -i --rm -p 8080:8080 quarkus/lionsdev-client-impl-quarkus
|
||||
#
|
||||
###
|
||||
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.10
|
||||
WORKDIR /work/
|
||||
RUN chown 1001 /work \
|
||||
&& chmod "g+rwX" /work \
|
||||
&& chown 1001:root /work
|
||||
COPY --chown=1001:root target/*-runner /work/application
|
||||
|
||||
EXPOSE 8080
|
||||
USER 1001
|
||||
|
||||
ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"]
|
||||
30
src/main/docker/Dockerfile.native-micro
Normal file
30
src/main/docker/Dockerfile.native-micro
Normal file
@@ -0,0 +1,30 @@
|
||||
####
|
||||
# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode.
|
||||
# It uses a micro base image, tuned for Quarkus native executables.
|
||||
# It reduces the size of the resulting container image.
|
||||
# Check https://quarkus.io/guides/quarkus-runtime-base-image for further information about this image.
|
||||
#
|
||||
# Before building the container image run:
|
||||
#
|
||||
# ./mvnw package -Dnative
|
||||
#
|
||||
# Then, build the image with:
|
||||
#
|
||||
# docker build -f src/main/docker/Dockerfile.native-micro -t quarkus/lionsdev-client-impl-quarkus .
|
||||
#
|
||||
# Then run the container using:
|
||||
#
|
||||
# docker run -i --rm -p 8080:8080 quarkus/lionsdev-client-impl-quarkus
|
||||
#
|
||||
###
|
||||
FROM quay.io/quarkus/quarkus-micro-image:2.0
|
||||
WORKDIR /work/
|
||||
RUN chown 1001 /work \
|
||||
&& chmod "g+rwX" /work \
|
||||
&& chown 1001:root /work
|
||||
COPY --chown=1001:root target/*-runner /work/application
|
||||
|
||||
EXPOSE 8080
|
||||
USER 1001
|
||||
|
||||
ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"]
|
||||
9
src/main/java/dev/lions/config/JSFConfiguration.java
Normal file
9
src/main/java/dev/lions/config/JSFConfiguration.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package dev.lions.config;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.faces.annotation.FacesConfig;
|
||||
|
||||
@ApplicationScoped
|
||||
@FacesConfig
|
||||
public class JSFConfiguration {
|
||||
}
|
||||
17
src/main/java/dev/lions/controllers/HomeController.java
Normal file
17
src/main/java/dev/lions/controllers/HomeController.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package dev.lions.controllers;
|
||||
|
||||
import jakarta.enterprise.context.RequestScoped;
|
||||
import jakarta.inject.Named;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Named
|
||||
@RequestScoped
|
||||
public class HomeController implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public String getWelcomeMessage() {
|
||||
System.out.println("HomeController.getWelcomeMessage() called");
|
||||
return "Welcome to Lions Dev";
|
||||
}
|
||||
}
|
||||
19
src/main/java/dev/lions/controllers/IndexController.java
Normal file
19
src/main/java/dev/lions/controllers/IndexController.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package dev.lions.controllers;
|
||||
|
||||
import jakarta.enterprise.context.RequestScoped;
|
||||
import jakarta.inject.Named;
|
||||
|
||||
@Named
|
||||
@RequestScoped
|
||||
public class IndexController {
|
||||
|
||||
private String message = "Welcome to Lions Dev!";
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
28
src/main/resources/META-INF/faces-config.xml
Normal file
28
src/main/resources/META-INF/faces-config.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<faces-config version="4.0"
|
||||
xmlns="https://jakarta.ee/xml/ns/jakartaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
|
||||
https://jakarta.ee/xml/ns/jakartaee/web-facesconfig_4_0.xsd">
|
||||
|
||||
<name>LionsDev</name>
|
||||
|
||||
<application>
|
||||
<locale-config>
|
||||
<default-locale>en</default-locale>
|
||||
<supported-locale>fr</supported-locale>
|
||||
</locale-config>
|
||||
</application>
|
||||
|
||||
<navigation-rule>
|
||||
<from-view-id>*</from-view-id>
|
||||
|
||||
<navigation-case>
|
||||
<description>Page index</description>
|
||||
<from-outcome>index</from-outcome>
|
||||
<to-view-id>/private/index.xhtml</to-view-id>
|
||||
<redirect/>
|
||||
</navigation-case>
|
||||
</navigation-rule>
|
||||
|
||||
</faces-config>
|
||||
@@ -0,0 +1,73 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="jakarta.faces.html"
|
||||
xmlns:f="jakarta.faces.core"
|
||||
xmlns:ui="jakarta.faces.facelets"
|
||||
xmlns:p="http://primefaces.org/ui">
|
||||
|
||||
<h:head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Lions Dev - <ui:insert name="title">Welcome</ui:insert></title>
|
||||
<h:outputStylesheet name="css/custom.css" />
|
||||
<h:outputStylesheet name="css/animations.css" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" />
|
||||
</h:head>
|
||||
|
||||
<h:body>
|
||||
<div class="layout-wrapper">
|
||||
<!-- Header -->
|
||||
<header class="layout-header">
|
||||
<div class="header-content">
|
||||
<div class="logo">
|
||||
<h:graphicImage name="images/logo.png" alt="Lions Dev Logo" height="50"/>
|
||||
</div>
|
||||
<nav>
|
||||
<ul class="nav-list">
|
||||
<li><a href="#home" class="nav-link">Accueil</a></li>
|
||||
<li><a href="#services" class="nav-link">Services</a></li>
|
||||
<li><a href="#contact" class="nav-link nav-button">Contact</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="mobile-menu-button">
|
||||
<i class="fas fa-bars"></i>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main>
|
||||
<ui:insert name="content">
|
||||
<p>Default content</p>
|
||||
</ui:insert>
|
||||
</main>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer class="layout-footer">
|
||||
<div class="footer-content">
|
||||
<div class="footer-section">
|
||||
<h3>À propos</h3>
|
||||
<p>Lions Dev - Intégrateur de solutions digitales</p>
|
||||
</div>
|
||||
<div class="footer-section">
|
||||
<h3>Contact</h3>
|
||||
<p>Email: contact@lions.dev</p>
|
||||
</div>
|
||||
<div class="footer-section">
|
||||
<h3>Suivez-nous</h3>
|
||||
<div class="social-links">
|
||||
<a href="#"><i class="fab fa-linkedin"></i></a>
|
||||
<a href="#"><i class="fab fa-github"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<p>© 2024 Lions Dev. Tous droits réservés.</p>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<h:outputScript name="js/custom.js" />
|
||||
<h:outputScript name="js/animations.js" />
|
||||
</h:body>
|
||||
</html>
|
||||
162
src/main/resources/META-INF/resources/css/animations.css
Normal file
162
src/main/resources/META-INF/resources/css/animations.css
Normal file
@@ -0,0 +1,162 @@
|
||||
.animate-on-scroll {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
transition: all 0.6s ease-out;
|
||||
}
|
||||
|
||||
.animate-on-scroll.animated {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.fade-in {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
transition: all 0.6s ease-out;
|
||||
}
|
||||
|
||||
.slide-in-left {
|
||||
opacity: 0;
|
||||
transform: translateX(-50px);
|
||||
transition: all 0.6s ease-out;
|
||||
}
|
||||
|
||||
.slide-in-right {
|
||||
opacity: 0;
|
||||
transform: translateX(50px);
|
||||
transition: all 0.6s ease-out;
|
||||
}
|
||||
|
||||
.animated {
|
||||
opacity: 1;
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
|
||||
.hover-effect {
|
||||
transition: transform 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.hover-effect:hover {
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
|
||||
.icon-animate {
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.card-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(33, 150, 243, 0.9);
|
||||
opacity: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transition: opacity 0.3s ease-in-out;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.overlay-text {
|
||||
color: white;
|
||||
font-size: 1.2rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.pulse-animation {
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Stats Container Styles */
|
||||
.stats-container {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin: 2rem 0;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
text-align: center;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.counter {
|
||||
font-size: 2.5rem;
|
||||
font-weight: bold;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
/* Loading Button Styles */
|
||||
.loading-button {
|
||||
position: relative;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.loading-button.loading {
|
||||
background-color: #ccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.loading-button.loading::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
top: 50%;
|
||||
right: 10px;
|
||||
transform: translateY(-50%);
|
||||
border: 2px solid #fff;
|
||||
border-radius: 50%;
|
||||
border-top-color: transparent;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: translateY(-50%) rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Dans animations.css */
|
||||
.service-card {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.service-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(45deg, var(--primary-color), var(--secondary-color));
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.service-card:hover::before {
|
||||
opacity: 0.1;
|
||||
}
|
||||
|
||||
.service-card .icon-animate {
|
||||
font-size: 2.5rem;
|
||||
color: var(--primary-color);
|
||||
margin-bottom: 1rem;
|
||||
display: inline-block;
|
||||
}
|
||||
219
src/main/resources/META-INF/resources/css/custom.css
Normal file
219
src/main/resources/META-INF/resources/css/custom.css
Normal file
@@ -0,0 +1,219 @@
|
||||
/* Global Styles */
|
||||
:root {
|
||||
--primary-color: #2196F3;
|
||||
--secondary-color: #1976D2;
|
||||
--text-color: #333333;
|
||||
--background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
color: var(--text-color);
|
||||
background-color: var(--background-color);
|
||||
}
|
||||
|
||||
/* Layout */
|
||||
.layout-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
.layout-header {
|
||||
background-color: var(--background-color);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
padding: 1rem 2rem;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.nav-list {
|
||||
display: flex;
|
||||
list-style: none;
|
||||
gap: 2rem;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.nav-button {
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 4px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Hero Section */
|
||||
.hero-section {
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)),
|
||||
url('#{resource["images/pattern.png"]}') repeat;
|
||||
color: white;
|
||||
padding: 4rem 2rem;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.hero-content {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.hero-button {
|
||||
font-size: 1.2rem;
|
||||
padding: 1rem 2rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.hero-section::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(45deg, rgba(33, 150, 243, 0.9), rgba(25, 118, 210, 0.9));
|
||||
}
|
||||
/* Services Section */
|
||||
.services-section {
|
||||
padding: 4rem 2rem;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.service-card {
|
||||
background-color: white;
|
||||
padding: 2rem;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
.layout-footer {
|
||||
background-color: #333;
|
||||
color: white;
|
||||
padding: 3rem 2rem 1rem;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.footer-content {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 2rem;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.footer-bottom {
|
||||
text-align: center;
|
||||
padding-top: 2rem;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
/* Responsive Design */
|
||||
@media (max-width: 768px) {
|
||||
.nav-list {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.layout-header {
|
||||
background-color: var(--background-color);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
padding: 1rem 2rem;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
z-index: 1000;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.layout-header.scroll-down {
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
.layout-header.scroll-up {
|
||||
transform: translateY(0);
|
||||
background-color: rgba(255, 255, 255, 0.95);
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* Ajout d'un padding-top au main pour compenser le header fixe */
|
||||
main {
|
||||
padding-top: 80px;
|
||||
}
|
||||
|
||||
/* Amélioration du style des boutons */
|
||||
.hero-button {
|
||||
background: linear-gradient(45deg, var(--primary-color), var(--secondary-color));
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 1rem 2.5rem;
|
||||
border-radius: 50px;
|
||||
font-size: 1.1rem;
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
box-shadow: 0 4px 15px rgba(33, 150, 243, 0.3);
|
||||
}
|
||||
|
||||
.hero-button:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 20px rgba(33, 150, 243, 0.4);
|
||||
}
|
||||
|
||||
/* Style pour la grille de services */
|
||||
.services-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 2rem;
|
||||
padding: 2rem;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.mobile-menu-button {
|
||||
display: none;
|
||||
font-size: 1.5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.mobile-menu-button {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.nav-list {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: white;
|
||||
flex-direction: column;
|
||||
padding: 1rem;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nav-list.active {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.nav-list li {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
}
|
||||
BIN
src/main/resources/META-INF/resources/images/logo.png
Normal file
BIN
src/main/resources/META-INF/resources/images/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
119
src/main/resources/META-INF/resources/js/animations.js
Normal file
119
src/main/resources/META-INF/resources/js/animations.js
Normal file
@@ -0,0 +1,119 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Initialize animations
|
||||
initializeAnimations();
|
||||
// Start counters when visible
|
||||
initializeCounters();
|
||||
// Initialize parallax effect
|
||||
initializeParallax();
|
||||
});
|
||||
|
||||
function initializeAnimations() {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.classList.add('animated');
|
||||
if (entry.target.classList.contains('fade-in')) {
|
||||
entry.target.style.opacity = '1';
|
||||
entry.target.style.transform = 'translateY(0)';
|
||||
}
|
||||
}
|
||||
});
|
||||
}, { threshold: 0.1 });
|
||||
|
||||
// Observe all elements with animation classes
|
||||
document.querySelectorAll('.animate-on-scroll, .fade-in, .slide-in-left, .slide-in-right')
|
||||
.forEach(element => observer.observe(element));
|
||||
}
|
||||
|
||||
function handleCardHover(card, isHovering) {
|
||||
const icon = card.querySelector('.icon-animate');
|
||||
const overlay = card.querySelector('.card-overlay');
|
||||
|
||||
if (isHovering) {
|
||||
icon.style.transform = 'scale(1.2) translateY(-10px)';
|
||||
overlay.style.opacity = '1';
|
||||
} else {
|
||||
icon.style.transform = 'scale(1) translateY(0)';
|
||||
overlay.style.opacity = '0';
|
||||
}
|
||||
}
|
||||
|
||||
function initializeCounters() {
|
||||
const counterObserver = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
const counter = entry.target;
|
||||
const target = parseInt(counter.dataset.count);
|
||||
animateCounter(counter, target);
|
||||
counterObserver.unobserve(counter);
|
||||
}
|
||||
});
|
||||
}, { threshold: 0.5 });
|
||||
|
||||
document.querySelectorAll('.stat-item').forEach(stat => {
|
||||
counterObserver.observe(stat);
|
||||
});
|
||||
}
|
||||
|
||||
function animateCounter(element, target) {
|
||||
const counter = element.querySelector('.counter');
|
||||
let current = 0;
|
||||
const increment = target / 50; // Divide animation into 50 steps
|
||||
const duration = 2000; // 2 seconds
|
||||
const interval = duration / 50;
|
||||
|
||||
const timer = setInterval(() => {
|
||||
current += increment;
|
||||
counter.textContent = Math.round(current);
|
||||
|
||||
if (current >= target) {
|
||||
counter.textContent = target;
|
||||
clearInterval(timer);
|
||||
}
|
||||
}, interval);
|
||||
}
|
||||
|
||||
function initializeParallax() {
|
||||
window.addEventListener('scroll', () => {
|
||||
const parallaxElements = document.querySelectorAll('[data-parallax="scroll"]');
|
||||
|
||||
parallaxElements.forEach(element => {
|
||||
const speed = element.dataset.speed || 0.5;
|
||||
const offset = window.pageYOffset;
|
||||
element.style.backgroundPositionY = `${offset * speed}px`;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function handleButtonClick(button) {
|
||||
// Add loading state
|
||||
button.classList.add('loading');
|
||||
button.disabled = true;
|
||||
|
||||
// Store original text
|
||||
const originalText = button.textContent;
|
||||
button.textContent = 'Loading...';
|
||||
|
||||
// Simulate loading (remove in production)
|
||||
setTimeout(() => {
|
||||
button.classList.remove('loading');
|
||||
button.disabled = false;
|
||||
button.textContent = originalText;
|
||||
}, 1000);
|
||||
|
||||
return true; // Allow navigation to proceed
|
||||
}
|
||||
|
||||
// Add smooth scrolling for all anchor links
|
||||
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
||||
anchor.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
const target = document.querySelector(this.getAttribute('href'));
|
||||
if (target) {
|
||||
target.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'start'
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
176
src/main/resources/META-INF/resources/js/custom.js
Normal file
176
src/main/resources/META-INF/resources/js/custom.js
Normal file
@@ -0,0 +1,176 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Navigation mobile toggle
|
||||
const mobileMenuButton = document.querySelector('.mobile-menu-button');
|
||||
const navList = document.querySelector('.nav-list');
|
||||
|
||||
if (mobileMenuButton) {
|
||||
mobileMenuButton.addEventListener('click', function() {
|
||||
navList.classList.toggle('active');
|
||||
});
|
||||
}
|
||||
|
||||
// Smooth scrolling for anchor links
|
||||
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
||||
anchor.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
const target = document.querySelector(this.getAttribute('href'));
|
||||
if (target) {
|
||||
target.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'start'
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Header scroll effect
|
||||
const header = document.querySelector('.layout-header');
|
||||
let lastScroll = 0;
|
||||
|
||||
window.addEventListener('scroll', () => {
|
||||
const currentScroll = window.pageYOffset;
|
||||
|
||||
if (currentScroll <= 0) {
|
||||
header.classList.remove('scroll-up');
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentScroll > lastScroll && !header.classList.contains('scroll-down')) {
|
||||
// Down
|
||||
header.classList.remove('scroll-up');
|
||||
header.classList.add('scroll-down');
|
||||
} else if (currentScroll < lastScroll && header.classList.contains('scroll-down')) {
|
||||
// Up
|
||||
header.classList.remove('scroll-down');
|
||||
header.classList.add('scroll-up');
|
||||
}
|
||||
lastScroll = currentScroll;
|
||||
});
|
||||
|
||||
// Intersection Observer for animations
|
||||
const animateOnScroll = () => {
|
||||
const elements = document.querySelectorAll('.animate-on-scroll');
|
||||
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.classList.add('animated');
|
||||
}
|
||||
});
|
||||
}, {
|
||||
threshold: 0.1
|
||||
});
|
||||
|
||||
elements.forEach(element => {
|
||||
observer.observe(element);
|
||||
});
|
||||
};
|
||||
|
||||
animateOnScroll();
|
||||
|
||||
// Form validation enhancement
|
||||
const enhanceFormValidation = () => {
|
||||
const forms = document.querySelectorAll('form');
|
||||
|
||||
forms.forEach(form => {
|
||||
const inputs = form.querySelectorAll('input, textarea');
|
||||
|
||||
inputs.forEach(input => {
|
||||
// Real-time validation
|
||||
input.addEventListener('input', function() {
|
||||
validateInput(this);
|
||||
});
|
||||
|
||||
// Blur validation
|
||||
input.addEventListener('blur', function() {
|
||||
validateInput(this);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const validateInput = (input) => {
|
||||
const parent = input.parentElement;
|
||||
const errorElement = parent.querySelector('.error-message') ||
|
||||
document.createElement('span');
|
||||
|
||||
errorElement.classList.add('error-message');
|
||||
|
||||
if (!input.value && input.hasAttribute('required')) {
|
||||
errorElement.textContent = 'Ce champ est requis';
|
||||
!parent.contains(errorElement) && parent.appendChild(errorElement);
|
||||
} else if (input.type === 'email' && !validateEmail(input.value)) {
|
||||
errorElement.textContent = 'Email invalide';
|
||||
!parent.contains(errorElement) && parent.appendChild(errorElement);
|
||||
} else {
|
||||
errorElement.remove();
|
||||
}
|
||||
};
|
||||
|
||||
const validateEmail = (email) => {
|
||||
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
||||
};
|
||||
|
||||
enhanceFormValidation();
|
||||
|
||||
// Loading state management for buttons
|
||||
const setupLoadingButtons = () => {
|
||||
const buttons = document.querySelectorAll('.loading-button');
|
||||
|
||||
buttons.forEach(button => {
|
||||
button.addEventListener('click', function(e) {
|
||||
if (!this.classList.contains('loading')) {
|
||||
this.classList.add('loading');
|
||||
this.setAttribute('disabled', 'disabled');
|
||||
|
||||
// Store original text
|
||||
const originalText = this.textContent;
|
||||
this.setAttribute('data-original-text', originalText);
|
||||
this.textContent = 'Chargement...';
|
||||
|
||||
// Simulate loading (remove in production and handle with actual form submission)
|
||||
setTimeout(() => {
|
||||
this.classList.remove('loading');
|
||||
this.removeAttribute('disabled');
|
||||
this.textContent = originalText;
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
setupLoadingButtons();
|
||||
|
||||
// Lazy loading for images
|
||||
const setupLazyLoading = () => {
|
||||
const images = document.querySelectorAll('img[data-src]');
|
||||
|
||||
const imageObserver = new IntersectionObserver((entries, observer) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
const img = entry.target;
|
||||
img.src = img.dataset.src;
|
||||
img.removeAttribute('data-src');
|
||||
observer.unobserve(img);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
images.forEach(img => imageObserver.observe(img));
|
||||
};
|
||||
|
||||
setupLazyLoading();
|
||||
});
|
||||
|
||||
// Service Worker Registration for PWA support
|
||||
if ('serviceWorker' in navigator) {
|
||||
window.addEventListener('load', () => {
|
||||
navigator.serviceWorker.register('/sw.js')
|
||||
.then(registration => {
|
||||
console.log('ServiceWorker registration successful');
|
||||
})
|
||||
.catch(error => {
|
||||
console.log('ServiceWorker registration failed:', error);
|
||||
});
|
||||
});
|
||||
}
|
||||
93
src/main/resources/META-INF/resources/private/index.xhtml
Normal file
93
src/main/resources/META-INF/resources/private/index.xhtml
Normal file
@@ -0,0 +1,93 @@
|
||||
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="jakarta.faces.html"
|
||||
xmlns:ui="jakarta.faces.facelets"
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/WEB-INF/template/page.xhtml">
|
||||
|
||||
<ui:define name="title">Accueil</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- Hero Section -->
|
||||
<section class="hero-section" id="home">
|
||||
<div class="hero-content fade-in">
|
||||
<h1>#{homeController.welcomeMessage}</h1>
|
||||
<p>Solutions digitales innovantes pour vos projets</p>
|
||||
<p:button value="Découvrir nos services" styleClass="hero-button pulse-animation" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Services Section -->
|
||||
<section class="services-section" id="services">
|
||||
<div class="services-content">
|
||||
<h2 class="section-title animate-on-scroll">Nos Services</h2>
|
||||
<div class="services-grid">
|
||||
<div class="service-card hover-effect animate-on-scroll">
|
||||
<i class="fas fa-code icon-animate"></i>
|
||||
<h3>Développement Web</h3>
|
||||
<p>Applications web modernes et performantes</p>
|
||||
<div class="card-overlay">
|
||||
<span class="overlay-text">En savoir plus</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="service-card hover-effect animate-on-scroll">
|
||||
<i class="fas fa-mobile-alt icon-animate"></i>
|
||||
<h3>Applications Mobiles</h3>
|
||||
<p>Solutions mobiles cross-platform</p>
|
||||
<div class="card-overlay">
|
||||
<span class="overlay-text">En savoir plus</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="service-card hover-effect animate-on-scroll">
|
||||
<i class="fas fa-cloud icon-animate"></i>
|
||||
<h3>Cloud Solutions</h3>
|
||||
<p>Infrastructure cloud sécurisée</p>
|
||||
<div class="card-overlay">
|
||||
<span class="overlay-text">En savoir plus</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Stats Section -->
|
||||
<section class="stats-section">
|
||||
<div class="stats-container">
|
||||
<div class="stat-item" data-count="100">
|
||||
<div class="counter">0</div>
|
||||
<p>Projets Réalisés</p>
|
||||
</div>
|
||||
<div class="stat-item" data-count="50">
|
||||
<div class="counter">0</div>
|
||||
<p>Clients Satisfaits</p>
|
||||
</div>
|
||||
<div class="stat-item" data-count="5">
|
||||
<div class="counter">0</div>
|
||||
<p>Années d'Expérience</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Contact Section -->
|
||||
<section class="contact-section" id="contact">
|
||||
<h:form id="contactForm">
|
||||
<div class="contact-content slide-in-right">
|
||||
<h2>Contactez-nous</h2>
|
||||
<div class="form-group">
|
||||
<p:inputText placeholder="Votre nom" required="true" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<p:inputText placeholder="Votre email" required="true" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<p:inputTextarea placeholder="Votre message" required="true" />
|
||||
</div>
|
||||
<p:commandButton value="Envoyer" styleClass="loading-button"
|
||||
onclick="return handleButtonClick(this);" />
|
||||
</div>
|
||||
</h:form>
|
||||
</section>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
25
src/main/resources/META-INF/web.xml
Normal file
25
src/main/resources/META-INF/web.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app version="6.0" xmlns="https://jakarta.ee/xml/ns/jakartaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd">
|
||||
|
||||
<welcome-file-list>
|
||||
<welcome-file>private/index.xhtml</welcome-file>
|
||||
</welcome-file-list>
|
||||
|
||||
<context-param>
|
||||
<param-name>jakarta.faces.PROJECT_STAGE</param-name>
|
||||
<param-value>Development</param-value>
|
||||
</context-param>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>Faces Servlet</servlet-name>
|
||||
<servlet-class>jakarta.faces.webapp.FacesServlet</servlet-class>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>Faces Servlet</servlet-name>
|
||||
<url-pattern>*.xhtml</url-pattern>
|
||||
</servlet-mapping>
|
||||
</web-app>
|
||||
22
src/main/resources/application.properties
Normal file
22
src/main/resources/application.properties
Normal file
@@ -0,0 +1,22 @@
|
||||
# Configuration serveur
|
||||
quarkus.http.port=8707
|
||||
quarkus.servlet.context-path=/lions-dev
|
||||
|
||||
# Configuration JSF
|
||||
quarkus.faces.enable=true
|
||||
quarkus.faces.servlet-mappings=*.xhtml
|
||||
quarkus.faces.project-stage=Development
|
||||
|
||||
# Configuration chemins d'acc<63>s
|
||||
quarkus.http.auth.permission.public.paths=/private/*,/index.xhtml
|
||||
quarkus.http.auth.permission.public.policy=permit
|
||||
|
||||
# Configuration ressources statiques
|
||||
quarkus.http.static-resources.enabled=true
|
||||
|
||||
# Configuration PrimeFaces
|
||||
quarkus.primefaces.theme=saga
|
||||
|
||||
# Configuration MyFaces
|
||||
quarkus.myfaces.mapping-suffix=.xhtml
|
||||
jakarta.faces.PROJECT_STAGE=Development
|
||||
Reference in New Issue
Block a user