Files
DemonGatanjieu-Anomalous_Mo…/web/modules/ui_material_notes.js
T
DemonGatanjieuandClaude Opus 5.5 0f7d6317ad Put Prompt Notes on the Material Library's Prompts page
ui_material_notes.js lists the notes above the saved prompts, each with
its model, LoRAs and prompt, Put into this workflow and New group of
nodes; a card opens the note's editor, which now has a way back to the
library, and New note starts one. The separate Prompt Notes button goes,
and so does the editor's "save to library" card with the route only it
used (save_prompt_note_material): a note is in the library already.
Notes keep their own files; prompt materials saved from notes before
still list and open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 17:39:38 +08:00

94 lines
3.8 KiB
JavaScript

/**
* Prompt Notes on the Material Library's Prompts page, above the saved prompts: each note
* (model, LoRAs, prompt) with Put into this workflow and New group of nodes
* (notebook_canvas.js); the card opens the note's editor (ui_notebooks.js) and New note
* starts one there. The notes stay where they always were (GET /anomalous/notebooks).
*/
import { translate as t } from './locales.js';
import { anomalousPrompt } from './ui_dialog.js';
function el(tag, className, text) {
const node = document.createElement(tag);
if (className) node.className = className;
if (text !== undefined) node.textContent = text;
return node;
}
const modelName = (model) => String(model?.filename || '').replace(/\.[^.]+$/, '');
function openNote(owner, note) {
owner.currentNotebook = note;
owner.showNotebooks();
}
function noteCard(owner, note) {
const data = note.data || {};
const card = el('article', 'anomalous-note-card');
card.tabIndex = 0;
card.onclick = () => openNote(owner, note);
card.onkeydown = (event) => {
if (event.target === card && ['Enter', ' '].includes(event.key)) {
event.preventDefault();
openNote(owner, note);
}
};
const head = el('div', 'anomalous-note-card-head');
head.append(el('strong', '', note.name));
const loras = (data.loras || []).length;
head.append(el('span', 'anomalous-note-card-meta',
[modelName(data.mainModel) || t('noteNoModel'), loras ? t('noteLoraCount', { count: loras }) : ''].filter(Boolean).join(' · ')));
card.append(head, el('p', 'anomalous-note-card-prompt', String(data.promptEn || '').trim() || t('noteNoPrompt')));
const actions = el('div', 'anomalous-note-card-actions');
for (const [className, key, run] of [
['anomalous-btn-primary', 'noteApplyButton', () => owner.applyNotebookToWorkflow()],
['anomalous-btn-ghost', 'sendToCanvas', () => owner.sendNotebookToCanvas()],
]) {
const button = el('button', className, t(key));
button.type = 'button';
button.onclick = (event) => {
event.stopPropagation();
owner.currentNotebook = note;
run();
};
actions.append(button);
}
card.append(actions);
return card;
}
async function newNote(owner) {
const name = String(await anomalousPrompt(t('newNotebookName'), '', t('createNotebook')) || '').trim();
if (!name) return;
owner.currentNotebook = {
filename: `${name}.json`,
name,
data: { baseModel: '', mainModel: null, loras: [], promptEn: '', promptZh: '' },
};
if (await owner.saveCurrentNotebook()) owner.showNotebooks();
}
function heading(titleKey, extra = null) {
const row = el('div', 'anomalous-note-shelf-heading');
row.append(el('span', '', t(titleKey)));
if (extra) row.append(extra);
return row;
}
/** The notes matching the library's search: a heading with New note, then their cards. */
export async function noteShelf(owner, signal) {
const response = await fetch('/anomalous/notebooks', { cache: 'no-store', signal });
const { notebooks = [] } = await response.json();
const query = String(owner.materialQuery || '').trim().toLowerCase();
const shown = notebooks.filter(note => !query || `${note.name} ${note.data?.promptEn || ''}`.toLowerCase().includes(query));
const create = el('button', 'anomalous-btn-ghost', t('createNotebook'));
create.type = 'button';
create.onclick = () => void newNote(owner);
const fragment = document.createDocumentFragment();
fragment.append(heading('noteShelfTitle', create), ...shown.map(note => noteCard(owner, note)));
if (!shown.length) fragment.append(el('p', 'anomalous-note-shelf-empty', t(query ? 'materialNoMatches' : 'noteShelfEmpty')));
return fragment;
}
export const savedPromptsHeading = () => heading('noteSavedPromptsTitle');