Add advanced style and button options to embed block

Introduces new attributes for card and button styles, and granular control over action buttons (view, clone, download) in both JS and PHP. Updates UI to use Dashicons, improves accessibility, and enhances CSS for multiple card and button styles, including minimal, bordered, shadow, and outline variants. Clone button now copies the URL to clipboard with feedback.
This commit is contained in:
feibisi 2025-07-31 14:45:00 +08:00
parent 729238cb5e
commit 105d769c7f
3 changed files with 362 additions and 60 deletions

182
block.js
View file

@ -47,10 +47,34 @@
type: 'boolean',
default: true
},
showDownload: {
showLanguage: {
type: 'boolean',
default: true
},
showActions: {
type: 'boolean',
default: true
},
showViewButton: {
type: 'boolean',
default: true
},
showCloneButton: {
type: 'boolean',
default: true
},
showDownloadButton: {
type: 'boolean',
default: true
},
cardStyle: {
type: 'string',
default: 'default'
},
buttonStyle: {
type: 'string',
default: 'primary'
},
alignment: {
type: 'string',
default: 'none'
@ -59,7 +83,11 @@
edit: function(props) {
const { attributes, setAttributes } = props;
const { platform, owner, repo, showDescription, showStats, showDownload, alignment } = attributes;
const {
platform, owner, repo, showDescription, showStats, showLanguage,
showActions, showViewButton, showCloneButton, showDownloadButton,
cardStyle, buttonStyle, alignment
} = attributes;
const [repoData, setRepoData] = useState(null);
const [loading, setLoading] = useState(false);
@ -131,52 +159,81 @@
if (!repoData) {
return el('div', { className: 'git-embed-placeholder' },
el('div', { className: 'git-embed-placeholder-content' },
el('span', { className: 'git-embed-placeholder-icon' }, '📦'),
el('span', { className: 'dashicons dashicons-admin-links git-embed-placeholder-icon' }),
el('h3', null, 'Git Repository Embed'),
el('p', null, 'Configure your repository details in the sidebar')
)
);
}
return el('div', { className: 'git-embed-card' },
const cardClass = `git-embed-card${cardStyle !== 'default' ? ` git-embed-card-${cardStyle}` : ''}`;
const downloadUrl = repoData.archive_url ?
repoData.archive_url.replace('{archive_format}', 'zipball').replace('{/ref}', '/main') : '';
return el('div', { className: cardClass },
el('div', { className: 'git-embed-header' },
el('h3', { className: 'git-embed-title' },
el('span', { className: 'dashicons dashicons-admin-links git-embed-repo-icon' }),
el('a', {
href: repoData.html_url,
target: '_blank',
rel: 'noopener'
}, repoData.full_name)
),
repoData.language && el('span', { className: 'git-embed-language' }, repoData.language)
),
showDescription && repoData.description &&
el('p', { className: 'git-embed-description' }, repoData.description),
showStats && el('div', { className: 'git-embed-stats' },
el('span', { className: 'git-embed-stat' },
el('span', { className: 'git-embed-icon' }, '⭐'),
repoData.stargazers_count.toLocaleString()
),
el('span', { className: 'git-embed-stat' },
el('span', { className: 'git-embed-icon' }, '🍴'),
repoData.forks_count.toLocaleString()
),
el('span', { className: 'git-embed-stat' },
el('span', { className: 'git-embed-icon' }, '📝'),
repoData.open_issues_count.toLocaleString()
showLanguage && repoData.language && el('span', { className: 'git-embed-language' },
el('span', { className: 'dashicons dashicons-editor-code' }),
repoData.language
)
),
showDownload && el('div', { className: 'git-embed-actions' },
el('a', {
href: repoData.html_url,
className: 'git-embed-button git-embed-button-primary',
target: '_blank',
rel: 'noopener'
}, 'View Repository'),
el('a', {
href: repoData.clone_url,
className: 'git-embed-button git-embed-button-secondary'
}, 'Clone')
)
showDescription && repoData.description &&
el('p', { className: 'git-embed-description' },
el('span', { className: 'dashicons dashicons-text-page' }),
repoData.description
),
showStats && el('div', { className: 'git-embed-stats' },
el('span', { className: 'git-embed-stat' },
el('span', { className: 'dashicons dashicons-star-filled' }),
el('span', { className: 'git-embed-stat-label' }, 'Stars:'),
el('span', { className: 'git-embed-stat-value' }, repoData.stargazers_count.toLocaleString())
),
el('span', { className: 'git-embed-stat' },
el('span', { className: 'dashicons dashicons-networking' }),
el('span', { className: 'git-embed-stat-label' }, 'Forks:'),
el('span', { className: 'git-embed-stat-value' }, repoData.forks_count.toLocaleString())
),
el('span', { className: 'git-embed-stat' },
el('span', { className: 'dashicons dashicons-editor-help' }),
el('span', { className: 'git-embed-stat-label' }, 'Issues:'),
el('span', { className: 'git-embed-stat-value' }, repoData.open_issues_count.toLocaleString())
)
),
showActions && (showViewButton || showCloneButton || showDownloadButton) &&
el('div', { className: 'git-embed-actions' },
showViewButton && el('a', {
href: repoData.html_url,
className: `git-embed-button git-embed-button-${buttonStyle}`,
target: '_blank',
rel: 'noopener'
},
el('span', { className: 'dashicons dashicons-external' }),
'View Repository'
),
showCloneButton && el('span', {
className: 'git-embed-button git-embed-button-secondary',
title: `Clone URL: ${repoData.clone_url}`
},
el('span', { className: 'dashicons dashicons-admin-page' }),
'Clone'
),
showDownloadButton && el('a', {
href: downloadUrl,
className: 'git-embed-button git-embed-button-secondary',
download: `${repoData.name}.zip`
},
el('span', { className: 'dashicons dashicons-download' }),
'Download ZIP'
)
)
);
};
@ -227,15 +284,70 @@
checked: showDescription,
onChange: (value) => setAttributes({ showDescription: value })
}),
el(ToggleControl, {
label: __('Show Programming Language', 'git-embed-feicode'),
checked: showLanguage,
onChange: (value) => setAttributes({ showLanguage: value })
}),
el(ToggleControl, {
label: __('Show Statistics', 'git-embed-feicode'),
checked: showStats,
onChange: (value) => setAttributes({ showStats: value })
}),
el(ToggleControl, {
label: __('Show Download Links', 'git-embed-feicode'),
checked: showDownload,
onChange: (value) => setAttributes({ showDownload: value })
label: __('Show Action Buttons', 'git-embed-feicode'),
checked: showActions,
onChange: (value) => setAttributes({ showActions: value })
})
),
el(PanelBody, {
title: __('Button Options', 'git-embed-feicode'),
initialOpen: false
},
el(ToggleControl, {
label: __('Show View Repository Button', 'git-embed-feicode'),
checked: showViewButton,
onChange: (value) => setAttributes({ showViewButton: value }),
disabled: !showActions
}),
el(ToggleControl, {
label: __('Show Clone Button', 'git-embed-feicode'),
checked: showCloneButton,
onChange: (value) => setAttributes({ showCloneButton: value }),
disabled: !showActions
}),
el(ToggleControl, {
label: __('Show Download ZIP Button', 'git-embed-feicode'),
checked: showDownloadButton,
onChange: (value) => setAttributes({ showDownloadButton: value }),
disabled: !showActions
}),
el(SelectControl, {
label: __('Button Style', 'git-embed-feicode'),
value: buttonStyle,
options: [
{ label: 'Primary (Green)', value: 'primary' },
{ label: 'Secondary (Gray)', value: 'secondary' },
{ label: 'Outline', value: 'outline' }
],
onChange: (value) => setAttributes({ buttonStyle: value }),
disabled: !showActions
})
),
el(PanelBody, {
title: __('Style Options', 'git-embed-feicode'),
initialOpen: false
},
el(SelectControl, {
label: __('Card Style', 'git-embed-feicode'),
value: cardStyle,
options: [
{ label: 'Default', value: 'default' },
{ label: 'Minimal', value: 'minimal' },
{ label: 'Bordered', value: 'bordered' },
{ label: 'Shadow', value: 'shadow' }
],
onChange: (value) => setAttributes({ cardStyle: value })
})
)
),

