PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.7
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.7
2.0.13 2.0.12 2.0.11 2.0.10 2.0.9 trunk 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8
blockenberg / blocks / password-strength-meter / index.js

index.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.7, at blocks/password-strength-meter/index.js

186 lines 13.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 ( function () {
2 var el = wp.element.createElement;
3 var useState = wp.element.useState;
4 var Fragment = wp.element.Fragment;
5 var registerBlockType = wp.blocks.registerBlockType;
6 var __ = wp.i18n.__;
7 var InspectorControls = wp.blockEditor.InspectorControls;
8 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
9 var useBlockProps = wp.blockEditor.useBlockProps;
10 var PanelBody = wp.components.PanelBody;
11 var RangeControl = wp.components.RangeControl;
12 var TextControl = wp.components.TextControl;
13 var ToggleControl = wp.components.ToggleControl;
14 var SelectControl = wp.components.SelectControl;
15
16 var _tc, _tv;
17 function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
18 function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
19
20 function scorePassword(pw, minLen) {
21 if (!pw) return 0;
22 var score = 0;
23 if (pw.length >= minLen) score++;
24 if (/[A-Z]/.test(pw)) score++;
25 if (/[a-z]/.test(pw)) score++;
26 if (/[0-9]/.test(pw)) score++;
27 if (/[^a-zA-Z0-9]/.test(pw)) score++;
28 return score; // 0-5
29 }
30
31 function strengthInfo(score, a) {
32 if (score <= 1) return { level: 1, label: a.labelWeak || 'Weak', color: a.colorWeak || '#ef4444' };
33 if (score <= 2) return { level: 2, label: a.labelFair || 'Fair', color: a.colorFair || '#f59e0b' };
34 if (score <= 3) return { level: 3, label: a.labelGood || 'Good', color: a.colorGood || '#3b82f6' };
35 return { level: 4, label: a.labelStrong || 'Strong', color: a.colorStrong || '#10b981' };
36 }
37
38 function PasswordStrengthPreview(props) {
39 var a = props.attributes;
40 var _pw = useState(''); var pw = _pw[0]; var setPw = _pw[1];
41 var _vis = useState(false); var vis = _vis[0]; var setVis = _vis[1];
42
43 var score = scorePassword(pw, a.minLength || 8);
44 var info = pw.length > 0 ? strengthInfo(score, a) : null;
45 var reqMetColor = a.reqMetColor || '#10b981';
46 var reqUnmetColor = a.reqUnmetColor || '#9ca3af';
47
48 var reqs = [
49 { key:'showLengthReq', met: pw.length >= (a.minLength||8), label: 'At least ' + (a.minLength||8) + ' characters' },
50 { key:'showUppercaseReq', met: /[A-Z]/.test(pw), label: 'Uppercase letter (A-Z)' },
51 { key:'showLowercaseReq', met: /[a-z]/.test(pw), label: 'Lowercase letter (a-z)' },
52 { key:'showNumberReq', met: /[0-9]/.test(pw), label: 'Number (0-9)' },
53 { key:'showSymbolReq', met: /[^a-zA-Z0-9]/.test(pw), label: 'Special character (!@#…)' }
54 ].filter(function(r){ return a[r.key]; });
55
56 var segments = [1,2,3,4].map(function(i){
57 var active = info && i <= info.level;
58 return el('div', { key:i, style:{flex:1,height:'6px',borderRadius:'3px',background:active?info.color:(a.barBg||'#e5e7eb'),transition:'background .3s'} });
59 });
60
61 return el('div', { style:{paddingTop:a.paddingTop+'px',paddingBottom:a.paddingBottom+'px',background:a.sectionBg||undefined}},
62 el('div', { style:{background:a.cardBg,borderRadius:(a.cardRadius||16)+'px',padding:'36px 32px',maxWidth:(a.maxWidth||480)+'px',margin:'0 auto',boxShadow:'0 4px 24px rgba(0,0,0,0.09)'}},
63
64 (a.showTitle||a.showSubtitle) && el('div', { style:{marginBottom:'22px'}},
65 a.showTitle && el('div', { style:{color:a.titleColor,marginBottom:'6px'}, className:'bkbg-psm-title'}, a.title),
66 a.showSubtitle && el('div', { style:{color:a.subtitleColor,opacity:.75}, className:'bkbg-psm-subtitle'}, a.subtitle)
67 ),
68
69 // Input + toggle
70 el('div', { style:{position:'relative',marginBottom:'14px'}},
71 el('input', {
72 type: vis ? 'text' : 'password',
73 value: pw,
74 placeholder: a.placeholder,
75 onChange: function(e){ setPw(e.target.value); },
76 style:{width:'100%',padding:'14px '+(a.showToggleVisibility?'48px':'16px')+' 14px 16px',fontSize:'16px',fontFamily:'inherit',borderRadius:(a.inputRadius||10)+'px',border:'1.5px solid '+(a.inputBorder||'#e5e7eb'),background:a.inputBg||'#f9fafb',outline:'none',boxSizing:'border-box'}
77 }),
78 a.showToggleVisibility && el('button', {
79 onClick: function(){ setVis(!vis); },
80 style:{position:'absolute',right:'12px',top:'50%',transform:'translateY(-50%)',background:'none',border:'none',cursor:'pointer',fontSize:'18px',padding:'4px',color:'#6b7280'}
81 }, vis ? '🙈' : '👁️')
82 ),
83
84 // Strength bar
85 el('div', { style:{display:'flex',gap:'5px',marginBottom:'8px'}}, segments),
86
87 // Strength label
88 el('div', { style:{height:'22px',marginBottom:'18px',display:'flex',alignItems:'center',justifyContent:'space-between'}},
89 el('span', { style:{fontSize:'13px',color:a.labelColor||'#374151'}}, info ? 'Password strength:' : ''),
90 info && el('span', { style:{fontSize:'13px',fontWeight:700,color:info.color} }, info.label)
91 ),
92
93 // Requirements checklist
94 reqs.length > 0 && el('div', { style:{display:'flex',flexDirection:'column',gap:'8px'}},
95 reqs.map(function(r) {
96 return el('div', { key:r.key, style:{display:'flex',alignItems:'center',gap:'10px',fontSize:'13px',color:r.met?reqMetColor:reqUnmetColor,fontWeight:r.met?600:400,transition:'color .2s'}},
97 el('span', { style:{fontSize:'15px',lineHeight:1}}, r.met ? '' : ''),
98 el('span', null, r.label)
99 );
100 })
101 )
102 )
103 );
104 }
105
106 registerBlockType('blockenberg/password-strength-meter', {
107 edit: function(props) {
108 var a = props.attributes; var set = props.setAttributes;
109 var blockProps = useBlockProps((function(){
110 var s = {};
111 var tv = getTypoCssVars();
112 if (tv) {
113 Object.assign(s, tv(a.titleTypo || {}, '--bkbg-psm-title'));
114 Object.assign(s, tv(a.subtitleTypo || {}, '--bkbg-psm-subtitle'));
115 }
116 return { style: s };
117 })());
118 var colorSettings = [
119 { value: a.accentColor, onChange: function(v){ set({accentColor:v}); }, label: 'Accent Color' },
120 { value: a.cardBg, onChange: function(v){ set({cardBg:v}); }, label: 'Card Background' },
121 { value: a.inputBg, onChange: function(v){ set({inputBg:v}); }, label: 'Input Background' },
122 { value: a.inputBorder, onChange: function(v){ set({inputBorder:v}); }, label: 'Input Border' },
123 { value: a.barBg, onChange: function(v){ set({barBg:v}); }, label: 'Bar Track Color' },
124 { value: a.colorWeak, onChange: function(v){ set({colorWeak:v}); }, label: 'Weak Color' },
125 { value: a.colorFair, onChange: function(v){ set({colorFair:v}); }, label: 'Fair Color' },
126 { value: a.colorGood, onChange: function(v){ set({colorGood:v}); }, label: 'Good Color' },
127 { value: a.colorStrong, onChange: function(v){ set({colorStrong:v}); }, label: 'Strong Color' },
128 { value: a.reqMetColor, onChange: function(v){ set({reqMetColor:v}); }, label: 'Requirement Met' },
129 { value: a.reqUnmetColor, onChange: function(v){ set({reqUnmetColor:v}); }, label: 'Requirement Unmet' },
130 { value: a.labelColor, onChange: function(v){ set({labelColor:v}); }, label: 'Label Color' },
131 { value: a.titleColor, onChange: function(v){ set({titleColor:v}); }, label: 'Title Color' },
132 { value: a.subtitleColor, onChange: function(v){ set({subtitleColor:v}); }, label: 'Subtitle Color' },
133 { value: a.sectionBg, onChange: function(v){ set({sectionBg:v}); }, label: 'Section Background' }
134 ];
135 return el(Fragment, null,
136 el(InspectorControls, null,
137 el(PanelBody, { title: 'Header', initialOpen: false },
138 el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Show Title', checked: a.showTitle, onChange: function(v){ set({showTitle:v}); } }),
139 el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Show Subtitle', checked: a.showSubtitle, onChange: function(v){ set({showSubtitle:v}); } }),
140 el(TextControl, { label: 'Title', value: a.title, onChange: function(v){ set({title:v}); } }),
141 el(TextControl, { label: 'Subtitle', value: a.subtitle, onChange: function(v){ set({subtitle:v}); } }),
142 el(TextControl, { label: 'Placeholder', value: a.placeholder, onChange: function(v){ set({placeholder:v}); } })
143 ),
144 el(PanelBody, { title: 'Strength Settings', initialOpen: true },
145 el(RangeControl, { label: 'Minimum Length Requirement', value: a.minLength, min: 4, max: 32, step: 1, onChange: function(v){ set({minLength:v}); } }),
146 el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Show Toggle Visibility', checked: a.showToggleVisibility, onChange: function(v){ set({showToggleVisibility:v}); } })
147 ),
148 el(PanelBody, { title: 'Requirements Checklist', initialOpen: false },
149 el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Minimum Length', checked: a.showLengthReq, onChange: function(v){ set({showLengthReq:v}); } }),
150 el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Uppercase Letter', checked: a.showUppercaseReq, onChange: function(v){ set({showUppercaseReq:v}); } }),
151 el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Lowercase Letter', checked: a.showLowercaseReq, onChange: function(v){ set({showLowercaseReq:v}); } }),
152 el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Number', checked: a.showNumberReq, onChange: function(v){ set({showNumberReq:v}); } }),
153 el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Special Character', checked: a.showSymbolReq, onChange: function(v){ set({showSymbolReq:v}); } })
154 ),
155 el(PanelBody, { title: 'Strength Labels', initialOpen: false },
156 el(TextControl, { label: 'Weak Label', value: a.labelWeak, onChange: function(v){ set({labelWeak:v}); } }),
157 el(TextControl, { label: 'Fair Label', value: a.labelFair, onChange: function(v){ set({labelFair:v}); } }),
158 el(TextControl, { label: 'Good Label', value: a.labelGood, onChange: function(v){ set({labelGood:v}); } }),
159 el(TextControl, { label: 'Strong Label', value: a.labelStrong, onChange: function(v){ set({labelStrong:v}); } })
160 ),
161
162 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
163 (function(){ var C = getTypoControl(); return C ? [
164 el(C, { key: 'title', label: __('Title', 'blockenberg'), value: a.titleTypo || {}, onChange: function(v){ set({titleTypo: v}); } }),
165 el(C, { key: 'subtitle', label: __('Subtitle', 'blockenberg'), value: a.subtitleTypo || {}, onChange: function(v){ set({subtitleTypo: v}); } })
166 ] : null; })()
167 ),
168 el(PanelColorSettings, { title: 'Colors', initialOpen: false, colorSettings: colorSettings }),
169 el(PanelBody, { title: 'Sizing & Layout', initialOpen: false },
170 el(RangeControl, { label: 'Card Border Radius', value: a.cardRadius, min: 0, max: 40, step: 1, onChange: function(v){ set({cardRadius:v}); } }),
171 el(RangeControl, { label: 'Input Border Radius', value: a.inputRadius, min: 0, max: 24, step: 1, onChange: function(v){ set({inputRadius:v}); } }),
172 el(RangeControl, { label: 'Max Width (px)', value: a.maxWidth, min: 300,max: 800, step: 10, onChange: function(v){ set({maxWidth:v}); } }),
173 el(RangeControl, { label: 'Padding Top (px)', value: a.paddingTop, min: 0, max: 160, step: 4, onChange: function(v){ set({paddingTop:v}); } }),
174 el(RangeControl, { label: 'Padding Bottom (px)', value: a.paddingBottom, min: 0, max: 160, step: 4, onChange: function(v){ set({paddingBottom:v}); } })
175 )
176 ),
177 el('div', blockProps, el(PasswordStrengthPreview, { attributes: a, setAttributes: set }))
178 );
179 },
180 save: function(props) {
181 var a = props.attributes;
182 return el('div', wp.blockEditor.useBlockProps.save(), el('div', { className: 'bkbg-psm-app', 'data-opts': JSON.stringify(a) }));
183 }
184 });
185 }() );
186