Files
ChatAIBot/static/js/utils.js
T
2026-05-29 08:52:33 +03:00

108 lines
3.6 KiB
JavaScript

export function parseImagePromptFromContent(content) {
if (!content || !content.includes('[IMAGE_PROMPT:')) return { text: content, prompt: null };
const match = content.match(/\[IMAGE_PROMPT:(.*?)\]/s);
const prompt = match ? match[1].trim() : null;
const text = content.replace(/\[IMAGE_PROMPT:.*?\]/gs, '').trim();
return { text, prompt };
}
export async function copyToClipboard(text) {
try {
await navigator.clipboard.writeText(text);
return true;
} catch {
return false;
}
}
export const GENRE_LABELS = {
adventure: 'Приключение',
horror: 'Хоррор',
romance: 'Романтика',
slice_of_life: 'Повседневность',
fantasy: 'Фэнтези',
sci_fi: 'Sci-Fi',
};
export function initWizard(modalEl, { totalSteps, onStepChange, validateStep }) {
let step = 1;
const pages = modalEl.querySelectorAll('.wizard-page');
const dots = modalEl.querySelectorAll('.wizard-step-dot');
const prevBtn = modalEl.querySelector('[id$="Prev"]');
const nextBtn = modalEl.querySelector('[id$="Next"]');
const saveBtn = modalEl.querySelector('[id$="Save"], [id$="Confirm"], [id$="Create"]');
function render() {
pages.forEach(p => p.classList.toggle('active', Number(p.dataset.step) === step));
dots.forEach(d => {
const n = Number(d.dataset.step);
d.classList.toggle('active', n === step);
d.classList.toggle('done', n < step);
});
prevBtn?.classList.toggle('hidden', step <= 1);
nextBtn?.classList.toggle('hidden', step >= totalSteps);
saveBtn?.classList.toggle('hidden', step < totalSteps);
onStepChange?.(step);
}
function goTo(next) {
if (next > step && validateStep && !validateStep(step)) return;
step = Math.max(1, Math.min(totalSteps, next));
render();
}
prevBtn?.addEventListener('click', () => goTo(step - 1));
nextBtn?.addEventListener('click', () => goTo(step + 1));
render();
return {
reset() { step = 1; render(); },
getStep: () => step,
goTo,
render,
};
}
export function bindGenreGrid(gridEl, selectedSet, onChange) {
gridEl.addEventListener('click', (e) => {
const btn = e.target.closest('.genre-btn');
if (!btn) return;
const genre = btn.dataset.genre;
if (selectedSet.has(genre)) {
selectedSet.delete(genre);
btn.classList.remove('selected');
} else {
selectedSet.add(genre);
btn.classList.add('selected');
}
onChange?.();
});
}
export function resetGenreGrid(gridEl, selectedSet) {
selectedSet.clear();
gridEl.querySelectorAll('.genre-btn').forEach(b => b.classList.remove('selected'));
}
export function getRpgSettingsFromDom(prefix = '') {
const id = (name) => document.getElementById(prefix + name);
return {
dice: id('settingDice')?.checked ?? true,
narrator: id('settingNarrator')?.checked ?? true,
quests: id('settingQuests')?.checked ?? true,
affinity: id('settingAffinity')?.checked ?? true,
choices: id('settingChoices')?.checked ?? true,
};
}
export function formatSessionDate(iso) {
if (!iso) return '';
const d = new Date(iso.includes('T') ? iso : iso.replace(' ', 'T') + 'Z');
if (Number.isNaN(d.getTime())) return '';
const now = new Date();
const sameDay = d.toDateString() === now.toDateString();
if (sameDay) return d.toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit' });
return d.toLocaleDateString('ru-RU', { day: 'numeric', month: 'short' });
}