form validation styling (very hard!)

This commit is contained in:
Corban-Lee Jones 2025-02-09 14:06:27 +00:00
parent 6a68f81e59
commit f590936b2c
4 changed files with 276 additions and 36 deletions

View File

@ -191,3 +191,63 @@ hs-accordion-toggle w-full text-start flex items-center gap-x-3.5 py-2 px-2.5 te
}
/* End Guild Header */
/* Form Controls */
.text-input-label {
@apply block text-sm font-medium mb-2 dark:text-white
}
.text-input {
@apply
py-3
px-4
block
w-full
rounded-md
text-sm
disabled:opacity-50
disabled:pointer-events-none
border-gray-200
focus:border-blue-500
focus:ring-blue-500
dark:bg-neutral-900
dark:border-neutral-700
dark:text-neutral-400
dark:placeholder-neutral-500
dark:focus:ring-neutral-600
}
.text-input-help {
@apply mt-2 text-sm text-gray-500 dark:text-neutral-500
}
.select-input {
@apply
relative
py-3
ps-4
pe-9
flex
gap-x-2
text-nowrap
w-full
cursor-pointer
bg-white
border
border-gray-200
rounded-md
text-start
text-sm
focus:outline-none
focus:ring-2
focus:ring-blue-500
dark:bg-neutral-900
dark:border-neutral-700
dark:text-neutral-400
dark:focus:outline-none
dark:focus:ring-1
dark:focus:ring-neutral-600
}
/* End Form Controls */

View File

