This commit is contained in:
@@ -726,51 +726,73 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
document.addEventListener('pkt:open-consent', openConsentModal);
|
||||
|
||||
const readAvatarValue = (form, field) => {
|
||||
const checked = form.querySelector(`[data-avatar-field="${field}"]:checked`);
|
||||
const avatarStyleConfigs = {
|
||||
lorelei: {
|
||||
fields: ['eyesVariant', 'eyebrowsVariant', 'mouthVariant', 'glassesVariant', 'hairVariant', 'beardVariant', 'earringsVariant'],
|
||||
paramMap: {
|
||||
eyesVariant: 'eyesVariant',
|
||||
eyebrowsVariant: 'eyebrowsVariant',
|
||||
mouthVariant: 'mouthVariant',
|
||||
glassesVariant: 'glassesVariant',
|
||||
hairVariant: 'hairVariant',
|
||||
beardVariant: 'beardVariant',
|
||||
earringsVariant: 'earringsVariant',
|
||||
},
|
||||
optionalProbabilityMap: {
|
||||
glassesVariant: 'glassesProbability',
|
||||
beardVariant: 'beardProbability',
|
||||
earringsVariant: 'earringsProbability',
|
||||
},
|
||||
alwaysProbabilityMap: {
|
||||
hairVariant: 'hairProbability',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const getCurrentAvatarStyle = (form) => {
|
||||
const input = form.querySelector('[data-avatar-style-select]');
|
||||
const value = input?.value || '';
|
||||
if (value) return value;
|
||||
return form.querySelector('[data-avatar-style-panel]')?.getAttribute('data-avatar-style-panel') || 'lorelei';
|
||||
};
|
||||
|
||||
const getAvatarSeedInput = (form) => form.querySelector('[data-avatar-seed]');
|
||||
|
||||
const getAvatarStylePanel = (form, style) => form.querySelector(`[data-avatar-style-panel="${style}"]`);
|
||||
|
||||
const readAvatarValue = (form, style, field) => {
|
||||
const panel = getAvatarStylePanel(form, style);
|
||||
if (!panel) return '';
|
||||
const checked = panel.querySelector(`[data-avatar-field="${field}"]:checked`);
|
||||
if (checked) return checked.value;
|
||||
const input = form.querySelector(`[data-avatar-field="${field}"]`);
|
||||
const input = panel.querySelector(`[data-avatar-field="${field}"]`);
|
||||
return input ? input.value : '';
|
||||
};
|
||||
|
||||
const avatarComponentFieldMap = {
|
||||
avatar_lorelei_eyes_variant: 'eyesVariant',
|
||||
avatar_lorelei_eyebrows_variant: 'eyebrowsVariant',
|
||||
avatar_lorelei_mouth_variant: 'mouthVariant',
|
||||
avatar_lorelei_glasses_variant: 'glassesVariant',
|
||||
avatar_lorelei_hair_variant: 'hairVariant',
|
||||
avatar_lorelei_beard_variant: 'beardVariant',
|
||||
avatar_lorelei_earrings_variant: 'earringsVariant',
|
||||
const getAvatarStyleConfig = (style) => {
|
||||
if (avatarStyleConfigs[style]) return avatarStyleConfigs[style];
|
||||
return avatarStyleConfigs.lorelei;
|
||||
};
|
||||
|
||||
const avatarComponentFields = Object.keys(avatarComponentFieldMap);
|
||||
const avatarEndpoint = '/api/avatar.php';
|
||||
const avatarOptionalProbabilityMap = {
|
||||
avatar_lorelei_glasses_variant: 'glassesProbability',
|
||||
avatar_lorelei_beard_variant: 'beardProbability',
|
||||
avatar_lorelei_earrings_variant: 'earringsProbability',
|
||||
};
|
||||
|
||||
const buildAvatarParams = (form, overrides = {}) => {
|
||||
const seed = overrides.avatar_preset || readAvatarValue(form, 'avatar_preset');
|
||||
const buildAvatarParams = (form, style = getCurrentAvatarStyle(form), overrides = {}) => {
|
||||
const styleConfig = getAvatarStyleConfig(style);
|
||||
const seed = overrides.avatar_seed || getAvatarSeedInput(form)?.value || '';
|
||||
if (!seed) return null;
|
||||
|
||||
const params = new URLSearchParams({ seed });
|
||||
const hairValue = Object.prototype.hasOwnProperty.call(overrides, 'avatar_lorelei_hair_variant')
|
||||
? overrides.avatar_lorelei_hair_variant
|
||||
: readAvatarValue(form, 'avatar_lorelei_hair_variant');
|
||||
params.set('hairProbability', '100');
|
||||
if (hairValue) {
|
||||
params.set('hairVariant', hairValue);
|
||||
}
|
||||
|
||||
avatarComponentFields.forEach((field) => {
|
||||
if (field === 'avatar_lorelei_hair_variant') return;
|
||||
const params = new URLSearchParams({ style, seed });
|
||||
styleConfig.fields.forEach((field) => {
|
||||
const value = Object.prototype.hasOwnProperty.call(overrides, field)
|
||||
? overrides[field]
|
||||
: readAvatarValue(form, field);
|
||||
const param = avatarComponentFieldMap[field];
|
||||
const probabilityParam = avatarOptionalProbabilityMap[field];
|
||||
: readAvatarValue(form, style, field);
|
||||
const param = styleConfig.paramMap[field];
|
||||
const probabilityParam = styleConfig.optionalProbabilityMap[field];
|
||||
const alwaysProbabilityParam = styleConfig.alwaysProbabilityMap[field];
|
||||
|
||||
if (alwaysProbabilityParam) {
|
||||
params.set(alwaysProbabilityParam, value ? '100' : '0');
|
||||
}
|
||||
|
||||
if (probabilityParam) {
|
||||
params.set(probabilityParam, value ? '100' : '0');
|
||||
@@ -788,7 +810,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const image = preview.querySelector('.pkt-avatar__img');
|
||||
if (!image) return;
|
||||
|
||||
const params = buildAvatarParams(form);
|
||||
const style = getCurrentAvatarStyle(form);
|
||||
const params = buildAvatarParams(form, style);
|
||||
if (!params) return;
|
||||
|
||||
const url = `${avatarEndpoint}?${params.toString()}`;
|
||||
@@ -796,20 +819,24 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
image.src = url;
|
||||
};
|
||||
|
||||
const getActiveAvatarField = (form) => {
|
||||
const activeTab = form.querySelector('[data-avatar-component-tab].is-active');
|
||||
return activeTab?.getAttribute('data-avatar-component-tab') || 'avatar_lorelei_eyes_variant';
|
||||
const getActiveAvatarField = (form, style) => {
|
||||
const panel = getAvatarStylePanel(form, style);
|
||||
if (!panel) return '';
|
||||
const activeTab = panel.querySelector('[data-avatar-component-tab].is-active');
|
||||
return activeTab?.getAttribute('data-avatar-component-tab') || panel.querySelector('[data-avatar-component-tab]')?.getAttribute('data-avatar-component-tab') || '';
|
||||
};
|
||||
|
||||
const updateAvatarOptionPreviews = (form, activeField = null) => {
|
||||
const updateAvatarOptionPreviews = (form, style, activeField = null) => {
|
||||
const panel = getAvatarStylePanel(form, style);
|
||||
if (!panel) return;
|
||||
const selector = activeField
|
||||
? `[data-avatar-component-panel="${activeField}"] [data-avatar-option-thumb]`
|
||||
: '[data-avatar-option-thumb]';
|
||||
|
||||
form.querySelectorAll(selector).forEach((image) => {
|
||||
panel.querySelectorAll(selector).forEach((image) => {
|
||||
const field = image.getAttribute('data-avatar-option-field') || '';
|
||||
const value = image.getAttribute('data-avatar-option-value') || '';
|
||||
const params = buildAvatarParams(form, { [field]: value });
|
||||
const params = buildAvatarParams(form, style, { [field]: value });
|
||||
if (!params) return;
|
||||
|
||||
const src = `${avatarEndpoint}?${params.toString()}`;
|
||||
@@ -819,52 +846,83 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
};
|
||||
|
||||
const ensureAvatarBuilderLoaded = (form) => {
|
||||
if (form.dataset.avatarInitialized === 'true') return;
|
||||
form.dataset.avatarInitialized = 'true';
|
||||
const ensureAvatarBuilderLoaded = (form, style = getCurrentAvatarStyle(form)) => {
|
||||
const loadedStyles = new Set((form.dataset.avatarInitializedStyles || '').split(',').filter(Boolean));
|
||||
if (loadedStyles.has(style)) return;
|
||||
loadedStyles.add(style);
|
||||
form.dataset.avatarInitializedStyles = Array.from(loadedStyles).join(',');
|
||||
updateAvatarPreview(form);
|
||||
updateAvatarOptionPreviews(form, getActiveAvatarField(form));
|
||||
updateAvatarOptionPreviews(form, style, getActiveAvatarField(form, style));
|
||||
};
|
||||
|
||||
document.querySelectorAll('[data-avatar-builder]').forEach((form) => {
|
||||
form.querySelectorAll('[data-avatar-field]').forEach((field) => {
|
||||
field.addEventListener('change', () => {
|
||||
ensureAvatarBuilderLoaded(form);
|
||||
const style = field.getAttribute('data-avatar-style') || getCurrentAvatarStyle(form);
|
||||
ensureAvatarBuilderLoaded(form, style);
|
||||
updateAvatarPreview(form);
|
||||
updateAvatarOptionPreviews(form, getActiveAvatarField(form));
|
||||
updateAvatarOptionPreviews(form, style, getActiveAvatarField(form, style));
|
||||
});
|
||||
field.addEventListener('input', () => {
|
||||
ensureAvatarBuilderLoaded(form);
|
||||
const style = field.getAttribute('data-avatar-style') || getCurrentAvatarStyle(form);
|
||||
ensureAvatarBuilderLoaded(form, style);
|
||||
updateAvatarPreview(form);
|
||||
updateAvatarOptionPreviews(form, getActiveAvatarField(form));
|
||||
updateAvatarOptionPreviews(form, style, getActiveAvatarField(form, style));
|
||||
});
|
||||
});
|
||||
|
||||
const setActiveComponentPanel = (field) => {
|
||||
form.querySelectorAll('[data-avatar-component-tab]').forEach((button) => {
|
||||
const setActiveComponentPanel = (style, field) => {
|
||||
const panel = getAvatarStylePanel(form, style);
|
||||
if (!panel) return;
|
||||
panel.querySelectorAll('[data-avatar-component-tab]').forEach((button) => {
|
||||
const active = button.getAttribute('data-avatar-component-tab') === field;
|
||||
button.classList.toggle('is-active', active);
|
||||
button.setAttribute('aria-selected', active ? 'true' : 'false');
|
||||
});
|
||||
form.querySelectorAll('[data-avatar-component-panel]').forEach((panel) => {
|
||||
panel.classList.toggle('is-active', panel.getAttribute('data-avatar-component-panel') === field);
|
||||
panel.querySelectorAll('[data-avatar-component-panel]').forEach((componentPanel) => {
|
||||
componentPanel.classList.toggle('is-active', componentPanel.getAttribute('data-avatar-component-panel') === field);
|
||||
});
|
||||
updateAvatarOptionPreviews(form, field);
|
||||
updateAvatarOptionPreviews(form, style, field);
|
||||
};
|
||||
|
||||
const setActiveStyle = (style) => {
|
||||
form.querySelectorAll('[data-avatar-style-panel]').forEach((panel) => {
|
||||
const active = panel.getAttribute('data-avatar-style-panel') === style;
|
||||
panel.hidden = !active;
|
||||
panel.classList.toggle('is-active', active);
|
||||
panel.querySelectorAll('[data-avatar-field]').forEach((input) => {
|
||||
input.disabled = !active;
|
||||
});
|
||||
});
|
||||
ensureAvatarBuilderLoaded(form, style);
|
||||
setActiveComponentPanel(style, getActiveAvatarField(form, style));
|
||||
updateAvatarPreview(form);
|
||||
};
|
||||
|
||||
form.querySelector('[data-avatar-style-select]')?.addEventListener('change', (event) => {
|
||||
const nextStyle = event.currentTarget?.value || getCurrentAvatarStyle(form);
|
||||
setActiveStyle(nextStyle);
|
||||
});
|
||||
|
||||
form.querySelectorAll('[data-avatar-component-tab]').forEach((button) => {
|
||||
button.addEventListener('click', () => {
|
||||
const style = button.getAttribute('data-avatar-style') || getCurrentAvatarStyle(form);
|
||||
const field = button.getAttribute('data-avatar-component-tab');
|
||||
if (field) {
|
||||
ensureAvatarBuilderLoaded(form);
|
||||
setActiveComponentPanel(field);
|
||||
ensureAvatarBuilderLoaded(form, style);
|
||||
setActiveComponentPanel(style, field);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
avatarComponentFields.forEach((field) => {
|
||||
form.querySelectorAll(`[data-avatar-field="${field}"]`).forEach((input) => {
|
||||
input.addEventListener('change', () => setActiveComponentPanel(field));
|
||||
Object.values(avatarStyleConfigs).forEach((styleConfig) => {
|
||||
styleConfig.fields.forEach((fieldName) => {
|
||||
form.querySelectorAll(`[data-avatar-field="${fieldName}"]`).forEach((input) => {
|
||||
input.addEventListener('change', () => {
|
||||
const style = input.getAttribute('data-avatar-style') || getCurrentAvatarStyle(form);
|
||||
setActiveComponentPanel(style, fieldName);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -891,29 +949,36 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
};
|
||||
|
||||
form.querySelector('[data-avatar-random]')?.addEventListener('click', () => {
|
||||
const seedField = form.querySelector('[data-avatar-field="avatar_preset"]');
|
||||
const style = getCurrentAvatarStyle(form);
|
||||
const styleConfig = getAvatarStyleConfig(style);
|
||||
const seedField = getAvatarSeedInput(form);
|
||||
if (!(seedField instanceof HTMLInputElement)) return;
|
||||
seedField.value = buildSeed();
|
||||
|
||||
avatarComponentFields.forEach((field) => {
|
||||
const options = Array.from(form.querySelectorAll(`[data-avatar-field="${field}"]`));
|
||||
styleConfig.fields.forEach((field) => {
|
||||
const panel = getAvatarStylePanel(form, style);
|
||||
if (!panel) return;
|
||||
const options = Array.from(panel.querySelectorAll(`[data-avatar-field="${field}"]`));
|
||||
if (!options.length) return;
|
||||
const randomOption = options[Math.floor(Math.random() * options.length)];
|
||||
if (!(randomOption instanceof HTMLInputElement)) return;
|
||||
randomOption.checked = true;
|
||||
});
|
||||
|
||||
ensureAvatarBuilderLoaded(form);
|
||||
ensureAvatarBuilderLoaded(form, style);
|
||||
updateAvatarPreview(form);
|
||||
updateAvatarOptionPreviews(form, getActiveAvatarField(form));
|
||||
updateAvatarOptionPreviews(form, style, getActiveAvatarField(form, style));
|
||||
});
|
||||
|
||||
setActiveStyle(getCurrentAvatarStyle(form));
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-modal-open="modalAvatar"]').forEach((button) => {
|
||||
button.addEventListener('click', () => {
|
||||
const form = document.querySelector('#modalAvatar [data-avatar-builder]');
|
||||
if (!form) return;
|
||||
window.setTimeout(() => ensureAvatarBuilderLoaded(form), 20);
|
||||
const style = getCurrentAvatarStyle(form);
|
||||
window.setTimeout(() => ensureAvatarBuilderLoaded(form, style), 20);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user