Skip to content

Commit 2b7a9cf

Browse files
authored
gcoai-stream-loading-text-animation.php: Added a new snippet for customizing the Steam field's loading text.
1 parent c61ee6a commit 2b7a9cf

File tree

1 file changed

+180
-0
lines changed

1 file changed

+180
-0
lines changed
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
<?php
2+
/**
3+
* Gravity Connect // OpenAI // Stream Loading Text Animation
4+
*
5+
* Adds a customizable shimmer animation and rotating spinner icon to the Stream field's
6+
* loading placeholders. Replaces the static "Loading..." text with animated text and/or
7+
* a rotating spinner icon.
8+
*/
9+
class GCOAI_Loading_Animation {
10+
11+
private $args;
12+
private static $styles_output = false;
13+
14+
public function __construct( $args = array() ) {
15+
$this->args = wp_parse_args( $args, array(
16+
'text' => 'Thinking...',
17+
'base_color' => '#000',
18+
'shimmer_color' => '#fff',
19+
'shimmer_duration' => '2.2s',
20+
'show_shimmer' => true,
21+
'show_spinner' => false,
22+
'spinner_size' => '24',
23+
'form_id' => null,
24+
) );
25+
26+
add_filter( 'gform_gcoai_field_loading_text', array( $this, 'filter_loading_text' ), 10, 3 );
27+
add_action( 'gform_register_init_scripts', array( $this, 'register_init_script' ), 10, 3 );
28+
add_action( 'wp_head', array( $this, 'output_styles' ) );
29+
add_action( 'admin_head', array( $this, 'output_styles' ) );
30+
}
31+
32+
public function register_init_script( $form, $field_values, $is_ajax ) {
33+
if ( empty( $form['id'] ) ) {
34+
return;
35+
}
36+
37+
// If form_id is specified, only run scripts on those forms
38+
if ( $this->args['form_id'] !== null ) {
39+
$form_ids = is_array( $this->args['form_id'] ) ? $this->args['form_id'] : array( $this->args['form_id'] );
40+
if ( ! in_array( $form['id'], $form_ids ) ) {
41+
return;
42+
}
43+
}
44+
45+
$markup = $this->get_shimmer_markup();
46+
$css = $this->get_styles_css();
47+
48+
$script = sprintf(
49+
"(function($) {
50+
var shimmerMarkup = %s;
51+
var shimmerStyles = %s;
52+
53+
function addStylesToPage() {
54+
if ( ! $('style.gw-gcoai-shimmer-style').length ) {
55+
$('<style>')
56+
.addClass('gw-gcoai-shimmer-style')
57+
.text(shimmerStyles)
58+
.appendTo('head');
59+
}
60+
}
61+
62+
function applyShimmerToPlaceholders(\$container) {
63+
var \$searchContext = \$container && \$container.length ? \$container : $(document);
64+
\$searchContext.find('.gcoai-output .gcoai-placeholder').html(shimmerMarkup);
65+
}
66+
67+
if ( window.gform && typeof window.gform.addFilter === 'function' ) {
68+
window.gform.addFilter('gcoai_stream_loading_placeholder', function(current, instance) {
69+
return shimmerMarkup;
70+
});
71+
}
72+
73+
$(function() {
74+
addStylesToPage();
75+
applyShimmerToPlaceholders();
76+
});
77+
78+
// Re-apply after Generate/Regenerate clicks
79+
$(document).on('click', '.gcoai-trigger, .gcoai-regenerate', function() {
80+
setTimeout(function() {
81+
applyShimmerToPlaceholders();
82+
}, 50);
83+
});
84+
85+
// Re-apply after AJAX completes
86+
$(document).ajaxComplete(function() {
87+
applyShimmerToPlaceholders();
88+
});
89+
})(jQuery);",
90+
wp_json_encode( $markup ),
91+
wp_json_encode( $css )
92+
);
93+
94+
GFFormDisplay::add_init_script( $form['id'], 'gcoai_loading_animation', GFFormDisplay::ON_PAGE_RENDER, $script );
95+
}
96+
97+
public function output_styles() {
98+
// Prevent duplicate output
99+
if ( self::$styles_output ) {
100+
return;
101+
}
102+
103+
$css = $this->get_styles_css();
104+
echo '<style class="gw-gcoai-shimmer-style">' . $css . '</style>';
105+
106+
self::$styles_output = true;
107+
}
108+
109+
public function get_shimmer_markup() {
110+
$spinner = '';
111+
112+
if ( $this->args['show_spinner'] ) {
113+
$spinner = sprintf(
114+
'<svg class="shimmer-spinner" xmlns="http://www.w3.org/2000/svg" width="%s" height="%s" stroke="%s" viewBox="0 0 24 24">
115+
<g class="spinner-rotate">
116+
<circle cx="12" cy="12" r="9.5" fill="none" stroke-width="1.5"/>
117+
</g>
118+
</svg>',
119+
esc_attr( $this->args['spinner_size'] ),
120+
esc_attr( $this->args['spinner_size'] ),
121+
esc_attr( $this->args['base_color'] )
122+
);
123+
}
124+
125+
$text_class = $this->args['show_shimmer'] ? 'shimmer' : 'shimmer-text';
126+
127+
return sprintf(
128+
'<span class="shimmer-wrapper">%s<span class="%s">%s</span></span>',
129+
$spinner,
130+
$text_class,
131+
esc_html( $this->args['text'] )
132+
);
133+
}
134+
135+
public function filter_loading_text( $placeholder, $field, $form = null ) {
136+
if ( ! class_exists( '\\GC_OpenAI\\Fields\\Stream' ) || ! $field instanceof \GC_OpenAI\Fields\Stream ) {
137+
return $placeholder;
138+
}
139+
140+
// If form_id is specified, only apply to those forms
141+
if ( $this->args['form_id'] !== null ) {
142+
$form_ids = is_array( $this->args['form_id'] ) ? $this->args['form_id'] : array( $this->args['form_id'] );
143+
if ( $form && ! in_array( rgar( $form, 'id' ), $form_ids ) ) {
144+
return $placeholder;
145+
}
146+
}
147+
148+
return $this->get_shimmer_markup();
149+
}
150+
151+
private function get_styles_css() {
152+
$base = esc_attr( $this->args['base_color'] );
153+
$shimmer = esc_attr( $this->args['shimmer_color'] );
154+
$dur = esc_attr( $this->args['shimmer_duration'] );
155+
156+
return
157+
'.shimmer-wrapper { display: inline-flex; align-items: center; gap: 8px; } ' .
158+
'.shimmer-spinner { flex-shrink: 0; } ' .
159+
'.spinner-rotate { transform-origin: center; animation: spinner-rotation 2s linear infinite; } ' .
160+
'.spinner-rotate circle { stroke-linecap: round; animation: spinner-stroke 1.5s ease-in-out infinite; } ' .
161+
'@keyframes spinner-rotation { 100% { transform: rotate(360deg); } } ' .
162+
'@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; } } ' .
163+
".shimmer-text { display: inline-block; color: {$base}; line-height: 1.2; } " .
164+
".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; } " .
165+
'@keyframes shimmer { 0% { background-position: -4rem top; } 70%, 100% { background-position: 12.5rem top; } }';
166+
}
167+
}
168+
169+
# Configuration
170+
171+
new GCOAI_Loading_Animation( array(
172+
'text' => 'Thinking...',
173+
'base_color' => '#292929',
174+
'shimmer_color' => '#fff',
175+
'shimmer_duration' => '2.2s',
176+
'show_shimmer' => true,
177+
'show_spinner' => true,
178+
'spinner_size' => '16',
179+
// 'form_id' => 123, // Uncomment and set to target specific form(s): 123 or array( 18, 22, 35 )
180+
) );

0 commit comments

Comments
 (0)