Skip to content
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 180 additions & 0 deletions gc-openai/gcoai-stream-loading-text-animation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
<?php
/**
* Gravity Connect // OpenAI // Stream Loading Text Animation
*
* Adds a customizable shimmer animation and rotating spinner icon to the Stream field's
* loading placeholders. Replaces the static "Loading..." text with animated text and/or
* a rotating spinner icon.
*/
class GCOAI_Loading_Animation {

private $args;
private static $styles_output = false;

public function __construct( $args = array() ) {
$this->args = wp_parse_args( $args, array(
'text' => 'Thinking...',
'base_color' => '#000',
'shimmer_color' => '#fff',
'shimmer_duration' => '2.2s',
'show_shimmer' => true,
'show_spinner' => false,
'spinner_size' => '24',
'form_id' => null,
) );

add_filter( 'gform_gcoai_field_loading_text', array( $this, 'filter_loading_text' ), 10, 3 );
add_action( 'gform_register_init_scripts', array( $this, 'register_init_script' ), 10, 3 );
add_action( 'wp_head', array( $this, 'output_styles' ) );
add_action( 'admin_head', array( $this, 'output_styles' ) );
}

public function register_init_script( $form, $field_values, $is_ajax ) {
if ( empty( $form['id'] ) ) {
return;
}

// If form_id is specified, only run scripts on those forms
if ( $this->args['form_id'] !== null ) {
$form_ids = is_array( $this->args['form_id'] ) ? $this->args['form_id'] : array( $this->args['form_id'] );
if ( ! in_array( $form['id'], $form_ids ) ) {
return;
}
}

$markup = $this->get_shimmer_markup();
$css = $this->get_styles_css();

$script = sprintf(
"(function($) {
var shimmerMarkup = %s;
var shimmerStyles = %s;

function addStylesToPage() {
if ( ! $('style.gw-gcoai-shimmer-style').length ) {
$('<style>')
.addClass('gw-gcoai-shimmer-style')
.text(shimmerStyles)
.appendTo('head');
}
}

function applyShimmerToPlaceholders(\$container) {
var \$searchContext = \$container && \$container.length ? \$container : $(document);
\$searchContext.find('.gcoai-output .gcoai-placeholder').html(shimmerMarkup);
}

if ( window.gform && typeof window.gform.addFilter === 'function' ) {
window.gform.addFilter('gcoai_stream_loading_placeholder', function(current, instance) {
return shimmerMarkup;
});
}

$(function() {
addStylesToPage();
applyShimmerToPlaceholders();
});

// Re-apply after Generate/Regenerate clicks
$(document).on('click', '.gcoai-trigger, .gcoai-regenerate', function() {
setTimeout(function() {
applyShimmerToPlaceholders();
}, 50);
});

// Re-apply after AJAX completes
$(document).ajaxComplete(function() {
applyShimmerToPlaceholders();
});
})(jQuery);",
wp_json_encode( $markup ),
wp_json_encode( $css )
);

GFFormDisplay::add_init_script( $form['id'], 'gcoai_loading_animation', GFFormDisplay::ON_PAGE_RENDER, $script );
}

public function output_styles() {
// Prevent duplicate output
if ( self::$styles_output ) {
return;
}

$css = $this->get_styles_css();
echo '<style class="gw-gcoai-shimmer-style">' . $css . '</style>';

Check failure on line 105 in gc-openai/gcoai-stream-loading-text-animation.php

View workflow job for this annotation

GitHub Actions / PHPCS (Files Changed)

Whitespace found at end of line
self::$styles_output = true;
}

public function get_shimmer_markup() {
$spinner = '';

if ( $this->args['show_spinner'] ) {
$spinner = sprintf(
'<svg class="shimmer-spinner" xmlns="http://www.w3.org/2000/svg" width="%s" height="%s" stroke="%s" viewBox="0 0 24 24">
<g class="spinner-rotate">
<circle cx="12" cy="12" r="9.5" fill="none" stroke-width="1.5"/>
</g>
</svg>',
esc_attr( $this->args['spinner_size'] ),
esc_attr( $this->args['spinner_size'] ),
esc_attr( $this->args['base_color'] )
);
}

$text_class = $this->args['show_shimmer'] ? 'shimmer' : 'shimmer-text';

return sprintf(
'<span class="shimmer-wrapper">%s<span class="%s">%s</span></span>',
$spinner,
$text_class,
esc_html( $this->args['text'] )
);
}

public function filter_loading_text( $placeholder, $field, $form = null ) {
if ( ! class_exists( '\\GC_OpenAI\\Fields\\Stream' ) || ! $field instanceof \GC_OpenAI\Fields\Stream ) {
return $placeholder;
}

// If form_id is specified, only apply to those forms
if ( $this->args['form_id'] !== null ) {
$form_ids = is_array( $this->args['form_id'] ) ? $this->args['form_id'] : array( $this->args['form_id'] );
if ( $form && ! in_array( rgar( $form, 'id' ), $form_ids ) ) {
return $placeholder;
}
}

return $this->get_shimmer_markup();
}

