diff --git a/block.js b/block.js index b7d1888..dce2d35 100644 --- a/block.js +++ b/block.js @@ -31,6 +31,14 @@ type: 'string', default: 'github' }, + customDomain: { + type: 'string', + default: '' + }, + customSiteName: { + type: 'string', + default: '' + }, owner: { type: 'string', default: '' @@ -85,7 +93,19 @@ }, buttonStyle: { type: 'string', - default: 'primary' + default: 'default' + }, + buttonSize: { + type: 'string', + default: 'medium' + }, + showIssuesButton: { + type: 'boolean', + default: false + }, + showForksButton: { + type: 'boolean', + default: false }, alignment: { type: 'string', @@ -96,9 +116,9 @@ edit: function(props) { const { attributes, setAttributes } = props; const { - platform, owner, repo, showDescription, showStats, showLanguage, - showActions, showViewButton, showCloneButton, showDownloadButton, - showAvatar, showSiteInfo, avatarSize, cardStyle, buttonStyle, alignment + 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); @@ -115,12 +135,19 @@ return; } + if ((platform === 'gitea' || platform === 'forgejo' || platform === 'gitlab' || platform === 'custom') && !customDomain) { + setError(`Please enter custom domain for ${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); @@ -148,10 +175,10 @@ }; useEffect(() => { - if (owner && repo) { + if (owner && repo && (platform === 'github' || (platform !== 'github' && customDomain))) { fetchRepoData(); } - }, [owner, repo, platform]); + }, [owner, repo, platform, customDomain, customSiteName]); const renderPreview = () => { if (loading) { @@ -180,15 +207,19 @@ 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 downloadUrl = repoData.archive_url ? repoData.archive_url.replace('{archive_format}', 'zipball').replace('{/ref}', '/main') : ''; return el('div', { className: cardClass }, - showSiteInfo && repoData.site_info && el('div', { className: 'git-embed-site-info' }, + 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' + className: 'git-embed-site-favicon', + onError: (e) => e.target.style.display = 'none' }), el('span', { className: 'git-embed-site-name' }, el('a', { @@ -226,9 +257,14 @@ ) ) ), - showLanguage && repoData.language && el('span', { className: 'git-embed-language' }, - el('span', { className: 'dashicons dashicons-editor-code' }), - repoData.language + 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') ) ), @@ -254,11 +290,11 @@ el('span', { className: 'git-embed-stat-value' }, repoData.open_issues_count.toLocaleString()) ) ), - showActions && (showViewButton || showCloneButton || showDownloadButton) && + 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}`, + className: `git-embed-button git-embed-button-${buttonStyle} ${buttonClass}`, target: '_blank', rel: 'noopener' }, @@ -266,7 +302,7 @@ 'View Repository' ), showCloneButton && el('span', { - className: 'git-embed-button git-embed-button-secondary', + className: `git-embed-button git-embed-button-secondary ${buttonClass}`, title: `Clone URL: ${repoData.clone_url}` }, el('span', { className: 'dashicons dashicons-admin-page' }), @@ -274,11 +310,29 @@ ), showDownloadButton && el('a', { href: downloadUrl, - className: 'git-embed-button git-embed-button-secondary', + className: `git-embed-button git-embed-button-secondary ${buttonClass}`, download: `${repoData.name}.zip` }, el('span', { className: 'dashicons dashicons-download' }), 'Download ZIP' + ), + 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 (${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 (${repoData.forks_count.toLocaleString()})` ) ) ); @@ -300,9 +354,28 @@ label: __('Platform', 'git-embed-feicode'), value: platform, options: [ - { label: 'GitHub', value: 'github' } + { label: 'GitHub', value: 'github' }, + { label: 'Gitea', value: 'gitea' }, + { label: 'Forgejo', value: 'forgejo' }, + { label: 'GitLab (Self-hosted)', value: 'gitlab' }, + { label: 'Custom Git Service', value: 'custom' } ], - onChange: (value) => setAttributes({ platform: value }) + onChange: (value) => setAttributes({ platform: value }), + help: platform !== 'github' ? 'Self-hosted Git service requires custom domain' : '' + }), + (platform !== 'github') && el(TextControl, { + label: __('Custom Domain', 'git-embed-feicode'), + value: customDomain, + onChange: (value) => setAttributes({ customDomain: value }), + placeholder: 'e.g. git.example.com', + help: `Enter the domain of your ${platform.charAt(0).toUpperCase() + platform.slice(1)} instance` + }), + (platform !== 'github') && el(TextControl, { + label: __('Custom Site Name (Optional)', 'git-embed-feicode'), + value: customSiteName, + onChange: (value) => setAttributes({ customSiteName: value }), + placeholder: 'e.g. Company Git', + help: 'Override the automatically detected site name' }), el(TextControl, { label: __('Repository Owner', 'git-embed-feicode'), @@ -319,7 +392,8 @@ el(Button, { isPrimary: true, onClick: fetchRepoData, - disabled: loading || !owner || !repo + disabled: loading || !owner || !repo || + (platform !== 'github' && !customDomain) }, loading ? 'Fetching...' : 'Fetch Repository') ), el(PanelBody, { @@ -389,16 +463,41 @@ 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', value: 'default' }, { label: 'Primary (Green)', value: 'primary' }, { label: 'Secondary (Gray)', value: 'secondary' }, - { label: 'Outline', value: 'outline' } + { label: 'Outline', value: 'outline' }, + { label: 'Ghost', value: 'ghost' } ], onChange: (value) => setAttributes({ buttonStyle: value }), disabled: !showActions + }), + el(SelectControl, { + label: __('Button Size', 'git-embed-feicode'), + value: buttonSize, + options: [ + { label: 'Small', value: 'small' }, + { label: 'Medium', value: 'medium' }, + { label: 'Large', value: 'large' } + ], + onChange: (value) => setAttributes({ buttonSize: value }), + disabled: !showActions }) ), el(PanelBody, { @@ -412,7 +511,9 @@ { label: 'Default', value: 'default' }, { label: 'Minimal', value: 'minimal' }, { label: 'Bordered', value: 'bordered' }, - { label: 'Shadow', value: 'shadow' } + { label: 'Shadow', value: 'shadow' }, + { label: 'Gradient', value: 'gradient' }, + { label: 'Glassmorphism', value: 'glass' } ], onChange: (value) => setAttributes({ cardStyle: value }) }) diff --git a/git-embed-feicode.php b/git-embed-feicode.php index 59a1d21..87d8120 100644 --- a/git-embed-feicode.php +++ b/git-embed-feicode.php @@ -43,6 +43,14 @@ class GitEmbedFeiCode { 'type' => 'string', 'default' => 'github' ], + 'customDomain' => [ + 'type' => 'string', + 'default' => '' + ], + 'customSiteName' => [ + 'type' => 'string', + 'default' => '' + ], 'owner' => [ 'type' => 'string', 'default' => '' @@ -85,7 +93,19 @@ class GitEmbedFeiCode { ], 'buttonStyle' => [ 'type' => 'string', - 'default' => 'primary' + 'default' => 'default' + ], + 'buttonSize' => [ + 'type' => 'string', + 'default' => 'medium' + ], + 'showIssuesButton' => [ + 'type' => 'boolean', + 'default' => false + ], + 'showForksButton' => [ + 'type' => 'boolean', + 'default' => false ], 'showAvatar' => [ 'type' => 'boolean', @@ -131,12 +151,18 @@ class GitEmbedFeiCode { $owner = sanitize_text_field($attributes['owner'] ?? ''); $repo = sanitize_text_field($attributes['repo'] ?? ''); $platform = sanitize_text_field($attributes['platform'] ?? 'github'); + $custom_domain = sanitize_text_field($attributes['customDomain'] ?? ''); + $custom_site_name = sanitize_text_field($attributes['customSiteName'] ?? ''); if (empty($owner) || empty($repo)) { return '
Repository information required
'; } - $repo_data = $this->fetch_repository_data($platform, $owner, $repo); + if (in_array($platform, ['gitea', 'forgejo', 'gitlab', 'custom']) && empty($custom_domain)) { + return '
Custom domain required for ' . ucfirst($platform) . '
'; + } + + $repo_data = $this->fetch_repository_data($platform, $owner, $repo, $custom_domain, $custom_site_name); if (!$repo_data) { return '
Failed to fetch repository data
'; @@ -145,24 +171,25 @@ class GitEmbedFeiCode { return $this->render_repository_card($repo_data, $attributes); } - private function fetch_repository_data(string $platform, string $owner, string $repo): ?array { - if ($platform !== 'github') { - return null; - } - - $cache_key = "git_embed_{$platform}_{$owner}_{$repo}"; + private function fetch_repository_data(string $platform, string $owner, string $repo, string $custom_domain = '', string $custom_site_name = ''): ?array { + $cache_key = "git_embed_{$platform}_{$owner}_{$repo}" . ($custom_domain ? "_{$custom_domain}" : '') . ($custom_site_name ? "_{$custom_site_name}" : ''); $cached = get_transient($cache_key); if ($cached !== false) { return $cached; } - $url = "https://api.github.com/repos/{$owner}/{$repo}"; + $api_config = $this->get_api_config($platform, $custom_domain, $custom_site_name); + if (!$api_config) { + return null; + } + + $url = $api_config['api_url'] . "/repos/{$owner}/{$repo}"; $response = wp_remote_get($url, [ 'timeout' => 15, 'headers' => [ 'User-Agent' => 'Git-Embed-FeiCode/1.0', - 'Accept' => 'application/vnd.github.v3+json' + 'Accept' => 'application/json' ] ]); @@ -176,38 +203,224 @@ class GitEmbedFeiCode { return null; } - $repo_data = [ - 'name' => $data['name'], - 'full_name' => $data['full_name'], - 'description' => $data['description'], - 'html_url' => $data['html_url'], - 'language' => $data['language'], - 'stargazers_count' => $data['stargazers_count'], - 'forks_count' => $data['forks_count'], - 'open_issues_count' => $data['open_issues_count'], - 'clone_url' => $data['clone_url'], - 'archive_url' => $data['archive_url'], - 'owner' => [ - 'login' => $data['owner']['login'], - 'avatar_url' => $data['owner']['avatar_url'], - 'html_url' => $data['owner']['html_url'], - 'type' => $data['owner']['type'] - ], - 'site_info' => [ - 'name' => 'GitHub', - 'url' => 'https://github.com', - 'favicon' => 'https://github.com/favicon.ico', - 'color' => '#24292f' - ] - ]; + $repo_data = $this->normalize_repository_data($data, $platform, $api_config); set_transient($cache_key, $repo_data, DAY_IN_SECONDS); - $this->cache_avatar($repo_data['owner']['avatar_url']); + if (!empty($repo_data['owner']['avatar_url'])) { + $this->cache_avatar($repo_data['owner']['avatar_url']); + } return $repo_data; } + private function get_api_config(string $platform, string $custom_domain = '', string $custom_site_name = ''): ?array { + switch ($platform) { + case 'github': + return [ + 'api_url' => 'https://api.github.com', + 'base_url' => 'https://github.com', + 'site_info' => [ + 'name' => 'GitHub', + 'url' => 'https://github.com', + 'favicon' => 'https://github.com/favicon.ico', + 'color' => '#24292f' + ] + ]; + + case 'gitea': + if (empty($custom_domain)) { + return null; + } + $domain = $this->normalize_domain($custom_domain); + $site_name = $custom_site_name ?: $this->get_site_name($domain, 'Gitea'); + return [ + 'api_url' => "https://{$domain}/api/v1", + 'base_url' => "https://{$domain}", + 'site_info' => [ + 'name' => $site_name, + 'url' => "https://{$domain}", + 'favicon' => "https://{$domain}/assets/img/favicon.png", + 'color' => '#609926' + ] + ]; + + case 'forgejo': + if (empty($custom_domain)) { + return null; + } + $domain = $this->normalize_domain($custom_domain); + $site_name = $custom_site_name ?: $this->get_site_name($domain, 'Forgejo'); + return [ + 'api_url' => "https://{$domain}/api/v1", + 'base_url' => "https://{$domain}", + 'site_info' => [ + 'name' => $site_name, + 'url' => "https://{$domain}", + 'favicon' => "https://{$domain}/assets/img/favicon.png", + 'color' => '#fb923c' + ] + ]; + + case 'gitlab': + if (empty($custom_domain)) { + return null; + } + $domain = $this->normalize_domain($custom_domain); + $site_name = $custom_site_name ?: $this->get_site_name($domain, 'GitLab'); + return [ + 'api_url' => "https://{$domain}/api/v4", + 'base_url' => "https://{$domain}", + 'site_info' => [ + 'name' => $site_name, + 'url' => "https://{$domain}", + 'favicon' => "https://{$domain}/assets/favicon.ico", + 'color' => '#fc6d26' + ] + ]; + + case 'custom': + if (empty($custom_domain)) { + return null; + } + $domain = $this->normalize_domain($custom_domain); + $site_name = $custom_site_name ?: $this->get_site_name($domain, 'Git Service'); + return [ + 'api_url' => "https://{$domain}/api/v1", + 'base_url' => "https://{$domain}", + 'site_info' => [ + 'name' => $site_name, + 'url' => "https://{$domain}", + 'favicon' => "https://{$domain}/favicon.ico", + 'color' => '#6366f1' + ] + ]; + + default: + return null; + } + } + + private function get_site_name(string $domain, string $fallback): string { + $cache_key = 'git_embed_site_name_' . md5($domain); + $cached = get_transient($cache_key); + + if ($cached !== false) { + return $cached; + } + + $response = wp_remote_get("https://{$domain}", [ + 'timeout' => 10, + 'headers' => [ + 'User-Agent' => 'Git-Embed-FeiCode/1.0' + ] + ]); + + if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) { + $body = wp_remote_retrieve_body($response); + if (preg_match('/]*>([^<]+)<\/title>/i', $body, $matches)) { + $title = trim(html_entity_decode($matches[1], ENT_QUOTES, 'UTF-8')); + if (!empty($title) && strlen($title) < 100) { + set_transient($cache_key, $title, DAY_IN_SECONDS); + return $title; + } + } + } + + set_transient($cache_key, $fallback, HOUR_IN_SECONDS); + return $fallback; + } + + private function normalize_domain(string $domain): string { + $domain = trim($domain); + $domain = preg_replace('/^https?:\/\//', '', $domain); + $domain = rtrim($domain, '/'); + return $domain; + } + + private function normalize_repository_data(array $data, string $platform, array $api_config): array { + $base_url = $api_config['base_url']; + + if ($platform === 'gitlab') { + return [ + 'name' => $data['name'], + 'full_name' => $data['path_with_namespace'] ?? ($data['namespace']['name'] . '/' . $data['name']), + 'description' => $data['description'], + 'html_url' => $data['web_url'], + 'language' => $data['language'] ?? null, + 'stargazers_count' => $data['star_count'] ?? 0, + 'forks_count' => $data['forks_count'] ?? 0, + 'open_issues_count' => $data['open_issues_count'] ?? 0, + 'clone_url' => $data['http_url_to_repo'], + 'archive_url' => $this->get_archive_url($data, $platform, $base_url), + 'owner' => [ + 'login' => $data['namespace']['name'] ?? $data['owner']['username'], + 'avatar_url' => $data['namespace']['avatar_url'] ?? $data['owner']['avatar_url'], + 'html_url' => $base_url . '/' . ($data['namespace']['name'] ?? $data['owner']['username']), + 'type' => $this->normalize_owner_type($data['namespace']['kind'] ?? 'user') + ], + 'site_info' => $api_config['site_info'], + 'platform' => $platform + ]; + } + + return [ + 'name' => $data['name'], + 'full_name' => $data['full_name'] ?? ($data['owner']['login'] . '/' . $data['name']), + 'description' => $data['description'], + 'html_url' => $data['html_url'], + 'language' => $data['language'], + 'stargazers_count' => $data['stargazers_count'] ?? $data['stars_count'] ?? 0, + 'forks_count' => $data['forks_count'] ?? $data['forks'] ?? 0, + 'open_issues_count' => $data['open_issues_count'] ?? $data['open_issues'] ?? 0, + 'clone_url' => $data['clone_url'], + 'archive_url' => $this->get_archive_url($data, $platform, $base_url), + 'owner' => [ + 'login' => $data['owner']['login'], + 'avatar_url' => $data['owner']['avatar_url'], + 'html_url' => $data['owner']['html_url'] ?? $base_url . '/' . $data['owner']['login'], + 'type' => $this->normalize_owner_type($data['owner']['type'] ?? 'User') + ], + 'site_info' => $api_config['site_info'], + 'platform' => $platform + ]; + } + + private function get_archive_url(array $data, string $platform, string $base_url): string { + if (isset($data['archive_url'])) { + return $data['archive_url']; + } + + $owner = $data['owner']['login'] ?? $data['namespace']['name'] ?? ''; + $repo = $data['name']; + + switch ($platform) { + case 'github': + return "https://api.github.com/repos/{$owner}/{$repo}/zipball/{archive_format}{/ref}"; + case 'gitlab': + $project_id = $data['id'] ?? ''; + return "{$base_url}/api/v4/projects/{$project_id}/repository/archive.zip"; + case 'gitea': + case 'forgejo': + case 'custom': + return "{$base_url}/{$owner}/{$repo}/archive/main.zip"; + default: + return ''; + } + } + + private function normalize_owner_type(string $type): string { + $type = strtolower($type); + switch ($type) { + case 'organization': + case 'org': + return 'Organization'; + case 'user': + default: + return 'User'; + } + } + private function cache_avatar(string $avatar_url): void { if (empty($avatar_url)) { return; @@ -239,30 +452,34 @@ class GitEmbedFeiCode { $show_view_button = $attributes['showViewButton'] ?? true; $show_clone_button = $attributes['showCloneButton'] ?? true; $show_download_button = $attributes['showDownloadButton'] ?? true; + $show_issues_button = $attributes['showIssuesButton'] ?? false; + $show_forks_button = $attributes['showForksButton'] ?? false; $show_avatar = $attributes['showAvatar'] ?? true; $show_site_info = $attributes['showSiteInfo'] ?? true; $avatar_size = $attributes['avatarSize'] ?? 'medium'; $card_style = $attributes['cardStyle'] ?? 'default'; - $button_style = $attributes['buttonStyle'] ?? 'primary'; + $button_style = $attributes['buttonStyle'] ?? 'default'; + $button_size = $attributes['buttonSize'] ?? 'medium'; $alignment = $attributes['alignment'] ?? 'none'; $align_class = $alignment !== 'none' ? " align{$alignment}" : ''; $card_class = $card_style !== 'default' ? " git-embed-card-{$card_style}" : ''; $avatar_class = "git-embed-avatar-{$avatar_size}"; + $button_class = "git-embed-button-{$button_size}"; - $download_url = str_replace('{archive_format}', 'zipball', $repo_data['archive_url']); - $download_url = str_replace('{/ref}', '/main', $download_url); + $download_url = $this->get_download_url($repo_data); ob_start(); ?>
-
+
<?php echo esc_attr($repo_data['site_info']['name']); ?> + loading="lazy" + onerror="this.style.display='none'"> @@ -301,12 +518,18 @@ class GitEmbedFeiCode {
- - - - +
+ + + + + + + + + - +
@@ -336,11 +559,11 @@ class GitEmbedFeiCode {
- +
View Repository @@ -349,7 +572,7 @@ class GitEmbedFeiCode {
@@ -408,10 +649,32 @@ class GitEmbedFeiCode { return ob_get_clean(); } + private function get_download_url(array $repo_data): string { + $platform = $repo_data['platform'] ?? 'github'; + $archive_url = $repo_data['archive_url'] ?? ''; + + switch ($platform) { + case 'github': + $url = str_replace('{archive_format}', 'zipball', $archive_url); + return str_replace('{/ref}', '/main', $url); + + case 'gitlab': + case 'gitea': + case 'forgejo': + case 'custom': + return $archive_url; + + default: + return $archive_url; + } + } + public function ajax_fetch_repo(): void { check_ajax_referer('git_embed_nonce', 'nonce'); $platform = sanitize_text_field($_POST['platform'] ?? ''); + $custom_domain = sanitize_text_field($_POST['customDomain'] ?? ''); + $custom_site_name = sanitize_text_field($_POST['customSiteName'] ?? ''); $owner = sanitize_text_field($_POST['owner'] ?? ''); $repo = sanitize_text_field($_POST['repo'] ?? ''); @@ -419,7 +682,11 @@ class GitEmbedFeiCode { wp_send_json_error('Repository information required'); } - $repo_data = $this->fetch_repository_data($platform, $owner, $repo); + if (in_array($platform, ['gitea', 'forgejo', 'gitlab', 'custom']) && empty($custom_domain)) { + wp_send_json_error('Custom domain required for ' . ucfirst($platform)); + } + + $repo_data = $this->fetch_repository_data($platform, $owner, $repo, $custom_domain, $custom_site_name); if (!$repo_data) { wp_send_json_error('Failed to fetch repository data'); @@ -436,6 +703,7 @@ class GitEmbedFeiCode { } $platform = sanitize_text_field($_POST['platform'] ?? ''); + $custom_domain = sanitize_text_field($_POST['customDomain'] ?? ''); $owner = sanitize_text_field($_POST['owner'] ?? ''); $repo = sanitize_text_field($_POST['repo'] ?? ''); @@ -443,13 +711,13 @@ class GitEmbedFeiCode { wp_send_json_error('Repository information required'); } - $this->clear_repository_cache($platform, $owner, $repo); + $this->clear_repository_cache($platform, $owner, $repo, $custom_domain); wp_send_json_success('Cache cleared successfully'); } - private function clear_repository_cache(string $platform, string $owner, string $repo): void { - $cache_key = "git_embed_{$platform}_{$owner}_{$repo}"; + private function clear_repository_cache(string $platform, string $owner, string $repo, string $custom_domain = ''): void { + $cache_key = "git_embed_{$platform}_{$owner}_{$repo}" . ($custom_domain ? "_{$custom_domain}" : ''); delete_transient($cache_key); global $wpdb; diff --git a/style.css b/style.css index 8a9a3dc..303eb9e 100644 --- a/style.css +++ b/style.css @@ -58,6 +58,30 @@ border: none; } +.git-embed-card-gradient { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + border: none; +} + +.git-embed-card-gradient .git-embed-title a, +.git-embed-card-gradient .git-embed-site-name a, +.git-embed-card-gradient .git-embed-owner-link { + color: rgba(255, 255, 255, 0.9); +} + +.git-embed-card-gradient .git-embed-description, +.git-embed-card-gradient .git-embed-stat { + color: rgba(255, 255, 255, 0.8); +} + +.git-embed-card-glass { + background: rgba(255, 255, 255, 0.25); + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.18); + box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37); +} + .git-embed-site-info { display: flex; align-items: center; @@ -89,6 +113,46 @@ text-decoration: underline; } +.git-embed-site-info.platform-github .git-embed-site-name a { + color: #24292f; +} + +.git-embed-site-info.platform-github .git-embed-site-name a:hover { + color: #0969da; +} + +.git-embed-site-info.platform-gitea .git-embed-site-name a { + color: #609926; +} + +.git-embed-site-info.platform-gitea .git-embed-site-name a:hover { + color: #4a7220; +} + +.git-embed-site-info.platform-forgejo .git-embed-site-name a { + color: #fb923c; +} + +.git-embed-site-info.platform-forgejo .git-embed-site-name a:hover { + color: #ea580c; +} + +.git-embed-site-info.platform-gitlab .git-embed-site-name a { + color: #fc6d26; +} + +.git-embed-site-info.platform-gitlab .git-embed-site-name a:hover { + color: #e24000; +} + +.git-embed-site-info.platform-custom .git-embed-site-name a { + color: #6366f1; +} + +.git-embed-site-info.platform-custom .git-embed-site-name a:hover { + color: #4f46e5; +} + .git-embed-header { display: flex; align-items: flex-start; @@ -318,6 +382,50 @@ text-decoration: none; } +.git-embed-button-ghost { + color: #0073aa; + background-color: transparent; + border-color: transparent; +} + +.git-embed-button-ghost:hover { + background-color: rgba(0, 115, 170, 0.1); + border-color: #0073aa; + color: #0073aa; + text-decoration: none; +} + +.git-embed-button-default { + color: #24292f; + background-color: #f6f8fa; + border-color: #d1d5da; +} + +.git-embed-button-default:hover { + background-color: #f3f4f6; + border-color: #c7ccd1; + color: #24292f; + text-decoration: none; +} + +.git-embed-button-small { + padding: 4px 8px; + font-size: 11px; + line-height: 1.4; +} + +.git-embed-button-medium { + padding: 6px 12px; + font-size: 12px; + line-height: 1.5; +} + +.git-embed-button-large { + padding: 8px 16px; + font-size: 14px; + line-height: 1.6; +} + .git-embed-clone-btn:hover .dashicons { animation: pulse 0.3s ease-in-out; } @@ -523,4 +631,52 @@ .git-embed-owner-type:empty { display: none; +} + +.git-embed-custom-domain-notice { + background: #fff3cd; + border: 1px solid #ffeaa7; + color: #856404; + padding: 8px 12px; + border-radius: 4px; + font-size: 12px; + margin-top: 8px; +} + +.git-embed-platform-badge { + display: inline-flex; + align-items: center; + gap: 4px; + font-size: 10px; + font-weight: 600; + padding: 2px 6px; + border-radius: 8px; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.git-embed-platform-badge.platform-github { + background: #f6f8fa; + color: #24292f; +} + +.git-embed-platform-badge.platform-gitea { + background: #f0f9e8; + color: #609926; +} + +.git-embed-platform-badge.platform-forgejo { + background: #fef3e2; + color: #fb923c; +} + +.components-panel__body .components-text-control__input:invalid { + border-color: #d63638; + box-shadow: 0 0 0 1px #d63638; +} + +.components-panel__body .components-text-control__help { + font-size: 12px; + color: #757575; + margin-top: 4px; } \ No newline at end of file