View file

@ -57,10 +57,34 @@ class GitEmbedFeiCode {
'type' => 'boolean',
'default' => true
],
'showDownload' => [
'showLanguage' => [
'type' => 'boolean',
'default' => true
],
'showActions' => [
'type' => 'boolean',
'default' => true
],
'showViewButton' => [
'type' => 'boolean',
'default' => true
],
'showCloneButton' => [
'type' => 'boolean',
'default' => true
],
'showDownloadButton' => [
'type' => 'boolean',
'default' => true
],
'cardStyle' => [
'type' => 'string',
'default' => 'default'
],
'buttonStyle' => [
'type' => 'string',
'default' => 'primary'
],
'alignment' => [
'type' => 'string',
'default' => 'none'
@ -157,62 +181,135 @@ class GitEmbedFeiCode {
private function render_repository_card(array $repo_data, array $attributes): string {
$show_description = $attributes['showDescription'] ?? true;
$show_stats = $attributes['showStats'] ?? true;
$show_download = $attributes['showDownload'] ?? true;
$show_language = $attributes['showLanguage'] ?? true;
$show_actions = $attributes['showActions'] ?? true;
$show_view_button = $attributes['showViewButton'] ?? true;
$show_clone_button = $attributes['showCloneButton'] ?? true;
$show_download_button = $attributes['showDownloadButton'] ?? true;
$card_style = $attributes['cardStyle'] ?? 'default';
$button_style = $attributes['buttonStyle'] ?? 'primary';
$alignment = $attributes['alignment'] ?? 'none';
$align_class = $alignment !== 'none' ? " align{$alignment}" : '';
$card_class = $card_style !== 'default' ? " git-embed-card-{$card_style}" : '';
$download_url = str_replace('{archive_format}', 'zipball', $repo_data['archive_url']);
$download_url = str_replace('{/ref}', '/main', $download_url);
ob_start();
?>
<div class="wp-block-git-embed-feicode-repository<?php echo esc_attr($align_class); ?>">
<div class="git-embed-card">
<div class="git-embed-card<?php echo esc_attr($card_class); ?>">
<div class="git-embed-header">
<h3 class="git-embed-title">
<span class="dashicons dashicons-admin-links git-embed-repo-icon"></span>
<a href="<?php echo esc_url($repo_data['html_url']); ?>" target="_blank" rel="noopener">
<?php echo esc_html($repo_data['full_name']); ?>
</a>
</h3>
<?php if ($repo_data['language']): ?>
<span class="git-embed-language"><?php echo esc_html($repo_data['language']); ?></span>
<?php if ($show_language && $repo_data['language']): ?>
<span class="git-embed-language">
<span class="dashicons dashicons-editor-code"></span>
<?php echo esc_html($repo_data['language']); ?>
</span>
<?php endif; ?>
</div>
<?php if ($show_description && $repo_data['description']): ?>
<p class="git-embed-description"><?php echo esc_html($repo_data['description']); ?></p>
<p class="git-embed-description">
<span class="dashicons dashicons-text-page"></span>
<?php echo esc_html($repo_data['description']); ?>
</p>
<?php endif; ?>
<?php if ($show_stats): ?>
<div class="git-embed-stats">
<span class="git-embed-stat">
<span class="git-embed-icon"></span>
<?php echo number_format_i18n($repo_data['stargazers_count']); ?>
<span class="dashicons dashicons-star-filled"></span>
<span class="git-embed-stat-label">Stars:</span>
<span class="git-embed-stat-value"><?php echo number_format_i18n($repo_data['stargazers_count']); ?></span>
</span>
<span class="git-embed-stat">
<span class="git-embed-icon">🍴</span>
<?php echo number_format_i18n($repo_data['forks_count']); ?>
<span class="dashicons dashicons-networking"></span>
<span class="git-embed-stat-label">Forks:</span>
<span class="git-embed-stat-value"><?php echo number_format_i18n($repo_data['forks_count']); ?></span>
</span>
<span class="git-embed-stat">
<span class="git-embed-icon">📝</span>
<?php echo number_format_i18n($repo_data['open_issues_count']); ?>
<span class="dashicons dashicons-editor-help"></span>
<span class="git-embed-stat-label">Issues:</span>
<span class="git-embed-stat-value"><?php echo number_format_i18n($repo_data['open_issues_count']); ?></span>
</span>
</div>
<?php endif; ?>
<?php if ($show_download): ?>
<?php if ($show_actions && ($show_view_button || $show_clone_button || $show_download_button)): ?>
<div class="git-embed-actions">
<a href="<?php echo esc_url($repo_data['html_url']); ?>"
class="git-embed-button git-embed-button-primary"
target="_blank" rel="noopener">
View Repository
</a>
<a href="<?php echo esc_url($repo_data['clone_url']); ?>"
class="git-embed-button git-embed-button-secondary">
Clone
</a>
<?php if ($show_view_button): ?>
<a href="<?php echo esc_url($repo_data['html_url']); ?>"
class="git-embed-button git-embed-button-<?php echo esc_attr($button_style); ?>"
target="_blank" rel="noopener">
<span class="dashicons dashicons-external"></span>
View Repository
</a>
<?php endif; ?>
<?php if ($show_clone_button): ?>
<button type="button"
class="git-embed-button git-embed-button-secondary git-embed-clone-btn"
data-clone-url="<?php echo esc_attr($repo_data['clone_url']); ?>"
title="Click to copy clone URL">
<span class="dashicons dashicons-admin-page"></span>
Clone
</button>
<?php endif; ?>
<?php if ($show_download_button): ?>
<a href="<?php echo esc_url($download_url); ?>"
class="git-embed-button git-embed-button-secondary"
download="<?php echo esc_attr($repo_data['name']); ?>.zip">
<span class="dashicons dashicons-download"></span>
Download ZIP
</a>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
</div>
<?php if ($show_clone_button): ?>
<script>
document.addEventListener('DOMContentLoaded', function() {
const cloneButtons = document.querySelectorAll('.git-embed-clone-btn');
cloneButtons.forEach(button => {
button.addEventListener('click', function() {
const cloneUrl = this.dataset.cloneUrl;
if (navigator.clipboard) {
navigator.clipboard.writeText(cloneUrl).then(() => {
const originalText = this.innerHTML;
this.innerHTML = '<span class="dashicons dashicons-yes"></span>Copied!';
setTimeout(() => {
this.innerHTML = originalText;
}, 2000);
});
} else {
const input = document.createElement('input');
input.value = cloneUrl;
document.body.appendChild(input);
input.select();
document.execCommand('copy');
document.body.removeChild(input);
const originalText = this.innerHTML;
this.innerHTML = '<span class="dashicons dashicons-yes"></span>Copied!';
setTimeout(() => {
this.innerHTML = originalText;
}, 2000);
}
});
});
});
</script>
<?php endif; ?>
<?php
return ob_get_clean();
}

View file

@ -43,6 +43,21 @@
box-shadow: 0 3px 12px rgba(0, 0, 0, 0.15);
}
.git-embed-card-minimal {
border: none;
box-shadow: none;
background: #f9f9f9;
}
.git-embed-card-bordered {
border: 2px solid #0073aa;
}
.git-embed-card-shadow {
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
border: none;
}
.git-embed-header {
display: flex;
align-items: center;
@ -59,6 +74,16 @@
line-height: 1.3;
flex: 1;
min-width: 0;
display: flex;
align-items: center;
gap: 8px;
}
.git-embed-repo-icon {
color: #0073aa;
font-size: 16px;
margin-top: 2px;
flex-shrink: 0;
}
.git-embed-title a {
@ -80,6 +105,13 @@
font-weight: 500;
color: #656d76;
white-space: nowrap;
display: flex;
align-items: center;
gap: 4px;
}
.git-embed-language .dashicons {
font-size: 14px;
}
.git-embed-description {
@ -87,6 +119,15 @@
font-size: 14px;
line-height: 1.5;
margin: 0 0 16px 0;
display: flex;
align-items: flex-start;
gap: 6px;
}
.git-embed-description .dashicons {
margin-top: 2px;
flex-shrink: 0;
color: #0073aa;
}
.git-embed-stats {
@ -105,8 +146,17 @@
font-weight: 500;
}
.git-embed-icon {
font-size: 14px;
.git-embed-stat .dashicons {
font-size: 16px;
color: #0073aa;
}
.git-embed-stat-label {
font-weight: 600;
}
.git-embed-stat-value {
font-weight: 500;
}
.git-embed-actions {
@ -118,7 +168,8 @@
.git-embed-button {
display: inline-flex;
align-items: center;
padding: 6px 12px;
gap: 6px;
padding: 8px 12px;
font-size: 12px;
font-weight: 500;
line-height: 1.5;
@ -127,6 +178,11 @@
cursor: pointer;
border: 1px solid;
transition: all 0.15s ease-in-out;
background: none;
}
.git-embed-button .dashicons {
font-size: 16px;
}
.git-embed-button-primary {
@ -155,6 +211,28 @@
text-decoration: none;
}
.git-embed-button-outline {
color: #0073aa;
background-color: transparent;
border-color: #0073aa;
}
.git-embed-button-outline:hover {
background-color: #0073aa;
color: #ffffff;
text-decoration: none;
}
.git-embed-clone-btn:hover .dashicons {
animation: pulse 0.3s ease-in-out;
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.1); }
100% { transform: scale(1); }
}
.git-embed-placeholder {
border: 2px dashed #c3c4c7;
border-radius: 8px;
@ -172,6 +250,7 @@
font-size: 48px;
display: block;
margin-bottom: 16px;
color: #0073aa;
}
.git-embed-placeholder h3 {
@ -260,6 +339,12 @@
.git-embed-stats {
justify-content: space-between;
}
.git-embed-stat {
flex-direction: column;
text-align: center;
gap: 2px;
}
}
.wp-block[data-type="git-embed-feicode/repository"] {
@ -272,4 +357,12 @@
.wp-block[data-type="git-embed-feicode/repository"].is-selected .git-embed-card {
box-shadow: 0 0 0 2px #007cba;
}
.components-panel__body .components-toggle-control .components-form-toggle:disabled {
opacity: 0.3;
}
.components-panel__body .components-select-control:disabled {
opacity: 0.3;
}