Merge branch 'feature/model-import' into feature/remote-access
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+3
-1
@@ -632,7 +632,9 @@ covered by the `styles.css` manifest.
|
||||
`prompt_gloss.js` looks up and keeps the tags' meanings in the picked language. `ui_prompt_source_deck.js`
|
||||
owns the card list (three built-in cards and the saved prompts), search, new-card form,
|
||||
library sync and renaming / deleting a saved prompt; `prompt_material_source.js` reads
|
||||
saved prompts as cards and saves one; `ui_prompt_card_popover.js` owns the card preview (hover
|
||||
saved prompts as cards and saves one; `ui_prompt_reference.js` is the reference column a
|
||||
clicked card opens in, between the cards and the boxes (its tags taken one by one or all, ticks
|
||||
on those the box has; it widens the drawer while open, and takes the cards' place where three columns do not fit); `ui_prompt_card_popover.js` owns the card preview (hover
|
||||
corridor, pin, Copy / Add / Rename / Delete); `prompt_card_drag.js` lets a card or a box be
|
||||
dragged out of the drawer onto a canvas prompt box or empty canvas (through `material_drag.js`
|
||||
and `prompt_drop.js`), passing through inside the drawer so the boxes still take it.
|
||||
|
||||
+5
-1
@@ -124,9 +124,13 @@
|
||||
- **Quick to open with many models, or models on a network drive** (a NAS, a cloud server's model disk): the page reads the headers of models not scanned yet 16 at a time and remembers them until the file changes, so it opens again at once; while it counts, it says **Counting your models…** instead of staying blank. On a cloud server with 1041 unscanned models it had taken 79 seconds each time.
|
||||
|
||||
### ⚙️ Settings in tabs (设置分组)
|
||||
- The settings page is split into tabs: **Look, Models, Workflows, Prompts, Backup, Help**. "Change where downloads go" opens Models directly.
|
||||
- The settings page is split into tabs: **Look, Models, Workflows, Node packs, Prompts, Backup, Help**. "Change where downloads go" opens Models directly.
|
||||
- **Where downloads (and now imports) go is a choice**: by base model (the new default), in Downloads then by base model, all in a Downloads folder, straight in the type's folder, or your own folder typed by hand; an example path shows the result. Without a saved setting, downloads now go by base model instead of into a Downloads folder.
|
||||
|
||||
### 🔖 Take single tags from a saved prompt (从存过的提示词里挑词)
|
||||
- **In Prompt Studio a clicked card opens as a reference** between the cards and the prompt you are editing, as its tags (with their meanings when a language is picked). Click one tag and only that tag goes into the prompt; tags the prompt has already are ticked. **Add all** puts the whole card in, as a click on a card used to; the preview's Add and dragging a card work as before. The ✕ closes the reference; beside the canvas the drawer widens by the column while it is open.
|
||||
- **It does not squeeze a narrow window**: where three columns do not fit (a side-panel browser window, a narrow drawer), the reference takes the card list's place and **‹ Cards** brings the list back, so the reference and the prompt you edit each get half the width.
|
||||
|
||||
### Fixes
|
||||
- **Edit emotions: every clip in the list, and the line follows the clip (编辑情绪:下拉列出全部音频,换音频台词跟着换)**: a box that already held a file listed only the files whose names contain it (the browser filters by the box's text), so a character's other clips seemed missing. Pressing the box now lists all of them, with the current file shown greyed; leaving without a pick keeps it. Picking another clip no longer keeps the old clip's line beside it: the line the node already reads for that clip is filled in, otherwise the line the node finds for the clip (its .txt / .lab or the annotation list) is filled in, with Anomalous_TTS from interface 14 on (older versions leave the box blank and the node reads the line when it speaks); going back to the first clip brings its line back. A blank line box shows, greyed, the line the node uses for its clip.
|
||||
- **Search a character's clips by line (按台词找参考音频)**: Edit emotions has a search box above the clips: type part of a line or a file name and the matches list with their lines, to hear (▶), **Use as main voice** or **Add as emotion** (a new emotion row with that clip and its line, ready for its name). Searching lines needs Anomalous_TTS interface 14; with an older version it searches file names.
|
||||
|
||||
@@ -343,7 +343,10 @@ while the page is visible (scheduled after the previous request), on focus/visib
|
||||
and after a save; a newer request cancels the older one and a failed one keeps the
|
||||
current cards. List summaries are not prompt bodies: a prompt's text is read through
|
||||
`material_prompt_data.js` once per filename and timestamp, since a saved prompt's text
|
||||
never changes. A card's role decides its box: a positive card never goes into a
|
||||
never changes. A clicked card opens as a reference (`ui_prompt_reference.js`, read only,
|
||||
one at a time) between the cards and the boxes: a click on one of its tags adds that tag,
|
||||
"Add all" the whole card (as the preview's Add does); the ticks follow the box's text on the
|
||||
same 400 ms poll. A card's role decides its box: a positive card never goes into a
|
||||
negative box or the reverse; boxes of unknown or both roles take either. A saved
|
||||
card's preview renames it (`update_material`, tags kept) or deletes it
|
||||
(`delete_material`, to the Recycle Bin). A card, or a box's handle with the box's text
|
||||
|
||||
@@ -1798,6 +1798,15 @@ export const i18n = {
|
||||
promptStudioRemoveTag: "删掉",
|
||||
promptStudioTagHint: "点一下选中(可调权重),双击改字,拖动换位置",
|
||||
promptStudioAllThere: "这些词已经都有了",
|
||||
promptStudioRefTitle: "参考:{name}",
|
||||
promptStudioRefClose: "关掉参考",
|
||||
promptStudioRefBack: "‹ 卡片",
|
||||
promptStudioRefAddAll: "全部加入",
|
||||
promptStudioRefAddAllHint: "把这张卡片的词一次全加进去(已经有的不重复加)",
|
||||
promptStudioRefNote: "点一个词,只把它加进正在改的提示词;打勾的是已经有的。",
|
||||
promptStudioRefTake: "只把这个词加进去",
|
||||
promptStudioRefThere: "这个词已经有了",
|
||||
promptStudioRefHint: "点卡片现在会先把它打开成参考,可以一个词一个词地挑;想整张加,点参考上的“全部加入”。",
|
||||
promptStudioAddedSkipped: "加了 {count} 个,{skipped} 个已经有了",
|
||||
promptDeckSearch: "搜索词卡…",
|
||||
promptDeckNew: "新建词卡",
|
||||
@@ -4485,6 +4494,15 @@ export const i18n = {
|
||||
promptStudioRemoveTag: "Remove",
|
||||
promptStudioTagHint: "Click to select (and set its weight), double-click to edit, drag to move",
|
||||
promptStudioAllThere: "Those tags are there already",
|
||||
promptStudioRefTitle: "Reference: {name}",
|
||||
promptStudioRefClose: "Close the reference",
|
||||
promptStudioRefBack: "‹ Cards",
|
||||
promptStudioRefAddAll: "Add all",
|
||||
promptStudioRefAddAllHint: "Add every tag of this card at once (those there already are not added twice)",
|
||||
promptStudioRefNote: "Click a tag to add just that one to the prompt being edited; ticked ones are there already.",
|
||||
promptStudioRefTake: "Add just this tag",
|
||||
promptStudioRefThere: "This tag is there already",
|
||||
promptStudioRefHint: "A clicked card now opens as a reference, to pick its tags one by one; to add it whole, press “Add all” on the reference.",
|
||||
promptStudioAddedSkipped: "Added {count}; {skipped} were there already",
|
||||
promptDeckSearch: "Search cards…",
|
||||
promptDeckNew: "New card",
|
||||
|
||||
@@ -67,7 +67,8 @@ export function withWeight(tag, weight) {
|
||||
return rounded === 1 ? core : `(${core}:${rounded})`;
|
||||
}
|
||||
|
||||
const tagKey = tag => tagWeight(tag).core.trim().toLowerCase();
|
||||
/** What makes two tags the same: their words, whatever the weight or case. */
|
||||
export const tagKey = tag => tagWeight(tag).core.trim().toLowerCase();
|
||||
|
||||
// New tags before item `at` (the end when past it); the text's ending stays at the end.
|
||||
function spliceTags(parsed, at, texts) {
|
||||
|
||||
@@ -45,7 +45,7 @@ const asTag = text => (/^[A-Z][a-z]/.test(text) ? text[0].toLowerCase() + text.s
|
||||
* (false when it did not). `prefs` is the studio's { view: 'tags' | 'text', glossLang }. `refuse(card)`
|
||||
* says why a card may not go in ('' when it may); `onSave(value)` keeps the text as a card.
|
||||
* `drawer` is the studio drawer, for the handle that drags the text onto the canvas.
|
||||
* Returns { element, role, render(), refresh(), addText(text) }.
|
||||
* Returns { element, role, value(), render(), refresh(), addText(text) }.
|
||||
*/
|
||||
export function createPromptBoxEditor({ role, name, getValue, write, prefs, refuse, onSave, drawer, scope }) {
|
||||
const id = nextEditorId++;
|
||||
@@ -406,6 +406,7 @@ export function createPromptBoxEditor({ role, name, getValue, write, prefs, refu
|
||||
return {
|
||||
element,
|
||||
role,
|
||||
value: getValue,
|
||||
render,
|
||||
/** Redraws when the text changed elsewhere (not while it is being edited here). */
|
||||
refresh() {
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* Prompt Studio's reference column: a clicked card opens here, between the cards and the prompt
|
||||
* boxes, as its tags (with their meanings when a language is picked), so single tags can be
|
||||
* taken from it: a click puts that tag into the box the card goes into (ui_prompt_target.js),
|
||||
* "Add all" the whole card. Tags the box has already are ticked. Read only: the card itself is
|
||||
* never changed here. In the drawer it widens the drawer by the column while it is open; where
|
||||
* three columns do not fit it takes the cards' place, and "‹ Cards" goes back (the stylesheet).
|
||||
*/
|
||||
|
||||
import { translate as t } from './locales.js';
|
||||
import { fetchGlosses, glossOf } from './prompt_gloss.js';
|
||||
import { promptTagsOf, tagKey, tagWeight } from './prompt_tags.js';
|
||||
import { showWorkbenchToast } from './ui_prompt_toast.js';
|
||||
|
||||
const POLL_MS = 400;
|
||||
const EXTRA_WIDTH = 280; // the drawer grows by this while the column is open
|
||||
const HINT_KEY = 'anomalous_prompt_reference_hint';
|
||||
const ROLE_KEYS = { positive: 'recipePromptRolePositive', negative: 'recipePromptRoleNegative' };
|
||||
|
||||
function el(tag, className, content) {
|
||||
const node = document.createElement(tag);
|
||||
if (className) node.className = className;
|
||||
if (content !== undefined) node.textContent = content;
|
||||
return node;
|
||||
}
|
||||
|
||||
function button(className, label, title, onClick) {
|
||||
const node = el('button', className, label);
|
||||
node.type = 'button';
|
||||
if (title) node.title = title;
|
||||
node.onclick = onClick;
|
||||
return node;
|
||||
}
|
||||
|
||||
/** Says once, the first time a card opens here, that a click no longer adds the whole card. */
|
||||
function hintOnce() {
|
||||
try {
|
||||
if (localStorage.getItem(HINT_KEY)) return;
|
||||
localStorage.setItem(HINT_KEY, '1');
|
||||
} catch { /* no storage here: say it each visit */ }
|
||||
showWorkbenchToast(t('promptStudioRefHint'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills `grid` (between the cards and the boxes). `target` is the prompt side ({ addCard(card,
|
||||
* text), valueFor(card) }); `prefs` the studio's { glossLang }. Returns { open(card), close(), render() }.
|
||||
*/
|
||||
export function createPromptReference(grid, { drawer, scope, prefs, target }) {
|
||||
const panel = el('section', 'anomalous-ps-ref');
|
||||
panel.hidden = true;
|
||||
const head = el('header', 'anomalous-ps-target-head');
|
||||
const label = el('div', 'anomalous-ps-target-label');
|
||||
const title = el('span', 'anomalous-ps-target-name');
|
||||
const closeButton = button('anomalous-ps-target-x', '✕', t('promptStudioRefClose'), () => close());
|
||||
closeButton.setAttribute('aria-label', t('promptStudioRefClose'));
|
||||
label.append(title, closeButton);
|
||||
const addAll = button('anomalous-ps-mini', t('promptStudioRefAddAll'), t('promptStudioRefAddAllHint'), () => {
|
||||
if (card) void target.addCard(card).then(render);
|
||||
});
|
||||
const back = button('anomalous-ps-mini anomalous-ps-ref-back', t('promptStudioRefBack'), t('promptStudioRefClose'), () => close());
|
||||
head.append(back, label, addAll);
|
||||
const role = el('span', 'anomalous-ps-role');
|
||||
const note = el('p', 'anomalous-ps-target-note', t('promptStudioRefNote'));
|
||||
const tagsEl = el('div', 'anomalous-ps-tags');
|
||||
panel.append(head, role, note, tagsEl);
|
||||
grid.insertBefore(panel, grid.children[1] || null); // right after the cards
|
||||
|
||||
let card = null;
|
||||
let seen = null; // the box text the ticks were drawn from
|
||||
let taken = new Set(); // tags taken from this card here (a translated one reads differently in the box)
|
||||
let widened = null; // { from, to } drawer widths while the column is open
|
||||
let glossTimer = null;
|
||||
let glossFailed = '';
|
||||
const timer = setInterval(() => {
|
||||
if (card && target.valueFor(card) !== seen) render();
|
||||
}, POLL_MS);
|
||||
scope.onDispose(() => { clearInterval(timer); clearTimeout(glossTimer); });
|
||||
|
||||
function widen(open) {
|
||||
if (!drawer.classList.contains('anomalous-prompt-studio-drawer')) return;
|
||||
if (open && !widened) {
|
||||
const from = drawer.getBoundingClientRect().width;
|
||||
const to = Math.round(Math.min(window.innerWidth * 0.85, from + EXTRA_WIDTH));
|
||||
drawer.style.width = `${to}px`;
|
||||
widened = { from, to };
|
||||
} else if (!open && widened) {
|
||||
// Dragged wider or narrower meanwhile: that width is the user's now.
|
||||
if (Math.round(drawer.getBoundingClientRect().width) === widened.to) drawer.style.width = `${widened.from}px`;
|
||||
widened = null;
|
||||
}
|
||||
}
|
||||
|
||||
function glossText(tag) {
|
||||
const meaning = glossOf(tag, prefs.glossLang);
|
||||
return meaning === undefined ? (glossFailed === prefs.glossLang ? '' : '…') : meaning;
|
||||
}
|
||||
|
||||
function wantGlosses(tags) {
|
||||
clearTimeout(glossTimer);
|
||||
const lang = prefs.glossLang;
|
||||
if (!lang || glossFailed === lang || tags.every(tag => glossOf(tag, lang) !== undefined)) return;
|
||||
glossTimer = setTimeout(async () => {
|
||||
const ok = await fetchGlosses(tags, lang, scope.signal);
|
||||
if (scope.signal.aborted || !card) return;
|
||||
if (!ok) glossFailed = lang;
|
||||
render();
|
||||
}, 250);
|
||||
}
|
||||
|
||||
function chipFor(tag, have) {
|
||||
const { core, weight } = tagWeight(tag);
|
||||
const there = have.has(tagKey(tag)) || taken.has(tagKey(tag));
|
||||
const chip = el('button', `anomalous-ps-tag is-ref${there ? ' is-there' : ''}`);
|
||||
chip.type = 'button';
|
||||
chip.title = t(there ? 'promptStudioRefThere' : 'promptStudioRefTake');
|
||||
const main = el('span', 'anomalous-ps-tag-main');
|
||||
if (there) main.append(el('span', 'anomalous-ps-ref-tick', '✓'));
|
||||
main.append(el('span', 'anomalous-ps-tag-text', core));
|
||||
if (weight !== 1) main.append(el('span', 'anomalous-ps-tag-weight', String(weight)));
|
||||
chip.append(main);
|
||||
if (prefs.glossLang) chip.append(el('span', 'anomalous-ps-tag-gloss', glossText(tag)));
|
||||
chip.onclick = async () => {
|
||||
if (there) return;
|
||||
chip.disabled = true;
|
||||
if (await target.addCard(card, tag)) taken.add(tagKey(tag));
|
||||
render();
|
||||
};
|
||||
return chip;
|
||||
}
|
||||
|
||||
/** Draws the open card's tags, ticking those its box has. */
|
||||
function render() {
|
||||
if (!card) return;
|
||||
seen = target.valueFor(card);
|
||||
const have = new Set(promptTagsOf(seen ?? '').map(tagKey));
|
||||
const tags = promptTagsOf(card.content);
|
||||
title.textContent = t('promptStudioRefTitle', { name: card.title });
|
||||
const cardRole = card.role === 'negative' ? 'negative' : 'positive';
|
||||
role.className = `anomalous-ps-role is-${cardRole}`;
|
||||
role.textContent = t(ROLE_KEYS[cardRole]);
|
||||
tagsEl.replaceChildren(...tags.map(tag => chipFor(tag, have)));
|
||||
wantGlosses(tags);
|
||||
}
|
||||
|
||||
function open(next) {
|
||||
hintOnce();
|
||||
if (card?.id !== next.id) taken = new Set();
|
||||
card = next;
|
||||
panel.hidden = false;
|
||||
grid.classList.add('has-ref');
|
||||
widen(true);
|
||||
render();
|
||||
}
|
||||
|
||||
function close() {
|
||||
card = null;
|
||||
panel.hidden = true;
|
||||
grid.classList.remove('has-ref');
|
||||
widen(false);
|
||||
}
|
||||
|
||||
return { open, close, render };
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
/**
|
||||
* Prompt Studio's cards: three common ones and the prompts you saved (prompt_material_source.js),
|
||||
* with search and a small form for a new card. A card is clicked (or added from its preview,
|
||||
* ui_prompt_card_popover.js) to go into the prompt box of its role, dragged onto a box, or
|
||||
* with search and a small form for a new card. A card is clicked to open it as a reference
|
||||
* (ui_prompt_reference.js, tags taken one by one), added whole from its preview
|
||||
* (ui_prompt_card_popover.js) into the prompt box of its role, dragged onto a box, or
|
||||
* dragged out onto the canvas (prompt_card_drag.js); a saved one is renamed or deleted from its
|
||||
* preview. The saved list is checked again every 30 seconds and when the window comes back.
|
||||
*/
|
||||
@@ -32,15 +33,15 @@ function button(className, label, title, onClick) {
|
||||
return node;
|
||||
}
|
||||
|
||||
/** Fills `parent`; `onPick(card)` takes a clicked card. Returns { sync() }. */
|
||||
export function createPromptSourceDeck(parent, drawer, scope, onPick) {
|
||||
/** Fills `parent`; `onPick(card)` takes a clicked card, `onAdd(card)` one added whole from its preview. Returns { sync() }. */
|
||||
export function createPromptSourceDeck(parent, drawer, scope, { onPick, onAdd }) {
|
||||
const presets = PROMPT_PRESETS.map(card => ({ ...card, title: t(card.titleKey) }));
|
||||
let saved = [];
|
||||
let keyword = '';
|
||||
const popover = createCardPopover({
|
||||
drawer,
|
||||
scope,
|
||||
onAdd: card => onPick(card),
|
||||
onAdd,
|
||||
onRename: card => void rename(card),
|
||||
onDelete: card => void remove(card),
|
||||
});
|
||||
|
||||
@@ -48,7 +48,7 @@ function refusal(card, boxRole) {
|
||||
|
||||
/**
|
||||
* Fills `parent`. `owner` keeps the draft; `prefs` is the studio's { view, glossLang };
|
||||
* `onSave(text, role)` keeps a box's text as a card. Returns { addCard(card), render() }.
|
||||
* `onSave(text, role)` keeps a box's text as a card. Returns { addCard(card, text), valueFor(card), render() }.
|
||||
*/
|
||||
export function createPromptTarget(parent, { owner, drawer, scope, prefs, onSave }) {
|
||||
const draft = owner.promptStudioDraft ||= { positive: '', negative: '' };
|
||||
@@ -162,17 +162,24 @@ export function createPromptTarget(parent, { owner, drawer, scope, prefs, onSave
|
||||
const timer = setInterval(tick, POLL_MS);
|
||||
scope.onDispose(() => clearInterval(timer));
|
||||
|
||||
/** The box a card goes into: the one of its role, or one that takes either; null when none does. */
|
||||
const editorFor = card => {
|
||||
const role = card.role === 'negative' ? 'negative' : 'positive';
|
||||
return editors.find(item => item.role === role) || editors.find(item => !refusal(card, item.role)) || null;
|
||||
};
|
||||
|
||||
return {
|
||||
/** A card clicked: into the box of its role (or one that takes either), at the end. */
|
||||
addCard(card) {
|
||||
const role = card.role === 'negative' ? 'negative' : 'positive';
|
||||
const editor = editors.find(item => item.role === role) || editors.find(item => !refusal(card, item.role));
|
||||
/** `text` (the whole card when left out) into the box the card goes into, at the end; false when it did not go in. */
|
||||
async addCard(card, text = card.content) {
|
||||
const editor = editorFor(card);
|
||||
if (!editor) {
|
||||
showWorkbenchToast(t('promptStudioNoBoxFor', { card: t(ROLE_NAMES[role]) }));
|
||||
return;
|
||||
showWorkbenchToast(t('promptStudioNoBoxFor', { card: t(ROLE_NAMES[card.role === 'negative' ? 'negative' : 'positive']) }));
|
||||
return false;
|
||||
}
|
||||
void editor.addText(card.content);
|
||||
return editor.addText(text);
|
||||
},
|
||||
/** The text of the box the card goes into, null when there is none. */
|
||||
valueFor: card => editorFor(card)?.value() ?? null,
|
||||
render: () => editors.forEach(editor => editor.render()),
|
||||
};
|
||||
}
|
||||
@@ -3,8 +3,9 @@
|
||||
* a top bar with the view switch (tags or the whole text), the language tags' meanings are shown
|
||||
* in (or none), and on the page "Beside the canvas", in the drawer its dock side, "Back to the
|
||||
* window" and Close; the cards on the drawer's outer side (ui_prompt_source_deck.js) and
|
||||
* the prompt boxes beside the canvas (ui_prompt_target.js). A clicked card goes into the box of
|
||||
* its role; Save on a box keeps its text as a card under My prompts. The view and the meaning
|
||||
* the prompt boxes beside the canvas (ui_prompt_target.js). A clicked card opens between them as
|
||||
* a reference (ui_prompt_reference.js) to take its tags one by one; Save on a box keeps its text
|
||||
* as a card under My prompts. The view and the meaning
|
||||
* language are remembered in this browser.
|
||||
*/
|
||||
|
||||
@@ -13,6 +14,7 @@ import { GLOSS_LANGUAGES } from './prompt_gloss.js';
|
||||
import { promptTitle } from './prompt_composition.js';
|
||||
import { savePromptCard } from './prompt_material_source.js';
|
||||
import { anomalousPrompt } from './ui_dialog.js';
|
||||
import { createPromptReference } from './ui_prompt_reference.js';
|
||||
import { createPromptSourceDeck } from './ui_prompt_source_deck.js';
|
||||
import { createPromptTarget } from './ui_prompt_target.js';
|
||||
import { showWorkbenchToast } from './ui_prompt_toast.js';
|
||||
@@ -91,6 +93,7 @@ export function createPromptWorkbench(owner, drawer, scope, { mode = 'docked', o
|
||||
savePrefs(prefs);
|
||||
drawSwitches();
|
||||
target.render();
|
||||
reference.render();
|
||||
};
|
||||
controls.append(glossPicker);
|
||||
|
||||
@@ -135,6 +138,11 @@ export function createPromptWorkbench(owner, drawer, scope, { mode = 'docked', o
|
||||
}
|
||||
}
|
||||
|
||||
const deck = createPromptSourceDeck(grid, drawer, scope, card => target.addCard(card));
|
||||
const deck = createPromptSourceDeck(grid, drawer, scope, {
|
||||
onPick: card => reference.open(card),
|
||||
onAdd: card => void target.addCard(card),
|
||||
});
|
||||
const target = createPromptTarget(grid, { owner, drawer, scope, prefs, onSave: save });
|
||||
// Between the cards and the boxes, whichever side the drawer is docked on.
|
||||
const reference = createPromptReference(grid, { drawer, scope, prefs, target });
|
||||
}
|
||||
@@ -20,6 +20,10 @@
|
||||
grid-template-columns: 240px minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.anomalous-prompt-page .anomalous-ps-grid.has-ref {
|
||||
grid-template-columns: 240px minmax(0, 1fr) minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.anomalous-ps {
|
||||
container: anomalous-ps / inline-size;
|
||||
display: flex;
|
||||
@@ -165,6 +169,51 @@
|
||||
grid-template-columns: minmax(0, 1fr) 200px;
|
||||
}
|
||||
|
||||
/* A card opened as a reference (ui_prompt_reference.js) sits between the cards and the boxes. */
|
||||
.anomalous-ps-grid.has-ref {
|
||||
grid-template-columns: 200px minmax(0, 1fr) minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.anomalous-prompt-studio-drawer:not(.is-dock-left) .anomalous-ps-grid.has-ref {
|
||||
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) 200px;
|
||||
}
|
||||
|
||||
.anomalous-ps-ref {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
min-height: 0;
|
||||
padding: 10px 12px 16px;
|
||||
overflow-y: auto;
|
||||
border-right: 1px solid var(--amb-border);
|
||||
background: var(--amb-bg-panel);
|
||||
}
|
||||
|
||||
.anomalous-prompt-studio-drawer:not(.is-dock-left) .anomalous-ps-ref {
|
||||
order: 1;
|
||||
border-right: 0;
|
||||
border-left: 1px solid var(--amb-border);
|
||||
}
|
||||
|
||||
.anomalous-ps-ref .anomalous-ps-role {
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.anomalous-ps-tag.is-ref {
|
||||
font-family: inherit;
|
||||
text-align: left;
|
||||
cursor: copy;
|
||||
}
|
||||
|
||||
.anomalous-ps-tag.is-ref.is-there {
|
||||
opacity: 0.55;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.anomalous-ps-ref-tick {
|
||||
color: var(--amb-ok-text);
|
||||
}
|
||||
|
||||
.anomalous-ps-deck {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -648,6 +697,7 @@
|
||||
|
||||
/* These blocks set their own display, which would outrank the hidden attribute. */
|
||||
.anomalous-ps-new[hidden],
|
||||
.anomalous-ps-ref[hidden],
|
||||
.anomalous-ps-target-note[hidden],
|
||||
.anomalous-ps-foreign[hidden],
|
||||
.anomalous-ps-tags[hidden],
|
||||
@@ -656,7 +706,33 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* A narrow drawer stacks the cards over the prompt boxes. */
|
||||
/* No room for three columns: the reference takes the cards' place, its "‹ Cards" goes back. */
|
||||
.anomalous-ps-ref-back {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@container anomalous-ps (max-width: 980px) {
|
||||
.anomalous-ps-grid.has-ref .anomalous-ps-deck {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.anomalous-ps-grid.has-ref,
|
||||
.anomalous-prompt-page .anomalous-ps-grid.has-ref,
|
||||
.anomalous-prompt-studio-drawer:not(.is-dock-left) .anomalous-ps-grid.has-ref {
|
||||
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.anomalous-ps-ref-back {
|
||||
display: inline-flex;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.anomalous-ps-ref .anomalous-ps-target-x {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* A narrow drawer stacks the cards (or the reference) over the prompt boxes. */
|
||||
@container anomalous-ps (max-width: 540px) {
|
||||
.anomalous-ps-grid,
|
||||
.anomalous-prompt-studio-drawer:not(.is-dock-left) .anomalous-ps-grid {
|
||||
@@ -664,8 +740,16 @@
|
||||
grid-template-rows: minmax(120px, 34%) minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.anomalous-ps-grid.has-ref,
|
||||
.anomalous-prompt-studio-drawer:not(.is-dock-left) .anomalous-ps-grid.has-ref {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
grid-template-rows: minmax(120px, 40%) minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.anomalous-ps-deck,
|
||||
.anomalous-prompt-studio-drawer:not(.is-dock-left) .anomalous-ps-deck {
|
||||
.anomalous-prompt-studio-drawer:not(.is-dock-left) .anomalous-ps-deck,
|
||||
.anomalous-ps-ref,
|
||||
.anomalous-prompt-studio-drawer:not(.is-dock-left) .anomalous-ps-ref {
|
||||
order: 0;
|
||||
border: 0;
|
||||
border-bottom: 1px solid var(--amb-border);
|
||||
|
||||
Reference in New Issue
Block a user