- Split monolithic app.js/style.css into Alpine.js components (icons, store, fileSection, confirm)
- Add central Alpine.store('files') as single source of truth for file lists and actions
- Replace duplicated Inbox/Outbox markup with reusable fileSection component (props: dir, canShare)
- Add shared window.Icons module to remove duplicated inline SVGs
- Replace browser-native confirm() for file deletion with a styled, accessible modal dialog
- Split CSS into design tokens, base, and component layers; modernize visuals
- Update web.go embed and server static routes for the new component/style dirs
86 lines
1.9 KiB
JavaScript
86 lines
1.9 KiB
JavaScript
/**
|
|
* Confirmation dialog (a promise-based modal store + UI component).
|
|
*
|
|
* Replaces the browser-native `confirm()` with a styled, accessible modal.
|
|
* Components request confirmation via `Alpine.store('confirm').show(opts)`,
|
|
* which resolves `true`/`false` when the user acts — mirroring a UI-library
|
|
* dialog API.
|
|
*/
|
|
(function () {
|
|
function register() {
|
|
Alpine.store('confirm', {
|
|
open: false,
|
|
title: '',
|
|
message: '',
|
|
danger: false,
|
|
_resolve: null,
|
|
|
|
show(opts) {
|
|
this.title = opts.title || 'Confirm';
|
|
this.message = opts.message || '';
|
|
this.danger = opts.danger || false;
|
|
this.open = true;
|
|
return new Promise((resolve) => {
|
|
this._resolve = resolve;
|
|
});
|
|
},
|
|
|
|
accept() {
|
|
this._close(true);
|
|
},
|
|
|
|
cancel() {
|
|
this._close(false);
|
|
},
|
|
|
|
_close(result) {
|
|
this.open = false;
|
|
const resolve = this._resolve;
|
|
this._resolve = null;
|
|
if (resolve) resolve(result);
|
|
},
|
|
});
|
|
|
|
Alpine.data('confirmDialog', () => ({
|
|
get store() {
|
|
return Alpine.store('confirm');
|
|
},
|
|
get open() {
|
|
return this.store.open;
|
|
},
|
|
get title() {
|
|
return this.store.title;
|
|
},
|
|
get message() {
|
|
return this.store.message;
|
|
},
|
|
get danger() {
|
|
return this.store.danger;
|
|
},
|
|
|
|
accept() {
|
|
this.store.accept();
|
|
},
|
|
cancel() {
|
|
this.store.cancel();
|
|
},
|
|
onEscape() {
|
|
if (this.open) this.cancel();
|
|
},
|
|
|
|
init() {
|
|
this.$watch('open', (visible) => {
|
|
if (visible) {
|
|
this.$nextTick(() => {
|
|
if (this.$refs.accept) this.$refs.accept.focus();
|
|
});
|
|
}
|
|
});
|
|
},
|
|
}));
|
|
}
|
|
|
|
if (window.Alpine) register();
|
|
else document.addEventListener('alpine:init', register);
|
|
})();
|