Fix what a walk through every page found before 1.63
Every page in both languages, all themes and at 480: - Give the window its own text colour: text with none took ComfyUI's, white on the light theme (Tidy headings and file names, the site chip). - Keep a task's link chip in its row, its x in reach, and colour the next-task chip. - Let choices in Settings wrap, the Models search shrink, and a workflow's preset row go to two lines. - Add --amb-on-link for text on the accent: pale in the dark themes, so white was hard to read. - Lists and colons follow the language (listSeparator, wordColon); tests/words_in_language.mjs keeps it so. - Right plurals in English, "AI" on the rail, one line left in Chinese translated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
6afbbf9059
commit
d778aec946
@@ -2,6 +2,10 @@
|
||||
|
||||
## v1.63.0 — unreleased
|
||||
|
||||
- 发版前把每个页面按中英文、深浅色和 480 窄宽走了一遍,修了一批小问题。浅色主题下,模型整理页的标题和文件名、任务上“接着做”的标签原来几乎看不见。窄窗口下,任务的“接着哪个任务”标签伸出窗口、× 点不到,设置页的主题按钮把页面撑出横向滚动,模型页的搜索框压住标题,工作流详情的“新预设”被切掉。
|
||||
- 英文界面的列表和冒号不再是中文标点,“1 saves”这类单复数对了,左边栏的 AI 工作台写作 “AI”,一条漏翻的提示补上了。深色主题下浅紫色按钮和角标上的字改成深色,看得更清楚。
|
||||
- A round through every page in both languages, all themes and at 480 fixed small things. In the light theme, the Tidy page's headings and file names and a task's "goes on in" chip could hardly be read. In a narrow window, a task's "goes on from" chip ran out of the window with its × out of reach, the theme buttons in Settings pushed the page sideways, the Models search sat over the title, and "New preset" was cut off.
|
||||
- The English window no longer shows Chinese punctuation in lists and after labels, "1 saves" and the like have the right plural, the rail says "AI" for the AI workbench, and one line that was left in Chinese is translated. In the dark themes, text on pale accent buttons and badges is dark now, so it reads better.
|
||||
- 侧栏下面的工具按常用程度排了:当前节点在最上面,然后是模型检查,模型扫描在最下面。
|
||||
- The rail's tools go by how often they are used: Current node first, then Model Check, with the scan last.
|
||||
- 当前节点的参数卡清爽了:来源不再一条一行,改成按工作流、搭配、图片、这里存的分开的小标签,同一渠道几条合成一个,点标签直接过去,几条的话先列出来。
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// What the code puts together itself goes through the locale: `.join('、')` or a ":" in a template shows
|
||||
// Chinese punctuation in the English window. tts_setup_api.js runs without the window's words.
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync, readdirSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const folder = join(dirname(fileURLToPath(import.meta.url)), '..', 'web', 'modules');
|
||||
const LEFT_OUT = new Set(['locales.js', 'tts_setup_api.js']);
|
||||
const CHINESE_JOIN = [/\.join\('[、:]'\)/, /:\$\{/, /\}:[`$]/, /(\$\{/];
|
||||
|
||||
const found = [];
|
||||
for (const name of readdirSync(folder).filter(file => file.endsWith('.js') && !LEFT_OUT.has(file))) {
|
||||
readFileSync(join(folder, name), 'utf8').split(/\r?\n/).forEach((line, index) => {
|
||||
if (/^\s*(\/\/|\*|\/\*)/.test(line)) return;
|
||||
if (CHINESE_JOIN.some(pattern => pattern.test(line))) found.push(`${name}:${index + 1}: ${line.trim()}`);
|
||||
});
|
||||
}
|
||||
assert.deepEqual(found, [], 'use t(\'listSeparator\') and t(\'wordColon\')');
|
||||
console.log('words in the shown language: ok');
|
||||
+31
-25
@@ -1220,6 +1220,9 @@ export const i18n = {
|
||||
homeStartNews: "看更新说明",
|
||||
shellActivity: "记录",
|
||||
shellAi: "AI 工作台",
|
||||
shellAiRail: "AI 工作台",
|
||||
listSeparator: "、",
|
||||
wordColon: ":",
|
||||
aiTasks: "AI 的任务",
|
||||
aiTaskCount: "{count} 个",
|
||||
aiUntitled: "未命名任务",
|
||||
@@ -4310,7 +4313,7 @@ export const i18n = {
|
||||
paramSetDiffers: "{count} different from the default",
|
||||
paramSetSame: "Same as the default",
|
||||
paramSetCompare: "Compare with the default",
|
||||
paramSetCount: "{count} presets",
|
||||
paramSetCount: "{count} {count|preset|presets}",
|
||||
workflowsSteps: "{count} {count|step|steps}",
|
||||
recipePromptShowAll: "Show all",
|
||||
compareWithDefault: "Compare with the default",
|
||||
@@ -4318,7 +4321,7 @@ export const i18n = {
|
||||
workflowOwnValuesHint: "The values saved with the workflow",
|
||||
workflowOwnValuesShort: "Saved with it",
|
||||
workflowPresetDiffers: "{count} different",
|
||||
workflowPresetMarked: "{count} values unlike the default, orange in the flow above",
|
||||
workflowPresetMarked: "{count} {count|value|values} unlike the default, orange in the flow above",
|
||||
workflowPresetAdd: "New preset",
|
||||
workflowPresetFromShown: "New from the one shown",
|
||||
workflowSetFromCanvas: "From canvas",
|
||||
@@ -4784,7 +4787,7 @@ export const i18n = {
|
||||
mainFloatingTriggerStyleIcon: 'Circular icon',
|
||||
mainFloatingTriggerStylePill: 'Labeled pill',
|
||||
mainResetFloatingTriggerPosition: 'Reset floating entry position',
|
||||
mainRetryInit: '插件界面初始化失败,点击可重试',
|
||||
mainRetryInit: 'The plugin window failed to start. Click to try again',
|
||||
mainRetryInitEn: 'The plugin UI failed to initialize. Click to retry.',
|
||||
mainShareFingerprints: "{hashed} of {total} {total|model|models} carry a fingerprint, so others can find the same file even under another name.",
|
||||
mainShareNoFingerprint: "{count} have none (not scanned, or not on this computer); others can only go by name or size, so scan first if you can.",
|
||||
@@ -4872,6 +4875,9 @@ export const i18n = {
|
||||
homeStartNews: "What's new",
|
||||
shellActivity: "Activity",
|
||||
shellAi: "AI workbench",
|
||||
shellAiRail: "AI",
|
||||
listSeparator: ", ",
|
||||
wordColon: ": ",
|
||||
aiTasks: "The AI's tasks",
|
||||
aiTaskCount: "{count}",
|
||||
aiUntitled: "Untitled task",
|
||||
@@ -4905,7 +4911,7 @@ export const i18n = {
|
||||
aiMapDenoise: "denoise {value}",
|
||||
aiMapBase: "base {name}",
|
||||
aiMapLoras: "{count} LoRA(s)",
|
||||
aiMapNodes: "{count} nodes",
|
||||
aiMapNodes: "{count} {count|node|nodes}",
|
||||
aiMapAdded: "added \"{title}\"",
|
||||
aiMapRemoved: "removed \"{title}\"",
|
||||
aiMapChanged: "{title} · {key}: {from} → {to}",
|
||||
@@ -5024,7 +5030,7 @@ export const i18n = {
|
||||
aiExecution_untracked: "No execution information yet",
|
||||
aiExecutionRefresh: "Refresh status",
|
||||
aiExecutionTime: "Elapsed {seconds}s",
|
||||
aiExecutionBatch: "{count} runs submitted",
|
||||
aiExecutionBatch: "{count} {count|run|runs} submitted",
|
||||
aiExecutionContact: "Last AI call started {seconds}s ago",
|
||||
aiExecutionReview: "ComfyUI finished this generation. Waiting for the AI to review and report the results.",
|
||||
aiExecutionUntracked: "The AI took the task, but its generation is not being tracked. Ask it to run through AMB or attach the exact IDs returned by its external submission.",
|
||||
@@ -5190,8 +5196,8 @@ export const i18n = {
|
||||
aiDecisionCanvas: "Where the AI works on the canvas",
|
||||
aiDecisionStop: "Stopped a run",
|
||||
aiDecisionGap: "Since the last recorded decision the AI {what}, with no new decision recorded.",
|
||||
aiDecisionGapRuns: "ran {count} times",
|
||||
aiDecisionGapCanvas: "changed the canvas {count} times",
|
||||
aiDecisionGapRuns: "ran {count} {count|time|times}",
|
||||
aiDecisionGapCanvas: "changed the canvas {count} {count|time|times}",
|
||||
aiDecisionsNone: "No decisions yet. Your choices on panels, what you allow or refuse and the materials you hand over are kept here by themselves; what you settle with the AI in its own chat, it records here with log_decision.",
|
||||
aiKind_act: "Action",
|
||||
aiLooks: "Looked things up {count} {count|time|times}",
|
||||
@@ -5576,27 +5582,27 @@ export const i18n = {
|
||||
snapshotNoTab: "Could not reach that tab: go to it first, then try again",
|
||||
savesRunOne: "Run",
|
||||
savesRunTimes: "times",
|
||||
savesRunning: "{count} runs to go",
|
||||
savesPicturesAll: "See all {count} pictures",
|
||||
savesRunning: "{count} {count|run|runs} to go",
|
||||
savesPicturesAll: "See all {count} {count|picture|pictures}",
|
||||
savesPicturesBack: "← All saves",
|
||||
savesPicturesTitle: "{name} · save {number} · {count} pictures",
|
||||
savesRunOneHint: "Run only this save, {count} times, a new seed each",
|
||||
savesRunsLeft: "{count} runs to go; their pictures come here",
|
||||
savesPicturesTitle: "{name} · save {number} · {count} {count|picture|pictures}",
|
||||
savesRunOneHint: "Run only this save, {count} {count|time|times}, a new seed each",
|
||||
savesRunsLeft: "{count} {count|run|runs} to go; their pictures come here",
|
||||
savesListToggle: "Saves",
|
||||
savesListBack: "← Workflows",
|
||||
savesListTitle: "{canvases} canvases, {saves} saves",
|
||||
savesListEmpty: "No saves yet. Right-click the canvas and choose \"Save this state\".",
|
||||
savesListFailed: "The saves could not be read: reload the page and try again.",
|
||||
savesListCount: "{count} saves",
|
||||
savesListCount: "{count} {count|save|saves}",
|
||||
savesListCanvasOpen: "Canvas open",
|
||||
savesListCanvasClosed: "Canvas closed",
|
||||
savesListRemove: "Remove these",
|
||||
savesListRemoveConfirm: "Move the {count} saves of \"{name}\" to the Recycle Bin? Their pictures stay.",
|
||||
savesListRemoveConfirm: "Move the {count} {count|save|saves} of \"{name}\" to the Recycle Bin? Their pictures stay.",
|
||||
snapshotOpenTab: "Open on a new tab",
|
||||
snapshotRemoveConfirm: "Move save {number} to the Recycle Bin? Its pictures stay.",
|
||||
snapshotNoPictures: "Not run yet",
|
||||
snapshotSaveFailed: "Not saved: {why}",
|
||||
snapshotLogged: "{marks} saves, {count} runs",
|
||||
snapshotLogged: "{marks} {marks|save|saves}, {count} {count|run|runs}",
|
||||
aiTool_pick_base: "Asked you to pick a base",
|
||||
aiRouteTitle: "How should the two models you picked be used?",
|
||||
aiRouteCard: "Your saved card: {name}",
|
||||
@@ -5695,13 +5701,13 @@ export const i18n = {
|
||||
aiTbPromptFrom_combo: "From a combo",
|
||||
aiTbPromptFrom_workflow: "From a workflow",
|
||||
aiTbPageTool: "Page-only helper: the AI can place it, not look it up",
|
||||
aiTbSettings: "{count} settings",
|
||||
aiTbSettings: "{count} {count|setting|settings}",
|
||||
aiTbPaid: "Paid",
|
||||
aiTbPageShort: "Page-only",
|
||||
aiTbDeprecated: "Deprecated",
|
||||
aiTbLoras: "{count} LoRAs",
|
||||
aiTbPartial: "Fragment",
|
||||
aiTbChoices: "{count} choices",
|
||||
aiTbChoices: "{count} {count|choice|choices}",
|
||||
aiTbPick: "Pick for the AI",
|
||||
aiTbPicked: "Picked",
|
||||
aiTbPickPrompt: "Pick just its prompt",
|
||||
@@ -5716,7 +5722,7 @@ export const i18n = {
|
||||
aiTbLoraList: "LoRAs",
|
||||
aiTbPositive: "Positive prompt",
|
||||
aiTbNegative: "Negative prompt",
|
||||
aiTbNodeCount: "{count} nodes",
|
||||
aiTbNodeCount: "{count} {count|node|nodes}",
|
||||
aiTbWords: "Trigger words",
|
||||
aiHandWorkflowWish: "With the workflow “{name}”: ",
|
||||
workflowHandHint: "Hand it to the AI: a task with this preset; you only tell the AI what to draw",
|
||||
@@ -5746,7 +5752,7 @@ export const i18n = {
|
||||
workflowFlowRunsIn: "Used in these presets:",
|
||||
workflowFlowRunsNowhere: "No preset uses it.",
|
||||
workflowFlowChangedHere: "Changed in this stage:",
|
||||
workflowFlowNodes: "{count} nodes: {ids}",
|
||||
workflowFlowNodes: "{count} {count|node|nodes}: {ids}",
|
||||
workflowFlowDiffNote: "Orange boxes are what this preset changed; struck out is the default's value.",
|
||||
aiToolboxTitle: "Materials for the AI",
|
||||
aiToolboxKind_nodes: "Nodes",
|
||||
@@ -5815,11 +5821,11 @@ export const i18n = {
|
||||
mcpDidLora: "The AI added the LoRA {name} (Ctrl+Z undoes it)",
|
||||
mcpDidCombo: "The AI placed the combo “{name}” (Ctrl+Z undoes it)",
|
||||
mcpDidNode: "The AI added the node “{name}” (Ctrl+Z undoes it)",
|
||||
mcpDidNodes: "The AI added {count} nodes (Ctrl+Z undoes it)",
|
||||
mcpDidNodes: "The AI added {count} {count|node|nodes} (Ctrl+Z undoes it)",
|
||||
mcpDidWire: "The AI wired “{from}” to “{to}” (Ctrl+Z undoes it)",
|
||||
mcpDidValues: "The AI changed {count} settings (Ctrl+Z undoes it)",
|
||||
mcpDidValues: "The AI changed {count} {count|setting|settings} (Ctrl+Z undoes it)",
|
||||
mcpDidFill: "The AI filled in this run on {count} {count|node|nodes} (Ctrl+Z undoes it)",
|
||||
mcpDidRemove: "The AI removed {count} nodes (Ctrl+Z undoes it)",
|
||||
mcpDidRemove: "The AI removed {count} {count|node|nodes} (Ctrl+Z undoes it)",
|
||||
mcpDidWorkflow: "The AI started the workflow “{name}”",
|
||||
mcpDidFix: "The AI put back {count} missing models (Ctrl+Z undoes it)",
|
||||
mcpDidRun: "The AI started the workflow",
|
||||
@@ -6198,12 +6204,12 @@ export const i18n = {
|
||||
tidyUsageRecycle: 'Move to the Recycle Bin',
|
||||
tidyUsageConfirm: 'Move the {count} picked models ({size}) with their covers and notes to the Recycle Bin? They can be restored from there.',
|
||||
tidyUsageRecycleFailed: 'Some models could not be moved to the Recycle Bin; the browser console says why.',
|
||||
tidyUsageRecycled: '✓ Sent {count} models to the Recycle Bin, {size} freed.',
|
||||
tidyUsageRecycled: '✓ Sent {count} {count|model|models} to the Recycle Bin, {size} freed.',
|
||||
tidyUsageNone: 'No models in this group.',
|
||||
tidyUsageMore: '{count} more ({size}) not listed; deal with the ones above first.',
|
||||
tidyUsagePacksLead: 'These packs work only through their nodes, and none of their nodes was run, opened or saved in this period (on the canvas or in an open tab counts as use). "Installed" counts from the day its folder was made. The plugin leaves node packs alone: "Find it in the Manager" opens ComfyUI Manager searched for the pack (its name is copied too, to paste in the search box if nothing shows); there, Disable it (it can be enabled again) or Uninstall it, then restart ComfyUI.',
|
||||
tidyUsageNoManager: 'ComfyUI Manager was not found. Once it is installed, node packs can be disabled or removed there.',
|
||||
tidyUsageNodes: '{count} nodes',
|
||||
tidyUsageNodes: '{count} {count|node|nodes}',
|
||||
tidyUsageNoNodes: 'No nodes',
|
||||
tidyUsageInstalled: 'installed {days} days ago',
|
||||
tidyUsageFeeds: 'The nodes of {packs} take what it makes: check those are not needed before disabling it',
|
||||
@@ -7248,7 +7254,7 @@ export const i18n = {
|
||||
scriptTuneResetLines: "{count} {count|line|lines} set for {count|itself|themselves}: let them follow this character",
|
||||
scriptTuneResetAll: "Let these lines follow the layer above in everything",
|
||||
scriptTuneLine: "Line {n}",
|
||||
scriptTuneLines: "{count} lines picked",
|
||||
scriptTuneLines: "{count} {count|line|lines} picked",
|
||||
scriptTuneWho: "Read by",
|
||||
scriptTuneFromLine: "This line",
|
||||
scriptTuneFromUsual: "{name}'s usual",
|
||||
|
||||
@@ -29,7 +29,7 @@ export function detectPlatform(url) {
|
||||
if (!clean) return null;
|
||||
const [, name, rgb] = PLATFORMS.find(([pattern]) => pattern.test(clean)) || [null, 'Web Link', ''];
|
||||
return rgb
|
||||
? { name, color: `rgb(${rgb})`, bg: `rgba(${rgb}, 0.15)`, border: `rgba(${rgb}, 0.4)` }
|
||||
? { name, color: `color-mix(in srgb, rgb(${rgb}) 60%, var(--amb-text-main))`, bg: `rgba(${rgb}, 0.15)`, border: `rgba(${rgb}, 0.4)` }
|
||||
: { name, color: 'var(--amb-text-muted)', bg: 'transparent', border: 'var(--amb-border-strong)' };
|
||||
}
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ function placeStructure(owner, data, position) {
|
||||
} catch (error) {
|
||||
if (error.code !== 'missing_nodes') throw error;
|
||||
void anomalousAlert(t('comboPlaceMissingNodes', {
|
||||
nodes: error.missing.map(item => (item.pack ? `${item.type}(${item.pack})` : item.type)).join('、'),
|
||||
nodes: error.missing.map(item => (item.pack ? `${item.type} (${item.pack})` : item.type)).join(t('listSeparator')),
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ export function looksRow(steps, number) {
|
||||
row.append(el('span', 'anomalous-ai-step-dot', number));
|
||||
const body = el('div', 'anomalous-ai-step-body');
|
||||
const tools = lookTools(steps).map(({ tool, count }) => counted(tool, count));
|
||||
const head = el('button', 'anomalous-ai-looks', `${t('aiLooks', { count: steps.length })}:${tools.join('、')}`);
|
||||
const head = el('button', 'anomalous-ai-looks', `${t('aiLooks', { count: steps.length })}${t('wordColon')}${tools.join(t('listSeparator'))}`);
|
||||
head.type = 'button';
|
||||
head.onclick = () => {
|
||||
details.hidden = !details.hidden;
|
||||
|
||||
@@ -50,7 +50,7 @@ export function decisionCard(record, numberOf = null) {
|
||||
if (BY[record.by]) head.append(el('span', `anomalous-ai-decision-by is-${record.by}`, t(BY[record.by])));
|
||||
card.append(head, el('div', 'anomalous-ai-decision-text', record.decision || ''));
|
||||
if (record.reason) card.append(el('div', 'anomalous-ai-decision-why', t('aiDecisionWhy', { reason: record.reason })));
|
||||
if (record.rejected?.length) card.append(el('div', 'anomalous-ai-decision-not', t('aiDecisionRejected', { options: record.rejected.join('、') })));
|
||||
if (record.rejected?.length) card.append(el('div', 'anomalous-ai-decision-not', t('aiDecisionRejected', { options: record.rejected.join(t('listSeparator')) })));
|
||||
if (record.related?.length) {
|
||||
const links = el('div', 'anomalous-ai-decision-links');
|
||||
links.append(el('span', '', t('aiDecisionAbout')), ...record.related.map(id => stepLink(id, numberOf)));
|
||||
@@ -64,7 +64,7 @@ function described(item) {
|
||||
switch (item.type) {
|
||||
case 'logged': return [item.title, item.decision];
|
||||
case 'answer': return [item.question || t('aiDecisionAnswer'), item.skipped ? t('aiPanelSkipped') : item.timed_out ? t('aiPanelTookRecommended', { answer: item.answer }) : item.answer];
|
||||
case 'gate': return [t(toolKey(item.tool)), [t(item.allowed ? 'aiDecisionAllowed' : 'aiDecisionRefused'), item.text].filter(Boolean).join(':')];
|
||||
case 'gate': return [t(toolKey(item.tool)), [t(item.allowed ? 'aiDecisionAllowed' : 'aiDecisionRefused'), item.text].filter(Boolean).join(t('wordColon'))];
|
||||
case 'toolbox': return [t('aiDecisionToolbox'), item.count ? t('aiDecisionToolboxText', { count: item.count, mode: t(`aiTbMode_${item.mode}`) }) : t('aiToolboxCleared')];
|
||||
case 'canvas': return [t('aiDecisionCanvas'), t(item.mode === 'new' ? 'aiCanvasChoseNew' : 'aiCanvasChoseCurrent')];
|
||||
case 'privacy': return [t('aiPrivacy'), t(item.on ? 'aiPrivacyChoseOn' : 'aiPrivacyChoseOff')];
|
||||
@@ -85,7 +85,7 @@ export function renderDecisionsView(pane, task, ctx) {
|
||||
const gap = task.decisions_gap;
|
||||
if (gap && items.length) {
|
||||
const parts = [gap.runs ? t('aiDecisionGapRuns', { count: gap.runs }) : '', gap.canvas ? t('aiDecisionGapCanvas', { count: gap.canvas }) : ''].filter(Boolean);
|
||||
body.append(el('div', 'anomalous-ai-decisions-gap', t('aiDecisionGap', { what: parts.join('、') })));
|
||||
body.append(el('div', 'anomalous-ai-decisions-gap', t('aiDecisionGap', { what: parts.join(t('listSeparator')) })));
|
||||
}
|
||||
if (!items.length) body.append(el('div', 'anomalous-ai-stage-empty anomalous-ai-decisions-none', t('aiDecisionsNone')));
|
||||
for (const item of items) {
|
||||
@@ -100,7 +100,7 @@ export function renderDecisionsView(pane, task, ctx) {
|
||||
if (BY[by]) top.append(el('span', `anomalous-ai-decision-by is-${by}`, t(BY[by])));
|
||||
text.append(top, el('div', 'anomalous-ai-decisions-words', words || ''));
|
||||
if (item.type === 'logged' && item.reason) text.append(el('div', 'anomalous-ai-decision-why', t('aiDecisionWhy', { reason: item.reason })));
|
||||
if (item.type === 'logged' && item.rejected?.length) text.append(el('div', 'anomalous-ai-decision-not', t('aiDecisionRejected', { options: item.rejected.join('、') })));
|
||||
if (item.type === 'logged' && item.rejected?.length) text.append(el('div', 'anomalous-ai-decision-not', t('aiDecisionRejected', { options: item.rejected.join(t('listSeparator')) })));
|
||||
const foot = el('div', 'anomalous-ai-decision-links');
|
||||
foot.append(el('span', '', timeLabel(item.at)), stepLink(item.step, ctx.numberOf));
|
||||
text.append(foot);
|
||||
|
||||
@@ -52,7 +52,7 @@ export function gateCard(step, taskId, changed) {
|
||||
if (!asked.decision || asked.earlier) return null;
|
||||
const words = asked.decision === 'allow'
|
||||
? t(step.state === 'allowed' ? 'aiGateAllowedLater' : 'aiGateAllowed')
|
||||
: t('aiGateDenied') + (asked.text ? `:${asked.text}` : '');
|
||||
: t('aiGateDenied') + (asked.text ? `${t('wordColon')}${asked.text}` : '');
|
||||
return el('div', `anomalous-ai-gate-answer is-${asked.decision}`, words);
|
||||
}
|
||||
const card = el('div', 'anomalous-ai-gate');
|
||||
|
||||
@@ -39,7 +39,7 @@ export function boxDetail(box) {
|
||||
const facts = box.facts || {};
|
||||
switch (box.role) {
|
||||
case 'lora': return [facts.file, Number.isFinite(facts.strength) ? `(${facts.strength})` : ''].filter(Boolean).join(' ');
|
||||
case 'prompt': return `${t(facts.polarity === 'negative' ? 'aiMapNegative' : 'aiMapPositive')}:${facts.text || '—'}`;
|
||||
case 'prompt': return `${t(facts.polarity === 'negative' ? 'aiMapNegative' : 'aiMapPositive')}${t('wordColon')}${facts.text || '—'}`;
|
||||
case 'sampler': return [size(facts), facts.steps ? t('aiRunSteps', { steps: facts.steps }) : '', facts.cfg !== undefined ? `CFG ${facts.cfg}` : '',
|
||||
facts.sampler_name || '', facts.denoise !== undefined && facts.denoise < 1 ? t('aiMapDenoise', { value: facts.denoise }) : ''].filter(Boolean).join(' · ');
|
||||
case 'size': return size(facts);
|
||||
|
||||
@@ -354,7 +354,7 @@ export async function openToolbox(task, changed = () => {}) {
|
||||
const current = list.find(facet => facet.key === state.facet);
|
||||
const open = button(`anomalous-tb-facet-open${current && state.picks.packs.includes(current.key) ? ' has-pack' : ''}`, [
|
||||
current?.source ? sourceBadge(current.source, 20) : icon('list', 15),
|
||||
el('span', 'anomalous-tb-facet-open-label', `${title}:${current?.label || t('aiTbEverything')}`),
|
||||
el('span', 'anomalous-tb-facet-open-label', `${title}${t('wordColon')}${current?.label || t('aiTbEverything')}`),
|
||||
el('span', 'anomalous-tb-facet-count', String(current?.count ?? beforeFacet.length)), icon('chevronDown', 14)],
|
||||
() => toggleFacetMenu({ host: main, top: side.offsetTop + side.offsetHeight, title, rows: rows(), button: open }), t('aiTbPickSource'));
|
||||
open.setAttribute('aria-haspopup', 'listbox');
|
||||
|
||||
@@ -334,7 +334,7 @@ export function openGptSovitsEditor(group, { onSaved } = {}) {
|
||||
const uses = usesOf(state.voices, path).map(use => t(`ttsRefsUse_${use.role}`, { name: use.name === MAIN ? t('ttsRefsMainVoice') : use.name }));
|
||||
const message = [
|
||||
t('ttsRefsRemoveConfirm', { file: baseName(path) }),
|
||||
uses.length ? t('ttsRefsRemoveUses', { uses: uses.join('、') }) : '',
|
||||
uses.length ? t('ttsRefsRemoveUses', { uses: uses.join(t('listSeparator')) }) : '',
|
||||
].filter(Boolean).join('\n');
|
||||
if (!await anomalousConfirm(message, t('ttsRefsRemove'))) return;
|
||||
if (state.playing?.path === path) stopPlaying();
|
||||
|
||||
@@ -177,7 +177,7 @@ function showChoices(owner, name, summary, { dialog, footer, close }) {
|
||||
if (summary.models?.total) {
|
||||
const { matched, total, missing } = summary.models;
|
||||
const hint = missing.length
|
||||
? t('backupModelsMissing', { names: missing.slice(0, 5).map(rel => rel.split('/').pop()).join('、'), count: missing.length })
|
||||
? t('backupModelsMissing', { names: missing.slice(0, 5).map(rel => rel.split('/').pop()).join(t('listSeparator')), count: missing.length })
|
||||
: '';
|
||||
models = checkbox(t('backupModels', { matched, total }), matched > 0, hint);
|
||||
dialog.append(models.line);
|
||||
|
||||
@@ -207,11 +207,11 @@ export async function saveSelectionAsCombo(owner, nodes = null) {
|
||||
el('p', 'anomalous-structure-note', t('comboFromSelectionKept', { count: structure.nodes.length, nodes: structureSummary(structure) })));
|
||||
if (dropped.length) {
|
||||
dialog.append(el('p', 'anomalous-structure-note is-muted', t('comboFromSelectionDropped', {
|
||||
count: dropped.length, nodes: dropped.map(node => node.title || node.type).join('、'),
|
||||
count: dropped.length, nodes: dropped.map(node => node.title || node.type).join(t('listSeparator')),
|
||||
})));
|
||||
}
|
||||
const open = openInputs(structure);
|
||||
if (open.length) dialog.append(el('p', 'anomalous-structure-note is-muted', t('comboFromSelectionOpen', { inputs: open.join('、') })));
|
||||
if (open.length) dialog.append(el('p', 'anomalous-structure-note is-muted', t('comboFromSelectionOpen', { inputs: open.join(t('listSeparator')) })));
|
||||
const rows = el('div', 'anomalous-structure-slots');
|
||||
const choices = structure.slots.map((slot) => {
|
||||
const row = el('label', 'anomalous-structure-slot');
|
||||
@@ -364,7 +364,7 @@ export function renderStructuredCombo(owner, host, note, toolbar) {
|
||||
const nodeName = (slot) => {
|
||||
const node = nodeOf.get(slot.node);
|
||||
if (!node) return null;
|
||||
return { text: `${node.title || node.name || node.type}${node.pack ? `(${node.pack})` : ''}`,
|
||||
return { text: `${node.title || node.name || node.type}${node.pack ? ` (${node.pack})` : ''}`,
|
||||
title: node.pack ? `${node.type} · ${node.pack}` : node.type };
|
||||
};
|
||||
const labelLine = (slot) => {
|
||||
@@ -506,15 +506,15 @@ export function renderStructuredCombo(owner, host, note, toolbar) {
|
||||
|
||||
const about = el('div', 'anomalous-structure-about');
|
||||
const open = openInputs(structure);
|
||||
if (open.length) about.append(el('p', 'anomalous-structure-note', t('comboOpenInputs', { inputs: open.join('、') })));
|
||||
if (open.length) about.append(el('p', 'anomalous-structure-note', t('comboOpenInputs', { inputs: open.join(t('listSeparator')) })));
|
||||
about.append(el('p', 'anomalous-structure-note is-muted', t('comboStructureNodes', { nodes: structureSummary(structure) })),
|
||||
el('p', 'anomalous-structure-note is-muted', t('comboFixedHint')));
|
||||
const packs = [...new Set(structure.nodes.map(item => item.pack).filter(Boolean))];
|
||||
if (packs.length) about.append(el('p', 'anomalous-structure-note is-muted', t('comboStructurePacks', { packs: packs.join('、') })));
|
||||
if (packs.length) about.append(el('p', 'anomalous-structure-note is-muted', t('comboStructurePacks', { packs: packs.join(t('listSeparator')) })));
|
||||
const missing = missingTypes(structure);
|
||||
if (missing.length) {
|
||||
about.append(el('p', 'anomalous-structure-note is-bad', t('comboStructureMissing', {
|
||||
nodes: missing.map(item => (item.pack ? `${item.type}(${item.pack})` : item.type)).join('、'),
|
||||
nodes: missing.map(item => (item.pack ? `${item.type} (${item.pack})` : item.type)).join(t('listSeparator')),
|
||||
})));
|
||||
}
|
||||
card.append(about);
|
||||
|
||||
@@ -260,7 +260,7 @@ export function _openGalleryReplacer(node, w, options = {}) {
|
||||
if (mode === 'replace') chosen = chosen.filter(pathMatchesBaseFilter);
|
||||
};
|
||||
const updateSelection = () => {
|
||||
const names = chosen.map(getName).join('、');
|
||||
const names = chosen.map(getName).join(t('listSeparator'));
|
||||
if (mode === 'insert') {
|
||||
selectionText.textContent = chosen.length ? t('pickerChosenLoras', { count: chosen.length, names }) : t('pickerChooseLoras');
|
||||
selectionText.title = names;
|
||||
|
||||
@@ -183,7 +183,7 @@ function keyBlock(keys, ticks, starred, focus) {
|
||||
function nodeList(title, nodes) {
|
||||
const block = el('div', 'anomalous-compare-node is-structure');
|
||||
block.append(el('div', 'anomalous-compare-node-title', title));
|
||||
block.append(el('div', 'anomalous-compare-structure-list', nodes.map(node => `${node.title} #${node.id}`).join('、')));
|
||||
block.append(el('div', 'anomalous-compare-structure-list', nodes.map(node => `${node.title} #${node.id}`).join(t('listSeparator'))));
|
||||
return block;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ function verificationBox(parent, missing) {
|
||||
if (!missing.length) return null;
|
||||
const box = appendText(parent, 'div', '', 'anomalous-wfs-verify');
|
||||
appendText(box, 'strong', formatRecipeText('recipeVerificationMissing', { count: missing.length }));
|
||||
appendText(box, 'small', missing.map((reference) => reference.saved_value).join('、'), 'anomalous-wfs-hint');
|
||||
appendText(box, 'small', missing.map((reference) => reference.saved_value).join(t('listSeparator')), 'anomalous-wfs-hint');
|
||||
const choice = appendText(box, 'label', '', 'anomalous-wfs-check');
|
||||
const input = document.createElement('input');
|
||||
input.type = 'checkbox';
|
||||
|
||||
@@ -482,7 +482,7 @@ function renderPackage() {
|
||||
const ok = !pkg.error;
|
||||
refs.summary.classList.toggle('is-error', !ok);
|
||||
if (ok && pkg.speakers.length > 1) {
|
||||
refs.summary.textContent = t('scriptDirectorPackageSummaryCast', { count: pkg.lineCount, speakers: pkg.speakers.join('、') });
|
||||
refs.summary.textContent = t('scriptDirectorPackageSummaryCast', { count: pkg.lineCount, speakers: pkg.speakers.join(t('listSeparator')) });
|
||||
} else if (ok) {
|
||||
const used = [...new Set(state.lines.filter(line => line.text.trim()).map(line => emotionLabel(line.emotion)))];
|
||||
refs.summary.textContent = t('scriptDirectorPackageSummary', { count: pkg.lineCount, emotions: used.join(' · ') });
|
||||
|
||||
@@ -30,7 +30,7 @@ export const PAGE_ICONS = {
|
||||
export const RAIL_PAGES = Object.freeze([
|
||||
{ page: 'home', id: 'anomalous-home-btn', labelKey: 'shellHome' },
|
||||
{ page: 'activity', id: 'anomalous-activity-btn', labelKey: 'shellActivity' },
|
||||
{ page: 'ai', id: 'anomalous-ai-btn', labelKey: 'shellAi' }, // the AI workbench (ui_ai_workbench.js)
|
||||
{ page: 'ai', id: 'anomalous-ai-btn', labelKey: 'shellAi', railKey: 'shellAiRail' }, // the AI workbench (ui_ai_workbench.js)
|
||||
{ page: 'models', id: 'anomalous-models-btn', labelKey: 'models' },
|
||||
{ page: 'gallery', id: 'anomalous-gallery-btn', labelKey: 'gallery' },
|
||||
{ page: 'recipes', id: 'anomalous-notebook-btn', labelKey: 'recipeTitle' },
|
||||
@@ -84,7 +84,7 @@ export function createShellRail(owner) {
|
||||
RAIL_PAGES.forEach((entry, index) => {
|
||||
const button = items.get(entry.page);
|
||||
const text = t(entry.labelKey);
|
||||
button.querySelector('.anomalous-rail-label').textContent = text;
|
||||
button.querySelector('.anomalous-rail-label').textContent = t(entry.railKey || entry.labelKey);
|
||||
button.setAttribute('aria-label', text);
|
||||
// Only the first nine have a number key.
|
||||
button.dataset.tooltip = index < 9 ? t('shellRailKey', { name: text, key: index + 1 }) : text;
|
||||
|
||||
@@ -354,7 +354,7 @@ export function renderDraftCard(draft, view, ctx, { solo = false } = {}) {
|
||||
.filter(item => !draft.target || needs.includes(item.id));
|
||||
if (missing.length) {
|
||||
body.append(el('div', 'anomalous-tts-card-note', t('ttsImportPretrainedNote', {
|
||||
files: missing.map(item => item.label).join('、'),
|
||||
files: missing.map(item => item.label).join(t('listSeparator')),
|
||||
size: formatSize(missing.reduce((sum, item) => sum + (item.size || 0), 0)),
|
||||
})));
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ export const UPLOAD_WARN_FILES = 1500;
|
||||
/** `a、b、c…`: the first few names of a list, in name order. */
|
||||
function few(names) {
|
||||
const sorted = [...names].sort((a, b) => a.localeCompare(b));
|
||||
return sorted.slice(0, 3).join('、') + (sorted.length > 3 ? '…' : '');
|
||||
return sorted.slice(0, 3).join(t('listSeparator')) + (sorted.length > 3 ? '…' : '');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -120,7 +120,7 @@ export function renderTtsPresets(status, groups, local) {
|
||||
: t('ttsPresetsPair', { ref: t(`scriptRunLang_${use.split('>')[0]}`), lang: t(`scriptRunLang_${use.split('>')[1]}`) }))),
|
||||
...uses.characters,
|
||||
];
|
||||
const message = t('ttsPresetDeleteAsk', { name: label(name) }) + (where.length ? `\n${t('ttsPresetDeleteUses', { list: where.join('、') })}` : '');
|
||||
const message = t('ttsPresetDeleteAsk', { name: label(name) }) + (where.length ? `\n${t('ttsPresetDeleteUses', { list: where.join(t('listSeparator')) })}` : '');
|
||||
if (!await anomalousConfirm(message, t('ttsPresetsTitle'), { okLabel: t('ttsPresetDelete') })) return;
|
||||
change(() => {
|
||||
removePreset(state, name);
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
--amb-border-strong: rgba(255, 255, 255, 0.16); /* controls and dividers that must show at rest */
|
||||
--amb-border-hover: rgba(255, 255, 255, 0.16);
|
||||
--amb-link: #a5b4fc; /* the one accent for links, selection and focus; tints via color-mix */
|
||||
--amb-on-link: #15171c;
|
||||
--amb-btn-primary-bg: #e5e7eb;
|
||||
--amb-btn-primary-hover: #ffffff;
|
||||
--amb-btn-primary-text: #111827;
|
||||
@@ -87,6 +88,7 @@ html.amb-theme-light {
|
||||
--amb-border-strong: rgba(0, 0, 0, 0.16);
|
||||
--amb-border-hover: rgba(0, 0, 0, 0.22);
|
||||
--amb-link: #4f46e5;
|
||||
--amb-on-link: #ffffff;
|
||||
--amb-btn-primary-bg: #1f2937;
|
||||
--amb-btn-primary-hover: #111827;
|
||||
--amb-btn-primary-text: #ffffff;
|
||||
@@ -154,6 +156,7 @@ html.amb-theme-light :is(.anomalous-workbench-overlay, .anomalous-gallery-viewer
|
||||
--amb-border-strong: rgba(255, 255, 255, 0.16);
|
||||
--amb-border-hover: rgba(255, 255, 255, 0.16);
|
||||
--amb-link: #a5b4fc;
|
||||
--amb-on-link: #15171c;
|
||||
--amb-btn-primary-bg: #e5e7eb;
|
||||
--amb-btn-primary-hover: #ffffff;
|
||||
--amb-btn-primary-text: #111827;
|
||||
@@ -239,6 +242,7 @@ html.theme-abyssal-scarlet,
|
||||
--amb-border-strong: rgba(255, 235, 240, 0.16);
|
||||
--amb-border-hover: rgba(220, 20, 60, 0.35);
|
||||
--amb-link: #F28CA0;
|
||||
--amb-on-link: #2a0c14;
|
||||
--amb-btn-primary-bg: #87384E;
|
||||
--amb-btn-primary-hover: #9c425b;
|
||||
--amb-btn-primary-text: #FFF5F7;
|
||||
@@ -478,6 +482,7 @@ html:not(.anomalous-floating-entry-enabled) [data-setting-id="Anomalous.ModelBro
|
||||
#anomalous-container {
|
||||
width: 90%;
|
||||
height: 90%;
|
||||
color: var(--amb-text-main);
|
||||
background-color: var(--amb-bg-page, var(--amb-bg-page));
|
||||
border: 1px solid var(--amb-border);
|
||||
border-radius: 8px;
|
||||
|
||||
@@ -134,7 +134,7 @@
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
width: min(360px, 100%);
|
||||
min-width: 120px;
|
||||
min-width: 0;
|
||||
padding: 0 10px;
|
||||
border: 1px solid var(--amb-border-strong);
|
||||
border-radius: 999px;
|
||||
|
||||
@@ -606,8 +606,10 @@ button.anomalous-scan-stat:hover {
|
||||
.anomalous-scan-segment {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
flex-shrink: 0;
|
||||
flex-shrink: 1;
|
||||
align-self: flex-start;
|
||||
box-sizing: border-box;
|
||||
max-width: 100%;
|
||||
gap: 2px;
|
||||
padding: 3px;
|
||||
border: 1px solid var(--amb-border);
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
.anomalous-node-section-head h3 {
|
||||
margin: 0;
|
||||
color: #8b91a3;
|
||||
color: var(--amb-text-muted);
|
||||
font-size: 10px;
|
||||
font-weight: 750;
|
||||
letter-spacing: 0.1em;
|
||||
@@ -392,7 +392,7 @@ button.anomalous-node-param-source:hover { background: color-mix(in srgb, var(--
|
||||
|
||||
.anomalous-node-muted {
|
||||
margin: 0;
|
||||
color: #8b91a3;
|
||||
color: var(--amb-text-muted);
|
||||
font-size: 11px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
@@ -127,6 +127,7 @@ html.amb-theme-light .anomalous-recipe-detail-view { --wfd-orange: #ea580c; }
|
||||
top: -16px;
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-end;
|
||||
gap: 10px;
|
||||
margin-top: 4px;
|
||||
@@ -137,7 +138,7 @@ html.amb-theme-light .anomalous-recipe-detail-view { --wfd-orange: #ea580c; }
|
||||
|
||||
.anomalous-wfd-tabs {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex: 1 1 240px;
|
||||
align-items: flex-end;
|
||||
gap: 2px;
|
||||
min-width: 0;
|
||||
@@ -806,5 +807,5 @@ html.amb-theme-light .anomalous-recipe-detail-view { --wfd-orange: #ea580c; }
|
||||
.anomalous-example-title { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; color: var(--amb-text-main); font-size: 13px; font-weight: 650; }
|
||||
.anomalous-example-badge { padding: 0 6px; border-radius: 6px; background: color-mix(in srgb, var(--amb-link) 18%, transparent); color: var(--amb-link); font-size: 11px; font-weight: 500; }
|
||||
.anomalous-example-about { margin: 3px 0 4px; color: var(--amb-text-soft); font-size: 12.5px; line-height: 1.6; }
|
||||
.anomalous-example-open { flex: none; height: 32px; padding: 0 12px; border: 0; border-radius: 8px; background: var(--amb-link); color: #fff; font: inherit; font-size: 12.5px; font-weight: 600; cursor: pointer; }
|
||||
.anomalous-example-open { flex: none; height: 32px; padding: 0 12px; border: 0; border-radius: 8px; background: var(--amb-link); color: var(--amb-on-link); font: inherit; font-size: 12.5px; font-weight: 600; cursor: pointer; }
|
||||
.anomalous-example-open:hover { filter: brightness(1.15); }
|
||||
|
||||
@@ -389,7 +389,7 @@
|
||||
padding: 0 7px;
|
||||
border-radius: 999px;
|
||||
background: var(--amb-link);
|
||||
color: #fff;
|
||||
color: var(--amb-on-link);
|
||||
font-size: 10.5px;
|
||||
font-weight: 700;
|
||||
line-height: 17px;
|
||||
|
||||
@@ -555,7 +555,7 @@
|
||||
border: 0;
|
||||
border-radius: 9px;
|
||||
background: var(--amb-link);
|
||||
color: #fff;
|
||||
color: var(--amb-on-link);
|
||||
font: inherit;
|
||||
font-size: 12.5px;
|
||||
font-weight: 600;
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
.anomalous-ai-tick.is-on {
|
||||
border-color: var(--amb-link);
|
||||
background: var(--amb-link);
|
||||
color: #fff;
|
||||
color: var(--amb-on-link);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
border: 0;
|
||||
border-radius: 999px;
|
||||
background: var(--amb-link);
|
||||
color: #fff;
|
||||
color: var(--amb-on-link);
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -343,7 +343,7 @@
|
||||
border: 0;
|
||||
border-radius: 8px;
|
||||
background: var(--amb-link);
|
||||
color: #fff;
|
||||
color: var(--amb-on-link);
|
||||
font: inherit;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
|
||||
@@ -167,7 +167,7 @@
|
||||
transition: opacity 0.15s, transform 0.15s, background 0.15s;
|
||||
}
|
||||
.anomalous-tb-card:hover .anomalous-tb-check { opacity: 1; }
|
||||
.anomalous-tb-card.is-picked .anomalous-tb-check { border-color: var(--amb-link); background: var(--amb-link); color: #fff; opacity: 1; transform: scale(1); }
|
||||
.anomalous-tb-card.is-picked .anomalous-tb-check { border-color: var(--amb-link); background: var(--amb-link); color: var(--amb-on-link); opacity: 1; transform: scale(1); }
|
||||
.anomalous-tb-star {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
@@ -292,7 +292,7 @@
|
||||
font-size: 12.5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.anomalous-tb-take { border-color: transparent; background: var(--amb-link); color: #fff; }
|
||||
.anomalous-tb-take { border-color: transparent; background: var(--amb-link); color: var(--amb-on-link); }
|
||||
.anomalous-tb-take.is-on { border-color: var(--amb-link); background: transparent; color: var(--amb-link); }
|
||||
.anomalous-tb-like:hover { background: rgba(var(--amb-ink-rgb), 0.06); color: var(--amb-text-main); }
|
||||
.anomalous-tb-like.is-on { color: var(--amb-text-main); }
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
padding: 0 5px;
|
||||
border-radius: 999px;
|
||||
background: var(--amb-link);
|
||||
color: var(--amb-btn-primary-text, #fff);
|
||||
color: var(--amb-on-link);
|
||||
font-size: 10.5px;
|
||||
font-weight: 700;
|
||||
line-height: 16px;
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
box-sizing: border-box;
|
||||
border-radius: 9px;
|
||||
background: var(--amb-link);
|
||||
color: #fff;
|
||||
color: var(--amb-on-link);
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
line-height: 18px;
|
||||
@@ -215,7 +215,7 @@
|
||||
border-radius: 50%;
|
||||
background: var(--amb-link);
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.45);
|
||||
color: #fff;
|
||||
color: var(--amb-on-link);
|
||||
}
|
||||
.anomalous-ai-pics-tile.is-picked .anomalous-ai-pics-mark { display: flex; }
|
||||
.anomalous-ai-pics-none { grid-column: 1 / -1; padding: 18px 6px; color: var(--amb-text-soft); font-size: 12.5px; text-align: center; }
|
||||
@@ -260,7 +260,7 @@
|
||||
box-sizing: border-box;
|
||||
border-radius: 9px;
|
||||
background: var(--amb-link);
|
||||
color: #fff;
|
||||
color: var(--amb-on-link);
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
font-variant-numeric: tabular-nums;
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
.anomalous-ai-task-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
max-width: 320px;
|
||||
border: 1px solid color-mix(in srgb, var(--amb-link) 40%, transparent);
|
||||
border-radius: 999px;
|
||||
@@ -90,10 +91,10 @@
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
.anomalous-ai-task-link.is-next { border: 1px solid color-mix(in srgb, var(--amb-link) 40%, transparent); font-size: 12px; } /* they are the chips: not the header's size */
|
||||
.anomalous-ai-task-link.is-next { border: 1px solid color-mix(in srgb, var(--amb-link) 40%, transparent); color: var(--amb-link); font-size: 12px; } /* they are the chips: not the header's size */
|
||||
.anomalous-ai-task-link span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.anomalous-ai-task-link-go:hover span, .anomalous-ai-task-link.is-next:hover span { text-decoration: underline; }
|
||||
.anomalous-ai-task-link-x { display: inline-flex; margin-right: 4px; padding: 3px; border: 0; border-radius: 50%; background: none; color: inherit; cursor: pointer; }
|
||||
.anomalous-ai-task-link-x { display: inline-flex; flex: none; margin-right: 4px; padding: 3px; border: 0; border-radius: 50%; background: none; color: inherit; cursor: pointer; }
|
||||
.anomalous-ai-task-link-x:hover { background: color-mix(in srgb, var(--amb-link) 18%, transparent); }
|
||||
.anomalous-ai-task-links-menu {
|
||||
position: fixed;
|
||||
|
||||
Reference in New Issue
Block a user