feat: Phase 1 — extract the client (web SPA + desktop) to dtoro/oikos-web
Problem: the hexagonal refactor churns the backend tree for nine more phases; the UI delivery stack (web/ SPA, cmd/desktop Wails wrapper, compose/web image) must move to its own repo first so doc/layout rewrites land once on a backend-only tree. Change: - New repo git.hubris.network/dtoro/oikos-web (v0.33.0): web/, desktop/ (updateURL repointed to oikos-web releases), compose/, own CI (web + desktop jobs), own deploy script (CI-green gate, TOCTOU guard, version-tagged images, prune-to-3), own webhook receiver on :9798 + launchd unit, own compose project publishing the same 8091:80. - Cutover executed on mac-mini in order: oikos stack's web service stopped+removed, oikos-web project brought up on 8091; outer Caddy untouched (targets the published port) — serving + Authentik flow + /wails 404 quirk verified post-cutover. - Stripped from oikos: web/, cmd/desktop/, compose/web/, desktop CI workflow, ci.yml web job, Makefile ui/desktop/desktop-package/install targets, the compose web service, oikos-web from deploy.sh's fallback prune list; wails + go-keyring dropped from go.mod, vendor synced. - README / CONTRIBUTING / AGENTS.md / .agents dev+operations docs now point at the new repo; mbse + mascot design docs carry a path note. Risk: production SPA serving depends on the new pipeline now; rollback is versioned-image re-up of the old web service from a pre-split checkout (port 8091). Desktop builds installed before the split still check dtoro/oikos releases — one manual reinstall, noted in the oikos-web release notes. Verification: go vet, make test (race), make generate-check, golangci (no new findings; baseline down 400→365); post-cutover curls — localhost:8091 200, /wails/runtime.js 404, outer Caddy 302 Authentik.
This commit is contained in:
360
web/node_modules/bits-ui/dist/bits/dialog/dialog.svelte.js
generated
vendored
Normal file
360
web/node_modules/bits-ui/dist/bits/dialog/dialog.svelte.js
generated
vendored
Normal file
@@ -0,0 +1,360 @@
|
||||
import { attachRef, boxWith, onDestroyEffect, } from "svelte-toolbelt";
|
||||
import { Context, watch } from "runed";
|
||||
import { createBitsAttrs, boolToStr, getDataOpenClosed, boolToEmptyStrOrUndef, getDataTransitionAttrs, } from "../../internal/attrs.js";
|
||||
import { kbd } from "../../internal/kbd.js";
|
||||
import { PresenceManager } from "../../internal/presence-manager.svelte.js";
|
||||
const dialogAttrs = createBitsAttrs({
|
||||
component: "dialog",
|
||||
parts: ["content", "trigger", "overlay", "title", "description", "close", "cancel", "action"],
|
||||
});
|
||||
const DialogRootContext = new Context("Dialog.Root | AlertDialog.Root");
|
||||
export class DialogRootState {
|
||||
static create(opts) {
|
||||
const parent = DialogRootContext.getOr(null);
|
||||
return DialogRootContext.set(new DialogRootState(opts, parent));
|
||||
}
|
||||
opts;
|
||||
triggerNode = $state(null);
|
||||
contentNode = $state(null);
|
||||
overlayNode = $state(null);
|
||||
descriptionNode = $state(null);
|
||||
contentId = $state(undefined);
|
||||
titleId = $state(undefined);
|
||||
triggerId = $state(undefined);
|
||||
descriptionId = $state(undefined);
|
||||
cancelNode = $state(null);
|
||||
nestedOpenCount = $state(0);
|
||||
depth;
|
||||
parent;
|
||||
contentPresence;
|
||||
overlayPresence;
|
||||
constructor(opts, parent) {
|
||||
this.opts = opts;
|
||||
this.parent = parent;
|
||||
this.depth = parent ? parent.depth + 1 : 0;
|
||||
this.handleOpen = this.handleOpen.bind(this);
|
||||
this.handleClose = this.handleClose.bind(this);
|
||||
this.contentPresence = new PresenceManager({
|
||||
ref: boxWith(() => this.contentNode),
|
||||
open: this.opts.open,
|
||||
enabled: true,
|
||||
onComplete: () => {
|
||||
this.opts.onOpenChangeComplete.current(this.opts.open.current);
|
||||
},
|
||||
});
|
||||
this.overlayPresence = new PresenceManager({
|
||||
ref: boxWith(() => this.overlayNode),
|
||||
open: this.opts.open,
|
||||
enabled: true,
|
||||
});
|
||||
watch(() => this.opts.open.current, (isOpen) => {
|
||||
if (!this.parent)
|
||||
return;
|
||||
if (isOpen) {
|
||||
this.parent.incrementNested();
|
||||
}
|
||||
else {
|
||||
this.parent.decrementNested();
|
||||
}
|
||||
}, { lazy: true });
|
||||
onDestroyEffect(() => {
|
||||
if (this.opts.open.current) {
|
||||
this.parent?.decrementNested();
|
||||
}
|
||||
});
|
||||
}
|
||||
handleOpen() {
|
||||
if (this.opts.open.current)
|
||||
return;
|
||||
this.opts.open.current = true;
|
||||
}
|
||||
handleClose() {
|
||||
if (!this.opts.open.current)
|
||||
return;
|
||||
this.opts.open.current = false;
|
||||
}
|
||||
getBitsAttr = (part) => {
|
||||
return dialogAttrs.getAttr(part, this.opts.variant.current);
|
||||
};
|
||||
incrementNested() {
|
||||
this.nestedOpenCount++;
|
||||
this.parent?.incrementNested();
|
||||
}
|
||||
decrementNested() {
|
||||
if (this.nestedOpenCount === 0)
|
||||
return;
|
||||
this.nestedOpenCount--;
|
||||
this.parent?.decrementNested();
|
||||
}
|
||||
sharedProps = $derived.by(() => ({
|
||||
"data-state": getDataOpenClosed(this.opts.open.current),
|
||||
}));
|
||||
}
|
||||
export class DialogTriggerState {
|
||||
static create(opts) {
|
||||
return new DialogTriggerState(opts, DialogRootContext.get());
|
||||
}
|
||||
opts;
|
||||
root;
|
||||
attachment;
|
||||
constructor(opts, root) {
|
||||
this.opts = opts;
|
||||
this.root = root;
|
||||
this.attachment = attachRef(this.opts.ref, (v) => {
|
||||
this.root.triggerNode = v;
|
||||
this.root.triggerId = v?.id;
|
||||
});
|
||||
this.onclick = this.onclick.bind(this);
|
||||
this.onkeydown = this.onkeydown.bind(this);
|
||||
}
|
||||
onclick(e) {
|
||||
if (this.opts.disabled.current)
|
||||
return;
|
||||
if (e.button > 0)
|
||||
return;
|
||||
this.root.handleOpen();
|
||||
}
|
||||
onkeydown(e) {
|
||||
if (this.opts.disabled.current)
|
||||
return;
|
||||
if (e.key === kbd.SPACE || e.key === kbd.ENTER) {
|
||||
e.preventDefault();
|
||||
this.root.handleOpen();
|
||||
}
|
||||
}
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
"aria-haspopup": "dialog",
|
||||
"aria-expanded": boolToStr(this.root.opts.open.current),
|
||||
"aria-controls": this.root.contentId,
|
||||
[this.root.getBitsAttr("trigger")]: "",
|
||||
onkeydown: this.onkeydown,
|
||||
onclick: this.onclick,
|
||||
disabled: this.opts.disabled.current ? true : undefined,
|
||||
...this.root.sharedProps,
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
export class DialogCloseState {
|
||||
static create(opts) {
|
||||
return new DialogCloseState(opts, DialogRootContext.get());
|
||||
}
|
||||
opts;
|
||||
root;
|
||||
attachment;
|
||||
constructor(opts, root) {
|
||||
this.opts = opts;
|
||||
this.root = root;
|
||||
this.attachment = attachRef(this.opts.ref);
|
||||
this.onclick = this.onclick.bind(this);
|
||||
this.onkeydown = this.onkeydown.bind(this);
|
||||
}
|
||||
onclick(e) {
|
||||
if (this.opts.disabled.current)
|
||||
return;
|
||||
if (e.button > 0)
|
||||
return;
|
||||
this.root.handleClose();
|
||||
}
|
||||
onkeydown(e) {
|
||||
if (this.opts.disabled.current)
|
||||
return;
|
||||
if (e.key === kbd.SPACE || e.key === kbd.ENTER) {
|
||||
e.preventDefault();
|
||||
this.root.handleClose();
|
||||
}
|
||||
}
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
[this.root.getBitsAttr(this.opts.variant.current)]: "",
|
||||
onclick: this.onclick,
|
||||
onkeydown: this.onkeydown,
|
||||
disabled: this.opts.disabled.current ? true : undefined,
|
||||
tabindex: 0,
|
||||
...this.root.sharedProps,
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
export class DialogActionState {
|
||||
static create(opts) {
|
||||
return new DialogActionState(opts, DialogRootContext.get());
|
||||
}
|
||||
opts;
|
||||
root;
|
||||
attachment;
|
||||
constructor(opts, root) {
|
||||
this.opts = opts;
|
||||
this.root = root;
|
||||
this.attachment = attachRef(this.opts.ref);
|
||||
}
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
[this.root.getBitsAttr("action")]: "",
|
||||
...this.root.sharedProps,
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
export class DialogTitleState {
|
||||
static create(opts) {
|
||||
return new DialogTitleState(opts, DialogRootContext.get());
|
||||
}
|
||||
opts;
|
||||
root;
|
||||
attachment;
|
||||
constructor(opts, root) {
|
||||
this.opts = opts;
|
||||
this.root = root;
|
||||
this.root.titleId = this.opts.id.current;
|
||||
this.attachment = attachRef(this.opts.ref);
|
||||
watch.pre(() => this.opts.id.current, (id) => {
|
||||
this.root.titleId = id;
|
||||
});
|
||||
}
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
role: "heading",
|
||||
"aria-level": this.opts.level.current,
|
||||
[this.root.getBitsAttr("title")]: "",
|
||||
...this.root.sharedProps,
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
export class DialogDescriptionState {
|
||||
static create(opts) {
|
||||
return new DialogDescriptionState(opts, DialogRootContext.get());
|
||||
}
|
||||
opts;
|
||||
root;
|
||||
attachment;
|
||||
constructor(opts, root) {
|
||||
this.opts = opts;
|
||||
this.root = root;
|
||||
this.root.descriptionId = this.opts.id.current;
|
||||
this.attachment = attachRef(this.opts.ref, (v) => {
|
||||
this.root.descriptionNode = v;
|
||||
});
|
||||
watch.pre(() => this.opts.id.current, (id) => {
|
||||
this.root.descriptionId = id;
|
||||
});
|
||||
}
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
[this.root.getBitsAttr("description")]: "",
|
||||
...this.root.sharedProps,
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
export class DialogContentState {
|
||||
static create(opts) {
|
||||
return new DialogContentState(opts, DialogRootContext.get());
|
||||
}
|
||||
opts;
|
||||
root;
|
||||
attachment;
|
||||
constructor(opts, root) {
|
||||
this.opts = opts;
|
||||
this.root = root;
|
||||
this.attachment = attachRef(this.opts.ref, (v) => {
|
||||
this.root.contentNode = v;
|
||||
this.root.contentId = v?.id;
|
||||
});
|
||||
}
|
||||
snippetProps = $derived.by(() => ({ open: this.root.opts.open.current }));
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
role: this.root.opts.variant.current === "alert-dialog" ? "alertdialog" : "dialog",
|
||||
"aria-modal": "true",
|
||||
"aria-describedby": this.root.descriptionId,
|
||||
"aria-labelledby": this.root.titleId,
|
||||
[this.root.getBitsAttr("content")]: "",
|
||||
style: {
|
||||
pointerEvents: "auto",
|
||||
outline: this.root.opts.variant.current === "alert-dialog" ? "none" : undefined,
|
||||
"--bits-dialog-depth": this.root.depth,
|
||||
"--bits-dialog-nested-count": this.root.nestedOpenCount,
|
||||
// CSS containment isolates style/layout calculations from the rest of the page,
|
||||
// improving performance when there's a large DOM behind the dialog.
|
||||
// Paint is omitted so tooltips/selects can render outside dialog bounds.
|
||||
contain: "layout style",
|
||||
},
|
||||
tabindex: this.root.opts.variant.current === "alert-dialog" ? -1 : undefined,
|
||||
"data-nested-open": boolToEmptyStrOrUndef(this.root.nestedOpenCount > 0),
|
||||
"data-nested": boolToEmptyStrOrUndef(this.root.parent !== null),
|
||||
...getDataTransitionAttrs(this.root.contentPresence.transitionStatus),
|
||||
...this.root.sharedProps,
|
||||
...this.attachment,
|
||||
}));
|
||||
get shouldRender() {
|
||||
return this.root.contentPresence.shouldRender;
|
||||
}
|
||||
}
|
||||
export class DialogOverlayState {
|
||||
static create(opts) {
|
||||
return new DialogOverlayState(opts, DialogRootContext.get());
|
||||
}
|
||||
opts;
|
||||
root;
|
||||
attachment;
|
||||
constructor(opts, root) {
|
||||
this.opts = opts;
|
||||
this.root = root;
|
||||
this.attachment = attachRef(this.opts.ref, (v) => (this.root.overlayNode = v));
|
||||
}
|
||||
snippetProps = $derived.by(() => ({ open: this.root.opts.open.current }));
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
[this.root.getBitsAttr("overlay")]: "",
|
||||
style: {
|
||||
pointerEvents: "auto",
|
||||
"--bits-dialog-depth": this.root.depth,
|
||||
"--bits-dialog-nested-count": this.root.nestedOpenCount,
|
||||
},
|
||||
"data-nested-open": boolToEmptyStrOrUndef(this.root.nestedOpenCount > 0),
|
||||
"data-nested": boolToEmptyStrOrUndef(this.root.parent !== null),
|
||||
...getDataTransitionAttrs(this.root.overlayPresence.transitionStatus),
|
||||
...this.root.sharedProps,
|
||||
...this.attachment,
|
||||
}));
|
||||
get shouldRender() {
|
||||
return this.root.overlayPresence.shouldRender;
|
||||
}
|
||||
}
|
||||
export class AlertDialogCancelState {
|
||||
static create(opts) {
|
||||
return new AlertDialogCancelState(opts, DialogRootContext.get());
|
||||
}
|
||||
opts;
|
||||
root;
|
||||
attachment;
|
||||
constructor(opts, root) {
|
||||
this.opts = opts;
|
||||
this.root = root;
|
||||
this.attachment = attachRef(this.opts.ref, (v) => (this.root.cancelNode = v));
|
||||
this.onclick = this.onclick.bind(this);
|
||||
this.onkeydown = this.onkeydown.bind(this);
|
||||
}
|
||||
onclick(e) {
|
||||
if (this.opts.disabled.current)
|
||||
return;
|
||||
if (e.button > 0)
|
||||
return;
|
||||
this.root.handleClose();
|
||||
}
|
||||
onkeydown(e) {
|
||||
if (this.opts.disabled.current)
|
||||
return;
|
||||
if (e.key === kbd.SPACE || e.key === kbd.ENTER) {
|
||||
e.preventDefault();
|
||||
this.root.handleClose();
|
||||
}
|
||||
}
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
[this.root.getBitsAttr("cancel")]: "",
|
||||
onclick: this.onclick,
|
||||
onkeydown: this.onkeydown,
|
||||
tabindex: 0,
|
||||
...this.root.sharedProps,
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
Reference in New Issue
Block a user