added additional plugins
This commit is contained in:
parent
c85895d306
commit
00e60ec1b7
132 changed files with 27514 additions and 0 deletions
442
native/wordpress/maple-code-blocks/assets/js/block-editor.js
Normal file
442
native/wordpress/maple-code-blocks/assets/js/block-editor.js
Normal file
|
|
@ -0,0 +1,442 @@
|
|||
/**
|
||||
* Maple Code Blocks - Gutenberg Block
|
||||
*
|
||||
* Block registration for the Maple Code Blocks plugin
|
||||
*/
|
||||
|
||||
(function(blocks, element, editor, components, i18n, data, apiFetch) {
|
||||
'use strict';
|
||||
|
||||
const el = element.createElement;
|
||||
const { registerBlockType } = blocks;
|
||||
const { Fragment } = element;
|
||||
const { InspectorControls, BlockControls, AlignmentToolbar, useBlockProps } = editor || {};
|
||||
|
||||
// For older WordPress versions, fallback
|
||||
const BlockProps = useBlockProps || function(props) { return props; };
|
||||
const {
|
||||
PanelBody,
|
||||
PanelRow,
|
||||
TextControl,
|
||||
SelectControl,
|
||||
ToggleControl,
|
||||
Button,
|
||||
Placeholder,
|
||||
Spinner,
|
||||
Notice,
|
||||
ToolbarGroup,
|
||||
ToolbarButton,
|
||||
__experimentalUnitControl: UnitControl,
|
||||
ExternalLink
|
||||
} = components;
|
||||
const { __ } = i18n;
|
||||
const { useState, useEffect } = element;
|
||||
const { useSelect } = data;
|
||||
|
||||
|
||||
// Debug: Log that script is loading
|
||||
console.log('Maple Code Blocks: Script loaded, attempting to register block');
|
||||
|
||||
// Register the block
|
||||
registerBlockType('maple-code-blocks/code-block', {
|
||||
title: __('Maple Code Block', 'maple-code-blocks'),
|
||||
description: __('Display code from GitHub, GitLab, Bitbucket, or Codeberg repositories', 'maple-code-blocks'),
|
||||
icon: {
|
||||
src: 'editor-code',
|
||||
background: '#0366d6',
|
||||
foreground: '#ffffff'
|
||||
},
|
||||
category: 'maple-code-blocks',
|
||||
keywords: ['github', 'code', 'repository', 'syntax', 'highlight', 'viewer'],
|
||||
attributes: {
|
||||
repository: {
|
||||
type: 'string',
|
||||
default: ''
|
||||
},
|
||||
theme: {
|
||||
type: 'string',
|
||||
default: 'dark'
|
||||
},
|
||||
height: {
|
||||
type: 'string',
|
||||
default: '600px'
|
||||
},
|
||||
showLineNumbers: {
|
||||
type: 'boolean',
|
||||
default: true
|
||||
},
|
||||
initialFile: {
|
||||
type: 'string',
|
||||
default: ''
|
||||
},
|
||||
title: {
|
||||
type: 'string',
|
||||
default: ''
|
||||
},
|
||||
isValid: {
|
||||
type: 'boolean',
|
||||
default: false
|
||||
},
|
||||
repoFiles: {
|
||||
type: 'array',
|
||||
default: []
|
||||
}
|
||||
},
|
||||
supports: {
|
||||
align: ['wide', 'full'],
|
||||
className: true,
|
||||
customClassName: true,
|
||||
html: false,
|
||||
anchor: true
|
||||
},
|
||||
|
||||
edit: function(props) {
|
||||
const { attributes, setAttributes, className, isSelected } = props;
|
||||
const {
|
||||
repository,
|
||||
theme,
|
||||
height,
|
||||
showLineNumbers,
|
||||
initialFile,
|
||||
title,
|
||||
isValid,
|
||||
repoFiles
|
||||
} = attributes;
|
||||
|
||||
const [isValidating, setIsValidating] = useState(false);
|
||||
const [validationError, setValidationError] = useState('');
|
||||
const [isLoadingFiles, setIsLoadingFiles] = useState(false);
|
||||
const [popularRepo, setPopularRepo] = useState('');
|
||||
|
||||
const blockProps = BlockProps({
|
||||
className: className + ' mcb-block-editor'
|
||||
});
|
||||
|
||||
// Validate repository when it changes
|
||||
useEffect(() => {
|
||||
if (repository && repository.includes('/')) {
|
||||
validateRepository();
|
||||
}
|
||||
}, [repository]);
|
||||
|
||||
// Validate repository format and existence
|
||||
const validateRepository = () => {
|
||||
setIsValidating(true);
|
||||
setValidationError('');
|
||||
|
||||
// Basic format validation
|
||||
const repoPattern = /^[a-zA-Z0-9\-_]+\/[a-zA-Z0-9\-_\.]+$/;
|
||||
if (!repoPattern.test(repository)) {
|
||||
setValidationError('Invalid format. Use: owner/repository');
|
||||
setIsValidating(false);
|
||||
setAttributes({ isValid: false });
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate with API
|
||||
apiFetch({
|
||||
path: '/maple-code-blocks/v1/validate-repo',
|
||||
method: 'POST',
|
||||
data: { repository: repository }
|
||||
}).then(response => {
|
||||
setAttributes({ isValid: true });
|
||||
setValidationError('');
|
||||
loadRepositoryFiles();
|
||||
}).catch(error => {
|
||||
setValidationError(error.message || 'Repository not found or inaccessible');
|
||||
setAttributes({ isValid: false });
|
||||
}).finally(() => {
|
||||
setIsValidating(false);
|
||||
});
|
||||
};
|
||||
|
||||
// Load repository files for initial file selection
|
||||
const loadRepositoryFiles = () => {
|
||||
setIsLoadingFiles(true);
|
||||
|
||||
apiFetch({
|
||||
path: '/maple-code-blocks/v1/get-files',
|
||||
method: 'POST',
|
||||
data: { repository: repository }
|
||||
}).then(response => {
|
||||
setAttributes({ repoFiles: response.files || [] });
|
||||
}).catch(error => {
|
||||
console.error('Failed to load files:', error);
|
||||
}).finally(() => {
|
||||
setIsLoadingFiles(false);
|
||||
});
|
||||
};
|
||||
|
||||
// Set a popular repository
|
||||
const setPopularRepository = (repo) => {
|
||||
setAttributes({ repository: repo });
|
||||
setPopularRepo('');
|
||||
};
|
||||
|
||||
// Height units for the control
|
||||
const units = [
|
||||
{ value: 'px', label: 'px' },
|
||||
{ value: '%', label: '%' },
|
||||
{ value: 'vh', label: 'vh' },
|
||||
{ value: 'em', label: 'em' },
|
||||
{ value: 'rem', label: 'rem' }
|
||||
];
|
||||
|
||||
return el(Fragment, {},
|
||||
// Block Controls Toolbar
|
||||
el(BlockControls, {},
|
||||
el(ToolbarGroup, {},
|
||||
el(ToolbarButton, {
|
||||
icon: 'update',
|
||||
label: __('Refresh Repository', 'maple-code-blocks'),
|
||||
onClick: validateRepository,
|
||||
disabled: !repository || isValidating
|
||||
}),
|
||||
el(ToolbarButton, {
|
||||
icon: 'external',
|
||||
label: __('View on GitHub', 'maple-code-blocks'),
|
||||
onClick: () => window.open('https://github.com/' + repository, '_blank'),
|
||||
disabled: !repository || !isValid
|
||||
})
|
||||
)
|
||||
),
|
||||
|
||||
// Inspector Controls (Sidebar)
|
||||
el(InspectorControls, {},
|
||||
el(PanelBody, {
|
||||
title: __('Repository Settings', 'maple-code-blocks'),
|
||||
initialOpen: true
|
||||
},
|
||||
el(TextControl, {
|
||||
label: __('GitHub Repository', 'maple-code-blocks'),
|
||||
value: repository,
|
||||
onChange: (value) => setAttributes({ repository: value }),
|
||||
placeholder: 'owner/repository',
|
||||
help: __('Format: owner/repository (e.g., facebook/react)', 'maple-code-blocks')
|
||||
}),
|
||||
|
||||
isValidating && el(Spinner),
|
||||
|
||||
validationError && el(Notice, {
|
||||
status: 'error',
|
||||
isDismissible: false
|
||||
}, validationError),
|
||||
|
||||
isValid && !isValidating && el(Notice, {
|
||||
status: 'success',
|
||||
isDismissible: false
|
||||
}, __('✓ Repository validated', 'maple-code-blocks')),
|
||||
|
||||
el(PanelRow, {},
|
||||
el('div', { style: { width: '100%' } },
|
||||
el('label', {}, __('Popular Repositories', 'maple-code-blocks')),
|
||||
el(SelectControl, {
|
||||
value: popularRepo,
|
||||
onChange: setPopularRepository,
|
||||
options: [
|
||||
{ label: __('Select a repository...', 'maple-code-blocks'), value: '' },
|
||||
...mcbBlockData.popularRepos.map(repo => ({
|
||||
label: repo,
|
||||
value: repo
|
||||
}))
|
||||
]
|
||||
})
|
||||
)
|
||||
),
|
||||
|
||||
repository && el(ExternalLink, {
|
||||
href: 'https://github.com/' + repository
|
||||
}, __('View on GitHub →', 'maple-code-blocks'))
|
||||
),
|
||||
|
||||
el(PanelBody, {
|
||||
title: __('Display Settings', 'maple-code-blocks'),
|
||||
initialOpen: false
|
||||
},
|
||||
el(TextControl, {
|
||||
label: __('Title (Optional)', 'maple-code-blocks'),
|
||||
value: title,
|
||||
onChange: (value) => setAttributes({ title: value }),
|
||||
placeholder: __('e.g., React Source Code', 'maple-code-blocks')
|
||||
}),
|
||||
|
||||
el(SelectControl, {
|
||||
label: __('Theme', 'maple-code-blocks'),
|
||||
value: theme,
|
||||
onChange: (value) => setAttributes({ theme: value }),
|
||||
options: mcbBlockData.themes
|
||||
}),
|
||||
|
||||
el('div', {
|
||||
className: 'mcb-height-control',
|
||||
style: { marginBottom: '20px' }
|
||||
},
|
||||
el('label', {}, __('Height', 'maple-code-blocks')),
|
||||
el(TextControl, {
|
||||
value: height,
|
||||
onChange: (value) => setAttributes({ height: value }),
|
||||
placeholder: '600px',
|
||||
help: __('Examples: 600px, 80vh, 100%', 'maple-code-blocks')
|
||||
})
|
||||
),
|
||||
|
||||
el(ToggleControl, {
|
||||
label: __('Show Line Numbers', 'maple-code-blocks'),
|
||||
checked: showLineNumbers,
|
||||
onChange: (value) => setAttributes({ showLineNumbers: value })
|
||||
})
|
||||
),
|
||||
|
||||
el(PanelBody, {
|
||||
title: __('Advanced Settings', 'maple-code-blocks'),
|
||||
initialOpen: false
|
||||
},
|
||||
isLoadingFiles && el(Spinner),
|
||||
|
||||
!isLoadingFiles && repoFiles.length > 0 && el(SelectControl, {
|
||||
label: __('Initial File to Display', 'maple-code-blocks'),
|
||||
value: initialFile,
|
||||
onChange: (value) => setAttributes({ initialFile: value }),
|
||||
options: [
|
||||
{ label: __('None (Show file browser)', 'maple-code-blocks'), value: '' },
|
||||
...repoFiles.map(file => ({
|
||||
label: file.name,
|
||||
value: file.path
|
||||
}))
|
||||
],
|
||||
help: __('Select a file to display when the viewer loads', 'maple-code-blocks')
|
||||
})
|
||||
)
|
||||
),
|
||||
|
||||
// Main Block Content
|
||||
el('div', blockProps,
|
||||
!repository ?
|
||||
// Empty state placeholder
|
||||
el(Placeholder, {
|
||||
icon: 'editor-code',
|
||||
label: __('GitHub Code Viewer', 'maple-code-blocks'),
|
||||
instructions: __('Display code from any public GitHub repository', 'maple-code-blocks')
|
||||
},
|
||||
el(TextControl, {
|
||||
value: repository,
|
||||
onChange: (value) => setAttributes({ repository: value }),
|
||||
placeholder: 'owner/repository',
|
||||
label: __('Repository', 'maple-code-blocks')
|
||||
}),
|
||||
el('div', { style: { marginTop: '10px' } },
|
||||
el('strong', {}, __('Quick Start:', 'maple-code-blocks')),
|
||||
el('div', { style: { marginTop: '5px' } },
|
||||
mcbBlockData.popularRepos.slice(0, 3).map(repo =>
|
||||
el(Button, {
|
||||
key: repo,
|
||||
isSecondary: true,
|
||||
onClick: () => setAttributes({ repository: repo }),
|
||||
style: { margin: '2px' }
|
||||
}, repo)
|
||||
)
|
||||
)
|
||||
)
|
||||
) :
|
||||
// Preview state
|
||||
el('div', {
|
||||
className: 'mcb-block-preview',
|
||||
style: {
|
||||
background: theme === 'dark' ? '#1e1e1e' : '#ffffff',
|
||||
border: '1px solid #e0e0e0',
|
||||
borderRadius: '4px',
|
||||
padding: '20px',
|
||||
minHeight: '200px'
|
||||
}
|
||||
},
|
||||
title && el('h3', {
|
||||
style: {
|
||||
margin: '0 0 10px 0',
|
||||
color: theme === 'dark' ? '#ffffff' : '#000000'
|
||||
}
|
||||
}, title),
|
||||
|
||||
el('div', {
|
||||
className: 'mcb-preview-header',
|
||||
style: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
marginBottom: '15px',
|
||||
paddingBottom: '10px',
|
||||
borderBottom: '1px solid ' + (theme === 'dark' ? '#444' : '#e0e0e0')
|
||||
}
|
||||
},
|
||||
el('svg', {
|
||||
width: '20',
|
||||
height: '20',
|
||||
viewBox: '0 0 24 24',
|
||||
style: { marginRight: '10px' }
|
||||
},
|
||||
el('path', {
|
||||
fill: theme === 'dark' ? '#ffffff' : '#000000',
|
||||
d: 'M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z'
|
||||
})
|
||||
),
|
||||
el('span', {
|
||||
style: {
|
||||
fontSize: '14px',
|
||||
color: theme === 'dark' ? '#d4d4d4' : '#666'
|
||||
}
|
||||
}, repository)
|
||||
),
|
||||
|
||||
el('div', {
|
||||
className: 'mcb-preview-info',
|
||||
style: {
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
gap: '15px',
|
||||
fontSize: '13px',
|
||||
color: theme === 'dark' ? '#969696' : '#666'
|
||||
}
|
||||
},
|
||||
el('div', {}, '🎨 Theme: ' + theme),
|
||||
el('div', {}, '📏 Height: ' + height),
|
||||
el('div', {}, showLineNumbers ? '✅ Line Numbers' : '❌ No Line Numbers'),
|
||||
initialFile && el('div', {}, '📄 Initial: ' + initialFile.split('/').pop())
|
||||
),
|
||||
|
||||
isValidating && el('div', {
|
||||
style: {
|
||||
textAlign: 'center',
|
||||
padding: '20px',
|
||||
color: theme === 'dark' ? '#ffffff' : '#000000'
|
||||
}
|
||||
}, el(Spinner), ' Validating repository...'),
|
||||
|
||||
!isValidating && isValid && el('div', {
|
||||
style: {
|
||||
marginTop: '15px',
|
||||
padding: '10px',
|
||||
background: theme === 'dark' ? '#0e4429' : '#d4edda',
|
||||
borderRadius: '4px',
|
||||
color: theme === 'dark' ? '#52c41a' : '#155724',
|
||||
fontSize: '13px'
|
||||
}
|
||||
}, '✓ Repository validated and ready to display')
|
||||
)
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
save: function(props) {
|
||||
// For server-side rendered blocks, we need to return something
|
||||
// This will be replaced by the PHP render callback
|
||||
return el('div', { className: 'maple-code-block-placeholder' }, 'Loading...');
|
||||
}
|
||||
});
|
||||
|
||||
})(
|
||||
window.wp.blocks,
|
||||
window.wp.element,
|
||||
window.wp.blockEditor || window.wp.editor,
|
||||
window.wp.components,
|
||||
window.wp.i18n,
|
||||
window.wp.data,
|
||||
window.wp.apiFetch
|
||||
);
|
||||
Loading…
Add table
Add a link
Reference in a new issue