Files
primefaces-freya-extension/FREYA_USAGE_GUIDE.md

18 KiB

Guide d'Utilisation - Freya avec PrimeFaces

Version : Freya 5.0.0 + PrimeFaces 14.0.0 Date : 2025-12-25 Sources : Documentation officielle Freya et exemples


🎯 Introduction

Ce guide montre comment utiliser les composants PrimeFaces standards avec le thème Freya dans vos applications Quarkus, basé sur les exemples officiels de Freya 5.0.0.

Important : Freya est un thème CSS pour PrimeFaces, pas une bibliothèque de composants. Vous utilisez les composants PrimeFaces standards (p:inputText, p:dataTable, etc.) avec les classes CSS de Freya.


📦 Installation

1. Dépendances Maven

<dependency>
    <groupId>dev.lions</groupId>
    <artifactId>primefaces-freya-extension</artifactId>
    <version>1.0.0-SNAPSHOT</version>
</dependency>

Cette extension fournit :

  • Thème Freya
  • Templates de layout
  • Composant FreyaMenu
  • Bean GuestPreferences

2. Configuration

application.properties :

primefaces.THEME=freya
primefaces.FONT_AWESOME=true
primefaces.CLIENT_SIDE_VALIDATION=true
primefaces.MOVE_SCRIPTS_TO_BOTTOM=true

🎨 Classes CSS Freya

Layout Classes (PrimeFlex)

Freya utilise PrimeFlex pour le layout :

<div class="grid">                    <!-- Grille responsive -->
    <div class="col-12 md:col-6">    <!-- Colonne : 12 cols mobile, 6 desktop -->
        <div class="card">            <!-- Carte Freya -->
            <!-- Contenu -->
        </div>
    </div>
</div>

Classes principales :

  • grid - Conteneur grille
  • col-{n} - Colonnes (1-12)
  • md:col-{n}, lg:col-{n} - Breakpoints responsive
  • card - Carte Freya avec ombre et border-radius
  • ui-fluid - Inputs 100% width

Form Classes

Pattern Field (recommandé) :

<div class="field">
    <p:outputLabel for="name" value="Nom" />
    <p:inputText id="name" value="#{bean.nom}" />
    <p:message for="name" />
</div>

Grid Formgrid :

<div class="grid formgrid">
    <div class="col-12 md:col-6">
        <div class="field">
            <p:outputLabel for="firstname" value="Prénom" />
            <p:inputText id="firstname" value="#{bean.prenom}" />
        </div>
    </div>
    <div class="col-12 md:col-6">
        <div class="field">
            <p:outputLabel for="lastname" value="Nom" />
            <p:inputText id="lastname" value="#{bean.nom}" />
        </div>
    </div>
</div>

Float Label :

<span class="ui-float-label">
    <p:inputText id="float-input" value="#{bean.username}" />
    <p:outputLabel for="@previous" value="Username" />
</span>

Icons in Inputs

<span class="ui-input-icon-left">
    <i class="pi pi-user"></i>
    <p:inputText placeholder="Username" />
</span>

<span class="ui-input-icon-right">
    <p:inputText placeholder="Search" />
    <i class="pi pi-search"></i>
</span>

📝 Composants de Formulaire

InputText

Basique :

<p:inputText value="#{bean.nom}" placeholder="Nom" />

Avec field pattern :

<div class="field">
    <p:outputLabel for="nom" value="Nom" />
    <p:inputText id="nom" value="#{bean.nom}" required="true" />
    <p:message for="nom" />
</div>

Disabled / Erreur :

<p:inputText value="#{bean.nom}" disabled="true" />
<p:inputText value="#{bean.nom}" styleClass="ui-state-error" />

InputTextarea

<div class="field">
    <p:outputLabel for="description" value="Description" />
    <p:inputTextarea id="description"
                     value="#{bean.description}"
                     rows="5"
                     autoResize="false" />
</div>

SelectOneMenu (Dropdown)

<div class="field">
    <p:outputLabel for="category" value="Catégorie" />
    <p:selectOneMenu id="category" value="#{bean.category}">
        <f:selectItem itemLabel="Sélectionnez..." itemValue="" />
        <f:selectItem itemLabel="Option 1" itemValue="1" />
        <f:selectItem itemLabel="Option 2" itemValue="2" />
    </p:selectOneMenu>
</div>

Avec filtre :

