FlatlyPage
Version 1.0.0 • 54 files • 724.77 KB
Files
.htaccess
.last_check
admin/account.php
admin/dashboard.php
admin/easyedit.js
admin/extensions.php
admin/generate-hash.php
admin/index.php
admin/logout.php
admin/preview.php
admin/scripts.php
admin/theme-edit/builder.php
admin/theme-edit/generator.php
admin/theme-edit/index.php
admin/themes.php
assets/fonts/inter/inter.css
assets/fonts/space-grotesk/space-grotesk.css
config.php
contact-handler.php
contact.php
css/admin.css
css/contact.css
css/styles.css
css/theme.css
data/.htaccess
data/index.php
data/settings.php
data/sitemap-config.php
engine/index.php
engine/renderion.php
extensions-loader.php
extensions/privimetrics/main.php
extensions/privimetrics/manifest.xml
extensions/scroll_to_top/main.php
extensions/scroll_to_top/manifest.xml
extensions/seo_image_master/main.php
extensions/seo_image_master/manifest.xml
favicons.txt
index.php
newsletter/.htaccess
newsletter/confirm.php
newsletter/manager.php
newsletter/newsletter-form.js
newsletter/newsletter-styles.css
newsletter/newsletter-unavailable.php
newsletter/newsletter.sql
newsletter/settings.php
newsletter/subscribe.php
newsletter/unsubscribe.php
page.php
robots.txt.php
sitemap.php
updater/index.php
version.txt
admin/easyedit.js
(function () {
const style = document.createElement('style');
style.textContent = `
.sas-floating-toolbar {
position: absolute;
background: linear-gradient(135deg, rgba(30, 30, 35, 0.98), rgba(20, 20, 25, 0.98));
backdrop-filter: blur(20px) saturate(180%);
-webkit-backdrop-filter: blur(20px) saturate(180%);
border: 1px solid rgba(255, 255, 255, 0.18);
border-radius: 14px;
padding: 6px;
display: flex;
gap: 3px;
z-index: 100000;
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.4),
0 2px 8px rgba(0, 0, 0, 0.2),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
opacity: 0;
visibility: hidden;
transform: translateY(12px) scale(0.92);
transition: all 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
pointer-events: none;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
.sas-floating-toolbar.active {
opacity: 1;
visibility: visible;
transform: translateY(0) scale(1);
pointer-events: all;
animation: toolbarEntrance 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes toolbarEntrance {
0% {
opacity: 0;
transform: translateY(12px) scale(0.92);
}
60% {
transform: translateY(-2px) scale(1.02);
}
100% {
opacity: 1;
transform: translateY(0) scale(1);
}
}
.sas-floating-toolbar button {
position: relative;
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.08);
color: rgba(255, 255, 255, 0.85);
width: 38px;
height: 38px;
cursor: pointer;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
overflow: hidden;
padding: 0;
}
.sas-floating-toolbar button svg {
width: 18px;
height: 18px;
transition: all 0.2s;
}
.sas-floating-toolbar button::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
border-radius: 50%;
background: rgba(255, 255, 255, 0.15);
transform: translate(-50%, -50%);
transition: width 0.4s, height 0.4s;
}
.sas-floating-toolbar button:hover {
background: rgba(255, 255, 255, 0.12);
border-color: rgba(255, 255, 255, 0.2);
color: #ffffff;
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.sas-floating-toolbar button:hover svg {
transform: scale(1.1);
}
.sas-floating-toolbar button:active::before {
width: 100px;
height: 100px;
}
.sas-floating-toolbar button:active {
transform: scale(0.95);
}
.sas-floating-toolbar .divider {
width: 1px;
background: linear-gradient(
to bottom,
rgba(255, 255, 255, 0),
rgba(255, 255, 255, 0.15),
rgba(255, 255, 255, 0)
);
margin: 8px 4px;
align-self: stretch;
}
.sas-floating-toolbar::after {
content: '';
position: absolute;
bottom: -7px;
left: 50%;
transform: translateX(-50%);
border-left: 7px solid transparent;
border-right: 7px solid transparent;
border-top: 7px solid rgba(30, 30, 35, 0.98);
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
}
.sas-floating-toolbar.arrow-left::after {
left: 20px;
transform: translateX(0);
}
.sas-floating-toolbar.arrow-right::after {
left: auto;
right: 20px;
transform: translateX(0);
}
.sas-floating-toolbar button[title]:hover::after {
content: attr(title);
position: absolute;
bottom: -32px;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.9);
color: white;
padding: 4px 8px;
border-radius: 6px;
font-size: 11px;
font-weight: 500;
white-space: nowrap;
pointer-events: none;
animation: tooltipFade 0.2s ease;
z-index: 1;
}
@keyframes tooltipFade {
from { opacity: 0; transform: translateX(-50%) translateY(-4px); }
to { opacity: 1; transform: translateX(-50%) translateY(0); }
}
`;
document.head.appendChild(style);
// SVG ICONS
const icons = {
bold: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M6 4h8a4 4 0 0 1 0 8H6z"/>
<path d="M6 12h9a4 4 0 0 1 0 8H6z"/>
</svg>`,
italic: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="19" y1="4" x2="10" y2="4"/>
<line x1="14" y1="20" x2="5" y2="20"/>
<line x1="15" y1="4" x2="9" y2="20"/>
</svg>`,
underline: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M6 3v7a6 6 0 0 0 12 0V3"/>
<line x1="4" y1="21" x2="20" y2="21"/>
</svg>`,
strikethrough: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M16 4H9a3 3 0 0 0-2.83 4"/>
<path d="M14 12a4 4 0 0 1 0 8H6"/>
<line x1="4" y1="12" x2="20" y2="12"/>
</svg>`,
quote: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 21c3 0 7-1 7-8V5c0-1.25-.756-2.017-2-2H4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2 1 0 1 0 1 1v1c0 1-1 2-2 2s-1 .008-1 1.031V20c0 1 0 1 1 1z"/>
<path d="M15 21c3 0 7-1 7-8V5c0-1.25-.757-2.017-2-2h-4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2h.75c0 2.25.25 4-2.75 4v3c0 1 0 1 1 1z"/>
</svg>`
};
// TOOLBAR STRUCTURE
const toolbar = document.createElement('div');
toolbar.className = 'sas-floating-toolbar';
toolbar.innerHTML = `
<button data-tag="b" title="Bold (Ctrl+B)">${icons.bold}</button>
<button data-tag="i" title="Italic (Ctrl+I)">${icons.italic}</button>
<div class="divider"></div>
<button data-tag="u" title="Underline (Ctrl+U)">${icons.underline}</button>
<button data-tag="s" title="Strikethrough">${icons.strikethrough}</button>
<div class="divider"></div>
<button data-tag="quote" title="Quote">${icons.quote}</button>
`;
document.body.appendChild(toolbar);
let activeInput = null;
let hideTimeout = null;
// SMART POSITIONING
const positionToolbar = (x, y) => {
const toolbarWidth = toolbar.offsetWidth;
const toolbarHeight = toolbar.offsetHeight;
const padding = 12;
const arrowOffset = 18;
let left = x - (toolbarWidth / 2);
let top = y - toolbarHeight - arrowOffset;
const viewportWidth = window.innerWidth;
const scrollTop = window.pageYOffset;
toolbar.classList.remove('arrow-left', 'arrow-right');
if (left < padding) {
left = padding;
toolbar.classList.add('arrow-left');
} else if (left + toolbarWidth > viewportWidth - padding) {
left = viewportWidth - toolbarWidth - padding;
toolbar.classList.add('arrow-right');
}
if (top < scrollTop + padding) {
top = y + arrowOffset;
}
toolbar.style.left = `${left}px`;
toolbar.style.top = `${top}px`;
};
// FORMATTING LOGIC
const formatText = (tag) => {
if (!activeInput) return;
const start = activeInput.selectionStart;
const end = activeInput.selectionEnd;
const value = activeInput.value;
const selectedText = value.substring(start, end);
if (!selectedText) return;
const openTag = `[${tag}]`;
const closeTag = `[/${tag}]`;
let replacement;
let newSelectionStart, newSelectionEnd;
const alreadyFormatted = selectedText.startsWith(openTag) && selectedText.endsWith(closeTag);
if (alreadyFormatted) {
replacement = selectedText.substring(openTag.length, selectedText.length - closeTag.length);
newSelectionStart = start;
newSelectionEnd = start + replacement.length;
} else {
replacement = openTag + selectedText + closeTag;
newSelectionStart = start;
newSelectionEnd = end + openTag.length + closeTag.length;
}
const scrollTop = activeInput.scrollTop;
activeInput.focus();
activeInput.setSelectionRange(start, end);
document.execCommand('insertText', false, replacement);
activeInput.setSelectionRange(newSelectionStart, newSelectionEnd);
activeInput.scrollTop = scrollTop;
activeInput.dispatchEvent(new Event('input', { bubbles: true }));
activeInput.dispatchEvent(new Event('change', { bubbles: true }));
};
const showToolbar = () => {
clearTimeout(hideTimeout);
toolbar.classList.add('active');
};
const hideToolbar = (immediate = false) => {
clearTimeout(hideTimeout);
if (immediate) {
toolbar.classList.remove('active');
} else {
hideTimeout = setTimeout(() => {
toolbar.classList.remove('active');
}, 100);
}
};
// EVENT HANDLERS
let selectionTimeout;
const handleSelection = (e) => {
clearTimeout(selectionTimeout);
selectionTimeout = setTimeout(() => {
const isTextInput = e.target.tagName === 'TEXTAREA' ||
(e.target.tagName === 'INPUT' && e.target.type === 'text');
if (!isTextInput) {
if (!e.target.closest('.sas-floating-toolbar')) {
hideToolbar(true);
}
return;
}
const start = e.target.selectionStart;
const end = e.target.selectionEnd;
const hasSelection = start !== end;
if (hasSelection) {
activeInput = e.target;
positionToolbar(e.pageX, e.pageY);
showToolbar();
} else {
if (!e.target.closest('.sas-floating-toolbar')) {
hideToolbar(true);
}
}
}, 10);
};
// Left click
document.addEventListener('mouseup', handleSelection);
// Right click
document.addEventListener('contextmenu', (e) => {
const isTextInput = e.target.tagName === 'TEXTAREA' ||
(e.target.tagName === 'INPUT' && e.target.type === 'text');
if (isTextInput) {
setTimeout(() => {
const start = e.target.selectionStart;
const end = e.target.selectionEnd;
if (start !== end) {
e.preventDefault();
handleSelection(e);
}
}, 10);
}
});
// Button clicks
toolbar.querySelectorAll('button[data-tag]').forEach(btn => {
btn.addEventListener('mousedown', (e) => {
e.preventDefault();
e.stopPropagation();
formatText(btn.dataset.tag);
});
});
// Keyboard shortcuts
document.addEventListener('keydown', (e) => {
if (!activeInput) return;
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
const modKey = isMac ? e.metaKey : e.ctrlKey;
if (modKey) {
const key = e.key.toLowerCase();
let tag = null;
switch (key) {
case 'b': tag = 'b'; break;
case 'i': tag = 'i'; break;
case 'u': tag = 'u'; break;
}
if (tag) {
e.preventDefault();
formatText(tag);
}
} else if (!e.shiftKey && !e.altKey) {
hideToolbar(true);
}
});
// Hide on scroll/resize
window.addEventListener('scroll', () => hideToolbar(true), { passive: true });
window.addEventListener('resize', () => hideToolbar(true), { passive: true });
// Prevent closing when clicking toolbar
toolbar.addEventListener('mousedown', (e) => e.stopPropagation());
// Hide when clicking outside
document.addEventListener('mousedown', (e) => {
if (!e.target.closest('.sas-floating-toolbar') && e.target !== activeInput) {
hideToolbar(true);
}
});
})();