git-embed-feicode/assets/block.js
feibisi fb4c759459 Update block icons, favicon logic, and translations
Changed block icon from 'admin-links' to 'embed-generic' and updated related dashicon classes in block.js. Updated CSS for placeholder icon display. In git-embed-feicode.php, switched all favicon URLs to use cn.cravatar.com for better reliability, improved owner type detection logic, and bumped plugin version to 1.1.0. Updated and regenerated Chinese translation files to reflect UI and terminology changes.
2025-08-14 11:35:48 +08:00

581 lines
No EOL
29 KiB
JavaScript

(function() {
const { registerBlockType } = wp.blocks;
const { createElement: el, useState, useEffect } = wp.element;
const {
InspectorControls,
BlockControls,
BlockAlignmentToolbar,
useBlockProps
} = wp.blockEditor;
const {
PanelBody,
TextControl,
ToggleControl,
SelectControl,
Button,
Spinner,
Notice
} = wp.components;
const { __ } = wp.i18n;
registerBlockType('git-embed-feicode/repository', {
title: __('Git Repository', 'git-embed-feicode'),
description: __('Embed a Git repository with information and stats', 'git-embed-feicode'),
icon: 'embed-generic',
category: 'embed',
supports: {
align: ['left', 'center', 'right', 'wide', 'full']
},
attributes: {
platform: {
type: 'string',
default: 'github'
},
customDomain: {
type: 'string',
default: ''
},
customSiteName: {
type: 'string',
default: ''
},
owner: {
type: 'string',
default: ''
},
repo: {
type: 'string',
default: ''
},
showDescription: {
type: 'boolean',
default: true
},
showStats: {
type: 'boolean',
default: true
},
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
},
showAvatar: {
type: 'boolean',
default: true
},
showSiteInfo: {
type: 'boolean',
default: true
},
avatarSize: {
type: 'string',
default: 'medium'
},
cardStyle: {
type: 'string',
default: 'default'
},
buttonStyle: {
type: 'string',
default: 'default'
},
buttonSize: {
type: 'string',
default: 'medium'
},
showIssuesButton: {
type: 'boolean',
default: false
},
showForksButton: {
type: 'boolean',
default: false
},
alignment: {
type: 'string',
default: 'none'
}
},
edit: function(props) {
const { attributes, setAttributes } = props;
const {
platform, customDomain, customSiteName, owner, repo, showDescription, showStats, showLanguage,
showActions, showViewButton, showCloneButton, showDownloadButton, showIssuesButton, showForksButton,
showAvatar, showSiteInfo, avatarSize, cardStyle, buttonStyle, buttonSize, alignment
} = attributes;
const [repoData, setRepoData] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const blockProps = useBlockProps({
className: alignment !== 'none' ? `align${alignment}` : ''
});
const fetchRepoData = () => {
if (!owner || !repo) {
setError(__('Please enter repository owner and name', 'git-embed-feicode'));
return;
}
if ((platform === 'gitea' || platform === 'forgejo' || platform === 'gitlab' || platform === 'custom') && !customDomain) {
setError(__('Please enter custom domain for', 'git-embed-feicode') + ' ' + platform.charAt(0).toUpperCase() + platform.slice(1));
return;
}
setLoading(true);
setError('');
const formData = new FormData();
formData.append('action', 'git_embed_fetch');
formData.append('platform', platform);
formData.append('customDomain', customDomain);
formData.append('customSiteName', customSiteName);
formData.append('owner', owner);
formData.append('repo', repo);
formData.append('nonce', gitEmbedAjax.nonce);
fetch(gitEmbedAjax.url, {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
setLoading(false);
if (data.success) {
setRepoData(data.data);
setError('');
} else {
setError(data.data || __('Failed to fetch repository', 'git-embed-feicode'));
setRepoData(null);
}
})
.catch(err => {
setLoading(false);
setError(__('Network error occurred', 'git-embed-feicode'));
setRepoData(null);
});
};
useEffect(() => {
if (owner && repo && (platform === 'github' || (platform !== 'github' && customDomain))) {
fetchRepoData();
}
}, [owner, repo, platform, customDomain, customSiteName]);
const getDisplayAvatarUrl = (repoData) => {
if (repoData.repo_avatar_url) {
return repoData.repo_avatar_url;
}
if (repoData.owner && repoData.owner.avatar_url) {
return repoData.owner.avatar_url;
}
return '';
};
const handleDownload = (url, filename) => {
window.open(url, '_blank');
};
const renderPreview = () => {
if (loading) {
return el('div', { className: 'git-embed-loading' },
el(Spinner),
el('p', null, __('Fetching repository data...', 'git-embed-feicode'))
);
}
if (error) {
return el(Notice, {
status: 'error',
isDismissible: false
}, error);
}
if (!repoData) {
return el('div', { className: 'git-embed-placeholder' },
el('div', { className: 'git-embed-placeholder-content' },
el('span', { className: 'dashicons dashicons-embed-generic git-embed-placeholder-icon' }),
el('h3', null, __('Git Repository Embed', 'git-embed-feicode')),
el('p', null, __('Configure your repository details in the sidebar', 'git-embed-feicode'))
)
);
}
const cardClass = `git-embed-card${cardStyle !== 'default' ? ` git-embed-card-${cardStyle}` : ''}`;
const avatarClass = `git-embed-avatar git-embed-avatar-${avatarSize}`;
const buttonClass = `git-embed-button-${buttonSize}`;
const downloadInfo = repoData.download_info || {};
const downloadUrl = downloadInfo.url || repoData.archive_url || '';
const downloadFilename = downloadInfo.filename || `${repoData.name}.zip`;
const downloadTitle = downloadInfo.name ?
__('Download', 'git-embed-feicode') + ' ' + downloadInfo.name + ' (' + downloadInfo.version + ')' :
__('Download ZIP', 'git-embed-feicode');
const displayAvatarUrl = getDisplayAvatarUrl(repoData);
return el('div', { className: cardClass },
showSiteInfo && repoData.site_info && el('div', {
className: `git-embed-site-info platform-${repoData.platform || 'github'}`
},
el('img', {
src: repoData.site_info.favicon,
alt: repoData.site_info.name,
className: 'git-embed-site-favicon',
onError: (e) => e.target.style.display = 'none'
}),
el('span', { className: 'git-embed-site-name' },
el('a', {
href: repoData.site_info.url,
target: '_blank',
rel: 'noopener'
}, repoData.site_info.name)
)
),
el('div', { className: 'git-embed-header' },
el('div', { className: 'git-embed-title-section' },
showAvatar && displayAvatarUrl && el('img', {
src: displayAvatarUrl,
alt: repoData.name,
className: avatarClass,
title: repoData.repo_avatar_url ? __('Repository Avatar', 'git-embed-feicode') : __('Owner Avatar', 'git-embed-feicode')
}),
el('div', { className: 'git-embed-title-content' },
el('h3', { className: 'git-embed-title' },
el('span', { className: 'dashicons dashicons-embed-generic git-embed-repo-icon' }),
el('a', {
href: repoData.html_url,
target: '_blank',
rel: 'noopener'
}, repoData.full_name)
),
showAvatar && repoData.owner && el('div', { className: 'git-embed-owner-info' },
repoData.owner.type && el('span', { className: 'git-embed-owner-type' }, repoData.owner.type),
el('a', {
href: repoData.owner.html_url,
target: '_blank',
rel: 'noopener',
className: 'git-embed-owner-link'
}, `@${repoData.owner.login}`),
repoData.repo_avatar_url && el('span', {
className: 'git-embed-repo-avatar-badge',
title: __('Repository has custom avatar', 'git-embed-feicode')
},
el('span', { className: '' })
)
)
)
),
el('div', { className: 'git-embed-meta-section' },
showLanguage && repoData.language && el('span', { className: 'git-embed-language' },
el('span', { className: 'dashicons dashicons-editor-code' }),
repoData.language
),
el('span', {
className: `git-embed-platform-badge platform-${repoData.platform || 'github'}`
}, repoData.platform ? repoData.platform.toUpperCase() : 'GITHUB')
)
),
showDescription && repoData.description &&
el('p', { className: 'git-embed-description' },
el('span', { className: 'dashicons dashicons-editor-quote' }),
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:', 'git-embed-feicode')),
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:', 'git-embed-feicode')),
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:', 'git-embed-feicode')),
el('span', { className: 'git-embed-stat-value' }, repoData.open_issues_count.toLocaleString())
)
),
showActions && (showViewButton || showCloneButton || showDownloadButton || showIssuesButton || showForksButton) &&
el('div', { className: 'git-embed-actions' },
showViewButton && el('a', {
href: repoData.html_url,
className: `git-embed-button git-embed-button-${buttonStyle} ${buttonClass}`,
target: '_blank',
rel: 'noopener'
},
el('span', { className: 'dashicons dashicons-external' }),
__('View Repository', 'git-embed-feicode')
),
showCloneButton && el('span', {
className: `git-embed-button git-embed-button-secondary ${buttonClass}`,
title: __('Clone URL:', 'git-embed-feicode') + ' ' + repoData.clone_url
},
el('span', { className: 'dashicons dashicons-admin-page' }),
__('Clone', 'git-embed-feicode')
),
showDownloadButton && downloadUrl && el('button', {
className: `git-embed-button git-embed-button-secondary ${buttonClass}`,
onClick: () => handleDownload(downloadUrl, downloadFilename),
title: downloadTitle
},
el('span', { className: 'dashicons dashicons-download' }),
downloadInfo.type === 'release' && downloadInfo.version ?
__('Download', 'git-embed-feicode') + ' ' + downloadInfo.version :
__('Download ZIP', 'git-embed-feicode')
),
showIssuesButton && el('a', {
href: `${repoData.html_url}/issues`,
className: `git-embed-button git-embed-button-outline ${buttonClass}`,
target: '_blank',
rel: 'noopener'
},
el('span', { className: 'dashicons dashicons-editor-help' }),
__('Issues', 'git-embed-feicode') + ' (' + repoData.open_issues_count.toLocaleString() + ')'
),
showForksButton && el('a', {
href: `${repoData.html_url}/forks`,
className: `git-embed-button git-embed-button-outline ${buttonClass}`,
target: '_blank',
rel: 'noopener'
},
el('span', { className: 'dashicons dashicons-networking' }),
__('Forks', 'git-embed-feicode') + ' (' + repoData.forks_count.toLocaleString() + ')'
)
)
);
};
return el('div', blockProps,
el(BlockControls, null,
el(BlockAlignmentToolbar, {
value: alignment,
onChange: (value) => setAttributes({ alignment: value })
})
),
el(InspectorControls, null,
el(PanelBody, {
title: __('Repository Settings', 'git-embed-feicode'),
initialOpen: true
},
el(SelectControl, {
label: __('Platform', 'git-embed-feicode'),
value: platform,
options: [
{ label: __('GitHub', 'git-embed-feicode'), value: 'github' },
{ label: __('Gitea', 'git-embed-feicode'), value: 'gitea' },
{ label: __('Forgejo', 'git-embed-feicode'), value: 'forgejo' },
{ label: __('GitLab (Self-hosted)', 'git-embed-feicode'), value: 'gitlab' },
{ label: __('Custom Git Service', 'git-embed-feicode'), value: 'custom' }
],
onChange: (value) => setAttributes({ platform: value }),
help: platform !== 'github' ? __('Self-hosted Git service requires custom domain', 'git-embed-feicode') : '',
__next40pxDefaultSize: true,
__nextHasNoMarginBottom: true
}),
(platform !== 'github') && el(TextControl, {
label: __('Custom Domain', 'git-embed-feicode'),
value: customDomain,
onChange: (value) => setAttributes({ customDomain: value }),
placeholder: __('e.g. git.example.com', 'git-embed-feicode'),
help: __('Enter the domain of your', 'git-embed-feicode') + ' ' + platform.charAt(0).toUpperCase() + platform.slice(1) + ' ' + __('instance', 'git-embed-feicode'),
__next40pxDefaultSize: true,
__nextHasNoMarginBottom: true
}),
(platform !== 'github') && el(TextControl, {
label: __('Custom Site Name (Optional)', 'git-embed-feicode'),
value: customSiteName,
onChange: (value) => setAttributes({ customSiteName: value }),
placeholder: __('e.g. Company Git', 'git-embed-feicode'),
help: __('Override the automatically detected site name', 'git-embed-feicode'),
__next40pxDefaultSize: true,
__nextHasNoMarginBottom: true
}),
el(TextControl, {
label: __('Repository Owner', 'git-embed-feicode'),
value: owner,
onChange: (value) => setAttributes({ owner: value }),
placeholder: __('e.g. facebook', 'git-embed-feicode'),
__next40pxDefaultSize: true,
__nextHasNoMarginBottom: true
}),
el(TextControl, {
label: __('Repository Name', 'git-embed-feicode'),
value: repo,
onChange: (value) => setAttributes({ repo: value }),
placeholder: __('e.g. react', 'git-embed-feicode'),
__next40pxDefaultSize: true,
__nextHasNoMarginBottom: true
}),
el(Button, {
isPrimary: true,
onClick: fetchRepoData,
disabled: loading || !owner || !repo ||
(platform !== 'github' && !customDomain)
}, loading ? __('Fetching...', 'git-embed-feicode') : __('Fetch Repository', 'git-embed-feicode'))
),
el(PanelBody, {
title: __('Display Options', 'git-embed-feicode'),
initialOpen: false
},
el(ToggleControl, {
label: __('Show Site Information', 'git-embed-feicode'),
checked: showSiteInfo,
onChange: (value) => setAttributes({ showSiteInfo: value })
}),
el(ToggleControl, {
label: __('Show Avatar', 'git-embed-feicode'),
checked: showAvatar,
onChange: (value) => setAttributes({ showAvatar: value }),
help: __('Shows repository avatar if available, otherwise owner avatar', 'git-embed-feicode')
}),
showAvatar && el(SelectControl, {
label: __('Avatar Size', 'git-embed-feicode'),
value: avatarSize,
options: [
{ label: __('Small', 'git-embed-feicode'), value: 'small' },
{ label: __('Medium', 'git-embed-feicode'), value: 'medium' },
{ label: __('Large', 'git-embed-feicode'), value: 'large' }
],
onChange: (value) => setAttributes({ avatarSize: value }),
__next40pxDefaultSize: true,
__nextHasNoMarginBottom: true
}),
el(ToggleControl, {
label: __('Show Description', 'git-embed-feicode'),
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 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(ToggleControl, {
label: __('Show Issues Button', 'git-embed-feicode'),
checked: showIssuesButton,
onChange: (value) => setAttributes({ showIssuesButton: value }),
disabled: !showActions
}),
el(ToggleControl, {
label: __('Show Forks Button', 'git-embed-feicode'),
checked: showForksButton,
onChange: (value) => setAttributes({ showForksButton: value }),
disabled: !showActions
}),
el(SelectControl, {
label: __('Button Style', 'git-embed-feicode'),
value: buttonStyle,
options: [
{ label: __('Default', 'git-embed-feicode'), value: 'default' },
{ label: __('Primary (Green)', 'git-embed-feicode'), value: 'primary' },
{ label: __('Secondary (Gray)', 'git-embed-feicode'), value: 'secondary' },
{ label: __('Outline', 'git-embed-feicode'), value: 'outline' },
{ label: __('Ghost', 'git-embed-feicode'), value: 'ghost' }
],
onChange: (value) => setAttributes({ buttonStyle: value }),
disabled: !showActions,
__next40pxDefaultSize: true,
__nextHasNoMarginBottom: true
}),
el(SelectControl, {
label: __('Button Size', 'git-embed-feicode'),
value: buttonSize,
options: [
{ label: __('Small', 'git-embed-feicode'), value: 'small' },
{ label: __('Medium', 'git-embed-feicode'), value: 'medium' },
{ label: __('Large', 'git-embed-feicode'), value: 'large' }
],
onChange: (value) => setAttributes({ buttonSize: value }),
disabled: !showActions,
__next40pxDefaultSize: true,
__nextHasNoMarginBottom: true
})
),
el(PanelBody, {
title: __('Style Options', 'git-embed-feicode'),
initialOpen: false
},
el(SelectControl, {
label: __('Card Style', 'git-embed-feicode'),
value: cardStyle,
options: [
{ label: __('Default', 'git-embed-feicode'), value: 'default' },
{ label: __('Minimal', 'git-embed-feicode'), value: 'minimal' },
{ label: __('Bordered', 'git-embed-feicode'), value: 'bordered' },
{ label: __('Shadow', 'git-embed-feicode'), value: 'shadow' },
{ label: __('Gradient', 'git-embed-feicode'), value: 'gradient' },
{ label: __('Glassmorphism', 'git-embed-feicode'), value: 'glass' }
],
onChange: (value) => setAttributes({ cardStyle: value }),
__next40pxDefaultSize: true,
__nextHasNoMarginBottom: true
})
)
),
el('div', { className: 'wp-block-git-embed-feicode-repository' },
renderPreview()
)
);
},
save: function() {
return null;
}
});
})();