Merge branch 'dev'

This commit is contained in:
Jeff Emmett 2026-03-21 16:01:13 -07:00
commit ecbbd2d5ff
1 changed files with 67 additions and 10 deletions

View File

@ -27,6 +27,10 @@ export class RStackSpaceSwitcher extends HTMLElement {
#shadow: ShadowRoot;
#spaces: SpaceInfo[] = [];
#loaded = false;
// Preserved create-form state across open/close
#createFormOpen = false;
#createName = '';
#createVisibility = 'public';
constructor() {
super();
@ -107,11 +111,27 @@ export class RStackSpaceSwitcher extends HTMLElement {
if (!this.#loaded) {
await this.#loadSpaces();
this.#renderMenu(menu, current);
} else {
// Restore create form state if it was open
this.#restoreCreateFormState(menu);
}
} else {
// Preserve create form state before closing
this.#saveCreateFormState(menu);
}
});
document.addEventListener("click", () => menu.classList.remove("open"));
// Close menu only when clicking outside both trigger and menu
document.addEventListener("click", (e) => {
if (!menu.classList.contains("open")) return;
const path = e.composedPath();
if (path.includes(menu) || path.includes(trigger)) return;
this.#saveCreateFormState(menu);
menu.classList.remove("open");
});
// Prevent clicks inside menu from closing it
menu.addEventListener("click", (e) => e.stopPropagation());
}
#visibilityInfo(s: SpaceInfo): { cls: string; label: string } {
@ -397,10 +417,11 @@ export class RStackSpaceSwitcher extends HTMLElement {
name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
toggle.addEventListener("click", (e) => {
e.stopPropagation();
e.preventDefault();
const showing = popout.classList.toggle("hidden");
if (!showing) nameInput.focus();
const wasHidden = popout.classList.contains("hidden");
popout.classList.toggle("hidden");
this.#createFormOpen = wasHidden;
if (wasHidden) nameInput.focus();
});
nameInput.addEventListener("input", () => {
@ -408,18 +429,17 @@ export class RStackSpaceSwitcher extends HTMLElement {
slugPreview.textContent = slug ? `slug: ${slug}` : "";
});
nameInput.addEventListener("click", (e) => e.stopPropagation());
cancelBtn.addEventListener("click", (e) => {
e.stopPropagation();
cancelBtn.addEventListener("click", () => {
popout.classList.add("hidden");
nameInput.value = "";
slugPreview.textContent = "";
status.textContent = "";
this.#createFormOpen = false;
this.#createName = '';
this.#createVisibility = 'public';
});
submitBtn.addEventListener("click", async (e) => {
e.stopPropagation();
submitBtn.addEventListener("click", async () => {
const name = nameInput.value.trim();
if (!name) { status.textContent = "Name required"; return; }
@ -479,6 +499,43 @@ export class RStackSpaceSwitcher extends HTMLElement {
}
}
#saveCreateFormState(menu: HTMLElement) {
const popout = menu.querySelector("#create-popout") as HTMLElement;
if (!popout) return;
this.#createFormOpen = !popout.classList.contains("hidden");
const nameInput = menu.querySelector("#create-name") as HTMLInputElement;
if (nameInput) this.#createName = nameInput.value;
const checkedRadio = menu.querySelector('input[name="create-vis"]:checked') as HTMLInputElement;
if (checkedRadio) this.#createVisibility = checkedRadio.value;
}
#restoreCreateFormState(menu: HTMLElement) {
const popout = menu.querySelector("#create-popout") as HTMLElement;
const nameInput = menu.querySelector("#create-name") as HTMLInputElement;
const slugPreview = menu.querySelector("#create-slug") as HTMLElement;
if (!popout || !nameInput) return;
if (this.#createFormOpen) {
popout.classList.remove("hidden");
}
if (this.#createName) {
nameInput.value = this.#createName;
const toSlug = (name: string) =>
name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
if (slugPreview) {
const slug = toSlug(this.#createName);
slugPreview.textContent = slug ? `slug: ${slug}` : "";
}
}
if (this.#createVisibility !== 'public') {
const radio = menu.querySelector(`input[name="create-vis"][value="${this.#createVisibility}"]`) as HTMLInputElement;
if (radio) radio.checked = true;
}
if (this.#createFormOpen) {
requestAnimationFrame(() => nameInput.focus());
}
}
#showRequestAccessModal(slug: string, spaceName: string) {
if (document.querySelector(".rstack-auth-overlay")) return;