feat: add password visibility button (#56)

Co-authored-by: Paul Werner <paul.werner@almig.de>
Co-authored-by: Anthony Lukin <anthony@lukin.dev>
This commit is contained in:
Paul Werner 2023-12-13 20:00:00 +01:00 committed by GitHub
parent 6e5ef061bf
commit bdf966fdae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 185 additions and 78 deletions

View file

@ -4,8 +4,8 @@
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="../../theme/keywind/login/resources/dist/index.css" rel="stylesheet">
<script defer src="../../theme/keywind/login/resources/dist/index.js" type="module"></script>
<link href="http://localhost:5173/src/index.css" rel="stylesheet">
<script defer src="http://localhost:5173/src/index.ts" type="module"></script>
</head>
<body class="bg-secondary-100 flex flex-col items-center justify-center min-h-screen sm:py-16">
<div class="max-w-md space-y-6 w-full">

View file

@ -4,8 +4,8 @@
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="../../theme/keywind/login/resources/dist/index.css" rel="stylesheet">
<script defer src="../../theme/keywind/login/resources/dist/index.js" type="module"></script>
<link href="http://localhost:5173/src/index.css" rel="stylesheet">
<script defer src="http://localhost:5173/src/index.ts" type="module"></script>
</head>
<body class="bg-secondary-100 flex flex-col items-center justify-center min-h-screen sm:py-16">
<div class="max-w-md space-y-6 w-full">
@ -34,12 +34,12 @@
<form class="m-0 space-y-4" method="post" action="loginAction">
<input name="totpSecret" type="hidden" value="totpSecret">
<div>
<label class="sr-only" for="totp"> One-time code * </label> <input autofocus aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="totp" name="totp" placeholder="One-time code *" autocomplete="off" type="text">
<label class="sr-only" for="totp"> One-time code * </label> <input autofocus aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="totp" name="totp" placeholder="One-time code *" type="text" autocomplete="off">
<div class="mt-2 text-red-600 text-sm">
</div>
</div>
<div>
<label class="sr-only" for="userLabel"> Device Name * </label> <input aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="userLabel" name="userLabel" placeholder="Device Name *" autocomplete="off" type="text">
<label class="sr-only" for="userLabel"> Device Name * </label> <input aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="userLabel" name="userLabel" placeholder="Device Name *" type="text" autocomplete="off">
<div class="mt-2 text-red-600 text-sm">
</div>
</div>

View file

@ -4,8 +4,8 @@
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="../../theme/keywind/login/resources/dist/index.css" rel="stylesheet">
<script defer src="../../theme/keywind/login/resources/dist/index.js" type="module"></script>
<link href="http://localhost:5173/src/index.css" rel="stylesheet">
<script defer src="http://localhost:5173/src/index.ts" type="module"></script>
</head>
<body class="bg-secondary-100 flex flex-col items-center justify-center min-h-screen sm:py-16">
<div class="max-w-md space-y-6 w-full">

View file

@ -4,8 +4,8 @@
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="../../theme/keywind/login/resources/dist/index.css" rel="stylesheet">
<script defer src="../../theme/keywind/login/resources/dist/index.js" type="module"></script>
<link href="http://localhost:5173/src/index.css" rel="stylesheet">
<script defer src="http://localhost:5173/src/index.ts" type="module"></script>
</head>
<body class="bg-secondary-100 flex flex-col items-center justify-center min-h-screen sm:py-16">
<div class="max-w-md space-y-6 w-full">

View file

@ -4,8 +4,8 @@
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="../../theme/keywind/login/resources/dist/index.css" rel="stylesheet">
<script defer src="../../theme/keywind/login/resources/dist/index.js" type="module"></script>
<link href="http://localhost:5173/src/index.css" rel="stylesheet">
<script defer src="http://localhost:5173/src/index.ts" type="module"></script>
</head>
<body class="bg-secondary-100 flex flex-col items-center justify-center min-h-screen sm:py-16">
<div class="max-w-md space-y-6 w-full">
@ -22,7 +22,7 @@
</div>
<form class="m-0 space-y-4" method="post" action="loginAction">
<div>
<label class="sr-only" for="otp"> One-time code * </label> <input autofocus required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="otp" name="otp" placeholder="One-time code *" autocomplete="off" type="text">
<label class="sr-only" for="otp"> One-time code * </label> <input autofocus required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="otp" name="otp" placeholder="One-time code *" type="text" autocomplete="off">
<div class="mt-2 text-red-600 text-sm">
</div>
</div>

View file

@ -4,8 +4,8 @@
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="../../theme/keywind/login/resources/dist/index.css" rel="stylesheet">
<script defer src="../../theme/keywind/login/resources/dist/index.js" type="module"></script>
<link href="http://localhost:5173/src/index.css" rel="stylesheet">
<script defer src="http://localhost:5173/src/index.ts" type="module"></script>
</head>
<body class="bg-secondary-100 flex flex-col items-center justify-center min-h-screen sm:py-16">
<div class="max-w-md space-y-6 w-full">

View file

@ -4,8 +4,8 @@
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="../../theme/keywind/login/resources/dist/index.css" rel="stylesheet">
<script defer src="../../theme/keywind/login/resources/dist/index.js" type="module"></script>
<link href="http://localhost:5173/src/index.css" rel="stylesheet">
<script defer src="http://localhost:5173/src/index.ts" type="module"></script>
</head>
<body class="bg-secondary-100 flex flex-col items-center justify-center min-h-screen sm:py-16">
<div class="max-w-md space-y-6 w-full">
@ -22,7 +22,20 @@
</div>
<form class="m-0 space-y-4" method="post" action="loginAction" onsubmit="login.disabled = true; return true;">
<div>
<label class="sr-only" for="password"> Password </label> <input autofocus required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="password" name="password" placeholder="Password" type="password">
<label class="sr-only" for="password"> Password </label>
<div class="relative" x-data="{ show: false }">
<input autofocus required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="password" name="password" placeholder="Password" :type="show ? 'text' : 'password'"> <button @click="show = !show" aria-controls="password" :aria-expanded="show" class="absolute text-secondary-400 right-3 top-3 sm:top-2" type="button">
<div x-show="!show">
<svg class="h-5 w-5" fill="currentColor" viewbox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path d="M10 12.5C11.3807 12.5 12.5 11.3807 12.5 10C12.5 8.61929 11.3807 7.5 10 7.5C8.61929 7.5 7.5 8.61929 7.5 10C7.5 11.3807 8.61929 12.5 10 12.5Z" /> <path clip-rule="evenodd" d="M0.664255 10.5904C0.517392 10.2087 0.517518 9.78563 0.66461 9.40408C2.10878 5.65788 5.7433 3 9.99859 3C14.256 3 17.892 5.66051 19.3347 9.40962C19.4816 9.79127 19.4814 10.2144 19.3344 10.5959C17.8902 14.3421 14.2557 17 10.0004 17C5.74298 17 2.10698 14.3395 0.664255 10.5904ZM14.0004 10C14.0004 12.2091 12.2095 14 10.0004 14C7.79123 14 6.00037 12.2091 6.00037 10C6.00037 7.79086 7.79123 6 10.0004 6C12.2095 6 14.0004 7.79086 14.0004 10Z" fill-rule="evenodd" />
</svg>
</div>
<div x-cloak x-show="show">
<svg class="h-5 w-5" fill="currentColor" viewbox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path clip-rule="evenodd" d="M3.28033 2.21967C2.98744 1.92678 2.51256 1.92678 2.21967 2.21967C1.92678 2.51256 1.92678 2.98744 2.21967 3.28033L16.7197 17.7803C17.0126 18.0732 17.4874 18.0732 17.7803 17.7803C18.0732 17.4874 18.0732 17.0126 17.7803 16.7197L16.0352 14.9745C17.5064 13.8594 18.6595 12.3465 19.3344 10.5959C19.4814 10.2144 19.4816 9.79127 19.3347 9.40962C17.892 5.66051 14.256 3 9.99859 3C8.28207 3 6.66657 3.43249 5.2551 4.19444L3.28033 2.21967ZM7.75194 6.69128L8.84367 7.78301C9.18951 7.60223 9.58291 7.5 10.0002 7.5C11.3809 7.5 12.5002 8.61929 12.5002 10C12.5002 10.4173 12.398 10.8107 12.2172 11.1565L13.3091 12.2484C13.7454 11.6077 14.0004 10.8336 14.0004 10C14.0004 7.79086 12.2095 6 10.0004 6C9.16675 6 8.39268 6.25501 7.75194 6.69128Z" fill-rule="evenodd" /> <path d="M10.7484 13.9302L13.2711 16.4529C12.2462 16.8074 11.1458 17 10.0004 17C5.74298 17 2.10698 14.3395 0.664255 10.5904C0.517392 10.2087 0.517518 9.78563 0.66461 9.40408C1.15603 8.12932 1.90108 6.98057 2.83791 6.01969L6.0702 9.25198C6.02436 9.4943 6.00037 9.74435 6.00037 10C6.00037 12.2091 7.79123 14 10.0004 14C10.256 14 10.5061 13.976 10.7484 13.9302Z" />
</svg>
</div></button>
</div>
<div class="mt-2 text-red-600 text-sm">
</div>
</div>

View file

@ -4,9 +4,9 @@
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="../../theme/keywind/login/resources/dist/index.css" rel="stylesheet">
<script defer src="../../theme/keywind/login/resources/dist/recoveryCodes.js" type="module"></script>
<script defer src="../../theme/keywind/login/resources/dist/index.js" type="module"></script>
<link href="http://localhost:5173/src/index.css" rel="stylesheet">
<script defer src="http://localhost:5173/dist/recoveryCodes.js" type="module"></script>
<script defer src="http://localhost:5173/src/index.ts" type="module"></script>
</head>
<body class="bg-secondary-100 flex flex-col items-center justify-center min-h-screen sm:py-16">
<div class="max-w-md space-y-6 w-full">

View file

@ -4,8 +4,8 @@
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="../../theme/keywind/login/resources/dist/index.css" rel="stylesheet">
<script defer src="../../theme/keywind/login/resources/dist/index.js" type="module"></script>
<link href="http://localhost:5173/src/index.css" rel="stylesheet">
<script defer src="http://localhost:5173/src/index.ts" type="module"></script>
</head>
<body class="bg-secondary-100 flex flex-col items-center justify-center min-h-screen sm:py-16">
<div class="max-w-md space-y-6 w-full">
@ -22,7 +22,7 @@
</div>
<form class="m-0 space-y-4" method="post" action="loginAction">
<div>
<label class="sr-only" for="recoveryCodeInput"> Recovery code #"codeNumber" </label> <input autofocus required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="recoveryCodeInput" name="recoveryCodeInput" placeholder="Recovery code #&quot;codeNumber&quot;" autocomplete="off" type="text">
<label class="sr-only" for="recoveryCodeInput"> Recovery code #"codeNumber" </label> <input autofocus required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="recoveryCodeInput" name="recoveryCodeInput" placeholder="Recovery code #&quot;codeNumber&quot;" type="text" autocomplete="off">
<div class="mt-2 text-red-600 text-sm">
</div>
</div>

View file

@ -4,8 +4,8 @@
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="../../theme/keywind/login/resources/dist/index.css" rel="stylesheet">
<script defer src="../../theme/keywind/login/resources/dist/index.js" type="module"></script>
<link href="http://localhost:5173/src/index.css" rel="stylesheet">
<script defer src="http://localhost:5173/src/index.ts" type="module"></script>
</head>
<body class="bg-secondary-100 flex flex-col items-center justify-center min-h-screen sm:py-16">
<div class="max-w-md space-y-6 w-full">
@ -22,7 +22,7 @@
</div>
<form class="m-0 space-y-4" method="post" action="loginAction">
<div>
<label class="sr-only" for="username"> Email </label> <input autofocus required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="username" name="username" placeholder="Email" autocomplete="email" type="text" value="Attempted Username">
<label class="sr-only" for="username"> Email </label> <input autofocus required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="username" name="username" placeholder="Email" type="text" autocomplete="email" value="Attempted Username">
<div class="mt-2 text-red-600 text-sm">
</div>
</div>

View file

@ -4,8 +4,8 @@
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="../../theme/keywind/login/resources/dist/index.css" rel="stylesheet">
<script defer src="../../theme/keywind/login/resources/dist/index.js" type="module"></script>
<link href="http://localhost:5173/src/index.css" rel="stylesheet">
<script defer src="http://localhost:5173/src/index.ts" type="module"></script>
</head>
<body class="bg-secondary-100 flex flex-col items-center justify-center min-h-screen sm:py-16">
<div class="max-w-md space-y-6 w-full">
@ -23,12 +23,38 @@
<form class="m-0 space-y-4" method="post" action="loginAction">
<input autocomplete="username" name="username" type="hidden" value="Username"> <input autocomplete="current-password" name="password" type="hidden">
<div>
<label class="sr-only" for="password-new"> New Password </label> <input autofocus required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="password-new" name="password-new" placeholder="New Password" autocomplete="new-password" type="password">
<label class="sr-only" for="password-new"> New Password </label>
<div class="relative" x-data="{ show: false }">
<input autofocus required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="password-new" name="password-new" placeholder="New Password" :type="show ? 'text' : 'password'" autocomplete="new-password"> <button @click="show = !show" aria-controls="password-new" :aria-expanded="show" class="absolute text-secondary-400 right-3 top-3 sm:top-2" type="button">
<div x-show="!show">
<svg class="h-5 w-5" fill="currentColor" viewbox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path d="M10 12.5C11.3807 12.5 12.5 11.3807 12.5 10C12.5 8.61929 11.3807 7.5 10 7.5C8.61929 7.5 7.5 8.61929 7.5 10C7.5 11.3807 8.61929 12.5 10 12.5Z" /> <path clip-rule="evenodd" d="M0.664255 10.5904C0.517392 10.2087 0.517518 9.78563 0.66461 9.40408C2.10878 5.65788 5.7433 3 9.99859 3C14.256 3 17.892 5.66051 19.3347 9.40962C19.4816 9.79127 19.4814 10.2144 19.3344 10.5959C17.8902 14.3421 14.2557 17 10.0004 17C5.74298 17 2.10698 14.3395 0.664255 10.5904ZM14.0004 10C14.0004 12.2091 12.2095 14 10.0004 14C7.79123 14 6.00037 12.2091 6.00037 10C6.00037 7.79086 7.79123 6 10.0004 6C12.2095 6 14.0004 7.79086 14.0004 10Z" fill-rule="evenodd" />
</svg>
</div>
<div x-cloak x-show="show">
<svg class="h-5 w-5" fill="currentColor" viewbox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path clip-rule="evenodd" d="M3.28033 2.21967C2.98744 1.92678 2.51256 1.92678 2.21967 2.21967C1.92678 2.51256 1.92678 2.98744 2.21967 3.28033L16.7197 17.7803C17.0126 18.0732 17.4874 18.0732 17.7803 17.7803C18.0732 17.4874 18.0732 17.0126 17.7803 16.7197L16.0352 14.9745C17.5064 13.8594 18.6595 12.3465 19.3344 10.5959C19.4814 10.2144 19.4816 9.79127 19.3347 9.40962C17.892 5.66051 14.256 3 9.99859 3C8.28207 3 6.66657 3.43249 5.2551 4.19444L3.28033 2.21967ZM7.75194 6.69128L8.84367 7.78301C9.18951 7.60223 9.58291 7.5 10.0002 7.5C11.3809 7.5 12.5002 8.61929 12.5002 10C12.5002 10.4173 12.398 10.8107 12.2172 11.1565L13.3091 12.2484C13.7454 11.6077 14.0004 10.8336 14.0004 10C14.0004 7.79086 12.2095 6 10.0004 6C9.16675 6 8.39268 6.25501 7.75194 6.69128Z" fill-rule="evenodd" /> <path d="M10.7484 13.9302L13.2711 16.4529C12.2462 16.8074 11.1458 17 10.0004 17C5.74298 17 2.10698 14.3395 0.664255 10.5904C0.517392 10.2087 0.517518 9.78563 0.66461 9.40408C1.15603 8.12932 1.90108 6.98057 2.83791 6.01969L6.0702 9.25198C6.02436 9.4943 6.00037 9.74435 6.00037 10C6.00037 12.2091 7.79123 14 10.0004 14C10.256 14 10.5061 13.976 10.7484 13.9302Z" />
</svg>
</div></button>
</div>
<div class="mt-2 text-red-600 text-sm">
</div>
</div>
<div>
<label class="sr-only" for="password-confirm"> Confirm password </label> <input required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="password-confirm" name="password-confirm" placeholder="Confirm password" autocomplete="new-password" type="password">
<label class="sr-only" for="password-confirm"> Confirm password </label>
<div class="relative" x-data="{ show: false }">
<input required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="password-confirm" name="password-confirm" placeholder="Confirm password" :type="show ? 'text' : 'password'" autocomplete="new-password"> <button @click="show = !show" aria-controls="password-confirm" :aria-expanded="show" class="absolute text-secondary-400 right-3 top-3 sm:top-2" type="button">
<div x-show="!show">
<svg class="h-5 w-5" fill="currentColor" viewbox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path d="M10 12.5C11.3807 12.5 12.5 11.3807 12.5 10C12.5 8.61929 11.3807 7.5 10 7.5C8.61929 7.5 7.5 8.61929 7.5 10C7.5 11.3807 8.61929 12.5 10 12.5Z" /> <path clip-rule="evenodd" d="M0.664255 10.5904C0.517392 10.2087 0.517518 9.78563 0.66461 9.40408C2.10878 5.65788 5.7433 3 9.99859 3C14.256 3 17.892 5.66051 19.3347 9.40962C19.4816 9.79127 19.4814 10.2144 19.3344 10.5959C17.8902 14.3421 14.2557 17 10.0004 17C5.74298 17 2.10698 14.3395 0.664255 10.5904ZM14.0004 10C14.0004 12.2091 12.2095 14 10.0004 14C7.79123 14 6.00037 12.2091 6.00037 10C6.00037 7.79086 7.79123 6 10.0004 6C12.2095 6 14.0004 7.79086 14.0004 10Z" fill-rule="evenodd" />
</svg>
</div>
<div x-cloak x-show="show">
<svg class="h-5 w-5" fill="currentColor" viewbox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path clip-rule="evenodd" d="M3.28033 2.21967C2.98744 1.92678 2.51256 1.92678 2.21967 2.21967C1.92678 2.51256 1.92678 2.98744 2.21967 3.28033L16.7197 17.7803C17.0126 18.0732 17.4874 18.0732 17.7803 17.7803C18.0732 17.4874 18.0732 17.0126 17.7803 16.7197L16.0352 14.9745C17.5064 13.8594 18.6595 12.3465 19.3344 10.5959C19.4814 10.2144 19.4816 9.79127 19.3347 9.40962C17.892 5.66051 14.256 3 9.99859 3C8.28207 3 6.66657 3.43249 5.2551 4.19444L3.28033 2.21967ZM7.75194 6.69128L8.84367 7.78301C9.18951 7.60223 9.58291 7.5 10.0002 7.5C11.3809 7.5 12.5002 8.61929 12.5002 10C12.5002 10.4173 12.398 10.8107 12.2172 11.1565L13.3091 12.2484C13.7454 11.6077 14.0004 10.8336 14.0004 10C14.0004 7.79086 12.2095 6 10.0004 6C9.16675 6 8.39268 6.25501 7.75194 6.69128Z" fill-rule="evenodd" /> <path d="M10.7484 13.9302L13.2711 16.4529C12.2462 16.8074 11.1458 17 10.0004 17C5.74298 17 2.10698 14.3395 0.664255 10.5904C0.517392 10.2087 0.517518 9.78563 0.66461 9.40408C1.15603 8.12932 1.90108 6.98057 2.83791 6.01969L6.0702 9.25198C6.02436 9.4943 6.00037 9.74435 6.00037 10C6.00037 12.2091 7.79123 14 10.0004 14C10.256 14 10.5061 13.976 10.7484 13.9302Z" />
</svg>
</div></button>
</div>
<div class="mt-2 text-red-600 text-sm">
</div>
</div>

View file

@ -4,8 +4,8 @@
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="../../theme/keywind/login/resources/dist/index.css" rel="stylesheet">
<script defer src="../../theme/keywind/login/resources/dist/index.js" type="module"></script>
<link href="http://localhost:5173/src/index.css" rel="stylesheet">
<script defer src="http://localhost:5173/src/index.ts" type="module"></script>
</head>
<body class="bg-secondary-100 flex flex-col items-center justify-center min-h-screen sm:py-16">
<div class="max-w-md space-y-6 w-full">
@ -22,22 +22,22 @@
</div>
<form class="m-0 space-y-4" method="post" action="loginAction">
<div>
<label class="sr-only" for="username"> Username </label> <input autofocus required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="username" name="username" placeholder="Username" autocomplete="username" type="text" value="">
<label class="sr-only" for="username"> Username </label> <input autofocus required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="username" name="username" placeholder="Username" type="text" autocomplete="username" value="">
<div class="mt-2 text-red-600 text-sm">
</div>
</div>
<div>
<label class="sr-only" for="email"> Email </label> <input required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="email" name="email" placeholder="Email" autocomplete="email" type="email" value="">
<label class="sr-only" for="email"> Email </label> <input required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="email" name="email" placeholder="Email" type="email" autocomplete="email" value="">
<div class="mt-2 text-red-600 text-sm">
</div>
</div>
<div>
<label class="sr-only" for="firstName"> First name </label> <input required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="firstName" name="firstName" placeholder="First name" autocomplete="given-name" type="text" value="">
<label class="sr-only" for="firstName"> First name </label> <input required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="firstName" name="firstName" placeholder="First name" type="text" autocomplete="given-name" value="">
<div class="mt-2 text-red-600 text-sm">
</div>
</div>
<div>
<label class="sr-only" for="lastName"> Last name </label> <input required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="lastName" name="lastName" placeholder="Last name" autocomplete="family-name" type="text" value="">
<label class="sr-only" for="lastName"> Last name </label> <input required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="lastName" name="lastName" placeholder="Last name" type="text" autocomplete="family-name" value="">
<div class="mt-2 text-red-600 text-sm">
</div>
</div>

View file

@ -4,8 +4,8 @@
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="../../theme/keywind/login/resources/dist/index.css" rel="stylesheet">
<script defer src="../../theme/keywind/login/resources/dist/index.js" type="module"></script>
<link href="http://localhost:5173/src/index.css" rel="stylesheet">
<script defer src="http://localhost:5173/src/index.ts" type="module"></script>
</head>
<body class="bg-secondary-100 flex flex-col items-center justify-center min-h-screen sm:py-16">
<div class="max-w-md space-y-6 w-full">
@ -22,7 +22,7 @@
</div>
<form class="m-0 space-y-4" method="post" action="loginAction" onsubmit="login.disabled = true; return true;">
<div>
<label class="sr-only" for="username"> Email </label> <input autofocus required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="username" name="username" placeholder="Email" autocomplete="email" type="text" value="">
<label class="sr-only" for="username"> Email </label> <input autofocus required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="username" name="username" placeholder="Email" type="text" autocomplete="email" value="">
<div class="mt-2 text-red-600 text-sm">
</div>
</div>

View file

@ -4,8 +4,8 @@
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="../../theme/keywind/login/resources/dist/index.css" rel="stylesheet">
<script defer src="../../theme/keywind/login/resources/dist/index.js" type="module"></script>
<link href="http://localhost:5173/src/index.css" rel="stylesheet">
<script defer src="http://localhost:5173/src/index.ts" type="module"></script>
</head>
<body class="bg-secondary-100 flex flex-col items-center justify-center min-h-screen sm:py-16">
<div class="max-w-md space-y-6 w-full">

View file

@ -4,8 +4,8 @@
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="../../theme/keywind/login/resources/dist/index.css" rel="stylesheet">
<script defer src="../../theme/keywind/login/resources/dist/index.js" type="module"></script>
<link href="http://localhost:5173/src/index.css" rel="stylesheet">
<script defer src="http://localhost:5173/src/index.ts" type="module"></script>
</head>
<body class="bg-secondary-100 flex flex-col items-center justify-center min-h-screen sm:py-16">
<div class="max-w-md space-y-6 w-full">
@ -23,12 +23,25 @@
<form class="m-0 space-y-4" method="post" action="loginAction" onsubmit="login.disabled = true; return true;">
<input name="credentialId" type="hidden" value="">
<div>
<label class="sr-only" for="username"> Email </label> <input autofocus required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="username" name="username" placeholder="Email" autocomplete="email" type="text" value="">
<label class="sr-only" for="username"> Email </label> <input autofocus required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="username" name="username" placeholder="Email" type="text" autocomplete="email" value="">
<div class="mt-2 text-red-600 text-sm">
</div>
</div>
<div>
<label class="sr-only" for="password"> Password </label> <input required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="password" name="password" placeholder="Password" type="password">
<label class="sr-only" for="password"> Password </label>
<div class="relative" x-data="{ show: false }">
<input required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="password" name="password" placeholder="Password" :type="show ? 'text' : 'password'"> <button @click="show = !show" aria-controls="password" :aria-expanded="show" class="absolute text-secondary-400 right-3 top-3 sm:top-2" type="button">
<div x-show="!show">
<svg class="h-5 w-5" fill="currentColor" viewbox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path d="M10 12.5C11.3807 12.5 12.5 11.3807 12.5 10C12.5 8.61929 11.3807 7.5 10 7.5C8.61929 7.5 7.5 8.61929 7.5 10C7.5 11.3807 8.61929 12.5 10 12.5Z" /> <path clip-rule="evenodd" d="M0.664255 10.5904C0.517392 10.2087 0.517518 9.78563 0.66461 9.40408C2.10878 5.65788 5.7433 3 9.99859 3C14.256 3 17.892 5.66051 19.3347 9.40962C19.4816 9.79127 19.4814 10.2144 19.3344 10.5959C17.8902 14.3421 14.2557 17 10.0004 17C5.74298 17 2.10698 14.3395 0.664255 10.5904ZM14.0004 10C14.0004 12.2091 12.2095 14 10.0004 14C7.79123 14 6.00037 12.2091 6.00037 10C6.00037 7.79086 7.79123 6 10.0004 6C12.2095 6 14.0004 7.79086 14.0004 10Z" fill-rule="evenodd" />
</svg>
</div>
<div x-cloak x-show="show">
<svg class="h-5 w-5" fill="currentColor" viewbox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path clip-rule="evenodd" d="M3.28033 2.21967C2.98744 1.92678 2.51256 1.92678 2.21967 2.21967C1.92678 2.51256 1.92678 2.98744 2.21967 3.28033L16.7197 17.7803C17.0126 18.0732 17.4874 18.0732 17.7803 17.7803C18.0732 17.4874 18.0732 17.0126 17.7803 16.7197L16.0352 14.9745C17.5064 13.8594 18.6595 12.3465 19.3344 10.5959C19.4814 10.2144 19.4816 9.79127 19.3347 9.40962C17.892 5.66051 14.256 3 9.99859 3C8.28207 3 6.66657 3.43249 5.2551 4.19444L3.28033 2.21967ZM7.75194 6.69128L8.84367 7.78301C9.18951 7.60223 9.58291 7.5 10.0002 7.5C11.3809 7.5 12.5002 8.61929 12.5002 10C12.5002 10.4173 12.398 10.8107 12.2172 11.1565L13.3091 12.2484C13.7454 11.6077 14.0004 10.8336 14.0004 10C14.0004 7.79086 12.2095 6 10.0004 6C9.16675 6 8.39268 6.25501 7.75194 6.69128Z" fill-rule="evenodd" /> <path d="M10.7484 13.9302L13.2711 16.4529C12.2462 16.8074 11.1458 17 10.0004 17C5.74298 17 2.10698 14.3395 0.664255 10.5904C0.517392 10.2087 0.517518 9.78563 0.66461 9.40408C1.15603 8.12932 1.90108 6.98057 2.83791 6.01969L6.0702 9.25198C6.02436 9.4943 6.00037 9.74435 6.00037 10C6.00037 12.2091 7.79123 14 10.0004 14C10.256 14 10.5061 13.976 10.7484 13.9302Z" />
</svg>
</div></button>
</div>
<div class="mt-2 text-red-600 text-sm">
</div>
</div>

View file

@ -4,8 +4,8 @@
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="../../theme/keywind/login/resources/dist/index.css" rel="stylesheet">
<script defer src="../../theme/keywind/login/resources/dist/index.js" type="module"></script>
<link href="http://localhost:5173/src/index.css" rel="stylesheet">
<script defer src="http://localhost:5173/src/index.ts" type="module"></script>
</head>
<body class="bg-secondary-100 flex flex-col items-center justify-center min-h-screen sm:py-16">
<div class="max-w-md space-y-6 w-full">

View file

@ -4,8 +4,8 @@
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="../../theme/keywind/login/resources/dist/index.css" rel="stylesheet">
<script defer src="../../theme/keywind/login/resources/dist/index.js" type="module"></script>
<link href="http://localhost:5173/src/index.css" rel="stylesheet">
<script defer src="http://localhost:5173/src/index.ts" type="module"></script>
</head>
<body class="bg-secondary-100 flex flex-col items-center justify-center min-h-screen sm:py-16">
<div class="max-w-md space-y-6 w-full">
@ -22,17 +22,17 @@
</div>
<form class="m-0 space-y-4" method="post" action="registrationAction">
<div>
<label class="sr-only" for="firstName"> First name </label> <input autofocus required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="firstName" name="firstName" placeholder="First name" autocomplete="given-name" type="text" value="">
<label class="sr-only" for="firstName"> First name </label> <input autofocus required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="firstName" name="firstName" placeholder="First name" type="text" autocomplete="given-name" value="">
<div class="mt-2 text-red-600 text-sm">
</div>
</div>
<div>
<label class="sr-only" for="lastName"> Last name </label> <input required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="lastName" name="lastName" placeholder="Last name" autocomplete="family-name" type="text" value="">
<label class="sr-only" for="lastName"> Last name </label> <input required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="lastName" name="lastName" placeholder="Last name" type="text" autocomplete="family-name" value="">
<div class="mt-2 text-red-600 text-sm">
</div>
</div>
<div>
<label class="sr-only" for="email"> Email </label> <input required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="email" name="email" placeholder="Email" autocomplete="email" type="email" value="">
<label class="sr-only" for="email"> Email </label> <input required aria-invalid="false" class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" id="email" name="email" placeholder="Email" type="email" autocomplete="email" value="">
<div class="mt-2 text-red-600 text-sm">
</div>
</div>

View file

@ -4,8 +4,8 @@
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="../../theme/keywind/login/resources/dist/index.css" rel="stylesheet">
<script defer src="../../theme/keywind/login/resources/dist/index.js" type="module"></script>
<link href="http://localhost:5173/src/index.css" rel="stylesheet">
<script defer src="http://localhost:5173/src/index.ts" type="module"></script>
</head>
<body class="bg-secondary-100 flex flex-col items-center justify-center min-h-screen sm:py-16">
<div class="max-w-md space-y-6 w-full">

View file

@ -4,9 +4,9 @@
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="../../theme/keywind/login/resources/dist/index.css" rel="stylesheet">
<script defer src="../../theme/keywind/login/resources/dist/webAuthnAuthenticate.js" type="module"></script>
<script defer src="../../theme/keywind/login/resources/dist/index.js" type="module"></script>
<link href="http://localhost:5173/src/index.css" rel="stylesheet">
<script defer src="http://localhost:5173/dist/webAuthnAuthenticate.js" type="module"></script>
<script defer src="http://localhost:5173/src/index.ts" type="module"></script>
</head>
<body class="bg-secondary-100 flex flex-col items-center justify-center min-h-screen sm:py-16">
<div class="max-w-md space-y-6 w-full">

View file

@ -4,8 +4,8 @@
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="../../theme/keywind/login/resources/dist/index.css" rel="stylesheet">
<script defer src="../../theme/keywind/login/resources/dist/index.js" type="module"></script>
<link href="http://localhost:5173/src/index.css" rel="stylesheet">
<script defer src="http://localhost:5173/src/index.ts" type="module"></script>
</head>
<body class="bg-secondary-100 flex flex-col items-center justify-center min-h-screen sm:py-16">
<div class="max-w-md space-y-6 w-full">

View file

@ -4,7 +4,7 @@
"scripts": {
"build": "tsc && vite build",
"build:jar": "vite-node scripts/build",
"dev": "vite build --watch",
"dev": "vite dev",
"test": "mvn test"
},
"dependencies": {

View file

@ -130,8 +130,8 @@ public class LoginDataModel {
private static Map<String, Object> createPropertiesModel() {
Map<String, Object> properties = new HashMap<>();
properties.put("scripts", "dist/index.js");
properties.put("styles", "dist/index.css");
properties.put("scripts", "src/index.ts");
properties.put("styles", "src/index.css");
return properties;
}
@ -227,7 +227,7 @@ public class LoginDataModel {
url.put("oauthAction", "oauthAction");
url.put("registrationAction", "registrationAction");
url.put("registrationUrl", "registrationUrl");
url.put("resourcesPath", "../../theme/keywind/login/resources");
url.put("resourcesPath", "http://localhost:5173");
return url;
}

View file

@ -0,0 +1,7 @@
<#-- https://github.com/tailwindlabs/heroicons/blob/master/src/20/solid/eye.svg -->
<#macro kw>
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path clip-rule="evenodd" d="M3.28033 2.21967C2.98744 1.92678 2.51256 1.92678 2.21967 2.21967C1.92678 2.51256 1.92678 2.98744 2.21967 3.28033L16.7197 17.7803C17.0126 18.0732 17.4874 18.0732 17.7803 17.7803C18.0732 17.4874 18.0732 17.0126 17.7803 16.7197L16.0352 14.9745C17.5064 13.8594 18.6595 12.3465 19.3344 10.5959C19.4814 10.2144 19.4816 9.79127 19.3347 9.40962C17.892 5.66051 14.256 3 9.99859 3C8.28207 3 6.66657 3.43249 5.2551 4.19444L3.28033 2.21967ZM7.75194 6.69128L8.84367 7.78301C9.18951 7.60223 9.58291 7.5 10.0002 7.5C11.3809 7.5 12.5002 8.61929 12.5002 10C12.5002 10.4173 12.398 10.8107 12.2172 11.1565L13.3091 12.2484C13.7454 11.6077 14.0004 10.8336 14.0004 10C14.0004 7.79086 12.2095 6 10.0004 6C9.16675 6 8.39268 6.25501 7.75194 6.69128Z" fill-rule="evenodd" />
<path d="M10.7484 13.9302L13.2711 16.4529C12.2462 16.8074 11.1458 17 10.0004 17C5.74298 17 2.10698 14.3395 0.664255 10.5904C0.517392 10.2087 0.517518 9.78563 0.66461 9.40408C1.15603 8.12932 1.90108 6.98057 2.83791 6.01969L6.0702 9.25198C6.02436 9.4943 6.00037 9.74435 6.00037 10C6.00037 12.2091 7.79123 14 10.0004 14C10.256 14 10.5061 13.976 10.7484 13.9302Z" />
</svg>
</#macro>

View file

@ -0,0 +1,7 @@
<#-- https://github.com/tailwindlabs/heroicons/blob/master/src/20/solid/eye.svg -->
<#macro kw>
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path d="M10 12.5C11.3807 12.5 12.5 11.3807 12.5 10C12.5 8.61929 11.3807 7.5 10 7.5C8.61929 7.5 7.5 8.61929 7.5 10C7.5 11.3807 8.61929 12.5 10 12.5Z" />
<path clip-rule="evenodd" d="M0.664255 10.5904C0.517392 10.2087 0.517518 9.78563 0.66461 9.40408C2.10878 5.65788 5.7433 3 9.99859 3C14.256 3 17.892 5.66051 19.3347 9.40962C19.4816 9.79127 19.4814 10.2144 19.3344 10.5959C17.8902 14.3421 14.2557 17 10.0004 17C5.74298 17 2.10698 14.3395 0.664255 10.5904ZM14.0004 10C14.0004 12.2091 12.2095 14 10.0004 14C7.79123 14 6.00037 12.2091 6.00037 10C6.00037 7.79086 7.79123 6 10.0004 6C12.2095 6 14.0004 7.79086 14.0004 10Z" fill-rule="evenodd" />
</svg>
</#macro>

View file

@ -1,33 +1,74 @@
<#import "/assets/icons/eye.ftl" as iconEye>
<#import "/assets/icons/eye-slash.ftl" as iconEyeSlash>
<#macro
kw
autofocus=false
class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm"
disabled=false
invalid=false
label=""
message=""
name=""
required=true
type="text"
rest...
>
<div>
<label class="sr-only" for="${name}">
${label}
</label>
<input
<#if autofocus>autofocus</#if>
<#if disabled>disabled</#if>
<#if required>required</#if>
<#if type == "password">
<div class="relative" x-data="{ show: false }">
<input
<#if autofocus>autofocus</#if>
<#if disabled>disabled</#if>
<#if required>required</#if>
aria-invalid="${invalid?c}"
class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm"
id="${name}"
name="${name}"
placeholder="${label}"
aria-invalid="${invalid?c}"
class="${class}"
id="${name}"
name="${name}"
placeholder="${label}"
:type="show ? 'text' : 'password'"
<#list rest as attrName, attrValue>
${attrName}="${attrValue}"
</#list>
>
<#list rest as attrName, attrValue>
${attrName}="${attrValue}"
</#list>
>
<button
@click="show = !show"
aria-controls="${name}"
:aria-expanded="show"
class="absolute text-secondary-400 right-3 top-3 sm:top-2"
type="button"
>
<div x-show="!show">
<@iconEye.kw />
</div>
<div x-cloak x-show="show">
<@iconEyeSlash.kw />
</div>
</button>
</div>
<#else>
<input
<#if autofocus>autofocus</#if>
<#if disabled>disabled</#if>
<#if required>required</#if>
aria-invalid="${invalid?c}"
class="${class}"
id="${name}"
name="${name}"
placeholder="${label}"
type="${type}"
<#list rest as attrName, attrValue>
${attrName}="${attrValue}"
</#list>
>
</#if>
<#if invalid?? && message??>
<div class="mt-2 text-red-600 text-sm">
${message?no_esc}

File diff suppressed because one or more lines are too long