array( 'type' => 'select', 'default' => 'bottom-right', 'label' => 'Position', 'options' => array( 'bottom-right', 'bottom-left', 'top-right', 'top-left' ) ), 'theme' => array( 'type' => 'select', 'default' => 'auto', 'label' => 'Theme', 'options' => array( 'auto', 'light', 'dark' ) ), 'icon' => array( 'type' => 'select', 'default' => 'accessibility', 'label' => 'Icon', 'options' => array( 'accessibility', 'eye', 'person' ) ), 'language' => array( 'type' => 'select', 'default' => 'auto', 'label' => 'Language', 'options' => array( 'auto', 'de', 'en', 'es' ) ), 'title' => array( 'type' => 'text', 'default' => '', 'label' => 'Panel title', 'max' => 80 ), 'subtitle' => array( 'type' => 'text', 'default' => '', 'label' => 'Panel subtitle', 'max' => 160 ), 'launcherStyle' => array( 'type' => 'select', 'default' => 'label', 'label' => 'Launcher style', 'options' => array( 'icon', 'label' ) ), 'launcherLabel' => array( 'type' => 'text', 'default' => '', 'label' => 'Launcher label', 'max' => 40 ), 'useCustomColors' => array( 'type' => 'boolean', 'default' => false, 'label' => 'Use the custom colors below instead of theme colors' ), 'primaryColor' => array( 'type' => 'color', 'default' => '#0f766e', 'label' => 'Primary color' ), 'backgroundColor' => array( 'type' => 'color', 'default' => '#ffffff', 'label' => 'Panel background' ), 'textColor' => array( 'type' => 'color', 'default' => '#1f2937', 'label' => 'Text color' ), 'surfaceColor' => array( 'type' => 'color', 'default' => '#f5f8f9', 'label' => 'Control surface' ), 'borderColor' => array( 'type' => 'color', 'default' => '#64748b', 'label' => 'Border color' ), 'buttonTextColor' => array( 'type' => 'color', 'default' => '#ffffff', 'label' => 'Button text and icon' ), 'fontFamily' => array( 'type' => 'select', 'default' => 'system', 'label' => 'Font family', 'options' => array( 'system', 'inherit', 'arial', 'verdana', 'georgia', 'mono' ) ), 'fontSize' => array( 'type' => 'number', 'default' => 14, 'label' => 'Base font size (px)', 'min' => 14, 'max' => 20 ), 'panelWidth' => array( 'type' => 'number', 'default' => 404, 'label' => 'Panel width (px)', 'min' => 300, 'max' => 640 ), 'borderRadius' => array( 'type' => 'number', 'default' => 24, 'label' => 'Panel corner radius (px)', 'min' => 0, 'max' => 32 ), 'controlRadius' => array( 'type' => 'number', 'default' => 9, 'label' => 'Control corner radius (px)', 'min' => 0, 'max' => 24 ), 'buttonSize' => array( 'type' => 'number', 'default' => 52, 'label' => 'Launcher size (px)', 'min' => 44, 'max' => 80 ), 'buttonRadius' => array( 'type' => 'number', 'default' => 50, 'label' => 'Launcher corner radius (%)', 'min' => 0, 'max' => 50 ), 'offsetX' => array( 'type' => 'number', 'default' => 24, 'label' => 'Desktop horizontal offset (px)', 'min' => 8, 'max' => 96 ), 'offsetY' => array( 'type' => 'number', 'default' => 24, 'label' => 'Desktop vertical offset (px)', 'min' => 8, 'max' => 160 ), 'mobileOffsetX' => array( 'type' => 'number', 'default' => 12, 'label' => 'Mobile horizontal offset (px)', 'min' => 8, 'max' => 32 ), 'mobileOffsetY' => array( 'type' => 'number', 'default' => 16, 'label' => 'Mobile vertical offset (px)', 'min' => 8, 'max' => 120 ), 'shadow' => array( 'type' => 'select', 'default' => 'soft', 'label' => 'Shadow', 'options' => array( 'none', 'soft', 'strong' ) ), 'density' => array( 'type' => 'select', 'default' => 'comfortable', 'label' => 'Control spacing', 'options' => array( 'compact', 'comfortable' ) ), ); } public static function defaults() { return array_map( function ( $field ) { return $field['default']; }, self::schema() ); } public static function presets() { $base = self::defaults(); return array( 'classic' => $base, 'dark' => array_merge( $base, array( 'theme' => 'dark', 'useCustomColors' => false, 'primaryColor' => '#5eead4', 'backgroundColor' => '#0f172a', 'textColor' => '#f8fafc', 'surfaceColor' => '#1e293b', 'borderColor' => '#94a3b8', 'buttonTextColor' => '#0f172a', 'borderRadius' => 20, 'controlRadius' => 12, 'shadow' => 'strong' ) ), 'minimal' => array_merge( $base, array( 'theme' => 'light', 'useCustomColors' => true, 'primaryColor' => '#1f2937', 'backgroundColor' => '#ffffff', 'textColor' => '#111827', 'surfaceColor' => '#f3f4f6', 'borderColor' => '#6b7280', 'buttonTextColor' => '#ffffff', 'borderRadius' => 0, 'controlRadius' => 0, 'buttonRadius' => 8, 'shadow' => 'none', 'density' => 'compact' ) ), 'warm' => array_merge( $base, array( 'theme' => 'light', 'useCustomColors' => true, 'primaryColor' => '#92400e', 'backgroundColor' => '#fffbeb', 'textColor' => '#451a03', 'surfaceColor' => '#fef3c7', 'borderColor' => '#92400e', 'buttonTextColor' => '#ffffff', 'fontFamily' => 'georgia', 'borderRadius' => 24, 'controlRadius' => 14, 'shadow' => 'soft' ) ), 'bold' => array_merge( $base, array( 'theme' => 'light', 'useCustomColors' => true, 'primaryColor' => '#6d28d9', 'backgroundColor' => '#faf5ff', 'textColor' => '#2e1065', 'surfaceColor' => '#f3e8ff', 'borderColor' => '#7e22ce', 'buttonTextColor' => '#ffffff', 'borderRadius' => 24, 'controlRadius' => 12, 'buttonRadius' => 50, 'launcherStyle' => 'label', 'shadow' => 'strong' ) ), ); } /** English names of the select values. Connectors translate them like every other text (see sourceStrings()). */ public static function choiceLabels() { return array( 'position' => array( 'bottom-right' => 'Bottom right', 'bottom-left' => 'Bottom left', 'top-right' => 'Top right', 'top-left' => 'Top left' ), 'theme' => array( 'auto' => 'Automatic (visitor system setting)', 'light' => 'Light', 'dark' => 'Dark' ), 'icon' => array( 'accessibility' => 'Figure', 'eye' => 'Eye', 'person' => 'Person' ), 'language' => array( 'auto' => 'Automatic (page language)', 'de' => 'German', 'en' => 'English', 'es' => 'Spanish' ), 'launcherStyle' => array( 'icon' => 'Icon only', 'label' => 'Icon with text' ), 'fontFamily' => array( 'system' => 'System font', 'inherit' => 'Website font', 'arial' => 'Arial / Helvetica', 'verdana' => 'Verdana / Geneva', 'georgia' => 'Georgia / Times', 'mono' => 'Monospace' ), 'shadow' => array( 'none' => 'No shadow', 'soft' => 'Subtle', 'strong' => 'Strong' ), 'density' => array( 'compact' => 'Compact', 'comfortable' => 'Spacious' ), ); } /** English preset names in menu order. */ public static function presetLabels() { return array( 'classic' => 'Classic', 'dark' => 'Dark', 'minimal' => 'Minimal', 'warm' => 'Warm', 'bold' => 'Bold' ); } /** * Every English text this file shows. The file itself never calls gettext: both connectors bundle it, and WordPress.org * only accepts a literal text domain in translation calls. Each connector therefore passes its own map * "English text => translation" (includes/admin-strings.php) to renderFields() and validate(); missing entries stay English. */ public static function sourceStrings() { $strings = array( 'Local widget appearance', 'These values apply only in local design mode. Empty titles and labels use the widget language defaults. All personal reading controls remain available to visitors. Check your color contrast and keyboard focus in the preview.', 'Start from a preset', 'Apply preset to form', 'Applying a preset replaces the appearance fields below. Save changes to publish them.', 'Invalid appearance settings. Previous values have been kept.', 'Invalid value for %s. The previous value has been kept.', ); foreach ( self::schema() as $field ) { $strings[] = $field['label']; } foreach ( self::choiceLabels() as $choices ) { $strings = array_merge( $strings, array_values( $choices ) ); } return array_values( array_unique( array_merge( $strings, array_values( self::presetLabels() ) ) ) ); } private static function text( $strings, $english ) { return is_array( $strings ) && isset( $strings[ $english ] ) && is_string( $strings[ $english ] ) && '' !== $strings[ $english ] ? $strings[ $english ] : $english; } /** * Revalidate at read time; retain safe previous values when submitted input is invalid. * `$text_domain` is kept for callers of earlier releases and unused. `$strings` translates the error messages. */ public static function validate( $input, $previous = null, $report = false, $error_group = 'accessonaut', $text_domain = 'accessonaut', $strings = array() ) { unset( $text_domain ); $defaults = self::defaults(); $result = is_array( $previous ) ? array_intersect_key( $previous, $defaults ) + $defaults : $defaults; if ( ! is_array( $input ) || count( $input ) > 64 ) { if ( $report ) { add_settings_error( $error_group, 'invalid_display', self::text( $strings, 'Invalid appearance settings. Previous values have been kept.' ) ); } return $result; } $invalid = self::text( $strings, 'Invalid value for %s. The previous value has been kept.' ); // A translation with a different number of placeholders must never break saving. if ( 1 !== preg_match_all( '/%(?:1\$)?s/', $invalid ) || 1 !== substr_count( str_replace( '%%', '', $invalid ), '%' ) ) { $invalid = 'Invalid value for %s. The previous value has been kept.'; } foreach ( self::schema() as $name => $field ) { if ( ! array_key_exists( $name, $input ) ) { continue; } $value = $input[ $name ]; $valid = false; switch ( $field['type'] ) { case 'select': $valid = is_string( $value ) && in_array( $value, $field['options'], true ); break; case 'color': $valid = is_string( $value ) && 1 === preg_match( '/\A#[a-fA-F0-9]{6}\z/', $value ); break; case 'boolean': $valid = in_array( $value, array( true, false, '1', '0', 1, 0 ), true ); $value = in_array( $value, array( true, '1', 1 ), true ); break; case 'number': $valid = ( is_int( $value ) || ( is_string( $value ) && 1 === preg_match( '/\A(?:0|[1-9][0-9]*)\z/', $value ) ) ) && $value >= $field['min'] && $value <= $field['max']; $value = $valid ? (int) $value : $value; break; case 'text': if ( is_string( $value ) ) { $value = trim( $value ); $length = preg_match_all( '/./us', $value, $unused ); $valid = false !== $length && $length <= $field['max'] && ! preg_match( '/[<>\x00-\x1f\x7f]/', $value ); } break; } if ( $valid ) { $result[ $name ] = $value; } elseif ( $report ) { add_settings_error( $error_group, 'invalid_display_' . $name, sprintf( $invalid, self::text( $strings, $field['label'] ) ) ); } } return $result; } /** `$text_domain` is kept for callers of earlier releases and unused. `$strings` translates every visible text. */ public static function renderFields( $display, $option_name = 'accessonaut_settings', $error_group = 'accessonaut', $text_domain = 'accessonaut', $strings = array() ) { unset( $text_domain ); $choices = self::choiceLabels(); ?>

$field ) : $id = 'accessonaut-display-' . $name; $input_name = $option_name . '[display_config][' . $name . ']'; ?>
/> min="" max="" step="1"maxlength="" />