/** * Carte Lovelace pour l'intégration CookCLI — liste navigable des recettes. * * Le détail d'une recette n'est plus géré par cette carte : un clic sur une * ligne navigue vers une vue générée par cookcli-recipe-strategy.js (voir ce * fichier), qui affiche étapes/ingrédients/minuteur via des cartes natives * et des cartes tierces (tabdeck-card, simple-timer-card). * * Consomme cookcli/recipes (path, name, time, servings, tags, image_url). * * Installation : * 1. Copie ce fichier dans config/www/cookcli-card.js * 2. Paramètres -> Tableaux de bord -> menu ⋮ -> Ressources -> Ajouter : * URL "/local/cookcli-card.js", type "Module JavaScript" * 3. Ajoute une carte manuelle sur un tableau de bord : * type: custom:cookcli-card * title: Mes recettes * detail_view_path: recette # doit correspondre au "path" de la vue de détail */ class CookCliCard extends HTMLElement { static getStubConfig() { return { title: "Recettes", detail_view_path: "recette" }; } setConfig(config) { this._config = config || {}; this._recipes = null; this._loading = false; this._error = null; if (!this.shadowRoot) { this.attachShadow({ mode: "open" }); this.shadowRoot.addEventListener("click", (event) => this._onClick(event)); } this._render(); } set hass(hass) { this._hass = hass; if (this._recipes === null && !this._loading) { this._fetchRecipes(); } } getCardSize() { return 6; } async _fetchRecipes() { this._loading = true; this._error = null; this._render(); try { const msg = { type: "cookcli/recipes" }; if (this._config.entry_id) msg.entry_id = this._config.entry_id; const result = await this._hass.connection.sendMessagePromise(msg); this._recipes = result.recipes || []; } catch (err) { this._error = (err && err.message) || "Erreur inconnue"; } finally { this._loading = false; this._render(); } } _navigateToRecipe(path) { const detailPath = this._config.detail_view_path || "recette"; // Racine du dashboard courant, ex: "/lovelace-cookcli" depuis // "/lovelace-cookcli/recettes" — on y accroche la vue de détail. const dashboardRoot = window.location.pathname.split("/").slice(0, 2).join("/"); const url = `${dashboardRoot}/${detailPath}?path=${encodeURIComponent(path)}`; // Navigation interne HA, sans recharger la page (comme un tap_action navigate). window.history.pushState(null, "", url); window.dispatchEvent(new CustomEvent("location-changed", { detail: { replace: false } })); } _onClick(event) { const itemEl = event.target.closest("[data-path]"); if (itemEl) { this._navigateToRecipe(itemEl.dataset.path); } } _escape(str) { const div = document.createElement("div"); div.textContent = str ?? ""; return div.innerHTML; } _renderList() { if (this._loading) { return `