<p:selectOneMenu value="#{bean.category}" filter="true" filterMatchMode="contains">
    <f:selectItems value="#{bean.categories}" />
</p:selectOneMenu>

Calendar (DatePicker)

<div class="field">
    <p:outputLabel for="date" value="Date" />
    <p:datePicker id="date" value="#{bean.date}" showIcon="true" />
</div>

SelectManyCheckbox

<div class="field">
    <p:outputLabel value="Options" />
    <p:selectManyCheckbox value="#{bean.selectedOptions}" layout="responsive" columns="3">
        <f:selectItem itemLabel="Option 1" itemValue="1" />
        <f:selectItem itemLabel="Option 2" itemValue="2" />
        <f:selectItem itemLabel="Option 3" itemValue="3" />
    </p:selectManyCheckbox>
</div>

SelectOneRadio

<div class="field">
    <p:outputLabel value="Catégorie" />
    <p:selectOneRadio value="#{bean.category}" layout="responsive" columns="2">
        <f:selectItem itemLabel="Accessories" itemValue="Accessories" />
        <f:selectItem itemLabel="Clothing" itemValue="Clothing" />
    </p:selectOneRadio>
</div>

📊 Composants de Données

DataTable

Basique :

<p:dataTable value="#{bean.users}" var="user" paginator="true" rows="10">
    <p:column headerText="Nom">
        <h:outputText value="#{user.nom}" />
    </p:column>
    <p:column headerText="Email">
        <h:outputText value="#{user.email}" />
    </p:column>
</p:dataTable>

Complet (Pattern Freya CRUD) :

<h:form id="form">
    <p:growl id="messages" showDetail="true" />

    <!-- Toolbar -->
    <p:toolbar styleClass="mb-4">
        <p:toolbarGroup>
            <p:commandButton value="Nouveau"
                           icon="pi pi-plus"
                           actionListener="#{bean.openNew}"
                           update="dialog-content"
                           oncomplete="PF('dialog').show()"
                           styleClass="ui-button-success" />
            <p:commandButton value="Supprimer"
                           icon="pi pi-trash"
                           actionListener="#{bean.deleteSelected}"
                           styleClass="ui-button-danger"
                           disabled="#{!bean.hasSelected()}"
                           update="@this">
                <p:confirm header="Confirmation"
                          message="Supprimer les éléments sélectionnés ?"
                          icon="pi pi-exclamation-triangle" />
            </p:commandButton>
        </p:toolbarGroup>
        <p:toolbarGroup align="right">
            <p:fileUpload mode="simple" skinSimple="true" label="Import" />
            <p:commandButton value="Export" icon="pi pi-upload" ajax="false">
                <p:dataExporter type="pdf" target="dt" fileName="data"/>
            </p:commandButton>
        </p:toolbarGroup>
    </p:toolbar>

    <!-- DataTable -->
    <p:dataTable id="dt"
                 widgetVar="dtTable"
                 var="item"
                 value="#{bean.items}"
                 selection="#{bean.selectedItems}"
                 rowKey="#{item.id}"
                 paginator="true"
                 rows="10"
                 reflow="true">

        <f:facet name="header">
            <div class="products-table-header">
                <span style="font-weight: bold">Gestion des Données</span>
                <span class="filter-container ui-input-icon-left">
                    <i class="pi pi-search"></i>
                    <p:inputText id="globalFilter"
                               onkeyup="PF('dtTable').filter()"
                               placeholder="Rechercher" />
                </span>
            </div>
        </f:facet>

        <p:ajax event="rowSelect" update=":form:toolbar" />
        <p:ajax event="rowUnselect" update=":form:toolbar" />

        <p:column selectionMode="multiple" exportable="false" />

        <p:column headerText="Nom" sortBy="#{item.nom}" filterBy="#{item.nom}">
            <h:outputText value="#{item.nom}" />
        </p:column>

        <p:column exportable="false">
            <p:commandButton icon="pi pi-pencil"
                           update=":form:dialog-content"
                           oncomplete="PF('dialog').show()"
                           styleClass="edit-button rounded-button ui-button-success">
                <f:setPropertyActionListener value="#{item}" target="#{bean.selectedItem}" />
            </p:commandButton>
            <p:commandButton icon="pi pi-trash"
                           styleClass="ui-button-warning rounded-button"
                           oncomplete="PF('deleteDialog').show()">
                <f:setPropertyActionListener value="#{item}" target="#{bean.selectedItem}" />
            </p:commandButton>
        </p:column>
    </p:dataTable>
