# blockenberg/2.0.7/blocks/content-score/index.js

Blockenberg — 600+ Advanced Gutenberg Blocks &amp; AI Agent for WordPress Block Editor, version 2.0.7. 192 lines.

- Page: https://pluginprobe.com/plugins/blockenberg/2.0.7/code/blocks/content-score/index.js
- Raw: https://pluginprobe.com/plugins/blockenberg/2.0.7/raw/blocks/content-score/index.js
- Modified: 2026-03-06T12:32:40+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/blockenberg/2.0.7/code/blocks/content-score/index.js#L10-L20`.

```javascript
( function () {
    const el = window.wp.element.createElement;
    const { registerBlockType } = window.wp.blocks;
    const { InspectorControls, useBlockProps, PanelColorSettings } = window.wp.blockEditor;
    const { PanelBody, RangeControl, ToggleControl, TextControl, SelectControl, Button } = window.wp.components;
    const { __ } = window.wp.i18n;

    var _bkbgCSgetTC, _bkbgCSgetTV;
    function getTC() { return _bkbgCSgetTC || (_bkbgCSgetTC = window.bkbgTypographyControl); }
    function getTV() { return _bkbgCSgetTV || (_bkbgCSgetTV = window.bkbgTypoCssVars); }
    function tv(obj, prefix) { var fn = getTV(); return fn ? fn(obj, prefix) : {}; }

    // ── Helpers ───────────────────────────────────────────────────────────────
    function overallScore( criteria ) {
        if ( ! criteria || ! criteria.length ) return 0;
        const total = criteria.reduce( ( s, c ) => s + ( ( c.score || 0 ) / ( c.max || 100 ) ) * 100, 0 );
        return Math.round( total / criteria.length );
    }

    function scoreGrade( n ) {
        if ( n >= 90 ) return 'A';
        if ( n >= 80 ) return 'B';
        if ( n >= 70 ) return 'C';
        if ( n >= 60 ) return 'D';
        return 'F';
    }

    function scoreColor( n, a ) {
        if ( n >= 75 ) return a.passColor;
        if ( n >= 50 ) return a.warnColor;
        return a.failColor;
    }

    // ── Circular gauge ────────────────────────────────────────────────────────
    function renderGauge( a, score ) {
        const S   = a.gaugeSize;
        const SW  = a.strokeWidth;
        const r   = ( S - SW * 2 ) / 2;
        const cx  = S / 2;
        const cy  = S / 2;
        const circ = 2 * Math.PI * r;
        // Arc from -90° (top), goes clockwise
        const offset = circ - ( score / 100 ) * circ;
        const clr = scoreColor( score, a );
        const grade = a.showGrade ? scoreGrade( score ) : '';

        return el( 'div', { className: 'bkbg-cs-gauge', style: { display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8, flexShrink: 0 } },
            a.label && el( 'div', { className: 'bkbg-cs-gauge-label', style: { color: a.mutedColor, textAlign: 'center' } }, a.label ),
            el( 'svg', { width: S, height: S, viewBox: `0 0 ${ S } ${ S }`, style: { display: 'block' } },
                // Track
                el( 'circle', { cx, cy, r, fill: 'none', stroke: a.trackColor, strokeWidth: SW } ),
                // Progress arc
                el( 'circle', {
                    cx, cy, r,
                    fill: 'none',
                    stroke: clr,
                    strokeWidth: SW,
                    strokeDasharray: circ,
                    strokeDashoffset: offset,
                    strokeLinecap: 'round',
                    transform: `rotate(-90 ${ cx } ${ cy })`,
                    style: { transition: 'stroke-dashoffset 0.5s' }
                } ),
                // Score number
                el( 'text', { x: cx, y: cy - ( grade ? 10 : 0 ), textAnchor: 'middle', dominantBaseline: 'middle', fontSize: S * 0.22, fontWeight: 800, fill: clr }, score ),
                // Grade
                grade && el( 'text', { x: cx, y: cy + S * 0.14, textAnchor: 'middle', dominantBaseline: 'middle', fontSize: S * 0.12, fontWeight: 700, fill: a.mutedColor }, `Grade ${ grade }` ),
            ),
        );
    }

    // ── Criteria list ─────────────────────────────────────────────────────────
    function renderCriteria( a ) {
        const criteria = a.criteria || [];
        return el( 'div', { className: 'bkbg-cs-criteria', style: { display: 'flex', flexDirection: 'column', gap: 10, flex: 1 } },
            criteria.map( ( c, ci ) => {
                const pct = Math.min( 100, Math.round( ( ( c.score || 0 ) / ( c.max || 100 ) ) * 100 ) );
                const clr = scoreColor( pct, a );
                return el( 'div', { key: ci, className: 'bkbg-cs-criterion' },
                    el( 'div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 4 } },
                        el( 'span', { className: 'bkbg-cs-crit-label', style: { color: a.textColor } }, c.label ),
                        el( 'span', { className: 'bkbg-cs-crit-score', style: { color: clr, minWidth: 36, textAlign: 'right' } }, `${ c.score }/${ c.max }` ),
                    ),
                    el( 'div', { style: { height: 6, background: a.trackColor, borderRadius: 99, overflow: 'hidden', marginBottom: c.note ? 3 : 0 } },
                        el( 'div', { style: { height: '100%', width: pct + '%', background: clr, borderRadius: 99 } } )
                    ),
                    c.note && el( 'span', { className: 'bkbg-cs-crit-note', style: { color: a.mutedColor } }, c.note ),
                );
            } )
        );
    }

    // ── Combined render ───────────────────────────────────────────────────────
    function renderScore( a ) {
        const score = overallScore( a.criteria );
        const isStack = a.layout !== 'side';
        const containerStyle = {
            display: 'flex',
            flexDirection: isStack ? 'column' : 'row',
            gap: 28,
            alignItems: isStack ? 'center' : 'flex-start',
        };
        return el( 'div', { className: 'bkbg-cs-inner', style: containerStyle },
            a.showGauge && renderGauge( a, score ),
            a.showCriteria && renderCriteria( a ),
        );
    }

    function updCriterion( setAttributes, criteria, ci, field, val ) {
        setAttributes( { criteria: criteria.map( ( c, i ) => i === ci ? { ...c, [field]: val } : c ) } );
    }

    // ── Block ─────────────────────────────────────────────────────────────────
    registerBlockType( 'blockenberg/content-score', {
        edit: function ( props ) {
            const { attributes: a, setAttributes } = props;
            const blockProps = useBlockProps( { className: 'bkbg-cs-wrap', style: Object.assign({ background: a.bgColor, padding: '20px', borderRadius: a.borderRadius + 'px', boxSizing: 'border-box', '--bkcs-label-sz': (a.labelSize || 13) + 'px' }, tv(a.typoTitle, '--bkcs-title-'), tv(a.typoBody, '--bkcs-body-')) } );

            return el( 'div', blockProps,
                el( InspectorControls, {},

                    el( PanelBody, { title: __( 'Settings', 'blockenberg' ), initialOpen: true },
                        el( TextControl,   { label: __( 'Title', 'blockenberg' ),       value: a.title, onChange: v => setAttributes( { title: v } ) } ),
                        el( ToggleControl, { label: __( 'Show Title', 'blockenberg' ),  checked: a.showTitle,   onChange: v => setAttributes( { showTitle:   v } ) } ),
                        el( TextControl,   { label: __( 'Gauge Label', 'blockenberg' ), value: a.label, onChange: v => setAttributes( { label: v } ) } ),
                        el( ToggleControl, { label: __( 'Show Gauge', 'blockenberg' ),    checked: a.showGauge,    onChange: v => setAttributes( { showGauge:    v } ) } ),
                        el( ToggleControl, { label: __( 'Show Grade', 'blockenberg' ),    checked: a.showGrade,    onChange: v => setAttributes( { showGrade:    v } ) } ),
                        el( ToggleControl, { label: __( 'Show Criteria', 'blockenberg' ), checked: a.showCriteria, onChange: v => setAttributes( { showCriteria: v } ) } ),
                        el( SelectControl, {
                            label: __( 'Layout', 'blockenberg' ),
                            value: a.layout,
                            options: [ { label: __( 'Side by Side', 'blockenberg' ), value: 'side' }, { label: __( 'Stacked', 'blockenberg' ), value: 'stack' } ],
                            onChange: v => setAttributes( { layout: v } ),
                        } ),
                    ),

                    el( PanelBody, { title: __( 'Style', 'blockenberg' ), initialOpen: false },
                        el( RangeControl, { label: __( 'Gauge Size', 'blockenberg' ),  value: a.gaugeSize,   onChange: v => setAttributes( { gaugeSize:   v } ), min: 80, max: 260, step: 10 } ),
                        el( RangeControl, { label: __( 'Ring Width', 'blockenberg' ),  value: a.strokeWidth, onChange: v => setAttributes( { strokeWidth: v } ), min: 5, max: 30 } ),
                        el( RangeControl, { label: __( 'Border Radius', 'blockenberg' ),value: a.borderRadius,onChange: v => setAttributes( { borderRadius:v } ), min: 0, max: 28 } ),
                    ),

                    
                    el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
                        getTC() && el( getTC(), { label: __( 'Title', 'blockenberg' ), value: a.typoTitle, onChange: function (v) { setAttributes({ typoTitle: v }); } }),
                        getTC() && el( getTC(), { label: __( 'Body Text', 'blockenberg' ), value: a.typoBody, onChange: function (v) { setAttributes({ typoBody: v }); } }),
                        el(RangeControl, { __nextHasNoMarginBottom: true, label: __('Label Size (px)', 'blockenberg'), value: a.labelSize, min: 10, max: 24, onChange: function (v) { setAttributes({ labelSize: v }); } })
                    ),
el( PanelColorSettings, {
                        title: __( 'Colors', 'blockenberg' ), initialOpen: false,
                        colorSettings: [
                            { label: __( 'Background', 'blockenberg' ), value: a.bgColor,    onChange: v => setAttributes( { bgColor:    v || '#ffffff' } ) },
                            { label: __( 'Card BG', 'blockenberg' ),    value: a.cardBg,     onChange: v => setAttributes( { cardBg:     v || '#f9fafb' } ) },
                            { label: __( 'Title', 'blockenberg' ),      value: a.titleColor, onChange: v => setAttributes( { titleColor: v || '#111827' } ) },
                            { label: __( 'Text', 'blockenberg' ),       value: a.textColor,  onChange: v => setAttributes( { textColor:  v || '#374151' } ) },
                            { label: __( 'Muted', 'blockenberg' ),      value: a.mutedColor, onChange: v => setAttributes( { mutedColor: v || '#6b7280' } ) },
                            { label: __( 'Track', 'blockenberg' ),      value: a.trackColor, onChange: v => setAttributes( { trackColor: v || '#e5e7eb' } ) },
                            { label: __( 'Pass (≥75%)', 'blockenberg' ),value: a.passColor,  onChange: v => setAttributes( { passColor:  v || '#10b981' } ) },
                            { label: __( 'Warn (50–74%)', 'blockenberg' ),value: a.warnColor,onChange: v => setAttributes( { warnColor:  v || '#f59e0b' } ) },
                            { label: __( 'Fail (<50%)', 'blockenberg' ), value: a.failColor, onChange: v => setAttributes( { failColor:  v || '#ef4444' } ) },
                        ]
                    } ),

                    el( PanelBody, { title: __( 'Criteria', 'blockenberg' ), initialOpen: false },
                        el( Button, { variant: 'secondary', style: { marginBottom: 10 }, onClick: () => setAttributes( { criteria: [ ...( a.criteria || [] ), { label: 'New Criterion', score: 70, max: 100, note: '' } ] } ) }, __( '+ Add Criterion', 'blockenberg' ) ),
                        a.criteria.map( ( c, ci ) =>
                            el( PanelBody, { key: ci, title: `${ c.label } (${ c.score }/${ c.max })`, initialOpen: false },
                                el( TextControl,  { label: __( 'Label', 'blockenberg' ), value: c.label, onChange: v => updCriterion( setAttributes, a.criteria, ci, 'label', v ) } ),
                                el( RangeControl, { label: __( 'Score', 'blockenberg' ), value: c.score, onChange: v => updCriterion( setAttributes, a.criteria, ci, 'score', v ), min: 0, max: c.max || 100 } ),
                                el( RangeControl, { label: __( 'Max', 'blockenberg' ),   value: c.max,   onChange: v => updCriterion( setAttributes, a.criteria, ci, 'max',   v ), min: 1, max: 200 } ),
                                el( TextControl,  { label: __( 'Note', 'blockenberg' ),  value: c.note,  onChange: v => updCriterion( setAttributes, a.criteria, ci, 'note',  v ) } ),
                                el( Button, { isDestructive: true, isSmall: true, onClick: () => setAttributes( { criteria: a.criteria.filter( ( _, x ) => x !== ci ) } ) }, __( 'Remove', 'blockenberg' ) ),
                            )
                        ),
                    ),
                ),

                a.showTitle && a.title && el( 'h3', { className: 'bkbg-cs-title', style: { color: a.titleColor } }, a.title ),
                renderScore( a ),
            );
        },

        save: function ( { attributes: a } ) {
            const blockProps = useBlockProps.save( { className: 'bkbg-cs-wrap', style: Object.assign({ background: a.bgColor, padding: '20px', borderRadius: a.borderRadius + 'px', boxSizing: 'border-box', '--bkcs-label-sz': (a.labelSize || 13) + 'px' }, tv(a.typoTitle, '--bkcs-title-'), tv(a.typoBody, '--bkcs-body-')) } );
            return el( 'div', blockProps,
                a.showTitle && a.title ? el( 'h3', { className: 'bkbg-cs-title', style: { color: a.titleColor } }, a.title ) : null,
                renderScore( a ),
            );
        },
    } );
}() );

```
