feat: functional 'create' modal for feed records

This commit is contained in:
Corban-Lee Jones 2025-04-30 23:59:20 +01:00
parent e0cb99974f
commit d8141e485c
4 changed files with 185 additions and 16 deletions

View File

@ -99,9 +99,7 @@
@apply text-sm text-gray-500 dark:text-neutral-500 text-nowrap;
}
/* Select Box */
.cj-select-toggle {
.cj-table-paging-select-toggle {
@apply form-select hs-select-disabled:pointer-events-none
hs-select-disabled:opacity-50 relative py-2 px-3 pe-9 flex text-nowrap w-full
cursor-pointer bg-white border border-gray-200 rounded-lg text-start text-sm
@ -110,7 +108,7 @@
dark:text-neutral-200 dark:hover:bg-neutral-800 dark:focus:bg-neutral-800;
}
.cj-select-dropdown {
.cj-table-paging-select-dropdown {
@apply mt-2 z-50 w-20 max-h-72 p-1 space-y-0.5 bg-white border border-gray-200
rounded-lg shadow-md overflow-hidden overflow-y-auto [&::-webkit-scrollbar]:w-2
[&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-track]:bg-gray-100
@ -119,12 +117,74 @@
dark:border-neutral-700;
}
.cj-select-option {
.cj-table-paging-select-option {
@apply py-2 px-3 w-full text-sm text-gray-800 cursor-pointer hover:bg-gray-100
rounded-lg focus:outline-hidden focus:bg-gray-100 dark:bg-neutral-900
dark:hover:bg-neutral-800 dark:text-neutral-200 dark:focus:bg-neutral-800;
}
/* Tag Select */
.cj-tag-select-wrapper {
@apply relative form-select has-invalid:group-[.submitted]:border-red-500
has-invalid:group-[.submitted]:ring-red-500 py-0 ps-0.5 pe-9 min-h-[46px] flex items-center flex-wrap
text-nowrap w-full border border-gray-200 rounded-lg text-start text-sm focus:border-blue-500
focus:ring-blue-500 dark:bg-neutral-900 dark:border-neutral-700 dark:text-neutral-400;
}
.cj-tag-select-dropdown {
@apply
z-80
min-w-fit
max-h-72
p-1.5
space-y-0.5
bg-white
border
border-gray-200 rounded-lg overflow-hidden
overflow-y-auto
[&::-webkit-scrollbar]:w-2
[&::-webkit-scrollbar-thumb]:rounded-full
[&::-webkit-scrollbar-track]: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;
}
.cj-tag-select-input {
@apply px-2 rounded-xs order-1 text-sm outline-hidden dark:bg-neutral-900 dark:placeholder-neutral-500
dark:text-neutral-400;
}
.cj-tag-select-option {
@apply flex items-center rounded-lg cursor-pointer py-2 ps-2 pe-4 w-full
text-gray-500
hover:bg-gray-100
focus:bg-gray-100
dark:text-neutral-200
dark:bg-neutral-900
dark:hover:bg-neutral-800
dark:focus:bg-neutral-800;
}
.cj-tag-select-option [data-icon] {
@apply size-8 me-2 flex shrink-0 items-center justify-center text-gray-500 dark:text-neutral-500;
}
.cj-tag-select-option [data-title] {
@apply text-sm font-semibold text-gray-800 dark:text-neutral-200;
}
.cj-tag-select-option [data-description] {
@apply text-xs text-gray-500 dark:text-neutral-500;
}
/* Layout Sidebar */
.sidebar-btn {

View File

@ -251,18 +251,25 @@ const table: HSDataTable = new HSDataTable(
offset: offset
};
// Close on click.
window.addEventListener('click', (evt) => {
const evtTarget = evt.target;
HSSelect.closeCurrentlyOpened(evtTarget as HTMLElement);
});
const pageSelectOptions: ISelectOptions = {
toggleTag: "<button type=\"button\" aria-expanded=\"false\"></button>",
toggleTag: '<button type="button" aria-expanded="false"></button>',
optionTemplate: `
<div class=\"flex justify-between items-center w-full\">
<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 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>`,
toggleClasses: "cj-select-toggle",
optionClasses: "cj-select-option",
dropdownClasses: `cj-select-dropdown`,
toggleClasses: "cj-table-paging-select-toggle",
optionClasses: "cj-table-paging-select-option",
dropdownClasses: `cj-table-paging-select-dropdown`,
dropdownSpace: 10,
dropdownScope: "parent",
dropdownPlacement: "top",
@ -299,4 +306,69 @@ const closeEditModal = () => {
editModal.close();
};
const channelsSelectOptions: ISelectOptions = {
placeholder: "Select option....",
mode: "tags",
tagsItemTemplate: `
<div class="flex flex-nowrap items-center relative z-10 bg-white border border-gray-200 rounded-lg p-1 m-1 dark:bg-neutral-900 dark:border-neutral-700 ">
<div class="size-6 flex justify-center items-center" data-icon></div>
<div class="whitespace-nowrap text-gray-800 dark:text-neutral-200" data-title></div>
<div class="inline-flex shrink-0 justify-center items-center size-5 ms-2 rounded-lg text-gray-800 bg-gray-200 hover:bg-gray-300 focus:outline-hidden focus:ring-2 focus:ring-gray-400 text-sm dark:bg-neutral-700/50 dark:hover:bg-neutral-700 dark:text-neutral-400 cursor-pointer" data-remove>
<svg class="shrink-0 size-3" xmlns="http://www.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"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
</div>
</div>
`,
optionTemplate: `
<div class="cj-tag-select-option">
<div data-icon></div>
<div>
<div data-title></div>
<div data-description></div></div>
<div class="ms-auto">
<span class="hidden hs-selected:block">
<svg class="shrink-0 size-4 text-blue-600" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"><path d="M12.736 3.97a.733.733 0 0 1 1.047 0c.286.289.29.756.01 1.05L7.88 12.01a.733.733 0 0 1-1.065.02L3.217 8.384a.757.757 0 0 1 0-1.06.733.733 0 0 1 1.047 0l3.052 3.093 5.4-6.425a.247.247 0 0 1 .02-.022Z"/></svg>
</span>
</div>
</div>
`,
tagsInputId: "formChannelsInput",
wrapperClasses: "cj-tag-select-wrapper",
dropdownClasses: "cj-tag-select-dropdown w-full",
tagsInputClasses: "cj-tag-select-input",
dropdownScope: "window",
dropdownSpace: 10,
dropdownPlacement: "bottom",
dropdownVerticalFixedPlacement: null
};
const channelSelect: HSSelect = new HSSelect(
$("#formChannels").get(0) as HTMLElement,
channelsSelectOptions
);
$("#editForm").on("submit", async event => {
event.preventDefault();
const form = $(event.target).get(0) as HTMLFormElement;
$(form).addClass("submitted");
if (!form.checkValidity()) return;
await $.ajax({
url: `/guild/${guildId}/feeds/api`,
method: "post",
dataType: "json",
data: $(event.target).serializeArray(),
success: () => {
table.fireEvent("draw");
closeEditModal();
},
error: error => {
alert(JSON.stringify(error, null, 4));
}
});
});
// #endregion

View File

@ -16,7 +16,7 @@ import { formatTimestamp } from "../../../src/ts/main";
const emptyTableHtml: string = `
<div class="max-w-md w-full min-h-[400px] flex flex-col justify-center mx-auto px-6 py-4">
<div class="flex justify-center items-center size-[46px] bg-gray-100 rounded-lg dark:bg-neutral-800">
<svg class="shrink-0 size-6 text-gray-600 dark:text-neutral-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"><path d="M4 11a9 9 0 0 1 9 9"></path><path d="M4 4a16 16 0 0 1 16 16"></path><circle cx="5" cy="19" r="1"></circle></svg>
<svg class="shrink-0 size-6 text-gray-600 dark:text-neutral-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 3c2.755 0 5.455.232 8.083.678.533.09.917.556.917 1.096v1.044a2.25 2.25 0 0 1-.659 1.591l-5.432 5.432a2.25 2.25 0 0 0-.659 1.591v2.927a2.25 2.25 0 0 1-1.244 2.013L9.75 21v-6.568a2.25 2.25 0 0 0-.659-1.591L3.659 7.409A2.25 2.25 0 0 1 3 5.818V4.774c0-.54.384-1.006.917-1.096A48.32 48.32 0 0 1 12 3Z" /></svg>
</div>
<h2 class="mt-5 font-semibold text-gray-800 dark:text-white">
No results found
@ -241,9 +241,9 @@ const pageSelectOptions: ISelectOptions = {
<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>`,
toggleClasses: "cj-select-toggle",
optionClasses: "cj-select-option",
dropdownClasses: `cj-select-dropdown`,
toggleClasses: "cj-table-paging-select-toggle",
optionClasses: "cj-table-paging-select-option",
dropdownClasses: `cj-table-paging-select-dropdown`,
dropdownSpace: 10,
dropdownScope: "parent",
dropdownPlacement: "top",

View File

@ -168,6 +168,43 @@
Please enter a valid URL.
</p>
</div>
<div>
</div>
<div>
</div>
<div class="relative">
<label for="formChannels" class="text-input-label">Channels</label>
<select name="channels" id="formChannels" class="--prevent-on-load-init" multiple>
<option value="">Choose</option>
<% guild.channels.cache
.filter(channel => channel.type == 0)
.sort((a, b) => a.rawPosition - b.rawPosition)
.forEach(channel => { %>
<option value="<%= channel.id %>" data-hs-select-option='{
"description": "<%= channel.id %>",
"icon": "<svg class=\"shrink-0 size-[16px]\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"4\" y1=\"9\" x2=\"20\" y2=\"9\"></line><line x1=\"4\" y1=\"15\" x2=\"20\" y2=\"15\"></line><line x1=\"10\" y1=\"3\" x2=\"8\" y2=\"21\"></line><line x1=\"16\" y1=\"3\" x2=\"14\" y2=\"21\"></line></svg>"
}'>
<%= channel.name %>
</option>
<% }); %>
</select>
</div>
<div>
</div>
<div></div>
<div></div>
<div>
<label for="formActive" class="flex gap-4">
<input type="checkbox" id="formActive" name="active" class="form-radio relative w-[3.25rem] h-7 p-px bg-gray-100 border-transparent text-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:ring-blue-600 disabled:opacity-50 disabled:pointer-events-none checked:bg-none checked:text-blue-600 checked:border-blue-600 focus:checked:border-blue-600 dark:bg-neutral-800 dark:border-neutral-700 dark:checked:bg-blue-500 dark:checked:border-blue-500 dark:focus:ring-offset-gray-600 before:inline-block before:size-6 before:bg-white checked:before:bg-blue-200 before:translate-x-0 checked:before:translate-x-full before:rounded-full before:shadow-sm before:transform before:ring-0 before:transition before:ease-in-out before:duration-200 dark:before:bg-neutral-400 dark:checked:before:bg-blue-200">
<span class="flex flex-col">
<span class="block text-sm dark:text-neutral-400">Active</span>
<span class="block text-sm text-gray-500 dark:text-neutral-500">Inactive entries will not be processed.</span>
</span>
</label>
</div>
</form>
<div class="flex items-center gap-x-2 mt-8">