Téléverser les fichiers vers "first-login-ui/src"

This commit is contained in:
2026-08-18 15:59:11 +02:00
parent 0d1dbab818
commit 61c2966ff7
+174 -2
View File
@@ -31,6 +31,64 @@ Kirigami.ApplicationWindow {
} }
} }
// Indicateur volontairement informatif : il ne bloque jamais
// la validation du mot de passe. La longueur est privilégiée,
// la diversité des caractères apporte un bonus visuel.
function passwordStrengthLevel(password) {
if (password.length === 0)
return 0
var classes = 0
if (/[a-z]/.test(password)) classes += 1
if (/[A-Z]/.test(password)) classes += 1
if (/[0-9]/.test(password)) classes += 1
if (/[^A-Za-z0-9]/.test(password)) classes += 1
var level = 1
if (password.length >= 16)
level = classes >= 2 ? 4 : 3
else if (password.length >= 12)
level = classes >= 2 ? 3 : 2
else if (password.length >= 8)
level = classes >= 3 ? 2 : 1
// Quelques motifs manifestement faibles : on réduit
// l'indication sans empêcher l'utilisateur de continuer.
var lower = password.toLowerCase()
if (lower === "password" || lower === "motdepasse" ||
lower === "azerty" || lower === "qwerty" ||
lower === "12345678" || /^(.)\1+$/.test(password)) {
level = 1
}
return level
}
function passwordStrengthLabel(level) {
if (level === 1) return "Faible"
if (level === 2) return "Moyen"
if (level === 3) return "Bon"
if (level === 4) return "Très bon"
return "Non évalué"
}
function passwordStrengthColor(level) {
if (level === 1) return "#dc2626"
if (level === 2) return "#d97706"
if (level === 3) return "#2563eb"
if (level === 4) return "#16a34a"
return "#cbd5e1"
}
function passwordStrengthHint(level) {
if (level === 1) return "Privilégiez surtout la longueur : une phrase de passe de 12 caractères ou plus est un bon point de départ."
if (level === 2) return "Correct pour un usage courant, mais quelques caractères supplémentaires amélioreraient sensiblement la robustesse."
if (level === 3) return "Bonne robustesse apparente : la longueur et la diversité sont satisfaisantes."
if (level === 4) return "Très bonne robustesse apparente : mot de passe long et suffisamment diversifié."
return "Saisissez votre nouveau mot de passe pour obtenir une indication de robustesse."
}
Shortcut { Shortcut {
sequence: "Ctrl+Q" sequence: "Ctrl+Q"
onActivated: Qt.quit() onActivated: Qt.quit()
@@ -85,13 +143,16 @@ Kirigami.ApplicationWindow {
component SecretField: Controls.TextField { component SecretField: Controls.TextField {
id: field id: field
property bool secretVisible: false
Layout.fillWidth: true Layout.fillWidth: true
implicitHeight: 50 implicitHeight: 50
echoMode: TextInput.Password echoMode: secretVisible ? TextInput.Normal : TextInput.Password
passwordCharacter: "●" passwordCharacter: "●"
font.pixelSize: 15 font.pixelSize: 15
leftPadding: 16 leftPadding: 16
rightPadding: 16 rightPadding: 56
selectByMouse: true selectByMouse: true
background: Rectangle { background: Rectangle {
@@ -100,6 +161,39 @@ Kirigami.ApplicationWindow {
border.width: field.activeFocus ? 2 : 1 border.width: field.activeFocus ? 2 : 1
border.color: field.activeFocus ? "#2563eb" : "#cbd5e1" border.color: field.activeFocus ? "#2563eb" : "#cbd5e1"
} }
Controls.ToolButton {
id: visibilityButton
anchors.right: parent.right
anchors.rightMargin: 8
anchors.verticalCenter: parent.verticalCenter
width: 38
height: 38
hoverEnabled: true
focusPolicy: Qt.NoFocus
Accessible.name: field.secretVisible ? "Masquer la valeur" : "Afficher la valeur"
onClicked: field.secretVisible = !field.secretVisible
contentItem: Kirigami.Icon {
source: field.secretVisible ? "view-hidden" : "view-visible"
implicitWidth: 20
implicitHeight: 20
color: visibilityButton.hovered ? "#2563eb" : "#64748b"
}
background: Rectangle {
radius: 8
color: visibilityButton.pressed ? "#dbeafe"
: visibilityButton.hovered ? "#eff6ff"
: "transparent"
Behavior on color {
ColorAnimation { duration: 100 }
}
}
}
} }
component StepDot: Rectangle { component StepDot: Rectangle {
@@ -575,6 +669,84 @@ Kirigami.ApplicationWindow {
placeholderText: "Choisissez votre mot de passe personnel" placeholderText: "Choisissez votre mot de passe personnel"
} }
// Indicateur de robustesse purement informatif.
// Il ne participe pas à la condition d'activation
// du bouton Continuer.
Rectangle {
id: strengthCard
Layout.fillWidth: true
implicitHeight: 112
radius: 12
color: "#f8fafc"
border.width: 1
border.color: "#e2e8f0"
property int strengthLevel: root.passwordStrengthLevel(newPassword.text)
ColumnLayout {
anchors.fill: parent
anchors.margins: 14
spacing: 8
RowLayout {
Layout.fillWidth: true
Controls.Label {
text: "Robustesse du mot de passe"
color: "#334155"
font.pixelSize: 12
font.weight: Font.DemiBold
}
Item { Layout.fillWidth: true }
Controls.Label {
text: root.passwordStrengthLabel(strengthCard.strengthLevel)
color: root.passwordStrengthColor(strengthCard.strengthLevel)
font.pixelSize: 12
font.weight: Font.Bold
}
}
RowLayout {
Layout.fillWidth: true
spacing: 6
Repeater {
model: 4
Rectangle {
required property int index
Layout.fillWidth: true
implicitHeight: 7
radius: 4
color: index < parent.parent.parent.strengthLevel
? root.passwordStrengthColor(strengthCard.strengthLevel)
: "#e2e8f0"
Behavior on color {
ColorAnimation { duration: 140 }
}
}
}
}
Controls.Label {
Layout.fillWidth: true
text: root.passwordStrengthHint(strengthCard.strengthLevel)
wrapMode: Text.WordWrap
color: "#64748b"
font.pixelSize: 11
}
}
}
Controls.Label {
text: "Indication uniquement : un mot de passe faible n'est pas bloqué."
color: "#94a3b8"
font.pixelSize: 11
}
Controls.Label { Controls.Label {
text: "Confirmation" text: "Confirmation"
color: "#334155" color: "#334155"