From ef84bb2c6381fe70b43c72a06a6f73d6777cc6d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=AAsufian=20nasser=E2=80=AC=E2=80=8F?= <166199800+sufyanaser@users.noreply.github.com> Date: Mon, 20 Jul 2026 18:29:34 +0300 Subject: [PATCH 1/4] Add projects library and separate project editor view --- index.html | 38 ++++++++++++++------------------------ 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/index.html b/index.html index fc19893..89b73e7 100644 --- a/index.html +++ b/index.html @@ -2,37 +2,27 @@ NASMIX - +
-

NASMIX

مشاريع التوزيع الموسيقي

جاري تحميل البيانات…
+

NASMIX

مشاريع التوزيع الموسيقي

جاري تحميل البيانات…
+
+
مكتبة المشاريع

الأغاني التي تعمل عليها

كل بطاقة تفتح مشروع الأغنية مباشرة مع جميع التفاصيل والأوامر والقرارات المحفوظة.

+
0 مشروع
+
+ +
+
- +
القرار المقترح

—

برومبت Suno الكامل

احفظه داخل مشروع الأغنية من مرحلة التوليد.

الوصف الموسيقي

عقد العزل

🔒

Exclude

CategoryCustom
Weirdness10%
Style Influence100%
Audio Influence0%

