export function createTemplatesMenu({ panel, fetchProjects, openProject, onShow, onHide }) {
let state = { templates: [], projects: [], loading: false, error: null };
const setState = (next) => {
state = { ...state, ...next };
render();
};
const renderEmpty = (parent, text) => {
const empty = document.createElement("div");
empty.className = "templates-empty";
empty.textContent = text;
parent.appendChild(empty);
};
const renderSection = (title, items, emptyText) => {
const section = document.createElement("div");
section.className = "templates-section";
const subtitle = document.createElement("div");
subtitle.className = "templates-subtitle";
subtitle.textContent = title;
section.appendChild(subtitle);
if (!items || !items.length) {
renderEmpty(section, emptyText);
} else {
items.forEach((item) => {
const card = document.createElement("button");
card.className = "example-card template-card";
card.type = "button";
card.addEventListener("click", () => openProject?.(item.id, item.type));
const titleEl = document.createElement("div");
titleEl.className = "card-title";
titleEl.textContent = item.name || item.id;
card.appendChild(titleEl);
const meta = document.createElement("div");
meta.className = "card-meta";
const typePill = document.createElement("span");
typePill.className = "card-pill";
typePill.dataset.kind = item.type || "project";
typePill.textContent = item.type === "template" ? "Шаблон" : "Проект";
meta.appendChild(typePill);
if (item.updatedAt) {
const updated = document.createElement("span");
updated.textContent = new Date(item.updatedAt).toLocaleDateString();
meta.appendChild(updated);
}
card.appendChild(meta);
section.appendChild(card);
});
}
return section;
};
const render = () => {
if (!panel) return;
panel.innerHTML = "";
const header = document.createElement("div");
header.className = "templates-header";
header.innerHTML = `Проекты и шаблоны`;
const actions = document.createElement("div");
actions.className = "templates-actions";
const refresh = document.createElement("button");
refresh.className = "templates-close";
refresh.type = "button";
refresh.title = "Обновить список";
refresh.setAttribute("aria-label", "Обновить список");
refresh.innerHTML = `
`;
refresh.addEventListener("click", () => load());
const closeBtn = document.createElement("button");
closeBtn.className = "templates-close";
closeBtn.type = "button";
closeBtn.setAttribute("aria-label", "Закрыть проекты и шаблоны");
closeBtn.innerHTML = `
`;
closeBtn.addEventListener("click", hide);
actions.appendChild(refresh);
actions.appendChild(closeBtn);
header.appendChild(actions);
panel.appendChild(header);
const body = document.createElement("div");
body.className = "templates-panel-body";
panel.appendChild(body);
if (state.loading) {
const loadingEl = document.createElement("div");
loadingEl.className = "templates-empty";
loadingEl.textContent = "Загрузка списка проектов...";
body.appendChild(loadingEl);
return;
}
if (state.error) {
const errorEl = document.createElement("div");
errorEl.className = "templates-empty";
errorEl.style.color = "var(--error)";
errorEl.textContent = state.error;
body.appendChild(errorEl);
}
body.appendChild(renderSection("Шаблоны", state.templates, "Нет шаблонов"));
body.appendChild(renderSection("Мои проекты", state.projects, "Нет сохранённых проектов"));
};
const load = async () => {
if (!fetchProjects) return;
setState({ loading: true, error: null });
try {
const data = await fetchProjects();
setState({
loading: false,
templates: data?.templates || [],
projects: data?.projects || [],
error: null
});
} catch (err) {
setState({ loading: false, error: err?.message || "Не удалось загрузить проекты" });
}
};
const hide = () => {
if (panel) {
panel.classList.add("hidden");
panel.style.display = "";
}
onHide?.();
};
const show = () => {
render();
if (panel) {
panel.classList.remove("hidden");
panel.style.display = "flex";
}
load();
onShow?.();
};
const toggle = () => {
if (!panel) return;
if (panel.classList.contains("hidden")) {
show();
} else {
hide();
}
};
const setData = (data = {}) => {
setState({
templates: data.templates || [],
projects: data.projects || [],
loading: false,
error: data.error || null
});
};
return { render, show, hide, toggle, reload: load, setData };
}