This is a viewer only at the moment see the article on how this works.
To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk
This is a preview from the server running through my markdig pipeline
HTMX on loistava kirjasto, joka tekee web-sovelluksistasi entistä dynaamisempia ja reagoivampia. Tässä viestissä näytän, miten HTMX:llä näytetään paahtoleipämainos ja vaihdetaan sisältöä sivulla.
Yksi normaalin HTMX:n "rajoituksista" on se, että yleensä vain yksi sisältö vaihdetaan takapäästä. Tämä voidaan kuitenkin ratkaista käyttämällä HX-Trigger
Headers ja pieni javascript.
Olen käyttänyt tätä yksinkertaista paahtoleipäilmoitusjärjestelmää jo jonkin aikaa. Se on yksinkertainen toiminto, joka vie viestin, keston ja tyypin (menestys, virhe, varoitus) ja näyttää paahtoleipäilmoituksen sivulla.
// HTMX toast notification
// Simple HTMX toast handler for use with hx-on::after-request
window.showToast = (message, duration = 3000, type = 'info') => {
const toast = document.getElementById('toast');
const toastMessage = document.getElementById('toast-message');
const toastText = document.getElementById('toast-text');
const toastIcon = document.getElementById('toast-icon');
// Reset classes
toastMessage.className = 'alert shadow-lg gap-2 transition-all duration-300 ease-in-out cursor-pointer';
toastIcon.className = 'bx text-2xl';
// Add DaisyUI alert type
const alertClass = `alert-${type}`;
toastMessage.classList.add(alertClass);
// Add icon class
const iconMap = {
success: 'bx-check-circle',
error: 'bx-error-circle',
warning: 'bx-error',
info: 'bx-info-circle'
};
const iconClass = iconMap[type] || 'bx-bell';
toastIcon.classList.add(iconClass);
// Set the message
toastText.textContent = message;
// Add slide-in animation
toastMessage.classList.add('animate-slide-in');
toast.classList.remove('hidden');
// Allow click to dismiss
toastMessage.onclick = () => hideToast();
// Auto-dismiss
clearTimeout(window.toastTimeout);
window.toastTimeout = setTimeout(() => hideToast(), duration);
function hideToast() {
toastMessage.classList.remove('animate-slide-in');
toastMessage.classList.add('animate-fade-out');
toastMessage.onclick = null;
toastMessage.addEventListener('animationend', () => {
toast.classList.add('hidden');
toastMessage.classList.remove('animate-fade-out');
}, { once: true });
}
};
Tämä käyttää pientä HTML-kimppua, jonka määrittelen omassani _Layout.cshtml-tiedosto (käyttäen suosikkiani Tailwind CSS & DaisyUI). Huomaa lopussa "luokan säilytyspalikka". Tämä on pieni temppu, jolla varmistetaan, että luokat säilyvät lopullisessa HTML-tuotoksessa. Tämä on todella myötätuuleen, kun katson vain cshtml
.
<div
id="toast"
class="toast toast-bottom fixed z-50 hidden w-full md:w-auto max-w-sm right-4 bottom-4"
>
<div
id="toast-message"
class="alert shadow-lg gap-2 transition-all duration-300 ease-in-out cursor-pointer"
>
<i id="toast-icon" class="bx text-2xl"></i>
<span id="toast-text">Notification message</span>
</div>
</div>
<!-- class-preserving dummy block -->
<div class="hidden">
<div class="alert alert-success alert-error alert-warning alert-info"></div>
<i class="bx bx-check-circle bx-error-circle bx-error bx-info-circle bx-bell"></i>
<div class="animate-slide-in animate-fade-out"></div>
</div>
Määritän tässä, mitä tiedostot "puiden shake" ja mitä animaatioluokkia paahtoleipä käyttää.
const defaultTheme = require("tailwindcss/defaultTheme");
module.exports = {
content: ["./Views/**/*.cshtml", "./Areas/**/*.cshtml"],
safelist: ["dark"],
darkMode: "class",
theme: {
extend: {
keyframes: {
'slide-in': {
'0%': { opacity: 0, transform: 'translateY(20px)' },
'100%': { opacity: 1, transform: 'translateY(0)' },
},
'fade-out': {
'0%': { opacity: 1 },
'100%': { opacity: 0 },
},
},
animation: {
'slide-in': 'slide-in 0.3s ease-out',
'fade-out': 'fade-out 0.5s ease-in forwards',
},
},
plugins: [require("daisyui")],
};
Salaisuus saada tämä kaikki toimimaan on käyttää HTMX-laukaisimen toiminnallisuus.
Nyt "normaalisti" tekisit Määrittele tämä varsinaisessa html / partakoneen koodissa:
<div hx-get="/clicked" hx-trigger="click[ctrlKey]">Control Click Me</div>
Tai voit määritellä sen tilausten jälkeisessä tapahtumassa. Joten jos teet jotain, se laukaisee uuden tapahtuman.
<button
hx-get="/api/do-something"
hx-swap="none"
hx-on::afterRequest="window.showToast('API call complete!', 3000, 'success')"
class="btn btn-primary"
>
Do Something
</button>
Tämä on kätevää, jos haluat vain "tehdä jotain, mikä osoittaa, että se on tehty", mutta minun tapauksessani haluan vaihtaa sisältöä ja nostaa maljan.
Response.Headers.Append("HX-Trigger", JsonSerializer.Serialize(new
{
showToast = new
{
toast = result.Message,
issuccess = result.Success
}
}));
Minun tapauksessani liipaisin on nimetty showToast
ja välitän viestin ja menestyslipun. Joten minun JS Olen määritellyt tapahtuman kuuntelijaksi tämän tapahtuman. "Tämän jälkeen showToast
toimi ja kulkee viestissä ja menestyslipussa.
// Handles HX-Trigger: { "showToast": { "toast": "...", "issuccess": true } }
document.body.addEventListener("showToast", (event) => {
const { toast, issuccess } = event.detail || {};
const type = issuccess === false ? 'error' : 'success';
showToast(toast || 'Done!', 3000, type);
});
Miksi käytän tätä? No, tuoreessa työprojektissa halusin ryhtyä toimenpiteisiin pöydässä näkyvän käyttäjän suhteen. Halusin näyttää paahtoleipäilmoituksen ja vaihtaa käyttäjärivin sisällön uuteen sisältöön.
Kuten näette, minulla on BUNCH nappeja, jotka "tekevät juttuja" käyttäjälle. Halusin näyttää paahtoleipäilmoituksen ja vaihtaa käyttäjärivin sisällön uuteen sisältöön.
Joten minun hallinnassani on yksinkertainen "kytkin", joka ottaa toiminnan nimen, tekee juttuja sitten palauttaa uuden pyynnön tulos.
private async Task ApplyAction(string email, string useraction)
{
if (!string.IsNullOrWhiteSpace(useraction) &&
Enum.TryParse<UserActionType>(useraction, true, out var parsedAction))
{
RequestResult result;
switch (parsedAction)
{
case UserActionType.FlipRoles:
result = await userActionService.FlipRestaurantPermissions(email);
break;
case UserActionType.UnflipRoles:
result = await userActionService.UnFlipRestaurantPermissions(email);
break;
case UserActionType.Enable2FA:
result = await userActionService.ToggleMFA(email, true);
break;
case UserActionType.Disable2FA:
result = await userActionService.ToggleMFA(email, false);
break;
case UserActionType.RevokeTokens:
result = await userActionService.RevokeTokens(email);
break;
case UserActionType.Lock:
result = await userActionService.Lock(email);
break;
case UserActionType.Unlock:
result = await userActionService.Unlock(email);
break;
case UserActionType.Nuke:
result = await userActionService.Nuke(email);
break;
case UserActionType.Disable:
result = await userActionService