PluginProbe
Copy Anything to Clipboard for WordPress – Copy Button, Copy Text & Copy Code / 5.5.4
Copy Anything to Clipboard for WordPress – Copy Button, Copy Text & Copy Code v5.5.4
5.5.4 5.5.3 3.1.0 3.2.0 3.2.1 3.3.0 3.4.0 3.4.1 3.4.2 3.4.3 3.5.0 3.5.1 3.5.2 3.6.0 3.7.0 3.8.0 3.8.1 3.8.2 3.8.3 4.0.0 4.0.2 4.0.3 4.0.4 4.0.5 4.1.0 All 79 releases
copy-the-code / includes / global-injector / styles / class-icon.php

class-icon.php in Copy Anything to Clipboard for WordPress – Copy Button, Copy Text & Copy Code 5.5.4, at includes/global-injector/styles/class-icon.php

370 lines 11.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Icon Style for Global Injector
4 *
5 * Defines the JSON schema, icons, and rendering logic for the Icon visual style.
6 * This class serves as the single source of truth for both PHP (frontend) and JS (admin preview).
7 *
8 * @package CTC
9 * @since 5.0.0
10 */
11
12 namespace CTC\Global_Injector\Styles;
13
14 /**
15 * Icon Style Class
16 */
17 class Icon {
18
19 /**
20 * Get the default configuration for icon style.
21 *
22 * This is the single source of truth for the icon JSON schema.
23 * Used by both PHP renderer and localized to JS for admin preview.
24 *
25 * @return array Default icon configuration.
26 */
27 public static function get_default_config() {
28 return [
29 'text' => [
30 'tooltip_text' => 'Copy to clipboard',
31 'success_text' => 'Copied!',
32 ],
33 'icon' => [
34 'icon_key' => 'clipboard',
35 'custom_url' => null, // Pro feature: custom icon URL.
36 ],
37 'style' => [
38 'icon_color' => '#6b7280',
39 'icon_hover_color' => '#4f46e5',
40 'bg_color' => '#ffffff',
41 'border_color' => '#e5e7eb',
42 'icon_size' => '16px',
43 'padding' => '8px',
44 'border_radius' => '8px',
45 'border_width' => '1px',
46 ],
47 ];
48 }
49
50 /**
51 * Get available icons for icon style.
52 *
53 * Each icon has a key and SVG markup.
54 * The key is stored in config, SVG is used for rendering.
55 *
56 * @return array Array of icons with key => SVG markup.
57 */
58 public static function get_icons() {
59 return [
60 'clipboard' => [
61 'label' => 'Clipboard',
62 'svg' => '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"/></svg>',
63 ],
64 'copy' => [
65 'label' => 'Copy',
66 'svg' => '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3"/></svg>',
67 ],
68 'paperclip' => [
69 'label' => 'Attachment',
70 'svg' => '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13"/></svg>',
71 ],
72 'link' => [
73 'label' => 'Link',
74 'svg' => '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"/></svg>',
75 ],
76 'document' => [
77 'label' => 'Document',
78 'svg' => '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/></svg>',
79 ],
80 'check' => [
81 'label' => 'Checkmark',
82 'svg' => '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>',
83 ],
84 ];
85 }
86
87 /**
88 * Get success icon (shown after copy).
89 *
90 * @return string SVG markup for success icon.
91 */
92 public static function get_success_icon() {
93 return '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>';
94 }
95
96 /**
97 * Generate a unique icon ID.
98 *
99 * @return string Unique icon ID.
100 */
101 public static function generate_icon_id() {
102 return 'ctc-copy-icon-' . wp_generate_password( 8, false, false );
103 }
104
105 /**
106 * Merge user config with defaults.
107 *
108 * @param array $user_config User-provided configuration.
109 * @return array Merged configuration.
110 */
111 public static function merge_config( $user_config = [] ) {
112 $defaults = self::get_default_config();
113
114 // Deep merge.
115 $merged = $defaults;
116
117 if ( isset( $user_config['text'] ) && is_array( $user_config['text'] ) ) {
118 $merged['text'] = array_merge( $defaults['text'], $user_config['text'] );
119 }
120
121 if ( isset( $user_config['icon'] ) && is_array( $user_config['icon'] ) ) {
122 $merged['icon'] = array_merge( $defaults['icon'], $user_config['icon'] );
123 }
124
125 if ( isset( $user_config['style'] ) && is_array( $user_config['style'] ) ) {
126 $merged['style'] = array_merge( $defaults['style'], $user_config['style'] );
127 }
128
129 return $merged;
130 }
131
132 /**
133 * Get the icon SVG by key.
134 *
135 * @param string $icon_key Icon key.
136 * @return string SVG markup or empty string if not found.
137 */
138 public static function get_icon_svg( $icon_key ) {
139 $icons = self::get_icons();
140
141 if ( isset( $icons[ $icon_key ]['svg'] ) ) {
142 return $icons[ $icon_key ]['svg'];
143 }
144
145 // Fallback to clipboard icon.
146 return $icons['clipboard']['svg'];
147 }
148
149 /**
150 * Build inline CSS variables from style config.
151 *
152 * @param array $style Style configuration.
153 * @return string Inline style attribute value.
154 */
155 public static function build_inline_styles( $style ) {
156 $css_vars = [
157 '--ctc-icon-color' => $style['icon_color'],
158 '--ctc-icon-hover-color' => $style['icon_hover_color'],
159 '--ctc-icon-bg' => $style['bg_color'],
160 '--ctc-icon-border' => $style['border_color'],
161 '--ctc-icon-size' => $style['icon_size'],
162 '--ctc-icon-padding' => $style['padding'],
163 '--ctc-icon-radius' => $style['border_radius'],
164 '--ctc-icon-border-width' => $style['border_width'],
165 ];
166
167 // Map CSS var names to property keys for unit detection.
168 $var_to_prop = [
169 '--ctc-icon-size' => 'icon_size',
170 '--ctc-icon-padding' => 'padding',
171 '--ctc-icon-radius' => 'border_radius',
172 '--ctc-icon-border-width' => 'border_width',
173 ];
174
175 $inline = [];
176 foreach ( $css_vars as $var => $value ) {
177 // Add 'px' unit for numeric properties.
178 if ( isset( $var_to_prop[ $var ] ) && is_numeric( $value ) ) {
179 $value = $value . 'px';
180 }
181 $inline[] = esc_attr( $var ) . ': ' . esc_attr( $value );
182 }
183
184 return implode( '; ', $inline );
185 }
186
187 /**
188 * Render the icon button HTML.
189 *
190 * This is the main render function used on the frontend.
191 * The same logic should be replicated in JS for admin preview.
192 *
193 * @param array $config Icon configuration (merged with defaults).
194 * @param string $icon_id Optional. Unique icon ID. Auto-generated if not provided.
195 * @return string Icon button HTML markup.
196 */
197 public static function render( $config = [], $icon_id = null ) {
198 // Merge with defaults.
199 $config = self::merge_config( $config );
200
201 // Generate icon ID if not provided.
202 if ( empty( $icon_id ) ) {
203 $icon_id = self::generate_icon_id();
204 }
205
206 // Get icon SVG.
207 $icon_svg = '';
208 if ( ! empty( $config['icon']['custom_url'] ) ) {
209 // Pro feature: custom icon.
210 $icon_svg = '<img src="' . esc_url( $config['icon']['custom_url'] ) . '" alt="" class="ctc-icon-img" />';
211 } else {
212 $icon_svg = '<span class="ctc-icon-svg">' . self::get_icon_svg( $config['icon']['icon_key'] ) . '</span>';
213 }
214
215 // Build inline styles.
216 $inline_styles = self::build_inline_styles( $config['style'] );
217
218 // Build the icon button HTML.
219 $html = sprintf(
220 '<button id="%s" class="ctc-copy-icon" style="%s" data-tooltip="%s" data-success-text="%s" aria-label="%s">%s</button>',
221 esc_attr( $icon_id ),
222 esc_attr( $inline_styles ),
223 esc_attr( $config['text']['tooltip_text'] ),
224 esc_attr( $config['text']['success_text'] ),
225 esc_attr( $config['text']['tooltip_text'] ),
226 $icon_svg
227 );
228
229 return $html;
230 }
231
232 /**
233 * Get base CSS for icon style.
234 *
235 * This CSS uses CSS variables that are set inline on each icon button.
236 * These are the "hidden" styles that users don't customize via UI.
237 *
238 * @return string CSS styles.
239 */
240 public static function get_base_css() {
241 return '
242 .ctc-copy-icon {
243 /* User-customizable via CSS variables */
244 color: var(--ctc-icon-color, #6b7280);
245 background-color: var(--ctc-icon-bg, #ffffff);
246 border-color: var(--ctc-icon-border, #e5e7eb);
247 border-width: var(--ctc-icon-border-width, 1px);
248 padding: var(--ctc-icon-padding, 8px);
249 border-radius: var(--ctc-icon-radius, 8px);
250
251 /* Hidden CSS - always applied, not customizable via UI */
252 display: inline-flex;
253 align-items: center;
254 justify-content: center;
255 border-style: solid;
256 cursor: pointer;
257 transition: all 0.2s ease;
258 position: absolute;
259 top: 8px;
260 right: 8px;
261 z-index: 10;
262 box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
263 }
264
265 .ctc-copy-icon:hover {
266 color: var(--ctc-icon-hover-color, #4f46e5);
267 background-color: var(--ctc-icon-bg, #ffffff);
268 }
269
270 .ctc-copy-icon:focus {
271 outline: 2px solid var(--ctc-icon-hover-color, #4f46e5);
272 outline-offset: 2px;
273 }
274
275 .ctc-copy-icon .ctc-icon-svg {
276 display: inline-flex;
277 align-items: center;
278 justify-content: center;
279 }
280
281 .ctc-copy-icon .ctc-icon-svg svg {
282 width: var(--ctc-icon-size, 16px);
283 height: var(--ctc-icon-size, 16px);
284 }
285
286 .ctc-copy-icon .ctc-icon-img {
287 width: var(--ctc-icon-size, 16px);
288 height: var(--ctc-icon-size, 16px);
289 object-fit: contain;
290 }
291
292 /* Success state */
293 .ctc-copy-icon.ctc-copied {
294 color: #059669;
295 border-color: #a7f3d0;
296 background-color: #ecfdf5;
297 }
298
299 /* Tooltip */
300 .ctc-copy-icon[data-tooltip]::before {
301 content: attr(data-tooltip);
302 position: absolute;
303 top: 50%;
304 right: calc(100% + 8px);
305 transform: translateY(-50%);
306 padding: 4px 8px;
307 background: #1e293b;
308 color: white;
309 font-size: 11px;
310 font-weight: 500;
311 border-radius: 4px;
312 white-space: nowrap;
313 opacity: 0;
314 visibility: hidden;
315 transition: opacity 0.2s ease, visibility 0.2s ease;
316 pointer-events: none;
317 }
318
319 .ctc-copy-icon:hover[data-tooltip]::before,
320 .ctc-copy-icon:focus[data-tooltip]::before {
321 opacity: 1;
322 visibility: visible;
323 }
324 ';
325 }
326
327 /**
328 * Get stylesheet CSS for Global Injector (frontend).
329 *
330 * Used when outputting inline CSS for Global Injector rules. Uses selector
331 * .ctc-copy-btn--icon and CSS variables (same as build_inline_styles mapping for Global Injector).
332 * This is the Global Injector counterpart to get_base_css() (which targets .ctc-copy-icon for shortcode/block).
333 *
334 * @return string Unminified CSS.
335 */
336 public static function get_global_injector_css() {
337 return '
338 .ctc-copy-btn--icon {
339 position: absolute;
340 z-index: 10;
341 padding: var(--ctc-padding, 8px);
342 background: var(--ctc-bg, transparent);
343 color: var(--ctc-icon-color, #6b7280);
344 border: var(--ctc-icon-stroke, 1px) solid var(--ctc-border-color, #e5e7eb);
345 border-radius: var(--ctc-border-radius, 6px);
346 }
347 .ctc-copy-btn--icon:hover {
348 color: var(--ctc-icon-hover-color, #4f46e5);
349 border-color: var(--ctc-icon-hover-color, #4f46e5);
350 }
351 ';
352 }
353
354 /**
355 * Get data to localize for JavaScript.
356 *
357 * This includes everything JS needs to render the icon preview.
358 *
359 * @return array Data for wp_localize_script.
360 */
361 public static function get_localize_data() {
362 return [
363 'defaultConfig' => self::get_default_config(),
364 'icons' => self::get_icons(),
365 'successIcon' => self::get_success_icon(),
366 'baseCSS' => self::get_base_css(),
367 ];
368 }
369 }
370