= 10 || $n === round($n)) { return number_format_i18n(round($n)); } return number_format_i18n($n, 1); } /** * The header of a 2.0 page: the mark and "AIPCF", the page name, one line on what it is for, * and a status pill. * * @param array{0: string, 1: string}|null $pill [state, label]: state is '', 'ok', 'warn' or 'bad'. * @param string $side Escaped HTML beside the pill (links). */ public static function header(string $title, string $text, ?array $pill = null, string $side = ''): string { return sprintf( '

%2$s

%3$s

%4$s

%5$s%6$s
', Brand::icon(24), esc_html(Brand::NAME), esc_html($title), esc_html($text), $pill !== null ? self::pill($pill[1], $pill[0]) : '', $side ); } /** * Section tabs inside a page (Settings: Connection, Models, ...). * * @param array $links slug => [label, url] */ public static function tabs(array $links, string $current, string $label): string { $out = ''; } /** * Cards side by side (two columns on wide screens). */ public static function grid(string $cards): string { return '
' . $cards . '
'; } /** * A link back to the page a sub-page belongs to ("Features"). */ public static function back(string $label, string $url): string { return '

' . esc_html($label) . '

'; } /** * A card: a title (with an optional status pill), one line on what it does, then its body. * * @param array{id?: string, text?: string, pill?: array{0: string, 1: string}} $o */ public static function card(string $title, string $body, array $o = []): string { $id = isset($o['id']) ? ' id="' . esc_attr($o['id']) . '"' : ''; return sprintf( '

%2$s

%3$s
%4$s%5$s
', $id, esc_html($title), isset($o['pill']) ? self::pill($o['pill'][1], $o['pill'][0]) : '', isset($o['text']) && $o['text'] !== '' ? '

' . esc_html($o['text']) . '

' : '', $body ); } /** * A setting row: the label, the control, one line of help, and optionally more behind * "Learn more". * * @param array{for?: string, help?: string, more?: string, link?: array{0: string, 1: string}, class?: string, attrs?: string} $o more: escaped HTML; link: [label, url], opens in a new tab; attrs: escaped attributes. */ public static function row(string $label, string $control, array $o = []): string { $labelHtml = isset($o['for']) ? '' : '' . esc_html($label) . ''; $link = isset($o['link']) ? ' ' . self::external($o['link'][0], $o['link'][1]) : ''; $help = (isset($o['help']) && $o['help'] !== '') || $link !== '' ? '

' . esc_html($o['help'] ?? '') . $link . '

' : ''; $more = isset($o['more']) && $o['more'] !== '' ? self::more(__('Learn more', 'aipcf-ai-provider-for-cloudflare'), $o['more']) : ''; $class = isset($o['class']) && $o['class'] !== '' ? ' ' . esc_attr($o['class']) : ''; return sprintf('
%1$s
%2$s%3$s%4$s
', $labelHtml, $control, $help, $more, $class, $o['attrs'] ?? ''); } /** * Rows that most people never need, behind one "More settings" disclosure at the end of a card. */ public static function moreSettings(string $rows): string { return '
' . esc_html__('More settings', 'aipcf-ai-provider-for-cloudflare') . '' . $rows . '
'; } /** * A switch that turns a feature on or off. Only for that: options use checks(). */ public static function toggle(string $key, bool $on, string $label, string $id): string { return sprintf( '', esc_attr(self::field($key)), esc_attr($id), checked($on, true, false), esc_html($label) ); } /** * Checkboxes to choose among options, one per line, each with an optional short note. * * @param array $options value => label and note. * @param list $selected */ public static function checks(string $key, array $options, array $selected, string $legend, string $id = ''): string { $out = '
' . esc_html($legend) . ''; $first = true; foreach ($options as $value => $opt) { $out .= sprintf( '', $first && $id !== '' ? ' id="' . esc_attr($id) . '"' : '', esc_attr(self::field($key)), esc_attr((string) $value), checked(in_array((string) $value, $selected, true), true, false), esc_html($opt['label']), isset($opt['note']) && $opt['note'] !== '' ? ' ' . esc_html($opt['note']) . '' : '' ); $first = false; } return $out . '
'; } /** * A link that opens another site in a new tab, marked as such. */ public static function external(string $label, string $url): string { return sprintf( '%2$s %3$s', esc_url($url), esc_html($label), esc_html__('(opens in a new tab)', 'aipcf-ai-provider-for-cloudflare') ); } /** * One checkbox for one option ("Keep prompt text in the gateway logs"). Not for turning a * feature on or off: that is toggle(). An unticked box sends "0". */ public static function check(string $key, bool $on, string $label, string $id): string { return sprintf( '', esc_attr(self::field($key)), esc_attr($id), checked($on, true, false), esc_html($label) ); } /** * A text field. * * @param array{placeholder?: string, wide?: bool} $o */ public static function text(string $key, string $value, string $id, array $o = []): string { return sprintf( '', esc_attr($id), esc_attr(self::field($key)), esc_attr($value), !empty($o['wide']) ? 'large-text' : 'regular-text', isset($o['placeholder']) ? ' placeholder="' . esc_attr($o['placeholder']) . '"' : '' ); } /** * A secret (token, key, password). The saved value is never printed: a blank field keeps it, * and "Remove" clears it (sent as {key}_clear). */ public static function secret(string $key, bool $saved, string $id): string { $out = sprintf( '', esc_attr($id), esc_attr(self::field($key)), esc_attr($saved ? __('Saved. Leave blank to keep it.', 'aipcf-ai-provider-for-cloudflare') : '') ); if ($saved) { $out .= sprintf( '', esc_attr(self::field($key . '_clear')), esc_html__('Remove the saved value', 'aipcf-ai-provider-for-cloudflare') ); } return $out; } /** * A multi-line text field. Takes its full field name, for options other than the settings * (prompts). */ public static function textarea(string $name, string $value, string $id, int $rows = 4, bool $code = false): string { return sprintf( '', esc_attr($id), esc_attr($name), max(2, $rows), $code ? ' code' : '', esc_textarea($value) ); } /** * A drop-down. * * @param array $options value => label */ public static function select(string $key, array $options, string $selected, string $id): string { $out = sprintf(''; } /** * A drop-down with option groups ("Meta Llama", "Google") and an optional first choice * outside them ("Cloudflare's default"). * * @param array> $groups group label => [value => label] */ public static function selectGroups(string $key, array $groups, string $selected, string $id, string $empty = ''): string { $out = sprintf(''; } /** * Where you are in a sequence of steps (the setup wizard). * * @param list $steps labels, in order */ public static function stepper(array $steps, int $current): string { $out = '
    '; foreach ($steps as $i => $label) { $state = $i < $current ? 'is-done' : ($i === $current ? 'is-current' : ''); // Done steps show a tick and say "Done" to screen readers, so the state is never colour alone. $out .= sprintf( '
  1. %4$s%5$s
  2. ', $state, $i === $current ? ' aria-current="step"' : '', $i < $current ? '✓' : (string) ($i + 1), $i < $current ? '' . esc_html__('Done:', 'aipcf-ai-provider-for-cloudflare') . ' ' : '', esc_html($label) ); } return $out . '
'; } /** * One choice among a few, each with a line on what it means. * * @param array $options */ public static function radios(string $name, array $options, string $selected, string $legend): string { $out = '
' . esc_html($legend) . ''; foreach ($options as $value => $opt) { $out .= sprintf( '', esc_attr($name), esc_attr((string) $value), checked($selected, (string) $value, false), esc_html($opt['label']), isset($opt['note']) && $opt['note'] !== '' ? '' . esc_html($opt['note']) . '' : '' ); } return $out . '
'; } /** * Steps with a done or to-do mark ("Get AI running"). Each step's action is escaped HTML. * * @param list $steps */ public static function checklist(array $steps): string { $out = '
    '; foreach ($steps as $step) { $out .= sprintf( '
  1. %2$s%3$s%4$s
  2. ', $step['done'] ? 'is-done' : 'is-todo', esc_html($step['done'] ? __('Done:', 'aipcf-ai-provider-for-cloudflare') : __('To do:', 'aipcf-ai-provider-for-cloudflare')), esc_html($step['text']), isset($step['action']) && $step['action'] !== '' ? ' ' . $step['action'] . '' : '' ); } return $out . '
'; } /** * A table. Cells are HTML the caller escaped (often other components: a pill, a link). * * @param list $head * @param list> $rows * @param list $foot */ public static function table(array $head, array $rows, array $foot = []): string { $out = '
'; foreach ($head as $h) { $out .= ''; } $out .= ''; foreach ($rows as $row) { $out .= ''; foreach ($row as $i => $cell) { $out .= $i === 0 ? '' : ''; } $out .= ''; } $out .= ''; if ($foot !== []) { $out .= ''; foreach ($foot as $i => $cell) { $out .= $i === 0 ? '' : ''; } $out .= ''; } return $out . '
' . esc_html($h) . '
' . $cell . '' . $cell . '
' . $cell . '' . $cell . '
'; } /** * A link inside a table cell or a sentence. */ public static function link(string $label, string $url): string { return '' . esc_html($label) . ''; } /** * A list of facts: what, the answer in bold, and a short note ("Writing: Gemma 4, default * text model"). * * @param list $rows */ public static function facts(array $rows, string $caption = ''): string { $out = '
' . ($caption !== '' ? '
' . esc_html($caption) . '
' : ''); foreach ($rows as $r) { $out .= sprintf( '
%1$s
%2$s%3$s
', esc_html($r[0]), esc_html($r[1]), isset($r[2]) && $r[2] !== '' ? '' . esc_html($r[2]) . '' : '' ); } return $out . '
'; } /** * A number field with its unit. * * @param int|float $value * @param array{min?: int|float, max?: int|float, step?: int|float, unit?: string} $o */ public static function number(string $key, $value, string $id, array $o = []): string { return sprintf( ' %7$s', esc_attr($id), esc_attr(self::field($key)), esc_attr((string) $value), isset($o['min']) ? ' min="' . esc_attr((string) $o['min']) . '"' : '', isset($o['max']) ? ' max="' . esc_attr((string) $o['max']) . '"' : '', esc_attr((string) ($o['step'] ?? 1)), isset($o['unit']) ? '' . esc_html($o['unit']) . '' : '' ); } /** * A row of figures: a big number and what it counts. A figure can be marked 'warn' (needs * you) or 'done'. * * @param list $items value: already formatted. */ public static function stats(array $items): string { $out = '
    '; foreach ($items as $item) { $state = isset($item['state']) && $item['state'] !== '' ? ' is-' . sanitize_html_class($item['state']) : ''; $out .= sprintf('
  • %2$s %3$s
  • ', $state, esc_html($item['value']), esc_html($item['label'])); } return $out . '
'; } /** * One line of status, under the figures. */ public static function status(string $text): string { return '

' . esc_html($text) . '

'; } /** * Actions: buttons first (at most one primary), then links, separated. * * @param list $items kind: primary, button (default) or link. */ public static function actions(array $items): string { $buttons = ''; $links = []; foreach ($items as $a) { $kind = $a['kind'] ?? 'button'; $classes = $kind === 'link' ? ['aipcf-ui-link'] : ['button', $kind === 'primary' ? 'button-primary' : 'button-secondary']; $attrs = ''; if (isset($a['busy'])) { $classes[] = 'aipcf-busy'; $attrs .= ' data-busy="' . esc_attr($a['busy']) . '"'; } if (isset($a['confirm'])) { $classes[] = 'aipcf-confirm'; $attrs .= ' data-confirm="' . esc_attr($a['confirm']) . '"'; } $html = sprintf('%4$s', esc_attr(implode(' ', $classes)), esc_url($a['url']), $attrs, esc_html($a['label'])); if ($kind === 'link') { $links[] = $html; } else { $buttons .= $html; } } $sep = ''; return '
' . $buttons . ($links !== [] ? '' . implode($sep, $links) . '' : '') . '
'; } /** * A notice inside a card: 'info', 'warn' or 'bad'. $announce for a message that is the * result of what the user just did (after a redirect), so screen readers read it out. */ public static function notice(string $text, string $type = 'info', bool $announce = false): string { $role = $announce ? ($type === 'info' ? ' role="status"' : ' role="alert"') : ''; return sprintf('

%2$s

', sanitize_html_class($type), esc_html($text), $role); } /** * A status pill: On, Off, Offline today, Needs you. * * @param string $state '', 'ok', 'warn' or 'bad'. */ public static function pill(string $label, string $state = ''): string { return sprintf('%2$s', $state !== '' ? ' is-' . sanitize_html_class($state) : '', esc_html($label)); } /** * Details behind a disclosure ("Learn more", "Which models"). */ public static function more(string $summary, string $html): string { return '
' . esc_html($summary) . '
' . $html . '
'; } /** * The Save button at the end of a form. It stays in place; once something changes it sticks * to the bottom of the window until saved (assets/admin/ui.js). */ public static function saveBar(): string { return '
' . esc_html__('You have unsaved changes.', 'aipcf-ai-provider-for-cloudflare') . '
'; } }