Конструктор — T123 версия /* ========== СТИЛИ ДЛЯ ШАБЛОНА №19 - ГИБКИЙ КОНТЕЙНЕР ========== */ .special-flex-19 { position: relative; width: 100%; height: 100%; background: #ffffff; overflow: hidden; } .special-flex-19 .flex19-photo-wrapper { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); width: 50%; height: 40%; min-width: 80px; min-height: 80px; max-width: 85%; max-height: 65%; transition: all 0.2s ease; z-index: 5; } .special-flex-19 .flex19-photo-area { position: relative; width: 100%; height: 100%; background: #e8e0d4; overflow: hidden; cursor: pointer; border-radius: 16px; box-shadow: inset 0 0 0 1px rgba(124,95,58,0.2); transition: box-shadow 0.2s; } .special-flex-19 .flex19-photo-area:hover { box-shadow: inset 0 0 0 2px #b5926a; } .special-flex-19 .photo-transform-container { position: relative; width: 100%; height: 100%; overflow: hidden; display: flex; align-items: center; justify-content: center; border-radius: 16px; } .special-flex-19 .photo-transform-container img { max-width: 100%; max-height: 100%; width: auto; height: auto; object-fit: contain; pointer-events: none; transform-origin: center center; } .special-flex-19 .photo-placeholder { width: 100%; height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; background: #fafafc; color: #b5926a; gap: 8px; cursor: pointer; border-radius: 16px; } .special-flex-19 .photo-placeholder svg { width: 32px; height: 32px; stroke: #b5926a; stroke-width: 1.5; fill: none; } .special-flex-19 .photo-placeholder span { font-size: 9px; font-family: 'Inter', sans-serif; } .special-flex-19 .flex19-size-controls { position: absolute; bottom: -35px; left: 50%; transform: translateX(-50%); display: flex; gap: 6px; background: rgba(0,0,0,0.85); backdrop-filter: blur(8px); padding: 6px 10px; border-radius: 30px; z-index: 30; opacity: 0; transition: opacity 0.2s; pointer-events: none; border: 1px solid rgba(255,255,255,0.2); white-space: nowrap; } .special-flex-19 .flex19-photo-wrapper:hover .flex19-size-controls { opacity: 1; pointer-events: auto; } .special-flex-19 .flex19-size-controls button { background: rgba(255,255,255,0.2); border: none; width: 28px; height: 28px; border-radius: 25px; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; color: white; transition: all 0.2s; font-size: 12px; } .special-flex-19 .flex19-size-controls button:hover { background: #4caf50; transform: scale(1.05); } .special-flex-19 .size-separator { width: 1px; height: 20px; background: rgba(255,255,255,0.3); margin: 0 4px; } .special-flex-19 .flex19-slider-item { display: flex; align-items: center; gap: 5px; color: white; font-size: 9px; font-family: 'Inter', sans-serif; } .special-flex-19 .flex19-slider-item input { width: 70px; height: 3px; -webkit-appearance: none; background: rgba(255,255,255,0.3); border-radius: 3px; outline: none; } .special-flex-19 .flex19-slider-item input::-webkit-slider-thumb { -webkit-appearance: none; width: 10px; height: 10px; border-radius: 50%; background: #4caf50; cursor: pointer; } .special-flex-19 .flex19-slider-item span { min-width: 30px; text-align: right; } .special-flex-19 .flex19-text-area { position: absolute; left: 50%; transform: translateX(-50%); text-align: center; font-family: 'Georgia', serif; font-size: 5.2px; line-height: 1.4; color: #607e9b; cursor: text; z-index: 10; max-width: 70%; white-space: nowrap; overflow-x: auto; background: transparent; padding: 2px 4px; border-radius: 4px; opacity: 0.5; } .special-flex-19 .flex19-text-area[contenteditable="true"]:focus { outline: none; background: rgba(96,126,155,0.1); } .special-flex-19 .image-controls { position: absolute; bottom: 10px; left: 50%; transform: translateX(-50%); display: flex; flex-wrap: wrap; gap: 4px; background: rgba(0,0,0,0.7); padding: 4px 8px; border-radius: 24px; backdrop-filter: blur(4px); z-index: 25; opacity: 0; transition: opacity 0.2s; pointer-events: none; } .special-flex-19 .flex19-photo-area:hover .image-controls { opacity: 1; pointer-events: auto; } .special-flex-19 .image-controls button { background: rgba(255,255,255,0.25); border: none; width: 24px; height: 24px; border-radius: 20px; cursor: pointer; font-size: 10px; transition: all 0.2s; color: white; } .special-flex-19 .image-controls button:hover { background: rgba(255,255,255,0.6); color: black; }
Очерки жизни
100%
Шаблоны T123
Страницы 0
Анимация
Создать книгу
Повторить как пользоваться

Дорогой друг

Рад приветствовать тебя в «Очерках жизни» — месте, где истории обретают форму, а память становится книгой.

Этот конструктор создан для тех, кто хочет запечатлеть важное: семейные хроники, портреты героев, воспоминания о путешествиях или благодарность близким.

Ты можешь:

  • добавлять фотографии и управлять ими (поворачивать, отражать, масштабировать);
  • редактировать текст — от заголовков до длинных заметок;
  • сохранять проект и экспортировать страницы в PDF;
  • отмечать любимые шаблоны звёздочкой;
  • включить фоновую музыку для вдохновения.

Всё просто: выбери шаблон, добавь фото и текст, меняй порядок страниц, смотри предпросмотр и сохраняй результат.

С уважением,
мастерская дизайна Evstafiadi

Выберите стиль книги

Классический
Скетч

Название книги

// ============================================================ // ========== ПАНЕЛЬ ТЕКСТА (БУКВА А) ========== // ============================================================ (function() { const panelText = document.getElementById('panelText'); const panelTextArrow = document.getElementById('panelTextArrow'); const fontSelect = document.getElementById('fontSelect'); const selectionInfo = document.getElementById('selectionInfo'); const fontSizeSlider = document.getElementById('fontSizeSlider'); const fontSizeValue = document.getElementById('fontSizeValue'); const letterSpacingSlider = document.getElementById('letterSpacingSlider'); const letterSpacingValue = document.getElementById('letterSpacingValue'); const boldBtn = document.getElementById('boldBtn'); const italicBtn = document.getElementById('italicBtn'); const normalBtn = document.getElementById('normalBtn'); const alignLeftBtn = document.getElementById('alignLeftBtn'); const alignCenterBtn = document.getElementById('alignCenterBtn'); const alignRightBtn = document.getElementById('alignRightBtn'); const alignJustifyBtn = document.getElementById('alignJustifyBtn'); const caseNormalBtn = document.getElementById('caseNormalBtn'); const caseUpperBtn = document.getElementById('caseUpperBtn'); const caseLowerBtn = document.getElementById('caseLowerBtn'); const textColorSwatch = document.getElementById('textColorSwatch'); const textColorPicker = document.getElementById('textColorPicker'); const textColorHex = document.getElementById('textColorHex'); const bgColorSwatch = document.getElementById('bgColorSwatch'); const bgColorPicker = document.getElementById('bgColorPicker'); const bgColorHex = document.getElementById('bgColorHex'); const resetTextStylesBtn = document.getElementById('resetTextStylesBtn'); const groups = { size: document.getElementById('groupSize'), letterSpacing: document.getElementById('groupLetterSpacing'), font: document.getElementById('groupFont'), style: document.getElementById('groupStyle'), align: document.getElementById('groupAlign'), case: document.getElementById('groupCase'), textColor: document.getElementById('groupTextColor'), bgColor: document.getElementById('groupBgColor') }; let hideTimeoutText = null; let savedRange = null; function isValidHex(hex) { return /^#[0-9A-Fa-f]{6}$/.test(hex); } function rgbToHex(r, g, b) { return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase(); } function getCurrentEditableElement() { const sel = window.getSelection(); if (!sel.isCollapsed && sel.rangeCount > 0) { let node = sel.getRangeAt(0).startContainer; if (node.nodeType === 3) node = node.parentElement; while (node && node !== document.body && !node.hasAttribute && !node.getAttribute) { node = node.parentElement; } if (node && node.closest && node.closest('.page-layout, .template-page, [contenteditable="true"]')) { return node; } } return null; } function saveSelection() { const sel = window.getSelection(); if (!sel.isCollapsed && sel.rangeCount > 0) { savedRange = sel.getRangeAt(0).cloneRange(); return true; } savedRange = null; return false; } function restoreSelection() { if (savedRange) { const sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(savedRange); } } function getStylesFromSelection() { if (!savedRange) return null; restoreSelection(); let node = savedRange.startContainer; if (node.nodeType === 3) node = node.parentElement; const f = window.getComputedStyle(node).fontFamily; const font = f ? f.split(',')[0].replace(/['"]/g, '').trim() : ''; const w = window.getComputedStyle(node).fontWeight; const bold = w === '700' || w === 'bold' || parseInt(w) >= 600; const italic = window.getComputedStyle(node).fontStyle === 'italic'; const a = window.getComputedStyle(node).textAlign; let align = 'left'; if (a === 'center') align = 'center'; else if (a === 'right') align = 'right'; else if (a === 'justify') align = 'justify'; const transform = window.getComputedStyle(node).textTransform; const fontSize = parseInt(window.getComputedStyle(node).fontSize); const ls = window.getComputedStyle(node).letterSpacing; const letterSpacing = ls === 'normal' ? 0 : parseFloat(ls); const color = window.getComputedStyle(node).color; let textColor = '#000000'; const colorMatch = color.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/); if (colorMatch) textColor = rgbToHex(parseInt(colorMatch[1]), parseInt(colorMatch[2]), parseInt(colorMatch[3])); const bgColorRaw = window.getComputedStyle(node).backgroundColor; let bgColor = 'transparent'; if (bgColorRaw !== 'rgba(0, 0, 0, 0)' && bgColorRaw !== 'transparent') { const bgMatch = bgColorRaw.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/); if (bgMatch) bgColor = rgbToHex(parseInt(bgMatch[1]), parseInt(bgMatch[2]), parseInt(bgMatch[3])); } return { font, bold, italic, align, transform, fontSize, letterSpacing, textColor, bgColor }; } function updateUI() { const styles = getStylesFromSelection(); if (!styles) { selectionInfo.innerHTML = 'Шрифт: —'; fontSelect.value = ''; fontSizeSlider.value = 14; fontSizeValue.textContent = '14px'; letterSpacingSlider.value = 0; letterSpacingValue.textContent = '0px'; boldBtn.classList.remove('active'); italicBtn.classList.remove('active'); normalBtn.classList.remove('active'); alignLeftBtn.classList.remove('active'); alignCenterBtn.classList.remove('active'); alignRightBtn.classList.remove('active'); alignJustifyBtn.classList.remove('active'); caseNormalBtn.classList.remove('active'); caseUpperBtn.classList.remove('active'); caseLowerBtn.classList.remove('active'); textColorSwatch.style.background = '#000000'; textColorHex.value = '#000000'; bgColorSwatch.style.background = 'transparent'; bgColorHex.value = 'transparent'; return; } selectionInfo.innerHTML = `Шрифт: ${styles.font}`; let fontValue = ''; if (styles.font === 'Georgia') fontValue = 'Georgia, serif'; else if (styles.font === 'Montserrat') fontValue = 'Montserrat, sans-serif'; else if (styles.font === 'Bebas Neue') fontValue = 'Bebas Neue, cursive'; else if (styles.font === 'Inter') fontValue = 'Inter, sans-serif'; fontSelect.value = fontValue; fontSizeSlider.value = styles.fontSize; fontSizeValue.textContent = styles.fontSize + 'px'; letterSpacingSlider.value = styles.letterSpacing; letterSpacingValue.textContent = styles.letterSpacing + 'px'; boldBtn.classList.remove('active'); italicBtn.classList.remove('active'); normalBtn.classList.remove('active'); if (styles.bold) boldBtn.classList.add('active'); if (styles.italic) italicBtn.classList.add('active'); if (!styles.bold && !styles.italic) normalBtn.classList.add('active'); alignLeftBtn.classList.remove('active'); alignCenterBtn.classList.remove('active'); alignRightBtn.classList.remove('active'); alignJustifyBtn.classList.remove('active'); if (styles.align === 'left') alignLeftBtn.classList.add('active'); else if (styles.align === 'center') alignCenterBtn.classList.add('active'); else if (styles.align === 'right') alignRightBtn.classList.add('active'); else if (styles.align === 'justify') alignJustifyBtn.classList.add('active'); caseNormalBtn.classList.remove('active'); caseUpperBtn.classList.remove('active'); caseLowerBtn.classList.remove('active'); if (styles.transform === 'none') caseNormalBtn.classList.add('active'); else if (styles.transform === 'uppercase') caseUpperBtn.classList.add('active'); else if (styles.transform === 'lowercase') caseLowerBtn.classList.add('active'); textColorSwatch.style.background = styles.textColor; textColorHex.value = styles.textColor; if (styles.bgColor === 'transparent') { bgColorSwatch.style.background = 'rgba(255,255,255,0.2)'; bgColorHex.value = 'transparent'; } else { bgColorSwatch.style.background = styles.bgColor; bgColorHex.value = styles.bgColor; } } function applyToSelection(styleName, value, preserveOtherStyles = true) { if (!savedRange) return; restoreSelection(); const sel = window.getSelection(); const range = sel.getRangeAt(0); const text = range.toString(); if (!text) return; range.deleteContents(); const span = document.createElement('span'); span.style[styleName] = value; if (preserveOtherStyles) { const styles = getStylesFromSelection(); if (styles) { if (styleName !== 'fontFamily') span.style.fontFamily = fontSelect.value || styles.font + ', serif'; if (styleName !== 'fontSize') span.style.fontSize = styles.fontSize + 'px'; if (styleName !== 'letterSpacing') span.style.letterSpacing = styles.letterSpacing + 'px'; if (styleName !== 'fontWeight') span.style.fontWeight = styles.bold ? 'bold' : 'normal'; if (styleName !== 'fontStyle') span.style.fontStyle = styles.italic ? 'italic' : 'normal'; if (styleName !== 'textAlign') span.style.textAlign = styles.align; if (styleName !== 'textTransform') span.style.textTransform = styles.transform; if (styleName !== 'color') span.style.color = styles.textColor; if (styleName !== 'backgroundColor') span.style.backgroundColor = styles.bgColor === 'transparent' ? 'transparent' : styles.bgColor; } } span.textContent = text; range.insertNode(span); sel.removeAllRanges(); const newRange = document.createRange(); newRange.selectNodeContents(span); sel.addRange(newRange); savedRange = newRange.cloneRange(); updateUI(); } function applyAlignmentToSelection(align) { if (!savedRange) return; restoreSelection(); const sel = window.getSelection(); const range = sel.getRangeAt(0); const text = range.toString(); if (!text) return; range.deleteContents(); const div = document.createElement('div'); div.style.textAlign = align; div.style.display = 'block'; const styles = getStylesFromSelection(); if (styles) { div.style.fontFamily = fontSelect.value || styles.font + ', serif'; div.style.fontSize = styles.fontSize + 'px'; div.style.letterSpacing = styles.letterSpacing + 'px'; div.style.fontWeight = styles.bold ? 'bold' : 'normal'; div.style.fontStyle = styles.italic ? 'italic' : 'normal'; div.style.textTransform = styles.transform; div.style.color = styles.textColor; div.style.backgroundColor = styles.bgColor === 'transparent' ? 'transparent' : styles.bgColor; } div.textContent = text; range.insertNode(div); sel.removeAllRanges(); const newRange = document.createRange(); newRange.selectNodeContents(div); sel.addRange(newRange); savedRange = newRange.cloneRange(); updateUI(); } function applyTextColorToSelection(color) { applyToSelection('color', color); } function applyBgColorToSelection(color) { applyToSelection('backgroundColor', color); } function toggleBold() { const styles = getStylesFromSelection(); if (styles && styles.bold) applyToSelection('fontWeight', 'normal'); else applyToSelection('fontWeight', 'bold'); } function toggleItalic() { const styles = getStylesFromSelection(); if (styles && styles.italic) applyToSelection('fontStyle', 'normal'); else applyToSelection('fontStyle', 'italic'); } function applyRegular() { applyToSelection('fontWeight', 'normal'); applyToSelection('fontStyle', 'normal'); } function applyCase(caseType) { if (caseType === 'normal') applyToSelection('textTransform', 'none'); else if (caseType === 'upper') applyToSelection('textTransform', 'uppercase'); else if (caseType === 'lower') applyToSelection('textTransform', 'lowercase'); } function showPanelText() { if (hideTimeoutText) clearTimeout(hideTimeoutText); panelText.classList.add('visible'); } function hidePanelText() { panelText.classList.remove('visible'); } function scheduleHideText() { if (hideTimeoutText) clearTimeout(hideTimeoutText); hideTimeoutText = setTimeout(() => hidePanelText(), 10000); } panelTextArrow.addEventListener('click', (e) => { e.stopPropagation(); if (window.hidePanelPhoto) window.hidePanelPhoto(); if (panelText.classList.contains('visible')) { hidePanelText(); if (hideTimeoutText) clearTimeout(hideTimeoutText); } else { showPanelText(); scheduleHideText(); } }); for (const [key, el] of Object.entries(groups)) { if (el && el.querySelector('h3')) { el.querySelector('h3').addEventListener('click', (e) => { e.stopPropagation(); for (const [k, group] of Object.entries(groups)) { if (group) { if (k === key) group.classList.add('active-group'); else group.classList.remove('active-group'); } } }); } } document.addEventListener('selectionchange', () => { const editable = getCurrentEditableElement(); if (editable) { setTimeout(() => { saveSelection(); updateUI(); showPanelText(); scheduleHideText(); }, 10); } }); if (fontSelect) fontSelect.addEventListener('change', () => applyToSelection('fontFamily', fontSelect.value)); if (fontSizeSlider) fontSizeSlider.addEventListener('input', () => { fontSizeValue.textContent = fontSizeSlider.value + 'px'; applyToSelection('fontSize', fontSizeSlider.value + 'px'); scheduleHideText(); }); if (letterSpacingSlider) letterSpacingSlider.addEventListener('input', () => { letterSpacingValue.textContent = letterSpacingSlider.value + 'px'; applyToSelection('letterSpacing', letterSpacingSlider.value + 'px'); scheduleHideText(); }); if (boldBtn) boldBtn.addEventListener('click', toggleBold); if (italicBtn) italicBtn.addEventListener('click', toggleItalic); if (normalBtn) normalBtn.addEventListener('click', applyRegular); if (alignLeftBtn) alignLeftBtn.addEventListener('click', () => applyAlignmentToSelection('left')); if (alignCenterBtn) alignCenterBtn.addEventListener('click', () => applyAlignmentToSelection('center')); if (alignRightBtn) alignRightBtn.addEventListener('click', () => applyAlignmentToSelection('right')); if (alignJustifyBtn) alignJustifyBtn.addEventListener('click', () => applyAlignmentToSelection('justify')); if (caseNormalBtn) caseNormalBtn.addEventListener('click', () => applyCase('normal')); if (caseUpperBtn) caseUpperBtn.addEventListener('click', () => applyCase('upper')); if (caseLowerBtn) caseLowerBtn.addEventListener('click', () => applyCase('lower')); if (textColorSwatch) textColorSwatch.addEventListener('mousedown', (e) => { e.preventDefault(); saveSelection(); textColorPicker.click(); }); if (textColorPicker) textColorPicker.addEventListener('input', (e) => { textColorHex.value = e.target.value.toUpperCase(); applyTextColorToSelection(e.target.value); scheduleHideText(); }); if (textColorHex) textColorHex.addEventListener('input', (e) => { let val = e.target.value; if (!val.startsWith('#')) val = '#' + val; if (isValidHex(val)) { textColorHex.value = val.toUpperCase(); applyTextColorToSelection(val.toUpperCase()); } }); if (bgColorSwatch) bgColorSwatch.addEventListener('mousedown', (e) => { e.preventDefault(); saveSelection(); bgColorPicker.click(); }); if (bgColorPicker) bgColorPicker.addEventListener('input', (e) => { bgColorHex.value = e.target.value.toUpperCase(); applyBgColorToSelection(e.target.value); scheduleHideText(); }); if (bgColorHex) bgColorHex.addEventListener('input', (e) => { let val = e.target.value; if (val === 'transparent') applyBgColorToSelection('transparent'); else { if (!val.startsWith('#')) val = '#' + val; if (isValidHex(val)) { bgColorHex.value = val.toUpperCase(); applyBgColorToSelection(val.toUpperCase()); } } }); if (resetTextStylesBtn) { resetTextStylesBtn.addEventListener('click', () => { if (savedRange) { const text = savedRange.toString(); if (text) { restoreSelection(); const sel = window.getSelection(); const range = sel.getRangeAt(0); range.deleteContents(); const textNode = document.createTextNode(text); range.insertNode(textNode); sel.removeAllRanges(); const newRange = document.createRange(); newRange.selectNodeContents(textNode); sel.addRange(newRange); savedRange = newRange.cloneRange(); updateUI(); } } scheduleHideText(); }); } hidePanelText(); })(); // ============================================================ // ========== ПАНЕЛЬ ФОТО (БУКВА И) ========== // ============================================================ (function() { const panelPhoto = document.getElementById('panelPhoto'); const panelPhotoArrow = document.getElementById('panelPhotoArrow'); let currentImage = null; let currentTransform = { scale: 1, rotate: 0, scaleX: 1, scaleY: 1, translateX: 0, translateY: 0 }; let hideTimeoutPhoto = null; const scaleSlider = document.getElementById('editScaleSlider'); const scaleValue = document.getElementById('editScaleValue'); const rotateLeftBtn = document.getElementById('editRotateLeft'); const rotateRightBtn = document.getElementById('editRotateRight'); const rotateAngle = document.getElementById('editRotateAngle'); const mirrorHorBtn = document.getElementById('editMirrorHor'); const mirrorVerBtn = document.getElementById('editMirrorVer'); const moveUpBtn = document.getElementById('editMoveUp'); const moveDownBtn = document.getElementById('editMoveDown'); const moveLeftBtn = document.getElementById('editMoveLeft'); const moveRightBtn = document.getElementById('editMoveRight'); const posXSpan = document.getElementById('editPosX'); const posYSpan = document.getElementById('editPosY'); const replaceBtn = document.getElementById('editReplacePhotoBtn'); const resetPhotoBtn = document.getElementById('editResetPhotoBtn'); function applyImageTransform() { if (!currentImage) return; const transform = `translate(${currentTransform.translateX}px, ${currentTransform.translateY}px) scale(${currentTransform.scale * currentTransform.scaleX}, ${currentTransform.scale * currentTransform.scaleY}) rotate(${currentTransform.rotate}deg)`; currentImage.style.transform = transform; if (scaleValue) scaleValue.textContent = Math.round(currentTransform.scale * 100) + '%'; if (rotateAngle) rotateAngle.value = currentTransform.rotate; if (posXSpan) posXSpan.textContent = currentTransform.translateX; if (posYSpan) posYSpan.textContent = currentTransform.translateY; } function updateActiveStates() { if (mirrorHorBtn) mirrorHorBtn.classList.remove('active'); if (mirrorVerBtn) mirrorVerBtn.classList.remove('active'); if (currentTransform.scaleX === -1 && mirrorHorBtn) mirrorHorBtn.classList.add('active'); if (currentTransform.scaleY === -1 && mirrorVerBtn) mirrorVerBtn.classList.add('active'); } function setActiveImage(img) { currentImage = img; currentTransform = { scale: 1, rotate: 0, scaleX: 1, scaleY: 1, translateX: 0, translateY: 0 }; if (scaleSlider) scaleSlider.value = 1; applyImageTransform(); updateActiveStates(); showPanelPhoto(); resetHideTimerPhoto(); } function showPanelPhoto() { if (hideTimeoutPhoto) clearTimeout(hideTimeoutPhoto); if (panelPhoto) panelPhoto.classList.add('visible'); } function hidePanelPhoto() { if (panelPhoto) panelPhoto.classList.remove('visible'); } function scheduleHidePhoto() { if (hideTimeoutPhoto) clearTimeout(hideTimeoutPhoto); hideTimeoutPhoto = setTimeout(() => hidePanelPhoto(), 10000); } function resetHideTimerPhoto() { if (hideTimeoutPhoto) clearTimeout(hideTimeoutPhoto); scheduleHidePhoto(); } window.hidePanelPhoto = hidePanelPhoto; if (panelPhotoArrow) { panelPhotoArrow.addEventListener('click', (e) => { e.stopPropagation(); if (window.hidePanelText) window.hidePanelText(); if (panelPhoto.classList.contains('visible')) { hidePanelPhoto(); if (hideTimeoutPhoto) clearTimeout(hideTimeoutPhoto); } else { showPanelPhoto(); scheduleHidePhoto(); } }); } // ГЛОБАЛЬНЫЙ ОБРАБОТЧИК ДЛЯ ВСЕХ ФОТО В КОНСТРУКТОРЕ document.addEventListener('click', (e) => { let target = e.target; if (target.tagName === 'IMG' && target.closest('.page-layout, .template-page')) { e.stopPropagation(); setActiveImage(target); } }); if (scaleSlider) scaleSlider.addEventListener('input', () => { currentTransform.scale = parseFloat(scaleSlider.value); applyImageTransform(); resetHideTimerPhoto(); }); if (rotateLeftBtn) rotateLeftBtn.addEventListener('click', () => { currentTransform.rotate -= 90; applyImageTransform(); resetHideTimerPhoto(); }); if (rotateRightBtn) rotateRightBtn.addEventListener('click', () => { currentTransform.rotate += 90; applyImageTransform(); resetHideTimerPhoto(); }); if (rotateAngle) rotateAngle.addEventListener('input', () => { currentTransform.rotate = parseInt(rotateAngle.value) || 0; applyImageTransform(); resetHideTimerPhoto(); }); if (mirrorHorBtn) mirrorHorBtn.addEventListener('click', () => { currentTransform.scaleX = currentTransform.scaleX === 1 ? -1 : 1; applyImageTransform(); updateActiveStates(); resetHideTimerPhoto(); }); if (mirrorVerBtn) mirrorVerBtn.addEventListener('click', () => { currentTransform.scaleY = currentTransform.scaleY === 1 ? -1 : 1; applyImageTransform(); updateActiveStates(); resetHideTimerPhoto(); }); if (moveUpBtn) moveUpBtn.addEventListener('click', () => { currentTransform.translateY -= 10; applyImageTransform(); resetHideTimerPhoto(); }); if (moveDownBtn) moveDownBtn.addEventListener('click', () => { currentTransform.translateY += 10; applyImageTransform(); resetHideTimerPhoto(); }); if (moveLeftBtn) moveLeftBtn.addEventListener('click', () => { currentTransform.translateX -= 10; applyImageTransform(); resetHideTimerPhoto(); }); if (moveRightBtn) moveRightBtn.addEventListener('click', () => { currentTransform.translateX += 10; applyImageTransform(); resetHideTimerPhoto(); }); if (replaceBtn) { replaceBtn.addEventListener('click', () => { if (!currentImage) return; const input = document.createElement('input'); input.type = 'file'; input.accept = 'image/*'; input.onchange = (e) => { const file = e.target.files[0]; if (file) { const reader = new FileReader(); reader.onload = (ev) => { currentImage.src = ev.target.result; currentTransform = { scale: 1, rotate: 0, scaleX: 1, scaleY: 1, translateX: 0, translateY: 0 }; if (scaleSlider) scaleSlider.value = 1; applyImageTransform(); updateActiveStates(); }; reader.readAsDataURL(file); } }; input.click(); resetHideTimerPhoto(); }); } if (resetPhotoBtn) { resetPhotoBtn.addEventListener('click', () => { currentTransform = { scale: 1, rotate: 0, scaleX: 1, scaleY: 1, translateX: 0, translateY: 0 }; if (scaleSlider) scaleSlider.value = 1; applyImageTransform(); updateActiveStates(); resetHideTimerPhoto(); }); } hidePanelPhoto(); })(); // Добавляем функции закрытия панелей в глобальный доступ window.hidePanelText = function() { const panelText = document.getElementById('panelText'); if (panelText) panelText.classList.remove('visible'); }; window.hidePanelPhoto = function() { const panelPhoto = document.getElementById('panelPhoto'); if (panelPhoto) panelPhoto.classList.remove('visible'); }; // Закрытие панелей при клике вне document.addEventListener('click', (e) => { const panelText = document.getElementById('panelText'); const panelTextArrow = document.getElementById('panelTextArrow'); const panelPhoto = document.getElementById('panelPhoto'); const panelPhotoArrow = document.getElementById('panelPhotoArrow'); if (panelText && !panelText.contains(e.target) && e.target !== panelTextArrow && !panelTextArrow.contains(e.target)) { if (window.hidePanelText) window.hidePanelText(); } if (panelPhoto && !panelPhoto.contains(e.target) && e.target !== panelPhotoArrow && !panelPhotoArrow.contains(e.target) && e.target.tagName !== 'IMG') { if (window.hidePanelPhoto) window.hidePanelPhoto(); } });
шаблоны 1,2
Герой 3
Крит 4
фото+ текст № 10 (5)
фото+текст № 6
шаблон 7
шаблон 8(14)
шаблон 9(15)
шаблон 10(16)
шаблон 11(17)
шаблон 12(18)
Шмуцтитул 13(19) афоризм
Шмуцтитул 14(20) усы
Дисклеймер №15(21)
Благодарность №16(22)
Оглавление №17(27)
Оглавление №18(28)
Адаптивный шаблон №19(29)
Спасибо №20
Участники №21
Корни №22
Глава 1 №23
Листья №24
Заметки №25(23)
Афоризм с кольцом №26(24)
Афоризм с дисклеймером №27(25)
Фото+текст рассказчик №28(13)
Только текст кольцо слева №29
Только текст №30
Фото+текст рассказчик отзеркаленный №31
Фото+текст рассказчик отзеркаленный №32
фото+текст край фото №33
Made on
Tilda