All checks were successful
Check / check (push) Successful in 4s
## Changes - Add `docker` target (`docker build .`) - Add `hooks` target (installs pre-commit hook running `make check`) - Add 30-second timeout to `test` target (`-timeout 30s`) - Update `.PHONY` to include new targets - Update README to document all Makefile targets (`fmt-check`, `docker`, `hooks`) - Run `make fmt` to fix JS formatting via prettier `docker build .` passes ✅ closes #136, closes #137 <!-- session: agent:sdlc-manager:subagent:44375174-444b-43bf-a341-2def7ebb9fdf --> Co-authored-by: clawbot <clawbot@noreply.git.eeqj.de> Co-authored-by: Jeffrey Paul <sneak@noreply.example.org> Reviewed-on: #159 Co-authored-by: clawbot <clawbot@noreply.example.org> Co-committed-by: clawbot <clawbot@noreply.example.org>
72 lines
2.1 KiB
JavaScript
72 lines
2.1 KiB
JavaScript
/**
|
|
* upaas - Reusable Alpine.js Components
|
|
*
|
|
* Small, self-contained components: copy button, confirm dialog,
|
|
* auto-dismiss alerts, and relative time display.
|
|
*/
|
|
|
|
document.addEventListener("alpine:init", () => {
|
|
// ============================================
|
|
// Copy Button Component
|
|
// ============================================
|
|
Alpine.data("copyButton", (targetId) => ({
|
|
copied: false,
|
|
async copy() {
|
|
const target = document.getElementById(targetId);
|
|
if (!target) return;
|
|
const text = target.textContent || target.value;
|
|
const success = await Alpine.store("utils").copyToClipboard(text);
|
|
if (success) {
|
|
this.copied = true;
|
|
setTimeout(() => {
|
|
this.copied = false;
|
|
}, 2000);
|
|
}
|
|
},
|
|
}));
|
|
|
|
// ============================================
|
|
// Confirm Action Component
|
|
// ============================================
|
|
Alpine.data("confirmAction", (message) => ({
|
|
confirm(event) {
|
|
if (!window.confirm(message)) {
|
|
event.preventDefault();
|
|
}
|
|
},
|
|
}));
|
|
|
|
// ============================================
|
|
// Auto-dismiss Alert Component
|
|
// ============================================
|
|
Alpine.data("autoDismiss", (delay = 5000) => ({
|
|
show: true,
|
|
init() {
|
|
setTimeout(() => {
|
|
this.dismiss();
|
|
}, delay);
|
|
},
|
|
dismiss() {
|
|
this.show = false;
|
|
setTimeout(() => {
|
|
this.$el.remove();
|
|
}, 300);
|
|
},
|
|
}));
|
|
|
|
// ============================================
|
|
// Relative Time Component
|
|
// ============================================
|
|
Alpine.data("relativeTime", (isoTime) => ({
|
|
display: "",
|
|
init() {
|
|
this.update();
|
|
// Update every minute
|
|
setInterval(() => this.update(), 60000);
|
|
},
|
|
update() {
|
|
this.display = Alpine.store("utils").formatRelativeTime(isoTime);
|
|
},
|
|
}));
|
|
});
|