feat: implement scroll indicators with disabled state styling
- Add document viewport scroll indicators with triangular arrows - Implement disabled state styling (grey background, cursor: not-allowed) - Add smooth scrolling with easing functions for indicator clicks - Include hover detection at top/bottom of viewport for indicator display - Fix CSS syntax error in scroll indicator styles - Add theme-aware styling for all UI themes (standard, greyscale, electric, psychedelic) - Extend confirmation dialog with theme-consistent danger and secondary button properties - Update UserInterfaceFramework.md to mark confirmation dialog as completed 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -208,23 +208,43 @@ Provides detailed information about the current editing session, including versi
|
|||||||
### Description
|
### Description
|
||||||
Provides user confirmation for potentially destructive operations that cannot be easily undone.
|
Provides user confirmation for potentially destructive operations that cannot be easily undone.
|
||||||
|
|
||||||
### Current Implementation
|
### Current Implementation ✅ COMPLETED
|
||||||
- **Method**: Browser native `confirm()` (temporary solution)
|
- **Method**: Custom theme-aware modal dialog
|
||||||
- **Trigger**: "🔄 Reset All" button in floating action panel
|
- **Trigger**: "🔄 Reset All" button in floating action panel
|
||||||
- **Message**: "Reset all content to original markdown? This will lose all edits and remove split sections."
|
- **Message**: "Reset all content to original markdown?"
|
||||||
|
- **Warning**: "This will permanently lose all edits and remove any split sections. This action cannot be undone."
|
||||||
|
|
||||||
|
### Features Implemented
|
||||||
|
- **Theme-Aware Styling**: Adapts to all UI themes (standard, greyscale, electric, psychedelic)
|
||||||
|
- **Clear Action Buttons**:
|
||||||
|
- Primary action: "Reset Document" (red danger button)
|
||||||
|
- Secondary action: "Keep Changes" (grey cancel button)
|
||||||
|
- **Enhanced UX**:
|
||||||
|
- Detailed consequence explanation with warning styling
|
||||||
|
- Professional modal overlay with smooth animations
|
||||||
|
- Proper focus management and accessibility
|
||||||
|
- **Keyboard Support**:
|
||||||
|
- ESC key to cancel
|
||||||
|
- Enter key to confirm
|
||||||
|
- Tab navigation between buttons
|
||||||
|
|
||||||
### Use Cases
|
### Use Cases
|
||||||
- **Reset All Sections**: Complete document reset to original state
|
- **Reset All Sections**: Complete document reset to original state
|
||||||
- **Future**: Delete operations, bulk changes, file operations
|
- **Future**: Extensible for delete operations, bulk changes, file operations
|
||||||
|
|
||||||
### Future Enhancement Plan
|
### Technical Implementation
|
||||||
**Target**: Replace browser confirm with custom modal dialog
|
**CSS Classes**:
|
||||||
- **Styling**: Theme-aware modal with clear action buttons
|
- `.ui-edit-confirmation-modal` - Modal container
|
||||||
- **Features**:
|
- `.ui-edit-confirmation-content` - Main message
|
||||||
- Clear primary/secondary action buttons
|
- `.ui-edit-confirmation-warning` - Warning section
|
||||||
- Detailed consequence explanation
|
- `.ui-edit-confirmation-buttons` - Button container
|
||||||
- Optional "Don't ask again" for non-critical confirmations
|
- `.ui-edit-button-confirm` - Danger action button
|
||||||
- **Accessibility**: Proper focus management, keyboard support
|
- `.ui-edit-button-cancel` - Cancel action button
|
||||||
|
|
||||||
|
**JavaScript Method**: `showConfirmation(message, confirmText, cancelText, warningText)`
|
||||||
|
- Returns Promise<boolean> for async/await support
|
||||||
|
- Theme-consistent styling via layered theme system
|
||||||
|
- Proper event cleanup and accessibility features
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -481,8 +481,145 @@ class CleanDocumentManager:
|
|||||||
border-top: 1px solid {props.get('editor_panel_border', '#dee2e6')};
|
border-top: 1px solid {props.get('editor_panel_border', '#dee2e6')};
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}}
|
}}
|
||||||
outline: none;
|
|
||||||
}}"""
|
/* Confirmation Dialog Styles */
|
||||||
|
.markitect-edit-mode .ui-edit-confirmation-modal {{
|
||||||
|
max-width: 500px;
|
||||||
|
}}
|
||||||
|
.markitect-edit-mode .ui-edit-confirmation-content {{
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.5;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
color: {props.get('editor_text_color', '#212529')};
|
||||||
|
}}
|
||||||
|
.markitect-edit-mode .ui-edit-confirmation-warning {{
|
||||||
|
background: {props.get('editor_warning_bg', '#fff3cd')};
|
||||||
|
border: 1px solid {props.get('editor_warning_border', '#ffeaa7')};
|
||||||
|
color: {props.get('editor_warning_text', '#856404')};
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin: 16px 0;
|
||||||
|
font-size: 14px;
|
||||||
|
}}
|
||||||
|
.markitect-edit-mode .ui-edit-confirmation-buttons {{
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}}
|
||||||
|
.markitect-edit-mode .ui-edit-button-confirm {{
|
||||||
|
background: {props.get('editor_danger_button', '#dc3545')};
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.2s, transform 0.1s;
|
||||||
|
}}
|
||||||
|
.markitect-edit-mode .ui-edit-button-confirm:hover {{
|
||||||
|
background: {props.get('editor_danger_button_hover', '#c82333')};
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}}
|
||||||
|
.markitect-edit-mode .ui-edit-button-confirm:active {{
|
||||||
|
transform: translateY(0);
|
||||||
|
}}
|
||||||
|
.markitect-edit-mode .ui-edit-button-confirm:focus {{
|
||||||
|
outline: 2px solid {props.get('editor_focus_color', '#007bff')};
|
||||||
|
outline-offset: 2px;
|
||||||
|
}}
|
||||||
|
.markitect-edit-mode .ui-edit-button-cancel {{
|
||||||
|
background: {props.get('editor_secondary_button', '#6c757d')};
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.2s, transform 0.1s;
|
||||||
|
}}
|
||||||
|
.markitect-edit-mode .ui-edit-button-cancel:hover {{
|
||||||
|
background: {props.get('editor_secondary_button_hover', '#545b62')};
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}}
|
||||||
|
.markitect-edit-mode .ui-edit-button-cancel:active {{
|
||||||
|
transform: translateY(0);
|
||||||
|
}}
|
||||||
|
.markitect-edit-mode .ui-edit-button-cancel:focus {{
|
||||||
|
outline: 2px solid {props.get('editor_focus_color', '#007bff')};
|
||||||
|
outline-offset: 2px;
|
||||||
|
}}
|
||||||
|
|
||||||
|
/* Document Scroll Indicators */
|
||||||
|
.ui-scroll-indicator {{
|
||||||
|
position: fixed;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 60px;
|
||||||
|
height: 30px;
|
||||||
|
background: {props.get('editor_panel_bg', '#f8f9fa')};
|
||||||
|
border: 1px solid {props.get('editor_panel_border', '#dee2e6')};
|
||||||
|
border-radius: 15px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
transition: opacity 0.3s ease, visibility 0.3s ease, transform 0.2s ease, background-color 0.2s ease;
|
||||||
|
z-index: 1000;
|
||||||
|
box-shadow: 0 4px 12px {props.get('editor_shadow', 'rgba(0,0,0,0.15)')};
|
||||||
|
}}
|
||||||
|
.ui-scroll-indicator:hover {{
|
||||||
|
transform: translateX(-50%) scale(1.05);
|
||||||
|
}}
|
||||||
|
.ui-scroll-indicator:not(.disabled):hover {{
|
||||||
|
background: {props.get('editor_button_hover', '#e9ecef')};
|
||||||
|
}}
|
||||||
|
.ui-scroll-indicator.active {{
|
||||||
|
opacity: 0.9;
|
||||||
|
visibility: visible;
|
||||||
|
}}
|
||||||
|
.ui-scroll-indicator.disabled {{
|
||||||
|
background: {props.get('editor_button_active', '#dee2e6')};
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.6;
|
||||||
|
}}
|
||||||
|
.ui-scroll-indicator.disabled:hover {{
|
||||||
|
transform: translateX(-50%);
|
||||||
|
background: {props.get('editor_button_active', '#dee2e6')};
|
||||||
|
}}
|
||||||
|
.ui-scroll-indicator-up {{
|
||||||
|
top: 20px;
|
||||||
|
}}
|
||||||
|
.ui-scroll-indicator-down {{
|
||||||
|
bottom: 20px;
|
||||||
|
}}
|
||||||
|
.ui-scroll-indicator::before {{
|
||||||
|
content: '';
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-style: solid;
|
||||||
|
transition: border-color 0.2s ease;
|
||||||
|
}}
|
||||||
|
.ui-scroll-indicator-up::before {{
|
||||||
|
border-left: 8px solid transparent;
|
||||||
|
border-right: 8px solid transparent;
|
||||||
|
border-bottom: 12px solid {props.get('editor_text_color', '#212529')};
|
||||||
|
}}
|
||||||
|
.ui-scroll-indicator-down::before {{
|
||||||
|
border-left: 8px solid transparent;
|
||||||
|
border-right: 8px solid transparent;
|
||||||
|
border-top: 12px solid {props.get('editor_text_color', '#212529')};
|
||||||
|
}}
|
||||||
|
.ui-scroll-indicator.disabled.ui-scroll-indicator-up::before {{
|
||||||
|
border-bottom-color: {props.get('editor_secondary_button', '#6c757d')};
|
||||||
|
}}
|
||||||
|
.ui-scroll-indicator.disabled.ui-scroll-indicator-down::before {{
|
||||||
|
border-top-color: {props.get('editor_secondary_button', '#6c757d')};
|
||||||
|
}}
|
||||||
|
"""
|
||||||
|
|
||||||
return f"<style>{base_css}{heading_css}{text_css}{element_css}{link_css}{accent_css}{ui_css}</style>"
|
return f"<style>{base_css}{heading_css}{text_css}{element_css}{link_css}{accent_css}{ui_css}</style>"
|
||||||
|
|
||||||
@@ -667,6 +804,13 @@ class CleanDocumentManager:
|
|||||||
console.error("Clean edit mode failed to initialize:", error);
|
console.error("Clean edit mode failed to initialize:", error);
|
||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
// Step 3: Initialize document scroll indicators (always available)
|
||||||
|
try {{
|
||||||
|
initializeScrollIndicators();
|
||||||
|
}} catch (error) {{
|
||||||
|
console.error("Scroll indicators failed to initialize:", error);
|
||||||
|
}}
|
||||||
}});
|
}});
|
||||||
|
|
||||||
// Handle CDN loading errors
|
// Handle CDN loading errors
|
||||||
@@ -1675,8 +1819,143 @@ class MarkitectCleanEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resetAllSections() {
|
/**
|
||||||
if (confirm('Reset all content to original markdown? This will lose all edits and remove split sections.')) {
|
* Show custom confirmation dialog with theme-consistent styling
|
||||||
|
* @param {string} message - The confirmation message
|
||||||
|
* @param {string} confirmText - Text for confirm button (default: "Confirm")
|
||||||
|
* @param {string} cancelText - Text for cancel button (default: "Cancel")
|
||||||
|
* @param {string} warningText - Optional warning text to highlight consequences
|
||||||
|
* @returns {Promise<boolean>} - True if confirmed, false if cancelled
|
||||||
|
*/
|
||||||
|
showConfirmation(message, confirmText = "Confirm", cancelText = "Cancel", warningText = null) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
// Remove any existing modal
|
||||||
|
const existingModal = document.querySelector('.ui-edit-modal-overlay');
|
||||||
|
if (existingModal) {
|
||||||
|
existingModal.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create modal overlay
|
||||||
|
const overlay = document.createElement('div');
|
||||||
|
overlay.className = 'ui-edit-modal-overlay';
|
||||||
|
|
||||||
|
// Create modal content
|
||||||
|
const modal = document.createElement('div');
|
||||||
|
modal.className = 'ui-edit-modal ui-edit-confirmation-modal';
|
||||||
|
|
||||||
|
// Create header
|
||||||
|
const header = document.createElement('div');
|
||||||
|
header.className = 'ui-edit-modal-header';
|
||||||
|
|
||||||
|
const title = document.createElement('h3');
|
||||||
|
title.className = 'ui-edit-modal-title';
|
||||||
|
title.textContent = 'Confirm Action';
|
||||||
|
|
||||||
|
const closeBtn = document.createElement('button');
|
||||||
|
closeBtn.className = 'ui-edit-modal-close';
|
||||||
|
closeBtn.innerHTML = '×';
|
||||||
|
closeBtn.setAttribute('aria-label', 'Close');
|
||||||
|
|
||||||
|
header.appendChild(title);
|
||||||
|
header.appendChild(closeBtn);
|
||||||
|
|
||||||
|
// Create body
|
||||||
|
const body = document.createElement('div');
|
||||||
|
body.className = 'ui-edit-modal-body';
|
||||||
|
|
||||||
|
const content = document.createElement('div');
|
||||||
|
content.className = 'ui-edit-confirmation-content';
|
||||||
|
content.textContent = message;
|
||||||
|
body.appendChild(content);
|
||||||
|
|
||||||
|
// Add warning section if provided
|
||||||
|
if (warningText) {
|
||||||
|
const warning = document.createElement('div');
|
||||||
|
warning.className = 'ui-edit-confirmation-warning';
|
||||||
|
warning.textContent = warningText;
|
||||||
|
body.appendChild(warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create footer with action buttons
|
||||||
|
const footer = document.createElement('div');
|
||||||
|
footer.className = 'ui-edit-modal-footer';
|
||||||
|
|
||||||
|
const buttonContainer = document.createElement('div');
|
||||||
|
buttonContainer.className = 'ui-edit-confirmation-buttons';
|
||||||
|
|
||||||
|
const cancelBtn = document.createElement('button');
|
||||||
|
cancelBtn.className = 'ui-edit-button-cancel';
|
||||||
|
cancelBtn.textContent = cancelText;
|
||||||
|
|
||||||
|
const confirmBtn = document.createElement('button');
|
||||||
|
confirmBtn.className = 'ui-edit-button-confirm';
|
||||||
|
confirmBtn.textContent = confirmText;
|
||||||
|
|
||||||
|
buttonContainer.appendChild(cancelBtn);
|
||||||
|
buttonContainer.appendChild(confirmBtn);
|
||||||
|
footer.appendChild(buttonContainer);
|
||||||
|
|
||||||
|
// Assemble modal
|
||||||
|
modal.appendChild(header);
|
||||||
|
modal.appendChild(body);
|
||||||
|
modal.appendChild(footer);
|
||||||
|
overlay.appendChild(modal);
|
||||||
|
document.body.appendChild(overlay);
|
||||||
|
|
||||||
|
// Function to close modal and resolve
|
||||||
|
const closeModal = (result) => {
|
||||||
|
overlay.remove();
|
||||||
|
resolve(result);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Event listeners
|
||||||
|
closeBtn.addEventListener('click', () => closeModal(false));
|
||||||
|
cancelBtn.addEventListener('click', () => closeModal(false));
|
||||||
|
confirmBtn.addEventListener('click', () => closeModal(true));
|
||||||
|
|
||||||
|
// Close on overlay click
|
||||||
|
overlay.addEventListener('click', (e) => {
|
||||||
|
if (e.target === overlay) {
|
||||||
|
closeModal(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Keyboard support
|
||||||
|
const handleKeyDown = (e) => {
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
closeModal(false);
|
||||||
|
} else if (e.key === 'Enter') {
|
||||||
|
closeModal(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener('keydown', handleKeyDown);
|
||||||
|
|
||||||
|
// Clean up event listener when modal is closed
|
||||||
|
const originalResolve = resolve;
|
||||||
|
resolve = (result) => {
|
||||||
|
document.removeEventListener('keydown', handleKeyDown);
|
||||||
|
originalResolve(result);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Show modal with animation
|
||||||
|
setTimeout(() => {
|
||||||
|
overlay.classList.add('active');
|
||||||
|
// Focus the confirm button for accessibility
|
||||||
|
confirmBtn.focus();
|
||||||
|
}, 10);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async resetAllSections() {
|
||||||
|
const confirmed = await this.showConfirmation(
|
||||||
|
'Reset all content to original markdown?',
|
||||||
|
'Reset Document',
|
||||||
|
'Keep Changes',
|
||||||
|
'This will permanently lose all edits and remove any split sections. This action cannot be undone.'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (confirmed) {
|
||||||
// Clear the section manager completely
|
// Clear the section manager completely
|
||||||
this.sectionManager.sections.clear();
|
this.sectionManager.sections.clear();
|
||||||
// Note: No longer tracking single editingSection
|
// Note: No longer tracking single editingSection
|
||||||
@@ -1912,6 +2191,136 @@ function initializeCleanEditor() {
|
|||||||
console.log('✅ Clean section editor initialized successfully');
|
console.log('✅ Clean section editor initialized successfully');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Document scroll indicators
|
||||||
|
function initializeScrollIndicators() {
|
||||||
|
// Create scroll indicators
|
||||||
|
const scrollUpIndicator = document.createElement('div');
|
||||||
|
scrollUpIndicator.className = 'ui-scroll-indicator ui-scroll-indicator-up';
|
||||||
|
scrollUpIndicator.setAttribute('aria-label', 'Scroll to top');
|
||||||
|
scrollUpIndicator.setAttribute('title', 'Scroll up');
|
||||||
|
|
||||||
|
const scrollDownIndicator = document.createElement('div');
|
||||||
|
scrollDownIndicator.className = 'ui-scroll-indicator ui-scroll-indicator-down';
|
||||||
|
scrollDownIndicator.setAttribute('aria-label', 'Scroll to bottom');
|
||||||
|
scrollDownIndicator.setAttribute('title', 'Scroll down');
|
||||||
|
|
||||||
|
document.body.appendChild(scrollUpIndicator);
|
||||||
|
document.body.appendChild(scrollDownIndicator);
|
||||||
|
|
||||||
|
let scrollIndicatorTimeout = null;
|
||||||
|
|
||||||
|
// Function to show/hide indicators based on scroll position and mouse position
|
||||||
|
function updateScrollIndicators(mouseY = null) {
|
||||||
|
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
||||||
|
const windowHeight = window.innerHeight;
|
||||||
|
const documentHeight = document.documentElement.scrollHeight;
|
||||||
|
|
||||||
|
// Determine if scrolling is possible in each direction
|
||||||
|
const canScrollUp = scrollTop > 0;
|
||||||
|
const canScrollDown = scrollTop < documentHeight - windowHeight;
|
||||||
|
|
||||||
|
// Only show indicators if there's any scroll possibility or if document is short
|
||||||
|
let showUp = false;
|
||||||
|
let showDown = false;
|
||||||
|
|
||||||
|
// Show indicators on mouseover near top/bottom of viewport
|
||||||
|
if (mouseY !== null) {
|
||||||
|
const topZone = 100; // pixels from top
|
||||||
|
const bottomZone = windowHeight - 100; // pixels from bottom
|
||||||
|
|
||||||
|
if (mouseY <= topZone) {
|
||||||
|
showUp = true;
|
||||||
|
}
|
||||||
|
if (mouseY >= bottomZone) {
|
||||||
|
showDown = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update indicator visibility and state
|
||||||
|
if (showUp) {
|
||||||
|
scrollUpIndicator.classList.add('active');
|
||||||
|
if (canScrollUp) {
|
||||||
|
scrollUpIndicator.classList.remove('disabled');
|
||||||
|
} else {
|
||||||
|
scrollUpIndicator.classList.add('disabled');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
scrollUpIndicator.classList.remove('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showDown) {
|
||||||
|
scrollDownIndicator.classList.add('active');
|
||||||
|
if (canScrollDown) {
|
||||||
|
scrollDownIndicator.classList.remove('disabled');
|
||||||
|
} else {
|
||||||
|
scrollDownIndicator.classList.add('disabled');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
scrollDownIndicator.classList.remove('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-hide after a delay when mouse moves away
|
||||||
|
if (scrollIndicatorTimeout) {
|
||||||
|
clearTimeout(scrollIndicatorTimeout);
|
||||||
|
}
|
||||||
|
scrollIndicatorTimeout = setTimeout(() => {
|
||||||
|
scrollUpIndicator.classList.remove('active');
|
||||||
|
scrollDownIndicator.classList.remove('active');
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mouse move handler
|
||||||
|
function handleMouseMove(e) {
|
||||||
|
updateScrollIndicators(e.clientY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Smooth scroll function
|
||||||
|
function smoothScroll(targetY, duration = 500) {
|
||||||
|
const startY = window.pageYOffset;
|
||||||
|
const difference = targetY - startY;
|
||||||
|
const startTime = performance.now();
|
||||||
|
|
||||||
|
function step(currentTime) {
|
||||||
|
const elapsed = currentTime - startTime;
|
||||||
|
const progress = Math.min(elapsed / duration, 1);
|
||||||
|
|
||||||
|
// Easing function (ease-out)
|
||||||
|
const easeOut = 1 - Math.pow(1 - progress, 3);
|
||||||
|
|
||||||
|
window.scrollTo(0, startY + difference * easeOut);
|
||||||
|
|
||||||
|
if (progress < 1) {
|
||||||
|
requestAnimationFrame(step);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
requestAnimationFrame(step);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Click handlers for smooth scrolling
|
||||||
|
scrollUpIndicator.addEventListener('click', () => {
|
||||||
|
const currentScroll = window.pageYOffset;
|
||||||
|
const targetScroll = Math.max(0, currentScroll - window.innerHeight * 0.8);
|
||||||
|
smoothScroll(targetScroll);
|
||||||
|
});
|
||||||
|
|
||||||
|
scrollDownIndicator.addEventListener('click', () => {
|
||||||
|
const currentScroll = window.pageYOffset;
|
||||||
|
const maxScroll = document.documentElement.scrollHeight - window.innerHeight;
|
||||||
|
const targetScroll = Math.min(maxScroll, currentScroll + window.innerHeight * 0.8);
|
||||||
|
smoothScroll(targetScroll);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Event listeners
|
||||||
|
document.addEventListener('mousemove', handleMouseMove);
|
||||||
|
document.addEventListener('scroll', () => updateScrollIndicators());
|
||||||
|
|
||||||
|
// Initial check
|
||||||
|
updateScrollIndicators();
|
||||||
|
|
||||||
|
console.log('✅ Document scroll indicators initialized');
|
||||||
|
}
|
||||||
|
|
||||||
// Export for testing and usage
|
// Export for testing and usage
|
||||||
if (typeof module !== 'undefined' && module.exports) {
|
if (typeof module !== 'undefined' && module.exports) {
|
||||||
module.exports = { Section, SectionManager, DOMRenderer, MarkitectCleanEditor };
|
module.exports = { Section, SectionManager, DOMRenderer, MarkitectCleanEditor };
|
||||||
|
|||||||
@@ -75,7 +75,14 @@ LAYERED_THEMES = {
|
|||||||
'editor_button_active': '#dee2e6',
|
'editor_button_active': '#dee2e6',
|
||||||
'editor_text_color': '#212529',
|
'editor_text_color': '#212529',
|
||||||
'editor_focus_color': '#0066cc',
|
'editor_focus_color': '#0066cc',
|
||||||
'editor_shadow': 'rgba(0,0,0,0.1)'
|
'editor_shadow': 'rgba(0,0,0,0.1)',
|
||||||
|
'editor_danger_button': '#dc3545',
|
||||||
|
'editor_danger_button_hover': '#c82333',
|
||||||
|
'editor_secondary_button': '#6c757d',
|
||||||
|
'editor_secondary_button_hover': '#545b62',
|
||||||
|
'editor_warning_bg': '#fff3cd',
|
||||||
|
'editor_warning_border': '#ffeaa7',
|
||||||
|
'editor_warning_text': '#856404'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'greyscale': {
|
'greyscale': {
|
||||||
@@ -93,10 +100,13 @@ LAYERED_THEMES = {
|
|||||||
'editor_accept_hover': '#777777',
|
'editor_accept_hover': '#777777',
|
||||||
'editor_cancel_bg': '#999999',
|
'editor_cancel_bg': '#999999',
|
||||||
'editor_cancel_hover': '#808080',
|
'editor_cancel_hover': '#808080',
|
||||||
'editor_reset_bg': '#aaaaaa',
|
'editor_danger_button': '#8b0000',
|
||||||
'editor_reset_hover': '#999999',
|
'editor_danger_button_hover': '#700000',
|
||||||
'editor_secondary_bg': '#bbbbbb',
|
'editor_secondary_button': '#666666',
|
||||||
'editor_secondary_hover': '#aaaaaa'
|
'editor_secondary_button_hover': '#555555',
|
||||||
|
'editor_warning_bg': '#f0f0f0',
|
||||||
|
'editor_warning_border': '#cccccc',
|
||||||
|
'editor_warning_text': '#555555'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'electric': {
|
'electric': {
|
||||||
@@ -109,7 +119,14 @@ LAYERED_THEMES = {
|
|||||||
'editor_button_active': '#0099ff',
|
'editor_button_active': '#0099ff',
|
||||||
'editor_text_color': '#00ffff',
|
'editor_text_color': '#00ffff',
|
||||||
'editor_focus_color': '#ffff00',
|
'editor_focus_color': '#ffff00',
|
||||||
'editor_shadow': '0 0 20px rgba(0,255,255,0.5), 0 0 40px rgba(255,255,0,0.2)'
|
'editor_shadow': '0 0 20px rgba(0,255,255,0.5), 0 0 40px rgba(255,255,0,0.2)',
|
||||||
|
'editor_danger_button': '#ff3366',
|
||||||
|
'editor_danger_button_hover': '#ff0033',
|
||||||
|
'editor_secondary_button': '#006699',
|
||||||
|
'editor_secondary_button_hover': '#004d73',
|
||||||
|
'editor_warning_bg': '#003366',
|
||||||
|
'editor_warning_border': '#00ffff',
|
||||||
|
'editor_warning_text': '#ffff00'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'psychedelic': {
|
'psychedelic': {
|
||||||
@@ -122,7 +139,14 @@ LAYERED_THEMES = {
|
|||||||
'editor_button_active': 'rgba(255,20,147,0.5)',
|
'editor_button_active': 'rgba(255,20,147,0.5)',
|
||||||
'editor_text_color': '#ffffff',
|
'editor_text_color': '#ffffff',
|
||||||
'editor_focus_color': '#ff1493',
|
'editor_focus_color': '#ff1493',
|
||||||
'editor_shadow': 'rgba(255,20,147,0.4)'
|
'editor_shadow': 'rgba(255,20,147,0.4)',
|
||||||
|
'editor_danger_button': 'linear-gradient(45deg, #ff0066, #cc0044)',
|
||||||
|
'editor_danger_button_hover': 'linear-gradient(45deg, #ff3388, #dd1155)',
|
||||||
|
'editor_secondary_button': 'linear-gradient(45deg, #8a2be2, #4b0082)',
|
||||||
|
'editor_secondary_button_hover': 'linear-gradient(45deg, #9932cc, #6a1a9a)',
|
||||||
|
'editor_warning_bg': 'linear-gradient(45deg, #ffa500, #ff8c00)',
|
||||||
|
'editor_warning_border': '#ff1493',
|
||||||
|
'editor_warning_text': '#ffffff'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user