WIP: Vendoo 1.44.0 – UX Foundation & Guided Workspaces #29

Draft
Masterluke77 wants to merge 284 commits from release/1.44.0-ux-foundation-production-update-v1 into main
Showing only changes of commit 6e8467bcd0 - Show all commits
+41 -26
View File
@@ -12,6 +12,18 @@
return node;
};
const setText = (node, value) => {
if (!node) return;
const normalized = String(value ?? '');
if (node.textContent !== normalized) node.textContent = normalized;
};
const setData = (node, name, value) => {
if (!node) return;
const normalized = String(value ?? '');
if (node.dataset[name] !== normalized) node.dataset[name] = normalized;
};
const readStoredView = () => {
try {
const stored = localStorage.getItem(VIEW_KEY) || 'create';
@@ -36,11 +48,6 @@
});
};
const parseNumber = value => {
const match = String(value || '').replace(/\./g, '').match(/\d+/);
return match ? Number(match[0]) : 0;
};
function createViewButton(view, label, copy) {
const button = createNode('button', 'ux-flux-view-tab');
button.type = 'button';
@@ -75,7 +82,7 @@
function setView(root, view, { persist = true, focus = false } = {}) {
const normalized = VALID_VIEWS.includes(view) ? view : 'create';
root.dataset.uxFluxView = normalized;
setData(root, 'uxFluxView', normalized);
if (persist) storeView(normalized);
root.querySelectorAll('[data-ux-flux-view]').forEach(button => {
@@ -101,8 +108,8 @@
const target = normalized === 'create'
? root.querySelector('#flux-studio-prompt')
: normalized === 'jobs'
? root.querySelector('#flux-job-center-body, #flux-job-center-toggle')
: root.querySelector('#flux-studio-history, #flux-studio-favorites-only');
? root.querySelector('#flux-job-center-toggle, #flux-job-center-body')
: root.querySelector('#flux-studio-favorites-only, #flux-studio-history');
focusNode(target);
}
}
@@ -297,15 +304,15 @@
const jobState = readJobState(root);
const jobBadge = root.querySelector('[data-ux-flux-view-badge="jobs"]');
if (jobBadge) {
jobBadge.textContent = jobState.issues ? 'Problem' : jobState.active ? 'Aktiv' : jobState.hasJobs ? 'Verlauf' : '';
jobBadge.dataset.tone = jobState.issues ? 'danger' : jobState.active ? 'working' : 'neutral';
setText(jobBadge, jobState.issues ? 'Problem' : jobState.active ? 'Aktiv' : jobState.hasJobs ? 'Verlauf' : '');
setData(jobBadge, 'tone', jobState.issues ? 'danger' : jobState.active ? 'working' : 'neutral');
}
const libraryBadge = root.querySelector('[data-ux-flux-view-badge="library"]');
if (libraryBadge) {
const count = readLibraryCount(root);
libraryBadge.textContent = count ? String(count) : '';
libraryBadge.dataset.tone = 'neutral';
setText(libraryBadge, count ? String(count) : '');
setData(libraryBadge, 'tone', 'neutral');
}
}
@@ -316,7 +323,7 @@
const image = root.querySelector('#flux-studio-preview-image');
const hasResult = Boolean(image?.getAttribute('src')) && !image.classList.contains('hidden');
const progress = root.querySelector('#flux-studio-progress');
const isBusy = progress && !progress.classList.contains('hidden');
const isBusy = Boolean(progress && !progress.classList.contains('hidden'));
const jobState = readJobState(root);
const completed = {
@@ -334,31 +341,30 @@
? 'result'
: 'profile';
root.dataset.uxFluxCurrentStep = current;
setData(root, 'uxFluxCurrentStep', current);
root.querySelectorAll('[data-ux-flux-step]').forEach(step => {
const id = step.dataset.uxFluxStep;
const active = id === current;
step.classList.toggle('is-current', active);
step.classList.toggle('is-complete', Boolean(completed[id]));
step.setAttribute('aria-pressed', String(active));
const state = step.querySelector('.ux-flux-step-state');
if (state) state.textContent = completed[id] ? 'Erledigt' : active ? 'Jetzt' : 'Offen';
setText(step.querySelector('.ux-flux-step-state'), completed[id] ? 'Erledigt' : active ? 'Jetzt' : 'Offen');
});
const next = root.querySelector('[data-ux-flux-next]');
if (next) {
if (!completed.prompt) {
next.dataset.uxFluxNext = 'prompt';
next.textContent = 'Prompt eingeben';
setData(next, 'uxFluxNext', 'prompt');
setText(next, 'Prompt eingeben');
} else if (jobState.issues || jobState.active || isBusy) {
next.dataset.uxFluxNext = 'jobs';
next.textContent = jobState.issues ? 'Probleme prüfen' : 'Auftrag überwachen';
setData(next, 'uxFluxNext', 'jobs');
setText(next, jobState.issues ? 'Probleme prüfen' : 'Auftrag überwachen');
} else if (hasResult) {
next.dataset.uxFluxNext = 'result';
next.textContent = 'Ergebnis prüfen';
setData(next, 'uxFluxNext', 'result');
setText(next, 'Ergebnis prüfen');
} else {
next.dataset.uxFluxNext = 'generate';
next.textContent = 'Profil prüfen & Auftrag starten';
setData(next, 'uxFluxNext', 'generate');
setText(next, 'Profil prüfen & Auftrag starten');
}
}
@@ -424,13 +430,22 @@
};
const observer = new MutationObserver(schedule);
observer.observe(root, {
const targets = [
root.querySelector('#flux-job-summary'),
root.querySelector('#flux-job-list'),
root.querySelector('#flux-history-page-info'),
root.querySelector('#flux-studio-history'),
root.querySelector('#flux-studio-preview-image'),
root.querySelector('#flux-studio-progress'),
root.querySelector('#flux-studio-status'),
].filter(Boolean);
targets.forEach(target => observer.observe(target, {
subtree: true,
childList: true,
characterData: true,
attributes: true,
attributeFilter: ['class', 'src', 'data-state', 'data-tone', 'disabled'],
});
}));
root.querySelectorAll('input,textarea,select').forEach(field => {
field.addEventListener('input', schedule);
field.addEventListener('change', schedule);