added additional plugins
This commit is contained in:
parent
c85895d306
commit
00e60ec1b7
132 changed files with 27514 additions and 0 deletions
292
native/wordpress/maple-code-blocks/assets/css/block-editor.css
Normal file
292
native/wordpress/maple-code-blocks/assets/css/block-editor.css
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
/**
|
||||
* GitHub Code Viewer Block Editor Styles
|
||||
*/
|
||||
|
||||
/* Block Editor Wrapper */
|
||||
.mcb-block-editor {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
|
||||
}
|
||||
|
||||
/* Block Preview */
|
||||
.mcb-block-preview {
|
||||
min-height: 200px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.mcb-block-preview:hover {
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* Preview Header */
|
||||
.mcb-preview-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-bottom: 10px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.mcb-preview-header svg {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Preview Info Grid */
|
||||
.mcb-preview-info {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 15px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.mcb-preview-info > div {
|
||||
padding: 5px 10px;
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.editor-styles-wrapper .mcb-block-preview.theme-dark .mcb-preview-info > div {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
/* Inspector Controls Customization */
|
||||
.mcb-height-control {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.mcb-height-control label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Popular Repos Buttons */
|
||||
.mcb-popular-repos {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 5px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* Validation States */
|
||||
.mcb-validation-success {
|
||||
color: #00a32a;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
margin-top: 8px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.mcb-validation-error {
|
||||
color: #cc1818;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
margin-top: 8px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* Loading State */
|
||||
.mcb-loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.mcb-loading .components-spinner {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
/* Placeholder Styles */
|
||||
.wp-block-maple-code-blocks-code-viewer .components-placeholder {
|
||||
min-height: 200px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
}
|
||||
|
||||
.wp-block-maple-code-blocks-code-viewer .components-placeholder .components-placeholder__label {
|
||||
font-size: 18px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.wp-block-maple-code-blocks-code-viewer .components-placeholder .components-placeholder__instructions {
|
||||
font-size: 14px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/* Quick Start Section */
|
||||
.mcb-quick-start {
|
||||
margin-top: 15px;
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.mcb-quick-start strong {
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.mcb-quick-start .components-button {
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
/* Block Alignment Support */
|
||||
.wp-block-maple-code-blocks-code-viewer.alignwide {
|
||||
max-width: 1280px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.wp-block-maple-code-blocks-code-viewer.alignfull {
|
||||
max-width: none;
|
||||
margin-left: calc(50% - 50vw);
|
||||
margin-right: calc(50% - 50vw);
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
/* Panel Body Customization */
|
||||
.components-panel__body .mcb-repo-input {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.components-panel__body .mcb-theme-preview {
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
margin-top: 10px;
|
||||
font-family: 'Monaco', 'Menlo', monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.components-panel__body .mcb-theme-preview.dark {
|
||||
background: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
}
|
||||
|
||||
.components-panel__body .mcb-theme-preview.light {
|
||||
background: #ffffff;
|
||||
color: #333333;
|
||||
border: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
/* External Link Style */
|
||||
.components-external-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin-top: 10px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* Toolbar Buttons */
|
||||
.block-editor-block-toolbar .mcb-toolbar-group {
|
||||
border-right: 1px solid #e0e0e0;
|
||||
padding-right: 6px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
/* Notice Improvements */
|
||||
.components-notice.mcb-notice {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.components-notice.mcb-notice .components-notice__content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* Selected State */
|
||||
.wp-block-maple-code-blocks-code-viewer.is-selected .mcb-block-preview {
|
||||
box-shadow: 0 0 0 1px #007cba;
|
||||
}
|
||||
|
||||
/* Help Text */
|
||||
.components-base-control__help {
|
||||
font-size: 12px;
|
||||
font-style: italic;
|
||||
color: #757575;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
/* File Selector */
|
||||
.mcb-file-selector {
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 4px;
|
||||
padding: 5px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.mcb-file-selector .mcb-file-option {
|
||||
padding: 5px 10px;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.mcb-file-selector .mcb-file-option:hover {
|
||||
background: #f0f0f0;
|
||||
}
|
||||
|
||||
.mcb-file-selector .mcb-file-option.selected {
|
||||
background: #007cba;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Responsive Design */
|
||||
@media (max-width: 782px) {
|
||||
.mcb-preview-info {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.mcb-quick-start .components-button {
|
||||
font-size: 12px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dark Theme Support for Editor */
|
||||
.editor-styles-wrapper .mcb-block-preview[data-theme="dark"] {
|
||||
background: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
}
|
||||
|
||||
.editor-styles-wrapper .mcb-block-preview[data-theme="light"] {
|
||||
background: #ffffff;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
/* Animation for validation */
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.mcb-validating {
|
||||
animation: pulse 1.5s infinite;
|
||||
}
|
||||
|
||||
/* Custom scrollbar for file list */
|
||||
.mcb-file-selector::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.mcb-file-selector::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
}
|
||||
|
||||
.mcb-file-selector::-webkit-scrollbar-thumb {
|
||||
background: #888;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.mcb-file-selector::-webkit-scrollbar-thumb:hover {
|
||||
background: #555;
|
||||
}
|
||||
202
native/wordpress/maple-code-blocks/assets/css/block-style.css
Normal file
202
native/wordpress/maple-code-blocks/assets/css/block-style.css
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
/**
|
||||
* GitHub Code Viewer Block Frontend Styles
|
||||
*/
|
||||
|
||||
/* Block Wrapper */
|
||||
.mcb-block-wrapper {
|
||||
margin: 30px auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* Alignment Support */
|
||||
.mcb-block-wrapper.alignleft {
|
||||
float: left;
|
||||
margin-right: 20px;
|
||||
max-width: 50%;
|
||||
}
|
||||
|
||||
.mcb-block-wrapper.alignright {
|
||||
float: right;
|
||||
margin-left: 20px;
|
||||
max-width: 50%;
|
||||
}
|
||||
|
||||
.mcb-block-wrapper.aligncenter {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.mcb-block-wrapper.aligncenter .maple-code-blocks {
|
||||
display: inline-block;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.mcb-block-wrapper.alignwide {
|
||||
max-width: 1280px;
|
||||
width: 100%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.mcb-block-wrapper.alignfull {
|
||||
max-width: none;
|
||||
width: 100vw;
|
||||
position: relative;
|
||||
left: 50%;
|
||||
right: 50%;
|
||||
margin-left: -50vw;
|
||||
margin-right: -50vw;
|
||||
}
|
||||
|
||||
/* Ensure the viewer respects container width */
|
||||
.mcb-block-wrapper .maple-code-blocks {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Custom Classes Support */
|
||||
.mcb-block-wrapper.is-style-minimal {
|
||||
box-shadow: none;
|
||||
border: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.mcb-block-wrapper.is-style-rounded .maple-code-blocks {
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.mcb-block-wrapper.is-style-shadowed .maple-code-blocks {
|
||||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
/* Responsive Adjustments */
|
||||
@media (max-width: 768px) {
|
||||
.mcb-block-wrapper.alignleft,
|
||||
.mcb-block-wrapper.alignright {
|
||||
float: none;
|
||||
max-width: 100%;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.mcb-block-wrapper.alignfull {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* Loading State for Frontend */
|
||||
.mcb-block-wrapper.is-loading {
|
||||
min-height: 400px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #f5f5f5;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.mcb-block-wrapper.is-loading::after {
|
||||
content: 'Loading repository...';
|
||||
color: #666;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
}
|
||||
|
||||
/* Error State */
|
||||
.mcb-block-wrapper .mcb-error {
|
||||
padding: 20px;
|
||||
background: #fee;
|
||||
border: 1px solid #fcc;
|
||||
border-radius: 4px;
|
||||
color: #c00;
|
||||
text-align: center;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
}
|
||||
|
||||
/* Integration with theme styles */
|
||||
.entry-content .mcb-block-wrapper {
|
||||
margin-top: 2em;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
.entry-content .mcb-block-wrapper:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.entry-content .mcb-block-wrapper:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* Print Styles */
|
||||
@media print {
|
||||
.mcb-block-wrapper .mcb-controls,
|
||||
.mcb-block-wrapper .mcb-status-bar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mcb-block-wrapper .maple-code-blocks {
|
||||
box-shadow: none;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
}
|
||||
|
||||
/* Accessibility Improvements */
|
||||
.mcb-block-wrapper .maple-code-blocks:focus-within {
|
||||
outline: 2px solid #007cba;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* High Contrast Mode Support */
|
||||
@media (prefers-contrast: high) {
|
||||
.mcb-block-wrapper .maple-code-blocks {
|
||||
border: 2px solid currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reduced Motion Support */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.mcb-block-wrapper .maple-code-blocks * {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dark Mode Support */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.mcb-block-wrapper.is-loading {
|
||||
background: #2a2a2a;
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
.mcb-block-wrapper.is-loading::after {
|
||||
color: #ccc;
|
||||
}
|
||||
}
|
||||
|
||||
/* Nested Block Support */
|
||||
.wp-block-group .mcb-block-wrapper,
|
||||
.wp-block-column .mcb-block-wrapper {
|
||||
margin-top: 1.5em;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
/* Pattern Library Support */
|
||||
.mcb-block-wrapper[data-pattern="documentation"] .maple-code-blocks {
|
||||
height: 400px !important;
|
||||
}
|
||||
|
||||
.mcb-block-wrapper[data-pattern="showcase"] .maple-code-blocks {
|
||||
height: 600px !important;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.mcb-block-wrapper[data-pattern="inline"] .maple-code-blocks {
|
||||
height: 300px !important;
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
min-width: 500px;
|
||||
}
|
||||
2
native/wordpress/maple-code-blocks/assets/css/index.php
Normal file
2
native/wordpress/maple-code-blocks/assets/css/index.php
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
<?php
|
||||
// Silence is golden.
|
||||
529
native/wordpress/maple-code-blocks/assets/css/mcb-styles.css
Normal file
529
native/wordpress/maple-code-blocks/assets/css/mcb-styles.css
Normal file
|
|
@ -0,0 +1,529 @@
|
|||
/* GitHub Code Viewer - Main Styles */
|
||||
|
||||
.maple-code-blocks {
|
||||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.08);
|
||||
background: #1e1e1e;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Dark Theme (Default) */
|
||||
.maple-code-blocks[data-theme="dark"],
|
||||
.maple-code-blocks.mcb-theme-dark {
|
||||
background: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
}
|
||||
|
||||
.maple-code-blocks[data-theme="dark"] .mcb-header,
|
||||
.maple-code-blocks.mcb-theme-dark .mcb-header {
|
||||
background: linear-gradient(180deg, #2d2d30 0%, #252526 100%);
|
||||
border-bottom: 1px solid #3e3e42;
|
||||
}
|
||||
|
||||
.maple-code-blocks[data-theme="dark"] .mcb-sidebar,
|
||||
.maple-code-blocks.mcb-theme-dark .mcb-sidebar {
|
||||
background: #252526;
|
||||
border-right: 1px solid #3e3e42;
|
||||
}
|
||||
|
||||
.maple-code-blocks[data-theme="dark"] .mcb-editor,
|
||||
.maple-code-blocks.mcb-theme-dark .mcb-editor {
|
||||
background: #1e1e1e;
|
||||
}
|
||||
|
||||
/* Light Theme */
|
||||
.maple-code-blocks[data-theme="light"],
|
||||
.maple-code-blocks.mcb-theme-light {
|
||||
background: #ffffff;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.maple-code-blocks[data-theme="light"] .mcb-header,
|
||||
.maple-code-blocks.mcb-theme-light .mcb-header {
|
||||
background: linear-gradient(180deg, #f3f3f3 0%, #e8e8e8 100%);
|
||||
border-bottom: 1px solid #d4d4d4;
|
||||
}
|
||||
|
||||
.maple-code-blocks[data-theme="light"] .mcb-sidebar,
|
||||
.maple-code-blocks.mcb-theme-light .mcb-sidebar {
|
||||
background: #f3f3f3;
|
||||
border-right: 1px solid #e8e8e8;
|
||||
}
|
||||
|
||||
.maple-code-blocks[data-theme="light"] .mcb-editor,
|
||||
.maple-code-blocks.mcb-theme-light .mcb-editor {
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
.mcb-header {
|
||||
padding: 12px 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.mcb-title {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.mcb-repo-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex: 1;
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
.mcb-github-icon,
|
||||
.mcb-platform-icon {
|
||||
fill: currentColor;
|
||||
opacity: 0.7;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.mcb-repo-name {
|
||||
font-size: 13px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.mcb-controls {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.mcb-controls button {
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 4px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.mcb-controls button:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.mcb-controls button svg {
|
||||
fill: currentColor;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* Content Area */
|
||||
.mcb-content {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Sidebar */
|
||||
.mcb-sidebar {
|
||||
width: 240px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.mcb-search-box {
|
||||
padding: 8px;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.mcb-search-input {
|
||||
width: 100%;
|
||||
padding: 6px 8px;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 4px;
|
||||
color: inherit;
|
||||
font-size: 12px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.mcb-search-input:focus {
|
||||
border-color: #007acc;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* File List */
|
||||
.mcb-file-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.mcb-file-item {
|
||||
padding: 6px 12px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 13px;
|
||||
transition: background-color 0.1s;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.mcb-file-item:hover {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.mcb-file-item.active {
|
||||
background: rgba(0, 122, 204, 0.3);
|
||||
}
|
||||
|
||||
.mcb-file-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.mcb-file-name {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.mcb-file-size {
|
||||
font-size: 11px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
/* Folder styles */
|
||||
.mcb-folder .mcb-file-icon,
|
||||
.mcb-parent-folder .mcb-file-icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.mcb-folder {
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.mcb-folder:hover,
|
||||
.mcb-parent-folder:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.mcb-parent-folder {
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
padding-bottom: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.mcb-breadcrumb {
|
||||
padding: 8px 12px;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
font-size: 12px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.mcb-path-label {
|
||||
opacity: 0.6;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.mcb-current-path {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
/* Editor Area */
|
||||
.mcb-editor {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Tabs */
|
||||
.mcb-tabs {
|
||||
display: flex;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
overflow-x: auto;
|
||||
min-height: 35px;
|
||||
}
|
||||
|
||||
.mcb-tab {
|
||||
padding: 8px 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
cursor: pointer;
|
||||
border-right: 1px solid rgba(255, 255, 255, 0.05);
|
||||
font-size: 13px;
|
||||
white-space: nowrap;
|
||||
user-select: none;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mcb-tab:hover {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.mcb-tab.active {
|
||||
background: var(--editor-bg, #1e1e1e);
|
||||
border-bottom: 2px solid #007acc;
|
||||
}
|
||||
|
||||
.mcb-tab-close {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 2px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.mcb-tab-close:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Code Area */
|
||||
.mcb-code-area {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mcb-welcome {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.mcb-welcome svg {
|
||||
fill: currentColor;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.mcb-welcome h4 {
|
||||
margin: 0 0 8px 0;
|
||||
font-size: 18px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.mcb-welcome p {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* Code Container */
|
||||
.mcb-code-container {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.mcb-code-header {
|
||||
padding: 8px 16px;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.mcb-filename {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.mcb-copy-btn {
|
||||
padding: 4px 12px;
|
||||
background: rgba(0, 122, 204, 0.2);
|
||||
border: 1px solid #007acc;
|
||||
border-radius: 4px;
|
||||
color: #007acc;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.mcb-copy-btn:hover {
|
||||
background: rgba(0, 122, 204, 0.3);
|
||||
}
|
||||
|
||||
.mcb-copy-btn.copied {
|
||||
background: rgba(0, 255, 0, 0.2);
|
||||
border-color: #00ff00;
|
||||
color: #00ff00;
|
||||
}
|
||||
|
||||
/* Code Wrapper */
|
||||
.mcb-code-wrapper {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.mcb-code-wrapper pre {
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
tab-size: 4;
|
||||
}
|
||||
|
||||
.mcb-code-wrapper code {
|
||||
display: block;
|
||||
font-family: inherit;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
/* Line Numbers */
|
||||
.line-numbers .line-number {
|
||||
display: inline-block;
|
||||
width: 40px;
|
||||
text-align: right;
|
||||
padding-right: 12px;
|
||||
color: #858585;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.line-numbers .line-content {
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
/* Status Bar */
|
||||
.mcb-status-bar {
|
||||
padding: 4px 16px;
|
||||
background: rgba(0, 122, 204, 0.15);
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.mcb-status-text {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.mcb-file-info {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
/* Loading Spinner */
|
||||
.mcb-loading {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 32px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.mcb-spinner {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border: 2px solid rgba(255, 255, 255, 0.2);
|
||||
border-top-color: #007acc;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.mcb-loading span {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Error State */
|
||||
.mcb-error {
|
||||
padding: 16px;
|
||||
background: #ff5252;
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
margin: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Scrollbars */
|
||||
.mcb-file-list::-webkit-scrollbar,
|
||||
.mcb-code-wrapper::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
.mcb-file-list::-webkit-scrollbar-track,
|
||||
.mcb-code-wrapper::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.mcb-file-list::-webkit-scrollbar-thumb,
|
||||
.mcb-code-wrapper::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.mcb-file-list::-webkit-scrollbar-thumb:hover,
|
||||
.mcb-code-wrapper::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
/* Fullscreen Mode */
|
||||
.maple-code-blocks.fullscreen {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 999999;
|
||||
height: 100vh !important;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* Responsive Design */
|
||||
@media (max-width: 768px) {
|
||||
.mcb-sidebar {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.mcb-code-wrapper {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.line-numbers .line-number {
|
||||
width: 30px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.mcb-sidebar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mcb-header {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.mcb-repo-info {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
187
native/wordpress/maple-code-blocks/assets/css/prism.css
Normal file
187
native/wordpress/maple-code-blocks/assets/css/prism.css
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
/* PrismJS - Minimal syntax highlighting styles */
|
||||
/* Optimized for GitHub Code Viewer Plugin */
|
||||
|
||||
/* Base styles */
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
color: #d4d4d4;
|
||||
background: none;
|
||||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;
|
||||
font-size: 13px;
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
word-spacing: normal;
|
||||
word-break: normal;
|
||||
word-wrap: normal;
|
||||
line-height: 1.6;
|
||||
tab-size: 4;
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
/* Token colors - Dark theme default */
|
||||
.token.comment,
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
color: #6a9955;
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
color: #d4d4d4;
|
||||
}
|
||||
|
||||
.token.namespace {
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
.token.property,
|
||||
.token.tag,
|
||||
.token.boolean,
|
||||
.token.number,
|
||||
.token.constant,
|
||||
.token.symbol,
|
||||
.token.deleted {
|
||||
color: #b5cea8;
|
||||
}
|
||||
|
||||
.token.selector,
|
||||
.token.attr-name,
|
||||
.token.string,
|
||||
.token.char,
|
||||
.token.builtin,
|
||||
.token.inserted {
|
||||
color: #ce9178;
|
||||
}
|
||||
|
||||
.token.operator,
|
||||
.token.entity,
|
||||
.token.url,
|
||||
.language-css .token.string,
|
||||
.style .token.string {
|
||||
color: #d4d4d4;
|
||||
}
|
||||
|
||||
.token.atrule,
|
||||
.token.attr-value,
|
||||
.token.keyword {
|
||||
color: #569cd6;
|
||||
}
|
||||
|
||||
.token.function,
|
||||
.token.class-name {
|
||||
color: #dcdcaa;
|
||||
}
|
||||
|
||||
.token.regex,
|
||||
.token.important,
|
||||
.token.variable {
|
||||
color: #d16969;
|
||||
}
|
||||
|
||||
.token.important,
|
||||
.token.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
/* Light theme overrides */
|
||||
.maple-code-blocks[data-theme="light"] .token.comment,
|
||||
.maple-code-blocks[data-theme="light"] .token.prolog,
|
||||
.maple-code-blocks[data-theme="light"] .token.doctype,
|
||||
.maple-code-blocks[data-theme="light"] .token.cdata {
|
||||
color: #008000;
|
||||
}
|
||||
|
||||
.maple-code-blocks[data-theme="light"] .token.punctuation {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.maple-code-blocks[data-theme="light"] .token.property,
|
||||
.maple-code-blocks[data-theme="light"] .token.tag,
|
||||
.maple-code-blocks[data-theme="light"] .token.boolean,
|
||||
.maple-code-blocks[data-theme="light"] .token.number,
|
||||
.maple-code-blocks[data-theme="light"] .token.constant,
|
||||
.maple-code-blocks[data-theme="light"] .token.symbol {
|
||||
color: #098658;
|
||||
}
|
||||
|
||||
.maple-code-blocks[data-theme="light"] .token.selector,
|
||||
.maple-code-blocks[data-theme="light"] .token.attr-name,
|
||||
.maple-code-blocks[data-theme="light"] .token.string,
|
||||
.maple-code-blocks[data-theme="light"] .token.char,
|
||||
.maple-code-blocks[data-theme="light"] .token.builtin,
|
||||
.maple-code-blocks[data-theme="light"] .token.inserted {
|
||||
color: #a31515;
|
||||
}
|
||||
|
||||
.maple-code-blocks[data-theme="light"] .token.operator,
|
||||
.maple-code-blocks[data-theme="light"] .token.entity,
|
||||
.maple-code-blocks[data-theme="light"] .token.url,
|
||||
.maple-code-blocks[data-theme="light"] .language-css .token.string,
|
||||
.maple-code-blocks[data-theme="light"] .style .token.string {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.maple-code-blocks[data-theme="light"] .token.atrule,
|
||||
.maple-code-blocks[data-theme="light"] .token.attr-value,
|
||||
.maple-code-blocks[data-theme="light"] .token.keyword {
|
||||
color: #0000ff;
|
||||
}
|
||||
|
||||
.maple-code-blocks[data-theme="light"] .token.function {
|
||||
color: #795e26;
|
||||
}
|
||||
|
||||
.maple-code-blocks[data-theme="light"] .token.class-name {
|
||||
color: #267f99;
|
||||
}
|
||||
|
||||
.maple-code-blocks[data-theme="light"] .token.regex,
|
||||
.maple-code-blocks[data-theme="light"] .token.important,
|
||||
.maple-code-blocks[data-theme="light"] .token.variable {
|
||||
color: #e90;
|
||||
}
|
||||
|
||||
/* Line highlighting */
|
||||
.line-highlight {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin-top: 1em;
|
||||
background: linear-gradient(to right, rgba(255, 255, 255, .1) 70%, rgba(255, 255, 255, 0));
|
||||
pointer-events: none;
|
||||
line-height: inherit;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
/* Selection styling */
|
||||
pre[class*="language-"]::-moz-selection,
|
||||
pre[class*="language-"] ::-moz-selection,
|
||||
code[class*="language-"]::-moz-selection,
|
||||
code[class*="language-"] ::-moz-selection {
|
||||
text-shadow: none;
|
||||
background: #264f78;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::selection,
|
||||
pre[class*="language-"] ::selection,
|
||||
code[class*="language-"]::selection,
|
||||
code[class*="language-"] ::selection {
|
||||
text-shadow: none;
|
||||
background: #264f78;
|
||||
}
|
||||
|
||||
/* Light theme selection */
|
||||
.maple-code-blocks[data-theme="light"] pre[class*="language-"]::selection,
|
||||
.maple-code-blocks[data-theme="light"] pre[class*="language-"] ::selection,
|
||||
.maple-code-blocks[data-theme="light"] code[class*="language-"]::selection,
|
||||
.maple-code-blocks[data-theme="light"] code[class*="language-"] ::selection {
|
||||
background: #add6ff;
|
||||
}
|
||||
2
native/wordpress/maple-code-blocks/assets/index.php
Normal file
2
native/wordpress/maple-code-blocks/assets/index.php
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
<?php
|
||||
// Silence is golden.
|
||||
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
|
||||
);
|
||||
225
native/wordpress/maple-code-blocks/assets/js/block-variations.js
Normal file
225
native/wordpress/maple-code-blocks/assets/js/block-variations.js
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
/**
|
||||
* GitHub Code Viewer Block Variations
|
||||
* Provides pre-configured block patterns for common use cases
|
||||
*/
|
||||
|
||||
(function(blocks, domReady) {
|
||||
'use strict';
|
||||
|
||||
domReady(function() {
|
||||
// Register block variations
|
||||
blocks.registerBlockVariation('maple-code-blocks/code-block', {
|
||||
name: 'react-component',
|
||||
title: 'Maple: React Component',
|
||||
description: 'Display a React component from GitHub',
|
||||
icon: 'editor-code',
|
||||
attributes: {
|
||||
repository: 'facebook/react',
|
||||
theme: 'dark',
|
||||
height: '500px',
|
||||
showLineNumbers: true,
|
||||
initialFile: 'packages/react/src/React.js'
|
||||
},
|
||||
scope: ['inserter']
|
||||
});
|
||||
|
||||
blocks.registerBlockVariation('maple-code-blocks/code-block', {
|
||||
name: 'documentation-viewer',
|
||||
title: 'Maple: Documentation Viewer',
|
||||
description: 'Display README or documentation files',
|
||||
icon: 'media-document',
|
||||
attributes: {
|
||||
repository: '',
|
||||
theme: 'light',
|
||||
height: '400px',
|
||||
showLineNumbers: false,
|
||||
initialFile: 'README.md'
|
||||
},
|
||||
scope: ['inserter']
|
||||
});
|
||||
|
||||
blocks.registerBlockVariation('maple-code-blocks/code-block', {
|
||||
name: 'full-repository',
|
||||
title: 'Maple: Full Repository Browser',
|
||||
description: 'Browse entire repository with file tree',
|
||||
icon: 'category',
|
||||
attributes: {
|
||||
repository: '',
|
||||
theme: 'dark',
|
||||
height: '700px',
|
||||
showLineNumbers: true,
|
||||
initialFile: ''
|
||||
},
|
||||
scope: ['inserter']
|
||||
});
|
||||
|
||||
blocks.registerBlockVariation('maple-code-blocks/code-block', {
|
||||
name: 'code-snippet',
|
||||
title: 'Maple: Code Snippet',
|
||||
description: 'Display a specific code file',
|
||||
icon: 'editor-code',
|
||||
attributes: {
|
||||
repository: '',
|
||||
theme: 'monokai',
|
||||
height: '300px',
|
||||
showLineNumbers: true,
|
||||
initialFile: ''
|
||||
},
|
||||
scope: ['inserter']
|
||||
});
|
||||
|
||||
blocks.registerBlockVariation('maple-code-blocks/code-block', {
|
||||
name: 'tutorial-code',
|
||||
title: 'Maple: Tutorial Code',
|
||||
description: 'Perfect for coding tutorials and education',
|
||||
icon: 'welcome-learn-more',
|
||||
attributes: {
|
||||
repository: '',
|
||||
theme: 'solarized',
|
||||
height: '450px',
|
||||
showLineNumbers: true,
|
||||
title: 'Example Code'
|
||||
},
|
||||
scope: ['inserter']
|
||||
});
|
||||
|
||||
// Register block styles (additional styling options)
|
||||
blocks.registerBlockStyle('maple-code-blocks/code-block', {
|
||||
name: 'default',
|
||||
label: 'Default',
|
||||
isDefault: true
|
||||
});
|
||||
|
||||
blocks.registerBlockStyle('maple-code-blocks/code-block', {
|
||||
name: 'minimal',
|
||||
label: 'Minimal',
|
||||
className: 'is-style-minimal'
|
||||
});
|
||||
|
||||
blocks.registerBlockStyle('maple-code-blocks/code-block', {
|
||||
name: 'rounded',
|
||||
label: 'Rounded',
|
||||
className: 'is-style-rounded'
|
||||
});
|
||||
|
||||
blocks.registerBlockStyle('maple-code-blocks/code-block', {
|
||||
name: 'shadowed',
|
||||
label: 'Shadowed',
|
||||
className: 'is-style-shadowed'
|
||||
});
|
||||
|
||||
// Register block patterns for complete layouts
|
||||
if (wp.blockEditor && wp.blockEditor.registerBlockPattern) {
|
||||
// Code Comparison Pattern
|
||||
wp.blockEditor.registerBlockPattern('maple-code-blocks/code-comparison', {
|
||||
title: 'Maple: Code Comparison',
|
||||
description: 'Compare code from two different repositories',
|
||||
categories: ['maple-code-blocks'],
|
||||
content: `
|
||||
<!-- wp:columns -->
|
||||
<div class="wp-block-columns">
|
||||
<!-- wp:column -->
|
||||
<div class="wp-block-column">
|
||||
<!-- wp:heading {"level":3} -->
|
||||
<h3>Original Implementation</h3>
|
||||
<!-- /wp:heading -->
|
||||
<!-- wp:maple-code-blocks/code-block {"repository":"facebook/react","theme":"dark","height":"400px"} /-->
|
||||
</div>
|
||||
<!-- /wp:column -->
|
||||
<!-- wp:column -->
|
||||
<div class="wp-block-column">
|
||||
<!-- wp:heading {"level":3} -->
|
||||
<h3>Alternative Implementation</h3>
|
||||
<!-- /wp:heading -->
|
||||
<!-- wp:maple-code-blocks/code-block {"repository":"vuejs/vue","theme":"dark","height":"400px"} /-->
|
||||
</div>
|
||||
<!-- /wp:column -->
|
||||
</div>
|
||||
<!-- /wp:columns -->`
|
||||
});
|
||||
|
||||
// Tutorial Pattern
|
||||
wp.blockEditor.registerBlockPattern('maple-code-blocks/tutorial-layout', {
|
||||
title: 'Maple: Tutorial Layout',
|
||||
description: 'Code tutorial with explanation',
|
||||
categories: ['maple-code-blocks'],
|
||||
content: `
|
||||
<!-- wp:group {"backgroundColor":"light-gray","padding":{"top":"40px","right":"40px","bottom":"40px","left":"40px"}} -->
|
||||
<div class="wp-block-group has-light-gray-background-color has-background" style="padding-top:40px;padding-right:40px;padding-bottom:40px;padding-left:40px">
|
||||
<!-- wp:heading -->
|
||||
<h2>Code Tutorial</h2>
|
||||
<!-- /wp:heading -->
|
||||
<!-- wp:paragraph -->
|
||||
<p>Here's an example of how to implement this feature:</p>
|
||||
<!-- /wp:paragraph -->
|
||||
<!-- wp:maple-code-blocks/code-block {"repository":"","theme":"light","height":"350px","showLineNumbers":true,"title":"Step 1: Basic Setup"} /-->
|
||||
<!-- wp:paragraph -->
|
||||
<p>Now let's add some advanced functionality:</p>
|
||||
<!-- /wp:paragraph -->
|
||||
<!-- wp:maple-code-blocks/code-block {"repository":"","theme":"light","height":"350px","showLineNumbers":true,"title":"Step 2: Advanced Features"} /-->
|
||||
</div>
|
||||
<!-- /wp:group -->`
|
||||
});
|
||||
|
||||
// Documentation Pattern
|
||||
wp.blockEditor.registerBlockPattern('maple-code-blocks/documentation', {
|
||||
title: 'Maple: Documentation Section',
|
||||
description: 'Documentation with embedded code',
|
||||
categories: ['maple-code-blocks'],
|
||||
content: `
|
||||
<!-- wp:heading -->
|
||||
<h2>API Documentation</h2>
|
||||
<!-- /wp:heading -->
|
||||
<!-- wp:paragraph -->
|
||||
<p>This library provides a simple interface for working with the API.</p>
|
||||
<!-- /wp:paragraph -->
|
||||
<!-- wp:heading {"level":3} -->
|
||||
<h3>Installation</h3>
|
||||
<!-- /wp:heading -->
|
||||
<!-- wp:code -->
|
||||
<pre class="wp-block-code"><code>npm install example-library</code></pre>
|
||||
<!-- /wp:code -->
|
||||
<!-- wp:heading {"level":3} -->
|
||||
<h3>Source Code</h3>
|
||||
<!-- /wp:heading -->
|
||||
<!-- wp:maple-code-blocks/code-block {"repository":"","theme":"dark","height":"500px","showLineNumbers":true} /-->
|
||||
<!-- wp:heading {"level":3} -->
|
||||
<h3>Examples</h3>
|
||||
<!-- /wp:heading -->
|
||||
<!-- wp:maple-code-blocks/code-block {"repository":"","theme":"dark","height":"300px","showLineNumbers":false,"initialFile":"examples/basic.js"} /-->`
|
||||
});
|
||||
|
||||
// Showcase Pattern
|
||||
wp.blockEditor.registerBlockPattern('maple-code-blocks/showcase', {
|
||||
title: 'Maple: Project Showcase',
|
||||
description: 'Showcase a GitHub project',
|
||||
categories: ['maple-code-blocks'],
|
||||
content: `
|
||||
<!-- wp:cover {"url":"","dimRatio":50,"align":"full"} -->
|
||||
<div class="wp-block-cover alignfull">
|
||||
<div class="wp-block-cover__inner-container">
|
||||
<!-- wp:heading {"textAlign":"center","level":1} -->
|
||||
<h1 class="has-text-align-center">Project Name</h1>
|
||||
<!-- /wp:heading -->
|
||||
<!-- wp:paragraph {"align":"center"} -->
|
||||
<p class="has-text-align-center">A brief description of your amazing project</p>
|
||||
<!-- /wp:paragraph -->
|
||||
<!-- wp:buttons {"layout":{"type":"flex","justifyContent":"center"}} -->
|
||||
<div class="wp-block-buttons">
|
||||
<!-- wp:button -->
|
||||
<div class="wp-block-button"><a class="wp-block-button__link">View on GitHub</a></div>
|
||||
<!-- /wp:button -->
|
||||
</div>
|
||||
<!-- /wp:buttons -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- /wp:cover -->
|
||||
<!-- wp:maple-code-blocks/code-block {"repository":"","theme":"dark","height":"600px","showLineNumbers":true,"align":"full"} /-->`
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
})(
|
||||
window.wp.blocks,
|
||||
window.wp.domReady
|
||||
);
|
||||
2
native/wordpress/maple-code-blocks/assets/js/index.php
Normal file
2
native/wordpress/maple-code-blocks/assets/js/index.php
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
<?php
|
||||
// Silence is golden.
|
||||
647
native/wordpress/maple-code-blocks/assets/js/mcb-script.js
Normal file
647
native/wordpress/maple-code-blocks/assets/js/mcb-script.js
Normal file
|
|
@ -0,0 +1,647 @@
|
|||
/**
|
||||
* GitHub Code Viewer - Main JavaScript
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
'use strict';
|
||||
|
||||
// GitHub Code Viewer Class
|
||||
class GitHubCodeViewer {
|
||||
constructor(element) {
|
||||
this.$element = $(element);
|
||||
this.repo = this.$element.data('repo');
|
||||
this.theme = this.$element.data('theme');
|
||||
this.showLineNumbers = this.$element.data('show-line-numbers');
|
||||
this.initialFile = this.$element.data('initial-file');
|
||||
|
||||
this.files = [];
|
||||
this.openTabs = [];
|
||||
this.activeTab = null;
|
||||
this.fileCache = {};
|
||||
this.activeRequests = []; // Track active AJAX requests
|
||||
this.currentPath = ''; // Track current folder path
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.bindEvents();
|
||||
this.loadRepositoryFiles();
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
// Search functionality with debouncing
|
||||
let searchTimeout;
|
||||
this.$element.on('input', '.mcb-search-input', (e) => {
|
||||
clearTimeout(searchTimeout);
|
||||
searchTimeout = setTimeout(() => {
|
||||
this.filterFiles($(e.target).val());
|
||||
}, 300); // Debounce for 300ms
|
||||
});
|
||||
|
||||
// File/folder selection
|
||||
this.$element.on('click', '.mcb-file-item', (e) => {
|
||||
const $item = $(e.currentTarget);
|
||||
const isFolder = $item.data('is-folder');
|
||||
const path = $item.data('path');
|
||||
|
||||
if (isFolder) {
|
||||
// Navigate to folder
|
||||
this.loadRepositoryFiles(path);
|
||||
} else {
|
||||
// Load file
|
||||
this.loadFile(path);
|
||||
}
|
||||
});
|
||||
|
||||
// Tab management
|
||||
this.$element.on('click', '.mcb-tab', (e) => {
|
||||
const $tab = $(e.currentTarget);
|
||||
const filePath = $tab.data('path');
|
||||
this.switchToTab(filePath);
|
||||
});
|
||||
|
||||
this.$element.on('click', '.mcb-tab-close', (e) => {
|
||||
e.stopPropagation();
|
||||
const $tab = $(e.target).closest('.mcb-tab');
|
||||
const filePath = $tab.data('path');
|
||||
this.closeTab(filePath);
|
||||
});
|
||||
|
||||
// Copy button
|
||||
this.$element.on('click', '.mcb-copy-btn', (e) => {
|
||||
this.copyCode($(e.target));
|
||||
});
|
||||
|
||||
// Home button - go to root
|
||||
this.$element.on('click', '.mcb-home-btn', () => {
|
||||
this.loadRepositoryFiles(''); // Load root
|
||||
});
|
||||
|
||||
// Refresh button
|
||||
this.$element.on('click', '.mcb-refresh-btn', () => {
|
||||
this.refreshFiles();
|
||||
});
|
||||
|
||||
// Fullscreen toggle
|
||||
this.$element.on('click', '.mcb-fullscreen-btn', () => {
|
||||
this.toggleFullscreen();
|
||||
});
|
||||
}
|
||||
|
||||
loadRepositoryFiles(path = '') {
|
||||
console.log('MCB: Loading repository files for:', this.repo, 'path:', path);
|
||||
const $fileList = this.$element.find('.mcb-file-list');
|
||||
|
||||
// Update current path
|
||||
this.currentPath = path;
|
||||
|
||||
// Show loading indicator
|
||||
$fileList.html('<div class="mcb-loading"><div class="mcb-spinner"></div><span>Loading files...</span></div>');
|
||||
|
||||
// Abort any pending requests
|
||||
this.abortActiveRequests();
|
||||
|
||||
console.log('MCB: Making AJAX request to:', mcb_ajax.ajax_url);
|
||||
const request = $.ajax({
|
||||
url: mcb_ajax.ajax_url,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'mcb_get_repo_files',
|
||||
repo: this.repo,
|
||||
path: path,
|
||||
nonce: mcb_ajax.nonce
|
||||
},
|
||||
success: (response) => {
|
||||
console.log('MCB: AJAX response:', response);
|
||||
this.removeRequest(request);
|
||||
if (response.success) {
|
||||
console.log('MCB: Files loaded:', response.data);
|
||||
this.files = response.data;
|
||||
this.renderFileList();
|
||||
|
||||
// Load initial file if specified
|
||||
if (this.initialFile) {
|
||||
const file = this.files.find(f => f.path === this.initialFile);
|
||||
if (file) {
|
||||
this.loadFile(this.initialFile);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.error('MCB: Error:', response.data);
|
||||
$fileList.html('<div class="mcb-error">' + response.data + '</div>');
|
||||
}
|
||||
},
|
||||
error: (xhr, status, error) => {
|
||||
console.error('MCB: AJAX failed:', status, error);
|
||||
this.removeRequest(request);
|
||||
$fileList.html('<div class="mcb-error">Failed to load repository files: ' + error + '</div>');
|
||||
}
|
||||
});
|
||||
|
||||
this.activeRequests.push(request);
|
||||
}
|
||||
|
||||
renderFileList() {
|
||||
const $fileList = this.$element.find('.mcb-file-list');
|
||||
$fileList.empty();
|
||||
|
||||
// Add current path breadcrumb if not at root
|
||||
if (this.currentPath) {
|
||||
const $breadcrumb = $('<div class="mcb-breadcrumb">');
|
||||
$breadcrumb.append('<span class="mcb-path-label">Path: </span>');
|
||||
$breadcrumb.append('<span class="mcb-current-path">/' + this.escapeHtml(this.currentPath) + '</span>');
|
||||
$fileList.append($breadcrumb);
|
||||
}
|
||||
|
||||
// Render files and folders
|
||||
this.files.forEach(file => {
|
||||
const $item = $('<div class="mcb-file-item">')
|
||||
.attr('data-path', file.path)
|
||||
.attr('data-name', file.name.toLowerCase())
|
||||
.attr('data-is-folder', file.is_folder || false);
|
||||
|
||||
// Add appropriate icon
|
||||
let icon;
|
||||
if (file.type === 'parent') {
|
||||
icon = '⬆'; // Up arrow for parent
|
||||
$item.addClass('mcb-parent-folder');
|
||||
} else if (file.is_folder) {
|
||||
icon = '📁'; // Folder icon
|
||||
$item.addClass('mcb-folder');
|
||||
} else {
|
||||
icon = this.getFileIcon(file.type);
|
||||
$item.addClass('mcb-file');
|
||||
}
|
||||
|
||||
$item.append('<span class="mcb-file-icon">' + icon + '</span>');
|
||||
$item.append('<span class="mcb-file-name">' + this.escapeHtml(file.name) + '</span>');
|
||||
|
||||
// Add file size for files only
|
||||
if (!file.is_folder) {
|
||||
const sizeStr = this.formatFileSize(file.size);
|
||||
$item.append('<span class="mcb-file-size">' + sizeStr + '</span>');
|
||||
}
|
||||
|
||||
$fileList.append($item);
|
||||
});
|
||||
}
|
||||
|
||||
organizeFileTree(files) {
|
||||
const tree = {};
|
||||
files.forEach(file => {
|
||||
const parts = file.path.split('/');
|
||||
let current = tree;
|
||||
|
||||
parts.forEach((part, index) => {
|
||||
if (index === parts.length - 1) {
|
||||
// It's a file
|
||||
current[part] = file;
|
||||
} else {
|
||||
// It's a directory
|
||||
if (!current[part]) {
|
||||
current[part] = {};
|
||||
}
|
||||
current = current[part];
|
||||
}
|
||||
});
|
||||
});
|
||||
return tree;
|
||||
}
|
||||
|
||||
filterFiles(searchTerm) {
|
||||
const $items = this.$element.find('.mcb-file-item');
|
||||
const term = searchTerm.toLowerCase();
|
||||
|
||||
$items.each((index, item) => {
|
||||
const $item = $(item);
|
||||
const fileName = $item.data('name');
|
||||
|
||||
if (!term || fileName.includes(term)) {
|
||||
$item.show();
|
||||
} else {
|
||||
$item.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadFile(filePath) {
|
||||
// Limit cache size to prevent memory issues
|
||||
this.limitCacheSize();
|
||||
|
||||
// Check if file is already in cache
|
||||
if (this.fileCache[filePath]) {
|
||||
this.displayFile(filePath, this.fileCache[filePath]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Update status
|
||||
this.updateStatus('Loading file...');
|
||||
|
||||
const request = $.ajax({
|
||||
url: mcb_ajax.ajax_url,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'mcb_load_file',
|
||||
repo: this.repo,
|
||||
file_path: filePath,
|
||||
nonce: mcb_ajax.nonce
|
||||
},
|
||||
success: (response) => {
|
||||
this.removeRequest(request);
|
||||
if (response.success) {
|
||||
this.fileCache[filePath] = response.data;
|
||||
this.displayFile(filePath, response.data);
|
||||
this.updateStatus('Ready');
|
||||
} else {
|
||||
this.showError('Failed to load file: ' + response.data);
|
||||
this.updateStatus('Error loading file');
|
||||
}
|
||||
},
|
||||
error: () => {
|
||||
this.removeRequest(request);
|
||||
this.showError('Network error while loading file');
|
||||
this.updateStatus('Network error');
|
||||
}
|
||||
});
|
||||
|
||||
this.activeRequests.push(request);
|
||||
}
|
||||
|
||||
displayFile(filePath, fileData) {
|
||||
// Store in cache
|
||||
this.fileCache[filePath] = fileData;
|
||||
|
||||
// Limit number of open tabs to prevent memory issues
|
||||
const maxTabs = 10;
|
||||
|
||||
// Add to tabs if not already open
|
||||
if (!this.openTabs.includes(filePath)) {
|
||||
// Check tab limit
|
||||
if (this.openTabs.length >= maxTabs) {
|
||||
// Close the oldest tab
|
||||
const oldestTab = this.openTabs[0];
|
||||
this.closeTab(oldestTab);
|
||||
}
|
||||
|
||||
this.openTabs.push(filePath);
|
||||
this.addTab(filePath, fileData.filename);
|
||||
}
|
||||
|
||||
// Only switch to tab if not already active
|
||||
if (this.activeTab !== filePath) {
|
||||
this.switchToTab(filePath);
|
||||
} else {
|
||||
// Just update the content if already active
|
||||
const $codeArea = this.$element.find('.mcb-code-area');
|
||||
const safeContent = this.createSafeCodeDisplay(fileData.content, fileData.filename);
|
||||
$codeArea.html(safeContent);
|
||||
|
||||
// Apply syntax highlighting
|
||||
if (typeof Prism !== 'undefined') {
|
||||
Prism.highlightAll();
|
||||
}
|
||||
|
||||
// Update status
|
||||
const fileSize = this.formatFileSize(fileData.content.length);
|
||||
const lineCount = fileData.content.split('\n').length;
|
||||
this.$element.find('.mcb-file-info').text(fileData.filename + ' • ' + lineCount + ' lines • ' + fileSize);
|
||||
}
|
||||
|
||||
// Display content
|
||||
const $codeArea = this.$element.find('.mcb-code-area');
|
||||
|
||||
// Create safe HTML content
|
||||
const safeContent = this.createSafeCodeDisplay(fileData.content, fileData.filename);
|
||||
$codeArea.html(safeContent);
|
||||
|
||||
// Apply syntax highlighting if Prism is loaded
|
||||
if (typeof Prism !== 'undefined') {
|
||||
Prism.highlightAll();
|
||||
}
|
||||
|
||||
// Mark file as active in sidebar
|
||||
this.$element.find('.mcb-file-item').removeClass('active');
|
||||
this.$element.find('.mcb-file-item[data-path="' + filePath + '"]').addClass('active');
|
||||
|
||||
// Update file info
|
||||
const file = this.files.find(f => f.path === filePath);
|
||||
if (file) {
|
||||
this.updateFileInfo(file);
|
||||
}
|
||||
}
|
||||
|
||||
createSafeCodeDisplay(content, filename) {
|
||||
// The content is already escaped by PHP, but we'll double-check
|
||||
const $container = $('<div class="mcb-code-container">');
|
||||
|
||||
// Header
|
||||
const $header = $('<div class="mcb-code-header">');
|
||||
$header.append($('<span class="mcb-filename">').text(filename));
|
||||
|
||||
// Copy button - store content in data, not attribute
|
||||
const $copyBtn = $('<button class="mcb-copy-btn">Copy</button>');
|
||||
$copyBtn.data('content', content); // Use data() instead of attr()
|
||||
$header.append($copyBtn);
|
||||
|
||||
$container.append($header);
|
||||
|
||||
// Code wrapper
|
||||
const $wrapper = $('<div class="mcb-code-wrapper">');
|
||||
const language = this.detectLanguage(filename);
|
||||
|
||||
// Create pre/code structure
|
||||
const $pre = $('<pre>').addClass('line-numbers');
|
||||
const $code = $('<code>').addClass('language-' + language);
|
||||
|
||||
// CRITICAL: Ensure content is text, not HTML
|
||||
$code.text(content);
|
||||
|
||||
$pre.append($code);
|
||||
$wrapper.append($pre);
|
||||
$container.append($wrapper);
|
||||
|
||||
return $container;
|
||||
}
|
||||
|
||||
addTab(filePath, filename) {
|
||||
const $tabs = this.$element.find('.mcb-tabs');
|
||||
|
||||
const $tab = $('<div class="mcb-tab">')
|
||||
.attr('data-path', filePath);
|
||||
|
||||
$tab.append('<span class="mcb-tab-title">' + this.escapeHtml(filename) + '</span>');
|
||||
$tab.append('<span class="mcb-tab-close">×</span>');
|
||||
|
||||
$tabs.append($tab);
|
||||
}
|
||||
|
||||
switchToTab(filePath) {
|
||||
// Prevent switching if already active
|
||||
if (this.activeTab === filePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.activeTab = filePath;
|
||||
|
||||
// Update tab states
|
||||
this.$element.find('.mcb-tab').removeClass('active');
|
||||
this.$element.find('.mcb-tab[data-path="' + filePath + '"]').addClass('active');
|
||||
|
||||
// Load file content if cached, otherwise just display the tab
|
||||
if (this.fileCache[filePath]) {
|
||||
// Display cached content without calling displayFile
|
||||
const $codeArea = this.$element.find('.mcb-code-area');
|
||||
const fileData = this.fileCache[filePath];
|
||||
const safeContent = this.createSafeCodeDisplay(fileData.content, fileData.filename);
|
||||
$codeArea.html(safeContent);
|
||||
|
||||
// Apply syntax highlighting if Prism is loaded
|
||||
if (typeof Prism !== 'undefined') {
|
||||
Prism.highlightAll();
|
||||
}
|
||||
|
||||
// Update status
|
||||
const fileSize = this.formatFileSize(fileData.content.length);
|
||||
const lineCount = fileData.content.split('\n').length;
|
||||
this.$element.find('.mcb-file-info').text(fileData.filename + ' • ' + lineCount + ' lines • ' + fileSize);
|
||||
}
|
||||
}
|
||||
|
||||
closeTab(filePath) {
|
||||
// Remove from open tabs
|
||||
const index = this.openTabs.indexOf(filePath);
|
||||
if (index > -1) {
|
||||
this.openTabs.splice(index, 1);
|
||||
}
|
||||
|
||||
// Remove tab element
|
||||
this.$element.find('.mcb-tab[data-path="' + filePath + '"]').remove();
|
||||
|
||||
// If this was the active tab, switch to another
|
||||
if (this.activeTab === filePath) {
|
||||
if (this.openTabs.length > 0) {
|
||||
this.switchToTab(this.openTabs[this.openTabs.length - 1]);
|
||||
} else {
|
||||
// Show welcome screen
|
||||
this.showWelcome();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
copyCode($button) {
|
||||
const content = $button.data('content'); // Use data() instead of attr()
|
||||
|
||||
if (!content) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create temporary textarea
|
||||
const $temp = $('<textarea>');
|
||||
$temp.val(content);
|
||||
$('body').append($temp);
|
||||
$temp.select();
|
||||
|
||||
try {
|
||||
document.execCommand('copy');
|
||||
$button.text('Copied!').addClass('copied');
|
||||
setTimeout(() => {
|
||||
$button.text('Copy').removeClass('copied');
|
||||
}, 2000);
|
||||
} catch (err) {
|
||||
console.error('Failed to copy:', err);
|
||||
}
|
||||
|
||||
$temp.remove();
|
||||
}
|
||||
|
||||
refreshFiles() {
|
||||
// Abort any pending requests first
|
||||
this.abortActiveRequests();
|
||||
|
||||
// Clear cache
|
||||
this.fileCache = {};
|
||||
|
||||
// Reload files at current path
|
||||
this.loadRepositoryFiles(this.currentPath);
|
||||
this.updateStatus('Repository refreshed');
|
||||
}
|
||||
|
||||
toggleFullscreen() {
|
||||
this.$element.toggleClass('fullscreen');
|
||||
}
|
||||
|
||||
showWelcome() {
|
||||
const $codeArea = this.$element.find('.mcb-code-area');
|
||||
const welcome = `
|
||||
<div class="mcb-welcome">
|
||||
<svg viewBox="0 0 24 24" width="64" height="64">
|
||||
<path d="M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0l4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z"/>
|
||||
</svg>
|
||||
<h4>GitHub Code Viewer</h4>
|
||||
<p>Select a file from the sidebar to view its content</p>
|
||||
</div>
|
||||
`;
|
||||
$codeArea.html(welcome);
|
||||
}
|
||||
|
||||
showError(message) {
|
||||
const $codeArea = this.$element.find('.mcb-code-area');
|
||||
$codeArea.html('<div class="mcb-error">' + this.escapeHtml(message) + '</div>');
|
||||
}
|
||||
|
||||
updateStatus(text) {
|
||||
this.$element.find('.mcb-status-text').text(text);
|
||||
}
|
||||
|
||||
updateFileInfo(file) {
|
||||
const info = file.name + ' • ' + this.formatFileSize(file.size) + ' • ' + file.type;
|
||||
this.$element.find('.mcb-file-info').text(info);
|
||||
}
|
||||
|
||||
formatFileSize(bytes) {
|
||||
if (bytes === 0) return '0 B';
|
||||
const k = 1024;
|
||||
const sizes = ['B', 'KB', 'MB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
detectLanguage(filename) {
|
||||
const ext = filename.split('.').pop().toLowerCase();
|
||||
const languageMap = {
|
||||
'js': 'javascript',
|
||||
'jsx': 'jsx',
|
||||
'ts': 'typescript',
|
||||
'tsx': 'tsx',
|
||||
'py': 'python',
|
||||
'rb': 'ruby',
|
||||
'php': 'php',
|
||||
'java': 'java',
|
||||
'c': 'c',
|
||||
'cpp': 'cpp',
|
||||
'cs': 'csharp',
|
||||
'go': 'go',
|
||||
'rs': 'rust',
|
||||
'swift': 'swift',
|
||||
'kt': 'kotlin',
|
||||
'scala': 'scala',
|
||||
'r': 'r',
|
||||
'sql': 'sql',
|
||||
'sh': 'bash',
|
||||
'yml': 'yaml',
|
||||
'json': 'json',
|
||||
'xml': 'xml',
|
||||
'html': 'html',
|
||||
'css': 'css',
|
||||
'scss': 'scss',
|
||||
'md': 'markdown'
|
||||
};
|
||||
|
||||
return languageMap[ext] || 'plain';
|
||||
}
|
||||
|
||||
getFileIcon(type) {
|
||||
const icons = {
|
||||
'javascript': '📜',
|
||||
'python': '🐍',
|
||||
'php': '🐘',
|
||||
'java': '☕',
|
||||
'cpp': '⚙️',
|
||||
'go': '🐹',
|
||||
'rust': '🦀',
|
||||
'ruby': '💎',
|
||||
'html': '🌐',
|
||||
'css': '🎨',
|
||||
'json': '📋',
|
||||
'markdown': '📝',
|
||||
'default': '📄'
|
||||
};
|
||||
|
||||
return icons[type] || icons.default;
|
||||
}
|
||||
|
||||
escapeHtml(text) {
|
||||
const map = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": '''
|
||||
};
|
||||
|
||||
return text.replace(/[&<>"']/g, m => map[m]);
|
||||
}
|
||||
|
||||
limitCacheSize() {
|
||||
// Limit cache to 20 files to prevent memory issues
|
||||
const maxCacheSize = 20;
|
||||
const cacheKeys = Object.keys(this.fileCache);
|
||||
|
||||
if (cacheKeys.length >= maxCacheSize) {
|
||||
// Remove oldest cached files (FIFO)
|
||||
const toRemove = cacheKeys.slice(0, cacheKeys.length - maxCacheSize + 1);
|
||||
toRemove.forEach(key => {
|
||||
delete this.fileCache[key];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
cleanupBeforeUnload() {
|
||||
// Clean up event listeners and large objects
|
||||
this.$element.off();
|
||||
this.abortActiveRequests();
|
||||
this.fileCache = null;
|
||||
this.files = null;
|
||||
this.openTabs = null;
|
||||
}
|
||||
|
||||
abortActiveRequests() {
|
||||
// Abort all pending AJAX requests
|
||||
if (this.activeRequests && this.activeRequests.length > 0) {
|
||||
this.activeRequests.forEach(request => {
|
||||
if (request && request.abort) {
|
||||
request.abort();
|
||||
}
|
||||
});
|
||||
this.activeRequests = [];
|
||||
}
|
||||
}
|
||||
|
||||
removeRequest(request) {
|
||||
const index = this.activeRequests.indexOf(request);
|
||||
if (index > -1) {
|
||||
this.activeRequests.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize all viewers on page
|
||||
$(document).ready(() => {
|
||||
console.log('MCB: Document ready, looking for .maple-code-blocks elements');
|
||||
const viewers = [];
|
||||
|
||||
$('.maple-code-blocks').each(function() {
|
||||
console.log('MCB: Initializing viewer for element:', this);
|
||||
try {
|
||||
const viewer = new GitHubCodeViewer(this);
|
||||
viewers.push(viewer);
|
||||
console.log('MCB: Viewer initialized successfully');
|
||||
} catch (error) {
|
||||
console.error('MCB: Error initializing viewer:', error);
|
||||
}
|
||||
});
|
||||
|
||||
console.log('MCB: Total viewers initialized:', viewers.length);
|
||||
|
||||
// Cleanup on page unload to prevent memory leaks
|
||||
$(window).on('beforeunload', () => {
|
||||
viewers.forEach(viewer => {
|
||||
if (viewer && viewer.cleanupBeforeUnload) {
|
||||
viewer.cleanupBeforeUnload();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
182
native/wordpress/maple-code-blocks/assets/js/prism.js
Normal file
182
native/wordpress/maple-code-blocks/assets/js/prism.js
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
/* PrismJS - Minimal Core for GitHub Code Viewer */
|
||||
/* This is a simplified version focused on safety and basic highlighting */
|
||||
|
||||
(function(){
|
||||
|
||||
if (typeof self === 'undefined' || !self.Prism || !self.document) {
|
||||
return;
|
||||
}
|
||||
|
||||
var Prism = window.Prism = {
|
||||
languages: {},
|
||||
|
||||
// Simplified tokenization with infinite loop prevention
|
||||
tokenize: function(text, grammar) {
|
||||
// Prevent tokenizing huge files
|
||||
if (text.length > 100000) {
|
||||
return [text]; // Return as plain text for very large files
|
||||
}
|
||||
|
||||
var tokens = [];
|
||||
var rest = text;
|
||||
var maxIterations = 10000; // Prevent infinite loops
|
||||
var iterations = 0;
|
||||
|
||||
while (rest.length > 0 && iterations < maxIterations) {
|
||||
iterations++;
|
||||
var matchFound = false;
|
||||
|
||||
for (var token in grammar) {
|
||||
if (!grammar.hasOwnProperty(token) || !grammar[token]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var pattern = grammar[token];
|
||||
if (pattern instanceof RegExp) {
|
||||
var matches = rest.match(pattern);
|
||||
|
||||
if (matches && matches.index === 0) {
|
||||
matchFound = true;
|
||||
tokens.push({
|
||||
type: token,
|
||||
content: matches[0]
|
||||
});
|
||||
rest = rest.substring(matches[0].length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no match found, consume one character as plain text
|
||||
if (!matchFound) {
|
||||
if (tokens.length > 0 && typeof tokens[tokens.length - 1] === 'string') {
|
||||
tokens[tokens.length - 1] += rest.charAt(0);
|
||||
} else {
|
||||
tokens.push(rest.charAt(0));
|
||||
}
|
||||
rest = rest.substring(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Add any remaining text
|
||||
if (rest.length > 0) {
|
||||
tokens.push(rest);
|
||||
}
|
||||
|
||||
return tokens;
|
||||
},
|
||||
|
||||
// Highlight element
|
||||
highlightElement: function(element) {
|
||||
var language = element.className.match(/language-(\w+)/);
|
||||
if (!language) return;
|
||||
|
||||
language = language[1];
|
||||
var grammar = Prism.languages[language];
|
||||
|
||||
if (!grammar) return;
|
||||
|
||||
// Get text content (already HTML escaped by PHP)
|
||||
var code = element.textContent;
|
||||
|
||||
// Simple tokenization
|
||||
var tokens = Prism.tokenize(code, grammar);
|
||||
|
||||
// Build highlighted HTML (safe because content is already escaped)
|
||||
var highlighted = tokens.map(function(token) {
|
||||
if (typeof token === 'string') {
|
||||
return token;
|
||||
}
|
||||
return '<span class="token ' + token.type + '">' + token.content + '</span>';
|
||||
}).join('');
|
||||
|
||||
element.innerHTML = highlighted;
|
||||
},
|
||||
|
||||
// Highlight all code blocks
|
||||
highlightAll: function() {
|
||||
var elements = document.querySelectorAll('code[class*="language-"], [class*="language-"] code');
|
||||
for (var i = 0, element; element = elements[i++];) {
|
||||
Prism.highlightElement(element);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Define basic grammars for common languages
|
||||
Prism.languages.javascript = {
|
||||
'comment': /\/\/.*|\/\*[\s\S]*?\*\//,
|
||||
'string': /(["'])(?:\\.|(?!\1)[^\\\r\n])*\1/,
|
||||
'keyword': /\b(?:var|let|const|function|return|if|else|for|while|do|switch|case|break|continue|typeof|instanceof|new|this|throw|try|catch|finally|async|await|class|extends|super|import|export|default|yield)\b/,
|
||||
'boolean': /\b(?:true|false)\b/,
|
||||
'number': /\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i,
|
||||
'function': /[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*(?=\s*\()/,
|
||||
'operator': /[+\-*/%=!<>&|^~?:]+/,
|
||||
'punctuation': /[{}[\];(),.:]/
|
||||
};
|
||||
|
||||
Prism.languages.python = {
|
||||
'comment': /#.*/,
|
||||
'string': /(["'])(?:\\.|(?!\1)[^\\\r\n])*\1/,
|
||||
'keyword': /\b(?:and|as|assert|async|await|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|not|or|pass|print|raise|return|try|while|with|yield)\b/,
|
||||
'boolean': /\b(?:True|False|None)\b/,
|
||||
'number': /\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?j?/i,
|
||||
'operator': /[+\-*/%=!<>&|^~]+/,
|
||||
'punctuation': /[{}[\];(),.:]/
|
||||
};
|
||||
|
||||
Prism.languages.php = {
|
||||
'comment': /\/\/.*|\/\*[\s\S]*?\*\/|#.*/,
|
||||
'string': /(["'])(?:\\.|(?!\1)[^\\\r\n])*\1/,
|
||||
'keyword': /\b(?:abstract|and|array|as|break|callable|case|catch|class|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|eval|exit|extends|final|finally|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|namespace|new|or|print|private|protected|public|require|require_once|return|static|switch|throw|trait|try|unset|use|var|while|xor|yield)\b/i,
|
||||
'boolean': /\b(?:false|true)\b/i,
|
||||
'variable': /\$\w+/,
|
||||
'number': /\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i,
|
||||
'operator': /[+\-*/%=!<>&|^~?:]+/,
|
||||
'punctuation': /[{}[\];(),.:]/
|
||||
};
|
||||
|
||||
Prism.languages.html = Prism.languages.xml = {
|
||||
'comment': /<!--[\s\S]*?-->/,
|
||||
'tag': {
|
||||
pattern: /<\/?[^\s>\/]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\.|(?!\1)[^\\])*\1|[^\s'">=]+))?)*\s*\/?>/i,
|
||||
inside: {
|
||||
'punctuation': /^<\/?|\/?>$/,
|
||||
'attr-name': /[^\s>\/]+/,
|
||||
'attr-value': /=(?:("|')(?:\\.|(?!\1)[^\\])*\1|[^\s'">=]+)/i
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Prism.languages.css = {
|
||||
'comment': /\/\*[\s\S]*?\*\//,
|
||||
'atrule': /@[\w-]+?.*?(?:;|(?=\s*\{))/i,
|
||||
'url': /url\((?:(["'])(?:\\.|(?!\1)[^\\\r\n])*\1|.*?)\)/i,
|
||||
'selector': /[^{}\s][^{}]*(?=\s*\{)/,
|
||||
'string': /(["'])(?:\\.|(?!\1)[^\\\r\n])*\1/,
|
||||
'property': /[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*(?=\s*:)/i,
|
||||
'important': /!important\b/i,
|
||||
'punctuation': /[(){};:]/
|
||||
};
|
||||
|
||||
Prism.languages.json = {
|
||||
'property': /"(?:\\.|[^\\"\r\n])*"(?=\s*:)/i,
|
||||
'string': /"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,
|
||||
'number': /\b0x[\dA-Fa-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee][+-]?\d+)?/,
|
||||
'punctuation': /[{}[\]);,]/,
|
||||
'operator': /:/g,
|
||||
'boolean': /\b(?:true|false)\b/i,
|
||||
'null': /\bnull\b/i
|
||||
};
|
||||
|
||||
// Language aliases
|
||||
Prism.languages.js = Prism.languages.javascript;
|
||||
Prism.languages.py = Prism.languages.python;
|
||||
|
||||
// Auto-initialize
|
||||
if (document.readyState !== 'loading') {
|
||||
setTimeout(Prism.highlightAll, 0);
|
||||
} else {
|
||||
document.addEventListener('DOMContentLoaded', Prism.highlightAll);
|
||||
}
|
||||
|
||||
})();
|
||||
118
native/wordpress/maple-code-blocks/assets/js/simple-block.js
Normal file
118
native/wordpress/maple-code-blocks/assets/js/simple-block.js
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
// Maple Code Blocks - Simple Block Registration
|
||||
console.log('Maple Code Blocks: Starting block registration');
|
||||
|
||||
(function(wp) {
|
||||
// Check if wp.blocks exists
|
||||
if (!wp || !wp.blocks) {
|
||||
console.error('Maple Code Blocks: wp.blocks not available');
|
||||
return;
|
||||
}
|
||||
|
||||
const { registerBlockType } = wp.blocks;
|
||||
const { TextControl, PanelBody, SelectControl } = wp.components;
|
||||
const { InspectorControls } = wp.blockEditor || wp.editor || {};
|
||||
const { Fragment, createElement: el } = wp.element;
|
||||
|
||||
console.log('Maple Code Blocks: Dependencies loaded, registering block...');
|
||||
|
||||
// Register the main Maple Code Block
|
||||
const blockRegistered = registerBlockType('maple-code-blocks/code-block', {
|
||||
title: 'Maple Code Block',
|
||||
description: 'Display code from GitHub, GitLab, Bitbucket or Codeberg',
|
||||
category: 'widgets',
|
||||
icon: 'editor-code',
|
||||
keywords: ['maple', 'code', 'github', 'gitlab', 'bitbucket'],
|
||||
attributes: {
|
||||
repository: {
|
||||
type: 'string',
|
||||
default: ''
|
||||
},
|
||||
theme: {
|
||||
type: 'string',
|
||||
default: 'dark'
|
||||
},
|
||||
height: {
|
||||
type: 'string',
|
||||
default: '600px'
|
||||
}
|
||||
},
|
||||
|
||||
edit: function(props) {
|
||||
const { attributes, setAttributes } = props;
|
||||
const { repository, theme, height } = attributes;
|
||||
|
||||
return el(Fragment, {},
|
||||
el(InspectorControls, {},
|
||||
el(PanelBody, { title: 'Repository Settings', initialOpen: true },
|
||||
el(TextControl, {
|
||||
label: 'Repository',
|
||||
value: repository,
|
||||
onChange: function(value) { setAttributes({ repository: value }) },
|
||||
placeholder: 'e.g., facebook/react or gitlab:gnome/gimp',
|
||||
help: 'Format: [platform:]owner/repo. Platforms: github (default), gitlab, bitbucket, codeberg. Examples: facebook/react, gitlab:gitlab-org/gitlab, bitbucket:atlassian/python-bitbucket, codeberg:forgejo/forgejo'
|
||||
}),
|
||||
el(SelectControl, {
|
||||
label: 'Theme',
|
||||
value: theme,
|
||||
options: [
|
||||
{ label: 'Dark', value: 'dark' },
|
||||
{ label: 'Light', value: 'light' },
|
||||
{ label: 'Monokai', value: 'monokai' },
|
||||
{ label: 'Solarized', value: 'solarized' }
|
||||
],
|
||||
onChange: function(value) { setAttributes({ theme: value }) }
|
||||
}),
|
||||
el(TextControl, {
|
||||
label: 'Height',
|
||||
value: height,
|
||||
onChange: function(value) { setAttributes({ height: value }) },
|
||||
placeholder: '600px'
|
||||
})
|
||||
)
|
||||
),
|
||||
el('div', {
|
||||
className: 'maple-code-block-editor',
|
||||
style: {
|
||||
padding: '20px',
|
||||
backgroundColor: theme === 'dark' ? '#1e1e1e' : '#fff',
|
||||
color: theme === 'dark' ? '#fff' : '#000',
|
||||
border: '1px solid #ddd',
|
||||
borderRadius: '4px'
|
||||
}
|
||||
},
|
||||
el('h3', { style: { marginTop: 0 } }, 'Maple Code Block'),
|
||||
repository ?
|
||||
el('p', {}, 'Repository: ', el('strong', {}, repository)) :
|
||||
el('p', { style: { color: '#999' } }, 'Enter a repository in the block settings'),
|
||||
el('p', {}, 'Theme: ', el('strong', {}, theme)),
|
||||
el('p', {}, 'Height: ', el('strong', {}, height))
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
save: function() {
|
||||
// Rendered server-side
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
if (blockRegistered) {
|
||||
console.log('Maple Code Blocks: Block registered successfully!', blockRegistered);
|
||||
} else {
|
||||
console.error('Maple Code Blocks: Block registration failed');
|
||||
}
|
||||
|
||||
})(window.wp);
|
||||
|
||||
// Also try registering with global wp if window.wp fails
|
||||
if (typeof wp !== 'undefined' && wp.blocks && !wp.blocks.getBlockType('maple-code-blocks/code-block')) {
|
||||
console.log('Maple Code Blocks: Attempting registration with global wp');
|
||||
wp.blocks.registerBlockType('maple-code-blocks/code-block', {
|
||||
title: 'Maple Code Block',
|
||||
description: 'Display code from repositories',
|
||||
category: 'widgets',
|
||||
icon: 'editor-code',
|
||||
edit: function() { return wp.element.createElement('div', {}, 'Maple Code Block'); },
|
||||
save: function() { return null; }
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
(function(wp) {
|
||||
const { registerBlockVariation } = wp.blocks;
|
||||
|
||||
wp.domReady(function() {
|
||||
// Register variations for the Maple Code Block
|
||||
registerBlockVariation('maple-code-blocks/code-block', {
|
||||
name: 'maple-github',
|
||||
title: 'Maple: GitHub Code',
|
||||
description: 'Display code from GitHub',
|
||||
icon: 'editor-code',
|
||||
attributes: {
|
||||
repository: 'facebook/react',
|
||||
theme: 'dark'
|
||||
},
|
||||
scope: ['inserter']
|
||||
});
|
||||
|
||||
registerBlockVariation('maple-code-blocks/code-block', {
|
||||
name: 'maple-gitlab',
|
||||
title: 'Maple: GitLab Code',
|
||||
description: 'Display code from GitLab',
|
||||
icon: 'editor-code',
|
||||
attributes: {
|
||||
repository: 'gitlab:gitlab-org/gitlab',
|
||||
theme: 'dark'
|
||||
},
|
||||
scope: ['inserter']
|
||||
});
|
||||
|
||||
registerBlockVariation('maple-code-blocks/code-block', {
|
||||
name: 'maple-documentation',
|
||||
title: 'Maple: Documentation',
|
||||
description: 'Display README or docs',
|
||||
icon: 'media-document',
|
||||
attributes: {
|
||||
repository: '',
|
||||
theme: 'light',
|
||||
height: '400px'
|
||||
},
|
||||
scope: ['inserter']
|
||||
});
|
||||
|
||||
console.log('Maple Code Blocks: Variations registered');
|
||||
});
|
||||
})(window.wp);
|
||||
Loading…
Add table
Add a link
Reference in a new issue