diff --git a/ansico-some-plugin/admin-script.js b/ansico-some-plugin/admin-script.js new file mode 100644 index 0000000..01b7814 --- /dev/null +++ b/ansico-some-plugin/admin-script.js @@ -0,0 +1,19 @@ +jQuery(document).ready(function($){ + var mediaUploader; + $('#ansico-upload-button').click(function(e) { + e.preventDefault(); + if (mediaUploader) { mediaUploader.open(); return; } + mediaUploader = wp.media({ title: 'Choose Avatar', button: { text: 'Set as Profile Picture' }, multiple: false }); + mediaUploader.on('select', function() { + var attachment = mediaUploader.state().get('selection').first().toJSON(); + $('#ansico-avatar-url').val(attachment.url); + $('#ansico-avatar-preview').attr('src', attachment.url).show(); + }); + mediaUploader.open(); + }); + $('#ansico-remove-button').click(function(e){ + e.preventDefault(); + $('#ansico-avatar-url').val(''); + $('#ansico-avatar-preview').hide().attr('src', ''); + }); +}); \ No newline at end of file diff --git a/ansico-some-plugin/ansico-some-plugin.php b/ansico-some-plugin/ansico-some-plugin.php new file mode 100644 index 0000000..9bb33cb --- /dev/null +++ b/ansico-some-plugin/ansico-some-plugin.php @@ -0,0 +1,176 @@ +ID, 'ansico_avatar_url', true ); + ?> +

Ansico Avatar

+ + + + + +
+ + + + +

Upload a custom profile picture. This will override Gravatar. If empty, Gravatar or standard logo will be used.

+
+ user_id ) ) { $user_id = $id_or_email->user_id; } + elseif ( is_string( $id_or_email ) ) { $user = get_user_by( 'email', $id_or_email ); if ( $user ) { $user_id = $user->ID; } } + + if ( $user_id ) { + $custom_avatar = get_user_meta( $user_id, 'ansico_avatar_url', true ); + if ( ! empty( $custom_avatar ) ) { return $custom_avatar; } + } + return $url; +} + +add_action( 'init', 'ansico_some_register_blocks' ); +function ansico_some_register_blocks() { + wp_register_script( + 'ansico-some-blocks-script', + plugins_url( 'block.js', __FILE__ ), + array( 'wp-blocks', 'wp-element', 'wp-block-editor', 'wp-data', 'wp-components' ), + '1.0.0' + ); + + wp_register_style( + 'ansico-some-blocks-style', + plugins_url( 'style.css', __FILE__ ), + array(), + '1.0.0' + ); + + register_block_type( 'ansico/some-author', array( + 'editor_script' => 'ansico-some-blocks-script', + 'editor_style' => 'ansico-some-blocks-style', + 'style' => 'ansico-some-blocks-style', + 'render_callback' => 'ansico_some_render_author_block' + ) ); + + register_block_type( 'ansico/some-comment', array( + 'editor_script' => 'ansico-some-blocks-script', + 'editor_style' => 'ansico-some-blocks-style', + 'style' => 'ansico-some-blocks-style', + 'render_callback' => 'ansico_some_render_comment_block' + ) ); +} + +function ansico_some_render_author_block( $attributes, $content, $block ) { + $post_id = get_the_ID(); + $author_id = get_post_field( 'post_author', $post_id ) ?: get_current_user_id(); + $name = get_the_author_meta( 'display_name', $author_id ); + $bio = get_the_author_meta( 'description', $author_id ); + $avatar_url = get_avatar_url( $author_id, array( 'size' => 100 ) ); + + ob_start(); + ?> +
'ansico-compact-author' ) ); ?>> +
+ Avatar +
+