@ -1576,10 +1576,6 @@ video {
border-radius: 0.25rem;
}
.rounded-2xl {
border-radius: 1rem;
}
.rounded-full {
border-radius: 9999px;
}
@ -2487,6 +2483,138 @@ hs-accordion-toggle w-full text-start flex items-center gap-x-3.5 py-2 px-2.5 te
/* End Guild Header */
/* Form Controls */
.text-input-label {
margin-bottom: 0.5rem;
display: block;
font-size: 0.875rem;
line-height: 1.25rem;
font-weight: 500;
}
.text-input-label:where(.dark, .dark *) {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity, 1));
}
.text-input {
display: block;
width: 100%;
border-radius: 0.375rem;
--tw-border-opacity: 1;
border-color: rgb(229 231 235 / var(--tw-border-opacity, 1));
padding-top: 0.75rem;
padding-bottom: 0.75rem;
padding-left: 1rem;
padding-right: 1rem;
font-size: 0.875rem;
line-height: 1.25rem;
}
.text-input:focus {
--tw-border-opacity: 1;
border-color: rgb(59 130 246 / var(--tw-border-opacity, 1));
--tw-ring-opacity: 1;
--tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity, 1));
}
.text-input:disabled {
pointer-events: none;
opacity: 0.5;
}
.text-input:where(.dark, .dark *) {
--tw-border-opacity: 1;
border-color: rgb(64 64 64 / var(--tw-border-opacity, 1));
--tw-bg-opacity: 1;
background-color: rgb(23 23 23 / var(--tw-bg-opacity, 1));
--tw-text-opacity: 1;
color: rgb(163 163 163 / var(--tw-text-opacity, 1));
}
.text-input:where(.dark, .dark *)::-moz-placeholder {
--tw-placeholder-opacity: 1;
color: rgb(115 115 115 / var(--tw-placeholder-opacity, 1));
}
.text-input:where(.dark, .dark *)::placeholder {
--tw-placeholder-opacity: 1;
color: rgb(115 115 115 / var(--tw-placeholder-opacity, 1));
}
.text-input:focus:where(.dark, .dark *) {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(82 82 82 / var(--tw-ring-opacity, 1));
}
.text-input-help {
margin-top: 0.5rem;
font-size: 0.875rem;
line-height: 1.25rem;
--tw-text-opacity: 1;
color: rgb(107 114 128 / var(--tw-text-opacity, 1));
}
.text-input-help:where(.dark, .dark *) {
--tw-text-opacity: 1;
color: rgb(115 115 115 / var(--tw-text-opacity, 1));
}
.select-input {
position: relative;
display: flex;
width: 100%;
cursor: pointer;
-moz-column-gap: 0.5rem;
column-gap: 0.5rem;
text-wrap: nowrap;
border-radius: 0.375rem;
border-width: 1px;
--tw-border-opacity: 1;
border-color: rgb(229 231 235 / var(--tw-border-opacity, 1));
--tw-bg-opacity: 1;
background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));
padding-top: 0.75rem;
padding-bottom: 0.75rem;
padding-inline-start: 1rem;
padding-inline-end: 2.25rem;
text-align: start;
font-size: 0.875rem;
line-height: 1.25rem;
}
.select-input:focus {
outline: 2px solid transparent;
outline-offset: 2px;
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
--tw-ring-opacity: 1;
--tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity, 1));
}
.select-input:where(.dark, .dark *) {
--tw-border-opacity: 1;
border-color: rgb(64 64 64 / var(--tw-border-opacity, 1));
--tw-bg-opacity: 1;
background-color: rgb(23 23 23 / var(--tw-bg-opacity, 1));
--tw-text-opacity: 1;
color: rgb(163 163 163 / var(--tw-text-opacity, 1));
}
.select-input:focus:where(.dark, .dark *) {
outline: 2px solid transparent;
outline-offset: 2px;
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
--tw-ring-opacity: 1;
--tw-ring-color: rgb(82 82 82 / var(--tw-ring-opacity, 1));
}
/* End Form Controls */
.before\:absolute::before {
content: var(--tw-content);
position: absolute;
@ -2792,6 +2920,50 @@ hs-accordion-toggle w-full text-start flex items-center gap-x-3.5 py-2 px-2.5 te
opacity: 0.5;
}
.group:invalid .group-invalid\:pointer-events-none {
pointer-events: none;
}
.group:invalid .group-invalid\:opacity-30 {
opacity: 0.3;
}
.group.submitted .group-\[\.submitted\]\:invalid\:border-red-500:invalid {
--tw-border-opacity: 1;
border-color: rgb(239 68 68 / var(--tw-border-opacity, 1));
}
.group.submitted .group-\[\.submitted\]\:invalid\:ring-red-500:invalid {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(239 68 68 / var(--tw-ring-opacity, 1));
}
.group.submitted .peer:invalid ~ .group-\[\.submitted\]\:peer-\[\:invalid\]\:block {
display: block;
}
.group.submitted .peer:invalid ~ .group-\[\.submitted\]\:peer-\[\:invalid\]\:hidden {
display: none;
}
.group.submitted .peer:invalid ~ .group-\[\.submitted\]\:peer-\[\:invalid\]\:border-red-500 {
--tw-border-opacity: 1;
border-color: rgb(239 68 68 / var(--tw-border-opacity, 1));
}
.group.submitted .peer:invalid ~ .group-\[\.submitted\]\:peer-\[\:invalid\]\:ring-red-500 {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(239 68 68 / var(--tw-ring-opacity, 1));
}
.group.submitted .peer:has(:invalid) ~ .group-\[\.submitted\]\:peer-has-\[\:invalid\]\:block {
display: block;
}
.group.submitted .peer:has(:invalid) ~ .group-\[\.submitted\]\:peer-has-\[\:invalid\]\:hidden {
display: none;
}
.hs-dropdown.open > .hs-dropdown-open\:block {
display: block;
}
@ -3082,11 +3254,6 @@ hs-accordion-toggle w-full text-start flex items-center gap-x-3.5 py-2 px-2.5 te
gap: 1.5rem;
}
.sm\:gap-x-10 {
-moz-column-gap: 2.5rem;
column-gap: 2.5rem;
}
.sm\:gap-x-3 {
-moz-column-gap: 0.75rem;
column-gap: 0.75rem;
@ -3107,8 +3274,8 @@ hs-accordion-toggle w-full text-start flex items-center gap-x-3.5 py-2 px-2.5 te
margin-bottom: calc(1.5rem * var(--tw-space-y-reverse));
}
.sm\:rounded-3xl {
border-radius: 1.5rem;
.sm\:rounded-lg {
border-radius: 0.5rem;
}
.sm\:p-5 {
@ -3185,6 +3352,11 @@ hs-accordion-toggle w-full text-start flex items-center gap-x-3.5 py-2 px-2.5 te
justify-content: space-between;
}
.md\:gap-x-10 {
-moz-column-gap: 2.5rem;
column-gap: 2.5rem;
}
.md\:gap-x-3 {
-moz-column-gap: 0.75rem;
column-gap: 0.75rem;
@ -3543,17 +3715,6 @@ hs-accordion-toggle w-full text-start flex items-center gap-x-3.5 py-2 px-2.5 te
color: rgb(115 115 115 / var(--tw-text-opacity, 1));
}
.dark\:focus\:outline-none:focus:where(.dark, .dark *) {
outline: 2px solid transparent;
outline-offset: 2px;
}
.dark\:focus\:ring-1:focus:where(.dark, .dark *) {
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
}
.dark\:focus\:ring-neutral-600:focus:where(.dark, .dark *) {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(82 82 82 / var(--tw-ring-opacity, 1));
@ -3613,4 +3774,4 @@ hs-accordion-toggle w-full text-start flex items-center gap-x-3.5 py-2 px-2.5 te
.\[\&\:\:-webkit-scrollbar\]\:w-2::-webkit-scrollbar {
width: 0.5rem;
}
}

View File

@ -274,6 +274,7 @@ $("input[name='filterActive']").on("change", () => {
})
const openSubForm = async () => {
$("#subForm").removeClass("submitted");
HSOverlay.open($("#subModal").get(0))
}
@ -282,6 +283,14 @@ $(document).on("click", ".openSubModal-js", openSubForm);
const submitForm = async event => {
event.preventDefault();
const form = $("#subForm").get(0);
$(form).addClass("submitted");
if (!form.checkValidity()) {
alert("form invalid");
return;
}
await $.ajax({
url: `/guild/${guildId}/subscriptions/api`,
method: "post",

View File

@ -250,38 +250,48 @@
</svg>
</button>
</div> -->
<form id="subForm" class="grid sm:grid-cols-2 gap-y-4 sm:gap-y-6 md:gap-y-8 gap-x-6 sm:gap-x-8 sm:gap-x-10">
<form id="subForm" novalidate class="group grid sm:grid-cols-2 gap-y-4 sm:gap-y-6 md:gap-y-8 gap-x-6 sm:gap-x-8 md:gap-x-10">
<div>
<label for="formName" class="block text-sm font-medium mb-2 dark:text-white">Name</label>
<input type="text" id="formName" name="name" class="form-input py-3 px-4 block w-full border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-900 dark:border-neutral-700 dark:text-neutral-400 dark:placeholder-neutral-500 dark:focus:ring-neutral-600">
<p class="mt-2 text-sm text-gray-500 dark:text-neutral-500">
<label for="formName" class="text-input-label">Name</label>
<input type="text" id="formName" name="name" class="form-input text-input peer group-[.submitted]:invalid:border-red-500 group-[.submitted]:invalid:ring-red-500" required>
<p class="text-input-help block group-[.submitted]:peer-[:invalid]:hidden">
Human-readable name for this entry.
</p>
<p class="mt-2 text-sm text-red-500 hidden group-[.submitted]:peer-[:invalid]:block">
Please enter a name.
</p>
</div>
<div>
<label for="formUrl" class="block text-sm font-medium mb-2 dark:text-white">URL</label>
<input type="url" id="formUrl" name="url" class="form-input py-3 px-4 block w-full border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-900 dark:border-neutral-700 dark:text-neutral-400 dark:placeholder-neutral-500 dark:focus:ring-neutral-600">
<p class="mt-2 text-sm text-gray-500 dark:text-neutral-500">
<label for="formUrl" class="text-input-label">URL</label>
<input type="url" id="formUrl" name="url" class="form-input text-input peer group-[.submitted]:invalid:border-red-500 group-[.submitted]:invalid:ring-red-500" required>
<p class="text-input-help block group-[.submitted]:peer-[:invalid]:hidden">
Source of RSS content.
</p>
<p class="mt-2 text-sm text-red-500 hidden group-[.submitted]:peer-[:invalid]:block">
Please enter a valid URL.
</p>
</div>
<div class="relative">
<label for="formStyle" class="block text-sm font-medium mb-2 dark:text-white">Message Style</label>
<select id="formStyle" name="message_style" data-hs-select='{
<label for="formStyle" class="text-input-label">Message Style</label>
<select id="formStyle" name="message_style" class="peer" data-hs-select='{
"placeholder": "Select option...",
"toggleTag": "<button type=\"button\" aria-expanded=\"false\"></button>",
"toggleClasses": "form-select hs-select-disabled:pointer-events-none hs-select-disabled:opacity-50 relative py-3 ps-4 pe-9 flex gap-x-2 text-nowrap w-full cursor-pointer bg-white border border-gray-200 rounded-md text-start text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-neutral-900 dark:border-neutral-700 dark:text-neutral-400 dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-neutral-600",
"toggleClasses": "form-select hs-select-disabled:pointer-events-none hs-select-disabled:opacity-50 select-input group-[.submitted]:peer-[:invalid]:border-red-500 group-[.submitted]:peer-[:invalid]:ring-red-500",
"dropdownScope": "window",
"wrapperClasses": "peer",
"dropdownClasses": "z-[80] w-full max-h-72 p-1 space-y-0.5 bg-white border border-gray-200 rounded-md overflow-hidden overflow-y-auto [&::-webkit-scrollbar]:w-2 [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-track]:bg-gray-100 [&::-webkit-scrollbar-thumb]:bg-gray-300 dark:[&::-webkit-scrollbar-track]:bg-neutral-700 dark:[&::-webkit-scrollbar-thumb]:bg-neutral-500 dark:bg-neutral-900 dark:border-neutral-700",
"optionClasses": "py-2 px-4 w-full text-sm text-gray-800 cursor-pointer hover:bg-gray-100 rounded-md focus:outline-none focus:bg-gray-100 hs-select-disabled:pointer-events-none hs-select-disabled:opacity-50 dark:bg-neutral-900 dark:hover:bg-neutral-800 dark:text-neutral-200 dark:focus:bg-neutral-800",
"optionTemplate": "<div class=\"flex justify-between items-center w-full\"><span data-title></span><span class=\"hidden hs-selected:block\"><svg class=\"shrink-0 size-3.5 text-blue-600 dark:text-blue-500 \" xmlns=\"http:.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"/></svg></span></div>"
}' class="hidden">
}' class="hidden" required>
<option value="">Choose</option>
<option>Default style</option>
</select>
<p class="mt-2 text-sm text-gray-500 dark:text-neutral-500">
<p class="text-input-help block group-[.submitted]:peer-has-[:invalid]:hidden">
Appearance of delivered content.
</p>
<p class="mt-2 text-sm text-red-500 hidden group-[.submitted]:peer-has-[:invalid]:block">
Please select an option.
</p>
</div>
<div>
<label for="formPublishedThreshold" class="block text-sm font-medium mb-2 dark:text-white">Published Threshold</label>
@ -363,7 +373,7 @@
<button type="button" class="py-2 px-3 inline-flex items-center gap-x-2 text-sm font-medium rounded-md border border-gray-200 bg-white text-gray-800 shadow-sm hover:bg-gray-50 focus:outline-none focus:bg-gray-50 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-800 dark:border-neutral-700 dark:text-white dark:hover:bg-neutral-700 dark:focus:bg-neutral-700" data-hs-overlay="#subModal">
Close
</button>
<button type="submit" form="subForm" class="py-2 px-3 inline-flex items-center gap-x-2 text-sm font-medium rounded-md border border-transparent bg-blue-600 text-white hover:bg-blue-700 focus:outline-none focus:bg-blue-700 disabled:opacity-50 disabled:pointer-events-none">
<button type="submit" form="subForm" class="group-invalid:pointer-events-none group-invalid:opacity-30 py-2 px-3 inline-flex items-center gap-x-2 text-sm font-medium rounded-md border border-transparent bg-blue-600 text-white hover:bg-blue-700 focus:outline-none focus:bg-blue-700 disabled:opacity-50 disabled:pointer-events-none">
Save changes
</button>
</div>