feat: complete code cleanup and create feature parity plan
Major Architecture Improvements: - Separate JavaScript library (lib/) with proper build system - Go CLI with embedded library using go:embed - Hot reload development with Air integration - Library + CLI build pipeline with npm run build Code Cleanup: - Remove obsolete assets (insertr-cli/assets/editor/) - Clean up package.json metadata and dependencies - Update .gitignore for new architecture - Remove unused 'marked' dependency New Documentation: - Add comprehensive TODO.md with feature gap analysis - Document critical gaps between prototype and current library - Create phased implementation plan for feature parity - Update DEVELOPMENT.md with hot reload workflow - Add LIBRARY.md documenting new architecture Hot Reload System: - Air watches both Go CLI and JavaScript library - Library changes trigger: rebuild → copy → CLI rebuild → serve - Seamless development experience across full stack Next Steps: - Current library is basic proof-of-concept (prompt() editing) - Archived prototype has production-ready features - Phase 1 focuses on professional forms and authentication - Phase 2 adds validation and content persistence
This commit is contained in:
57
lib/src/core/api-client.js
Normal file
57
lib/src/core/api-client.js
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* ApiClient - Handle communication with content API
|
||||
*/
|
||||
export class ApiClient {
|
||||
constructor(options = {}) {
|
||||
this.baseUrl = options.apiEndpoint || '/api/content';
|
||||
this.siteId = options.siteId || 'default';
|
||||
}
|
||||
|
||||
async getContent(contentId) {
|
||||
try {
|
||||
const response = await fetch(`${this.baseUrl}/sites/${this.siteId}/content/${contentId}`);
|
||||
return response.ok ? await response.json() : null;
|
||||
} catch (error) {
|
||||
console.warn('Failed to fetch content:', contentId, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async updateContent(contentId, content) {
|
||||
try {
|
||||
const response = await fetch(`${this.baseUrl}/sites/${this.siteId}/content/${contentId}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ value: content })
|
||||
});
|
||||
|
||||
return response.ok;
|
||||
} catch (error) {
|
||||
console.error('Failed to update content:', contentId, error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async createContent(contentId, content, type) {
|
||||
try {
|
||||
const response = await fetch(`${this.baseUrl}/sites/${this.siteId}/content`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
id: contentId,
|
||||
value: content,
|
||||
type: type
|
||||
})
|
||||
});
|
||||
|
||||
return response.ok;
|
||||
} catch (error) {
|
||||
console.error('Failed to create content:', contentId, error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
110
lib/src/core/editor.js
Normal file
110
lib/src/core/editor.js
Normal file
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* InsertrEditor - Visual editing functionality
|
||||
*/
|
||||
export class InsertrEditor {
|
||||
constructor(core, options = {}) {
|
||||
this.core = core;
|
||||
this.options = options;
|
||||
this.isActive = false;
|
||||
}
|
||||
|
||||
start() {
|
||||
if (this.isActive) return;
|
||||
|
||||
console.log('🚀 Starting Insertr Editor');
|
||||
this.isActive = true;
|
||||
|
||||
// Add editor styles
|
||||
this.addEditorStyles();
|
||||
|
||||
// Initialize all enhanced elements
|
||||
const elements = this.core.getAllElements();
|
||||
console.log(`📝 Found ${elements.length} editable elements`);
|
||||
|
||||
elements.forEach(meta => this.initializeElement(meta));
|
||||
}
|
||||
|
||||
initializeElement(meta) {
|
||||
const { element, contentId, contentType } = meta;
|
||||
|
||||
// Add visual indicators
|
||||
element.style.cursor = 'pointer';
|
||||
element.style.position = 'relative';
|
||||
|
||||
// Add interaction handlers
|
||||
this.addHoverEffects(element);
|
||||
this.addClickHandler(element, meta);
|
||||
}
|
||||
|
||||
addHoverEffects(element) {
|
||||
element.addEventListener('mouseenter', () => {
|
||||
element.classList.add('insertr-editing-hover');
|
||||
});
|
||||
|
||||
element.addEventListener('mouseleave', () => {
|
||||
element.classList.remove('insertr-editing-hover');
|
||||
});
|
||||
}
|
||||
|
||||
addClickHandler(element, meta) {
|
||||
element.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
this.openEditor(meta);
|
||||
});
|
||||
}
|
||||
|
||||
openEditor(meta) {
|
||||
const { contentId, contentType, element } = meta;
|
||||
const currentContent = element.textContent.trim();
|
||||
|
||||
// For now, use a simple prompt (will be replaced with proper modal)
|
||||
const newContent = prompt(
|
||||
`Edit ${contentType} content (ID: ${contentId}):`,
|
||||
currentContent
|
||||
);
|
||||
|
||||
if (newContent !== null && newContent !== currentContent) {
|
||||
this.updateContent(meta, newContent);
|
||||
}
|
||||
}
|
||||
|
||||
updateContent(meta, newContent) {
|
||||
const { element } = meta;
|
||||
|
||||
// Update the element content
|
||||
element.textContent = newContent;
|
||||
|
||||
// TODO: Save to backend API
|
||||
console.log(`💾 Content updated:`, meta.contentId, newContent);
|
||||
}
|
||||
|
||||
addEditorStyles() {
|
||||
const styles = `
|
||||
.insertr-editing-hover {
|
||||
outline: 2px dashed #007cba !important;
|
||||
outline-offset: 2px !important;
|
||||
background-color: rgba(0, 124, 186, 0.05) !important;
|
||||
}
|
||||
|
||||
[data-insertr-enhanced="true"]:hover::after {
|
||||
content: "✏️ " attr(data-content-type);
|
||||
position: absolute;
|
||||
top: -25px;
|
||||
left: 0;
|
||||
background: #007cba;
|
||||
color: white;
|
||||
padding: 2px 6px;
|
||||
font-size: 11px;
|
||||
border-radius: 3px;
|
||||
white-space: nowrap;
|
||||
z-index: 1000;
|
||||
font-family: monospace;
|
||||
}
|
||||
`;
|
||||
|
||||
const styleSheet = document.createElement('style');
|
||||
styleSheet.type = 'text/css';
|
||||
styleSheet.innerHTML = styles;
|
||||
document.head.appendChild(styleSheet);
|
||||
}
|
||||
}
|
||||
32
lib/src/core/insertr.js
Normal file
32
lib/src/core/insertr.js
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* InsertrCore - Core functionality for content management
|
||||
*/
|
||||
export class InsertrCore {
|
||||
constructor(options = {}) {
|
||||
this.options = {
|
||||
apiEndpoint: options.apiEndpoint || '/api/content',
|
||||
siteId: options.siteId || 'default',
|
||||
...options
|
||||
};
|
||||
}
|
||||
|
||||
// Find all enhanced elements on the page
|
||||
findEnhancedElements() {
|
||||
return document.querySelectorAll('[data-insertr-enhanced="true"]');
|
||||
}
|
||||
|
||||
// Get element metadata
|
||||
getElementMetadata(element) {
|
||||
return {
|
||||
contentId: element.getAttribute('data-content-id'),
|
||||
contentType: element.getAttribute('data-content-type'),
|
||||
element: element
|
||||
};
|
||||
}
|
||||
|
||||
// Get all elements with their metadata
|
||||
getAllElements() {
|
||||
const elements = this.findEnhancedElements();
|
||||
return Array.from(elements).map(el => this.getElementMetadata(el));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user