PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 1.0.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v1.0.0
2.7.0 2.6.0 2.5.0 2.4.0 2.3.0 2.2.0 2.1.1 2.1.0 2.0.2 2.0.1 2.0.0 1.32.0 1.31.0 1.30.0 1.29.0 1.28.0 1.27.0 1.26.0 1.25.0 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.10.0 All 48 releases
thinkrank / src / admin / components / content-brief / KeywordInput.js

KeywordInput.js in ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO 1.0.0, at src/admin/components/content-brief/KeywordInput.js

107 lines 3.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Keyword Input Component
3 *
4 * Reusable component for managing multiple keyword/URL inputs
5 *
6 * @package ThinkRank
7 * @since 1.0.0
8 */
9
10 import { useState } from '@wordpress/element';
11 import { TextControl } from '@wordpress/components';
12 import { __ } from '@wordpress/i18n';
13 import { plus, close } from '@wordpress/icons';
14
15 const KeywordInput = ({
16 keywords = [''],
17 onChange,
18 label = __('Keywords', 'thinkrank'),
19 help = '',
20 placeholder = __('Enter keyword...', 'thinkrank'),
21 maxItems = 10
22 }) => {
23 /**
24 * Handle keyword change
25 */
26 const handleKeywordChange = (index, value) => {
27 const newKeywords = [...keywords];
28 newKeywords[index] = value;
29 onChange(newKeywords);
30 };
31
32 /**
33 * Add new keyword input
34 */
35 const addKeyword = () => {
36 if (keywords.length < maxItems) {
37 onChange([...keywords, '']);
38 }
39 };
40
41 /**
42 * Remove keyword input
43 */
44 const removeKeyword = (index) => {
45 if (keywords.length > 1) {
46 const newKeywords = keywords.filter((_, i) => i !== index);
47 onChange(newKeywords);
48 }
49 };
50
51 return (
52 <div className="thinkrank-mb-4">
53 <label className="thinkrank-block thinkrank-text-sm thinkrank-font-semibold thinkrank-text-primary thinkrank-mb-2">
54 {label}
55 </label>
56
57 {help && (
58 <p className="thinkrank-text-sm thinkrank-text-secondary thinkrank-mb-3">
59 {help}
60 </p>
61 )}
62
63 <div className="thinkrank-space-y-3">
64 {keywords.map((keyword, index) => (
65 <div key={index} className="thinkrank-flex thinkrank-gap-2">
66 <div className="thinkrank-flex-1">
67 <TextControl
68 value={keyword}
69 onChange={(value) => handleKeywordChange(index, value)}
70 placeholder={placeholder}
71 __next40pxDefaultSize={true}
72 __nextHasNoMarginBottom={true}
73 />
74 </div>
75
76 {keywords.length > 1 && (
77 <button
78 className="thinkrank-btn thinkrank-btn--danger thinkrank-btn--sm thinkrank-w-10 thinkrank-h-10 thinkrank-flex-center"
79 onClick={() => removeKeyword(index)}
80 title={__('Remove', 'thinkrank')}
81 >
82 <svg className="thinkrank-w-4 thinkrank-h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
83 <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
84 </svg>
85 </button>
86 )}
87 </div>
88 ))}
89 </div>
90
91 {keywords.length < maxItems && (
92 <button
93 className="thinkrank-btn thinkrank-btn--secondary thinkrank-btn--sm thinkrank-flex thinkrank-items-center thinkrank-gap-2 thinkrank-mt-2"
94 onClick={addKeyword}
95 >
96 <svg className="thinkrank-w-4 thinkrank-h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
97 <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
98 </svg>
99 {label.includes('URL') ? __('Add URL', 'thinkrank') : __('Add Keyword', 'thinkrank')}
100 </button>
101 )}
102 </div>
103 );
104 };
105
106 export default KeywordInput;
107