+
+ +
+
+
+ 50 ) ); + + $domain = ''; + if ( ! empty( $url ) ) { + $domain = parse_url( $url, PHP_URL_HOST ); + $domain = str_replace( 'www.', '', $domain ); + } + + $time_display = $time; + if ( ! empty( $time ) ) { + $timestamp = strtotime( $time ); + if ( $timestamp ) { + $date_format = get_option( 'date_format' ); + $time_format = get_option( 'time_format' ); + $formatted_time = wp_date( $time_format, $timestamp ); + $formatted_date = wp_date( $date_format, $timestamp ); + $time_display = $formatted_time . ' · ' . $formatted_date; + } + } + + $source_label = __( 'Source:', 'ansico-some-plugin' ); + if ( $source_label === 'Source:' ) { + $locale = get_locale(); + if ( strpos( $locale, 'da' ) === 0 ) { $source_label = 'Kilde:'; } + elseif ( strpos( $locale, 'sv' ) === 0 ) { $source_label = 'Källa:'; } + elseif ( strpos( $locale, 'no' ) === 0 || strpos( $locale, 'nb' ) === 0 || strpos( $locale, 'nn' ) === 0 ) { $source_label = 'Kilde:'; } + elseif ( strpos( $locale, 'de' ) === 0 ) { $source_label = 'Quelle:'; } + } + + ob_start(); + ?> +
'ansico-some-tweet' ) ); ?>> + Avatar +
+
+ + +
+
+ + + +
+
+ \ No newline at end of file diff --git a/ansico-some-plugin/block.js b/ansico-some-plugin/block.js new file mode 100644 index 0000000..b05adb7 --- /dev/null +++ b/ansico-some-plugin/block.js @@ -0,0 +1,73 @@ +( function( blocks, element, blockEditor, data, components ) { + var el = element.createElement; + var useBlockProps = blockEditor.useBlockProps; + var InnerBlocks = blockEditor.InnerBlocks; + var TextControl = components.TextControl; + var TextareaControl = components.TextareaControl; + var useSelect = data.useSelect; + var Spinner = components.Spinner; + + blocks.registerBlockType( 'ansico/some-author', { + title: 'Ansico Author Profile', icon: 'admin-users', category: 'widgets', supports: { html: false }, + edit: function( props ) { + var blockProps = useBlockProps(); + var authorDetails = useSelect( function( select ) { + var core = select( 'core' ); var editor = select( 'core/editor' ); + var authorId = editor ? editor.getCurrentPostAttribute( 'author' ) : null; + if ( ! authorId ) { var currentUser = core.getCurrentUser(); authorId = currentUser ? currentUser.id : null; } + return authorId ? core.getUser( authorId ) : null; + }, [] ); + if ( ! authorDetails ) { return el( 'div', blockProps, el( Spinner ) ); } + var avatarUrl = authorDetails.avatar_urls ? authorDetails.avatar_urls['96'] : ''; + + return el( 'div', blockProps, + el( 'div', { className: 'ansico-some-author-box' }, + el( 'img', { src: avatarUrl, className: 'ansico-some-avatar', alt: 'Avatar' } ), + el( 'div', { className: 'ansico-some-info' }, + el( 'h3', { className: 'ansico-some-name' }, authorDetails.name || 'Author Name' ), + el( 'p', { className: 'ansico-some-bio' }, authorDetails.description || '...' ), + el( 'div', { className: 'ansico-some-social-links' }, + el( InnerBlocks, { allowedBlocks: [ 'core/social-links' ], template: [ [ 'core/social-links', {}, [] ] ] } ) + ) + ) + ) + ); + }, + save: function() { return el( 'div', useBlockProps.save(), el( InnerBlocks.Content ) ); } + } ); + + blocks.registerBlockType( 'ansico/some-comment', { + title: 'Ansico SoMe Comment', icon: 'format-status', category: 'widgets', supports: { html: false }, + attributes: { text: { type: 'string', default: '' }, url: { type: 'string', default: '' }, time: { type: 'string', default: '' } }, + edit: function( props ) { + var attributes = props.attributes; var setAttributes = props.setAttributes; var blockProps = useBlockProps(); + var authorDetails = useSelect( function( select ) { + var core = select( 'core' ); var editor = select( 'core/editor' ); + var authorId = editor ? editor.getCurrentPostAttribute( 'author' ) : null; + if ( ! authorId ) { var currentUser = core.getCurrentUser(); authorId = currentUser ? currentUser.id : null; } + return authorId ? core.getUser( authorId ) : null; + }, [] ); + if ( ! authorDetails ) { return el( 'div', blockProps, el( Spinner ) ); } + var avatarUrl = authorDetails.avatar_urls ? authorDetails.avatar_urls['48'] : ''; + + return el( 'div', blockProps, + el( 'div', { className: 'ansico-some-tweet' }, + el( 'img', { src: avatarUrl, className: 'ansico-tweet-avatar', alt: 'Avatar' } ), + el( 'div', { className: 'ansico-tweet-content' }, + el( 'div', { className: 'ansico-tweet-header' }, + el( 'span', { className: 'ansico-tweet-name' }, authorDetails.name || 'Author' ), + el( 'span', { className: 'ansico-tweet-time' }, attributes.time || 'Time' ) + ), + el( 'div', { className: 'ansico-tweet-text' }, attributes.text || 'Message text...' ) + ) + ), + el( 'div', { style: { marginTop: '10px', borderTop: '1px solid #ddd', paddingTop: '10px' } }, + el( TextareaControl, { label: 'Comment Text', value: attributes.text, onChange: function( v ) { setAttributes( { text: v } ); } } ), + el( TextControl, { label: 'Source URL', value: attributes.url, onChange: function( v ) { setAttributes( { url: v } ); } } ), + el( TextControl, { label: 'Time (e.g. 2026-04-12 19:43)', value: attributes.time, onChange: function( v ) { setAttributes( { time: v } ); } } ) + ) + ); + }, + save: function() { return null; } + } ); +} )( window.wp.blocks, window.wp.element, window.wp.blockEditor, window.wp.data, window.wp.components ); \ No newline at end of file diff --git a/ansico-some-plugin/style.css b/ansico-some-plugin/style.css new file mode 100644 index 0000000..2459744 --- /dev/null +++ b/ansico-some-plugin/style.css @@ -0,0 +1,54 @@ +/* Author Profile - Compact */ +.ansico-some-author-box { display: flex; gap: 20px; align-items: flex-start; background: #ffffff; padding: 15px; border-radius: 8px; border: 1px solid #eaeaea; } +.ansico-some-avatar { width: 80px; height: 80px; min-width: 80px; border-radius: 50%; object-fit: cover; border: 2px solid #f0f0f0; margin: 0 !important; } +.ansico-some-name { margin: 0 0 5px 0 !important; font-size: 18px; font-weight: 700; } +.ansico-some-bio { margin: 0 0 10px 0 !important; font-size: 14px; color: #444; line-height: 1.5; } + +/* SoMe Comment (Tweet Style) - FORCED LAYOUT */ +.ansico-some-tweet { + display: flex !important; + flex-direction: row !important; + gap: 12px !important; + align-items: flex-start !important; + padding: 12px; + border: 1px solid #eff3f4; + border-radius: 12px; + background: #ffffff; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + margin-bottom: 24px; + box-sizing: border-box; +} + +.ansico-tweet-avatar { + width: 48px !important; + height: 48px !important; + min-width: 48px !important; + border-radius: 50% !important; + object-fit: cover !important; + margin: 0 !important; + display: block !important; +} + +.ansico-tweet-content { + flex: 1 1 auto !important; + width: 100%; +} + +.ansico-tweet-header { + display: flex !important; + align-items: baseline !important; + flex-wrap: wrap; + gap: 8px !important; + margin-bottom: 2px !important; +} + +.ansico-tweet-name { font-weight: 700 !important; color: #0f1419 !important; font-size: 15px !important; } +.ansico-tweet-time { color: #536471 !important; font-size: 14px !important; } +.ansico-tweet-text { font-size: 15px !important; line-height: 1.4 !important; color: #0f1419 !important; } +.ansico-tweet-text p { margin-top: 0; } +.ansico-tweet-footer { font-size: 11px !important; color: #536471 !important; margin-top: 8px !important; } +.ansico-tweet-footer a { color: #1d9bf0 !important; text-decoration: none !important; } +.ansico-tweet-footer a:hover { text-decoration: underline !important; } + +.wp-block-ansico-some-author .ansico-some-bio { font-size: 14px; } +.wp-block-ansico-some-author { margin-bottom: 24px; } \ No newline at end of file