155 lines
4.7 KiB
JavaScript
155 lines
4.7 KiB
JavaScript
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 = `<span class="templates-title">Проекты и шаблоны</span>`;
|
||
const actions = document.createElement("div");
|
||
actions.style.display = "flex";
|
||
actions.style.gap = "6px";
|
||
const refresh = document.createElement("button");
|
||
refresh.className = "templates-close";
|
||
refresh.title = "Обновить список";
|
||
refresh.textContent = "↻";
|
||
refresh.addEventListener("click", () => load());
|
||
const closeBtn = document.createElement("button");
|
||
closeBtn.className = "templates-close";
|
||
closeBtn.textContent = "×";
|
||
closeBtn.addEventListener("click", hide);
|
||
actions.appendChild(refresh);
|
||
actions.appendChild(closeBtn);
|
||
header.appendChild(actions);
|
||
panel.appendChild(header);
|
||
|
||
if (state.loading) {
|
||
const loadingEl = document.createElement("div");
|
||
loadingEl.className = "templates-empty";
|
||
loadingEl.textContent = "Загрузка списка проектов...";
|
||
panel.appendChild(loadingEl);
|
||
return;
|
||
}
|
||
|
||
if (state.error) {
|
||
const errorEl = document.createElement("div");
|
||
errorEl.className = "templates-empty";
|
||
errorEl.style.color = "var(--error)";
|
||
errorEl.textContent = state.error;
|
||
panel.appendChild(errorEl);
|
||
}
|
||
|
||
panel.appendChild(renderSection("Шаблоны", state.templates, "Нет шаблонов"));
|
||
panel.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 = "grid";
|
||
}
|
||
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 };
|
||
}
|