private function get_styles_css() {
$base = esc_attr( $this->args['base_color'] );
$shimmer = esc_attr( $this->args['shimmer_color'] );
$dur = esc_attr( $this->args['shimmer_duration'] );

return

Check failure on line 156 in gc-openai/gcoai-stream-loading-text-animation.php

View workflow job for this annotation

GitHub Actions / PHPCS (Files Changed)

Whitespace found at end of line
".shimmer-wrapper { display: inline-flex; align-items: center; gap: 8px; } " .

Check failure on line 157 in gc-openai/gcoai-stream-loading-text-animation.php

View workflow job for this annotation

GitHub Actions / PHPCS (Files Changed)

String &quot;.shimmer-wrapper { display: inline-flex; align-items: center; gap: 8px; } &quot; does not require double quotes; use single quotes instead
".shimmer-spinner { flex-shrink: 0; } " .

Check failure on line 158 in gc-openai/gcoai-stream-loading-text-animation.php

View workflow job for this annotation

GitHub Actions / PHPCS (Files Changed)

String &quot;.shimmer-spinner { flex-shrink: 0; } &quot; does not require double quotes; use single quotes instead
".spinner-rotate { transform-origin: center; animation: spinner-rotation 2s linear infinite; } " .

Check failure on line 159 in gc-openai/gcoai-stream-loading-text-animation.php

View workflow job for this annotation

GitHub Actions / PHPCS (Files Changed)

String &quot;.spinner-rotate { transform-origin: center; animation: spinner-rotation 2s linear infinite; } &quot; does not require double quotes; use single quotes instead
".spinner-rotate circle { stroke-linecap: round; animation: spinner-stroke 1.5s ease-in-out infinite; } " .

Check failure on line 160 in gc-openai/gcoai-stream-loading-text-animation.php

View workflow job for this annotation

GitHub Actions / PHPCS (Files Changed)

String &quot;.spinner-rotate circle { stroke-linecap: round; animation: spinner-stroke 1.5s ease-in-out infinite; } &quot; does not require double quotes; use single quotes instead
"@keyframes spinner-rotation { 100% { transform: rotate(360deg); } } " .

Check failure on line 161 in gc-openai/gcoai-stream-loading-text-animation.php

View workflow job for this annotation

GitHub Actions / PHPCS (Files Changed)

String &quot;@Keyframes spinner-rotation { 100% { transform: rotate(360deg); } } &quot; does not require double quotes; use single quotes instead
"@keyframes spinner-stroke { 0% { stroke-dasharray: 0 150; stroke-dashoffset: 0; } 47.5% { stroke-dasharray: 42 150; stroke-dashoffset: -16; } 95%, 100% { stroke-dasharray: 42 150; stroke-dashoffset: -59; } } " .

Check failure on line 162 in gc-openai/gcoai-stream-loading-text-animation.php

View workflow job for this annotation

GitHub Actions / PHPCS (Files Changed)

String &quot;@Keyframes spinner-stroke { 0% { stroke-dasharray: 0 150; stroke-dashoffset: 0; } 47.5% { stroke-dasharray: 42 150; stroke-dashoffset: -16; } 95%, 100% { stroke-dasharray: 42 150; stroke-dashoffset: -59; } } &quot; does not require double quotes; use single quotes instead
".shimmer-text { display: inline-block; color: {$base}; line-height: 1.2; } " .
".shimmer { display: inline-block; color: {$base}; line-height: 1.2; background: {$base} linear-gradient(to left, {$base}, {$shimmer} 50%, {$base}); background-position: -4rem top; background-repeat: no-repeat; background-size: 4rem 100%; -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; animation: shimmer {$dur} infinite; } " .
"@keyframes shimmer { 0% { background-position: -4rem top; } 70%, 100% { background-position: 12.5rem top; } }";

Check failure on line 165 in gc-openai/gcoai-stream-loading-text-animation.php

View workflow job for this annotation

GitHub Actions / PHPCS (Files Changed)

String &quot;@Keyframes shimmer { 0% { background-position: -4rem top; } 70%, 100% { background-position: 12.5rem top; } }&quot; does not require double quotes; use single quotes instead
}
}

# Configuration

new GCOAI_Loading_Animation( array(
'text' => 'Thinking...',
'base_color' => '#292929',
'shimmer_color' => '#fff',
'shimmer_duration' => '2.2s',
'show_shimmer' => true,
'show_spinner' => true,
'spinner_size' => '16',
// 'form_id' => 123, // Uncomment and set to target specific form(s): 123 or array( 18, 22, 35 )
) );
Loading