</h:form>

🗂️ Composants Panel

Dialog

Basique :

<p:dialog header="Détails"
          widgetVar="dialog"
          modal="true"
          showEffect="fade"
          responsive="true">
    <p:outputPanel id="dialog-content">
        <!-- Contenu -->
    </p:outputPanel>
</p:dialog>

Avec formulaire et footer :

<p:dialog header="Éditer"
          widgetVar="editDialog"
          modal="true"
          responsive="true">
    <p:outputPanel id="edit-content" class="ui-fluid">
        <p:outputPanel rendered="#{not empty bean.selectedItem}">
            <div class="field">
                <p:outputLabel for="name" value="Nom" />
                <p:inputText id="name" value="#{bean.selectedItem.nom}" required="true" />
            </div>
            <div class="field">
                <p:outputLabel for="description" value="Description" />
                <p:inputTextarea id="description" value="#{bean.selectedItem.description}" />
            </div>
        </p:outputPanel>
    </p:outputPanel>

    <f:facet name="footer">
        <p:commandButton value="Annuler"
                       icon="pi pi-times"
                       onclick="PF('editDialog').hide()"
                       styleClass="ui-button-secondary" />
        <p:commandButton value="Sauvegarder"
                       icon="pi pi-check"
                       actionListener="#{bean.save}"
                       update="edit-content"
                       oncomplete="if(!args.validationFailed) PF('editDialog').hide()"
                       styleClass="ui-button-success" />
    </f:facet>
</p:dialog>

Panel

<p:panel header="Titre du Panel" toggleable="true" collapsed="false">
    <p>Contenu du panel...</p>
</p:panel>

AccordionPanel

<p:accordionPanel multiple="false">
    <p:tab title="Section 1">
        <p>Contenu de la section 1...</p>
    </p:tab>
    <p:tab title="Section 2">
        <p>Contenu de la section 2...</p>
    </p:tab>
</p:accordionPanel>

🔘 Composants Button

CommandButton

Basique :

<p:commandButton value="Sauvegarder"
                action="#{bean.save}"
                update="form" />

Avec icône :

<p:commandButton value="Nouveau"
                icon="pi pi-plus"
                actionListener="#{bean.create}" />

Avec styles Freya :

<!-- Success -->
<p:commandButton value="Créer"
                icon="pi pi-check"
                styleClass="ui-button-success" />

<!-- Warning -->
<p:commandButton value="Attention"
                icon="pi pi-exclamation-triangle"
                styleClass="ui-button-warning" />

<!-- Danger -->
<p:commandButton value="Supprimer"
                icon="pi pi-trash"
                styleClass="ui-button-danger" />

<!-- Secondary -->
<p:commandButton value="Annuler"
                icon="pi pi-times"
                styleClass="ui-button-secondary" />

<!-- Rounded -->
<p:commandButton icon="pi pi-pencil"
                styleClass="rounded-button ui-button-success" />

Groupe de boutons :

<f:facet name="footer">
    <p:commandButton value="Annuler"
                   icon="pi pi-times"
                   styleClass="ui-button-secondary" />
    <p:commandButton value="Sauvegarder"
                   icon="pi pi-check"
                   styleClass="ui-button-success" />
</f:facet>

💬 Composants Message

Message (pour un champ)

<div class="field">
    <p:outputLabel for="email" value="Email" />
    <p:inputText id="email" value="#{bean.email}" required="true" />
    <p:message for="email" />
</div>

Messages (tous les messages)

<h:form>
    <p:messages id="messages" showDetail="true" closable="true" />
    <!-- Formulaire -->
</h:form>

Growl (notifications toast)

<h:form>
    <p:growl id="growl" showDetail="true" />
    <p:commandButton value="Save"
                   action="#{bean.save}"
                   update="growl" />
</h:form>

Dans le bean :

public void save() {
    // Logic...
    FacesContext.getCurrentInstance().addMessage(null,
        new FacesMessage(FacesMessage.SEVERITY_INFO,
                        "Succès",
                        "Données sauvegardées avec succès"));
}

📐 Patterns de Layout

Page Complète avec Card