+ + \ No newline at end of file From 350e1993bae720d93d38f52f42ca66ac45865df5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=AAsufian=20nasser=E2=80=AC=E2=80=8F?= <166199800+sufyanaser@users.noreply.github.com> Date: Mon, 20 Jul 2026 18:30:11 +0300 Subject: [PATCH 2/4] Add interactive saved projects library --- ui/projects-library.js | 122 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 ui/projects-library.js diff --git a/ui/projects-library.js b/ui/projects-library.js new file mode 100644 index 0000000..8e73377 --- /dev/null +++ b/ui/projects-library.js @@ -0,0 +1,122 @@ +(() => { + "use strict"; + + const $ = (id) => document.getElementById(id); + let projects = []; + + const formatDate = (value) => { + if (!value) return "—"; + try { return new Intl.DateTimeFormat("ar-IQ", { dateStyle:"medium", timeStyle:"short" }).format(new Date(value)); } + catch { return "—"; } + }; + + const completedCount = (project) => new Set(project.completedStages || []).size; + const safe = (value) => String(value || "").replace(/[&<>'"]/g, (c) => ({"&":"&","<":"<",">":">","'":"'",'"':"""}[c])); + + function showLibrary() { + history.replaceState(null, "", location.pathname + location.search); + $("projectsLibrary").hidden = false; + $("projectEditorView").hidden = true; + $("backToProjectsButton").hidden = true; + $("appPageTitle").textContent = "مشاريع التوزيع الموسيقي"; + render().catch(console.error); + } + + function openProject(id) { + window.NASMixProjectStore.setActive(id); + location.hash = `project=${encodeURIComponent(id)}`; + location.reload(); + } + + async function createProject() { + const project = await window.NASMixProjectStore.save(window.NASMixProjectStore.createProject("مشروع أغنية جديد")); + openProject(project.id); + } + + async function importProject(file) { + const parsed = JSON.parse(await file.text()); + if (!parsed?.brief) throw new Error("Invalid NASMIX project"); + parsed.id = window.NASMixProjectStore.createId("project"); + parsed.name = parsed.name || parsed.brief.songName || "مشروع مستورد"; + const project = await window.NASMixProjectStore.save(parsed); + openProject(project.id); + } + + function card(project) { + const brief = project.brief || {}; + const count = completedCount(project); + const title = project.name || brief.songName || "مشروع بدون اسم"; + const meta = [brief.tempo ? `${brief.tempo} BPM` : null, brief.key, brief.maqam, brief.timeSignature].filter(Boolean).join(" · ") || "لم تُدخل بيانات الأغنية بعد"; + return `
+
المرحلة ${String(project.currentStage || 1).padStart(2,"0")}${formatDate(project.updatedAt)}
+

${safe(title)}

${safe(meta)}

+
${safe(brief.mainInstrument || "بدون آلة قائدة")}${safe(brief.primaryGroove || "بدون إيقاع")}
+ +
`; + } + + function applyFilter() { + const query = String($("projectSearchInput").value || "").trim().toLowerCase(); + const filtered = query ? projects.filter((project) => { + const brief = project.brief || {}; + return [project.name, brief.songName, brief.maqam, brief.mainInstrument, brief.primaryGroove, brief.mood].some((value) => String(value || "").toLowerCase().includes(query)); + }) : projects; + $("projectsGrid").innerHTML = filtered.map(card).join(""); + $("emptyProjectsState").hidden = projects.length !== 0; + $("projectsGrid").hidden = projects.length === 0; + $("projectsCount").textContent = `${projects.length} مشروع`; + } + + async function render() { + projects = await window.NASMixProjectStore.list(); + applyFilter(); + } + + function bind() { + $("libraryNewProjectButton").addEventListener("click", createProject); + $("emptyNewProjectButton").addEventListener("click", createProject); + $("backToProjectsButton").addEventListener("click", showLibrary); + $("projectSearchInput").addEventListener("input", applyFilter); + $("projectsGrid").addEventListener("click", (event) => { + const target = event.target.closest("[data-open-project], .project-card"); + const id = target?.dataset.openProject || target?.dataset.projectId; + if (id) openProject(id); + }); + $("projectsGrid").addEventListener("keydown", (event) => { + if ((event.key === "Enter" || event.key === " ") && event.target.classList.contains("project-card")) { + event.preventDefault(); openProject(event.target.dataset.projectId); + } + }); + $("libraryImportInput").addEventListener("change", async (event) => { + const file = event.target.files?.[0]; + if (!file) return; + try { await importProject(file); } + catch { alert("ملف المشروع غير صالح"); } + event.target.value = ""; + }); + } + + async function init() { + if (!window.NASMixProjectStore || !$("projectsLibrary")) return; + bind(); + const match = location.hash.match(/^#project=(.+)$/); + if (match) { + const id = decodeURIComponent(match[1]); + const project = await window.NASMixProjectStore.get(id); + if (project) { + window.NASMixProjectStore.setActive(id); + $("projectsLibrary").hidden = true; + $("projectEditorView").hidden = false; + $("backToProjectsButton").hidden = false; + $("appPageTitle").textContent = project.name || project.brief?.songName || "مشروع الأغنية"; + return; + } + } + showLibrary(); + } + + window.addEventListener("DOMContentLoaded", () => init().catch(console.error)); + window.addEventListener("nasmix:project-loaded", (event) => { + if (!$("projectEditorView").hidden) $("appPageTitle").textContent = event.detail?.name || event.detail?.brief?.songName || "مشروع الأغنية"; + }); +})(); \ No newline at end of file From 7aacfcd024cc55efd509e41fa3b3a8047aa0e557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=AAsufian=20nasser=E2=80=AC=E2=80=8F?= <166199800+sufyanaser@users.noreply.github.com> Date: Mon, 20 Jul 2026 18:30:31 +0300 Subject: [PATCH 3/4] Style projects library dashboard --- ui/projects-library.css | 1 + 1 file changed, 1 insertion(+) create mode 100644 ui/projects-library.css diff --git a/ui/projects-library.css b/ui/projects-library.css new file mode 100644 index 0000000..7ffe48e --- /dev/null +++ b/ui/projects-library.css @@ -0,0 +1 @@ +.projects-library{padding:22px}.library-heading{display:flex;align-items:flex-end;justify-content:space-between;gap:18px;padding:20px;border:1px solid var(--line);border-radius:18px;background:var(--panel)}.library-heading h2{font-size:26px;margin-top:5px}.library-heading p{margin:8px 0 0;color:var(--muted);max-width:720px}.library-kicker{color:var(--accent);font-size:12px;font-weight:800}.library-actions{display:flex;gap:9px;flex-wrap:wrap}.library-tools{display:flex;align-items:flex-end;justify-content:space-between;gap:12px;margin:16px 0}.library-search{width:min(420px,100%)}.projects-count{color:var(--muted);font-size:13px}.projects-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px}.project-card{display:grid;gap:16px;min-height:260px;padding:16px;border:1px solid var(--line);border-radius:18px;background:var(--panel);cursor:pointer;transition:transform .16s ease,border-color .16s ease,box-shadow .16s ease}.project-card:hover,.project-card:focus{transform:translateY(-2px);border-color:var(--accent);box-shadow:0 14px 32px var(--shadow);outline:none}.project-card-top,.project-card-footer{display:flex;align-items:center;justify-content:space-between;gap:10px}.project-stage{padding:6px 9px;border-radius:999px;background:var(--accent-soft);color:var(--accent);font-size:11px}.project-updated{font-size:11px;color:var(--muted)}.project-card-main h3{font-size:20px}.project-card-main p{margin:7px 0 0;color:var(--muted);direction:ltr;text-align:right}.project-tags{display:flex;gap:7px;flex-wrap:wrap}.project-tags span{padding:6px 8px;border:1px solid var(--line);border-radius:999px;color:var(--label);font-size:11px;background:var(--input)}.project-card-footer{margin-top:auto}.project-card-footer>div:first-child{display:grid}.project-card-footer strong{font-size:17px}.project-card-footer span{font-size:10px;color:var(--muted)}.project-progress-track{flex:1;height:6px;border-radius:999px;background:var(--input);overflow:hidden}.project-progress-track i{display:block;height:100%;background:linear-gradient(90deg,var(--accent),var(--accent-2));border-radius:inherit}.open-project-button{min-height:34px;padding:7px 10px;font-size:11px}.empty-projects{padding:60px 20px;text-align:center;border:1px dashed var(--line-strong);border-radius:18px;background:var(--panel)}.empty-projects strong{font-size:20px}.empty-projects p{color:var(--muted)}#backToProjectsButton{min-height:38px}@media(max-width:980px){.projects-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.library-heading{align-items:stretch;flex-direction:column}}@media(max-width:620px){.projects-library{padding:12px}.projects-grid{grid-template-columns:1fr}.library-tools{align-items:stretch;flex-direction:column}.library-actions{display:grid;grid-template-columns:1fr}.project-card{min-height:230px}} \ No newline at end of file From b4e248482577fb0b6d448b09ff58c3cbc0a8475c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=AAsufian=20nasser=E2=80=AC=E2=80=8F?= <166199800+sufyanaser@users.noreply.github.com> Date: Mon, 20 Jul 2026 18:30:51 +0300 Subject: [PATCH 4/4] Cache projects library assets --- sw.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sw.js b/sw.js index cb23d56..b8e8736 100644 --- a/sw.js +++ b/sw.js @@ -1,7 +1,7 @@ -const CACHE_NAME = "nasmix-shell-v7"; +const CACHE_NAME = "nasmix-shell-v8"; const APP_SHELL = [ - "./","./index.html","./ui/styles.css","./ui/prompt-safety.css","./ui/compact-brief.css","./ui/app.js", - "./ui/project-store.js","./ui/song-brief.js","./ui/project-workspace.js","./ui/project-bootstrap.js", + "./","./index.html","./ui/styles.css","./ui/prompt-safety.css","./ui/compact-brief.css","./ui/projects-library.css","./ui/app.js", + "./ui/project-store.js","./ui/song-brief.js","./ui/project-workspace.js","./ui/project-bootstrap.js","./ui/projects-library.js", "./data/catalog.json","./data/presets-acoustic.json","./data/presets-modern.json","./data/project-schema.json", "./data/knowledge/manifest.json","./data/knowledge/reliability.json","./data/knowledge/evidence-registry.json", "./data/knowledge/workflow-stages.json","./data/knowledge/musical-roles.json","./manifest.webmanifest","./assets/icon.svg"