<ui:composition template="/WEB-INF/template.xhtml">
    <ui:define name="title">Ma Page</ui:define>

    <ui:define name="content">
        <div class="grid">
            <div class="col-12">
                <div class="card">
                    <h5>Titre</h5>
                    <p>Contenu...</p>
                </div>
            </div>
        </div>
    </ui:define>
</ui:composition>

Deux Colonnes

<div class="grid">
    <div class="col-12 lg:col-6">
        <div class="card">
            <h5>Colonne Gauche</h5>
            <!-- Contenu -->
        </div>
    </div>
    <div class="col-12 lg:col-6">
        <div class="card">
            <h5>Colonne Droite</h5>
            <!-- Contenu -->
        </div>
    </div>
</div>

Formulaire Complet

<div class="grid">
    <div class="col-12">
        <div class="card">
            <h:form id="userForm" class="ui-fluid">
                <h5>Nouvel Utilisateur</h5>

                <div class="grid formgrid">
                    <div class="col-12 md:col-6">
                        <div class="field">
                            <p:outputLabel for="firstname" value="Prénom" />
                            <p:inputText id="firstname" value="#{bean.user.firstname}" required="true" />
                            <p:message for="firstname" />
                        </div>
                    </div>
                    <div class="col-12 md:col-6">
                        <div class="field">
                            <p:outputLabel for="lastname" value="Nom" />
                            <p:inputText id="lastname" value="#{bean.user.lastname}" required="true" />
                            <p:message for="lastname" />
                        </div>
                    </div>
                </div>

                <div class="field">
                    <p:outputLabel for="email" value="Email" />
                    <p:inputText id="email" value="#{bean.user.email}" required="true" />
                    <p:message for="email" />
                </div>

                <div class="field">
                    <p:outputLabel for="role" value="Rôle" />
                    <p:selectOneMenu id="role" value="#{bean.user.role}">
                        <f:selectItem itemLabel="Sélectionnez..." itemValue="" />
                        <f:selectItems value="#{bean.roles}" />
                    </p:selectOneMenu>
                </div>

                <div class="field">
                    <p:commandButton value="Annuler"
                                   icon="pi pi-times"
                                   styleClass="ui-button-secondary"
                                   style="margin-right: .5rem" />
                    <p:commandButton value="Sauvegarder"
                                   icon="pi pi-check"
                                   action="#{bean.save}"
                                   update="userForm"
                                   styleClass="ui-button-success" />
                </div>
            </h:form>
        </div>
    </div>
</div>

🎨 Composant FreyaMenu

Usage :

<html xmlns:fr="http://primefaces.org/freya">

<fr:menu model="#{menuBean.model}" />

Bean :

@Named
@SessionScoped
public class MenuBean implements Serializable {
    private MenuModel model;

    @PostConstruct
    public void init() {
        model = new DefaultMenuModel();

        DefaultMenuItem item1 = DefaultMenuItem.builder()
            .value("Dashboard")
            .icon("pi pi-home")
            .outcome("/dashboard.xhtml")
            .build();
        model.getElements().add(item1);

        DefaultSubMenu subMenu = DefaultSubMenu.builder()
            .label("Gestion")
            .icon("pi pi-cog")
            .build();

        DefaultMenuItem subItem = DefaultMenuItem.builder()
            .value("Utilisateurs")
            .outcome("/users/list.xhtml")
            .build();
        subMenu.getElements().add(subItem);

        model.getElements().add(subMenu);
    }

    public MenuModel getModel() {
        return model;
    }
}

📚 Ressources

Documentation Officielle

Exemples Sources Freya

  • Localisation : C:/Users/dadyo/PersonalProjects/lions-workspace/freya/tag/src/main/webapp/
  • Fichiers : input.xhtml, crud.xhtml, formlayout.xhtml, button.xhtml, etc.

Bonnes Pratiques

  1. Utiliser les classes Freya : grid, card, field, formgrid
  2. Pattern field cohérent : Label + Input + Message
  3. ui-fluid pour formulaires : Inputs 100% width
  4. Responsive design : Utiliser col-12 lg:col-6 etc.
  5. Icônes PrimeIcons : pi pi-*
  6. Styles de boutons : ui-button-success, ui-button-danger, etc.
  7. Messages appropriés : p:message pour champs, p:growl pour notifications
  8. Dialog modal : Toujours avec modal="true" et responsive="true"

Version : 1.0.0 Dernière mise à jour : 2025-12-25